@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
|
@@ -21445,6 +21445,32 @@ function vnextGateHold(storePath, runId) {
|
|
|
21445
21445
|
function vnextAdmittedToken(storePath, runId) {
|
|
21446
21446
|
return owners.get(storePath)?.admitted.get(runId)?.token;
|
|
21447
21447
|
}
|
|
21448
|
+
function attachVnextDriveSession(storePath, runId, token, session) {
|
|
21449
|
+
const owner = record(storePath);
|
|
21450
|
+
const current = owner.admitted.get(runId);
|
|
21451
|
+
if (!current || current.token !== token) {
|
|
21452
|
+
throw runtimeError("run_events_illegal", runId, "drive session requires the exact admitted token");
|
|
21453
|
+
}
|
|
21454
|
+
if (current.driveSession) {
|
|
21455
|
+
throw runtimeError("run_busy", runId, `run ${runId} already has a drive session`);
|
|
21456
|
+
}
|
|
21457
|
+
current.driveSession = session;
|
|
21458
|
+
}
|
|
21459
|
+
function clearVnextDriveSession(storePath, runId, token) {
|
|
21460
|
+
const owner = owners.get(storePath);
|
|
21461
|
+
const current = owner?.admitted.get(runId);
|
|
21462
|
+
if (!current || current.token !== token) return;
|
|
21463
|
+
delete current.driveSession;
|
|
21464
|
+
}
|
|
21465
|
+
function vnextOpenDriveSessions(storePath) {
|
|
21466
|
+
const owner = owners.get(storePath);
|
|
21467
|
+
if (!owner) return [];
|
|
21468
|
+
const sessions = [];
|
|
21469
|
+
for (const current of owner.admitted.values()) {
|
|
21470
|
+
if (current.driveSession) sessions.push(current.driveSession);
|
|
21471
|
+
}
|
|
21472
|
+
return sessions;
|
|
21473
|
+
}
|
|
21448
21474
|
function enqueueVnextScheduledRun(storePath, runId, configRevision, bound, start) {
|
|
21449
21475
|
const owner = record(storePath);
|
|
21450
21476
|
if (owner.admitted.has(runId) || owner.queue.some((item) => item.runId === runId)) {
|
|
@@ -21872,15 +21898,16 @@ function cancelVnextRun(context, runId, options = {}) {
|
|
|
21872
21898
|
events.push(event);
|
|
21873
21899
|
return event;
|
|
21874
21900
|
};
|
|
21901
|
+
const cancelReason = options.reason ?? "operator_cancel";
|
|
21875
21902
|
const activeAttempt = Boolean(folded.currentStep?.attemptId) || vnextFoldPanelAttemptIds(folded.currentStep).length > 0;
|
|
21876
21903
|
push("run.cancel_requested", {
|
|
21877
21904
|
actor: { kind: "runtime", id: context.homeRuntimeId },
|
|
21878
|
-
reason:
|
|
21905
|
+
reason: cancelReason
|
|
21879
21906
|
});
|
|
21880
21907
|
let status = "cancelled";
|
|
21881
21908
|
if (folded.status === "running" && activeAttempt) {
|
|
21882
21909
|
status = "cancelling";
|
|
21883
|
-
push("run.status_changed", { status: "cancelling", reason:
|
|
21910
|
+
push("run.status_changed", { status: "cancelling", reason: cancelReason });
|
|
21884
21911
|
const attemptIds = new Set(vnextFoldPanelAttemptIds(folded.currentStep));
|
|
21885
21912
|
if (folded.currentStep?.attemptId) attemptIds.add(folded.currentStep.attemptId);
|
|
21886
21913
|
for (const attemptId of attemptIds) {
|
|
@@ -21893,7 +21920,7 @@ function cancelVnextRun(context, runId, options = {}) {
|
|
|
21893
21920
|
abortControllers.push(owned.controller);
|
|
21894
21921
|
}
|
|
21895
21922
|
} else if (folded.status === "blocked_uncertain") {
|
|
21896
|
-
push("run.status_changed", { status: "cancelling", reason:
|
|
21923
|
+
push("run.status_changed", { status: "cancelling", reason: cancelReason });
|
|
21897
21924
|
const attemptId = folded.currentStep?.attemptId;
|
|
21898
21925
|
if (attemptId) {
|
|
21899
21926
|
const capability = context.eventStore.capabilityByAttempt(attemptId);
|
|
@@ -21905,13 +21932,13 @@ function cancelVnextRun(context, runId, options = {}) {
|
|
|
21905
21932
|
for (const owned of vnextAttemptControllers(context.eventStore.path, runId)) {
|
|
21906
21933
|
abortControllers.push(owned.controller);
|
|
21907
21934
|
}
|
|
21908
|
-
push("run.status_changed", { status: "cancelled", reason:
|
|
21935
|
+
push("run.status_changed", { status: "cancelled", reason: cancelReason });
|
|
21909
21936
|
status = "cancelled";
|
|
21910
21937
|
} else if (folded.status === "running" && !activeAttempt) {
|
|
21911
|
-
push("run.status_changed", { status: "cancelling", reason:
|
|
21912
|
-
push("run.status_changed", { status: "cancelled", reason:
|
|
21938
|
+
push("run.status_changed", { status: "cancelling", reason: cancelReason });
|
|
21939
|
+
push("run.status_changed", { status: "cancelled", reason: cancelReason });
|
|
21913
21940
|
} else {
|
|
21914
|
-
push("run.status_changed", { status: "cancelled", reason:
|
|
21941
|
+
push("run.status_changed", { status: "cancelled", reason: cancelReason });
|
|
21915
21942
|
}
|
|
21916
21943
|
for (const event of events) context.eventStore.appendEvent(event);
|
|
21917
21944
|
const nextState = foldStoredVnextRun(context, run);
|
|
@@ -23787,12 +23814,77 @@ async function driveAdmitted(context, runId, producer, token, options = {}) {
|
|
|
23787
23814
|
}
|
|
23788
23815
|
return latest;
|
|
23789
23816
|
}
|
|
23817
|
+
function newDriveId(runId, token, runtimeId, monotonicNs) {
|
|
23818
|
+
return `drv_${createHash10("sha256").update(`${runId}\0${token}\0${runtimeId}\0${monotonicNs}`, "utf8").digest("hex").slice(0, 24)}`;
|
|
23819
|
+
}
|
|
23820
|
+
function inflightAttemptId(state) {
|
|
23821
|
+
const leftover = unreconciledPanelAttemptId(state);
|
|
23822
|
+
if (leftover) return leftover;
|
|
23823
|
+
if (state.currentStep?.attemptId) {
|
|
23824
|
+
const located = vnextFoldPanelAttempt(state.currentStep, state.currentStep.attemptId);
|
|
23825
|
+
const status = located?.attempt.status;
|
|
23826
|
+
if (status === "starting" || status === "executing" || status === "settling") return state.currentStep.attemptId;
|
|
23827
|
+
}
|
|
23828
|
+
return void 0;
|
|
23829
|
+
}
|
|
23830
|
+
function recordExecutingUnrecordedFailure(context, runId, attemptId, stepId) {
|
|
23831
|
+
context.eventStore.transaction(() => {
|
|
23832
|
+
const run = requireRun(context, runId);
|
|
23833
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
23834
|
+
const sequence = context.eventStore.nextSequence(runId);
|
|
23835
|
+
const event = {
|
|
23836
|
+
...vnextEventBase(context, run, now, vnextMonotonicNs()),
|
|
23837
|
+
eventId: newVnextEventId(),
|
|
23838
|
+
eventType: "run.status_changed",
|
|
23839
|
+
sequence,
|
|
23840
|
+
payload: { status: "failed", reason: "executing_unrecorded", stepId }
|
|
23841
|
+
};
|
|
23842
|
+
context.eventStore.appendEvent(event);
|
|
23843
|
+
context.eventStore.settleCapability(attemptId, "revoked");
|
|
23844
|
+
const next = foldStoredVnextRun(context, run);
|
|
23845
|
+
persistVnextRunState(context, runId, next, sequence);
|
|
23846
|
+
context.eventStore.updateRunStatus(runId, "failed", now);
|
|
23847
|
+
});
|
|
23848
|
+
}
|
|
23849
|
+
function recordBareDriveFailure(context, runId) {
|
|
23850
|
+
if (isVnextRuntimeContextClosed(context)) return;
|
|
23851
|
+
try {
|
|
23852
|
+
const run = context.eventStore.run(runId);
|
|
23853
|
+
if (!run) return;
|
|
23854
|
+
const state = foldStoredVnextRun(context, run);
|
|
23855
|
+
if (isTerminalRunStatus(state.status) || state.status === "cancelling") return;
|
|
23856
|
+
const inflight = inflightAttemptId(state);
|
|
23857
|
+
if (inflight) {
|
|
23858
|
+
const currentStep = state.currentStep;
|
|
23859
|
+
const located = vnextFoldPanelAttempt(currentStep, inflight);
|
|
23860
|
+
if (currentStep && currentStep.panel.order.length === 1 && located?.attempt.status === "starting") {
|
|
23861
|
+
const plan = rehydrateVnextCompiledPlanFromStore(context.eventStore, run);
|
|
23862
|
+
const step = plan.steps[currentStep.stepId];
|
|
23863
|
+
if (step?.kind === "gate") return;
|
|
23864
|
+
if (step && (step.kind === "agent" || step.kind === "moa") && step.assignments.maximum > 1) return;
|
|
23865
|
+
recordExecutingUnrecordedFailure(context, runId, inflight, currentStep.stepId);
|
|
23866
|
+
}
|
|
23867
|
+
return;
|
|
23868
|
+
}
|
|
23869
|
+
cancelVnextRun(context, runId, { reason: "drive_error" });
|
|
23870
|
+
} catch {
|
|
23871
|
+
}
|
|
23872
|
+
}
|
|
23873
|
+
async function closeDriveProducer(producer) {
|
|
23874
|
+
if (typeof producer.close !== "function") return;
|
|
23875
|
+
try {
|
|
23876
|
+
await producer.close();
|
|
23877
|
+
} catch {
|
|
23878
|
+
}
|
|
23879
|
+
}
|
|
23790
23880
|
var VnextRunScheduler = class _VnextRunScheduler {
|
|
23791
23881
|
context;
|
|
23882
|
+
bundle;
|
|
23792
23883
|
configRevision;
|
|
23793
|
-
constructor(context,
|
|
23884
|
+
constructor(context, bundle) {
|
|
23794
23885
|
this.context = context;
|
|
23795
|
-
this.
|
|
23886
|
+
this.bundle = bundle;
|
|
23887
|
+
this.configRevision = bundle.configRevision;
|
|
23796
23888
|
}
|
|
23797
23889
|
static for(context, bundle) {
|
|
23798
23890
|
if (String(bundle.project.value.id) !== context.projectId) {
|
|
@@ -23800,7 +23892,7 @@ var VnextRunScheduler = class _VnextRunScheduler {
|
|
|
23800
23892
|
}
|
|
23801
23893
|
const limits = vnextProjectAdmissionLimits(bundle);
|
|
23802
23894
|
bindVnextSchedulerPolicy(context.eventStore.path, limits.maxConcurrentRuns, bundle.configRevision);
|
|
23803
|
-
return new _VnextRunScheduler(context, bundle
|
|
23895
|
+
return new _VnextRunScheduler(context, bundle);
|
|
23804
23896
|
}
|
|
23805
23897
|
enqueue(runId, producer, options = {}) {
|
|
23806
23898
|
requireTrustedProducer(producer);
|
|
@@ -23822,6 +23914,91 @@ var VnextRunScheduler = class _VnextRunScheduler {
|
|
|
23822
23914
|
return Promise.reject(error);
|
|
23823
23915
|
}
|
|
23824
23916
|
}
|
|
23917
|
+
openDriveSession(runId, options) {
|
|
23918
|
+
const policy = vnextSchedulerPolicy(this.context.eventStore.path);
|
|
23919
|
+
if (!policy || policy.configRevision !== this.configRevision) {
|
|
23920
|
+
return Promise.reject(runtimeError("scheduler_policy_conflict", runId, "scheduler handle does not match the active policy"));
|
|
23921
|
+
}
|
|
23922
|
+
try {
|
|
23923
|
+
const run = requireRun(this.context, runId);
|
|
23924
|
+
if (isTerminalRunStatus(run.status) || run.status === "cancelling") {
|
|
23925
|
+
return Promise.reject(runtimeError("run_busy", runId, `run ${runId} is already ${run.status}`));
|
|
23926
|
+
}
|
|
23927
|
+
} catch (error) {
|
|
23928
|
+
return Promise.reject(error);
|
|
23929
|
+
}
|
|
23930
|
+
const limits = vnextProjectAdmissionLimits(this.bundle);
|
|
23931
|
+
const driveOptions = {
|
|
23932
|
+
liveMode: options.liveMode ?? options.mode === "live"
|
|
23933
|
+
};
|
|
23934
|
+
if (options.allowLimits !== void 0) driveOptions.allowLimits = options.allowLimits;
|
|
23935
|
+
let opened = false;
|
|
23936
|
+
const pending = {
|
|
23937
|
+
resolve: (_value) => void 0,
|
|
23938
|
+
reject: (_error) => void 0
|
|
23939
|
+
};
|
|
23940
|
+
const settled = new Promise((resolve7, reject) => {
|
|
23941
|
+
pending.resolve = resolve7;
|
|
23942
|
+
pending.reject = reject;
|
|
23943
|
+
});
|
|
23944
|
+
void settled.then(void 0, () => void 0);
|
|
23945
|
+
return new Promise((resolveOpen, rejectOpen) => {
|
|
23946
|
+
const queued = enqueueVnextScheduledRun(
|
|
23947
|
+
this.context.eventStore.path,
|
|
23948
|
+
runId,
|
|
23949
|
+
this.configRevision,
|
|
23950
|
+
limits.maxConcurrentRuns,
|
|
23951
|
+
async (token) => {
|
|
23952
|
+
let producer;
|
|
23953
|
+
try {
|
|
23954
|
+
producer = options.createProducer();
|
|
23955
|
+
requireTrustedProducer(producer);
|
|
23956
|
+
const current = requireRun(this.context, runId);
|
|
23957
|
+
if (current.status === "created") {
|
|
23958
|
+
pinVnextCompiledPlan(this.context, this.bundle, runId);
|
|
23959
|
+
}
|
|
23960
|
+
const started = startVnextRun(this.context, runId, driveOptions);
|
|
23961
|
+
if (started.handoff) {
|
|
23962
|
+
const error = runtimeError("run_handoff_required", runId, started.handoff.detail);
|
|
23963
|
+
Object.assign(error, { handoff: started.handoff });
|
|
23964
|
+
throw error;
|
|
23965
|
+
}
|
|
23966
|
+
const driveId = newDriveId(runId, token, this.context.homeRuntimeId, vnextMonotonicNs());
|
|
23967
|
+
const session = {
|
|
23968
|
+
driveId,
|
|
23969
|
+
runId,
|
|
23970
|
+
token,
|
|
23971
|
+
homeRuntimeId: this.context.homeRuntimeId,
|
|
23972
|
+
mode: options.mode,
|
|
23973
|
+
openedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23974
|
+
controller: new AbortController(),
|
|
23975
|
+
settled
|
|
23976
|
+
};
|
|
23977
|
+
attachVnextDriveSession(this.context.eventStore.path, runId, token, session);
|
|
23978
|
+
opened = true;
|
|
23979
|
+
resolveOpen({ driveId, settled });
|
|
23980
|
+
try {
|
|
23981
|
+
const result = await driveAdmitted(this.context, runId, producer, token, driveOptions);
|
|
23982
|
+
pending.resolve(result);
|
|
23983
|
+
return result;
|
|
23984
|
+
} catch (error) {
|
|
23985
|
+
recordBareDriveFailure(this.context, runId);
|
|
23986
|
+
pending.reject(error);
|
|
23987
|
+
throw error;
|
|
23988
|
+
}
|
|
23989
|
+
} finally {
|
|
23990
|
+
if (producer) await closeDriveProducer(producer);
|
|
23991
|
+
clearVnextDriveSession(this.context.eventStore.path, runId, token);
|
|
23992
|
+
}
|
|
23993
|
+
}
|
|
23994
|
+
);
|
|
23995
|
+
void queued.then(void 0, (error) => {
|
|
23996
|
+
if (!opened) {
|
|
23997
|
+
rejectOpen(error);
|
|
23998
|
+
}
|
|
23999
|
+
});
|
|
24000
|
+
});
|
|
24001
|
+
}
|
|
23825
24002
|
};
|
|
23826
24003
|
function invokeProducer(producer, request) {
|
|
23827
24004
|
let pending;
|
|
@@ -24160,6 +24337,9 @@ function prepareDispatch(context, runId, producerId) {
|
|
|
24160
24337
|
const run = requireRun(context, runId);
|
|
24161
24338
|
const plan = rehydrateVnextCompiledPlanFromStore(context.eventStore, run);
|
|
24162
24339
|
const state = foldStoredVnextRun(context, run);
|
|
24340
|
+
if (vnextPanelDispatchSeams.skipDispatch?.()) {
|
|
24341
|
+
return { kind: "return", state };
|
|
24342
|
+
}
|
|
24163
24343
|
if (state.status === "cancelling" && vnextAttemptControllers(context.eventStore.path, runId).length === 0) {
|
|
24164
24344
|
return {
|
|
24165
24345
|
kind: "return",
|
|
@@ -26017,6 +26197,36 @@ function sendJson(response, status, payload) {
|
|
|
26017
26197
|
response.writeHead(status, { "content-type": "application/json", "content-length": Buffer.byteLength(body) });
|
|
26018
26198
|
response.end(body);
|
|
26019
26199
|
}
|
|
26200
|
+
var DEFAULT_RUNTIME_STOP_GRACE_MS = 3e4;
|
|
26201
|
+
var MAX_RUNTIME_STOP_GRACE_MS = 6e5;
|
|
26202
|
+
function runtimeStopGraceMs(env = process.env) {
|
|
26203
|
+
const raw = env.KXM_RUNTIME_STOP_GRACE_MS;
|
|
26204
|
+
if (raw === void 0 || raw.trim() === "") return DEFAULT_RUNTIME_STOP_GRACE_MS;
|
|
26205
|
+
const parsed = Number(raw.trim());
|
|
26206
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < 0 || parsed > MAX_RUNTIME_STOP_GRACE_MS) {
|
|
26207
|
+
process.stderr.write(
|
|
26208
|
+
`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}
|
|
26209
|
+
`
|
|
26210
|
+
);
|
|
26211
|
+
return DEFAULT_RUNTIME_STOP_GRACE_MS;
|
|
26212
|
+
}
|
|
26213
|
+
return parsed;
|
|
26214
|
+
}
|
|
26215
|
+
async function waitForDriveSessions(settled, graceMs) {
|
|
26216
|
+
if (settled.length === 0) return;
|
|
26217
|
+
let timeout;
|
|
26218
|
+
try {
|
|
26219
|
+
await Promise.race([
|
|
26220
|
+
Promise.allSettled(settled),
|
|
26221
|
+
new Promise((resolve7) => {
|
|
26222
|
+
timeout = setTimeout(resolve7, graceMs);
|
|
26223
|
+
timeout.unref?.();
|
|
26224
|
+
})
|
|
26225
|
+
]);
|
|
26226
|
+
} finally {
|
|
26227
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
26228
|
+
}
|
|
26229
|
+
}
|
|
26020
26230
|
async function startVnextRuntimeSupervisor(options = {}) {
|
|
26021
26231
|
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
26022
26232
|
const paths = vnextRuntimePaths(options.stateRoot !== void 0 ? { stateRoot: options.stateRoot } : {});
|
|
@@ -26038,7 +26248,6 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
|
|
|
26038
26248
|
const runtimeId = `rtm_${createHash11("sha256").update(`${paths.stateRoot}\0${process.pid}\0${now()}\0${randomBytes2(16).toString("hex")}`, "utf8").digest("hex").slice(0, 24)}`;
|
|
26039
26249
|
const requestedPort = requestedPortOption ?? 0;
|
|
26040
26250
|
let activeRuntimeId = runtimeId;
|
|
26041
|
-
const activeDrives = /* @__PURE__ */ new Map();
|
|
26042
26251
|
const contexts = /* @__PURE__ */ new Map();
|
|
26043
26252
|
const contextFor = (projectRoot) => {
|
|
26044
26253
|
if (!isAbsolute4(projectRoot)) {
|
|
@@ -26132,34 +26341,8 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
|
|
|
26132
26341
|
}
|
|
26133
26342
|
const run = context.eventStore.run(runId);
|
|
26134
26343
|
if (!run) throw runtimeError("run_unknown", runId, "run not found");
|
|
26135
|
-
|
|
26136
|
-
|
|
26137
|
-
return;
|
|
26138
|
-
}
|
|
26139
|
-
if (run.status === "completed" || run.status === "failed" || run.status === "cancelled" || run.status === "cancelling") {
|
|
26140
|
-
sendJson(response, 409, { ok: false, error: "run_busy", message: `run ${runId} is already ${run.status}` });
|
|
26141
|
-
return;
|
|
26142
|
-
}
|
|
26143
|
-
let releaseActive = () => {
|
|
26144
|
-
};
|
|
26145
|
-
const activePromise = new Promise((resolve7) => {
|
|
26146
|
-
releaseActive = resolve7;
|
|
26147
|
-
});
|
|
26148
|
-
activeDrives.set(runId, activePromise);
|
|
26149
|
-
const cleanupActive = () => {
|
|
26150
|
-
activeDrives.delete(runId);
|
|
26151
|
-
releaseActive();
|
|
26152
|
-
};
|
|
26153
|
-
if (run.status === "created") {
|
|
26154
|
-
pinVnextCompiledPlan(context, bundle, runId);
|
|
26155
|
-
const plan = startVnextRun(context, runId, { allowLimits: true });
|
|
26156
|
-
if (plan.handoff) {
|
|
26157
|
-
cleanupActive();
|
|
26158
|
-
sendJson(response, 409, { ok: false, error: "run_handoff_required", handoff: plan.handoff });
|
|
26159
|
-
return;
|
|
26160
|
-
}
|
|
26161
|
-
}
|
|
26162
|
-
const producer = body.mode === "live" ? createVnextOneShotProducer({
|
|
26344
|
+
const delayMs = typeof body.delayMs === "number" && body.delayMs > 0 ? body.delayMs : 0;
|
|
26345
|
+
const createProducer = () => body.mode === "live" ? createVnextOneShotProducer({
|
|
26163
26346
|
projectRoot,
|
|
26164
26347
|
defaultHarness: String(bundle.project.value.defaultHarness ?? "pi"),
|
|
26165
26348
|
resolveHarness: (agentId) => {
|
|
@@ -26178,56 +26361,50 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
|
|
|
26178
26361
|
}
|
|
26179
26362
|
return { provider, model: modelName };
|
|
26180
26363
|
}
|
|
26181
|
-
}) : (() => {
|
|
26182
|
-
|
|
26183
|
-
|
|
26184
|
-
|
|
26185
|
-
|
|
26186
|
-
|
|
26187
|
-
|
|
26188
|
-
});
|
|
26189
|
-
})();
|
|
26190
|
-
let drivePromise;
|
|
26364
|
+
}) : createVnextSimulatedProducer(async () => {
|
|
26365
|
+
if (delayMs > 0) {
|
|
26366
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
26367
|
+
}
|
|
26368
|
+
return { outcome: "passed" };
|
|
26369
|
+
});
|
|
26370
|
+
let session;
|
|
26191
26371
|
let earlyError;
|
|
26192
26372
|
try {
|
|
26193
26373
|
const scheduler = VnextRunScheduler.for(context, bundle);
|
|
26194
|
-
|
|
26195
|
-
|
|
26374
|
+
const opening = scheduler.openDriveSession(runId, {
|
|
26375
|
+
mode: body.mode,
|
|
26376
|
+
allowLimits: true,
|
|
26377
|
+
liveMode: body.mode === "live",
|
|
26378
|
+
createProducer
|
|
26379
|
+
});
|
|
26380
|
+
opening.catch((err) => {
|
|
26196
26381
|
earlyError = err;
|
|
26197
26382
|
});
|
|
26383
|
+
session = await opening;
|
|
26198
26384
|
} catch (err) {
|
|
26199
26385
|
earlyError = err;
|
|
26200
26386
|
}
|
|
26201
|
-
await Promise.resolve();
|
|
26202
26387
|
if (earlyError) {
|
|
26203
|
-
cleanupActive();
|
|
26204
26388
|
const errStr = String(earlyError);
|
|
26389
|
+
if (errStr.includes("run_handoff_required")) {
|
|
26390
|
+
const handoff = earlyError.handoff;
|
|
26391
|
+
sendJson(response, 409, { ok: false, error: "run_handoff_required", ...handoff !== void 0 ? { handoff } : {} });
|
|
26392
|
+
return;
|
|
26393
|
+
}
|
|
26205
26394
|
if (errStr.includes("run_busy") || errStr.includes("scheduler_policy_conflict")) {
|
|
26206
|
-
if ("close" in producer && typeof producer.close === "function") {
|
|
26207
|
-
try {
|
|
26208
|
-
await producer.close();
|
|
26209
|
-
} catch {
|
|
26210
|
-
}
|
|
26211
|
-
}
|
|
26212
26395
|
sendJson(response, 409, { ok: false, error: "run_busy", message: `run ${runId} is already admitted or queued` });
|
|
26213
26396
|
return;
|
|
26214
26397
|
}
|
|
26215
26398
|
throw earlyError;
|
|
26216
26399
|
}
|
|
26217
|
-
void
|
|
26218
|
-
cleanupActive();
|
|
26219
|
-
if ("close" in producer && typeof producer.close === "function") {
|
|
26220
|
-
try {
|
|
26221
|
-
await producer.close();
|
|
26222
|
-
} catch {
|
|
26223
|
-
}
|
|
26224
|
-
}
|
|
26225
|
-
}).catch(() => {
|
|
26400
|
+
void session.settled.catch(() => {
|
|
26226
26401
|
});
|
|
26402
|
+
if (response.writableEnded) return;
|
|
26227
26403
|
sendJson(response, 202, {
|
|
26228
26404
|
ok: true,
|
|
26229
26405
|
status: "accepted",
|
|
26230
26406
|
runId,
|
|
26407
|
+
driveId: session.driveId,
|
|
26231
26408
|
poll: `/v1/runs/${runId}`,
|
|
26232
26409
|
mode: body.mode
|
|
26233
26410
|
});
|
|
@@ -26358,9 +26535,18 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
|
|
|
26358
26535
|
registry.markStopping(process.pid, now());
|
|
26359
26536
|
} catch {
|
|
26360
26537
|
}
|
|
26361
|
-
|
|
26362
|
-
|
|
26538
|
+
const openSessions = [...contexts.values()].flatMap((context) => vnextOpenDriveSessions(context.eventStore.path).map((session) => ({ context, session })));
|
|
26539
|
+
for (const { context, session } of openSessions) {
|
|
26540
|
+
try {
|
|
26541
|
+
cancelVnextRun(context, session.runId, { reason: "runtime_shutdown" });
|
|
26542
|
+
} catch {
|
|
26543
|
+
}
|
|
26544
|
+
try {
|
|
26545
|
+
session.controller.abort();
|
|
26546
|
+
} catch {
|
|
26547
|
+
}
|
|
26363
26548
|
}
|
|
26549
|
+
await waitForDriveSessions(openSessions.map(({ session }) => session.settled), runtimeStopGraceMs());
|
|
26364
26550
|
for (const context of contexts.values()) closeVnextRuntimeContext(context);
|
|
26365
26551
|
contexts.clear();
|
|
26366
26552
|
const closed = new Promise((resolveStop) => server.close(() => resolveStop()));
|
|
@@ -26398,10 +26584,13 @@ async function vnextRuntimeRequest(handle, method, path, body) {
|
|
|
26398
26584
|
return payload;
|
|
26399
26585
|
}
|
|
26400
26586
|
export {
|
|
26587
|
+
DEFAULT_RUNTIME_STOP_GRACE_MS,
|
|
26588
|
+
MAX_RUNTIME_STOP_GRACE_MS,
|
|
26401
26589
|
ensureVnextSupervisor,
|
|
26402
26590
|
hashVnextSupervisorToken,
|
|
26403
26591
|
hashVnextTokenProof,
|
|
26404
26592
|
readVnextSupervisorToken,
|
|
26593
|
+
runtimeStopGraceMs,
|
|
26405
26594
|
startVnextRuntimeSupervisor,
|
|
26406
26595
|
vnextRuntimeRequest,
|
|
26407
26596
|
vnextSupervisorStatus,
|
package/plugins/kxm/package.json
CHANGED
|
@@ -43,6 +43,11 @@ import { loadKxmUpdateConfig } from "../kxm-update-config.ts";
|
|
|
43
43
|
import type { InstallKindReport, InstallProbe } from "../kxm-install-kind.ts";
|
|
44
44
|
import { print, type CliIo, type CliSpawnResult, type Runtime } from "./types.ts";
|
|
45
45
|
|
|
46
|
+
export const vnextDriveCliSeams: {
|
|
47
|
+
ensureSupervisor?: typeof ensureVnextSupervisor;
|
|
48
|
+
runtimeRequest?: typeof vnextRuntimeRequest;
|
|
49
|
+
} = {};
|
|
50
|
+
|
|
46
51
|
const repoRoot = resolve(fileURLToPath(new URL("../../../../", import.meta.url)));
|
|
47
52
|
|
|
48
53
|
export function initPlanPayload(plan: VnextInitializationPlan): Record<string, unknown> {
|
|
@@ -505,9 +510,21 @@ export async function cmdVnextRunDrive(runtime: Runtime, runId: string, simulate
|
|
|
505
510
|
print(runtime.io, runtime.json, { ok: true, command: "runs drive", dryRun: true, runId, mode }, `drive plan: run ${runId} in ${mode} mode (no events written)`);
|
|
506
511
|
return 0;
|
|
507
512
|
}
|
|
508
|
-
const supervisor = await ensureVnextSupervisor({ env: runtime.env });
|
|
509
|
-
const result = await vnextRuntimeRequest(supervisor, "POST", `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`, { mode });
|
|
510
|
-
|
|
513
|
+
const supervisor = await (vnextDriveCliSeams.ensureSupervisor ?? ensureVnextSupervisor)({ env: runtime.env });
|
|
514
|
+
const result = await (vnextDriveCliSeams.runtimeRequest ?? vnextRuntimeRequest)(supervisor, "POST", `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`, { mode });
|
|
515
|
+
const driveId = result.driveId;
|
|
516
|
+
const poll = result.poll;
|
|
517
|
+
const status = result.status;
|
|
518
|
+
if (typeof driveId !== "string" || driveId.length === 0 || typeof poll !== "string" || poll.length === 0 || status !== "accepted") {
|
|
519
|
+
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");
|
|
520
|
+
return 1;
|
|
521
|
+
}
|
|
522
|
+
print(
|
|
523
|
+
runtime.io,
|
|
524
|
+
runtime.json,
|
|
525
|
+
{ ok: true, command: "runs drive", runId, driveId, poll, mode, status },
|
|
526
|
+
`drive ${driveId}: accepted (poll ${poll})`,
|
|
527
|
+
);
|
|
511
528
|
return 0;
|
|
512
529
|
} catch (error) {
|
|
513
530
|
if (error instanceof VnextConfigError) {
|
|
@@ -7,7 +7,7 @@ import { AGENT_COMMANDS_MAP, enforceToolPolicy, getMcpTools, reconcileInbox } fr
|
|
|
7
7
|
import { deliverInboxNotification } from "./inbox.ts";
|
|
8
8
|
import type { HubEvent, MessageRecord } from "./protocol.ts";
|
|
9
9
|
|
|
10
|
-
const VERSION = "0.7.
|
|
10
|
+
const VERSION = "0.7.15";
|
|
11
11
|
const inbox = new Map<string, MessageRecord>();
|
|
12
12
|
const notifiedInbox = new Set<string>();
|
|
13
13
|
let meshClient: HubClient | undefined;
|