@dusky-bluehour/agent-service 0.6.4 → 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 +33 -222
- 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 +7 -4
- package/scripts/generate-from-common.mjs +387 -0
- package/scripts/init.mjs +81 -8
- package/scripts/validate.mjs +249 -2
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,19 +386,32 @@ 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}`);
|
|
210
400
|
}
|
|
211
401
|
}
|
|
212
402
|
|
|
403
|
+
if (!pkg.bin || pkg.bin['tri-agent-manager'] !== 'scripts/init.mjs') {
|
|
404
|
+
fail('[package] bin 설정 오류: tri-agent-manager -> scripts/init.mjs 가 필요합니다.');
|
|
405
|
+
}
|
|
406
|
+
|
|
213
407
|
const requiredFiles = [
|
|
408
|
+
'common',
|
|
214
409
|
'claude-code',
|
|
215
410
|
'antigravity',
|
|
216
411
|
'codex',
|
|
217
412
|
'catalog/tool-catalog.ko.json',
|
|
218
413
|
'scripts/init.mjs',
|
|
414
|
+
'scripts/generate-from-common.mjs',
|
|
219
415
|
'scripts/validate.mjs'
|
|
220
416
|
];
|
|
221
417
|
for (const fileEntry of requiredFiles) {
|
|
@@ -228,7 +424,8 @@ async function validatePackageJson() {
|
|
|
228
424
|
'docs/COMPOSITION.ko.md',
|
|
229
425
|
'docs/DEPLOYMENT-GUIDE.ko.md',
|
|
230
426
|
'docs/UPDATE-GUIDE.ko.md',
|
|
231
|
-
'docs/UX-FLOW.ko.md'
|
|
427
|
+
'docs/UX-FLOW.ko.md',
|
|
428
|
+
'docs/NPM-PUBLISH-REPO-ONLY.ko.md'
|
|
232
429
|
];
|
|
233
430
|
for (const fileEntry of excludedFromPublish) {
|
|
234
431
|
if (Array.isArray(pkg.files) && pkg.files.includes(fileEntry)) {
|
|
@@ -277,10 +474,29 @@ async function validateSkillDirectory(toolName) {
|
|
|
277
474
|
fail(`[${toolName}] frontmatter name/description 누락: ${skillFile}`);
|
|
278
475
|
}
|
|
279
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
|
+
|
|
280
489
|
if (toolName === 'codex') {
|
|
281
490
|
const openaiYaml = path.join(skillsPath, skillName, 'agents', 'openai.yaml');
|
|
282
491
|
if (!(await exists(openaiYaml))) {
|
|
283
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
|
+
}
|
|
284
500
|
}
|
|
285
501
|
}
|
|
286
502
|
}
|
|
@@ -447,6 +663,36 @@ async function validateAntigravityExtras() {
|
|
|
447
663
|
fail(`[antigravity] JSON 파싱 실패: ${path.relative(rootDir, f)} (${error.message})`);
|
|
448
664
|
}
|
|
449
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
|
+
}
|
|
450
696
|
}
|
|
451
697
|
|
|
452
698
|
async function validateReadmes() {
|
|
@@ -621,6 +867,7 @@ async function runCliSmokeTests() {
|
|
|
621
867
|
|
|
622
868
|
async function main() {
|
|
623
869
|
await validatePackageJson();
|
|
870
|
+
await validateCommonSources();
|
|
624
871
|
await validateCatalog();
|
|
625
872
|
await validateReadmes();
|
|
626
873
|
|