@linzumi/cli 0.0.108-beta → 0.0.109-beta

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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +117 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -58,7 +58,7 @@ Install the CLI or run it with `npx`:
58
58
  ```bash
59
59
  npm install -g @linzumi/cli@latest
60
60
  npx -y @linzumi/cli@latest signup
61
- npx -y @linzumi/cli@0.0.108-beta --version
61
+ npx -y @linzumi/cli@0.0.109-beta --version
62
62
  linzumi --version
63
63
  ```
64
64
 
package/dist/index.js CHANGED
@@ -20078,7 +20078,7 @@ var linzumiCliVersion, linzumiCliVersionText;
20078
20078
  var init_version = __esm({
20079
20079
  "src/version.ts"() {
20080
20080
  "use strict";
20081
- linzumiCliVersion = "0.0.108-beta";
20081
+ linzumiCliVersion = "0.0.109-beta";
20082
20082
  linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
20083
20083
  }
20084
20084
  });
@@ -25064,6 +25064,7 @@ async function openLocalCodexRunner(options, log2, cleanup, close, runnerDrainHo
25064
25064
  const latestResumeReconcileByThread = /* @__PURE__ */ new Map();
25065
25065
  let acceptingInbound = true;
25066
25066
  const inboundQueueWorkspace = () => runnerWorkspaceSlug(options) ?? "default";
25067
+ const resolveRunnerBoundChannel = () => options.channelSession?.channelSlug ?? threadSessionRegistry.list()[0]?.channel;
25067
25068
  const durableInboundQueueFor = (channel, kandanThreadId) => {
25068
25069
  const workspace = inboundQueueWorkspace();
25069
25070
  const cacheKey = `${workspace}:${channel}:${kandanThreadId}`;
@@ -26845,7 +26846,25 @@ async function openLocalCodexRunner(options, log2, cleanup, close, runnerDrainHo
26845
26846
  }
26846
26847
  const record = threadSessionRegistry.list().find((entry) => entry.kandanThreadId === kandanThreadId);
26847
26848
  if (record === void 0) {
26848
- return "ignored";
26849
+ const boundChannel = resolveRunnerBoundChannel();
26850
+ if (boundChannel === void 0 || !acceptingInbound) {
26851
+ return "ignored";
26852
+ }
26853
+ const queue2 = durableInboundQueueFor(boundChannel, kandanThreadId);
26854
+ const enqueued = queue2.enqueue(
26855
+ event.seq,
26856
+ event.localRunnerEventType === void 0 ? "live" : "replay",
26857
+ serializeKandanChatEventForQueue(event),
26858
+ Date.now()
26859
+ );
26860
+ log2("runner.spawn_on_miss_enqueued_without_local_record", {
26861
+ kandanThreadId,
26862
+ channel: boundChannel,
26863
+ seq: event.seq,
26864
+ enqueued: enqueued.accepted
26865
+ });
26866
+ await publishUnroutedDurableEnqueueState(boundChannel, event);
26867
+ return "spawned";
26849
26868
  }
26850
26869
  const queueChannel = record.channel;
26851
26870
  const watermarkKey = threadSourceSeqWatermarkKey(
@@ -26971,6 +26990,44 @@ async function openLocalCodexRunner(options, log2, cleanup, close, runnerDrainHo
26971
26990
  }
26972
26991
  });
26973
26992
  };
26993
+ const drainThreadQueueAfterSpawn = async (kandanThreadId, spawnResponse) => {
26994
+ if (spawnResponse !== void 0 && spawnResponse.ok === false) {
26995
+ return;
26996
+ }
26997
+ if (!acceptingInbound) {
26998
+ return;
26999
+ }
27000
+ const record = threadSessionRegistry.list().find((entry) => entry.kandanThreadId === kandanThreadId);
27001
+ if (record === void 0) {
27002
+ return;
27003
+ }
27004
+ const queue = durableInboundQueueFor(record.channel, kandanThreadId);
27005
+ if (queue.entries().length === 0) {
27006
+ return;
27007
+ }
27008
+ log2("runner.inbound_drain_after_spawn", {
27009
+ kandanThreadId,
27010
+ channel: record.channel,
27011
+ pending: queue.entries().length
27012
+ });
27013
+ await drainOwnedThreadQueue(
27014
+ record,
27015
+ latestResumeReconcileByThread.get(kandanThreadId) ?? []
27016
+ ).catch((error) => {
27017
+ log2("runner.inbound_drain_after_spawn_failed", {
27018
+ kandanThreadId,
27019
+ message: error instanceof Error ? error.message : String(error)
27020
+ });
27021
+ });
27022
+ };
27023
+ const startThreadRunnerProcessFromServerControl = async (control, cwd) => {
27024
+ const response = await startThreadRunnerProcess(control, cwd);
27025
+ const kandanThreadId = optionalThreadControlField(control, "threadId");
27026
+ if (kandanThreadId !== void 0) {
27027
+ await drainThreadQueueAfterSpawn(kandanThreadId, response);
27028
+ }
27029
+ return response;
27030
+ };
26974
27031
  const consumeResumeReconcile = (reconcileValue) => {
26975
27032
  const byThread = /* @__PURE__ */ new Map();
26976
27033
  const entries = parseResumeReconcileEntries(reconcileValue);
@@ -27228,6 +27285,29 @@ async function openLocalCodexRunner(options, log2, cleanup, close, runnerDrainHo
27228
27285
  });
