agents-inc 0.156.0 → 0.157.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.
Files changed (173) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/{chunk-PMUABBPG.js → chunk-24IGOJ7E.js} +9 -13
  3. package/dist/chunk-24IGOJ7E.js.map +1 -0
  4. package/dist/{chunk-H6UTKTLK.js → chunk-3E52LCYC.js} +98 -34
  5. package/dist/chunk-3E52LCYC.js.map +1 -0
  6. package/dist/{chunk-UMH2YZKG.js → chunk-4CIAZOTD.js} +4 -6
  7. package/dist/{chunk-UMH2YZKG.js.map → chunk-4CIAZOTD.js.map} +1 -1
  8. package/dist/{chunk-D2CAV7MG.js → chunk-4DMFK67G.js} +2 -2
  9. package/dist/{chunk-PNMM5HNX.js → chunk-4EPJWN7C.js} +9 -10
  10. package/dist/chunk-4EPJWN7C.js.map +1 -0
  11. package/dist/{chunk-MHRC3KRX.js → chunk-4KHUHPX4.js} +3 -3
  12. package/dist/chunk-4KHUHPX4.js.map +1 -0
  13. package/dist/{chunk-2H7UWE2G.js → chunk-CEGHC7L5.js} +13 -12
  14. package/dist/chunk-CEGHC7L5.js.map +1 -0
  15. package/dist/{chunk-MO5FGLVS.js → chunk-DCIC35R7.js} +11 -12
  16. package/dist/chunk-DCIC35R7.js.map +1 -0
  17. package/dist/{chunk-ILUVL7WM.js → chunk-DZD25NHW.js} +2 -2
  18. package/dist/{chunk-IO5YBKHV.js → chunk-G6G2FT2G.js} +10 -8
  19. package/dist/chunk-G6G2FT2G.js.map +1 -0
  20. package/dist/{chunk-RWOYPOMR.js → chunk-IGOFZG3S.js} +19 -5
  21. package/dist/chunk-IGOFZG3S.js.map +1 -0
  22. package/dist/{chunk-CLFHC2DK.js → chunk-K2VTGT45.js} +17 -18
  23. package/dist/chunk-K2VTGT45.js.map +1 -0
  24. package/dist/{chunk-YO2LTXB4.js → chunk-KTXVQ7OM.js} +115 -10
  25. package/dist/chunk-KTXVQ7OM.js.map +1 -0
  26. package/dist/{chunk-SY4X2LND.js → chunk-KUZBMEWR.js} +3 -3
  27. package/dist/{chunk-ZUAZHDKP.js → chunk-LDBVIPTP.js} +277 -40
  28. package/dist/chunk-LDBVIPTP.js.map +1 -0
  29. package/dist/{chunk-PCC4LBKB.js → chunk-MU2TQ5KK.js} +2 -2
  30. package/dist/{chunk-4G2YHZIM.js → chunk-O4K42CJB.js} +4 -6
  31. package/dist/{chunk-4G2YHZIM.js.map → chunk-O4K42CJB.js.map} +1 -1
  32. package/dist/{chunk-HXKOIWLU.js → chunk-P6OKOH62.js} +2 -6
  33. package/dist/chunk-P6OKOH62.js.map +1 -0
  34. package/dist/{chunk-IXRZAHZF.js → chunk-PGZSNNDA.js} +4 -4
  35. package/dist/{chunk-LJCNUP6M.js → chunk-PVPNVK3W.js} +2 -2
  36. package/dist/{chunk-4A4L3YIW.js → chunk-PXGDA2SY.js} +6 -7
  37. package/dist/chunk-PXGDA2SY.js.map +1 -0
  38. package/dist/{chunk-G47TDUK3.js → chunk-QNAMXQKF.js} +2 -2
  39. package/dist/{chunk-5OKLCVM4.js → chunk-QO4XD5V5.js} +3 -3
  40. package/dist/{chunk-5F2YR5XV.js → chunk-QXPMQBEI.js} +15 -5
  41. package/dist/chunk-QXPMQBEI.js.map +1 -0
  42. package/dist/{chunk-F5T6TV4Z.js → chunk-RLU2IXD3.js} +40 -14
  43. package/dist/chunk-RLU2IXD3.js.map +1 -0
  44. package/dist/{chunk-WCAUUBHO.js → chunk-RVXI5VQU.js} +14758 -14501
  45. package/dist/chunk-RVXI5VQU.js.map +1 -0
  46. package/dist/{chunk-WFRTHH3A.js → chunk-TZRXWFF5.js} +3 -3
  47. package/dist/{chunk-HG4JPXJT.js → chunk-V7PMQDDU.js} +23 -10
  48. package/dist/chunk-V7PMQDDU.js.map +1 -0
  49. package/dist/{chunk-Y5Y7XHVU.js → chunk-VI6U2PJG.js} +4 -4
  50. package/dist/{chunk-TBOVYLQJ.js → chunk-VTIDLRNA.js} +2 -2
  51. package/dist/{chunk-OKH64JZE.js → chunk-WCZNQECQ.js} +2 -2
  52. package/dist/{chunk-QWVXOCXO.js → chunk-WENBESZO.js} +7 -9
  53. package/dist/{chunk-QWVXOCXO.js.map → chunk-WENBESZO.js.map} +1 -1
  54. package/dist/{chunk-TNGMF4UX.js → chunk-XOZAKFTS.js} +12 -12
  55. package/dist/chunk-XOZAKFTS.js.map +1 -0
  56. package/dist/{chunk-6RLV45HN.js → chunk-YG5YPVTJ.js} +6 -6
  57. package/dist/chunk-YG5YPVTJ.js.map +1 -0
  58. package/dist/{chunk-HTYH7CKN.js → chunk-YKFCUVHG.js} +3 -3
  59. package/dist/{chunk-VPASBA7P.js → chunk-YXI3BTQQ.js} +2 -2
  60. package/dist/chunk-Z3H2K5PK.js +1352 -0
  61. package/dist/chunk-Z3H2K5PK.js.map +1 -0
  62. package/dist/{chunk-5QZAK6J7.js → chunk-ZAQ6WMJV.js} +50 -18
  63. package/dist/chunk-ZAQ6WMJV.js.map +1 -0
  64. package/dist/{chunk-GS2NZ3GD.js → chunk-ZBYVDXZG.js} +5 -5
  65. package/dist/chunk-ZBYVDXZG.js.map +1 -0
  66. package/dist/commands/build/marketplace.js +9 -12
  67. package/dist/commands/build/marketplace.js.map +1 -1
  68. package/dist/commands/build/plugins.js +9 -12
  69. package/dist/commands/build/plugins.js.map +1 -1
  70. package/dist/commands/compile.js +15 -19
  71. package/dist/commands/compile.js.map +1 -1
  72. package/dist/commands/doctor.js +75 -54
  73. package/dist/commands/doctor.js.map +1 -1
  74. package/dist/commands/edit.js +154 -109
  75. package/dist/commands/edit.js.map +1 -1
  76. package/dist/commands/eject.js +68 -38
  77. package/dist/commands/eject.js.map +1 -1
  78. package/dist/commands/init.js +36 -39
  79. package/dist/commands/list.js +8 -10
  80. package/dist/commands/list.js.map +1 -1
  81. package/dist/commands/new/marketplace.js +8 -11
  82. package/dist/commands/new/marketplace.js.map +1 -1
  83. package/dist/commands/search.js +10 -13
  84. package/dist/commands/search.js.map +1 -1
  85. package/dist/commands/share.js +8 -10
  86. package/dist/commands/share.js.map +1 -1
  87. package/dist/commands/uninstall.js +39 -28
  88. package/dist/commands/uninstall.js.map +1 -1
  89. package/dist/commands/update.js +7 -10
  90. package/dist/commands/update.js.map +1 -1
  91. package/dist/components/common/removal-plan-confirm.js +2 -2
  92. package/dist/components/common/select-list.js +2 -2
  93. package/dist/components/wizard/category-grid.js +4 -5
  94. package/dist/components/wizard/checkbox-grid.js +4 -4
  95. package/dist/components/wizard/domain-selection.js +9 -11
  96. package/dist/components/wizard/run-wizard-session.js +26 -28
  97. package/dist/components/wizard/scroll-affordance.js +2 -2
  98. package/dist/components/wizard/skill-agent-summary.js +5 -7
  99. package/dist/components/wizard/source-grid.js +5 -6
  100. package/dist/components/wizard/stack-selection.js +7 -9
  101. package/dist/components/wizard/step-agents.js +8 -10
  102. package/dist/components/wizard/step-build.js +7 -9
  103. package/dist/components/wizard/step-confirm.js +9 -11
  104. package/dist/components/wizard/step-sources.js +8 -10
  105. package/dist/components/wizard/step-stack.js +8 -10
  106. package/dist/components/wizard/summary-panel.js +8 -10
  107. package/dist/components/wizard/toast.js +2 -2
  108. package/dist/components/wizard/wizard-layout.js +12 -14
  109. package/dist/components/wizard/wizard-tabs.js +2 -4
  110. package/dist/components/wizard/wizard.js +25 -27
  111. package/dist/hooks/init.js +36 -39
  112. package/dist/hooks/init.js.map +1 -1
  113. package/dist/load-agent-defs-M6LRVISN.js +13 -0
  114. package/dist/recompile-project-agents-G7ZM25PC.js +17 -0
  115. package/dist/{source-loader-3DL3NYUX.js → source-loader-BIAEDR5R.js} +4 -8
  116. package/dist/src/agents/_templates/agent.liquid +2 -2
  117. package/dist/stores/wizard-store.js +6 -6
  118. package/package.json +1 -1
  119. package/src/agents/_templates/agent.liquid +2 -2
  120. package/src/schemas/custom-metadata.schema.json +1 -1
  121. package/src/schemas/marketplace.schema.json +2 -1
  122. package/dist/chunk-2H7UWE2G.js.map +0 -1
  123. package/dist/chunk-4A4L3YIW.js.map +0 -1
  124. package/dist/chunk-5F2YR5XV.js.map +0 -1
  125. package/dist/chunk-5QZAK6J7.js.map +0 -1
  126. package/dist/chunk-6RLV45HN.js.map +0 -1
  127. package/dist/chunk-CLFHC2DK.js.map +0 -1
  128. package/dist/chunk-F2AMBBIA.js +0 -64
  129. package/dist/chunk-F2AMBBIA.js.map +0 -1
  130. package/dist/chunk-F5T6TV4Z.js.map +0 -1
  131. package/dist/chunk-GS2NZ3GD.js.map +0 -1
  132. package/dist/chunk-H6UTKTLK.js.map +0 -1
  133. package/dist/chunk-HG4JPXJT.js.map +0 -1
  134. package/dist/chunk-HXKOIWLU.js.map +0 -1
  135. package/dist/chunk-IO5YBKHV.js.map +0 -1
  136. package/dist/chunk-MHRC3KRX.js.map +0 -1
  137. package/dist/chunk-MO5FGLVS.js.map +0 -1
  138. package/dist/chunk-PMUABBPG.js.map +0 -1
  139. package/dist/chunk-PNMM5HNX.js.map +0 -1
  140. package/dist/chunk-RWOYPOMR.js.map +0 -1
  141. package/dist/chunk-TNGMF4UX.js.map +0 -1
  142. package/dist/chunk-VASLW636.js +0 -23
  143. package/dist/chunk-VASLW636.js.map +0 -1
  144. package/dist/chunk-WCAUUBHO.js.map +0 -1
  145. package/dist/chunk-WUQ3MTPF.js +0 -173
  146. package/dist/chunk-WUQ3MTPF.js.map +0 -1
  147. package/dist/chunk-XAXJWXI4.js +0 -1667
  148. package/dist/chunk-XAXJWXI4.js.map +0 -1
  149. package/dist/chunk-YO2LTXB4.js.map +0 -1
  150. package/dist/chunk-ZUAZHDKP.js.map +0 -1
  151. package/dist/copy-local-skills-NSUTBVLJ.js +0 -14
  152. package/dist/load-agent-defs-X4E57I2U.js +0 -15
  153. package/dist/loader-G6BFG2VA.js +0 -24
  154. package/dist/recompile-project-agents-JE4MM72I.js +0 -20
  155. package/dist/recompile-project-agents-JE4MM72I.js.map +0 -1
  156. package/dist/source-loader-3DL3NYUX.js.map +0 -1
  157. /package/dist/{chunk-D2CAV7MG.js.map → chunk-4DMFK67G.js.map} +0 -0
  158. /package/dist/{chunk-ILUVL7WM.js.map → chunk-DZD25NHW.js.map} +0 -0
  159. /package/dist/{chunk-SY4X2LND.js.map → chunk-KUZBMEWR.js.map} +0 -0
  160. /package/dist/{chunk-PCC4LBKB.js.map → chunk-MU2TQ5KK.js.map} +0 -0
  161. /package/dist/{chunk-IXRZAHZF.js.map → chunk-PGZSNNDA.js.map} +0 -0
  162. /package/dist/{chunk-LJCNUP6M.js.map → chunk-PVPNVK3W.js.map} +0 -0
  163. /package/dist/{chunk-G47TDUK3.js.map → chunk-QNAMXQKF.js.map} +0 -0
  164. /package/dist/{chunk-5OKLCVM4.js.map → chunk-QO4XD5V5.js.map} +0 -0
  165. /package/dist/{chunk-WFRTHH3A.js.map → chunk-TZRXWFF5.js.map} +0 -0
  166. /package/dist/{chunk-Y5Y7XHVU.js.map → chunk-VI6U2PJG.js.map} +0 -0
  167. /package/dist/{chunk-TBOVYLQJ.js.map → chunk-VTIDLRNA.js.map} +0 -0
  168. /package/dist/{chunk-OKH64JZE.js.map → chunk-WCZNQECQ.js.map} +0 -0
  169. /package/dist/{chunk-HTYH7CKN.js.map → chunk-YKFCUVHG.js.map} +0 -0
  170. /package/dist/{chunk-VPASBA7P.js.map → chunk-YXI3BTQQ.js.map} +0 -0
  171. /package/dist/{copy-local-skills-NSUTBVLJ.js.map → load-agent-defs-M6LRVISN.js.map} +0 -0
  172. /package/dist/{load-agent-defs-X4E57I2U.js.map → recompile-project-agents-G7ZM25PC.js.map} +0 -0
  173. /package/dist/{loader-G6BFG2VA.js.map → source-loader-BIAEDR5R.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,37 @@ Each release has detailed notes in its own file under [`changelogs/`](./changelo
7
7
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
8
8
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
9
9
 
10
+ ## [0.157.0] - 2026-08-23
11
+
12
+ **The accuracy programme lands: scope travels end to end, every command prints the name the installation configured, and a run that cannot finish says so**
13
+
14
+ - Scope now travels end to end — a project-scoped skill can no longer be assigned to a global sub-agent in the editor, and the share payload, the worker and the CLI all read one scope vocabulary from `@workspace/matrix` (EDITOR-08, EDITOR-02, SERVER-04)
15
+ - Every command prints the configured `branding.name`, the interactive dashboard included (CLI-702, CLI-773)
16
+ - A run that cannot finish names what it owes and the one command that finishes it, and exits non-zero (CLI-607, CLI-612, CLI-618, CLI-649, CLI-800, CLI-811)
17
+ - `edit` decides its scope once, where it had answered the same question six times with two answers disagreeing (CLI-363)
18
+ - `build marketplace` refuses rather than writing a manifest its own loader rejects, and a closed union no longer answers a marketplace's own slug with somebody else's catalogue (CLI-611, CLI-502, CLI-644, CLI-675)
19
+ - The wizard's warnings reach the screen — sorted into the startup band, or a toast when raised after mount — and `TOAST_KEYS` is derived rather than hand-written (CLI-591, CLI-592, CLI-663)
20
+ - Configuration truth: `splitConfigByScope`'s comment corrected against code the owner ruled right, the seed schema shared with the editor, `eject` no longer writing over a config it could not read, and six producers of the sub-agent roster brought into agreement (CLI-538, CLI-614, CLI-602, CLI-492)
21
+ - Three guards refuse a build that moved under a running suite; every symptom of that race had been an ordinary assertion failure reading as a regression the change under test caused (CLI-671, CLI-699, CLI-708)
22
+ - Sixteen gates over surfaces no checker had opened — the briefing contract, spec-name vocabulary, symbol citations, spawn doors, refusal expectations, findings citations, skipped specs, test-only exports, derived producer rosters, and three the repository had decided by incident (CLI-566, CLI-589, CLI-587, CLI-588, CLI-562, CLI-605, CLI-627, CLI-626, CLI-544, CLI-581, CLI-616, CLI-658, CLI-664, CLI-355, CLI-356, CLI-358)
23
+ - Six specs that could not fail, repaired and mutation-proved — the old assertion stays green on the same mutation the new one catches (CLI-660, CLI-661, CLI-662, CLI-756, CLI-608, CLI-601)
24
+ - The unit suite no longer depends on the developer's shell, and one unescaped pipe no longer deletes a whole journey row (CLI-686, CLI-696)
25
+ - Removed: `output-validator.ts` and thirty-five exported symbols only tests invoked, `plugin-manifest-finder.ts` and `skill-fetcher.ts` among them (CLI-673, CLI-657, CLI-681)
26
+ - `extractStack` moved out of its spec into a tested helper, and the `D-NNN` tracker ids migrated to the workspace prefix (CLI-669, CLI-574, CLI-680)
27
+ - Web: the deployed editor's address is committed rather than assembled, the documentation's claims are re-derived from the CLI, and the landing page and docs read as one product — plus a seven-way chunk split that leaves an ordinary deploy re-hashing 29 KB instead of 1.03 MB (REPO-09, WWW-04, WWW-10, WWW-07)
28
+
29
+ See [changelogs/0.157.0.md](./changelogs/0.157.0.md) for full details.
30
+
31
+ ## [0.156.1] - 2026-08-20
32
+
33
+ **A test helper that walked the long way round, and the standard that had blessed the number it walked to**
34
+
35
+ - `BuildStep.focusSkill` looks at the screen before it presses Tab and confirms every press against the frame, so it no longer pays a 33-category lap to reach the category the grid opened on, nor passes its own target while a repaint is in flight (CLI-595)
36
+ - `MAX_FOCUS_ATTEMPTS` is deleted — the walk terminates on a real lap and raises `CategoryWalkError` naming the categories it observed, because a press budget reports the number it gave up at
37
+ - No shipped code changed: the published tarball is identical to 0.156.0's
38
+
39
+ See [changelogs/0.156.1.md](./changelogs/0.156.1.md) for full details.
40
+
10
41
  ## [0.156.0] - 2026-08-20
11
42
 
12
43
  **The programme audits its own output, and a guard finds the defect every suite was blind to**
@@ -2,31 +2,27 @@
2
2
  import {
3
3
  claimSlug,
4
4
  computeFileHash,
5
+ glob,
5
6
  injectForkedFromMetadata,
7
+ readFile,
6
8
  readLocalSkillMetadata,
9
+ readSkillMetadata,
7
10
  resolveInstallPaths,
8
11
  seedExternalSkillSchema,
9
12
  seedPayloadSchema,
10
13
  validateSkillPath,
14
+ writeFile,
11
15
  writeMetadataYaml
12
- } from "./chunk-WCAUUBHO.js";
13
- import {
14
- glob,
15
- readFile,
16
- readSkillMetadata,
17
- writeFile
18
- } from "./chunk-XAXJWXI4.js";
19
- import {
20
- getCategoryDomain
21
- } from "./chunk-RWOYPOMR.js";
16
+ } from "./chunk-RVXI5VQU.js";
22
17
  import {
18
+ getCategoryDomain,
23
19
  typedEntries
24
- } from "./chunk-VASLW636.js";
20
+ } from "./chunk-IGOFZG3S.js";
25
21
  import {
26
22
  GITHUB_SOURCE,
27
23
  LOCAL_SKILLS_PATH,
28
24
  STANDARD_FILES
29
- } from "./chunk-IO5YBKHV.js";
25
+ } from "./chunk-G6G2FT2G.js";
30
26
 
