@joeyshi12/casper 0.15.7 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -6
- package/dist/mcp.js +1 -1
- package/dist/server.js +830 -733
- package/dist/web/assets/{abnfDiagram-N423BO3Z-jvSYyvNw.js → abnfDiagram-N423BO3Z-DQdd062N.js} +1 -1
- package/dist/web/assets/{arc-BiHYHdUQ.js → arc-WhOJ_KR1.js} +1 -1
- package/dist/web/assets/{architectureDiagram-T3A2C74G-4Eqc-u3C.js → architectureDiagram-T3A2C74G-3zZgBQZT.js} +1 -1
- package/dist/web/assets/{blockDiagram-VBNYF7ZC-BcOcmlBN.js → blockDiagram-VBNYF7ZC-CW9mWWLl.js} +1 -1
- package/dist/web/assets/{c4Diagram-5PPSVZJV-BUudyYqU.js → c4Diagram-5PPSVZJV-xXmfR_aG.js} +1 -1
- package/dist/web/assets/channel-QybFlytR.js +1 -0
- package/dist/web/assets/{chunk-2GRJ4B5K-bTMhoJSQ.js → chunk-2GRJ4B5K-CuCN8EG_.js} +1 -1
- package/dist/web/assets/{chunk-2Q5K7J3B-BYp6dfdp.js → chunk-2Q5K7J3B-BC-h61jv.js} +1 -1
- package/dist/web/assets/{chunk-5RXB4S5H-Dg3ASlI5.js → chunk-5RXB4S5H-BqZ4ICSN.js} +1 -1
- package/dist/web/assets/{chunk-5VM5RSS4-B7uwpCHf.js → chunk-5VM5RSS4-_EcX9Eg6.js} +1 -1
- package/dist/web/assets/{chunk-6Q2QTUOP-DVTiWdGW.js → chunk-6Q2QTUOP-Rjg4xt7f.js} +1 -1
- package/dist/web/assets/{chunk-GF5L2VYU-C2LdpbyU.js → chunk-GF5L2VYU-CllNzjfD.js} +1 -1
- package/dist/web/assets/{chunk-JWPE2WC7-CMX4-S8P.js → chunk-JWPE2WC7-Cc24s09e.js} +1 -1
- package/dist/web/assets/{chunk-KBJHAD2P-D92STFuF.js → chunk-KBJHAD2P-DYClY3b3.js} +1 -1
- package/dist/web/assets/{chunk-RYQCIY6F-B2PLxj_Q.js → chunk-RYQCIY6F-C5PSe7M_.js} +1 -1
- package/dist/web/assets/{chunk-XXDRQBXY-DCpI_0Ix.js → chunk-XXDRQBXY-DK8-XmXo.js} +1 -1
- package/dist/web/assets/classDiagram-JCYQIIEL-CcJ6l3H0.js +1 -0
- package/dist/web/assets/classDiagram-v2-OCEON4UE-CcJ6l3H0.js +1 -0
- package/dist/web/assets/{cose-bilkent-JH36ORCC-KtY-8vxF.js → cose-bilkent-JH36ORCC-Dxs4GA2q.js} +1 -1
- package/dist/web/assets/{cynefin-VYW2F7L2-DkTsGV_4.js → cynefin-VYW2F7L2-kzjViLcF.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-MW4NZA55-BVPMHgGu.js → cynefinDiagram-MW4NZA55-B9zBzt3B.js} +1 -1
- package/dist/web/assets/{dagre-VZM6K2ZE-DT-S1NOU.js → dagre-VZM6K2ZE-BNwMkCZi.js} +1 -1
- package/dist/web/assets/{diagram-7IWD3JNH-DUJvV7wV.js → diagram-7IWD3JNH-DpIoQsS7.js} +1 -1
- package/dist/web/assets/{diagram-B4RE2ZJO-DmpnY7ob.js → diagram-B4RE2ZJO-BKWdzhKi.js} +1 -1
- package/dist/web/assets/{diagram-LBJQPF4R-nEMZNwen.js → diagram-LBJQPF4R-DBbKFigX.js} +1 -1
- package/dist/web/assets/{diagram-Q27KOJAE-Dr-59ElI.js → diagram-Q27KOJAE-B7qLPRw9.js} +1 -1
- package/dist/web/assets/{diagram-UB23O5K3-4wvmRauY.js → diagram-UB23O5K3-DVncy6q5.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-BXEA7PRR-055xAlHi.js → ebnfDiagram-BXEA7PRR-B9rA3ylb.js} +1 -1
- package/dist/web/assets/{erDiagram-JOGREHBK-DqWTDG8u.js → erDiagram-JOGREHBK-BExDcOc7.js} +1 -1
- package/dist/web/assets/{flowDiagram-UKHOOZJN-D3lUh0yb.js → flowDiagram-UKHOOZJN-B1xPLh9u.js} +1 -1
- package/dist/web/assets/{ganttDiagram-PKOTCBZU-aV5l2zrT.js → ganttDiagram-PKOTCBZU-BYS5NkM6.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-DS77QQ5N-BK2KCI35.js → gitGraphDiagram-DS77QQ5N-CN4An7lt.js} +1 -1
- package/dist/web/assets/{index-Dv1My9Ob.js → index-BuQTY976.js} +1 -1
- package/dist/web/assets/{index-B5ZDbS-R.js → index-BwBYAAwi.js} +48 -48
- package/dist/web/assets/{infoDiagram-6WML65LV-BcSXYnWm.js → infoDiagram-6WML65LV-sk97M0G1.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-WSZJBQD7-C0LFAfcz.js → ishikawaDiagram-WSZJBQD7-BzW2rVh6.js} +1 -1
- package/dist/web/assets/{journeyDiagram-NVQOT4AX-1Zs22Gpd.js → journeyDiagram-NVQOT4AX-iaCo98OS.js} +1 -1
- package/dist/web/assets/{kanban-definition-27J2QSJJ-DW6RwD7S.js → kanban-definition-27J2QSJJ-Ce38xzYm.js} +1 -1
- package/dist/web/assets/{linear-Cfzhrbed.js → linear-BoUX9N6W.js} +1 -1
- package/dist/web/assets/{mermaid.core-D0VPssrU.js → mermaid.core-CC54dZcH.js} +4 -4
- package/dist/web/assets/{mindmap-definition-FAOFIHXS-BeD5KiWO.js → mindmap-definition-FAOFIHXS-BxRXpNJ-.js} +1 -1
- package/dist/web/assets/{pegDiagram-VL7TDLO6-JDLyI4Gc.js → pegDiagram-VL7TDLO6-Cg0-J9c8.js} +1 -1
- package/dist/web/assets/{pieDiagram-7S7Q4E2Y-BY3XpjEU.js → pieDiagram-7S7Q4E2Y-DUjXAJq4.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-CIZ2JOQS-C4oT4Lqc.js → quadrantDiagram-CIZ2JOQS-q1HsW0pP.js} +1 -1
- package/dist/web/assets/{railroadDiagram-AXF67PYL-lfzvVyK7.js → railroadDiagram-AXF67PYL-ats1_veK.js} +1 -1
- package/dist/web/assets/{requirementDiagram-LRYGKXZP-wGnOD5SS.js → requirementDiagram-LRYGKXZP-CV2_uFpI.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-W5VNT64P-DJQ2VW0G.js → sankeyDiagram-W5VNT64P-BwyC8qNn.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-SI44F4Z6-Bz_rjvWZ.js → sequenceDiagram-SI44F4Z6-72yj0uCA.js} +1 -1
- package/dist/web/assets/{sizeCapture-X5ZJPWSS-BgxIA36S.js → sizeCapture-X5ZJPWSS-CV7PeUrN.js} +1 -1
- package/dist/web/assets/{stateDiagram-OKZ733FA-DpL_B9Mu.js → stateDiagram-OKZ733FA-B08_WgjO.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-UEYNNEHI-80B2GltS.js +1 -0
- package/dist/web/assets/{swimlanes-SLNWSIFB-B6uTv46X.js → swimlanes-SLNWSIFB-DnBKpTQH.js} +2 -2
- package/dist/web/assets/swimlanesDiagram-ULZ7WXOC-CeWA7IPZ.js +8 -0
- package/dist/web/assets/{timeline-definition-Z64GVDOM-DvMUcNNs.js → timeline-definition-Z64GVDOM-BAoT5Fu8.js} +1 -1
- package/dist/web/assets/{vennDiagram-T6HMQDX7-K_9U-J2A.js → vennDiagram-T6HMQDX7-VLzfwvza.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-T6FBY63Y-DwMi4kCd.js → wardleyDiagram-T6FBY63Y-QaCRHB2e.js} +1 -1
- package/dist/web/assets/{xychartDiagram-ELKLHX3M-BkcnShpk.js → xychartDiagram-ELKLHX3M-DCUP6k1x.js} +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/dist/web/assets/channel-BueZNEdT.js +0 -1
- package/dist/web/assets/classDiagram-JCYQIIEL-CSEqsvyn.js +0 -1
- package/dist/web/assets/classDiagram-v2-OCEON4UE-CSEqsvyn.js +0 -1
- package/dist/web/assets/stateDiagram-v2-UEYNNEHI-DsD9j9Fu.js +0 -1
- package/dist/web/assets/swimlanesDiagram-ULZ7WXOC-BxNKQaPC.js +0 -8
package/dist/server.js
CHANGED
|
@@ -118,13 +118,9 @@ function agentConfig(prompt, mcp) {
|
|
|
118
118
|
casper: mcp ? { command: process.execPath, args: [mcp], env: {}, timeout: 1e4 } : { command: "casper", args: ["mcp"], env: {}, timeout: 1e4 }
|
|
119
119
|
},
|
|
120
120
|
tools: ["*"],
|
|
121
|
-
toolAliases: {},
|
|
122
|
-
allowedTools: [],
|
|
123
121
|
resources: [],
|
|
124
|
-
hooks:
|
|
125
|
-
|
|
126
|
-
includeMcpJson: true,
|
|
127
|
-
model: null
|
|
122
|
+
hooks: [],
|
|
123
|
+
includeMcpJson: true
|
|
128
124
|
};
|
|
129
125
|
}
|
|
130
126
|
function installAgentFile(home2, dataDir) {
|
|
@@ -317,17 +313,18 @@ var init_config = __esm({
|
|
|
317
313
|
kiroBin: resolveKiroBin(setting("KIRO_BIN", "kiroBin", "kiro-cli"), home),
|
|
318
314
|
defaultCwd: setting("DEFAULT_CWD", "defaultCwd", process.cwd()),
|
|
319
315
|
maxLiveSessions: settingInt("MAX_LIVE_SESSIONS", "maxLiveSessions", 6),
|
|
320
|
-
/** The agent Casper installs, with the widget tools.
|
|
321
|
-
* if missing rather than failing. */
|
|
316
|
+
/** The agent Casper installs, with the widget tools. kiro falls back to its Default
|
|
317
|
+
* mode if it is missing rather than failing. */
|
|
322
318
|
defaultAgent: setting("DEFAULT_AGENT", "defaultAgent", "casper"),
|
|
323
319
|
/** Filesystem root the file endpoints are confined to. Defaults to /; narrow it
|
|
324
320
|
* to keep authenticated users out of system files such as /etc or SSH keys. */
|
|
325
321
|
fileRoot: path5.resolve(setting("CASPER_FILE_ROOT", "fileRoot", "/")),
|
|
322
|
+
/** kiro's session store, one directory per workspace. */
|
|
326
323
|
kiroSessionsDir: path5.resolve(
|
|
327
324
|
setting(
|
|
328
325
|
"CASPER_KIRO_SESSIONS_DIR",
|
|
329
326
|
"kiroSessionsDir",
|
|
330
|
-
path5.join(home, ".kiro", "sessions"
|
|
327
|
+
path5.join(home, ".kiro", "sessions")
|
|
331
328
|
)
|
|
332
329
|
),
|
|
333
330
|
casperDataDir: dataDirPath(),
|
|
@@ -403,13 +400,6 @@ CREATE TABLE IF NOT EXISTS turn_endings (
|
|
|
403
400
|
items TEXT NOT NULL
|
|
404
401
|
);
|
|
405
402
|
CREATE INDEX IF NOT EXISTS turn_endings_chat ON turn_endings (chat_id);
|
|
406
|
-
CREATE TABLE IF NOT EXISTS subagent_links (
|
|
407
|
-
child_session_id TEXT PRIMARY KEY,
|
|
408
|
-
parent_session_id TEXT NOT NULL,
|
|
409
|
-
tool_call_id TEXT NOT NULL,
|
|
410
|
-
stage_name TEXT NOT NULL
|
|
411
|
-
);
|
|
412
|
-
CREATE INDEX IF NOT EXISTS subagent_links_parent ON subagent_links (parent_session_id);
|
|
413
403
|
`;
|
|
414
404
|
}
|
|
415
405
|
});
|
|
@@ -639,10 +629,22 @@ function isJsonRpcError(m) {
|
|
|
639
629
|
function isJsonRpcNotification(m) {
|
|
640
630
|
return !("id" in m) && "method" in m;
|
|
641
631
|
}
|
|
642
|
-
|
|
632
|
+
function kiroToolName(call) {
|
|
633
|
+
const meta = call._meta?.kiro;
|
|
634
|
+
if (meta?.kind === "agent-subtask")
|
|
635
|
+
return SUBAGENT_TOOL;
|
|
636
|
+
const server = meta?.serverName;
|
|
637
|
+
if (!server)
|
|
638
|
+
return void 0;
|
|
639
|
+
const title = call.title ?? "";
|
|
640
|
+
const prefix = `@${server}/`;
|
|
641
|
+
return `${server}/${title.startsWith(prefix) ? title.slice(prefix.length) : title}`;
|
|
642
|
+
}
|
|
643
|
+
var SUBAGENT_TOOL, ACP_METHODS, KIRO_AGENT_NOT_FOUND;
|
|
643
644
|
var init_acp = __esm({
|
|
644
645
|
"shared/dist/acp.js"() {
|
|
645
646
|
"use strict";
|
|
647
|
+
SUBAGENT_TOOL = "invoke_sub_agent";
|
|
646
648
|
ACP_METHODS = {
|
|
647
649
|
initialize: "initialize",
|
|
648
650
|
sessionNew: "session/new",
|
|
@@ -650,19 +652,12 @@ var init_acp = __esm({
|
|
|
650
652
|
sessionPrompt: "session/prompt",
|
|
651
653
|
sessionCancel: "session/cancel",
|
|
652
654
|
sessionSetMode: "session/set_mode",
|
|
653
|
-
|
|
655
|
+
sessionSetConfigOption: "session/set_config_option",
|
|
654
656
|
sessionUpdate: "session/update",
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
KIRO_NOTIFICATIONS = {
|
|
658
|
-
metadata: "_kiro.dev/metadata",
|
|
659
|
-
subagentListUpdate: "_kiro.dev/subagent/list_update",
|
|
660
|
-
mcpServerInitialized: "_kiro.dev/mcp/server_initialized",
|
|
661
|
-
mcpServerInitFailure: "_kiro.dev/mcp/server_init_failure",
|
|
662
|
-
commandsAvailable: "_kiro.dev/commands/available",
|
|
663
|
-
mcpOauthRequest: "_kiro.dev/mcp/oauth_request",
|
|
664
|
-
compactionStatus: "_kiro.dev/compaction/status"
|
|
657
|
+
requestPermission: "session/request_permission",
|
|
658
|
+
compact: "_kiro/session/compact"
|
|
665
659
|
};
|
|
660
|
+
KIRO_AGENT_NOT_FOUND = "_kiro/customAgent/not_found";
|
|
666
661
|
}
|
|
667
662
|
});
|
|
668
663
|
|
|
@@ -759,7 +754,7 @@ function foldSessionUpdate(draft, u, seq, ts) {
|
|
|
759
754
|
}
|
|
760
755
|
if (u.sessionUpdate === "tool_call") {
|
|
761
756
|
const tc = u;
|
|
762
|
-
const toolName = tc
|
|
757
|
+
const toolName = kiroToolName(tc);
|
|
763
758
|
return {
|
|
764
759
|
items: [
|
|
765
760
|
...commitDraft(draft, `s-${seq}`, ts),
|
|
@@ -801,6 +796,7 @@ var emptyDraft;
|
|
|
801
796
|
var init_turnFold = __esm({
|
|
802
797
|
"shared/dist/turnFold.js"() {
|
|
803
798
|
"use strict";
|
|
799
|
+
init_acp();
|
|
804
800
|
emptyDraft = () => ({ items: [], streamingText: "", streamingThought: "" });
|
|
805
801
|
}
|
|
806
802
|
});
|
|
@@ -831,10 +827,15 @@ import { execFile } from "node:child_process";
|
|
|
831
827
|
import { promisify } from "node:util";
|
|
832
828
|
function invalidateAgents() {
|
|
833
829
|
cache = null;
|
|
830
|
+
liveModes = null;
|
|
831
|
+
}
|
|
832
|
+
function rememberModes(modes) {
|
|
833
|
+
if (modes.length > 0) liveModes = modes;
|
|
834
834
|
}
|
|
835
835
|
async function listAgents() {
|
|
836
|
+
if (liveModes) return liveModes;
|
|
836
837
|
if (cache && Date.now() - cache.at < CACHE_TTL_MS) return cache.agents;
|
|
837
|
-
const found = /* @__PURE__ */ new Map();
|
|
838
|
+
const found = /* @__PURE__ */ new Map([[DEFAULT_MODE.id, DEFAULT_MODE]]);
|
|
838
839
|
try {
|
|
839
840
|
const { stdout, stderr } = await execFileAsync(config.kiroBin, ["agent", "list"], {
|
|
840
841
|
cwd: config.defaultCwd,
|
|
@@ -843,30 +844,26 @@ async function listAgents() {
|
|
|
843
844
|
const text2 = (stderr || "") + "\n" + (stdout || "");
|
|
844
845
|
for (const rawLine of text2.split("\n")) {
|
|
845
846
|
const line = rawLine.replace(ANSI, "");
|
|
846
|
-
const m = /^\s{0,2}(\*\s)?([A-Za-z0-9_-]+)\s{2,}(
|
|
847
|
-
line
|
|
848
|
-
);
|
|
847
|
+
const m = /^\s{0,2}(\*\s)?([A-Za-z0-9_-]+)\s{2,}(Global|Workspace|Local)(?:\s|$)/.exec(line);
|
|
849
848
|
if (!m) continue;
|
|
850
849
|
const id = m[2];
|
|
851
850
|
if (!found.has(id)) found.set(id, { id, name: id });
|
|
852
851
|
}
|
|
853
852
|
} catch {
|
|
854
853
|
}
|
|
855
|
-
|
|
856
|
-
cache = { at: Date.now(), agents };
|
|
854
|
+
cache = { at: Date.now(), agents: [...found.values()] };
|
|
857
855
|
return cache.agents;
|
|
858
856
|
}
|
|
859
|
-
var execFileAsync,
|
|
857
|
+
var execFileAsync, DEFAULT_MODE, CACHE_TTL_MS, cache, liveModes, ANSI;
|
|
860
858
|
var init_agents = __esm({
|
|
861
859
|
"server/src/session/agents.ts"() {
|
|
862
860
|
"use strict";
|
|
863
861
|
init_config();
|
|
864
862
|
execFileAsync = promisify(execFile);
|
|
865
|
-
|
|
866
|
-
{ id: "kiro_default", name: "kiro_default", description: "General-purpose Kiro agent" }
|
|
867
|
-
];
|
|
863
|
+
DEFAULT_MODE = { id: "vibe", name: "Default", description: "General coding assistance" };
|
|
868
864
|
CACHE_TTL_MS = 15e3;
|
|
869
865
|
cache = null;
|
|
866
|
+
liveModes = null;
|
|
870
867
|
ANSI = /\x1b\[[0-9;]*m/g;
|
|
871
868
|
}
|
|
872
869
|
});
|
|
@@ -1072,6 +1069,10 @@ var init_AcpClient = __esm({
|
|
|
1072
1069
|
if (this.closed) return;
|
|
1073
1070
|
this.write({ jsonrpc: "2.0", id, result });
|
|
1074
1071
|
}
|
|
1072
|
+
respondError(id, code, message) {
|
|
1073
|
+
if (this.closed) return;
|
|
1074
|
+
this.write({ jsonrpc: "2.0", id, error: { code, message } });
|
|
1075
|
+
}
|
|
1075
1076
|
write(msg) {
|
|
1076
1077
|
this.writable.write(JSON.stringify(msg) + "\n");
|
|
1077
1078
|
}
|
|
@@ -1093,7 +1094,12 @@ var init_AcpClient = __esm({
|
|
|
1093
1094
|
import { spawn } from "node:child_process";
|
|
1094
1095
|
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
1095
1096
|
import split22 from "split2";
|
|
1096
|
-
|
|
1097
|
+
function permissionOutcome(params) {
|
|
1098
|
+
const options = params?.options ?? [];
|
|
1099
|
+
const pick = options.find((o) => o.kind === "allow_once") ?? options.find((o) => o.kind === "reject_once");
|
|
1100
|
+
return pick ? { outcome: { outcome: "selected", optionId: pick.optionId } } : { outcome: { outcome: "cancelled" } };
|
|
1101
|
+
}
|
|
1102
|
+
var STDERR_KEEP, COMPACT_TIMEOUT_MS, KiroProcess;
|
|
1097
1103
|
var init_KiroProcess = __esm({
|
|
1098
1104
|
"server/src/session/KiroProcess.ts"() {
|
|
1099
1105
|
"use strict";
|
|
@@ -1101,18 +1107,19 @@ var init_KiroProcess = __esm({
|
|
|
1101
1107
|
init_config();
|
|
1102
1108
|
init_AcpClient();
|
|
1103
1109
|
STDERR_KEEP = 8;
|
|
1110
|
+
COMPACT_TIMEOUT_MS = 10 * 6e4;
|
|
1104
1111
|
KiroProcess = class extends EventEmitter3 {
|
|
1105
1112
|
client;
|
|
1106
1113
|
child;
|
|
1107
1114
|
log;
|
|
1108
1115
|
disposed = false;
|
|
1109
1116
|
recentStderr = [];
|
|
1117
|
+
// kiro's optional methods, as advertised by initialize.
|
|
1118
|
+
extensionMethods = /* @__PURE__ */ new Set();
|
|
1110
1119
|
constructor(opts, log) {
|
|
1111
1120
|
super();
|
|
1112
1121
|
this.log = log;
|
|
1113
|
-
const args = ["acp", "--
|
|
1114
|
-
if (opts.agent) args.push("--agent", opts.agent);
|
|
1115
|
-
if (opts.model) args.push("--model", opts.model);
|
|
1122
|
+
const args = ["acp", "--agent-engine", "v3"];
|
|
1116
1123
|
this.log.info({ bin: config.kiroBin, args, cwd: opts.cwd }, "spawning kiro-cli acp");
|
|
1117
1124
|
this.child = spawn(config.kiroBin, args, {
|
|
1118
1125
|
cwd: opts.cwd,
|
|
@@ -1124,8 +1131,12 @@ var init_KiroProcess = __esm({
|
|
|
1124
1131
|
this.emit("notification", n);
|
|
1125
1132
|
});
|
|
1126
1133
|
this.client.on("serverRequest", (req) => {
|
|
1127
|
-
|
|
1128
|
-
|
|
1134
|
+
if (req.method === ACP_METHODS.requestPermission) {
|
|
1135
|
+
this.client.respond(req.id, permissionOutcome(req.params));
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
this.log.debug({ method: req.method }, "acp: unsupported request from kiro");
|
|
1139
|
+
this.client.respondError(req.id, -32601, `Method not found: ${req.method}`);
|
|
1129
1140
|
});
|
|
1130
1141
|
const stderrLines = this.child.stderr.pipe(split22());
|
|
1131
1142
|
stderrLines.on("data", (line) => {
|
|
@@ -1157,9 +1168,9 @@ var init_KiroProcess = __esm({
|
|
|
1157
1168
|
this.child.stdout.on("error", () => {
|
|
1158
1169
|
});
|
|
1159
1170
|
}
|
|
1160
|
-
/** The ACP initialize handshake.
|
|
1171
|
+
/** The ACP initialize handshake. Keeps the optional methods kiro advertises. */
|
|
1161
1172
|
async initialize() {
|
|
1162
|
-
await this.client.request(ACP_METHODS.initialize, {
|
|
1173
|
+
const res = await this.client.request(ACP_METHODS.initialize, {
|
|
1163
1174
|
protocolVersion: 1,
|
|
1164
1175
|
clientCapabilities: {
|
|
1165
1176
|
fs: { readTextFile: false, writeTextFile: false },
|
|
@@ -1167,6 +1178,10 @@ var init_KiroProcess = __esm({
|
|
|
1167
1178
|
},
|
|
1168
1179
|
clientInfo: { name: "casper", version: "0.5.0" }
|
|
1169
1180
|
});
|
|
1181
|
+
const methods = res?.agentCapabilities?._meta?.kiro?.extensionMethods;
|
|
1182
|
+
this.extensionMethods = new Set(
|
|
1183
|
+
Array.isArray(methods) ? methods.filter((m) => typeof m === "string") : []
|
|
1184
|
+
);
|
|
1170
1185
|
}
|
|
1171
1186
|
newSession(params) {
|
|
1172
1187
|
return this.client.request(ACP_METHODS.sessionNew, params);
|
|
@@ -1189,14 +1204,19 @@ var init_KiroProcess = __esm({
|
|
|
1189
1204
|
return this.client.request(ACP_METHODS.sessionSetMode, { sessionId, modeId });
|
|
1190
1205
|
}
|
|
1191
1206
|
setModel(sessionId, modelId) {
|
|
1192
|
-
return this.client.request(ACP_METHODS.
|
|
1193
|
-
}
|
|
1194
|
-
execCommand(sessionId, command) {
|
|
1195
|
-
return this.client.request(ACP_METHODS.commandsExecute, {
|
|
1207
|
+
return this.client.request(ACP_METHODS.sessionSetConfigOption, {
|
|
1196
1208
|
sessionId,
|
|
1197
|
-
|
|
1209
|
+
configId: "model",
|
|
1210
|
+
value: modelId
|
|
1198
1211
|
});
|
|
1199
1212
|
}
|
|
1213
|
+
/** Summarises the conversation so far. Resolves once kiro has finished. */
|
|
1214
|
+
compact(sessionId) {
|
|
1215
|
+
if (!this.extensionMethods.has(ACP_METHODS.compact)) {
|
|
1216
|
+
return Promise.reject(new Error("This kiro-cli does not offer compaction"));
|
|
1217
|
+
}
|
|
1218
|
+
return this.client.request(ACP_METHODS.compact, { sessionId }, COMPACT_TIMEOUT_MS);
|
|
1219
|
+
}
|
|
1200
1220
|
/** Recent stderr from kiro, for attaching to a failure. */
|
|
1201
1221
|
stderrTail() {
|
|
1202
1222
|
return this.recentStderr.join("\n").trim();
|
|
@@ -1418,302 +1438,383 @@ var init_SubagentTracker = __esm({
|
|
|
1418
1438
|
"server/src/session/SubagentTracker.ts"() {
|
|
1419
1439
|
"use strict";
|
|
1420
1440
|
SubagentTracker = class {
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1441
|
+
constructor(now = () => (/* @__PURE__ */ new Date()).toISOString()) {
|
|
1442
|
+
this.now = now;
|
|
1443
|
+
}
|
|
1444
|
+
byId = /* @__PURE__ */ new Map();
|
|
1445
|
+
/** The tool call that starts a subagent arrived. */
|
|
1446
|
+
started(subagentId, toolCallId, name) {
|
|
1447
|
+
if (this.byId.has(subagentId)) return false;
|
|
1448
|
+
const at = this.now();
|
|
1449
|
+
this.byId.set(subagentId, {
|
|
1450
|
+
sessionId: subagentId,
|
|
1451
|
+
stageName: name,
|
|
1452
|
+
toolCallId,
|
|
1453
|
+
status: "working",
|
|
1454
|
+
createdAt: at,
|
|
1455
|
+
updatedAt: at
|
|
1456
|
+
});
|
|
1457
|
+
return true;
|
|
1458
|
+
}
|
|
1459
|
+
/** One of the subagent's own updates arrived. `activity` is the title of a tool call it
|
|
1460
|
+
* started, which becomes the row's "what it is doing now". */
|
|
1461
|
+
progressed(subagentId, activity) {
|
|
1462
|
+
const s = this.byId.get(subagentId);
|
|
1463
|
+
if (!s || s.status !== "working") return false;
|
|
1464
|
+
s.updatedAt = this.now();
|
|
1465
|
+
if (!activity || activity === s.activity) return false;
|
|
1466
|
+
s.activity = activity;
|
|
1467
|
+
return true;
|
|
1468
|
+
}
|
|
1469
|
+
/** The call that started a subagent finished. */
|
|
1470
|
+
finished(toolCallId, ok2) {
|
|
1471
|
+
for (const s of this.byId.values()) {
|
|
1472
|
+
if (s.toolCallId !== toolCallId || s.status !== "working") continue;
|
|
1473
|
+
s.status = ok2 ? "completed" : "failed";
|
|
1474
|
+
s.activity = void 0;
|
|
1475
|
+
s.updatedAt = this.now();
|
|
1476
|
+
return true;
|
|
1456
1477
|
}
|
|
1457
|
-
return
|
|
1478
|
+
return false;
|
|
1458
1479
|
}
|
|
1459
|
-
/** Called when the parent turn ends. The
|
|
1460
|
-
*
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
this.pendingCalls.length = 0;
|
|
1465
|
-
for (const s of this.byChild.values()) {
|
|
1480
|
+
/** Called when the parent turn ends. The turn waits on its subagents, so any still
|
|
1481
|
+
* working was stopped with it, and kiro does not always report that. */
|
|
1482
|
+
turnEnded() {
|
|
1483
|
+
let changed = false;
|
|
1484
|
+
for (const s of this.byId.values()) {
|
|
1466
1485
|
if (s.status !== "working") continue;
|
|
1467
1486
|
s.status = "failed";
|
|
1468
1487
|
s.activity = "Stopped";
|
|
1469
|
-
s.updatedAt = now();
|
|
1488
|
+
s.updatedAt = this.now();
|
|
1470
1489
|
changed = true;
|
|
1471
1490
|
}
|
|
1472
1491
|
return changed;
|
|
1473
1492
|
}
|
|
1474
|
-
/**
|
|
1475
|
-
* hasn't started, so a stage waiting on a dependency still shows up. */
|
|
1476
|
-
listForCall(toolCallId) {
|
|
1477
|
-
const call = this.pendingCalls.find((c) => c.toolCallId === toolCallId);
|
|
1478
|
-
const started = [...this.byChild.values()].filter((s) => s.toolCallId === toolCallId);
|
|
1479
|
-
if (!call) return started.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
1480
|
-
const startedNames = new Set(started.map((s) => s.stageName));
|
|
1481
|
-
const pending = call.stages.filter((s) => !startedNames.has(s.name)).map((s) => ({
|
|
1482
|
-
sessionId: `pending:${toolCallId}:${s.name}`,
|
|
1483
|
-
stageName: s.name,
|
|
1484
|
-
toolCallId,
|
|
1485
|
-
status: "pending",
|
|
1486
|
-
activity: s.depends_on?.length ? `Waits for ${s.depends_on.join(" and ")}` : void 0,
|
|
1487
|
-
createdAt: "",
|
|
1488
|
-
updatedAt: ""
|
|
1489
|
-
}));
|
|
1490
|
-
return [...started.sort((a, b) => a.createdAt.localeCompare(b.createdAt)), ...pending];
|
|
1491
|
-
}
|
|
1493
|
+
/** Copies, so a recorded event keeps the state it was recorded with. */
|
|
1492
1494
|
list() {
|
|
1493
|
-
return [...this.
|
|
1495
|
+
return [...this.byId.values()].map((s) => ({ ...s })).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
1494
1496
|
}
|
|
1495
|
-
get(
|
|
1496
|
-
|
|
1497
|
+
get(subagentId) {
|
|
1498
|
+
const s = this.byId.get(subagentId);
|
|
1499
|
+
return s && { ...s };
|
|
1497
1500
|
}
|
|
1498
1501
|
};
|
|
1499
1502
|
}
|
|
1500
1503
|
});
|
|
1501
1504
|
|
|
1502
|
-
// server/src/session/
|
|
1503
|
-
function showSummaryAsAnswer(transcript) {
|
|
1504
|
-
const out = [];
|
|
1505
|
-
for (const item of transcript) {
|
|
1506
|
-
if (item.type === "message" && item.message.role === "assistant" && item.message.text.trim() === INTERRUPTED) {
|
|
1507
|
-
continue;
|
|
1508
|
-
}
|
|
1509
|
-
if (item.type === "tool_call" && item.tool.name === "summary") {
|
|
1510
|
-
const input = item.tool.input;
|
|
1511
|
-
const result = typeof input?.taskResult === "string" ? input.taskResult.trim() : "";
|
|
1512
|
-
if (result) out.push({ type: "message", message: { id: item.tool.id, role: "assistant", text: result } });
|
|
1513
|
-
continue;
|
|
1514
|
-
}
|
|
1515
|
-
out.push(item);
|
|
1516
|
-
}
|
|
1517
|
-
return out;
|
|
1518
|
-
}
|
|
1519
|
-
var INTERRUPTED;
|
|
1520
|
-
var init_subagentResult = __esm({
|
|
1521
|
-
"server/src/session/subagentResult.ts"() {
|
|
1522
|
-
"use strict";
|
|
1523
|
-
INTERRUPTED = "Tool uses were interrupted, waiting for the next user prompt";
|
|
1524
|
-
}
|
|
1525
|
-
});
|
|
1526
|
-
|
|
1527
|
-
// server/src/session/subagentFallbackMatch.ts
|
|
1528
|
-
function isStageInput(v) {
|
|
1529
|
-
return typeof v === "object" && v !== null && typeof v.name === "string";
|
|
1530
|
-
}
|
|
1531
|
-
function subagentCallInput(tool) {
|
|
1532
|
-
if (tool.name !== "subagent") return null;
|
|
1533
|
-
const input = tool.input;
|
|
1534
|
-
if (!input || !Array.isArray(input.stages)) return null;
|
|
1535
|
-
const stages = input.stages.filter(isStageInput);
|
|
1536
|
-
return { task: typeof input.task === "string" ? input.task : void 0, stages };
|
|
1537
|
-
}
|
|
1538
|
-
function expectedTitle(call, stage) {
|
|
1539
|
-
const task = call.task ?? "";
|
|
1540
|
-
const expanded = stage.prompt_template ? stage.prompt_template.replace("{task}", task) : task;
|
|
1541
|
-
return expanded.slice(0, TITLE_MAX_LENGTH);
|
|
1542
|
-
}
|
|
1543
|
-
function subagentCallsIn(transcript) {
|
|
1544
|
-
const calls = [];
|
|
1545
|
-
transcript.forEach((item, itemIndex) => {
|
|
1546
|
-
if (item.type !== "tool_call") return;
|
|
1547
|
-
const input = subagentCallInput(item.tool);
|
|
1548
|
-
if (!input) return;
|
|
1549
|
-
calls.push({ toolCallId: item.tool.id, itemIndex, input });
|
|
1550
|
-
});
|
|
1551
|
-
return calls;
|
|
1552
|
-
}
|
|
1553
|
-
function matchSubagentsFallback(calls, children) {
|
|
1554
|
-
const sortedCalls = [...calls].sort((a, b) => a.itemIndex - b.itemIndex);
|
|
1555
|
-
const unclaimed = [...children].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
1556
|
-
const matches = [];
|
|
1557
|
-
for (const call of sortedCalls) {
|
|
1558
|
-
for (const stage of call.input.stages) {
|
|
1559
|
-
const want = expectedTitle(call.input, stage);
|
|
1560
|
-
if (!want) continue;
|
|
1561
|
-
const i = unclaimed.findIndex((c) => want.startsWith(c.title) || c.title.startsWith(want));
|
|
1562
|
-
if (i < 0) continue;
|
|
1563
|
-
const child = unclaimed.splice(i, 1)[0];
|
|
1564
|
-
matches.push({ sessionId: child.sessionId, toolCallId: call.toolCallId, stageName: stage.name });
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
return matches;
|
|
1568
|
-
}
|
|
1569
|
-
var TITLE_MAX_LENGTH;
|
|
1570
|
-
var init_subagentFallbackMatch = __esm({
|
|
1571
|
-
"server/src/session/subagentFallbackMatch.ts"() {
|
|
1572
|
-
"use strict";
|
|
1573
|
-
TITLE_MAX_LENGTH = 150;
|
|
1574
|
-
}
|
|
1575
|
-
});
|
|
1576
|
-
|
|
1577
|
-
// server/src/session/kiroFiles.ts
|
|
1505
|
+
// server/src/session/kiroV3Files.ts
|
|
1578
1506
|
import fs9 from "node:fs/promises";
|
|
1579
1507
|
import path10 from "node:path";
|
|
1580
|
-
function
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
if (b.kind !== "toolUse" || !isRecord(b.data)) return null;
|
|
1585
|
-
const { toolUseId, name, input } = b.data;
|
|
1586
|
-
if (typeof toolUseId !== "string") return null;
|
|
1587
|
-
return { toolUseId, name: typeof name === "string" ? name : void 0, input };
|
|
1588
|
-
}
|
|
1589
|
-
function toolResultData(b) {
|
|
1590
|
-
if (b.kind !== "toolResult" || !isRecord(b.data)) return null;
|
|
1591
|
-
const { toolUseId, status, content } = b.data;
|
|
1592
|
-
if (typeof toolUseId !== "string") return null;
|
|
1593
|
-
return { toolUseId, status: typeof status === "string" ? status : void 0, content };
|
|
1594
|
-
}
|
|
1595
|
-
function contentBlocks(content) {
|
|
1596
|
-
return Array.isArray(content) ? content.filter(isContentBlock) : [];
|
|
1597
|
-
}
|
|
1598
|
-
function blockText(c) {
|
|
1599
|
-
if (typeof c.data === "string") return c.data;
|
|
1600
|
-
if (isRecord(c.data) && typeof c.data.text === "string") return c.data.text;
|
|
1601
|
-
return "";
|
|
1508
|
+
function iso(value) {
|
|
1509
|
+
if (!value) return void 0;
|
|
1510
|
+
const ms = Date.parse(value);
|
|
1511
|
+
return Number.isNaN(ms) ? value : new Date(ms).toISOString();
|
|
1602
1512
|
}
|
|
1603
|
-
function
|
|
1604
|
-
|
|
1513
|
+
async function workspaceDirs() {
|
|
1514
|
+
const root = config.kiroSessionsDir;
|
|
1515
|
+
try {
|
|
1516
|
+
const entries = await fs9.readdir(root, { withFileTypes: true });
|
|
1517
|
+
return entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== V2_STORE).map((e) => path10.join(root, e.name));
|
|
1518
|
+
} catch {
|
|
1519
|
+
return [];
|
|
1520
|
+
}
|
|
1605
1521
|
}
|
|
1606
|
-
function
|
|
1607
|
-
const
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1522
|
+
async function v3SessionDirs() {
|
|
1523
|
+
const out = /* @__PURE__ */ new Map();
|
|
1524
|
+
await Promise.all(
|
|
1525
|
+
(await workspaceDirs()).map(async (dir) => {
|
|
1526
|
+
try {
|
|
1527
|
+
for (const e of await fs9.readdir(dir, { withFileTypes: true })) {
|
|
1528
|
+
if (e.isDirectory() && !e.name.startsWith(".") && isValidSessionId(e.name)) {
|
|
1529
|
+
out.set(e.name, path10.join(dir, e.name));
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
} catch {
|
|
1533
|
+
}
|
|
1534
|
+
})
|
|
1535
|
+
);
|
|
1536
|
+
return out;
|
|
1620
1537
|
}
|
|
1621
|
-
async function
|
|
1622
|
-
if (!isValidSessionId(sessionId)) return;
|
|
1623
|
-
const
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1538
|
+
async function v3SessionDir(sessionId) {
|
|
1539
|
+
if (!isValidSessionId(sessionId)) return void 0;
|
|
1540
|
+
const found = await Promise.all(
|
|
1541
|
+
(await workspaceDirs()).map(async (dir) => {
|
|
1542
|
+
const candidate = path10.join(dir, sessionId);
|
|
1543
|
+
try {
|
|
1544
|
+
await fs9.access(path10.join(candidate, "session.json"));
|
|
1545
|
+
return candidate;
|
|
1546
|
+
} catch {
|
|
1547
|
+
return void 0;
|
|
1548
|
+
}
|
|
1549
|
+
})
|
|
1550
|
+
);
|
|
1551
|
+
return found.find((d) => d !== void 0);
|
|
1631
1552
|
}
|
|
1632
|
-
|
|
1633
|
-
if (!
|
|
1553
|
+
function contextUsageOf(line) {
|
|
1554
|
+
if (!line.includes('"contextUsage"')) return void 0;
|
|
1634
1555
|
try {
|
|
1635
|
-
const
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
);
|
|
1639
|
-
return summarize(JSON.parse(raw));
|
|
1556
|
+
const p = JSON.parse(line).payload;
|
|
1557
|
+
const value = isRecord(p.value) ? p.value.usagePercentage : void 0;
|
|
1558
|
+
return p.type === "session_metadata" && p.key === "contextUsage" && typeof value === "number" ? value : void 0;
|
|
1640
1559
|
} catch {
|
|
1641
|
-
return
|
|
1560
|
+
return void 0;
|
|
1642
1561
|
}
|
|
1643
1562
|
}
|
|
1644
|
-
async function
|
|
1563
|
+
async function lastContextUsage(file) {
|
|
1564
|
+
let handle2;
|
|
1645
1565
|
try {
|
|
1646
|
-
|
|
1647
|
-
const mtime = st.mtime.toISOString();
|
|
1648
|
-
return mtime > child.updatedAt ? { ...child, updatedAt: mtime } : child;
|
|
1566
|
+
handle2 = await fs9.open(file, "r");
|
|
1649
1567
|
} catch {
|
|
1650
|
-
return
|
|
1568
|
+
return void 0;
|
|
1651
1569
|
}
|
|
1652
|
-
}
|
|
1653
|
-
async function readChildSession(childSessionId, parentSessionId) {
|
|
1654
|
-
if (!isValidSessionId(childSessionId)) return null;
|
|
1655
1570
|
try {
|
|
1656
|
-
const
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1571
|
+
const { size } = await handle2.stat();
|
|
1572
|
+
let end = size;
|
|
1573
|
+
let tail = "";
|
|
1574
|
+
while (end > 0 && size - end < CONTEXT_TAIL_BYTES) {
|
|
1575
|
+
const start = Math.max(0, end - CONTEXT_CHUNK_BYTES);
|
|
1576
|
+
const buf = Buffer.alloc(end - start);
|
|
1577
|
+
await handle2.read(buf, 0, buf.length, start);
|
|
1578
|
+
end = start;
|
|
1579
|
+
const lines = (buf.toString("utf8") + tail).split("\n");
|
|
1580
|
+
tail = end > 0 ? lines.shift() : "";
|
|
1581
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
1582
|
+
const value = contextUsageOf(lines[i]);
|
|
1583
|
+
if (value !== void 0) return value;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
return tail ? contextUsageOf(tail) : void 0;
|
|
1587
|
+
} finally {
|
|
1588
|
+
await handle2.close();
|
|
1661
1589
|
}
|
|
1662
1590
|
}
|
|
1663
|
-
async function
|
|
1664
|
-
|
|
1665
|
-
let names;
|
|
1591
|
+
async function readV3Session(dir) {
|
|
1592
|
+
let j;
|
|
1666
1593
|
try {
|
|
1667
|
-
|
|
1594
|
+
j = JSON.parse(await fs9.readFile(path10.join(dir, "session.json"), "utf8"));
|
|
1668
1595
|
} catch {
|
|
1669
|
-
return
|
|
1596
|
+
return null;
|
|
1670
1597
|
}
|
|
1671
|
-
const
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
);
|
|
1684
|
-
return out;
|
|
1685
|
-
}
|
|
1686
|
-
async function promptCount(sessionId) {
|
|
1687
|
-
const entries = await readJsonlEntries(sessionId);
|
|
1688
|
-
return entries.filter((e) => e.kind === "Prompt").length;
|
|
1598
|
+
const title = j.title?.trim() ?? "";
|
|
1599
|
+
const createdAt = iso(j.createdAt) ?? (/* @__PURE__ */ new Date(0)).toISOString();
|
|
1600
|
+
return {
|
|
1601
|
+
sessionId: j.id,
|
|
1602
|
+
title: title === PLACEHOLDER_TITLE ? "" : title,
|
|
1603
|
+
cwd: j.workspacePaths?.[0] ?? "",
|
|
1604
|
+
createdAt,
|
|
1605
|
+
updatedAt: iso(j.lastModifiedAt) ?? createdAt,
|
|
1606
|
+
agentId: j.agentMode,
|
|
1607
|
+
modelId: j.modelId,
|
|
1608
|
+
contextUsagePercentage: await lastContextUsage(path10.join(dir, "messages.jsonl"))
|
|
1609
|
+
};
|
|
1689
1610
|
}
|
|
1690
|
-
async function
|
|
1691
|
-
if (!isValidSessionId(sessionId)) return [];
|
|
1611
|
+
async function readLines(file, filter) {
|
|
1692
1612
|
let raw;
|
|
1693
1613
|
try {
|
|
1694
|
-
raw = await fs9.readFile(
|
|
1614
|
+
raw = await fs9.readFile(file, "utf8");
|
|
1695
1615
|
} catch {
|
|
1696
1616
|
return [];
|
|
1697
1617
|
}
|
|
1698
|
-
const
|
|
1618
|
+
const out = [];
|
|
1699
1619
|
for (const line of raw.split("\n")) {
|
|
1700
|
-
|
|
1701
|
-
if (!trimmed) continue;
|
|
1620
|
+
if (!line.trim() || filter && !line.includes(filter)) continue;
|
|
1702
1621
|
try {
|
|
1703
|
-
|
|
1622
|
+
const parsed = JSON.parse(line);
|
|
1623
|
+
if (isRecord(parsed) && isRecord(parsed.payload) && typeof parsed.id === "string") out.push(parsed);
|
|
1704
1624
|
} catch {
|
|
1705
1625
|
}
|
|
1706
1626
|
}
|
|
1707
|
-
return
|
|
1627
|
+
return out;
|
|
1708
1628
|
}
|
|
1709
|
-
|
|
1710
|
-
if (
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1629
|
+
function userText(content) {
|
|
1630
|
+
if (typeof content === "string") return content;
|
|
1631
|
+
if (!Array.isArray(content)) return "";
|
|
1632
|
+
return content.map((b) => isRecord(b) && b.type === "text" && typeof b.text === "string" ? b.text : "").join("");
|
|
1633
|
+
}
|
|
1634
|
+
function resultBlocks(content) {
|
|
1635
|
+
if (typeof content === "string") return content ? [{ type: "text", text: content }] : [];
|
|
1636
|
+
if (Array.isArray(content)) return content.filter((b) => !(isRecord(b) && b.type === "image"));
|
|
1637
|
+
return isRecord(content) ? [{ kind: "json", data: content }] : [];
|
|
1638
|
+
}
|
|
1639
|
+
function isCompactionCopy(id, seen) {
|
|
1640
|
+
if (!id.startsWith("compact_")) return false;
|
|
1641
|
+
const rest = id.slice("compact_".length);
|
|
1642
|
+
const sep = rest.indexOf("_");
|
|
1643
|
+
return sep >= 0 && seen.has(rest.slice(sep + 1));
|
|
1644
|
+
}
|
|
1645
|
+
async function readV3Entries(file) {
|
|
1646
|
+
const out = [];
|
|
1647
|
+
const toolsById = /* @__PURE__ */ new Map();
|
|
1648
|
+
const addTool = (tool) => {
|
|
1649
|
+
const seen2 = toolsById.get(tool.id);
|
|
1650
|
+
if (seen2) {
|
|
1651
|
+
Object.assign(seen2, { ...tool, content: seen2.content, output: seen2.output ?? tool.output });
|
|
1652
|
+
return;
|
|
1653
|
+
}
|
|
1654
|
+
toolsById.set(tool.id, tool);
|
|
1655
|
+
out.push({ kind: "item", item: { type: "tool_call", tool } });
|
|
1656
|
+
};
|
|
1657
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1658
|
+
for (const line of await readLines(file)) {
|
|
1659
|
+
const copy = isCompactionCopy(line.id, seen);
|
|
1660
|
+
seen.add(line.id);
|
|
1661
|
+
if (copy) continue;
|
|
1662
|
+
const p = line.payload;
|
|
1663
|
+
const parsed = line.timestamp ? Date.parse(line.timestamp) : NaN;
|
|
1664
|
+
const at = Number.isNaN(parsed) ? void 0 : parsed;
|
|
1665
|
+
switch (p.type) {
|
|
1666
|
+
case "user":
|
|
1667
|
+
out.push({ kind: "prompt", id: line.id, text: userText(p.content), atMs: at, timestamp: at });
|
|
1668
|
+
break;
|
|
1669
|
+
case "assistant": {
|
|
1670
|
+
const text2 = str2(p.content) ?? "";
|
|
1671
|
+
if (!text2.trim()) break;
|
|
1672
|
+
if (p.operationType === "Summary") {
|
|
1673
|
+
out.push({ kind: "item", item: { type: "compaction", id: `c-${line.id}`, summary: text2, timestamp: at } });
|
|
1674
|
+
} else if (p.operationType === "Reasoning") {
|
|
1675
|
+
if (text2.trim() !== HIDDEN_REASONING) {
|
|
1676
|
+
out.push({ kind: "item", item: { type: "message", message: { id: `t-${line.id}`, role: "thinking", text: text2.trim(), timestamp: at } } });
|
|
1677
|
+
}
|
|
1678
|
+
} else {
|
|
1679
|
+
out.push({ kind: "item", item: { type: "message", message: { id: `a-${line.id}`, role: "assistant", text: text2, timestamp: at } } });
|
|
1680
|
+
}
|
|
1681
|
+
break;
|
|
1682
|
+
}
|
|
1683
|
+
case "tool_call": {
|
|
1684
|
+
const id = str2(p.toolCallId);
|
|
1685
|
+
if (!id) break;
|
|
1686
|
+
const title = str2(p.title);
|
|
1687
|
+
const meta = isRecord(p._meta) ? p._meta : void 0;
|
|
1688
|
+
const args = p.args;
|
|
1689
|
+
const input = p.toolName === "tool_call" && isRecord(args) && "arguments" in args ? args.arguments : args;
|
|
1690
|
+
addTool({
|
|
1691
|
+
id,
|
|
1692
|
+
// A call kiro copied in from a kiro 2.x session has no kind, only 2.x's tool name,
|
|
1693
|
+
// which the web renders by.
|
|
1694
|
+
name: kiroToolName({ title, _meta: meta }) ?? (p.kind === void 0 ? str2(p.toolName) : void 0),
|
|
1695
|
+
title: title ?? str2(p.toolName) ?? id,
|
|
1696
|
+
kind: str2(p.kind),
|
|
1697
|
+
status: p.status === "failed" ? "failed" : "completed",
|
|
1698
|
+
input,
|
|
1699
|
+
content: []
|
|
1700
|
+
});
|
|
1701
|
+
break;
|
|
1702
|
+
}
|
|
1703
|
+
case "tool_result": {
|
|
1704
|
+
const tool = toolsById.get(str2(p.toolCallId) ?? "");
|
|
1705
|
+
if (!tool) break;
|
|
1706
|
+
tool.status = p.success === false ? "failed" : "completed";
|
|
1707
|
+
tool.content = resultBlocks(p.content);
|
|
1708
|
+
break;
|
|
1709
|
+
}
|
|
1710
|
+
case "sub_agent_start": {
|
|
1711
|
+
const name = str2(p.subAgentName) ?? "subagent";
|
|
1712
|
+
addTool({
|
|
1713
|
+
id: line.id.endsWith(START_SUFFIX) ? line.id.slice(0, -START_SUFFIX.length) : line.id,
|
|
1714
|
+
name: SUBAGENT_TOOL,
|
|
1715
|
+
title: `Sub-agent: ${name}`,
|
|
1716
|
+
kind: "other",
|
|
1717
|
+
// Without a result the parent turn ended while the subagent ran.
|
|
1718
|
+
status: "failed",
|
|
1719
|
+
input: { name, prompt: str2(p.prompt), explanation: str2(p.explanation) },
|
|
1720
|
+
content: []
|
|
1721
|
+
});
|
|
1722
|
+
break;
|
|
1723
|
+
}
|
|
1724
|
+
case "sub_agent_complete": {
|
|
1725
|
+
const tool = toolsById.get(line.id.endsWith(COMPLETE_SUFFIX) ? line.id.slice(0, -COMPLETE_SUFFIX.length) : "");
|
|
1726
|
+
if (!tool) break;
|
|
1727
|
+
tool.status = p.status === "success" ? "completed" : "failed";
|
|
1728
|
+
tool.output = str2(p.response);
|
|
1729
|
+
break;
|
|
1730
|
+
}
|
|
1731
|
+
default:
|
|
1732
|
+
break;
|
|
1733
|
+
}
|
|
1716
1734
|
}
|
|
1735
|
+
return out;
|
|
1736
|
+
}
|
|
1737
|
+
async function readSubExecutions(dir) {
|
|
1738
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1739
|
+
for (const line of await readLines(path10.join(dir, "messages.jsonl"), '"sub_agent_')) {
|
|
1740
|
+
const p = line.payload;
|
|
1741
|
+
const subId = str2(p.subSessionId);
|
|
1742
|
+
if (!subId) continue;
|
|
1743
|
+
const at = iso(line.timestamp) ?? (/* @__PURE__ */ new Date(0)).toISOString();
|
|
1744
|
+
if (p.type === "sub_agent_start") {
|
|
1745
|
+
byId.set(subId, {
|
|
1746
|
+
sessionId: subId,
|
|
1747
|
+
name: str2(p.subAgentName) ?? subId,
|
|
1748
|
+
toolCallId: line.id.endsWith(START_SUFFIX) ? line.id.slice(0, -START_SUFFIX.length) : line.id,
|
|
1749
|
+
status: "failed",
|
|
1750
|
+
stopped: true,
|
|
1751
|
+
createdAt: at,
|
|
1752
|
+
updatedAt: at
|
|
1753
|
+
});
|
|
1754
|
+
} else if (p.type === "sub_agent_complete") {
|
|
1755
|
+
const sub = byId.get(subId);
|
|
1756
|
+
if (!sub) continue;
|
|
1757
|
+
sub.status = p.status === "success" ? "completed" : "failed";
|
|
1758
|
+
sub.stopped = false;
|
|
1759
|
+
sub.updatedAt = at;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
return [...byId.values()];
|
|
1763
|
+
}
|
|
1764
|
+
function subExecutionFile(dir, subagentId) {
|
|
1765
|
+
return isValidSessionId(subagentId) ? path10.join(dir, "sub-executions", `${subagentId}.jsonl`) : void 0;
|
|
1766
|
+
}
|
|
1767
|
+
var PLACEHOLDER_TITLE, HIDDEN_REASONING, CONTEXT_TAIL_BYTES, CONTEXT_CHUNK_BYTES, isRecord, str2, V2_STORE, START_SUFFIX, COMPLETE_SUFFIX;
|
|
1768
|
+
var init_kiroV3Files = __esm({
|
|
1769
|
+
"server/src/session/kiroV3Files.ts"() {
|
|
1770
|
+
"use strict";
|
|
1771
|
+
init_dist();
|
|
1772
|
+
init_config();
|
|
1773
|
+
init_paths2();
|
|
1774
|
+
PLACEHOLDER_TITLE = "New Session";
|
|
1775
|
+
HIDDEN_REASONING = "...";
|
|
1776
|
+
CONTEXT_TAIL_BYTES = 1024 * 1024;
|
|
1777
|
+
CONTEXT_CHUNK_BYTES = 16 * 1024;
|
|
1778
|
+
isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1779
|
+
str2 = (v) => typeof v === "string" ? v : void 0;
|
|
1780
|
+
V2_STORE = "cli";
|
|
1781
|
+
START_SUFFIX = "-sub-agent-start";
|
|
1782
|
+
COMPLETE_SUFFIX = "-sub-agent-complete";
|
|
1783
|
+
}
|
|
1784
|
+
});
|
|
1785
|
+
|
|
1786
|
+
// server/src/session/kiroFiles.ts
|
|
1787
|
+
import fs10 from "node:fs/promises";
|
|
1788
|
+
import path11 from "node:path";
|
|
1789
|
+
async function readPersistedSession(sessionId) {
|
|
1790
|
+
const dir = await v3SessionDir(sessionId);
|
|
1791
|
+
return dir ? readV3Session(dir) : null;
|
|
1792
|
+
}
|
|
1793
|
+
async function readPersistedSessions(sessionIds) {
|
|
1794
|
+
const dirs = await v3SessionDirs();
|
|
1795
|
+
const out = /* @__PURE__ */ new Map();
|
|
1796
|
+
await Promise.all(
|
|
1797
|
+
sessionIds.filter(isValidSessionId).map(async (id) => {
|
|
1798
|
+
const dir = dirs.get(id);
|
|
1799
|
+
const found = dir ? await readV3Session(dir) : null;
|
|
1800
|
+
if (found) out.set(id, found);
|
|
1801
|
+
})
|
|
1802
|
+
);
|
|
1803
|
+
return out;
|
|
1804
|
+
}
|
|
1805
|
+
async function deletePersistedSession(sessionId) {
|
|
1806
|
+
const dir = await v3SessionDir(sessionId);
|
|
1807
|
+
if (dir) await fs10.rm(dir, { recursive: true, force: true });
|
|
1808
|
+
}
|
|
1809
|
+
async function isLoadable(sessionId) {
|
|
1810
|
+
return await v3SessionDir(sessionId) !== void 0;
|
|
1811
|
+
}
|
|
1812
|
+
async function readEntries(sessionId) {
|
|
1813
|
+
const dir = await v3SessionDir(sessionId);
|
|
1814
|
+
return dir ? readV3Entries(path11.join(dir, "messages.jsonl")) : [];
|
|
1815
|
+
}
|
|
1816
|
+
async function promptCount(sessionId) {
|
|
1817
|
+
return (await readEntries(sessionId)).filter((e) => e.kind === "prompt").length;
|
|
1717
1818
|
}
|
|
1718
1819
|
function endingItems(e) {
|
|
1719
1820
|
const prefix = `te${e.id}-`;
|
|
@@ -1725,93 +1826,71 @@ function endingItems(e) {
|
|
|
1725
1826
|
);
|
|
1726
1827
|
return items;
|
|
1727
1828
|
}
|
|
1728
|
-
|
|
1829
|
+
function mergeTranscript(entries, attachments, endings) {
|
|
1729
1830
|
const items = [];
|
|
1730
1831
|
let userOrdinal = 0;
|
|
1731
|
-
const toolsById = /* @__PURE__ */ new Map();
|
|
1732
1832
|
const waiting = [...endings];
|
|
1733
1833
|
let replaced = false;
|
|
1734
1834
|
const unrecorded = (e) => [
|
|
1735
1835
|
{ type: "message", message: { id: `te${e.id}-u`, role: "user", text: e.prompt, timestamp: e.startedAt } },
|
|
1736
1836
|
...endingItems(e)
|
|
1737
1837
|
];
|
|
1738
|
-
for (const entry of
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
);
|
|
1753
|
-
while (waiting.length && waiting[0] !== matched && waiting[0].endedAt < at - STAMP_PAD_MS) {
|
|
1754
|
-
items.push(...unrecorded(waiting.shift()));
|
|
1755
|
-
}
|
|
1756
|
-
if (matched) waiting.splice(waiting.indexOf(matched), 1);
|
|
1757
|
-
}
|
|
1758
|
-
const attached = attachments?.get(userOrdinal);
|
|
1759
|
-
userOrdinal++;
|
|
1760
|
-
if (text2.trim() || attached?.length)
|
|
1761
|
-
pushMsg({ id: `u-${baseId}`, role: "user", text: text2, timestamp: ts, attachments: attached });
|
|
1762
|
-
if (matched) {
|
|
1763
|
-
items.push(...endingItems(matched));
|
|
1764
|
-
replaced = true;
|
|
1765
|
-
}
|
|
1766
|
-
} else if (entry.kind === "AssistantMessage") {
|
|
1767
|
-
if (replaced) continue;
|
|
1768
|
-
const thinking = textOf("thinking");
|
|
1769
|
-
if (thinking.trim())
|
|
1770
|
-
pushMsg({ id: `t-${baseId}`, role: "thinking", text: thinking.trim(), timestamp: ts });
|
|
1771
|
-
const text2 = textOf("text");
|
|
1772
|
-
if (text2.trim())
|
|
1773
|
-
pushMsg({ id: `a-${baseId}`, role: "assistant", text: text2, timestamp: ts });
|
|
1774
|
-
for (const c of content) {
|
|
1775
|
-
const d = toolUseData(c);
|
|
1776
|
-
if (!d) continue;
|
|
1777
|
-
const tool = {
|
|
1778
|
-
id: d.toolUseId,
|
|
1779
|
-
name: d.name,
|
|
1780
|
-
title: d.name ?? d.toolUseId,
|
|
1781
|
-
status: "completed",
|
|
1782
|
-
input: d.input,
|
|
1783
|
-
content: []
|
|
1784
|
-
};
|
|
1785
|
-
toolsById.set(d.toolUseId, tool);
|
|
1786
|
-
items.push({ type: "tool_call", tool });
|
|
1787
|
-
}
|
|
1788
|
-
} else if (entry.kind === "ToolResults") {
|
|
1789
|
-
if (replaced) continue;
|
|
1790
|
-
for (const c of content) {
|
|
1791
|
-
const d = toolResultData(c);
|
|
1792
|
-
if (!d) continue;
|
|
1793
|
-
const tool = toolsById.get(d.toolUseId);
|
|
1794
|
-
if (!tool) continue;
|
|
1795
|
-
tool.status = d.status === "error" ? "failed" : "completed";
|
|
1796
|
-
tool.content = renderableBlocks(d.content);
|
|
1838
|
+
for (const entry of entries) {
|
|
1839
|
+
if (entry.kind === "item") {
|
|
1840
|
+
if (!replaced || entry.item.type === "compaction") items.push(entry.item);
|
|
1841
|
+
continue;
|
|
1842
|
+
}
|
|
1843
|
+
replaced = false;
|
|
1844
|
+
const text2 = stripAttachmentsLine(entry.text);
|
|
1845
|
+
let matched;
|
|
1846
|
+
const at = entry.atMs;
|
|
1847
|
+
if (at !== void 0) {
|
|
1848
|
+
matched = waiting.find(
|
|
1849
|
+
(e) => e.prompt.trim() === text2.trim() && at >= e.startedAt - STAMP_PAD_MS && at <= e.endedAt + STAMP_PAD_MS
|
|
1850
|
+
);
|
|
1851
|
+
while (waiting.length && waiting[0] !== matched && waiting[0].endedAt < at - STAMP_PAD_MS) {
|
|
1852
|
+
items.push(...unrecorded(waiting.shift()));
|
|
1797
1853
|
}
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1854
|
+
if (matched) waiting.splice(waiting.indexOf(matched), 1);
|
|
1855
|
+
}
|
|
1856
|
+
const attached = attachments?.get(userOrdinal);
|
|
1857
|
+
userOrdinal++;
|
|
1858
|
+
if (text2.trim() || attached?.length) {
|
|
1859
|
+
items.push({ type: "message", message: { id: `u-${entry.id}`, role: "user", text: text2, timestamp: entry.timestamp, attachments: attached } });
|
|
1860
|
+
}
|
|
1861
|
+
if (matched) {
|
|
1862
|
+
items.push(...endingItems(matched));
|
|
1863
|
+
replaced = true;
|
|
1802
1864
|
}
|
|
1803
1865
|
}
|
|
1804
1866
|
for (const e of waiting) items.push(...unrecorded(e));
|
|
1805
1867
|
return items;
|
|
1806
1868
|
}
|
|
1807
|
-
|
|
1869
|
+
async function hydrateTranscript(sessionId, attachments, endings = []) {
|
|
1870
|
+
return mergeTranscript(await readEntries(sessionId), attachments, endings);
|
|
1871
|
+
}
|
|
1872
|
+
async function listSubExecutions(sessionId) {
|
|
1873
|
+
const dir = await v3SessionDir(sessionId);
|
|
1874
|
+
return dir ? readSubExecutions(dir) : null;
|
|
1875
|
+
}
|
|
1876
|
+
async function hydrateSubExecution(sessionId, subagentId) {
|
|
1877
|
+
const dir = await v3SessionDir(sessionId);
|
|
1878
|
+
const file = dir ? subExecutionFile(dir, subagentId) : void 0;
|
|
1879
|
+
if (!file) return null;
|
|
1880
|
+
try {
|
|
1881
|
+
await fs10.access(file);
|
|
1882
|
+
} catch {
|
|
1883
|
+
return null;
|
|
1884
|
+
}
|
|
1885
|
+
return mergeTranscript(await readV3Entries(file), void 0, []);
|
|
1886
|
+
}
|
|
1887
|
+
var STAMP_PAD_MS;
|
|
1808
1888
|
var init_kiroFiles = __esm({
|
|
1809
1889
|
"server/src/session/kiroFiles.ts"() {
|
|
1810
1890
|
"use strict";
|
|
1811
1891
|
init_dist();
|
|
1812
|
-
init_config();
|
|
1813
1892
|
init_paths2();
|
|
1814
|
-
|
|
1893
|
+
init_kiroV3Files();
|
|
1815
1894
|
STAMP_PAD_MS = 2e3;
|
|
1816
1895
|
}
|
|
1817
1896
|
});
|
|
@@ -1933,50 +2012,18 @@ var init_chatStore = __esm({
|
|
|
1933
2012
|
}
|
|
1934
2013
|
});
|
|
1935
2014
|
|
|
1936
|
-
// server/src/session/subagentLinks.ts
|
|
1937
|
-
var SubagentLinkStore;
|
|
1938
|
-
var init_subagentLinks = __esm({
|
|
1939
|
-
"server/src/session/subagentLinks.ts"() {
|
|
1940
|
-
"use strict";
|
|
1941
|
-
init_db();
|
|
1942
|
-
SubagentLinkStore = class {
|
|
1943
|
-
/** Record (or correct) one child's link. Idempotent: a repeat call with the same
|
|
1944
|
-
* values is a no-op, and the row always reflects the latest call to resolve it. */
|
|
1945
|
-
record(childSessionId, parentSessionId, toolCallId, stageName) {
|
|
1946
|
-
db().prepare(
|
|
1947
|
-
`INSERT INTO subagent_links (child_session_id, parent_session_id, tool_call_id, stage_name)
|
|
1948
|
-
VALUES (?, ?, ?, ?)
|
|
1949
|
-
ON CONFLICT(child_session_id) DO UPDATE SET
|
|
1950
|
-
parent_session_id = excluded.parent_session_id,
|
|
1951
|
-
tool_call_id = excluded.tool_call_id,
|
|
1952
|
-
stage_name = excluded.stage_name`
|
|
1953
|
-
).run(childSessionId, parentSessionId, toolCallId, stageName);
|
|
1954
|
-
}
|
|
1955
|
-
/** Every link recorded for one parent session's children, keyed by child session id. */
|
|
1956
|
-
forParent(parentSessionId) {
|
|
1957
|
-
const rows = db().prepare(
|
|
1958
|
-
"SELECT child_session_id, tool_call_id, stage_name FROM subagent_links WHERE parent_session_id = ?"
|
|
1959
|
-
).all(parentSessionId);
|
|
1960
|
-
const out = /* @__PURE__ */ new Map();
|
|
1961
|
-
for (const r of rows) out.set(r.child_session_id, { toolCallId: r.tool_call_id, stageName: r.stage_name });
|
|
1962
|
-
return out;
|
|
1963
|
-
}
|
|
1964
|
-
};
|
|
1965
|
-
}
|
|
1966
|
-
});
|
|
1967
|
-
|
|
1968
2015
|
// server/src/session/SessionManager.ts
|
|
1969
|
-
import
|
|
1970
|
-
import
|
|
2016
|
+
import fs11 from "node:fs";
|
|
2017
|
+
import path12 from "node:path";
|
|
1971
2018
|
function resolveCwd(input) {
|
|
1972
2019
|
const raw = input?.trim();
|
|
1973
|
-
const abs = raw ?
|
|
2020
|
+
const abs = raw ? path12.resolve(config.defaultCwd, raw) : config.defaultCwd;
|
|
1974
2021
|
if (!isWithinRoot(config.fileRoot, abs)) {
|
|
1975
2022
|
throw new Error(`Working directory is outside the allowed root: ${abs}`);
|
|
1976
2023
|
}
|
|
1977
2024
|
let stat;
|
|
1978
2025
|
try {
|
|
1979
|
-
stat =
|
|
2026
|
+
stat = fs11.statSync(abs);
|
|
1980
2027
|
} catch {
|
|
1981
2028
|
stat = void 0;
|
|
1982
2029
|
}
|
|
@@ -1984,37 +2031,44 @@ function resolveCwd(input) {
|
|
|
1984
2031
|
throw new Error(`Working directory path is a file, not a directory: ${abs}`);
|
|
1985
2032
|
}
|
|
1986
2033
|
if (!stat) {
|
|
1987
|
-
|
|
2034
|
+
fs11.mkdirSync(abs, { recursive: true });
|
|
1988
2035
|
}
|
|
1989
2036
|
return abs;
|
|
1990
2037
|
}
|
|
1991
|
-
function
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
case
|
|
1998
|
-
return { kind: "
|
|
2038
|
+
function kiroMeta(update) {
|
|
2039
|
+
return update._meta?.kiro;
|
|
2040
|
+
}
|
|
2041
|
+
function sessionInfoEvent(sessionId, update) {
|
|
2042
|
+
const info = update._meta?.kiro;
|
|
2043
|
+
switch (info?.kind) {
|
|
2044
|
+
case "context_usage":
|
|
2045
|
+
return typeof info.usagePercentage === "number" ? { kind: "metadata", params: { sessionId, contextUsagePercentage: info.usagePercentage } } : null;
|
|
2046
|
+
case "summarization_started":
|
|
2047
|
+
return { kind: "compaction", params: { sessionId, status: { type: "started" }, summary: null } };
|
|
2048
|
+
case "summarization_completed":
|
|
2049
|
+
return {
|
|
2050
|
+
kind: "compaction",
|
|
2051
|
+
params: { sessionId, status: { type: "completed" }, summary: info.conversationSummary ?? null }
|
|
2052
|
+
};
|
|
2053
|
+
case "summarization_failed":
|
|
2054
|
+
return { kind: "compaction", params: { sessionId, status: { type: "failed" }, summary: null } };
|
|
1999
2055
|
default:
|
|
2000
2056
|
return null;
|
|
2001
2057
|
}
|
|
2002
2058
|
}
|
|
2003
|
-
function
|
|
2004
|
-
|
|
2005
|
-
return params?.sessionId;
|
|
2059
|
+
function sessionModel(res) {
|
|
2060
|
+
return res.configOptions?.find((o) => o.id === "model")?.currentValue;
|
|
2006
2061
|
}
|
|
2007
|
-
function
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
return { toolCallId, stages };
|
|
2062
|
+
function subExecutionSummary(sub) {
|
|
2063
|
+
return {
|
|
2064
|
+
sessionId: sub.sessionId,
|
|
2065
|
+
stageName: sub.name,
|
|
2066
|
+
toolCallId: sub.toolCallId,
|
|
2067
|
+
status: sub.status,
|
|
2068
|
+
activity: sub.stopped ? "Stopped" : void 0,
|
|
2069
|
+
createdAt: sub.createdAt,
|
|
2070
|
+
updatedAt: sub.updatedAt
|
|
2071
|
+
};
|
|
2018
2072
|
}
|
|
2019
2073
|
function newerOf(a, b) {
|
|
2020
2074
|
return a && a.localeCompare(b) > 0 ? a : b;
|
|
@@ -2026,7 +2080,7 @@ function firstPromptText(transcript) {
|
|
|
2026
2080
|
function isGhost(s, hasFile) {
|
|
2027
2081
|
return !hasFile && s.hasBeenLive && !s.proc;
|
|
2028
2082
|
}
|
|
2029
|
-
var CANCEL_GRACE_MS, Session, TRANSCRIPT_PAGE_SIZE, SessionManager;
|
|
2083
|
+
var CANCEL_GRACE_MS, Session, TRANSCRIPT_UPDATES, TRANSCRIPT_PAGE_SIZE, SessionManager;
|
|
2030
2084
|
var init_SessionManager = __esm({
|
|
2031
2085
|
"server/src/session/SessionManager.ts"() {
|
|
2032
2086
|
"use strict";
|
|
@@ -2040,11 +2094,8 @@ var init_SessionManager = __esm({
|
|
|
2040
2094
|
init_TurnState();
|
|
2041
2095
|
init_TurnRecorder();
|
|
2042
2096
|
init_SubagentTracker();
|
|
2043
|
-
init_subagentResult();
|
|
2044
|
-
init_subagentFallbackMatch();
|
|
2045
2097
|
init_kiroFiles();
|
|
2046
2098
|
init_chatStore();
|
|
2047
|
-
init_subagentLinks();
|
|
2048
2099
|
CANCEL_GRACE_MS = 1e4;
|
|
2049
2100
|
Session = class {
|
|
2050
2101
|
sessionId;
|
|
@@ -2093,21 +2144,20 @@ var init_SessionManager = __esm({
|
|
|
2093
2144
|
return event;
|
|
2094
2145
|
}
|
|
2095
2146
|
};
|
|
2147
|
+
TRANSCRIPT_UPDATES = /* @__PURE__ */ new Set(["agent_message_chunk", "agent_thought_chunk", "tool_call", "tool_call_update"]);
|
|
2096
2148
|
TRANSCRIPT_PAGE_SIZE = 80;
|
|
2097
2149
|
SessionManager = class {
|
|
2098
2150
|
sessions = /* @__PURE__ */ new Map();
|
|
2099
2151
|
log;
|
|
2100
2152
|
store = new ChatStore();
|
|
2101
|
-
subagentLinks = new SubagentLinkStore();
|
|
2102
|
-
// Children the title fallback already tried and could not match. Matching hydrates the
|
|
2103
|
-
// whole parent transcript (145 MB in one chat), so each child is tried once per process.
|
|
2104
|
-
unmatchedChildren = /* @__PURE__ */ new Map();
|
|
2105
2153
|
spawnProcess;
|
|
2106
2154
|
cancelGraceMs;
|
|
2155
|
+
defaultModel;
|
|
2107
2156
|
constructor(log, opts = {}) {
|
|
2108
2157
|
this.log = log;
|
|
2109
2158
|
this.spawnProcess = opts.spawn ?? ((o, l) => new KiroProcess(o, l));
|
|
2110
2159
|
this.cancelGraceMs = opts.cancelGraceMs ?? CANCEL_GRACE_MS;
|
|
2160
|
+
this.defaultModel = opts.defaultModel ?? (async () => void 0);
|
|
2111
2161
|
}
|
|
2112
2162
|
/** What a session is called, from every read path. */
|
|
2113
2163
|
titleOf(chat, parts) {
|
|
@@ -2115,7 +2165,7 @@ var init_SessionManager = __esm({
|
|
|
2115
2165
|
override: chat.title ?? void 0,
|
|
2116
2166
|
kiroTitle: parts.kiroTitle,
|
|
2117
2167
|
firstPrompt: parts.firstPrompt,
|
|
2118
|
-
folder: isManagedWorkspace(parts.cwd) ? void 0 :
|
|
2168
|
+
folder: isManagedWorkspace(parts.cwd) ? void 0 : path12.basename(parts.cwd)
|
|
2119
2169
|
});
|
|
2120
2170
|
}
|
|
2121
2171
|
renameChat(chatId, title) {
|
|
@@ -2173,7 +2223,7 @@ var init_SessionManager = __esm({
|
|
|
2173
2223
|
}
|
|
2174
2224
|
/** The reload itself, called with the session's reload claim held. */
|
|
2175
2225
|
async replaceProcess(chatId, s) {
|
|
2176
|
-
if (!await
|
|
2226
|
+
if (!await isLoadable(s.sessionId)) {
|
|
2177
2227
|
throw new Error(
|
|
2178
2228
|
"kiro has not saved this session yet. Send a message first, then reload."
|
|
2179
2229
|
);
|
|
@@ -2187,9 +2237,9 @@ var init_SessionManager = __esm({
|
|
|
2187
2237
|
});
|
|
2188
2238
|
}
|
|
2189
2239
|
s.availableModes = [];
|
|
2240
|
+
invalidateAgents();
|
|
2190
2241
|
await this.ensureProc(s);
|
|
2191
2242
|
s.lastActivity = Date.now();
|
|
2192
|
-
invalidateAgents();
|
|
2193
2243
|
this.log.info({ sessionId: s.sessionId, cwd: s.cwd }, "session reloaded");
|
|
2194
2244
|
return this.getDetail(chatId);
|
|
2195
2245
|
}
|
|
@@ -2244,30 +2294,30 @@ var init_SessionManager = __esm({
|
|
|
2244
2294
|
wire(s, proc) {
|
|
2245
2295
|
proc.on("notification", (n) => {
|
|
2246
2296
|
if (s.replaying) return;
|
|
2247
|
-
if (n.method ===
|
|
2248
|
-
|
|
2249
|
-
const resolved = s.subagents.apply(params.subagents);
|
|
2250
|
-
for (const link of resolved) {
|
|
2251
|
-
this.subagentLinks.record(link.sessionId, s.sessionId, link.toolCallId, link.stageName);
|
|
2252
|
-
}
|
|
2253
|
-
s.record({ kind: "subagents_changed", subagents: s.subagents.list() });
|
|
2297
|
+
if (n.method === KIRO_AGENT_NOT_FOUND) {
|
|
2298
|
+
this.log.warn({ sessionId: s.sessionId, detail: n.params }, "kiro could not use the requested agent");
|
|
2254
2299
|
return;
|
|
2255
2300
|
}
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2301
|
+
if (n.method !== ACP_METHODS.sessionUpdate) return;
|
|
2302
|
+
const params = n.params;
|
|
2303
|
+
if (!params?.update || params.sessionId && params.sessionId !== s.sessionId) return;
|
|
2304
|
+
const { update } = params;
|
|
2305
|
+
const meta = kiroMeta(update);
|
|
2306
|
+
if (meta?.replay) return;
|
|
2307
|
+
if (update.sessionUpdate === "session_info_update") {
|
|
2308
|
+
const payload = sessionInfoEvent(s.sessionId, update);
|
|
2309
|
+
if (payload) s.record(payload);
|
|
2310
|
+
return;
|
|
2311
|
+
}
|
|
2312
|
+
if (!TRANSCRIPT_UPDATES.has(update.sessionUpdate)) return;
|
|
2313
|
+
const subagentId = meta?.agentSubtaskId;
|
|
2314
|
+
if (subagentId && meta.kind !== "agent-subtask") {
|
|
2315
|
+
const title = update.sessionUpdate === "tool_call" ? update.title : void 0;
|
|
2316
|
+
if (s.subagents.progressed(subagentId, title)) this.recordSubagents(s);
|
|
2269
2317
|
return;
|
|
2270
2318
|
}
|
|
2319
|
+
if (subagentId) this.trackSubagentCall(s, subagentId, update);
|
|
2320
|
+
s.record({ kind: "session_update", update });
|
|
2271
2321
|
});
|
|
2272
2322
|
proc.on("exit", (code, signal) => {
|
|
2273
2323
|
if (s.proc !== proc) return;
|
|
@@ -2276,28 +2326,50 @@ var init_SessionManager = __esm({
|
|
|
2276
2326
|
s.running = false;
|
|
2277
2327
|
});
|
|
2278
2328
|
}
|
|
2329
|
+
/** Follows the tool call that starts a subagent, from its start to its result. */
|
|
2330
|
+
trackSubagentCall(s, subagentId, update) {
|
|
2331
|
+
const call = update;
|
|
2332
|
+
if (typeof call.toolCallId !== "string") return;
|
|
2333
|
+
let changed = false;
|
|
2334
|
+
if (call.sessionUpdate === "tool_call") {
|
|
2335
|
+
const name = typeof call.rawInput?.name === "string" ? call.rawInput.name : call.title ?? subagentId;
|
|
2336
|
+
changed = s.subagents.started(subagentId, call.toolCallId, name);
|
|
2337
|
+
} else if (call.status === "completed" || call.status === "failed") {
|
|
2338
|
+
changed = s.subagents.finished(call.toolCallId, call.status === "completed");
|
|
2339
|
+
}
|
|
2340
|
+
if (changed) this.recordSubagents(s);
|
|
2341
|
+
}
|
|
2342
|
+
recordSubagents(s) {
|
|
2343
|
+
s.record({ kind: "subagents_changed", subagents: s.subagents.list() });
|
|
2344
|
+
}
|
|
2279
2345
|
/** Gets or spawns the kiro process for a session. */
|
|
2280
2346
|
async ensureProc(s) {
|
|
2281
2347
|
if (s.proc) return s.proc;
|
|
2282
2348
|
if (s.spawning) return s.spawning;
|
|
2283
2349
|
s.spawning = (async () => {
|
|
2284
2350
|
await this.ensureCapacity();
|
|
2285
|
-
const proc = this.spawnProcess(
|
|
2286
|
-
{ cwd: s.cwd, agent: s.agentId, model: s.modelId },
|
|
2287
|
-
this.log
|
|
2288
|
-
);
|
|
2351
|
+
const proc = this.spawnProcess({ cwd: s.cwd }, this.log);
|
|
2289
2352
|
this.wire(s, proc);
|
|
2290
2353
|
await proc.initialize();
|
|
2291
2354
|
let res;
|
|
2292
2355
|
if (s.hasBeenLive) {
|
|
2293
2356
|
s.replaying = true;
|
|
2294
2357
|
try {
|
|
2295
|
-
res = await proc.loadSession({
|
|
2358
|
+
res = await proc.loadSession({
|
|
2359
|
+
sessionId: s.sessionId,
|
|
2360
|
+
cwd: s.cwd,
|
|
2361
|
+
mcpServers: [],
|
|
2362
|
+
...s.modelId ? { _meta: { kiro: { modelId: s.modelId } } } : {}
|
|
2363
|
+
});
|
|
2296
2364
|
} finally {
|
|
2297
2365
|
s.replaying = false;
|
|
2298
2366
|
}
|
|
2299
2367
|
} else {
|
|
2300
|
-
res = await proc.newSession({
|
|
2368
|
+
res = await proc.newSession({
|
|
2369
|
+
cwd: s.cwd,
|
|
2370
|
+
mcpServers: [],
|
|
2371
|
+
_meta: { kiro: { modeId: s.agentId, modelId: s.modelId } }
|
|
2372
|
+
});
|
|
2301
2373
|
}
|
|
2302
2374
|
if (!s.hasBeenLive && res.sessionId !== s.sessionId) {
|
|
2303
2375
|
this.sessions.delete(s.sessionId);
|
|
@@ -2307,6 +2379,8 @@ var init_SessionManager = __esm({
|
|
|
2307
2379
|
s.availableModes = res.modes.availableModes;
|
|
2308
2380
|
s.currentModeId = res.modes.currentModeId;
|
|
2309
2381
|
s.agentId = res.modes.currentModeId ?? s.agentId;
|
|
2382
|
+
s.modelId = sessionModel(res) ?? s.modelId;
|
|
2383
|
+
rememberModes(res.modes.availableModes);
|
|
2310
2384
|
s.markLive();
|
|
2311
2385
|
s.proc = proc;
|
|
2312
2386
|
s.spawning = void 0;
|
|
@@ -2347,7 +2421,7 @@ var init_SessionManager = __esm({
|
|
|
2347
2421
|
const s = new Session(tempId, store, cwd);
|
|
2348
2422
|
s.agentId = opts.agentId ?? config.defaultAgent;
|
|
2349
2423
|
s.currentModeId = s.agentId;
|
|
2350
|
-
s.modelId = opts.modelId;
|
|
2424
|
+
s.modelId = opts.modelId ?? await this.defaultModel();
|
|
2351
2425
|
this.sessions.set(tempId, s);
|
|
2352
2426
|
try {
|
|
2353
2427
|
await this.ensureProc(s);
|
|
@@ -2357,7 +2431,7 @@ var init_SessionManager = __esm({
|
|
|
2357
2431
|
}
|
|
2358
2432
|
this.store.create(chatId);
|
|
2359
2433
|
this.store.bindSession(chatId, s.sessionId);
|
|
2360
|
-
const name = sanitizeTitle(opts.title ?? "") || (opts.freshWorkspace ? "" :
|
|
2434
|
+
const name = sanitizeTitle(opts.title ?? "") || (opts.freshWorkspace ? "" : path12.basename(s.cwd));
|
|
2361
2435
|
if (name) {
|
|
2362
2436
|
this.store.setTitle(chatId, name);
|
|
2363
2437
|
s.title = name;
|
|
@@ -2467,12 +2541,29 @@ ${tail}` : err.message;
|
|
|
2467
2541
|
s.modelId = modelId;
|
|
2468
2542
|
s.lastActivity = Date.now();
|
|
2469
2543
|
}
|
|
2544
|
+
/** Runs one of kiro's slash commands. Compaction is the only one Casper offers. It
|
|
2545
|
+
* returns once kiro has started; its progress arrives as compaction events. */
|
|
2470
2546
|
async execCommand(chatId, command) {
|
|
2547
|
+
if (command.replace(/^\//, "") !== "compact") throw new Error(`Unsupported command: ${command}`);
|
|
2471
2548
|
const s = await this.ensureOpen(chatId);
|
|
2472
2549
|
await this.settleReload(s);
|
|
2550
|
+
if (s.turnState.get().compacting) throw new Error("The conversation is already being compacted");
|
|
2473
2551
|
const proc = await this.ensureProc(s);
|
|
2474
|
-
await proc.execCommand(s.sessionId, command);
|
|
2475
2552
|
s.lastActivity = Date.now();
|
|
2553
|
+
const status = (type) => ({
|
|
2554
|
+
kind: "compaction",
|
|
2555
|
+
params: { sessionId: s.sessionId, status: { type }, summary: null }
|
|
2556
|
+
});
|
|
2557
|
+
s.record(status("started"));
|
|
2558
|
+
proc.compact(s.sessionId).then(
|
|
2559
|
+
() => {
|
|
2560
|
+
if (s.turnState.get().compacting && s.proc === proc) s.record(status("completed"));
|
|
2561
|
+
},
|
|
2562
|
+
(err) => {
|
|
2563
|
+
this.log.warn({ err, sessionId: s.sessionId }, "compaction failed");
|
|
2564
|
+
if (s.turnState.get().compacting && s.proc === proc) s.record(status("failed"));
|
|
2565
|
+
}
|
|
2566
|
+
);
|
|
2476
2567
|
}
|
|
2477
2568
|
/** The one place a ChatSummary is assembled, since kiro's file and Casper's
|
|
2478
2569
|
* live state each hold part of the truth. */
|
|
@@ -2500,13 +2591,13 @@ ${tail}` : err.message;
|
|
|
2500
2591
|
}
|
|
2501
2592
|
async listChats() {
|
|
2502
2593
|
const rows = this.store.all();
|
|
2503
|
-
const files = await
|
|
2504
|
-
rows.map((r) => r.sessionId
|
|
2594
|
+
const files = await readPersistedSessions(
|
|
2595
|
+
rows.map((r) => r.sessionId).filter((id) => !!id)
|
|
2505
2596
|
);
|
|
2506
2597
|
const out = [];
|
|
2507
|
-
rows.forEach((row
|
|
2598
|
+
rows.forEach((row) => {
|
|
2508
2599
|
const live = row.sessionId ? this.sessions.get(row.sessionId) : void 0;
|
|
2509
|
-
const persisted = files
|
|
2600
|
+
const persisted = row.sessionId ? files.get(row.sessionId) : void 0;
|
|
2510
2601
|
if (live && isGhost(live, !!persisted)) {
|
|
2511
2602
|
this.evict(live.sessionId);
|
|
2512
2603
|
return;
|
|
@@ -2549,68 +2640,36 @@ ${tail}` : err.message;
|
|
|
2549
2640
|
const end = Math.max(start, Math.min(start + limit, transcript.length));
|
|
2550
2641
|
return transcript.slice(start, end);
|
|
2551
2642
|
}
|
|
2552
|
-
/**
|
|
2553
|
-
* A
|
|
2554
|
-
* A child the tracker never saw falls back to a recorded link or title matching
|
|
2555
|
-
* (subagentFallbackMatch.ts).
|
|
2556
|
-
*/
|
|
2643
|
+
/** A chat's subagents: the ones kiro recorded in the session's file, and live ones from
|
|
2644
|
+
* the tracker. A live row wins over the file's until the file records how it ended. */
|
|
2557
2645
|
async getSubagents(chatId) {
|
|
2558
2646
|
const sessionId = this.sessionIdOf(chatId);
|
|
2559
|
-
const
|
|
2560
|
-
const live = s ? s.subagents.list() : [];
|
|
2561
|
-
const liveToolCalls = new Set(live.map((a) => a.toolCallId).filter((id) => !!id));
|
|
2562
|
-
const pending = s ? [...liveToolCalls].flatMap((id) => s.subagents.listForCall(id).filter((a) => a.status === "pending")) : [];
|
|
2563
|
-
const onDisk = await listChildSessions(sessionId);
|
|
2564
|
-
const links = this.subagentLinks.forParent(sessionId);
|
|
2565
|
-
const liveIds = new Set(live.map((a) => a.sessionId));
|
|
2566
|
-
const tried = this.unmatchedChildren.get(sessionId) ?? /* @__PURE__ */ new Set();
|
|
2567
|
-
const unresolved = onDisk.filter(
|
|
2568
|
-
(c) => !liveIds.has(c.sessionId) && !links.has(c.sessionId) && !tried.has(c.sessionId)
|
|
2569
|
-
);
|
|
2570
|
-
const fallback = unresolved.length ? matchSubagentsFallback(subagentCallsIn(await hydrateTranscript(sessionId)), unresolved) : [];
|
|
2571
|
-
const fallbackByChild = new Map(fallback.map((m) => [m.sessionId, m]));
|
|
2572
|
-
for (const m of fallback) this.subagentLinks.record(m.sessionId, sessionId, m.toolCallId, m.stageName);
|
|
2573
|
-
for (const c of unresolved) if (!fallbackByChild.has(c.sessionId)) tried.add(c.sessionId);
|
|
2574
|
-
this.unmatchedChildren.set(sessionId, tried);
|
|
2647
|
+
const live = this.sessions.get(sessionId)?.subagents.list() ?? [];
|
|
2575
2648
|
const byId = /* @__PURE__ */ new Map();
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
byId.set(
|
|
2579
|
-
|
|
2580
|
-
stageName: link?.stageName ?? (child.title || child.sessionId),
|
|
2581
|
-
toolCallId: link?.toolCallId,
|
|
2582
|
-
status: "completed",
|
|
2583
|
-
createdAt: child.createdAt,
|
|
2584
|
-
updatedAt: child.updatedAt
|
|
2585
|
-
});
|
|
2649
|
+
const finished = /* @__PURE__ */ new Set();
|
|
2650
|
+
for (const sub of await listSubExecutions(sessionId) ?? []) {
|
|
2651
|
+
byId.set(sub.sessionId, subExecutionSummary(sub));
|
|
2652
|
+
if (!sub.stopped) finished.add(sub.sessionId);
|
|
2586
2653
|
}
|
|
2587
|
-
for (const a of live) byId.set(a.sessionId, a);
|
|
2588
|
-
|
|
2589
|
-
return [...startedThenPending, ...pending];
|
|
2654
|
+
for (const a of live) if (!finished.has(a.sessionId)) byId.set(a.sessionId, a);
|
|
2655
|
+
return [...byId.values()].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
2590
2656
|
}
|
|
2591
2657
|
/** One subagent's own transcript, hydrated the same way a chat's is. */
|
|
2592
|
-
// Polled while a subagent runs, so it reads only the
|
|
2593
|
-
async getSubagentDetail(chatId,
|
|
2658
|
+
// Polled while a subagent runs, so it reads only the subagent's own files.
|
|
2659
|
+
async getSubagentDetail(chatId, subagentId) {
|
|
2594
2660
|
const parentSessionId = this.sessionIdOf(chatId);
|
|
2595
|
-
const
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
const
|
|
2599
|
-
const
|
|
2600
|
-
|
|
2601
|
-
stageName: link?.stageName ?? (child.title || childSessionId),
|
|
2602
|
-
toolCallId: link?.toolCallId,
|
|
2603
|
-
status: "completed",
|
|
2604
|
-
createdAt: child.createdAt,
|
|
2605
|
-
updatedAt: child.updatedAt
|
|
2606
|
-
};
|
|
2607
|
-
const transcript = showSummaryAsAnswer(await hydrateTranscript(childSessionId));
|
|
2608
|
-
return { subagent: summary, transcript };
|
|
2661
|
+
const live = this.sessions.get(parentSessionId)?.subagents.get(subagentId);
|
|
2662
|
+
const recorded = (await listSubExecutions(parentSessionId))?.find((x) => x.sessionId === subagentId);
|
|
2663
|
+
if (!live && !recorded) throw new Error(`Unknown subagent: ${subagentId}`);
|
|
2664
|
+
const transcript = await hydrateSubExecution(parentSessionId, subagentId) ?? [];
|
|
2665
|
+
const subagent = recorded && (!live || !recorded.stopped) ? subExecutionSummary(recorded) : live;
|
|
2666
|
+
return { subagent, transcript };
|
|
2609
2667
|
}
|
|
2610
2668
|
/** One projection, so a dormant session and a live one cannot disagree. */
|
|
2611
|
-
buildDetail(chat, s,
|
|
2669
|
+
buildDetail(chat, s, hydrated, persisted) {
|
|
2670
|
+
const { transcript, head } = this.resumePoint(s, hydrated);
|
|
2612
2671
|
return {
|
|
2613
|
-
summary: this.summaryOf(chat, s, persisted,
|
|
2672
|
+
summary: this.summaryOf(chat, s, persisted, hydrated),
|
|
2614
2673
|
modes: s?.availableModes ?? [],
|
|
2615
2674
|
currentModeId: s?.currentModeId ?? persisted?.agentId,
|
|
2616
2675
|
transcript: transcript.slice(-TRANSCRIPT_PAGE_SIZE),
|
|
@@ -2619,16 +2678,19 @@ ${tail}` : err.message;
|
|
|
2619
2678
|
...emptyObservabilitySnapshot(),
|
|
2620
2679
|
contextUsagePercentage: persisted?.contextUsagePercentage ?? 0
|
|
2621
2680
|
},
|
|
2622
|
-
head
|
|
2681
|
+
head
|
|
2623
2682
|
};
|
|
2624
2683
|
}
|
|
2625
2684
|
/**
|
|
2626
|
-
*
|
|
2627
|
-
* turn
|
|
2685
|
+
* Where a reconnecting client picks up: the transcript, and the cursor its events replay
|
|
2686
|
+
* after. A turn in flight replays whole from its turn_started and is left out of the
|
|
2687
|
+
* transcript, since kiro writes the prompt at once but a tool call only once it ends, so
|
|
2688
|
+
* kiro's copy of the turn lacks whatever is still running.
|
|
2628
2689
|
*/
|
|
2629
|
-
|
|
2690
|
+
resumePoint(s, transcript) {
|
|
2691
|
+
if (!s) return { transcript, head: 0 };
|
|
2630
2692
|
const head = s.store.head();
|
|
2631
|
-
if (!s.running) return head;
|
|
2693
|
+
if (!s.running) return { transcript, head };
|
|
2632
2694
|
const { events } = s.store.getSince(0);
|
|
2633
2695
|
let started;
|
|
2634
2696
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
@@ -2637,18 +2699,19 @@ ${tail}` : err.message;
|
|
|
2637
2699
|
break;
|
|
2638
2700
|
}
|
|
2639
2701
|
}
|
|
2640
|
-
if (!started || started.payload.kind !== "turn_started") return head;
|
|
2702
|
+
if (!started || started.payload.kind !== "turn_started") return { transcript, head };
|
|
2641
2703
|
const promptText = stripAttachmentsLine(
|
|
2642
2704
|
started.payload.prompt.filter((b) => b.type === "text").map((b) => b.text).join("")
|
|
2643
2705
|
).trim();
|
|
2706
|
+
let cut = transcript.length;
|
|
2644
2707
|
for (let i = transcript.length - 1; i >= 0; i--) {
|
|
2645
2708
|
const it = transcript[i];
|
|
2646
2709
|
if (it.type === "message" && it.message.role === "user") {
|
|
2647
|
-
if (promptText && it.message.text.trim() === promptText)
|
|
2710
|
+
if (promptText && it.message.text.trim() === promptText) cut = i;
|
|
2648
2711
|
break;
|
|
2649
2712
|
}
|
|
2650
2713
|
}
|
|
2651
|
-
return started.seq - 1;
|
|
2714
|
+
return { transcript: transcript.slice(0, cut), head: started.seq - 1 };
|
|
2652
2715
|
}
|
|
2653
2716
|
evict(sessionId) {
|
|
2654
2717
|
const s = this.sessions.get(sessionId);
|
|
@@ -2682,6 +2745,70 @@ ${tail}` : err.message;
|
|
|
2682
2745
|
}
|
|
2683
2746
|
});
|
|
2684
2747
|
|
|
2748
|
+
// server/src/session/models.ts
|
|
2749
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
2750
|
+
import { promisify as promisify2 } from "node:util";
|
|
2751
|
+
async function configuredDefault() {
|
|
2752
|
+
try {
|
|
2753
|
+
const { stdout } = await execFileAsync2(config.kiroBin, [
|
|
2754
|
+
"settings",
|
|
2755
|
+
"chat.defaultModel",
|
|
2756
|
+
"-f",
|
|
2757
|
+
"json"
|
|
2758
|
+
]);
|
|
2759
|
+
const value = JSON.parse(stdout);
|
|
2760
|
+
return typeof value === "string" && value ? value : void 0;
|
|
2761
|
+
} catch {
|
|
2762
|
+
return void 0;
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
async function listModels(log) {
|
|
2766
|
+
if (cache2) return cache2;
|
|
2767
|
+
const { stdout } = await execFileAsync2(
|
|
2768
|
+
config.kiroBin,
|
|
2769
|
+
["chat", "--list-models", "-f", "json"],
|
|
2770
|
+
{ maxBuffer: 4 * 1024 * 1024 }
|
|
2771
|
+
);
|
|
2772
|
+
const parsed = JSON.parse(stdout);
|
|
2773
|
+
const configured = await configuredDefault();
|
|
2774
|
+
const preferred = parsed.models.some((m) => m.model_id === configured) ? configured : parsed.default_model;
|
|
2775
|
+
cache2 = parsed.models.map((m, i) => ({
|
|
2776
|
+
modelId: m.model_id,
|
|
2777
|
+
modelName: m.model_name,
|
|
2778
|
+
description: m.description,
|
|
2779
|
+
contextWindowTokens: m.context_window_tokens,
|
|
2780
|
+
rateMultiplier: m.rate_multiplier,
|
|
2781
|
+
rateUnit: m.rate_unit,
|
|
2782
|
+
isDefault: preferred ? m.model_id === preferred : m.default_model ?? i === 0
|
|
2783
|
+
}));
|
|
2784
|
+
log.info({ count: cache2.length, default: preferred }, "loaded model list");
|
|
2785
|
+
return cache2;
|
|
2786
|
+
}
|
|
2787
|
+
async function defaultModelId(log) {
|
|
2788
|
+
try {
|
|
2789
|
+
return (await listModels(log)).find((m) => m.isDefault)?.modelId;
|
|
2790
|
+
} catch {
|
|
2791
|
+
return void 0;
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
async function kiroVersion() {
|
|
2795
|
+
try {
|
|
2796
|
+
const { stdout } = await execFileAsync2(config.kiroBin, ["--version"]);
|
|
2797
|
+
return stdout.trim();
|
|
2798
|
+
} catch {
|
|
2799
|
+
return void 0;
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
var execFileAsync2, cache2;
|
|
2803
|
+
var init_models = __esm({
|
|
2804
|
+
"server/src/session/models.ts"() {
|
|
2805
|
+
"use strict";
|
|
2806
|
+
init_config();
|
|
2807
|
+
execFileAsync2 = promisify2(execFile2);
|
|
2808
|
+
cache2 = null;
|
|
2809
|
+
}
|
|
2810
|
+
});
|
|
2811
|
+
|
|
2685
2812
|
// server/src/util/rateLimit.ts
|
|
2686
2813
|
var AttemptLimiter;
|
|
2687
2814
|
var init_rateLimit = __esm({
|
|
@@ -2828,63 +2955,6 @@ var init_auth = __esm({
|
|
|
2828
2955
|
}
|
|
2829
2956
|
});
|
|
2830
2957
|
|
|
2831
|
-
// server/src/session/models.ts
|
|
2832
|
-
import { execFile as execFile2 } from "node:child_process";
|
|
2833
|
-
import { promisify as promisify2 } from "node:util";
|
|
2834
|
-
async function configuredDefault() {
|
|
2835
|
-
try {
|
|
2836
|
-
const { stdout } = await execFileAsync2(config.kiroBin, [
|
|
2837
|
-
"settings",
|
|
2838
|
-
"chat.defaultModel",
|
|
2839
|
-
"-f",
|
|
2840
|
-
"json"
|
|
2841
|
-
]);
|
|
2842
|
-
const value = JSON.parse(stdout);
|
|
2843
|
-
return typeof value === "string" && value ? value : void 0;
|
|
2844
|
-
} catch {
|
|
2845
|
-
return void 0;
|
|
2846
|
-
}
|
|
2847
|
-
}
|
|
2848
|
-
async function listModels(log) {
|
|
2849
|
-
if (cache2) return cache2;
|
|
2850
|
-
const { stdout } = await execFileAsync2(
|
|
2851
|
-
config.kiroBin,
|
|
2852
|
-
["chat", "--list-models", "-f", "json"],
|
|
2853
|
-
{ maxBuffer: 4 * 1024 * 1024 }
|
|
2854
|
-
);
|
|
2855
|
-
const parsed = JSON.parse(stdout);
|
|
2856
|
-
const configured = await configuredDefault();
|
|
2857
|
-
const preferred = parsed.models.some((m) => m.model_id === configured) ? configured : parsed.default_model;
|
|
2858
|
-
cache2 = parsed.models.map((m, i) => ({
|
|
2859
|
-
modelId: m.model_id,
|
|
2860
|
-
modelName: m.model_name,
|
|
2861
|
-
description: m.description,
|
|
2862
|
-
contextWindowTokens: m.context_window_tokens,
|
|
2863
|
-
rateMultiplier: m.rate_multiplier,
|
|
2864
|
-
rateUnit: m.rate_unit,
|
|
2865
|
-
isDefault: preferred ? m.model_id === preferred : m.default_model ?? i === 0
|
|
2866
|
-
}));
|
|
2867
|
-
log.info({ count: cache2.length, default: preferred }, "loaded model list");
|
|
2868
|
-
return cache2;
|
|
2869
|
-
}
|
|
2870
|
-
async function kiroVersion() {
|
|
2871
|
-
try {
|
|
2872
|
-
const { stdout } = await execFileAsync2(config.kiroBin, ["--version"]);
|
|
2873
|
-
return stdout.trim();
|
|
2874
|
-
} catch {
|
|
2875
|
-
return void 0;
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
|
-
var execFileAsync2, cache2;
|
|
2879
|
-
var init_models = __esm({
|
|
2880
|
-
"server/src/session/models.ts"() {
|
|
2881
|
-
"use strict";
|
|
2882
|
-
init_config();
|
|
2883
|
-
execFileAsync2 = promisify2(execFile2);
|
|
2884
|
-
cache2 = null;
|
|
2885
|
-
}
|
|
2886
|
-
});
|
|
2887
|
-
|
|
2888
2958
|
// server/src/routes/models.ts
|
|
2889
2959
|
function registerModelRoutes(app) {
|
|
2890
2960
|
app.get("/api/models", async () => {
|
|
@@ -2914,8 +2984,8 @@ var init_agents2 = __esm({
|
|
|
2914
2984
|
});
|
|
2915
2985
|
|
|
2916
2986
|
// server/src/util/confinedFile.ts
|
|
2917
|
-
import
|
|
2918
|
-
import
|
|
2987
|
+
import fs12 from "node:fs/promises";
|
|
2988
|
+
import path13 from "node:path";
|
|
2919
2989
|
async function resolveConfined(input, spec) {
|
|
2920
2990
|
let target = null;
|
|
2921
2991
|
for (const root of spec.lexical) {
|
|
@@ -2931,7 +3001,7 @@ async function resolveConfined(input, spec) {
|
|
|
2931
3001
|
if (!real) return { ok: false, ...await spec.notFound() };
|
|
2932
3002
|
let stat;
|
|
2933
3003
|
try {
|
|
2934
|
-
stat = await
|
|
3004
|
+
stat = await fs12.stat(real);
|
|
2935
3005
|
} catch {
|
|
2936
3006
|
return { ok: false, ...await spec.notFound() };
|
|
2937
3007
|
}
|
|
@@ -2970,7 +3040,7 @@ async function resolveChatPath(sessions, sessionId, requestedPath, require2) {
|
|
|
2970
3040
|
async function workspaceNotFound(cwd) {
|
|
2971
3041
|
let missing;
|
|
2972
3042
|
try {
|
|
2973
|
-
missing = !(await
|
|
3043
|
+
missing = !(await fs12.stat(cwd)).isDirectory();
|
|
2974
3044
|
} catch {
|
|
2975
3045
|
missing = true;
|
|
2976
3046
|
}
|
|
@@ -2990,7 +3060,7 @@ async function resolveAbsolutePath(input, require2) {
|
|
|
2990
3060
|
});
|
|
2991
3061
|
}
|
|
2992
3062
|
async function classifyDirent(parentReal, entry, realRoots) {
|
|
2993
|
-
const absolute =
|
|
3063
|
+
const absolute = path13.join(parentReal, entry.name);
|
|
2994
3064
|
if (entry.isDirectory()) return { kind: "directory", real: absolute };
|
|
2995
3065
|
if (entry.isFile()) return { kind: "file", real: absolute };
|
|
2996
3066
|
if (!entry.isSymbolicLink()) return null;
|
|
@@ -2998,7 +3068,7 @@ async function classifyDirent(parentReal, entry, realRoots) {
|
|
|
2998
3068
|
const real = await realConfineToRoot(root, absolute);
|
|
2999
3069
|
if (!real) continue;
|
|
3000
3070
|
try {
|
|
3001
|
-
const stat = await
|
|
3071
|
+
const stat = await fs12.stat(real);
|
|
3002
3072
|
if (stat.isDirectory()) return { kind: "directory", real };
|
|
3003
3073
|
if (stat.isFile()) return { kind: "file", real };
|
|
3004
3074
|
} catch {
|
|
@@ -3016,7 +3086,7 @@ var init_confinedFile = __esm({
|
|
|
3016
3086
|
});
|
|
3017
3087
|
|
|
3018
3088
|
// server/src/util/filekind.ts
|
|
3019
|
-
import
|
|
3089
|
+
import path14 from "node:path";
|
|
3020
3090
|
function mimeForExt(ext) {
|
|
3021
3091
|
return MIME_MAP[ext.toLowerCase()] ?? "application/octet-stream";
|
|
3022
3092
|
}
|
|
@@ -3036,7 +3106,7 @@ function looksBinary(buf) {
|
|
|
3036
3106
|
return control / buf.length > 0.3;
|
|
3037
3107
|
}
|
|
3038
3108
|
function classifyKind(name) {
|
|
3039
|
-
const ext =
|
|
3109
|
+
const ext = path14.extname(name).toLowerCase();
|
|
3040
3110
|
if (ext in IMAGE_EXTS) return "image";
|
|
3041
3111
|
if (TEXT_EXTS.has(ext)) return "text";
|
|
3042
3112
|
return "binary";
|
|
@@ -3146,9 +3216,9 @@ var init_filekind = __esm({
|
|
|
3146
3216
|
});
|
|
3147
3217
|
|
|
3148
3218
|
// server/src/routes/filePreview.ts
|
|
3149
|
-
import
|
|
3219
|
+
import fs13 from "node:fs/promises";
|
|
3150
3220
|
import { createReadStream } from "node:fs";
|
|
3151
|
-
import
|
|
3221
|
+
import path15 from "node:path";
|
|
3152
3222
|
function tooLargeForPreview(size, maxBytes) {
|
|
3153
3223
|
return {
|
|
3154
3224
|
error: `File too large for preview (${(size / 1024 / 1024).toFixed(1)} MB, max ${maxBytes / 1024 / 1024} MB)`
|
|
@@ -3175,7 +3245,7 @@ function hexdump(buf) {
|
|
|
3175
3245
|
return lines.join("\n");
|
|
3176
3246
|
}
|
|
3177
3247
|
async function sendFilePreview(req, reply, realTarget, stat) {
|
|
3178
|
-
const ext =
|
|
3248
|
+
const ext = path15.extname(realTarget).toLowerCase();
|
|
3179
3249
|
const mime = mimeForExt(ext);
|
|
3180
3250
|
const isImage2 = mime.startsWith("image/");
|
|
3181
3251
|
const isPdf = mime === "application/pdf";
|
|
@@ -3220,7 +3290,7 @@ async function sendFilePreview(req, reply, realTarget, stat) {
|
|
|
3220
3290
|
if (kind === "binary") {
|
|
3221
3291
|
let fh;
|
|
3222
3292
|
try {
|
|
3223
|
-
fh = await
|
|
3293
|
+
fh = await fs13.open(realTarget, "r");
|
|
3224
3294
|
const buf = Buffer.alloc(Math.min(HEXDUMP_BYTES, stat.size));
|
|
3225
3295
|
const { bytesRead } = await fh.read(buf, 0, buf.length, 0);
|
|
3226
3296
|
const head = buf.subarray(0, bytesRead);
|
|
@@ -3264,9 +3334,9 @@ var init_filePreview = __esm({
|
|
|
3264
3334
|
});
|
|
3265
3335
|
|
|
3266
3336
|
// server/src/routes/fs.ts
|
|
3267
|
-
import
|
|
3337
|
+
import fs14 from "node:fs/promises";
|
|
3268
3338
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
3269
|
-
import
|
|
3339
|
+
import path16 from "node:path";
|
|
3270
3340
|
function registerFsRoutes(app) {
|
|
3271
3341
|
app.get(
|
|
3272
3342
|
"/api/fs/dirs",
|
|
@@ -3274,10 +3344,10 @@ function registerFsRoutes(app) {
|
|
|
3274
3344
|
const input = (req.query.path ?? "").trim();
|
|
3275
3345
|
const base = config.defaultCwd;
|
|
3276
3346
|
const endsWithSep = input.endsWith("/");
|
|
3277
|
-
const resolved = input ?
|
|
3278
|
-
const dir = endsWithSep || !input ? resolved :
|
|
3279
|
-
const prefix = endsWithSep || !input ? "" :
|
|
3280
|
-
const targetKind = await
|
|
3347
|
+
const resolved = input ? path16.resolve(base, input) : base;
|
|
3348
|
+
const dir = endsWithSep || !input ? resolved : path16.dirname(resolved);
|
|
3349
|
+
const prefix = endsWithSep || !input ? "" : path16.basename(resolved);
|
|
3350
|
+
const targetKind = await fs14.stat(resolved).then((s) => s.isDirectory() ? "directory" : "file").catch(() => "missing");
|
|
3281
3351
|
const listing = await resolveAbsolutePath(dir, "directory");
|
|
3282
3352
|
if (!listing.ok) {
|
|
3283
3353
|
if (listing.status === 403) return replyWith(reply, listing);
|
|
@@ -3286,7 +3356,7 @@ function registerFsRoutes(app) {
|
|
|
3286
3356
|
const realDir = listing.real;
|
|
3287
3357
|
let entries = [];
|
|
3288
3358
|
try {
|
|
3289
|
-
const dirents = await
|
|
3359
|
+
const dirents = await fs14.readdir(realDir, { withFileTypes: true });
|
|
3290
3360
|
const checks2 = await Promise.all(
|
|
3291
3361
|
dirents.map(async (d) => {
|
|
3292
3362
|
const target = await classifyDirent(realDir, d, absoluteRoots());
|
|
@@ -3297,7 +3367,7 @@ function registerFsRoutes(app) {
|
|
|
3297
3367
|
entries = checks2.filter((name) => name !== null).filter((name) => name.toLowerCase().startsWith(prefix.toLowerCase())).sort((a, b) => {
|
|
3298
3368
|
if (isDot(a) !== isDot(b)) return isDot(a) ? 1 : -1;
|
|
3299
3369
|
return a.localeCompare(b);
|
|
3300
|
-
}).slice(0, 500).map((name) =>
|
|
3370
|
+
}).slice(0, 500).map((name) => path16.join(dir, name));
|
|
3301
3371
|
} catch {
|
|
3302
3372
|
entries = [];
|
|
3303
3373
|
}
|
|
@@ -3312,7 +3382,7 @@ function registerFsRoutes(app) {
|
|
|
3312
3382
|
reply.code(400);
|
|
3313
3383
|
return { error: "path parameter is required" };
|
|
3314
3384
|
}
|
|
3315
|
-
if (!
|
|
3385
|
+
if (!path16.isAbsolute(filePath)) {
|
|
3316
3386
|
reply.code(400);
|
|
3317
3387
|
return { error: "path must be absolute" };
|
|
3318
3388
|
}
|
|
@@ -3322,7 +3392,7 @@ function registerFsRoutes(app) {
|
|
|
3322
3392
|
reply.header("Content-Type", "application/octet-stream");
|
|
3323
3393
|
reply.header(
|
|
3324
3394
|
"Content-Disposition",
|
|
3325
|
-
`attachment; filename="${
|
|
3395
|
+
`attachment; filename="${path16.basename(resolved.real).replace(/"/g, "")}"`
|
|
3326
3396
|
);
|
|
3327
3397
|
reply.header("Content-Length", resolved.stat.size);
|
|
3328
3398
|
return reply.send(createReadStream2(resolved.real));
|
|
@@ -3493,9 +3563,9 @@ var init_subagents = __esm({
|
|
|
3493
3563
|
});
|
|
3494
3564
|
|
|
3495
3565
|
// server/src/routes/workspace.ts
|
|
3496
|
-
import
|
|
3566
|
+
import fs15 from "node:fs/promises";
|
|
3497
3567
|
import { createReadStream as createReadStream3 } from "node:fs";
|
|
3498
|
-
import
|
|
3568
|
+
import path17 from "node:path";
|
|
3499
3569
|
function registerWorkspaceRoutes(app, manager) {
|
|
3500
3570
|
app.get(
|
|
3501
3571
|
"/api/chats/:id/tree",
|
|
@@ -3510,7 +3580,7 @@ function registerWorkspaceRoutes(app, manager) {
|
|
|
3510
3580
|
const { cwd, relative, real: realTarget } = resolved;
|
|
3511
3581
|
let dirents;
|
|
3512
3582
|
try {
|
|
3513
|
-
dirents = await
|
|
3583
|
+
dirents = await fs15.readdir(realTarget, { withFileTypes: true, encoding: "utf8" });
|
|
3514
3584
|
} catch {
|
|
3515
3585
|
return replyWith(reply, await workspaceNotFound(cwd));
|
|
3516
3586
|
}
|
|
@@ -3524,7 +3594,7 @@ function registerWorkspaceRoutes(app, manager) {
|
|
|
3524
3594
|
continue;
|
|
3525
3595
|
}
|
|
3526
3596
|
try {
|
|
3527
|
-
const stat = await
|
|
3597
|
+
const stat = await fs15.stat(target.real);
|
|
3528
3598
|
entries.push({
|
|
3529
3599
|
name: d.name,
|
|
3530
3600
|
path: entryRelative,
|
|
@@ -3553,8 +3623,8 @@ function registerWorkspaceRoutes(app, manager) {
|
|
|
3553
3623
|
reply.code(413);
|
|
3554
3624
|
return { error: `File too large (${(stat.size / 1024 / 1024).toFixed(1)} MB, max 100 MB)` };
|
|
3555
3625
|
}
|
|
3556
|
-
const ext =
|
|
3557
|
-
const filename =
|
|
3626
|
+
const ext = path17.extname(realTarget);
|
|
3627
|
+
const filename = path17.basename(realTarget);
|
|
3558
3628
|
const asciiName = filename.replace(/[^\w.\-]/g, "_");
|
|
3559
3629
|
reply.header("Content-Type", mimeForExt(ext));
|
|
3560
3630
|
reply.header(
|
|
@@ -3589,27 +3659,27 @@ var init_workspace = __esm({
|
|
|
3589
3659
|
|
|
3590
3660
|
// server/src/routes/uploads.ts
|
|
3591
3661
|
import { createReadStream as createReadStream4, createWriteStream } from "node:fs";
|
|
3592
|
-
import
|
|
3593
|
-
import
|
|
3662
|
+
import fs16 from "node:fs/promises";
|
|
3663
|
+
import path18 from "node:path";
|
|
3594
3664
|
import crypto4 from "node:crypto";
|
|
3595
3665
|
import { execFile as execFile3 } from "node:child_process";
|
|
3596
3666
|
import { pipeline } from "node:stream/promises";
|
|
3597
3667
|
function sanitizeName(raw) {
|
|
3598
|
-
const base =
|
|
3668
|
+
const base = path18.basename(raw).replace(/[^\w.\- ]/g, "_").trim();
|
|
3599
3669
|
if (!base || base === "." || base === "..") return `upload-${Date.now()}`;
|
|
3600
3670
|
return base.replace(/^\.+/, "") || `upload-${Date.now()}`;
|
|
3601
3671
|
}
|
|
3602
3672
|
async function uniquePath(dir, name) {
|
|
3603
|
-
const ext =
|
|
3673
|
+
const ext = path18.extname(name);
|
|
3604
3674
|
const stem = name.slice(0, name.length - ext.length);
|
|
3605
3675
|
let candidate = name;
|
|
3606
3676
|
let n = 1;
|
|
3607
3677
|
while (true) {
|
|
3608
3678
|
try {
|
|
3609
|
-
await
|
|
3679
|
+
await fs16.access(path18.join(dir, candidate));
|
|
3610
3680
|
candidate = `${stem} (${n++})${ext}`;
|
|
3611
3681
|
} catch {
|
|
3612
|
-
return
|
|
3682
|
+
return path18.join(dir, candidate);
|
|
3613
3683
|
}
|
|
3614
3684
|
}
|
|
3615
3685
|
}
|
|
@@ -3629,7 +3699,7 @@ function fileType(absPath) {
|
|
|
3629
3699
|
async function sampleStrings(absPath, limit = 40) {
|
|
3630
3700
|
let fh;
|
|
3631
3701
|
try {
|
|
3632
|
-
fh = await
|
|
3702
|
+
fh = await fs16.open(absPath, "r");
|
|
3633
3703
|
const buf = Buffer.alloc(STRINGS_SCAN_BYTES);
|
|
3634
3704
|
const { bytesRead } = await fh.read(buf, 0, STRINGS_SCAN_BYTES, 0);
|
|
3635
3705
|
const out = [];
|
|
@@ -3661,7 +3731,7 @@ function registerUploadRoutes(app) {
|
|
|
3661
3731
|
return { error: "Invalid chat id" };
|
|
3662
3732
|
}
|
|
3663
3733
|
const uploadDir = chatUploadsDir(req.params.chatId);
|
|
3664
|
-
await
|
|
3734
|
+
await fs16.mkdir(uploadDir, { recursive: true, mode: 448 });
|
|
3665
3735
|
const results = [];
|
|
3666
3736
|
const parts = req.files();
|
|
3667
3737
|
for await (const part of parts) {
|
|
@@ -3675,17 +3745,17 @@ function registerUploadRoutes(app) {
|
|
|
3675
3745
|
return { error: `Failed to store ${name}` };
|
|
3676
3746
|
}
|
|
3677
3747
|
if (part.file.truncated) {
|
|
3678
|
-
await
|
|
3748
|
+
await fs16.rm(dest, { force: true });
|
|
3679
3749
|
reply.code(413);
|
|
3680
3750
|
return {
|
|
3681
3751
|
error: `${name} exceeds the max upload size (${Math.round(config.maxUploadBytes / 1024 / 1024)} MB)`
|
|
3682
3752
|
};
|
|
3683
3753
|
}
|
|
3684
|
-
const stat = await
|
|
3685
|
-
const ext =
|
|
3754
|
+
const stat = await fs16.stat(dest);
|
|
3755
|
+
const ext = path18.extname(dest);
|
|
3686
3756
|
const kind = classifyKind(dest);
|
|
3687
3757
|
const uploaded = {
|
|
3688
|
-
name:
|
|
3758
|
+
name: path18.basename(dest),
|
|
3689
3759
|
path: dest,
|
|
3690
3760
|
size: stat.size,
|
|
3691
3761
|
mimeType: mimeForExt(ext),
|
|
@@ -3741,7 +3811,7 @@ var init_health = __esm({
|
|
|
3741
3811
|
});
|
|
3742
3812
|
|
|
3743
3813
|
// server/src/ws/dirWatchers.ts
|
|
3744
|
-
import
|
|
3814
|
+
import fs17 from "node:fs";
|
|
3745
3815
|
function diffWatchSet(current, next) {
|
|
3746
3816
|
const have = new Set(current);
|
|
3747
3817
|
const want = new Set(next.slice(0, MAX_WATCHES));
|
|
@@ -3765,7 +3835,7 @@ function createDirWatchers(opts) {
|
|
|
3765
3835
|
const target = await opts.resolve(relative);
|
|
3766
3836
|
if (!target || closed) return;
|
|
3767
3837
|
try {
|
|
3768
|
-
const watcher =
|
|
3838
|
+
const watcher = fs17.watch(target, { persistent: false }, () => {
|
|
3769
3839
|
const existing = timers.get(relative);
|
|
3770
3840
|
if (existing) clearTimeout(existing);
|
|
3771
3841
|
timers.set(
|
|
@@ -3823,7 +3893,7 @@ function handleConnection(socket, manager, chatId, startCursor) {
|
|
|
3823
3893
|
return null;
|
|
3824
3894
|
}
|
|
3825
3895
|
},
|
|
3826
|
-
onChange: (
|
|
3896
|
+
onChange: (path21) => send(socket, { type: "fs_changed", path: path21 })
|
|
3827
3897
|
});
|
|
3828
3898
|
const forward = (event) => {
|
|
3829
3899
|
if (event.seq <= cursor) return;
|
|
@@ -3956,7 +4026,7 @@ var init_gateway = __esm({
|
|
|
3956
4026
|
});
|
|
3957
4027
|
|
|
3958
4028
|
// server/src/app.ts
|
|
3959
|
-
import
|
|
4029
|
+
import fs18 from "node:fs";
|
|
3960
4030
|
import Fastify from "fastify";
|
|
3961
4031
|
import websocket from "@fastify/websocket";
|
|
3962
4032
|
import fastifyStatic from "@fastify/static";
|
|
@@ -3975,7 +4045,7 @@ async function buildApp() {
|
|
|
3975
4045
|
transport: isProd ? void 0 : { target: "pino/file", options: { destination: 2 } }
|
|
3976
4046
|
}
|
|
3977
4047
|
});
|
|
3978
|
-
const manager = new SessionManager(logger);
|
|
4048
|
+
const manager = new SessionManager(logger, { defaultModel: () => defaultModelId(logger) });
|
|
3979
4049
|
const startedAt = Date.now();
|
|
3980
4050
|
await app.register(websocket, {
|
|
3981
4051
|
options: { maxPayload: 16 * 1024 * 1024 }
|
|
@@ -3993,20 +4063,20 @@ async function buildApp() {
|
|
|
3993
4063
|
registerWorkspaceRoutes(app, manager);
|
|
3994
4064
|
registerUploadRoutes(app);
|
|
3995
4065
|
registerWsGateway(app, manager);
|
|
3996
|
-
if (
|
|
4066
|
+
if (fs18.existsSync(config.webDist)) {
|
|
3997
4067
|
await app.register(fastifyStatic, {
|
|
3998
4068
|
root: config.webDist
|
|
3999
4069
|
});
|
|
4000
4070
|
app.addHook("onSend", async (req, reply) => {
|
|
4001
|
-
const
|
|
4002
|
-
if (
|
|
4071
|
+
const path21 = req.url.split("?")[0] ?? "";
|
|
4072
|
+
if (path21 === "/manifest.json" || path21.startsWith("/icons/")) {
|
|
4003
4073
|
reply.header("cache-control", "public, max-age=300");
|
|
4004
4074
|
}
|
|
4005
4075
|
});
|
|
4006
4076
|
app.setNotFoundHandler((req, reply) => {
|
|
4007
|
-
const
|
|
4008
|
-
const looksLikeAsset =
|
|
4009
|
-
if (
|
|
4077
|
+
const path21 = req.url.split("?")[0] ?? "";
|
|
4078
|
+
const looksLikeAsset = path21.startsWith("/assets/") || /\.[a-zA-Z0-9]+$/.test(path21);
|
|
4079
|
+
if (path21.startsWith("/api/") || path21.startsWith("/ws") || looksLikeAsset) {
|
|
4010
4080
|
reply.code(404).send({ error: "Not found" });
|
|
4011
4081
|
return;
|
|
4012
4082
|
}
|
|
@@ -4021,6 +4091,7 @@ var init_app = __esm({
|
|
|
4021
4091
|
init_config();
|
|
4022
4092
|
init_logger();
|
|
4023
4093
|
init_SessionManager();
|
|
4094
|
+
init_models();
|
|
4024
4095
|
init_auth();
|
|
4025
4096
|
init_models2();
|
|
4026
4097
|
init_agents2();
|
|
@@ -4077,19 +4148,22 @@ var init_server = __esm({
|
|
|
4077
4148
|
// server/src/cli/doctor.ts
|
|
4078
4149
|
var doctor_exports = {};
|
|
4079
4150
|
__export(doctor_exports, {
|
|
4151
|
+
agentFormat: () => agentFormat,
|
|
4080
4152
|
doctor: () => doctor,
|
|
4153
|
+
kiroMajor: () => kiroMajor,
|
|
4081
4154
|
mcpWiring: () => mcpWiring
|
|
4082
4155
|
});
|
|
4083
4156
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
4084
|
-
import
|
|
4085
|
-
import
|
|
4157
|
+
import fs19 from "node:fs";
|
|
4158
|
+
import os4 from "node:os";
|
|
4159
|
+
import path19 from "node:path";
|
|
4086
4160
|
function which(bin) {
|
|
4087
|
-
if (bin.includes("/")) return
|
|
4088
|
-
for (const dir of (process.env.PATH ?? "").split(
|
|
4161
|
+
if (bin.includes("/")) return fs19.existsSync(bin) ? bin : void 0;
|
|
4162
|
+
for (const dir of (process.env.PATH ?? "").split(path19.delimiter)) {
|
|
4089
4163
|
if (dir === "") continue;
|
|
4090
|
-
const candidate =
|
|
4164
|
+
const candidate = path19.join(dir, bin);
|
|
4091
4165
|
try {
|
|
4092
|
-
|
|
4166
|
+
fs19.accessSync(candidate, fs19.constants.X_OK);
|
|
4093
4167
|
return candidate;
|
|
4094
4168
|
} catch {
|
|
4095
4169
|
}
|
|
@@ -4113,11 +4187,28 @@ function mcpWiring(agentJson, resolve) {
|
|
|
4113
4187
|
return { ok: false, detail: `${command || "(no command)"} not found - widgets are unavailable` };
|
|
4114
4188
|
}
|
|
4115
4189
|
const script = args.find((a) => a.endsWith(".js"));
|
|
4116
|
-
if (script && !
|
|
4190
|
+
if (script && !fs19.existsSync(script)) {
|
|
4117
4191
|
return { ok: false, detail: `${script} is gone - delete the agent file and restart to rewrite it` };
|
|
4118
4192
|
}
|
|
4119
4193
|
return { ok: true, detail: script ?? `${command} ${args.join(" ")}` };
|
|
4120
4194
|
}
|
|
4195
|
+
function agentFormat(agentJson) {
|
|
4196
|
+
let agent;
|
|
4197
|
+
try {
|
|
4198
|
+
agent = JSON.parse(agentJson);
|
|
4199
|
+
} catch {
|
|
4200
|
+
return { ok: false, detail: "the agent file is not valid JSON" };
|
|
4201
|
+
}
|
|
4202
|
+
const v2Fields = ["allowedTools", "toolsSettings"].filter((f) => f in agent);
|
|
4203
|
+
return v2Fields.length === 0 ? { ok: true, detail: "in the kiro V3 format" } : {
|
|
4204
|
+
ok: false,
|
|
4205
|
+
detail: `has ${v2Fields.join(" and ")}, so kiro V3 skips it - delete the file and restart to rewrite it`
|
|
4206
|
+
};
|
|
4207
|
+
}
|
|
4208
|
+
function kiroMajor(versionOutput) {
|
|
4209
|
+
const m = /(\d+)\.\d+\.\d+/.exec(versionOutput);
|
|
4210
|
+
return m ? Number(m[1]) : void 0;
|
|
4211
|
+
}
|
|
4121
4212
|
function checks() {
|
|
4122
4213
|
const out = [];
|
|
4123
4214
|
out.push({
|
|
@@ -4133,7 +4224,10 @@ function checks() {
|
|
|
4133
4224
|
} catch {
|
|
4134
4225
|
version = "(version unavailable)";
|
|
4135
4226
|
}
|
|
4136
|
-
|
|
4227
|
+
const major = kiroMajor(version);
|
|
4228
|
+
out.push(
|
|
4229
|
+
major === void 0 || major >= 3 ? { ok: true, name: "kiro-cli", detail: `${version} at ${kiro}` } : { ok: false, name: "kiro-cli", detail: `${version} at ${kiro} - Casper needs kiro-cli 3.0 or later` }
|
|
4230
|
+
);
|
|
4137
4231
|
} else {
|
|
4138
4232
|
out.push({
|
|
4139
4233
|
ok: false,
|
|
@@ -4145,7 +4239,7 @@ function checks() {
|
|
|
4145
4239
|
const settings = readSettings(config.configFile);
|
|
4146
4240
|
const hasToken = typeof settings.token === "string" && settings.token !== "";
|
|
4147
4241
|
out.push(
|
|
4148
|
-
|
|
4242
|
+
fs19.existsSync(config.configFile) ? {
|
|
4149
4243
|
ok: hasToken,
|
|
4150
4244
|
name: "settings",
|
|
4151
4245
|
detail: hasToken ? `${config.configFile} (token set)` : `${config.configFile} exists but has no token - auth is DISABLED`
|
|
@@ -4155,8 +4249,8 @@ function checks() {
|
|
|
4155
4249
|
detail: `${config.configFile} not found; a token is generated on first run`
|
|
4156
4250
|
}
|
|
4157
4251
|
);
|
|
4158
|
-
if (
|
|
4159
|
-
const mode =
|
|
4252
|
+
if (fs19.existsSync(config.configFile)) {
|
|
4253
|
+
const mode = fs19.statSync(config.configFile).mode & 511;
|
|
4160
4254
|
out.push({
|
|
4161
4255
|
ok: mode === 384,
|
|
4162
4256
|
name: "settings mode",
|
|
@@ -4164,10 +4258,10 @@ function checks() {
|
|
|
4164
4258
|
});
|
|
4165
4259
|
}
|
|
4166
4260
|
try {
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
const db2 =
|
|
4170
|
-
const size =
|
|
4261
|
+
fs19.mkdirSync(config.casperDataDir, { recursive: true });
|
|
4262
|
+
fs19.accessSync(config.casperDataDir, fs19.constants.W_OK);
|
|
4263
|
+
const db2 = path19.join(config.casperDataDir, "casper.db");
|
|
4264
|
+
const size = fs19.existsSync(db2) ? `, casper.db ${(fs19.statSync(db2).size / 1024).toFixed(0)} KB` : "";
|
|
4171
4265
|
out.push({ ok: true, name: "data dir", detail: `${config.casperDataDir} writable${size}` });
|
|
4172
4266
|
} catch (err) {
|
|
4173
4267
|
out.push({
|
|
@@ -4178,22 +4272,25 @@ function checks() {
|
|
|
4178
4272
|
});
|
|
4179
4273
|
}
|
|
4180
4274
|
out.push(
|
|
4181
|
-
|
|
4275
|
+
fs19.existsSync(config.webDist) ? { ok: true, name: "web app", detail: config.webDist } : {
|
|
4182
4276
|
ok: false,
|
|
4183
4277
|
fatal: true,
|
|
4184
4278
|
name: "web app",
|
|
4185
4279
|
detail: `${config.webDist} not found - the package is incomplete or CASPER_WEB_DIST is wrong`
|
|
4186
4280
|
}
|
|
4187
4281
|
);
|
|
4188
|
-
const agent =
|
|
4189
|
-
const hasAgent =
|
|
4282
|
+
const agent = path19.join(os4.homedir(), ".kiro", "agents", "casper.json");
|
|
4283
|
+
const hasAgent = fs19.existsSync(agent);
|
|
4190
4284
|
out.push({
|
|
4191
4285
|
ok: hasAgent,
|
|
4192
4286
|
name: "casper agent",
|
|
4193
4287
|
detail: hasAgent ? agent : `${agent} missing - it is installed on first run`
|
|
4194
4288
|
});
|
|
4195
4289
|
if (hasAgent) {
|
|
4196
|
-
const
|
|
4290
|
+
const json = fs19.readFileSync(agent, "utf8");
|
|
4291
|
+
const format = agentFormat(json);
|
|
4292
|
+
out.push({ ok: format.ok, name: "agent format", detail: format.detail });
|
|
4293
|
+
const wiring = mcpWiring(json, which);
|
|
4197
4294
|
out.push({ ok: wiring.ok, name: "casper mcp", detail: wiring.detail });
|
|
4198
4295
|
}
|
|
4199
4296
|
return out;
|
|
@@ -4657,14 +4754,14 @@ var init_server2 = __esm({
|
|
|
4657
4754
|
"server/src/mcp/server.ts"() {
|
|
4658
4755
|
"use strict";
|
|
4659
4756
|
init_protocol();
|
|
4660
|
-
VERSION = true ? "0.
|
|
4757
|
+
VERSION = true ? "0.16.0" : "dev";
|
|
4661
4758
|
}
|
|
4662
4759
|
});
|
|
4663
4760
|
|
|
4664
4761
|
// server/src/cli/program.ts
|
|
4665
|
-
import
|
|
4666
|
-
import
|
|
4667
|
-
import
|
|
4762
|
+
import fs20 from "node:fs";
|
|
4763
|
+
import os5 from "node:os";
|
|
4764
|
+
import path20 from "node:path";
|
|
4668
4765
|
|
|
4669
4766
|
// server/node_modules/commander/lib/error.js
|
|
4670
4767
|
var CommanderError = class extends Error {
|
|
@@ -5255,8 +5352,8 @@ var Help = class {
|
|
|
5255
5352
|
* @param {string} str
|
|
5256
5353
|
* @returns {number}
|
|
5257
5354
|
*/
|
|
5258
|
-
displayWidth(
|
|
5259
|
-
return stripVTControlCharacters(
|
|
5355
|
+
displayWidth(str3) {
|
|
5356
|
+
return stripVTControlCharacters(str3).length;
|
|
5260
5357
|
}
|
|
5261
5358
|
/**
|
|
5262
5359
|
* Style the title for displaying in the help. Called with 'Usage:', 'Options:', etc.
|
|
@@ -5264,11 +5361,11 @@ var Help = class {
|
|
|
5264
5361
|
* @param {string} str
|
|
5265
5362
|
* @returns {string}
|
|
5266
5363
|
*/
|
|
5267
|
-
styleTitle(
|
|
5268
|
-
return
|
|
5364
|
+
styleTitle(str3) {
|
|
5365
|
+
return str3;
|
|
5269
5366
|
}
|
|
5270
|
-
styleUsage(
|
|
5271
|
-
return
|
|
5367
|
+
styleUsage(str3) {
|
|
5368
|
+
return str3.split(" ").map((word) => {
|
|
5272
5369
|
if (word === "[options]") return this.styleOptionText(word);
|
|
5273
5370
|
if (word === "[command]") return this.styleSubcommandText(word);
|
|
5274
5371
|
if (word[0] === "[" || word[0] === "<")
|
|
@@ -5276,46 +5373,46 @@ var Help = class {
|
|
|
5276
5373
|
return this.styleCommandText(word);
|
|
5277
5374
|
}).join(" ");
|
|
5278
5375
|
}
|
|
5279
|
-
styleCommandDescription(
|
|
5280
|
-
return this.styleDescriptionText(
|
|
5376
|
+
styleCommandDescription(str3) {
|
|
5377
|
+
return this.styleDescriptionText(str3);
|
|
5281
5378
|
}
|
|
5282
|
-
styleOptionDescription(
|
|
5283
|
-
return this.styleDescriptionText(
|
|
5379
|
+
styleOptionDescription(str3) {
|
|
5380
|
+
return this.styleDescriptionText(str3);
|
|
5284
5381
|
}
|
|
5285
|
-
styleSubcommandDescription(
|
|
5286
|
-
return this.styleDescriptionText(
|
|
5382
|
+
styleSubcommandDescription(str3) {
|
|
5383
|
+
return this.styleDescriptionText(str3);
|
|
5287
5384
|
}
|
|
5288
|
-
styleArgumentDescription(
|
|
5289
|
-
return this.styleDescriptionText(
|
|
5385
|
+
styleArgumentDescription(str3) {
|
|
5386
|
+
return this.styleDescriptionText(str3);
|
|
5290
5387
|
}
|
|
5291
|
-
styleDescriptionText(
|
|
5292
|
-
return
|
|
5388
|
+
styleDescriptionText(str3) {
|
|
5389
|
+
return str3;
|
|
5293
5390
|
}
|
|
5294
|
-
styleOptionTerm(
|
|
5295
|
-
return this.styleOptionText(
|
|
5391
|
+
styleOptionTerm(str3) {
|
|
5392
|
+
return this.styleOptionText(str3);
|
|
5296
5393
|
}
|
|
5297
|
-
styleSubcommandTerm(
|
|
5298
|
-
return
|
|
5394
|
+
styleSubcommandTerm(str3) {
|
|
5395
|
+
return str3.split(" ").map((word) => {
|
|
5299
5396
|
if (word === "[options]") return this.styleOptionText(word);
|
|
5300
5397
|
if (word[0] === "[" || word[0] === "<")
|
|
5301
5398
|
return this.styleArgumentText(word);
|
|
5302
5399
|
return this.styleSubcommandText(word);
|
|
5303
5400
|
}).join(" ");
|
|
5304
5401
|
}
|
|
5305
|
-
styleArgumentTerm(
|
|
5306
|
-
return this.styleArgumentText(
|
|
5402
|
+
styleArgumentTerm(str3) {
|
|
5403
|
+
return this.styleArgumentText(str3);
|
|
5307
5404
|
}
|
|
5308
|
-
styleOptionText(
|
|
5309
|
-
return
|
|
5405
|
+
styleOptionText(str3) {
|
|
5406
|
+
return str3;
|
|
5310
5407
|
}
|
|
5311
|
-
styleArgumentText(
|
|
5312
|
-
return
|
|
5408
|
+
styleArgumentText(str3) {
|
|
5409
|
+
return str3;
|
|
5313
5410
|
}
|
|
5314
|
-
styleSubcommandText(
|
|
5315
|
-
return
|
|
5411
|
+
styleSubcommandText(str3) {
|
|
5412
|
+
return str3;
|
|
5316
5413
|
}
|
|
5317
|
-
styleCommandText(
|
|
5318
|
-
return
|
|
5414
|
+
styleCommandText(str3) {
|
|
5415
|
+
return str3;
|
|
5319
5416
|
}
|
|
5320
5417
|
/**
|
|
5321
5418
|
* Calculate the pad width from the maximum term length.
|
|
@@ -5338,8 +5435,8 @@ var Help = class {
|
|
|
5338
5435
|
* @param {string} str
|
|
5339
5436
|
* @returns {boolean}
|
|
5340
5437
|
*/
|
|
5341
|
-
preformatted(
|
|
5342
|
-
return /\n[^\S\r\n]/.test(
|
|
5438
|
+
preformatted(str3) {
|
|
5439
|
+
return /\n[^\S\r\n]/.test(str3);
|
|
5343
5440
|
}
|
|
5344
5441
|
/**
|
|
5345
5442
|
* Format the "item", which consists of a term and description. Pad the term and wrap the description, indenting the following lines.
|
|
@@ -5385,9 +5482,9 @@ ${itemIndentStr}`);
|
|
|
5385
5482
|
* @param {number} width
|
|
5386
5483
|
* @returns {string}
|
|
5387
5484
|
*/
|
|
5388
|
-
boxWrap(
|
|
5389
|
-
if (width < this.minWidthToWrap) return
|
|
5390
|
-
const rawLines =
|
|
5485
|
+
boxWrap(str3, width) {
|
|
5486
|
+
if (width < this.minWidthToWrap) return str3;
|
|
5487
|
+
const rawLines = str3.split(/\r\n|\n/);
|
|
5391
5488
|
const chunkPattern = /[\s]*[^\s]+/g;
|
|
5392
5489
|
const wrappedLines = [];
|
|
5393
5490
|
rawLines.forEach((line) => {
|
|
@@ -5677,9 +5774,9 @@ var DualOptions = class {
|
|
|
5677
5774
|
return option.negate === (negativeValue === value);
|
|
5678
5775
|
}
|
|
5679
5776
|
};
|
|
5680
|
-
function camelcase(
|
|
5681
|
-
return
|
|
5682
|
-
return
|
|
5777
|
+
function camelcase(str3) {
|
|
5778
|
+
return str3.split("-").reduce((str4, word) => {
|
|
5779
|
+
return str4 + word[0].toUpperCase() + word.slice(1);
|
|
5683
5780
|
});
|
|
5684
5781
|
}
|
|
5685
5782
|
function splitOptionFlags(flags) {
|
|
@@ -5839,14 +5936,14 @@ var Command = class _Command extends EventEmitter {
|
|
|
5839
5936
|
this._showSuggestionAfterError = true;
|
|
5840
5937
|
this._savedState = null;
|
|
5841
5938
|
this._outputConfiguration = {
|
|
5842
|
-
writeOut: (
|
|
5843
|
-
writeErr: (
|
|
5844
|
-
outputError: (
|
|
5939
|
+
writeOut: (str3) => process2.stdout.write(str3),
|
|
5940
|
+
writeErr: (str3) => process2.stderr.write(str3),
|
|
5941
|
+
outputError: (str3, write) => write(str3),
|
|
5845
5942
|
getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : void 0,
|
|
5846
5943
|
getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : void 0,
|
|
5847
5944
|
getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()),
|
|
5848
5945
|
getErrHasColors: () => useColor() ?? (process2.stderr.isTTY && process2.stderr.hasColors?.()),
|
|
5849
|
-
stripColor: (
|
|
5946
|
+
stripColor: (str3) => stripVTControlCharacters2(str3)
|
|
5850
5947
|
};
|
|
5851
5948
|
this._hidden = false;
|
|
5852
5949
|
this._helpOption = void 0;
|
|
@@ -7574,18 +7671,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7574
7671
|
* @param {string} [description]
|
|
7575
7672
|
* @return {(this | string | undefined)} `this` command for chaining, or version string if no arguments
|
|
7576
7673
|
*/
|
|
7577
|
-
version(
|
|
7578
|
-
if (
|
|
7579
|
-
this._version =
|
|
7674
|
+
version(str3, flags, description) {
|
|
7675
|
+
if (str3 === void 0) return this._version;
|
|
7676
|
+
this._version = str3;
|
|
7580
7677
|
flags = flags || "-V, --version";
|
|
7581
7678
|
description = description || "output the version number";
|
|
7582
7679
|
const versionOption = this.createOption(flags, description);
|
|
7583
7680
|
this._versionOptionName = versionOption.attributeName();
|
|
7584
7681
|
this._registerOption(versionOption);
|
|
7585
7682
|
this.on("option:" + versionOption.name(), () => {
|
|
7586
|
-
this._outputConfiguration.writeOut(`${
|
|
7683
|
+
this._outputConfiguration.writeOut(`${str3}
|
|
7587
7684
|
`);
|
|
7588
|
-
this._exit(0, "commander.version",
|
|
7685
|
+
this._exit(0, "commander.version", str3);
|
|
7589
7686
|
});
|
|
7590
7687
|
return this;
|
|
7591
7688
|
}
|
|
@@ -7596,10 +7693,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7596
7693
|
* @param {object} [argsDescription]
|
|
7597
7694
|
* @return {(string|Command)}
|
|
7598
7695
|
*/
|
|
7599
|
-
description(
|
|
7600
|
-
if (
|
|
7696
|
+
description(str3, argsDescription) {
|
|
7697
|
+
if (str3 === void 0 && argsDescription === void 0)
|
|
7601
7698
|
return this._description;
|
|
7602
|
-
this._description =
|
|
7699
|
+
this._description = str3;
|
|
7603
7700
|
if (argsDescription) {
|
|
7604
7701
|
this._argsDescription = argsDescription;
|
|
7605
7702
|
}
|
|
@@ -7611,9 +7708,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7611
7708
|
* @param {string} [str]
|
|
7612
7709
|
* @return {(string|Command)}
|
|
7613
7710
|
*/
|
|
7614
|
-
summary(
|
|
7615
|
-
if (
|
|
7616
|
-
this._summary =
|
|
7711
|
+
summary(str3) {
|
|
7712
|
+
if (str3 === void 0) return this._summary;
|
|
7713
|
+
this._summary = str3;
|
|
7617
7714
|
return this;
|
|
7618
7715
|
}
|
|
7619
7716
|
/**
|
|
@@ -7661,8 +7758,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7661
7758
|
* @param {string} [str]
|
|
7662
7759
|
* @return {(string|Command)}
|
|
7663
7760
|
*/
|
|
7664
|
-
usage(
|
|
7665
|
-
if (
|
|
7761
|
+
usage(str3) {
|
|
7762
|
+
if (str3 === void 0) {
|
|
7666
7763
|
if (this._usage) return this._usage;
|
|
7667
7764
|
const args = this.registeredArguments.map((arg) => {
|
|
7668
7765
|
return humanReadableArgName(arg);
|
|
@@ -7673,7 +7770,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7673
7770
|
this.registeredArguments.length ? args : []
|
|
7674
7771
|
).join(" ");
|
|
7675
7772
|
}
|
|
7676
|
-
this._usage =
|
|
7773
|
+
this._usage = str3;
|
|
7677
7774
|
return this;
|
|
7678
7775
|
}
|
|
7679
7776
|
/**
|
|
@@ -7682,9 +7779,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7682
7779
|
* @param {string} [str]
|
|
7683
7780
|
* @return {(string|Command)}
|
|
7684
7781
|
*/
|
|
7685
|
-
name(
|
|
7686
|
-
if (
|
|
7687
|
-
this._name =
|
|
7782
|
+
name(str3) {
|
|
7783
|
+
if (str3 === void 0) return this._name;
|
|
7784
|
+
this._name = str3;
|
|
7688
7785
|
return this;
|
|
7689
7786
|
}
|
|
7690
7787
|
/**
|
|
@@ -7777,9 +7874,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7777
7874
|
* @param {string} [path]
|
|
7778
7875
|
* @return {(string|null|Command)}
|
|
7779
7876
|
*/
|
|
7780
|
-
executableDir(
|
|
7781
|
-
if (
|
|
7782
|
-
this._executableDir =
|
|
7877
|
+
executableDir(path21) {
|
|
7878
|
+
if (path21 === void 0) return this._executableDir;
|
|
7879
|
+
this._executableDir = path21;
|
|
7783
7880
|
return this;
|
|
7784
7881
|
}
|
|
7785
7882
|
/**
|
|
@@ -7818,17 +7915,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7818
7915
|
let hasColors;
|
|
7819
7916
|
let helpWidth;
|
|
7820
7917
|
if (error) {
|
|
7821
|
-
baseWrite = (
|
|
7918
|
+
baseWrite = (str3) => this._outputConfiguration.writeErr(str3);
|
|
7822
7919
|
hasColors = this._outputConfiguration.getErrHasColors();
|
|
7823
7920
|
helpWidth = this._outputConfiguration.getErrHelpWidth();
|
|
7824
7921
|
} else {
|
|
7825
|
-
baseWrite = (
|
|
7922
|
+
baseWrite = (str3) => this._outputConfiguration.writeOut(str3);
|
|
7826
7923
|
hasColors = this._outputConfiguration.getOutHasColors();
|
|
7827
7924
|
helpWidth = this._outputConfiguration.getOutHelpWidth();
|
|
7828
7925
|
}
|
|
7829
|
-
const write = (
|
|
7830
|
-
if (!hasColors)
|
|
7831
|
-
return baseWrite(
|
|
7926
|
+
const write = (str3) => {
|
|
7927
|
+
if (!hasColors) str3 = this._outputConfiguration.stripColor(str3);
|
|
7928
|
+
return baseWrite(str3);
|
|
7832
7929
|
};
|
|
7833
7930
|
return { error, write, hasColors, helpWidth };
|
|
7834
7931
|
}
|
|
@@ -8037,7 +8134,7 @@ var program = new Command();
|
|
|
8037
8134
|
// server/src/cli/program.ts
|
|
8038
8135
|
init_paths();
|
|
8039
8136
|
init_settings();
|
|
8040
|
-
var VERSION2 = true ? "0.
|
|
8137
|
+
var VERSION2 = true ? "0.16.0" : "dev";
|
|
8041
8138
|
async function bootstrap() {
|
|
8042
8139
|
const file = configFilePath();
|
|
8043
8140
|
const settings = readSettings(file);
|
|
@@ -8050,7 +8147,7 @@ async function bootstrap() {
|
|
|
8050
8147
|
`);
|
|
8051
8148
|
}
|
|
8052
8149
|
const { installAgentFile: installAgentFile2 } = await Promise.resolve().then(() => (init_agentFile(), agentFile_exports));
|
|
8053
|
-
const agent = installAgentFile2(
|
|
8150
|
+
const agent = installAgentFile2(os5.homedir(), dataDirPath());
|
|
8054
8151
|
if (agent.action === "installed" || agent.action === "updated") {
|
|
8055
8152
|
process.stdout.write(`casper agent ${agent.action}: ${agent.target}
|
|
8056
8153
|
`);
|
|
@@ -8083,8 +8180,8 @@ async function resetToken(value) {
|
|
|
8083
8180
|
updateSettings(file, { token });
|
|
8084
8181
|
process.stdout.write(`wrote a new token to ${file}
|
|
8085
8182
|
`);
|
|
8086
|
-
const dbFile =
|
|
8087
|
-
if (
|
|
8183
|
+
const dbFile = path20.join(dataDirPath(), "casper.db");
|
|
8184
|
+
if (fs20.existsSync(dbFile)) {
|
|
8088
8185
|
const { LoginStore: LoginStore2 } = await Promise.resolve().then(() => (init_logins(), logins_exports));
|
|
8089
8186
|
new LoginStore2().revokeAll();
|
|
8090
8187
|
process.stdout.write("revoked all device sessions\n");
|