@a5c-ai/babysitter-codex 0.1.6-staging.f48a64a2 → 0.1.6

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 (33) hide show
  1. package/.app.json +3 -0
  2. package/.codex-plugin/plugin.json +47 -0
  3. package/README.md +41 -108
  4. package/assets/icon.svg +7 -0
  5. package/assets/logo.svg +8 -0
  6. package/bin/install-shared.js +509 -0
  7. package/bin/install.js +29 -433
  8. package/bin/uninstall.js +19 -120
  9. package/{.codex/hooks → hooks}/babysitter-session-start.sh +0 -0
  10. package/{.codex/hooks → hooks}/babysitter-stop-hook.sh +0 -0
  11. package/{.codex/hooks.json → hooks.json} +3 -3
  12. package/package.json +9 -5
  13. package/scripts/team-install.js +32 -424
  14. package/skills/babysit/SKILL.md +798 -0
  15. package/{.codex/skills → skills}/call/SKILL.md +1 -0
  16. package/{.codex/skills → skills}/yolo/SKILL.md +3 -0
  17. package/.codex/config.toml +0 -25
  18. package/.codex/skills/babysit/SKILL.md +0 -385
  19. package/SKILL.md +0 -385
  20. /package/{.codex/hooks → hooks}/user-prompt-submit.sh +0 -0
  21. /package/{.codex/skills → skills}/assimilate/SKILL.md +0 -0
  22. /package/{.codex/skills → skills}/doctor/SKILL.md +0 -0
  23. /package/{.codex/skills → skills}/forever/SKILL.md +0 -0
  24. /package/{.codex/skills → skills}/help/SKILL.md +0 -0
  25. /package/{.codex/skills → skills}/issue/SKILL.md +0 -0
  26. /package/{.codex/skills → skills}/model/SKILL.md +0 -0
  27. /package/{.codex/skills → skills}/observe/SKILL.md +0 -0
  28. /package/{.codex/skills → skills}/plan/SKILL.md +0 -0
  29. /package/{.codex/skills → skills}/project-install/SKILL.md +0 -0
  30. /package/{.codex/skills → skills}/resume/SKILL.md +0 -0
  31. /package/{.codex/skills → skills}/retrospect/SKILL.md +0 -0
  32. /package/{.codex/skills → skills}/team-install/SKILL.md +0 -0
  33. /package/{.codex/skills → skills}/user-install/SKILL.md +0 -0
package/bin/install.js CHANGED
@@ -1,450 +1,46 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- /**
5
- * install.js
6
- *
7
- * Installs the Codex-facing Babysitter skill bundle globally under CODEX_HOME,
8
- * installs Codex mode-wrapper skills such as `$call` and `$plan`,
9
- * clones/updates the process library into ~/.a5c via the SDK CLI.
10
- */
11
-
12
- const fs = require('fs');
13
4
  const path = require('path');
14
- const os = require('os');
15
- const { spawnSync } = require('child_process');
5
+ const {
6
+ copyPluginBundle,
7
+ ensureGlobalProcessLibrary,
8
+ ensureMarketplaceEntry,
9
+ getCodexHome,
10
+ getHomeMarketplacePath,
11
+ getHomePluginRoot,
12
+ installCodexSurface,
13
+ mergeCodexConfigFile,
14
+ warnWindowsHooks,
15
+ } = require('./install-shared');
16
16
 
17
- const SKILL_NAME = 'babysit';
18
- const LEGACY_SKILL_NAME = 'babysitter-codex';
19
- const MODE_SKILL_NAMES = [
20
- 'assimilate',
21
- 'call',
22
- 'doctor',
23
- 'forever',
24
- 'help',
25
- 'issue',
26
- 'model',
27
- 'observe',
28
- 'plan',
29
- 'project-install',
30
- 'resume',
31
- 'retrospect',
32
- 'team-install',
33
- 'user-install',
34
- 'yolo',
35
- ];
36
17
  const PACKAGE_ROOT = path.resolve(__dirname, '..');
