agents-inc 0.174.0 → 0.176.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 (90) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/dist/{chunk-APWMMZOK.js → chunk-3F5LT433.js} +157 -53
  3. package/dist/chunk-3F5LT433.js.map +1 -0
  4. package/dist/chunk-5CFHP6Z5.js +109 -0
  5. package/dist/chunk-5CFHP6Z5.js.map +1 -0
  6. package/dist/{chunk-3PJZ4QNJ.js → chunk-B7AVWSK2.js} +21 -11
  7. package/dist/chunk-B7AVWSK2.js.map +1 -0
  8. package/dist/{chunk-H5E6IO2L.js → chunk-C2BSCEDN.js} +9 -11
  9. package/dist/chunk-C2BSCEDN.js.map +1 -0
  10. package/dist/{chunk-R7GKQBZJ.js → chunk-CKBWEWHZ.js} +96 -52
  11. package/dist/chunk-CKBWEWHZ.js.map +1 -0
  12. package/dist/{chunk-IXVGBUWI.js → chunk-EC3JXT23.js} +5 -5
  13. package/dist/{chunk-E45IT3HC.js → chunk-ENET4IF6.js} +998 -472
  14. package/dist/chunk-ENET4IF6.js.map +1 -0
  15. package/dist/{chunk-FQF6VHO3.js → chunk-FACDJH6O.js} +12 -105
  16. package/dist/chunk-FACDJH6O.js.map +1 -0
  17. package/dist/{chunk-TVEDNGVP.js → chunk-H6WUOW5F.js} +2 -2
  18. package/dist/{chunk-7BHDKEGK.js → chunk-JNRACLNS.js} +3 -3
  19. package/dist/{chunk-IAQFZFWD.js → chunk-JTMSFBCA.js} +231 -24
  20. package/dist/chunk-JTMSFBCA.js.map +1 -0
  21. package/dist/{chunk-EFXVYQGT.js → chunk-MQZNDK5F.js} +39 -40
  22. package/dist/chunk-MQZNDK5F.js.map +1 -0
  23. package/dist/{chunk-QCX66KBM.js → chunk-SN64WNWE.js} +3 -3
  24. package/dist/{chunk-WUSEZFER.js → chunk-U46LYYRA.js} +3 -2
  25. package/dist/{chunk-WUSEZFER.js.map → chunk-U46LYYRA.js.map} +1 -1
  26. package/dist/{chunk-6PGXTLA4.js → chunk-U672FZVC.js} +2 -2
  27. package/dist/{chunk-AIBVAYHS.js → chunk-UE4Z3YMB.js} +2 -2
  28. package/dist/chunk-UE4Z3YMB.js.map +1 -0
  29. package/dist/{chunk-REHVGFJE.js → chunk-XMQIWPIR.js} +84 -32
  30. package/dist/chunk-XMQIWPIR.js.map +1 -0
  31. package/dist/{chunk-I3WF6L43.js → chunk-XYBHH3M5.js} +2 -2
  32. package/dist/{chunk-ECPFYHDX.js → chunk-ZBI6GFJD.js} +11 -11
  33. package/dist/chunk-ZBI6GFJD.js.map +1 -0
  34. package/dist/commands/build/marketplace.js +5 -4
  35. package/dist/commands/build/marketplace.js.map +1 -1
  36. package/dist/commands/build/plugins.js +7 -6
  37. package/dist/commands/build/plugins.js.map +1 -1
  38. package/dist/commands/compile.js +20 -16
  39. package/dist/commands/compile.js.map +1 -1
  40. package/dist/commands/doctor.js +106 -87
  41. package/dist/commands/doctor.js.map +1 -1
  42. package/dist/commands/edit.js +76 -48
  43. package/dist/commands/edit.js.map +1 -1
  44. package/dist/commands/eject.js +31 -18
  45. package/dist/commands/eject.js.map +1 -1
  46. package/dist/commands/init.js +17 -17
  47. package/dist/commands/list.js +10 -9
  48. package/dist/commands/list.js.map +1 -1
  49. package/dist/commands/new/marketplace.js +5 -4
  50. package/dist/commands/new/marketplace.js.map +1 -1
  51. package/dist/commands/search.js +14 -9
  52. package/dist/commands/search.js.map +1 -1
  53. package/dist/commands/share.js +20 -22
  54. package/dist/commands/share.js.map +1 -1
  55. package/dist/commands/uninstall.js +24 -19
  56. package/dist/commands/uninstall.js.map +1 -1
  57. package/dist/commands/update.js +110 -31
  58. package/dist/commands/update.js.map +1 -1
  59. package/dist/components/common/select-list.js +2 -2
  60. package/dist/components/common/skill-agent-summary.js +4 -3
  61. package/dist/components/common/summary-panel.js +5 -4
  62. package/dist/hooks/init.js +24 -25
  63. package/dist/hooks/init.js.map +1 -1
  64. package/dist/load-agent-defs-5BSECHE6.js +14 -0
  65. package/dist/{recompile-project-agents-KYK44C24.js → recompile-project-agents-U3UGHPWG.js} +8 -8
  66. package/dist/{source-loader-G5I4RNUP.js → source-loader-E2Y5MMN5.js} +4 -4
  67. package/package.json +1 -1
  68. package/dist/chunk-3PJZ4QNJ.js.map +0 -1
  69. package/dist/chunk-AIBVAYHS.js.map +0 -1
  70. package/dist/chunk-APWMMZOK.js.map +0 -1
  71. package/dist/chunk-E45IT3HC.js.map +0 -1
  72. package/dist/chunk-ECPFYHDX.js.map +0 -1
  73. package/dist/chunk-EFXVYQGT.js.map +0 -1
  74. package/dist/chunk-FQF6VHO3.js.map +0 -1
  75. package/dist/chunk-H5E6IO2L.js.map +0 -1
  76. package/dist/chunk-IAQFZFWD.js.map +0 -1
  77. package/dist/chunk-ORO2T4K2.js +0 -96
  78. package/dist/chunk-ORO2T4K2.js.map +0 -1
  79. package/dist/chunk-R7GKQBZJ.js.map +0 -1
  80. package/dist/chunk-REHVGFJE.js.map +0 -1
  81. package/dist/load-agent-defs-5U5KAURA.js +0 -14
  82. /package/dist/{chunk-IXVGBUWI.js.map → chunk-EC3JXT23.js.map} +0 -0
  83. /package/dist/{chunk-TVEDNGVP.js.map → chunk-H6WUOW5F.js.map} +0 -0
  84. /package/dist/{chunk-7BHDKEGK.js.map → chunk-JNRACLNS.js.map} +0 -0
  85. /package/dist/{chunk-QCX66KBM.js.map → chunk-SN64WNWE.js.map} +0 -0
  86. /package/dist/{chunk-6PGXTLA4.js.map → chunk-U672FZVC.js.map} +0 -0
  87. /package/dist/{chunk-I3WF6L43.js.map → chunk-XYBHH3M5.js.map} +0 -0
  88. /package/dist/{load-agent-defs-5U5KAURA.js.map → load-agent-defs-5BSECHE6.js.map} +0 -0
  89. /package/dist/{recompile-project-agents-KYK44C24.js.map → recompile-project-agents-U3UGHPWG.js.map} +0 -0
  90. /package/dist/{source-loader-G5I4RNUP.js.map → source-loader-E2Y5MMN5.js.map} +0 -0
