@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
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@dusky-bluehour/agent-service",
3
- "version": "0.6.6",
3
+ "version": "0.6.8",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "description": "Service operation skills/workflows pack for Claude Code, Antigravity, and Codex",
7
+ "description": "Service operation skills/workflows pack for Claude Code, Gemini CLI, and Codex",
8
8
  "type": "module",
9
9
  "bin": {
10
10
  "tri-agent-manager": "scripts/init.mjs"
@@ -20,7 +20,7 @@
20
20
  "files": [
21
21
  "common",
22
22
  "claude-code",
23
- "antigravity",
23
+ "gemini",
24
24
  "codex",
25
25
  "catalog/tool-catalog.ko.json",
26
26
  "scripts/init.mjs",
@@ -34,7 +34,7 @@
34
34
  "workflow",
35
35
  "codex",
36
36
  "claude-code",
37
- "antigravity",
37
+ "gemini-cli",
38
38
  "devops",
39
39
  "security",
40
40
  "code-review"
@@ -8,7 +8,7 @@ const __filename = fileURLToPath(import.meta.url);
8
8
  const __dirname = path.dirname(__filename);
9
9
  const rootDir = path.resolve(__dirname, '..');
10
10
 
11
- const DEFAULT_TOOL_IDS = ['claude-code', 'codex', 'antigravity'];
11
+ const DEFAULT_TOOL_IDS = ['claude-code', 'codex', 'gemini'];
12
12
  const args = new Set(process.argv.slice(2));
13
13
  const checkMode = args.has('--check');
14
14
 
@@ -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 [
@@ -124,7 +159,7 @@ function renderYamlList(lines, indent, values) {
124
159
  }
125
160
  }
126
161
 
127
- function renderAntigravityWorkflowDefinition(workflow) {
162
+ function renderGeminiWorkflowDefinition(workflow) {
128
163
  const lines = [];
129
164
  lines.push('# generated by scripts/generate-from-common.mjs');
130
165
  lines.push('workflow:');
@@ -153,6 +188,346 @@ 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 renderGeminiCommandToml(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
+ const promptLines = [];
258
+ promptLines.push(`${command.id} - ${command.name}`);
259
+ promptLines.push(`Phase: ${command.phase ?? ''} | Owner: ${command.owner_role ?? ''}`);
260
+ promptLines.push('');
261
+ promptLines.push('[Purpose]');
262
+ promptLines.push(String(command.purpose ?? ''));
263
+ promptLines.push('');
264
+ promptLines.push('[Input Contract]');
265
+ promptLines.push('Required:');
266
+ for (const item of (requiredInputs ?? [])) {
267
+ promptLines.push(`- ${item}`);
268
+ }
269
+ promptLines.push('Optional:');
270
+ for (const item of (optionalInputs ?? [])) {
271
+ promptLines.push(`- ${item}`);
272
+ }
273
+ promptLines.push('');
274
+ promptLines.push('[Execution Steps]');
275
+ for (const [index, step] of (executionSteps ?? []).entries()) {
276
+ promptLines.push(`${index + 1}. ${step}`);
277
+ }
278
+ promptLines.push('');
279
+ promptLines.push('[Quality Gates]');
280
+ for (const gate of (qualityGates ?? [])) {
281
+ promptLines.push(`- ${gate}`);
282
+ }
283
+ promptLines.push('');
284
+ promptLines.push('[Output Artifacts]');
285
+ for (const artifact of (artifacts ?? [])) {
286
+ promptLines.push(`- ${artifact}`);
287
+ }
288
+ promptLines.push('');
289
+ promptLines.push('[Handoff]');
290
+ promptLines.push(`- next_roles: ${(Array.isArray(nextRoles) && nextRoles.length > 0 ? nextRoles.join(', ') : '(none)')}`);
291
+ promptLines.push(`- blockers: ${(Array.isArray(blockers) && blockers.length > 0 ? blockers.join(', ') : '(none)')}`);
292
+ promptLines.push('');
293
+ promptLines.push('Additional context: {{args}}');
294
+
295
+ const description = `${command.name} (${command.phase ?? ''} · ${command.owner_role ?? ''})`;
296
+
297
+ return [
298
+ `prompt = """${promptLines.join('\n')}"""`,
299
+ `description = "${description.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`,
300
+ ''
301
+ ].join('\n');
302
+ }
303
+
304
+ function renderCodexCommandSkillMarkdown(command, skillName) {
305
+ const requiredInputs = Array.isArray(command.input_contract?.required)
306
+ ? command.input_contract.required.map((item) => `[필수] ${item}`)
307
+ : [];
308
+ const optionalInputs = Array.isArray(command.input_contract?.optional)
309
+ ? command.input_contract.optional.map((item) => `[선택] ${item}`)
310
+ : [];
311
+ const executionSteps = Array.isArray(command.execution_contract?.steps)
312
+ ? command.execution_contract.steps
313
+ : [];
314
+ const qualityGates = Array.isArray(command.quality_gates) ? command.quality_gates : [];
315
+ const artifacts = Array.isArray(command.output_contract?.artifacts)
316
+ ? command.output_contract.artifacts
317
+ : [];
318
+ const nextRoles = Array.isArray(command.handoff?.next_roles) ? command.handoff.next_roles : [];
319
+ const blockers = Array.isArray(command.handoff?.blockers) ? command.handoff.blockers : [];
320
+
321
+ const checklistLines = toBulletLines([...requiredInputs, ...optionalInputs]);
322
+ const procedureLines = toNumberedLines([
323
+ `명령 계약을 확인한다: ${command.id} (${command.name})`,
324
+ ...executionSteps,
325
+ '품질 게이트를 검증한다.',
326
+ '산출물과 핸드오프를 보고한다.'
327
+ ]);
328
+ const reportLines = toBulletLines([
329
+ `실행 명령: ${command.id}`,
330
+ `입력 검증: 필수 입력 충족 여부 / 누락 항목`,
331
+ `품질 게이트: ${qualityGates.length > 0 ? qualityGates.join(' | ') : '(없음)'}`,
332
+ `산출물: ${artifacts.length > 0 ? artifacts.join(', ') : '(없음)'}`,
333
+ `핸드오프: 다음 역할 ${nextRoles.length > 0 ? nextRoles.join(', ') : '(없음)'}`
334
+ ]);
335
+ const stopLines = toBulletLines([
336
+ '필수 입력이 누락된 경우',
337
+ '품질 게이트를 충족하지 못한 경우',
338
+ ...blockers
339
+ ]);
340
+ const qualityRuleLines = toBulletLines([
341
+ '검증되지 않은 추정은 사실과 분리해서 기록한다.',
342
+ '품질 게이트를 우회하지 않는다.',
343
+ ...qualityGates
344
+ ]);
345
+
346
+ return [
347
+ '---',
348
+ `name: ${skillName}`,
349
+ `description: ${command.name} 명령 계약을 Codex 스킬 형태로 실행한다.`,
350
+ '---',
351
+ '',
352
+ '# 시작 전 체크리스트',
353
+ '',
354
+ ...checklistLines,
355
+ '',
356
+ '# 실행 절차',
357
+ '',
358
+ ...procedureLines,
359
+ '',
360
+ '# 결과 보고 형식',
361
+ '',
362
+ ...reportLines,
363
+ '',
364
+ '# 중단 조건',
365
+ '',
366
+ ...stopLines,
367
+ '',
368
+ '# 품질 규칙',
369
+ '',
370
+ ...qualityRuleLines,
371
+ ''
372
+ ].join('\n');
373
+ }
374
+
375
+ function renderCodexCommandOpenAiYaml(command) {
376
+ return [
377
+ 'skill:',
378
+ ` display_name: ${quoteYamlString(command.name ?? command.id)}`,
379
+ ` short_description: ${quoteYamlString(`${command.phase ?? ''} · ${command.owner_role ?? ''}`)}`,
380
+ ` default_prompt: ${quoteYamlString(`${command.id} 명령 계약을 준수해 실행해줘.`)}`,
381
+ ''
382
+ ].join('\n');
383
+ }
384
+
385
+ function buildClaudePermissionsFromSecurityPolicy(securityPolicy, includeLocalOverrides = false) {
386
+ const shared = securityPolicy.shared_permissions ?? {};
387
+ const claude = securityPolicy.claude_code ?? {};
388
+
389
+ const allow = [];
390
+ const ask = [];
391
+ const deny = [];
392
+
393
+ if (shared.read_all) {
394
+ allow.push('Read');
395
+ }
396
+ if (shared.edit_all) {
397
+ allow.push('Edit');
398
+ }
399
+
400
+ for (const pattern of shared.allow_bash ?? []) {
401
+ allow.push(toBashRule(pattern));
402
+ }
403
+ for (const pattern of shared.ask_bash ?? []) {
404
+ ask.push(toBashRule(pattern));
405
+ }
406
+ for (const pattern of shared.deny_bash ?? []) {
407
+ deny.push(toBashRule(pattern));
408
+ }
409
+ for (const pattern of shared.deny_read ?? []) {
410
+ deny.push(toPathRule('Read', pattern));
411
+ }
412
+ for (const pattern of shared.deny_edit ?? []) {
413
+ deny.push(toPathRule('Edit', pattern));
414
+ }
415
+
416
+ if (includeLocalOverrides) {
417
+ for (const pattern of claude.local_overrides?.ask_bash ?? []) {
418
+ ask.push(toBashRule(pattern));
419
+ }
420
+ }
421
+
422
+ return {
423
+ defaultMode: claude.default_mode ?? 'acceptEdits',
424
+ disableBypassPermissionsMode: claude.disable_bypass_permissions_mode ?? 'disable',
425
+ additionalDirectories: includeLocalOverrides
426
+ ? (claude.local_overrides?.additional_directories ?? [])
427
+ : (claude.additional_directories ?? []),
428
+ allow: [...new Set(allow)],
429
+ ask: [...new Set(ask)],
430
+ deny: [...new Set(deny)]
431
+ };
432
+ }
433
+
434
+ function renderClaudeProjectSettingsJson(securityPolicy) {
435
+ return {
436
+ $schema: 'https://json.schemastore.org/claude-code-settings.json',
437
+ permissions: buildClaudePermissionsFromSecurityPolicy(securityPolicy, false),
438
+ enabledPlugins: securityPolicy.claude_code?.enabled_plugins ?? {}
439
+ };
440
+ }
441
+
442
+ function renderClaudeLocalSettingsJson(securityPolicy) {
443
+ const claude = securityPolicy.claude_code ?? {};
444
+ return {
445
+ $schema: 'https://json.schemastore.org/claude-code-settings.json',
446
+ permissions: {
447
+ additionalDirectories: claude.local_overrides?.additional_directories ?? [],
448
+ ask: [...new Set((claude.local_overrides?.ask_bash ?? []).map((pattern) => toBashRule(pattern)))]
449
+ }
450
+ };
451
+ }
452
+
453
+ function renderGeminiEditorPolicyJson(securityPolicy) {
454
+ const shared = securityPolicy.shared_permissions ?? {};
455
+ return {
456
+ schema_version: '1.0.0',
457
+ policy_id: securityPolicy.policy_id ?? 'strict-dev',
458
+ description_ko:
459
+ 'Gemini CLI에서 수동 반영할 수 있는 프로젝트 보안/권한 정책 템플릿',
460
+ editor: securityPolicy.gemini?.editor_settings ?? {},
461
+ command_policy: {
462
+ allow_shell: shared.allow_bash ?? [],
463
+ ask_shell: shared.ask_bash ?? [],
464
+ deny_shell: shared.deny_bash ?? []
465
+ },
466
+ path_policy: {
467
+ deny_read: shared.deny_read ?? [],
468
+ deny_edit: shared.deny_edit ?? []
469
+ }
470
+ };
471
+ }
472
+
473
+ function renderCodexRuntimePolicyJson(securityPolicy) {
474
+ const shared = securityPolicy.shared_permissions ?? {};
475
+ return {
476
+ schema_version: '1.0.0',
477
+ policy_id: securityPolicy.policy_id ?? 'strict-dev',
478
+ description_ko:
479
+ 'Codex 프로젝트 규칙(AGENTS.md)과 함께 사용하는 런타임 권한 정책 템플릿',
480
+ runtime: securityPolicy.codex?.runtime_policy ?? {},
481
+ command_policy: {
482
+ allow_shell: shared.allow_bash ?? [],
483
+ ask_shell: shared.ask_bash ?? [],
484
+ deny_shell: shared.deny_bash ?? []
485
+ },
486
+ path_policy: {
487
+ deny_read: shared.deny_read ?? [],
488
+ deny_edit: shared.deny_edit ?? []
489
+ }
490
+ };
491
+ }
492
+
493
+ function renderCodexPermissionsMarkdown(securityPolicy) {
494
+ const shared = securityPolicy.shared_permissions ?? {};
495
+ const runtime = securityPolicy.codex?.runtime_policy ?? {};
496
+ const allowShell = shared.allow_bash ?? [];
497
+ const askShell = shared.ask_bash ?? [];
498
+ const denyShell = shared.deny_bash ?? [];
499
+
500
+ return [
501
+ '# Codex 권한 정책 템플릿',
502
+ '',
503
+ '이 문서는 `common/settings/security-policy.json`에서 자동 생성됩니다.',
504
+ '`AGENTS.md`의 프로젝트 규칙 섹션에 붙여 넣어 팀 기본 정책으로 사용하세요.',
505
+ '',
506
+ '## 런타임 정책',
507
+ '',
508
+ ...toBulletLines([
509
+ `sandbox_mode: ${runtime.sandbox_mode ?? 'workspace-write'}`,
510
+ `network_access: ${runtime.network_access ?? 'restricted'}`,
511
+ `git_write_actions: ${runtime.git_write_actions ?? 'ask'}`,
512
+ `destructive_shell: ${runtime.destructive_shell ?? 'deny'}`,
513
+ `global_package_installs: ${runtime.global_package_installs ?? 'deny'}`
514
+ ]),
515
+ '',
516
+ '## Shell 허용 규칙',
517
+ '',
518
+ ...toBulletLines(allowShell.map((rule) => `\`${rule}\``)),
519
+ '',
520
+ '## Shell 확인(ask) 규칙',
521
+ '',
522
+ ...toBulletLines(askShell.map((rule) => `\`${rule}\``)),
523
+ '',
524
+ '## Shell 차단 규칙',
525
+ '',
526
+ ...toBulletLines(denyShell.map((rule) => `\`${rule}\``)),
527
+ ''
528
+ ].join('\n');
529
+ }
530
+
156
531
  function buildWorkflowCatalogByTool(commonWorkflowCatalog) {
157
532
  const toolIds = Array.isArray(commonWorkflowCatalog.tools)
158
533
  ? commonWorkflowCatalog.tools
@@ -268,12 +643,11 @@ async function writeOrCheck(filePath, expected, state) {
268
643
  state.written += 1;
269
644
  }
270
645
 
271
- async function pruneAntigravityWorkflowDefinitions(expectedFileNames, state) {
272
- const dir = path.join(rootDir, 'antigravity', 'workflows', 'definitions');
646
+ async function pruneGeneratedFilesBySuffix(dir, suffix, expectedFileNames, state) {
273
647
  await fs.mkdir(dir, { recursive: true });
274
648
  const entries = await fs.readdir(dir, { withFileTypes: true });
275
649
  for (const entry of entries) {
276
- if (!entry.isFile() || !entry.name.endsWith('.workflow.yaml')) {
650
+ if (!entry.isFile() || !entry.name.endsWith(suffix)) {
277
651
  continue;
278
652
  }
279
653
  if (expectedFileNames.has(entry.name)) {
@@ -289,14 +663,39 @@ async function pruneAntigravityWorkflowDefinitions(expectedFileNames, state) {
289
663
  }
290
664
  }
291
665
 
666
+ async function pruneCodexCommandSkills(expectedDirNames, state) {
667
+ const dir = path.join(rootDir, 'codex', 'skills');
668
+ await fs.mkdir(dir, { recursive: true });
669
+ const entries = await fs.readdir(dir, { withFileTypes: true });
670
+
671
+ for (const entry of entries) {
672
+ if (!entry.isDirectory() || !/^cmd-[a-z0-9-]+$/.test(entry.name)) {
673
+ continue;
674
+ }
675
+ if (expectedDirNames.has(entry.name)) {
676
+ continue;
677
+ }
678
+
679
+ const removePath = path.join(dir, entry.name);
680
+ if (checkMode) {
681
+ state.outOfDate.push(path.relative(rootDir, removePath));
682
+ continue;
683
+ }
684
+ await fs.rm(removePath, { recursive: true, force: true });
685
+ state.deleted += 1;
686
+ }
687
+ }
688
+
292
689
  async function main() {
690
+ const packageJson = await readJson('package.json');
293
691
  const commands = await readJson('common/commands/command-catalog.json');
294
692
  const commonWorkflowCatalog = await readJson('common/workflows/workflow-catalog.json');
295
693
  const skillCatalog = await readJson('common/skills/skill-catalog.json');
694
+ const securityPolicy = await readJson('common/settings/security-policy.json');
296
695
  const claudeSubagents = await readJson('common/claude/subagent-catalog.json');
297
696
  const claudeTeams = await readJson('common/claude/team-catalog.json');
298
- const antigravityAgents = await readJson('common/antigravity/agent-catalog.json');
299
- const antigravityArtifacts = await readJson('common/antigravity/artifact-catalog.json');
697
+ const geminiAgents = await readJson('common/gemini/agent-catalog.json');
698
+ const geminiArtifacts = await readJson('common/gemini/artifact-catalog.json');
300
699
  const { toolIds, catalogs: workflowCatalogByTool } = buildWorkflowCatalogByTool(
301
700
  commonWorkflowCatalog
302
701
  );
@@ -313,23 +712,138 @@ async function main() {
313
712
  await writeOrCheck(commandPath, toPrettyJson(commands), state);
314
713
  }
315
714
 
316
- for (const toolId of toolIds) {
317
- const catalog = workflowCatalogByTool?.[toolId];
318
- if (!catalog) {
319
- throw new Error(`[workflows] tool 누락: ${toolId}`);
715
+ await writeOrCheck(
716
+ path.join(rootDir, 'claude-code', 'settings', 'settings.json'),
717
+ toPrettyJson(renderClaudeProjectSettingsJson(securityPolicy)),
718
+ state
719
+ );
720
+ await writeOrCheck(
721
+ path.join(rootDir, 'claude-code', 'settings', 'settings.local.json'),
722
+ toPrettyJson(renderClaudeLocalSettingsJson(securityPolicy)),
723
+ state
724
+ );
725
+ await writeOrCheck(
726
+ path.join(rootDir, 'gemini', 'settings', 'editor-policy.json'),
727
+ toPrettyJson(renderGeminiEditorPolicyJson(securityPolicy)),
728
+ state
729
+ );
730
+ await writeOrCheck(
731
+ path.join(rootDir, 'codex', 'settings', 'runtime-policy.json'),
732
+ toPrettyJson(renderCodexRuntimePolicyJson(securityPolicy)),
733
+ state
734
+ );
735
+ await writeOrCheck(
736
+ path.join(rootDir, 'codex', 'instructions', 'AGENTS.permissions.generated.md'),
737
+ renderCodexPermissionsMarkdown(securityPolicy),
738
+ state
739
+ );
740
+ await pruneGeneratedFilesBySuffix(
741
+ path.join(rootDir, 'claude-code', 'settings'),
742
+ '.json',
743
+ new Set(['settings.json', 'settings.local.json']),
744
+ state
745
+ );
746
+ await pruneGeneratedFilesBySuffix(
747
+ path.join(rootDir, 'gemini', 'settings'),
748
+ '.json',
749
+ new Set(['editor-policy.json']),
750
+ state
751
+ );
752
+ await pruneGeneratedFilesBySuffix(
753
+ path.join(rootDir, 'codex', 'settings'),
754
+ '.json',
755
+ new Set(['runtime-policy.json']),
756
+ state
757
+ );
758
+
759
+ const claudeCommandFileNames = new Set();
760
+ const geminiCommandFileNames = new Set();
761
+ const codexCommandSkillNames = new Set();
762
+ for (const command of commands.commands ?? []) {
763
+ if (!command?.id) {
764
+ throw new Error('[commands] command id가 비어 있습니다.');
320
765
  }
321
- const workflowPath = path.join(rootDir, toolId, 'workflows', 'workflow-catalog.json');
322
- await writeOrCheck(workflowPath, toPrettyJson(catalog), state);
766
+ const basename = normalizeCommandBasename(command.id);
767
+ claudeCommandFileNames.add(`${basename}.md`);
768
+ geminiCommandFileNames.add(`${basename}.toml`);
769
+ codexCommandSkillNames.add(basename);
770
+
771
+ await writeOrCheck(
772
+ path.join(rootDir, 'claude-code', 'commands', 'native', `${basename}.md`),
773
+ renderClaudeCommandMarkdown(command),
774
+ state
775
+ );
776
+ await writeOrCheck(
777
+ path.join(rootDir, 'gemini', 'commands', 'definitions', `${basename}.toml`),
778
+ renderGeminiCommandToml(command),
779
+ state
780
+ );
781
+ await writeOrCheck(
782
+ path.join(rootDir, 'codex', 'skills', basename, 'SKILL.md'),
783
+ renderCodexCommandSkillMarkdown(command, basename),
784
+ state
785
+ );
786
+ await writeOrCheck(
787
+ path.join(rootDir, 'codex', 'skills', basename, 'agents', 'openai.yaml'),
788
+ renderCodexCommandOpenAiYaml(command),
789
+ state
790
+ );
323
791
  }
792
+ await pruneGeneratedFilesBySuffix(
793
+ path.join(rootDir, 'claude-code', 'commands', 'native'),
794
+ '.md',
795
+ claudeCommandFileNames,
796
+ state
797
+ );
798
+ await pruneGeneratedFilesBySuffix(
799
+ path.join(rootDir, 'gemini', 'commands', 'definitions'),
800
+ '.toml',
801
+ geminiCommandFileNames,
802
+ state
803
+ );
804
+ // Remove legacy .md command definitions (migrated to .toml)
805
+ await pruneGeneratedFilesBySuffix(
806
+ path.join(rootDir, 'gemini', 'commands', 'definitions'),
807
+ '.md',
808
+ new Set(),
809
+ state
810
+ );
811
+ await pruneCodexCommandSkills(codexCommandSkillNames, state);
812
+
813
+ await writeOrCheck(
814
+ path.join(rootDir, 'gemini', 'gemini-extension.json'),
815
+ toPrettyJson({
816
+ name: 'tri-agent-manager',
817
+ version: packageJson.version,
818
+ description: 'Service operation skills and workflows pack for Gemini CLI',
819
+ contextFileName: 'GEMINI.md'
820
+ }),
821
+ state
822
+ );
324
823
 
325
- const antigravityWorkflowNames = new Set();
326
- for (const workflow of workflowCatalogByTool.antigravity?.workflows ?? []) {
824
+ // Workflows are gemini-only: only generate workflow catalog for gemini
825
+ {
826
+ const geminiCatalog = workflowCatalogByTool?.gemini;
827
+ if (!geminiCatalog) {
828
+ throw new Error('[workflows] gemini workflow catalog 누락');
829
+ }
830
+ const workflowPath = path.join(rootDir, 'gemini', 'workflows', 'workflow-catalog.json');
831
+ await writeOrCheck(workflowPath, toPrettyJson(geminiCatalog), state);
832
+ }
833
+
834
+ const geminiWorkflowNames = new Set();
835
+ for (const workflow of workflowCatalogByTool.gemini?.workflows ?? []) {
327
836
  const filename = `${workflow.id}.workflow.yaml`;
328
- antigravityWorkflowNames.add(filename);
329
- const definitionPath = path.join(rootDir, 'antigravity', 'workflows', 'definitions', filename);
330
- await writeOrCheck(definitionPath, renderAntigravityWorkflowDefinition(workflow), state);
837
+ geminiWorkflowNames.add(filename);
838
+ const definitionPath = path.join(rootDir, 'gemini', 'workflows', 'definitions', filename);
839
+ await writeOrCheck(definitionPath, renderGeminiWorkflowDefinition(workflow), state);
331
840
  }
332
- await pruneAntigravityWorkflowDefinitions(antigravityWorkflowNames, state);
841
+ await pruneGeneratedFilesBySuffix(
842
+ path.join(rootDir, 'gemini', 'workflows', 'definitions'),
843
+ '.workflow.yaml',
844
+ geminiWorkflowNames,
845
+ state
846
+ );
333
847
 
334
848
  for (const skill of skillCatalog.skills ?? []) {
335
849
  for (const toolId of toolIds) {
@@ -353,14 +867,14 @@ async function main() {
353
867
  );
354
868
 
355
869
  await writeOrCheck(
356
- path.join(rootDir, 'antigravity', 'agents', 'agent-catalog.json'),
357
- toPrettyJson(antigravityAgents),
870
+ path.join(rootDir, 'gemini', 'agents', 'agent-catalog.json'),
871
+ toPrettyJson(geminiAgents),
358
872
  state
359
873
  );
360
874
 
361
875
  await writeOrCheck(
362
- path.join(rootDir, 'antigravity', 'artifacts', 'artifact-catalog.json'),
363
- toPrettyJson(antigravityArtifacts),
876
+ path.join(rootDir, 'gemini', 'artifacts', 'artifact-catalog.json'),
877
+ toPrettyJson(geminiArtifacts),
364
878
  state
365
879
  );
366
880