@a5c-ai/babysitter-opencode 5.0.1-staging.d73033a7 → 5.0.1-staging.daf8e165bc4a

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.
Files changed (63) hide show
  1. package/README.md +19 -21
  2. package/bin/cli.cjs +1 -191
  3. package/bin/cli.js +90 -49
  4. package/bin/install-shared.cjs +1 -478
  5. package/bin/install-shared.js +615 -0
  6. package/bin/install.cjs +1 -143
  7. package/bin/install.js +18 -98
  8. package/bin/uninstall.cjs +1 -87
  9. package/bin/uninstall.js +12 -34
  10. package/commands/blueprints.md +64 -0
  11. package/commands/call.md +11 -7
  12. package/commands/check-forbidden-markers.md +68 -0
  13. package/commands/cleanup.md +37 -9
  14. package/commands/contrib.md +31 -31
  15. package/commands/doctor.md +7 -8
  16. package/commands/forever.md +6 -6
  17. package/commands/help.md +246 -244
  18. package/commands/observe.md +17 -12
  19. package/commands/plan.md +17 -7
  20. package/commands/plugins.md +22 -255
  21. package/commands/project-install.md +10 -10
  22. package/commands/resume.md +8 -8
  23. package/commands/retrospect.md +55 -55
  24. package/commands/user-install.md +10 -10
  25. package/commands/yolo.md +11 -7
  26. package/hooks/babysitter-proxied-session-created.js +20 -212
  27. package/hooks/babysitter-proxied-session-created.sh +11 -0
  28. package/hooks/babysitter-proxied-shell-env.js +23 -145
  29. package/hooks/babysitter-proxied-shell-env.sh +3 -0
  30. package/hooks/babysitter-proxied-stop-hook.sh +3 -0
  31. package/hooks/babysitter-proxied-tool-execute-after.js +22 -160
  32. package/hooks/babysitter-proxied-tool-execute-after.sh +3 -0
  33. package/hooks/babysitter-proxied-tool-execute-before.js +22 -162
  34. package/hooks/babysitter-proxied-tool-execute-before.sh +3 -0
  35. package/hooks/hooks.json +14 -22
  36. package/package.json +21 -19
  37. package/plugin.json +6 -4
  38. package/scripts/create-release-tag.mjs +18 -0
  39. package/scripts/publish-from-tag.mjs +41 -0
  40. package/scripts/team-install.js +23 -0
  41. package/skills/accomplish-status/SKILL.md +8 -2
  42. package/skills/babysit/SKILL.md +35 -10
  43. package/skills/blueprints/SKILL.md +66 -0
  44. package/skills/call/SKILL.md +5 -1
  45. package/skills/check-forbidden-markers/SKILL.md +69 -0
  46. package/skills/cleanup/SKILL.md +37 -9
  47. package/skills/doctor/SKILL.md +7 -8
  48. package/skills/help/SKILL.md +13 -11
  49. package/skills/observe/SKILL.md +7 -2
  50. package/skills/plan/SKILL.md +11 -1
  51. package/skills/plugins/SKILL.md +12 -245
  52. package/skills/yolo/SKILL.md +5 -1
  53. package/versions.json +2 -2
  54. package/hooks/babysitter-proxied-session-idle.js +0 -173
  55. package/hooks/hooks.json.legacy +0 -46
  56. package/hooks/proxied-hooks.json +0 -47
  57. package/hooks/session-created.js +0 -182
  58. package/hooks/session-idle.js +0 -124
  59. package/hooks/shell-env.js +0 -88
  60. package/hooks/tool-execute-after.js +0 -107
  61. package/hooks/tool-execute-before.js +0 -109
  62. package/scripts/sync-command-docs.cjs +0 -107
  63. package/scripts/sync-command-surfaces.js +0 -52
