agents-inc 0.170.1 → 0.170.2

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 (163) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/{chunk-BMRUNMPV.js → chunk-2YA4DDRM.js} +35 -35
  3. package/dist/chunk-2YA4DDRM.js.map +1 -0
  4. package/dist/{chunk-44TE3RKH.js → chunk-3ED3KHHD.js} +5 -4
  5. package/dist/chunk-3ED3KHHD.js.map +1 -0
  6. package/dist/{chunk-3G7X2WKI.js → chunk-5BNX73OU.js} +18 -38
  7. package/dist/chunk-5BNX73OU.js.map +1 -0
  8. package/dist/{chunk-7RDMTR64.js → chunk-66AEVERM.js} +785 -256
  9. package/dist/chunk-66AEVERM.js.map +1 -0
  10. package/dist/{chunk-PJWGTNOX.js → chunk-7C3PFRBU.js} +144 -186
  11. package/dist/chunk-7C3PFRBU.js.map +1 -0
  12. package/dist/{chunk-52HDHJ7I.js → chunk-AUNRHWH4.js} +32 -21
  13. package/dist/chunk-AUNRHWH4.js.map +1 -0
  14. package/dist/{chunk-KOLDW6SF.js → chunk-BBDGYJHX.js} +2 -2
  15. package/dist/chunk-BBDGYJHX.js.map +1 -0
  16. package/dist/{chunk-SZYQISA2.js → chunk-ELV5WDS3.js} +43 -29
  17. package/dist/chunk-ELV5WDS3.js.map +1 -0
  18. package/dist/{chunk-MQ6CGZNJ.js → chunk-GAKVZNTX.js} +1879 -2019
  19. package/dist/chunk-GAKVZNTX.js.map +1 -0
  20. package/dist/chunk-GEMW5RQ2.js +1169 -0
  21. package/dist/chunk-GEMW5RQ2.js.map +1 -0
  22. package/dist/{chunk-NQW25DCF.js → chunk-GHHJYNAN.js} +1 -7
  23. package/dist/chunk-GHHJYNAN.js.map +1 -0
  24. package/dist/{chunk-WTWMGH2C.js → chunk-HACRR422.js} +2 -2
  25. package/dist/chunk-HACRR422.js.map +1 -0
  26. package/dist/{chunk-F2BHT5C4.js → chunk-IWY5IR4F.js} +129 -151
  27. package/dist/chunk-IWY5IR4F.js.map +1 -0
  28. package/dist/{chunk-JFLVEFFP.js → chunk-KIK5EZYD.js} +1 -1
  29. package/dist/chunk-KIK5EZYD.js.map +1 -0
  30. package/dist/{chunk-USVBYQSQ.js → chunk-O4LN3HFI.js} +16 -6
  31. package/dist/chunk-O4LN3HFI.js.map +1 -0
  32. package/dist/{chunk-RIPSGNLU.js → chunk-OCAVW6N5.js} +3 -3
  33. package/dist/chunk-OCAVW6N5.js.map +1 -0
  34. package/dist/{chunk-4AAOOAIN.js → chunk-P6CYS4JK.js} +2 -2
  35. package/dist/chunk-P6CYS4JK.js.map +1 -0
  36. package/dist/chunk-PLFANHRZ.js +35 -0
  37. package/dist/chunk-PLFANHRZ.js.map +1 -0
  38. package/dist/{chunk-6ZRH5RHC.js → chunk-PMUZR4XO.js} +4 -4
  39. package/dist/chunk-PMUZR4XO.js.map +1 -0
  40. package/dist/{chunk-F5EBEATU.js → chunk-PSUTNOQ2.js} +34 -46
  41. package/dist/chunk-PSUTNOQ2.js.map +1 -0
  42. package/dist/chunk-RIK45Q4I.js +103 -0
  43. package/dist/chunk-RIK45Q4I.js.map +1 -0
  44. package/dist/{chunk-HED2DAXZ.js → chunk-THO7LO5B.js} +5 -5
  45. package/dist/chunk-THO7LO5B.js.map +1 -0
  46. package/dist/{chunk-OYJQUA3D.js → chunk-YGDWHDOY.js} +31 -13
  47. package/dist/chunk-YGDWHDOY.js.map +1 -0
  48. package/dist/{chunk-NCWDK6L7.js → chunk-YXKTY5WM.js} +254 -379
  49. package/dist/chunk-YXKTY5WM.js.map +1 -0
  50. package/dist/{chunk-NEZ4OAOL.js → chunk-ZEGM3MVR.js} +3 -5
  51. package/dist/chunk-ZEGM3MVR.js.map +1 -0
  52. package/dist/commands/build/marketplace.js +46 -46
  53. package/dist/commands/build/marketplace.js.map +1 -1
  54. package/dist/commands/build/plugins.js +25 -28
  55. package/dist/commands/build/plugins.js.map +1 -1
  56. package/dist/commands/compile.js +87 -178
  57. package/dist/commands/compile.js.map +1 -1
  58. package/dist/commands/doctor.js +510 -360
  59. package/dist/commands/doctor.js.map +1 -1
  60. package/dist/commands/edit.js +451 -357
  61. package/dist/commands/edit.js.map +1 -1
  62. package/dist/commands/eject.js +144 -125
  63. package/dist/commands/eject.js.map +1 -1
  64. package/dist/commands/init.js +20 -27
  65. package/dist/commands/list.js +39 -55
  66. package/dist/commands/list.js.map +1 -1
  67. package/dist/commands/new/marketplace.js +6 -11
  68. package/dist/commands/new/marketplace.js.map +1 -1
  69. package/dist/commands/search.js +35 -32
  70. package/dist/commands/search.js.map +1 -1
  71. package/dist/commands/share.js +17 -77
  72. package/dist/commands/share.js.map +1 -1
  73. package/dist/commands/uninstall.js +159 -222
  74. package/dist/commands/uninstall.js.map +1 -1
  75. package/dist/commands/update.js +9 -32
  76. package/dist/commands/update.js.map +1 -1
  77. package/dist/components/common/prompt-confirm.js +2 -2
  78. package/dist/components/common/removal-plan-confirm.js +2 -2
  79. package/dist/components/common/scroll-affordance.js +2 -2
  80. package/dist/components/common/select-list.js +2 -2
  81. package/dist/components/common/skill-agent-summary.js +4 -4
  82. package/dist/components/common/spinner.js +2 -4
  83. package/dist/components/common/summary-panel.js +5 -5
  84. package/dist/components/common/summary-panel.js.map +1 -1
  85. package/dist/config-exports.js +7 -3
  86. package/dist/config-exports.js.map +1 -1
  87. package/dist/hooks/init.js +18 -19
  88. package/dist/hooks/init.js.map +1 -1
  89. package/dist/index.js.map +1 -1
  90. package/dist/load-agent-defs-6QUUMGHK.js +14 -0
  91. package/dist/recompile-project-agents-I33KQJFB.js +65 -0
  92. package/dist/recompile-project-agents-I33KQJFB.js.map +1 -0
  93. package/dist/{source-loader-C5SQXZXI.js → source-loader-TTJVW2ER.js} +5 -5
  94. package/dist/src/agents/developer/ai-developer/playbook.md +2 -5
  95. package/dist/src/agents/developer/api-developer/playbook.md +2 -5
  96. package/dist/src/agents/developer/cli-developer/playbook.md +2 -5
  97. package/dist/src/agents/developer/web-developer/playbook.md +2 -5
  98. package/dist/src/agents/meta/agent-summoner/output.md +2 -2
  99. package/dist/src/agents/meta/agent-summoner/playbook.md +1 -13
  100. package/dist/src/agents/meta/codex-keeper/critical-requirements.md +2 -5
  101. package/dist/src/agents/meta/convention-keeper/critical-requirements.md +2 -4
  102. package/dist/src/agents/tester/ai-tester/critical-requirements.md +1 -2
  103. package/dist/src/agents/tester/ai-tester/playbook.md +2 -0
  104. package/dist/src/agents/tester/api-tester/critical-requirements.md +1 -2
  105. package/dist/src/agents/tester/api-tester/playbook.md +2 -0
  106. package/dist/src/agents/tester/cli-tester/critical-requirements.md +1 -2
  107. package/dist/src/agents/tester/cli-tester/playbook.md +2 -0
  108. package/dist/src/agents/tester/web-tester/critical-requirements.md +1 -2
  109. package/dist/src/agents/tester/web-tester/playbook.md +2 -0
  110. package/package.json +9 -8
  111. package/src/agents/developer/ai-developer/playbook.md +2 -5
  112. package/src/agents/developer/api-developer/playbook.md +2 -5
  113. package/src/agents/developer/cli-developer/playbook.md +2 -5
  114. package/src/agents/developer/web-developer/playbook.md +2 -5
  115. package/src/agents/meta/agent-summoner/output.md +2 -2
  116. package/src/agents/meta/agent-summoner/playbook.md +1 -13
  117. package/src/agents/meta/codex-keeper/critical-requirements.md +2 -5
  118. package/src/agents/meta/convention-keeper/critical-requirements.md +2 -4
  119. package/src/agents/tester/ai-tester/critical-requirements.md +1 -2
  120. package/src/agents/tester/ai-tester/playbook.md +2 -0
  121. package/src/agents/tester/api-tester/critical-requirements.md +1 -2
  122. package/src/agents/tester/api-tester/playbook.md +2 -0
  123. package/src/agents/tester/cli-tester/critical-requirements.md +1 -2
  124. package/src/agents/tester/cli-tester/playbook.md +2 -0
  125. package/src/agents/tester/web-tester/critical-requirements.md +1 -2
  126. package/src/agents/tester/web-tester/playbook.md +2 -0
  127. package/src/schemas/project-config.schema.json +0 -3
  128. package/src/schemas/project-source-config.schema.json +0 -6
  129. package/dist/chunk-3G7X2WKI.js.map +0 -1
  130. package/dist/chunk-44TE3RKH.js.map +0 -1
  131. package/dist/chunk-4AAOOAIN.js.map +0 -1
  132. package/dist/chunk-52HDHJ7I.js.map +0 -1
  133. package/dist/chunk-6HNXYYVF.js +0 -373
  134. package/dist/chunk-6HNXYYVF.js.map +0 -1
  135. package/dist/chunk-6ZRH5RHC.js.map +0 -1
  136. package/dist/chunk-7RDMTR64.js.map +0 -1
  137. package/dist/chunk-BMRUNMPV.js.map +0 -1
  138. package/dist/chunk-CLPUWOSA.js +0 -46
  139. package/dist/chunk-CLPUWOSA.js.map +0 -1
  140. package/dist/chunk-F2BHT5C4.js.map +0 -1
  141. package/dist/chunk-F5EBEATU.js.map +0 -1
  142. package/dist/chunk-HED2DAXZ.js.map +0 -1
  143. package/dist/chunk-JFLVEFFP.js.map +0 -1
  144. package/dist/chunk-KOLDW6SF.js.map +0 -1
  145. package/dist/chunk-MQ6CGZNJ.js.map +0 -1
  146. package/dist/chunk-NCWDK6L7.js.map +0 -1
  147. package/dist/chunk-NEZ4OAOL.js.map +0 -1
  148. package/dist/chunk-NIHUOWE4.js +0 -106
  149. package/dist/chunk-NIHUOWE4.js.map +0 -1
  150. package/dist/chunk-NQW25DCF.js.map +0 -1
  151. package/dist/chunk-OYJQUA3D.js.map +0 -1
  152. package/dist/chunk-PJWGTNOX.js.map +0 -1
  153. package/dist/chunk-RIPSGNLU.js.map +0 -1
  154. package/dist/chunk-SZYQISA2.js.map +0 -1
  155. package/dist/chunk-USVBYQSQ.js.map +0 -1
  156. package/dist/chunk-V3KTSP3Q.js +0 -940
  157. package/dist/chunk-V3KTSP3Q.js.map +0 -1
  158. package/dist/chunk-WTWMGH2C.js.map +0 -1
  159. package/dist/load-agent-defs-YMDWBFDP.js +0 -14
  160. package/dist/recompile-project-agents-SZ76WNTW.js +0 -18
  161. package/dist/source-loader-C5SQXZXI.js.map +0 -1
  162. /package/dist/{load-agent-defs-YMDWBFDP.js.map → load-agent-defs-6QUUMGHK.js.map} +0 -0
  163. /package/dist/{recompile-project-agents-SZ76WNTW.js.map → source-loader-TTJVW2ER.js.map} +0 -0