37
- const IS_WIN = process.platform === 'win32';
38
- const GLOBAL_HOOK_SPECS = [
39
- { event: 'SessionStart', script: 'babysitter-session-start.sh' },
40
- { event: 'UserPromptSubmit', script: 'user-prompt-submit.sh' },
41
- { event: 'Stop', script: 'babysitter-stop-hook.sh' },
42
- ];
43
- const INSTALL_ENTRIES = [
44
- { source: 'SKILL.md', required: true },
45
- { source: '.codex', required: true },
46
- { source: 'scripts', required: true },
47
- { source: 'babysitter.lock.json', required: true },
48
- ];
49
- const LEGACY_PROMPT_NAMES = ['babysit.md', ...MODE_SKILL_NAMES.map((name) => `${name}.md`)];
50
-
51
- function getCodexHome() {
52
- if (process.env.CODEX_HOME) return process.env.CODEX_HOME;
53
- return path.join(os.homedir(), '.codex');
54
- }
55
-
56
- function getGlobalStateDir() {
57
- if (process.env.BABYSITTER_GLOBAL_STATE_DIR) {
58
- return path.resolve(process.env.BABYSITTER_GLOBAL_STATE_DIR);
59
- }
60
- return path.join(os.homedir(), '.a5c');
61
- }
62
-
63
- function writeFileIfChanged(filePath, contents) {
64
- if (fs.existsSync(filePath)) {
65
- const current = fs.readFileSync(filePath, 'utf8');
66
- if (current === contents) {
67
- return false;
68
- }
69
- }
70
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
71
- fs.writeFileSync(filePath, contents, 'utf8');
72
- return true;
73
- }
74
-
75
- function copyRecursive(src, dest) {
76
- const stat = fs.statSync(src);
77
- if (stat.isDirectory()) {
78
- fs.mkdirSync(dest, { recursive: true });
79
- for (const entry of fs.readdirSync(src)) {
80
- if (['node_modules', '.a5c', '.git', 'test', '.gitignore'].includes(entry)) continue;
81
- copyRecursive(path.join(src, entry), path.join(dest, entry));
82
- }
83
- return;
84
- }
85
-
86
- if (path.basename(src) === 'SKILL.md') {
87
- const file = fs.readFileSync(src);
88
- const hasBom = file.length >= 3 && file[0] === 0xef && file[1] === 0xbb && file[2] === 0xbf;
89
- fs.mkdirSync(path.dirname(dest), { recursive: true });
90
- fs.writeFileSync(dest, hasBom ? file.subarray(3) : file);
91
- return;
92
- }
93
-
94
- fs.mkdirSync(path.dirname(dest), { recursive: true });
95
- fs.copyFileSync(src, dest);
96
- }
97
-
98
- function listModeSkillEntries() {
99
- const skillsDir = path.join(PACKAGE_ROOT, '.codex', 'skills');
100
- if (!fs.existsSync(skillsDir)) {
101
- throw new Error(`required Codex skills directory is missing: ${skillsDir}`);
102
- }
103
- return fs
104
- .readdirSync(skillsDir, { withFileTypes: true })
105
- .filter((entry) => entry.isDirectory() && entry.name !== SKILL_NAME)
106
- .sort((a, b) => a.name.localeCompare(b.name))
107
- .map((entry) => {
108
- const skillName = entry.name;
109
- const skillFile = path.join(skillsDir, skillName, 'SKILL.md');
110
- if (!fs.existsSync(skillFile)) {
111
- throw new Error(`required mode skill payload is missing: ${skillFile}`);
112
- }
113
- return {
114
- skillName,
115
- sourceDir: path.join('.codex', 'skills', skillName),
116
- };
117
- });
118
- }
119
-
120
- function renderCodexConfigToml() {
121
- return [
122
- 'approval_policy = "on-request"',
123
- 'sandbox_mode = "workspace-write"',
124
- 'project_doc_max_bytes = 65536',
125
- '',
126
- '[sandbox_workspace_write]',
127
- 'writable_roots = [".a5c", ".codex"]',
128
- '',
129
- '[features]',
130
- 'codex_hooks = true',
131
- 'multi_agent = true',
132
- '',
133
- '[agents]',
134
- 'max_depth = 3',
135
- 'max_threads = 4',
136
- '',
137
- ].join('\n');
138
- }
139
-
140
- function insertRootKey(content, key, line) {
141
- const keyPattern = new RegExp(`^\\s*${key}\\s*=`, 'm');
142
- if (keyPattern.test(content)) {
143
- return content;
144
- }
145
- const sectionMatch = content.match(/^\[[^\]]+\]\s*$/m);
146
- if (!sectionMatch || sectionMatch.index === undefined) {
147
- return content.trim()
148
- ? `${content.trimEnd()}\n${line}\n`
149
- : `${line}\n`;
150
- }
151
- const before = content.slice(0, sectionMatch.index).trimEnd();
152
- const after = content.slice(sectionMatch.index);
153
- return before
154
- ? `${before}\n${line}\n\n${after}`
155
- : `${line}\n\n${after}`;
156
- }
157
-
158
- function ensureSectionLine(content, sectionName, lineKey, line) {
159
- const keyPattern = new RegExp(`^\\s*${lineKey}\\s*=`, 'm');
160
- if (keyPattern.test(content)) {
161
- return content;
162
- }
163
- const sectionHeader = `[${sectionName}]`;
164
- const escapedSection = sectionName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
165
- const sectionPattern = new RegExp(`^\\[${escapedSection}\\]\\s*$`, 'm');
166
- if (sectionPattern.test(content)) {
167
- return content.replace(sectionPattern, `${sectionHeader}\n${line}`);
168
- }
169
- return content.trim()
170
- ? `${content.trimEnd()}\n\n${sectionHeader}\n${line}\n`
171
- : `${sectionHeader}\n${line}\n`;
172
- }
173
-
174
- function ensureWritableRoots(content) {
175
- const sectionPattern = /^\[sandbox_workspace_write\]\s*$/m;
176
- const rootsPattern = /^writable_roots\s*=\s*\[(.*?)\]\s*$/m;
177
- const requiredRoots = ['.a5c', '.codex'];
178
-
179
- if (!sectionPattern.test(content)) {
180
- return content.trim()
181
- ? `${content.trimEnd()}\n\n[sandbox_workspace_write]\nwritable_roots = [".a5c", ".codex"]\n`
182
- : '[sandbox_workspace_write]\nwritable_roots = [".a5c", ".codex"]\n';
183
- }
184
-
185
- if (!rootsPattern.test(content)) {
186
- return content.replace(
187
- sectionPattern,
188
- '[sandbox_workspace_write]\nwritable_roots = [".a5c", ".codex"]',
189
- );
190
- }
191
-
192
- return content.replace(rootsPattern, (_match, inner) => {
193
- const values = inner
194
- .split(',')
195
- .map((part) => part.trim())
196
- .filter(Boolean)
197
- .map((part) => part.replace(/^"(.*)"$/, '$1'));
198
- const merged = [...new Set([...values, ...requiredRoots])];
199
- const rendered = merged.map((value) => `"${value}"`).join(', ');
200
- return `writable_roots = [${rendered}]`;
201
- });
202
- }
203
-
204
- function mergeCodexConfig(existing) {
205
- let content = existing.trim() ? existing : '';
206
- content = insertRootKey(content, 'approval_policy', 'approval_policy = "on-request"');
207
- content = insertRootKey(content, 'sandbox_mode', 'sandbox_mode = "workspace-write"');
208
- content = insertRootKey(content, 'project_doc_max_bytes', 'project_doc_max_bytes = 65536');
209
- content = ensureWritableRoots(content);
210
- content = ensureSectionLine(content, 'features', 'codex_hooks', 'codex_hooks = true');
211
- content = ensureSectionLine(content, 'features', 'multi_agent', 'multi_agent = true');
212
- content = ensureSectionLine(content, 'agents', 'max_depth', 'max_depth = 3');
213
- content = ensureSectionLine(content, 'agents', 'max_threads', 'max_threads = 4');
214
- return `${content.trimEnd()}\n`;
215
- }
216
-
217
- function renderHookCommand(filePath) {
218
- const normalized = String(filePath).replace(/\\/g, '/');
219
- return normalized.includes(' ') ? `"${normalized}"` : normalized;
220
- }
221
-
222
- function buildHooksConfig(hooksRoot) {
223
- return {
224
- hooks: Object.fromEntries(
225
- GLOBAL_HOOK_SPECS.map(({ event, script }) => [
226
- event,
227
- [
228
- {
229
- matcher: '*',
230
- hooks: [
231
- {
232
- type: 'command',
233
- command: renderHookCommand(path.join(hooksRoot, script)),
234
- },
235
- ],
236
- },
237
- ],
238
- ]),
239
- ),
240
- };
241
- }
242
-
243
- function ensureExecutableHooks(hookDir) {
244
- if (IS_WIN || !fs.existsSync(hookDir)) {
245
- return;
246
- }
247
- for (const name of fs.readdirSync(hookDir)) {
248
- const hookPath = path.join(hookDir, name);
249
- if (name.endsWith('.sh') && fs.statSync(hookPath).isFile()) {
250
- fs.chmodSync(hookPath, 0o755);
251
- }
252
- }
253
- console.log(`[babysitter-codex] +x ${hookDir}`);
254
- }
255
-
256
- function resolveBabysitterCommand(packageRoot) {
257
- if (process.env.BABYSITTER_SDK_CLI) {
258
- return {
259
- command: process.execPath,
260
- argsPrefix: [path.resolve(process.env.BABYSITTER_SDK_CLI)],
261
- };
262
- }
263
- try {
264
- return {
265
- command: process.execPath,
266
- argsPrefix: [
267
- require.resolve('@a5c-ai/babysitter-sdk/dist/cli/main.js', {
268
- paths: [packageRoot],
269
- }),
270
- ],
271
- };
272
- } catch {
273
- return {
274
- command: 'babysitter',
275
- argsPrefix: [],
276
- };
277
- }
278
- }
279
-
280
- function runBabysitterCli(packageRoot, cliArgs, options = {}) {
281
- const resolved = resolveBabysitterCommand(packageRoot);
282
- const result = spawnSync(resolved.command, [...resolved.argsPrefix, ...cliArgs], {
283
- cwd: options.cwd || process.cwd(),
284
- stdio: ['ignore', 'pipe', 'pipe'],
285
- encoding: 'utf8',
286
- env: {
287
- ...process.env,
288
- ...(options.env || {}),
289
- },
290
- });
291
- if (result.status !== 0) {
292
- const stderr = (result.stderr || '').trim();
293
- const stdout = (result.stdout || '').trim();
294
- throw new Error(
295
- `babysitter ${cliArgs.join(' ')} failed` +
296
- (stderr ? `: ${stderr}` : stdout ? `: ${stdout}` : ''),
297
- );
298
- }
299
- return result.stdout;
300
- }
301
-
302
- function ensureGlobalProcessLibrary(packageRoot) {
303
- const active = JSON.parse(
304
- runBabysitterCli(
305
- packageRoot,
306
- ['process-library:active', '--state-dir', getGlobalStateDir(), '--json'],
307
- { cwd: packageRoot },
308
- ),
309
- );
310
- console.log(`[babysitter-codex] process library: ${active.binding?.dir}`);
311
- if (active.defaultSpec?.cloneDir) {
312
- console.log(`[babysitter-codex] process library clone: ${active.defaultSpec.cloneDir}`);
313
- }
314
- console.log(`[babysitter-codex] process library state: ${active.stateFile}`);
315
- }
316
-
317
- function mergeCodexHomeConfig(codexHome) {
318
- const configPath = path.join(codexHome, 'config.toml');
319
- if (!fs.existsSync(configPath)) {
320
- writeFileIfChanged(configPath, renderCodexConfigToml());
321
- console.log(`[babysitter-codex] wrote ${configPath}`);
322
- return;
323
- }
324
-
325
- const content = mergeCodexConfig(fs.readFileSync(configPath, 'utf8'));
326
- if (writeFileIfChanged(configPath, content)) {
327
- console.log(`[babysitter-codex] merged ${configPath}`);
328
- }
329
- }
330
-
331
- function installGlobalHooks(codexHome) {
332
- const srcHooksDir = path.join(PACKAGE_ROOT, '.codex', 'hooks');
333
- if (!fs.existsSync(srcHooksDir)) {
334
- throw new Error(`required hook payload is missing: ${srcHooksDir}`);
335
- }
336
-
337
- const hooksDir = path.join(codexHome, 'hooks');
338
- copyRecursive(srcHooksDir, hooksDir);
339
- console.log('[babysitter-codex] hooks/');
340
-
341
- const hooksConfigPath = path.join(codexHome, 'hooks.json');
342
- writeFileIfChanged(
343
- hooksConfigPath,
344
- `${JSON.stringify(buildHooksConfig(hooksDir), null, 2)}\n`,
345
- );
346
- console.log('[babysitter-codex] hooks.json');
347
-
348
- ensureExecutableHooks(hooksDir);
349
- }
350
-
351
- function removeLegacySkillDir(codexHome) {
352
- const legacyDir = path.join(codexHome, 'skills', LEGACY_SKILL_NAME);
353
- if (!fs.existsSync(legacyDir)) {
354
- return;
355
- }
356
- fs.rmSync(legacyDir, { recursive: true, force: true });
357
- console.log(`[babysitter-codex] removed legacy skill ${legacyDir}`);
358
- }
359
-
360
- function removeEmbeddedPromptSource(skillDir) {
361
- const embeddedPromptsDir = path.join(skillDir, 'prompts');
362
- if (!fs.existsSync(embeddedPromptsDir)) {
363
- return;
364
- }
365
- fs.rmSync(embeddedPromptsDir, { recursive: true, force: true });
366
- console.log(`[babysitter-codex] removed embedded prompt source ${embeddedPromptsDir}`);
367
- }
368
-
369
- function removeLegacyPrompts(codexHome) {
370
- for (const promptName of LEGACY_PROMPT_NAMES) {
371
- const promptPath = path.join(codexHome, 'prompts', promptName);
372
- if (!fs.existsSync(promptPath)) {
373
- continue;
374
- }
375
- fs.rmSync(promptPath, { force: true });
376
- console.log(`[babysitter-codex] removed legacy prompt ${promptPath}`);
377
- }
378
- }
379
-
380
- function installEntry(skillDir, entry) {
381
- const src = path.join(PACKAGE_ROOT, entry.source);
382
- const dest = path.join(skillDir, entry.source);
383
- if (!fs.existsSync(src)) {
384
- if (entry.required) {
385
- throw new Error(`required install payload is missing: ${src}`);
386
- }
387
- return false;
388
- }
389
- copyRecursive(src, dest);
390
- console.log(`[babysitter-codex] ${entry.source}${fs.statSync(src).isDirectory() ? '/' : ''}`);
391
- return true;
392
- }
393
-
394
- function installModeSkillEntry(codexHome, entry) {
395
- const src = path.join(PACKAGE_ROOT, entry.sourceDir);
396
- const dest = path.join(codexHome, 'skills', entry.skillName);
397
- copyRecursive(src, dest);
398
- console.log(`[babysitter-codex] skills/${entry.skillName}/`);
399
- }
400
-
401
- function verifyInstalledPayload(skillDir, codexHome) {
402
- const modeSkillEntries = listModeSkillEntries();
403
- const missing = INSTALL_ENTRIES
404
- .map((entry) => entry.source)
405
- .filter((source) => !fs.existsSync(path.join(skillDir, source)));
406
- if (missing.length > 0) {
407
- throw new Error(`installed skill is incomplete; missing: ${missing.join(', ')}`);
408
- }
409
- for (const entry of modeSkillEntries) {
410
- if (!fs.existsSync(path.join(codexHome, 'skills', entry.skillName, 'SKILL.md'))) {
411
- throw new Error(`installed mode skill is missing: ${entry.skillName}`);
412
- }
413
- }
414
- }
415
18
 
