@nowcrew/daemon 0.5.11 → 0.5.13
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 +77 -0
- package/dist/config.js +38 -0
- package/dist/execution-event-limit.js +59 -0
- package/dist/execution-journal-lock.js +262 -0
- package/dist/execution-journal.js +678 -0
- package/dist/execution-protocol.js +310 -0
- package/dist/execution-runner.js +637 -0
- package/dist/execution-supervisor-child.js +185 -0
- package/dist/execution-supervisor.js +209 -0
- package/dist/local-executor.js +326 -0
- package/dist/machine-info.js +13 -4
- package/dist/origin-decision.js +42 -0
- package/dist/prompt.js +23 -1
- package/dist/runner.js +146 -340
- package/dist/runtimes/claude.js +9 -1
- package/dist/runtimes/codex.js +21 -5
- package/dist/runtimes/kimi.js +3 -0
- package/dist/scheduled-run-report.js +15 -7
- package/dist/serve.js +412 -57
- package/dist/token.js +5 -2
- package/dist/workspace.js +39 -11
- package/package.json +3 -2
package/dist/token.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** 用机器令牌为某 agent 换取 per-launch 的 sk_agent_*。 */
|
|
2
|
-
export async function mintAgentToken(serverUrl, machineToken, handle, displayName,
|
|
2
|
+
export async function mintAgentToken(serverUrl, machineToken, handle, displayName, options = {}, fetchImpl = fetch) {
|
|
3
3
|
const res = await fetchImpl(`${serverUrl}/daemon/agents/token`, {
|
|
4
4
|
method: "POST",
|
|
5
5
|
headers: {
|
|
@@ -10,7 +10,10 @@ export async function mintAgentToken(serverUrl, machineToken, handle, displayNam
|
|
|
10
10
|
body: JSON.stringify({
|
|
11
11
|
handle,
|
|
12
12
|
...(displayName ? { displayName } : {}),
|
|
13
|
-
...(wakeThreadRoot ? { wakeThreadRoot } : {}),
|
|
13
|
+
...(options.wakeThreadRoot ? { wakeThreadRoot: options.wakeThreadRoot } : {}),
|
|
14
|
+
...(options.wakeContextUpToSeq !== undefined ? { wakeContextUpToSeq: options.wakeContextUpToSeq } : {}),
|
|
15
|
+
...(options.agentRunId ? { agentRunId: options.agentRunId } : {}),
|
|
16
|
+
...(options.executionId ? { executionId: options.executionId } : {}),
|
|
14
17
|
}),
|
|
15
18
|
});
|
|
16
19
|
const body = (await res.json().catch(() => null));
|
package/dist/workspace.js
CHANGED
|
@@ -2,18 +2,27 @@
|
|
|
2
2
|
* 准备 agent 在本机的工作区:
|
|
3
3
|
* <agentsRoot>/<handle>/
|
|
4
4
|
* ├── MEMORY.md 长期记忆/角色 (首次创建种子)
|
|
5
|
-
* ├── .crew/
|
|
5
|
+
* ├── .crew/prompts/<execution>.md 按 execution 隔离的系统提示词
|
|
6
6
|
* └── .crew/crew 注入 PATH 的 CLI wrapper (0755)
|
|
7
7
|
*
|
|
8
8
|
* spawn runtime 时把 <ws>/.crew 置于 PATH 最前,于是 agent 的 `crew ...` 命中 wrapper。
|
|
9
9
|
*/
|
|
10
10
|
import { mkdir, writeFile, readFile, chmod, access } from "node:fs/promises";
|
|
11
|
-
import { randomUUID } from "node:crypto";
|
|
11
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
/** 文件系统安全的 taskKey:仅留 [\w.-],其余转 _,截断,避免路径穿越/超长。 */
|
|
14
14
|
export function safeKey(key) {
|
|
15
15
|
return key.replace(/[^\w.-]+/g, "_").replace(/^[-.]+/, "").slice(0, 80) || "default";
|
|
16
16
|
}
|
|
17
|
+
/** Stable, collision-resistant single path component for server-provided opaque identifiers. */
|
|
18
|
+
export function opaqueKey(key) {
|
|
19
|
+
const readable = safeKey(key).slice(0, 40);
|
|
20
|
+
const digest = createHash("sha256").update(key, "utf8").digest("hex");
|
|
21
|
+
return `${readable}-${digest}`;
|
|
22
|
+
}
|
|
23
|
+
function workspaceKey(key, mode) {
|
|
24
|
+
return mode === "opaque" ? opaqueKey(key) : safeKey(key);
|
|
25
|
+
}
|
|
17
26
|
async function exists(p) {
|
|
18
27
|
try {
|
|
19
28
|
await access(p);
|
|
@@ -33,8 +42,10 @@ export async function prepareWorkspace(input) {
|
|
|
33
42
|
await writeFile(memoryPath, memorySeed(input.handle, input.description), "utf8");
|
|
34
43
|
}
|
|
35
44
|
const memory = await readFile(memoryPath, "utf8");
|
|
36
|
-
//
|
|
37
|
-
const
|
|
45
|
+
// 系统提示词按 execution 隔离;省略 identity 的兼容调用每次使用随机路径。
|
|
46
|
+
const promptDir = join(crewDir, "prompts");
|
|
47
|
+
await mkdir(promptDir, { recursive: true });
|
|
48
|
+
const systemPromptPath = join(promptDir, `${opaqueKey(input.executionId ?? randomUUID())}.md`);
|
|
38
49
|
if (input.systemPrompt != null)
|
|
39
50
|
await writeFile(systemPromptPath, input.systemPrompt, "utf8");
|
|
40
51
|
// crew wrapper:exec 构建后的 CLI;凭证/地址经 env 注入,故 wrapper 极简
|
|
@@ -53,16 +64,21 @@ export async function prepareWorkspace(input) {
|
|
|
53
64
|
let runDir = dir;
|
|
54
65
|
let workLogPath = join(dir, "tasks", "default", "work-log.md");
|
|
55
66
|
if (input.taskKey) {
|
|
56
|
-
runDir = join(dir, "tasks",
|
|
67
|
+
runDir = join(dir, "tasks", workspaceKey(input.taskKey, input.keyMode));
|
|
57
68
|
await mkdir(runDir, { recursive: true });
|
|
58
69
|
workLogPath = join(runDir, "work-log.md");
|
|
59
70
|
}
|
|
60
71
|
const workLog = (await exists(workLogPath)) ? await readFile(workLogPath, "utf8") : "";
|
|
61
|
-
//
|
|
72
|
+
// resumeKey 可跨不同 task cwd 维持同一底层会话;协议键用 opaque 映射,legacy 保持 safeKey。
|
|
73
|
+
const sessionDir = input.resumeKey
|
|
74
|
+
? join(crewDir, "sessions", workspaceKey(input.resumeKey, input.keyMode))
|
|
75
|
+
: runDir;
|
|
76
|
+
if (input.resumeKey)
|
|
77
|
+
await mkdir(sessionDir, { recursive: true });
|
|
62
78
|
let agentSessionId = null;
|
|
63
79
|
let sessionResume = false;
|
|
64
|
-
if (input.taskKey) {
|
|
65
|
-
const sessionPath = join(
|
|
80
|
+
if (input.taskKey || input.resumeKey) {
|
|
81
|
+
const sessionPath = join(sessionDir, ".session");
|
|
66
82
|
if (await exists(sessionPath)) {
|
|
67
83
|
agentSessionId = (await readFile(sessionPath, "utf8")).trim() || null;
|
|
68
84
|
sessionResume = !!agentSessionId;
|
|
@@ -72,16 +88,28 @@ export async function prepareWorkspace(input) {
|
|
|
72
88
|
await writeFile(sessionPath, agentSessionId, "utf8");
|
|
73
89
|
}
|
|
74
90
|
}
|
|
75
|
-
return {
|
|
91
|
+
return {
|
|
92
|
+
dir,
|
|
93
|
+
crewDir,
|
|
94
|
+
systemPromptPath,
|
|
95
|
+
memory,
|
|
96
|
+
homeDir,
|
|
97
|
+
runDir,
|
|
98
|
+
workLogPath,
|
|
99
|
+
workLog,
|
|
100
|
+
agentSessionId,
|
|
101
|
+
sessionResume,
|
|
102
|
+
sessionDir,
|
|
103
|
+
};
|
|
76
104
|
}
|
|
77
105
|
/**
|
|
78
106
|
* 冷启动时轮换会话 id:写入新 uuid 到 <runDir>/.session 并返回。
|
|
79
107
|
* 已有会话但本轮决定不续用(warm 窗口过期 / CREW_RESUME=off)时调用——起一个全新会话,
|
|
80
108
|
* 避免拿已存在的 id 走 `--session-id`(claude 会判定 id 冲突),同时保持「一线程一(当前)会话」。
|
|
81
109
|
*/
|
|
82
|
-
export async function rotateAgentSession(
|
|
110
|
+
export async function rotateAgentSession(sessionDir) {
|
|
83
111
|
const id = randomUUID();
|
|
84
|
-
await writeFile(join(
|
|
112
|
+
await writeFile(join(sessionDir, ".session"), id, "utf8");
|
|
85
113
|
return id;
|
|
86
114
|
}
|
|
87
115
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowcrew/daemon",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "crew daemon — 运行在用户机器:拉起/管理 agent 进程,注入 crew CLI,归一化 runtime 事件",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"cross-spawn": "^7.0.6",
|
|
21
21
|
"ws": "^8",
|
|
22
|
-
"
|
|
22
|
+
"zod": "^3.23.0",
|
|
23
|
+
"@nowcrew/cli": "^0.4.5"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"@types/cross-spawn": "^6.0.6",
|