scream-code 0.13.8 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{app-CJGX8qct.mjs → app-BXslKpYT.mjs} +44 -8
- package/dist/{dispatch-DevL-OSj.mjs → dispatch-202xtik3.mjs} +328 -115
- package/dist/{dispatch-D5doFUQU.mjs → dispatch-D71h_08g.mjs} +1 -1
- package/dist/main.mjs +1 -1
- package/dist/{text-input-dialog-B9Klg3re.mjs → text-input-dialog-BzVVVncg.mjs} +22 -0
- package/dist/{text-input-dialog-Bnu3s0gP.mjs → text-input-dialog-DVWsE7Gh.mjs} +1 -1
- package/package.json +1 -1
|
@@ -4,8 +4,8 @@ import { dirname as __cjsShimDirname } from 'node:path';
|
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
|
-
import { $t as isTodoItemShape, A as renderDiffLinesClustered, An as CLI_COMMAND_NAME, At as ENABLE_TERMINAL_FOCUS_REPORTING, B as BackgroundAgentStatusComponent, Bn as MemoryMemoStore, Bt as TERMINAL_THEME_LIGHT, Cn as loadTuiConfig, Ct as createThemeStyles, D as toggleEmptySessionHint, Dn as getInputHistoryFile, Dt as parseOsc11BackgroundTheme, E as isTurnElapsedEnabled, En as getDataDir, Et as detectTerminalTheme, F as estimateTokens, Fn as fetchCatalog, Ft as OSC11_RESPONSE_PREFIX_NO_ESC, G as getBreathingFrame, Gn as isOrphanedToolCallError, H as AgentGroupComponent, Hn as log, Ht as isStreaming, I as getSharedSpeedTracker, In as saveCatalogCache, It as QUERY_TERMINAL_THEME, J as refineGoal, Jt as printableChar, K as resetBreathingClock, Kn as ErrorCodes, L as SkillActivationComponent, Ln as ScreamHarness, Lt as TERMINAL_FOCUS_IN, M as langFromPath, Mn as CLI_USER_AGENT_PRODUCT, Mt as OSC11_QUERY, N as CachedContainer, Nn as PRODUCT_NAME, Nt as OSC11_RESPONSE, O as ToolCallComponent, On as getLogDir, Ot as DISABLE_TERMINAL_FOCUS_REPORTING, P as ThinkingComponent, Pn as DEFAULT_CATALOG_URL, Pt as OSC11_RESPONSE_PREFIX, Qt as formatErrorMessage, R as ReadGroupComponent, Rt as TERMINAL_FOCUS_OUT, S as getDaemonInstructions, Sn as TuiLikePreferencesSchema, St as createMarkdownTheme, T as isEmptySessionHintDismissed, Tn as detectShellEnvironment, Tt as getColorPalette, U as WelcomeComponent, Un as resolveGlobalLogPath, Ut as FooterComponent, V as AssistantMessageComponent, Vn as flushDiagnosticLogs, Vt as isBusy, W as BREATHE_CYCLE_MS, Wn as isScreamError, Xt as appendStreamingArgsPreview, Yt as STATUS_BULLET, Zt as argsRecord, _ as refreshUpdateCache, _n as isExperimentalFlagEnabled, _t as clearInfoPanelState, an as EMPTY_SESSION_HINT_URL, b as readJsonlFile, bn as PULSE_WAVE_FRAMES, bt as resolveThemeSync, c as hasDispose, cn as SESSION_TIPS, ct as handlePlanCommand, d as formatMemoryMemoForInjection, dn as getCtrlDHint, en as parseStreamingArgs, et as toTerminalHyperlink, fn as getLlmNotSetMessage, g as selectUpdateTarget, gn as sortSlashCommands, gt as supportsBalance, hn as BUILTIN_SLASH_COMMANDS, ht as refreshProviderBalance, i as buildRoleAdditionalText, in as CHARS_PER_TOKEN, j as highlightLines, jn as CLI_UI_MODE, jt as ENABLE_TERMINAL_THEME_REPORTING, k as renderDiffLines, kn as detectInstallSource, kt as DISABLE_TERMINAL_THEME_REPORTING, l as isPlanExpandable, ln as TIP_ROTATION_INTERVAL_MS, mn as buildSkillSlashCommands, n as clearEvalPanelState, nn as stringValue, nt as getModelCycleLevel, on as EXIT_CONFIRM_WINDOW_MS, ot as handleFusionPlanCommand, pn as getNoActiveSessionMessage, q as clearGoalState, qn as SCREAM_ERROR_INFO, r as openUrl, rn as truncateErrorMessage, s as disposeChildren, sn as MAIN_AGENT_ID, t as dispatchInput, tn as serializeToolResultOutput, tt as changeThinkingLevel, u as MoonLoader, un as getCtrlCHint, v as readUpdateCache, vn as setExperimentalFlags, w as UserMessageComponent, wn as saveTuiConfig, wt as contrastTextHex, xn as TuiConfigParseError, xt as createEditorTheme, y as appendJsonlLine, yn as PIXEL_PULSE_FRAMES, z as parseReadGroupOutput, zn as resolveScreamHome, zt as TERMINAL_THEME_DARK } from "./dispatch-
|
|
8
|
-
import { a as setLocale, o as t } from "./text-input-dialog-
|
|
7
|
+
import { $t as isTodoItemShape, A as renderDiffLinesClustered, An as CLI_COMMAND_NAME, At as ENABLE_TERMINAL_FOCUS_REPORTING, B as BackgroundAgentStatusComponent, Bn as MemoryMemoStore, Bt as TERMINAL_THEME_LIGHT, Cn as loadTuiConfig, Ct as createThemeStyles, D as toggleEmptySessionHint, Dn as getInputHistoryFile, Dt as parseOsc11BackgroundTheme, E as isTurnElapsedEnabled, En as getDataDir, Et as detectTerminalTheme, F as estimateTokens, Fn as fetchCatalog, Ft as OSC11_RESPONSE_PREFIX_NO_ESC, G as getBreathingFrame, Gn as isOrphanedToolCallError, H as AgentGroupComponent, Hn as log, Ht as isStreaming, I as getSharedSpeedTracker, In as saveCatalogCache, It as QUERY_TERMINAL_THEME, J as refineGoal, Jt as printableChar, K as resetBreathingClock, Kn as ErrorCodes, L as SkillActivationComponent, Ln as ScreamHarness, Lt as TERMINAL_FOCUS_IN, M as langFromPath, Mn as CLI_USER_AGENT_PRODUCT, Mt as OSC11_QUERY, N as CachedContainer, Nn as PRODUCT_NAME, Nt as OSC11_RESPONSE, O as ToolCallComponent, On as getLogDir, Ot as DISABLE_TERMINAL_FOCUS_REPORTING, P as ThinkingComponent, Pn as DEFAULT_CATALOG_URL, Pt as OSC11_RESPONSE_PREFIX, Qt as formatErrorMessage, R as ReadGroupComponent, Rt as TERMINAL_FOCUS_OUT, S as getDaemonInstructions, Sn as TuiLikePreferencesSchema, St as createMarkdownTheme, T as isEmptySessionHintDismissed, Tn as detectShellEnvironment, Tt as getColorPalette, U as WelcomeComponent, Un as resolveGlobalLogPath, Ut as FooterComponent, V as AssistantMessageComponent, Vn as flushDiagnosticLogs, Vt as isBusy, W as BREATHE_CYCLE_MS, Wn as isScreamError, Xt as appendStreamingArgsPreview, Yt as STATUS_BULLET, Zt as argsRecord, _ as refreshUpdateCache, _n as isExperimentalFlagEnabled, _t as clearInfoPanelState, an as EMPTY_SESSION_HINT_URL, b as readJsonlFile, bn as PULSE_WAVE_FRAMES, bt as resolveThemeSync, c as hasDispose, cn as SESSION_TIPS, ct as handlePlanCommand, d as formatMemoryMemoForInjection, dn as getCtrlDHint, en as parseStreamingArgs, et as toTerminalHyperlink, fn as getLlmNotSetMessage, g as selectUpdateTarget, gn as sortSlashCommands, gt as supportsBalance, hn as BUILTIN_SLASH_COMMANDS, ht as refreshProviderBalance, i as buildRoleAdditionalText, in as CHARS_PER_TOKEN, j as highlightLines, jn as CLI_UI_MODE, jt as ENABLE_TERMINAL_THEME_REPORTING, k as renderDiffLines, kn as detectInstallSource, kt as DISABLE_TERMINAL_THEME_REPORTING, l as isPlanExpandable, ln as TIP_ROTATION_INTERVAL_MS, mn as buildSkillSlashCommands, n as clearEvalPanelState, nn as stringValue, nt as getModelCycleLevel, on as EXIT_CONFIRM_WINDOW_MS, ot as handleFusionPlanCommand, pn as getNoActiveSessionMessage, q as clearGoalState, qn as SCREAM_ERROR_INFO, r as openUrl, rn as truncateErrorMessage, s as disposeChildren, sn as MAIN_AGENT_ID, t as dispatchInput, tn as serializeToolResultOutput, tt as changeThinkingLevel, u as MoonLoader, un as getCtrlCHint, v as readUpdateCache, vn as setExperimentalFlags, w as UserMessageComponent, wn as saveTuiConfig, wt as contrastTextHex, xn as TuiConfigParseError, xt as createEditorTheme, y as appendJsonlLine, yn as PIXEL_PULSE_FRAMES, z as parseReadGroupOutput, zn as resolveScreamHome, zt as TERMINAL_THEME_DARK } from "./dispatch-202xtik3.mjs";
|
|
8
|
+
import { a as setLocale, o as t } from "./text-input-dialog-BzVVVncg.mjs";
|
|
9
9
|
import { createRequire } from "node:module";
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
11
|
import { access, mkdir, mkdtemp, readFile, readdir, realpath, rm, unlink, writeFile } from "node:fs/promises";
|
|
@@ -30,7 +30,7 @@ function optionalBuildString(value) {
|
|
|
30
30
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
31
31
|
}
|
|
32
32
|
const SCREAM_BUILD_INFO = {
|
|
33
|
-
version: optionalBuildString("0.
|
|
33
|
+
version: optionalBuildString("0.14.0"),
|
|
34
34
|
channel: optionalBuildString(""),
|
|
35
35
|
commit: optionalBuildString(""),
|
|
36
36
|
buildTarget: optionalBuildString("darwin-arm64")
|
|
@@ -2909,9 +2909,9 @@ var SessionEventHandler = class {
|
|
|
2909
2909
|
const { name, purpose } = event.candidate;
|
|
2910
2910
|
if (name.length === 0) return;
|
|
2911
2911
|
if (this.promptedSkillCandidates.has(name)) return;
|
|
2912
|
-
this.promptedSkillCandidates.add(name);
|
|
2913
2912
|
const session = this.host.session;
|
|
2914
2913
|
if (session === void 0) return;
|
|
2914
|
+
this.promptedSkillCandidates.add(name);
|
|
2915
2915
|
if (this.host.streamingUI.hasActiveTurn()) {
|
|
2916
2916
|
this.pendingSkillCandidates.push({
|
|
2917
2917
|
name,
|
|
@@ -12192,7 +12192,7 @@ var ScreamTUI = class {
|
|
|
12192
12192
|
const card = new OnboardingCardComponent({
|
|
12193
12193
|
colors: this.state.theme.colors,
|
|
12194
12194
|
onConfigure: () => {
|
|
12195
|
-
import("./dispatch-
|
|
12195
|
+
import("./dispatch-D71h_08g.mjs").then(({ handleConnectCommand }) => handleConnectCommand(this, "")).finally(() => {
|
|
12196
12196
|
this.restoreEditor();
|
|
12197
12197
|
});
|
|
12198
12198
|
},
|
|
@@ -13237,6 +13237,44 @@ function mapCcConnectMode(mode) {
|
|
|
13237
13237
|
};
|
|
13238
13238
|
}
|
|
13239
13239
|
}
|
|
13240
|
+
/**
|
|
13241
|
+
* Install the stdout EPIPE guard and return the line writer handed to
|
|
13242
|
+
* {@link ClaudeStreamJsonWriter}.
|
|
13243
|
+
*
|
|
13244
|
+
* cc-connect closes our stdout when it kills/restarts the agent (idle
|
|
13245
|
+
* timeout, /restart, config change). Writing after that raises EPIPE as an
|
|
13246
|
+
* unhandled error and crashes the process. The pipe is gone — results can
|
|
13247
|
+
* no longer be delivered — so exit quietly instead of burning tokens as a
|
|
13248
|
+
* zombie waiting for a signal that may never come.
|
|
13249
|
+
*
|
|
13250
|
+
* Both the `error` event on stdout and a throw from `stdout.write` are
|
|
13251
|
+
* covered: EPIPE → process.exit(0); any other error is surfaced (rethrown or
|
|
13252
|
+
* logged) so real I/O failures are not masked.
|
|
13253
|
+
*/
|
|
13254
|
+
function installStdoutEpipeGuard() {
|
|
13255
|
+
const handleStdoutClosed = () => {
|
|
13256
|
+
log.debug("stream-json: stdout closed (EPIPE), exiting");
|
|
13257
|
+
process.exit(0);
|
|
13258
|
+
};
|
|
13259
|
+
process.stdout.on("error", (error) => {
|
|
13260
|
+
if (error.code === "EPIPE") {
|
|
13261
|
+
handleStdoutClosed();
|
|
13262
|
+
return;
|
|
13263
|
+
}
|
|
13264
|
+
log.error("stream-json: stdout error", { error: String(error) });
|
|
13265
|
+
});
|
|
13266
|
+
return (line) => {
|
|
13267
|
+
try {
|
|
13268
|
+
process.stdout.write(`${line}\n`);
|
|
13269
|
+
} catch (error) {
|
|
13270
|
+
if (error.code === "EPIPE") {
|
|
13271
|
+
handleStdoutClosed();
|
|
13272
|
+
return;
|
|
13273
|
+
}
|
|
13274
|
+
throw error;
|
|
13275
|
+
}
|
|
13276
|
+
};
|
|
13277
|
+
}
|
|
13240
13278
|
async function runStreamJson(opts) {
|
|
13241
13279
|
const homeDir = resolveScreamHome();
|
|
13242
13280
|
const workDir = opts.workDir ?? process.cwd();
|
|
@@ -13257,9 +13295,7 @@ async function runStreamJson(opts) {
|
|
|
13257
13295
|
}
|
|
13258
13296
|
const streamSubagentModels = streamTuiConfig.subagentModels;
|
|
13259
13297
|
harness.setSubagentModelBindings(() => streamSubagentModels);
|
|
13260
|
-
const writer = new ClaudeStreamJsonWriter((
|
|
13261
|
-
process.stdout.write(`${line}\n`);
|
|
13262
|
-
});
|
|
13298
|
+
const writer = new ClaudeStreamJsonWriter(installStdoutEpipeGuard());
|
|
13263
13299
|
let session;
|
|
13264
13300
|
let currentSessionId;
|
|
13265
13301
|
let sessionKey = "cc-connect-main";
|
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import { i as __require, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-D90kvbyJ.mjs";
|
|
7
7
|
import { C as join$1, D as resolve$1, E as relative$1, S as isAbsolute$1, T as parse$7, a as isSupportedFile, b as basename$1, i as ingestFile, r as ingestDirectory, t as multiSearch, w as normalize, x as dirname$2, y as KnowledgeStore } from "./src-BH9W5k24.mjs";
|
|
8
8
|
import { t as require_base64_js } from "./base64-js-DzVmk6Nb.mjs";
|
|
9
|
-
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-
|
|
9
|
+
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-BzVVVncg.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
12
12
|
import * as fs$1 from "node:fs/promises";
|
|
@@ -64654,7 +64654,23 @@ function renderPrompt(template, vars) {
|
|
|
64654
64654
|
}
|
|
64655
64655
|
//#endregion
|
|
64656
64656
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/skill-tool.md
|
|
64657
|
-
var skill_tool_default = "Invoke a registered skill from the current skill listing. BLOCKING REQUIREMENT: when a skill from the listing matches the user's request, you MUST call this tool (not free-form text). Do NOT call the same skill repeatedly inside one turn — recursive depth is capped at {{ MAX_SKILL_QUERY_DEPTH }}.";
|
|
64657
|
+
var skill_tool_default = "Invoke a registered skill from the current skill listing. BLOCKING REQUIREMENT: when a skill from the listing matches the user's request, you MUST call this tool (not free-form text). Do NOT call the same skill repeatedly inside one turn — recursive depth is capped at {{ MAX_SKILL_QUERY_DEPTH }}.\n\n## Currently model-invocable skills\n{{ AVAILABLE_SKILLS }}\nThis list is a construction-time snapshot; for the live catalog inspect the skill registry.";
|
|
64658
|
+
/** Max skills to list inline in the tool description; rest are summarized. */
|
|
64659
|
+
const MAX_INLINE_SKILLS = 15;
|
|
64660
|
+
/** Max description length per skill line. */
|
|
64661
|
+
const MAX_SKILL_DESC_CHARS = 100;
|
|
64662
|
+
function buildSkillToolDescription(agent) {
|
|
64663
|
+
const skills = agent.skills?.registry.listInvocableSkills() ?? [];
|
|
64664
|
+
const lines = skills.slice(0, MAX_INLINE_SKILLS).map((s) => {
|
|
64665
|
+
const desc = s.description.trim().replaceAll(/\n/g, " ").slice(0, MAX_SKILL_DESC_CHARS);
|
|
64666
|
+
return `- ${s.name}: ${desc}`;
|
|
64667
|
+
});
|
|
64668
|
+
if (skills.length > MAX_INLINE_SKILLS) lines.push(`…${String(skills.length - MAX_INLINE_SKILLS)} more (see skill registry)`);
|
|
64669
|
+
return renderPrompt(skill_tool_default, {
|
|
64670
|
+
MAX_SKILL_QUERY_DEPTH: 3,
|
|
64671
|
+
AVAILABLE_SKILLS: lines.length > 0 ? lines.join("\n") : "(none currently registered)"
|
|
64672
|
+
});
|
|
64673
|
+
}
|
|
64658
64674
|
var NestedSkillTooDeepError = class extends Error {
|
|
64659
64675
|
skillName;
|
|
64660
64676
|
depth;
|
|
@@ -64674,11 +64690,12 @@ var SkillTool = class SkillTool {
|
|
|
64674
64690
|
agent;
|
|
64675
64691
|
options;
|
|
64676
64692
|
name = "Skill";
|
|
64677
|
-
description
|
|
64693
|
+
description;
|
|
64678
64694
|
parameters = toInputJsonSchema(SkillToolInputSchema);
|
|
64679
64695
|
constructor(agent, options = {}) {
|
|
64680
64696
|
this.agent = agent;
|
|
64681
64697
|
this.options = options;
|
|
64698
|
+
this.description = buildSkillToolDescription(agent);
|
|
64682
64699
|
}
|
|
64683
64700
|
resolveExecution(args) {
|
|
64684
64701
|
return {
|
|
@@ -76706,10 +76723,10 @@ function stripContextMetadata(message) {
|
|
|
76706
76723
|
}
|
|
76707
76724
|
//#endregion
|
|
76708
76725
|
//#region ../../packages/agent-core/src/agent/compaction/compaction-instruction.md
|
|
76709
|
-
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)
|
|
76726
|
+
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) after the summary — 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 after the summary (the skill-candidate marker line described below comes after all memory-memo blocks):\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). Then output exactly\none marker as the very LAST line of your response — after all memory-memo\nblocks:\n\n- If a process is genuinely worth capturing as a reusable skill (reusable\n beyond this one task — do not emit for one-off actions; the evidence must\n be concrete and verifiable: exact file paths, commands, or step sequences\n from the conversation, e.g. \"run `pnpm vitest run -t compaction` in\n packages/agent-core to reproduce the compaction snapshots\". Vague evidence\n like \"used a script\" is not acceptable):\n\n[[skill-candidate: <name>|<one-line purpose>|<evidence>]]\n\n- If none exists, output instead:\n\n[[skill-candidate: none]]\n\nThis marker line is MANDATORY — never omit it, and output at most one\ncandidate marker.\n";
|
|
76710
76727
|
//#endregion
|
|
76711
76728
|
//#region ../../packages/agent-core/src/agent/compaction/compaction-update-instruction.md
|
|
76712
|
-
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)
|
|
76729
|
+
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) after the updated summary — 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 after the updated summary (the skill-candidate marker line described below comes after all memory-memo blocks):\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<!-- Skill Candidate Detection (after memory-memo) -->\n\n## Skill candidates\n\nAFTER the memory-memo block(s), scan ONLY the new messages being compacted\n(not the content already covered by the previous summary — candidates from\nolder messages were already considered) for reusable processes\n(project-specific build steps, recurring debugging patterns, or tool\nworkflows). Then output exactly one marker as the very LAST line of your\nresponse — after all memory-memo blocks:\n\n- If a process is genuinely worth capturing as a reusable skill (reusable\n beyond this one task — do not emit for one-off actions; the evidence must\n be concrete and verifiable: exact file paths, commands, or step sequences\n from the new messages):\n\n[[skill-candidate: <name>|<one-line purpose>|<evidence>]]\n\n- If none exists, output instead:\n\n[[skill-candidate: none]]\n\nThis marker line is MANDATORY — never omit it, and output at most one\ncandidate marker.\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";
|
|
76713
76730
|
//#endregion
|
|
76714
76731
|
//#region ../../packages/agent-core/src/agent/compaction/render-messages.ts
|
|
76715
76732
|
const TOOL_RESULT_MAX_CHARS = 2e3;
|
|
@@ -77157,7 +77174,7 @@ var FullCompaction = class {
|
|
|
77157
77174
|
blockedByTurn: false
|
|
77158
77175
|
};
|
|
77159
77176
|
this.compacting = active;
|
|
77160
|
-
active.promise = this.compactionWorker(abortController.signal, data, compactedCount);
|
|
77177
|
+
active.promise = this.compactionWorker(abortController.signal, data, compactedCount, active);
|
|
77161
77178
|
}
|
|
77162
77179
|
cancel() {
|
|
77163
77180
|
this.markCanceled();
|
|
@@ -77186,6 +77203,13 @@ var FullCompaction = class {
|
|
|
77186
77203
|
this.lowWaterMark = 0;
|
|
77187
77204
|
this.reactiveAttempted = false;
|
|
77188
77205
|
}
|
|
77206
|
+
/** The low-water mark is measured against the model's context window, so a
|
|
77207
|
+
* model switch (different max_context_tokens) invalidates it. Without a
|
|
77208
|
+
* reset, a stale mark from a large model can mask the overflow threshold
|
|
77209
|
+
* of a smaller model and suppress compaction until the provider overflows. */
|
|
77210
|
+
resetLowWaterMark() {
|
|
77211
|
+
this.lowWaterMark = 0;
|
|
77212
|
+
}
|
|
77189
77213
|
async handleOverflowError(signal, error) {
|
|
77190
77214
|
if (this.reactiveAttempted) throw error;
|
|
77191
77215
|
if (!this.beginAutoCompaction(false) && !this.compacting) {
|
|
@@ -77197,6 +77221,12 @@ var FullCompaction = class {
|
|
|
77197
77221
|
throw error;
|
|
77198
77222
|
}
|
|
77199
77223
|
this.reactiveAttempted = true;
|
|
77224
|
+
if (this.compacting) try {
|
|
77225
|
+
await this.block(signal);
|
|
77226
|
+
} catch (blockError) {
|
|
77227
|
+
if (signal.aborted || isAbortError$1(blockError)) throw blockError;
|
|
77228
|
+
throw error;
|
|
77229
|
+
}
|
|
77200
77230
|
}
|
|
77201
77231
|
async beforeStep(signal) {
|
|
77202
77232
|
this.agent.microCompaction.detect();
|
|
@@ -77246,13 +77276,14 @@ var FullCompaction = class {
|
|
|
77246
77276
|
async block(signal) {
|
|
77247
77277
|
const active = this.compacting;
|
|
77248
77278
|
if (!active) return;
|
|
77279
|
+
signal.throwIfAborted();
|
|
77249
77280
|
active.blockedByTurn = true;
|
|
77250
77281
|
const timeoutId = setTimeout(() => {
|
|
77251
77282
|
if (this.compacting === active) {
|
|
77252
77283
|
this.compactionTimedOut = true;
|
|
77253
|
-
this.markCanceled("压缩超时(
|
|
77284
|
+
this.markCanceled("压缩超时(120秒),已取消。请使用 /compact 手动重试。");
|
|
77254
77285
|
}
|
|
77255
|
-
},
|
|
77286
|
+
}, 12e4);
|
|
77256
77287
|
const onAbort = () => {
|
|
77257
77288
|
clearTimeout(timeoutId);
|
|
77258
77289
|
if (this.compacting === active) this.cancel();
|
|
@@ -77269,7 +77300,7 @@ var FullCompaction = class {
|
|
|
77269
77300
|
signal.removeEventListener("abort", onAbort);
|
|
77270
77301
|
}
|
|
77271
77302
|
}
|
|
77272
|
-
async compactionWorker(signal, data, compactedCount) {
|
|
77303
|
+
async compactionWorker(signal, data, compactedCount, owner) {
|
|
77273
77304
|
const originalHistory = [...this.agent.context.history];
|
|
77274
77305
|
const systemPromptTokens = estimateTokens$1(this.agent.getRuntimeSystemPrompt());
|
|
77275
77306
|
const toolTokens = estimateTokensForTools(this.agent.tools.loopTools);
|
|
@@ -77309,24 +77340,27 @@ var FullCompaction = class {
|
|
|
77309
77340
|
} catch (error) {
|
|
77310
77341
|
if (error instanceof APIContextOverflowError || error instanceof TruncatedError) {
|
|
77311
77342
|
const reduced = this.strategy.reduceCompactOnOverflow(messagesToCompact);
|
|
77312
|
-
if (reduced < compactedCount)
|
|
77313
|
-
|
|
77314
|
-
|
|
77315
|
-
compactedCount,
|
|
77316
|
-
tokensBefore: estimateTokensForMessages(messagesToCompact)
|
|
77317
|
-
});
|
|
77318
|
-
const result = await summarizeWithFallback(messagesToCompact, summarizeOnce);
|
|
77319
|
-
summary = result.summary;
|
|
77320
|
-
usage = result.usage;
|
|
77321
|
-
break;
|
|
77343
|
+
if (reduced < compactedCount) {
|
|
77344
|
+
compactedCount = reduced;
|
|
77345
|
+
continue;
|
|
77322
77346
|
}
|
|
77323
|
-
|
|
77347
|
+
this.agent.log.warn("compaction overflow at minimum split, falling back to re-summarize", {
|
|
77348
|
+
compactedCount,
|
|
77349
|
+
tokensBefore: estimateTokensForMessages(messagesToCompact)
|
|
77350
|
+
});
|
|
77351
|
+
const result = await summarizeWithFallback(messagesToCompact, summarizeOnce);
|
|
77352
|
+
summary = result.summary;
|
|
77353
|
+
usage = result.usage;
|
|
77354
|
+
break;
|
|
77355
|
+
}
|
|
77356
|
+
if (!isRetryableGenerateError(error)) throw error;
|
|
77324
77357
|
if (retryCount + 1 >= 5) throw error;
|
|
77325
|
-
await sleepForRetry(delays
|
|
77358
|
+
await sleepForRetry(computeDelayMs(error, delays, retryCount + 1), signal);
|
|
77326
77359
|
retryCount += 1;
|
|
77327
77360
|
}
|
|
77328
77361
|
}
|
|
77329
77362
|
if (usage !== null) this.agent.usage.record(model, usage);
|
|
77363
|
+
if (this.compacting !== owner) return void 0;
|
|
77330
77364
|
const newHistory = this.agent.context.history;
|
|
77331
77365
|
for (let i = 0; i < originalHistory.length; i++) if (newHistory[i] !== originalHistory[i]) {
|
|
77332
77366
|
this.markCanceled("上下文已被更改(如 /revoke),压缩已取消");
|
|
@@ -77341,6 +77375,7 @@ var FullCompaction = class {
|
|
|
77341
77375
|
} else this.lastCompactionFiles = void 0;
|
|
77342
77376
|
for (const msg of messagesToCompactForOps) extractFileOpsFromMessage(msg, fileOps);
|
|
77343
77377
|
const toolCallHistory = formatToolCallHistory(messagesToCompactForOps);
|
|
77378
|
+
const skillCandidateSummary = summary;
|
|
77344
77379
|
const processedSummary = this.postProcessSummary(summary, fileOps, toolCallHistory, compactedCount);
|
|
77345
77380
|
const tokensAfter = systemPromptTokens + toolTokens + estimateTokens$1(processedSummary) + estimateTokensForMessages(recent);
|
|
77346
77381
|
const fileLists = computeFileLists(fileOps);
|
|
@@ -77366,20 +77401,23 @@ var FullCompaction = class {
|
|
|
77366
77401
|
this.lowWaterMark = Math.floor(this.effectiveTokenCount * 1.1);
|
|
77367
77402
|
await this.extractAndStoreMemos(processedSummary, messagesToCompactForOps);
|
|
77368
77403
|
this.triggerPostCompactHook(data, result);
|
|
77369
|
-
this.detectSkillCandidates(
|
|
77404
|
+
this.detectSkillCandidates(skillCandidateSummary);
|
|
77370
77405
|
this.consecutiveCompactionFailures = 0;
|
|
77371
77406
|
this._shouldInjectSessionSummary = true;
|
|
77372
77407
|
} catch (error) {
|
|
77373
|
-
const
|
|
77374
|
-
|
|
77408
|
+
const stale = this.compacting !== null && this.compacting !== owner;
|
|
77409
|
+
const wasTimedOut = stale ? false : this.compactionTimedOut;
|
|
77410
|
+
if (!stale) this.compactionTimedOut = false;
|
|
77375
77411
|
if (!isAbortError$1(error) || wasTimedOut) {
|
|
77376
|
-
const blockedByTurn =
|
|
77377
|
-
|
|
77378
|
-
|
|
77379
|
-
|
|
77380
|
-
|
|
77381
|
-
|
|
77382
|
-
|
|
77412
|
+
const blockedByTurn = stale || owner.blockedByTurn === true;
|
|
77413
|
+
if (!stale) {
|
|
77414
|
+
this.consecutiveCompactionFailures += 1;
|
|
77415
|
+
if (this.consecutiveCompactionFailures >= MAX_CONSECUTIVE_FAILURES) this.agent.emitEvent({
|
|
77416
|
+
type: "warning",
|
|
77417
|
+
message: `压缩连续失败 ${String(this.consecutiveCompactionFailures)} 次,已自动暂停本回合的自动压缩。使用 /compact 手动重试。`,
|
|
77418
|
+
code: "compaction_circuit_open"
|
|
77419
|
+
});
|
|
77420
|
+
}
|
|
77383
77421
|
this.agent.log.error("compaction failed", {
|
|
77384
77422
|
code: isScreamError(error) ? error.code : void 0,
|
|
77385
77423
|
error,
|
|
@@ -77388,7 +77426,7 @@ var FullCompaction = class {
|
|
|
77388
77426
|
compactedCount,
|
|
77389
77427
|
tokensBefore
|
|
77390
77428
|
});
|
|
77391
|
-
this.markCanceled();
|
|
77429
|
+
if (!stale) this.markCanceled();
|
|
77392
77430
|
if (!blockedByTurn) {
|
|
77393
77431
|
const details = {
|
|
77394
77432
|
model,
|
|
@@ -77400,7 +77438,7 @@ var FullCompaction = class {
|
|
|
77400
77438
|
...payload
|
|
77401
77439
|
});
|
|
77402
77440
|
}
|
|
77403
|
-
if (blockedByTurn) {
|
|
77441
|
+
if (blockedByTurn && !stale) {
|
|
77404
77442
|
if (isScreamError(error) && error.code === ErrorCodes.AUTH_LOGIN_REQUIRED) throw error;
|
|
77405
77443
|
throw new ScreamError(ErrorCodes.COMPACTION_FAILED, String(error), { cause: error });
|
|
77406
77444
|
}
|
|
@@ -77491,27 +77529,41 @@ var FullCompaction = class {
|
|
|
77491
77529
|
}
|
|
77492
77530
|
/**
|
|
77493
77531
|
* Detects [[skill-candidate: <name>|<purpose>|<evidence>]] markers in the
|
|
77494
|
-
* compaction summary and emits a `skill_candidate` event
|
|
77495
|
-
*
|
|
77496
|
-
*
|
|
77497
|
-
*
|
|
77532
|
+
* compaction summary and emits a `skill_candidate` event (at most one per
|
|
77533
|
+
* compact). Best-effort and fully isolated: a parse failure or a missing
|
|
77534
|
+
* marker never affects compaction or memory extraction — this method only
|
|
77535
|
+
* reads the summary and emits an event.
|
|
77536
|
+
*
|
|
77537
|
+
* Tolerant parsing: the evidence segment may contain `|` characters and
|
|
77538
|
+
* newlines, and the explicit `[[skill-candidate: none]]` marker (emitted
|
|
77539
|
+
* when the model found nothing) is recognized and skipped. When several
|
|
77540
|
+
* markers appear (e.g. an old one carried over into an update summary),
|
|
77541
|
+
* the LAST valid candidate wins — the templates mandate the marker as the
|
|
77542
|
+
* final line of the response, so the trailing one is the model's verdict
|
|
77543
|
+
* for this round.
|
|
77498
77544
|
*/
|
|
77499
77545
|
detectSkillCandidates(summary) {
|
|
77500
77546
|
try {
|
|
77501
|
-
const matches = summary.matchAll(/\[\[skill-candidate:\s*([^|\]]
|
|
77547
|
+
const matches = summary.matchAll(/\[\[skill-candidate:\s*([^|\]]+?)(?:\|([^|\]]*)\|([\s\S]*?))?\]\]/g);
|
|
77548
|
+
let chosen;
|
|
77502
77549
|
for (const m of matches) {
|
|
77503
|
-
const name = m[1]
|
|
77550
|
+
const name = m[1]?.trim() ?? "";
|
|
77504
77551
|
if (name.length === 0) continue;
|
|
77505
|
-
|
|
77506
|
-
|
|
77507
|
-
|
|
77508
|
-
|
|
77509
|
-
|
|
77510
|
-
|
|
77511
|
-
|
|
77512
|
-
|
|
77513
|
-
|
|
77552
|
+
if (name.toLowerCase() === "none") {
|
|
77553
|
+
chosen = void 0;
|
|
77554
|
+
continue;
|
|
77555
|
+
}
|
|
77556
|
+
if (m[2] === void 0) continue;
|
|
77557
|
+
chosen = {
|
|
77558
|
+
name,
|
|
77559
|
+
purpose: m[2].trim(),
|
|
77560
|
+
evidence: (m[3] ?? "").trim()
|
|
77561
|
+
};
|
|
77514
77562
|
}
|
|
77563
|
+
if (chosen !== void 0) this.agent.emitEvent({
|
|
77564
|
+
type: "skill_candidate",
|
|
77565
|
+
candidate: chosen
|
|
77566
|
+
});
|
|
77515
77567
|
} catch (error) {
|
|
77516
77568
|
this.agent.log.warn("Skill candidate detection failed", { error: String(error) });
|
|
77517
77569
|
}
|
|
@@ -77529,7 +77581,7 @@ var FullCompaction = class {
|
|
|
77529
77581
|
*/
|
|
77530
77582
|
postProcessSummary(summary, fileOps, toolCallHistory, compactedCount) {
|
|
77531
77583
|
const todos = this.agent.tools.storeData()["todo"] ?? [];
|
|
77532
|
-
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();
|
|
77584
|
+
const base = summary.trim().replaceAll(/<files>[\s\S]*?<\/files>\s*/g, "").replaceAll(/\[\[skill-candidate:[\s\S]*?\]\]\s*/g, "").replace(/^> The conversation before this point was compacted:[\s\S]*?continue from here\.\s*\n+/m, "").trimEnd();
|
|
77533
77585
|
const sections = [];
|
|
77534
77586
|
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.`);
|
|
77535
77587
|
if (base.length > 0) sections.push(base);
|
|
@@ -78855,7 +78907,10 @@ var ConfigState = class {
|
|
|
78855
78907
|
this._cwd = changed.cwd;
|
|
78856
78908
|
this.agent.jian.chdir(changed.cwd);
|
|
78857
78909
|
}
|
|
78858
|
-
if (changed.modelAlias
|
|
78910
|
+
if (changed.modelAlias && changed.modelAlias !== this._modelAlias) {
|
|
78911
|
+
this._modelAlias = changed.modelAlias;
|
|
78912
|
+
this.agent.fullCompaction.resetLowWaterMark();
|
|
78913
|
+
}
|
|
78859
78914
|
if (changed.profileName) this._profileName = changed.profileName;
|
|
78860
78915
|
if (changed.thinkingLevel !== void 0) this._thinkingLevel = resolveThinkingEffort(changed.thinkingLevel, this.agent.screamConfig?.thinking);
|
|
78861
78916
|
if (changed.systemPrompt !== void 0) this._systemPrompt = changed.systemPrompt;
|
|
@@ -129417,7 +129472,7 @@ async function guidedGoalSetup(host) {
|
|
|
129417
129472
|
host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
|
|
129418
129473
|
return;
|
|
129419
129474
|
}
|
|
129420
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
129475
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-DVWsE7Gh.mjs");
|
|
129421
129476
|
const initialDesc = await promptText(host, TextInputDialogComponent, {
|
|
129422
129477
|
title: t("goal.setup_title_initial"),
|
|
129423
129478
|
subtitle: t("goal.setup_desc_hint"),
|
|
@@ -129438,7 +129493,7 @@ async function guidedGoalSetup(host) {
|
|
|
129438
129493
|
await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
|
|
129439
129494
|
}
|
|
129440
129495
|
async function showGoalConfigWizard(host, session, objective, replace) {
|
|
129441
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
129496
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-DVWsE7Gh.mjs");
|
|
129442
129497
|
const turnInput = await promptNumber(host, TextInputDialogComponent, {
|
|
129443
129498
|
title: t("goal.wizard_title", { objective }),
|
|
129444
129499
|
subtitle: t("goal.budget_turns_hint"),
|
|
@@ -131524,16 +131579,16 @@ const renderTruncated = (_toolCall, result, ctx) => {
|
|
|
131524
131579
|
var ShellExecutionComponent = class extends Container {
|
|
131525
131580
|
constructor(options) {
|
|
131526
131581
|
super();
|
|
131527
|
-
if (options.showCommand === true) this.addCommandPreview(options.command ?? "", options.commandPreviewLines);
|
|
131582
|
+
if (options.showCommand === true) this.addCommandPreview(options.command ?? "", options.commandPreviewLines, options.colors);
|
|
131528
131583
|
if (options.result !== void 0) this.addResultPreview(options.result, options.colors, options.expanded ?? false, options.resultPreviewLines ?? 15);
|
|
131529
131584
|
}
|
|
131530
|
-
addCommandPreview(command, previewLines) {
|
|
131585
|
+
addCommandPreview(command, previewLines, colors) {
|
|
131531
131586
|
if (command.length === 0) return;
|
|
131532
|
-
const allLines = command
|
|
131587
|
+
const allLines = highlightLines(command, "bash", colors);
|
|
131533
131588
|
const lines = previewLines === void 0 ? allLines : allLines.slice(0, previewLines);
|
|
131534
131589
|
for (const [i, line] of lines.entries()) {
|
|
131535
131590
|
const prefix = i === 0 ? "$ " : " ";
|
|
131536
|
-
this.addChild(new Text(chalk.dim(prefix
|
|
131591
|
+
this.addChild(new Text(`${chalk.dim(prefix)}${line}`, 2, 0));
|
|
131537
131592
|
}
|
|
131538
131593
|
}
|
|
131539
131594
|
addResultPreview(result, colors, expanded, previewLines) {
|
|
@@ -131554,8 +131609,8 @@ const shellExecutionResultRenderer = (toolCall, result, ctx) => [new ShellExecut
|
|
|
131554
131609
|
result,
|
|
131555
131610
|
colors: ctx.colors,
|
|
131556
131611
|
expanded: ctx.expanded,
|
|
131557
|
-
showCommand:
|
|
131558
|
-
commandPreviewLines: void 0
|
|
131612
|
+
showCommand: true,
|
|
131613
|
+
commandPreviewLines: ctx.expanded ? void 0 : 3
|
|
131559
131614
|
})];
|
|
131560
131615
|
//#endregion
|
|
131561
131616
|
//#region src/tui/components/media/image-thumbnail.ts
|
|
@@ -131834,6 +131889,26 @@ function pickChip(toolName) {
|
|
|
131834
131889
|
return REGISTRY[toolName];
|
|
131835
131890
|
}
|
|
131836
131891
|
//#endregion
|
|
131892
|
+
//#region src/tui/components/messages/tool-renderers/glance-lines.ts
|
|
131893
|
+
/**
|
|
131894
|
+
* Renders pre-composed glance lines (ANSI-colored) with hard per-line
|
|
131895
|
+
* truncation to the actual render width. Unlike `Text`, long lines never
|
|
131896
|
+
* wrap — each logical line always occupies exactly one visual row, so
|
|
131897
|
+
* column-aligned samples (Grep matches) never break their alignment on
|
|
131898
|
+
* narrow terminals.
|
|
131899
|
+
*/
|
|
131900
|
+
var GlanceLinesComponent = class {
|
|
131901
|
+
lines;
|
|
131902
|
+
constructor(lines) {
|
|
131903
|
+
this.lines = lines;
|
|
131904
|
+
}
|
|
131905
|
+
invalidate() {}
|
|
131906
|
+
render(width) {
|
|
131907
|
+
const safeWidth = Math.max(width, 1);
|
|
131908
|
+
return this.lines.map((line) => truncateToWidth(` ${line}`, safeWidth, "…"));
|
|
131909
|
+
}
|
|
131910
|
+
};
|
|
131911
|
+
//#endregion
|
|
131837
131912
|
//#region src/tui/components/messages/tool-renderers/summary.ts
|
|
131838
131913
|
const GLANCE_SAMPLES = 3;
|
|
131839
131914
|
const MAX_EXTENSION_COUNTS = 4;
|
|
@@ -131843,11 +131918,13 @@ function withGlance(glance) {
|
|
|
131843
131918
|
if (result.is_error) return renderTruncated(toolCall, result, ctx);
|
|
131844
131919
|
const out = [];
|
|
131845
131920
|
if (glance !== null) {
|
|
131846
|
-
const
|
|
131847
|
-
if (
|
|
131848
|
-
|
|
131849
|
-
|
|
131850
|
-
|
|
131921
|
+
const glanceOut = glance(toolCall, result, ctx.colors);
|
|
131922
|
+
if (typeof glanceOut === "string") {
|
|
131923
|
+
if (glanceOut.length > 0) {
|
|
131924
|
+
const indented = glanceOut.split("\n").map((l) => ` ${l}`).join("\n");
|
|
131925
|
+
out.push(new Text(indented, 0, 0));
|
|
131926
|
+
}
|
|
131927
|
+
} else out.push(glanceOut);
|
|
131851
131928
|
}
|
|
131852
131929
|
if (ctx.expanded && result.output.length > 0) out.push(new Text(chalk.dim(result.output), 4, 0));
|
|
131853
131930
|
return out;
|
|
@@ -131870,29 +131947,35 @@ function readSearchResultsMatches(result) {
|
|
|
131870
131947
|
if (display.kind !== "search_results") return void 0;
|
|
131871
131948
|
return display.matches;
|
|
131872
131949
|
}
|
|
131873
|
-
function
|
|
131874
|
-
|
|
131875
|
-
|
|
131950
|
+
function styleFilePath(path) {
|
|
131951
|
+
const idx = path.lastIndexOf("/");
|
|
131952
|
+
if (idx < 0) return path;
|
|
131953
|
+
return `${chalk.dim(path.slice(0, idx + 1))}${path.slice(idx + 1)}`;
|
|
131876
131954
|
}
|
|
131877
131955
|
const grepGlance = (_toolCall, result, colors) => {
|
|
131878
131956
|
const matches = readSearchResultsMatches(result);
|
|
131879
131957
|
if (matches !== void 0 && matches.length > 0) {
|
|
131880
|
-
const
|
|
131881
|
-
const
|
|
131882
|
-
|
|
131958
|
+
const samples = matches.slice(0, GLANCE_SAMPLES);
|
|
131959
|
+
const plainLocs = samples.map((m) => m.line > 0 ? `${m.file}:${String(m.line)}` : m.file);
|
|
131960
|
+
const colWidth = Math.max(...plainLocs.map((s) => visibleWidth(s)));
|
|
131961
|
+
const lineNoColor = chalk.hex(colors.roleTool);
|
|
131962
|
+
const lines = samples.map((m, i) => {
|
|
131963
|
+
const loc = m.line > 0 ? `${styleFilePath(m.file)}${chalk.dim(":")}${lineNoColor(String(m.line))}` : styleFilePath(m.file);
|
|
131964
|
+
const pad = " ".repeat(Math.max(0, colWidth - visibleWidth(plainLocs[i] ?? "")));
|
|
131965
|
+
const text = m.text.trim();
|
|
131966
|
+
return text.length > 0 ? `${loc}${pad} ${chalk.dim(text)}` : `${loc}${pad}`;
|
|
131883
131967
|
});
|
|
131884
131968
|
const remaining = matches.length - GLANCE_SAMPLES;
|
|
131885
131969
|
if (remaining > 0) lines.push(chalk.dim(`+${String(remaining)} more`));
|
|
131886
|
-
return lines
|
|
131970
|
+
return new GlanceLinesComponent(lines);
|
|
131887
131971
|
}
|
|
131888
131972
|
const lines = nonEmptyLines(result.output);
|
|
131889
131973
|
if (lines.length === 0) return "";
|
|
131890
131974
|
const samples = lines.slice(0, GLANCE_SAMPLES).map(pathFromGrepLine);
|
|
131891
131975
|
const remaining = lines.length - samples.length;
|
|
131892
|
-
const
|
|
131893
|
-
const out = samples.map((s) => fileColor(s));
|
|
131976
|
+
const out = samples.map((s) => styleFilePath(s));
|
|
131894
131977
|
if (remaining > 0) out.push(chalk.dim(`+${String(remaining)} more`));
|
|
131895
|
-
return out
|
|
131978
|
+
return new GlanceLinesComponent(out);
|
|
131896
131979
|
};
|
|
131897
131980
|
function fileBasename(path) {
|
|
131898
131981
|
const idx = path.lastIndexOf("/");
|
|
@@ -134037,7 +134120,7 @@ async function findCcConnectResidualPaths(excludePath) {
|
|
|
134037
134120
|
existing.push(p);
|
|
134038
134121
|
} catch {}
|
|
134039
134122
|
}
|
|
134040
|
-
return existing.
|
|
134123
|
+
return existing.toSorted();
|
|
134041
134124
|
}
|
|
134042
134125
|
async function handleCcCommand(host) {
|
|
134043
134126
|
const daemon = resolveDaemonMode();
|
|
@@ -134077,7 +134160,7 @@ function runLifecycleAction(host, daemon, action) {
|
|
|
134077
134160
|
host.refreshCcStatus();
|
|
134078
134161
|
} else host.showError(t("cc.start_failed", {
|
|
134079
134162
|
label,
|
|
134080
|
-
output: output || "
|
|
134163
|
+
output: output || t("cc.unknown_error")
|
|
134081
134164
|
}));
|
|
134082
134165
|
})();
|
|
134083
134166
|
}
|
|
@@ -134087,7 +134170,7 @@ function buildUninstallSummary(daemon, install, residualPaths = []) {
|
|
|
134087
134170
|
t("cc.will_clean"),
|
|
134088
134171
|
t("cc.clean_daemon", { label: daemon.method }),
|
|
134089
134172
|
t("cc.clean_config", { detail: t("cc.clean_config.detail") }),
|
|
134090
|
-
"
|
|
134173
|
+
t("cc.uninstall_step_npm")
|
|
134091
134174
|
];
|
|
134092
134175
|
if (install.version) lines.push(t("cc.current_version", { version: install.version }));
|
|
134093
134176
|
if (install.entry) lines.push(t("cc.install_path", { path: install.entry }));
|
|
@@ -135034,9 +135117,92 @@ function getPlatforms() {
|
|
|
135034
135117
|
type: "wecom",
|
|
135035
135118
|
setupCmd: "wecom setup --project default",
|
|
135036
135119
|
note: t("ccconnect.note_wecom")
|
|
135120
|
+
},
|
|
135121
|
+
{
|
|
135122
|
+
name: "QQ 官方 bot",
|
|
135123
|
+
type: "qqbot",
|
|
135124
|
+
setupCmd: "qqbot setup --project default"
|
|
135125
|
+
},
|
|
135126
|
+
{
|
|
135127
|
+
name: "LINE",
|
|
135128
|
+
type: "line",
|
|
135129
|
+
setupCmd: "line setup --project default"
|
|
135130
|
+
},
|
|
135131
|
+
{
|
|
135132
|
+
name: "微博",
|
|
135133
|
+
type: "weibo",
|
|
135134
|
+
setupCmd: "weibo setup --project default"
|
|
135135
|
+
},
|
|
135136
|
+
{
|
|
135137
|
+
name: "WPS 协作",
|
|
135138
|
+
type: "wps-xiezuo",
|
|
135139
|
+
setupCmd: "wps-xiezuo setup --project default"
|
|
135140
|
+
},
|
|
135141
|
+
{
|
|
135142
|
+
name: "Matrix",
|
|
135143
|
+
type: "matrix",
|
|
135144
|
+
setupCmd: "matrix setup --project default",
|
|
135145
|
+
note: t("ccconnect.note_matrix")
|
|
135146
|
+
},
|
|
135147
|
+
{
|
|
135148
|
+
name: "Cisco Webex",
|
|
135149
|
+
type: "webex",
|
|
135150
|
+
setupCmd: "webex setup --project default",
|
|
135151
|
+
note: t("ccconnect.note_webex")
|
|
135152
|
+
},
|
|
135153
|
+
{
|
|
135154
|
+
name: "MAX",
|
|
135155
|
+
type: "max",
|
|
135156
|
+
setupCmd: "max setup --project default",
|
|
135157
|
+
note: t("ccconnect.note_max")
|
|
135158
|
+
},
|
|
135159
|
+
{
|
|
135160
|
+
name: "Google Chat",
|
|
135161
|
+
type: "googlechat",
|
|
135162
|
+
setupCmd: "googlechat setup --project default",
|
|
135163
|
+
note: t("ccconnect.note_googlechat")
|
|
135164
|
+
},
|
|
135165
|
+
{
|
|
135166
|
+
name: "Cloud Web",
|
|
135167
|
+
type: "cloud_web",
|
|
135168
|
+
setupCmd: "cloud_web setup --project default",
|
|
135169
|
+
note: t("ccconnect.note_cloud_web")
|
|
135170
|
+
},
|
|
135171
|
+
{
|
|
135172
|
+
name: "腾讯元宝",
|
|
135173
|
+
type: "yuanbao",
|
|
135174
|
+
setupCmd: "yuanbao setup --project default",
|
|
135175
|
+
note: t("ccconnect.note_yuanbao")
|
|
135176
|
+
},
|
|
135177
|
+
{
|
|
135178
|
+
name: "Tuitui",
|
|
135179
|
+
type: "tuitui",
|
|
135180
|
+
setupCmd: "tuitui setup --project default",
|
|
135181
|
+
note: t("ccconnect.note_tuitui")
|
|
135182
|
+
},
|
|
135183
|
+
{
|
|
135184
|
+
name: "WPS 数字员工",
|
|
135185
|
+
type: "wps-agentspace",
|
|
135186
|
+
setupCmd: "wps-agentspace setup --project default",
|
|
135187
|
+
note: t("ccconnect.note_wps_agentspace")
|
|
135037
135188
|
}
|
|
135038
135189
|
];
|
|
135039
135190
|
}
|
|
135191
|
+
/**
|
|
135192
|
+
* Platform types introduced by cc-connect v1.4/v1.5. Older cc-connect
|
|
135193
|
+
* binaries do not recognise these, so the post-config notice tells the user
|
|
135194
|
+
* to update cc-connect first.
|
|
135195
|
+
*/
|
|
135196
|
+
const NEW_PLATFORM_TYPES = new Set([
|
|
135197
|
+
"matrix",
|
|
135198
|
+
"webex",
|
|
135199
|
+
"max",
|
|
135200
|
+
"googlechat",
|
|
135201
|
+
"cloud_web",
|
|
135202
|
+
"yuanbao",
|
|
135203
|
+
"tuitui",
|
|
135204
|
+
"wps-agentspace"
|
|
135205
|
+
]);
|
|
135040
135206
|
const CONFIG_PATH = join(homedir(), ".cc-connect", "config.toml");
|
|
135041
135207
|
function checkCcConnect() {
|
|
135042
135208
|
try {
|
|
@@ -135051,43 +135217,80 @@ function checkCcConnect() {
|
|
|
135051
135217
|
return { installed: false };
|
|
135052
135218
|
}
|
|
135053
135219
|
}
|
|
135220
|
+
/** Auto-detect the path to the scream binary, including the stream-json subcommand. */
|
|
135054
135221
|
function detectScreamPath() {
|
|
135222
|
+
const execBase = process.execPath.toLowerCase();
|
|
135223
|
+
if (execBase.endsWith("/scream") || execBase.endsWith("\\scream") || execBase.endsWith("scream.exe")) return `${quoteShellPath(process.execPath)} stream-json`;
|
|
135224
|
+
if (execBase.includes("node") && process.argv[1]) {
|
|
135225
|
+
const arg1 = process.argv[1];
|
|
135226
|
+
if (arg1.includes("scream-code") || arg1.includes("scream")) return `node ${quoteShellPath(arg1)} stream-json`;
|
|
135227
|
+
}
|
|
135055
135228
|
try {
|
|
135056
135229
|
const first = execSync(process.platform === "win32" ? "where scream" : "which scream 2>/dev/null", {
|
|
135057
135230
|
encoding: "utf-8",
|
|
135058
135231
|
timeout: 3e3
|
|
135059
135232
|
}).trim().split(/[\r\n]+/)[0]?.trim() ?? "";
|
|
135060
|
-
if (first) return `${first} stream-json`;
|
|
135233
|
+
if (first) return `${quoteShellPath(first)} stream-json`;
|
|
135061
135234
|
} catch {}
|
|
135062
135235
|
return "scream stream-json";
|
|
135063
135236
|
}
|
|
135064
|
-
|
|
135065
|
-
|
|
135066
|
-
|
|
135067
|
-
|
|
135068
|
-
|
|
135069
|
-
|
|
135070
|
-
|
|
135071
|
-
|
|
135072
|
-
|
|
135073
|
-
|
|
135074
|
-
|
|
135075
|
-
|
|
135076
|
-
|
|
135077
|
-
|
|
135078
|
-
|
|
135079
|
-
|
|
135080
|
-
const m = line.match(/^type\s*=\s*"(\S+)"/);
|
|
135081
|
-
if (m) return m[1];
|
|
135082
|
-
}
|
|
135237
|
+
/**
|
|
135238
|
+
* Double-quote a path for shell parsing. cc-connect runs `cmd` through a
|
|
135239
|
+
* shell, so an unquoted path containing spaces would be split apart.
|
|
135240
|
+
*/
|
|
135241
|
+
function quoteShellPath(path) {
|
|
135242
|
+
return `"${path.replaceAll(/"/g, "\\\"")}"`;
|
|
135243
|
+
}
|
|
135244
|
+
/** Parse every configured platform type from config.toml content. */
|
|
135245
|
+
function parseConfiguredTypes(content) {
|
|
135246
|
+
const types = [];
|
|
135247
|
+
let inPlatforms = false;
|
|
135248
|
+
for (const line of content.split("\n")) {
|
|
135249
|
+
const trimmed = line.trim();
|
|
135250
|
+
if (trimmed.startsWith("[[projects.platforms]]")) {
|
|
135251
|
+
inPlatforms = true;
|
|
135252
|
+
continue;
|
|
135083
135253
|
}
|
|
135084
|
-
|
|
135254
|
+
if (trimmed.startsWith("[")) {
|
|
135255
|
+
inPlatforms = false;
|
|
135256
|
+
continue;
|
|
135257
|
+
}
|
|
135258
|
+
if (inPlatforms) {
|
|
135259
|
+
const m = trimmed.match(/^type\s*=\s*["']([^"']+)["']/);
|
|
135260
|
+
if (m?.[1]) types.push(m[1]);
|
|
135261
|
+
}
|
|
135262
|
+
}
|
|
135263
|
+
return types;
|
|
135264
|
+
}
|
|
135265
|
+
function readConfiguredTypes() {
|
|
135266
|
+
if (!existsSync(CONFIG_PATH)) return [];
|
|
135267
|
+
try {
|
|
135268
|
+
return parseConfiguredTypes(readFileSync(CONFIG_PATH, "utf-8"));
|
|
135085
135269
|
} catch {
|
|
135086
|
-
return;
|
|
135270
|
+
return [];
|
|
135087
135271
|
}
|
|
135088
135272
|
}
|
|
135089
|
-
|
|
135090
|
-
|
|
135273
|
+
/** True when config content already has an active (non-comment) platform of this type. */
|
|
135274
|
+
function hasPlatformConfigured(content, type) {
|
|
135275
|
+
const escaped = type.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
135276
|
+
return new RegExp(`^\\s*type\\s*=\\s*["']${escaped}["']`, "m").test(content);
|
|
135277
|
+
}
|
|
135278
|
+
/** Minimal semver-ish check: "1.5.0" >= "1.5.0". */
|
|
135279
|
+
function isVersionAtLeast(version, min) {
|
|
135280
|
+
if (!version) return false;
|
|
135281
|
+
const parse = (v) => v.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
135282
|
+
const [a = 0, b = 0, c = 0] = parse(version);
|
|
135283
|
+
const [x = 0, y = 0, z = 0] = parse(min);
|
|
135284
|
+
return a > x || a === x && (b > y || b === y && c >= z);
|
|
135285
|
+
}
|
|
135286
|
+
/**
|
|
135287
|
+
* Quote a value for TOML. Literal strings ('...') cannot contain a single
|
|
135288
|
+
* quote at all (no escape mechanism), so values with one fall back to a
|
|
135289
|
+
* basic string ("...") where backslash and double-quote are escaped.
|
|
135290
|
+
*/
|
|
135291
|
+
function tomlString(value) {
|
|
135292
|
+
if (!value.includes("'")) return `'${value}'`;
|
|
135293
|
+
return `"${value.replaceAll(/\\/g, "\\\\").replaceAll(/"/g, "\\\"")}"`;
|
|
135091
135294
|
}
|
|
135092
135295
|
function generateConfig(platform) {
|
|
135093
135296
|
const dir = dirname$1(CONFIG_PATH);
|
|
@@ -135095,11 +135298,15 @@ function generateConfig(platform) {
|
|
|
135095
135298
|
const platformBlock = `\n[[projects.platforms]]\ntype = "${platform.type}"\n`;
|
|
135096
135299
|
if (existsSync(CONFIG_PATH)) {
|
|
135097
135300
|
const existing = readFileSync(CONFIG_PATH, "utf-8");
|
|
135098
|
-
if (existing
|
|
135301
|
+
if (hasPlatformConfigured(existing, platform.type)) return;
|
|
135099
135302
|
writeFileSync(CONFIG_PATH, existing + platformBlock, "utf-8");
|
|
135100
135303
|
return;
|
|
135101
135304
|
}
|
|
135102
|
-
writeFileSync(CONFIG_PATH,
|
|
135305
|
+
writeFileSync(CONFIG_PATH, buildConfigContent(platform, detectScreamPath(), process.cwd()), "utf-8");
|
|
135306
|
+
}
|
|
135307
|
+
/** Build the full config.toml content for a fresh setup. */
|
|
135308
|
+
function buildConfigContent(platform, screamCmd, cwd) {
|
|
135309
|
+
return [
|
|
135103
135310
|
t("ccconnect.config_comment_attachment"),
|
|
135104
135311
|
"attachment_send = \"on\"",
|
|
135105
135312
|
"",
|
|
@@ -135110,21 +135317,22 @@ function generateConfig(platform) {
|
|
|
135110
135317
|
"type = \"claudecode\"",
|
|
135111
135318
|
"",
|
|
135112
135319
|
"[projects.agent.options]",
|
|
135113
|
-
`cmd =
|
|
135114
|
-
`work_dir =
|
|
135115
|
-
"mode
|
|
135320
|
+
`cmd = ${tomlString(screamCmd)}`,
|
|
135321
|
+
`work_dir = ${tomlString(cwd)}`,
|
|
135322
|
+
"# Permission mode: default (confirm each tool) | acceptEdits | plan | auto | bypassPermissions (yolo) | dontAsk",
|
|
135323
|
+
"mode = \"auto\"",
|
|
135116
135324
|
"",
|
|
135117
135325
|
"[[projects.platforms]]",
|
|
135118
135326
|
`type = "${platform.type}"`,
|
|
135119
135327
|
""
|
|
135120
|
-
].join("\n")
|
|
135328
|
+
].join("\n");
|
|
135121
135329
|
}
|
|
135122
135330
|
const SEP = "──".repeat(20);
|
|
135123
135331
|
/**
|
|
135124
135332
|
* Build the full notice text shown after platform selection.
|
|
135125
135333
|
* Common management commands come first; detailed setup steps follow.
|
|
135126
135334
|
*/
|
|
135127
|
-
function buildNoticeText(platform, isReconfigure) {
|
|
135335
|
+
function buildNoticeText(platform, isReconfigure, installedVersion) {
|
|
135128
135336
|
const daemon = getDaemonInstructions(dirname$1(CONFIG_PATH));
|
|
135129
135337
|
const parts = [];
|
|
135130
135338
|
if (isReconfigure) {
|
|
@@ -135136,6 +135344,10 @@ function buildNoticeText(platform, isReconfigure) {
|
|
|
135136
135344
|
parts.push("");
|
|
135137
135345
|
parts.push(t("ccconnect.config_written", { path: CONFIG_PATH }));
|
|
135138
135346
|
}
|
|
135347
|
+
if (NEW_PLATFORM_TYPES.has(platform.type) && !isVersionAtLeast(installedVersion, "1.5.0")) {
|
|
135348
|
+
parts.push("");
|
|
135349
|
+
parts.push(t("ccconnect.new_platform_version_hint"));
|
|
135350
|
+
}
|
|
135139
135351
|
parts.push("");
|
|
135140
135352
|
parts.push(t("ccconnect.quick_ref"));
|
|
135141
135353
|
parts.push("");
|
|
@@ -135189,13 +135401,14 @@ function buildNoticeText(platform, isReconfigure) {
|
|
|
135189
135401
|
return parts.join("\n");
|
|
135190
135402
|
}
|
|
135191
135403
|
async function handleChannelCommand(host, _args) {
|
|
135192
|
-
|
|
135404
|
+
const cc = checkCcConnect();
|
|
135405
|
+
if (!cc.installed) {
|
|
135193
135406
|
host.showNotice(t("ccconnect.not_installed"), t("ccconnect.install_guide"));
|
|
135194
135407
|
return;
|
|
135195
135408
|
}
|
|
135196
|
-
const
|
|
135409
|
+
const configuredTypes = readConfiguredTypes();
|
|
135197
135410
|
const options = getPlatforms().map((p) => {
|
|
135198
|
-
const isConfigured =
|
|
135411
|
+
const isConfigured = configuredTypes.includes(p.type);
|
|
135199
135412
|
return {
|
|
135200
135413
|
value: p.type,
|
|
135201
135414
|
label: isConfigured ? t("ccconnect.already_configured", { name: p.name }) : p.name,
|
|
@@ -135206,7 +135419,7 @@ async function handleChannelCommand(host, _args) {
|
|
|
135206
135419
|
title: t("ccconnect.picker_title"),
|
|
135207
135420
|
hint: t("ccconnect.picker_hint"),
|
|
135208
135421
|
options,
|
|
135209
|
-
currentValue:
|
|
135422
|
+
currentValue: configuredTypes[0],
|
|
135210
135423
|
colors: host.state.theme.colors,
|
|
135211
135424
|
onSelect: (value) => {
|
|
135212
135425
|
host.restoreEditor();
|
|
@@ -135215,12 +135428,12 @@ async function handleChannelCommand(host, _args) {
|
|
|
135215
135428
|
host.showError(t("error.internal"));
|
|
135216
135429
|
return;
|
|
135217
135430
|
}
|
|
135218
|
-
if (
|
|
135219
|
-
host.showNotice(t("ccconnect.reconfigured", { name: platform.name }), buildNoticeText(platform, true));
|
|
135431
|
+
if (configuredTypes.includes(value)) {
|
|
135432
|
+
host.showNotice(t("ccconnect.reconfigured", { name: platform.name }), buildNoticeText(platform, true, cc.version));
|
|
135220
135433
|
return;
|
|
135221
135434
|
}
|
|
135222
135435
|
generateConfig(platform);
|
|
135223
|
-
host.showNotice(t("ccconnect.config_done", { name: platform.name }), buildNoticeText(platform, false));
|
|
135436
|
+
host.showNotice(t("ccconnect.config_done", { name: platform.name }), buildNoticeText(platform, false, cc.version));
|
|
135224
135437
|
},
|
|
135225
135438
|
onCancel: () => {
|
|
135226
135439
|
host.restoreEditor();
|
|
@@ -136072,7 +136285,7 @@ function buildRoleAdditionalText(prefs) {
|
|
|
136072
136285
|
if (items.length === 0 && (doNot === void 0 || doNot.length === 0) && !hasToolPriority) return "";
|
|
136073
136286
|
lines.push("", ...items);
|
|
136074
136287
|
if (doNot !== void 0 && doNot.length > 0) lines.push("", "## Do NOT (explicit prohibitions — NEVER do these)", doNot);
|
|
136075
|
-
if (hasToolPriority) lines.push("", "## Tool priority (set via /like — HIGHEST PRIORITY)", prefs.toolPriority === "skill" ? "For every user request
|
|
136288
|
+
if (hasToolPriority) lines.push("", "## Tool priority (set via /like — HIGHEST PRIORITY)", prefs.toolPriority === "skill" ? "For every user request: (1) first analyze the intent, (2) then identify whether any installed skill matches THIS request, (3) if one matches, invoke the Skill tool with it as your FIRST action — before MCP tools or doing it yourself, (4) if none matches, proceed with MCP tools or solve it yourself. Consult the skill list shown in the Skill tool description whenever you are unsure what is installed." : "For every user request: (1) first analyze the intent, (2) then identify whether any available MCP tool matches THIS request, (3) if one matches, use it as your FIRST action — before the Skill tool or doing it yourself, (4) if none matches, proceed with the Skill tool or solve it yourself.");
|
|
136076
136289
|
lines.push("", t("like.priority"));
|
|
136077
136290
|
return lines.join("\n");
|
|
136078
136291
|
}
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { Kt as handleConnectCommand } from "./dispatch-
|
|
6
|
+
import { Kt as handleConnectCommand } from "./dispatch-202xtik3.mjs";
|
|
7
7
|
export { handleConnectCommand };
|
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-BXslKpYT.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);
|
|
@@ -410,6 +410,8 @@ const dictionaries = {
|
|
|
410
410
|
"cc.confirm_uninstall": "确认彻底卸载 cc-connect?",
|
|
411
411
|
"cc.uninstall_irreversible": "此操作不可撤销,所有 cc-connect 数据将被清除",
|
|
412
412
|
"cc.confirm_uninstall_btn": "确认卸载",
|
|
413
|
+
"cc.uninstall_step_npm": "· 执行 npm uninstall -g cc-connect",
|
|
414
|
+
"cc.unknown_error": "未知错误",
|
|
413
415
|
"auth.fetching_models": "正在拉取最新模型目录...",
|
|
414
416
|
"auth.catalog_fetch_failed": "拉取远程模型目录失败: {error}。请检查网络(目录站点在你的网络环境下可能无法访问)后重试,或使用 /config diy 自行配置服务商。",
|
|
415
417
|
"auth.no_providers": "没有已配置的模型商。",
|
|
@@ -959,6 +961,15 @@ const dictionaries = {
|
|
|
959
961
|
"ccconnect.note_botfather": "需先在 @BotFather 创建 bot",
|
|
960
962
|
"ccconnect.note_napcat": "需要 NapCat/OneBot",
|
|
961
963
|
"ccconnect.note_wecom": "需要公网 IP",
|
|
964
|
+
"ccconnect.note_matrix": "E2EE 加密,需 homeserver + access token",
|
|
965
|
+
"ccconnect.note_webex": "需在 developer.webex.com 创建 Bot",
|
|
966
|
+
"ccconnect.note_max": "需通过 @MasterBot 创建 bot",
|
|
967
|
+
"ccconnect.note_googlechat": "需 GCP 服务账号 JSON",
|
|
968
|
+
"ccconnect.note_cloud_web": "自建 IM 网关",
|
|
969
|
+
"ccconnect.note_yuanbao": "腾讯元宝,需 app-key:app-secret",
|
|
970
|
+
"ccconnect.note_tuitui": "需 app_id + app_secret",
|
|
971
|
+
"ccconnect.note_wps_agentspace": "需 app_id + wps_sid",
|
|
972
|
+
"ccconnect.new_platform_version_hint": "⚠ 该平台需要 cc-connect v1.5.0 及以上,请先更新 cc-connect",
|
|
962
973
|
"ccconnect.config_comment_attachment": "# 全局:允许/禁止图片和文件回传到聊天(on = 开启,off = 关闭)",
|
|
963
974
|
"ccconnect.reconfigured": "{name} 已配置(配置不会丢失)",
|
|
964
975
|
"ccconnect.config_path": "配置文件:{path}",
|
|
@@ -1490,6 +1501,8 @@ const dictionaries = {
|
|
|
1490
1501
|
"cc.confirm_uninstall": "Completely uninstall cc-connect?",
|
|
1491
1502
|
"cc.uninstall_irreversible": "This cannot be undone. All cc-connect data will be removed.",
|
|
1492
1503
|
"cc.confirm_uninstall_btn": "Confirm Uninstall",
|
|
1504
|
+
"cc.uninstall_step_npm": "· Run npm uninstall -g cc-connect",
|
|
1505
|
+
"cc.unknown_error": "Unknown error",
|
|
1493
1506
|
"auth.fetching_models": "Fetching latest model catalog...",
|
|
1494
1507
|
"auth.catalog_fetch_failed": "Failed to fetch the remote model catalog: {error}. Check your network (the catalog host may be unreachable in your region) and retry, or use /config diy to set up a provider manually.",
|
|
1495
1508
|
"auth.no_providers": "No model providers configured.",
|
|
@@ -2039,6 +2052,15 @@ const dictionaries = {
|
|
|
2039
2052
|
"ccconnect.note_botfather": "Create a bot at @BotFather first",
|
|
2040
2053
|
"ccconnect.note_napcat": "Requires NapCat/OneBot",
|
|
2041
2054
|
"ccconnect.note_wecom": "Requires public IP",
|
|
2055
|
+
"ccconnect.note_matrix": "E2EE encrypted, needs homeserver + access token",
|
|
2056
|
+
"ccconnect.note_webex": "Create a bot at developer.webex.com",
|
|
2057
|
+
"ccconnect.note_max": "Create a bot via @MasterBot",
|
|
2058
|
+
"ccconnect.note_googlechat": "Requires GCP service account JSON",
|
|
2059
|
+
"ccconnect.note_cloud_web": "Self-hosted IM gateway",
|
|
2060
|
+
"ccconnect.note_yuanbao": "Tencent Yuanbao, needs app-key:app-secret",
|
|
2061
|
+
"ccconnect.note_tuitui": "Needs app_id + app_secret",
|
|
2062
|
+
"ccconnect.note_wps_agentspace": "Needs app_id + wps_sid",
|
|
2063
|
+
"ccconnect.new_platform_version_hint": "⚠ This platform requires cc-connect v1.5.0 or newer. Please update cc-connect first.",
|
|
2042
2064
|
"ccconnect.config_comment_attachment": "# Global: allow/disallow image & file backhaul to chat (on = enabled, off = disabled)",
|
|
2043
2065
|
"ccconnect.reconfigured": "{name} already configured (config preserved)",
|
|
2044
2066
|
"ccconnect.config_path": "Config file: {path}",
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { t as TextInputDialogComponent } from "./text-input-dialog-
|
|
6
|
+
import { t as TextInputDialogComponent } from "./text-input-dialog-BzVVVncg.mjs";
|
|
7
7
|
export { TextInputDialogComponent };
|