@gajae-code/coding-agent 0.11.11 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +131 -4
- package/dist/types/async/job-manager.d.ts +17 -3
- package/dist/types/cli/read-cli.d.ts +1 -0
- package/dist/types/commands/deep-interview.d.ts +9 -0
- package/dist/types/commands/harness.d.ts +22 -0
- package/dist/types/commands/read.d.ts +6 -0
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/provider-auth-health.d.ts +14 -0
- package/dist/types/config/provider-ranking.d.ts +59 -0
- package/dist/types/config/settings-schema.d.ts +83 -1
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/exa/mcp-client.d.ts +10 -1
- package/dist/types/exec/bash-executor.d.ts +45 -12
- package/dist/types/extensibility/extensions/types.d.ts +38 -4
- package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
- package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
- package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
- package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
- package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
- package/dist/types/extensibility/shared-events.d.ts +6 -0
- package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +5 -12
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +17 -32
- package/dist/types/gjc-runtime/deep-interview-stage.d.ts +37 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +4 -135
- package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
- package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +70 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +5 -46
- package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +27 -1
- package/dist/types/gjc-runtime/team-store.d.ts +12 -0
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
- package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +17 -0
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +31 -80
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -5
- package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
- package/dist/types/main.d.ts +1 -1
- package/dist/types/memories/index.d.ts +2 -0
- package/dist/types/modes/acp/acp-agent.d.ts +10 -19
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
- package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
- package/dist/types/modes/components/read-tool-group.d.ts +4 -4
- package/dist/types/modes/components/session-observer-overlay.d.ts +22 -0
- package/dist/types/modes/components/settings-selector.d.ts +11 -0
- package/dist/types/modes/components/status-line/gh.d.ts +5 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
- package/dist/types/modes/controllers/event-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
- package/dist/types/reminders/star-reminder.d.ts +3 -13
- package/dist/types/runtime-mcp/manager.d.ts +1 -0
- package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
- package/dist/types/sdk/acp/adapter.d.ts +3 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +5 -0
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +4 -1
- package/dist/types/sdk/bus/config.d.ts +6 -2
- package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
- package/dist/types/sdk/bus/index.d.ts +44 -1
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +44 -0
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
- package/dist/types/sdk/bus/reconciliation-store.d.ts +69 -0
- package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
- package/dist/types/sdk/bus/rich-render.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
- package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +11 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
- package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
- package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/sdk/host/query/revision-store.d.ts +2 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/prompt-status.d.ts +23 -3
- package/dist/types/sdk/session.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +82 -12
- package/dist/types/session/artifacts.d.ts +8 -0
- package/dist/types/session/blob-store.d.ts +57 -4
- package/dist/types/session/internal/managed-session-storage.d.ts +8 -1
- package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
- package/dist/types/session/session-manager.d.ts +48 -19
- package/dist/types/session/session-storage.d.ts +4 -0
- package/dist/types/session/streaming-output.d.ts +96 -12
- package/dist/types/setup/credential-import.d.ts +12 -0
- package/dist/types/skill-state/active-state.d.ts +12 -4
- package/dist/types/skill-state/workflow-hud.d.ts +9 -0
- package/dist/types/task/executor.d.ts +3 -2
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/task/provider-retry-status.d.ts +8 -0
- package/dist/types/task/receipt.d.ts +7 -1
- package/dist/types/task/types.d.ts +23 -0
- package/dist/types/tools/ask-answer-registry.d.ts +2 -2
- package/dist/types/tools/bash-interactive.d.ts +4 -1
- package/dist/types/tools/bash.d.ts +3 -1
- package/dist/types/tools/browser/launch.d.ts +7 -0
- package/dist/types/tools/fetch.d.ts +17 -1
- package/dist/types/tools/image-gen.d.ts +4 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/output-meta.d.ts +44 -3
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read-internals.d.ts +12 -0
- package/dist/types/tools/read.d.ts +45 -7
- package/dist/types/tools/resource-gc.d.ts +4 -0
- package/dist/types/tools/review.d.ts +5 -7
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/tools/tool-result.d.ts +7 -1
- package/dist/types/utils/gh.d.ts +13 -0
- package/dist/types/utils/image-resize.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +2 -0
- package/dist/types/web/search/providers/searxng.d.ts +7 -0
- package/dist/types/web/search/providers/xai.d.ts +2 -0
- package/package.json +11 -13
- package/scripts/acp-conformance-agent.ts +218 -0
- package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
- package/scripts/capture-gjc-bundle-settings.ts +306 -0
- package/scripts/capture-sticky-viewport-showcase.ts +292 -0
- package/scripts/generate-sdk-operation-inventory.ts +5 -0
- package/scripts/resident-memory-bench.ts +1341 -0
- package/scripts/run-acp-conformance.ts +285 -0
- package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
- package/scripts/verify-sticky-viewport-showcase.ts +611 -0
- package/src/async/job-manager.ts +78 -20
- package/src/capability/index.ts +8 -0
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/plugin-cli.ts +176 -18
- package/src/cli/read-cli.ts +2 -1
- package/src/cli.ts +1 -0
- package/src/commands/deep-interview.ts +29 -9
- package/src/commands/harness.ts +35 -12
- package/src/commands/read.ts +11 -2
- package/src/commands/team.ts +20 -2
- package/src/config/file-lock.ts +11 -2
- package/src/config/model-registry.ts +21 -2
- package/src/config/provider-auth-health.ts +42 -0
- package/src/config/provider-ranking.ts +119 -0
- package/src/config/settings-schema.ts +74 -1
- package/src/config/settings.ts +246 -108
- package/src/coordinator-mcp/question-gate-codec.ts +1 -1
- package/src/coordinator-mcp/server.ts +5 -12
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +230 -82
- package/src/defaults/gjc/skills/ralplan/SKILL.md +77 -41
- package/src/defaults/gjc/skills/team/SKILL.md +3 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +62 -39
- package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
- package/src/defaults/gjc-defaults.ts +4 -4
- package/src/eval/py/executor.ts +7 -2
- package/src/exa/mcp-client.ts +12 -3
- package/src/exec/bash-executor.ts +144 -27
- package/src/extensibility/extensions/runner.ts +15 -0
- package/src/extensibility/extensions/types.ts +46 -5
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
- package/src/extensibility/gjc-plugins/index.ts +19 -2
- package/src/extensibility/gjc-plugins/installer.ts +189 -50
- package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
- package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
- package/src/extensibility/gjc-plugins/observability.ts +3 -3
- package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
- package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
- package/src/extensibility/gjc-plugins/schema.ts +84 -12
- package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
- package/src/extensibility/gjc-plugins/types.ts +141 -0
- package/src/extensibility/gjc-plugins/validation.ts +9 -0
- package/src/extensibility/shared-events.ts +5 -0
- package/src/gjc-runtime/deep-interview-ambiguity.ts +47 -82
- package/src/gjc-runtime/deep-interview-recorder.ts +227 -310
- package/src/gjc-runtime/deep-interview-runtime.ts +109 -270
- package/src/gjc-runtime/deep-interview-stage.ts +1016 -0
- package/src/gjc-runtime/deep-interview-state.ts +12 -943
- package/src/gjc-runtime/gc-render.ts +1 -0
- package/src/gjc-runtime/gc-runtime.ts +11 -1
- package/src/gjc-runtime/launch-tmux.ts +25 -6
- package/src/gjc-runtime/managed-owner-admission.ts +1 -1
- package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
- package/src/gjc-runtime/ralplan-runtime.ts +1149 -98
- package/src/gjc-runtime/state-runtime.ts +2 -1
- package/src/gjc-runtime/state-writer.ts +70 -222
- package/src/gjc-runtime/team-launch.ts +42 -5
- package/src/gjc-runtime/team-runtime.ts +1085 -40
- package/src/gjc-runtime/team-store.ts +32 -0
- package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
- package/src/gjc-runtime/team-worker-memory-guard.ts +363 -0
- package/src/gjc-runtime/team-workers.ts +1 -0
- package/src/gjc-runtime/tmux-owner-isolation.ts +28 -0
- package/src/gjc-runtime/tmux-sessions.ts +58 -13
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +414 -618
- package/src/gjc-runtime/workflow-manifest.generated.json +105 -449
- package/src/gjc-runtime/workflow-manifest.ts +38 -247
- package/src/hooks/native-skill-hook.ts +17 -4
- package/src/hooks/skill-state.ts +1 -23
- package/src/internal-urls/docs-index.generated.ts +21 -22
- package/src/internal-urls/local-root-gc.ts +127 -0
- package/src/main.ts +9 -5
- package/src/memories/index.ts +10 -0
- package/src/modes/DESIGN.md +98 -0
- package/src/modes/acp/acp-agent.ts +339 -191
- package/src/modes/acp/acp-event-mapper.ts +14 -7
- package/src/modes/acp/acp-mode.ts +39 -3
- package/src/modes/components/assistant-message.ts +123 -22
- package/src/modes/components/gjc-bundle-settings.ts +508 -0
- package/src/modes/components/irc-sidebar.ts +176 -62
- package/src/modes/components/model-selector.ts +61 -4
- package/src/modes/components/notifications-settings-editor.ts +12 -1
- package/src/modes/components/oauth-selector.ts +96 -28
- package/src/modes/components/read-tool-group.ts +82 -14
- package/src/modes/components/session-observer-overlay.ts +457 -83
- package/src/modes/components/settings-selector.ts +116 -23
- package/src/modes/components/status-line/gh.ts +16 -0
- package/src/modes/components/tool-execution.ts +138 -27
- package/src/modes/components/tool-status-header.ts +3 -14
- package/src/modes/components/transcript-viewer-overlay.ts +99 -24
- package/src/modes/controllers/command-controller.ts +4 -0
- package/src/modes/controllers/event-controller.ts +109 -27
- package/src/modes/controllers/extension-ui-controller.ts +26 -2
- package/src/modes/controllers/input-controller.ts +18 -3
- package/src/modes/controllers/selector-controller.ts +127 -36
- package/src/modes/interactive-mode.ts +62 -3
- package/src/modes/irc-observation-ledger.ts +71 -15
- package/src/modes/runtime-init.ts +22 -2
- package/src/modes/types.ts +2 -0
- package/src/modes/utils/ui-helpers.ts +94 -1
- package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
- package/src/prompts/agents/architect.md +9 -1
- package/src/prompts/agents/critic.md +9 -0
- package/src/prompts/system/eager-todo.md +8 -4
- package/src/prompts/system/system-prompt.md +11 -5
- package/src/prompts/tools/bash.md +5 -5
- package/src/prompts/tools/read.md +4 -2
- package/src/prompts/tools/search-tool-bm25.md +5 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/reminders/star-reminder.ts +4 -42
- package/src/runtime-mcp/manager.ts +19 -4
- package/src/runtime-mcp/smithery-auth.ts +17 -2
- package/src/runtime-mcp/smithery-connect.ts +11 -1
- package/src/sdk/acp/adapter.ts +22 -6
- package/src/sdk/broker/lifecycle.ts +25 -6
- package/src/sdk/broker/transport.ts +35 -3
- package/src/sdk/bus/attachment-registry.ts +5 -1
- package/src/sdk/bus/chat-daemon-cli.ts +4 -39
- package/src/sdk/bus/chat-daemon-control.ts +6 -3
- package/src/sdk/bus/config.ts +18 -2
- package/src/sdk/bus/control-drain-lease.ts +104 -0
- package/src/sdk/bus/index.ts +984 -146
- package/src/sdk/bus/kind-aware-reconciliation.ts +317 -0
- package/src/sdk/bus/lifecycle-commands.ts +4 -1
- package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
- package/src/sdk/bus/prompt-reconciliation.ts +2 -1
- package/src/sdk/bus/reconciliation-store.ts +303 -0
- package/src/sdk/bus/rich-draft.ts +1 -1
- package/src/sdk/bus/rich-render.ts +2 -2
- package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
- package/src/sdk/bus/telegram-cli.ts +33 -8
- package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +11 -4
- package/src/sdk/bus/telegram-daemon.ts +916 -23
- package/src/sdk/bus/telegram-reference.ts +40 -3
- package/src/sdk/bus/threaded-render.ts +48 -3
- package/src/sdk/bus/topic-registry.ts +20 -0
- package/src/sdk/host/control/dispatch.ts +5 -1
- package/src/sdk/host/control/operations.ts +1 -1
- package/src/sdk/host/host.ts +23 -1
- package/src/sdk/host/query/handlers.ts +55 -0
- package/src/sdk/host/query/revision-store.ts +36 -2
- package/src/sdk/host/reverse-leases.ts +44 -7
- package/src/sdk/mcp/server.ts +46 -18
- package/src/sdk/prompt-status.ts +16 -3
- package/src/sdk/protocol/operation-inventory.generated.json +51 -0
- package/src/sdk/protocol/operation-registry.ts +7 -2
- package/src/sdk/session.ts +101 -10
- package/src/session/agent-session.ts +1286 -220
- package/src/session/artifacts.ts +22 -0
- package/src/session/auth-broker-config.ts +10 -3
- package/src/session/blob-store.ts +915 -24
- package/src/session/internal/managed-session-scope.ts +44 -6
- package/src/session/internal/managed-session-storage.ts +48 -6
- package/src/session/memory-guard-checkpoint-participant.ts +131 -0
- package/src/session/session-manager.ts +2364 -438
- package/src/session/session-storage.ts +9 -1
- package/src/session/streaming-output.ts +500 -111
- package/src/setup/credential-import.ts +75 -13
- package/src/setup/provider-onboarding.ts +19 -4
- package/src/skill-state/active-state.ts +32 -10
- package/src/skill-state/workflow-hud.ts +42 -2
- package/src/skill-state/workflow-mutation-guard.ts +560 -8
- package/src/task/executor.ts +122 -39
- package/src/task/index.ts +23 -14
- package/src/task/provider-retry-status.ts +16 -0
- package/src/task/receipt.ts +23 -7
- package/src/task/render.ts +6 -2
- package/src/task/types.ts +108 -0
- package/src/tools/ask-answer-registry.ts +12 -6
- package/src/tools/ask.ts +169 -118
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash-interactive.ts +8 -3
- package/src/tools/bash.ts +503 -60
- package/src/tools/browser/launch.ts +41 -6
- package/src/tools/fetch.ts +114 -23
- package/src/tools/find.ts +1 -0
- package/src/tools/image-gen.ts +29 -5
- package/src/tools/index.ts +4 -0
- package/src/tools/output-meta.ts +281 -20
- package/src/tools/path-utils.ts +8 -3
- package/src/tools/read-internals.ts +44 -0
- package/src/tools/read.ts +1560 -310
- package/src/tools/resource-gc.ts +182 -18
- package/src/tools/review.ts +5 -7
- package/src/tools/search.ts +1 -0
- package/src/tools/subagent-render.ts +6 -2
- package/src/tools/subagent.ts +6 -0
- package/src/tools/telegram-send.ts +6 -3
- package/src/tools/tool-result.ts +14 -1
- package/src/utils/gh.ts +39 -0
- package/src/utils/image-resize.ts +3 -0
- package/src/web/search/providers/anthropic.ts +4 -4
- package/src/web/search/providers/codex.ts +1 -1
- package/src/web/search/providers/kimi.ts +15 -5
- package/src/web/search/providers/searxng.ts +47 -4
- package/src/web/search/providers/xai.ts +7 -2
- package/dist/types/gjc-runtime/deep-interview-draft.d.ts +0 -8
- package/dist/types/gjc-runtime/deep-interview-payload.d.ts +0 -41
- package/dist/types/gjc-runtime/deep-interview-repair.d.ts +0 -17
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
- package/src/gjc-runtime/deep-interview-draft.ts +0 -843
- package/src/gjc-runtime/deep-interview-payload.ts +0 -262
- package/src/gjc-runtime/deep-interview-repair.ts +0 -1674
- package/src/gjc-runtime/ultragoal-pipeline.ts +0 -306
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
1
2
|
import {
|
|
2
3
|
type Component,
|
|
3
4
|
padding,
|
|
@@ -21,6 +22,46 @@ const IRC_SIDEBAR_MAX_RENDER_SOURCE_UTF8_BYTES = 64 * 1_024;
|
|
|
21
22
|
const IRC_SIDEBAR_OLDER_MESSAGES_ELISION = "… older IRC messages elided …";
|
|
22
23
|
const IRC_SIDEBAR_MESSAGE_ELISION = " … message elided …";
|
|
23
24
|
|
|
25
|
+
export const __ircSidebarPerfCounters = {
|
|
26
|
+
enabled: false,
|
|
27
|
+
projectionMemoHits: 0,
|
|
28
|
+
projectionMemoMisses: 0,
|
|
29
|
+
recordsVisited: 0,
|
|
30
|
+
sourceBytes: 0,
|
|
31
|
+
rows: 0,
|
|
32
|
+
styledCacheHits: 0,
|
|
33
|
+
styledCacheMisses: 0,
|
|
34
|
+
wrapCalls: 0,
|
|
35
|
+
snapshot() {
|
|
36
|
+
return {
|
|
37
|
+
projectionMemoHits: this.projectionMemoHits,
|
|
38
|
+
projectionMemoMisses: this.projectionMemoMisses,
|
|
39
|
+
recordsVisited: this.recordsVisited,
|
|
40
|
+
sourceBytes: this.sourceBytes,
|
|
41
|
+
rows: this.rows,
|
|
42
|
+
styledCacheHits: this.styledCacheHits,
|
|
43
|
+
styledCacheMisses: this.styledCacheMisses,
|
|
44
|
+
wrapCalls: this.wrapCalls,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
enable(): void {
|
|
48
|
+
this.enabled = true;
|
|
49
|
+
},
|
|
50
|
+
disable(): void {
|
|
51
|
+
this.enabled = false;
|
|
52
|
+
},
|
|
53
|
+
reset(): void {
|
|
54
|
+
this.projectionMemoHits = 0;
|
|
55
|
+
this.projectionMemoMisses = 0;
|
|
56
|
+
this.recordsVisited = 0;
|
|
57
|
+
this.sourceBytes = 0;
|
|
58
|
+
this.rows = 0;
|
|
59
|
+
this.styledCacheHits = 0;
|
|
60
|
+
this.styledCacheMisses = 0;
|
|
61
|
+
this.wrapCalls = 0;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
24
65
|
/** Computes transcript/sidebar widths while preserving at least half the terminal for the transcript. */
|
|
25
66
|
export function computeIrcSplitWidths(width: number): {
|
|
26
67
|
leftWidth: number;
|
|
@@ -34,12 +75,7 @@ export function computeIrcSplitWidths(width: number): {
|
|
|
34
75
|
0,
|
|
35
76
|
Math.min(preferredSidebar, normalizedWidth - IRC_SEPARATOR_WIDTH - transcriptFloor),
|
|
36
77
|
);
|
|
37
|
-
|
|
38
|
-
// The sidebar yields entirely rather than rendering below its readable minimum.
|
|
39
|
-
if (sidebarWidth < IRC_SIDEBAR_MIN_WIDTH) {
|
|
40
|
-
return { leftWidth: normalizedWidth, separatorWidth: 0, rightWidth: 0 };
|
|
41
|
-
}
|
|
42
|
-
|
|
78
|
+
if (sidebarWidth < IRC_SIDEBAR_MIN_WIDTH) return { leftWidth: normalizedWidth, separatorWidth: 0, rightWidth: 0 };
|
|
43
79
|
return {
|
|
44
80
|
leftWidth: normalizedWidth - IRC_SEPARATOR_WIDTH - sidebarWidth,
|
|
45
81
|
separatorWidth: IRC_SEPARATOR_WIDTH,
|
|
@@ -47,52 +83,99 @@ export function computeIrcSplitWidths(width: number): {
|
|
|
47
83
|
};
|
|
48
84
|
}
|
|
49
85
|
|
|
50
|
-
|
|
51
|
-
|
|
86
|
+
type SemanticLine = Readonly<{
|
|
87
|
+
kind: "header" | "body" | "elision" | "blank";
|
|
88
|
+
text: string;
|
|
89
|
+
sender?: string;
|
|
90
|
+
recipient?: string;
|
|
91
|
+
time?: string;
|
|
92
|
+
}>;
|
|
93
|
+
export type IrcSidebarSemanticProjection = Readonly<{ token: string; lines: readonly SemanticLine[] }>;
|
|
94
|
+
const projectionMemo = new WeakMap<
|
|
95
|
+
IrcObservationLedger,
|
|
96
|
+
{ epoch: number; width: number; projection: IrcSidebarSemanticProjection }
|
|
97
|
+
>();
|
|
98
|
+
|
|
99
|
+
function semanticProjectionToken(lines: readonly SemanticLine[]): string {
|
|
100
|
+
const hash = crypto.createHash("sha256");
|
|
101
|
+
const length = Buffer.allocUnsafe(4);
|
|
102
|
+
const writeField = (value: string | undefined): void => {
|
|
103
|
+
length.writeUInt32BE(value === undefined ? 0xffffffff : Buffer.byteLength(value, "utf8"));
|
|
104
|
+
hash.update(length);
|
|
105
|
+
if (value !== undefined) hash.update(value, "utf8");
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
hash.update("gjc:irc:sidebar-semantic-projection:v1\0");
|
|
109
|
+
length.writeUInt32BE(lines.length);
|
|
110
|
+
hash.update(length);
|
|
111
|
+
for (const line of lines) {
|
|
112
|
+
writeField(line.kind);
|
|
113
|
+
writeField(line.text);
|
|
114
|
+
writeField(line.sender);
|
|
115
|
+
writeField(line.recipient);
|
|
116
|
+
writeField(line.time);
|
|
117
|
+
}
|
|
118
|
+
return hash.digest("hex");
|
|
52
119
|
}
|
|
53
120
|
|
|
54
|
-
function
|
|
121
|
+
function projectRecord(
|
|
55
122
|
record: IrcObservationRecord,
|
|
56
123
|
width: number,
|
|
57
|
-
componentTheme: IrcSidebarTheme,
|
|
58
124
|
maxRows: number,
|
|
59
125
|
maxSourceUtf8Bytes: number,
|
|
60
|
-
): { lines:
|
|
126
|
+
): { lines: SemanticLine[]; sourceUtf8Bytes: number; truncated: boolean } {
|
|
61
127
|
const bodyWidth = Math.max(1, width - 2);
|
|
62
128
|
const sourceLimit = Math.min(maxSourceUtf8Bytes, Math.max(0, maxRows - 1) * bodyWidth);
|
|
63
129
|
const clipped = projectIrcText(record.text, sourceLimit);
|
|
64
130
|
const block = formatIrcMessageBlock({ ...record, text: clipped.text });
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
131
|
+
const lines: SemanticLine[] = [
|
|
132
|
+
{
|
|
133
|
+
kind: "header",
|
|
134
|
+
text: `${block.sender} → ${block.recipient} · ${block.time}`,
|
|
135
|
+
sender: block.sender,
|
|
136
|
+
recipient: block.recipient,
|
|
137
|
+
time: block.time,
|
|
138
|
+
},
|
|
139
|
+
];
|
|
68
140
|
let truncated = clipped.truncated;
|
|
69
|
-
|
|
70
141
|
body: for (const bodyLine of block.bodyLines) {
|
|
142
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.wrapCalls++;
|
|
71
143
|
for (const wrappedLine of wrapTextWithAnsi(bodyLine, bodyWidth)) {
|
|
72
144
|
if (lines.length >= maxRows) {
|
|
73
145
|
truncated = true;
|
|
74
146
|
break body;
|
|
75
147
|
}
|
|
76
|
-
lines.push(
|
|
148
|
+
lines.push({ kind: "body", text: ` ${wrappedLine}` });
|
|
77
149
|
}
|
|
78
150
|
}
|
|
79
151
|
if (truncated && maxRows > 1) {
|
|
80
|
-
const marker =
|
|
81
|
-
if (lines.length >= maxRows) lines[maxRows - 1] =
|
|
82
|
-
else lines.push(
|
|
152
|
+
const marker: SemanticLine = { kind: "elision", text: IRC_SIDEBAR_MESSAGE_ELISION };
|
|
153
|
+
if (lines.length >= maxRows) lines[maxRows - 1] = marker;
|
|
154
|
+
else lines.push(marker);
|
|
83
155
|
}
|
|
84
156
|
return { lines, sourceUtf8Bytes: clipped.utf8Bytes, truncated };
|
|
85
157
|
}
|
|
86
158
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
159
|
+
/** The authoritative bounded, display-neutral IRC sidebar projection. */
|
|
160
|
+
export function getIrcSidebarSemanticProjection(
|
|
161
|
+
ledger: IrcObservationLedger,
|
|
162
|
+
width: number,
|
|
163
|
+
): IrcSidebarSemanticProjection {
|
|
164
|
+
if (width <= 0) return { token: "", lines: [] };
|
|
165
|
+
const memo = projectionMemo.get(ledger);
|
|
166
|
+
const cachedProjection = memo?.epoch === ledger.mutationEpoch && memo.width === width ? memo.projection : undefined;
|
|
167
|
+
if (cachedProjection) {
|
|
168
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.projectionMemoHits++;
|
|
169
|
+
return cachedProjection;
|
|
170
|
+
}
|
|
171
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.projectionMemoMisses++;
|
|
172
|
+
const newestFirstBlocks: SemanticLine[][] = [];
|
|
92
173
|
let renderedRows = 0;
|
|
93
174
|
let renderedSourceUtf8Bytes = 0;
|
|
94
175
|
let omittedOlderRecords = false;
|
|
176
|
+
const records = ledger.getSidebarRecords();
|
|
95
177
|
for (let index = records.length - 1; index >= 0; index--) {
|
|
178
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.recordsVisited++;
|
|
96
179
|
const separatorRows = newestFirstBlocks.length > 0 ? 1 : 0;
|
|
97
180
|
const availableRows = IRC_SIDEBAR_MAX_RENDER_ROWS - renderedRows - separatorRows - 2;
|
|
98
181
|
const availableSourceUtf8Bytes = IRC_SIDEBAR_MAX_RENDER_SOURCE_UTF8_BYTES - renderedSourceUtf8Bytes;
|
|
@@ -101,32 +184,32 @@ function renderSidebarRecords(ledger: IrcObservationLedger, width: number, compo
|
|
|
101
184
|
omittedOlderRecords = true;
|
|
102
185
|
break;
|
|
103
186
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
availableSourceUtf8Bytes,
|
|
111
|
-
);
|
|
112
|
-
newestFirstBlocks.push(rendered.lines);
|
|
113
|
-
renderedRows += separatorRows + rendered.lines.length;
|
|
114
|
-
renderedSourceUtf8Bytes += rendered.sourceUtf8Bytes;
|
|
115
|
-
if (rendered.truncated) {
|
|
187
|
+
const projected = projectRecord(records[index], width, availableRows, availableSourceUtf8Bytes);
|
|
188
|
+
newestFirstBlocks.push(projected.lines);
|
|
189
|
+
renderedRows += separatorRows + projected.lines.length;
|
|
190
|
+
renderedSourceUtf8Bytes += projected.sourceUtf8Bytes;
|
|
191
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.sourceBytes += projected.sourceUtf8Bytes;
|
|
192
|
+
if (projected.truncated) {
|
|
116
193
|
omittedOlderRecords = index > 0;
|
|
117
194
|
break;
|
|
118
195
|
}
|
|
119
196
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
lines.push(truncateToWidth(componentTheme.fg("dim", IRC_SIDEBAR_OLDER_MESSAGES_ELISION), width));
|
|
124
|
-
}
|
|
197
|
+
const lines: SemanticLine[] = omittedOlderRecords
|
|
198
|
+
? [{ kind: "elision", text: IRC_SIDEBAR_OLDER_MESSAGES_ELISION }]
|
|
199
|
+
: [];
|
|
125
200
|
for (const block of newestFirstBlocks.reverse()) {
|
|
126
|
-
if (lines.length > 0) lines.push("");
|
|
201
|
+
if (lines.length > 0) lines.push({ kind: "blank", text: "" });
|
|
127
202
|
lines.push(...block);
|
|
128
203
|
}
|
|
129
|
-
|
|
204
|
+
const bounded = lines.slice(0, IRC_SIDEBAR_MAX_RENDER_ROWS);
|
|
205
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.rows += bounded.length;
|
|
206
|
+
const projection = { token: semanticProjectionToken(bounded), lines: bounded };
|
|
207
|
+
projectionMemo.set(ledger, { epoch: ledger.mutationEpoch, width, projection });
|
|
208
|
+
return projection;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function getIrcSidebarSemanticToken(ledger: IrcObservationLedger, width: number): string {
|
|
212
|
+
return getIrcSidebarSemanticProjection(ledger, width).token;
|
|
130
213
|
}
|
|
131
214
|
|
|
132
215
|
export interface IrcSidebarTheme {
|
|
@@ -134,64 +217,96 @@ export interface IrcSidebarTheme {
|
|
|
134
217
|
bold(text: string): string;
|
|
135
218
|
readonly boxSharp: { readonly vertical: string };
|
|
136
219
|
}
|
|
137
|
-
|
|
138
220
|
export type IrcSidebarThemeSource = IrcSidebarTheme | (() => IrcSidebarTheme);
|
|
139
221
|
|
|
140
222
|
/** Read-only IRC history alongside the active transcript. */
|
|
141
223
|
export class IrcSplitViewComponent implements ViewportAnchorProvider {
|
|
142
224
|
#visible = false;
|
|
225
|
+
#themeGeneration = 0;
|
|
226
|
+
#styledMemo:
|
|
227
|
+
| { token: string; width: number; themeGeneration: number; theme: IrcSidebarTheme; lines: string[] }
|
|
228
|
+
| undefined;
|
|
143
229
|
|
|
144
230
|
constructor(
|
|
145
231
|
private readonly leftPane: Component,
|
|
146
232
|
private readonly ledger: IrcObservationLedger,
|
|
147
233
|
private readonly componentTheme: IrcSidebarThemeSource,
|
|
148
234
|
) {}
|
|
149
|
-
|
|
150
235
|
get visible(): boolean {
|
|
151
236
|
return this.#visible;
|
|
152
237
|
}
|
|
153
|
-
|
|
154
238
|
effectiveSidebarVisible(width = process.stdout.columns ?? 0): boolean {
|
|
155
239
|
return this.#visible && computeIrcSplitWidths(width).rightWidth > 0;
|
|
156
240
|
}
|
|
157
|
-
|
|
158
241
|
setVisible(visible: boolean): void {
|
|
159
|
-
if (this.#visible
|
|
160
|
-
|
|
161
|
-
|
|
242
|
+
if (this.#visible !== visible) {
|
|
243
|
+
this.#visible = visible;
|
|
244
|
+
this.invalidate();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
invalidateTheme(): void {
|
|
248
|
+
this.#themeGeneration++;
|
|
249
|
+
this.#styledMemo = undefined;
|
|
250
|
+
}
|
|
251
|
+
resetSource(): void {
|
|
252
|
+
projectionMemo.delete(this.ledger);
|
|
253
|
+
this.#styledMemo = undefined;
|
|
162
254
|
}
|
|
163
|
-
|
|
164
255
|
render(width: number): string[] {
|
|
165
256
|
return this.renderWithViewportAnchors(width).lines;
|
|
166
257
|
}
|
|
167
|
-
|
|
258
|
+
#renderSidebar(width: number, componentTheme: IrcSidebarTheme): string[] {
|
|
259
|
+
const projection = getIrcSidebarSemanticProjection(this.ledger, width);
|
|
260
|
+
const cached = this.#styledMemo;
|
|
261
|
+
if (
|
|
262
|
+
cached?.token === projection.token &&
|
|
263
|
+
cached.width === width &&
|
|
264
|
+
cached.themeGeneration === this.#themeGeneration &&
|
|
265
|
+
cached.theme === componentTheme
|
|
266
|
+
) {
|
|
267
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.styledCacheHits++;
|
|
268
|
+
return cached.lines;
|
|
269
|
+
}
|
|
270
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.styledCacheMisses++;
|
|
271
|
+
const lines = projection.lines.map(line => {
|
|
272
|
+
if (line.kind === "header")
|
|
273
|
+
return truncateToWidth(
|
|
274
|
+
`${componentTheme.fg("accent", componentTheme.bold(line.sender!))} → ${line.recipient} · ${componentTheme.fg("dim", line.time!)}`,
|
|
275
|
+
width,
|
|
276
|
+
);
|
|
277
|
+
return truncateToWidth(line.kind === "elision" ? componentTheme.fg("dim", line.text) : line.text, width);
|
|
278
|
+
});
|
|
279
|
+
this.#styledMemo = {
|
|
280
|
+
token: projection.token,
|
|
281
|
+
width,
|
|
282
|
+
themeGeneration: this.#themeGeneration,
|
|
283
|
+
theme: componentTheme,
|
|
284
|
+
lines,
|
|
285
|
+
};
|
|
286
|
+
return lines;
|
|
287
|
+
}
|
|
168
288
|
renderWithViewportAnchors(width: number): ViewportAnchorRender {
|
|
169
289
|
if (!this.#visible) return renderComponentWithViewportAnchors(this.leftPane, width);
|
|
170
|
-
|
|
171
290
|
const componentTheme = typeof this.componentTheme === "function" ? this.componentTheme() : this.componentTheme;
|
|
172
291
|
const { leftWidth, separatorWidth, rightWidth } = computeIrcSplitWidths(width);
|
|
173
292
|
if (rightWidth === 0) return renderComponentWithViewportAnchors(this.leftPane, width);
|
|
174
|
-
|
|
175
|
-
const separatorText = componentTheme.fg("dim", ` ${componentTheme.boxSharp.vertical} `);
|
|
176
|
-
const separator = separatorWidth > 0 ? separatorText : "";
|
|
293
|
+
const separator = separatorWidth > 0 ? componentTheme.fg("dim", ` ${componentTheme.boxSharp.vertical} `) : "";
|
|
177
294
|
const leftRender = withTerminalGraphicsFallback(
|
|
178
295
|
() => renderComponentWithViewportAnchors(this.leftPane, leftWidth),
|
|
179
296
|
{ allowCursorNeutralImages: true },
|
|
180
297
|
);
|
|
181
|
-
const rightLines =
|
|
298
|
+
const rightLines = this.#renderSidebar(rightWidth, componentTheme);
|
|
182
299
|
const lineCount = Math.max(leftRender.lines.length, rightLines.length);
|
|
183
300
|
const lines: string[] = [];
|
|
184
301
|
const anchors: ViewportAnchorRender["anchors"] = [];
|
|
185
|
-
|
|
186
302
|
const leftOffset = lineCount - leftRender.lines.length;
|
|
187
303
|
const rightOffset = lineCount - rightLines.length;
|
|
188
304
|
for (let index = 0; index < lineCount; index++) {
|
|
189
305
|
const leftIndex = index - leftOffset;
|
|
190
306
|
const leftRaw = leftRender.lines[leftIndex] ?? "";
|
|
191
307
|
const right = truncateToWidth(rightLines[index - rightOffset] ?? "", rightWidth);
|
|
192
|
-
if (TERMINAL.isImageLine(leftRaw))
|
|
193
|
-
|
|
194
|
-
} else {
|
|
308
|
+
if (TERMINAL.isImageLine(leftRaw)) lines.push(leftRaw + padding(leftWidth) + separator + right);
|
|
309
|
+
else {
|
|
195
310
|
const left = truncateToWidth(leftRaw, leftWidth);
|
|
196
311
|
lines.push(left + padding(Math.max(0, leftWidth - visibleWidth(left))) + separator + right);
|
|
197
312
|
}
|
|
@@ -199,7 +314,6 @@ export class IrcSplitViewComponent implements ViewportAnchorProvider {
|
|
|
199
314
|
}
|
|
200
315
|
return { lines, anchors };
|
|
201
316
|
}
|
|
202
|
-
|
|
203
317
|
invalidate(): void {
|
|
204
318
|
this.leftPane.invalidate?.();
|
|
205
319
|
}
|
|
@@ -31,6 +31,8 @@ import {
|
|
|
31
31
|
} from "../../config/model-resolver";
|
|
32
32
|
import { type ModelSelectorValue, normalizeModelSelectorValue, selectorHead } from "../../config/model-selector-value";
|
|
33
33
|
import type { ModelProfileConfig } from "../../config/models-config-schema";
|
|
34
|
+
import { getProviderAuthHealth } from "../../config/provider-auth-health";
|
|
35
|
+
import { compareRankedProviders, type ProviderAuthState } from "../../config/provider-ranking";
|
|
34
36
|
import type { Settings } from "../../config/settings";
|
|
35
37
|
import { type ThemeColor, theme } from "../../modes/theme/theme";
|
|
36
38
|
import { formatModelOnboardingInlineHint } from "../../setup/model-onboarding-guidance";
|
|
@@ -542,10 +544,22 @@ export class ModelSelectorComponent extends Container {
|
|
|
542
544
|
this.#applyTabFilter();
|
|
543
545
|
}
|
|
544
546
|
|
|
547
|
+
#resolveProviderAuthState(providerId: string): ProviderAuthState {
|
|
548
|
+
const health = getProviderAuthHealth(this.#modelRegistry.authStorage, providerId);
|
|
549
|
+
if (health) return health;
|
|
550
|
+
return this.#modelRegistry.hasConfiguredProviderAuth(providerId) ? "configured" : "none";
|
|
551
|
+
}
|
|
552
|
+
|
|
545
553
|
#sortModels(models: ModelItem[]): void {
|
|
546
|
-
// Sort: default-tagged model first, then MRU, then
|
|
554
|
+
// Sort: default-tagged model first, then MRU, then provider ranking
|
|
547
555
|
const mruOrder = this.#settings.getStorage()?.getModelUsageOrder() ?? [];
|
|
548
556
|
const mruIndex = new Map(mruOrder.map((key, i) => [key, i]));
|
|
557
|
+
const providerAuthStateById = new Map<string, ProviderAuthState>();
|
|
558
|
+
for (const item of models) {
|
|
559
|
+
if (!providerAuthStateById.has(item.provider)) {
|
|
560
|
+
providerAuthStateById.set(item.provider, this.#resolveProviderAuthState(item.provider));
|
|
561
|
+
}
|
|
562
|
+
}
|
|
549
563
|
|
|
550
564
|
const modelRank = (item: ModelItem) => computeModelRank(item.model, this.#roles);
|
|
551
565
|
|
|
@@ -566,7 +580,18 @@ export class ModelSelectorComponent extends Container {
|
|
|
566
580
|
if (aMru !== bMru) return aMru - bMru;
|
|
567
581
|
|
|
568
582
|
// By provider, then recency within provider
|
|
569
|
-
const providerCmp =
|
|
583
|
+
const providerCmp = compareRankedProviders(
|
|
584
|
+
{
|
|
585
|
+
id: a.provider,
|
|
586
|
+
label: a.provider,
|
|
587
|
+
authState: providerAuthStateById.get(a.provider) ?? "none",
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
id: b.provider,
|
|
591
|
+
label: b.provider,
|
|
592
|
+
authState: providerAuthStateById.get(b.provider) ?? "none",
|
|
593
|
+
},
|
|
594
|
+
);
|
|
570
595
|
if (providerCmp !== 0) return providerCmp;
|
|
571
596
|
|
|
572
597
|
// Priority field (lower = better, e.g. OpenAI code backend priority values)
|
|
@@ -608,6 +633,12 @@ export class ModelSelectorComponent extends Container {
|
|
|
608
633
|
#sortCanonicalModels(models: CanonicalModelItem[]): void {
|
|
609
634
|
const mruOrder = this.#settings.getStorage()?.getModelUsageOrder() ?? [];
|
|
610
635
|
const mruIndex = new Map(mruOrder.map((key, i) => [key, i]));
|
|
636
|
+
const providerAuthStateById = new Map<string, ProviderAuthState>();
|
|
637
|
+
for (const item of models) {
|
|
638
|
+
if (!providerAuthStateById.has(item.model.provider)) {
|
|
639
|
+
providerAuthStateById.set(item.model.provider, this.#resolveProviderAuthState(item.model.provider));
|
|
640
|
+
}
|
|
641
|
+
}
|
|
611
642
|
|
|
612
643
|
const modelRank = (item: CanonicalModelItem) => computeModelRank(item.model, this.#roles);
|
|
613
644
|
|
|
@@ -620,7 +651,18 @@ export class ModelSelectorComponent extends Container {
|
|
|
620
651
|
const bMru = mruIndex.get(`${b.model.provider}/${b.model.id}`) ?? Number.MAX_SAFE_INTEGER;
|
|
621
652
|
if (aMru !== bMru) return aMru - bMru;
|
|
622
653
|
|
|
623
|
-
const providerCmp =
|
|
654
|
+
const providerCmp = compareRankedProviders(
|
|
655
|
+
{
|
|
656
|
+
id: a.model.provider,
|
|
657
|
+
label: a.model.provider,
|
|
658
|
+
authState: providerAuthStateById.get(a.model.provider) ?? "none",
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
id: b.model.provider,
|
|
662
|
+
label: b.model.provider,
|
|
663
|
+
authState: providerAuthStateById.get(b.model.provider) ?? "none",
|
|
664
|
+
},
|
|
665
|
+
);
|
|
624
666
|
if (providerCmp !== 0) return providerCmp;
|
|
625
667
|
|
|
626
668
|
return a.id.localeCompare(b.id);
|
|
@@ -735,8 +777,23 @@ export class ModelSelectorComponent extends Container {
|
|
|
735
777
|
for (const provider of this.#modelRegistry.getDiscoverableProviders()) {
|
|
736
778
|
providerSet.add(provider);
|
|
737
779
|
}
|
|
780
|
+
const providerAuthStateById = new Map<string, ProviderAuthState>();
|
|
781
|
+
for (const provider of providerSet) {
|
|
782
|
+
providerAuthStateById.set(provider, this.#resolveProviderAuthState(provider));
|
|
783
|
+
}
|
|
738
784
|
const sortedProviderIds = Array.from(providerSet).sort((left, right) =>
|
|
739
|
-
|
|
785
|
+
compareRankedProviders(
|
|
786
|
+
{
|
|
787
|
+
id: left,
|
|
788
|
+
label: formatProviderTabLabel(left),
|
|
789
|
+
authState: providerAuthStateById.get(left) ?? "none",
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
id: right,
|
|
793
|
+
label: formatProviderTabLabel(right),
|
|
794
|
+
authState: providerAuthStateById.get(right) ?? "none",
|
|
795
|
+
},
|
|
796
|
+
),
|
|
740
797
|
);
|
|
741
798
|
this.#providers = [...STATIC_PROVIDER_TABS, ...sortedProviderIds.map(createProviderTab)];
|
|
742
799
|
const activeIndex = this.#providers.findIndex(tab => tab.id === activeTabId);
|
|
@@ -32,6 +32,7 @@ export interface NotificationsEditorPreferences {
|
|
|
32
32
|
richDraftEnabled: boolean;
|
|
33
33
|
toolActivityEnabled: boolean;
|
|
34
34
|
streamingEnabled: boolean;
|
|
35
|
+
sound: "all" | "important" | "none";
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/** Secret-safe snapshot used to render the Notifications tab. */
|
|
@@ -160,7 +161,8 @@ type HomeActionId =
|
|
|
160
161
|
| "reconnect"
|
|
161
162
|
| "remove"
|
|
162
163
|
| "preferences"
|
|
163
|
-
| "tool-activity"
|
|
164
|
+
| "tool-activity"
|
|
165
|
+
| "sound";
|
|
164
166
|
|
|
165
167
|
interface Action {
|
|
166
168
|
id: HomeActionId | "telegram" | "external" | "save" | "save-inactive" | "cancel" | "confirm";
|
|
@@ -197,6 +199,7 @@ function emptyState(): NotificationsEditorState {
|
|
|
197
199
|
richDraftEnabled: false,
|
|
198
200
|
toolActivityEnabled: false,
|
|
199
201
|
streamingEnabled: true,
|
|
202
|
+
sound: "all",
|
|
200
203
|
},
|
|
201
204
|
};
|
|
202
205
|
}
|
|
@@ -942,6 +945,9 @@ export class NotificationsSettingsEditorComponent implements Component, Focusabl
|
|
|
942
945
|
case "test":
|
|
943
946
|
draft.streamingEnabled = !draft.streamingEnabled;
|
|
944
947
|
return;
|
|
948
|
+
case "sound":
|
|
949
|
+
draft.sound = draft.sound === "all" ? "important" : draft.sound === "important" ? "none" : "all";
|
|
950
|
+
return;
|
|
945
951
|
default:
|
|
946
952
|
return;
|
|
947
953
|
}
|
|
@@ -1092,6 +1098,11 @@ export class NotificationsSettingsEditorComponent implements Component, Focusabl
|
|
|
1092
1098
|
label: `Telegram streaming: ${draft.streamingEnabled ? "on" : "off"}`,
|
|
1093
1099
|
description: "Toggle the unsaved Telegram streaming preference.",
|
|
1094
1100
|
},
|
|
1101
|
+
{
|
|
1102
|
+
id: "sound",
|
|
1103
|
+
label: `Telegram notification sound: ${draft.sound}`,
|
|
1104
|
+
description: "Cycle between all, important, and none notification sounds.",
|
|
1105
|
+
},
|
|
1095
1106
|
{ id: "save", label: "Save preferences", description: "Atomically persist this preference draft." },
|
|
1096
1107
|
{ id: "cancel", label: "Cancel and discard draft", description: "Leave saved preferences unchanged." },
|
|
1097
1108
|
];
|