@gajae-code/coding-agent 0.18.12 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +467 -0
- package/dist/types/capability/rule.d.ts +7 -2
- package/dist/types/cli/append-system-prompt.d.ts +6 -0
- package/dist/types/cli/args.d.ts +7 -2
- package/dist/types/cli/customize-doctor-precedence.d.ts +16 -0
- package/dist/types/cli/customize-doctor.d.ts +4 -3
- package/dist/types/cli/public-command-errors.d.ts +1 -0
- package/dist/types/cli/root-flags.d.ts +0 -12
- package/dist/types/cli/update-cli.d.ts +7 -2
- package/dist/types/cli-main.d.ts +0 -6
- package/dist/types/commands/launch.d.ts +0 -6
- package/dist/types/commands/migrate.d.ts +1 -1
- package/dist/types/commands/sdk.d.ts +8 -0
- package/dist/types/commit/map-reduce/index.d.ts +4 -4
- package/dist/types/config/autorouting-tier-map.d.ts +23 -1
- package/dist/types/config/config-hot-reload.d.ts +5 -0
- package/dist/types/config/file-lock.d.ts +44 -2
- package/dist/types/config/model-profile-activation.d.ts +19 -5
- package/dist/types/config/model-registry.d.ts +16 -3
- package/dist/types/config/model-resolver.d.ts +5 -4
- package/dist/types/config/settings-schema.d.ts +11 -1
- package/dist/types/coordinator-mcp/server.d.ts +4 -0
- package/dist/types/customization/import.d.ts +2 -0
- package/dist/types/customization/types.d.ts +1 -1
- package/dist/types/dap/session.d.ts +11 -2
- package/dist/types/discovery/helpers.d.ts +7 -2
- package/dist/types/edit/index.d.ts +5 -0
- package/dist/types/edit/modes/patch.d.ts +9 -0
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/export/ttsr.d.ts +19 -0
- package/dist/types/extensibility/extensions/types.d.ts +5 -1
- package/dist/types/extensibility/slash-commands.d.ts +1 -0
- package/dist/types/gjc-runtime/ralplan-current-final.d.ts +54 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +24 -0
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +6 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
- package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
- package/dist/types/hindsight/content.d.ts +5 -6
- package/dist/types/internal-urls/types.d.ts +2 -0
- package/dist/types/lsp/clients/swiftlint-client.d.ts +0 -4
- package/dist/types/main.d.ts +23 -18
- package/dist/types/migrate/action-planner.d.ts +10 -1
- package/dist/types/migrate/adapters/codex.d.ts +1 -1
- package/dist/types/migrate/adapters/index.d.ts +35 -3
- package/dist/types/migrate/hook-module.d.ts +23 -0
- package/dist/types/migrate/report.d.ts +2 -1
- package/dist/types/migrate/types.d.ts +69 -2
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
- package/dist/types/modes/components/model-selector.d.ts +43 -0
- package/dist/types/modes/prompt-suggestion-controller.d.ts +1 -1
- package/dist/types/modes/utils/host-status.d.ts +15 -11
- package/dist/types/runtime-mcp/project-host-values.d.ts +11 -5
- package/dist/types/sdk/broker/broker-exit.d.ts +1 -1
- package/dist/types/sdk/broker/broker.d.ts +22 -1
- package/dist/types/sdk/broker/ensure.d.ts +5 -2
- package/dist/types/sdk/broker/hop.d.ts +9 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +22 -0
- package/dist/types/sdk/broker/session-index.d.ts +2 -0
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/index.d.ts +21 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +7 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +2 -0
- package/dist/types/sdk/bus/threaded-render.d.ts +2 -1
- package/dist/types/sdk/host/control/operations.d.ts +5 -1
- package/dist/types/sdk/host/events.d.ts +4 -0
- package/dist/types/sdk/host/host.d.ts +2 -1
- package/dist/types/sdk/host/prompt-image-upload.d.ts +43 -0
- package/dist/types/sdk/host/session-runtime.d.ts +8 -8
- package/dist/types/sdk/host/surface-policy.d.ts +2 -1
- package/dist/types/sdk/lifecycle/service.d.ts +12 -0
- package/dist/types/sdk/prompt-status.d.ts +11 -4
- package/dist/types/session/agent-session.d.ts +50 -8
- package/dist/types/session/session-manager.d.ts +16 -0
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +13 -1
- package/dist/types/slash-commands/helpers/mcp.d.ts +5 -0
- package/dist/types/ssh/ssh-executor.d.ts +8 -1
- package/dist/types/system-prompt.d.ts +3 -2
- package/dist/types/task/role-body.d.ts +11 -0
- package/dist/types/tools/awaiting-input.d.ts +28 -0
- package/dist/types/tools/bash-allowed-prefixes.d.ts +6 -0
- package/dist/types/tools/bash-skill-urls.d.ts +4 -0
- package/dist/types/tools/bash.d.ts +7 -0
- package/dist/types/tools/descriptors.d.ts +13 -2
- package/dist/types/tools/fetch.d.ts +6 -0
- package/dist/types/tools/irc.d.ts +5 -3
- package/dist/types/tools/tmux-self-injection-guard.d.ts +2 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +1 -1
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/utils/file-mentions.d.ts +5 -0
- package/dist/types/utils/image-limits.d.ts +7 -0
- package/dist/types/utils/image-loading.d.ts +0 -1
- package/dist/types/utils/open.d.ts +0 -1
- package/dist/types/utils/pasted-image-loading.d.ts +1 -5
- package/dist/types/utils/prompt-suggestion.d.ts +2 -2
- package/dist/types/utils/shell-snapshot.d.ts +2 -0
- package/dist/types/utils/title-generator.d.ts +13 -3
- package/dist/types/web/search/providers/codex.d.ts +6 -7
- package/package.json +9 -8
- package/scripts/acp-conformance-agent.ts +12 -2
- package/scripts/generate-sdk-operation-inventory.ts +16 -0
- package/src/capability/fs.ts +31 -3
- package/src/capability/rule.ts +11 -2
- package/src/cli/append-system-prompt.ts +12 -0
- package/src/cli/args.ts +11 -7
- package/src/cli/customize-doctor-precedence.ts +31 -0
- package/src/cli/customize-doctor.ts +49 -39
- package/src/cli/fast-help.ts +0 -2
- package/src/cli/migrate-cli.ts +14 -3
- package/src/cli/public-command-errors.ts +2 -0
- package/src/cli/root-flags.ts +0 -2
- package/src/cli/update-cli.ts +247 -6
- package/src/commands/harness.ts +25 -15
- package/src/commands/migrate.ts +3 -3
- package/src/commands/sdk.ts +81 -11
- package/src/commit/agentic/agent.ts +6 -6
- package/src/commit/analysis/conventional.ts +14 -5
- package/src/commit/map-reduce/index.ts +7 -7
- package/src/commit/pipeline.ts +12 -12
- package/src/config/autorouting-tier-map.ts +20 -1
- package/src/config/config-file.ts +106 -3
- package/src/config/config-hot-reload.ts +8 -0
- package/src/config/file-lock.ts +1431 -304
- package/src/config/keybindings.ts +154 -7
- package/src/config/model-profile-activation.ts +177 -39
- package/src/config/model-registry.ts +380 -55
- package/src/config/model-resolver.ts +49 -21
- package/src/config/settings-schema.ts +13 -1
- package/src/config/settings.ts +2 -0
- package/src/coordinator-mcp/server.ts +37 -2
- package/src/crash/sanitize.ts +3 -1
- package/src/customization/import.ts +276 -7
- package/src/customization/inventory.ts +24 -8
- package/src/customization/types.ts +1 -0
- package/src/dap/client.ts +3 -2
- package/src/dap/session.ts +161 -36
- package/src/debug/crash-diagnostics.ts +87 -5
- package/src/debug/report-bundle.ts +71 -2
- package/src/discovery/builtin.ts +4 -3
- package/src/discovery/helpers.ts +24 -14
- package/src/edit/index.ts +191 -5
- package/src/edit/modes/patch.ts +27 -0
- package/src/eval/py/runtime.ts +44 -4
- package/src/exec/non-interactive-env.ts +0 -1
- package/src/export/html/index.ts +60 -20
- package/src/export/ttsr.ts +176 -1
- package/src/extensibility/extensions/loader.ts +2 -0
- package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +63 -1
- package/src/extensibility/extensions/types.ts +5 -1
- package/src/extensibility/hooks/loader.ts +10 -2
- package/src/extensibility/plugins/marketplace/manager.ts +36 -10
- package/src/extensibility/slash-commands.ts +5 -0
- package/src/gjc-runtime/gc-runtime.ts +4 -1
- package/src/gjc-runtime/launch-tmux.ts +23 -13
- package/src/gjc-runtime/ralplan-current-final.ts +294 -0
- package/src/gjc-runtime/ralplan-runtime.ts +95 -1
- package/src/gjc-runtime/state-writer.ts +109 -5
- package/src/gjc-runtime/tmux-sessions.ts +93 -13
- package/src/gjc-runtime/ultragoal-change-set.ts +90 -11
- package/src/gjc-runtime/ultragoal-guard.ts +9 -1
- package/src/gjc-runtime/ultragoal-runtime.ts +15 -5
- package/src/harness-control-plane/finalize.ts +11 -0
- package/src/harness-control-plane/receipt-spool.ts +105 -28
- package/src/harness-control-plane/storage.ts +124 -6
- package/src/hindsight/content.ts +116 -16
- package/src/hindsight/mental-models.ts +22 -10
- package/src/hindsight/state.ts +7 -4
- package/src/hooks/native-skill-hook.ts +3 -1
- package/src/internal-urls/artifact-protocol.ts +3 -1
- package/src/internal-urls/docs-index.generated.ts +14 -14
- package/src/internal-urls/local-protocol.ts +28 -3
- package/src/internal-urls/types.ts +2 -0
- package/src/lsp/client.ts +2 -1
- package/src/lsp/clients/biome-client.ts +2 -0
- package/src/lsp/clients/swiftlint-client.ts +2 -0
- package/src/main.ts +330 -92
- package/src/memories/index.ts +25 -2
- package/src/migrate/action-planner.ts +517 -2
- package/src/migrate/adapters/claude-code.ts +141 -3
- package/src/migrate/adapters/codex.ts +57 -5
- package/src/migrate/adapters/index.ts +240 -5
- package/src/migrate/adapters/opencode.ts +4 -0
- package/src/migrate/executor.ts +141 -3
- package/src/migrate/hook-module.ts +193 -0
- package/src/migrate/report.ts +45 -1
- package/src/migrate/types.ts +73 -3
- package/src/modes/acp/acp-agent.ts +10 -1
- package/src/modes/components/agent-dashboard.ts +20 -4
- package/src/modes/components/customization/customization-dashboard.ts +7 -0
- package/src/modes/components/customization/import-wizard.ts +29 -3
- package/src/modes/components/model-selector.ts +157 -103
- package/src/modes/components/welcome.ts +3 -1
- package/src/modes/controllers/command-controller.ts +271 -16
- package/src/modes/controllers/event-controller.ts +1 -1
- package/src/modes/controllers/extension-ui-controller.ts +31 -1
- package/src/modes/controllers/goal-mode-controller.ts +79 -10
- package/src/modes/controllers/input-controller.ts +2 -0
- package/src/modes/controllers/plan-mode-controller.ts +49 -4
- package/src/modes/controllers/runtime-mcp-command-controller.ts +7 -6
- package/src/modes/controllers/selector-controller.ts +14 -1
- package/src/modes/interactive-mode.ts +55 -4
- package/src/modes/prompt-suggestion-controller.ts +1 -1
- package/src/modes/runtime-init.ts +5 -1
- package/src/modes/utils/host-status.ts +21 -10
- package/src/prompts/agent-fragments/browser-aside.md +2 -2
- package/src/prompts/system/irc-incoming.md +3 -1
- package/src/prompts/tools/irc.md +1 -1
- package/src/runtime-mcp/manager.ts +8 -3
- package/src/runtime-mcp/project-host-values.ts +12 -8
- package/src/runtime-mcp/tool-bridge.ts +68 -4
- package/src/runtime-mcp/transports/stdio.ts +2 -1
- package/src/sdk/broker/broker-exit.ts +2 -0
- package/src/sdk/broker/broker.ts +143 -4
- package/src/sdk/broker/ensure.ts +74 -6
- package/src/sdk/broker/hop.ts +13 -1
- package/src/sdk/broker/lifecycle-ledger.ts +3 -0
- package/src/sdk/broker/lifecycle.ts +102 -6
- package/src/sdk/broker/session-index.ts +29 -4
- package/src/sdk/broker/transport.ts +17 -1
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +408 -14
- package/src/sdk/bus/session-control.ts +2 -0
- package/src/sdk/bus/slack-daemon.ts +105 -9
- package/src/sdk/bus/telegram-daemon-contract.ts +7 -1
- package/src/sdk/bus/telegram-daemon.ts +10 -2
- package/src/sdk/bus/threaded-render.ts +20 -1
- package/src/sdk/cli/session-cli.ts +2 -0
- package/src/sdk/host/control/dispatch.ts +13 -1
- package/src/sdk/host/control/operations.ts +10 -1
- package/src/sdk/host/events.ts +67 -4
- package/src/sdk/host/host.ts +8 -2
- package/src/sdk/host/prompt-image-upload.ts +438 -0
- package/src/sdk/host/sdk-surface-parity.test.ts +15 -0
- package/src/sdk/host/session-runtime.test.ts +1537 -24
- package/src/sdk/host/session-runtime.ts +332 -36
- package/src/sdk/host/surface-policy.ts +4 -0
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +90 -2
- package/src/sdk/host/websocket-transport.ts +19 -7
- package/src/sdk/lifecycle/service.ts +14 -1
- package/src/sdk/prompt-status.ts +6 -4
- package/src/sdk/protocol/adapter-validation.ts +28 -1
- package/src/sdk/protocol/operation-inventory.generated.json +160 -0
- package/src/sdk/protocol/operation-registry.ts +33 -3
- package/src/sdk/session.ts +123 -36
- package/src/session/agent-session.ts +1614 -329
- package/src/session/history-storage.ts +182 -12
- package/src/session/internal/managed-session-scope.ts +47 -18
- package/src/session/internal/managed-session-storage.ts +71 -1
- package/src/session/session-manager.ts +90 -5
- package/src/session-import/redact.ts +53 -2
- package/src/skill-state/workflow-mutation-guard.ts +1498 -18
- package/src/slash-commands/builtin-registry.ts +6 -3
- package/src/slash-commands/helpers/mcp.ts +11 -3
- package/src/ssh/ssh-executor.ts +9 -2
- package/src/stt/recorder.ts +26 -9
- package/src/system-prompt.ts +61 -16
- package/src/task/executor.ts +12 -8
- package/src/task/role-body.ts +84 -0
- package/src/task/token-log-mode.test.ts +162 -0
- package/src/task/token-log.ts +91 -2
- package/src/tools/archive-reader.ts +650 -37
- package/src/tools/ask.ts +1 -0
- package/src/tools/ast-grep.ts +7 -2
- package/src/tools/auto-generated-guard.ts +12 -3
- package/src/tools/awaiting-input.ts +114 -0
- package/src/tools/bash-allowed-prefixes.ts +61 -1
- package/src/tools/bash-skill-urls.ts +58 -5
- package/src/tools/bash.ts +99 -26
- package/src/tools/browser/tab-worker.ts +39 -13
- package/src/tools/browser.ts +17 -7
- package/src/tools/cron.ts +10 -1
- package/src/tools/debug.ts +9 -2
- package/src/tools/descriptors.test.ts +4 -4
- package/src/tools/descriptors.ts +16 -4
- package/src/tools/eval.ts +15 -0
- package/src/tools/fetch.ts +90 -2
- package/src/tools/gh.ts +27 -12
- package/src/tools/image-gen.ts +20 -6
- package/src/tools/irc.ts +5 -3
- package/src/tools/monitor.ts +9 -1
- package/src/tools/output-meta.ts +51 -3
- package/src/tools/read.ts +9 -2
- package/src/tools/recipe/runner.ts +23 -12
- package/src/tools/render-utils.ts +2 -2
- package/src/tools/search.ts +3 -2
- package/src/tools/ssh.ts +274 -8
- package/src/tools/subagent.ts +10 -4
- package/src/tools/tmux-self-injection-guard.ts +3301 -122
- package/src/tools/tool-catalog.generated.ts +1 -1
- package/src/tools/ultragoal-ask-guard.ts +13 -1
- package/src/tools/write.ts +7 -0
- package/src/tui/tree-list.ts +15 -1
- package/src/utils/commit-message-generator.ts +3 -2
- package/src/utils/external-editor.ts +21 -7
- package/src/utils/file-mentions.ts +46 -6
- package/src/utils/git.ts +38 -7
- package/src/utils/image-limits.ts +8 -0
- package/src/utils/image-loading.ts +1 -1
- package/src/utils/open.ts +73 -4
- package/src/utils/pasted-image-loading.ts +9 -8
- package/src/utils/prompt-suggestion.ts +5 -4
- package/src/utils/shell-snapshot.ts +9 -1
- package/src/utils/title-generator.ts +65 -20
- package/src/web/search/index.ts +2 -1
- package/src/web/search/providers/codex.ts +29 -32
|
@@ -59,6 +59,7 @@ function safe(text: string): string {
|
|
|
59
59
|
|
|
60
60
|
const STATUS_COLORS: Record<InventoryRow["status"], (text: string) => string> = {
|
|
61
61
|
enabled: text => theme.fg("success", text),
|
|
62
|
+
"stored-only": text => theme.fg("warning", text),
|
|
62
63
|
disabled: text => theme.fg("muted", text),
|
|
63
64
|
invalid: text => theme.fg("error", text),
|
|
64
65
|
shadowed: text => theme.fg("warning", text),
|
|
@@ -281,6 +282,12 @@ export class CustomizationDashboard extends Container {
|
|
|
281
282
|
async #toggleSelected(): Promise<void> {
|
|
282
283
|
const row = this.#selectedRow();
|
|
283
284
|
if (!row || !this.#guardScope(row)) return;
|
|
285
|
+
if (row.status === "stored-only") {
|
|
286
|
+
this.#flashStatus(
|
|
287
|
+
"project hooks are stored-only; import into Global .gjc or configure an explicit hook path to load them",
|
|
288
|
+
);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
284
291
|
if (row.status === "invalid" || row.status === "shadowed" || row.status === "quarantined") {
|
|
285
292
|
this.#flashStatus(`cannot toggle a ${row.status} entry; resolve its diagnostics first`);
|
|
286
293
|
return;
|
|
@@ -313,20 +313,46 @@ export class ImportWizard extends Container {
|
|
|
313
313
|
counts.set(entry.outcome, (counts.get(entry.outcome) ?? 0) + 1);
|
|
314
314
|
}
|
|
315
315
|
const summary = [...counts.entries()].map(([outcome, count]) => `${count} ${outcome}`).join(", ");
|
|
316
|
+
const storedOnlyProjectHooks =
|
|
317
|
+
this.#result.ok &&
|
|
318
|
+
this.#plan?.preview.destinationScope === "project" &&
|
|
319
|
+
this.#result.entries.some(
|
|
320
|
+
entry =>
|
|
321
|
+
entry.surface === "hooks" &&
|
|
322
|
+
(entry.outcome === "imported" || entry.outcome === "renamed" || entry.outcome === "overwritten"),
|
|
323
|
+
);
|
|
316
324
|
this.#headerText.setText(
|
|
317
325
|
this.#result.ok
|
|
318
326
|
? theme.bold(theme.fg("success", "Import complete"))
|
|
319
327
|
: theme.bold(theme.fg("error", "Import failed — rolled back, no partial import")),
|
|
320
328
|
);
|
|
321
329
|
const failed = this.#result.entries.filter(e => e.outcome === "failed").slice(0, 5);
|
|
330
|
+
const completionMessages: string[] = [];
|
|
331
|
+
if (this.#result.ok) {
|
|
332
|
+
if (storedOnlyProjectHooks) {
|
|
333
|
+
completionMessages.push(
|
|
334
|
+
theme.fg(
|
|
335
|
+
"warning",
|
|
336
|
+
"Project-scope hooks are stored-only; ordinary sessions do not load repository hook modules.",
|
|
337
|
+
),
|
|
338
|
+
theme.fg("muted", "Import hooks into Global .gjc or configure an explicit hook path to activate them."),
|
|
339
|
+
theme.fg(
|
|
340
|
+
"muted",
|
|
341
|
+
"Other imported entries take effect after the documented reload/new-session boundary.",
|
|
342
|
+
),
|
|
343
|
+
);
|
|
344
|
+
} else {
|
|
345
|
+
completionMessages.push(
|
|
346
|
+
theme.fg("muted", "Imported entries take effect after the documented reload/new-session boundary."),
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
322
350
|
this.#bodyText.setText(
|
|
323
351
|
[
|
|
324
352
|
summary,
|
|
325
353
|
"",
|
|
326
354
|
...failed.map(e => theme.fg("error", ` ✗ ${e.surface}: ${safe(e.sourceName)} — ${safe(e.reason ?? "")}`)),
|
|
327
|
-
...
|
|
328
|
-
? [theme.fg("muted", "Imported entries take effect after the documented reload/new-session boundary.")]
|
|
329
|
-
: []),
|
|
355
|
+
...completionMessages,
|
|
330
356
|
].join("\n"),
|
|
331
357
|
);
|
|
332
358
|
this.#footerText.setText(theme.fg("muted", "enter/esc: close"));
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
Container,
|
|
11
11
|
fuzzyFilter,
|
|
12
|
+
fuzzyMatch,
|
|
12
13
|
getKeybindings,
|
|
13
14
|
Input,
|
|
14
15
|
matchesKey,
|
|
@@ -99,6 +100,150 @@ function computeModelRank(model: Model, roles: Record<string, RoleAssignment | u
|
|
|
99
100
|
return roles.default && modelsAreEqual(roles.default.model, model) ? 0 : 1;
|
|
100
101
|
}
|
|
101
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Compute and assign fuzzy scores to model items based on a query.
|
|
105
|
+
* Scores are based on fuzzy matching against the model's searchable text.
|
|
106
|
+
*/
|
|
107
|
+
function fuzzyTokensScore(query: string, text: string): number | undefined {
|
|
108
|
+
const tokens = query
|
|
109
|
+
.trim()
|
|
110
|
+
.split(/\s+/)
|
|
111
|
+
.filter(token => token.length > 0);
|
|
112
|
+
if (tokens.length === 0) return undefined;
|
|
113
|
+
let total = 0;
|
|
114
|
+
for (const token of tokens) {
|
|
115
|
+
const match = fuzzyMatch(token, text);
|
|
116
|
+
if (!match.matches) return undefined;
|
|
117
|
+
total += match.score;
|
|
118
|
+
}
|
|
119
|
+
return total;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function assignFuzzyScoresToModels(items: ModelItem[], query: string): void {
|
|
123
|
+
if (!query.trim()) {
|
|
124
|
+
for (const item of items) item.fuzzyScore = undefined;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
for (const item of items) {
|
|
128
|
+
// Overwrite every item so a raw-query miss cannot retain an earlier score.
|
|
129
|
+
item.fuzzyScore = fuzzyTokensScore(query, `${item.id} ${item.provider}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Compute and assign fuzzy scores to canonical model items based on a query.
|
|
135
|
+
*/
|
|
136
|
+
export function assignFuzzyScoresToCanonicalModels(items: CanonicalModelItem[], query: string): void {
|
|
137
|
+
if (!query.trim()) {
|
|
138
|
+
for (const item of items) item.fuzzyScore = undefined;
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
for (const item of items) {
|
|
142
|
+
item.fuzzyScore = fuzzyTokensScore(query, item.searchText);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface RankedModelOrderContext {
|
|
147
|
+
roles: RoleAssignments;
|
|
148
|
+
mruIndex: ReadonlyMap<string, number>;
|
|
149
|
+
providerAuthStateById: ReadonlyMap<string, ProviderAuthState>;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const MODEL_DATE_RE = /-(\d{8})$/;
|
|
153
|
+
const MODEL_LATEST_RE = /-latest$/;
|
|
154
|
+
|
|
155
|
+
/** Ranking shared by the provider view: fuzzy quality, default, MRU, provider, recency. */
|
|
156
|
+
export function compareModelItemsForRanking(a: ModelItem, b: ModelItem, context: RankedModelOrderContext): number {
|
|
157
|
+
const { roles, mruIndex, providerAuthStateById } = context;
|
|
158
|
+
const aHasFuzzyScore = a.fuzzyScore !== undefined;
|
|
159
|
+
const bHasFuzzyScore = b.fuzzyScore !== undefined;
|
|
160
|
+
if (aHasFuzzyScore || bHasFuzzyScore) {
|
|
161
|
+
const aScore = a.fuzzyScore ?? Number.MAX_SAFE_INTEGER;
|
|
162
|
+
const bScore = b.fuzzyScore ?? Number.MAX_SAFE_INTEGER;
|
|
163
|
+
if (aScore !== bScore) return aScore - bScore;
|
|
164
|
+
// Ties keep the established default-first, then MRU/provider ordering.
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const aRank = computeModelRank(a.model, roles);
|
|
168
|
+
const bRank = computeModelRank(b.model, roles);
|
|
169
|
+
if (aRank !== bRank) return aRank - bRank;
|
|
170
|
+
|
|
171
|
+
const aMru = mruIndex.get(a.selector) ?? Number.MAX_SAFE_INTEGER;
|
|
172
|
+
const bMru = mruIndex.get(b.selector) ?? Number.MAX_SAFE_INTEGER;
|
|
173
|
+
if (aMru !== bMru) return aMru - bMru;
|
|
174
|
+
|
|
175
|
+
const providerCmp = compareRankedProviders(
|
|
176
|
+
{ id: a.provider, label: a.provider, authState: providerAuthStateById.get(a.provider) ?? "none" },
|
|
177
|
+
{ id: b.provider, label: b.provider, authState: providerAuthStateById.get(b.provider) ?? "none" },
|
|
178
|
+
);
|
|
179
|
+
if (providerCmp !== 0) return providerCmp;
|
|
180
|
+
|
|
181
|
+
// Priority field (lower = better, e.g. OpenAI code backend priority values)
|
|
182
|
+
const aPri = a.model.priority ?? Number.MAX_SAFE_INTEGER;
|
|
183
|
+
const bPri = b.model.priority ?? Number.MAX_SAFE_INTEGER;
|
|
184
|
+
if (aPri !== bPri) return aPri - bPri;
|
|
185
|
+
|
|
186
|
+
// Version number descending (higher version = better model)
|
|
187
|
+
const aVer = extractVersionNumber(a.id);
|
|
188
|
+
const bVer = extractVersionNumber(b.id);
|
|
189
|
+
if (aVer !== bVer) return bVer - aVer;
|
|
190
|
+
|
|
191
|
+
const aIsLatest = MODEL_LATEST_RE.test(a.id);
|
|
192
|
+
const bIsLatest = MODEL_LATEST_RE.test(b.id);
|
|
193
|
+
const aDate = a.id.match(MODEL_DATE_RE)?.[1] ?? "";
|
|
194
|
+
const bDate = b.id.match(MODEL_DATE_RE)?.[1] ?? "";
|
|
195
|
+
|
|
196
|
+
const aHasRecency = aIsLatest || aDate !== "";
|
|
197
|
+
const bHasRecency = bIsLatest || bDate !== "";
|
|
198
|
+
if (aHasRecency !== bHasRecency) return aHasRecency ? -1 : 1;
|
|
199
|
+
if (!aHasRecency) return a.id.localeCompare(b.id);
|
|
200
|
+
if (aIsLatest !== bIsLatest) return aIsLatest ? -1 : 1;
|
|
201
|
+
if (aDate && bDate) return bDate.localeCompare(aDate);
|
|
202
|
+
return aIsLatest ? -1 : bIsLatest ? 1 : a.id.localeCompare(b.id);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Ranking shared by the canonical view: fuzzy quality, default, MRU, provider, then id. */
|
|
206
|
+
export function compareCanonicalModelItemsForRanking(
|
|
207
|
+
a: CanonicalModelItem,
|
|
208
|
+
b: CanonicalModelItem,
|
|
209
|
+
context: RankedModelOrderContext,
|
|
210
|
+
): number {
|
|
211
|
+
const { roles, mruIndex, providerAuthStateById } = context;
|
|
212
|
+
const aHasFuzzyScore = a.fuzzyScore !== undefined;
|
|
213
|
+
const bHasFuzzyScore = b.fuzzyScore !== undefined;
|
|
214
|
+
if (aHasFuzzyScore || bHasFuzzyScore) {
|
|
215
|
+
const aScore = a.fuzzyScore ?? Number.MAX_SAFE_INTEGER;
|
|
216
|
+
const bScore = b.fuzzyScore ?? Number.MAX_SAFE_INTEGER;
|
|
217
|
+
if (aScore !== bScore) return aScore - bScore;
|
|
218
|
+
// Ties keep the established default-first, then MRU/provider ordering.
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const aRank = computeModelRank(a.model, roles);
|
|
222
|
+
const bRank = computeModelRank(b.model, roles);
|
|
223
|
+
if (aRank !== bRank) return aRank - bRank;
|
|
224
|
+
|
|
225
|
+
const aKey = `${a.model.provider}/${a.model.id}`;
|
|
226
|
+
const bKey = `${b.model.provider}/${b.model.id}`;
|
|
227
|
+
const aMru = mruIndex.get(aKey) ?? Number.MAX_SAFE_INTEGER;
|
|
228
|
+
const bMru = mruIndex.get(bKey) ?? Number.MAX_SAFE_INTEGER;
|
|
229
|
+
if (aMru !== bMru) return aMru - bMru;
|
|
230
|
+
|
|
231
|
+
const providerCmp = compareRankedProviders(
|
|
232
|
+
{
|
|
233
|
+
id: a.model.provider,
|
|
234
|
+
label: a.model.provider,
|
|
235
|
+
authState: providerAuthStateById.get(a.model.provider) ?? "none",
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
id: b.model.provider,
|
|
239
|
+
label: b.model.provider,
|
|
240
|
+
authState: providerAuthStateById.get(b.model.provider) ?? "none",
|
|
241
|
+
},
|
|
242
|
+
);
|
|
243
|
+
if (providerCmp !== 0) return providerCmp;
|
|
244
|
+
return a.id.localeCompare(b.id);
|
|
245
|
+
}
|
|
246
|
+
|
|
102
247
|
interface ModelItem {
|
|
103
248
|
kind: "provider";
|
|
104
249
|
provider: string;
|
|
@@ -107,6 +252,7 @@ interface ModelItem {
|
|
|
107
252
|
selector: string;
|
|
108
253
|
thinkingLevel?: ThinkingLevel;
|
|
109
254
|
explicitThinkingLevel?: boolean;
|
|
255
|
+
fuzzyScore?: number;
|
|
110
256
|
}
|
|
111
257
|
|
|
112
258
|
interface CanonicalModelItem {
|
|
@@ -120,6 +266,7 @@ interface CanonicalModelItem {
|
|
|
120
266
|
compactSearchText: string;
|
|
121
267
|
thinkingLevel?: ThinkingLevel;
|
|
122
268
|
explicitThinkingLevel?: boolean;
|
|
269
|
+
fuzzyScore?: number;
|
|
123
270
|
}
|
|
124
271
|
|
|
125
272
|
type ScopedModelItem = ScopedModelSelection;
|
|
@@ -646,7 +793,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
646
793
|
this.#configuredDefaultChain ?? normalizeModelSelectorValue(this.#settings.getModelRole("default"));
|
|
647
794
|
if (configuredChain.length < 2) return false;
|
|
648
795
|
|
|
649
|
-
const allModels = this.#modelRegistry.getAll();
|
|
796
|
+
const allModels = this.#modelRegistry.getAll(this.#authSessionId);
|
|
650
797
|
const matchPreferences = { usageOrder: this.#settings.getStorage()?.getModelUsageOrder() };
|
|
651
798
|
return configuredChain.slice(1).some(selector => {
|
|
652
799
|
const resolved = resolveModelRoleValue(selector, allModels, {
|
|
@@ -662,7 +809,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
662
809
|
|
|
663
810
|
#loadRoleModels(): RoleAssignments {
|
|
664
811
|
const roles: RoleAssignments = {};
|
|
665
|
-
const allModels = this.#modelRegistry.getAll();
|
|
812
|
+
const allModels = this.#modelRegistry.getAll(this.#authSessionId);
|
|
666
813
|
const matchPreferences = { usageOrder: this.#settings.getStorage()?.getModelUsageOrder() };
|
|
667
814
|
const agentModelOverrides = this.#settings.get("task.agentModelOverrides");
|
|
668
815
|
const activeProfile = this.#activeModelProfile
|
|
@@ -738,7 +885,6 @@ export class ModelSelectorComponent extends Container {
|
|
|
738
885
|
}
|
|
739
886
|
|
|
740
887
|
#sortModels(models: ModelItem[], roles: RoleAssignments = this.#roles): void {
|
|
741
|
-
// Sort: default-tagged model first, then MRU, then provider ranking
|
|
742
888
|
const mruOrder = this.#settings.getStorage()?.getModelUsageOrder() ?? [];
|
|
743
889
|
const mruIndex = new Map(mruOrder.map((key, i) => [key, i]));
|
|
744
890
|
const providerAuthStateById = new Map<string, ProviderAuthState>();
|
|
@@ -747,74 +893,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
747
893
|
providerAuthStateById.set(item.provider, this.#resolveProviderAuthState(item.provider));
|
|
748
894
|
}
|
|
749
895
|
}
|
|
750
|
-
|
|
751
|
-
const modelRank = (item: ModelItem) => computeModelRank(item.model, roles);
|
|
752
|
-
|
|
753
|
-
const dateRe = /-(\d{8})$/;
|
|
754
|
-
const latestRe = /-latest$/;
|
|
755
|
-
|
|
756
|
-
models.sort((a, b) => {
|
|
757
|
-
const aKey = a.selector;
|
|
758
|
-
const bKey = b.selector;
|
|
759
|
-
|
|
760
|
-
const aRank = modelRank(a);
|
|
761
|
-
const bRank = modelRank(b);
|
|
762
|
-
if (aRank !== bRank) return aRank - bRank;
|
|
763
|
-
|
|
764
|
-
// Then MRU order (models in mruIndex come before those not in it)
|
|
765
|
-
const aMru = mruIndex.get(aKey) ?? Number.MAX_SAFE_INTEGER;
|
|
766
|
-
const bMru = mruIndex.get(bKey) ?? Number.MAX_SAFE_INTEGER;
|
|
767
|
-
if (aMru !== bMru) return aMru - bMru;
|
|
768
|
-
|
|
769
|
-
// By provider, then recency within provider
|
|
770
|
-
const providerCmp = compareRankedProviders(
|
|
771
|
-
{
|
|
772
|
-
id: a.provider,
|
|
773
|
-
label: a.provider,
|
|
774
|
-
authState: providerAuthStateById.get(a.provider) ?? "none",
|
|
775
|
-
},
|
|
776
|
-
{
|
|
777
|
-
id: b.provider,
|
|
778
|
-
label: b.provider,
|
|
779
|
-
authState: providerAuthStateById.get(b.provider) ?? "none",
|
|
780
|
-
},
|
|
781
|
-
);
|
|
782
|
-
if (providerCmp !== 0) return providerCmp;
|
|
783
|
-
|
|
784
|
-
// Priority field (lower = better, e.g. OpenAI code backend priority values)
|
|
785
|
-
const aPri = a.model.priority ?? Number.MAX_SAFE_INTEGER;
|
|
786
|
-
const bPri = b.model.priority ?? Number.MAX_SAFE_INTEGER;
|
|
787
|
-
if (aPri !== bPri) return aPri - bPri;
|
|
788
|
-
|
|
789
|
-
// Version number descending (higher version = better model)
|
|
790
|
-
const aVer = extractVersionNumber(a.id);
|
|
791
|
-
const bVer = extractVersionNumber(b.id);
|
|
792
|
-
if (aVer !== bVer) return bVer - aVer;
|
|
793
|
-
|
|
794
|
-
const aIsLatest = latestRe.test(a.id);
|
|
795
|
-
const bIsLatest = latestRe.test(b.id);
|
|
796
|
-
const aDate = a.id.match(dateRe)?.[1] ?? "";
|
|
797
|
-
const bDate = b.id.match(dateRe)?.[1] ?? "";
|
|
798
|
-
|
|
799
|
-
// Both have dates or latest tags — sort by recency
|
|
800
|
-
const aHasRecency = aIsLatest || aDate !== "";
|
|
801
|
-
const bHasRecency = bIsLatest || bDate !== "";
|
|
802
|
-
|
|
803
|
-
// Models with recency info come before those without
|
|
804
|
-
if (aHasRecency !== bHasRecency) return aHasRecency ? -1 : 1;
|
|
805
|
-
|
|
806
|
-
// If neither has recency info, fall back to alphabetical
|
|
807
|
-
if (!aHasRecency) return a.id.localeCompare(b.id);
|
|
808
|
-
|
|
809
|
-
// -latest always sorts first within recency group
|
|
810
|
-
if (aIsLatest !== bIsLatest) return aIsLatest ? -1 : 1;
|
|
811
|
-
|
|
812
|
-
// Both have dates — descending (newest first)
|
|
813
|
-
if (aDate && bDate) return bDate.localeCompare(aDate);
|
|
814
|
-
|
|
815
|
-
// One has date, other is latest — latest first
|
|
816
|
-
return aIsLatest ? -1 : bIsLatest ? 1 : a.id.localeCompare(b.id);
|
|
817
|
-
});
|
|
896
|
+
models.sort((a, b) => compareModelItemsForRanking(a, b, { roles, mruIndex, providerAuthStateById }));
|
|
818
897
|
}
|
|
819
898
|
|
|
820
899
|
#sortCanonicalModels(models: CanonicalModelItem[], roles: RoleAssignments = this.#roles): void {
|
|
@@ -826,34 +905,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
826
905
|
providerAuthStateById.set(item.model.provider, this.#resolveProviderAuthState(item.model.provider));
|
|
827
906
|
}
|
|
828
907
|
}
|
|
829
|
-
|
|
830
|
-
const modelRank = (item: CanonicalModelItem) => computeModelRank(item.model, roles);
|
|
831
|
-
|
|
832
|
-
models.sort((a, b) => {
|
|
833
|
-
const aRank = modelRank(a);
|
|
834
|
-
const bRank = modelRank(b);
|
|
835
|
-
if (aRank !== bRank) return aRank - bRank;
|
|
836
|
-
|
|
837
|
-
const aMru = mruIndex.get(`${a.model.provider}/${a.model.id}`) ?? Number.MAX_SAFE_INTEGER;
|
|
838
|
-
const bMru = mruIndex.get(`${b.model.provider}/${b.model.id}`) ?? Number.MAX_SAFE_INTEGER;
|
|
839
|
-
if (aMru !== bMru) return aMru - bMru;
|
|
840
|
-
|
|
841
|
-
const providerCmp = compareRankedProviders(
|
|
842
|
-
{
|
|
843
|
-
id: a.model.provider,
|
|
844
|
-
label: a.model.provider,
|
|
845
|
-
authState: providerAuthStateById.get(a.model.provider) ?? "none",
|
|
846
|
-
},
|
|
847
|
-
{
|
|
848
|
-
id: b.model.provider,
|
|
849
|
-
label: b.model.provider,
|
|
850
|
-
authState: providerAuthStateById.get(b.model.provider) ?? "none",
|
|
851
|
-
},
|
|
852
|
-
);
|
|
853
|
-
if (providerCmp !== 0) return providerCmp;
|
|
854
|
-
|
|
855
|
-
return a.id.localeCompare(b.id);
|
|
856
|
-
});
|
|
908
|
+
models.sort((a, b) => compareCanonicalModelItemsForRanking(a, b, { roles, mruIndex, providerAuthStateById }));
|
|
857
909
|
}
|
|
858
910
|
|
|
859
911
|
#buildScopedModelItems(): ModelItem[] {
|
|
@@ -869,7 +921,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
869
921
|
}
|
|
870
922
|
|
|
871
923
|
#buildAvailableModelItems(): ModelItem[] {
|
|
872
|
-
return this.#modelRegistry.getAvailable().map((model: Model) => ({
|
|
924
|
+
return this.#modelRegistry.getAvailable(this.#authSessionId).map((model: Model) => ({
|
|
873
925
|
kind: "provider",
|
|
874
926
|
provider: model.provider,
|
|
875
927
|
id: model.id,
|
|
@@ -1205,10 +1257,12 @@ export class ModelSelectorComponent extends Container {
|
|
|
1205
1257
|
? alphaFiltered
|
|
1206
1258
|
: baseCanonicalModels;
|
|
1207
1259
|
const fuzzyMatches = fuzzyFilter(fuzzySource, query, ({ searchText }) => searchText);
|
|
1260
|
+
assignFuzzyScoresToCanonicalModels(fuzzyMatches, query);
|
|
1208
1261
|
this.#sortCanonicalModels(fuzzyMatches);
|
|
1209
1262
|
this.#filteredCanonicalModels = fuzzyMatches;
|
|
1210
1263
|
} else {
|
|
1211
1264
|
const fuzzyMatches = fuzzyFilter(baseModels, query, ({ id, provider }) => `${id} ${provider}`);
|
|
1265
|
+
assignFuzzyScoresToModels(fuzzyMatches, query);
|
|
1212
1266
|
this.#sortModels(fuzzyMatches);
|
|
1213
1267
|
this.#filteredModels = fuzzyMatches;
|
|
1214
1268
|
}
|
|
@@ -1256,7 +1310,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
1256
1310
|
if (isInheritedRoleSelector(configuredSelector)) continue;
|
|
1257
1311
|
const selectors = resolveConfiguredModelPatterns(configuredSelector, this.#settings);
|
|
1258
1312
|
for (const selector of selectors.length > 0 ? selectors : [configuredSelector]) {
|
|
1259
|
-
const resolved = resolveModelRoleValue(selector, this.#modelRegistry.getAll(), {
|
|
1313
|
+
const resolved = resolveModelRoleValue(selector, this.#modelRegistry.getAll(this.#authSessionId), {
|
|
1260
1314
|
settings: this.#settings,
|
|
1261
1315
|
matchPreferences: { usageOrder: this.#settings.getStorage()?.getModelUsageOrder() },
|
|
1262
1316
|
modelRegistry: this.#modelRegistry,
|
|
@@ -1369,7 +1423,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
1369
1423
|
}
|
|
1370
1424
|
|
|
1371
1425
|
#getProfileAvailableModels(): Model[] {
|
|
1372
|
-
return this.#modelRegistry.getAvailable();
|
|
1426
|
+
return this.#modelRegistry.getAvailable(this.#authSessionId);
|
|
1373
1427
|
}
|
|
1374
1428
|
|
|
1375
1429
|
#createProfileResolutionRegistry(availableModels: readonly Model[]) {
|
|
@@ -2108,7 +2162,7 @@ export class ModelSelectorComponent extends Container {
|
|
|
2108
2162
|
for (const role of PROFILE_ROLE_PREVIEW_ORDER) {
|
|
2109
2163
|
const selector = profile.modelMapping[role];
|
|
2110
2164
|
if (!selector) continue;
|
|
2111
|
-
const resolved = resolveModelRoleValue(selector, this.#modelRegistry.getAll(), {
|
|
2165
|
+
const resolved = resolveModelRoleValue(selector, this.#modelRegistry.getAll(this.#authSessionId), {
|
|
2112
2166
|
settings: this.#settings,
|
|
2113
2167
|
matchPreferences: { usageOrder: this.#settings.getStorage()?.getModelUsageOrder() },
|
|
2114
2168
|
modelRegistry: this.#modelRegistry,
|
|
@@ -3,6 +3,7 @@ import { APP_NAME } from "@gajae-code/utils";
|
|
|
3
3
|
import { formatBuildLabel } from "../../build-metadata";
|
|
4
4
|
import { formatKeyHint, type KeyDisplayContext } from "../../config/keybindings";
|
|
5
5
|
import { type ThemeColor, theme } from "../../modes/theme/theme";
|
|
6
|
+
import { sanitizeStatusText } from "../shared";
|
|
6
7
|
|
|
7
8
|
export interface RecentSession {
|
|
8
9
|
name: string;
|
|
@@ -536,7 +537,8 @@ export class WelcomeComponent implements Component {
|
|
|
536
537
|
}
|
|
537
538
|
|
|
538
539
|
#pill(icon: string, text: string, color: ThemeColor): string {
|
|
539
|
-
|
|
540
|
+
const safeText = sanitizeStatusText(text);
|
|
541
|
+
return `${theme.fg("borderMuted", "[")} ${theme.fg(color, icon)} ${theme.fg("muted", safeText)} ${theme.fg(
|
|
540
542
|
"borderMuted",
|
|
541
543
|
"]",
|
|
542
544
|
)}`;
|