agents-inc 0.168.0 → 0.170.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +18 -15
- package/dist/{chunk-JIBCVXXL.js → chunk-3G7X2WKI.js} +4 -4
- package/dist/{chunk-JOEA52NR.js → chunk-44TE3RKH.js} +46 -2
- package/dist/chunk-44TE3RKH.js.map +1 -0
- package/dist/{chunk-NU2K5G54.js → chunk-52HDHJ7I.js} +11 -19
- package/dist/chunk-52HDHJ7I.js.map +1 -0
- package/dist/{chunk-EH2PGPLP.js → chunk-6HNXYYVF.js} +39 -22
- package/dist/chunk-6HNXYYVF.js.map +1 -0
- package/dist/{chunk-4UKMQUAU.js → chunk-6ZRH5RHC.js} +10 -11
- package/dist/chunk-6ZRH5RHC.js.map +1 -0
- package/dist/{chunk-5JUQKGCP.js → chunk-7RDMTR64.js} +14 -34
- package/dist/chunk-7RDMTR64.js.map +1 -0
- package/dist/{chunk-3LZNY46H.js → chunk-BMRUNMPV.js} +4 -4
- package/dist/{chunk-VVRI35SK.js → chunk-CLPUWOSA.js} +4 -4
- package/dist/{chunk-VVRI35SK.js.map → chunk-CLPUWOSA.js.map} +1 -1
- package/dist/{chunk-TW35AEB4.js → chunk-F2BHT5C4.js} +9 -7
- package/dist/chunk-F2BHT5C4.js.map +1 -0
- package/dist/{chunk-27AVGFXH.js → chunk-F5EBEATU.js} +2 -2
- package/dist/{chunk-GE7NUPMI.js → chunk-HED2DAXZ.js} +3 -3
- package/dist/{chunk-7PYXS2QU.js → chunk-KOLDW6SF.js} +3 -3
- package/dist/{chunk-7PYXS2QU.js.map → chunk-KOLDW6SF.js.map} +1 -1
- package/dist/{chunk-C2UISKIM.js → chunk-MQ6CGZNJ.js} +109 -422
- package/dist/chunk-MQ6CGZNJ.js.map +1 -0
- package/dist/{chunk-P6I72PR3.js → chunk-NCWDK6L7.js} +115 -196
- package/dist/chunk-NCWDK6L7.js.map +1 -0
- package/dist/{chunk-VRXX4D6K.js → chunk-NEZ4OAOL.js} +1 -1
- package/dist/chunk-NEZ4OAOL.js.map +1 -0
- package/dist/chunk-NIHUOWE4.js +106 -0
- package/dist/chunk-NIHUOWE4.js.map +1 -0
- package/dist/{chunk-OI2H6M5I.js → chunk-NQW25DCF.js} +2 -2
- package/dist/chunk-NQW25DCF.js.map +1 -0
- package/dist/{chunk-ZUGH4MQG.js → chunk-OYJQUA3D.js} +3 -3
- package/dist/{chunk-ZUGH4MQG.js.map → chunk-OYJQUA3D.js.map} +1 -1
- package/dist/{chunk-AG3ZVM3B.js → chunk-PJWGTNOX.js} +186 -210
- package/dist/chunk-PJWGTNOX.js.map +1 -0
- package/dist/{chunk-HR7TK2XW.js → chunk-RIPSGNLU.js} +3 -3
- package/dist/chunk-RIPSGNLU.js.map +1 -0
- package/dist/{chunk-4DRFEYCE.js → chunk-SZYQISA2.js} +7 -7
- package/dist/chunk-SZYQISA2.js.map +1 -0
- package/dist/{chunk-W6GO2CYX.js → chunk-USVBYQSQ.js} +2 -2
- package/dist/{chunk-H4ZKGGTE.js → chunk-V3KTSP3Q.js} +50 -42
- package/dist/chunk-V3KTSP3Q.js.map +1 -0
- package/dist/{chunk-KTLKR4YY.js → chunk-WTWMGH2C.js} +2 -2
- package/dist/commands/build/marketplace.js +23 -22
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +8 -9
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/compile.js +19 -20
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +17 -18
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +118 -297
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +21 -33
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +17 -45
- package/dist/commands/list.js +19 -17
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/marketplace.js +11 -11
- package/dist/commands/new/marketplace.js.map +1 -1
- package/dist/commands/search.js +12 -13
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/share.js +11 -12
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/uninstall.js +18 -20
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +8 -9
- package/dist/commands/update.js.map +1 -1
- package/dist/components/common/removal-plan-confirm.js +2 -2
- package/dist/components/common/scroll-affordance.js +9 -0
- package/dist/components/common/select-list.js +2 -3
- package/dist/components/common/skill-agent-summary.js +11 -0
- package/dist/components/common/spinner.js +1 -1
- package/dist/{chunk-QWFG7Y3R.js → components/common/summary-panel.js} +57 -31
- package/dist/components/common/summary-panel.js.map +1 -0
- package/dist/config-exports.js +1 -1
- package/dist/hooks/init.js +18 -46
- package/dist/hooks/init.js.map +1 -1
- package/dist/load-agent-defs-YMDWBFDP.js +14 -0
- package/dist/recompile-project-agents-SZ76WNTW.js +18 -0
- package/dist/{source-loader-FRJTCSDL.js → source-loader-C5SQXZXI.js} +5 -5
- package/dist/src/agents/meta/codex-keeper/playbook.md +2 -3
- package/package.json +2 -3
- package/src/agents/meta/codex-keeper/playbook.md +2 -3
- package/src/schemas/project-config.schema.json +1 -1
- package/assets/demo.tape +0 -266
- package/dist/chunk-23DNVNFP.js +0 -292
- package/dist/chunk-23DNVNFP.js.map +0 -1
- package/dist/chunk-3DIDV6H3.js +0 -268
- package/dist/chunk-3DIDV6H3.js.map +0 -1
- package/dist/chunk-4DRFEYCE.js.map +0 -1
- package/dist/chunk-4HWOYYY7.js +0 -92
- package/dist/chunk-4HWOYYY7.js.map +0 -1
- package/dist/chunk-4UKMQUAU.js.map +0 -1
- package/dist/chunk-5JUQKGCP.js.map +0 -1
- package/dist/chunk-6WGXTB2L.js +0 -28
- package/dist/chunk-6WGXTB2L.js.map +0 -1
- package/dist/chunk-AG3ZVM3B.js.map +0 -1
- package/dist/chunk-C2UISKIM.js.map +0 -1
- package/dist/chunk-CMJBKQUH.js +0 -23
- package/dist/chunk-CMJBKQUH.js.map +0 -1
- package/dist/chunk-DJEO3F2H.js +0 -230
- package/dist/chunk-DJEO3F2H.js.map +0 -1
- package/dist/chunk-EH2PGPLP.js.map +0 -1
- package/dist/chunk-GRL73YPF.js +0 -197
- package/dist/chunk-GRL73YPF.js.map +0 -1
- package/dist/chunk-H4ZKGGTE.js.map +0 -1
- package/dist/chunk-HI6YB7XP.js +0 -59
- package/dist/chunk-HI6YB7XP.js.map +0 -1
- package/dist/chunk-HL3GYRMR.js +0 -17
- package/dist/chunk-HL3GYRMR.js.map +0 -1
- package/dist/chunk-HR7TK2XW.js.map +0 -1
- package/dist/chunk-JOEA52NR.js.map +0 -1
- package/dist/chunk-JPMV4E4E.js +0 -118
- package/dist/chunk-JPMV4E4E.js.map +0 -1
- package/dist/chunk-JVUN6AOO.js +0 -237
- package/dist/chunk-JVUN6AOO.js.map +0 -1
- package/dist/chunk-KQ3PDARZ.js +0 -25
- package/dist/chunk-KQ3PDARZ.js.map +0 -1
- package/dist/chunk-L3W2JWBA.js +0 -168
- package/dist/chunk-L3W2JWBA.js.map +0 -1
- package/dist/chunk-LFUJCRCT.js +0 -27
- package/dist/chunk-LFUJCRCT.js.map +0 -1
- package/dist/chunk-NU2K5G54.js.map +0 -1
- package/dist/chunk-OI2H6M5I.js.map +0 -1
- package/dist/chunk-P6I72PR3.js.map +0 -1
- package/dist/chunk-PCFUXQJA.js +0 -317
- package/dist/chunk-PCFUXQJA.js.map +0 -1
- package/dist/chunk-PLX2FLEQ.js +0 -48
- package/dist/chunk-PLX2FLEQ.js.map +0 -1
- package/dist/chunk-QWFG7Y3R.js.map +0 -1
- package/dist/chunk-SLBL3WIP.js +0 -121
- package/dist/chunk-SLBL3WIP.js.map +0 -1
- package/dist/chunk-TSIU7DME.js +0 -43
- package/dist/chunk-TSIU7DME.js.map +0 -1
- package/dist/chunk-TW35AEB4.js.map +0 -1
- package/dist/chunk-VRXX4D6K.js.map +0 -1
- package/dist/chunk-W5KEYSOL.js +0 -51
- package/dist/chunk-W5KEYSOL.js.map +0 -1
- package/dist/chunk-WNLF5EDZ.js +0 -1170
- package/dist/chunk-WNLF5EDZ.js.map +0 -1
- package/dist/chunk-WTJ3AY33.js +0 -31
- package/dist/chunk-WTJ3AY33.js.map +0 -1
- package/dist/chunk-X6ZZEYO3.js +0 -53
- package/dist/chunk-X6ZZEYO3.js.map +0 -1
- package/dist/chunk-XQHZPINL.js +0 -89
- package/dist/chunk-XQHZPINL.js.map +0 -1
- package/dist/chunk-YN3SWF53.js +0 -35
- package/dist/chunk-YN3SWF53.js.map +0 -1
- package/dist/components/wizard/category-grid.js +0 -13
- package/dist/components/wizard/checkbox-grid.js +0 -12
- package/dist/components/wizard/domain-selection.js +0 -18
- package/dist/components/wizard/run-wizard-session.js +0 -40
- package/dist/components/wizard/run-wizard-session.js.map +0 -1
- package/dist/components/wizard/scroll-affordance.js +0 -9
- package/dist/components/wizard/skill-agent-summary.js +0 -13
- package/dist/components/wizard/source-grid.js +0 -16
- package/dist/components/wizard/source-grid.js.map +0 -1
- package/dist/components/wizard/stack-selection.js +0 -17
- package/dist/components/wizard/stack-selection.js.map +0 -1
- package/dist/components/wizard/step-agents.js +0 -18
- package/dist/components/wizard/step-agents.js.map +0 -1
- package/dist/components/wizard/step-build.js +0 -18
- package/dist/components/wizard/step-build.js.map +0 -1
- package/dist/components/wizard/step-confirm.js +0 -18
- package/dist/components/wizard/step-confirm.js.map +0 -1
- package/dist/components/wizard/step-sources.js +0 -19
- package/dist/components/wizard/step-sources.js.map +0 -1
- package/dist/components/wizard/step-stack.js +0 -18
- package/dist/components/wizard/step-stack.js.map +0 -1
- package/dist/components/wizard/summary-panel.js +0 -17
- package/dist/components/wizard/summary-panel.js.map +0 -1
- package/dist/components/wizard/toast.js +0 -9
- package/dist/components/wizard/toast.js.map +0 -1
- package/dist/components/wizard/wizard-layout.js +0 -22
- package/dist/components/wizard/wizard-layout.js.map +0 -1
- package/dist/components/wizard/wizard-tabs.js +0 -11
- package/dist/components/wizard/wizard-tabs.js.map +0 -1
- package/dist/components/wizard/wizard.js +0 -39
- package/dist/components/wizard/wizard.js.map +0 -1
- package/dist/load-agent-defs-5XMVB3MU.js +0 -14
- package/dist/load-agent-defs-5XMVB3MU.js.map +0 -1
- package/dist/recompile-project-agents-7PQWYQ6B.js +0 -18
- package/dist/recompile-project-agents-7PQWYQ6B.js.map +0 -1
- package/dist/source-loader-FRJTCSDL.js.map +0 -1
- package/dist/stores/wizard-store.js +0 -24
- package/dist/stores/wizard-store.js.map +0 -1
- /package/assets/{demo.gif → legacy-wizard.gif} +0 -0
- /package/dist/{chunk-JIBCVXXL.js.map → chunk-3G7X2WKI.js.map} +0 -0
- /package/dist/{chunk-3LZNY46H.js.map → chunk-BMRUNMPV.js.map} +0 -0
- /package/dist/{chunk-27AVGFXH.js.map → chunk-F5EBEATU.js.map} +0 -0
- /package/dist/{chunk-GE7NUPMI.js.map → chunk-HED2DAXZ.js.map} +0 -0
- /package/dist/{chunk-W6GO2CYX.js.map → chunk-USVBYQSQ.js.map} +0 -0
- /package/dist/{chunk-KTLKR4YY.js.map → chunk-WTWMGH2C.js.map} +0 -0
- /package/dist/components/{wizard → common}/scroll-affordance.js.map +0 -0
- /package/dist/components/{wizard → common}/skill-agent-summary.js.map +0 -0
- /package/dist/{components/wizard/category-grid.js.map → load-agent-defs-YMDWBFDP.js.map} +0 -0
- /package/dist/{components/wizard/checkbox-grid.js.map → recompile-project-agents-SZ76WNTW.js.map} +0 -0
- /package/dist/{components/wizard/domain-selection.js.map → source-loader-C5SQXZXI.js.map} +0 -0
package/dist/chunk-CMJBKQUH.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
MIN_TERMINAL_SIZE
|
|
4
|
-
} from "./chunk-AG3ZVM3B.js";
|
|
5
|
-
|
|
6
|
-
// src/cli/utils/terminal.ts
|
|
7
|
-
function clearTerminalScreen() {
|
|
8
|
-
process.stdout.write("\x1B[H\x1B[2J\x1B[3J");
|
|
9
|
-
}
|
|
10
|
-
function isTerminalLargeEnough(columns, rows) {
|
|
11
|
-
return columns >= MIN_TERMINAL_SIZE.COLS && rows >= MIN_TERMINAL_SIZE.ROWS;
|
|
12
|
-
}
|
|
13
|
-
function formatTerminalTooSmallMessage(columns) {
|
|
14
|
-
const issue = columns < MIN_TERMINAL_SIZE.COLS ? `too narrow (need ${MIN_TERMINAL_SIZE.COLS})` : `too short (need ${MIN_TERMINAL_SIZE.ROWS})`;
|
|
15
|
-
return `Terminal ${issue}. Please resize.`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export {
|
|
19
|
-
clearTerminalScreen,
|
|
20
|
-
isTerminalLargeEnough,
|
|
21
|
-
formatTerminalTooSmallMessage
|
|
22
|
-
};
|
|
23
|
-
//# sourceMappingURL=chunk-CMJBKQUH.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/utils/terminal.ts"],"sourcesContent":["import { MIN_TERMINAL_SIZE } from \"../consts.js\";\n\n/**\n * Clears the terminal screen and scrollback, moving the cursor to the top.\n * Shared by BaseCommand.clearTerminal and the init dashboard.\n */\nexport function clearTerminalScreen(): void {\n process.stdout.write(\"\\x1b[H\\x1b[2J\\x1b[3J\");\n}\n\n/** Whether the terminal clears {@link MIN_TERMINAL_SIZE} in BOTH dimensions. */\nexport function isTerminalLargeEnough(columns: number, rows: number): boolean {\n return columns >= MIN_TERMINAL_SIZE.COLS && rows >= MIN_TERMINAL_SIZE.ROWS;\n}\n\n/**\n * The one resize prompt, worded in one place because two gates print it and they\n * must not drift: `BaseCommand.ensureTerminalSize` blocks a command from\n * launching too small, and `WizardLayout` replaces the wizard tree when the\n * terminal shrinks under a session already running. The E2E constants\n * `STEP_TEXT.TOO_NARROW` / `TOO_SHORT` key off this text, so a second wording\n * would leave one of the two gates unassertable.\n *\n * Precondition: {@link isTerminalLargeEnough} is false. Width is reported in\n * preference to height, so \"not too narrow\" here means \"too short\" — which is\n * why the height is not a parameter.\n */\nexport function formatTerminalTooSmallMessage(columns: number): string {\n const issue =\n columns < MIN_TERMINAL_SIZE.COLS\n ? `too narrow (need ${MIN_TERMINAL_SIZE.COLS})`\n : `too short (need ${MIN_TERMINAL_SIZE.ROWS})`;\n return `Terminal ${issue}. Please resize.`;\n}\n"],"mappings":";;;;;;AAMO,SAAS,sBAA4B;AAC1C,UAAQ,OAAO,MAAM,sBAAsB;AAC7C;AAGO,SAAS,sBAAsB,SAAiB,MAAuB;AAC5E,SAAO,WAAW,kBAAkB,QAAQ,QAAQ,kBAAkB;AACxE;AAcO,SAAS,8BAA8B,SAAyB;AACrE,QAAM,QACJ,UAAU,kBAAkB,OACxB,oBAAoB,kBAAkB,IAAI,MAC1C,mBAAmB,kBAAkB,IAAI;AAC/C,SAAO,YAAY,KAAK;AAC1B;","names":[]}
|
package/dist/chunk-DJEO3F2H.js
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
getDomainDisplayName
|
|
4
|
-
} from "./chunk-YN3SWF53.js";
|
|
5
|
-
import {
|
|
6
|
-
useMeasuredHeight
|
|
7
|
-
} from "./chunk-TSIU7DME.js";
|
|
8
|
-
import {
|
|
9
|
-
useRowScroll
|
|
10
|
-
} from "./chunk-LFUJCRCT.js";
|
|
11
|
-
import {
|
|
12
|
-
KEY_SPACE
|
|
13
|
-
} from "./chunk-WTJ3AY33.js";
|
|
14
|
-
import {
|
|
15
|
-
BUILT_IN_AGENT_GROUPS,
|
|
16
|
-
BUILT_IN_AGENT_IDS,
|
|
17
|
-
deriveScopeBadges,
|
|
18
|
-
formatScopeTag,
|
|
19
|
-
useWizardStore
|
|
20
|
-
} from "./chunk-WNLF5EDZ.js";
|
|
21
|
-
import {
|
|
22
|
-
isAgentName,
|
|
23
|
-
toTitleCase
|
|
24
|
-
} from "./chunk-C2UISKIM.js";
|
|
25
|
-
import {
|
|
26
|
-
matrix,
|
|
27
|
-
typedKeys
|
|
28
|
-
} from "./chunk-NU2K5G54.js";
|
|
29
|
-
import {
|
|
30
|
-
CLI_COLORS,
|
|
31
|
-
UI_SYMBOLS
|
|
32
|
-
} from "./chunk-AG3ZVM3B.js";
|
|
33
|
-
|
|
34
|
-
// src/cli/components/wizard/step-agents.tsx
|
|
35
|
-
import { groupBy, unique } from "remeda";
|
|
36
|
-
import { Box, Text, useInput } from "ink";
|
|
37
|
-
import React, { useMemo, useState } from "react";
|
|
38
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
39
|
-
function agentIdsNamedByStacks(matrix2) {
|
|
40
|
-
return unique(matrix2.suggestedStacks.flatMap((stack) => typedKeys(stack.skills)));
|
|
41
|
-
}
|
|
42
|
-
function selectableSourceAgents(matrix2) {
|
|
43
|
-
return agentIdsNamedByStacks(matrix2).filter(isAgentName).filter((agentName) => !BUILT_IN_AGENT_IDS.has(agentName));
|
|
44
|
-
}
|
|
45
|
-
function buildAgentGroups(matrix2) {
|
|
46
|
-
const customAgentIds = selectableSourceAgents(matrix2);
|
|
47
|
-
if (customAgentIds.length === 0) return BUILT_IN_AGENT_GROUPS;
|
|
48
|
-
const customItems = customAgentIds.map((agentId) => {
|
|
49
|
-
const explicitDomain = matrix2.agentDefinedDomains?.[agentId];
|
|
50
|
-
const domainKey = explicitDomain ?? (agentId.split("-")[0] || "custom");
|
|
51
|
-
return {
|
|
52
|
-
groupLabel: getDomainDisplayName(domainKey),
|
|
53
|
-
item: {
|
|
54
|
-
id: agentId,
|
|
55
|
-
label: toTitleCase(agentId),
|
|
56
|
-
description: "Custom agent"
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
});
|
|
60
|
-
const customGroups = Object.entries(groupBy(customItems, (c) => c.groupLabel)).map(
|
|
61
|
-
([label, entries]) => ({ label, items: entries.map((entry) => entry.item) })
|
|
62
|
-
);
|
|
63
|
-
return [...BUILT_IN_AGENT_GROUPS, ...customGroups];
|
|
64
|
-
}
|
|
65
|
-
function buildFlatRows(groups) {
|
|
66
|
-
return groups.flatMap((group, groupIndex) => [
|
|
67
|
-
...groupIndex > 0 ? [{ type: "spacer" }] : [],
|
|
68
|
-
{ type: "header", label: group.label },
|
|
69
|
-
...group.items.map((agent) => ({ type: "agent", agent }))
|
|
70
|
-
]);
|
|
71
|
-
}
|
|
72
|
-
function buildFocusableIds(groups) {
|
|
73
|
-
return [...groups.flatMap((group) => group.items.map((a) => a.id)), "continue"];
|
|
74
|
-
}
|
|
75
|
-
function focusableIdAt(ids, index) {
|
|
76
|
-
const id = ids[index];
|
|
77
|
-
if (id === void 0) throw new Error(`No focusable row at index ${index} of ${ids.length}`);
|
|
78
|
-
return id;
|
|
79
|
-
}
|
|
80
|
-
var StepAgents = () => {
|
|
81
|
-
const selectedAgents = useWizardStore((s) => s.selectedAgents);
|
|
82
|
-
const agentConfigs = useWizardStore((s) => s.agentConfigs);
|
|
83
|
-
const agentGroups = useMemo(() => buildAgentGroups(matrix), []);
|
|
84
|
-
const flatRows = useMemo(() => buildFlatRows(agentGroups), [agentGroups]);
|
|
85
|
-
const focusableIds = useMemo(() => buildFocusableIds(agentGroups), [agentGroups]);
|
|
86
|
-
const [focusedId, setFocusedId] = useState(() => {
|
|
87
|
-
const stored = useWizardStore.getState().focusedAgentId;
|
|
88
|
-
return stored && focusableIds.includes(stored) ? stored : focusableIdAt(focusableIds, 0);
|
|
89
|
-
});
|
|
90
|
-
const { ref: listRef, measuredHeight: listHeight } = useMeasuredHeight();
|
|
91
|
-
const focusedRowIndex = focusedId !== "continue" ? flatRows.findIndex((row) => row.type === "agent" && row.agent.id === focusedId) : -1;
|
|
92
|
-
const { scrollEnabled, scrollTop } = useRowScroll({
|
|
93
|
-
focusedIndex: Math.max(0, focusedRowIndex),
|
|
94
|
-
itemCount: flatRows.length,
|
|
95
|
-
availableHeight: listHeight
|
|
96
|
-
});
|
|
97
|
-
useInput((input, key) => {
|
|
98
|
-
if (key.escape) {
|
|
99
|
-
useWizardStore.getState().goBack();
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const currentIdx = focusableIds.indexOf(focusedId);
|
|
103
|
-
if (key.upArrow || input === "k") {
|
|
104
|
-
const nextIdx = currentIdx <= 0 ? focusableIds.length - 1 : currentIdx - 1;
|
|
105
|
-
setFocusedId(focusableIdAt(focusableIds, nextIdx));
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
if (key.downArrow || input === "j") {
|
|
109
|
-
const nextIdx = currentIdx >= focusableIds.length - 1 ? 0 : currentIdx + 1;
|
|
110
|
-
setFocusedId(focusableIdAt(focusableIds, nextIdx));
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (key.return) {
|
|
114
|
-
useWizardStore.getState().setStep("confirm");
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (input === KEY_SPACE && focusedId !== "continue") {
|
|
118
|
-
useWizardStore.getState().toggleAgent(focusedId);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
React.useEffect(() => {
|
|
122
|
-
useWizardStore.getState().setFocusedAgentId(focusedId === "continue" ? null : focusedId);
|
|
123
|
-
}, [focusedId]);
|
|
124
|
-
const focusedGroupLabel = agentGroups.find((g) => g.items.some((a) => a.id === focusedId))?.label;
|
|
125
|
-
const selectedCount = selectedAgents.length;
|
|
126
|
-
const continueLabel = selectedCount > 0 ? `Continue with ${selectedCount} agent(s)` : "Continue without agents";
|
|
127
|
-
const isContinueFocused = focusedId === "continue";
|
|
128
|
-
const rowElements = flatRows.map((row, index) => {
|
|
129
|
-
switch (row.type) {
|
|
130
|
-
case "header":
|
|
131
|
-
return /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: row.label === focusedGroupLabel ? /* @__PURE__ */ jsx(
|
|
132
|
-
Text,
|
|
133
|
-
{
|
|
134
|
-
color: CLI_COLORS.WHITE,
|
|
135
|
-
backgroundColor: CLI_COLORS.LABEL_BG,
|
|
136
|
-
children: ` ${row.label} `
|
|
137
|
-
}
|
|
138
|
-
) : /* @__PURE__ */ jsxs(Text, { dimColor: true, bold: true, children: [
|
|
139
|
-
" ",
|
|
140
|
-
row.label
|
|
141
|
-
] }) }, `header-${row.label}`);
|
|
142
|
-
case "spacer":
|
|
143
|
-
return /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { children: " " }) }, `spacer-${index}`);
|
|
144
|
-
case "agent": {
|
|
145
|
-
const isFocused = row.agent.id === focusedId;
|
|
146
|
-
const isSelected = selectedAgents.includes(row.agent.id);
|
|
147
|
-
const checkbox = isSelected ? "[\u2713]" : "[ ]";
|
|
148
|
-
const pointer = isFocused ? UI_SYMBOLS.CHEVRON : UI_SYMBOLS.CHEVRON_SPACER;
|
|
149
|
-
const agentConfig = agentConfigs.find((ac) => ac.name === row.agent.id && !ac.excluded);
|
|
150
|
-
const excludedConfig = agentConfigs.find((ac) => ac.name === row.agent.id && ac.excluded);
|
|
151
|
-
const badges = deriveScopeBadges(agentConfig, excludedConfig);
|
|
152
|
-
const scope = badges.scope ?? "global";
|
|
153
|
-
const secondaryScope = badges.secondaryScope;
|
|
154
|
-
return /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
155
|
-
/* @__PURE__ */ jsx(Text, { ...isFocused && { color: CLI_COLORS.PRIMARY }, children: pointer }),
|
|
156
|
-
/* @__PURE__ */ jsxs(
|
|
157
|
-
Text,
|
|
158
|
-
{
|
|
159
|
-
...(isSelected || isFocused) && { color: CLI_COLORS.PRIMARY },
|
|
160
|
-
bold: isFocused,
|
|
161
|
-
children: [
|
|
162
|
-
" ",
|
|
163
|
-
checkbox,
|
|
164
|
-
" "
|
|
165
|
-
]
|
|
166
|
-
}
|
|
167
|
-
),
|
|
168
|
-
/* @__PURE__ */ jsx(Text, { color: scope === "global" ? CLI_COLORS.WARNING : CLI_COLORS.TOAST_BG, children: formatScopeTag(scope) }),
|
|
169
|
-
secondaryScope && /* @__PURE__ */ jsx(
|
|
170
|
-
Text,
|
|
171
|
-
{
|
|
172
|
-
color: secondaryScope === "global" ? CLI_COLORS.WARNING : CLI_COLORS.TOAST_BG,
|
|
173
|
-
children: formatScopeTag(secondaryScope)
|
|
174
|
-
}
|
|
175
|
-
),
|
|
176
|
-
/* @__PURE__ */ jsxs(
|
|
177
|
-
Text,
|
|
178
|
-
{
|
|
179
|
-
...(isSelected || isFocused) && { color: CLI_COLORS.PRIMARY },
|
|
180
|
-
bold: isFocused,
|
|
181
|
-
children: [
|
|
182
|
-
" ",
|
|
183
|
-
row.agent.label
|
|
184
|
-
]
|
|
185
|
-
}
|
|
186
|
-
),
|
|
187
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
188
|
-
" ",
|
|
189
|
-
row.agent.description
|
|
190
|
-
] })
|
|
191
|
-
] }) }, row.agent.id);
|
|
192
|
-
}
|
|
193
|
-
default: {
|
|
194
|
-
const _exhaustive = row;
|
|
195
|
-
return _exhaustive;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: "100%", flexGrow: 1, flexBasis: 0, children: [
|
|
200
|
-
/* @__PURE__ */ jsx(Box, { ref: listRef, flexDirection: "column", flexGrow: 1, flexBasis: 0, children: /* @__PURE__ */ jsx(
|
|
201
|
-
Box,
|
|
202
|
-
{
|
|
203
|
-
flexDirection: "column",
|
|
204
|
-
flexGrow: 1,
|
|
205
|
-
...scrollEnabled && { overflow: "hidden" },
|
|
206
|
-
children: /* @__PURE__ */ jsx(
|
|
207
|
-
Box,
|
|
208
|
-
{
|
|
209
|
-
flexDirection: "column",
|
|
210
|
-
marginTop: scrollTop > 0 ? -scrollTop : 0,
|
|
211
|
-
...scrollEnabled && { flexShrink: 0 },
|
|
212
|
-
children: rowElements
|
|
213
|
-
}
|
|
214
|
-
)
|
|
215
|
-
}
|
|
216
|
-
) }),
|
|
217
|
-
/* @__PURE__ */ jsxs(Text, { ...isContinueFocused && { color: CLI_COLORS.PRIMARY }, bold: isContinueFocused, children: [
|
|
218
|
-
isContinueFocused ? UI_SYMBOLS.CHEVRON : UI_SYMBOLS.CHEVRON_SPACER,
|
|
219
|
-
" ",
|
|
220
|
-
"\u2192",
|
|
221
|
-
" ",
|
|
222
|
-
continueLabel
|
|
223
|
-
] })
|
|
224
|
-
] });
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
export {
|
|
228
|
-
StepAgents
|
|
229
|
-
};
|
|
230
|
-
//# sourceMappingURL=chunk-DJEO3F2H.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/components/wizard/step-agents.tsx"],"sourcesContent":["import { groupBy, unique } from \"remeda\";\nimport { Box, Text, useInput } from \"ink\";\nimport {\n BUILT_IN_AGENT_GROUPS,\n BUILT_IN_AGENT_IDS,\n deriveScopeBadges,\n formatScopeTag,\n} from \"../../lib/wizard/index.js\";\nimport type { AgentGroup, AgentItem } from \"../../lib/wizard/index.js\";\nimport React, { useMemo, useState } from \"react\";\nimport { CLI_COLORS, UI_SYMBOLS } from \"../../consts.js\";\nimport { matrix } from \"../../lib/matrix/matrix-provider.js\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport type { AgentName, MergedSkillsMatrix } from \"../../types/index.js\";\nimport { isAgentName } from \"../../utils/type-guards.js\";\nimport { typedKeys } from \"../../utils/typed-object.js\";\nimport { toTitleCase } from \"../../utils/string.js\";\nimport { useMeasuredHeight } from \"../hooks/use-measured-height.js\";\nimport { useRowScroll } from \"../hooks/use-row-scroll.js\";\nimport { KEY_SPACE } from \"./hotkeys.js\";\nimport { getDomainDisplayName } from \"./utils.js\";\n\ntype FocusId = AgentName | \"continue\";\n\ntype ListRow =\n { type: \"header\"; label: string } | { type: \"spacer\" } | { type: \"agent\"; agent: AgentItem };\n\n/**\n * The sub-agents a loaded source's stacks name, as the strings a stack file spells them.\n *\n * `typedKeys` types them `AgentName` because `ResolvedStack.skills` is keyed by it, but the keys\n * arrive from a marketplace's own YAML and nothing between there and here narrows them — which\n * is exactly the claim the filter below has to test.\n */\nfunction agentIdsNamedByStacks(matrix: MergedSkillsMatrix): string[] {\n return unique(matrix.suggestedStacks.flatMap((stack) => typedKeys(stack.skills)));\n}\n\n/**\n * The rows a loaded source adds to the built-in grid.\n *\n * Narrowed with `isAgentName` and deliberately NOT cast to it. A row here is a name the user can\n * put into `config.agents`, and only the CLI's own `src/agents/` declares a sub-agent a compile\n * pass can honour — that directory is the whole of the roster (owner ruling 2026-08-21) and is\n * what `AGENT_NAMES` is generated from. So a stack naming an agent the CLI does not ship\n * contributes nothing: offering it a row wrote a name that reached `AgentName`,\n * `SelectedAgentName` and `ProjectAgentName` alike and then left `compile` with no definition to\n * compile.\n */\nfunction selectableSourceAgents(matrix: MergedSkillsMatrix): AgentName[] {\n return agentIdsNamedByStacks(matrix)\n .filter(isAgentName)\n .filter((agentName) => !BUILT_IN_AGENT_IDS.has(agentName));\n}\n\nfunction buildAgentGroups(matrix: MergedSkillsMatrix): AgentGroup[] {\n const customAgentIds = selectableSourceAgents(matrix);\n\n if (customAgentIds.length === 0) return BUILT_IN_AGENT_GROUPS;\n\n // Group custom agents by explicit domain (from metadata.yaml) or kebab prefix fallback\n const customItems = customAgentIds.map((agentId) => {\n const explicitDomain = matrix.agentDefinedDomains?.[agentId];\n const domainKey = explicitDomain ?? (agentId.split(\"-\")[0] || \"custom\");\n return {\n groupLabel: getDomainDisplayName(domainKey),\n item: {\n id: agentId,\n label: toTitleCase(agentId),\n description: \"Custom agent\",\n },\n };\n });\n const customGroups: AgentGroup[] = Object.entries(groupBy(customItems, (c) => c.groupLabel)).map(\n ([label, entries]) => ({ label, items: entries.map((entry) => entry.item) }),\n );\n\n return [...BUILT_IN_AGENT_GROUPS, ...customGroups];\n}\n\nfunction buildFlatRows(groups: AgentGroup[]): ListRow[] {\n return groups.flatMap((group, groupIndex): ListRow[] => [\n ...(groupIndex > 0 ? [{ type: \"spacer\" as const }] : []),\n { type: \"header\" as const, label: group.label },\n ...group.items.map((agent): ListRow => ({ type: \"agent\", agent })),\n ]);\n}\n\nfunction buildFocusableIds(groups: AgentGroup[]): FocusId[] {\n return [...groups.flatMap((group) => group.items.map((a) => a.id)), \"continue\"];\n}\n\n/**\n * Asserting row lookup. `buildFocusableIds` always appends \"continue\", so the\n * list is never empty and every caller below wraps within it — a miss means the\n * wrap arithmetic is wrong, which is worth a diagnostic rather than a focus that\n * silently stops moving.\n */\nfunction focusableIdAt(ids: FocusId[], index: number): FocusId {\n const id = ids[index];\n if (id === undefined) throw new Error(`No focusable row at index ${index} of ${ids.length}`);\n return id;\n}\n\nexport const StepAgents: React.FC = () => {\n const selectedAgents = useWizardStore((s) => s.selectedAgents);\n const agentConfigs = useWizardStore((s) => s.agentConfigs);\n\n const agentGroups = useMemo(() => buildAgentGroups(matrix), []);\n const flatRows = useMemo(() => buildFlatRows(agentGroups), [agentGroups]);\n const focusableIds = useMemo(() => buildFocusableIds(agentGroups), [agentGroups]);\n\n const [focusedId, setFocusedId] = useState<FocusId>(() => {\n const stored = useWizardStore.getState().focusedAgentId;\n return stored && focusableIds.includes(stored) ? stored : focusableIdAt(focusableIds, 0);\n });\n const { ref: listRef, measuredHeight: listHeight } = useMeasuredHeight();\n\n const focusedRowIndex =\n focusedId !== \"continue\"\n ? flatRows.findIndex((row) => row.type === \"agent\" && row.agent.id === focusedId)\n : -1;\n // The Agents grid clips silently: `useRowScroll` exposes no hidden-line counts\n // and this view renders no `ScrollAffordance`, by owner decision — see the\n // hook's doc comment.\n const { scrollEnabled, scrollTop } = useRowScroll({\n focusedIndex: Math.max(0, focusedRowIndex),\n itemCount: flatRows.length,\n availableHeight: listHeight,\n });\n\n useInput((input, key) => {\n if (key.escape) {\n useWizardStore.getState().goBack();\n return;\n }\n\n const currentIdx = focusableIds.indexOf(focusedId);\n\n if (key.upArrow || input === \"k\") {\n const nextIdx = currentIdx <= 0 ? focusableIds.length - 1 : currentIdx - 1;\n setFocusedId(focusableIdAt(focusableIds, nextIdx));\n return;\n }\n\n if (key.downArrow || input === \"j\") {\n const nextIdx = currentIdx >= focusableIds.length - 1 ? 0 : currentIdx + 1;\n setFocusedId(focusableIdAt(focusableIds, nextIdx));\n return;\n }\n\n if (key.return) {\n useWizardStore.getState().setStep(\"confirm\");\n return;\n }\n\n if (input === KEY_SPACE && focusedId !== \"continue\") {\n useWizardStore.getState().toggleAgent(focusedId);\n }\n });\n\n // Sync focusedAgentId so the wizard-level S key handler can toggle agent scope\n React.useEffect(() => {\n useWizardStore.getState().setFocusedAgentId(focusedId === \"continue\" ? null : focusedId);\n }, [focusedId]);\n\n const focusedGroupLabel = agentGroups.find((g) => g.items.some((a) => a.id === focusedId))?.label;\n\n const selectedCount = selectedAgents.length;\n const continueLabel =\n selectedCount > 0 ? `Continue with ${selectedCount} agent(s)` : \"Continue without agents\";\n\n const isContinueFocused = focusedId === \"continue\";\n\n const rowElements = flatRows.map((row, index) => {\n switch (row.type) {\n case \"header\":\n return (\n <Box key={`header-${row.label}`} flexShrink={0}>\n {row.label === focusedGroupLabel ? (\n <Text\n color={CLI_COLORS.WHITE}\n backgroundColor={CLI_COLORS.LABEL_BG}\n >{` ${row.label} `}</Text>\n ) : (\n <Text dimColor bold>\n {\" \"}\n {row.label}\n </Text>\n )}\n </Box>\n );\n case \"spacer\":\n return (\n <Box key={`spacer-${index}`} flexShrink={0}>\n <Text> </Text>\n </Box>\n );\n case \"agent\": {\n const isFocused = row.agent.id === focusedId;\n const isSelected = selectedAgents.includes(row.agent.id);\n const checkbox = isSelected ? \"[\\u2713]\" : \"[ ]\";\n const pointer = isFocused ? UI_SYMBOLS.CHEVRON : UI_SYMBOLS.CHEVRON_SPACER;\n const agentConfig = agentConfigs.find((ac) => ac.name === row.agent.id && !ac.excluded);\n const excludedConfig = agentConfigs.find((ac) => ac.name === row.agent.id && ac.excluded);\n const badges = deriveScopeBadges(agentConfig, excludedConfig);\n const scope = badges.scope ?? \"global\";\n const secondaryScope = badges.secondaryScope;\n return (\n <Box key={row.agent.id} flexShrink={0}>\n <Text>\n <Text {...(isFocused && { color: CLI_COLORS.PRIMARY })}>{pointer}</Text>\n <Text\n {...((isSelected || isFocused) && { color: CLI_COLORS.PRIMARY })}\n bold={isFocused}\n >\n {\" \"}\n {checkbox}{\" \"}\n </Text>\n <Text color={scope === \"global\" ? CLI_COLORS.WARNING : CLI_COLORS.TOAST_BG}>\n {formatScopeTag(scope)}\n </Text>\n {secondaryScope && (\n <Text\n color={secondaryScope === \"global\" ? CLI_COLORS.WARNING : CLI_COLORS.TOAST_BG}\n >\n {formatScopeTag(secondaryScope)}\n </Text>\n )}\n <Text\n {...((isSelected || isFocused) && { color: CLI_COLORS.PRIMARY })}\n bold={isFocused}\n >\n {\" \"}\n {row.agent.label}\n </Text>\n <Text dimColor> {row.agent.description}</Text>\n </Text>\n </Box>\n );\n }\n default: {\n const _exhaustive: never = row;\n return _exhaustive;\n }\n }\n });\n\n return (\n <Box flexDirection=\"column\" width=\"100%\" flexGrow={1} flexBasis={0}>\n <Box ref={listRef} flexDirection=\"column\" flexGrow={1} flexBasis={0}>\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n {...(scrollEnabled && { overflow: \"hidden\" as const })}\n >\n <Box\n flexDirection=\"column\"\n marginTop={scrollTop > 0 ? -scrollTop : 0}\n {...(scrollEnabled && { flexShrink: 0 })}\n >\n {rowElements}\n </Box>\n </Box>\n </Box>\n\n <Text {...(isContinueFocused && { color: CLI_COLORS.PRIMARY })} bold={isContinueFocused}>\n {isContinueFocused ? UI_SYMBOLS.CHEVRON : UI_SYMBOLS.CHEVRON_SPACER} {\"\\u2192\"}{\" \"}\n {continueLabel}\n </Text>\n </Box>\n );\n};\n"],"mappings":"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","names":["matrix"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/seed/seed-apply.ts","../src/cli/utils/open-url.ts"],"sourcesContent":["import os from \"os\";\n\nimport { isDeepEqual, omit, partition, pick } from \"remeda\";\n\nimport { loadProjectConfigFromDir } from \"../configuration/project-config.js\";\nimport { isActiveAt } from \"../configuration/scope-predicates.js\";\nimport { providerInUse } from \"../installation/install-layout.js\";\nimport { getCategoryDomain, getSkillDisplayName, matrix } from \"../matrix/matrix-provider.js\";\nimport { orderDomains } from \"../wizard/domain-order.js\";\nimport { SHARED_CONFIG_APPLY, SHARED_CONFIG_ARRIVALS } from \"../../utils/messages.js\";\nimport { typedEntries, typedKeys, typedValues } from \"../../utils/typed-object.js\";\n\nimport type { WizardResultV2 } from \"../../components/wizard/wizard.js\";\nimport type { AgentName } from \"../../types/agents.js\";\nimport type {\n AgentScopeConfig,\n ProjectConfig,\n SkillConfig,\n SkillScope,\n} from \"../../types/config.js\";\nimport type { Category, Domain } from \"../../types/matrix.js\";\nimport type { SkillAssignment, SkillId } from \"../../types/skills.js\";\nimport type { StackAgentConfig } from \"../../types/stacks.js\";\nimport type { SeedPayload, SeedSkill } from \"@workspace/matrix/seed\";\n\n/**\n * What applying a shared configuration may not take away, split by reason: each has its own remedy.\n */\nexport type KeptFromRoundTrip = {\n /** Written here, so no shared configuration ever carried them. */\n authoredSkillIds: SkillId[];\n /** Named by the configuration but unplaceable by this catalogue. */\n unplaceableSkillIds: SkillId[];\n};\n\n/**\n * A kept skill's row displaced by the payload's own skill in a one-skill category. The skill stays\n * installed; the row goes.\n */\nexport type UnassignedRow = { skillId: SkillId; agentName: AgentName; category: Category };\n\nexport type ReconciledSharedConfig = {\n result: WizardResultV2;\n kept: KeptFromRoundTrip;\n unassigned: UnassignedRow[];\n};\n\nexport type ReconcileOptions = {\n decoded: WizardResultV2;\n /** Its own config, or the global one it inherits. */\n installed: ProjectConfig | null;\n /** From `skillsAuthoredHere`, the one definition both halves share. */\n authoredHere: ReadonlySet<SkillId>;\n /**\n * `SeedMapping.skippedSkillIds` as the caller already reported them, so the two cannot disagree.\n */\n unplaceable: ReadonlySet<string>;\n};\n\nconst NOTHING_KEPT: KeptFromRoundTrip = {\n authoredSkillIds: [],\n unplaceableSkillIds: [],\n};\n\n/**\n * Puts back what the destructive apply may not remove: skills written here (the payload never\n * named them) and ids it named that this catalogue cannot place (removal is on intent, never on\n * inability). Scope is {@link restoreInstalledGlobal}'s. Restored into the RESULT, not excused at\n * the writer: the removal diff drives the uninstall and file deletion whatever the merger does. A\n * kept skill also needs its stack rows and domain, or the next run deletes it.\n */\nexport function reconcileSharedConfig(options: ReconcileOptions): ReconciledSharedConfig {\n const { decoded, installed } = options;\n if (!installed) return nothingToReconcile(decoded);\n\n const keptSkills = skillsToKeep(options, installed);\n if (keptSkills.length === 0) return nothingToReconcile(decoded);\n\n const { result, unassigned } = withKeptEntries(decoded, installed, keptSkills);\n return { result, kept: describeKept(options, keptSkills), unassigned };\n}\n\nfunction nothingToReconcile(decoded: WizardResultV2): ReconciledSharedConfig {\n return { result: decoded, kept: NOTHING_KEPT, unassigned: [] };\n}\n\n/** A tombstone is neither: nothing is installed, so nothing needs protecting. */\nfunction skillsToKeep(options: ReconcileOptions, installed: ProjectConfig): SkillConfig[] {\n const named = new Set(options.decoded.skills.map((skill) => skill.id));\n\n return installed.skills.filter(\n (skill) => !skill.excluded && !named.has(skill.id) && mayNotRemove(skill, options),\n );\n}\n\nfunction mayNotRemove(skill: SkillConfig, options: ReconcileOptions): boolean {\n return options.authoredHere.has(skill.id) || options.unplaceable.has(skill.id);\n}\n\ntype KeptReason = \"authored\" | \"unplaceable\";\n\nfunction describeKept(options: ReconcileOptions, keptSkills: SkillConfig[]): KeptFromRoundTrip {\n const idsKeptFor = (reason: KeptReason): SkillId[] =>\n keptSkills.filter((skill) => reasonKept(skill, options) === reason).map((skill) => skill.id);\n\n return {\n authoredSkillIds: idsKeptFor(\"authored\"),\n unplaceableSkillIds: idsKeptFor(\"unplaceable\"),\n };\n}\n\n/**\n * Where both apply, the more permanent claim is disclosed: `update` can resolve an unplaceable id,\n * nothing changes who authored a skill.\n */\nfunction reasonKept(skill: SkillConfig, options: ReconcileOptions): KeptReason {\n return options.authoredHere.has(skill.id) ? \"authored\" : \"unplaceable\";\n}\n\nfunction withKeptEntries(\n decoded: WizardResultV2,\n installed: ProjectConfig,\n keptSkills: SkillConfig[],\n): Pick<ReconciledSharedConfig, \"result\" | \"unassigned\"> {\n const withSkills: WizardResultV2 = {\n ...decoded,\n skills: [...decoded.skills, ...keptSkills],\n selectedDomains: withKeptDomains(decoded.selectedDomains, keptSkills),\n };\n if (decoded.assignedStack === undefined) return { result: withSkills, unassigned: [] };\n\n const { assignedStack, unassigned } = withKeptStackRows(decoded.assignedStack, installed.stack, {\n keptSkillIds: new Set(keptSkills.map((skill) => skill.id)),\n survivingAgents: new Set(decoded.selectedAgents),\n });\n return { result: { ...withSkills, assignedStack }, unassigned };\n}\n\nfunction withKeptDomains(selected: Domain[], keptSkills: SkillConfig[]): Domain[] {\n const keptDomains = keptSkills.flatMap((skill) => domainOfSkill(skill.id) ?? []);\n const missing = keptDomains.filter((domain) => !selected.includes(domain));\n if (missing.length === 0) return selected;\n\n return orderDomains([...selected, ...new Set(missing)]);\n}\n\n/** Undefined for an entry the loaded source cannot resolve; `edit` reports those itself. */\nfunction domainOfSkill(skillId: SkillId): Domain | undefined {\n const category = matrix.skills[skillId]?.category;\n return category === undefined ? undefined : getCategoryDomain(category);\n}\n\ntype KeptRowFilter = {\n keptSkillIds: ReadonlySet<SkillId>;\n survivingAgents: ReadonlySet<AgentName>;\n};\n\ntype KeptRows = {\n assignedStack: Partial<Record<AgentName, StackAgentConfig>>;\n unassigned: UnassignedRow[];\n};\n\n/**\n * `assignedStack` replaces the derived stack, so a kept skill's installed rows are its only rows.\n * Rows under a sub-agent this configuration removes go with it. A kept row joins the payload's\n * under its category, except in a one-skill category the payload fills: the payload's skill takes\n * the slot (as {@link arrivingRows} does) and the kept row is returned as unassigned.\n */\nfunction withKeptStackRows(\n assigned: Partial<Record<AgentName, StackAgentConfig>>,\n installedStack: Partial<Record<AgentName, StackAgentConfig>> | undefined,\n filter: KeptRowFilter,\n): KeptRows {\n const isKept = (_category: Category, row: SkillAssignment): boolean =>\n filter.keptSkillIds.has(row.id);\n\n return typedEntries<AgentName, StackAgentConfig>(installedStack ?? {})\n .filter(([agent]) => filter.survivingAgents.has(agent))\n .reduce<KeptRows>(\n (carried, [agent, agentStack]) =>\n withAgentKeptRows(carried, agent, rowsWhere(agentStack, isKept), assigned[agent]),\n { assignedStack: assigned, unassigned: [] },\n );\n}\n\nfunction withAgentKeptRows(\n carried: KeptRows,\n agent: AgentName,\n keptRows: [Category, SkillAssignment][],\n payloadRows: StackAgentConfig | undefined,\n): KeptRows {\n const filled = filledExclusiveCategories(payloadRows);\n const [displaced, joining] = partition(keptRows, ([category]) => filled.has(category));\n\n return {\n assignedStack: withAppendedRows(carried.assignedStack, agent, joining),\n unassigned: [\n ...carried.unassigned,\n ...displaced.map(([category, row]) => ({ skillId: row.id, agentName: agent, category })),\n ],\n };\n}\n\n/**\n * Puts back each installed sub-agent the payload assigns an unplaceable skill, as installed:\n * the decode carries sub-agents in only through placed skills, and its absence is a catalogue\n * limit, not an instruction.\n */\nexport function withUnplaceableAssignees(\n decoded: WizardResultV2,\n installed: ProjectConfig | null,\n payload: SeedPayload,\n unplaceable: ReadonlySet<string>,\n): WizardResultV2 {\n if (!installed) return decoded;\n\n const assigned = assigneesOfHeld(payload, installed, unplaceable);\n const selected = new Set(decoded.selectedAgents);\n const leftOutThoughAssigned = (agent: AgentScopeConfig): boolean =>\n !agent.excluded && assigned.has(agent.name) && !selected.has(agent.name);\n\n const assignees = installed.agents.filter(leftOutThoughAssigned);\n if (assignees.length === 0) return decoded;\n\n return {\n ...decoded,\n selectedAgents: [...decoded.selectedAgents, ...assignees.map((agent) => agent.name)],\n agentConfigs: [...decoded.agentConfigs, ...assignees],\n };\n}\n\n/** Less any the payload switches off. */\nfunction assigneesOfHeld(\n payload: SeedPayload,\n installed: ProjectConfig,\n unplaceable: ReadonlySet<string>,\n): Set<string> {\n const held = new Set<string>(\n installed.skills.filter((skill) => !skill.excluded).map((skill) => skill.id),\n );\n const isHeldUnplaceable = ([id]: [string, SeedSkill]): boolean =>\n unplaceable.has(id) && held.has(id);\n const isNotSwitchedOff = (name: string): boolean => payload.agents[name]?.on !== false;\n\n return new Set(\n typedEntries<string, SeedSkill>(payload.skills)\n .filter(isHeldUnplaceable)\n .flatMap(([, skill]) => typedKeys<string>(skill.assignments))\n .filter(isNotSwitchedOff),\n );\n}\n\nexport type InstalledGlobal = Pick<ProjectConfig, \"skills\" | \"agents\" | \"stack\">;\n\n/**\n * Read from the global config, which every registered project inherits, rather than from a\n * project's possibly older inlined copy; through the project's own provider. `null` when absent.\n */\nexport async function readInstalledGlobal(projectDir: string): Promise<InstalledGlobal | null> {\n const loaded = await loadProjectConfigFromDir(os.homedir(), providerInUse(projectDir));\n return loaded?.config ?? null;\n}\n\ntype GlobalEntries = { skillIds: SkillId[]; agentNames: AgentName[] };\n\nexport type HeldGlobal = {\n result: WizardResultV2;\n /**\n * Global entries the configuration names that the global install holds; their skills are skipped.\n */\n installed: GlobalEntries;\n /**\n * Of those, the ones stated otherwise, plus (from {@link restoreInstalledGlobal}) every omitted\n * one.\n */\n keptAsInstalled: GlobalEntries;\n};\n\nconst NO_GLOBAL_ENTRIES: GlobalEntries = { skillIds: [], agentNames: [] };\n\n/**\n * From a project `--from` only ADDS to the global install (owner ruling 2026-10-02): every global\n * entry it already holds is restated as held — install mode, tuning and rows. What it lacks\n * arrives whole, including a new skill's row on a held sub-agent. `installed` is `null` at the\n * home directory and on a machine with no global install.\n */\nexport function holdInstalledGlobal(\n decoded: WizardResultV2,\n installed: InstalledGlobal | null,\n): HeldGlobal {\n if (!installed) {\n return { result: decoded, installed: NO_GLOBAL_ENTRIES, keptAsInstalled: NO_GLOBAL_ENTRIES };\n }\n\n const heldSkills = activeGlobalById(installed.skills, (skill) => skill.id);\n const heldAgents = activeGlobalById(installed.agents, (agent) => agent.name);\n const skills = pairWithHeld(decoded.skills, heldSkills, (skill) => skill.id);\n const agents = pairWithHeld(decoded.agentConfigs, heldAgents, (agent) => agent.name);\n const namedSkillIds = skills.map(({ named }) => named.id);\n const namedAgentNames = agents.map(({ named }) => named.name);\n const assignedStack =\n decoded.assignedStack &&\n withHeldRows(decoded.assignedStack, installed.stack, {\n agentNames: namedAgentNames,\n skippedSkillIds: new Set(namedSkillIds),\n });\n\n const restatesSkill = ({ named, held }: Held<SkillConfig>): boolean =>\n named.origin === held.origin;\n const restatesAgent = ({ named, held }: Held<AgentScopeConfig>): boolean =>\n named.model === held.model &&\n named.codexModel === held.codexModel &&\n named.effort === held.effort &&\n sameAssignments(decoded.assignedStack?.[named.name], assignedStack?.[named.name]);\n\n return {\n result: {\n ...decoded,\n skills: decoded.skills.map(asHeld(skills)),\n agentConfigs: decoded.agentConfigs.map(asHeld(agents)),\n ...(assignedStack !== undefined && { assignedStack }),\n },\n installed: { skillIds: namedSkillIds, agentNames: namedAgentNames },\n keptAsInstalled: {\n skillIds: skills.filter((pair) => !restatesSkill(pair)).map(({ named }) => named.id),\n agentNames: agents.filter((pair) => !restatesAgent(pair)).map(({ named }) => named.name),\n },\n };\n}\n\n/**\n * Also puts back every global entry the configuration omits, for the destructive `edit --from`:\n * the global install's entries are not a project's to remove.\n */\nexport function restoreInstalledGlobal(\n decoded: WizardResultV2,\n installed: InstalledGlobal | null,\n): HeldGlobal {\n const held = holdInstalledGlobal(decoded, installed);\n if (!installed) return held;\n\n const omitted = omittedGlobal(held.result, installed);\n const { skillIds, agentNames } = held.keptAsInstalled;\n return {\n ...held,\n result: withOmittedGlobal(held.result, installed, omitted),\n keptAsInstalled: {\n skillIds: [...skillIds, ...omitted.skills.map((skill) => skill.id)],\n agentNames: [...agentNames, ...omitted.agents.map((agent) => agent.name)],\n },\n };\n}\n\nfunction activeGlobalById<Entry extends SkillConfig | AgentScopeConfig, Key extends string>(\n entries: Entry[],\n keyOf: (entry: Entry) => Key,\n): Map<Key, Entry> {\n return new Map(\n entries.filter((entry) => isActiveAt(entry, \"global\")).map((entry) => [keyOf(entry), entry]),\n );\n}\n\ntype Held<Entry> = { named: Entry; held: Entry };\n\nfunction asHeld<Entry>(pairs: Held<Entry>[]): (entry: Entry) => Entry {\n const heldFor = new Map(pairs.map(({ named, held }) => [named, held]));\n return (entry) => heldFor.get(entry) ?? entry;\n}\n\nfunction pairWithHeld<Entry extends SkillConfig | AgentScopeConfig, Key extends string>(\n decoded: Entry[],\n heldByKey: ReadonlyMap<Key, Entry>,\n keyOf: (entry: Entry) => Key,\n): Held<Entry>[] {\n return decoded.flatMap((named) => {\n const held = heldByKey.get(keyOf(named));\n return held !== undefined && isActiveAt(named, \"global\") ? [{ named, held }] : [];\n });\n}\n\n/** Row order is not part of what a sub-agent loads. */\nexport function sameAssignments(\n left: StackAgentConfig | undefined,\n right: StackAgentConfig | undefined,\n): boolean {\n return isDeepEqual(assignmentKeys(left), assignmentKeys(right));\n}\n\nfunction assignmentKeys(agentStack: StackAgentConfig | undefined): string[] {\n return typedEntries<Category, SkillAssignment[]>(agentStack ?? {})\n .flatMap(([category, assignments]) =>\n assignments.map((row) => `${category}/${row.id}/${row.preloaded === true}`),\n )\n .sort();\n}\n\n/** None where the global install gives the sub-agent none. */\nfunction withInstalledRows(\n assigned: Partial<Record<AgentName, StackAgentConfig>>,\n installedStack: InstalledGlobal[\"stack\"],\n agentNames: AgentName[],\n): Partial<Record<AgentName, StackAgentConfig>> {\n return { ...omit(assigned, agentNames), ...pick(installedStack ?? {}, agentNames) };\n}\n\ntype HeldRows = { agentNames: AgentName[]; skippedSkillIds: ReadonlySet<SkillId> };\n\n/** Existing rows stay first and unchanged; arriving skills bring their rows after them. */\nfunction withHeldRows(\n assigned: Partial<Record<AgentName, StackAgentConfig>>,\n installedStack: InstalledGlobal[\"stack\"],\n held: HeldRows,\n): Partial<Record<AgentName, StackAgentConfig>> {\n const asInstalled = withInstalledRows(assigned, installedStack, held.agentNames);\n\n return held.agentNames.reduce(\n (stack, agentName) =>\n withAppendedRows(\n stack,\n agentName,\n arrivingRows(assigned[agentName], stack[agentName], held.skippedSkillIds),\n ),\n asInstalled,\n );\n}\n\n/**\n * Rows bringing a skill the global install lacks, under a category with room. In a one-skill\n * category the sub-agent already fills, the arriving skill installs without that row.\n */\nfunction arrivingRows(\n stated: StackAgentConfig | undefined,\n installed: StackAgentConfig | undefined,\n skippedSkillIds: ReadonlySet<SkillId>,\n): [Category, SkillAssignment][] {\n const alreadyLoaded = new Set(rowIds(installed));\n const filled = filledExclusiveCategories(installed);\n const arrives = (category: Category, row: SkillAssignment): boolean =>\n !skippedSkillIds.has(row.id) && !alreadyLoaded.has(row.id) && !filled.has(category);\n\n return rowsWhere(stated, arrives);\n}\n\nfunction rowIds(agentStack: StackAgentConfig | undefined): SkillId[] {\n return typedValues<Category, SkillAssignment[]>(agentStack ?? {}).flatMap((rows) =>\n rows.map((row) => row.id),\n );\n}\n\n/** An undeclared category is not exclusive (see `propagate.ts`). */\nfunction filledExclusiveCategories(agentStack: StackAgentConfig | undefined): Set<Category> {\n const isExclusive = (category: Category): boolean =>\n matrix.categories[category]?.exclusive === true;\n\n return new Set(\n typedEntries<Category, SkillAssignment[]>(agentStack ?? {})\n .filter(([category, rows]) => rows.length > 0 && isExclusive(category))\n .map(([category]) => category),\n );\n}\n\nfunction withAppendedRows(\n stack: Partial<Record<AgentName, StackAgentConfig>>,\n agentName: AgentName,\n added: [Category, SkillAssignment][],\n): Partial<Record<AgentName, StackAgentConfig>> {\n if (added.length === 0) return stack;\n return { ...stack, [agentName]: appendRows(stack[agentName] ?? {}, added) };\n}\n\nfunction rowsWhere(\n agentStack: StackAgentConfig | undefined,\n keep: (category: Category, row: SkillAssignment) => boolean,\n): [Category, SkillAssignment][] {\n return typedEntries<Category, SkillAssignment[]>(agentStack ?? {}).flatMap(([category, rows]) =>\n rows\n .filter((row) => keep(category, row))\n .map((row): [Category, SkillAssignment] => [category, row]),\n );\n}\n\nfunction appendRows(\n agentStack: StackAgentConfig,\n added: [Category, SkillAssignment][],\n): StackAgentConfig {\n return added.reduce<StackAgentConfig>(\n (rows, [category, row]) => ({ ...rows, [category]: [...(rows[category] ?? []), row] }),\n agentStack,\n );\n}\n\ntype OmittedGlobal = { skills: SkillConfig[]; agents: AgentScopeConfig[] };\n\nfunction omittedGlobal(result: WizardResultV2, installed: InstalledGlobal): OmittedGlobal {\n const namedSkillIds = new Set(result.skills.map((skill) => skill.id));\n const namedAgentNames = new Set(result.agentConfigs.map((agent) => agent.name));\n\n return {\n skills: [...activeGlobalById(installed.skills, (skill) => skill.id).values()].filter(\n (skill) => !namedSkillIds.has(skill.id),\n ),\n agents: [...activeGlobalById(installed.agents, (agent) => agent.name).values()].filter(\n (agent) => !namedAgentNames.has(agent.name),\n ),\n };\n}\n\nfunction withOmittedGlobal(\n result: WizardResultV2,\n installed: InstalledGlobal,\n omitted: OmittedGlobal,\n): WizardResultV2 {\n const omittedAgentNames = omitted.agents.map((agent) => agent.name);\n\n return {\n ...result,\n skills: [...result.skills, ...omitted.skills],\n agentConfigs: [...result.agentConfigs, ...omitted.agents],\n selectedAgents: [...new Set([...result.selectedAgents, ...omittedAgentNames])],\n selectedDomains: withKeptDomains(result.selectedDomains, omitted.skills),\n ...(result.assignedStack !== undefined && {\n assignedStack: withInstalledRows(result.assignedStack, installed.stack, omittedAgentNames),\n }),\n };\n}\n\n/**\n * A carried skill's bytes written over a global skill directory would change it like a reinstall.\n */\nexport function notInstalledGlobally<Entry extends { id: SkillId }>(\n entries: Entry[],\n held: HeldGlobal,\n): Entry[] {\n const installed = new Set(held.installed.skillIds);\n return entries.filter((entry) => !installed.has(entry.id));\n}\n\nexport type ArrivingEntries = { skillIds: SkillId[]; agentNames: AgentName[] };\n\nexport type Arrivals = Record<SkillScope, ArrivingEntries>;\n\nexport function arrivalsByScope(skills: SkillConfig[], agents: AgentScopeConfig[]): Arrivals {\n const landingAt = (scope: SkillScope): ArrivingEntries => ({\n skillIds: skills.filter((skill) => isActiveAt(skill, scope)).map((skill) => skill.id),\n agentNames: agents.filter((agent) => isActiveAt(agent, scope)).map((agent) => agent.name),\n });\n return { project: landingAt(\"project\"), global: landingAt(\"global\") };\n}\n\nfunction installArrivals(held: HeldGlobal): Arrivals {\n const installedSkillIds = new Set(held.installed.skillIds);\n const installedAgentNames = new Set(held.installed.agentNames);\n return arrivalsByScope(\n held.result.skills.filter((skill) => !installedSkillIds.has(skill.id)),\n held.result.agentConfigs.filter((agent) => !installedAgentNames.has(agent.name)),\n );\n}\n\n/** A skipped global skill is named, so no unarriving skill goes unmentioned. */\nexport function installPlanLines(held: HeldGlobal): string[] {\n return [\n ...arrivalLines(installArrivals(held)),\n ...scopeLines(SHARED_CONFIG_ARRIVALS.SKIPPED_HEADING, {\n skillIds: held.installed.skillIds,\n agentNames: [],\n }),\n ];\n}\n\nexport function skillLabel(skillId: SkillId): string {\n const displayName = getSkillDisplayName(skillId);\n return displayName === skillId ? skillId : `${displayName} (${skillId})`;\n}\n\nexport function arrivalLines(arrivals: Arrivals): string[] {\n return [\n ...scopeLines(SHARED_CONFIG_ARRIVALS.PROJECT_HEADING, arrivals.project),\n ...scopeLines(SHARED_CONFIG_ARRIVALS.GLOBAL_HEADING, arrivals.global),\n ];\n}\n\nfunction scopeLines(heading: string, entries: ArrivingEntries): string[] {\n const groups = [\n { label: SHARED_CONFIG_APPLY.SKILLS_HEADING, items: entries.skillIds.map(skillLabel) },\n { label: SHARED_CONFIG_APPLY.AGENTS_HEADING, items: entries.agentNames },\n ].filter((group) => group.items.length > 0);\n if (groups.length === 0) return [];\n\n return [\n heading,\n ...groups.flatMap((group) => [` ${group.label}`, ...group.items.map((item) => ` ${item}`)]),\n ];\n}\n","import { execCommand } from \"./exec.js\";\nimport { getErrorMessage } from \"./errors.js\";\n\n/** The shell-out one platform answers \"open this with whatever handles it\" with. */\nexport type OpenerCommand = { command: string; args: string[] };\n\n/**\n * Never a throw. A machine with no browser, no desktop session or no opener at all is a\n * legitimate place to run this CLI, so failing to open a link is something to say rather than\n * something to fail on — the same posture the seed boundaries take, and for the same reason:\n * the link is already printed by the time this runs, so nothing is lost by it not working.\n */\nexport type OpenUrlResult = { ok: true } | { ok: false; error: string };\n\n/**\n * The command a platform opens a link with.\n *\n * There is no dependency for this. All three are one-line shell-outs to something the operating\n * system already ships, and a package for it would be a fourth thing to keep current for no\n * behaviour this does not have.\n *\n * Windows goes through `cmd` because `start` is a shell builtin rather than a program, and the\n * empty string after it is its TITLE argument: without one, `start` reads the first quoted\n * argument it is given as the window title and opens nothing.\n */\nexport function browserOpenerCommand(platform: NodeJS.Platform, url: string): OpenerCommand {\n if (platform === \"darwin\") return { command: \"open\", args: [url] };\n if (platform === \"win32\") return { command: \"cmd\", args: [\"/c\", \"start\", \"\", url] };\n return { command: \"xdg-open\", args: [url] };\n}\n\nfunction openerRefusedMessage(command: string, exitCode: number): string {\n return `Could not open your browser — '${command}' exited ${exitCode}.`;\n}\n\nfunction openerUnavailableMessage(command: string, reason: string): string {\n return `Could not open your browser — '${command}' could not be run: ${reason}`;\n}\n\n/**\n * Hands a link to whatever this platform opens links with.\n *\n * The URL travels as its own argument rather than inside a command line: `execCommand` spawns\n * without a shell, so the argument vector is the whole of the injection guard — there is no\n * string for a link to break out of.\n */\nexport async function openUrl(url: string): Promise<OpenUrlResult> {\n const { command, args } = browserOpenerCommand(process.platform, url);\n\n try {\n const result = await execCommand(command, args);\n if (result.exitCode !== 0) {\n return { ok: false, error: openerRefusedMessage(command, result.exitCode) };\n }\n return { ok: true };\n } catch (error) {\n return { ok: false, error: openerUnavailableMessage(command, getErrorMessage(error)) };\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-GRL73YPF.js
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
useMeasuredHeight
|
|
4
|
-
} from "./chunk-TSIU7DME.js";
|
|
5
|
-
import {
|
|
6
|
-
useKeyboardNavigation
|
|
7
|
-
} from "./chunk-JOEA52NR.js";
|
|
8
|
-
import {
|
|
9
|
-
useRowScroll
|
|
10
|
-
} from "./chunk-LFUJCRCT.js";
|
|
11
|
-
import {
|
|
12
|
-
showWarningsAsToast,
|
|
13
|
-
useWizardStore
|
|
14
|
-
} from "./chunk-WNLF5EDZ.js";
|
|
15
|
-
import {
|
|
16
|
-
matrix,
|
|
17
|
-
typedKeys
|
|
18
|
-
} from "./chunk-NU2K5G54.js";
|
|
19
|
-
import {
|
|
20
|
-
CLI_COLORS,
|
|
21
|
-
UI_SYMBOLS
|
|
22
|
-
} from "./chunk-AG3ZVM3B.js";
|
|
23
|
-
|
|
24
|
-
// src/cli/components/wizard/stack-selection.tsx
|
|
25
|
-
import { groupBy } from "remeda";
|
|
26
|
-
import { Box, Text } from "ink";
|
|
27
|
-
import { useMemo } from "react";
|
|
28
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
29
|
-
var OTHER_FRAMEWORKS_LABEL = "Other Frameworks";
|
|
30
|
-
var GROUP_ORDER = ["React", "CLI"];
|
|
31
|
-
var SCRATCH_LABEL = "Start from scratch";
|
|
32
|
-
var SCRATCH_DESCRIPTION = "Select domains and skills manually";
|
|
33
|
-
function toStackItem(stack) {
|
|
34
|
-
return { id: stack.id, name: stack.name, description: stack.description };
|
|
35
|
-
}
|
|
36
|
-
function compareGroupLabels(a, b) {
|
|
37
|
-
const ai = GROUP_ORDER.indexOf(a);
|
|
38
|
-
const bi = GROUP_ORDER.indexOf(b);
|
|
39
|
-
if (ai !== -1 && bi !== -1) return ai - bi;
|
|
40
|
-
if (ai !== -1) return -1;
|
|
41
|
-
if (bi !== -1) return 1;
|
|
42
|
-
return a.localeCompare(b);
|
|
43
|
-
}
|
|
44
|
-
function groupStacks(stacks) {
|
|
45
|
-
const byLabel = groupBy(stacks, (stack) => stack.group || void 0);
|
|
46
|
-
const ungrouped = stacks.filter((stack) => !stack.group).map(toStackItem);
|
|
47
|
-
const labelled = Object.entries(byLabel).sort(([a], [b]) => compareGroupLabels(a, b));
|
|
48
|
-
if (labelled.length === 0) {
|
|
49
|
-
return [{ label: "", items: ungrouped }];
|
|
50
|
-
}
|
|
51
|
-
const groups = labelled.map(([label, stacksInGroup]) => ({
|
|
52
|
-
label,
|
|
53
|
-
items: stacksInGroup.map(toStackItem)
|
|
54
|
-
}));
|
|
55
|
-
return ungrouped.length > 0 ? [...groups, { label: OTHER_FRAMEWORKS_LABEL, items: ungrouped }] : groups;
|
|
56
|
-
}
|
|
57
|
-
function buildFocusableIds(groups) {
|
|
58
|
-
return [...groups.flatMap((g) => g.items.map((i) => i.id)), "scratch"];
|
|
59
|
-
}
|
|
60
|
-
function buildStackRows(groups) {
|
|
61
|
-
const groupRows = groups.flatMap((group, groupIndex) => [
|
|
62
|
-
...groupIndex > 0 ? [{ type: "spacer" }] : [],
|
|
63
|
-
...group.label ? [{ type: "header", label: group.label }] : [],
|
|
64
|
-
...group.items.map((item) => ({ type: "stack", item }))
|
|
65
|
-
]);
|
|
66
|
-
return [...groupRows, { type: "spacer" }, { type: "scratch" }];
|
|
67
|
-
}
|
|
68
|
-
function isRowFocused(row, focusedId) {
|
|
69
|
-
if (row.type === "stack") return row.item.id === focusedId;
|
|
70
|
-
return row.type === "scratch" && focusedId === "scratch";
|
|
71
|
-
}
|
|
72
|
-
var StackRow = ({ item, isFocused }) => {
|
|
73
|
-
const pointer = isFocused ? UI_SYMBOLS.CHEVRON : UI_SYMBOLS.CHEVRON_SPACER;
|
|
74
|
-
return /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
75
|
-
/* @__PURE__ */ jsx(Text, { ...isFocused && { color: CLI_COLORS.PRIMARY }, children: pointer }),
|
|
76
|
-
/* @__PURE__ */ jsxs(Text, { ...isFocused && { color: CLI_COLORS.PRIMARY }, bold: isFocused, children: [
|
|
77
|
-
" ",
|
|
78
|
-
item.name
|
|
79
|
-
] }),
|
|
80
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
81
|
-
" ",
|
|
82
|
-
item.description
|
|
83
|
-
] })
|
|
84
|
-
] }) });
|
|
85
|
-
};
|
|
86
|
-
var ScratchRow = ({ isFocused }) => {
|
|
87
|
-
const pointer = isFocused ? UI_SYMBOLS.CHEVRON : UI_SYMBOLS.CHEVRON_SPACER;
|
|
88
|
-
return /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
89
|
-
/* @__PURE__ */ jsx(Text, { ...isFocused && { color: CLI_COLORS.PRIMARY }, children: pointer }),
|
|
90
|
-
/* @__PURE__ */ jsxs(Text, { ...isFocused && { color: CLI_COLORS.PRIMARY }, bold: isFocused, children: [
|
|
91
|
-
" ",
|
|
92
|
-
SCRATCH_LABEL
|
|
93
|
-
] }),
|
|
94
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
95
|
-
" ",
|
|
96
|
-
SCRATCH_DESCRIPTION
|
|
97
|
-
] })
|
|
98
|
-
] }) });
|
|
99
|
-
};
|
|
100
|
-
var StackSelection = ({ onCancel }) => {
|
|
101
|
-
const {
|
|
102
|
-
selectStack,
|
|
103
|
-
setApproach,
|
|
104
|
-
setStackAction,
|
|
105
|
-
populateFromSkillIds,
|
|
106
|
-
preselectAgentsFromStack,
|
|
107
|
-
startFromScratch,
|
|
108
|
-
setStep
|
|
109
|
-
} = useWizardStore();
|
|
110
|
-
const stacks = matrix.suggestedStacks;
|
|
111
|
-
const groups = useMemo(() => groupStacks(stacks), [stacks]);
|
|
112
|
-
const rows = useMemo(() => buildStackRows(groups), [groups]);
|
|
113
|
-
const focusableIds = useMemo(() => buildFocusableIds(groups), [groups]);
|
|
114
|
-
const { focusedIndex } = useKeyboardNavigation(focusableIds.length, {
|
|
115
|
-
...onCancel !== void 0 && { onEscape: onCancel },
|
|
116
|
-
onEnter: (index) => handleSelect(focusableIds[index] ?? "scratch")
|
|
117
|
-
});
|
|
118
|
-
const focusedId = focusableIds[focusedIndex] ?? "scratch";
|
|
119
|
-
const { ref: listRef, measuredHeight: listHeight } = useMeasuredHeight();
|
|
120
|
-
const focusedVisualRow = useMemo(
|
|
121
|
-
() => rows.findIndex((row) => isRowFocused(row, focusedId)),
|
|
122
|
-
[rows, focusedId]
|
|
123
|
-
);
|
|
124
|
-
const { scrollEnabled, scrollTop } = useRowScroll({
|
|
125
|
-
focusedIndex: focusedVisualRow,
|
|
126
|
-
itemCount: rows.length,
|
|
127
|
-
availableHeight: listHeight
|
|
128
|
-
});
|
|
129
|
-
function applyStack(stack) {
|
|
130
|
-
selectStack(stack.id);
|
|
131
|
-
setStackAction("customize");
|
|
132
|
-
const stackAgents = typedKeys(stack.skills);
|
|
133
|
-
preselectAgentsFromStack(stackAgents);
|
|
134
|
-
const globalPreselections = useWizardStore.getState().globalPreselections;
|
|
135
|
-
const globalIds = globalPreselections?.map((s) => s.id) ?? [];
|
|
136
|
-
const mergedIds = [.../* @__PURE__ */ new Set([...stack.allSkillIds, ...globalIds])];
|
|
137
|
-
showWarningsAsToast(() => populateFromSkillIds(mergedIds, globalPreselections ?? void 0));
|
|
138
|
-
setApproach("stack");
|
|
139
|
-
setStep("domains");
|
|
140
|
-
}
|
|
141
|
-
function handleSelect(selectedId) {
|
|
142
|
-
if (selectedId === "scratch") {
|
|
143
|
-
showWarningsAsToast(startFromScratch);
|
|
144
|
-
setStep("domains");
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
const focusedStack = stacks.find((s) => s.id === selectedId);
|
|
148
|
-
if (focusedStack) applyStack(focusedStack);
|
|
149
|
-
}
|
|
150
|
-
return /* @__PURE__ */ jsx(Box, { ref: listRef, flexDirection: "column", flexGrow: 1, flexBasis: 0, children: /* @__PURE__ */ jsx(
|
|
151
|
-
Box,
|
|
152
|
-
{
|
|
153
|
-
flexDirection: "column",
|
|
154
|
-
flexGrow: 1,
|
|
155
|
-
...scrollEnabled && { overflow: "hidden" },
|
|
156
|
-
children: /* @__PURE__ */ jsx(
|
|
157
|
-
Box,
|
|
158
|
-
{
|
|
159
|
-
flexDirection: "column",
|
|
160
|
-
marginTop: scrollTop > 0 ? -scrollTop : 0,
|
|
161
|
-
...scrollEnabled && { flexShrink: 0 },
|
|
162
|
-
children: rows.map((row, index) => {
|
|
163
|
-
switch (row.type) {
|
|
164
|
-
case "spacer":
|
|
165
|
-
return /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { children: " " }) }, `spacer-${index}`);
|
|
166
|
-
case "header":
|
|
167
|
-
return /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, bold: true, children: [
|
|
168
|
-
" ",
|
|
169
|
-
row.label
|
|
170
|
-
] }) }, `header-${row.label}`);
|
|
171
|
-
case "stack":
|
|
172
|
-
return /* @__PURE__ */ jsx(
|
|
173
|
-
StackRow,
|
|
174
|
-
{
|
|
175
|
-
item: row.item,
|
|
176
|
-
isFocused: row.item.id === focusedId
|
|
177
|
-
},
|
|
178
|
-
row.item.id
|
|
179
|
-
);
|
|
180
|
-
case "scratch":
|
|
181
|
-
return /* @__PURE__ */ jsx(ScratchRow, { isFocused: focusedId === "scratch" }, "scratch");
|
|
182
|
-
default: {
|
|
183
|
-
const _exhaustive = row;
|
|
184
|
-
return _exhaustive;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
})
|
|
188
|
-
}
|
|
189
|
-
)
|
|
190
|
-
}
|
|
191
|
-
) });
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
export {
|
|
195
|
-
StackSelection
|
|
196
|
-
};
|
|
197
|
-
//# sourceMappingURL=chunk-GRL73YPF.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/components/wizard/stack-selection.tsx"],"sourcesContent":["import { groupBy } from \"remeda\";\nimport { useKeyboardNavigation } from \"../hooks/use-keyboard-navigation.js\";\nimport { Box, Text } from \"ink\";\nimport React, { useMemo } from \"react\";\nimport { CLI_COLORS, UI_SYMBOLS } from \"../../consts.js\";\nimport { matrix } from \"../../lib/matrix/matrix-provider.js\";\nimport { showWarningsAsToast, useWizardStore } from \"../../stores/wizard-store.js\";\nimport { useMeasuredHeight } from \"../hooks/use-measured-height.js\";\nimport { useRowScroll } from \"../hooks/use-row-scroll.js\";\n\nimport type { AgentName, ResolvedStack } from \"../../types/index.js\";\nimport { typedKeys } from \"../../utils/typed-object.js\";\n\ntype StackItem = Pick<ResolvedStack, \"id\" | \"name\" | \"description\">;\ntype StackGroup = { label: string; items: StackItem[] };\n/** A focusable row id: a stack id, or the \"scratch\" sentinel for the \"Start from scratch\" row. */\ntype FocusId = string;\n\nconst OTHER_FRAMEWORKS_LABEL = \"Other Frameworks\";\nconst GROUP_ORDER: string[] = [\"React\", \"CLI\"];\nconst SCRATCH_LABEL = \"Start from scratch\";\nconst SCRATCH_DESCRIPTION = \"Select domains and skills manually\";\n\ntype GroupableStack = Pick<ResolvedStack, \"id\" | \"name\" | \"description\" | \"group\">;\n\nfunction toStackItem(stack: GroupableStack): StackItem {\n return { id: stack.id, name: stack.name, description: stack.description };\n}\n\n/** GROUP_ORDER labels first (in order), then unknown labels alphabetically. */\nfunction compareGroupLabels(a: string, b: string): number {\n const ai = GROUP_ORDER.indexOf(a);\n const bi = GROUP_ORDER.indexOf(b);\n if (ai !== -1 && bi !== -1) return ai - bi;\n if (ai !== -1) return -1;\n if (bi !== -1) return 1;\n return a.localeCompare(b);\n}\n\nfunction groupStacks(stacks: GroupableStack[]): StackGroup[] {\n // `|| undefined` keeps an empty-string group ungrouped; groupBy drops undefined keys.\n const byLabel = groupBy(stacks, (stack) => stack.group || undefined);\n const ungrouped = stacks.filter((stack) => !stack.group).map(toStackItem);\n\n // No explicit groups — flat list, no headers\n const labelled = Object.entries(byLabel).sort(([a], [b]) => compareGroupLabels(a, b));\n if (labelled.length === 0) {\n return [{ label: \"\", items: ungrouped }];\n }\n\n const groups = labelled.map(([label, stacksInGroup]) => ({\n label,\n items: stacksInGroup.map(toStackItem),\n }));\n return ungrouped.length > 0\n ? [...groups, { label: OTHER_FRAMEWORKS_LABEL, items: ungrouped }]\n : groups;\n}\n\nfunction buildFocusableIds(groups: StackGroup[]): FocusId[] {\n return [...groups.flatMap((g) => g.items.map((i) => i.id)), \"scratch\"];\n}\n\ntype StackListRow =\n | { type: \"header\"; label: string }\n | { type: \"spacer\" }\n | { type: \"stack\"; item: StackItem }\n | { type: \"scratch\" };\n\n/** One row per rendered line — headers, spacers, stack items, then the scratch row. */\nfunction buildStackRows(groups: StackGroup[]): StackListRow[] {\n const groupRows = groups.flatMap((group, groupIndex): StackListRow[] => [\n ...(groupIndex > 0 ? [{ type: \"spacer\" as const }] : []),\n ...(group.label ? [{ type: \"header\" as const, label: group.label }] : []),\n ...group.items.map((item): StackListRow => ({ type: \"stack\", item })),\n ]);\n return [...groupRows, { type: \"spacer\" }, { type: \"scratch\" }];\n}\n\nfunction isRowFocused(row: StackListRow, focusedId: FocusId): boolean {\n if (row.type === \"stack\") return row.item.id === focusedId;\n return row.type === \"scratch\" && focusedId === \"scratch\";\n}\n\nconst StackRow: React.FC<{ item: StackItem; isFocused: boolean }> = ({ item, isFocused }) => {\n const pointer = isFocused ? UI_SYMBOLS.CHEVRON : UI_SYMBOLS.CHEVRON_SPACER;\n return (\n <Box flexShrink={0}>\n <Text>\n <Text {...(isFocused && { color: CLI_COLORS.PRIMARY })}>{pointer}</Text>\n <Text {...(isFocused && { color: CLI_COLORS.PRIMARY })} bold={isFocused}>\n {\" \"}\n {item.name}\n </Text>\n <Text dimColor>\n {\" \"}\n {item.description}\n </Text>\n </Text>\n </Box>\n );\n};\n\nconst ScratchRow: React.FC<{ isFocused: boolean }> = ({ isFocused }) => {\n const pointer = isFocused ? UI_SYMBOLS.CHEVRON : UI_SYMBOLS.CHEVRON_SPACER;\n return (\n <Box flexShrink={0}>\n <Text>\n <Text {...(isFocused && { color: CLI_COLORS.PRIMARY })}>{pointer}</Text>\n <Text {...(isFocused && { color: CLI_COLORS.PRIMARY })} bold={isFocused}>\n {\" \"}\n {SCRATCH_LABEL}\n </Text>\n <Text dimColor>\n {\" \"}\n {SCRATCH_DESCRIPTION}\n </Text>\n </Text>\n </Box>\n );\n};\n\nexport type StackSelectionProps = {\n onCancel?: (() => void) | undefined;\n};\n\nexport const StackSelection: React.FC<StackSelectionProps> = ({ onCancel }) => {\n const {\n selectStack,\n setApproach,\n setStackAction,\n populateFromSkillIds,\n preselectAgentsFromStack,\n startFromScratch,\n setStep,\n } = useWizardStore();\n\n const stacks = matrix.suggestedStacks;\n const groups = useMemo(() => groupStacks(stacks), [stacks]);\n const rows = useMemo(() => buildStackRows(groups), [groups]);\n const focusableIds = useMemo(() => buildFocusableIds(groups), [groups]);\n\n const { focusedIndex } = useKeyboardNavigation(focusableIds.length, {\n ...(onCancel !== undefined && { onEscape: onCancel }),\n onEnter: (index) => handleSelect(focusableIds[index] ?? \"scratch\"),\n });\n const focusedId: FocusId = focusableIds[focusedIndex] ?? \"scratch\";\n const { ref: listRef, measuredHeight: listHeight } = useMeasuredHeight();\n\n const focusedVisualRow = useMemo(\n () => rows.findIndex((row) => isRowFocused(row, focusedId)),\n [rows, focusedId],\n );\n\n const { scrollEnabled, scrollTop } = useRowScroll({\n focusedIndex: focusedVisualRow,\n itemCount: rows.length,\n availableHeight: listHeight,\n });\n\n // The stack's own skills merged with the global preselections, and its agent\n // keys merged with the global agent preselections.\n //\n // The merge is the one population that runs while Ink owns the terminal: the global\n // preselections come from the global config, which can name a skill the loaded source does\n // not carry, so it warns from under a painted frame. `showWarningsAsToast` is what keeps that\n // off a stderr the next repaint would scroll away.\n function applyStack(stack: ResolvedStack): void {\n selectStack(stack.id);\n setStackAction(\"customize\");\n\n const stackAgents = typedKeys<AgentName>(stack.skills);\n preselectAgentsFromStack(stackAgents);\n\n const globalPreselections = useWizardStore.getState().globalPreselections;\n const globalIds = globalPreselections?.map((s) => s.id) ?? [];\n const mergedIds = [...new Set([...stack.allSkillIds, ...globalIds])];\n showWarningsAsToast(() => populateFromSkillIds(mergedIds, globalPreselections ?? undefined));\n\n setApproach(\"stack\");\n setStep(\"domains\");\n }\n\n function handleSelect(selectedId: FocusId): void {\n if (selectedId === \"scratch\") {\n // Same population, same frame: the scratch row applies the global preselections too.\n showWarningsAsToast(startFromScratch);\n setStep(\"domains\");\n return;\n }\n\n const focusedStack = stacks.find((s) => s.id === selectedId);\n if (focusedStack) applyStack(focusedStack);\n }\n\n return (\n <Box ref={listRef} flexDirection=\"column\" flexGrow={1} flexBasis={0}>\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n {...(scrollEnabled && { overflow: \"hidden\" as const })}\n >\n <Box\n flexDirection=\"column\"\n marginTop={scrollTop > 0 ? -scrollTop : 0}\n {...(scrollEnabled && { flexShrink: 0 })}\n >\n {rows.map((row, index) => {\n switch (row.type) {\n case \"spacer\":\n return (\n <Box key={`spacer-${index}`} flexShrink={0}>\n <Text> </Text>\n </Box>\n );\n case \"header\":\n return (\n <Box key={`header-${row.label}`} flexShrink={0}>\n <Text dimColor bold>\n {\" \"}\n {row.label}\n </Text>\n </Box>\n );\n case \"stack\":\n return (\n <StackRow\n key={row.item.id}\n item={row.item}\n isFocused={row.item.id === focusedId}\n />\n );\n case \"scratch\":\n return <ScratchRow key=\"scratch\" isFocused={focusedId === \"scratch\"} />;\n default: {\n const _exhaustive: never = row;\n return _exhaustive;\n }\n }\n })}\n </Box>\n </Box>\n </Box>\n );\n};\n"],"mappings":"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","names":[]}
|