@a5c-ai/babysitter-opencode 5.0.1-staging.3b77846e → 5.0.1-staging.542f8525

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -131,7 +131,7 @@ plugin registers hooks for the following OpenCode events:
131
131
  |----------------|-----------------|---------|
132
132
  | `session.created` | `session-start` | Initialize session state |
133
133
  | `session.idle` | `stop` | Check for pending effects |
134
- | `shell.env` | -- | Inject env vars (BABYSITTER_SESSION_ID) |
134
+ | `shell.env` | -- | Inject env vars (AGENT_SESSION_ID) |
135
135
  | `tool.execute.before` | `pre-tool-use` | Pre-tool-use awareness |
136
136
  | `tool.execute.after` | `post-tool-use` | Post-tool-use awareness |
137
137
 
@@ -147,7 +147,7 @@ the agent runs the full orchestration loop within a single turn by calling
147
147
  The `shell.env` hook self-injects these variables since OpenCode does not
148
148
  natively provide them:
149
149
 
150
- - `BABYSITTER_SESSION_ID` -- Unique session identifier
150
+ - `AGENT_SESSION_ID` -- Unique session identifier
151
151
  - `OPENCODE_SESSION_ID` -- Alias for session ID
152
152
  - `BABYSITTER_STATE_DIR` -- State directory path
153
153
  - `BABYSITTER_RUNS_DIR` -- Runs directory path
@@ -362,13 +362,13 @@ Mark as FAIL if:
362
362
  - Parse the output and inspect the `resolvedFrom` field. Classify as follows:
363
363
  - `resolvedFrom: "pid-marker"` → mark as PASS ("Session ID derives from the live Claude Code ancestor process -- authoritative").
364
364
  - `resolvedFrom: "env-file"` → mark as PASS with a note ("CLAUDE_ENV_FILE was used; typically healthy").
365
- - `resolvedFrom: "env-var"` → mark as WARN ("`BABYSITTER_SESSION_ID` is set without a corroborating PID marker. Likely stale from a prior Claude Code session -- see GitHub issue #130").
366
- - Remediation: run `babysitter session:cleanup` and start a fresh Claude Code session, or `unset BABYSITTER_SESSION_ID` before invoking babysitter.
365
+ - `resolvedFrom: "env-var"` → mark as WARN ("`AGENT_SESSION_ID` is set without a corroborating PID marker. Likely stale from a prior Claude Code session -- see GitHub issue #130").
366
+ - Remediation: run `babysitter session:cleanup` and start a fresh Claude Code session, or `unset AGENT_SESSION_ID` before invoking babysitter.
367
367
  - `resolvedFrom: "none"` → mark as ERROR ("No session ID resolvable. Either no session-start hook fired, or the ancestor walk failed").
368
368
 
369
369
  **Env-var shadow check:**
370
370
  - Independently inspect `envVarPresent` and `envVarMatches` in the output.
371
- - If `envVarPresent && !envVarMatches`, mark as WARN ("`BABYSITTER_SESSION_ID` in env does not match the resolved session ID; a stale value is shadowing the authoritative one. Unset the env var").
371
+ - If `envVarPresent && !envVarMatches`, mark as WARN ("`AGENT_SESSION_ID` in env does not match the resolved session ID; a stale value is shadowing the authoritative one. Unset the env var").
372
372
 
373
373
  ---
374
374
 
@@ -390,7 +390,7 @@ Mark as FAIL if:
390
390
 
391
391
  - Enumerate files in `~/.a5c/` matching the pattern `current-session-*-pid-*`.
392
392
  - Count markers per harness (derived from the filename).
393
- - If more than one live marker exists for the same harness, mark as INFO ("Multiple live Claude Code / harness sessions detected; ensure each shell scopes `BABYSITTER_SESSION_ID` appropriately -- the PID marker handles this automatically").
393
+ - If more than one live marker exists for the same harness, mark as INFO ("Multiple live Claude Code / harness sessions detected; ensure each shell scopes `AGENT_SESSION_ID` appropriately -- the PID marker handles this automatically").
394
394
  - Otherwise mark as PASS.
395
395
 
396
396
  ---
@@ -501,7 +501,7 @@ babysitter session:cleanup --dry-run # preview
501
501
  babysitter session:cleanup # apply
502
502
 
503
503
  # 2. Unset a stale env var
504
- unset BABYSITTER_SESSION_ID
504
+ unset AGENT_SESSION_ID
505
505
 
506
506
  # 3. Re-bind a run explicitly if needed
507
507
  babysitter session:resume --session-id <fresh-id> --state-dir ~/.a5c --run-id <runId> --runs-dir .a5c/runs
