@a5c-ai/babysitter-codex 0.1.11-staging.f6cb97d6 → 5.0.0
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/.codex-plugin/plugin.json +14 -12
- package/README.md +17 -15
- package/assets/logo.png +0 -0
- package/bin/cli.js +8 -16
- package/bin/install-shared.js +360 -63
- package/bin/install.js +12 -30
- package/bin/uninstall.js +11 -27
- package/hooks/babysitter-proxied-session-start.sh +11 -0
- package/hooks/babysitter-proxied-stop.sh +3 -0
- package/hooks/babysitter-proxied-user-prompt-submit.sh +3 -0
- package/hooks.json +5 -5
- package/package.json +13 -16
- package/plugin.lock.json +153 -0
- package/scripts/create-release-tag.mjs +18 -0
- package/scripts/publish-from-tag.mjs +12 -0
- package/scripts/team-install.js +14 -77
- package/skills/babysit/SKILL.md +2 -0
- package/skills/cleanup/SKILL.md +21 -0
- package/skills/contrib/SKILL.md +34 -0
- package/skills/doctor/SKILL.md +5 -5
- package/skills/help/SKILL.md +3 -2
- package/skills/observe/SKILL.md +1 -1
- package/skills/plugins/SKILL.md +257 -0
- package/babysitter.lock.json +0 -18
- package/hooks/babysitter-session-start.sh +0 -44
- package/hooks/babysitter-stop-hook.sh +0 -44
- package/hooks/user-prompt-submit.sh +0 -33
- package/scripts/sync-command-skills.js +0 -45
- package/skills/issue/SKILL.md +0 -16
- package/skills/model/SKILL.md +0 -15
- package/skills/team-install/SKILL.md +0 -15
package/bin/install-shared.js
CHANGED
|
@@ -5,8 +5,196 @@ const os = require('os');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const { spawnSync } = require('child_process');
|
|
7
7
|
|
|
8
|
-
const PLUGIN_NAME =
|
|
8
|
+
const PLUGIN_NAME = "babysitter";
|
|
9
9
|
const PLUGIN_CATEGORY = 'Coding';
|
|
10
|
+
|
|
11
|
+
function getUserHome() {
|
|
12
|
+
return os.homedir();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getHarnessHome() {
|
|
16
|
+
return path.join(os.homedir(), ".codex");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getHomePluginRoot(scope) {
|
|
20
|
+
if (scope === 'workspace') return path.join(process.cwd(), '.a5c', 'plugins', PLUGIN_NAME);
|
|
21
|
+
return path.join(path.join(os.homedir(), ".agents/plugins"), PLUGIN_NAME);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getHomeMarketplacePath() {
|
|
25
|
+
return path.join(os.homedir(), ".agents/plugins/marketplace.json");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function writeFileIfChanged(filePath, contents) {
|
|
29
|
+
try {
|
|
30
|
+
const existing = fs.readFileSync(filePath, 'utf8');
|
|
31
|
+
if (existing === contents) return false;
|
|
32
|
+
} catch {}
|
|
33
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
34
|
+
fs.writeFileSync(filePath, contents);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function copyRecursive(src, dest) {
|
|
39
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
40
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
41
|
+
if (entry.name === 'node_modules' || entry.name === '.git') continue;
|
|
42
|
+
const s = path.join(src, entry.name);
|
|
43
|
+
const d = path.join(dest, entry.name);
|
|
44
|
+
if (entry.isDirectory()) {
|
|
45
|
+
copyRecursive(s, d);
|
|
46
|
+
} else {
|
|
47
|
+
fs.copyFileSync(s, d);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function copyPluginBundle(packageRoot, pluginRoot) {
|
|
53
|
+
const bundleEntries = fs.readdirSync(packageRoot).filter(
|
|
54
|
+
e => !['node_modules', '.git', 'test', 'dist'].includes(e)
|
|
55
|
+
);
|
|
56
|
+
fs.mkdirSync(pluginRoot, { recursive: true });
|
|
57
|
+
for (const entry of bundleEntries) {
|
|
58
|
+
const src = path.join(packageRoot, entry);
|
|
59
|
+
const dest = path.join(pluginRoot, entry);
|
|
60
|
+
const stat = fs.statSync(src);
|
|
61
|
+
if (stat.isDirectory()) {
|
|
62
|
+
copyRecursive(src, dest);
|
|
63
|
+
} else {
|
|
64
|
+
fs.copyFileSync(src, dest);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function readJson(filePath) {
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function writeJson(filePath, value) {
|
|
78
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
79
|
+
fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\n');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function ensureExecutable(filePath) {
|
|
83
|
+
try {
|
|
84
|
+
fs.chmodSync(filePath, 0o755);
|
|
85
|
+
} catch {}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function normalizeMarketplaceSourcePath(source, marketplacePath) {
|
|
89
|
+
if (typeof source === 'string') {
|
|
90
|
+
return path.relative(path.dirname(marketplacePath), source).replace(/\\/g, '/');
|
|
91
|
+
}
|
|
92
|
+
return source;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function ensureMarketplaceEntry(marketplacePath, pluginRoot) {
|
|
96
|
+
let marketplace = readJson(marketplacePath) || {
|
|
97
|
+
name: "a5c.ai",
|
|
98
|
+
plugins: [],
|
|
99
|
+
};
|
|
100
|
+
if (!Array.isArray(marketplace.plugins)) marketplace.plugins = [];
|
|
101
|
+
const idx = marketplace.plugins.findIndex(p => p.name === PLUGIN_NAME);
|
|
102
|
+
const relSource = './' + normalizeMarketplaceSourcePath(pluginRoot, marketplacePath);
|
|
103
|
+
const entry = {
|
|
104
|
+
name: PLUGIN_NAME,
|
|
105
|
+
source: relSource,
|
|
106
|
+
description: "Orchestrate complex, multi-step workflows with event-sourced state management, hook-based extensibility, and human-in-the-loop approval",
|
|
107
|
+
version: "5.0.0",
|
|
108
|
+
author: { name: "a5c.ai" },
|
|
109
|
+
};
|
|
110
|
+
if (idx >= 0) marketplace.plugins[idx] = entry;
|
|
111
|
+
else marketplace.plugins.push(entry);
|
|
112
|
+
writeJson(marketplacePath, marketplace);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function removeMarketplaceEntry(marketplacePath) {
|
|
116
|
+
const marketplace = readJson(marketplacePath);
|
|
117
|
+
if (!marketplace || !Array.isArray(marketplace.plugins)) return;
|
|
118
|
+
marketplace.plugins = marketplace.plugins.filter(p => p.name !== PLUGIN_NAME);
|
|
119
|
+
writeJson(marketplacePath, marketplace);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function warnWindowsHooks() {
|
|
123
|
+
if (process.platform === 'win32') {
|
|
124
|
+
console.warn('[' + PLUGIN_NAME + '] Windows detected — shell hooks (.sh) require Git Bash or WSL.');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function runPostInstall(pluginRoot) {
|
|
129
|
+
const postInstall = path.join(pluginRoot, 'scripts', 'post-install.js');
|
|
130
|
+
if (fs.existsSync(postInstall)) {
|
|
131
|
+
spawnSync(process.execPath, [postInstall], {
|
|
132
|
+
cwd: pluginRoot, stdio: 'inherit',
|
|
133
|
+
env: { ...process.env, PLUGIN_ROOT: pluginRoot },
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function getGlobalStateDir() {
|
|
139
|
+
return process.env.BABYSITTER_GLOBAL_STATE_DIR || path.join(getUserHome(), '.a5c');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function resolveCliCommand(packageRoot) {
|
|
143
|
+
try {
|
|
144
|
+
const result = spawnSync('babysitter', ['--version'], { stdio: 'pipe', timeout: 10000 });
|
|
145
|
+
if (result.status === 0) return 'babysitter';
|
|
146
|
+
} catch {}
|
|
147
|
+
const versionsPath = path.join(packageRoot, 'versions.json');
|
|
148
|
+
const versions = readJson(versionsPath) || {};
|
|
149
|
+
const ver = versions.sdkVersion || 'latest';
|
|
150
|
+
return `npx -y @a5c-ai/babysitter-sdk@${ver}`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function runCli(packageRoot, cliArgs, options = {}) {
|
|
154
|
+
const cmd = resolveCliCommand(packageRoot);
|
|
155
|
+
const parts = cmd.split(' ');
|
|
156
|
+
const result = spawnSync(parts[0], [...parts.slice(1), ...cliArgs], {
|
|
157
|
+
stdio: options.stdio || 'inherit',
|
|
158
|
+
timeout: options.timeout || 120000,
|
|
159
|
+
cwd: options.cwd || process.cwd(),
|
|
160
|
+
env: { ...process.env, ...options.env },
|
|
161
|
+
});
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function ensureGlobalProcessLibrary(packageRoot) {
|
|
166
|
+
const stateDir = getGlobalStateDir();
|
|
167
|
+
const activeFile = path.join(stateDir, 'active', 'process-library.json');
|
|
168
|
+
let active = readJson(activeFile);
|
|
169
|
+
if (active && active.binding && active.binding.dir) {
|
|
170
|
+
return active;
|
|
171
|
+
}
|
|
172
|
+
const defaultSpec = readJson(path.join(stateDir, 'process-library-defaults.json'));
|
|
173
|
+
const cloneDir = defaultSpec && defaultSpec.cloneDir
|
|
174
|
+
? defaultSpec.cloneDir
|
|
175
|
+
: path.join(stateDir, 'process-library', PLUGIN_NAME + '-repo');
|
|
176
|
+
runCli(packageRoot, [
|
|
177
|
+
'process-library:clone',
|
|
178
|
+
'--dir', cloneDir,
|
|
179
|
+
'--state-dir', stateDir,
|
|
180
|
+
'--json',
|
|
181
|
+
], { stdio: 'pipe' });
|
|
182
|
+
runCli(packageRoot, [
|
|
183
|
+
'process-library:use',
|
|
184
|
+
'--dir', cloneDir,
|
|
185
|
+
'--state-dir', stateDir,
|
|
186
|
+
'--json',
|
|
187
|
+
], { stdio: 'pipe' });
|
|
188
|
+
active = readJson(activeFile);
|
|
189
|
+
return {
|
|
190
|
+
binding: active && active.binding ? active.binding : { dir: cloneDir },
|
|
191
|
+
defaultSpec: defaultSpec || { cloneDir },
|
|
192
|
+
stateFile: activeFile,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
const LEGACY_MARKETPLACE_PLUGIN_NAMES = ['babysitter-codex'];
|
|
10
198
|
const LEGACY_SKILL_NAMES = [
|
|
11
199
|
'babysit',
|
|
12
200
|
'babysitter-codex',
|
|
@@ -49,6 +237,11 @@ const LEGACY_HOOK_SCRIPT_NAMES = [
|
|
|
49
237
|
'babysitter-stop-hook.sh',
|
|
50
238
|
'user-prompt-submit.sh',
|
|
51
239
|
];
|
|
240
|
+
const MANAGED_HOOK_SCRIPT_NAMES = [
|
|
241
|
+
'babysitter-proxied-session-start.sh',
|
|
242
|
+
'babysitter-proxied-stop.sh',
|
|
243
|
+
'babysitter-proxied-user-prompt-submit.sh',
|
|
244
|
+
];
|
|
52
245
|
const DEFAULT_MARKETPLACE = {
|
|
53
246
|
name: 'local-plugins',
|
|
54
247
|
interface: {
|
|
@@ -58,12 +251,13 @@ const DEFAULT_MARKETPLACE = {
|
|
|
58
251
|
};
|
|
59
252
|
const PLUGIN_BUNDLE_ENTRIES = [
|
|
60
253
|
'.codex-plugin',
|
|
61
|
-
'.app.json',
|
|
62
254
|
'assets',
|
|
63
255
|
'hooks',
|
|
64
256
|
'hooks.json',
|
|
65
257
|
'skills',
|
|
66
|
-
'
|
|
258
|
+
'.app.json',
|
|
259
|
+
'plugin.lock.json',
|
|
260
|
+
'README.md',
|
|
67
261
|
];
|
|
68
262
|
|
|
69
263
|
function getCodexHome() {
|
|
@@ -71,24 +265,11 @@ function getCodexHome() {
|
|
|
71
265
|
return path.join(os.homedir(), '.codex');
|
|
72
266
|
}
|
|
73
267
|
|
|
74
|
-
function getUserHome() {
|
|
75
|
-
if (process.env.USERPROFILE) return path.resolve(process.env.USERPROFILE);
|
|
76
|
-
if (process.env.HOME) return path.resolve(process.env.HOME);
|
|
77
|
-
return os.homedir();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function getGlobalStateDir() {
|
|
81
|
-
if (process.env.BABYSITTER_GLOBAL_STATE_DIR) {
|
|
82
|
-
return path.resolve(process.env.BABYSITTER_GLOBAL_STATE_DIR);
|
|
83
|
-
}
|
|
84
|
-
return path.join(getUserHome(), '.a5c');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
268
|
function getHomePluginRoot() {
|
|
88
269
|
if (process.env.BABYSITTER_CODEX_PLUGIN_DIR) {
|
|
89
270
|
return path.resolve(process.env.BABYSITTER_CODEX_PLUGIN_DIR, PLUGIN_NAME);
|
|
90
271
|
}
|
|
91
|
-
return path.join(
|
|
272
|
+
return path.join(getUserHome(), '.agents', 'plugins', PLUGIN_NAME);
|
|
92
273
|
}
|
|
93
274
|
|
|
94
275
|
function getHomeMarketplacePath() {
|
|
@@ -98,6 +279,14 @@ function getHomeMarketplacePath() {
|
|
|
98
279
|
return path.join(getUserHome(), '.agents', 'plugins', 'marketplace.json');
|
|
99
280
|
}
|
|
100
281
|
|
|
282
|
+
function getWorkspacePluginRoot(workspaceRoot) {
|
|
283
|
+
return path.join(path.resolve(workspaceRoot), '.agents', 'plugins', PLUGIN_NAME);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function getWorkspaceMarketplacePath(workspaceRoot) {
|
|
287
|
+
return path.join(path.resolve(workspaceRoot), '.agents', 'plugins', 'marketplace.json');
|
|
288
|
+
}
|
|
289
|
+
|
|
101
290
|
function renderCodexConfigToml() {
|
|
102
291
|
return [
|
|
103
292
|
'approval_policy = "on-request"',
|
|
@@ -118,18 +307,6 @@ function renderCodexConfigToml() {
|
|
|
118
307
|
].join('\n');
|
|
119
308
|
}
|
|
120
309
|
|
|
121
|
-
function writeFileIfChanged(filePath, contents) {
|
|
122
|
-
if (fs.existsSync(filePath)) {
|
|
123
|
-
const current = fs.readFileSync(filePath, 'utf8');
|
|
124
|
-
if (current === contents) {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
129
|
-
fs.writeFileSync(filePath, contents, 'utf8');
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
310
|
function copyRecursive(src, dest) {
|
|
134
311
|
const stat = fs.statSync(src);
|
|
135
312
|
if (stat.isDirectory()) {
|
|
@@ -290,38 +467,77 @@ function runBabysitterCli(packageRoot, cliArgs, options = {}) {
|
|
|
290
467
|
}
|
|
291
468
|
|
|
292
469
|
function ensureGlobalProcessLibrary(packageRoot) {
|
|
293
|
-
|
|
470
|
+
const stateDir = getGlobalStateDir();
|
|
471
|
+
const activeFile = path.join(stateDir, 'active', 'process-library.json');
|
|
472
|
+
const current = readJson(activeFile);
|
|
473
|
+
if (current && current.defaultBinding && current.defaultBinding.dir) {
|
|
474
|
+
return {
|
|
475
|
+
stateFile: activeFile,
|
|
476
|
+
binding: current.defaultBinding,
|
|
477
|
+
defaultSpec: {
|
|
478
|
+
stateDir,
|
|
479
|
+
repo: current.defaultBinding.repoUrl,
|
|
480
|
+
cloneDir: current.defaultBinding.dir,
|
|
481
|
+
},
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const cloneDir = path.join(stateDir, 'process-library', `${PLUGIN_NAME}-repo`);
|
|
486
|
+
runBabysitterCli(
|
|
487
|
+
packageRoot,
|
|
488
|
+
[
|
|
489
|
+
'process-library:clone',
|
|
490
|
+
'--dir', cloneDir,
|
|
491
|
+
'--state-dir', stateDir,
|
|
492
|
+
'--json',
|
|
493
|
+
],
|
|
494
|
+
{ cwd: packageRoot },
|
|
495
|
+
);
|
|
496
|
+
runBabysitterCli(
|
|
497
|
+
packageRoot,
|
|
498
|
+
[
|
|
499
|
+
'process-library:use',
|
|
500
|
+
'--dir', cloneDir,
|
|
501
|
+
'--state-dir', stateDir,
|
|
502
|
+
'--json',
|
|
503
|
+
],
|
|
504
|
+
{ cwd: packageRoot },
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
const active = JSON.parse(
|
|
294
508
|
runBabysitterCli(
|
|
295
509
|
packageRoot,
|
|
296
|
-
['process-library:active', '--state-dir',
|
|
510
|
+
['process-library:active', '--state-dir', stateDir, '--json'],
|
|
297
511
|
{ cwd: packageRoot },
|
|
298
512
|
),
|
|
299
513
|
);
|
|
300
|
-
}
|
|
301
514
|
|
|
302
|
-
|
|
303
|
-
|
|
515
|
+
return {
|
|
516
|
+
stateFile: active.stateFile || activeFile,
|
|
517
|
+
binding: active.binding || active.defaultBinding || { dir: cloneDir },
|
|
518
|
+
defaultSpec: active.defaultSpec || {
|
|
519
|
+
stateDir,
|
|
520
|
+
repo: process.env.BABYSITTER_PROCESS_LIBRARY_REPO || null,
|
|
521
|
+
cloneDir,
|
|
522
|
+
},
|
|
523
|
+
};
|
|
304
524
|
}
|
|
305
525
|
|
|
306
|
-
function
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
function ensureExecutable(filePath) {
|
|
311
|
-
try {
|
|
312
|
-
fs.chmodSync(filePath, 0o755);
|
|
313
|
-
} catch {
|
|
314
|
-
// Best-effort only. Windows and some filesystems may ignore mode changes.
|
|
315
|
-
}
|
|
526
|
+
function getMarketplaceRootDir(marketplacePath) {
|
|
527
|
+
const pluginsDir = path.dirname(marketplacePath);
|
|
528
|
+
const dotAgentsDir = path.dirname(pluginsDir);
|
|
529
|
+
return path.dirname(dotAgentsDir);
|
|
316
530
|
}
|
|
317
531
|
|
|
318
532
|
function normalizeMarketplaceSourcePath(marketplacePath, pluginSourcePath) {
|
|
319
|
-
let next = pluginSourcePath;
|
|
320
|
-
if (path.isAbsolute(next)) {
|
|
321
|
-
next = path.relative(path.dirname(marketplacePath), next);
|
|
322
|
-
}
|
|
533
|
+
let next = path.relative(getMarketplaceRootDir(marketplacePath), pluginSourcePath);
|
|
323
534
|
next = String(next || '').replace(/\\/g, '/');
|
|
324
|
-
if (!next.
|
|
535
|
+
if (!next || next === '.' || next.startsWith('../')) {
|
|
536
|
+
throw new Error(
|
|
537
|
+
`Plugin source path must live under ${getMarketplaceRootDir(marketplacePath)} so Codex can load it via a ./-prefixed marketplace entry.`,
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
if (!next.startsWith('./')) {
|
|
325
541
|
next = `./${next}`;
|
|
326
542
|
}
|
|
327
543
|
return next;
|
|
@@ -347,15 +563,15 @@ function ensureMarketplaceEntry(marketplacePath, pluginSourcePath) {
|
|
|
347
563
|
},
|
|
348
564
|
category: PLUGIN_CATEGORY,
|
|
349
565
|
};
|
|
350
|
-
const existingIndex = Array.isArray(marketplace.plugins)
|
|
351
|
-
? marketplace.plugins.findIndex((entry) => entry && entry.name === PLUGIN_NAME)
|
|
352
|
-
: -1;
|
|
353
566
|
if (!Array.isArray(marketplace.plugins)) {
|
|
354
567
|
marketplace.plugins = [nextEntry];
|
|
355
|
-
} else if (existingIndex >= 0) {
|
|
356
|
-
marketplace.plugins[existingIndex] = nextEntry;
|
|
357
568
|
} else {
|
|
358
|
-
marketplace.plugins.
|
|
569
|
+
const sanitized = marketplace.plugins.filter((entry) => (
|
|
570
|
+
entry &&
|
|
571
|
+
entry.name !== PLUGIN_NAME &&
|
|
572
|
+
!LEGACY_MARKETPLACE_PLUGIN_NAMES.includes(entry.name)
|
|
573
|
+
));
|
|
574
|
+
marketplace.plugins = [...sanitized, nextEntry];
|
|
359
575
|
}
|
|
360
576
|
writeJson(marketplacePath, marketplace);
|
|
361
577
|
return nextEntry;
|
|
@@ -369,7 +585,11 @@ function removeMarketplaceEntry(marketplacePath) {
|
|
|
369
585
|
if (!Array.isArray(marketplace.plugins)) {
|
|
370
586
|
return;
|
|
371
587
|
}
|
|
372
|
-
marketplace.plugins = marketplace.plugins.filter((entry) =>
|
|
588
|
+
marketplace.plugins = marketplace.plugins.filter((entry) => (
|
|
589
|
+
entry &&
|
|
590
|
+
entry.name !== PLUGIN_NAME &&
|
|
591
|
+
!LEGACY_MARKETPLACE_PLUGIN_NAMES.includes(entry.name)
|
|
592
|
+
));
|
|
373
593
|
writeJson(marketplacePath, marketplace);
|
|
374
594
|
}
|
|
375
595
|
|
|
@@ -469,7 +689,7 @@ function installManagedHooks(packageRoot, codexHome) {
|
|
|
469
689
|
const targetRoot = path.join(codexHome, 'hooks');
|
|
470
690
|
fs.mkdirSync(targetRoot, { recursive: true });
|
|
471
691
|
|
|
472
|
-
for (const scriptName of
|
|
692
|
+
for (const scriptName of MANAGED_HOOK_SCRIPT_NAMES) {
|
|
473
693
|
const sourcePath = path.join(sourceRoot, scriptName);
|
|
474
694
|
const targetPath = path.join(targetRoot, scriptName);
|
|
475
695
|
copyRecursive(sourcePath, targetPath);
|
|
@@ -485,6 +705,46 @@ function installCodexSurface(packageRoot, codexHome) {
|
|
|
485
705
|
installManagedHooks(packageRoot, codexHome);
|
|
486
706
|
}
|
|
487
707
|
|
|
708
|
+
function harnessTeamInstall(packageRoot, pluginRoot, workspace) {
|
|
709
|
+
var workspaceRoot = path.resolve(workspace);
|
|
710
|
+
var resolvedPluginRoot = pluginRoot ? path.resolve(pluginRoot) : getWorkspacePluginRoot(workspaceRoot);
|
|
711
|
+
var marketplacePath = getWorkspaceMarketplacePath(workspaceRoot);
|
|
712
|
+
var codexHome = path.join(workspaceRoot, '.codex');
|
|
713
|
+
var codexConfigPath = path.join(codexHome, 'config.toml');
|
|
714
|
+
var teamDir = path.join(workspaceRoot, '.a5c', 'team');
|
|
715
|
+
|
|
716
|
+
var processLibraryState = ensureGlobalProcessLibrary(packageRoot);
|
|
717
|
+
ensureMarketplaceEntry(marketplacePath, resolvedPluginRoot);
|
|
718
|
+
mergeCodexConfigFile(codexConfigPath);
|
|
719
|
+
installCodexSurface(packageRoot, codexHome);
|
|
720
|
+
warnWindowsHooks();
|
|
721
|
+
|
|
722
|
+
writeJson(path.join(teamDir, 'install.json'), {
|
|
723
|
+
packageRoot: packageRoot,
|
|
724
|
+
workspaceRoot: workspaceRoot,
|
|
725
|
+
pluginRoot: resolvedPluginRoot,
|
|
726
|
+
marketplacePath: marketplacePath,
|
|
727
|
+
codexConfigPath: codexConfigPath,
|
|
728
|
+
processLibraryCloneDir: (processLibraryState.defaultSpec && processLibraryState.defaultSpec.cloneDir)
|
|
729
|
+
|| (processLibraryState.binding && processLibraryState.binding.dir),
|
|
730
|
+
processLibraryStateFile: processLibraryState.stateFile
|
|
731
|
+
|| path.join(getGlobalStateDir(), 'active', 'process-library.json'),
|
|
732
|
+
});
|
|
733
|
+
writeJson(path.join(teamDir, 'profile.json'), {
|
|
734
|
+
pluginRoot: resolvedPluginRoot,
|
|
735
|
+
marketplacePath: marketplacePath,
|
|
736
|
+
codexConfigPath: codexConfigPath,
|
|
737
|
+
processLibraryLookupCommand: 'babysitter process-library:active --json',
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
function harnessInstall(packageRoot, _pluginRoot) {
|
|
742
|
+
const codexConfigPath = path.join(getCodexHome(), 'config.toml');
|
|
743
|
+
mergeCodexConfigFile(codexConfigPath);
|
|
744
|
+
ensureGlobalProcessLibrary(packageRoot);
|
|
745
|
+
warnWindowsHooks();
|
|
746
|
+
}
|
|
747
|
+
|
|
488
748
|
function warnWindowsHooks() {
|
|
489
749
|
if (process.platform !== 'win32') {
|
|
490
750
|
return;
|
|
@@ -496,17 +756,54 @@ function warnWindowsHooks() {
|
|
|
496
756
|
console.warn('[babysitter] If hooks do not fire, run `codex --version` and upgrade if you are below 0.119.0.');
|
|
497
757
|
}
|
|
498
758
|
|
|
759
|
+
|
|
499
760
|
module.exports = {
|
|
500
|
-
|
|
761
|
+
PLUGIN_NAME,
|
|
762
|
+
PLUGIN_CATEGORY,
|
|
763
|
+
getUserHome,
|
|
764
|
+
getHarnessHome,
|
|
765
|
+
writeFileIfChanged,
|
|
766
|
+
readJson,
|
|
767
|
+
writeJson,
|
|
768
|
+
ensureExecutable,
|
|
769
|
+
runPostInstall,
|
|
770
|
+
getGlobalStateDir,
|
|
771
|
+
resolveCliCommand,
|
|
772
|
+
runCli,
|
|
501
773
|
ensureGlobalProcessLibrary,
|
|
774
|
+
PLUGIN_BUNDLE_ENTRIES,
|
|
775
|
+
copyRecursive,
|
|
776
|
+
copyPluginBundle,
|
|
777
|
+
DEFAULT_MARKETPLACE,
|
|
778
|
+
normalizeMarketplaceSourcePath,
|
|
502
779
|
ensureMarketplaceEntry,
|
|
780
|
+
removeMarketplaceEntry,
|
|
781
|
+
installManagedSkills,
|
|
782
|
+
mergeManagedHooksConfig,
|
|
783
|
+
installManagedHooks,
|
|
784
|
+
warnWindowsHooks,
|
|
785
|
+
LEGACY_MARKETPLACE_PLUGIN_NAMES,
|
|
786
|
+
LEGACY_SKILL_NAMES,
|
|
787
|
+
LEGACY_PROMPT_NAMES,
|
|
788
|
+
LEGACY_HOOK_SCRIPT_NAMES,
|
|
789
|
+
MANAGED_HOOK_SCRIPT_NAMES,
|
|
503
790
|
getCodexHome,
|
|
504
|
-
getHomeMarketplacePath,
|
|
505
791
|
getHomePluginRoot,
|
|
506
|
-
|
|
792
|
+
getHomeMarketplacePath,
|
|
793
|
+
getWorkspacePluginRoot,
|
|
794
|
+
getWorkspaceMarketplacePath,
|
|
795
|
+
renderCodexConfigToml,
|
|
796
|
+
insertRootKey,
|
|
797
|
+
ensureSectionLine,
|
|
798
|
+
ensureWritableRoots,
|
|
799
|
+
mergeCodexConfig,
|
|
507
800
|
mergeCodexConfigFile,
|
|
801
|
+
resolveBabysitterCommand,
|
|
802
|
+
runBabysitterCli,
|
|
803
|
+
ensureGlobalProcessLibrary,
|
|
804
|
+
getMarketplaceRootDir,
|
|
508
805
|
removeLegacyCodexSurface,
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
806
|
+
installCodexSurface,
|
|
807
|
+
harnessInstall,
|
|
808
|
+
harnessTeamInstall,
|
|
512
809
|
};
|
package/bin/install.js
CHANGED
|
@@ -2,45 +2,27 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const
|
|
6
|
-
copyPluginBundle,
|
|
7
|
-
ensureGlobalProcessLibrary,
|
|
8
|
-
ensureMarketplaceEntry,
|
|
9
|
-
getCodexHome,
|
|
10
|
-
getHomeMarketplacePath,
|
|
11
|
-
getHomePluginRoot,
|
|
12
|
-
installCodexSurface,
|
|
13
|
-
mergeCodexConfigFile,
|
|
14
|
-
warnWindowsHooks,
|
|
15
|
-
} = require('./install-shared');
|
|
5
|
+
const shared = require('./install-shared');
|
|
16
6
|
|
|
17
7
|
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
18
8
|
|
|
19
9
|
function main() {
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const marketplacePath = getHomeMarketplacePath();
|
|
10
|
+
const pluginRoot = shared.getHomePluginRoot();
|
|
11
|
+
const marketplacePath = shared.getHomeMarketplacePath();
|
|
23
12
|
|
|
24
|
-
console.log(`[
|
|
13
|
+
console.log(`[${shared.PLUGIN_NAME}] Installing plugin to ${pluginRoot}`);
|
|
25
14
|
|
|
26
15
|
try {
|
|
27
|
-
copyPluginBundle(PACKAGE_ROOT, pluginRoot);
|
|
28
|
-
ensureMarketplaceEntry(marketplacePath, pluginRoot);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const active = ensureGlobalProcessLibrary(PACKAGE_ROOT);
|
|
33
|
-
console.log(`[babysitter] marketplace: ${marketplacePath}`);
|
|
34
|
-
console.log(`[babysitter] process library: ${active.binding?.dir}`);
|
|
35
|
-
if (active.defaultSpec?.cloneDir) {
|
|
36
|
-
console.log(`[babysitter] process library clone: ${active.defaultSpec.cloneDir}`);
|
|
16
|
+
shared.copyPluginBundle(PACKAGE_ROOT, pluginRoot);
|
|
17
|
+
shared.ensureMarketplaceEntry(marketplacePath, pluginRoot);
|
|
18
|
+
if (typeof shared.harnessInstall === 'function') {
|
|
19
|
+
shared.harnessInstall(PACKAGE_ROOT, pluginRoot);
|
|
37
20
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
console.log(
|
|
41
|
-
console.log('[babysitter] Restart Codex to pick up the installed plugin and config changes.');
|
|
21
|
+
shared.runPostInstall && shared.runPostInstall(pluginRoot);
|
|
22
|
+
console.log(`[${shared.PLUGIN_NAME}] Installation complete!`);
|
|
23
|
+
console.log(`[${shared.PLUGIN_NAME}] Restart your IDE/CLI to pick up the plugin.`);
|
|
42
24
|
} catch (err) {
|
|
43
|
-
console.error(`[
|
|
25
|
+
console.error(`[${shared.PLUGIN_NAME}] Failed to install: ${err.message}`);
|
|
44
26
|
process.exitCode = 1;
|
|
45
27
|
}
|
|
46
28
|
}
|
package/bin/uninstall.js
CHANGED
|
@@ -2,39 +2,23 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const
|
|
6
|
-
getCodexHome,
|
|
7
|
-
getHomeMarketplacePath,
|
|
8
|
-
getHomePluginRoot,
|
|
9
|
-
removeLegacyCodexSurface,
|
|
10
|
-
removeMarketplaceEntry,
|
|
11
|
-
} = require('./install-shared');
|
|
5
|
+
const shared = require('./install-shared');
|
|
12
6
|
|
|
13
7
|
function main() {
|
|
14
|
-
const
|
|
15
|
-
const pluginRoot = getHomePluginRoot();
|
|
16
|
-
const marketplacePath = getHomeMarketplacePath();
|
|
17
|
-
let removedPlugin = false;
|
|
8
|
+
const pluginRoot = shared.getHomePluginRoot();
|
|
18
9
|
|
|
19
|
-
if (fs.existsSync(pluginRoot)) {
|
|
20
|
-
|
|
21
|
-
fs.rmSync(pluginRoot, { recursive: true, force: true });
|
|
22
|
-
console.log(`[babysitter] Removed ${pluginRoot}`);
|
|
23
|
-
removedPlugin = true;
|
|
24
|
-
} catch (err) {
|
|
25
|
-
console.warn(`[babysitter] Warning: Could not remove plugin directory ${pluginRoot}: ${err.message}`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
removeMarketplaceEntry(marketplacePath);
|
|
30
|
-
removeLegacyCodexSurface(codexHome);
|
|
31
|
-
|
|
32
|
-
if (!removedPlugin) {
|
|
33
|
-
console.log('[babysitter] Plugin directory not found, legacy Codex surface cleaned if present.');
|
|
10
|
+
if (!fs.existsSync(pluginRoot)) {
|
|
11
|
+
console.log(`[${shared.PLUGIN_NAME}] Plugin not installed at ${pluginRoot}`);
|
|
34
12
|
return;
|
|
35
13
|
}
|
|
36
14
|
|
|
37
|
-
|
|
15
|
+
try {
|
|
16
|
+
fs.rmSync(pluginRoot, { recursive: true, force: true });
|
|
17
|
+
console.log(`[${shared.PLUGIN_NAME}] Uninstalled from ${pluginRoot}`);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
console.error(`[${shared.PLUGIN_NAME}] Failed to uninstall: ${err.message}`);
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
}
|
|
38
22
|
}
|
|
39
23
|
|
|
40
24
|
main();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Session Start — installs SDK if needed, then runs hook handler.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
PLUGIN_ROOT="${PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
|
|
5
|
+
SDK_VERSION=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('${PLUGIN_ROOT}/versions.json','utf8')).sdkVersion||'latest')}catch{console.log('latest')}" 2>/dev/null || echo "latest")
|
|
6
|
+
if ! command -v babysitter &>/dev/null; then
|
|
7
|
+
npm i -g "@a5c-ai/babysitter-sdk@${SDK_VERSION}" --loglevel=error 2>/dev/null || \
|
|
8
|
+
npm i -g "@a5c-ai/babysitter-sdk@${SDK_VERSION}" --prefix "$HOME/.local" --loglevel=error 2>/dev/null || true
|
|
9
|
+
[ -d "$HOME/.local/bin" ] && export PATH="$HOME/.local/bin:$PATH"
|
|
10
|
+
fi
|
|
11
|
+
babysitter hook:run --harness unified --hook-type session-start --json
|