31
27
  // src/cli/lib/seed/external-skills.ts
32
28
  import path from "path";
@@ -255,4 +251,4 @@ export {
255
251
  SEED_USER_AGENT,
256
252
  fetchSeedConfig
257
253
  };
258
- //# sourceMappingURL=chunk-PMUABBPG.js.map
254
+ //# sourceMappingURL=chunk-24IGOJ7E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/seed/external-skills.ts","../src/cli/lib/seed/fetch-seed.ts"],"sourcesContent":["import path from \"path\";\n\nimport { seedExternalSkillSchema } from \"@workspace/matrix/seed\";\n\nimport { GITHUB_SOURCE, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../../consts.js\";\nimport { resolveInstallPaths } from \"../installation/install-base-dir.js\";\nimport { readSkillMetadata } from \"../loading/loader.js\";\nimport { getCategoryDomain } from \"../matrix/matrix-provider.js\";\nimport { claimSlug } from \"../matrix/skill-resolution.js\";\nimport { validateSkillPath } from \"../skills/skill-copier.js\";\nimport {\n injectForkedFromMetadata,\n readLocalSkillMetadata,\n writeMetadataYaml,\n} from \"../skills/skill-metadata.js\";\nimport { computeFileHash } from \"../versioning.js\";\nimport { glob, readFile, writeFile } from \"../../utils/fs.js\";\nimport { typedEntries } from \"../../utils/typed-object.js\";\n\nimport type { SkillScope } from \"../../types/config.js\";\nimport type { Domain, MergedSkillsMatrix, ResolvedSkill } from \"../../types/matrix.js\";\nimport type { CategoryPath, SkillId, SkillSlug } from \"../../types/skills.js\";\nimport type { ForkedFromMetadata, LocalSkillMetadata } from \"../skills/skill-metadata.js\";\nimport type {\n SeedExternalSkill,\n SeedPayload,\n SeedSkill,\n SeedSkillTree,\n} from \"@workspace/matrix/seed\";\n\n/**\n * One skill the payload carries rather than names, seated and ready to be written.\n *\n * `skillDir` and `domain` are resolved once, where the checks that make them safe already are:\n * the directory has to be the one the catalogue entry points at, because that is what tells the\n * copy step this skill is already where it belongs, and the domain is what the category guard has\n * just proved this catalogue declares.\n */\nexport type ExternalSkillInstall = {\n id: SkillId;\n scope: SkillScope;\n skill: SeedExternalSkill;\n domain: Domain;\n skillDir: string;\n};\n\n/** One external entry with the skill row that selected it — what the payload says about it. */\ntype SelectedExternal = { id: SkillId; skill: SeedExternalSkill; entry: SeedSkill };\n\n/**\n * Names every carried skill a payload asks to install as a plugin, not just the first.\n *\n * There is nothing to install them FROM: the payload is the source, so no marketplace serves\n * these ids. Coercing them to eject would install something the payload did not ask for, under a\n * mode the sharer's own screen still shows as plugin — so the ids are named and the run stops.\n */\nfunction pluginInstallError(ids: SkillId[]): string {\n return [\n \"This configuration cannot be installed: these skills travel inside it, so no marketplace \" +\n \"serves them and they cannot be installed as plugins:\",\n ...ids.map((id) => ` ${id}`),\n \"Re-share it with each skill above set to eject, which is the only way a carried skill installs.\",\n ].join(\"\\n\");\n}\n\n/**\n * The external entries this selection actually names.\n *\n * Presence in `skills` is selection and `external` is only where the bytes are, so content nobody\n * picked installs nothing — seating it would put a skill in the catalogue no part of the\n * configuration asked for.\n */\nfunction selectedExternals(payload: SeedPayload): SelectedExternal[] {\n return typedEntries<SkillId, SeedExternalSkill>(payload.external ?? {}).flatMap(([id, skill]) => {\n const entry = payload.skills[id];\n return entry ? [{ id, skill, entry }] : [];\n });\n}\n\nfunction askedForAsPlugin(externals: SelectedExternal[]): SkillId[] {\n return externals.filter(({ entry }) => entry.install !== \"eject\").map(({ id }) => id);\n}\n\n/**\n * Boundary cast: a carried skill's id is minted at intake and belongs to no generated union,\n * which is exactly what makes it external. It is its own slug too — a skill outside every\n * catalogue has no shorter name anything else would recognise, and the sending side says the same.\n */\nfunction externalSlug(id: SkillId): SkillSlug {\n return id as SkillSlug;\n}\n\n/** The repository's owner as a handle, which is all the authorship a carried skill records. */\nfunction skillAuthor(repo: string): string {\n const [owner = repo] = repo.split(\"/\");\n return `@${owner}`;\n}\n\n/** The repository ref a carried skill's provenance records, in the form every other ref wears. */\nfunction repoRef(repo: string): string {\n return `${GITHUB_SOURCE.GITHUB_PREFIX}${repo}`;\n}\n\n/** Where a carried skill's directory goes: under the skills directory of the scope it names. */\nfunction externalSkillDir(id: SkillId, scope: SkillScope, projectDir: string): string {\n return path.join(resolveInstallPaths(projectDir, scope).skillsDir, id);\n}\n\n/**\n * The catalogue entry a carried skill becomes on arrival.\n *\n * It declares no relationships and is named by none, which is honest: nothing outside the\n * catalogue can say what this skill conflicts with, and nothing inside it knows the skill exists.\n */\nfunction externalCatalogueEntry(install: ExternalSkillInstall): ResolvedSkill {\n return {\n id: install.id,\n slug: externalSlug(install.id),\n displayName: install.skill.displayName,\n description: install.skill.description,\n // Boundary cast held by the guard above it: the category was confirmed against the catalogue\n // the payload names, and this one has just been shown to declare it too.\n category: install.skill.categoryId as CategoryPath,\n author: skillAuthor(install.skill.repo),\n path: `${LOCAL_SKILLS_PATH}/${install.id}/`,\n conflictsWith: [],\n requires: [],\n alternatives: [],\n discourages: [],\n // Local and custom for the same reason: the bytes are on this machine and nowhere else, and\n // the skill was authored outside the vocabulary this catalogue ships.\n local: true,\n custom: true,\n localPath: install.skillDir,\n };\n}\n\n/**\n * Seats one carried skill in the catalogue, or leaves it unseated.\n *\n * A skill is PLACED in the taxonomy and never extends it, so a category this catalogue has no\n * definition for belongs to no domain, renders in no tab and reaches no sub-agent. Left unseated,\n * the id falls to the decode's own skip, which reports it by name.\n */\nfunction seatExternalSkill(\n { id, skill, entry }: SelectedExternal,\n matrix: MergedSkillsMatrix,\n projectDir: string,\n): ExternalSkillInstall[] {\n const domain = getCategoryDomain(skill.categoryId);\n if (domain === undefined) return [];\n\n const install: ExternalSkillInstall = {\n id,\n skill,\n domain,\n scope: entry.scope,\n skillDir: externalSkillDir(id, entry.scope, projectDir),\n };\n\n matrix.skills[id] = externalCatalogueEntry(install);\n // Completes the map over the matrix: an entry the slug map does not carry is invisible to\n // anything that addresses a skill by slug.\n claimSlug(matrix.slugMap, externalSlug(id), id);\n\n return [install];\n}\n\n/**\n * Seats the catalogue entries a payload carries, and says where each one's bytes go.\n *\n * Every other id in a payload is resolved against a catalogue the receiver already has, so one it\n * does not know is skipped and reported. A carried skill answers to no catalogue at all — which is\n * why its whole directory travels — so it has to BECOME a catalogue entry before the decode reads\n * the selection, or it is skipped like any other unknown id and the configuration installs\n * quietly smaller than it was shared.\n *\n * The entries are written into `matrix` in place, exactly as the local-skill merge writes the\n * skills it discovers on disk. That matrix is the object `initializeMatrix` seated, which is what\n * {@link getCategoryDomain} reads — every caller passes the loaded source's own.\n *\n * @throws {Error} If any carried skill asks to be installed as a plugin — see\n * {@link pluginInstallError}.\n */\nexport function registerExternalSkills(\n payload: SeedPayload,\n matrix: MergedSkillsMatrix,\n projectDir: string,\n): ExternalSkillInstall[] {\n const externals = selectedExternals(payload);\n const asPlugin = askedForAsPlugin(externals);\n\n if (asPlugin.length > 0) throw new Error(pluginInstallError(asPlugin));\n\n return externals.flatMap((external) => seatExternalSkill(external, matrix, projectDir));\n}\n\n/**\n * Writes each carried skill's directory where its own entry said, and registers it on disk.\n *\n * Three things have to be true afterwards, and each is a separate act: the files are there, the\n * skill answers to the id the configuration recorded, and a metadata.yaml describes it well\n * enough for the next `edit`, `compile` or `list` to find it again. The seat above lasts one run;\n * this is what makes the install survive.\n */\nexport async function writeExternalSkills(installs: ExternalSkillInstall[]): Promise<void> {\n for (const install of installs) {\n await writeSkillTree(install);\n await writeSkillManifest(install);\n await registerSkillOnDisk(install);\n }\n}\n\n/**\n * The directory as the payload holds it, keys and all.\n *\n * The keys came off the wire, so a payload may ask for any path it likes — including one that\n * climbs out of the skill's own directory. They answer to the same guard a marketplace's own\n * paths do.\n */\nasync function writeSkillTree(install: ExternalSkillInstall): Promise<void> {\n for (const [relativePath, contents] of Object.entries(install.skill.files)) {\n const filePath = path.join(install.skillDir, relativePath);\n validateSkillPath(filePath, install.skillDir, relativePath);\n await writeFile(filePath, contents);\n }\n}\n\n/** The frontmatter block at the head of a SKILL.md, and the `name` field inside it. */\nconst FRONTMATTER_BLOCK = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\nconst NAME_FIELD = /^name:.*$/m;\n\n/**\n * Names the skill by the id it installs under.\n *\n * Every loader reads a skill's id off this one field, and a compiled sub-agent references the id\n * the configuration recorded — the one minted at intake, which is also this directory's name. The\n * repository the skill came from knew about neither, so left as it was written the two never\n * meet: the sub-agent names a skill Claude Code knows as something else, and the next load\n * registers an id no configuration carries.\n *\n * Only the name. Everything else in the block is the author's and travels untouched.\n */\nfunction withInstalledName(manifest: string, install: ExternalSkillInstall): string {\n const named = `name: ${install.id}`;\n const block = FRONTMATTER_BLOCK.exec(manifest);\n\n // A manifest with no frontmatter at all describes no skill to Claude Code either. The payload\n // carries both fields one needs, so it is given one rather than installed unreadable.\n if (!block) {\n return `---\\n${named}\\ndescription: ${install.skill.description}\\n---\\n\\n${manifest}`;\n }\n\n const [whole, fields = \"\"] = block;\n const renamed = NAME_FIELD.test(fields)\n ? fields.replace(NAME_FIELD, named)\n : `${named}\\n${fields}`;\n\n // The block is anchored at the head of the file, so what follows it is the rest verbatim.\n return `---\\n${renamed}\\n---${manifest.slice(whole.length)}`;\n}\n\nasync function writeSkillManifest(install: ExternalSkillInstall): Promise<void> {\n const manifestPath = path.join(install.skillDir, STANDARD_FILES.SKILL_MD);\n await writeFile(manifestPath, withInstalledName(await readFile(manifestPath), install));\n}\n\n/**\n * What the payload confirmed, over what the repository shipped, over what neither says.\n *\n * The order is the whole of it. The taxonomy is the placement the user chose against the\n * catalogue this configuration names, and the repository's own idea of where its skill belongs\n * answers to a taxonomy nobody here shares — so that is written over the file. Everything else\n * the repository wrote is kept, because its author knows more about their skill than a default\n * does.\n *\n * The defaults underneath exist because `doctor` validates every installed metadata.yaml, and a\n * file this command writes that that command reports as an error is the CLI disagreeing with\n * itself — in a file the user cannot fix, since the skill is somebody else's repository. Neither\n * is invented: the authorship is the repository's owner, and the usage line is the same words the\n * stack loader already writes for every skill reference it has nothing more specific for.\n */\nfunction externalSkillMetadata(\n install: ExternalSkillInstall,\n shipped: LocalSkillMetadata | null,\n): LocalSkillMetadata {\n return {\n author: skillAuthor(install.skill.repo),\n usageGuidance: `Use when working with ${install.skill.displayName}`,\n ...shipped,\n displayName: install.skill.displayName,\n slug: install.id,\n category: install.skill.categoryId,\n domain: install.domain,\n cliDescription: install.skill.description,\n custom: true,\n };\n}\n\n/**\n * Registers the skill on disk, where the next command will look for it.\n *\n * `forkedFrom` is stamped through the one writer that stamps it, because it is the package's\n * single answer to \"did the CLI put this directory here?\" — `uninstall` reads it to decide what it\n * may delete, and the producer reads it to decide what the round trip owns. A carried skill IS the\n * round trip's; a skill the user wrote by hand is not, and carries nothing.\n *\n * The repository AND the directory inside it, because this is the only record of where these bytes\n * came from. Sharing this installation has to rebuild the entry the payload carried, and a\n * repository alone cannot say which of its directories travelled — see {@link readCarriedSkills}.\n */\nasync function registerSkillOnDisk(install: ExternalSkillInstall): Promise<void> {\n const metadataPath = path.join(install.skillDir, STANDARD_FILES.METADATA_YAML);\n const shipped = await readLocalSkillMetadata(install.skillDir);\n\n await writeMetadataYaml(metadataPath, externalSkillMetadata(install, shipped));\n await injectForkedFromMetadata(\n install.skillDir,\n install.id,\n await computeFileHash(path.join(install.skillDir, STANDARD_FILES.SKILL_MD)),\n { source: repoRef(install.skill.repo), path: install.skill.path },\n );\n}\n\n/**\n * One installed skill directory the round trip owns, and what its install recorded about it.\n *\n * Read by the caller rather than here: whether a directory is the CLI's copy or the user's own\n * work is a question about ownership, which `installation-payload.ts` already asks of every entry\n * before anything else. This module answers only the next one — whether the bytes have to travel.\n */\nexport type OwnedSkillDir = { id: string; skillDir: string; provenance: ForkedFromMetadata };\n\n/**\n * What one installation carries rather than names.\n *\n * The same shape the mapper's other readings wear: what can travel, and the lines naming what\n * cannot. Both halves matter — a payload quietly missing content it could not read still mints an\n * id, and that id installs a configuration nobody chose.\n */\nexport type ContentReading = {\n /** Skill id -> the entry a receiver seats it from. Keyed exactly as the wire keys `external`. */\n external: Record<string, SeedExternalSkill>;\n /** One line per skill whose content this installation cannot carry, for the refusal. */\n uncarryable: string[];\n};\n\n/** What one owned directory turns out to carry: content, a reason it cannot, or nothing. */\ntype CarriedRead =\n | { carries: \"content\"; id: string; skill: SeedExternalSkill }\n | { carries: \"nothing\" }\n | { carries: \"unshareable\"; line: string };\n\nfunction unnameableRepoMessage(id: string): string {\n return `${id} travels inside a shared configuration, and this installation does not record the repository its content came from`;\n}\n\nfunction uncarryableContentMessage(id: string, reason: string): string {\n return `${id} travels inside a shared configuration, and ${reason}`;\n}\n\n/**\n * The inverse of {@link repoRef}: the repository a ref names, or nothing when it names none this\n * contract can state.\n *\n * Provenance is written as a ref because that is the form every other source in a configuration\n * wears; the wire wants GitHub's own `owner/name`. Any other ref is a repository this contract has\n * no word for, which is a refusal rather than something to guess at.\n */\nfunction repoFromRef(ref: string | undefined): string | undefined {\n if (ref === undefined || !ref.startsWith(GITHUB_SOURCE.GITHUB_PREFIX)) return undefined;\n return ref.slice(GITHUB_SOURCE.GITHUB_PREFIX.length);\n}\n\n/** Every file under the skill, keyed by its path relative to it — dotfiles and nesting included. */\nasync function readSkillTree(skillDir: string): Promise<SeedSkillTree> {\n const files = await glob(\"**/*\", skillDir, { dot: true });\n const entries = await Promise.all(\n files.map(async (file) => [file, await readFile(path.join(skillDir, file))] as const),\n );\n return Object.fromEntries(entries);\n}\n\n/**\n * Rebuilds the entry a carried skill arrived as, from the directory the install wrote.\n *\n * The bytes as they stand rather than as they arrived: the manifest was renamed to the id this\n * install recorded, and a user may have edited the skill since. Both are what is installed here,\n * and what is installed here is what a share carries.\n *\n * Validated against the contract's own schema rather than by rules restated here — that is what\n * makes the weight limit, the manifest requirement and every field's shape one definition rather\n * than two that can drift.\n */\nasync function readCarriedSkill({ id, skillDir, provenance }: OwnedSkillDir): Promise<CarriedRead> {\n // The directory is what marks a skill as one no catalogue can resolve. Without it there is a\n // catalogue behind this id, so the receiver installs it from there and the bytes stay home.\n if (provenance.path === undefined) return { carries: \"nothing\" };\n\n const repo = repoFromRef(provenance.source);\n if (repo === undefined) return { carries: \"unshareable\", line: unnameableRepoMessage(id) };\n\n const described = await readSkillMetadata(path.join(skillDir, STANDARD_FILES.METADATA_YAML));\n if (!described.usable) {\n return { carries: \"unshareable\", line: uncarryableContentMessage(id, described.reason) };\n }\n\n const parsed = seedExternalSkillSchema.safeParse({\n displayName: described.metadata.displayName,\n description: described.metadata.cliDescription,\n categoryId: described.metadata.category,\n repo,\n path: provenance.path,\n files: await readSkillTree(skillDir),\n });\n if (!parsed.success) {\n const reason = parsed.error.issues.map((issue) => issue.message).join(\"; \");\n return { carries: \"unshareable\", line: uncarryableContentMessage(id, reason) };\n }\n\n return { carries: \"content\", id, skill: parsed.data };\n}\n\n/**\n * What a set of owned skill directories carries, and what it cannot.\n *\n * The mirror of {@link registerExternalSkills}: that seats an entry a payload carried and writes\n * its bytes, this reads those bytes back into the entry a payload carries. Every other id in a\n * configuration is resolved by the receiver against a catalogue it already has, so its content has\n * nothing to add; an added skill answers to no catalogue in either direction, and a share that\n * named it without carrying it would mint an id that installs a configuration missing it.\n */\nexport async function readCarriedSkills(owned: OwnedSkillDir[]): Promise<ContentReading> {\n const reads = await Promise.all(owned.map(readCarriedSkill));\n\n return {\n external: Object.fromEntries(\n reads.flatMap((read) => (read.carries === \"content\" ? [[read.id, read.skill]] : [])),\n ),\n uncarryable: reads.flatMap((read) => (read.carries === \"unshareable\" ? [read.line] : [])),\n };\n}\n","import { seedPayloadSchema, type SeedPayload } from \"@workspace/matrix/seed\";\n\n/** The config store behind agentsinc.sh. Overridable so tests never touch the network. */\nexport const SEED_API_URL = process.env.AGENTS_INC_API_URL ?? \"https://api.agentsinc.sh\";\n\n/**\n * Identifies this fetch as the CLI rather than a browser.\n *\n * `GET /configs/:id` is the only place either side can observe a config being *installed* rather\n * than merely built, and the worker can only separate that from someone opening a share link if\n * we say so. Without this the conversion signal does not exist.\n */\nexport const SEED_USER_AGENT = \"agents-inc-cli\";\n\nexport type FetchSeedResult = { ok: true; payload: SeedPayload } | { ok: false; error: string };\n\n/**\n * Fetches and validates a shared configuration.\n *\n * Every failure is a message rather than a throw: this runs before anything has been written, so\n * there is nothing to roll back and the caller's job is to explain rather than recover.\n */\nexport async function fetchSeedConfig(id: string): Promise<FetchSeedResult> {\n const url = `${SEED_API_URL}/configs/${encodeURIComponent(id)}`;\n\n let response: Response;\n try {\n response = await fetch(url, {\n headers: { accept: \"application/json\", \"user-agent\": SEED_USER_AGENT },\n });\n } catch {\n return { ok: false, error: `Could not reach ${SEED_API_URL} — check your connection.` };\n }\n\n if (response.status === 404) {\n return { ok: false, error: `No configuration found for id '${id}'.` };\n }\n if (!response.ok) {\n return { ok: false, error: `Fetching configuration failed (HTTP ${response.status}).` };\n }\n\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n return { ok: false, error: \"The configuration store returned something that is not JSON.\" };\n }\n\n const parsed = seedPayloadSchema.safeParse(body);\n if (!parsed.success) {\n // Names the remedy rather than a cause it cannot observe. The payload was validated by the\n // store on the way IN, so a stored payload that no longer parses means the contract moved\n // underneath it — and every way that happens lands in this one `safeParse`: an id minted\n // before a version bump, an id minted after one, and a body that is simply broken. The CLI\n // cannot tell them apart, and the one thing true of all three is that re-sharing fixes it,\n // because the store content-addresses an id and a fresh share mints one under this version.\n return {\n ok: false,\n error: `Configuration '${id}' is not in a format this version of the CLI can install. Shared ids are never migrated — re-share the configuration to mint a current one, or update the CLI if that id came from a newer version.`,\n };\n }\n\n return { ok: true, payload: parsed.data };\n}\n"],"mappings":"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","names":[]}
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SelectList
4
- } from "./chunk-TBOVYLQJ.js";
4
+ } from "./chunk-VTIDLRNA.js";
5
5
  import {
6
6
  seedToWizardResult
7
- } from "./chunk-MO5FGLVS.js";
7
+ } from "./chunk-DCIC35R7.js";
8
8
  import {
9
9
  runWizardSession
10
- } from "./chunk-IXRZAHZF.js";
10
+ } from "./chunk-PGZSNNDA.js";
11
11
  import {
12
12
  useTerminalDimensions
13
- } from "./chunk-HG4JPXJT.js";
13
+ } from "./chunk-V7PMQDDU.js";
14
14
  import {
15
15
  Spinner
16
16
  } from "./chunk-ZBPEFQ4G.js";
