@nowcrew/daemon 0.6.97-beta.9 → 0.6.97
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 +7 -0
- package/dist/computer-main.js +0 -0
- package/dist/machine-info.js +0 -2
- package/dist/main.js +0 -0
- package/dist/project-skills/machine-hello-publisher.js +6 -95
- package/dist/provider-env.js +8 -3
- package/dist/runtimes/codex-app-server-runner.js +2 -0
- package/dist/runtimes/codex-execution-policy.js +12 -0
- package/dist/runtimes/codex.js +2 -0
- package/dist/serve.js +6 -53
- package/package.json +9 -8
package/README.md
CHANGED
|
@@ -413,6 +413,13 @@ discovery is unchanged: Claude may still load `~/.claude/skills`, and Codex may
|
|
|
413
413
|
and `~/.agents/skills`. The DeepSeek Codex variant keeps its Agent-private `.codex-deepseek` Home for
|
|
414
414
|
provider credentials. Project bindings do not hide or rewrite any of those sources.
|
|
415
415
|
|
|
416
|
+
Both Codex launchers disable host automatic memories and inherit the execution's prepared environment,
|
|
417
|
+
overriding host `core`, default exclusions, `exclude` and `include_only` filters. These are process-local
|
|
418
|
+
settings: authentication, providers and Skills retain the configured Home, and no other environment
|
|
419
|
+
scope is merged. The policy version in Codex's session fingerprint cold-starts older native sessions
|
|
420
|
+
once, then subsequent runs can resume normally. Explicit `shell_environment_policy.set` entries, shell
|
|
421
|
+
startup scripts and Agent notes remain separate configuration; this change does not correct them.
|
|
422
|
+
|
|
416
423
|
Binding changes reconcile immediately when the Computer is online. On reconnect the server sends the
|
|
417
424
|
complete binding set for every Agent assigned to that Computer, including empty sets that clear stale
|
|
418
425
|
links left by offline unbinds. Every non-empty execution snapshot is also reconciled immediately before
|
package/dist/computer-main.js
CHANGED
|
File without changes
|
package/dist/machine-info.js
CHANGED
|
@@ -33,7 +33,6 @@ export const SELF_TRAINING_EXECUTION_CAPABILITY = "self_training_execution_v1";
|
|
|
33
33
|
export const EXECUTION_LARGE_ATTACHMENTS_CAPABILITY = "execution_attachments_300m_v1";
|
|
34
34
|
export const PROJECT_SKILL_PROJECTION_CAPABILITY = "project_skill_projection_v2";
|
|
35
35
|
export const MACHINE_ENVIRONMENT_CAPABILITY = "machine_environment_v1";
|
|
36
|
-
export const MACHINE_HELLO_ACK_CAPABILITY = "machine_hello_ack_v1";
|
|
37
36
|
export const NATIVE_PROJECT_WORKSPACE_READINESS = Object.freeze({
|
|
38
37
|
resolverReady: true,
|
|
39
38
|
nativeRuntimeAdaptersReady: true,
|
|
@@ -63,7 +62,6 @@ export const DAEMON_CAPABILITIES = Object.freeze([
|
|
|
63
62
|
"agent_ability_runtime_assets_v1",
|
|
64
63
|
"agent_environments_v1",
|
|
65
64
|
MACHINE_ENVIRONMENT_CAPABILITY,
|
|
66
|
-
MACHINE_HELLO_ACK_CAPABILITY,
|
|
67
65
|
]);
|
|
68
66
|
/** 能力只按平台过滤,进程存活期间静态(CLAUDE.md 红线)。Windows 在 junction/copy 真机 smoke 通过前不宣告 Project Skills。 */
|
|
69
67
|
export const daemonCapabilities = (runtimePlatform = process.platform, readiness = NATIVE_PROJECT_WORKSPACE_READINESS) => {
|
package/dist/main.js
CHANGED
|
File without changes
|
|
@@ -1,109 +1,20 @@
|
|
|
1
1
|
import { WebSocket } from "ws";
|
|
2
|
-
const HELLO_RETRY_DELAYS_MS = [1_000, 2_000, 4_000];
|
|
3
2
|
/** 记住最近一次 hello 与 socket,便于存储身份变化后重发;Project Skills 状态恒为 ready。 */
|
|
4
3
|
export function createMachineHelloPublisher(input) {
|
|
5
4
|
let latest = null;
|
|
6
5
|
let latestSocket = null;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// 发送代次:每开一轮新发送(attach/publish/republish)自增,随帧发出并要求 ack 回显。
|
|
10
|
-
let generation = 0;
|
|
11
|
-
let retryTimer;
|
|
12
|
-
const clearRetry = () => {
|
|
13
|
-
if (retryTimer !== undefined) {
|
|
14
|
-
clearTimeout(retryTimer);
|
|
15
|
-
retryTimer = undefined;
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
const scheduleRetry = () => {
|
|
19
|
-
clearRetry();
|
|
20
|
-
if (acknowledged || latest === null || latestSocket?.readyState !== WebSocket.OPEN)
|
|
21
|
-
return;
|
|
22
|
-
// 当前 server 不支持 ack → 不排重试(否则永远等不到确认,白跑满退避)。
|
|
23
|
-
if (input.ackSupported && !input.ackSupported())
|
|
24
|
-
return;
|
|
25
|
-
const delay = HELLO_RETRY_DELAYS_MS[attempts - 1];
|
|
26
|
-
if (delay === undefined) {
|
|
27
|
-
// 退避跑满仍未 ack:期待 ack(ackSupported 已声明支持)才升级为断连重连,避免旧行为下反复重连。
|
|
28
|
-
if (input.ackSupported !== undefined && latestSocket !== null)
|
|
29
|
-
input.onExhausted?.(latestSocket);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
retryTimer = setTimeout(() => {
|
|
33
|
-
retryTimer = undefined;
|
|
34
|
-
sendCurrent();
|
|
35
|
-
}, delay);
|
|
36
|
-
};
|
|
37
|
-
function sendCurrent() {
|
|
38
|
-
if (latest === null || latestSocket?.readyState !== WebSocket.OPEN || acknowledged)
|
|
6
|
+
const republish = () => {
|
|
7
|
+
if (latest === null || latestSocket?.readyState !== WebSocket.OPEN)
|
|
39
8
|
return;
|
|
40
|
-
|
|
41
|
-
const hello = input.effective({ ...latest, projectSkillsStatus: "ready", helloSeq: generation });
|
|
42
|
-
const attempt = attempts + 1;
|
|
43
|
-
attempts = attempt;
|
|
9
|
+
const hello = input.effective({ ...latest, projectSkillsStatus: "ready" });
|
|
44
10
|
try {
|
|
45
11
|
latestSocket.send(JSON.stringify(hello));
|
|
46
|
-
input.onSent(hello
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
input.onSendFailed?.(hello, attempt, error);
|
|
12
|
+
input.onSent(hello);
|
|
50
13
|
}
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
const attach = (socket) => {
|
|
54
|
-
clearRetry();
|
|
55
|
-
latestSocket = socket;
|
|
56
|
-
acknowledged = false;
|
|
57
|
-
attempts = 0;
|
|
58
|
-
generation += 1;
|
|
59
|
-
sendCurrent();
|
|
60
|
-
};
|
|
61
|
-
const detach = (socket) => {
|
|
62
|
-
if (latestSocket !== socket)
|
|
63
|
-
return;
|
|
64
|
-
clearRetry();
|
|
65
|
-
latestSocket = null;
|
|
66
|
-
acknowledged = false;
|
|
67
|
-
attempts = 0;
|
|
68
|
-
};
|
|
69
|
-
const republish = () => {
|
|
70
|
-
if (latest === null || latestSocket === null)
|
|
71
|
-
return;
|
|
72
|
-
clearRetry();
|
|
73
|
-
acknowledged = false;
|
|
74
|
-
attempts = 0;
|
|
75
|
-
generation += 1;
|
|
76
|
-
sendCurrent();
|
|
77
|
-
};
|
|
78
|
-
const acknowledge = (socket, seq) => {
|
|
79
|
-
// 非当前 socket / 已确认 / 该 socket 已在关闭(close 后迟到的 ack)一律忽略:
|
|
80
|
-
// 后者会错误触发 onAck→清零强制重连计数,削弱重连上限。
|
|
81
|
-
if (latestSocket !== socket || latest === null || acknowledged || socket.readyState !== WebSocket.OPEN)
|
|
82
|
-
return;
|
|
83
|
-
// 代次校验:只接受回显当前代次的 ack,忽略上一代次迟到的 ack(否则会误停新代次的重试)。
|
|
84
|
-
// seq 缺省(老 server 不回显)时退回仅按 socket 匹配,保持兼容。
|
|
85
|
-
if (seq !== undefined && seq !== generation)
|
|
86
|
-
return;
|
|
87
|
-
acknowledged = true;
|
|
88
|
-
clearRetry();
|
|
89
|
-
input.onAck?.(input.effective({ ...latest, projectSkillsStatus: "ready" }));
|
|
14
|
+
catch { /* 非 OPEN,忽略 */ }
|
|
90
15
|
};
|
|
91
16
|
return Object.freeze({
|
|
92
|
-
publish: (hello, socket) => {
|
|
93
|
-
latest = hello;
|
|
94
|
-
if (latestSocket !== socket) {
|
|
95
|
-
attach(socket);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
acknowledged = false;
|
|
99
|
-
attempts = 0;
|
|
100
|
-
generation += 1;
|
|
101
|
-
clearRetry();
|
|
102
|
-
sendCurrent();
|
|
103
|
-
},
|
|
104
|
-
attach,
|
|
105
|
-
detach,
|
|
17
|
+
publish: (hello, socket) => { latest = hello; latestSocket = socket; republish(); },
|
|
106
18
|
republish,
|
|
107
|
-
acknowledge,
|
|
108
19
|
});
|
|
109
20
|
}
|
package/dist/provider-env.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { DEEPSEEK_CODEX_KEY_ENV, deepSeekCodexHome, } from "./runtimes/codex-deepseek-config.js";
|
|
13
13
|
import { mergeRuntimeEnvironments } from "./runtime-environment-merge.js";
|
|
14
|
+
import { CODEX_EXECUTION_POLICY_VERSION } from "./runtimes/codex-execution-policy.js";
|
|
14
15
|
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
15
16
|
const RESERVED_ENV = new Set([
|
|
16
17
|
"PATH",
|
|
@@ -125,11 +126,15 @@ export function applyDeepSeekHarnessMachineEnv(base, machineEnv, platform = proc
|
|
|
125
126
|
}
|
|
126
127
|
/**
|
|
127
128
|
* provider 关键配置指纹:Claude Custom 路由和 Codex DeepSeek key 有无都会改变会话边界,
|
|
128
|
-
* 供 pickResumeId 判定冷启动。
|
|
129
|
+
* 供 pickResumeId 判定冷启动。Codex 还包含执行策略版本,避免续用带宿主记忆的旧会话。
|
|
130
|
+
* 不含 key 明文(同 Provider 换 key 可续);其他 runtime 的 default 仍为 null。
|
|
129
131
|
*/
|
|
130
132
|
export function providerFingerprint(runtime, cfg) {
|
|
131
|
-
if (runtime === "codex"
|
|
132
|
-
|
|
133
|
+
if (runtime === "codex") {
|
|
134
|
+
const provider = cfg.provider === "deepseek"
|
|
135
|
+
? `deepseek|${cfg.providerBaseUrl ?? "default"}|${cfg.providerApiKey ? "key" : "nokey"}`
|
|
136
|
+
: "default";
|
|
137
|
+
return `${CODEX_EXECUTION_POLICY_VERSION}|${provider}`;
|
|
133
138
|
}
|
|
134
139
|
if (runtime !== "claude" || cfg.provider !== "custom")
|
|
135
140
|
return null;
|
|
@@ -10,6 +10,7 @@ import { assertCodexCollaborationVersion, assertCodexNativeWorkspaceVersion, ass
|
|
|
10
10
|
import { decideTurnRetry, itemMakesTurnUnsafe } from "./codex-turn-retry.js";
|
|
11
11
|
import { startFirstProgressWatchdog } from "./progress-watchdog.js";
|
|
12
12
|
import { prepareThreadDelivery, ThreadDeliveryColdStartRequired } from "../thread-input-delivery.js";
|
|
13
|
+
import { codexExecutionPolicyArgs } from "./codex-execution-policy.js";
|
|
13
14
|
const RunnerInputSchema = z.object({
|
|
14
15
|
systemPrompt: z.string().min(1),
|
|
15
16
|
wakePrompt: z.string().min(1),
|
|
@@ -57,6 +58,7 @@ export function codexAppServerArgs(input) {
|
|
|
57
58
|
// multi_agent 按开关;multi_agent_v2 无条件关,钉死已验证的 v1 契约(spec 2b)。
|
|
58
59
|
"-c", `features.multi_agent=${input.collaborationTools === true}`,
|
|
59
60
|
"-c", "features.multi_agent_v2=false",
|
|
61
|
+
...codexExecutionPolicyArgs(),
|
|
60
62
|
"app-server", "--listen", "stdio://",
|
|
61
63
|
];
|
|
62
64
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Bump when old native transcripts must not cross a changed execution boundary. */
|
|
2
|
+
export const CODEX_EXECUTION_POLICY_VERSION = "nowwork-codex-context-v1";
|
|
3
|
+
/** Process-local overrides: keep host auth/Skills without importing host automatic memory. */
|
|
4
|
+
export function codexExecutionPolicyArgs() {
|
|
5
|
+
return [
|
|
6
|
+
"features.memories=false",
|
|
7
|
+
'shell_environment_policy.inherit="all"',
|
|
8
|
+
"shell_environment_policy.ignore_default_excludes=true",
|
|
9
|
+
"shell_environment_policy.exclude=[]",
|
|
10
|
+
"shell_environment_policy.include_only=[]",
|
|
11
|
+
].flatMap(value => ["-c", value]);
|
|
12
|
+
}
|
package/dist/runtimes/codex.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
// cross-spawn:win32 上 npm CLI 是 .cmd shim,node 原生 spawn 不带 shell 无法执行(ENOENT/EINVAL)
|
|
5
5
|
import spawn from "cross-spawn";
|
|
6
|
+
import { codexExecutionPolicyArgs } from "./codex-execution-policy.js";
|
|
6
7
|
/** Minimum CLI whose real app-server contract supports NowCrew native project workspaces. */
|
|
7
8
|
export const CODEX_NATIVE_WORKSPACE_MIN_VERSION = "0.148.0";
|
|
8
9
|
/** Minimum CLI whose `multi_agent` collaboration tool contract was empirically verified (2026-08-28). */
|
|
@@ -26,6 +27,7 @@ export function buildCodexArgs(input) {
|
|
|
26
27
|
args.push("-c", `model_reasoning_effort=${effort}`);
|
|
27
28
|
// 纵深防御:exec 启动器没有 initialize 握手、无法断言版本,协作工具恒关(spec 2b)。
|
|
28
29
|
args.push("-c", "features.multi_agent=false", "-c", "features.multi_agent_v2=false");
|
|
30
|
+
args.push(...codexExecutionPolicyArgs());
|
|
29
31
|
if (input.projectRootMarkers) {
|
|
30
32
|
args.push("-c", `project_root_markers=${JSON.stringify(input.projectRootMarkers)}`);
|
|
31
33
|
}
|
package/dist/serve.js
CHANGED
|
@@ -9,7 +9,7 @@ import { randomUUID } from "node:crypto";
|
|
|
9
9
|
import { dslog, setSlogDefaults, drainSpool, flushSlog } from "./slog.js";
|
|
10
10
|
import { mergeRunAgentResults, reportScheduledStartFailure, runAgent } from "./runner.js";
|
|
11
11
|
import { buildOriginDecisionRetryPrompt, buildScheduledPrompt } from "./prompt.js";
|
|
12
|
-
import { daemonCapabilities, daemonCapabilityBindings,
|
|
12
|
+
import { daemonCapabilities, daemonCapabilityBindings, } from "./machine-info.js";
|
|
13
13
|
import { reconcileExecutionJournal } from "./execution-recovery.js";
|
|
14
14
|
import { initReleaseSlog, reportDaemonConnectionClose, reportReleaseError } from "./release-channel-guard.js";
|
|
15
15
|
import { handleWorkspaceControlRequest } from "./workspace-control-handler.js";
|
|
@@ -65,10 +65,6 @@ export function serve(config, opts = {}) {
|
|
|
65
65
|
let serverCapabilities = new Set();
|
|
66
66
|
let backoff = 1000;
|
|
67
67
|
const maxBackoff = opts.maxBackoffMs ?? 30_000;
|
|
68
|
-
// hello 重试跑满仍未 ack 时主动断连重连(破 server 侧连接归属/fence 死锁)。收到 ack 清零;
|
|
69
|
-
// 连续多次仍拿不到 ack 则停手,退回 connected-offline,避免事故期把控制面打成重连风暴。
|
|
70
|
-
const maxUnackedHelloReconnects = 3;
|
|
71
|
-
let unackedHelloReconnects = 0;
|
|
72
68
|
const testShutdown = readTestShutdownConfiguration(process.env);
|
|
73
69
|
const shutdownTimeoutMs = opts.shutdownTimeoutMs ?? testShutdown.timeoutMs ?? 30_000;
|
|
74
70
|
const createWebSocket = opts.createWebSocket ?? ((url) => new WebSocket(url));
|
|
@@ -164,41 +160,7 @@ export function serve(config, opts = {}) {
|
|
|
164
160
|
: configuredIdentity;
|
|
165
161
|
return currentIdentity === undefined ? hello : { ...hello, ...currentIdentity };
|
|
166
162
|
},
|
|
167
|
-
onSent: (hello
|
|
168
|
-
attempt, hostname: hello.hostname, daemon_version: hello.daemonVersion,
|
|
169
|
-
}),
|
|
170
|
-
onSendFailed: (hello, attempt, error) => dslog("daemon.machine_hello_send_failed", "机器 hello 发送失败", {
|
|
171
|
-
level: "WARN", attempt, hostname: hello.hostname, daemon_version: hello.daemonVersion,
|
|
172
|
-
error_message: error instanceof Error ? error.message : String(error),
|
|
173
|
-
}),
|
|
174
|
-
onAck: (hello) => {
|
|
175
|
-
unackedHelloReconnects = 0; // 拿到确认 = 本连接登记成功,清零强制重连计数。
|
|
176
|
-
dslog("daemon.machine_hello_ack_received", "机器 hello 已收到控制面确认", {
|
|
177
|
-
hostname: hello.hostname, daemon_version: hello.daemonVersion,
|
|
178
|
-
});
|
|
179
|
-
},
|
|
180
|
-
// 仅当当前 server 声明支持 ack 才重试;老 server 收不到 ack,重试无意义(退回单次上报)。
|
|
181
|
-
ackSupported: () => serverCapabilities.has(MACHINE_HELLO_ACK_CAPABILITY),
|
|
182
|
-
// 重试跑满仍未 ack → 断开当前连接,靠重连换新连接(新 epoch/token)破 server 侧 fence 死锁。
|
|
183
|
-
onExhausted: (socket) => {
|
|
184
|
-
if (stopped || ws !== socket || socket.readyState !== WebSocket.OPEN)
|
|
185
|
-
return;
|
|
186
|
-
if (unackedHelloReconnects >= maxUnackedHelloReconnects) {
|
|
187
|
-
dslog("daemon.machine_hello_unacked_giveup", "机器 hello 连续多次重连仍未确认,停止强制重连(保持连接,等待下次事件或人工介入)", {
|
|
188
|
-
level: "ERROR", reconnects: unackedHelloReconnects,
|
|
189
|
-
});
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
unackedHelloReconnects += 1;
|
|
193
|
-
// 抖动重连间隔:控制面回滚时多台 daemon 会同时耗尽重试,固定间隔会同步重连造成羊群。
|
|
194
|
-
// close handler 用当前 backoff 排重连,这里注入 1~4s 随机值把各机错峰(open 会再把它复位)。
|
|
195
|
-
const jitteredBackoff = 1_000 + Math.floor(Math.random() * 3_000);
|
|
196
|
-
backoff = Math.min(jitteredBackoff, maxBackoff);
|
|
197
|
-
dslog("daemon.machine_hello_unacked_reconnect", "机器 hello 重试跑满仍未确认,断开重连换新连接", {
|
|
198
|
-
level: "WARN", reconnects: unackedHelloReconnects, backoff_ms: backoff,
|
|
199
|
-
});
|
|
200
|
-
socket.close(1011, "machine hello unacknowledged");
|
|
201
|
-
},
|
|
163
|
+
onSent: (hello) => log(`📤 已上报机器信息: ${hello.hostname} · ${hello.os} · installed=[${hello.runtimes.join(",")}] · executable=[${hello.executionRuntimes.join(",")}] · agents=[${hello.agentHandles.join(",")}]`),
|
|
202
164
|
});
|
|
203
165
|
const machineRuntime = createMachineRuntimeEnvironment({
|
|
204
166
|
config,
|
|
@@ -348,7 +310,6 @@ export function serve(config, opts = {}) {
|
|
|
348
310
|
// 连上了才有机会把离线期间(断连原因/退出前)落盘的日志补传上去
|
|
349
311
|
void drainSpool();
|
|
350
312
|
// 上报本机信息 (hostname/os/daemon 版本/已装 runtimes)
|
|
351
|
-
machineHelloPublisher.attach(openedSocket);
|
|
352
313
|
machineRuntime.open(openedSocket, { capabilities: capabilities.machineHello, beforePublish: Promise.resolve(), connectionId });
|
|
353
314
|
opts.onOpen?.(ws);
|
|
354
315
|
void sendSnapshot(`reconnect-${randomUUID()}`);
|
|
@@ -391,11 +352,6 @@ export function serve(config, opts = {}) {
|
|
|
391
352
|
if (typeof decoded !== "object" || decoded === null)
|
|
392
353
|
return;
|
|
393
354
|
const rawType = "type" in decoded && typeof decoded.type === "string" ? decoded.type : "";
|
|
394
|
-
if (rawType === "machine:hello_ack") {
|
|
395
|
-
const ackSeq = "helloSeq" in decoded && typeof decoded.helloSeq === "number" ? decoded.helloSeq : undefined;
|
|
396
|
-
machineHelloPublisher.acknowledge(connectionSocket, ackSeq);
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
355
|
if (rawType === "machine:environment:get" || rawType === "machine:environment:refresh") {
|
|
400
356
|
await handleMachineEnvironmentFrame(decoded, machineRuntime.provider, sendToConnection);
|
|
401
357
|
return;
|
|
@@ -779,11 +735,6 @@ export function serve(config, opts = {}) {
|
|
|
779
735
|
// ready 帧带 server 视角的 machineId/workspaceId → 作为后续所有日志的默认关联键
|
|
780
736
|
const r = msg;
|
|
781
737
|
setSlogDefaults({ machine_id: r.machineId, workspace_id: r.workspaceId });
|
|
782
|
-
// 旧 server 无此字段 → 空集合(daemon 保持全部旧行为)。ackSupported() 依赖它判断是否重试,
|
|
783
|
-
// 必须在任何 republish() 之前就位;否则本轮 republish 看到空集合→不排重试→整套 ack/重连机制哑火。
|
|
784
|
-
serverCapabilities = new Set(Array.isArray(r.serverCapabilities)
|
|
785
|
-
? r.serverCapabilities.filter((c) => typeof c === "string")
|
|
786
|
-
: []);
|
|
787
738
|
if (opts.storageRuntime !== undefined && typeof r.workspaceId === "string" && typeof r.machineId === "string") {
|
|
788
739
|
const bindingSocket = ws;
|
|
789
740
|
bindStorageServerIdentity(opts.storageRuntime, { workspaceId: r.workspaceId, machineId: r.machineId }, {
|
|
@@ -800,7 +751,10 @@ export function serve(config, opts = {}) {
|
|
|
800
751
|
},
|
|
801
752
|
});
|
|
802
753
|
}
|
|
803
|
-
|
|
754
|
+
// 旧 server 无此字段 → 空集合(daemon 保持全部旧行为)。
|
|
755
|
+
serverCapabilities = new Set(Array.isArray(r.serverCapabilities)
|
|
756
|
+
? r.serverCapabilities.filter((c) => typeof c === "string")
|
|
757
|
+
: []);
|
|
804
758
|
if (serverCapabilities.has(PROJECT_SKILLS_CAPABILITY)) {
|
|
805
759
|
void projectSkillsController.initialize()
|
|
806
760
|
.then(() => projectSkillsController.publishCurrent())
|
|
@@ -1249,7 +1203,6 @@ export function serve(config, opts = {}) {
|
|
|
1249
1203
|
});
|
|
1250
1204
|
connectionSocket.on("close", (code) => {
|
|
1251
1205
|
machineRuntime.close(connectionSocket);
|
|
1252
|
-
machineHelloPublisher.detach(connectionSocket);
|
|
1253
1206
|
if (stopped || ws !== connectionSocket)
|
|
1254
1207
|
return;
|
|
1255
1208
|
// server 能力随连接失效;下个连接的 ready 帧重新声明(防降级重连后沿用过期能力)。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowcrew/daemon",
|
|
3
|
-
"version": "0.6.97
|
|
3
|
+
"version": "0.6.97",
|
|
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
|
+
}
|