@neta-art/cohub-cli 7.1.2 → 8.0.1
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 +40 -2
- package/dist/auth.js +38 -5
- package/dist/client.js +5 -2
- package/dist/commands/runtime.d.ts +1 -2
- package/dist/commands/runtime.js +169 -293
- package/dist/commands/sandboxd-binary.d.ts +1 -1
- package/dist/commands/sandboxd-binary.js +13 -5
- package/dist/runtime/archive-store.d.ts +5 -1
- package/dist/runtime/archive-store.js +22 -6
- package/dist/runtime/connection.d.ts +4 -2
- package/dist/runtime/connection.js +113 -44
- package/dist/runtime/diagnostics.d.ts +3 -0
- package/dist/runtime/diagnostics.js +3 -0
- package/dist/runtime/harness.d.ts +7 -0
- package/dist/runtime/harness.js +63 -17
- package/dist/runtime/instance.d.ts +5 -0
- package/dist/runtime/instance.js +159 -0
- package/dist/runtime/json-rpc.d.ts +2 -0
- package/dist/runtime/json-rpc.js +2 -0
- package/dist/runtime/launch.d.ts +20 -0
- package/dist/runtime/launch.js +176 -0
- package/dist/runtime/native-codex-hook.d.ts +1 -0
- package/dist/runtime/native-codex-hook.js +28 -0
- package/dist/runtime/native-install.d.ts +21 -0
- package/dist/runtime/native-install.js +130 -0
- package/dist/runtime/native-ipc.d.ts +26 -0
- package/dist/runtime/native-ipc.js +101 -0
- package/dist/runtime/native-pi-extension.d.ts +20 -0
- package/dist/runtime/native-pi-extension.js +47 -0
- package/dist/runtime/native-sync-store.d.ts +97 -0
- package/dist/runtime/native-sync-store.js +365 -0
- package/dist/runtime/native-sync.d.ts +25 -0
- package/dist/runtime/native-sync.js +128 -0
- package/dist/runtime/native-transcript.d.ts +27 -0
- package/dist/runtime/native-transcript.js +281 -0
- package/dist/runtime/presentation.d.ts +21 -0
- package/dist/runtime/presentation.js +78 -0
- package/dist/runtime/process-group.d.ts +2 -0
- package/dist/runtime/process-group.js +124 -31
- package/dist/runtime/session-store.d.ts +17 -2
- package/dist/runtime/session-store.js +118 -9
- package/dist/runtime/space-binding.d.ts +3 -0
- package/dist/runtime/space-binding.js +43 -6
- package/dist/runtime/supervisor.d.ts +16 -0
- package/dist/runtime/supervisor.js +277 -0
- package/dist/runtime/worker.d.ts +1 -0
- package/dist/runtime/worker.js +20 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -84,12 +84,37 @@ COHUB_SPACE_ID=<spaceId> cohub spaces prompt "message" --json
|
|
|
84
84
|
|
|
85
85
|
Connect one local workspace to a Space and select Pi or Codex per turn.
|
|
86
86
|
|
|
87
|
+
To keep using native terminals with ordinary Cohub Chats / Turns:
|
|
88
|
+
使用原生终端,并同步到普通 Cohub Chat / Turn:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
cohub runtime up -d --harness pi --harness codex
|
|
92
|
+
cohub runtime attach --harness pi --harness codex
|
|
93
|
+
# Reload Pi / restart Codex and approve its hook trust prompt.
|
|
94
|
+
# 重载 Pi / 重启 Codex,并审核 Hook 信任提示。
|
|
95
|
+
cohub runtime detach --harness pi --harness codex # Pause; retain data / 暂停,保留数据
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`attach` explicitly authorizes this project's opened conversation history and raw native archives.
|
|
99
|
+
The Runtime Supervisor is the single local Daemon: Pi / Codex integrations use its private IPC,
|
|
100
|
+
while native Turn events use the existing Runtime WebSocket. Configuration is backed up, existing
|
|
101
|
+
Runtime bindings are reused, and competing continuations fork at complete Turns without blocking native work. Requires Pi 0.85.1+ or Codex with stable
|
|
102
|
+
Hooks enabled. User-level integrations remain inert outside opted-in directories. See
|
|
103
|
+
[boundaries and privacy](../../docs/local-runtime.md#native-clients--原生客户端).
|
|
104
|
+
|
|
105
|
+
`attach` 明确授权上传当前项目打开的对话历史与原生归档;复用现有绑定,配置修改前备份。
|
|
106
|
+
冲突时按完整 Turn 分支,不阻塞本地执行。用户级集成在未授权目录中不会采集数据。
|
|
107
|
+
|
|
108
|
+
|
|
87
109
|
```bash
|
|
88
110
|
cohub runtime up ./project --harness pi --harness codex
|
|
89
111
|
cohub runtime up ./project --space <spaceId> --harness codex
|
|
90
112
|
cohub -s <spaceId> spaces prompt "Continue" --harness codex
|
|
91
113
|
cohub runtime status --space <spaceId>
|
|
92
114
|
cohub runtime logs --space <spaceId> --follow
|
|
115
|
+
cohub runtime up -d
|
|
116
|
+
cohub runtime down
|
|
117
|
+
cohub runtime up -n --name another-project
|
|
93
118
|
```
|
|
94
119
|
|
|
95
120
|
Runtime diagnostics stay as redacted JSONL under the local Runtime state directory and
|
|
@@ -105,8 +130,21 @@ confirmation. See [Runtime details](../../docs/local-runtime.md).
|
|
|
105
130
|
|
|
106
131
|
When `--space` is omitted, Runtime remembers a Space for the canonical local directory,
|
|
107
132
|
account, and environment in `~/.config/cohub/runtime-spaces.json`. The first start creates
|
|
108
|
-
and records a local Space; later starts reuse
|
|
109
|
-
|
|
133
|
+
and records a local Space after prompting; later starts recommend reuse. `-n` now means
|
|
134
|
+
`--new` (boolean); use `--name <name>` for naming. An explicit `--space` or `COHUB_SPACE_ID`
|
|
135
|
+
overrides and updates the directory binding. `--yes` accepts defaults and local execution;
|
|
136
|
+
with explicit `--new`, it creates another Space.
|
|
137
|
+
|
|
138
|
+
`-d` runs the same supervisor in the background and returns the URL, PID and log location.
|
|
139
|
+
Readiness requires both Harness and files. If it is still starting after 30 seconds, exit
|
|
140
|
+
code 2 means it remains in the background trying to connect. `status --json` includes
|
|
141
|
+
local process and remote component status. `down` retains all data and requires `--yes`
|
|
142
|
+
when executions remain unconfirmed. `logs --level warn --follow` shows sensitive events;
|
|
143
|
+
foreground startup prints these automatically. Runtime commands never fall back to Home.
|
|
144
|
+
|
|
145
|
+
普通使用只需 `cohub runtime up`,首次提示新建,后续优先复用。`-n` 是 `--new` 的简写,
|
|
146
|
+
`--name` 单独指定名称。`-d` 后台运行并返回链接、PID 和日志位置;`down` 停止但保留所有数据。
|
|
147
|
+
断网及临时凭证错误自动重试;断连不代表任务已停止,也不会自动重跑工具。
|
|
110
148
|
|
|
111
149
|
## Chats and prompts
|
|
112
150
|
|
package/dist/auth.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { resolveCohubEnvironment } from "@neta-art/cohub";
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { withRuntimeSpaceBindingsLock } from "./runtime/space-binding.js";
|
|
3
5
|
import { homedir } from "node:os";
|
|
4
6
|
import { join } from "node:path";
|
|
5
7
|
import { setTimeout as delay } from "node:timers/promises";
|
|
@@ -31,7 +33,14 @@ const deviceCodePath = (env = currentEnv()) => join(CONFIG_DIR, env === "dev" ?
|
|
|
31
33
|
const legacyTokenPath = (env = currentEnv()) => join(CONFIG_DIR, env === "dev" ? "token.dev" : "token");
|
|
32
34
|
const writePrivateJson = (path, value) => {
|
|
33
35
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
34
|
-
|
|
36
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
37
|
+
try {
|
|
38
|
+
writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, { encoding: "utf-8", mode: 0o600, flag: "wx" });
|
|
39
|
+
renameSync(temporary, path);
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
rmSync(temporary, { force: true });
|
|
43
|
+
}
|
|
35
44
|
};
|
|
36
45
|
const readJson = (path) => {
|
|
37
46
|
if (!existsSync(path))
|
|
@@ -55,6 +64,7 @@ const formPost = async (url, body) => {
|
|
|
55
64
|
method: "POST",
|
|
56
65
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
57
66
|
body,
|
|
67
|
+
signal: AbortSignal.timeout(15_000),
|
|
58
68
|
});
|
|
59
69
|
const contentType = response.headers.get("content-type") ?? "";
|
|
60
70
|
const data = contentType.includes("application/json")
|
|
@@ -142,9 +152,25 @@ export async function requireAccessToken() {
|
|
|
142
152
|
throw new AuthRequiredError();
|
|
143
153
|
return token;
|
|
144
154
|
}
|
|
145
|
-
|
|
155
|
+
let refreshInFlight = null;
|
|
156
|
+
export function refreshAccessToken(session = readAuthSession()) {
|
|
146
157
|
if (!session?.refreshToken)
|
|
147
|
-
|
|
158
|
+
return Promise.reject(new AuthRequiredError());
|
|
159
|
+
if (refreshInFlight)
|
|
160
|
+
return refreshInFlight;
|
|
161
|
+
const path = sessionPath(session.env);
|
|
162
|
+
refreshInFlight = withRuntimeSpaceBindingsLock(async () => {
|
|
163
|
+
const current = readJson(path);
|
|
164
|
+
if (!current)
|
|
165
|
+
throw new AuthRequiredError();
|
|
166
|
+
// Another process may already have rotated this refresh token.
|
|
167
|
+
if (current.refreshToken !== session.refreshToken || current.updatedAt !== session.updatedAt)
|
|
168
|
+
return current.accessToken;
|
|
169
|
+
return performRefresh(current);
|
|
170
|
+
}, { path, lockPath: `${path}.refresh.lock` }).finally(() => { refreshInFlight = null; });
|
|
171
|
+
return refreshInFlight;
|
|
172
|
+
}
|
|
173
|
+
async function performRefresh(session) {
|
|
148
174
|
const config = authConfig(session.env);
|
|
149
175
|
const { response, data } = await formPost(tokenEndpoint(session.issuer), new URLSearchParams({
|
|
150
176
|
client_id: session.clientId,
|
|
@@ -155,12 +181,19 @@ export async function refreshAccessToken(session = readAuthSession()) {
|
|
|
155
181
|
}));
|
|
156
182
|
if (!response.ok) {
|
|
157
183
|
if (isUnrecoverableRefreshError(data)) {
|
|
158
|
-
|
|
184
|
+
if (readJson(sessionPath(session.env))?.refreshToken === session.refreshToken)
|
|
185
|
+
clearAuthSession();
|
|
159
186
|
return null;
|
|
160
187
|
}
|
|
161
188
|
throw new Error(formatAuthError(data, response.status));
|
|
162
189
|
}
|
|
163
190
|
const next = toSession(data, config, session.env, session);
|
|
191
|
+
// Never overwrite a login/logout that completed while the request was in flight.
|
|
192
|
+
const current = readJson(sessionPath(session.env));
|
|
193
|
+
if (!current)
|
|
194
|
+
throw new AuthRequiredError();
|
|
195
|
+
if (current.refreshToken !== session.refreshToken)
|
|
196
|
+
return current.accessToken;
|
|
164
197
|
writePrivateJson(sessionPath(session.env), next);
|
|
165
198
|
return next.accessToken;
|
|
166
199
|
}
|
package/dist/client.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { CohubClient, CohubHttpClient, readRequestSourceFromEnv } from "@neta-art/cohub";
|
|
2
|
-
import { clearAuthSession, resolveAccessToken } from "./auth.js";
|
|
2
|
+
import { clearAuthSession, readAuthSession, resolveAccessToken } from "./auth.js";
|
|
3
3
|
const clientOptions = () => ({
|
|
4
4
|
getAccessToken: resolveAccessToken,
|
|
5
|
-
onUnauthorized:
|
|
5
|
+
onUnauthorized: (context) => {
|
|
6
|
+
if (!process.env.COHUB_EXECUTION_TOKEN?.trim() && context.matchesRejectedToken(readAuthSession()?.accessToken ?? null))
|
|
7
|
+
clearAuthSession();
|
|
8
|
+
},
|
|
6
9
|
requestSource: () => readRequestSourceFromEnv(process.env, { via: "cli" }) ?? {
|
|
7
10
|
via: "cli",
|
|
8
11
|
},
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
|
-
export
|
|
3
|
-
export declare function parseRuntimeHarnesses(values: string[]): ("pi" | "codex")[];
|
|
2
|
+
export { resolveLocalSpaceName, parseRuntimeHarnesses } from "../runtime/launch.js";
|
|
4
3
|
export declare function registerRuntime(program: Command): void;
|