@@ -18,7 +18,7 @@ import {
18
18
  fetchSeedConfig,
19
19
  registerExternalSkills,
20
20
  writeExternalSkills
21
- } from "./chunk-PMUABBPG.js";
21
+ } from "./chunk-24IGOJ7E.js";
22
22
  import {
23
23
  promptValue
24
24
  } from "./chunk-JCPANDNR.js";
@@ -26,54 +26,53 @@ import {
26
26
  compileAgentsAllScopes,
27
27
  loadSource,
28
28
  writeProjectConfig
29
- } from "./chunk-WUQ3MTPF.js";
29
+ } from "./chunk-Z3H2K5PK.js";
30
30
  import {
31
+ copyLocalSkills,
31
32
  discoverInstalledSkills
32
- } from "./chunk-5QZAK6J7.js";
33
+ } from "./chunk-ZAQ6WMJV.js";
33
34
  import {
34
35
  loadAgentDefs
35
- } from "./chunk-MHRC3KRX.js";
36
- import {
37
- copyLocalSkills
38
- } from "./chunk-F2AMBBIA.js";
36
+ } from "./chunk-4KHUHPX4.js";
39
37
  import {
40
38
  render
41
39
  } from "./chunk-JFLVEFFP.js";
42
40
  import {
43
41
  BaseCommand,
44
42
  EXIT_CODES
45
- } from "./chunk-YO2LTXB4.js";
43
+ } from "./chunk-KTXVQ7OM.js";
46
44
  import {
47
45
  clearTerminalScreen
48
- } from "./chunk-G47TDUK3.js";
46
+ } from "./chunk-QNAMXQKF.js";
49
47
  import {
48
+ INCOMPLETE_WORK_RECOVERY,
50
49
  INSTALL_MODE_DESCRIPTIONS,
51
50
  INSTALL_MODE_LABELS,
52
51
  STATUS_MESSAGES,
53
- SUCCESS_MESSAGES,
52
+ agentsNotCompiled,
54
53
  buildAgentScopeMap,
55
54
  carriedSkillsWritten,
56
55
  deriveInstallMode,
57
56
  detectGlobalInstallation,
58
57
  detectInstallation,
59
58
  detectProjectInstallation,
59
+ fileExists,
60
+ getErrorMessage,
60
61
  getInstallationInfo,
61
62
  globalScopedAgentsHint,
63
+ initSucceeded,
62
64
  isHomeDirectory,
63
65
  loadProjectConfig,
66
+ readFileSafe,
67
+ resolveBranding,
64
68
  resolveInstallPaths,
69
+ settingsFileSchema,
65
70
  sharedConfigExistingInstall,
66
71
  sharedConfigGlobalInstall,
67
72
  skippedUnknownAgents,
68
- skippedUnknownSkills
69
- } from "./chunk-WCAUUBHO.js";
70
- import {
71
- fileExists,
72
- getErrorMessage,
73
- readFileSafe,
74
- settingsFileSchema,
73
+ skippedUnknownSkills,
75
74
  warn
76
- } from "./chunk-XAXJWXI4.js";
75
+ } from "./chunk-RVXI5VQU.js";
77
76
  import {
78
77
  ASCII_LOGO,
79
78
  CLAUDE_DIR,
@@ -85,7 +84,7 @@ import {
85
84
  EJECT_SOURCE,
86
85
  MAX_CONFIG_FILE_SIZE,
87
86
  STANDARD_FILES
88
- } from "./chunk-IO5YBKHV.js";
87
+ } from "./chunk-G6G2FT2G.js";
89
88
 
