@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.
@@ -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: "operator_cancel"
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: "operator_cancel" });
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: "operator_cancel" });
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: "operator_cancel" });
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: "operator_cancel" });
21912
- push("run.status_changed", { status: "cancelled", reason: "operator_cancel" });
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: "operator_cancel" });
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, configRevision) {
23884
+ constructor(context, bundle) {
23794
23885
  this.context = context;
23795
- this.configRevision = configRevision;
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.configRevision);
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
- if (activeDrives.has(runId)) {
26136
- sendJson(response, 409, { ok: false, error: "run_busy", message: `run ${runId} is already executing` });
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
- const delayMs = typeof body.delayMs === "number" && body.delayMs > 0 ? body.delayMs : 0;
26183
- return createVnextSimulatedProducer(async () => {
26184
- if (delayMs > 0) {
26185
- await new Promise((r) => setTimeout(r, delayMs));
26186
- }
26187
- return { outcome: "passed" };
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
- drivePromise = scheduler.enqueue(runId, producer, { allowLimits: true, liveMode: body.mode === "live" });
26195
- drivePromise.catch((err) => {
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 drivePromise.finally(async () => {
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
- if (activeDrives.size > 0) {
26362
- await Promise.allSettled([...activeDrives.values()]);
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,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kxm-claude-plugin",
3
- "version": "0.7.14",
3
+ "version": "0.7.15",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -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
- print(runtime.io, runtime.json, { ok: true, command: "runs drive", run: result.run, handoff: result.handoff, events: result.events }, `run ${runId}: ${(result.run as { status?: string } | undefined)?.status ?? "driven"}`);
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.14";
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;