@dusky-bluehour/agent-service 0.6.6 → 0.6.8

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 (127) hide show
  1. package/README.md +255 -36
  2. package/catalog/tool-catalog.ko.json +92 -57
  3. package/claude-code/README.md +75 -30
  4. package/claude-code/commands/native/cmd-dev-be-api.md +51 -0
  5. package/claude-code/commands/native/cmd-dev-fe-hook-separate.md +51 -0
  6. package/claude-code/commands/native/cmd-dev-fe-ui-componentize.md +51 -0
  7. package/claude-code/commands/native/cmd-dev-perf-optimize.md +51 -0
  8. package/claude-code/commands/native/cmd-dev-sequential-autorun.md +51 -0
  9. package/claude-code/commands/native/cmd-doc-handoff.md +52 -0
  10. package/claude-code/commands/native/cmd-improve-techdebt.md +51 -0
  11. package/claude-code/commands/native/cmd-incident-triage.md +51 -0
  12. package/claude-code/commands/native/cmd-ops-ci-cd-gate.md +51 -0
  13. package/claude-code/commands/native/cmd-ops-deploy.md +51 -0
  14. package/claude-code/commands/native/cmd-ops-monitoring.md +51 -0
  15. package/claude-code/commands/native/cmd-plan-arch-decision.md +51 -0
  16. package/claude-code/commands/native/cmd-plan-implementation-bootstrap.md +51 -0
  17. package/claude-code/commands/native/cmd-plan-prd-details.md +51 -0
  18. package/claude-code/commands/native/cmd-plan-prd-master.md +52 -0
  19. package/claude-code/commands/native/cmd-plan-req-lock.md +52 -0
  20. package/claude-code/commands/native/cmd-review-code.md +51 -0
  21. package/claude-code/commands/native/cmd-sec-dependency-audit.md +51 -0
  22. package/claude-code/commands/native/cmd-sec-threat-model.md +51 -0
  23. package/claude-code/commands/native/cmd-test-unit-integration.md +51 -0
  24. package/claude-code/instructions/CLAUDE.template.md +42 -0
  25. package/claude-code/settings/settings.json +183 -0
  26. package/claude-code/settings/settings.local.json +10 -0
  27. package/codex/README.md +58 -24
  28. package/codex/instructions/AGENTS.permissions.generated.md +121 -0
  29. package/codex/instructions/AGENTS.template.md +18 -3
  30. package/codex/settings/runtime-policy.json +188 -0
  31. package/codex/skills/cmd-dev-be-api/SKILL.md +43 -0
  32. package/codex/skills/cmd-dev-be-api/agents/openai.yaml +4 -0
  33. package/codex/skills/cmd-dev-fe-hook-separate/SKILL.md +43 -0
  34. package/codex/skills/cmd-dev-fe-hook-separate/agents/openai.yaml +4 -0
  35. package/codex/skills/cmd-dev-fe-ui-componentize/SKILL.md +43 -0
  36. package/codex/skills/cmd-dev-fe-ui-componentize/agents/openai.yaml +4 -0
  37. package/codex/skills/cmd-dev-perf-optimize/SKILL.md +43 -0
  38. package/codex/skills/cmd-dev-perf-optimize/agents/openai.yaml +4 -0
  39. package/codex/skills/cmd-dev-sequential-autorun/SKILL.md +43 -0
  40. package/codex/skills/cmd-dev-sequential-autorun/agents/openai.yaml +4 -0
  41. package/codex/skills/cmd-doc-handoff/SKILL.md +43 -0
  42. package/codex/skills/cmd-doc-handoff/agents/openai.yaml +4 -0
  43. package/codex/skills/cmd-improve-techdebt/SKILL.md +43 -0
  44. package/codex/skills/cmd-improve-techdebt/agents/openai.yaml +4 -0
  45. package/codex/skills/cmd-incident-triage/SKILL.md +43 -0
  46. package/codex/skills/cmd-incident-triage/agents/openai.yaml +4 -0
  47. package/codex/skills/cmd-ops-ci-cd-gate/SKILL.md +43 -0
  48. package/codex/skills/cmd-ops-ci-cd-gate/agents/openai.yaml +4 -0
  49. package/codex/skills/cmd-ops-deploy/SKILL.md +43 -0
  50. package/codex/skills/cmd-ops-deploy/agents/openai.yaml +4 -0
  51. package/codex/skills/cmd-ops-monitoring/SKILL.md +43 -0
  52. package/codex/skills/cmd-ops-monitoring/agents/openai.yaml +4 -0
  53. package/codex/skills/cmd-plan-arch-decision/SKILL.md +43 -0
  54. package/codex/skills/cmd-plan-arch-decision/agents/openai.yaml +4 -0
  55. package/codex/skills/cmd-plan-implementation-bootstrap/SKILL.md +43 -0
  56. package/codex/skills/cmd-plan-implementation-bootstrap/agents/openai.yaml +4 -0
  57. package/codex/skills/cmd-plan-prd-details/SKILL.md +43 -0
  58. package/codex/skills/cmd-plan-prd-details/agents/openai.yaml +4 -0
  59. package/codex/skills/cmd-plan-prd-master/SKILL.md +44 -0
  60. package/codex/skills/cmd-plan-prd-master/agents/openai.yaml +4 -0
  61. package/codex/skills/cmd-plan-req-lock/SKILL.md +44 -0
  62. package/codex/skills/cmd-plan-req-lock/agents/openai.yaml +4 -0
  63. package/codex/skills/cmd-review-code/SKILL.md +43 -0
  64. package/codex/skills/cmd-review-code/agents/openai.yaml +4 -0
  65. package/codex/skills/cmd-sec-dependency-audit/SKILL.md +43 -0
  66. package/codex/skills/cmd-sec-dependency-audit/agents/openai.yaml +4 -0
  67. package/codex/skills/cmd-sec-threat-model/SKILL.md +43 -0
  68. package/codex/skills/cmd-sec-threat-model/agents/openai.yaml +4 -0
  69. package/codex/skills/cmd-test-unit-integration/SKILL.md +43 -0
  70. package/codex/skills/cmd-test-unit-integration/agents/openai.yaml +4 -0
  71. package/common/settings/security-policy.json +221 -0
  72. package/common/skills/skill-catalog.json +368 -136
  73. package/common/workflows/workflow-catalog.json +89 -1238
  74. package/gemini/README.md +104 -0
  75. package/gemini/commands/definitions/cmd-dev-be-api.toml +35 -0
  76. package/gemini/commands/definitions/cmd-dev-fe-hook-separate.toml +35 -0
  77. package/gemini/commands/definitions/cmd-dev-fe-ui-componentize.toml +35 -0
  78. package/gemini/commands/definitions/cmd-dev-perf-optimize.toml +35 -0
  79. package/gemini/commands/definitions/cmd-dev-sequential-autorun.toml +35 -0
  80. package/gemini/commands/definitions/cmd-doc-handoff.toml +36 -0
  81. package/gemini/commands/definitions/cmd-improve-techdebt.toml +35 -0
  82. package/gemini/commands/definitions/cmd-incident-triage.toml +35 -0
  83. package/gemini/commands/definitions/cmd-ops-ci-cd-gate.toml +35 -0
  84. package/gemini/commands/definitions/cmd-ops-deploy.toml +35 -0
  85. package/gemini/commands/definitions/cmd-ops-monitoring.toml +35 -0
  86. package/gemini/commands/definitions/cmd-plan-arch-decision.toml +35 -0
  87. package/gemini/commands/definitions/cmd-plan-implementation-bootstrap.toml +35 -0
  88. package/gemini/commands/definitions/cmd-plan-prd-details.toml +35 -0
  89. package/gemini/commands/definitions/cmd-plan-prd-master.toml +36 -0
  90. package/gemini/commands/definitions/cmd-plan-req-lock.toml +36 -0
  91. package/gemini/commands/definitions/cmd-review-code.toml +35 -0
  92. package/gemini/commands/definitions/cmd-sec-dependency-audit.toml +35 -0
  93. package/gemini/commands/definitions/cmd-sec-threat-model.toml +35 -0
  94. package/gemini/commands/definitions/cmd-test-unit-integration.toml +35 -0
  95. package/gemini/gemini-extension.json +6 -0
  96. package/gemini/instructions/GEMINI.template.md +34 -0
  97. package/gemini/settings/editor-policy.json +193 -0
  98. package/{antigravity → gemini}/skills/change-safety-review/SKILL.md +8 -6
  99. package/{antigravity → gemini}/skills/code-review-and-improvement/SKILL.md +8 -3
  100. package/gemini/skills/frontend-repetition-pack/SKILL.md +44 -0
  101. package/gemini/skills/incident-response/SKILL.md +44 -0
  102. package/{antigravity → gemini}/skills/prd-to-production-pipeline/SKILL.md +13 -4
  103. package/{antigravity → gemini}/skills/release-and-operations/SKILL.md +11 -3
  104. package/gemini/skills/security-hardening/SKILL.md +43 -0
  105. package/gemini/skills/service-lifecycle-orchestration/SKILL.md +46 -0
  106. package/{antigravity → gemini}/workflows/workflow-catalog.json +1 -1
  107. package/package.json +4 -4
  108. package/scripts/generate-from-common.mjs +537 -23
  109. package/scripts/init.mjs +310 -41
  110. package/scripts/validate.mjs +264 -32
  111. package/antigravity/README.md +0 -43
  112. package/antigravity/skills/frontend-repetition-pack/SKILL.md +0 -35
  113. package/antigravity/skills/incident-response/SKILL.md +0 -35
  114. package/antigravity/skills/security-hardening/SKILL.md +0 -35
  115. package/antigravity/skills/service-lifecycle-orchestration/SKILL.md +0 -36
  116. package/claude-code/workflows/workflow-catalog.json +0 -688
  117. package/codex/workflows/workflow-catalog.json +0 -450
  118. /package/{antigravity/agents → common/gemini}/agent-catalog.json +0 -0
  119. /package/{antigravity/artifacts → common/gemini}/artifact-catalog.json +0 -0
  120. /package/{common/antigravity → gemini/agents}/agent-catalog.json +0 -0
  121. /package/{common/antigravity → gemini/artifacts}/artifact-catalog.json +0 -0
  122. /package/{antigravity → gemini}/commands/command-catalog.json +0 -0
  123. /package/{antigravity → gemini}/workflows/definitions/WF-FRONTEND-REFACTOR.workflow.yaml +0 -0
  124. /package/{antigravity → gemini}/workflows/definitions/WF-INCIDENT-RESPONSE.workflow.yaml +0 -0
  125. /package/{antigravity → gemini}/workflows/definitions/WF-PRD-TO-PRODUCTION.workflow.yaml +0 -0
  126. /package/{antigravity → gemini}/workflows/definitions/WF-SECURITY-HARDENING.workflow.yaml +0 -0
  127. /package/{antigravity → gemini}/workflows/definitions/WF-SERVICE-E2E.workflow.yaml +0 -0
