@linzumi/cli 0.0.89-beta → 0.0.90-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 +141 -18
  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.89-beta --version
61
+ npx -y @linzumi/cli@0.0.90-beta --version
62
62
  linzumi --version
63
63
  ```
64
64
 
package/dist/index.js CHANGED
@@ -5338,6 +5338,43 @@ var init_itemProjection = __esm({
5338
5338
  function rowStreamStateIsTerminal(state) {
5339
5339
  return state !== void 0 && terminalRowStreamStates.has(state);
5340
5340
  }
5341
+ function codexProtocolFailureReasonFromItems(items) {
5342
+ for (const value of items) {
5343
+ const reason = codexProtocolFailureReasonFromItem(objectValue(value));
5344
+ if (reason !== void 0) {
5345
+ return reason;
5346
+ }
5347
+ }
5348
+ return void 0;
5349
+ }
5350
+ function codexProtocolFailureReasonFromItem(item) {
5351
+ if (item === void 0) {
5352
+ return void 0;
5353
+ }
5354
+ const explicitReason = stringValue(item.codex_protocol_failure_reason) ?? stringValue(item.protocolFailureReason);
5355
+ if (explicitReason !== void 0) {
5356
+ return explicitReason;
5357
+ }
5358
+ const itemType = stringValue(item.type);
5359
+ if (itemType !== "function_call_output" && itemType !== "custom_tool_call_output") {
5360
+ return void 0;
5361
+ }
5362
+ const output = stringValue(item.output) ?? stringValue(item.result) ?? stringValue(item.text) ?? stringValue(item.content);
5363
+ const unsupportedCall = unsupportedCodexCallName(output);
5364
+ return unsupportedCall === void 0 ? void 0 : `${unsupportedCodexToolCallReasonPrefix}: ${unsupportedCall}`;
5365
+ }
5366
+ function unsupportedCodexCallName(output) {
5367
+ const prefix = "unsupported call:";
5368
+ if (output === void 0) {
5369
+ return void 0;
5370
+ }
5371
+ const normalized = output.trim();
5372
+ if (!normalized.toLowerCase().startsWith(prefix)) {
5373
+ return void 0;
5374
+ }
5375
+ const callName = normalized.slice(prefix.length).trim();
5376
+ return callName === "" ? "unknown" : callName;
5377
+ }
5341
5378
  function createInitialLoopState() {
5342
5379
  return {
5343
5380
  phase: "running",
@@ -5482,6 +5519,7 @@ function createTurn(state, turnId, sourceSeq) {
5482
5519
  turnId,
5483
5520
  sourceSeq,
5484
5521
  phase: "active",
5522
+ protocolFailureReason: void 0,
5485
5523
  items: []
5486
5524
  };
5487
5525
  state.turns.set(turnId, turn);
@@ -5588,6 +5626,10 @@ function handleDelta(turn, signal, deps, effects) {
5588
5626
  emitRowUpdate(turn, item, deltaIndex, streamState, deps, effects);
5589
5627
  }
5590
5628
  function handleItemCompleted(turn, params, deps, effects) {
5629
+ const completedItem = objectValue(params.item);
5630
+ if (completedItem !== void 0) {
5631
+ turn.protocolFailureReason ??= codexProtocolFailureReasonFromItem(completedItem);
5632
+ }
5591
5633
  const completed = completedItemForNotification(params);
5592
5634
  if (completed === void 0) {
5593
5635
  return;
@@ -5757,6 +5799,7 @@ function handleSnapshot(state, turnId, snapshot, deps, effects) {
5757
5799
  return;
5758
5800
  }
5759
5801
  const rawItems = Array.isArray(snapshot.items) ? snapshot.items : [];
5802
+ turn.protocolFailureReason ??= codexProtocolFailureReasonFromItems(rawItems);
5760
5803
  const projected = projectSnapshotItems(rawItems);
5761
5804
  const consumedItemKeys = /* @__PURE__ */ new Set();
5762
5805
  const matches = /* @__PURE__ */ new Map();
@@ -5862,6 +5905,17 @@ function handleSnapshot(state, turnId, snapshot, deps, effects) {
5862
5905
  const assistantResponseSeen = turn.items.some(
5863
5906
  (item) => item.identity.streamKind === "assistant" && item.posted
5864
5907
  ) || projected.some((proj) => proj.streamKind === "assistant");
5908
+ const terminalFailureReason = turn.protocolFailureReason ?? (assistantResponseSeen ? void 0 : completedWithoutAssistantOutputReason);
5909
+ if (turn.protocolFailureReason !== void 0) {
5910
+ effects.push(
5911
+ log("codex.turn_completed_with_protocol_failure", {
5912
+ thread_key: deps.threadKey,
5913
+ turn_id: turn.turnId,
5914
+ source_seq: turn.sourceSeq,
5915
+ reason: turn.protocolFailureReason
5916
+ })
5917
+ );
5918
+ }
5865
5919
  if (!assistantResponseSeen) {
5866
5920
  effects.push(
5867
5921
  log("codex.turn_completed_without_assistant_output", {
@@ -5880,19 +5934,19 @@ function handleSnapshot(state, turnId, snapshot, deps, effects) {
5880
5934
  thread_key: deps.threadKey,
5881
5935
  turn_id: turn.turnId,
5882
5936
  seq: turn.sourceSeq,
5883
- ...assistantResponseSeen ? { status: "processed" } : {
5937
+ ...terminalFailureReason === void 0 ? { status: "processed" } : {
5884
5938
  status: "failed",
5885
- reason: completedWithoutAssistantOutputReason
5939
+ reason: terminalFailureReason
5886
5940
  }
5887
5941
  },
5888
5942
  resolution: "must_ack"
5889
5943
  });
5890
5944
  effects.push(
5891
- assistantResponseSeen ? { type: "turnTerminal", turnId: turn.turnId, outcome: "completed" } : {
5945
+ terminalFailureReason === void 0 ? { type: "turnTerminal", turnId: turn.turnId, outcome: "completed" } : {
5892
5946
  type: "turnTerminal",
5893
5947
  turnId: turn.turnId,
5894
5948
  outcome: "failed",
5895
- reason: completedWithoutAssistantOutputReason
5949
+ reason: terminalFailureReason
5896
5950
  }
5897
5951
  );
5898
5952
  state.turns.delete(turn.turnId);
@@ -5973,7 +6027,7 @@ function failureReason(params) {
5973
6027
  function log(event, fields) {
5974
6028
  return { type: "log", event, fields };
5975
6029
  }
5976
- var terminalRowStreamStates, turnMappingReadyMethod, turnMappingFailedMethod, maxTerminalTurnIds, completedWithoutAssistantOutputReason, turnTerminalFailureMethods, handledNotificationMethods;
6030
+ var terminalRowStreamStates, turnMappingReadyMethod, turnMappingFailedMethod, maxTerminalTurnIds, completedWithoutAssistantOutputReason, unsupportedCodexToolCallReasonPrefix, turnTerminalFailureMethods, handledNotificationMethods;
5977
6031
  var init_transition = __esm({
5978
6032
  "src/pipeline/transition.ts"() {
5979
6033
  "use strict";
@@ -5989,6 +6043,7 @@ var init_transition = __esm({
5989
6043
  turnMappingFailedMethod = "pipeline/turnMappingFailed";
5990
6044
  maxTerminalTurnIds = 512;
5991
6045
  completedWithoutAssistantOutputReason = "Codex completed without producing a response.";
6046
+ unsupportedCodexToolCallReasonPrefix = "Codex emitted unsupported tool call";
5992
6047
  turnTerminalFailureMethods = /* @__PURE__ */ new Map([
5993
6048
  ["turn/failed", "failed"],
5994
6049
  ["turn/aborted", "interrupted"],
@@ -6543,17 +6598,22 @@ function rawItemFromToolCallMessage(message) {
6543
6598
  const structured = message.structured;
6544
6599
  const itemId = /^item-\d+$/.test(message.itemKey) ? void 0 : message.itemKey;
6545
6600
  const idField = itemId === void 0 ? {} : { id: itemId };
6601
+ const output = typeof structured.output === "string" ? structured.output : "";
6546
6602
  switch (stringValue(structured.kind)) {
6547
- case "codex_command_execution":
6603
+ case "codex_command_execution": {
6604
+ const protocolFailureReason = unsupportedToolCallReason(output);
6605
+ const protocolFailureField = protocolFailureReason === void 0 ? {} : { codex_protocol_failure_reason: protocolFailureReason };
6548
6606
  return {
6549
6607
  type: "commandExecution",
6550
6608
  ...idField,
6609
+ ...protocolFailureField,
6551
6610
  command: stringValue(structured.command) ?? "command",
6552
6611
  cwd: stringValue(structured.cwd) ?? "",
6553
6612
  status: stringValue(structured.status) ?? "",
6554
6613
  ...stringValue(structured.process_id) === void 0 || stringValue(structured.process_id) === "" ? {} : { processId: stringValue(structured.process_id) },
6555
- aggregatedOutput: typeof structured.output === "string" ? structured.output : ""
6614
+ aggregatedOutput: output
6556
6615
  };
6616
+ }
6557
6617
  case "codex_file_change":
6558
6618
  return {
6559
6619
  type: "fileChange",
@@ -6566,6 +6626,15 @@ function rawItemFromToolCallMessage(message) {
6566
6626
  return void 0;
6567
6627
  }
6568
6628
  }
6629
+ function unsupportedToolCallReason(output) {
6630
+ const prefix = "unsupported call:";
6631
+ const normalized = output.trim();
6632
+ if (!normalized.toLowerCase().startsWith(prefix)) {
6633
+ return void 0;
6634
+ }
6635
+ const callName = normalized.slice(prefix.length).trim();
6636
+ return `Codex emitted unsupported tool call: ${callName === "" ? "unknown" : callName}`;
6637
+ }
6569
6638
  function mergeSnapshotItems(readItems, sessionItems) {
6570
6639
  if (sessionItems.length === 0) {
6571
6640
  return [...readItems];
@@ -11599,6 +11668,23 @@ var init_channelSession = __esm({
11599
11668
  // src/claudeCodePipeline.ts
11600
11669
  import { existsSync as existsSync3 } from "node:fs";
11601
11670
  import { isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
11671
+ function claudeIncompleteProgressCompletionReason(body, bodySource) {
11672
+ if (bodySource !== "assistant_aggregate") {
11673
+ return void 0;
11674
+ }
11675
+ const normalized = body.trim().replace(/\s+/g, " ").toLowerCase();
11676
+ if (normalized === "") {
11677
+ return void 0;
11678
+ }
11679
+ const continuationPatterns = [
11680
+ /\blet me\b.*\bbefore\b.*\b(writing|implementing|editing|patching|making|changing|coding|updating)\b/u,
11681
+ /\blet me\b.*\b(check|inspect|confirm|look|verify|investigate|find|review)\b/u,
11682
+ /\bi(?:'|\u2019)ll\b.*\b(check|inspect|confirm|look|verify|investigate|find|review|write|implement|update|edit|patch|run)\b/u,
11683
+ /\bi will\b.*\b(check|inspect|confirm|look|verify|investigate|find|review|write|implement|update|edit|patch|run)\b/u,
11684
+ /\bnext\b.*\b(i(?:'|\u2019)ll|i will|let me)\b/u
11685
+ ];
11686
+ return continuationPatterns.some((pattern) => pattern.test(normalized)) ? incompleteProgressCompletionReason : void 0;
11687
+ }
11602
11688
  function createClaudeCodeSessionPipeline(host) {
11603
11689
  const sourceSeqByTurn = /* @__PURE__ */ new Map();
11604
11690
  const snapshotsByTurn = /* @__PURE__ */ new Map();
@@ -11728,6 +11814,10 @@ function createClaudeCodeSessionPipeline(host) {
11728
11814
  submit("turn/completed", { turnId: turn.turnId });
11729
11815
  activeTurn = void 0;
11730
11816
  };
11817
+ const failTurn2 = (turn, reason) => {
11818
+ submit("turn/failed", { turnId: turn.turnId, reason });
11819
+ activeTurn = void 0;
11820
+ };
11731
11821
  const handleToolResult = (turn, event) => {
11732
11822
  const pending = turn.pendingTools.get(event.itemKey);
11733
11823
  turn.pendingTools.delete(event.itemKey);
@@ -11945,6 +12035,19 @@ function createClaudeCodeSessionPipeline(host) {
11945
12035
  }
11946
12036
  const turn = ensureTurn();
11947
12037
  lastUsage = event.usage ?? lastUsage;
12038
+ const incompleteProgressReason = claudeIncompleteProgressCompletionReason(
12039
+ event.body,
12040
+ event.bodySource
12041
+ );
12042
+ if (incompleteProgressReason !== void 0) {
12043
+ host.log("claude_pipeline.incomplete_progress_completion", {
12044
+ thread_key: host.threadKey,
12045
+ turn_id: turn.turnId,
12046
+ body_source: event.bodySource ?? "unspecified"
12047
+ });
12048
+ failTurn2(turn, incompleteProgressReason);
12049
+ return;
12050
+ }
11948
12051
  finishTurn(turn, event.body);
11949
12052
  return;
11950
12053
  }
@@ -11954,6 +12057,19 @@ function createClaudeCodeSessionPipeline(host) {
11954
12057
  return;
11955
12058
  }
11956
12059
  lastUsage = event.usage ?? lastUsage;
12060
+ const incompleteProgressReason = claudeIncompleteProgressCompletionReason(
12061
+ event.body,
12062
+ event.bodySource
12063
+ );
12064
+ if (incompleteProgressReason !== void 0) {
12065
+ host.log("claude_pipeline.incomplete_progress_completion", {
12066
+ thread_key: host.threadKey,
12067
+ turn_id: activeTurn.turnId,
12068
+ body_source: event.bodySource ?? "unspecified"
12069
+ });
12070
+ failTurn2(activeTurn, incompleteProgressReason);
12071
+ return;
12072
+ }
11957
12073
  finishTurn(activeTurn, event.body);
11958
12074
  return;
11959
12075
  }
@@ -11966,11 +12082,7 @@ function createClaudeCodeSessionPipeline(host) {
11966
12082
  });
11967
12083
  return;
11968
12084
  }
11969
- submit("turn/failed", {
11970
- turnId: activeTurn.turnId,
11971
- reason: event.reason
11972
- });
11973
- activeTurn = void 0;
12085
+ failTurn2(activeTurn, event.reason);
11974
12086
  return;
11975
12087
  }
11976
12088
  }
@@ -12182,12 +12294,13 @@ function claudeToolInputSummary(input) {
12182
12294
  return void 0;
12183
12295
  }
12184
12296
  }
12185
- var maxRetainedSnapshots, todoStatusGlyphs;
12297
+ var incompleteProgressCompletionReason, maxRetainedSnapshots, todoStatusGlyphs;
12186
12298
  var init_claudeCodePipeline = __esm({
12187
12299
  "src/claudeCodePipeline.ts"() {
12188
12300
  "use strict";
12189
12301
  init_json();
12190
12302
  init_integration();
12303
+ incompleteProgressCompletionReason = "Claude Code ended after an incomplete progress response instead of a final answer";
12191
12304
  maxRetainedSnapshots = 8;
12192
12305
  todoStatusGlyphs = {
12193
12306
  completed: "[x]",
@@ -13322,7 +13435,9 @@ async function startClaudeCodeSession(options) {
13322
13435
  return completeClaudeCodeSession(options, state);
13323
13436
  }
13324
13437
  async function emitClaudeCodeTurnCompleted(options, state) {
13325
- const body = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state)) ?? "";
13438
+ const aggregateText = nonEmptyText(claudeAssistantAggregateText(state));
13439
+ const body = state.resultText ?? aggregateText ?? "";
13440
+ const bodySource = state.resultText !== void 0 ? "result" : aggregateText !== void 0 ? "assistant_aggregate" : "empty";
13326
13441
  if (state.sessionId === void 0) {
13327
13442
  return;
13328
13443
  }
@@ -13330,12 +13445,17 @@ async function emitClaudeCodeTurnCompleted(options, state) {
13330
13445
  type: "turn_completed",
13331
13446
  sessionId: state.sessionId,
13332
13447
  body,
13448
+ bodySource,
13333
13449
  usage: state.usage
13334
13450
  });
13335
13451
  }
13336
13452
  async function completeClaudeCodeSession(options, state) {
13337
- const body = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state)) ?? state.lastCompletedTurnBody;
13338
- if (body === void 0) {
13453
+ const aggregateText = nonEmptyText(claudeAssistantAggregateText(state));
13454
+ const completion = state.resultText !== void 0 ? { body: state.resultText, bodySource: "result" } : aggregateText !== void 0 ? { body: aggregateText, bodySource: "assistant_aggregate" } : state.lastCompletedTurnBody !== void 0 ? {
13455
+ body: state.lastCompletedTurnBody,
13456
+ bodySource: "last_completed_turn"
13457
+ } : void 0;
13458
+ if (completion === void 0) {
13339
13459
  return await failClaudeCodeSession(
13340
13460
  options,
13341
13461
  state.sessionId,
@@ -13351,13 +13471,14 @@ async function completeClaudeCodeSession(options, state) {
13351
13471
  }
13352
13472
  const result = {
13353
13473
  sessionId: state.sessionId,
13354
- body,
13474
+ body: completion.body,
13355
13475
  usage: state.usage
13356
13476
  };
13357
13477
  await options.onTranscriptEvent?.({
13358
13478
  type: "session_completed",
13359
13479
  sessionId: result.sessionId,
13360
13480
  body: result.body,
13481
+ bodySource: completion.bodySource,
13361
13482
  usage: result.usage
13362
13483
  });
13363
13484
  return result;
@@ -18989,7 +19110,7 @@ var linzumiCliVersion, linzumiCliVersionText;
18989
19110
  var init_version = __esm({
18990
19111
  "src/version.ts"() {
18991
19112
  "use strict";
18992
- linzumiCliVersion = "0.0.89-beta";
19113
+ linzumiCliVersion = "0.0.90-beta";
18993
19114
  linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
18994
19115
  }
18995
19116
  });
@@ -27258,6 +27379,7 @@ async function startClaudeCodeProviderInstance(args) {
27258
27379
  args.log("claude_code.turn_completed", {
27259
27380
  linzumi_thread_id: threadId,
27260
27381
  claude_session_id: event.sessionId,
27382
+ body_source: event.bodySource ?? null,
27261
27383
  body_preview: claudeConsoleBodyPreview(event.body)
27262
27384
  });
27263
27385
  settleFirstTurn();
@@ -27659,6 +27781,7 @@ function claudeSessionStoreEntryPayload(args, event) {
27659
27781
  case "session_completed":
27660
27782
  return {
27661
27783
  body: event.body,
27784
+ bodySource: event.bodySource ?? null,
27662
27785
  usage: event.usage ?? null
27663
27786
  };
27664
27787
  case "turn_interrupted":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "0.0.89-beta",
3
+ "version": "0.0.90-beta",
4
4
  "description": "Linzumi CLI — 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": {