@nowcrew/daemon 0.6.79-beta.1 → 0.6.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-ability/resolver.js +10 -7
- package/dist/daemon-update-controller.js +4 -1
- package/dist/daemon-update-eligibility.js +1 -1
- package/dist/execution-protocol.js +1 -0
- package/dist/execution-runner.js +9 -3
- package/dist/local-execution-prompt.js +3 -2
- package/dist/local-executor.js +50 -37
- package/dist/machine-info.js +3 -0
- package/dist/project-skills/capability.js +109 -0
- package/dist/project-skills/controller-convergence.js +57 -0
- package/dist/project-skills/projection-set-switch.js +419 -0
- package/dist/project-skills/projection-state-domain.js +170 -0
- package/dist/project-skills/projection-state-store.js +842 -0
- package/dist/project-skills/projection-state-transaction.js +322 -0
- package/dist/project-skills/projection-state.js +3 -0
- package/dist/project-skills/runtime-root-bootstrap.js +53 -0
- package/dist/project-skills/runtime-root-domain.js +268 -0
- package/dist/project-skills/runtime-root-gc.js +293 -0
- package/dist/project-skills/runtime-root-lease-artifact.js +46 -0
- package/dist/project-skills/runtime-root-leases.js +487 -0
- package/dist/project-skills/runtime-root-source-identity.js +60 -0
- package/dist/project-skills/runtime-root-startup.js +50 -0
- package/dist/project-skills/runtime-root-state-artifact-domain.js +143 -0
- package/dist/project-skills/runtime-root-state-index.js +356 -0
- package/dist/project-skills/runtime-root-store.js +722 -0
- package/dist/project-skills/serve-capability.js +28 -0
- package/dist/project-skills/serve-startup.js +60 -0
- package/dist/provider-env.js +21 -3
- package/dist/runner.js +2 -1
- package/dist/runtimes/codex-app-server-runner.js +9 -1
- package/dist/runtimes/codex-deepseek-config.js +17 -7
- package/dist/runtimes/codex.js +3 -0
- package/dist/self-training-workspace.js +15 -0
- package/dist/supervised-runtime.js +1 -0
- package/dist/workspace.js +13 -10
- package/package.json +1 -1
|
@@ -10,8 +10,8 @@ import { PROJECT_MANIFEST_SOURCE_PATH, ProjectDependencyManifestSchema, } from "
|
|
|
10
10
|
import { normalizeRepositoryIdentity } from "../repository-identity.js";
|
|
11
11
|
const runFile = promisify(execFile);
|
|
12
12
|
const MAX_FILES = 5_000;
|
|
13
|
-
const
|
|
14
|
-
const
|
|
13
|
+
export const AGENT_ABILITY_MAX_TOTAL_BYTES = 200 * 1024 * 1024;
|
|
14
|
+
export const AGENT_ABILITY_MAX_FILE_BYTES = 100 * 1024 * 1024;
|
|
15
15
|
const MAX_INSTRUCTIONS_BYTES = 96 * 1024;
|
|
16
16
|
const MAX_MEMORY_BYTES = 64 * 1024;
|
|
17
17
|
const AUTHORING_ONLY_ROOTS = new Set([".claude"]);
|
|
@@ -125,10 +125,11 @@ export const collectAbilityFiles = async (root) => {
|
|
|
125
125
|
if (info.isDirectory())
|
|
126
126
|
await visit(absolute);
|
|
127
127
|
else if (info.isFile()) {
|
|
128
|
-
if (info.size >
|
|
128
|
+
if (info.size > AGENT_ABILITY_MAX_FILE_BYTES) {
|
|
129
129
|
throw new Error(`ability_file_size_exceeded:${relative(root, absolute)}`);
|
|
130
|
+
}
|
|
130
131
|
totalBytes += info.size;
|
|
131
|
-
if (totalBytes >
|
|
132
|
+
if (totalBytes > AGENT_ABILITY_MAX_TOTAL_BYTES)
|
|
132
133
|
throw new Error("ability_total_size_exceeded");
|
|
133
134
|
if (files.length >= MAX_FILES)
|
|
134
135
|
throw new Error("ability_file_count_exceeded");
|
|
@@ -262,7 +263,7 @@ export const validateAbilityDependencyDeclarations = (manifest, lock) => {
|
|
|
262
263
|
throw new Error("ability_lock_has_undeclared_dependency");
|
|
263
264
|
}
|
|
264
265
|
};
|
|
265
|
-
const
|
|
266
|
+
export const scanAbilityFiles = (files, manifest) => {
|
|
266
267
|
const findings = [];
|
|
267
268
|
const secrets = [
|
|
268
269
|
/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/u,
|
|
@@ -270,7 +271,9 @@ const scan = (files, manifest) => {
|
|
|
270
271
|
/\bAK(?:ID|IA)[A-Z0-9]{12,}\b/u,
|
|
271
272
|
];
|
|
272
273
|
const executable = new Set([".exe", ".dll", ".dylib", ".so", ".bin", ".class", ".jar"]);
|
|
273
|
-
const allowedBinaryDocuments = new Set([
|
|
274
|
+
const allowedBinaryDocuments = new Set([
|
|
275
|
+
".pdf", ".png", ".jpg", ".jpeg", ".gif", ".webp", ".xlsx", ".xls", ".docx", ".pptx", ".ttf", ".otf",
|
|
276
|
+
]);
|
|
274
277
|
for (const file of files) {
|
|
275
278
|
let text;
|
|
276
279
|
try {
|
|
@@ -396,7 +399,7 @@ export async function resolveAbilityRelease(agentsRoot, command) {
|
|
|
396
399
|
}
|
|
397
400
|
const externalPaths = await verifyExternalDependencies(cacheRoot, resolved.root, lock);
|
|
398
401
|
files = await collectAbilityFiles(resolved.root);
|
|
399
|
-
const security =
|
|
402
|
+
const security = scanAbilityFiles(files, manifest);
|
|
400
403
|
const kinds = new Set(lock.assets.map((asset) => asset.kind));
|
|
401
404
|
const memory = [];
|
|
402
405
|
for (const [layer, mounts] of [["release-policy", manifest.spec.memory.policy], ["release-seed", manifest.spec.memory.seeds]]) {
|
|
@@ -4,11 +4,13 @@ const DaemonUpdateMessageSchema = z.object({
|
|
|
4
4
|
type: z.literal("daemon:update"),
|
|
5
5
|
updateId: z.string().uuid(),
|
|
6
6
|
targetVersion: z.string().refine(isDaemonReleaseVersion, "invalid daemon release version"),
|
|
7
|
+
registryUrl: z.string().url().optional(),
|
|
7
8
|
}).strict();
|
|
8
9
|
const DaemonRestartMessageSchema = z.object({
|
|
9
10
|
type: z.literal("daemon:restart"),
|
|
10
11
|
updateId: z.string().uuid(),
|
|
11
12
|
targetVersion: z.string().refine(isDaemonReleaseVersion, "invalid daemon release version"),
|
|
13
|
+
registryUrl: z.string().url().optional(),
|
|
12
14
|
}).strict();
|
|
13
15
|
const DaemonControlMessageSchema = z.union([DaemonUpdateMessageSchema, DaemonRestartMessageSchema]);
|
|
14
16
|
export function createDaemonUpdateController(deps) {
|
|
@@ -24,13 +26,14 @@ export function createDaemonUpdateController(deps) {
|
|
|
24
26
|
failed(message.updateId, "ineligible");
|
|
25
27
|
return;
|
|
26
28
|
}
|
|
29
|
+
const registryUrl = message.registryUrl ?? eligibility.registryUrl;
|
|
27
30
|
const preparation = message.type === "daemon:restart"
|
|
28
31
|
? await deps.prepareRestart()
|
|
29
32
|
: await deps.install({
|
|
30
33
|
targetVersion: message.targetVersion,
|
|
34
|
+
...(registryUrl === undefined ? {} : { registryUrl }),
|
|
31
35
|
packageRoot: eligibility.packageRoot,
|
|
32
36
|
npmPrefix: eligibility.npmPrefix,
|
|
33
|
-
...(eligibility.registryUrl === undefined ? {} : { registryUrl: eligibility.registryUrl }),
|
|
34
37
|
onInstalling: () => {
|
|
35
38
|
deps.sendStatus({ type: "daemon:update-status", updateId: message.updateId, status: "installing" });
|
|
36
39
|
},
|
|
@@ -14,7 +14,7 @@ import { assertRegistryCoversDescriptors, listManagedServiceDescriptorPaths, man
|
|
|
14
14
|
export async function managedDaemonCapabilities(eligibility) {
|
|
15
15
|
try {
|
|
16
16
|
return (await eligibility()).eligible
|
|
17
|
-
? ["daemon_update_v1", "daemon_restart_v1", "daemon_layout_migration_v1"]
|
|
17
|
+
? ["daemon_update_v1", "daemon_restart_v1", "daemon_update_registry_v1", "daemon_layout_migration_v1"]
|
|
18
18
|
: [];
|
|
19
19
|
}
|
|
20
20
|
catch {
|
|
@@ -200,6 +200,7 @@ export const ExecutionStartSchema = z.object({
|
|
|
200
200
|
language: z.enum(["zh", "en"]),
|
|
201
201
|
systemPrompt: z.string(),
|
|
202
202
|
wakePrompt: z.string(),
|
|
203
|
+
maintenancePurpose: z.literal("self_training").optional(),
|
|
203
204
|
}).strict(),
|
|
204
205
|
runtime: z.object({
|
|
205
206
|
name: RuntimeSchema,
|
package/dist/execution-runner.js
CHANGED
|
@@ -567,8 +567,9 @@ export async function runExecution(config, input, dependencies) {
|
|
|
567
567
|
projectContext = await cancellable(resolveProjectContext(projectSnapshot, projectWorkspaceRegistry), dependencies.cancellation);
|
|
568
568
|
sessionContextFingerprint = projectSessionContextFingerprint(spec.runtime.name, projectSnapshot);
|
|
569
569
|
}
|
|
570
|
+
const selfTraining = spec.instructions.maintenancePurpose === "self_training";
|
|
570
571
|
let recalledMemory = "";
|
|
571
|
-
if (spec.agent.memoryEnabled === true && dependencies.agentMemory !== undefined) {
|
|
572
|
+
if (!selfTraining && spec.agent.memoryEnabled === true && dependencies.agentMemory !== undefined) {
|
|
572
573
|
try {
|
|
573
574
|
recalledMemory = await cancellable(dependencies.agentMemory.recall(spec.agent.handle, spec.instructions.wakePrompt, spec.executionId, spec.agent.memoryAgentId ?? null), dependencies.cancellation);
|
|
574
575
|
}
|
|
@@ -827,7 +828,10 @@ export async function runExecution(config, input, dependencies) {
|
|
|
827
828
|
const baseSystemPromptBudget = spec.agent.abilityRelease === undefined
|
|
828
829
|
? systemPromptBudget
|
|
829
830
|
: Math.max(0, Math.min(systemPromptBudget, Math.max(32 * 1024, systemPromptBudget - 168 * 1024)));
|
|
830
|
-
const systemPromptWithLocalFacts = withLocalExecutionFacts(spec.instructions.systemPrompt, baseSystemPromptBudget, {
|
|
831
|
+
const systemPromptWithLocalFacts = withLocalExecutionFacts(spec.instructions.systemPrompt, baseSystemPromptBudget, {
|
|
832
|
+
...(selfTraining ? { isolateLocalMemory: true } : {}),
|
|
833
|
+
collaborationTools: config.codexCollaborationTools && spec.runtime.name === "codex",
|
|
834
|
+
});
|
|
831
835
|
const boundedSystemPrompt = (context) => appendAgentMemoryContext(typeof systemPromptWithLocalFacts === "string"
|
|
832
836
|
? systemPromptWithLocalFacts
|
|
833
837
|
: systemPromptWithLocalFacts(context), recalledMemory, baseSystemPromptBudget);
|
|
@@ -876,12 +880,13 @@ export async function runExecution(config, input, dependencies) {
|
|
|
876
880
|
} : {}),
|
|
877
881
|
},
|
|
878
882
|
session: {
|
|
879
|
-
enabled: config.resume,
|
|
883
|
+
enabled: selfTraining ? false : config.resume,
|
|
880
884
|
warmMs: config.resumeWarmMs,
|
|
881
885
|
budgetTokens: config.sessionBudgetTokens,
|
|
882
886
|
softTokens: config.sessionSoftTokens,
|
|
883
887
|
maxTurns: config.sessionMaxTurns,
|
|
884
888
|
},
|
|
889
|
+
...(selfTraining ? { maintenancePurpose: "self_training" } : {}),
|
|
885
890
|
localMemoryV2Enabled: config.localMemoryV2Handles?.has(spec.agent.handle) === true,
|
|
886
891
|
};
|
|
887
892
|
const result = await Promise.race([
|
|
@@ -1048,6 +1053,7 @@ export async function runExecution(config, input, dependencies) {
|
|
|
1048
1053
|
}
|
|
1049
1054
|
await dependencies.journal.complete(spec.executionId, completion);
|
|
1050
1055
|
if (completion.outcome === "succeeded"
|
|
1056
|
+
&& spec.instructions.maintenancePurpose !== "self_training"
|
|
1051
1057
|
&& spec.agent.memoryEnabled === true
|
|
1052
1058
|
&& memoryCaptureFinalText !== null
|
|
1053
1059
|
&& dependencies.agentMemory !== undefined) {
|
|
@@ -47,12 +47,13 @@ function takeCompletePromptSections(sections, maxBytes) {
|
|
|
47
47
|
/** v1 server instructions opt in to daemon-owned paths and bounded local workspace context. */
|
|
48
48
|
export function withLocalExecutionFacts(serverPrompt, maxBytes, options = {}) {
|
|
49
49
|
return ({ workspace, resuming, projectContext, trainingProjectContext }) => {
|
|
50
|
-
const memory = capMemoryForInject(workspace.memory);
|
|
50
|
+
const memory = options.isolateLocalMemory ? "" : capMemoryForInject(workspace.memory);
|
|
51
51
|
const workLog = resuming ? "" : capWorkLogForInject(workspace.workLog);
|
|
52
52
|
const collaborationPrompt = options.collaborationTools === true ? buildCollaborationToolsPrompt() : "";
|
|
53
53
|
const mandatoryWorkspacePrompt = `${buildRuntimeWorkspacePrompt(projectContext)}${buildTrainingGitProjectPrompt(trainingProjectContext)}`;
|
|
54
|
+
const crewHome = options.isolateLocalMemory ? workspace.runDir : workspace.dir;
|
|
54
55
|
const localFactSections = [`\n\n## Local execution facts
|
|
55
|
-
- $CREW_HOME: ${
|
|
56
|
+
- $CREW_HOME: ${crewHome}
|
|
56
57
|
- $CREW_TASK_LOG: ${workspace.workLogPath}`,
|
|
57
58
|
...(memory ? [`\n\n## Injected MEMORY.md (bounded local context)\n${memory}`] : []),
|
|
58
59
|
...(workLog ? [`\n\n## Injected work-log (bounded local context)\n${workLog}`] : []),
|
package/dist/local-executor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createInterface } from "node:readline";
|
|
2
2
|
import { readFile, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { delimiter, join } from "node:path";
|
|
4
|
+
import { cleanupSelfTrainingRunDir } from "./self-training-workspace.js";
|
|
4
5
|
import { prepareWorkspace, rotateAgentSession, safeKey, } from "./workspace.js";
|
|
5
6
|
import { CLAUDE_ADDITIONAL_DIRECTORY_INSTRUCTIONS_ENV, isClaudeAdditionalDirectoryInstructionsSupported, probeClaudeVersion, spawnClaude, } from "./runtimes/claude.js";
|
|
6
7
|
import { spawnCodex } from "./runtimes/codex.js";
|
|
@@ -8,7 +9,7 @@ import { DEEPSEEK_CODEX_MODEL, DEEPSEEK_CODEX_REASONING_LEVELS, materializeDeepS
|
|
|
8
9
|
import { materializeDefaultCodexHome } from "./runtimes/codex-home.js";
|
|
9
10
|
import { materializePrivateCodexHome } from "./codex-home-launch.js";
|
|
10
11
|
import { spawnKimi, KIMI_EFFORT_LEVELS } from "./runtimes/kimi.js";
|
|
11
|
-
import { applyDeepSeekHarnessMachineEnv, applyProviderEnv, providerFingerprint, } from "./provider-env.js";
|
|
12
|
+
import { applyDeepSeekHarnessMachineEnv, applyProviderEnv, providerFingerprint, sanitizeEnvVars, } from "./provider-env.js";
|
|
12
13
|
import { augmentedPath } from "./runtime-path.js";
|
|
13
14
|
import { extractFinalText, extractRunMeta, normalizeEvent, parseLine, } from "./normalize.js";
|
|
14
15
|
import { readSession, writeSession, pickResumeId, isNearBudget } from "./session.js";
|
|
@@ -68,14 +69,6 @@ function withoutClaudeInstructionFlag(env) {
|
|
|
68
69
|
const warnRuntimeLocally = (code) => {
|
|
69
70
|
process.stderr.write(`[runtime-warning] ${code}\n`);
|
|
70
71
|
};
|
|
71
|
-
export function sanitizeEnvVars(raw) {
|
|
72
|
-
if (!raw)
|
|
73
|
-
return {};
|
|
74
|
-
return Object.fromEntries(Object.entries(raw).filter(([key, value]) => typeof value === "string"
|
|
75
|
-
&& ENV_KEY_RE.test(key)
|
|
76
|
-
&& !key.toUpperCase().startsWith("CREW_")
|
|
77
|
-
&& !RESERVED_ENV.has(key.toUpperCase())));
|
|
78
|
-
}
|
|
79
72
|
export function awaitExit(child) {
|
|
80
73
|
return new Promise((resolve) => {
|
|
81
74
|
let settled = false;
|
|
@@ -126,6 +119,7 @@ async function launchLegacyRuntime(request) {
|
|
|
126
119
|
effectivePermission: request.effectivePermission,
|
|
127
120
|
...(request.model === undefined ? {} : { model: request.model }),
|
|
128
121
|
...(request.reasoning === undefined ? {} : { reasoning: request.reasoning }),
|
|
122
|
+
...(request.networkAccess === undefined ? {} : { networkAccess: request.networkAccess }),
|
|
129
123
|
};
|
|
130
124
|
if (request.runtime === "claude") {
|
|
131
125
|
const additionalDirectories = request.claudeAdditionalDirectories
|
|
@@ -215,6 +209,7 @@ export async function executeLocal(input, callbacks = {}, dependencies = {}) {
|
|
|
215
209
|
async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
216
210
|
const providerConfig = input.launch.providerConfig ?? {};
|
|
217
211
|
const { runtime } = input;
|
|
212
|
+
const isolatedMaintenance = input.maintenancePurpose === "self_training";
|
|
218
213
|
const isDeepSeekCodex = runtime.name === "codex" && providerConfig.provider === "deepseek";
|
|
219
214
|
const currentModel = isDeepSeekCodex ? DEEPSEEK_CODEX_MODEL : runtime.model ?? null;
|
|
220
215
|
const launchModel = isDeepSeekCodex ? DEEPSEEK_CODEX_MODEL : runtime.model;
|
|
@@ -239,6 +234,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
239
234
|
? {}
|
|
240
235
|
: { sessionContextFingerprint: input.sessionContextFingerprint }),
|
|
241
236
|
...(input.launch.description ? { description: input.launch.description } : {}),
|
|
237
|
+
...(isolatedMaintenance ? { skipLocalMemory: true } : {}),
|
|
242
238
|
}), dependencies.cancellation);
|
|
243
239
|
}
|
|
244
240
|
catch (error) {
|
|
@@ -269,12 +265,23 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
269
265
|
}
|
|
270
266
|
const sourceCodexHome = inheritedEnv.CODEX_HOME
|
|
271
267
|
?? (inheritedEnv.HOME === undefined ? undefined : join(inheritedEnv.HOME, ".codex"));
|
|
268
|
+
let materializedDeepSeekHome;
|
|
272
269
|
try {
|
|
273
270
|
if (isDeepSeekCodex && !providerConfig.providerApiKey) {
|
|
274
271
|
throw new Error("DeepSeek API key is not configured for this Agent");
|
|
275
272
|
}
|
|
276
273
|
if (isDeepSeekCodex) {
|
|
277
|
-
|
|
274
|
+
const providerBaseUrl = providerConfig.providerBaseUrl
|
|
275
|
+
? new URL(providerConfig.providerBaseUrl, input.launch.serverUrl).toString()
|
|
276
|
+
: undefined;
|
|
277
|
+
const materialize = dependencies.materializeDeepSeekCodexHome ?? materializeDeepSeekCodexHome;
|
|
278
|
+
const materializeOptions = {
|
|
279
|
+
...(providerBaseUrl === undefined ? {} : { baseUrl: providerBaseUrl }),
|
|
280
|
+
...(isolatedMaintenance ? { selfTraining: true } : {}),
|
|
281
|
+
};
|
|
282
|
+
materializedDeepSeekHome = await awaitWithCancellation(providerBaseUrl === undefined && !isolatedMaintenance
|
|
283
|
+
? materialize(workspace.homeDir)
|
|
284
|
+
: materialize(workspace.homeDir, materializeOptions), dependencies.cancellation);
|
|
278
285
|
}
|
|
279
286
|
const supportsNativeResume = runtime.name === "claude"
|
|
280
287
|
|| (dependencies.launchRuntime !== undefined && runtimeCapability(runtime.name).nativeResume);
|
|
@@ -402,29 +409,30 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
402
409
|
const systemPrompt = localMemoryResultPath === null
|
|
403
410
|
? baseSystemPrompt
|
|
404
411
|
: `${baseSystemPrompt}${structuredMemoryInstructions ?? ""}`;
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
412
|
+
if (!isolatedMaintenance)
|
|
413
|
+
try {
|
|
414
|
+
localMemoryTelemetry = createLocalMemoryTelemetry({
|
|
415
|
+
executionId: input.executionId,
|
|
416
|
+
agentHandle: input.handle,
|
|
417
|
+
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
418
|
+
runtime: runtime.name,
|
|
419
|
+
stableProtocolRuntime: dependencies.launchRuntime !== undefined,
|
|
420
|
+
agentDir: executionWorkspace.dir,
|
|
421
|
+
runDir: executionWorkspace.runDir,
|
|
422
|
+
isMemoryPrune: memoryPruneTraceId !== null,
|
|
423
|
+
diagnosticsTimeoutMs: dependencies.localMemoryDiagnosticsTimeoutMs
|
|
424
|
+
?? LOCAL_MEMORY_DIAGNOSTICS_TIMEOUT_MS,
|
|
425
|
+
});
|
|
426
|
+
await localMemoryTelemetry.captureBefore();
|
|
427
|
+
}
|
|
428
|
+
catch (error) {
|
|
429
|
+
localMemoryTelemetry = null;
|
|
430
|
+
logLocalMemoryDiagnosticsFailure({
|
|
431
|
+
executionId: input.executionId,
|
|
432
|
+
agentHandle: input.handle,
|
|
433
|
+
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
434
|
+
}, "initialize", error);
|
|
435
|
+
}
|
|
428
436
|
if (memoryPruneTraceId !== null) {
|
|
429
437
|
memoryPruneSharedWriteKey = JSON.stringify([input.launch.agentsRoot, input.handle]);
|
|
430
438
|
const activePruneCount = (activeMemoryPrunes.get(memoryPruneSharedWriteKey) ?? 0) + 1;
|
|
@@ -458,6 +466,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
458
466
|
}
|
|
459
467
|
}
|
|
460
468
|
memoryPruneFailurePhase = "runtime_prepare";
|
|
469
|
+
const crewHome = isolatedMaintenance ? executionWorkspace.runDir : workspace.dir;
|
|
461
470
|
const baseEnv = {
|
|
462
471
|
...inheritedEnv,
|
|
463
472
|
...sanitizeEnvVars(providerConfig.envVars),
|
|
@@ -466,7 +475,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
466
475
|
CREW_SERVER_URL: input.launch.serverUrl,
|
|
467
476
|
CREW_TOKEN: input.launch.token,
|
|
468
477
|
CREW_CHANNEL: input.channelId,
|
|
469
|
-
CREW_HOME:
|
|
478
|
+
CREW_HOME: crewHome,
|
|
470
479
|
// Keep the daemon-selected storage root authoritative for runtimes.
|
|
471
480
|
// In profile-backed NowWork sessions the daemon config may differ from
|
|
472
481
|
// the daemon process environment, so inheriting CREW_AGENTS_ROOT is not
|
|
@@ -476,7 +485,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
476
485
|
...(input.launch.qaReportRoot === undefined ? {} : { QA_REPORT_HUB: input.launch.qaReportRoot }),
|
|
477
486
|
// Expose only the training root; ability-specific workspace layout stays
|
|
478
487
|
// owned by the training package rather than the NowWork daemon.
|
|
479
|
-
QA_RUNTIME_ROOT: join(
|
|
488
|
+
QA_RUNTIME_ROOT: join(crewHome, "training"),
|
|
480
489
|
CREW_TASK_DIR: executionWorkspace.runDir,
|
|
481
490
|
CREW_TASK_LOG: executionWorkspace.workLogPath,
|
|
482
491
|
...(input.wakeMessageId ? { CREW_WAKE_MESSAGE_ID: input.wakeMessageId } : {}),
|
|
@@ -492,7 +501,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
492
501
|
};
|
|
493
502
|
const providerEnv = applyProviderEnv(baseEnv, runtime.name, input.launch.codexHomeMode === undefined
|
|
494
503
|
? providerConfig
|
|
495
|
-
: { ...providerConfig, codexHomeMode: input.launch.codexHomeMode }, workspace.homeDir);
|
|
504
|
+
: { ...providerConfig, codexHomeMode: input.launch.codexHomeMode }, workspace.homeDir, materializedDeepSeekHome);
|
|
496
505
|
const childEnv = runtime.name === "deepseek-harness"
|
|
497
506
|
? applyDeepSeekHarnessMachineEnv(providerEnv, inheritedEnv)
|
|
498
507
|
: providerEnv;
|
|
@@ -503,7 +512,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
503
512
|
qa_runtime_root: childEnv.QA_RUNTIME_ROOT ?? null,
|
|
504
513
|
qa_runtime_root_present: childEnv.QA_RUNTIME_ROOT !== undefined,
|
|
505
514
|
inherited_qa_runtime_root_present: inheritedEnv.QA_RUNTIME_ROOT !== undefined,
|
|
506
|
-
training_root: join(
|
|
515
|
+
training_root: join(crewHome, "training"),
|
|
507
516
|
project_context_present: input.projectContext !== undefined,
|
|
508
517
|
project_ids: JSON.stringify(input.projectContext === undefined
|
|
509
518
|
? []
|
|
@@ -635,6 +644,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
635
644
|
...(input.projectContext === undefined ? {} : {
|
|
636
645
|
projectContext: input.projectContext,
|
|
637
646
|
}),
|
|
647
|
+
...(isolatedMaintenance && runtime.name === "codex" ? { networkAccess: true } : {}),
|
|
638
648
|
...(input.projectContext === undefined && workspaceRoots.length === 0
|
|
639
649
|
? {}
|
|
640
650
|
: { workspaceRoots: Object.freeze(workspaceRoots) }),
|
|
@@ -1118,5 +1128,8 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
1118
1128
|
const detail = error instanceof Error ? error.message : String(error);
|
|
1119
1129
|
process.stderr.write(`[execution] failed to remove prompt ${workspace.systemPromptPath}: ${detail}\n`);
|
|
1120
1130
|
}
|
|
1131
|
+
if (isolatedMaintenance) {
|
|
1132
|
+
await cleanupSelfTrainingRunDir(join(workspace.dir, "tasks"), executionWorkspace.runDir);
|
|
1133
|
+
}
|
|
1121
1134
|
}
|
|
1122
1135
|
}
|
package/dist/machine-info.js
CHANGED
|
@@ -25,7 +25,9 @@ export { executableRuntimes } from "./runtime-capabilities.js";
|
|
|
25
25
|
const execFileP = promisify(execFile);
|
|
26
26
|
export const PROJECT_WORKSPACES_CAPABILITY = "project_workspaces_v1";
|
|
27
27
|
export const TRAINING_PROJECT_DEPENDENCIES_CAPABILITY = "training_project_dependencies_v1";
|
|
28
|
+
export const SELF_TRAINING_EXECUTION_CAPABILITY = "self_training_execution_v1";
|
|
28
29
|
export const EXECUTION_LARGE_ATTACHMENTS_CAPABILITY = "execution_attachments_300m_v1";
|
|
30
|
+
export const PROJECT_SKILL_PROJECTION_CAPABILITY = "project_skill_projection_v2";
|
|
29
31
|
export const NATIVE_PROJECT_WORKSPACE_READINESS = Object.freeze({
|
|
30
32
|
resolverReady: true,
|
|
31
33
|
nativeRuntimeAdaptersReady: true,
|
|
@@ -42,6 +44,7 @@ export const DAEMON_CAPABILITIES = Object.freeze([
|
|
|
42
44
|
"execution_machine_queue_v1",
|
|
43
45
|
"execution_agent_memory_policy_v1",
|
|
44
46
|
"execution_agent_memory_mapping_v1",
|
|
47
|
+
SELF_TRAINING_EXECUTION_CAPABILITY,
|
|
45
48
|
"project_skills_v1",
|
|
46
49
|
"project_skill_projection_v2",
|
|
47
50
|
PROJECT_WORKSPACES_CAPABILITY,
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { PROJECT_SKILLS_CAPABILITY, PROJECT_SKILL_PROJECTION_V2_CAPABILITY, } from "./types.js";
|
|
2
|
+
export function projectSkillV2RolloutReady(platform, readiness) {
|
|
3
|
+
const platformReady = platform === "darwin"
|
|
4
|
+
|| platform === "linux"
|
|
5
|
+
|| (platform === "win32" && readiness.nativeWindowsSmokePassed);
|
|
6
|
+
return platformReady
|
|
7
|
+
&& readiness.runtimeRootStorePrimitiveReady
|
|
8
|
+
&& readiness.runtimeRootStoreRecoveryReady
|
|
9
|
+
&& readiness.leaseRecoveryReady
|
|
10
|
+
&& readiness.controllerReady
|
|
11
|
+
&& readiness.executionHandlerReady
|
|
12
|
+
&& readiness.codexAdapterReady
|
|
13
|
+
&& readiness.claudeAdapterReady;
|
|
14
|
+
}
|
|
15
|
+
export function effectiveProjectSkillCapabilities(capabilities, projectSkillsReady, projectSkillV2Ready) {
|
|
16
|
+
const projectSkillCapabilitiesReady = projectSkillsReady && projectSkillV2Ready;
|
|
17
|
+
if (!projectSkillCapabilitiesReady
|
|
18
|
+
&& !capabilities.includes(PROJECT_SKILLS_CAPABILITY)
|
|
19
|
+
&& !capabilities.includes(PROJECT_SKILL_PROJECTION_V2_CAPABILITY)
|
|
20
|
+
&& Object.isFrozen(capabilities))
|
|
21
|
+
return capabilities;
|
|
22
|
+
const filtered = capabilities.filter((capability) => capability !== PROJECT_SKILL_PROJECTION_V2_CAPABILITY
|
|
23
|
+
&& (projectSkillCapabilitiesReady || capability !== PROJECT_SKILLS_CAPABILITY));
|
|
24
|
+
if (!projectSkillCapabilitiesReady || !filtered.includes(PROJECT_SKILLS_CAPABILITY)) {
|
|
25
|
+
return Object.freeze(filtered);
|
|
26
|
+
}
|
|
27
|
+
const v1Index = filtered.indexOf(PROJECT_SKILLS_CAPABILITY);
|
|
28
|
+
return Object.freeze([
|
|
29
|
+
...filtered.slice(0, v1Index + 1),
|
|
30
|
+
PROJECT_SKILL_PROJECTION_V2_CAPABILITY,
|
|
31
|
+
...filtered.slice(v1Index + 1),
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
export function withProjectSkillCapabilityStatus(value, status) {
|
|
35
|
+
return {
|
|
36
|
+
...value,
|
|
37
|
+
projectSkillsStatus: status,
|
|
38
|
+
capabilities: status === "ready"
|
|
39
|
+
? value.capabilities
|
|
40
|
+
: effectiveProjectSkillCapabilities(value.capabilities, false, false),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const settleReadinessGate = async (operation) => {
|
|
44
|
+
try {
|
|
45
|
+
return await operation() === true;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
export async function createProjectSkillConnectionCapabilitySnapshot(input) {
|
|
52
|
+
const runtimeRootStorePrimitiveReady = await settleReadinessGate(input.probeRuntimeRootStorePrimitive);
|
|
53
|
+
const controllerReady = await settleReadinessGate(input.initializeController);
|
|
54
|
+
const recoveryReady = await settleReadinessGate(input.recoverRuntimeRootsAndLeases);
|
|
55
|
+
const readiness = Object.freeze({
|
|
56
|
+
runtimeRootStorePrimitiveReady,
|
|
57
|
+
runtimeRootStoreRecoveryReady: recoveryReady,
|
|
58
|
+
leaseRecoveryReady: recoveryReady,
|
|
59
|
+
controllerReady,
|
|
60
|
+
executionHandlerReady: true,
|
|
61
|
+
codexAdapterReady: true,
|
|
62
|
+
claudeAdapterReady: true,
|
|
63
|
+
nativeWindowsSmokePassed: false,
|
|
64
|
+
});
|
|
65
|
+
const projectSkillsReady = projectSkillV2RolloutReady(input.platform, readiness);
|
|
66
|
+
return Object.freeze({
|
|
67
|
+
capabilities: effectiveProjectSkillCapabilities(input.baseCapabilities, projectSkillsReady, projectSkillsReady),
|
|
68
|
+
projectSkillsReady,
|
|
69
|
+
readiness,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export async function prepareProjectSkillConnectionCapabilities(input) {
|
|
73
|
+
const snapshot = await createProjectSkillConnectionCapabilitySnapshot({
|
|
74
|
+
...input,
|
|
75
|
+
baseCapabilities: [...input.baseCapabilities, ...await input.additionalCapabilities()],
|
|
76
|
+
});
|
|
77
|
+
input.applyReadiness(snapshot.projectSkillsReady);
|
|
78
|
+
return snapshot.capabilities;
|
|
79
|
+
}
|
|
80
|
+
export function createProjectSkillControllerReadiness(input) {
|
|
81
|
+
let status = "initializing";
|
|
82
|
+
let initialization = null;
|
|
83
|
+
const ensure = () => {
|
|
84
|
+
if (status === "ready")
|
|
85
|
+
return Promise.resolve(true);
|
|
86
|
+
if (initialization !== null)
|
|
87
|
+
return initialization;
|
|
88
|
+
status = "initializing";
|
|
89
|
+
const attempt = input.initialize().then(() => {
|
|
90
|
+
status = "ready";
|
|
91
|
+
return true;
|
|
92
|
+
}, (error) => {
|
|
93
|
+
status = "unavailable";
|
|
94
|
+
input.onUnavailable(error);
|
|
95
|
+
return false;
|
|
96
|
+
}).finally(() => {
|
|
97
|
+
if (initialization === attempt)
|
|
98
|
+
initialization = null;
|
|
99
|
+
input.onSettled();
|
|
100
|
+
});
|
|
101
|
+
initialization = attempt;
|
|
102
|
+
return attempt;
|
|
103
|
+
};
|
|
104
|
+
return Object.freeze({
|
|
105
|
+
status: () => status,
|
|
106
|
+
ensure,
|
|
107
|
+
applyPreflight: (ready) => { status = ready ? "ready" : "unavailable"; },
|
|
108
|
+
});
|
|
109
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ProjectProjectionError, } from "./reconciler.js";
|
|
2
|
+
export const MAX_REMEMBERED_PROJECT_SKILL_AGENTS = 64;
|
|
3
|
+
const compareBinary = (left, right) => {
|
|
4
|
+
if (left < right)
|
|
5
|
+
return -1;
|
|
6
|
+
if (left > right)
|
|
7
|
+
return 1;
|
|
8
|
+
return 0;
|
|
9
|
+
};
|
|
10
|
+
const copySnapshot = (snapshot) => Object.freeze({
|
|
11
|
+
bindings: Object.freeze(snapshot.bindings.map((binding) => Object.freeze({ ...binding }))),
|
|
12
|
+
generation: snapshot.generation,
|
|
13
|
+
});
|
|
14
|
+
export function createProjectSkillSnapshotEpoch(maxEntries = MAX_REMEMBERED_PROJECT_SKILL_AGENTS) {
|
|
15
|
+
if (!Number.isSafeInteger(maxEntries) || maxEntries < 1) {
|
|
16
|
+
throw new ProjectProjectionError("skill_projection_failed");
|
|
17
|
+
}
|
|
18
|
+
const snapshots = new Map();
|
|
19
|
+
return Object.freeze({
|
|
20
|
+
begin() {
|
|
21
|
+
snapshots.clear();
|
|
22
|
+
},
|
|
23
|
+
remember(handle, snapshot) {
|
|
24
|
+
const previous = snapshots.get(handle);
|
|
25
|
+
if (previous !== undefined && snapshot.generation < previous.generation)
|
|
26
|
+
return;
|
|
27
|
+
if (previous === undefined && snapshots.size >= maxEntries) {
|
|
28
|
+
throw new ProjectProjectionError("skill_projection_failed");
|
|
29
|
+
}
|
|
30
|
+
snapshots.set(handle, copySnapshot(snapshot));
|
|
31
|
+
},
|
|
32
|
+
forget(handle) {
|
|
33
|
+
snapshots.delete(handle);
|
|
34
|
+
},
|
|
35
|
+
entries() {
|
|
36
|
+
return Object.freeze([...snapshots.entries()]
|
|
37
|
+
.sort(([left], [right]) => compareBinary(left, right))
|
|
38
|
+
.map(([handle, snapshot]) => Object.freeze([handle, copySnapshot(snapshot)])));
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const stableErrorCode = (reason) => reason?.code === "skill_projection_snapshot_corrupt"
|
|
43
|
+
? "skill_projection_snapshot_corrupt"
|
|
44
|
+
: "skill_projection_failed";
|
|
45
|
+
export function toPathPrivateConvergenceResults(entries, results) {
|
|
46
|
+
return Object.freeze(entries.map(([handle], index) => {
|
|
47
|
+
const result = results[index];
|
|
48
|
+
if (result?.status === "fulfilled") {
|
|
49
|
+
return Object.freeze({ handle, status: "fulfilled" });
|
|
50
|
+
}
|
|
51
|
+
return Object.freeze({
|
|
52
|
+
handle,
|
|
53
|
+
status: "rejected",
|
|
54
|
+
errorCode: stableErrorCode(result?.reason),
|
|
55
|
+
});
|
|
56
|
+
}));
|
|
57
|
+
}
|