scream-code 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -46,9 +46,9 @@ import { lookup } from "node:dns/promises";
46
46
  import { isIP } from "node:net";
47
47
  import { AsyncLocalStorage } from "node:async_hooks";
48
48
  import { Command, Option } from "commander";
49
- import { CombinedAutocompleteProvider, Container, Editor, Image, Input, Key, Markdown, ProcessTerminal, Spacer, TUI, Text, decodeKittyPrintable, deleteAllKittyImages, fuzzyFilter, fuzzyMatch, getCapabilities, getImageDimensions, isKeyRelease, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
50
- import chalk, { chalkStderr } from "chalk";
51
49
  import { createInterface } from "node:readline/promises";
50
+ import chalk, { chalkStderr } from "chalk";
51
+ import { CombinedAutocompleteProvider, Container, Editor, Image, Input, Key, Markdown, ProcessTerminal, Spacer, TUI, Text, decodeKittyPrintable, deleteAllKittyImages, fuzzyFilter, fuzzyMatch, getCapabilities, getImageDimensions, isKeyRelease, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
52
52
  import { highlight, supportsLanguage } from "cli-highlight";
53
53
  import { diffWords } from "diff";
54
54
  import { promisify } from "node:util";
@@ -81345,10 +81345,10 @@ function blockDecision(event, results) {
81345
81345
  }
81346
81346
  function toHookInputData(input) {
81347
81347
  const result = {};
81348
- for (const [key, value] of Object.entries(input)) result[camelToSnake$2(key)] = value;
81348
+ for (const [key, value] of Object.entries(input)) result[camelToSnake$1(key)] = value;
81349
81349
  return result;
81350
81350
  }
81351
- function camelToSnake$2(value) {
81351
+ function camelToSnake$1(value) {
81352
81352
  return value.replaceAll(/[A-Z]/g, (ch) => `_${ch.toLowerCase()}`);
81353
81353
  }
81354
81354
  //#endregion
@@ -99668,7 +99668,7 @@ function rawThinking(config) {
99668
99668
  function snakeToCamel(str) {
99669
99669
  return str.replaceAll(/_([a-z])/g, (_, ch) => ch.toUpperCase());
99670
99670
  }
99671
- function camelToSnake$1(str) {
99671
+ function camelToSnake(str) {
99672
99672
  return str.replaceAll(/[A-Z]/g, (ch) => `_${ch.toLowerCase()}`);
99673
99673
  }
99674
99674
  const DEFAULT_CONFIG_FILE_TEXT = `# ~/.scream-code/config.toml
@@ -99835,7 +99835,7 @@ function configToTomlData(config) {
99835
99835
  "defaultPlanMode",
99836
99836
  "mergeAllAvailableSkills",
99837
99837
  "extraSkillDirs"
99838
- ]) setDefined(out, camelToSnake$1(key), config[key]);
99838
+ ]) setDefined(out, camelToSnake(key), config[key]);
99839
99839
  setRecordSection(out, "providers", config.providers, providerToToml);
99840
99840
  setRecordSection(out, "models", config.models, modelToToml);
99841
99841
  setSection(out, "thinking", config.thinking, thinkingToToml);
@@ -99868,20 +99868,20 @@ function setSection(out, snakeKey, value, toToml) {
99868
99868
  }
99869
99869
  function providerToToml(provider, rawProvider) {
99870
99870
  const out = cloneRecord(rawProvider);
99871
- for (const [key, value] of Object.entries(provider)) if (key === "oauth" && value !== void 0) out[camelToSnake$1(key)] = oauthToToml(value);
99872
- else if ((key === "env" || key === "customHeaders") && value !== void 0) out[camelToSnake$1(key)] = cloneUnknown(value);
99873
- else setDefined(out, camelToSnake$1(key), value);
99871
+ for (const [key, value] of Object.entries(provider)) if (key === "oauth" && value !== void 0) out[camelToSnake(key)] = oauthToToml(value);
99872
+ else if ((key === "env" || key === "customHeaders") && value !== void 0) out[camelToSnake(key)] = cloneUnknown(value);
99873
+ else setDefined(out, camelToSnake(key), value);
99874
99874
  return out;
99875
99875
  }
99876
99876
  function modelToToml(model, rawModel) {
99877
99877
  const out = cloneRecord(rawModel);
99878
- for (const [key, value] of Object.entries(model)) if (key === "capabilities" && Array.isArray(value)) out[camelToSnake$1(key)] = [...value];
99879
- else setDefined(out, camelToSnake$1(key), value);
99878
+ for (const [key, value] of Object.entries(model)) if (key === "capabilities" && Array.isArray(value)) out[camelToSnake(key)] = [...value];
99879
+ else setDefined(out, camelToSnake(key), value);
99880
99880
  return out;
99881
99881
  }
99882
99882
  function thinkingToToml(thinking, rawThinking) {
99883
99883
  const out = cloneRecord(rawThinking);
99884
- for (const [key, value] of Object.entries(thinking)) setDefined(out, camelToSnake$1(key), value);
99884
+ for (const [key, value] of Object.entries(thinking)) setDefined(out, camelToSnake(key), value);
99885
99885
  return out;
99886
99886
  }
99887
99887
  function permissionToToml(permission, rawPermission) {
@@ -99895,7 +99895,7 @@ function permissionToToml(permission, rawPermission) {
99895
99895
  }
99896
99896
  function permissionRuleToToml(rule) {
99897
99897
  const out = {};
99898
- for (const [key, value] of Object.entries(rule)) setDefined(out, camelToSnake$1(key), value);
99898
+ for (const [key, value] of Object.entries(rule)) setDefined(out, camelToSnake(key), value);
99899
99899
  return out;
99900
99900
  }
99901
99901
  function servicesToToml(services, rawServices) {
@@ -99908,19 +99908,19 @@ function servicesToToml(services, rawServices) {
99908
99908
  }
99909
99909
  function serviceToToml(service) {
99910
99910
  const out = {};
99911
- for (const [key, value] of Object.entries(service)) if (key === "oauth" && value !== void 0) out[camelToSnake$1(key)] = oauthToToml(value);
99912
- else if (key === "customHeaders" && value !== void 0) out[camelToSnake$1(key)] = cloneUnknown(value);
99913
- else setDefined(out, camelToSnake$1(key), value);
99911
+ for (const [key, value] of Object.entries(service)) if (key === "oauth" && value !== void 0) out[camelToSnake(key)] = oauthToToml(value);
99912
+ else if (key === "customHeaders" && value !== void 0) out[camelToSnake(key)] = cloneUnknown(value);
99913
+ else setDefined(out, camelToSnake(key), value);
99914
99914
  return out;
99915
99915
  }
99916
99916
  function loopControlToToml(loopControl, rawLoopControl) {
99917
99917
  const out = cloneRecord(rawLoopControl);
99918
- for (const [key, value] of Object.entries(loopControl)) setDefined(out, camelToSnake$1(key), value);
99918
+ for (const [key, value] of Object.entries(loopControl)) setDefined(out, camelToSnake(key), value);
99919
99919
  return out;
99920
99920
  }
99921
99921
  function backgroundToToml(background, rawBackground) {
99922
99922
  const out = cloneRecord(rawBackground);
99923
- for (const [key, value] of Object.entries(background)) setDefined(out, camelToSnake$1(key), value);
99923
+ for (const [key, value] of Object.entries(background)) setDefined(out, camelToSnake(key), value);
99924
99924
  return out;
99925
99925
  }
99926
99926
  function setHooks(out, hooks) {
@@ -99932,12 +99932,12 @@ function setHooks(out, hooks) {
99932
99932
  }
99933
99933
  function hookToToml(hook) {
99934
99934
  const out = {};
99935
- for (const [key, value] of Object.entries(hook)) setDefined(out, camelToSnake$1(key), value);
99935
+ for (const [key, value] of Object.entries(hook)) setDefined(out, camelToSnake(key), value);
99936
99936
  return out;
99937
99937
  }
99938
99938
  function oauthToToml(oauth) {
99939
99939
  const out = {};
99940
- for (const [key, value] of Object.entries(oauth)) out[camelToSnake$1(key)] = value;
99940
+ for (const [key, value] of Object.entries(oauth)) out[camelToSnake(key)] = value;
99941
99941
  return out;
99942
99942
  }
99943
99943
  function isPlainObject$1(value) {
@@ -119240,25 +119240,6 @@ const SessionSummaryStateSchema = z.object({
119240
119240
  title: z.string().optional(),
119241
119241
  custom: z.record(z.string(), z.unknown()).optional()
119242
119242
  });
119243
- const CcConnectHistoryEntrySchema = z.object({
119244
- role: z.string(),
119245
- content: z.string(),
119246
- timestamp: z.string().optional()
119247
- });
119248
- const CcConnectSessionSchema = z.object({
119249
- id: z.string(),
119250
- name: z.string().optional(),
119251
- agent_session_id: z.string().optional(),
119252
- agent_type: z.string().optional(),
119253
- history: z.array(CcConnectHistoryEntrySchema).nullable().optional(),
119254
- created_at: z.string().optional(),
119255
- updated_at: z.string().optional()
119256
- });
119257
- const CcConnectSnapshotSchema = z.object({
119258
- sessions: z.record(z.string(), CcConnectSessionSchema).optional(),
119259
- active_session: z.record(z.string(), z.string()).optional(),
119260
- version: z.number().optional()
119261
- });
119262
119243
  var SessionStore = class {
119263
119244
  homeDir;
119264
119245
  sessionsDir;
@@ -119403,17 +119384,11 @@ var SessionStore = class {
119403
119384
  async listAll() {
119404
119385
  const index = await readSessionIndex(this.homeDir, this.sessionsDir);
119405
119386
  const sessions = [];
119406
- const seenAgentIds = /* @__PURE__ */ new Set();
119407
119387
  for (const entry of index.values()) {
119408
119388
  if (!await isDirectory(entry.sessionDir)) continue;
119409
119389
  const summary = await this.summaryFromDir(entry.sessionId, entry.sessionDir, entry.workDir);
119410
119390
  sessions.push(summary);
119411
- seenAgentIds.add(entry.sessionId);
119412
119391
  }
119413
- try {
119414
- const ccSessions = await listCcConnectSessions(seenAgentIds);
119415
- sessions.push(...ccSessions);
119416
- } catch {}
119417
119392
  sessions.sort(compareSessionSummary);
119418
119393
  return sessions;
119419
119394
  }
@@ -119587,90 +119562,6 @@ function compareSessionSummary(a, b) {
119587
119562
  if (a.id > b.id) return 1;
119588
119563
  return 0;
119589
119564
  }
119590
- const CC_CONNECT_SESSIONS_DIR = join$1(homedir(), ".cc-connect", "sessions");
119591
- /**
119592
- * Scan `~/.cc-connect/sessions/*.json` and return ScreamCode-compatible
119593
- * SessionSummary entries for every cc-connect session that has a
119594
- * non-empty agent_session_id (i.e. can actually be resumed).
119595
- *
119596
- * Sessions whose `agent_session_id` already appears in `seenAgentIds` are
119597
- * skipped — the native ScreamCode session takes precedence.
119598
- */
119599
- async function listCcConnectSessions(seenAgentIds) {
119600
- let entries;
119601
- try {
119602
- entries = await readdir(CC_CONNECT_SESSIONS_DIR);
119603
- } catch {
119604
- return [];
119605
- }
119606
- const results = [];
119607
- for (const name of entries) {
119608
- if (!name.endsWith(".json")) continue;
119609
- const projectName = name.slice(0, -5);
119610
- const parsed = await readCcConnectSnapshot(join$1(CC_CONNECT_SESSIONS_DIR, name));
119611
- if (parsed === void 0) continue;
119612
- for (const [, ccSession] of Object.entries(parsed.sessions ?? {})) {
119613
- const agentId = ccSession.agent_session_id?.trim();
119614
- if (!agentId || agentId.length === 0) continue;
119615
- if (seenAgentIds.has(agentId)) continue;
119616
- const summary = ccSessionToSummary(ccSession, agentId, projectName);
119617
- if (summary !== void 0) {
119618
- results.push(summary);
119619
- seenAgentIds.add(agentId);
119620
- }
119621
- }
119622
- }
119623
- return results;
119624
- }
119625
- async function readCcConnectSnapshot(filePath) {
119626
- try {
119627
- const raw = await readFile(filePath, "utf-8");
119628
- const parsed = JSON.parse(raw);
119629
- const result = CcConnectSnapshotSchema.safeParse(parsed);
119630
- return result.success ? result.data : void 0;
119631
- } catch {
119632
- return;
119633
- }
119634
- }
119635
- /** Extract the last user-message content for a preview in the picker. */
119636
- function lastPromptFromCcHistory(history) {
119637
- if (!history || history.length === 0) return void 0;
119638
- for (let i = history.length - 1; i >= 0; i--) {
119639
- const entry = history[i];
119640
- if (entry && entry.role === "user" && entry.content?.trim().length > 0) return entry.content.trim();
119641
- }
119642
- }
119643
- function ccSessionToSummary(cc, agentSessionId, projectName) {
119644
- const id = `cc:${projectName}/${cc.id}`;
119645
- const createdAt = parseCcTimestamp(cc.created_at);
119646
- const updatedAt = parseCcTimestamp(cc.updated_at) ?? createdAt;
119647
- if (createdAt === void 0 && updatedAt === void 0) return void 0;
119648
- const title = cc.name?.trim() ?? cc.id;
119649
- const lastPrompt = lastPromptFromCcHistory(cc.history);
119650
- const metadata = {
119651
- source: "cc-connect",
119652
- agentSessionId,
119653
- ccProject: projectName,
119654
- ccSessionId: cc.id
119655
- };
119656
- if (cc.agent_type) metadata["agentType"] = cc.agent_type;
119657
- return {
119658
- id,
119659
- workDir: homedir(),
119660
- sessionDir: "",
119661
- createdAt: createdAt ?? updatedAt,
119662
- updatedAt: updatedAt ?? createdAt,
119663
- title: title.length > 0 ? title : void 0,
119664
- lastPrompt,
119665
- metadata
119666
- };
119667
- }
119668
- /** Parse an ISO-8601 timestamp with optional timezone offset to epoch ms. */
119669
- function parseCcTimestamp(value) {
119670
- if (!value) return void 0;
119671
- const ms = Date.parse(value);
119672
- return Number.isFinite(ms) ? ms : void 0;
119673
- }
119674
119565
  //#endregion
119675
119566
  //#region ../../packages/jian/src/errors.ts
119676
119567
  /**
@@ -121652,6 +121543,7 @@ const dictionaries = {
121652
121543
  "session.title": "会话",
121653
121544
  "session.loading": "正在加载会话...",
121654
121545
  "session_picker.empty": "未找到会话。按 Escape 关闭。",
121546
+ "session_picker.cc_restricted": "CC专属会话不支持切换或删除,请点击或复制下方文件路径进入手动管理",
121655
121547
  "session.picker_title": "会话 ",
121656
121548
  "session.delete_confirm": "⚠️ 按 Enter 确认删除,Esc 取消",
121657
121549
  "session.picker_hint": "(↑↓ 导航,Enter 选择,d 删除,Esc 取消)",
@@ -121767,7 +121659,7 @@ const dictionaries = {
121767
121659
  "skill.skill_removed": "该 Skill 及其子 Skill 已从当前会话中移除。",
121768
121660
  "skill.delete_failed": "删除失败。",
121769
121661
  "skill.delete_failed_msg": "删除失败: {msg}",
121770
- "skill.confirm_uninstall": "确认卸载",
121662
+ "skill.confirm_uninstall": "确认卸载 \"{label}\"?",
121771
121663
  "skill.uninstall_reversible": "卸载后可在 Skill 中心重新安装",
121772
121664
  "skill.uninstall_yes": "是,卸载",
121773
121665
  "toolcall.bg_agent_lost": "后台 agent 丢失(会话在完成前已重启)",
@@ -122139,8 +122031,6 @@ const dictionaries = {
122139
122031
  "market.design_card_desc": "14 种设计卡片生成(封面/图文/社交分享/长篇排版),Parchment × Swiss 双风格体系",
122140
122032
  "market.superpowers_name": "Superpowers 开发技能包",
122141
122033
  "market.superpowers_desc": "14 个开发方法论技能:TDD、系统调试、代码审查、子代理驱动开发、并行代理、头脑风暴等",
122142
- "market.audio_name": "Audio Skill 录音分析",
122143
- "market.audio_desc": "本地录音分析自动化,含 RAG 知识库。适用于销售录音复盘、会议纪要、质量评分等",
122144
122034
  "market.scrapling_name": "Scrapling 网页爬取",
122145
122035
  "market.scrapling_desc": "基于 Scrapling 的智能爬虫技能,支持 Cloudflare/WAF 绕过、登录会话、自动抓取解析",
122146
122036
  "market.astock_name": "A 股数据分析",
@@ -122728,6 +122618,7 @@ const dictionaries = {
122728
122618
  "session.title": "Sessions",
122729
122619
  "session.loading": "Loading sessions...",
122730
122620
  "session_picker.empty": "No sessions found. Press Escape to close.",
122621
+ "session_picker.cc_restricted": "CC sessions cannot be switched or deleted. Use the file path below to manage manually",
122731
122622
  "session.picker_title": "Sessions ",
122732
122623
  "session.delete_confirm": "⚠️ Press Enter to confirm delete, Esc to cancel",
122733
122624
  "session.picker_hint": "(↑↓ Navigate, Enter Select, d Delete, Esc Cancel)",
@@ -122843,7 +122734,7 @@ const dictionaries = {
122843
122734
  "skill.skill_removed": "This skill and its sub-skills have been removed from the current session.",
122844
122735
  "skill.delete_failed": "Delete failed.",
122845
122736
  "skill.delete_failed_msg": "Delete failed: {msg}",
122846
- "skill.confirm_uninstall": "Confirm Uninstall",
122737
+ "skill.confirm_uninstall": "Uninstall \"{label}\"?",
122847
122738
  "skill.uninstall_reversible": "You can reinstall from the Skill center later",
122848
122739
  "skill.uninstall_yes": "Yes, uninstall",
122849
122740
  "toolcall.bg_agent_lost": "Background agent lost (session restarted before completion)",
@@ -123215,8 +123106,6 @@ const dictionaries = {
123215
123106
  "market.design_card_desc": "14 design card generators (cover/photo/social/long-form), Parchment × Swiss dual-style system",
123216
123107
  "market.superpowers_name": "Superpowers Dev Skill Pack",
123217
123108
  "market.superpowers_desc": "14 dev methodology skills: TDD, system debugging, code review, subagent-driven dev, parallel agents, brainstorming, etc.",
123218
- "market.audio_name": "Audio Skill Recording Analysis",
123219
- "market.audio_desc": "Local recording analysis automation with RAG knowledge base. For sales review, meeting minutes, quality scoring, etc.",
123220
123109
  "market.scrapling_name": "Scrapling Web Scraper",
123221
123110
  "market.scrapling_desc": "Smart scraper based on Scrapling, supports Cloudflare/WAF bypass, login sessions, auto-extraction",
123222
123111
  "market.astock_name": "A-Share Data Analysis",
@@ -124742,66 +124631,6 @@ const DEFAULT_OAUTH_PROVIDER_NAME = "managed:scream-code";
124742
124631
  ErrorCodes.AUTH_LOGIN_REQUIRED;
124743
124632
  const SCREAM_CODE_PLUGIN_MARKETPLACE_URL_ENV = "SCREAM_CODE_PLUGIN_MARKETPLACE_URL";
124744
124633
  //#endregion
124745
- //#region src/migration/command.ts
124746
- function registerMigrateCommand(parent, _onMigrate) {
124747
- parent.command("migrate").description("将旧版 scream-cli 安装的数据迁移到 scream-code。(已停用)").action(() => {
124748
- process.stdout.write("迁移功能已取消,不再支持从 scream-cli 导入数据。\n");
124749
- process.exit(0);
124750
- });
124751
- }
124752
- //#endregion
124753
- //#region src/migration/badge.ts
124754
- /**
124755
- * Pure helpers for composing session labels in the session picker.
124756
- *
124757
- * Detection rule for the `[imported]` badge: `metadata.imported_from_scream_cli`
124758
- * is strictly the boolean `true`. This mirrors the value written by
124759
- * `migration-legacy` into the session's `state.json` `custom` block.
124760
- */
124761
- const IMPORTED_BADGE = "[已导入]";
124762
- const IMPORTED_FLAG_KEY = "imported_from_scream_cli";
124763
- function isImportedSession(metadata) {
124764
- if (metadata === void 0) return false;
124765
- return metadata[IMPORTED_FLAG_KEY] === true;
124766
- }
124767
- function formatSessionLabel(input) {
124768
- return `${isImportedSession(input.metadata) ? `${IMPORTED_BADGE} ` : ""}${input.title}`;
124769
- }
124770
- //#endregion
124771
- //#region ../../packages/migration-legacy/src/scream-cli-schema.ts
124772
- const OldWorkDirMetaSchema = z.object({
124773
- path: z.string(),
124774
- jian: z.string().default("local"),
124775
- last_session_id: z.string().nullable().optional()
124776
- });
124777
- z.object({ work_dirs: z.array(OldWorkDirMetaSchema).default([]) });
124778
- z.object({
124779
- version: z.number().optional(),
124780
- approval: z.object({
124781
- yolo: z.boolean().optional(),
124782
- afk: z.boolean().optional(),
124783
- auto_approve_actions: z.array(z.string()).optional()
124784
- }).partial().optional(),
124785
- additional_dirs: z.array(z.string()).optional(),
124786
- custom_title: z.string().nullable().optional(),
124787
- title_generated: z.boolean().optional(),
124788
- title_generate_attempts: z.number().optional(),
124789
- plan_mode: z.boolean().optional(),
124790
- plan_session_id: z.string().nullable().optional(),
124791
- plan_slug: z.string().nullable().optional(),
124792
- wire_mtime: z.number().nullable().optional(),
124793
- archived: z.boolean().optional(),
124794
- archived_at: z.number().nullable().optional(),
124795
- auto_archive_exempt: z.boolean().optional(),
124796
- todos: z.array(z.unknown()).optional()
124797
- }).passthrough();
124798
- //#endregion
124799
- //#region ../../packages/migration-legacy/src/steps/config.ts
124800
- function camelToSnake(s) {
124801
- return s.replaceAll(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
124802
- }
124803
- new Set(Object.keys(ScreamConfigSchema.shape).filter((k) => k !== "raw" && k !== "providers" && k !== "models" && k !== "hooks").map(camelToSnake));
124804
- //#endregion
124805
124634
  //#region src/cli/update/types.ts
124806
124635
  function emptyUpdateCache() {
124807
124636
  return {
@@ -124874,7 +124703,7 @@ function optionalBuildString(value) {
124874
124703
  return typeof value === "string" && value.length > 0 ? value : void 0;
124875
124704
  }
124876
124705
  const SCREAM_BUILD_INFO = {
124877
- version: optionalBuildString("0.9.2"),
124706
+ version: optionalBuildString("0.9.4"),
124878
124707
  channel: optionalBuildString(""),
124879
124708
  commit: optionalBuildString(""),
124880
124709
  buildTarget: optionalBuildString("darwin-arm64")
@@ -125031,19 +124860,24 @@ function errorMessage(error) {
125031
124860
  }
125032
124861
  //#endregion
125033
124862
  //#region src/cli/commands.ts
125034
- function createProgram(version, onMain, onMigrate, onPluginNodeRunner = () => {}, onStreamJson = () => {}, onChannelSetup = () => {}) {
124863
+ function createProgram(version, onMain, onPluginNodeRunner = () => {}, onStreamJson = () => {}, onChannelSetup = () => {}) {
125035
124864
  const program = new Command(CLI_COMMAND_NAME).description("下一代智能体的起点").version(version, "-V, --version").allowUnknownOption(false).configureHelp({ helpWidth: 100 }).helpOption("-h, --help", "显示帮助。").addHelpText("after", "\n文档: https://scream-cli.github.io/scream-code/\n");
125036
124865
  program.addOption(new Option("-S, --session [id]", "恢复会话。带 ID:恢复该会话。不带 ID:交互式选择。").argParser((val) => val === true ? "" : val)).addOption(new Option("-r, --resume [id]").hideHelp().argParser((val) => val === true ? "" : val)).option("-C, --continue", "继续当前工作目录的上一个会话。", false).option("-y, --yolo", "自动批准所有操作。", false).option("--auto", "以自动权限模式启动。", false).addOption(new Option("-m, --model <model>", "本次调用使用的 LLM 模型别名。默认使用 config.toml 中的 default_model。")).addOption(new Option("-p, --prompt <prompt>", "非交互式运行一条提示并打印响应。")).addOption(new Option("--output-format <format>", "提示模式的输出格式。默认为 text。").choices(["text", "stream-json"])).addOption(new Option("--skills-dir <dir>", "从该目录加载技能,而不是自动发现的用户和项目目录。可多次指定。").argParser((value, previous) => [...previous ?? [], value]).default([])).addOption(new Option("--yes").hideHelp().default(false)).addOption(new Option("--auto-approve").hideHelp().default(false)).option("--plan", "以计划模式启动。", false).option("--wolfpack", "启动时默认开启 WolfPack 批量并发模式。", false);
125037
124866
  registerExportCommand(program);
125038
- registerMigrateCommand(program, onMigrate);
125039
- program.command("stream-json", { hidden: true }).option("--input-format <fmt>", "stream-json").option("--output-format <fmt>", "stream-json").option("--resume <id>", "resume a previous session").option("--model <model>", "model to use").option("--permission-mode <mode>", "permission mode").option("--permission-prompt-tool <mode>", "(ignored, cc-connect compat)").option("--replay-user-messages", "(ignored, cc-connect compat)").option("--verbose", "(ignored, cc-connect compat)").option("--system-prompt <text>", "(ignored, cc-connect compat)").option("--append-system-prompt <text>", "(passed through to agent)").option("--append-system-prompt-file <path>", "(passed through to agent; file contents are read and merged)").option("--allowedTools <list>", "(ignored, cc-connect compat)").option("--disallowedTools <list>", "(ignored, cc-connect compat)").option("--effort <value>", "(ignored, cc-connect compat)").option("--max-context-tokens <N>", "(ignored, cc-connect compat)").option("--skills-dir <dir>", "additional skills directory (repeatable)", (value, previous) => [...previous ?? [], value], []).option("--plugin-dir <dir>", "(ignored, cc-connect compat; repeatable)", (value, previous) => [...previous ?? [], value], []).action((subOpts) => {
124867
+ program.command("stream-json", { hidden: true }).option("--input-format <fmt>", "stream-json").option("--output-format <fmt>", "stream-json").option("--resume <id>", "resume a previous session").option("--model <model>", "model to use").option("--permission-mode <mode>", "permission mode").option("--permission-prompt-tool <mode>", "(ignored, cc-connect compat)").option("--replay-user-messages", "(ignored, cc-connect compat)").option("--verbose", "(ignored, cc-connect compat)").option("--system-prompt <text>", "(passed through to agent system prompt)").option("--append-system-prompt <text>", "(passed through to agent)").option("--append-system-prompt-file <path>", "(passed through to agent; file contents are read and merged)").option("--allowedTools <list>", "(comma-separated tool whitelist)").option("--disallowedTools <list>", "(comma-separated tool blacklist)").option("--effort <value>", "(reasoning effort: low/medium/high/max)").option("--max-context-tokens <N>", "(ignored, cc-connect compat)").option("--skills-dir <dir>", "additional skills directory (repeatable)", (value, previous) => [...previous ?? [], value], []).option("--plugin-dir <dir>", "(ignored, cc-connect compat; repeatable)", (value, previous) => [...previous ?? [], value], []).action((subOpts) => {
125040
124868
  onStreamJson({
125041
124869
  resume: subOpts["resume"],
125042
124870
  model: subOpts["model"],
125043
124871
  permissionMode: subOpts["permissionMode"],
125044
124872
  skillsDirs: subOpts["skillsDir"] ?? [],
125045
124873
  appendSystemPrompt: subOpts["appendSystemPrompt"],
125046
- appendSystemPromptFile: subOpts["appendSystemPromptFile"]
124874
+ appendSystemPromptFile: subOpts["appendSystemPromptFile"],
124875
+ systemPrompt: subOpts["systemPrompt"],
124876
+ allowedTools: subOpts["allowedTools"],
124877
+ disallowedTools: subOpts["disallowedTools"],
124878
+ effort: subOpts["effort"],
124879
+ maxContextTokens: subOpts["maxContextTokens"],
124880
+ pluginDirs: subOpts["pluginDir"] ?? []
125047
124881
  });
125048
124882
  });
125049
124883
  program.command("channel").description("管理 cc-connect 消息平台通道").command("setup").description("配置 cc-connect 并选择要连接的平台").action(() => {
@@ -125111,7 +124945,6 @@ function validateOptions(opts) {
125111
124945
  * Agent/runtime settings live in core's `config.toml`; this file owns only
125112
124946
  * terminal UI preferences for the scream-code client.
125113
124947
  */
125114
- const INVALID_TUI_CONFIG_MESSAGE = t("tui.invalid_config");
125115
124948
  const TuiThemeSchema = z.enum([
125116
124949
  "dark",
125117
124950
  "light",
@@ -125179,7 +125012,7 @@ var TuiConfigParseError = class extends Error {
125179
125012
  name = "TuiConfigParseError";
125180
125013
  fallback;
125181
125014
  constructor(fallback) {
125182
- super(INVALID_TUI_CONFIG_MESSAGE);
125015
+ super(t("tui.invalid_config"));
125183
125016
  this.fallback = fallback;
125184
125017
  }
125185
125018
  };
@@ -135236,7 +135069,7 @@ function generateConfig$1(platform) {
135236
135069
  "type = \"claudecode\"",
135237
135070
  "",
135238
135071
  "[projects.agent.options]",
135239
- `cli_path = '${escapeSingleQuotes(detectScreamPath$1())}'`,
135072
+ `cmd = '${escapeSingleQuotes(detectScreamPath$1())}'`,
135240
135073
  `work_dir = '${escapeSingleQuotes(process.cwd())}'`,
135241
135074
  "mode = \"default\"",
135242
135075
  "",
@@ -135580,134 +135413,130 @@ var MoonLoader = class extends Text {
135580
135413
  *
135581
135414
  * Used when the remote marketplace cannot be fetched at runtime.
135582
135415
  */
135583
- const FALLBACK_SKILL_MARKETPLACE = [
135584
- {
135585
- id: "gsap-skills",
135586
- displayName: t("market.gsap_name"),
135587
- description: t("market.gsap_desc"),
135588
- source: "https://github.com/greensock/gsap-skills"
135589
- },
135590
- {
135591
- id: "claude-design-card",
135592
- displayName: t("market.design_card_name"),
135593
- description: t("market.design_card_desc"),
135594
- source: "https://github.com/geekjourneyx/claude-design-card"
135595
- },
135596
- {
135597
- id: "superpowers",
135598
- displayName: t("market.superpowers_name"),
135599
- description: t("market.superpowers_desc"),
135600
- source: "https://github.com/obra/superpowers"
135601
- },
135602
- {
135603
- id: "audio-skill",
135604
- displayName: t("market.audio_name"),
135605
- description: t("market.audio_desc"),
135606
- source: "https://github.com/LIUTod/audio-skill"
135607
- },
135608
- {
135609
- id: "scrapling-skill",
135610
- displayName: t("market.scrapling_name"),
135611
- description: t("market.scrapling_desc"),
135612
- source: "https://github.com/Cedriccmh/claude-code-skill-scrapling"
135613
- },
135614
- {
135615
- id: "a-stock-data",
135616
- displayName: t("market.astock_name"),
135617
- description: t("market.astock_desc"),
135618
- source: "https://github.com/simonlin1212/a-stock-data"
135619
- },
135620
- {
135621
- id: "humanizer",
135622
- displayName: t("market.humanizer_name"),
135623
- description: t("market.humanizer_desc"),
135624
- source: "https://github.com/blader/humanizer"
135625
- },
135626
- {
135627
- id: "patent-disclosure-skill",
135628
- displayName: t("market.patent_name"),
135629
- description: t("market.patent_desc"),
135630
- source: "https://github.com/handsomestWei/patent-disclosure-skill"
135631
- },
135632
- {
135633
- id: "contract-review-pro",
135634
- displayName: t("market.contract_name"),
135635
- description: t("market.contract_desc"),
135636
- source: "https://github.com/CSlawyer1985/contract-review-pro"
135637
- },
135638
- {
135639
- id: "academic-research-skills",
135640
- displayName: t("market.academic_name"),
135641
- description: t("market.academic_desc"),
135642
- source: "https://github.com/Imbad0202/academic-research-skills"
135643
- },
135644
- {
135645
- id: "headroom",
135646
- displayName: t("market.headroom_name"),
135647
- description: t("market.headroom_desc"),
135648
- source: "https://github.com/chopratejas/headroom"
135649
- },
135650
- {
135651
- id: "xiaohu-wechat-format",
135652
- displayName: t("market.xiaohu_wechat_name"),
135653
- description: t("market.xiaohu_wechat_desc"),
135654
- source: "https://github.com/xiaohuailabs/xiaohu-wechat-format"
135655
- },
135656
- {
135657
- id: "huashu-design",
135658
- displayName: t("market.huashu_name"),
135659
- description: t("market.huashu_desc"),
135660
- source: "https://github.com/alchaincyf/huashu-design"
135661
- },
135662
- {
135663
- id: "html-video",
135664
- displayName: t("market.html_video_name"),
135665
- description: t("market.html_video_desc"),
135666
- source: "https://github.com/nexu-io/html-video"
135667
- },
135668
- {
135669
- id: "xiaohu-video-translate",
135670
- displayName: t("market.xiaohu_translate_name"),
135671
- description: t("market.xiaohu_translate_desc"),
135672
- source: "https://github.com/xiaohuailabs/xiaohu-video-translate"
135673
- },
135674
- {
135675
- id: "videocut-skills",
135676
- displayName: t("market.videocut_name"),
135677
- description: t("market.videocut_desc"),
135678
- source: "https://github.com/Ceeon/videocut-skills"
135679
- },
135680
- {
135681
- id: "taste-skill",
135682
- displayName: t("market.taste_name"),
135683
- description: t("market.taste_desc"),
135684
- source: "https://github.com/Leonxlnx/taste-skill"
135685
- },
135686
- {
135687
- id: "vtake-skills",
135688
- displayName: t("market.vtake_name"),
135689
- description: t("market.vtake_desc"),
135690
- source: "https://github.com/notedit/vtake-skills"
135691
- },
135692
- {
135693
- id: "remotion-skills",
135694
- displayName: t("market.remotion_name"),
135695
- description: t("market.remotion_desc"),
135696
- source: "https://github.com/remotion-dev/skills"
135697
- },
135698
- {
135699
- id: "html-anything",
135700
- displayName: t("market.html_anything_name"),
135701
- description: t("market.html_anything_desc"),
135702
- source: "https://github.com/nexu-io/html-anything"
135703
- },
135704
- {
135705
- id: "guizang-social-card-skill",
135706
- displayName: t("market.guizang_name"),
135707
- description: t("market.guizang_desc"),
135708
- source: "https://github.com/op7418/guizang-social-card-skill"
135709
- }
135710
- ];
135416
+ function getFallbackSkillMarketplace() {
135417
+ return [
135418
+ {
135419
+ id: "gsap-skills",
135420
+ displayName: t("market.gsap_name"),
135421
+ description: t("market.gsap_desc"),
135422
+ source: "https://github.com/greensock/gsap-skills"
135423
+ },
135424
+ {
135425
+ id: "claude-design-card",
135426
+ displayName: t("market.design_card_name"),
135427
+ description: t("market.design_card_desc"),
135428
+ source: "https://github.com/geekjourneyx/claude-design-card"
135429
+ },
135430
+ {
135431
+ id: "superpowers",
135432
+ displayName: t("market.superpowers_name"),
135433
+ description: t("market.superpowers_desc"),
135434
+ source: "https://github.com/obra/superpowers"
135435
+ },
135436
+ {
135437
+ id: "scrapling-skill",
135438
+ displayName: t("market.scrapling_name"),
135439
+ description: t("market.scrapling_desc"),
135440
+ source: "https://github.com/Cedriccmh/claude-code-skill-scrapling"
135441
+ },
135442
+ {
135443
+ id: "a-stock-data",
135444
+ displayName: t("market.astock_name"),
135445
+ description: t("market.astock_desc"),
135446
+ source: "https://github.com/simonlin1212/a-stock-data"
135447
+ },
135448
+ {
135449
+ id: "humanizer",
135450
+ displayName: t("market.humanizer_name"),
135451
+ description: t("market.humanizer_desc"),
135452
+ source: "https://github.com/blader/humanizer"
135453
+ },
135454
+ {
135455
+ id: "patent-disclosure-skill",
135456
+ displayName: t("market.patent_name"),
135457
+ description: t("market.patent_desc"),
135458
+ source: "https://github.com/handsomestWei/patent-disclosure-skill"
135459
+ },
135460
+ {
135461
+ id: "contract-review-pro",
135462
+ displayName: t("market.contract_name"),
135463
+ description: t("market.contract_desc"),
135464
+ source: "https://github.com/CSlawyer1985/contract-review-pro"
135465
+ },
135466
+ {
135467
+ id: "academic-research-skills",
135468
+ displayName: t("market.academic_name"),
135469
+ description: t("market.academic_desc"),
135470
+ source: "https://github.com/Imbad0202/academic-research-skills"
135471
+ },
135472
+ {
135473
+ id: "headroom",
135474
+ displayName: t("market.headroom_name"),
135475
+ description: t("market.headroom_desc"),
135476
+ source: "https://github.com/chopratejas/headroom"
135477
+ },
135478
+ {
135479
+ id: "xiaohu-wechat-format",
135480
+ displayName: t("market.xiaohu_wechat_name"),
135481
+ description: t("market.xiaohu_wechat_desc"),
135482
+ source: "https://github.com/xiaohuailabs/xiaohu-wechat-format"
135483
+ },
135484
+ {
135485
+ id: "huashu-design",
135486
+ displayName: t("market.huashu_name"),
135487
+ description: t("market.huashu_desc"),
135488
+ source: "https://github.com/alchaincyf/huashu-design"
135489
+ },
135490
+ {
135491
+ id: "html-video",
135492
+ displayName: t("market.html_video_name"),
135493
+ description: t("market.html_video_desc"),
135494
+ source: "https://github.com/nexu-io/html-video"
135495
+ },
135496
+ {
135497
+ id: "xiaohu-video-translate",
135498
+ displayName: t("market.xiaohu_translate_name"),
135499
+ description: t("market.xiaohu_translate_desc"),
135500
+ source: "https://github.com/xiaohuailabs/xiaohu-video-translate"
135501
+ },
135502
+ {
135503
+ id: "videocut-skills",
135504
+ displayName: t("market.videocut_name"),
135505
+ description: t("market.videocut_desc"),
135506
+ source: "https://github.com/Ceeon/videocut-skills"
135507
+ },
135508
+ {
135509
+ id: "taste-skill",
135510
+ displayName: t("market.taste_name"),
135511
+ description: t("market.taste_desc"),
135512
+ source: "https://github.com/Leonxlnx/taste-skill"
135513
+ },
135514
+ {
135515
+ id: "vtake-skills",
135516
+ displayName: t("market.vtake_name"),
135517
+ description: t("market.vtake_desc"),
135518
+ source: "https://github.com/notedit/vtake-skills"
135519
+ },
135520
+ {
135521
+ id: "remotion-skills",
135522
+ displayName: t("market.remotion_name"),
135523
+ description: t("market.remotion_desc"),
135524
+ source: "https://github.com/remotion-dev/skills"
135525
+ },
135526
+ {
135527
+ id: "html-anything",
135528
+ displayName: t("market.html_anything_name"),
135529
+ description: t("market.html_anything_desc"),
135530
+ source: "https://github.com/nexu-io/html-anything"
135531
+ },
135532
+ {
135533
+ id: "guizang-social-card-skill",
135534
+ displayName: t("market.guizang_name"),
135535
+ description: t("market.guizang_desc"),
135536
+ source: "https://github.com/op7418/guizang-social-card-skill"
135537
+ }
135538
+ ];
135539
+ }
135711
135540
  //#endregion
135712
135541
  //#region src/tui/commands/skill-center.ts
135713
135542
  const SKILL_DESC_MAX = 60;
@@ -135807,7 +135636,7 @@ async function loadMarketplace(host) {
135807
135636
  const { plugins } = await loadPluginMarketplace({ workDir: host.state.appState.workDir });
135808
135637
  return plugins;
135809
135638
  } catch {
135810
- return [...FALLBACK_SKILL_MARKETPLACE];
135639
+ return [...getFallbackSkillMarketplace()];
135811
135640
  }
135812
135641
  }
135813
135642
  function buildOptions(host, skills, plugins, marketplace) {
@@ -136006,7 +135835,7 @@ async function uninstallManualSkill(host, skill) {
136006
135835
  async function confirmUninstall(host, label, description) {
136007
135836
  return new Promise((resolve) => {
136008
135837
  const picker = new ChoicePickerComponent({
136009
- title: `${t("skill.confirm_uninstall")} "${label}"?`,
135838
+ title: t("skill.confirm_uninstall", { label }),
136010
135839
  hint: t("skill.uninstall_reversible"),
136011
135840
  options: [{
136012
135841
  value: "no",
@@ -136837,7 +136666,7 @@ function resize(){
136837
136666
  ctx.setTransform(DPR,0,0,DPR,0,0);
136838
136667
  }
136839
136668
  resize();
136840
- window.addEventListener('resize',resize);
136669
+ window.addEventListener('resize',function(){resize();markDirty()});
136841
136670
 
136842
136671
  // 相机
136843
136672
  var camRotX=0.25,camRotY=0.4;
@@ -136855,33 +136684,6 @@ var graphData;
136855
136684
  var nodePositions={};
136856
136685
  var nodeData=[];
136857
136686
 
136858
- // 节点漂浮参数:每个节点独立相位,渲染时叠加微小偏移
136859
- var floatParams={};
136860
- var frameTime=0;
136861
- function ensureFloat(id){
136862
- if(floatParams[id])return;
136863
- floatParams[id]={
136864
- phaseX:Math.random()*Math.PI*2,
136865
- phaseY:Math.random()*Math.PI*2,
136866
- phaseZ:Math.random()*Math.PI*2,
136867
- ampX:1.5+Math.random()*2.5,
136868
- ampY:1.5+Math.random()*2.5,
136869
- ampZ:1+Math.random()*2,
136870
- speed:0.0004+Math.random()*0.0004
136871
- };
136872
- }
136873
- // 返回某节点当前帧的漂浮后位置(不修改原 nodePositions,避免拾取错位)
136874
- function floatingPos(id,t){
136875
- var p=nodePositions[id];if(!p)return p;
136876
- var f=floatParams[id];if(!f)return p;
136877
- if(t===undefined)t=frameTime;
136878
- return{
136879
- x:p.x+Math.sin(t*f.speed+f.phaseX)*f.ampX,
136880
- y:p.y+Math.cos(t*f.speed*1.1+f.phaseY)*f.ampY,
136881
- z:p.z+Math.sin(t*f.speed*0.8+f.phaseZ)*f.ampZ
136882
- };
136883
- }
136884
-
136885
136687
  // ─── 3D 投影 ──────────────────────────────────────────
136886
136688
  function project(p){
136887
136689
  var cosY=Math.cos(camRotY),sinY=Math.sin(camRotY);
@@ -136985,10 +136787,6 @@ function buildNebulae(){
136985
136787
  baseX:p.x+r*Math.sin(phi)*Math.cos(theta),
136986
136788
  baseY:p.y+r*Math.sin(phi)*Math.sin(theta),
136987
136789
  baseZ:p.z+r*Math.cos(phi),
136988
- phase:Math.random()*Math.PI*2,
136989
- ampX:2+Math.random()*4,
136990
- ampY:2+Math.random()*4,
136991
- ampZ:1+Math.random()*3,
136992
136790
  size:0.5+Math.random()*0.8,
136993
136791
  op:0.15+Math.random()*0.2
136994
136792
  });
@@ -136996,19 +136794,14 @@ function buildNebulae(){
136996
136794
  });
136997
136795
  }
136998
136796
 
136999
- function drawNebulae(t){
136797
+ function drawNebulae(){
137000
136798
  ctx.save();
137001
136799
  for(var i=0;i<nebulaDots.length;i++){
137002
136800
  var d=nebulaDots[i];
137003
- // 不规则漂浮
137004
- var x=d.baseX+Math.sin(t*0.0003+d.phase)*d.ampX;
137005
- var y=d.baseY+Math.cos(t*0.0004+d.phase*1.3)*d.ampY;
137006
- var z=d.baseZ+Math.sin(t*0.0002+d.phase*0.7)*d.ampZ;
137007
- var p=project({x:x,y:y,z:z});
136801
+ var p=project({x:d.baseX,y:d.baseY,z:d.baseZ});
137008
136802
  if(p.z<=0)continue;
137009
136803
  var r=Math.max(0.3,d.size*p.scale*0.5);
137010
136804
  if(r<0.4)continue;
137011
- // 远处淡,近处稍清晰
137012
136805
  var alpha=d.op*Math.min(1,p.scale*1.5);
137013
136806
  ctx.fillStyle='rgba(0,0,0,'+alpha.toFixed(3)+')';
137014
136807
  ctx.beginPath();
@@ -137185,7 +136978,7 @@ function computeProjMap(){
137185
136978
  vis.events.forEach(function(id){visAll.add(id)});
137186
136979
  var map={allIds:visAll};
137187
136980
  visAll.forEach(function(id){
137188
- var p=floatingPos(id);
136981
+ var p=nodePositions[id];
137189
136982
  if(p)map[id]=project(p);
137190
136983
  });
137191
136984
  return map;
@@ -137217,6 +137010,7 @@ function startInertia(){
137217
137010
  camRotY+=velRotY;
137218
137011
  camRotX=Math.max(-1.2,Math.min(1.2,camRotX+velRotX));
137219
137012
  velRotX*=0.94;velRotY*=0.94;
137013
+ markDirty();
137220
137014
  inertiaRAF=requestAnimationFrame(step);
137221
137015
  }
137222
137016
  inertiaRAF=requestAnimationFrame(step);
@@ -137255,7 +137049,7 @@ function pickNode(sx,sy){
137255
137049
  vis.events.forEach(function(id){visAll.add(id)});
137256
137050
  var best=null,bestDist=Infinity;
137257
137051
  visAll.forEach(function(id){
137258
- var p=floatingPos(id);if(!p)return;
137052
+ var p=nodePositions[id];if(!p)return;
137259
137053
  var sp=project(p);
137260
137054
  if(sp.z<=0)return;
137261
137055
  var data=nodeData.find(function(n){return n.id===id});
@@ -137294,14 +137088,16 @@ canvas.addEventListener('mousemove',function(e){
137294
137088
  velRotY=(e.clientX-lastMoveX)/dt*0.005;
137295
137089
  velRotX=(e.clientY-lastMoveY)/dt*0.005;
137296
137090
  lastMoveTime=now;lastMoveX=e.clientX;lastMoveY=e.clientY;
137091
+ markDirty();
137297
137092
  }else if(isPanning){
137298
137093
  var pdx=e.clientX-dragStart.x,pdy=e.clientY-dragStart.y;
137299
137094
  var scale=fov/camDist;
137300
137095
  camTargetX=dragStart.panX - pdx*scale;
137301
137096
  camTargetY=dragStart.panY + pdy*scale;
137097
+ markDirty();
137302
137098
  }else{
137303
137099
  var id=pickNode(e.clientX,e.clientY);
137304
- if(id!==hoveredId){hoveredId=id;canvas.style.cursor=id?'pointer':'grab';}
137100
+ if(id!==hoveredId){hoveredId=id;canvas.style.cursor=id?'pointer':'grab';markDirty();}
137305
137101
  if(id)showTooltip(e.clientX,e.clientY,id);
137306
137102
  else hideTooltip();
137307
137103
  }
@@ -137325,10 +137121,10 @@ canvas.addEventListener('mouseup',function(e){
137325
137121
  if(data.kind==='event'&&!expEv.has(id))expEv.add(id);
137326
137122
  }
137327
137123
  selId=id;navStack=[];
137328
- focusOn(id);rebuildLabels();
137124
+ focusOn(id);rebuildLabels();markDirty();
137329
137125
  },250);
137330
137126
  }else{
137331
- selId=null;rebuildLabels();closeModal();
137127
+ selId=null;rebuildLabels();closeModal();markDirty();
137332
137128
  }
137333
137129
  });
137334
137130
 
@@ -137344,13 +137140,13 @@ canvas.addEventListener('dblclick',function(e){
137344
137140
  if(data){
137345
137141
  if(!expEnt.has(id)&&!expEv.has(id)){expEnt.add(id);}
137346
137142
  selId=id;navStack=[];
137347
- focusOn(id);rebuildLabels();
137143
+ focusOn(id);rebuildLabels();markDirty();
137348
137144
  showModal(id,data.kind);
137349
137145
  }
137350
137146
  }else{
137351
137147
  expEnt.clear();expEv.clear();selId=null;
137352
137148
  if(graphData)graphData.entities.forEach(function(en){expEnt.add(en.id)});
137353
- closeModal();rebuildLabels();fitView();
137149
+ closeModal();rebuildLabels();fitView();markDirty();
137354
137150
  }
137355
137151
  });
137356
137152
 
@@ -137368,6 +137164,7 @@ canvas.addEventListener('wheel',function(e){
137368
137164
  var scaleAfter=fov/camDist;
137369
137165
  camTargetX=worldX - (mx-W/2)/scaleAfter;
137370
137166
  camTargetY=worldY + (my-H/2)/scaleAfter;
137167
+ markDirty();
137371
137168
  },{passive:false});
137372
137169
 
137373
137170
  function focusOn(id){
@@ -137387,6 +137184,7 @@ function focusOn(id){
137387
137184
  camTargetY=startTy+(endTy-startTy)*e;
137388
137185
  camTargetZ=startTz+(endTz-startTz)*e;
137389
137186
  camDist=startDist+(endDist-startDist)*e;
137187
+ markDirty();
137390
137188
  if(t<1)focusAnim=requestAnimationFrame(step);
137391
137189
  }
137392
137190
  focusAnim=requestAnimationFrame(step);
@@ -137397,7 +137195,7 @@ function fitView(){
137397
137195
  var ids=[];
137398
137196
  vis.entities.forEach(function(id){ids.push(id)});
137399
137197
  vis.events.forEach(function(id){ids.push(id)});
137400
- if(!ids.length){camTargetX=0;camTargetY=0;camTargetZ=0;camDist=700;return}
137198
+ if(!ids.length){camTargetX=0;camTargetY=0;camTargetZ=0;camDist=700;markDirty();return}
137401
137199
  var x0=Infinity,x1=-Infinity,y0=Infinity,y1=-Infinity,z0=Infinity,z1=-Infinity;
137402
137200
  ids.forEach(function(id){var p=nodePositions[id];if(!p)return;if(p.x<x0)x0=p.x;if(p.x>x1)x1=p.x;if(p.y<y0)y0=p.y;if(p.y>y1)y1=p.y;if(p.z<z0)z0=p.z;if(p.z>z1)z1=p.z});
137403
137201
  var cx=(x0+x1)/2,cy=(y0+y1)/2,cz=(z0+z1)/2;
@@ -137418,6 +137216,7 @@ function fitView(){
137418
137216
  camDist=startDist+(endDist-startDist)*e;
137419
137217
  camRotX=startRotX+(endRotX-startRotX)*e;
137420
137218
  camRotY=startRotY+(endRotY-startRotY)*e;
137219
+ markDirty();
137421
137220
  if(t<1)focusAnim=requestAnimationFrame(step);
137422
137221
  }
137423
137222
  focusAnim=requestAnimationFrame(step);
@@ -137432,6 +137231,7 @@ function startAutoRotate(){
137432
137231
  var t=Math.min(1,elapsed/duration);
137433
137232
  var fade=1-t;
137434
137233
  camRotY+=speed*fade;
137234
+ markDirty();
137435
137235
  if(t<1)autoRotRAF=requestAnimationFrame(step);
137436
137236
  }
137437
137237
  autoRotRAF=requestAnimationFrame(step);
@@ -137494,14 +137294,14 @@ function esc(s){if(!s)return'';return String(s).replace(/&/g,'&amp;').replace(/<
137494
137294
  document.getElementById('btn-reset').onclick=function(){
137495
137295
  expEnt.clear();expEv.clear();selId=null;
137496
137296
  if(graphData)graphData.entities.forEach(function(e){expEnt.add(e.id)});
137497
- closeModal();rebuildLabels();fitView();
137297
+ closeModal();rebuildLabels();fitView();markDirty();
137498
137298
  };
137499
137299
  document.getElementById('btn-expand').onclick=function(){
137500
137300
  if(graphData){
137501
137301
  graphData.entities.forEach(function(e){expEnt.add(e.id)});
137502
137302
  graphData.events.forEach(function(e){expEv.add(e.id)});
137503
137303
  }
137504
- selId=null;closeModal();rebuildLabels();fitView();
137304
+ selId=null;closeModal();rebuildLabels();fitView();markDirty();
137505
137305
  };
137506
137306
  document.getElementById('btn-close').onclick=closeModal;
137507
137307
  document.getElementById('modal-mask').addEventListener('click',closeModal);
@@ -137543,11 +137343,12 @@ window.addEventListener('keydown',function(e){
137543
137343
  if(e.key==='Escape'){
137544
137344
  if(document.getElementById('modal').classList.contains('open'))closeModal();
137545
137345
  else{selId=null;rebuildLabels()}
137346
+ markDirty();
137546
137347
  }else if(e.key===' '){
137547
137348
  e.preventDefault();
137548
137349
  expEnt.clear();expEv.clear();selId=null;
137549
137350
  if(graphData)graphData.entities.forEach(function(en){expEnt.add(en.id)});
137550
- closeModal();rebuildLabels();fitView();
137351
+ closeModal();rebuildLabels();fitView();markDirty();
137551
137352
  }else if(e.key==='ArrowRight'||e.key==='ArrowDown'){e.preventDefault();navigateRelated('next');}
137552
137353
  else if(e.key==='ArrowLeft'||e.key==='ArrowUp'){e.preventDefault();navigateRelated('prev');}
137553
137354
  });
@@ -137557,7 +137358,7 @@ var searchInput=document.getElementById('search-input');
137557
137358
  var searchQuery='',searchMatches=null;
137558
137359
  searchInput.addEventListener('input',function(){
137559
137360
  searchQuery=searchInput.value.trim().toLowerCase();
137560
- if(!searchQuery){searchMatches=null;rebuildLabels();return}
137361
+ if(!searchQuery){searchMatches=null;rebuildLabels();markDirty();return}
137561
137362
  searchMatches=new Set();
137562
137363
  var firstMatch=null;
137563
137364
  if(graphData){
@@ -137588,9 +137389,10 @@ searchInput.addEventListener('input',function(){
137588
137389
  });
137589
137390
  selId=firstMatch;focusOn(firstMatch);rebuildLabels();
137590
137391
  }
137392
+ markDirty();
137591
137393
  });
137592
137394
  searchInput.addEventListener('keydown',function(e){
137593
- if(e.key==='Escape'){searchInput.value='';searchQuery='';searchMatches=null;rebuildLabels();searchInput.blur();}
137395
+ if(e.key==='Escape'){searchInput.value='';searchQuery='';searchMatches=null;rebuildLabels();searchInput.blur();markDirty();}
137594
137396
  else if(e.key==='Enter'&&searchMatches&&searchMatches.size>0){
137595
137397
  var first=Array.from(searchMatches)[0];
137596
137398
  var data=nodeData.find(function(n){return n.id===first});
@@ -137670,20 +137472,24 @@ miniCanvas.addEventListener('click',function(e){
137670
137472
  var e=t<.5?2*t*t:1-Math.pow(-2*t+2,2)/2;
137671
137473
  camTargetX=startTx+(worldX-startTx)*e;
137672
137474
  camTargetZ=startTz+(worldZ-startTz)*e;
137475
+ markDirty();
137673
137476
  if(t<1)focusAnim=requestAnimationFrame(step);
137674
137477
  }
137675
137478
  focusAnim=requestAnimationFrame(step);
137676
137479
  });
137677
137480
 
137678
137481
  // ─── 主渲染循环 ──────────────────────────────────────
137482
+ var dirty=true;
137483
+ function markDirty(){dirty=true}
137679
137484
  function animate(){
137680
137485
  requestAnimationFrame(animate);
137681
137486
  if(!graphData)return;
137682
- frameTime=performance.now();
137487
+ if(!dirty)return;
137488
+ dirty=false;
137683
137489
  ctx.clearRect(0,0,W,H);
137684
137490
  ctx.fillStyle='#fafafa';
137685
137491
  ctx.fillRect(0,0,W,H);
137686
- drawNebulae(frameTime);
137492
+ drawNebulae();
137687
137493
  var projMap=computeProjMap();
137688
137494
  var connSet=computeConnSet(projMap.allIds);
137689
137495
  drawEdges(projMap,connSet);
@@ -137736,11 +137542,11 @@ fetch('/api/graph').then(function(r){return r.json()}).then(function(data){
137736
137542
  });
137737
137543
  forceLayout3D();
137738
137544
  buildNebulae();
137739
- nodeData.forEach(function(n){ensureFloat(n.id)});
137740
137545
  rebuildLabels();
137741
137546
  fitView();
137742
137547
  animate();
137743
137548
  startAutoRotate();
137549
+ new EventSource('/api/heartbeat');
137744
137550
  }).catch(function(err){
137745
137551
  document.getElementById('loading').style.display='none';
137746
137552
  errorMsg.style.display='block';
@@ -137864,6 +137670,22 @@ async function handleWeb(host) {
137864
137670
  serveGraphJSON(store, res);
137865
137671
  return;
137866
137672
  }
137673
+ if (req.url === "/api/heartbeat") {
137674
+ res.writeHead(200, {
137675
+ "Content-Type": "text/event-stream",
137676
+ "Cache-Control": "no-store",
137677
+ Connection: "keep-alive"
137678
+ });
137679
+ const timer = setInterval(() => {
137680
+ res.write(": ping\n\n");
137681
+ }, 15e3);
137682
+ res.on("close", () => {
137683
+ clearInterval(timer);
137684
+ server.close();
137685
+ });
137686
+ res.write(": ok\n\n");
137687
+ return;
137688
+ }
137867
137689
  serveHTML(res, getLocale());
137868
137690
  });
137869
137691
  registerServer(server);
@@ -146316,6 +146138,7 @@ function sessionRowsForPicker(sessions, currentSessionId, currentSessionHasConte
146316
146138
  title: session.title ?? null,
146317
146139
  last_prompt: session.lastPrompt ?? null,
146318
146140
  work_dir: session.workDir,
146141
+ session_dir: session.sessionDir ?? "",
146319
146142
  updated_at: session.updatedAt ?? session.createdAt ?? 0,
146320
146143
  metadata: session.metadata
146321
146144
  }));
@@ -147856,6 +147679,24 @@ var MemoryPickerComponent = class extends Container {
147856
147679
  }
147857
147680
  };
147858
147681
  //#endregion
147682
+ //#region src/tui/utils/session-label.ts
147683
+ /**
147684
+ * Helpers for composing session labels in the session picker.
147685
+ *
147686
+ * Detection rule for the `[imported]` badge: `metadata.imported_from_scream_cli`
147687
+ * is strictly the boolean `true`. This mirrors the value written by
147688
+ * the old migration-legacy package into the session's `state.json` `custom` block.
147689
+ */
147690
+ const IMPORTED_BADGE = "[已导入]";
147691
+ const IMPORTED_FLAG_KEY = "imported_from_scream_cli";
147692
+ function isImportedSession(metadata) {
147693
+ if (metadata === void 0) return false;
147694
+ return metadata[IMPORTED_FLAG_KEY] === true;
147695
+ }
147696
+ function formatSessionLabel(input) {
147697
+ return `${isImportedSession(input.metadata) ? `${IMPORTED_BADGE} ` : ""}${input.title}`;
147698
+ }
147699
+ //#endregion
147859
147700
  //#region src/tui/components/dialogs/session-picker.ts
147860
147701
  /**
147861
147702
  * SessionPicker — pi-tui version of the session selection dialog.
@@ -147906,6 +147747,7 @@ var SessionPickerComponent = class extends Container {
147906
147747
  onSelect;
147907
147748
  onCancel;
147908
147749
  onDelete;
147750
+ onStatus;
147909
147751
  maxVisibleSessions;
147910
147752
  loading;
147911
147753
  focused = false;
@@ -147920,6 +147762,7 @@ var SessionPickerComponent = class extends Container {
147920
147762
  this.onSelect = opts.onSelect;
147921
147763
  this.onCancel = opts.onCancel;
147922
147764
  this.onDelete = opts.onDelete;
147765
+ this.onStatus = opts.onStatus;
147923
147766
  this.maxVisibleSessions = opts.maxVisibleSessions ?? 4;
147924
147767
  }
147925
147768
  handleInput(data) {
@@ -147936,9 +147779,17 @@ var SessionPickerComponent = class extends Container {
147936
147779
  if (!session) return;
147937
147780
  if (this.confirmingDelete) {
147938
147781
  this.confirmingDelete = false;
147782
+ if (session.metadata?.["source"] === "cc-connect") {
147783
+ this.onStatus(t("session_picker.cc_restricted"));
147784
+ return;
147785
+ }
147939
147786
  this.onDelete?.(session.id);
147940
147787
  return;
147941
147788
  }
147789
+ if (session.metadata?.["source"] === "cc-connect") {
147790
+ this.onStatus(t("session_picker.cc_restricted"));
147791
+ return;
147792
+ }
147942
147793
  this.onSelect(session.id);
147943
147794
  return;
147944
147795
  }
@@ -147955,7 +147806,12 @@ var SessionPickerComponent = class extends Container {
147955
147806
  const k = printableChar(data);
147956
147807
  if ((k === "d" || k === "D") && !this.confirmingDelete && this.sessions.length > 0) {
147957
147808
  const session = this.sessions[this.selectedIndex];
147958
- if (session && session.id !== this.currentSessionId) this.confirmingDelete = true;
147809
+ if (!session) return;
147810
+ if (session.metadata?.["source"] === "cc-connect") {
147811
+ this.onStatus(t("session_picker.cc_restricted"));
147812
+ return;
147813
+ }
147814
+ if (session.id !== this.currentSessionId) this.confirmingDelete = true;
147959
147815
  }
147960
147816
  }
147961
147817
  render(width) {
@@ -148026,12 +147882,12 @@ var SessionPickerComponent = class extends Container {
148026
147882
  const metaGap = " ";
148027
147883
  const metaGapWidth = visibleWidth(metaGap);
148028
147884
  const idLineWidth = indentWidth + idWidth;
148029
- const aliasedDir = homeAlias(session.work_dir);
148030
- const dirWidth = visibleWidth(aliasedDir);
148031
- if (idLineWidth + metaGapWidth + dirWidth <= width) card.push(indent + chalk.hex(colors.textMuted)(fullId) + chalk.hex(colors.textDim)(metaGap) + chalk.hex(colors.textMuted)(aliasedDir));
147885
+ const displayDir = session.session_dir ? homeAlias(session.session_dir) : homeAlias(session.work_dir);
147886
+ const dirWidth = visibleWidth(displayDir);
147887
+ if (idLineWidth + metaGapWidth + dirWidth <= width) card.push(indent + chalk.hex(colors.textMuted)(fullId) + chalk.hex(colors.textDim)(metaGap) + chalk.hex(colors.textMuted)(displayDir));
148032
147888
  else {
148033
147889
  card.push(indent + chalk.hex(colors.textMuted)(truncateToWidth(fullId, Math.max(idWidth, width - indentWidth), ELLIPSIS)));
148034
- const dir = truncatePathLeft(aliasedDir, Math.max(8, width - indentWidth));
147890
+ const dir = truncatePathLeft(displayDir, Math.max(8, width - indentWidth));
148035
147891
  card.push(indent + chalk.hex(colors.textMuted)(dir));
148036
147892
  }
148037
147893
  const rawPrompt = session.last_prompt?.trim();
@@ -148693,6 +148549,9 @@ var DialogManager = class {
148693
148549
  loading: this.host.getIsLoadingSessions(),
148694
148550
  currentSessionId: this.host.getCurrentSessionId(),
148695
148551
  colors: this.host.state.theme.colors,
148552
+ onStatus: (message) => {
148553
+ this.host.showStatus(message);
148554
+ },
148696
148555
  onSelect: (pickerId) => {
148697
148556
  const row = this.host.getSessions().find((s) => s.id === pickerId);
148698
148557
  const isCc = row?.metadata?.["source"] === "cc-connect";
@@ -149940,7 +149799,7 @@ function generateConfig(cliPath, platformType) {
149940
149799
  "type = \"claudecode\"",
149941
149800
  "",
149942
149801
  "[projects.agent.options]",
149943
- `cli_path = '${cliPath}'`,
149802
+ `cmd = '${cliPath}'`,
149944
149803
  `work_dir = '${workDir}'`,
149945
149804
  "mode = \"default\"",
149946
149805
  "",
@@ -150087,13 +149946,15 @@ var ClaudeStreamJsonWriter = class {
150087
149946
  this.currentModel = model;
150088
149947
  }
150089
149948
  /** Emit the `system` / `init` event. Called once after session creation. */
150090
- emitSystem(sessionId) {
149949
+ emitSystem(sessionId, model) {
150091
149950
  this.sessionId = sessionId;
150092
- this.writeJson({
149951
+ const event = {
150093
149952
  type: "system",
150094
149953
  subtype: "init",
150095
149954
  session_id: sessionId
150096
- });
149955
+ };
149956
+ if (model) event["model"] = model;
149957
+ this.writeLine(JSON.stringify(event));
150097
149958
  }
150098
149959
  /** Accumulate assistant text delta. Flush buffered thinking first. */
150099
149960
  writeAssistantDelta(delta) {
@@ -150204,14 +150065,16 @@ var ClaudeStreamJsonWriter = class {
150204
150065
  content: `Resume this session: scream -r ${sessionId}`
150205
150066
  });
150206
150067
  }
150207
- /** Emit a `control_request` event for cc-connect permission flow. */
150068
+ /** Emit a `control_request` event for cc-connect permission flow.
150069
+ * Format matches cc-connect's handleControlRequest which expects
150070
+ * `request.subtype = "can_use_tool"`, `request.tool_name`, `request.input`. */
150208
150071
  emitControlRequest(requestId, toolCallId, toolName, input) {
150209
150072
  this.writeJson({
150210
150073
  type: "control_request",
150211
150074
  request_id: requestId,
150212
- tool_use: {
150213
- id: toolCallId,
150214
- name: toolName,
150075
+ request: {
150076
+ subtype: "can_use_tool",
150077
+ tool_name: toolName,
150215
150078
  input
150216
150079
  }
150217
150080
  });
@@ -150263,7 +150126,7 @@ async function* readStdinMessages() {
150263
150126
  log.warn("stream-json: failed to parse stdin line", { line: trimmed.slice(0, 200) });
150264
150127
  continue;
150265
150128
  }
150266
- if (msg.type === "user" || msg.type === "control_response") yield msg;
150129
+ if (msg.type === "user" || msg.type === "control_response" || msg.type === "control_cancel_request") yield msg;
150267
150130
  else log.debug("stream-json: ignoring unknown stdin message type", { type: msg.type });
150268
150131
  }
150269
150132
  }
@@ -150351,7 +150214,8 @@ async function runStreamJson(opts) {
150351
150214
  error: String(error)
150352
150215
  });
150353
150216
  }
150354
- if (appendPrompt) {
150217
+ const hasSystemPrompt = opts.systemPrompt && opts.systemPrompt.trim().length > 0;
150218
+ if (hasSystemPrompt || appendPrompt) {
150355
150219
  try {
150356
150220
  originalAgentsMd = await readFile(agentsMdPath, "utf-8");
150357
150221
  } catch {}
@@ -150360,10 +150224,13 @@ async function runStreamJson(opts) {
150360
150224
  cc-connect send --image /absolute/path/to/image.png
150361
150225
  cc-connect send --file /absolute/path/to/file.pdf
150362
150226
  当用户要求你发送文件、截图、生成的图片时,使用 Bash 工具执行上述命令即可。
150363
- \n${appendPrompt}`;
150227
+ \n${hasSystemPrompt ? `# System Prompt (from --system-prompt)\n\n${opts.systemPrompt}\n` : ""}\n${appendPrompt ? appendPrompt : ""}`;
150364
150228
  await writeFile(agentsMdPath, originalAgentsMd ? `${ccPrompt}\n\n${originalAgentsMd}` : ccPrompt, "utf-8");
150365
150229
  injectedAgentsMd = true;
150366
- log.info("stream-json: injected cc-connect system prompt into AGENTS.md");
150230
+ log.info("stream-json: injected cc-connect system prompt into AGENTS.md", {
150231
+ hasSystemPrompt,
150232
+ hasAppendPrompt: appendPrompt.length > 0
150233
+ });
150367
150234
  }
150368
150235
  try {
150369
150236
  await harness.ensureConfigFile();
@@ -150382,6 +150249,17 @@ async function runStreamJson(opts) {
150382
150249
  } else log.warn("stream-json: control_response for unknown request_id", { requestId: msg.response.request_id });
150383
150250
  continue;
150384
150251
  }
150252
+ if (msg.type === "control_cancel_request") {
150253
+ const pending = pendingApprovals.get(msg.request_id);
150254
+ if (pending) {
150255
+ pendingApprovals.delete(msg.request_id);
150256
+ pending.resolve({
150257
+ decision: "rejected",
150258
+ feedback: "Permission request cancelled"
150259
+ });
150260
+ }
150261
+ continue;
150262
+ }
150385
150263
  const userText = extractUserText(msg);
150386
150264
  if (!userText) {
150387
150265
  log.warn("stream-json: empty user message, skipping");
@@ -150414,7 +150292,12 @@ async function runStreamJson(opts) {
150414
150292
  workDir,
150415
150293
  model,
150416
150294
  permission: mappedPermission,
150417
- planMode: mappedPlanMode
150295
+ planMode: mappedPlanMode,
150296
+ thinking: opts.effort,
150297
+ metadata: {
150298
+ source: "cc-connect",
150299
+ agentType: "scream-code"
150300
+ }
150418
150301
  });
150419
150302
  log.info("stream-json: recreated session", { sessionId: session.id });
150420
150303
  }
@@ -150425,14 +150308,19 @@ async function runStreamJson(opts) {
150425
150308
  workDir,
150426
150309
  model,
150427
150310
  permission: mappedPermission,
150428
- planMode: mappedPlanMode
150311
+ planMode: mappedPlanMode,
150312
+ thinking: opts.effort,
150313
+ metadata: {
150314
+ source: "cc-connect",
150315
+ agentType: "scream-code"
150316
+ }
150429
150317
  });
150430
150318
  log.info("stream-json: created session", { sessionId: session.id });
150431
150319
  }
150432
150320
  currentSessionId = session.id;
150433
150321
  writer.setSessionId(session.id);
150434
150322
  writer.setModel(opts.model ?? config.defaultModel ?? "");
150435
- writer.emitSystem(sessionKey);
150323
+ writer.emitSystem(sessionKey, opts.model ?? config.defaultModel);
150436
150324
  function sendControlRequest(request) {
150437
150325
  let resolve;
150438
150326
  const promise = new Promise((res) => {
@@ -150443,25 +150331,55 @@ async function runStreamJson(opts) {
150443
150331
  writer.emitControlRequest(reqId, request.toolCallId, request.toolName, request.display);
150444
150332
  return promise;
150445
150333
  }
150334
+ const allowedSet = opts.allowedTools ? new Set(opts.allowedTools.split(",").map((t) => t.trim()).filter(Boolean)) : void 0;
150335
+ const disallowedSet = opts.disallowedTools ? new Set(opts.disallowedTools.split(",").map((t) => t.trim()).filter(Boolean)) : void 0;
150336
+ function isToolBlocked(toolName) {
150337
+ if (disallowedSet?.has(toolName)) return true;
150338
+ if (allowedSet && allowedSet.size > 0 && !allowedSet.has(toolName)) return true;
150339
+ return false;
150340
+ }
150446
150341
  switch (opts.permissionMode) {
150447
150342
  case "yolo":
150448
150343
  case "bypassPermissions":
150449
- session.setApprovalHandler(() => ({ decision: "approved" }));
150344
+ session.setApprovalHandler((request) => {
150345
+ if (isToolBlocked(request.toolName)) return {
150346
+ decision: "rejected",
150347
+ feedback: `Tool ${request.toolName} is disallowed`
150348
+ };
150349
+ return { decision: "approved" };
150350
+ });
150450
150351
  break;
150451
150352
  case "dontAsk":
150452
- session.setApprovalHandler(() => ({
150453
- decision: "rejected",
150454
- feedback: "dontAsk 模式下工具调用被自动拒绝"
150455
- }));
150353
+ session.setApprovalHandler((request) => {
150354
+ if (disallowedSet?.has(request.toolName)) return {
150355
+ decision: "rejected",
150356
+ feedback: `Tool ${request.toolName} is disallowed`
150357
+ };
150358
+ if (allowedSet?.has(request.toolName)) return { decision: "approved" };
150359
+ return {
150360
+ decision: "rejected",
150361
+ feedback: "dontAsk mode: tool call auto-denied"
150362
+ };
150363
+ });
150456
150364
  break;
150457
150365
  case "acceptEdits":
150458
150366
  session.setApprovalHandler((request) => {
150367
+ if (isToolBlocked(request.toolName)) return {
150368
+ decision: "rejected",
150369
+ feedback: `Tool ${request.toolName} is disallowed`
150370
+ };
150459
150371
  if (["Edit", "Write"].includes(request.toolName)) return { decision: "approved" };
150460
150372
  return sendControlRequest(request);
150461
150373
  });
150462
150374
  break;
150463
150375
  default:
150464
- session.setApprovalHandler((request) => sendControlRequest(request));
150376
+ session.setApprovalHandler((request) => {
150377
+ if (isToolBlocked(request.toolName)) return {
150378
+ decision: "rejected",
150379
+ feedback: `Tool ${request.toolName} is disallowed`
150380
+ };
150381
+ return sendControlRequest(request);
150382
+ });
150465
150383
  break;
150466
150384
  }
150467
150385
  session.setQuestionHandler(() => null);
@@ -150526,6 +150444,10 @@ async function runStreamJson(opts) {
150526
150444
  if (type === "turn.step.started" || type === "turn.step.interrupted") writer.flushAssistant();
150527
150445
  else if (type === "turn.step.retrying") writer.discardAssistant();
150528
150446
  else if (type === "assistant.delta") writer.writeAssistantDelta(event.delta);
150447
+ else if (type === "thinking.delta") writer.writeThinkingDelta(event.delta);
150448
+ else if (type === "tool.call.started") writer.writeToolCall(event.toolCallId, event.name, event.args);
150449
+ else if (type === "tool.call.delta") writer.writeToolCallDelta(event.toolCallId, event.name, event.argumentsPart);
150450
+ else if (type === "tool.result") writer.writeToolResult(event.toolCallId, event.output, event.isError);
150529
150451
  else if (type === "turn.step.completed") {
150530
150452
  if (event.usage) {
150531
150453
  const inputTotal = (event.usage.inputOther ?? 0) + (event.usage.inputCacheRead ?? 0) + (event.usage.inputCacheCreation ?? 0);
@@ -150658,11 +150580,6 @@ async function handleMainCommand(opts, version) {
150658
150580
  }
150659
150581
  await runShell(validated.options, version);
150660
150582
  }
150661
- /** `scream migrate` — permanently disabled. */
150662
- async function handleMigrateCommand() {
150663
- process.stdout.write("迁移功能已取消,不再支持从 scream-cli 导入数据。\n");
150664
- process.exit(0);
150665
- }
150666
150583
  function main() {
150667
150584
  initProcessName();
150668
150585
  const version = getVersion();
@@ -150674,13 +150591,6 @@ function main() {
150674
150591
  process.stderr.write(`查看日志:${resolveGlobalLogPath(resolveScreamHome())}\n`);
150675
150592
  process.exit(1);
150676
150593
  });
150677
- }, () => {
150678
- handleMigrateCommand().catch(async (error) => {
150679
- await logStartupFailure("运行迁移", error);
150680
- process.stderr.write(formatStartupError(error, { operation: "运行迁移" }));
150681
- process.stderr.write(`查看日志:${resolveGlobalLogPath(resolveScreamHome())}\n`);
150682
- process.exit(1);
150683
- });
150684
150594
  }, (entry, args) => {
150685
150595
  runPluginNodeEntry(entry, args).catch(async (error) => {
150686
150596
  await logStartupFailure("运行插件节点入口", error);