@@ -12,7 +12,7 @@ const __filename = fileURLToPath(import.meta.url);
12
12
  const __dirname = path.dirname(__filename);
13
13
  const rootDir = path.resolve(__dirname, '..');
14
14
 
15
- const toolDirs = ['claude-code', 'codex', 'antigravity'];
15
+ const toolDirs = ['claude-code', 'codex', 'gemini'];
16
16
  const errors = [];
17
17
 
18
18
  function fail(message) {
@@ -51,6 +51,18 @@ function parseFrontmatter(content) {
51
51
  return result;
52
52
  }
53
53
 
54
+ function normalizeCommandBasename(commandId) {
55
+ const normalized = String(commandId ?? '')
56
+ .trim()
57
+ .toLowerCase()
58
+ .replace(/[^a-z0-9-]+/g, '-')
59
+ .replace(/^-+|-+$/g, '');
60
+ if (!normalized) {
61
+ throw new Error(`invalid command id: ${commandId}`);
62
+ }
63
+ return normalized;
64
+ }
65
+
54
66
  async function validateCatalog() {
55
67
  const catalogPath = path.join(rootDir, 'catalog', 'tool-catalog.ko.json');
56
68
  if (!(await exists(catalogPath))) {
@@ -193,10 +205,11 @@ async function validateCommonSources() {
193
205
  'common/commands/command-catalog.json',
194
206
  'common/workflows/workflow-catalog.json',
195
207
  'common/skills/skill-catalog.json',
208
+ 'common/settings/security-policy.json',
196
209
  'common/claude/subagent-catalog.json',
197
210
  'common/claude/team-catalog.json',
198
- 'common/antigravity/agent-catalog.json',
199
- 'common/antigravity/artifact-catalog.json'
211
+ 'common/gemini/agent-catalog.json',
212
+ 'common/gemini/artifact-catalog.json'
200
213
  ];
201
214
 
202
215
  const commonData = {};
@@ -220,10 +233,8 @@ async function validateCommonSources() {
220
233
  }
221
234
 
222
235
  const toolSet = new Set(Array.isArray(workflowCatalog.tools) ? workflowCatalog.tools : []);
223
- for (const toolId of toolDirs) {
224
- if (!toolSet.has(toolId)) {
225
- fail(`[common/workflows] tools에 필수 tool 누락: ${toolId}`);
226
- }
236
+ if (!toolSet.has('gemini')) {
237
+ fail('[common/workflows] tools에 필수 tool 누락: gemini');
227
238
  }
228
239
 
229
240
  if (!workflowCatalog.workflow_policy || typeof workflowCatalog.workflow_policy !== 'object') {
@@ -358,6 +369,21 @@ async function validateCommonSources() {
358
369
  fail(`[common/skills] 중단 조건 누락: ${skill.id}`);
359
370
  }
360
371
 
372
+ for (const toolId of toolSet) {
373
+ const procedures = skill.procedures?.[toolId] ?? [];
374
+ for (const step of procedures) {
375
+ if (/\bCMD-[A-Z]/.test(step)) {
376
+ fail(`[common/skills] CMD-* 참조 금지 위반: ${skill.id}/${toolId} → "${step.slice(0, 60)}…"`);
377
+ }
378
+ if (/\bWF-[A-Z]/.test(step)) {
379
+ fail(`[common/skills] WF-* 참조 금지 위반: ${skill.id}/${toolId} → "${step.slice(0, 60)}…"`);
380
+ }
381
+ if (/\bART-[A-Z]/.test(step)) {
382
+ fail(`[common/skills] ART-* 참조 금지 위반: ${skill.id}/${toolId} → "${step.slice(0, 60)}…"`);
383
+ }
384
+ }
385
+ }
386
+
361
387
  if (!skill.codex_openai) {
362
388
  fail(`[common/skills] codex_openai 누락: ${skill.id}`);
363
389
  } else {
@@ -369,6 +395,30 @@ async function validateCommonSources() {
369
395
  }
370
396
  }
371
397
  }
398
+
399
+ const securityPolicy = commonData['common/settings/security-policy.json'];
400
+ if (securityPolicy) {
401
+ if (!securityPolicy.policy_id || !securityPolicy.shared_permissions) {
402
+ fail('[common/settings] policy_id/shared_permissions 누락');
403
+ }
404
+ const shared = securityPolicy.shared_permissions ?? {};
405
+ for (const field of [
406
+ 'allow_bash',
407
+ 'ask_bash',
408
+ 'deny_bash',
409
+ 'deny_read',
410
+ 'deny_edit'
411
+ ]) {
412
+ if (!Array.isArray(shared[field])) {
413
+ fail(`[common/settings] 배열 누락: ${field}`);
414
+ }
415
+ }
416
+
417
+ const claude = securityPolicy.claude_code ?? {};
418
+ if (!claude.default_mode || !claude.disable_bypass_permissions_mode) {
419
+ fail('[common/settings] claude_code default_mode/disable_bypass_permissions_mode 누락');
420
+ }
421
+ }
372
422
  }
373
423
 
374
424
  async function validatePackageJson() {
@@ -407,7 +457,7 @@ async function validatePackageJson() {
407
457
  const requiredFiles = [
408
458
  'common',
409
459
  'claude-code',
410
- 'antigravity',
460
+ 'gemini',
411
461
  'codex',
412
462
  'catalog/tool-catalog.ko.json',
413
463
  'scripts/init.mjs',
@@ -506,7 +556,7 @@ async function validateCommandCatalog(toolName) {
506
556
  const filePath = path.join(rootDir, toolName, 'commands', 'command-catalog.json');
507
557
  if (!(await exists(filePath))) {
508
558
  fail(`[${toolName}] command-catalog.json 누락`);
509
- return { commandIds: new Set() };
559
+ return { commandIds: new Set(), commandFileBases: new Set() };
510
560
  }
511
561
 
512
562
  let data;
@@ -514,12 +564,12 @@ async function validateCommandCatalog(toolName) {
514
564
  data = await readJson(filePath);
515
565
  } catch (error) {
516
566
  fail(`[${toolName}] command-catalog.json 파싱 실패: ${error.message}`);
517
- return { commandIds: new Set() };
567
+ return { commandIds: new Set(), commandFileBases: new Set() };
518
568
  }
519
569
 
520
570
  if (!Array.isArray(data.commands) || data.commands.length === 0) {
521
571
  fail(`[${toolName}] commands 배열 누락 또는 비어 있음`);
522
- return { commandIds: new Set() };
572
+ return { commandIds: new Set(), commandFileBases: new Set() };
523
573
  }
524
574
 
525
575
  const requiredFields = [
@@ -536,6 +586,7 @@ async function validateCommandCatalog(toolName) {
536
586
  ];
537
587
 
538
588
  const commandIds = new Set();
589
+ const commandFileBases = new Set();
539
590
  for (const cmd of data.commands) {
540
591
  for (const field of requiredFields) {
541
592
  if (!(field in cmd)) {
@@ -552,6 +603,11 @@ async function validateCommandCatalog(toolName) {
552
603
  fail(`[${toolName}] 중복 명령 ID: ${cmd.id}`);
553
604
  }
554
605
  commandIds.add(cmd.id);
606
+ try {
607
+ commandFileBases.add(normalizeCommandBasename(cmd.id));
608
+ } catch (error) {
609
+ fail(`[${toolName}] 명령 ID 형식 오류: ${cmd.id} (${error.message})`);
610
+ }
555
611
  }
556
612
 
557
613
  const repeatedIds = [
@@ -566,7 +622,7 @@ async function validateCommandCatalog(toolName) {
566
622
  }
567
623
  }
568
624
 
569
- return { commandIds };
625
+ return { commandIds, commandFileBases };
570
626
  }
571
627
 
572
628
  async function validateWorkflowCatalog(toolName, commandIds) {
@@ -620,7 +676,7 @@ async function validateWorkflowCatalog(toolName, commandIds) {
620
676
  }
621
677
  }
622
678
 
623
- async function validateClaudeExtras() {
679
+ async function validateClaudeExtras(commandFileBases) {
624
680
  const subagentsPath = path.join(rootDir, 'claude-code', 'subagents');
625
681
  if (!(await exists(subagentsPath))) {
626
682
  fail('[claude-code] subagents 디렉터리 누락');
@@ -645,30 +701,58 @@ async function validateClaudeExtras() {
645
701
  if (!(await exists(teamCatalog))) {
646
702
  fail('[claude-code] team-catalog.json 누락');
647
703
  }
704
+
705
+ const commandDir = path.join(rootDir, 'claude-code', 'commands', 'native');
706
+ if (!(await exists(commandDir))) {
707
+ fail('[claude-code] commands/native 디렉터리 누락');
708
+ return;
709
+ }
710
+
711
+ const commandFiles = new Set((await fs.readdir(commandDir)).filter((file) => file.endsWith('.md')));
712
+ for (const base of commandFileBases) {
713
+ const expected = `${base}.md`;
714
+ if (!commandFiles.has(expected)) {
715
+ fail(`[claude-code] native command 누락: commands/native/${expected}`);
716
+ }
717
+ }
718
+ }
719
+
720
+ async function validateCodexExtras(commandFileBases) {
721
+ const codexSkillDir = path.join(rootDir, 'codex', 'skills');
722
+ for (const base of commandFileBases) {
723
+ const skillFile = path.join(codexSkillDir, base, 'SKILL.md');
724
+ const openAiYaml = path.join(codexSkillDir, base, 'agents', 'openai.yaml');
725
+ if (!(await exists(skillFile))) {
726
+ fail(`[codex] 명령 스킬 누락: skills/${base}/SKILL.md`);
727
+ }
728
+ if (!(await exists(openAiYaml))) {
729
+ fail(`[codex] 명령 스킬 openai.yaml 누락: skills/${base}/agents/openai.yaml`);
730
+ }
731
+ }
648
732
  }
649
733
 
650
- async function validateAntigravityExtras() {
651
- const agentCatalog = path.join(rootDir, 'antigravity', 'agents', 'agent-catalog.json');
652
- const artifactCatalog = path.join(rootDir, 'antigravity', 'artifacts', 'artifact-catalog.json');
734
+ async function validateGeminiExtras(commandFileBases) {
735
+ const agentCatalog = path.join(rootDir, 'gemini', 'agents', 'agent-catalog.json');
736
+ const artifactCatalog = path.join(rootDir, 'gemini', 'artifacts', 'artifact-catalog.json');
653
737
 
654
738
  for (const f of [agentCatalog, artifactCatalog]) {
655
739
  if (!(await exists(f))) {
656
- fail(`[antigravity] 누락: ${path.relative(rootDir, f)}`);
740
+ fail(`[gemini] 누락: ${path.relative(rootDir, f)}`);
657
741
  continue;
658
742
  }
659
743
 
660
744
  try {
661
745
  await readJson(f);
662
746
  } catch (error) {
663
- fail(`[antigravity] JSON 파싱 실패: ${path.relative(rootDir, f)} (${error.message})`);
747
+ fail(`[gemini] JSON 파싱 실패: ${path.relative(rootDir, f)} (${error.message})`);
664
748
  }
665
749
  }
666
750
 
667
- const workflowCatalogPath = path.join(rootDir, 'antigravity', 'workflows', 'workflow-catalog.json');
668
- const workflowDefsDir = path.join(rootDir, 'antigravity', 'workflows', 'definitions');
751
+ const workflowCatalogPath = path.join(rootDir, 'gemini', 'workflows', 'workflow-catalog.json');
752
+ const workflowDefsDir = path.join(rootDir, 'gemini', 'workflows', 'definitions');
669
753
 
670
754
  if (!(await exists(workflowDefsDir))) {
671
- fail('[antigravity] workflow definitions 디렉터리 누락');
755
+ fail('[gemini] workflow definitions 디렉터리 누락');
672
756
  return;
673
757
  }
674
758
 
@@ -676,7 +760,7 @@ async function validateAntigravityExtras() {
676
760
  try {
677
761
  workflowCatalog = await readJson(workflowCatalogPath);
678
762
  } catch (error) {
679
- fail(`[antigravity] workflow-catalog.json 파싱 실패: ${error.message}`);
763
+ fail(`[gemini] workflow-catalog.json 파싱 실패: ${error.message}`);
680
764
  return;
681
765
  }
682
766
 
@@ -690,7 +774,39 @@ async function validateAntigravityExtras() {
690
774
  for (const workflowId of workflowIds) {
691
775
  const expected = `${workflowId}.workflow.yaml`;
692
776
  if (!definitionFiles.includes(expected)) {
693
- fail(`[antigravity] workflow definition 누락: ${expected}`);
777
+ fail(`[gemini] workflow definition 누락: ${expected}`);
778
+ }
779
+ }
780
+
781
+ const commandDefinitionsDir = path.join(rootDir, 'gemini', 'commands', 'definitions');
782
+ if (!(await exists(commandDefinitionsDir))) {
783
+ fail('[gemini] commands/definitions 디렉터리 누락');
784
+ return;
785
+ }
786
+
787
+ const commandDefinitionFiles = new Set(
788
+ (await fs.readdir(commandDefinitionsDir)).filter((file) => file.endsWith('.toml'))
789
+ );
790
+ for (const base of commandFileBases) {
791
+ const expected = `${base}.toml`;
792
+ if (!commandDefinitionFiles.has(expected)) {
793
+ fail(`[gemini] command definition 누락: commands/definitions/${expected}`);
794
+ }
795
+ }
796
+
797
+ const extensionJsonPath = path.join(rootDir, 'gemini', 'gemini-extension.json');
798
+ if (!(await exists(extensionJsonPath))) {
799
+ fail('[gemini] gemini-extension.json 누락');
800
+ } else {
801
+ try {
802
+ const extensionData = await readJson(extensionJsonPath);
803
+ for (const field of ['name', 'version', 'description']) {
804
+ if (!extensionData[field]) {
805
+ fail(`[gemini] gemini-extension.json 필수 필드 누락: ${field}`);
806
+ }
807
+ }
808
+ } catch (error) {
809
+ fail(`[gemini] gemini-extension.json 파싱 실패: ${error.message}`);
694
810
  }
695
811
  }
696
812
  }
@@ -704,6 +820,89 @@ async function validateReadmes() {
704
820
  }
705
821
  }
706
822
 
823
+ async function validateSettingsOutputs() {
824
+ const settingsFiles = [
825
+ 'claude-code/settings/settings.json',
826
+ 'claude-code/settings/settings.local.json',
827
+ 'gemini/settings/editor-policy.json',
828
+ 'codex/settings/runtime-policy.json'
829
+ ];
830
+
831
+ for (const relPath of settingsFiles) {
832
+ const fullPath = path.join(rootDir, relPath);
833
+ if (!(await exists(fullPath))) {
834
+ fail(`[settings] 파일 누락: ${relPath}`);
835
+ continue;
836
+ }
837
+ try {
838
+ await readJson(fullPath);
839
+ } catch (error) {
840
+ fail(`[settings] JSON 파싱 실패: ${relPath} (${error.message})`);
841
+ }
842
+ }
843
+
844
+ const claudeProjectPath = path.join(
845
+ rootDir,
846
+ 'claude-code',
847
+ 'settings',
848
+ 'settings.json'
849
+ );
850
+ if (await exists(claudeProjectPath)) {
851
+ try {
852
+ const claude = await readJson(claudeProjectPath);
853
+ const permissions = claude.permissions ?? {};
854
+ const validModes = new Set([
855
+ 'default',
856
+ 'acceptEdits',
857
+ 'plan',
858
+ 'dontAsk',
859
+ 'bypassPermissions'
860
+ ]);
861
+ if (!validModes.has(permissions.defaultMode)) {
862
+ fail(`[settings] Claude defaultMode 값 오류: ${permissions.defaultMode}`);
863
+ }
864
+ for (const key of ['allow', 'ask', 'deny']) {
865
+ if (!Array.isArray(permissions[key])) {
866
+ fail(`[settings] Claude permissions.${key} 누락`);
867
+ }
868
+ }
869
+ } catch (error) {
870
+ fail(`[settings] Claude 설정 검증 실패: ${error.message}`);
871
+ }
872
+ }
873
+
874
+ const codexAgentsPermissionPath = path.join(
875
+ rootDir,
876
+ 'codex',
877
+ 'instructions',
878
+ 'AGENTS.permissions.generated.md'
879
+ );
880
+ if (!(await exists(codexAgentsPermissionPath))) {
881
+ fail('[settings] Codex AGENTS.permissions.generated.md 누락');
882
+ }
883
+ }
884
+
885
+ async function validateProjectRuleTemplates() {
886
+ const requiredFiles = [
887
+ 'claude-code/instructions/CLAUDE.template.md',
888
+ 'codex/instructions/AGENTS.template.md',
889
+ 'gemini/instructions/GEMINI.template.md'
890
+ ];
891
+
892
+ for (const relPath of requiredFiles) {
893
+ const fullPath = path.join(rootDir, relPath);
894
+ if (!(await exists(fullPath))) {
895
+ fail(`[project-rules] 템플릿 누락: ${relPath}`);
896
+ continue;
897
+ }
898
+
899
+ const content = await fs.readFile(fullPath, 'utf8');
900
+ if (!content.trim()) {
901
+ fail(`[project-rules] 템플릿 비어 있음: ${relPath}`);
902
+ }
903
+ }
904
+ }
905
+
707
906
  async function runCliSmokeTests() {
708
907
  const nodeBin = process.execPath;
709
908
  const cliPath = path.join(rootDir, 'scripts', 'init.mjs');
@@ -723,7 +922,7 @@ async function runCliSmokeTests() {
723
922
  '--tool',
724
923
  'codex',
725
924
  '--components',
726
- 'skills,workflows,commands',
925
+ 'skills,commands',
727
926
  '--target',
728
927
  '/tmp/tri-agent-manager-validate',
729
928
  '--dry-run',
@@ -765,7 +964,7 @@ async function runCliSmokeTests() {
765
964
  '--tool',
766
965
  'codex',
767
966
  '--components',
768
- 'skills,workflows,commands',
967
+ 'skills,commands',
769
968
  '--target',
770
969
  '/tmp/tri-agent-manager-validate',
771
970
  '--dry-run',
@@ -785,11 +984,11 @@ async function runCliSmokeTests() {
785
984
  cliPath,
786
985
  'install',
787
986
  '--tool',
788
- 'antigravity',
987
+ 'gemini',
789
988
  '--components',
790
989
  'skills,workflows',
791
990
  '--install-root',
792
- 'antigravity=.agent-custom',
991
+ 'gemini=.gemini-custom',
793
992
  '--target',
794
993
  '/tmp/tri-agent-manager-validate',
795
994
  '--dry-run',
@@ -802,6 +1001,30 @@ async function runCliSmokeTests() {
802
1001
  fail(`[cli] install --install-root dry-run 실행 실패: ${error.message}`);
803
1002
  }
804
1003
 
1004
+ try {
1005
+ await execFileAsync(
1006
+ nodeBin,
1007
+ [
1008
+ cliPath,
1009
+ 'install',
1010
+ '--tool',
1011
+ 'gemini',
1012
+ '--components',
1013
+ 'skills',
1014
+ '--project-rules',
1015
+ 'if-instructions',
1016
+ '--target',
1017
+ '/tmp/tri-agent-manager-validate',
1018
+ '--dry-run',
1019
+ '--yes',
1020
+ '--non-interactive'
1021
+ ],
1022
+ { cwd: rootDir }
1023
+ );
1024
+ } catch (error) {
1025
+ fail(`[cli] install --project-rules dry-run 실행 실패: ${error.message}`);
1026
+ }
1027
+
805
1028
  try {
806
1029
  await execFileAsync(
807
1030
  nodeBin,
@@ -851,7 +1074,7 @@ async function runCliSmokeTests() {
851
1074
  '--tool',
852
1075
  'codex',
853
1076
  '--components',
854
- 'skills,workflows,commands',
1077
+ 'skills,commands',
855
1078
  '--target',
856
1079
  '/tmp/tri-agent-manager-validate',
857
1080
  '--dry-run',
@@ -870,15 +1093,24 @@ async function main() {
870
1093
  await validateCommonSources();
871
1094
  await validateCatalog();
872
1095
  await validateReadmes();
1096
+ await validateSettingsOutputs();
1097
+ await validateProjectRuleTemplates();
873
1098
 
1099
+ const commandFileBaseByTool = {};
1100
+ let geminiCommandIds = new Set();
874
1101
  for (const toolName of toolDirs) {
875
1102
  await validateSkillDirectory(toolName);
876
- const { commandIds } = await validateCommandCatalog(toolName);
877
- await validateWorkflowCatalog(toolName, commandIds);
1103
+ const { commandIds, commandFileBases } = await validateCommandCatalog(toolName);
1104
+ commandFileBaseByTool[toolName] = commandFileBases;
1105
+ if (toolName === 'gemini') {
1106
+ geminiCommandIds = commandIds;
1107
+ }
878
1108
  }
1109
+ await validateWorkflowCatalog('gemini', geminiCommandIds);
879
1110
 
880
- await validateClaudeExtras();
881
- await validateAntigravityExtras();
1111
+ await validateClaudeExtras(commandFileBaseByTool['claude-code'] ?? new Set());
1112
+ await validateCodexExtras(commandFileBaseByTool.codex ?? new Set());
1113
+ await validateGeminiExtras(commandFileBaseByTool.gemini ?? new Set());
882
1114
  await runCliSmokeTests();
883
1115
 
884
1116
  if (errors.length > 0) {
@@ -1,43 +0,0 @@
1
- # Antigravity 운영팩
2
-
3
- 이 폴더는 Antigravity의 Manager-에이전트-Artifact 흐름을 기준으로, 서비스 운영 전체를 실행 가능한 형태로 정리한 패키지입니다.
4
- 정의 원천은 저장소 `common/*`이며, 이 폴더의 파일은 생성 스크립트(`npm run generate`) 결과입니다.
5
- 직접 수정 대신 공통 원천을 수정한 뒤 재생성해 주세요.
6
-
7
- ## 폴더 구성
8
-
9
- - `skills/`: 역할별 실행 스킬
10
- - `agents/agent-catalog.json`: 에이전트 역할 카탈로그
11
- - `artifacts/artifact-catalog.json`: 단계별 Artifact 계약
12
- - `workflows/workflow-catalog.json`: 오케스트레이션 워크플로우
13
- - `workflows/definitions/*.workflow.yaml`: Antigravity 실행용 워크플로우 정의 파일
14
- - `commands/command-catalog.json`: 공통 명령 계약
15
-
16
- ## 빠른 시작
17
-
18
- 1. `WF-SERVICE-E2E`(기본 E2E), `WF-SECURITY-HARDENING`(보안), `WF-INCIDENT-RESPONSE`(장애 대응), `WF-PRD-TO-PRODUCTION`(PRD→구현) 등 목적별 워크플로우를 선택해 주세요.
19
- 2. 각 단계의 `input_artifact` 필드를 먼저 검증해 주세요.
20
- 3. 지정된 `agent`가 `commands`를 수행합니다.
21
- 4. `output_artifact` 검증 후 다음 단계로 진행해 주세요.
22
-
23
- 워크플로우 카탈로그에서 선택한 ID와 동일한 이름의 정의 파일을 `workflows/definitions/`에서 사용하시면 됩니다. 예: `WF-SERVICE-E2E.workflow.yaml`
24
-
25
- ## 반복 작업 역할 분리
26
-
27
- - UI 컴포넌트화: `frontend-repetition-agent` + `CMD-DEV-FE-UI-COMPONENTIZE`
28
- - Hook 분리: `frontend-repetition-agent` + `CMD-DEV-FE-HOOK-SEPARATE`
29
- - 성능 최적화: `performance-agent` + `CMD-DEV-PERF-OPTIMIZE`
30
- - 변경점 안전 검토: `change-safety-review` + `CMD-TEST-UNIT-INTEGRATION`, `CMD-REVIEW-CODE`
31
- - PRD 작성: `prd-writer-agent`
32
-
33
- ## 운영 규칙
34
-
35
- - Manager 에이전트가 단계 전환 권한을 가집니다.
36
- - Artifact 검증 실패 시 단계 중단 후 원인 수정을 우선해 주세요.
37
- - 보안/배포 단계는 우회 없이 게이트를 통과해야 합니다.
38
-
39
- ## 참고 문서 (검증일: 2026-02-17)
40
-
41
- - [Google Antigravity 발표](https://developers.googleblog.com/build-with-google-antigravity-our-new-agentic-development-platform/)
42
- - [Antigravity 공식 문서](https://antigravity.dev/docs)
43
- - [Antigravity 워크플로우 문서](https://antigravity.im/documentation)
@@ -1,35 +0,0 @@
1
- ---
2
- name: frontend-repetition-pack
3
- description: UI 컴포넌트화, Hook 분리, 성능 최적화를 표준 단계로 실행한다. 반복 프론트엔드 개선 작업에서 사용한다.
4
- ---
5
-
6
- # 시작 전 체크리스트
7
-
8
- - 중복 UI 후보 목록을 수집한다 (화면/컴포넌트/사용 횟수).
9
- - 기준 지표를 기록한다 (번들 크기, 렌더 횟수, 핵심 UX 지연 시간).
10
- - 디자인 토큰/컴포넌트 규칙을 확인한다.
11
- - 상태 로직 분리 대상(부수효과/비동기/공유 상태)을 표시한다.
12
-
13
- # 실행 절차
14
-
15
- 1. `CMD-DEV-FE-UI-COMPONENTIZE`
16
- 2. `CMD-DEV-FE-HOOK-SEPARATE`
17
- 3. `CMD-DEV-PERF-OPTIMIZE`
18
-
19
- # 결과 보고 형식
20
-
21
- - 컴포넌트화 결과: 기존->신규 매핑, 공통 Props 계약
22
- - Hook 분리 결과: Hook 이름, 입력/출력, 부수효과 정책
23
- - 성능 결과: 전/후 지표와 측정 조건
24
- - 남은 리팩터 항목: 우선순위와 예상 영향
25
-
26
- # 중단 조건
27
-
28
- - 시각적 회귀가 차단 이슈 수준으로 발생한 경우
29
- - 컴포넌트 계약이 확정되지 않아 호출부 정리가 불가능한 경우
30
- - 전/후 성능 비교가 불가능해 개선 효과를 증명할 수 없는 경우
31
-
32
- # 품질 규칙
33
-
34
- - 단계별 전후 지표를 Artifact에 남긴다.
35
- - 계약 없는 리팩터링 금지
@@ -1,35 +0,0 @@
1
- ---
2
- name: incident-response
3
- description: 장애 대응, 근본 원인 수정, 재발 방지까지 수행한다. 운영 장애 및 핫픽스 대응에서 사용한다.
4
- ---
5
-
6
- # 시작 전 체크리스트
7
-
8
- - 장애 심각도(SEV), 영향 범위, 시작 시각을 확정한다.
9
- - 즉시 복구 경로(롤백/우회/트래픽 차단)를 준비한다.
10
- - 커뮤니케이션 채널과 의사결정 책임자를 지정한다.
11
- - 로그/메트릭/알림 스냅샷을 보존한다.
12
-
13
- # 실행 절차
14
-
15
- 1. `CMD-INCIDENT-TRIAGE`로 복구 우선
16
- 2. `CMD-IMPROVE-TECHDEBT`로 근본 원인 보완
17
- 3. `CMD-DOC-HANDOFF`로 재발 방지 문서화
18
-
19
- # 결과 보고 형식
20
-
21
- - 타임라인: 탐지->완화->복구 시각
22
- - 복구 조치: 실행 명령/설정 변경/결과
23
- - 근본 원인: 기술 원인, 프로세스 원인
24
- - 재발 방지 액션: 담당자, 마감일, 검증 방법
25
-
26
- # 중단 조건
27
-
28
- - 고객 영향이 지속되는데 복구 경로가 없는 경우
29
- - 데이터 손상 가능성이 있어 즉시 격리가 필요한 경우
30
- - 재발 방지 액션의 책임자/기한이 확정되지 않은 경우
31
-
32
- # 품질 규칙
33
-
34
- - RCA와 재발 방지 액션 없는 종료 금지
35
- - 복구와 개선을 분리 보고
@@ -1,35 +0,0 @@
1
- ---
2
- name: security-hardening
3
- description: 위협 모델링과 취약점 감사를 수행하고 보완 및 재검증까지 실행한다. 보안 강화 요청에서 사용한다.
4
- ---
5
-
6
- # 시작 전 체크리스트
7
-
8
- - 신뢰 경계와 보호 대상 자산을 확정한다.
9
- - 의존성 목록과 현재 취약점 현황을 수집한다.
10
- - 위협 모델링 범위(인증/인가/데이터/운영)를 고정한다.
11
- - 예외 승인 정책(책임자, 만료일)을 준비한다.
12
-
13
- # 실행 절차
14
-
15
- 1. `WF-SECURITY-HARDENING` 실행
16
- 2. `CMD-SEC-THREAT-MODEL`, `CMD-SEC-DEPENDENCY-AUDIT` 수행
17
- 3. 보완 반영 후 테스트/리뷰 재실행
18
-
19
- # 결과 보고 형식
20
-
21
- - 위협/취약점 목록: 심각도, 영향, 우선순위
22
- - 보완 적용 내역: 코드/설정 변경과 근거
23
- - 재검증 결과: 스캔/테스트/리뷰 결과
24
- - 잔여 위험 및 예외 승인: 책임자, 만료일
25
-
26
- # 중단 조건
27
-
28
- - 치명 취약점이 남아 있는데 배포를 진행하려는 경우
29
- - 고위험 위협에 대한 완화 통제가 정의되지 않은 경우
30
- - 예외 승인이 만료일 없이 요청된 경우
31
-
32
- # 품질 규칙
33
-
34
- - 치명 취약점 0건 전까지 종료 금지
35
- - 예외 수용은 만료일 포함
@@ -1,36 +0,0 @@
1
- ---
2
- name: service-lifecycle-orchestration
3
- description: Plan-Implement-Test-Review-Release 흐름을 Manager 중심으로 실행한다. 신규 서비스 구축 및 대형 기능 출시에 사용한다.
4
- ---
5
-
6
- # 시작 전 체크리스트
7
-
8
- - 요구사항/ADR/범위/비범위를 확정한다.
9
- - 각 단계 책임 역할과 승인자를 지정한다.
10
- - 단계별 진입/종료 기준을 작업 시작 전에 확인한다.
11
- - 리스크와 롤백 전략을 초기 단계에서 기록한다.
12
-
13
- # 실행 절차
14
-
15
- 1. `WF-SERVICE-E2E`를 선택한다.
16
- 2. 단계별 입력 Artifact 스키마를 검증한다.
17
- 3. 해당 단계 에이전트가 명령 ID를 수행한다.
18
- 4. 출력 Artifact 검증 후 다음 단계로 진행한다.
19
-
20
- # 결과 보고 형식
21
-
22
- - 단계 상태: 완료/미완료/차단요인
23
- - 실행 근거: 단계별 명령 ID와 결과
24
- - 품질 상태: 테스트/보안/리뷰 게이트 결과
25
- - 다음 행동: 담당자, 마감 조건, 선행 조건
26
-
27
- # 중단 조건
28
-
29
- - 진입 기준이 충족되지 않은 단계가 있는 경우
30
- - 차단 이슈가 해결되지 않았는데 다음 단계로 이동하려는 경우
31
- - 롤백 전략 없이 배포 단계 진입이 요청된 경우
32
-
33
- # 품질 규칙
34
-
35
- - Artifact 검증 실패 시 단계 진행 금지
36
- - command ID 없는 임의 실행 금지