scream-code 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.mjs CHANGED
@@ -71217,6 +71217,31 @@ function renderBashDescription(shellName) {
71217
71217
  function withoutBackgroundDescription(description) {
71218
71218
  return description.replace(/\n\nIf `run_in_background=true`,[\s\S]*?point them to the `\/tasks` command, which opens an interactive panel; it has no subcommands\./, "\n\nBackground execution is disabled for this agent. Do not set `run_in_background=true`.").replace(` For possibly long-running foreground commands, set the \`timeout\` argument in seconds. Foreground commands default to ${String(DEFAULT_TIMEOUT_S)}s and allow up to ${String(MAX_TIMEOUT_S)}s.`, ` For possibly long-running commands, set the \`timeout\` argument in seconds. The default is ${String(DEFAULT_TIMEOUT_S)}s; foreground commands allow up to ${String(MAX_TIMEOUT_S)}s.`).replace(/\n- Prefer `run_in_background=true`[\s\S]*?conversation to continue before the command finishes\./, "\n- Do not set `run_in_background=true`; background task management tools are not available.");
71219
71219
  }
71220
+ function rejectDangerousCommand(pattern, hint) {
71221
+ return {
71222
+ isError: true,
71223
+ output: `Scream Code self-protection blocked this command.\n\nThe command matches a dangerous pattern (${pattern}) that could kill Scream Code's own process.\n\nInstead: ${hint}`
71224
+ };
71225
+ }
71226
+ function validateCommand(command, isWindows) {
71227
+ const cmd = command;
71228
+ if (/\bkill\s+-9\s+-1\b/.test(cmd) || /\bkill\s+-KILL\s+-1\b/.test(cmd)) return rejectDangerousCommand("kill -9 -1", "Use 'kill <pid>' with a specific PID to terminate the target process.");
71229
+ if (/\b(killall|pkill)\b.*\b(node|scream)/i.test(cmd)) return rejectDangerousCommand("killall/pkill node", "Use 'kill <pid>' with a specific PID, or use the server's own stop command.");
71230
+ if (isWindows) {
71231
+ if (/\btasklist\b/.test(cmd) && /\bgrep\b.*\b(node|scream)/i.test(cmd) && /\b(taskkill|tskill)\b/.test(cmd)) return rejectDangerousCommand("tasklist | grep node | taskkill pipeline", "Use 'taskkill /PID <pid>' with the specific preview server PID. First run 'tasklist | grep -i node' to find the exact PID, then kill only that one.");
71232
+ if (/\btaskkill\b.*\/IM\s+node/i.test(cmd)) return rejectDangerousCommand("taskkill /IM node.exe", "Use 'taskkill /PID <pid>' with a specific PID instead of killing by image name.");
71233
+ if (/\bwmic\s+process\s+.*where\s+.*name.*=.*node/i.test(cmd) && /\bdelete\b/i.test(cmd)) return rejectDangerousCommand("wmic process delete", "Use 'taskkill /PID <pid>' with a specific PID instead.");
71234
+ if (/\bstop-process\b.*-Name\s+node/i.test(cmd)) return rejectDangerousCommand("Stop-Process -Name node", "Use 'Stop-Process -Id <pid>' with a specific PID instead.");
71235
+ } else {
71236
+ if (/\bps\b/.test(cmd) && /\bgrep\b.*\b(node|scream)/i.test(cmd) && /\bxargs\s+kill\b/.test(cmd)) return rejectDangerousCommand("ps | grep node | xargs kill pipeline", "Use 'kill <pid>' with a specific PID instead.");
71237
+ if (/\bpgrep\b.*\b(node|scream)/i.test(cmd) && /\bxargs\s+kill\b/.test(cmd)) return rejectDangerousCommand("pgrep node | xargs kill", "Use 'kill <pid>' with a specific PID instead.");
71238
+ }
71239
+ return null;
71240
+ }
71241
+ function buildSelfProtectionPreamble(isWindows) {
71242
+ if (isWindows) return "_SCREAM_CHECK(){ for _a in \"$@\";do [ \"$_a\" = \"$SCREAM_PID\" ]&&{ echo \"Scream Code self-protection: refusing to kill itself (pid $SCREAM_PID). Use a specific non-Scream PID.\">&2;return 1;};done;return 0;};kill(){ _SCREAM_CHECK \"$@\"||return 1;command kill \"$@\";};pkill(){ echo \"Scream Code self-protection: pkill blocked. Use kill <pid>.\">&2;return 1;};taskkill(){ _SCREAM_CHECK \"$@\"||return 1;command taskkill \"$@\";};tskill(){ _SCREAM_CHECK \"$@\"||return 1;command tskill \"$@\";};";
71243
+ return "_SCREAM_CHECK(){ for _a in \"$@\";do [ \"$_a\" = \"$SCREAM_PID\" ]||[ \"$_a\" = \"-$SCREAM_PID\" ]&&{ echo \"Scream Code self-protection: refusing to kill itself (pid $SCREAM_PID). Use a specific non-Scream PID.\">&2;return 1;};done;return 0;};kill(){ _SCREAM_CHECK \"$@\"||return 1;command kill \"$@\";};pkill(){ echo \"Scream Code self-protection: pkill blocked. Use kill <pid>.\">&2;return 1;};killall(){ echo \"Scream Code self-protection: killall blocked. Use kill <pid>.\">&2;return 1;};";
71244
+ }
71220
71245
  var BashTool = class {
71221
71246
  jian;
71222
71247
  cwd;
@@ -71253,16 +71278,18 @@ var BashTool = class {
71253
71278
  }
71254
71279
  spawn(effectiveCwd, command) {
71255
71280
  const shellCwd = this.isWindowsBash ? windowsPathToPosixPath(effectiveCwd) : effectiveCwd;
71281
+ const preamble = buildSelfProtectionPreamble(this.isWindowsBash);
71256
71282
  const shellArgs = [
71257
71283
  this.jian.osEnv.shellPath,
71258
71284
  "-c",
71259
- `cd ${shellQuote$1(shellCwd)} && ${command}`
71285
+ `cd ${shellQuote$1(shellCwd)} && ${preamble}; ${command}`
71260
71286
  ];
71261
71287
  const noninteractiveEnv = {
71262
71288
  NO_COLOR: "1",
71263
71289
  TERM: "dumb",
71264
71290
  GIT_TERMINAL_PROMPT: process.env["GIT_TERMINAL_PROMPT"] ?? "0",
71265
- SHELL: this.jian.osEnv.shellPath
71291
+ SHELL: this.jian.osEnv.shellPath,
71292
+ SCREAM_PID: String(process.pid)
71266
71293
  };
71267
71294
  const mergedEnv = {
71268
71295
  ...process.env,
@@ -71279,6 +71306,8 @@ var BashTool = class {
71279
71306
  isError: true,
71280
71307
  output: "Command cannot be empty."
71281
71308
  };
71309
+ const validationError = validateCommand(args.command, this.isWindowsBash);
71310
+ if (validationError !== null) return validationError;
71282
71311
  if (args.run_in_background) {
71283
71312
  if (!this.allowBackground) return {
71284
71313
  isError: true,
@@ -124475,6 +124504,30 @@ const BUILTIN_REGISTRY = [
124475
124504
  displayName: "Academic Research 学术研究",
124476
124505
  description: "完整学术研究管线:深度研究(13 Agent 团队 × 7 种模式)+ 学术写作(12 Agent 管线)+ 同行评审(7 Agent 多视角审稿),全流程覆盖",
124477
124506
  source: "https://github.com/Imbad0202/academic-research-skills"
124507
+ },
124508
+ {
124509
+ id: "taste-skill",
124510
+ displayName: "Taste Skill 品味提升",
124511
+ description: "让 AI 拥有好品味,不再生成无聊、千篇一律的平庸内容",
124512
+ source: "https://github.com/Leonxlnx/taste-skill"
124513
+ },
124514
+ {
124515
+ id: "headroom",
124516
+ displayName: "Headroom 压缩优化",
124517
+ description: "在内容送达 LLM 前压缩工具输出、日志、文件和 RAG 块,节省 60-95% Token,答案质量不变",
124518
+ source: "https://github.com/chopratejas/headroom"
124519
+ },
124520
+ {
124521
+ id: "composio",
124522
+ displayName: "Composio 工具集成",
124523
+ description: "1000+ 工具集、工具搜索、上下文管理、认证和沙盒工作台,帮助构建能把意图转化为行动的 AI Agent",
124524
+ source: "https://github.com/ComposioHQ/composio"
124525
+ },
124526
+ {
124527
+ id: "remotion",
124528
+ displayName: "Remotion 视频编程",
124529
+ description: "用 React 程序化生成视频,代码驱动动画、剪辑和渲染",
124530
+ source: "https://github.com/remotion-dev/remotion"
124478
124531
  }
124479
124532
  ];
124480
124533
  async function handlePluginCommand(host, _args) {
@@ -124534,8 +124587,8 @@ async function uninstallAndReport(host, id) {
124534
124587
  }
124535
124588
  }
124536
124589
  async function openPluginPanel(host) {
124537
- const marketplace = await loadSafe(host);
124538
- const installed = await loadInstalled(host);
124590
+ host.showStatus("正在加载插件中心…", "cyan");
124591
+ const [marketplace, installed] = await Promise.all([loadSafe(host), loadInstalled(host)]);
124539
124592
  const options = buildOptions(marketplace, installed);
124540
124593
  if (options.length === 0) {
124541
124594
  host.showNotice("ScreamCode 插件中心", "暂无可用插件。请检查网络或稍后重试。");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scream-code",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "The Starting Point for Next-Gen Agents",
5
5
  "license": "MIT",
6
6
  "author": "ScreamCli",
@@ -51,6 +51,7 @@
51
51
  "test": "pnpm -w run build:packages && vitest run",
52
52
  "e2e": "pnpm -w run build:packages && SCREAM_E2E=1 vitest run test/e2e",
53
53
  "e2e:real": "pnpm -w run build:packages && SCREAM_E2E_REAL=1 vitest run test/e2e/real-llm-smoke.e2e.test.ts",
54
+ "preinstall": "node -e \"console.log('\\n📦 正在安装 scream-code,请稍候...\\n')\"",
54
55
  "postinstall": "node scripts/postinstall.mjs",
55
56
  "smoke": "node dist/main.mjs --version"
56
57
  },
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Create a desktop shortcut for Scream Code on Windows.
3
+ *
4
+ * Only runs on Win32 and for global installs. Never fails the install —
5
+ * errors are caught and swallowed.
6
+ */
7
+
8
+ import { execFileSync } from 'node:child_process';
9
+
10
+ export function createDesktopShortcut() {
11
+ if (process.platform !== 'win32') return;
12
+
13
+ try {
14
+ execFileSync(
15
+ 'powershell.exe',
16
+ [
17
+ '-NoProfile',
18
+ '-ExecutionPolicy', 'Bypass',
19
+ '-Command',
20
+ shortcutPowerShellScript,
21
+ ],
22
+ { stdio: 'ignore', timeout: 10_000 },
23
+ );
24
+ } catch {
25
+ // Never fail the install over a shortcut.
26
+ }
27
+ }
28
+
29
+ const shortcutPowerShellScript = `
30
+ $ErrorActionPreference = 'Stop'
31
+
32
+ $DesktopPath = [Environment]::GetFolderPath('Desktop')
33
+ $ShortcutPath = "$DesktopPath\\Scream Code.lnk"
34
+ $WshShell = New-Object -ComObject WScript.Shell
35
+ $Shortcut = $WshShell.CreateShortcut($ShortcutPath)
36
+
37
+ $wt = Get-Command wt.exe -ErrorAction SilentlyContinue
38
+ $pwsh7 = Get-Command pwsh.exe -ErrorAction SilentlyContinue
39
+ $ps5 = Get-Command powershell.exe -ErrorAction SilentlyContinue
40
+
41
+ if ($wt) {
42
+ $Shortcut.TargetPath = $wt.Source
43
+ $Shortcut.Arguments = '--title "Scream Code" cmd /k "chcp 65001 > nul && scream"'
44
+ }
45
+ elseif ($pwsh7) {
46
+ $Shortcut.TargetPath = $pwsh7.Source
47
+ $Shortcut.Arguments = '-NoExit -Command "chcp 65001 > $null; scream"'
48
+ }
49
+ elseif ($ps5) {
50
+ $Shortcut.TargetPath = $ps5.Source
51
+ $Shortcut.Arguments = '-NoExit -Command "chcp 65001 > $null; [Console]::OutputEncoding = [Console]::InputEncoding = [Text.Encoding]::UTF8; $Host.UI.RawUI.WindowTitle = ''Scream Code''; scream"'
52
+ }
53
+ else {
54
+ $Shortcut.TargetPath = 'powershell.exe'
55
+ $Shortcut.Arguments = '-NoExit -Command "chcp 65001 > $null; [Console]::OutputEncoding = [Console]::InputEncoding = [Text.Encoding]::UTF8; $Host.UI.RawUI.WindowTitle = ''Scream Code''; scream"'
56
+ }
57
+
58
+ $Shortcut.WorkingDirectory = $env:USERPROFILE
59
+ $Shortcut.Description = 'Scream Code - AI 命令行助手'
60
+ $Shortcut.Save()
61
+ `.trim();
@@ -113,6 +113,7 @@ import {
113
113
  detectLegacyShims,
114
114
  renameInPlace,
115
115
  } from './postinstall/migrate.mjs';
116
+ import { createDesktopShortcut } from './postinstall/shortcut.mjs';
116
117
  import {
117
118
  logForeignScreamInTheWay,
118
119
  logMigrationBlocked,
@@ -263,6 +264,12 @@ async function main() {
263
264
  );
264
265
  }
265
266
 
267
+ try {
268
+ createDesktopShortcut();
269
+ } catch {
270
+ // Never fail the install over a shortcut.
271
+ }
272
+
266
273
  main().catch((err) => {
267
274
  const message = err instanceof Error ? err.message : String(err);
268
275
  notify(`[scream-code] postinstall warning: ${message}`);