@@ -1,19 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- getSkillEntryDisplayName,
4
3
  typedValues
5
- } from "./chunk-AIBVAYHS.js";
4
+ } from "./chunk-UE4Z3YMB.js";
6
5
  import {
7
- CLI_COLORS,
8
- EJECT_SOURCE,
9
- UI_SYMBOLS,
10
6
  isActiveAt,
11
7
  isGlobalTombstone
12
- } from "./chunk-WUSEZFER.js";
13
-
14
- // src/cli/components/common/skill-agent-summary.tsx
15
- import { Box, Text } from "ink";
16
- import "react";
8
+ } from "./chunk-U46LYYRA.js";
17
9
 
18
10
  // src/cli/lib/configuration/scope-diff.ts
19
11
  import { difference, indexBy, partition, unique } from "remeda";
@@ -116,6 +108,12 @@ function toRemovedSkillRow(skill) {
116
108
  function toRemovedAgentRow(agent) {
117
109
  return { name: agent.name, status: "removed" };
118
110
  }
111
+ function namedByActiveEntries(entries) {
112
+ return indexBy(
113
+ entries.filter((entry) => !entry.excluded),
114
+ ({ id }) => id
115
+ );
116
+ }
119
117
  var AGENT_SETTINGS = [
120
118
  ["model", (agent) => agent.model],
121
119
  ["codex model", (agent) => agent.codexModel],
@@ -137,8 +135,7 @@ function namedByEntries(change, before, after) {
137
135
  return { ...change, namedBy };
138
136
  }
139
137
  function activeEntriesOf(skillIds, skills) {
140
- const active = skills.filter((entry) => !entry.excluded && skillIds.includes(entry.id));
141
- return indexBy(active, ({ id }) => id);
138
+ return namedByActiveEntries(skills.filter((entry) => skillIds.includes(entry.id)));
142
139
  }
143
140
  function agentStateIn(config, name) {
144
141
  const agent = config.agents.find((entry) => entry.name === name && !entry.excluded);
@@ -164,100 +161,10 @@ function assignedSkillIds(rows) {
164
161
  return unique(typedValues(rows ?? {}).flatMap((assignments) => assignments.map(({ id }) => id)));
165
162
  }
166
163
 
167
- // src/cli/components/common/skill-agent-summary.tsx
168
- import { jsx, jsxs } from "react/jsx-runtime";
169
- var TableHeader = ({ children }) => /* @__PURE__ */ jsx(Text, { bold: true, color: CLI_COLORS.WARNING, children });
170
- var ScopeLabel = ({ children }) => /* @__PURE__ */ jsx(Text, { color: CLI_COLORS.WHITE, backgroundColor: CLI_COLORS.LABEL_BG, children: ` ${children} ` });
171
- var EjectIcon = () => /* @__PURE__ */ jsxs(Text, { color: CLI_COLORS.WARNING, children: [
172
- " ",
173
- UI_SYMBOLS.EJECT
174
- ] });
175
- var DIFF_PREFIX = {
176
- added: `${UI_SYMBOLS.ADDED} `,
177
- "mode-changed": `${UI_SYMBOLS.CHANGED} `,
178
- overwritten: `${UI_SYMBOLS.OVERWRITTEN} `,
179
- changed: `${UI_SYMBOLS.CHANGED} `,
180
- removed: `${UI_SYMBOLS.REMOVED} `,
181
- unchanged: `${UI_SYMBOLS.BULLET} `
182
- };
183
- var DIFF_COLOR = {
184
- added: CLI_COLORS.SUCCESS,
185
- "mode-changed": CLI_COLORS.WARNING,
186
- overwritten: CLI_COLORS.WARNING,
187
- changed: CLI_COLORS.WARNING,
188
- removed: CLI_COLORS.ERROR,
189
- unchanged: CLI_COLORS.NEUTRAL
190
- };
191
- var NAME_GUTTER_COLUMNS = 3;
192
- var SkillRow = ({ row }) => /* @__PURE__ */ jsxs(Box, { width: "50%", paddingRight: NAME_GUTTER_COLUMNS, children: [
193
- /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { color: DIFF_COLOR[row.status], children: DIFF_PREFIX[row.status] }) }),
194
- /* @__PURE__ */ jsxs(Text, { color: DIFF_COLOR[row.status], children: [
195
- getSkillEntryDisplayName(row),
196
- row.source === EJECT_SOURCE && /* @__PURE__ */ jsx(EjectIcon, {})
197
- ] })
198
- ] });
199
- var AgentRow = ({ row }) => /* @__PURE__ */ jsxs(Text, { color: DIFF_COLOR[row.status], children: [
200
- DIFF_PREFIX[row.status],
201
- row.name
202
- ] });
203
- var skillRowKey = (row) => row.status === "removed" ? `removed-${row.id}` : row.id;
204
- var agentRowKey = (row) => row.status === "removed" ? `removed-${row.name}` : row.name;
205
- var SkillAgentSummary = ({
206
- skillConfigs,
207
- agentConfigs,
208
- ...baseline
209
- }) => {
210
- const diff = computeScopeDiff({
211
- currentSkills: skillConfigs,
212
- currentAgents: agentConfigs,
213
- ...baseline
214
- });
215
- if (!diff.hasContent) return null;
216
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", width: "100%", children: [
217
- /* @__PURE__ */ jsxs(
218
- Box,
219
- {
220
- flexDirection: "column",
221
- borderStyle: "single",
222
- flexGrow: 2,
223
- flexBasis: 0,
224
- borderRight: true,
225
- borderTop: false,
226
- borderBottom: false,
227
- borderLeft: false,
228
- borderColor: CLI_COLORS.NEUTRAL,
229
- borderRightDimColor: true,
230
- children: [
231
- /* @__PURE__ */ jsx(TableHeader, { children: "Skills" }),
232
- diff.projectSkillRows.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
233
- /* @__PURE__ */ jsx(ScopeLabel, { children: "Project" }),
234
- /* @__PURE__ */ jsx(Box, { flexWrap: "wrap", children: diff.projectSkillRows.map((row) => /* @__PURE__ */ jsx(SkillRow, { row }, skillRowKey(row))) })
235
- ] }),
236
- diff.globalSkillRows.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
237
- /* @__PURE__ */ jsx(ScopeLabel, { children: "Global" }),
238
- /* @__PURE__ */ jsx(Box, { flexWrap: "wrap", children: diff.globalSkillRows.map((row) => /* @__PURE__ */ jsx(SkillRow, { row }, skillRowKey(row))) })
239
- ] })
240
- ]
241
- }
242
- ),
243
- /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, flexBasis: 0, marginLeft: 1, paddingLeft: 1, children: [
244
- /* @__PURE__ */ jsx(TableHeader, { children: "Agents" }),
245
- diff.projectAgentRows.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
246
- /* @__PURE__ */ jsx(ScopeLabel, { children: "Project" }),
247
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: diff.projectAgentRows.map((row) => /* @__PURE__ */ jsx(AgentRow, { row }, agentRowKey(row))) })
248
- ] }),
249
- diff.globalAgentRows.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
250
- /* @__PURE__ */ jsx(ScopeLabel, { children: "Global" }),
251
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: diff.globalAgentRows.map((row) => /* @__PURE__ */ jsx(AgentRow, { row }, agentRowKey(row))) })
252
- ] })
253
- ] })
254
- ] });
255
- };
256
-
257
164
  export {
258
165
  computeScopeDiff,
259
166
  formatScopeTag,
260
- agentChangesAmong,
261
- SkillAgentSummary
167
+ namedByActiveEntries,
168
+ agentChangesAmong
262
169
  };
