agents-inc 0.152.0 → 0.153.0
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/CHANGELOG.md +44 -0
- package/README.md +44 -48
- package/dist/{chunk-LDP5ASDM.js → chunk-2HC2SNRP.js} +2 -15
- package/dist/chunk-2HC2SNRP.js.map +1 -0
- package/dist/{chunk-WKTHWQKM.js → chunk-35VOK7XE.js} +1338 -2573
- package/dist/chunk-35VOK7XE.js.map +1 -0
- package/dist/{chunk-SX5H6TSC.js → chunk-4VYALFQZ.js} +11 -8
- package/dist/chunk-4VYALFQZ.js.map +1 -0
- package/dist/{chunk-KXYVJGJP.js → chunk-6CNRMCFM.js} +3 -2
- package/dist/{chunk-KXYVJGJP.js.map → chunk-6CNRMCFM.js.map} +1 -1
- package/dist/{chunk-LZ52XEPR.js → chunk-ACKC577F.js} +7 -6
- package/dist/chunk-ACKC577F.js.map +1 -0
- package/dist/{chunk-XHUODHZ4.js → chunk-BMGBA6HJ.js} +22 -49
- package/dist/chunk-BMGBA6HJ.js.map +1 -0
- package/dist/{chunk-FVDKAVOL.js → chunk-EFU6P3B7.js} +18 -51
- package/dist/chunk-EFU6P3B7.js.map +1 -0
- package/dist/{chunk-STMHDOZD.js → chunk-F7Z5I6GU.js} +12 -9
- package/dist/chunk-F7Z5I6GU.js.map +1 -0
- package/dist/{chunk-E5X6RJ4E.js → chunk-FIHTAFST.js} +29 -26
- package/dist/chunk-FIHTAFST.js.map +1 -0
- package/dist/{chunk-QZZJFYUQ.js → chunk-FRWKCE6R.js} +3 -3
- package/dist/chunk-FRWKCE6R.js.map +1 -0
- package/dist/{chunk-5UWKOOIS.js → chunk-HEBPKK5L.js} +129 -195
- package/dist/chunk-HEBPKK5L.js.map +1 -0
- package/dist/{chunk-MJ2KHG24.js → chunk-IO4VEW5U.js} +6 -6
- package/dist/{chunk-MJ2KHG24.js.map → chunk-IO4VEW5U.js.map} +1 -1
- package/dist/{chunk-TUPYW2IQ.js → chunk-JC7DBPRD.js} +9 -12
- package/dist/chunk-JC7DBPRD.js.map +1 -0
- package/dist/{chunk-5GUOIJSG.js → chunk-JFAUQDZM.js} +3 -15
- package/dist/chunk-JFAUQDZM.js.map +1 -0
- package/dist/{chunk-ZL7PFNHN.js → chunk-K3O3YQYG.js} +2 -2
- package/dist/{chunk-SKQWRUPX.js → chunk-K7PJDWER.js} +59 -33
- package/dist/chunk-K7PJDWER.js.map +1 -0
- package/dist/{chunk-MVR3SYMN.js → chunk-KET3EVGX.js} +4 -3
- package/dist/{chunk-MVR3SYMN.js.map → chunk-KET3EVGX.js.map} +1 -1
- package/dist/{chunk-MWG4VU64.js → chunk-M5HSTNYU.js} +50 -56
- package/dist/chunk-M5HSTNYU.js.map +1 -0
- package/dist/{chunk-TJJPWUMA.js → chunk-NSJ2S7R5.js} +3 -2
- package/dist/{chunk-TJJPWUMA.js.map → chunk-NSJ2S7R5.js.map} +1 -1
- package/dist/{chunk-IHUY4M22.js → chunk-NXGMM5YN.js} +4 -4
- package/dist/chunk-NXQAY5U7.js +18441 -0
- package/dist/chunk-NXQAY5U7.js.map +1 -0
- package/dist/{chunk-Q2KG7UV3.js → chunk-OJJLYHM3.js} +2 -1
- package/dist/{chunk-Q2KG7UV3.js.map → chunk-OJJLYHM3.js.map} +1 -1
- package/dist/{chunk-PZIZNMHK.js → chunk-ORJ5Y222.js} +159 -138
- package/dist/chunk-ORJ5Y222.js.map +1 -0
- package/dist/{chunk-NR3OZGL4.js → chunk-OZXAJNLA.js} +2 -1
- package/dist/{chunk-NR3OZGL4.js.map → chunk-OZXAJNLA.js.map} +1 -1
- package/dist/{chunk-MM7CTTAV.js → chunk-Q5FLW4JG.js} +2 -2
- package/dist/{chunk-MM7CTTAV.js.map → chunk-Q5FLW4JG.js.map} +1 -1
- package/dist/{chunk-GRVKW3CC.js → chunk-R4SEU3DF.js} +3 -2
- package/dist/{chunk-GRVKW3CC.js.map → chunk-R4SEU3DF.js.map} +1 -1
- package/dist/{chunk-76ADG7LQ.js → chunk-R54KIGN2.js} +8 -22
- package/dist/chunk-R54KIGN2.js.map +1 -0
- package/dist/{chunk-SBHBBZKF.js → chunk-REKOWTIB.js} +25 -120
- package/dist/chunk-REKOWTIB.js.map +1 -0
- package/dist/chunk-TY6CAOL7.js +40 -0
- package/dist/chunk-TY6CAOL7.js.map +1 -0
- package/dist/{chunk-BNSRA6HL.js → chunk-U2DNAHFE.js} +39 -176
- package/dist/chunk-U2DNAHFE.js.map +1 -0
- package/dist/{chunk-PMM2MYMA.js → chunk-U2YSGBHA.js} +624 -349
- package/dist/chunk-U2YSGBHA.js.map +1 -0
- package/dist/{chunk-DTSG5XZB.js → chunk-V3ENMW7G.js} +3 -3
- package/dist/{chunk-L7SZXUBJ.js → chunk-VECFAKM5.js} +7 -6
- package/dist/{chunk-L7SZXUBJ.js.map → chunk-VECFAKM5.js.map} +1 -1
- package/dist/chunk-VGEBYCQZ.js +59 -0
- package/dist/chunk-VGEBYCQZ.js.map +1 -0
- package/dist/chunk-VZRO7RYT.js +3694 -0
- package/dist/chunk-VZRO7RYT.js.map +1 -0
- package/dist/{chunk-LASI35KT.js → chunk-WDAO3RUY.js} +14 -28
- package/dist/chunk-WDAO3RUY.js.map +1 -0
- package/dist/{chunk-MQ7FLIYS.js → chunk-WG6V6VJV.js} +3 -2
- package/dist/{chunk-MQ7FLIYS.js.map → chunk-WG6V6VJV.js.map} +1 -1
- package/dist/chunk-X5XJ6WKO.js +284 -0
- package/dist/chunk-X5XJ6WKO.js.map +1 -0
- package/dist/{chunk-RNJWAKMO.js → chunk-XGMOXMS4.js} +9 -8
- package/dist/chunk-XGMOXMS4.js.map +1 -0
- package/dist/{chunk-IUQBOCSU.js → chunk-ZBPEFQ4G.js} +2 -1
- package/dist/{chunk-IUQBOCSU.js.map → chunk-ZBPEFQ4G.js.map} +1 -1
- package/dist/{chunk-QRDTLVXG.js → chunk-ZNDLUWWD.js} +9 -22
- package/dist/chunk-ZNDLUWWD.js.map +1 -0
- package/dist/commands/build/marketplace.js +114 -35
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +9 -10
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/compile.js +97 -70
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +793 -64
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +169 -208
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +24 -39
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +41 -46
- package/dist/commands/list.js +10 -12
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/search.js +20 -81
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +25 -31
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +82 -332
- package/dist/commands/update.js.map +1 -1
- package/dist/components/common/confirm.js +1 -1
- package/dist/components/common/prompt-confirm.js +1 -1
- package/dist/components/common/select-list.js +2 -2
- package/dist/components/common/spinner.js +1 -1
- package/dist/components/wizard/category-grid.js +5 -6
- package/dist/components/wizard/checkbox-grid.js +5 -6
- package/dist/components/wizard/domain-selection.js +12 -13
- package/dist/components/wizard/run-wizard-session.js +30 -36
- package/dist/components/wizard/scroll-affordance.js +2 -2
- package/dist/components/wizard/skill-agent-summary.js +7 -7
- package/dist/components/wizard/source-grid.js +6 -11
- package/dist/components/wizard/stack-selection.js +9 -9
- package/dist/components/wizard/step-agents.js +12 -12
- package/dist/components/wizard/step-build.js +10 -11
- package/dist/components/wizard/step-confirm.js +11 -11
- package/dist/components/wizard/step-sources.js +11 -17
- package/dist/components/wizard/step-stack.js +10 -10
- package/dist/components/wizard/summary-panel.js +10 -10
- package/dist/components/wizard/toast.js +2 -2
- package/dist/components/wizard/wizard-layout.js +15 -16
- package/dist/components/wizard/wizard-tabs.js +6 -12
- package/dist/components/wizard/wizard.js +29 -35
- package/dist/config-exports.js +1 -1
- package/dist/copy-local-skills-KF2RAVD3.js +14 -0
- package/dist/hooks/init.js +49 -48
- package/dist/hooks/init.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/load-agent-defs-DGXGBU3Q.js +15 -0
- package/dist/{loader-5JP4S7CJ.js → loader-4U7UCE2Y.js} +7 -5
- package/dist/recompile-project-agents-CJVBAWDJ.js +20 -0
- package/dist/{source-loader-MZYCPL2S.js → source-loader-ZNSYJJCI.js} +6 -6
- package/dist/src/agents/developer/ai-developer/identity.md +4 -4
- package/dist/src/agents/developer/ai-developer/playbook.md +1 -1
- package/dist/src/agents/developer/api-developer/identity.md +4 -4
- package/dist/src/agents/developer/api-developer/metadata.yaml +1 -1
- package/dist/src/agents/developer/cli-developer/identity.md +4 -4
- package/dist/src/agents/developer/web-developer/identity.md +2 -2
- package/dist/src/agents/developer/web-developer/metadata.yaml +1 -1
- package/dist/src/agents/meta/agent-summoner/identity.md +4 -5
- package/dist/src/agents/meta/agent-summoner/output.md +2 -2
- package/dist/src/agents/meta/agent-summoner/playbook.md +15 -16
- package/dist/src/agents/meta/codex-keeper/identity.md +4 -4
- package/dist/src/agents/meta/codex-keeper/playbook.md +1 -1
- package/dist/src/agents/meta/convention-keeper/identity.md +1 -1
- package/dist/src/agents/meta/skill-summoner/critical-reminders.md +0 -34
- package/dist/src/agents/meta/skill-summoner/critical-requirements.md +27 -3
- package/dist/src/agents/meta/skill-summoner/identity.md +2 -2
- package/{src/agents/planning/web-pm → dist/src/agents/planning/pm}/critical-reminders.md +10 -7
- package/dist/src/agents/planning/{web-pm → pm}/critical-requirements.md +8 -4
- package/dist/src/agents/planning/pm/identity.md +47 -0
- package/dist/src/agents/planning/pm/metadata.yaml +12 -0
- package/dist/src/agents/planning/{web-pm → pm}/output.md +7 -90
- package/dist/src/agents/planning/pm/playbook.md +185 -0
- package/dist/src/agents/researcher/ai-researcher/critical-reminders.md +58 -0
- package/dist/src/agents/researcher/ai-researcher/critical-requirements.md +40 -0
- package/dist/src/agents/researcher/ai-researcher/identity.md +86 -0
- package/dist/src/agents/researcher/ai-researcher/metadata.yaml +10 -0
- package/dist/src/agents/researcher/ai-researcher/output.md +363 -0
- package/dist/src/agents/researcher/ai-researcher/playbook.md +545 -0
- package/dist/src/agents/researcher/api-researcher/critical-reminders.md +16 -0
- package/dist/src/agents/researcher/api-researcher/identity.md +7 -7
- package/dist/src/agents/researcher/cli-researcher/critical-reminders.md +50 -0
- package/dist/src/agents/researcher/cli-researcher/critical-requirements.md +36 -0
- package/dist/src/agents/researcher/cli-researcher/identity.md +87 -0
- package/dist/src/agents/researcher/cli-researcher/metadata.yaml +10 -0
- package/dist/src/agents/researcher/cli-researcher/output.md +343 -0
- package/dist/src/agents/researcher/cli-researcher/playbook.md +370 -0
- package/dist/src/agents/researcher/web-researcher/identity.md +5 -6
- package/dist/src/agents/reviewer/reviewer/critical-reminders.md +29 -0
- package/dist/src/agents/reviewer/reviewer/critical-requirements.md +31 -0
- package/dist/src/agents/reviewer/reviewer/identity.md +41 -0
- package/dist/src/agents/reviewer/reviewer/metadata.yaml +12 -0
- package/dist/src/agents/reviewer/reviewer/output.md +202 -0
- package/dist/src/agents/reviewer/reviewer/playbook.md +141 -0
- package/dist/src/agents/tester/ai-tester/critical-reminders.md +48 -0
- package/dist/src/agents/tester/ai-tester/critical-requirements.md +49 -0
- package/dist/src/agents/tester/ai-tester/identity.md +62 -0
- package/dist/src/agents/tester/ai-tester/metadata.yaml +12 -0
- package/dist/src/agents/tester/ai-tester/output.md +375 -0
- package/dist/src/agents/tester/ai-tester/playbook.md +789 -0
- package/dist/src/agents/tester/api-tester/identity.md +3 -3
- package/dist/src/agents/tester/cli-tester/critical-reminders.md +3 -3
- package/dist/src/agents/tester/cli-tester/critical-requirements.md +2 -2
- package/dist/src/agents/tester/cli-tester/identity.md +3 -3
- package/dist/src/agents/tester/cli-tester/output.md +4 -4
- package/dist/src/agents/tester/cli-tester/playbook.md +3 -3
- package/dist/src/agents/tester/web-tester/identity.md +3 -3
- package/dist/stores/wizard-store.js +8 -6
- package/package.json +13 -2
- package/src/agents/developer/ai-developer/identity.md +4 -4
- package/src/agents/developer/ai-developer/playbook.md +1 -1
- package/src/agents/developer/api-developer/identity.md +4 -4
- package/src/agents/developer/api-developer/metadata.yaml +1 -1
- package/src/agents/developer/cli-developer/identity.md +4 -4
- package/src/agents/developer/web-developer/identity.md +2 -2
- package/src/agents/developer/web-developer/metadata.yaml +1 -1
- package/src/agents/meta/agent-summoner/identity.md +4 -5
- package/src/agents/meta/agent-summoner/output.md +2 -2
- package/src/agents/meta/agent-summoner/playbook.md +15 -16
- package/src/agents/meta/codex-keeper/identity.md +4 -4
- package/src/agents/meta/codex-keeper/playbook.md +1 -1
- package/src/agents/meta/convention-keeper/identity.md +1 -1
- package/src/agents/meta/skill-summoner/critical-reminders.md +0 -34
- package/src/agents/meta/skill-summoner/critical-requirements.md +27 -3
- package/src/agents/meta/skill-summoner/identity.md +2 -2
- package/{dist/src/agents/planning/web-pm → src/agents/planning/pm}/critical-reminders.md +10 -7
- package/src/agents/planning/{web-pm → pm}/critical-requirements.md +8 -4
- package/src/agents/planning/pm/identity.md +47 -0
- package/src/agents/planning/pm/metadata.yaml +12 -0
- package/src/agents/planning/{web-pm → pm}/output.md +7 -90
- package/src/agents/planning/pm/playbook.md +185 -0
- package/src/agents/researcher/ai-researcher/critical-reminders.md +58 -0
- package/src/agents/researcher/ai-researcher/critical-requirements.md +40 -0
- package/src/agents/researcher/ai-researcher/identity.md +86 -0
- package/src/agents/researcher/ai-researcher/metadata.yaml +10 -0
- package/src/agents/researcher/ai-researcher/output.md +363 -0
- package/src/agents/researcher/ai-researcher/playbook.md +545 -0
- package/src/agents/researcher/api-researcher/critical-reminders.md +16 -0
- package/src/agents/researcher/api-researcher/identity.md +7 -7
- package/src/agents/researcher/cli-researcher/critical-reminders.md +50 -0
- package/src/agents/researcher/cli-researcher/critical-requirements.md +36 -0
- package/src/agents/researcher/cli-researcher/identity.md +87 -0
- package/src/agents/researcher/cli-researcher/metadata.yaml +10 -0
- package/src/agents/researcher/cli-researcher/output.md +343 -0
- package/src/agents/researcher/cli-researcher/playbook.md +370 -0
- package/src/agents/researcher/web-researcher/identity.md +5 -6
- package/src/agents/reviewer/reviewer/critical-reminders.md +29 -0
- package/src/agents/reviewer/reviewer/critical-requirements.md +31 -0
- package/src/agents/reviewer/reviewer/identity.md +41 -0
- package/src/agents/reviewer/reviewer/metadata.yaml +12 -0
- package/src/agents/reviewer/reviewer/output.md +202 -0
- package/src/agents/reviewer/reviewer/playbook.md +141 -0
- package/src/agents/tester/ai-tester/critical-reminders.md +48 -0
- package/src/agents/tester/ai-tester/critical-requirements.md +49 -0
- package/src/agents/tester/ai-tester/identity.md +62 -0
- package/src/agents/tester/ai-tester/metadata.yaml +12 -0
- package/src/agents/tester/ai-tester/output.md +375 -0
- package/src/agents/tester/ai-tester/playbook.md +789 -0
- package/src/agents/tester/api-tester/identity.md +3 -3
- package/src/agents/tester/cli-tester/critical-reminders.md +3 -3
- package/src/agents/tester/cli-tester/critical-requirements.md +2 -2
- package/src/agents/tester/cli-tester/identity.md +3 -3
- package/src/agents/tester/cli-tester/output.md +4 -4
- package/src/agents/tester/cli-tester/playbook.md +3 -3
- package/src/agents/tester/web-tester/identity.md +3 -3
- package/src/schemas/metadata.schema.json +31 -2
- package/src/schemas/project-config.schema.json +61 -15
- package/src/schemas/project-source-config.schema.json +0 -47
- package/dist/chunk-5GUOIJSG.js.map +0 -1
- package/dist/chunk-5UWKOOIS.js.map +0 -1
- package/dist/chunk-76ADG7LQ.js.map +0 -1
- package/dist/chunk-BNSRA6HL.js.map +0 -1
- package/dist/chunk-E5X6RJ4E.js.map +0 -1
- package/dist/chunk-EEPELKOM.js +0 -5938
- package/dist/chunk-EEPELKOM.js.map +0 -1
- package/dist/chunk-F7T5AFFN.js +0 -20
- package/dist/chunk-F7T5AFFN.js.map +0 -1
- package/dist/chunk-FVDKAVOL.js.map +0 -1
- package/dist/chunk-KFB5CRXZ.js +0 -377
- package/dist/chunk-KFB5CRXZ.js.map +0 -1
- package/dist/chunk-KR65TPKC.js +0 -664
- package/dist/chunk-KR65TPKC.js.map +0 -1
- package/dist/chunk-LASI35KT.js.map +0 -1
- package/dist/chunk-LDP5ASDM.js.map +0 -1
- package/dist/chunk-LZ52XEPR.js.map +0 -1
- package/dist/chunk-M7HO7NBK.js +0 -88
- package/dist/chunk-M7HO7NBK.js.map +0 -1
- package/dist/chunk-MWG4VU64.js.map +0 -1
- package/dist/chunk-ODNDXQH2.js +0 -77
- package/dist/chunk-ODNDXQH2.js.map +0 -1
- package/dist/chunk-P44SXVH3.js +0 -80
- package/dist/chunk-P44SXVH3.js.map +0 -1
- package/dist/chunk-PMM2MYMA.js.map +0 -1
- package/dist/chunk-PZIZNMHK.js.map +0 -1
- package/dist/chunk-Q45ZU6HD.js +0 -37
- package/dist/chunk-Q45ZU6HD.js.map +0 -1
- package/dist/chunk-QRDTLVXG.js.map +0 -1
- package/dist/chunk-QZZJFYUQ.js.map +0 -1
- package/dist/chunk-R5NOI2LP.js +0 -170
- package/dist/chunk-R5NOI2LP.js.map +0 -1
- package/dist/chunk-RNJWAKMO.js.map +0 -1
- package/dist/chunk-SBHBBZKF.js.map +0 -1
- package/dist/chunk-SKQWRUPX.js.map +0 -1
- package/dist/chunk-STMHDOZD.js.map +0 -1
- package/dist/chunk-SX5H6TSC.js.map +0 -1
- package/dist/chunk-TUPYW2IQ.js.map +0 -1
- package/dist/chunk-UBEDZ4FD.js +0 -4198
- package/dist/chunk-UBEDZ4FD.js.map +0 -1
- package/dist/chunk-VY6MNOXL.js +0 -20
- package/dist/chunk-VY6MNOXL.js.map +0 -1
- package/dist/chunk-WBCPLH66.js +0 -42
- package/dist/chunk-WBCPLH66.js.map +0 -1
- package/dist/chunk-WKTHWQKM.js.map +0 -1
- package/dist/chunk-XHUODHZ4.js.map +0 -1
- package/dist/chunk-ZPPHXXAP.js +0 -252
- package/dist/chunk-ZPPHXXAP.js.map +0 -1
- package/dist/commands/import/skill.js +0 -344
- package/dist/commands/import/skill.js.map +0 -1
- package/dist/commands/new/agent.js +0 -300
- package/dist/commands/new/agent.js.map +0 -1
- package/dist/commands/new/marketplace.js +0 -310
- package/dist/commands/new/marketplace.js.map +0 -1
- package/dist/commands/new/skill.js +0 -26
- package/dist/commands/validate.js +0 -575
- package/dist/commands/validate.js.map +0 -1
- package/dist/components/wizard/search-modal.js +0 -13
- package/dist/components/wizard/selection-card.js +0 -9
- package/dist/components/wizard/step-settings.js +0 -18
- package/dist/copy-local-skills-6EMVN7RB.js +0 -14
- package/dist/load-agent-defs-BWOUVEAR.js +0 -15
- package/dist/load-agent-defs-BWOUVEAR.js.map +0 -1
- package/dist/loader-5JP4S7CJ.js.map +0 -1
- package/dist/recompile-project-agents-6DL45TDI.js +0 -19
- package/dist/recompile-project-agents-6DL45TDI.js.map +0 -1
- package/dist/source-loader-MZYCPL2S.js.map +0 -1
- package/dist/src/agents/developer/web-architecture/critical-reminders.md +0 -48
- package/dist/src/agents/developer/web-architecture/critical-requirements.md +0 -65
- package/dist/src/agents/developer/web-architecture/identity.md +0 -64
- package/dist/src/agents/developer/web-architecture/metadata.yaml +0 -12
- package/dist/src/agents/developer/web-architecture/output.md +0 -449
- package/dist/src/agents/developer/web-architecture/playbook.md +0 -481
- package/dist/src/agents/pattern/pattern-scout/critical-reminders.md +0 -71
- package/dist/src/agents/pattern/pattern-scout/critical-requirements.md +0 -31
- package/dist/src/agents/pattern/pattern-scout/identity.md +0 -25
- package/dist/src/agents/pattern/pattern-scout/metadata.yaml +0 -10
- package/dist/src/agents/pattern/pattern-scout/output.md +0 -290
- package/dist/src/agents/pattern/pattern-scout/playbook.md +0 -1806
- package/dist/src/agents/pattern/web-pattern-critique/critical-reminders.md +0 -30
- package/dist/src/agents/pattern/web-pattern-critique/critical-requirements.md +0 -28
- package/dist/src/agents/pattern/web-pattern-critique/identity.md +0 -41
- package/dist/src/agents/pattern/web-pattern-critique/metadata.yaml +0 -12
- package/dist/src/agents/pattern/web-pattern-critique/output.md +0 -314
- package/dist/src/agents/pattern/web-pattern-critique/playbook.md +0 -572
- package/dist/src/agents/planning/api-pm/critical-reminders.md +0 -48
- package/dist/src/agents/planning/api-pm/critical-requirements.md +0 -41
- package/dist/src/agents/planning/api-pm/identity.md +0 -39
- package/dist/src/agents/planning/api-pm/metadata.yaml +0 -12
- package/dist/src/agents/planning/api-pm/output.md +0 -475
- package/dist/src/agents/planning/api-pm/playbook.md +0 -129
- package/dist/src/agents/planning/web-pm/identity.md +0 -26
- package/dist/src/agents/planning/web-pm/metadata.yaml +0 -12
- package/dist/src/agents/planning/web-pm/playbook.md +0 -318
- package/dist/src/agents/reviewer/ai-reviewer/critical-reminders.md +0 -40
- package/dist/src/agents/reviewer/ai-reviewer/critical-requirements.md +0 -37
- package/dist/src/agents/reviewer/ai-reviewer/identity.md +0 -51
- package/dist/src/agents/reviewer/ai-reviewer/metadata.yaml +0 -10
- package/dist/src/agents/reviewer/ai-reviewer/output.md +0 -395
- package/dist/src/agents/reviewer/ai-reviewer/playbook.md +0 -90
- package/dist/src/agents/reviewer/api-reviewer/critical-reminders.md +0 -31
- package/dist/src/agents/reviewer/api-reviewer/critical-requirements.md +0 -27
- package/dist/src/agents/reviewer/api-reviewer/identity.md +0 -51
- package/dist/src/agents/reviewer/api-reviewer/metadata.yaml +0 -12
- package/dist/src/agents/reviewer/api-reviewer/output.md +0 -343
- package/dist/src/agents/reviewer/api-reviewer/playbook.md +0 -288
- package/dist/src/agents/reviewer/cli-reviewer/critical-reminders.md +0 -33
- package/dist/src/agents/reviewer/cli-reviewer/critical-requirements.md +0 -30
- package/dist/src/agents/reviewer/cli-reviewer/identity.md +0 -44
- package/dist/src/agents/reviewer/cli-reviewer/metadata.yaml +0 -12
- package/dist/src/agents/reviewer/cli-reviewer/output.md +0 -414
- package/dist/src/agents/reviewer/cli-reviewer/playbook.md +0 -218
- package/dist/src/agents/reviewer/infra-reviewer/critical-reminders.md +0 -38
- package/dist/src/agents/reviewer/infra-reviewer/critical-requirements.md +0 -38
- package/dist/src/agents/reviewer/infra-reviewer/identity.md +0 -53
- package/dist/src/agents/reviewer/infra-reviewer/metadata.yaml +0 -10
- package/dist/src/agents/reviewer/infra-reviewer/output.md +0 -364
- package/dist/src/agents/reviewer/infra-reviewer/playbook.md +0 -161
- package/dist/src/agents/reviewer/web-reviewer/critical-reminders.md +0 -31
- package/dist/src/agents/reviewer/web-reviewer/critical-requirements.md +0 -26
- package/dist/src/agents/reviewer/web-reviewer/identity.md +0 -40
- package/dist/src/agents/reviewer/web-reviewer/metadata.yaml +0 -12
- package/dist/src/agents/reviewer/web-reviewer/output.md +0 -333
- package/dist/src/agents/reviewer/web-reviewer/playbook.md +0 -156
- package/src/agents/developer/web-architecture/critical-reminders.md +0 -48
- package/src/agents/developer/web-architecture/critical-requirements.md +0 -65
- package/src/agents/developer/web-architecture/identity.md +0 -64
- package/src/agents/developer/web-architecture/metadata.yaml +0 -12
- package/src/agents/developer/web-architecture/output.md +0 -449
- package/src/agents/developer/web-architecture/playbook.md +0 -481
- package/src/agents/pattern/pattern-scout/critical-reminders.md +0 -71
- package/src/agents/pattern/pattern-scout/critical-requirements.md +0 -31
- package/src/agents/pattern/pattern-scout/identity.md +0 -25
- package/src/agents/pattern/pattern-scout/metadata.yaml +0 -10
- package/src/agents/pattern/pattern-scout/output.md +0 -290
- package/src/agents/pattern/pattern-scout/playbook.md +0 -1806
- package/src/agents/pattern/web-pattern-critique/critical-reminders.md +0 -30
- package/src/agents/pattern/web-pattern-critique/critical-requirements.md +0 -28
- package/src/agents/pattern/web-pattern-critique/identity.md +0 -41
- package/src/agents/pattern/web-pattern-critique/metadata.yaml +0 -12
- package/src/agents/pattern/web-pattern-critique/output.md +0 -314
- package/src/agents/pattern/web-pattern-critique/playbook.md +0 -572
- package/src/agents/planning/api-pm/critical-reminders.md +0 -48
- package/src/agents/planning/api-pm/critical-requirements.md +0 -41
- package/src/agents/planning/api-pm/identity.md +0 -39
- package/src/agents/planning/api-pm/metadata.yaml +0 -12
- package/src/agents/planning/api-pm/output.md +0 -475
- package/src/agents/planning/api-pm/playbook.md +0 -129
- package/src/agents/planning/web-pm/identity.md +0 -26
- package/src/agents/planning/web-pm/metadata.yaml +0 -12
- package/src/agents/planning/web-pm/playbook.md +0 -318
- package/src/agents/reviewer/ai-reviewer/critical-reminders.md +0 -40
- package/src/agents/reviewer/ai-reviewer/critical-requirements.md +0 -37
- package/src/agents/reviewer/ai-reviewer/identity.md +0 -51
- package/src/agents/reviewer/ai-reviewer/metadata.yaml +0 -10
- package/src/agents/reviewer/ai-reviewer/output.md +0 -395
- package/src/agents/reviewer/ai-reviewer/playbook.md +0 -90
- package/src/agents/reviewer/api-reviewer/critical-reminders.md +0 -31
- package/src/agents/reviewer/api-reviewer/critical-requirements.md +0 -27
- package/src/agents/reviewer/api-reviewer/identity.md +0 -51
- package/src/agents/reviewer/api-reviewer/metadata.yaml +0 -12
- package/src/agents/reviewer/api-reviewer/output.md +0 -343
- package/src/agents/reviewer/api-reviewer/playbook.md +0 -288
- package/src/agents/reviewer/cli-reviewer/critical-reminders.md +0 -33
- package/src/agents/reviewer/cli-reviewer/critical-requirements.md +0 -30
- package/src/agents/reviewer/cli-reviewer/identity.md +0 -44
- package/src/agents/reviewer/cli-reviewer/metadata.yaml +0 -12
- package/src/agents/reviewer/cli-reviewer/output.md +0 -414
- package/src/agents/reviewer/cli-reviewer/playbook.md +0 -218
- package/src/agents/reviewer/infra-reviewer/critical-reminders.md +0 -38
- package/src/agents/reviewer/infra-reviewer/critical-requirements.md +0 -38
- package/src/agents/reviewer/infra-reviewer/identity.md +0 -53
- package/src/agents/reviewer/infra-reviewer/metadata.yaml +0 -10
- package/src/agents/reviewer/infra-reviewer/output.md +0 -364
- package/src/agents/reviewer/infra-reviewer/playbook.md +0 -161
- package/src/agents/reviewer/web-reviewer/critical-reminders.md +0 -31
- package/src/agents/reviewer/web-reviewer/critical-requirements.md +0 -26
- package/src/agents/reviewer/web-reviewer/identity.md +0 -40
- package/src/agents/reviewer/web-reviewer/metadata.yaml +0 -12
- package/src/agents/reviewer/web-reviewer/output.md +0 -333
- package/src/agents/reviewer/web-reviewer/playbook.md +0 -156
- /package/dist/{chunk-ZL7PFNHN.js.map → chunk-K3O3YQYG.js.map} +0 -0
- /package/dist/{chunk-IHUY4M22.js.map → chunk-NXGMM5YN.js.map} +0 -0
- /package/dist/{chunk-DTSG5XZB.js.map → chunk-V3ENMW7G.js.map} +0 -0
- /package/dist/{commands/new/skill.js.map → copy-local-skills-KF2RAVD3.js.map} +0 -0
- /package/dist/{components/wizard/search-modal.js.map → load-agent-defs-DGXGBU3Q.js.map} +0 -0
- /package/dist/{components/wizard/selection-card.js.map → loader-4U7UCE2Y.js.map} +0 -0
- /package/dist/{components/wizard/step-settings.js.map → recompile-project-agents-CJVBAWDJ.js.map} +0 -0
- /package/dist/{copy-local-skills-6EMVN7RB.js.map → source-loader-ZNSYJJCI.js.map} +0 -0
package/dist/commands/doctor.js
CHANGED
|
@@ -2,58 +2,591 @@
|
|
|
2
2
|
import {
|
|
3
3
|
detectProject,
|
|
4
4
|
loadSource
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
5
|
+
} from "../chunk-F7Z5I6GU.js";
|
|
6
|
+
import "../chunk-REKOWTIB.js";
|
|
7
|
+
import "../chunk-NXGMM5YN.js";
|
|
8
|
+
import "../chunk-FRWKCE6R.js";
|
|
9
9
|
import {
|
|
10
10
|
filterExcludedEntries,
|
|
11
11
|
listAgentMdFiles
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-FIHTAFST.js";
|
|
13
13
|
import {
|
|
14
14
|
BaseCommand,
|
|
15
15
|
EXIT_CODES
|
|
16
|
-
} from "../chunk-
|
|
17
|
-
import "../chunk-
|
|
16
|
+
} from "../chunk-X5XJ6WKO.js";
|
|
17
|
+
import "../chunk-TY6CAOL7.js";
|
|
18
|
+
import "../chunk-K3O3YQYG.js";
|
|
18
19
|
import {
|
|
20
|
+
checkMatrixHealth,
|
|
21
|
+
configDirsInPlay,
|
|
22
|
+
declaresNoContent,
|
|
19
23
|
discoverLocalSkills,
|
|
20
24
|
effectivelyExcludedSkillIds,
|
|
25
|
+
findConfigLoadFailures,
|
|
26
|
+
getInstalledPluginsRegistryPath,
|
|
27
|
+
getProjectConfigPath,
|
|
28
|
+
getProjectPluginsDir,
|
|
21
29
|
getStackSkillIds,
|
|
30
|
+
getUserPluginsDir,
|
|
22
31
|
getVerifiedPluginInstallPaths,
|
|
23
32
|
installBaseDir,
|
|
24
33
|
isHomeDirectory,
|
|
34
|
+
isLocalSource,
|
|
35
|
+
isRecord,
|
|
36
|
+
listRegisteredPluginInstalls,
|
|
37
|
+
loadConfig,
|
|
38
|
+
loadProjectConfigFromDir,
|
|
39
|
+
loadProjectSourceConfig,
|
|
40
|
+
loadSkillsMatrixFromSource,
|
|
25
41
|
parseMarketplacePluginRef,
|
|
26
42
|
resolveInstallPaths,
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
resolvePrimarySourceEntry,
|
|
44
|
+
validateAgentFrontmatter,
|
|
45
|
+
validateAllPlugins,
|
|
46
|
+
validatePlugin,
|
|
47
|
+
validateProjectConfig,
|
|
48
|
+
validateSkillFrontmatter
|
|
49
|
+
} from "../chunk-NXQAY5U7.js";
|
|
29
50
|
import {
|
|
51
|
+
agentYamlGenerationSchema,
|
|
30
52
|
directoryExists,
|
|
31
53
|
fileExists,
|
|
54
|
+
formatZodErrors,
|
|
32
55
|
getErrorMessage,
|
|
33
|
-
|
|
34
|
-
|
|
56
|
+
glob,
|
|
57
|
+
listDirectories,
|
|
58
|
+
metadataValidationSchema,
|
|
59
|
+
parseFrontmatter,
|
|
60
|
+
readFile,
|
|
61
|
+
readSkillMetadata,
|
|
62
|
+
setVerbose,
|
|
63
|
+
skillCategoriesFileSchema,
|
|
64
|
+
skillRulesFileSchema,
|
|
65
|
+
splitMetadataValidationIssues,
|
|
66
|
+
stackConfigValidationSchema,
|
|
67
|
+
stacksConfigSchema,
|
|
68
|
+
validateSkillMetadata
|
|
69
|
+
} from "../chunk-U2YSGBHA.js";
|
|
35
70
|
import {
|
|
36
71
|
matrix
|
|
37
|
-
} from "../chunk-
|
|
72
|
+
} from "../chunk-35VOK7XE.js";
|
|
38
73
|
import "../chunk-VASLW636.js";
|
|
39
74
|
import {
|
|
40
75
|
CLAUDE_SRC_DIR,
|
|
41
76
|
CLI_INVOKE_COMMAND,
|
|
42
77
|
DEFAULT_BRANDING,
|
|
78
|
+
DIRS,
|
|
43
79
|
EJECT_SOURCE,
|
|
44
80
|
LOCAL_SKILLS_PATH,
|
|
81
|
+
PLUGIN_MANIFEST_DIR,
|
|
82
|
+
SKILLS_DIR_PATH,
|
|
83
|
+
SKILL_CATEGORIES_PATH,
|
|
84
|
+
SKILL_RULES_PATH,
|
|
85
|
+
STACKS_FILE_PATH,
|
|
45
86
|
STANDARD_FILES,
|
|
46
87
|
UI_SYMBOLS
|
|
47
|
-
} from "../chunk-
|
|
48
|
-
import "../chunk-
|
|
88
|
+
} from "../chunk-R54KIGN2.js";
|
|
89
|
+
import "../chunk-VZRO7RYT.js";
|
|
49
90
|
|
|
50
91
|
// src/cli/commands/doctor.ts
|
|
51
|
-
import
|
|
92
|
+
import os2 from "os";
|
|
93
|
+
import path3 from "path";
|
|
94
|
+
|
|
95
|
+
// src/cli/lib/source-validator.ts
|
|
52
96
|
import path from "path";
|
|
97
|
+
import { parse as parseYaml } from "yaml";
|
|
98
|
+
import "zod";
|
|
99
|
+
async function isSourceRepo(dir) {
|
|
100
|
+
const sourceConfig = await loadProjectSourceConfig(dir);
|
|
101
|
+
return directoryExists(path.join(dir, sourceConfig?.skillsDir ?? SKILLS_DIR_PATH));
|
|
102
|
+
}
|
|
103
|
+
function isSnakeCase(key) {
|
|
104
|
+
return /[a-z]_[a-z]/.test(key);
|
|
105
|
+
}
|
|
106
|
+
function checkSnakeCaseKeys(rawMetadata, relPath) {
|
|
107
|
+
if (!isRecord(rawMetadata)) return [];
|
|
108
|
+
return Object.keys(rawMetadata).filter(isSnakeCase).map((key) => ({
|
|
109
|
+
severity: "error",
|
|
110
|
+
file: relPath,
|
|
111
|
+
message: `Key '${key}' uses snake_case \u2014 use camelCase instead`
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
function checkDirNameMatchesSkillId(skillId, relPath, dirName) {
|
|
115
|
+
if (skillId === dirName) return [];
|
|
116
|
+
return [
|
|
117
|
+
{
|
|
118
|
+
severity: "warning",
|
|
119
|
+
file: relPath,
|
|
120
|
+
message: `Directory name '${dirName}' does not match skill id '${skillId}'`
|
|
121
|
+
}
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
async function checkSkillDirName(skillsDir, skillsDirRelPath, skillDir) {
|
|
125
|
+
const dirName = path.basename(skillDir);
|
|
126
|
+
const skillMdRelPath = path.join(skillsDirRelPath, skillDir, STANDARD_FILES.SKILL_MD);
|
|
127
|
+
try {
|
|
128
|
+
const content = await readFile(path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD));
|
|
129
|
+
const frontmatter = parseFrontmatter(content, skillMdRelPath);
|
|
130
|
+
if (frontmatter === null) {
|
|
131
|
+
return [
|
|
132
|
+
{
|
|
133
|
+
severity: "warning",
|
|
134
|
+
file: skillMdRelPath,
|
|
135
|
+
message: `Cannot verify directory name '${dirName}': missing or invalid ${STANDARD_FILES.SKILL_MD} frontmatter`
|
|
136
|
+
}
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
return checkDirNameMatchesSkillId(frontmatter.name, skillMdRelPath, dirName);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
return [
|
|
142
|
+
{
|
|
143
|
+
severity: "warning",
|
|
144
|
+
file: skillMdRelPath,
|
|
145
|
+
message: `Cannot verify directory name '${dirName}': ${getErrorMessage(error)}`
|
|
146
|
+
}
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function validateSkillFilePairs(skillMdDirs, metadataDirs, skillsDir) {
|
|
151
|
+
const missingMetadata = [...skillMdDirs].filter((dir) => !metadataDirs.has(dir)).map((dir) => ({
|
|
152
|
+
severity: "error",
|
|
153
|
+
file: path.join(skillsDir, dir),
|
|
154
|
+
message: `Missing ${STANDARD_FILES.METADATA_YAML} \u2014 skill directory has ${STANDARD_FILES.SKILL_MD} but no metadata`
|
|
155
|
+
}));
|
|
156
|
+
const missingSkillMd = [...metadataDirs].filter((dir) => !skillMdDirs.has(dir)).map((dir) => ({
|
|
157
|
+
severity: "error",
|
|
158
|
+
file: path.join(skillsDir, dir),
|
|
159
|
+
message: `Missing ${STANDARD_FILES.SKILL_MD} \u2014 skill directory has ${STANDARD_FILES.METADATA_YAML} but no SKILL.md`
|
|
160
|
+
}));
|
|
161
|
+
return [...missingMetadata, ...missingSkillMd];
|
|
162
|
+
}
|
|
163
|
+
async function validateSource(sourcePath) {
|
|
164
|
+
const issues = [];
|
|
165
|
+
const resolvedPath = path.isAbsolute(sourcePath) ? sourcePath : path.resolve(sourcePath);
|
|
166
|
+
if (!await directoryExists(resolvedPath)) {
|
|
167
|
+
issues.push({
|
|
168
|
+
severity: "error",
|
|
169
|
+
file: resolvedPath,
|
|
170
|
+
message: "Source directory does not exist"
|
|
171
|
+
});
|
|
172
|
+
return buildResult(issues, 0);
|
|
173
|
+
}
|
|
174
|
+
const sourceProjectConfig = await loadProjectSourceConfig(resolvedPath);
|
|
175
|
+
const skillsDirRelPath = sourceProjectConfig?.skillsDir ?? SKILLS_DIR_PATH;
|
|
176
|
+
const skillsDir = path.join(resolvedPath, skillsDirRelPath);
|
|
177
|
+
if (!await directoryExists(skillsDir)) {
|
|
178
|
+
issues.push({
|
|
179
|
+
severity: "error",
|
|
180
|
+
file: skillsDir,
|
|
181
|
+
message: "Skills directory does not exist"
|
|
182
|
+
});
|
|
183
|
+
return buildResult(issues, 0);
|
|
184
|
+
}
|
|
185
|
+
const skillMdFiles = await glob(`**/${STANDARD_FILES.SKILL_MD}`, skillsDir);
|
|
186
|
+
const metadataFiles = await glob(`**/${STANDARD_FILES.METADATA_YAML}`, skillsDir);
|
|
187
|
+
const skillMdDirs = new Set(skillMdFiles.map((f) => path.dirname(f)));
|
|
188
|
+
const metadataDirs = new Set(metadataFiles.map((f) => path.dirname(f)));
|
|
189
|
+
issues.push(...validateSkillFilePairs(skillMdDirs, metadataDirs, skillsDir));
|
|
190
|
+
const validMetadataFiles = metadataFiles.filter((f) => skillMdDirs.has(path.dirname(f)));
|
|
191
|
+
for (const metadataFile of validMetadataFiles) {
|
|
192
|
+
issues.push(...await validateOneSkill(skillsDir, skillsDirRelPath, metadataFile));
|
|
193
|
+
}
|
|
194
|
+
issues.push(...await checkCrossReferences(resolvedPath));
|
|
195
|
+
const extraIssues = await Promise.all([
|
|
196
|
+
validateStacks(resolvedPath),
|
|
197
|
+
validateAgents(resolvedPath),
|
|
198
|
+
validateConfigFiles(resolvedPath)
|
|
199
|
+
]);
|
|
200
|
+
issues.push(...extraIssues.flat());
|
|
201
|
+
return buildResult(issues, validMetadataFiles.length);
|
|
202
|
+
}
|
|
203
|
+
async function validateOneSkill(skillsDir, skillsDirRelPath, metadataFile) {
|
|
204
|
+
const relPath = path.join(skillsDirRelPath, metadataFile);
|
|
205
|
+
let rawMetadata;
|
|
206
|
+
try {
|
|
207
|
+
rawMetadata = parseYaml(await readFile(path.join(skillsDir, metadataFile)));
|
|
208
|
+
} catch (error) {
|
|
209
|
+
return [
|
|
210
|
+
{
|
|
211
|
+
severity: "error",
|
|
212
|
+
file: relPath,
|
|
213
|
+
message: `Failed to parse YAML: ${getErrorMessage(error)}`
|
|
214
|
+
}
|
|
215
|
+
];
|
|
216
|
+
}
|
|
217
|
+
return [
|
|
218
|
+
...checkSnakeCaseKeys(rawMetadata, relPath),
|
|
219
|
+
...checkMetadataSchema(rawMetadata, relPath),
|
|
220
|
+
// Independent of metadata validity — the id lives in SKILL.md frontmatter
|
|
221
|
+
...await checkSkillDirName(skillsDir, skillsDirRelPath, path.dirname(metadataFile))
|
|
222
|
+
];
|
|
223
|
+
}
|
|
224
|
+
function checkMetadataSchema(rawMetadata, relPath) {
|
|
225
|
+
const result = validateSkillMetadata(rawMetadata);
|
|
226
|
+
if (result.success) return [];
|
|
227
|
+
const { errors, warnings } = splitMetadataValidationIssues(result.error, rawMetadata);
|
|
228
|
+
return [
|
|
229
|
+
...errors.map((message) => ({ severity: "error", file: relPath, message })),
|
|
230
|
+
...warnings.map((message) => ({ severity: "warning", file: relPath, message }))
|
|
231
|
+
];
|
|
232
|
+
}
|
|
233
|
+
async function checkCrossReferences(resolvedPath) {
|
|
234
|
+
try {
|
|
235
|
+
await loadSkillsMatrixFromSource({ sourceFlag: resolvedPath, skipExtraSources: true });
|
|
236
|
+
return checkMatrixHealth(matrix).map((healthIssue) => ({
|
|
237
|
+
severity: healthIssue.severity,
|
|
238
|
+
file: SKILL_CATEGORIES_PATH,
|
|
239
|
+
message: healthIssue.details
|
|
240
|
+
}));
|
|
241
|
+
} catch (error) {
|
|
242
|
+
return [
|
|
243
|
+
{
|
|
244
|
+
severity: "warning",
|
|
245
|
+
file: SKILL_CATEGORIES_PATH,
|
|
246
|
+
message: `Cross-reference validation skipped: failed to load categories/rules: ${getErrorMessage(error)}`
|
|
247
|
+
}
|
|
248
|
+
];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async function validateStacks(resolvedPath) {
|
|
252
|
+
const stacksDir = path.join(resolvedPath, DIRS.stacks);
|
|
253
|
+
if (!await directoryExists(stacksDir)) return [];
|
|
254
|
+
const [skillMetaIssues, configIssues] = await Promise.all([
|
|
255
|
+
validateYamlFiles({
|
|
256
|
+
baseDir: stacksDir,
|
|
257
|
+
relBaseDir: DIRS.stacks,
|
|
258
|
+
pattern: `**/skills/**/${STANDARD_FILES.METADATA_YAML}`,
|
|
259
|
+
schema: metadataValidationSchema
|
|
260
|
+
}),
|
|
261
|
+
validateYamlFiles({
|
|
262
|
+
baseDir: stacksDir,
|
|
263
|
+
relBaseDir: DIRS.stacks,
|
|
264
|
+
pattern: `*/${STANDARD_FILES.CONFIG_YAML}`,
|
|
265
|
+
schema: stackConfigValidationSchema
|
|
266
|
+
})
|
|
267
|
+
]);
|
|
268
|
+
return [...skillMetaIssues, ...configIssues];
|
|
269
|
+
}
|
|
270
|
+
async function validateAgents(resolvedPath) {
|
|
271
|
+
const agentsDir = path.join(resolvedPath, DIRS.agents);
|
|
272
|
+
if (!await directoryExists(agentsDir)) return [];
|
|
273
|
+
return validateYamlFiles({
|
|
274
|
+
baseDir: agentsDir,
|
|
275
|
+
relBaseDir: DIRS.agents,
|
|
276
|
+
pattern: `**/${STANDARD_FILES.AGENT_METADATA_YAML}`,
|
|
277
|
+
schema: agentYamlGenerationSchema
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
async function validateConfigFiles(resolvedPath) {
|
|
281
|
+
const results = await Promise.all([
|
|
282
|
+
validateTsConfig(resolvedPath, SKILL_CATEGORIES_PATH, skillCategoriesFileSchema),
|
|
283
|
+
validateTsConfig(resolvedPath, SKILL_RULES_PATH, skillRulesFileSchema),
|
|
284
|
+
validateTsConfig(resolvedPath, STACKS_FILE_PATH, stacksConfigSchema)
|
|
285
|
+
]);
|
|
286
|
+
return results.flat();
|
|
287
|
+
}
|
|
288
|
+
async function validateYamlFiles(opts) {
|
|
289
|
+
const issues = [];
|
|
290
|
+
const files = await glob(opts.pattern, opts.baseDir);
|
|
291
|
+
for (const relFile of files) {
|
|
292
|
+
const absPath = path.join(opts.baseDir, relFile);
|
|
293
|
+
const displayPath = path.join(opts.relBaseDir, relFile);
|
|
294
|
+
let parsed;
|
|
295
|
+
try {
|
|
296
|
+
parsed = parseYaml(await readFile(absPath));
|
|
297
|
+
} catch {
|
|
298
|
+
issues.push({ severity: "error", file: displayPath, message: "Failed to parse YAML" });
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
const result = opts.schema.safeParse(parsed);
|
|
302
|
+
if (result.success) continue;
|
|
303
|
+
issues.push(
|
|
304
|
+
...formatZodErrors(result.error).map((message) => ({
|
|
305
|
+
severity: "error",
|
|
306
|
+
file: displayPath,
|
|
307
|
+
message
|
|
308
|
+
}))
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
return issues;
|
|
312
|
+
}
|
|
313
|
+
async function validateTsConfig(resolvedPath, relConfigPath, schema) {
|
|
314
|
+
const absPath = path.join(resolvedPath, relConfigPath);
|
|
315
|
+
if (!await fileExists(absPath)) return [];
|
|
316
|
+
try {
|
|
317
|
+
const loaded = await loadConfig(absPath, schema);
|
|
318
|
+
if (loaded === null) {
|
|
319
|
+
return [{ severity: "error", file: relConfigPath, message: "Config has no default export" }];
|
|
320
|
+
}
|
|
321
|
+
return [];
|
|
322
|
+
} catch (error) {
|
|
323
|
+
return [
|
|
324
|
+
{ severity: "error", file: relConfigPath, message: formatLoadError(relConfigPath, error) }
|
|
325
|
+
];
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function formatLoadError(relConfigPath, error) {
|
|
329
|
+
const raw = getErrorMessage(error);
|
|
330
|
+
const stripped = raw.replace(/Failed to load config from '[^']+':\s*/, "");
|
|
331
|
+
return `Failed to load ${relConfigPath}: ${stripped}`;
|
|
332
|
+
}
|
|
333
|
+
function buildResult(issues, skillCount) {
|
|
334
|
+
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
335
|
+
const warningCount = issues.filter((i) => i.severity === "warning").length;
|
|
336
|
+
return { issues, skillCount, errorCount, warningCount };
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/cli/lib/content-validator.ts
|
|
340
|
+
import os from "os";
|
|
341
|
+
import path2 from "path";
|
|
342
|
+
var CWD_SOURCE_NAME = "current directory";
|
|
343
|
+
var NOTHING_VALIDATED = { count: 0, issues: [], notes: [] };
|
|
344
|
+
function mergeValidations(parts) {
|
|
345
|
+
return parts.reduce(
|
|
346
|
+
(acc, part) => ({
|
|
347
|
+
count: acc.count + part.count,
|
|
348
|
+
issues: [...acc.issues, ...part.issues],
|
|
349
|
+
notes: [...acc.notes, ...part.notes]
|
|
350
|
+
}),
|
|
351
|
+
NOTHING_VALIDATED
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
function displayDir(absolutePath) {
|
|
355
|
+
const home = os.homedir();
|
|
356
|
+
if (absolutePath === home) return "~";
|
|
357
|
+
if (absolutePath.startsWith(home + path2.sep)) {
|
|
358
|
+
return `~${path2.sep}${path2.relative(home, absolutePath)}`;
|
|
359
|
+
}
|
|
360
|
+
return absolutePath;
|
|
361
|
+
}
|
|
362
|
+
function toIssues(file, result) {
|
|
363
|
+
return [
|
|
364
|
+
...result.errors.map((message) => ({ severity: "error", file, message })),
|
|
365
|
+
...result.warnings.map((message) => ({ severity: "warning", file, message }))
|
|
366
|
+
];
|
|
367
|
+
}
|
|
368
|
+
var CONFIG_UNREADABLE = "exists but could not be loaded";
|
|
369
|
+
async function validateProjectConfigFile(projectDir) {
|
|
370
|
+
const [present, failures] = await Promise.all([
|
|
371
|
+
countExistingConfigs(projectDir),
|
|
372
|
+
findConfigLoadFailures(projectDir)
|
|
373
|
+
]);
|
|
374
|
+
return { count: present, issues: failures.map(toUnreadableConfigIssue), notes: [] };
|
|
375
|
+
}
|
|
376
|
+
function toUnreadableConfigIssue(failure) {
|
|
377
|
+
return {
|
|
378
|
+
severity: "error",
|
|
379
|
+
file: displayDir(failure.configPath),
|
|
380
|
+
message: `${CONFIG_UNREADABLE}: ${failure.reason}`
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
async function countExistingConfigs(projectDir) {
|
|
384
|
+
const present = await Promise.all(
|
|
385
|
+
configDirsInPlay(projectDir).map((dir) => fileExists(getProjectConfigPath(dir)))
|
|
386
|
+
);
|
|
387
|
+
return present.filter(Boolean).length;
|
|
388
|
+
}
|
|
389
|
+
async function validateRegisteredSources(projectDir) {
|
|
390
|
+
const primary = await resolvePrimarySourceEntry(projectDir);
|
|
391
|
+
const registered = [primary];
|
|
392
|
+
const remote = registered.filter((source) => !isLocalSource(source.url));
|
|
393
|
+
const local = await localSourcesToValidate(projectDir, registered);
|
|
394
|
+
const outcomes = await Promise.all(local.map(validateOneSource));
|
|
395
|
+
return {
|
|
396
|
+
count: local.length,
|
|
397
|
+
issues: outcomes.flatMap((outcome) => outcome.issues),
|
|
398
|
+
notes: [
|
|
399
|
+
...outcomes.map((outcome) => outcome.note),
|
|
400
|
+
...remote.map((source) => `${source.name} (${source.url}) \u2014 skipped (remote source)`)
|
|
401
|
+
]
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
async function localSourcesToValidate(projectDir, registered) {
|
|
405
|
+
const local = registered.filter((source) => isLocalSource(source.url));
|
|
406
|
+
const alreadyCovered = local.some(
|
|
407
|
+
(source) => path2.resolve(projectDir, source.url) === projectDir
|
|
408
|
+
);
|
|
409
|
+
if (alreadyCovered || !await isSourceRepo(projectDir)) return local;
|
|
410
|
+
return [...local, { name: CWD_SOURCE_NAME, url: projectDir }];
|
|
411
|
+
}
|
|
412
|
+
async function validateOneSource(source) {
|
|
413
|
+
const label = `${source.name} (${source.url})`;
|
|
414
|
+
try {
|
|
415
|
+
const result = await validateSource(source.url);
|
|
416
|
+
return { note: `${label} \u2014 ${result.skillCount} skills`, issues: result.issues };
|
|
417
|
+
} catch (error) {
|
|
418
|
+
return {
|
|
419
|
+
note: `${label} \u2014 failed`,
|
|
420
|
+
issues: [{ severity: "error", file: source.url, message: getErrorMessage(error) }]
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
async function validateInstalledPlugins(projectDir) {
|
|
425
|
+
const dirs = [
|
|
426
|
+
getUserPluginsDir(),
|
|
427
|
+
...isHomeDirectory(projectDir) ? [] : [getProjectPluginsDir(projectDir)]
|
|
428
|
+
];
|
|
429
|
+
return mergeValidations(await Promise.all(dirs.map(validatePluginsDirectory)));
|
|
430
|
+
}
|
|
431
|
+
async function validatePluginsDirectory(pluginsDir) {
|
|
432
|
+
if (!await directoryExists(pluginsDir)) return NOTHING_VALIDATED;
|
|
433
|
+
if (await fileExists(getInstalledPluginsRegistryPath(pluginsDir))) {
|
|
434
|
+
const registryValidation = await validateRegistryPlugins(pluginsDir);
|
|
435
|
+
if (registryValidation !== void 0) return registryValidation;
|
|
436
|
+
}
|
|
437
|
+
const pluginDirs = await findPluginDirectories(pluginsDir);
|
|
438
|
+
if (pluginDirs.length === 0) return NOTHING_VALIDATED;
|
|
439
|
+
const { results } = await validateAllPlugins(pluginsDir);
|
|
440
|
+
return {
|
|
441
|
+
count: results.length,
|
|
442
|
+
issues: results.flatMap(({ name, result }) => toIssues(name, result)),
|
|
443
|
+
notes: []
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
async function validateRegistryPlugins(pluginsDir) {
|
|
447
|
+
let installs;
|
|
448
|
+
try {
|
|
449
|
+
installs = await listRegisteredPluginInstalls(pluginsDir);
|
|
450
|
+
} catch (error) {
|
|
451
|
+
return {
|
|
452
|
+
count: 0,
|
|
453
|
+
issues: [
|
|
454
|
+
{
|
|
455
|
+
severity: "error",
|
|
456
|
+
file: displayDir(getInstalledPluginsRegistryPath(pluginsDir)),
|
|
457
|
+
message: getErrorMessage(error)
|
|
458
|
+
}
|
|
459
|
+
],
|
|
460
|
+
notes: []
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
if (installs.length === 0) return void 0;
|
|
464
|
+
const results = await Promise.all(
|
|
465
|
+
installs.map(
|
|
466
|
+
async ({ pluginKey, installPath }) => toIssues(pluginKey, await validatePlugin(installPath))
|
|
467
|
+
)
|
|
468
|
+
);
|
|
469
|
+
return { count: installs.length, issues: results.flat(), notes: [] };
|
|
470
|
+
}
|
|
471
|
+
async function findPluginDirectories(pluginsDir) {
|
|
472
|
+
const entries = await listDirectories(pluginsDir);
|
|
473
|
+
const checks = await Promise.all(
|
|
474
|
+
entries.map(async (name) => ({
|
|
475
|
+
name,
|
|
476
|
+
isPlugin: await directoryExists(path2.join(pluginsDir, name, PLUGIN_MANIFEST_DIR))
|
|
477
|
+
}))
|
|
478
|
+
);
|
|
479
|
+
return checks.filter((check) => check.isPlugin).map((check) => check.name);
|
|
480
|
+
}
|
|
481
|
+
async function validateInstalledSkills(projectDir) {
|
|
482
|
+
return mergeValidations(
|
|
483
|
+
await Promise.all(installedDirs(projectDir, "skillsDir").map(validateSkillsDirectory))
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
async function validateInstalledAgents(projectDir) {
|
|
487
|
+
return mergeValidations(
|
|
488
|
+
await Promise.all(installedDirs(projectDir, "agentsDir").map(validateAgentsDirectory))
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
function installedDirs(projectDir, key) {
|
|
492
|
+
const global = resolveInstallPaths(projectDir, "global")[key];
|
|
493
|
+
if (isHomeDirectory(projectDir)) return [global];
|
|
494
|
+
return [global, resolveInstallPaths(projectDir, "project")[key]];
|
|
495
|
+
}
|
|
496
|
+
async function listInstalledArtifacts(projectDir) {
|
|
497
|
+
const [skills, agents] = await Promise.all([
|
|
498
|
+
listAcrossScopes(installedDirs(projectDir, "skillsDir"), listDirectories),
|
|
499
|
+
listAcrossScopes(installedDirs(projectDir, "agentsDir"), listAgentMdFiles)
|
|
500
|
+
]);
|
|
501
|
+
return { skills, agents };
|
|
502
|
+
}
|
|
503
|
+
async function listAcrossScopes(dirs, listEntries) {
|
|
504
|
+
const perDir = await Promise.all(dirs.map((dir) => listDisplayPaths(dir, listEntries)));
|
|
505
|
+
return perDir.flat();
|
|
506
|
+
}
|
|
507
|
+
async function listDisplayPaths(dir, listEntries) {
|
|
508
|
+
if (!await directoryExists(dir)) return [];
|
|
509
|
+
const entries = await listEntries(dir);
|
|
510
|
+
return entries.map((entry) => displayDir(path2.join(dir, entry)));
|
|
511
|
+
}
|
|
512
|
+
async function validateSkillsDirectory(skillsDir) {
|
|
513
|
+
if (!await directoryExists(skillsDir)) return NOTHING_VALIDATED;
|
|
514
|
+
const skillDirs = await listDirectories(skillsDir);
|
|
515
|
+
if (skillDirs.length === 0) return NOTHING_VALIDATED;
|
|
516
|
+
const results = await Promise.all(
|
|
517
|
+
skillDirs.map(async (name) => {
|
|
518
|
+
const skillDir = path2.join(skillsDir, name);
|
|
519
|
+
return toIssues(displayDir(skillDir), await validateInstalledSkill(skillDir));
|
|
520
|
+
})
|
|
521
|
+
);
|
|
522
|
+
return { count: skillDirs.length, issues: results.flat(), notes: [] };
|
|
523
|
+
}
|
|
524
|
+
async function validateAgentsDirectory(agentsDir) {
|
|
525
|
+
if (!await directoryExists(agentsDir)) return NOTHING_VALIDATED;
|
|
526
|
+
const agentFiles = await listAgentMdFiles(agentsDir);
|
|
527
|
+
if (agentFiles.length === 0) return NOTHING_VALIDATED;
|
|
528
|
+
const results = await Promise.all(
|
|
529
|
+
agentFiles.map(async (fileName) => {
|
|
530
|
+
const agentPath = path2.join(agentsDir, fileName);
|
|
531
|
+
return toIssues(displayDir(agentPath), await validateAgentFrontmatter(agentPath));
|
|
532
|
+
})
|
|
533
|
+
);
|
|
534
|
+
return { count: agentFiles.length, issues: results.flat(), notes: [] };
|
|
535
|
+
}
|
|
536
|
+
async function validateInstalledSkill(skillDir) {
|
|
537
|
+
const skillMdPath = path2.join(skillDir, STANDARD_FILES.SKILL_MD);
|
|
538
|
+
const metadataPath = path2.join(skillDir, STANDARD_FILES.METADATA_YAML);
|
|
539
|
+
const errors = [];
|
|
540
|
+
const warnings = [];
|
|
541
|
+
if (!await fileExists(skillMdPath)) {
|
|
542
|
+
errors.push(`Missing ${STANDARD_FILES.SKILL_MD}`);
|
|
543
|
+
} else {
|
|
544
|
+
const frontmatterResult = await validateSkillFrontmatter(skillMdPath);
|
|
545
|
+
errors.push(...frontmatterResult.errors);
|
|
546
|
+
warnings.push(...frontmatterResult.warnings);
|
|
547
|
+
}
|
|
548
|
+
if (!await fileExists(metadataPath)) {
|
|
549
|
+
errors.push(`Missing ${STANDARD_FILES.METADATA_YAML}`);
|
|
550
|
+
} else {
|
|
551
|
+
const metadataResult = await validateInstalledSkillMetadata(metadataPath);
|
|
552
|
+
errors.push(...metadataResult.errors);
|
|
553
|
+
warnings.push(...metadataResult.warnings);
|
|
554
|
+
}
|
|
555
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
556
|
+
}
|
|
557
|
+
async function validateInstalledSkillMetadata(metadataPath) {
|
|
558
|
+
const read = await readSkillMetadata(metadataPath);
|
|
559
|
+
if (!read.usable) {
|
|
560
|
+
return {
|
|
561
|
+
valid: false,
|
|
562
|
+
errors: [`${STANDARD_FILES.METADATA_YAML}: ${read.reason}`],
|
|
563
|
+
warnings: []
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
const metadata = read.metadata;
|
|
567
|
+
const result = validateSkillMetadata(metadata);
|
|
568
|
+
if (result.success) {
|
|
569
|
+
return { valid: true, errors: [], warnings: [] };
|
|
570
|
+
}
|
|
571
|
+
const { errors, warnings } = splitMetadataValidationIssues(result.error, metadata);
|
|
572
|
+
return {
|
|
573
|
+
valid: errors.length === 0,
|
|
574
|
+
errors: errors.map((e) => `${STANDARD_FILES.METADATA_YAML}: ${e}`),
|
|
575
|
+
warnings: warnings.map((w) => `${STANDARD_FILES.METADATA_YAML}: ${w}`)
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// src/cli/commands/doctor.ts
|
|
53
580
|
import { countBy, unique } from "remeda";
|
|
54
581
|
var CONFIG_TS_REL = `${CLAUDE_SRC_DIR}/${STANDARD_FILES.CONFIG_TS}`;
|
|
55
|
-
function
|
|
56
|
-
if (
|
|
582
|
+
async function resolveConfigState(detected, projectDir) {
|
|
583
|
+
if (detected?.config) return { kind: "loaded", config: detected.config };
|
|
584
|
+
const loaded = await loadProjectConfigFromDir(projectDir);
|
|
585
|
+
if (!loaded) return { kind: "absent" };
|
|
586
|
+
return declaresNoContent(loaded.config) ? { kind: "declares-nothing", config: loaded.config } : { kind: "loaded", config: loaded.config };
|
|
587
|
+
}
|
|
588
|
+
function checkConfigValid(state) {
|
|
589
|
+
if (state.kind === "absent") {
|
|
57
590
|
return {
|
|
58
591
|
result: {
|
|
59
592
|
kind: "config",
|
|
@@ -64,6 +597,17 @@ function checkConfigValid(config) {
|
|
|
64
597
|
config: null
|
|
65
598
|
};
|
|
66
599
|
}
|
|
600
|
+
if (state.kind === "declares-nothing") {
|
|
601
|
+
return {
|
|
602
|
+
result: {
|
|
603
|
+
kind: "config-empty",
|
|
604
|
+
status: "warn",
|
|
605
|
+
message: `${CONFIG_TS_REL} is valid but declares no skills and no agents`
|
|
606
|
+
},
|
|
607
|
+
config: state.config
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
const { config } = state;
|
|
67
611
|
const validation = validateProjectConfig(config);
|
|
68
612
|
if (!validation.valid) {
|
|
69
613
|
return {
|
|
@@ -111,20 +655,15 @@ async function checkSkillsResolved(config, matrix2, projectDir) {
|
|
|
111
655
|
}
|
|
112
656
|
const [localResult, globalResult] = await Promise.all([
|
|
113
657
|
discoverLocalSkills(projectDir),
|
|
114
|
-
!isHomeDirectory(projectDir) ? discoverLocalSkills(
|
|
658
|
+
!isHomeDirectory(projectDir) ? discoverLocalSkills(os2.homedir()) : null
|
|
115
659
|
]);
|
|
116
660
|
const localSkillIds = /* @__PURE__ */ new Set([
|
|
117
661
|
...localResult?.skills.map((s) => s.id) ?? [],
|
|
118
662
|
...globalResult?.skills.map((s) => s.id) ?? []
|
|
119
663
|
]);
|
|
120
|
-
const missingSkills =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const inLocal = localSkillIds.has(skillId);
|
|
124
|
-
if (!inMatrix && !inLocal) {
|
|
125
|
-
missingSkills.push(skillId);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
664
|
+
const missingSkills = uniqueSkills.filter(
|
|
665
|
+
(skillId) => !(skillId in matrix2.skills) && !localSkillIds.has(skillId)
|
|
666
|
+
);
|
|
128
667
|
if (missingSkills.length > 0) {
|
|
129
668
|
return {
|
|
130
669
|
kind: "skills",
|
|
@@ -140,7 +679,7 @@ async function checkSkillsResolved(config, matrix2, projectDir) {
|
|
|
140
679
|
};
|
|
141
680
|
}
|
|
142
681
|
async function checkAgentsCompiled(config, projectDir) {
|
|
143
|
-
const agents = config.agents
|
|
682
|
+
const agents = config.agents;
|
|
144
683
|
if (agents.length === 0) {
|
|
145
684
|
return {
|
|
146
685
|
kind: "agents",
|
|
@@ -153,7 +692,7 @@ async function checkAgentsCompiled(config, projectDir) {
|
|
|
153
692
|
const agentChecks = await Promise.all(
|
|
154
693
|
agents.map(async (agent) => {
|
|
155
694
|
const agentsDir = agent.scope === "global" ? globalAgentsDir : projectAgentsDir;
|
|
156
|
-
const agentPath =
|
|
695
|
+
const agentPath = path3.join(agentsDir, `${agent.name}.md`);
|
|
157
696
|
return { name: agent.name, compiled: await fileExists(agentPath) };
|
|
158
697
|
})
|
|
159
698
|
);
|
|
@@ -190,30 +729,21 @@ async function checkNoOrphans(config, projectDir) {
|
|
|
190
729
|
const projectMdFiles = projectExists ? await listAgentMdFiles(projectAgentsDir) : [];
|
|
191
730
|
const globalMdFiles = globalExists ? await listAgentMdFiles(globalAgentsDir) : [];
|
|
192
731
|
const activeProjectAgents = new Set(
|
|
193
|
-
|
|
732
|
+
config.agents.filter((a) => a.scope === "project" && !a.excluded).map((a) => a.name)
|
|
194
733
|
);
|
|
195
734
|
const knownGlobalAgents = new Set(
|
|
196
|
-
|
|
735
|
+
config.agents.filter((a) => a.scope === "global").map((a) => a.name)
|
|
197
736
|
);
|
|
198
737
|
const knownProjectDirAgents = scopesShareAgentsDir ? /* @__PURE__ */ new Set([...activeProjectAgents, ...knownGlobalAgents]) : activeProjectAgents;
|
|
199
|
-
const orphanedFiles = [
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
orphanedFiles.push(agentName);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
for (const file of globalMdFiles) {
|
|
207
|
-
const agentName = file.replace(/\.md$/, "");
|
|
208
|
-
if (!knownGlobalAgents.has(agentName)) {
|
|
209
|
-
orphanedFiles.push(agentName);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
738
|
+
const orphanedFiles = [
|
|
739
|
+
...orphanedAgentNames(projectMdFiles, knownProjectDirAgents),
|
|
740
|
+
...orphanedAgentNames(globalMdFiles, knownGlobalAgents)
|
|
741
|
+
];
|
|
212
742
|
if (orphanedFiles.length > 0) {
|
|
213
743
|
return {
|
|
214
744
|
kind: "orphans",
|
|
215
745
|
status: "warn",
|
|
216
|
-
message:
|
|
746
|
+
message: plural(orphanedFiles.length, "orphaned agent file"),
|
|
217
747
|
details: orphanedFiles.map((f) => `- ${f}.md (not in config)`)
|
|
218
748
|
};
|
|
219
749
|
}
|
|
@@ -223,8 +753,29 @@ async function checkNoOrphans(config, projectDir) {
|
|
|
223
753
|
message: "No orphaned agent files"
|
|
224
754
|
};
|
|
225
755
|
}
|
|
756
|
+
function orphanedAgentNames(mdFiles, knownAgents) {
|
|
757
|
+
return mdFiles.map((fileName) => fileName.replace(/\.md$/, "")).filter((agentName) => !knownAgents.has(agentName));
|
|
758
|
+
}
|
|
759
|
+
async function checkUnownedInstallation(projectDir) {
|
|
760
|
+
const { skills, agents } = await listInstalledArtifacts(projectDir);
|
|
761
|
+
if (skills.length === 0 && agents.length === 0) return skippedResult("orphans");
|
|
762
|
+
return {
|
|
763
|
+
kind: "orphans-unowned",
|
|
764
|
+
status: "fail",
|
|
765
|
+
// The per-line "(not in config)" the other verdict repeats is said once here instead:
|
|
766
|
+
// with no configuration it is true of every line, and there are as many lines as files.
|
|
767
|
+
message: `${countedArtifacts(skills, agents)} installed here, and no configuration declares them`,
|
|
768
|
+
details: [...skills, ...agents].map((artifact) => `- ${artifact}`)
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
function countedArtifacts(skills, agents) {
|
|
772
|
+
return [
|
|
773
|
+
...skills.length > 0 ? [plural(skills.length, "skill")] : [],
|
|
774
|
+
...agents.length > 0 ? [plural(agents.length, "agent")] : []
|
|
775
|
+
].join(" and ");
|
|
776
|
+
}
|
|
226
777
|
async function checkSkillsInstalled(config, projectDir) {
|
|
227
|
-
const skills = config.skills
|
|
778
|
+
const skills = config.skills;
|
|
228
779
|
const ejectSkills = skills.filter((s) => s.source === EJECT_SOURCE);
|
|
229
780
|
if (ejectSkills.length === 0) {
|
|
230
781
|
return {
|
|
@@ -236,7 +787,7 @@ async function checkSkillsInstalled(config, projectDir) {
|
|
|
236
787
|
const skillChecks = await Promise.all(
|
|
237
788
|
ejectSkills.map(async (skill) => {
|
|
238
789
|
const baseDir = installBaseDir(projectDir, skill.scope);
|
|
239
|
-
const skillMdPath =
|
|
790
|
+
const skillMdPath = path3.join(baseDir, LOCAL_SKILLS_PATH, skill.id, STANDARD_FILES.SKILL_MD);
|
|
240
791
|
return { id: skill.id, installed: await fileExists(skillMdPath) };
|
|
241
792
|
})
|
|
242
793
|
);
|
|
@@ -245,7 +796,7 @@ async function checkSkillsInstalled(config, projectDir) {
|
|
|
245
796
|
return {
|
|
246
797
|
kind: "installed",
|
|
247
798
|
status: "warn",
|
|
248
|
-
message: `${missingSkills.length
|
|
799
|
+
message: `${plural(missingSkills.length, "skill")} missing from disk`,
|
|
249
800
|
details: missingSkills.map((s) => `- ${s} (not found in ${LOCAL_SKILLS_PATH}/)`)
|
|
250
801
|
};
|
|
251
802
|
}
|
|
@@ -280,7 +831,7 @@ async function checkPluginSkillsInstalled(config, projectDir) {
|
|
|
280
831
|
return {
|
|
281
832
|
kind: "plugins",
|
|
282
833
|
status: "warn",
|
|
283
|
-
message: `${missingSkills.length
|
|
834
|
+
message: `${plural(missingSkills.length, "skill")} not installed as plugins`,
|
|
284
835
|
details: missingSkills.map((s) => `- ${s} (no enabled plugin found)`)
|
|
285
836
|
};
|
|
286
837
|
}
|
|
@@ -313,7 +864,82 @@ async function checkSourceReachable(projectDir) {
|
|
|
313
864
|
};
|
|
314
865
|
}
|
|
315
866
|
}
|
|
867
|
+
var CONFIG_CHECK = {
|
|
868
|
+
kind: "content-config",
|
|
869
|
+
name: "Config",
|
|
870
|
+
noun: "config",
|
|
871
|
+
run: validateProjectConfigFile
|
|
872
|
+
};
|
|
873
|
+
var CONTENT_CHECKS = [
|
|
874
|
+
{
|
|
875
|
+
kind: "content-sources",
|
|
876
|
+
name: "Sources",
|
|
877
|
+
noun: "source",
|
|
878
|
+
// The registered sources are the ones config.ts names.
|
|
879
|
+
readsConfig: true,
|
|
880
|
+
run: validateRegisteredSources
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
kind: "content-plugins",
|
|
884
|
+
name: "Plugins",
|
|
885
|
+
noun: "plugin",
|
|
886
|
+
readsConfig: false,
|
|
887
|
+
run: validateInstalledPlugins
|
|
888
|
+
},
|
|
889
|
+
{
|
|
890
|
+
kind: "content-skills",
|
|
891
|
+
name: "Skills",
|
|
892
|
+
noun: "skill",
|
|
893
|
+
readsConfig: false,
|
|
894
|
+
run: validateInstalledSkills
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
kind: "content-agents",
|
|
898
|
+
name: "Agents",
|
|
899
|
+
noun: "agent",
|
|
900
|
+
readsConfig: false,
|
|
901
|
+
run: validateInstalledAgents
|
|
902
|
+
}
|
|
903
|
+
];
|
|
904
|
+
function contentStatus(errors, warnings) {
|
|
905
|
+
if (errors > 0) return "fail";
|
|
906
|
+
if (warnings > 0) return "warn";
|
|
907
|
+
return "pass";
|
|
908
|
+
}
|
|
909
|
+
function contentMessage(noun, count, errors, warnings) {
|
|
910
|
+
if (errors === 0 && warnings === 0) {
|
|
911
|
+
return count === 0 ? `No ${noun}s to validate` : `${plural(count, noun)} validated`;
|
|
912
|
+
}
|
|
913
|
+
return `${plural(count, noun)}: ${plural(errors, "error")}, ${plural(warnings, "warning")}`;
|
|
914
|
+
}
|
|
915
|
+
function formatContentIssue(issue) {
|
|
916
|
+
const marker = issue.severity === "error" ? "ERROR" : "WARN";
|
|
917
|
+
return `- [${marker}] ${issue.file}: ${issue.message}`;
|
|
918
|
+
}
|
|
919
|
+
function toContentResult(check, validation) {
|
|
920
|
+
const errors = validation.issues.filter((issue) => issue.severity === "error").length;
|
|
921
|
+
const warnings = validation.issues.length - errors;
|
|
922
|
+
return {
|
|
923
|
+
kind: check.kind,
|
|
924
|
+
status: contentStatus(errors, warnings),
|
|
925
|
+
message: contentMessage(check.noun, validation.count, errors, warnings),
|
|
926
|
+
details: [
|
|
927
|
+
...validation.notes.map((note) => `- ${note}`),
|
|
928
|
+
...validation.issues.map(formatContentIssue)
|
|
929
|
+
]
|
|
930
|
+
};
|
|
931
|
+
}
|
|
316
932
|
var CHECK_WIDTH = 20;
|
|
933
|
+
var SECTION_INDENT = " ";
|
|
934
|
+
var ROW_INDENT = " ";
|
|
935
|
+
var SECTION_CONTENT = "Content checks";
|
|
936
|
+
var SECTION_OPERATIONAL = "Operational checks";
|
|
937
|
+
var SKIP_AFTER_CONTENT_ERRORS = "Skipped \u2014 fix the content errors above first";
|
|
938
|
+
var SKIP_NO_INSTALLATION = "Skipped \u2014 no installation here (skills source repository)";
|
|
939
|
+
var SKIP_CONFIG_UNREADABLE = "Skipped \u2014 the configuration that names them cannot be read";
|
|
940
|
+
function plural(count, word) {
|
|
941
|
+
return `${count} ${word}${count === 1 ? "" : "s"}`;
|
|
942
|
+
}
|
|
317
943
|
function formatCheckName(name) {
|
|
318
944
|
return name.padEnd(CHECK_WIDTH);
|
|
319
945
|
}
|
|
@@ -334,21 +960,20 @@ function formatStatus(status) {
|
|
|
334
960
|
}
|
|
335
961
|
}
|
|
336
962
|
function formatCheckLine(name, result) {
|
|
337
|
-
const headerLine =
|
|
963
|
+
const headerLine = `${ROW_INDENT}${formatCheckName(name)}${formatStatus(result.status)} ${result.message}`;
|
|
338
964
|
const detailLines = (result.details ?? []).map(
|
|
339
|
-
(detail) =>
|
|
965
|
+
(detail) => `${ROW_INDENT}${" ".repeat(CHECK_WIDTH)} ${detail}`
|
|
340
966
|
);
|
|
341
967
|
return [headerLine, ...detailLines];
|
|
342
968
|
}
|
|
343
969
|
function formatSummary(results) {
|
|
344
970
|
const counts = countBy(results, (r) => r.status);
|
|
345
|
-
const plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
346
971
|
const parts = [
|
|
347
972
|
`${counts.pass ?? 0} passed`,
|
|
348
973
|
plural(counts.warn ?? 0, "warning"),
|
|
349
974
|
plural(counts.fail ?? 0, "error")
|
|
350
975
|
];
|
|
351
|
-
return
|
|
976
|
+
return `${SECTION_INDENT}Summary: ${parts.join(", ")}`;
|
|
352
977
|
}
|
|
353
978
|
var TIPS = [
|
|
354
979
|
{
|
|
@@ -361,6 +986,31 @@ var TIPS = [
|
|
|
361
986
|
status: "fail",
|
|
362
987
|
tip: ` Tip: Run '${CLI_INVOKE_COMMAND} init' to create or fix configuration`
|
|
363
988
|
},
|
|
989
|
+
{
|
|
990
|
+
// The remedy for a valid config with nothing in it. Not the tip above: there is nothing to
|
|
991
|
+
// create and nothing to fix. `init` on this config opens the wizard rather than the dashboard
|
|
992
|
+
// — that is what the detection returning null is FOR — so it is the way to fill it in.
|
|
993
|
+
kind: "config-empty",
|
|
994
|
+
status: "warn",
|
|
995
|
+
tip: ` Tip: Nothing is configured yet \u2014 run '${CLI_INVOKE_COMMAND} init' to choose skills and sub-agents`
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
// The one remedy that applies to a config that cannot be read. `init` does not clear such a
|
|
999
|
+
// file — it refuses it — so the tip above would send the reader in a circle; this is the same
|
|
1000
|
+
// way out `edit` and `init` themselves name, worded the same way.
|
|
1001
|
+
kind: "content-config",
|
|
1002
|
+
status: "fail",
|
|
1003
|
+
tip: ` Tip: There is no automatic repair \u2014 recreate the configuration: '${CLI_INVOKE_COMMAND} uninstall' still works on a config it cannot read, then '${CLI_INVOKE_COMMAND} init'`
|
|
1004
|
+
},
|
|
1005
|
+
{
|
|
1006
|
+
// Printed beside the config tip above, which says how to get a configuration back and
|
|
1007
|
+
// nothing about the files that outlived the old one. Both halves are named with what they
|
|
1008
|
+
// actually do: `uninstall` matches skill directories by their own `forked-from` metadata,
|
|
1009
|
+
// so it clears them without a config — and identifies compiled agents only through one.
|
|
1010
|
+
kind: "orphans-unowned",
|
|
1011
|
+
status: "fail",
|
|
1012
|
+
tip: ` Tip: Nothing declares the files above \u2014 '${CLI_INVOKE_COMMAND} init' writes a configuration that can own them again, or '${CLI_INVOKE_COMMAND} uninstall' removes the installed skills (the compiled agents outlive it: identifying them needs the configuration that is gone)`
|
|
1013
|
+
},
|
|
364
1014
|
{
|
|
365
1015
|
kind: "skills",
|
|
366
1016
|
status: "fail",
|
|
@@ -383,6 +1033,15 @@ function formatTips(results) {
|
|
|
383
1033
|
function skippedResult(kind) {
|
|
384
1034
|
return { kind, status: "skip", message: "Skipped (config invalid)" };
|
|
385
1035
|
}
|
|
1036
|
+
function sourceUnreachableSkillsResult() {
|
|
1037
|
+
return { kind: "skills", status: "skip", message: "Skipped (source unreachable)" };
|
|
1038
|
+
}
|
|
1039
|
+
function skippedContentResult(kind) {
|
|
1040
|
+
return { kind, status: "skip", message: SKIP_CONFIG_UNREADABLE };
|
|
1041
|
+
}
|
|
1042
|
+
function runContentCheck(check, projectDir) {
|
|
1043
|
+
return safeCheck(check.kind, async () => toContentResult(check, await check.run(projectDir)));
|
|
1044
|
+
}
|
|
386
1045
|
async function safeCheck(kind, fn) {
|
|
387
1046
|
try {
|
|
388
1047
|
return await fn();
|
|
@@ -394,15 +1053,15 @@ var Doctor = class _Doctor extends BaseCommand {
|
|
|
394
1053
|
static summary = "Diagnose common configuration issues";
|
|
395
1054
|
static description = `Run diagnostic checks on your ${DEFAULT_BRANDING.NAME} configuration to identify issues with config validity, skill resolution, agent compilation, and source connectivity.`;
|
|
396
1055
|
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
397
|
-
// Override parent baseFlags to drop --source (not relevant for diagnostics)
|
|
398
|
-
static baseFlags = {};
|
|
399
1056
|
static flags = {};
|
|
400
1057
|
async run() {
|
|
401
1058
|
await this.parse(_Doctor);
|
|
402
1059
|
setVerbose(true);
|
|
403
1060
|
const projectDir = process.cwd();
|
|
404
1061
|
this.printHeader();
|
|
405
|
-
const
|
|
1062
|
+
const contentResults = await this.runContentChecks(projectDir);
|
|
1063
|
+
const operationalResults = await this.runOperationalChecks(projectDir, contentResults);
|
|
1064
|
+
const results = [...contentResults, ...operationalResults];
|
|
406
1065
|
this.printResults(results);
|
|
407
1066
|
if (results.some((r) => r.status === "fail")) {
|
|
408
1067
|
this.exit(EXIT_CODES.ERROR);
|
|
@@ -412,24 +1071,70 @@ var Doctor = class _Doctor extends BaseCommand {
|
|
|
412
1071
|
this.log("");
|
|
413
1072
|
this.log(`${DEFAULT_BRANDING.NAME} Doctor`);
|
|
414
1073
|
this.log("");
|
|
415
|
-
this.log(
|
|
1074
|
+
this.log(`${SECTION_INDENT}Checking configuration health...`);
|
|
416
1075
|
this.log("");
|
|
417
1076
|
}
|
|
418
|
-
|
|
1077
|
+
/**
|
|
1078
|
+
* The config is checked first and alone. A check that reads it to know what to validate would
|
|
1079
|
+
* otherwise ask a file already reported as unreadable — and asking is what emitted the loader's
|
|
1080
|
+
* own failure line once per read, spliced between these rows. Everything that walks installed
|
|
1081
|
+
* content on disk still runs: it says something true whatever the config is in.
|
|
1082
|
+
*/
|
|
1083
|
+
async runContentChecks(projectDir) {
|
|
1084
|
+
this.log(`${SECTION_INDENT}${SECTION_CONTENT}`);
|
|
1085
|
+
const configResult = await runContentCheck(CONFIG_CHECK, projectDir);
|
|
1086
|
+
const configUnreadable = configResult.status === "fail";
|
|
1087
|
+
const rows = await Promise.all(
|
|
1088
|
+
CONTENT_CHECKS.map(async (check) => ({
|
|
1089
|
+
name: check.name,
|
|
1090
|
+
result: check.readsConfig && configUnreadable ? skippedContentResult(check.kind) : await runContentCheck(check, projectDir)
|
|
1091
|
+
}))
|
|
1092
|
+
);
|
|
1093
|
+
const allRows = [{ name: CONFIG_CHECK.name, result: configResult }, ...rows];
|
|
1094
|
+
for (const row of allRows) {
|
|
1095
|
+
this.logCheck(row.name, row.result);
|
|
1096
|
+
}
|
|
1097
|
+
return allRows.map((row) => row.result);
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* The operational layer runs only when it can say something the reader can act on:
|
|
1101
|
+
* not after content errors (its findings would be their cascades), and not in a
|
|
1102
|
+
* source repository with nothing installed (a marketplace author has no install
|
|
1103
|
+
* for it to describe).
|
|
1104
|
+
*/
|
|
1105
|
+
async runOperationalChecks(projectDir, contentResults) {
|
|
1106
|
+
this.log("");
|
|
1107
|
+
this.log(`${SECTION_INDENT}${SECTION_OPERATIONAL}`);
|
|
1108
|
+
if (contentResults.some((r) => r.status === "fail")) {
|
|
1109
|
+
this.log(`${ROW_INDENT}${SKIP_AFTER_CONTENT_ERRORS}`);
|
|
1110
|
+
return [];
|
|
1111
|
+
}
|
|
419
1112
|
const detected = await detectProject(projectDir);
|
|
420
|
-
|
|
1113
|
+
if (!detected && await this.isUninstalledSourceRepo(projectDir)) {
|
|
1114
|
+
this.log(`${ROW_INDENT}${SKIP_NO_INSTALLATION}`);
|
|
1115
|
+
return [];
|
|
1116
|
+
}
|
|
1117
|
+
return this.runAllChecks(projectDir, await resolveConfigState(detected, projectDir));
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* A config file that exists but failed to load also detects as "no project", and
|
|
1121
|
+
* that is a finding rather than an absence — so the skip requires no config file
|
|
1122
|
+
* at all, not merely no usable one.
|
|
1123
|
+
*/
|
|
1124
|
+
async isUninstalledSourceRepo(projectDir) {
|
|
1125
|
+
if (await fileExists(getProjectConfigPath(projectDir))) return false;
|
|
1126
|
+
return isSourceRepo(projectDir);
|
|
1127
|
+
}
|
|
1128
|
+
async runAllChecks(projectDir, configState) {
|
|
1129
|
+
const { result: configResult, config } = checkConfigValid(configState);
|
|
421
1130
|
this.logCheck("Config Valid", configResult);
|
|
422
1131
|
const sourceResult = await safeCheck("source", () => checkSourceReachable(projectDir));
|
|
423
1132
|
const filteredConfig = config ? filterExcludedEntries(config) : null;
|
|
424
|
-
const skillsResult =
|
|
425
|
-
kind: "skills",
|
|
426
|
-
status: "skip",
|
|
427
|
-
message: "Skipped (source unreachable)"
|
|
428
|
-
} : await safeCheck("skills", () => checkSkillsResolved(config, matrix, projectDir));
|
|
1133
|
+
const skillsResult = await this.resolveSkillsCheck(config, sourceResult, projectDir);
|
|
429
1134
|
this.logCheck("Skills Resolved", skillsResult);
|
|
430
1135
|
const agentsResult = filteredConfig ? await safeCheck("agents", () => checkAgentsCompiled(filteredConfig, projectDir)) : skippedResult("agents");
|
|
431
1136
|
this.logCheck("Agents Compiled", agentsResult);
|
|
432
|
-
const orphansResult =
|
|
1137
|
+
const orphansResult = await this.resolveOrphansCheck(config, configState, projectDir);
|
|
433
1138
|
this.logCheck("No Orphans", orphansResult);
|
|
434
1139
|
const installedResult = filteredConfig ? await safeCheck("installed", () => checkSkillsInstalled(filteredConfig, projectDir)) : skippedResult("installed");
|
|
435
1140
|
this.logCheck("Skills Installed", installedResult);
|
|
@@ -446,6 +1151,30 @@ var Doctor = class _Doctor extends BaseCommand {
|
|
|
446
1151
|
sourceResult
|
|
447
1152
|
];
|
|
448
1153
|
}
|
|
1154
|
+
/**
|
|
1155
|
+
* The orphan row, and which question it can answer. With a config it names the compiled
|
|
1156
|
+
* agents that config does not; with no config at all every installed file is unowned and it
|
|
1157
|
+
* names all of them. It skips for the one state left — a config that loads and fails
|
|
1158
|
+
* validation — because there the file that says who owns what has already been rejected, and
|
|
1159
|
+
* an installation must not be called stranded on the strength of one nobody can trust.
|
|
1160
|
+
*/
|
|
1161
|
+
async resolveOrphansCheck(config, configState, projectDir) {
|
|
1162
|
+
if (config) return safeCheck("orphans", () => checkNoOrphans(config, projectDir));
|
|
1163
|
+
if (configState.kind === "absent") {
|
|
1164
|
+
return safeCheck("orphans", () => checkUnownedInstallation(projectDir));
|
|
1165
|
+
}
|
|
1166
|
+
return skippedResult("orphans");
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* The skills row, and the two states in which it cannot be computed: no config to read the
|
|
1170
|
+
* skills out of, and a source that never loaded — so there is no populated matrix to resolve
|
|
1171
|
+
* them against, and every configured skill would be reported "not found".
|
|
1172
|
+
*/
|
|
1173
|
+
async resolveSkillsCheck(config, sourceResult, projectDir) {
|
|
1174
|
+
if (!config) return skippedResult("skills");
|
|
1175
|
+
if (sourceResult.status === "fail") return sourceUnreachableSkillsResult();
|
|
1176
|
+
return safeCheck("skills", () => checkSkillsResolved(config, matrix, projectDir));
|
|
1177
|
+
}
|
|
449
1178
|
logCheck(name, result) {
|
|
450
1179
|
for (const line of formatCheckLine(name, result)) {
|
|
451
1180
|
this.log(line);
|