@@ -1,173 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Unified Session Idle Hook for OpenCode
4
- * Routes through hooks-proxy for all hook execution.
5
- *
6
- * Fires when the OpenCode agent goes idle. Checks if the current babysitter
7
- * run has pending effects that need attention. Since OpenCode does NOT have a
8
- * blocking stop hook, this is fire-and-forget -- it outputs context about
9
- * pending effects so the agent can decide whether to continue iterating.
10
- *
11
- * Delegates to `babysitter hook:run --hook-type stop` via hooks-proxy.
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, existsSync, writeFileSync } = 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
- const PROXY_MARKER = path.join(PLUGIN_ROOT, ".hooks-proxy-install-attempted");
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
- function getSdkVersion() {
46
- try {
47
- const versions = JSON.parse(readFileSync(path.join(PLUGIN_ROOT, "versions.json"), "utf8"));
48
- return versions.sdkVersion || "latest";
49
- } catch {
50
- return "latest";
51
- }
52
- }
53
-
54
- function resolveHooksProxy() {
55
- try {
56
- execSync("a5c-hooks-proxy --version", { stdio: "pipe", timeout: 5000 });
57
- return "a5c-hooks-proxy";
58
- } catch { /* not in PATH */ }
59
-
60
- const localProxy = path.join(
61
- process.env.HOME || process.env.USERPROFILE || "~",
62
- ".local", "bin", process.platform === "win32" ? "a5c-hooks-proxy.exe" : "a5c-hooks-proxy"
63
- );
64
- if (existsSync(localProxy)) {
65
- return localProxy;
66
- }
67
-
68
- return null;
69
- }
70
-
71
- function installHooksProxy(version) {
72
- if (existsSync(PROXY_MARKER)) return;
73
-
74
- try {
75
- execSync(`npm i -g "@a5c-ai/hooks-proxy-cli@${version}" --loglevel=error`, {
76
- stdio: "pipe",
77
- timeout: 120000,
78
- });
79
- blog(`Installed hooks-proxy globally (${version})`);
80
- } catch {
81
- try {
82
- const prefix = path.join(process.env.HOME || process.env.USERPROFILE || "~", ".local");
83
- execSync(`npm i -g "@a5c-ai/hooks-proxy-cli@${version}" --prefix "${prefix}" --loglevel=error`, {
84
- stdio: "pipe",
85
- timeout: 120000,
86
- });
87
- blog(`Installed hooks-proxy to user prefix (${version})`);
88
- } catch {
89
- blog("hooks-proxy installation failed");
90
- }
91
- }
92
-
93
- try { writeFileSync(PROXY_MARKER, version); } catch { /* best-effort */ }
94
- }
95
-
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`;
98
- const result = execSync(`"${proxy}" invoke --adapter opencode --handler "${handler}" --json`, {
99
- input: inputJson,
100
- stdio: ["pipe", "pipe", "pipe"],
101
- timeout: 30000,
102
- env: { ...process.env, BABYSITTER_STATE_DIR: STATE_DIR },
103
- });
104
- return result.toString("utf8").trim();
105
- }
106
-
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`;
109
- const result = execSync(`npx -y "@a5c-ai/hooks-proxy-cli@${version}" invoke --adapter opencode --handler "${handler}" --json`, {
110
- input: inputJson,
111
- stdio: ["pipe", "pipe", "pipe"],
112
- timeout: 60000,
113
- env: { ...process.env, BABYSITTER_STATE_DIR: STATE_DIR },
114
- });
115
- return result.toString("utf8").trim();
116
- }
117
-
118
- function main() {
119
- blog("Unified session-idle hook invoked");
120
-
121
- const sessionId = process.env.BABYSITTER_SESSION_ID
122
- || process.env.OPENCODE_SESSION_ID
123
- || "";
124
-
125
- if (!sessionId) {
126
- blog("No session ID -- nothing to check");
127
- process.stdout.write("{}\n");
128
- return;
129
- }
130
-
131
- const sdkVersion = getSdkVersion();
132
-
133
- // Ensure hooks-proxy is installed
134
- let proxy = resolveHooksProxy();
135
- if (!proxy) {
136
- installHooksProxy(sdkVersion);
137
- proxy = resolveHooksProxy();
138
- }
139
-
140
- const hookInput = JSON.stringify({
141
- session_id: sessionId,
142
- cwd: process.cwd(),
143
- harness: "opencode",
144
- plugin_root: PLUGIN_ROOT,
145
- });
146
-
147
- blog(`Checking run status for session ${sessionId}`);
148
-
149
- let result;
150
- try {
151
- if (proxy) {
152
- blog(`Using hooks-proxy: ${proxy}`);
153
- result = runViaProxy(proxy, "stop", hookInput);
154
- } else {
155
- blog("hooks-proxy not found after install, using npx fallback");
156
- result = runViaNpxProxy(sdkVersion, "stop", hookInput);
157
- }
158
- } catch (err) {
159
- blog(`Hook execution failed: ${err.message}`);
160
- result = "{}";
161
- }
162
-
163
- blog(`Hook result: ${result}`);
164
-
165
- try {
166
- const parsed = JSON.parse(result);
167
- process.stdout.write(JSON.stringify(parsed) + "\n");
168
- } catch {
169
- process.stdout.write("{}\n");
170
- }
171
- }
172
-
173
- main();
@@ -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,47 +0,0 @@
1
- {
2
- "_comment": "NOT ACTIVE — Alternative hooks.json using per-hook unified scripts with hooks-proxy support. To activate, replace hooks.json with this file.",
3
- "version": 1,
4
- "description": "Babysitter hook registration for OpenCode. Maps OpenCode plugin events to unified babysitter hook scripts with hooks-proxy support.",
5
- "hooks": {
6
- "session.created": [
7
- {
8
- "type": "command",
9
- "script": "hooks/babysitter-proxied-session-created.js",
10
- "description": "Initialize babysitter session state and inject context (proxied via a5c-hooks-proxy)",
11
- "timeoutMs": 30000
12
- }
13
- ],
14
- "session.idle": [
15
- {
16
- "type": "command",
17
- "script": "hooks/babysitter-proxied-session-idle.js",
18
- "description": "Check for pending babysitter effects when agent goes idle (proxied via a5c-hooks-proxy)",
19
- "timeoutMs": 30000
20
- }
21
- ],
22
- "shell.env": [
23
- {
24
- "type": "command",
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)",
27
- "timeoutMs": 5000
28
- }
29
- ],
30
- "tool.execute.before": [
31
- {
32
- "type": "command",
33
- "script": "hooks/babysitter-proxied-tool-execute-before.js",
34
- "description": "Pre-tool-use hook for babysitter awareness (proxied via a5c-hooks-proxy)",
35
- "timeoutMs": 10000
36
- }
37
- ],
38
- "tool.execute.after": [
39
- {
40
- "type": "command",
41
- "script": "hooks/babysitter-proxied-tool-execute-after.js",
42
- "description": "Post-tool-use hook for babysitter awareness (proxied via a5c-hooks-proxy)",
43
- "timeoutMs": 10000
44
- }
45
- ]
46
- }
47
- }
@@ -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();