@gajae-code/coding-agent 0.12.0 → 0.12.2
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 +111 -0
- package/dist/types/async/job-manager.d.ts +17 -3
- package/dist/types/config/settings-schema.d.ts +56 -2
- 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 +16 -2
- 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/gjc-runtime/launch-tmux.d.ts +1 -0
- package/dist/types/gjc-runtime/ralplan-review-conflicts.d.ts +114 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +23 -3
- package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +25 -0
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +10 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +37 -80
- package/dist/types/modes/acp/acp-agent.d.ts +2 -19
- package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
- package/dist/types/modes/components/irc-sidebar.d.ts +16 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
- package/dist/types/modes/components/session-observer-overlay.d.ts +18 -0
- package/dist/types/modes/components/settings-selector.d.ts +9 -0
- package/dist/types/modes/components/status-line/gh.d.ts +5 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/event-controller.d.ts +1 -1
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +2 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +9 -0
- package/dist/types/modes/theme/theme.d.ts +3 -1
- package/dist/types/modes/types.d.ts +32 -0
- package/dist/types/reminders/star-reminder.d.ts +3 -13
- package/dist/types/runtime-mcp/manager.d.ts +1 -0
- package/dist/types/sdk/acp/adapter.d.ts +3 -1
- 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 +5 -1
- package/dist/types/sdk/bus/config.d.ts +6 -2
- package/dist/types/sdk/bus/index.d.ts +29 -0
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +8 -1
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +7 -3
- 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 +12 -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/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 +40 -2
- 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 +30 -4
- package/dist/types/session/session-manager.d.ts +23 -6
- package/dist/types/session/session-storage.d.ts +4 -0
- package/dist/types/session/streaming-output.d.ts +36 -7
- package/dist/types/setup/credential-import.d.ts +12 -0
- package/dist/types/skill-state/active-state.d.ts +12 -0
- package/dist/types/skill-state/workflow-hud.d.ts +6 -0
- package/dist/types/task/executor.d.ts +3 -2
- package/dist/types/task/index.d.ts +7 -1
- package/dist/types/task/output-manager.d.ts +1 -0
- package/dist/types/task/provider-retry-status.d.ts +8 -0
- package/dist/types/task/receipt.d.ts +9 -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/image-gen.d.ts +4 -0
- package/dist/types/tools/index.d.ts +6 -0
- package/dist/types/tools/output-meta.d.ts +23 -2
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read.d.ts +0 -6
- package/dist/types/tools/review.d.ts +5 -7
- package/dist/types/tools/subagent.d.ts +2 -0
- 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 +10 -8
- package/scripts/acp-conformance-agent.ts +218 -0
- package/scripts/capture-gjc-bundle-settings.ts +306 -0
- package/scripts/dogfood-ralplan-review-conflicts.ts +272 -0
- package/scripts/generate-sdk-operation-inventory.ts +5 -0
- package/scripts/resident-memory-bench.ts +1341 -0
- package/scripts/run-acp-conformance.ts +290 -0
- package/src/async/job-manager.ts +99 -39
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/plugin-cli.ts +176 -18
- package/src/commands/team.ts +19 -1
- package/src/config/file-lock.ts +11 -2
- package/src/config/settings-schema.ts +53 -2
- package/src/coordinator-mcp/question-gate-codec.ts +1 -1
- package/src/coordinator-mcp/server.ts +5 -12
- package/src/debug/index.ts +42 -17
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -0
- package/src/defaults/gjc/skills/ralplan/SKILL.md +25 -20
- package/src/defaults/gjc/skills/team/SKILL.md +2 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +39 -26
- package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
- package/src/defaults/gjc-defaults.ts +4 -4
- 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 +18 -1
- 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/gjc-runtime/launch-tmux.ts +25 -6
- package/src/gjc-runtime/launch-worktree.ts +103 -1
- package/src/gjc-runtime/ledger-event-renderer.ts +1 -0
- package/src/gjc-runtime/managed-owner-admission.ts +1 -1
- package/src/gjc-runtime/ralplan-review-conflicts.ts +472 -0
- package/src/gjc-runtime/ralplan-runtime.ts +491 -27
- package/src/gjc-runtime/team-launch.ts +8 -0
- package/src/gjc-runtime/team-runtime.ts +140 -32
- package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
- package/src/gjc-runtime/tmux-owner-isolation.ts +10 -0
- package/src/gjc-runtime/tmux-sessions.ts +58 -13
- package/src/gjc-runtime/ultragoal-evidence.ts +6 -74
- package/src/gjc-runtime/ultragoal-runtime.ts +635 -612
- package/src/gjc-runtime/workflow-manifest.generated.json +37 -99
- package/src/gjc-runtime/workflow-manifest.ts +21 -70
- package/src/internal-urls/docs-index.generated.ts +16 -16
- package/src/modes/DESIGN.md +104 -0
- package/src/modes/acp/acp-agent.ts +298 -186
- package/src/modes/components/gjc-bundle-settings.ts +508 -0
- package/src/modes/components/irc-sidebar.ts +30 -1
- package/src/modes/components/notifications-settings-editor.ts +12 -1
- package/src/modes/components/oauth-selector.ts +68 -30
- package/src/modes/components/session-observer-overlay.ts +305 -86
- package/src/modes/components/settings-selector.ts +56 -5
- package/src/modes/components/status-line/gh.ts +16 -0
- package/src/modes/components/tool-status-header.ts +3 -15
- package/src/modes/components/transcript-viewer-overlay.ts +99 -24
- package/src/modes/controllers/command-controller.ts +42 -34
- package/src/modes/controllers/event-controller.ts +27 -16
- package/src/modes/controllers/extension-ui-controller.ts +193 -34
- package/src/modes/controllers/selector-controller.ts +160 -22
- package/src/modes/interactive-mode.ts +189 -62
- package/src/modes/jobs-observer.ts +1 -1
- package/src/modes/runtime-init.ts +3 -0
- package/src/modes/theme/theme.ts +11 -9
- package/src/modes/types.ts +88 -0
- package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
- package/src/prompts/system/eager-todo.md +8 -4
- package/src/prompts/system/system-prompt.md +11 -4
- package/src/prompts/tools/bash.md +5 -5
- 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/sdk/acp/adapter.ts +22 -6
- package/src/sdk/broker/lifecycle.ts +18 -13
- 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 +7 -3
- package/src/sdk/bus/config.ts +18 -2
- package/src/sdk/bus/index.ts +661 -126
- package/src/sdk/bus/kind-aware-reconciliation.ts +148 -73
- package/src/sdk/bus/lifecycle-commands.ts +4 -1
- package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
- package/src/sdk/bus/reconciliation-store.ts +95 -16
- 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 +12 -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/query/revision-store.ts +36 -2
- package/src/sdk/host/reverse-leases.ts +44 -7
- package/src/sdk/prompt-status.ts +16 -3
- package/src/sdk/protocol/operation-inventory.generated.json +33 -0
- package/src/sdk/session.ts +89 -9
- package/src/session/agent-session.ts +844 -173
- 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 +200 -111
- package/src/session/internal/managed-session-storage.ts +492 -62
- package/src/session/session-manager.ts +1614 -435
- package/src/session/session-storage.ts +38 -45
- package/src/session/streaming-output.ts +238 -68
- package/src/setup/credential-import.ts +75 -13
- package/src/skill-state/active-state.ts +32 -0
- package/src/skill-state/workflow-hud.ts +17 -0
- package/src/skill-state/workflow-mutation-guard.ts +496 -2
- package/src/task/executor.ts +122 -39
- package/src/task/index.ts +280 -45
- package/src/task/output-manager.ts +24 -14
- package/src/task/provider-retry-status.ts +16 -0
- package/src/task/receipt.ts +34 -8
- 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 +86 -55
- 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/find.ts +1 -0
- package/src/tools/image-gen.ts +29 -5
- package/src/tools/index.ts +6 -0
- package/src/tools/output-meta.ts +108 -14
- package/src/tools/path-utils.ts +3 -2
- package/src/tools/read.ts +18 -0
- 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/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/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/ultragoal-pipeline.d.ts +0 -23
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
- 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,
|
|
@@ -650,6 +652,7 @@ function getSettingsTabs(): Tab[] {
|
|
|
650
652
|
return { id, label: `${icon} ${meta.label}` };
|
|
651
653
|
}),
|
|
652
654
|
{ id: "plugins", label: `${theme.icon.package} Plugins` },
|
|
655
|
+
{ id: "gjc-bundles", label: `${theme.icon.package} GJC Bundles` },
|
|
653
656
|
];
|
|
654
657
|
}
|
|
655
658
|
|
|
@@ -672,6 +675,14 @@ export interface SettingsRuntimeContext {
|
|
|
672
675
|
petAvailable?: boolean;
|
|
673
676
|
/** Terminal environment used to select unavailable-pet guidance. Omitted in production to use Bun.env. */
|
|
674
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;
|
|
675
686
|
}
|
|
676
687
|
|
|
677
688
|
/** Status line settings subset for preview */
|
|
@@ -740,10 +751,11 @@ export class SettingsSelectorComponent extends Container {
|
|
|
740
751
|
#tabBar: TabBar;
|
|
741
752
|
#currentList: SettingsList | null = null;
|
|
742
753
|
#pluginComponent: PluginSettingsComponent | null = null;
|
|
754
|
+
#gjcBundleComponent: GjcBundleSettingsComponent | null = null;
|
|
743
755
|
#notificationsEditor: NotificationsSettingsEditorComponent | null = null;
|
|
744
756
|
#statusPreviewContainer: Container | null = null;
|
|
745
757
|
#statusPreviewText: Text | null = null;
|
|
746
|
-
#currentTabId: SettingTab | "plugins" = "appearance";
|
|
758
|
+
#currentTabId: SettingTab | "plugins" | "gjc-bundles" = "appearance";
|
|
747
759
|
#textInputActive = false;
|
|
748
760
|
|
|
749
761
|
constructor(
|
|
@@ -759,7 +771,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
759
771
|
// Tab bar
|
|
760
772
|
this.#tabBar = new TabBar("Settings", getSettingsTabs(), getTabBarTheme());
|
|
761
773
|
this.#tabBar.onTabChange = () => {
|
|
762
|
-
this.#switchToTab(this.#tabBar.getActiveTab().id as SettingTab | "plugins");
|
|
774
|
+
this.#switchToTab(this.#tabBar.getActiveTab().id as SettingTab | "plugins" | "gjc-bundles");
|
|
763
775
|
};
|
|
764
776
|
|
|
765
777
|
this.addChild(this.#tabBar);
|
|
@@ -774,7 +786,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
774
786
|
this.addChild(new DynamicBorder());
|
|
775
787
|
}
|
|
776
788
|
|
|
777
|
-
#switchToTab(tabId: SettingTab | "plugins"): void {
|
|
789
|
+
#switchToTab(tabId: SettingTab | "plugins" | "gjc-bundles"): void {
|
|
778
790
|
if (this.#currentTabId === "notifications" && tabId !== "notifications" && !this.#disposeNotificationsEditor()) {
|
|
779
791
|
return;
|
|
780
792
|
}
|
|
@@ -789,6 +801,11 @@ export class SettingsSelectorComponent extends Container {
|
|
|
789
801
|
this.removeChild(this.#pluginComponent);
|
|
790
802
|
this.#pluginComponent = null;
|
|
791
803
|
}
|
|
804
|
+
if (this.#gjcBundleComponent) {
|
|
805
|
+
this.removeChild(this.#gjcBundleComponent);
|
|
806
|
+
this.#gjcBundleComponent.dispose();
|
|
807
|
+
this.#gjcBundleComponent = null;
|
|
808
|
+
}
|
|
792
809
|
if (this.#statusPreviewContainer) {
|
|
793
810
|
this.removeChild(this.#statusPreviewContainer);
|
|
794
811
|
this.#statusPreviewContainer = null;
|
|
@@ -801,6 +818,8 @@ export class SettingsSelectorComponent extends Container {
|
|
|
801
818
|
|
|
802
819
|
if (tabId === "plugins") {
|
|
803
820
|
this.#showPluginsTab();
|
|
821
|
+
} else if (tabId === "gjc-bundles") {
|
|
822
|
+
this.#showGjcBundlesTab();
|
|
804
823
|
} else if (tabId === "notifications") {
|
|
805
824
|
this.#showNotificationsTab();
|
|
806
825
|
} else {
|
|
@@ -1224,7 +1243,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1224
1243
|
|
|
1225
1244
|
/** Re-evaluate condition gates against the current settings and refresh the active list. */
|
|
1226
1245
|
#refreshCurrentTabItems(defs: SettingDef[]): void {
|
|
1227
|
-
if (this.#currentTabId === "plugins" || !this.#currentList) return;
|
|
1246
|
+
if (this.#currentTabId === "plugins" || this.#currentTabId === "gjc-bundles" || !this.#currentList) return;
|
|
1228
1247
|
this.#currentList.setItems(this.#buildItemsForTab(defs, this.#currentTabId));
|
|
1229
1248
|
}
|
|
1230
1249
|
|
|
@@ -1271,15 +1290,31 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1271
1290
|
});
|
|
1272
1291
|
this.addChild(this.#pluginComponent);
|
|
1273
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
|
+
}
|
|
1274
1307
|
|
|
1275
1308
|
getFocusComponent(): Component {
|
|
1276
|
-
return (this.#currentList || this.#pluginComponent || this.#notificationsEditor)!;
|
|
1309
|
+
return (this.#currentList || this.#pluginComponent || this.#gjcBundleComponent || this.#notificationsEditor)!;
|
|
1277
1310
|
}
|
|
1278
1311
|
|
|
1279
1312
|
override dispose(): void {
|
|
1280
1313
|
if (this.#notificationsEditor?.navigationLocked) return;
|
|
1281
1314
|
this.#notificationsEditor?.dispose();
|
|
1282
1315
|
this.#notificationsEditor = null;
|
|
1316
|
+
this.#gjcBundleComponent?.dispose();
|
|
1317
|
+
this.#gjcBundleComponent = null;
|
|
1283
1318
|
super.dispose();
|
|
1284
1319
|
}
|
|
1285
1320
|
|
|
@@ -1301,6 +1336,18 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1301
1336
|
this.#notificationsEditor.handleInput(data);
|
|
1302
1337
|
return;
|
|
1303
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
|
+
}
|
|
1304
1351
|
|
|
1305
1352
|
// Handle tab switching — but NOT when a text input is active, since
|
|
1306
1353
|
// arrow keys must reach the cursor and Tab must not switch tabs.
|
|
@@ -1319,6 +1366,10 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1319
1366
|
this.#pluginComponent.handleInput(data);
|
|
1320
1367
|
return;
|
|
1321
1368
|
}
|
|
1369
|
+
if (this.#gjcBundleComponent) {
|
|
1370
|
+
this.#gjcBundleComponent.handleInput(data);
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1322
1373
|
|
|
1323
1374
|
// Fallback for future top-level content that does not own cancellation.
|
|
1324
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
|
+
}
|
|
@@ -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,
|
|
@@ -206,7 +206,6 @@ export class StatusLineComponent implements Component {
|
|
|
206
206
|
separator: settings.get("statusLine.separator"),
|
|
207
207
|
showHookStatus: settings.get("statusLine.showHookStatus"),
|
|
208
208
|
showSkillHud: settings.get("statusLine.showSkillHud"),
|
|
209
|
-
showActionHints: settings.get("statusLine.showActionHints"),
|
|
210
209
|
segmentOptions: settings.getGroup("statusLine").segmentOptions,
|
|
211
210
|
sessionAccent: settings.get("statusLine.sessionAccent"),
|
|
212
211
|
maxRows: settings.get("statusLine.maxRows"),
|
|
@@ -416,19 +415,8 @@ export class StatusLineComponent implements Component {
|
|
|
416
415
|
};
|
|
417
416
|
try {
|
|
418
417
|
// 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);
|
|
418
|
+
const pr = await lookupCurrentPr();
|
|
419
|
+
setCachedPr(pr);
|
|
432
420
|
} finally {
|
|
433
421
|
this.#prLookupInFlight = false;
|
|
434
422
|
if (this.#onBranchChange) {
|
|
@@ -54,6 +54,34 @@ export type TranscriptViewerOverlayOptions = {
|
|
|
54
54
|
|
|
55
55
|
type RenderedEntry = { lineStart: number; lineCount: number };
|
|
56
56
|
|
|
57
|
+
export const __transcriptViewerPerfCounters = {
|
|
58
|
+
enabled: false,
|
|
59
|
+
layoutCacheHits: 0,
|
|
60
|
+
layoutCacheMisses: 0,
|
|
61
|
+
refreshRuns: 0,
|
|
62
|
+
rebuildRuns: 0,
|
|
63
|
+
snapshot() {
|
|
64
|
+
return {
|
|
65
|
+
layoutCacheHits: this.layoutCacheHits,
|
|
66
|
+
layoutCacheMisses: this.layoutCacheMisses,
|
|
67
|
+
refreshRuns: this.refreshRuns,
|
|
68
|
+
rebuildRuns: this.rebuildRuns,
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
enable(): void {
|
|
72
|
+
this.enabled = true;
|
|
73
|
+
},
|
|
74
|
+
disable(): void {
|
|
75
|
+
this.enabled = false;
|
|
76
|
+
},
|
|
77
|
+
reset(): void {
|
|
78
|
+
this.layoutCacheHits = 0;
|
|
79
|
+
this.layoutCacheMisses = 0;
|
|
80
|
+
this.refreshRuns = 0;
|
|
81
|
+
this.rebuildRuns = 0;
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
57
85
|
/** Message-agnostic, modal transcript browser over resolved projection entries. */
|
|
58
86
|
export class TranscriptViewerOverlay extends Container {
|
|
59
87
|
#options: TranscriptViewerOverlayOptions;
|
|
@@ -73,6 +101,7 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
73
101
|
#followTailPending = false;
|
|
74
102
|
#skipFollowTailOnce = false;
|
|
75
103
|
#followTailActive = false;
|
|
104
|
+
#layoutCache = new Map<string, Map<string, string[]>>();
|
|
76
105
|
|
|
77
106
|
constructor(options: TranscriptViewerOverlayOptions) {
|
|
78
107
|
super();
|
|
@@ -87,7 +116,11 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
87
116
|
get isFullscreen(): boolean {
|
|
88
117
|
return this.#fullscreen;
|
|
89
118
|
}
|
|
90
|
-
refresh(identityMap?: ReadonlyMap<string, string
|
|
119
|
+
refresh(identityMap?: ReadonlyMap<string, string>, preserveLayoutCache = false): void {
|
|
120
|
+
if (__transcriptViewerPerfCounters.enabled) __transcriptViewerPerfCounters.refreshRuns++;
|
|
121
|
+
// Incremental sources explicitly invalidate same-id payload patches before requesting a
|
|
122
|
+
// preserving refresh. Other source changes conservatively drop all layout variants.
|
|
123
|
+
if (!preserveLayoutCache) this.#layoutCache.clear();
|
|
91
124
|
const previous = this.selectedEntryId;
|
|
92
125
|
const previousPosition = this.#selected;
|
|
93
126
|
const reconciledPrevious = previous ? (identityMap?.get(previous) ?? previous) : undefined;
|
|
@@ -109,9 +142,15 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
109
142
|
this.#initialized = true;
|
|
110
143
|
this.#rebuild();
|
|
111
144
|
}
|
|
145
|
+
invalidateLayoutEntries(entryIds: readonly string[]): void {
|
|
146
|
+
for (const id of entryIds) this.#layoutCache.delete(id);
|
|
147
|
+
}
|
|
112
148
|
override render(width: number): string[] {
|
|
113
|
-
|
|
114
|
-
this
|
|
149
|
+
const nextWidth = Math.max(1, width);
|
|
150
|
+
const widthChanged = nextWidth !== this.#width;
|
|
151
|
+
this.#width = nextWidth;
|
|
152
|
+
if (widthChanged) this.#layoutCache.clear();
|
|
153
|
+
if (widthChanged || getMarkdownTheme() !== this.#mdTheme) this.#rebuild();
|
|
115
154
|
const defaultHeader = this.#fullscreen
|
|
116
155
|
? [theme.fg("accent", "Transcript block")]
|
|
117
156
|
: [theme.fg("accent", sanitizeText(this.#options.title ?? "Transcript"))];
|
|
@@ -179,6 +218,7 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
179
218
|
if (this.#fullscreen) {
|
|
180
219
|
this.#fullscreen = false;
|
|
181
220
|
this.#scrollOffset = 0;
|
|
221
|
+
this.#rebuild();
|
|
182
222
|
this.#requestRender();
|
|
183
223
|
} else this.#options.onClose();
|
|
184
224
|
return;
|
|
@@ -208,6 +248,7 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
208
248
|
this.#followTailActive = false;
|
|
209
249
|
this.#followTailPending = false;
|
|
210
250
|
this.#selected = 0;
|
|
251
|
+
this.#rebuild();
|
|
211
252
|
this.#scrollOffset = 0;
|
|
212
253
|
this.#requestRender();
|
|
213
254
|
return;
|
|
@@ -216,6 +257,7 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
216
257
|
this.#followTailActive = true;
|
|
217
258
|
this.#followTailPending = true;
|
|
218
259
|
this.#selected = Math.max(0, count - 1);
|
|
260
|
+
this.#rebuild();
|
|
219
261
|
this.#scrollOffset = this.#lines.length;
|
|
220
262
|
this.#requestRender();
|
|
221
263
|
return;
|
|
@@ -228,6 +270,7 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
228
270
|
this.#followTailActive = false;
|
|
229
271
|
this.#fullscreen = true;
|
|
230
272
|
this.#scrollOffset = 0;
|
|
273
|
+
this.#rebuild();
|
|
231
274
|
this.#requestRender();
|
|
232
275
|
return;
|
|
233
276
|
}
|
|
@@ -243,6 +286,7 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
243
286
|
const entry = this.#entries[this.#selected];
|
|
244
287
|
if (entry?.rawViewable !== false) {
|
|
245
288
|
this.#raw.has(entry.id) ? this.#raw.delete(entry.id) : this.#raw.add(entry.id);
|
|
289
|
+
this.#rebuild();
|
|
246
290
|
this.#requestRender();
|
|
247
291
|
}
|
|
248
292
|
}
|
|
@@ -284,6 +328,7 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
284
328
|
this.#followTailActive = false;
|
|
285
329
|
this.#followTailPending = false;
|
|
286
330
|
this.#selected = Math.max(0, Math.min(this.#selected + direction * 5, this.#entries.length - 1));
|
|
331
|
+
this.#rebuild();
|
|
287
332
|
this.#scrollOffset += direction * PAGE_SIZE;
|
|
288
333
|
this.#requestRender();
|
|
289
334
|
}
|
|
@@ -327,32 +372,58 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
327
372
|
this.#options.requestRender?.();
|
|
328
373
|
}
|
|
329
374
|
#rebuild(): void {
|
|
375
|
+
if (__transcriptViewerPerfCounters.enabled) __transcriptViewerPerfCounters.rebuildRuns++;
|
|
376
|
+
// Theme is tracked by reference outside the variant key; a reference change clears
|
|
377
|
+
// the whole cache so plain and markdown layouts pick up new markdown colors.
|
|
378
|
+
const currentMdTheme = getMarkdownTheme();
|
|
379
|
+
if (currentMdTheme !== this.#mdTheme) {
|
|
380
|
+
this.#mdTheme = currentMdTheme;
|
|
381
|
+
this.#layoutCache.clear();
|
|
382
|
+
}
|
|
330
383
|
const lines: string[] = [];
|
|
331
384
|
this.#renderedEntries = [];
|
|
332
385
|
const display = this.#fullscreen ? this.#entries.slice(this.#selected, this.#selected + 1) : this.#entries;
|
|
333
386
|
const contentWidth = Math.max(1, this.#width - INDENT.length - 1);
|
|
334
387
|
for (const entry of display) {
|
|
335
388
|
const start = lines.length;
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
lines.
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
389
|
+
const entryLines = this.#renderEntryLines(entry, contentWidth);
|
|
390
|
+
lines.push(...entryLines);
|
|
391
|
+
// Cumulative positions are recomputed from cached line lengths on every rebuild
|
|
392
|
+
// so PR2c can later separate virtual coordinates from materialized lines.
|
|
393
|
+
this.#renderedEntries.push({ lineStart: start, lineCount: entryLines.length });
|
|
394
|
+
}
|
|
395
|
+
this.#lines = lines.length ? lines : [theme.fg("dim", "No transcript entries yet.")];
|
|
396
|
+
}
|
|
397
|
+
#renderEntryLines(entry: TranscriptViewerEntry, contentWidth: number): string[] {
|
|
398
|
+
const selected = entry.id === this.selectedEntryId;
|
|
399
|
+
const expanded = this.#fullscreen || this.#expanded.has(entry.id);
|
|
400
|
+
const raw = this.#raw.has(entry.id);
|
|
401
|
+
const variantKey = `${expanded ? 1 : 0}|${raw ? 1 : 0}|${selected ? 1 : 0}|${contentWidth}`;
|
|
402
|
+
let variants = this.#layoutCache.get(entry.id);
|
|
403
|
+
if (variants) {
|
|
404
|
+
const cached = variants.get(variantKey);
|
|
405
|
+
if (cached) {
|
|
406
|
+
if (__transcriptViewerPerfCounters.enabled) __transcriptViewerPerfCounters.layoutCacheHits++;
|
|
407
|
+
return cached;
|
|
355
408
|
}
|
|
409
|
+
}
|
|
410
|
+
if (__transcriptViewerPerfCounters.enabled) __transcriptViewerPerfCounters.layoutCacheMisses++;
|
|
411
|
+
const lines: string[] = [];
|
|
412
|
+
lines.push("");
|
|
413
|
+
lines.push(
|
|
414
|
+
`${selected ? theme.fg("accent", "▶") : " "} ${theme.fg("muted", `[${sanitizeText(entry.label ?? entry.kind)}]`)}`,
|
|
415
|
+
);
|
|
416
|
+
if (
|
|
417
|
+
!raw &&
|
|
418
|
+
expanded &&
|
|
419
|
+
selected &&
|
|
420
|
+
entry.kind === "tool" &&
|
|
421
|
+
entry.richRenderEligible === true &&
|
|
422
|
+
entry.renderDescriptor
|
|
423
|
+
) {
|
|
424
|
+
for (const line of renderToolDisplayLines(entry.renderDescriptor, contentWidth, theme))
|
|
425
|
+
lines.push(`${INDENT}${line}`);
|
|
426
|
+
} else {
|
|
356
427
|
const text = sanitizeText(
|
|
357
428
|
(raw
|
|
358
429
|
? entry.payload.text
|
|
@@ -375,9 +446,13 @@ export class TranscriptViewerOverlay extends Container {
|
|
|
375
446
|
for (const line of preview) lines.push(`${INDENT}${truncateToWidth(line, contentWidth)}`);
|
|
376
447
|
if (text.split("\n").length > PREVIEW_LINES) lines.push(`${INDENT}${theme.fg("dim", "... more (Space)")}`);
|
|
377
448
|
}
|
|
378
|
-
this.#renderedEntries.push({ lineStart: start, lineCount: lines.length - start });
|
|
379
449
|
}
|
|
380
|
-
|
|
450
|
+
if (!variants) {
|
|
451
|
+
variants = new Map();
|
|
452
|
+
this.#layoutCache.set(entry.id, variants);
|
|
453
|
+
}
|
|
454
|
+
variants.set(variantKey, lines);
|
|
455
|
+
return lines;
|
|
381
456
|
}
|
|
382
457
|
#markdown(text: string, width: number): string[] {
|
|
383
458
|
return new Markdown(text, 0, 0, this.#mdTheme).render(width).map(line => `${INDENT}${line.trimEnd()}`);
|
|
@@ -34,7 +34,12 @@ import { BorderedLoader } from "../../modes/components/bordered-loader";
|
|
|
34
34
|
import { DynamicBorder } from "../../modes/components/dynamic-border";
|
|
35
35
|
import { EvalExecutionComponent } from "../../modes/components/eval-execution";
|
|
36
36
|
import { getMarkdownTheme, getSymbolTheme, theme } from "../../modes/theme/theme";
|
|
37
|
-
import
|
|
37
|
+
import {
|
|
38
|
+
clearInteractiveActivityLoaders,
|
|
39
|
+
type InteractiveModeContext,
|
|
40
|
+
stopInteractiveActivityIndicator,
|
|
41
|
+
suspendInteractiveActivityIndicator,
|
|
42
|
+
} from "../../modes/types";
|
|
38
43
|
import { computeContextBreakdown, renderContextUsage } from "../../modes/utils/context-usage";
|
|
39
44
|
import { buildHotkeysMarkdown, formatHotkeyMarkdownCode } from "../../modes/utils/hotkeys-markdown";
|
|
40
45
|
import { buildToolsMarkdown } from "../../modes/utils/tools-markdown";
|
|
@@ -965,12 +970,10 @@ export class CommandController {
|
|
|
965
970
|
|
|
966
971
|
async #runNewSessionFlow(options?: NewSessionOptions, label: string = "New session started"): Promise<boolean> {
|
|
967
972
|
if (!(await this.ctx.session.newSession(options))) return false;
|
|
973
|
+
if (this.ctx.isStopped?.()) return false;
|
|
974
|
+
clearInteractiveActivityLoaders(this.ctx);
|
|
968
975
|
|
|
969
|
-
|
|
970
|
-
this.ctx.loadingAnimation.stop();
|
|
971
|
-
this.ctx.loadingAnimation = undefined;
|
|
972
|
-
}
|
|
973
|
-
this.ctx.statusContainer.clear();
|
|
976
|
+
stopInteractiveActivityIndicator(this.ctx);
|
|
974
977
|
this.ctx.resetIrcSidebarSession();
|
|
975
978
|
this.ctx.resetObserverRegistry();
|
|
976
979
|
setSessionTerminalTitle(this.ctx.sessionManager.getSessionName(), this.ctx.sessionManager.getCwd());
|
|
@@ -991,6 +994,7 @@ export class CommandController {
|
|
|
991
994
|
|
|
992
995
|
this.ctx.chatContainer.addChild(new Text(`${theme.fg("accent", `${theme.status.success} ${label}`)}`, 1, 0));
|
|
993
996
|
await this.ctx.reloadTodos();
|
|
997
|
+
if (this.ctx.isStopped?.()) return false;
|
|
994
998
|
this.ctx.ui.requestRender();
|
|
995
999
|
return true;
|
|
996
1000
|
}
|
|
@@ -1000,19 +1004,18 @@ export class CommandController {
|
|
|
1000
1004
|
}
|
|
1001
1005
|
|
|
1002
1006
|
async handleContextClearCommand(): Promise<void> {
|
|
1003
|
-
if (this.ctx.
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
}
|
|
1007
|
-
this.ctx.statusContainer.clear();
|
|
1008
|
-
|
|
1007
|
+
if (this.ctx.isStopped?.()) return;
|
|
1008
|
+
clearInteractiveActivityLoaders(this.ctx);
|
|
1009
|
+
stopInteractiveActivityIndicator(this.ctx);
|
|
1009
1010
|
if (this.ctx.session.isCompacting) {
|
|
1010
1011
|
this.ctx.session.abortCompaction();
|
|
1011
1012
|
while (this.ctx.session.isCompacting) {
|
|
1012
1013
|
await Bun.sleep(10);
|
|
1013
1014
|
}
|
|
1014
1015
|
}
|
|
1016
|
+
if (this.ctx.isStopped?.()) return;
|
|
1015
1017
|
if (!(await this.ctx.session.clearContext())) return;
|
|
1018
|
+
if (this.ctx.isStopped?.()) return;
|
|
1016
1019
|
setSessionTerminalTitle(this.ctx.sessionManager.getSessionName(), this.ctx.sessionManager.getCwd());
|
|
1017
1020
|
|
|
1018
1021
|
this.ctx.statusLine.invalidate();
|
|
@@ -1033,6 +1036,7 @@ export class CommandController {
|
|
|
1033
1036
|
new Text(`${theme.fg("accent", `${theme.status.success} Context cleared`)}`, 1, 0),
|
|
1034
1037
|
);
|
|
1035
1038
|
await this.ctx.reloadTodos();
|
|
1039
|
+
if (this.ctx.isStopped?.()) return;
|
|
1036
1040
|
this.ctx.ui.requestRender();
|
|
1037
1041
|
}
|
|
1038
1042
|
|
|
@@ -1049,17 +1053,15 @@ export class CommandController {
|
|
|
1049
1053
|
this.ctx.showWarning("Wait for the current response to finish or abort it before forking.");
|
|
1050
1054
|
return;
|
|
1051
1055
|
}
|
|
1052
|
-
if (this.ctx.loadingAnimation) {
|
|
1053
|
-
this.ctx.loadingAnimation.stop();
|
|
1054
|
-
this.ctx.loadingAnimation = undefined;
|
|
1055
|
-
}
|
|
1056
|
-
this.ctx.statusContainer.clear();
|
|
1057
1056
|
|
|
1058
1057
|
const success = await this.ctx.session.fork();
|
|
1058
|
+
if (this.ctx.isStopped?.()) return;
|
|
1059
1059
|
if (!success) {
|
|
1060
1060
|
this.ctx.showError("Fork failed (session not persisted or cancelled)");
|
|
1061
1061
|
return;
|
|
1062
1062
|
}
|
|
1063
|
+
clearInteractiveActivityLoaders(this.ctx);
|
|
1064
|
+
stopInteractiveActivityIndicator(this.ctx);
|
|
1063
1065
|
this.ctx.resetIrcSidebarSession();
|
|
1064
1066
|
|
|
1065
1067
|
this.ctx.statusLine.invalidate();
|
|
@@ -1175,6 +1177,10 @@ export class CommandController {
|
|
|
1175
1177
|
}
|
|
1176
1178
|
this.ctx.showError(`Bash command failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1177
1179
|
}
|
|
1180
|
+
const bashComponent = this.ctx.bashComponent;
|
|
1181
|
+
if (isDeferred && bashComponent && this.ctx.pendingBashComponents.includes(bashComponent)) {
|
|
1182
|
+
this.ctx.pendingMessagesContainer.detachChild(bashComponent);
|
|
1183
|
+
}
|
|
1178
1184
|
|
|
1179
1185
|
this.ctx.bashComponent = undefined;
|
|
1180
1186
|
this.ctx.ui.requestRender();
|
|
@@ -1252,11 +1258,7 @@ export class CommandController {
|
|
|
1252
1258
|
customInstructionsOrOptions?: string | CompactOptions,
|
|
1253
1259
|
isAuto = false,
|
|
1254
1260
|
): Promise<CompactionOutcome> {
|
|
1255
|
-
|
|
1256
|
-
this.ctx.loadingAnimation.stop();
|
|
1257
|
-
this.ctx.loadingAnimation = undefined;
|
|
1258
|
-
}
|
|
1259
|
-
this.ctx.statusContainer.clear();
|
|
1261
|
+
const releaseActivityIndicator = suspendInteractiveActivityIndicator(this.ctx);
|
|
1260
1262
|
|
|
1261
1263
|
const originalOnEscape = this.ctx.editor.onEscape;
|
|
1262
1264
|
this.ctx.editor.onEscape = () => {
|
|
@@ -1283,24 +1285,28 @@ export class CommandController {
|
|
|
1283
1285
|
? customInstructionsOrOptions
|
|
1284
1286
|
: undefined;
|
|
1285
1287
|
await this.ctx.session.compact(instructions, options);
|
|
1288
|
+
if (this.ctx.isStopped?.()) return outcome;
|
|
1286
1289
|
|
|
1287
1290
|
this.ctx.rebuildChatFromMessages("reconcile-same-transcript");
|
|
1288
1291
|
|
|
1289
1292
|
this.ctx.statusLine.invalidate();
|
|
1290
1293
|
this.ctx.updateEditorTopBorder();
|
|
1291
1294
|
} catch (error) {
|
|
1292
|
-
|
|
1293
|
-
|
|
1295
|
+
outcome = error instanceof CompactionCancelledError ? "cancelled" : "failed";
|
|
1296
|
+
if (this.ctx.isStopped?.()) return outcome;
|
|
1297
|
+
if (outcome === "cancelled") {
|
|
1294
1298
|
this.ctx.showError("Compaction cancelled");
|
|
1295
1299
|
} else {
|
|
1296
|
-
outcome = "failed";
|
|
1297
1300
|
const message = error instanceof Error ? error.message : String(error);
|
|
1298
1301
|
this.ctx.showError(`Compaction failed: ${message}`);
|
|
1299
1302
|
}
|
|
1300
1303
|
} finally {
|
|
1301
1304
|
compactingLoader.stop();
|
|
1302
|
-
this.ctx.
|
|
1303
|
-
|
|
1305
|
+
if (!this.ctx.isStopped?.()) {
|
|
1306
|
+
this.ctx.statusContainer.clear();
|
|
1307
|
+
this.ctx.editor.onEscape = originalOnEscape;
|
|
1308
|
+
}
|
|
1309
|
+
releaseActivityIndicator();
|
|
1304
1310
|
}
|
|
1305
1311
|
await this.ctx.flushCompactionQueue({ willRetry: false });
|
|
1306
1312
|
return outcome;
|
|
@@ -1319,11 +1325,7 @@ export class CommandController {
|
|
|
1319
1325
|
return;
|
|
1320
1326
|
}
|
|
1321
1327
|
|
|
1322
|
-
|
|
1323
|
-
this.ctx.loadingAnimation.stop();
|
|
1324
|
-
this.ctx.loadingAnimation = undefined;
|
|
1325
|
-
}
|
|
1326
|
-
this.ctx.statusContainer.clear();
|
|
1328
|
+
const releaseActivityIndicator = suspendInteractiveActivityIndicator(this.ctx);
|
|
1327
1329
|
|
|
1328
1330
|
const originalOnEscape = this.ctx.editor.onEscape;
|
|
1329
1331
|
this.ctx.editor.onEscape = () => {
|
|
@@ -1343,6 +1345,7 @@ export class CommandController {
|
|
|
1343
1345
|
try {
|
|
1344
1346
|
// Handoff generation runs as a oneshot request; the new session is shown after it completes.
|
|
1345
1347
|
const result = await this.ctx.session.handoff(customInstructions);
|
|
1348
|
+
if (this.ctx.isStopped?.()) return;
|
|
1346
1349
|
|
|
1347
1350
|
if (!result) {
|
|
1348
1351
|
this.ctx.showError("Handoff cancelled");
|
|
@@ -1357,6 +1360,7 @@ export class CommandController {
|
|
|
1357
1360
|
this.ctx.updateEditorTopBorder();
|
|
1358
1361
|
this.ctx.updateEditorBorderColor();
|
|
1359
1362
|
await this.ctx.reloadTodos();
|
|
1363
|
+
if (this.ctx.isStopped?.()) return;
|
|
1360
1364
|
|
|
1361
1365
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
1362
1366
|
this.ctx.chatContainer.addChild(
|
|
@@ -1366,6 +1370,7 @@ export class CommandController {
|
|
|
1366
1370
|
this.ctx.showStatus(`Handoff document saved to: ${result.savedPath}`);
|
|
1367
1371
|
}
|
|
1368
1372
|
} catch (error) {
|
|
1373
|
+
if (this.ctx.isStopped?.()) return;
|
|
1369
1374
|
const message = error instanceof Error ? error.message : String(error);
|
|
1370
1375
|
if (message === "Handoff cancelled" || (error instanceof Error && error.name === "AbortError")) {
|
|
1371
1376
|
this.ctx.showError("Handoff cancelled");
|
|
@@ -1385,8 +1390,11 @@ export class CommandController {
|
|
|
1385
1390
|
}
|
|
1386
1391
|
} finally {
|
|
1387
1392
|
handoffLoader.stop();
|
|
1388
|
-
this.ctx.
|
|
1389
|
-
|
|
1393
|
+
if (!this.ctx.isStopped?.()) {
|
|
1394
|
+
this.ctx.statusContainer.clear();
|
|
1395
|
+
this.ctx.editor.onEscape = originalOnEscape;
|
|
1396
|
+
}
|
|
1397
|
+
releaseActivityIndicator();
|
|
1390
1398
|
}
|
|
1391
1399
|
}
|
|
1392
1400
|
|