@nowcrew/daemon 0.6.88-beta.3 → 0.6.88-beta.31
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 +89 -14
- package/dist/agent-ability/controller.js +11 -1
- package/dist/agent-ability/git-errors.js +22 -0
- package/dist/agent-ability/materializer.js +21 -10
- package/dist/agent-ability/resolver.js +12 -4
- package/dist/agent-environment-contract.js +55 -0
- package/dist/agent-environment-control.js +24 -0
- package/dist/agent-environment-execution.js +98 -0
- package/dist/agent-environments.js +275 -0
- package/dist/agent-memory/policy.js +3 -1
- package/dist/automatic-daemon-installer.js +51 -2
- package/dist/automatic-install-target.js +8 -0
- package/dist/computer-main.js +18 -0
- package/dist/computer-profile.js +17 -4
- package/dist/computer-setup-client.js +318 -0
- package/dist/computer-setup-orchestration.js +203 -0
- package/dist/computer-setup.js +244 -0
- package/dist/config.js +30 -12
- package/dist/console-formatter.js +3 -3
- package/dist/console.js +15 -2
- package/dist/daemon-update-eligibility.js +1 -1
- package/dist/execution-journal.js +9 -6
- package/dist/execution-protocol.js +2 -1
- package/dist/execution-runner.js +16 -10
- package/dist/i18n.js +19 -0
- package/dist/list-models.js +13 -11
- package/dist/local-execution-lease.js +22 -0
- package/dist/local-executor.js +88 -92
- package/dist/local-memory/candidate.js +43 -0
- package/dist/local-memory/index-budget.js +8 -0
- package/dist/local-memory/inventory-cli.js +61 -0
- package/dist/local-memory/inventory-preview.js +159 -0
- package/dist/local-memory/inventory-source.js +159 -0
- package/dist/local-memory/pending-match.js +29 -0
- package/dist/local-memory/pending-query.js +100 -0
- package/dist/local-memory/pending-schema.js +29 -0
- package/dist/local-memory/pending-source.js +126 -0
- package/dist/local-memory/pending.js +34 -84
- package/dist/local-memory/prompt.js +20 -12
- package/dist/local-memory/read-cli.js +97 -12
- package/dist/local-memory/rollout.js +82 -0
- package/dist/local-memory/runtime.js +24 -17
- package/dist/local-memory/work-log-execution.js +31 -0
- package/dist/local-memory/work-log.js +58 -0
- package/dist/local-memory/write.js +27 -58
- package/dist/local-runtime-environment.js +50 -0
- package/dist/machine-environment-cache.js +147 -0
- package/dist/machine-environment-contract.js +10 -0
- package/dist/machine-environment-control.js +27 -0
- package/dist/machine-environment-policy.js +75 -0
- package/dist/machine-environment-process.js +110 -0
- package/dist/machine-info.js +70 -25
- package/dist/machine-runtime-environment.js +189 -0
- package/dist/machine-shell-environment-capture.js +135 -0
- package/dist/machine-windows-environment-capture.js +215 -0
- package/dist/machine-windows-environment-script.js +158 -0
- package/dist/main.js +4 -69
- package/dist/marketplace-controller.js +75 -0
- package/dist/marketplace-protocol.js +38 -0
- package/dist/marketplace-runner.js +234 -0
- package/dist/marketplace-serve.js +17 -0
- package/dist/message-file-preview.js +246 -0
- package/dist/native-thread-context.js +59 -0
- package/dist/pre-admission-rejection.js +64 -0
- package/dist/project-skills/execution-adapter.js +3 -2
- package/dist/project-skills/runtime-launch.js +14 -0
- package/dist/prompt.js +15 -15
- package/dist/provider-env.js +26 -15
- package/dist/runner.js +31 -19
- package/dist/runtime-environment-merge.js +16 -0
- package/dist/runtime-health-handler.js +10 -0
- package/dist/runtime-health.js +3 -1
- package/dist/runtime-path.js +22 -12
- package/dist/runtime-probe.js +35 -6
- package/dist/runtimes/acp-probe-transport.js +69 -0
- package/dist/runtimes/claude-models.js +20 -9
- package/dist/runtimes/claude-session-start-hook.js +24 -0
- package/dist/runtimes/claude-thread-runner.js +266 -0
- package/dist/runtimes/claude.js +23 -4
- package/dist/runtimes/codex-app-server-runner.js +43 -4
- package/dist/runtimes/deepseek-harness-launch.js +10 -0
- package/dist/runtimes/deepseek-harness-profile.js +92 -0
- package/dist/runtimes/deepseek-harness-runner.js +226 -0
- package/dist/runtimes/deepseek-harness.js +76 -15
- package/dist/runtimes/harness-probe-retry.js +42 -0
- package/dist/runtimes/hermes-models.js +2 -1
- package/dist/runtimes/kimi-acp-runner.js +84 -15
- package/dist/runtimes/opencode-runner.js +7 -1
- package/dist/runtimes/opencode.js +2 -2
- package/dist/serve.js +95 -184
- package/dist/server-url.js +25 -0
- package/dist/session.js +4 -0
- package/dist/slog.js +2 -1
- package/dist/storage-identity.js +0 -3
- package/dist/storage-runtime.js +2 -2
- package/dist/storage-serve-adapter.js +6 -72
- package/dist/supervised-runtime.js +28 -18
- package/dist/thread-input-delivery.js +217 -0
- package/dist/token.js +0 -1
- package/dist/workspace-control-handler.js +27 -0
- package/dist/workspace-fs.js +66 -15
- package/dist/workspace.js +1 -1
- package/package.json +5 -4
- package/dist/codex-home-launch.js +0 -7
- package/dist/codex-home-mode-controller.js +0 -68
- package/dist/daemon-migration-controller.js +0 -211
- package/dist/daemon-migration-wiring.js +0 -22
- package/dist/runtimes/codex-home-migration-cli.js +0 -26
- package/dist/runtimes/codex-home-migration.js +0 -112
- package/dist/runtimes/codex-home.js +0 -236
- package/dist/storage-control.js +0 -212
- package/dist/storage-copy.js +0 -628
- package/dist/storage-credential-guard.js +0 -21
- package/dist/storage-doctor.js +0 -228
- package/dist/storage-manifest.js +0 -1027
- package/dist/storage-migration-controller.js +0 -440
- package/dist/storage-migration-manifest.js +0 -105
- package/dist/storage-migration-policy.js +0 -100
- package/dist/storage-runtime-controller.js +0 -381
- package/dist/storage-runtime-readiness.js +0 -240
- package/dist/storage-safe-fs.js +0 -302
- package/dist/storage-status-delivery.js +0 -224
- package/dist/storage-status-replay.js +0 -140
- package/dist/storage-target-confirmation.js +0 -129
- package/dist/storage-worker-command.js +0 -37
- package/dist/storage-worker-executor.js +0 -449
- package/dist/storage-worker-handoff.js +0 -151
- package/dist/storage-worker-operation.js +0 -294
- package/dist/storage-worker-status.js +0 -259
package/dist/serve.js
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/** 常驻控制面桥接;按请求拉起本地 runtime。 */
|
|
2
|
+
import { handleAgentEnvironmentFrame } from "./agent-environment-control.js";
|
|
3
|
+
import { handleMachineEnvironmentFrame } from "./machine-environment-control.js";
|
|
4
|
+
import { createMachineRuntimeEnvironment } from "./machine-runtime-environment.js";
|
|
5
5
|
import { WebSocket } from "ws";
|
|
6
|
+
import { persistPreAdmissionRejection, rejectQueuedAdmission } from "./pre-admission-rejection.js";
|
|
6
7
|
import { join } from "node:path";
|
|
7
8
|
import { randomUUID } from "node:crypto";
|
|
8
9
|
import { dslog, setSlogDefaults, drainSpool, flushSlog } from "./slog.js";
|
|
9
10
|
import { mergeRunAgentResults, reportScheduledStartFailure, runAgent } from "./runner.js";
|
|
10
11
|
import { buildOriginDecisionRetryPrompt, buildScheduledPrompt } from "./prompt.js";
|
|
11
|
-
import {
|
|
12
|
+
import { daemonCapabilities, daemonCapabilityBindings, } from "./machine-info.js";
|
|
12
13
|
import { reconcileExecutionJournal } from "./execution-recovery.js";
|
|
13
14
|
import { initReleaseSlog, reportDaemonConnectionClose, reportReleaseError } from "./release-channel-guard.js";
|
|
14
|
-
import {
|
|
15
|
-
import { listWorkspace, readWorkspaceFile } from "./workspace-fs.js";
|
|
16
|
-
import { listSkills } from "./skills.js";
|
|
15
|
+
import { handleWorkspaceControlRequest } from "./workspace-control-handler.js";
|
|
17
16
|
import { inspectRaftWorkspace, importRaftWorkspace } from "./workspace-import.js";
|
|
18
|
-
import { listRuntimeModels } from "./list-models.js";
|
|
19
17
|
import { normalizeScheduledContext } from "./scheduled-report.js";
|
|
20
18
|
import { formatDaemonLogLine } from "./log-format.js";
|
|
21
19
|
import { reportAgentRunComplete } from "./scheduled-run-report.js";
|
|
@@ -49,12 +47,10 @@ import { createProjectSkillsReconciler, } from "./project-skills/reconciler.js";
|
|
|
49
47
|
import { initializedProjectSkillsReconciler } from "./project-skills/initialized-reconciler.js";
|
|
50
48
|
import { parseMemoryPruneTraceId } from "./memory-prune-diagnostics.js";
|
|
51
49
|
import { probeRuntimeHealth } from "./runtime-health.js";
|
|
52
|
-
import {
|
|
50
|
+
import { createServeMarketplace } from "./marketplace-serve.js";
|
|
53
51
|
import { buildControlPlaneUrl } from "./control-plane-url.js";
|
|
54
|
-
import { createServeMigrationController, handleMigrationControlMessage } from "./daemon-migration-wiring.js";
|
|
55
|
-
import { createCodexHomeModeController } from "./codex-home-mode-controller.js";
|
|
56
52
|
import { resolveDaemonLocalStateRootFromEnv } from "./daemon-local-home.js";
|
|
57
|
-
import {
|
|
53
|
+
import { bindStorageServerIdentity, createStorageIdentityAdmission, } from "./storage-serve-adapter.js";
|
|
58
54
|
export { buildControlPlaneUrl } from "./control-plane-url.js";
|
|
59
55
|
// normalize.ts 的活动种类 → activity 枚举
|
|
60
56
|
const ACTIVITY_MAP = {
|
|
@@ -80,9 +76,6 @@ export function serve(config, opts = {}) {
|
|
|
80
76
|
?? (config.agentMemory === null ? undefined : createAgentMemoryBridge(config.agentMemory));
|
|
81
77
|
const executionTelemetry = createExecutionTelemetryJournal(config.agentsRoot);
|
|
82
78
|
const executeProtocol = opts.execution?.runExecution ?? runExecution;
|
|
83
|
-
let detectedExecutionRuntimes = [], executionRuntimesKnown = false;
|
|
84
|
-
let runtimeFacts = null;
|
|
85
|
-
const runtimeProbe = createRuntimeProbeCoordinator();
|
|
86
79
|
const localHome = opts.localHome ?? resolveDaemonLocalStateRootFromEnv();
|
|
87
80
|
const hostCoordinator = opts.execution?.hostCoordinator
|
|
88
81
|
?? createHostExecutionCoordinator({
|
|
@@ -127,28 +120,14 @@ export function serve(config, opts = {}) {
|
|
|
127
120
|
catch { /* reconnect/timeout reconciliation handles a lost status frame */ }
|
|
128
121
|
},
|
|
129
122
|
});
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
config,
|
|
133
|
-
...(opts.profileName === undefined ? {} : { profileName: opts.profileName }),
|
|
134
|
-
isBusy: () => executionRuns.size > 0 || legacyRuns.size > 0,
|
|
135
|
-
sendStatus: (frame) => { try {
|
|
136
|
-
if (ws?.readyState === WebSocket.OPEN)
|
|
137
|
-
ws.send(JSON.stringify(frame));
|
|
138
|
-
}
|
|
139
|
-
catch { /* reconnect */ } },
|
|
140
|
-
});
|
|
141
|
-
const codexHomeModeController = createCodexHomeModeController({ ...(opts.profileName === undefined ? {} : { profileName: opts.profileName }), scheduleRestart: opts.update?.scheduleRestart ?? scheduleServiceRestart, getServiceSpec: async () => { const eligibility = await updateEligibility(); return eligibility.eligible ? eligibility.serviceSpec : null; }, isBusy: () => executionRuns.size > 0 || legacyRuns.size > 0, sendStatus: (frame) => { try {
|
|
142
|
-
if (ws?.readyState === WebSocket.OPEN)
|
|
143
|
-
ws.send(JSON.stringify(frame));
|
|
144
|
-
}
|
|
145
|
-
catch { /* reconnect */ } } });
|
|
123
|
+
const marketplace = createServeMarketplace(config, localSlots, hostCoordinator);
|
|
124
|
+
const storageIdentityAdmission = createStorageIdentityAdmission(opts.storageRuntime);
|
|
146
125
|
const projectionCoordinator = createAgentProjectionCoordinator();
|
|
147
126
|
const { projectRegistry, projectWorkspaceRegistry, projectDependencyProvisioner } = createProjectRegistryWiring(config.agentsRoot, opts.execution?.dependencies);
|
|
148
127
|
const agentAbilityRuntime = createAgentAbilityRuntime(config.agentsRoot, {
|
|
149
128
|
...opts.agentAbility,
|
|
150
129
|
coordinator: projectionCoordinator,
|
|
151
|
-
isAdmissionClosed:
|
|
130
|
+
isAdmissionClosed: storageIdentityAdmission.isAdmissionClosed,
|
|
152
131
|
});
|
|
153
132
|
let projectSkillsController;
|
|
154
133
|
const projectSkillsReconciler = opts.projectSkills?.reconciler ?? createProjectSkillsReconciler({
|
|
@@ -169,7 +148,7 @@ export function serve(config, opts = {}) {
|
|
|
169
148
|
}
|
|
170
149
|
catch { /* 下一次 ready 或项目操作会重新发送完整快照 */ }
|
|
171
150
|
},
|
|
172
|
-
isAdmissionClosed:
|
|
151
|
+
isAdmissionClosed: storageIdentityAdmission.isAdmissionClosed,
|
|
173
152
|
reconcile: (handle, bindings) => projectSkillsReconciler.reconcile(handle, bindings),
|
|
174
153
|
});
|
|
175
154
|
const logRegistryFailure = (error) => dslog("project_skills.registry_failed", "本机项目注册表读取失败,本次不上报项目清单(能力不受影响)", {
|
|
@@ -177,7 +156,7 @@ export function serve(config, opts = {}) {
|
|
|
177
156
|
});
|
|
178
157
|
const machineHelloPublisher = createMachineHelloPublisher({
|
|
179
158
|
effective: (hello) => {
|
|
180
|
-
const configuredIdentity = opts.
|
|
159
|
+
const configuredIdentity = opts.storageRuntime?.identity;
|
|
181
160
|
const currentIdentity = typeof configuredIdentity === "function"
|
|
182
161
|
? configuredIdentity()
|
|
183
162
|
: configuredIdentity;
|
|
@@ -185,25 +164,19 @@ export function serve(config, opts = {}) {
|
|
|
185
164
|
},
|
|
186
165
|
onSent: (hello) => log(`📤 已上报机器信息: ${hello.hostname} · ${hello.os} · installed=[${hello.runtimes.join(",")}] · executable=[${hello.executionRuntimes.join(",")}] · agents=[${hello.agentHandles.join(",")}]`),
|
|
187
166
|
});
|
|
167
|
+
const machineRuntime = createMachineRuntimeEnvironment({
|
|
168
|
+
config,
|
|
169
|
+
...(opts.machineEnvironment === undefined ? {} : { provider: opts.machineEnvironment }),
|
|
170
|
+
...(opts.machineInfo === undefined ? {} : { machineInfo: opts.machineInfo }),
|
|
171
|
+
...(opts.profileName === undefined ? {} : { profileName: opts.profileName }),
|
|
172
|
+
additionalCapabilities: async () => managedDaemonCapabilities(updateEligibility),
|
|
173
|
+
publish: machineHelloPublisher.publish,
|
|
174
|
+
onError: (code, context) => dslog("execution.runtime_detection_failed", "机器环境或 runtime 探测失败", { level: "ERROR", error_code: code, ...context }),
|
|
175
|
+
});
|
|
176
|
+
machineRuntime.prewarm();
|
|
188
177
|
const initializedProjectSkills = initializedProjectSkillsReconciler(() => projectSkillsController.ensureScanned(), projectSkillsReconciler);
|
|
189
178
|
const configuredCapabilities = opts.machineInfo?.capabilities ?? daemonCapabilities(process.platform);
|
|
190
|
-
const
|
|
191
|
-
const storageStatusDelivery = createServeStorageStatusDelivery(opts.storageMigration, {
|
|
192
|
-
onPersistenceError: (error) => dslog("daemon.storage_status_outbox_failed", "存储迁移状态 outbox 持久化失败", { level: "ERROR", error_message: error.message }),
|
|
193
|
-
transmit: (frame) => { try {
|
|
194
|
-
if (ws?.readyState === WebSocket.OPEN)
|
|
195
|
-
ws.send(JSON.stringify(frame));
|
|
196
|
-
}
|
|
197
|
-
catch { /* retry */ } },
|
|
198
|
-
});
|
|
199
|
-
const storageMigrationRuntime = attachStorageMigrationRuntime(opts.storageMigration, {
|
|
200
|
-
isBusy: () => executionRuns.size > 0 || legacyRuns.size > 0,
|
|
201
|
-
waitForExecutionFrames: () => executionFrameQueue,
|
|
202
|
-
flushLocalState: flushSlog,
|
|
203
|
-
sendStatus: storageStatusDelivery.send,
|
|
204
|
-
});
|
|
205
|
-
storageMigrationAdmissionClosed = storageMigrationRuntime.isAdmissionClosed;
|
|
206
|
-
const prepareCapabilities = async () => daemonCapabilityBindings(process.platform, [...storageCapabilities, ...await managedDaemonCapabilities(updateEligibility)]);
|
|
179
|
+
const prepareCapabilities = async () => daemonCapabilityBindings(process.platform, [...configuredCapabilities, ...await managedDaemonCapabilities(updateEligibility)]);
|
|
207
180
|
const safeExecutionSend = (frame) => {
|
|
208
181
|
try {
|
|
209
182
|
if (ws?.readyState !== WebSocket.OPEN)
|
|
@@ -237,6 +210,11 @@ export function serve(config, opts = {}) {
|
|
|
237
210
|
return;
|
|
238
211
|
}
|
|
239
212
|
safeExecutionSend(frame);
|
|
213
|
+
if (frame.type === "execution:rejected" && frame.preAdmissionProof) {
|
|
214
|
+
const entry = await executionJournal.get(frame.executionId);
|
|
215
|
+
if (entry?.completion)
|
|
216
|
+
completionRetransmitter.track(entry.completion);
|
|
217
|
+
}
|
|
240
218
|
};
|
|
241
219
|
const replayExecutionTelemetry = async () => {
|
|
242
220
|
const frames = await executionTelemetry.replay();
|
|
@@ -312,67 +290,29 @@ export function serve(config, opts = {}) {
|
|
|
312
290
|
if (stopped)
|
|
313
291
|
return;
|
|
314
292
|
const wsUrl = (opts.buildControlPlaneUrl ?? buildControlPlaneUrl)(config.serverUrl, config.machineToken, process.platform, undefined, capabilities.controlPlaneUrl);
|
|
315
|
-
|
|
293
|
+
const connectionSocket = createWebSocket(wsUrl);
|
|
294
|
+
ws = connectionSocket;
|
|
295
|
+
const sendToConnection = (frame) => {
|
|
296
|
+
try {
|
|
297
|
+
if (!stopped && ws === connectionSocket && connectionSocket.readyState === WebSocket.OPEN)
|
|
298
|
+
connectionSocket.send(JSON.stringify(frame));
|
|
299
|
+
}
|
|
300
|
+
catch { /* 旧连接请求由服务端超时处理。 */ }
|
|
301
|
+
};
|
|
316
302
|
let connectionEpochToken;
|
|
317
|
-
|
|
303
|
+
connectionSocket.on("open", () => {
|
|
318
304
|
connectionEpochToken = projectSkillsController.beginConnectionEpoch();
|
|
319
|
-
|
|
320
|
-
const openedSocket =
|
|
305
|
+
storageIdentityAdmission.beginIdentityBinding();
|
|
306
|
+
const openedSocket = connectionSocket;
|
|
307
|
+
const connectionId = randomUUID();
|
|
321
308
|
backoff = 1000;
|
|
322
309
|
connectedAt = Date.now();
|
|
323
310
|
log(`🔌 已连接控制面 ${config.serverUrl}`);
|
|
324
|
-
dslog("daemon.ws_open", "已连接控制面", { server_url: config.serverUrl });
|
|
311
|
+
dslog("daemon.ws_open", "已连接控制面", { server_url: config.serverUrl, connection_id: connectionId });
|
|
325
312
|
// 连上了才有机会把离线期间(断连原因/退出前)落盘的日志补传上去
|
|
326
313
|
void drainSpool();
|
|
327
314
|
// 上报本机信息 (hostname/os/daemon 版本/已装 runtimes)
|
|
328
|
-
|
|
329
|
-
const storageReplay = replayStorageMigrationStatus(opts.storageMigration, openedSocket, () => ws === openedSocket, (error) => {
|
|
330
|
-
dslog("daemon.storage_status_replay_failed", "存储迁移状态重放失败", {
|
|
331
|
-
level: "ERROR", error_message: error.message,
|
|
332
|
-
});
|
|
333
|
-
}, storageStatusDelivery.send);
|
|
334
|
-
const { detectInstalled, detectExecutable = detectExecutionRuntimesWithSignal } = opts.machineInfo ?? {};
|
|
335
|
-
const helloPromise = (opts.machineInfo?.collect ?? collectMachineHello)(config.agentsRoot, config.executionLimits, process.platform, {
|
|
336
|
-
...(detectInstalled ? { detectInstalled } : {}),
|
|
337
|
-
...(opts.profileName === undefined ? {} : { profileName: opts.profileName }),
|
|
338
|
-
// First hello must not wait for third-party handshakes; optional transports arrive in the refresh.
|
|
339
|
-
detectExecutable: async (installed) => conservativeExecutionRuntimes(installed),
|
|
340
|
-
additionalCapabilities: async () => [...(await managedDaemonCapabilities(updateEligibility)), ...(opts.profileName === undefined ? [] : ["codex_home_mode_v1"])],
|
|
341
|
-
capabilities: capabilities.machineHello,
|
|
342
|
-
codexHomeMode: config.codexHomeMode,
|
|
343
|
-
});
|
|
344
|
-
runtimeFacts = helloPromise
|
|
345
|
-
.then(async (hello) => {
|
|
346
|
-
if (hello.executionProtocol === undefined) {
|
|
347
|
-
executionRuntimesKnown = true;
|
|
348
|
-
return [];
|
|
349
|
-
}
|
|
350
|
-
const detected = await runtimeProbe.detect(hello.runtimes, detectExecutable);
|
|
351
|
-
executionRuntimesKnown = true;
|
|
352
|
-
await storageReplay;
|
|
353
|
-
if (ws === openedSocket && openedSocket.readyState === WebSocket.OPEN
|
|
354
|
-
&& detected.some((runtime) => !hello.executionRuntimes.includes(runtime))) {
|
|
355
|
-
detectedExecutionRuntimes = detected;
|
|
356
|
-
machineHelloPublisher.publish({ ...hello, executionRuntimes: [...detected] }, openedSocket);
|
|
357
|
-
}
|
|
358
|
-
return detected;
|
|
359
|
-
})
|
|
360
|
-
.catch((error) => {
|
|
361
|
-
executionRuntimesKnown = true;
|
|
362
|
-
dslog("execution.runtime_detection_failed", "runtime 探测失败", {
|
|
363
|
-
level: "ERROR", error_message: error.message,
|
|
364
|
-
});
|
|
365
|
-
return [];
|
|
366
|
-
});
|
|
367
|
-
void helloPromise
|
|
368
|
-
.then(async (hello) => {
|
|
369
|
-
await storageReplay;
|
|
370
|
-
if (ws !== openedSocket || openedSocket.readyState !== WebSocket.OPEN)
|
|
371
|
-
return;
|
|
372
|
-
detectedExecutionRuntimes = hello.executionRuntimes;
|
|
373
|
-
machineHelloPublisher.publish(hello, openedSocket);
|
|
374
|
-
})
|
|
375
|
-
.catch(() => { });
|
|
315
|
+
machineRuntime.open(openedSocket, { capabilities: capabilities.machineHello, beforePublish: Promise.resolve(), connectionId });
|
|
376
316
|
opts.onOpen?.(ws);
|
|
377
317
|
void sendSnapshot(`reconnect-${randomUUID()}`);
|
|
378
318
|
void executionJournal.replay()
|
|
@@ -401,8 +341,8 @@ export function serve(config, opts = {}) {
|
|
|
401
341
|
});
|
|
402
342
|
});
|
|
403
343
|
});
|
|
404
|
-
|
|
405
|
-
if (stopped)
|
|
344
|
+
connectionSocket.on("message", async (data) => {
|
|
345
|
+
if (stopped || ws !== connectionSocket)
|
|
406
346
|
return;
|
|
407
347
|
let decoded;
|
|
408
348
|
try {
|
|
@@ -414,8 +354,10 @@ export function serve(config, opts = {}) {
|
|
|
414
354
|
if (typeof decoded !== "object" || decoded === null)
|
|
415
355
|
return;
|
|
416
356
|
const rawType = "type" in decoded && typeof decoded.type === "string" ? decoded.type : "";
|
|
417
|
-
if (
|
|
357
|
+
if (rawType === "machine:environment:get" || rawType === "machine:environment:refresh") {
|
|
358
|
+
await handleMachineEnvironmentFrame(decoded, machineRuntime.provider, sendToConnection);
|
|
418
359
|
return;
|
|
360
|
+
}
|
|
419
361
|
if (rawType === "daemon:update" || rawType === "daemon:restart") {
|
|
420
362
|
void updateController.handle(decoded).catch((error) => {
|
|
421
363
|
dslog("daemon.control_failed", "daemon 控制操作处理失败", {
|
|
@@ -424,19 +366,6 @@ export function serve(config, opts = {}) {
|
|
|
424
366
|
});
|
|
425
367
|
return;
|
|
426
368
|
}
|
|
427
|
-
if (rawType === "daemon:migrate") {
|
|
428
|
-
void handleMigrationControlMessage(migrationController, decoded).catch((error) => dslog("daemon.migration_failed", "daemon 布局迁移失败", { level: "ERROR", error_message: error.message }));
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
if (rawType === "daemon:codex-home-mode") {
|
|
432
|
-
void codexHomeModeController.handle(decoded).catch((error) => dslog("daemon.codex_home_mode_failed", "Codex Home 模式切换失败", { level: "ERROR", error_message: error.message }));
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
if (handleStorageMigrationControl(opts.storageMigration, rawType, decoded, storageStatusDelivery.send, (kind, error) => {
|
|
436
|
-
dslog(kind === "migration" ? "daemon.storage_migration_failed" : "daemon.storage_migration_confirmation_failed", kind === "migration" ? "存储迁移控制操作失败" : "存储迁移 hello 确认处理失败", { level: "ERROR", error_message: error.message });
|
|
437
|
-
})) {
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
369
|
if (rawType.startsWith("execution:")) {
|
|
441
370
|
const parsedExecution = ServerToDaemonExecutionFrameSchema.safeParse(decoded);
|
|
442
371
|
if (!parsedExecution.success) {
|
|
@@ -498,10 +427,10 @@ export function serve(config, opts = {}) {
|
|
|
498
427
|
return;
|
|
499
428
|
}
|
|
500
429
|
const spec = frame;
|
|
501
|
-
if (
|
|
430
|
+
if (storageIdentityAdmission.isAdmissionClosed()) {
|
|
502
431
|
safeExecutionSend(ExecutionRejectedSchema.parse({
|
|
503
432
|
type: "execution:rejected", protocolVersion: 1, executionId: spec.executionId,
|
|
504
|
-
reason: "resource_limit", message: "Storage
|
|
433
|
+
reason: "resource_limit", message: "Storage identity binding is not complete",
|
|
505
434
|
at: new Date().toISOString(),
|
|
506
435
|
}));
|
|
507
436
|
return;
|
|
@@ -560,18 +489,8 @@ export function serve(config, opts = {}) {
|
|
|
560
489
|
: spec.context.scheduledRunId === undefined ? "normal" : "scheduled";
|
|
561
490
|
let reservation = sharedSlots.reserve(spec.agent.handle, "execution", executionClass);
|
|
562
491
|
if (!reservation.accepted) {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
execution_id: spec.executionId,
|
|
566
|
-
agent_handle: spec.agent.handle,
|
|
567
|
-
execution_class: executionClass,
|
|
568
|
-
...reservation.facts,
|
|
569
|
-
});
|
|
570
|
-
safeExecutionSend(ExecutionRejectedSchema.parse({
|
|
571
|
-
type: "execution:rejected", protocolVersion: 1, executionId: spec.executionId,
|
|
572
|
-
reason: "resource_limit", message: "Local machine execution queue is full",
|
|
573
|
-
at: new Date().toISOString(),
|
|
574
|
-
}));
|
|
492
|
+
await rejectQueuedAdmission({ journal: executionJournal, knownExecutionHashes, executionRuns,
|
|
493
|
+
report: reportExecutionFrame, replay: sendJournalStatus }, spec, executionClass, reservation.facts);
|
|
575
494
|
return;
|
|
576
495
|
}
|
|
577
496
|
knownExecutionHashes.set(spec.executionId, hash);
|
|
@@ -710,9 +629,7 @@ export function serve(config, opts = {}) {
|
|
|
710
629
|
let availableRuntimes;
|
|
711
630
|
try {
|
|
712
631
|
availableRuntimes = opts.execution?.availableRuntimes?.()
|
|
713
|
-
??
|
|
714
|
-
? detectedExecutionRuntimes
|
|
715
|
-
: await (runtimeFacts ?? Promise.resolve(detectedExecutionRuntimes)));
|
|
632
|
+
?? await machineRuntime.availableRuntimes(spec.runtime.name);
|
|
716
633
|
}
|
|
717
634
|
catch (error) {
|
|
718
635
|
cleanupExecutionReservation("runtime_detection_failed");
|
|
@@ -729,6 +646,7 @@ export function serve(config, opts = {}) {
|
|
|
729
646
|
}
|
|
730
647
|
const execution = executeProtocol(config, spec, {
|
|
731
648
|
...opts.execution?.dependencies,
|
|
649
|
+
machineEnvironment: machineRuntime.provider,
|
|
732
650
|
capabilities: capabilities.executionRunner,
|
|
733
651
|
projectSkills: opts.execution?.dependencies?.projectSkills ?? initializedProjectSkills,
|
|
734
652
|
abilityRelease: opts.execution?.dependencies?.abilityRelease ?? agentAbilityRuntime.materializer,
|
|
@@ -741,6 +659,13 @@ export function serve(config, opts = {}) {
|
|
|
741
659
|
...reservation.facts,
|
|
742
660
|
},
|
|
743
661
|
report: reportExecutionFrame,
|
|
662
|
+
confirmPreAdmission: async (rejection) => {
|
|
663
|
+
const prior = await executionJournal.get(spec.executionId);
|
|
664
|
+
if (prior !== null || stopped || knownExecutionHashes.get(spec.executionId) !== hash
|
|
665
|
+
|| executionRuns.get(spec.executionId) !== execution)
|
|
666
|
+
return false;
|
|
667
|
+
return await persistPreAdmissionRejection(executionJournal, spec, rejection) !== null;
|
|
668
|
+
},
|
|
744
669
|
startupGate: runtimeStartupGate,
|
|
745
670
|
startupTimeoutMs: config.executionLimits.startupTimeoutMs,
|
|
746
671
|
onRuntimePhase: (phase, runtime) => {
|
|
@@ -812,17 +737,17 @@ export function serve(config, opts = {}) {
|
|
|
812
737
|
// ready 帧带 server 视角的 machineId/workspaceId → 作为后续所有日志的默认关联键
|
|
813
738
|
const r = msg;
|
|
814
739
|
setSlogDefaults({ machine_id: r.machineId, workspace_id: r.workspaceId });
|
|
815
|
-
if (opts.
|
|
740
|
+
if (opts.storageRuntime !== undefined && typeof r.workspaceId === "string" && typeof r.machineId === "string") {
|
|
816
741
|
const bindingSocket = ws;
|
|
817
|
-
|
|
742
|
+
bindStorageServerIdentity(opts.storageRuntime, { workspaceId: r.workspaceId, machineId: r.machineId }, {
|
|
818
743
|
onBound: () => {
|
|
819
744
|
if (bindingSocket !== ws || bindingSocket?.readyState !== WebSocket.OPEN)
|
|
820
745
|
return;
|
|
821
|
-
|
|
746
|
+
storageIdentityAdmission.completeIdentityBinding();
|
|
822
747
|
machineHelloPublisher.republish();
|
|
823
748
|
},
|
|
824
749
|
onError: (error) => {
|
|
825
|
-
dslog("daemon.storage_identity_bind_failed", "
|
|
750
|
+
dslog("daemon.storage_identity_bind_failed", "存储 Workspace 身份绑定失败", { level: "ERROR", error_message: error.message });
|
|
826
751
|
if (bindingSocket === ws && bindingSocket?.readyState === WebSocket.OPEN)
|
|
827
752
|
bindingSocket.close(1011, "storage identity binding failed");
|
|
828
753
|
},
|
|
@@ -867,15 +792,17 @@ export function serve(config, opts = {}) {
|
|
|
867
792
|
return;
|
|
868
793
|
}
|
|
869
794
|
if (msg.type === "runtime-health:probe") {
|
|
870
|
-
const result = await
|
|
795
|
+
const result = await machineRuntime.health(msg, opts.runtimeHealth?.probe);
|
|
871
796
|
if (result !== null) {
|
|
872
|
-
|
|
873
|
-
ws?.send(JSON.stringify({ type: "fs:result", ...result }));
|
|
874
|
-
}
|
|
875
|
-
catch { /* server 会超时 */ }
|
|
797
|
+
sendToConnection({ type: "fs:result", ...result });
|
|
876
798
|
}
|
|
877
799
|
return;
|
|
878
800
|
}
|
|
801
|
+
if (marketplace.handle(msg, frame => { try {
|
|
802
|
+
ws?.send(JSON.stringify(frame));
|
|
803
|
+
}
|
|
804
|
+
catch { /* server 会按请求超时处理 */ } }))
|
|
805
|
+
return;
|
|
879
806
|
if (await agentAbilityRuntime.tryHandleControlMessage(msg, serverCapabilities, (frame) => ws?.send(JSON.stringify(frame))))
|
|
880
807
|
return;
|
|
881
808
|
// 导入 raft agent 工作区:inspect 反填 name/description;import 复制用户内容
|
|
@@ -901,31 +828,16 @@ export function serve(config, opts = {}) {
|
|
|
901
828
|
}
|
|
902
829
|
return;
|
|
903
830
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
try {
|
|
910
|
-
ws?.send(JSON.stringify({ type: "fs:result", reqId: req.reqId, ...r }));
|
|
911
|
-
}
|
|
912
|
-
catch { /* 忽略 */ }
|
|
913
|
-
};
|
|
914
|
-
try {
|
|
915
|
-
const data2 = req.type === "fs:list" ? await listWorkspace(root, req.path)
|
|
916
|
-
: req.type === "fs:read" ? await readWorkspaceFile(root, req.path)
|
|
917
|
-
: req.type === "skills:list" ? await listSkills(req.runtime)
|
|
918
|
-
: { models: await listRuntimeModels(req.type === "probe-models" ? (req.runtime ?? "") : "") };
|
|
919
|
-
reply({ ok: true, data: data2 });
|
|
920
|
-
}
|
|
921
|
-
catch (e) {
|
|
922
|
-
reply({ ok: false, error: e.message });
|
|
923
|
-
}
|
|
831
|
+
if (await handleAgentEnvironmentFrame(msg, config.agentsRoot, sendToConnection))
|
|
832
|
+
return;
|
|
833
|
+
const fileResult = await handleWorkspaceControlRequest(msg, config.agentsRoot, projectWorkspaceRegistry, machineRuntime.models);
|
|
834
|
+
if (fileResult) {
|
|
835
|
+
sendToConnection(fileResult);
|
|
924
836
|
return;
|
|
925
837
|
}
|
|
926
838
|
if (msg.type !== "agent:start")
|
|
927
839
|
return; // ready/error 等忽略
|
|
928
|
-
if (
|
|
840
|
+
if (storageIdentityAdmission.isAdmissionClosed())
|
|
929
841
|
return;
|
|
930
842
|
// 任务键:scheduled run 用 runId(每次运行独立 cwd/work-log;overlap 由 server 端 skip_if_running 管,
|
|
931
843
|
// daemon 的 running 去重只兜底"同一 run 重复投递");普通唤醒仍是 线程锚点 ?? 频道。
|
|
@@ -1090,15 +1002,14 @@ export function serve(config, opts = {}) {
|
|
|
1090
1002
|
const ackHint = `\n**协作礼仪:决定接手后,先用 \`${sendCmd}\` 在该任务线程说一声你来跟进**——用日常语言带上你对问题的理解或打算先查什么,不要写"我接 task #N"这类内部编号;写不出实质内容就不单发,并进第一条实质进展,但不要长时间闷头干活把线程空着。`;
|
|
1091
1003
|
// 图片/文件附件:crew message read 会在消息下列出附件及其 id;图片需下载后用 Read 工具查看,才能真正"看到"内容。
|
|
1092
1004
|
const attHint = `\n若消息带图片/文件附件(read 会列出 id),用 \`crew attachment get <id>\` 下载到本地,图片再用 Read 工具打开查看后再处理。`;
|
|
1093
|
-
//
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
: `crew message read --channel ${msg.channelId}`;
|
|
1005
|
+
// 启动上下文由执行层交付;legacy 提示词也不能要求模型补读或退回频道历史。
|
|
1006
|
+
const contextHint = threadId
|
|
1007
|
+
? "直接依据程序交付的本线程上下文与新消息处理,无需启动补读历史。"
|
|
1008
|
+
: "没有线程锚点,只处理明确来信或请求补充当前任务线程,不读取频道历史猜测。";
|
|
1098
1009
|
const wakeText = scheduled
|
|
1099
1010
|
? buildScheduledPrompt(msg.channelId, msg.wake?.content ?? "", scheduled.outputPolicy, scheduled.externalNotificationPolicy)
|
|
1100
1011
|
: (msg.wake?.content
|
|
1101
|
-
? `你被唤醒(${msg.reason}): ${msg.wake.content}\n
|
|
1012
|
+
? `你被唤醒(${msg.reason}): ${msg.wake.content}\n${contextHint}${reasonHint}${ackHint}${threadHint}${attHint}`
|
|
1102
1013
|
: undefined);
|
|
1103
1014
|
const wakeOrigin = scheduled ? undefined : msg.wake?.origin;
|
|
1104
1015
|
const guarded = await runWithOriginDecisionGuard(wakeOrigin, async (attempt) => {
|
|
@@ -1124,11 +1035,12 @@ export function serve(config, opts = {}) {
|
|
|
1124
1035
|
},
|
|
1125
1036
|
} : {}),
|
|
1126
1037
|
...(wakeOrigin ? { wakeOrigin, originDecisionAttempt: attempt } : {}),
|
|
1127
|
-
//
|
|
1128
|
-
...(!scheduled && threadId ? { wakeMessageId: threadId } : {}),
|
|
1038
|
+
// legacy wake.threadId 已由 Server 归一到线程根;与普通触发消息 id 分开透传。
|
|
1039
|
+
...(!scheduled && threadId ? { threadId, wakeMessageId: threadId } : {}),
|
|
1129
1040
|
...(!scheduled && msg.wake?.seq !== undefined ? { wakeContextUpToSeq: msg.wake.seq } : {}),
|
|
1130
1041
|
...(attemptWake ? { wake: attemptWake } : {}),
|
|
1131
1042
|
}, reportActivity, reportConsole, {
|
|
1043
|
+
machineEnvironment: machineRuntime.provider,
|
|
1132
1044
|
cancellation: controller.cancellation,
|
|
1133
1045
|
startupGate: runtimeStartupGate,
|
|
1134
1046
|
startupTimeoutMs: config.executionLimits.startupTimeoutMs,
|
|
@@ -1291,8 +1203,9 @@ export function serve(config, opts = {}) {
|
|
|
1291
1203
|
void flushSlog(); // 每轮收尾冲一次,保证 run.end 尽快可查
|
|
1292
1204
|
}
|
|
1293
1205
|
});
|
|
1294
|
-
|
|
1295
|
-
|
|
1206
|
+
connectionSocket.on("close", (code) => {
|
|
1207
|
+
machineRuntime.close(connectionSocket);
|
|
1208
|
+
if (stopped || ws !== connectionSocket)
|
|
1296
1209
|
return;
|
|
1297
1210
|
// server 能力随连接失效;下个连接的 ready 帧重新声明(防降级重连后沿用过期能力)。
|
|
1298
1211
|
serverCapabilities = new Set();
|
|
@@ -1316,9 +1229,9 @@ export function serve(config, opts = {}) {
|
|
|
1316
1229
|
}, backoff);
|
|
1317
1230
|
backoff = Math.min(backoff * 2, maxBackoff);
|
|
1318
1231
|
});
|
|
1319
|
-
|
|
1232
|
+
connectionSocket.on("error", () => {
|
|
1320
1233
|
if (!stopped)
|
|
1321
|
-
|
|
1234
|
+
connectionSocket.close();
|
|
1322
1235
|
});
|
|
1323
1236
|
}
|
|
1324
1237
|
const ready = (async () => {
|
|
@@ -1356,9 +1269,7 @@ export function serve(config, opts = {}) {
|
|
|
1356
1269
|
stopPromise = (async () => {
|
|
1357
1270
|
stopped = true;
|
|
1358
1271
|
concurrencyTelemetry.stop();
|
|
1359
|
-
runtimeProbe.stop();
|
|
1360
1272
|
completionRetransmitter.stop();
|
|
1361
|
-
storageStatusDelivery.stop();
|
|
1362
1273
|
const deadline = createShutdownDeadline(shutdownTimeoutMs);
|
|
1363
1274
|
if (reconnectTimer !== null) {
|
|
1364
1275
|
clearTimeout(reconnectTimer);
|
|
@@ -1366,10 +1277,10 @@ export function serve(config, opts = {}) {
|
|
|
1366
1277
|
}
|
|
1367
1278
|
const webSocketClosed = closeWebSocketWithinDeadline(ws, deadline.signal);
|
|
1368
1279
|
const pending = [
|
|
1280
|
+
machineRuntime.stop(),
|
|
1369
1281
|
webSocketClosed,
|
|
1370
1282
|
updateController.drain(),
|
|
1371
|
-
|
|
1372
|
-
codexHomeModeController.drain(),
|
|
1283
|
+
marketplace.stop(),
|
|
1373
1284
|
executionFrameQueue,
|
|
1374
1285
|
...executionRuns.values(),
|
|
1375
1286
|
...[...legacyRuns.values()].map((run) => run.done),
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const CANONICAL_PRODUCTION_HOST = "nowwork.nowcoder.com";
|
|
2
|
+
const PRODUCTION_HOST_ALIASES = new Set([
|
|
3
|
+
CANONICAL_PRODUCTION_HOST,
|
|
4
|
+
"nowwork-in.nowcoder.com",
|
|
5
|
+
]);
|
|
6
|
+
function canonicalHostname(hostname) {
|
|
7
|
+
const normalized = hostname.toLowerCase();
|
|
8
|
+
return isProductionServerHostname(normalized) ? CANONICAL_PRODUCTION_HOST : normalized;
|
|
9
|
+
}
|
|
10
|
+
export function isProductionServerHostname(hostname) {
|
|
11
|
+
return PRODUCTION_HOST_ALIASES.has(hostname.toLowerCase());
|
|
12
|
+
}
|
|
13
|
+
/** Host identity used by profile/service guards; the public and internal production names are aliases. */
|
|
14
|
+
export function serverHostIdentity(serverUrl) {
|
|
15
|
+
return canonicalHostname(new URL(serverUrl).hostname);
|
|
16
|
+
}
|
|
17
|
+
/** URL identity used by storage records; preserve path/port/query while collapsing production host aliases. */
|
|
18
|
+
export function serverUrlIdentity(serverUrl) {
|
|
19
|
+
const parsed = new URL(serverUrl);
|
|
20
|
+
parsed.hostname = canonicalHostname(parsed.hostname);
|
|
21
|
+
return parsed.toString().replace(/\/+$/u, "");
|
|
22
|
+
}
|
|
23
|
+
export function serverUrlsMatch(left, right) {
|
|
24
|
+
return serverUrlIdentity(left) === serverUrlIdentity(right);
|
|
25
|
+
}
|
package/dist/session.js
CHANGED
|
@@ -24,6 +24,10 @@ export async function readSession(runDir) {
|
|
|
24
24
|
if (typeof o.sessionId !== "string" || !o.sessionId)
|
|
25
25
|
return null;
|
|
26
26
|
return {
|
|
27
|
+
...(typeof o.runtime === "string" ? { runtime: o.runtime } : {}),
|
|
28
|
+
...(typeof o.threadRoot === "string" ? { threadRoot: o.threadRoot } : {}),
|
|
29
|
+
...(Number.isSafeInteger(o.threadContextSeq) && o.threadContextSeq >= 0 ? { threadContextSeq: o.threadContextSeq } : {}),
|
|
30
|
+
...(typeof o.threadHistoryComplete === "boolean" ? { threadHistoryComplete: o.threadHistoryComplete } : {}),
|
|
27
31
|
sessionId: o.sessionId,
|
|
28
32
|
lastRunAt: typeof o.lastRunAt === "number" ? o.lastRunAt : 0,
|
|
29
33
|
turns: typeof o.turns === "number" ? o.turns : 0,
|
package/dist/slog.js
CHANGED
|
@@ -16,6 +16,7 @@ import { join, resolve } from "node:path";
|
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
17
17
|
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, unlinkSync } from "node:fs";
|
|
18
18
|
import { resolveDaemonLocalStateRoot } from "./daemon-local-home.js";
|
|
19
|
+
import { isProductionServerHostname } from "./server-url.js";
|
|
19
20
|
const FLUSH_INTERVAL_MS = 1500;
|
|
20
21
|
const BATCH_SIZE = 50;
|
|
21
22
|
const SPOOL_MAX_FILES = 50; // spool 目录文件数上限,超出丢最旧(日志非关键数据,防无限膨胀)
|
|
@@ -30,7 +31,7 @@ let lastErrorAt = 0;
|
|
|
30
31
|
let exitHookInstalled = false;
|
|
31
32
|
let localStateRoot;
|
|
32
33
|
function deploymentEnvironment(serverHost) {
|
|
33
|
-
if (serverHost
|
|
34
|
+
if (serverHost !== undefined && isProductionServerHostname(serverHost))
|
|
34
35
|
return "prod";
|
|
35
36
|
if (serverHost === "nowwork-dev.nowcoder.com")
|
|
36
37
|
return "dev";
|
package/dist/storage-identity.js
CHANGED
|
@@ -39,8 +39,5 @@ export function storageHelloIdentity(input) {
|
|
|
39
39
|
daemonRootFingerprint: fingerprint("daemon-root", layout.daemonRoot),
|
|
40
40
|
agentRootFingerprint: fingerprint("agent-root", layout.agentItemsRoot),
|
|
41
41
|
...(ownership === undefined ? {} : { storageOwnership: ownership }),
|
|
42
|
-
...(installation.storageMigrationId === undefined
|
|
43
|
-
? {}
|
|
44
|
-
: { storageMigrationId: installation.storageMigrationId }),
|
|
45
42
|
});
|
|
46
43
|
}
|
package/dist/storage-runtime.js
CHANGED
|
@@ -2,12 +2,12 @@ import { findInstallationForProfile, readInstallations, resolveLocalStorageRoots
|
|
|
2
2
|
import { storageHelloIdentity } from "./storage-identity.js";
|
|
3
3
|
import { storageLayout } from "./storage-layout.js";
|
|
4
4
|
import { readStorageOwnershipClaim, resolveWorkspaceStorageOwnershipClaim, } from "./storage-ownership.js";
|
|
5
|
-
|
|
5
|
+
import { serverUrlsMatch } from "./server-url.js";
|
|
6
6
|
export function resolveStorageRuntime(input) {
|
|
7
7
|
const installation = findInstallationForProfile(input.records, input.profile);
|
|
8
8
|
if (installation === null)
|
|
9
9
|
return null;
|
|
10
|
-
if (
|
|
10
|
+
if (!serverUrlsMatch(installation.serverUrl, input.serverUrl)) {
|
|
11
11
|
throw new Error("installation server identity does not match the active profile");
|
|
12
12
|
}
|
|
13
13
|
const local = resolveLocalStorageRoots({
|