@joeyshi12/casper 0.15.6 → 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 +836 -723
- 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,287 +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
|
-
|
|
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;
|
|
1433
1477
|
}
|
|
1434
|
-
return
|
|
1478
|
+
return false;
|
|
1435
1479
|
}
|
|
1436
|
-
/**
|
|
1437
|
-
*
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
for (const
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
}
|
|
1447
|
-
this.byChild.set(info.sessionId, {
|
|
1448
|
-
sessionId: info.sessionId,
|
|
1449
|
-
stageName: info.sessionName,
|
|
1450
|
-
toolCallId,
|
|
1451
|
-
status: info.status.type === "terminated" ? "completed" : "working",
|
|
1452
|
-
activity: info.status.message,
|
|
1453
|
-
createdAt: existing?.createdAt ?? nowIso,
|
|
1454
|
-
updatedAt: nowIso
|
|
1455
|
-
});
|
|
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()) {
|
|
1485
|
+
if (s.status !== "working") continue;
|
|
1486
|
+
s.status = "failed";
|
|
1487
|
+
s.activity = "Stopped";
|
|
1488
|
+
s.updatedAt = this.now();
|
|
1489
|
+
changed = true;
|
|
1456
1490
|
}
|
|
1457
|
-
return
|
|
1458
|
-
}
|
|
1459
|
-
/** Started stages plus a synthetic 'pending' row for each declared stage that
|
|
1460
|
-
* hasn't started, so a stage waiting on a dependency still shows up. */
|
|
1461
|
-
listForCall(toolCallId) {
|
|
1462
|
-
const call = this.pendingCalls.find((c) => c.toolCallId === toolCallId);
|
|
1463
|
-
const started = [...this.byChild.values()].filter((s) => s.toolCallId === toolCallId);
|
|
1464
|
-
if (!call) return started.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
1465
|
-
const startedNames = new Set(started.map((s) => s.stageName));
|
|
1466
|
-
const pending = call.stages.filter((s) => !startedNames.has(s.name)).map((s) => ({
|
|
1467
|
-
sessionId: `pending:${toolCallId}:${s.name}`,
|
|
1468
|
-
stageName: s.name,
|
|
1469
|
-
toolCallId,
|
|
1470
|
-
status: "pending",
|
|
1471
|
-
activity: s.depends_on?.length ? `Waits for ${s.depends_on.join(" and ")}` : void 0,
|
|
1472
|
-
createdAt: "",
|
|
1473
|
-
updatedAt: ""
|
|
1474
|
-
}));
|
|
1475
|
-
return [...started.sort((a, b) => a.createdAt.localeCompare(b.createdAt)), ...pending];
|
|
1491
|
+
return changed;
|
|
1476
1492
|
}
|
|
1493
|
+
/** Copies, so a recorded event keeps the state it was recorded with. */
|
|
1477
1494
|
list() {
|
|
1478
|
-
return [...this.
|
|
1495
|
+
return [...this.byId.values()].map((s) => ({ ...s })).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
1479
1496
|
}
|
|
1480
|
-
get(
|
|
1481
|
-
|
|
1497
|
+
get(subagentId) {
|
|
1498
|
+
const s = this.byId.get(subagentId);
|
|
1499
|
+
return s && { ...s };
|
|
1482
1500
|
}
|
|
1483
1501
|
};
|
|
1484
1502
|
}
|
|
1485
1503
|
});
|
|
1486
1504
|
|
|
1487
|
-
// server/src/session/
|
|
1488
|
-
function showSummaryAsAnswer(transcript) {
|
|
1489
|
-
const out = [];
|
|
1490
|
-
for (const item of transcript) {
|
|
1491
|
-
if (item.type === "message" && item.message.role === "assistant" && item.message.text.trim() === INTERRUPTED) {
|
|
1492
|
-
continue;
|
|
1493
|
-
}
|
|
1494
|
-
if (item.type === "tool_call" && item.tool.name === "summary") {
|
|
1495
|
-
const input = item.tool.input;
|
|
1496
|
-
const result = typeof input?.taskResult === "string" ? input.taskResult.trim() : "";
|
|
1497
|
-
if (result) out.push({ type: "message", message: { id: item.tool.id, role: "assistant", text: result } });
|
|
1498
|
-
continue;
|
|
1499
|
-
}
|
|
1500
|
-
out.push(item);
|
|
1501
|
-
}
|
|
1502
|
-
return out;
|
|
1503
|
-
}
|
|
1504
|
-
var INTERRUPTED;
|
|
1505
|
-
var init_subagentResult = __esm({
|
|
1506
|
-
"server/src/session/subagentResult.ts"() {
|
|
1507
|
-
"use strict";
|
|
1508
|
-
INTERRUPTED = "Tool uses were interrupted, waiting for the next user prompt";
|
|
1509
|
-
}
|
|
1510
|
-
});
|
|
1511
|
-
|
|
1512
|
-
// server/src/session/subagentFallbackMatch.ts
|
|
1513
|
-
function isStageInput(v) {
|
|
1514
|
-
return typeof v === "object" && v !== null && typeof v.name === "string";
|
|
1515
|
-
}
|
|
1516
|
-
function subagentCallInput(tool) {
|
|
1517
|
-
if (tool.name !== "subagent") return null;
|
|
1518
|
-
const input = tool.input;
|
|
1519
|
-
if (!input || !Array.isArray(input.stages)) return null;
|
|
1520
|
-
const stages = input.stages.filter(isStageInput);
|
|
1521
|
-
return { task: typeof input.task === "string" ? input.task : void 0, stages };
|
|
1522
|
-
}
|
|
1523
|
-
function expectedTitle(call, stage) {
|
|
1524
|
-
const task = call.task ?? "";
|
|
1525
|
-
const expanded = stage.prompt_template ? stage.prompt_template.replace("{task}", task) : task;
|
|
1526
|
-
return expanded.slice(0, TITLE_MAX_LENGTH);
|
|
1527
|
-
}
|
|
1528
|
-
function subagentCallsIn(transcript) {
|
|
1529
|
-
const calls = [];
|
|
1530
|
-
transcript.forEach((item, itemIndex) => {
|
|
1531
|
-
if (item.type !== "tool_call") return;
|
|
1532
|
-
const input = subagentCallInput(item.tool);
|
|
1533
|
-
if (!input) return;
|
|
1534
|
-
calls.push({ toolCallId: item.tool.id, itemIndex, input });
|
|
1535
|
-
});
|
|
1536
|
-
return calls;
|
|
1537
|
-
}
|
|
1538
|
-
function matchSubagentsFallback(calls, children) {
|
|
1539
|
-
const sortedCalls = [...calls].sort((a, b) => a.itemIndex - b.itemIndex);
|
|
1540
|
-
const unclaimed = [...children].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
1541
|
-
const matches = [];
|
|
1542
|
-
for (const call of sortedCalls) {
|
|
1543
|
-
for (const stage of call.input.stages) {
|
|
1544
|
-
const want = expectedTitle(call.input, stage);
|
|
1545
|
-
if (!want) continue;
|
|
1546
|
-
const i = unclaimed.findIndex((c) => want.startsWith(c.title) || c.title.startsWith(want));
|
|
1547
|
-
if (i < 0) continue;
|
|
1548
|
-
const child = unclaimed.splice(i, 1)[0];
|
|
1549
|
-
matches.push({ sessionId: child.sessionId, toolCallId: call.toolCallId, stageName: stage.name });
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
return matches;
|
|
1553
|
-
}
|
|
1554
|
-
var TITLE_MAX_LENGTH;
|
|
1555
|
-
var init_subagentFallbackMatch = __esm({
|
|
1556
|
-
"server/src/session/subagentFallbackMatch.ts"() {
|
|
1557
|
-
"use strict";
|
|
1558
|
-
TITLE_MAX_LENGTH = 150;
|
|
1559
|
-
}
|
|
1560
|
-
});
|
|
1561
|
-
|
|
1562
|
-
// server/src/session/kiroFiles.ts
|
|
1505
|
+
// server/src/session/kiroV3Files.ts
|
|
1563
1506
|
import fs9 from "node:fs/promises";
|
|
1564
1507
|
import path10 from "node:path";
|
|
1565
|
-
function
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
if (b.kind !== "toolUse" || !isRecord(b.data)) return null;
|
|
1570
|
-
const { toolUseId, name, input } = b.data;
|
|
1571
|
-
if (typeof toolUseId !== "string") return null;
|
|
1572
|
-
return { toolUseId, name: typeof name === "string" ? name : void 0, input };
|
|
1573
|
-
}
|
|
1574
|
-
function toolResultData(b) {
|
|
1575
|
-
if (b.kind !== "toolResult" || !isRecord(b.data)) return null;
|
|
1576
|
-
const { toolUseId, status, content } = b.data;
|
|
1577
|
-
if (typeof toolUseId !== "string") return null;
|
|
1578
|
-
return { toolUseId, status: typeof status === "string" ? status : void 0, content };
|
|
1579
|
-
}
|
|
1580
|
-
function contentBlocks(content) {
|
|
1581
|
-
return Array.isArray(content) ? content.filter(isContentBlock) : [];
|
|
1582
|
-
}
|
|
1583
|
-
function blockText(c) {
|
|
1584
|
-
if (typeof c.data === "string") return c.data;
|
|
1585
|
-
if (isRecord(c.data) && typeof c.data.text === "string") return c.data.text;
|
|
1586
|
-
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();
|
|
1587
1512
|
}
|
|
1588
|
-
function
|
|
1589
|
-
|
|
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
|
+
}
|
|
1590
1521
|
}
|
|
1591
|
-
function
|
|
1592
|
-
const
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
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;
|
|
1605
1537
|
}
|
|
1606
|
-
async function
|
|
1607
|
-
if (!isValidSessionId(sessionId)) return;
|
|
1608
|
-
const
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
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);
|
|
1616
1552
|
}
|
|
1617
|
-
|
|
1618
|
-
if (!
|
|
1553
|
+
function contextUsageOf(line) {
|
|
1554
|
+
if (!line.includes('"contextUsage"')) return void 0;
|
|
1619
1555
|
try {
|
|
1620
|
-
const
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
);
|
|
1624
|
-
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;
|
|
1625
1559
|
} catch {
|
|
1626
|
-
return
|
|
1560
|
+
return void 0;
|
|
1627
1561
|
}
|
|
1628
1562
|
}
|
|
1629
|
-
async function
|
|
1563
|
+
async function lastContextUsage(file) {
|
|
1564
|
+
let handle2;
|
|
1630
1565
|
try {
|
|
1631
|
-
|
|
1632
|
-
const mtime = st.mtime.toISOString();
|
|
1633
|
-
return mtime > child.updatedAt ? { ...child, updatedAt: mtime } : child;
|
|
1566
|
+
handle2 = await fs9.open(file, "r");
|
|
1634
1567
|
} catch {
|
|
1635
|
-
return
|
|
1568
|
+
return void 0;
|
|
1636
1569
|
}
|
|
1637
|
-
}
|
|
1638
|
-
async function readChildSession(childSessionId, parentSessionId) {
|
|
1639
|
-
if (!isValidSessionId(childSessionId)) return null;
|
|
1640
1570
|
try {
|
|
1641
|
-
const
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
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();
|
|
1646
1589
|
}
|
|
1647
1590
|
}
|
|
1648
|
-
async function
|
|
1649
|
-
|
|
1650
|
-
let names;
|
|
1591
|
+
async function readV3Session(dir) {
|
|
1592
|
+
let j;
|
|
1651
1593
|
try {
|
|
1652
|
-
|
|
1594
|
+
j = JSON.parse(await fs9.readFile(path10.join(dir, "session.json"), "utf8"));
|
|
1653
1595
|
} catch {
|
|
1654
|
-
return
|
|
1596
|
+
return null;
|
|
1655
1597
|
}
|
|
1656
|
-
const
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
);
|
|
1669
|
-
return out;
|
|
1670
|
-
}
|
|
1671
|
-
async function promptCount(sessionId) {
|
|
1672
|
-
const entries = await readJsonlEntries(sessionId);
|
|
1673
|
-
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
|
+
};
|
|
1674
1610
|
}
|
|
1675
|
-
async function
|
|
1676
|
-
if (!isValidSessionId(sessionId)) return [];
|
|
1611
|
+
async function readLines(file, filter) {
|
|
1677
1612
|
let raw;
|
|
1678
1613
|
try {
|
|
1679
|
-
raw = await fs9.readFile(
|
|
1614
|
+
raw = await fs9.readFile(file, "utf8");
|
|
1680
1615
|
} catch {
|
|
1681
1616
|
return [];
|
|
1682
1617
|
}
|
|
1683
|
-
const
|
|
1618
|
+
const out = [];
|
|
1684
1619
|
for (const line of raw.split("\n")) {
|
|
1685
|
-
|
|
1686
|
-
if (!trimmed) continue;
|
|
1620
|
+
if (!line.trim() || filter && !line.includes(filter)) continue;
|
|
1687
1621
|
try {
|
|
1688
|
-
|
|
1622
|
+
const parsed = JSON.parse(line);
|
|
1623
|
+
if (isRecord(parsed) && isRecord(parsed.payload) && typeof parsed.id === "string") out.push(parsed);
|
|
1689
1624
|
} catch {
|
|
1690
1625
|
}
|
|
1691
1626
|
}
|
|
1692
|
-
return
|
|
1627
|
+
return out;
|
|
1693
1628
|
}
|
|
1694
|
-
|
|
1695
|
-
if (
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
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
|
+
}
|
|
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
|
+
}
|
|
1701
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;
|
|
1702
1818
|
}
|
|
1703
1819
|
function endingItems(e) {
|
|
1704
1820
|
const prefix = `te${e.id}-`;
|
|
@@ -1710,93 +1826,71 @@ function endingItems(e) {
|
|
|
1710
1826
|
);
|
|
1711
1827
|
return items;
|
|
1712
1828
|
}
|
|
1713
|
-
|
|
1829
|
+
function mergeTranscript(entries, attachments, endings) {
|
|
1714
1830
|
const items = [];
|
|
1715
1831
|
let userOrdinal = 0;
|
|
1716
|
-
const toolsById = /* @__PURE__ */ new Map();
|
|
1717
1832
|
const waiting = [...endings];
|
|
1718
1833
|
let replaced = false;
|
|
1719
1834
|
const unrecorded = (e) => [
|
|
1720
1835
|
{ type: "message", message: { id: `te${e.id}-u`, role: "user", text: e.prompt, timestamp: e.startedAt } },
|
|
1721
1836
|
...endingItems(e)
|
|
1722
1837
|
];
|
|
1723
|
-
for (const entry of
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
);
|
|
1738
|
-
while (waiting.length && waiting[0] !== matched && waiting[0].endedAt < at - STAMP_PAD_MS) {
|
|
1739
|
-
items.push(...unrecorded(waiting.shift()));
|
|
1740
|
-
}
|
|
1741
|
-
if (matched) waiting.splice(waiting.indexOf(matched), 1);
|
|
1742
|
-
}
|
|
1743
|
-
const attached = attachments?.get(userOrdinal);
|
|
1744
|
-
userOrdinal++;
|
|
1745
|
-
if (text2.trim() || attached?.length)
|
|
1746
|
-
pushMsg({ id: `u-${baseId}`, role: "user", text: text2, timestamp: ts, attachments: attached });
|
|
1747
|
-
if (matched) {
|
|
1748
|
-
items.push(...endingItems(matched));
|
|
1749
|
-
replaced = true;
|
|
1750
|
-
}
|
|
1751
|
-
} else if (entry.kind === "AssistantMessage") {
|
|
1752
|
-
if (replaced) continue;
|
|
1753
|
-
const thinking = textOf("thinking");
|
|
1754
|
-
if (thinking.trim())
|
|
1755
|
-
pushMsg({ id: `t-${baseId}`, role: "thinking", text: thinking.trim(), timestamp: ts });
|
|
1756
|
-
const text2 = textOf("text");
|
|
1757
|
-
if (text2.trim())
|
|
1758
|
-
pushMsg({ id: `a-${baseId}`, role: "assistant", text: text2, timestamp: ts });
|
|
1759
|
-
for (const c of content) {
|
|
1760
|
-
const d = toolUseData(c);
|
|
1761
|
-
if (!d) continue;
|
|
1762
|
-
const tool = {
|
|
1763
|
-
id: d.toolUseId,
|
|
1764
|
-
name: d.name,
|
|
1765
|
-
title: d.name ?? d.toolUseId,
|
|
1766
|
-
status: "completed",
|
|
1767
|
-
input: d.input,
|
|
1768
|
-
content: []
|
|
1769
|
-
};
|
|
1770
|
-
toolsById.set(d.toolUseId, tool);
|
|
1771
|
-
items.push({ type: "tool_call", tool });
|
|
1772
|
-
}
|
|
1773
|
-
} else if (entry.kind === "ToolResults") {
|
|
1774
|
-
if (replaced) continue;
|
|
1775
|
-
for (const c of content) {
|
|
1776
|
-
const d = toolResultData(c);
|
|
1777
|
-
if (!d) continue;
|
|
1778
|
-
const tool = toolsById.get(d.toolUseId);
|
|
1779
|
-
if (!tool) continue;
|
|
1780
|
-
tool.status = d.status === "error" ? "failed" : "completed";
|
|
1781
|
-
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()));
|
|
1782
1853
|
}
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
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;
|
|
1787
1864
|
}
|
|
1788
1865
|
}
|
|
1789
1866
|
for (const e of waiting) items.push(...unrecorded(e));
|
|
1790
1867
|
return items;
|
|
1791
1868
|
}
|
|
1792
|
-
|
|
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;
|
|
1793
1888
|
var init_kiroFiles = __esm({
|
|
1794
1889
|
"server/src/session/kiroFiles.ts"() {
|
|
1795
1890
|
"use strict";
|
|
1796
1891
|
init_dist();
|
|
1797
|
-
init_config();
|
|
1798
1892
|
init_paths2();
|
|
1799
|
-
|
|
1893
|
+
init_kiroV3Files();
|
|
1800
1894
|
STAMP_PAD_MS = 2e3;
|
|
1801
1895
|
}
|
|
1802
1896
|
});
|
|
@@ -1918,50 +2012,18 @@ var init_chatStore = __esm({
|
|
|
1918
2012
|
}
|
|
1919
2013
|
});
|
|
1920
2014
|
|
|
1921
|
-
// server/src/session/subagentLinks.ts
|
|
1922
|
-
var SubagentLinkStore;
|
|
1923
|
-
var init_subagentLinks = __esm({
|
|
1924
|
-
"server/src/session/subagentLinks.ts"() {
|
|
1925
|
-
"use strict";
|
|
1926
|
-
init_db();
|
|
1927
|
-
SubagentLinkStore = class {
|
|
1928
|
-
/** Record (or correct) one child's link. Idempotent: a repeat call with the same
|
|
1929
|
-
* values is a no-op, and the row always reflects the latest call to resolve it. */
|
|
1930
|
-
record(childSessionId, parentSessionId, toolCallId, stageName) {
|
|
1931
|
-
db().prepare(
|
|
1932
|
-
`INSERT INTO subagent_links (child_session_id, parent_session_id, tool_call_id, stage_name)
|
|
1933
|
-
VALUES (?, ?, ?, ?)
|
|
1934
|
-
ON CONFLICT(child_session_id) DO UPDATE SET
|
|
1935
|
-
parent_session_id = excluded.parent_session_id,
|
|
1936
|
-
tool_call_id = excluded.tool_call_id,
|
|
1937
|
-
stage_name = excluded.stage_name`
|
|
1938
|
-
).run(childSessionId, parentSessionId, toolCallId, stageName);
|
|
1939
|
-
}
|
|
1940
|
-
/** Every link recorded for one parent session's children, keyed by child session id. */
|
|
1941
|
-
forParent(parentSessionId) {
|
|
1942
|
-
const rows = db().prepare(
|
|
1943
|
-
"SELECT child_session_id, tool_call_id, stage_name FROM subagent_links WHERE parent_session_id = ?"
|
|
1944
|
-
).all(parentSessionId);
|
|
1945
|
-
const out = /* @__PURE__ */ new Map();
|
|
1946
|
-
for (const r of rows) out.set(r.child_session_id, { toolCallId: r.tool_call_id, stageName: r.stage_name });
|
|
1947
|
-
return out;
|
|
1948
|
-
}
|
|
1949
|
-
};
|
|
1950
|
-
}
|
|
1951
|
-
});
|
|
1952
|
-
|
|
1953
2015
|
// server/src/session/SessionManager.ts
|
|
1954
|
-
import
|
|
1955
|
-
import
|
|
2016
|
+
import fs11 from "node:fs";
|
|
2017
|
+
import path12 from "node:path";
|
|
1956
2018
|
function resolveCwd(input) {
|
|
1957
2019
|
const raw = input?.trim();
|
|
1958
|
-
const abs = raw ?
|
|
2020
|
+
const abs = raw ? path12.resolve(config.defaultCwd, raw) : config.defaultCwd;
|
|
1959
2021
|
if (!isWithinRoot(config.fileRoot, abs)) {
|
|
1960
2022
|
throw new Error(`Working directory is outside the allowed root: ${abs}`);
|
|
1961
2023
|
}
|
|
1962
2024
|
let stat;
|
|
1963
2025
|
try {
|
|
1964
|
-
stat =
|
|
2026
|
+
stat = fs11.statSync(abs);
|
|
1965
2027
|
} catch {
|
|
1966
2028
|
stat = void 0;
|
|
1967
2029
|
}
|
|
@@ -1969,37 +2031,44 @@ function resolveCwd(input) {
|
|
|
1969
2031
|
throw new Error(`Working directory path is a file, not a directory: ${abs}`);
|
|
1970
2032
|
}
|
|
1971
2033
|
if (!stat) {
|
|
1972
|
-
|
|
2034
|
+
fs11.mkdirSync(abs, { recursive: true });
|
|
1973
2035
|
}
|
|
1974
2036
|
return abs;
|
|
1975
2037
|
}
|
|
1976
|
-
function
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
case
|
|
1983
|
-
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 } };
|
|
1984
2055
|
default:
|
|
1985
2056
|
return null;
|
|
1986
2057
|
}
|
|
1987
2058
|
}
|
|
1988
|
-
function
|
|
1989
|
-
|
|
1990
|
-
return params?.sessionId;
|
|
2059
|
+
function sessionModel(res) {
|
|
2060
|
+
return res.configOptions?.find((o) => o.id === "model")?.currentValue;
|
|
1991
2061
|
}
|
|
1992
|
-
function
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
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
|
+
};
|
|
2003
2072
|
}
|
|
2004
2073
|
function newerOf(a, b) {
|
|
2005
2074
|
return a && a.localeCompare(b) > 0 ? a : b;
|
|
@@ -2011,7 +2080,7 @@ function firstPromptText(transcript) {
|
|
|
2011
2080
|
function isGhost(s, hasFile) {
|
|
2012
2081
|
return !hasFile && s.hasBeenLive && !s.proc;
|
|
2013
2082
|
}
|
|
2014
|
-
var CANCEL_GRACE_MS, Session, TRANSCRIPT_PAGE_SIZE, SessionManager;
|
|
2083
|
+
var CANCEL_GRACE_MS, Session, TRANSCRIPT_UPDATES, TRANSCRIPT_PAGE_SIZE, SessionManager;
|
|
2015
2084
|
var init_SessionManager = __esm({
|
|
2016
2085
|
"server/src/session/SessionManager.ts"() {
|
|
2017
2086
|
"use strict";
|
|
@@ -2025,11 +2094,8 @@ var init_SessionManager = __esm({
|
|
|
2025
2094
|
init_TurnState();
|
|
2026
2095
|
init_TurnRecorder();
|
|
2027
2096
|
init_SubagentTracker();
|
|
2028
|
-
init_subagentResult();
|
|
2029
|
-
init_subagentFallbackMatch();
|
|
2030
2097
|
init_kiroFiles();
|
|
2031
2098
|
init_chatStore();
|
|
2032
|
-
init_subagentLinks();
|
|
2033
2099
|
CANCEL_GRACE_MS = 1e4;
|
|
2034
2100
|
Session = class {
|
|
2035
2101
|
sessionId;
|
|
@@ -2078,21 +2144,20 @@ var init_SessionManager = __esm({
|
|
|
2078
2144
|
return event;
|
|
2079
2145
|
}
|
|
2080
2146
|
};
|
|
2147
|
+
TRANSCRIPT_UPDATES = /* @__PURE__ */ new Set(["agent_message_chunk", "agent_thought_chunk", "tool_call", "tool_call_update"]);
|
|
2081
2148
|
TRANSCRIPT_PAGE_SIZE = 80;
|
|
2082
2149
|
SessionManager = class {
|
|
2083
2150
|
sessions = /* @__PURE__ */ new Map();
|
|
2084
2151
|
log;
|
|
2085
2152
|
store = new ChatStore();
|
|
2086
|
-
subagentLinks = new SubagentLinkStore();
|
|
2087
|
-
// Children the title fallback already tried and could not match. Matching hydrates the
|
|
2088
|
-
// whole parent transcript (145 MB in one chat), so each child is tried once per process.
|
|
2089
|
-
unmatchedChildren = /* @__PURE__ */ new Map();
|
|
2090
2153
|
spawnProcess;
|
|
2091
2154
|
cancelGraceMs;
|
|
2155
|
+
defaultModel;
|
|
2092
2156
|
constructor(log, opts = {}) {
|
|
2093
2157
|
this.log = log;
|
|
2094
2158
|
this.spawnProcess = opts.spawn ?? ((o, l) => new KiroProcess(o, l));
|
|
2095
2159
|
this.cancelGraceMs = opts.cancelGraceMs ?? CANCEL_GRACE_MS;
|
|
2160
|
+
this.defaultModel = opts.defaultModel ?? (async () => void 0);
|
|
2096
2161
|
}
|
|
2097
2162
|
/** What a session is called, from every read path. */
|
|
2098
2163
|
titleOf(chat, parts) {
|
|
@@ -2100,7 +2165,7 @@ var init_SessionManager = __esm({
|
|
|
2100
2165
|
override: chat.title ?? void 0,
|
|
2101
2166
|
kiroTitle: parts.kiroTitle,
|
|
2102
2167
|
firstPrompt: parts.firstPrompt,
|
|
2103
|
-
folder: isManagedWorkspace(parts.cwd) ? void 0 :
|
|
2168
|
+
folder: isManagedWorkspace(parts.cwd) ? void 0 : path12.basename(parts.cwd)
|
|
2104
2169
|
});
|
|
2105
2170
|
}
|
|
2106
2171
|
renameChat(chatId, title) {
|
|
@@ -2158,7 +2223,7 @@ var init_SessionManager = __esm({
|
|
|
2158
2223
|
}
|
|
2159
2224
|
/** The reload itself, called with the session's reload claim held. */
|
|
2160
2225
|
async replaceProcess(chatId, s) {
|
|
2161
|
-
if (!await
|
|
2226
|
+
if (!await isLoadable(s.sessionId)) {
|
|
2162
2227
|
throw new Error(
|
|
2163
2228
|
"kiro has not saved this session yet. Send a message first, then reload."
|
|
2164
2229
|
);
|
|
@@ -2172,9 +2237,9 @@ var init_SessionManager = __esm({
|
|
|
2172
2237
|
});
|
|
2173
2238
|
}
|
|
2174
2239
|
s.availableModes = [];
|
|
2240
|
+
invalidateAgents();
|
|
2175
2241
|
await this.ensureProc(s);
|
|
2176
2242
|
s.lastActivity = Date.now();
|
|
2177
|
-
invalidateAgents();
|
|
2178
2243
|
this.log.info({ sessionId: s.sessionId, cwd: s.cwd }, "session reloaded");
|
|
2179
2244
|
return this.getDetail(chatId);
|
|
2180
2245
|
}
|
|
@@ -2229,30 +2294,30 @@ var init_SessionManager = __esm({
|
|
|
2229
2294
|
wire(s, proc) {
|
|
2230
2295
|
proc.on("notification", (n) => {
|
|
2231
2296
|
if (s.replaying) return;
|
|
2232
|
-
if (n.method ===
|
|
2233
|
-
|
|
2234
|
-
const resolved = s.subagents.apply(params.subagents);
|
|
2235
|
-
for (const link of resolved) {
|
|
2236
|
-
this.subagentLinks.record(link.sessionId, s.sessionId, link.toolCallId, link.stageName);
|
|
2237
|
-
}
|
|
2238
|
-
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");
|
|
2239
2299
|
return;
|
|
2240
2300
|
}
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
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);
|
|
2254
2317
|
return;
|
|
2255
2318
|
}
|
|
2319
|
+
if (subagentId) this.trackSubagentCall(s, subagentId, update);
|
|
2320
|
+
s.record({ kind: "session_update", update });
|
|
2256
2321
|
});
|
|
2257
2322
|
proc.on("exit", (code, signal) => {
|
|
2258
2323
|
if (s.proc !== proc) return;
|
|
@@ -2261,28 +2326,50 @@ var init_SessionManager = __esm({
|
|
|
2261
2326
|
s.running = false;
|
|
2262
2327
|
});
|
|
2263
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
|
+
}
|
|
2264
2345
|
/** Gets or spawns the kiro process for a session. */
|
|
2265
2346
|
async ensureProc(s) {
|
|
2266
2347
|
if (s.proc) return s.proc;
|
|
2267
2348
|
if (s.spawning) return s.spawning;
|
|
2268
2349
|
s.spawning = (async () => {
|
|
2269
2350
|
await this.ensureCapacity();
|
|
2270
|
-
const proc = this.spawnProcess(
|
|
2271
|
-
{ cwd: s.cwd, agent: s.agentId, model: s.modelId },
|
|
2272
|
-
this.log
|
|
2273
|
-
);
|
|
2351
|
+
const proc = this.spawnProcess({ cwd: s.cwd }, this.log);
|
|
2274
2352
|
this.wire(s, proc);
|
|
2275
2353
|
await proc.initialize();
|
|
2276
2354
|
let res;
|
|
2277
2355
|
if (s.hasBeenLive) {
|
|
2278
2356
|
s.replaying = true;
|
|
2279
2357
|
try {
|
|
2280
|
-
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
|
+
});
|
|
2281
2364
|
} finally {
|
|
2282
2365
|
s.replaying = false;
|
|
2283
2366
|
}
|
|
2284
2367
|
} else {
|
|
2285
|
-
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
|
+
});
|
|
2286
2373
|
}
|
|
2287
2374
|
if (!s.hasBeenLive && res.sessionId !== s.sessionId) {
|
|
2288
2375
|
this.sessions.delete(s.sessionId);
|
|
@@ -2292,6 +2379,8 @@ var init_SessionManager = __esm({
|
|
|
2292
2379
|
s.availableModes = res.modes.availableModes;
|
|
2293
2380
|
s.currentModeId = res.modes.currentModeId;
|
|
2294
2381
|
s.agentId = res.modes.currentModeId ?? s.agentId;
|
|
2382
|
+
s.modelId = sessionModel(res) ?? s.modelId;
|
|
2383
|
+
rememberModes(res.modes.availableModes);
|
|
2295
2384
|
s.markLive();
|
|
2296
2385
|
s.proc = proc;
|
|
2297
2386
|
s.spawning = void 0;
|
|
@@ -2332,7 +2421,7 @@ var init_SessionManager = __esm({
|
|
|
2332
2421
|
const s = new Session(tempId, store, cwd);
|
|
2333
2422
|
s.agentId = opts.agentId ?? config.defaultAgent;
|
|
2334
2423
|
s.currentModeId = s.agentId;
|
|
2335
|
-
s.modelId = opts.modelId;
|
|
2424
|
+
s.modelId = opts.modelId ?? await this.defaultModel();
|
|
2336
2425
|
this.sessions.set(tempId, s);
|
|
2337
2426
|
try {
|
|
2338
2427
|
await this.ensureProc(s);
|
|
@@ -2342,7 +2431,7 @@ var init_SessionManager = __esm({
|
|
|
2342
2431
|
}
|
|
2343
2432
|
this.store.create(chatId);
|
|
2344
2433
|
this.store.bindSession(chatId, s.sessionId);
|
|
2345
|
-
const name = sanitizeTitle(opts.title ?? "") || (opts.freshWorkspace ? "" :
|
|
2434
|
+
const name = sanitizeTitle(opts.title ?? "") || (opts.freshWorkspace ? "" : path12.basename(s.cwd));
|
|
2346
2435
|
if (name) {
|
|
2347
2436
|
this.store.setTitle(chatId, name);
|
|
2348
2437
|
s.title = name;
|
|
@@ -2400,6 +2489,7 @@ ${tail}` : err.message;
|
|
|
2400
2489
|
s.cancelTimer = void 0;
|
|
2401
2490
|
s.running = false;
|
|
2402
2491
|
s.lastActivity = Date.now();
|
|
2492
|
+
if (s.subagents.turnEnded()) s.record({ kind: "subagents_changed", subagents: s.subagents.list() });
|
|
2403
2493
|
});
|
|
2404
2494
|
}
|
|
2405
2495
|
saveEnding(chatId, ending) {
|
|
@@ -2451,12 +2541,29 @@ ${tail}` : err.message;
|
|
|
2451
2541
|
s.modelId = modelId;
|
|
2452
2542
|
s.lastActivity = Date.now();
|
|
2453
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. */
|
|
2454
2546
|
async execCommand(chatId, command) {
|
|
2547
|
+
if (command.replace(/^\//, "") !== "compact") throw new Error(`Unsupported command: ${command}`);
|
|
2455
2548
|
const s = await this.ensureOpen(chatId);
|
|
2456
2549
|
await this.settleReload(s);
|
|
2550
|
+
if (s.turnState.get().compacting) throw new Error("The conversation is already being compacted");
|
|
2457
2551
|
const proc = await this.ensureProc(s);
|
|
2458
|
-
await proc.execCommand(s.sessionId, command);
|
|
2459
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
|
+
);
|
|
2460
2567
|
}
|
|
2461
2568
|
/** The one place a ChatSummary is assembled, since kiro's file and Casper's
|
|
2462
2569
|
* live state each hold part of the truth. */
|
|
@@ -2484,13 +2591,13 @@ ${tail}` : err.message;
|
|
|
2484
2591
|
}
|
|
2485
2592
|
async listChats() {
|
|
2486
2593
|
const rows = this.store.all();
|
|
2487
|
-
const files = await
|
|
2488
|
-
rows.map((r) => r.sessionId
|
|
2594
|
+
const files = await readPersistedSessions(
|
|
2595
|
+
rows.map((r) => r.sessionId).filter((id) => !!id)
|
|
2489
2596
|
);
|
|
2490
2597
|
const out = [];
|
|
2491
|
-
rows.forEach((row
|
|
2598
|
+
rows.forEach((row) => {
|
|
2492
2599
|
const live = row.sessionId ? this.sessions.get(row.sessionId) : void 0;
|
|
2493
|
-
const persisted = files
|
|
2600
|
+
const persisted = row.sessionId ? files.get(row.sessionId) : void 0;
|
|
2494
2601
|
if (live && isGhost(live, !!persisted)) {
|
|
2495
2602
|
this.evict(live.sessionId);
|
|
2496
2603
|
return;
|
|
@@ -2533,68 +2640,36 @@ ${tail}` : err.message;
|
|
|
2533
2640
|
const end = Math.max(start, Math.min(start + limit, transcript.length));
|
|
2534
2641
|
return transcript.slice(start, end);
|
|
2535
2642
|
}
|
|
2536
|
-
/**
|
|
2537
|
-
* A
|
|
2538
|
-
* A child the tracker never saw falls back to a recorded link or title matching
|
|
2539
|
-
* (subagentFallbackMatch.ts).
|
|
2540
|
-
*/
|
|
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. */
|
|
2541
2645
|
async getSubagents(chatId) {
|
|
2542
2646
|
const sessionId = this.sessionIdOf(chatId);
|
|
2543
|
-
const
|
|
2544
|
-
const live = s ? s.subagents.list() : [];
|
|
2545
|
-
const liveToolCalls = new Set(live.map((a) => a.toolCallId).filter((id) => !!id));
|
|
2546
|
-
const pending = s ? [...liveToolCalls].flatMap((id) => s.subagents.listForCall(id).filter((a) => a.status === "pending")) : [];
|
|
2547
|
-
const onDisk = await listChildSessions(sessionId);
|
|
2548
|
-
const links = this.subagentLinks.forParent(sessionId);
|
|
2549
|
-
const liveIds = new Set(live.map((a) => a.sessionId));
|
|
2550
|
-
const tried = this.unmatchedChildren.get(sessionId) ?? /* @__PURE__ */ new Set();
|
|
2551
|
-
const unresolved = onDisk.filter(
|
|
2552
|
-
(c) => !liveIds.has(c.sessionId) && !links.has(c.sessionId) && !tried.has(c.sessionId)
|
|
2553
|
-
);
|
|
2554
|
-
const fallback = unresolved.length ? matchSubagentsFallback(subagentCallsIn(await hydrateTranscript(sessionId)), unresolved) : [];
|
|
2555
|
-
const fallbackByChild = new Map(fallback.map((m) => [m.sessionId, m]));
|
|
2556
|
-
for (const m of fallback) this.subagentLinks.record(m.sessionId, sessionId, m.toolCallId, m.stageName);
|
|
2557
|
-
for (const c of unresolved) if (!fallbackByChild.has(c.sessionId)) tried.add(c.sessionId);
|
|
2558
|
-
this.unmatchedChildren.set(sessionId, tried);
|
|
2647
|
+
const live = this.sessions.get(sessionId)?.subagents.list() ?? [];
|
|
2559
2648
|
const byId = /* @__PURE__ */ new Map();
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
byId.set(
|
|
2563
|
-
|
|
2564
|
-
stageName: link?.stageName ?? (child.title || child.sessionId),
|
|
2565
|
-
toolCallId: link?.toolCallId,
|
|
2566
|
-
status: "completed",
|
|
2567
|
-
createdAt: child.createdAt,
|
|
2568
|
-
updatedAt: child.updatedAt
|
|
2569
|
-
});
|
|
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);
|
|
2570
2653
|
}
|
|
2571
|
-
for (const a of live) byId.set(a.sessionId, a);
|
|
2572
|
-
|
|
2573
|
-
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));
|
|
2574
2656
|
}
|
|
2575
2657
|
/** One subagent's own transcript, hydrated the same way a chat's is. */
|
|
2576
|
-
// Polled while a subagent runs, so it reads only the
|
|
2577
|
-
async getSubagentDetail(chatId,
|
|
2658
|
+
// Polled while a subagent runs, so it reads only the subagent's own files.
|
|
2659
|
+
async getSubagentDetail(chatId, subagentId) {
|
|
2578
2660
|
const parentSessionId = this.sessionIdOf(chatId);
|
|
2579
|
-
const
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
const
|
|
2583
|
-
const
|
|
2584
|
-
|
|
2585
|
-
stageName: link?.stageName ?? (child.title || childSessionId),
|
|
2586
|
-
toolCallId: link?.toolCallId,
|
|
2587
|
-
status: "completed",
|
|
2588
|
-
createdAt: child.createdAt,
|
|
2589
|
-
updatedAt: child.updatedAt
|
|
2590
|
-
};
|
|
2591
|
-
const transcript = showSummaryAsAnswer(await hydrateTranscript(childSessionId));
|
|
2592
|
-
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 };
|
|
2593
2667
|
}
|
|
2594
2668
|
/** One projection, so a dormant session and a live one cannot disagree. */
|
|
2595
|
-
buildDetail(chat, s,
|
|
2669
|
+
buildDetail(chat, s, hydrated, persisted) {
|
|
2670
|
+
const { transcript, head } = this.resumePoint(s, hydrated);
|
|
2596
2671
|
return {
|
|
2597
|
-
summary: this.summaryOf(chat, s, persisted,
|
|
2672
|
+
summary: this.summaryOf(chat, s, persisted, hydrated),
|
|
2598
2673
|
modes: s?.availableModes ?? [],
|
|
2599
2674
|
currentModeId: s?.currentModeId ?? persisted?.agentId,
|
|
2600
2675
|
transcript: transcript.slice(-TRANSCRIPT_PAGE_SIZE),
|
|
@@ -2603,16 +2678,19 @@ ${tail}` : err.message;
|
|
|
2603
2678
|
...emptyObservabilitySnapshot(),
|
|
2604
2679
|
contextUsagePercentage: persisted?.contextUsagePercentage ?? 0
|
|
2605
2680
|
},
|
|
2606
|
-
head
|
|
2681
|
+
head
|
|
2607
2682
|
};
|
|
2608
2683
|
}
|
|
2609
2684
|
/**
|
|
2610
|
-
*
|
|
2611
|
-
* 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.
|
|
2612
2689
|
*/
|
|
2613
|
-
|
|
2690
|
+
resumePoint(s, transcript) {
|
|
2691
|
+
if (!s) return { transcript, head: 0 };
|
|
2614
2692
|
const head = s.store.head();
|
|
2615
|
-
if (!s.running) return head;
|
|
2693
|
+
if (!s.running) return { transcript, head };
|
|
2616
2694
|
const { events } = s.store.getSince(0);
|
|
2617
2695
|
let started;
|
|
2618
2696
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
@@ -2621,18 +2699,19 @@ ${tail}` : err.message;
|
|
|
2621
2699
|
break;
|
|
2622
2700
|
}
|
|
2623
2701
|
}
|
|
2624
|
-
if (!started || started.payload.kind !== "turn_started") return head;
|
|
2702
|
+
if (!started || started.payload.kind !== "turn_started") return { transcript, head };
|
|
2625
2703
|
const promptText = stripAttachmentsLine(
|
|
2626
2704
|
started.payload.prompt.filter((b) => b.type === "text").map((b) => b.text).join("")
|
|
2627
2705
|
).trim();
|
|
2706
|
+
let cut = transcript.length;
|
|
2628
2707
|
for (let i = transcript.length - 1; i >= 0; i--) {
|
|
2629
2708
|
const it = transcript[i];
|
|
2630
2709
|
if (it.type === "message" && it.message.role === "user") {
|
|
2631
|
-
if (promptText && it.message.text.trim() === promptText)
|
|
2710
|
+
if (promptText && it.message.text.trim() === promptText) cut = i;
|
|
2632
2711
|
break;
|
|
2633
2712
|
}
|
|
2634
2713
|
}
|
|
2635
|
-
return started.seq - 1;
|
|
2714
|
+
return { transcript: transcript.slice(0, cut), head: started.seq - 1 };
|
|
2636
2715
|
}
|
|
2637
2716
|
evict(sessionId) {
|
|
2638
2717
|
const s = this.sessions.get(sessionId);
|
|
@@ -2666,6 +2745,70 @@ ${tail}` : err.message;
|
|
|
2666
2745
|
}
|
|
2667
2746
|
});
|
|
2668
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
|
+
|
|
2669
2812
|
// server/src/util/rateLimit.ts
|
|
2670
2813
|
var AttemptLimiter;
|
|
2671
2814
|
var init_rateLimit = __esm({
|
|
@@ -2812,63 +2955,6 @@ var init_auth = __esm({
|
|
|
2812
2955
|
}
|
|
2813
2956
|
});
|
|
2814
2957
|
|
|
2815
|
-
// server/src/session/models.ts
|
|
2816
|
-
import { execFile as execFile2 } from "node:child_process";
|
|
2817
|
-
import { promisify as promisify2 } from "node:util";
|
|
2818
|
-
async function configuredDefault() {
|
|
2819
|
-
try {
|
|
2820
|
-
const { stdout } = await execFileAsync2(config.kiroBin, [
|
|
2821
|
-
"settings",
|
|
2822
|
-
"chat.defaultModel",
|
|
2823
|
-
"-f",
|
|
2824
|
-
"json"
|
|
2825
|
-
]);
|
|
2826
|
-
const value = JSON.parse(stdout);
|
|
2827
|
-
return typeof value === "string" && value ? value : void 0;
|
|
2828
|
-
} catch {
|
|
2829
|
-
return void 0;
|
|
2830
|
-
}
|
|
2831
|
-
}
|
|
2832
|
-
async function listModels(log) {
|
|
2833
|
-
if (cache2) return cache2;
|
|
2834
|
-
const { stdout } = await execFileAsync2(
|
|
2835
|
-
config.kiroBin,
|
|
2836
|
-
["chat", "--list-models", "-f", "json"],
|
|
2837
|
-
{ maxBuffer: 4 * 1024 * 1024 }
|
|
2838
|
-
);
|
|
2839
|
-
const parsed = JSON.parse(stdout);
|
|
2840
|
-
const configured = await configuredDefault();
|
|
2841
|
-
const preferred = parsed.models.some((m) => m.model_id === configured) ? configured : parsed.default_model;
|
|
2842
|
-
cache2 = parsed.models.map((m, i) => ({
|
|
2843
|
-
modelId: m.model_id,
|
|
2844
|
-
modelName: m.model_name,
|
|
2845
|
-
description: m.description,
|
|
2846
|
-
contextWindowTokens: m.context_window_tokens,
|
|
2847
|
-
rateMultiplier: m.rate_multiplier,
|
|
2848
|
-
rateUnit: m.rate_unit,
|
|
2849
|
-
isDefault: preferred ? m.model_id === preferred : m.default_model ?? i === 0
|
|
2850
|
-
}));
|
|
2851
|
-
log.info({ count: cache2.length, default: preferred }, "loaded model list");
|
|
2852
|
-
return cache2;
|
|
2853
|
-
}
|
|
2854
|
-
async function kiroVersion() {
|
|
2855
|
-
try {
|
|
2856
|
-
const { stdout } = await execFileAsync2(config.kiroBin, ["--version"]);
|
|
2857
|
-
return stdout.trim();
|
|
2858
|
-
} catch {
|
|
2859
|
-
return void 0;
|
|
2860
|
-
}
|
|
2861
|
-
}
|
|
2862
|
-
var execFileAsync2, cache2;
|
|
2863
|
-
var init_models = __esm({
|
|
2864
|
-
"server/src/session/models.ts"() {
|
|
2865
|
-
"use strict";
|
|
2866
|
-
init_config();
|
|
2867
|
-
execFileAsync2 = promisify2(execFile2);
|
|
2868
|
-
cache2 = null;
|
|
2869
|
-
}
|
|
2870
|
-
});
|
|
2871
|
-
|
|
2872
2958
|
// server/src/routes/models.ts
|
|
2873
2959
|
function registerModelRoutes(app) {
|
|
2874
2960
|
app.get("/api/models", async () => {
|
|
@@ -2898,8 +2984,8 @@ var init_agents2 = __esm({
|
|
|
2898
2984
|
});
|
|
2899
2985
|
|
|
2900
2986
|
// server/src/util/confinedFile.ts
|
|
2901
|
-
import
|
|
2902
|
-
import
|
|
2987
|
+
import fs12 from "node:fs/promises";
|
|
2988
|
+
import path13 from "node:path";
|
|
2903
2989
|
async function resolveConfined(input, spec) {
|
|
2904
2990
|
let target = null;
|
|
2905
2991
|
for (const root of spec.lexical) {
|
|
@@ -2915,7 +3001,7 @@ async function resolveConfined(input, spec) {
|
|
|
2915
3001
|
if (!real) return { ok: false, ...await spec.notFound() };
|
|
2916
3002
|
let stat;
|
|
2917
3003
|
try {
|
|
2918
|
-
stat = await
|
|
3004
|
+
stat = await fs12.stat(real);
|
|
2919
3005
|
} catch {
|
|
2920
3006
|
return { ok: false, ...await spec.notFound() };
|
|
2921
3007
|
}
|
|
@@ -2954,7 +3040,7 @@ async function resolveChatPath(sessions, sessionId, requestedPath, require2) {
|
|
|
2954
3040
|
async function workspaceNotFound(cwd) {
|
|
2955
3041
|
let missing;
|
|
2956
3042
|
try {
|
|
2957
|
-
missing = !(await
|
|
3043
|
+
missing = !(await fs12.stat(cwd)).isDirectory();
|
|
2958
3044
|
} catch {
|
|
2959
3045
|
missing = true;
|
|
2960
3046
|
}
|
|
@@ -2974,7 +3060,7 @@ async function resolveAbsolutePath(input, require2) {
|
|
|
2974
3060
|
});
|
|
2975
3061
|
}
|
|
2976
3062
|
async function classifyDirent(parentReal, entry, realRoots) {
|
|
2977
|
-
const absolute =
|
|
3063
|
+
const absolute = path13.join(parentReal, entry.name);
|
|
2978
3064
|
if (entry.isDirectory()) return { kind: "directory", real: absolute };
|
|
2979
3065
|
if (entry.isFile()) return { kind: "file", real: absolute };
|
|
2980
3066
|
if (!entry.isSymbolicLink()) return null;
|
|
@@ -2982,7 +3068,7 @@ async function classifyDirent(parentReal, entry, realRoots) {
|
|
|
2982
3068
|
const real = await realConfineToRoot(root, absolute);
|
|
2983
3069
|
if (!real) continue;
|
|
2984
3070
|
try {
|
|
2985
|
-
const stat = await
|
|
3071
|
+
const stat = await fs12.stat(real);
|
|
2986
3072
|
if (stat.isDirectory()) return { kind: "directory", real };
|
|
2987
3073
|
if (stat.isFile()) return { kind: "file", real };
|
|
2988
3074
|
} catch {
|
|
@@ -3000,7 +3086,7 @@ var init_confinedFile = __esm({
|
|
|
3000
3086
|
});
|
|
3001
3087
|
|
|
3002
3088
|
// server/src/util/filekind.ts
|
|
3003
|
-
import
|
|
3089
|
+
import path14 from "node:path";
|
|
3004
3090
|
function mimeForExt(ext) {
|
|
3005
3091
|
return MIME_MAP[ext.toLowerCase()] ?? "application/octet-stream";
|
|
3006
3092
|
}
|
|
@@ -3020,7 +3106,7 @@ function looksBinary(buf) {
|
|
|
3020
3106
|
return control / buf.length > 0.3;
|
|
3021
3107
|
}
|
|
3022
3108
|
function classifyKind(name) {
|
|
3023
|
-
const ext =
|
|
3109
|
+
const ext = path14.extname(name).toLowerCase();
|
|
3024
3110
|
if (ext in IMAGE_EXTS) return "image";
|
|
3025
3111
|
if (TEXT_EXTS.has(ext)) return "text";
|
|
3026
3112
|
return "binary";
|
|
@@ -3130,9 +3216,9 @@ var init_filekind = __esm({
|
|
|
3130
3216
|
});
|
|
3131
3217
|
|
|
3132
3218
|
// server/src/routes/filePreview.ts
|
|
3133
|
-
import
|
|
3219
|
+
import fs13 from "node:fs/promises";
|
|
3134
3220
|
import { createReadStream } from "node:fs";
|
|
3135
|
-
import
|
|
3221
|
+
import path15 from "node:path";
|
|
3136
3222
|
function tooLargeForPreview(size, maxBytes) {
|
|
3137
3223
|
return {
|
|
3138
3224
|
error: `File too large for preview (${(size / 1024 / 1024).toFixed(1)} MB, max ${maxBytes / 1024 / 1024} MB)`
|
|
@@ -3159,7 +3245,7 @@ function hexdump(buf) {
|
|
|
3159
3245
|
return lines.join("\n");
|
|
3160
3246
|
}
|
|
3161
3247
|
async function sendFilePreview(req, reply, realTarget, stat) {
|
|
3162
|
-
const ext =
|
|
3248
|
+
const ext = path15.extname(realTarget).toLowerCase();
|
|
3163
3249
|
const mime = mimeForExt(ext);
|
|
3164
3250
|
const isImage2 = mime.startsWith("image/");
|
|
3165
3251
|
const isPdf = mime === "application/pdf";
|
|
@@ -3204,7 +3290,7 @@ async function sendFilePreview(req, reply, realTarget, stat) {
|
|
|
3204
3290
|
if (kind === "binary") {
|
|
3205
3291
|
let fh;
|
|
3206
3292
|
try {
|
|
3207
|
-
fh = await
|
|
3293
|
+
fh = await fs13.open(realTarget, "r");
|
|
3208
3294
|
const buf = Buffer.alloc(Math.min(HEXDUMP_BYTES, stat.size));
|
|
3209
3295
|
const { bytesRead } = await fh.read(buf, 0, buf.length, 0);
|
|
3210
3296
|
const head = buf.subarray(0, bytesRead);
|
|
@@ -3248,9 +3334,9 @@ var init_filePreview = __esm({
|
|
|
3248
3334
|
});
|
|
3249
3335
|
|
|
3250
3336
|
// server/src/routes/fs.ts
|
|
3251
|
-
import
|
|
3337
|
+
import fs14 from "node:fs/promises";
|
|
3252
3338
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
3253
|
-
import
|
|
3339
|
+
import path16 from "node:path";
|
|
3254
3340
|
function registerFsRoutes(app) {
|
|
3255
3341
|
app.get(
|
|
3256
3342
|
"/api/fs/dirs",
|
|
@@ -3258,10 +3344,10 @@ function registerFsRoutes(app) {
|
|
|
3258
3344
|
const input = (req.query.path ?? "").trim();
|
|
3259
3345
|
const base = config.defaultCwd;
|
|
3260
3346
|
const endsWithSep = input.endsWith("/");
|
|
3261
|
-
const resolved = input ?
|
|
3262
|
-
const dir = endsWithSep || !input ? resolved :
|
|
3263
|
-
const prefix = endsWithSep || !input ? "" :
|
|
3264
|
-
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");
|
|
3265
3351
|
const listing = await resolveAbsolutePath(dir, "directory");
|
|
3266
3352
|
if (!listing.ok) {
|
|
3267
3353
|
if (listing.status === 403) return replyWith(reply, listing);
|
|
@@ -3270,7 +3356,7 @@ function registerFsRoutes(app) {
|
|
|
3270
3356
|
const realDir = listing.real;
|
|
3271
3357
|
let entries = [];
|
|
3272
3358
|
try {
|
|
3273
|
-
const dirents = await
|
|
3359
|
+
const dirents = await fs14.readdir(realDir, { withFileTypes: true });
|
|
3274
3360
|
const checks2 = await Promise.all(
|
|
3275
3361
|
dirents.map(async (d) => {
|
|
3276
3362
|
const target = await classifyDirent(realDir, d, absoluteRoots());
|
|
@@ -3281,7 +3367,7 @@ function registerFsRoutes(app) {
|
|
|
3281
3367
|
entries = checks2.filter((name) => name !== null).filter((name) => name.toLowerCase().startsWith(prefix.toLowerCase())).sort((a, b) => {
|
|
3282
3368
|
if (isDot(a) !== isDot(b)) return isDot(a) ? 1 : -1;
|
|
3283
3369
|
return a.localeCompare(b);
|
|
3284
|
-
}).slice(0, 500).map((name) =>
|
|
3370
|
+
}).slice(0, 500).map((name) => path16.join(dir, name));
|
|
3285
3371
|
} catch {
|
|
3286
3372
|
entries = [];
|
|
3287
3373
|
}
|
|
@@ -3296,7 +3382,7 @@ function registerFsRoutes(app) {
|
|
|
3296
3382
|
reply.code(400);
|
|
3297
3383
|
return { error: "path parameter is required" };
|
|
3298
3384
|
}
|
|
3299
|
-
if (!
|
|
3385
|
+
if (!path16.isAbsolute(filePath)) {
|
|
3300
3386
|
reply.code(400);
|
|
3301
3387
|
return { error: "path must be absolute" };
|
|
3302
3388
|
}
|
|
@@ -3306,7 +3392,7 @@ function registerFsRoutes(app) {
|
|
|
3306
3392
|
reply.header("Content-Type", "application/octet-stream");
|
|
3307
3393
|
reply.header(
|
|
3308
3394
|
"Content-Disposition",
|
|
3309
|
-
`attachment; filename="${
|
|
3395
|
+
`attachment; filename="${path16.basename(resolved.real).replace(/"/g, "")}"`
|
|
3310
3396
|
);
|
|
3311
3397
|
reply.header("Content-Length", resolved.stat.size);
|
|
3312
3398
|
return reply.send(createReadStream2(resolved.real));
|
|
@@ -3477,9 +3563,9 @@ var init_subagents = __esm({
|
|
|
3477
3563
|
});
|
|
3478
3564
|
|
|
3479
3565
|
// server/src/routes/workspace.ts
|
|
3480
|
-
import
|
|
3566
|
+
import fs15 from "node:fs/promises";
|
|
3481
3567
|
import { createReadStream as createReadStream3 } from "node:fs";
|
|
3482
|
-
import
|
|
3568
|
+
import path17 from "node:path";
|
|
3483
3569
|
function registerWorkspaceRoutes(app, manager) {
|
|
3484
3570
|
app.get(
|
|
3485
3571
|
"/api/chats/:id/tree",
|
|
@@ -3494,7 +3580,7 @@ function registerWorkspaceRoutes(app, manager) {
|
|
|
3494
3580
|
const { cwd, relative, real: realTarget } = resolved;
|
|
3495
3581
|
let dirents;
|
|
3496
3582
|
try {
|
|
3497
|
-
dirents = await
|
|
3583
|
+
dirents = await fs15.readdir(realTarget, { withFileTypes: true, encoding: "utf8" });
|
|
3498
3584
|
} catch {
|
|
3499
3585
|
return replyWith(reply, await workspaceNotFound(cwd));
|
|
3500
3586
|
}
|
|
@@ -3508,7 +3594,7 @@ function registerWorkspaceRoutes(app, manager) {
|
|
|
3508
3594
|
continue;
|
|
3509
3595
|
}
|
|
3510
3596
|
try {
|
|
3511
|
-
const stat = await
|
|
3597
|
+
const stat = await fs15.stat(target.real);
|
|
3512
3598
|
entries.push({
|
|
3513
3599
|
name: d.name,
|
|
3514
3600
|
path: entryRelative,
|
|
@@ -3537,8 +3623,8 @@ function registerWorkspaceRoutes(app, manager) {
|
|
|
3537
3623
|
reply.code(413);
|
|
3538
3624
|
return { error: `File too large (${(stat.size / 1024 / 1024).toFixed(1)} MB, max 100 MB)` };
|
|
3539
3625
|
}
|
|
3540
|
-
const ext =
|
|
3541
|
-
const filename =
|
|
3626
|
+
const ext = path17.extname(realTarget);
|
|
3627
|
+
const filename = path17.basename(realTarget);
|
|
3542
3628
|
const asciiName = filename.replace(/[^\w.\-]/g, "_");
|
|
3543
3629
|
reply.header("Content-Type", mimeForExt(ext));
|
|
3544
3630
|
reply.header(
|
|
@@ -3573,27 +3659,27 @@ var init_workspace = __esm({
|
|
|
3573
3659
|
|
|
3574
3660
|
// server/src/routes/uploads.ts
|
|
3575
3661
|
import { createReadStream as createReadStream4, createWriteStream } from "node:fs";
|
|
3576
|
-
import
|
|
3577
|
-
import
|
|
3662
|
+
import fs16 from "node:fs/promises";
|
|
3663
|
+
import path18 from "node:path";
|
|
3578
3664
|
import crypto4 from "node:crypto";
|
|
3579
3665
|
import { execFile as execFile3 } from "node:child_process";
|
|
3580
3666
|
import { pipeline } from "node:stream/promises";
|
|
3581
3667
|
function sanitizeName(raw) {
|
|
3582
|
-
const base =
|
|
3668
|
+
const base = path18.basename(raw).replace(/[^\w.\- ]/g, "_").trim();
|
|
3583
3669
|
if (!base || base === "." || base === "..") return `upload-${Date.now()}`;
|
|
3584
3670
|
return base.replace(/^\.+/, "") || `upload-${Date.now()}`;
|
|
3585
3671
|
}
|
|
3586
3672
|
async function uniquePath(dir, name) {
|
|
3587
|
-
const ext =
|
|
3673
|
+
const ext = path18.extname(name);
|
|
3588
3674
|
const stem = name.slice(0, name.length - ext.length);
|
|
3589
3675
|
let candidate = name;
|
|
3590
3676
|
let n = 1;
|
|
3591
3677
|
while (true) {
|
|
3592
3678
|
try {
|
|
3593
|
-
await
|
|
3679
|
+
await fs16.access(path18.join(dir, candidate));
|
|
3594
3680
|
candidate = `${stem} (${n++})${ext}`;
|
|
3595
3681
|
} catch {
|
|
3596
|
-
return
|
|
3682
|
+
return path18.join(dir, candidate);
|
|
3597
3683
|
}
|
|
3598
3684
|
}
|
|
3599
3685
|
}
|
|
@@ -3613,7 +3699,7 @@ function fileType(absPath) {
|
|
|
3613
3699
|
async function sampleStrings(absPath, limit = 40) {
|
|
3614
3700
|
let fh;
|
|
3615
3701
|
try {
|
|
3616
|
-
fh = await
|
|
3702
|
+
fh = await fs16.open(absPath, "r");
|
|
3617
3703
|
const buf = Buffer.alloc(STRINGS_SCAN_BYTES);
|
|
3618
3704
|
const { bytesRead } = await fh.read(buf, 0, STRINGS_SCAN_BYTES, 0);
|
|
3619
3705
|
const out = [];
|
|
@@ -3645,7 +3731,7 @@ function registerUploadRoutes(app) {
|
|
|
3645
3731
|
return { error: "Invalid chat id" };
|
|
3646
3732
|
}
|
|
3647
3733
|
const uploadDir = chatUploadsDir(req.params.chatId);
|
|
3648
|
-
await
|
|
3734
|
+
await fs16.mkdir(uploadDir, { recursive: true, mode: 448 });
|
|
3649
3735
|
const results = [];
|
|
3650
3736
|
const parts = req.files();
|
|
3651
3737
|
for await (const part of parts) {
|
|
@@ -3659,17 +3745,17 @@ function registerUploadRoutes(app) {
|
|
|
3659
3745
|
return { error: `Failed to store ${name}` };
|
|
3660
3746
|
}
|
|
3661
3747
|
if (part.file.truncated) {
|
|
3662
|
-
await
|
|
3748
|
+
await fs16.rm(dest, { force: true });
|
|
3663
3749
|
reply.code(413);
|
|
3664
3750
|
return {
|
|
3665
3751
|
error: `${name} exceeds the max upload size (${Math.round(config.maxUploadBytes / 1024 / 1024)} MB)`
|
|
3666
3752
|
};
|
|
3667
3753
|
}
|
|
3668
|
-
const stat = await
|
|
3669
|
-
const ext =
|
|
3754
|
+
const stat = await fs16.stat(dest);
|
|
3755
|
+
const ext = path18.extname(dest);
|
|
3670
3756
|
const kind = classifyKind(dest);
|
|
3671
3757
|
const uploaded = {
|
|
3672
|
-
name:
|
|
3758
|
+
name: path18.basename(dest),
|
|
3673
3759
|
path: dest,
|
|
3674
3760
|
size: stat.size,
|
|
3675
3761
|
mimeType: mimeForExt(ext),
|
|
@@ -3725,7 +3811,7 @@ var init_health = __esm({
|
|
|
3725
3811
|
});
|
|
3726
3812
|
|
|
3727
3813
|
// server/src/ws/dirWatchers.ts
|
|
3728
|
-
import
|
|
3814
|
+
import fs17 from "node:fs";
|
|
3729
3815
|
function diffWatchSet(current, next) {
|
|
3730
3816
|
const have = new Set(current);
|
|
3731
3817
|
const want = new Set(next.slice(0, MAX_WATCHES));
|
|
@@ -3749,7 +3835,7 @@ function createDirWatchers(opts) {
|
|
|
3749
3835
|
const target = await opts.resolve(relative);
|
|
3750
3836
|
if (!target || closed) return;
|
|
3751
3837
|
try {
|
|
3752
|
-
const watcher =
|
|
3838
|
+
const watcher = fs17.watch(target, { persistent: false }, () => {
|
|
3753
3839
|
const existing = timers.get(relative);
|
|
3754
3840
|
if (existing) clearTimeout(existing);
|
|
3755
3841
|
timers.set(
|
|
@@ -3807,7 +3893,7 @@ function handleConnection(socket, manager, chatId, startCursor) {
|
|
|
3807
3893
|
return null;
|
|
3808
3894
|
}
|
|
3809
3895
|
},
|
|
3810
|
-
onChange: (
|
|
3896
|
+
onChange: (path21) => send(socket, { type: "fs_changed", path: path21 })
|
|
3811
3897
|
});
|
|
3812
3898
|
const forward = (event) => {
|
|
3813
3899
|
if (event.seq <= cursor) return;
|
|
@@ -3940,7 +4026,7 @@ var init_gateway = __esm({
|
|
|
3940
4026
|
});
|
|
3941
4027
|
|
|
3942
4028
|
// server/src/app.ts
|
|
3943
|
-
import
|
|
4029
|
+
import fs18 from "node:fs";
|
|
3944
4030
|
import Fastify from "fastify";
|
|
3945
4031
|
import websocket from "@fastify/websocket";
|
|
3946
4032
|
import fastifyStatic from "@fastify/static";
|
|
@@ -3959,7 +4045,7 @@ async function buildApp() {
|
|
|
3959
4045
|
transport: isProd ? void 0 : { target: "pino/file", options: { destination: 2 } }
|
|
3960
4046
|
}
|
|
3961
4047
|
});
|
|
3962
|
-
const manager = new SessionManager(logger);
|
|
4048
|
+
const manager = new SessionManager(logger, { defaultModel: () => defaultModelId(logger) });
|
|
3963
4049
|
const startedAt = Date.now();
|
|
3964
4050
|
await app.register(websocket, {
|
|
3965
4051
|
options: { maxPayload: 16 * 1024 * 1024 }
|
|
@@ -3977,20 +4063,20 @@ async function buildApp() {
|
|
|
3977
4063
|
registerWorkspaceRoutes(app, manager);
|
|
3978
4064
|
registerUploadRoutes(app);
|
|
3979
4065
|
registerWsGateway(app, manager);
|
|
3980
|
-
if (
|
|
4066
|
+
if (fs18.existsSync(config.webDist)) {
|
|
3981
4067
|
await app.register(fastifyStatic, {
|
|
3982
4068
|
root: config.webDist
|
|
3983
4069
|
});
|
|
3984
4070
|
app.addHook("onSend", async (req, reply) => {
|
|
3985
|
-
const
|
|
3986
|
-
if (
|
|
4071
|
+
const path21 = req.url.split("?")[0] ?? "";
|
|
4072
|
+
if (path21 === "/manifest.json" || path21.startsWith("/icons/")) {
|
|
3987
4073
|
reply.header("cache-control", "public, max-age=300");
|
|
3988
4074
|
}
|
|
3989
4075
|
});
|
|
3990
4076
|
app.setNotFoundHandler((req, reply) => {
|
|
3991
|
-
const
|
|
3992
|
-
const looksLikeAsset =
|
|
3993
|
-
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) {
|
|
3994
4080
|
reply.code(404).send({ error: "Not found" });
|
|
3995
4081
|
return;
|
|
3996
4082
|
}
|
|
@@ -4005,6 +4091,7 @@ var init_app = __esm({
|
|
|
4005
4091
|
init_config();
|
|
4006
4092
|
init_logger();
|
|
4007
4093
|
init_SessionManager();
|
|
4094
|
+
init_models();
|
|
4008
4095
|
init_auth();
|
|
4009
4096
|
init_models2();
|
|
4010
4097
|
init_agents2();
|
|
@@ -4061,19 +4148,22 @@ var init_server = __esm({
|
|
|
4061
4148
|
// server/src/cli/doctor.ts
|
|
4062
4149
|
var doctor_exports = {};
|
|
4063
4150
|
__export(doctor_exports, {
|
|
4151
|
+
agentFormat: () => agentFormat,
|
|
4064
4152
|
doctor: () => doctor,
|
|
4153
|
+
kiroMajor: () => kiroMajor,
|
|
4065
4154
|
mcpWiring: () => mcpWiring
|
|
4066
4155
|
});
|
|
4067
4156
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
4068
|
-
import
|
|
4069
|
-
import
|
|
4157
|
+
import fs19 from "node:fs";
|
|
4158
|
+
import os4 from "node:os";
|
|
4159
|
+
import path19 from "node:path";
|
|
4070
4160
|
function which(bin) {
|
|
4071
|
-
if (bin.includes("/")) return
|
|
4072
|
-
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)) {
|
|
4073
4163
|
if (dir === "") continue;
|
|
4074
|
-
const candidate =
|
|
4164
|
+
const candidate = path19.join(dir, bin);
|
|
4075
4165
|
try {
|
|
4076
|
-
|
|
4166
|
+
fs19.accessSync(candidate, fs19.constants.X_OK);
|
|
4077
4167
|
return candidate;
|
|
4078
4168
|
} catch {
|
|
4079
4169
|
}
|
|
@@ -4097,11 +4187,28 @@ function mcpWiring(agentJson, resolve) {
|
|
|
4097
4187
|
return { ok: false, detail: `${command || "(no command)"} not found - widgets are unavailable` };
|
|
4098
4188
|
}
|
|
4099
4189
|
const script = args.find((a) => a.endsWith(".js"));
|
|
4100
|
-
if (script && !
|
|
4190
|
+
if (script && !fs19.existsSync(script)) {
|
|
4101
4191
|
return { ok: false, detail: `${script} is gone - delete the agent file and restart to rewrite it` };
|
|
4102
4192
|
}
|
|
4103
4193
|
return { ok: true, detail: script ?? `${command} ${args.join(" ")}` };
|
|
4104
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
|
+
}
|
|
4105
4212
|
function checks() {
|
|
4106
4213
|
const out = [];
|
|
4107
4214
|
out.push({
|
|
@@ -4117,7 +4224,10 @@ function checks() {
|
|
|
4117
4224
|
} catch {
|
|
4118
4225
|
version = "(version unavailable)";
|
|
4119
4226
|
}
|
|
4120
|
-
|
|
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
|
+
);
|
|
4121
4231
|
} else {
|
|
4122
4232
|
out.push({
|
|
4123
4233
|
ok: false,
|
|
@@ -4129,7 +4239,7 @@ function checks() {
|
|
|
4129
4239
|
const settings = readSettings(config.configFile);
|
|
4130
4240
|
const hasToken = typeof settings.token === "string" && settings.token !== "";
|
|
4131
4241
|
out.push(
|
|
4132
|
-
|
|
4242
|
+
fs19.existsSync(config.configFile) ? {
|
|
4133
4243
|
ok: hasToken,
|
|
4134
4244
|
name: "settings",
|
|
4135
4245
|
detail: hasToken ? `${config.configFile} (token set)` : `${config.configFile} exists but has no token - auth is DISABLED`
|
|
@@ -4139,8 +4249,8 @@ function checks() {
|
|
|
4139
4249
|
detail: `${config.configFile} not found; a token is generated on first run`
|
|
4140
4250
|
}
|
|
4141
4251
|
);
|
|
4142
|
-
if (
|
|
4143
|
-
const mode =
|
|
4252
|
+
if (fs19.existsSync(config.configFile)) {
|
|
4253
|
+
const mode = fs19.statSync(config.configFile).mode & 511;
|
|
4144
4254
|
out.push({
|
|
4145
4255
|
ok: mode === 384,
|
|
4146
4256
|
name: "settings mode",
|
|
@@ -4148,10 +4258,10 @@ function checks() {
|
|
|
4148
4258
|
});
|
|
4149
4259
|
}
|
|
4150
4260
|
try {
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
const db2 =
|
|
4154
|
-
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` : "";
|
|
4155
4265
|
out.push({ ok: true, name: "data dir", detail: `${config.casperDataDir} writable${size}` });
|
|
4156
4266
|
} catch (err) {
|
|
4157
4267
|
out.push({
|
|
@@ -4162,22 +4272,25 @@ function checks() {
|
|
|
4162
4272
|
});
|
|
4163
4273
|
}
|
|
4164
4274
|
out.push(
|
|
4165
|
-
|
|
4275
|
+
fs19.existsSync(config.webDist) ? { ok: true, name: "web app", detail: config.webDist } : {
|
|
4166
4276
|
ok: false,
|
|
4167
4277
|
fatal: true,
|
|
4168
4278
|
name: "web app",
|
|
4169
4279
|
detail: `${config.webDist} not found - the package is incomplete or CASPER_WEB_DIST is wrong`
|
|
4170
4280
|
}
|
|
4171
4281
|
);
|
|
4172
|
-
const agent =
|
|
4173
|
-
const hasAgent =
|
|
4282
|
+
const agent = path19.join(os4.homedir(), ".kiro", "agents", "casper.json");
|
|
4283
|
+
const hasAgent = fs19.existsSync(agent);
|
|
4174
4284
|
out.push({
|
|
4175
4285
|
ok: hasAgent,
|
|
4176
4286
|
name: "casper agent",
|
|
4177
4287
|
detail: hasAgent ? agent : `${agent} missing - it is installed on first run`
|
|
4178
4288
|
});
|
|
4179
4289
|
if (hasAgent) {
|
|
4180
|
-
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);
|
|
4181
4294
|
out.push({ ok: wiring.ok, name: "casper mcp", detail: wiring.detail });
|
|
4182
4295
|
}
|
|
4183
4296
|
return out;
|
|
@@ -4641,14 +4754,14 @@ var init_server2 = __esm({
|
|
|
4641
4754
|
"server/src/mcp/server.ts"() {
|
|
4642
4755
|
"use strict";
|
|
4643
4756
|
init_protocol();
|
|
4644
|
-
VERSION = true ? "0.
|
|
4757
|
+
VERSION = true ? "0.16.0" : "dev";
|
|
4645
4758
|
}
|
|
4646
4759
|
});
|
|
4647
4760
|
|
|
4648
4761
|
// server/src/cli/program.ts
|
|
4649
|
-
import
|
|
4650
|
-
import
|
|
4651
|
-
import
|
|
4762
|
+
import fs20 from "node:fs";
|
|
4763
|
+
import os5 from "node:os";
|
|
4764
|
+
import path20 from "node:path";
|
|
4652
4765
|
|
|
4653
4766
|
// server/node_modules/commander/lib/error.js
|
|
4654
4767
|
var CommanderError = class extends Error {
|
|
@@ -5239,8 +5352,8 @@ var Help = class {
|
|
|
5239
5352
|
* @param {string} str
|
|
5240
5353
|
* @returns {number}
|
|
5241
5354
|
*/
|
|
5242
|
-
displayWidth(
|
|
5243
|
-
return stripVTControlCharacters(
|
|
5355
|
+
displayWidth(str3) {
|
|
5356
|
+
return stripVTControlCharacters(str3).length;
|
|
5244
5357
|
}
|
|
5245
5358
|
/**
|
|
5246
5359
|
* Style the title for displaying in the help. Called with 'Usage:', 'Options:', etc.
|
|
@@ -5248,11 +5361,11 @@ var Help = class {
|
|
|
5248
5361
|
* @param {string} str
|
|
5249
5362
|
* @returns {string}
|
|
5250
5363
|
*/
|
|
5251
|
-
styleTitle(
|
|
5252
|
-
return
|
|
5364
|
+
styleTitle(str3) {
|
|
5365
|
+
return str3;
|
|
5253
5366
|
}
|
|
5254
|
-
styleUsage(
|
|
5255
|
-
return
|
|
5367
|
+
styleUsage(str3) {
|
|
5368
|
+
return str3.split(" ").map((word) => {
|
|
5256
5369
|
if (word === "[options]") return this.styleOptionText(word);
|
|
5257
5370
|
if (word === "[command]") return this.styleSubcommandText(word);
|
|
5258
5371
|
if (word[0] === "[" || word[0] === "<")
|
|
@@ -5260,46 +5373,46 @@ var Help = class {
|
|
|
5260
5373
|
return this.styleCommandText(word);
|
|
5261
5374
|
}).join(" ");
|
|
5262
5375
|
}
|
|
5263
|
-
styleCommandDescription(
|
|
5264
|
-
return this.styleDescriptionText(
|
|
5376
|
+
styleCommandDescription(str3) {
|
|
5377
|
+
return this.styleDescriptionText(str3);
|
|
5265
5378
|
}
|
|
5266
|
-
styleOptionDescription(
|
|
5267
|
-
return this.styleDescriptionText(
|
|
5379
|
+
styleOptionDescription(str3) {
|
|
5380
|
+
return this.styleDescriptionText(str3);
|
|
5268
5381
|
}
|
|
5269
|
-
styleSubcommandDescription(
|
|
5270
|
-
return this.styleDescriptionText(
|
|
5382
|
+
styleSubcommandDescription(str3) {
|
|
5383
|
+
return this.styleDescriptionText(str3);
|
|
5271
5384
|
}
|
|
5272
|
-
styleArgumentDescription(
|
|
5273
|
-
return this.styleDescriptionText(
|
|
5385
|
+
styleArgumentDescription(str3) {
|
|
5386
|
+
return this.styleDescriptionText(str3);
|
|
5274
5387
|
}
|
|
5275
|
-
styleDescriptionText(
|
|
5276
|
-
return
|
|
5388
|
+
styleDescriptionText(str3) {
|
|
5389
|
+
return str3;
|
|
5277
5390
|
}
|
|
5278
|
-
styleOptionTerm(
|
|
5279
|
-
return this.styleOptionText(
|
|
5391
|
+
styleOptionTerm(str3) {
|
|
5392
|
+
return this.styleOptionText(str3);
|
|
5280
5393
|
}
|
|
5281
|
-
styleSubcommandTerm(
|
|
5282
|
-
return
|
|
5394
|
+
styleSubcommandTerm(str3) {
|
|
5395
|
+
return str3.split(" ").map((word) => {
|
|
5283
5396
|
if (word === "[options]") return this.styleOptionText(word);
|
|
5284
5397
|
if (word[0] === "[" || word[0] === "<")
|
|
5285
5398
|
return this.styleArgumentText(word);
|
|
5286
5399
|
return this.styleSubcommandText(word);
|
|
5287
5400
|
}).join(" ");
|
|
5288
5401
|
}
|
|
5289
|
-
styleArgumentTerm(
|
|
5290
|
-
return this.styleArgumentText(
|
|
5402
|
+
styleArgumentTerm(str3) {
|
|
5403
|
+
return this.styleArgumentText(str3);
|
|
5291
5404
|
}
|
|
5292
|
-
styleOptionText(
|
|
5293
|
-
return
|
|
5405
|
+
styleOptionText(str3) {
|
|
5406
|
+
return str3;
|
|
5294
5407
|
}
|
|
5295
|
-
styleArgumentText(
|
|
5296
|
-
return
|
|
5408
|
+
styleArgumentText(str3) {
|
|
5409
|
+
return str3;
|
|
5297
5410
|
}
|
|
5298
|
-
styleSubcommandText(
|
|
5299
|
-
return
|
|
5411
|
+
styleSubcommandText(str3) {
|
|
5412
|
+
return str3;
|
|
5300
5413
|
}
|
|
5301
|
-
styleCommandText(
|
|
5302
|
-
return
|
|
5414
|
+
styleCommandText(str3) {
|
|
5415
|
+
return str3;
|
|
5303
5416
|
}
|
|
5304
5417
|
/**
|
|
5305
5418
|
* Calculate the pad width from the maximum term length.
|
|
@@ -5322,8 +5435,8 @@ var Help = class {
|
|
|
5322
5435
|
* @param {string} str
|
|
5323
5436
|
* @returns {boolean}
|
|
5324
5437
|
*/
|
|
5325
|
-
preformatted(
|
|
5326
|
-
return /\n[^\S\r\n]/.test(
|
|
5438
|
+
preformatted(str3) {
|
|
5439
|
+
return /\n[^\S\r\n]/.test(str3);
|
|
5327
5440
|
}
|
|
5328
5441
|
/**
|
|
5329
5442
|
* Format the "item", which consists of a term and description. Pad the term and wrap the description, indenting the following lines.
|
|
@@ -5369,9 +5482,9 @@ ${itemIndentStr}`);
|
|
|
5369
5482
|
* @param {number} width
|
|
5370
5483
|
* @returns {string}
|
|
5371
5484
|
*/
|
|
5372
|
-
boxWrap(
|
|
5373
|
-
if (width < this.minWidthToWrap) return
|
|
5374
|
-
const rawLines =
|
|
5485
|
+
boxWrap(str3, width) {
|
|
5486
|
+
if (width < this.minWidthToWrap) return str3;
|
|
5487
|
+
const rawLines = str3.split(/\r\n|\n/);
|
|
5375
5488
|
const chunkPattern = /[\s]*[^\s]+/g;
|
|
5376
5489
|
const wrappedLines = [];
|
|
5377
5490
|
rawLines.forEach((line) => {
|
|
@@ -5661,9 +5774,9 @@ var DualOptions = class {
|
|
|
5661
5774
|
return option.negate === (negativeValue === value);
|
|
5662
5775
|
}
|
|
5663
5776
|
};
|
|
5664
|
-
function camelcase(
|
|
5665
|
-
return
|
|
5666
|
-
return
|
|
5777
|
+
function camelcase(str3) {
|
|
5778
|
+
return str3.split("-").reduce((str4, word) => {
|
|
5779
|
+
return str4 + word[0].toUpperCase() + word.slice(1);
|
|
5667
5780
|
});
|
|
5668
5781
|
}
|
|
5669
5782
|
function splitOptionFlags(flags) {
|
|
@@ -5823,14 +5936,14 @@ var Command = class _Command extends EventEmitter {
|
|
|
5823
5936
|
this._showSuggestionAfterError = true;
|
|
5824
5937
|
this._savedState = null;
|
|
5825
5938
|
this._outputConfiguration = {
|
|
5826
|
-
writeOut: (
|
|
5827
|
-
writeErr: (
|
|
5828
|
-
outputError: (
|
|
5939
|
+
writeOut: (str3) => process2.stdout.write(str3),
|
|
5940
|
+
writeErr: (str3) => process2.stderr.write(str3),
|
|
5941
|
+
outputError: (str3, write) => write(str3),
|
|
5829
5942
|
getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : void 0,
|
|
5830
5943
|
getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : void 0,
|
|
5831
5944
|
getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()),
|
|
5832
5945
|
getErrHasColors: () => useColor() ?? (process2.stderr.isTTY && process2.stderr.hasColors?.()),
|
|
5833
|
-
stripColor: (
|
|
5946
|
+
stripColor: (str3) => stripVTControlCharacters2(str3)
|
|
5834
5947
|
};
|
|
5835
5948
|
this._hidden = false;
|
|
5836
5949
|
this._helpOption = void 0;
|
|
@@ -7558,18 +7671,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7558
7671
|
* @param {string} [description]
|
|
7559
7672
|
* @return {(this | string | undefined)} `this` command for chaining, or version string if no arguments
|
|
7560
7673
|
*/
|
|
7561
|
-
version(
|
|
7562
|
-
if (
|
|
7563
|
-
this._version =
|
|
7674
|
+
version(str3, flags, description) {
|
|
7675
|
+
if (str3 === void 0) return this._version;
|
|
7676
|
+
this._version = str3;
|
|
7564
7677
|
flags = flags || "-V, --version";
|
|
7565
7678
|
description = description || "output the version number";
|
|
7566
7679
|
const versionOption = this.createOption(flags, description);
|
|
7567
7680
|
this._versionOptionName = versionOption.attributeName();
|
|
7568
7681
|
this._registerOption(versionOption);
|
|
7569
7682
|
this.on("option:" + versionOption.name(), () => {
|
|
7570
|
-
this._outputConfiguration.writeOut(`${
|
|
7683
|
+
this._outputConfiguration.writeOut(`${str3}
|
|
7571
7684
|
`);
|
|
7572
|
-
this._exit(0, "commander.version",
|
|
7685
|
+
this._exit(0, "commander.version", str3);
|
|
7573
7686
|
});
|
|
7574
7687
|
return this;
|
|
7575
7688
|
}
|
|
@@ -7580,10 +7693,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7580
7693
|
* @param {object} [argsDescription]
|
|
7581
7694
|
* @return {(string|Command)}
|
|
7582
7695
|
*/
|
|
7583
|
-
description(
|
|
7584
|
-
if (
|
|
7696
|
+
description(str3, argsDescription) {
|
|
7697
|
+
if (str3 === void 0 && argsDescription === void 0)
|
|
7585
7698
|
return this._description;
|
|
7586
|
-
this._description =
|
|
7699
|
+
this._description = str3;
|
|
7587
7700
|
if (argsDescription) {
|
|
7588
7701
|
this._argsDescription = argsDescription;
|
|
7589
7702
|
}
|
|
@@ -7595,9 +7708,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7595
7708
|
* @param {string} [str]
|
|
7596
7709
|
* @return {(string|Command)}
|
|
7597
7710
|
*/
|
|
7598
|
-
summary(
|
|
7599
|
-
if (
|
|
7600
|
-
this._summary =
|
|
7711
|
+
summary(str3) {
|
|
7712
|
+
if (str3 === void 0) return this._summary;
|
|
7713
|
+
this._summary = str3;
|
|
7601
7714
|
return this;
|
|
7602
7715
|
}
|
|
7603
7716
|
/**
|
|
@@ -7645,8 +7758,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7645
7758
|
* @param {string} [str]
|
|
7646
7759
|
* @return {(string|Command)}
|
|
7647
7760
|
*/
|
|
7648
|
-
usage(
|
|
7649
|
-
if (
|
|
7761
|
+
usage(str3) {
|
|
7762
|
+
if (str3 === void 0) {
|
|
7650
7763
|
if (this._usage) return this._usage;
|
|
7651
7764
|
const args = this.registeredArguments.map((arg) => {
|
|
7652
7765
|
return humanReadableArgName(arg);
|
|
@@ -7657,7 +7770,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7657
7770
|
this.registeredArguments.length ? args : []
|
|
7658
7771
|
).join(" ");
|
|
7659
7772
|
}
|
|
7660
|
-
this._usage =
|
|
7773
|
+
this._usage = str3;
|
|
7661
7774
|
return this;
|
|
7662
7775
|
}
|
|
7663
7776
|
/**
|
|
@@ -7666,9 +7779,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7666
7779
|
* @param {string} [str]
|
|
7667
7780
|
* @return {(string|Command)}
|
|
7668
7781
|
*/
|
|
7669
|
-
name(
|
|
7670
|
-
if (
|
|
7671
|
-
this._name =
|
|
7782
|
+
name(str3) {
|
|
7783
|
+
if (str3 === void 0) return this._name;
|
|
7784
|
+
this._name = str3;
|
|
7672
7785
|
return this;
|
|
7673
7786
|
}
|
|
7674
7787
|
/**
|
|
@@ -7761,9 +7874,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7761
7874
|
* @param {string} [path]
|
|
7762
7875
|
* @return {(string|null|Command)}
|
|
7763
7876
|
*/
|
|
7764
|
-
executableDir(
|
|
7765
|
-
if (
|
|
7766
|
-
this._executableDir =
|
|
7877
|
+
executableDir(path21) {
|
|
7878
|
+
if (path21 === void 0) return this._executableDir;
|
|
7879
|
+
this._executableDir = path21;
|
|
7767
7880
|
return this;
|
|
7768
7881
|
}
|
|
7769
7882
|
/**
|
|
@@ -7802,17 +7915,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
7802
7915
|
let hasColors;
|
|
7803
7916
|
let helpWidth;
|
|
7804
7917
|
if (error) {
|
|
7805
|
-
baseWrite = (
|
|
7918
|
+
baseWrite = (str3) => this._outputConfiguration.writeErr(str3);
|
|
7806
7919
|
hasColors = this._outputConfiguration.getErrHasColors();
|
|
7807
7920
|
helpWidth = this._outputConfiguration.getErrHelpWidth();
|
|
7808
7921
|
} else {
|
|
7809
|
-
baseWrite = (
|
|
7922
|
+
baseWrite = (str3) => this._outputConfiguration.writeOut(str3);
|
|
7810
7923
|
hasColors = this._outputConfiguration.getOutHasColors();
|
|
7811
7924
|
helpWidth = this._outputConfiguration.getOutHelpWidth();
|
|
7812
7925
|
}
|
|
7813
|
-
const write = (
|
|
7814
|
-
if (!hasColors)
|
|
7815
|
-
return baseWrite(
|
|
7926
|
+
const write = (str3) => {
|
|
7927
|
+
if (!hasColors) str3 = this._outputConfiguration.stripColor(str3);
|
|
7928
|
+
return baseWrite(str3);
|
|
7816
7929
|
};
|
|
7817
7930
|
return { error, write, hasColors, helpWidth };
|
|
7818
7931
|
}
|
|
@@ -8021,7 +8134,7 @@ var program = new Command();
|
|
|
8021
8134
|
// server/src/cli/program.ts
|
|
8022
8135
|
init_paths();
|
|
8023
8136
|
init_settings();
|
|
8024
|
-
var VERSION2 = true ? "0.
|
|
8137
|
+
var VERSION2 = true ? "0.16.0" : "dev";
|
|
8025
8138
|
async function bootstrap() {
|
|
8026
8139
|
const file = configFilePath();
|
|
8027
8140
|
const settings = readSettings(file);
|
|
@@ -8034,7 +8147,7 @@ async function bootstrap() {
|
|
|
8034
8147
|
`);
|
|
8035
8148
|
}
|
|
8036
8149
|
const { installAgentFile: installAgentFile2 } = await Promise.resolve().then(() => (init_agentFile(), agentFile_exports));
|
|
8037
|
-
const agent = installAgentFile2(
|
|
8150
|
+
const agent = installAgentFile2(os5.homedir(), dataDirPath());
|
|
8038
8151
|
if (agent.action === "installed" || agent.action === "updated") {
|
|
8039
8152
|
process.stdout.write(`casper agent ${agent.action}: ${agent.target}
|
|
8040
8153
|
`);
|
|
@@ -8067,8 +8180,8 @@ async function resetToken(value) {
|
|
|
8067
8180
|
updateSettings(file, { token });
|
|
8068
8181
|
process.stdout.write(`wrote a new token to ${file}
|
|
8069
8182
|
`);
|
|
8070
|
-
const dbFile =
|
|
8071
|
-
if (
|
|
8183
|
+
const dbFile = path20.join(dataDirPath(), "casper.db");
|
|
8184
|
+
if (fs20.existsSync(dbFile)) {
|
|
8072
8185
|
const { LoginStore: LoginStore2 } = await Promise.resolve().then(() => (init_logins(), logins_exports));
|
|
8073
8186
|
new LoginStore2().revokeAll();
|
|
8074
8187
|
process.stdout.write("revoked all device sessions\n");
|