scream-code 0.12.7 → 0.12.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{app-DoxADJlo.mjs → app-CyJPMDaK.mjs} +294 -157
- package/dist/main.mjs +1 -1
- package/package.json +1 -1
|
@@ -76465,10 +76465,10 @@ function stripContextMetadata(message) {
|
|
|
76465
76465
|
}
|
|
76466
76466
|
//#endregion
|
|
76467
76467
|
//#region ../../packages/agent-core/src/agent/compaction/compaction-instruction.md
|
|
76468
|
-
var compaction_instruction_default = "\n--- This message is a direct task, not part of the above conversation ---\n\nYou are now given a task to compact this conversation context according to specific priorities and output requirements.\n\nOutput text only. DO NOT CALL ANY TOOLS. Calling tools will be rejected and fails the task. You already have all the information you need in the conversation history. You have only one chance.\n\nThe goal of compaction is to keep essential code patterns, technical details, and architectural decisions for continuing development without losing context after the above messages are cleared work.\n\n{{ customInstruction }}\n\n<!-- Memory Memo Extraction (PRIORITY — do not skip) -->\n\n## 任务经验提取\n\nAFTER completing the compaction summary below, scan the messages being compacted for **
|
|
76468
|
+
var compaction_instruction_default = "\n--- This message is a direct task, not part of the above conversation ---\n\nYou are now given a task to compact this conversation context according to specific priorities and output requirements.\n\nOutput text only. DO NOT CALL ANY TOOLS. Calling tools will be rejected and fails the task. You already have all the information you need in the conversation history. You have only one chance.\n\nThe goal of compaction is to keep essential code patterns, technical details, and architectural decisions for continuing development without losing context after the above messages are cleared work.\n\n{{ customInstruction }}\n\n<!-- Memory Memo Extraction (PRIORITY — do not skip) -->\n\n## 任务经验提取\n\nAFTER completing the compaction summary below, scan the messages being compacted for **task loops**. A task loop is \"completed\" when:\n- The user made a clear request or asked a specific question\n- You provided a solution or answer\n- The outcome is clear (success, partial success, or failure)\n\n**You MUST output at least one memory-memo block** (or the `{\"none\": true}` marker) at the very end of your response — omitting the section entirely is not allowed. Record completed task loops as full experience records; record **in-progress work** as a lower-priority record whose \"outcome\" is \"进行中\" (so the ongoing task survives compaction and can be resumed later).\n\nFor each task loop found, output a structured experience record **at the very end of your response**:\n\n```memory-memo\n{\n \"userNeed\": \"<the user's need or goal, one sentence>\",\n \"approach\": \"<what was done — the approach taken, 2-4 sentences>\",\n \"outcome\": \"<final result, e.g. '完成', '部分完成', '失败: reason', or '进行中' for in-progress work>\",\n \"whatFailed\": \"<dead ends tried — things that didn't work, or 'none'>\",\n \"whatWorked\": \"<key actions that ultimately worked, or 'none'>\",\n \"tags\": [\"<tag1>\", \"<tag2>\", \"<tag3>\"],\n \"note\": \"<optional: a soft, AI-readable note/suggestion that makes the record easier for future turns to understand — e.g. '这类任务先查接口可用性再写代码'. Omit if none>\"\n}\n```\n\nGuidelines:\n- Record important failed attempts in \"whatFailed\" to help avoid repeating mistakes.\n- Record key successful actions in \"whatWorked\" to help reuse effective approaches.\n- Include 3-5 semantic \"tags\" summarizing the task domain, tech stack, or action type (e.g. [\"react\", \"auth\", \"部署\"]).\n- \"note\" is optional: a one-sentence advisory note that helps future AI understand/reuse the record faster. It is a soft suggestion, not a user-enforced rule.\n- For in-progress work: record it with \"outcome\": \"进行中\" and describe where the task stands and what remains — this is what lets the agent resume seamlessly after compaction.\n- Merge closely related sub-tasks into a single record.\n- Use the exact field names and JSON format shown above (no extra fields beyond \"note\").\n\nIf no task loops (completed or in-progress) are found in the compacted messages, output:\n```memory-memo\n{\"none\": true}\n```\n\n<!-- Compression Priorities (in order) -->\n\n1. **Current Task State**: What is being worked on RIGHT NOW\n2. **Errors & Solutions**: All encountered errors and their resolutions\n3. **Code Evolution**: Final working versions only (remove intermediate attempts)\n4. **System Context**: Project structure, dependencies, environment setup\n5. **Design Decisions**: Architectural choices and their rationale\n6. **Next Steps**: The ordered, actionable plan going forward\n7. **TODO Items**: Unfinished tasks and known issues\n\n<!-- Required Output Structure -->\n\n## Current Focus\n\n[What we're working on now]\n\n## Environment\n\n- [Key setup/config points]\n- ...\n\n## Completed Tasks\n\n- [Task]: [Brief outcome]\n- ...\n\n## Active Issues\n\n- [Issue]: [Status/Next steps]\n- ...\n\n## Key Decisions\n\n- [Decision]: [rationale] — preserve architectural choices and why they were made\n- ...\n\n## Next Steps\n\n1. [The very next actionable step]\n2. [Then this]\n3. ...\n\n## Code State\n\n### [Critical file name]\n\n[Brief description of the file's purpose and current state]\n\n```\n[The latest version of critical code snippets in this file, <20 lines]\n```\n\n### [Critical file name]\n\n- [Useful classes/methods/functions]: [Brief description/usage]\n- ...\n\n<!-- Omit non-critical code, intermediate attempts, and resolved errors -->\n\n## Important Context\n\n- [Any crucial information not covered above]\n- ...\n\n## All User Messages\n\n- [Detailed non tool use user message]\n- ...\n\n## Skill candidates\n\nScan the compressed messages for reusable processes (project-specific build\nsteps, recurring debugging patterns, or tool workflows). If any is genuinely\nworth capturing as a reusable skill, output at the very end, at most one:\n\n[[skill-candidate: <name>|<one-line purpose>|<evidence>]]\n\n- The evidence must be concrete and verifiable: exact file paths, commands, or\n step sequences from the conversation (e.g. \"run `pnpm vitest run -t compaction`\n in packages/agent-core to reproduce the compaction snapshots\"). Vague evidence\n like \"used a script\" is not acceptable.\n- Only emit a candidate when the process is genuinely reusable beyond this one\n task; do not emit for one-off actions.\n\nOmit if none.\n";
|
|
76469
76469
|
//#endregion
|
|
76470
76470
|
//#region ../../packages/agent-core/src/agent/compaction/compaction-update-instruction.md
|
|
76471
|
-
var compaction_update_instruction_default = "\n--- This message is a direct task, not part of the above conversation ---\n\nYou are now given a task to UPDATE an existing compaction summary with new messages that came in after the last compaction.\n\nA previous compaction summary already exists at the top of the conversation (the first assistant message). You must NOT discard it. Instead, merge the new information into the existing structure, keeping all previously captured state intact unless explicitly contradicted or resolved by the new messages.\n\nOutput text only. DO NOT CALL ANY TOOLS. Calling tools will be rejected and fails the task. You have only one chance.\n\n{{ customInstruction }}\n\n<!-- Previous Summary Reference -->\n\nThe first assistant message above is the PREVIOUS summary. Treat it as the source of truth for everything that happened before the new messages. Do not restate it verbatim — produce an updated, merged summary.\n\n<!-- Memory Memo Extraction (PRIORITY — do not skip) -->\n\n## 任务经验提取\n\nAFTER completing the updated summary below, scan ONLY the new messages being compacted (not those already covered by the previous summary) for **
|
|
76471
|
+
var compaction_update_instruction_default = "\n--- This message is a direct task, not part of the above conversation ---\n\nYou are now given a task to UPDATE an existing compaction summary with new messages that came in after the last compaction.\n\nA previous compaction summary already exists at the top of the conversation (the first assistant message). You must NOT discard it. Instead, merge the new information into the existing structure, keeping all previously captured state intact unless explicitly contradicted or resolved by the new messages.\n\nOutput text only. DO NOT CALL ANY TOOLS. Calling tools will be rejected and fails the task. You have only one chance.\n\n{{ customInstruction }}\n\n<!-- Previous Summary Reference -->\n\nThe first assistant message above is the PREVIOUS summary. Treat it as the source of truth for everything that happened before the new messages. Do not restate it verbatim — produce an updated, merged summary.\n\n<!-- Memory Memo Extraction (PRIORITY — do not skip) -->\n\n## 任务经验提取\n\nAFTER completing the updated summary below, scan ONLY the new messages being compacted (not those already covered by the previous summary) for **task loops**. A task loop is \"completed\" when:\n- The user made a clear request or asked a specific question\n- You provided a solution or answer\n- The outcome is clear (success, partial success, or failure)\n\n**You MUST output at least one memory-memo block** (or the `{\"none\": true}` marker) at the very end of your response — omitting the section entirely is not allowed. Record completed task loops as full experience records; record **in-progress work** as a lower-priority record whose \"outcome\" is \"进行中\" (so the ongoing task survives compaction and can be resumed later).\n\nFor each task loop found, output a structured experience record **at the very end of your response**:\n\n```memory-memo\n{\n \"userNeed\": \"<the user's need or goal, one sentence>\",\n \"approach\": \"<what was done — the approach taken, 2-4 sentences>\",\n \"outcome\": \"<final result, e.g. '完成', '部分完成', '失败: reason', or '进行中' for in-progress work>\",\n \"whatFailed\": \"<dead ends tried — things that didn't work, or 'none'>\",\n \"whatWorked\": \"<key actions that ultimately worked, or 'none'>\",\n \"tags\": [\"<tag1>\", \"<tag2>\", \"<tag3>\"],\n \"note\": \"<optional: a soft, AI-readable note/suggestion that makes the record easier for future turns to understand — e.g. '这类任务先查接口可用性再写代码'. Omit if none>\"\n}\n```\n\nGuidelines:\n- Record important failed attempts in \"whatFailed\" to help avoid repeating mistakes.\n- Record key successful actions in \"whatWorked\" to help reuse effective approaches.\n- Include 3-5 semantic \"tags\" summarizing the task domain, tech stack, or action type.\n- For in-progress work: record it with \"outcome\": \"进行中\" and describe where the task stands and what remains — this is what lets the agent resume seamlessly after compaction.\n- Merge closely related sub-tasks into a single record.\n- Use the exact field names and JSON format shown above.\n\nIf no task loops (completed or in-progress) are found in the new compacted messages, output:\n```memory-memo\n{\"none\": true}\n```\n\n<!-- Update Rules -->\n\n1. Preserve the section structure of the previous summary (Current Focus, Environment, Completed Tasks, Active Issues, Key Decisions, Next Steps, Code State, Important Context, All User Messages).\n2. Move newly-completed tasks from \"Current Focus\" / \"Active Issues\" into \"Completed Tasks\".\n3. Update \"Current Focus\" to reflect what is being worked on RIGHT NOW.\n4. Append new user messages to \"All User Messages\" — do not repeat those already captured.\n5. Refresh \"Code State\" code snippets only if newer versions exist in the new messages.\n6. Drop resolved issues from \"Active Issues\"; add newly-discovered ones.\n7. Merge new decisions into \"Key Decisions\" (keep prior decisions unless explicitly overturned); merge new steps into \"Next Steps\" (reorder if priorities changed).\n8. Do not invent new information. If the new messages say nothing about a section, carry the previous content forward unchanged.\n\n<!-- Required Output Structure -->\n\n## Current Focus\n\n[What we're working on now]\n\n## Environment\n\n- [Key setup/config points]\n- ...\n\n## Completed Tasks\n\n- [Task]: [Brief outcome]\n- ...\n\n## Active Issues\n\n- [Issue]: [Status/Next steps]\n- ...\n\n## Key Decisions\n\n- [Decision]: [rationale] — preserve architectural choices and why they were made\n- ...\n\n## Next Steps\n\n1. [The very next actionable step]\n2. [Then this]\n3. ...\n\n## Code State\n\n### [Critical file name]\n\n[Brief description of the file's purpose and current state]\n\n```\n[The latest version of critical code snippets in this file, <20 lines]\n```\n\n## Important Context\n\n- [Any crucial information not covered above]\n- ...\n\n## All User Messages\n\n- [Detailed non tool use user message]\n- ...\n";
|
|
76472
76472
|
//#endregion
|
|
76473
76473
|
//#region ../../packages/agent-core/src/agent/compaction/render-messages.ts
|
|
76474
76474
|
const TOOL_RESULT_MAX_CHARS = 2e3;
|
|
@@ -76560,8 +76560,9 @@ const DEFAULT_COMPACTION_CONFIG = {
|
|
|
76560
76560
|
blockRatio: .85,
|
|
76561
76561
|
reservedContextSize: 5e4,
|
|
76562
76562
|
maxCompactionPerTurn: 3,
|
|
76563
|
-
maxRecentMessages:
|
|
76564
|
-
maxRecentUserMessages:
|
|
76563
|
+
maxRecentMessages: 16,
|
|
76564
|
+
maxRecentUserMessages: 8,
|
|
76565
|
+
maxRecentTokens: 2e4,
|
|
76565
76566
|
maxRecentSizeRatio: .2,
|
|
76566
76567
|
minOverflowReductionRatio: .05,
|
|
76567
76568
|
turnGrowthMultiplier: 2.5
|
|
@@ -76603,7 +76604,7 @@ var DefaultCompactionStrategy = class {
|
|
|
76603
76604
|
if (m2.role === "user") recentUserMessages++;
|
|
76604
76605
|
recentSize += estimateTokensForMessage(m2);
|
|
76605
76606
|
if (canSplitAfter(messages, splitIndex)) bestN = splitIndex + 1;
|
|
76606
|
-
if ((recentMessages >= this.config.maxRecentMessages || recentUserMessages >= this.config.maxRecentUserMessages || recentSize >= this.maxSize * this.config.maxRecentSizeRatio) && bestN !== void 0) break;
|
|
76607
|
+
if ((recentMessages >= this.config.maxRecentMessages || recentUserMessages >= this.config.maxRecentUserMessages || recentSize >= this.config.maxRecentTokens || recentSize >= this.maxSize * this.config.maxRecentSizeRatio) && bestN !== void 0) break;
|
|
76607
76608
|
}
|
|
76608
76609
|
return bestN ?? 0;
|
|
76609
76610
|
}
|
|
@@ -77091,7 +77092,7 @@ var FullCompaction = class {
|
|
|
77091
77092
|
} else this.lastCompactionFiles = void 0;
|
|
77092
77093
|
for (const msg of messagesToCompactForOps) extractFileOpsFromMessage(msg, fileOps);
|
|
77093
77094
|
const toolCallHistory = formatToolCallHistory(messagesToCompactForOps);
|
|
77094
|
-
const processedSummary = this.postProcessSummary(summary, fileOps, toolCallHistory);
|
|
77095
|
+
const processedSummary = this.postProcessSummary(summary, fileOps, toolCallHistory, compactedCount);
|
|
77095
77096
|
const tokensAfter = estimateTokens$1(processedSummary) + estimateTokensForMessages(recent);
|
|
77096
77097
|
const fileLists = computeFileLists(fileOps);
|
|
77097
77098
|
const MAX_PERSISTED_FILES = 100;
|
|
@@ -77114,7 +77115,7 @@ var FullCompaction = class {
|
|
|
77114
77115
|
this.agent.context.applyCompaction(result);
|
|
77115
77116
|
this.lastCompactionFiles = fileLists;
|
|
77116
77117
|
this.lowWaterMark = Math.floor(this.effectiveTokenCount * 1.1);
|
|
77117
|
-
await this.extractAndStoreMemos(processedSummary);
|
|
77118
|
+
await this.extractAndStoreMemos(processedSummary, messagesToCompactForOps);
|
|
77118
77119
|
this.triggerPostCompactHook(data, result);
|
|
77119
77120
|
this.detectSkillCandidates(processedSummary);
|
|
77120
77121
|
this.consecutiveCompactionFailures = 0;
|
|
@@ -77178,16 +77179,27 @@ var FullCompaction = class {
|
|
|
77178
77179
|
}
|
|
77179
77180
|
});
|
|
77180
77181
|
}
|
|
77181
|
-
/** Extract memory memos from compaction summary and store them.
|
|
77182
|
-
|
|
77182
|
+
/** Extract memory memos from compaction summary and store them. When the
|
|
77183
|
+
* summary carries no memory-memo block, fall back to recording the most
|
|
77184
|
+
* recent real user message from the compacted history as a low-confidence
|
|
77185
|
+
* in-progress memo, so an ongoing task survives compaction even if the
|
|
77186
|
+
* model omitted the extraction section. */
|
|
77187
|
+
async extractAndStoreMemos(summary, messagesToCompact) {
|
|
77183
77188
|
const memoStore = this.agent.memoStore;
|
|
77184
77189
|
if (!memoStore) {
|
|
77185
77190
|
this.agent.log.info("Memory memo store not available, skipping extraction");
|
|
77186
77191
|
return;
|
|
77187
77192
|
}
|
|
77188
77193
|
this.agent.log.info("Scanning compaction summary for memory memos", { summaryLen: summary.length });
|
|
77189
|
-
|
|
77194
|
+
let memos = parseMemoryMemos(summary);
|
|
77190
77195
|
this.agent.log.info("Memory memo parse result", { memoCount: memos.length });
|
|
77196
|
+
if (memos.length === 0 && messagesToCompact !== void 0) {
|
|
77197
|
+
const fallback = /```memory-memo[\s\S]*?"none"\s*:\s*true[\s\S]*?```/.test(summary) ? void 0 : this.buildFallbackMemo(messagesToCompact);
|
|
77198
|
+
if (fallback !== void 0) {
|
|
77199
|
+
memos = [fallback];
|
|
77200
|
+
this.agent.log.info("Compaction summary carried no memory-memo; stored fallback memo", { userNeed: fallback.userNeed.slice(0, 120) });
|
|
77201
|
+
}
|
|
77202
|
+
}
|
|
77191
77203
|
if (memos.length === 0) return;
|
|
77192
77204
|
const sessionId = this.agent.homedir ? basename$1(dirname$2(dirname$2(this.agent.homedir))) : "unknown";
|
|
77193
77205
|
const sessionTitle = await this.agent.getSessionTitle();
|
|
@@ -77206,6 +77218,28 @@ var FullCompaction = class {
|
|
|
77206
77218
|
sessionId
|
|
77207
77219
|
});
|
|
77208
77220
|
}
|
|
77221
|
+
/** Build a low-confidence fallback memo from the most recent real user
|
|
77222
|
+
* message in the compacted history (origin.kind === 'user'), so an ongoing
|
|
77223
|
+
* task is not lost when the summary omits the memory-memo section. */
|
|
77224
|
+
buildFallbackMemo(messages) {
|
|
77225
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
77226
|
+
const msg = messages[i];
|
|
77227
|
+
if (msg === void 0 || msg.role !== "user" || msg.origin?.kind !== "user") continue;
|
|
77228
|
+
const text = msg.content.filter((p) => p.type === "text").map((p) => p.text).join("").trim();
|
|
77229
|
+
if (text.length === 0) continue;
|
|
77230
|
+
return createMemoryMemo({
|
|
77231
|
+
sourceSessionId: "",
|
|
77232
|
+
userNeed: text.slice(0, 300),
|
|
77233
|
+
approach: "(压缩时自动兜底记录:压缩摘要未生成完整任务经验提取,此处记录最近一条用户请求,用于跨压缩恢复进行中任务。请结合会话上下文核实。)",
|
|
77234
|
+
outcome: "进行中",
|
|
77235
|
+
whatFailed: "none",
|
|
77236
|
+
whatWorked: "none",
|
|
77237
|
+
tags: ["compaction-fallback"],
|
|
77238
|
+
note: "低置信度自动记录:建议后续在上下文恢复后核实并补充完整经验。",
|
|
77239
|
+
extractionSource: "compaction"
|
|
77240
|
+
});
|
|
77241
|
+
}
|
|
77242
|
+
}
|
|
77209
77243
|
/**
|
|
77210
77244
|
* Detects [[skill-candidate: <name>|<purpose>|<evidence>]] markers in the
|
|
77211
77245
|
* compaction summary and emits a `skill_candidate` event for each one (at
|
|
@@ -77238,11 +77272,17 @@ var FullCompaction = class {
|
|
|
77238
77272
|
* the compaction summary so active tasks and file context survive
|
|
77239
77273
|
* compression. Without this, both are lost after compaction because the
|
|
77240
77274
|
* original messages containing them are removed from the context window.
|
|
77275
|
+
*
|
|
77276
|
+
* When messages were actually compacted (`compactedCount > 0`), a leading
|
|
77277
|
+
* elision note tells the model how much of the conversation is missing and
|
|
77278
|
+
* that the summary is working notes, not verbatim history — so the tail
|
|
77279
|
+
* messages after the summary are not mistaken for a continuous conversation.
|
|
77241
77280
|
*/
|
|
77242
|
-
postProcessSummary(summary, fileOps, toolCallHistory) {
|
|
77281
|
+
postProcessSummary(summary, fileOps, toolCallHistory, compactedCount) {
|
|
77243
77282
|
const todos = this.agent.tools.storeData()["todo"] ?? [];
|
|
77244
|
-
const base = summary.trim().replaceAll(/<files>[\s\S]*?<\/files>\s*/g, "").trimEnd();
|
|
77283
|
+
const base = summary.trim().replaceAll(/<files>[\s\S]*?<\/files>\s*/g, "").replace(/^> The conversation before this point was compacted:[\s\S]*?continue from here\.\s*\n+/m, "").trimEnd();
|
|
77245
77284
|
const sections = [];
|
|
77285
|
+
if (compactedCount > 0) sections.push(`> The conversation before this point was compacted: ${String(compactedCount)} earlier message(s) were omitted and are covered by this summary. Treat the summary below as working notes, not verbatim history — the messages after it continue from here.`);
|
|
77246
77286
|
if (base.length > 0) sections.push(base);
|
|
77247
77287
|
if (todos.length > 0) {
|
|
77248
77288
|
const lines = todos.map((t) => {
|
|
@@ -121775,7 +121815,7 @@ function optionalBuildString(value) {
|
|
|
121775
121815
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
121776
121816
|
}
|
|
121777
121817
|
const SCREAM_BUILD_INFO = {
|
|
121778
|
-
version: optionalBuildString("0.12.
|
|
121818
|
+
version: optionalBuildString("0.12.8"),
|
|
121779
121819
|
channel: optionalBuildString(""),
|
|
121780
121820
|
commit: optionalBuildString(""),
|
|
121781
121821
|
buildTarget: optionalBuildString("darwin-arm64")
|
|
@@ -122762,28 +122802,46 @@ const BUILTIN_SLASH_COMMANDS = [
|
|
|
122762
122802
|
name: "auto",
|
|
122763
122803
|
aliases: [],
|
|
122764
122804
|
description: "registry.auto_desc",
|
|
122765
|
-
priority:
|
|
122805
|
+
priority: 220,
|
|
122766
122806
|
availability: "always"
|
|
122767
122807
|
},
|
|
122768
122808
|
{
|
|
122769
122809
|
name: "yes",
|
|
122770
122810
|
aliases: ["yolo"],
|
|
122771
122811
|
description: "registry.yolo_desc",
|
|
122772
|
-
priority:
|
|
122812
|
+
priority: 219,
|
|
122773
122813
|
availability: "always"
|
|
122774
122814
|
},
|
|
122775
122815
|
{
|
|
122776
122816
|
name: "ask",
|
|
122777
122817
|
aliases: ["ask"],
|
|
122778
122818
|
description: "registry.ask_desc",
|
|
122779
|
-
priority:
|
|
122819
|
+
priority: 218,
|
|
122820
|
+
availability: "always"
|
|
122821
|
+
},
|
|
122822
|
+
{
|
|
122823
|
+
name: "goal",
|
|
122824
|
+
aliases: ["goaloff"],
|
|
122825
|
+
description: "registry.goal_desc",
|
|
122826
|
+
argumentHint: "[objective]",
|
|
122827
|
+
priority: 217,
|
|
122828
|
+
availability: (args) => {
|
|
122829
|
+
const trimmed = args.trim();
|
|
122830
|
+
return trimmed === "" || trimmed === "status" || trimmed === "pause" || trimmed === "off" ? "always" : "idle-only";
|
|
122831
|
+
}
|
|
122832
|
+
},
|
|
122833
|
+
{
|
|
122834
|
+
name: "wolfpack",
|
|
122835
|
+
aliases: ["wp"],
|
|
122836
|
+
description: "registry.wolfpack_desc",
|
|
122837
|
+
priority: 216,
|
|
122780
122838
|
availability: "always"
|
|
122781
122839
|
},
|
|
122782
122840
|
{
|
|
122783
122841
|
name: "rlm",
|
|
122784
122842
|
aliases: ["rlm"],
|
|
122785
122843
|
description: "registry.rlm_desc",
|
|
122786
|
-
priority:
|
|
122844
|
+
priority: 215,
|
|
122787
122845
|
availability: "always"
|
|
122788
122846
|
},
|
|
122789
122847
|
{
|
|
@@ -122791,39 +122849,21 @@ const BUILTIN_SLASH_COMMANDS = [
|
|
|
122791
122849
|
aliases: [],
|
|
122792
122850
|
description: "registry.rlm_max_depth_desc",
|
|
122793
122851
|
argumentHint: "[N]",
|
|
122794
|
-
priority:
|
|
122795
|
-
availability: "always"
|
|
122796
|
-
},
|
|
122797
|
-
{
|
|
122798
|
-
name: "wolfpack",
|
|
122799
|
-
aliases: ["wp"],
|
|
122800
|
-
description: "registry.wolfpack_desc",
|
|
122801
|
-
priority: 122,
|
|
122852
|
+
priority: 214,
|
|
122802
122853
|
availability: "always"
|
|
122803
122854
|
},
|
|
122804
122855
|
{
|
|
122805
122856
|
name: "sessions",
|
|
122806
122857
|
aliases: ["resume"],
|
|
122807
122858
|
description: "registry.sessions_desc",
|
|
122808
|
-
priority:
|
|
122809
|
-
},
|
|
122810
|
-
{
|
|
122811
|
-
name: "goal",
|
|
122812
|
-
aliases: ["goaloff"],
|
|
122813
|
-
description: "registry.goal_desc",
|
|
122814
|
-
argumentHint: "[objective]",
|
|
122815
|
-
priority: 120,
|
|
122816
|
-
availability: (args) => {
|
|
122817
|
-
const trimmed = args.trim();
|
|
122818
|
-
return trimmed === "" || trimmed === "status" || trimmed === "pause" || trimmed === "off" ? "always" : "idle-only";
|
|
122819
|
-
}
|
|
122859
|
+
priority: 213
|
|
122820
122860
|
},
|
|
122821
122861
|
{
|
|
122822
122862
|
name: "memory",
|
|
122823
122863
|
aliases: ["memo", "mem"],
|
|
122824
122864
|
description: "registry.memory_desc",
|
|
122825
122865
|
argumentHint: "[query]",
|
|
122826
|
-
priority:
|
|
122866
|
+
priority: 212,
|
|
122827
122867
|
availability: "always"
|
|
122828
122868
|
},
|
|
122829
122869
|
{
|
|
@@ -122831,96 +122871,61 @@ const BUILTIN_SLASH_COMMANDS = [
|
|
|
122831
122871
|
aliases: ["know"],
|
|
122832
122872
|
description: "registry.knowledge_desc",
|
|
122833
122873
|
argumentHint: "[query]",
|
|
122834
|
-
priority:
|
|
122874
|
+
priority: 211,
|
|
122835
122875
|
availability: "always"
|
|
122836
122876
|
},
|
|
122837
|
-
{
|
|
122838
|
-
name: "new",
|
|
122839
|
-
aliases: ["clear"],
|
|
122840
|
-
description: "registry.new_desc",
|
|
122841
|
-
priority: 120
|
|
122842
|
-
},
|
|
122843
122877
|
{
|
|
122844
122878
|
name: "model",
|
|
122845
122879
|
aliases: [],
|
|
122846
122880
|
description: "registry.model_desc",
|
|
122847
122881
|
argumentHint: "[alias]",
|
|
122848
|
-
priority:
|
|
122882
|
+
priority: 210
|
|
122883
|
+
},
|
|
122884
|
+
{
|
|
122885
|
+
name: "new",
|
|
122886
|
+
aliases: ["clear"],
|
|
122887
|
+
description: "registry.new_desc",
|
|
122888
|
+
priority: 209
|
|
122849
122889
|
},
|
|
122850
122890
|
{
|
|
122851
122891
|
name: "compact",
|
|
122852
122892
|
aliases: [],
|
|
122853
122893
|
description: "registry.compact_desc",
|
|
122854
|
-
priority:
|
|
122894
|
+
priority: 208
|
|
122855
122895
|
},
|
|
122856
122896
|
{
|
|
122857
|
-
name: "
|
|
122858
|
-
aliases: ["
|
|
122859
|
-
description: "registry.
|
|
122860
|
-
priority:
|
|
122861
|
-
availability: "idle-only"
|
|
122897
|
+
name: "fusionplan",
|
|
122898
|
+
aliases: ["fp"],
|
|
122899
|
+
description: "registry.fusionplan_desc",
|
|
122900
|
+
priority: 207,
|
|
122901
|
+
availability: (args) => args.trim().toLowerCase() === "clear" ? "idle-only" : "always"
|
|
122862
122902
|
},
|
|
122863
122903
|
{
|
|
122864
122904
|
name: "plan",
|
|
122865
122905
|
aliases: [],
|
|
122866
122906
|
description: "registry.plan_desc",
|
|
122867
|
-
priority:
|
|
122868
|
-
availability: (args) => args.trim().toLowerCase() === "clear" ? "idle-only" : "always"
|
|
122869
|
-
},
|
|
122870
|
-
{
|
|
122871
|
-
name: "fusionplan",
|
|
122872
|
-
aliases: ["fp"],
|
|
122873
|
-
description: "registry.fusionplan_desc",
|
|
122874
|
-
priority: 118,
|
|
122907
|
+
priority: 206,
|
|
122875
122908
|
availability: (args) => args.trim().toLowerCase() === "clear" ? "idle-only" : "always"
|
|
122876
122909
|
},
|
|
122877
122910
|
{
|
|
122878
122911
|
name: "tasks",
|
|
122879
122912
|
aliases: ["task"],
|
|
122880
122913
|
description: "registry.tasks_desc",
|
|
122881
|
-
priority:
|
|
122882
|
-
availability: "always"
|
|
122883
|
-
},
|
|
122884
|
-
{
|
|
122885
|
-
name: "help",
|
|
122886
|
-
aliases: ["h", "?"],
|
|
122887
|
-
description: "registry.help_desc",
|
|
122888
|
-
priority: 116,
|
|
122889
|
-
availability: "always"
|
|
122890
|
-
},
|
|
122891
|
-
{
|
|
122892
|
-
name: "status",
|
|
122893
|
-
aliases: [],
|
|
122894
|
-
description: "registry.status_desc",
|
|
122895
|
-
priority: 115,
|
|
122896
|
-
availability: "always"
|
|
122897
|
-
},
|
|
122898
|
-
{
|
|
122899
|
-
name: "usage",
|
|
122900
|
-
aliases: [],
|
|
122901
|
-
description: "registry.usage_desc",
|
|
122902
|
-
priority: 114,
|
|
122914
|
+
priority: 205,
|
|
122903
122915
|
availability: "always"
|
|
122904
122916
|
},
|
|
122905
122917
|
{
|
|
122906
122918
|
name: "btw",
|
|
122907
122919
|
aliases: [],
|
|
122908
122920
|
description: "registry.btw_desc",
|
|
122909
|
-
priority:
|
|
122921
|
+
priority: 204,
|
|
122910
122922
|
availability: "always"
|
|
122911
122923
|
},
|
|
122912
122924
|
{
|
|
122913
122925
|
name: "like",
|
|
122914
122926
|
aliases: [],
|
|
122915
122927
|
description: "registry.like_desc",
|
|
122916
|
-
priority:
|
|
122917
|
-
availability: "always"
|
|
122918
|
-
},
|
|
122919
|
-
{
|
|
122920
|
-
name: "mcp",
|
|
122921
|
-
aliases: [],
|
|
122922
|
-
description: "registry.mcp_desc",
|
|
122923
|
-
priority: 112,
|
|
122928
|
+
priority: 203,
|
|
122924
122929
|
availability: "always"
|
|
122925
122930
|
},
|
|
122926
122931
|
{
|
|
@@ -122931,127 +122936,162 @@ const BUILTIN_SLASH_COMMANDS = [
|
|
|
122931
122936
|
"plugins"
|
|
122932
122937
|
],
|
|
122933
122938
|
description: "registry.skill_desc",
|
|
122934
|
-
priority:
|
|
122939
|
+
priority: 202,
|
|
122935
122940
|
availability: "always"
|
|
122936
122941
|
},
|
|
122937
122942
|
{
|
|
122938
|
-
name: "
|
|
122943
|
+
name: "fork",
|
|
122939
122944
|
aliases: [],
|
|
122940
|
-
description: "registry.
|
|
122941
|
-
priority:
|
|
122945
|
+
description: "registry.fork_desc",
|
|
122946
|
+
priority: 201
|
|
122947
|
+
},
|
|
122948
|
+
{
|
|
122949
|
+
name: "title",
|
|
122950
|
+
aliases: ["rename"],
|
|
122951
|
+
description: "registry.title_desc",
|
|
122952
|
+
priority: 200,
|
|
122942
122953
|
availability: "always"
|
|
122943
122954
|
},
|
|
122944
122955
|
{
|
|
122945
|
-
name: "
|
|
122956
|
+
name: "config",
|
|
122946
122957
|
aliases: [],
|
|
122947
|
-
description: "registry.
|
|
122948
|
-
priority:
|
|
122958
|
+
description: "registry.config_desc",
|
|
122959
|
+
priority: 199
|
|
122960
|
+
},
|
|
122961
|
+
{
|
|
122962
|
+
name: "help",
|
|
122963
|
+
aliases: ["h", "?"],
|
|
122964
|
+
description: "registry.help_desc",
|
|
122965
|
+
priority: 198,
|
|
122949
122966
|
availability: "always"
|
|
122950
122967
|
},
|
|
122951
122968
|
{
|
|
122952
|
-
name: "
|
|
122953
|
-
aliases: [],
|
|
122954
|
-
description: "registry.
|
|
122955
|
-
priority:
|
|
122969
|
+
name: "make-skill",
|
|
122970
|
+
aliases: ["makeskill", "craftskill"],
|
|
122971
|
+
description: "registry.make_skill_desc",
|
|
122972
|
+
priority: 197,
|
|
122956
122973
|
availability: "idle-only"
|
|
122957
122974
|
},
|
|
122958
122975
|
{
|
|
122959
|
-
name: "
|
|
122976
|
+
name: "mcp",
|
|
122960
122977
|
aliases: [],
|
|
122961
|
-
description: "registry.
|
|
122962
|
-
priority:
|
|
122978
|
+
description: "registry.mcp_desc",
|
|
122979
|
+
priority: 196,
|
|
122980
|
+
availability: "always"
|
|
122963
122981
|
},
|
|
122964
122982
|
{
|
|
122965
|
-
name: "
|
|
122966
|
-
aliases: [
|
|
122967
|
-
description: "registry.
|
|
122968
|
-
priority:
|
|
122983
|
+
name: "status",
|
|
122984
|
+
aliases: [],
|
|
122985
|
+
description: "registry.status_desc",
|
|
122986
|
+
priority: 195,
|
|
122969
122987
|
availability: "always"
|
|
122970
122988
|
},
|
|
122971
122989
|
{
|
|
122972
|
-
name: "
|
|
122990
|
+
name: "usage",
|
|
122973
122991
|
aliases: [],
|
|
122974
|
-
description: "registry.
|
|
122975
|
-
priority:
|
|
122992
|
+
description: "registry.usage_desc",
|
|
122993
|
+
priority: 194,
|
|
122994
|
+
availability: "always"
|
|
122976
122995
|
},
|
|
122977
122996
|
{
|
|
122978
|
-
name: "
|
|
122997
|
+
name: "revoke",
|
|
122979
122998
|
aliases: [],
|
|
122980
|
-
description: "registry.
|
|
122981
|
-
priority:
|
|
122999
|
+
description: "registry.revoke_desc",
|
|
123000
|
+
priority: 193,
|
|
123001
|
+
availability: "idle-only"
|
|
123002
|
+
},
|
|
123003
|
+
{
|
|
123004
|
+
name: "cc",
|
|
123005
|
+
aliases: [],
|
|
123006
|
+
description: "registry.cc_desc",
|
|
123007
|
+
priority: 192,
|
|
123008
|
+
availability: "always"
|
|
123009
|
+
},
|
|
123010
|
+
{
|
|
123011
|
+
name: "cc-connect",
|
|
123012
|
+
aliases: [],
|
|
123013
|
+
description: "registry.cc_connect_desc",
|
|
123014
|
+
priority: 191,
|
|
122982
123015
|
availability: "always"
|
|
122983
123016
|
},
|
|
122984
123017
|
{
|
|
122985
123018
|
name: "theme",
|
|
122986
123019
|
aliases: [],
|
|
122987
123020
|
description: "registry.theme_desc",
|
|
122988
|
-
priority:
|
|
123021
|
+
priority: 190,
|
|
122989
123022
|
availability: "always"
|
|
122990
123023
|
},
|
|
122991
123024
|
{
|
|
122992
123025
|
name: "language",
|
|
122993
123026
|
aliases: ["lang"],
|
|
122994
123027
|
description: "registry.language_desc",
|
|
122995
|
-
priority:
|
|
123028
|
+
priority: 189,
|
|
123029
|
+
availability: "always"
|
|
123030
|
+
},
|
|
123031
|
+
{
|
|
123032
|
+
name: "permission",
|
|
123033
|
+
aliases: [],
|
|
123034
|
+
description: "registry.permission_desc",
|
|
123035
|
+
priority: 188,
|
|
122996
123036
|
availability: "always"
|
|
122997
123037
|
},
|
|
122998
123038
|
{
|
|
122999
123039
|
name: "editor",
|
|
123000
123040
|
aliases: [],
|
|
123001
123041
|
description: "registry.editor_desc",
|
|
123002
|
-
priority:
|
|
123042
|
+
priority: 187,
|
|
123003
123043
|
availability: "always"
|
|
123004
123044
|
},
|
|
123005
123045
|
{
|
|
123006
123046
|
name: "settings",
|
|
123007
123047
|
aliases: [],
|
|
123008
123048
|
description: "registry.settings_desc",
|
|
123009
|
-
priority:
|
|
123049
|
+
priority: 186,
|
|
123010
123050
|
availability: "always"
|
|
123011
123051
|
},
|
|
123012
123052
|
{
|
|
123013
123053
|
name: "init",
|
|
123014
123054
|
aliases: [],
|
|
123015
123055
|
description: "registry.init_desc",
|
|
123016
|
-
priority:
|
|
123056
|
+
priority: 185
|
|
123017
123057
|
},
|
|
123018
123058
|
{
|
|
123019
123059
|
name: "export-md",
|
|
123020
123060
|
aliases: ["export"],
|
|
123021
123061
|
description: "registry.export_md_desc",
|
|
123022
|
-
priority:
|
|
123062
|
+
priority: 184
|
|
123023
123063
|
},
|
|
123024
123064
|
{
|
|
123025
123065
|
name: "export-debug-zip",
|
|
123026
123066
|
aliases: [],
|
|
123027
123067
|
description: "registry.export_debug_desc",
|
|
123028
|
-
priority:
|
|
123068
|
+
priority: 183
|
|
123069
|
+
},
|
|
123070
|
+
{
|
|
123071
|
+
name: "eval",
|
|
123072
|
+
aliases: [],
|
|
123073
|
+
description: "registry.eval_desc",
|
|
123074
|
+
priority: 182
|
|
123029
123075
|
},
|
|
123030
123076
|
{
|
|
123031
123077
|
name: "update",
|
|
123032
123078
|
aliases: [],
|
|
123033
123079
|
description: "registry.update_desc",
|
|
123034
|
-
priority:
|
|
123080
|
+
priority: 181,
|
|
123035
123081
|
availability: "idle-only"
|
|
123036
123082
|
},
|
|
123037
123083
|
{
|
|
123038
123084
|
name: "version",
|
|
123039
123085
|
aliases: [],
|
|
123040
123086
|
description: "registry.version_desc",
|
|
123041
|
-
priority:
|
|
123087
|
+
priority: 180,
|
|
123042
123088
|
availability: "always"
|
|
123043
123089
|
},
|
|
123044
123090
|
{
|
|
123045
123091
|
name: "logout",
|
|
123046
123092
|
aliases: ["disconnect"],
|
|
123047
123093
|
description: "registry.logout_desc",
|
|
123048
|
-
priority:
|
|
123049
|
-
},
|
|
123050
|
-
{
|
|
123051
|
-
name: "eval",
|
|
123052
|
-
aliases: [],
|
|
123053
|
-
description: "registry.eval_desc",
|
|
123054
|
-
priority: 92
|
|
123094
|
+
priority: 179
|
|
123055
123095
|
},
|
|
123056
123096
|
{
|
|
123057
123097
|
name: "exit",
|
|
@@ -125693,7 +125733,15 @@ const HEADING_HASH_PREFIX = /^((?:\u001B\[[0-9;]*m)*)#{1,6}[ \t]+/;
|
|
|
125693
125733
|
* takes one formatter function per token; tokens not listed here fall back to
|
|
125694
125734
|
* its DEFAULT_THEME.
|
|
125695
125735
|
*/
|
|
125696
|
-
|
|
125736
|
+
/**
|
|
125737
|
+
* Markdown code-block highlight theme: green-dominant mapping (keyword,
|
|
125738
|
+
* function, built_in → primary; strings → success; numbers → warning;
|
|
125739
|
+
* comments → textDim). Kept distinct from the shared preview theme in
|
|
125740
|
+
* code-highlight-theme.ts on purpose — markdown code blocks use the green
|
|
125741
|
+
* primary hue, while file-preview panels use the classic blue/red/yellow
|
|
125742
|
+
* scheme mapped to the same palette. Both follow the active theme.
|
|
125743
|
+
*/
|
|
125744
|
+
function createMarkdownCodeHighlightTheme(colors) {
|
|
125697
125745
|
const keyword = chalk.hex(colors.primary);
|
|
125698
125746
|
const str = chalk.hex(colors.success);
|
|
125699
125747
|
const comment = chalk.hex(colors.textDim);
|
|
@@ -125743,7 +125791,7 @@ function createMarkdownTheme(colors) {
|
|
|
125743
125791
|
const stripHash = (text) => text.replace(HEADING_HASH_PREFIX, "$1");
|
|
125744
125792
|
const muted = chalk.hex(colors.textMuted);
|
|
125745
125793
|
const border = chalk.hex(colors.border);
|
|
125746
|
-
const codeTheme =
|
|
125794
|
+
const codeTheme = createMarkdownCodeHighlightTheme(colors);
|
|
125747
125795
|
return {
|
|
125748
125796
|
heading: (text) => chalk.bold.hex(colors.text)(stripHash(text)),
|
|
125749
125797
|
link: (text) => chalk.hex(colors.mdLink)(text),
|
|
@@ -128981,6 +129029,60 @@ var CachedContainer = class extends Container {
|
|
|
128981
129029
|
}
|
|
128982
129030
|
};
|
|
128983
129031
|
//#endregion
|
|
129032
|
+
//#region src/tui/theme/code-highlight-theme.ts
|
|
129033
|
+
function createCodeHighlightTheme(colors) {
|
|
129034
|
+
const keyword = chalk.hex(colors.mdCodeBlock);
|
|
129035
|
+
const str = chalk.hex(colors.error);
|
|
129036
|
+
const num = chalk.hex(colors.primary);
|
|
129037
|
+
const fn = chalk.hex(colors.warning);
|
|
129038
|
+
const builtin = chalk.hex(colors.planMode);
|
|
129039
|
+
const cls = chalk.hex(colors.accent);
|
|
129040
|
+
const text = chalk.hex(colors.text);
|
|
129041
|
+
return {
|
|
129042
|
+
keyword,
|
|
129043
|
+
built_in: builtin,
|
|
129044
|
+
type: keyword,
|
|
129045
|
+
literal: builtin,
|
|
129046
|
+
number: num,
|
|
129047
|
+
regexp: str,
|
|
129048
|
+
string: str,
|
|
129049
|
+
subst: str,
|
|
129050
|
+
symbol: num,
|
|
129051
|
+
class: cls,
|
|
129052
|
+
function: fn,
|
|
129053
|
+
title: fn,
|
|
129054
|
+
params: text,
|
|
129055
|
+
comment: num,
|
|
129056
|
+
doctag: num,
|
|
129057
|
+
meta: chalk.hex(colors.textMuted),
|
|
129058
|
+
"meta-keyword": keyword,
|
|
129059
|
+
"meta-string": str,
|
|
129060
|
+
section: keyword,
|
|
129061
|
+
tag: keyword,
|
|
129062
|
+
name: fn,
|
|
129063
|
+
"builtin-name": builtin,
|
|
129064
|
+
attr: fn,
|
|
129065
|
+
attribute: fn,
|
|
129066
|
+
variable: text,
|
|
129067
|
+
bullet: num,
|
|
129068
|
+
code: str,
|
|
129069
|
+
emphasis: (s) => chalk.italic(s),
|
|
129070
|
+
strong: (s) => chalk.bold(s),
|
|
129071
|
+
formula: text,
|
|
129072
|
+
link: chalk.hex(colors.mdLink),
|
|
129073
|
+
quote: chalk.hex(colors.mdQuote),
|
|
129074
|
+
addition: chalk.hex(colors.diffAdded),
|
|
129075
|
+
deletion: chalk.hex(colors.diffRemoved),
|
|
129076
|
+
"selector-tag": keyword,
|
|
129077
|
+
"selector-id": cls,
|
|
129078
|
+
"selector-class": cls,
|
|
129079
|
+
"selector-attr": fn,
|
|
129080
|
+
"selector-pseudo": fn,
|
|
129081
|
+
"template-tag": str,
|
|
129082
|
+
"template-variable": fn
|
|
129083
|
+
};
|
|
129084
|
+
}
|
|
129085
|
+
//#endregion
|
|
128984
129086
|
//#region src/tui/components/media/code-highlight.ts
|
|
128985
129087
|
/**
|
|
128986
129088
|
* Shared syntax-highlighting helpers for code previews
|
|
@@ -129018,13 +129120,14 @@ function langFromPath(filePath) {
|
|
|
129018
129120
|
const lang = EXT_LANG_MAP[ext] ?? ext;
|
|
129019
129121
|
return supportsLanguage(lang) ? lang : void 0;
|
|
129020
129122
|
}
|
|
129021
|
-
function highlightLines(code, lang) {
|
|
129123
|
+
function highlightLines(code, lang, colors) {
|
|
129022
129124
|
const normalizedLang = lang?.trim().toLowerCase();
|
|
129023
129125
|
if (!normalizedLang || !supportsLanguage(normalizedLang)) return code.split("\n");
|
|
129024
129126
|
try {
|
|
129025
129127
|
return highlight(code, {
|
|
129026
129128
|
language: normalizedLang,
|
|
129027
|
-
ignoreIllegals: true
|
|
129129
|
+
ignoreIllegals: true,
|
|
129130
|
+
theme: createCodeHighlightTheme(colors)
|
|
129028
129131
|
}).split("\n");
|
|
129029
129132
|
} catch {
|
|
129030
129133
|
return code.split("\n");
|
|
@@ -129086,10 +129189,12 @@ function visualizeIndent(line) {
|
|
|
129086
129189
|
}
|
|
129087
129190
|
/**
|
|
129088
129191
|
* Render a diff line's code with leading-whitespace visualization (tabs as
|
|
129089
|
-
* `->`, spaces as `·`, dimmed) and optional syntax highlighting.
|
|
129090
|
-
* runs on the raw code
|
|
129091
|
-
*
|
|
129092
|
-
*
|
|
129192
|
+
* `->`, spaces as `·`, dimmed) and optional syntax highlighting. Indent
|
|
129193
|
+
* visualization runs on the raw code FIRST, then highlighting runs on the
|
|
129194
|
+
* stripped remainder: once the text is ANSI-tinted (the theme's `default`
|
|
129195
|
+
* color wraps whitespace too), a leading tab is no longer the first raw
|
|
129196
|
+
* character and would be missed. The dimmed indent itself carries no token
|
|
129197
|
+
* color.
|
|
129093
129198
|
*
|
|
129094
129199
|
* When highlighting is on and produced token colors, the diff line color is
|
|
129095
129200
|
* layered as the base foreground: syntax tokens override it, but every ANSI
|
|
@@ -129098,17 +129203,18 @@ function visualizeIndent(line) {
|
|
|
129098
129203
|
* When highlighting is off (streaming) or produced no token colors, the code
|
|
129099
129204
|
* part is colored with the diff line color instead.
|
|
129100
129205
|
*/
|
|
129101
|
-
function renderDiffCode(code, colorFn, highlight, lang) {
|
|
129102
|
-
const { text, indentEnd } = visualizeIndent(
|
|
129206
|
+
function renderDiffCode(code, colorFn, highlight, lang, colors) {
|
|
129207
|
+
const { text, indentEnd } = visualizeIndent(code);
|
|
129103
129208
|
const indent = text.slice(0, indentEnd);
|
|
129104
129209
|
const rest = text.slice(indentEnd);
|
|
129105
129210
|
const dimIndent = indent.length > 0 ? chalk.dim(indent) : indent;
|
|
129106
|
-
|
|
129211
|
+
const source = highlight ? highlightLines(rest, lang, colors)[0] ?? rest : rest;
|
|
129212
|
+
if (highlight && ANSI_RE.test(source)) {
|
|
129107
129213
|
const prefix = extractAnsiPrefix(colorFn);
|
|
129108
|
-
if (prefix.length > 0) return dimIndent + prefix +
|
|
129109
|
-
return dimIndent +
|
|
129214
|
+
if (prefix.length > 0) return dimIndent + prefix + source.replace(ANSI_RESET_RE, (m) => m + prefix) + "\x1B[39m";
|
|
129215
|
+
return dimIndent + source;
|
|
129110
129216
|
}
|
|
129111
|
-
return dimIndent + colorFn(
|
|
129217
|
+
return dimIndent + colorFn(source);
|
|
129112
129218
|
}
|
|
129113
129219
|
/**
|
|
129114
129220
|
* Compute word-level diff between two single lines and highlight the changed
|
|
@@ -129242,7 +129348,7 @@ function renderDiffLines(oldText, newText, path, colors, isIncomplete = false, o
|
|
|
129242
129348
|
const line = shown[i];
|
|
129243
129349
|
const marker = line.kind === "add" ? "+" : "-";
|
|
129244
129350
|
const color = line.kind === "add" ? s.add : s.del;
|
|
129245
|
-
output.push(s.gutter(String(line.lineNum).padStart(4) + " ") + color(`${marker} `) + renderDiffCode(line.code, color, doHighlight, lang));
|
|
129351
|
+
output.push(s.gutter(String(line.lineNum).padStart(4) + " ") + color(`${marker} `) + renderDiffCode(line.code, color, doHighlight, lang, colors));
|
|
129246
129352
|
i += 1;
|
|
129247
129353
|
}
|
|
129248
129354
|
const hidden = changedLines.length - shown.length;
|
|
@@ -129293,11 +129399,11 @@ function buildClusters(diffLines, contextLines) {
|
|
|
129293
129399
|
removedCount: removed
|
|
129294
129400
|
};
|
|
129295
129401
|
}
|
|
129296
|
-
function formatDiffRow(line, s, doHighlight, lang) {
|
|
129402
|
+
function formatDiffRow(line, s, doHighlight, lang, colors) {
|
|
129297
129403
|
const gutter = s.gutter(String(line.lineNum).padStart(4) + " ");
|
|
129298
|
-
if (line.kind === "add") return gutter + s.add("+ ") + renderDiffCode(line.code, s.add, doHighlight, lang);
|
|
129299
|
-
if (line.kind === "delete") return gutter + s.del("- ") + renderDiffCode(line.code, s.del, doHighlight, lang);
|
|
129300
|
-
return gutter + " " + renderDiffCode(line.code, (x) => x, doHighlight, lang);
|
|
129404
|
+
if (line.kind === "add") return gutter + s.add("+ ") + renderDiffCode(line.code, s.add, doHighlight, lang, colors);
|
|
129405
|
+
if (line.kind === "delete") return gutter + s.del("- ") + renderDiffCode(line.code, s.del, doHighlight, lang, colors);
|
|
129406
|
+
return gutter + " " + renderDiffCode(line.code, (x) => x, doHighlight, lang, colors);
|
|
129301
129407
|
}
|
|
129302
129408
|
/**
|
|
129303
129409
|
* Render a diff with surrounding context, eliding unchanged middle
|
|
@@ -129368,7 +129474,7 @@ function renderDiffLinesClustered(oldText, newText, path, colors, opts = {}) {
|
|
|
129368
129474
|
i += 2;
|
|
129369
129475
|
continue;
|
|
129370
129476
|
}
|
|
129371
|
-
output.push(formatDiffRow(line, s, doHighlight, lang));
|
|
129477
|
+
output.push(formatDiffRow(line, s, doHighlight, lang, colors));
|
|
129372
129478
|
body++;
|
|
129373
129479
|
if (line.kind !== "context") shownChanges++;
|
|
129374
129480
|
prevEnd = i;
|
|
@@ -131251,7 +131357,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
131251
131357
|
if (name === "Write") {
|
|
131252
131358
|
const content = str(this.toolCall.args["content"]);
|
|
131253
131359
|
if (content.length === 0) return;
|
|
131254
|
-
const allLines = highlightLines(content, langFromPath(str(this.toolCall.args["file_path"] ?? this.toolCall.args["path"])));
|
|
131360
|
+
const allLines = highlightLines(content, langFromPath(str(this.toolCall.args["file_path"] ?? this.toolCall.args["path"])), this.colors);
|
|
131255
131361
|
const writeShouldCap = !this.expanded;
|
|
131256
131362
|
const shown = writeShouldCap ? allLines.slice(0, 10) : allLines;
|
|
131257
131363
|
const remaining = allLines.length - shown.length;
|
|
@@ -131356,7 +131462,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
131356
131462
|
const fragmentEnd = Math.min(streamText.length, fragmentStart + ToolCallComponent.WRITE_STREAM_TAIL_RAW_CHARS);
|
|
131357
131463
|
const fragment = unescapeJsonStringValue(streamText, fragmentStart, fragmentEnd);
|
|
131358
131464
|
if (fragment.length === 0) return;
|
|
131359
|
-
const lines = highlightLines(fragment, this.writeStreamLang);
|
|
131465
|
+
const lines = highlightLines(fragment, this.writeStreamLang, this.colors);
|
|
131360
131466
|
const displayLines = lines.slice(-10);
|
|
131361
131467
|
const firstFragmentLineNo = this.writeStreamNlCount + (tailStart > contentStart ? 2 : 1);
|
|
131362
131468
|
const skipped = lines.length - displayLines.length;
|
|
@@ -138164,6 +138270,8 @@ var SessionEventHandler = class {
|
|
|
138164
138270
|
this.renderedSkillActivationIds.clear();
|
|
138165
138271
|
this.renderedMcpServerStatusKeys.clear();
|
|
138166
138272
|
this.stopAllMcpServerStatusSpinners();
|
|
138273
|
+
this.pendingSkillCandidates = [];
|
|
138274
|
+
this.promptedSkillCandidates.clear();
|
|
138167
138275
|
this.host.setAppState({ subagentUsage: {} });
|
|
138168
138276
|
}
|
|
138169
138277
|
startSubscription() {
|
|
@@ -138419,6 +138527,12 @@ var SessionEventHandler = class {
|
|
|
138419
138527
|
const todos = this.host.state.todoPanel.getTodos();
|
|
138420
138528
|
if (todos.length > 0 && todos.every((todo) => todo.status === "done")) this.host.streamingUI.setTodoList([]);
|
|
138421
138529
|
this.host.streamingUI.resetToolUi();
|
|
138530
|
+
if (this.pendingSkillCandidates.length > 0 && this.host.state.queuedMessages.length === 0) {
|
|
138531
|
+
const pending = this.pendingSkillCandidates;
|
|
138532
|
+
this.pendingSkillCandidates = [];
|
|
138533
|
+
const session = this.host.session;
|
|
138534
|
+
if (session !== void 0) for (const candidate of pending) this.promptSkillCandidate(session, candidate.name, candidate.purpose);
|
|
138535
|
+
}
|
|
138422
138536
|
this.host.streamingUI.finalizeTurn(sendQueued);
|
|
138423
138537
|
}
|
|
138424
138538
|
handleStepBegin(event) {
|
|
@@ -138793,6 +138907,10 @@ var SessionEventHandler = class {
|
|
|
138793
138907
|
}
|
|
138794
138908
|
/** Candidates already prompted this session, to avoid repeating the request. */
|
|
138795
138909
|
promptedSkillCandidates = /* @__PURE__ */ new Set();
|
|
138910
|
+
/** Skill candidates detected while a turn was still active. Flushed at the
|
|
138911
|
+
* next turn end so the AskUserQuestion dialog never interrupts an ongoing
|
|
138912
|
+
* response. */
|
|
138913
|
+
pendingSkillCandidates = [];
|
|
138796
138914
|
/**
|
|
138797
138915
|
* Handles a `skill_candidate` event emitted after compaction detected a
|
|
138798
138916
|
* reusable process in the summary. Best-effort and non-fatal: if the session
|
|
@@ -138800,6 +138918,10 @@ var SessionEventHandler = class {
|
|
|
138800
138918
|
* no confirmation. When it works, the model runs an AskUserQuestion dialog
|
|
138801
138919
|
* (确定/忽略) so the user can confirm or dismiss with a single keystroke,
|
|
138802
138920
|
* then generates the skill via MakeSkillPlanTool on confirmation.
|
|
138921
|
+
*
|
|
138922
|
+
* If a turn is still streaming (the compaction finished while the agent was
|
|
138923
|
+
* mid-response), the candidate is queued and prompted at the next turn end —
|
|
138924
|
+
* never interrupting the running turn.
|
|
138803
138925
|
*/
|
|
138804
138926
|
handleSkillCandidate(event) {
|
|
138805
138927
|
try {
|
|
@@ -138809,10 +138931,25 @@ var SessionEventHandler = class {
|
|
|
138809
138931
|
this.promptedSkillCandidates.add(name);
|
|
138810
138932
|
const session = this.host.session;
|
|
138811
138933
|
if (session === void 0) return;
|
|
138812
|
-
|
|
138813
|
-
|
|
138934
|
+
if (this.host.streamingUI.hasActiveTurn()) {
|
|
138935
|
+
this.pendingSkillCandidates.push({
|
|
138936
|
+
name,
|
|
138937
|
+
purpose
|
|
138938
|
+
});
|
|
138939
|
+
return;
|
|
138940
|
+
}
|
|
138941
|
+
this.promptSkillCandidate(session, name, purpose);
|
|
138814
138942
|
} catch {}
|
|
138815
138943
|
}
|
|
138944
|
+
/** Fire the AskUserQuestion prompt for a skill candidate. On failure, surface
|
|
138945
|
+
* a status hint instead of failing silently so the user still learns the
|
|
138946
|
+
* candidate was detected. */
|
|
138947
|
+
promptSkillCandidate(session, name, purpose) {
|
|
138948
|
+
const request = `检测到可复用过程「${name}」${purpose ? `(${purpose})` : ""}。请用 AskUserQuestion 工具询问用户是否将其保存为可复用技能(选项:生成 / 忽略)。用户选择「生成」后,用 MakeSkillPlanTool 生成该技能;选择「忽略」则直接说明已跳过。`;
|
|
138949
|
+
session.prompt(request).catch(() => {
|
|
138950
|
+
this.host.showStatus(`检测到可复用过程「${name}」,但询问失败。可稍后手动处理。`, this.host.state.theme.colors.warning);
|
|
138951
|
+
});
|
|
138952
|
+
}
|
|
138816
138953
|
finishCompaction(sendQueued) {
|
|
138817
138954
|
if (!this.host.streamingUI.hasActiveTurn()) {
|
|
138818
138955
|
this.host.setAppState({
|
|
@@ -145163,7 +145300,7 @@ function renderDisplayBlock(block, s, colors) {
|
|
|
145163
145300
|
});
|
|
145164
145301
|
case "file_content": {
|
|
145165
145302
|
const lang = block.language ?? langFromPath(block.path);
|
|
145166
|
-
const allLines = highlightLines(replaceTabs(block.content), lang);
|
|
145303
|
+
const allLines = highlightLines(replaceTabs(block.content), lang, colors);
|
|
145167
145304
|
const shown = allLines.slice(0, CONTENT_SUMMARY_MAX_LINES);
|
|
145168
145305
|
const lines = [s.strong(block.path)];
|
|
145169
145306
|
for (const [i, line] of shown.entries()) lines.push(s.gutter(String(i + 1).padStart(4) + " ") + line);
|
|
@@ -145574,7 +145711,7 @@ function buildDiffBody(block, colors) {
|
|
|
145574
145711
|
}
|
|
145575
145712
|
function buildFileContentBody(block, colors) {
|
|
145576
145713
|
const lang = block.language ?? langFromPath(block.path);
|
|
145577
|
-
const highlighted = highlightLines(block.content, lang);
|
|
145714
|
+
const highlighted = highlightLines(block.content, lang, colors);
|
|
145578
145715
|
const gutter = chalk.hex(colors.diffGutter);
|
|
145579
145716
|
return {
|
|
145580
145717
|
lines: highlighted.map((line, i) => gutter(String(i + 1).padStart(4) + " ") + line),
|
package/dist/main.mjs
CHANGED
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
7
|
//#region src/main.ts
|
|
8
8
|
try {
|
|
9
|
-
(await import("./app-
|
|
9
|
+
(await import("./app-CyJPMDaK.mjs")).main();
|
|
10
10
|
} catch (error) {
|
|
11
11
|
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
12
12
|
process.exit(1);
|