@nowcrew/daemon 0.6.30 → 0.6.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/dist/agent-ability/materializer.js +4 -4
- package/dist/config.js +3 -3
- package/dist/execution-runner.js +17 -13
- package/dist/host-execution-coordinator.js +169 -52
- package/dist/local-executor.js +107 -34
- package/dist/project-skills/reconciler.js +5 -2
- package/dist/remote/claude-bridge.js +558 -0
- package/dist/remote/claude-channel.js +164 -0
- package/dist/remote/codex-client.js +451 -0
- package/dist/remote/codex-runtime.js +77 -0
- package/dist/remote/config.js +135 -0
- package/dist/remote/gateway.js +879 -0
- package/dist/remote/identity.js +39 -0
- package/dist/remote/owner.js +77 -0
- package/dist/remote/protocol.js +211 -0
- package/dist/remote/remote-cli.js +254 -0
- package/dist/remote/runtime-probe.js +182 -0
- package/dist/remote/session-discovery.js +249 -0
- package/dist/remote/wrapper.js +40 -0
- package/dist/remote-web/assets/index-B_6VM_tw.js +94 -0
- package/dist/remote-web/assets/index-L6EiQbJn.css +1 -0
- package/dist/remote-web/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/remote-web/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/remote-web/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/remote-web/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/remote-web/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/remote-web/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/remote-web/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/remote-web/icons/nowwork-192.png +0 -0
- package/dist/remote-web/icons/nowwork-512.png +0 -0
- package/dist/remote-web/icons/nowwork.svg +7 -0
- package/dist/remote-web/index.html +20 -0
- package/dist/remote-web/manifest.webmanifest +13 -0
- package/dist/remote-web/sw.js +12 -0
- package/dist/runner.js +6 -1
- package/dist/runtime-startup-gate.js +47 -23
- package/dist/runtimes/codex-app-server-runner.js +6 -0
- package/dist/serve.js +55 -3
- package/dist/shared-execution-slots.js +75 -16
- package/package.json +1 -1
package/dist/local-executor.js
CHANGED
|
@@ -19,7 +19,7 @@ import { decodeExternalOutputEvent, extractExternalAnswer, ExternalAnswerDecoder
|
|
|
19
19
|
import { cleanupMaterializedAttachments as cleanupAttachments, executionAttachmentDirectory, materializeAttachments, } from "./attachments.js";
|
|
20
20
|
import { routeRuntimeAttachments, runtimeCapability, } from "./runtime-capabilities.js";
|
|
21
21
|
import { awaitWithCancellation, RuntimeCancelledError, } from "./runtime-cancellation.js";
|
|
22
|
-
import { isRuntimeReadyEvent, } from "./runtime-startup-gate.js";
|
|
22
|
+
import { isRuntimeReadyEvent, isRuntimeRunningEvent, } from "./runtime-startup-gate.js";
|
|
23
23
|
import { dslog } from "./slog.js";
|
|
24
24
|
import { boundedDiagnosticJsonArray } from "./diagnostic-json.js";
|
|
25
25
|
import { ProjectProjectionError, } from "./project-skills/reconciler.js";
|
|
@@ -61,6 +61,7 @@ function logMemoryPruneDiagnosticsFailure(input, traceId, phase, error) {
|
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
63
|
const STDERR_TAIL_CAP = 2_000;
|
|
64
|
+
const RUNTIME_RUNNING_CALLBACK_TIMEOUT_MS = 10_000;
|
|
64
65
|
const MEMORY_PRUNE_DIAGNOSTICS_TIMEOUT_MS = 2_000;
|
|
65
66
|
const LOCAL_MEMORY_DIAGNOSTICS_TIMEOUT_MS = 250;
|
|
66
67
|
const CLAUDE_INSTRUCTION_WARNING = "claude_additional_directory_instructions_unverified";
|
|
@@ -266,7 +267,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
266
267
|
}
|
|
267
268
|
let materialized = null;
|
|
268
269
|
let knownAttachmentDirectory = null;
|
|
269
|
-
|
|
270
|
+
const startupReservationState = { current: null };
|
|
270
271
|
let memoryPruneTraceId = null;
|
|
271
272
|
let memoryPruneRuntimeExitCode;
|
|
272
273
|
let memoryPruneExecutorCompleted = false;
|
|
@@ -479,31 +480,11 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
479
480
|
const launchRuntime = dependencies.launchRuntime ?? launchLegacyRuntime;
|
|
480
481
|
if (dependencies.cancellation?.isRequested())
|
|
481
482
|
throw new RuntimeCancelledError();
|
|
482
|
-
startupReservation = dependencies.startupGate?.reserve(runtime.name) ?? null;
|
|
483
|
-
if (startupReservation !== null) {
|
|
484
|
-
const startupQueueEnteredAt = Date.now();
|
|
485
|
-
dslog("runtime.start_queued", "runtime 等待启动许可", {
|
|
486
|
-
execution_id: input.executionId,
|
|
487
|
-
runtime: runtime.name,
|
|
488
|
-
queued: startupReservation.isQueued(),
|
|
489
|
-
});
|
|
490
|
-
try {
|
|
491
|
-
await awaitWithCancellation(startupReservation.ready, dependencies.cancellation);
|
|
492
|
-
dslog("runtime.start_granted", "runtime 获得启动许可", {
|
|
493
|
-
execution_id: input.executionId,
|
|
494
|
-
runtime: runtime.name,
|
|
495
|
-
startup_queue_ms: Date.now() - startupQueueEnteredAt,
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
catch (error) {
|
|
499
|
-
startupReservation.release();
|
|
500
|
-
throw error;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
const runtimeLaunchAt = Date.now();
|
|
504
|
-
memoryPruneFailurePhase = "runtime_launch";
|
|
505
483
|
let activeProjectSkillRuntimeRoot;
|
|
506
|
-
const
|
|
484
|
+
const abilityContext = input.abilityRelease !== undefined && dependencies.abilityRelease !== undefined
|
|
485
|
+
? await dependencies.abilityRelease.prepareAndLaunch(input.launch.agentsRoot, input.handle, input.abilityRelease, async (context) => context)
|
|
486
|
+
: undefined;
|
|
487
|
+
const prepareRuntimeLaunch = async (runtimeRoot) => {
|
|
507
488
|
activeProjectSkillRuntimeRoot = runtimeRoot;
|
|
508
489
|
const effectiveSystemPrompt = abilityContext === undefined
|
|
509
490
|
? systemPrompt
|
|
@@ -602,24 +583,55 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
602
583
|
projectContext: input.projectContext,
|
|
603
584
|
}),
|
|
604
585
|
};
|
|
586
|
+
return launchRequest;
|
|
587
|
+
};
|
|
588
|
+
let runtimeLaunchAt = Date.now();
|
|
589
|
+
const launchPreparedRuntime = async (runtimeRoot) => {
|
|
590
|
+
const launchRequest = await prepareRuntimeLaunch(runtimeRoot);
|
|
591
|
+
if (dependencies.cancellation?.isRequested())
|
|
592
|
+
throw new RuntimeCancelledError();
|
|
593
|
+
const startupLane = memoryPruneTraceId === null ? "foreground" : "memory_prune";
|
|
594
|
+
startupReservationState.current = dependencies.startupGate?.reserve(runtime.name, startupLane) ?? null;
|
|
595
|
+
const startupReservation = startupReservationState.current;
|
|
596
|
+
if (startupReservation !== null) {
|
|
597
|
+
const startupQueueEnteredAt = Date.now();
|
|
598
|
+
dslog("runtime.start_queued", "runtime 等待启动许可", {
|
|
599
|
+
execution_id: input.executionId,
|
|
600
|
+
runtime: runtime.name,
|
|
601
|
+
startup_lane: startupLane,
|
|
602
|
+
queued: startupReservation.isQueued(),
|
|
603
|
+
});
|
|
604
|
+
try {
|
|
605
|
+
await awaitWithCancellation(startupReservation.ready, dependencies.cancellation);
|
|
606
|
+
dslog("runtime.start_granted", "runtime 获得启动许可", {
|
|
607
|
+
execution_id: input.executionId,
|
|
608
|
+
runtime: runtime.name,
|
|
609
|
+
startup_lane: startupLane,
|
|
610
|
+
startup_queue_ms: Date.now() - startupQueueEnteredAt,
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
catch (error) {
|
|
614
|
+
startupReservation.release();
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
await callbacks.onRuntimeStarting?.(runtime.name);
|
|
619
|
+
runtimeLaunchAt = Date.now();
|
|
605
620
|
memoryPruneFailurePhase = "runtime_launch";
|
|
606
621
|
return launchRuntime(launchRequest);
|
|
607
622
|
};
|
|
608
|
-
const launchWithAbility = (runtimeRoot) => input.abilityRelease !== undefined && dependencies.abilityRelease !== undefined
|
|
609
|
-
? dependencies.abilityRelease.prepareAndLaunch(input.launch.agentsRoot, input.handle, input.abilityRelease, (abilityContext) => launchPreparedRuntime(runtimeRoot, abilityContext))
|
|
610
|
-
: launchPreparedRuntime(runtimeRoot);
|
|
611
623
|
let child;
|
|
612
624
|
if (input.projectSkills !== undefined && dependencies.projectSkills !== undefined) {
|
|
613
625
|
const launchOwner = dependencies.projectSkillLeaseSafeLaunchOwner;
|
|
614
626
|
if (launchOwner === undefined)
|
|
615
627
|
throw new ProjectProjectionError("skill_projection_failed");
|
|
616
|
-
child = await dependencies.projectSkills.prepareAndLaunch(input.launch.agentsRoot, input.executionId, input.handle, input.projectSkills, launchOwner.claim(
|
|
628
|
+
child = await dependencies.projectSkills.prepareAndLaunch(input.launch.agentsRoot, input.executionId, input.handle, input.projectSkills, launchOwner.claim(launchPreparedRuntime), (warning) => callbacks.onConsole?.({
|
|
617
629
|
stream: "system",
|
|
618
630
|
text: formatProjectSkillRuntimeWarning(warning),
|
|
619
631
|
}));
|
|
620
632
|
}
|
|
621
633
|
else {
|
|
622
|
-
child = await
|
|
634
|
+
child = await launchPreparedRuntime();
|
|
623
635
|
}
|
|
624
636
|
localMemoryTelemetry?.markRuntimeStarted();
|
|
625
637
|
memoryPruneFailurePhase = "runtime_execution";
|
|
@@ -640,15 +652,24 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
640
652
|
// 每轮独立:tool_use/result 关联状态不能跨 execution 泄漏。
|
|
641
653
|
const consoleFormatter = createConsoleFormatter();
|
|
642
654
|
let runtimeReady = false;
|
|
655
|
+
let runtimeRunning = false;
|
|
643
656
|
let resolveRuntimeReady;
|
|
644
657
|
const runtimeReadySignal = new Promise((resolve) => { resolveRuntimeReady = resolve; });
|
|
645
658
|
let runtimeReadyNotification = Promise.resolve();
|
|
659
|
+
let runtimeRunningNotification = Promise.resolve();
|
|
660
|
+
let rejectRuntimeRunningFailure;
|
|
661
|
+
const runtimeRunningFailure = new Promise((_resolve, reject) => {
|
|
662
|
+
rejectRuntimeRunningFailure = reject;
|
|
663
|
+
});
|
|
664
|
+
// The failure can arrive in the same stdout turn before the exit race is installed.
|
|
665
|
+
// Attach a handler immediately while retaining the original rejection for that race.
|
|
666
|
+
void runtimeRunningFailure.catch(() => undefined);
|
|
646
667
|
const markRuntimeReady = () => {
|
|
647
668
|
if (runtimeReady)
|
|
648
669
|
return;
|
|
649
670
|
runtimeReady = true;
|
|
650
671
|
localMemoryTelemetry?.markRuntimeReady();
|
|
651
|
-
|
|
672
|
+
startupReservationState.current?.release();
|
|
652
673
|
dslog("runtime.start_ready", "runtime 已完成初始化", {
|
|
653
674
|
execution_id: input.executionId,
|
|
654
675
|
runtime: runtime.name,
|
|
@@ -657,6 +678,51 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
657
678
|
runtimeReadyNotification = Promise.resolve(callbacks.onRuntimeReady?.(runtime.name));
|
|
658
679
|
resolveRuntimeReady();
|
|
659
680
|
};
|
|
681
|
+
const markRuntimeRunning = () => {
|
|
682
|
+
if (runtimeRunning)
|
|
683
|
+
return;
|
|
684
|
+
runtimeRunning = true;
|
|
685
|
+
let callbackTimer;
|
|
686
|
+
runtimeRunningNotification = Promise.race([
|
|
687
|
+
Promise.resolve().then(() => callbacks.onRuntimeRunning?.(runtime.name)),
|
|
688
|
+
new Promise((_resolve, reject) => {
|
|
689
|
+
const callbackTimeoutMs = dependencies.runtimeRunningCallbackTimeoutMs
|
|
690
|
+
?? RUNTIME_RUNNING_CALLBACK_TIMEOUT_MS;
|
|
691
|
+
callbackTimer = setTimeout(() => reject(new Error(`${runtime.name} runtime-running callback timed out after ${callbackTimeoutMs}ms`)), callbackTimeoutMs);
|
|
692
|
+
}),
|
|
693
|
+
]).finally(() => {
|
|
694
|
+
if (callbackTimer !== undefined)
|
|
695
|
+
clearTimeout(callbackTimer);
|
|
696
|
+
});
|
|
697
|
+
void runtimeRunningNotification.catch((error) => {
|
|
698
|
+
// Persisting the running phase is part of execution liveness. Propagate
|
|
699
|
+
// its failure immediately: cancellation is best-effort and must not be
|
|
700
|
+
// allowed to keep the execution or its slots alive indefinitely.
|
|
701
|
+
rejectRuntimeRunningFailure(error);
|
|
702
|
+
try {
|
|
703
|
+
void child.cancel?.().catch((cancelError) => {
|
|
704
|
+
dslog("runtime.running_callback_cancel_failed", "runtime-running 回调失败后的取消也失败", {
|
|
705
|
+
level: "ERROR",
|
|
706
|
+
execution_id: input.executionId,
|
|
707
|
+
runtime: runtime.name,
|
|
708
|
+
error_message: cancelError instanceof Error
|
|
709
|
+
? cancelError.message.slice(0, 500)
|
|
710
|
+
: String(cancelError).slice(0, 500),
|
|
711
|
+
});
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
catch (cancelError) {
|
|
715
|
+
dslog("runtime.running_callback_cancel_failed", "runtime-running 回调失败后的取消也失败", {
|
|
716
|
+
level: "ERROR",
|
|
717
|
+
execution_id: input.executionId,
|
|
718
|
+
runtime: runtime.name,
|
|
719
|
+
error_message: cancelError instanceof Error
|
|
720
|
+
? cancelError.message.slice(0, 500)
|
|
721
|
+
: String(cancelError).slice(0, 500),
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
};
|
|
660
726
|
const readline = createInterface({ input: child.stdout });
|
|
661
727
|
readline.on("line", (line) => {
|
|
662
728
|
const event = parseLine(line);
|
|
@@ -665,6 +731,11 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
665
731
|
localMemoryTelemetry?.observe(event);
|
|
666
732
|
if (isRuntimeReadyEvent(runtime.name, event))
|
|
667
733
|
markRuntimeReady();
|
|
734
|
+
if (isRuntimeRunningEvent(runtime.name, event)) {
|
|
735
|
+
if (!runtimeReady)
|
|
736
|
+
markRuntimeReady();
|
|
737
|
+
markRuntimeRunning();
|
|
738
|
+
}
|
|
668
739
|
const meta = extractRunMeta(event);
|
|
669
740
|
if (meta.sessionId)
|
|
670
741
|
sessionId = meta.sessionId;
|
|
@@ -723,6 +794,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
723
794
|
child.stderr.on("end", () => codexStartupStageParser?.finish());
|
|
724
795
|
let runtimeExit;
|
|
725
796
|
try {
|
|
797
|
+
const startupReservation = startupReservationState.current;
|
|
726
798
|
if (startupReservation !== null) {
|
|
727
799
|
let startupTimer;
|
|
728
800
|
let startupOutcome;
|
|
@@ -761,7 +833,8 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
761
833
|
}
|
|
762
834
|
await runtimeReadyNotification;
|
|
763
835
|
}
|
|
764
|
-
runtimeExit = await awaitWithCancellation(child.exit, dependencies.cancellation);
|
|
836
|
+
runtimeExit = await awaitWithCancellation(Promise.race([child.exit, runtimeRunningFailure]), dependencies.cancellation);
|
|
837
|
+
await runtimeRunningNotification;
|
|
765
838
|
}
|
|
766
839
|
catch (error) {
|
|
767
840
|
if (error instanceof RuntimeCancelledError) {
|
|
@@ -831,7 +904,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
831
904
|
};
|
|
832
905
|
}
|
|
833
906
|
finally {
|
|
834
|
-
|
|
907
|
+
startupReservationState.current?.release();
|
|
835
908
|
try {
|
|
836
909
|
await localMemoryTelemetry?.finish();
|
|
837
910
|
}
|
|
@@ -105,7 +105,7 @@ export const canonicalTrainingSkillLinkTarget = (source, link, trainingSkillsRoo
|
|
|
105
105
|
: null;
|
|
106
106
|
};
|
|
107
107
|
export const isTrainingSkillLink = (source, link, trainingSkillsRoot, platform) => canonicalTrainingSkillLinkTarget(source, link, trainingSkillsRoot, platform) !== null;
|
|
108
|
-
const preserveNonProjectSkills = async (projectionTarget, trainingSkillsRoot, platform) => {
|
|
108
|
+
const preserveNonProjectSkills = async (projectionTarget, trainingSkillsRoot, platform, projectSkillNames) => {
|
|
109
109
|
const names = new Set();
|
|
110
110
|
if (!await exists(projectionTarget.target))
|
|
111
111
|
return names;
|
|
@@ -130,6 +130,8 @@ const preserveNonProjectSkills = async (projectionTarget, trainingSkillsRoot, pl
|
|
|
130
130
|
const canonicalTarget = canonicalTrainingSkillLinkTarget(source, link, trainingSkillsRoot, platform);
|
|
131
131
|
if (canonicalTarget === null)
|
|
132
132
|
continue;
|
|
133
|
+
if (projectSkillNames.has(entry.name))
|
|
134
|
+
continue;
|
|
133
135
|
await symlink(platform === "win32" ? canonicalTarget : link, destination, platform === "win32" ? "junction" : "dir");
|
|
134
136
|
}
|
|
135
137
|
else {
|
|
@@ -194,6 +196,7 @@ export function createProjectSkillsReconciler(deps) {
|
|
|
194
196
|
resolutionRecords.push(Object.freeze({ ...binding, sourcePath: null, mode: "missing" }));
|
|
195
197
|
}
|
|
196
198
|
}
|
|
199
|
+
const linkedNames = new Set(linked.map((item) => item.binding.skillName));
|
|
197
200
|
const id = randomUUID();
|
|
198
201
|
const targets = projectionTargets(agentRoot, id);
|
|
199
202
|
const nextProjectionDiagnostics = [];
|
|
@@ -202,7 +205,7 @@ export function createProjectSkillsReconciler(deps) {
|
|
|
202
205
|
await mkdir(dirname(target.target), { recursive: true });
|
|
203
206
|
await mkdir(target.staging, { mode: 0o700 });
|
|
204
207
|
await markProjectionStaging(target, id);
|
|
205
|
-
const preservedNames = await preserveNonProjectSkills(target, join(agentRoot, "training", "skills"), platform);
|
|
208
|
+
const preservedNames = await preserveNonProjectSkills(target, join(agentRoot, "training", "skills"), platform, linkedNames);
|
|
206
209
|
for (const item of linked) {
|
|
207
210
|
if (preservedNames.has(item.binding.skillName)) {
|
|
208
211
|
throw new ProjectProjectionError("skill_name_conflict");
|