@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
|
@@ -22,10 +22,12 @@ import type {
|
|
|
22
22
|
StatusLineSeparatorStyle,
|
|
23
23
|
} from "../../config/settings-schema";
|
|
24
24
|
import { SETTING_TABS, TAB_METADATA } from "../../config/settings-schema";
|
|
25
|
+
import type { GjcRuntimeSnapshotProvider } from "../../extensibility/gjc-plugins/runtime-quarantine";
|
|
25
26
|
import { getCurrentThemeName, getSelectListTheme, getSettingsListTheme, theme } from "../../modes/theme/theme";
|
|
26
27
|
import { matchesAppInterrupt } from "../../modes/utils/keybinding-matchers";
|
|
27
28
|
import { getTabBarTheme } from "../shared";
|
|
28
29
|
import { DynamicBorder } from "./dynamic-border";
|
|
30
|
+
import { GjcBundleSettingsComponent } from "./gjc-bundle-settings";
|
|
29
31
|
import {
|
|
30
32
|
type NotificationsEditorOperations,
|
|
31
33
|
NotificationsSettingsEditorComponent,
|
|
@@ -235,18 +237,16 @@ function getSavedUsageMode(): UsageMode {
|
|
|
235
237
|
return segmentOptions.usage?.mode === "remaining" ? "remaining" : "used";
|
|
236
238
|
}
|
|
237
239
|
|
|
238
|
-
function
|
|
240
|
+
function getUsageModeSettings(mode: string): StatusLineSegmentOptions {
|
|
239
241
|
const normalizedMode: UsageMode = mode === "remaining" ? "remaining" : "used";
|
|
240
242
|
const segmentOptions = settings.get("statusLine.segmentOptions") as StatusLineSegmentOptions;
|
|
241
|
-
|
|
243
|
+
return {
|
|
242
244
|
...segmentOptions,
|
|
243
245
|
usage: {
|
|
244
246
|
...(segmentOptions.usage ?? {}),
|
|
245
247
|
mode: normalizedMode,
|
|
246
248
|
},
|
|
247
249
|
};
|
|
248
|
-
settings.set("statusLine.segmentOptions", nextOptions as Record<string, unknown>);
|
|
249
|
-
return nextOptions;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
function statusSegmentLabel(id: StatusLineSegmentId): string {
|
|
@@ -613,14 +613,17 @@ class StatusLineCustomEditor extends Container {
|
|
|
613
613
|
}
|
|
614
614
|
|
|
615
615
|
#save(): void {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
616
|
+
const saved = commitInteractiveSettings(this.callbacks, () => {
|
|
617
|
+
settings.set("statusLine.preset", "custom");
|
|
618
|
+
settings.set("statusLine.leftSegments", [...this.#draft.leftSegments]);
|
|
619
|
+
settings.set("statusLine.rightSegments", [...this.#draft.rightSegments]);
|
|
620
|
+
settings.set("statusLine.separator", this.#draft.separator);
|
|
621
|
+
settings.set(
|
|
622
|
+
"statusLine.segmentOptions",
|
|
623
|
+
cloneSegmentOptions(this.#draft.segmentOptions) as Record<string, unknown>,
|
|
624
|
+
);
|
|
625
|
+
});
|
|
626
|
+
if (!saved) return;
|
|
624
627
|
this.callbacks.onChange("statusLine.preset", "custom");
|
|
625
628
|
this.callbacks.onChange("statusLine.leftSegments", [...this.#draft.leftSegments]);
|
|
626
629
|
this.callbacks.onChange("statusLine.rightSegments", [...this.#draft.rightSegments]);
|
|
@@ -649,6 +652,7 @@ function getSettingsTabs(): Tab[] {
|
|
|
649
652
|
return { id, label: `${icon} ${meta.label}` };
|
|
650
653
|
}),
|
|
651
654
|
{ id: "plugins", label: `${theme.icon.package} Plugins` },
|
|
655
|
+
{ id: "gjc-bundles", label: `${theme.icon.package} GJC Bundles` },
|
|
652
656
|
];
|
|
653
657
|
}
|
|
654
658
|
|
|
@@ -671,6 +675,14 @@ export interface SettingsRuntimeContext {
|
|
|
671
675
|
petAvailable?: boolean;
|
|
672
676
|
/** Terminal environment used to select unavailable-pet guidance. Omitted in production to use Bun.env. */
|
|
673
677
|
terminalEnv?: NodeJS.ProcessEnv;
|
|
678
|
+
/**
|
|
679
|
+
* Runtime evidence published by the session for the current activation
|
|
680
|
+
* generation. Omitted when no session published one, in which case the GJC
|
|
681
|
+
* Bundles tab honestly reports runtime status as unavailable.
|
|
682
|
+
*/
|
|
683
|
+
gjcRuntimeSnapshot?: GjcRuntimeSnapshotProvider;
|
|
684
|
+
/** Activation generation the published snapshot must match to be merged. */
|
|
685
|
+
gjcActivationGeneration?: number;
|
|
674
686
|
}
|
|
675
687
|
|
|
676
688
|
/** Status line settings subset for preview */
|
|
@@ -707,9 +719,29 @@ export interface SettingsCallbacks {
|
|
|
707
719
|
getStatusLinePreview?: (width?: number) => string;
|
|
708
720
|
/** Called when plugins change */
|
|
709
721
|
onPluginsChanged?: () => void;
|
|
722
|
+
/** Called when an interactive setting cannot be committed. */
|
|
723
|
+
onError?: (message: string) => void;
|
|
710
724
|
/** Called when settings panel is closed */
|
|
711
725
|
onCancel: () => void;
|
|
712
726
|
}
|
|
727
|
+
function commitInteractiveSettings(callbacks: SettingsCallbacks, commit: () => void): boolean {
|
|
728
|
+
if (!settings.canWriteDurableConfig()) {
|
|
729
|
+
callbacks.onError?.(
|
|
730
|
+
"Cannot change settings while config.yml has invalid YAML syntax. Repair config.yml and reload settings.",
|
|
731
|
+
);
|
|
732
|
+
return false;
|
|
733
|
+
}
|
|
734
|
+
try {
|
|
735
|
+
commit();
|
|
736
|
+
return true;
|
|
737
|
+
} catch (error) {
|
|
738
|
+
if (!settings.canWriteDurableConfig()) {
|
|
739
|
+
callbacks.onError?.(error instanceof Error ? error.message : String(error));
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
throw error;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
713
745
|
|
|
714
746
|
/**
|
|
715
747
|
* Main tabbed settings selector component.
|
|
@@ -719,10 +751,11 @@ export class SettingsSelectorComponent extends Container {
|
|
|
719
751
|
#tabBar: TabBar;
|
|
720
752
|
#currentList: SettingsList | null = null;
|
|
721
753
|
#pluginComponent: PluginSettingsComponent | null = null;
|
|
754
|
+
#gjcBundleComponent: GjcBundleSettingsComponent | null = null;
|
|
722
755
|
#notificationsEditor: NotificationsSettingsEditorComponent | null = null;
|
|
723
756
|
#statusPreviewContainer: Container | null = null;
|
|
724
757
|
#statusPreviewText: Text | null = null;
|
|
725
|
-
#currentTabId: SettingTab | "plugins" = "appearance";
|
|
758
|
+
#currentTabId: SettingTab | "plugins" | "gjc-bundles" = "appearance";
|
|
726
759
|
#textInputActive = false;
|
|
727
760
|
|
|
728
761
|
constructor(
|
|
@@ -738,7 +771,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
738
771
|
// Tab bar
|
|
739
772
|
this.#tabBar = new TabBar("Settings", getSettingsTabs(), getTabBarTheme());
|
|
740
773
|
this.#tabBar.onTabChange = () => {
|
|
741
|
-
this.#switchToTab(this.#tabBar.getActiveTab().id as SettingTab | "plugins");
|
|
774
|
+
this.#switchToTab(this.#tabBar.getActiveTab().id as SettingTab | "plugins" | "gjc-bundles");
|
|
742
775
|
};
|
|
743
776
|
|
|
744
777
|
this.addChild(this.#tabBar);
|
|
@@ -753,7 +786,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
753
786
|
this.addChild(new DynamicBorder());
|
|
754
787
|
}
|
|
755
788
|
|
|
756
|
-
#switchToTab(tabId: SettingTab | "plugins"): void {
|
|
789
|
+
#switchToTab(tabId: SettingTab | "plugins" | "gjc-bundles"): void {
|
|
757
790
|
if (this.#currentTabId === "notifications" && tabId !== "notifications" && !this.#disposeNotificationsEditor()) {
|
|
758
791
|
return;
|
|
759
792
|
}
|
|
@@ -768,6 +801,11 @@ export class SettingsSelectorComponent extends Container {
|
|
|
768
801
|
this.removeChild(this.#pluginComponent);
|
|
769
802
|
this.#pluginComponent = null;
|
|
770
803
|
}
|
|
804
|
+
if (this.#gjcBundleComponent) {
|
|
805
|
+
this.removeChild(this.#gjcBundleComponent);
|
|
806
|
+
this.#gjcBundleComponent.dispose();
|
|
807
|
+
this.#gjcBundleComponent = null;
|
|
808
|
+
}
|
|
771
809
|
if (this.#statusPreviewContainer) {
|
|
772
810
|
this.removeChild(this.#statusPreviewContainer);
|
|
773
811
|
this.#statusPreviewContainer = null;
|
|
@@ -780,6 +818,8 @@ export class SettingsSelectorComponent extends Container {
|
|
|
780
818
|
|
|
781
819
|
if (tabId === "plugins") {
|
|
782
820
|
this.#showPluginsTab();
|
|
821
|
+
} else if (tabId === "gjc-bundles") {
|
|
822
|
+
this.#showGjcBundlesTab();
|
|
783
823
|
} else if (tabId === "notifications") {
|
|
784
824
|
this.#showNotificationsTab();
|
|
785
825
|
} else {
|
|
@@ -994,11 +1034,18 @@ export class SettingsSelectorComponent extends Container {
|
|
|
994
1034
|
// The shared pet commit policy rechecks capability immediately
|
|
995
1035
|
// before mutation and persists only on acceptance; the settings
|
|
996
1036
|
// surface must not persist ahead of that result.
|
|
997
|
-
|
|
1037
|
+
let accepted = false;
|
|
1038
|
+
if (
|
|
1039
|
+
!commitInteractiveSettings(this.callbacks, () => {
|
|
1040
|
+
accepted = this.callbacks.onPetCommit?.(value) ?? false;
|
|
1041
|
+
})
|
|
1042
|
+
) {
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
998
1045
|
done(accepted ? value : undefined);
|
|
999
1046
|
return;
|
|
1000
1047
|
}
|
|
1001
|
-
this.#setSettingValue(def.path, value);
|
|
1048
|
+
if (!commitInteractiveSettings(this.callbacks, () => this.#setSettingValue(def.path, value))) return;
|
|
1002
1049
|
this.callbacks.onChange(def.path, value);
|
|
1003
1050
|
done(value);
|
|
1004
1051
|
},
|
|
@@ -1031,7 +1078,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1031
1078
|
value => {
|
|
1032
1079
|
// Empty string clears the setting; undefined-typed string settings
|
|
1033
1080
|
// store "" which the browser.ts expandPath ignores (no-op fallback).
|
|
1034
|
-
this.#setSettingValue(def.path, value);
|
|
1081
|
+
if (!commitInteractiveSettings(this.callbacks, () => this.#setSettingValue(def.path, value))) return;
|
|
1035
1082
|
this.callbacks.onChange(def.path, value);
|
|
1036
1083
|
wrappedDone(value);
|
|
1037
1084
|
},
|
|
@@ -1089,7 +1136,15 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1089
1136
|
getSettingsListTheme(),
|
|
1090
1137
|
(id, newValue) => {
|
|
1091
1138
|
if (id === STATUS_LINE_USAGE_MODE_ID) {
|
|
1092
|
-
const segmentOptions =
|
|
1139
|
+
const segmentOptions = getUsageModeSettings(newValue);
|
|
1140
|
+
if (
|
|
1141
|
+
!commitInteractiveSettings(this.callbacks, () => {
|
|
1142
|
+
settings.set("statusLine.segmentOptions", segmentOptions as Record<string, unknown>);
|
|
1143
|
+
})
|
|
1144
|
+
) {
|
|
1145
|
+
this.#refreshCurrentTabItems(defs);
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1093
1148
|
this.callbacks.onChange("statusLine.segmentOptions", segmentOptions);
|
|
1094
1149
|
if (tabId === "appearance") {
|
|
1095
1150
|
this.#triggerStatusLinePreview();
|
|
@@ -1105,14 +1160,20 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1105
1160
|
|
|
1106
1161
|
if (def.type === "boolean") {
|
|
1107
1162
|
const boolValue = newValue === "true";
|
|
1108
|
-
settings.set(path, boolValue as never)
|
|
1163
|
+
if (!commitInteractiveSettings(this.callbacks, () => settings.set(path, boolValue as never))) {
|
|
1164
|
+
this.#refreshCurrentTabItems(defs);
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1109
1167
|
this.callbacks.onChange(path, boolValue);
|
|
1110
1168
|
|
|
1111
1169
|
if (tabId === "appearance") {
|
|
1112
1170
|
this.#triggerStatusLinePreview();
|
|
1113
1171
|
}
|
|
1114
1172
|
} else if (def.type === "enum") {
|
|
1115
|
-
settings.set(path, newValue as never)
|
|
1173
|
+
if (!commitInteractiveSettings(this.callbacks, () => settings.set(path, newValue as never))) {
|
|
1174
|
+
this.#refreshCurrentTabItems(defs);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1116
1177
|
this.callbacks.onChange(path, newValue);
|
|
1117
1178
|
}
|
|
1118
1179
|
// Submenu/text types already persisted the value inside their own
|
|
@@ -1182,7 +1243,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1182
1243
|
|
|
1183
1244
|
/** Re-evaluate condition gates against the current settings and refresh the active list. */
|
|
1184
1245
|
#refreshCurrentTabItems(defs: SettingDef[]): void {
|
|
1185
|
-
if (this.#currentTabId === "plugins" || !this.#currentList) return;
|
|
1246
|
+
if (this.#currentTabId === "plugins" || this.#currentTabId === "gjc-bundles" || !this.#currentList) return;
|
|
1186
1247
|
this.#currentList.setItems(this.#buildItemsForTab(defs, this.#currentTabId));
|
|
1187
1248
|
}
|
|
1188
1249
|
|
|
@@ -1229,15 +1290,31 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1229
1290
|
});
|
|
1230
1291
|
this.addChild(this.#pluginComponent);
|
|
1231
1292
|
}
|
|
1293
|
+
#showGjcBundlesTab(): void {
|
|
1294
|
+
this.#gjcBundleComponent = new GjcBundleSettingsComponent(
|
|
1295
|
+
this.context.cwd,
|
|
1296
|
+
{
|
|
1297
|
+
onClose: () => this.callbacks.onCancel(),
|
|
1298
|
+
onBundlesChanged: () => this.callbacks.onPluginsChanged?.(),
|
|
1299
|
+
},
|
|
1300
|
+
{
|
|
1301
|
+
runtimeSnapshotProvider: this.context.gjcRuntimeSnapshot,
|
|
1302
|
+
activationGeneration: this.context.gjcActivationGeneration,
|
|
1303
|
+
},
|
|
1304
|
+
);
|
|
1305
|
+
this.addChild(this.#gjcBundleComponent);
|
|
1306
|
+
}
|
|
1232
1307
|
|
|
1233
1308
|
getFocusComponent(): Component {
|
|
1234
|
-
return (this.#currentList || this.#pluginComponent || this.#notificationsEditor)!;
|
|
1309
|
+
return (this.#currentList || this.#pluginComponent || this.#gjcBundleComponent || this.#notificationsEditor)!;
|
|
1235
1310
|
}
|
|
1236
1311
|
|
|
1237
1312
|
override dispose(): void {
|
|
1238
1313
|
if (this.#notificationsEditor?.navigationLocked) return;
|
|
1239
1314
|
this.#notificationsEditor?.dispose();
|
|
1240
1315
|
this.#notificationsEditor = null;
|
|
1316
|
+
this.#gjcBundleComponent?.dispose();
|
|
1317
|
+
this.#gjcBundleComponent = null;
|
|
1241
1318
|
super.dispose();
|
|
1242
1319
|
}
|
|
1243
1320
|
|
|
@@ -1259,6 +1336,18 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1259
1336
|
this.#notificationsEditor.handleInput(data);
|
|
1260
1337
|
return;
|
|
1261
1338
|
}
|
|
1339
|
+
if (this.#gjcBundleComponent && this.#currentTabId === "gjc-bundles") {
|
|
1340
|
+
if (tabNavigation) {
|
|
1341
|
+
if (this.#gjcBundleComponent.navigationLocked) {
|
|
1342
|
+
this.#gjcBundleComponent.handleInput(data);
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
1345
|
+
this.#tabBar.handleInput(data);
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
this.#gjcBundleComponent.handleInput(data);
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1262
1351
|
|
|
1263
1352
|
// Handle tab switching — but NOT when a text input is active, since
|
|
1264
1353
|
// arrow keys must reach the cursor and Tab must not switch tabs.
|
|
@@ -1277,6 +1366,10 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1277
1366
|
this.#pluginComponent.handleInput(data);
|
|
1278
1367
|
return;
|
|
1279
1368
|
}
|
|
1369
|
+
if (this.#gjcBundleComponent) {
|
|
1370
|
+
this.#gjcBundleComponent.handleInput(data);
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1280
1373
|
|
|
1281
1374
|
// Fallback for future top-level content that does not own cancellation.
|
|
1282
1375
|
if (matchesAppInterrupt(data)) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type RunGh, runGhDefault } from "../../../utils/gh";
|
|
2
|
+
|
|
3
|
+
const STATUS_LINE_GH_TIMEOUT_MS = 5_000;
|
|
4
|
+
|
|
5
|
+
export async function lookupCurrentPr(runGh: RunGh = runGhDefault): Promise<{ number: number; url: string } | null> {
|
|
6
|
+
try {
|
|
7
|
+
const result = await runGh(["pr", "view", "--json", "number,url"], { timeoutMs: STATUS_LINE_GH_TIMEOUT_MS });
|
|
8
|
+
if (result.exitCode !== 0 || result.timedOut) return null;
|
|
9
|
+
|
|
10
|
+
const pr = JSON.parse(result.stdout) as { number?: unknown; url?: unknown };
|
|
11
|
+
if (typeof pr.number !== "number" || typeof pr.url !== "string") return null;
|
|
12
|
+
return { number: pr.number, url: pr.url };
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -129,6 +129,21 @@ function stabilizeStreamingPreviews(previews: PerFileDiffPreview[]): PerFileDiff
|
|
|
129
129
|
return changed ? next : previews;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
function previewsAreEqual(a: PerFileDiffPreview[] | undefined, b: PerFileDiffPreview[]): boolean {
|
|
133
|
+
return (
|
|
134
|
+
a?.length === b.length &&
|
|
135
|
+
a.every((preview, index) => {
|
|
136
|
+
const next = b[index];
|
|
137
|
+
return (
|
|
138
|
+
preview.path === next?.path &&
|
|
139
|
+
preview.diff === next.diff &&
|
|
140
|
+
preview.error === next.error &&
|
|
141
|
+
preview.firstChangedLine === next.firstChangedLine
|
|
142
|
+
);
|
|
143
|
+
})
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
132
147
|
function isEditLikeToolName(toolName: string): boolean {
|
|
133
148
|
return toolName === "edit" || toolName === "apply_patch";
|
|
134
149
|
}
|
|
@@ -144,6 +159,8 @@ export interface ToolExecutionOptions {
|
|
|
144
159
|
editFuzzyThreshold?: number;
|
|
145
160
|
editAllowFuzzy?: boolean;
|
|
146
161
|
hashlineAutoDropPureInsertDuplicates?: boolean;
|
|
162
|
+
/** Internal observer for visible asynchronous renderer mutations. */
|
|
163
|
+
onVisibleTranscriptMutation?: () => void;
|
|
147
164
|
}
|
|
148
165
|
|
|
149
166
|
export interface ToolExecutionHandle {
|
|
@@ -168,6 +185,11 @@ export interface ToolExecutionHandle {
|
|
|
168
185
|
* back to {@link setExpanded}.
|
|
169
186
|
*/
|
|
170
187
|
setManuallyExpanded?(expanded: boolean): void;
|
|
188
|
+
/**
|
|
189
|
+
* Internal capability for dispatchers that need exact synchronous visible-output
|
|
190
|
+
* detection. Optional so existing structural handles remain source compatible.
|
|
191
|
+
*/
|
|
192
|
+
consumeVisibleTranscriptChange?(): boolean;
|
|
171
193
|
}
|
|
172
194
|
|
|
173
195
|
/**
|
|
@@ -213,8 +235,11 @@ export class ToolExecutionComponent extends Container {
|
|
|
213
235
|
#argsIdentityVersion = 0;
|
|
214
236
|
#lastArgsReference: any;
|
|
215
237
|
#shareArgsWithRenderer = false;
|
|
216
|
-
// Cached converted images for Kitty protocol (which requires PNG), keyed by index
|
|
217
|
-
#convertedImages: Map<number, { data: string; mimeType: string }> = new Map();
|
|
238
|
+
// Cached converted images for Kitty protocol (which requires PNG), keyed by index and source.
|
|
239
|
+
#convertedImages: Map<number, { data: string; mimeType: string; source: string }> = new Map();
|
|
240
|
+
#imageConversionGenerations = new Map<number, number>();
|
|
241
|
+
#imageConversionsInFlight = new Map<number, string>();
|
|
242
|
+
|
|
218
243
|
// Spinner animation for partial task results
|
|
219
244
|
#spinnerFrame?: number;
|
|
220
245
|
#spinnerAnimation?: AnimationRegistration;
|
|
@@ -229,6 +254,10 @@ export class ToolExecutionComponent extends Container {
|
|
|
229
254
|
expanded: false,
|
|
230
255
|
isPartial: true,
|
|
231
256
|
};
|
|
257
|
+
#onVisibleTranscriptMutation?: () => void;
|
|
258
|
+
#visibleTranscriptChanged = false;
|
|
259
|
+
#visibleProjection = "";
|
|
260
|
+
#disposed = false;
|
|
232
261
|
|
|
233
262
|
constructor(
|
|
234
263
|
toolName: string,
|
|
@@ -246,6 +275,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
246
275
|
this.#editFuzzyThreshold = options.editFuzzyThreshold;
|
|
247
276
|
this.#editAllowFuzzy = options.editAllowFuzzy;
|
|
248
277
|
this.#hashlineAutoDropPureInsertDuplicates = options.hashlineAutoDropPureInsertDuplicates;
|
|
278
|
+
this.#onVisibleTranscriptMutation = options.onVisibleTranscriptMutation;
|
|
279
|
+
|
|
249
280
|
this.#tool = tool;
|
|
250
281
|
this.#ui = ui;
|
|
251
282
|
this.#cwd = cwd;
|
|
@@ -273,18 +304,23 @@ export class ToolExecutionComponent extends Container {
|
|
|
273
304
|
this.#editMode = resolveEditModeForTool(toolName, tool);
|
|
274
305
|
|
|
275
306
|
this.#updateDisplay();
|
|
307
|
+
this.#visibleProjection = this.#captureLogicalVisibleProjection();
|
|
308
|
+
|
|
276
309
|
void this.#runPreviewDiff();
|
|
277
310
|
}
|
|
278
311
|
|
|
279
312
|
updateArgs(args: any, _toolCallId?: string): void {
|
|
313
|
+
const argsChanged = !Bun.deepEquals(this.#args, args);
|
|
314
|
+
if (!argsChanged && !this.#editMode) return;
|
|
280
315
|
if (args !== this.#lastArgsReference) {
|
|
281
316
|
this.#lastArgsReference = args;
|
|
282
317
|
this.#argsIdentityVersion += 1;
|
|
283
318
|
}
|
|
284
|
-
this.#args = this.#shareArgsWithRenderer ? args : cloneToolArgs(args);
|
|
319
|
+
this.#args = argsChanged ? (this.#shareArgsWithRenderer ? args : cloneToolArgs(args)) : this.#args;
|
|
285
320
|
this.#updateSpinnerAnimation();
|
|
286
321
|
void this.#runPreviewDiff();
|
|
287
322
|
this.#updateDisplay();
|
|
323
|
+
this.#markVisibleMutationIfChanged();
|
|
288
324
|
}
|
|
289
325
|
|
|
290
326
|
/**
|
|
@@ -295,6 +331,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
295
331
|
this.#argsComplete = true;
|
|
296
332
|
this.#updateSpinnerAnimation();
|
|
297
333
|
void this.#runPreviewDiff();
|
|
334
|
+
this.#updateDisplay();
|
|
335
|
+
this.#markVisibleMutationIfChanged();
|
|
298
336
|
}
|
|
299
337
|
|
|
300
338
|
async #runPreviewDiff(): Promise<void> {
|
|
@@ -338,14 +376,17 @@ export class ToolExecutionComponent extends Container {
|
|
|
338
376
|
hashlineAutoDropPureInsertDuplicates: this.#hashlineAutoDropPureInsertDuplicates,
|
|
339
377
|
isStreaming,
|
|
340
378
|
});
|
|
341
|
-
if (controller.signal.aborted) return;
|
|
379
|
+
if (this.#disposed || controller.signal.aborted) return;
|
|
342
380
|
if (previews) {
|
|
343
|
-
|
|
381
|
+
const nextPreview = isStreaming ? stabilizeStreamingPreviews(previews) : previews;
|
|
382
|
+
const changed = !previewsAreEqual(this.#editDiffPreview, nextPreview);
|
|
383
|
+
this.#editDiffPreview = nextPreview;
|
|
344
384
|
this.#updateDisplay();
|
|
345
385
|
this.#ui.requestRender();
|
|
386
|
+
if (changed) this.#markVisibleMutationIfChanged(true);
|
|
346
387
|
}
|
|
347
388
|
} catch (err) {
|
|
348
|
-
if (controller.signal.aborted) return;
|
|
389
|
+
if (this.#disposed || controller.signal.aborted) return;
|
|
349
390
|
logger.warn("Edit preview diff failed", { tool: this.#toolName, error: String(err) });
|
|
350
391
|
}
|
|
351
392
|
}
|
|
@@ -359,8 +400,10 @@ export class ToolExecutionComponent extends Container {
|
|
|
359
400
|
isPartial = false,
|
|
360
401
|
_toolCallId?: string,
|
|
361
402
|
): void {
|
|
403
|
+
if (this.#isPartial === isPartial && Bun.deepEquals(this.#result, result)) return;
|
|
362
404
|
this.#textOutputCache = undefined;
|
|
363
405
|
this.#result = result;
|
|
406
|
+
this.#invalidateStaleKittyConversions();
|
|
364
407
|
this.#isPartial = isPartial;
|
|
365
408
|
// When tool is complete, ensure args are marked complete so spinner stops
|
|
366
409
|
if (!isPartial) {
|
|
@@ -370,6 +413,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
370
413
|
this.#updateDisplay();
|
|
371
414
|
// Convert non-PNG images to PNG for Kitty protocol (async)
|
|
372
415
|
this.#maybeConvertImagesForKitty();
|
|
416
|
+
this.#markVisibleMutationIfChanged();
|
|
373
417
|
}
|
|
374
418
|
|
|
375
419
|
/**
|
|
@@ -383,40 +427,101 @@ export class ToolExecutionComponent extends Container {
|
|
|
383
427
|
return [...contentImages, ...detailImages];
|
|
384
428
|
}
|
|
385
429
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
*/
|
|
390
|
-
#maybeConvertImagesForKitty(): void {
|
|
391
|
-
// Only needed for Kitty protocol
|
|
392
|
-
if (TERMINAL.imageProtocol !== ImageProtocol.Kitty) return;
|
|
393
|
-
if (!this.#result) return;
|
|
394
|
-
|
|
395
|
-
const imageBlocks = this.#getAllImageBlocks();
|
|
430
|
+
#imageSource(image: { data?: string; mimeType?: string }): string | undefined {
|
|
431
|
+
return image.data && image.mimeType ? `${image.mimeType}\u0000${image.data}` : undefined;
|
|
432
|
+
}
|
|
396
433
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
if (
|
|
434
|
+
#invalidateStaleKittyConversions(): void {
|
|
435
|
+
const images = this.#getAllImageBlocks();
|
|
436
|
+
const indices = new Set<number>();
|
|
437
|
+
for (let index = 0; index < images.length; index++) {
|
|
438
|
+
const source = this.#imageSource(images[index]);
|
|
439
|
+
if (!source) continue;
|
|
440
|
+
indices.add(index);
|
|
441
|
+
if (this.#convertedImages.get(index)?.source !== source) this.#convertedImages.delete(index);
|
|
442
|
+
if (this.#imageConversionsInFlight.get(index) !== source) {
|
|
443
|
+
this.#imageConversionsInFlight.delete(index);
|
|
444
|
+
this.#imageConversionGenerations.set(index, (this.#imageConversionGenerations.get(index) ?? 0) + 1);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
for (const index of this.#convertedImages.keys()) {
|
|
448
|
+
if (!indices.has(index)) this.#convertedImages.delete(index);
|
|
449
|
+
}
|
|
450
|
+
for (const index of this.#imageConversionsInFlight.keys()) {
|
|
451
|
+
if (!indices.has(index)) {
|
|
452
|
+
this.#imageConversionsInFlight.delete(index);
|
|
453
|
+
this.#imageConversionGenerations.set(index, (this.#imageConversionGenerations.get(index) ?? 0) + 1);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
403
457
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
458
|
+
/** Convert non-PNG images to PNG for Kitty graphics protocol. */
|
|
459
|
+
#maybeConvertImagesForKitty(): void {
|
|
460
|
+
if (TERMINAL.imageProtocol !== ImageProtocol.Kitty) return;
|
|
461
|
+
for (const [index, image] of this.#getAllImageBlocks().entries()) {
|
|
462
|
+
const source = this.#imageSource(image);
|
|
463
|
+
if (!source || image.mimeType === "image/png") continue;
|
|
464
|
+
if (
|
|
465
|
+
this.#convertedImages.get(index)?.source === source ||
|
|
466
|
+
this.#imageConversionsInFlight.get(index) === source
|
|
467
|
+
)
|
|
468
|
+
continue;
|
|
469
|
+
const generation = this.#imageConversionGenerations.get(index) ?? 0;
|
|
470
|
+
this.#imageConversionsInFlight.set(index, source);
|
|
471
|
+
new Bun.Image(Buffer.from(image.data!, "base64"))
|
|
407
472
|
.png()
|
|
408
473
|
.toBase64()
|
|
409
474
|
.then(data => {
|
|
410
|
-
|
|
475
|
+
if (
|
|
476
|
+
this.#disposed ||
|
|
477
|
+
this.#imageConversionGenerations.get(index) !== generation ||
|
|
478
|
+
this.#imageConversionsInFlight.get(index) !== source ||
|
|
479
|
+
this.#imageSource(this.#getAllImageBlocks()[index] ?? {}) !== source
|
|
480
|
+
)
|
|
481
|
+
return;
|
|
482
|
+
this.#imageConversionsInFlight.delete(index);
|
|
483
|
+
this.#convertedImages.set(index, { data, mimeType: "image/png", source });
|
|
411
484
|
this.#updateDisplay();
|
|
412
485
|
this.#ui.requestRender();
|
|
486
|
+
this.#markVisibleMutationIfChanged(true);
|
|
413
487
|
})
|
|
414
488
|
.catch(() => {
|
|
415
|
-
|
|
489
|
+
if (
|
|
490
|
+
this.#disposed ||
|
|
491
|
+
this.#imageConversionGenerations.get(index) !== generation ||
|
|
492
|
+
this.#imageConversionsInFlight.get(index) !== source
|
|
493
|
+
)
|
|
494
|
+
return;
|
|
495
|
+
this.#imageConversionsInFlight.delete(index);
|
|
416
496
|
});
|
|
417
497
|
}
|
|
418
498
|
}
|
|
419
499
|
|
|
500
|
+
#captureLogicalVisibleProjection(): string {
|
|
501
|
+
return this.render(10_000).join("\n");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
#markVisibleMutationIfChanged(notify = false): void {
|
|
505
|
+
const projection = this.#captureLogicalVisibleProjection();
|
|
506
|
+
if (projection === this.#visibleProjection) return;
|
|
507
|
+
this.#visibleProjection = projection;
|
|
508
|
+
this.#markVisibleMutation(notify);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
#markVisibleMutation(notify = false): void {
|
|
512
|
+
if (notify) {
|
|
513
|
+
this.#onVisibleTranscriptMutation?.();
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
this.#visibleTranscriptChanged = true;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
consumeVisibleTranscriptChange(): boolean {
|
|
520
|
+
const changed = this.#visibleTranscriptChanged;
|
|
521
|
+
this.#visibleTranscriptChanged = false;
|
|
522
|
+
return changed;
|
|
523
|
+
}
|
|
524
|
+
|
|
420
525
|
/**
|
|
421
526
|
* Start or stop spinner animation based on whether this is a partial task result.
|
|
422
527
|
*/
|
|
@@ -430,6 +535,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
430
535
|
const needsSpinner = isStreamingArgs || isPartialTask;
|
|
431
536
|
if (needsSpinner && !this.#spinnerAnimation) {
|
|
432
537
|
this.#spinnerAnimation = registerAnimationCallback(() => {
|
|
538
|
+
if (this.#disposed) return;
|
|
433
539
|
const frameCount = theme.spinnerFrames.length;
|
|
434
540
|
if (frameCount === 0) return;
|
|
435
541
|
this.#spinnerFrame = ((this.#spinnerFrame ?? -1) + 1) % frameCount;
|
|
@@ -456,6 +562,11 @@ export class ToolExecutionComponent extends Container {
|
|
|
456
562
|
}
|
|
457
563
|
|
|
458
564
|
override dispose(): void {
|
|
565
|
+
if (this.#disposed) return;
|
|
566
|
+
this.#disposed = true;
|
|
567
|
+
this.#imageConversionGenerations.clear();
|
|
568
|
+
this.#imageConversionsInFlight.clear();
|
|
569
|
+
this.#convertedImages.clear();
|
|
459
570
|
this.stopAnimation();
|
|
460
571
|
super.dispose();
|
|
461
572
|
}
|
|
@@ -2,7 +2,6 @@ import * as fs from "node:fs";
|
|
|
2
2
|
|
|
3
3
|
import { type Component, truncateToWidth, visibleWidth } from "@gajae-code/tui";
|
|
4
4
|
import { formatCount, getProjectDir } from "@gajae-code/utils";
|
|
5
|
-
import { $ } from "bun";
|
|
6
5
|
import {
|
|
7
6
|
type AppKeybinding,
|
|
8
7
|
KEYBINDINGS,
|
|
@@ -20,6 +19,7 @@ import type { ActionRegistry, FocusDomain } from "../action-registry";
|
|
|
20
19
|
import { EMPTY_JOBS_SNAPSHOT, type JobsSnapshot } from "../jobs-observer";
|
|
21
20
|
import { sanitizeStatusText } from "../shared";
|
|
22
21
|
import { renderSkillHudBar } from "./skill-hud/render";
|
|
22
|
+
import { lookupCurrentPr } from "./status-line/gh";
|
|
23
23
|
import {
|
|
24
24
|
canReuseCachedPr,
|
|
25
25
|
createPrCacheContext,
|
|
@@ -416,19 +416,8 @@ export class StatusLineComponent implements Component {
|
|
|
416
416
|
};
|
|
417
417
|
try {
|
|
418
418
|
// Requires `gh repo set-default` to be configured; fails gracefully if not
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
setCachedPr(null);
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
const pr = JSON.parse(result.stdout.toString()) as { number: number; url: string };
|
|
425
|
-
if (typeof pr.number === "number") {
|
|
426
|
-
setCachedPr({ number: pr.number, url: pr.url });
|
|
427
|
-
} else {
|
|
428
|
-
setCachedPr(null);
|
|
429
|
-
}
|
|
430
|
-
} catch {
|
|
431
|
-
setCachedPr(null);
|
|
419
|
+
const pr = await lookupCurrentPr();
|
|
420
|
+
setCachedPr(pr);
|
|
432
421
|
} finally {
|
|
433
422
|
this.#prLookupInFlight = false;
|
|
434
423
|
if (this.#onBranchChange) {
|