@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/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@a5c-ai/babysitter-codex",
3
- "version": "0.1.6-staging.f48a64a2",
3
+ "version": "0.1.6",
4
4
  "description": "Babysitter Codex skill bundle and integration package for OpenAI Codex CLI with SDK-managed process-library bootstrapping, 15 orchestration modes, and BOM-safe SKILL installation",
5
5
  "scripts": {
6
6
  "test": "node test/integration.test.js && node test/packaged-install.test.js",
7
7
  "test:integration": "node test/integration.test.js",
8
8
  "team:install": "node scripts/team-install.js",
9
- "lint": "node -e \"const fs=require('fs'); const path=require('path'); const cp=require('child_process'); const walk=(dir)=>{for(const entry of fs.readdirSync(dir)){const file=path.join(dir, entry); const stat=fs.statSync(file); if(stat.isDirectory()) walk(file); else if(file.endsWith('.js')) cp.execFileSync(process.execPath,['--check',file],{stdio:'inherit'});}}; ['.codex','bin','scripts','test'].forEach((dir)=>{if(fs.existsSync(dir)) walk(dir);});\"",
9
+ "lint": "node -e \"const fs=require('fs'); const path=require('path'); const cp=require('child_process'); const walk=(dir)=>{for(const entry of fs.readdirSync(dir)){const file=path.join(dir, entry); const stat=fs.statSync(file); if(stat.isDirectory()) walk(file); else if(file.endsWith('.js')) cp.execFileSync(process.execPath,['--check',file],{stdio:'inherit'});}}; ['skills','bin','scripts','test'].forEach((dir)=>{if(fs.existsSync(dir)) walk(dir);});\"",
10
10
  "deploy": "npm publish --access public",
11
11
  "deploy:staging": "npm publish --access public --tag staging"
12
12
  },
@@ -14,8 +14,12 @@
14
14
  "babysitter-codex": "bin/cli.js"
15
15
  },
16
16
  "files": [
17
- "SKILL.md",
18
- ".codex/",
17
+ ".codex-plugin/",
18
+ ".app.json",
19
+ "assets/",
20
+ "hooks/",
21
+ "hooks.json",
22
+ "skills/",
19
23
  "bin/",
20
24
  "scripts/",
21
25
  "babysitter.lock.json"
@@ -39,6 +43,6 @@
39
43
  },
40
44
  "homepage": "https://github.com/a5c-ai/babysitter/tree/main/plugins/babysitter-codex#readme",
41
45
  "dependencies": {
42
- "@a5c-ai/babysitter-sdk": "0.0.183-staging.f48a64a2"
46
+ "@a5c-ai/babysitter-sdk": "0.0.183"
43
47
  }
44
48
  }
@@ -2,56 +2,16 @@
2
2
  'use strict';
3
3
 
4
4
  const fs = require('fs');
5
- const os = require('os');
6
5
  const path = require('path');
7
- const { spawnSync } = require('child_process');
8
-
9
- const SKILL_NAME = 'babysit';
10
- const MODE_SKILL_NAMES = [
11
- 'assimilate',
12
- 'call',
13
- 'doctor',
14
- 'forever',
15
- 'help',
16
- 'issue',
17
- 'model',
18
- 'observe',
19
- 'plan',
20
- 'project-install',
21
- 'resume',
22
- 'retrospect',
23
- 'team-install',
24
- 'user-install',
25
- 'yolo',
26
- ];
27
- const DEFAULT_PROCESS_LIBRARY_REPO = 'https://github.com/a5c-ai/babysitter.git';
28
- const DEFAULT_PROCESS_LIBRARY_SUBPATH = 'library';
29
- const DEFAULT_PROCESS_LIBRARY_REFERENCE_SUBPATH = 'library/reference';
30
- const WORKSPACE_SKILL_ENTRIES = [
31
- { source: 'SKILL.md', target: 'SKILL.md' },
32
- { source: 'scripts', target: 'scripts' },
33
- { source: 'babysitter.lock.json', target: 'babysitter.lock.json' },
34
- ];
35
-
36
- function listModeSkillEntries(packageRoot) {
37
- const skillsDir = path.join(packageRoot, '.codex', 'skills');
38
- return fs
39
- .readdirSync(skillsDir, { withFileTypes: true })
40
- .filter((entry) => entry.isDirectory() && entry.name !== SKILL_NAME)
41
- .sort((a, b) => a.name.localeCompare(b.name))
42
- .map((entry) => {
43
- const skillName = entry.name;
44
- const skillFile = path.join(skillsDir, skillName, 'SKILL.md');
45
- if (!fs.existsSync(skillFile)) {
46
- throw new Error(`missing mode skill template: ${skillFile}`);
47
- }
48
- return skillName;
49
- });
50
- }
51
-
52
- function readJson(filePath) {
53
- return JSON.parse(fs.readFileSync(filePath, 'utf8'));
54
- }
6
+ const {
7
+ copyPluginBundle,
8
+ ensureGlobalProcessLibrary,
9
+ ensureMarketplaceEntry,
10
+ installCodexSurface,
11
+ mergeCodexConfigFile,
12
+ warnWindowsHooks,
13
+ writeJson,
14
+ } = require('../bin/install-shared');
55
15
 