416
19
  function main() {
417
20
  const codexHome = getCodexHome();
418
- const skillDir = path.join(codexHome, 'skills', SKILL_NAME);
419
- const modeSkillEntries = listModeSkillEntries();
21
+ const pluginRoot = getHomePluginRoot();
22
+ const marketplacePath = getHomeMarketplacePath();
420
23
 
421
- console.log(`[babysitter-codex] Installing skill to ${skillDir}`);
24
+ console.log(`[babysitter-codex] Installing plugin to ${pluginRoot}`);
422
25
 
423
26
  try {
424
- fs.mkdirSync(skillDir, { recursive: true });
425
-
426
- for (const entry of INSTALL_ENTRIES) {
427
- installEntry(skillDir, entry);
428
- }
429
- for (const entry of modeSkillEntries) {
430
- installModeSkillEntry(codexHome, entry);
431
- }
432
-
433
- verifyInstalledPayload(skillDir, codexHome);
434
- removeEmbeddedPromptSource(skillDir);
435
- removeLegacySkillDir(codexHome);
436
- removeLegacyPrompts(codexHome);
437
- mergeCodexHomeConfig(codexHome);
438
- installGlobalHooks(codexHome);
439
-
440
- ensureExecutableHooks(path.join(skillDir, '.codex', 'hooks'));
441
-
442
- ensureGlobalProcessLibrary(PACKAGE_ROOT);
443
-
27
+ copyPluginBundle(PACKAGE_ROOT, pluginRoot);
28
+ ensureMarketplaceEntry(marketplacePath, pluginRoot);
29
+ mergeCodexConfigFile(path.join(codexHome, 'config.toml'));
30
+ installCodexSurface(PACKAGE_ROOT, codexHome);
31
+
32
+ const active = ensureGlobalProcessLibrary(PACKAGE_ROOT);
33
+ console.log(`[babysitter-codex] marketplace: ${marketplacePath}`);
34
+ console.log(`[babysitter-codex] process library: ${active.binding?.dir}`);
35
+ if (active.defaultSpec?.cloneDir) {
36
+ console.log(`[babysitter-codex] process library clone: ${active.defaultSpec.cloneDir}`);
37
+ }
38
+ console.log(`[babysitter-codex] process library state: ${active.stateFile}`);
39
+ warnWindowsHooks();
444
40
  console.log('[babysitter-codex] Installation complete!');
445
- console.log('[babysitter-codex] Restart Codex to pick up the updated global skill and mode-skill config.');
41
+ console.log('[babysitter-codex] Restart Codex to pick up the installed plugin and config changes.');
446
42
  } catch (err) {
447
- console.error(`[babysitter-codex] Failed to install skill files: ${err.message}`);
43
+ console.error(`[babysitter-codex] Failed to install plugin: ${err.message}`);
448
44
  process.exitCode = 1;
449
45
  }
450
46
  }
