@creative-dswork/dscode 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dscode.mjs
CHANGED
|
@@ -214348,7 +214348,7 @@ function generateRecoveryTimelineHTML(recoveryArcs) {
|
|
|
214348
214348
|
<span style="background:${COLORS.warn};color:#000;padding:4px 10px;border-radius:4px;font-size:12px;font-weight:600;white-space:nowrap;">\u{1F50D} Step ${arc.detectionStep}</span>
|
|
214349
214349
|
<span style="color:${COLORS.textMuted};font-size:14px;">\u2192</span>
|
|
214350
214350
|
<span style="background:${effectiveColor};color:#000;padding:4px 10px;border-radius:4px;font-size:12px;font-weight:600;white-space:nowrap;">${effectiveIcon} Step ${arc.correctionStep}</span>
|
|
214351
|
-
<span style="background:rgba(
|
|
214351
|
+
<span style="background:rgba(212,151,8,0.15);padding:2px 8px;border-radius:4px;font-size:11px;color:${COLORS.accent};">${detLabel}</span>
|
|
214352
214352
|
<span style="font-size:11px;color:${COLORS.textMuted};">${arc.stepsToRecover} steps</span>
|
|
214353
214353
|
${arc.misdiagnosisCount > 0 ? `<span style="background:rgba(210,153,29,0.15);padding:2px 8px;border-radius:4px;font-size:11px;color:${COLORS.warn};">${arc.misdiagnosisCount} \u6B21\u8BEF\u5224</span>` : ""}
|
|
214354
214354
|
</div>
|
|
@@ -214356,7 +214356,7 @@ function generateRecoveryTimelineHTML(recoveryArcs) {
|
|
|
214356
214356
|
<span style="color:${COLORS.danger};">${escapeHtml(arc.errorAgent)}</span>: ${escapeHtml(arc.errorSummary)}
|
|
214357
214357
|
\u2192 <span style="color:${effectiveColor};">${escapeHtml(arc.correctionAgent)}</span>: ${escapeHtml(arc.correctionSummary)}
|
|
214358
214358
|
</div>
|
|
214359
|
-
<div style="font-size:12px;color:${COLORS.accent};font-style:italic;padding:8px 12px;background:rgba(
|
|
214359
|
+
<div style="font-size:12px;color:${COLORS.accent};font-style:italic;padding:8px 12px;background:rgba(212,151,8,0.08);border-radius:4px;border-left:3px solid ${COLORS.accent};margin-top:8px;">
|
|
214360
214360
|
\u{1F4A1} \u6839\u56E0\u5047\u8BF4: ${escapeHtml(arc.rootCauseHypothesis)}
|
|
214361
214361
|
</div>
|
|
214362
214362
|
</div>`;
|
|
@@ -214444,7 +214444,7 @@ function generateRuleChainHTML(attribution, rulesApplied) {
|
|
|
214444
214444
|
"Rule3": "Irrecoverable Point \u2014 identifies the FIRST step that made the correct path unrecoverable (not necessarily the first error)"
|
|
214445
214445
|
};
|
|
214446
214446
|
const ruleItems = rulesApplied.map((r) => `
|
|
214447
|
-
<div style="padding:8px 12px;margin:4px 0;background:${r === "Rule3" ? "rgba(
|
|
214447
|
+
<div style="padding:8px 12px;margin:4px 0;background:${r === "Rule3" ? "rgba(224,85,83,0.15)" : "rgba(212,151,8,0.1)"};border-left:3px solid ${r === "Rule3" ? COLORS.danger : COLORS.accent};border-radius:4px;">
|
|
214448
214448
|
<strong style="color:${COLORS.accent};font-size:13px;">${escapeHtml(r)}</strong>
|
|
214449
214449
|
<div style="font-size:12px;color:${COLORS.textMuted};margin-top:2px;">${escapeHtml(ruleDescriptions[r] ?? "")}</div>
|
|
214450
214450
|
</div>`).join("");
|
|
@@ -214471,7 +214471,7 @@ function generateCascadePathHTML(cascadePath) {
|
|
|
214471
214471
|
<span style="font-family:monospace;font-size:13px;color:${COLORS.accent};">${escapeHtml(e.fromZoneId)}:${e.fromStepId}</span>
|
|
214472
214472
|
<span style="color:${COLORS.textMuted};font-size:18px;">\u2192</span>
|
|
214473
214473
|
<span style="font-family:monospace;font-size:13px;">${escapeHtml(e.toZoneId)}:${e.toStepId}</span>
|
|
214474
|
-
<span style="background:rgba(
|
|
214474
|
+
<span style="background:rgba(212,151,8,0.15);padding:2px 8px;border-radius:4px;font-size:11px;color:${COLORS.accent};">${mechanismLabel}</span>
|
|
214475
214475
|
<span style="font-size:11px;color:${COLORS.textMuted};">\u6570\u636E: ${escapeHtml(e.dataItem)}</span>
|
|
214476
214476
|
</div>`;
|
|
214477
214477
|
}).join("");
|
|
@@ -214503,9 +214503,9 @@ body {
|
|
|
214503
214503
|
max-width: 1200px;
|
|
214504
214504
|
margin: 0 auto;
|
|
214505
214505
|
}
|
|
214506
|
-
h1 { font-size: 28px; font-weight: 600; margin-bottom: 4px; color: #
|
|
214507
|
-
h2 { font-size: 20px; font-weight: 600; margin: 32px 0 16px; color: #
|
|
214508
|
-
h3 { font-size: 16px; font-weight: 600; margin-bottom: 8px; color: #
|
|
214506
|
+
h1 { font-size: 28px; font-weight: 600; margin-bottom: 4px; color: #e8e4dd; }
|
|
214507
|
+
h2 { font-size: 20px; font-weight: 600; margin: 32px 0 16px; color: #e8e4dd; border-bottom: 1px solid ${COLORS.border}; padding-bottom: 8px; }
|
|
214508
|
+
h3 { font-size: 16px; font-weight: 600; margin-bottom: 8px; color: #e8e4dd; }
|
|
214509
214509
|
.header { background: ${COLORS.card}; border: 1px solid ${COLORS.border}; border-radius: 8px; padding: 24px; margin-bottom: 24px; }
|
|
214510
214510
|
.header-meta { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; margin-top: 16px; }
|
|
214511
214511
|
.meta-item { }
|
|
@@ -214686,7 +214686,7 @@ ${(() => {
|
|
|
214686
214686
|
grouped[cat].push(r);
|
|
214687
214687
|
}
|
|
214688
214688
|
return Object.entries(grouped).map(([cat, catRules]) => `
|
|
214689
|
-
<h3 style="font-size:15px;font-weight:600;margin:24px 0 12px;color:#
|
|
214689
|
+
<h3 style="font-size:15px;font-weight:600;margin:24px 0 12px;color:#e8e4dd;">${escapeHtml(catLabels[cat] ?? cat)}</h3>
|
|
214690
214690
|
${catRules.map((r) => {
|
|
214691
214691
|
const sevLabel = r.severity >= 1 ? "ERROR" : r.severity >= 0.6 ? "WARN" : "INFO";
|
|
214692
214692
|
const sevColor = r.severity >= 1 ? COLORS.danger : r.severity >= 0.6 ? COLORS.warn : COLORS.accent;
|
|
@@ -214707,7 +214707,7 @@ ${catRules.map((r) => {
|
|
|
214707
214707
|
${r.rawDescription ? `
|
|
214708
214708
|
<details style="margin-bottom:8px;">
|
|
214709
214709
|
<summary style="font-size:11px;color:${COLORS.accent};cursor:pointer;">\u{1F4DD} \u8BE6\u7EC6\u63CF\u8FF0</summary>
|
|
214710
|
-
<p style="font-size:12px;color:${COLORS.textMuted};margin:4px 0;padding:8px;background:rgba(
|
|
214710
|
+
<p style="font-size:12px;color:${COLORS.textMuted};margin:4px 0;padding:8px;background:rgba(212,151,8,0.05);border-radius:4px;white-space:pre-wrap;">${escapeHtml(r.rawDescription)}</p>
|
|
214711
214711
|
</details>` : ""}
|
|
214712
214712
|
${r.severity >= 1 ? `<div style="font-size:11px;color:${COLORS.danger};margin-bottom:6px;">\u26A0 \u5EFA\u8BAE\u6301\u4E45\u5316\u5230 Agent \u914D\u7F6E (${escapeHtml(r.targetLayer)})</div>` : ""}
|
|
214713
214713
|
<div style="background:${COLORS.card};border-radius:4px;padding:10px 12px;">
|
|
@@ -214771,15 +214771,15 @@ var init_dashboard = __esm({
|
|
|
214771
214771
|
"src/eval/dashboard.ts"() {
|
|
214772
214772
|
"use strict";
|
|
214773
214773
|
COLORS = {
|
|
214774
|
-
ok: "#
|
|
214775
|
-
warn: "#
|
|
214776
|
-
danger: "#
|
|
214777
|
-
bg: "#
|
|
214778
|
-
card: "#
|
|
214779
|
-
border: "#
|
|
214780
|
-
text: "#
|
|
214781
|
-
textMuted: "#
|
|
214782
|
-
accent: "#
|
|
214774
|
+
ok: "#5ca860",
|
|
214775
|
+
warn: "#d4a017",
|
|
214776
|
+
danger: "#e05553",
|
|
214777
|
+
bg: "#1e1c19",
|
|
214778
|
+
card: "#282622",
|
|
214779
|
+
border: "#3a3732",
|
|
214780
|
+
text: "#e8e4dd",
|
|
214781
|
+
textMuted: "#8a8580",
|
|
214782
|
+
accent: "#d49708"
|
|
214783
214783
|
};
|
|
214784
214784
|
CASCADE_MECHANISM_LABELS = {
|
|
214785
214785
|
data_contamination: "\u6570\u636E\u6C61\u67D3",
|
|
@@ -220426,6 +220426,83 @@ var init_at_file_resolver = __esm({
|
|
|
220426
220426
|
}
|
|
220427
220427
|
});
|
|
220428
220428
|
|
|
220429
|
+
// src/ui/shared/tool-result-formatter.ts
|
|
220430
|
+
function extractWriteSummary(text) {
|
|
220431
|
+
const lines = text.split("\n");
|
|
220432
|
+
const meaningful = [];
|
|
220433
|
+
for (const line of lines) {
|
|
220434
|
+
if (meaningful.length >= 2) break;
|
|
220435
|
+
const trimmed = line.trim();
|
|
220436
|
+
if (trimmed.length > 0) {
|
|
220437
|
+
meaningful.push(trimmed);
|
|
220438
|
+
}
|
|
220439
|
+
}
|
|
220440
|
+
if (meaningful.length === 0) return text.slice(0, DEFAULT_MAX_CHARS);
|
|
220441
|
+
const summary = meaningful.join("\n");
|
|
220442
|
+
const remainingLines = lines.length - 2;
|
|
220443
|
+
if (remainingLines > 0) {
|
|
220444
|
+
return `${summary}
|
|
220445
|
+
\u2026 (${remainingLines} more lines \u2014 anchor preview hidden)`;
|
|
220446
|
+
}
|
|
220447
|
+
return summary;
|
|
220448
|
+
}
|
|
220449
|
+
function isJSON(text) {
|
|
220450
|
+
const trimmed = text.trim();
|
|
220451
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return false;
|
|
220452
|
+
try {
|
|
220453
|
+
JSON.parse(trimmed);
|
|
220454
|
+
return true;
|
|
220455
|
+
} catch {
|
|
220456
|
+
return false;
|
|
220457
|
+
}
|
|
220458
|
+
}
|
|
220459
|
+
function prettyPrintJSON(text) {
|
|
220460
|
+
return JSON.stringify(JSON.parse(text.trim()), null, 2);
|
|
220461
|
+
}
|
|
220462
|
+
function formatCodeBlock(text, lang) {
|
|
220463
|
+
const fence = lang ? "```" + lang : "```";
|
|
220464
|
+
return `${fence}
|
|
220465
|
+
${text}
|
|
220466
|
+
\`\`\``;
|
|
220467
|
+
}
|
|
220468
|
+
function truncate(text) {
|
|
220469
|
+
if (text.length <= DEFAULT_MAX_CHARS) return text;
|
|
220470
|
+
return text.slice(0, DEFAULT_MAX_CHARS) + `
|
|
220471
|
+
\u2026 (${text.length - DEFAULT_MAX_CHARS} more chars)`;
|
|
220472
|
+
}
|
|
220473
|
+
function formatToolResultForUI(toolName, rawText) {
|
|
220474
|
+
if (!rawText) return "";
|
|
220475
|
+
switch (toolName) {
|
|
220476
|
+
case "write_file":
|
|
220477
|
+
case "overwrite_file":
|
|
220478
|
+
return extractWriteSummary(rawText);
|
|
220479
|
+
case "bash":
|
|
220480
|
+
return formatCodeBlock(truncate(rawText), "sh");
|
|
220481
|
+
case "grep":
|
|
220482
|
+
case "glob": {
|
|
220483
|
+
if (isJSON(rawText)) {
|
|
220484
|
+
return formatCodeBlock(truncate(prettyPrintJSON(rawText)), "json");
|
|
220485
|
+
}
|
|
220486
|
+
return formatCodeBlock(truncate(rawText));
|
|
220487
|
+
}
|
|
220488
|
+
case "read_file":
|
|
220489
|
+
return formatCodeBlock(truncate(rawText));
|
|
220490
|
+
default: {
|
|
220491
|
+
if (isJSON(rawText)) {
|
|
220492
|
+
return formatCodeBlock(truncate(prettyPrintJSON(rawText)), "json");
|
|
220493
|
+
}
|
|
220494
|
+
return truncate(rawText);
|
|
220495
|
+
}
|
|
220496
|
+
}
|
|
220497
|
+
}
|
|
220498
|
+
var DEFAULT_MAX_CHARS;
|
|
220499
|
+
var init_tool_result_formatter = __esm({
|
|
220500
|
+
"src/ui/shared/tool-result-formatter.ts"() {
|
|
220501
|
+
"use strict";
|
|
220502
|
+
DEFAULT_MAX_CHARS = 600;
|
|
220503
|
+
}
|
|
220504
|
+
});
|
|
220505
|
+
|
|
220429
220506
|
// src/session/display.ts
|
|
220430
220507
|
function extractText(content) {
|
|
220431
220508
|
if (typeof content === "string") return content;
|
|
@@ -220449,9 +220526,10 @@ function extractThinkingFromContent(blocks) {
|
|
|
220449
220526
|
}
|
|
220450
220527
|
return parts.length > 0 ? parts.join("\n\n") : void 0;
|
|
220451
220528
|
}
|
|
220452
|
-
function extractToolResultText(blocks) {
|
|
220529
|
+
function extractToolResultText(blocks, toolName) {
|
|
220453
220530
|
if (!Array.isArray(blocks)) return "";
|
|
220454
|
-
|
|
220531
|
+
const raw = blocks.filter((b) => b && b.type === "text").map((b) => b.text).join("\n");
|
|
220532
|
+
return formatToolResultForUI(toolName, raw);
|
|
220455
220533
|
}
|
|
220456
220534
|
function rebuildDisplayMessages(messages, visionMessages) {
|
|
220457
220535
|
const visionMap = /* @__PURE__ */ new Map();
|
|
@@ -220494,14 +220572,17 @@ function rebuildDisplayMessages(messages, visionMessages) {
|
|
|
220494
220572
|
const toolCallId = m.toolCallId;
|
|
220495
220573
|
if (toolCallId && lastAssistantToolIds.has(toolCallId)) {
|
|
220496
220574
|
const toolIdx = lastAssistantToolIds.get(toolCallId);
|
|
220497
|
-
const
|
|
220575
|
+
const assistantMsg = messages[lastAssistantIdx];
|
|
220576
|
+
const parsedTools = assistantMsg.__parsedTools;
|
|
220577
|
+
const toolName = parsedTools?.[toolIdx]?.name ?? "unknown";
|
|
220578
|
+
const resultText = extractToolResultText(m.content, toolName);
|
|
220498
220579
|
const isError = !!m.isError;
|
|
220499
220580
|
let results = pendingResults.get(lastAssistantIdx);
|
|
220500
220581
|
if (!results) {
|
|
220501
220582
|
results = /* @__PURE__ */ new Map();
|
|
220502
220583
|
pendingResults.set(lastAssistantIdx, results);
|
|
220503
220584
|
}
|
|
220504
|
-
results.set(toolCallId, { result: resultText, isError });
|
|
220585
|
+
results.set(toolCallId, { result: resultText, isError, toolName });
|
|
220505
220586
|
} else {
|
|
220506
220587
|
output.add(i);
|
|
220507
220588
|
}
|
|
@@ -220577,6 +220658,7 @@ var init_display = __esm({
|
|
|
220577
220658
|
"src/session/display.ts"() {
|
|
220578
220659
|
"use strict";
|
|
220579
220660
|
init_image_cache();
|
|
220661
|
+
init_tool_result_formatter();
|
|
220580
220662
|
}
|
|
220581
220663
|
});
|
|
220582
220664
|
|
|
@@ -220682,6 +220764,7 @@ import { createServer, request as httpRequest2 } from "node:http";
|
|
|
220682
220764
|
import { readFileSync as readFileSync23, existsSync as existsSync25 } from "node:fs";
|
|
220683
220765
|
import { join as join28, extname as extname2, resolve as resolve10 } from "node:path";
|
|
220684
220766
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
220767
|
+
import { streamSimple as streamSimple3 } from "@mariozechner/pi-ai";
|
|
220685
220768
|
function extractImagesFromToolResult(result) {
|
|
220686
220769
|
if (!result || typeof result !== "object") return void 0;
|
|
220687
220770
|
const r = result;
|
|
@@ -220707,6 +220790,7 @@ var init_web_backend = __esm({
|
|
|
220707
220790
|
init_mcp_browser();
|
|
220708
220791
|
init_at_file_resolver();
|
|
220709
220792
|
init_display();
|
|
220793
|
+
init_tool_result_formatter();
|
|
220710
220794
|
init_ws_server();
|
|
220711
220795
|
WebUiBackend = class {
|
|
220712
220796
|
port;
|
|
@@ -220730,6 +220814,11 @@ var init_web_backend = __esm({
|
|
|
220730
220814
|
pendingImages = [];
|
|
220731
220815
|
// Message accumulation for the current assistant turn
|
|
220732
220816
|
currentAssistant = null;
|
|
220817
|
+
// Context window broadcast throttling
|
|
220818
|
+
contextWindowThrottleTimer = null;
|
|
220819
|
+
contextWindowThrottlePending = false;
|
|
220820
|
+
lastArtifactHtml = "";
|
|
220821
|
+
isAssistantTurn = false;
|
|
220733
220822
|
constructor(options) {
|
|
220734
220823
|
this.port = options.port;
|
|
220735
220824
|
this.harness = options.harness;
|
|
@@ -220758,23 +220847,29 @@ var init_web_backend = __esm({
|
|
|
220758
220847
|
this.broadcast({ type: "tool_start", name: e.name, args: e.args });
|
|
220759
220848
|
});
|
|
220760
220849
|
h.events.on("tool:end", (e) => {
|
|
220761
|
-
const
|
|
220850
|
+
const rawResult = typeof e.result === "string" ? e.result : JSON.stringify(e.result);
|
|
220851
|
+
const rs = formatToolResultForUI(e.name, rawResult);
|
|
220762
220852
|
const imgs = extractImagesFromToolResult(e.result);
|
|
220763
220853
|
if (this.currentAssistant) {
|
|
220764
220854
|
this.currentAssistant.tools = this.currentAssistant.tools.filter((t) => t.name !== e.name || t.result !== "");
|
|
220765
220855
|
this.currentAssistant.tools.push({ name: e.name, args: "", result: rs, isError: e.isError, images: imgs });
|
|
220766
220856
|
}
|
|
220767
220857
|
this.broadcast({ type: "tool_end", name: e.name, result: rs, isError: e.isError, images: imgs });
|
|
220858
|
+
this.broadcastContextWindow(false);
|
|
220768
220859
|
});
|
|
220769
220860
|
h.events.on("turn:streaming:start", () => {
|
|
220770
220861
|
this.currentAssistant = { thinking: "", text: "", tools: [] };
|
|
220771
220862
|
this.broadcast({ type: "assistant_start" });
|
|
220772
220863
|
this.startSessionTimeBroadcast();
|
|
220864
|
+
this.isAssistantTurn = true;
|
|
220773
220865
|
});
|
|
220774
220866
|
h.events.on("turn:end", () => {
|
|
220775
220867
|
this.broadcastSessionTime();
|
|
220868
|
+
const toolsForBroadcast = this.currentAssistant?.tools ?? [];
|
|
220776
220869
|
this.currentAssistant = null;
|
|
220777
220870
|
this.broadcast({ type: "assistant_end" });
|
|
220871
|
+
this.isAssistantTurn = false;
|
|
220872
|
+
this.broadcastContextWindow(true, toolsForBroadcast);
|
|
220778
220873
|
this.pushSessionListToAll();
|
|
220779
220874
|
});
|
|
220780
220875
|
h.events.on("turn:abort", () => {
|
|
@@ -220810,6 +220905,7 @@ var init_web_backend = __esm({
|
|
|
220810
220905
|
this.currentAssistant = null;
|
|
220811
220906
|
this.pendingImages = [];
|
|
220812
220907
|
this.broadcast({ type: "clear_conversation" });
|
|
220908
|
+
this.broadcastContextWindow(true);
|
|
220813
220909
|
});
|
|
220814
220910
|
h.events.on("config:change", (e) => {
|
|
220815
220911
|
this.broadcast({ type: "config", data: e.data });
|
|
@@ -220827,6 +220923,9 @@ var init_web_backend = __esm({
|
|
|
220827
220923
|
h.events.on("session:created", () => {
|
|
220828
220924
|
this.pushSessionListToAll();
|
|
220829
220925
|
});
|
|
220926
|
+
h.events.on("session:deleted", () => {
|
|
220927
|
+
this.pushSessionListToAll();
|
|
220928
|
+
});
|
|
220830
220929
|
}
|
|
220831
220930
|
setAppHostManager(manager) {
|
|
220832
220931
|
this.appHostManager = manager;
|
|
@@ -220903,12 +221002,15 @@ var init_web_backend = __esm({
|
|
|
220903
221002
|
});
|
|
220904
221003
|
}
|
|
220905
221004
|
this.broadcast({ type: "tool_end", name, result: resultStr, isError, images });
|
|
221005
|
+
this.broadcastContextWindow(false);
|
|
220906
221006
|
}
|
|
220907
221007
|
finishAssistantMessage() {
|
|
220908
221008
|
this.broadcastSessionTime();
|
|
220909
221009
|
this.stopSessionTimeBroadcast();
|
|
221010
|
+
const toolsForBroadcast2 = this.currentAssistant?.tools ?? [];
|
|
220910
221011
|
this.currentAssistant = null;
|
|
220911
221012
|
this.broadcast({ type: "assistant_end" });
|
|
221013
|
+
this.broadcastContextWindow(true, toolsForBroadcast2);
|
|
220912
221014
|
const sm2 = this.harness.sessionManager;
|
|
220913
221015
|
if (sm2) {
|
|
220914
221016
|
const sessions2 = sm2.listSessions();
|
|
@@ -220934,6 +221036,7 @@ var init_web_backend = __esm({
|
|
|
220934
221036
|
projectPath: s.projectPath || "",
|
|
220935
221037
|
preview: s.preview || "",
|
|
220936
221038
|
totalActiveMs: s.id === currentId2 ? sm2.getTotalActiveMs() : s.totalActiveMs ?? 0,
|
|
221039
|
+
contentHash: s.contentHash ?? "",
|
|
220937
221040
|
pendingPermission: s.pendingPermission || void 0
|
|
220938
221041
|
}))
|
|
220939
221042
|
});
|
|
@@ -221013,9 +221116,11 @@ var init_web_backend = __esm({
|
|
|
221013
221116
|
focusEditor() {
|
|
221014
221117
|
}
|
|
221015
221118
|
clearConversationView() {
|
|
221119
|
+
const toolsForBroadcast3 = this.currentAssistant?.tools ?? [];
|
|
221016
221120
|
this.currentAssistant = null;
|
|
221017
221121
|
this.pendingImages = [];
|
|
221018
221122
|
this.broadcast({ type: "clear_conversation" });
|
|
221123
|
+
this.broadcastContextWindow(true, toolsForBroadcast3);
|
|
221019
221124
|
}
|
|
221020
221125
|
// ── UiBackend Processing ──
|
|
221021
221126
|
setProcessing(processing) {
|
|
@@ -221060,6 +221165,7 @@ var init_web_backend = __esm({
|
|
|
221060
221165
|
config: configData,
|
|
221061
221166
|
messages
|
|
221062
221167
|
});
|
|
221168
|
+
this.broadcastContextWindow(true);
|
|
221063
221169
|
if (this.mcpManager) {
|
|
221064
221170
|
this.pushMcpState();
|
|
221065
221171
|
}
|
|
@@ -221252,6 +221358,10 @@ var init_web_backend = __esm({
|
|
|
221252
221358
|
client.send({ type: "file_list_result", prefix: cmd.prefix, items });
|
|
221253
221359
|
break;
|
|
221254
221360
|
}
|
|
221361
|
+
case "artifact": {
|
|
221362
|
+
await this.handleArtifact(client, cmd);
|
|
221363
|
+
break;
|
|
221364
|
+
}
|
|
221255
221365
|
case "mcp": {
|
|
221256
221366
|
this.handleMcp(client, cmd);
|
|
221257
221367
|
break;
|
|
@@ -221309,6 +221419,7 @@ var init_web_backend = __esm({
|
|
|
221309
221419
|
projectPath: s.projectPath || "",
|
|
221310
221420
|
preview: s.preview || "",
|
|
221311
221421
|
totalActiveMs: s.id === currentId ? sessionManager.getTotalActiveMs() : s.totalActiveMs ?? 0,
|
|
221422
|
+
contentHash: s.contentHash ?? "",
|
|
221312
221423
|
pendingPermission: s.pendingPermission || void 0
|
|
221313
221424
|
}))
|
|
221314
221425
|
});
|
|
@@ -221339,6 +221450,7 @@ var init_web_backend = __esm({
|
|
|
221339
221450
|
projectPath: s.projectPath || "",
|
|
221340
221451
|
preview: s.preview || "",
|
|
221341
221452
|
totalActiveMs: s.id === currentId ? sm.getTotalActiveMs() : s.totalActiveMs ?? 0,
|
|
221453
|
+
contentHash: s.contentHash ?? "",
|
|
221342
221454
|
pendingPermission: s.pendingPermission || void 0
|
|
221343
221455
|
}))
|
|
221344
221456
|
});
|
|
@@ -221446,7 +221558,8 @@ var init_web_backend = __esm({
|
|
|
221446
221558
|
modelId: s.modelId,
|
|
221447
221559
|
projectPath: s.projectPath || "",
|
|
221448
221560
|
preview: s.preview || "",
|
|
221449
|
-
totalActiveMs: s.totalActiveMs ?? 0
|
|
221561
|
+
totalActiveMs: s.totalActiveMs ?? 0,
|
|
221562
|
+
contentHash: s.contentHash ?? ""
|
|
221450
221563
|
}))
|
|
221451
221564
|
});
|
|
221452
221565
|
}
|
|
@@ -221480,7 +221593,8 @@ var init_web_backend = __esm({
|
|
|
221480
221593
|
modelId: s.modelId,
|
|
221481
221594
|
projectPath: s.projectPath || "",
|
|
221482
221595
|
preview: s.preview || "",
|
|
221483
|
-
totalActiveMs: s.totalActiveMs ?? 0
|
|
221596
|
+
totalActiveMs: s.totalActiveMs ?? 0,
|
|
221597
|
+
contentHash: s.contentHash ?? ""
|
|
221484
221598
|
}));
|
|
221485
221599
|
client.send({ type: "sessions", data });
|
|
221486
221600
|
break;
|
|
@@ -221506,7 +221620,8 @@ var init_web_backend = __esm({
|
|
|
221506
221620
|
modelId: s.modelId,
|
|
221507
221621
|
projectPath: s.projectPath || "",
|
|
221508
221622
|
preview: s.preview || "",
|
|
221509
|
-
totalActiveMs: s.totalActiveMs ?? 0
|
|
221623
|
+
totalActiveMs: s.totalActiveMs ?? 0,
|
|
221624
|
+
contentHash: s.contentHash ?? ""
|
|
221510
221625
|
}))
|
|
221511
221626
|
});
|
|
221512
221627
|
break;
|
|
@@ -221601,6 +221716,7 @@ ${matchList}` });
|
|
|
221601
221716
|
config: this.buildConfigData(),
|
|
221602
221717
|
messages
|
|
221603
221718
|
});
|
|
221719
|
+
this.broadcastContextWindow(true);
|
|
221604
221720
|
this.pushSessionList(client);
|
|
221605
221721
|
break;
|
|
221606
221722
|
}
|
|
@@ -221609,15 +221725,21 @@ ${matchList}` });
|
|
|
221609
221725
|
client.send({ type: "error", text: "Session ID required." });
|
|
221610
221726
|
return;
|
|
221611
221727
|
}
|
|
221728
|
+
const wasCurrent = sessionManager.getCurrentSessionId?.() === cmd.id;
|
|
221612
221729
|
const result = sessionManager.deleteSession(cmd.id);
|
|
221613
221730
|
if (!result.success) {
|
|
221614
221731
|
client.send({ type: "error", text: `Failed to delete session: ${result.error}` });
|
|
221615
221732
|
return;
|
|
221616
221733
|
}
|
|
221734
|
+
if (wasCurrent) {
|
|
221735
|
+
client.send({ type: "clear_conversation" });
|
|
221736
|
+
}
|
|
221617
221737
|
client.send({ type: "info", display: "toast", text: "Session deleted." });
|
|
221618
221738
|
const sessions = sessionManager.listSessions();
|
|
221739
|
+
const currentId = sessionManager.getCurrentSessionId?.() ?? void 0;
|
|
221619
221740
|
client.send({
|
|
221620
221741
|
type: "sessions",
|
|
221742
|
+
currentSessionId: currentId,
|
|
221621
221743
|
data: sessions.slice(0, 50).map((s) => ({
|
|
221622
221744
|
id: s.id,
|
|
221623
221745
|
title: s.title,
|
|
@@ -221628,7 +221750,8 @@ ${matchList}` });
|
|
|
221628
221750
|
modelId: s.modelId,
|
|
221629
221751
|
projectPath: s.projectPath || "",
|
|
221630
221752
|
preview: s.preview || "",
|
|
221631
|
-
totalActiveMs: s.totalActiveMs ?? 0
|
|
221753
|
+
totalActiveMs: s.totalActiveMs ?? 0,
|
|
221754
|
+
contentHash: s.contentHash ?? ""
|
|
221632
221755
|
}))
|
|
221633
221756
|
});
|
|
221634
221757
|
break;
|
|
@@ -221716,6 +221839,44 @@ ${matchList}` });
|
|
|
221716
221839
|
const vms = this.harness.sessionManager?.visionMessages ?? [];
|
|
221717
221840
|
return rebuildDisplayMessages(messages, vms);
|
|
221718
221841
|
}
|
|
221842
|
+
getSkillToolNames() {
|
|
221843
|
+
const names = /* @__PURE__ */ new Set();
|
|
221844
|
+
const sm = this.harness.skillManager;
|
|
221845
|
+
if (sm) {
|
|
221846
|
+
for (const name of sm.listAllSkillNames()) {
|
|
221847
|
+
names.add(name);
|
|
221848
|
+
}
|
|
221849
|
+
}
|
|
221850
|
+
return names;
|
|
221851
|
+
}
|
|
221852
|
+
broadcastContextWindow(bypassThrottle, toolsOverride) {
|
|
221853
|
+
const cm = this.harness.contextManager;
|
|
221854
|
+
const cw = cm.getContextWindow();
|
|
221855
|
+
if (cw <= 0) return;
|
|
221856
|
+
if (!bypassThrottle) {
|
|
221857
|
+
if (this.contextWindowThrottleTimer) {
|
|
221858
|
+
this.contextWindowThrottlePending = true;
|
|
221859
|
+
return;
|
|
221860
|
+
}
|
|
221861
|
+
this.contextWindowThrottleTimer = setTimeout(() => {
|
|
221862
|
+
this.contextWindowThrottleTimer = null;
|
|
221863
|
+
if (this.contextWindowThrottlePending) {
|
|
221864
|
+
this.contextWindowThrottlePending = false;
|
|
221865
|
+
this.broadcastContextWindow(true, toolsOverride);
|
|
221866
|
+
}
|
|
221867
|
+
}, 500);
|
|
221868
|
+
}
|
|
221869
|
+
const messages = this.harness.agent.state.messages;
|
|
221870
|
+
const tools = toolsOverride ?? this.currentAssistant?.tools ?? [];
|
|
221871
|
+
const breakdown = cm.getCategoryBreakdown(messages, tools, this.getSkillToolNames());
|
|
221872
|
+
this.broadcast({
|
|
221873
|
+
type: "context_window",
|
|
221874
|
+
total: breakdown.total,
|
|
221875
|
+
used: breakdown.used,
|
|
221876
|
+
free: breakdown.free,
|
|
221877
|
+
categories: breakdown.categories
|
|
221878
|
+
});
|
|
221879
|
+
}
|
|
221719
221880
|
broadcast(event) {
|
|
221720
221881
|
this.wsServer.broadcast(event);
|
|
221721
221882
|
}
|
|
@@ -221791,6 +221952,224 @@ ${matchList}` });
|
|
|
221791
221952
|
res.end("Not Found");
|
|
221792
221953
|
}
|
|
221793
221954
|
}
|
|
221955
|
+
async handleArtifact(client, cmd) {
|
|
221956
|
+
try {
|
|
221957
|
+
let styleConstraints = "";
|
|
221958
|
+
try {
|
|
221959
|
+
const skillPath = join28(this.config.projectPath, ".dscode", "html_output_skill");
|
|
221960
|
+
if (existsSync25(skillPath)) {
|
|
221961
|
+
styleConstraints = readFileSync23(skillPath, "utf-8");
|
|
221962
|
+
}
|
|
221963
|
+
} catch {
|
|
221964
|
+
}
|
|
221965
|
+
const designColors = `DESIGN SYSTEM COLORS (MUST use these exact hex values for EVERY color in your HTML):
|
|
221966
|
+
- Background: #f8f7f5
|
|
221967
|
+
- Surface: #f3f2ef
|
|
221968
|
+
- Border: #e6e4e0
|
|
221969
|
+
- Text: #2d2a26
|
|
221970
|
+
- Muted Text: #8a8580
|
|
221971
|
+
- Accent: #ca8a04 (warm amber/gold \u2014 use for highlights, progress bars, headings)
|
|
221972
|
+
- Success: #347539 text on #edf4ed background
|
|
221973
|
+
- Error: #9f2f2d text on #fdebec background
|
|
221974
|
+
- Warning: #956400 text on #fbf3db background
|
|
221975
|
+
- User Bubble: #ca8a04 background, #ffffff text`;
|
|
221976
|
+
const defaultStyleConstraints = `CRITICAL STYLE RULES:
|
|
221977
|
+
- Use the exact hex colors from DESIGN SYSTEM COLORS above \u2014 do NOT substitute with other greens, reds, or blues
|
|
221978
|
+
- Flat design: 1px solid var(--border) borders, no box-shadow, no gradients
|
|
221979
|
+
- Border-radius: 8px for cards/panels, 6px for buttons, 12px for large containers
|
|
221980
|
+
- Typography: system-ui, -apple-system, sans-serif for labels; monospace for data values
|
|
221981
|
+
- Emoji for visual markers, CSS conic-gradient or inline SVG for chart-like elements
|
|
221982
|
+
- Background MUST be #f8f7f5, never white (#fff) or transparent
|
|
221983
|
+
- Text MUST be #2d2a26, never pure black (#000) or cold gray
|
|
221984
|
+
- The accent color MUST be #ca8a04 (warm amber), never blue`;
|
|
221985
|
+
const systemPrompt = `You are an expert HTML dashboard designer. Generate a single, self-contained HTML file.
|
|
221986
|
+
|
|
221987
|
+
CRITICAL RULES:
|
|
221988
|
+
- Output ONLY valid HTML starting with <!DOCTYPE html>
|
|
221989
|
+
- All CSS MUST be inlined in <style> tags within <head>
|
|
221990
|
+
- NO external resources (fonts, images, scripts, CDN links)
|
|
221991
|
+
- Use system-ui, -apple-system, sans-serif for labels and monospace for data values
|
|
221992
|
+
- Use emoji icons for visual markers
|
|
221993
|
+
- Use CSS conic-gradient or inline SVG for chart-like elements
|
|
221994
|
+
- Make it visually rich and data-dense
|
|
221995
|
+
- Self-contained, single HTML document
|
|
221996
|
+
|
|
221997
|
+
${designColors}
|
|
221998
|
+
|
|
221999
|
+
${styleConstraints ? `ARTIFACT STYLE RULES (from .dscode/html_output_skill):
|
|
222000
|
+
${styleConstraints}
|
|
222001
|
+
` : defaultStyleConstraints}
|
|
222002
|
+
|
|
222003
|
+
Respond ONLY with the raw HTML starting with <!DOCTYPE html>. DO NOT wrap the output in markdown code fences (no \`\`\`html). DO NOT add any explanatory text before or after the HTML. Just output the HTML directly.`;
|
|
222004
|
+
let sessionSummary = "";
|
|
222005
|
+
if (cmd.context === "session_dashboard" || cmd.action === "generate") {
|
|
222006
|
+
sessionSummary = this.buildSessionSummary();
|
|
222007
|
+
}
|
|
222008
|
+
let userPrompt;
|
|
222009
|
+
if (cmd.action === "generate") {
|
|
222010
|
+
userPrompt = `Create a rich visual dashboard for this coding session. Use the data below to build a comprehensive, beautiful dashboard:
|
|
222011
|
+
|
|
222012
|
+
${sessionSummary}
|
|
222013
|
+
|
|
222014
|
+
Make it visually stunning with emojis, progress bars, color-coded metrics, and CSS charts.`;
|
|
222015
|
+
} else {
|
|
222016
|
+
const existingHtml = this.lastArtifactHtml || "";
|
|
222017
|
+
userPrompt = `Here is the current dashboard HTML:
|
|
222018
|
+
|
|
222019
|
+
${existingHtml.slice(0, 5e3)}
|
|
222020
|
+
|
|
222021
|
+
User instruction: ${cmd.instruction || "update the dashboard"}
|
|
222022
|
+
|
|
222023
|
+
Modify the HTML to fulfill the user's request. Output the complete modified HTML.`;
|
|
222024
|
+
}
|
|
222025
|
+
const model = resolveModel(this.config.provider, this.config.modelId);
|
|
222026
|
+
client.send({ type: "artifact_start" });
|
|
222027
|
+
let fullHtml = "";
|
|
222028
|
+
const stream = streamSimple3(model, {
|
|
222029
|
+
systemPrompt,
|
|
222030
|
+
messages: [{ role: "user", content: userPrompt, timestamp: Date.now() }]
|
|
222031
|
+
}, {
|
|
222032
|
+
apiKey: this.config.apiKey,
|
|
222033
|
+
maxTokens: this.config.maxTokens,
|
|
222034
|
+
timeoutMs: 12e4,
|
|
222035
|
+
maxRetries: 1
|
|
222036
|
+
});
|
|
222037
|
+
for await (const event of stream) {
|
|
222038
|
+
if (event.type === "text_delta") {
|
|
222039
|
+
fullHtml += event.delta;
|
|
222040
|
+
client.send({ type: "artifact_delta", delta: event.delta });
|
|
222041
|
+
} else if (event.type === "error") {
|
|
222042
|
+
client.send({ type: "error", text: `Artifact generation error: ${event.errorMessage || "Unknown error"}` });
|
|
222043
|
+
}
|
|
222044
|
+
}
|
|
222045
|
+
fullHtml = this.stripArtifactFences(fullHtml);
|
|
222046
|
+
this.lastArtifactHtml = fullHtml;
|
|
222047
|
+
client.send({ type: "artifact_end" });
|
|
222048
|
+
} catch (err) {
|
|
222049
|
+
client.send({ type: "artifact_end" });
|
|
222050
|
+
client.send({
|
|
222051
|
+
type: "error",
|
|
222052
|
+
text: `Artifact generation failed: ${err instanceof Error ? err.message : String(err)}`
|
|
222053
|
+
});
|
|
222054
|
+
}
|
|
222055
|
+
}
|
|
222056
|
+
stripArtifactFences(html) {
|
|
222057
|
+
let result = html.trim();
|
|
222058
|
+
const fencePattern = /^```(?:html)?\s*\n/;
|
|
222059
|
+
result = result.replace(fencePattern, "");
|
|
222060
|
+
const endFence = /\n```\s*$/;
|
|
222061
|
+
result = result.replace(endFence, "");
|
|
222062
|
+
if (!result.trimStart().startsWith("<")) {
|
|
222063
|
+
return html;
|
|
222064
|
+
}
|
|
222065
|
+
return result;
|
|
222066
|
+
}
|
|
222067
|
+
buildSessionSummary() {
|
|
222068
|
+
const sm = this.harness.sessionManager;
|
|
222069
|
+
const agent = this.harness.agent;
|
|
222070
|
+
const cm = this.harness.contextManager;
|
|
222071
|
+
const messages = agent.state.messages;
|
|
222072
|
+
const tools = this.currentAssistant?.tools ?? [];
|
|
222073
|
+
const breakdown = cm.getCategoryBreakdown(messages, tools, this.getSkillToolNames());
|
|
222074
|
+
const totalTokens = breakdown.total;
|
|
222075
|
+
const usedTokens = breakdown.used;
|
|
222076
|
+
const freeTokens = breakdown.free;
|
|
222077
|
+
const usagePercent = totalTokens > 0 ? Math.round(usedTokens / totalTokens * 100) : 0;
|
|
222078
|
+
const categories = breakdown.categories;
|
|
222079
|
+
const toolStats = /* @__PURE__ */ new Map();
|
|
222080
|
+
for (const msg of messages) {
|
|
222081
|
+
const m = msg;
|
|
222082
|
+
if (m.role === "assistant" && Array.isArray(m.content)) {
|
|
222083
|
+
for (const block of m.content) {
|
|
222084
|
+
if (block.type === "toolCall") {
|
|
222085
|
+
const name = block.name || "unknown";
|
|
222086
|
+
const existing = toolStats.get(name) || { calls: 0, errors: 0 };
|
|
222087
|
+
existing.calls++;
|
|
222088
|
+
toolStats.set(name, existing);
|
|
222089
|
+
}
|
|
222090
|
+
}
|
|
222091
|
+
}
|
|
222092
|
+
if (m.role === "toolResult" && m.isError) {
|
|
222093
|
+
const name = m.toolName || "unknown";
|
|
222094
|
+
const existing = toolStats.get(name);
|
|
222095
|
+
if (existing) {
|
|
222096
|
+
existing.errors++;
|
|
222097
|
+
} else {
|
|
222098
|
+
toolStats.set(name, { calls: 0, errors: 1 });
|
|
222099
|
+
}
|
|
222100
|
+
}
|
|
222101
|
+
}
|
|
222102
|
+
const toolEntries = Array.from(toolStats.entries()).map(([name, stats]) => ({
|
|
222103
|
+
name,
|
|
222104
|
+
callCount: stats.calls,
|
|
222105
|
+
errorCount: stats.errors,
|
|
222106
|
+
successCount: stats.calls - stats.errors,
|
|
222107
|
+
successRate: stats.calls > 0 ? Math.round((stats.calls - stats.errors) / stats.calls * 100) : 100
|
|
222108
|
+
})).sort((a, b) => b.callCount - a.callCount);
|
|
222109
|
+
const totalToolCalls = toolEntries.reduce((sum, t) => sum + t.callCount, 0);
|
|
222110
|
+
const totalToolErrors = toolEntries.reduce((sum, t) => sum + t.errorCount, 0);
|
|
222111
|
+
const sessionActiveMs = sm?.getTotalActiveMs?.() ?? 0;
|
|
222112
|
+
const turnCount = messages.filter((m) => m.role === "user").length;
|
|
222113
|
+
const avgTurnMs = turnCount > 0 ? Math.round(sessionActiveMs / turnCount) : 0;
|
|
222114
|
+
const pressureScore = totalTokens > 0 ? Math.round(usedTokens / totalTokens * 100) : 0;
|
|
222115
|
+
let pressureLabel = "low";
|
|
222116
|
+
if (pressureScore > 95) pressureLabel = "critical";
|
|
222117
|
+
else if (pressureScore > 80) pressureLabel = "high";
|
|
222118
|
+
else if (pressureScore > 50) pressureLabel = "moderate";
|
|
222119
|
+
const topTools = toolEntries.slice(0, 3).map((t) => ({
|
|
222120
|
+
name: t.name,
|
|
222121
|
+
successRate: t.successRate,
|
|
222122
|
+
warning: t.errorCount > 0 && t.errorCount / t.callCount > 0.2 ? "\u26A0\uFE0F" : ""
|
|
222123
|
+
}));
|
|
222124
|
+
function formatMs(ms) {
|
|
222125
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
222126
|
+
const sec = Math.floor(ms / 1e3);
|
|
222127
|
+
if (sec < 60) return `${sec}s`;
|
|
222128
|
+
const min = Math.floor(sec / 60);
|
|
222129
|
+
const remainSec = sec % 60;
|
|
222130
|
+
if (min < 60) return `${min}m ${remainSec}s`;
|
|
222131
|
+
const hrs = Math.floor(min / 60);
|
|
222132
|
+
const remainMin = min % 60;
|
|
222133
|
+
return `${hrs}h ${remainMin}m`;
|
|
222134
|
+
}
|
|
222135
|
+
return JSON.stringify({
|
|
222136
|
+
tokenUsage: {
|
|
222137
|
+
total: totalTokens,
|
|
222138
|
+
used: usedTokens,
|
|
222139
|
+
free: freeTokens,
|
|
222140
|
+
usagePercent,
|
|
222141
|
+
categories: {
|
|
222142
|
+
system: categories.system ?? null,
|
|
222143
|
+
rules: categories.rules ?? null,
|
|
222144
|
+
user: categories.user ?? null,
|
|
222145
|
+
thinking: categories.thinking ?? null,
|
|
222146
|
+
readwrite: categories.readwrite ?? null,
|
|
222147
|
+
edit: categories.edit ?? null,
|
|
222148
|
+
shell: categories.shell ?? null,
|
|
222149
|
+
skill: categories.skill ?? null,
|
|
222150
|
+
mcp: categories.mcp ?? null,
|
|
222151
|
+
other: categories.other ?? null
|
|
222152
|
+
}
|
|
222153
|
+
},
|
|
222154
|
+
toolStatistics: {
|
|
222155
|
+
tools: toolEntries,
|
|
222156
|
+
totalToolsCalled: totalToolCalls,
|
|
222157
|
+
totalErrors: totalToolErrors
|
|
222158
|
+
},
|
|
222159
|
+
timing: {
|
|
222160
|
+
sessionActiveMs,
|
|
222161
|
+
sessionActiveFormatted: formatMs(sessionActiveMs),
|
|
222162
|
+
turnCount,
|
|
222163
|
+
avgTurnMs,
|
|
222164
|
+
avgTurnFormatted: formatMs(avgTurnMs)
|
|
222165
|
+
},
|
|
222166
|
+
contextHealth: {
|
|
222167
|
+
pressureScore,
|
|
222168
|
+
pressureLabel
|
|
222169
|
+
},
|
|
222170
|
+
topTools
|
|
222171
|
+
}, null, 2);
|
|
222172
|
+
}
|
|
221794
222173
|
};
|
|
221795
222174
|
}
|
|
221796
222175
|
});
|
|
@@ -222033,6 +222412,7 @@ var SessionStore = class {
|
|
|
222033
222412
|
|
|
222034
222413
|
// src/session/manager.ts
|
|
222035
222414
|
import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync2 } from "node:fs";
|
|
222415
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
222036
222416
|
import { join as join5 } from "node:path";
|
|
222037
222417
|
function ulid() {
|
|
222038
222418
|
const t = Date.now().toString(36).padStart(10, "0");
|
|
@@ -222126,6 +222506,7 @@ var SessionManager = class {
|
|
|
222126
222506
|
preview: "",
|
|
222127
222507
|
hasImages: false,
|
|
222128
222508
|
imageCount: 0,
|
|
222509
|
+
contentHash: "",
|
|
222129
222510
|
totalActiveMs: 0
|
|
222130
222511
|
};
|
|
222131
222512
|
this.accumulatedMs = 0;
|
|
@@ -222182,6 +222563,8 @@ var SessionManager = class {
|
|
|
222182
222563
|
if (!this.current.preview) {
|
|
222183
222564
|
this.current.preview = extractFirstUserMessage(messages);
|
|
222184
222565
|
}
|
|
222566
|
+
const contentHash2 = createHash3("sha256").update(messages.map((m) => `${m.role}:${String(m.content ?? "").slice(0, 200)}`).join("|")).digest("hex").slice(0, 12);
|
|
222567
|
+
this.current.contentHash = contentHash2;
|
|
222185
222568
|
this.current.projectPath = this.projectPath;
|
|
222186
222569
|
let totalImages = 0;
|
|
222187
222570
|
let hasImages = false;
|
|
@@ -222253,6 +222636,7 @@ var SessionManager = class {
|
|
|
222253
222636
|
deleteSession(id) {
|
|
222254
222637
|
try {
|
|
222255
222638
|
this.store.delete(id);
|
|
222639
|
+
if (id === this.current?.id) this.current = null;
|
|
222256
222640
|
this.events?.emit({ type: "session:deleted", id });
|
|
222257
222641
|
return { success: true };
|
|
222258
222642
|
} catch (err) {
|
|
@@ -222402,6 +222786,99 @@ var ContextManager = class {
|
|
|
222402
222786
|
const reservedTools = 3e3;
|
|
222403
222787
|
return this.contextWindow - this.maxTokens - reservedSystem - reservedTools;
|
|
222404
222788
|
}
|
|
222789
|
+
getContextWindow() {
|
|
222790
|
+
return this.contextWindow;
|
|
222791
|
+
}
|
|
222792
|
+
classifyToolCategory(toolName, skillNames) {
|
|
222793
|
+
if (toolName.startsWith("mcp__")) return "mcp";
|
|
222794
|
+
if (skillNames?.has(toolName)) return "skill";
|
|
222795
|
+
if (toolName === "read_file" || toolName === "list_files" || toolName === "grep" || toolName === "glob" || toolName === "write_file" || toolName === "overwrite_file")
|
|
222796
|
+
return "readwrite";
|
|
222797
|
+
if (toolName === "edit" || toolName === "edit_undo") return "edit";
|
|
222798
|
+
if (toolName === "bash") return "shell";
|
|
222799
|
+
return "other";
|
|
222800
|
+
}
|
|
222801
|
+
getCategoryBreakdown(messages, tools, skillNames) {
|
|
222802
|
+
const categories = {
|
|
222803
|
+
system: 0,
|
|
222804
|
+
rules: 0,
|
|
222805
|
+
user: 0,
|
|
222806
|
+
thinking: 0,
|
|
222807
|
+
readwrite: 0,
|
|
222808
|
+
edit: 0,
|
|
222809
|
+
shell: 0,
|
|
222810
|
+
skill: 0,
|
|
222811
|
+
mcp: 0,
|
|
222812
|
+
other: 0
|
|
222813
|
+
};
|
|
222814
|
+
let systemMsgIndex = 0;
|
|
222815
|
+
for (const msg of messages) {
|
|
222816
|
+
const m = msg;
|
|
222817
|
+
const role = m?.role;
|
|
222818
|
+
const content = m?.content;
|
|
222819
|
+
if (role === "system") {
|
|
222820
|
+
systemMsgIndex++;
|
|
222821
|
+
const target = systemMsgIndex === 1 ? "system" : "rules";
|
|
222822
|
+
if (typeof content === "string") {
|
|
222823
|
+
categories[target] += estimateTokens(content);
|
|
222824
|
+
categories[target] += 4;
|
|
222825
|
+
} else if (Array.isArray(content)) {
|
|
222826
|
+
for (const block of content) {
|
|
222827
|
+
if (block?.type === "text" && typeof block.text === "string") {
|
|
222828
|
+
categories[target] += estimateTokens(block.text);
|
|
222829
|
+
}
|
|
222830
|
+
}
|
|
222831
|
+
categories[target] += 4;
|
|
222832
|
+
}
|
|
222833
|
+
} else if (role === "user") {
|
|
222834
|
+
if (typeof content === "string") {
|
|
222835
|
+
categories.user += estimateTokens(content);
|
|
222836
|
+
} else if (Array.isArray(content)) {
|
|
222837
|
+
for (const block of content) {
|
|
222838
|
+
if (block?.type === "text" && typeof block.text === "string") {
|
|
222839
|
+
categories.user += estimateTokens(block.text);
|
|
222840
|
+
}
|
|
222841
|
+
}
|
|
222842
|
+
}
|
|
222843
|
+
categories.user += 4;
|
|
222844
|
+
} else if (role === "assistant") {
|
|
222845
|
+
if (typeof content === "string") {
|
|
222846
|
+
categories.thinking += estimateTokens(content);
|
|
222847
|
+
} else if (Array.isArray(content)) {
|
|
222848
|
+
for (const block of content) {
|
|
222849
|
+
if (block?.type === "text" && typeof block.text === "string") {
|
|
222850
|
+
categories.thinking += estimateTokens(block.text);
|
|
222851
|
+
} else if (block?.type === "thinking" && typeof block.thinking === "string") {
|
|
222852
|
+
categories.thinking += estimateTokens(block.thinking);
|
|
222853
|
+
}
|
|
222854
|
+
}
|
|
222855
|
+
}
|
|
222856
|
+
categories.thinking += 4;
|
|
222857
|
+
} else if (role === "toolResult") {
|
|
222858
|
+
const toolName = m?.toolName ?? "";
|
|
222859
|
+
const cat = this.classifyToolCategory(toolName, skillNames);
|
|
222860
|
+
if (Array.isArray(content)) {
|
|
222861
|
+
for (const block of content) {
|
|
222862
|
+
if (block?.type === "text" && typeof block.text === "string") {
|
|
222863
|
+
categories[cat] += estimateTokens(block.text);
|
|
222864
|
+
}
|
|
222865
|
+
}
|
|
222866
|
+
} else if (typeof content === "string") {
|
|
222867
|
+
categories[cat] += estimateTokens(content);
|
|
222868
|
+
}
|
|
222869
|
+
categories[cat] += 20;
|
|
222870
|
+
}
|
|
222871
|
+
}
|
|
222872
|
+
for (const tool of tools) {
|
|
222873
|
+
const cat = this.classifyToolCategory(tool.name, skillNames);
|
|
222874
|
+
const resultTokens = typeof tool.result === "string" ? estimateTokens(tool.result) : 0;
|
|
222875
|
+
categories[cat] += resultTokens + 20;
|
|
222876
|
+
}
|
|
222877
|
+
const used = Object.values(categories).reduce((a, b) => a + b, 0);
|
|
222878
|
+
const total = this.contextWindow;
|
|
222879
|
+
const free = Math.max(0, total - used);
|
|
222880
|
+
return { total, used, free, categories };
|
|
222881
|
+
}
|
|
222405
222882
|
getEstimatedTokens(messages) {
|
|
222406
222883
|
return estimateMessagesTokens(messages);
|
|
222407
222884
|
}
|
|
@@ -222409,14 +222886,14 @@ var ContextManager = class {
|
|
|
222409
222886
|
|
|
222410
222887
|
// src/memory/store.ts
|
|
222411
222888
|
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
222412
|
-
import { createHash as
|
|
222889
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
222413
222890
|
import { join as join6 } from "node:path";
|
|
222414
222891
|
var MemoryStore = class {
|
|
222415
222892
|
dataDir;
|
|
222416
222893
|
projectHash;
|
|
222417
222894
|
constructor(dataDir, projectPath) {
|
|
222418
222895
|
this.dataDir = join6(dataDir, "memory");
|
|
222419
|
-
this.projectHash =
|
|
222896
|
+
this.projectHash = createHash4("sha256").update(projectPath).digest("hex").slice(0, 12);
|
|
222420
222897
|
if (!existsSync6(this.dataDir)) {
|
|
222421
222898
|
mkdirSync5(this.dataDir, { recursive: true });
|
|
222422
222899
|
}
|
|
@@ -222531,16 +223008,16 @@ import { join as join9, resolve as resolve2, dirname as dirname2 } from "node:pa
|
|
|
222531
223008
|
import { Type as Type2 } from "@mariozechner/pi-ai";
|
|
222532
223009
|
|
|
222533
223010
|
// src/drivers/edit/hash.ts
|
|
222534
|
-
import { createHash as
|
|
223011
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
222535
223012
|
import { Type } from "@mariozechner/pi-ai";
|
|
222536
223013
|
function computeLineHash(line) {
|
|
222537
|
-
return
|
|
223014
|
+
return createHash5("md5").update(line.trim()).digest("hex").slice(0, 6);
|
|
222538
223015
|
}
|
|
222539
223016
|
function computeResolutionHash(line) {
|
|
222540
|
-
return
|
|
223017
|
+
return createHash5("md5").update(line.trim()).digest("hex").slice(0, 8);
|
|
222541
223018
|
}
|
|
222542
223019
|
function computeFileVersion(content) {
|
|
222543
|
-
return "fv_" +
|
|
223020
|
+
return "fv_" + createHash5("sha256").update(content).digest("hex").slice(0, 8);
|
|
222544
223021
|
}
|
|
222545
223022
|
function hashLines(lines) {
|
|
222546
223023
|
const resolutionMap = /* @__PURE__ */ new Map();
|
|
@@ -222593,7 +223070,7 @@ function computeContextHash(lines, lineIdx) {
|
|
|
222593
223070
|
const prev = findNonEmptyBefore(lines, lineIdx);
|
|
222594
223071
|
const curr = lines[lineIdx].trim();
|
|
222595
223072
|
const next = findNonEmptyAfter(lines, lineIdx);
|
|
222596
|
-
return
|
|
223073
|
+
return createHash5("md5").update(`${prev}
|
|
222597
223074
|
${curr}
|
|
222598
223075
|
${next}`).digest("hex").slice(0, 8);
|
|
222599
223076
|
}
|
|
@@ -223192,7 +223669,7 @@ function generateLocalDiff(oldLines, newLines, ops, ctx) {
|
|
|
223192
223669
|
// src/checkpoint/index.ts
|
|
223193
223670
|
import { homedir as homedir4 } from "node:os";
|
|
223194
223671
|
import { join as join8 } from "node:path";
|
|
223195
|
-
import { createHash as
|
|
223672
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
223196
223673
|
|
|
223197
223674
|
// src/checkpoint/checkpoint-manager.ts
|
|
223198
223675
|
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2 } from "node:fs";
|
|
@@ -223498,7 +223975,7 @@ var _snapshotStore = null;
|
|
|
223498
223975
|
var _checkpointManager = null;
|
|
223499
223976
|
var _fileWriteTracker = null;
|
|
223500
223977
|
function initCheckpointSystem(projectPath, sessionId) {
|
|
223501
|
-
const projectHash =
|
|
223978
|
+
const projectHash = createHash6("sha256").update(projectPath).digest("hex").slice(0, 12);
|
|
223502
223979
|
const baseDir = join8(homedir4(), ".dscode", "checkpoints", "per-project", projectHash, sessionId);
|
|
223503
223980
|
_snapshotStore = new SnapshotStore();
|
|
223504
223981
|
const store = new FileSystemCheckpointStore(baseDir);
|
|
@@ -224101,7 +224578,7 @@ import { resolve as resolve4 } from "node:path";
|
|
|
224101
224578
|
import { Type as Type5 } from "@mariozechner/pi-ai";
|
|
224102
224579
|
|
|
224103
224580
|
// src/drivers/edit/recovery.ts
|
|
224104
|
-
import { createHash as
|
|
224581
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
224105
224582
|
function recoverBySnapshot(snapshotLines, currentLines, operations, snapshotCtx) {
|
|
224106
224583
|
let expectedLines;
|
|
224107
224584
|
try {
|
|
@@ -224281,7 +224758,7 @@ function computeContextHash2(lines, lineIdx) {
|
|
|
224281
224758
|
const prev = findNonEmptyBefore2(lines, lineIdx);
|
|
224282
224759
|
const curr = lines[lineIdx].trim();
|
|
224283
224760
|
const next = findNonEmptyAfter2(lines, lineIdx);
|
|
224284
|
-
return
|
|
224761
|
+
return createHash7("md5").update(`${prev}
|
|
224285
224762
|
${curr}
|
|
224286
224763
|
${next}`).digest("hex").slice(0, 8);
|
|
224287
224764
|
}
|
|
@@ -228200,6 +228677,7 @@ var ConversationView = class {
|
|
|
228200
228677
|
this.thinkingBuffer = "";
|
|
228201
228678
|
this.toolEntries = [];
|
|
228202
228679
|
this.renderedToolCount = 0;
|
|
228680
|
+
this.tui.requestRender(true);
|
|
228203
228681
|
}
|
|
228204
228682
|
thinkingDelta(delta) {
|
|
228205
228683
|
this.thinkingBuffer += delta;
|
|
@@ -228551,7 +229029,7 @@ var ConversationView = class {
|
|
|
228551
229029
|
this.box.addChild(permText);
|
|
228552
229030
|
this.liveComponents.push(permText);
|
|
228553
229031
|
}
|
|
228554
|
-
this.tui.requestRender(
|
|
229032
|
+
this.tui.requestRender(false);
|
|
228555
229033
|
}
|
|
228556
229034
|
};
|
|
228557
229035
|
|
|
@@ -228749,6 +229227,23 @@ var HybridAutocompleteProvider = class {
|
|
|
228749
229227
|
return true;
|
|
228750
229228
|
}
|
|
228751
229229
|
};
|
|
229230
|
+
function formatTokens(n) {
|
|
229231
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
229232
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
|
|
229233
|
+
return String(n);
|
|
229234
|
+
}
|
|
229235
|
+
function formatContextPercent(estimated, contextWindow) {
|
|
229236
|
+
if (contextWindow <= 0 || !isFinite(estimated) || Number.isNaN(estimated)) return null;
|
|
229237
|
+
const pct = Math.round(estimated / contextWindow * 100);
|
|
229238
|
+
const text = `\u2593\u2593 ${pct}%`;
|
|
229239
|
+
if (pct > 95) return c.red(text);
|
|
229240
|
+
if (pct > 80) return c.yellow(text);
|
|
229241
|
+
return c.dim(text);
|
|
229242
|
+
}
|
|
229243
|
+
function formatCost(total) {
|
|
229244
|
+
if (total >= 0.01) return `$${total.toFixed(4)}`;
|
|
229245
|
+
return `\xA2${(total * 100).toFixed(2)}`;
|
|
229246
|
+
}
|
|
228752
229247
|
var TuiApp = class {
|
|
228753
229248
|
deps;
|
|
228754
229249
|
terminal;
|
|
@@ -229418,13 +229913,27 @@ var TuiApp = class {
|
|
|
229418
229913
|
this.markActivity();
|
|
229419
229914
|
this.conversation.toolEnd(name, result, isError);
|
|
229420
229915
|
}
|
|
229421
|
-
finishAssistantMessage() {
|
|
229916
|
+
finishAssistantMessage(usage) {
|
|
229422
229917
|
this.finalizeIdleSegment();
|
|
229423
229918
|
this.conversation.finishAssistantMessage();
|
|
229919
|
+
const parts = [];
|
|
229424
229920
|
if (this.totalWaitMs >= 1e3) {
|
|
229425
|
-
this.
|
|
229426
|
-
|
|
229427
|
-
|
|
229921
|
+
parts.push(`\u23F1 ${this.formatElapsed(this.totalWaitMs)}`);
|
|
229922
|
+
}
|
|
229923
|
+
if (usage && usage.input > 0 && usage.output > 0) {
|
|
229924
|
+
parts.push(`\u{1F4CA} ${formatTokens(usage.input)}\u2193 ${formatTokens(usage.output)}\u2191`);
|
|
229925
|
+
}
|
|
229926
|
+
{
|
|
229927
|
+
const estimatedTokens = this.deps.contextManager.getEstimatedTokens(this.deps.agent.state.messages);
|
|
229928
|
+
const contextWindow = this.deps.contextManager.getContextWindow();
|
|
229929
|
+
const ctxStr = formatContextPercent(estimatedTokens, contextWindow);
|
|
229930
|
+
if (ctxStr) parts.push(ctxStr);
|
|
229931
|
+
}
|
|
229932
|
+
if (usage && usage.cost.total > 0) {
|
|
229933
|
+
parts.push(`\u{1F4B0} ${formatCost(usage.cost.total)}`);
|
|
229934
|
+
}
|
|
229935
|
+
if (parts.length > 0) {
|
|
229936
|
+
this.conversation.addInfo(c.dim(parts.join(" \xB7 ")));
|
|
229428
229937
|
}
|
|
229429
229938
|
}
|
|
229430
229939
|
addInfo(text, _display) {
|
|
@@ -229708,8 +230217,8 @@ var TuiBackend = class {
|
|
|
229708
230217
|
deps.events.on("turn:streaming:start", () => {
|
|
229709
230218
|
this.tui.startAssistantMessage();
|
|
229710
230219
|
});
|
|
229711
|
-
deps.events.on("turn:end", () => {
|
|
229712
|
-
this.tui.finishAssistantMessage();
|
|
230220
|
+
deps.events.on("turn:end", (e) => {
|
|
230221
|
+
this.tui.finishAssistantMessage(e.usage);
|
|
229713
230222
|
});
|
|
229714
230223
|
deps.events.on("message:user", (e) => {
|
|
229715
230224
|
this.tui.addUserMessage(e.text);
|
|
@@ -230957,7 +231466,8 @@ You have a \`skill\` tool available. When you decide to use a skill from the lis
|
|
|
230957
231466
|
if (event.type === "turn_end") {
|
|
230958
231467
|
this.sessionManager.trySaveSession(this.agent);
|
|
230959
231468
|
const turnEndMsg = event.message;
|
|
230960
|
-
|
|
231469
|
+
const rawUsage = turnEndMsg?.usage;
|
|
231470
|
+
this.events.emit({ type: "turn:end", stopReason: turnEndMsg?.stopReason, usage: rawUsage ? { input: rawUsage.input, output: rawUsage.output, cacheRead: rawUsage.cacheRead, cacheWrite: rawUsage.cacheWrite, total: rawUsage.totalTokens, cost: { total: rawUsage.cost.total } } : void 0 });
|
|
230961
231471
|
const msg = turnEndMsg;
|
|
230962
231472
|
if (msg?.stopReason === "length") {
|
|
230963
231473
|
this.events.emit({ type: "ui:info", text: "Output truncated (hit max_tokens). Continue from where you left off." });
|