@dusky-bluehour/agent-service 0.6.6 → 0.6.7

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 (98) hide show
  1. package/README.md +20 -28
  2. package/antigravity/README.md +7 -0
  3. package/antigravity/commands/definitions/cmd-dev-be-api.md +43 -0
  4. package/antigravity/commands/definitions/cmd-dev-fe-hook-separate.md +43 -0
  5. package/antigravity/commands/definitions/cmd-dev-fe-ui-componentize.md +43 -0
  6. package/antigravity/commands/definitions/cmd-dev-perf-optimize.md +43 -0
  7. package/antigravity/commands/definitions/cmd-dev-sequential-autorun.md +43 -0
  8. package/antigravity/commands/definitions/cmd-doc-handoff.md +44 -0
  9. package/antigravity/commands/definitions/cmd-improve-techdebt.md +43 -0
  10. package/antigravity/commands/definitions/cmd-incident-triage.md +43 -0
  11. package/antigravity/commands/definitions/cmd-ops-ci-cd-gate.md +43 -0
  12. package/antigravity/commands/definitions/cmd-ops-deploy.md +43 -0
  13. package/antigravity/commands/definitions/cmd-ops-monitoring.md +43 -0
  14. package/antigravity/commands/definitions/cmd-plan-arch-decision.md +43 -0
  15. package/antigravity/commands/definitions/cmd-plan-implementation-bootstrap.md +43 -0
  16. package/antigravity/commands/definitions/cmd-plan-prd-details.md +43 -0
  17. package/antigravity/commands/definitions/cmd-plan-prd-master.md +44 -0
  18. package/antigravity/commands/definitions/cmd-plan-req-lock.md +44 -0
  19. package/antigravity/commands/definitions/cmd-review-code.md +43 -0
  20. package/antigravity/commands/definitions/cmd-sec-dependency-audit.md +43 -0
  21. package/antigravity/commands/definitions/cmd-sec-threat-model.md +43 -0
  22. package/antigravity/commands/definitions/cmd-test-unit-integration.md +43 -0
  23. package/antigravity/instructions/WORKSPACE-RULES.template.md +34 -0
  24. package/antigravity/settings/editor-policy.json +193 -0
  25. package/catalog/tool-catalog.ko.json +77 -16
  26. package/claude-code/README.md +27 -0
  27. package/claude-code/commands/native/cmd-dev-be-api.md +51 -0
  28. package/claude-code/commands/native/cmd-dev-fe-hook-separate.md +51 -0
  29. package/claude-code/commands/native/cmd-dev-fe-ui-componentize.md +51 -0
  30. package/claude-code/commands/native/cmd-dev-perf-optimize.md +51 -0
  31. package/claude-code/commands/native/cmd-dev-sequential-autorun.md +51 -0
  32. package/claude-code/commands/native/cmd-doc-handoff.md +52 -0
  33. package/claude-code/commands/native/cmd-improve-techdebt.md +51 -0
  34. package/claude-code/commands/native/cmd-incident-triage.md +51 -0
  35. package/claude-code/commands/native/cmd-ops-ci-cd-gate.md +51 -0
  36. package/claude-code/commands/native/cmd-ops-deploy.md +51 -0
  37. package/claude-code/commands/native/cmd-ops-monitoring.md +51 -0
  38. package/claude-code/commands/native/cmd-plan-arch-decision.md +51 -0
  39. package/claude-code/commands/native/cmd-plan-implementation-bootstrap.md +51 -0
  40. package/claude-code/commands/native/cmd-plan-prd-details.md +51 -0
  41. package/claude-code/commands/native/cmd-plan-prd-master.md +52 -0
  42. package/claude-code/commands/native/cmd-plan-req-lock.md +52 -0
  43. package/claude-code/commands/native/cmd-review-code.md +51 -0
  44. package/claude-code/commands/native/cmd-sec-dependency-audit.md +51 -0
  45. package/claude-code/commands/native/cmd-sec-threat-model.md +51 -0
  46. package/claude-code/commands/native/cmd-test-unit-integration.md +51 -0
  47. package/claude-code/instructions/CLAUDE.template.md +42 -0
  48. package/claude-code/settings/settings.json +183 -0
  49. package/claude-code/settings/settings.local.json +10 -0
  50. package/codex/README.md +13 -1
  51. package/codex/instructions/AGENTS.permissions.generated.md +121 -0
  52. package/codex/instructions/AGENTS.template.md +18 -3
  53. package/codex/settings/runtime-policy.json +188 -0
  54. package/codex/skills/cmd-dev-be-api/SKILL.md +43 -0
  55. package/codex/skills/cmd-dev-be-api/agents/openai.yaml +4 -0
  56. package/codex/skills/cmd-dev-fe-hook-separate/SKILL.md +43 -0
  57. package/codex/skills/cmd-dev-fe-hook-separate/agents/openai.yaml +4 -0
  58. package/codex/skills/cmd-dev-fe-ui-componentize/SKILL.md +43 -0
  59. package/codex/skills/cmd-dev-fe-ui-componentize/agents/openai.yaml +4 -0
  60. package/codex/skills/cmd-dev-perf-optimize/SKILL.md +43 -0
  61. package/codex/skills/cmd-dev-perf-optimize/agents/openai.yaml +4 -0
  62. package/codex/skills/cmd-dev-sequential-autorun/SKILL.md +43 -0
  63. package/codex/skills/cmd-dev-sequential-autorun/agents/openai.yaml +4 -0
  64. package/codex/skills/cmd-doc-handoff/SKILL.md +43 -0
  65. package/codex/skills/cmd-doc-handoff/agents/openai.yaml +4 -0
  66. package/codex/skills/cmd-improve-techdebt/SKILL.md +43 -0
  67. package/codex/skills/cmd-improve-techdebt/agents/openai.yaml +4 -0
  68. package/codex/skills/cmd-incident-triage/SKILL.md +43 -0
  69. package/codex/skills/cmd-incident-triage/agents/openai.yaml +4 -0
  70. package/codex/skills/cmd-ops-ci-cd-gate/SKILL.md +43 -0
  71. package/codex/skills/cmd-ops-ci-cd-gate/agents/openai.yaml +4 -0
  72. package/codex/skills/cmd-ops-deploy/SKILL.md +43 -0
  73. package/codex/skills/cmd-ops-deploy/agents/openai.yaml +4 -0
  74. package/codex/skills/cmd-ops-monitoring/SKILL.md +43 -0
  75. package/codex/skills/cmd-ops-monitoring/agents/openai.yaml +4 -0
  76. package/codex/skills/cmd-plan-arch-decision/SKILL.md +43 -0
  77. package/codex/skills/cmd-plan-arch-decision/agents/openai.yaml +4 -0
  78. package/codex/skills/cmd-plan-implementation-bootstrap/SKILL.md +43 -0
  79. package/codex/skills/cmd-plan-implementation-bootstrap/agents/openai.yaml +4 -0
  80. package/codex/skills/cmd-plan-prd-details/SKILL.md +43 -0
  81. package/codex/skills/cmd-plan-prd-details/agents/openai.yaml +4 -0
  82. package/codex/skills/cmd-plan-prd-master/SKILL.md +44 -0
  83. package/codex/skills/cmd-plan-prd-master/agents/openai.yaml +4 -0
  84. package/codex/skills/cmd-plan-req-lock/SKILL.md +44 -0
  85. package/codex/skills/cmd-plan-req-lock/agents/openai.yaml +4 -0
  86. package/codex/skills/cmd-review-code/SKILL.md +43 -0
  87. package/codex/skills/cmd-review-code/agents/openai.yaml +4 -0
  88. package/codex/skills/cmd-sec-dependency-audit/SKILL.md +43 -0
  89. package/codex/skills/cmd-sec-dependency-audit/agents/openai.yaml +4 -0
  90. package/codex/skills/cmd-sec-threat-model/SKILL.md +43 -0
  91. package/codex/skills/cmd-sec-threat-model/agents/openai.yaml +4 -0
  92. package/codex/skills/cmd-test-unit-integration/SKILL.md +43 -0
  93. package/codex/skills/cmd-test-unit-integration/agents/openai.yaml +4 -0
  94. package/common/settings/security-policy.json +221 -0
  95. package/package.json +1 -1
  96. package/scripts/generate-from-common.mjs +489 -4
  97. package/scripts/init.mjs +285 -36
  98. package/scripts/validate.mjs +208 -9
