@dusky-bluehour/agent-service 0.6.5 → 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 +36 -25
- package/antigravity/README.md +14 -1
- package/antigravity/agents/agent-catalog.json +5 -5
- 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/antigravity/skills/change-safety-review/SKILL.md +40 -0
- package/antigravity/skills/code-review-and-improvement/SKILL.md +20 -0
- package/antigravity/skills/frontend-repetition-pack/SKILL.md +20 -0
- package/antigravity/skills/incident-response/SKILL.md +20 -0
- package/antigravity/skills/prd-to-production-pipeline/SKILL.md +21 -1
- package/antigravity/skills/release-and-operations/SKILL.md +20 -0
- package/antigravity/skills/security-hardening/SKILL.md +21 -1
- package/antigravity/skills/service-lifecycle-orchestration/SKILL.md +21 -1
- package/antigravity/workflows/definitions/WF-FRONTEND-REFACTOR.workflow.yaml +38 -0
- package/antigravity/workflows/definitions/WF-INCIDENT-RESPONSE.workflow.yaml +41 -0
- package/antigravity/workflows/definitions/WF-PRD-TO-PRODUCTION.workflow.yaml +76 -0
- package/antigravity/workflows/definitions/WF-SECURITY-HARDENING.workflow.yaml +40 -0
- package/antigravity/workflows/definitions/WF-SERVICE-E2E.workflow.yaml +67 -0
- package/antigravity/workflows/workflow-catalog.json +5 -5
- package/catalog/tool-catalog.ko.json +78 -17
- package/claude-code/README.md +31 -1
- package/claude-code/agent-teams/team-catalog.json +7 -7
- 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/claude-code/skills/change-safety-review/SKILL.md +40 -0
- package/claude-code/skills/code-review-and-improvement/SKILL.md +21 -1
- package/claude-code/skills/frontend-repetition-pack/SKILL.md +21 -1
- package/claude-code/skills/incident-response/SKILL.md +21 -1
- package/claude-code/skills/prd-to-production-pipeline/SKILL.md +21 -1
- package/claude-code/skills/release-and-operations/SKILL.md +21 -1
- package/claude-code/skills/security-hardening/SKILL.md +21 -1
- package/claude-code/skills/service-lifecycle-orchestration/SKILL.md +21 -1
- package/claude-code/workflows/workflow-catalog.json +8 -8
- package/codex/README.md +18 -3
- package/codex/automations/automation-recipes.toml +4 -4
- package/codex/instructions/AGENTS.permissions.generated.md +121 -0
- package/codex/instructions/AGENTS.template.md +24 -8
- package/codex/settings/runtime-policy.json +188 -0
- package/codex/skills/change-safety-review/SKILL.md +40 -0
- package/codex/skills/change-safety-review/agents/openai.yaml +4 -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/codex/skills/code-review-and-improvement/SKILL.md +21 -1
- package/codex/skills/frontend-repetition-pack/SKILL.md +20 -0
- package/codex/skills/incident-response/SKILL.md +21 -1
- package/codex/skills/prd-to-production-pipeline/SKILL.md +21 -1
- package/codex/skills/release-and-operations/SKILL.md +20 -0
- package/codex/skills/security-hardening/SKILL.md +21 -1
- package/codex/skills/service-lifecycle-orchestration/SKILL.md +21 -1
- package/codex/workflows/workflow-catalog.json +6 -6
- package/common/antigravity/agent-catalog.json +72 -0
- package/common/antigravity/artifact-catalog.json +184 -0
- package/common/claude/subagent-catalog.json +419 -0
- package/common/claude/team-catalog.json +69 -0
- package/common/commands/command-catalog.json +942 -0
- package/common/settings/security-policy.json +221 -0
- package/common/skills/skill-catalog.json +566 -0
- package/common/workflows/workflow-catalog.json +1550 -0
- package/package.json +6 -2
- package/scripts/generate-from-common.mjs +872 -0
- package/scripts/init.mjs +295 -36
- package/scripts/validate.mjs +451 -10
package/scripts/validate.mjs
CHANGED
|
@@ -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))) {
|
|
@@ -188,6 +200,214 @@ async function validateCatalog() {
|
|
|
188
200
|
}
|
|
189
201
|
}
|
|
190
202
|
|
|
203
|
+
async function validateCommonSources() {
|
|
204
|
+
const requiredJsonFiles = [
|
|
205
|
+
'common/commands/command-catalog.json',
|
|
206
|
+
'common/workflows/workflow-catalog.json',
|
|
207
|
+
'common/skills/skill-catalog.json',
|
|
208
|
+
'common/settings/security-policy.json',
|
|
209
|
+
'common/claude/subagent-catalog.json',
|
|
210
|
+
'common/claude/team-catalog.json',
|
|
211
|
+
'common/antigravity/agent-catalog.json',
|
|
212
|
+
'common/antigravity/artifact-catalog.json'
|
|
213
|
+
];
|
|
214
|
+
|
|
215
|
+
const commonData = {};
|
|
216
|
+
for (const relPath of requiredJsonFiles) {
|
|
217
|
+
const fullPath = path.join(rootDir, relPath);
|
|
218
|
+
if (!(await exists(fullPath))) {
|
|
219
|
+
fail(`[common] 파일 누락: ${relPath}`);
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
commonData[relPath] = await readJson(fullPath);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
fail(`[common] JSON 파싱 실패: ${relPath} (${error.message})`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const workflowCatalog = commonData['common/workflows/workflow-catalog.json'];
|
|
230
|
+
if (workflowCatalog) {
|
|
231
|
+
if (!Array.isArray(workflowCatalog.tools) || workflowCatalog.tools.length === 0) {
|
|
232
|
+
fail('[common/workflows] tools 배열 누락 또는 비어 있음');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const toolSet = new Set(Array.isArray(workflowCatalog.tools) ? workflowCatalog.tools : []);
|
|
236
|
+
for (const toolId of toolDirs) {
|
|
237
|
+
if (!toolSet.has(toolId)) {
|
|
238
|
+
fail(`[common/workflows] tools에 필수 tool 누락: ${toolId}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!workflowCatalog.workflow_policy || typeof workflowCatalog.workflow_policy !== 'object') {
|
|
243
|
+
fail('[common/workflows] workflow_policy 누락');
|
|
244
|
+
} else {
|
|
245
|
+
for (const toolId of toolSet) {
|
|
246
|
+
if (!(toolId in workflowCatalog.workflow_policy)) {
|
|
247
|
+
fail(`[common/workflows] workflow_policy 누락: ${toolId}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (!Array.isArray(workflowCatalog.workflows) || workflowCatalog.workflows.length === 0) {
|
|
253
|
+
fail('[common/workflows] workflows 배열 누락 또는 비어 있음');
|
|
254
|
+
} else {
|
|
255
|
+
const workflowIds = new Set();
|
|
256
|
+
const workflowMap = new Map();
|
|
257
|
+
for (const workflow of workflowCatalog.workflows) {
|
|
258
|
+
if (!workflow?.id) {
|
|
259
|
+
fail('[common/workflows] workflow id 누락');
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (workflowIds.has(workflow.id)) {
|
|
263
|
+
fail(`[common/workflows] 중복 workflow id: ${workflow.id}`);
|
|
264
|
+
}
|
|
265
|
+
workflowIds.add(workflow.id);
|
|
266
|
+
workflowMap.set(workflow.id, workflow);
|
|
267
|
+
|
|
268
|
+
if (!workflow.profiles || typeof workflow.profiles !== 'object') {
|
|
269
|
+
fail(`[common/workflows] profiles 누락: ${workflow.id}`);
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const profileTools = Object.keys(workflow.profiles);
|
|
274
|
+
if (profileTools.length === 0) {
|
|
275
|
+
fail(`[common/workflows] profile 비어 있음: ${workflow.id}`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
for (const toolId of profileTools) {
|
|
279
|
+
if (!toolSet.has(toolId)) {
|
|
280
|
+
fail(`[common/workflows] 알 수 없는 tool profile: ${workflow.id}/${toolId}`);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
const profile = workflow.profiles[toolId];
|
|
284
|
+
if (!profile || typeof profile !== 'object') {
|
|
285
|
+
fail(`[common/workflows] profile 형식 오류: ${workflow.id}/${toolId}`);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (!profile.name || !profile.summary || !profile.when_to_use) {
|
|
289
|
+
fail(`[common/workflows] profile 필수 필드 누락: ${workflow.id}/${toolId}`);
|
|
290
|
+
}
|
|
291
|
+
if (!Array.isArray(profile.stages) || profile.stages.length === 0) {
|
|
292
|
+
fail(`[common/workflows] profile stages 누락: ${workflow.id}/${toolId}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (!workflowCatalog.workflow_order || typeof workflowCatalog.workflow_order !== 'object') {
|
|
298
|
+
fail('[common/workflows] workflow_order 누락');
|
|
299
|
+
} else {
|
|
300
|
+
for (const toolId of toolSet) {
|
|
301
|
+
const order = workflowCatalog.workflow_order[toolId];
|
|
302
|
+
if (!Array.isArray(order)) {
|
|
303
|
+
fail(`[common/workflows] workflow_order 형식 오류: ${toolId}`);
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
const seen = new Set();
|
|
307
|
+
for (const workflowId of order) {
|
|
308
|
+
if (!workflowIds.has(workflowId)) {
|
|
309
|
+
fail(`[common/workflows] workflow_order가 없는 id 참조: ${toolId}/${workflowId}`);
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
const workflow = workflowMap.get(workflowId);
|
|
313
|
+
if (!workflow?.profiles?.[toolId]) {
|
|
314
|
+
fail(`[common/workflows] workflow_order와 profile 불일치: ${toolId}/${workflowId}`);
|
|
315
|
+
}
|
|
316
|
+
if (seen.has(workflowId)) {
|
|
317
|
+
fail(`[common/workflows] workflow_order 중복: ${toolId}/${workflowId}`);
|
|
318
|
+
}
|
|
319
|
+
seen.add(workflowId);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const skillCatalog = commonData['common/skills/skill-catalog.json'];
|
|
327
|
+
if (skillCatalog) {
|
|
328
|
+
if (!Array.isArray(skillCatalog.skills) || skillCatalog.skills.length === 0) {
|
|
329
|
+
fail('[common/skills] skills 배열 누락 또는 비어 있음');
|
|
330
|
+
} else {
|
|
331
|
+
const toolSet = new Set(Array.isArray(skillCatalog.tools) ? skillCatalog.tools : []);
|
|
332
|
+
for (const toolId of toolDirs) {
|
|
333
|
+
if (!toolSet.has(toolId)) {
|
|
334
|
+
fail(`[common/skills] tools 누락: ${toolId}`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const skillIds = new Set();
|
|
339
|
+
for (const skill of skillCatalog.skills) {
|
|
340
|
+
if (!skill?.id) {
|
|
341
|
+
fail('[common/skills] skill id 누락');
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
if (skillIds.has(skill.id)) {
|
|
345
|
+
fail(`[common/skills] 중복 skill id: ${skill.id}`);
|
|
346
|
+
}
|
|
347
|
+
skillIds.add(skill.id);
|
|
348
|
+
|
|
349
|
+
for (const toolId of toolSet) {
|
|
350
|
+
if (!skill.names?.[toolId] || !skill.descriptions?.[toolId]) {
|
|
351
|
+
fail(`[common/skills] 이름/설명 누락: ${skill.id}/${toolId}`);
|
|
352
|
+
}
|
|
353
|
+
if (!Array.isArray(skill.procedures?.[toolId]) || skill.procedures[toolId].length === 0) {
|
|
354
|
+
fail(`[common/skills] 실행 절차 누락: ${skill.id}/${toolId}`);
|
|
355
|
+
}
|
|
356
|
+
if (
|
|
357
|
+
!Array.isArray(skill.quality_rules?.[toolId]) ||
|
|
358
|
+
skill.quality_rules[toolId].length === 0
|
|
359
|
+
) {
|
|
360
|
+
fail(`[common/skills] 품질 규칙 누락: ${skill.id}/${toolId}`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (!Array.isArray(skill.input_checklist) || skill.input_checklist.length === 0) {
|
|
365
|
+
fail(`[common/skills] 시작 전 체크리스트 누락: ${skill.id}`);
|
|
366
|
+
}
|
|
367
|
+
if (!Array.isArray(skill.report_format) || skill.report_format.length === 0) {
|
|
368
|
+
fail(`[common/skills] 결과 보고 형식 누락: ${skill.id}`);
|
|
369
|
+
}
|
|
370
|
+
if (!Array.isArray(skill.stop_conditions) || skill.stop_conditions.length === 0) {
|
|
371
|
+
fail(`[common/skills] 중단 조건 누락: ${skill.id}`);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (!skill.codex_openai) {
|
|
375
|
+
fail(`[common/skills] codex_openai 누락: ${skill.id}`);
|
|
376
|
+
} else {
|
|
377
|
+
const ui = skill.codex_openai;
|
|
378
|
+
if (!ui.display_name || !ui.short_description || !ui.default_prompt) {
|
|
379
|
+
fail(`[common/skills] codex_openai 필수 필드 누락: ${skill.id}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const securityPolicy = commonData['common/settings/security-policy.json'];
|
|
387
|
+
if (securityPolicy) {
|
|
388
|
+
if (!securityPolicy.policy_id || !securityPolicy.shared_permissions) {
|
|
389
|
+
fail('[common/settings] policy_id/shared_permissions 누락');
|
|
390
|
+
}
|
|
391
|
+
const shared = securityPolicy.shared_permissions ?? {};
|
|
392
|
+
for (const field of [
|
|
393
|
+
'allow_bash',
|
|
394
|
+
'ask_bash',
|
|
395
|
+
'deny_bash',
|
|
396
|
+
'deny_read',
|
|
397
|
+
'deny_edit'
|
|
398
|
+
]) {
|
|
399
|
+
if (!Array.isArray(shared[field])) {
|
|
400
|
+
fail(`[common/settings] 배열 누락: ${field}`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const claude = securityPolicy.claude_code ?? {};
|
|
405
|
+
if (!claude.default_mode || !claude.disable_bypass_permissions_mode) {
|
|
406
|
+
fail('[common/settings] claude_code default_mode/disable_bypass_permissions_mode 누락');
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
191
411
|
async function validatePackageJson() {
|
|
192
412
|
const packagePath = path.join(rootDir, 'package.json');
|
|
193
413
|
if (!(await exists(packagePath))) {
|
|
@@ -203,7 +423,14 @@ async function validatePackageJson() {
|
|
|
203
423
|
return;
|
|
204
424
|
}
|
|
205
425
|
|
|
206
|
-
const requiredScripts = [
|
|
426
|
+
const requiredScripts = [
|
|
427
|
+
'generate',
|
|
428
|
+
'generate:check',
|
|
429
|
+
'validate',
|
|
430
|
+
'pack:dry-run',
|
|
431
|
+
'prepublish:check',
|
|
432
|
+
'prepublishOnly'
|
|
433
|
+
];
|
|
207
434
|
for (const scriptName of requiredScripts) {
|
|
208
435
|
if (!pkg.scripts || !(scriptName in pkg.scripts)) {
|
|
209
436
|
fail(`[package] scripts 누락: ${scriptName}`);
|
|
@@ -215,11 +442,13 @@ async function validatePackageJson() {
|
|
|
215
442
|
}
|
|
216
443
|
|
|
217
444
|
const requiredFiles = [
|
|
445
|
+
'common',
|
|
218
446
|
'claude-code',
|
|
219
447
|
'antigravity',
|
|
220
448
|
'codex',
|
|
221
449
|
'catalog/tool-catalog.ko.json',
|
|
222
450
|
'scripts/init.mjs',
|
|
451
|
+
'scripts/generate-from-common.mjs',
|
|
223
452
|
'scripts/validate.mjs'
|
|
224
453
|
];
|
|
225
454
|
for (const fileEntry of requiredFiles) {
|
|
@@ -282,10 +511,29 @@ async function validateSkillDirectory(toolName) {
|
|
|
282
511
|
fail(`[${toolName}] frontmatter name/description 누락: ${skillFile}`);
|
|
283
512
|
}
|
|
284
513
|
|
|
514
|
+
for (const heading of [
|
|
515
|
+
'# 시작 전 체크리스트',
|
|
516
|
+
'# 실행 절차',
|
|
517
|
+
'# 결과 보고 형식',
|
|
518
|
+
'# 중단 조건',
|
|
519
|
+
'# 품질 규칙'
|
|
520
|
+
]) {
|
|
521
|
+
if (!content.includes(heading)) {
|
|
522
|
+
fail(`[${toolName}] SKILL 섹션 누락: ${skillName}/${heading}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
285
526
|
if (toolName === 'codex') {
|
|
286
527
|
const openaiYaml = path.join(skillsPath, skillName, 'agents', 'openai.yaml');
|
|
287
528
|
if (!(await exists(openaiYaml))) {
|
|
288
529
|
fail(`[codex] openai.yaml 누락: ${skillName}`);
|
|
530
|
+
} else {
|
|
531
|
+
const raw = await fs.readFile(openaiYaml, 'utf8');
|
|
532
|
+
for (const key of ['display_name', 'short_description', 'default_prompt']) {
|
|
533
|
+
if (!new RegExp(`\\b${key}:\\s+\".+\"`).test(raw)) {
|
|
534
|
+
fail(`[codex] openai.yaml 필수 필드 누락: ${skillName}/${key}`);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
289
537
|
}
|
|
290
538
|
}
|
|
291
539
|
}
|
|
@@ -295,7 +543,7 @@ async function validateCommandCatalog(toolName) {
|
|
|
295
543
|
const filePath = path.join(rootDir, toolName, 'commands', 'command-catalog.json');
|
|
296
544
|
if (!(await exists(filePath))) {
|
|
297
545
|
fail(`[${toolName}] command-catalog.json 누락`);
|
|
298
|
-
return { commandIds: new Set() };
|
|
546
|
+
return { commandIds: new Set(), commandFileBases: new Set() };
|
|
299
547
|
}
|
|
300
548
|
|
|
301
549
|
let data;
|
|
@@ -303,12 +551,12 @@ async function validateCommandCatalog(toolName) {
|
|
|
303
551
|
data = await readJson(filePath);
|
|
304
552
|
} catch (error) {
|
|
305
553
|
fail(`[${toolName}] command-catalog.json 파싱 실패: ${error.message}`);
|
|
306
|
-
return { commandIds: new Set() };
|
|
554
|
+
return { commandIds: new Set(), commandFileBases: new Set() };
|
|
307
555
|
}
|
|
308
556
|
|
|
309
557
|
if (!Array.isArray(data.commands) || data.commands.length === 0) {
|
|
310
558
|
fail(`[${toolName}] commands 배열 누락 또는 비어 있음`);
|
|
311
|
-
return { commandIds: new Set() };
|
|
559
|
+
return { commandIds: new Set(), commandFileBases: new Set() };
|
|
312
560
|
}
|
|
313
561
|
|
|
314
562
|
const requiredFields = [
|
|
@@ -325,6 +573,7 @@ async function validateCommandCatalog(toolName) {
|
|
|
325
573
|
];
|
|
326
574
|
|
|
327
575
|
const commandIds = new Set();
|
|
576
|
+
const commandFileBases = new Set();
|
|
328
577
|
for (const cmd of data.commands) {
|
|
329
578
|
for (const field of requiredFields) {
|
|
330
579
|
if (!(field in cmd)) {
|
|
@@ -341,6 +590,11 @@ async function validateCommandCatalog(toolName) {
|
|
|
341
590
|
fail(`[${toolName}] 중복 명령 ID: ${cmd.id}`);
|
|
342
591
|
}
|
|
343
592
|
commandIds.add(cmd.id);
|
|
593
|
+
try {
|
|
594
|
+
commandFileBases.add(normalizeCommandBasename(cmd.id));
|
|
595
|
+
} catch (error) {
|
|
596
|
+
fail(`[${toolName}] 명령 ID 형식 오류: ${cmd.id} (${error.message})`);
|
|
597
|
+
}
|
|
344
598
|
}
|
|
345
599
|
|
|
346
600
|
const repeatedIds = [
|
|
@@ -355,7 +609,7 @@ async function validateCommandCatalog(toolName) {
|
|
|
355
609
|
}
|
|
356
610
|
}
|
|
357
611
|
|
|
358
|
-
return { commandIds };
|
|
612
|
+
return { commandIds, commandFileBases };
|
|
359
613
|
}
|
|
360
614
|
|
|
361
615
|
async function validateWorkflowCatalog(toolName, commandIds) {
|
|
@@ -409,7 +663,7 @@ async function validateWorkflowCatalog(toolName, commandIds) {
|
|
|
409
663
|
}
|
|
410
664
|
}
|
|
411
665
|
|
|
412
|
-
async function validateClaudeExtras() {
|
|
666
|
+
async function validateClaudeExtras(commandFileBases) {
|
|
413
667
|
const subagentsPath = path.join(rootDir, 'claude-code', 'subagents');
|
|
414
668
|
if (!(await exists(subagentsPath))) {
|
|
415
669
|
fail('[claude-code] subagents 디렉터리 누락');
|
|
@@ -434,9 +688,37 @@ async function validateClaudeExtras() {
|
|
|
434
688
|
if (!(await exists(teamCatalog))) {
|
|
435
689
|
fail('[claude-code] team-catalog.json 누락');
|
|
436
690
|
}
|
|
691
|
+
|
|
692
|
+
const commandDir = path.join(rootDir, 'claude-code', 'commands', 'native');
|
|
693
|
+
if (!(await exists(commandDir))) {
|
|
694
|
+
fail('[claude-code] commands/native 디렉터리 누락');
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const commandFiles = new Set((await fs.readdir(commandDir)).filter((file) => file.endsWith('.md')));
|
|
699
|
+
for (const base of commandFileBases) {
|
|
700
|
+
const expected = `${base}.md`;
|
|
701
|
+
if (!commandFiles.has(expected)) {
|
|
702
|
+
fail(`[claude-code] native command 누락: commands/native/${expected}`);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
437
705
|
}
|
|
438
706
|
|
|
439
|
-
async function
|
|
707
|
+
async function validateCodexExtras(commandFileBases) {
|
|
708
|
+
const codexSkillDir = path.join(rootDir, 'codex', 'skills');
|
|
709
|
+
for (const base of commandFileBases) {
|
|
710
|
+
const skillFile = path.join(codexSkillDir, base, 'SKILL.md');
|
|
711
|
+
const openAiYaml = path.join(codexSkillDir, base, 'agents', 'openai.yaml');
|
|
712
|
+
if (!(await exists(skillFile))) {
|
|
713
|
+
fail(`[codex] 명령 스킬 누락: skills/${base}/SKILL.md`);
|
|
714
|
+
}
|
|
715
|
+
if (!(await exists(openAiYaml))) {
|
|
716
|
+
fail(`[codex] 명령 스킬 openai.yaml 누락: skills/${base}/agents/openai.yaml`);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
async function validateAntigravityExtras(commandFileBases) {
|
|
440
722
|
const agentCatalog = path.join(rootDir, 'antigravity', 'agents', 'agent-catalog.json');
|
|
441
723
|
const artifactCatalog = path.join(rootDir, 'antigravity', 'artifacts', 'artifact-catalog.json');
|
|
442
724
|
|
|
@@ -452,6 +734,52 @@ async function validateAntigravityExtras() {
|
|
|
452
734
|
fail(`[antigravity] JSON 파싱 실패: ${path.relative(rootDir, f)} (${error.message})`);
|
|
453
735
|
}
|
|
454
736
|
}
|
|
737
|
+
|
|
738
|
+
const workflowCatalogPath = path.join(rootDir, 'antigravity', 'workflows', 'workflow-catalog.json');
|
|
739
|
+
const workflowDefsDir = path.join(rootDir, 'antigravity', 'workflows', 'definitions');
|
|
740
|
+
|
|
741
|
+
if (!(await exists(workflowDefsDir))) {
|
|
742
|
+
fail('[antigravity] workflow definitions 디렉터리 누락');
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
let workflowCatalog;
|
|
747
|
+
try {
|
|
748
|
+
workflowCatalog = await readJson(workflowCatalogPath);
|
|
749
|
+
} catch (error) {
|
|
750
|
+
fail(`[antigravity] workflow-catalog.json 파싱 실패: ${error.message}`);
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const workflowIds = new Set(
|
|
755
|
+
Array.isArray(workflowCatalog.workflows) ? workflowCatalog.workflows.map((wf) => wf.id) : []
|
|
756
|
+
);
|
|
757
|
+
const definitionFiles = (await fs.readdir(workflowDefsDir))
|
|
758
|
+
.filter((file) => file.endsWith('.workflow.yaml'))
|
|
759
|
+
.sort();
|
|
760
|
+
|
|
761
|
+
for (const workflowId of workflowIds) {
|
|
762
|
+
const expected = `${workflowId}.workflow.yaml`;
|
|
763
|
+
if (!definitionFiles.includes(expected)) {
|
|
764
|
+
fail(`[antigravity] workflow definition 누락: ${expected}`);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
const commandDefinitionsDir = path.join(rootDir, 'antigravity', 'commands', 'definitions');
|
|
769
|
+
if (!(await exists(commandDefinitionsDir))) {
|
|
770
|
+
fail('[antigravity] commands/definitions 디렉터리 누락');
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
const commandDefinitionFiles = new Set(
|
|
775
|
+
(await fs.readdir(commandDefinitionsDir)).filter((file) => file.endsWith('.md'))
|
|
776
|
+
);
|
|
777
|
+
for (const base of commandFileBases) {
|
|
778
|
+
const expected = `${base}.md`;
|
|
779
|
+
if (!commandDefinitionFiles.has(expected)) {
|
|
780
|
+
fail(`[antigravity] command definition 누락: commands/definitions/${expected}`);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
455
783
|
}
|
|
456
784
|
|
|
457
785
|
async function validateReadmes() {
|
|
@@ -463,6 +791,89 @@ async function validateReadmes() {
|
|
|
463
791
|
}
|
|
464
792
|
}
|
|
465
793
|
|
|
794
|
+
async function validateSettingsOutputs() {
|
|
795
|
+
const settingsFiles = [
|
|
796
|
+
'claude-code/settings/settings.json',
|
|
797
|
+
'claude-code/settings/settings.local.json',
|
|
798
|
+
'antigravity/settings/editor-policy.json',
|
|
799
|
+
'codex/settings/runtime-policy.json'
|
|
800
|
+
];
|
|
801
|
+
|
|
802
|
+
for (const relPath of settingsFiles) {
|
|
803
|
+
const fullPath = path.join(rootDir, relPath);
|
|
804
|
+
if (!(await exists(fullPath))) {
|
|
805
|
+
fail(`[settings] 파일 누락: ${relPath}`);
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
try {
|
|
809
|
+
await readJson(fullPath);
|
|
810
|
+
} catch (error) {
|
|
811
|
+
fail(`[settings] JSON 파싱 실패: ${relPath} (${error.message})`);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
const claudeProjectPath = path.join(
|
|
816
|
+
rootDir,
|
|
817
|
+
'claude-code',
|
|
818
|
+
'settings',
|
|
819
|
+
'settings.json'
|
|
820
|
+
);
|
|
821
|
+
if (await exists(claudeProjectPath)) {
|
|
822
|
+
try {
|
|
823
|
+
const claude = await readJson(claudeProjectPath);
|
|
824
|
+
const permissions = claude.permissions ?? {};
|
|
825
|
+
const validModes = new Set([
|
|
826
|
+
'default',
|
|
827
|
+
'acceptEdits',
|
|
828
|
+
'plan',
|
|
829
|
+
'dontAsk',
|
|
830
|
+
'bypassPermissions'
|
|
831
|
+
]);
|
|
832
|
+
if (!validModes.has(permissions.defaultMode)) {
|
|
833
|
+
fail(`[settings] Claude defaultMode 값 오류: ${permissions.defaultMode}`);
|
|
834
|
+
}
|
|
835
|
+
for (const key of ['allow', 'ask', 'deny']) {
|
|
836
|
+
if (!Array.isArray(permissions[key])) {
|
|
837
|
+
fail(`[settings] Claude permissions.${key} 누락`);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
} catch (error) {
|
|
841
|
+
fail(`[settings] Claude 설정 검증 실패: ${error.message}`);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const codexAgentsPermissionPath = path.join(
|
|
846
|
+
rootDir,
|
|
847
|
+
'codex',
|
|
848
|
+
'instructions',
|
|
849
|
+
'AGENTS.permissions.generated.md'
|
|
850
|
+
);
|
|
851
|
+
if (!(await exists(codexAgentsPermissionPath))) {
|
|
852
|
+
fail('[settings] Codex AGENTS.permissions.generated.md 누락');
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
async function validateProjectRuleTemplates() {
|
|
857
|
+
const requiredFiles = [
|
|
858
|
+
'claude-code/instructions/CLAUDE.template.md',
|
|
859
|
+
'codex/instructions/AGENTS.template.md',
|
|
860
|
+
'antigravity/instructions/WORKSPACE-RULES.template.md'
|
|
861
|
+
];
|
|
862
|
+
|
|
863
|
+
for (const relPath of requiredFiles) {
|
|
864
|
+
const fullPath = path.join(rootDir, relPath);
|
|
865
|
+
if (!(await exists(fullPath))) {
|
|
866
|
+
fail(`[project-rules] 템플릿 누락: ${relPath}`);
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
871
|
+
if (!content.trim()) {
|
|
872
|
+
fail(`[project-rules] 템플릿 비어 있음: ${relPath}`);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
466
877
|
async function runCliSmokeTests() {
|
|
467
878
|
const nodeBin = process.execPath;
|
|
468
879
|
const cliPath = path.join(rootDir, 'scripts', 'init.mjs');
|
|
@@ -561,6 +972,30 @@ async function runCliSmokeTests() {
|
|
|
561
972
|
fail(`[cli] install --install-root dry-run 실행 실패: ${error.message}`);
|
|
562
973
|
}
|
|
563
974
|
|
|
975
|
+
try {
|
|
976
|
+
await execFileAsync(
|
|
977
|
+
nodeBin,
|
|
978
|
+
[
|
|
979
|
+
cliPath,
|
|
980
|
+
'install',
|
|
981
|
+
'--tool',
|
|
982
|
+
'antigravity',
|
|
983
|
+
'--components',
|
|
984
|
+
'skills',
|
|
985
|
+
'--project-rules',
|
|
986
|
+
'if-instructions',
|
|
987
|
+
'--target',
|
|
988
|
+
'/tmp/tri-agent-manager-validate',
|
|
989
|
+
'--dry-run',
|
|
990
|
+
'--yes',
|
|
991
|
+
'--non-interactive'
|
|
992
|
+
],
|
|
993
|
+
{ cwd: rootDir }
|
|
994
|
+
);
|
|
995
|
+
} catch (error) {
|
|
996
|
+
fail(`[cli] install --project-rules dry-run 실행 실패: ${error.message}`);
|
|
997
|
+
}
|
|
998
|
+
|
|
564
999
|
try {
|
|
565
1000
|
await execFileAsync(
|
|
566
1001
|
nodeBin,
|
|
@@ -626,17 +1061,23 @@ async function runCliSmokeTests() {
|
|
|
626
1061
|
|
|
627
1062
|
async function main() {
|
|
628
1063
|
await validatePackageJson();
|
|
1064
|
+
await validateCommonSources();
|
|
629
1065
|
await validateCatalog();
|
|
630
1066
|
await validateReadmes();
|
|
1067
|
+
await validateSettingsOutputs();
|
|
1068
|
+
await validateProjectRuleTemplates();
|
|
631
1069
|
|
|
1070
|
+
const commandFileBaseByTool = {};
|
|
632
1071
|
for (const toolName of toolDirs) {
|
|
633
1072
|
await validateSkillDirectory(toolName);
|
|
634
|
-
const { commandIds } = await validateCommandCatalog(toolName);
|
|
1073
|
+
const { commandIds, commandFileBases } = await validateCommandCatalog(toolName);
|
|
1074
|
+
commandFileBaseByTool[toolName] = commandFileBases;
|
|
635
1075
|
await validateWorkflowCatalog(toolName, commandIds);
|
|
636
1076
|
}
|
|
637
1077
|
|
|
638
|
-
await validateClaudeExtras();
|
|
639
|
-
await
|
|
1078
|
+
await validateClaudeExtras(commandFileBaseByTool['claude-code'] ?? new Set());
|
|
1079
|
+
await validateCodexExtras(commandFileBaseByTool.codex ?? new Set());
|
|
1080
|
+
await validateAntigravityExtras(commandFileBaseByTool.antigravity ?? new Set());
|
|
640
1081
|
await runCliSmokeTests();
|
|
641
1082
|
|
|
642
1083
|
if (errors.length > 0) {
|