@nowcrew/daemon 0.6.91-beta.6 → 0.6.91-beta.7
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/dist/agent-ability/types.js +1 -1
- package/dist/computer-main.js +0 -0
- package/dist/execution-concurrency-telemetry.js +1 -0
- package/dist/execution-journal.js +1 -1
- package/dist/execution-protocol.js +1 -1
- package/dist/execution-runner.js +3 -2
- package/dist/external-output.js +2 -1
- package/dist/local-executor.js +2 -2
- package/dist/main.js +0 -0
- package/dist/normalize.js +9 -5
- package/dist/runtime-capabilities.js +2 -1
- package/dist/runtime-startup-gate.js +1 -0
- package/dist/runtimes/pi-runner.js +28 -0
- package/dist/runtimes/pi.js +17 -0
- package/dist/supervised-runtime.js +20 -0
- package/package.json +9 -8
|
@@ -81,7 +81,7 @@ export const DaemonAbilityManifestSchema = z.object({
|
|
|
81
81
|
cases: z.array(SafeAbilityPathSchema).max(1_000).default([]),
|
|
82
82
|
}).strict().default({ cases: [] }),
|
|
83
83
|
compatibility: z.object({
|
|
84
|
-
providers: z.array(z.enum(["claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness"])).min(1),
|
|
84
|
+
providers: z.array(z.enum(["claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness", "pi"])).min(1),
|
|
85
85
|
minNowCrewVersion: z.string().regex(/^\d+\.\d+\.\d+$/u),
|
|
86
86
|
}).strict().optional(),
|
|
87
87
|
permissions: z.object({
|
package/dist/computer-main.js
CHANGED
|
File without changes
|
|
@@ -8,7 +8,7 @@ import { provePosixProcessGroupStopped } from "./execution-posix-stop-proof.js";
|
|
|
8
8
|
export { JournalLockedError, JournalLockCorruptionError } from "./execution-journal-lock.js";
|
|
9
9
|
const ExecutionIdSchema = z.string().uuid();
|
|
10
10
|
const TimestampSchema = z.string().datetime({ offset: true });
|
|
11
|
-
const RuntimeSchema = z.enum(["claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness"]);
|
|
11
|
+
const RuntimeSchema = z.enum(["claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness", "pi"]);
|
|
12
12
|
const RUNTIME_READY_SUFFIX = ".runtime-ready";
|
|
13
13
|
const RawJournalEntrySchema = z.object({
|
|
14
14
|
executionId: ExecutionIdSchema,
|
|
@@ -13,7 +13,7 @@ const ExitCodeSchema = z.number().int().min(MIN_SIGNED_32_INTEGER).max(MAX_PG_IN
|
|
|
13
13
|
const ProviderErrorCategorySchema = z.enum(["auth", "quota", "rate_limit", "timeout", "network", "upstream", "cli", "unknown"]);
|
|
14
14
|
const ProviderHttpStatusSchema = z.number().int().min(100).max(599);
|
|
15
15
|
const ProviderErrorCodeSchema = z.string().min(1).max(128).regex(/^[A-Za-z0-9_.:-]+$/u);
|
|
16
|
-
const RuntimeSchema = z.enum(["claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness"]);
|
|
16
|
+
const RuntimeSchema = z.enum(["claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness", "pi"]);
|
|
17
17
|
const UnsafePathCharacterSchema = /[\p{Cc}<>:"/\\|?*]/u;
|
|
18
18
|
const WindowsReservedNameSchema = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i;
|
|
19
19
|
export const AgentHandleSchema = z.string().min(1).max(64).refine((handle) => handle !== "."
|
package/dist/execution-runner.js
CHANGED
|
@@ -285,11 +285,12 @@ function admission(spec, config, dependencies, at) {
|
|
|
285
285
|
return { rejected: rejection(spec.executionId, "resource_limit", "Local execution capacity is exhausted", at) };
|
|
286
286
|
}
|
|
287
287
|
const permission = effectivePermission(spec, config);
|
|
288
|
-
if ((spec.runtime.name === "kimi" || spec.runtime.name === "hermes" || spec.runtime.name === "opencode")
|
|
288
|
+
if ((spec.runtime.name === "kimi" || spec.runtime.name === "hermes" || spec.runtime.name === "opencode" || spec.runtime.name === "pi")
|
|
289
289
|
&& permission !== "full_access") {
|
|
290
290
|
const displayName = spec.runtime.name === "kimi"
|
|
291
291
|
? "Kimi"
|
|
292
|
-
: spec.runtime.name === "hermes" ? "Hermes"
|
|
292
|
+
: spec.runtime.name === "hermes" ? "Hermes"
|
|
293
|
+
: spec.runtime.name === "pi" ? "Pi" : "OpenCode";
|
|
293
294
|
return {
|
|
294
295
|
rejected: rejection(spec.executionId, "local_policy_denied", `${displayName} cannot enforce ${permission} permission`, at),
|
|
295
296
|
};
|
package/dist/external-output.js
CHANGED
|
@@ -212,7 +212,8 @@ export function decodeExternalOutputEvent(runtime, event, decoder) {
|
|
|
212
212
|
}
|
|
213
213
|
if ((runtime === "hermes" && candidate.type === "hermes.acp.text_delta")
|
|
214
214
|
|| (runtime === "deepseek-harness" && candidate.type === "deepseek-harness.acp.text_delta")
|
|
215
|
-
|| (runtime === "opencode" && candidate.type === "opencode.text_delta")
|
|
215
|
+
|| (runtime === "opencode" && candidate.type === "opencode.text_delta")
|
|
216
|
+
|| (runtime === "pi" && candidate.type === "pi.text_delta")) {
|
|
216
217
|
return typeof candidate.text === "string" ? decoder.push(candidate.text) : [];
|
|
217
218
|
}
|
|
218
219
|
return candidate.type === undefined
|
package/dist/local-executor.js
CHANGED
|
@@ -89,7 +89,7 @@ export function awaitExit(child) {
|
|
|
89
89
|
}
|
|
90
90
|
export function exitActivity(runtime, exitCode, stderrTail) {
|
|
91
91
|
if ((runtime === "codex" || runtime === "kimi" || runtime === "hermes"
|
|
92
|
-
|| runtime === "opencode" || runtime === "deepseek-harness" || exitCode === -1) && exitCode !== 0) {
|
|
92
|
+
|| runtime === "opencode" || runtime === "deepseek-harness" || runtime === "pi" || exitCode === -1) && exitCode !== 0) {
|
|
93
93
|
return {
|
|
94
94
|
kind: "error",
|
|
95
95
|
label: "运行出错",
|
|
@@ -97,7 +97,7 @@ export function exitActivity(runtime, exitCode, stderrTail) {
|
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
if ((runtime === "kimi" || runtime === "hermes" || runtime === "opencode"
|
|
100
|
-
|| runtime === "deepseek-harness") && exitCode === 0) {
|
|
100
|
+
|| runtime === "deepseek-harness" || runtime === "pi") && exitCode === 0) {
|
|
101
101
|
return { kind: "done", label: "本轮结束" };
|
|
102
102
|
}
|
|
103
103
|
return null;
|
package/dist/main.js
CHANGED
|
File without changes
|
package/dist/normalize.js
CHANGED
|
@@ -37,7 +37,8 @@ export function extractFinalText(event) {
|
|
|
37
37
|
const e = (event ?? {});
|
|
38
38
|
if ((e.type === "kimi.acp.text_delta" || e.type === "hermes.acp.text_delta"
|
|
39
39
|
|| e.type === "deepseek-harness.acp.text_delta"
|
|
40
|
-
|| e.type === "opencode.text_delta"
|
|
40
|
+
|| e.type === "opencode.text_delta"
|
|
41
|
+
|| e.type === "pi.text_delta") && e.text)
|
|
41
42
|
return e.text;
|
|
42
43
|
if (e.type === "result" && !e.is_error && e.result?.trim())
|
|
43
44
|
return e.result.trim();
|
|
@@ -70,15 +71,18 @@ export function normalizeEvent(event) {
|
|
|
70
71
|
}
|
|
71
72
|
if ((e.type === "kimi.acp.text_delta" || e.type === "hermes.acp.text_delta"
|
|
72
73
|
|| e.type === "deepseek-harness.acp.text_delta"
|
|
73
|
-
|| e.type === "opencode.text_delta"
|
|
74
|
+
|| e.type === "opencode.text_delta"
|
|
75
|
+
|| e.type === "pi.text_delta") && e.text?.trim()) {
|
|
74
76
|
return [{ kind: "text", label: "思考/说明", detail: e.text }];
|
|
75
77
|
}
|
|
76
78
|
if (e.type === "kimi.acp.tool_call" || e.type === "hermes.acp.tool_call"
|
|
77
|
-
|| e.type === "deepseek-harness.acp.tool_call" || e.type === "opencode.tool_call"
|
|
79
|
+
|| e.type === "deepseek-harness.acp.tool_call" || e.type === "opencode.tool_call"
|
|
80
|
+
|| e.type === "pi.tool_call") {
|
|
78
81
|
return [{ kind: "tool", label: e.title ? `工具:${e.title}` : "工具调用" }];
|
|
79
82
|
}
|
|
80
83
|
if (e.type === "kimi.acp.tool_result" || e.type === "hermes.acp.tool_result"
|
|
81
|
-
|| e.type === "deepseek-harness.acp.tool_result" || e.type === "opencode.tool_result"
|
|
84
|
+
|| e.type === "deepseek-harness.acp.tool_result" || e.type === "opencode.tool_result"
|
|
85
|
+
|| e.type === "pi.tool_result") {
|
|
82
86
|
return [{ kind: "tool_result", label: "工具返回" }];
|
|
83
87
|
}
|
|
84
88
|
if (e.type === "system" && e.subtype === "init") {
|
|
@@ -97,7 +101,7 @@ export function normalizeEvent(event) {
|
|
|
97
101
|
if (e.type === "turn.completed") {
|
|
98
102
|
return [{ kind: "done", label: "本轮结束" }];
|
|
99
103
|
}
|
|
100
|
-
if (e.type === "opencode.error") {
|
|
104
|
+
if (e.type === "opencode.error" || e.type === "pi.error") {
|
|
101
105
|
const detail = typeof event.message === "string"
|
|
102
106
|
? event.message
|
|
103
107
|
: undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ATTACHMENT_NATIVE_IMAGE_MAX_BYTES } from "./attachment-limits.js";
|
|
2
2
|
export const LOCAL_EXECUTION_RUNTIMES = [
|
|
3
|
-
"claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness",
|
|
3
|
+
"claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness", "pi",
|
|
4
4
|
];
|
|
5
5
|
export const LOCAL_RUNTIME_CAPABILITIES = Object.freeze({
|
|
6
6
|
claude: Object.freeze({
|
|
@@ -33,6 +33,7 @@ export const LOCAL_RUNTIME_CAPABILITIES = Object.freeze({
|
|
|
33
33
|
nativeResume: false,
|
|
34
34
|
systemPromptTransport: "protocol",
|
|
35
35
|
}),
|
|
36
|
+
pi: Object.freeze({ transport: "pi-json", nativeResume: false, systemPromptTransport: "protocol" }),
|
|
36
37
|
});
|
|
37
38
|
export function runtimeCapability(runtime) {
|
|
38
39
|
return LOCAL_RUNTIME_CAPABILITIES[runtime];
|
|
@@ -96,6 +96,7 @@ export function createRuntimeStartupGate(limits, now = Date.now) {
|
|
|
96
96
|
hermes: activeByRuntimeAndLane.get(activeKey("hermes", "foreground")) ?? 0,
|
|
97
97
|
opencode: activeByRuntimeAndLane.get(activeKey("opencode", "foreground")) ?? 0,
|
|
98
98
|
"deepseek-harness": activeByRuntimeAndLane.get(activeKey("deepseek-harness", "foreground")) ?? 0,
|
|
99
|
+
pi: activeByRuntimeAndLane.get(activeKey("pi", "foreground")) ?? 0,
|
|
99
100
|
},
|
|
100
101
|
}),
|
|
101
102
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { once } from "node:events";
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import spawn from "cross-spawn";
|
|
6
|
+
import { augmentedPath } from "../runtime-path.js";
|
|
7
|
+
import { buildPiArgs, createPiEventDecoder } from "./pi.js";
|
|
8
|
+
async function readInput() { process.stdin.setEncoding("utf8"); let text = ""; for await (const chunk of process.stdin)
|
|
9
|
+
text += String(chunk); return JSON.parse(text); }
|
|
10
|
+
async function emit(event) { if (process.stdout.write(`${JSON.stringify(event)}\n`))
|
|
11
|
+
return; await once(process.stdout, "drain"); }
|
|
12
|
+
export async function runPi(bin) { const input = await readInput(); const child = spawn(bin, buildPiArgs(input), { cwd: process.cwd(), env: { ...process.env, PATH: augmentedPath(), PWD: process.cwd() }, stdio: ["ignore", "pipe", "pipe"] }); if (!child.stdout || !child.stderr)
|
|
13
|
+
throw new Error("Pi process did not expose stdio"); child.stderr.pipe(process.stderr, { end: false }); const exit = once(child, "close"); const decoder = createPiEventDecoder(); for await (const line of createInterface({ input: child.stdout })) {
|
|
14
|
+
try {
|
|
15
|
+
for (const event of decoder.push(JSON.parse(line)))
|
|
16
|
+
await emit(event);
|
|
17
|
+
}
|
|
18
|
+
catch { }
|
|
19
|
+
} const [code, signal] = await exit; const result = decoder.finish(); if (!result.ok) {
|
|
20
|
+
process.stderr.write(`${result.error}\n`);
|
|
21
|
+
return 1;
|
|
22
|
+
} return code === 0 ? 0 : (code ?? (signal ? 128 : 1)); }
|
|
23
|
+
const { values } = parseArgs({ args: process.argv.slice(2), options: { bin: { type: "string" } } });
|
|
24
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
25
|
+
if (!values.bin)
|
|
26
|
+
throw new Error("--bin is required");
|
|
27
|
+
runPi(values.bin).then(code => { process.exitCode = code; }).catch(error => { process.stderr.write(`Pi runner failed: ${String(error)}\n`); process.exitCode = 1; });
|
|
28
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function buildPiArgs(options) { return ["--mode", "json", "--print", "--no-session", "--system-prompt", options.systemPrompt, ...(options.model ? ["--model", options.model] : []), ...(options.reasoning && options.reasoning !== "default" ? ["--thinking", options.reasoning] : []), options.wakePrompt]; }
|
|
2
|
+
export function createPiEventDecoder() { let sessionId = null; let finalText = ""; let error = null; let sawTurnEnd = false; let usage; return { push(raw) { const e = (raw ?? {}); const out = []; if (e.type === "session" && typeof e.id === "string") {
|
|
3
|
+
sessionId = e.id;
|
|
4
|
+
out.push({ type: "thread.started", thread_id: e.id });
|
|
5
|
+
} const ae = e.assistantMessageEvent; if (e.type === "message_update" && ae?.type === "text_delta" && typeof ae.delta === "string") {
|
|
6
|
+
finalText += ae.delta;
|
|
7
|
+
out.push({ type: "pi.text_delta", text: ae.delta });
|
|
8
|
+
} if (e.type === "message_update" && typeof ae?.type === "string" && /tool(call|_call)/iu.test(ae.type))
|
|
9
|
+
out.push({ type: "pi.tool_call", ...(ae.name ? { title: ae.name } : {}) }); if (e.type === "message_end" && e.message?.role === "assistant")
|
|
10
|
+
usage = e.message.usage; if (e.type === "turn_end") {
|
|
11
|
+
sawTurnEnd = true;
|
|
12
|
+
const u = usage;
|
|
13
|
+
out.push({ type: "turn.completed", ...(u ? { usage: { input_tokens: u.input ?? 0, output_tokens: u.output ?? 0, cache_read_input_tokens: u.cacheRead ?? 0, cache_creation_input_tokens: u.cacheWrite ?? 0 } } : {}) });
|
|
14
|
+
} if (e.type === "error" || e.type === "agent_error") {
|
|
15
|
+
error = typeof e.error === "string" ? e.error : (e.error?.message ?? "Pi error");
|
|
16
|
+
out.push({ type: "pi.error", message: error });
|
|
17
|
+
} return out; }, finish() { return { ok: error === null && sawTurnEnd, ...(error === null && sawTurnEnd ? {} : { error: error ?? "Pi stream ended without turn completion" }), finalText, sessionId, usage }; } }; }
|
|
@@ -61,6 +61,26 @@ export function supervisorLaunch(request) {
|
|
|
61
61
|
}),
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
+
if (request.runtime === "pi") {
|
|
65
|
+
if (request.effectivePermission !== "full_access") {
|
|
66
|
+
throw new Error(`Pi cannot enforce ${request.effectivePermission} permission`);
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
command: process.execPath,
|
|
70
|
+
args: [
|
|
71
|
+
fileURLToPath(new URL("./runtimes/pi-runner.js", import.meta.url)),
|
|
72
|
+
"--bin", request.bin,
|
|
73
|
+
],
|
|
74
|
+
cwd: request.cwd,
|
|
75
|
+
env: request.env,
|
|
76
|
+
stdinText: JSON.stringify({
|
|
77
|
+
systemPrompt: request.systemPrompt,
|
|
78
|
+
wakePrompt: request.wakePrompt,
|
|
79
|
+
...(request.model === undefined ? {} : { model: request.model }),
|
|
80
|
+
...(request.reasoning === undefined ? {} : { reasoning: request.reasoning }),
|
|
81
|
+
}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
64
84
|
if (request.runtime === "opencode") {
|
|
65
85
|
if (request.effectivePermission !== "full_access") {
|
|
66
86
|
throw new Error(`OpenCode cannot enforce ${request.effectivePermission} permission`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowcrew/daemon",
|
|
3
|
-
"version": "0.6.91-beta.
|
|
3
|
+
"version": "0.6.91-beta.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "crew daemon — 运行在用户机器:拉起/管理 agent 进程,注入 crew CLI,归一化 runtime 事件",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -18,6 +18,13 @@
|
|
|
18
18
|
"publishConfig": {
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"daemon": "pnpm --filter @nowcrew/cli build && tsx src/main.ts",
|
|
23
|
+
"build": "tsc -p tsconfig.json",
|
|
24
|
+
"prepublishOnly": "pnpm build && node ../scripts/daemon-release-artifact.mjs --strict-registry",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"typecheck": "tsc --noEmit"
|
|
27
|
+
},
|
|
21
28
|
"dependencies": {
|
|
22
29
|
"@agentclientprotocol/sdk": "1.2.1",
|
|
23
30
|
"@nowcrew/cli": "0.4.17",
|
|
@@ -39,11 +46,5 @@
|
|
|
39
46
|
"tsx": "^4.19.0",
|
|
40
47
|
"typescript": "^5.6.0",
|
|
41
48
|
"vitest": "^2.1.0"
|
|
42
|
-
},
|
|
43
|
-
"scripts": {
|
|
44
|
-
"daemon": "pnpm --filter @nowcrew/cli build && tsx src/main.ts",
|
|
45
|
-
"build": "tsc -p tsconfig.json",
|
|
46
|
-
"test": "vitest run",
|
|
47
|
-
"typecheck": "tsc --noEmit"
|
|
48
49
|
}
|
|
49
|
-
}
|
|
50
|
+
}
|