@@ -36,6 +36,41 @@ function quoteYamlString(value) {
36
36
  return `"${normalized.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
37
37
  }
38
38
 
39
+ function normalizeCommandBasename(commandId) {
40
+ const normalized = String(commandId ?? '')
41
+ .trim()
42
+ .toLowerCase()
43
+ .replace(/[^a-z0-9-]+/g, '-')
44
+ .replace(/^-+|-+$/g, '');
45
+
46
+ if (!normalized) {
47
+ throw new Error(`[commands] command id가 비어 있습니다: ${commandId}`);
48
+ }
49
+ return normalized;
50
+ }
51
+
52
+ function toBulletLines(values) {
53
+ if (!Array.isArray(values) || values.length === 0) {
54
+ return ['- (없음)'];
55
+ }
56
+ return values.map((value) => `- ${value}`);
57
+ }
58
+
59
+ function toNumberedLines(values) {
60
+ if (!Array.isArray(values) || values.length === 0) {
61
+ return ['1. (없음)'];
62
+ }
63
+ return values.map((value, index) => `${index + 1}. ${value}`);
64
+ }
65
+
66
+ function toBashRule(pattern) {
67
+ return `Bash(${pattern})`;
68
+ }
69
+
70
+ function toPathRule(kind, pattern) {
71
+ return `${kind}(${pattern})`;
72
+ }
73
+
39
74
  function renderCodexOpenAiYaml(skill) {
40
75
  const ui = skill.codex_openai ?? {};
41
76
  return [
@@ -153,6 +188,339 @@ function renderAntigravityWorkflowDefinition(workflow) {
153
188
  return lines.join('\n');
154
189
  }
155
190
 
191
+ function renderClaudeCommandMarkdown(command) {
192
+ const requiredInputs = command.input_contract?.required;
193
+ const optionalInputs = command.input_contract?.optional;
194
+ const executionSteps = command.execution_contract?.steps;
195
+ const qualityGates = command.quality_gates;
196
+ const artifacts = command.output_contract?.artifacts;
197
+ const nextRoles = command.handoff?.next_roles;
198
+ const blockers = command.handoff?.blockers;
199
+
200
+ return [
201
+ '---',
202
+ `description: ${quoteYamlString(`${command.name} (${command.id})`)}`,
203
+ 'argument-hint: "[추가 컨텍스트]"',
204
+ '---',
205
+ '',
206
+ `이 명령은 \`${command.id}\` 계약을 그대로 적용합니다.`,
207
+ `추가 컨텍스트가 있으면 반영하세요: $ARGUMENTS`,
208
+ '',
209
+ '## 목적',
210
+ '',
211
+ String(command.purpose ?? ''),
212
+ '',
213
+ '## 입력 계약',
214
+ '',
215
+ '### 필수 입력',
216
+ ...toBulletLines(requiredInputs),
217
+ '',
218
+ '### 선택 입력',
219
+ ...toBulletLines(optionalInputs),
220
+ '',
221
+ '## 실행 절차',
222
+ '',
223
+ ...toNumberedLines(executionSteps),
224
+ '',
225
+ '## 품질 게이트',
226
+ '',
227
+ ...toBulletLines(qualityGates),
228
+ '',
229
+ '## 산출물',
230
+ '',
231
+ ...toBulletLines(artifacts),
232
+ '',
233
+ '## 핸드오프',
234
+ '',
235
+ `- 다음 역할: ${(Array.isArray(nextRoles) && nextRoles.length > 0 ? nextRoles.join(', ') : '(없음)')}`,
236
+ `- 차단 요인: ${(Array.isArray(blockers) && blockers.length > 0 ? blockers.join(', ') : '(없음)')}`,
237
+ '',
238
+ '## 결과 응답 형식',
239
+ '',
240
+ '- 실행 요약(무엇을 왜 수행했는지)',
241
+ '- 입력 검증(충족/누락 항목)',
242
+ '- 품질 게이트 통과 여부',
243
+ '- 산출물 및 다음 핸드오프',
244
+ ''
245
+ ].join('\n');
246
+ }
247
+
248
+ function renderAntigravityCommandDefinition(command) {
249
+ const requiredInputs = command.input_contract?.required;
250
+ const optionalInputs = command.input_contract?.optional;
251
+ const executionSteps = command.execution_contract?.steps;
252
+ const qualityGates = command.quality_gates;
253
+ const artifacts = command.output_contract?.artifacts;
254
+ const nextRoles = command.handoff?.next_roles;
255
+ const blockers = command.handoff?.blockers;
256
+
257
+ return [
258
+ '# generated by scripts/generate-from-common.mjs',
259
+ '',
260
+ `# ${command.id} - ${command.name}`,
261
+ '',
262
+ `- phase: ${command.phase ?? ''}`,
263
+ `- owner_role: ${command.owner_role ?? ''}`,
264
+ '',
265
+ '## Purpose',
266
+ '',
267
+ String(command.purpose ?? ''),
268
+ '',
269
+ '## Input Contract',
270
+ '',
271
+ '### Required',
272
+ ...toBulletLines(requiredInputs),
273
+ '',
274
+ '### Optional',
275
+ ...toBulletLines(optionalInputs),
276
+ '',
277
+ '## Execution Contract',
278
+ '',
279
+ ...toNumberedLines(executionSteps),
280
+ '',
281
+ '## Quality Gates',
282
+ '',
283
+ ...toBulletLines(qualityGates),
284
+ '',
285
+ '## Output Contract',
286
+ '',
287
+ ...toBulletLines(artifacts),
288
+ '',
289
+ '## Handoff',
290
+ '',
291
+ `- next_roles: ${(Array.isArray(nextRoles) && nextRoles.length > 0 ? nextRoles.join(', ') : '(none)')}`,
292
+ `- blockers: ${(Array.isArray(blockers) && blockers.length > 0 ? blockers.join(', ') : '(none)')}`,
293
+ ''
294
+ ].join('\n');
295
+ }
296
+
297
+ function renderCodexCommandSkillMarkdown(command, skillName) {
298
+ const requiredInputs = Array.isArray(command.input_contract?.required)
299
+ ? command.input_contract.required.map((item) => `[필수] ${item}`)
300
+ : [];
301
+ const optionalInputs = Array.isArray(command.input_contract?.optional)
302
+ ? command.input_contract.optional.map((item) => `[선택] ${item}`)
303
+ : [];
304
+ const executionSteps = Array.isArray(command.execution_contract?.steps)
305
+ ? command.execution_contract.steps
306
+ : [];
307
+ const qualityGates = Array.isArray(command.quality_gates) ? command.quality_gates : [];
308
+ const artifacts = Array.isArray(command.output_contract?.artifacts)
309
+ ? command.output_contract.artifacts
310
+ : [];
311
+ const nextRoles = Array.isArray(command.handoff?.next_roles) ? command.handoff.next_roles : [];
312
+ const blockers = Array.isArray(command.handoff?.blockers) ? command.handoff.blockers : [];
313
+
314
+ const checklistLines = toBulletLines([...requiredInputs, ...optionalInputs]);
315
+ const procedureLines = toNumberedLines([
316
+ `명령 계약을 확인한다: ${command.id} (${command.name})`,
317
+ ...executionSteps,
318
+ '품질 게이트를 검증한다.',
319
+ '산출물과 핸드오프를 보고한다.'
320
+ ]);
321
+ const reportLines = toBulletLines([
322
+ `실행 명령: ${command.id}`,
323
+ `입력 검증: 필수 입력 충족 여부 / 누락 항목`,
324
+ `품질 게이트: ${qualityGates.length > 0 ? qualityGates.join(' | ') : '(없음)'}`,
325
+ `산출물: ${artifacts.length > 0 ? artifacts.join(', ') : '(없음)'}`,
326
+ `핸드오프: 다음 역할 ${nextRoles.length > 0 ? nextRoles.join(', ') : '(없음)'}`
327
+ ]);
328
+ const stopLines = toBulletLines([
329
+ '필수 입력이 누락된 경우',
330
+ '품질 게이트를 충족하지 못한 경우',
331
+ ...blockers
332
+ ]);
333
+ const qualityRuleLines = toBulletLines([
334
+ '검증되지 않은 추정은 사실과 분리해서 기록한다.',
335
+ '품질 게이트를 우회하지 않는다.',
336
+ ...qualityGates
337
+ ]);
338
+
339
+ return [
340
+ '---',
341
+ `name: ${skillName}`,
342
+ `description: ${command.name} 명령 계약을 Codex 스킬 형태로 실행한다.`,
343
+ '---',
344
+ '',
345
+ '# 시작 전 체크리스트',
346
+ '',
347
+ ...checklistLines,
348
+ '',
349
+ '# 실행 절차',
350
+ '',
351
+ ...procedureLines,
352
+ '',
353
+ '# 결과 보고 형식',
354
+ '',
355
+ ...reportLines,
356
+ '',
357
+ '# 중단 조건',
358
+ '',
359
+ ...stopLines,
360
+ '',
361
+ '# 품질 규칙',
362
+ '',
363
+ ...qualityRuleLines,
364
+ ''
365
+ ].join('\n');
366
+ }
367
+
368
+ function renderCodexCommandOpenAiYaml(command) {
369
+ return [
370
+ 'skill:',
371
+ ` display_name: ${quoteYamlString(command.name ?? command.id)}`,
372
+ ` short_description: ${quoteYamlString(`${command.phase ?? ''} · ${command.owner_role ?? ''}`)}`,
373
+ ` default_prompt: ${quoteYamlString(`${command.id} 명령 계약을 준수해 실행해줘.`)}`,
374
+ ''
375
+ ].join('\n');
376
+ }
377
+
378
+ function buildClaudePermissionsFromSecurityPolicy(securityPolicy, includeLocalOverrides = false) {
379
+ const shared = securityPolicy.shared_permissions ?? {};
380
+ const claude = securityPolicy.claude_code ?? {};
381
+
382
+ const allow = [];
383
+ const ask = [];
384
+ const deny = [];
385
+
386
+ if (shared.read_all) {
387
+ allow.push('Read');
388
+ }
389
+ if (shared.edit_all) {
390
+ allow.push('Edit');
391
+ }
392
+
393
+ for (const pattern of shared.allow_bash ?? []) {
394
+ allow.push(toBashRule(pattern));
395
+ }
396
+ for (const pattern of shared.ask_bash ?? []) {
397
+ ask.push(toBashRule(pattern));
398
+ }
399
+ for (const pattern of shared.deny_bash ?? []) {
400
+ deny.push(toBashRule(pattern));
401
+ }
402
+ for (const pattern of shared.deny_read ?? []) {
403
+ deny.push(toPathRule('Read', pattern));
404
+ }
405
+ for (const pattern of shared.deny_edit ?? []) {
406
+ deny.push(toPathRule('Edit', pattern));
407
+ }
408
+
409
+ if (includeLocalOverrides) {
410
+ for (const pattern of claude.local_overrides?.ask_bash ?? []) {
411
+ ask.push(toBashRule(pattern));
412
+ }
413
+ }
414
+
415
+ return {
416
+ defaultMode: claude.default_mode ?? 'acceptEdits',
417
+ disableBypassPermissionsMode: claude.disable_bypass_permissions_mode ?? 'disable',
418
+ additionalDirectories: includeLocalOverrides
419
+ ? (claude.local_overrides?.additional_directories ?? [])
420
+ : (claude.additional_directories ?? []),
421
+ allow: [...new Set(allow)],
422
+ ask: [...new Set(ask)],
423
+ deny: [...new Set(deny)]
424
+ };
425
+ }
426
+
427
+ function renderClaudeProjectSettingsJson(securityPolicy) {
428
+ return {
429
+ $schema: 'https://json.schemastore.org/claude-code-settings.json',
430
+ permissions: buildClaudePermissionsFromSecurityPolicy(securityPolicy, false),
431
+ enabledPlugins: securityPolicy.claude_code?.enabled_plugins ?? {}
432
+ };
433
+ }
434
+
435
+ function renderClaudeLocalSettingsJson(securityPolicy) {
436
+ const claude = securityPolicy.claude_code ?? {};
437
+ return {
438
+ $schema: 'https://json.schemastore.org/claude-code-settings.json',
439
+ permissions: {
440
+ additionalDirectories: claude.local_overrides?.additional_directories ?? [],
441
+ ask: [...new Set((claude.local_overrides?.ask_bash ?? []).map((pattern) => toBashRule(pattern)))]
442
+ }
443
+ };
444
+ }
445
+
446
+ function renderAntigravityEditorPolicyJson(securityPolicy) {
447
+ const shared = securityPolicy.shared_permissions ?? {};
448
+ return {
449
+ schema_version: '1.0.0',
450
+ policy_id: securityPolicy.policy_id ?? 'strict-dev',
451
+ description_ko:
452
+ 'Antigravity Editor에서 수동 반영할 수 있는 프로젝트 보안/권한 정책 템플릿',
453
+ editor: securityPolicy.antigravity?.editor_settings ?? {},
454
+ command_policy: {
455
+ allow_shell: shared.allow_bash ?? [],
456
+ ask_shell: shared.ask_bash ?? [],
457
+ deny_shell: shared.deny_bash ?? []
458
+ },
459
+ path_policy: {
460
+ deny_read: shared.deny_read ?? [],
461
+ deny_edit: shared.deny_edit ?? []
462
+ }
463
+ };
464
+ }
465
+
466
+ function renderCodexRuntimePolicyJson(securityPolicy) {
467
+ const shared = securityPolicy.shared_permissions ?? {};
468
+ return {
469
+ schema_version: '1.0.0',
470
+ policy_id: securityPolicy.policy_id ?? 'strict-dev',
471
+ description_ko:
472
+ 'Codex 프로젝트 규칙(AGENTS.md)과 함께 사용하는 런타임 권한 정책 템플릿',
473
+ runtime: securityPolicy.codex?.runtime_policy ?? {},
474
+ command_policy: {
475
+ allow_shell: shared.allow_bash ?? [],
476
+ ask_shell: shared.ask_bash ?? [],
477
+ deny_shell: shared.deny_bash ?? []
478
+ },
479
+ path_policy: {
480
+ deny_read: shared.deny_read ?? [],
481
+ deny_edit: shared.deny_edit ?? []
482
+ }
483
+ };
484
+ }
485
+
486
+ function renderCodexPermissionsMarkdown(securityPolicy) {
487
+ const shared = securityPolicy.shared_permissions ?? {};
488
+ const runtime = securityPolicy.codex?.runtime_policy ?? {};
489
+ const allowShell = shared.allow_bash ?? [];
490
+ const askShell = shared.ask_bash ?? [];
491
+ const denyShell = shared.deny_bash ?? [];
492
+
493
+ return [
494
+ '# Codex 권한 정책 템플릿',
495
+ '',
496
+ '이 문서는 `common/settings/security-policy.json`에서 자동 생성됩니다.',
497
+ '`AGENTS.md`의 프로젝트 규칙 섹션에 붙여 넣어 팀 기본 정책으로 사용하세요.',
498
+ '',
499
+ '## 런타임 정책',
500
+ '',
501
+ ...toBulletLines([
502
+ `sandbox_mode: ${runtime.sandbox_mode ?? 'workspace-write'}`,
503
+ `network_access: ${runtime.network_access ?? 'restricted'}`,
504
+ `git_write_actions: ${runtime.git_write_actions ?? 'ask'}`,
505
+ `destructive_shell: ${runtime.destructive_shell ?? 'deny'}`,
506
+ `global_package_installs: ${runtime.global_package_installs ?? 'deny'}`
507
+ ]),
508
+ '',
509
+ '## Shell 허용 규칙',
510
+ '',
511
+ ...toBulletLines(allowShell.map((rule) => `\`${rule}\``)),
512
+ '',
513
+ '## Shell 확인(ask) 규칙',
514
+ '',
515
+ ...toBulletLines(askShell.map((rule) => `\`${rule}\``)),
516
+ '',
517
+ '## Shell 차단 규칙',
518
+ '',
519
+ ...toBulletLines(denyShell.map((rule) => `\`${rule}\``)),
520
+ ''
521
+ ].join('\n');
522
+ }
523
+
156
524
  function buildWorkflowCatalogByTool(commonWorkflowCatalog) {
157
525
  const toolIds = Array.isArray(commonWorkflowCatalog.tools)
158
526
  ? commonWorkflowCatalog.tools
@@ -268,12 +636,11 @@ async function writeOrCheck(filePath, expected, state) {
268
636
  state.written += 1;
269
637
  }
270
638
 
271
- async function pruneAntigravityWorkflowDefinitions(expectedFileNames, state) {
272
- const dir = path.join(rootDir, 'antigravity', 'workflows', 'definitions');
639
+ async function pruneGeneratedFilesBySuffix(dir, suffix, expectedFileNames, state) {
273
640
  await fs.mkdir(dir, { recursive: true });
274
641
  const entries = await fs.readdir(dir, { withFileTypes: true });
275
642
  for (const entry of entries) {
276
- if (!entry.isFile() || !entry.name.endsWith('.workflow.yaml')) {
643
+ if (!entry.isFile() || !entry.name.endsWith(suffix)) {
277
644
  continue;
278
645
  }
279
646
  if (expectedFileNames.has(entry.name)) {
@@ -289,10 +656,34 @@ async function pruneAntigravityWorkflowDefinitions(expectedFileNames, state) {
289
656
  }
290
657
  }
291
658
 
659
+ async function pruneCodexCommandSkills(expectedDirNames, state) {
660
+ const dir = path.join(rootDir, 'codex', 'skills');
661
+ await fs.mkdir(dir, { recursive: true });
662
+ const entries = await fs.readdir(dir, { withFileTypes: true });
663
+
664
+ for (const entry of entries) {
665
+ if (!entry.isDirectory() || !/^cmd-[a-z0-9-]+$/.test(entry.name)) {
666
+ continue;
667
+ }
668
+ if (expectedDirNames.has(entry.name)) {
669
+ continue;
670
+ }
671
+
672
+ const removePath = path.join(dir, entry.name);
673
+ if (checkMode) {
674
+ state.outOfDate.push(path.relative(rootDir, removePath));
675
+ continue;
676
+ }
677
+ await fs.rm(removePath, { recursive: true, force: true });
678
+ state.deleted += 1;
679
+ }
680
+ }
681
+
292
682
  async function main() {
293
683
  const commands = await readJson('common/commands/command-catalog.json');
294
684
  const commonWorkflowCatalog = await readJson('common/workflows/workflow-catalog.json');
295
685
  const skillCatalog = await readJson('common/skills/skill-catalog.json');
686
+ const securityPolicy = await readJson('common/settings/security-policy.json');
296
687
  const claudeSubagents = await readJson('common/claude/subagent-catalog.json');
297
688
  const claudeTeams = await readJson('common/claude/team-catalog.json');
298
689
  const antigravityAgents = await readJson('common/antigravity/agent-catalog.json');
@@ -313,6 +704,95 @@ async function main() {
313
704
  await writeOrCheck(commandPath, toPrettyJson(commands), state);
314
705
  }
315
706
 
707
+ await writeOrCheck(
708
+ path.join(rootDir, 'claude-code', 'settings', 'settings.json'),
709
+ toPrettyJson(renderClaudeProjectSettingsJson(securityPolicy)),
710
+ state
711
+ );
712
+ await writeOrCheck(
713
+ path.join(rootDir, 'claude-code', 'settings', 'settings.local.json'),
714
+ toPrettyJson(renderClaudeLocalSettingsJson(securityPolicy)),
715
+ state
716
+ );
717
+ await writeOrCheck(
718
+ path.join(rootDir, 'antigravity', 'settings', 'editor-policy.json'),
719
+ toPrettyJson(renderAntigravityEditorPolicyJson(securityPolicy)),
720
+ state
721
+ );
722
+ await writeOrCheck(
723
+ path.join(rootDir, 'codex', 'settings', 'runtime-policy.json'),
724
+ toPrettyJson(renderCodexRuntimePolicyJson(securityPolicy)),
725
+ state
726
+ );
727
+ await writeOrCheck(
728
+ path.join(rootDir, 'codex', 'instructions', 'AGENTS.permissions.generated.md'),
729
+ renderCodexPermissionsMarkdown(securityPolicy),
730
+ state
731
+ );
732
+ await pruneGeneratedFilesBySuffix(
733
+ path.join(rootDir, 'claude-code', 'settings'),
734
+ '.json',
735
+ new Set(['settings.json', 'settings.local.json']),
736
+ state
737
+ );
738
+ await pruneGeneratedFilesBySuffix(
739
+ path.join(rootDir, 'antigravity', 'settings'),
740
+ '.json',
741
+ new Set(['editor-policy.json']),
742
+ state
743
+ );
744
+ await pruneGeneratedFilesBySuffix(
745
+ path.join(rootDir, 'codex', 'settings'),
746
+ '.json',
747
+ new Set(['runtime-policy.json']),
748
+ state
749
+ );
750
+
751
+ const commandFileNames = new Set();
752
+ const codexCommandSkillNames = new Set();
753
+ for (const command of commands.commands ?? []) {
754
+ if (!command?.id) {
755
+ throw new Error('[commands] command id가 비어 있습니다.');
756
+ }
757
+ const basename = normalizeCommandBasename(command.id);
758
+ commandFileNames.add(`${basename}.md`);
759
+ codexCommandSkillNames.add(basename);
760
+
761
+ await writeOrCheck(
762
+ path.join(rootDir, 'claude-code', 'commands', 'native', `${basename}.md`),
763
+ renderClaudeCommandMarkdown(command),
764
+ state
765
+ );
766
+ await writeOrCheck(
767
+ path.join(rootDir, 'antigravity', 'commands', 'definitions', `${basename}.md`),
768
+ renderAntigravityCommandDefinition(command),
769
+ state
770
+ );
771
+ await writeOrCheck(
772
+ path.join(rootDir, 'codex', 'skills', basename, 'SKILL.md'),
773
+ renderCodexCommandSkillMarkdown(command, basename),
774
+ state
775
+ );
776
+ await writeOrCheck(
777
+ path.join(rootDir, 'codex', 'skills', basename, 'agents', 'openai.yaml'),
778
+ renderCodexCommandOpenAiYaml(command),
779
+ state
780
+ );
781
+ }
782
+ await pruneGeneratedFilesBySuffix(
783
+ path.join(rootDir, 'claude-code', 'commands', 'native'),
784
+ '.md',
785
+ commandFileNames,
786
+ state
787
+ );
788
+ await pruneGeneratedFilesBySuffix(
789
+ path.join(rootDir, 'antigravity', 'commands', 'definitions'),
790
+ '.md',
791
+ commandFileNames,
792
+ state
793
+ );
794
+ await pruneCodexCommandSkills(codexCommandSkillNames, state);
795
+
316
796
  for (const toolId of toolIds) {
317
797
  const catalog = workflowCatalogByTool?.[toolId];
318
798
  if (!catalog) {
@@ -329,7 +809,12 @@ async function main() {
329
809
  const definitionPath = path.join(rootDir, 'antigravity', 'workflows', 'definitions', filename);
330
810
  await writeOrCheck(definitionPath, renderAntigravityWorkflowDefinition(workflow), state);
331
811
  }
332
- await pruneAntigravityWorkflowDefinitions(antigravityWorkflowNames, state);
812
+ await pruneGeneratedFilesBySuffix(
813
+ path.join(rootDir, 'antigravity', 'workflows', 'definitions'),
814
+ '.workflow.yaml',
815
+ antigravityWorkflowNames,
816
+ state
817
+ );
333
818
 
334
819
  for (const skill of skillCatalog.skills ?? []) {
335
820
  for (const toolId of toolIds) {