diff --git a/opencode.json b/opencode.json new file mode 100644 index 00000000000..4b2c91be27f --- /dev/null +++ b/opencode.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://opencode.ai/config.json", + "plugin": [ + "opencode-session-start-plugin" + ] +} diff --git a/packages/opencode-session-start-plugin/package.json b/packages/opencode-session-start-plugin/package.json new file mode 100644 index 00000000000..10f56036911 --- /dev/null +++ b/packages/opencode-session-start-plugin/package.json @@ -0,0 +1,12 @@ +{ + "name": "opencode-session-start-plugin", + "version": "1.0.0", + "type": "module", + "main": "src/index.ts", + "dependencies": { + "@opencode-ai/plugin": "workspace:*" + }, + "devDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/packages/opencode-session-start-plugin/src/index.ts b/packages/opencode-session-start-plugin/src/index.ts new file mode 100644 index 00000000000..90eac6d1f3b --- /dev/null +++ b/packages/opencode-session-start-plugin/src/index.ts @@ -0,0 +1,36 @@ +import { Plugin, tool } from "@opencode-ai/plugin" +import fs from "fs" +import path from "path" + +export const SessionStartPlugin: Plugin = async (ctx) => { + return { + tool: { + testSessionStart: tool({ + description: "Test the session.start hook - returns status", + args: {}, + async execute() { + return "SessionStartPlugin loaded - check console for hook trigger" + }, + }), + }, + "session.start": async ({ sessionID, directory, projectID }, { context }) => { + console.log("🎯 session.start hook FIRED!") + console.log(" sessionID:", sessionID) + console.log(" directory:", directory) + console.log(" projectID:", projectID) + + const testContext = `[TEST] This context was injected by the session.start hook! +Session ID: ${sessionID} +Working Directory: ${directory} +Project ID: ${projectID} +Timestamp: ${new Date().toISOString()}` + + context.push(testContext) + + console.log("✅ Context injected into system prompt") + console.log(" Context length:", context.join("\n").length, "chars") + }, + } +} + +export default SessionStartPlugin diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 75bd3c9dfac..fe891c26d0d 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -648,7 +648,26 @@ export namespace SessionPrompt { await Plugin.trigger("experimental.chat.messages.transform", {}, { messages: msgs }) // Build system prompt, adding structured output instruction if needed - const system = [...(await SystemPrompt.environment(model)), ...(await InstructionPrompt.system())] + // First, check if this is the first message in the session for session.start hook + const existingMessages = await Session.messages({ sessionID }) + const isFirstMessage = existingMessages.length <= 1 // Only the message just created + + let sessionStartContext: string[] = [] + if (isFirstMessage) { + await Plugin.trigger( + "session.start", + { sessionID, directory: session.directory, projectID: session.projectID }, + { context: [] }, + ).then((result) => { + sessionStartContext = result.context + }) + } + + const system = [ + ...sessionStartContext, + ...(await SystemPrompt.environment(model)), + ...(await InstructionPrompt.system()), + ] const format = lastUser.format ?? { type: "text" } if (format.type === "json_schema") { system.push(STRUCTURED_OUTPUT_SYSTEM_PROMPT) diff --git a/packages/plugin/src/index.ts b/packages/plugin/src/index.ts index 76370d1d5a7..e709f6a2068 100644 --- a/packages/plugin/src/index.ts +++ b/packages/plugin/src/index.ts @@ -152,6 +152,19 @@ export interface Hooks { [key: string]: ToolDefinition } auth?: AuthHook + /** + * Called when a new session starts, before the first message is processed. + * Plugins can inject context into the system prompt using this hook. + * The context strings are appended to the system prompt. + */ + "session.start"?: ( + input: { + sessionID: string + directory: string + projectID: string + }, + output: { context: string[] }, + ) => Promise /** * Called when a new message is received */ diff --git a/test-hook.sh b/test-hook.sh new file mode 100644 index 00000000000..6f45c8abefd --- /dev/null +++ b/test-hook.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# Test script for session.start hook + +echo "==============================================" +echo "Testing session.start Hook" +echo "==============================================" + +# Check if bun is available +if ! command -v bun &> /dev/null; then + echo "❌ Bun not found. Please install Bun first:" + echo " curl -fsSL https://bun.sh/install | bash" + exit 1 +fi + +# Check if we're in the right directory +if [ ! -f "package.json" ]; then + echo "❌ Not in opencode directory" + echo " Run: cd ~/opencode-test" + exit 1 +fi + +echo "✅ Bun found" +echo "✅ In opencode directory" + +# Install dependencies if needed +if [ ! -d "node_modules" ]; then + echo "📦 Installing dependencies..." + bun install +fi + +echo "" +echo "==============================================" +echo "To test the session.start hook:" +echo "==============================================" +echo "" +echo "1. Run: bun run dev" +echo "2. OpenCode will start" +echo "3. Start a NEW session (not continue)" +echo "4. You'll see in the logs:" +echo " 🎯 session.start hook FIRED!" +echo " ✅ Context injected into system prompt" +echo "" +echo "Or run with a specific project:" +echo " bun run dev /path/to/your/project" +echo "" +echo "=============================================="