263
- //# sourceMappingURL=chunk-FQF6VHO3.js.map
170
+ //# sourceMappingURL=chunk-FACDJH6O.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/configuration/scope-diff.ts"],"sourcesContent":["import { difference, indexBy, partition, unique } from \"remeda\";\nimport type { AgentScopeConfig, SkillConfig, SkillScope } from \"../../types/config\";\nimport type { AgentName, SkillId, StackAgentConfig } from \"../../types/index\";\nimport { typedValues } from \"../../utils/typed-object\";\nimport { isActiveAt, isGlobalTombstone, type ScopedEntry } from \"./scope-predicates\";\n\nexport type ScopeDiffInput = {\n currentSkills: SkillConfig[];\n currentAgents: AgentScopeConfig[];\n installedSkillConfigs: SkillConfig[] | null;\n installedAgentConfigs: AgentScopeConfig[] | null;\n isInitMode: boolean;\n /** Skills whose files the run writes over where they stand. */\n overwrittenSkillIds?: ReadonlySet<SkillId>;\n /** Sub-agents that keep their slot and still change. */\n changedAgentNames?: ReadonlySet<AgentName>;\n};\n\nexport type DiffRowStatus =\n \"added\" | \"mode-changed\" | \"overwritten\" | \"changed\" | \"removed\" | \"unchanged\";\n\nexport type SkillDiffRow = {\n id: SkillId;\n source: string;\n status: Exclude<DiffRowStatus, \"changed\">;\n /** The name the entry the row was drawn from records; absent where it records none. */\n displayName?: string;\n};\n\nexport type AgentDiffRow = {\n name: AgentName;\n status: Exclude<DiffRowStatus, \"mode-changed\" | \"overwritten\">;\n};\n\nexport type ScopeDiff = {\n projectSkillRows: SkillDiffRow[];\n globalSkillRows: SkillDiffRow[];\n projectAgentRows: AgentDiffRow[];\n globalAgentRows: AgentDiffRow[];\n hasContent: boolean;\n};\n\nconst NOTHING: ReadonlySet<never> = new Set();\n\n/** One scope's share of a roster's diff: the entries listed with a status, then the removals. */\ntype ScopeEntries<Entry> = { listed: Entry[]; removed: Entry[] };\n\ntype RosterDiff<Entry> = Record<SkillScope, ScopeEntries<Entry>>;\n\n/**\n * A tombstone occupies its (id, scope) slot without filling it: it silences a global install at\n * project scope. Slot checks count tombstones; removal and `~` read the active baseline only.\n */\nexport function computeScopeDiff(input: ScopeDiffInput): ScopeDiff {\n const { currentSkills, currentAgents, installedSkillConfigs, installedAgentConfigs, isInitMode } =\n input;\n const overwritten = input.overwrittenSkillIds ?? NOTHING;\n const changed = input.changedAgentNames ?? NOTHING;\n\n const skills = diffRoster(currentSkills, installedSkillConfigs, (skill) => skill.id, isInitMode);\n const agents = diffRoster(\n currentAgents,\n installedAgentConfigs,\n (agent) => agent.name,\n isInitMode,\n );\n const skillRow = skillRowClassifier(installedSkillConfigs, overwritten);\n const agentRow = agentRowClassifier(installedAgentConfigs, changed);\n\n const projectSkillRows = rowsOf(skills.project, skillRow, toRemovedSkillRow);\n const globalSkillRows = rowsOf(skills.global, skillRow, toRemovedSkillRow);\n const projectAgentRows = rowsOf(agents.project, agentRow, toRemovedAgentRow);\n const globalAgentRows = rowsOf(agents.global, agentRow, toRemovedAgentRow);\n\n const hasContent = [projectSkillRows, globalSkillRows, projectAgentRows, globalAgentRows].some(\n (rows) => rows.length > 0,\n );\n\n return { projectSkillRows, globalSkillRows, projectAgentRows, globalAgentRows, hasContent };\n}\n\nfunction diffRoster<Entry extends ScopedEntry>(\n current: Entry[],\n installed: Entry[] | null,\n identityOf: (entry: Entry) => string,\n isInitMode: boolean,\n): RosterDiff<Entry> {\n // The installs the baseline actually records; tombstones are not installs.\n const activeBaseline = (installed ?? []).filter((entry) => !entry.excluded);\n const vacated = vacatedInstalls(activeBaseline, current, identityOf);\n const projectEntries = current.filter((entry) => isActiveAt(entry, \"project\"));\n const claimedByProject = new Set(projectEntries.map(identityOf));\n // A vacated global the project claims is inherited: listed once under Global, never removed.\n const [inheritedGlobals, removedGlobals] = partition(\n vacated.filter((entry) => entry.scope === \"global\"),\n (entry) => claimedByProject.has(identityOf(entry)),\n );\n\n return {\n project: {\n listed: projectEntries,\n removed: vacated.filter((entry) => entry.scope === \"project\"),\n },\n global: {\n listed: [\n ...current.filter((entry) => isActiveAt(entry, \"global\")),\n ...inheritedGlobals,\n ...current.filter(isGlobalTombstone),\n ],\n removed: isInitMode ? [] : removedGlobals,\n },\n };\n}\n\n/** Baseline installs whose slot nothing in current, active or tombstone, occupies. */\nfunction vacatedInstalls<Entry extends ScopedEntry>(\n activeBaseline: Entry[],\n current: Entry[],\n identityOf: (entry: Entry) => string,\n): Entry[] {\n const slotOf = (entry: Entry) => slotKey(identityOf(entry), entry.scope);\n const occupiedSlots = new Set(current.map(slotOf));\n return activeBaseline.filter((install) => !occupiedSlots.has(slotOf(install)));\n}\n\nfunction rowsOf<Entry, Row>(\n entries: ScopeEntries<Entry>,\n toRow: (entry: Entry) => Row,\n toRemovedRow: (entry: Entry) => Row,\n): Row[] {\n return [...entries.listed.map(toRow), ...entries.removed.map(toRemovedRow)];\n}\n\n/** The `(id, scope)` SLOT key this module diffs on, rather than the id alone. */\nfunction slotKey(identity: string, scope: SkillScope | undefined): string {\n return `${identity}:${scope}`;\n}\n\nexport function formatScopeTag(scope: SkillScope): \"[G]\" | \"[P]\" {\n return scope === \"global\" ? \"[G]\" : \"[P]\";\n}\n\nfunction skillRowClassifier(\n installed: SkillConfig[] | null,\n overwritten: ReadonlySet<SkillId>,\n): (skill: SkillConfig) => SkillDiffRow {\n const installedSlots = installed\n ? new Set(installed.map((skill) => slotKey(skill.id, skill.scope)))\n : null;\n const installedOriginBySlot = installed\n ? new Map(\n installed\n .filter((skill) => !skill.excluded)\n .map((skill) => [slotKey(skill.id, skill.scope), skill.origin]),\n )\n : null;\n return (skill) => ({\n id: skill.id,\n source: skill.origin,\n status: skillStatus(skill, installedSlots, installedOriginBySlot, overwritten),\n ...recordedNameOf(skill),\n });\n}\n\nfunction recordedNameOf(skill: SkillConfig): Pick<SkillDiffRow, \"displayName\"> {\n return skill.displayName === undefined ? {} : { displayName: skill.displayName };\n}\n\nfunction agentRowClassifier(\n installed: AgentScopeConfig[] | null,\n changed: ReadonlySet<AgentName>,\n): (agent: AgentScopeConfig) => AgentDiffRow {\n const installedSlots = installed\n ? new Set(installed.map((agent) => slotKey(agent.name, agent.scope)))\n : null;\n return (agent) => ({ name: agent.name, status: agentStatus(agent, installedSlots, changed) });\n}\n\n/**\n * Compares `origin`, which is where a skill's install mode is recorded. An overwrite outranks a\n * mode change: a copy its plugin replaces is deleted, not merely switched. A mask is never written.\n */\nfunction skillStatus(\n skill: SkillConfig,\n installedSlots: Set<string> | null,\n installedOriginBySlot: Map<string, string> | null,\n overwritten: ReadonlySet<SkillId>,\n): SkillDiffRow[\"status\"] {\n const slot = slotKey(skill.id, skill.scope);\n if (installedSlots === null || !installedSlots.has(slot)) return \"added\";\n if (!skill.excluded && overwritten.has(skill.id)) return \"overwritten\";\n\n const installedOrigin = installedOriginBySlot?.get(slot);\n const modeChanged = installedOrigin != null && installedOrigin !== skill.origin;\n return modeChanged ? \"mode-changed\" : \"unchanged\";\n}\n\n/** A mask is never the sub-agent that changes: its active half is. */\nfunction agentStatus(\n agent: AgentScopeConfig,\n installedSlots: Set<string> | null,\n changed: ReadonlySet<AgentName>,\n): AgentDiffRow[\"status\"] {\n const isNew = installedSlots === null || !installedSlots.has(slotKey(agent.name, agent.scope));\n if (isNew) return \"added\";\n return !agent.excluded && changed.has(agent.name) ? \"changed\" : \"unchanged\";\n}\n\nfunction toRemovedSkillRow(skill: SkillConfig): SkillDiffRow {\n return { id: skill.id, source: skill.origin, status: \"removed\", ...recordedNameOf(skill) };\n}\n\nfunction toRemovedAgentRow(agent: AgentScopeConfig): AgentDiffRow {\n return { name: agent.name, status: \"removed\" };\n}\n\n/** The entry each skill is named by, as a panel row drawn from that entry names it. */\nexport type NamedBy = Partial<Record<SkillId, Pick<SkillConfig, \"id\" | \"displayName\">>>;\n\nexport function namedByActiveEntries(\n entries: readonly Pick<SkillConfig, \"id\" | \"displayName\" | \"excluded\">[],\n): NamedBy {\n return indexBy(\n entries.filter((entry) => !entry.excluded),\n ({ id }) => id,\n );\n}\n\n/** A sub-agent that keeps its slot and still changes: the skills its rows gain and lose, and its retunes. */\nexport type AgentChange = {\n name: AgentName;\n scope: SkillScope;\n gains: SkillId[];\n loses: SkillId[];\n settings: SettingChange[];\n /** The run's entry for a skill it gains, the install's for one it loses. */\n namedBy?: NamedBy;\n};\n\n/** `undefined` where the setting is left to its default. */\nexport type SettingChange = {\n setting: AgentSetting;\n from: string | undefined;\n to: string | undefined;\n};\n\ntype AgentSetting = \"model\" | \"codex model\" | \"effort\";\n\nconst AGENT_SETTINGS: ReadonlyArray<\n [AgentSetting, (agent: AgentScopeConfig) => string | undefined]\n> = [\n [\"model\", (agent) => agent.model],\n [\"codex model\", (agent) => agent.codexModel],\n [\"effort\", (agent) => agent.effort],\n];\n\n/** One sub-agent as a config records it: its entry and its skill rows. */\nexport type AgentState = { agent: AgentScopeConfig; rows: StackAgentConfig | undefined };\n\ntype AgentsAndRows = {\n agents: AgentScopeConfig[];\n skills: SkillConfig[];\n stack?: Partial<Record<string, StackAgentConfig>>;\n};\n\n/** How each named sub-agent moves between two configs; one either config lacks is not named. */\nexport function agentChangesAmong(\n names: readonly AgentName[],\n before: AgentsAndRows,\n after: AgentsAndRows,\n): AgentChange[] {\n return names.flatMap((name) => {\n const was = agentStateIn(before, name);\n const is = agentStateIn(after, name);\n if (was === undefined || is === undefined) return [];\n return [namedByEntries(agentChange(was, is), before.skills, after.skills)];\n });\n}\n\nfunction namedByEntries(\n change: AgentChange,\n before: SkillConfig[],\n after: SkillConfig[],\n): AgentChange {\n const namedBy = {\n ...activeEntriesOf(change.loses, before),\n ...activeEntriesOf(change.gains, after),\n };\n return { ...change, namedBy };\n}\n\nfunction activeEntriesOf(skillIds: readonly SkillId[], skills: SkillConfig[]): NamedBy {\n return namedByActiveEntries(skills.filter((entry) => skillIds.includes(entry.id)));\n}\n\n/** Its active entry, never the mask a project's own copy leaves; `undefined` where none is. */\nfunction agentStateIn(config: AgentsAndRows, name: AgentName): AgentState | undefined {\n const agent = config.agents.find((entry) => entry.name === name && !entry.excluded);\n return agent === undefined ? undefined : { agent, rows: config.stack?.[name] };\n}\n\nexport function agentChange(before: AgentState, after: AgentState): AgentChange {\n const beforeIds = assignedSkillIds(before.rows);\n const afterIds = assignedSkillIds(after.rows);\n\n return {\n name: after.agent.name,\n scope: after.agent.scope,\n gains: difference(afterIds, beforeIds),\n loses: difference(beforeIds, afterIds),\n settings: settingChanges(before.agent, after.agent),\n };\n}\n\nfunction settingChanges(before: AgentScopeConfig, after: AgentScopeConfig): SettingChange[] {\n return AGENT_SETTINGS.filter(([, read]) => read(before) !== read(after)).map(\n ([setting, read]) => ({ setting, from: read(before), to: read(after) }),\n );\n}\n\nfunction assignedSkillIds(rows: StackAgentConfig | undefined): SkillId[] {\n return unique(typedValues(rows ?? {}).flatMap((assignments) => assignments.map(({ id }) => id)));\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  execCommand,
4
4
  getErrorMessage
