open-tui-orchestrator 0.9.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/CHANGELOG.md +205 -0
- package/INSTALL-zh.md +96 -0
- package/INSTALL.md +96 -0
- package/LICENSE +48 -0
- package/README-zh.md +181 -0
- package/README.md +181 -0
- package/cli.mjs +37 -0
- package/docs/adapt.md +103 -0
- package/docs/assets/kimicode-agent-swarm-10-subagents.png +0 -0
- package/docs/auto-recovery.md +23 -0
- package/docs/caller-driven.md +121 -0
- package/docs/claude-adapter.md +25 -0
- package/docs/execution-contract.md +70 -0
- package/docs/inactive-windows.md +11 -0
- package/docs/kimi-adapter.md +27 -0
- package/docs/kimi-integration.md +56 -0
- package/docs/maintenance-lock.md +32 -0
- package/docs/openclaw-adapter.md +59 -0
- package/docs/openclaw-assessment-2026-09-06.md +59 -0
- package/docs/opencode-adapter.md +25 -0
- package/docs/pi-adapter.md +58 -0
- package/docs/public-readiness.md +63 -0
- package/docs/release-policy.md +39 -0
- package/docs/security-audit-2026-09-09.md +41 -0
- package/docs/trust-and-safety.md +64 -0
- package/docs/verification-2026-09-06.md +22 -0
- package/docs/verification-recovery-2026-09-06.md +36 -0
- package/orch.mjs +20 -0
- package/package.json +36 -0
- package/release.json +116 -0
- package/repair.mjs +228 -0
- package/scripts/adapt.mjs +35 -0
- package/scripts/agent-auth-prompt.txt +10 -0
- package/scripts/agent.mjs +1 -0
- package/scripts/core/adapt-lib.mjs +219 -0
- package/scripts/core/agent-auth-prompt.txt +10 -0
- package/scripts/core/agent-profiles/hermes.json +59 -0
- package/scripts/core/agent.mjs +1 -0
- package/scripts/core/checkpoint.mjs +38 -0
- package/scripts/core/claude-host.mjs +50 -0
- package/scripts/core/claude-runtime.mjs +111 -0
- package/scripts/core/contracts.mjs +161 -0
- package/scripts/core/host-cli.mjs +204 -0
- package/scripts/core/host-model.mjs +323 -0
- package/scripts/core/host-probe.mjs +16 -0
- package/scripts/core/inactive-window.mjs +32 -0
- package/scripts/core/inactive-window.ps1 +36 -0
- package/scripts/core/kimi-host.mjs +41 -0
- package/scripts/core/kimi-runtime.mjs +140 -0
- package/scripts/core/lease-lock.ps1 +32 -0
- package/scripts/core/leases.mjs +176 -0
- package/scripts/core/maintenance-lock.mjs +77 -0
- package/scripts/core/native-argv.mjs +9 -0
- package/scripts/core/network-policy.mjs +18 -0
- package/scripts/core/openclaw-bootstrap.mjs +25 -0
- package/scripts/core/openclaw-config.mjs +35 -0
- package/scripts/core/openclaw-host.mjs +29 -0
- package/scripts/core/openclaw-runtime.mjs +33 -0
- package/scripts/core/openclaw-window.mjs +44 -0
- package/scripts/core/opencode-host.mjs +80 -0
- package/scripts/core/opencode-runtime.mjs +131 -0
- package/scripts/core/orchestrate-sdk.mjs +2595 -0
- package/scripts/core/pi-host.mjs +29 -0
- package/scripts/core/pi-runtime.mjs +54 -0
- package/scripts/core/pi-shutdown.mjs +16 -0
- package/scripts/core/poll-windows.mjs +48 -0
- package/scripts/core/print-profile.mjs +79 -0
- package/scripts/core/print-runtime.mjs +106 -0
- package/scripts/core/pty-host.mjs +38 -0
- package/scripts/core/recovery.mjs +75 -0
- package/scripts/core/run-board.mjs +155 -0
- package/scripts/core/run-guardian.mjs +130 -0
- package/scripts/core/runner.mjs +274 -0
- package/scripts/core/runtime-context.mjs +23 -0
- package/scripts/core/unit-carrier.mjs +55 -0
- package/scripts/core/unit-command.mjs +96 -0
- package/scripts/core/unit-runtime.mjs +107 -0
- package/scripts/gate.mjs +162 -0
- package/scripts/host-cli.mjs +2 -0
- package/scripts/install-deps.mjs +58 -0
- package/scripts/maintenance-lock.mjs +46 -0
- package/scripts/network-policy.mjs +2 -0
- package/scripts/open-tui-orchestrator-force.mjs +239 -0
- package/scripts/open-tui-orchestrator-preflight.mjs +85 -0
- package/scripts/orchestrate-sdk.mjs +59 -0
- package/scripts/package-lock.json +242 -0
- package/scripts/package.json +9 -0
- package/scripts/platform-guard.mjs +23 -0
- package/scripts/poll-windows.mjs +8 -0
- package/scripts/release-integrity.mjs +94 -0
- package/scripts/runtime-context.mjs +2 -0
- package/scripts/sdk-dependency-check.mjs +32 -0
- package/scripts/todo-list.mjs +89 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {fileURLToPath} from 'node:url';
|
|
4
|
+
import {spawn} from 'node:child_process';
|
|
5
|
+
import {opencodeArgs, opencodePlannerArgs} from './opencode-host.mjs';
|
|
6
|
+
import {nativeArgumentLines} from './native-argv.mjs';
|
|
7
|
+
|
|
8
|
+
const quote = (s) => "'" + String(s).replaceAll("'", "''") + "'";
|
|
9
|
+
|
|
10
|
+
// Parse `opencode run --format json` event stream: return the last assistant text part.
|
|
11
|
+
export function opencodeAssistantText(raw) {
|
|
12
|
+
let final = '';
|
|
13
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
14
|
+
if (!line.trim()) continue;
|
|
15
|
+
try {
|
|
16
|
+
const ev = JSON.parse(line);
|
|
17
|
+
if (ev.type === 'error') throw new Error('OPENCODE_RESPONSE_FAILED: ' + String(ev.error || ev.message || ''));
|
|
18
|
+
const part = ev.part;
|
|
19
|
+
if (ev.type === 'text' && part && part.type === 'text' && part.text && String(part.text).trim()) {
|
|
20
|
+
final = String(part.text);
|
|
21
|
+
}
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error.message && error.message.startsWith('OPENCODE_RESPONSE_FAILED')) throw error;
|
|
24
|
+
// ignore non-JSON lines / partial events
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return final;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function runOpenCodePlanner(config, prompt, cwd) {
|
|
31
|
+
const args = [...opencodePlannerArgs(config, {model: process.env.ORCH_MODEL, cwd}), '--', prompt];
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const child = spawn(config.bin, args, {cwd, env: process.env, windowsHide: true, shell: false, stdio: ['ignore', 'pipe', 'pipe']});
|
|
34
|
+
let raw = '', errorText = '', timedOut = false;
|
|
35
|
+
const timer = setTimeout(() => { timedOut = true; child.kill(); }, Number(process.env.ORCH_DECOMPOSE_TIMEOUT_MS || 90000));
|
|
36
|
+
child.stdout.on('data', (b) => { raw += b; if (raw.length > 8000000) child.kill(); });
|
|
37
|
+
child.stderr.on('data', (b) => { errorText += b; });
|
|
38
|
+
child.on('error', (e) => { clearTimeout(timer); reject(e); });
|
|
39
|
+
child.on('exit', (code) => {
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
try {
|
|
42
|
+
if (timedOut || code !== 0) throw new Error(timedOut ? 'OPENCODE_PLANNER_TIMEOUT' : 'OPENCODE_PLANNER_FAILED: exit ' + code);
|
|
43
|
+
const final = opencodeAssistantText(raw);
|
|
44
|
+
if (!final) throw new Error('OPENCODE_PLANNER_EMPTY_RESPONSE' + (errorText ? ': ' + String(errorText).slice(0, 300) : ''));
|
|
45
|
+
resolve({final});
|
|
46
|
+
} catch (e) { reject(e); }
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function writeOpenCodeLauncher(config, {key, prompt, suffix, workspace, temp}) {
|
|
52
|
+
const stem = String(key + '-' + suffix).replace(/[^a-zA-Z0-9_-]/g, '-');
|
|
53
|
+
const token = /【本块唯一标识】\s*([A-Za-z0-9][A-Za-z0-9_-]*)/.exec(prompt)?.[1];
|
|
54
|
+
if (!token) throw new Error('OpenCode window requires a completion token');
|
|
55
|
+
fs.mkdirSync(temp, {recursive: true});
|
|
56
|
+
const lp = path.join(temp, 'win-launch-' + stem + '.ps1');
|
|
57
|
+
const pidf = path.join(temp, 'window-' + stem + '.pid');
|
|
58
|
+
const pf = path.join(temp, 'agent-win-' + stem + '.md');
|
|
59
|
+
const rf = path.join(temp, 'win-' + stem + '.result.json');
|
|
60
|
+
const log = path.join(temp, 'win-' + stem + '.out.log');
|
|
61
|
+
fs.writeFileSync(pf, prompt, 'utf8');
|
|
62
|
+
const args = opencodeArgs(config, {model: process.env.ORCH_MODEL, effort: process.env.ORCH_EFFORT, cwd: workspace});
|
|
63
|
+
const body = [
|
|
64
|
+
"$ErrorActionPreference = 'Continue'",
|
|
65
|
+
'trap { exit 0 }',
|
|
66
|
+
`$PID | Set-Content -LiteralPath ${quote(pidf)} -Encoding UTF8`,
|
|
67
|
+
'$env:TERM = "xterm-256color"',
|
|
68
|
+
'[Console]::OutputEncoding = [System.Text.Encoding]::UTF8',
|
|
69
|
+
'$OutputEncoding = [System.Text.Encoding]::UTF8',
|
|
70
|
+
'chcp 65001 | Out-Null',
|
|
71
|
+
'[Console]::InputEncoding = [System.Text.Encoding]::UTF8',
|
|
72
|
+
'Write-Host "============================================="',
|
|
73
|
+
'Write-Host " OPENCODE TASK RUNNING - closes automatically on completion"',
|
|
74
|
+
'Write-Host "============================================="',
|
|
75
|
+
`Set-Location -LiteralPath ${quote(workspace)}`,
|
|
76
|
+
`$env:ORCH_WINDOW = '1'`,
|
|
77
|
+
`$token = ${quote(token)}`,
|
|
78
|
+
`$log = ${quote(log)}`,
|
|
79
|
+
`$resultFile = ${quote(rf)}`,
|
|
80
|
+
"function Write-Result {",
|
|
81
|
+
" param([int]$code,[string]$report)",
|
|
82
|
+
" try {",
|
|
83
|
+
" $json = '{\"__EXIT__\":' + $code + ',\"__DONE__\":true,\"__REPORT__\":' + (ConvertTo-Json $report -Compress) + '}'",
|
|
84
|
+
" $d = Split-Path -Parent $resultFile; if ($d -and -not (Test-Path -LiteralPath $d)) { New-Item -ItemType Directory -Force -Path $d | Out-Null }",
|
|
85
|
+
" Set-Content -LiteralPath $resultFile -Value ($json + \"`r`n__EXIT__=\" + $code) -Encoding UTF8",
|
|
86
|
+
" try { Set-Content -LiteralPath ($resultFile + '.self-closed') -Value '1' -Encoding ASCII } catch { }",
|
|
87
|
+
" } catch { }",
|
|
88
|
+
"}",
|
|
89
|
+
"$p = (Get-Content -Raw -Encoding UTF8 '" + String(pf).replace(/'/g, "''") + "').Trim()",
|
|
90
|
+
"if ([string]::IsNullOrWhiteSpace($p)) { Write-Result 2 ''; exit 0 }",
|
|
91
|
+
// The prompt rides as the final argv element: fold it into the array BEFORE the
|
|
92
|
+
// Windows PowerShell 5.1 native-argv fix-up so embedded quotes/newlines survive.
|
|
93
|
+
"$agentArgs = @(" + args.map(quote).join(',') + ') + @($p)',
|
|
94
|
+
...nativeArgumentLines(),
|
|
95
|
+
// 与 kimi 窗同款外观修复:opencode 诊断走 stderr,2>&1 合并时 PS5.1 会刷红色
|
|
96
|
+
// NativeCommandError 块;ErrorRecord 还原后以普通文本进日志,完成 token 不受影响。
|
|
97
|
+
`& ${quote(config.bin)} @agentArgs 2>&1 | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { $_.TargetObject } else { $_ } } | Tee-Object -FilePath $log`,
|
|
98
|
+
"$code = $LASTEXITCODE",
|
|
99
|
+
"# opencode run -i exits on its own after the turn; capture the tail containing the token.",
|
|
100
|
+
"$report = ''",
|
|
101
|
+
"if (Test-Path -LiteralPath $log) {",
|
|
102
|
+
" $lines = Get-Content -LiteralPath $log -Encoding UTF8 -ErrorAction SilentlyContinue",
|
|
103
|
+
" $hit = $lines | Where-Object { $_.Contains($token) } | Select-Object -Last 1",
|
|
104
|
+
" if ($hit) { $report = $hit } else { $report = ($lines | Select-Object -Last 3) -join \"`n\" }",
|
|
105
|
+
"}",
|
|
106
|
+
"Write-Result $code $report",
|
|
107
|
+
'exit 0',
|
|
108
|
+
].join('\r\n');
|
|
109
|
+
fs.writeFileSync(lp, '\ufeff' + body, 'utf8');
|
|
110
|
+
return {lp, pidf, pf, rf, log};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export async function waitOpenCodeResult(rf, timeoutMs, pidf) {
|
|
114
|
+
const end = Date.now() + timeoutMs;
|
|
115
|
+
while (Date.now() < end) {
|
|
116
|
+
if (fs.existsSync(rf)) {
|
|
117
|
+
try {
|
|
118
|
+
// Write-Result appends a human-readable `__EXIT__=N` trailer line (read by
|
|
119
|
+
// readExitCode); only the first line is the JSON record.
|
|
120
|
+
const r = JSON.parse(fs.readFileSync(rf, 'utf8').replace(/^\uFEFF/, '').split(/\r?\n/)[0]);
|
|
121
|
+
return {done: true, exitCode: r.__EXIT__, text: r.__REPORT__ || ''};
|
|
122
|
+
} catch {}
|
|
123
|
+
}
|
|
124
|
+
if (fs.existsSync(pidf)) {
|
|
125
|
+
const pid = Number(fs.readFileSync(pidf, 'utf8').replace(/^\uFEFF/, ''));
|
|
126
|
+
try { process.kill(pid, 0); } catch { return {done: true, exitCode: 1, text: 'OpenCode launcher exited without result'}; }
|
|
127
|
+
}
|
|
128
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
129
|
+
}
|
|
130
|
+
return {done: false, exitCode: null, text: 'OpenCode completion timeout'};
|
|
131
|
+
}
|