package/bin/uninstall.js CHANGED
@@ -1,137 +1,36 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- /**
5
- * uninstall.js
6
- *
7
- * Removes the globally installed Codex Babysitter skill, its mode-wrapper
8
- * skills, and any legacy prompt aliases left from older installs. The globally
9
- * cloned process library is intentionally kept.
10
- */
11
-
12
4
  const fs = require('fs');
13
- const path = require('path');
14
- const os = require('os');
15
-
16
- const SKILL_NAMES = [
17
- 'babysit',
18
- 'babysitter-codex',
19
- 'assimilate',
20
- 'call',
21
- 'doctor',
22
- 'forever',
23
- 'help',
24
- 'issue',
25
- 'model',
26
- 'observe',
27
- 'plan',
28
- 'project-install',
29
- 'resume',
30
- 'retrospect',
31
- 'team-install',
32
- 'user-install',
33
- 'yolo',
34
- ];
35
- const PROMPT_NAMES = [
36
- 'assimilate.md',
37
- 'call.md',
38
- 'doctor.md',
39
- 'forever.md',
40
- 'help.md',
41
- 'issue.md',
42
- 'model.md',
43
- 'observe.md',
44
- 'plan.md',
45
- 'project-install.md',
46
- 'resume.md',
47
- 'retrospect.md',
48
- 'team-install.md',
49
- 'user-install.md',
50
- 'yolo.md',
51
- 'babysit.md',
52
- ];
53
- const HOOK_SCRIPT_NAMES = [
54
- 'babysitter-session-start.sh',
55
- 'babysitter-stop-hook.sh',
56
- 'user-prompt-submit.sh',
57
- ];
58
-
59
- function getCodexHome() {
60
- if (process.env.CODEX_HOME) return process.env.CODEX_HOME;
61
- return path.join(os.homedir(), '.codex');
62
- }
5
+ const {
6
+ getCodexHome,
7
+ getHomeMarketplacePath,
8
+ getHomePluginRoot,
9
+ removeLegacyCodexSurface,
10
+ removeMarketplaceEntry,
11
+ } = require('./install-shared');
63
12
 