5
- } from "./chunk-E45IT3HC.js";
5
+ } from "./chunk-ENET4IF6.js";
6
6
 
7
7
  // src/cli/utils/open-url.ts
8
8
  function browserOpenerCommand(platform, url) {
@@ -32,4 +32,4 @@ async function openUrl(url) {
32
32
  export {
33
33
  openUrl
34
34
  };
35
- //# sourceMappingURL=chunk-TVEDNGVP.js.map
35
+ //# sourceMappingURL=chunk-H6WUOW5F.js.map
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getLocalAgentDefinitions
4
- } from "./chunk-IXVGBUWI.js";
4
+ } from "./chunk-EC3JXT23.js";
5
5
  import {
6
6
  loadMergedAgents
7
- } from "./chunk-E45IT3HC.js";
7
+ } from "./chunk-ENET4IF6.js";
8
8
 
9
9
  // src/cli/lib/operations/project/load-agent-defs.ts
10
10
  async function loadAgentDefs() {
@@ -20,4 +20,4 @@ async function loadAgentDefs() {
20
20
  export {
21
21
  loadAgentDefs
22
22
  };
23
- //# sourceMappingURL=chunk-7BHDKEGK.js.map
23
+ //# sourceMappingURL=chunk-JNRACLNS.js.map
@@ -1,12 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ namedByActiveEntries
4
+ } from "./chunk-FACDJH6O.js";
5
+ import {
6
+ ConfigLoadError,
7
+ FailedLeavingPluginsSwitchedOnError,
8
+ INFO_MESSAGES,
9
+ PluginsLeftSwitchedOnError,
3
10
  STATUS_MESSAGES,
4
11
  addedToGlobalSubAgents,
5
12
  buildMarketplacePluginRef,
13
+ chooseProviderForThisRun,
6
14
  claimSlug,
15
+ codexPluginLeftSwitchedOn,
7
16
  completedWithFailures,
17
+ configDeclaresNothing,
8
18
  copy,
9
19
  defaultUsageGuidance,
20
+ detectInstallations,
10
21
  directoryExists,
11
22
  fetchMarketplace,
12
23
  fileExists,
@@ -16,6 +27,7 @@ import {
16
27
  getErrorMessage,
17
28
  getStackSkillIds,
18
29
  glob,
30
+ holdsAConfigDeclaringNothing,
19
31
  hostAt,
20
32
  installationConfigsUnreadable,
21
33
  isHomeDirectory,
@@ -24,6 +36,7 @@ import {
24
36
  loadStackById,
25
37
  parseFrontmatter,
26
38
  pluginsInstalled,
39
+ pluginsLeftSwitchedOn,
27
40
  propagatedRecompileSummary,
28
41
  providerInUse,
29
42
  providerToNameAt,
@@ -44,13 +57,13 @@ import {
44
57
  sharedConfigProjectScopeAtHome,
45
58
  skillAssignedToNoAgent,
46
59
  skillMetadataUnusableDetail,
60
+ skippedSkills,
47
61
  skippedUnknownAgents,
48
- skippedUnknownSkills,
49
62
  validateSkillPath,
50
63
  verbose,
51
64
  warn,
52
65
  writeFile
53
- } from "./chunk-E45IT3HC.js";
66
+ } from "./chunk-ENET4IF6.js";
54
67
  import {
55
68
  BUILT_IN_MATRIX,
56
69
  getCategoryDomain,
@@ -60,22 +73,24 @@ import {
60
73
  typedEntries,
61
74
  typedKeys,
62
75
  typedValues
63
- } from "./chunk-AIBVAYHS.js";
76
+ } from "./chunk-UE4Z3YMB.js";
64
77
  import {
65
78
  CLI_COLORS,
66
79
  CLI_INVOKE_COMMAND,
67
80
  DEFAULT_BRANDING,
81
+ EDITOR_URL,
68
82
  EJECT_SOURCE,
69
83
  GITHUB_PREFIX,
70
84
  GITHUB_SOURCE,
71
85
  LOCAL_SKILLS_PATH,
72
86
  MIN_TERMINAL_SIZE,
87
+ PROVIDERS,
73
88
  STANDARD_FILES,
74
89
  externalIdsNamingNoDirectory,
75
90
  isActiveAt,
76
91
  orderDomains,
77
92
  seedExternalSkillSchema
78
- } from "./chunk-WUSEZFER.js";
93
+ } from "./chunk-U46LYYRA.js";
79
94
 
80
95
  // src/cli/utils/terminal.ts
81
96
  function clearTerminalScreen() {
@@ -103,8 +118,100 @@ var EXIT_CODES = {
103
118
  COMPLETED_WITH_FAILURES: 5
104
119
  };
105
120
 
106
- // src/cli/lib/seed/external-skills.ts
121
+ // src/cli/lib/installation/provider-flag.ts
107
122
  import os from "os";
123
+ import { Flags } from "@oclif/core";
124
+ function providerFlag() {
125
+ return Flags.string({
126
+ description: "Which provider's installation this run is about",
127
+ helpValue: `<${PROVIDERS.join("|")}>`,
128
+ options: [...PROVIDERS]
129
+ });
130
+ }
131
+ function providerNamedBy(flagValue) {
132
+ if (flagValue === void 0) return void 0;
133
+ return PROVIDERS.find((provider) => provider === flagValue);
134
+ }
135
+ var PROVIDER_FLAG = "--provider";
136
+ var PROVIDER_FLAG_WITH_ITS_VALUE = `${PROVIDER_FLAG}=`;
137
+ var END_OF_FLAGS = "--";
138
+ function providerNamedIn(argv) {
139
+ const end = argv.indexOf(END_OF_FLAGS);
140
+ const flags = end === -1 ? argv : argv.slice(0, end);
141
+ const spaced = flags.indexOf(PROVIDER_FLAG);
142
+ if (spaced !== -1) return providerNamedBy(flags[spaced + 1]);
143
+ const joined = flags.find((token) => token.startsWith(PROVIDER_FLAG_WITH_ITS_VALUE));
144
+ return providerNamedBy(joined?.slice(PROVIDER_FLAG_WITH_ITS_VALUE.length));
145
+ }
146
+ function providerNeedsAConfigurationToInstall() {
147
+ return `--provider names which installation to create and needs the configuration to create it from, so it is only meaningful beside --from. Build one at ${EDITOR_URL}, then run '${CLI_INVOKE_COMMAND} init --from <id> --provider <provider>'.`;
148
+ }
149
+ function ambiguousInstallation(subject, providers, scopeRoot) {
150
+ return `${scopeRoot} holds ${providers.length} installations \u2014 ${providers.join(" and ")} \u2014 so ${subject} cannot tell which one you mean. Name it with --provider <${providers.join("|")}>. Nothing has been changed.`;
151
+ }
152
+ async function installationsInPlay(cwd) {
153
+ const found = await detectInstallations(cwd);
154
+ const inTheProject = atScope(found, "project");
155
+ if (inTheProject.length > 0) return { scopeRoot: cwd, providers: providersOf(inTheProject) };
156
+ return { scopeRoot: os.homedir(), providers: providersOf(atScope(found, "global")) };
157
+ }
158
+ function atScope(found, scope) {
159
+ return found.filter((installation) => installation.scope === scope);
160
+ }
161
+ function providersOf(installations) {
162
+ return installations.map((installation) => installation.provider);
163
+ }
164
+ async function refuseAnAmbiguousInstallation(cwd, subject, named, onAmbiguous) {
165
+ if (named !== void 0) {
166
+ chooseProviderForThisRun(named);
167
+ return;
168
+ }
169
+ const { scopeRoot, providers } = await installationsInPlay(cwd);
170
+ if (providers.length <= 1) return;
171
+ onAmbiguous(ambiguousInstallation(subject, providers, scopeRoot));
172
+ }
173
+ async function holdsOnlyAConfigDeclaringNothing(cwd) {
174
+ if (!await holdsAConfigDeclaringNothing(cwd)) return false;
175
+ return atScope(await detectInstallations(cwd), "project").length === 0;
176
+ }
177
+ async function homeHoldsAnInstallationFor(cwd, named) {
178
+ const atHome = providersOf(atScope(await detectInstallations(cwd), "global")).filter(
179
+ (provider) => named === void 0 || provider === named
180
+ );
181
+ const declaringContent = await Promise.all(atHome.map(homeConfigDeclaresContent));
182
+ return declaringContent.includes(true);
183
+ }
184
+ async function homeConfigDeclaresContent(provider) {
185
+ try {
186
+ return !await configDeclaresNothing(os.homedir(), provider);
187
+ } catch (error) {
188
+ if (error instanceof ConfigLoadError) return true;
189
+ throw error;
190
+ }
191
+ }
192
+ async function providersInPlay(cwd) {
193
+ return (await installationsInPlay(cwd)).providers;
194
+ }
195
+ async function installationToName(cwd, named) {
196
+ if (named !== void 0) return named;
197
+ const providers = await providersInPlay(cwd);
198
+ return providers.length > 1 ? providers : void 0;
199
+ }
200
+ async function ambiguityFinding(cwd) {
201
+ const { scopeRoot, providers } = await installationsInPlay(cwd);
202
+ if (providers.length <= 1) return null;
203
+ return ambiguousInstallation("every command that acts on one", providers, scopeRoot);
204
+ }
205
+ async function otherInstallationsInThisScope(cwd) {
206
+ const { scopeRoot, providers } = await installationsInPlay(cwd);
207
+ const showing = providerInUse(scopeRoot);
208
+ const others = providers.filter((provider) => provider !== showing);
209
+ if (others.length === 0) return null;
210
+ return `${scopeRoot} holds ${providers.length} installations \u2014 ${providers.join(" and ")} \u2014 and this is the ${showing} one. Show another with --provider <${providers.join("|")}>.`;
211
+ }
212
+
213
+ // src/cli/lib/seed/external-skills.ts
214
+ import os2 from "os";
108
215
  import path from "path";
109
216
  import { mkdtemp } from "fs/promises";
110
217
 
@@ -326,9 +433,38 @@ function notADirectoryNameError(ids) {
326
433
  "A skill id is the directory the skill is written into, so an id holding a path separator, or naming '.' or '..', would be written somewhere other than a directory of its own, and one holding a control character would hand it to the terminal wherever that directory is named. Re-share it with each skill above added again, which mints an id \u2014 'external-<category>-<name>' \u2014 that names one directory."
327
434
  ].join("\n");
328
435
  }
436
+ var DIRECTORY_NAME_MAX_BYTES = 255;
437
+ function overrunsADirectoryName(id) {
438
+ return Buffer.byteLength(id, "utf8") > DIRECTORY_NAME_MAX_BYTES;
439
+ }
440
+ function externalIdsTooLongForADirectory(payload) {
441
+ return Object.keys(payload.external ?? {}).filter(overrunsADirectoryName);
442
+ }
443
+ function tooLongForADirectoryError(ids) {
444
+ return [
445
+ "This configuration cannot be installed: these skills travel inside it under ids longer than a directory name may be:",
446
+ ...ids.map((id) => ` ${JSON.stringify(id)}`),
447
+ `A skill id is the directory the skill is written into, and a directory name may hold at most ${String(DIRECTORY_NAME_MAX_BYTES)} bytes, so none of these could be written. Re-share it without each skill above.`
448
+ ].join("\n");
449
+ }
450
+ var CARRIED_ID_PREFIX = "external-";
451
+ function externalIdsLackingThePrefix(payload) {
452
+ return Object.keys(payload.external ?? {}).filter((id) => !id.startsWith(CARRIED_ID_PREFIX));
453
+ }
454
+ function lacksThePrefixError(ids) {
455
+ return [
456
+ "This configuration cannot be installed: these skills travel inside it under ids that do not start with 'external-':",
457
+ ...ids.map((id) => ` ${id}`),
458
+ "A skill id is the directory the skill installs into, and no marketplace may publish under the name 'external', so an id starting 'external-' is the only kind that can never take the place of a marketplace's skill. Re-share it with each skill above added again, which mints such an id \u2014 'external-<category>-<name>'."
459
+ ].join("\n");
460
+ }
329
461
  function registerExternalSkills(payload, matrix2, projectDir) {
330
462
  const notDirectoryNames = externalIdsNamingNoDirectory(payload);
331
463
  if (notDirectoryNames.length > 0) throw new Error(notADirectoryNameError(notDirectoryNames));
464
+ const tooLong = externalIdsTooLongForADirectory(payload);
465
+ if (tooLong.length > 0) throw new Error(tooLongForADirectoryError(tooLong));
466
+ const unprefixed = externalIdsLackingThePrefix(payload);
467
+ if (unprefixed.length > 0) throw new Error(lacksThePrefixError(unprefixed));
332
468
  const externals = selectedExternals(payload);
333
469
  const asPlugin = askedForAsPlugin(externals);
334
470
  const colliding = claimingACatalogueId(externals, matrix2);
@@ -344,7 +480,7 @@ async function writeExternalSkills(installs) {
344
480
  var SCRATCH_DIR_PREFIX = "agents-inc-carried-";
345
481
  async function carriedSkillsThatDiffer(installs) {
346
482
  if (installs.length === 0) return [];
347
- const scratch = await mkdtemp(path.join(os.tmpdir(), SCRATCH_DIR_PREFIX));
483
+ const scratch = await mkdtemp(path.join(os2.tmpdir(), SCRATCH_DIR_PREFIX));
348
484
  try {
349
485
  const written = await Promise.all(
350
486
  installs.map(async (install) => writeExternalSkill(await scratchCopyOf(install, scratch)))
@@ -495,7 +631,7 @@ async function readCarriedSkills(owned) {
495
631
  }
496
632
 
497
633
  // src/cli/lib/seed/seed-apply.ts
498
- import os2 from "os";
634
+ import os3 from "os";
499
635
  import { isDeepEqual, omit, partition, pick } from "remeda";
500
636
  var NOTHING_KEPT = {
501
637
  authoredSkillIds: [],
@@ -572,7 +708,7 @@ function withAgentKeptRows(carried, agent, keptRows, payloadRows) {
572
708
  };
573
709
  }
574
710
  async function readInstalledGlobal(projectDir) {
575
- const loaded = await loadProjectConfigFromDir(os2.homedir(), providerInUse(projectDir));
711
+ const loaded = await loadProjectConfigFromDir(os3.homedir(), providerInUse(projectDir));
576
712
  return loaded?.config ?? null;
577
713
  }
578
714
  var NO_GLOBAL_ENTRIES = { skillIds: [], agentNames: [] };
@@ -750,8 +886,12 @@ function entriesActiveAt(skills, agents, scope) {
750
886
  agentNames: agents.filter((agent) => isActiveAt(agent, scope)).map((agent) => agent.name)
751
887
  };
752
888
  }
889
+ function panelRowEntries(held) {
890
+ return namedByActiveEntries(held.result.skills);
891
+ }
753
892
  function joinedStatement(held) {
754
- return held.joined.length === 0 ? [] : [addedToGlobalSubAgents(held.joined)];
893
+ if (held.joined.length === 0) return [];
894
+ return [addedToGlobalSubAgents(held.joined, panelRowEntries(held))];
755
895
  }
756
896
  function projectScopedContent(result) {
757
897
  return entriesActiveAt(result.skills, result.agentConfigs, "project");
@@ -769,19 +909,37 @@ import { unique } from "remeda";
769
909
  // src/cli/lib/operations/source/ensure-marketplace.ts
770
910
  async function ensureMarketplace(sourceResult, host) {
771
911
  const marketplace = await resolveMarketplaceName(sourceResult);
772
- if (marketplace === null) return { marketplace: null, registered: false };
912
+ if (marketplace === null) return { marketplace: null, registered: false, leftOn: [] };
773
913
  const exists = await host.marketplaceExists(marketplace);
774
914
  if (!exists) {
775
915
  const marketplaceSource = sourceResult.sourceConfig.source.replace(/^github:/, "");
776
916
  await host.addMarketplace(marketplaceSource);
777
- return { marketplace, registered: true };
917
+ return { marketplace, registered: true, leftOn: [] };
778
918
  }
919
+ const outcome = await refreshOutcome(marketplace, host);
920
+ warnOfShortfalls(outcome);
921
+ return { marketplace, registered: false, leftOn: outcome.leftOn };
922
+ }
923
+ async function refreshOutcome(marketplace, host) {
779
924
  try {
780
925
  await host.refreshMarketplace(marketplace);
781
- } catch {
782
- warn("Could not update marketplace \u2014 continuing with cached version");
926
+ return { refreshed: true, leftOn: [] };
927
+ } catch (error) {
928
+ return outcomeOfRefusal(error);
929
+ }
930
+ }
931
+ function outcomeOfRefusal(error) {
932
+ if (error instanceof PluginsLeftSwitchedOnError) return { refreshed: true, leftOn: error.leftOn };
933
+ if (error instanceof FailedLeavingPluginsSwitchedOnError) {
934
+ return { refreshed: false, leftOn: error.leftOn };
935
+ }
936
+ return { refreshed: false, leftOn: [] };
937
+ }
938
+ function warnOfShortfalls({ refreshed, leftOn }) {
939
+ if (!refreshed) warn("Could not update marketplace \u2014 continuing with cached version");
940
+ for (const { pluginKey, configFile, reason } of leftOn) {
941
+ warn(codexPluginLeftSwitchedOn(pluginKey, configFile, reason));
783
942
  }
784
- return { marketplace, registered: false };
785
943
  }
786
944
  async function resolveMarketplaceName(sourceResult) {
787
945
  if (sourceResult.marketplace) return sourceResult.marketplace;
@@ -805,7 +963,12 @@ async function requireMarketplace(sourceResult, purpose, host) {
805
963
  error: `Cannot ${purpose}: marketplace could not be resolved from '${sourceResult.sourceConfig.source}'. Plugin install mode requires a marketplace \u2014 fix the marketplace or switch the affected skills to eject mode.`
806
964
  };
807
965
  }
808
- return { ok: true, marketplace: mpResult.marketplace, registered: mpResult.registered };
966
+ return {
967
+ ok: true,
968
+ marketplace: mpResult.marketplace,
969
+ registered: mpResult.registered,
970
+ leftOn: mpResult.leftOn
971
+ };
809
972
  }
810
973
 
811
974
  // src/cli/lib/operations/skills/install-plugin-skills.ts
@@ -839,6 +1002,10 @@ async function installPluginSkills(skills, marketplace, projectDir) {
839
1002
  var TERMINAL_RESIZE_POLL_MS = 500;
840
1003
  var terminalColumns = () => process.stdout.columns ?? MIN_TERMINAL_SIZE.COLS;
841
1004
  var terminalRows = () => process.stdout.rows ?? MIN_TERMINAL_SIZE.ROWS;
1005
+ function sayFirst(line) {
1006
+ process.stderr.write(`${line}
1007
+ `);
1008
+ }
842
1009
  function isTerminalBigEnough() {
843
1010
  return isTerminalLargeEnough(terminalColumns(), terminalRows());
844
1011
  }
@@ -872,10 +1039,27 @@ function hasActiveProjectEntry(skills, skillId) {
872
1039
  var BaseCommand = class extends Command {
873
1040
  /** Non-empty decides the exit code; see {@link exitIfWorkIncomplete}. */
874
1041
  incompleteWork = [];
1042
+ /** Warned of by the refresh that left them; non-empty fails the run, as in `update`. */
1043
+ switchesLeftOn = [];
875
1044
  async init() {
876
1045
  await super.init();
877
1046
  await this.ensureTerminalSize();
878
1047
  }
1048
+ /**
1049
+ * Called first where a command starts work on the installation in play, which for a project whose
1050
+ * config declares nothing is the global one, or none where HOME holds none the run could work on.
1051
+ */
1052
+ async sayWhenTheGlobalInstallationStandsIn(named) {
1053
+ if (!await holdsOnlyAConfigDeclaringNothing(process.cwd())) return;
1054
+ const standsIn = await homeHoldsAnInstallationFor(process.cwd(), named);
1055
+ sayFirst(
1056
+ standsIn ? INFO_MESSAGES.GLOBAL_INSTALLATION_STANDS_IN : INFO_MESSAGES.NO_GLOBAL_INSTALLATION_STANDS_IN
1057
+ );
1058
+ }
1059
+ /** For a command that never works on the global installation: `line` says what it does instead. */
1060
+ async sayWhenTheProjectsConfigDeclaresNothing(line) {
1061
+ if (await holdsOnlyAConfigDeclaringNothing(process.cwd())) sayFirst(line);
1062
+ }
879
1063
  async ensureTerminalSize() {
880
1064
  if (isTerminalBigEnough()) return;
881
1065
  clearTerminalScreen();
@@ -908,6 +1092,7 @@ var BaseCommand = class extends Command {
908
1092
  if (!required.ok) {
909
1093
  this.error(required.error, { exit: EXIT_CODES.ERROR });
910
1094
  }
1095
+ this.switchesLeftOn.push(...required.leftOn);
911
1096
  if (required.registered) {
912
1097
  onRegistered?.(required.marketplace);
913
1098
  }
@@ -971,10 +1156,11 @@ var BaseCommand = class extends Command {
971
1156
  this.log(propagatedRecompileSummary(rewrittenCount + unchangedCount, failedCount));
972
1157
  }
973
1158
  reportUnassignedSkills(config, selected) {
1159
+ const namedBy = namedByActiveEntries(selected);
974
1160
  for (const { skillId, blockedBy } of findUnassignedSkills(config, selected)) {
975
- this.warn(skillAssignedToNoAgent(skillId));
1161
+ this.warn(skillAssignedToNoAgent(skillId, namedBy));
976
1162
  if (blockedBy.length > 0) {
977
- this.warn(scopeBlockedStackAssignment(blockedBy, skillId));
1163
+ this.warn(scopeBlockedStackAssignment(blockedBy, skillId, namedBy));
978
1164
  }
979
1165
  }
980
1166
  }
@@ -1014,14 +1200,17 @@ var BaseCommand = class extends Command {
1014
1200
  if (!isHomeDirectory(projectDir) || installsAtHome(result)) return;
1015
1201
  const { skillIds, agentNames } = projectScopedContent(result);
1016
1202
  const provider = providerToNameAt(projectDir, providerInUse(projectDir));
1017
- this.error(sharedConfigProjectScopeAtHome(skillIds, agentNames, installedHere, provider), {
1018
- exit: EXIT_CODES.ERROR
1019
- });
1203
+ const namedBy = namedByActiveEntries(result.skills);
1204
+ this.error(
1205
+ sharedConfigProjectScopeAtHome(skillIds, agentNames, installedHere, provider, namedBy),
1206
+ { exit: EXIT_CODES.ERROR }
1207
+ );
1020
1208
  }
1021
- warnOfSkippedEntries(mapping) {
1209
+ /** `unloadedSkillIds`: skills the marketplace ships and could not load, never unknown ones. */
1210
+ warnOfSkippedEntries(mapping, unloadedSkillIds) {
1022
1211
  const { skippedSkillIds, skippedAgentNames, agentsOnlySkippedSkillsCarried } = mapping;
1023
1212
  if (skippedSkillIds.length > 0) {
1024
- this.warn(skippedUnknownSkills(skippedSkillIds, agentsOnlySkippedSkillsCarried));
1213
+ this.warn(skippedSkills(skippedSkillIds, agentsOnlySkippedSkillsCarried, unloadedSkillIds));
1025
1214
  }
1026
1215
  if (skippedAgentNames.length > 0) this.warn(skippedUnknownAgents(skippedAgentNames));
1027
1216
  }
@@ -1068,17 +1257,34 @@ var BaseCommand = class extends Command {
1068
1257
  }
1069
1258
  /** Every command that records must call this; `this.exit` skips the `Error:` framing. */
1070
1259
  exitIfWorkIncomplete() {
1260
+ this.listIncompleteWork();
1261
+ this.failIfPluginsLeftSwitchedOn();
1262
+ if (this.hasIncompleteWork) this.exit(EXIT_CODES.COMPLETED_WITH_FAILURES);
1263
+ }
1264
+ listIncompleteWork() {
1071
1265
  if (!this.hasIncompleteWork) return;
1072
1266
  this.log(`
1073
1267
  ${chalk.hex(CLI_COLORS.WARNING)(completedWithFailures(this.incompleteWork))}
1074
1268
  `);
1075
- this.exit(EXIT_CODES.COMPLETED_WITH_FAILURES);
1269
+ }
1270
+ failIfPluginsLeftSwitchedOn() {
1271
+ if (this.switchesLeftOn.length === 0) return;
1272
+ const pluginKeys = this.switchesLeftOn.map(({ pluginKey }) => pluginKey);
1273
+ this.error(pluginsLeftSwitchedOn(pluginKeys), { exit: EXIT_CODES.ERROR });
1076
1274
  }
1077
1275
  };
1078
1276
 
1079
1277
  export {
1080
1278
  clearTerminalScreen,
1081
1279
  EXIT_CODES,
1280
+ providerFlag,
1281
+ providerNamedBy,
1282
+ providerNamedIn,
1283
+ providerNeedsAConfigurationToInstall,
1284
+ refuseAnAmbiguousInstallation,
1285
+ installationToName,
1286
+ ambiguityFinding,
1287
+ otherInstallationsInThisScope,
1082
1288
  registerExternalSkills,
1083
1289
  writeExternalSkills,
1084
1290
  carriedSkillsThatDiffer,
@@ -1089,8 +1295,9 @@ export {
1089
1295
  restoreInstalledGlobal,
1090
1296
  sameAssignments,
1091
1297
  notInstalledGlobally,
1298
+ panelRowEntries,
1092
1299
  joinedStatement,
1093
1300
  installsAtHome,
1094
1301
  BaseCommand
1095
1302
  };
1096
- //# sourceMappingURL=chunk-IAQFZFWD.js.map
1303
+ //# sourceMappingURL=chunk-JTMSFBCA.js.map