@dimi-agent/cli 0.6.1 → 0.6.2

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 (2) hide show
  1. package/dist/main.mjs +146 -84
  2. package/package.json +4 -4
package/dist/main.mjs CHANGED
@@ -378194,6 +378194,21 @@ var init_tool_call = __esmMin((() => {
378194
378194
  get toolCallView() {
378195
378195
  return this.toolCall;
378196
378196
  }
378197
+ /**
378198
+ * Whether this call has reached a terminal state. Ordinary tools finish when
378199
+ * their result lands; agent and read cards derive their phase from events
378200
+ * (subagent lifecycle / read status), falling back to the result. Used by
378201
+ * transcript folding to avoid collapsing calls the user still needs to
378202
+ * watch (a running agent would otherwise disappear into the summary line).
378203
+ */
378204
+ isFinished() {
378205
+ if (this.toolCall.name === "Agent" || this.toolCall.name === "AgentSwarm") {
378206
+ const phase = this.getSubagentSnapshot().phase;
378207
+ return phase === "done" || phase === "failed" || phase === "backgrounded";
378208
+ }
378209
+ if (this.toolCall.name === "Read") return this.getReadSnapshot().phase !== "pending";
378210
+ return this.result !== void 0;
378211
+ }
378197
378212
  /** Notifies the listener when internal state changes, if a group is attached. */
378198
378213
  notifySnapshotChange() {
378199
378214
  this.onSnapshotChange?.();
@@ -387216,6 +387231,82 @@ var init_terminal_notification = __esmMin((() => {
387216
387231
  init_terminal();
387217
387232
  }));
387218
387233
  //#endregion
387234
+ //#region src/tui/utils/transcript-window.ts
387235
+ /**
387236
+ * Read a non-negative integer env var, falling back to `fallback` when it is
387237
+ * unset, empty, negative, or not an integer. `0` is a valid value (call sites
387238
+ * treat it as "feature disabled").
387239
+ */
387240
+ function readEnvInt(name, fallback) {
387241
+ const raw = process.env[name];
387242
+ if (raw === void 0 || raw.trim() === "") return fallback;
387243
+ const value = Number(raw);
387244
+ if (!Number.isInteger(value) || value < 0) return fallback;
387245
+ return value;
387246
+ }
387247
+ /**
387248
+ * Group consecutive entries into turns by `turnId`. Entries with the same
387249
+ * non-undefined `turnId` that are adjacent belong to the same turn.
387250
+ *
387251
+ * Entries with an undefined `turnId` are buffered and attached to the *next*
387252
+ * defined turn. This matters because a user message is appended (with
387253
+ * `turnId: undefined`) before its turn actually starts, so without this
387254
+ * buffering every user message would become its own single-entry turn at the
387255
+ * front and get trimmed first. Any undefined entries left at the tail (no
387256
+ * following turn) become their own turn.
387257
+ */
387258
+ function groupTurns(entries) {
387259
+ const turns = [];
387260
+ let current;
387261
+ let pendingUndefined = [];
387262
+ for (const entry of entries) {
387263
+ const turnId = entry.turnId;
387264
+ if (turnId === void 0) {
387265
+ pendingUndefined.push(entry);
387266
+ continue;
387267
+ }
387268
+ if (current !== void 0 && current.turnId === turnId) current.entries.push(entry);
387269
+ else {
387270
+ current = {
387271
+ turnId,
387272
+ entries: [...pendingUndefined, entry]
387273
+ };
387274
+ pendingUndefined = [];
387275
+ turns.push(current);
387276
+ }
387277
+ }
387278
+ if (pendingUndefined.length > 0) turns.push({
387279
+ turnId: void 0,
387280
+ entries: pendingUndefined
387281
+ });
387282
+ return turns;
387283
+ }
387284
+ /**
387285
+ * Decide which entries to destroy so the remaining turns fit within
387286
+ * `maxTurns`. Returns an empty set when the turn count is within
387287
+ * `maxTurns + hysteresis`. Oldest turns are removed first; the most recent
387288
+ * turn is never removed (it is the active / just-finished turn).
387289
+ */
387290
+ function turnsToTrim(turns, maxTurns, hysteresis) {
387291
+ const toRemove = /* @__PURE__ */ new Set();
387292
+ if (turns.length <= maxTurns + hysteresis) return toRemove;
387293
+ let remaining = turns.length;
387294
+ for (let i = 0; i < turns.length - 1 && remaining > maxTurns; i++) {
387295
+ const turn = turns[i];
387296
+ for (const entry of turn.entries) toRemove.add(entry);
387297
+ remaining--;
387298
+ }
387299
+ return toRemove;
387300
+ }
387301
+ var TRANSCRIPT_MAX_TURNS, TRANSCRIPT_EXPAND_TURNS, TRANSCRIPT_HYSTERESIS, TRANSCRIPT_KEEP_RECENT_STEPS, TRANSCRIPT_KEEP_TRAILING_TOOL_CALLS;
387302
+ var init_transcript_window = __esmMin((() => {
387303
+ TRANSCRIPT_MAX_TURNS = readEnvInt("DIMI_CODE_TUI_MAX_TURNS", 15);
387304
+ TRANSCRIPT_EXPAND_TURNS = readEnvInt("DIMI_CODE_TUI_EXPAND_TURNS", 3);
387305
+ TRANSCRIPT_HYSTERESIS = readEnvInt("DIMI_CODE_TUI_HYSTERESIS", 5);
387306
+ TRANSCRIPT_KEEP_RECENT_STEPS = readEnvInt("DIMI_CODE_TUI_KEEP_RECENT_STEPS", 30);
387307
+ TRANSCRIPT_KEEP_TRAILING_TOOL_CALLS = readEnvInt("DIMI_CODE_TUI_KEEP_TRAILING_TOOL_CALLS", 2);
387308
+ }));
387309
+ //#endregion
387219
387310
  //#region src/tui/controllers/streaming-ui.ts
387220
387311
  var StreamingUIController;
387221
387312
  var init_streaming_ui = __esmMin((() => {
@@ -387231,6 +387322,7 @@ var init_streaming_ui = __esmMin((() => {
387231
387322
  init_event_payload();
387232
387323
  init_terminal_notification();
387233
387324
  init_transcript_id();
387325
+ init_transcript_window();
387234
387326
  StreamingUIController = class {
387235
387327
  host;
387236
387328
  flushTimer;
@@ -387714,6 +387806,7 @@ var init_streaming_ui = __esmMin((() => {
387714
387806
  state.transcriptContainer.addChild(tc);
387715
387807
  state.ui.requestRender();
387716
387808
  }
387809
+ this.host.foldTrailingToolCalls(TRANSCRIPT_KEEP_TRAILING_TOOL_CALLS);
387717
387810
  if (toolCall.name === "ExitPlanMode" && typeof toolCall.args["plan"] !== "string") {
387718
387811
  const session = this.host.requireSession();
387719
387812
  (async () => {
@@ -390462,81 +390555,6 @@ var init_tmux_keyboard = __esmMin((() => {
390462
390555
  TMUX_EXTENDED_KEYS_FORMAT_XTERM_WARNING = "tmux extended-keys-format is xterm. Dimi works best with csi-u. Add `set -g extended-keys-format csi-u` to ~/.tmux.conf and restart tmux.";
390463
390556
  }));
390464
390557
  //#endregion
390465
- //#region src/tui/utils/transcript-window.ts
390466
- /**
390467
- * Read a non-negative integer env var, falling back to `fallback` when it is
390468
- * unset, empty, negative, or not an integer. `0` is a valid value (call sites
390469
- * treat it as "feature disabled").
390470
- */
390471
- function readEnvInt(name, fallback) {
390472
- const raw = process.env[name];
390473
- if (raw === void 0 || raw.trim() === "") return fallback;
390474
- const value = Number(raw);
390475
- if (!Number.isInteger(value) || value < 0) return fallback;
390476
- return value;
390477
- }
390478
- /**
390479
- * Group consecutive entries into turns by `turnId`. Entries with the same
390480
- * non-undefined `turnId` that are adjacent belong to the same turn.
390481
- *
390482
- * Entries with an undefined `turnId` are buffered and attached to the *next*
390483
- * defined turn. This matters because a user message is appended (with
390484
- * `turnId: undefined`) before its turn actually starts, so without this
390485
- * buffering every user message would become its own single-entry turn at the
390486
- * front and get trimmed first. Any undefined entries left at the tail (no
390487
- * following turn) become their own turn.
390488
- */
390489
- function groupTurns(entries) {
390490
- const turns = [];
390491
- let current;
390492
- let pendingUndefined = [];
390493
- for (const entry of entries) {
390494
- const turnId = entry.turnId;
390495
- if (turnId === void 0) {
390496
- pendingUndefined.push(entry);
390497
- continue;
390498
- }
390499
- if (current !== void 0 && current.turnId === turnId) current.entries.push(entry);
390500
- else {
390501
- current = {
390502
- turnId,
390503
- entries: [...pendingUndefined, entry]
390504
- };
390505
- pendingUndefined = [];
390506
- turns.push(current);
390507
- }
390508
- }
390509
- if (pendingUndefined.length > 0) turns.push({
390510
- turnId: void 0,
390511
- entries: pendingUndefined
390512
- });
390513
- return turns;
390514
- }
390515
- /**
390516
- * Decide which entries to destroy so the remaining turns fit within
390517
- * `maxTurns`. Returns an empty set when the turn count is within
390518
- * `maxTurns + hysteresis`. Oldest turns are removed first; the most recent
390519
- * turn is never removed (it is the active / just-finished turn).
390520
- */
390521
- function turnsToTrim(turns, maxTurns, hysteresis) {
390522
- const toRemove = /* @__PURE__ */ new Set();
390523
- if (turns.length <= maxTurns + hysteresis) return toRemove;
390524
- let remaining = turns.length;
390525
- for (let i = 0; i < turns.length - 1 && remaining > maxTurns; i++) {
390526
- const turn = turns[i];
390527
- for (const entry of turn.entries) toRemove.add(entry);
390528
- remaining--;
390529
- }
390530
- return toRemove;
390531
- }
390532
- var TRANSCRIPT_MAX_TURNS, TRANSCRIPT_EXPAND_TURNS, TRANSCRIPT_HYSTERESIS, TRANSCRIPT_KEEP_RECENT_STEPS;
390533
- var init_transcript_window = __esmMin((() => {
390534
- TRANSCRIPT_MAX_TURNS = readEnvInt("DIMI_CODE_TUI_MAX_TURNS", 15);
390535
- TRANSCRIPT_EXPAND_TURNS = readEnvInt("DIMI_CODE_TUI_EXPAND_TURNS", 3);
390536
- TRANSCRIPT_HYSTERESIS = readEnvInt("DIMI_CODE_TUI_HYSTERESIS", 5);
390537
- TRANSCRIPT_KEEP_RECENT_STEPS = readEnvInt("DIMI_CODE_TUI_KEEP_RECENT_STEPS", 30);
390538
- }));
390539
- //#endregion
390540
390558
  //#region src/tui/dimi-tui.ts
390541
390559
  function loadingTipKind(mode) {
390542
390560
  if (mode === "waiting" || mode === "tool") return "moon";
@@ -391895,6 +391913,7 @@ var init_dimi_tui = __esmMin((() => {
391895
391913
  markTranscriptComponent(component, entry);
391896
391914
  this.state.transcriptContainer.addChild(component);
391897
391915
  }
391916
+ if (entry.kind === "tool_call") this.foldTrailingToolCalls(TRANSCRIPT_KEEP_TRAILING_TOOL_CALLS);
391898
391917
  const trimmed = this.trimTranscriptWindow();
391899
391918
  const merged = this.mergeCurrentTurnSteps();
391900
391919
  if (component || trimmed || merged) this.state.ui.requestRender();
@@ -391999,6 +392018,21 @@ var init_dimi_tui = __esmMin((() => {
391999
392018
  return this.foldCurrentTurnSteps(TRANSCRIPT_KEEP_RECENT_STEPS);
392000
392019
  }
392001
392020
  collapseTrailingToolCalls() {
392021
+ this.foldTrailingToolCalls(0);
392022
+ }
392023
+ /**
392024
+ * Fold the trailing contiguous run of tool calls, keeping the most recent
392025
+ * `keepExpanded` calls expanded. `keepExpanded = 0` collapses the whole run
392026
+ * (used when visible content follows, e.g. an assistant message or turn
392027
+ * end); a positive cap folds progressively while the run is still growing
392028
+ * so older calls merge into the summary immediately instead of staying
392029
+ * expanded until the run ends.
392030
+ *
392031
+ * Only finished calls fold — a call that is still running (streaming args,
392032
+ * a live subagent, a pending read) stays visible because its progress is
392033
+ * live information the user is watching.
392034
+ */
392035
+ foldTrailingToolCalls(keepExpanded) {
392002
392036
  const children = this.state.transcriptContainer.children;
392003
392037
  let start = children.length;
392004
392038
  const toolCalls = [];
@@ -392020,21 +392054,49 @@ var init_dimi_tui = __esmMin((() => {
392020
392054
  const standaloneNames = new Set(["AllDone", "WaitFor"]);
392021
392055
  const standaloneCalls = new Set(toolCalls.filter((call) => standaloneNames.has(call.toolCallView.name)));
392022
392056
  const sequenceCalls = toolCalls.filter((call) => !standaloneCalls.has(call));
392057
+ if (sequenceCalls.length === 0) return;
392058
+ const foldCount = sequenceCalls.length - keepExpanded;
392059
+ if (foldCount <= 0) return;
392023
392060
  const components = children.slice(start);
392024
392061
  const standalone = [];
392025
392062
  const sequenceComponents = [];
392063
+ const keptComponents = [];
392064
+ let remainingToFold = foldCount;
392065
+ let stoppedAtUnfinished = false;
392026
392066
  for (const component of components) {
392027
- if (component instanceof ToolCallSequenceComponent) {
392028
- sequenceComponents.push(...component.children);
392029
- component.clear();
392067
+ if (stoppedAtUnfinished) {
392068
+ keptComponents.push(component);
392030
392069
  continue;
392031
392070
  }
392032
- if (component instanceof ToolCallComponent && standaloneCalls.has(component)) standalone.push(component);
392033
- else sequenceComponents.push(component);
392034
- }
392035
- if (sequenceCalls.length === 0) return;
392036
- const sequence = new ToolCallSequenceComponent(sequenceComponents, sequenceCalls, this.state.toolDisplayMode);
392037
- children.splice(start, components.length, sequence, ...standalone);
392071
+ if (component instanceof ToolCallComponent && standaloneCalls.has(component)) {
392072
+ standalone.push(component);
392073
+ continue;
392074
+ }
392075
+ const calls = toolCallsIn(component);
392076
+ const callCount = calls?.filter((call) => !standaloneCalls.has(call)).length ?? 0;
392077
+ const hasUnfinished = calls?.some((call) => !call.isFinished()) ?? false;
392078
+ if (remainingToFold > 0 && hasUnfinished) {
392079
+ keptComponents.push(component);
392080
+ stoppedAtUnfinished = true;
392081
+ continue;
392082
+ }
392083
+ if (remainingToFold > 0) {
392084
+ if (component instanceof ToolCallSequenceComponent) {
392085
+ sequenceComponents.push(...component.children);
392086
+ component.clear();
392087
+ } else sequenceComponents.push(component);
392088
+ remainingToFold -= callCount;
392089
+ } else keptComponents.push(component);
392090
+ }
392091
+ if (sequenceComponents.length === 0) return;
392092
+ const foldedCalls = [];
392093
+ for (const component of sequenceComponents) {
392094
+ const componentCalls = toolCallsIn(component);
392095
+ if (componentCalls !== void 0) foldedCalls.push(...componentCalls.filter((call) => !standaloneCalls.has(call)));
392096
+ }
392097
+ if (foldedCalls.length === 0) return;
392098
+ const sequence = new ToolCallSequenceComponent(sequenceComponents, foldedCalls, this.state.toolDisplayMode);
392099
+ children.splice(start, components.length, sequence, ...standalone, ...keptComponents);
392038
392100
  this.state.transcriptContainer.invalidate();
392039
392101
  }
392040
392102
  foldCurrentTurnSteps(keepSteps) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dimi-agent/cli",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "The Starting Point for Next-Gen Agents",
5
5
  "keywords": [
6
6
  "agent",
@@ -60,12 +60,12 @@
60
60
  "tsx": "^4.21.0",
61
61
  "yazl": "^3.3.1",
62
62
  "zod": "^4.3.6",
63
- "@dimi-agent/agent-core-v2": "^0.1.0",
64
- "@dimi-agent/dimi-telemetry": "^0.1.0",
63
+ "@dimi-agent/dimi-oauth": "^0.1.0",
65
64
  "@dimi-agent/dimi-sdk": "^0.2.0",
66
65
  "@dimi-agent/dimi-web": "^0.1.0",
66
+ "@dimi-agent/agent-core-v2": "^0.1.0",
67
+ "@dimi-agent/dimi-telemetry": "^0.1.0",
67
68
  "@dimi-agent/kap-server": "^0.1.0",
68
- "@dimi-agent/dimi-oauth": "^0.1.0",
69
69
  "@dimi-agent/pi-tui": "^0.1.0",
70
70
  "@dimi-agent/remote": "^0.1.0"
71
71
  },