@dusky-bluehour/agent-service 0.6.5 → 0.6.6
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 +19 -0
- package/antigravity/README.md +7 -1
- package/antigravity/agents/agent-catalog.json +5 -5
- 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 +1 -1
- package/claude-code/README.md +4 -1
- package/claude-code/agent-teams/team-catalog.json +7 -7
- 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 +5 -2
- package/codex/automations/automation-recipes.toml +4 -4
- package/codex/instructions/AGENTS.template.md +6 -5
- package/codex/skills/change-safety-review/SKILL.md +40 -0
- package/codex/skills/change-safety-review/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/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 +387 -0
- package/scripts/init.mjs +10 -0
- package/scripts/validate.mjs +243 -1
package/scripts/validate.mjs
CHANGED
|
@@ -188,6 +188,189 @@ async function validateCatalog() {
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
async function validateCommonSources() {
|
|
192
|
+
const requiredJsonFiles = [
|
|
193
|
+
'common/commands/command-catalog.json',
|
|
194
|
+
'common/workflows/workflow-catalog.json',
|
|
195
|
+
'common/skills/skill-catalog.json',
|
|
196
|
+
'common/claude/subagent-catalog.json',
|
|
197
|
+
'common/claude/team-catalog.json',
|
|
198
|
+
'common/antigravity/agent-catalog.json',
|
|
199
|
+
'common/antigravity/artifact-catalog.json'
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
const commonData = {};
|
|
203
|
+
for (const relPath of requiredJsonFiles) {
|
|
204
|
+
const fullPath = path.join(rootDir, relPath);
|
|
205
|
+
if (!(await exists(fullPath))) {
|
|
206
|
+
fail(`[common] 파일 누락: ${relPath}`);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
commonData[relPath] = await readJson(fullPath);
|
|
211
|
+
} catch (error) {
|
|
212
|
+
fail(`[common] JSON 파싱 실패: ${relPath} (${error.message})`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const workflowCatalog = commonData['common/workflows/workflow-catalog.json'];
|
|
217
|
+
if (workflowCatalog) {
|
|
218
|
+
if (!Array.isArray(workflowCatalog.tools) || workflowCatalog.tools.length === 0) {
|
|
219
|
+
fail('[common/workflows] tools 배열 누락 또는 비어 있음');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const toolSet = new Set(Array.isArray(workflowCatalog.tools) ? workflowCatalog.tools : []);
|
|
223
|
+
for (const toolId of toolDirs) {
|
|
224
|
+
if (!toolSet.has(toolId)) {
|
|
225
|
+
fail(`[common/workflows] tools에 필수 tool 누락: ${toolId}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!workflowCatalog.workflow_policy || typeof workflowCatalog.workflow_policy !== 'object') {
|
|
230
|
+
fail('[common/workflows] workflow_policy 누락');
|
|
231
|
+
} else {
|
|
232
|
+
for (const toolId of toolSet) {
|
|
233
|
+
if (!(toolId in workflowCatalog.workflow_policy)) {
|
|
234
|
+
fail(`[common/workflows] workflow_policy 누락: ${toolId}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!Array.isArray(workflowCatalog.workflows) || workflowCatalog.workflows.length === 0) {
|
|
240
|
+
fail('[common/workflows] workflows 배열 누락 또는 비어 있음');
|
|
241
|
+
} else {
|
|
242
|
+
const workflowIds = new Set();
|
|
243
|
+
const workflowMap = new Map();
|
|
244
|
+
for (const workflow of workflowCatalog.workflows) {
|
|
245
|
+
if (!workflow?.id) {
|
|
246
|
+
fail('[common/workflows] workflow id 누락');
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (workflowIds.has(workflow.id)) {
|
|
250
|
+
fail(`[common/workflows] 중복 workflow id: ${workflow.id}`);
|
|
251
|
+
}
|
|
252
|
+
workflowIds.add(workflow.id);
|
|
253
|
+
workflowMap.set(workflow.id, workflow);
|
|
254
|
+
|
|
255
|
+
if (!workflow.profiles || typeof workflow.profiles !== 'object') {
|
|
256
|
+
fail(`[common/workflows] profiles 누락: ${workflow.id}`);
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const profileTools = Object.keys(workflow.profiles);
|
|
261
|
+
if (profileTools.length === 0) {
|
|
262
|
+
fail(`[common/workflows] profile 비어 있음: ${workflow.id}`);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
for (const toolId of profileTools) {
|
|
266
|
+
if (!toolSet.has(toolId)) {
|
|
267
|
+
fail(`[common/workflows] 알 수 없는 tool profile: ${workflow.id}/${toolId}`);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const profile = workflow.profiles[toolId];
|
|
271
|
+
if (!profile || typeof profile !== 'object') {
|
|
272
|
+
fail(`[common/workflows] profile 형식 오류: ${workflow.id}/${toolId}`);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (!profile.name || !profile.summary || !profile.when_to_use) {
|
|
276
|
+
fail(`[common/workflows] profile 필수 필드 누락: ${workflow.id}/${toolId}`);
|
|
277
|
+
}
|
|
278
|
+
if (!Array.isArray(profile.stages) || profile.stages.length === 0) {
|
|
279
|
+
fail(`[common/workflows] profile stages 누락: ${workflow.id}/${toolId}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!workflowCatalog.workflow_order || typeof workflowCatalog.workflow_order !== 'object') {
|
|
285
|
+
fail('[common/workflows] workflow_order 누락');
|
|
286
|
+
} else {
|
|
287
|
+
for (const toolId of toolSet) {
|
|
288
|
+
const order = workflowCatalog.workflow_order[toolId];
|
|
289
|
+
if (!Array.isArray(order)) {
|
|
290
|
+
fail(`[common/workflows] workflow_order 형식 오류: ${toolId}`);
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
const seen = new Set();
|
|
294
|
+
for (const workflowId of order) {
|
|
295
|
+
if (!workflowIds.has(workflowId)) {
|
|
296
|
+
fail(`[common/workflows] workflow_order가 없는 id 참조: ${toolId}/${workflowId}`);
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
const workflow = workflowMap.get(workflowId);
|
|
300
|
+
if (!workflow?.profiles?.[toolId]) {
|
|
301
|
+
fail(`[common/workflows] workflow_order와 profile 불일치: ${toolId}/${workflowId}`);
|
|
302
|
+
}
|
|
303
|
+
if (seen.has(workflowId)) {
|
|
304
|
+
fail(`[common/workflows] workflow_order 중복: ${toolId}/${workflowId}`);
|
|
305
|
+
}
|
|
306
|
+
seen.add(workflowId);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const skillCatalog = commonData['common/skills/skill-catalog.json'];
|
|
314
|
+
if (skillCatalog) {
|
|
315
|
+
if (!Array.isArray(skillCatalog.skills) || skillCatalog.skills.length === 0) {
|
|
316
|
+
fail('[common/skills] skills 배열 누락 또는 비어 있음');
|
|
317
|
+
} else {
|
|
318
|
+
const toolSet = new Set(Array.isArray(skillCatalog.tools) ? skillCatalog.tools : []);
|
|
319
|
+
for (const toolId of toolDirs) {
|
|
320
|
+
if (!toolSet.has(toolId)) {
|
|
321
|
+
fail(`[common/skills] tools 누락: ${toolId}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const skillIds = new Set();
|
|
326
|
+
for (const skill of skillCatalog.skills) {
|
|
327
|
+
if (!skill?.id) {
|
|
328
|
+
fail('[common/skills] skill id 누락');
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (skillIds.has(skill.id)) {
|
|
332
|
+
fail(`[common/skills] 중복 skill id: ${skill.id}`);
|
|
333
|
+
}
|
|
334
|
+
skillIds.add(skill.id);
|
|
335
|
+
|
|
336
|
+
for (const toolId of toolSet) {
|
|
337
|
+
if (!skill.names?.[toolId] || !skill.descriptions?.[toolId]) {
|
|
338
|
+
fail(`[common/skills] 이름/설명 누락: ${skill.id}/${toolId}`);
|
|
339
|
+
}
|
|
340
|
+
if (!Array.isArray(skill.procedures?.[toolId]) || skill.procedures[toolId].length === 0) {
|
|
341
|
+
fail(`[common/skills] 실행 절차 누락: ${skill.id}/${toolId}`);
|
|
342
|
+
}
|
|
343
|
+
if (
|
|
344
|
+
!Array.isArray(skill.quality_rules?.[toolId]) ||
|
|
345
|
+
skill.quality_rules[toolId].length === 0
|
|
346
|
+
) {
|
|
347
|
+
fail(`[common/skills] 품질 규칙 누락: ${skill.id}/${toolId}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (!Array.isArray(skill.input_checklist) || skill.input_checklist.length === 0) {
|
|
352
|
+
fail(`[common/skills] 시작 전 체크리스트 누락: ${skill.id}`);
|
|
353
|
+
}
|
|
354
|
+
if (!Array.isArray(skill.report_format) || skill.report_format.length === 0) {
|
|
355
|
+
fail(`[common/skills] 결과 보고 형식 누락: ${skill.id}`);
|
|
356
|
+
}
|
|
357
|
+
if (!Array.isArray(skill.stop_conditions) || skill.stop_conditions.length === 0) {
|
|
358
|
+
fail(`[common/skills] 중단 조건 누락: ${skill.id}`);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (!skill.codex_openai) {
|
|
362
|
+
fail(`[common/skills] codex_openai 누락: ${skill.id}`);
|
|
363
|
+
} else {
|
|
364
|
+
const ui = skill.codex_openai;
|
|
365
|
+
if (!ui.display_name || !ui.short_description || !ui.default_prompt) {
|
|
366
|
+
fail(`[common/skills] codex_openai 필수 필드 누락: ${skill.id}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
191
374
|
async function validatePackageJson() {
|
|
192
375
|
const packagePath = path.join(rootDir, 'package.json');
|
|
193
376
|
if (!(await exists(packagePath))) {
|
|
@@ -203,7 +386,14 @@ async function validatePackageJson() {
|
|
|
203
386
|
return;
|
|
204
387
|
}
|
|
205
388
|
|
|
206
|
-
const requiredScripts = [
|
|
389
|
+
const requiredScripts = [
|
|
390
|
+
'generate',
|
|
391
|
+
'generate:check',
|
|
392
|
+
'validate',
|
|
393
|
+
'pack:dry-run',
|
|
394
|
+
'prepublish:check',
|
|
395
|
+
'prepublishOnly'
|
|
396
|
+
];
|
|
207
397
|
for (const scriptName of requiredScripts) {
|
|
208
398
|
if (!pkg.scripts || !(scriptName in pkg.scripts)) {
|
|
209
399
|
fail(`[package] scripts 누락: ${scriptName}`);
|
|
@@ -215,11 +405,13 @@ async function validatePackageJson() {
|
|
|
215
405
|
}
|
|
216
406
|
|
|
217
407
|
const requiredFiles = [
|
|
408
|
+
'common',
|
|
218
409
|
'claude-code',
|
|
219
410
|
'antigravity',
|
|
220
411
|
'codex',
|
|
221
412
|
'catalog/tool-catalog.ko.json',
|
|
222
413
|
'scripts/init.mjs',
|
|
414
|
+
'scripts/generate-from-common.mjs',
|
|
223
415
|
'scripts/validate.mjs'
|
|
224
416
|
];
|
|
225
417
|
for (const fileEntry of requiredFiles) {
|
|
@@ -282,10 +474,29 @@ async function validateSkillDirectory(toolName) {
|
|
|
282
474
|
fail(`[${toolName}] frontmatter name/description 누락: ${skillFile}`);
|
|
283
475
|
}
|
|
284
476
|
|
|
477
|
+
for (const heading of [
|
|
478
|
+
'# 시작 전 체크리스트',
|
|
479
|
+
'# 실행 절차',
|
|
480
|
+
'# 결과 보고 형식',
|
|
481
|
+
'# 중단 조건',
|
|
482
|
+
'# 품질 규칙'
|
|
483
|
+
]) {
|
|
484
|
+
if (!content.includes(heading)) {
|
|
485
|
+
fail(`[${toolName}] SKILL 섹션 누락: ${skillName}/${heading}`);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
285
489
|
if (toolName === 'codex') {
|
|
286
490
|
const openaiYaml = path.join(skillsPath, skillName, 'agents', 'openai.yaml');
|
|
287
491
|
if (!(await exists(openaiYaml))) {
|
|
288
492
|
fail(`[codex] openai.yaml 누락: ${skillName}`);
|
|
493
|
+
} else {
|
|
494
|
+
const raw = await fs.readFile(openaiYaml, 'utf8');
|
|
495
|
+
for (const key of ['display_name', 'short_description', 'default_prompt']) {
|
|
496
|
+
if (!new RegExp(`\\b${key}:\\s+\".+\"`).test(raw)) {
|
|
497
|
+
fail(`[codex] openai.yaml 필수 필드 누락: ${skillName}/${key}`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
289
500
|
}
|
|
290
501
|
}
|
|
291
502
|
}
|
|
@@ -452,6 +663,36 @@ async function validateAntigravityExtras() {
|
|
|
452
663
|
fail(`[antigravity] JSON 파싱 실패: ${path.relative(rootDir, f)} (${error.message})`);
|
|
453
664
|
}
|
|
454
665
|
}
|
|
666
|
+
|
|
667
|
+
const workflowCatalogPath = path.join(rootDir, 'antigravity', 'workflows', 'workflow-catalog.json');
|
|
668
|
+
const workflowDefsDir = path.join(rootDir, 'antigravity', 'workflows', 'definitions');
|
|
669
|
+
|
|
670
|
+
if (!(await exists(workflowDefsDir))) {
|
|
671
|
+
fail('[antigravity] workflow definitions 디렉터리 누락');
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
let workflowCatalog;
|
|
676
|
+
try {
|
|
677
|
+
workflowCatalog = await readJson(workflowCatalogPath);
|
|
678
|
+
} catch (error) {
|
|
679
|
+
fail(`[antigravity] workflow-catalog.json 파싱 실패: ${error.message}`);
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const workflowIds = new Set(
|
|
684
|
+
Array.isArray(workflowCatalog.workflows) ? workflowCatalog.workflows.map((wf) => wf.id) : []
|
|
685
|
+
);
|
|
686
|
+
const definitionFiles = (await fs.readdir(workflowDefsDir))
|
|
687
|
+
.filter((file) => file.endsWith('.workflow.yaml'))
|
|
688
|
+
.sort();
|
|
689
|
+
|
|
690
|
+
for (const workflowId of workflowIds) {
|
|
691
|
+
const expected = `${workflowId}.workflow.yaml`;
|
|
692
|
+
if (!definitionFiles.includes(expected)) {
|
|
693
|
+
fail(`[antigravity] workflow definition 누락: ${expected}`);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
455
696
|
}
|
|
456
697
|
|
|
457
698
|
async function validateReadmes() {
|
|
@@ -626,6 +867,7 @@ async function runCliSmokeTests() {
|
|
|
626
867
|
|
|
627
868
|
async function main() {
|
|
628
869
|
await validatePackageJson();
|
|
870
|
+
await validateCommonSources();
|
|
629
871
|
await validateCatalog();
|
|
630
872
|
await validateReadmes();
|
|
631
873
|
|