@@ -120,7 +120,7 @@ function resolveHooksProxy() {
120
120
  // ---------------------------------------------------------------------------
121
121
 
122
122
  function runViaProxy(proxy, hookType, inputJson) {
123
- const handler = `babysitter hook:run --harness unified --hook-type ${hookType} --plugin-root ${PLUGIN_ROOT} --state-dir ${STATE_DIR} --json`;
123
+ const handler = `babysitter hook:run --harness unified --hook-type ${hookType} --state-dir ${STATE_DIR} --json`;
124
124
  const result = execSync(`"${proxy}" invoke --adapter opencode --handler "${handler}" --json`, {
125
125
  input: inputJson,
126
126
  stdio: ["pipe", "pipe", "pipe"],
@@ -131,7 +131,7 @@ function runViaProxy(proxy, hookType, inputJson) {
131
131
  }
132
132
 
133
133
  function runViaNpxProxy(version, hookType, inputJson) {
134
- const handler = `babysitter hook:run --harness unified --hook-type ${hookType} --plugin-root ${PLUGIN_ROOT} --state-dir ${STATE_DIR} --json`;
134
+ const handler = `babysitter hook:run --harness unified --hook-type ${hookType} --state-dir ${STATE_DIR} --json`;
135
135
  const result = execSync(`npx -y "@a5c-ai/hooks-proxy-cli@${version}" invoke --adapter opencode --handler "${handler}" --json`, {
136
136
  input: inputJson,
137
137
  stdio: ["pipe", "pipe", "pipe"],
@@ -151,11 +151,11 @@ function main() {
151
151
 
152
152
  // Generate a session ID if OpenCode doesn't provide one
153
153
  const sessionId = process.env.OPENCODE_SESSION_ID
154
- || process.env.BABYSITTER_SESSION_ID
154
+ || process.env.AGENT_SESSION_ID
155
155
  || crypto.randomUUID();
156
156
 
157
157
  // Set env var so downstream hooks can pick it up
158
- process.env.BABYSITTER_SESSION_ID = sessionId;
158
+ process.env.AGENT_SESSION_ID = sessionId;
159
159
 
160
160
  const sdkVersion = getSdkVersion();
161
161
 
@@ -94,7 +94,7 @@ function installHooksProxy(version) {
94
94
  }
95
95
 
96
96
  function runViaProxy(proxy, hookType, inputJson) {
97
- const handler = `babysitter hook:run --harness unified --hook-type ${hookType} --plugin-root ${PLUGIN_ROOT} --state-dir ${STATE_DIR} --json`;
97
+ const handler = `babysitter hook:run --harness unified --hook-type ${hookType} --state-dir ${STATE_DIR} --json`;
98
98
  const result = execSync(`"${proxy}" invoke --adapter opencode --handler "${handler}" --json`, {
99
99
  input: inputJson,
100
100
  stdio: ["pipe", "pipe", "pipe"],
@@ -105,7 +105,7 @@ function runViaProxy(proxy, hookType, inputJson) {
105
105
  }
106
106
 
107
107
  function runViaNpxProxy(version, hookType, inputJson) {
108
- const handler = `babysitter hook:run --harness unified --hook-type ${hookType} --plugin-root ${PLUGIN_ROOT} --state-dir ${STATE_DIR} --json`;
108
+ const handler = `babysitter hook:run --harness unified --hook-type ${hookType} --state-dir ${STATE_DIR} --json`;
109
109
  const result = execSync(`npx -y "@a5c-ai/hooks-proxy-cli@${version}" invoke --adapter opencode --handler "${handler}" --json`, {
110
110
  input: inputJson,
111
111
  stdio: ["pipe", "pipe", "pipe"],
@@ -118,7 +118,7 @@ function runViaNpxProxy(version, hookType, inputJson) {
118
118
  function main() {
119
119
  blog("Unified session-idle hook invoked");
120
120
 
121
- const sessionId = process.env.BABYSITTER_SESSION_ID
121
+ const sessionId = process.env.AGENT_SESSION_ID
122
122
  || process.env.OPENCODE_SESSION_ID
123
123
  || "";
124
124
 
@@ -5,7 +5,7 @@
5
5
  * but primarily performs direct env var injection.
6
6
  *
7
7
  * Fires when OpenCode initializes a shell environment. Injects babysitter
8
- * environment variables (BABYSITTER_SESSION_ID, BABYSITTER_STATE_DIR, etc.)
8
+ * environment variables (AGENT_SESSION_ID, BABYSITTER_STATE_DIR, etc.)
9
9
  * so that subprocesses and other hooks can discover the active session.
10
10
  *
11
11
  * This is critical for OpenCode because it does NOT natively inject
@@ -100,7 +100,7 @@ function main() {
100
100
  blog("Unified shell-env hook invoked");
101
101
 
102
102
  // Resolve or generate session ID
103
- const sessionId = process.env.BABYSITTER_SESSION_ID
103
+ const sessionId = process.env.AGENT_SESSION_ID
104
104
  || process.env.OPENCODE_SESSION_ID
105
105
  || crypto.randomUUID();
106
106
 
@@ -114,7 +114,7 @@ function main() {
114
114
 
115
115
  // Build env vars to inject
116
116
  const env = {
117
- BABYSITTER_SESSION_ID: sessionId,
117
+ AGENT_SESSION_ID: sessionId,
118
118
  OPENCODE_SESSION_ID: sessionId,
119
119
  BABYSITTER_STATE_DIR: STATE_DIR,
120
120
  BABYSITTER_RUNS_DIR: RUNS_DIR,
@@ -95,7 +95,7 @@ function installHooksProxy(version) {
95
95
  }
96
96
 
97
97
  function main() {
98
- const sessionId = process.env.BABYSITTER_SESSION_ID
98
+ const sessionId = process.env.AGENT_SESSION_ID
99
99
  || process.env.OPENCODE_SESSION_ID
100
100
  || "";
101
101
 
@@ -131,7 +131,7 @@ function main() {
131
131
  proxy = resolveHooksProxy();
132
132
  }
133
133
 
134
- const handler = `babysitter hook:run --harness unified --hook-type post-tool-use --plugin-root ${PLUGIN_ROOT} --state-dir ${STATE_DIR} --json`;
134
+ const handler = `babysitter hook:run --harness unified --hook-type post-tool-use --state-dir ${STATE_DIR} --json`;
135
135
 
136
136
  try {
137
137
  let result;
@@ -95,7 +95,7 @@ function installHooksProxy(version) {
95
95
  }
96
96
 
97
97
  function main() {
98
- const sessionId = process.env.BABYSITTER_SESSION_ID
98
+ const sessionId = process.env.AGENT_SESSION_ID
99
99
  || process.env.OPENCODE_SESSION_ID
100
100
  || "";
101
101
 
@@ -132,7 +132,7 @@ function main() {
132
132
  proxy = resolveHooksProxy();
133
133
  }
134
134
 
135
- const handler = `babysitter hook:run --harness unified --hook-type pre-tool-use --plugin-root ${PLUGIN_ROOT} --state-dir ${STATE_DIR} --json`;
135
+ const handler = `babysitter hook:run --harness unified --hook-type pre-tool-use --state-dir ${STATE_DIR} --json`;
136
136
 
137
137
  try {
138
138
  let result;
package/hooks/hooks.json CHANGED
@@ -22,7 +22,7 @@
22
22
  {
23
23
  "type": "command",
24
24
  "script": "hooks/babysitter-proxied-shell-env.js",
25
- "description": "Inject BABYSITTER_SESSION_ID and other env vars into shell (proxied via a5c-hooks-proxy)",
25
+ "description": "Inject AGENT_SESSION_ID and other env vars into shell (proxied via a5c-hooks-proxy)",
26
26
  "timeoutMs": 5000
27
27
  }
28
28
  ],
@@ -23,7 +23,7 @@
23
23
  {
24
24
  "type": "command",
25
25
  "script": "hooks/babysitter-proxied-shell-env.js",
26
- "description": "Inject BABYSITTER_SESSION_ID and other env vars into shell (proxied via a5c-hooks-proxy)",
26
+ "description": "Inject AGENT_SESSION_ID and other env vars into shell (proxied via a5c-hooks-proxy)",
27
27
  "timeoutMs": 5000
28
28
  }
29
29
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a5c-ai/babysitter-opencode",
3
- "version": "5.0.1-staging.3b77846e",
3
+ "version": "5.0.1-staging.542f8525",
4
4
  "description": "Babysitter orchestration plugin for OpenCode with SDK-managed process-library bootstrapping and in-turn iteration model",
5
5
  "scripts": {
6
6
  "test": "node test/integration.test.js",
@@ -41,6 +41,6 @@
41
41
  },
42
42
  "homepage": "https://github.com/a5c-ai/babysitter/tree/main/plugins/babysitter-opencode#readme",
43
43
  "dependencies": {
44
- "@a5c-ai/babysitter-sdk": "5.0.1-staging.3b77846e"
44
+ "@a5c-ai/babysitter-sdk": "5.0.1-staging.542f8525"
45
45
  }
46
46
  }
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babysitter",
3
- "version": "5.0.1-staging.3b77846e",
3
+ "version": "5.0.1-staging.542f8525",
4
4
  "description": "Orchestrate complex, multi-step workflows with event-sourced state management, hook-based extensibility, and human-in-the-loop approval -- powered by the Babysitter SDK",
5
5
  "author": "a5c.ai",
6
6
  "license": "MIT",
@@ -363,13 +363,13 @@ Mark as FAIL if:
363
363
  - Parse the output and inspect the `resolvedFrom` field. Classify as follows:
364
364
  - `resolvedFrom: "pid-marker"` → mark as PASS ("Session ID derives from the live Claude Code ancestor process -- authoritative").
365
365
  - `resolvedFrom: "env-file"` → mark as PASS with a note ("CLAUDE_ENV_FILE was used; typically healthy").
366
- - `resolvedFrom: "env-var"` → mark as WARN ("`BABYSITTER_SESSION_ID` is set without a corroborating PID marker. Likely stale from a prior Claude Code session -- see GitHub issue #130").
367
- - Remediation: run `babysitter session:cleanup` and start a fresh Claude Code session, or `unset BABYSITTER_SESSION_ID` before invoking babysitter.
366
+ - `resolvedFrom: "env-var"` → mark as WARN ("`AGENT_SESSION_ID` is set without a corroborating PID marker. Likely stale from a prior Claude Code session -- see GitHub issue #130").
367
+ - Remediation: run `babysitter session:cleanup` and start a fresh Claude Code session, or `unset AGENT_SESSION_ID` before invoking babysitter.
368
368
  - `resolvedFrom: "none"` → mark as ERROR ("No session ID resolvable. Either no session-start hook fired, or the ancestor walk failed").
369
369
 
370
370
  **Env-var shadow check:**
371
371
  - Independently inspect `envVarPresent` and `envVarMatches` in the output.
372
- - If `envVarPresent && !envVarMatches`, mark as WARN ("`BABYSITTER_SESSION_ID` in env does not match the resolved session ID; a stale value is shadowing the authoritative one. Unset the env var").
372
+ - If `envVarPresent && !envVarMatches`, mark as WARN ("`AGENT_SESSION_ID` in env does not match the resolved session ID; a stale value is shadowing the authoritative one. Unset the env var").
373
373
 
374
374
  ---
375
375
 
@@ -391,7 +391,7 @@ Mark as FAIL if:
391
391
 
392
392
  - Enumerate files in `~/.a5c/` matching the pattern `current-session-*-pid-*`.
393
393
  - Count markers per harness (derived from the filename).
394
- - If more than one live marker exists for the same harness, mark as INFO ("Multiple live Claude Code / harness sessions detected; ensure each shell scopes `BABYSITTER_SESSION_ID` appropriately -- the PID marker handles this automatically").
394
+ - If more than one live marker exists for the same harness, mark as INFO ("Multiple live Claude Code / harness sessions detected; ensure each shell scopes `AGENT_SESSION_ID` appropriately -- the PID marker handles this automatically").
395
395
  - Otherwise mark as PASS.
396
396
 
397
397
  ---
@@ -502,7 +502,7 @@ babysitter session:cleanup --dry-run # preview
502
502
  babysitter session:cleanup # apply
503
503
 
504
504
  # 2. Unset a stale env var
505
- unset BABYSITTER_SESSION_ID
505
+ unset AGENT_SESSION_ID
506
506
 
507
507
  # 3. Re-bind a run explicitly if needed
508
508
  babysitter session:resume --session-id <fresh-id> --state-dir ~/.a5c --run-id <runId> --runs-dir .a5c/runs
package/versions.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "sdkVersion": "5.0.1-staging.3b77846e",
2
+ "sdkVersion": "5.0.1-staging.542f8525",
3
3
  "pluginVersion": "0.1.0"
4
4
  }
@@ -1,46 +0,0 @@
1
- {
2
- "version": 1,
3
- "description": "Babysitter hook registration for OpenCode. Maps OpenCode plugin events to babysitter hook scripts.",
4
- "hooks": {
5
- "session.created": [
6
- {
7
- "type": "command",
8
- "script": "hooks/session-created.js",
9
- "description": "Initialize babysitter session state and inject context",
10
- "timeoutMs": 30000
11
- }
12
- ],
13
- "session.idle": [
14
- {
15
- "type": "command",
16
- "script": "hooks/session-idle.js",
17
- "description": "Check for pending babysitter effects when agent goes idle",
18
- "timeoutMs": 30000
19
- }
20
- ],
21
- "shell.env": [
22
- {
23
- "type": "command",
24
- "script": "hooks/shell-env.js",
25
- "description": "Inject BABYSITTER_SESSION_ID and other env vars into shell",
26
- "timeoutMs": 5000
27
- }
28
- ],
29
- "tool.execute.before": [
30
- {
31
- "type": "command",
32
- "script": "hooks/tool-execute-before.js",
33
- "description": "Pre-tool-use hook for babysitter awareness",
34
- "timeoutMs": 10000
35
- }
36
- ],
37
- "tool.execute.after": [
38
- {
39
- "type": "command",
40
- "script": "hooks/tool-execute-after.js",
41
- "description": "Post-tool-use hook for babysitter awareness",
42
- "timeoutMs": 10000
43
- }
44
- ]
45
- }
46
- }
@@ -1,182 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Babysitter Session Created Hook for OpenCode
4
- *
5
- * Fires when an OpenCode session is created. Ensures the babysitter SDK CLI
6
- * is installed, then delegates to `babysitter hook:run --hook-type session-start`
7
- * to create baseline session state.
8
- *
9
- * OpenCode plugin protocol:
10
- * - Receives event context as JSON via process.argv or stdin
11
- * - Outputs JSON to stdout
12
- * - Exit 0 = success
13
- */
14
-
15
- "use strict";
16
-
17
- const { execSync, execFileSync } = require("child_process");
18
- const { readFileSync, mkdirSync, appendFileSync, existsSync, writeFileSync } = require("fs");
19
- const os = require("os");
20
- const path = require("path");
21
- const crypto = require("crypto");
22
-
23
- const PLUGIN_ROOT = process.env.OPENCODE_PLUGIN_ROOT || path.resolve(__dirname, "..");
24
- const GLOBAL_ROOT = process.env.BABYSITTER_GLOBAL_STATE_DIR || path.join(os.homedir(), ".a5c");
25
- const STATE_DIR = process.env.BABYSITTER_STATE_DIR || path.join(GLOBAL_ROOT, "state");
26
- const LOG_DIR = process.env.BABYSITTER_LOG_DIR || path.join(GLOBAL_ROOT, "logs");
27
- const LOG_FILE = path.join(LOG_DIR, "babysitter-session-created-hook.log");
28
-
29
- // ---------------------------------------------------------------------------
30
- // Logging
31
- // ---------------------------------------------------------------------------
32
-
33
- function ensureDir(dir) {
34
- try { mkdirSync(dir, { recursive: true }); } catch { /* best-effort */ }
35
- }
36
-
37
- function blog(msg) {
38
- ensureDir(LOG_DIR);
39
- const ts = new Date().toISOString();
40
- try {
41
- appendFileSync(LOG_FILE, `[INFO] ${ts} ${msg}\n`);
42
- } catch { /* best-effort */ }
43
- }
44
-
45
- // ---------------------------------------------------------------------------
46
- // SDK version & install
47
- // ---------------------------------------------------------------------------
48
-
49
- function getSdkVersion() {
50
- try {
51
- const versions = JSON.parse(readFileSync(path.join(PLUGIN_ROOT, "versions.json"), "utf8"));
52
- return versions.sdkVersion || "latest";
53
- } catch {
54
- return "latest";
55
- }
56
- }
57
-
58
- function hasBabysitterCli() {
59
- try {
60
- execSync("babysitter --version", { stdio: "pipe", timeout: 10000 });
61
- return true;
62
- } catch {
63
- return false;
64
- }
65
- }
66
-
67
- function installSdk(version) {
68
- const marker = path.join(PLUGIN_ROOT, ".babysitter-install-attempted");
69
- if (existsSync(marker)) return;
70
-
71
- try {
72
- execSync(`npm i -g "@a5c-ai/babysitter-sdk@${version}" --loglevel=error`, {
73
- stdio: "pipe",
74
- timeout: 120000,
75
- });
76
- blog(`Installed SDK globally (${version})`);
77
- } catch {
78
- // Try user-local prefix
79
- try {
80
- const prefix = path.join(process.env.HOME || process.env.USERPROFILE || "~", ".local");
81
- execSync(`npm i -g "@a5c-ai/babysitter-sdk@${version}" --prefix "${prefix}" --loglevel=error`, {
82
- stdio: "pipe",
83
- timeout: 120000,
84
- });
85
- blog(`Installed SDK to user prefix (${version})`);
86
- } catch {
87
- blog("SDK installation failed");
88
- }
89
- }
90
-
91
- try { writeFileSync(marker, version); } catch { /* best-effort */ }
92
- }
93
-
94
- // ---------------------------------------------------------------------------
95
- // CLI execution helper
96
- // ---------------------------------------------------------------------------
97
-
98
- function runBabysitterHook(hookType, inputJson) {
99
- const sdkVersion = getSdkVersion();
100
- const args = [
101
- "hook:run",
102
- "--hook-type", hookType,
103
- "--harness", "opencode",
104
- "--plugin-root", PLUGIN_ROOT,
105
- "--state-dir", STATE_DIR,
106
- "--json",
107
- ];
108
-
109
- try {
110
- const result = execSync(`babysitter ${args.join(" ")}`, {
111
- input: inputJson,
112
- stdio: ["pipe", "pipe", "pipe"],
113
- timeout: 30000,
114
- env: { ...process.env, BABYSITTER_STATE_DIR: STATE_DIR },
115
- });
116
- return result.toString("utf8").trim();
117
- } catch (err) {
118
- // Fall back to npx
119
- try {
120
- const result = execSync(`npx -y "@a5c-ai/babysitter-sdk@${sdkVersion}" ${args.join(" ")}`, {
121
- input: inputJson,
122
- stdio: ["pipe", "pipe", "pipe"],
123
- timeout: 60000,
124
- env: { ...process.env, BABYSITTER_STATE_DIR: STATE_DIR },
125
- });
126
- return result.toString("utf8").trim();
127
- } catch (npxErr) {
128
- blog(`Hook execution failed: ${npxErr.message}`);
129
- return "{}";
130
- }
131
- }
132
- }
133
-
134
- // ---------------------------------------------------------------------------
135
- // Main
136
- // ---------------------------------------------------------------------------
137
-
138
- function main() {
139
- blog("session-created hook invoked");
140
- blog(`PLUGIN_ROOT=${PLUGIN_ROOT}`);
141
-
142
- // Generate a session ID if OpenCode doesn't provide one
143
- const sessionId = process.env.OPENCODE_SESSION_ID
144
- || process.env.BABYSITTER_SESSION_ID
145
- || crypto.randomUUID();
146
-
147
- // Set env var so downstream hooks can pick it up
148
- process.env.BABYSITTER_SESSION_ID = sessionId;
149
-
150
- const sdkVersion = getSdkVersion();
151
-
152
- // Ensure SDK is installed
153
- if (!hasBabysitterCli()) {
154
- blog("SDK CLI not found, attempting install");
155
- installSdk(sdkVersion);
156
- }
157
-
158
- // Build hook input
159
- const hookInput = JSON.stringify({
160
- session_id: sessionId,
161
- cwd: process.cwd(),
162
- harness: "opencode",
163
- plugin_root: PLUGIN_ROOT,
164
- });
165
-
166
- blog(`Hook input: ${hookInput}`);
167
-
168
- // Delegate to SDK hook handler
169
- const result = runBabysitterHook("session-start", hookInput);
170
-
171
- blog(`Hook result: ${result}`);
172
-
173
- // Output result
174
- try {
175
- const parsed = JSON.parse(result);
176
- process.stdout.write(JSON.stringify(parsed) + "\n");
177
- } catch {
178
- process.stdout.write("{}\n");
179
- }
180
- }
181
-
182
- main();
@@ -1,124 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Babysitter Session Idle Hook for OpenCode
4
- *
5
- * Fires when the OpenCode agent goes idle. Checks if the current babysitter
6
- * run has pending effects that need attention. Since OpenCode does NOT have a
7
- * blocking stop hook, this is fire-and-forget -- it outputs context about
8
- * pending effects so the agent can decide whether to continue iterating.
9
- *
10
- * Delegates to `babysitter hook:run --hook-type stop` (which handles the
11
- * run-state inspection and iteration tracking).
12
- *
13
- * OpenCode plugin protocol:
14
- * - Receives event context as JSON via stdin
15
- * - Outputs JSON to stdout
16
- * - Exit 0 = success
17
- */
18
-
19
- "use strict";
20
-
21
- const { execSync } = require("child_process");
22
- const { readFileSync, mkdirSync, appendFileSync } = require("fs");
23
- const os = require("os");
24
- const path = require("path");
25
-
26
- const PLUGIN_ROOT = process.env.OPENCODE_PLUGIN_ROOT || path.resolve(__dirname, "..");
27
- const GLOBAL_ROOT = process.env.BABYSITTER_GLOBAL_STATE_DIR || path.join(os.homedir(), ".a5c");
28
- const STATE_DIR = process.env.BABYSITTER_STATE_DIR || path.join(GLOBAL_ROOT, "state");
29
- const LOG_DIR = process.env.BABYSITTER_LOG_DIR || path.join(GLOBAL_ROOT, "logs");
30
- const LOG_FILE = path.join(LOG_DIR, "babysitter-session-idle-hook.log");
31
-
32
- function ensureDir(dir) {
33
- try { mkdirSync(dir, { recursive: true }); } catch { /* best-effort */ }
34
- }
35
-
36
- function blog(msg) {
37
- ensureDir(LOG_DIR);
38
- const ts = new Date().toISOString();
39
- try {
40
- appendFileSync(LOG_FILE, `[INFO] ${ts} ${msg}\n`);
41
- } catch { /* best-effort */ }
42
- }
43
-
44
- function getSdkVersion() {
45
- try {
46
- const versions = JSON.parse(readFileSync(path.join(PLUGIN_ROOT, "versions.json"), "utf8"));
47
- return versions.sdkVersion || "latest";
48
- } catch {
49
- return "latest";
50
- }
51
- }
52
-
53
- function runBabysitterHook(hookType, inputJson) {
54
- const sdkVersion = getSdkVersion();
55
- const args = [
56
- "hook:run",
57
- "--hook-type", hookType,
58
- "--harness", "opencode",
59
- "--plugin-root", PLUGIN_ROOT,
60
- "--state-dir", STATE_DIR,
61
- "--json",
62
- ];
63
-
64
- try {
65
- const result = execSync(`babysitter ${args.join(" ")}`, {
66
- input: inputJson,
67
- stdio: ["pipe", "pipe", "pipe"],
68
- timeout: 30000,
69
- env: { ...process.env, BABYSITTER_STATE_DIR: STATE_DIR },
70
- });
71
- return result.toString("utf8").trim();
72
- } catch {
73
- try {
74
- const result = execSync(`npx -y "@a5c-ai/babysitter-sdk@${sdkVersion}" ${args.join(" ")}`, {
75
- input: inputJson,
76
- stdio: ["pipe", "pipe", "pipe"],
77
- timeout: 60000,
78
- env: { ...process.env, BABYSITTER_STATE_DIR: STATE_DIR },
79
- });
80
- return result.toString("utf8").trim();
81
- } catch (err) {
82
- blog(`Hook execution failed: ${err.message}`);
83
- return "{}";
84
- }
85
- }
86
- }
87
-
88
- function main() {
89
- blog("session-idle hook invoked");
90
-
91
- const sessionId = process.env.BABYSITTER_SESSION_ID
92
- || process.env.OPENCODE_SESSION_ID
93
- || "";
94
-
95
- if (!sessionId) {
96
- blog("No session ID -- nothing to check");
97
- process.stdout.write("{}\n");
98
- return;
99
- }
100
-
101
- const hookInput = JSON.stringify({
102
- session_id: sessionId,
103
- cwd: process.cwd(),
104
- harness: "opencode",
105
- plugin_root: PLUGIN_ROOT,
106
- });
107
-
108
- blog(`Checking run status for session ${sessionId}`);
109
-
110
- // Delegate to the stop hook handler, which inspects run state
111
- // and returns block/allow decisions
112
- const result = runBabysitterHook("stop", hookInput);
113
-
114
- blog(`Hook result: ${result}`);
115
-
116
- try {
117
- const parsed = JSON.parse(result);
118
- process.stdout.write(JSON.stringify(parsed) + "\n");
119
- } catch {
120
- process.stdout.write("{}\n");
121
- }
122
- }
123
-
124
- main();
@@ -1,88 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Babysitter Shell Environment Hook for OpenCode
4
- *
5
- * Fires when OpenCode initializes a shell environment. Injects babysitter
6
- * environment variables (BABYSITTER_SESSION_ID, BABYSITTER_STATE_DIR, etc.)
7
- * so that subprocesses and other hooks can discover the active session.
8
- *
9
- * This is critical for OpenCode because it does NOT natively inject
10
- * distinctive env vars into plugins -- the babysitter plugin must self-inject
11
- * them via this hook.
12
- *
13
- * OpenCode plugin protocol:
14
- * - Outputs env var assignments as JSON: { "env": { "KEY": "VALUE" } }
15
- * - Exit 0 = success
16
- */
17
-
18
- "use strict";
19
-
20
- const { readFileSync, mkdirSync, appendFileSync, existsSync } = require("fs");
21
- const os = require("os");
22
- const path = require("path");
23
- const crypto = require("crypto");
24
-
25
- const PLUGIN_ROOT = process.env.OPENCODE_PLUGIN_ROOT || path.resolve(__dirname, "..");
26
- const GLOBAL_ROOT = process.env.BABYSITTER_GLOBAL_STATE_DIR || path.join(os.homedir(), ".a5c");
27
- const STATE_DIR = process.env.BABYSITTER_STATE_DIR || path.join(GLOBAL_ROOT, "state");
28
- const RUNS_DIR = process.env.BABYSITTER_RUNS_DIR || path.join(GLOBAL_ROOT, "runs");
29
- const LOG_DIR = process.env.BABYSITTER_LOG_DIR || path.join(GLOBAL_ROOT, "logs");
30
- const LOG_FILE = path.join(LOG_DIR, "babysitter-shell-env-hook.log");
31
-
32
- function ensureDir(dir) {
33
- try { mkdirSync(dir, { recursive: true }); } catch { /* best-effort */ }
34
- }
35
-
36
- function blog(msg) {
37
- ensureDir(LOG_DIR);
38
- const ts = new Date().toISOString();
39
- try {
40
- appendFileSync(LOG_FILE, `[INFO] ${ts} ${msg}\n`);
41
- } catch { /* best-effort */ }
42
- }
43
-
44
- function getSdkVersion() {
45
- try {
46
- const versions = JSON.parse(readFileSync(path.join(PLUGIN_ROOT, "versions.json"), "utf8"));
47
- return versions.sdkVersion || "latest";
48
- } catch {
49
- return "latest";
50
- }
51
- }
52
-
53
- function main() {
54
- blog("shell-env hook invoked");
55
-
56
- // Resolve or generate session ID
57
- const sessionId = process.env.BABYSITTER_SESSION_ID
58
- || process.env.OPENCODE_SESSION_ID
59
- || crypto.randomUUID();
60
-
61
- const sdkVersion = getSdkVersion();
62
-
63
- // Build env vars to inject
64
- const env = {
65
- BABYSITTER_SESSION_ID: sessionId,
66
- OPENCODE_SESSION_ID: sessionId,
67
- BABYSITTER_STATE_DIR: STATE_DIR,
68
- BABYSITTER_RUNS_DIR: RUNS_DIR,
69
- OPENCODE_PLUGIN_ROOT: PLUGIN_ROOT,
70
- };
71
-
72
- // Add SDK version for downstream hooks
73
- if (sdkVersion && sdkVersion !== "latest") {
74
- env.BABYSITTER_SDK_VERSION = sdkVersion;
75
- }
76
-
77
- // Add global state dir if defined
78
- const globalStateDir = process.env.BABYSITTER_GLOBAL_STATE_DIR;
79
- if (globalStateDir) {
80
- env.BABYSITTER_GLOBAL_STATE_DIR = globalStateDir;
81
- }
82
-
83
- blog(`Injecting env: ${JSON.stringify(env)}`);
84
-
85
- process.stdout.write(JSON.stringify({ env }) + "\n");
86
- }
87
-
88
- main();
@@ -1,107 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Babysitter Tool Execute After Hook for OpenCode
4
- *
5
- * Fires after a tool execution in OpenCode. Delegates to
6
- * `babysitter hook:run --hook-type post-tool-use` for post-tool-use awareness.
7
- *
8
- * This hook can be used to:
9
- * - Log tool execution results for babysitter run observability
10
- * - Trigger babysitter effects based on tool outputs
11
- * - Update session state after tool executions
12
- *
13
- * OpenCode plugin protocol:
14
- * - Receives tool result context as JSON via stdin
15
- * - Outputs JSON to stdout
16
- * - Exit 0 = success
17
- */
18
-
19
- "use strict";
20
-
21
- const { execSync } = require("child_process");
22
- const { readFileSync, mkdirSync, appendFileSync } = require("fs");
23
- const os = require("os");
24
- const path = require("path");
25
-
26
- const PLUGIN_ROOT = process.env.OPENCODE_PLUGIN_ROOT || path.resolve(__dirname, "..");
27
- const GLOBAL_ROOT = process.env.BABYSITTER_GLOBAL_STATE_DIR || path.join(os.homedir(), ".a5c");
28
- const STATE_DIR = process.env.BABYSITTER_STATE_DIR || path.join(GLOBAL_ROOT, "state");
29
- const LOG_DIR = process.env.BABYSITTER_LOG_DIR || path.join(GLOBAL_ROOT, "logs");
30
- const LOG_FILE = path.join(LOG_DIR, "babysitter-tool-after-hook.log");
31
-
32
- function ensureDir(dir) {
33
- try { mkdirSync(dir, { recursive: true }); } catch { /* best-effort */ }
34
- }
35
-
36
- function blog(msg) {
37
- ensureDir(LOG_DIR);
38
- const ts = new Date().toISOString();
39
- try {
40
- appendFileSync(LOG_FILE, `[INFO] ${ts} ${msg}\n`);
41
- } catch { /* best-effort */ }
42
- }
43
-
44
- function getSdkVersion() {
45
- try {
46
- const versions = JSON.parse(readFileSync(path.join(PLUGIN_ROOT, "versions.json"), "utf8"));
47
- return versions.sdkVersion || "latest";
48
- } catch {
49
- return "latest";
50
- }
51
- }
52
-
53
- function main() {
54
- const sessionId = process.env.BABYSITTER_SESSION_ID
55
- || process.env.OPENCODE_SESSION_ID
56
- || "";
57
-
58
- if (!sessionId) {
59
- process.stdout.write("{}\n");
60
- return;
61
- }
62
-
63
- // Read stdin for tool result context
64
- let inputData = "";
65
- try {
66
- inputData = require("fs").readFileSync(0, "utf8");
67
- } catch {
68
- // No stdin available
69
- }
70
-
71
- blog(`tool-execute-after: session=${sessionId}`);
72
-
73
- const hookInput = JSON.stringify({
74
- session_id: sessionId,
75
- cwd: process.cwd(),
76
- harness: "opencode",
77
- plugin_root: PLUGIN_ROOT,
78
- tool_result: inputData ? JSON.parse(inputData) : {},
79
- });
80
-
81
- const sdkVersion = getSdkVersion();
82
- const args = [
83
- "hook:run",
84
- "--hook-type", "post-tool-use",
85
- "--harness", "opencode",
86
- "--plugin-root", PLUGIN_ROOT,
87
- "--state-dir", STATE_DIR,
88
- "--json",
89
- ];
90
-
91
- try {
92
- const result = execSync(`babysitter ${args.join(" ")}`, {
93
- input: hookInput,
94
- stdio: ["pipe", "pipe", "pipe"],
95
- timeout: 10000,
96
- env: { ...process.env, BABYSITTER_STATE_DIR: STATE_DIR },
97
- });
98
- const output = result.toString("utf8").trim();
99
- blog(`Hook result: ${output}`);
100
- process.stdout.write((output || "{}") + "\n");
101
- } catch {
102
- blog("Post-tool-use hook failed -- non-blocking");
103
- process.stdout.write("{}\n");
104
- }
105
- }
106
-
107
- main();
@@ -1,109 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Babysitter Tool Execute Before Hook for OpenCode
4
- *
5
- * Fires before a tool execution in OpenCode. Delegates to
6
- * `babysitter hook:run --hook-type pre-tool-use` for pre-tool-use awareness.
7
- *
8
- * This hook can be used to:
9
- * - Log tool invocations for babysitter run observability
10
- * - Block certain tool calls during specific orchestration phases
11
- * - Inject babysitter context into tool arguments
12
- *
13
- * OpenCode plugin protocol:
14
- * - Receives tool context as JSON via stdin
15
- * - Outputs JSON to stdout (empty = allow, { block: true } = block)
16
- * - Exit 0 = success
17
- */
18
-
19
- "use strict";
20
-
21
- const { execSync } = require("child_process");
22
- const { readFileSync, mkdirSync, appendFileSync } = require("fs");
23
- const os = require("os");
24
- const path = require("path");
25
-
26
- const PLUGIN_ROOT = process.env.OPENCODE_PLUGIN_ROOT || path.resolve(__dirname, "..");
27
- const GLOBAL_ROOT = process.env.BABYSITTER_GLOBAL_STATE_DIR || path.join(os.homedir(), ".a5c");
28
- const STATE_DIR = process.env.BABYSITTER_STATE_DIR || path.join(GLOBAL_ROOT, "state");
29
- const LOG_DIR = process.env.BABYSITTER_LOG_DIR || path.join(GLOBAL_ROOT, "logs");
30
- const LOG_FILE = path.join(LOG_DIR, "babysitter-tool-before-hook.log");
31
-
32
- function ensureDir(dir) {
33
- try { mkdirSync(dir, { recursive: true }); } catch { /* best-effort */ }
34
- }
35
-
36
- function blog(msg) {
37
- ensureDir(LOG_DIR);
38
- const ts = new Date().toISOString();
39
- try {
40
- appendFileSync(LOG_FILE, `[INFO] ${ts} ${msg}\n`);
41
- } catch { /* best-effort */ }
42
- }
43
-
44
- function getSdkVersion() {
45
- try {
46
- const versions = JSON.parse(readFileSync(path.join(PLUGIN_ROOT, "versions.json"), "utf8"));
47
- return versions.sdkVersion || "latest";
48
- } catch {
49
- return "latest";
50
- }
51
- }
52
-
53
- function main() {
54
- const sessionId = process.env.BABYSITTER_SESSION_ID
55
- || process.env.OPENCODE_SESSION_ID
56
- || "";
57
-
58
- if (!sessionId) {
59
- // No session -- pass through without intervention
60
- process.stdout.write("{}\n");
61
- return;
62
- }
63
-
64
- // Read stdin for tool context
65
- let inputData = "";
66
- try {
67
- inputData = require("fs").readFileSync(0, "utf8");
68
- } catch {
69
- // No stdin available
70
- }
71
-
72
- blog(`tool-execute-before: session=${sessionId}`);
73
-
74
- const hookInput = JSON.stringify({
75
- session_id: sessionId,
76
- cwd: process.cwd(),
77
- harness: "opencode",
78
- plugin_root: PLUGIN_ROOT,
79
- tool_context: inputData ? JSON.parse(inputData) : {},
80
- });
81
-
82
- const sdkVersion = getSdkVersion();
83
- const args = [
84
- "hook:run",
85
- "--hook-type", "pre-tool-use",
86
- "--harness", "opencode",
87
- "--plugin-root", PLUGIN_ROOT,
88
- "--state-dir", STATE_DIR,
89
- "--json",
90
- ];
91
-
92
- try {
93
- const result = execSync(`babysitter ${args.join(" ")}`, {
94
- input: hookInput,
95
- stdio: ["pipe", "pipe", "pipe"],
96
- timeout: 10000,
97
- env: { ...process.env, BABYSITTER_STATE_DIR: STATE_DIR },
98
- });
99
- const output = result.toString("utf8").trim();
100
- blog(`Hook result: ${output}`);
101
- process.stdout.write((output || "{}") + "\n");
102
- } catch {
103
- // On failure, allow the tool execution to proceed
104
- blog("Pre-tool-use hook failed -- allowing execution");
105
- process.stdout.write("{}\n");
106
- }
107
- }
108
-
109
- main();