@nowcrew/daemon 0.6.97 → 0.6.98-beta.2
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 +0 -7
- package/dist/automatic-service-migration.js +7 -6
- package/dist/cloud-report-upload.js +1 -10
- package/dist/computer-main.js +0 -0
- package/dist/computer-service.js +40 -42
- package/dist/computer-setup-client.js +5 -2
- package/dist/execution-journal.js +3 -1
- package/dist/execution-protocol.js +1 -1
- package/dist/execution-runner.js +4 -1
- package/dist/local-execution-prompt.js +8 -3
- package/dist/local-executor.js +63 -39
- package/dist/local-memory/commit-telemetry.js +30 -0
- package/dist/local-memory/execution-workspace.js +62 -0
- package/dist/local-memory/full-index-search.js +47 -0
- package/dist/local-memory/index-budget.js +9 -3
- package/dist/local-memory/initialization-identity.js +36 -0
- package/dist/local-memory/inventory-cli.js +52 -8
- package/dist/local-memory/inventory-source.js +15 -8
- package/dist/local-memory/inventory-v2.js +362 -0
- package/dist/local-memory/legacy-adapter.js +233 -0
- package/dist/local-memory/migration-access.js +242 -0
- package/dist/local-memory/migration-cli.js +54 -0
- package/dist/local-memory/migration-io.js +199 -0
- package/dist/local-memory/migration-pending.js +9 -0
- package/dist/local-memory/migration-plan.js +432 -0
- package/dist/local-memory/migration-schema.js +55 -0
- package/dist/local-memory/migration-state-invariants.js +65 -0
- package/dist/local-memory/migration-store.js +414 -0
- package/dist/local-memory/migration-tool-entry.js +21 -0
- package/dist/local-memory/pending-query.js +5 -2
- package/dist/local-memory/pending-schema.js +1 -1
- package/dist/local-memory/pending.js +16 -2
- package/dist/local-memory/prompt.js +21 -5
- package/dist/local-memory/read-cli.js +98 -76
- package/dist/local-memory/rollout.js +79 -11
- package/dist/local-memory/runtime.js +181 -13
- package/dist/local-memory/source-path.js +13 -0
- package/dist/local-memory/storage-format.js +152 -0
- package/dist/local-memory/write.js +189 -21
- package/dist/local-memory/writer-mode.js +13 -0
- package/dist/local-memory-diagnostics.js +94 -13
- package/dist/local-memory-telemetry.js +19 -2
- package/dist/machine-info.js +5 -0
- package/dist/main.js +0 -0
- package/dist/marketplace-protocol.js +1 -1
- package/dist/marketplace-remote.js +1 -1
- package/dist/marketplace-runner.js +1 -1
- package/dist/memory-migration-controller.js +89 -0
- package/dist/memory-migration-inspect.js +108 -0
- package/dist/memory-migration-journal.js +14 -0
- package/dist/memory-migration-protocol.js +14 -0
- package/dist/memory-migration-runtime.js +305 -0
- package/dist/memory-prune-diagnostics.js +60 -4
- package/dist/message-file-preview.js +11 -1
- package/dist/npm-command.js +5 -5
- package/dist/powershell-command.js +12 -0
- package/dist/project-skills/machine-hello-publisher.js +95 -6
- package/dist/prompt.js +6 -2
- package/dist/provider-env.js +3 -8
- package/dist/runner.js +1 -1
- package/dist/runtimes/claude-thread-runner.js +25 -4
- package/dist/runtimes/codex-app-server-runner.js +0 -2
- package/dist/runtimes/codex.js +0 -2
- package/dist/serve.js +91 -9
- package/dist/token.js +1 -0
- package/dist/windows-scheduled-task.js +3 -3
- package/dist/windows-task-principal.js +26 -0
- package/dist/workspace-control-handler.js +16 -3
- package/dist/workspace.js +13 -2
- package/package.json +8 -9
- package/dist/runtimes/codex-execution-policy.js +0 -12
package/README.md
CHANGED
|
@@ -413,13 +413,6 @@ 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
|
-
|
|
423
416
|
Binding changes reconcile immediately when the Computer is online. On reconnect the server sends the
|
|
424
417
|
complete binding set for every Agent assigned to that Computer, including empty sets that clear stale
|
|
425
418
|
links left by offline unbinds. Every non-empty execution snapshot is also reconciled immediately before
|
|
@@ -3,6 +3,8 @@ import { posix, win32 } from "node:path";
|
|
|
3
3
|
import { buildServiceSpec, serviceStatus, windowsCommandArg, } from "./computer-service.js";
|
|
4
4
|
import { daemonGlobalInstallation } from "./daemon-installation.js";
|
|
5
5
|
import { inspectLegacyServiceInstallationDetails } from "./legacy-service-installation.js";
|
|
6
|
+
import { powershellCommandArgs } from "./powershell-command.js";
|
|
7
|
+
import { windowsTaskPrincipalFields, windowsTaskPrincipalMatches, windowsTaskPrincipalScript, } from "./windows-task-principal.js";
|
|
6
8
|
function encoded(value) {
|
|
7
9
|
return Buffer.from(value, "utf16le").toString("base64");
|
|
8
10
|
}
|
|
@@ -142,12 +144,11 @@ async function discoverWindows(input, identity) {
|
|
|
142
144
|
"$n=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($args[0]));",
|
|
143
145
|
"$tasks=@(Get-ScheduledTask -ErrorAction Stop|Where-Object{$_.TaskPath -eq '\\' -and $_.TaskName -ceq $n});",
|
|
144
146
|
"if($tasks.Count -ne 1){[pscustomobject]@{count=$tasks.Count}|ConvertTo-Json -Compress;exit 0};",
|
|
145
|
-
"$task=$tasks[0];$actions=@($task.Actions)
|
|
146
|
-
|
|
147
|
+
"$task=$tasks[0];$actions=@($task.Actions);",
|
|
148
|
+
windowsTaskPrincipalScript,
|
|
149
|
+
`[pscustomobject]@{count=1;state=[int]$task.State;actionCount=$actions.Count;execute=if($actions.Count -eq 1){$actions[0].Execute}else{$null};arguments=if($actions.Count -eq 1){$actions[0].Arguments}else{$null};${windowsTaskPrincipalFields}}|ConvertTo-Json -Compress;`,
|
|
147
150
|
].join("");
|
|
148
|
-
const result = await input.runner("powershell.exe", [
|
|
149
|
-
"-NoProfile", "-NonInteractive", "-Command", script, encoded(identity.id),
|
|
150
|
-
]);
|
|
151
|
+
const result = await input.runner("powershell.exe", powershellCommandArgs(script, [encoded(identity.id)]));
|
|
151
152
|
if (result.exitCode !== 0) {
|
|
152
153
|
throw new Error(`Unable to inspect legacy scheduled task: ${result.stderr.trim() || `exit ${result.exitCode}`}`);
|
|
153
154
|
}
|
|
@@ -165,7 +166,7 @@ async function discoverWindows(input, identity) {
|
|
|
165
166
|
: null;
|
|
166
167
|
if (definition.count !== 1
|
|
167
168
|
|| definition.actionCount !== 1
|
|
168
|
-
|| definition
|
|
169
|
+
|| !windowsTaskPrincipalMatches(definition)
|
|
169
170
|
|| !win32.isAbsolute(definition.execute ?? "")
|
|
170
171
|
|| match === null
|
|
171
172
|
|| match[2] !== input.desired.profile
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { homedir, hostname, platform } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
const ALIYUN_MARKER = /alibaba|aliyun|alicloud/iu;
|
|
5
4
|
function readMarker(path) {
|
|
6
5
|
try {
|
|
@@ -29,15 +28,7 @@ export function detectCloudProvider(env = process.env, platformName = platform()
|
|
|
29
28
|
}
|
|
30
29
|
export function findOssUploadScript(env = process.env, exists = existsSync) {
|
|
31
30
|
const explicit = env.CREW_OSS_UPLOAD_SCRIPT?.trim();
|
|
32
|
-
|
|
33
|
-
return exists(explicit) ? explicit : undefined;
|
|
34
|
-
const home = env.HOME?.trim() || homedir();
|
|
35
|
-
const candidates = [
|
|
36
|
-
join(home, ".claude", "skills", "oss-upload", "scripts", "oss_upload.py"),
|
|
37
|
-
join(home, ".codex", "skills", "oss-upload", "scripts", "oss_upload.py"),
|
|
38
|
-
join(home, ".agents", "skills", "oss-upload", "scripts", "oss_upload.py"),
|
|
39
|
-
];
|
|
40
|
-
return candidates.find(exists);
|
|
31
|
+
return explicit && exists(explicit) ? explicit : undefined;
|
|
41
32
|
}
|
|
42
33
|
export function cloudReportUploadFacts(env = process.env, platformName = platform(), hostName = hostname(), readMarkerValue, exists) {
|
|
43
34
|
const provider = detectCloudProvider(env, platformName, hostName, readMarkerValue);
|
package/dist/computer-main.js
CHANGED
|
File without changes
|
package/dist/computer-service.js
CHANGED
|
@@ -6,7 +6,9 @@ import { promisify } from "node:util";
|
|
|
6
6
|
import { dirname, resolve } from "node:path";
|
|
7
7
|
import { normalizeDaemonNpmRegistry } from "./npm-registry.js";
|
|
8
8
|
import { daemonRegistryCandidates } from "./daemon-registry.js";
|
|
9
|
+
import { windowsTaskPrincipalFields, windowsTaskPrincipalMatches, windowsTaskPrincipalScript, } from "./windows-task-principal.js";
|
|
9
10
|
import { npmInvocation } from "./npm-command.js";
|
|
11
|
+
import { powershellCommandArgs } from "./powershell-command.js";
|
|
10
12
|
const execFileAsync = promisify(execFile);
|
|
11
13
|
const WINDOWS_STOP_TIMEOUT_MS = 5_000;
|
|
12
14
|
const WINDOWS_STOP_POLL_MS = 100;
|
|
@@ -195,12 +197,11 @@ async function windowsTaskDefinitionMatches(spec, runner) {
|
|
|
195
197
|
"$n=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($args[0]));",
|
|
196
198
|
"$tasks=@(Get-ScheduledTask -ErrorAction Stop|Where-Object{$_.TaskPath -eq '\\' -and $_.TaskName -ceq $n});",
|
|
197
199
|
"if($tasks.Count -ne 1){[pscustomobject]@{count=$tasks.Count}|ConvertTo-Json -Compress;exit 0};",
|
|
198
|
-
"$task=$tasks[0];$actions=@($task.Actions)
|
|
199
|
-
|
|
200
|
+
"$task=$tasks[0];$actions=@($task.Actions);",
|
|
201
|
+
windowsTaskPrincipalScript,
|
|
202
|
+
`[pscustomobject]@{count=1;actionCount=$actions.Count;execute=if($actions.Count -eq 1){$actions[0].Execute}else{$null};arguments=if($actions.Count -eq 1){$actions[0].Arguments}else{$null};${windowsTaskPrincipalFields}}|ConvertTo-Json -Compress;`,
|
|
200
203
|
].join("");
|
|
201
|
-
const result = await runner("powershell.exe", [
|
|
202
|
-
"-NoProfile", "-NonInteractive", "-Command", script, encodedName,
|
|
203
|
-
]);
|
|
204
|
+
const result = await runner("powershell.exe", powershellCommandArgs(script, [encodedName]));
|
|
204
205
|
if (result.exitCode !== 0) {
|
|
205
206
|
throw new Error(`Unable to inspect scheduled task definition: ${result.stderr.trim() || `exit ${result.exitCode}`}`);
|
|
206
207
|
}
|
|
@@ -214,7 +215,7 @@ async function windowsTaskDefinitionMatches(spec, runner) {
|
|
|
214
215
|
const expectedArguments = spec.daemonCommand.slice(1).map(windowsCommandArg).join(" ");
|
|
215
216
|
return definition.count === 1
|
|
216
217
|
&& definition.actionCount === 1
|
|
217
|
-
&& definition
|
|
218
|
+
&& windowsTaskPrincipalMatches(definition)
|
|
218
219
|
&& sameWindowsPath(definition.execute, spec.daemonCommand[0])
|
|
219
220
|
&& definition.arguments === expectedArguments;
|
|
220
221
|
}
|
|
@@ -226,9 +227,7 @@ async function windowsTaskState(spec, runner) {
|
|
|
226
227
|
"$tasks=@(Get-ScheduledTask -ErrorAction Stop|Where-Object{$_.TaskPath -eq '\\' -and $_.TaskName -ceq $n});",
|
|
227
228
|
"if($tasks.Count -eq 0){'missing'}elseif($tasks.Count -eq 1){'state:'+([int]$tasks[0].State)}else{throw 'duplicate scheduled tasks'}",
|
|
228
229
|
].join("");
|
|
229
|
-
const result = await runner("powershell.exe", [
|
|
230
|
-
"-NoProfile", "-NonInteractive", "-Command", script, encodedName,
|
|
231
|
-
]);
|
|
230
|
+
const result = await runner("powershell.exe", powershellCommandArgs(script, [encodedName]));
|
|
232
231
|
if (result.exitCode !== 0) {
|
|
233
232
|
throw new Error(`Unable to query scheduled task: ${result.stderr.trim() || `exit ${result.exitCode}`}`);
|
|
234
233
|
}
|
|
@@ -279,10 +278,9 @@ export async function installService(spec, runner = systemCommandRunner) {
|
|
|
279
278
|
"$principal=New-ScheduledTaskPrincipal -UserId $identity -LogonType Interactive -RunLevel Limited;",
|
|
280
279
|
"Register-ScheduledTask -TaskName $name -TaskPath '\\' -Action $action -Trigger $trigger -Settings $settings -Principal $principal -ErrorAction Stop|Out-Null;",
|
|
281
280
|
].join("");
|
|
282
|
-
await checked(runner, "powershell.exe", [
|
|
283
|
-
"-NoProfile", "-NonInteractive", "-Command", script,
|
|
281
|
+
await checked(runner, "powershell.exe", powershellCommandArgs(script, [
|
|
284
282
|
encodedName, encodedExecutable, encodedArguments,
|
|
285
|
-
], "Scheduled task installation");
|
|
283
|
+
]), "Scheduled task installation");
|
|
286
284
|
return;
|
|
287
285
|
}
|
|
288
286
|
if (spec.descriptorPath === null || spec.descriptor === null)
|
|
@@ -418,6 +416,33 @@ export async function serviceAction(spec, action, runner = systemCommandRunner)
|
|
|
418
416
|
}
|
|
419
417
|
}
|
|
420
418
|
const systemDetachedSpawn = (command, args, options) => spawn(command, [...args], options);
|
|
419
|
+
function windowsRestartCommandArgs(spec) {
|
|
420
|
+
if (!spec.runtimeProcessIdentity)
|
|
421
|
+
throw new Error("Windows daemon process identity is required for restart");
|
|
422
|
+
const encodedName = Buffer.from(spec.id, "utf16le").toString("base64");
|
|
423
|
+
const encodedExecutable = Buffer.from(spec.daemonCommand[0], "utf16le").toString("base64");
|
|
424
|
+
const encodedArguments = Buffer.from(spec.daemonCommand.slice(1).map(windowsCommandArg).join(" "), "utf16le").toString("base64");
|
|
425
|
+
const script = [
|
|
426
|
+
"$ErrorActionPreference='Stop';",
|
|
427
|
+
"$n=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($args[1]));",
|
|
428
|
+
"$exe=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($args[2]));",
|
|
429
|
+
"$argv=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($args[3]));",
|
|
430
|
+
"$task=@(Get-ScheduledTask -ErrorAction Stop|Where-Object{$_.TaskPath -eq '\\' -and $_.TaskName -ceq $n});if($task.Count -ne 1){throw 'scheduled task identity changed'};",
|
|
431
|
+
"$actions=@($task[0].Actions);if($actions.Count -ne 1 -or -not [String]::Equals($actions[0].Execute,$exe,[StringComparison]::OrdinalIgnoreCase) -or $actions[0].Arguments -cne $argv){throw 'scheduled task action changed'};",
|
|
432
|
+
"$p=Get-Process -Id ([int]$args[0]) -ErrorAction Stop;",
|
|
433
|
+
"if($p.StartTime.ToUniversalTime().ToFileTimeUtc().ToString() -cne $args[4]){throw 'daemon process identity changed'};",
|
|
434
|
+
"$p.Kill();",
|
|
435
|
+
"if(-not $p.WaitForExit(10000)){throw 'daemon exit timeout'};",
|
|
436
|
+
"$deadline=[DateTime]::UtcNow.AddSeconds(10);",
|
|
437
|
+
"do{$task=@(Get-ScheduledTask -ErrorAction Stop|Where-Object{$_.TaskPath -eq '\\' -and $_.TaskName -ceq $n});if($task.Count -ne 1){throw 'scheduled task identity changed'};if([int]$task[0].State -ne 4){break};Start-Sleep -Milliseconds 100}while([DateTime]::UtcNow -lt $deadline);",
|
|
438
|
+
"if([int]$task[0].State -eq 4){throw 'scheduled task stop timeout'};",
|
|
439
|
+
"$actions=@($task[0].Actions);if($actions.Count -ne 1 -or -not [String]::Equals($actions[0].Execute,$exe,[StringComparison]::OrdinalIgnoreCase) -or $actions[0].Arguments -cne $argv){throw 'scheduled task action changed'};",
|
|
440
|
+
"& schtasks.exe /Run /TN $n | Out-Null;if($LASTEXITCODE -ne 0){throw 'scheduled task start failed'};",
|
|
441
|
+
].join("");
|
|
442
|
+
return powershellCommandArgs(script, [
|
|
443
|
+
String(process.pid), encodedName, encodedExecutable, encodedArguments, spec.runtimeProcessIdentity,
|
|
444
|
+
]);
|
|
445
|
+
}
|
|
421
446
|
const RESTART_HELPER_SOURCE = String.raw `
|
|
422
447
|
const { spawnSync } = require("node:child_process");
|
|
423
448
|
const spec = JSON.parse(process.argv[1]);
|
|
@@ -428,27 +453,7 @@ setTimeout(() => {
|
|
|
428
453
|
} else if (spec.platform === "linux") {
|
|
429
454
|
restarted = spawnSync("systemctl", ["--user", "--no-block", "restart", spec.id], { stdio: "ignore", shell: false });
|
|
430
455
|
} else {
|
|
431
|
-
|
|
432
|
-
const encodedExecutable = Buffer.from(spec.executable, "utf16le").toString("base64");
|
|
433
|
-
const encodedArguments = Buffer.from(spec.arguments, "utf16le").toString("base64");
|
|
434
|
-
const script = [
|
|
435
|
-
"$ErrorActionPreference='Stop';",
|
|
436
|
-
"$n=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($args[1]));",
|
|
437
|
-
"$exe=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($args[2]));",
|
|
438
|
-
"$argv=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($args[3]));",
|
|
439
|
-
"$task=@(Get-ScheduledTask -ErrorAction Stop|Where-Object{$_.TaskPath -eq '\\' -and $_.TaskName -ceq $n});if($task.Count -ne 1){throw 'scheduled task identity changed'};",
|
|
440
|
-
"$actions=@($task[0].Actions);if($actions.Count -ne 1 -or -not [String]::Equals($actions[0].Execute,$exe,[StringComparison]::OrdinalIgnoreCase) -or $actions[0].Arguments -cne $argv){throw 'scheduled task action changed'};",
|
|
441
|
-
"$p=Get-Process -Id ([int]$args[0]) -ErrorAction Stop;",
|
|
442
|
-
"if($p.StartTime.ToUniversalTime().ToFileTimeUtc().ToString() -cne $args[4]){throw 'daemon process identity changed'};",
|
|
443
|
-
"$p.Kill();",
|
|
444
|
-
"if(-not $p.WaitForExit(10000)){throw 'daemon exit timeout'};",
|
|
445
|
-
"$deadline=[DateTime]::UtcNow.AddSeconds(10);",
|
|
446
|
-
"do{$task=@(Get-ScheduledTask -ErrorAction Stop|Where-Object{$_.TaskPath -eq '\\' -and $_.TaskName -ceq $n});if($task.Count -ne 1){throw 'scheduled task identity changed'};if([int]$task[0].State -ne 4){break};Start-Sleep -Milliseconds 100}while([DateTime]::UtcNow -lt $deadline);",
|
|
447
|
-
"if([int]$task[0].State -eq 4){throw 'scheduled task stop timeout'};",
|
|
448
|
-
"$actions=@($task[0].Actions);if($actions.Count -ne 1 -or -not [String]::Equals($actions[0].Execute,$exe,[StringComparison]::OrdinalIgnoreCase) -or $actions[0].Arguments -cne $argv){throw 'scheduled task action changed'};",
|
|
449
|
-
"& schtasks.exe /Run /TN $n | Out-Null;if($LASTEXITCODE -ne 0){throw 'scheduled task start failed'};",
|
|
450
|
-
].join("");
|
|
451
|
-
restarted = spawnSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script, String(spec.daemonPid), encodedName, encodedExecutable, encodedArguments, spec.processIdentity], { stdio: "ignore", shell: false });
|
|
456
|
+
restarted = spawnSync("powershell.exe", spec.powershellArgs, { stdio: "ignore", shell: false });
|
|
452
457
|
}
|
|
453
458
|
if (restarted.status !== 0) process.send?.({ type: "restart-failed", status: restarted.status });
|
|
454
459
|
setTimeout(() => {
|
|
@@ -470,15 +475,8 @@ export function scheduleServiceRestart(spec, spawnDetached = systemDetachedSpawn
|
|
|
470
475
|
? { platform: spec.platform, id: spec.id }
|
|
471
476
|
: {
|
|
472
477
|
platform: spec.platform,
|
|
473
|
-
|
|
474
|
-
daemonPid: process.pid,
|
|
475
|
-
executable: spec.daemonCommand[0],
|
|
476
|
-
arguments: spec.daemonCommand.slice(1).map(windowsCommandArg).join(" "),
|
|
477
|
-
processIdentity: spec.runtimeProcessIdentity,
|
|
478
|
+
powershellArgs: windowsRestartCommandArgs(spec),
|
|
478
479
|
};
|
|
479
|
-
if (spec.platform === "win32" && !payload.processIdentity) {
|
|
480
|
-
throw new Error("Windows daemon process identity is required for restart");
|
|
481
|
-
}
|
|
482
480
|
const child = spawnDetached(process.execPath, ["-e", RESTART_HELPER_SOURCE, JSON.stringify(payload)], { detached: true, stdio: ["ignore", "ignore", "ignore", "ipc"], shell: false });
|
|
483
481
|
child.unref();
|
|
484
482
|
let settleFailure;
|
|
@@ -627,7 +625,7 @@ export async function windowsProfileIsPrivate(path, runner = systemCommandRunner
|
|
|
627
625
|
"$unsafe=$rules|Where-Object { $_.AccessControlType -eq 'Allow' -and $safe -notcontains $_.IdentityReference.Translate([Security.Principal.SecurityIdentifier]).Value };",
|
|
628
626
|
"if($unsafe){'false'}else{'true'}",
|
|
629
627
|
].join("");
|
|
630
|
-
const result = await runner("powershell.exe",
|
|
628
|
+
const result = await runner("powershell.exe", powershellCommandArgs(script, [encodedPath]));
|
|
631
629
|
if (result.exitCode !== 0)
|
|
632
630
|
throw new Error(`Profile ACL inspection failed: ${result.stderr.trim() || `exit ${result.exitCode}`}`);
|
|
633
631
|
if (result.stdout.trim() === "true")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { hostname } from "node:os";
|
|
3
3
|
import { MachineTokenSchema } from "./computer-profile.js";
|
|
4
|
+
import { powershellCommandArgs } from "./powershell-command.js";
|
|
4
5
|
import { systemCommandRunner, } from "./computer-service.js";
|
|
5
6
|
const HttpUrlSchema = z.string().url().refine((value) => {
|
|
6
7
|
const url = new URL(value);
|
|
@@ -309,8 +310,10 @@ export function createComputerSetupClient(options) {
|
|
|
309
310
|
};
|
|
310
311
|
}
|
|
311
312
|
export async function openSetupBrowser(url, platform = process.platform, runner = systemCommandRunner) {
|
|
312
|
-
const command = platform === "win32" ? "
|
|
313
|
-
const args =
|
|
313
|
+
const command = platform === "win32" ? "powershell.exe" : platform === "darwin" ? "open" : "xdg-open";
|
|
314
|
+
const args = platform === "win32"
|
|
315
|
+
? powershellCommandArgs("Start-Process -FilePath $args[0] -ErrorAction Stop | Out-Null", [url])
|
|
316
|
+
: [url];
|
|
314
317
|
const result = await runner(command, args);
|
|
315
318
|
if (result.exitCode !== 0) {
|
|
316
319
|
throw new Error(`Unable to open the computer setup browser: ${redactSetupSecrets(result.stderr.trim() || `exit ${result.exitCode}`)}`);
|
|
@@ -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", "pi"]);
|
|
11
|
+
const RuntimeSchema = z.enum(["claude", "codex", "kimi", "hermes", "opencode", "deepseek-harness", "memory_migration", "pi"]);
|
|
12
12
|
const RUNTIME_READY_SUFFIX = ".runtime-ready";
|
|
13
13
|
const RawJournalEntrySchema = z.object({
|
|
14
14
|
executionId: ExecutionIdSchema,
|
|
@@ -523,6 +523,8 @@ export function createExecutionJournal(agentsRoot, options = {}) {
|
|
|
523
523
|
}
|
|
524
524
|
};
|
|
525
525
|
const pruneInternal = async () => {
|
|
526
|
+
if (options.retainCompleted)
|
|
527
|
+
return;
|
|
526
528
|
const protectedExecutionIds = new Set(options.protectedExecutionIds?.() ?? []);
|
|
527
529
|
const entries = await readAll();
|
|
528
530
|
const acknowledged = entries
|
|
@@ -319,7 +319,7 @@ const RawExecutionCompletedSchema = z.object({
|
|
|
319
319
|
providerErrorCategory: ProviderErrorCategorySchema.optional(),
|
|
320
320
|
providerHttpStatus: ProviderHttpStatusSchema.optional(),
|
|
321
321
|
providerErrorCode: ProviderErrorCodeSchema.optional(),
|
|
322
|
-
runtime: RuntimeSchema,
|
|
322
|
+
runtime: z.union([RuntimeSchema, z.literal("memory_migration")]),
|
|
323
323
|
model: z.string().optional(),
|
|
324
324
|
resumed: z.boolean(),
|
|
325
325
|
finalText: z.string().optional(),
|
package/dist/execution-runner.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { isLocalMemoryV2Enabled, localMemoryV2Environment, resolveReposRoot } from "./config.js";
|
|
4
|
+
import { detectLocalMemoryStorageVersion } from "./local-memory/storage-format.js";
|
|
4
5
|
import { DaemonToServerExecutionFrameSchema, ExecutionCompletedSchema, ExecutionRejectedSchema, ExecutionStartSchema, } from "./execution-protocol.js";
|
|
5
6
|
import { JournalConflictError } from "./execution-journal.js";
|
|
6
7
|
import { boundExecutionFrame } from "./execution-event-limit.js";
|
|
@@ -838,8 +839,9 @@ export async function runExecution(config, input, dependencies) {
|
|
|
838
839
|
const localMemoryGuardInBase = localMemoryV2Environment(config.serverUrl) === "custom";
|
|
839
840
|
const boundedSystemPrompt = (context) => {
|
|
840
841
|
const enabled = context.workspace.localMemoryV2Enabled ?? localMemoryV2Enabled;
|
|
841
|
-
const systemPromptWithLocalFacts = withLocalExecutionFacts(`${spec.instructions.systemPrompt}${enabled && localMemoryGuardInBase ? renderLocalMemoryV2WriteGuard() : ""}`, baseSystemPromptBudget, {
|
|
842
|
+
const systemPromptWithLocalFacts = withLocalExecutionFacts(`${spec.instructions.systemPrompt}${enabled && localMemoryGuardInBase && detectLocalMemoryStorageVersion(context.workspace.memory) !== 2 ? renderLocalMemoryV2WriteGuard() : ""}`, baseSystemPromptBudget, {
|
|
842
843
|
...(selfTraining ? { isolateLocalMemory: true } : {}),
|
|
844
|
+
memoryQuery: spec.instructions.wakePrompt,
|
|
843
845
|
collaborationTools: config.codexCollaborationTools && spec.runtime.name === "codex",
|
|
844
846
|
});
|
|
845
847
|
const base = typeof systemPromptWithLocalFacts === "string"
|
|
@@ -879,6 +881,7 @@ export async function runExecution(config, input, dependencies) {
|
|
|
879
881
|
serverUrl: config.serverUrl,
|
|
880
882
|
token: credential.token,
|
|
881
883
|
agentId: credential.agentId,
|
|
884
|
+
...(dependencies.controlIdentity === undefined ? {} : dependencies.controlIdentity),
|
|
882
885
|
agentsRoot: config.agentsRoot,
|
|
883
886
|
reposRoot: resolveReposRoot(config.agentsRoot, config.reposRoot),
|
|
884
887
|
...(config.qaReportRoot === undefined ? {} : { qaReportRoot: config.qaReportRoot }),
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* 本机执行提示词的合成与预算裁剪。
|
|
3
3
|
*
|
|
4
4
|
* server 提示词是权威部分,绝不裁剪;项目工作区提示词是绑定执行的强制部分,放不下就直接失败;
|
|
5
|
-
*
|
|
5
|
+
* 本机事实与旧格式预览可按预算省略;schema2身份和置顶规则必须保留,放不下则拒绝执行。
|
|
6
6
|
*/
|
|
7
|
+
import { detectLocalMemoryStorageVersion } from "./local-memory/storage-format.js";
|
|
7
8
|
import { buildCollaborationToolsPrompt, buildRuntimeWorkspacePrompt, capMemoryForInject, capWorkLogForInject, } from "./prompt.js";
|
|
8
9
|
const trainingProjectJson = (project) => JSON.stringify({
|
|
9
10
|
repositoryKey: project.repositoryKey,
|
|
@@ -57,10 +58,14 @@ export function withLocalExecutionFacts(serverPrompt, maxBytes, options = {}) {
|
|
|
57
58
|
}
|
|
58
59
|
const remaining = maxBytes - requiredBytes - Math.max(0, reservedPromptBytes);
|
|
59
60
|
const factsBytes = Buffer.byteLength(localFacts, "utf8");
|
|
60
|
-
if (factsBytes > remaining)
|
|
61
|
+
if (factsBytes > remaining) {
|
|
62
|
+
if (!options.isolateLocalMemory && detectLocalMemoryStorageVersion(workspace.memory) === 2) {
|
|
63
|
+
throw new Error("local_memory_identity_budget_exceeded");
|
|
64
|
+
}
|
|
61
65
|
return `${serverPrompt}${collaborationPrompt}${mandatoryWorkspacePrompt}`;
|
|
66
|
+
}
|
|
62
67
|
const memoryHeading = "\n\n## Injected MEMORY.md (bounded local context)\n";
|
|
63
|
-
const memory = options.isolateLocalMemory ? "" : capMemoryForInject(workspace.memory, undefined, remaining - factsBytes - Buffer.byteLength(memoryHeading, "utf8"));
|
|
68
|
+
const memory = options.isolateLocalMemory ? "" : capMemoryForInject(workspace.memory, undefined, remaining - factsBytes - Buffer.byteLength(memoryHeading, "utf8"), options.memoryQuery);
|
|
64
69
|
const memorySection = memory === "" ? "" : memoryHeading + memory;
|
|
65
70
|
const workLogSection = workLog === "" ? "" : `\n\n## Injected work-log (bounded local context)\n${workLog}`;
|
|
66
71
|
const workLogBudget = remaining - factsBytes - Buffer.byteLength(memorySection, "utf8");
|
package/dist/local-executor.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createInterface } from "node:readline";
|
|
|
6
6
|
import { readFile, rm, writeFile } from "node:fs/promises";
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { cleanupSelfTrainingRunDir } from "./self-training-workspace.js";
|
|
9
|
-
import {
|
|
9
|
+
import { rotateAgentSession, safeKey, } from "./workspace.js";
|
|
10
10
|
import { CLAUDE_ADDITIONAL_DIRECTORY_INSTRUCTIONS_ENV, isClaudeAdditionalDirectoryInstructionsSupported, probeClaudeVersion, spawnClaude, } from "./runtimes/claude.js";
|
|
11
11
|
import { spawnCodex } from "./runtimes/codex.js";
|
|
12
12
|
import { DEEPSEEK_CODEX_MODEL, DEEPSEEK_CODEX_REASONING_LEVELS, materializeDeepSeekCodexHome, } from "./runtimes/codex-deepseek-config.js";
|
|
@@ -39,13 +39,20 @@ import { projectSkillRuntimeDirectories, } from "./project-skills/runtime-launch
|
|
|
39
39
|
import { logIdentityRosterRuntimePrepared } from "./identity-roster-telemetry.js";
|
|
40
40
|
import { diffMemoryPruneNotes, evaluateMemoryPrunePostcondition, inspectMemoryPruneFilesWithinDeadline, logMemoryPruneDiagnosticsFailure, memoryPruneSnapshotFields, parseMemoryPruneTraceId, } from "./memory-prune-diagnostics.js";
|
|
41
41
|
import { createLocalMemoryTelemetry, logLocalMemoryContextPrepareFailure, logLocalMemoryDiagnosticsFailure, } from "./local-memory-telemetry.js";
|
|
42
|
+
import { LOCAL_MEMORY_DIAGNOSTICS_TIMEOUT_MS } from "./local-memory-diagnostics.js";
|
|
42
43
|
import { CodexStartupStageParser } from "./codex-startup-stage.js";
|
|
43
44
|
import { formatRuntimeStartupError } from "./runtime-startup-error.js";
|
|
44
45
|
import { logRuntimeEnvironmentContract } from "./runtime-environment-telemetry.js";
|
|
45
|
-
import { commitLocalMemoryResultAfterExit,
|
|
46
|
+
import { commitLocalMemoryResultAfterExit, isLocalMemoryV2Eligible, localMemoryResultPath as makeLocalMemoryResultPath, } from "./local-memory/runtime.js";
|
|
46
47
|
import { prepareLocalMemoryPrompt } from "./local-memory/prompt.js";
|
|
47
|
-
import { reportLocalMemoryV2Deferred
|
|
48
|
+
import { reportLocalMemoryV2Deferred } from "./local-memory/rollout.js";
|
|
49
|
+
import { prepareExecutionMemoryWorkspace } from "./local-memory/execution-workspace.js";
|
|
48
50
|
import { localMemoryV2Environment } from "./config.js";
|
|
51
|
+
import { detectLocalMemoryStorageVersion } from "./local-memory/storage-format.js";
|
|
52
|
+
import { MEMORY_STATE_GUARD_CAPABILITY, MEMORY_STORAGE_V2_CAPABILITY } from "./memory-migration-protocol.js";
|
|
53
|
+
import { resolveLocalMemoryWriterMode } from "./local-memory/writer-mode.js";
|
|
54
|
+
import { logLocalMemoryCommitApplied } from "./local-memory/commit-telemetry.js";
|
|
55
|
+
import { shouldUseMigrationDeferredPending } from "./local-memory/migration-pending.js";
|
|
49
56
|
export class RuntimeRunningCallbackTimeoutError extends Error {
|
|
50
57
|
constructor(runtime, timeoutMs) {
|
|
51
58
|
super(`${runtime} runtime-running callback timed out after ${timeoutMs}ms`);
|
|
@@ -59,7 +66,6 @@ const STDERR_TAIL_CAP = 2_000;
|
|
|
59
66
|
// the old failure mode where a callback could hold execution slots forever.
|
|
60
67
|
const RUNTIME_RUNNING_CALLBACK_TIMEOUT_MS = 30_000;
|
|
61
68
|
const MEMORY_PRUNE_DIAGNOSTICS_TIMEOUT_MS = 2_000;
|
|
62
|
-
const LOCAL_MEMORY_DIAGNOSTICS_TIMEOUT_MS = 250;
|
|
63
69
|
const CLAUDE_INSTRUCTION_WARNING = "claude_additional_directory_instructions_unverified";
|
|
64
70
|
const CODEX_COLLABORATION_EXEC_WARNING = "codex_collaboration_disabled_on_exec";
|
|
65
71
|
function withoutClaudeInstructionFlag(env) {
|
|
@@ -211,37 +217,12 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
211
217
|
: "high"
|
|
212
218
|
: runtime.reasoning;
|
|
213
219
|
const providerFp = providerFingerprint(runtime.name, providerConfig);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
agentsRoot: input.launch.agentsRoot,
|
|
218
|
-
handle: input.handle,
|
|
219
|
-
cliPath: input.launch.cliPath,
|
|
220
|
-
executionId: input.executionId,
|
|
221
|
-
...(input.keyMode === undefined ? {} : { keyMode: input.keyMode }),
|
|
222
|
-
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
223
|
-
...(input.resumeKey === undefined ? {} : { resumeKey: input.resumeKey }),
|
|
224
|
-
...(input.sessionContextFingerprint === undefined
|
|
225
|
-
? {}
|
|
226
|
-
: { sessionContextFingerprint: input.sessionContextFingerprint }),
|
|
227
|
-
...(input.launch.description ? { description: input.launch.description } : {}),
|
|
228
|
-
...(isolatedMaintenance ? { skipLocalMemory: true } : {}),
|
|
229
|
-
}), dependencies.cancellation);
|
|
230
|
-
}
|
|
231
|
-
catch (error) {
|
|
232
|
-
logLocalMemoryContextPrepareFailure({
|
|
233
|
-
executionId: input.executionId,
|
|
234
|
-
agentHandle: input.handle,
|
|
235
|
-
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
236
|
-
}, "workspace_prepare", error);
|
|
237
|
-
throw error;
|
|
238
|
-
}
|
|
239
|
-
const memoryRollout = await resolveLocalMemoryV2Rollout({ workspace, handle: input.handle,
|
|
240
|
-
serverUrl: input.launch.serverUrl, requested: input.localMemoryV2Enabled === true,
|
|
241
|
-
selfTraining: isolatedMaintenance, ...(input.launch.description ? { description: input.launch.description } : {}) });
|
|
242
|
-
workspace = { ...workspace, localMemoryV2Enabled: memoryRollout.enabled };
|
|
220
|
+
const preparedMemory = await prepareExecutionMemoryWorkspace(input, isolatedMaintenance, dependencies.cancellation);
|
|
221
|
+
let workspace = preparedMemory.workspace;
|
|
222
|
+
const memoryRollout = preparedMemory.mode;
|
|
243
223
|
input = { ...input, localMemoryV2Enabled: memoryRollout.enabled };
|
|
244
|
-
const localMemoryV2Initialized =
|
|
224
|
+
const localMemoryV2Initialized = preparedMemory.initialized;
|
|
225
|
+
let localMemoryWriterMode = resolveLocalMemoryWriterMode(workspace, memoryRollout);
|
|
245
226
|
let materialized = null;
|
|
246
227
|
let knownAttachmentDirectory = null;
|
|
247
228
|
const startupReservationState = { current: null };
|
|
@@ -252,6 +233,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
252
233
|
let memoryPruneBeforeSnapshot = null;
|
|
253
234
|
let memoryPruneSharedWriteKey = null;
|
|
254
235
|
let localMemoryResultPath = null;
|
|
236
|
+
let migrationDeferredPending = false;
|
|
255
237
|
let environmentSnapshot;
|
|
256
238
|
let executionWorkspace = workspace;
|
|
257
239
|
let localMemoryTelemetry = null;
|
|
@@ -390,29 +372,41 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
390
372
|
const attachmentPlan = routeRuntimeAttachments(runtime.name, materialized?.attachments ?? []);
|
|
391
373
|
let baseWakePrompt = `${resolvePrompt(input.wakePrompt, promptContext)}${attachmentPlan.promptSuffix}`;
|
|
392
374
|
memoryPruneTraceId = isolatedMaintenance ? null : parseMemoryPruneTraceId(baseWakePrompt);
|
|
393
|
-
|
|
394
|
-
|
|
375
|
+
localMemoryWriterMode = resolveLocalMemoryWriterMode(executionWorkspace, memoryRollout);
|
|
376
|
+
migrationDeferredPending = shouldUseMigrationDeferredPending({ pruneTraceId: memoryPruneTraceId,
|
|
377
|
+
writerMode: localMemoryWriterMode, rolloutEnabled: memoryRollout.enabled,
|
|
378
|
+
legacyFallback: memoryRollout.legacyFallback,
|
|
379
|
+
failure: memoryRollout.failure, memory: executionWorkspace.memory });
|
|
380
|
+
if (memoryRollout.deferred || migrationDeferredPending)
|
|
381
|
+
reportLocalMemoryV2Deferred(input.executionId, input.handle, memoryPruneTraceId !== null || input.maintenancePurpose === "memory_prune", memoryRollout.legacyFallback, memoryRollout.failure, migrationDeferredPending);
|
|
382
|
+
if (memoryPruneTraceId !== null && localMemoryWriterMode === "blocked" && !migrationDeferredPending) {
|
|
383
|
+
throw new Error(memoryRollout.failure === "inspection_failed" ? "local_memory_inspection_failed" : "local_memory_v2_requires_migration");
|
|
384
|
+
}
|
|
395
385
|
if (memoryPruneTraceId !== null) {
|
|
396
386
|
executionWorkspace = await resolveMemoryPruneWorkLog(executionWorkspace, input);
|
|
397
387
|
promptContext = { ...promptContext, workspace: executionWorkspace };
|
|
398
388
|
baseWakePrompt = `${resolvePrompt(input.wakePrompt, promptContext)}${attachmentPlan.promptSuffix}`;
|
|
399
389
|
}
|
|
400
|
-
if (
|
|
390
|
+
if ((localMemoryWriterMode === "v2" && memoryPruneTraceId !== null
|
|
401
391
|
&& isLocalMemoryV2Eligible({
|
|
402
392
|
enabledForHandle: true,
|
|
403
393
|
agentHomePreexisted: workspace.agentHomePreexisted === true,
|
|
404
394
|
memorySeedCreated: executionWorkspace.memorySeedCreated === true && (localMemoryV2Initialized || workspace.localMemoryV2Initialized !== false),
|
|
405
395
|
localMemoryV2Initialized,
|
|
406
396
|
memoryPrune: true,
|
|
407
|
-
})) {
|
|
397
|
+
})) || migrationDeferredPending) {
|
|
408
398
|
localMemoryResultPath = makeLocalMemoryResultPath(executionWorkspace.runDir, input.executionId);
|
|
409
399
|
}
|
|
410
400
|
const memoryPrompt = await prepareLocalMemoryPrompt({
|
|
411
401
|
agentDir: executionWorkspace.dir, executionId: input.executionId, agentHandle: input.handle,
|
|
412
402
|
enabled: input.localMemoryV2Enabled === true, query: baseWakePrompt,
|
|
413
403
|
resultPath: localMemoryResultPath, maxBytes: input.maxSystemPromptBytes,
|
|
414
|
-
|
|
404
|
+
storageVersion: detectLocalMemoryStorageVersion(executionWorkspace.memory),
|
|
405
|
+
strictRollout: !isolatedMaintenance && !memoryRollout.legacyFallback && (localMemoryV2Environment(input.launch.serverUrl) === "dev"
|
|
406
|
+
|| detectLocalMemoryStorageVersion(executionWorkspace.memory) === 2),
|
|
415
407
|
deferred: memoryRollout.deferred,
|
|
408
|
+
...(memoryRollout.legacyFallback ? { legacyFallback: true } : {}),
|
|
409
|
+
...(migrationDeferredPending ? { migrationDeferred: true } : {}),
|
|
416
410
|
renderBase: (reservedPromptBytes) => resolvePrompt(input.systemPrompt, { ...promptContext, reservedPromptBytes }),
|
|
417
411
|
});
|
|
418
412
|
localMemoryResultPath = memoryPrompt.resultPath;
|
|
@@ -909,6 +903,11 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
909
903
|
exitCode,
|
|
910
904
|
workLogPath: executionWorkspace.workLogPath,
|
|
911
905
|
expectedWorkLogSha256: workLogSha256(executionWorkspace.workLog),
|
|
906
|
+
...(localMemoryWriterMode === "v2" ? {
|
|
907
|
+
writerCapabilities: [MEMORY_STORAGE_V2_CAPABILITY, MEMORY_STATE_GUARD_CAPABILITY],
|
|
908
|
+
requiredStorageVersion: 2,
|
|
909
|
+
} : {}),
|
|
910
|
+
...(migrationDeferredPending ? { migrationDeferredPending: true } : {}),
|
|
912
911
|
});
|
|
913
912
|
const committed = exitCode !== 0 ? await commit() : await withWorkLogCommit(workLogExecutionKey(input.launch.agentsRoot, input.handle, input.taskKey), commit, dependencies.cancellation);
|
|
914
913
|
if (committed.status === "failed" || committed.status === "missing") {
|
|
@@ -922,6 +921,14 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
922
921
|
});
|
|
923
922
|
throw new Error(`local_memory_commit_failed: ${reason}`);
|
|
924
923
|
}
|
|
924
|
+
if (committed.status === "applied") {
|
|
925
|
+
if (localMemoryWriterMode === "v2" && (committed.storageVersionBefore !== 2 || committed.storageVersionAfter !== 2
|
|
926
|
+
|| committed.committedState !== true)) {
|
|
927
|
+
throw new Error("local_memory_commit_failed: local_memory_v2_commit_state_invalid");
|
|
928
|
+
}
|
|
929
|
+
logLocalMemoryCommitApplied({ executionId: input.executionId, agentHandle: input.handle,
|
|
930
|
+
pruneTraceId: memoryPruneTraceId, committed });
|
|
931
|
+
}
|
|
925
932
|
memoryPruneFailurePhase = "runtime_finalize";
|
|
926
933
|
}
|
|
927
934
|
const errorTail = [
|
|
@@ -1045,6 +1052,23 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
1045
1052
|
after_incomplete_file_count: noteDiff.after_manifest.incomplete_file_count,
|
|
1046
1053
|
changes: serializedChanges.json,
|
|
1047
1054
|
});
|
|
1055
|
+
const pendingDiff = diffMemoryPruneNotes(memoryPruneBeforeSnapshot.pending_manifest
|
|
1056
|
+
?? { files: [], total_count: 0, omitted_count: 0, truncated: false }, snapshot.pending_manifest
|
|
1057
|
+
?? { files: [], total_count: 0, omitted_count: 0, truncated: false });
|
|
1058
|
+
const serializedPendingChanges = boundedDiagnosticJsonArray(pendingDiff.changes);
|
|
1059
|
+
const pendingChangesTruncated = pendingDiff.truncated || serializedPendingChanges.truncated;
|
|
1060
|
+
dslog("memory_prune.pending_changed", "长期记忆 pending 候选变化已评估", {
|
|
1061
|
+
execution_id: input.executionId,
|
|
1062
|
+
agent_handle: input.handle,
|
|
1063
|
+
task_key: input.taskKey,
|
|
1064
|
+
prune_trace_id: memoryPruneTraceId,
|
|
1065
|
+
change_count: pendingDiff.change_count,
|
|
1066
|
+
changes_truncated: pendingChangesTruncated,
|
|
1067
|
+
evidence_complete: pendingDiff.evidence_complete && !pendingChangesTruncated,
|
|
1068
|
+
before_total_count: pendingDiff.before_manifest.total_count,
|
|
1069
|
+
after_total_count: pendingDiff.after_manifest.total_count,
|
|
1070
|
+
changes: serializedPendingChanges.json,
|
|
1071
|
+
});
|
|
1048
1072
|
const postcondition = evaluateMemoryPrunePostcondition(memoryPruneBeforeSnapshot, snapshot, {
|
|
1049
1073
|
executorCompleted: memoryPruneExecutorCompleted,
|
|
1050
1074
|
...(memoryPruneRuntimeExitCode === undefined
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { dslog } from "../slog.js";
|
|
2
|
+
function boundedIds(ids) {
|
|
3
|
+
return {
|
|
4
|
+
value: (ids ?? []).slice(0, 100).join(","),
|
|
5
|
+
count: ids?.length ?? 0,
|
|
6
|
+
truncated: (ids?.length ?? 0) > 100,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function logLocalMemoryCommitApplied(input) {
|
|
10
|
+
const { committed } = input;
|
|
11
|
+
const created = boundedIds(committed.createdIds);
|
|
12
|
+
const updated = boundedIds(committed.updatedIds);
|
|
13
|
+
const statusChanged = boundedIds(committed.statusChangedIds);
|
|
14
|
+
const pending = boundedIds(committed.pendingIds);
|
|
15
|
+
dslog("local_memory.commit_applied", "结构化本地记忆提交已验证", {
|
|
16
|
+
execution_id: input.executionId, agent_handle: input.agentHandle, prune_trace_id: input.pruneTraceId,
|
|
17
|
+
storage_version_before: committed.storageVersionBefore,
|
|
18
|
+
storage_version_after: committed.storageVersionAfter,
|
|
19
|
+
committed_state: committed.committedState,
|
|
20
|
+
writer_mode: committed.pendingReason === "legacy_requires_migration"
|
|
21
|
+
? "pending_only"
|
|
22
|
+
: committed.storageVersionAfter === 2 && committed.committedState ? "v2" : "legacy",
|
|
23
|
+
created_id_count: created.count, created_ids: created.value, created_ids_truncated: created.truncated,
|
|
24
|
+
updated_id_count: updated.count, updated_ids: updated.value, updated_ids_truncated: updated.truncated,
|
|
25
|
+
status_changed_id_count: statusChanged.count, status_changed_ids: statusChanged.value,
|
|
26
|
+
status_changed_ids_truncated: statusChanged.truncated,
|
|
27
|
+
pending_id_count: pending.count, pending_ids: pending.value, pending_ids_truncated: pending.truncated,
|
|
28
|
+
pending_reason: committed.pendingReason,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { prepareWorkspace } from "../workspace.js";
|
|
2
|
+
import { awaitWithCancellation } from "../runtime-cancellation.js";
|
|
3
|
+
import { logLocalMemoryContextPrepareFailure } from "../local-memory-telemetry.js";
|
|
4
|
+
import { resolveLocalMemoryV2Rollout } from "./rollout.js";
|
|
5
|
+
import { initializeLocalMemoryV2ForWorkspace } from "./runtime.js";
|
|
6
|
+
import { withMemoryAccess } from "./migration-access.js";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { readFile } from "node:fs/promises";
|
|
9
|
+
// A fresh Agent may receive the daemon's full ten-wide execution burst. The
|
|
10
|
+
// first turn publishes schema2 durably; the remaining turns must wait to reuse
|
|
11
|
+
// that committed fact instead of timing out on the generic short IO window.
|
|
12
|
+
const EXECUTION_MEMORY_ACCESS_WAIT_MS = 30_000;
|
|
13
|
+
export async function prepareExecutionMemoryWorkspace(input, isolated, cancellation) {
|
|
14
|
+
try {
|
|
15
|
+
const prepare = async (context) => {
|
|
16
|
+
const prepared = await prepareWorkspace({
|
|
17
|
+
agentsRoot: input.launch.agentsRoot, handle: input.handle, cliPath: input.launch.cliPath,
|
|
18
|
+
executionId: input.executionId,
|
|
19
|
+
...(input.keyMode === undefined ? {} : { keyMode: input.keyMode }),
|
|
20
|
+
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
21
|
+
...(input.resumeKey === undefined ? {} : { resumeKey: input.resumeKey }),
|
|
22
|
+
...(input.sessionContextFingerprint === undefined ? {} : { sessionContextFingerprint: input.sessionContextFingerprint }),
|
|
23
|
+
...(input.launch.description ? { description: input.launch.description } : {}),
|
|
24
|
+
...(isolated ? { skipLocalMemory: true } : {}),
|
|
25
|
+
});
|
|
26
|
+
const workspace = context?.created ? { ...prepared, agentHomePreexisted: false } : prepared;
|
|
27
|
+
const initialMode = await resolveLocalMemoryV2Rollout({ workspace, handle: input.handle, serverUrl: input.launch.serverUrl,
|
|
28
|
+
agentId: input.launch.agentId, requested: input.localMemoryV2Enabled === true, selfTraining: isolated,
|
|
29
|
+
...(input.launch.description ? { description: input.launch.description } : {}) });
|
|
30
|
+
const initializationBinding = input.launch.workspaceId !== undefined && input.launch.machineId !== undefined
|
|
31
|
+
? { workspaceId: input.launch.workspaceId, machineId: input.launch.machineId }
|
|
32
|
+
: undefined;
|
|
33
|
+
const initialized = await initializeLocalMemoryV2ForWorkspace(workspace, initialMode.enabled, input.launch.agentId, initializationBinding);
|
|
34
|
+
const memory = initialized && !workspace.localMemoryV2Initialized
|
|
35
|
+
? await readFile(join(workspace.dir, "MEMORY.md"), "utf8")
|
|
36
|
+
: workspace.memory;
|
|
37
|
+
const currentWorkspace = { ...workspace, memory };
|
|
38
|
+
const mode = initialized && !workspace.localMemoryV2Initialized
|
|
39
|
+
? await resolveLocalMemoryV2Rollout({ workspace: currentWorkspace, handle: input.handle,
|
|
40
|
+
serverUrl: input.launch.serverUrl, agentId: input.launch.agentId,
|
|
41
|
+
requested: input.localMemoryV2Enabled === true, selfTraining: isolated,
|
|
42
|
+
...(input.launch.description ? { description: input.launch.description } : {}) })
|
|
43
|
+
: initialMode;
|
|
44
|
+
return { workspace: { ...currentWorkspace, localMemoryV2Enabled: mode.enabled }, mode, initialized };
|
|
45
|
+
};
|
|
46
|
+
return await awaitWithCancellation(isolated ? prepare()
|
|
47
|
+
: withMemoryAccess(join(input.launch.agentsRoot, input.handle), prepare, {
|
|
48
|
+
create: true,
|
|
49
|
+
waitMs: EXECUTION_MEMORY_ACCESS_WAIT_MS,
|
|
50
|
+
initializedRecoveryIdentity: {
|
|
51
|
+
agentId: input.launch.agentId,
|
|
52
|
+
...(input.launch.workspaceId === undefined ? {} : { workspaceId: input.launch.workspaceId }),
|
|
53
|
+
...(input.launch.machineId === undefined ? {} : { machineId: input.launch.machineId }),
|
|
54
|
+
},
|
|
55
|
+
}), cancellation);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
logLocalMemoryContextPrepareFailure({ executionId: input.executionId, agentHandle: input.handle,
|
|
59
|
+
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }) }, "workspace_prepare", error);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|