56
16
  function parseArgs(argv) {
57
17
  const args = {
@@ -68,366 +28,21 @@ function parseArgs(argv) {
68
28
  return args;
69
29
  }
70
30
 
71
- function getGlobalStateDir() {
72
- if (process.env.BABYSITTER_GLOBAL_STATE_DIR) {
73
- return path.resolve(process.env.BABYSITTER_GLOBAL_STATE_DIR);
74
- }
75
- return path.join(os.homedir(), '.a5c');
76
- }
77
-
78
- function splitProcessLibrarySubpath(value) {
79
- return String(value)
80
- .split(/[\\/]+/)
81
- .map((part) => part.trim())
82
- .filter(Boolean);
83
- }
84
-
85
- function renderWorkspaceConfigToml() {
86
- return [
87
- 'approval_policy = "on-request"',
88
- 'sandbox_mode = "workspace-write"',
89
- 'project_doc_max_bytes = 65536',
90
- '',
91
- '[sandbox_workspace_write]',
92
- 'writable_roots = [".a5c", ".codex"]',
93
- '',
94
- '[features]',
95
- 'codex_hooks = true',
96
- 'multi_agent = true',
97
- '',
98
- '[agents]',
99
- 'max_depth = 3',
100
- 'max_threads = 4',
101
- '',
102
- ].join('\n');
103
- }
104
-
105
- function writeFileIfChanged(filePath, contents) {
106
- if (fs.existsSync(filePath)) {
107
- const current = fs.readFileSync(filePath, 'utf8');
108
- if (current === contents) {
109
- return false;
110
- }
111
- }
112
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
113
- fs.writeFileSync(filePath, contents, 'utf8');
114
- return true;
115
- }
116
-
117
- function copyRecursive(src, dest) {
118
- const stat = fs.statSync(src);
119
- if (stat.isDirectory()) {
120
- fs.mkdirSync(dest, { recursive: true });
121
- for (const entry of fs.readdirSync(src)) {
122
- if (['node_modules', '.a5c', '.git', 'test', '.gitignore'].includes(entry)) continue;
123
- copyRecursive(path.join(src, entry), path.join(dest, entry));
124
- }
125
- return;
126
- }
127
-
128
- if (path.basename(src) === 'SKILL.md') {
129
- const file = fs.readFileSync(src);
130
- const hasBom = file.length >= 3 && file[0] === 0xef && file[1] === 0xbb && file[2] === 0xbf;
131
- fs.mkdirSync(path.dirname(dest), { recursive: true });
132
- fs.writeFileSync(dest, hasBom ? file.subarray(3) : file);
133
- return;
134
- }
135
-
136
- fs.mkdirSync(path.dirname(dest), { recursive: true });
137
- fs.copyFileSync(src, dest);
138
- }
139
-
140
- function installWorkspaceSkill(packageRoot, workspaceRoot, dryRun) {
141
- const workspaceSkillsRoot = path.join(workspaceRoot, '.codex', 'skills');
142
- const workspaceSkillRoot = path.join(workspaceRoot, '.codex', 'skills', SKILL_NAME);
143
- const workspaceHookScriptsRoot = path.join(workspaceRoot, '.codex', 'hooks');
144
- const modeSkillNames = listModeSkillEntries(packageRoot);
145
-
146
- if (dryRun) {
147
- return {
148
- workspaceSkillsRoot,
149
- workspaceSkillRoot,
150
- workspaceHookScriptsRoot,
151
- };
152
- }
153
-
154
- fs.rmSync(workspaceSkillRoot, { recursive: true, force: true });
155
- fs.mkdirSync(workspaceSkillsRoot, { recursive: true });
156
- fs.mkdirSync(workspaceSkillRoot, { recursive: true });
157
-
158
- for (const entry of WORKSPACE_SKILL_ENTRIES) {
159
- copyRecursive(
160
- path.join(packageRoot, entry.source),
161
- path.join(workspaceSkillRoot, entry.target),
162
- );
163
- }
164
-
165
- fs.mkdirSync(workspaceHookScriptsRoot, { recursive: true });
166
- copyRecursive(path.join(packageRoot, '.codex', 'hooks'), workspaceHookScriptsRoot);
167
-
168
- for (const skillName of modeSkillNames) {
169
- copyRecursive(
170
- path.join(packageRoot, '.codex', 'skills', skillName),
171
- path.join(workspaceSkillsRoot, skillName),
172
- );
173
- }
174
-
175
- return {
176
- workspaceSkillsRoot,
177
- workspaceSkillRoot,
178
- workspaceHookScriptsRoot,
179
- };
180
- }
181
-
182
- function insertRootKey(content, key, line) {
183
- const keyPattern = new RegExp(`^\\s*${key}\\s*=`, 'm');
184
- if (keyPattern.test(content)) {
185
- return content;
186
- }
187
- const sectionMatch = content.match(/^\[[^\]]+\]\s*$/m);
188
- if (!sectionMatch || sectionMatch.index === undefined) {
189
- return content.trim()
190
- ? `${content.trimEnd()}\n${line}\n`
191
- : `${line}\n`;
192
- }
193
- const before = content.slice(0, sectionMatch.index).trimEnd();
194
- const after = content.slice(sectionMatch.index);
195
- return before
196
- ? `${before}\n${line}\n\n${after}`
197
- : `${line}\n\n${after}`;
198
- }
199
-
200
- function ensureSectionLine(content, sectionName, lineKey, line) {
201
- const keyPattern = new RegExp(`^\\s*${lineKey}\\s*=`, 'm');
202
- if (keyPattern.test(content)) {
203
- return content;
204
- }
205
- const sectionHeader = `[${sectionName}]`;
206
- const sectionPattern = new RegExp(`^\\[${sectionName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\]\\s*$`, 'm');
207
- if (sectionPattern.test(content)) {
208
- return content.replace(sectionPattern, `${sectionHeader}\n${line}`);
209
- }
210
- return content.trim()
211
- ? `${content.trimEnd()}\n\n${sectionHeader}\n${line}\n`
212
- : `${sectionHeader}\n${line}\n`;
213
- }
214
-
215
- function ensureWritableRoots(content) {
216
- const sectionPattern = /^\[sandbox_workspace_write\]\s*$/m;
217
- const rootsPattern = /^writable_roots\s*=\s*\[(.*?)\]\s*$/m;
218
- const requiredRoots = ['.a5c', '.codex'];
219
-
220
- if (!sectionPattern.test(content)) {
221
- return content.trim()
222
- ? `${content.trimEnd()}\n\n[sandbox_workspace_write]\nwritable_roots = [".a5c", ".codex"]\n`
223
- : '[sandbox_workspace_write]\nwritable_roots = [".a5c", ".codex"]\n';
224
- }
225
-
226
- if (!rootsPattern.test(content)) {
227
- return content.replace(sectionPattern, '[sandbox_workspace_write]\nwritable_roots = [".a5c", ".codex"]');
228
- }
229
-
230
- return content.replace(rootsPattern, (_match, inner) => {
231
- const values = inner
232
- .split(',')
233
- .map((part) => part.trim())
234
- .filter(Boolean)
235
- .map((part) => part.replace(/^"(.*)"$/, '$1'));
236
- const merged = [...new Set([...values, ...requiredRoots])];
237
- const rendered = merged.map((value) => `"${value}"`).join(', ');
238
- return `writable_roots = [${rendered}]`;
239
- });
240
- }
241
-
242
- function mergeWorkspaceConfig(existing) {
243
- let content = existing.trim() ? existing : '';
244
- content = insertRootKey(content, 'approval_policy', 'approval_policy = "on-request"');
245
- content = insertRootKey(content, 'sandbox_mode', 'sandbox_mode = "workspace-write"');
246
- content = insertRootKey(content, 'project_doc_max_bytes', 'project_doc_max_bytes = 65536');
247
- content = ensureWritableRoots(content);
248
- content = ensureSectionLine(content, 'features', 'codex_hooks', 'codex_hooks = true');
249
- content = ensureSectionLine(content, 'features', 'multi_agent', 'multi_agent = true');
250
- content = ensureSectionLine(content, 'agents', 'max_depth', 'max_depth = 3');
251
- content = ensureSectionLine(content, 'agents', 'max_threads', 'max_threads = 4');
252
- return `${content.trimEnd()}\n`;
253
- }
254
-
255
- function resolveBabysitterCommand(packageRoot) {
256
- if (process.env.BABYSITTER_SDK_CLI) {
257
- return {
258
- command: process.execPath,
259
- argsPrefix: [path.resolve(process.env.BABYSITTER_SDK_CLI)],
260
- };
261
- }
262
- try {
263
- return {
264
- command: process.execPath,
265
- argsPrefix: [
266
- require.resolve('@a5c-ai/babysitter-sdk/dist/cli/main.js', {
267
- paths: [packageRoot],
268
- }),
269
- ],
270
- };
271
- } catch {
272
- return {
273
- command: 'babysitter',
274
- argsPrefix: [],
275
- };
276
- }
277
- }
278
-
279
- function runBabysitterCli(packageRoot, cliArgs, options = {}) {
280
- const resolved = resolveBabysitterCommand(packageRoot);
281
- const result = spawnSync(resolved.command, [...resolved.argsPrefix, ...cliArgs], {
282
- cwd: options.cwd || process.cwd(),
283
- stdio: ['ignore', 'pipe', 'pipe'],
284
- encoding: 'utf8',
285
- env: {
286
- ...process.env,
287
- ...(options.env || {}),
288
- },
289
- });
290
- if (result.status !== 0) {
291
- const stderr = (result.stderr || '').trim();
292
- const stdout = (result.stdout || '').trim();
293
- throw new Error(
294
- `babysitter ${cliArgs.join(' ')} failed` +
295
- (stderr ? `: ${stderr}` : stdout ? `: ${stdout}` : ''),
296
- );
297
- }
298
- return result.stdout;
299
- }
300
-
301
- function resolveProcessLibrarySpec() {
302
- const stateDir = getGlobalStateDir();
303
- const repo = process.env.BABYSITTER_PROCESS_LIBRARY_REPO || DEFAULT_PROCESS_LIBRARY_REPO;
304
- const ref = process.env.BABYSITTER_PROCESS_LIBRARY_REF || '';
305
- const cloneDir = path.join(stateDir, 'process-library', 'babysitter-repo');
306
- const processSubpath = process.env.BABYSITTER_PROCESS_LIBRARY_SUBPATH || DEFAULT_PROCESS_LIBRARY_SUBPATH;
307
- const referenceSubpath = process.env.BABYSITTER_PROCESS_LIBRARY_REFERENCE_SUBPATH || DEFAULT_PROCESS_LIBRARY_REFERENCE_SUBPATH;
308
- return {
309
- repo,
310
- ref: ref || undefined,
311
- cloneDir,
312
- processRoot: path.join(cloneDir, ...splitProcessLibrarySubpath(processSubpath)),
313
- referenceRoot: path.join(cloneDir, ...splitProcessLibrarySubpath(referenceSubpath)),
314
- stateDir,
315
- };
316
- }
317
-
318
- function removeLegacyWorkspacePrompts(workspaceRoot) {
319
- const promptsRoot = path.join(workspaceRoot, '.codex', 'prompts');
320
- for (const promptFile of MODE_SKILL_NAMES.map((name) => `${name}.md`).concat('babysit.md')) {
321
- const promptPath = path.join(promptsRoot, promptFile);
322
- if (fs.existsSync(promptPath)) {
323
- fs.rmSync(promptPath, { force: true });
324
- }
325
- }
326
- if (fs.existsSync(promptsRoot)) {
327
- try {
328
- if (fs.readdirSync(promptsRoot).length === 0) {
329
- fs.rmSync(promptsRoot, { recursive: true, force: true });
330
- }
331
- } catch {
332
- // Best effort cleanup only.
333
- }
334
- }
335
- }
336
-
337
- function ensureActiveProcessLibrary(packageRoot, dryRun) {
338
- const spec = resolveProcessLibrarySpec();
339
- const activeArgs = ['process-library:active', '--state-dir', spec.stateDir, '--json'];
340
- if (dryRun) {
341
- return {
342
- ...spec,
343
- plannedCommands: [
344
- `babysitter ${activeArgs.join(' ')}`,
345
- ],
346
- activeStateFile: path.join(spec.stateDir, 'active', 'process-library.json'),
347
- binding: null,
348
- };
349
- }
350
-
351
- const active = JSON.parse(runBabysitterCli(packageRoot, activeArgs, { cwd: packageRoot }));
352
- return {
353
- ...spec,
354
- plannedCommands: [],
355
- activeStateFile: active.stateFile,
356
- binding: active.binding || null,
357
- };
358
- }
359
-
360
- function buildHooksConfig() {
361
- return {
362
- hooks: {
363
- SessionStart: [
364
- {
365
- matcher: '*',
366
- hooks: [
367
- {
368
- type: 'command',
369
- command: '.codex/hooks/babysitter-session-start.sh',
370
- },
371
- ],
372
- },
373
- ],
374
- UserPromptSubmit: [
375
- {
376
- matcher: '*',
377
- hooks: [
378
- {
379
- type: 'command',
380
- command: '.codex/hooks/user-prompt-submit.sh',
381
- },
382
- ],
383
- },
384
- ],
385
- Stop: [
386
- {
387
- matcher: '*',
388
- hooks: [
389
- {
390
- type: 'command',
391
- command: '.codex/hooks/babysitter-stop-hook.sh',
392
- },
393
- ],
394
- },
395
- ],
396
- },
397
- };
398
- }
399
-
400
31
  function main() {
401
32
  const args = parseArgs(process.argv);
402
33
  const packageRoot = path.resolve(process.env.BABYSITTER_PACKAGE_ROOT || path.join(__dirname, '..'));
403
34
  const workspaceRoot = args.workspace;
404
- const lockPath = path.join(packageRoot, 'babysitter.lock.json');
405
- if (!fs.existsSync(lockPath)) {
406
- throw new Error(`missing lock file: ${lockPath}`);
407
- }
408
- const lock = readJson(lockPath);
409
- const workspaceHooksConfigPath = path.join(workspaceRoot, '.codex', 'hooks.json');
35
+ const workspacePluginRoot = path.join(workspaceRoot, 'plugins', 'babysitter-codex');
36
+ const workspaceMarketplacePath = path.join(workspaceRoot, '.agents', 'plugins', 'marketplace.json');
410
37
  const workspaceConfigPath = path.join(workspaceRoot, '.codex', 'config.toml');
411
- const { workspaceSkillsRoot, workspaceSkillRoot, workspaceHookScriptsRoot } = installWorkspaceSkill(packageRoot, workspaceRoot, args.dryRun);
412
- const processLibrary = ensureActiveProcessLibrary(packageRoot, args.dryRun);
38
+
413
39
  const installInfo = {
414
40
  installedAt: new Date().toISOString(),
415
- runtime: lock.runtime,
416
- content: lock.content,
417
- lockVersion: lock.version,
418
41
  packageRoot,
419
42
  workspaceRoot,
420
- workspaceSkillsRoot,
421
- workspaceSkillRoot,
422
- workspaceConfigPath,
423
- workspaceHooksConfigPath,
424
- hookScriptsRoot: workspaceHookScriptsRoot,
425
- processLibraryRepo: processLibrary.repo,
426
- ...(processLibrary.ref ? { processLibraryRef: processLibrary.ref } : {}),
427
- processLibraryCloneDir: processLibrary.cloneDir,
428
- processLibraryRoot: processLibrary.processRoot,
429
- processLibraryReferenceRoot: processLibrary.referenceRoot,
430
- processLibraryStateFile: processLibrary.activeStateFile,
43
+ pluginRoot: workspacePluginRoot,
44
+ marketplacePath: workspaceMarketplacePath,
45
+ codexConfigPath: workspaceConfigPath,
431
46
  };
432
47
 
433
48
  if (args.dryRun) {
@@ -435,43 +50,36 @@ function main() {
435
50
  ok: true,
436
51
  dryRun: true,
437
52
  installInfo,
438
- processLibrary: {
439
- repo: processLibrary.repo,
440
- ...(processLibrary.ref ? { ref: processLibrary.ref } : {}),
441
- cloneDir: processLibrary.cloneDir,
442
- processRoot: processLibrary.processRoot,
443
- referenceRoot: processLibrary.referenceRoot,
444
- stateFile: processLibrary.activeStateFile,
445
- plannedCommands: processLibrary.plannedCommands,
446
- },
447
53
  }, null, 2));
448
54
  return;
449
55
  }
