@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.
- package/README.md +20 -28
- package/antigravity/README.md +7 -0
- package/antigravity/commands/definitions/cmd-dev-be-api.md +43 -0
- package/antigravity/commands/definitions/cmd-dev-fe-hook-separate.md +43 -0
- package/antigravity/commands/definitions/cmd-dev-fe-ui-componentize.md +43 -0
- package/antigravity/commands/definitions/cmd-dev-perf-optimize.md +43 -0
- package/antigravity/commands/definitions/cmd-dev-sequential-autorun.md +43 -0
- package/antigravity/commands/definitions/cmd-doc-handoff.md +44 -0
- package/antigravity/commands/definitions/cmd-improve-techdebt.md +43 -0
- package/antigravity/commands/definitions/cmd-incident-triage.md +43 -0
- package/antigravity/commands/definitions/cmd-ops-ci-cd-gate.md +43 -0
- package/antigravity/commands/definitions/cmd-ops-deploy.md +43 -0
- package/antigravity/commands/definitions/cmd-ops-monitoring.md +43 -0
- package/antigravity/commands/definitions/cmd-plan-arch-decision.md +43 -0
- package/antigravity/commands/definitions/cmd-plan-implementation-bootstrap.md +43 -0
- package/antigravity/commands/definitions/cmd-plan-prd-details.md +43 -0
- package/antigravity/commands/definitions/cmd-plan-prd-master.md +44 -0
- package/antigravity/commands/definitions/cmd-plan-req-lock.md +44 -0
- package/antigravity/commands/definitions/cmd-review-code.md +43 -0
- package/antigravity/commands/definitions/cmd-sec-dependency-audit.md +43 -0
- package/antigravity/commands/definitions/cmd-sec-threat-model.md +43 -0
- package/antigravity/commands/definitions/cmd-test-unit-integration.md +43 -0
- package/antigravity/instructions/WORKSPACE-RULES.template.md +34 -0
- package/antigravity/settings/editor-policy.json +193 -0
- package/catalog/tool-catalog.ko.json +77 -16
- package/claude-code/README.md +27 -0
- package/claude-code/commands/native/cmd-dev-be-api.md +51 -0
- package/claude-code/commands/native/cmd-dev-fe-hook-separate.md +51 -0
- package/claude-code/commands/native/cmd-dev-fe-ui-componentize.md +51 -0
- package/claude-code/commands/native/cmd-dev-perf-optimize.md +51 -0
- package/claude-code/commands/native/cmd-dev-sequential-autorun.md +51 -0
- package/claude-code/commands/native/cmd-doc-handoff.md +52 -0
- package/claude-code/commands/native/cmd-improve-techdebt.md +51 -0
- package/claude-code/commands/native/cmd-incident-triage.md +51 -0
- package/claude-code/commands/native/cmd-ops-ci-cd-gate.md +51 -0
- package/claude-code/commands/native/cmd-ops-deploy.md +51 -0
- package/claude-code/commands/native/cmd-ops-monitoring.md +51 -0
- package/claude-code/commands/native/cmd-plan-arch-decision.md +51 -0
- package/claude-code/commands/native/cmd-plan-implementation-bootstrap.md +51 -0
- package/claude-code/commands/native/cmd-plan-prd-details.md +51 -0
- package/claude-code/commands/native/cmd-plan-prd-master.md +52 -0
- package/claude-code/commands/native/cmd-plan-req-lock.md +52 -0
- package/claude-code/commands/native/cmd-review-code.md +51 -0
- package/claude-code/commands/native/cmd-sec-dependency-audit.md +51 -0
- package/claude-code/commands/native/cmd-sec-threat-model.md +51 -0
- package/claude-code/commands/native/cmd-test-unit-integration.md +51 -0
- package/claude-code/instructions/CLAUDE.template.md +42 -0
- package/claude-code/settings/settings.json +183 -0
- package/claude-code/settings/settings.local.json +10 -0
- package/codex/README.md +13 -1
- package/codex/instructions/AGENTS.permissions.generated.md +121 -0
- package/codex/instructions/AGENTS.template.md +18 -3
- package/codex/settings/runtime-policy.json +188 -0
- package/codex/skills/cmd-dev-be-api/SKILL.md +43 -0
- package/codex/skills/cmd-dev-be-api/agents/openai.yaml +4 -0
- package/codex/skills/cmd-dev-fe-hook-separate/SKILL.md +43 -0
- package/codex/skills/cmd-dev-fe-hook-separate/agents/openai.yaml +4 -0
- package/codex/skills/cmd-dev-fe-ui-componentize/SKILL.md +43 -0
- package/codex/skills/cmd-dev-fe-ui-componentize/agents/openai.yaml +4 -0
- package/codex/skills/cmd-dev-perf-optimize/SKILL.md +43 -0
- package/codex/skills/cmd-dev-perf-optimize/agents/openai.yaml +4 -0
- package/codex/skills/cmd-dev-sequential-autorun/SKILL.md +43 -0
- package/codex/skills/cmd-dev-sequential-autorun/agents/openai.yaml +4 -0
- package/codex/skills/cmd-doc-handoff/SKILL.md +43 -0
- package/codex/skills/cmd-doc-handoff/agents/openai.yaml +4 -0
- package/codex/skills/cmd-improve-techdebt/SKILL.md +43 -0
- package/codex/skills/cmd-improve-techdebt/agents/openai.yaml +4 -0
- package/codex/skills/cmd-incident-triage/SKILL.md +43 -0
- package/codex/skills/cmd-incident-triage/agents/openai.yaml +4 -0
- package/codex/skills/cmd-ops-ci-cd-gate/SKILL.md +43 -0
- package/codex/skills/cmd-ops-ci-cd-gate/agents/openai.yaml +4 -0
- package/codex/skills/cmd-ops-deploy/SKILL.md +43 -0
- package/codex/skills/cmd-ops-deploy/agents/openai.yaml +4 -0
- package/codex/skills/cmd-ops-monitoring/SKILL.md +43 -0
- package/codex/skills/cmd-ops-monitoring/agents/openai.yaml +4 -0
- package/codex/skills/cmd-plan-arch-decision/SKILL.md +43 -0
- package/codex/skills/cmd-plan-arch-decision/agents/openai.yaml +4 -0
- package/codex/skills/cmd-plan-implementation-bootstrap/SKILL.md +43 -0
- package/codex/skills/cmd-plan-implementation-bootstrap/agents/openai.yaml +4 -0
- package/codex/skills/cmd-plan-prd-details/SKILL.md +43 -0
- package/codex/skills/cmd-plan-prd-details/agents/openai.yaml +4 -0
- package/codex/skills/cmd-plan-prd-master/SKILL.md +44 -0
- package/codex/skills/cmd-plan-prd-master/agents/openai.yaml +4 -0
- package/codex/skills/cmd-plan-req-lock/SKILL.md +44 -0
- package/codex/skills/cmd-plan-req-lock/agents/openai.yaml +4 -0
- package/codex/skills/cmd-review-code/SKILL.md +43 -0
- package/codex/skills/cmd-review-code/agents/openai.yaml +4 -0
- package/codex/skills/cmd-sec-dependency-audit/SKILL.md +43 -0
- package/codex/skills/cmd-sec-dependency-audit/agents/openai.yaml +4 -0
- package/codex/skills/cmd-sec-threat-model/SKILL.md +43 -0
- package/codex/skills/cmd-sec-threat-model/agents/openai.yaml +4 -0
- package/codex/skills/cmd-test-unit-integration/SKILL.md +43 -0
- package/codex/skills/cmd-test-unit-integration/agents/openai.yaml +4 -0
- package/common/settings/security-policy.json +221 -0
- package/package.json +1 -1
- package/scripts/generate-from-common.mjs +489 -4
- package/scripts/init.mjs +285 -36
- 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
|
|
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(
|
|
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
|
|
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) {
|