64
13
  function main() {
65
14
  const codexHome = getCodexHome();
66
- let removedAny = false;
67
-
68
- for (const skillName of SKILL_NAMES) {
69
- const skillDir = path.join(codexHome, 'skills', skillName);
70
- if (!fs.existsSync(skillDir)) {
71
- continue;
72
- }
73
- try {
74
- fs.rmSync(skillDir, { recursive: true, force: true });
75
- console.log(`[babysitter-codex] Removed ${skillDir}`);
76
- removedAny = true;
77
- } catch (err) {
78
- console.warn(`[babysitter-codex] Warning: Could not remove skill directory ${skillDir}: ${err.message}`);
79
- }
80
- }
81
-
82
- for (const promptName of PROMPT_NAMES) {
83
- const promptPath = path.join(codexHome, 'prompts', promptName);
84
- if (!fs.existsSync(promptPath)) {
85
- continue;
86
- }
87
- try {
88
- fs.rmSync(promptPath, { force: true });
89
- console.log(`[babysitter-codex] Removed ${promptPath}`);
90
- removedAny = true;
91
- } catch (err) {
92
- console.warn(`[babysitter-codex] Warning: Could not remove prompt ${promptPath}: ${err.message}`);
93
- }
94
- }
15
+ const pluginRoot = getHomePluginRoot();
16
+ const marketplacePath = getHomeMarketplacePath();
17
+ let removedPlugin = false;
95
18
 
96
- for (const hookName of HOOK_SCRIPT_NAMES) {
97
- const hookPath = path.join(codexHome, 'hooks', hookName);
98
- if (!fs.existsSync(hookPath)) {
99
- continue;
100
- }
19
+ if (fs.existsSync(pluginRoot)) {
101
20
  try {
102
- fs.rmSync(hookPath, { force: true });
103
- console.log(`[babysitter-codex] Removed ${hookPath}`);
104
- removedAny = true;
21
+ fs.rmSync(pluginRoot, { recursive: true, force: true });
22
+ console.log(`[babysitter-codex] Removed ${pluginRoot}`);
23
+ removedPlugin = true;
105
24
  } catch (err) {
106
- console.warn(`[babysitter-codex] Warning: Could not remove hook script ${hookPath}: ${err.message}`);
25
+ console.warn(`[babysitter-codex] Warning: Could not remove plugin directory ${pluginRoot}: ${err.message}`);
107
26
  }
108
27
  }
109
28
 
110
- const hooksConfigPath = path.join(codexHome, 'hooks.json');
111
- if (fs.existsSync(hooksConfigPath)) {
112
- try {
113
- fs.rmSync(hooksConfigPath, { force: true });
114
- console.log(`[babysitter-codex] Removed ${hooksConfigPath}`);
115
- removedAny = true;
116
- } catch (err) {
117
- console.warn(`[babysitter-codex] Warning: Could not remove hook config ${hooksConfigPath}: ${err.message}`);
118
- }
119
- }
120
-
121
- const hooksDir = path.join(codexHome, 'hooks');
122
- if (fs.existsSync(hooksDir)) {
123
- try {
124
- if (fs.readdirSync(hooksDir).length === 0) {
125
- fs.rmSync(hooksDir, { recursive: true, force: true });
126
- console.log(`[babysitter-codex] Removed ${hooksDir}`);
127
- }
128
- } catch (err) {
129
- console.warn(`[babysitter-codex] Warning: Could not clean hook directory ${hooksDir}: ${err.message}`);
130
- }
131
- }
29
+ removeMarketplaceEntry(marketplacePath);
30
+ removeLegacyCodexSurface(codexHome);
132
31
 
133
- if (!removedAny) {
134
- console.log('[babysitter-codex] Skill directory not found, nothing to remove.');
32
+ if (!removedPlugin) {
33
+ console.log('[babysitter-codex] Plugin directory not found, legacy Codex surface cleaned if present.');
135
34
  return;
136
35
  }
137
36
 
File without changes
@@ -6,7 +6,7 @@
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
9
- "command": ".codex/hooks/babysitter-session-start.sh"
9
+ "command": "./hooks/babysitter-session-start.sh"
10
10
  }
11
11
  ]
12
12
  }
@@ -17,7 +17,7 @@
17
17
  "hooks": [
18
18
  {
19
19
  "type": "command",
20
- "command": ".codex/hooks/user-prompt-submit.sh"
20
+ "command": "./hooks/user-prompt-submit.sh"
21
21
  }
22
22
  ]
23
23
  }
@@ -28,7 +28,7 @@
28
28
  "hooks": [
29
29
  {
30
30
  "type": "command",
31
- "command": ".codex/hooks/babysitter-stop-hook.sh"
31
+ "command": "./hooks/babysitter-stop-hook.sh"
32
32
  }
33
33
  ]
34
34
  }