@wrongstack/tui 1.0.26 → 1.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-action-type.d.ts +14 -0
- package/dist/app-panel-state.d.ts +24 -0
- package/dist/app-settings-type.d.ts +1 -0
- package/dist/components/history/scrollbar-rail.d.ts +1 -1
- package/dist/components/settings-picker.d.ts +2 -1
- package/dist/components/status-bar-types.d.ts +13 -0
- package/dist/components/status-bar.d.ts +1 -1
- package/dist/components/theme-picker.d.ts +19 -7
- package/dist/connections-health.d.ts +1 -0
- package/dist/connections-slash.d.ts +2 -2
- package/dist/hit-test.d.ts +2 -2
- package/dist/hooks/failed-run-tracker.d.ts +30 -0
- package/dist/hooks/tui-slash-command-options.d.ts +9 -0
- package/dist/hooks/use-app-picker-keys.d.ts +2 -1
- package/dist/hooks/use-mcp-status-bridge.d.ts +18 -0
- package/dist/hooks/use-next-steps-auto-submit.d.ts +4 -2
- package/dist/hooks/use-picker-keys-types.d.ts +5 -0
- package/dist/hooks/use-provider-quota.d.ts +5 -0
- package/dist/hooks/use-theme-picker-handler.d.ts +7 -2
- package/dist/hooks/use-tui-slash-commands.d.ts +1 -1
- package/dist/index.js +2177 -1919
- package/dist/input-validation/action-types.d.ts +1 -1
- package/dist/reducers/composer-action-types.d.ts +1 -1
- package/dist/settings-contracts.d.ts +1 -0
- package/dist/theme-picker-rows.d.ts +70 -0
- package/dist/theme-presets/options.d.ts +13 -1
- package/dist/theme-presets/rose-pine.d.ts +1 -1
- package/dist/theme-types.d.ts +6 -0
- package/dist/theme-utils.d.ts +11 -0
- package/dist/use-controller-key-pipeline.d.ts +2 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -24887,378 +24887,1014 @@ var require_jsx_runtime = __commonJS({
|
|
|
24887
24887
|
}
|
|
24888
24888
|
});
|
|
24889
24889
|
|
|
24890
|
-
// src/
|
|
24891
|
-
var
|
|
24892
|
-
__export(
|
|
24893
|
-
|
|
24890
|
+
// src/connection-actions.ts
|
|
24891
|
+
var connection_actions_exports = {};
|
|
24892
|
+
__export(connection_actions_exports, {
|
|
24893
|
+
RESTARTABLE_SERVICES: () => RESTARTABLE_SERVICES,
|
|
24894
|
+
executeConnectionAction: () => executeConnectionAction,
|
|
24895
|
+
isEndpointAlive: () => isEndpointAlive,
|
|
24896
|
+
isRestartableService: () => isRestartableService,
|
|
24897
|
+
killChronicleServer: () => killChronicleServer,
|
|
24898
|
+
killCodebaseIndexServer: () => killCodebaseIndexServer,
|
|
24899
|
+
killKanbanServer: () => killKanbanServer,
|
|
24900
|
+
killMailboxServer: () => killMailboxServer,
|
|
24901
|
+
killSageServer: () => killSageServer,
|
|
24902
|
+
killSessionCatalogServer: () => killSessionCatalogServer,
|
|
24903
|
+
restartAllConnectionServices: () => restartAllConnectionServices,
|
|
24904
|
+
waitForShutdown: () => waitForShutdown
|
|
24894
24905
|
});
|
|
24895
|
-
import
|
|
24906
|
+
import * as net from "node:net";
|
|
24896
24907
|
import {
|
|
24897
|
-
|
|
24898
|
-
|
|
24908
|
+
ChronicleProjectServerClient,
|
|
24909
|
+
createChronicleProjectAccess,
|
|
24910
|
+
resolveChronicleProjectServerOptions
|
|
24911
|
+
} from "@wrongstack/core/chronicle";
|
|
24912
|
+
import {
|
|
24913
|
+
isMailboxProjectServerAvailable,
|
|
24914
|
+
MailboxProjectServerConnection
|
|
24899
24915
|
} from "@wrongstack/core/coordination";
|
|
24900
|
-
import { SessionCatalogProjectClient
|
|
24901
|
-
import { resolveWstackPaths as resolveWstackPaths3 } from "@wrongstack/core/utils";
|
|
24902
|
-
import { getKanbanServerConnection as getKanbanServerConnection2 } from "@wrongstack/kanban";
|
|
24903
|
-
import { readGovernanceDaemonOperatorStatus } from "@wrongstack/runtime/governance-bootstrap";
|
|
24904
|
-
import { isSageProjectServerAvailable as isSageProjectServerAvailable2, SageProjectServerConnection as SageProjectServerConnection2 } from "@wrongstack/sage";
|
|
24916
|
+
import { SessionCatalogProjectClient } from "@wrongstack/core/session-catalog";
|
|
24905
24917
|
import {
|
|
24906
|
-
|
|
24907
|
-
|
|
24908
|
-
|
|
24918
|
+
assertDaemonRuntimeVersion,
|
|
24919
|
+
resolveWstackPaths as resolveWstackPaths2,
|
|
24920
|
+
toErrorMessage
|
|
24921
|
+
} from "@wrongstack/core/utils";
|
|
24922
|
+
import {
|
|
24923
|
+
closeKanbanServerConnections,
|
|
24924
|
+
getKanbanServerConnection,
|
|
24925
|
+
isKanbanServerAvailable
|
|
24926
|
+
} from "@wrongstack/kanban";
|
|
24927
|
+
import { isSageProjectServerAvailable, SageProjectServerConnection } from "@wrongstack/sage";
|
|
24928
|
+
import {
|
|
24929
|
+
checkCodebaseIndexServerHealth,
|
|
24930
|
+
ensureCodebaseIndexServer,
|
|
24931
|
+
shutdownCodebaseIndexServer
|
|
24909
24932
|
} from "@wrongstack/tools";
|
|
24910
|
-
|
|
24911
|
-
|
|
24912
|
-
sessionCatalogHealth(projectRoot),
|
|
24913
|
-
chronicleHealth(projectRoot),
|
|
24914
|
-
codebaseIndexHealth(projectRoot),
|
|
24915
|
-
sageHealth(projectRoot),
|
|
24916
|
-
kanbanHealth(projectRoot),
|
|
24917
|
-
mailboxHealth(projectRoot),
|
|
24918
|
-
governanceHealth(projectRoot)
|
|
24919
|
-
]);
|
|
24920
|
-
const required = services.filter((s2) => s2.required);
|
|
24921
|
-
const overall = required.some((s2) => s2.status === "error") ? "error" : required.some((s2) => s2.status !== "healthy") ? "degraded" : "healthy";
|
|
24922
|
-
return { checkedAt: Date.now(), overall, services };
|
|
24933
|
+
function isRestartableService(serviceId) {
|
|
24934
|
+
return RESTARTABLE_SERVICES.includes(serviceId);
|
|
24923
24935
|
}
|
|
24924
|
-
|
|
24925
|
-
|
|
24926
|
-
|
|
24927
|
-
const
|
|
24928
|
-
|
|
24929
|
-
|
|
24930
|
-
|
|
24936
|
+
function isEndpointAlive(endpoint) {
|
|
24937
|
+
return new Promise((resolve) => {
|
|
24938
|
+
const sock = net.createConnection(endpoint);
|
|
24939
|
+
const timer = setTimeout(() => {
|
|
24940
|
+
sock.destroy();
|
|
24941
|
+
resolve(false);
|
|
24942
|
+
}, 500);
|
|
24943
|
+
timer.unref?.();
|
|
24944
|
+
sock.once("connect", () => {
|
|
24945
|
+
clearTimeout(timer);
|
|
24946
|
+
sock.destroy();
|
|
24947
|
+
resolve(true);
|
|
24948
|
+
});
|
|
24949
|
+
sock.once("error", () => {
|
|
24950
|
+
clearTimeout(timer);
|
|
24951
|
+
sock.destroy();
|
|
24952
|
+
resolve(false);
|
|
24931
24953
|
});
|
|
24954
|
+
});
|
|
24955
|
+
}
|
|
24956
|
+
async function waitForShutdown(probe) {
|
|
24957
|
+
const pollIntervalMs = 250;
|
|
24958
|
+
if (!probe) {
|
|
24959
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
24960
|
+
return;
|
|
24961
|
+
}
|
|
24962
|
+
const deadline = Date.now() + 3e3;
|
|
24963
|
+
while (Date.now() < deadline) {
|
|
24932
24964
|
try {
|
|
24933
|
-
const
|
|
24965
|
+
const stillUp = await probe();
|
|
24966
|
+
if (!stillUp) return;
|
|
24967
|
+
} catch {
|
|
24968
|
+
return;
|
|
24969
|
+
}
|
|
24970
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
24971
|
+
}
|
|
24972
|
+
throw new Error("Daemon did not stop before the restart deadline; restart was not verified.");
|
|
24973
|
+
}
|
|
24974
|
+
async function executeConnectionAction(serviceId, action, projectRoot, indexDir) {
|
|
24975
|
+
switch (serviceId) {
|
|
24976
|
+
case "session-catalog":
|
|
24977
|
+
return killSessionCatalogServer(projectRoot, action);
|
|
24978
|
+
case "kanban":
|
|
24979
|
+
return killKanbanServer(projectRoot, action);
|
|
24980
|
+
case "sage":
|
|
24981
|
+
return killSageServer(projectRoot, action);
|
|
24982
|
+
case "chronicle":
|
|
24983
|
+
return killChronicleServer(projectRoot, action);
|
|
24984
|
+
case "codebase-index":
|
|
24985
|
+
return killCodebaseIndexServer(projectRoot, indexDir, action);
|
|
24986
|
+
case "mailbox":
|
|
24987
|
+
return killMailboxServer(projectRoot, action);
|
|
24988
|
+
case "governance":
|
|
24934
24989
|
return {
|
|
24935
|
-
|
|
24936
|
-
|
|
24937
|
-
|
|
24938
|
-
|
|
24939
|
-
|
|
24940
|
-
|
|
24941
|
-
|
|
24942
|
-
|
|
24943
|
-
|
|
24944
|
-
|
|
24945
|
-
|
|
24946
|
-
|
|
24947
|
-
|
|
24948
|
-
|
|
24990
|
+
serviceId: "governance",
|
|
24991
|
+
action,
|
|
24992
|
+
success: false,
|
|
24993
|
+
message: "Governance control plane is read-only; daemon restart is not supported."
|
|
24994
|
+
};
|
|
24995
|
+
default:
|
|
24996
|
+
return {
|
|
24997
|
+
serviceId,
|
|
24998
|
+
action,
|
|
24999
|
+
success: false,
|
|
25000
|
+
message: `Unknown service: ${serviceId}`
|
|
25001
|
+
};
|
|
25002
|
+
}
|
|
25003
|
+
}
|
|
25004
|
+
async function restartAllConnectionServices(projectRoot, indexDir) {
|
|
25005
|
+
const results = [];
|
|
25006
|
+
for (const id of RESTARTABLE_SERVICES) {
|
|
25007
|
+
try {
|
|
25008
|
+
results.push(await executeConnectionAction(id, "restart", projectRoot, indexDir));
|
|
25009
|
+
} catch (error) {
|
|
25010
|
+
results.push({
|
|
25011
|
+
serviceId: id,
|
|
25012
|
+
action: "restart",
|
|
25013
|
+
success: false,
|
|
25014
|
+
message: toErrorMessage(error)
|
|
25015
|
+
});
|
|
25016
|
+
}
|
|
25017
|
+
}
|
|
25018
|
+
return results;
|
|
25019
|
+
}
|
|
25020
|
+
async function killSessionCatalogServer(projectRoot, action) {
|
|
25021
|
+
const paths = resolveWstackPaths2({ projectRoot });
|
|
25022
|
+
const client = new SessionCatalogProjectClient({
|
|
25023
|
+
projectDir: paths.projectDir,
|
|
25024
|
+
projectRoot
|
|
25025
|
+
});
|
|
25026
|
+
try {
|
|
25027
|
+
const previousPid = action === "restart" ? await client.callExisting("ping", {}, { timeoutMs: 1e3 }).then(
|
|
25028
|
+
(health2) => health2.pid,
|
|
25029
|
+
() => void 0
|
|
25030
|
+
) : void 0;
|
|
25031
|
+
const result = await client.shutdown(`TUI request: ${action}`);
|
|
25032
|
+
if (!result.stopped && action === "shutdown") {
|
|
25033
|
+
return {
|
|
25034
|
+
serviceId: "session-catalog",
|
|
25035
|
+
action,
|
|
25036
|
+
success: false,
|
|
25037
|
+
message: "Session Catalog IPC daemon is not running"
|
|
24949
25038
|
};
|
|
24950
|
-
} finally {
|
|
24951
|
-
await client.close().catch(() => void 0);
|
|
24952
25039
|
}
|
|
25040
|
+
if (action === "restart") return await restartSessionCatalogServer(projectRoot, previousPid);
|
|
25041
|
+
return {
|
|
25042
|
+
serviceId: "session-catalog",
|
|
25043
|
+
action,
|
|
25044
|
+
success: true,
|
|
25045
|
+
message: "Session Catalog IPC daemon shutdown requested"
|
|
25046
|
+
};
|
|
24953
25047
|
} catch (error) {
|
|
24954
|
-
const offline = isOfflineConnectionError(error);
|
|
24955
25048
|
return {
|
|
24956
|
-
|
|
24957
|
-
|
|
24958
|
-
|
|
24959
|
-
|
|
24960
|
-
mode: offline ? "on-demand project-daemon" : "project-daemon",
|
|
24961
|
-
detail: offline ? "Not running for this project; it starts on demand when a session is used." : "Project-scoped session ownership and catalog are unavailable.",
|
|
24962
|
-
latencyMs: Date.now() - startedAt,
|
|
24963
|
-
lastError: error instanceof Error ? error.message : String(error)
|
|
25049
|
+
serviceId: "session-catalog",
|
|
25050
|
+
action,
|
|
25051
|
+
success: false,
|
|
25052
|
+
message: toErrorMessage(error)
|
|
24964
25053
|
};
|
|
25054
|
+
} finally {
|
|
25055
|
+
await client.close().catch(() => void 0);
|
|
24965
25056
|
}
|
|
24966
25057
|
}
|
|
24967
|
-
async function
|
|
24968
|
-
const
|
|
24969
|
-
|
|
25058
|
+
async function restartSessionCatalogServer(projectRoot, previousPid) {
|
|
25059
|
+
const paths = resolveWstackPaths2({ projectRoot });
|
|
25060
|
+
const probe = () => {
|
|
25061
|
+
const client = new SessionCatalogProjectClient({
|
|
25062
|
+
projectDir: paths.projectDir,
|
|
25063
|
+
projectRoot
|
|
25064
|
+
});
|
|
25065
|
+
return client.callExisting("ping", {}, { timeoutMs: 1e3 }).then(
|
|
25066
|
+
() => true,
|
|
25067
|
+
() => false
|
|
25068
|
+
).finally(() => client.close().catch(() => void 0));
|
|
25069
|
+
};
|
|
25070
|
+
await waitForShutdown(probe);
|
|
25071
|
+
const verify = new SessionCatalogProjectClient({
|
|
25072
|
+
projectDir: paths.projectDir,
|
|
25073
|
+
projectRoot
|
|
25074
|
+
});
|
|
24970
25075
|
try {
|
|
24971
|
-
|
|
24972
|
-
|
|
24973
|
-
|
|
25076
|
+
const health2 = await verify.ping();
|
|
25077
|
+
assertDaemonRuntimeVersion(health2.runtimeVersion);
|
|
25078
|
+
if (previousPid !== void 0 && health2.pid === previousPid) {
|
|
25079
|
+
return {
|
|
25080
|
+
serviceId: "session-catalog",
|
|
25081
|
+
action: "restart",
|
|
25082
|
+
success: false,
|
|
25083
|
+
message: `Session Catalog IPC daemon did not restart (owner PID is still ${previousPid})`
|
|
25084
|
+
};
|
|
25085
|
+
}
|
|
24974
25086
|
return {
|
|
24975
|
-
|
|
24976
|
-
|
|
24977
|
-
|
|
24978
|
-
|
|
24979
|
-
mode: access.mode,
|
|
24980
|
-
detail: quarantined.length > 0 ? `Serving, but ${quarantined.length} day(s) were quarantined for a broken chain: ${quarantined.map((family) => family.day).join(", ")}.` : access.mode === "server" ? "One project owner collects, processes, stores, and serves telemetry." : "Inline fallback is active; ownership is not shared across clients.",
|
|
24981
|
-
ownerPid: health2.pid,
|
|
24982
|
-
endpoint: health2.endpoint,
|
|
24983
|
-
storage: health2.chronicleDirectory,
|
|
24984
|
-
uptimeMs: health2.uptimeMs,
|
|
24985
|
-
latencyMs: Date.now() - startedAt,
|
|
24986
|
-
clients: health2.clients,
|
|
24987
|
-
activeRequests: health2.activeRequests,
|
|
24988
|
-
queuedWork: health2.journal.pendingEvents,
|
|
24989
|
-
watcher: { active: health2.watcher.active, watchedFiles: health2.watcher.watchedFiles },
|
|
24990
|
-
...quarantined[0] ? { lastError: quarantined[0].reason } : health2.watcher.lastError ? { lastError: health2.watcher.lastError } : {}
|
|
25087
|
+
serviceId: "session-catalog",
|
|
25088
|
+
action: "restart",
|
|
25089
|
+
success: true,
|
|
25090
|
+
message: "Session Catalog IPC daemon restarted successfully"
|
|
24991
25091
|
};
|
|
24992
25092
|
} catch (error) {
|
|
24993
|
-
return
|
|
24994
|
-
"
|
|
24995
|
-
|
|
24996
|
-
|
|
24997
|
-
|
|
24998
|
-
|
|
24999
|
-
Date.now() - startedAt
|
|
25000
|
-
);
|
|
25093
|
+
return {
|
|
25094
|
+
serviceId: "session-catalog",
|
|
25095
|
+
action: "restart",
|
|
25096
|
+
success: false,
|
|
25097
|
+
message: `Session Catalog IPC daemon restarted but verification failed: ${toErrorMessage(error)}`
|
|
25098
|
+
};
|
|
25001
25099
|
} finally {
|
|
25002
|
-
await
|
|
25100
|
+
await verify.close().catch(() => void 0);
|
|
25003
25101
|
}
|
|
25004
25102
|
}
|
|
25005
|
-
async function
|
|
25006
|
-
|
|
25007
|
-
const availability = resolveProjectIndexDaemonAvailability(projectRoot);
|
|
25008
|
-
if (availability.kind === "endpoint-invalid") {
|
|
25103
|
+
async function killKanbanServer(projectRoot, action) {
|
|
25104
|
+
if (process.env["WRONGSTACK_KANBAN_SERVER"] === "0") {
|
|
25009
25105
|
return {
|
|
25010
|
-
|
|
25011
|
-
|
|
25012
|
-
|
|
25013
|
-
|
|
25014
|
-
mode: "endpoint-invalid",
|
|
25015
|
-
detail: `Socket path is ${availability.byteLength} bytes \u2014 over this platform's ${availability.maxBytes}-byte sun_path limit. Queries fall back to a process-local index. Set a shorter TMPDIR to restore the shared daemon.`,
|
|
25016
|
-
endpoint: availability.endpoint,
|
|
25017
|
-
latencyMs: Date.now() - startedAt
|
|
25106
|
+
serviceId: "kanban",
|
|
25107
|
+
action,
|
|
25108
|
+
success: false,
|
|
25109
|
+
message: "Kanban IPC daemon is disabled via WRONGSTACK_KANBAN_SERVER=0"
|
|
25018
25110
|
};
|
|
25019
25111
|
}
|
|
25112
|
+
let connection;
|
|
25020
25113
|
try {
|
|
25021
|
-
|
|
25022
|
-
|
|
25023
|
-
});
|
|
25024
|
-
const connection = getIndexState().server;
|
|
25114
|
+
connection = await getKanbanServerConnection(projectRoot);
|
|
25115
|
+
} catch (error) {
|
|
25025
25116
|
return {
|
|
25026
|
-
|
|
25027
|
-
|
|
25028
|
-
|
|
25029
|
-
|
|
25030
|
-
mode: "project-server",
|
|
25031
|
-
detail: health2.server?.activity.indexing ? `Indexing ${health2.server.activity.currentFile}/${health2.server.activity.totalFiles}.` : "Shared symbol index is ready for project queries.",
|
|
25032
|
-
ownerPid: connection.pid,
|
|
25033
|
-
endpoint: connection.endpoint,
|
|
25034
|
-
storage: connection.indexDir ?? resolveWstackPaths3({ projectRoot }).projectCodebaseIndex,
|
|
25035
|
-
uptimeMs: health2.server?.uptimeMs,
|
|
25036
|
-
latencyMs: health2.latencyMs ?? Date.now() - startedAt,
|
|
25037
|
-
clients: health2.server?.clients,
|
|
25038
|
-
activeRequests: health2.server?.activeRequests,
|
|
25039
|
-
queuedWork: health2.server?.queuedWrites,
|
|
25040
|
-
watcher: health2.server ? { active: health2.server.watchingExternal, watchedFiles: health2.server.watchingClients } : void 0
|
|
25117
|
+
serviceId: "kanban",
|
|
25118
|
+
action,
|
|
25119
|
+
success: false,
|
|
25120
|
+
message: toErrorMessage(error)
|
|
25041
25121
|
};
|
|
25042
|
-
} catch (error) {
|
|
25043
|
-
if (isOfflineConnectionError(error)) {
|
|
25044
|
-
return {
|
|
25045
|
-
...failureService(
|
|
25046
|
-
"codebase-index",
|
|
25047
|
-
"Codebase index",
|
|
25048
|
-
false,
|
|
25049
|
-
"on-demand project-server",
|
|
25050
|
-
error,
|
|
25051
|
-
Date.now() - startedAt
|
|
25052
|
-
),
|
|
25053
|
-
status: "offline",
|
|
25054
|
-
detail: "Not running for this project; it starts on demand when indexing is used."
|
|
25055
|
-
};
|
|
25056
|
-
}
|
|
25057
|
-
return failureService(
|
|
25058
|
-
"codebase-index",
|
|
25059
|
-
"Codebase index",
|
|
25060
|
-
false,
|
|
25061
|
-
"project-server",
|
|
25062
|
-
error,
|
|
25063
|
-
Date.now() - startedAt
|
|
25064
|
-
);
|
|
25065
25122
|
}
|
|
25066
|
-
|
|
25067
|
-
async function sageHealth(projectRoot) {
|
|
25068
|
-
const startedAt = Date.now();
|
|
25069
|
-
if (!isSageProjectServerAvailable2()) {
|
|
25123
|
+
if (!connection) {
|
|
25070
25124
|
return {
|
|
25071
|
-
|
|
25072
|
-
|
|
25073
|
-
|
|
25074
|
-
|
|
25075
|
-
mode: "unavailable",
|
|
25076
|
-
detail: "The packaged SAGE project server is unavailable in this runtime."
|
|
25125
|
+
serviceId: "kanban",
|
|
25126
|
+
action,
|
|
25127
|
+
success: false,
|
|
25128
|
+
message: "Kanban IPC daemon is not running"
|
|
25077
25129
|
};
|
|
25078
25130
|
}
|
|
25079
|
-
const connection = new SageProjectServerConnection2(projectRoot);
|
|
25080
25131
|
try {
|
|
25081
|
-
const
|
|
25082
|
-
|
|
25132
|
+
const result = await connection.request("shutdown", {
|
|
25133
|
+
reason: `TUI request: ${action}`
|
|
25134
|
+
});
|
|
25135
|
+
if (!result.stopping) {
|
|
25083
25136
|
return {
|
|
25084
|
-
|
|
25085
|
-
|
|
25086
|
-
|
|
25087
|
-
|
|
25088
|
-
mode: "on-demand project-server",
|
|
25089
|
-
detail: "Not running for this project; it starts on demand when memory is used.",
|
|
25090
|
-
endpoint: connection.getState().endpoint,
|
|
25091
|
-
latencyMs: Date.now() - startedAt
|
|
25137
|
+
serviceId: "kanban",
|
|
25138
|
+
action,
|
|
25139
|
+
success: false,
|
|
25140
|
+
message: "Kanban IPC daemon shutdown failed (not confirmed)"
|
|
25092
25141
|
};
|
|
25093
25142
|
}
|
|
25094
|
-
|
|
25143
|
+
if (action === "restart") {
|
|
25144
|
+
closeKanbanServerConnections();
|
|
25145
|
+
return await restartKanbanServer(projectRoot);
|
|
25146
|
+
}
|
|
25095
25147
|
return {
|
|
25096
|
-
|
|
25097
|
-
|
|
25098
|
-
|
|
25099
|
-
|
|
25100
|
-
mode: "project-server",
|
|
25101
|
-
detail: `Persistent project memory backend: ${status.health.backend}.`,
|
|
25102
|
-
ownerPid: status.pid,
|
|
25103
|
-
endpoint: status.endpoint,
|
|
25104
|
-
storage: status.storageRoot,
|
|
25105
|
-
latencyMs: Date.now() - startedAt,
|
|
25106
|
-
clients: status.clients,
|
|
25107
|
-
activeRequests: status.pendingRequests
|
|
25148
|
+
serviceId: "kanban",
|
|
25149
|
+
action,
|
|
25150
|
+
success: true,
|
|
25151
|
+
message: "Kanban IPC daemon shutdown requested"
|
|
25108
25152
|
};
|
|
25109
25153
|
} catch (error) {
|
|
25110
|
-
return failureService(
|
|
25111
|
-
"sage",
|
|
25112
|
-
"SAGE memory",
|
|
25113
|
-
false,
|
|
25114
|
-
"project-server",
|
|
25115
|
-
error,
|
|
25116
|
-
Date.now() - startedAt
|
|
25117
|
-
);
|
|
25118
|
-
} finally {
|
|
25119
|
-
connection.close();
|
|
25120
|
-
}
|
|
25121
|
-
}
|
|
25122
|
-
async function kanbanHealth(projectRoot) {
|
|
25123
|
-
const startedAt = Date.now();
|
|
25124
|
-
if (process.env["WRONGSTACK_KANBAN_SERVER"] === "0") {
|
|
25125
25154
|
return {
|
|
25126
|
-
|
|
25127
|
-
|
|
25128
|
-
|
|
25129
|
-
|
|
25130
|
-
mode: "disabled",
|
|
25131
|
-
detail: "Kanban IPC daemon is disabled via WRONGSTACK_KANBAN_SERVER=0."
|
|
25155
|
+
serviceId: "kanban",
|
|
25156
|
+
action,
|
|
25157
|
+
success: false,
|
|
25158
|
+
message: toErrorMessage(error)
|
|
25132
25159
|
};
|
|
25133
25160
|
}
|
|
25134
|
-
|
|
25161
|
+
}
|
|
25162
|
+
async function restartKanbanServer(projectRoot) {
|
|
25163
|
+
await waitForShutdown(() => isKanbanServerAvailable(projectRoot));
|
|
25135
25164
|
try {
|
|
25136
|
-
connection = await
|
|
25137
|
-
|
|
25138
|
-
|
|
25139
|
-
|
|
25140
|
-
|
|
25141
|
-
|
|
25142
|
-
|
|
25143
|
-
|
|
25144
|
-
|
|
25145
|
-
);
|
|
25146
|
-
|
|
25147
|
-
if (!connection) {
|
|
25165
|
+
const connection = await getKanbanServerConnection(projectRoot);
|
|
25166
|
+
if (!connection) {
|
|
25167
|
+
return {
|
|
25168
|
+
serviceId: "kanban",
|
|
25169
|
+
action: "restart",
|
|
25170
|
+
success: false,
|
|
25171
|
+
message: "Kanban IPC daemon failed to restart (no connection after re-init)"
|
|
25172
|
+
};
|
|
25173
|
+
}
|
|
25174
|
+
const health2 = await connection.request("ping", {}, { timeoutMs: 1e4 });
|
|
25175
|
+
assertDaemonRuntimeVersion(health2.runtimeVersion);
|
|
25148
25176
|
return {
|
|
25149
|
-
|
|
25150
|
-
|
|
25151
|
-
|
|
25152
|
-
|
|
25153
|
-
mode: "disabled",
|
|
25154
|
-
detail: "Kanban IPC daemon is disabled in this runtime."
|
|
25177
|
+
serviceId: "kanban",
|
|
25178
|
+
action: "restart",
|
|
25179
|
+
success: true,
|
|
25180
|
+
message: "Kanban IPC daemon restarted successfully"
|
|
25155
25181
|
};
|
|
25156
|
-
}
|
|
25157
|
-
try {
|
|
25158
|
-
const status = await connection.request("ping", {}, { timeoutMs: 5e3 });
|
|
25182
|
+
} catch (error) {
|
|
25159
25183
|
return {
|
|
25160
|
-
|
|
25161
|
-
|
|
25162
|
-
|
|
25163
|
-
|
|
25164
|
-
mode: "project-server",
|
|
25165
|
-
detail: `Single shared project-server owns kanban state (v${status.protocolVersion}).`,
|
|
25166
|
-
ownerPid: status.pid,
|
|
25167
|
-
endpoint: status.endpoint,
|
|
25168
|
-
storage: status.databasePath,
|
|
25169
|
-
latencyMs: Date.now() - startedAt,
|
|
25170
|
-
clients: status.clients,
|
|
25171
|
-
activeRequests: status.pendingRequests,
|
|
25172
|
-
uptimeMs: Date.now() - new Date(status.startedAt).getTime()
|
|
25184
|
+
serviceId: "kanban",
|
|
25185
|
+
action: "restart",
|
|
25186
|
+
success: false,
|
|
25187
|
+
message: `Kanban IPC daemon restarted but verification failed: ${toErrorMessage(error)}`
|
|
25173
25188
|
};
|
|
25174
|
-
} catch (error) {
|
|
25175
|
-
return failureService(
|
|
25176
|
-
"kanban",
|
|
25177
|
-
"Kanban IPC",
|
|
25178
|
-
true,
|
|
25179
|
-
"project-server",
|
|
25180
|
-
error,
|
|
25181
|
-
Date.now() - startedAt
|
|
25182
|
-
);
|
|
25183
25189
|
}
|
|
25184
25190
|
}
|
|
25185
|
-
async function
|
|
25186
|
-
|
|
25187
|
-
if (!isMailboxProjectServerAvailable2()) {
|
|
25191
|
+
async function killSageServer(projectRoot, action) {
|
|
25192
|
+
if (!isSageProjectServerAvailable()) {
|
|
25188
25193
|
return {
|
|
25189
|
-
|
|
25190
|
-
|
|
25191
|
-
|
|
25192
|
-
|
|
25193
|
-
mode: "unavailable",
|
|
25194
|
-
detail: "The packaged mailbox project server is unavailable in this runtime."
|
|
25194
|
+
serviceId: "sage",
|
|
25195
|
+
action,
|
|
25196
|
+
success: false,
|
|
25197
|
+
message: "SAGE project server is unavailable in this runtime"
|
|
25195
25198
|
};
|
|
25196
25199
|
}
|
|
25197
|
-
const connection = new
|
|
25198
|
-
resolveWstackPaths3({ projectRoot }).projectDir
|
|
25199
|
-
);
|
|
25200
|
+
const connection = new SageProjectServerConnection(projectRoot);
|
|
25200
25201
|
try {
|
|
25201
|
-
const
|
|
25202
|
-
if (!
|
|
25202
|
+
const result = await connection.shutdown(`TUI request: ${action}`);
|
|
25203
|
+
if (!result.stopped) {
|
|
25204
|
+
if (action === "restart" && result.reason === "not-running") {
|
|
25205
|
+
return await restartSageServer(projectRoot);
|
|
25206
|
+
}
|
|
25203
25207
|
return {
|
|
25204
|
-
|
|
25205
|
-
|
|
25206
|
-
|
|
25207
|
-
|
|
25208
|
-
mode: "on-demand project-server",
|
|
25209
|
-
detail: "Not running for this project; it starts on demand when mailbox is used.",
|
|
25210
|
-
endpoint: connection.getState().endpoint,
|
|
25211
|
-
latencyMs: Date.now() - startedAt
|
|
25208
|
+
serviceId: "sage",
|
|
25209
|
+
action,
|
|
25210
|
+
success: false,
|
|
25211
|
+
message: `SAGE memory server shutdown failed: ${result.reason ?? "unknown"}`
|
|
25212
25212
|
};
|
|
25213
25213
|
}
|
|
25214
|
+
if (action === "restart") {
|
|
25215
|
+
return await restartSageServer(projectRoot);
|
|
25216
|
+
}
|
|
25214
25217
|
return {
|
|
25215
|
-
|
|
25216
|
-
|
|
25217
|
-
|
|
25218
|
-
|
|
25219
|
-
mode: "project-server",
|
|
25220
|
-
detail: `Single shared project-server owns inter-agent mailbox state (v${status.protocolVersion}).`,
|
|
25221
|
-
ownerPid: status.pid,
|
|
25222
|
-
endpoint: status.endpoint,
|
|
25223
|
-
storage: status.databasePath,
|
|
25224
|
-
latencyMs: Date.now() - startedAt,
|
|
25225
|
-
clients: status.clients,
|
|
25226
|
-
activeRequests: status.pendingRequests,
|
|
25227
|
-
uptimeMs: Date.now() - new Date(status.startedAt).getTime()
|
|
25218
|
+
serviceId: "sage",
|
|
25219
|
+
action,
|
|
25220
|
+
success: true,
|
|
25221
|
+
message: "SAGE memory server shutdown requested"
|
|
25228
25222
|
};
|
|
25229
25223
|
} catch (error) {
|
|
25230
|
-
return
|
|
25231
|
-
"
|
|
25232
|
-
|
|
25233
|
-
|
|
25234
|
-
|
|
25235
|
-
|
|
25236
|
-
Date.now() - startedAt
|
|
25237
|
-
);
|
|
25224
|
+
return {
|
|
25225
|
+
serviceId: "sage",
|
|
25226
|
+
action,
|
|
25227
|
+
success: false,
|
|
25228
|
+
message: toErrorMessage(error)
|
|
25229
|
+
};
|
|
25238
25230
|
} finally {
|
|
25239
25231
|
connection.close();
|
|
25240
25232
|
}
|
|
25241
25233
|
}
|
|
25242
|
-
async function
|
|
25243
|
-
|
|
25244
|
-
|
|
25245
|
-
|
|
25246
|
-
|
|
25234
|
+
async function restartSageServer(projectRoot) {
|
|
25235
|
+
await waitForShutdown(async () => {
|
|
25236
|
+
const probe = new SageProjectServerConnection(projectRoot);
|
|
25237
|
+
try {
|
|
25238
|
+
return await probe.status() !== null;
|
|
25239
|
+
} finally {
|
|
25240
|
+
probe.close();
|
|
25241
|
+
}
|
|
25242
|
+
});
|
|
25243
|
+
const verifyConn = new SageProjectServerConnection(projectRoot);
|
|
25244
|
+
try {
|
|
25245
|
+
const health2 = await verifyConn.call(
|
|
25246
|
+
"ping",
|
|
25247
|
+
{},
|
|
25248
|
+
{ timeoutMs: 1e4, meta: { clientId: `sage-restart-${process.pid}` } }
|
|
25249
|
+
);
|
|
25250
|
+
assertDaemonRuntimeVersion(health2.runtimeVersion);
|
|
25247
25251
|
return {
|
|
25248
|
-
|
|
25249
|
-
|
|
25250
|
-
|
|
25251
|
-
|
|
25252
|
-
mode: missing ? "compatibility-default-off" : "project-daemon",
|
|
25253
|
-
detail: missing ? "Not active for this project. Existing agent and model execution remains unchanged." : `Read-only governance status is unavailable: ${result.message}`,
|
|
25254
|
-
latencyMs: Date.now() - startedAt,
|
|
25255
|
-
control: "none",
|
|
25256
|
-
...missing ? {} : { lastError: result.message }
|
|
25252
|
+
serviceId: "sage",
|
|
25253
|
+
action: "restart",
|
|
25254
|
+
success: true,
|
|
25255
|
+
message: "SAGE memory server restarted successfully"
|
|
25257
25256
|
};
|
|
25258
|
-
}
|
|
25259
|
-
|
|
25260
|
-
|
|
25261
|
-
|
|
25257
|
+
} catch (error) {
|
|
25258
|
+
return {
|
|
25259
|
+
serviceId: "sage",
|
|
25260
|
+
action: "restart",
|
|
25261
|
+
success: false,
|
|
25262
|
+
message: `SAGE memory server restarted but verification failed: ${toErrorMessage(error)}`
|
|
25263
|
+
};
|
|
25264
|
+
} finally {
|
|
25265
|
+
verifyConn.close();
|
|
25266
|
+
}
|
|
25267
|
+
}
|
|
25268
|
+
async function killChronicleServer(projectRoot, action) {
|
|
25269
|
+
const options = resolveChronicleProjectServerOptions({ projectRoot });
|
|
25270
|
+
const client = new ChronicleProjectServerClient(options);
|
|
25271
|
+
try {
|
|
25272
|
+
const result = await client.shutdown(`TUI request: ${action}`);
|
|
25273
|
+
if (!result.stopped) {
|
|
25274
|
+
if (action === "restart" && result.reason === "offline") {
|
|
25275
|
+
return await restartChronicleServer(projectRoot);
|
|
25276
|
+
}
|
|
25277
|
+
return {
|
|
25278
|
+
serviceId: "chronicle",
|
|
25279
|
+
action,
|
|
25280
|
+
success: false,
|
|
25281
|
+
message: `Chronicle telemetry server shutdown failed: ${result.reason ?? "unknown"}`
|
|
25282
|
+
};
|
|
25283
|
+
}
|
|
25284
|
+
if (action === "restart") {
|
|
25285
|
+
return await restartChronicleServer(projectRoot);
|
|
25286
|
+
}
|
|
25287
|
+
return {
|
|
25288
|
+
serviceId: "chronicle",
|
|
25289
|
+
action,
|
|
25290
|
+
success: true,
|
|
25291
|
+
message: "Chronicle telemetry server shutdown requested"
|
|
25292
|
+
};
|
|
25293
|
+
} catch (error) {
|
|
25294
|
+
return {
|
|
25295
|
+
serviceId: "chronicle",
|
|
25296
|
+
action,
|
|
25297
|
+
success: false,
|
|
25298
|
+
message: toErrorMessage(error)
|
|
25299
|
+
};
|
|
25300
|
+
} finally {
|
|
25301
|
+
client.close();
|
|
25302
|
+
}
|
|
25303
|
+
}
|
|
25304
|
+
async function restartChronicleServer(projectRoot) {
|
|
25305
|
+
const options = resolveChronicleProjectServerOptions({ projectRoot });
|
|
25306
|
+
const endpoint = new ChronicleProjectServerClient(options).endpoint;
|
|
25307
|
+
await waitForShutdown(async () => isEndpointAlive(endpoint));
|
|
25308
|
+
let access;
|
|
25309
|
+
try {
|
|
25310
|
+
access = createChronicleProjectAccess({ projectRoot });
|
|
25311
|
+
const health2 = await access.call("ping", {}, { timeoutMs: 1e4 });
|
|
25312
|
+
if (access.mode !== "server") {
|
|
25313
|
+
return {
|
|
25314
|
+
serviceId: "chronicle",
|
|
25315
|
+
action: "restart",
|
|
25316
|
+
success: false,
|
|
25317
|
+
message: `Chronicle telemetry server restarted but running in ${access.mode} mode (expected server)`
|
|
25318
|
+
};
|
|
25319
|
+
}
|
|
25320
|
+
assertDaemonRuntimeVersion(health2.runtimeVersion);
|
|
25321
|
+
return {
|
|
25322
|
+
serviceId: "chronicle",
|
|
25323
|
+
action: "restart",
|
|
25324
|
+
success: true,
|
|
25325
|
+
message: "Chronicle telemetry server restarted successfully"
|
|
25326
|
+
};
|
|
25327
|
+
} catch (error) {
|
|
25328
|
+
return {
|
|
25329
|
+
serviceId: "chronicle",
|
|
25330
|
+
action: "restart",
|
|
25331
|
+
success: false,
|
|
25332
|
+
message: `Chronicle telemetry server restarted but verification failed: ${toErrorMessage(error)}`
|
|
25333
|
+
};
|
|
25334
|
+
} finally {
|
|
25335
|
+
await access?.close();
|
|
25336
|
+
}
|
|
25337
|
+
}
|
|
25338
|
+
async function killCodebaseIndexServer(projectRoot, indexDir, action) {
|
|
25339
|
+
try {
|
|
25340
|
+
const result = await shutdownCodebaseIndexServer(
|
|
25341
|
+
projectRoot,
|
|
25342
|
+
indexDir,
|
|
25343
|
+
`tui-request:${action}`
|
|
25344
|
+
);
|
|
25345
|
+
if (!result.stopped) {
|
|
25346
|
+
if (action === "restart" && result.reason === "not-running") {
|
|
25347
|
+
return await restartCodebaseIndexServer(projectRoot, indexDir);
|
|
25348
|
+
}
|
|
25349
|
+
return {
|
|
25350
|
+
serviceId: "codebase-index",
|
|
25351
|
+
action,
|
|
25352
|
+
success: false,
|
|
25353
|
+
message: `Codebase index server shutdown failed: ${result.reason ?? "unknown"}`
|
|
25354
|
+
};
|
|
25355
|
+
}
|
|
25356
|
+
if (action === "restart") {
|
|
25357
|
+
return await restartCodebaseIndexServer(projectRoot, indexDir);
|
|
25358
|
+
}
|
|
25359
|
+
return {
|
|
25360
|
+
serviceId: "codebase-index",
|
|
25361
|
+
action,
|
|
25362
|
+
success: true,
|
|
25363
|
+
message: "Codebase index server shutdown requested"
|
|
25364
|
+
};
|
|
25365
|
+
} catch (error) {
|
|
25366
|
+
return {
|
|
25367
|
+
serviceId: "codebase-index",
|
|
25368
|
+
action,
|
|
25369
|
+
success: false,
|
|
25370
|
+
message: toErrorMessage(error)
|
|
25371
|
+
};
|
|
25372
|
+
}
|
|
25373
|
+
}
|
|
25374
|
+
async function restartCodebaseIndexServer(projectRoot, indexDir) {
|
|
25375
|
+
await waitForShutdown(async () => {
|
|
25376
|
+
try {
|
|
25377
|
+
await checkCodebaseIndexServerHealth(projectRoot, indexDir, {
|
|
25378
|
+
timeoutMs: 1e3
|
|
25379
|
+
});
|
|
25380
|
+
return true;
|
|
25381
|
+
} catch {
|
|
25382
|
+
return false;
|
|
25383
|
+
}
|
|
25384
|
+
});
|
|
25385
|
+
try {
|
|
25386
|
+
await ensureCodebaseIndexServer({ projectRoot, indexDir });
|
|
25387
|
+
const health2 = await checkCodebaseIndexServerHealth(projectRoot, indexDir, {
|
|
25388
|
+
timeoutMs: 1e4
|
|
25389
|
+
});
|
|
25390
|
+
if (health2.status !== "healthy") {
|
|
25391
|
+
return {
|
|
25392
|
+
serviceId: "codebase-index",
|
|
25393
|
+
action: "restart",
|
|
25394
|
+
success: false,
|
|
25395
|
+
message: `Codebase index server restart verification failed: ${health2.status}`
|
|
25396
|
+
};
|
|
25397
|
+
}
|
|
25398
|
+
assertDaemonRuntimeVersion(health2.server?.runtimeVersion);
|
|
25399
|
+
return {
|
|
25400
|
+
serviceId: "codebase-index",
|
|
25401
|
+
action: "restart",
|
|
25402
|
+
success: true,
|
|
25403
|
+
message: "Codebase index server restarted successfully"
|
|
25404
|
+
};
|
|
25405
|
+
} catch (error) {
|
|
25406
|
+
return {
|
|
25407
|
+
serviceId: "codebase-index",
|
|
25408
|
+
action: "restart",
|
|
25409
|
+
success: false,
|
|
25410
|
+
message: `Codebase index server restarted but verification failed: ${toErrorMessage(error)}`
|
|
25411
|
+
};
|
|
25412
|
+
}
|
|
25413
|
+
}
|
|
25414
|
+
async function killMailboxServer(projectRoot, action) {
|
|
25415
|
+
if (!isMailboxProjectServerAvailable()) {
|
|
25416
|
+
return {
|
|
25417
|
+
serviceId: "mailbox",
|
|
25418
|
+
action,
|
|
25419
|
+
success: false,
|
|
25420
|
+
message: "Mailbox project server is unavailable in this runtime"
|
|
25421
|
+
};
|
|
25422
|
+
}
|
|
25423
|
+
const connection = new MailboxProjectServerConnection(
|
|
25424
|
+
resolveWstackPaths2({ projectRoot }).projectDir
|
|
25425
|
+
);
|
|
25426
|
+
try {
|
|
25427
|
+
const result = await connection.shutdown(`TUI request: ${action}`);
|
|
25428
|
+
if (!result.stopped) {
|
|
25429
|
+
if (action === "restart" && result.reason === "offline") {
|
|
25430
|
+
return await restartMailboxServer(projectRoot);
|
|
25431
|
+
}
|
|
25432
|
+
return {
|
|
25433
|
+
serviceId: "mailbox",
|
|
25434
|
+
action,
|
|
25435
|
+
success: false,
|
|
25436
|
+
message: `Mailbox IPC server shutdown failed: ${result.reason ?? "unknown"}`
|
|
25437
|
+
};
|
|
25438
|
+
}
|
|
25439
|
+
if (action === "restart") {
|
|
25440
|
+
return await restartMailboxServer(projectRoot);
|
|
25441
|
+
}
|
|
25442
|
+
return {
|
|
25443
|
+
serviceId: "mailbox",
|
|
25444
|
+
action,
|
|
25445
|
+
success: true,
|
|
25446
|
+
message: "Mailbox IPC server shutdown requested"
|
|
25447
|
+
};
|
|
25448
|
+
} catch (error) {
|
|
25449
|
+
return {
|
|
25450
|
+
serviceId: "mailbox",
|
|
25451
|
+
action,
|
|
25452
|
+
success: false,
|
|
25453
|
+
message: toErrorMessage(error)
|
|
25454
|
+
};
|
|
25455
|
+
} finally {
|
|
25456
|
+
connection.close();
|
|
25457
|
+
}
|
|
25458
|
+
}
|
|
25459
|
+
async function restartMailboxServer(projectRoot) {
|
|
25460
|
+
await waitForShutdown(async () => {
|
|
25461
|
+
const probe = new MailboxProjectServerConnection(
|
|
25462
|
+
resolveWstackPaths2({ projectRoot }).projectDir
|
|
25463
|
+
);
|
|
25464
|
+
try {
|
|
25465
|
+
return await probe.probeStatus() !== null;
|
|
25466
|
+
} finally {
|
|
25467
|
+
probe.close();
|
|
25468
|
+
}
|
|
25469
|
+
});
|
|
25470
|
+
const verifyConn = new MailboxProjectServerConnection(
|
|
25471
|
+
resolveWstackPaths2({ projectRoot }).projectDir
|
|
25472
|
+
);
|
|
25473
|
+
try {
|
|
25474
|
+
const health2 = await verifyConn.call("ping", {}, { timeoutMs: 1e4 });
|
|
25475
|
+
assertDaemonRuntimeVersion(health2.runtimeVersion);
|
|
25476
|
+
return {
|
|
25477
|
+
serviceId: "mailbox",
|
|
25478
|
+
action: "restart",
|
|
25479
|
+
success: true,
|
|
25480
|
+
message: "Mailbox IPC server restarted successfully"
|
|
25481
|
+
};
|
|
25482
|
+
} catch (error) {
|
|
25483
|
+
return {
|
|
25484
|
+
serviceId: "mailbox",
|
|
25485
|
+
action: "restart",
|
|
25486
|
+
success: false,
|
|
25487
|
+
message: `Mailbox IPC server restarted but verification failed: ${toErrorMessage(error)}`
|
|
25488
|
+
};
|
|
25489
|
+
} finally {
|
|
25490
|
+
verifyConn.close();
|
|
25491
|
+
}
|
|
25492
|
+
}
|
|
25493
|
+
var RESTARTABLE_SERVICES;
|
|
25494
|
+
var init_connection_actions = __esm({
|
|
25495
|
+
"src/connection-actions.ts"() {
|
|
25496
|
+
"use strict";
|
|
25497
|
+
RESTARTABLE_SERVICES = [
|
|
25498
|
+
"session-catalog",
|
|
25499
|
+
"chronicle",
|
|
25500
|
+
"codebase-index",
|
|
25501
|
+
"sage",
|
|
25502
|
+
"kanban",
|
|
25503
|
+
"mailbox"
|
|
25504
|
+
];
|
|
25505
|
+
}
|
|
25506
|
+
});
|
|
25507
|
+
|
|
25508
|
+
// src/connections-health.ts
|
|
25509
|
+
var connections_health_exports = {};
|
|
25510
|
+
__export(connections_health_exports, {
|
|
25511
|
+
collectConnectionsHealth: () => collectConnectionsHealth
|
|
25512
|
+
});
|
|
25513
|
+
import { createChronicleProjectAccess as createChronicleProjectAccess2 } from "@wrongstack/core/chronicle";
|
|
25514
|
+
import {
|
|
25515
|
+
isMailboxProjectServerAvailable as isMailboxProjectServerAvailable2,
|
|
25516
|
+
MailboxProjectServerConnection as MailboxProjectServerConnection2
|
|
25517
|
+
} from "@wrongstack/core/coordination";
|
|
25518
|
+
import { SessionCatalogProjectClient as SessionCatalogProjectClient2 } from "@wrongstack/core/session-catalog";
|
|
25519
|
+
import { resolveWstackPaths as resolveWstackPaths3, withDaemonVersion } from "@wrongstack/core/utils";
|
|
25520
|
+
import { getKanbanServerConnection as getKanbanServerConnection2 } from "@wrongstack/kanban";
|
|
25521
|
+
import { readGovernanceDaemonOperatorStatus } from "@wrongstack/runtime/governance-bootstrap";
|
|
25522
|
+
import { isSageProjectServerAvailable as isSageProjectServerAvailable2, SageProjectServerConnection as SageProjectServerConnection2 } from "@wrongstack/sage";
|
|
25523
|
+
import {
|
|
25524
|
+
checkCodebaseIndexServerHealth as checkCodebaseIndexServerHealth2,
|
|
25525
|
+
getIndexState,
|
|
25526
|
+
resolveProjectIndexDaemonAvailability
|
|
25527
|
+
} from "@wrongstack/tools";
|
|
25528
|
+
async function collectConnectionsHealth(projectRoot) {
|
|
25529
|
+
const services = await Promise.all([
|
|
25530
|
+
sessionCatalogHealth(projectRoot),
|
|
25531
|
+
chronicleHealth(projectRoot),
|
|
25532
|
+
codebaseIndexHealth(projectRoot),
|
|
25533
|
+
sageHealth(projectRoot),
|
|
25534
|
+
kanbanHealth(projectRoot),
|
|
25535
|
+
mailboxHealth(projectRoot),
|
|
25536
|
+
governanceHealth(projectRoot)
|
|
25537
|
+
]);
|
|
25538
|
+
const required = services.filter((s2) => s2.required);
|
|
25539
|
+
const overall = required.some((s2) => s2.status === "error") ? "error" : services.some((s2) => s2.versionMismatch) || required.some((s2) => s2.status !== "healthy") ? "degraded" : "healthy";
|
|
25540
|
+
return { checkedAt: Date.now(), overall, services };
|
|
25541
|
+
}
|
|
25542
|
+
async function sessionCatalogHealth(projectRoot) {
|
|
25543
|
+
const startedAt = Date.now();
|
|
25544
|
+
try {
|
|
25545
|
+
const paths = resolveWstackPaths3({ projectRoot });
|
|
25546
|
+
const client = new SessionCatalogProjectClient2({
|
|
25547
|
+
projectDir: paths.projectDir,
|
|
25548
|
+
projectRoot
|
|
25549
|
+
});
|
|
25550
|
+
try {
|
|
25551
|
+
const health2 = await client.callExisting("ping", {}, { timeoutMs: 3e3 });
|
|
25552
|
+
return withDaemonVersion(
|
|
25553
|
+
{
|
|
25554
|
+
id: "session-catalog",
|
|
25555
|
+
label: "Session Catalog",
|
|
25556
|
+
status: health2.damagedRows > 0 ? "degraded" : "healthy",
|
|
25557
|
+
required: true,
|
|
25558
|
+
mode: "project-daemon",
|
|
25559
|
+
detail: health2.damagedRows > 0 ? `${health2.damagedRows} damaged catalog row(s); rebuild is required.` : `${health2.catalogRows} catalog session(s), ${health2.liveLeases} live lease(s), ${health2.reservations} reservation(s).`,
|
|
25560
|
+
ownerPid: health2.pid,
|
|
25561
|
+
endpoint: health2.endpoint,
|
|
25562
|
+
storage: health2.databasePath,
|
|
25563
|
+
uptimeMs: health2.uptimeMs,
|
|
25564
|
+
latencyMs: Date.now() - startedAt,
|
|
25565
|
+
clients: health2.clients,
|
|
25566
|
+
activeRequests: health2.activeRequests,
|
|
25567
|
+
queuedWork: health2.reservations + health2.maintenanceLeases
|
|
25568
|
+
},
|
|
25569
|
+
health2?.runtimeVersion
|
|
25570
|
+
);
|
|
25571
|
+
} finally {
|
|
25572
|
+
await client.close().catch(() => void 0);
|
|
25573
|
+
}
|
|
25574
|
+
} catch (error) {
|
|
25575
|
+
const offline = isOfflineConnectionError(error);
|
|
25576
|
+
return {
|
|
25577
|
+
id: "session-catalog",
|
|
25578
|
+
label: "Session Catalog",
|
|
25579
|
+
status: offline ? "offline" : "error",
|
|
25580
|
+
required: !offline,
|
|
25581
|
+
mode: offline ? "on-demand project-daemon" : "project-daemon",
|
|
25582
|
+
detail: offline ? "Not running for this project; it starts on demand when a session is used." : "Project-scoped session ownership and catalog are unavailable.",
|
|
25583
|
+
latencyMs: Date.now() - startedAt,
|
|
25584
|
+
lastError: error instanceof Error ? error.message : String(error)
|
|
25585
|
+
};
|
|
25586
|
+
}
|
|
25587
|
+
}
|
|
25588
|
+
async function chronicleHealth(projectRoot) {
|
|
25589
|
+
const startedAt = Date.now();
|
|
25590
|
+
let access;
|
|
25591
|
+
try {
|
|
25592
|
+
access = createChronicleProjectAccess2({ projectRoot });
|
|
25593
|
+
const health2 = await access.call("ping", {}, { timeoutMs: 5e3 });
|
|
25594
|
+
const quarantined = health2.quarantinedFamilies ?? [];
|
|
25595
|
+
return withDaemonVersion(
|
|
25596
|
+
{
|
|
25597
|
+
id: "chronicle",
|
|
25598
|
+
label: "Chronicle telemetry",
|
|
25599
|
+
status: quarantined.length > 0 ? "degraded" : access.mode === "server" ? "healthy" : "degraded",
|
|
25600
|
+
required: true,
|
|
25601
|
+
mode: access.mode,
|
|
25602
|
+
detail: quarantined.length > 0 ? `Serving, but ${quarantined.length} day(s) were quarantined for a broken chain: ${quarantined.map((family) => family.day).join(", ")}.` : access.mode === "server" ? "One project owner collects, processes, stores, and serves telemetry." : "Inline fallback is active; ownership is not shared across clients.",
|
|
25603
|
+
ownerPid: health2.pid,
|
|
25604
|
+
endpoint: health2.endpoint,
|
|
25605
|
+
storage: health2.chronicleDirectory,
|
|
25606
|
+
uptimeMs: health2.uptimeMs,
|
|
25607
|
+
latencyMs: Date.now() - startedAt,
|
|
25608
|
+
clients: health2.clients,
|
|
25609
|
+
activeRequests: health2.activeRequests,
|
|
25610
|
+
queuedWork: health2.journal.pendingEvents,
|
|
25611
|
+
watcher: { active: health2.watcher.active, watchedFiles: health2.watcher.watchedFiles },
|
|
25612
|
+
...quarantined[0] ? { lastError: quarantined[0].reason } : health2.watcher.lastError ? { lastError: health2.watcher.lastError } : {}
|
|
25613
|
+
},
|
|
25614
|
+
health2?.runtimeVersion
|
|
25615
|
+
);
|
|
25616
|
+
} catch (error) {
|
|
25617
|
+
return failureService(
|
|
25618
|
+
"chronicle",
|
|
25619
|
+
"Chronicle telemetry",
|
|
25620
|
+
true,
|
|
25621
|
+
access?.mode ?? "unavailable",
|
|
25622
|
+
error,
|
|
25623
|
+
Date.now() - startedAt
|
|
25624
|
+
);
|
|
25625
|
+
} finally {
|
|
25626
|
+
await access?.close();
|
|
25627
|
+
}
|
|
25628
|
+
}
|
|
25629
|
+
async function codebaseIndexHealth(projectRoot) {
|
|
25630
|
+
const startedAt = Date.now();
|
|
25631
|
+
const availability = resolveProjectIndexDaemonAvailability(projectRoot);
|
|
25632
|
+
if (availability.kind === "endpoint-invalid") {
|
|
25633
|
+
return {
|
|
25634
|
+
id: "codebase-index",
|
|
25635
|
+
label: "Codebase index",
|
|
25636
|
+
status: "unavailable",
|
|
25637
|
+
required: false,
|
|
25638
|
+
mode: "endpoint-invalid",
|
|
25639
|
+
detail: `Socket path is ${availability.byteLength} bytes \u2014 over this platform's ${availability.maxBytes}-byte sun_path limit. Queries fall back to a process-local index. Set a shorter TMPDIR to restore the shared daemon.`,
|
|
25640
|
+
endpoint: availability.endpoint,
|
|
25641
|
+
latencyMs: Date.now() - startedAt
|
|
25642
|
+
};
|
|
25643
|
+
}
|
|
25644
|
+
try {
|
|
25645
|
+
const health2 = await checkCodebaseIndexServerHealth2(projectRoot, void 0, {
|
|
25646
|
+
timeoutMs: 2e3
|
|
25647
|
+
});
|
|
25648
|
+
const connection = getIndexState().server;
|
|
25649
|
+
return withDaemonVersion(
|
|
25650
|
+
{
|
|
25651
|
+
id: "codebase-index",
|
|
25652
|
+
label: "Codebase index",
|
|
25653
|
+
status: health2.status === "unresponsive" ? "error" : health2.status,
|
|
25654
|
+
required: false,
|
|
25655
|
+
mode: "project-server",
|
|
25656
|
+
detail: health2.server?.activity.indexing ? `Indexing ${health2.server.activity.currentFile}/${health2.server.activity.totalFiles}.` : "Shared symbol index is ready for project queries.",
|
|
25657
|
+
ownerPid: connection.pid,
|
|
25658
|
+
endpoint: connection.endpoint,
|
|
25659
|
+
storage: connection.indexDir ?? resolveWstackPaths3({ projectRoot }).projectCodebaseIndex,
|
|
25660
|
+
uptimeMs: health2.server?.uptimeMs,
|
|
25661
|
+
latencyMs: health2.latencyMs ?? Date.now() - startedAt,
|
|
25662
|
+
clients: health2.server?.clients,
|
|
25663
|
+
activeRequests: health2.server?.activeRequests,
|
|
25664
|
+
queuedWork: health2.server?.queuedWrites,
|
|
25665
|
+
watcher: health2.server ? { active: health2.server.watchingExternal, watchedFiles: health2.server.watchingClients } : void 0
|
|
25666
|
+
},
|
|
25667
|
+
health2.server?.runtimeVersion
|
|
25668
|
+
);
|
|
25669
|
+
} catch (error) {
|
|
25670
|
+
if (isOfflineConnectionError(error)) {
|
|
25671
|
+
return {
|
|
25672
|
+
...failureService(
|
|
25673
|
+
"codebase-index",
|
|
25674
|
+
"Codebase index",
|
|
25675
|
+
false,
|
|
25676
|
+
"on-demand project-server",
|
|
25677
|
+
error,
|
|
25678
|
+
Date.now() - startedAt
|
|
25679
|
+
),
|
|
25680
|
+
status: "offline",
|
|
25681
|
+
detail: "Not running for this project; it starts on demand when indexing is used."
|
|
25682
|
+
};
|
|
25683
|
+
}
|
|
25684
|
+
return failureService(
|
|
25685
|
+
"codebase-index",
|
|
25686
|
+
"Codebase index",
|
|
25687
|
+
false,
|
|
25688
|
+
"project-server",
|
|
25689
|
+
error,
|
|
25690
|
+
Date.now() - startedAt
|
|
25691
|
+
);
|
|
25692
|
+
}
|
|
25693
|
+
}
|
|
25694
|
+
async function sageHealth(projectRoot) {
|
|
25695
|
+
const startedAt = Date.now();
|
|
25696
|
+
if (!isSageProjectServerAvailable2()) {
|
|
25697
|
+
return {
|
|
25698
|
+
id: "sage",
|
|
25699
|
+
label: "SAGE memory",
|
|
25700
|
+
status: "unavailable",
|
|
25701
|
+
required: false,
|
|
25702
|
+
mode: "unavailable",
|
|
25703
|
+
detail: "The packaged SAGE project server is unavailable in this runtime."
|
|
25704
|
+
};
|
|
25705
|
+
}
|
|
25706
|
+
const connection = new SageProjectServerConnection2(projectRoot);
|
|
25707
|
+
try {
|
|
25708
|
+
const status = await connection.status();
|
|
25709
|
+
if (!status) {
|
|
25710
|
+
return {
|
|
25711
|
+
id: "sage",
|
|
25712
|
+
label: "SAGE memory",
|
|
25713
|
+
status: "offline",
|
|
25714
|
+
required: false,
|
|
25715
|
+
mode: "on-demand project-server",
|
|
25716
|
+
detail: "Not running for this project; it starts on demand when memory is used.",
|
|
25717
|
+
endpoint: connection.getState().endpoint,
|
|
25718
|
+
latencyMs: Date.now() - startedAt
|
|
25719
|
+
};
|
|
25720
|
+
}
|
|
25721
|
+
const healthStatus = status.health.status === "ready" ? "healthy" : status.health.status === "degraded" ? "degraded" : "error";
|
|
25722
|
+
return withDaemonVersion(
|
|
25723
|
+
{
|
|
25724
|
+
id: "sage",
|
|
25725
|
+
label: "SAGE memory",
|
|
25726
|
+
status: healthStatus,
|
|
25727
|
+
required: false,
|
|
25728
|
+
mode: "project-server",
|
|
25729
|
+
detail: `Persistent project memory backend: ${status.health.backend}.`,
|
|
25730
|
+
ownerPid: status.pid,
|
|
25731
|
+
endpoint: status.endpoint,
|
|
25732
|
+
storage: status.storageRoot,
|
|
25733
|
+
latencyMs: Date.now() - startedAt,
|
|
25734
|
+
clients: status.clients,
|
|
25735
|
+
activeRequests: status.pendingRequests
|
|
25736
|
+
},
|
|
25737
|
+
status?.runtimeVersion
|
|
25738
|
+
);
|
|
25739
|
+
} catch (error) {
|
|
25740
|
+
return failureService(
|
|
25741
|
+
"sage",
|
|
25742
|
+
"SAGE memory",
|
|
25743
|
+
false,
|
|
25744
|
+
"project-server",
|
|
25745
|
+
error,
|
|
25746
|
+
Date.now() - startedAt
|
|
25747
|
+
);
|
|
25748
|
+
} finally {
|
|
25749
|
+
connection.close();
|
|
25750
|
+
}
|
|
25751
|
+
}
|
|
25752
|
+
async function kanbanHealth(projectRoot) {
|
|
25753
|
+
const startedAt = Date.now();
|
|
25754
|
+
if (process.env["WRONGSTACK_KANBAN_SERVER"] === "0") {
|
|
25755
|
+
return {
|
|
25756
|
+
id: "kanban",
|
|
25757
|
+
label: "Kanban IPC",
|
|
25758
|
+
status: "unavailable",
|
|
25759
|
+
required: false,
|
|
25760
|
+
mode: "disabled",
|
|
25761
|
+
detail: "Kanban IPC daemon is disabled via WRONGSTACK_KANBAN_SERVER=0."
|
|
25762
|
+
};
|
|
25763
|
+
}
|
|
25764
|
+
let connection;
|
|
25765
|
+
try {
|
|
25766
|
+
connection = await getKanbanServerConnection2(projectRoot);
|
|
25767
|
+
} catch (error) {
|
|
25768
|
+
return failureService(
|
|
25769
|
+
"kanban",
|
|
25770
|
+
"Kanban IPC",
|
|
25771
|
+
false,
|
|
25772
|
+
"project-server",
|
|
25773
|
+
error,
|
|
25774
|
+
Date.now() - startedAt
|
|
25775
|
+
);
|
|
25776
|
+
}
|
|
25777
|
+
if (!connection) {
|
|
25778
|
+
return {
|
|
25779
|
+
id: "kanban",
|
|
25780
|
+
label: "Kanban IPC",
|
|
25781
|
+
status: "unavailable",
|
|
25782
|
+
required: false,
|
|
25783
|
+
mode: "disabled",
|
|
25784
|
+
detail: "Kanban IPC daemon is disabled in this runtime."
|
|
25785
|
+
};
|
|
25786
|
+
}
|
|
25787
|
+
try {
|
|
25788
|
+
const status = await connection.request("ping", {}, { timeoutMs: 5e3 });
|
|
25789
|
+
return withDaemonVersion(
|
|
25790
|
+
{
|
|
25791
|
+
id: "kanban",
|
|
25792
|
+
label: "Kanban IPC",
|
|
25793
|
+
status: "healthy",
|
|
25794
|
+
required: true,
|
|
25795
|
+
mode: "project-server",
|
|
25796
|
+
detail: `Single shared project-server owns kanban state (v${status.protocolVersion}).`,
|
|
25797
|
+
ownerPid: status.pid,
|
|
25798
|
+
endpoint: status.endpoint,
|
|
25799
|
+
storage: status.databasePath,
|
|
25800
|
+
latencyMs: Date.now() - startedAt,
|
|
25801
|
+
clients: status.clients,
|
|
25802
|
+
activeRequests: status.pendingRequests,
|
|
25803
|
+
uptimeMs: Date.now() - new Date(status.startedAt).getTime()
|
|
25804
|
+
},
|
|
25805
|
+
status?.runtimeVersion
|
|
25806
|
+
);
|
|
25807
|
+
} catch (error) {
|
|
25808
|
+
return failureService(
|
|
25809
|
+
"kanban",
|
|
25810
|
+
"Kanban IPC",
|
|
25811
|
+
true,
|
|
25812
|
+
"project-server",
|
|
25813
|
+
error,
|
|
25814
|
+
Date.now() - startedAt
|
|
25815
|
+
);
|
|
25816
|
+
}
|
|
25817
|
+
}
|
|
25818
|
+
async function mailboxHealth(projectRoot) {
|
|
25819
|
+
const startedAt = Date.now();
|
|
25820
|
+
if (!isMailboxProjectServerAvailable2()) {
|
|
25821
|
+
return {
|
|
25822
|
+
id: "mailbox",
|
|
25823
|
+
label: "Mailbox IPC",
|
|
25824
|
+
status: "unavailable",
|
|
25825
|
+
required: false,
|
|
25826
|
+
mode: "unavailable",
|
|
25827
|
+
detail: "The packaged mailbox project server is unavailable in this runtime."
|
|
25828
|
+
};
|
|
25829
|
+
}
|
|
25830
|
+
const connection = new MailboxProjectServerConnection2(
|
|
25831
|
+
resolveWstackPaths3({ projectRoot }).projectDir
|
|
25832
|
+
);
|
|
25833
|
+
try {
|
|
25834
|
+
const status = await connection.probeStatus();
|
|
25835
|
+
if (!status) {
|
|
25836
|
+
return {
|
|
25837
|
+
id: "mailbox",
|
|
25838
|
+
label: "Mailbox IPC",
|
|
25839
|
+
status: "offline",
|
|
25840
|
+
required: false,
|
|
25841
|
+
mode: "on-demand project-server",
|
|
25842
|
+
detail: "Not running for this project; it starts on demand when mailbox is used.",
|
|
25843
|
+
endpoint: connection.getState().endpoint,
|
|
25844
|
+
latencyMs: Date.now() - startedAt
|
|
25845
|
+
};
|
|
25846
|
+
}
|
|
25847
|
+
return withDaemonVersion(
|
|
25848
|
+
{
|
|
25849
|
+
id: "mailbox",
|
|
25850
|
+
label: "Mailbox IPC",
|
|
25851
|
+
status: "healthy",
|
|
25852
|
+
required: true,
|
|
25853
|
+
mode: "project-server",
|
|
25854
|
+
detail: `Single shared project-server owns inter-agent mailbox state (v${status.protocolVersion}).`,
|
|
25855
|
+
ownerPid: status.pid,
|
|
25856
|
+
endpoint: status.endpoint,
|
|
25857
|
+
storage: status.databasePath,
|
|
25858
|
+
latencyMs: Date.now() - startedAt,
|
|
25859
|
+
clients: status.clients,
|
|
25860
|
+
activeRequests: status.pendingRequests,
|
|
25861
|
+
uptimeMs: Date.now() - new Date(status.startedAt).getTime()
|
|
25862
|
+
},
|
|
25863
|
+
status?.runtimeVersion
|
|
25864
|
+
);
|
|
25865
|
+
} catch (error) {
|
|
25866
|
+
return failureService(
|
|
25867
|
+
"mailbox",
|
|
25868
|
+
"Mailbox IPC",
|
|
25869
|
+
true,
|
|
25870
|
+
"project-server",
|
|
25871
|
+
error,
|
|
25872
|
+
Date.now() - startedAt
|
|
25873
|
+
);
|
|
25874
|
+
} finally {
|
|
25875
|
+
connection.close();
|
|
25876
|
+
}
|
|
25877
|
+
}
|
|
25878
|
+
async function governanceHealth(projectRoot) {
|
|
25879
|
+
const startedAt = Date.now();
|
|
25880
|
+
const result = await readGovernanceDaemonOperatorStatus(projectRoot);
|
|
25881
|
+
if (!result.available) {
|
|
25882
|
+
const missing = result.code === "broker_missing";
|
|
25883
|
+
return {
|
|
25884
|
+
id: "governance",
|
|
25885
|
+
label: "Governance control plane",
|
|
25886
|
+
status: missing ? "offline" : "error",
|
|
25887
|
+
required: false,
|
|
25888
|
+
mode: missing ? "compatibility-default-off" : "project-daemon",
|
|
25889
|
+
detail: missing ? "Not active for this project. Existing agent and model execution remains unchanged." : `Read-only governance status is unavailable: ${result.message}`,
|
|
25890
|
+
latencyMs: Date.now() - startedAt,
|
|
25891
|
+
control: "none",
|
|
25892
|
+
...missing ? {} : { lastError: result.message }
|
|
25893
|
+
};
|
|
25894
|
+
}
|
|
25895
|
+
const { status } = result;
|
|
25896
|
+
return {
|
|
25897
|
+
id: "governance",
|
|
25262
25898
|
label: "Governance control plane",
|
|
25263
25899
|
status: status.signal.level === "healthy" ? "healthy" : "degraded",
|
|
25264
25900
|
required: false,
|
|
@@ -34210,6 +34846,23 @@ function parseHexColor(hex) {
|
|
|
34210
34846
|
const n = Number.parseInt(raw, 16);
|
|
34211
34847
|
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
34212
34848
|
}
|
|
34849
|
+
function relativeLuminance(hex) {
|
|
34850
|
+
const rgb = parseHexColor(hex);
|
|
34851
|
+
if (!rgb) return null;
|
|
34852
|
+
const [r, g, b] = rgb.map((channel) => {
|
|
34853
|
+
const s2 = channel / 255;
|
|
34854
|
+
return s2 <= 0.03928 ? s2 / 12.92 : ((s2 + 0.055) / 1.055) ** 2.4;
|
|
34855
|
+
});
|
|
34856
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
34857
|
+
}
|
|
34858
|
+
function contrastRatio(foreground, background) {
|
|
34859
|
+
const a = relativeLuminance(foreground);
|
|
34860
|
+
const b = relativeLuminance(background);
|
|
34861
|
+
if (a === null || b === null) return 1;
|
|
34862
|
+
const lighter = Math.max(a, b);
|
|
34863
|
+
const darker = Math.min(a, b);
|
|
34864
|
+
return Math.round((lighter + 0.05) / (darker + 0.05) * 10) / 10;
|
|
34865
|
+
}
|
|
34213
34866
|
function detectSupportsBackground(env3 = process.env, isTTY = process.stdout.isTTY ?? false) {
|
|
34214
34867
|
if (!isTTY) return false;
|
|
34215
34868
|
if (typeof env3["NO_COLOR"] === "string" && env3["NO_COLOR"] !== "") return false;
|
|
@@ -35647,296 +36300,26 @@ var nightfoxPresets = {
|
|
|
35647
36300
|
};
|
|
35648
36301
|
|
|
35649
36302
|
// src/theme-presets/options.ts
|
|
35650
|
-
|
|
35651
|
-
|
|
35652
|
-
|
|
35653
|
-
|
|
35654
|
-
|
|
35655
|
-
|
|
35656
|
-
|
|
35657
|
-
|
|
35658
|
-
|
|
35659
|
-
|
|
35660
|
-
|
|
35661
|
-
|
|
35662
|
-
|
|
35663
|
-
|
|
35664
|
-
|
|
35665
|
-
|
|
35666
|
-
|
|
35667
|
-
|
|
35668
|
-
|
|
35669
|
-
|
|
35670
|
-
name: "Gruvbox Dark",
|
|
35671
|
-
description: "Warm earthy retro palette \u2014 orange, olive and muted aqua"
|
|
35672
|
-
},
|
|
35673
|
-
{
|
|
35674
|
-
id: "solarized-dark",
|
|
35675
|
-
name: "Solarized Dark",
|
|
35676
|
-
description: "Precision contrast, base16 classic with teal undertones"
|
|
35677
|
-
},
|
|
35678
|
-
{
|
|
35679
|
-
id: "one-dark",
|
|
35680
|
-
name: "One Dark",
|
|
35681
|
-
description: "Atom's iconic dark palette \u2014 blue-led with warm accents"
|
|
35682
|
-
},
|
|
35683
|
-
{
|
|
35684
|
-
id: "monokai",
|
|
35685
|
-
name: "Monokai",
|
|
35686
|
-
description: "Sublime Text classic \u2014 vivid magenta, cyan and lime"
|
|
35687
|
-
},
|
|
35688
|
-
{
|
|
35689
|
-
id: "rose-pine",
|
|
35690
|
-
name: "Ros\xE9 Pine",
|
|
35691
|
-
description: "Aesthetic pine & foam \u2014 soft pastel evening tones"
|
|
35692
|
-
},
|
|
35693
|
-
{ id: "kanagawa", name: "Kanagawa", description: "Hokusai-inspired waves \u2014 sumi ink on washi" },
|
|
35694
|
-
{
|
|
35695
|
-
id: "ayu-dark",
|
|
35696
|
-
name: "Ayu Dark",
|
|
35697
|
-
description: "Simple, pleasant dark \u2014 warm orange + cool blue mix"
|
|
35698
|
-
},
|
|
35699
|
-
{
|
|
35700
|
-
id: "everforest",
|
|
35701
|
-
name: "Everforest",
|
|
35702
|
-
description: "Green-based comfort palette \u2014 forest greens and warm tans"
|
|
35703
|
-
},
|
|
35704
|
-
{
|
|
35705
|
-
id: "night-owl",
|
|
35706
|
-
name: "Night Owl",
|
|
35707
|
-
description: "Sarah Drasner's night theme \u2014 deep navy with bold accents"
|
|
35708
|
-
},
|
|
35709
|
-
{
|
|
35710
|
-
id: "synthwave",
|
|
35711
|
-
name: "Synthwave '84",
|
|
35712
|
-
description: "Hot pink + neon cyan on deep purple \u2014 80s retro glow"
|
|
35713
|
-
},
|
|
35714
|
-
{
|
|
35715
|
-
id: "github-dark",
|
|
35716
|
-
name: "GitHub Dark",
|
|
35717
|
-
description: "GitHub's default dark \u2014 crisp blue on near-black"
|
|
35718
|
-
},
|
|
35719
|
-
{
|
|
35720
|
-
id: "material-ocean",
|
|
35721
|
-
name: "Material Ocean",
|
|
35722
|
-
description: "Deepest Material variant \u2014 ink blue with pastel accents"
|
|
35723
|
-
},
|
|
35724
|
-
{ id: "nightfox", name: "Nightfox", description: "Balanced slate blue with muted sage and rose" },
|
|
35725
|
-
{
|
|
35726
|
-
id: "oxocarbon",
|
|
35727
|
-
name: "Oxocarbon",
|
|
35728
|
-
description: "IBM Carbon-derived \u2014 neutral greys, electric blue & pink"
|
|
35729
|
-
},
|
|
35730
|
-
{
|
|
35731
|
-
id: "catppuccin-macchiato",
|
|
35732
|
-
name: "Catppuccin Macchiato",
|
|
35733
|
-
description: "Warmer, one shade lighter than Mocha"
|
|
35734
|
-
},
|
|
35735
|
-
{
|
|
35736
|
-
id: "catppuccin-frappe",
|
|
35737
|
-
name: "Catppuccin Frapp\xE9",
|
|
35738
|
-
description: "The lightest Catppuccin dark \u2014 gentle midday contrast"
|
|
35739
|
-
},
|
|
35740
|
-
{
|
|
35741
|
-
id: "gruvbox-material",
|
|
35742
|
-
name: "Gruvbox Material",
|
|
35743
|
-
description: "Softened Gruvbox \u2014 same warmth, lower eye strain"
|
|
35744
|
-
},
|
|
35745
|
-
{
|
|
35746
|
-
id: "tokyo-night-storm",
|
|
35747
|
-
name: "Tokyo Night Storm",
|
|
35748
|
-
description: "Tokyo Night on a lifted blue-grey base"
|
|
35749
|
-
},
|
|
35750
|
-
{
|
|
35751
|
-
id: "rose-pine-moon",
|
|
35752
|
-
name: "Ros\xE9 Pine Moon",
|
|
35753
|
-
description: "Ros\xE9 Pine at dusk \u2014 deeper base, same soft accents"
|
|
35754
|
-
},
|
|
35755
|
-
{
|
|
35756
|
-
id: "zenburn",
|
|
35757
|
-
name: "Zenburn",
|
|
35758
|
-
description: "The classic low-contrast grey \u2014 desaturated and calm"
|
|
35759
|
-
},
|
|
35760
|
-
{
|
|
35761
|
-
id: "palenight",
|
|
35762
|
-
name: "Palenight",
|
|
35763
|
-
description: "Material Palenight \u2014 indigo base, candy accents"
|
|
35764
|
-
},
|
|
35765
|
-
{
|
|
35766
|
-
id: "horizon",
|
|
35767
|
-
name: "Horizon",
|
|
35768
|
-
description: "Warm coral and mint on charcoal \u2014 sunset gradient"
|
|
35769
|
-
},
|
|
35770
|
-
{
|
|
35771
|
-
id: "sonokai",
|
|
35772
|
-
name: "Sonokai",
|
|
35773
|
-
description: "Monokai Pro descendant \u2014 punchy on warm graphite"
|
|
35774
|
-
},
|
|
35775
|
-
{
|
|
35776
|
-
id: "edge-dark",
|
|
35777
|
-
name: "Edge Dark",
|
|
35778
|
-
description: "Clean, evenly-weighted palette on desaturated navy"
|
|
35779
|
-
},
|
|
35780
|
-
{
|
|
35781
|
-
id: "moonfly",
|
|
35782
|
-
name: "Moonfly",
|
|
35783
|
-
description: "Near-black base with high-chroma accents \u2014 maximum contrast"
|
|
35784
|
-
},
|
|
35785
|
-
{
|
|
35786
|
-
id: "melange",
|
|
35787
|
-
name: "Melange",
|
|
35788
|
-
description: "Warm sepia and clay \u2014 the least blue dark theme here"
|
|
35789
|
-
},
|
|
35790
|
-
{
|
|
35791
|
-
id: "poimandres",
|
|
35792
|
-
name: "Poimandres",
|
|
35793
|
-
description: "Teal-forward, low-saturation \u2014 mint on deep indigo"
|
|
35794
|
-
},
|
|
35795
|
-
{
|
|
35796
|
-
id: "vitesse-dark",
|
|
35797
|
-
name: "Vitesse Dark",
|
|
35798
|
-
description: "Anthony Fu's minimal palette \u2014 muted, print-like"
|
|
35799
|
-
},
|
|
35800
|
-
{
|
|
35801
|
-
id: "aura",
|
|
35802
|
-
name: "Aura Dark",
|
|
35803
|
-
description: "Vivid purple and spring green on near-black violet"
|
|
35804
|
-
},
|
|
35805
|
-
{
|
|
35806
|
-
id: "dark-plus",
|
|
35807
|
-
name: "VS Code Dark+",
|
|
35808
|
-
description: "Visual Studio Code's default \u2014 familiar blue/orange/teal"
|
|
35809
|
-
},
|
|
35810
|
-
{ id: "monochrome", name: "Monochrome", description: "Pure grayscale \u2014 no hue, only luminance" },
|
|
35811
|
-
{
|
|
35812
|
-
id: "matrix",
|
|
35813
|
-
name: "Matrix Green",
|
|
35814
|
-
description: "Phosphor green CRT terminal \u2014 digital rain aesthetic"
|
|
35815
|
-
},
|
|
35816
|
-
{
|
|
35817
|
-
id: "amber",
|
|
35818
|
-
name: "Amber CRT",
|
|
35819
|
-
description: "Warm phosphor CRT terminal \u2014 glowing vintage amber"
|
|
35820
|
-
},
|
|
35821
|
-
{
|
|
35822
|
-
id: "cyber-noir",
|
|
35823
|
-
name: "Cyber Noir",
|
|
35824
|
-
description: "Stark white and slate on jet black \u2014 minimalist high contrast"
|
|
35825
|
-
},
|
|
35826
|
-
{
|
|
35827
|
-
id: "cobalt-mono",
|
|
35828
|
-
name: "Cobalt Monochrome",
|
|
35829
|
-
description: "Luminous cyan on deep abyss blue \u2014 oceanic blueprint"
|
|
35830
|
-
},
|
|
35831
|
-
{
|
|
35832
|
-
id: "blood-moon",
|
|
35833
|
-
name: "Blood Moon",
|
|
35834
|
-
description: "Crimson & scarlet on obsidian \u2014 brooding dark mode"
|
|
35835
|
-
},
|
|
35836
|
-
{
|
|
35837
|
-
id: "cobalt2",
|
|
35838
|
-
name: "Cobalt2",
|
|
35839
|
-
description: "Wes Bos' signature theme \u2014 deep navy with golden yellow & cyan"
|
|
35840
|
-
},
|
|
35841
|
-
{
|
|
35842
|
-
id: "shades-of-purple",
|
|
35843
|
-
name: "Shades of Purple",
|
|
35844
|
-
description: "Ahmad Awais' bold purple palette with neon yellow & magenta"
|
|
35845
|
-
},
|
|
35846
|
-
{
|
|
35847
|
-
id: "flexoki-dark",
|
|
35848
|
-
name: "Flexoki Dark",
|
|
35849
|
-
description: "Steph Ango's inky warm paper palette \u2014 natural earthy accents"
|
|
35850
|
-
},
|
|
35851
|
-
{
|
|
35852
|
-
id: "laserwave",
|
|
35853
|
-
name: "LaserWave",
|
|
35854
|
-
description: "80s retrowave \u2014 neon flamingo and turquoise on violet"
|
|
35855
|
-
},
|
|
35856
|
-
{
|
|
35857
|
-
id: "andromeda",
|
|
35858
|
-
name: "Andromeda",
|
|
35859
|
-
description: "Deep interstellar dark with vibrant neon teal and pink"
|
|
35860
|
-
},
|
|
35861
|
-
{
|
|
35862
|
-
id: "github-dark-dimmed",
|
|
35863
|
-
name: "GitHub Dark Dimmed",
|
|
35864
|
-
description: "GitHub's softer slate dark theme \u2014 gentle blues and pastels"
|
|
35865
|
-
},
|
|
35866
|
-
{
|
|
35867
|
-
id: "snazzy",
|
|
35868
|
-
name: "Hyper Snazzy",
|
|
35869
|
-
description: "Sindre Sorhus' elegant saturated terminal palette"
|
|
35870
|
-
},
|
|
35871
|
-
{
|
|
35872
|
-
id: "tokyo-night-moon",
|
|
35873
|
-
name: "Tokyo Night Moon",
|
|
35874
|
-
description: "Tokyo Night on balanced deep indigo \u2014 vibrant accents"
|
|
35875
|
-
},
|
|
35876
|
-
{
|
|
35877
|
-
id: "gruvbox-dark-hard",
|
|
35878
|
-
name: "Gruvbox Dark Hard",
|
|
35879
|
-
description: "Maximum contrast Gruvbox on deep pitch charcoal"
|
|
35880
|
-
},
|
|
35881
|
-
{
|
|
35882
|
-
id: "oceanic-next",
|
|
35883
|
-
name: "Oceanic Next",
|
|
35884
|
-
description: "Teal-and-slate classic \u2014 calm blue, warm coral"
|
|
35885
|
-
},
|
|
35886
|
-
{
|
|
35887
|
-
id: "one-half-dark",
|
|
35888
|
-
name: "One Half Dark",
|
|
35889
|
-
description: "Atom's One Half \u2014 One Dark with cleaner contrast"
|
|
35890
|
-
},
|
|
35891
|
-
{ id: "ayu-mirage", name: "Ayu Mirage", description: "Dusk-slate Ayu, between Dark and Light" },
|
|
35892
|
-
{ id: "seti", name: "Seti", description: "Long-running VS Code classic \u2014 charcoal, gold, cyan" },
|
|
35893
|
-
{ id: "paraiso-dark", name: "Paraiso Dark", description: "Base16 plum \u2014 warm, muted, low-glare" },
|
|
35894
|
-
{
|
|
35895
|
-
id: "darcula",
|
|
35896
|
-
name: "Darcula",
|
|
35897
|
-
description: "JetBrains' default dark \u2014 grey-green with amber"
|
|
35898
|
-
},
|
|
35899
|
-
{
|
|
35900
|
-
id: "slack-dark",
|
|
35901
|
-
name: "Slack Aubergine",
|
|
35902
|
-
description: "Deep aubergine with sky blue and lime"
|
|
35903
|
-
},
|
|
35904
|
-
{
|
|
35905
|
-
id: "vitesse-black",
|
|
35906
|
-
name: "Vitesse Black",
|
|
35907
|
-
description: "Vitesse on true black \u2014 least glare here"
|
|
35908
|
-
},
|
|
35909
|
-
{
|
|
35910
|
-
id: "atom-dark",
|
|
35911
|
-
name: "Atom Dark",
|
|
35912
|
-
description: "The original Atom grey \u2014 neutral, low-chroma"
|
|
35913
|
-
},
|
|
35914
|
-
{
|
|
35915
|
-
id: "github-dark-high-contrast",
|
|
35916
|
-
name: "GitHub Dark High Contrast",
|
|
35917
|
-
description: "Accessible GitHub \u2014 boosted text and borders"
|
|
35918
|
-
},
|
|
35919
|
-
{
|
|
35920
|
-
id: "contrast-max",
|
|
35921
|
-
name: "Maximum Contrast",
|
|
35922
|
-
description: "Original \u2014 pure black, AAA-targeted text and borders"
|
|
35923
|
-
},
|
|
35924
|
-
{
|
|
35925
|
-
id: "colorblind-safe",
|
|
35926
|
-
name: "Colorblind Safe",
|
|
35927
|
-
description: "Original \u2014 blue/orange coding, no red-vs-green reliance"
|
|
35928
|
-
},
|
|
35929
|
-
{
|
|
35930
|
-
id: "sandstone",
|
|
35931
|
-
name: "Sandstone",
|
|
35932
|
-
description: "Original \u2014 warm stone neutrals with sage and clay"
|
|
35933
|
-
},
|
|
35934
|
-
{
|
|
35935
|
-
id: "everforest-hard",
|
|
35936
|
-
name: "Everforest Hard",
|
|
35937
|
-
description: "Everforest on its deepest base \u2014 more depth, same greens"
|
|
35938
|
-
}
|
|
35939
|
-
];
|
|
36303
|
+
import { THEME_PRESET_IDS, THEME_PRESET_META } from "@wrongstack/core/types";
|
|
36304
|
+
var THEME_OPTIONS = THEME_PRESET_IDS.map((id) => ({
|
|
36305
|
+
id,
|
|
36306
|
+
name: THEME_PRESET_META[id].name,
|
|
36307
|
+
description: THEME_PRESET_META[id].description,
|
|
36308
|
+
family: THEME_PRESET_META[id].family
|
|
36309
|
+
})).sort(
|
|
36310
|
+
// Group by family, keeping canonical order WITHIN each family.
|
|
36311
|
+
//
|
|
36312
|
+
// `THEME_PRESET_IDS` is not family-ordered — the Catppuccin variants sit
|
|
36313
|
+
// ~15 rows apart, and the three `misc-N` buckets scatter single palettes
|
|
36314
|
+
// across the whole list. Sorting here (rather than in the picker) is what
|
|
36315
|
+
// makes the grouping usable: the reducer, the Enter handler and the rendered
|
|
36316
|
+
// window all index into THIS array, so reordering it in one place keeps
|
|
36317
|
+
// `selected` meaning the same thing everywhere.
|
|
36318
|
+
//
|
|
36319
|
+
// `Array.prototype.sort` is stable, so sorting only on `family` preserves
|
|
36320
|
+
// canonical order inside each group without a second comparison.
|
|
36321
|
+
(a, b) => a.family.localeCompare(b.family)
|
|
36322
|
+
);
|
|
35940
36323
|
|
|
35941
36324
|
// src/theme-presets/rose-pine.ts
|
|
35942
36325
|
var rosePinePresets = {
|
|
@@ -35953,7 +36336,7 @@ var rosePinePresets = {
|
|
|
35953
36336
|
user: "#f6c177",
|
|
35954
36337
|
assistant: "#c4a7e7",
|
|
35955
36338
|
tool: "#9ccfd8",
|
|
35956
|
-
success: "#
|
|
36339
|
+
success: "#3e8fb0",
|
|
35957
36340
|
warn: "#f6c177",
|
|
35958
36341
|
error: "#eb6f92",
|
|
35959
36342
|
borderDefault: "#524f67",
|
|
@@ -37060,7 +37443,7 @@ var PANEL_IDS = Object.freeze([
|
|
|
37060
37443
|
"connections"
|
|
37061
37444
|
// Ctrl+N
|
|
37062
37445
|
]);
|
|
37063
|
-
var TOTAL_SETTINGS_FIELD_COUNT = PANEL_POSITION_FIELD_START + PANEL_IDS.length +
|
|
37446
|
+
var TOTAL_SETTINGS_FIELD_COUNT = PANEL_POSITION_FIELD_START + PANEL_IDS.length + 5;
|
|
37064
37447
|
var DEFAULT_PANEL_POSITIONS = Object.freeze({
|
|
37065
37448
|
projectPicker: "bottom",
|
|
37066
37449
|
fleet: "bottom",
|
|
@@ -42671,6 +43054,7 @@ import {
|
|
|
42671
43054
|
formatQuotaResetIn,
|
|
42672
43055
|
getAllProviderQuota,
|
|
42673
43056
|
onProviderQuota,
|
|
43057
|
+
quotaExhaustionInMs,
|
|
42674
43058
|
quotaResetInMs,
|
|
42675
43059
|
quotaWindowLabel,
|
|
42676
43060
|
worstProviderQuotaWindow
|
|
@@ -42679,11 +43063,15 @@ function readWorst() {
|
|
|
42679
43063
|
const worst = worstProviderQuotaWindow(getAllProviderQuota());
|
|
42680
43064
|
if (!worst) return void 0;
|
|
42681
43065
|
const resetIn = formatQuotaResetIn(quotaResetInMs(worst.window));
|
|
43066
|
+
const exhaustsIn = formatQuotaResetIn(
|
|
43067
|
+
quotaExhaustionInMs(worst.snapshot.providerId, worst.snapshot.meterId, worst.window)
|
|
43068
|
+
);
|
|
42682
43069
|
return {
|
|
42683
43070
|
providerId: worst.snapshot.providerId,
|
|
42684
43071
|
windowLabel: quotaWindowLabel(worst.window),
|
|
42685
43072
|
usedPercent: worst.window.usedPercent,
|
|
42686
43073
|
...resetIn !== void 0 ? { resetIn } : {},
|
|
43074
|
+
...exhaustsIn !== void 0 ? { exhaustsIn } : {},
|
|
42687
43075
|
reached: worst.snapshot.reachedWindowId === worst.window.id
|
|
42688
43076
|
};
|
|
42689
43077
|
}
|
|
@@ -43702,6 +44090,7 @@ function buildSafetyWorkEntries(p) {
|
|
|
43702
44090
|
isNoColor
|
|
43703
44091
|
);
|
|
43704
44092
|
const reset = quota.resetIn ? ` ${glyphs.clock}${quota.resetIn}` : "";
|
|
44093
|
+
const pace = quota.exhaustsIn ? ` \u2192100% ~${quota.exhaustsIn}` : "";
|
|
43705
44094
|
return entry("quota", "quota", p, [
|
|
43706
44095
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Text2, { color, children: [
|
|
43707
44096
|
icon(STATUSLINE_ICONS.quota, isNoColor),
|
|
@@ -43709,7 +44098,8 @@ function buildSafetyWorkEntries(p) {
|
|
|
43709
44098
|
" ",
|
|
43710
44099
|
pct,
|
|
43711
44100
|
"%",
|
|
43712
|
-
reset
|
|
44101
|
+
reset,
|
|
44102
|
+
pace
|
|
43713
44103
|
] }),
|
|
43714
44104
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Text2, { color, children: [
|
|
43715
44105
|
icon(STATUSLINE_ICONS.quota, isNoColor),
|
|
@@ -44145,6 +44535,11 @@ function buildMinimumChips(p) {
|
|
|
44145
44535
|
stateLabel
|
|
44146
44536
|
] }) : null,
|
|
44147
44537
|
yolo && showChip("yolo") ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Text2, { color: chipColor(theme.error, isNoColor), bold: true, children: isNoColor ? "YOLO" : `${STATUSLINE_ICONS.yolo} YOLO` }) : null,
|
|
44538
|
+
// No effort suffix here: minimum mode is the DEFAULT statusline and its
|
|
44539
|
+
// chips are single-level elements the fitter can only DROP, never degrade,
|
|
44540
|
+
// so a qualifier on this chip could never shed — it would evict trailing
|
|
44541
|
+
// chips at moderate widths instead. Same reason the minimum context chip
|
|
44542
|
+
// omits its `[strategy]`, which the detailed full level does render.
|
|
44148
44543
|
showChip("model") ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Text2, { color: chipColor(theme.monitor.agents, isNoColor), children: [
|
|
44149
44544
|
provider ? `${provider}/` : "",
|
|
44150
44545
|
model
|
|
@@ -44372,6 +44767,7 @@ var STATUSLINE_SIDE_INSET = 1;
|
|
|
44372
44767
|
var StatusBar = (0, import_react51.memo)(function StatusBar2({
|
|
44373
44768
|
model,
|
|
44374
44769
|
provider,
|
|
44770
|
+
effort,
|
|
44375
44771
|
version,
|
|
44376
44772
|
latestVersion,
|
|
44377
44773
|
updateAvailable,
|
|
@@ -44510,14 +44906,19 @@ var StatusBar = (0, import_react51.memo)(function StatusBar2({
|
|
|
44510
44906
|
stateLabel
|
|
44511
44907
|
] }) : null;
|
|
44512
44908
|
const modelColor = isNoColor ? void 0 : theme.monitor.agents;
|
|
44909
|
+
const effortSuffix = effort ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Text2, { dimColor: !isNoColor, children: ` \xB7 ${effort}` }) : null;
|
|
44513
44910
|
const modelStatusChip = showChip("model") ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Text2, { color: modelColor, children: [
|
|
44514
44911
|
provider ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Text2, { dimColor: !isNoColor, children: [
|
|
44515
44912
|
provider,
|
|
44516
44913
|
"/"
|
|
44517
44914
|
] }) : null,
|
|
44518
|
-
model
|
|
44915
|
+
model,
|
|
44916
|
+
effortSuffix
|
|
44917
|
+
] }) : null;
|
|
44918
|
+
const modelShortChip = showChip("model") ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Text2, { color: modelColor, children: [
|
|
44919
|
+
model,
|
|
44920
|
+
effortSuffix
|
|
44519
44921
|
] }) : null;
|
|
44520
|
-
const modelShortChip = showChip("model") ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Text2, { color: modelColor, children: model }) : null;
|
|
44521
44922
|
const modelMicroChip = showChip("model") ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Text2, { color: modelColor, children: truncateChip(model, 10) }) : null;
|
|
44522
44923
|
const indexStatusChip = buildIndexStatusChip(indexState, showChip, isNoColor);
|
|
44523
44924
|
const quota = useProviderQuota();
|
|
@@ -45907,7 +46308,7 @@ function TodosMonitor({ todos }) {
|
|
|
45907
46308
|
setSelected((value) => Math.min(Math.max(0, ordered.length - 1), value + 1));
|
|
45908
46309
|
}
|
|
45909
46310
|
});
|
|
45910
|
-
const
|
|
46311
|
+
const renderRow5 = (t, idx) => {
|
|
45911
46312
|
const isSelected = window2.start + idx === selected;
|
|
45912
46313
|
const marker = isSelected ? "\u203A " : " ";
|
|
45913
46314
|
const num = String(todos.indexOf(t) + 1).padStart(2);
|
|
@@ -46003,9 +46404,9 @@ function TodosMonitor({ todos }) {
|
|
|
46003
46404
|
accent: theme.warn
|
|
46004
46405
|
}
|
|
46005
46406
|
) : twoCols ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Box2, { flexDirection: "row", gap: 3, marginTop: 1, children: [
|
|
46006
|
-
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box2, { flexDirection: "column", width: colWidth, children: visible.slice(0, mid).map((t, i) =>
|
|
46007
|
-
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box2, { flexDirection: "column", width: colWidth, children: visible.slice(mid).map((t, i) =>
|
|
46008
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box2, { flexDirection: "column", marginTop: 1, children: visible.map(
|
|
46407
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box2, { flexDirection: "column", width: colWidth, children: visible.slice(0, mid).map((t, i) => renderRow5(t, i)) }),
|
|
46408
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box2, { flexDirection: "column", width: colWidth, children: visible.slice(mid).map((t, i) => renderRow5(t, mid + i)) })
|
|
46409
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Box2, { flexDirection: "column", marginTop: 1, children: visible.map(renderRow5) })
|
|
46009
46410
|
]
|
|
46010
46411
|
}
|
|
46011
46412
|
);
|
|
@@ -46439,6 +46840,7 @@ function AppStatusRegion({
|
|
|
46439
46840
|
{
|
|
46440
46841
|
provider: liveProvider,
|
|
46441
46842
|
model: liveModel,
|
|
46843
|
+
effort: getSettings ? state.settingsPicker.open ? state.settingsPicker.reasoningEffort : getSettings().reasoningEffort : void 0,
|
|
46442
46844
|
version: appVersion,
|
|
46443
46845
|
latestVersion,
|
|
46444
46846
|
updateAvailable,
|
|
@@ -51072,1249 +51474,678 @@ function collectMultiFileDiffItems(toolName, output, _input) {
|
|
|
51072
51474
|
diffText = trimmed;
|
|
51073
51475
|
}
|
|
51074
51476
|
if (!diffText?.trim()) return void 0;
|
|
51075
|
-
const blocks = splitGitStyleDiff(diffText);
|
|
51076
|
-
if (blocks.length === 0) {
|
|
51077
|
-
const path13 = explicitFiles[0] ?? extractPatchHeaderPath(diffText);
|
|
51078
|
-
return [{ path: path13, diff: diffText }];
|
|
51079
|
-
}
|
|
51080
|
-
return blocks.map((block, idx) => ({
|
|
51081
|
-
path: explicitFiles[idx] ?? block.path,
|
|
51082
|
-
diff: block.diff
|
|
51083
|
-
}));
|
|
51084
|
-
}
|
|
51085
|
-
return void 0;
|
|
51086
|
-
}
|
|
51087
|
-
function extractUnifiedDiffText(text) {
|
|
51088
|
-
const lines = text.split("\n");
|
|
51089
|
-
const start = lines.findIndex(
|
|
51090
|
-
(line) => (
|
|
51091
|
-
// Real unified-diff `--- ` headers carry a file path, not a label like
|
|
51092
|
-
// `--- SAGE: ...`; reject uppercase-label patterns that hook notices
|
|
51093
|
-
// append to tool output after a blank-line separator.
|
|
51094
|
-
line.startsWith("--- ") && !/^--- [A-Z]{2,}:/.test(line) || line.startsWith("diff --git") || line.startsWith("@@")
|
|
51095
|
-
)
|
|
51096
|
-
);
|
|
51097
|
-
if (start === -1) return void 0;
|
|
51098
|
-
let end = lines.length;
|
|
51099
|
-
for (let i = start + 1; i < lines.length; i++) {
|
|
51100
|
-
if (lines[i]?.length === 0) {
|
|
51101
|
-
end = i;
|
|
51102
|
-
break;
|
|
51103
|
-
}
|
|
51104
|
-
}
|
|
51105
|
-
return lines.slice(start, end).join("\n");
|
|
51106
|
-
}
|
|
51107
|
-
function newFileDiffFromWriteInput(output, input) {
|
|
51108
|
-
if (!input || typeof input !== "object") return void 0;
|
|
51109
|
-
const obj = input;
|
|
51110
|
-
const content = stringOf(obj["content"]);
|
|
51111
|
-
if (content === void 0) return void 0;
|
|
51112
|
-
const path13 = stringOf(output["path"]) ?? stringOf(obj["path"]) ?? "new file";
|
|
51113
|
-
const lines = content === "" ? [] : content.replace(/\n$/, "").split("\n");
|
|
51114
|
-
const header = [`+++ ${path13}`, `@@ -0,0 +1,${lines.length} @@`];
|
|
51115
|
-
return [...header, ...lines.map((line) => `+${line}`)].join("\n");
|
|
51116
|
-
}
|
|
51117
|
-
function splitGitStyleDiff(diff2) {
|
|
51118
|
-
const lines = diff2.split("\n");
|
|
51119
|
-
const blocks = [];
|
|
51120
|
-
let current = null;
|
|
51121
|
-
const flush = () => {
|
|
51122
|
-
if (!current) return;
|
|
51123
|
-
const text = current.body.join("\n").trim();
|
|
51124
|
-
if (text) blocks.push({ path: current.path, diff: text });
|
|
51125
|
-
current = null;
|
|
51126
|
-
};
|
|
51127
|
-
for (const line of lines) {
|
|
51128
|
-
if (line.startsWith("diff --git ")) {
|
|
51129
|
-
flush();
|
|
51130
|
-
current = { path: parseDiffGitPath(line), body: [line], hasGitHeader: true };
|
|
51131
|
-
continue;
|
|
51132
|
-
}
|
|
51133
|
-
if (current) {
|
|
51134
|
-
current.body.push(line);
|
|
51135
|
-
if (!current.hasGitHeader && line.startsWith("--- a/") && current.body.length > 2) {
|
|
51136
|
-
const carriedBody = current.body.slice(0, -1);
|
|
51137
|
-
const carriedPath = current.path;
|
|
51138
|
-
const text = carriedBody.join("\n").trim();
|
|
51139
|
-
if (text) blocks.push({ path: carriedPath, diff: text });
|
|
51140
|
-
current = {
|
|
51141
|
-
path: line.slice("--- a/".length).trim(),
|
|
51142
|
-
body: [line],
|
|
51143
|
-
hasGitHeader: false
|
|
51144
|
-
};
|
|
51145
|
-
}
|
|
51146
|
-
} else if (line.startsWith("--- a/")) {
|
|
51147
|
-
current = { path: line.slice("--- a/".length).trim(), body: [line], hasGitHeader: false };
|
|
51148
|
-
} else if (line.startsWith("+++ b/")) {
|
|
51149
|
-
current = { body: [line], hasGitHeader: false };
|
|
51150
|
-
}
|
|
51151
|
-
}
|
|
51152
|
-
flush();
|
|
51153
|
-
if (blocks.length === 1 && !blocks[0].path) {
|
|
51154
|
-
const path13 = extractPatchHeaderPath(blocks[0].diff);
|
|
51155
|
-
if (path13) blocks[0] = { path: path13, diff: blocks[0].diff };
|
|
51156
|
-
}
|
|
51157
|
-
return blocks;
|
|
51158
|
-
}
|
|
51159
|
-
function parseDiffGitPath(line) {
|
|
51160
|
-
const rest = line.slice("diff --git ".length).trim();
|
|
51161
|
-
if (!rest) return void 0;
|
|
51162
|
-
const sep = rest.lastIndexOf(" b/");
|
|
51163
|
-
if (sep > 0 && sep > rest.length - sep - 3) {
|
|
51164
|
-
return rest.slice(sep + 3);
|
|
51165
|
-
}
|
|
51166
|
-
const spaceIdx = rest.lastIndexOf(" ");
|
|
51167
|
-
if (spaceIdx > 0) {
|
|
51168
|
-
const rhs = rest.slice(spaceIdx + 1);
|
|
51169
|
-
return rhs.startsWith("b/") ? rhs.slice(2) : rhs;
|
|
51170
|
-
}
|
|
51171
|
-
return void 0;
|
|
51172
|
-
}
|
|
51173
|
-
function extractPatchHeaderPath(diffText) {
|
|
51174
|
-
for (const line of diffText.split("\n")) {
|
|
51175
|
-
if (line.startsWith("+++ ")) {
|
|
51176
|
-
const path13 = line.slice(4).trim();
|
|
51177
|
-
const cleaned = path13.replace(/^b\//, "").split(" ")[0].trim();
|
|
51178
|
-
return cleaned || void 0;
|
|
51179
|
-
}
|
|
51180
|
-
}
|
|
51181
|
-
return void 0;
|
|
51182
|
-
}
|
|
51183
|
-
|
|
51184
|
-
// src/components/history/diff-model.ts
|
|
51185
|
-
var DIFF_MAX_LINES = 200;
|
|
51186
|
-
var MULTI_DIFF_MAX_FILES = 20;
|
|
51187
|
-
var MULTI_DIFF_MAX_ROWS = 400;
|
|
51188
|
-
var MULTI_DIFF_SUMMARY_THRESHOLD = 5;
|
|
51189
|
-
function summarizeMultiFileDiffs(items) {
|
|
51190
|
-
let added = 0;
|
|
51191
|
-
let removed = 0;
|
|
51192
|
-
let hiddenAdded = 0;
|
|
51193
|
-
let hiddenRemoved = 0;
|
|
51194
|
-
let truncatedFiles = 0;
|
|
51195
|
-
for (const item of items) {
|
|
51196
|
-
added += item.preview.added;
|
|
51197
|
-
removed += item.preview.removed;
|
|
51198
|
-
hiddenAdded += item.preview.hiddenAdded;
|
|
51199
|
-
hiddenRemoved += item.preview.hiddenRemoved;
|
|
51200
|
-
if (item.preview.hidden > 0) truncatedFiles += 1;
|
|
51201
|
-
}
|
|
51202
|
-
const omitted = items.omitted;
|
|
51203
|
-
if (omitted) {
|
|
51204
|
-
added += omitted.added;
|
|
51205
|
-
removed += omitted.removed;
|
|
51206
|
-
}
|
|
51207
|
-
return {
|
|
51208
|
-
fileCount: items.length + (omitted?.fileCount ?? 0),
|
|
51209
|
-
added,
|
|
51210
|
-
removed,
|
|
51211
|
-
hiddenAdded,
|
|
51212
|
-
hiddenRemoved,
|
|
51213
|
-
truncatedFiles,
|
|
51214
|
-
omittedFiles: omitted?.fileCount ?? 0
|
|
51215
|
-
};
|
|
51216
|
-
}
|
|
51217
|
-
function formatMultiDiffSummary(summary, threshold = MULTI_DIFF_SUMMARY_THRESHOLD) {
|
|
51218
|
-
if (threshold === 0) return null;
|
|
51219
|
-
const effectiveThreshold = threshold < 0 ? MULTI_DIFF_SUMMARY_THRESHOLD : threshold;
|
|
51220
|
-
if (summary.fileCount < effectiveThreshold) return null;
|
|
51221
|
-
const parts = [`${summary.fileCount} files`];
|
|
51222
|
-
if (summary.added > 0) parts.push(`+${summary.added}`);
|
|
51223
|
-
if (summary.removed > 0) parts.push(`-${summary.removed}`);
|
|
51224
|
-
if (summary.hiddenAdded > 0 || summary.hiddenRemoved > 0) {
|
|
51225
|
-
const hiddenParts = [];
|
|
51226
|
-
if (summary.hiddenAdded > 0) hiddenParts.push(`+${summary.hiddenAdded}`);
|
|
51227
|
-
if (summary.hiddenRemoved > 0) hiddenParts.push(`-${summary.hiddenRemoved}`);
|
|
51228
|
-
parts.push(
|
|
51229
|
-
`\u2026 ${hiddenParts.join(" ")} hidden across ${summary.truncatedFiles} file${summary.truncatedFiles === 1 ? "" : "s"}`
|
|
51230
|
-
);
|
|
51231
|
-
}
|
|
51232
|
-
const omittedFiles = summary.omittedFiles ?? 0;
|
|
51233
|
-
if (omittedFiles > 0) {
|
|
51234
|
-
parts.push(`${omittedFiles} more file${omittedFiles === 1 ? "" : "s"} not rendered`);
|
|
51235
|
-
}
|
|
51236
|
-
return parts.join(" \xB7 ");
|
|
51237
|
-
}
|
|
51238
|
-
function formatDiffStats(added, removed) {
|
|
51239
|
-
const parts = [];
|
|
51240
|
-
if (added > 0) parts.push(`added ${added} line${added === 1 ? "" : "s"}`);
|
|
51241
|
-
if (removed > 0) parts.push(`removed ${removed} line${removed === 1 ? "" : "s"}`);
|
|
51242
|
-
if (parts.length === 0) return null;
|
|
51243
|
-
const joined = parts.join(", ");
|
|
51244
|
-
return joined.charAt(0).toUpperCase() + joined.slice(1);
|
|
51245
|
-
}
|
|
51246
|
-
function parseUnifiedDiff(diff2, maxLines) {
|
|
51247
|
-
return parseUnifiedDiffPreview(diff2, maxLines);
|
|
51248
|
-
}
|
|
51249
|
-
function extractDiffPreview(toolName, output, input) {
|
|
51250
|
-
if (!output) return void 0;
|
|
51251
|
-
const text = output.trim();
|
|
51252
|
-
if (!text) return void 0;
|
|
51253
|
-
let diff2;
|
|
51254
|
-
if (toolName === "edit" || toolName === "diff" || toolName === "write") {
|
|
51255
|
-
const parsed = tryParseJson(text);
|
|
51256
|
-
if (parsed && typeof parsed === "object") {
|
|
51257
|
-
const obj = parsed;
|
|
51258
|
-
diff2 = toolName === "write" && obj["created"] === true ? newFileDiffFromWriteInput(obj, input) ?? stringOf(obj["diff"]) : stringOf(obj["diff"]);
|
|
51259
|
-
} else {
|
|
51260
|
-
diff2 = extractUnifiedDiffText(text);
|
|
51261
|
-
}
|
|
51262
|
-
} else if (toolName === "patch") {
|
|
51263
|
-
const parsed = tryParseJson(text);
|
|
51264
|
-
if (parsed && typeof parsed === "object") {
|
|
51265
|
-
diff2 = stringOf(parsed["diff"]) ?? stringOf(parsed["stdout"]);
|
|
51266
|
-
} else if (text.includes("@@") || text.startsWith("---")) {
|
|
51267
|
-
diff2 = text;
|
|
51268
|
-
}
|
|
51269
|
-
} else if (toolName === "replace") {
|
|
51270
|
-
const parsed = tryParseJson(text);
|
|
51271
|
-
if (parsed && typeof parsed === "object") {
|
|
51272
|
-
diff2 = joinReplaceDiffs(parsed);
|
|
51273
|
-
}
|
|
51274
|
-
}
|
|
51275
|
-
if (!diff2?.trim() || diff2.startsWith("(no-op")) return void 0;
|
|
51276
|
-
const preview = parseUnifiedDiff(diff2, DIFF_MAX_LINES);
|
|
51277
|
-
return preview.rows.length > 0 ? preview : void 0;
|
|
51278
|
-
}
|
|
51279
|
-
function extractMultiFileDiffs(toolName, output, input) {
|
|
51280
|
-
if (!output) return void 0;
|
|
51281
|
-
const items = collectMultiFileDiffItems(toolName, output, input);
|
|
51282
|
-
if (items === void 0) return void 0;
|
|
51283
|
-
if (items.length === 0) return void 0;
|
|
51284
|
-
const previews = [];
|
|
51285
|
-
const candidateItems = items.slice(0, MULTI_DIFF_MAX_FILES);
|
|
51286
|
-
let remainingRows = MULTI_DIFF_MAX_ROWS;
|
|
51287
|
-
let visited = 0;
|
|
51288
|
-
for (const item of candidateItems) {
|
|
51289
|
-
if (remainingRows <= 0) break;
|
|
51290
|
-
visited++;
|
|
51291
|
-
const preview = parseUnifiedDiff(item.diff, Math.min(DIFF_MAX_LINES, remainingRows));
|
|
51292
|
-
if (preview.rows.length === 0) continue;
|
|
51293
|
-
previews.push({ path: item.path ?? "unknown file", preview });
|
|
51294
|
-
remainingRows -= preview.rows.length;
|
|
51295
|
-
}
|
|
51296
|
-
const omittedItems = items.slice(visited);
|
|
51297
|
-
if (omittedItems.length > 0) {
|
|
51298
|
-
let added = 0;
|
|
51299
|
-
let removed = 0;
|
|
51300
|
-
for (const item of omittedItems) {
|
|
51301
|
-
const summary = countUnifiedDiffChanges(item.diff);
|
|
51302
|
-
added += summary.added;
|
|
51303
|
-
removed += summary.removed;
|
|
51304
|
-
}
|
|
51305
|
-
previews.omitted = { fileCount: omittedItems.length, added, removed };
|
|
51306
|
-
}
|
|
51307
|
-
return previews.length > 0 ? previews : void 0;
|
|
51308
|
-
}
|
|
51309
|
-
|
|
51310
|
-
// src/components/history/code-block.tsx
|
|
51311
|
-
var import_jsx_runtime49 = __toESM(require_jsx_runtime(), 1);
|
|
51312
|
-
var MAX_CODE_LINES = 80;
|
|
51313
|
-
var DIFF_FALLBACK_WRAP_WIDTH = 100;
|
|
51314
|
-
var HARD_TAB_WIDTH = 8;
|
|
51315
|
-
function expandTabs(text, tabWidth = HARD_TAB_WIDTH) {
|
|
51316
|
-
if (!text.includes(" ")) return text;
|
|
51317
|
-
let out = "";
|
|
51318
|
-
let col = 0;
|
|
51319
|
-
for (const ch of text) {
|
|
51320
|
-
if (ch === " ") {
|
|
51321
|
-
const advance = tabWidth - col % tabWidth;
|
|
51322
|
-
out += " ".repeat(advance);
|
|
51323
|
-
col += advance;
|
|
51324
|
-
} else {
|
|
51325
|
-
out += ch;
|
|
51326
|
-
col += 1;
|
|
51327
|
-
}
|
|
51328
|
-
}
|
|
51329
|
-
return out;
|
|
51330
|
-
}
|
|
51331
|
-
function CodeBlockImpl({
|
|
51332
|
-
code,
|
|
51333
|
-
lang,
|
|
51334
|
-
contentWidth
|
|
51335
|
-
}) {
|
|
51336
|
-
useActiveTheme();
|
|
51337
|
-
let lines = sanitizeTerminalText(code, HARD_TAB_WIDTH).replace(/\n+$/, "").split("\n");
|
|
51338
|
-
const hidden = Math.max(0, lines.length - MAX_CODE_LINES);
|
|
51339
|
-
if (hidden > 0) lines = lines.slice(0, MAX_CODE_LINES);
|
|
51340
|
-
const gutterW = String(lines.length).length;
|
|
51341
|
-
const maxW = Math.max(1, Math.min(contentWidth - 4 - gutterW - 1, 120));
|
|
51342
|
-
let carry = {};
|
|
51343
|
-
const rows = lines.map((raw) => {
|
|
51344
|
-
const expanded = expandTabs(raw);
|
|
51345
|
-
const display = truncateDisplay(expanded, maxW);
|
|
51346
|
-
const r = highlightLine(display, lang, carry);
|
|
51347
|
-
carry = r.carry;
|
|
51348
|
-
return r.tokens;
|
|
51349
|
-
});
|
|
51350
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(HistoryRail, { color: theme.borderDefault, children: [
|
|
51351
|
-
lang !== "plain" ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: lang }) : null,
|
|
51352
|
-
rows.map((tokens, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Text2, { children: [
|
|
51353
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: `${String(i + 1).padStart(gutterW, " ")} ` }),
|
|
51354
|
-
tokens.length === 0 ? " " : tokens.map((t, j) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
51355
|
-
Text2,
|
|
51356
|
-
{
|
|
51357
|
-
dimColor: Boolean(t.dim),
|
|
51358
|
-
bold: Boolean(t.bold),
|
|
51359
|
-
...t.color ? { color: t.color } : {},
|
|
51360
|
-
children: t.text
|
|
51361
|
-
},
|
|
51362
|
-
j
|
|
51363
|
-
))
|
|
51364
|
-
] }, i)),
|
|
51365
|
-
hidden > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, italic: true, children: `\u2026 +${hidden} more line${hidden === 1 ? "" : "s"}` }) : null
|
|
51366
|
-
] });
|
|
51367
|
-
}
|
|
51368
|
-
function DiffFileBlock({
|
|
51369
|
-
path: path13,
|
|
51370
|
-
preview,
|
|
51371
|
-
useColor = true,
|
|
51372
|
-
contentWidth
|
|
51373
|
-
}) {
|
|
51374
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Box2, { flexDirection: "column", marginTop: 1, children: [
|
|
51375
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Box2, { flexDirection: "row", marginBottom: 0, children: [
|
|
51376
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { bold: true, color: theme.accent, children: `\u25B8 ${path13}` }),
|
|
51377
|
-
preview.added > 0 || preview.removed > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: ` (${preview.added > 0 ? `+${preview.added}` : ""}${preview.added > 0 && preview.removed > 0 ? " " : ""}${preview.removed > 0 ? `-${preview.removed}` : ""})` }) : null
|
|
51378
|
-
] }),
|
|
51379
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
51380
|
-
DiffBlock,
|
|
51381
|
-
{
|
|
51382
|
-
rows: preview.rows,
|
|
51383
|
-
hidden: preview.hidden,
|
|
51384
|
-
added: preview.added,
|
|
51385
|
-
removed: preview.removed,
|
|
51386
|
-
hiddenAdded: preview.hiddenAdded,
|
|
51387
|
-
hiddenRemoved: preview.hiddenRemoved,
|
|
51388
|
-
useColor,
|
|
51389
|
-
lang: langFromPath(path13),
|
|
51390
|
-
showStats: false,
|
|
51391
|
-
contentWidth
|
|
51392
|
-
}
|
|
51393
|
-
)
|
|
51394
|
-
] });
|
|
51395
|
-
}
|
|
51396
|
-
function applyWashTokens(tokens, onWash) {
|
|
51397
|
-
if (!onWash) return tokens;
|
|
51398
|
-
return tokens.map((t) => {
|
|
51399
|
-
if (t.color !== "syntax.comment") return t;
|
|
51400
|
-
return { ...t, color: "syntax.commentOnWash", dim: false };
|
|
51401
|
-
});
|
|
51402
|
-
}
|
|
51403
|
-
function renderTokens(tokens, onWash = false) {
|
|
51404
|
-
const effective = applyWashTokens(tokens, onWash);
|
|
51405
|
-
if (effective.length === 0) return " ";
|
|
51406
|
-
return effective.map((t, j) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
51407
|
-
Text2,
|
|
51408
|
-
{
|
|
51409
|
-
dimColor: Boolean(t.dim),
|
|
51410
|
-
bold: Boolean(t.bold),
|
|
51411
|
-
...t.color ? { color: t.color } : {},
|
|
51412
|
-
children: t.text
|
|
51413
|
-
},
|
|
51414
|
-
j
|
|
51415
|
-
));
|
|
51416
|
-
}
|
|
51417
|
-
function wrapTokens(tokens, width) {
|
|
51418
|
-
if (width <= 0) return [tokens];
|
|
51419
|
-
const segments = [];
|
|
51420
|
-
let current = [];
|
|
51421
|
-
let currentWidth = 0;
|
|
51422
|
-
for (const t of tokens) {
|
|
51423
|
-
let text = t.text;
|
|
51424
|
-
while (text.length > 0) {
|
|
51425
|
-
const room = width - currentWidth;
|
|
51426
|
-
if (room <= 0) {
|
|
51427
|
-
segments.push(current);
|
|
51428
|
-
current = [];
|
|
51429
|
-
currentWidth = 0;
|
|
51430
|
-
continue;
|
|
51431
|
-
}
|
|
51432
|
-
const [piece, rest] = splitDisplay(text, room);
|
|
51433
|
-
if (!piece) {
|
|
51434
|
-
segments.push(current);
|
|
51435
|
-
current = [];
|
|
51436
|
-
currentWidth = 0;
|
|
51437
|
-
continue;
|
|
51438
|
-
}
|
|
51439
|
-
current.push({ ...t, text: piece });
|
|
51440
|
-
currentWidth += displayWidth(piece);
|
|
51441
|
-
text = rest;
|
|
51442
|
-
}
|
|
51443
|
-
}
|
|
51444
|
-
if (current.length > 0 || segments.length === 0) segments.push(current);
|
|
51445
|
-
return segments;
|
|
51446
|
-
}
|
|
51447
|
-
function DiffBlock({
|
|
51448
|
-
rows,
|
|
51449
|
-
hidden,
|
|
51450
|
-
added = 0,
|
|
51451
|
-
removed = 0,
|
|
51452
|
-
hiddenAdded = 0,
|
|
51453
|
-
hiddenRemoved = 0,
|
|
51454
|
-
useColor = true,
|
|
51455
|
-
lang = "plain",
|
|
51456
|
-
showStats = true,
|
|
51457
|
-
contentWidth
|
|
51458
|
-
}) {
|
|
51459
|
-
const lineNoOf = (row) => row.kind === "del" ? row.oldLine : row.newLine ?? row.oldLine;
|
|
51460
|
-
let gutterWidth = 1;
|
|
51461
|
-
for (const r of rows) {
|
|
51462
|
-
const n = lineNoOf(r);
|
|
51463
|
-
if (typeof n === "number" && String(n).length > gutterWidth) gutterWidth = String(n).length;
|
|
51464
|
-
}
|
|
51465
|
-
const blank = " ".repeat(gutterWidth);
|
|
51466
|
-
const markerFor = (kind) => {
|
|
51467
|
-
if (kind === "add") return "+";
|
|
51468
|
-
if (kind === "del") return "-";
|
|
51469
|
-
return " ";
|
|
51470
|
-
};
|
|
51471
|
-
const textForDisplay = (row) => {
|
|
51472
|
-
if ((row.kind === "add" || row.kind === "del" || row.kind === "ctx") && row.text.length > 0) {
|
|
51473
|
-
return sanitizeTerminalText(expandTabs(row.text.slice(1)), HARD_TAB_WIDTH) || " ";
|
|
51474
|
-
}
|
|
51475
|
-
return sanitizeTerminalText(expandTabs(row.text), HARD_TAB_WIDTH) || " ";
|
|
51476
|
-
};
|
|
51477
|
-
const stats = showStats ? formatDiffStats(added, removed) : null;
|
|
51478
|
-
const terminalWrapGuard = typeof contentWidth === "number" ? 1 : 0;
|
|
51479
|
-
const bodyBudget = typeof contentWidth === "number" ? Math.max(1, contentWidth - (2 + 3 + gutterWidth + 3 + terminalWrapGuard)) : DIFF_FALLBACK_WRAP_WIDTH;
|
|
51480
|
-
const hasWidth = typeof contentWidth === "number";
|
|
51481
|
-
const padBody = (seg) => {
|
|
51482
|
-
if (!hasWidth) return 0;
|
|
51483
|
-
const len = seg.reduce((n, t) => n + displayWidth(t.text), 0);
|
|
51484
|
-
return Math.max(0, bodyBudget - len);
|
|
51485
|
-
};
|
|
51486
|
-
const contPrefix = ` ${blank} `;
|
|
51487
|
-
const hiddenStats = [];
|
|
51488
|
-
if (hiddenAdded > 0) hiddenStats.push(`+${hiddenAdded}`);
|
|
51489
|
-
if (hiddenRemoved > 0) hiddenStats.push(`-${hiddenRemoved}`);
|
|
51490
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Box2, { flexDirection: "column", marginLeft: 2, marginTop: 0, children: [
|
|
51491
|
-
stats ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Text2, { children: [
|
|
51492
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: "\u23BF " }),
|
|
51493
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { children: stats })
|
|
51494
|
-
] }) : null,
|
|
51495
|
-
rows.map((row, i) => {
|
|
51496
|
-
const key2 = i;
|
|
51497
|
-
if (row.kind === "hunk") {
|
|
51498
|
-
if (i === 0) return null;
|
|
51499
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: ` ${blank} \u22EF` }, key2);
|
|
51500
|
-
}
|
|
51501
|
-
if (row.kind === "meta") {
|
|
51502
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: ` ${blank} ${sanitizeTerminalText(row.text)}` }, key2);
|
|
51503
|
-
}
|
|
51504
|
-
const n = lineNoOf(row);
|
|
51505
|
-
const ln = typeof n === "number" ? String(n).padStart(gutterWidth, " ") : blank;
|
|
51506
|
-
const body = textForDisplay(row);
|
|
51507
|
-
const tokens = highlightLine(body, lang).tokens;
|
|
51508
|
-
const segments = wrapTokens(tokens, bodyBudget);
|
|
51509
|
-
if (row.kind === "ctx") {
|
|
51510
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Box2, { flexDirection: "column", children: segments.map((seg, si) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Text2, { children: [
|
|
51511
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: si === 0 ? ` ${ln} ` : contPrefix }),
|
|
51512
|
-
renderTokens(seg)
|
|
51513
|
-
] }, si)) }, key2);
|
|
51514
|
-
}
|
|
51515
|
-
const marker = markerFor(row.kind);
|
|
51516
|
-
const markerColor = row.kind === "add" ? theme.success : theme.error;
|
|
51517
|
-
if (useColor) {
|
|
51518
|
-
const bg = row.kind === "add" ? theme.diffAddBg : theme.diffDelBg;
|
|
51519
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Box2, { flexDirection: "column", children: segments.map((seg, si) => {
|
|
51520
|
-
const pad = padBody(seg);
|
|
51521
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Text2, { backgroundColor: bg, children: [
|
|
51522
|
-
si === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
|
|
51523
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: ` ${ln} ` }),
|
|
51524
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { color: markerColor, bold: true, children: marker }),
|
|
51525
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { children: " " })
|
|
51526
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: contPrefix }),
|
|
51527
|
-
renderTokens(seg, true),
|
|
51528
|
-
pad > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { children: " ".repeat(pad) }) : null
|
|
51529
|
-
] }, si);
|
|
51530
|
-
}) }, key2);
|
|
51531
|
-
}
|
|
51532
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Box2, { flexDirection: "column", children: segments.map((seg, si) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Text2, { children: [
|
|
51533
|
-
si === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
|
|
51534
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: ` ${ln} ` }),
|
|
51535
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { color: markerColor, bold: true, children: marker }),
|
|
51536
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { children: " " })
|
|
51537
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: contPrefix }),
|
|
51538
|
-
renderTokens(seg)
|
|
51539
|
-
] }, si)) }, key2);
|
|
51540
|
-
}),
|
|
51541
|
-
hidden > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, italic: true, children: ` ${blank} \u2026 ${hidden} more line${hidden === 1 ? "" : "s"}${hiddenStats.length > 0 ? ` (${hiddenStats.join(" ")} hidden)` : ""}` }) : null
|
|
51542
|
-
] });
|
|
51543
|
-
}
|
|
51544
|
-
var CodeBlock = (0, import_react62.memo)(CodeBlockImpl);
|
|
51545
|
-
|
|
51546
|
-
// src/components/confirm-prompt.tsx
|
|
51547
|
-
var import_jsx_runtime50 = __toESM(require_jsx_runtime(), 1);
|
|
51548
|
-
var BUTTON_COLOR = {
|
|
51549
|
-
yes: "green",
|
|
51550
|
-
no: "red",
|
|
51551
|
-
always: "cyan",
|
|
51552
|
-
"always-exact": "cyan",
|
|
51553
|
-
"always-command": "cyan",
|
|
51554
|
-
"always-tool": "yellow",
|
|
51555
|
-
deny: "red"
|
|
51556
|
-
};
|
|
51557
|
-
function buttonLabels(_suggestedPattern, toolName = "exec") {
|
|
51558
|
-
return [
|
|
51559
|
-
{ decision: "yes", bracket: "[y]", rest: "es " },
|
|
51560
|
-
{ decision: "no", bracket: "[n]", rest: "o " },
|
|
51561
|
-
{ decision: "always-exact", bracket: "[a]", rest: " same args " },
|
|
51562
|
-
...toolName === "exec" ? [{ decision: "always-command", bracket: "[c]", rest: " command " }] : [],
|
|
51563
|
-
{ decision: "always-tool", bracket: "[t]", rest: " tool " },
|
|
51564
|
-
{ decision: "deny", bracket: "[d]", rest: "eny" }
|
|
51565
|
-
];
|
|
51566
|
-
}
|
|
51567
|
-
function stringifyInput(input) {
|
|
51568
|
-
if (!input || typeof input !== "object") return "";
|
|
51569
|
-
const obj = input;
|
|
51570
|
-
return Object.entries(obj).filter(([k]) => k !== "content" && k !== "new_string" && k !== "diff").map(([k, v]) => `${k}: ${truncate(JSON.stringify(v), 80)}`).join(" ");
|
|
51477
|
+
const blocks = splitGitStyleDiff(diffText);
|
|
51478
|
+
if (blocks.length === 0) {
|
|
51479
|
+
const path13 = explicitFiles[0] ?? extractPatchHeaderPath(diffText);
|
|
51480
|
+
return [{ path: path13, diff: diffText }];
|
|
51481
|
+
}
|
|
51482
|
+
return blocks.map((block, idx) => ({
|
|
51483
|
+
path: explicitFiles[idx] ?? block.path,
|
|
51484
|
+
diff: block.diff
|
|
51485
|
+
}));
|
|
51486
|
+
}
|
|
51487
|
+
return void 0;
|
|
51571
51488
|
}
|
|
51572
|
-
function
|
|
51573
|
-
|
|
51489
|
+
function extractUnifiedDiffText(text) {
|
|
51490
|
+
const lines = text.split("\n");
|
|
51491
|
+
const start = lines.findIndex(
|
|
51492
|
+
(line) => (
|
|
51493
|
+
// Real unified-diff `--- ` headers carry a file path, not a label like
|
|
51494
|
+
// `--- SAGE: ...`; reject uppercase-label patterns that hook notices
|
|
51495
|
+
// append to tool output after a blank-line separator.
|
|
51496
|
+
line.startsWith("--- ") && !/^--- [A-Z]{2,}:/.test(line) || line.startsWith("diff --git") || line.startsWith("@@")
|
|
51497
|
+
)
|
|
51498
|
+
);
|
|
51499
|
+
if (start === -1) return void 0;
|
|
51500
|
+
let end = lines.length;
|
|
51501
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
51502
|
+
if (lines[i]?.length === 0) {
|
|
51503
|
+
end = i;
|
|
51504
|
+
break;
|
|
51505
|
+
}
|
|
51506
|
+
}
|
|
51507
|
+
return lines.slice(start, end).join("\n");
|
|
51574
51508
|
}
|
|
51575
|
-
function
|
|
51576
|
-
if (!input || typeof input !== "object") return
|
|
51509
|
+
function newFileDiffFromWriteInput(output, input) {
|
|
51510
|
+
if (!input || typeof input !== "object") return void 0;
|
|
51577
51511
|
const obj = input;
|
|
51578
|
-
const
|
|
51579
|
-
if (
|
|
51580
|
-
const
|
|
51581
|
-
|
|
51582
|
-
|
|
51583
|
-
|
|
51512
|
+
const content = stringOf(obj["content"]);
|
|
51513
|
+
if (content === void 0) return void 0;
|
|
51514
|
+
const path13 = stringOf(output["path"]) ?? stringOf(obj["path"]) ?? "new file";
|
|
51515
|
+
const lines = content === "" ? [] : content.replace(/\n$/, "").split("\n");
|
|
51516
|
+
const header = [`+++ ${path13}`, `@@ -0,0 +1,${lines.length} @@`];
|
|
51517
|
+
return [...header, ...lines.map((line) => `+${line}`)].join("\n");
|
|
51518
|
+
}
|
|
51519
|
+
function splitGitStyleDiff(diff2) {
|
|
51520
|
+
const lines = diff2.split("\n");
|
|
51521
|
+
const blocks = [];
|
|
51522
|
+
let current = null;
|
|
51523
|
+
const flush = () => {
|
|
51524
|
+
if (!current) return;
|
|
51525
|
+
const text = current.body.join("\n").trim();
|
|
51526
|
+
if (text) blocks.push({ path: current.path, diff: text });
|
|
51527
|
+
current = null;
|
|
51528
|
+
};
|
|
51529
|
+
for (const line of lines) {
|
|
51530
|
+
if (line.startsWith("diff --git ")) {
|
|
51531
|
+
flush();
|
|
51532
|
+
current = { path: parseDiffGitPath(line), body: [line], hasGitHeader: true };
|
|
51533
|
+
continue;
|
|
51534
|
+
}
|
|
51535
|
+
if (current) {
|
|
51536
|
+
current.body.push(line);
|
|
51537
|
+
if (!current.hasGitHeader && line.startsWith("--- a/") && current.body.length > 2) {
|
|
51538
|
+
const carriedBody = current.body.slice(0, -1);
|
|
51539
|
+
const carriedPath = current.path;
|
|
51540
|
+
const text = carriedBody.join("\n").trim();
|
|
51541
|
+
if (text) blocks.push({ path: carriedPath, diff: text });
|
|
51542
|
+
current = {
|
|
51543
|
+
path: line.slice("--- a/".length).trim(),
|
|
51544
|
+
body: [line],
|
|
51545
|
+
hasGitHeader: false
|
|
51546
|
+
};
|
|
51547
|
+
}
|
|
51548
|
+
} else if (line.startsWith("--- a/")) {
|
|
51549
|
+
current = { path: line.slice("--- a/".length).trim(), body: [line], hasGitHeader: false };
|
|
51550
|
+
} else if (line.startsWith("+++ b/")) {
|
|
51551
|
+
current = { body: [line], hasGitHeader: false };
|
|
51552
|
+
}
|
|
51584
51553
|
}
|
|
51585
|
-
|
|
51586
|
-
if (
|
|
51587
|
-
|
|
51554
|
+
flush();
|
|
51555
|
+
if (blocks.length === 1 && !blocks[0].path) {
|
|
51556
|
+
const path13 = extractPatchHeaderPath(blocks[0].diff);
|
|
51557
|
+
if (path13) blocks[0] = { path: path13, diff: blocks[0].diff };
|
|
51588
51558
|
}
|
|
51589
|
-
return
|
|
51590
|
-
}
|
|
51591
|
-
var CONFIRM_DIFF_MAX_LINES = 20;
|
|
51592
|
-
function renderDiffLine(line) {
|
|
51593
|
-
const prefix = line.startsWith("+") ? "green" : line.startsWith("-") ? "red" : line.startsWith("@@") ? "cyan" : void 0;
|
|
51594
|
-
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { ...prefix ? { color: prefix } : {}, children: [
|
|
51595
|
-
line,
|
|
51596
|
-
"\n"
|
|
51597
|
-
] }, line);
|
|
51559
|
+
return blocks;
|
|
51598
51560
|
}
|
|
51599
|
-
function
|
|
51600
|
-
const
|
|
51601
|
-
if (
|
|
51602
|
-
|
|
51603
|
-
|
|
51604
|
-
|
|
51605
|
-
rows: preview.rows,
|
|
51606
|
-
hidden: preview.hidden,
|
|
51607
|
-
added: preview.added,
|
|
51608
|
-
removed: preview.removed,
|
|
51609
|
-
hiddenAdded: preview.hiddenAdded,
|
|
51610
|
-
hiddenRemoved: preview.hiddenRemoved,
|
|
51611
|
-
useColor: theme.supportsBackground,
|
|
51612
|
-
lang: langFromPath(path13 ?? "")
|
|
51613
|
-
}
|
|
51614
|
-
);
|
|
51561
|
+
function parseDiffGitPath(line) {
|
|
51562
|
+
const rest = line.slice("diff --git ".length).trim();
|
|
51563
|
+
if (!rest) return void 0;
|
|
51564
|
+
const sep = rest.lastIndexOf(" b/");
|
|
51565
|
+
if (sep > 0 && sep > rest.length - sep - 3) {
|
|
51566
|
+
return rest.slice(sep + 3);
|
|
51615
51567
|
}
|
|
51616
|
-
const
|
|
51617
|
-
|
|
51568
|
+
const spaceIdx = rest.lastIndexOf(" ");
|
|
51569
|
+
if (spaceIdx > 0) {
|
|
51570
|
+
const rhs = rest.slice(spaceIdx + 1);
|
|
51571
|
+
return rhs.startsWith("b/") ? rhs.slice(2) : rhs;
|
|
51572
|
+
}
|
|
51573
|
+
return void 0;
|
|
51618
51574
|
}
|
|
51619
|
-
function
|
|
51620
|
-
|
|
51621
|
-
|
|
51622
|
-
|
|
51623
|
-
|
|
51624
|
-
|
|
51625
|
-
destructive,
|
|
51626
|
-
boundaryReason,
|
|
51627
|
-
writeTargets,
|
|
51628
|
-
maxRows
|
|
51629
|
-
}) {
|
|
51630
|
-
const size = useTerminalSize();
|
|
51631
|
-
const rowBudget = maxRows ?? size.rows;
|
|
51632
|
-
const buttons = import_react63.default.useRef(/* @__PURE__ */ new Map());
|
|
51633
|
-
const partialMouse = import_react63.default.useRef("");
|
|
51634
|
-
const decided = import_react63.default.useRef(false);
|
|
51635
|
-
const decide = (decision) => {
|
|
51636
|
-
if (decided.current) return;
|
|
51637
|
-
decided.current = true;
|
|
51638
|
-
onDecision(decision);
|
|
51639
|
-
};
|
|
51640
|
-
const { stdin } = use_stdin_default();
|
|
51641
|
-
import_react63.default.useEffect(() => {
|
|
51642
|
-
if (!stdin) return;
|
|
51643
|
-
const onData = (data) => {
|
|
51644
|
-
const chunk = splitTrailingMousePartial(partialMouse.current + data.toString());
|
|
51645
|
-
partialMouse.current = chunk.pending;
|
|
51646
|
-
for (const event of parseMouseEvents(chunk.consumed)) {
|
|
51647
|
-
if (event.kind !== "press" || event.button !== "left") continue;
|
|
51648
|
-
for (const [decision, node] of buttons.current) {
|
|
51649
|
-
const rect = measure_element_default(node);
|
|
51650
|
-
if (event.x > rect.x && event.x <= rect.x + rect.width && event.y > rect.y && event.y <= rect.y + rect.height) {
|
|
51651
|
-
decide(decision);
|
|
51652
|
-
break;
|
|
51653
|
-
}
|
|
51654
|
-
}
|
|
51655
|
-
}
|
|
51656
|
-
};
|
|
51657
|
-
stdin.on("data", onData);
|
|
51658
|
-
return () => {
|
|
51659
|
-
stdin.off("data", onData);
|
|
51660
|
-
};
|
|
51661
|
-
}, [stdin, decide]);
|
|
51662
|
-
import_react63.default.useEffect(() => {
|
|
51663
|
-
writeOut("\x07");
|
|
51664
|
-
}, []);
|
|
51665
|
-
use_input_default((input2, key2) => {
|
|
51666
|
-
if (key2.ctrl || key2.meta || decided.current) return;
|
|
51667
|
-
if (!input2 || input2 === "\r" || input2 === "\n") return;
|
|
51668
|
-
if (input2 === "Y" && !boundaryReason) {
|
|
51669
|
-
onEnableYolo();
|
|
51670
|
-
return;
|
|
51671
|
-
}
|
|
51672
|
-
const ch = input2.toLowerCase();
|
|
51673
|
-
if (ch === "y") {
|
|
51674
|
-
decide("yes");
|
|
51675
|
-
} else if (ch === "n") {
|
|
51676
|
-
decide("no");
|
|
51677
|
-
} else if (ch === "a") {
|
|
51678
|
-
decide("always-exact");
|
|
51679
|
-
} else if (ch === "c" && toolName === "exec") {
|
|
51680
|
-
decide("always-command");
|
|
51681
|
-
} else if (ch === "t") {
|
|
51682
|
-
decide("always-tool");
|
|
51683
|
-
} else if (ch === "d") {
|
|
51684
|
-
decide("deny");
|
|
51685
|
-
}
|
|
51686
|
-
});
|
|
51687
|
-
const inputSummary = stringifyInput(input);
|
|
51688
|
-
const inp = input;
|
|
51689
|
-
const diff2 = payloadDiff(input);
|
|
51690
|
-
const diffPath = typeof inp?.path === "string" ? inp.path : void 0;
|
|
51691
|
-
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(PanelInputProvider, { value: true, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(MonitorViewportProvider, { value: { columns: size.columns, rows: rowBudget }, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
|
|
51692
|
-
MonitorShell,
|
|
51693
|
-
{
|
|
51694
|
-
accent: "yellow",
|
|
51695
|
-
icon: "\u26A0",
|
|
51696
|
-
title: `APPROVAL REQUIRED \xB7 ${toolName}`,
|
|
51697
|
-
footer: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Box2, { flexDirection: "row", flexWrap: "wrap", children: buttonLabels(suggestedPattern, toolName).map((label) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
51698
|
-
Box2,
|
|
51699
|
-
{
|
|
51700
|
-
flexShrink: 0,
|
|
51701
|
-
ref: (node) => {
|
|
51702
|
-
if (node) buttons.current.set(label.decision, node);
|
|
51703
|
-
else buttons.current.delete(label.decision);
|
|
51704
|
-
},
|
|
51705
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { children: [
|
|
51706
|
-
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Text2, { bold: true, color: BUTTON_COLOR[label.decision], children: label.bracket }),
|
|
51707
|
-
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Text2, { dimColor: true, children: label.rest })
|
|
51708
|
-
] })
|
|
51709
|
-
},
|
|
51710
|
-
label.decision
|
|
51711
|
-
)) }),
|
|
51712
|
-
children: [
|
|
51713
|
-
inputSummary ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Text2, { dimColor: true, children: inputSummary }) : null,
|
|
51714
|
-
boundaryReason ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { color: "yellow", children: [
|
|
51715
|
-
"KANBAN BOUNDARY: ",
|
|
51716
|
-
boundaryReason
|
|
51717
|
-
] }) : null,
|
|
51718
|
-
writeTargets && writeTargets.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { color: "yellow", children: [
|
|
51719
|
-
"WRITES: ",
|
|
51720
|
-
writeTargets.slice(0, 5).join(", "),
|
|
51721
|
-
writeTargets.length > 5 ? ` (+${writeTargets.length - 5} more)` : ""
|
|
51722
|
-
] }) : null,
|
|
51723
|
-
diff2 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Box2, { flexDirection: "column", marginY: 1, children: renderDiff(diff2, diffPath) }) : null,
|
|
51724
|
-
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { dimColor: true, children: [
|
|
51725
|
-
"Remember: [a] this input; ",
|
|
51726
|
-
toolName === "exec" ? "[c] executable, any args; " : "",
|
|
51727
|
-
"[t] tool, any input. Destructive calls still prompt."
|
|
51728
|
-
] }),
|
|
51729
|
-
!boundaryReason ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Box2, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { dimColor: true, children: [
|
|
51730
|
-
" ",
|
|
51731
|
-
"Tip: press",
|
|
51732
|
-
" ",
|
|
51733
|
-
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Text2, { bold: true, color: "yellow", children: "Y" }),
|
|
51734
|
-
" ",
|
|
51735
|
-
"to enable YOLO mode",
|
|
51736
|
-
destructive ? " (this destructive approval remains)" : " (skips future routine approvals)",
|
|
51737
|
-
"."
|
|
51738
|
-
] }) }) : null
|
|
51739
|
-
]
|
|
51575
|
+
function extractPatchHeaderPath(diffText) {
|
|
51576
|
+
for (const line of diffText.split("\n")) {
|
|
51577
|
+
if (line.startsWith("+++ ")) {
|
|
51578
|
+
const path13 = line.slice(4).trim();
|
|
51579
|
+
const cleaned = path13.replace(/^b\//, "").split(" ")[0].trim();
|
|
51580
|
+
return cleaned || void 0;
|
|
51740
51581
|
}
|
|
51741
|
-
|
|
51582
|
+
}
|
|
51583
|
+
return void 0;
|
|
51742
51584
|
}
|
|
51743
51585
|
|
|
51744
|
-
// src/components/
|
|
51745
|
-
var
|
|
51746
|
-
|
|
51747
|
-
|
|
51748
|
-
|
|
51749
|
-
|
|
51750
|
-
|
|
51751
|
-
|
|
51752
|
-
|
|
51753
|
-
|
|
51754
|
-
|
|
51755
|
-
|
|
51756
|
-
|
|
51757
|
-
|
|
51758
|
-
|
|
51759
|
-
|
|
51760
|
-
|
|
51761
|
-
closeKanbanServerConnections,
|
|
51762
|
-
getKanbanServerConnection,
|
|
51763
|
-
isKanbanServerAvailable
|
|
51764
|
-
} from "@wrongstack/kanban";
|
|
51765
|
-
import { isSageProjectServerAvailable, SageProjectServerConnection } from "@wrongstack/sage";
|
|
51766
|
-
import {
|
|
51767
|
-
checkCodebaseIndexServerHealth,
|
|
51768
|
-
ensureCodebaseIndexServer,
|
|
51769
|
-
shutdownCodebaseIndexServer
|
|
51770
|
-
} from "@wrongstack/tools";
|
|
51771
|
-
var RESTARTABLE_SERVICES = [
|
|
51772
|
-
"session-catalog",
|
|
51773
|
-
"chronicle",
|
|
51774
|
-
"codebase-index",
|
|
51775
|
-
"sage",
|
|
51776
|
-
"kanban",
|
|
51777
|
-
"mailbox"
|
|
51778
|
-
];
|
|
51779
|
-
function isRestartableService(serviceId) {
|
|
51780
|
-
return RESTARTABLE_SERVICES.includes(serviceId);
|
|
51781
|
-
}
|
|
51782
|
-
function isEndpointAlive(endpoint) {
|
|
51783
|
-
return new Promise((resolve) => {
|
|
51784
|
-
const sock = net.createConnection(endpoint);
|
|
51785
|
-
const timer = setTimeout(() => {
|
|
51786
|
-
sock.destroy();
|
|
51787
|
-
resolve(false);
|
|
51788
|
-
}, 500);
|
|
51789
|
-
timer.unref?.();
|
|
51790
|
-
sock.once("connect", () => {
|
|
51791
|
-
clearTimeout(timer);
|
|
51792
|
-
sock.destroy();
|
|
51793
|
-
resolve(true);
|
|
51794
|
-
});
|
|
51795
|
-
sock.once("error", () => {
|
|
51796
|
-
clearTimeout(timer);
|
|
51797
|
-
sock.destroy();
|
|
51798
|
-
resolve(false);
|
|
51799
|
-
});
|
|
51800
|
-
});
|
|
51801
|
-
}
|
|
51802
|
-
async function waitForShutdown(probe) {
|
|
51803
|
-
const pollIntervalMs = 250;
|
|
51804
|
-
if (!probe) {
|
|
51805
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
51806
|
-
return;
|
|
51586
|
+
// src/components/history/diff-model.ts
|
|
51587
|
+
var DIFF_MAX_LINES = 200;
|
|
51588
|
+
var MULTI_DIFF_MAX_FILES = 20;
|
|
51589
|
+
var MULTI_DIFF_MAX_ROWS = 400;
|
|
51590
|
+
var MULTI_DIFF_SUMMARY_THRESHOLD = 5;
|
|
51591
|
+
function summarizeMultiFileDiffs(items) {
|
|
51592
|
+
let added = 0;
|
|
51593
|
+
let removed = 0;
|
|
51594
|
+
let hiddenAdded = 0;
|
|
51595
|
+
let hiddenRemoved = 0;
|
|
51596
|
+
let truncatedFiles = 0;
|
|
51597
|
+
for (const item of items) {
|
|
51598
|
+
added += item.preview.added;
|
|
51599
|
+
removed += item.preview.removed;
|
|
51600
|
+
hiddenAdded += item.preview.hiddenAdded;
|
|
51601
|
+
hiddenRemoved += item.preview.hiddenRemoved;
|
|
51602
|
+
if (item.preview.hidden > 0) truncatedFiles += 1;
|
|
51807
51603
|
}
|
|
51808
|
-
const
|
|
51809
|
-
|
|
51810
|
-
|
|
51811
|
-
|
|
51812
|
-
if (!stillUp) return;
|
|
51813
|
-
} catch {
|
|
51814
|
-
return;
|
|
51815
|
-
}
|
|
51816
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
51604
|
+
const omitted = items.omitted;
|
|
51605
|
+
if (omitted) {
|
|
51606
|
+
added += omitted.added;
|
|
51607
|
+
removed += omitted.removed;
|
|
51817
51608
|
}
|
|
51609
|
+
return {
|
|
51610
|
+
fileCount: items.length + (omitted?.fileCount ?? 0),
|
|
51611
|
+
added,
|
|
51612
|
+
removed,
|
|
51613
|
+
hiddenAdded,
|
|
51614
|
+
hiddenRemoved,
|
|
51615
|
+
truncatedFiles,
|
|
51616
|
+
omittedFiles: omitted?.fileCount ?? 0
|
|
51617
|
+
};
|
|
51818
51618
|
}
|
|
51819
|
-
|
|
51820
|
-
|
|
51821
|
-
|
|
51822
|
-
|
|
51823
|
-
|
|
51824
|
-
|
|
51825
|
-
|
|
51826
|
-
|
|
51827
|
-
|
|
51828
|
-
|
|
51829
|
-
|
|
51830
|
-
|
|
51831
|
-
|
|
51832
|
-
|
|
51833
|
-
case "governance":
|
|
51834
|
-
return {
|
|
51835
|
-
serviceId: "governance",
|
|
51836
|
-
action,
|
|
51837
|
-
success: false,
|
|
51838
|
-
message: "Governance control plane is read-only; daemon restart is not supported."
|
|
51839
|
-
};
|
|
51840
|
-
default:
|
|
51841
|
-
return {
|
|
51842
|
-
serviceId,
|
|
51843
|
-
action,
|
|
51844
|
-
success: false,
|
|
51845
|
-
message: `Unknown service: ${serviceId}`
|
|
51846
|
-
};
|
|
51619
|
+
function formatMultiDiffSummary(summary, threshold = MULTI_DIFF_SUMMARY_THRESHOLD) {
|
|
51620
|
+
if (threshold === 0) return null;
|
|
51621
|
+
const effectiveThreshold = threshold < 0 ? MULTI_DIFF_SUMMARY_THRESHOLD : threshold;
|
|
51622
|
+
if (summary.fileCount < effectiveThreshold) return null;
|
|
51623
|
+
const parts = [`${summary.fileCount} files`];
|
|
51624
|
+
if (summary.added > 0) parts.push(`+${summary.added}`);
|
|
51625
|
+
if (summary.removed > 0) parts.push(`-${summary.removed}`);
|
|
51626
|
+
if (summary.hiddenAdded > 0 || summary.hiddenRemoved > 0) {
|
|
51627
|
+
const hiddenParts = [];
|
|
51628
|
+
if (summary.hiddenAdded > 0) hiddenParts.push(`+${summary.hiddenAdded}`);
|
|
51629
|
+
if (summary.hiddenRemoved > 0) hiddenParts.push(`-${summary.hiddenRemoved}`);
|
|
51630
|
+
parts.push(
|
|
51631
|
+
`\u2026 ${hiddenParts.join(" ")} hidden across ${summary.truncatedFiles} file${summary.truncatedFiles === 1 ? "" : "s"}`
|
|
51632
|
+
);
|
|
51847
51633
|
}
|
|
51848
|
-
|
|
51849
|
-
|
|
51850
|
-
|
|
51851
|
-
const client = new SessionCatalogProjectClient({
|
|
51852
|
-
projectDir: paths.projectDir,
|
|
51853
|
-
projectRoot
|
|
51854
|
-
});
|
|
51855
|
-
try {
|
|
51856
|
-
const previousPid = action === "restart" ? await client.callExisting("ping", {}, { timeoutMs: 1e3 }).then(
|
|
51857
|
-
(health2) => health2.pid,
|
|
51858
|
-
() => void 0
|
|
51859
|
-
) : void 0;
|
|
51860
|
-
const result = await client.shutdown(`TUI request: ${action}`);
|
|
51861
|
-
if (!result.stopped && action === "shutdown") {
|
|
51862
|
-
return {
|
|
51863
|
-
serviceId: "session-catalog",
|
|
51864
|
-
action,
|
|
51865
|
-
success: false,
|
|
51866
|
-
message: "Session Catalog IPC daemon is not running"
|
|
51867
|
-
};
|
|
51868
|
-
}
|
|
51869
|
-
if (action === "restart") return await restartSessionCatalogServer(projectRoot, previousPid);
|
|
51870
|
-
return {
|
|
51871
|
-
serviceId: "session-catalog",
|
|
51872
|
-
action,
|
|
51873
|
-
success: true,
|
|
51874
|
-
message: "Session Catalog IPC daemon shutdown requested"
|
|
51875
|
-
};
|
|
51876
|
-
} catch (error) {
|
|
51877
|
-
return {
|
|
51878
|
-
serviceId: "session-catalog",
|
|
51879
|
-
action,
|
|
51880
|
-
success: false,
|
|
51881
|
-
message: toErrorMessage(error)
|
|
51882
|
-
};
|
|
51883
|
-
} finally {
|
|
51884
|
-
await client.close().catch(() => void 0);
|
|
51634
|
+
const omittedFiles = summary.omittedFiles ?? 0;
|
|
51635
|
+
if (omittedFiles > 0) {
|
|
51636
|
+
parts.push(`${omittedFiles} more file${omittedFiles === 1 ? "" : "s"} not rendered`);
|
|
51885
51637
|
}
|
|
51638
|
+
return parts.join(" \xB7 ");
|
|
51886
51639
|
}
|
|
51887
|
-
|
|
51888
|
-
const
|
|
51889
|
-
|
|
51890
|
-
|
|
51891
|
-
|
|
51892
|
-
|
|
51893
|
-
|
|
51894
|
-
|
|
51895
|
-
|
|
51896
|
-
|
|
51897
|
-
|
|
51898
|
-
|
|
51899
|
-
|
|
51900
|
-
const
|
|
51901
|
-
|
|
51902
|
-
|
|
51903
|
-
|
|
51904
|
-
|
|
51905
|
-
|
|
51906
|
-
|
|
51907
|
-
|
|
51908
|
-
|
|
51909
|
-
|
|
51910
|
-
|
|
51911
|
-
|
|
51912
|
-
|
|
51640
|
+
function formatDiffStats(added, removed) {
|
|
51641
|
+
const parts = [];
|
|
51642
|
+
if (added > 0) parts.push(`added ${added} line${added === 1 ? "" : "s"}`);
|
|
51643
|
+
if (removed > 0) parts.push(`removed ${removed} line${removed === 1 ? "" : "s"}`);
|
|
51644
|
+
if (parts.length === 0) return null;
|
|
51645
|
+
const joined = parts.join(", ");
|
|
51646
|
+
return joined.charAt(0).toUpperCase() + joined.slice(1);
|
|
51647
|
+
}
|
|
51648
|
+
function parseUnifiedDiff(diff2, maxLines) {
|
|
51649
|
+
return parseUnifiedDiffPreview(diff2, maxLines);
|
|
51650
|
+
}
|
|
51651
|
+
function extractDiffPreview(toolName, output, input) {
|
|
51652
|
+
if (!output) return void 0;
|
|
51653
|
+
const text = output.trim();
|
|
51654
|
+
if (!text) return void 0;
|
|
51655
|
+
let diff2;
|
|
51656
|
+
if (toolName === "edit" || toolName === "diff" || toolName === "write") {
|
|
51657
|
+
const parsed = tryParseJson(text);
|
|
51658
|
+
if (parsed && typeof parsed === "object") {
|
|
51659
|
+
const obj = parsed;
|
|
51660
|
+
diff2 = toolName === "write" && obj["created"] === true ? newFileDiffFromWriteInput(obj, input) ?? stringOf(obj["diff"]) : stringOf(obj["diff"]);
|
|
51661
|
+
} else {
|
|
51662
|
+
diff2 = extractUnifiedDiffText(text);
|
|
51663
|
+
}
|
|
51664
|
+
} else if (toolName === "patch") {
|
|
51665
|
+
const parsed = tryParseJson(text);
|
|
51666
|
+
if (parsed && typeof parsed === "object") {
|
|
51667
|
+
diff2 = stringOf(parsed["diff"]) ?? stringOf(parsed["stdout"]);
|
|
51668
|
+
} else if (text.includes("@@") || text.startsWith("---")) {
|
|
51669
|
+
diff2 = text;
|
|
51670
|
+
}
|
|
51671
|
+
} else if (toolName === "replace") {
|
|
51672
|
+
const parsed = tryParseJson(text);
|
|
51673
|
+
if (parsed && typeof parsed === "object") {
|
|
51674
|
+
diff2 = joinReplaceDiffs(parsed);
|
|
51913
51675
|
}
|
|
51914
|
-
return {
|
|
51915
|
-
serviceId: "session-catalog",
|
|
51916
|
-
action: "restart",
|
|
51917
|
-
success: true,
|
|
51918
|
-
message: "Session Catalog IPC daemon restarted successfully"
|
|
51919
|
-
};
|
|
51920
|
-
} catch (error) {
|
|
51921
|
-
return {
|
|
51922
|
-
serviceId: "session-catalog",
|
|
51923
|
-
action: "restart",
|
|
51924
|
-
success: false,
|
|
51925
|
-
message: `Session Catalog IPC daemon restarted but verification failed: ${toErrorMessage(error)}`
|
|
51926
|
-
};
|
|
51927
|
-
} finally {
|
|
51928
|
-
await verify.close().catch(() => void 0);
|
|
51929
51676
|
}
|
|
51677
|
+
if (!diff2?.trim() || diff2.startsWith("(no-op")) return void 0;
|
|
51678
|
+
const preview = parseUnifiedDiff(diff2, DIFF_MAX_LINES);
|
|
51679
|
+
return preview.rows.length > 0 ? preview : void 0;
|
|
51930
51680
|
}
|
|
51931
|
-
|
|
51932
|
-
if (
|
|
51933
|
-
|
|
51934
|
-
|
|
51935
|
-
|
|
51936
|
-
|
|
51937
|
-
|
|
51938
|
-
|
|
51939
|
-
|
|
51940
|
-
|
|
51941
|
-
|
|
51942
|
-
|
|
51943
|
-
|
|
51944
|
-
|
|
51945
|
-
|
|
51946
|
-
|
|
51947
|
-
success: false,
|
|
51948
|
-
message: toErrorMessage(error)
|
|
51949
|
-
};
|
|
51950
|
-
}
|
|
51951
|
-
if (!connection) {
|
|
51952
|
-
return {
|
|
51953
|
-
serviceId: "kanban",
|
|
51954
|
-
action,
|
|
51955
|
-
success: false,
|
|
51956
|
-
message: "Kanban IPC daemon is not running"
|
|
51957
|
-
};
|
|
51681
|
+
function extractMultiFileDiffs(toolName, output, input) {
|
|
51682
|
+
if (!output) return void 0;
|
|
51683
|
+
const items = collectMultiFileDiffItems(toolName, output, input);
|
|
51684
|
+
if (items === void 0) return void 0;
|
|
51685
|
+
if (items.length === 0) return void 0;
|
|
51686
|
+
const previews = [];
|
|
51687
|
+
const candidateItems = items.slice(0, MULTI_DIFF_MAX_FILES);
|
|
51688
|
+
let remainingRows = MULTI_DIFF_MAX_ROWS;
|
|
51689
|
+
let visited = 0;
|
|
51690
|
+
for (const item of candidateItems) {
|
|
51691
|
+
if (remainingRows <= 0) break;
|
|
51692
|
+
visited++;
|
|
51693
|
+
const preview = parseUnifiedDiff(item.diff, Math.min(DIFF_MAX_LINES, remainingRows));
|
|
51694
|
+
if (preview.rows.length === 0) continue;
|
|
51695
|
+
previews.push({ path: item.path ?? "unknown file", preview });
|
|
51696
|
+
remainingRows -= preview.rows.length;
|
|
51958
51697
|
}
|
|
51959
|
-
|
|
51960
|
-
|
|
51961
|
-
|
|
51962
|
-
|
|
51963
|
-
|
|
51964
|
-
|
|
51965
|
-
|
|
51966
|
-
|
|
51967
|
-
success: false,
|
|
51968
|
-
message: "Kanban IPC daemon shutdown failed (not confirmed)"
|
|
51969
|
-
};
|
|
51970
|
-
}
|
|
51971
|
-
if (action === "restart") {
|
|
51972
|
-
closeKanbanServerConnections();
|
|
51973
|
-
return await restartKanbanServer(projectRoot);
|
|
51698
|
+
const omittedItems = items.slice(visited);
|
|
51699
|
+
if (omittedItems.length > 0) {
|
|
51700
|
+
let added = 0;
|
|
51701
|
+
let removed = 0;
|
|
51702
|
+
for (const item of omittedItems) {
|
|
51703
|
+
const summary = countUnifiedDiffChanges(item.diff);
|
|
51704
|
+
added += summary.added;
|
|
51705
|
+
removed += summary.removed;
|
|
51974
51706
|
}
|
|
51975
|
-
|
|
51976
|
-
serviceId: "kanban",
|
|
51977
|
-
action,
|
|
51978
|
-
success: true,
|
|
51979
|
-
message: "Kanban IPC daemon shutdown requested"
|
|
51980
|
-
};
|
|
51981
|
-
} catch (error) {
|
|
51982
|
-
return {
|
|
51983
|
-
serviceId: "kanban",
|
|
51984
|
-
action,
|
|
51985
|
-
success: false,
|
|
51986
|
-
message: toErrorMessage(error)
|
|
51987
|
-
};
|
|
51707
|
+
previews.omitted = { fileCount: omittedItems.length, added, removed };
|
|
51988
51708
|
}
|
|
51709
|
+
return previews.length > 0 ? previews : void 0;
|
|
51989
51710
|
}
|
|
51990
|
-
|
|
51991
|
-
|
|
51992
|
-
|
|
51993
|
-
|
|
51994
|
-
|
|
51995
|
-
|
|
51996
|
-
|
|
51997
|
-
|
|
51998
|
-
|
|
51999
|
-
|
|
52000
|
-
|
|
51711
|
+
|
|
51712
|
+
// src/components/history/code-block.tsx
|
|
51713
|
+
var import_jsx_runtime49 = __toESM(require_jsx_runtime(), 1);
|
|
51714
|
+
var MAX_CODE_LINES = 80;
|
|
51715
|
+
var DIFF_FALLBACK_WRAP_WIDTH = 100;
|
|
51716
|
+
var HARD_TAB_WIDTH = 8;
|
|
51717
|
+
function expandTabs(text, tabWidth = HARD_TAB_WIDTH) {
|
|
51718
|
+
if (!text.includes(" ")) return text;
|
|
51719
|
+
let out = "";
|
|
51720
|
+
let col = 0;
|
|
51721
|
+
for (const ch of text) {
|
|
51722
|
+
if (ch === " ") {
|
|
51723
|
+
const advance = tabWidth - col % tabWidth;
|
|
51724
|
+
out += " ".repeat(advance);
|
|
51725
|
+
col += advance;
|
|
51726
|
+
} else {
|
|
51727
|
+
out += ch;
|
|
51728
|
+
col += 1;
|
|
52001
51729
|
}
|
|
52002
|
-
await connection.request("ping", {}, { timeoutMs: 1e4 });
|
|
52003
|
-
return {
|
|
52004
|
-
serviceId: "kanban",
|
|
52005
|
-
action: "restart",
|
|
52006
|
-
success: true,
|
|
52007
|
-
message: "Kanban IPC daemon restarted successfully"
|
|
52008
|
-
};
|
|
52009
|
-
} catch (error) {
|
|
52010
|
-
return {
|
|
52011
|
-
serviceId: "kanban",
|
|
52012
|
-
action: "restart",
|
|
52013
|
-
success: false,
|
|
52014
|
-
message: `Kanban IPC daemon restarted but verification failed: ${toErrorMessage(error)}`
|
|
52015
|
-
};
|
|
52016
51730
|
}
|
|
51731
|
+
return out;
|
|
52017
51732
|
}
|
|
52018
|
-
|
|
52019
|
-
|
|
52020
|
-
|
|
52021
|
-
|
|
52022
|
-
|
|
52023
|
-
|
|
52024
|
-
|
|
52025
|
-
|
|
52026
|
-
|
|
52027
|
-
const
|
|
52028
|
-
|
|
52029
|
-
|
|
52030
|
-
|
|
52031
|
-
|
|
52032
|
-
|
|
51733
|
+
function CodeBlockImpl({
|
|
51734
|
+
code,
|
|
51735
|
+
lang,
|
|
51736
|
+
contentWidth
|
|
51737
|
+
}) {
|
|
51738
|
+
useActiveTheme();
|
|
51739
|
+
let lines = sanitizeTerminalText(code, HARD_TAB_WIDTH).replace(/\n+$/, "").split("\n");
|
|
51740
|
+
const hidden = Math.max(0, lines.length - MAX_CODE_LINES);
|
|
51741
|
+
if (hidden > 0) lines = lines.slice(0, MAX_CODE_LINES);
|
|
51742
|
+
const gutterW = String(lines.length).length;
|
|
51743
|
+
const maxW = Math.max(1, Math.min(contentWidth - 4 - gutterW - 1, 120));
|
|
51744
|
+
let carry = {};
|
|
51745
|
+
const rows = lines.map((raw) => {
|
|
51746
|
+
const expanded = expandTabs(raw);
|
|
51747
|
+
const display = truncateDisplay(expanded, maxW);
|
|
51748
|
+
const r = highlightLine(display, lang, carry);
|
|
51749
|
+
carry = r.carry;
|
|
51750
|
+
return r.tokens;
|
|
51751
|
+
});
|
|
51752
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(HistoryRail, { color: theme.borderDefault, children: [
|
|
51753
|
+
lang !== "plain" ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: lang }) : null,
|
|
51754
|
+
rows.map((tokens, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Text2, { children: [
|
|
51755
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: `${String(i + 1).padStart(gutterW, " ")} ` }),
|
|
51756
|
+
tokens.length === 0 ? " " : tokens.map((t, j) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
51757
|
+
Text2,
|
|
51758
|
+
{
|
|
51759
|
+
dimColor: Boolean(t.dim),
|
|
51760
|
+
bold: Boolean(t.bold),
|
|
51761
|
+
...t.color ? { color: t.color } : {},
|
|
51762
|
+
children: t.text
|
|
51763
|
+
},
|
|
51764
|
+
j
|
|
51765
|
+
))
|
|
51766
|
+
] }, i)),
|
|
51767
|
+
hidden > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, italic: true, children: `\u2026 +${hidden} more line${hidden === 1 ? "" : "s"}` }) : null
|
|
51768
|
+
] });
|
|
51769
|
+
}
|
|
51770
|
+
function DiffFileBlock({
|
|
51771
|
+
path: path13,
|
|
51772
|
+
preview,
|
|
51773
|
+
useColor = true,
|
|
51774
|
+
contentWidth
|
|
51775
|
+
}) {
|
|
51776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Box2, { flexDirection: "column", marginTop: 1, children: [
|
|
51777
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Box2, { flexDirection: "row", marginBottom: 0, children: [
|
|
51778
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { bold: true, color: theme.accent, children: `\u25B8 ${path13}` }),
|
|
51779
|
+
preview.added > 0 || preview.removed > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: ` (${preview.added > 0 ? `+${preview.added}` : ""}${preview.added > 0 && preview.removed > 0 ? " " : ""}${preview.removed > 0 ? `-${preview.removed}` : ""})` }) : null
|
|
51780
|
+
] }),
|
|
51781
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
51782
|
+
DiffBlock,
|
|
51783
|
+
{
|
|
51784
|
+
rows: preview.rows,
|
|
51785
|
+
hidden: preview.hidden,
|
|
51786
|
+
added: preview.added,
|
|
51787
|
+
removed: preview.removed,
|
|
51788
|
+
hiddenAdded: preview.hiddenAdded,
|
|
51789
|
+
hiddenRemoved: preview.hiddenRemoved,
|
|
51790
|
+
useColor,
|
|
51791
|
+
lang: langFromPath(path13),
|
|
51792
|
+
showStats: false,
|
|
51793
|
+
contentWidth
|
|
52033
51794
|
}
|
|
52034
|
-
|
|
52035
|
-
|
|
52036
|
-
action,
|
|
52037
|
-
success: false,
|
|
52038
|
-
message: `SAGE memory server shutdown failed: ${result.reason ?? "unknown"}`
|
|
52039
|
-
};
|
|
52040
|
-
}
|
|
52041
|
-
if (action === "restart") {
|
|
52042
|
-
return await restartSageServer(projectRoot);
|
|
52043
|
-
}
|
|
52044
|
-
return {
|
|
52045
|
-
serviceId: "sage",
|
|
52046
|
-
action,
|
|
52047
|
-
success: true,
|
|
52048
|
-
message: "SAGE memory server shutdown requested"
|
|
52049
|
-
};
|
|
52050
|
-
} catch (error) {
|
|
52051
|
-
return {
|
|
52052
|
-
serviceId: "sage",
|
|
52053
|
-
action,
|
|
52054
|
-
success: false,
|
|
52055
|
-
message: toErrorMessage(error)
|
|
52056
|
-
};
|
|
52057
|
-
} finally {
|
|
52058
|
-
connection.close();
|
|
52059
|
-
}
|
|
51795
|
+
)
|
|
51796
|
+
] });
|
|
52060
51797
|
}
|
|
52061
|
-
|
|
52062
|
-
|
|
52063
|
-
|
|
52064
|
-
|
|
52065
|
-
|
|
52066
|
-
} finally {
|
|
52067
|
-
probe.close();
|
|
52068
|
-
}
|
|
51798
|
+
function applyWashTokens(tokens, onWash) {
|
|
51799
|
+
if (!onWash) return tokens;
|
|
51800
|
+
return tokens.map((t) => {
|
|
51801
|
+
if (t.color !== "syntax.comment") return t;
|
|
51802
|
+
return { ...t, color: "syntax.commentOnWash", dim: false };
|
|
52069
51803
|
});
|
|
52070
|
-
const verifyConn = new SageProjectServerConnection(projectRoot);
|
|
52071
|
-
try {
|
|
52072
|
-
await verifyConn.call(
|
|
52073
|
-
"ping",
|
|
52074
|
-
{},
|
|
52075
|
-
{ timeoutMs: 1e4, meta: { clientId: `sage-restart-${process.pid}` } }
|
|
52076
|
-
);
|
|
52077
|
-
return {
|
|
52078
|
-
serviceId: "sage",
|
|
52079
|
-
action: "restart",
|
|
52080
|
-
success: true,
|
|
52081
|
-
message: "SAGE memory server restarted successfully"
|
|
52082
|
-
};
|
|
52083
|
-
} catch (error) {
|
|
52084
|
-
return {
|
|
52085
|
-
serviceId: "sage",
|
|
52086
|
-
action: "restart",
|
|
52087
|
-
success: false,
|
|
52088
|
-
message: `SAGE memory server restarted but verification failed: ${toErrorMessage(error)}`
|
|
52089
|
-
};
|
|
52090
|
-
} finally {
|
|
52091
|
-
verifyConn.close();
|
|
52092
|
-
}
|
|
52093
51804
|
}
|
|
52094
|
-
|
|
52095
|
-
const
|
|
52096
|
-
|
|
52097
|
-
|
|
52098
|
-
|
|
52099
|
-
|
|
52100
|
-
|
|
52101
|
-
|
|
51805
|
+
function renderTokens(tokens, onWash = false) {
|
|
51806
|
+
const effective = applyWashTokens(tokens, onWash);
|
|
51807
|
+
if (effective.length === 0) return " ";
|
|
51808
|
+
return effective.map((t, j) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
51809
|
+
Text2,
|
|
51810
|
+
{
|
|
51811
|
+
dimColor: Boolean(t.dim),
|
|
51812
|
+
bold: Boolean(t.bold),
|
|
51813
|
+
...t.color ? { color: t.color } : {},
|
|
51814
|
+
children: t.text
|
|
51815
|
+
},
|
|
51816
|
+
j
|
|
51817
|
+
));
|
|
51818
|
+
}
|
|
51819
|
+
function wrapTokens(tokens, width) {
|
|
51820
|
+
if (width <= 0) return [tokens];
|
|
51821
|
+
const segments = [];
|
|
51822
|
+
let current = [];
|
|
51823
|
+
let currentWidth = 0;
|
|
51824
|
+
for (const t of tokens) {
|
|
51825
|
+
let text = t.text;
|
|
51826
|
+
while (text.length > 0) {
|
|
51827
|
+
const room = width - currentWidth;
|
|
51828
|
+
if (room <= 0) {
|
|
51829
|
+
segments.push(current);
|
|
51830
|
+
current = [];
|
|
51831
|
+
currentWidth = 0;
|
|
51832
|
+
continue;
|
|
52102
51833
|
}
|
|
52103
|
-
|
|
52104
|
-
|
|
52105
|
-
|
|
52106
|
-
|
|
52107
|
-
|
|
52108
|
-
|
|
52109
|
-
|
|
52110
|
-
|
|
52111
|
-
|
|
51834
|
+
const [piece, rest] = splitDisplay(text, room);
|
|
51835
|
+
if (!piece) {
|
|
51836
|
+
segments.push(current);
|
|
51837
|
+
current = [];
|
|
51838
|
+
currentWidth = 0;
|
|
51839
|
+
continue;
|
|
51840
|
+
}
|
|
51841
|
+
current.push({ ...t, text: piece });
|
|
51842
|
+
currentWidth += displayWidth(piece);
|
|
51843
|
+
text = rest;
|
|
52112
51844
|
}
|
|
52113
|
-
return {
|
|
52114
|
-
serviceId: "chronicle",
|
|
52115
|
-
action,
|
|
52116
|
-
success: true,
|
|
52117
|
-
message: "Chronicle telemetry server shutdown requested"
|
|
52118
|
-
};
|
|
52119
|
-
} catch (error) {
|
|
52120
|
-
return {
|
|
52121
|
-
serviceId: "chronicle",
|
|
52122
|
-
action,
|
|
52123
|
-
success: false,
|
|
52124
|
-
message: toErrorMessage(error)
|
|
52125
|
-
};
|
|
52126
|
-
} finally {
|
|
52127
|
-
client.close();
|
|
52128
51845
|
}
|
|
51846
|
+
if (current.length > 0 || segments.length === 0) segments.push(current);
|
|
51847
|
+
return segments;
|
|
52129
51848
|
}
|
|
52130
|
-
|
|
52131
|
-
|
|
52132
|
-
|
|
52133
|
-
|
|
52134
|
-
|
|
52135
|
-
|
|
52136
|
-
|
|
52137
|
-
|
|
52138
|
-
|
|
52139
|
-
|
|
52140
|
-
|
|
52141
|
-
|
|
52142
|
-
|
|
52143
|
-
|
|
52144
|
-
|
|
52145
|
-
|
|
52146
|
-
|
|
52147
|
-
serviceId: "chronicle",
|
|
52148
|
-
action: "restart",
|
|
52149
|
-
success: true,
|
|
52150
|
-
message: "Chronicle telemetry server restarted successfully"
|
|
52151
|
-
};
|
|
52152
|
-
} catch (error) {
|
|
52153
|
-
return {
|
|
52154
|
-
serviceId: "chronicle",
|
|
52155
|
-
action: "restart",
|
|
52156
|
-
success: false,
|
|
52157
|
-
message: `Chronicle telemetry server restarted but verification failed: ${toErrorMessage(error)}`
|
|
52158
|
-
};
|
|
52159
|
-
} finally {
|
|
52160
|
-
await access?.close();
|
|
51849
|
+
function DiffBlock({
|
|
51850
|
+
rows,
|
|
51851
|
+
hidden,
|
|
51852
|
+
added = 0,
|
|
51853
|
+
removed = 0,
|
|
51854
|
+
hiddenAdded = 0,
|
|
51855
|
+
hiddenRemoved = 0,
|
|
51856
|
+
useColor = true,
|
|
51857
|
+
lang = "plain",
|
|
51858
|
+
showStats = true,
|
|
51859
|
+
contentWidth
|
|
51860
|
+
}) {
|
|
51861
|
+
const lineNoOf = (row) => row.kind === "del" ? row.oldLine : row.newLine ?? row.oldLine;
|
|
51862
|
+
let gutterWidth = 1;
|
|
51863
|
+
for (const r of rows) {
|
|
51864
|
+
const n = lineNoOf(r);
|
|
51865
|
+
if (typeof n === "number" && String(n).length > gutterWidth) gutterWidth = String(n).length;
|
|
52161
51866
|
}
|
|
52162
|
-
|
|
52163
|
-
|
|
52164
|
-
|
|
52165
|
-
|
|
52166
|
-
|
|
52167
|
-
|
|
52168
|
-
|
|
52169
|
-
)
|
|
52170
|
-
|
|
52171
|
-
if (action === "restart" && result.reason === "not-running") {
|
|
52172
|
-
return await restartCodebaseIndexServer(projectRoot, indexDir);
|
|
52173
|
-
}
|
|
52174
|
-
return {
|
|
52175
|
-
serviceId: "codebase-index",
|
|
52176
|
-
action,
|
|
52177
|
-
success: false,
|
|
52178
|
-
message: `Codebase index server shutdown failed: ${result.reason ?? "unknown"}`
|
|
52179
|
-
};
|
|
52180
|
-
}
|
|
52181
|
-
if (action === "restart") {
|
|
52182
|
-
return await restartCodebaseIndexServer(projectRoot, indexDir);
|
|
51867
|
+
const blank = " ".repeat(gutterWidth);
|
|
51868
|
+
const markerFor = (kind) => {
|
|
51869
|
+
if (kind === "add") return "+";
|
|
51870
|
+
if (kind === "del") return "-";
|
|
51871
|
+
return " ";
|
|
51872
|
+
};
|
|
51873
|
+
const textForDisplay = (row) => {
|
|
51874
|
+
if ((row.kind === "add" || row.kind === "del" || row.kind === "ctx") && row.text.length > 0) {
|
|
51875
|
+
return sanitizeTerminalText(expandTabs(row.text.slice(1)), HARD_TAB_WIDTH) || " ";
|
|
52183
51876
|
}
|
|
52184
|
-
return
|
|
52185
|
-
|
|
52186
|
-
|
|
52187
|
-
|
|
52188
|
-
|
|
52189
|
-
|
|
52190
|
-
|
|
52191
|
-
return
|
|
52192
|
-
|
|
52193
|
-
|
|
52194
|
-
|
|
52195
|
-
|
|
52196
|
-
|
|
52197
|
-
}
|
|
51877
|
+
return sanitizeTerminalText(expandTabs(row.text), HARD_TAB_WIDTH) || " ";
|
|
51878
|
+
};
|
|
51879
|
+
const stats = showStats ? formatDiffStats(added, removed) : null;
|
|
51880
|
+
const terminalWrapGuard = typeof contentWidth === "number" ? 1 : 0;
|
|
51881
|
+
const bodyBudget = typeof contentWidth === "number" ? Math.max(1, contentWidth - (2 + 3 + gutterWidth + 3 + terminalWrapGuard)) : DIFF_FALLBACK_WRAP_WIDTH;
|
|
51882
|
+
const hasWidth = typeof contentWidth === "number";
|
|
51883
|
+
const padBody = (seg) => {
|
|
51884
|
+
if (!hasWidth) return 0;
|
|
51885
|
+
const len = seg.reduce((n, t) => n + displayWidth(t.text), 0);
|
|
51886
|
+
return Math.max(0, bodyBudget - len);
|
|
51887
|
+
};
|
|
51888
|
+
const contPrefix = ` ${blank} `;
|
|
51889
|
+
const hiddenStats = [];
|
|
51890
|
+
if (hiddenAdded > 0) hiddenStats.push(`+${hiddenAdded}`);
|
|
51891
|
+
if (hiddenRemoved > 0) hiddenStats.push(`-${hiddenRemoved}`);
|
|
51892
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Box2, { flexDirection: "column", marginLeft: 2, marginTop: 0, children: [
|
|
51893
|
+
stats ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Text2, { children: [
|
|
51894
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: "\u23BF " }),
|
|
51895
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { children: stats })
|
|
51896
|
+
] }) : null,
|
|
51897
|
+
rows.map((row, i) => {
|
|
51898
|
+
const key2 = i;
|
|
51899
|
+
if (row.kind === "hunk") {
|
|
51900
|
+
if (i === 0) return null;
|
|
51901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: ` ${blank} \u22EF` }, key2);
|
|
51902
|
+
}
|
|
51903
|
+
if (row.kind === "meta") {
|
|
51904
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: ` ${blank} ${sanitizeTerminalText(row.text)}` }, key2);
|
|
51905
|
+
}
|
|
51906
|
+
const n = lineNoOf(row);
|
|
51907
|
+
const ln = typeof n === "number" ? String(n).padStart(gutterWidth, " ") : blank;
|
|
51908
|
+
const body = textForDisplay(row);
|
|
51909
|
+
const tokens = highlightLine(body, lang).tokens;
|
|
51910
|
+
const segments = wrapTokens(tokens, bodyBudget);
|
|
51911
|
+
if (row.kind === "ctx") {
|
|
51912
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Box2, { flexDirection: "column", children: segments.map((seg, si) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Text2, { children: [
|
|
51913
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: si === 0 ? ` ${ln} ` : contPrefix }),
|
|
51914
|
+
renderTokens(seg)
|
|
51915
|
+
] }, si)) }, key2);
|
|
51916
|
+
}
|
|
51917
|
+
const marker = markerFor(row.kind);
|
|
51918
|
+
const markerColor = row.kind === "add" ? theme.success : theme.error;
|
|
51919
|
+
if (useColor) {
|
|
51920
|
+
const bg = row.kind === "add" ? theme.diffAddBg : theme.diffDelBg;
|
|
51921
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Box2, { flexDirection: "column", children: segments.map((seg, si) => {
|
|
51922
|
+
const pad = padBody(seg);
|
|
51923
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Text2, { backgroundColor: bg, children: [
|
|
51924
|
+
si === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
|
|
51925
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: ` ${ln} ` }),
|
|
51926
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { color: markerColor, bold: true, children: marker }),
|
|
51927
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { children: " " })
|
|
51928
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: contPrefix }),
|
|
51929
|
+
renderTokens(seg, true),
|
|
51930
|
+
pad > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { children: " ".repeat(pad) }) : null
|
|
51931
|
+
] }, si);
|
|
51932
|
+
}) }, key2);
|
|
51933
|
+
}
|
|
51934
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Box2, { flexDirection: "column", children: segments.map((seg, si) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(Text2, { children: [
|
|
51935
|
+
si === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
|
|
51936
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: ` ${ln} ` }),
|
|
51937
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { color: markerColor, bold: true, children: marker }),
|
|
51938
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { children: " " })
|
|
51939
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, children: contPrefix }),
|
|
51940
|
+
renderTokens(seg)
|
|
51941
|
+
] }, si)) }, key2);
|
|
51942
|
+
}),
|
|
51943
|
+
hidden > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Text2, { dimColor: true, italic: true, children: ` ${blank} \u2026 ${hidden} more line${hidden === 1 ? "" : "s"}${hiddenStats.length > 0 ? ` (${hiddenStats.join(" ")} hidden)` : ""}` }) : null
|
|
51944
|
+
] });
|
|
51945
|
+
}
|
|
51946
|
+
var CodeBlock = (0, import_react62.memo)(CodeBlockImpl);
|
|
51947
|
+
|
|
51948
|
+
// src/components/confirm-prompt.tsx
|
|
51949
|
+
var import_jsx_runtime50 = __toESM(require_jsx_runtime(), 1);
|
|
51950
|
+
var BUTTON_COLOR = {
|
|
51951
|
+
yes: "green",
|
|
51952
|
+
no: "red",
|
|
51953
|
+
always: "cyan",
|
|
51954
|
+
"always-exact": "cyan",
|
|
51955
|
+
"always-command": "cyan",
|
|
51956
|
+
"always-tool": "yellow",
|
|
51957
|
+
deny: "red"
|
|
51958
|
+
};
|
|
51959
|
+
function buttonLabels(_suggestedPattern, toolName = "exec") {
|
|
51960
|
+
return [
|
|
51961
|
+
{ decision: "yes", bracket: "[y]", rest: "es " },
|
|
51962
|
+
{ decision: "no", bracket: "[n]", rest: "o " },
|
|
51963
|
+
{ decision: "always-exact", bracket: "[a]", rest: " same args " },
|
|
51964
|
+
...toolName === "exec" ? [{ decision: "always-command", bracket: "[c]", rest: " command " }] : [],
|
|
51965
|
+
{ decision: "always-tool", bracket: "[t]", rest: " tool " },
|
|
51966
|
+
{ decision: "deny", bracket: "[d]", rest: "eny" }
|
|
51967
|
+
];
|
|
52198
51968
|
}
|
|
52199
|
-
|
|
52200
|
-
|
|
52201
|
-
|
|
52202
|
-
|
|
52203
|
-
|
|
52204
|
-
|
|
52205
|
-
|
|
52206
|
-
|
|
52207
|
-
|
|
52208
|
-
|
|
52209
|
-
|
|
52210
|
-
|
|
52211
|
-
|
|
52212
|
-
|
|
52213
|
-
|
|
52214
|
-
|
|
52215
|
-
|
|
52216
|
-
|
|
52217
|
-
|
|
52218
|
-
|
|
52219
|
-
|
|
52220
|
-
message: "Codebase index server restarted but is unresponsive"
|
|
52221
|
-
};
|
|
52222
|
-
}
|
|
52223
|
-
return {
|
|
52224
|
-
serviceId: "codebase-index",
|
|
52225
|
-
action: "restart",
|
|
52226
|
-
success: true,
|
|
52227
|
-
message: "Codebase index server restarted successfully"
|
|
52228
|
-
};
|
|
52229
|
-
} catch (error) {
|
|
52230
|
-
return {
|
|
52231
|
-
serviceId: "codebase-index",
|
|
52232
|
-
action: "restart",
|
|
52233
|
-
success: false,
|
|
52234
|
-
message: `Codebase index server restarted but verification failed: ${toErrorMessage(error)}`
|
|
52235
|
-
};
|
|
51969
|
+
function stringifyInput(input) {
|
|
51970
|
+
if (!input || typeof input !== "object") return "";
|
|
51971
|
+
const obj = input;
|
|
51972
|
+
return Object.entries(obj).filter(([k]) => k !== "content" && k !== "new_string" && k !== "diff").map(([k, v]) => `${k}: ${truncate(JSON.stringify(v), 80)}`).join(" ");
|
|
51973
|
+
}
|
|
51974
|
+
function truncate(s2, max) {
|
|
51975
|
+
return s2.length <= max ? s2 : `${s2.slice(0, max - 1)}\u2026`;
|
|
51976
|
+
}
|
|
51977
|
+
function payloadDiff(input) {
|
|
51978
|
+
if (!input || typeof input !== "object") return "";
|
|
51979
|
+
const obj = input;
|
|
51980
|
+
const filePath = typeof obj["path"] === "string" ? obj["path"] : "file";
|
|
51981
|
+
if (typeof obj["diff"] === "string" && obj["diff"]) return obj["diff"];
|
|
51982
|
+
const newString = obj["new_string"];
|
|
51983
|
+
if (typeof newString === "string") {
|
|
51984
|
+
const oldString = typeof obj["old_string"] === "string" ? obj["old_string"] : "";
|
|
51985
|
+
return unifiedDiff(oldString, newString, { fromFile: filePath, toFile: filePath, context: 2 });
|
|
51986
|
+
}
|
|
51987
|
+
const content = obj["content"];
|
|
51988
|
+
if (typeof content === "string" && content) {
|
|
51989
|
+
return unifiedDiff("", content, { fromFile: "/dev/null", toFile: filePath, context: 0 });
|
|
52236
51990
|
}
|
|
51991
|
+
return "";
|
|
52237
51992
|
}
|
|
52238
|
-
|
|
52239
|
-
|
|
52240
|
-
|
|
52241
|
-
|
|
52242
|
-
|
|
52243
|
-
|
|
52244
|
-
|
|
52245
|
-
|
|
51993
|
+
var CONFIRM_DIFF_MAX_LINES = 20;
|
|
51994
|
+
function renderDiffLine(line) {
|
|
51995
|
+
const prefix = line.startsWith("+") ? "green" : line.startsWith("-") ? "red" : line.startsWith("@@") ? "cyan" : void 0;
|
|
51996
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { ...prefix ? { color: prefix } : {}, children: [
|
|
51997
|
+
line,
|
|
51998
|
+
"\n"
|
|
51999
|
+
] }, line);
|
|
52000
|
+
}
|
|
52001
|
+
function renderDiff(diff2, path13) {
|
|
52002
|
+
const preview = parseUnifiedDiff(diff2, CONFIRM_DIFF_MAX_LINES);
|
|
52003
|
+
if (preview.rows.length > 0) {
|
|
52004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
52005
|
+
DiffBlock,
|
|
52006
|
+
{
|
|
52007
|
+
rows: preview.rows,
|
|
52008
|
+
hidden: preview.hidden,
|
|
52009
|
+
added: preview.added,
|
|
52010
|
+
removed: preview.removed,
|
|
52011
|
+
hiddenAdded: preview.hiddenAdded,
|
|
52012
|
+
hiddenRemoved: preview.hiddenRemoved,
|
|
52013
|
+
useColor: theme.supportsBackground,
|
|
52014
|
+
lang: langFromPath(path13 ?? "")
|
|
52015
|
+
}
|
|
52016
|
+
);
|
|
52246
52017
|
}
|
|
52247
|
-
const
|
|
52248
|
-
|
|
52249
|
-
|
|
52250
|
-
|
|
52251
|
-
|
|
52252
|
-
|
|
52253
|
-
|
|
52254
|
-
|
|
52018
|
+
const lines = diff2.split("\n").filter((l) => l.length > 0).slice(0, CONFIRM_DIFF_MAX_LINES);
|
|
52019
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Box2, { flexDirection: "column", paddingX: 2, children: lines.map((l) => renderDiffLine(l)) });
|
|
52020
|
+
}
|
|
52021
|
+
function ConfirmPrompt({
|
|
52022
|
+
toolName,
|
|
52023
|
+
input,
|
|
52024
|
+
suggestedPattern,
|
|
52025
|
+
onDecision,
|
|
52026
|
+
onEnableYolo,
|
|
52027
|
+
destructive,
|
|
52028
|
+
boundaryReason,
|
|
52029
|
+
writeTargets,
|
|
52030
|
+
maxRows
|
|
52031
|
+
}) {
|
|
52032
|
+
const size = useTerminalSize();
|
|
52033
|
+
const rowBudget = maxRows ?? size.rows;
|
|
52034
|
+
const buttons = import_react63.default.useRef(/* @__PURE__ */ new Map());
|
|
52035
|
+
const partialMouse = import_react63.default.useRef("");
|
|
52036
|
+
const decided = import_react63.default.useRef(false);
|
|
52037
|
+
const decide = (decision) => {
|
|
52038
|
+
if (decided.current) return;
|
|
52039
|
+
decided.current = true;
|
|
52040
|
+
onDecision(decision);
|
|
52041
|
+
};
|
|
52042
|
+
const { stdin } = use_stdin_default();
|
|
52043
|
+
import_react63.default.useEffect(() => {
|
|
52044
|
+
if (!stdin) return;
|
|
52045
|
+
const onData = (data) => {
|
|
52046
|
+
const chunk = splitTrailingMousePartial(partialMouse.current + data.toString());
|
|
52047
|
+
partialMouse.current = chunk.pending;
|
|
52048
|
+
for (const event of parseMouseEvents(chunk.consumed)) {
|
|
52049
|
+
if (event.kind !== "press" || event.button !== "left") continue;
|
|
52050
|
+
for (const [decision, node] of buttons.current) {
|
|
52051
|
+
const rect = measure_element_default(node);
|
|
52052
|
+
if (event.x > rect.x && event.x <= rect.x + rect.width && event.y > rect.y && event.y <= rect.y + rect.height) {
|
|
52053
|
+
decide(decision);
|
|
52054
|
+
break;
|
|
52055
|
+
}
|
|
52056
|
+
}
|
|
52255
52057
|
}
|
|
52256
|
-
return {
|
|
52257
|
-
serviceId: "mailbox",
|
|
52258
|
-
action,
|
|
52259
|
-
success: false,
|
|
52260
|
-
message: `Mailbox IPC server shutdown failed: ${result.reason ?? "unknown"}`
|
|
52261
|
-
};
|
|
52262
|
-
}
|
|
52263
|
-
if (action === "restart") {
|
|
52264
|
-
return await restartMailboxServer(projectRoot);
|
|
52265
|
-
}
|
|
52266
|
-
return {
|
|
52267
|
-
serviceId: "mailbox",
|
|
52268
|
-
action,
|
|
52269
|
-
success: true,
|
|
52270
|
-
message: "Mailbox IPC server shutdown requested"
|
|
52271
52058
|
};
|
|
52272
|
-
|
|
52273
|
-
return {
|
|
52274
|
-
|
|
52275
|
-
action,
|
|
52276
|
-
success: false,
|
|
52277
|
-
message: toErrorMessage(error)
|
|
52059
|
+
stdin.on("data", onData);
|
|
52060
|
+
return () => {
|
|
52061
|
+
stdin.off("data", onData);
|
|
52278
52062
|
};
|
|
52279
|
-
}
|
|
52280
|
-
|
|
52281
|
-
|
|
52282
|
-
}
|
|
52283
|
-
|
|
52284
|
-
|
|
52285
|
-
|
|
52286
|
-
|
|
52287
|
-
|
|
52288
|
-
|
|
52289
|
-
|
|
52290
|
-
|
|
52291
|
-
|
|
52063
|
+
}, [stdin, decide]);
|
|
52064
|
+
import_react63.default.useEffect(() => {
|
|
52065
|
+
writeOut("\x07");
|
|
52066
|
+
}, []);
|
|
52067
|
+
use_input_default((input2, key2) => {
|
|
52068
|
+
if (key2.ctrl || key2.meta || decided.current) return;
|
|
52069
|
+
if (!input2 || input2 === "\r" || input2 === "\n") return;
|
|
52070
|
+
if (input2 === "Y" && !boundaryReason) {
|
|
52071
|
+
onEnableYolo();
|
|
52072
|
+
return;
|
|
52073
|
+
}
|
|
52074
|
+
const ch = input2.toLowerCase();
|
|
52075
|
+
if (ch === "y") {
|
|
52076
|
+
decide("yes");
|
|
52077
|
+
} else if (ch === "n") {
|
|
52078
|
+
decide("no");
|
|
52079
|
+
} else if (ch === "a") {
|
|
52080
|
+
decide("always-exact");
|
|
52081
|
+
} else if (ch === "c" && toolName === "exec") {
|
|
52082
|
+
decide("always-command");
|
|
52083
|
+
} else if (ch === "t") {
|
|
52084
|
+
decide("always-tool");
|
|
52085
|
+
} else if (ch === "d") {
|
|
52086
|
+
decide("deny");
|
|
52292
52087
|
}
|
|
52293
52088
|
});
|
|
52294
|
-
const
|
|
52295
|
-
|
|
52296
|
-
);
|
|
52297
|
-
|
|
52298
|
-
|
|
52299
|
-
|
|
52300
|
-
|
|
52301
|
-
|
|
52302
|
-
|
|
52303
|
-
|
|
52304
|
-
|
|
52305
|
-
|
|
52306
|
-
|
|
52307
|
-
|
|
52308
|
-
|
|
52309
|
-
|
|
52310
|
-
|
|
52311
|
-
|
|
52312
|
-
|
|
52313
|
-
|
|
52314
|
-
|
|
52089
|
+
const inputSummary = stringifyInput(input);
|
|
52090
|
+
const inp = input;
|
|
52091
|
+
const diff2 = payloadDiff(input);
|
|
52092
|
+
const diffPath = typeof inp?.path === "string" ? inp.path : void 0;
|
|
52093
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(PanelInputProvider, { value: true, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(MonitorViewportProvider, { value: { columns: size.columns, rows: rowBudget }, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
|
|
52094
|
+
MonitorShell,
|
|
52095
|
+
{
|
|
52096
|
+
accent: "yellow",
|
|
52097
|
+
icon: "\u26A0",
|
|
52098
|
+
title: `APPROVAL REQUIRED \xB7 ${toolName}`,
|
|
52099
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Box2, { flexDirection: "row", flexWrap: "wrap", children: buttonLabels(suggestedPattern, toolName).map((label) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
52100
|
+
Box2,
|
|
52101
|
+
{
|
|
52102
|
+
flexShrink: 0,
|
|
52103
|
+
ref: (node) => {
|
|
52104
|
+
if (node) buttons.current.set(label.decision, node);
|
|
52105
|
+
else buttons.current.delete(label.decision);
|
|
52106
|
+
},
|
|
52107
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { children: [
|
|
52108
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Text2, { bold: true, color: BUTTON_COLOR[label.decision], children: label.bracket }),
|
|
52109
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Text2, { dimColor: true, children: label.rest })
|
|
52110
|
+
] })
|
|
52111
|
+
},
|
|
52112
|
+
label.decision
|
|
52113
|
+
)) }),
|
|
52114
|
+
children: [
|
|
52115
|
+
inputSummary ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Text2, { dimColor: true, children: inputSummary }) : null,
|
|
52116
|
+
boundaryReason ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { color: "yellow", children: [
|
|
52117
|
+
"KANBAN BOUNDARY: ",
|
|
52118
|
+
boundaryReason
|
|
52119
|
+
] }) : null,
|
|
52120
|
+
writeTargets && writeTargets.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { color: "yellow", children: [
|
|
52121
|
+
"WRITES: ",
|
|
52122
|
+
writeTargets.slice(0, 5).join(", "),
|
|
52123
|
+
writeTargets.length > 5 ? ` (+${writeTargets.length - 5} more)` : ""
|
|
52124
|
+
] }) : null,
|
|
52125
|
+
diff2 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Box2, { flexDirection: "column", marginY: 1, children: renderDiff(diff2, diffPath) }) : null,
|
|
52126
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { dimColor: true, children: [
|
|
52127
|
+
"Remember: [a] this input; ",
|
|
52128
|
+
toolName === "exec" ? "[c] executable, any args; " : "",
|
|
52129
|
+
"[t] tool, any input. Destructive calls still prompt."
|
|
52130
|
+
] }),
|
|
52131
|
+
!boundaryReason ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Box2, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Text2, { dimColor: true, children: [
|
|
52132
|
+
" ",
|
|
52133
|
+
"Tip: press",
|
|
52134
|
+
" ",
|
|
52135
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Text2, { bold: true, color: "yellow", children: "Y" }),
|
|
52136
|
+
" ",
|
|
52137
|
+
"to enable YOLO mode",
|
|
52138
|
+
destructive ? " (this destructive approval remains)" : " (skips future routine approvals)",
|
|
52139
|
+
"."
|
|
52140
|
+
] }) }) : null
|
|
52141
|
+
]
|
|
52142
|
+
}
|
|
52143
|
+
) }) });
|
|
52315
52144
|
}
|
|
52316
52145
|
|
|
52317
52146
|
// src/components/connections-panel.tsx
|
|
52147
|
+
var import_react64 = __toESM(require_react(), 1);
|
|
52148
|
+
init_connection_actions();
|
|
52318
52149
|
init_connections_health();
|
|
52319
52150
|
var import_jsx_runtime51 = __toESM(require_jsx_runtime(), 1);
|
|
52320
52151
|
var REFRESH_MS = 8e3;
|
|
@@ -54184,8 +54015,10 @@ var SETTINGS_FIELD_LABELS = [
|
|
|
54184
54015
|
// 60
|
|
54185
54016
|
"Right sidebar",
|
|
54186
54017
|
// 61
|
|
54187
|
-
"Tool result view"
|
|
54018
|
+
"Tool result view",
|
|
54188
54019
|
// 62
|
|
54020
|
+
"Tool Coach"
|
|
54021
|
+
// 63
|
|
54189
54022
|
];
|
|
54190
54023
|
|
|
54191
54024
|
// src/components/model-picker-effort.ts
|
|
@@ -55878,6 +55711,7 @@ function resolveSettingsFieldValue(field, input) {
|
|
|
55878
55711
|
[10, "featureMemory"],
|
|
55879
55712
|
[11, "featureSkills"],
|
|
55880
55713
|
[12, "featureModelsRegistry"],
|
|
55714
|
+
[63, "featureToolCoach"],
|
|
55881
55715
|
[14, "allowOutsideProjectRoot"],
|
|
55882
55716
|
[18, "enhanceEnabled"],
|
|
55883
55717
|
[20, "indexOnStart"],
|
|
@@ -56087,6 +55921,7 @@ function getSettingsFieldValue(values, field) {
|
|
|
56087
55921
|
[10, "featureMemory"],
|
|
56088
55922
|
[11, "featureSkills"],
|
|
56089
55923
|
[12, "featureModelsRegistry"],
|
|
55924
|
+
[63, "featureToolCoach"],
|
|
56090
55925
|
[14, "allowOutsideProjectRoot"],
|
|
56091
55926
|
[18, "enhanceEnabled"],
|
|
56092
55927
|
[20, "indexOnStart"],
|
|
@@ -56176,6 +56011,10 @@ var SETTINGS_SECTIONS = [
|
|
|
56176
56011
|
name: "Features",
|
|
56177
56012
|
fields: [8, 9, 10, 11, 12, 13, 14]
|
|
56178
56013
|
},
|
|
56014
|
+
{
|
|
56015
|
+
name: "Agent guidance",
|
|
56016
|
+
fields: [63]
|
|
56017
|
+
},
|
|
56179
56018
|
{
|
|
56180
56019
|
name: "Tools",
|
|
56181
56020
|
fields: [15, 16, 17, 18, 19, 20, 21, 22, 42, 45]
|
|
@@ -56264,6 +56103,7 @@ var SETTINGS_DEFAULTS = Object.freeze({
|
|
|
56264
56103
|
featureMemory: true,
|
|
56265
56104
|
featureSkills: true,
|
|
56266
56105
|
featureModelsRegistry: true,
|
|
56106
|
+
featureToolCoach: true,
|
|
56267
56107
|
tokenSavingTier: "off",
|
|
56268
56108
|
allowOutsideProjectRoot: true,
|
|
56269
56109
|
contextAutoCompact: true,
|
|
@@ -56331,6 +56171,7 @@ function buildResetPatch(field) {
|
|
|
56331
56171
|
[10, "featureMemory"],
|
|
56332
56172
|
[11, "featureSkills"],
|
|
56333
56173
|
[12, "featureModelsRegistry"],
|
|
56174
|
+
[63, "featureToolCoach"],
|
|
56334
56175
|
[13, "tokenSavingTier"],
|
|
56335
56176
|
[14, "allowOutsideProjectRoot"],
|
|
56336
56177
|
[15, "maxIterations"],
|
|
@@ -56525,6 +56366,7 @@ function SettingsPicker({
|
|
|
56525
56366
|
featureMemory,
|
|
56526
56367
|
featureSkills,
|
|
56527
56368
|
featureModelsRegistry,
|
|
56369
|
+
featureToolCoach,
|
|
56528
56370
|
tokenSavingTier,
|
|
56529
56371
|
allowOutsideProjectRoot,
|
|
56530
56372
|
maxIterations,
|
|
@@ -56875,7 +56717,13 @@ function SettingsPicker({
|
|
|
56875
56717
|
value: `${boolVal(showSidebar ?? true)}${sidebarPinned ? " \xB7 pinned" : ""}`,
|
|
56876
56718
|
detail: sidebarPinned ? "A panel is routed to the sidebar \u2014 set that panel to bottom to unlock hiding" : "Show or hide the right sidebar in the TUI (chat history takes full width when off)"
|
|
56877
56719
|
},
|
|
56878
|
-
toolResultViewSettingRow(toolResultViewMode)
|
|
56720
|
+
toolResultViewSettingRow(toolResultViewMode),
|
|
56721
|
+
{ section: "Agent guidance" },
|
|
56722
|
+
{
|
|
56723
|
+
label: "Tool Coach",
|
|
56724
|
+
value: boolVal(featureToolCoach),
|
|
56725
|
+
detail: "Suggest enabled tools and guide recovery after tool errors (default on)"
|
|
56726
|
+
}
|
|
56879
56727
|
];
|
|
56880
56728
|
const fieldRowIndex = [];
|
|
56881
56729
|
for (let i = 0; i < rows.length; i++) {
|
|
@@ -57460,8 +57308,86 @@ function SubagentModelsPanel({
|
|
|
57460
57308
|
] });
|
|
57461
57309
|
}
|
|
57462
57310
|
|
|
57311
|
+
// src/theme-picker-rows.ts
|
|
57312
|
+
function filterThemeOptions(options, query) {
|
|
57313
|
+
const terms = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
57314
|
+
if (terms.length === 0) return options;
|
|
57315
|
+
return options.filter((opt) => {
|
|
57316
|
+
const haystack = `${opt.name} ${opt.id} ${opt.description}`.toLowerCase();
|
|
57317
|
+
return terms.every((term) => haystack.includes(term));
|
|
57318
|
+
});
|
|
57319
|
+
}
|
|
57320
|
+
function buildThemeRows(options) {
|
|
57321
|
+
const rows = [];
|
|
57322
|
+
let lastFamily;
|
|
57323
|
+
for (const [index, option] of options.entries()) {
|
|
57324
|
+
if (option.family !== lastFamily) {
|
|
57325
|
+
rows.push({ kind: "header", family: option.family });
|
|
57326
|
+
lastFamily = option.family;
|
|
57327
|
+
}
|
|
57328
|
+
rows.push({ kind: "option", option, index });
|
|
57329
|
+
}
|
|
57330
|
+
return rows;
|
|
57331
|
+
}
|
|
57332
|
+
function windowThemeRows(rows, selected, budget) {
|
|
57333
|
+
if (rows.length === 0) return { rows: [], hasAbove: false, hasBelow: false };
|
|
57334
|
+
const focusPos = Math.max(
|
|
57335
|
+
0,
|
|
57336
|
+
rows.findIndex((r) => r.kind === "option" && r.index === selected)
|
|
57337
|
+
);
|
|
57338
|
+
let headerPos = focusPos;
|
|
57339
|
+
for (let i = focusPos; i >= 0; i -= 1) {
|
|
57340
|
+
if (rows[i].kind === "header") {
|
|
57341
|
+
headerPos = i;
|
|
57342
|
+
break;
|
|
57343
|
+
}
|
|
57344
|
+
}
|
|
57345
|
+
const capacity = Math.max(2, budget);
|
|
57346
|
+
let start = focusPos + 1 - headerPos <= capacity ? headerPos : focusPos;
|
|
57347
|
+
let end = focusPos + 1;
|
|
57348
|
+
let used = end - start;
|
|
57349
|
+
while (used < capacity && end < rows.length) {
|
|
57350
|
+
const cost = needsHeaderAbove(rows, end) ? 2 : 1;
|
|
57351
|
+
if (used + cost > capacity) break;
|
|
57352
|
+
end += cost;
|
|
57353
|
+
used += cost;
|
|
57354
|
+
}
|
|
57355
|
+
while (used < capacity && start > 0) {
|
|
57356
|
+
start -= 1;
|
|
57357
|
+
used += 1;
|
|
57358
|
+
}
|
|
57359
|
+
return {
|
|
57360
|
+
rows: rows.slice(start, end),
|
|
57361
|
+
hasAbove: start > 0,
|
|
57362
|
+
hasBelow: end < rows.length
|
|
57363
|
+
};
|
|
57364
|
+
}
|
|
57365
|
+
function needsHeaderAbove(rows, pos) {
|
|
57366
|
+
const row = rows[pos];
|
|
57367
|
+
if (row === void 0) return false;
|
|
57368
|
+
return row.kind === "header" || rows[pos - 1]?.kind === "header";
|
|
57369
|
+
}
|
|
57370
|
+
|
|
57463
57371
|
// src/components/theme-preview.tsx
|
|
57464
57372
|
var import_jsx_runtime81 = __toESM(require_jsx_runtime(), 1);
|
|
57373
|
+
var CONTRAST_FLOOR = 3;
|
|
57374
|
+
function ContrastRow({
|
|
57375
|
+
fg,
|
|
57376
|
+
bg,
|
|
57377
|
+
label
|
|
57378
|
+
}) {
|
|
57379
|
+
const ratio = contrastRatio(fg, bg);
|
|
57380
|
+
const weak = ratio < CONTRAST_FLOOR;
|
|
57381
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(Text2, { children: [
|
|
57382
|
+
" ",
|
|
57383
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Text2, { dimColor: true, children: label.padEnd(5) }),
|
|
57384
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Text2, { color: weak ? "yellow" : void 0, children: weak ? "\u25B2" : "\xB7" }),
|
|
57385
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(Text2, { color: weak ? "yellow" : void 0, bold: weak, children: [
|
|
57386
|
+
ratio.toFixed(1),
|
|
57387
|
+
":1"
|
|
57388
|
+
] })
|
|
57389
|
+
] });
|
|
57390
|
+
}
|
|
57465
57391
|
function ThemePreview({
|
|
57466
57392
|
presetId,
|
|
57467
57393
|
active,
|
|
@@ -57567,6 +57493,21 @@ function ThemePreview({
|
|
|
57567
57493
|
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Text2, { backgroundColor: preset.diffDelBg, children: " " })
|
|
57568
57494
|
] })
|
|
57569
57495
|
] })
|
|
57496
|
+
},
|
|
57497
|
+
{
|
|
57498
|
+
// Placed LAST so the existing trim-from-bottom order is untouched: a
|
|
57499
|
+
// short terminal drops contrast before it drops the sample/diff the user
|
|
57500
|
+
// actually judges the palette by.
|
|
57501
|
+
key: "contrast",
|
|
57502
|
+
// Label + three readings = 4 physical rows. The cost must match the real
|
|
57503
|
+
// height or the trim loop lets the preview overrun the picker's budget.
|
|
57504
|
+
cost: 4,
|
|
57505
|
+
render: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(Box2, { flexDirection: "column", children: [
|
|
57506
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Text2, { dimColor: true, children: "contrast" }),
|
|
57507
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(ContrastRow, { fg: preset.textPrimary, bg: preset.surface, label: "text" }),
|
|
57508
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(ContrastRow, { fg: preset.success, bg: preset.diffAddBg, label: "+add" }),
|
|
57509
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(ContrastRow, { fg: preset.error, bg: preset.diffDelBg, label: "-del" })
|
|
57510
|
+
] })
|
|
57570
57511
|
}
|
|
57571
57512
|
];
|
|
57572
57513
|
let used = 0;
|
|
@@ -57595,21 +57536,21 @@ function ThemePicker({
|
|
|
57595
57536
|
activeId,
|
|
57596
57537
|
hint,
|
|
57597
57538
|
columns = 0,
|
|
57598
|
-
maxRows
|
|
57539
|
+
maxRows,
|
|
57540
|
+
filter = ""
|
|
57599
57541
|
}) {
|
|
57600
57542
|
const split = columns >= SPLIT_MIN_COLUMNS && options.length > 0 && (maxRows === void 0 || maxRows >= PREVIEW_MIN_ROWS);
|
|
57601
57543
|
const listMaxRows = split && maxRows !== void 0 ? Math.min(maxRows, PREVIEW_FULL_ROWS) : maxRows;
|
|
57602
|
-
const
|
|
57603
|
-
|
|
57604
|
-
|
|
57605
|
-
|
|
57606
|
-
|
|
57607
|
-
|
|
57608
|
-
|
|
57609
|
-
|
|
57610
|
-
|
|
57611
|
-
const
|
|
57612
|
-
const selectedOption = options[Math.max(0, Math.min(selected, options.length - 1))];
|
|
57544
|
+
const visibleOptions = filterThemeOptions(options, filter);
|
|
57545
|
+
const rows = buildThemeRows(visibleOptions);
|
|
57546
|
+
const { rows: rows_terminal } = useTerminalSize();
|
|
57547
|
+
const chromeRows = 4;
|
|
57548
|
+
const markerRows = 4;
|
|
57549
|
+
const listBudget = listMaxRows === void 0 ? Math.max(1, rows_terminal - chromeRows - markerRows - SHELL_RESERVED_ROWS) : Math.max(1, listMaxRows - chromeRows - markerRows);
|
|
57550
|
+
const safeSelected = Math.max(0, Math.min(selected, Math.max(0, visibleOptions.length - 1)));
|
|
57551
|
+
const window2 = windowThemeRows(rows, safeSelected, listBudget);
|
|
57552
|
+
const selectedOption = visibleOptions[safeSelected];
|
|
57553
|
+
const innerWidth = (split ? LIST_COLUMN_WIDTH : Math.max(0, columns)) - LIST_CHROME_COLUMNS;
|
|
57613
57554
|
const list = /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(
|
|
57614
57555
|
Box2,
|
|
57615
57556
|
{
|
|
@@ -57620,40 +57561,19 @@ function ThemePicker({
|
|
|
57620
57561
|
...split ? { width: LIST_COLUMN_WIDTH, flexShrink: 0 } : {},
|
|
57621
57562
|
children: [
|
|
57622
57563
|
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { color: "cyan", bold: true, children: "\u2501\u2501 TUI Theme \u2501\u2501" }),
|
|
57623
|
-
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { dimColor: true, wrap: "truncate-end", children: "\u2191\u2193 \xB7
|
|
57624
|
-
|
|
57625
|
-
"
|
|
57626
|
-
|
|
57627
|
-
|
|
57628
|
-
|
|
57629
|
-
|
|
57630
|
-
const i = start + j;
|
|
57631
|
-
const isActive = opt.id === activeId;
|
|
57632
|
-
const isSelected = i === selected;
|
|
57633
|
-
return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(
|
|
57634
|
-
Text2,
|
|
57635
|
-
{
|
|
57636
|
-
wrap: "truncate-end",
|
|
57637
|
-
inverse: isSelected,
|
|
57638
|
-
...isSelected ? { color: "cyan" } : {},
|
|
57639
|
-
children: [
|
|
57640
|
-
isSelected ? "\u203A " : " ",
|
|
57641
|
-
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { bold: true, children: opt.name.padEnd(21) }),
|
|
57642
|
-
isActive ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { color: "green", children: " [active]" }) : null,
|
|
57643
|
-
split ? null : /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(Text2, { dimColor: true, children: [
|
|
57644
|
-
" ",
|
|
57645
|
-
opt.description
|
|
57646
|
-
] })
|
|
57647
|
-
]
|
|
57648
|
-
},
|
|
57649
|
-
opt.id
|
|
57650
|
-
);
|
|
57651
|
-
}),
|
|
57652
|
-
hasBelow ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(Text2, { dimColor: true, children: [
|
|
57653
|
-
" \u2026 ",
|
|
57654
|
-
options.length - end,
|
|
57655
|
-
" more below"
|
|
57564
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { dimColor: true, wrap: "truncate-end", children: "\u2191\u2193 Enter apply \xB7 / \xB7 u undo \xB7 Esc" }),
|
|
57565
|
+
filter ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(Text2, { color: "yellow", wrap: "truncate-end", children: [
|
|
57566
|
+
"/",
|
|
57567
|
+
filter,
|
|
57568
|
+
visibleOptions.length,
|
|
57569
|
+
" match",
|
|
57570
|
+
visibleOptions.length === 1 ? "" : "es"
|
|
57656
57571
|
] }) : null,
|
|
57572
|
+
window2.hasAbove ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { dimColor: true, children: " \u2026 more above" }) : null,
|
|
57573
|
+
window2.rows.map(
|
|
57574
|
+
(row) => renderRow2(row, keyFor(row), activeId, safeSelected, split, innerWidth)
|
|
57575
|
+
),
|
|
57576
|
+
window2.hasBelow ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { dimColor: true, children: " \u2026 more below" }) : null,
|
|
57657
57577
|
hint ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { color: "yellow", wrap: "truncate-end", children: hint }) : null
|
|
57658
57578
|
]
|
|
57659
57579
|
}
|
|
@@ -57674,8 +57594,67 @@ function ThemePicker({
|
|
|
57674
57594
|
)
|
|
57675
57595
|
] });
|
|
57676
57596
|
}
|
|
57677
|
-
|
|
57678
|
-
|
|
57597
|
+
function keyFor(row) {
|
|
57598
|
+
return row.kind === "header" ? `h:${row.family}` : `o:${row.option.id}`;
|
|
57599
|
+
}
|
|
57600
|
+
function renderRow2(row, key2, activeId, selected, split, innerWidth) {
|
|
57601
|
+
if (row.kind === "header") {
|
|
57602
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { color: "blue", bold: true, dimColor: true, wrap: "truncate-end", children: row.family }, key2);
|
|
57603
|
+
}
|
|
57604
|
+
const opt = row.option;
|
|
57605
|
+
const isActive = opt.id === activeId;
|
|
57606
|
+
const isSelected = row.index === selected;
|
|
57607
|
+
const fixed = ROW_BASE_COLUMNS + (isActive ? ACTIVE_MARKER_COLUMNS : 0);
|
|
57608
|
+
const showSwatches = !split && innerWidth - fixed >= SWATCH_COLUMNS;
|
|
57609
|
+
const showDescription = !split && innerWidth - fixed - (showSwatches ? SWATCH_COLUMNS : 0) >= MIN_DESCRIPTION_COLUMNS;
|
|
57610
|
+
return (
|
|
57611
|
+
// The cursor/name/marker run and the swatches are SIBLINGS, not nested.
|
|
57612
|
+
// Ink propagates a parent's `inverse` to nested children, so keeping
|
|
57613
|
+
// <Swatches/> inside the inverted <Text> inverted every chip — each swatch
|
|
57614
|
+
// would render in the complement of its own colour, which defeats the
|
|
57615
|
+
// point of sampling the palette.
|
|
57616
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(Box2, { flexDirection: "row", children: [
|
|
57617
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(Text2, { inverse: isSelected, ...isSelected ? { color: "cyan" } : {}, children: [
|
|
57618
|
+
isSelected ? "\u203A " : " ",
|
|
57619
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { bold: true, children: fitName(opt.name) }),
|
|
57620
|
+
isActive ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { color: "green", children: " [active]" }) : null
|
|
57621
|
+
] }),
|
|
57622
|
+
showSwatches ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Swatches, { optionId: opt.id }) : null,
|
|
57623
|
+
showDescription ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(Text2, { dimColor: true, wrap: "truncate-end", children: [
|
|
57624
|
+
" ",
|
|
57625
|
+
opt.description
|
|
57626
|
+
] }) : null
|
|
57627
|
+
] }, key2)
|
|
57628
|
+
);
|
|
57629
|
+
}
|
|
57630
|
+
var NAME_COLUMNS = 21;
|
|
57631
|
+
function fitName(name) {
|
|
57632
|
+
return name.length > NAME_COLUMNS ? `${name.slice(0, NAME_COLUMNS - 1)}\u2026` : name.padEnd(NAME_COLUMNS);
|
|
57633
|
+
}
|
|
57634
|
+
var SWATCH_COLUMNS = 7;
|
|
57635
|
+
var ROW_BASE_COLUMNS = 2 + NAME_COLUMNS;
|
|
57636
|
+
var ACTIVE_MARKER_COLUMNS = 9;
|
|
57637
|
+
var MIN_DESCRIPTION_COLUMNS = 12;
|
|
57638
|
+
var LIST_CHROME_COLUMNS = 4;
|
|
57639
|
+
function Swatches({ optionId }) {
|
|
57640
|
+
const preset = themePresets[optionId];
|
|
57641
|
+
if (!preset) return null;
|
|
57642
|
+
const chips = [
|
|
57643
|
+
preset.accent,
|
|
57644
|
+
preset.brandPrimary,
|
|
57645
|
+
preset.user,
|
|
57646
|
+
preset.success,
|
|
57647
|
+
preset.error,
|
|
57648
|
+
preset.surfaceRaised
|
|
57649
|
+
];
|
|
57650
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(Text2, { children: [
|
|
57651
|
+
" ",
|
|
57652
|
+
chips.map((color, i) => /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Text2, { backgroundColor: color, children: " " }, `${optionId}-${i}`))
|
|
57653
|
+
] });
|
|
57654
|
+
}
|
|
57655
|
+
var SHELL_RESERVED_ROWS = 6;
|
|
57656
|
+
var LIST_COLUMN_WIDTH = 43;
|
|
57657
|
+
var SPLIT_MIN_COLUMNS = 92;
|
|
57679
57658
|
var PREVIEW_MIN_ROWS = 12;
|
|
57680
57659
|
var PREVIEW_FULL_ROWS = 18;
|
|
57681
57660
|
|
|
@@ -58094,6 +58073,7 @@ function AppViewPickers({
|
|
|
58094
58073
|
selected: state.themePicker.selected,
|
|
58095
58074
|
activeId: getActiveThemeName(),
|
|
58096
58075
|
hint: state.themePicker.hint,
|
|
58076
|
+
filter: state.themePicker.filter,
|
|
58097
58077
|
columns: mainColumnWidth,
|
|
58098
58078
|
maxRows: pickerMaxRows
|
|
58099
58079
|
}
|
|
@@ -58177,6 +58157,7 @@ function AppViewPickers({
|
|
|
58177
58157
|
featureMemory: state.settingsPicker.featureMemory,
|
|
58178
58158
|
featureSkills: state.settingsPicker.featureSkills,
|
|
58179
58159
|
featureModelsRegistry: state.settingsPicker.featureModelsRegistry,
|
|
58160
|
+
featureToolCoach: state.settingsPicker.featureToolCoach,
|
|
58180
58161
|
tokenSavingTier: state.settingsPicker.tokenSavingTier,
|
|
58181
58162
|
allowOutsideProjectRoot: state.settingsPicker.allowOutsideProjectRoot,
|
|
58182
58163
|
contextAutoCompact: state.settingsPicker.contextAutoCompact,
|
|
@@ -62072,7 +62053,7 @@ function ComposerTopRail({
|
|
|
62072
62053
|
function inputContentWidth(termColumns) {
|
|
62073
62054
|
return Math.max(8, termColumns - 4);
|
|
62074
62055
|
}
|
|
62075
|
-
function
|
|
62056
|
+
function renderRow3(cells, rowKey, promptColor) {
|
|
62076
62057
|
const out = [];
|
|
62077
62058
|
let run = "";
|
|
62078
62059
|
let runStart = 0;
|
|
@@ -62401,7 +62382,7 @@ var Input = (0, import_react78.memo)(function Input2({
|
|
|
62401
62382
|
const padding = " ".repeat(Math.max(0, contentWidth - rowWidth));
|
|
62402
62383
|
return /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(Text2, { children: [
|
|
62403
62384
|
/* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text2, { color: disabled ? theme.error : accent ?? theme.brandPrimary, children: "\u2502 " }),
|
|
62404
|
-
row.length === 0 ? null :
|
|
62385
|
+
row.length === 0 ? null : renderRow3(row, `r${i}`, promptColor),
|
|
62405
62386
|
/* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text2, { children: padding }),
|
|
62406
62387
|
/* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text2, { color: disabled ? theme.error : accent ?? theme.brandPrimary, children: " \u2502" })
|
|
62407
62388
|
] }, i);
|
|
@@ -62902,7 +62883,7 @@ var EntryHeightCache = class {
|
|
|
62902
62883
|
};
|
|
62903
62884
|
|
|
62904
62885
|
// src/hit-test.ts
|
|
62905
|
-
var SCROLLBAR_HIT_WIDTH =
|
|
62886
|
+
var SCROLLBAR_HIT_WIDTH = 8;
|
|
62906
62887
|
function historyViewportRows(termRows, bottomHeight) {
|
|
62907
62888
|
return Math.max(1, Math.floor(termRows) - Math.max(0, Math.floor(bottomHeight)));
|
|
62908
62889
|
}
|
|
@@ -63702,10 +63683,10 @@ function renderTable(tableLines, maxWidth) {
|
|
|
63702
63683
|
const widths = computeWidths([header, ...dataRows], cols, maxWidth, sepWidths);
|
|
63703
63684
|
const lines = [];
|
|
63704
63685
|
lines.push(border("\u250C", "\u252C", "\u2510", widths));
|
|
63705
|
-
lines.push(...
|
|
63686
|
+
lines.push(...renderRow4(header, widths, aligns));
|
|
63706
63687
|
lines.push(border("\u251C", "\u253C", "\u2524", widths));
|
|
63707
63688
|
for (const row of dataRows) {
|
|
63708
|
-
lines.push(...
|
|
63689
|
+
lines.push(...renderRow4(row, widths, aligns));
|
|
63709
63690
|
}
|
|
63710
63691
|
lines.push(border("\u2514", "\u2534", "\u2518", widths));
|
|
63711
63692
|
return lines.join("\n");
|
|
@@ -63771,9 +63752,12 @@ function border(left, mid, right, widths) {
|
|
|
63771
63752
|
return left + widths.map((w) => "\u2500".repeat(w + 2)).join(mid) + right;
|
|
63772
63753
|
}
|
|
63773
63754
|
function stripInlineMarkers(text) {
|
|
63774
|
-
return text.
|
|
63755
|
+
return text.split(/(`.+?`)/).map((part, i) => i % 2 === 1 ? part.slice(1, -1) : stripEmphasis(part)).join("");
|
|
63775
63756
|
}
|
|
63776
|
-
function
|
|
63757
|
+
function stripEmphasis(text) {
|
|
63758
|
+
return text.replace(/\*\*(?!\s)(.+?)(?<!\s)\*\*/g, "$1").replace(/(?<!\*)\*(?![\s*])(.+?)(?<![\s*])\*(?!\*)/g, "$1").replace(/~~(.+?)~~/g, "$1");
|
|
63759
|
+
}
|
|
63760
|
+
function renderRow4(cells, widths, aligns) {
|
|
63777
63761
|
const safe = cells.map((cell) => breakLigatures(stripInlineMarkers(cell)));
|
|
63778
63762
|
const wrapped = safe.map((c, i) => wrapCell(c, widths[i] ?? MIN_COL_WIDTH));
|
|
63779
63763
|
const height = Math.max(1, ...wrapped.map((w) => w.length));
|
|
@@ -63804,7 +63788,7 @@ function wrapCell(text, width) {
|
|
|
63804
63788
|
continue;
|
|
63805
63789
|
}
|
|
63806
63790
|
if (cur) {
|
|
63807
|
-
out.push(
|
|
63791
|
+
out.push(clipVisual(cur.trimEnd(), width));
|
|
63808
63792
|
cur = "";
|
|
63809
63793
|
curWidth = 0;
|
|
63810
63794
|
}
|
|
@@ -63814,7 +63798,7 @@ function wrapCell(text, width) {
|
|
|
63814
63798
|
while (restWidth > width) {
|
|
63815
63799
|
const [collected, remaining] = splitDisplay(rest, width);
|
|
63816
63800
|
if (collected === "") break;
|
|
63817
|
-
out.push(
|
|
63801
|
+
out.push(clipVisual(collected, width));
|
|
63818
63802
|
rest = remaining;
|
|
63819
63803
|
restWidth = strWidth(rest);
|
|
63820
63804
|
}
|
|
@@ -63825,13 +63809,11 @@ function wrapCell(text, width) {
|
|
|
63825
63809
|
curWidth = wordWidth;
|
|
63826
63810
|
}
|
|
63827
63811
|
}
|
|
63828
|
-
if (cur) out.push(
|
|
63812
|
+
if (cur) out.push(clipVisual(cur.trimEnd(), width));
|
|
63829
63813
|
return out.length === 0 ? [""] : out;
|
|
63830
63814
|
}
|
|
63831
|
-
function
|
|
63832
|
-
|
|
63833
|
-
if (w >= targetWidth) return truncateDisplay(text, targetWidth, "");
|
|
63834
|
-
return text + " ".repeat(targetWidth - w);
|
|
63815
|
+
function clipVisual(text, targetWidth) {
|
|
63816
|
+
return strWidth(text) > targetWidth ? truncateDisplay(text, targetWidth, "") : text;
|
|
63835
63817
|
}
|
|
63836
63818
|
function padCell(text, width, align) {
|
|
63837
63819
|
const visualLen = strWidth(text);
|
|
@@ -65764,6 +65746,7 @@ var Scrollbar = (0, import_react88.memo)(function Scrollbar2({
|
|
|
65764
65746
|
),
|
|
65765
65747
|
/* @__PURE__ */ (0, import_jsx_runtime116.jsx)(Text2, { children: " " }),
|
|
65766
65748
|
/* @__PURE__ */ (0, import_jsx_runtime116.jsx)(Text2, { color: copyHit?.inspectCol !== void 0 ? theme.accent : void 0, children: copyHit?.inspectCol !== void 0 ? INSPECT_ICON : " " }),
|
|
65749
|
+
/* @__PURE__ */ (0, import_jsx_runtime116.jsx)(Text2, { children: " " }),
|
|
65767
65750
|
/* @__PURE__ */ (0, import_jsx_runtime116.jsx)(Text2, { ...inBand || row === markedRow ? { color: theme.accent } : {}, children: isHead ? "\u2588" : inBand ? "\u258C" : row === markedRow ? "\u25C0" : " " }),
|
|
65768
65751
|
/* @__PURE__ */ (0, import_jsx_runtime116.jsx)(
|
|
65769
65752
|
Text2,
|
|
@@ -66529,7 +66512,10 @@ function closePanels(state) {
|
|
|
66529
66512
|
sddBoard: state.sddBoard ? { ...state.sddBoard, monitorOpen: false } : state.sddBoard,
|
|
66530
66513
|
worktreeMonitorOpen: false,
|
|
66531
66514
|
coordinator: { ...state.coordinator, monitorOpen: false },
|
|
66532
|
-
|
|
66515
|
+
// `preview` is explicitly cleared: the spread would carry a live-preview
|
|
66516
|
+
// flag into the next `/theme` open, so arrows would start applying themes
|
|
66517
|
+
// with no keypress opting in.
|
|
66518
|
+
themePicker: { ...state.themePicker, open: false, preview: false },
|
|
66533
66519
|
skillPicker: { ...state.skillPicker, open: false },
|
|
66534
66520
|
resourceMenu: { ...state.resourceMenu, open: false, pendingAction: void 0 }
|
|
66535
66521
|
};
|
|
@@ -68286,6 +68272,7 @@ function useSettingsAutoSave(state, saveSettings, dispatch) {
|
|
|
68286
68272
|
featureMemory: sp.featureMemory,
|
|
68287
68273
|
featureSkills: sp.featureSkills,
|
|
68288
68274
|
featureModelsRegistry: sp.featureModelsRegistry,
|
|
68275
|
+
featureToolCoach: sp.featureToolCoach,
|
|
68289
68276
|
featureTokenSaving: sp.tokenSavingTier,
|
|
68290
68277
|
allowOutsideProjectRoot: sp.allowOutsideProjectRoot,
|
|
68291
68278
|
contextAutoCompact: sp.contextAutoCompact,
|
|
@@ -68353,6 +68340,7 @@ function useSettingsAutoSave(state, saveSettings, dispatch) {
|
|
|
68353
68340
|
state.settingsPicker.featureMemory,
|
|
68354
68341
|
state.settingsPicker.featureSkills,
|
|
68355
68342
|
state.settingsPicker.featureModelsRegistry,
|
|
68343
|
+
state.settingsPicker.featureToolCoach,
|
|
68356
68344
|
state.settingsPicker.tokenSavingTier,
|
|
68357
68345
|
state.settingsPicker.allowOutsideProjectRoot,
|
|
68358
68346
|
state.settingsPicker.contextAutoCompact,
|
|
@@ -68570,6 +68558,7 @@ function useStreamChipExpiration({
|
|
|
68570
68558
|
|
|
68571
68559
|
// src/hooks/use-theme-state.ts
|
|
68572
68560
|
var import_react102 = __toESM(require_react(), 1);
|
|
68561
|
+
import { THEME_RANDOM_ID } from "@wrongstack/core/types";
|
|
68573
68562
|
function useThemeState({ configStore }) {
|
|
68574
68563
|
(0, import_react102.useEffect)(() => {
|
|
68575
68564
|
let randomMode = false;
|
|
@@ -68589,7 +68578,7 @@ function useThemeState({ configStore }) {
|
|
|
68589
68578
|
}, RANDOM_THEME_ROTATION_MS);
|
|
68590
68579
|
};
|
|
68591
68580
|
const syncTheme = (preset) => {
|
|
68592
|
-
if (!preset) {
|
|
68581
|
+
if (!preset || preset === THEME_RANDOM_ID) {
|
|
68593
68582
|
startRandomMode();
|
|
68594
68583
|
return;
|
|
68595
68584
|
}
|
|
@@ -70140,6 +70129,7 @@ function createInitialState(options) {
|
|
|
70140
70129
|
featureMemory: true,
|
|
70141
70130
|
featureSkills: true,
|
|
70142
70131
|
featureModelsRegistry: true,
|
|
70132
|
+
featureToolCoach: true,
|
|
70143
70133
|
tokenSavingTier: "off",
|
|
70144
70134
|
allowOutsideProjectRoot: true,
|
|
70145
70135
|
contextAutoCompact: true,
|
|
@@ -70735,6 +70725,11 @@ var composerActionTypes = [
|
|
|
70735
70725
|
"themePickerClose",
|
|
70736
70726
|
"themePickerMove",
|
|
70737
70727
|
"themePickerHint",
|
|
70728
|
+
"themePickerFilter",
|
|
70729
|
+
"themePickerFilterMode",
|
|
70730
|
+
"themePickerPreview",
|
|
70731
|
+
"themePickerUndo",
|
|
70732
|
+
"themePickerSwapPrevious",
|
|
70738
70733
|
"modePickerOpen",
|
|
70739
70734
|
"modePickerClose",
|
|
70740
70735
|
"modePickerMove",
|
|
@@ -70926,7 +70921,14 @@ function reduceComposerPickers(state, action) {
|
|
|
70926
70921
|
return {
|
|
70927
70922
|
...state,
|
|
70928
70923
|
...closePanels(state),
|
|
70929
|
-
themePicker: {
|
|
70924
|
+
themePicker: {
|
|
70925
|
+
open: true,
|
|
70926
|
+
selected,
|
|
70927
|
+
hint: void 0,
|
|
70928
|
+
filter: "",
|
|
70929
|
+
filtering: false,
|
|
70930
|
+
previous: getActiveThemeName()
|
|
70931
|
+
}
|
|
70930
70932
|
};
|
|
70931
70933
|
}
|
|
70932
70934
|
case "themePickerClose":
|
|
@@ -70935,7 +70937,9 @@ function reduceComposerPickers(state, action) {
|
|
|
70935
70937
|
themePicker: { open: false, selected: 0 }
|
|
70936
70938
|
};
|
|
70937
70939
|
case "themePickerMove": {
|
|
70938
|
-
const
|
|
70940
|
+
const visible = filterThemeOptions(THEME_OPTIONS, state.themePicker.filter ?? "");
|
|
70941
|
+
const n = visible.length;
|
|
70942
|
+
if (n === 0) return state;
|
|
70939
70943
|
const next = (state.themePicker.selected + action.delta + n) % n;
|
|
70940
70944
|
if (next === state.themePicker.selected) return state;
|
|
70941
70945
|
return {
|
|
@@ -70948,6 +70952,57 @@ function reduceComposerPickers(state, action) {
|
|
|
70948
70952
|
...state,
|
|
70949
70953
|
themePicker: { ...state.themePicker, hint: action.text }
|
|
70950
70954
|
};
|
|
70955
|
+
case "themePickerPreview":
|
|
70956
|
+
return {
|
|
70957
|
+
...state,
|
|
70958
|
+
themePicker: {
|
|
70959
|
+
...state.themePicker,
|
|
70960
|
+
preview: action.on,
|
|
70961
|
+
// Entering preview re-baselines `previous` to whatever is live RIGHT
|
|
70962
|
+
// NOW, so Esc restores the palette that was in effect when preview
|
|
70963
|
+
// began — not the one from when the picker was first opened.
|
|
70964
|
+
...action.on ? { previous: getActiveThemeName() } : {}
|
|
70965
|
+
}
|
|
70966
|
+
};
|
|
70967
|
+
case "themePickerFilterMode":
|
|
70968
|
+
return {
|
|
70969
|
+
...state,
|
|
70970
|
+
themePicker: {
|
|
70971
|
+
...state.themePicker,
|
|
70972
|
+
filtering: action.on,
|
|
70973
|
+
// Leaving filter mode with `/` also drops the query, so the mode
|
|
70974
|
+
// flag and the visible list can never disagree about what is shown.
|
|
70975
|
+
filter: action.on ? state.themePicker.filter : ""
|
|
70976
|
+
}
|
|
70977
|
+
};
|
|
70978
|
+
case "themePickerFilter": {
|
|
70979
|
+
const previousId = filterThemeOptions(THEME_OPTIONS, state.themePicker.filter ?? "")[state.themePicker.selected]?.id;
|
|
70980
|
+
const visible = filterThemeOptions(THEME_OPTIONS, action.text);
|
|
70981
|
+
const retained = visible.findIndex((o) => o.id === previousId);
|
|
70982
|
+
return {
|
|
70983
|
+
...state,
|
|
70984
|
+
themePicker: {
|
|
70985
|
+
...state.themePicker,
|
|
70986
|
+
filter: action.text,
|
|
70987
|
+
selected: retained >= 0 ? retained : 0,
|
|
70988
|
+
hint: void 0
|
|
70989
|
+
}
|
|
70990
|
+
};
|
|
70991
|
+
}
|
|
70992
|
+
case "themePickerUndo":
|
|
70993
|
+
return state;
|
|
70994
|
+
case "themePickerSwapPrevious": {
|
|
70995
|
+
const visible = filterThemeOptions(THEME_OPTIONS, state.themePicker.filter ?? "");
|
|
70996
|
+
const activeIndex = visible.findIndex((o) => o.id === getActiveThemeName());
|
|
70997
|
+
return {
|
|
70998
|
+
...state,
|
|
70999
|
+
themePicker: {
|
|
71000
|
+
...state.themePicker,
|
|
71001
|
+
previous: getActiveThemeName(),
|
|
71002
|
+
...activeIndex >= 0 ? { selected: activeIndex } : {}
|
|
71003
|
+
}
|
|
71004
|
+
};
|
|
71005
|
+
}
|
|
70951
71006
|
case "modePickerOpen":
|
|
70952
71007
|
return {
|
|
70953
71008
|
...state,
|
|
@@ -71357,6 +71412,11 @@ function reduceComposer(state, action) {
|
|
|
71357
71412
|
case "themePickerClose":
|
|
71358
71413
|
case "themePickerMove":
|
|
71359
71414
|
case "themePickerHint":
|
|
71415
|
+
case "themePickerFilter":
|
|
71416
|
+
case "themePickerFilterMode":
|
|
71417
|
+
case "themePickerPreview":
|
|
71418
|
+
case "themePickerUndo":
|
|
71419
|
+
case "themePickerSwapPrevious":
|
|
71360
71420
|
case "modePickerOpen":
|
|
71361
71421
|
case "modePickerClose":
|
|
71362
71422
|
case "modePickerMove":
|
|
@@ -73257,6 +73317,7 @@ function reduceSettingsPanel(state, action) {
|
|
|
73257
73317
|
featureMemory: action.featureMemory,
|
|
73258
73318
|
featureSkills: action.featureSkills,
|
|
73259
73319
|
featureModelsRegistry: action.featureModelsRegistry,
|
|
73320
|
+
featureToolCoach: action.featureToolCoach,
|
|
73260
73321
|
tokenSavingTier: action.tokenSavingTier,
|
|
73261
73322
|
allowOutsideProjectRoot: action.allowOutsideProjectRoot,
|
|
73262
73323
|
contextAutoCompact: action.contextAutoCompact,
|
|
@@ -73851,6 +73912,11 @@ function reduceSettingsValues(state, action) {
|
|
|
73851
73912
|
hint: void 0
|
|
73852
73913
|
}
|
|
73853
73914
|
};
|
|
73915
|
+
if (f === 63)
|
|
73916
|
+
return {
|
|
73917
|
+
...state,
|
|
73918
|
+
settingsPicker: { ...sp, featureToolCoach: !sp.featureToolCoach, hint: void 0 }
|
|
73919
|
+
};
|
|
73854
73920
|
if (f >= PANEL_POSITION_FIELD_START && f - PANEL_POSITION_FIELD_START < PANEL_IDS.length) {
|
|
73855
73921
|
const PANEL_POSITION_CYCLE = ["bottom", "sidebar"];
|
|
73856
73922
|
const panelId = PANEL_IDS[f - PANEL_POSITION_FIELD_START];
|
|
@@ -75564,18 +75630,50 @@ function createChatSearchSlashCommand(deps) {
|
|
|
75564
75630
|
|
|
75565
75631
|
// src/connections-slash.ts
|
|
75566
75632
|
function createConnectionsSlashCommand(deps) {
|
|
75633
|
+
let restarting = false;
|
|
75567
75634
|
return {
|
|
75568
75635
|
name: "connections",
|
|
75569
75636
|
aliases: ["conn", "conns"],
|
|
75570
75637
|
description: "Show service connection health and restart daemons \u2014 Session Catalog, Chronicle, Codebase Index, SAGE, Kanban, Mailbox, Governance.",
|
|
75571
|
-
argsHint: "[open]",
|
|
75638
|
+
argsHint: "[open|restart]",
|
|
75572
75639
|
category: "Inspect",
|
|
75573
|
-
help: "Usage:\n /connections \u2014 open the interactive service health and restart panel\n /connections open \u2014 same as above\n",
|
|
75574
|
-
async run(args) {
|
|
75640
|
+
help: "Usage:\n /connections \u2014 open the interactive service health and restart panel\n /connections open \u2014 same as above\n /connections restart \u2014 restart all six supported project daemons without opening the panel\nGovernance is read-only and is excluded from restart.\n",
|
|
75641
|
+
async run(args, ctx) {
|
|
75575
75642
|
const trimmed = args.trim().toLowerCase();
|
|
75643
|
+
if (trimmed === "restart") {
|
|
75644
|
+
if (!ctx?.projectRoot) return { message: "No active project; cannot restart daemons." };
|
|
75645
|
+
if (restarting) return { message: "Connection daemon restart is already in progress." };
|
|
75646
|
+
restarting = true;
|
|
75647
|
+
try {
|
|
75648
|
+
const { executeConnectionAction: executeConnectionAction2, RESTARTABLE_SERVICES: RESTARTABLE_SERVICES2 } = await Promise.resolve().then(() => (init_connection_actions(), connection_actions_exports));
|
|
75649
|
+
const projectRoot = ctx.projectRoot;
|
|
75650
|
+
const lines = [];
|
|
75651
|
+
let succeeded = 0;
|
|
75652
|
+
for (const serviceId of RESTARTABLE_SERVICES2) {
|
|
75653
|
+
try {
|
|
75654
|
+
const result = await executeConnectionAction2(serviceId, "restart", projectRoot);
|
|
75655
|
+
if (result.success) succeeded++;
|
|
75656
|
+
lines.push(`${result.success ? "OK" : "FAILED"} ${serviceId}: ${result.message}`);
|
|
75657
|
+
} catch (error) {
|
|
75658
|
+
lines.push(
|
|
75659
|
+
`FAILED ${serviceId}: ${error instanceof Error ? error.message : String(error)}`
|
|
75660
|
+
);
|
|
75661
|
+
}
|
|
75662
|
+
}
|
|
75663
|
+
return {
|
|
75664
|
+
message: [
|
|
75665
|
+
`Restarted ${succeeded}/${RESTARTABLE_SERVICES2.length} project daemons.`,
|
|
75666
|
+
...lines,
|
|
75667
|
+
"Governance skipped: read-only service."
|
|
75668
|
+
].join("\n")
|
|
75669
|
+
};
|
|
75670
|
+
} finally {
|
|
75671
|
+
restarting = false;
|
|
75672
|
+
}
|
|
75673
|
+
}
|
|
75576
75674
|
const panelRequest = trimmed === "" || trimmed === "open" || trimmed === "--open";
|
|
75577
75675
|
if (!panelRequest) {
|
|
75578
|
-
return { message: "Usage: /connections [open]" };
|
|
75676
|
+
return { message: "Usage: /connections [open|restart]" };
|
|
75579
75677
|
}
|
|
75580
75678
|
const opened = deps.onPanelOpen?.current?.("toggleConnectionsPanel") ?? false;
|
|
75581
75679
|
if (opened) return { message: "" };
|
|
@@ -79586,6 +79684,50 @@ import {
|
|
|
79586
79684
|
matchTodoIdFromPrompt
|
|
79587
79685
|
} from "@wrongstack/tools/auto-proceed-loop-guard";
|
|
79588
79686
|
import { todoTool } from "@wrongstack/tools/todo";
|
|
79687
|
+
|
|
79688
|
+
// src/hooks/failed-run-tracker.ts
|
|
79689
|
+
var FAILED_RUN_CONTINUE_PROMPT = "The previous run stopped on an API error (the provider failed after its retries), not on a decision of mine. Continue from where it stopped; do not redo work that is already done. If you cannot tell how far it got, say so and stop.";
|
|
79690
|
+
function createFailedRunTracker(events, leaderSessionId) {
|
|
79691
|
+
let providerFailure = null;
|
|
79692
|
+
let pendingFailure = false;
|
|
79693
|
+
const isLeader = (sessionId) => {
|
|
79694
|
+
const leader = leaderSessionId();
|
|
79695
|
+
return sessionId === void 0 || leader === void 0 || sessionId === leader;
|
|
79696
|
+
};
|
|
79697
|
+
const offs = [
|
|
79698
|
+
events.on("agent.run.started", (e) => {
|
|
79699
|
+
if (!isLeader(e.sessionId)) return;
|
|
79700
|
+
providerFailure = null;
|
|
79701
|
+
pendingFailure = false;
|
|
79702
|
+
}),
|
|
79703
|
+
events.on("provider.error", (e) => {
|
|
79704
|
+
if (!isLeader(e.sessionId)) return;
|
|
79705
|
+
providerFailure = { retryable: e.retryable };
|
|
79706
|
+
}),
|
|
79707
|
+
events.on("provider.response", (e) => {
|
|
79708
|
+
if (!isLeader(e.sessionId)) return;
|
|
79709
|
+
providerFailure = null;
|
|
79710
|
+
}),
|
|
79711
|
+
events.on("agent.run.completed", (e) => {
|
|
79712
|
+
if (!isLeader(e.sessionId)) return;
|
|
79713
|
+
pendingFailure = e.status === "failed" && providerFailure?.retryable === true;
|
|
79714
|
+
providerFailure = null;
|
|
79715
|
+
})
|
|
79716
|
+
];
|
|
79717
|
+
return {
|
|
79718
|
+
pending: () => pendingFailure,
|
|
79719
|
+
consume() {
|
|
79720
|
+
const had = pendingFailure;
|
|
79721
|
+
pendingFailure = false;
|
|
79722
|
+
return had;
|
|
79723
|
+
},
|
|
79724
|
+
dispose() {
|
|
79725
|
+
for (const off of offs) off();
|
|
79726
|
+
}
|
|
79727
|
+
};
|
|
79728
|
+
}
|
|
79729
|
+
|
|
79730
|
+
// src/hooks/use-next-steps-auto-submit.ts
|
|
79589
79731
|
async function commitTodoTransition(agent, todos) {
|
|
79590
79732
|
if (!agent?.ctx?.state) return null;
|
|
79591
79733
|
try {
|
|
@@ -79600,7 +79742,8 @@ function selectAutoProceedCandidate({
|
|
|
79600
79742
|
suggestions = [],
|
|
79601
79743
|
autoSuggestions = [],
|
|
79602
79744
|
yolo = false,
|
|
79603
|
-
autonomyNextPrompt
|
|
79745
|
+
autonomyNextPrompt,
|
|
79746
|
+
failedRun = false
|
|
79604
79747
|
}) {
|
|
79605
79748
|
const todo = resolveContinuation({ todos, suggestions: [] });
|
|
79606
79749
|
if (todo.source === "todo") {
|
|
@@ -79612,7 +79755,12 @@ function selectAutoProceedCandidate({
|
|
|
79612
79755
|
return { source: "auto-suggestion", prompt, label: automatic };
|
|
79613
79756
|
}
|
|
79614
79757
|
const suggestion = suggestions.find((item) => item.trim().length > 0)?.trim();
|
|
79615
|
-
|
|
79758
|
+
if (suggestion) return { source: "suggestion", prompt: suggestion, label: suggestion };
|
|
79759
|
+
return failedRun ? {
|
|
79760
|
+
source: "failed-run",
|
|
79761
|
+
prompt: FAILED_RUN_CONTINUE_PROMPT,
|
|
79762
|
+
label: "resume after the API error"
|
|
79763
|
+
} : null;
|
|
79616
79764
|
}
|
|
79617
79765
|
function useNextStepsAutoSubmit({
|
|
79618
79766
|
state,
|
|
@@ -79646,6 +79794,17 @@ function useNextStepsAutoSubmit({
|
|
|
79646
79794
|
const autoSubmitLoopGuardRef = (0, import_react135.useRef)(createAutoProceedLoopGuard());
|
|
79647
79795
|
const continuationAttemptTrackerRef = (0, import_react135.useRef)(createContinuationAttemptTracker());
|
|
79648
79796
|
const [nextStepsRecheck, setNextStepsRecheck] = (0, import_react135.useState)(0);
|
|
79797
|
+
const failedRunTrackerRef = (0, import_react135.useRef)(null);
|
|
79798
|
+
(0, import_react135.useEffect)(() => {
|
|
79799
|
+
const events = agent?.events;
|
|
79800
|
+
if (!events) return;
|
|
79801
|
+
const tracker = createFailedRunTracker(events, () => agent?.ctx?.session?.id);
|
|
79802
|
+
failedRunTrackerRef.current = tracker;
|
|
79803
|
+
return () => {
|
|
79804
|
+
tracker.dispose();
|
|
79805
|
+
failedRunTrackerRef.current = null;
|
|
79806
|
+
};
|
|
79807
|
+
}, [agent]);
|
|
79649
79808
|
(0, import_react135.useEffect)(() => {
|
|
79650
79809
|
autoSubmitStreakRef.current = 0;
|
|
79651
79810
|
autoSubmitCapWarnedRef.current = false;
|
|
@@ -79665,7 +79824,7 @@ function useNextStepsAutoSubmit({
|
|
|
79665
79824
|
nextStepsAutoSubmitTodoIdRef.current = null;
|
|
79666
79825
|
return;
|
|
79667
79826
|
}
|
|
79668
|
-
if (state.autoProceedHold) {
|
|
79827
|
+
if (state.autoProceedHold || state.steeringPending) {
|
|
79669
79828
|
clearInterval(nextStepsAutoSubmitTimerRef.current);
|
|
79670
79829
|
nextStepsAutoSubmitTimerRef.current = void 0;
|
|
79671
79830
|
setNextStepsAutoSubmitCountdown(null);
|
|
@@ -79691,7 +79850,8 @@ function useNextStepsAutoSubmit({
|
|
|
79691
79850
|
suggestions,
|
|
79692
79851
|
autoSuggestions: isYolo ? getAutoSuggestions?.() ?? [] : [],
|
|
79693
79852
|
yolo: isYolo,
|
|
79694
|
-
autonomyNextPrompt
|
|
79853
|
+
autonomyNextPrompt,
|
|
79854
|
+
failedRun: failedRunTrackerRef.current?.pending() ?? false
|
|
79695
79855
|
});
|
|
79696
79856
|
nextStepsAutoSubmitTodosRef.current = allTodos;
|
|
79697
79857
|
if (!candidate) {
|
|
@@ -79742,6 +79902,7 @@ function useNextStepsAutoSubmit({
|
|
|
79742
79902
|
nextStepsAutoSubmitSuggestionRef.current = null;
|
|
79743
79903
|
nextStepsAutoSubmitSourceRef.current = null;
|
|
79744
79904
|
nextStepsAutoSubmitTodoIdRef.current = null;
|
|
79905
|
+
if (source === "failed-run") failedRunTrackerRef.current?.consume();
|
|
79745
79906
|
if (suggestion) {
|
|
79746
79907
|
if (source === "todo" && todoId) {
|
|
79747
79908
|
if (agent?.ctx?.state) {
|
|
@@ -79835,7 +79996,7 @@ function useNextStepsAutoSubmit({
|
|
|
79835
79996
|
}
|
|
79836
79997
|
setSuggestions?.([]);
|
|
79837
79998
|
const truncatedForMessage = suggestion.length > 100 ? `${suggestion.slice(0, 97)}\u2026` : suggestion;
|
|
79838
|
-
const reason = source === "todo" ? stalledMatchFailed ? "the stalled prompt could not be matched to any todo on the board" : "No more open todos to advance to" : `the same prompt was fed ${repetition.runLength} times in a row`;
|
|
79999
|
+
const reason = source === "failed-run" ? "the run failed on an API error again after one automatic retry" : source === "todo" ? stalledMatchFailed ? "the stalled prompt could not be matched to any todo on the board" : "No more open todos to advance to" : `the same prompt was fed ${repetition.runLength} times in a row`;
|
|
79839
80000
|
dispatch({
|
|
79840
80001
|
type: "addEntry",
|
|
79841
80002
|
entry: {
|
|
@@ -79879,6 +80040,7 @@ ${GROUNDED_NO_PROGRESS_STEER}` : suggestion;
|
|
|
79879
80040
|
}, [
|
|
79880
80041
|
state.status,
|
|
79881
80042
|
state.autoProceedHold,
|
|
80043
|
+
state.steeringPending,
|
|
79882
80044
|
autonomyLive,
|
|
79883
80045
|
state.enhance,
|
|
79884
80046
|
state.enhanceBusy,
|
|
@@ -80127,6 +80289,7 @@ function usePanelControllers({
|
|
|
80127
80289
|
featureMemory: s2.featureMemory ?? true,
|
|
80128
80290
|
featureSkills: s2.featureSkills ?? true,
|
|
80129
80291
|
featureModelsRegistry: s2.featureModelsRegistry ?? true,
|
|
80292
|
+
featureToolCoach: s2.featureToolCoach ?? true,
|
|
80130
80293
|
tokenSavingTier: s2.featureTokenSaving ?? "off",
|
|
80131
80294
|
allowOutsideProjectRoot: s2.allowOutsideProjectRoot ?? true,
|
|
80132
80295
|
contextAutoCompact: s2.contextAutoCompact ?? true,
|
|
@@ -82164,36 +82327,51 @@ function useThemePickerHandler({
|
|
|
82164
82327
|
configStore,
|
|
82165
82328
|
saveThemePreset,
|
|
82166
82329
|
dispatch,
|
|
82167
|
-
selectedIndex: selectedIndex2
|
|
82330
|
+
selectedIndex: selectedIndex2,
|
|
82331
|
+
filter,
|
|
82332
|
+
previous
|
|
82168
82333
|
}) {
|
|
82334
|
+
const applyPreset = (0, import_react149.useCallback)(
|
|
82335
|
+
(presetName, verb) => {
|
|
82336
|
+
setActiveTheme(presetName);
|
|
82337
|
+
try {
|
|
82338
|
+
configStore?.update({ themePreset: presetName });
|
|
82339
|
+
void saveThemePreset?.(presetName).catch((err) => {
|
|
82340
|
+
dispatch({
|
|
82341
|
+
type: "addEntry",
|
|
82342
|
+
entry: {
|
|
82343
|
+
kind: "warn",
|
|
82344
|
+
text: `Theme applied in-memory but could not persist to disk: ${err instanceof Error ? err.message : String(err)}`
|
|
82345
|
+
}
|
|
82346
|
+
});
|
|
82347
|
+
});
|
|
82348
|
+
} catch {
|
|
82349
|
+
}
|
|
82350
|
+
dispatch({
|
|
82351
|
+
type: "addEntry",
|
|
82352
|
+
entry: {
|
|
82353
|
+
kind: "info",
|
|
82354
|
+
text: `Theme preset ${verb} "${presetName}"${getActiveThemeName() === presetName ? "" : ` (fallback applied: ${getActiveThemeName()})`}.`
|
|
82355
|
+
}
|
|
82356
|
+
});
|
|
82357
|
+
},
|
|
82358
|
+
[configStore, dispatch, saveThemePreset]
|
|
82359
|
+
);
|
|
82169
82360
|
const onThemePickerEnter = (0, import_react149.useCallback)(() => {
|
|
82170
|
-
const preset = THEME_OPTIONS[Math.max(0, selectedIndex2)];
|
|
82361
|
+
const preset = filterThemeOptions(THEME_OPTIONS, filter ?? "")[Math.max(0, selectedIndex2)];
|
|
82171
82362
|
const presetName = preset?.id;
|
|
82172
82363
|
if (!presetName) return;
|
|
82173
|
-
|
|
82174
|
-
try {
|
|
82175
|
-
configStore?.update({ themePreset: presetName });
|
|
82176
|
-
void saveThemePreset?.(presetName).catch((err) => {
|
|
82177
|
-
dispatch({
|
|
82178
|
-
type: "addEntry",
|
|
82179
|
-
entry: {
|
|
82180
|
-
kind: "warn",
|
|
82181
|
-
text: `Theme applied in-memory but could not persist to disk: ${err instanceof Error ? err.message : String(err)}`
|
|
82182
|
-
}
|
|
82183
|
-
});
|
|
82184
|
-
});
|
|
82185
|
-
} catch {
|
|
82186
|
-
}
|
|
82187
|
-
dispatch({
|
|
82188
|
-
type: "addEntry",
|
|
82189
|
-
entry: {
|
|
82190
|
-
kind: "info",
|
|
82191
|
-
text: `Theme preset switched to "${presetName}"${getActiveThemeName() === presetName ? "" : ` (fallback applied: ${getActiveThemeName()})`}.`
|
|
82192
|
-
}
|
|
82193
|
-
});
|
|
82364
|
+
applyPreset(presetName, "switched to");
|
|
82194
82365
|
dispatch({ type: "themePickerClose" });
|
|
82195
|
-
}, [
|
|
82196
|
-
|
|
82366
|
+
}, [applyPreset, dispatch, filter, selectedIndex2]);
|
|
82367
|
+
const onThemePickerUndo = (0, import_react149.useCallback)(() => {
|
|
82368
|
+
if (previous === void 0 || previous === getActiveThemeName()) return;
|
|
82369
|
+
const current = getActiveThemeName();
|
|
82370
|
+
applyPreset(previous, "restored to");
|
|
82371
|
+
dispatch({ type: "themePickerHint", text: `Undid \u2192 ${previous} (was ${current})` });
|
|
82372
|
+
dispatch({ type: "themePickerSwapPrevious" });
|
|
82373
|
+
}, [applyPreset, dispatch, previous]);
|
|
82374
|
+
return { onThemePickerEnter, onThemePickerUndo };
|
|
82197
82375
|
}
|
|
82198
82376
|
|
|
82199
82377
|
// src/hooks/use-tui-controllers.ts
|
|
@@ -83598,7 +83776,8 @@ function useSettingsSlashCommands(deps, part) {
|
|
|
83598
83776
|
state,
|
|
83599
83777
|
hiddenItemsRef,
|
|
83600
83778
|
setHiddenItems,
|
|
83601
|
-
openStatuslinePicker
|
|
83779
|
+
openStatuslinePicker,
|
|
83780
|
+
applyThemePreset
|
|
83602
83781
|
} = deps;
|
|
83603
83782
|
(0, import_react158.useEffect)(() => {
|
|
83604
83783
|
if (part !== "core") return;
|
|
@@ -83870,10 +84049,11 @@ Available chords:
|
|
|
83870
84049
|
message: `Unknown theme preset "${arg}". Available: ${names}`
|
|
83871
84050
|
};
|
|
83872
84051
|
}
|
|
83873
|
-
|
|
83874
|
-
|
|
83875
|
-
|
|
83876
|
-
}
|
|
84052
|
+
if (applyThemePreset) {
|
|
84053
|
+
applyThemePreset(THEME_OPTIONS[presetIdx].id);
|
|
84054
|
+
return { message: void 0 };
|
|
84055
|
+
}
|
|
84056
|
+
dispatch({ type: "themePickerOpen", selected: presetIdx });
|
|
83877
84057
|
return { message: void 0 };
|
|
83878
84058
|
}
|
|
83879
84059
|
dispatch({ type: "themePickerOpen" });
|
|
@@ -83909,7 +84089,10 @@ function useTuiSlashCommands({
|
|
|
83909
84089
|
setMailboxPanelOpen,
|
|
83910
84090
|
switchAutonomy,
|
|
83911
84091
|
listSessions,
|
|
83912
|
-
openPromptPicker
|
|
84092
|
+
openPromptPicker,
|
|
84093
|
+
configStore,
|
|
84094
|
+
saveThemePreset,
|
|
84095
|
+
applyThemePreset
|
|
83913
84096
|
}) {
|
|
83914
84097
|
const sliceDeps = {
|
|
83915
84098
|
slashRegistry,
|
|
@@ -83932,7 +84115,10 @@ function useTuiSlashCommands({
|
|
|
83932
84115
|
setMailboxPanelOpen,
|
|
83933
84116
|
switchAutonomy,
|
|
83934
84117
|
listSessions,
|
|
83935
|
-
openPromptPicker
|
|
84118
|
+
openPromptPicker,
|
|
84119
|
+
configStore,
|
|
84120
|
+
saveThemePreset,
|
|
84121
|
+
applyThemePreset
|
|
83936
84122
|
};
|
|
83937
84123
|
useSessionSlashCommands(sliceDeps, "head");
|
|
83938
84124
|
useProviderSlashCommands(sliceDeps);
|
|
@@ -84271,6 +84457,7 @@ function routeSettingsOverlayKey(host, input, key2, isEnter) {
|
|
|
84271
84457
|
featureMemory: config.featureMemory ?? true,
|
|
84272
84458
|
featureSkills: config.featureSkills ?? true,
|
|
84273
84459
|
featureModelsRegistry: config.featureModelsRegistry ?? true,
|
|
84460
|
+
featureToolCoach: config.featureToolCoach ?? true,
|
|
84274
84461
|
tokenSavingTier: config.featureTokenSaving ?? "off",
|
|
84275
84462
|
allowOutsideProjectRoot: config.allowOutsideProjectRoot ?? true,
|
|
84276
84463
|
contextAutoCompact: config.contextAutoCompact ?? true,
|
|
@@ -87190,19 +87377,33 @@ function tryAuthModelPickerKeys(host, input, key2, isEnter, debouncedEnter2) {
|
|
|
87190
87377
|
if (state.themePicker.open) {
|
|
87191
87378
|
if (key2.ctrl || key2.meta) return true;
|
|
87192
87379
|
if (key2.escape) {
|
|
87380
|
+
if (state.themePicker.preview) {
|
|
87381
|
+
if (state.themePicker.previous) setActiveTheme(state.themePicker.previous);
|
|
87382
|
+
dispatch({ type: "themePickerPreview", on: false });
|
|
87383
|
+
dispatch({ type: "themePickerClose" });
|
|
87384
|
+
return true;
|
|
87385
|
+
}
|
|
87386
|
+
if (state.themePicker.filtering || state.themePicker.filter) {
|
|
87387
|
+
dispatch({ type: "themePickerFilterMode", on: false });
|
|
87388
|
+
return true;
|
|
87389
|
+
}
|
|
87193
87390
|
dispatch({ type: "themePickerClose" });
|
|
87194
87391
|
return true;
|
|
87195
87392
|
}
|
|
87196
|
-
if (
|
|
87197
|
-
dispatch({ type: "
|
|
87198
|
-
return true;
|
|
87199
|
-
}
|
|
87200
|
-
if (key2.upArrow) {
|
|
87201
|
-
dispatch({ type: "themePickerMove", delta: -1 });
|
|
87393
|
+
if (!state.themePicker.filtering && input === "p") {
|
|
87394
|
+
dispatch({ type: "themePickerPreview", on: !state.themePicker.preview });
|
|
87202
87395
|
return true;
|
|
87203
87396
|
}
|
|
87204
|
-
|
|
87205
|
-
|
|
87397
|
+
const previewed = state.themePicker.preview;
|
|
87398
|
+
const moveBy = key2.mouse?.kind === "wheel" ? key2.mouse.wheel > 0 ? -1 : 1 : 0;
|
|
87399
|
+
if (key2.upArrow || key2.downArrow || moveBy !== 0) {
|
|
87400
|
+
const delta = key2.upArrow ? -1 : key2.downArrow ? 1 : moveBy;
|
|
87401
|
+
const next = (state.themePicker.selected + delta + filterThemeOptions(THEME_OPTIONS, state.themePicker.filter ?? "").length) % filterThemeOptions(THEME_OPTIONS, state.themePicker.filter ?? "").length;
|
|
87402
|
+
if (previewed) {
|
|
87403
|
+
const focused = filterThemeOptions(THEME_OPTIONS, state.themePicker.filter ?? "")[next];
|
|
87404
|
+
if (focused) setActiveTheme(focused.id);
|
|
87405
|
+
}
|
|
87406
|
+
dispatch({ type: "themePickerMove", delta });
|
|
87206
87407
|
return true;
|
|
87207
87408
|
}
|
|
87208
87409
|
if (isEnter) {
|
|
@@ -87215,6 +87416,30 @@ function tryAuthModelPickerKeys(host, input, key2, isEnter, debouncedEnter2) {
|
|
|
87215
87416
|
}
|
|
87216
87417
|
return true;
|
|
87217
87418
|
}
|
|
87419
|
+
const query = state.themePicker.filter ?? "";
|
|
87420
|
+
if (!key2.ctrl && input === "/") {
|
|
87421
|
+
dispatch({ type: "themePickerFilterMode", on: !state.themePicker.filtering });
|
|
87422
|
+
return true;
|
|
87423
|
+
}
|
|
87424
|
+
if (state.themePicker.filtering) {
|
|
87425
|
+
if (key2.delete || input === "\x7F" || key2.backspace) {
|
|
87426
|
+
dispatch({ type: "themePickerFilter", text: query.slice(0, -1) });
|
|
87427
|
+
return true;
|
|
87428
|
+
}
|
|
87429
|
+
if (input && !key2.ctrl && !key2.meta && input.length === 1 && input >= " ") {
|
|
87430
|
+
dispatch({ type: "themePickerFilter", text: query + input });
|
|
87431
|
+
return true;
|
|
87432
|
+
}
|
|
87433
|
+
}
|
|
87434
|
+
if (!state.themePicker.filtering && input === "u") {
|
|
87435
|
+
host.inputGateRef.current = true;
|
|
87436
|
+
try {
|
|
87437
|
+
host.onThemePickerUndo?.();
|
|
87438
|
+
} finally {
|
|
87439
|
+
host.inputGateRef.current = false;
|
|
87440
|
+
}
|
|
87441
|
+
return true;
|
|
87442
|
+
}
|
|
87218
87443
|
return true;
|
|
87219
87444
|
}
|
|
87220
87445
|
if (state.skillPicker.open) {
|
|
@@ -88148,6 +88373,7 @@ function useAppPickerKeys({
|
|
|
88148
88373
|
statuslineHiddenForPicker,
|
|
88149
88374
|
onPickerEnter,
|
|
88150
88375
|
onThemePickerEnter,
|
|
88376
|
+
onThemePickerUndo,
|
|
88151
88377
|
setPromptFavorite
|
|
88152
88378
|
}) {
|
|
88153
88379
|
const {
|
|
@@ -88646,7 +88872,8 @@ function useAppPickerKeys({
|
|
|
88646
88872
|
if (action) dispatch(action);
|
|
88647
88873
|
},
|
|
88648
88874
|
onPickerEnter,
|
|
88649
|
-
onThemePickerEnter
|
|
88875
|
+
onThemePickerEnter,
|
|
88876
|
+
onThemePickerUndo
|
|
88650
88877
|
});
|
|
88651
88878
|
}
|
|
88652
88879
|
|
|
@@ -89187,6 +89414,7 @@ function useControllerKeyPipeline({
|
|
|
89187
89414
|
statuslineHiddenForPicker,
|
|
89188
89415
|
onPickerEnter,
|
|
89189
89416
|
onThemePickerEnter,
|
|
89417
|
+
onThemePickerUndo,
|
|
89190
89418
|
setPromptFavorite,
|
|
89191
89419
|
stateRef,
|
|
89192
89420
|
exitRequestedRef,
|
|
@@ -89306,6 +89534,7 @@ function useControllerKeyPipeline({
|
|
|
89306
89534
|
statuslineHiddenForPicker,
|
|
89307
89535
|
onPickerEnter,
|
|
89308
89536
|
onThemePickerEnter,
|
|
89537
|
+
onThemePickerUndo,
|
|
89309
89538
|
setPromptFavorite
|
|
89310
89539
|
});
|
|
89311
89540
|
const { interruptsSyncRef, runInterruptLadder } = useInterruptLadder({
|
|
@@ -89926,6 +90155,30 @@ function useAppController(props) {
|
|
|
89926
90155
|
clearDraft,
|
|
89927
90156
|
runBlocksRef
|
|
89928
90157
|
});
|
|
90158
|
+
const applyThemePreset = (0, import_react163.useCallback)(
|
|
90159
|
+
(preset) => {
|
|
90160
|
+
setActiveTheme(preset);
|
|
90161
|
+
const warnPersist = (err) => dispatch({
|
|
90162
|
+
type: "addEntry",
|
|
90163
|
+
entry: {
|
|
90164
|
+
kind: "warn",
|
|
90165
|
+
text: `Theme applied in-memory but could not persist to disk: ${err instanceof Error ? err.message : String(err)}`
|
|
90166
|
+
}
|
|
90167
|
+
});
|
|
90168
|
+
try {
|
|
90169
|
+
configStore?.update({ themePreset: preset });
|
|
90170
|
+
} catch (err) {
|
|
90171
|
+
warnPersist(err);
|
|
90172
|
+
return;
|
|
90173
|
+
}
|
|
90174
|
+
try {
|
|
90175
|
+
void props.saveThemePreset?.(preset).catch(warnPersist);
|
|
90176
|
+
} catch (err) {
|
|
90177
|
+
warnPersist(err);
|
|
90178
|
+
}
|
|
90179
|
+
},
|
|
90180
|
+
[configStore, dispatch, props.saveThemePreset]
|
|
90181
|
+
);
|
|
89929
90182
|
useTuiSlashCommands({
|
|
89930
90183
|
slashRegistry,
|
|
89931
90184
|
skillLoader: props.skillLoader,
|
|
@@ -89947,7 +90200,9 @@ function useAppController(props) {
|
|
|
89947
90200
|
setMailboxPanelOpen,
|
|
89948
90201
|
switchAutonomy,
|
|
89949
90202
|
listSessions,
|
|
89950
|
-
openPromptPicker
|
|
90203
|
+
openPromptPicker,
|
|
90204
|
+
configStore,
|
|
90205
|
+
applyThemePreset
|
|
89951
90206
|
});
|
|
89952
90207
|
useProviderEventBridge({
|
|
89953
90208
|
events,
|
|
@@ -90067,11 +90322,13 @@ function useAppController(props) {
|
|
|
90067
90322
|
setDraft,
|
|
90068
90323
|
tokenPreviewsRef
|
|
90069
90324
|
});
|
|
90070
|
-
const { onThemePickerEnter } = useThemePickerHandler({
|
|
90325
|
+
const { onThemePickerEnter, onThemePickerUndo } = useThemePickerHandler({
|
|
90071
90326
|
configStore,
|
|
90072
90327
|
saveThemePreset: props.saveThemePreset,
|
|
90073
90328
|
dispatch,
|
|
90074
|
-
selectedIndex: state.themePicker.selected
|
|
90329
|
+
selectedIndex: state.themePicker.selected,
|
|
90330
|
+
filter: state.themePicker.filter,
|
|
90331
|
+
previous: state.themePicker.previous
|
|
90075
90332
|
});
|
|
90076
90333
|
const { runInterruptLadder, stableOnKey } = useControllerKeyPipeline({
|
|
90077
90334
|
sessionGenerationRef,
|
|
@@ -90098,6 +90355,7 @@ function useAppController(props) {
|
|
|
90098
90355
|
statuslineHiddenForPicker,
|
|
90099
90356
|
onPickerEnter,
|
|
90100
90357
|
onThemePickerEnter,
|
|
90358
|
+
onThemePickerUndo,
|
|
90101
90359
|
setPromptFavorite,
|
|
90102
90360
|
stateRef,
|
|
90103
90361
|
exitRequestedRef,
|