scream-code 0.9.1 → 0.9.3

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";
@@ -62700,7 +62700,7 @@ async function resolveSkillRoots(options) {
62700
62700
  const roots = [];
62701
62701
  const mergeAllAvailableSkills = options.mergeAllAvailableSkills ?? true;
62702
62702
  const { userHomeDir, workDir } = options.paths;
62703
- const projectRoot = await findProjectRoot$1(workDir);
62703
+ const projectRoot = await findProjectRoot$2(workDir);
62704
62704
  if (options.explicitDirs !== void 0 && options.explicitDirs.length > 0) await pushConfiguredDirs(roots, options.explicitDirs, projectRoot, userHomeDir, "user", isDir, realpath);
62705
62705
  else {
62706
62706
  await pushBrandGroup(roots, PROJECT_BRAND_DIRS, projectRoot, "project", mergeAllAvailableSkills, isDir, realpath);
@@ -62885,7 +62885,7 @@ async function defaultIsFile(p) {
62885
62885
  return false;
62886
62886
  }
62887
62887
  }
62888
- async function findProjectRoot$1(workDir) {
62888
+ async function findProjectRoot$2(workDir) {
62889
62889
  const start = resolve$1(workDir);
62890
62890
  let current = start;
62891
62891
  while (true) {
@@ -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
@@ -81883,7 +81883,7 @@ async function loadRoleAdditional(_jian) {
81883
81883
  }
81884
81884
  async function loadAgentsMd(jian) {
81885
81885
  const workDir = jian.getcwd();
81886
- const dirs = dirsRootToLeaf(jian, workDir, await findProjectRoot(jian, workDir));
81886
+ const dirs = dirsRootToLeaf(jian, workDir, await findProjectRoot$1(jian, workDir));
81887
81887
  const discovered = [];
81888
81888
  const seen = /* @__PURE__ */ new Set();
81889
81889
  const collect = async (path) => {
@@ -81905,7 +81905,7 @@ async function loadAgentsMd(jian) {
81905
81905
  }
81906
81906
  return renderAgentFiles(discovered);
81907
81907
  }
81908
- async function findProjectRoot(jian, workDir) {
81908
+ async function findProjectRoot$1(jian, workDir) {
81909
81909
  const initial = jian.normpath(workDir);
81910
81910
  let current = initial;
81911
81911
  while (true) {
@@ -96954,7 +96954,7 @@ var coder_default = "extends: agent\nname: coder\npromptVars:\n roleAdditional:
96954
96954
  var explore_default = "extends: agent\nname: explore\npromptVars:\n roleAdditional: |\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\n\n You are a codebase exploration specialist. Your role is EXCLUSIVELY to search, read, and analyze existing code and resources. You do NOT have access to file editing tools.\n\n Your strengths:\n - Rapidly finding files using glob patterns\n - Searching code and text with powerful regex patterns\n - Reading and analyzing file contents\n - Running read-only shell commands (git log, git diff, ls, find, etc.)\n\n Guidelines:\n - Use Glob for broad file pattern matching. Patterns MUST contain a literal anchor (extension or subdirectory); pure wildcards like `*` or `**/*` are rejected by the tool.\n - Use Grep for searching file contents with regex\n - Use Read when you know the specific file path\n - Use Bash ONLY for read-only operations (ls, git status, git log, git diff, find)\n - NEVER use Bash for any file creation or modification commands\n - Adapt your search depth based on the thoroughness level specified by the caller\n - Wherever possible, spawn multiple parallel tool calls for grepping and reading files to maximize speed\n - If a search returns empty results, you MUST try at least one alternate strategy (different pattern, broader path, or alternate naming convention) before concluding the target doesn't exist\n\n If the prompt includes a <git-context> block, use it to orient yourself about the repository state before starting your investigation.\n\n You are meant to be a fast agent. Complete the search request efficiently and report your findings clearly in a structured format.\nwhenToUse: |\n Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (e.g. \"src/**/*.yaml\"), search code for keywords (e.g. \"database connection\"), or answer questions about the codebase (e.g. \"how does the auth module work?\"). When calling this agent, specify the desired thoroughness level: \"quick\" for basic searches, \"medium\" for moderate exploration, or \"thorough\" for comprehensive analysis across multiple locations and naming conventions. Use this agent for any read-only exploration that will clearly require more than 3 search queries. Prefer launching multiple explore agents concurrently when investigating independent questions.\ntools:\n - Bash\n - Read\n - ReadMediaFile\n - Glob\n - Grep\n - WebSearch\n - MemoryLookup\n - MemoryConsolidatePlan\n - MemoryConsolidateApply\n - FetchURL\n";
96955
96955
  //#endregion
96956
96956
  //#region ../../packages/agent-core/src/profile/default/init.md
96957
- var init_default = "You are a software engineering expert with many years of programming experience. Please explore the current project directory to understand the project's architecture and main details.\n\nTask requirements:\n1. Analyze the project structure and identify key configuration files (such as pyproject.toml, package.json, Cargo.toml, etc.).\n2. Understand the project's technology stack, build process and runtime architecture.\n3. Identify how the code is organized and main module divisions.\n4. Discover project-specific development conventions, testing strategies, and deployment processes.\n\nAfter the exploration, you should do a thorough summary of your findings and overwrite it into `AGENTS.md` file in the project root. You need to refer to what is already in the file when you do so.\n\nFor your information, `AGENTS.md` is a file intended to be read by AI coding agents. Expect the reader of this file know nothing about the project.\n\nYou should compose this file according to the actual project content. Do not make any assumptions or generalizations. Ensure the information is accurate and useful. You must use the natural language that is mainly used in the project's comments and documentation.\n\nPopular sections that people usually write in `AGENTS.md` are:\n\n- Project overview\n- Build and test commands\n- Code style guidelines\n- Testing instructions\n- Security considerations\n";
96957
+ var init_default = "You are a software engineering expert with many years of programming experience. The user wants to generate an `AGENTS.md` file for their project.\n\nThe `AGENTS.md` file MUST be written to `<TARGET_DIR>/AGENTS.md`. <SCOPE_HINT>\n\nTask requirements:\n1. Analyze the project structure and identify key configuration files (such as pyproject.toml, package.json, Cargo.toml, etc.).\n2. Understand the project's technology stack, build process and runtime architecture.\n3. Identify how the code is organized and main module divisions.\n4. Discover project-specific development conventions, testing strategies, and deployment processes.\n\nAfter the exploration, you should do a thorough summary of your findings and overwrite it into `AGENTS.md` file in <TARGET_DIR>. You need to refer to what is already in the file when you do so.\n\nFor your information, `AGENTS.md` is a file intended to be read by AI coding agents. Expect the reader of this file know nothing about the project.\n\nYou should compose this file according to the actual project content. Do not make any assumptions or generalizations. Ensure the information is accurate and useful. You must use the natural language that is mainly used in the project's comments and documentation.\n\nPopular sections that people usually write in `AGENTS.md` are:\n\n- Project overview\n- Build and test commands\n- Code style guidelines\n- Testing instructions\n- Security considerations\n";
96958
96958
  //#endregion
96959
96959
  //#region ../../packages/agent-core/src/profile/default.ts
96960
96960
  const PROFILE_SOURCES = {
@@ -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) {
@@ -104132,13 +104132,16 @@ var Session$1 = class {
104132
104132
  const context = await prepareSystemPromptContext(agent.jian);
104133
104133
  agent.useProfile(profile, context);
104134
104134
  }
104135
- async generateAgentsMd() {
104135
+ async generateAgentsMd(targetDir) {
104136
104136
  await this.skillsReady;
104137
104137
  const mainAgent = this.requireMainAgent();
104138
104138
  try {
104139
+ const workDir = mainAgent.jian.getcwd();
104140
+ const scopeHint = targetDir !== void 0 && resolve(targetDir) === resolve(workDir) ? "Strictly analyze only <TARGET_DIR>. Do NOT explore any parent directories or sibling directories outside <TARGET_DIR>." : "You may explore from the current working directory upward to <TARGET_DIR> as needed to understand the whole project.";
104141
+ const prompt = DEFAULT_INIT_PROMPT.replaceAll("<TARGET_DIR>", targetDir ?? "the project root").replaceAll("<SCOPE_HINT>", scopeHint);
104139
104142
  await (await mainAgent.subagentHost.spawn("coder", {
104140
104143
  parentToolCallId: "generate-agents-md",
104141
- prompt: DEFAULT_INIT_PROMPT,
104144
+ prompt,
104142
104145
  description: "Initialize AGENTS.md",
104143
104146
  runInBackground: false,
104144
104147
  origin: {
@@ -118957,8 +118960,8 @@ var SessionAPIImpl = class {
118957
118960
  async removeMcpServer(payload) {
118958
118961
  await this.session.mcp.removeServer(payload.name);
118959
118962
  }
118960
- generateAgentsMd(_payload) {
118961
- return this.session.generateAgentsMd();
118963
+ generateAgentsMd(payload) {
118964
+ return this.session.generateAgentsMd(payload.targetDir);
118962
118965
  }
118963
118966
  async prompt({ agentId, ...payload }) {
118964
118967
  if (agentId === "main") await this.updatePromptMetadata(promptMetadataTextFromPayload(payload));
@@ -121461,6 +121464,13 @@ const dictionaries = {
121461
121464
  "knowledge.menu_title": "SAG知识库管理",
121462
121465
  "knowledge.menu_hint": "选择操作(esc 退出)",
121463
121466
  "knowledge.op_failed": "操作失败: {msg}",
121467
+ "init.select_title": "选择 AGENTS.md 生成位置",
121468
+ "init.select_hint": "当前目录:{currentDir} · 项目根目录:{projectRoot}",
121469
+ "init.current_dir": "当前目录",
121470
+ "init.current_dir_desc": "仅在当前目录生成并分析",
121471
+ "init.project_root": "项目根目录",
121472
+ "init.project_root_desc": "基于当前目录,允许 AI 自行向上探索后生成",
121473
+ "init.cancelled": "已取消初始化",
121464
121474
  "loop.permission_auto": "权限已切到 auto(循环期间不再弹审批)。",
121465
121475
  "loop.disabled": "循环模式已关闭。",
121466
121476
  "loop.prompt_updated": "循环提示词已更新。",
@@ -121757,7 +121767,7 @@ const dictionaries = {
121757
121767
  "skill.skill_removed": "该 Skill 及其子 Skill 已从当前会话中移除。",
121758
121768
  "skill.delete_failed": "删除失败。",
121759
121769
  "skill.delete_failed_msg": "删除失败: {msg}",
121760
- "skill.confirm_uninstall": "确认卸载",
121770
+ "skill.confirm_uninstall": "确认卸载 \"{label}\"?",
121761
121771
  "skill.uninstall_reversible": "卸载后可在 Skill 中心重新安装",
121762
121772
  "skill.uninstall_yes": "是,卸载",
121763
121773
  "toolcall.bg_agent_lost": "后台 agent 丢失(会话在完成前已重启)",
@@ -122129,8 +122139,6 @@ const dictionaries = {
122129
122139
  "market.design_card_desc": "14 种设计卡片生成(封面/图文/社交分享/长篇排版),Parchment × Swiss 双风格体系",
122130
122140
  "market.superpowers_name": "Superpowers 开发技能包",
122131
122141
  "market.superpowers_desc": "14 个开发方法论技能:TDD、系统调试、代码审查、子代理驱动开发、并行代理、头脑风暴等",
122132
- "market.audio_name": "Audio Skill 录音分析",
122133
- "market.audio_desc": "本地录音分析自动化,含 RAG 知识库。适用于销售录音复盘、会议纪要、质量评分等",
122134
122142
  "market.scrapling_name": "Scrapling 网页爬取",
122135
122143
  "market.scrapling_desc": "基于 Scrapling 的智能爬虫技能,支持 Cloudflare/WAF 绕过、登录会话、自动抓取解析",
122136
122144
  "market.astock_name": "A 股数据分析",
@@ -122530,6 +122538,13 @@ const dictionaries = {
122530
122538
  "knowledge.menu_title": "SAG Knowledge Base",
122531
122539
  "knowledge.menu_hint": "Select an action (Esc to exit)",
122532
122540
  "knowledge.op_failed": "Operation failed: {msg}",
122541
+ "init.select_title": "Select AGENTS.md location",
122542
+ "init.select_hint": "Current: {currentDir} · Project root: {projectRoot}",
122543
+ "init.current_dir": "Current directory",
122544
+ "init.current_dir_desc": "Generate and analyze current directory only",
122545
+ "init.project_root": "Project root",
122546
+ "init.project_root_desc": "Start from current directory, let AI explore upward to find root",
122547
+ "init.cancelled": "Initialization cancelled",
122533
122548
  "loop.permission_auto": "Permissions switched to auto (no approvals during loop).",
122534
122549
  "loop.disabled": "Loop mode disabled.",
122535
122550
  "loop.prompt_updated": "Loop prompt updated.",
@@ -122826,7 +122841,7 @@ const dictionaries = {
122826
122841
  "skill.skill_removed": "This skill and its sub-skills have been removed from the current session.",
122827
122842
  "skill.delete_failed": "Delete failed.",
122828
122843
  "skill.delete_failed_msg": "Delete failed: {msg}",
122829
- "skill.confirm_uninstall": "Confirm Uninstall",
122844
+ "skill.confirm_uninstall": "Uninstall \"{label}\"?",
122830
122845
  "skill.uninstall_reversible": "You can reinstall from the Skill center later",
122831
122846
  "skill.uninstall_yes": "Yes, uninstall",
122832
122847
  "toolcall.bg_agent_lost": "Background agent lost (session restarted before completion)",
@@ -123198,8 +123213,6 @@ const dictionaries = {
123198
123213
  "market.design_card_desc": "14 design card generators (cover/photo/social/long-form), Parchment × Swiss dual-style system",
123199
123214
  "market.superpowers_name": "Superpowers Dev Skill Pack",
123200
123215
  "market.superpowers_desc": "14 dev methodology skills: TDD, system debugging, code review, subagent-driven dev, parallel agents, brainstorming, etc.",
123201
- "market.audio_name": "Audio Skill Recording Analysis",
123202
- "market.audio_desc": "Local recording analysis automation with RAG knowledge base. For sales review, meeting minutes, quality scoring, etc.",
123203
123216
  "market.scrapling_name": "Scrapling Web Scraper",
123204
123217
  "market.scrapling_desc": "Smart scraper based on Scrapling, supports Cloudflare/WAF bypass, login sessions, auto-extraction",
123205
123218
  "market.astock_name": "A-Share Data Analysis",
@@ -123549,7 +123562,10 @@ var SDKRpcClient = class {
123549
123562
  });
123550
123563
  }
123551
123564
  async generateAgentsMd(input) {
123552
- return (await this.getRpc()).generateAgentsMd({ sessionId: input.sessionId });
123565
+ return (await this.getRpc()).generateAgentsMd({
123566
+ sessionId: input.sessionId,
123567
+ targetDir: input.targetDir
123568
+ });
123553
123569
  }
123554
123570
  async cancel(input) {
123555
123571
  return (await this.getRpc()).cancel({
@@ -124030,9 +124046,12 @@ var Session = class {
124030
124046
  input: normalizePromptInput(input)
124031
124047
  });
124032
124048
  }
124033
- async init() {
124049
+ async init(targetDir) {
124034
124050
  this.ensureOpen();
124035
- await this.rpc.generateAgentsMd({ sessionId: this.id });
124051
+ await this.rpc.generateAgentsMd({
124052
+ sessionId: this.id,
124053
+ targetDir
124054
+ });
124036
124055
  }
124037
124056
  async cancel() {
124038
124057
  this.ensureOpen();
@@ -124719,66 +124738,6 @@ const DEFAULT_OAUTH_PROVIDER_NAME = "managed:scream-code";
124719
124738
  ErrorCodes.AUTH_LOGIN_REQUIRED;
124720
124739
  const SCREAM_CODE_PLUGIN_MARKETPLACE_URL_ENV = "SCREAM_CODE_PLUGIN_MARKETPLACE_URL";
124721
124740
  //#endregion
124722
- //#region src/migration/command.ts
124723
- function registerMigrateCommand(parent, _onMigrate) {
124724
- parent.command("migrate").description("将旧版 scream-cli 安装的数据迁移到 scream-code。(已停用)").action(() => {
124725
- process.stdout.write("迁移功能已取消,不再支持从 scream-cli 导入数据。\n");
124726
- process.exit(0);
124727
- });
124728
- }
124729
- //#endregion
124730
- //#region src/migration/badge.ts
124731
- /**
124732
- * Pure helpers for composing session labels in the session picker.
124733
- *
124734
- * Detection rule for the `[imported]` badge: `metadata.imported_from_scream_cli`
124735
- * is strictly the boolean `true`. This mirrors the value written by
124736
- * `migration-legacy` into the session's `state.json` `custom` block.
124737
- */
124738
- const IMPORTED_BADGE = "[已导入]";
124739
- const IMPORTED_FLAG_KEY = "imported_from_scream_cli";
124740
- function isImportedSession(metadata) {
124741
- if (metadata === void 0) return false;
124742
- return metadata[IMPORTED_FLAG_KEY] === true;
124743
- }
124744
- function formatSessionLabel(input) {
124745
- return `${isImportedSession(input.metadata) ? `${IMPORTED_BADGE} ` : ""}${input.title}`;
124746
- }
124747
- //#endregion
124748
- //#region ../../packages/migration-legacy/src/scream-cli-schema.ts
124749
- const OldWorkDirMetaSchema = z.object({
124750
- path: z.string(),
124751
- jian: z.string().default("local"),
124752
- last_session_id: z.string().nullable().optional()
124753
- });
124754
- z.object({ work_dirs: z.array(OldWorkDirMetaSchema).default([]) });
124755
- z.object({
124756
- version: z.number().optional(),
124757
- approval: z.object({
124758
- yolo: z.boolean().optional(),
124759
- afk: z.boolean().optional(),
124760
- auto_approve_actions: z.array(z.string()).optional()
124761
- }).partial().optional(),
124762
- additional_dirs: z.array(z.string()).optional(),
124763
- custom_title: z.string().nullable().optional(),
124764
- title_generated: z.boolean().optional(),
124765
- title_generate_attempts: z.number().optional(),
124766
- plan_mode: z.boolean().optional(),
124767
- plan_session_id: z.string().nullable().optional(),
124768
- plan_slug: z.string().nullable().optional(),
124769
- wire_mtime: z.number().nullable().optional(),
124770
- archived: z.boolean().optional(),
124771
- archived_at: z.number().nullable().optional(),
124772
- auto_archive_exempt: z.boolean().optional(),
124773
- todos: z.array(z.unknown()).optional()
124774
- }).passthrough();
124775
- //#endregion
124776
- //#region ../../packages/migration-legacy/src/steps/config.ts
124777
- function camelToSnake(s) {
124778
- return s.replaceAll(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
124779
- }
124780
- new Set(Object.keys(ScreamConfigSchema.shape).filter((k) => k !== "raw" && k !== "providers" && k !== "models" && k !== "hooks").map(camelToSnake));
124781
- //#endregion
124782
124741
  //#region src/cli/update/types.ts
124783
124742
  function emptyUpdateCache() {
124784
124743
  return {
@@ -124851,7 +124810,7 @@ function optionalBuildString(value) {
124851
124810
  return typeof value === "string" && value.length > 0 ? value : void 0;
124852
124811
  }
124853
124812
  const SCREAM_BUILD_INFO = {
124854
- version: optionalBuildString("0.9.1"),
124813
+ version: optionalBuildString("0.9.3"),
124855
124814
  channel: optionalBuildString(""),
124856
124815
  commit: optionalBuildString(""),
124857
124816
  buildTarget: optionalBuildString("darwin-arm64")
@@ -125008,11 +124967,10 @@ function errorMessage(error) {
125008
124967
  }
125009
124968
  //#endregion
125010
124969
  //#region src/cli/commands.ts
125011
- function createProgram(version, onMain, onMigrate, onPluginNodeRunner = () => {}, onStreamJson = () => {}, onChannelSetup = () => {}) {
124970
+ function createProgram(version, onMain, onPluginNodeRunner = () => {}, onStreamJson = () => {}, onChannelSetup = () => {}) {
125012
124971
  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");
125013
124972
  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);
125014
124973
  registerExportCommand(program);
125015
- registerMigrateCommand(program, onMigrate);
125016
124974
  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) => {
125017
124975
  onStreamJson({
125018
124976
  resume: subOpts["resume"],
@@ -125088,7 +125046,6 @@ function validateOptions(opts) {
125088
125046
  * Agent/runtime settings live in core's `config.toml`; this file owns only
125089
125047
  * terminal UI preferences for the scream-code client.
125090
125048
  */
125091
- const INVALID_TUI_CONFIG_MESSAGE = t("tui.invalid_config");
125092
125049
  const TuiThemeSchema = z.enum([
125093
125050
  "dark",
125094
125051
  "light",
@@ -125156,7 +125113,7 @@ var TuiConfigParseError = class extends Error {
125156
125113
  name = "TuiConfigParseError";
125157
125114
  fallback;
125158
125115
  constructor(fallback) {
125159
- super(INVALID_TUI_CONFIG_MESSAGE);
125116
+ super(t("tui.invalid_config"));
125160
125117
  this.fallback = fallback;
125161
125118
  }
125162
125119
  };
@@ -129910,10 +129867,17 @@ async function handleInitCommand(host) {
129910
129867
  host.showError(getLlmNotSetMessage());
129911
129868
  return;
129912
129869
  }
129870
+ const workDir = host.state.appState.workDir;
129871
+ const projectRoot = findProjectRoot(workDir);
129872
+ const targetDir = projectRoot === void 0 || projectRoot === workDir ? workDir : await selectInitTargetDir(host, workDir, projectRoot);
129873
+ if (targetDir === void 0) {
129874
+ host.showStatus(t("init.cancelled"));
129875
+ return;
129876
+ }
129913
129877
  host.deferUserMessages = true;
129914
129878
  host.beginSessionRequest();
129915
129879
  try {
129916
- await session.init();
129880
+ await session.init(targetDir);
129917
129881
  host.streamingUI.finalizeTurn((item) => {
129918
129882
  host.sendQueuedMessage(session, item);
129919
129883
  });
@@ -129929,6 +129893,62 @@ async function handleInitCommand(host) {
129929
129893
  host.deferUserMessages = false;
129930
129894
  }
129931
129895
  }
129896
+ const PROJECT_ROOT_MARKERS = [
129897
+ "package.json",
129898
+ "Cargo.toml",
129899
+ "pyproject.toml",
129900
+ "go.mod",
129901
+ "pom.xml",
129902
+ "tsconfig.json"
129903
+ ];
129904
+ function findProjectRoot(startDir) {
129905
+ let dir = resolve(startDir);
129906
+ let markerDir;
129907
+ while (true) {
129908
+ if (existsSync(resolve(dir, ".git"))) return dir;
129909
+ if (markerDir === void 0) {
129910
+ for (const marker of PROJECT_ROOT_MARKERS) if (existsSync(resolve(dir, marker))) {
129911
+ markerDir = dir;
129912
+ break;
129913
+ }
129914
+ }
129915
+ const parent = dirname$1(dir);
129916
+ if (parent === dir) break;
129917
+ dir = parent;
129918
+ }
129919
+ return markerDir;
129920
+ }
129921
+ function selectInitTargetDir(host, workDir, projectRoot) {
129922
+ const { promise, resolve } = Promise.withResolvers();
129923
+ const options = [{
129924
+ value: workDir,
129925
+ label: t("init.current_dir"),
129926
+ description: t("init.current_dir_desc")
129927
+ }, {
129928
+ value: projectRoot,
129929
+ label: t("init.project_root"),
129930
+ description: t("init.project_root_desc")
129931
+ }];
129932
+ const picker = new ChoicePickerComponent({
129933
+ title: t("init.select_title"),
129934
+ hint: t("init.select_hint", {
129935
+ currentDir: workDir,
129936
+ projectRoot
129937
+ }),
129938
+ options,
129939
+ colors: host.state.theme.colors,
129940
+ onSelect: (value) => {
129941
+ host.restoreEditor();
129942
+ resolve(value);
129943
+ },
129944
+ onCancel: () => {
129945
+ host.restoreEditor();
129946
+ resolve(void 0);
129947
+ }
129948
+ });
129949
+ host.mountEditorReplacement(picker);
129950
+ return promise;
129951
+ }
129932
129952
  //#endregion
129933
129953
  //#region src/tui/components/messages/goal-panel.ts
129934
129954
  const WRAP_WIDTH = 72;
@@ -135494,134 +135514,130 @@ var MoonLoader = class extends Text {
135494
135514
  *
135495
135515
  * Used when the remote marketplace cannot be fetched at runtime.
135496
135516
  */
135497
- const FALLBACK_SKILL_MARKETPLACE = [
135498
- {
135499
- id: "gsap-skills",
135500
- displayName: t("market.gsap_name"),
135501
- description: t("market.gsap_desc"),
135502
- source: "https://github.com/greensock/gsap-skills"
135503
- },
135504
- {
135505
- id: "claude-design-card",
135506
- displayName: t("market.design_card_name"),
135507
- description: t("market.design_card_desc"),
135508
- source: "https://github.com/geekjourneyx/claude-design-card"
135509
- },
135510
- {
135511
- id: "superpowers",
135512
- displayName: t("market.superpowers_name"),
135513
- description: t("market.superpowers_desc"),
135514
- source: "https://github.com/obra/superpowers"
135515
- },
135516
- {
135517
- id: "audio-skill",
135518
- displayName: t("market.audio_name"),
135519
- description: t("market.audio_desc"),
135520
- source: "https://github.com/LIUTod/audio-skill"
135521
- },
135522
- {
135523
- id: "scrapling-skill",
135524
- displayName: t("market.scrapling_name"),
135525
- description: t("market.scrapling_desc"),
135526
- source: "https://github.com/Cedriccmh/claude-code-skill-scrapling"
135527
- },
135528
- {
135529
- id: "a-stock-data",
135530
- displayName: t("market.astock_name"),
135531
- description: t("market.astock_desc"),
135532
- source: "https://github.com/simonlin1212/a-stock-data"
135533
- },
135534
- {
135535
- id: "humanizer",
135536
- displayName: t("market.humanizer_name"),
135537
- description: t("market.humanizer_desc"),
135538
- source: "https://github.com/blader/humanizer"
135539
- },
135540
- {
135541
- id: "patent-disclosure-skill",
135542
- displayName: t("market.patent_name"),
135543
- description: t("market.patent_desc"),
135544
- source: "https://github.com/handsomestWei/patent-disclosure-skill"
135545
- },
135546
- {
135547
- id: "contract-review-pro",
135548
- displayName: t("market.contract_name"),
135549
- description: t("market.contract_desc"),
135550
- source: "https://github.com/CSlawyer1985/contract-review-pro"
135551
- },
135552
- {
135553
- id: "academic-research-skills",
135554
- displayName: t("market.academic_name"),
135555
- description: t("market.academic_desc"),
135556
- source: "https://github.com/Imbad0202/academic-research-skills"
135557
- },
135558
- {
135559
- id: "headroom",
135560
- displayName: t("market.headroom_name"),
135561
- description: t("market.headroom_desc"),
135562
- source: "https://github.com/chopratejas/headroom"
135563
- },
135564
- {
135565
- id: "xiaohu-wechat-format",
135566
- displayName: t("market.xiaohu_wechat_name"),
135567
- description: t("market.xiaohu_wechat_desc"),
135568
- source: "https://github.com/xiaohuailabs/xiaohu-wechat-format"
135569
- },
135570
- {
135571
- id: "huashu-design",
135572
- displayName: t("market.huashu_name"),
135573
- description: t("market.huashu_desc"),
135574
- source: "https://github.com/alchaincyf/huashu-design"
135575
- },
135576
- {
135577
- id: "html-video",
135578
- displayName: t("market.html_video_name"),
135579
- description: t("market.html_video_desc"),
135580
- source: "https://github.com/nexu-io/html-video"
135581
- },
135582
- {
135583
- id: "xiaohu-video-translate",
135584
- displayName: t("market.xiaohu_translate_name"),
135585
- description: t("market.xiaohu_translate_desc"),
135586
- source: "https://github.com/xiaohuailabs/xiaohu-video-translate"
135587
- },
135588
- {
135589
- id: "videocut-skills",
135590
- displayName: t("market.videocut_name"),
135591
- description: t("market.videocut_desc"),
135592
- source: "https://github.com/Ceeon/videocut-skills"
135593
- },
135594
- {
135595
- id: "taste-skill",
135596
- displayName: t("market.taste_name"),
135597
- description: t("market.taste_desc"),
135598
- source: "https://github.com/Leonxlnx/taste-skill"
135599
- },
135600
- {
135601
- id: "vtake-skills",
135602
- displayName: t("market.vtake_name"),
135603
- description: t("market.vtake_desc"),
135604
- source: "https://github.com/notedit/vtake-skills"
135605
- },
135606
- {
135607
- id: "remotion-skills",
135608
- displayName: t("market.remotion_name"),
135609
- description: t("market.remotion_desc"),
135610
- source: "https://github.com/remotion-dev/skills"
135611
- },
135612
- {
135613
- id: "html-anything",
135614
- displayName: t("market.html_anything_name"),
135615
- description: t("market.html_anything_desc"),
135616
- source: "https://github.com/nexu-io/html-anything"
135617
- },
135618
- {
135619
- id: "guizang-social-card-skill",
135620
- displayName: t("market.guizang_name"),
135621
- description: t("market.guizang_desc"),
135622
- source: "https://github.com/op7418/guizang-social-card-skill"
135623
- }
135624
- ];
135517
+ function getFallbackSkillMarketplace() {
135518
+ return [
135519
+ {
135520
+ id: "gsap-skills",
135521
+ displayName: t("market.gsap_name"),
135522
+ description: t("market.gsap_desc"),
135523
+ source: "https://github.com/greensock/gsap-skills"
135524
+ },
135525
+ {
135526
+ id: "claude-design-card",
135527
+ displayName: t("market.design_card_name"),
135528
+ description: t("market.design_card_desc"),
135529
+ source: "https://github.com/geekjourneyx/claude-design-card"
135530
+ },
135531
+ {
135532
+ id: "superpowers",
135533
+ displayName: t("market.superpowers_name"),
135534
+ description: t("market.superpowers_desc"),
135535
+ source: "https://github.com/obra/superpowers"
135536
+ },
135537
+ {
135538
+ id: "scrapling-skill",
135539
+ displayName: t("market.scrapling_name"),
135540
+ description: t("market.scrapling_desc"),
135541
+ source: "https://github.com/Cedriccmh/claude-code-skill-scrapling"
135542
+ },
135543
+ {
135544
+ id: "a-stock-data",
135545
+ displayName: t("market.astock_name"),
135546
+ description: t("market.astock_desc"),
135547
+ source: "https://github.com/simonlin1212/a-stock-data"
135548
+ },
135549
+ {
135550
+ id: "humanizer",
135551
+ displayName: t("market.humanizer_name"),
135552
+ description: t("market.humanizer_desc"),
135553
+ source: "https://github.com/blader/humanizer"
135554
+ },
135555
+ {
135556
+ id: "patent-disclosure-skill",
135557
+ displayName: t("market.patent_name"),
135558
+ description: t("market.patent_desc"),
135559
+ source: "https://github.com/handsomestWei/patent-disclosure-skill"
135560
+ },
135561
+ {
135562
+ id: "contract-review-pro",
135563
+ displayName: t("market.contract_name"),
135564
+ description: t("market.contract_desc"),
135565
+ source: "https://github.com/CSlawyer1985/contract-review-pro"
135566
+ },
135567
+ {
135568
+ id: "academic-research-skills",
135569
+ displayName: t("market.academic_name"),
135570
+ description: t("market.academic_desc"),
135571
+ source: "https://github.com/Imbad0202/academic-research-skills"
135572
+ },
135573
+ {
135574
+ id: "headroom",
135575
+ displayName: t("market.headroom_name"),
135576
+ description: t("market.headroom_desc"),
135577
+ source: "https://github.com/chopratejas/headroom"
135578
+ },
135579
+ {
135580
+ id: "xiaohu-wechat-format",
135581
+ displayName: t("market.xiaohu_wechat_name"),
135582
+ description: t("market.xiaohu_wechat_desc"),
135583
+ source: "https://github.com/xiaohuailabs/xiaohu-wechat-format"
135584
+ },
135585
+ {
135586
+ id: "huashu-design",
135587
+ displayName: t("market.huashu_name"),
135588
+ description: t("market.huashu_desc"),
135589
+ source: "https://github.com/alchaincyf/huashu-design"
135590
+ },
135591
+ {
135592
+ id: "html-video",
135593
+ displayName: t("market.html_video_name"),
135594
+ description: t("market.html_video_desc"),
135595
+ source: "https://github.com/nexu-io/html-video"
135596
+ },
135597
+ {
135598
+ id: "xiaohu-video-translate",
135599
+ displayName: t("market.xiaohu_translate_name"),
135600
+ description: t("market.xiaohu_translate_desc"),
135601
+ source: "https://github.com/xiaohuailabs/xiaohu-video-translate"
135602
+ },
135603
+ {
135604
+ id: "videocut-skills",
135605
+ displayName: t("market.videocut_name"),
135606
+ description: t("market.videocut_desc"),
135607
+ source: "https://github.com/Ceeon/videocut-skills"
135608
+ },
135609
+ {
135610
+ id: "taste-skill",
135611
+ displayName: t("market.taste_name"),
135612
+ description: t("market.taste_desc"),
135613
+ source: "https://github.com/Leonxlnx/taste-skill"
135614
+ },
135615
+ {
135616
+ id: "vtake-skills",
135617
+ displayName: t("market.vtake_name"),
135618
+ description: t("market.vtake_desc"),
135619
+ source: "https://github.com/notedit/vtake-skills"
135620
+ },
135621
+ {
135622
+ id: "remotion-skills",
135623
+ displayName: t("market.remotion_name"),
135624
+ description: t("market.remotion_desc"),
135625
+ source: "https://github.com/remotion-dev/skills"
135626
+ },
135627
+ {
135628
+ id: "html-anything",
135629
+ displayName: t("market.html_anything_name"),
135630
+ description: t("market.html_anything_desc"),
135631
+ source: "https://github.com/nexu-io/html-anything"
135632
+ },
135633
+ {
135634
+ id: "guizang-social-card-skill",
135635
+ displayName: t("market.guizang_name"),
135636
+ description: t("market.guizang_desc"),
135637
+ source: "https://github.com/op7418/guizang-social-card-skill"
135638
+ }
135639
+ ];
135640
+ }
135625
135641
  //#endregion
135626
135642
  //#region src/tui/commands/skill-center.ts
135627
135643
  const SKILL_DESC_MAX = 60;
@@ -135721,7 +135737,7 @@ async function loadMarketplace(host) {
135721
135737
  const { plugins } = await loadPluginMarketplace({ workDir: host.state.appState.workDir });
135722
135738
  return plugins;
135723
135739
  } catch {
135724
- return [...FALLBACK_SKILL_MARKETPLACE];
135740
+ return [...getFallbackSkillMarketplace()];
135725
135741
  }
135726
135742
  }
135727
135743
  function buildOptions(host, skills, plugins, marketplace) {
@@ -135920,7 +135936,7 @@ async function uninstallManualSkill(host, skill) {
135920
135936
  async function confirmUninstall(host, label, description) {
135921
135937
  return new Promise((resolve) => {
135922
135938
  const picker = new ChoicePickerComponent({
135923
- title: `${t("skill.confirm_uninstall")} "${label}"?`,
135939
+ title: t("skill.confirm_uninstall", { label }),
135924
135940
  hint: t("skill.uninstall_reversible"),
135925
135941
  options: [{
135926
135942
  value: "no",
@@ -136751,7 +136767,7 @@ function resize(){
136751
136767
  ctx.setTransform(DPR,0,0,DPR,0,0);
136752
136768
  }
136753
136769
  resize();
136754
- window.addEventListener('resize',resize);
136770
+ window.addEventListener('resize',function(){resize();markDirty()});
136755
136771
 
136756
136772
  // 相机
136757
136773
  var camRotX=0.25,camRotY=0.4;
@@ -136769,33 +136785,6 @@ var graphData;
136769
136785
  var nodePositions={};
136770
136786
  var nodeData=[];
136771
136787
 
136772
- // 节点漂浮参数:每个节点独立相位,渲染时叠加微小偏移
136773
- var floatParams={};
136774
- var frameTime=0;
136775
- function ensureFloat(id){
136776
- if(floatParams[id])return;
136777
- floatParams[id]={
136778
- phaseX:Math.random()*Math.PI*2,
136779
- phaseY:Math.random()*Math.PI*2,
136780
- phaseZ:Math.random()*Math.PI*2,
136781
- ampX:1.5+Math.random()*2.5,
136782
- ampY:1.5+Math.random()*2.5,
136783
- ampZ:1+Math.random()*2,
136784
- speed:0.0004+Math.random()*0.0004
136785
- };
136786
- }
136787
- // 返回某节点当前帧的漂浮后位置(不修改原 nodePositions,避免拾取错位)
136788
- function floatingPos(id,t){
136789
- var p=nodePositions[id];if(!p)return p;
136790
- var f=floatParams[id];if(!f)return p;
136791
- if(t===undefined)t=frameTime;
136792
- return{
136793
- x:p.x+Math.sin(t*f.speed+f.phaseX)*f.ampX,
136794
- y:p.y+Math.cos(t*f.speed*1.1+f.phaseY)*f.ampY,
136795
- z:p.z+Math.sin(t*f.speed*0.8+f.phaseZ)*f.ampZ
136796
- };
136797
- }
136798
-
136799
136788
  // ─── 3D 投影 ──────────────────────────────────────────
136800
136789
  function project(p){
136801
136790
  var cosY=Math.cos(camRotY),sinY=Math.sin(camRotY);
@@ -136899,10 +136888,6 @@ function buildNebulae(){
136899
136888
  baseX:p.x+r*Math.sin(phi)*Math.cos(theta),
136900
136889
  baseY:p.y+r*Math.sin(phi)*Math.sin(theta),
136901
136890
  baseZ:p.z+r*Math.cos(phi),
136902
- phase:Math.random()*Math.PI*2,
136903
- ampX:2+Math.random()*4,
136904
- ampY:2+Math.random()*4,
136905
- ampZ:1+Math.random()*3,
136906
136891
  size:0.5+Math.random()*0.8,
136907
136892
  op:0.15+Math.random()*0.2
136908
136893
  });
@@ -136910,19 +136895,14 @@ function buildNebulae(){
136910
136895
  });
136911
136896
  }
136912
136897
 
136913
- function drawNebulae(t){
136898
+ function drawNebulae(){
136914
136899
  ctx.save();
136915
136900
  for(var i=0;i<nebulaDots.length;i++){
136916
136901
  var d=nebulaDots[i];
136917
- // 不规则漂浮
136918
- var x=d.baseX+Math.sin(t*0.0003+d.phase)*d.ampX;
136919
- var y=d.baseY+Math.cos(t*0.0004+d.phase*1.3)*d.ampY;
136920
- var z=d.baseZ+Math.sin(t*0.0002+d.phase*0.7)*d.ampZ;
136921
- var p=project({x:x,y:y,z:z});
136902
+ var p=project({x:d.baseX,y:d.baseY,z:d.baseZ});
136922
136903
  if(p.z<=0)continue;
136923
136904
  var r=Math.max(0.3,d.size*p.scale*0.5);
136924
136905
  if(r<0.4)continue;
136925
- // 远处淡,近处稍清晰
136926
136906
  var alpha=d.op*Math.min(1,p.scale*1.5);
136927
136907
  ctx.fillStyle='rgba(0,0,0,'+alpha.toFixed(3)+')';
136928
136908
  ctx.beginPath();
@@ -137099,7 +137079,7 @@ function computeProjMap(){
137099
137079
  vis.events.forEach(function(id){visAll.add(id)});
137100
137080
  var map={allIds:visAll};
137101
137081
  visAll.forEach(function(id){
137102
- var p=floatingPos(id);
137082
+ var p=nodePositions[id];
137103
137083
  if(p)map[id]=project(p);
137104
137084
  });
137105
137085
  return map;
@@ -137131,6 +137111,7 @@ function startInertia(){
137131
137111
  camRotY+=velRotY;
137132
137112
  camRotX=Math.max(-1.2,Math.min(1.2,camRotX+velRotX));
137133
137113
  velRotX*=0.94;velRotY*=0.94;
137114
+ markDirty();
137134
137115
  inertiaRAF=requestAnimationFrame(step);
137135
137116
  }
137136
137117
  inertiaRAF=requestAnimationFrame(step);
@@ -137169,7 +137150,7 @@ function pickNode(sx,sy){
137169
137150
  vis.events.forEach(function(id){visAll.add(id)});
137170
137151
  var best=null,bestDist=Infinity;
137171
137152
  visAll.forEach(function(id){
137172
- var p=floatingPos(id);if(!p)return;
137153
+ var p=nodePositions[id];if(!p)return;
137173
137154
  var sp=project(p);
137174
137155
  if(sp.z<=0)return;
137175
137156
  var data=nodeData.find(function(n){return n.id===id});
@@ -137208,14 +137189,16 @@ canvas.addEventListener('mousemove',function(e){
137208
137189
  velRotY=(e.clientX-lastMoveX)/dt*0.005;
137209
137190
  velRotX=(e.clientY-lastMoveY)/dt*0.005;
137210
137191
  lastMoveTime=now;lastMoveX=e.clientX;lastMoveY=e.clientY;
137192
+ markDirty();
137211
137193
  }else if(isPanning){
137212
137194
  var pdx=e.clientX-dragStart.x,pdy=e.clientY-dragStart.y;
137213
137195
  var scale=fov/camDist;
137214
137196
  camTargetX=dragStart.panX - pdx*scale;
137215
137197
  camTargetY=dragStart.panY + pdy*scale;
137198
+ markDirty();
137216
137199
  }else{
137217
137200
  var id=pickNode(e.clientX,e.clientY);
137218
- if(id!==hoveredId){hoveredId=id;canvas.style.cursor=id?'pointer':'grab';}
137201
+ if(id!==hoveredId){hoveredId=id;canvas.style.cursor=id?'pointer':'grab';markDirty();}
137219
137202
  if(id)showTooltip(e.clientX,e.clientY,id);
137220
137203
  else hideTooltip();
137221
137204
  }
@@ -137239,10 +137222,10 @@ canvas.addEventListener('mouseup',function(e){
137239
137222
  if(data.kind==='event'&&!expEv.has(id))expEv.add(id);
137240
137223
  }
137241
137224
  selId=id;navStack=[];
137242
- focusOn(id);rebuildLabels();
137225
+ focusOn(id);rebuildLabels();markDirty();
137243
137226
  },250);
137244
137227
  }else{
137245
- selId=null;rebuildLabels();closeModal();
137228
+ selId=null;rebuildLabels();closeModal();markDirty();
137246
137229
  }
137247
137230
  });
137248
137231
 
@@ -137258,13 +137241,13 @@ canvas.addEventListener('dblclick',function(e){
137258
137241
  if(data){
137259
137242
  if(!expEnt.has(id)&&!expEv.has(id)){expEnt.add(id);}
137260
137243
  selId=id;navStack=[];
137261
- focusOn(id);rebuildLabels();
137244
+ focusOn(id);rebuildLabels();markDirty();
137262
137245
  showModal(id,data.kind);
137263
137246
  }
137264
137247
  }else{
137265
137248
  expEnt.clear();expEv.clear();selId=null;
137266
137249
  if(graphData)graphData.entities.forEach(function(en){expEnt.add(en.id)});
137267
- closeModal();rebuildLabels();fitView();
137250
+ closeModal();rebuildLabels();fitView();markDirty();
137268
137251
  }
137269
137252
  });
137270
137253
 
@@ -137282,6 +137265,7 @@ canvas.addEventListener('wheel',function(e){
137282
137265
  var scaleAfter=fov/camDist;
137283
137266
  camTargetX=worldX - (mx-W/2)/scaleAfter;
137284
137267
  camTargetY=worldY + (my-H/2)/scaleAfter;
137268
+ markDirty();
137285
137269
  },{passive:false});
137286
137270
 
137287
137271
  function focusOn(id){
@@ -137301,6 +137285,7 @@ function focusOn(id){
137301
137285
  camTargetY=startTy+(endTy-startTy)*e;
137302
137286
  camTargetZ=startTz+(endTz-startTz)*e;
137303
137287
  camDist=startDist+(endDist-startDist)*e;
137288
+ markDirty();
137304
137289
  if(t<1)focusAnim=requestAnimationFrame(step);
137305
137290
  }
137306
137291
  focusAnim=requestAnimationFrame(step);
@@ -137311,7 +137296,7 @@ function fitView(){
137311
137296
  var ids=[];
137312
137297
  vis.entities.forEach(function(id){ids.push(id)});
137313
137298
  vis.events.forEach(function(id){ids.push(id)});
137314
- if(!ids.length){camTargetX=0;camTargetY=0;camTargetZ=0;camDist=700;return}
137299
+ if(!ids.length){camTargetX=0;camTargetY=0;camTargetZ=0;camDist=700;markDirty();return}
137315
137300
  var x0=Infinity,x1=-Infinity,y0=Infinity,y1=-Infinity,z0=Infinity,z1=-Infinity;
137316
137301
  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});
137317
137302
  var cx=(x0+x1)/2,cy=(y0+y1)/2,cz=(z0+z1)/2;
@@ -137332,6 +137317,7 @@ function fitView(){
137332
137317
  camDist=startDist+(endDist-startDist)*e;
137333
137318
  camRotX=startRotX+(endRotX-startRotX)*e;
137334
137319
  camRotY=startRotY+(endRotY-startRotY)*e;
137320
+ markDirty();
137335
137321
  if(t<1)focusAnim=requestAnimationFrame(step);
137336
137322
  }
137337
137323
  focusAnim=requestAnimationFrame(step);
@@ -137346,6 +137332,7 @@ function startAutoRotate(){
137346
137332
  var t=Math.min(1,elapsed/duration);
137347
137333
  var fade=1-t;
137348
137334
  camRotY+=speed*fade;
137335
+ markDirty();
137349
137336
  if(t<1)autoRotRAF=requestAnimationFrame(step);
137350
137337
  }
137351
137338
  autoRotRAF=requestAnimationFrame(step);
@@ -137408,14 +137395,14 @@ function esc(s){if(!s)return'';return String(s).replace(/&/g,'&amp;').replace(/<
137408
137395
  document.getElementById('btn-reset').onclick=function(){
137409
137396
  expEnt.clear();expEv.clear();selId=null;
137410
137397
  if(graphData)graphData.entities.forEach(function(e){expEnt.add(e.id)});
137411
- closeModal();rebuildLabels();fitView();
137398
+ closeModal();rebuildLabels();fitView();markDirty();
137412
137399
  };
137413
137400
  document.getElementById('btn-expand').onclick=function(){
137414
137401
  if(graphData){
137415
137402
  graphData.entities.forEach(function(e){expEnt.add(e.id)});
137416
137403
  graphData.events.forEach(function(e){expEv.add(e.id)});
137417
137404
  }
137418
- selId=null;closeModal();rebuildLabels();fitView();
137405
+ selId=null;closeModal();rebuildLabels();fitView();markDirty();
137419
137406
  };
137420
137407
  document.getElementById('btn-close').onclick=closeModal;
137421
137408
  document.getElementById('modal-mask').addEventListener('click',closeModal);
@@ -137457,11 +137444,12 @@ window.addEventListener('keydown',function(e){
137457
137444
  if(e.key==='Escape'){
137458
137445
  if(document.getElementById('modal').classList.contains('open'))closeModal();
137459
137446
  else{selId=null;rebuildLabels()}
137447
+ markDirty();
137460
137448
  }else if(e.key===' '){
137461
137449
  e.preventDefault();
137462
137450
  expEnt.clear();expEv.clear();selId=null;
137463
137451
  if(graphData)graphData.entities.forEach(function(en){expEnt.add(en.id)});
137464
- closeModal();rebuildLabels();fitView();
137452
+ closeModal();rebuildLabels();fitView();markDirty();
137465
137453
  }else if(e.key==='ArrowRight'||e.key==='ArrowDown'){e.preventDefault();navigateRelated('next');}
137466
137454
  else if(e.key==='ArrowLeft'||e.key==='ArrowUp'){e.preventDefault();navigateRelated('prev');}
137467
137455
  });
@@ -137471,7 +137459,7 @@ var searchInput=document.getElementById('search-input');
137471
137459
  var searchQuery='',searchMatches=null;
137472
137460
  searchInput.addEventListener('input',function(){
137473
137461
  searchQuery=searchInput.value.trim().toLowerCase();
137474
- if(!searchQuery){searchMatches=null;rebuildLabels();return}
137462
+ if(!searchQuery){searchMatches=null;rebuildLabels();markDirty();return}
137475
137463
  searchMatches=new Set();
137476
137464
  var firstMatch=null;
137477
137465
  if(graphData){
@@ -137502,9 +137490,10 @@ searchInput.addEventListener('input',function(){
137502
137490
  });
137503
137491
  selId=firstMatch;focusOn(firstMatch);rebuildLabels();
137504
137492
  }
137493
+ markDirty();
137505
137494
  });
137506
137495
  searchInput.addEventListener('keydown',function(e){
137507
- if(e.key==='Escape'){searchInput.value='';searchQuery='';searchMatches=null;rebuildLabels();searchInput.blur();}
137496
+ if(e.key==='Escape'){searchInput.value='';searchQuery='';searchMatches=null;rebuildLabels();searchInput.blur();markDirty();}
137508
137497
  else if(e.key==='Enter'&&searchMatches&&searchMatches.size>0){
137509
137498
  var first=Array.from(searchMatches)[0];
137510
137499
  var data=nodeData.find(function(n){return n.id===first});
@@ -137584,20 +137573,24 @@ miniCanvas.addEventListener('click',function(e){
137584
137573
  var e=t<.5?2*t*t:1-Math.pow(-2*t+2,2)/2;
137585
137574
  camTargetX=startTx+(worldX-startTx)*e;
137586
137575
  camTargetZ=startTz+(worldZ-startTz)*e;
137576
+ markDirty();
137587
137577
  if(t<1)focusAnim=requestAnimationFrame(step);
137588
137578
  }
137589
137579
  focusAnim=requestAnimationFrame(step);
137590
137580
  });
137591
137581
 
137592
137582
  // ─── 主渲染循环 ──────────────────────────────────────
137583
+ var dirty=true;
137584
+ function markDirty(){dirty=true}
137593
137585
  function animate(){
137594
137586
  requestAnimationFrame(animate);
137595
137587
  if(!graphData)return;
137596
- frameTime=performance.now();
137588
+ if(!dirty)return;
137589
+ dirty=false;
137597
137590
  ctx.clearRect(0,0,W,H);
137598
137591
  ctx.fillStyle='#fafafa';
137599
137592
  ctx.fillRect(0,0,W,H);
137600
- drawNebulae(frameTime);
137593
+ drawNebulae();
137601
137594
  var projMap=computeProjMap();
137602
137595
  var connSet=computeConnSet(projMap.allIds);
137603
137596
  drawEdges(projMap,connSet);
@@ -137650,11 +137643,11 @@ fetch('/api/graph').then(function(r){return r.json()}).then(function(data){
137650
137643
  });
137651
137644
  forceLayout3D();
137652
137645
  buildNebulae();
137653
- nodeData.forEach(function(n){ensureFloat(n.id)});
137654
137646
  rebuildLabels();
137655
137647
  fitView();
137656
137648
  animate();
137657
137649
  startAutoRotate();
137650
+ new EventSource('/api/heartbeat');
137658
137651
  }).catch(function(err){
137659
137652
  document.getElementById('loading').style.display='none';
137660
137653
  errorMsg.style.display='block';
@@ -137778,6 +137771,22 @@ async function handleWeb(host) {
137778
137771
  serveGraphJSON(store, res);
137779
137772
  return;
137780
137773
  }
137774
+ if (req.url === "/api/heartbeat") {
137775
+ res.writeHead(200, {
137776
+ "Content-Type": "text/event-stream",
137777
+ "Cache-Control": "no-store",
137778
+ Connection: "keep-alive"
137779
+ });
137780
+ const timer = setInterval(() => {
137781
+ res.write(": ping\n\n");
137782
+ }, 15e3);
137783
+ res.on("close", () => {
137784
+ clearInterval(timer);
137785
+ server.close();
137786
+ });
137787
+ res.write(": ok\n\n");
137788
+ return;
137789
+ }
137781
137790
  serveHTML(res, getLocale());
137782
137791
  });
137783
137792
  registerServer(server);
@@ -147770,6 +147779,24 @@ var MemoryPickerComponent = class extends Container {
147770
147779
  }
147771
147780
  };
147772
147781
  //#endregion
147782
+ //#region src/tui/utils/session-label.ts
147783
+ /**
147784
+ * Helpers for composing session labels in the session picker.
147785
+ *
147786
+ * Detection rule for the `[imported]` badge: `metadata.imported_from_scream_cli`
147787
+ * is strictly the boolean `true`. This mirrors the value written by
147788
+ * the old migration-legacy package into the session's `state.json` `custom` block.
147789
+ */
147790
+ const IMPORTED_BADGE = "[已导入]";
147791
+ const IMPORTED_FLAG_KEY = "imported_from_scream_cli";
147792
+ function isImportedSession(metadata) {
147793
+ if (metadata === void 0) return false;
147794
+ return metadata[IMPORTED_FLAG_KEY] === true;
147795
+ }
147796
+ function formatSessionLabel(input) {
147797
+ return `${isImportedSession(input.metadata) ? `${IMPORTED_BADGE} ` : ""}${input.title}`;
147798
+ }
147799
+ //#endregion
147773
147800
  //#region src/tui/components/dialogs/session-picker.ts
147774
147801
  /**
147775
147802
  * SessionPicker — pi-tui version of the session selection dialog.
@@ -150572,11 +150599,6 @@ async function handleMainCommand(opts, version) {
150572
150599
  }
150573
150600
  await runShell(validated.options, version);
150574
150601
  }
150575
- /** `scream migrate` — permanently disabled. */
150576
- async function handleMigrateCommand() {
150577
- process.stdout.write("迁移功能已取消,不再支持从 scream-cli 导入数据。\n");
150578
- process.exit(0);
150579
- }
150580
150602
  function main() {
150581
150603
  initProcessName();
150582
150604
  const version = getVersion();
@@ -150588,13 +150610,6 @@ function main() {
150588
150610
  process.stderr.write(`查看日志:${resolveGlobalLogPath(resolveScreamHome())}\n`);
150589
150611
  process.exit(1);
150590
150612
  });
150591
- }, () => {
150592
- handleMigrateCommand().catch(async (error) => {
150593
- await logStartupFailure("运行迁移", error);
150594
- process.stderr.write(formatStartupError(error, { operation: "运行迁移" }));
150595
- process.stderr.write(`查看日志:${resolveGlobalLogPath(resolveScreamHome())}\n`);
150596
- process.exit(1);
150597
- });
150598
150613
  }, (entry, args) => {
150599
150614
  runPluginNodeEntry(entry, args).catch(async (error) => {
150600
150615
  await logStartupFailure("运行插件节点入口", error);
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-CwKaEg7v.mjs")).main();
9
+ (await import("./app-BE3SBnF0.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);
package/icon.ico CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scream-code",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "A terminal-native AI agent for builders",
5
5
  "license": "MIT",
6
6
  "author": "ScreamCli",
@@ -74,7 +74,6 @@
74
74
  "@scream-code/config": "workspace:^",
75
75
  "@scream-code/knowledge": "workspace:*",
76
76
  "@scream-code/memory": "workspace:*",
77
- "@scream-code/migration-legacy": "workspace:^",
78
77
  "@scream-code/scream-code-sdk": "workspace:^",
79
78
  "@types/semver": "^7.7.0",
80
79
  "tsx": "^4.21.0"