@kontextmind/kxm 0.7.14 → 0.7.16

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.
Files changed (47) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/docs/configuration.md +1 -2
  3. package/docs/operator-pi-packages.md +5 -2
  4. package/package.json +1 -1
  5. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  6. package/plugins/kxm/dist/cli.js +20 -3
  7. package/plugins/kxm/dist/core.js +4 -0
  8. package/plugins/kxm/dist/extension.js +3066 -2
  9. package/plugins/kxm/dist/mcp-server.js +1 -1
  10. package/plugins/kxm/dist/runtime.js +263 -70
  11. package/plugins/kxm/dist/server.js +4 -0
  12. package/plugins/kxm/dist/vnext-runtime-supervisor.js +259 -70
  13. package/plugins/kxm/package.json +1 -1
  14. package/plugins/kxm/src/cli/vnext.ts +20 -3
  15. package/plugins/kxm/src/extension.ts +9 -0
  16. package/plugins/kxm/src/mcp-server.ts +1 -1
  17. package/plugins/kxm/src/providers/antigravity/LICENSE +21 -0
  18. package/plugins/kxm/src/providers/antigravity/README.md +19 -0
  19. package/plugins/kxm/src/providers/antigravity/auth/index.ts +17 -0
  20. package/plugins/kxm/src/providers/antigravity/auth/oauth.ts +449 -0
  21. package/plugins/kxm/src/providers/antigravity/client/client.ts +562 -0
  22. package/plugins/kxm/src/providers/antigravity/client/index.ts +1 -0
  23. package/plugins/kxm/src/providers/antigravity/diagnostics/diagnostics.ts +97 -0
  24. package/plugins/kxm/src/providers/antigravity/diagnostics/index.ts +1 -0
  25. package/plugins/kxm/src/providers/antigravity/index.ts +24 -0
  26. package/plugins/kxm/src/providers/antigravity/models/discovery.ts +155 -0
  27. package/plugins/kxm/src/providers/antigravity/models/grouping.ts +425 -0
  28. package/plugins/kxm/src/providers/antigravity/models/index.ts +3 -0
  29. package/plugins/kxm/src/providers/antigravity/models/models.ts +501 -0
  30. package/plugins/kxm/src/providers/antigravity/pi-compat.ts +279 -0
  31. package/plugins/kxm/src/providers/antigravity/register.ts +123 -0
  32. package/plugins/kxm/src/providers/antigravity/stream/index.ts +1 -0
  33. package/plugins/kxm/src/providers/antigravity/stream/stream.ts +1461 -0
  34. package/plugins/kxm/src/providers/antigravity/types/enums.ts +50 -0
  35. package/plugins/kxm/src/providers/antigravity/types/index.ts +2 -0
  36. package/plugins/kxm/src/providers/antigravity/types/types.ts +293 -0
  37. package/plugins/kxm/src/providers/antigravity/usage/index.ts +1 -0
  38. package/plugins/kxm/src/providers/antigravity/usage/usage.ts +361 -0
  39. package/plugins/kxm/src/providers/antigravity/utils/http.ts +32 -0
  40. package/plugins/kxm/src/providers/antigravity/utils/index.ts +3 -0
  41. package/plugins/kxm/src/providers/antigravity/utils/security.ts +75 -0
  42. package/plugins/kxm/src/providers/antigravity/utils/util.ts +133 -0
  43. package/plugins/kxm/src/redact.ts +4 -0
  44. package/plugins/kxm/src/vnext-engine.ts +183 -3
  45. package/plugins/kxm/src/vnext-runtime-owner.ts +50 -0
  46. package/plugins/kxm/src/vnext-runtime-supervisor.ts +83 -58
  47. 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: "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.16",
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) {
@@ -5,6 +5,11 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
5
5
  import { AGENT_COMMANDS, enforceToolPolicy } from "./commands.ts";
6
6
  import { HubClient, HubHttpError } from "./client.ts";
7
7
  import { nousFactoryWork, type NousRegistrationReport } from "./nous-pi.ts";
8
+ import {
9
+ antigravityRegistrationNotice,
10
+ registerAntigravityProvider,
11
+ type AntigravityRegistration,
12
+ } from "./providers/antigravity/register.ts";
8
13
  import { areaForTool, classifyFailure, diagnosticEvidence, diagnosticSummary, type Diagnostic } from "./diagnostics.ts";
9
14
  import {
10
15
  MAX_CONTENT_CHARS,
@@ -160,6 +165,7 @@ export function assistantFailure(messages: unknown[]): Diagnostic | undefined {
160
165
  export default function piMeshExtension(pi: ExtensionAPI): void | Promise<void> {
161
166
  let client: HubClient | undefined;
162
167
  let nousReport: NousRegistrationReport | undefined;
168
+ let antigravityReport: AntigravityRegistration | undefined;
163
169
  let pending: MessageRecord[] = [];
164
170
  let activatingInbound: MessageRecord | undefined;
165
171
  let awaitingActivation: MessageRecord | undefined;
@@ -640,6 +646,8 @@ export default function piMeshExtension(pi: ExtensionAPI): void | Promise<void>
640
646
 
641
647
  pi.on("session_start", async (event: { reason?: string }, ctx) => {
642
648
  shuttingDown = false;
649
+ const antigravityNotice = antigravityRegistrationNotice(antigravityReport, pi);
650
+ if (antigravityNotice) ctx.ui.notify(antigravityNotice.message, antigravityNotice.type);
643
651
  if (nousReport?.guidance.length) {
644
652
  for (const item of nousReport.guidance) {
645
653
  ctx.ui.notify(item.message, item.level);
@@ -924,6 +932,7 @@ export default function piMeshExtension(pi: ExtensionAPI): void | Promise<void>
924
932
  },
925
933
  });
926
934
 
935
+ antigravityReport = registerAntigravityProvider(pi);
927
936
  return nousFactoryWork(pi, (report) => {
928
937
  nousReport = report;
929
938
  });
@@ -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.16";
11
11
  const inbox = new Map<string, MessageRecord>();
12
12
  const notifiedInbox = new Set<string>();
13
13
  let meshClient: HubClient | undefined;
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rahul Arya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,19 @@
1
+ # Antigravity provider (vendored)
2
+
3
+ Provider-only subset of `pi-antigravity`, built into the kxm plugin.
4
+
5
+ - Upstream: [Rahularya01/pi-antigravity](https://github.com/Rahularya01/pi-antigravity)
6
+ - KontextMind fork: [kontextmind/pi-antigravity](https://github.com/kontextmind/pi-antigravity)
7
+ - Fork commit: `86f76ab08f16784be5bfc281dda9c645651a433b`
8
+ - License: MIT, Copyright (c) 2026 Rahul Arya — see `LICENSE`
9
+
10
+ The Pi provider id remains `antigravity` so existing credentials in Pi's auth
11
+ store (`/login antigravity`) carry over. This slice vendors Google OAuth
12
+ (PKCE, `localhost:51121` callback + paste-URL fallback), Cloud Code Assist
13
+ streaming, dynamic model catalog with last-known-good cache and static
14
+ fallback, thinking-variant mapping, and quota surfaces used by the model list.
15
+
16
+ Not vendored here: image generation, `/antigravity.image`, and extra slash
17
+ commands (`/antigravity.models`, `/antigravity.doctor`). `usage.ts` is a dead
18
+ slash-command surface kept because quota parsing shares client types; it is not
19
+ registered. No `@earendil-works/pi-ai` import.
@@ -0,0 +1,17 @@
1
+ export {
2
+ loginAntigravity,
3
+ refreshAntigravityToken,
4
+ getApiKey,
5
+ CLIENT_ID,
6
+ CLIENT_SECRET,
7
+ REDIRECT_URI,
8
+ AUTH_URL,
9
+ TOKEN_URL,
10
+ SCOPES,
11
+ CALLBACK_HOST,
12
+ OAUTH_CALLBACK_TIMEOUT_MS,
13
+ generatePKCE,
14
+ buildAuthorizationUrl,
15
+ parsePastedCallback,
16
+ } from "./oauth.ts";
17
+ export type { OAuthCredentials, OAuthLoginCallbacks } from "./oauth.ts";