27229
27286
  }
27230
27287
  };
27288
+ const publishUnroutedDurableEnqueueState = async (channel, event) => {
27289
+ if (event.threadId === void 0) {
27290
+ return;
27291
+ }
27292
+ const payload = {
27293
+ workspace: inboundQueueWorkspace(),
27294
+ channel,
27295
+ thread_id: event.threadId,
27296
+ instance_id: instanceId,
27297
+ seq: event.seq,
27298
+ status: "queued",
27299
+ reason: "queued for durable resume"
27300
+ };
27301
+ try {
27302
+ await kandan.push(topic, "message_state", payload);
27303
+ } catch (error) {
27304
+ log2("runner.spawn_on_miss_state_push_failed", {
27305
+ thread_id: event.threadId,
27306
+ status: "queued",
27307
+ message: error instanceof Error ? error.message : String(error)
27308
+ });
27309
+ }
27310
+ };
27231
27311
  const deadLetterPublisherFor = (record) => {
27232
27312
  return async ({ sourceSeq, reason, attempts, alreadyPublished }) => {
27233
27313
  log2("runner.inbound_dead_lettered", {
@@ -27738,7 +27818,7 @@ async function openLocalCodexRunner(options, log2, cleanup, close, runnerDrainHo
27738
27818
  control,
27739
27819
  log2,
27740
27820
  attachThreadSession,
27741
- shouldUseThreadProcesses(options) ? startThreadRunnerProcess : void 0,
27821
+ shouldUseThreadProcesses(options) ? startThreadRunnerProcessFromServerControl : void 0,
27742
27822
  (id) => leaseEpochRegistry.current(id),
27743
27823
  commitLiveWorkerAcceptedSourceSeq,
27744
27824
  captureLiveFollowUpEvent,
@@ -31326,7 +31406,8 @@ ${developerPrompt}`,
31326
31406
  metadata: {
31327
31407
  local_codex_runner: {
31328
31408
  event_type: "codex_start_instructions",
31329
- codex_thread_id: codexThreadId
31409
+ codex_thread_id: codexThreadId,
31410
+ instructions_body: developerPrompt
31330
31411
  }
31331
31412
  }
31332
31413
  },
@@ -70921,22 +71002,49 @@ async function resolveMcpAuth(args) {
70921
71002
  mode: "personal-agent-delegation"
70922
71003
  };
70923
71004
  }
70924
- const token = args.explicitToken ?? readCachedLocalRunnerToken(args.kandanUrl, args.authFilePath)?.accessToken;
71005
+ const accessToken = await resolveMcpLocalRunnerToken({
71006
+ kandanUrl: args.kandanUrl,
71007
+ explicitToken: args.explicitToken,
71008
+ authFilePath: args.authFilePath,
71009
+ workspaceSlug: args.workspaceSlug,
71010
+ channelSlug: args.channelSlug
71011
+ });
71012
+ return { accessToken, mode: "local-runner" };
71013
+ }
71014
+ async function resolveMcpLocalRunnerToken(args, deps = {
71015
+ readCachedToken: readCachedLocalRunnerToken,
71016
+ validateTokenOutcome: validateLocalRunnerTokenOutcome,
71017
+ resolveToken: resolveLocalRunnerToken
71018
+ }) {
71019
+ const token = args.explicitToken ?? deps.readCachedToken(args.kandanUrl, args.authFilePath)?.accessToken;
70925
71020
  if (token === void 0) {
70926
71021
  throw new Error(
70927
71022
  "missing Linzumi MCP token; run linzumi auth or pass --token"
70928
71023
  );
70929
71024
  }
70930
- const valid = await validateLocalRunnerToken({
71025
+ const outcome = await deps.validateTokenOutcome({
70931
71026
  kandanUrl: args.kandanUrl,
70932
71027
  accessToken: token,
70933
71028
  workspaceSlug: args.workspaceSlug,
70934
71029
  channelSlug: args.channelSlug
70935
71030
  });
70936
- if (!valid) {
70937
- throw new Error("Linzumi MCP token was rejected by the server");
71031
+ if (outcome === "usable") {
71032
+ return token;
71033
+ }
71034
+ const _recoverable = outcome;
71035
+ void _recoverable;
71036
+ try {
71037
+ return await deps.resolveToken({
71038
+ kandanUrl: args.kandanUrl,
71039
+ workspaceSlug: args.workspaceSlug,
71040
+ channelSlug: args.channelSlug,
71041
+ authFilePath: args.authFilePath
71042
+ });
71043
+ } catch (error) {
71044
+ throw new Error(
71045
+ `Linzumi MCP token was rejected by the server and re-mint failed: ${error instanceof Error ? error.message : String(error)}`
71046
+ );
70938
71047
  }
70939
- return { accessToken: token, mode: "local-runner" };
70940
71048
  }
70941
71049
  function mcpJsonResult(value) {
70942
71050
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "0.0.108-beta",
3
+ "version": "0.0.109-beta",
4
4
  "description": "Linzumi CLI \u2014 point a Codex agent at the real code on your laptop, with your team watching and steering from shared threads.",
5
5
  "type": "module",
6
6
  "bin": {