@mobius-os/mobius 0.3.7 → 0.3.8

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/package.json +1 -1
  2. package/src/aimux.ts +24 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mobius-os/mobius",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "type": "module",
5
5
  "description": "Mobius terminal client. Reuses Mobius frontend TypeScript types and jsonl entry shapes.",
6
6
  "bin": {
package/src/aimux.ts CHANGED
@@ -88,12 +88,24 @@ async function pythonForAimux(onProgress?: (p: InstallProgress) => void): Promis
88
88
  // 解压到 ~/.mobius/python-bundle/ 后用 `<python> -m aimux` 运行,彻底绕开宿主机
89
89
  // 系统 python(如被精简掉 ensurepip 的容器镜像)。aimux 全部依赖为纯 Python,
90
90
  // 故三平台可共用同一套打包产物,分别按 arch 发布到 CDN。
91
- const BUNDLE_VER = '1'
91
+ const BUNDLE_VER = '2'
92
92
  const bundleDir = () => path.join(mobiusHome(), 'python-bundle')
93
93
  const bundlePython = () => WIN
94
94
  ? path.join(bundleDir(), 'python', 'python.exe')
95
95
  : path.join(bundleDir(), 'python', 'bin', 'python3')
96
96
 
97
+ /** Persistent child-process diagnostics. Never include the JWT in this file. */
98
+ export const aimuxLogPath = () => path.join(mobiusHome(), 'aimux.log')
99
+
100
+ function appendAimuxLog(write: { queue: Promise<void> }, text: string): void {
101
+ write.queue = write.queue
102
+ .then(async () => {
103
+ await fs.mkdir(mobiusHome(), { recursive: true })
104
+ await fs.appendFile(aimuxLogPath(), text, 'utf8')
105
+ })
106
+ .catch(() => {})
107
+ }
108
+
97
109
  /** 当前平台对应的内置运行时包名;mac-arm64 走 mac-x64(Rosetta 2)。 */
98
110
  export function bundleArch(): string | null {
99
111
  const { platform, arch } = process
@@ -288,9 +300,13 @@ export class AimuxSupervisor {
288
300
  this.child = child
289
301
  this.startHeartbeat()
290
302
  let tail = '' // 缓存 aimux 最近输出, 进程异常退出时带进状态行, 便于诊断(code=1 不再是黑盒)
303
+ const logWrite = { queue: Promise.resolve() }
304
+ appendAimuxLog(logWrite, `\n===== AIMUX start ${new Date().toISOString()} =====\n`)
305
+ appendAimuxLog(logWrite, `server=${server} identifier=${identifier} platform=${process.platform} arch=${process.arch}\n`)
291
306
  const classify = (buf: Buffer) => {
292
307
  const text = buf.toString('utf8')
293
308
  tail = (tail + text).slice(-4000)
309
+ appendAimuxLog(logWrite, text)
294
310
  if (!this.bridgeConnected && /connected|registered|event stream|heartbeat|sse/i.test(text)) {
295
311
  onStatus({ state: 'starting', phase: 'heartbeat', detail: 'AIMUX 已启动,等待 bridge 心跳确认…', identifier })
296
312
  } else if (/connection (refused|reset|closed|error)|failed to connect|unauthorized|forbidden|token.*invalid/i.test(text)) {
@@ -298,15 +314,19 @@ export class AimuxSupervisor {
298
314
  }
299
315
  }
300
316
  child.stdout?.on('data', classify); child.stderr?.on('data', classify)
301
- child.on('error', e => onStatus({ state: 'failed', phase: 'retrying', detail: `AIMUX 启动失败: ${e.message}`, identifier }))
317
+ child.on('error', e => {
318
+ appendAimuxLog(logWrite, `\n[spawn error] ${e.stack || e.message}\n`)
319
+ onStatus({ state: 'failed', phase: 'retrying', detail: `AIMUX 启动失败: ${e.message} · 日志: ${aimuxLogPath()}`, identifier })
320
+ })
302
321
  child.on('exit', code => {
303
322
  if (this.child !== child) return
304
323
  this.child = null
305
324
  this.stopHeartbeat()
306
325
  if (this.stopping) { onStatus({ state: 'stopped', phase: 'idle', detail: 'AIMUX 已停止', identifier }); return }
326
+ appendAimuxLog(logWrite, `\n===== AIMUX exit code=${code} ${new Date().toISOString()} =====\n`)
307
327
  const reason = code !== 0 && tail.trim()
308
- ? `AIMUX 进程退出(code=${code}): ${tail.trim().split(/[\r\n]+/).filter(Boolean).slice(-3).join(' ⏎ ').slice(-200)}`
309
- : `AIMUX 进程退出(code=${code})`
328
+ ? `AIMUX 进程退出(code=${code}): ${tail.trim().split(/[\r\n]+/).filter(Boolean).slice(-3).join(' ⏎ ').slice(-220)} · 日志: ${aimuxLogPath()}`
329
+ : `AIMUX 进程退出(code=${code}) · 日志: ${aimuxLogPath()}`
310
330
  this.scheduleReconnect(reason)
311
331
  })
312
332
  }