450
56
 
57
+ copyPluginBundle(packageRoot, workspacePluginRoot);
58
+ ensureMarketplaceEntry(workspaceMarketplacePath, workspacePluginRoot);
59
+ mergeCodexConfigFile(workspaceConfigPath);
60
+ installCodexSurface(packageRoot, path.join(workspaceRoot, '.codex'));
61
+
62
+ const active = ensureGlobalProcessLibrary(packageRoot);
63
+ installInfo.processLibraryStateFile = active.stateFile;
64
+ installInfo.processLibraryRoot = active.binding?.dir || '';
65
+ installInfo.processLibraryCloneDir = active.defaultSpec?.cloneDir || '';
66
+
451
67
  const outDir = path.join(workspaceRoot, '.a5c', 'team');
452
68
  fs.mkdirSync(outDir, { recursive: true });
453
- removeLegacyWorkspacePrompts(workspaceRoot);
454
- fs.mkdirSync(path.dirname(workspaceHooksConfigPath), { recursive: true });
455
- writeFileIfChanged(workspaceHooksConfigPath, `${JSON.stringify(buildHooksConfig(), null, 2)}\n`);
456
- const existingWorkspaceConfig = fs.existsSync(workspaceConfigPath)
457
- ? fs.readFileSync(workspaceConfigPath, 'utf8')
458
- : renderWorkspaceConfigToml();
459
- writeFileIfChanged(workspaceConfigPath, mergeWorkspaceConfig(existingWorkspaceConfig));
460
- fs.writeFileSync(path.join(outDir, 'install.json'), JSON.stringify(installInfo, null, 2), 'utf8');
69
+ writeJson(path.join(outDir, 'install.json'), installInfo);
461
70
 
462
71
  const profilePath = path.join(outDir, 'profile.json');
463
72
  if (!fs.existsSync(profilePath)) {
464
- fs.writeFileSync(profilePath, JSON.stringify({
73
+ writeJson(profilePath, {
465
74
  teamName: 'default',
466
- workspaceSkillsRoot,
467
- installedSkillRoot: workspaceSkillRoot,
468
- workspaceConfigPath,
469
- workspaceHooksConfigPath,
470
- hookScriptsRoot: workspaceHookScriptsRoot,
75
+ pluginRoot: workspacePluginRoot,
76
+ marketplacePath: workspaceMarketplacePath,
77
+ codexConfigPath: workspaceConfigPath,
471
78
  processLibraryLookupCommand: 'babysitter process-library:active --json',
472
- }, null, 2), 'utf8');
79
+ });
473
80
  }
474
81
 
82
+ warnWindowsHooks();
475
83
  console.log('[team-install] complete');
476
84
  }
477
85