@@ -1,27 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SelectList
4
- } from "./chunk-44TE3RKH.js";
4
+ } from "./chunk-3ED3KHHD.js";
5
5
  import {
6
- holdInstalledGlobal,
7
- installPlanLines,
8
- notInstalledGlobally,
9
- openUrl,
10
- readInstalledGlobal
11
- } from "./chunk-6HNXYYVF.js";
6
+ openUrl
7
+ } from "./chunk-PLFANHRZ.js";
12
8
  import {
13
9
  fetchSeedConfig
14
- } from "./chunk-OYJQUA3D.js";
10
+ } from "./chunk-YGDWHDOY.js";
15
11
  import {
16
12
  promptConfirm,
17
13
  promptValue
18
- } from "./chunk-4AAOOAIN.js";
14
+ } from "./chunk-P6CYS4JK.js";
19
15
  import {
20
16
  Confirm
21
17
  } from "./chunk-OZXAJNLA.js";
22
18
  import {
23
19
  hostCompileNotices
24
- } from "./chunk-F5EBEATU.js";
20
+ } from "./chunk-PSUTNOQ2.js";
25
21
  import {
26
22
  compileAgentsAllScopes,
27
23
  compileProjectScope,
@@ -29,30 +25,36 @@ import {
29
25
  movedGlobalAgentInputs,
30
26
  sayCapturedWarnings,
31
27
  writeProjectConfig
32
- } from "./chunk-7RDMTR64.js";
28
+ } from "./chunk-66AEVERM.js";
33
29
  import {
34
30
  copyLocalSkills,
35
31
  discoverInstalledSkills
36
- } from "./chunk-F2BHT5C4.js";
32
+ } from "./chunk-IWY5IR4F.js";
37
33
  import {
38
34
  loadAgentDefs
39
- } from "./chunk-HED2DAXZ.js";
35
+ } from "./chunk-THO7LO5B.js";
40
36
  import {
41
37
  render
42
- } from "./chunk-JFLVEFFP.js";
38
+ } from "./chunk-KIK5EZYD.js";
43
39
  import {
44
40
  providerFlag,
45
41
  providerNamedBy,
46
42
  providerNeedsAConfigurationToInstall
47
- } from "./chunk-RIPSGNLU.js";
43
+ } from "./chunk-OCAVW6N5.js";
48
44
  import {
49
45
  BaseCommand,
50
46
  EXIT_CODES,
51
47
  clearTerminalScreen,
48
+ holdInstalledGlobal,
49
+ installPlanLines,
50
+ installsAtHome,
51
+ notInstalledGlobally,
52
+ readInstalledGlobal,
52
53
  registerExternalSkills,
53
54
  writeExternalSkills
54
- } from "./chunk-V3KTSP3Q.js";
55
+ } from "./chunk-GEMW5RQ2.js";
55
56
  import {
57
+ ERROR_MESSAGES,
56
58
  INCOMPLETE_WORK_RECOVERY,
57
59
  INSTALL_MODE_DESCRIPTIONS,
58
60
  INSTALL_MODE_LABELS,
@@ -63,6 +65,7 @@ import {
63
65
  agentCodec,
64
66
  agentsNotCompiled,
65
67
  applySharedConfigHere,
68
+ assertNamedSourceUsable,
66
69
  buildAgentScopeMap,
67
70
  carriedSkillsWritten,
68
71
  chooseProviderForThisRun,
@@ -71,7 +74,7 @@ import {
71
74
  detectProjectInstallation,
72
75
  fileExists,
73
76
  getErrorMessage,
74
- getInstallationInfo,
77
+ getInstallationsByProvider,
75
78
  globalScopedAgentsHint,
76
79
  holdsItsOwnInstallation,
77
80
  hostAt,
@@ -80,10 +83,9 @@ import {
80
83
  isHomeDirectory,
81
84
  isLocalSource,
82
85
  keptAsInstalledGlobally,
83
- loadProjectConfig,
84
86
  permissionFiles,
85
- plural,
86
87
  providerInUse,
88
+ providerToNameAt,
87
89
  readFileSafe,
88
90
  relativeConfigPath,
89
91
  resolveBranding,
@@ -91,10 +93,11 @@ import {
91
93
  seedToInstallSelection,
92
94
  settingsFileSchema,
93
95
  sharedConfigExistingInstall,
94
- skippedUnknownAgents,
95
- skippedUnknownSkills,
96
96
  warn
97
- } from "./chunk-MQ6CGZNJ.js";
97
+ } from "./chunk-GAKVZNTX.js";
98
+ import {
99
+ plural
100
+ } from "./chunk-AUNRHWH4.js";
98
101
  import {
99
102
  ASCII_LOGO,
100
103
  CLI_COLORS,
@@ -104,30 +107,31 @@ import {
104
107
  EJECT_SOURCE,
105
108
  MAX_CONFIG_FILE_SIZE,
106
109
  editorConfigUrl
107
- } from "./chunk-PJWGTNOX.js";
110
+ } from "./chunk-7C3PFRBU.js";
108
111
 
109
112
  // src/cli/commands/init.tsx
110
113
  import "react";
111
114
  import { Flags } from "@oclif/core";
112
115
  import { Box as Box2, Text as Text2, useApp } from "ink";
116
+ import { partition } from "remeda";
113
117
 
114
118
  // src/cli/components/hooks/use-terminal-dimensions.ts
115
119
  import { useState, useEffect } from "react";
116
120
  import { useStdout } from "ink";
117
121
  var DEFAULT_COLUMNS = 80;
118
122
  var DEFAULT_ROWS = 24;
119
- function useTerminalDimensions() {
120
- const { stdout } = useStdout();
121
- const [dimensions, setDimensions] = useState(() => ({
123
+ function dimensionsOf(stdout) {
124
+ return {
122
125
  columns: stdout.columns || DEFAULT_COLUMNS,
123
126
  rows: stdout.rows || DEFAULT_ROWS
124
- }));
127
+ };
128
+ }
129
+ function useTerminalDimensions() {
130
+ const { stdout } = useStdout();
131
+ const [dimensions, setDimensions] = useState(() => dimensionsOf(stdout));
125
132
  useEffect(() => {
126
133
  const handleResize = () => {
127
- setDimensions({
128
- columns: stdout.columns || DEFAULT_COLUMNS,
129
- rows: stdout.rows || DEFAULT_ROWS
130
- });
134
+ setDimensions(dimensionsOf(stdout));
131
135
  };
132
136
  stdout.on("resize", handleResize);
133
137
  return () => {
@@ -248,16 +252,24 @@ var Dashboard = ({ data, onSelect, onCancel }) => {
248
252
  )
249
253
  ] });
250
254
  };
251
- function dashboardCountLines(data) {
252
- const lines = [
253
- ` Skills: ${data.skillCount} installed`,
254
- ` Agents: ${data.agentCount} compiled`,
255
- ` Mode: ${INSTALL_MODE_LABELS[data.mode]}`
255
+ function dashboardCountLines({ installations }) {
256
+ const named = installations.length > 1;
257
+ const blocks = installations.map((installation) => [
258
+ ...named ? [` Provider: ${installation.provider}`] : [],
259
+ ...installationCountLines(installation)
260
+ ]);
261
+ return blankLineBetween(blocks);
262
+ }
263
+ function blankLineBetween(blocks) {
264
+ return blocks.flatMap((block, index) => index === 0 ? block : ["", ...block]);
265
+ }
266
+ function installationCountLines(installation) {
267
+ return [
268
+ ` Skills: ${installation.skillCount} installed`,
269
+ ` Agents: ${installation.agentCount} compiled`,
270
+ ` Mode: ${INSTALL_MODE_LABELS[installation.mode]}`,
271
+ ...installation.marketplace ? [` Marketplace: ${installation.marketplace}`] : []
256
272
  ];
257
- if (data.source) {
258
- lines.push(` Marketplace: ${data.source}`);
259
- }
260
- return lines;
261
273
  }
262
274
  function formatDashboardText(data) {
263
275
  return [data.name, "", ...dashboardCountLines(data), "", DASHBOARD_OPTIONS_LINE].join("\n");
@@ -301,12 +313,7 @@ function sharedConfigSourceFlags(flags, payload) {
301
313
  return { marketplace: flags.marketplace ?? payload.marketplace };
302
314
  }
303
315
  var Init = class _Init extends BaseCommand {
304
- /**
305
- * The name this run prints itself under, resolved once on {@link install}'s spine because the
306
- * closing line is printed several calls below it. Same shape and same reason as `uninstall`'s
307
- * field: a plain `string` holding the shipped default rather than an optional every reader
308
- * would have to answer for.
309
- */
316
+ /** Resolved once in {@link install}; the closing line is printed several calls below. */
310
317
  brandingName = DEFAULT_BRANDING.NAME;
311
318
  static summary = `Initialize ${DEFAULT_BRANDING.NAME} in this project`;
312
319
  static description = "Build a configuration in agentsinc.sh/editor, or install one by id with --from. Over an existing installation, shows its dashboard.";
@@ -340,95 +347,57 @@ var Init = class _Init extends BaseCommand {
340
347
  }),
341
348
  provider: providerFlag()
342
349
  };
343
- /**
344
- * The command in two statements: do the work, then answer for it.
345
- *
346
- * {@link install} owns every path through the setup and returns however it likes; the exit
347
- * code is decided once, here, after the last of them. Deciding it inside would mean deciding
348
- * it at each of that method's endings, and an ending added later would inherit the exit-0
349
- * default silently — which is the defect this pair exists to close. `edit` is two statements
350
- * for the same reason.
351
- */
350
+ /** The exit code is decided once, after every path through {@link install} has ended. */
352
351
  async run() {
353
352
  await this.install();
354
353
  this.exitIfWorkIncomplete();
355
354
  }
356
- /**
357
- * The editor, opened on whatever `--from` named — or on nothing when it named nothing.
358
- *
359
- * **One rule, both commands (owner ruling 2026-08-24): `--ui` opens the command's SUBJECT, and
360
- * `--from` is what supplies one.** `edit --ui` alone opens this installation because that is
361
- * `edit`'s subject; `init --ui` alone opens the catalogue because a fresh directory has none.
362
- * Given an id, either opens that id — which is what makes a shared configuration something a
363
- * recipient can look at rather than only apply blind.
364
- *
365
- * No publish happens here and none is needed. `edit --ui` mints an id because an installation
366
- * is not a configuration the store holds yet; an id already IS one, so this is
367
- * `editorConfigUrl` and nothing else — no network, no marketplace, no catalogue load.
368
- *
369
- * The link is PRINTED first and opened second. Over a pipe, in CI, and on a machine with no
370
- * desktop session there is no browser to be anybody's — a link nobody can copy is the whole
371
- * loss, so opening one is the convenience on top and a failure to open is a warning beside a
372
- * link that still works.
373
- *
374
- * A marketplace named here cannot ride along: the address carries an id and nothing else, so
375
- * the line under the link says how to add it in the editor.
376
- */
377
- async openEditor(projectDir, id, marketplace) {
355
+ /** The link is printed before it is opened, so it still works where no browser can open. */
356
+ async openEditor(projectDir, provider, id, marketplace) {
378
357
  const url = id === void 0 ? EDITOR_URL : editorConfigUrl(id);
379
358
  const marketplaceLine = marketplace === void 0 ? void 0 : this.addMarketplaceLineOrFail(marketplace);
380
359
  this.log(id === void 0 ? `Build it at ${url}` : `Open it at ${url}`);
381
360
  if (marketplaceLine !== void 0) this.log(marketplaceLine);
382
- this.log(applySharedConfigHere(id, await holdsItsOwnInstallation(projectDir)));
361
+ this.log(applySharedConfigHere(id, await holdsItsOwnInstallation(projectDir), provider));
383
362
  if (!process.stdin.isTTY) return;
384
363
  const opened = await openUrl(url);
385
364
  if (!opened.ok) this.warn(opened.error);
386
365
  }
387
- /**
388
- * Every route `init` has, in the order they are tried: the editor for `--ui` and for a
389
- * marketplace named without `--from`; for a bare run, the installation's dashboard — or the
390
- * editor where nothing is installed; and the install of the configuration `--from` names.
391
- */
392
366
  async install() {
393
367
  const { flags } = await this.parse(_Init);
394
368
  const projectDir = process.cwd();
395
369
  this.settleTheProviderForThisRun(flags);
396
- if (opensTheEditor(flags)) return this.openEditor(projectDir, flags.from, flags.marketplace);
370
+ if (opensTheEditor(flags)) {
371
+ return this.openEditor(
372
+ projectDir,
373
+ providerNamedBy(flags.provider),
374
+ flags.from,
375
+ flags.marketplace
376
+ );
377
+ }
397
378
  await this.ensureConfigReadable(projectDir);
398
379
  if (flags.from === void 0) return this.showDashboardOrOpenEditor(projectDir);
399
380
  this.brandingName = await this.resolveBrandingName(projectDir);
400
381
  const selection = await this.selectionFromSharedConfig(flags.from, flags, projectDir);
401
382
  if (!selection) this.exit(EXIT_CODES.CANCELLED);
402
383
  this.reportValidationErrors(selection.result.validation);
403
- await this.handleInstallation(selection);
384
+ await this.handleInstallation(selection, projectDir);
404
385
  }
405
- /** A bare `init`: the installation's dashboard, or the editor where nothing is installed. */
406
386
  async showDashboardOrOpenEditor(projectDir) {
407
387
  const dashboard = await runDashboardFlow(projectDir, this.config, (msg) => this.log(msg));
408
388
  if (dashboard === "cancelled") this.error("Cancelled", { exit: EXIT_CODES.CANCELLED });
409
- if (dashboard === "not-installed") await this.openEditor(projectDir);
389
+ if (dashboard === "not-installed") await this.openEditor(projectDir, void 0);
410
390
  }
411
- /** The editor's marketplace line, or the refusal the install route gives a ref it cannot read. */
391
+ /** Refused as the install route refuses it, since the line echoes the ref it was given. */
412
392
  addMarketplaceLineOrFail(ref) {
413
393
  try {
394
+ assertNamedSourceUsable(ref);
414
395
  return addMarketplaceInTheEditor(ref, isLocalSource(ref));
415
396
  } catch (error) {
416
397
  this.handleError(error);
417
398
  }
418
399
  }
419
- /**
420
- * Commits this run to the provider `--provider` named, or refuses a flag with nothing to name.
421
- *
422
- * **`--provider` is a LOCATION parameter, not a feature switch**, and the control that proves it
423
- * is `--provider claude`: naming the default out loud installs byte-for-byte what no flag
424
- * installs, because all the flag decides is which folder this run creates. Without that half
425
- * "the flag selects an installation" would be indistinguishable from "the flag means Codex".
426
- *
427
- * **And it is meaningless without `--from` (D15).** The provider is chosen in the web app, so
428
- * the only run that can be told one is the run that installs what the app produced. It also
429
- * gives the placement refusal something to refuse BEFORE anything is written: with `--from`
430
- * required, a provider always arrives beside a payload the pre-flight can read.
431
- */
400
+ /** `--provider` only picks which folder an install creates, so it needs `--from`. */
432
401
  settleTheProviderForThisRun(flags) {
433
402
  const named = providerNamedBy(flags.provider);
434
403
  if (named === void 0) return;
@@ -437,46 +406,21 @@ var Init = class _Init extends BaseCommand {
437
406
  }
438
407
  chooseProviderForThisRun(named);
439
408
  }
440
- /**
441
- * The `--from <id>` producer: fetch and map — and, at a terminal, one question.
442
- *
443
- * It installs into a clean directory, which is what the first refusal is: a shared
444
- * configuration is installed whole, so a directory already holding one has it applied with
445
- * `edit --from` instead, or is uninstalled first. The second is about the LOCATION rather than what is already in it — a global
446
- * installation holds only global-scoped content. Both fire before anything is written.
447
- *
448
- * A global installation ABOVE a project is not in the way. It is not this project's, so the run
449
- * adds to it what it lacks and states every entry it already holds as installed (see
450
- * `holdInstalledGlobal`).
451
- *
452
- * Before writing anything the run lists what goes into the project and what into the global
453
- * install. At a terminal it then asks, and a no writes nothing. With no terminal — a CI job or a
454
- * script — it prints the same lists and carries on: running headless is most of why the flag
455
- * exists.
456
- */
409
+ /** Every refusal fires before anything is written. */
457
410
  async selectionFromSharedConfig(id, flags, projectDir) {
458
411
  await this.refuseInstalledProject(projectDir, id);
459
- this.log(`Fetching configuration ${id}...`);
460
- const fetched = await fetchSeedConfig(id);
461
- if (!fetched.ok) {
462
- this.error(fetched.error, { exit: EXIT_CODES.ERROR });
463
- }
464
- const sourceFlags = sharedConfigSourceFlags(flags, fetched.payload);
465
- const { sourceResult, startupMessages } = await this.loadSourceOrFail(sourceFlags);
412
+ const payload = await this.fetchSharedConfigOrFail(id);
413
+ const sourceFlags = sharedConfigSourceFlags(flags, payload);
414
+ const { sourceResult, startupMessages } = await this.loadSourceOrFail(sourceFlags, projectDir);
466
415
  const carriedSkills = this.registerExternalSkillsOrFail(
467
- fetched.payload,
416
+ payload,
468
417
  sourceResult.matrix,
469
418
  projectDir
470
419
  );
471
- const { result, skippedSkillIds, skippedAgentNames } = this.decodeSeedOrFail(
472
- fetched.payload,
473
- sourceResult.matrix
474
- );
420
+ const mapping = this.decodeSeedOrFail(payload, sourceResult.matrix);
421
+ const { result } = mapping;
475
422
  this.refuseProjectScopedContentAtHome(result, projectDir);
476
- const held = holdInstalledGlobal(
477
- result,
478
- isHomeDirectory(projectDir) ? null : await readInstalledGlobal(projectDir)
479
- );
423
+ const held = holdInstalledGlobal(result, await installedGlobalToHold(projectDir));
480
424
  const arrivingCarried = notInstalledGlobally(carriedSkills, held);
481
425
  await this.refuseSharedConfigBeforeAsking(
482
426
  held.result,
@@ -485,26 +429,15 @@ var Init = class _Init extends BaseCommand {
485
429
  sourceResult
486
430
  );
487
431
  sayCapturedWarnings(startupMessages);
488
- if (skippedSkillIds.length > 0) this.warn(skippedUnknownSkills(skippedSkillIds));
489
- if (skippedAgentNames.length > 0) this.warn(skippedUnknownAgents(skippedAgentNames));
490
- if (selectsNothing(held.result)) {
491
- this.error(`Configuration '${id}' contains no skills this catalog can install.`, {
492
- exit: EXIT_CODES.ERROR
493
- });
494
- }
495
- this.logWhatGoesWhere(held);
432
+ this.warnOfSkippedEntries(mapping, held.result.selectedAgents);
433
+ this.refuseAnEmptySelection(held.result, id);
434
+ this.logWhatGoesWhere(held, installsAtHome(result) ? id : void 0);
496
435
  if (process.stdin.isTTY && !await this.confirmInstall()) {
497
436
  this.log("Setup cancelled");
498
437
  return null;
499
438
  }
500
439
  await this.writeCarriedSkills(arrivingCarried);
501
- const arriving = notInstalledGlobally(held.result.skills, held);
502
- if (arriving.length > 0) {
503
- this.log(
504
- `Installing ${arriving.length} skill(s) across ${result.selectedAgents.length} sub-agent(s)
505
- `
506
- );
507
- }
440
+ this.announceArrivingSkills(held, result.selectedAgents.length);
508
441
  return {
509
442
  result: held.result,
510
443
  sourceResult,
@@ -512,22 +445,29 @@ var Init = class _Init extends BaseCommand {
512
445
  installedAlready: new Set(held.installed.skillIds)
513
446
  };
514
447
  }
515
- /**
516
- * The two lists — what goes into this project, and what into the global install — then the
517
- * global skills skipped as already installed, the held sub-agents a new skill joins, and the
518
- * global entries the configuration states otherwise than they are installed, which stay.
519
- */
520
- logWhatGoesWhere(held) {
448
+ /** `idAppliedAtHome` is the id only where a run from home would take the configuration. */
449
+ logWhatGoesWhere(held, idAppliedAtHome) {
521
450
  for (const line of installPlanLines(held)) {
522
451
  this.log(line);
523
452
  }
524
453
  const { skillIds, agentNames } = held.keptAsInstalled;
525
454
  if (skillIds.length > 0 || agentNames.length > 0) {
526
- this.log(keptAsInstalledGlobally(skillIds, agentNames));
455
+ this.log(keptAsInstalledGlobally(skillIds, agentNames, idAppliedAtHome));
527
456
  }
528
457
  this.log("");
529
458
  }
530
- /** The question under the lists, defaulting to no: nothing has been written yet. */
459
+ refuseAnEmptySelection(result, id) {
460
+ if (!selectsNothing(result)) return;
461
+ this.error(`Configuration '${id}' contains no skills this catalog can install.`, {
462
+ exit: EXIT_CODES.ERROR
463
+ });
464
+ }
465
+ announceArrivingSkills(held, agentCount) {
466
+ const arriving = notInstalledGlobally(held.result.skills, held);
467
+ if (arriving.length === 0) return;
468
+ this.log(`Installing ${arriving.length} skill(s) across ${agentCount} sub-agent(s)
469
+ `);
470
+ }
531
471
  async confirmInstall() {
532
472
  const outcome = await promptConfirm(({ onConfirm, onCancel }) => /* @__PURE__ */ jsx2(
533
473
  Confirm,
@@ -539,28 +479,23 @@ var Init = class _Init extends BaseCommand {
539
479
  ));
540
480
  return outcome === "confirmed";
541
481
  }
542
- /**
543
- * Refuses to install a shared configuration into a directory that already has one.
544
- *
545
- * Project-scoped detection rather than `detectInstallation`, whose global fallback would refuse
546
- * every clean project on a machine with a global install. A global install above the project is
547
- * added to rather than refused over — see {@link selectionFromSharedConfig}.
548
- *
549
- * This runs before the fetch: there is nothing to learn from the network about a directory that
550
- * is already spoken for.
551
- */
482
+ /** Project-scoped: `detectInstallation`'s global fallback would refuse every clean project. */
552
483
  async refuseInstalledProject(projectDir, id) {
553
484
  const installation = await detectProjectInstallation(projectDir);
554
485
  if (!installation) return;
555
- this.error(sharedConfigExistingInstall(installation.configPath, id), {
486
+ const provider = providerToNameAt(projectDir, providerInUse(projectDir));
487
+ this.error(sharedConfigExistingInstall(installation.configPath, id, provider), {
556
488
  exit: EXIT_CODES.ERROR
557
489
  });
558
490
  }
559
- /**
560
- * The decode refuses a payload the config model has nowhere to write (see
561
- * `seedToInstallSelection`). That is a failure of this command, reported with this command's exit
562
- * code rather than left to surface as an unhandled throw.
563
- */
491
+ async fetchSharedConfigOrFail(id) {
492
+ this.log(`Fetching configuration ${id}...`);
493
+ const fetched = await fetchSeedConfig(id);
494
+ if (!fetched.ok) {
495
+ this.error(fetched.error, { exit: EXIT_CODES.ERROR });
496
+ }
497
+ return fetched.payload;
498
+ }
564
499
  decodeSeedOrFail(payload, matrix) {
565
500
  try {
566
501
  return seedToInstallSelection(payload, matrix);
@@ -568,14 +503,6 @@ var Init = class _Init extends BaseCommand {
568
503
  this.handleError(error);
569
504
  }
570
505
  }
571
- /**
572
- * Seats the catalogue entries the payload carries with it, or refuses the run.
573
- *
574
- * The refusals are `registerExternalSkills`' own — a carried skill asked for as a plugin, which
575
- * no marketplace serves, and a carried skill claiming an id the loaded catalogue already owns,
576
- * whose bytes would be written over that catalogue's own copy — and are reported with this
577
- * command's exit code for the same reason the decode's is.
578
- */
579
506
  registerExternalSkillsOrFail(payload, matrix, projectDir) {
580
507
  try {
581
508
  return registerExternalSkills(payload, matrix, projectDir);
@@ -583,19 +510,18 @@ var Init = class _Init extends BaseCommand {
583
510
  this.handleError(error);
584
511
  }
585
512
  }
586
- /** Writes the skills the payload brought with it, and says which they were. */
587
513
  async writeCarriedSkills(carried) {
588
514
  if (carried.length === 0) return;
589
515
  await writeExternalSkills(carried);
590
516
  this.log(carriedSkillsWritten(carried.map((skill) => skill.id)));
591
517
  }
592
- async loadSourceOrFail(flags) {
518
+ async loadSourceOrFail(flags, projectDir) {
593
519
  try {
594
520
  const loaded = await loadSource({
595
- // The one load that may CHOOSE a marketplace rather than read the stored one.
521
+ // The one load that may choose a marketplace rather than read the stored one.
596
522
  caller: "init",
597
523
  ...flags.marketplace !== void 0 && { sourceFlag: flags.marketplace },
598
- projectDir: process.cwd(),
524
+ projectDir,
599
525
  captureStartupMessages: true
600
526
  });
601
527
  return { sourceResult: loaded.sourceResult, startupMessages: loaded.startupMessages };
@@ -605,88 +531,83 @@ var Init = class _Init extends BaseCommand {
605
531
  });
606
532
  }
607
533
  }
608
- async handleInstallation({
609
- result,
610
- sourceResult,
611
- sourceFlags,
612
- installedAlready
613
- }) {
614
- const projectDir = process.cwd();
615
- const activeSkills = result.skills.filter((s) => !s.excluded);
616
- const toInstall = activeSkills.filter((s) => !installedAlready.has(s.id));
617
- const installMode = deriveInstallMode(toInstall);
618
- const ejectedSkills = toInstall.filter((s) => s.origin === EJECT_SOURCE);
619
- const pluginSkills = toInstall.filter((s) => s.origin !== EJECT_SOURCE);
620
- this.logInstallPlan(installMode, ejectedSkills, pluginSkills);
621
- const resolvedMarketplace = pluginSkills.length > 0 ? await this.requireMarketplaceOrExit(
534
+ async handleInstallation({ result, sourceResult, sourceFlags, installedAlready }, projectDir) {
535
+ const plan = planInstall(result, installedAlready);
536
+ this.logInstallPlan(plan);
537
+ const resolvedMarketplace = await this.marketplaceForPluginSkills(
538
+ plan.pluginSkills,
622
539
  sourceResult,
623
- "install plugin skills",
624
- hostAt(projectDir),
625
- (marketplace) => this.log(`Registering marketplace "${marketplace}"...`)
626
- ) : null;
627
- const copyResult = ejectedSkills.length > 0 ? await this.copyEjectSkillsStep(ejectedSkills, projectDir, sourceResult, installMode) : null;
540
+ projectDir
541
+ );
542
+ const copyResult = await this.copyEjectedSkills(plan, projectDir, sourceResult);
628
543
  if (resolvedMarketplace !== null) {
629
544
  await this.installPluginSkillsReported(
630
- pluginSkills,
545
+ plan.pluginSkills,
631
546
  resolvedMarketplace,
632
547
  projectDir,
633
548
  sourceResult.matrix
634
549
  );
635
550
  }
636
- const pluginModeSucceeded = resolvedMarketplace !== null;
637
551
  try {
638
- const { configResult, compileResult, agentScopeMap } = await this.writeConfigAndCompile(
552
+ const written = await this.writeConfigAndCompile(
639
553
  result,
640
554
  sourceResult,
641
- sourceFlags
642
- );
643
- this.reportSuccess(
644
- configResult,
645
- compileResult,
646
- agentScopeMap,
647
- installMode,
648
- pluginModeSucceeded,
649
- copyResult
555
+ sourceFlags,
556
+ projectDir
650
557
  );
558
+ this.reportSuccess(written, copyResult, projectDir);
651
559
  await this.showPermissionNotice(projectDir);
652
560
  } catch (error) {
653
561
  this.handleError(error);
654
562
  }
655
563
  }
656
- /**
657
- * The permission notice, where there is one to show. It is an Ink app with no exit of its own,
658
- * so one frame is rendered and let go: the notice is information, not a prompt, and `--from`
659
- * has to complete over a pipe and in CI.
660
- */
564
+ async marketplaceForPluginSkills(pluginSkills, sourceResult, projectDir) {
565
+ if (pluginSkills.length === 0) return null;
566
+ return this.requireMarketplaceOrExit(
567
+ sourceResult,
568
+ "install plugin skills",
569
+ hostAt(projectDir),
570
+ (marketplace) => this.log(`Registering marketplace "${marketplace}"...`)
571
+ );
572
+ }
573
+ /** One frame, then unmount: the notice has no exit of its own and `--from` must run headless. */
661
574
  async showPermissionNotice(projectDir) {
662
575
  const permissionWarning = await checkPermissions(projectDir);
663
576
  if (!permissionWarning) return;
664
577
  const { unmount } = render(permissionWarning);
665
578
  unmount();
666
579
  }
667
- logInstallPlan(installMode, ejectedSkills, pluginSkills) {
580
+ logInstallPlan(plan) {
668
581
  this.log("\n");
669
- this.log(`Selected ${plural(ejectedSkills.length + pluginSkills.length, "skill")}`);
670
- this.log(
671
- `Install mode: ${installMode === "mixed" ? `${INSTALL_MODE_LABELS.mixed} (${ejectedSkills.length} eject, ${pluginSkills.length} plugin)` : INSTALL_MODE_DESCRIPTIONS[installMode]}`
672
- );
582
+ this.log(`Selected ${plural(plan.ejectedSkills.length + plan.pluginSkills.length, "skill")}`);
583
+ this.log(`Install mode: ${installModeDescription(plan)}`);
673
584
  }
674
- /**
675
- * Copies the ejected skills and says how many landed at each scope, in the words
676
- * {@link skillsCopiedLine} chooses.
677
- */
678
- async copyEjectSkillsStep(localSkills, projectDir, sourceResult, installMode) {
585
+ async copyEjectedSkills({ ejectedSkills, installMode }, projectDir, sourceResult) {
586
+ if (ejectedSkills.length === 0) return null;
679
587
  this.log("Copying skills to local directory...");
680
- const copyResult = await copyLocalSkills(localSkills, projectDir, sourceResult);
588
+ const copyResult = await copyLocalSkills(ejectedSkills, projectDir, sourceResult);
681
589
  this.log(skillsCopiedLine(copyResult, installMode, projectDir));
682
590
  return copyResult;
683
591
  }
684
- async writeConfigAndCompile(result, sourceResult, flags) {
592
+ async writeConfigAndCompile(result, sourceResult, flags, projectDir) {
593
+ const configResult = await this.writeConfigReported(result, sourceResult, flags, projectDir);
594
+ const agentScopeMap = buildAgentScopeMap(configResult.config);
595
+ const compileResult = await this.compileInstalledAgents(
596
+ configResult.propagation,
597
+ agentScopeMap,
598
+ projectDir
599
+ );
600
+ this.reportCompilation(compileResult);
601
+ await this.reportWhatThisHostCannotCarry(projectDir);
602
+ this.reportFanOut(configResult.propagation);
603
+ return { configResult, compileResult, agentScopeMap };
604
+ }
605
+ async writeConfigReported(result, sourceResult, flags, projectDir) {
685
606
  this.log("Generating configuration...");
686
607
  const configResult = await writeProjectConfig({
687
608
  selection: result,
688
609
  sourceResult,
689
- projectDir: process.cwd(),
610
+ projectDir,
690
611
  ...flags.marketplace !== void 0 && { sourceFlag: flags.marketplace }
691
612
  });
692
613
  if (configResult.wasMerged) {
@@ -695,51 +616,28 @@ var Init = class _Init extends BaseCommand {
695
616
  this.log(`Configuration saved (${plural(configResult.config.agents.length, "agent")})
696
617
  `);
697
618
  this.reportUnassignedSkills(configResult.config, result.skills);
619
+ return configResult;
620
+ }
621
+ async compileInstalledAgents(written, agentScopeMap, projectDir) {
698
622
  this.log(STATUS_MESSAGES.COMPILING_AGENTS);
699
- const cwd = process.cwd();
700
623
  const agentDefs = await loadAgentDefs();
701
- const { allSkills } = await discoverInstalledSkills(cwd);
702
- const agentScopeMap = buildAgentScopeMap(configResult.config);
703
- const compile = compilesGlobalScope(cwd, configResult.propagation) ? compileAgentsAllScopes : compileProjectScope;
704
- const compileResult = await compile({
705
- projectDir: cwd,
624
+ const { allSkills } = await discoverInstalledSkills(projectDir);
625
+ const compile = compilesGlobalScope(projectDir, written) ? compileAgentsAllScopes : compileProjectScope;
626
+ return compile({
627
+ projectDir,
706
628
  sourcePath: agentDefs.sourcePath,
707
629
  skills: allSkills,
708
630
  agentScopeMap
709
631
  });
710
- this.reportCompilation(compileResult);
711
- await this.reportWhatThisHostCannotCarry(cwd);
712
- this.reportFanOut(configResult.propagation);
713
- return { configResult, compileResult, agentScopeMap };
714
632
  }
715
- /**
716
- * What this host could not carry, after the compile summary and once per run.
717
- *
718
- * `init --from` is the door a configuration somebody ELSE wrote arrives through, so it is
719
- * precisely the run that must not be silent about the parts of it that did not survive the
720
- * translation. `compile` prints the same lines in the same order — see
721
- * {@link hostCompileNotices}, which is the one place either of them gets them from.
722
- *
723
- * A Claude install expresses every setting and carries every sub-agent, so it gets one line at
724
- * most: the trust dialog, while its project sub-agents' completion gate cannot run in this
725
- * folder.
726
- */
727
- async reportWhatThisHostCannotCarry(cwd) {
728
- for (const notice of await hostCompileNotices(providerInUse(cwd), cwd)) {
633
+ async reportWhatThisHostCannotCarry(projectDir) {
634
+ for (const notice of await hostCompileNotices(providerInUse(projectDir), projectDir)) {
729
635
  this.log(notice);
730
636
  }
731
637
  }
732
638
  /**
733
- * What the compile pass did, including the half this command used to drop.
734
- *
735
- * It read `compiled` and nothing else, so a pass that lost a sub-agent printed a number that
736
- * looked perfectly right — `compiled` counts successes, so it is correct either way — and the
737
- * failures reached no surface at all: no count, no reason, no exit code. A user's FIRST
738
- * install could silently land a roster missing a sub-agent.
739
- *
740
- * The compile is the last thing `init` does, so a failure here cannot be answered by aborting:
741
- * the skills are on disk and `config.ts` and `config-types.ts` describe them. What is owed is
742
- * the account, which {@link BaseCommand.exitIfWorkIncomplete} prints and answers for.
639
+ * Failures are recorded rather than aborted on: the skills and config are already written, and
640
+ * {@link BaseCommand.exitIfWorkIncomplete} answers for them.
743
641
  */
744
642
  reportCompilation(compileResult) {
745
643
  const { compiled, failed, warnings } = compileResult;
@@ -756,104 +654,41 @@ var Init = class _Init extends BaseCommand {
756
654
  }
757
655
  this.recordIncompleteWork(agentsNotCompiled(failed), INCOMPLETE_WORK_RECOVERY.RECOMPILE);
758
656
  }
759
- reportSuccess(configResult, compileResult, agentScopeMap, installMode, pluginModeSucceeded, copyResult) {
657
+ reportSuccess({ configResult, compileResult, agentScopeMap }, copyResult, projectDir) {
760
658
  if (!this.hasIncompleteWork) this.log(`${initSucceeded(this.brandingName)}
761
659
  `);
762
- const isEjectOutput = installMode === "eject" || installMode === "mixed" && !pluginModeSucceeded;
763
- if (isEjectOutput && copyResult && copyResult.totalCopied > 0) {
764
- this.reportSkillsCopied(copyResult);
660
+ if (copyResult !== null && copyResult.totalCopied > 0) {
661
+ this.logDirectoryBlocks("Skills copied to:", skillsCopiedBlocks(projectDir, copyResult));
765
662
  }
766
- this.reportAgentsCompiled(compileResult.compiled, agentScopeMap);
767
- this.reportConfiguration(configResult.configPath, agentScopeMap);
663
+ this.logDirectoryBlocks(
664
+ "Agents compiled to:",
665
+ agentsCompiledBlocks(projectDir, compileResult.compiled, agentScopeMap)
666
+ );
667
+ this.reportConfiguration(configResult, agentScopeMap, projectDir);
768
668
  }
769
- /**
770
- * Names the config that actually holds this install's assignments, and where a
771
- * recompile of them has to be run from.
772
- *
773
- * Split by the same `agentScopeMap` the two reporters above split on, because the
774
- * same scope decides both. A project config's `stack` is filtered down to
775
- * project-scoped agents on the way out, so a wholly GLOBAL install leaves it
776
- * carrying no assignment at all — naming it sends the user to a file with nothing
777
- * in it — and `compile` in this cwd runs the PROJECT pass, which recompiles no
778
- * global agent. At the home root both scopes resolve to one file and one pass, so
779
- * there is nothing to split and the project wording stands.
780
- */
781
- reportConfiguration(projectConfigPath, agentScopeMap) {
782
- const cwd = process.cwd();
669
+ reportConfiguration({ configPath, propagation }, agentScopeMap, projectDir) {
783
670
  const paths = {
784
- global: resolveInstallPaths(cwd, "global").configPath,
785
- project: projectConfigPath
671
+ global: resolveInstallPaths(projectDir, "global").configPath,
672
+ project: configPath
786
673
  };
787
- const split = splitAgentScopes(cwd, agentScopeMap);
674
+ const split = splitAgentScopes(projectDir, agentScopeMap);
788
675
  this.log("Configuration:");
789
- for (const configPath of configsHoldingAssignments(split, paths)) {
790
- this.log(` ${configPath}`);
676
+ for (const written of configsWritten(projectDir, paths, propagation.globalWritten)) {
677
+ this.log(` ${written}`);
791
678
  }
792
679
  this.log("");
793
680
  this.log("To customize agent-skill assignments:");
794
- for (const [index, step] of customizationSteps(split, paths.global, cwd).entries()) {
681
+ for (const [index, step] of customizationSteps(split, paths.global, projectDir).entries()) {
795
682
  this.log(` ${index + 1}. ${step}`);
796
683
  }
797
684
  this.log("");
798
685
  }
799
- /**
800
- * Reports where the skills actually landed. `copyLocalSkills` splits by scope,
801
- * so a default install driven from a project directory writes every skill
802
- * under HOME — reporting the project path there names a directory that was
803
- * never written.
804
- *
805
- * This block is a filesystem listing, so the entries are the on-disk directory
806
- * names — skill ids, not display names. `copySkillsToLocalFlattened` names each
807
- * destination directory after `skill.id`, so a user can copy any line and `cd`
808
- * into it.
809
- */
810
- reportSkillsCopied(copyResult) {
811
- const cwd = process.cwd();
812
- const groups = isHomeDirectory(cwd) ? [
813
- {
814
- dir: resolveInstallPaths(cwd, "project").skillsDir,
815
- copied: [...copyResult.globalCopied, ...copyResult.projectCopied]
816
- }
817
- ] : [
818
- { dir: resolveInstallPaths(cwd, "global").skillsDir, copied: copyResult.globalCopied },
819
- { dir: resolveInstallPaths(cwd, "project").skillsDir, copied: copyResult.projectCopied }
820
- ].filter((group) => group.copied.length > 0);
821
- for (const group of groups) {
822
- this.log("Skills copied to:");
823
- this.log(` ${group.dir}`);
824
- for (const copied of group.copied) {
825
- this.log(` ${copied.skillId}/`);
826
- }
827
- this.log("");
828
- }
829
- }
830
- /**
831
- * Reports where the agents actually landed, mirroring the scope split
832
- * `compileAgentsAllScopes` performs: one pass at the home root, otherwise a
833
- * global pass under HOME and a project pass under the project directory.
834
- *
835
- * **The EXTENSION is the host's, per scope, and was Claude's literal `.md` until C5.** This
836
- * block describes the filesystem, so every line under a path header has to be a name a user can
837
- * copy out and open — and a Codex install printed `web-developer.md` above a directory holding
838
- * `web-developer.toml`. The two scopes are read separately because they can be on two hosts.
839
- */
840
- reportAgentsCompiled(compiled, agentScopeMap) {
841
- const cwd = process.cwd();
842
- const groups = isHomeDirectory(cwd) ? [{ ...compiledInto(cwd, "project"), agents: compiled }] : [
843
- {
844
- ...compiledInto(cwd, "global"),
845
- agents: compiled.filter((name) => agentScopeMap.get(name) === "global")
846
- },
847
- {
848
- ...compiledInto(cwd, "project"),
849
- agents: compiled.filter((name) => agentScopeMap.get(name) !== "global")
850
- }
851
- ].filter((group) => group.agents.length > 0);
852
- for (const group of groups) {
853
- this.log("Agents compiled to:");
854
- this.log(` ${group.dir}`);
855
- for (const agentName of group.agents) {
856
- this.log(` ${agentName}${group.extension}`);
686
+ logDirectoryBlocks(heading, blocks) {
687
+ for (const { dir, entries } of blocks) {
688
+ this.log(heading);
689
+ this.log(` ${dir}`);
690
+ for (const entry of entries) {
691
+ this.log(` ${entry}`);
857
692
  }
858
693
  this.log("");
859
694
  }
@@ -865,6 +700,24 @@ function opensTheEditor(flags) {
865
700
  function selectsNothing(result) {
866
701
  return result.skills.length === 0 && result.selectedAgents.length === 0;
867
702
  }
703
+ async function installedGlobalToHold(projectDir) {
704
+ if (isHomeDirectory(projectDir)) return null;
705
+ return await readInstalledGlobal(projectDir);
706
+ }
707
+ function planInstall(result, installedAlready) {
708
+ const toInstall = result.skills.filter(
709
+ (skill) => !skill.excluded && !installedAlready.has(skill.id)
710
+ );
711
+ const [ejectedSkills, pluginSkills] = partition(
712
+ toInstall,
713
+ (skill) => skill.origin === EJECT_SOURCE
714
+ );
715
+ return { installMode: deriveInstallMode(toInstall), ejectedSkills, pluginSkills };
716
+ }
717
+ function installModeDescription({ installMode, ejectedSkills, pluginSkills }) {
718
+ if (installMode !== "mixed") return INSTALL_MODE_DESCRIPTIONS[installMode];
719
+ return `${INSTALL_MODE_LABELS.mixed} (${ejectedSkills.length} eject, ${pluginSkills.length} plugin)`;
720
+ }
868
721
  function compilesGlobalScope(cwd, written) {
869
722
  return isHomeDirectory(cwd) || movedGlobalAgentInputs(written);
870
723
  }
@@ -881,10 +734,47 @@ function skillsCopiedLine(copyResult, installMode, projectDir) {
881
734
  const landedAt = globalCount > 0 ? "global" : "project";
882
735
  return `Copied ${copied} to ${resolveInstallPaths(projectDir, landedAt).skillsDir}/${lineEnd}`;
883
736
  }
884
- function compiledInto(cwd, scope) {
737
+ function hasEntries(block) {
738
+ return block.entries.length > 0;
739
+ }
740
+ function oneBlockPerDir(blocks) {
741
+ const dirs = [...new Set(blocks.map((block) => block.dir))];
742
+ return dirs.map((dir) => ({
743
+ dir,
744
+ entries: blocks.filter((block) => block.dir === dir).flatMap((block) => block.entries)
745
+ }));
746
+ }
747
+ function skillsCopiedBlocks(projectDir, copyResult) {
748
+ return oneBlockPerDir(
749
+ [
750
+ copiedSkillsBlock(projectDir, "global", copyResult.globalCopied),
751
+ copiedSkillsBlock(projectDir, "project", copyResult.projectCopied)
752
+ ].filter(hasEntries)
753
+ );
754
+ }
755
+ function copiedSkillsBlock(projectDir, scope, copied) {
885
756
  return {
886
- dir: resolveInstallPaths(cwd, scope).agentsDir,
887
- extension: agentCodec(providerInUse(installBaseDir(cwd, scope))).extension
757
+ dir: resolveInstallPaths(projectDir, scope).skillsDir,
758
+ entries: copied.map(({ skillId }) => `${skillId}/`)
759
+ };
760
+ }
761
+ function agentsCompiledBlocks(projectDir, compiled, agentScopeMap) {
762
+ const [globalAgents, projectAgents] = partition(
763
+ compiled,
764
+ (name) => agentScopeMap.get(name) === "global"
765
+ );
766
+ return oneBlockPerDir(
767
+ [
768
+ compiledAgentsBlock(projectDir, "global", globalAgents),
769
+ compiledAgentsBlock(projectDir, "project", projectAgents)
770
+ ].filter(hasEntries)
771
+ );
772
+ }
773
+ function compiledAgentsBlock(projectDir, scope, agents) {
774
+ const { extension } = agentCodec(providerInUse(installBaseDir(projectDir, scope)));
775
+ return {
776
+ dir: resolveInstallPaths(projectDir, scope).agentsDir,
777
+ entries: agents.map((name) => `${name}${extension}`)
888
778
  };
889
779
  }
890
780
  function splitAgentScopes(cwd, agentScopeMap) {
@@ -896,10 +786,9 @@ function splitAgentScopes(cwd, agentScopeMap) {
896
786
  isGlobalOnly: globalAgentCount > 0 && globalAgentCount === scopes.length
897
787
  };
898
788
  }
899
- function configsHoldingAssignments(split, paths) {
900
- if (split.isGlobalOnly) return [paths.global];
901
- if (split.globalAgentCount > 0) return [paths.global, paths.project];
902
- return [paths.project];
789
+ function configsWritten(projectDir, paths, globalWritten) {
790
+ if (isHomeDirectory(projectDir)) return [paths.project];
791
+ return globalWritten ? [paths.global, paths.project] : [paths.project];
903
792
  }
904
793
  function customizationSteps(split, globalConfigPath, projectDir) {
905
794
  if (split.isGlobalOnly) {
@@ -912,32 +801,18 @@ function customizationSteps(split, globalConfigPath, projectDir) {
912
801
  ];
913
802
  }
914
803
  async function getDashboardData(projectDir) {
915
- const [info, loaded, branding] = await Promise.all([
916
- getInstallationInfo(),
917
- loadProjectConfig(projectDir),
804
+ const [installations, branding] = await Promise.all([
805
+ getInstallationsByProvider(projectDir),
918
806
  resolveBranding(projectDir)
919
807
  ]);
920
- const activeSkills = loaded?.config.skills.filter((s) => !s.excluded);
921
- const skillCount = info?.skillCount ?? 0;
922
- const agentCount = info?.agentCount ?? 0;
923
- const mode = info?.mode ?? (activeSkills ? deriveInstallMode(activeSkills) : "eject");
924
- const source = loaded?.config.marketplace;
925
- return {
926
- name: branding.name,
927
- skillCount,
928
- agentCount,
929
- mode,
930
- ...source !== void 0 && { source }
931
- };
808
+ if (installations.length === 0) throw new Error(ERROR_MESSAGES.NO_INSTALLATION);
809
+ return { name: branding.name, installations };
932
810
  }
933
811
 
934
812
  export {
935
813
  Dashboard,
936
- dashboardCountLines,
937
814
  formatDashboardText,
938
- showDashboard,
939
815
  runDashboardFlow,
940
- Init,
941
- getDashboardData
816
+ Init
942
817
  };
943
- //# sourceMappingURL=chunk-NCWDK6L7.js.map
818
+ //# sourceMappingURL=chunk-YXKTY5WM.js.map