@mobius-os/mobius 0.3.6 → 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.
- package/README.md +4 -3
- package/package.json +6 -26
- package/src/aimux.ts +24 -4
package/README.md
CHANGED
|
@@ -169,6 +169,7 @@ mobius
|
|
|
169
169
|
|
|
170
170
|
If the PATH export is not already in the shell profile, add it to `~/.bashrc`
|
|
171
171
|
once. Using the explicit user prefix avoids the `EACCES ... /usr/local/lib/node_modules/mobius`
|
|
172
|
-
error produced by a root-owned npm global prefix. The built package
|
|
173
|
-
`tsx`
|
|
174
|
-
TypeScript entry point without retaining the source checkout's
|
|
172
|
+
error produced by a root-owned npm global prefix. The source and built package
|
|
173
|
+
both declare `tsx` as a runtime dependency, so production/global installs can
|
|
174
|
+
execute the TypeScript entry point without retaining the source checkout's
|
|
175
|
+
devDependencies.
|
package/package.json
CHANGED
|
@@ -1,50 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mobius-os/mobius",
|
|
3
|
-
"version": "0.3.
|
|
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": {
|
|
7
7
|
"mobius": "bin/mobius-tui.js",
|
|
8
8
|
"mobius-tui": "bin/mobius-tui.js"
|
|
9
9
|
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "tsx src/main.tsx"
|
|
12
|
+
},
|
|
10
13
|
"files": [
|
|
11
14
|
"bin",
|
|
12
15
|
"src",
|
|
13
16
|
"README.md"
|
|
14
17
|
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"dev": "tsx src/main.tsx",
|
|
17
|
-
"start": "tsx src/main.tsx",
|
|
18
|
-
"typecheck": "tsc --noEmit",
|
|
19
|
-
"test:integration": "tsx tests/integration.test.ts",
|
|
20
|
-
"test:ui": "tsx tests/ui.test.tsx",
|
|
21
|
-
"test:flow": "tsx tests/flow.test.tsx",
|
|
22
|
-
"test:resume": "tsx tests/resume.test.tsx",
|
|
23
|
-
"test:aimux": "tsx tests/aimux.test.tsx",
|
|
24
|
-
"test:reconnect": "tsx tests/reconnect.test.tsx",
|
|
25
|
-
"test:screen": "tsx tests/screen.test.tsx",
|
|
26
|
-
"test:scroll": "tsx tests/scroll.test.tsx",
|
|
27
|
-
"test": "npm run typecheck && npm run test:ui && npm run test:integration"
|
|
28
|
-
},
|
|
29
18
|
"dependencies": {
|
|
30
19
|
"chalk": "^5.3.0",
|
|
31
20
|
"cli-highlight": "2.1.11",
|
|
32
21
|
"extract-zip": "^2.0.1",
|
|
33
22
|
"ink": "5.2.0",
|
|
34
23
|
"marked": "12.0.2",
|
|
35
|
-
"react": "18.3.1"
|
|
36
|
-
|
|
37
|
-
"devDependencies": {
|
|
38
|
-
"@types/node": "18.19.34",
|
|
39
|
-
"@types/react": "18.3.3",
|
|
40
|
-
"ink-testing-library": "4.0.0",
|
|
41
|
-
"tsx": "4.19.2",
|
|
42
|
-
"typescript": "5.4.5"
|
|
24
|
+
"react": "18.3.1",
|
|
25
|
+
"tsx": "4.19.2"
|
|
43
26
|
},
|
|
44
27
|
"engines": {
|
|
45
28
|
"node": ">=18"
|
|
46
|
-
},
|
|
47
|
-
"publishConfig": {
|
|
48
|
-
"access": "public"
|
|
49
29
|
}
|
|
50
30
|
}
|
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 = '
|
|
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 =>
|
|
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(-
|
|
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
|
}
|