@kontextmind/kxm 0.7.14 → 0.7.15
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/.claude-plugin/marketplace.json +1 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +16 -3
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime.js +259 -70
- package/plugins/kxm/dist/vnext-runtime-supervisor.js +259 -70
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli/vnext.ts +20 -3
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/vnext-engine.ts +183 -3
- package/plugins/kxm/src/vnext-runtime-owner.ts +50 -0
- package/plugins/kxm/src/vnext-runtime-supervisor.ts +83 -58
- package/plugins/kxm/src/vnext-runtime.ts +9 -8
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "kxm",
|
|
4
4
|
"displayName": "KXM",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.15",
|
|
6
6
|
"description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "KontextMind",
|
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -33101,6 +33101,7 @@ function verifyVnextMigration(projectRoot, options = {}) {
|
|
|
33101
33101
|
}
|
|
33102
33102
|
|
|
33103
33103
|
// plugins/kxm/src/cli/vnext.ts
|
|
33104
|
+
var vnextDriveCliSeams = {};
|
|
33104
33105
|
var repoRoot3 = resolve20(fileURLToPath4(new URL("../../../../", import.meta.url)));
|
|
33105
33106
|
function initPlanPayload(plan) {
|
|
33106
33107
|
return {
|
|
@@ -33544,9 +33545,21 @@ async function cmdVnextRunDrive(runtime, runId, simulated) {
|
|
|
33544
33545
|
print(runtime.io, runtime.json, { ok: true, command: "runs drive", dryRun: true, runId, mode }, `drive plan: run ${runId} in ${mode} mode (no events written)`);
|
|
33545
33546
|
return 0;
|
|
33546
33547
|
}
|
|
33547
|
-
const supervisor = await ensureVnextSupervisor({ env: runtime.env });
|
|
33548
|
-
const result = await vnextRuntimeRequest(supervisor, "POST", `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`, { mode });
|
|
33549
|
-
|
|
33548
|
+
const supervisor = await (vnextDriveCliSeams.ensureSupervisor ?? ensureVnextSupervisor)({ env: runtime.env });
|
|
33549
|
+
const result = await (vnextDriveCliSeams.runtimeRequest ?? vnextRuntimeRequest)(supervisor, "POST", `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`, { mode });
|
|
33550
|
+
const driveId = result.driveId;
|
|
33551
|
+
const poll = result.poll;
|
|
33552
|
+
const status = result.status;
|
|
33553
|
+
if (typeof driveId !== "string" || driveId.length === 0 || typeof poll !== "string" || poll.length === 0 || status !== "accepted") {
|
|
33554
|
+
print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "run_drive_io_failed" }, "run drive failed because a local operation did not complete");
|
|
33555
|
+
return 1;
|
|
33556
|
+
}
|
|
33557
|
+
print(
|
|
33558
|
+
runtime.io,
|
|
33559
|
+
runtime.json,
|
|
33560
|
+
{ ok: true, command: "runs drive", runId, driveId, poll, mode, status },
|
|
33561
|
+
`drive ${driveId}: accepted (poll ${poll})`
|
|
33562
|
+
);
|
|
33550
33563
|
return 0;
|
|
33551
33564
|
} catch (error) {
|
|
33552
33565
|
if (error instanceof VnextConfigError) {
|
|
@@ -17036,7 +17036,7 @@ async function deliverInboxNotification(messageId, delivered, notify) {
|
|
|
17036
17036
|
}
|
|
17037
17037
|
|
|
17038
17038
|
// plugins/kxm/src/mcp-server.ts
|
|
17039
|
-
var VERSION = "0.7.
|
|
17039
|
+
var VERSION = "0.7.15";
|
|
17040
17040
|
var inbox = /* @__PURE__ */ new Map();
|
|
17041
17041
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
17042
17042
|
var meshClient;
|
|
@@ -21877,6 +21877,32 @@ function vnextGateHold(storePath, runId) {
|
|
|
21877
21877
|
function vnextAdmittedToken(storePath, runId) {
|
|
21878
21878
|
return owners.get(storePath)?.admitted.get(runId)?.token;
|
|
21879
21879
|
}
|
|
21880
|
+
function attachVnextDriveSession(storePath, runId, token, session) {
|
|
21881
|
+
const owner = record(storePath);
|
|
21882
|
+
const current = owner.admitted.get(runId);
|
|
21883
|
+
if (!current || current.token !== token) {
|
|
21884
|
+
throw runtimeError("run_events_illegal", runId, "drive session requires the exact admitted token");
|
|
21885
|
+
}
|
|
21886
|
+
if (current.driveSession) {
|
|
21887
|
+
throw runtimeError("run_busy", runId, `run ${runId} already has a drive session`);
|
|
21888
|
+
}
|
|
21889
|
+
current.driveSession = session;
|
|
21890
|
+
}
|
|
21891
|
+
function clearVnextDriveSession(storePath, runId, token) {
|
|
21892
|
+
const owner = owners.get(storePath);
|
|
21893
|
+
const current = owner?.admitted.get(runId);
|
|
21894
|
+
if (!current || current.token !== token) return;
|
|
21895
|
+
delete current.driveSession;
|
|
21896
|
+
}
|
|
21897
|
+
function vnextOpenDriveSessions(storePath) {
|
|
21898
|
+
const owner = owners.get(storePath);
|
|
21899
|
+
if (!owner) return [];
|
|
21900
|
+
const sessions = [];
|
|
21901
|
+
for (const current of owner.admitted.values()) {
|
|
21902
|
+
if (current.driveSession) sessions.push(current.driveSession);
|
|
21903
|
+
}
|
|
21904
|
+
return sessions;
|
|
21905
|
+
}
|
|
21880
21906
|
function enqueueVnextScheduledRun(storePath, runId, configRevision, bound, start) {
|
|
21881
21907
|
const owner = record(storePath);
|
|
21882
21908
|
if (owner.admitted.has(runId) || owner.queue.some((item) => item.runId === runId)) {
|
|
@@ -22315,15 +22341,16 @@ function cancelVnextRun(context, runId, options = {}) {
|
|
|
22315
22341
|
events.push(event);
|
|
22316
22342
|
return event;
|
|
22317
22343
|
};
|
|
22344
|
+
const cancelReason = options.reason ?? "operator_cancel";
|
|
22318
22345
|
const activeAttempt = Boolean(folded.currentStep?.attemptId) || vnextFoldPanelAttemptIds(folded.currentStep).length > 0;
|
|
22319
22346
|
push("run.cancel_requested", {
|
|
22320
22347
|
actor: { kind: "runtime", id: context.homeRuntimeId },
|
|
22321
|
-
reason:
|
|
22348
|
+
reason: cancelReason
|
|
22322
22349
|
});
|
|
22323
22350
|
let status = "cancelled";
|
|
22324
22351
|
if (folded.status === "running" && activeAttempt) {
|
|
22325
22352
|
status = "cancelling";
|
|
22326
|
-
push("run.status_changed", { status: "cancelling", reason:
|
|
22353
|
+
push("run.status_changed", { status: "cancelling", reason: cancelReason });
|
|
22327
22354
|
const attemptIds = new Set(vnextFoldPanelAttemptIds(folded.currentStep));
|
|
22328
22355
|
if (folded.currentStep?.attemptId) attemptIds.add(folded.currentStep.attemptId);
|
|
22329
22356
|
for (const attemptId of attemptIds) {
|
|
@@ -22336,7 +22363,7 @@ function cancelVnextRun(context, runId, options = {}) {
|
|
|
22336
22363
|
abortControllers.push(owned.controller);
|
|
22337
22364
|
}
|
|
22338
22365
|
} else if (folded.status === "blocked_uncertain") {
|
|
22339
|
-
push("run.status_changed", { status: "cancelling", reason:
|
|
22366
|
+
push("run.status_changed", { status: "cancelling", reason: cancelReason });
|
|
22340
22367
|
const attemptId = folded.currentStep?.attemptId;
|
|
22341
22368
|
if (attemptId) {
|
|
22342
22369
|
const capability = context.eventStore.capabilityByAttempt(attemptId);
|
|
@@ -22348,13 +22375,13 @@ function cancelVnextRun(context, runId, options = {}) {
|
|
|
22348
22375
|
for (const owned of vnextAttemptControllers(context.eventStore.path, runId)) {
|
|
22349
22376
|
abortControllers.push(owned.controller);
|
|
22350
22377
|
}
|
|
22351
|
-
push("run.status_changed", { status: "cancelled", reason:
|
|
22378
|
+
push("run.status_changed", { status: "cancelled", reason: cancelReason });
|
|
22352
22379
|
status = "cancelled";
|
|
22353
22380
|
} else if (folded.status === "running" && !activeAttempt) {
|
|
22354
|
-
push("run.status_changed", { status: "cancelling", reason:
|
|
22355
|
-
push("run.status_changed", { status: "cancelled", reason:
|
|
22381
|
+
push("run.status_changed", { status: "cancelling", reason: cancelReason });
|
|
22382
|
+
push("run.status_changed", { status: "cancelled", reason: cancelReason });
|
|
22356
22383
|
} else {
|
|
22357
|
-
push("run.status_changed", { status: "cancelled", reason:
|
|
22384
|
+
push("run.status_changed", { status: "cancelled", reason: cancelReason });
|
|
22358
22385
|
}
|
|
22359
22386
|
for (const event of events) context.eventStore.appendEvent(event);
|
|
22360
22387
|
const nextState = foldStoredVnextRun(context, run);
|
|
@@ -24271,12 +24298,77 @@ async function driveAdmitted(context, runId, producer, token, options = {}) {
|
|
|
24271
24298
|
}
|
|
24272
24299
|
return latest;
|
|
24273
24300
|
}
|
|
24301
|
+
function newDriveId(runId, token, runtimeId, monotonicNs) {
|
|
24302
|
+
return `drv_${createHash11("sha256").update(`${runId}\0${token}\0${runtimeId}\0${monotonicNs}`, "utf8").digest("hex").slice(0, 24)}`;
|
|
24303
|
+
}
|
|
24304
|
+
function inflightAttemptId(state) {
|
|
24305
|
+
const leftover = unreconciledPanelAttemptId(state);
|
|
24306
|
+
if (leftover) return leftover;
|
|
24307
|
+
if (state.currentStep?.attemptId) {
|
|
24308
|
+
const located = vnextFoldPanelAttempt(state.currentStep, state.currentStep.attemptId);
|
|
24309
|
+
const status = located?.attempt.status;
|
|
24310
|
+
if (status === "starting" || status === "executing" || status === "settling") return state.currentStep.attemptId;
|
|
24311
|
+
}
|
|
24312
|
+
return void 0;
|
|
24313
|
+
}
|
|
24314
|
+
function recordExecutingUnrecordedFailure(context, runId, attemptId, stepId) {
|
|
24315
|
+
context.eventStore.transaction(() => {
|
|
24316
|
+
const run = requireRun(context, runId);
|
|
24317
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
24318
|
+
const sequence = context.eventStore.nextSequence(runId);
|
|
24319
|
+
const event = {
|
|
24320
|
+
...vnextEventBase(context, run, now, vnextMonotonicNs()),
|
|
24321
|
+
eventId: newVnextEventId(),
|
|
24322
|
+
eventType: "run.status_changed",
|
|
24323
|
+
sequence,
|
|
24324
|
+
payload: { status: "failed", reason: "executing_unrecorded", stepId }
|
|
24325
|
+
};
|
|
24326
|
+
context.eventStore.appendEvent(event);
|
|
24327
|
+
context.eventStore.settleCapability(attemptId, "revoked");
|
|
24328
|
+
const next = foldStoredVnextRun(context, run);
|
|
24329
|
+
persistVnextRunState(context, runId, next, sequence);
|
|
24330
|
+
context.eventStore.updateRunStatus(runId, "failed", now);
|
|
24331
|
+
});
|
|
24332
|
+
}
|
|
24333
|
+
function recordBareDriveFailure(context, runId) {
|
|
24334
|
+
if (isVnextRuntimeContextClosed(context)) return;
|
|
24335
|
+
try {
|
|
24336
|
+
const run = context.eventStore.run(runId);
|
|
24337
|
+
if (!run) return;
|
|
24338
|
+
const state = foldStoredVnextRun(context, run);
|
|
24339
|
+
if (isTerminalRunStatus(state.status) || state.status === "cancelling") return;
|
|
24340
|
+
const inflight = inflightAttemptId(state);
|
|
24341
|
+
if (inflight) {
|
|
24342
|
+
const currentStep = state.currentStep;
|
|
24343
|
+
const located = vnextFoldPanelAttempt(currentStep, inflight);
|
|
24344
|
+
if (currentStep && currentStep.panel.order.length === 1 && located?.attempt.status === "starting") {
|
|
24345
|
+
const plan = rehydrateVnextCompiledPlanFromStore(context.eventStore, run);
|
|
24346
|
+
const step = plan.steps[currentStep.stepId];
|
|
24347
|
+
if (step?.kind === "gate") return;
|
|
24348
|
+
if (step && (step.kind === "agent" || step.kind === "moa") && step.assignments.maximum > 1) return;
|
|
24349
|
+
recordExecutingUnrecordedFailure(context, runId, inflight, currentStep.stepId);
|
|
24350
|
+
}
|
|
24351
|
+
return;
|
|
24352
|
+
}
|
|
24353
|
+
cancelVnextRun(context, runId, { reason: "drive_error" });
|
|
24354
|
+
} catch {
|
|
24355
|
+
}
|
|
24356
|
+
}
|
|
24357
|
+
async function closeDriveProducer(producer) {
|
|
24358
|
+
if (typeof producer.close !== "function") return;
|
|
24359
|
+
try {
|
|
24360
|
+
await producer.close();
|
|
24361
|
+
} catch {
|
|
24362
|
+
}
|
|
24363
|
+
}
|
|
24274
24364
|
var VnextRunScheduler = class _VnextRunScheduler {
|
|
24275
24365
|
context;
|
|
24366
|
+
bundle;
|
|
24276
24367
|
configRevision;
|
|
24277
|
-
constructor(context,
|
|
24368
|
+
constructor(context, bundle) {
|
|
24278
24369
|
this.context = context;
|
|
24279
|
-
this.
|
|
24370
|
+
this.bundle = bundle;
|
|
24371
|
+
this.configRevision = bundle.configRevision;
|
|
24280
24372
|
}
|
|
24281
24373
|
static for(context, bundle) {
|
|
24282
24374
|
if (String(bundle.project.value.id) !== context.projectId) {
|
|
@@ -24284,7 +24376,7 @@ var VnextRunScheduler = class _VnextRunScheduler {
|
|
|
24284
24376
|
}
|
|
24285
24377
|
const limits = vnextProjectAdmissionLimits(bundle);
|
|
24286
24378
|
bindVnextSchedulerPolicy(context.eventStore.path, limits.maxConcurrentRuns, bundle.configRevision);
|
|
24287
|
-
return new _VnextRunScheduler(context, bundle
|
|
24379
|
+
return new _VnextRunScheduler(context, bundle);
|
|
24288
24380
|
}
|
|
24289
24381
|
enqueue(runId, producer, options = {}) {
|
|
24290
24382
|
requireTrustedProducer(producer);
|
|
@@ -24306,6 +24398,91 @@ var VnextRunScheduler = class _VnextRunScheduler {
|
|
|
24306
24398
|
return Promise.reject(error);
|
|
24307
24399
|
}
|
|
24308
24400
|
}
|
|
24401
|
+
openDriveSession(runId, options) {
|
|
24402
|
+
const policy = vnextSchedulerPolicy(this.context.eventStore.path);
|
|
24403
|
+
if (!policy || policy.configRevision !== this.configRevision) {
|
|
24404
|
+
return Promise.reject(runtimeError("scheduler_policy_conflict", runId, "scheduler handle does not match the active policy"));
|
|
24405
|
+
}
|
|
24406
|
+
try {
|
|
24407
|
+
const run = requireRun(this.context, runId);
|
|
24408
|
+
if (isTerminalRunStatus(run.status) || run.status === "cancelling") {
|
|
24409
|
+
return Promise.reject(runtimeError("run_busy", runId, `run ${runId} is already ${run.status}`));
|
|
24410
|
+
}
|
|
24411
|
+
} catch (error) {
|
|
24412
|
+
return Promise.reject(error);
|
|
24413
|
+
}
|
|
24414
|
+
const limits = vnextProjectAdmissionLimits(this.bundle);
|
|
24415
|
+
const driveOptions = {
|
|
24416
|
+
liveMode: options.liveMode ?? options.mode === "live"
|
|
24417
|
+
};
|
|
24418
|
+
if (options.allowLimits !== void 0) driveOptions.allowLimits = options.allowLimits;
|
|
24419
|
+
let opened = false;
|
|
24420
|
+
const pending = {
|
|
24421
|
+
resolve: (_value) => void 0,
|
|
24422
|
+
reject: (_error) => void 0
|
|
24423
|
+
};
|
|
24424
|
+
const settled = new Promise((resolve9, reject) => {
|
|
24425
|
+
pending.resolve = resolve9;
|
|
24426
|
+
pending.reject = reject;
|
|
24427
|
+
});
|
|
24428
|
+
void settled.then(void 0, () => void 0);
|
|
24429
|
+
return new Promise((resolveOpen, rejectOpen) => {
|
|
24430
|
+
const queued = enqueueVnextScheduledRun(
|
|
24431
|
+
this.context.eventStore.path,
|
|
24432
|
+
runId,
|
|
24433
|
+
this.configRevision,
|
|
24434
|
+
limits.maxConcurrentRuns,
|
|
24435
|
+
async (token) => {
|
|
24436
|
+
let producer;
|
|
24437
|
+
try {
|
|
24438
|
+
producer = options.createProducer();
|
|
24439
|
+
requireTrustedProducer(producer);
|
|
24440
|
+
const current = requireRun(this.context, runId);
|
|
24441
|
+
if (current.status === "created") {
|
|
24442
|
+
pinVnextCompiledPlan(this.context, this.bundle, runId);
|
|
24443
|
+
}
|
|
24444
|
+
const started = startVnextRun(this.context, runId, driveOptions);
|
|
24445
|
+
if (started.handoff) {
|
|
24446
|
+
const error = runtimeError("run_handoff_required", runId, started.handoff.detail);
|
|
24447
|
+
Object.assign(error, { handoff: started.handoff });
|
|
24448
|
+
throw error;
|
|
24449
|
+
}
|
|
24450
|
+
const driveId = newDriveId(runId, token, this.context.homeRuntimeId, vnextMonotonicNs());
|
|
24451
|
+
const session = {
|
|
24452
|
+
driveId,
|
|
24453
|
+
runId,
|
|
24454
|
+
token,
|
|
24455
|
+
homeRuntimeId: this.context.homeRuntimeId,
|
|
24456
|
+
mode: options.mode,
|
|
24457
|
+
openedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24458
|
+
controller: new AbortController(),
|
|
24459
|
+
settled
|
|
24460
|
+
};
|
|
24461
|
+
attachVnextDriveSession(this.context.eventStore.path, runId, token, session);
|
|
24462
|
+
opened = true;
|
|
24463
|
+
resolveOpen({ driveId, settled });
|
|
24464
|
+
try {
|
|
24465
|
+
const result = await driveAdmitted(this.context, runId, producer, token, driveOptions);
|
|
24466
|
+
pending.resolve(result);
|
|
24467
|
+
return result;
|
|
24468
|
+
} catch (error) {
|
|
24469
|
+
recordBareDriveFailure(this.context, runId);
|
|
24470
|
+
pending.reject(error);
|
|
24471
|
+
throw error;
|
|
24472
|
+
}
|
|
24473
|
+
} finally {
|
|
24474
|
+
if (producer) await closeDriveProducer(producer);
|
|
24475
|
+
clearVnextDriveSession(this.context.eventStore.path, runId, token);
|
|
24476
|
+
}
|
|
24477
|
+
}
|
|
24478
|
+
);
|
|
24479
|
+
void queued.then(void 0, (error) => {
|
|
24480
|
+
if (!opened) {
|
|
24481
|
+
rejectOpen(error);
|
|
24482
|
+
}
|
|
24483
|
+
});
|
|
24484
|
+
});
|
|
24485
|
+
}
|
|
24309
24486
|
};
|
|
24310
24487
|
function invokeProducer(producer, request) {
|
|
24311
24488
|
let pending;
|
|
@@ -24644,6 +24821,9 @@ function prepareDispatch(context, runId, producerId) {
|
|
|
24644
24821
|
const run = requireRun(context, runId);
|
|
24645
24822
|
const plan = rehydrateVnextCompiledPlanFromStore(context.eventStore, run);
|
|
24646
24823
|
const state = foldStoredVnextRun(context, run);
|
|
24824
|
+
if (vnextPanelDispatchSeams.skipDispatch?.()) {
|
|
24825
|
+
return { kind: "return", state };
|
|
24826
|
+
}
|
|
24647
24827
|
if (state.status === "cancelling" && vnextAttemptControllers(context.eventStore.path, runId).length === 0) {
|
|
24648
24828
|
return {
|
|
24649
24829
|
kind: "return",
|
|
@@ -26501,6 +26681,36 @@ function sendJson(response, status, payload) {
|
|
|
26501
26681
|
response.writeHead(status, { "content-type": "application/json", "content-length": Buffer.byteLength(body) });
|
|
26502
26682
|
response.end(body);
|
|
26503
26683
|
}
|
|
26684
|
+
var DEFAULT_RUNTIME_STOP_GRACE_MS = 3e4;
|
|
26685
|
+
var MAX_RUNTIME_STOP_GRACE_MS = 6e5;
|
|
26686
|
+
function runtimeStopGraceMs(env = process.env) {
|
|
26687
|
+
const raw = env.KXM_RUNTIME_STOP_GRACE_MS;
|
|
26688
|
+
if (raw === void 0 || raw.trim() === "") return DEFAULT_RUNTIME_STOP_GRACE_MS;
|
|
26689
|
+
const parsed = Number(raw.trim());
|
|
26690
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < 0 || parsed > MAX_RUNTIME_STOP_GRACE_MS) {
|
|
26691
|
+
process.stderr.write(
|
|
26692
|
+
`KXM_RUNTIME_STOP_GRACE_MS must be an integer between 0 and ${MAX_RUNTIME_STOP_GRACE_MS} ms (10 minutes); using default ${DEFAULT_RUNTIME_STOP_GRACE_MS}
|
|
26693
|
+
`
|
|
26694
|
+
);
|
|
26695
|
+
return DEFAULT_RUNTIME_STOP_GRACE_MS;
|
|
26696
|
+
}
|
|
26697
|
+
return parsed;
|
|
26698
|
+
}
|
|
26699
|
+
async function waitForDriveSessions(settled, graceMs) {
|
|
26700
|
+
if (settled.length === 0) return;
|
|
26701
|
+
let timeout;
|
|
26702
|
+
try {
|
|
26703
|
+
await Promise.race([
|
|
26704
|
+
Promise.allSettled(settled),
|
|
26705
|
+
new Promise((resolve9) => {
|
|
26706
|
+
timeout = setTimeout(resolve9, graceMs);
|
|
26707
|
+
timeout.unref?.();
|
|
26708
|
+
})
|
|
26709
|
+
]);
|
|
26710
|
+
} finally {
|
|
26711
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
26712
|
+
}
|
|
26713
|
+
}
|
|
26504
26714
|
async function startVnextRuntimeSupervisor(options = {}) {
|
|
26505
26715
|
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
26506
26716
|
const paths = vnextRuntimePaths(options.stateRoot !== void 0 ? { stateRoot: options.stateRoot } : {});
|
|
@@ -26522,7 +26732,6 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
|
|
|
26522
26732
|
const runtimeId = `rtm_${createHash12("sha256").update(`${paths.stateRoot}\0${process.pid}\0${now()}\0${randomBytes3(16).toString("hex")}`, "utf8").digest("hex").slice(0, 24)}`;
|
|
26523
26733
|
const requestedPort = requestedPortOption ?? 0;
|
|
26524
26734
|
let activeRuntimeId = runtimeId;
|
|
26525
|
-
const activeDrives = /* @__PURE__ */ new Map();
|
|
26526
26735
|
const contexts = /* @__PURE__ */ new Map();
|
|
26527
26736
|
const contextFor = (projectRoot) => {
|
|
26528
26737
|
if (!isAbsolute4(projectRoot)) {
|
|
@@ -26616,34 +26825,8 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
|
|
|
26616
26825
|
}
|
|
26617
26826
|
const run = context.eventStore.run(runId);
|
|
26618
26827
|
if (!run) throw runtimeError("run_unknown", runId, "run not found");
|
|
26619
|
-
|
|
26620
|
-
|
|
26621
|
-
return;
|
|
26622
|
-
}
|
|
26623
|
-
if (run.status === "completed" || run.status === "failed" || run.status === "cancelled" || run.status === "cancelling") {
|
|
26624
|
-
sendJson(response, 409, { ok: false, error: "run_busy", message: `run ${runId} is already ${run.status}` });
|
|
26625
|
-
return;
|
|
26626
|
-
}
|
|
26627
|
-
let releaseActive = () => {
|
|
26628
|
-
};
|
|
26629
|
-
const activePromise = new Promise((resolve9) => {
|
|
26630
|
-
releaseActive = resolve9;
|
|
26631
|
-
});
|
|
26632
|
-
activeDrives.set(runId, activePromise);
|
|
26633
|
-
const cleanupActive = () => {
|
|
26634
|
-
activeDrives.delete(runId);
|
|
26635
|
-
releaseActive();
|
|
26636
|
-
};
|
|
26637
|
-
if (run.status === "created") {
|
|
26638
|
-
pinVnextCompiledPlan(context, bundle, runId);
|
|
26639
|
-
const plan = startVnextRun(context, runId, { allowLimits: true });
|
|
26640
|
-
if (plan.handoff) {
|
|
26641
|
-
cleanupActive();
|
|
26642
|
-
sendJson(response, 409, { ok: false, error: "run_handoff_required", handoff: plan.handoff });
|
|
26643
|
-
return;
|
|
26644
|
-
}
|
|
26645
|
-
}
|
|
26646
|
-
const producer = body.mode === "live" ? createVnextOneShotProducer({
|
|
26828
|
+
const delayMs = typeof body.delayMs === "number" && body.delayMs > 0 ? body.delayMs : 0;
|
|
26829
|
+
const createProducer = () => body.mode === "live" ? createVnextOneShotProducer({
|
|
26647
26830
|
projectRoot,
|
|
26648
26831
|
defaultHarness: String(bundle.project.value.defaultHarness ?? "pi"),
|
|
26649
26832
|
resolveHarness: (agentId) => {
|
|
@@ -26662,56 +26845,50 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
|
|
|
26662
26845
|
}
|
|
26663
26846
|
return { provider, model: modelName };
|
|
26664
26847
|
}
|
|
26665
|
-
}) : (() => {
|
|
26666
|
-
|
|
26667
|
-
|
|
26668
|
-
|
|
26669
|
-
|
|
26670
|
-
|
|
26671
|
-
|
|
26672
|
-
});
|
|
26673
|
-
})();
|
|
26674
|
-
let drivePromise;
|
|
26848
|
+
}) : createVnextSimulatedProducer(async () => {
|
|
26849
|
+
if (delayMs > 0) {
|
|
26850
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
26851
|
+
}
|
|
26852
|
+
return { outcome: "passed" };
|
|
26853
|
+
});
|
|
26854
|
+
let session;
|
|
26675
26855
|
let earlyError;
|
|
26676
26856
|
try {
|
|
26677
26857
|
const scheduler = VnextRunScheduler.for(context, bundle);
|
|
26678
|
-
|
|
26679
|
-
|
|
26858
|
+
const opening = scheduler.openDriveSession(runId, {
|
|
26859
|
+
mode: body.mode,
|
|
26860
|
+
allowLimits: true,
|
|
26861
|
+
liveMode: body.mode === "live",
|
|
26862
|
+
createProducer
|
|
26863
|
+
});
|
|
26864
|
+
opening.catch((err) => {
|
|
26680
26865
|
earlyError = err;
|
|
26681
26866
|
});
|
|
26867
|
+
session = await opening;
|
|
26682
26868
|
} catch (err) {
|
|
26683
26869
|
earlyError = err;
|
|
26684
26870
|
}
|
|
26685
|
-
await Promise.resolve();
|
|
26686
26871
|
if (earlyError) {
|
|
26687
|
-
cleanupActive();
|
|
26688
26872
|
const errStr = String(earlyError);
|
|
26873
|
+
if (errStr.includes("run_handoff_required")) {
|
|
26874
|
+
const handoff = earlyError.handoff;
|
|
26875
|
+
sendJson(response, 409, { ok: false, error: "run_handoff_required", ...handoff !== void 0 ? { handoff } : {} });
|
|
26876
|
+
return;
|
|
26877
|
+
}
|
|
26689
26878
|
if (errStr.includes("run_busy") || errStr.includes("scheduler_policy_conflict")) {
|
|
26690
|
-
if ("close" in producer && typeof producer.close === "function") {
|
|
26691
|
-
try {
|
|
26692
|
-
await producer.close();
|
|
26693
|
-
} catch {
|
|
26694
|
-
}
|
|
26695
|
-
}
|
|
26696
26879
|
sendJson(response, 409, { ok: false, error: "run_busy", message: `run ${runId} is already admitted or queued` });
|
|
26697
26880
|
return;
|
|
26698
26881
|
}
|
|
26699
26882
|
throw earlyError;
|
|
26700
26883
|
}
|
|
26701
|
-
void
|
|
26702
|
-
cleanupActive();
|
|
26703
|
-
if ("close" in producer && typeof producer.close === "function") {
|
|
26704
|
-
try {
|
|
26705
|
-
await producer.close();
|
|
26706
|
-
} catch {
|
|
26707
|
-
}
|
|
26708
|
-
}
|
|
26709
|
-
}).catch(() => {
|
|
26884
|
+
void session.settled.catch(() => {
|
|
26710
26885
|
});
|
|
26886
|
+
if (response.writableEnded) return;
|
|
26711
26887
|
sendJson(response, 202, {
|
|
26712
26888
|
ok: true,
|
|
26713
26889
|
status: "accepted",
|
|
26714
26890
|
runId,
|
|
26891
|
+
driveId: session.driveId,
|
|
26715
26892
|
poll: `/v1/runs/${runId}`,
|
|
26716
26893
|
mode: body.mode
|
|
26717
26894
|
});
|
|
@@ -26842,9 +27019,18 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
|
|
|
26842
27019
|
registry.markStopping(process.pid, now());
|
|
26843
27020
|
} catch {
|
|
26844
27021
|
}
|
|
26845
|
-
|
|
26846
|
-
|
|
27022
|
+
const openSessions = [...contexts.values()].flatMap((context) => vnextOpenDriveSessions(context.eventStore.path).map((session) => ({ context, session })));
|
|
27023
|
+
for (const { context, session } of openSessions) {
|
|
27024
|
+
try {
|
|
27025
|
+
cancelVnextRun(context, session.runId, { reason: "runtime_shutdown" });
|
|
27026
|
+
} catch {
|
|
27027
|
+
}
|
|
27028
|
+
try {
|
|
27029
|
+
session.controller.abort();
|
|
27030
|
+
} catch {
|
|
27031
|
+
}
|
|
26847
27032
|
}
|
|
27033
|
+
await waitForDriveSessions(openSessions.map(({ session }) => session.settled), runtimeStopGraceMs());
|
|
26848
27034
|
for (const context of contexts.values()) closeVnextRuntimeContext(context);
|
|
26849
27035
|
contexts.clear();
|
|
26850
27036
|
const closed = new Promise((resolveStop) => server.close(() => resolveStop()));
|
|
@@ -29167,11 +29353,13 @@ export {
|
|
|
29167
29353
|
DEFAULT_LOG_MAX_BYTES,
|
|
29168
29354
|
DEFAULT_LOG_MAX_FILES,
|
|
29169
29355
|
DEFAULT_MODES_CONFIG,
|
|
29356
|
+
DEFAULT_RUNTIME_STOP_GRACE_MS,
|
|
29170
29357
|
DEFAULT_SOCKET_DIR,
|
|
29171
29358
|
DEFAULT_SUBAGENT_MODELS,
|
|
29172
29359
|
IMPROVEMENT_REPORT_SCHEMA,
|
|
29173
29360
|
IMPROVEMENT_REPORT_V1_SCHEMA,
|
|
29174
29361
|
LOG_LEVEL_PRIORITY,
|
|
29362
|
+
MAX_RUNTIME_STOP_GRACE_MS,
|
|
29175
29363
|
MAX_SSH_OUTPUT_BYTES,
|
|
29176
29364
|
MAX_SSH_OUTPUT_LINES,
|
|
29177
29365
|
NATIVE_HARNESS_PROVIDERS,
|
|
@@ -29289,6 +29477,7 @@ export {
|
|
|
29289
29477
|
rotateLogFiles,
|
|
29290
29478
|
runHarnessUpdate,
|
|
29291
29479
|
runtimeError,
|
|
29480
|
+
runtimeStopGraceMs,
|
|
29292
29481
|
sanitizeLogOutput,
|
|
29293
29482
|
startVnextRuntimeSupervisor,
|
|
29294
29483
|
tableColumns,
|