maka-agent 0.2.0-dev.14.20260902 → 0.2.0-dev.16.20260903
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/dist/cli-core.js +0 -1
- package/dist/pi-transcript.js +48 -0
- package/dist/pi-tui-form-interaction.js +497 -0
- package/dist/pi-tui-pickers.js +256 -55
- package/dist/pi-tui-runner.js +215 -12
- package/dist/runtime-host-cli.js +17 -42
- package/dist/runtime-host-lifecycle-transaction.js +31 -13
- package/dist/runtime-host-managed-lifecycle-manager.js +1 -1
- package/dist/runtime-host-onboarding.js +3 -1
- package/dist/runtime-host-openrc-service.js +469 -0
- package/dist/runtime-host-run-command.js +6 -2
- package/dist/runtime-host-service-command.js +3 -3
- package/dist/runtime-host-service-management-command.js +43 -15
- package/dist/runtime-host-session-channel.js +3 -0
- package/dist/runtime-host-session-driver.js +21 -6
- package/dist/runtime-host-setup-command.js +30 -31
- package/dist/tui-context-refresh.js +103 -0
- package/dist/tui-copy-catalog.js +73 -0
- package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
- package/node_modules/@maka/core/dist/chat-model-choice.js +4 -0
- package/node_modules/@maka/core/dist/computer-use.js +27 -92
- package/node_modules/@maka/core/dist/interaction.js +577 -3
- package/node_modules/@maka/core/dist/llm-connections.js +4 -0
- package/node_modules/@maka/core/dist/local-memory.js +2 -2
- package/node_modules/@maka/core/dist/model-call-usage-projection.js +3 -0
- package/node_modules/@maka/core/dist/model-metadata.js +26 -7
- package/node_modules/@maka/core/dist/model-thinking.js +17 -0
- package/node_modules/@maka/core/dist/provider-registry.js +1 -0
- package/node_modules/@maka/core/dist/runtime-event.js +23 -1
- package/node_modules/@maka/core/dist/scheduled-task.js +4 -0
- package/node_modules/@maka/core/dist/session.js +95 -2
- package/node_modules/@maka/core/dist/text-sanitize.js +19 -0
- package/node_modules/@maka/core/dist/usage-ledger-merge.js +3 -0
- package/node_modules/@maka/core/dist/usage-record-schema.js +11 -5
- package/node_modules/@maka/core/dist/workhub-creation-intent.js +75 -9
- package/node_modules/@maka/core/dist/workhub-session-resolver.js +50 -0
- package/node_modules/@maka/core/package.json +2 -0
- package/node_modules/@maka/eval/dist/harbor-external-subject.js +2 -1
- package/node_modules/@maka/eval/dist/harness-executor.js +3 -2
- package/node_modules/@maka/eval/dist/install-preflight.js +39 -10
- package/node_modules/@maka/eval/dist/process-termination.js +83 -0
- package/node_modules/@maka/mcp/dist/sep-2243.js +3 -3
- package/node_modules/@maka/runtime/dist/agent-run.js +6 -3
- package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +332 -118
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction-contract.js +6 -1
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +171 -341
- package/node_modules/@maka/runtime/dist/bots/telegram-bridge.js +3 -26
- package/node_modules/@maka/runtime/dist/bundled-skill-catalog.generated.js +1 -1
- package/node_modules/@maka/runtime/dist/computer-use-codec.js +1 -141
- package/node_modules/@maka/runtime/dist/computer-use-tools.js +23 -105
- package/node_modules/@maka/runtime/dist/context-budget-policy.js +20 -26
- package/node_modules/@maka/runtime/dist/context-budget.js +18 -20
- package/node_modules/@maka/runtime/dist/conversation-copy.js +23 -19
- package/node_modules/@maka/runtime/dist/cua-frame-state.js +1 -69
- package/node_modules/@maka/runtime/dist/github-copilot-oauth-enrollment.js +267 -0
- package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +6 -9
- package/node_modules/@maka/runtime/dist/history-compact-summarizer.js +67 -23
- package/node_modules/@maka/runtime/dist/history-compact-summary-validation.js +11 -18
- package/node_modules/@maka/runtime/dist/history-compaction.js +66 -73
- package/node_modules/@maka/runtime/dist/interaction-authority.js +69 -0
- package/node_modules/@maka/runtime/dist/mcp-tools.js +13 -1
- package/node_modules/@maka/runtime/dist/memory-extraction.js +11 -11
- package/node_modules/@maka/runtime/dist/model-adapter.js +24 -6
- package/node_modules/@maka/runtime/dist/model-factory.js +14 -5
- package/node_modules/@maka/runtime/dist/oauth-provider-contracts.js +28 -1
- package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +7 -6
- package/node_modules/@maka/runtime/dist/opencode-session-header.js +29 -0
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +11 -1
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +12 -11
- package/node_modules/@maka/runtime/dist/runtime-read-model.js +51 -13
- package/node_modules/@maka/runtime/dist/scheduled-task-tools.js +3 -0
- package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +26 -0
- package/node_modules/@maka/runtime/dist/session-manager.js +1 -0
- package/node_modules/@maka/runtime/dist/session-projection-helpers.js +16 -1
- package/node_modules/@maka/runtime/dist/stream-graph-projection.js +6 -0
- package/node_modules/@maka/runtime/dist/stream-graph-read-model.js +5 -0
- package/node_modules/@maka/runtime/dist/stream-usage-fallback-fetch.js +74 -0
- package/node_modules/@maka/runtime/dist/subscription-credentials.js +51 -4
- package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +47 -3
- package/node_modules/@maka/runtime/dist/system-prompt/main-session-prompt.js +20 -1
- package/node_modules/@maka/runtime/dist/test-connection.js +18 -11
- package/node_modules/@maka/runtime/dist/tool-runtime.js +183 -0
- package/node_modules/@maka/runtime/package.json +1 -0
- package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +14 -0
- package/node_modules/@maka/runtime-host/dist/client/client-capability-channel.js +84 -1
- package/node_modules/@maka/runtime-host/dist/client/host-profile.js +68 -51
- package/node_modules/@maka/runtime-host/dist/client/index.js +1 -1
- package/node_modules/@maka/runtime-host/dist/client/owner-connection-code.js +8 -5
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +342 -36
- package/node_modules/@maka/runtime-host/dist/client/reconnect-lifecycle.js +60 -4
- package/node_modules/@maka/runtime-host/dist/peer-mesh/index.js +3 -3
- package/node_modules/@maka/runtime-host/dist/peer-mesh/limits.js +1 -1
- package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +48 -60
- package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +847 -431
- package/node_modules/@maka/runtime-host/dist/peer-mesh/owner.js +33 -74
- package/node_modules/@maka/runtime-host/dist/peer-mesh/store.js +82 -69
- package/node_modules/@maka/runtime-host/dist/peer-reachability/index.js +21 -0
- package/node_modules/@maka/runtime-host/dist/peer-reachability/model.js +202 -0
- package/node_modules/@maka/runtime-host/dist/peer-reachability/owner.js +119 -0
- package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +245 -0
- package/node_modules/@maka/runtime-host/dist/protocol/agent-graph.js +4 -1
- package/node_modules/@maka/runtime-host/dist/protocol/client-capability.js +68 -0
- package/node_modules/@maka/runtime-host/dist/protocol/connection-effects.js +15 -8
- package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +7 -23
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +47 -1
- package/node_modules/@maka/runtime-host/dist/protocol/oauth.js +25 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/peer-mesh.js +14 -31
- package/node_modules/@maka/runtime-host/dist/protocol/scheduled-task.js +19 -6
- package/node_modules/@maka/runtime-host/dist/protocol/session-collaboration.js +36 -1
- package/node_modules/@maka/runtime-host/dist/protocol/session-revision.js +11 -2
- package/node_modules/@maka/runtime-host/dist/protocol/usage-pricing.js +16 -2
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +51 -2
- package/node_modules/@maka/runtime-host/dist/server/access-authority.js +35 -2
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +1 -0
- package/node_modules/@maka/runtime-host/dist/server/client-capability-coordinator.js +12 -10
- package/node_modules/@maka/runtime-host/dist/server/client-capability-invocation-broker.js +163 -30
- package/node_modules/@maka/runtime-host/dist/server/connection-effect-coordinator.js +38 -14
- package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +45 -22
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +78 -20
- package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +4 -2
- package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +2 -1
- package/node_modules/@maka/runtime-host/dist/server/execution-service.js +49 -28
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +3 -6
- package/node_modules/@maka/runtime-host/dist/server/interaction-coordinator.js +130 -27
- package/node_modules/@maka/runtime-host/dist/server/interaction-projection.js +30 -1
- package/node_modules/@maka/runtime-host/dist/server/listener-set.js +2 -4
- package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +16 -3
- package/node_modules/@maka/runtime-host/dist/server/oauth-coordinator.js +66 -3
- package/node_modules/@maka/runtime-host/dist/server/oauth-execution-authority.js +20 -3
- package/node_modules/@maka/runtime-host/dist/server/peer-listener.js +8 -21
- package/node_modules/@maka/runtime-host/dist/server/peer-mesh-authority.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +6 -3
- package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +72 -12
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +48 -18
- package/node_modules/@maka/runtime-host/dist/server/session-turn-access-request-coordinator.js +43 -26
- package/node_modules/@maka/runtime-host/dist/server/usage-pricing-coordinator.js +15 -1
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +229 -4
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +146 -8
- package/node_modules/@maka/runtime-host/dist/transport/peer-native.js +32 -6
- package/node_modules/@maka/runtime-host/package.json +1 -0
- package/node_modules/@maka/storage/dist/agent-run-store.js +18 -5
- package/node_modules/@maka/storage/dist/codex-session-adapter.js +14 -0
- package/node_modules/@maka/storage/dist/execution-stores.js +5 -0
- package/node_modules/@maka/storage/dist/interaction-store.js +13 -1
- package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +9 -3
- package/node_modules/@maka/storage/dist/runtime-policy/coordinator.js +49 -19
- package/node_modules/@maka/storage/dist/runtime-policy/oauth-login-receipt-document.js +3 -1
- package/node_modules/@maka/storage/dist/runtime-policy/onboarding-transaction.js +13 -5
- package/node_modules/@maka/storage/dist/session-copy-cleanup.js +4 -2
- package/node_modules/@maka/storage/dist/session-store.js +39 -6
- package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +16 -9
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-schema.js +30 -3
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +117 -0
- package/node_modules/@maka/storage/dist/sqlite-usage-store.js +29 -6
- package/node_modules/@maka/storage/dist/usage-stores.js +3 -1
- package/package.json +1 -1
package/dist/pi-tui-pickers.js
CHANGED
|
@@ -16,9 +16,10 @@
|
|
|
16
16
|
* specific language governing permissions and limitations
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
|
-
import { CombinedAutocompleteProvider, Editor, Key, SelectList, decodeKittyPrintable, isKeyRepeat, matchesKey, truncateToWidth, visibleWidth, } from '@earendil-works/pi-tui';
|
|
19
|
+
import { CombinedAutocompleteProvider, Editor, Key, SelectList, decodeKittyPrintable, isKeyRepeat, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from '@earendil-works/pi-tui';
|
|
20
20
|
import { defineUiMessageCatalog, formatUiMessage, resolveUiMessageCatalog, } from '@maka/core/ui-locale';
|
|
21
|
-
import { providerDefaultsOf, } from '@maka/core/llm-connections';
|
|
21
|
+
import { providerDefaultsOf, validateSlug, } from '@maka/core/llm-connections';
|
|
22
|
+
import { CONNECTION_NAME_MAX_LENGTH } from '@maka/core/runtime-policy';
|
|
22
23
|
import { ansi, editorTheme, selectListTheme, stripAnsi } from './tui-ansi.js';
|
|
23
24
|
import { TUI_COPY_RESOURCES } from './tui-copy-catalog.js';
|
|
24
25
|
const TUI_PICKER_COPY = resolveUiMessageCatalog(defineUiMessageCatalog()(TUI_COPY_RESOURCES.pickers));
|
|
@@ -399,24 +400,37 @@ export class UserQuestionOverlay {
|
|
|
399
400
|
}
|
|
400
401
|
render(width) {
|
|
401
402
|
const safeWidth = Math.max(1, width);
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
403
|
+
// The title wraps like the option rows: a long question must not lose its
|
|
404
|
+
// tail to a hard cut at the terminal width (#4610).
|
|
405
|
+
const wrappedTitle = wrapTextWithAnsi(`${this.input.title} ${ansi.accent(this.input.rightLabel)}`, safeWidth);
|
|
406
|
+
const titleLines = (wrappedTitle.length > 0 ? wrappedTitle : ['']).map((line) => padLine(line, safeWidth));
|
|
407
|
+
const hint = padLine(ansi.dim(this.input.hint), safeWidth);
|
|
408
|
+
const blank = padLine('', safeWidth);
|
|
409
|
+
const divider = padLine(ansi.accent('-'.repeat(safeWidth)), safeWidth);
|
|
410
|
+
const inputRows = this.renderInputRow(safeWidth);
|
|
411
|
+
const optionRows = this.input.options.map((option, index) => formatUserQuestionOptionRow(option, index === this.activeIndex, safeWidth));
|
|
412
|
+
const assemble = (title, options) => [
|
|
413
|
+
...title,
|
|
414
|
+
hint,
|
|
415
|
+
blank,
|
|
416
|
+
...options.flat(),
|
|
417
|
+
...inputRows,
|
|
418
|
+
divider,
|
|
406
419
|
];
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
+
const full = assemble(titleLines, optionRows);
|
|
421
|
+
const budget = this.input.maxRows?.() ?? Number.POSITIVE_INFINITY;
|
|
422
|
+
if (full.length <= budget)
|
|
423
|
+
return full;
|
|
424
|
+
// Over budget pi-tui would slice(0, maxHeight) — silently dropping the
|
|
425
|
+
// input row and divider. Degrade instead: cap the title at two lines and
|
|
426
|
+
// give every option an equal share of the remaining rows, each ending in
|
|
427
|
+
// a visible ellipsis when clamped. Only a terminal too short for one row
|
|
428
|
+
// per option still overflows, falling back to the pre-existing clip.
|
|
429
|
+
const cappedTitle = clampRowsWithEllipsis(titleLines, 2, safeWidth);
|
|
430
|
+
const fixedRows = cappedTitle.length + 2 + inputRows.length + 1;
|
|
431
|
+
const optionBudget = Math.max(this.input.options.length, budget - fixedRows);
|
|
432
|
+
const perOption = Math.max(1, Math.floor(optionBudget / Math.max(1, this.input.options.length)));
|
|
433
|
+
return assemble(cappedTitle, optionRows.map((rows) => clampRowsWithEllipsis(rows, perOption, safeWidth)));
|
|
420
434
|
}
|
|
421
435
|
renderInputRow(width) {
|
|
422
436
|
const prefix = this.onInputRow ? '→ ' : ' ';
|
|
@@ -715,15 +729,57 @@ function formatPickerItemLine(line, width) {
|
|
|
715
729
|
const padded = padLine(line, width);
|
|
716
730
|
return stripAnsi(line).startsWith('→ ') ? ansi.reverse(padded) : padded;
|
|
717
731
|
}
|
|
732
|
+
/**
|
|
733
|
+
* One AskUserQuestion option row, wrapped instead of truncated (#4610): the
|
|
734
|
+
* option body is the decision content, and options routinely carry long
|
|
735
|
+
* trade-off descriptions that a hard cut at the terminal width made
|
|
736
|
+
* unreadable. Continuation lines indent under the option body, aligned past
|
|
737
|
+
* the `→ `/` ` marker; the active row's highlight band covers every wrapped
|
|
738
|
+
* line, not just the first.
|
|
739
|
+
*/
|
|
740
|
+
export function formatUserQuestionOptionRow(option, active, width) {
|
|
741
|
+
const safeWidth = Math.max(1, width);
|
|
742
|
+
const prefix = active ? '→ ' : ' ';
|
|
743
|
+
const body = option.description
|
|
744
|
+
? `${option.label} ${active ? option.description : ansi.dim(option.description)}`
|
|
745
|
+
: option.label;
|
|
746
|
+
const wrapped = wrapTextWithAnsi(body, Math.max(1, safeWidth - USER_QUESTION_ROW_PREFIX_WIDTH));
|
|
747
|
+
const continuation = ' '.repeat(USER_QUESTION_ROW_PREFIX_WIDTH);
|
|
748
|
+
return (wrapped.length > 0 ? wrapped : ['']).map((line, index) => {
|
|
749
|
+
const padded = padLine(`${index === 0 ? prefix : continuation}${line}`, safeWidth);
|
|
750
|
+
return active ? ansi.reverse(padded) : padded;
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Cap an already-formatted wrapped row group at `maxRows`, folding the last
|
|
755
|
+
* kept line into an ellipsis so the elision is visible. truncateToWidth is
|
|
756
|
+
* ANSI-aware, so an active (reversed) line keeps its closing SGR.
|
|
757
|
+
*/
|
|
758
|
+
export function clampRowsWithEllipsis(rows, maxRows, width) {
|
|
759
|
+
if (rows.length <= maxRows)
|
|
760
|
+
return rows;
|
|
761
|
+
const keep = Math.max(1, maxRows);
|
|
762
|
+
const kept = rows.slice(0, keep);
|
|
763
|
+
// truncateToWidth only appends its marker when it actually cuts, and the
|
|
764
|
+
// kept row is already padded to full width — so cut one column short and
|
|
765
|
+
// add the ellipsis by hand to guarantee the elision stays visible.
|
|
766
|
+
const shortened = truncateToWidth(kept[kept.length - 1] ?? '', Math.max(1, width - 1), '');
|
|
767
|
+
kept[kept.length - 1] = padLine(`${shortened}…`, width);
|
|
768
|
+
return kept;
|
|
769
|
+
}
|
|
718
770
|
function padLine(text, width) {
|
|
719
771
|
const safeWidth = Math.max(1, width);
|
|
720
772
|
const trimmed = visibleWidth(text) > safeWidth ? truncateToWidth(text, safeWidth, '') : text;
|
|
721
773
|
return `${trimmed}${' '.repeat(Math.max(0, safeWidth - visibleWidth(trimmed)))}`;
|
|
722
774
|
}
|
|
723
|
-
function keyEntryHint(copy, hasConnection,
|
|
775
|
+
function keyEntryHint(copy, hasConnection, returnsTo) {
|
|
724
776
|
const action = hasConnection ? 'reuse' : 'enter';
|
|
725
|
-
|
|
726
|
-
|
|
777
|
+
return copy.keyHints[action][returnsTo];
|
|
778
|
+
}
|
|
779
|
+
/** The union's discriminant sits on `target.kind`, one level down — TS will
|
|
780
|
+
* not narrow the entry from that check alone, so route through this guard. */
|
|
781
|
+
function isCreateEntry(entry) {
|
|
782
|
+
return entry.target.kind === 'create';
|
|
727
783
|
}
|
|
728
784
|
const ONBOARDING_MODELS_MAX_VISIBLE = 10;
|
|
729
785
|
/**
|
|
@@ -744,7 +800,11 @@ export class OnboardingWizard {
|
|
|
744
800
|
searchEditor;
|
|
745
801
|
baseUrlEditor;
|
|
746
802
|
keyEditor;
|
|
803
|
+
nameEditor;
|
|
804
|
+
slugEditor;
|
|
747
805
|
modelsSearchEditor;
|
|
806
|
+
identityFocus = 'name';
|
|
807
|
+
identityNameDraft = '';
|
|
748
808
|
filtered;
|
|
749
809
|
list;
|
|
750
810
|
// Models phase state. Selection seeds from the picked provider's enabled set
|
|
@@ -784,6 +844,19 @@ export class OnboardingWizard {
|
|
|
784
844
|
if (this.picked)
|
|
785
845
|
this.input.onSubmitKey(value);
|
|
786
846
|
};
|
|
847
|
+
this.nameEditor = new Editor(tui, editorTheme(), { paddingX: 0 });
|
|
848
|
+
this.nameEditor.onSubmit = (value) => {
|
|
849
|
+
// Enter on the optional name advances to the slug field in-frame. The
|
|
850
|
+
// Editor clears itself on submit, so capture the value here and restore
|
|
851
|
+
// the visible text — Esc back from the slug field must not find a blank
|
|
852
|
+
// name, and the slug submit reads the draft, not the editor.
|
|
853
|
+
this.identityNameDraft = value;
|
|
854
|
+
this.nameEditor.setText(value);
|
|
855
|
+
this.identityFocus = 'slug';
|
|
856
|
+
this.status = { kind: 'prompt' };
|
|
857
|
+
};
|
|
858
|
+
this.slugEditor = new Editor(tui, editorTheme(), { paddingX: 0 });
|
|
859
|
+
this.slugEditor.onSubmit = (value) => this.submitIdentity(value);
|
|
787
860
|
this.modelsSearchEditor = new Editor(tui, editorTheme(), { paddingX: 0 });
|
|
788
861
|
this.modelsSearchEditor.onChange = (text) => this.applyModelQuery(text);
|
|
789
862
|
}
|
|
@@ -799,9 +872,19 @@ export class OnboardingWizard {
|
|
|
799
872
|
}
|
|
800
873
|
enterKeyPhase(provider) {
|
|
801
874
|
this.picked = provider;
|
|
802
|
-
// A
|
|
875
|
+
// A create target stops at the identity step first: name and slug come
|
|
876
|
+
// prefilled with the Host-derived defaults, and accepting them verbatim
|
|
877
|
+
// sends the same bare target a build without this step would send.
|
|
878
|
+
// A relay has no registry endpoint, so the wizard must still collect one
|
|
803
879
|
// before the key — the deferred phase-2 step from #1254 (#3405).
|
|
804
|
-
|
|
880
|
+
const create = isCreateEntry(provider);
|
|
881
|
+
this.phase = create ? 'identity' : provider.requiresBaseUrl ? 'baseUrl' : 'key';
|
|
882
|
+
if (create) {
|
|
883
|
+
this.identityFocus = 'name';
|
|
884
|
+
this.nameEditor.setText(provider.label);
|
|
885
|
+
this.identityNameDraft = provider.label;
|
|
886
|
+
this.slugEditor.setText(provider.suggestedSlug);
|
|
887
|
+
}
|
|
805
888
|
this.status = { kind: 'prompt' };
|
|
806
889
|
this.baseUrlEditor.setText('');
|
|
807
890
|
this.keyEditor.setText('');
|
|
@@ -817,6 +900,41 @@ export class OnboardingWizard {
|
|
|
817
900
|
this.modelsSearchEditor.setText('');
|
|
818
901
|
this.input.onPickProvider(provider);
|
|
819
902
|
}
|
|
903
|
+
/**
|
|
904
|
+
* Slug submit on the identity step. The name field needs no validation of
|
|
905
|
+
* its own beyond the catalog's length cap: empty or untouched means the
|
|
906
|
+
* provider label stays. An empty or untouched slug likewise keeps the
|
|
907
|
+
* Host-derived identity — only a genuinely edited slug crosses the wire,
|
|
908
|
+
* and it must pass the same rule the catalog decoder enforces.
|
|
909
|
+
*/
|
|
910
|
+
submitIdentity(rawSlug) {
|
|
911
|
+
const picked = this.picked;
|
|
912
|
+
if (!picked || !isCreateEntry(picked) || this.phase !== 'identity')
|
|
913
|
+
return;
|
|
914
|
+
const slug = rawSlug.trim();
|
|
915
|
+
const name = this.identityNameDraft.trim();
|
|
916
|
+
if (name.length > CONNECTION_NAME_MAX_LENGTH) {
|
|
917
|
+
this.identityFocus = 'name';
|
|
918
|
+
this.status = { kind: 'error', text: this.copy.identityNameTooLong };
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
const customSlug = slug.length > 0 && slug !== picked.suggestedSlug ? slug : null;
|
|
922
|
+
if (customSlug !== null) {
|
|
923
|
+
const error = validateSlug(customSlug);
|
|
924
|
+
if (error) {
|
|
925
|
+
this.identityFocus = 'slug';
|
|
926
|
+
this.status = { kind: 'error', text: this.copy.identitySlugInvalid };
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
const defaultName = picked.label;
|
|
931
|
+
this.input.onSubmitIdentity({
|
|
932
|
+
slug: customSlug,
|
|
933
|
+
name: name.length > 0 && name !== defaultName ? name : null,
|
|
934
|
+
});
|
|
935
|
+
this.status = { kind: 'prompt' };
|
|
936
|
+
this.phase = picked.requiresBaseUrl ? 'baseUrl' : 'key';
|
|
937
|
+
}
|
|
820
938
|
submitBaseUrl(value) {
|
|
821
939
|
if (!this.picked || this.phase !== 'baseUrl')
|
|
822
940
|
return;
|
|
@@ -877,6 +995,17 @@ export class OnboardingWizard {
|
|
|
877
995
|
this.modelHighlight = 0;
|
|
878
996
|
this.modelScroll = 0;
|
|
879
997
|
}
|
|
998
|
+
/** Runner hook: the Host rejected the requested slug — bounce back to the
|
|
999
|
+
* identity step with the user's text intact so they can edit it. */
|
|
1000
|
+
setIdentityError(text) {
|
|
1001
|
+
if (this.picked?.target.kind !== 'create')
|
|
1002
|
+
return;
|
|
1003
|
+
this.phase = 'identity';
|
|
1004
|
+
this.identityFocus = 'slug';
|
|
1005
|
+
this.status = { kind: 'error', text };
|
|
1006
|
+
this.keyEditor.setText('');
|
|
1007
|
+
this.keyEditor.disableSubmit = false;
|
|
1008
|
+
}
|
|
880
1009
|
/** Runner hook: verify is in flight. Lock the key field and show progress. */
|
|
881
1010
|
setVerifying() {
|
|
882
1011
|
if (this.phase !== 'key')
|
|
@@ -937,17 +1066,40 @@ export class OnboardingWizard {
|
|
|
937
1066
|
this.searchEditor.invalidate();
|
|
938
1067
|
this.baseUrlEditor.invalidate();
|
|
939
1068
|
this.keyEditor.invalidate();
|
|
1069
|
+
this.nameEditor.invalidate();
|
|
1070
|
+
this.slugEditor.invalidate();
|
|
940
1071
|
this.modelsSearchEditor.invalidate();
|
|
941
1072
|
this.list.invalidate();
|
|
942
1073
|
}
|
|
943
|
-
/** Step label: relays
|
|
944
|
-
|
|
945
|
-
|
|
1074
|
+
/** Step label: relays add a base-URL step, create targets an identity one. */
|
|
1075
|
+
stepFor(phase) {
|
|
1076
|
+
const create = this.picked?.target.kind === 'create';
|
|
1077
|
+
const relay = this.picked?.requiresBaseUrl === true;
|
|
1078
|
+
const total = 3 + (create ? 1 : 0) + (relay ? 1 : 0);
|
|
1079
|
+
let position = 1;
|
|
1080
|
+
if (phase === 'search')
|
|
1081
|
+
return `1/${total}`;
|
|
1082
|
+
if (create) {
|
|
1083
|
+
position += 1;
|
|
1084
|
+
if (phase === 'identity')
|
|
1085
|
+
return `${position}/${total}`;
|
|
1086
|
+
}
|
|
1087
|
+
if (relay) {
|
|
1088
|
+
position += 1;
|
|
1089
|
+
if (phase === 'baseUrl')
|
|
1090
|
+
return `${position}/${total}`;
|
|
1091
|
+
}
|
|
1092
|
+
position += 1;
|
|
1093
|
+
if (phase === 'key')
|
|
1094
|
+
return `${position}/${total}`;
|
|
1095
|
+
return `${total}/${total}`;
|
|
946
1096
|
}
|
|
947
1097
|
handleInput(data) {
|
|
948
1098
|
switch (this.phase) {
|
|
949
1099
|
case 'search':
|
|
950
1100
|
return this.handleSearchInput(data);
|
|
1101
|
+
case 'identity':
|
|
1102
|
+
return this.handleIdentityInput(data);
|
|
951
1103
|
case 'baseUrl':
|
|
952
1104
|
return this.handleBaseUrlInput(data);
|
|
953
1105
|
case 'key':
|
|
@@ -958,15 +1110,41 @@ export class OnboardingWizard {
|
|
|
958
1110
|
return this.handleSuccessInput(data);
|
|
959
1111
|
}
|
|
960
1112
|
}
|
|
961
|
-
|
|
1113
|
+
handleIdentityInput(data) {
|
|
962
1114
|
if (matchesKey(data, Key.ctrl('c'))) {
|
|
963
1115
|
this.input.onCancel();
|
|
964
1116
|
return;
|
|
965
1117
|
}
|
|
966
1118
|
if (matchesKey(data, Key.escape)) {
|
|
1119
|
+
// One level back: slug field → name field → provider search.
|
|
1120
|
+
if (this.identityFocus === 'slug') {
|
|
1121
|
+
this.identityFocus = 'name';
|
|
1122
|
+
this.status = { kind: 'prompt' };
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
967
1125
|
this.phase = 'search';
|
|
968
1126
|
this.picked = undefined;
|
|
969
1127
|
this.status = { kind: 'prompt' };
|
|
1128
|
+
this.input.onBack();
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
(this.identityFocus === 'name' ? this.nameEditor : this.slugEditor).handleInput(data);
|
|
1132
|
+
}
|
|
1133
|
+
handleBaseUrlInput(data) {
|
|
1134
|
+
if (matchesKey(data, Key.ctrl('c'))) {
|
|
1135
|
+
this.input.onCancel();
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
if (matchesKey(data, Key.escape)) {
|
|
1139
|
+
// One level back: a create target returns to its identity step.
|
|
1140
|
+
if (this.picked?.target.kind === 'create') {
|
|
1141
|
+
this.phase = 'identity';
|
|
1142
|
+
}
|
|
1143
|
+
else {
|
|
1144
|
+
this.phase = 'search';
|
|
1145
|
+
this.picked = undefined;
|
|
1146
|
+
}
|
|
1147
|
+
this.status = { kind: 'prompt' };
|
|
970
1148
|
this.baseUrlEditor.setText('');
|
|
971
1149
|
this.input.onBack();
|
|
972
1150
|
return;
|
|
@@ -1002,11 +1180,14 @@ export class OnboardingWizard {
|
|
|
1002
1180
|
return;
|
|
1003
1181
|
}
|
|
1004
1182
|
if (matchesKey(data, Key.escape)) {
|
|
1005
|
-
// One level back: a relay returns to its base-URL step,
|
|
1006
|
-
// else to the provider search.
|
|
1183
|
+
// One level back: a relay returns to its base-URL step, a create target
|
|
1184
|
+
// to its identity step, everything else to the provider search.
|
|
1007
1185
|
if (this.picked?.requiresBaseUrl) {
|
|
1008
1186
|
this.phase = 'baseUrl';
|
|
1009
1187
|
}
|
|
1188
|
+
else if (this.picked?.target.kind === 'create') {
|
|
1189
|
+
this.phase = 'identity';
|
|
1190
|
+
}
|
|
1010
1191
|
else {
|
|
1011
1192
|
this.phase = 'search';
|
|
1012
1193
|
this.picked = undefined;
|
|
@@ -1108,6 +1289,8 @@ export class OnboardingWizard {
|
|
|
1108
1289
|
switch (this.phase) {
|
|
1109
1290
|
case 'search':
|
|
1110
1291
|
return this.renderSearch(safeWidth);
|
|
1292
|
+
case 'identity':
|
|
1293
|
+
return this.renderIdentity(safeWidth);
|
|
1111
1294
|
case 'baseUrl':
|
|
1112
1295
|
return this.renderBaseUrl(safeWidth);
|
|
1113
1296
|
case 'key':
|
|
@@ -1118,17 +1301,43 @@ export class OnboardingWizard {
|
|
|
1118
1301
|
return this.renderSuccess(safeWidth);
|
|
1119
1302
|
}
|
|
1120
1303
|
}
|
|
1304
|
+
focusOnly(active) {
|
|
1305
|
+
for (const editor of [
|
|
1306
|
+
this.searchEditor,
|
|
1307
|
+
this.nameEditor,
|
|
1308
|
+
this.slugEditor,
|
|
1309
|
+
this.baseUrlEditor,
|
|
1310
|
+
this.keyEditor,
|
|
1311
|
+
this.modelsSearchEditor,
|
|
1312
|
+
]) {
|
|
1313
|
+
editor.focused = editor === active;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
renderIdentity(width) {
|
|
1317
|
+
this.focusOnly(this.identityFocus === 'name' ? this.nameEditor : this.slugEditor);
|
|
1318
|
+
const label = this.picked?.label ?? '';
|
|
1319
|
+
return [
|
|
1320
|
+
padLine(`${this.copy.setupTitle} ${ansi.dim(`· ${this.stepFor('identity')}`)} ${ansi.accent(label)}`, width),
|
|
1321
|
+
padLine(ansi.dim(this.copy.identityHint), width),
|
|
1322
|
+
padLine('', width),
|
|
1323
|
+
...this.renderFieldRow(this.nameEditor, this.copy.connectionNameLabel, width),
|
|
1324
|
+
padLine('', width),
|
|
1325
|
+
...this.renderFieldRow(this.slugEditor, this.copy.connectionSlugLabel, width),
|
|
1326
|
+
padLine('', width),
|
|
1327
|
+
padLine(this.status.kind === 'error'
|
|
1328
|
+
? ansi.red(`✗ ${this.status.text}`)
|
|
1329
|
+
: ansi.dim(this.copy.continueAction), width),
|
|
1330
|
+
padLine(ansi.accent('-'.repeat(width)), width),
|
|
1331
|
+
];
|
|
1332
|
+
}
|
|
1121
1333
|
renderBaseUrl(width) {
|
|
1122
|
-
this.
|
|
1123
|
-
this.baseUrlEditor.focused = true;
|
|
1124
|
-
this.keyEditor.focused = false;
|
|
1125
|
-
this.modelsSearchEditor.focused = false;
|
|
1334
|
+
this.focusOnly(this.baseUrlEditor);
|
|
1126
1335
|
const label = this.picked?.label ?? '';
|
|
1127
1336
|
const hint = this.picked?.target.kind === 'existing'
|
|
1128
1337
|
? this.copy.reuseBaseUrlHint
|
|
1129
1338
|
: this.copy.enterBaseUrlHint;
|
|
1130
1339
|
return [
|
|
1131
|
-
padLine(`${this.copy.setupTitle} ${ansi.dim(`· ${this.
|
|
1340
|
+
padLine(`${this.copy.setupTitle} ${ansi.dim(`· ${this.stepFor('baseUrl')}`)} ${ansi.accent(label)}`, width),
|
|
1132
1341
|
padLine(ansi.dim(hint), width),
|
|
1133
1342
|
padLine('', width),
|
|
1134
1343
|
...this.renderFieldRow(this.baseUrlEditor, this.copy.baseUrlLabel, width),
|
|
@@ -1140,12 +1349,9 @@ export class OnboardingWizard {
|
|
|
1140
1349
|
];
|
|
1141
1350
|
}
|
|
1142
1351
|
renderSearch(width) {
|
|
1143
|
-
this.searchEditor
|
|
1144
|
-
this.baseUrlEditor.focused = false;
|
|
1145
|
-
this.keyEditor.focused = false;
|
|
1146
|
-
this.modelsSearchEditor.focused = false;
|
|
1352
|
+
this.focusOnly(this.searchEditor);
|
|
1147
1353
|
return [
|
|
1148
|
-
padLine(`${this.copy.setupTitle} ${ansi.dim(`· ${this.
|
|
1354
|
+
padLine(`${this.copy.setupTitle} ${ansi.dim(`· ${this.stepFor('search')}`)} ${ansi.accent(String(this.filtered.length))}`, width),
|
|
1149
1355
|
padLine(ansi.dim(this.copy.providerSearchHint), width),
|
|
1150
1356
|
padLine('', width),
|
|
1151
1357
|
...this.renderFieldRow(this.searchEditor, this.copy.searchLabel, width),
|
|
@@ -1157,14 +1363,15 @@ export class OnboardingWizard {
|
|
|
1157
1363
|
];
|
|
1158
1364
|
}
|
|
1159
1365
|
renderKey(width) {
|
|
1160
|
-
this.
|
|
1161
|
-
this.baseUrlEditor.focused = false;
|
|
1162
|
-
this.keyEditor.focused = this.status.kind === 'prompt' || this.status.kind === 'error';
|
|
1163
|
-
this.modelsSearchEditor.focused = false;
|
|
1366
|
+
this.focusOnly(this.status.kind === 'prompt' || this.status.kind === 'error' ? this.keyEditor : null);
|
|
1164
1367
|
const label = this.picked?.label ?? '';
|
|
1165
|
-
const hint = keyEntryHint(this.copy, this.picked?.target.kind === 'existing', this.picked?.requiresBaseUrl === true
|
|
1368
|
+
const hint = keyEntryHint(this.copy, this.picked?.target.kind === 'existing', this.picked?.requiresBaseUrl === true
|
|
1369
|
+
? 'baseUrl'
|
|
1370
|
+
: this.picked?.target.kind === 'create'
|
|
1371
|
+
? 'identity'
|
|
1372
|
+
: 'provider');
|
|
1166
1373
|
return [
|
|
1167
|
-
padLine(`${this.copy.setupTitle} ${ansi.dim(`· ${this.
|
|
1374
|
+
padLine(`${this.copy.setupTitle} ${ansi.dim(`· ${this.stepFor('key')}`)} ${ansi.accent(label)}`, width),
|
|
1168
1375
|
padLine(ansi.dim(hint), width),
|
|
1169
1376
|
padLine('', width),
|
|
1170
1377
|
...this.renderFieldRow(this.keyEditor, this.copy.apiKeyLabel, width),
|
|
@@ -1186,13 +1393,10 @@ export class OnboardingWizard {
|
|
|
1186
1393
|
}
|
|
1187
1394
|
}
|
|
1188
1395
|
renderModels(width) {
|
|
1189
|
-
this.
|
|
1190
|
-
this.baseUrlEditor.focused = false;
|
|
1191
|
-
this.keyEditor.focused = false;
|
|
1192
|
-
this.modelsSearchEditor.focused = this.status.kind !== 'saving';
|
|
1396
|
+
this.focusOnly(this.status.kind !== 'saving' ? this.modelsSearchEditor : null);
|
|
1193
1397
|
const label = this.picked?.label ?? '';
|
|
1194
1398
|
const lines = [
|
|
1195
|
-
padLine(`${this.copy.setupTitle} ${ansi.dim(`· ${this.
|
|
1399
|
+
padLine(`${this.copy.setupTitle} ${ansi.dim(`· ${this.stepFor('models')}`)} ${ansi.accent(label)}`, width),
|
|
1196
1400
|
padLine(ansi.dim(this.copy.modelSelectionHint), width),
|
|
1197
1401
|
padLine('', width),
|
|
1198
1402
|
...this.renderFieldRow(this.modelsSearchEditor, this.copy.searchLabel, width),
|
|
@@ -1229,10 +1433,7 @@ export class OnboardingWizard {
|
|
|
1229
1433
|
}
|
|
1230
1434
|
}
|
|
1231
1435
|
renderSuccess(width) {
|
|
1232
|
-
this.
|
|
1233
|
-
this.baseUrlEditor.focused = false;
|
|
1234
|
-
this.keyEditor.focused = false;
|
|
1235
|
-
this.modelsSearchEditor.focused = false;
|
|
1436
|
+
this.focusOnly(null);
|
|
1236
1437
|
const label = this.picked?.label ?? '';
|
|
1237
1438
|
return [
|
|
1238
1439
|
padLine(`${this.copy.setupTitle} ${ansi.dim(`· ${this.copy.complete}`)} ${ansi.accent(label)}`, width),
|