Files
mlkem-sync/.opencode/plugins/session-start.js
FallenSigh 8fdf944555 feat: init mlkem project with Verilator test framework
- sync_rtl/common/: skid_buffer, pipeline_reg, defines (valid/ready)
- sync_rtl/mod_add/: modular adder example with Verilator C++ TB
- test_framework/: Python-driven Verilator compile/sim/compare pipeline
- test_framework/modules/mod_add/: 50-vector test plan, full鏈路 PASS
- .trellis/spec/: RTL and test_framework conventions documented
2026-06-24 19:43:29 +08:00

102 lines
3.7 KiB
JavaScript

/* global process */
/**
* Trellis Session Start Plugin
*
* Injects context when user sends the first message in a session.
* Uses OpenCode's chat.message hook directly so the context persists in history.
*/
import { TrellisContext, contextCollector, debugLog, isTrellisSubagent } from "../lib/trellis-context.js"
import {
buildSessionContext,
hasPersistedInjectedContext,
markContextInjected,
} from "../lib/session-utils.js"
// OpenCode 1.2.x expects plugins to be factory functions (see inject-subagent-context.js comment).
export default async ({ directory, client }) => {
const ctx = new TrellisContext(directory)
debugLog("session", "Plugin loaded, directory:", directory)
return {
event: ({ event }) => {
try {
if (event?.type === "session.compacted" && event?.properties?.sessionID) {
const sessionID = event.properties.sessionID
contextCollector.clear(sessionID)
debugLog("session", "Cleared processed flag after compaction for session:", sessionID)
}
} catch (error) {
debugLog(
"session",
"Error in event hook:",
error instanceof Error ? error.message : String(error),
)
}
},
// chat.message - triggered when user sends a message.
// Modify the message in-place so the context is persisted with updateMessage/updatePart.
"chat.message": async (input, output) => {
try {
const sessionID = input.sessionID
const agent = input.agent || "unknown"
debugLog("session", "chat.message called, sessionID:", sessionID, "agent:", agent)
// Skip Trellis sub-agent turns — sub-agent context is injected by
// `inject-subagent-context.js` on the parent's tool.execute.before;
// re-injecting the main-session SessionStart here would drown that.
if (isTrellisSubagent(input)) {
debugLog("session", "Skipping trellis subagent turn:", agent)
return
}
if (process.env.TRELLIS_HOOKS === "0" || process.env.TRELLIS_DISABLE_HOOKS === "1") {
debugLog("session", "Skipping - TRELLIS_HOOKS disabled")
return
}
if (process.env.OPENCODE_NON_INTERACTIVE === "1") {
debugLog("session", "Skipping - non-interactive mode")
return
}
if (contextCollector.isProcessed(sessionID)) {
debugLog("session", "Skipping - session already processed")
return
}
if (await hasPersistedInjectedContext(client, ctx.directory, sessionID)) {
contextCollector.markProcessed(sessionID)
debugLog("session", "Skipping - session already contains persisted Trellis context")
return
}
const context = buildSessionContext(ctx, input)
debugLog("session", "Built context, length:", context.length)
const parts = output?.parts || []
const textPartIndex = parts.findIndex(
p => p.type === "text" && p.text !== undefined
)
if (textPartIndex !== -1) {
const originalText = parts[textPartIndex].text || ""
parts[textPartIndex].text = `${context}\n\n---\n\n${originalText}`
markContextInjected(parts[textPartIndex])
debugLog("session", "Injected context into chat.message text part, length:", context.length)
} else {
const injectedPart = { type: "text", text: context }
markContextInjected(injectedPart)
parts.unshift(injectedPart)
debugLog("session", "Prepended new text part with context, length:", context.length)
}
contextCollector.markProcessed(sessionID)
} catch (error) {
debugLog("session", "Error in chat.message:", error.message, error.stack)
}
},
}
}