irises 1.0.17 → 1.0.18

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.
Files changed (2) hide show
  1. package/bin/iris +93 -49
  2. package/package.json +6 -6
package/bin/iris CHANGED
@@ -25,61 +25,63 @@ const scriptDir = path.dirname(scriptPath)
25
25
  // 解决 PRoot/容器/L2S 等环境下 process.execPath 被虚拟化的问题
26
26
  const wrapperRoot = path.resolve(scriptDir, "..")
27
27
 
28
+ const SIGNAL_EXIT_CODES = {
29
+ SIGHUP: 129,
30
+ SIGINT: 130,
31
+ SIGTERM: 143,
32
+ }
33
+
28
34
  function run(target) {
29
- const result = childProcess.spawnSync(target, process.argv.slice(2), {
35
+ // 不使用 spawnSync:Windows/PowerShell Ctrl+C 可能先中断 Node 包装器,
36
+ // 但子进程 Iris 为了保护 TUI 会吞掉 SIGINT,导致子进程孤儿化并留下 lock。
37
+ // 使用异步 spawn 后,包装器会转发信号并等待真正的 Iris 进程退出。
38
+ const child = childProcess.spawn(target, process.argv.slice(2), {
30
39
  stdio: "inherit",
31
40
  env: Object.assign({}, process.env, { __IRIS_PKG_DIR: wrapperRoot }),
41
+ windowsHide: false,
32
42
  })
33
- if (result.error) {
34
- console.error(result.error.message)
35
- process.exit(1)
36
- }
37
- const code = typeof result.status === "number" ? result.status : 0
38
- process.exit(code)
39
- }
40
43
 
41
- // 1. 环境变量覆盖
42
- const envPath = process.env.IRIS_BIN_PATH
43
- if (envPath) {
44
- run(envPath)
45
- }
44
+ let childExited = false
45
+ const cleanupHandlers = []
46
+ for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
47
+ const handler = () => {
48
+ if (childExited) return
49
+ try {
50
+ child.kill(signal)
51
+ } catch {
52
+ // ignore — 子进程可能已经退出
53
+ }
54
+ }
55
+ process.on(signal, handler)
56
+ cleanupHandlers.push(() => process.off(signal, handler))
57
+ }
46
58
 
47
- // 2. postinstall 缓存
48
- const cached = path.join(scriptDir, ".iris")
49
- if (fs.existsSync(cached)) {
50
- run(cached)
51
- }
59
+ const cleanup = () => {
60
+ childExited = true
61
+ for (const cleanupHandler of cleanupHandlers) cleanupHandler()
62
+ }
52
63
 
53
- // 3. 平台检测
54
- const platformMap = {
55
- darwin: "darwin",
56
- linux: "linux",
57
- win32: "windows",
58
- }
59
- const archMap = {
60
- x64: "x64",
61
- arm64: "arm64",
62
- arm: "arm",
63
- }
64
+ child.on("error", (err) => {
65
+ cleanup()
66
+ console.error(err.message)
67
+ process.exit(1)
68
+ })
64
69
 
65
- let platform = platformMap[os.platform()]
66
- if (!platform) {
67
- platform = os.platform()
68
- }
69
- let arch = archMap[os.arch()]
70
- if (!arch) {
71
- arch = os.arch()
70
+ child.on("exit", (code, signal) => {
71
+ cleanup()
72
+ if (typeof code === "number") {
73
+ process.exit(code)
74
+ }
75
+ process.exit(SIGNAL_EXIT_CODES[signal] || 1)
76
+ })
72
77
  }
73
- const base = "irises-" + platform + "-" + arch
74
- const binary = platform === "windows" ? "iris.exe" : "iris"
75
78
 
76
- // 4. 搜索 node_modules
77
- function findBinary(startDir) {
79
+ function findBinary(startDir, packageName, binaryName) {
78
80
  let current = startDir
79
81
  for (;;) {
80
82
  const modules = path.join(current, "node_modules")
81
83
  if (fs.existsSync(modules)) {
82
- const candidate = path.join(modules, base, "bin", binary)
84
+ const candidate = path.join(modules, packageName, "bin", binaryName)
83
85
  if (fs.existsSync(candidate)) return candidate
84
86
  }
85
87
  const parent = path.dirname(current)
@@ -90,13 +92,55 @@ function findBinary(startDir) {
90
92
  }
91
93
  }
92
94
 
93
- const resolved = findBinary(path.resolve(scriptDir, ".."))
94
- if (!resolved) {
95
- console.error(
96
- "未找到当前平台的 Iris 二进制。" +
97
- " 可尝试手动安装 \"" + base + "\" 包。"
98
- )
99
- process.exit(1)
95
+ function main() {
96
+ // 1. 环境变量覆盖
97
+ const envPath = process.env.IRIS_BIN_PATH
98
+ if (envPath) {
99
+ run(envPath)
100
+ return
101
+ }
102
+
103
+ // 2. postinstall 缓存
104
+ const cached = path.join(scriptDir, ".iris")
105
+ if (fs.existsSync(cached)) {
106
+ run(cached)
107
+ return
108
+ }
109
+
110
+ // 3. 平台检测
111
+ const platformMap = {
112
+ darwin: "darwin",
113
+ linux: "linux",
114
+ win32: "windows",
115
+ }
116
+ const archMap = {
117
+ x64: "x64",
118
+ arm64: "arm64",
119
+ arm: "arm",
120
+ }
121
+
122
+ let platform = platformMap[os.platform()]
123
+ if (!platform) {
124
+ platform = os.platform()
125
+ }
126
+ let arch = archMap[os.arch()]
127
+ if (!arch) {
128
+ arch = os.arch()
129
+ }
130
+ const base = "irises-" + platform + "-" + arch
131
+ const binary = platform === "windows" ? "iris.exe" : "iris"
132
+
133
+ // 4. 搜索 node_modules
134
+ const resolved = findBinary(path.resolve(scriptDir, ".."), base, binary)
135
+ if (!resolved) {
136
+ console.error(
137
+ "未找到当前平台的 Iris 二进制。" +
138
+ " 可尝试手动安装 \"" + base + "\" 包。"
139
+ )
140
+ process.exit(1)
141
+ }
142
+
143
+ run(resolved)
100
144
  }
101
145
 
102
- run(resolved)
146
+ main()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "irises",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "模块化、可解耦的 AI 聊天框架,支持多平台、多 LLM、工具调用",
5
5
  "license": "GPL-3.0-only",
6
6
  "bin": {
@@ -10,10 +10,10 @@
10
10
  "postinstall": "bun ./postinstall.mjs || node ./postinstall.mjs"
11
11
  },
12
12
  "optionalDependencies": {
13
- "irises-darwin-x64": "1.0.17",
14
- "irises-linux-x64": "1.0.17",
15
- "irises-darwin-arm64": "1.0.17",
16
- "irises-windows-x64": "1.0.17",
17
- "irises-linux-arm64": "1.0.17"
13
+ "irises-darwin-x64": "1.0.18",
14
+ "irises-linux-x64": "1.0.18",
15
+ "irises-darwin-arm64": "1.0.18",
16
+ "irises-windows-x64": "1.0.18",
17
+ "irises-linux-arm64": "1.0.18"
18
18
  }
19
19
  }