@aragon-agent/cli 0.6.34 → 0.6.36
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 +21 -0
- package/README.md +173 -7
- package/dist/agent/agent-mode.d.ts +20 -4
- package/dist/agent/agent-mode.js +20 -4
- package/dist/agent/controller.d.ts +67 -3
- package/dist/agent/controller.js +106 -5
- package/dist/agent/headless.js +31 -0
- package/dist/agent/kit-apply.d.ts +56 -0
- package/dist/agent/kit-apply.js +209 -0
- package/dist/agent/model-profile-settings.d.ts +28 -0
- package/dist/agent/model-profile-settings.js +142 -29
- package/dist/agent/reducer.d.ts +13 -2
- package/dist/agent/reducer.js +1 -0
- package/dist/cli.js +12 -0
- package/dist/commands/agents-command.d.ts +15 -0
- package/dist/commands/agents-command.js +27 -0
- package/dist/commands/builtins.js +135 -4
- package/dist/commands/kit-command.d.ts +20 -0
- package/dist/commands/kit-command.js +131 -0
- package/dist/commands/perf.d.ts +11 -0
- package/dist/commands/perf.js +2 -1
- package/dist/commands/registry.d.ts +14 -0
- package/dist/config/app-paths.d.ts +15 -0
- package/dist/config/app-paths.js +33 -2
- package/dist/config/env.d.ts +4 -1
- package/dist/config/env.js +28 -2
- package/dist/config/kit-resolution.d.ts +93 -0
- package/dist/config/kit-resolution.js +226 -0
- package/dist/config/load.d.ts +10 -0
- package/dist/config/load.js +8 -1
- package/dist/config/model-kits.d.ts +224 -0
- package/dist/config/model-kits.js +302 -0
- package/dist/config/model-profile-store.d.ts +25 -0
- package/dist/config/model-profiles.d.ts +41 -3
- package/dist/config/model-profiles.js +46 -5
- package/dist/config/schema.d.ts +84 -0
- package/dist/config/schema.js +39 -0
- package/dist/config/store.js +12 -1
- package/dist/config/ui-state.d.ts +18 -0
- package/dist/config/ui-state.js +9 -0
- package/dist/exec/events.d.ts +25 -0
- package/dist/exec/events.js +4 -0
- package/dist/exec/index.js +16 -1
- package/dist/exec/runner.js +10 -0
- package/dist/input/keymap.js +18 -4
- package/dist/proc/limits.d.ts +16 -0
- package/dist/proc/limits.js +16 -0
- package/dist/proc/supervisor.d.ts +20 -1
- package/dist/proc/supervisor.js +42 -14
- package/dist/prompts/command.d.ts +34 -0
- package/dist/prompts/command.js +237 -0
- package/dist/prompts/copy.d.ts +89 -0
- package/dist/prompts/copy.js +131 -0
- package/dist/prompts/fill.d.ts +51 -0
- package/dist/prompts/fill.js +46 -0
- package/dist/prompts/limits.d.ts +53 -0
- package/dist/prompts/limits.js +53 -0
- package/dist/prompts/normalize.d.ts +53 -0
- package/dist/prompts/normalize.js +190 -0
- package/dist/prompts/resolve.d.ts +31 -0
- package/dist/prompts/resolve.js +60 -0
- package/dist/prompts/search.d.ts +58 -0
- package/dist/prompts/search.js +146 -0
- package/dist/prompts/store.d.ts +86 -0
- package/dist/prompts/store.js +453 -0
- package/dist/prompts/types.d.ts +204 -0
- package/dist/prompts/types.js +13 -0
- package/dist/session/checkpoint.d.ts +8 -1
- package/dist/session/checkpoint.js +6 -0
- package/dist/session/persist.d.ts +19 -1
- package/dist/session/persist.js +13 -1
- package/dist/session/startup-session.d.ts +7 -2
- package/dist/session/startup-session.js +5 -2
- package/dist/session/store.js +3 -0
- package/dist/session/validate-session.js +64 -1
- package/dist/team/limits.d.ts +25 -0
- package/dist/team/limits.js +26 -0
- package/dist/team/runtime.js +27 -2
- package/dist/team/settled.d.ts +57 -0
- package/dist/team/settled.js +87 -0
- package/dist/team/subagent.js +48 -2
- package/dist/team/timeline.d.ts +74 -0
- package/dist/team/timeline.js +101 -0
- package/dist/team/types.d.ts +24 -1
- package/dist/todo/acceptance.d.ts +120 -0
- package/dist/todo/acceptance.js +399 -0
- package/dist/todo/follow-through.d.ts +48 -23
- package/dist/todo/follow-through.js +110 -44
- package/dist/todo/limits.d.ts +62 -1
- package/dist/todo/limits.js +62 -1
- package/dist/todo/panel-rows.d.ts +29 -39
- package/dist/todo/panel-rows.js +37 -83
- package/dist/todo/plan-sections.d.ts +60 -0
- package/dist/todo/plan-sections.js +108 -0
- package/dist/todo/prompt.d.ts +17 -12
- package/dist/todo/prompt.js +59 -40
- package/dist/todo/row-window.d.ts +51 -0
- package/dist/todo/row-window.js +107 -0
- package/dist/todo/store.d.ts +139 -31
- package/dist/todo/store.js +271 -73
- package/dist/todo/todo-tool.d.ts +33 -8
- package/dist/todo/todo-tool.js +186 -30
- package/dist/todo/types.d.ts +58 -0
- package/dist/ui/App.js +414 -54
- package/dist/ui/Composer.d.ts +6 -2
- package/dist/ui/Composer.js +2 -2
- package/dist/ui/Header.d.ts +17 -1
- package/dist/ui/Header.js +8 -2
- package/dist/ui/PromptInput.d.ts +21 -1
- package/dist/ui/PromptInput.js +22 -2
- package/dist/ui/ScrollbackShell.d.ts +22 -7
- package/dist/ui/ScrollbackShell.js +8 -1
- package/dist/ui/StatusBar.d.ts +18 -0
- package/dist/ui/StatusBar.js +11 -3
- package/dist/ui/TeamPanel.d.ts +35 -41
- package/dist/ui/TeamPanel.js +53 -163
- package/dist/ui/TodoPanel.d.ts +17 -14
- package/dist/ui/TodoPanel.js +146 -38
- package/dist/ui/Transcript.js +23 -3
- package/dist/ui/composer-input.d.ts +10 -0
- package/dist/ui/composer-input.js +57 -24
- package/dist/ui/entries/TeamCard.d.ts +18 -2
- package/dist/ui/entries/TeamCard.js +47 -13
- package/dist/ui/entries/TodoCard.d.ts +26 -11
- package/dist/ui/entries/TodoCard.js +56 -15
- package/dist/ui/glyphs.d.ts +19 -0
- package/dist/ui/glyphs.js +4 -0
- package/dist/ui/layout/agents-board.d.ts +102 -0
- package/dist/ui/layout/agents-board.js +389 -0
- package/dist/ui/layout/cells.d.ts +61 -0
- package/dist/ui/layout/cells.js +156 -0
- package/dist/ui/layout/header-hints.d.ts +23 -3
- package/dist/ui/layout/header-hints.js +73 -7
- package/dist/ui/layout/kit-chip.d.ts +50 -0
- package/dist/ui/layout/kit-chip.js +81 -0
- package/dist/ui/layout/status-detail-layout.js +9 -0
- package/dist/ui/layout/status-layout.d.ts +13 -0
- package/dist/ui/layout/team-row.d.ts +139 -0
- package/dist/ui/layout/team-row.js +246 -0
- package/dist/ui/layout/todo-layout.d.ts +38 -0
- package/dist/ui/layout/todo-layout.js +75 -0
- package/dist/ui/layout/virtual-window.js +32 -3
- package/dist/ui/overlays/AgentsBoardOverlay.d.ts +57 -0
- package/dist/ui/overlays/AgentsBoardOverlay.js +183 -0
- package/dist/ui/overlays/HelpOverlay.js +24 -2
- package/dist/ui/overlays/KitEditor.d.ts +23 -0
- package/dist/ui/overlays/KitEditor.js +101 -0
- package/dist/ui/overlays/KitManager.d.ts +23 -0
- package/dist/ui/overlays/KitManager.js +104 -0
- package/dist/ui/overlays/KitPicker.d.ts +49 -0
- package/dist/ui/overlays/KitPicker.js +58 -0
- package/dist/ui/overlays/ModelProfilePicker.js +16 -6
- package/dist/ui/overlays/PromptEditorPage.d.ts +48 -0
- package/dist/ui/overlays/PromptEditorPage.js +227 -0
- package/dist/ui/overlays/PromptLibraryOverlay.d.ts +37 -0
- package/dist/ui/overlays/PromptLibraryOverlay.js +191 -0
- package/dist/ui/overlays/PromptPicker.d.ts +36 -0
- package/dist/ui/overlays/PromptPicker.js +129 -0
- package/dist/ui/overlays/PromptTextArea.d.ts +86 -0
- package/dist/ui/overlays/PromptTextArea.js +141 -0
- package/dist/ui/overlays/SettingsScreen.js +139 -16
- package/dist/ui/overlays/kit-picker-state.d.ts +87 -0
- package/dist/ui/overlays/kit-picker-state.js +136 -0
- package/dist/ui/overlays/kit-settings-state.d.ts +129 -0
- package/dist/ui/overlays/kit-settings-state.js +267 -0
- package/dist/ui/overlays/model-profile-state.d.ts +26 -3
- package/dist/ui/overlays/model-profile-state.js +59 -6
- package/dist/ui/overlays/prompt-library-state.d.ts +162 -0
- package/dist/ui/overlays/prompt-library-state.js +335 -0
- package/dist/ui/overlays/prompt-picker-state.d.ts +71 -0
- package/dist/ui/overlays/prompt-picker-state.js +98 -0
- package/dist/ui/scrollback/LiveTail.d.ts +2 -2
- package/dist/ui/scrollback/LiveTail.js +7 -2
- package/dist/ui/scrollback/band.js +14 -1
- package/dist/ui/scrollback/live-preview.js +10 -3
- package/dist/ui/scrollback/tail-window.d.ts +12 -0
- package/dist/ui/scrollback/tail-window.js +17 -2
- package/dist/ui/scrollback/use-scrollback-view.js +7 -0
- package/dist/ui/team-status.d.ts +166 -0
- package/dist/ui/team-status.js +252 -0
- package/dist/ui/transcript-text.js +13 -4
- package/dist/ui/use-startup-notices.d.ts +35 -1
- package/dist/ui/use-startup-notices.js +29 -2
- package/dist/ui/use-wheel-routing.js +10 -2
- package/package.json +2 -2
|
@@ -24,7 +24,10 @@ import { ModelProfileEditor } from './ModelProfileEditor.js';
|
|
|
24
24
|
import { ModelDiscoveryList } from './ModelDiscoveryList.js';
|
|
25
25
|
import { useModelProbe } from './use-model-probe.js';
|
|
26
26
|
import { canProbe, editorProbeTarget, visibleProbeViews } from './model-probe-view.js';
|
|
27
|
-
import { createModelProfileState, createCustomProfile, modelProfileReducer, profileUsers, draftTeam, draftSubagentProfileId, subagentModelSummary, subagentSelectedId } from './model-profile-state.js';
|
|
27
|
+
import { createModelProfileState, createCustomProfile, modelProfileReducer, profileUsers, draftTeam, draftSubagentProfileId, subagentModelSummary, subagentSelectedId, SUBAGENT_FAST_ROW_ID } from './model-profile-state.js';
|
|
28
|
+
import { KitEditor } from './KitEditor.js';
|
|
29
|
+
import { KitManager } from './KitManager.js';
|
|
30
|
+
import { heldSlots, kitManagerRows, kitPackRow, kitReducer } from './kit-settings-state.js';
|
|
28
31
|
/**
|
|
29
32
|
* THE ROOT PAGE'S ROW INDEXES, AS NAMES (subagent-model V-5).
|
|
30
33
|
*
|
|
@@ -32,12 +35,18 @@ import { createModelProfileState, createCustomProfile, modelProfileReducer, prof
|
|
|
32
35
|
* model row moves every one of them. Each site below now cites its constant,
|
|
33
36
|
* so adding a row later is a one-line change instead of a silent regression
|
|
34
37
|
* that focuses an error message on the wrong field.
|
|
38
|
+
*
|
|
39
|
+
* DERIVED FROM ONE LIST (agent-model-kits §4.5), because the kit row is the
|
|
40
|
+
* fifth of these and the "five offsets agreed by accident" defect does not need
|
|
41
|
+
* a sequel. Order here IS the render order.
|
|
35
42
|
*/
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const
|
|
43
|
+
const ROOT_ROWS = ['main', 'fast', 'subagent', 'kit', 'manage'];
|
|
44
|
+
const ROOT_MAIN = ROOT_ROWS.indexOf('main');
|
|
45
|
+
const ROOT_FAST = ROOT_ROWS.indexOf('fast');
|
|
46
|
+
const ROOT_SUBAGENT = ROOT_ROWS.indexOf('subagent');
|
|
47
|
+
const ROOT_KIT = ROOT_ROWS.indexOf('kit');
|
|
48
|
+
const ROOT_MANAGE = ROOT_ROWS.indexOf('manage');
|
|
49
|
+
const ROOT_FIRST_FIELD = ROOT_ROWS.length;
|
|
41
50
|
/** Stand-in target while no editor exists; no probe row is rendered then. */
|
|
42
51
|
const NO_PROFILE_TARGET = { provider: '', model: '', baseUrl: null,
|
|
43
52
|
apiKey: null };
|
|
@@ -523,8 +532,23 @@ function saveError(result) {
|
|
|
523
532
|
};
|
|
524
533
|
return errors[result.code ?? ''] ?? 'Could not save. Review settings and retry.';
|
|
525
534
|
}
|
|
535
|
+
function isKitAction(action) {
|
|
536
|
+
return action.type.startsWith('kit-');
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* ONE REDUCER FOR THE WHOLE SCREEN, TWO OWNERS INSIDE IT (agent-model-kits §4.5).
|
|
540
|
+
*
|
|
541
|
+
* The kit pages need their own data mutations (create, duplicate, delete, apply)
|
|
542
|
+
* but must not introduce a second state object: `Save`, `Esc` and the dirty
|
|
543
|
+
* badge are shared, and a second store is how a settings screen starts
|
|
544
|
+
* disagreeing with itself. `kitReducer` returns the SAME state shape, so the
|
|
545
|
+
* split is invisible from the outside.
|
|
546
|
+
*/
|
|
547
|
+
function settingsReducer(state, action) {
|
|
548
|
+
return isKitAction(action) ? kitReducer(state, action) : modelProfileReducer(state, action);
|
|
549
|
+
}
|
|
526
550
|
function useProfileSettingsState(props) {
|
|
527
|
-
const [state, dispatch] = useReducer(
|
|
551
|
+
const [state, dispatch] = useReducer(settingsReducer, props.draft, createModelProfileState);
|
|
528
552
|
const [initial, setInitial] = useState(() => profileSettingsValues(props.initial, props.draft));
|
|
529
553
|
const [values, setValues] = useState(initial);
|
|
530
554
|
const [index, setIndex] = useState(0);
|
|
@@ -559,12 +583,16 @@ function useProfileSettingsState(props) {
|
|
|
559
583
|
&& ['provider', 'model', 'baseUrl', 'contextWindow', 'apiKey'].includes(item.key)),
|
|
560
584
|
...FIELDS.filter((item) => library.fastId === null
|
|
561
585
|
&& ['fastModel', 'fastProvider'].includes(item.key)), ...PROFILE_FIELDS];
|
|
562
|
-
//
|
|
563
|
-
// the `fields` block -
|
|
564
|
-
|
|
586
|
+
// SEVEN FIXED ROWS now (Main, Fast, SUBAGENT, Kit pack, Manage, Save, Reload)
|
|
587
|
+
// around the `fields` block - derived from ROOT_ROWS so the count and the
|
|
588
|
+
// offsets cannot drift apart (see those constants).
|
|
589
|
+
const count = fields.length + ROOT_ROWS.length + 2;
|
|
565
590
|
const field = fields[index - ROOT_FIRST_FIELD];
|
|
566
591
|
const readError = state.draft.readError;
|
|
567
|
-
|
|
592
|
+
// THREE CONFIRMATIONS SHARE ONE PAGE, which is why the page name - not a
|
|
593
|
+
// boolean - is what the renderer and the input hook both branch on.
|
|
594
|
+
const confirming = state.page === 'delete-confirm' || state.page === 'discard-confirm'
|
|
595
|
+
|| state.page === 'kit-delete';
|
|
568
596
|
return { state, dispatch, initial, setInitial, values, setValues, index, setIndex,
|
|
569
597
|
error, setError, persisted, setPersisted, confirmIndex, setConfirmIndex,
|
|
570
598
|
reloadPending, setReloadPending, offset, library, glyphs, dirty, fields, count,
|
|
@@ -651,6 +679,11 @@ function activateRootSetting(props, view) {
|
|
|
651
679
|
// `draft.patch.team` rather than a `${role}Id` library key.
|
|
652
680
|
dispatch({ type: 'page', page: 'picker', role: 'subagent' });
|
|
653
681
|
}
|
|
682
|
+
else if (index === ROOT_KIT) {
|
|
683
|
+
// The fourth root row opens the manager, not a picker: kits are data the user
|
|
684
|
+
// owns here, and `ctrl+K` is where they are CONSUMED (agent-model-kits §4.5).
|
|
685
|
+
dispatch({ type: 'page', page: 'kits' });
|
|
686
|
+
}
|
|
654
687
|
else if (index === ROOT_MANAGE)
|
|
655
688
|
dispatch({ type: 'page', page: 'manager' });
|
|
656
689
|
else
|
|
@@ -717,6 +750,11 @@ function useSettingsConfirmationInput(props, view) {
|
|
|
717
750
|
}
|
|
718
751
|
if (!key.return)
|
|
719
752
|
return;
|
|
753
|
+
if (state.page === 'kit-delete') {
|
|
754
|
+
dispatch(confirmIndex === 1 ? { type: 'kit-confirm-delete' }
|
|
755
|
+
: { type: 'page', page: 'kits' });
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
720
758
|
if (state.page === 'delete-confirm') {
|
|
721
759
|
dispatch(confirmIndex === 1 ? { type: 'confirm-delete' }
|
|
722
760
|
: { type: 'page', page: 'manager' });
|
|
@@ -729,8 +767,26 @@ function useSettingsConfirmationInput(props, view) {
|
|
|
729
767
|
props.onClose?.();
|
|
730
768
|
}, { isActive: confirming });
|
|
731
769
|
}
|
|
770
|
+
/**
|
|
771
|
+
* The kit deletion confirmation (agent-model-kits D-9 / AC-30).
|
|
772
|
+
*
|
|
773
|
+
* `Cancel` IS THE DEFAULT FOCUS, like the profile confirmation next door: the
|
|
774
|
+
* `Enter` key that opened this page must not be the one that deletes. The second
|
|
775
|
+
* line names what the user loses - a kit, and with it the default pointer and any
|
|
776
|
+
* session binding that named it.
|
|
777
|
+
*/
|
|
778
|
+
function renderKitDeleteConfirmation(props, view) {
|
|
779
|
+
const { state, confirmIndex, glyphs } = view;
|
|
780
|
+
const kit = (state.draft.profiles?.kits ?? []).find((item) => item.id === state.kitDraft?.id);
|
|
781
|
+
const rows = ['Cancel', 'Delete'].map((label, at) => (_jsxs(Text, { wrap: "truncate", color: props.theme.primary, children: [confirmIndex === at ? `${glyphs.caret} ` : ' ', label] }, label)));
|
|
782
|
+
rows.push(_jsx(Text, { wrap: "truncate", color: props.theme.muted, children: `Deletes kit "${kit?.name ?? ''}". Its three slots stay as they are; only the preset goes.` }, "consequence"));
|
|
783
|
+
return _jsx(OverlayFrame, { ...props, title: `Delete kit ${kit?.name ?? ''}?`, hint: "Enter choose | Esc continue", rows: rows, scrollOffset: confirmIndex });
|
|
784
|
+
}
|
|
732
785
|
function renderSettingsConfirmation(props, view) {
|
|
733
786
|
const { state, library, confirmIndex, glyphs } = view;
|
|
787
|
+
const deletingKit = state.page === 'kit-delete';
|
|
788
|
+
if (deletingKit)
|
|
789
|
+
return renderKitDeleteConfirmation(props, view);
|
|
734
790
|
const deleting = state.page === 'delete-confirm';
|
|
735
791
|
const name = library.entries.find((entry) => entry.id === state.deleteId)?.name ?? '';
|
|
736
792
|
// UNBIND-AND-DELETE (D-6): a referenced entry stays deletable in ONE flow,
|
|
@@ -780,6 +836,16 @@ function fastTierUnavailable(props, view) {
|
|
|
780
836
|
}
|
|
781
837
|
function renderProfileSubpage(props, view) {
|
|
782
838
|
const { state, library, dispatch, setConfirmIndex } = view;
|
|
839
|
+
// THE KIT PAGES (agent-model-kits §4.5). They are dispatched BEFORE the profile
|
|
840
|
+
// pages because `'kit-slot'` RENDERS a profile picker while belonging to the
|
|
841
|
+
// kit editor - the page name, not the component, decides where the user is.
|
|
842
|
+
if (state.page === 'kits')
|
|
843
|
+
return _jsx(KitManager, { ...props, rows: kitManagerRows(state), error: state.error, dispatch: dispatch, onBack: () => dispatch({ type: 'page', page: 'root' }) });
|
|
844
|
+
if (state.page === 'kit-edit' && state.kitDraft)
|
|
845
|
+
return _jsx(KitEditor, { ...props, draft: state.kitDraft, state: state, dispatch: dispatch });
|
|
846
|
+
if (state.page === 'kit-slot' && state.kitDraft) {
|
|
847
|
+
return renderKitSlotPicker(props, view, state.kitDraft);
|
|
848
|
+
}
|
|
783
849
|
if (state.page === 'editor' && state.editor)
|
|
784
850
|
return _jsx(ModelProfileEditor, { ...props, editor: state.editor, users: profileUsers(library, state.editor.original.id, draftSubagentProfileId(state.draft)), error: state.error, dispatch: dispatch, probeView: view.probeViews.test, probeBusy: view.probe.busy, probeTarget: view.probeTarget, onTest: () => startTest(view), onDiscover: () => startDiscovery(view, dispatch), onCancelProbe: view.probe.cancel });
|
|
785
851
|
// A DISCOVERY IS A PAGE, NOT A POPUP: the list is where the answer belongs, and
|
|
@@ -788,13 +854,50 @@ function renderProfileSubpage(props, view) {
|
|
|
788
854
|
return _jsx(ModelDiscoveryList, { ...props, provider: state.editor.provider, currentModel: state.editor.model, view: view.probeViews.discovery, busy: view.probe.discovery.phase === 'discovering', onChoose: (model) => dispatch({ type: 'choose-model', model }), onRetry: () => startDiscovery(view, dispatch), onBack: () => dispatch({ type: 'page', page: 'editor' }), onCancelProbe: view.probe.cancel });
|
|
789
855
|
// A NEW PROFILE SEEDED FROM THE MAIN CONNECTION while the subagent picker is
|
|
790
856
|
// open: 'subagent' is picker-only (6.2), so the seed role falls back to
|
|
791
|
-
// 'main' while `state.role` keeps driving the select that binds it.
|
|
792
|
-
|
|
857
|
+
// 'main' while `state.role` keeps driving the select that binds it. 'binding'
|
|
858
|
+
// is the kit slot's chooser and seeds the same way.
|
|
859
|
+
const createRole = state.role === 'subagent' || state.role === 'binding'
|
|
860
|
+
? 'main' : state.role;
|
|
793
861
|
if (state.page === 'picker' || state.page === 'manager')
|
|
794
862
|
return _jsx(ModelProfilePicker, { ...props, profiles: library, savedProfiles: state.draft.baseline.modelProfiles, role: state.role, customProfile: createCustomProfile(state.draft, createRole), manager: state.page === 'manager', error: state.error, selectedIdOverride: state.role === 'subagent' ? subagentSelectedId(state.draft) : undefined, subagentProfileId: draftSubagentProfileId(state.draft), fastTierOff: state.role === 'subagent' && fastTierUnavailable(props, view), onSelect: (id) => dispatch({ type: 'select', role: state.role, id }), onCreate: () => dispatch({ type: 'edit', profile: createCustomProfile(state.draft, createRole),
|
|
795
863
|
bindNew: state.page === 'picker' }), onEdit: (profile) => dispatch({ type: 'edit', profile }), onDuplicate: (id) => dispatch({ type: 'duplicate', id }), onDelete: (id) => { setConfirmIndex(0); dispatch({ type: 'delete', id }); }, onCancel: () => dispatch({ type: 'page', page: 'root' }) });
|
|
796
864
|
return null;
|
|
797
865
|
}
|
|
866
|
+
/** Which slot value the kit picker should mark `[Selected]`. */
|
|
867
|
+
function kitSlotSelection(kitDraft) {
|
|
868
|
+
if (kitDraft.slot === 'main')
|
|
869
|
+
return kitDraft.mainProfileId || null;
|
|
870
|
+
if (kitDraft.slot === 'fast')
|
|
871
|
+
return kitDraft.fastProfileId;
|
|
872
|
+
if (kitDraft.subagent.model === 'profile')
|
|
873
|
+
return kitDraft.subagent.modelProfileId;
|
|
874
|
+
return kitDraft.subagent.model === 'fast' ? SUBAGENT_FAST_ROW_ID : null;
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* The slot chooser: the SAME profile picker, in its `binding` role.
|
|
878
|
+
*
|
|
879
|
+
* A kit slot can only name a profile, so there is no `Current custom` row and no
|
|
880
|
+
* `Same as main` (those are the subagent slot's own three-state vocabulary). The
|
|
881
|
+
* subagent slot keeps the `subagent` role, which is why `Fast tier (off - falls
|
|
882
|
+
* back to main)` needs no new wording anywhere (RV-P2-6).
|
|
883
|
+
*/
|
|
884
|
+
function renderKitSlotPicker(props, view, kitDraft) {
|
|
885
|
+
const { state, library, dispatch } = view;
|
|
886
|
+
const role = kitDraft.slot === 'subagent' ? 'subagent' : 'binding';
|
|
887
|
+
return _jsx(ModelProfilePicker, { ...props, profiles: library, savedProfiles: state.draft.baseline.modelProfiles, role: role, customProfile: createCustomProfile(state.draft, 'main'), error: state.error, selectedIdOverride: kitSlotSelection(kitDraft), subagentProfileId: draftSubagentProfileId(state.draft), fastTierOff: kitDraft.slot === 'subagent' && fastTierUnavailable(props, view), onSelect: (id) => {
|
|
888
|
+
if (kitDraft.slot === 'main') {
|
|
889
|
+
dispatch({ type: 'kit-main', id });
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
if (kitDraft.slot === 'fast') {
|
|
893
|
+
dispatch({ type: 'kit-fast', id });
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
dispatch({ type: 'kit-subagent',
|
|
897
|
+
model: id === null ? 'main' : id === SUBAGENT_FAST_ROW_ID ? 'fast' : 'profile',
|
|
898
|
+
modelProfileId: id === null || id === SUBAGENT_FAST_ROW_ID ? null : id });
|
|
899
|
+
}, onCreate: () => dispatch({ type: 'edit', profile: createCustomProfile(state.draft, 'main') }), onEdit: (profile) => dispatch({ type: 'edit', profile }), onDuplicate: (id) => dispatch({ type: 'duplicate', id }), onDelete: (id) => dispatch({ type: 'delete', id }), onCancel: () => dispatch({ type: 'kit-cancel' }) });
|
|
900
|
+
}
|
|
798
901
|
function buildRootSettingsRows(props, view) {
|
|
799
902
|
const { library, fields, values, persisted, readError, index, glyphs, state } = view;
|
|
800
903
|
const name = (id) => {
|
|
@@ -823,9 +926,29 @@ function buildRootSettingsRows(props, view) {
|
|
|
823
926
|
modelProfileId: team.modelProfileId, mainConnection, fastConnection,
|
|
824
927
|
profiles: state.draft.profiles,
|
|
825
928
|
hasKey: (id) => (props.apiKeys[id] ?? '').length > 0 });
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
929
|
+
// HELD SLOTS SHOW THE KIT'S EFFECTIVE VALUES (RV-P0-2 / AC-38). Three rows on
|
|
930
|
+
// this page read the FILE's bindings while the header reads the live ones, so
|
|
931
|
+
// without this the screen says `Main profile Opus` over a header that says
|
|
932
|
+
// `haiku` - and the only available conclusion is that the app is broken.
|
|
933
|
+
// `Enter` on any of these rows writes an explicit choice, which releases that
|
|
934
|
+
// slot (§4.3), so what the user sees is what they are about to change.
|
|
935
|
+
const held = heldSlots(state);
|
|
936
|
+
const kitTag = held.kitName ? ` (kit ${held.kitName})` : '';
|
|
937
|
+
const mainValue = `${name(held.mainId ?? library.mainId)}${held.held.includes('main')
|
|
938
|
+
? kitTag : ''}`;
|
|
939
|
+
const fastValue = held.held.includes('fast')
|
|
940
|
+
? `${held.fastId ? name(held.fastId) : 'Off (this kit turns the tier off)'}${kitTag}`
|
|
941
|
+
: name(library.fastId);
|
|
942
|
+
const subagentValue = held.subagent
|
|
943
|
+
? `${subagentModelSummary({ mode: held.subagent.model,
|
|
944
|
+
modelProfileId: held.subagent.modelProfileId, mainConnection, fastConnection,
|
|
945
|
+
profiles: state.draft.profiles,
|
|
946
|
+
hasKey: (id) => (props.apiKeys[id] ?? '').length > 0 })}${kitTag}`
|
|
947
|
+
: subagentLine;
|
|
948
|
+
const lines = [`Main profile ${mainValue}`,
|
|
949
|
+
`Fast profile ${fastValue}`,
|
|
950
|
+
`Subagent model ${subagentValue}`,
|
|
951
|
+
`Kit pack ${kitPackRow(state)}`,
|
|
829
952
|
`Manage profiles ${library.entries.length} saved`,
|
|
830
953
|
...fields.map((item) => `${item.label.padEnd(18)}${item.key === 'apiKey'
|
|
831
954
|
? values.apiKey ? 'Configured (replacement)' : props.apiKeys[values.provider]
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `ctrl+K` list, as a pure view model (agent-model-kits §4.6 / D-10).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/ui/**` is inside `glyphs.test.ts::inScope`.
|
|
5
|
+
*
|
|
6
|
+
* WHY THE ROWS ARE COMPUTED HERE AND NOT IN THE COMPONENT: three surfaces print
|
|
7
|
+
* the same three connections (this list, the settings manager, `/kit list`).
|
|
8
|
+
* One function produces them, so the wording of "the fast tier is off" cannot
|
|
9
|
+
* differ between the key the user pressed and the command they typed.
|
|
10
|
+
*/
|
|
11
|
+
import type { CliConfig, TeamConfig } from '../../config/schema.js';
|
|
12
|
+
import type { ModelProfilesConfig } from '../../config/model-profiles.js';
|
|
13
|
+
import { type KitConnection, type KitSlot } from '../../config/model-kits.js';
|
|
14
|
+
import { type ActiveKit } from '../../config/kit-resolution.js';
|
|
15
|
+
export interface KitPickerRow {
|
|
16
|
+
/** `null` = `Current setup` (the release action). */
|
|
17
|
+
id: string | null;
|
|
18
|
+
/** The one-line label, markers included. */
|
|
19
|
+
label: string;
|
|
20
|
+
/** Machine-checkable markers, so tests never grep a rendered string. */
|
|
21
|
+
markers: {
|
|
22
|
+
inUse: boolean;
|
|
23
|
+
isDefault: boolean;
|
|
24
|
+
modified: boolean;
|
|
25
|
+
};
|
|
26
|
+
/** Non-empty when a referenced profile is gone. */
|
|
27
|
+
missing: KitSlot[];
|
|
28
|
+
}
|
|
29
|
+
export interface KitPickerInput {
|
|
30
|
+
library?: ModelProfilesConfig | undefined;
|
|
31
|
+
active: ActiveKit;
|
|
32
|
+
}
|
|
33
|
+
/** `provider:model` plus the endpoint clause shared by every surface. */
|
|
34
|
+
export declare function connectionText(connection: KitConnection): string;
|
|
35
|
+
/**
|
|
36
|
+
* Rows in a FIXED order: `Current setup` first, then the library's own order.
|
|
37
|
+
*
|
|
38
|
+
* The first row never moves (AC-24) - it is the only row that can always be
|
|
39
|
+
* chosen, and a list whose "off" entry wanders with the data is a list a user
|
|
40
|
+
* has to read every single time.
|
|
41
|
+
*/
|
|
42
|
+
export declare function kitRows(input: KitPickerInput): KitPickerRow[];
|
|
43
|
+
/**
|
|
44
|
+
* The three bindings `Current setup` describes.
|
|
45
|
+
*
|
|
46
|
+
* STRUCTURAL, NOT `CliConfig`: the caller hands in the PERSISTED config for this
|
|
47
|
+
* block (§4.6), because the live config no longer holds the file's bindings once
|
|
48
|
+
* a session kit is applied - it mirrors the kit (I-6). Both shapes satisfy this
|
|
49
|
+
* interface, so neither layer has to convert anything.
|
|
50
|
+
*/
|
|
51
|
+
export interface KitConnectionsSource {
|
|
52
|
+
provider: string;
|
|
53
|
+
model: string;
|
|
54
|
+
team?: {
|
|
55
|
+
model: TeamConfig['model'];
|
|
56
|
+
modelProfileId?: string | null;
|
|
57
|
+
} | undefined;
|
|
58
|
+
fast: {
|
|
59
|
+
enabled: boolean;
|
|
60
|
+
provider: string;
|
|
61
|
+
model: string;
|
|
62
|
+
};
|
|
63
|
+
modelProfiles?: ModelProfilesConfig | undefined;
|
|
64
|
+
}
|
|
65
|
+
/** The three lines under the focused row (§4.6). */
|
|
66
|
+
export declare function kitDetail(input: {
|
|
67
|
+
row: KitPickerRow;
|
|
68
|
+
library?: ModelProfilesConfig | undefined;
|
|
69
|
+
config: CliConfig;
|
|
70
|
+
/** The config file's copy of the bindings; see the `Current setup` note below. */
|
|
71
|
+
diskConfig?: KitConnectionsSource | undefined;
|
|
72
|
+
}): string[];
|
|
73
|
+
/**
|
|
74
|
+
* The footer. `busy` is a warning, never a reason to hide the list (§4.7).
|
|
75
|
+
*
|
|
76
|
+
* THE LAST CLAUSE IS D-7, VERBATIM: this overlay is a session-only surface, so it
|
|
77
|
+
* says where the persistence actually lives. Without it the natural reading of
|
|
78
|
+
* `Enter` is "make this my default", and D-7 exists to keep that action one
|
|
79
|
+
* deliberate trip to `/settings` instead of one keystroke next to a browse key.
|
|
80
|
+
* It is LAST so that a 40-column terminal clips the pointer, never the action.
|
|
81
|
+
*/
|
|
82
|
+
export declare function kitPickHint(input: {
|
|
83
|
+
busy: boolean;
|
|
84
|
+
hasKits: boolean;
|
|
85
|
+
}): string;
|
|
86
|
+
/** The one guidance row an empty library renders (AC-26). */
|
|
87
|
+
export declare const NO_KITS_HINT = "No kits yet. Create one in /settings (Settings > Kit pack).";
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `ctrl+K` list, as a pure view model (agent-model-kits §4.6 / D-10).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/ui/**` is inside `glyphs.test.ts::inScope`.
|
|
5
|
+
*
|
|
6
|
+
* WHY THE ROWS ARE COMPUTED HERE AND NOT IN THE COMPONENT: three surfaces print
|
|
7
|
+
* the same three connections (this list, the settings manager, `/kit list`).
|
|
8
|
+
* One function produces them, so the wording of "the fast tier is off" cannot
|
|
9
|
+
* differ between the key the user pressed and the command they typed.
|
|
10
|
+
*/
|
|
11
|
+
import { kitSlotConnections } from '../../config/model-kits.js';
|
|
12
|
+
import { CURRENT_SETUP_NAME } from '../../config/kit-resolution.js';
|
|
13
|
+
function duplicateNames(kits) {
|
|
14
|
+
const seen = new Set();
|
|
15
|
+
const repeated = new Set();
|
|
16
|
+
for (const kit of kits) {
|
|
17
|
+
if (seen.has(kit.name))
|
|
18
|
+
repeated.add(kit.name);
|
|
19
|
+
seen.add(kit.name);
|
|
20
|
+
}
|
|
21
|
+
return repeated;
|
|
22
|
+
}
|
|
23
|
+
/** `provider:model` plus the endpoint clause shared by every surface. */
|
|
24
|
+
export function connectionText(connection) {
|
|
25
|
+
const endpoint = connection.baseUrl ? hostOf(connection.baseUrl) : 'default URL';
|
|
26
|
+
return `${connection.provider}:${connection.model} ${endpoint}`;
|
|
27
|
+
}
|
|
28
|
+
function hostOf(baseUrl) {
|
|
29
|
+
try {
|
|
30
|
+
const url = new URL(baseUrl);
|
|
31
|
+
return url.username || url.password || url.search || url.hash ? 'Invalid URL' : url.host;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return 'Invalid URL';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Rows in a FIXED order: `Current setup` first, then the library's own order.
|
|
39
|
+
*
|
|
40
|
+
* The first row never moves (AC-24) - it is the only row that can always be
|
|
41
|
+
* chosen, and a list whose "off" entry wanders with the data is a list a user
|
|
42
|
+
* has to read every single time.
|
|
43
|
+
*/
|
|
44
|
+
export function kitRows(input) {
|
|
45
|
+
const kits = input.library?.kits ?? [];
|
|
46
|
+
const repeated = duplicateNames(kits);
|
|
47
|
+
const rows = [{
|
|
48
|
+
id: null,
|
|
49
|
+
label: `${input.active.source === 'none' ? '[In use] ' : ''}${CURRENT_SETUP_NAME}`,
|
|
50
|
+
markers: { inUse: input.active.source === 'none', isDefault: false, modified: false },
|
|
51
|
+
missing: [],
|
|
52
|
+
}];
|
|
53
|
+
for (const kit of kits) {
|
|
54
|
+
const inUse = input.active.source !== 'none' && input.active.id === kit.id;
|
|
55
|
+
const isDefault = (input.library?.defaultKitId ?? null) === kit.id;
|
|
56
|
+
const modified = inUse && input.active.modified;
|
|
57
|
+
const missing = inUse ? input.active.missingProfiles : [];
|
|
58
|
+
// A DUPLICATE NAME gets its id prefix, exactly as the profile picker does:
|
|
59
|
+
// two rows reading `Cheap` would make Enter a coin flip.
|
|
60
|
+
const identity = repeated.has(kit.name) ? `#${kit.id.slice(0, 8)} ` : '';
|
|
61
|
+
const markers = [inUse ? '[In use]' : '', isDefault ? '[Default]' : '']
|
|
62
|
+
.filter(Boolean).join(' ');
|
|
63
|
+
rows.push({
|
|
64
|
+
id: kit.id,
|
|
65
|
+
label: `${identity}${markers ? `${markers} ` : ''}${kit.name}${modified ? '~' : ''}`,
|
|
66
|
+
markers: { inUse, isDefault, modified },
|
|
67
|
+
missing,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return rows;
|
|
71
|
+
}
|
|
72
|
+
function subagentText(config) {
|
|
73
|
+
const mode = config.team?.model ?? 'main';
|
|
74
|
+
if (mode === 'main')
|
|
75
|
+
return 'same as main';
|
|
76
|
+
if (mode === 'fast')
|
|
77
|
+
return 'fast tier model';
|
|
78
|
+
const id = config.team?.modelProfileId ?? null;
|
|
79
|
+
const entry = id ? config.modelProfiles?.entries.find((item) => item.id === id) : undefined;
|
|
80
|
+
return entry ? `profile ${entry.name}` : 'Profile missing';
|
|
81
|
+
}
|
|
82
|
+
/** The three lines under the focused row (§4.6). */
|
|
83
|
+
export function kitDetail(input) {
|
|
84
|
+
const { row, library, config } = input;
|
|
85
|
+
const kit = row.id ? (library?.kits ?? []).find((item) => item.id === row.id) : undefined;
|
|
86
|
+
if (!kit) {
|
|
87
|
+
// `Current setup` describes the FILE's bindings - what the next process
|
|
88
|
+
// would run - because that is exactly what choosing it restores.
|
|
89
|
+
//
|
|
90
|
+
// THE LIVE CONFIG IS THE WRONG SOURCE WHILE A SESSION KIT IS HELD: it mirrors
|
|
91
|
+
// the kit (I-6), so this block would print the current values and thereby
|
|
92
|
+
// promise that releasing the kit changes nothing. The first row is the only
|
|
93
|
+
// row whose whole meaning is "what the file says", so it is the only one that
|
|
94
|
+
// has to be read from the file.
|
|
95
|
+
const file = input.diskConfig ?? config;
|
|
96
|
+
const fast = file.fast.enabled
|
|
97
|
+
? `${file.fast.provider || file.provider}:${file.fast.model || '(not set)'}`
|
|
98
|
+
: 'off';
|
|
99
|
+
return [`main ${file.provider}:${file.model}`,
|
|
100
|
+
`subagent ${subagentText(file)}`,
|
|
101
|
+
`fast ${fast}`];
|
|
102
|
+
}
|
|
103
|
+
const connections = kitSlotConnections(library, kit);
|
|
104
|
+
const mainLine = connections.main ? connectionText(connections.main) : 'Profile missing';
|
|
105
|
+
const fastLine = kit.fastProfileId === null ? 'off (this kit turns the tier off)'
|
|
106
|
+
: connections.fast ? `${connectionText(connections.fast)} tier on` : 'Profile missing';
|
|
107
|
+
// THE SUBAGENT LINE REUSES THE SLOT'S OWN THREE-STATE VOCABULARY (`same as main`
|
|
108
|
+
// / `fast tier` / a profile), so this block and the settings screen's subagent
|
|
109
|
+
// row cannot say different things about the same kit.
|
|
110
|
+
const subagentLine = kit.subagent.model === 'main' ? 'same as main'
|
|
111
|
+
: kit.subagent.model === 'fast'
|
|
112
|
+
? (connections.fast ? 'fast tier' : 'fast tier (off - falls back to main)')
|
|
113
|
+
: connections.subagent.name
|
|
114
|
+
? `profile ${connections.subagent.name} ${connections.subagent.provider}:${connections.subagent.model}` : 'Profile missing';
|
|
115
|
+
return [`main ${mainLine}`, `subagent ${subagentLine}`, `fast ${fastLine}`];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The footer. `busy` is a warning, never a reason to hide the list (§4.7).
|
|
119
|
+
*
|
|
120
|
+
* THE LAST CLAUSE IS D-7, VERBATIM: this overlay is a session-only surface, so it
|
|
121
|
+
* says where the persistence actually lives. Without it the natural reading of
|
|
122
|
+
* `Enter` is "make this my default", and D-7 exists to keep that action one
|
|
123
|
+
* deliberate trip to `/settings` instead of one keystroke next to a browse key.
|
|
124
|
+
* It is LAST so that a 40-column terminal clips the pointer, never the action.
|
|
125
|
+
*/
|
|
126
|
+
export function kitPickHint(input) {
|
|
127
|
+
if (!input.hasKits)
|
|
128
|
+
return 'Esc close | Create a kit in /settings';
|
|
129
|
+
if (input.busy) {
|
|
130
|
+
return 'Enter use for this session (blocked while running) | Esc close'
|
|
131
|
+
+ ' | Set a default in /settings';
|
|
132
|
+
}
|
|
133
|
+
return 'Enter use for this session | Esc close | Set a default in /settings';
|
|
134
|
+
}
|
|
135
|
+
/** The one guidance row an empty library renders (AC-26). */
|
|
136
|
+
export const NO_KITS_HINT = 'No kits yet. Create one in /settings (Settings > Kit pack).';
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The settings screen's kit pages: manager rows, the editor draft, and the ONE
|
|
3
|
+
* reducer that turns intents into draft mutations (agent-model-kits §4.5).
|
|
4
|
+
*
|
|
5
|
+
* ASCII ONLY - `src/ui/**` is inside `glyphs.test.ts::inScope`.
|
|
6
|
+
*
|
|
7
|
+
* TWO REDUCERS, ONE PAGE AXIS. `modelProfileReducer` owns the profile pages and
|
|
8
|
+
* `kitReducer` owns kit data; both return the same `ModelProfileState`, so the
|
|
9
|
+
* screen still has exactly one state object and one Save button. The alternative
|
|
10
|
+
* - a second state machine inside `SettingsScreen.tsx`, which is already over the
|
|
11
|
+
* 1000-line cap - is what this module exists to avoid.
|
|
12
|
+
*
|
|
13
|
+
* NOTHING HERE WRITES ANYTHING: every action mutates the transaction draft and
|
|
14
|
+
* sets `dirty`. `Save` stays the only writer (F-7/F-10).
|
|
15
|
+
*/
|
|
16
|
+
import type { KitSlot, AgentKit } from '../../config/model-kits.js';
|
|
17
|
+
import type { ModelProfilesConfig } from '../../config/model-profiles.js';
|
|
18
|
+
import type { SubagentModelMode } from '../../team/model.js';
|
|
19
|
+
import type { ModelProfileState } from './model-profile-state.js';
|
|
20
|
+
export interface KitDraft {
|
|
21
|
+
/** `null` while creating; the delete confirmation reuses this field as its id. */
|
|
22
|
+
id: string | null;
|
|
23
|
+
name: string;
|
|
24
|
+
mainProfileId: string;
|
|
25
|
+
/** `null` = this kit turns the fast tier off (D-8). */
|
|
26
|
+
fastProfileId: string | null;
|
|
27
|
+
subagent: {
|
|
28
|
+
model: SubagentModelMode;
|
|
29
|
+
modelProfileId: string | null;
|
|
30
|
+
};
|
|
31
|
+
/** Which slot the profile picker is choosing for; `null` on the editor page. */
|
|
32
|
+
slot: KitSlot | null;
|
|
33
|
+
error?: string;
|
|
34
|
+
/** The row the cursor jumps to when `error` is set (focus-lands-on-error). */
|
|
35
|
+
field?: KitSlot | 'name';
|
|
36
|
+
}
|
|
37
|
+
export type KitAction = {
|
|
38
|
+
type: 'kit-open';
|
|
39
|
+
id: string | null;
|
|
40
|
+
} | {
|
|
41
|
+
type: 'kit-name';
|
|
42
|
+
value: string;
|
|
43
|
+
} | {
|
|
44
|
+
type: 'kit-slot';
|
|
45
|
+
slot: KitSlot;
|
|
46
|
+
} | {
|
|
47
|
+
type: 'kit-main';
|
|
48
|
+
id: string | null;
|
|
49
|
+
} | {
|
|
50
|
+
type: 'kit-fast';
|
|
51
|
+
id: string | null;
|
|
52
|
+
} | {
|
|
53
|
+
type: 'kit-subagent';
|
|
54
|
+
model: SubagentModelMode;
|
|
55
|
+
modelProfileId: string | null;
|
|
56
|
+
} | {
|
|
57
|
+
type: 'kit-save';
|
|
58
|
+
} | {
|
|
59
|
+
type: 'kit-cancel';
|
|
60
|
+
} | {
|
|
61
|
+
type: 'kit-duplicate';
|
|
62
|
+
id: string;
|
|
63
|
+
} | {
|
|
64
|
+
type: 'kit-delete';
|
|
65
|
+
id: string;
|
|
66
|
+
} | {
|
|
67
|
+
type: 'kit-confirm-delete';
|
|
68
|
+
} | {
|
|
69
|
+
type: 'kit-apply';
|
|
70
|
+
id: string;
|
|
71
|
+
} | {
|
|
72
|
+
type: 'kit-default';
|
|
73
|
+
id: string;
|
|
74
|
+
};
|
|
75
|
+
/** The library the transaction would save, with a read error falling back to empty. */
|
|
76
|
+
export declare function draftLibrary(state: ModelProfileState): ModelProfilesConfig;
|
|
77
|
+
export declare function findKitInState(state: ModelProfileState, id: string | null): AgentKit | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Open the editor on an existing kit, or on a PREFILLED new one (§4.10).
|
|
80
|
+
*
|
|
81
|
+
* THE FIRST KIT IS NEVER A BLANK FORM (D-13): it starts from the three bindings
|
|
82
|
+
* this machine already runs, so "create a kit" is one rename and one Save. When
|
|
83
|
+
* no Main profile is bound the kit starts with an empty main slot and Save
|
|
84
|
+
* refuses - the picker's own `Create profile` action is where a profile is born,
|
|
85
|
+
* which keeps this module free of the profile-creating code path.
|
|
86
|
+
*/
|
|
87
|
+
export declare function openKitDraft(state: ModelProfileState, id: string | null): KitDraft;
|
|
88
|
+
/** Every kit-page intent, applied to the ONE draft. */
|
|
89
|
+
export declare function kitReducer(state: ModelProfileState, action: KitAction): ModelProfileState;
|
|
90
|
+
/** One manager row: the label with its markers, plus the three-slot summary. */
|
|
91
|
+
export interface KitManagerRow {
|
|
92
|
+
id: string;
|
|
93
|
+
label: string;
|
|
94
|
+
summary: string;
|
|
95
|
+
isDefault: boolean;
|
|
96
|
+
inUse: boolean;
|
|
97
|
+
}
|
|
98
|
+
/** Rows in library order, each with the markers the picker also uses (§4.5). */
|
|
99
|
+
export declare function kitManagerRows(state: ModelProfileState): KitManagerRow[];
|
|
100
|
+
/**
|
|
101
|
+
* The `Kit pack` root row's five states (§4.5 table, AC-27).
|
|
102
|
+
*
|
|
103
|
+
* READ FROM THE DRAFT, not from the live config: the row sits inside a
|
|
104
|
+
* transaction, and showing the saved state under a pending selection is how a
|
|
105
|
+
* settings screen lies to the user about what `Save` is going to do.
|
|
106
|
+
*/
|
|
107
|
+
export declare function kitPackRow(state: ModelProfileState): string;
|
|
108
|
+
/** Which of the three root rows must show the KIT's value, and under which name. */
|
|
109
|
+
export interface HeldSlots {
|
|
110
|
+
kitName: string | null;
|
|
111
|
+
/** The slots the session kit still owns; `mainId`/`fastId` are only meaningful
|
|
112
|
+
* for a slot in this list (`null` means "this kit turns the tier off"). */
|
|
113
|
+
held: KitSlot[];
|
|
114
|
+
mainId: string | null;
|
|
115
|
+
fastId: string | null;
|
|
116
|
+
subagent: {
|
|
117
|
+
model: SubagentModelMode;
|
|
118
|
+
modelProfileId: string | null;
|
|
119
|
+
} | null;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* The held slots' EFFECTIVE values (RV-P0-2).
|
|
123
|
+
*
|
|
124
|
+
* WITHOUT THIS the root page shows the file's bindings while the header shows the
|
|
125
|
+
* kit's, and the only conclusion available to the user is that one of them is
|
|
126
|
+
* broken. `Enter` on any of these rows writes an explicit choice, which releases
|
|
127
|
+
* that slot - so "what you see is what you change" stays true.
|
|
128
|
+
*/
|
|
129
|
+
export declare function heldSlots(state: ModelProfileState): HeldSlots;
|