90
89
  // src/cli/commands/init.tsx
91
90
  import "react";
@@ -163,11 +162,12 @@ var DASHBOARD_OPTIONS = [
163
162
  { label: "Doctor", value: "doctor" },
164
163
  { label: "List", value: "list" }
165
164
  ];
166
- var Dashboard = ({ onSelect, onCancel }) => {
165
+ var DashboardTitle = ({ name }) => name === DEFAULT_BRANDING.NAME ? /* @__PURE__ */ jsx2(Text2, { children: ASCII_LOGO }) : /* @__PURE__ */ jsx2(Text2, { bold: true, children: name });
166
+ var Dashboard = ({ name, onSelect, onCancel }) => {
167
167
  const { exit } = useApp();
168
168
  const { rows: terminalHeight } = useTerminalDimensions();
169
169
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: terminalHeight, children: [
170
- /* @__PURE__ */ jsx2(Box2, { marginBottom: 1, children: /* @__PURE__ */ jsx2(Text2, { children: ASCII_LOGO }) }),
170
+ /* @__PURE__ */ jsx2(Box2, { marginBottom: 1, children: /* @__PURE__ */ jsx2(DashboardTitle, { name }) }),
171
171
  /* @__PURE__ */ jsx2(
172
172
  SelectList,
173
173
  {
@@ -187,7 +187,7 @@ var Dashboard = ({ onSelect, onCancel }) => {
187
187
  function formatDashboardText(data) {
188
188
  const modeLabel = INSTALL_MODE_LABELS[data.mode];
189
189
  const lines = [
190
- DEFAULT_BRANDING.NAME,
190
+ data.name,
191
191
  "",
192
192
  ` Skills: ${data.skillCount} installed`,
193
193
  ` Agents: ${data.agentCount} compiled`,
@@ -208,7 +208,14 @@ async function showDashboard(projectDir, log) {
208
208
  return null;
209
209
  }
210
210
  const selectedCommand = await promptValue(
211
- (resolve) => /* @__PURE__ */ jsx2(Dashboard, { onSelect: (command) => resolve(command), onCancel: () => resolve(null) }),
211
+ (resolve) => /* @__PURE__ */ jsx2(
212
+ Dashboard,
213
+ {
214
+ name: data.name,
215
+ onSelect: (command) => resolve(command),
216
+ onCancel: () => resolve(null)
217
+ }
218
+ ),
212
219
  { onExit: null, clearOnResolve: true }
213
220
  );
214
221
  clearTerminalScreen();
@@ -234,6 +241,13 @@ function sharedConfigSourceFlags(flags, payload) {
234
241
  return { marketplace: flags.marketplace ?? payload.marketplace };
235
242
  }
236
243
  var Init = class _Init extends BaseCommand {
244
+ /**
245
+ * The name this run prints itself under, resolved once on {@link install}'s spine because the
246
+ * closing line is printed several calls below it. Same shape and same reason as `uninstall`'s
247
+ * field: a plain `string` holding the shipped default rather than an optional every reader
248
+ * would have to answer for.
249
+ */
250
+ brandingName = DEFAULT_BRANDING.NAME;
237
251
  static summary = `Initialize ${DEFAULT_BRANDING.NAME} in this project`;
238
252
  static description = "Interactive wizard to set up skills and agents. Supports Plugin Mode (native install) and Eject Mode (copy to .claude/).";
239
253
  static examples = [
@@ -257,15 +271,29 @@ var Init = class _Init extends BaseCommand {
257
271
  helpValue: "<id>"
258
272
  })
259
273
  };
274
+ /**
275
+ * The command in two statements: do the work, then answer for it.
276
+ *
277
+ * {@link install} owns every path through the setup and returns however it likes; the exit
278
+ * code is decided once, here, after the last of them. Deciding it inside would mean deciding
279
+ * it at each of that method's endings, and an ending added later would inherit the exit-0
280
+ * default silently — which is the defect this pair exists to close. `edit` is two statements
281
+ * for the same reason.
282
+ */
283
+ async run() {
284
+ await this.install();
285
+ this.exitIfWorkIncomplete();
286
+ }
260
287
  /**
261
288
  * One spine, two producers. The wizard and a shared id differ only in *where the selection
262
289
  * comes from* — everything after it (the empty guard, the install pipeline) is identical, so it
263
290
  * lives here once rather than being written twice and drifting.
264
291
  */
265
- async run() {
292
+ async install() {
266
293
  const { flags } = await this.parse(_Init);
267
294
  const projectDir = process.cwd();
268
295
  await this.ensureConfigReadable(projectDir);
296
+ this.brandingName = await this.resolveBrandingName(projectDir);
269
297
  if (!flags.from && await this.showDashboardIfInitialized(projectDir)) return;
270
298
  const selection = flags.from ? await this.selectionFromSharedConfig(flags.from, flags, projectDir) : await this.selectionFromWizard(flags, projectDir);
271
299
  if (!selection) this.exit(EXIT_CODES.CANCELLED);
@@ -571,13 +599,39 @@ var Init = class _Init extends BaseCommand {
571
599
  skills: allSkills,
572
600
  agentScopeMap
573
601
  });
574
- this.log(`Compiled ${compileResult.compiled.length} agents
575
- `);
602
+ this.reportCompilation(compileResult);
576
603
  this.reportPropagatedRecompile(configResult.propagation);
577
604
  return { configResult, compileResult, agentScopeMap };
578
605
  }
606
+ /**
607
+ * What the compile pass did, including the half this command used to drop.
608
+ *
609
+ * It read `compiled` and nothing else, so a pass that lost a sub-agent printed a number that
610
+ * looked perfectly right — `compiled` counts successes, so it is correct either way — and the
611
+ * failures reached no surface at all: no count, no reason, no exit code. A user's FIRST
612
+ * install could silently land a roster missing a sub-agent.
613
+ *
614
+ * The compile is the last thing `init` does, so a failure here cannot be answered by aborting:
615
+ * the skills are on disk and `config.ts` and `config-types.ts` describe them. What is owed is
616
+ * the account, which {@link BaseCommand.exitIfWorkIncomplete} prints and answers for.
617
+ */
618
+ reportCompilation(compileResult) {
619
+ const { compiled, failed, warnings } = compileResult;
620
+ const summary = `Compiled ${compiled.length} agents`;
621
+ if (failed.length === 0) {
622
+ this.log(`${summary}
623
+ `);
624
+ return;
625
+ }
626
+ this.log(`${summary} (${failed.length} failed)
627
+ `);
628
+ for (const warning of warnings) {
629
+ this.warn(warning);
630
+ }
631
+ this.recordIncompleteWork(agentsNotCompiled(failed), INCOMPLETE_WORK_RECOVERY.RECOMPILE);
632
+ }
579
633
  reportSuccess(configResult, compileResult, agentScopeMap, installMode, pluginModeSucceeded, copyResult) {
580
- this.log(`${SUCCESS_MESSAGES.INIT_SUCCESS}
634
+ if (!this.hasIncompleteWork) this.log(`${initSucceeded(this.brandingName)}
581
635
  `);
582
636
  const isEjectOutput = installMode === "eject" || installMode === "mixed" && !pluginModeSucceeded;
583
637
  if (isEjectOutput && copyResult && copyResult.totalCopied > 0) {
@@ -699,13 +753,23 @@ function customizationSteps(split, globalConfigPath) {
699
753
  ];
700
754
  }
701
755
  async function getDashboardData(projectDir) {
702
- const [info, loaded] = await Promise.all([getInstallationInfo(), loadProjectConfig(projectDir)]);
756
+ const [info, loaded, branding] = await Promise.all([
757
+ getInstallationInfo(),
758
+ loadProjectConfig(projectDir),
759
+ resolveBranding(projectDir)
760
+ ]);
703
761
  const activeSkills = loaded?.config.skills.filter((s) => !s.excluded);
704
762
  const skillCount = info?.skillCount ?? 0;
705
763
  const agentCount = info?.agentCount ?? 0;
706
764
  const mode = info?.mode ?? (activeSkills ? deriveInstallMode(activeSkills) : "eject");
707
765
  const source = loaded?.config.marketplace;
708
- return { skillCount, agentCount, mode, ...source !== void 0 && { source } };
766
+ return {
767
+ name: branding.name,
768
+ skillCount,
769
+ agentCount,
770
+ mode,
771
+ ...source !== void 0 && { source }
772
+ };
709
773
  }
710
774
 
711
775
  export {
@@ -715,4 +779,4 @@ export {
715
779
  Init,
716
780
  getDashboardData
717
781
  };
718
- //# sourceMappingURL=chunk-H6UTKTLK.js.map
782
+ //# sourceMappingURL=chunk-3E52LCYC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/init.tsx","../src/cli/lib/permission-checker.tsx"],"sourcesContent":["import React from \"react\";\n\nimport { Flags, type Interfaces } from \"@oclif/core\";\nimport { Box, Text, useApp } from \"ink\";\nimport { render } from \"../components/render.js\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { type WizardResultV2 } from \"../components/wizard/wizard.js\";\nimport { runWizardSession } from \"../components/wizard/run-wizard-session.js\";\nimport { useTerminalDimensions } from \"../components/hooks/use-terminal-dimensions.js\";\nimport { type SourceLoadResult } from \"../lib/loading/index.js\";\nimport {\n loadSource,\n loadAgentDefs,\n copyLocalSkills,\n writeProjectConfig,\n compileAgentsAllScopes,\n type CompilationResult,\n type SkillCopyResult,\n discoverInstalledSkills,\n} from \"../lib/operations/index.js\";\nimport { fetchSeedConfig } from \"../lib/seed/fetch-seed.js\";\nimport {\n registerExternalSkills,\n writeExternalSkills,\n type ExternalSkillInstall,\n} from \"../lib/seed/external-skills.js\";\nimport { seedToWizardResult, type SeedMapping } from \"../lib/seed/seed-to-wizard.js\";\nimport { getInstallationInfo } from \"../lib/plugins/plugin-info.js\";\nimport { loadProjectConfig } from \"../lib/configuration/project-config.js\";\nimport { resolveBranding } from \"../lib/configuration/config.js\";\nimport {\n type InstallMode,\n detectInstallation,\n detectGlobalInstallation,\n detectProjectInstallation,\n deriveInstallMode,\n resolveInstallPaths,\n buildAgentScopeMap,\n isHomeDirectory,\n INSTALL_MODE_LABELS,\n INSTALL_MODE_DESCRIPTIONS,\n} from \"../lib/installation/index.js\";\nimport { checkPermissions } from \"../lib/permission-checker.js\";\nimport {\n ASCII_LOGO,\n CLAUDE_SRC_DIR,\n CLI_INVOKE_COMMAND,\n DEFAULT_BRANDING,\n EDIT_PROJECT_SETUP_FLAG,\n EJECT_SOURCE,\n STANDARD_FILES,\n} from \"../consts.js\";\nimport { clearTerminalScreen } from \"../utils/terminal.js\";\nimport { SelectList, type SelectListItem } from \"../components/common/select-list.js\";\nimport { promptValue } from \"../components/common/prompt-confirm.js\";\nimport { Spinner } from \"../components/common/spinner.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport type { AgentName, MergedSkillsMatrix, SkillScope } from \"../types/index.js\";\nimport { type StartupMessage } from \"../utils/logger.js\";\nimport {\n INCOMPLETE_WORK_RECOVERY,\n STATUS_MESSAGES,\n agentsNotCompiled,\n carriedSkillsWritten,\n globalScopedAgentsHint,\n initSucceeded,\n sharedConfigExistingInstall,\n sharedConfigGlobalInstall,\n skippedUnknownAgents,\n skippedUnknownSkills,\n} from \"../utils/messages.js\";\nimport type { SeedPayload } from \"@workspace/matrix/seed\";\n\nconst DASHBOARD_OPTIONS = [\n { label: \"Edit\", value: \"edit\" },\n { label: \"Compile\", value: \"compile\" },\n { label: \"Doctor\", value: \"doctor\" },\n { label: \"List\", value: \"list\" },\n] as const satisfies readonly SelectListItem<string>[];\n\n/** The commands offered by the project dashboard (single source: DASHBOARD_OPTIONS). */\nexport type DashboardCommand = (typeof DASHBOARD_OPTIONS)[number][\"value\"];\n\n/**\n * The dashboard's title: {@link ASCII_LOGO} for an installation resting on the shipped branding,\n * and the configured name in its place for one that white-labels it.\n *\n * **The logo gives way rather than sitting above the name, because it spells the shipped name.**\n * `branding.name` replaces a heading everywhere else it is read — every configured leg of\n * `commands/branding-name-reaches-headings` asserts {@link DEFAULT_BRANDING.NAME} is ABSENT — so\n * painting `AGENTS INC` in block capitals above `Northwind` would leave the vendor's name at the\n * most prominent surface the product has, which is the one thing white-labelling is for.\n *\n * The default path is untouched by construction: {@link resolveBranding} answers\n * {@link DEFAULT_BRANDING.NAME} for a configuration with no `branding` key, so an unbranded\n * install takes the logo arm. A configuration naming the shipped name explicitly takes it too —\n * it asked for the shipped name and gets the shipped presentation of it.\n */\nconst DashboardTitle: React.FC<{ name: string }> = ({ name }) =>\n name === DEFAULT_BRANDING.NAME ? <Text>{ASCII_LOGO}</Text> : <Text bold>{name}</Text>;\n\ntype DashboardProps = {\n /** The resolved branding name, as {@link DashboardData.name} carries it. */\n name: string;\n onSelect: (command: DashboardCommand) => void;\n onCancel: () => void;\n};\n\nconst Dashboard: React.FC<DashboardProps> = ({ name, onSelect, onCancel }) => {\n const { exit } = useApp();\n const { rows: terminalHeight } = useTerminalDimensions();\n\n return (\n <Box flexDirection=\"column\" height={terminalHeight}>\n <Box marginBottom={1}>\n <DashboardTitle name={name} />\n </Box>\n <SelectList\n items={DASHBOARD_OPTIONS}\n onSelect={(command) => {\n onSelect(command);\n exit();\n }}\n onCancel={() => {\n onCancel();\n exit();\n }}\n />\n </Box>\n );\n};\n\n/** Formats the dashboard summary as plain text lines (for non-interactive/test output). */\nexport function formatDashboardText(data: DashboardData): string {\n const modeLabel = INSTALL_MODE_LABELS[data.mode];\n const lines = [\n data.name,\n \"\",\n ` Skills: ${data.skillCount} installed`,\n ` Agents: ${data.agentCount} compiled`,\n ` Mode: ${modeLabel}`,\n ];\n if (data.source) {\n lines.push(` Marketplace: ${data.source}`);\n }\n lines.push(\"\");\n lines.push(` [Edit] [Compile] [Doctor] [List]`);\n return lines.join(\"\\n\");\n}\n\n/**\n * Shows the project dashboard and returns the selected command (or null if cancelled).\n * In non-interactive environments (no TTY), prints the summary text and returns null.\n */\nexport async function showDashboard(\n projectDir: string,\n log?: (message: string) => void,\n): Promise<DashboardCommand | null> {\n const data = await getDashboardData(projectDir);\n\n // Non-interactive: print text summary and exit (CI, piped, tests)\n if (!process.stdin.isTTY) {\n const output = log ?? console.log;\n output(formatDashboardText(data));\n return null;\n }\n\n // First-wins resolution via promptValue; clearOnResolve repaints a clean\n // terminal before unmount (dashboard occupies the full height).\n const selectedCommand = await promptValue<DashboardCommand | null>(\n (resolve) => (\n <Dashboard\n name={data.name}\n onSelect={(command) => resolve(command)}\n onCancel={() => resolve(null)}\n />\n ),\n { onExit: null, clearOnResolve: true },\n );\n\n clearTerminalScreen();\n\n return selectedCommand;\n}\n\n/**\n * Why the dashboard is on screen.\n *\n * `\"init\"` — the user ran `cc init` in an already-installed directory. That is a request\n * to set this project up, so choosing Edit continues the setup: it must materialise the\n * project even if the wizard changes nothing.\n *\n * `\"standalone\"` — the bare `cc` dashboard. Edit is just an editor there; a pass with no\n * changes is an inspection and must leave the filesystem untouched.\n */\nexport type DashboardOrigin = \"init\" | \"standalone\";\n\n/** The extra argv a dashboard selection needs to carry its origin into the command. */\nfunction dashboardCommandArgv(command: DashboardCommand, origin: DashboardOrigin): string[] {\n if (command !== \"edit\" || origin !== \"init\") return [];\n return [`--${EDIT_PROJECT_SETUP_FLAG}`];\n}\n\n/**\n * Shared dashboard entry: when the project is already initialized, shows the\n * dashboard and runs the chosen command. Returns true when the project was\n * initialized (dashboard shown), false otherwise. Never exits the process —\n * callers decide (the init hook exits SUCCESS at its own call site).\n */\nexport async function runDashboardFlow(\n projectDir: string,\n config: Interfaces.Config,\n origin: DashboardOrigin,\n log?: (message: string) => void,\n): Promise<boolean> {\n const installation = await detectInstallation(projectDir);\n if (!installation) return false;\n\n const selectedCommand = await showDashboard(projectDir, log);\n if (selectedCommand) {\n await config.runCommand(selectedCommand, dashboardCommandArgv(selectedCommand, origin));\n }\n return true;\n}\n\n/**\n * What `init` decided to install, and the little each producer knows that the shared spine does\n * not. Keeping these on the value rather than branching on a flag downstream is what stops the\n * two paths growing separate copies of the install sequence.\n */\n/**\n * The marketplace this run was pointed at, as oclif hands it over.\n *\n * `marketplace` is a required key holding `string | undefined` rather than\n * `marketplace?: string` because that is what oclif produces: a non-required flag still gets\n * its key written on the parse result, set to `undefined` when it was not passed. Under\n * `exactOptionalPropertyTypes` the two are different types, and `?` would be describing a\n * producer that never omits the key.\n */\ntype SourceFlags = { marketplace: string | undefined };\n\ntype Selection = {\n result: WizardResultV2;\n sourceResult: SourceLoadResult;\n /**\n * The marketplace this selection was actually loaded from, which the shared spine records in\n * the written config. Carried on the value because a shared id may name one the command line\n * did not, and the install has to record where its skills really came from either way.\n */\n sourceFlags: SourceFlags;\n /** Whether a person is at the terminal, so the permission notice may wait for them. */\n interactive: boolean;\n /** What to say if the selection turns out to be empty — only the producer knows why it is. */\n emptyMessage: string;\n};\n\n/**\n * Whether a decoded selection would write anything into the user's own ~/.claude. Skills and\n * sub-agents are asked separately because either can be globally scoped on its own: a shared\n * configuration can pin every skill to the project and still send a sub-agent home, and the\n * reverse.\n */\nfunction writesGlobalContent(result: WizardResultV2): boolean {\n return (\n result.skills.some((skill) => skill.scope === \"global\") ||\n result.agentConfigs.some((agent) => agent.scope === \"global\")\n );\n}\n\n/**\n * Which marketplace a shared configuration installs from.\n *\n * A payload names the one its skills were fetched from, because a skill id carries whose skill it\n * is and never where that repository lives — so without the ref the load walks on to the default\n * public catalogue and installs a different repository's skill under the same id.\n *\n * `--marketplace` still outranks it: naming one is an instruction about THIS install, while the\n * payload's ref is a record of where the sharer's came from. A payload that names none leaves the\n * flag undefined, which puts the load back on the rungs it has always walked.\n */\nfunction sharedConfigSourceFlags(flags: SourceFlags, payload: SeedPayload): SourceFlags {\n return { marketplace: flags.marketplace ?? payload.marketplace };\n}\n\nexport default class Init extends BaseCommand {\n /**\n * The name this run prints itself under, resolved once on {@link install}'s spine because the\n * closing line is printed several calls below it. Same shape and same reason as `uninstall`'s\n * field: a plain `string` holding the shipped default rather than an optional every reader\n * would have to answer for.\n */\n private brandingName: string = DEFAULT_BRANDING.NAME;\n\n static summary = `Initialize ${DEFAULT_BRANDING.NAME} in this project`;\n static description =\n \"Interactive wizard to set up skills and agents. Supports Plugin Mode (native install) and Eject Mode (copy to .claude/).\";\n\n static examples = [\n {\n description: \"Start the setup wizard\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n {\n description: \"Initialize from a custom marketplace\",\n command: \"<%= config.bin %> <%= command.id %> --marketplace github:org/marketplace\",\n },\n ];\n\n static flags = {\n marketplace: Flags.string({\n char: \"m\",\n description: \"Skills marketplace path or URL\",\n required: false,\n }),\n from: Flags.string({\n description: \"Install a configuration shared from agentsinc.sh by its id, without the wizard\",\n helpValue: \"<id>\",\n }),\n };\n\n /**\n * The command in two statements: do the work, then answer for it.\n *\n * {@link install} owns every path through the setup and returns however it likes; the exit\n * code is decided once, here, after the last of them. Deciding it inside would mean deciding\n * it at each of that method's endings, and an ending added later would inherit the exit-0\n * default silently — which is the defect this pair exists to close. `edit` is two statements\n * for the same reason.\n */\n async run(): Promise<void> {\n await this.install();\n this.exitIfWorkIncomplete();\n }\n\n /**\n * One spine, two producers. The wizard and a shared id differ only in *where the selection\n * comes from* — everything after it (the empty guard, the install pipeline) is identical, so it\n * lives here once rather than being written twice and drifting.\n */\n private async install(): Promise<void> {\n const { flags } = await this.parse(Init);\n const projectDir = process.cwd();\n\n // Every route below reads the configs first — to show a dashboard, to refuse a shared id, or\n // to inline the global one. One that exists but cannot be read is recreated, not installed\n // over, and saying so here is what keeps the raw loader error off the screen.\n await this.ensureConfigReadable(projectDir);\n\n // Read once on the spine, because the closing line is printed several calls below it. The\n // degrade arm of `resolveBrandingName` cannot fire here: the line above has already refused\n // every config this would read.\n this.brandingName = await this.resolveBrandingName(projectDir);\n\n // Only a bare `init` is diverted to the dashboard. An id is an explicit instruction to install\n // *that* configuration, so it overrides an existing installation instead.\n if (!flags.from && (await this.showDashboardIfInitialized(projectDir))) return;\n\n const selection = flags.from\n ? await this.selectionFromSharedConfig(flags.from, flags, projectDir)\n : await this.selectionFromWizard(flags, projectDir);\n\n if (!selection) this.exit(EXIT_CODES.CANCELLED);\n\n // On the spine rather than in either producer: a broken constraint is a fact about the\n // selection, not about where it came from, and `edit` reports the same fact the same way\n // the moment the wizard hands it one. Both producers run the same validator over the same\n // matrix — the wizard over what was chosen, `--from` over what survived the decode — so\n // what is said here is this catalog's verdict either way.\n this.reportValidationErrors(selection.result.validation);\n\n // A sub-agent is installable on its own — it has front-matter, a prompt and a compiled file\n // without owning a single skill — so only a selection with neither is nothing to install.\n if (selection.result.skills.length === 0 && selection.result.selectedAgents.length === 0) {\n // The producer supplies the wording because only it knows why empty means what it means:\n // nothing chosen, versus a payload this catalog cannot install.\n this.error(selection.emptyMessage, { exit: EXIT_CODES.ERROR });\n }\n\n await this.handleInstallation(\n selection.result,\n selection.sourceResult,\n selection.sourceFlags,\n selection.interactive,\n );\n }\n\n /** The interactive producer: load the source, run the wizard, return what was chosen. */\n private async selectionFromWizard(\n flags: SourceFlags,\n projectDir: string,\n ): Promise<Selection | null> {\n // The blank global config is created by writeProjectConfig() once the\n // wizard succeeds, never before it renders: a cancelled init must leave no\n // artifact that the next run could mistake for an existing installation.\n const isGlobalRoot = isHomeDirectory(projectDir);\n\n const { sourceResult, startupMessages } = await this.loadWizardInputsUnderSpinner(flags);\n\n const result = await this.runWizard(startupMessages, isGlobalRoot);\n if (!result) return null;\n\n return {\n result,\n sourceResult,\n sourceFlags: flags,\n // A person is already at the terminal, so the permission notice can wait for them.\n interactive: true,\n emptyMessage: \"No skills selected\",\n };\n }\n\n /**\n * Everything the wizard needs, loaded behind a spinner that comes down whichever way the\n * await ends.\n *\n * The cleanup is a `finally` because a source that cannot be loaded refuses the run from\n * inside this await, and oclif would otherwise paint its error under an Ink tree still\n * repainting over it. Never a `catch`: the throw reaches oclif untouched, or both the\n * error rendering and the exit code change with it.\n */\n private async loadWizardInputsUnderSpinner(flags: SourceFlags): Promise<{\n sourceResult: SourceLoadResult;\n startupMessages: StartupMessage[];\n }> {\n const { unmount, clear: clearSpinner } = render(\n <Spinner label={STATUS_MESSAGES.LOADING_SKILLS} />,\n );\n try {\n return await this.loadSourceOrFail(flags);\n } finally {\n clearSpinner();\n unmount();\n }\n }\n\n /**\n * The `--from <id>` producer: fetch and map, no wizard. Nothing here may assume a TTY — running\n * headless is most of why the flag exists.\n *\n * It is also greenfield-only, which is what two of the three refusals are: a shared\n * configuration is installed whole, so anything it would have to install over has to be\n * uninstalled first. The third is about the LOCATION rather than what is already in it — a\n * global installation holds only global-scoped content, and this is the one producer that never\n * asked. All three fire before anything is written.\n */\n private async selectionFromSharedConfig(\n id: string,\n flags: SourceFlags,\n projectDir: string,\n ): Promise<Selection> {\n await this.refuseInstalledProject(projectDir);\n\n this.log(`Fetching configuration ${id}...`);\n const fetched = await fetchSeedConfig(id);\n if (!fetched.ok) {\n this.error(fetched.error, { exit: EXIT_CODES.ERROR });\n }\n\n const sourceFlags = sharedConfigSourceFlags(flags, fetched.payload);\n const { sourceResult } = await this.loadSourceOrFail(sourceFlags);\n // Before the decode, because a skill the payload CARRIES answers to no catalogue: unseated,\n // its id is skipped like any other unknown one and its content is never read.\n const carriedSkills = this.registerExternalSkillsOrFail(\n fetched.payload,\n sourceResult.matrix,\n projectDir,\n );\n const { result, skippedSkillIds, skippedAgentNames } = this.decodeSeedOrFail(\n fetched.payload,\n sourceResult.matrix,\n );\n\n // The location refusal is `BaseCommand`'s, because `edit --from` reaches the same\n // contradiction through the other door and an invariant enforced on one producer is enforced\n // nowhere. It runs before {@link refuseBlockingGlobalInstall} because it needs no filesystem\n // probe to answer: where the install root is, and what the payload said, is all of it.\n this.refuseProjectScopedContentAtHome(result, projectDir);\n await this.refuseBlockingGlobalInstall(result);\n\n // After the refusals and before the install: every refusal on this path fires with nothing\n // written, and the copy step that follows finds these skills already where they belong.\n await this.writeCarriedSkills(carriedSkills);\n\n // Named, not counted. \"3 skills were skipped\" cannot be acted on; the ids can, and this is the\n // one moment the user can tell whether what they shared is what they are getting. Worded once,\n // in `messages.ts`, because `edit --from` reports the same skips about the same wire.\n if (skippedSkillIds.length > 0) this.warn(skippedUnknownSkills(skippedSkillIds));\n if (skippedAgentNames.length > 0) this.warn(skippedUnknownAgents(skippedAgentNames));\n\n if (result.skills.length > 0) {\n this.log(\n `Installing ${result.skills.length} skill(s) across ${result.selectedAgents.length} sub-agent(s)\\n`,\n );\n }\n\n return {\n result,\n sourceResult,\n sourceFlags,\n interactive: false,\n emptyMessage: `Configuration '${id}' contains no skills this catalog can install.`,\n };\n }\n\n /**\n * Refuses to install a shared configuration into a directory that already has one.\n *\n * Project-scoped detection rather than `detectInstallation`, whose global fallback would refuse\n * every clean project on a machine with a global install — including for a payload that never\n * goes near it. Whether a global install is in the way is a question about the PAYLOAD, and\n * {@link refuseBlockingGlobalInstall} is where it is asked.\n *\n * This runs before the fetch: there is nothing to learn from the network about a directory that\n * is already spoken for.\n */\n private async refuseInstalledProject(projectDir: string): Promise<void> {\n const installation = await detectProjectInstallation(projectDir);\n if (!installation) return;\n\n this.error(sharedConfigExistingInstall(installation.configPath), { exit: EXIT_CODES.ERROR });\n }\n\n /**\n * The other half of the same rule. A payload carrying global-scoped skills or sub-agents writes\n * into the user's own ~/.claude, so an installation there is in its way even when this project\n * is spotless. A payload with nothing global cannot reach that far and is never refused for it.\n */\n private async refuseBlockingGlobalInstall(result: WizardResultV2): Promise<void> {\n if (!writesGlobalContent(result)) return;\n\n const globalInstallation = await detectGlobalInstallation();\n if (!globalInstallation) return;\n\n this.error(sharedConfigGlobalInstall(globalInstallation.configPath), {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n /**\n * The decode refuses a payload the config model has nowhere to write (see `seedToWizardResult`).\n * That is a failure of this command, reported with this command's exit code rather than left to\n * surface as an unhandled throw.\n */\n private decodeSeedOrFail(payload: SeedPayload, matrix: MergedSkillsMatrix): SeedMapping {\n try {\n return seedToWizardResult(payload, matrix);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Seats the catalogue entries the payload carries with it, or refuses the run.\n *\n * The refusal is `registerExternalSkills`' own — a carried skill asked for as a plugin, which\n * no marketplace serves — and is reported with this command's exit code for the same reason the\n * decode's is.\n */\n private registerExternalSkillsOrFail(\n payload: SeedPayload,\n matrix: MergedSkillsMatrix,\n projectDir: string,\n ): ExternalSkillInstall[] {\n try {\n return registerExternalSkills(payload, matrix, projectDir);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /** Writes the skills the payload brought with it, and says which they were. */\n private async writeCarriedSkills(carried: ExternalSkillInstall[]): Promise<void> {\n if (carried.length === 0) return;\n\n await writeExternalSkills(carried);\n // Named rather than counted, like the skips: these are the entries no catalogue can explain,\n // so this line is the only place the user learns what arrived with the configuration itself.\n this.log(carriedSkillsWritten(carried.map((skill) => skill.id)));\n }\n\n private async showDashboardIfInitialized(projectDir: string): Promise<boolean> {\n return runDashboardFlow(projectDir, this.config, \"init\", (msg) => this.log(msg));\n }\n\n private async loadSourceOrFail(\n flags: SourceFlags,\n ): Promise<{ sourceResult: SourceLoadResult; startupMessages: StartupMessage[] }> {\n try {\n const loaded = await loadSource({\n // The one load that may CHOOSE a marketplace rather than read the stored one.\n caller: \"init\",\n ...(flags.marketplace !== undefined && { sourceFlag: flags.marketplace }),\n projectDir: process.cwd(),\n captureStartupMessages: true,\n });\n return { sourceResult: loaded.sourceResult, startupMessages: loaded.startupMessages };\n } catch (error) {\n this.error(getErrorMessage(error), {\n exit: EXIT_CODES.ERROR,\n });\n }\n }\n\n /**\n * `init`'s wizard opens on an empty selection, and can open on nothing else: it is reached\n * only once {@link showDashboardIfInitialized} has found no installation, and that check\n * falls back to the home directory — so a global roster to hydrate from would have diverted\n * this run to the dashboard before the wizard was built. Hydrating a saved selection is\n * `edit`'s job, and `Edit.runEditWizard` is where it happens.\n */\n private async runWizard(\n startupMessages: StartupMessage[],\n isGlobalRoot: boolean,\n ): Promise<WizardResultV2 | null> {\n return runWizardSession({\n hydrate: { isEditingFromGlobalScope: isGlobalRoot },\n props: {\n version: this.config.version,\n logo: ASCII_LOGO,\n startupMessages,\n },\n onCancel: () => this.log(\"Setup cancelled\"),\n clearTerminal: () => this.clearTerminal(),\n });\n }\n\n private async handleInstallation(\n result: WizardResultV2,\n sourceResult: SourceLoadResult,\n flags: SourceFlags,\n /**\n * Whether the caller can hold the terminal. The permission notice is an Ink app with no exit\n * of its own, so `waitUntilExit()` only ever resolves because a person is there to end it —\n * which is fine after the wizard and a hang everywhere else. `--from` sets this false: it has\n * to complete over a pipe and in CI.\n */\n interactive = true,\n ): Promise<void> {\n const projectDir = process.cwd();\n const activeSkills = result.skills.filter((s) => !s.excluded);\n const installMode = deriveInstallMode(activeSkills);\n const ejectedSkills = activeSkills.filter((s) => s.origin === EJECT_SOURCE);\n const pluginSkills = activeSkills.filter((s) => s.origin !== EJECT_SOURCE);\n\n this.logInstallPlan(installMode, ejectedSkills, pluginSkills);\n\n // Resolve marketplace up front — BEFORE any filesystem mutation. If\n // resolution fails in mixed mode, the hard-error must fire before\n // `copyEjectSkillsStep` copies anything to `.claude/skills/`, otherwise\n // we leave an orphaned half-install with no config.ts to recognise it.\n const resolvedMarketplace =\n pluginSkills.length > 0\n ? await this.requireMarketplaceOrExit(\n sourceResult,\n \"install plugin skills\",\n (marketplace) => this.log(`Registering marketplace \"${marketplace}\"...`),\n )\n : null;\n\n const copyResult =\n installMode === \"eject\" || installMode === \"mixed\"\n ? await this.copyEjectSkillsStep(ejectedSkills, projectDir, sourceResult, installMode)\n : null;\n\n if (resolvedMarketplace !== null) {\n await this.installPluginSkillsReported(\n pluginSkills,\n resolvedMarketplace,\n projectDir,\n sourceResult.matrix,\n );\n }\n // The shared install reporter hard-errors on any failure, so reaching here with\n // a resolved marketplace means plugin mode fully succeeded.\n const pluginModeSucceeded = resolvedMarketplace !== null;\n\n try {\n const { configResult, compileResult, agentScopeMap } = await this.writeConfigAndCompile(\n result,\n sourceResult,\n flags,\n );\n this.reportSuccess(\n configResult,\n compileResult,\n agentScopeMap,\n installMode,\n pluginModeSucceeded,\n copyResult,\n );\n\n await this.showPermissionNotice(projectDir, interactive);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * The permission notice, where there is one to show. It is an Ink app with no exit of its own,\n * so `waitUntilExit()` only ever resolves because a person is there to end it — which is fine\n * after the wizard and a hang everywhere else. Without a terminal to hold, one frame is\n * rendered and let go: the notice is information, not a prompt, so there is nothing to answer\n * and nothing to wait for.\n */\n private async showPermissionNotice(projectDir: string, interactive: boolean): Promise<void> {\n const permissionWarning = await checkPermissions(projectDir);\n if (!permissionWarning) return;\n\n if (!interactive) {\n const { unmount } = render(permissionWarning);\n unmount();\n return;\n }\n\n const { waitUntilExit } = render(permissionWarning);\n await waitUntilExit();\n }\n\n private logInstallPlan(\n installMode: InstallMode,\n ejectedSkills: WizardResultV2[\"skills\"],\n pluginSkills: WizardResultV2[\"skills\"],\n ): void {\n this.log(\"\\n\");\n this.log(`Selected ${ejectedSkills.length + pluginSkills.length} skills`);\n this.log(\n `Install mode: ${\n installMode === \"mixed\"\n ? `${INSTALL_MODE_LABELS.mixed} (${ejectedSkills.length} eject, ${pluginSkills.length} plugin)`\n : INSTALL_MODE_DESCRIPTIONS[installMode]\n }`,\n );\n }\n\n private async copyEjectSkillsStep(\n localSkills: WizardResultV2[\"skills\"],\n projectDir: string,\n sourceResult: SourceLoadResult,\n installMode: InstallMode,\n ): Promise<SkillCopyResult> {\n this.log(\"Copying skills to local directory...\");\n const copyResult = await copyLocalSkills(localSkills, projectDir, sourceResult);\n\n if (installMode === \"mixed\") {\n if (copyResult.projectCopied.length > 0 && copyResult.globalCopied.length > 0) {\n this.log(\n `Copied ${copyResult.totalCopied} local skills (${copyResult.projectCopied.length} project, ${copyResult.globalCopied.length} global)`,\n );\n } else if (copyResult.globalCopied.length > 0) {\n this.log(`Copied ${copyResult.globalCopied.length} local skills to ~/.claude/skills/`);\n } else {\n this.log(`Copied ${copyResult.projectCopied.length} local skills to .claude/skills/`);\n }\n } else {\n this.log(`Copied ${copyResult.totalCopied} skills to .claude/skills/\\n`);\n }\n\n return copyResult;\n }\n\n private async writeConfigAndCompile(\n result: WizardResultV2,\n sourceResult: SourceLoadResult,\n flags: SourceFlags,\n ): Promise<{\n configResult: Awaited<ReturnType<typeof writeProjectConfig>>;\n compileResult: CompilationResult;\n agentScopeMap: Map<AgentName, SkillScope>;\n }> {\n this.log(\"Generating configuration...\");\n const configResult = await writeProjectConfig({\n wizardResult: result,\n sourceResult,\n projectDir: process.cwd(),\n ...(flags.marketplace !== undefined && { sourceFlag: flags.marketplace }),\n });\n\n if (configResult.wasMerged) {\n this.log(`Merged with existing config at ${configResult.existingConfigPath}`);\n }\n\n this.log(`Configuration saved (${configResult.config.agents.length} agents)\\n`);\n this.reportUnassignedSkills(configResult.config);\n\n this.log(STATUS_MESSAGES.COMPILING_AGENTS);\n const cwd = process.cwd();\n const agentDefs = await loadAgentDefs();\n const { allSkills } = await discoverInstalledSkills(cwd);\n const agentScopeMap = buildAgentScopeMap(configResult.config);\n const compileResult = await compileAgentsAllScopes({\n projectDir: cwd,\n sourcePath: agentDefs.sourcePath,\n skills: allSkills,\n agentScopeMap,\n });\n this.reportCompilation(compileResult);\n\n this.reportPropagatedRecompile(configResult.propagation);\n\n return { configResult, compileResult, agentScopeMap };\n }\n\n /**\n * What the compile pass did, including the half this command used to drop.\n *\n * It read `compiled` and nothing else, so a pass that lost a sub-agent printed a number that\n * looked perfectly right — `compiled` counts successes, so it is correct either way — and the\n * failures reached no surface at all: no count, no reason, no exit code. A user's FIRST\n * install could silently land a roster missing a sub-agent.\n *\n * The compile is the last thing `init` does, so a failure here cannot be answered by aborting:\n * the skills are on disk and `config.ts` and `config-types.ts` describe them. What is owed is\n * the account, which {@link BaseCommand.exitIfWorkIncomplete} prints and answers for.\n */\n private reportCompilation(compileResult: CompilationResult): void {\n const { compiled, failed, warnings } = compileResult;\n const summary = `Compiled ${compiled.length} agents`;\n\n if (failed.length === 0) {\n this.log(`${summary}\\n`);\n return;\n }\n\n this.log(`${summary} (${failed.length} failed)\\n`);\n for (const warning of warnings) {\n this.warn(warning);\n }\n // Recorded off `failed` rather than off the warnings just printed: `warnings` also carries\n // entries that are not failures — a scope with nothing to compile contributes one on every\n // project-context run — and the ending must not file those as work owed.\n this.recordIncompleteWork(agentsNotCompiled(failed), INCOMPLETE_WORK_RECOVERY.RECOMPILE);\n }\n\n private reportSuccess(\n configResult: Awaited<ReturnType<typeof writeProjectConfig>>,\n compileResult: CompilationResult,\n agentScopeMap: Map<AgentName, SkillScope>,\n installMode: InstallMode,\n pluginModeSucceeded: boolean,\n copyResult: SkillCopyResult | null,\n ): void {\n // A run with work owed ends on the failure account instead — `initialized successfully!`\n // over a roster missing a sub-agent is the claim being withdrawn, not a line beside it.\n // Where the install landed is still reported below: that is what the account is about.\n if (!this.hasIncompleteWork) this.log(`${initSucceeded(this.brandingName)}\\n`);\n\n const isEjectOutput =\n installMode === \"eject\" || (installMode === \"mixed\" && !pluginModeSucceeded);\n if (isEjectOutput && copyResult && copyResult.totalCopied > 0) {\n this.reportSkillsCopied(copyResult);\n }\n this.reportAgentsCompiled(compileResult.compiled, agentScopeMap);\n this.reportConfiguration(configResult.configPath, agentScopeMap);\n }\n\n /**\n * Names the config that actually holds this install's assignments, and where a\n * recompile of them has to be run from.\n *\n * Split by the same `agentScopeMap` the two reporters above split on, because the\n * same scope decides both. A project config's `stack` is filtered down to\n * project-scoped agents on the way out, so a wholly GLOBAL install leaves it\n * carrying no assignment at all — naming it sends the user to a file with nothing\n * in it — and `compile` in this cwd runs the PROJECT pass, which recompiles no\n * global agent. At the home root both scopes resolve to one file and one pass, so\n * there is nothing to split and the project wording stands.\n */\n private reportConfiguration(\n projectConfigPath: string,\n agentScopeMap: Map<AgentName, SkillScope>,\n ): void {\n const cwd = process.cwd();\n const paths = {\n global: resolveInstallPaths(cwd, \"global\").configPath,\n project: projectConfigPath,\n };\n const split = splitAgentScopes(cwd, agentScopeMap);\n\n this.log(\"Configuration:\");\n for (const configPath of configsHoldingAssignments(split, paths)) {\n this.log(` ${configPath}`);\n }\n this.log(\"\");\n\n this.log(\"To customize agent-skill assignments:\");\n for (const [index, step] of customizationSteps(split, paths.global).entries()) {\n this.log(` ${index + 1}. ${step}`);\n }\n this.log(\"\");\n }\n\n /**\n * Reports where the skills actually landed. `copyLocalSkills` splits by scope,\n * so a default install driven from a project directory writes every skill\n * under HOME — reporting the project path there names a directory that was\n * never written.\n *\n * This block is a filesystem listing, so the entries are the on-disk directory\n * names — skill ids, not display names. `copySkillsToLocalFlattened` names each\n * destination directory after `skill.id`, so a user can copy any line and `cd`\n * into it.\n */\n private reportSkillsCopied(copyResult: SkillCopyResult): void {\n const cwd = process.cwd();\n const groups = isHomeDirectory(cwd)\n ? [\n {\n dir: resolveInstallPaths(cwd, \"project\").skillsDir,\n copied: [...copyResult.globalCopied, ...copyResult.projectCopied],\n },\n ]\n : [\n { dir: resolveInstallPaths(cwd, \"global\").skillsDir, copied: copyResult.globalCopied },\n { dir: resolveInstallPaths(cwd, \"project\").skillsDir, copied: copyResult.projectCopied },\n ].filter((group) => group.copied.length > 0);\n\n for (const group of groups) {\n this.log(\"Skills copied to:\");\n this.log(` ${group.dir}`);\n for (const copied of group.copied) {\n this.log(` ${copied.skillId}/`);\n }\n this.log(\"\");\n }\n }\n\n /**\n * Reports where the agents actually landed, mirroring the scope split\n * `compileAgentsAllScopes` performs: one pass at the home root, otherwise a\n * global pass under HOME and a project pass under the project directory.\n */\n private reportAgentsCompiled(\n compiled: AgentName[],\n agentScopeMap: Map<AgentName, SkillScope>,\n ): void {\n const cwd = process.cwd();\n const groups = isHomeDirectory(cwd)\n ? [{ dir: resolveInstallPaths(cwd, \"project\").agentsDir, agents: compiled }]\n : [\n {\n dir: resolveInstallPaths(cwd, \"global\").agentsDir,\n agents: compiled.filter((name) => agentScopeMap.get(name) === \"global\"),\n },\n {\n dir: resolveInstallPaths(cwd, \"project\").agentsDir,\n agents: compiled.filter((name) => agentScopeMap.get(name) !== \"global\"),\n },\n ].filter((group) => group.agents.length > 0);\n\n for (const group of groups) {\n this.log(\"Agents compiled to:\");\n this.log(` ${group.dir}`);\n for (const agentName of group.agents) {\n this.log(` ${agentName}.md`);\n }\n this.log(\"\");\n }\n }\n}\n\n/** The two config files an install can write, as the closing block refers to them. */\ntype ConfigPaths = { global: string; project: string };\n\n/** How this install's sub-agents fall across the two scopes, seen from the directory it ran in. */\ntype AgentScopeSplit = { globalAgentCount: number; isGlobalOnly: boolean };\n\n/**\n * At the home root the two scopes resolve to ONE config file and ONE compile pass, so there\n * is nothing to split and the split reports none — which is what leaves the project wording\n * standing there unchanged. Same fork `reportAgentsCompiled` makes over the same question.\n */\nfunction splitAgentScopes(cwd: string, agentScopeMap: Map<AgentName, SkillScope>): AgentScopeSplit {\n if (isHomeDirectory(cwd)) return { globalAgentCount: 0, isGlobalOnly: false };\n\n const scopes = [...agentScopeMap.values()];\n const globalAgentCount = scopes.filter((scope) => scope === \"global\").length;\n return {\n globalAgentCount,\n isGlobalOnly: globalAgentCount > 0 && globalAgentCount === scopes.length,\n };\n}\n\n/**\n * The config file(s) this install's assignments actually landed in. A wholly global install\n * has none in the project file — the writer filters its `stack` down to project-scoped\n * agents — so naming it would send the user to a file with nothing in it.\n */\nfunction configsHoldingAssignments(split: AgentScopeSplit, paths: ConfigPaths): string[] {\n if (split.isGlobalOnly) return [paths.global];\n if (split.globalAgentCount > 0) return [paths.global, paths.project];\n return [paths.project];\n}\n\n/**\n * What changing an assignment takes, in the order it takes it. The compile step is the half\n * that has to be scope-aware: `compile` run in a project directory performs the PROJECT pass\n * only, so it recompiles no global agent — which `globalScopedAgentsHint` already says, in\n * the words `compile` itself says it in when it lands in the mirror image of this state.\n */\nfunction customizationSteps(split: AgentScopeSplit, globalConfigPath: string): string[] {\n if (split.isGlobalOnly) {\n return [`Edit ${globalConfigPath}`, globalScopedAgentsHint(split.globalAgentCount)];\n }\n\n return [\n `Edit ${CLAUDE_SRC_DIR}/${STANDARD_FILES.CONFIG_TS}`,\n `Run '${CLI_INVOKE_COMMAND} compile' to regenerate agents`,\n ...(split.globalAgentCount > 0 ? [globalScopedAgentsHint(split.globalAgentCount)] : []),\n ];\n}\n\nexport type DashboardData = {\n /**\n * The name the dashboard is titled with — `branding.name` where the configuration supplies one\n * and {@link DEFAULT_BRANDING.NAME} otherwise. Carried on the data rather than read by either\n * consumer so {@link formatDashboardText} stays a pure function of what it is handed, and so\n * the one place that reaches a configuration is the one that already loads it.\n *\n * **Both of {@link showDashboard}'s branches read it, and that is the invariant to keep.** This\n * field was resolved for the piped branch alone for as long as it was, while the `Dashboard`\n * component was handed only its callbacks and painted {@link ASCII_LOGO} — so the dashboard a\n * person actually sees was the one surface `branding.name` never reached, and every spec on the\n * subject drove through a pipe and could not see it.\n */\n name: string;\n skillCount: number;\n agentCount: number;\n mode: InstallMode;\n source?: string;\n};\n\n/**\n * Gathers dashboard data from the installation and project config.\n *\n * Both counts come from the same scope-aware installation so the summary cannot\n * mix a project-only figure with a global one — a default install driven from a\n * project directory puts every skill and agent under HOME.\n */\nexport async function getDashboardData(projectDir: string): Promise<DashboardData> {\n // ABORT is the posture on `resolveBranding`, and it is the one already in force: the\n // `loadProjectConfig` beside it raises for the same file, so a configuration that cannot be\n // evaluated fails this call whether branding is read or not. Nothing is degraded here that was\n // not already, and the dashboard is only reached once an installation has been detected.\n const [info, loaded, branding] = await Promise.all([\n getInstallationInfo(),\n loadProjectConfig(projectDir),\n resolveBranding(projectDir),\n ]);\n\n const activeSkills = loaded?.config.skills.filter((s) => !s.excluded);\n const skillCount = info?.skillCount ?? 0;\n const agentCount = info?.agentCount ?? 0;\n const mode = info?.mode ?? (activeSkills ? deriveInstallMode(activeSkills) : \"eject\");\n const source = loaded?.config.marketplace;\n\n return {\n name: branding.name,\n skillCount,\n agentCount,\n mode,\n ...(source !== undefined && { source }),\n };\n}\n","import React from \"react\";\nimport { z } from \"zod\";\n\nimport { Text, Box } from \"ink\";\nimport path from \"path\";\n\nimport { CLAUDE_DIR, CLI_COLORS, MAX_CONFIG_FILE_SIZE, STANDARD_FILES } from \"../consts\";\nimport { fileExists, readFileSafe } from \"../utils/fs\";\nimport { warn } from \"../utils/logger\";\nimport { settingsFileSchema } from \"./schemas\";\n\ntype SettingsFile = z.infer<typeof settingsFileSchema>;\ntype PermissionConfig = NonNullable<SettingsFile[\"permissions\"]>;\n\n/**\n * Reads one settings file's permissions block; undefined when absent, malformed, or empty.\n *\n * settings.json belongs to Claude Code, which adds keys on its own release schedule. This CLI\n * consumes `permissions` and owns nothing else in the file, so it stays silent about every other\n * field rather than warning about settings it has no standing to judge.\n */\nasync function readSettingsPermissions(filePath: string): Promise<PermissionConfig | undefined> {\n if (!(await fileExists(filePath))) return undefined;\n try {\n const content = await readFileSafe(filePath, MAX_CONFIG_FILE_SIZE);\n const raw: unknown = JSON.parse(content);\n const result = settingsFileSchema.safeParse(raw);\n const parsed: SettingsFile = result.success ? result.data : {};\n return parsed.permissions;\n } catch {\n warn(`Malformed settings file at '${filePath}' — skipping`);\n return undefined;\n }\n}\n\n/** Permissions from the first settings file that defines them — settings.local.json wins. */\nasync function loadPermissions(projectRoot: string): Promise<PermissionConfig | undefined> {\n const settingsPath = path.join(projectRoot, CLAUDE_DIR, STANDARD_FILES.SETTINGS_JSON);\n const localSettingsPath = path.join(projectRoot, CLAUDE_DIR, STANDARD_FILES.SETTINGS_LOCAL_JSON);\n\n for (const filePath of [localSettingsPath, settingsPath]) {\n const permissions = await readSettingsPermissions(filePath);\n if (permissions) return permissions;\n }\n return undefined;\n}\n\nexport async function checkPermissions(projectRoot: string): Promise<React.ReactElement | null> {\n const permissions = await loadPermissions(projectRoot);\n\n if (!permissions) {\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={CLI_COLORS.WARNING} padding={1}>\n <Text bold color={CLI_COLORS.WARNING}>\n Permission Notice\n </Text>\n <Text>No permissions configured in .claude/settings.json</Text>\n <Text>Agents will prompt for approval on each tool use.</Text>\n <Text> </Text>\n <Text>For autonomous operation, add to .claude/settings.json:</Text>\n <Text> </Text>\n <Text color={CLI_COLORS.DIM}>{\"{\"}</Text>\n <Text color={CLI_COLORS.DIM}>{' \"permissions\": {'}</Text>\n <Text color={CLI_COLORS.DIM}>{' \"allow\": ['}</Text>\n <Text color={CLI_COLORS.DIM}>{' \"Read(*)\",'}</Text>\n <Text color={CLI_COLORS.DIM}>{' \"Bash(git *)\",'}</Text>\n <Text color={CLI_COLORS.DIM}>{' \"Bash(bun *)\"'}</Text>\n <Text color={CLI_COLORS.DIM}>{\" ]\"}</Text>\n <Text color={CLI_COLORS.DIM}>{\" }\"}</Text>\n <Text color={CLI_COLORS.DIM}>{\"}\"}</Text>\n </Box>\n );\n }\n\n const hasRestrictiveBash = permissions.deny?.some(\n (rule) => rule === \"Bash(*)\" || rule === \"Bash\",\n );\n const hasNoAllows = !permissions.allow || permissions.allow.length === 0;\n\n if (hasRestrictiveBash || hasNoAllows) {\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={CLI_COLORS.WARNING} padding={1}>\n <Text bold color={CLI_COLORS.WARNING}>\n Permission Warnings\n </Text>\n {hasRestrictiveBash && (\n <Text>\n ⚠ Bash is denied in permissions. Some agents require Bash for git, testing, and build\n commands.\n </Text>\n )}\n {hasNoAllows && (\n <Text>⚠ No allow rules configured. Agents will prompt for each tool use.</Text>\n )}\n </Box>\n );\n }\n\n return null;\n}\n"],"mappings":"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","names":["Box","Text","jsx","jsxs","Text","Box"]}
@@ -2,16 +2,14 @@
2
2
  import {
3
3
  buildMarketplacePluginRef,
4
4
  claudePluginInstall,
5
+ getErrorMessage,
5
6
  isLocalOnlySkill,
6
7
  toClaudePluginScope
7
- } from "./chunk-WCAUUBHO.js";
8
- import {
9
- getErrorMessage
10
- } from "./chunk-XAXJWXI4.js";
8
+ } from "./chunk-RVXI5VQU.js";
11
9
  import {
12
10
  CLI_INVOKE_COMMAND,
13
11
  EJECT_SOURCE
14
- } from "./chunk-IO5YBKHV.js";
12
+ } from "./chunk-G6G2FT2G.js";
15
13
 
16
14
  // src/cli/lib/operations/skills/install-plugin-skills.ts
17
15
  function pluginInstallFailureError(failedCount) {
@@ -46,4 +44,4 @@ export {
46
44
  unbackedPluginInstallError,
47
45
  installPluginSkills
48
46
  };
49
- //# sourceMappingURL=chunk-UMH2YZKG.js.map
47
+ //# sourceMappingURL=chunk-4CIAZOTD.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/lib/operations/skills/install-plugin-skills.ts"],"sourcesContent":["import { claudePluginInstall } from \"../../../utils/exec.js\";\nimport { isLocalOnlySkill } from \"../../loading/multi-source-loader.js\";\nimport { buildMarketplacePluginRef, toClaudePluginScope } from \"../../plugins/index.js\";\nimport { getErrorMessage } from \"../../../utils/errors.js\";\nimport { CLI_INVOKE_COMMAND, EJECT_SOURCE } from \"../../../consts.js\";\nimport type { MergedSkillsMatrix, SkillId } from \"../../../types/index.js\";\nimport type { SkillConfig } from \"../../../types/config.js\";\n\nexport type PluginInstallResult = {\n installed: Array<{ id: SkillId; ref: string }>;\n failed: Array<{ id: SkillId; error: string }>;\n};\n\n/**\n * Hard-error message for failed plugin installs. Plugin install intent is\n * inviolable (never fall back to eject) — callers MUST error with this BEFORE\n * config is written, or config.ts gains orphan entries claiming the skill\n * is installed.\n */\nexport function pluginInstallFailureError(failedCount: number): string {\n return `Failed to install ${failedCount} plugin skill(s). Plugin install intent could not be honored. Verify the skill id matches the marketplace, run '${CLI_INVOKE_COMMAND} update' to refresh the marketplace, or switch affected skills to eject mode.`;\n}\n\n/**\n * Skills asking to be installed as plugins that no marketplace carries.\n *\n * A skill that exists only in this project cannot be pulled from anywhere, so the ask is\n * refusable BEFORE anything is attempted — which is what separates it from an install\n * that was tried and failed. The Sources grid reads {@link isLocalOnlySkill} to decide\n * whether to offer the plugin cell at all, so this guard shares it: a caller reaching\n * past that surface must meet the same rule it did.\n */\nexport function unbackedPluginSkillIds(\n skills: SkillConfig[],\n matrix: MergedSkillsMatrix,\n): SkillId[] {\n return skills\n .filter((skill) => skill.origin !== EJECT_SOURCE)\n .filter((skill) => isLocalOnlySkill(matrix.skills[skill.id]))\n .map((skill) => skill.id);\n}\n\n/**\n * The refusal text for {@link unbackedPluginSkillIds}. Deliberately NOT\n * {@link pluginInstallFailureError}: refreshing a marketplace and checking an id against\n * it are impossible instructions for a skill the user wrote themselves, so the two\n * failures owe different advice.\n */\nexport function unbackedPluginInstallError(ids: SkillId[]): string {\n return `Cannot install ${ids.length} skill(s) as plugins — no marketplace carries them: ${ids.join(\", \")}. A skill that exists only in this project can only be installed as a local copy. Set it to Local on the Sources step, or publish it to a marketplace first.`;\n}\n\n/**\n * Installs skill plugins via the Claude CLI, routing by scope.\n *\n * For each skill, constructs the plugin ref as `{skillId}@{marketplace}`\n * and invokes `claudePluginInstall` with the correct scope.\n */\nexport async function installPluginSkills(\n skills: SkillConfig[],\n marketplace: string,\n projectDir: string,\n): Promise<PluginInstallResult> {\n const pluginSkills = skills.filter((s) => s.origin !== EJECT_SOURCE);\n const installed: PluginInstallResult[\"installed\"] = [];\n const failed: PluginInstallResult[\"failed\"] = [];\n\n for (const skill of pluginSkills) {\n const pluginRef = buildMarketplacePluginRef(skill.id, marketplace);\n const pluginScope = toClaudePluginScope(skill.scope);\n try {\n await claudePluginInstall(pluginRef, pluginScope, projectDir);\n installed.push({ id: skill.id, ref: pluginRef });\n } catch (error) {\n failed.push({ id: skill.id, error: getErrorMessage(error) });\n }\n }\n\n return { installed, failed };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAmBO,SAAS,0BAA0B,aAA6B;AACrE,SAAO,qBAAqB,WAAW,mHAAmH,kBAAkB;AAC9K;AAWO,SAAS,uBACd,QACA,QACW;AACX,SAAO,OACJ,OAAO,CAAC,UAAU,MAAM,WAAW,YAAY,EAC/C,OAAO,CAAC,UAAU,iBAAiB,OAAO,OAAO,MAAM,EAAE,CAAC,CAAC,EAC3D,IAAI,CAAC,UAAU,MAAM,EAAE;AAC5B;AAQO,SAAS,2BAA2B,KAAwB;AACjE,SAAO,kBAAkB,IAAI,MAAM,4DAAuD,IAAI,KAAK,IAAI,CAAC;AAC1G;AAQA,eAAsB,oBACpB,QACA,aACA,YAC8B;AAC9B,QAAM,eAAe,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,YAAY;AACnE,QAAM,YAA8C,CAAC;AACrD,QAAM,SAAwC,CAAC;AAE/C,aAAW,SAAS,cAAc;AAChC,UAAM,YAAY,0BAA0B,MAAM,IAAI,WAAW;AACjE,UAAM,cAAc,oBAAoB,MAAM,KAAK;AACnD,QAAI;AACF,YAAM,oBAAoB,WAAW,aAAa,UAAU;AAC5D,gBAAU,KAAK,EAAE,IAAI,MAAM,IAAI,KAAK,UAAU,CAAC;AAAA,IACjD,SAAS,OAAO;AACd,aAAO,KAAK,EAAE,IAAI,MAAM,IAAI,OAAO,gBAAgB,KAAK,EAAE,CAAC;AAAA,IAC7D;AAAA,EACF;AAEA,SAAO,EAAE,WAAW,OAAO;AAC7B;","names":[]}
1
+ {"version":3,"sources":["../src/cli/lib/operations/skills/install-plugin-skills.ts"],"sourcesContent":["import { claudePluginInstall } from \"../../../utils/exec.js\";\nimport { isLocalOnlySkill } from \"../../loading/multi-source-loader.js\";\nimport { buildMarketplacePluginRef, toClaudePluginScope } from \"../../plugins/index.js\";\nimport { getErrorMessage } from \"../../../utils/errors.js\";\nimport { CLI_INVOKE_COMMAND, EJECT_SOURCE } from \"../../../consts.js\";\nimport type { MergedSkillsMatrix, SkillId } from \"../../../types/index.js\";\nimport type { SkillConfig } from \"../../../types/config.js\";\n\nexport type PluginInstallResult = {\n installed: Array<{ id: SkillId; ref: string }>;\n failed: Array<{ id: SkillId; error: string }>;\n};\n\n/**\n * Hard-error message for failed plugin installs. Plugin install intent is\n * inviolable (never fall back to eject) — callers MUST error with this BEFORE\n * config is written, or config.ts gains orphan entries claiming the skill\n * is installed.\n */\nexport function pluginInstallFailureError(failedCount: number): string {\n return `Failed to install ${failedCount} plugin skill(s). Plugin install intent could not be honored. Verify the skill id matches the marketplace, run '${CLI_INVOKE_COMMAND} update' to refresh the marketplace, or switch affected skills to eject mode.`;\n}\n\n/**\n * Skills asking to be installed as plugins that no marketplace carries.\n *\n * A skill that exists only in this project cannot be pulled from anywhere, so the ask is\n * refusable BEFORE anything is attempted — which is what separates it from an install\n * that was tried and failed. The Sources grid reads {@link isLocalOnlySkill} to decide\n * whether to offer the plugin cell at all, so this guard shares it: a caller reaching\n * past that surface must meet the same rule it did.\n */\nexport function unbackedPluginSkillIds(\n skills: SkillConfig[],\n matrix: MergedSkillsMatrix,\n): SkillId[] {\n return skills\n .filter((skill) => skill.origin !== EJECT_SOURCE)\n .filter((skill) => isLocalOnlySkill(matrix.skills[skill.id]))\n .map((skill) => skill.id);\n}\n\n/**\n * The refusal text for {@link unbackedPluginSkillIds}. Deliberately NOT\n * {@link pluginInstallFailureError}: refreshing a marketplace and checking an id against\n * it are impossible instructions for a skill the user wrote themselves, so the two\n * failures owe different advice.\n */\nexport function unbackedPluginInstallError(ids: SkillId[]): string {\n return `Cannot install ${ids.length} skill(s) as plugins — no marketplace carries them: ${ids.join(\", \")}. A skill that exists only in this project can only be installed as a local copy. Set it to Local on the Sources step, or publish it to a marketplace first.`;\n}\n\n/**\n * Installs skill plugins via the Claude CLI, routing by scope.\n *\n * For each skill, constructs the plugin ref as `{skillId}@{marketplace}`\n * and invokes `claudePluginInstall` with the correct scope.\n */\nexport async function installPluginSkills(\n skills: SkillConfig[],\n marketplace: string,\n projectDir: string,\n): Promise<PluginInstallResult> {\n const pluginSkills = skills.filter((s) => s.origin !== EJECT_SOURCE);\n const installed: PluginInstallResult[\"installed\"] = [];\n const failed: PluginInstallResult[\"failed\"] = [];\n\n for (const skill of pluginSkills) {\n const pluginRef = buildMarketplacePluginRef(skill.id, marketplace);\n const pluginScope = toClaudePluginScope(skill.scope);\n try {\n await claudePluginInstall(pluginRef, pluginScope, projectDir);\n installed.push({ id: skill.id, ref: pluginRef });\n } catch (error) {\n failed.push({ id: skill.id, error: getErrorMessage(error) });\n }\n }\n\n return { installed, failed };\n}\n"],"mappings":";;;;;;;;;;;;;;AAmBO,SAAS,0BAA0B,aAA6B;AACrE,SAAO,qBAAqB,WAAW,mHAAmH,kBAAkB;AAC9K;AAWO,SAAS,uBACd,QACA,QACW;AACX,SAAO,OACJ,OAAO,CAAC,UAAU,MAAM,WAAW,YAAY,EAC/C,OAAO,CAAC,UAAU,iBAAiB,OAAO,OAAO,MAAM,EAAE,CAAC,CAAC,EAC3D,IAAI,CAAC,UAAU,MAAM,EAAE;AAC5B;AAQO,SAAS,2BAA2B,KAAwB;AACjE,SAAO,kBAAkB,IAAI,MAAM,4DAAuD,IAAI,KAAK,IAAI,CAAC;AAC1G;AAQA,eAAsB,oBACpB,QACA,aACA,YAC8B;AAC9B,QAAM,eAAe,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,YAAY;AACnE,QAAM,YAA8C,CAAC;AACrD,QAAM,SAAwC,CAAC;AAE/C,aAAW,SAAS,cAAc;AAChC,UAAM,YAAY,0BAA0B,MAAM,IAAI,WAAW;AACjE,UAAM,cAAc,oBAAoB,MAAM,KAAK;AACnD,QAAI;AACF,YAAM,oBAAoB,WAAW,aAAa,UAAU;AAC5D,gBAAU,KAAK,EAAE,IAAI,MAAM,IAAI,KAAK,UAAU,CAAC;AAAA,IACjD,SAAS,OAAO;AACd,aAAO,KAAK,EAAE,IAAI,MAAM,IAAI,OAAO,gBAAgB,KAAK,EAAE,CAAC;AAAA,IAC7D;AAAA,EACF;AAEA,SAAO,EAAE,WAAW,OAAO;AAC7B;","names":[]}