@dimi-agent/cli 0.6.0 → 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.
- package/dist/main.mjs +148 -85
- package/package.json +9 -9
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?.();
|
|
@@ -378352,6 +378367,7 @@ var init_tool_call = __esmMin((() => {
|
|
|
378352
378367
|
const wait = this.waitState;
|
|
378353
378368
|
if (wait === void 0 || wait.ended || wait.timedOut) return;
|
|
378354
378369
|
wait.ended = true;
|
|
378370
|
+
wait.endedElapsedSeconds = Math.min(wait.maxSeconds, Math.max(0, Math.floor((Date.now() - wait.startedAtMs) / 1e3)));
|
|
378355
378371
|
this.stopWaitTimer();
|
|
378356
378372
|
this.headerText.setText(this.buildHeader());
|
|
378357
378373
|
this.notifySnapshotChange();
|
|
@@ -378621,7 +378637,7 @@ var init_tool_call = __esmMin((() => {
|
|
|
378621
378637
|
timerText = `${max} (timeout)`;
|
|
378622
378638
|
} else if (wait.ended) {
|
|
378623
378639
|
verb = currentTheme.boldFg("success", "Waited");
|
|
378624
|
-
timerText = `${formatElapsed(elapsedSeconds)} / ${max}`;
|
|
378640
|
+
timerText = `${formatElapsed(wait.endedElapsedSeconds ?? elapsedSeconds)} / ${max}`;
|
|
378625
378641
|
} else {
|
|
378626
378642
|
verb = currentTheme.boldFg("primary", "Waiting");
|
|
378627
378643
|
timerText = `${formatElapsed(elapsedSeconds)} / ${max}`;
|
|
@@ -387215,6 +387231,82 @@ var init_terminal_notification = __esmMin((() => {
|
|
|
387215
387231
|
init_terminal();
|
|
387216
387232
|
}));
|
|
387217
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
|
|
387218
387310
|
//#region src/tui/controllers/streaming-ui.ts
|
|
387219
387311
|
var StreamingUIController;
|
|
387220
387312
|
var init_streaming_ui = __esmMin((() => {
|
|
@@ -387230,6 +387322,7 @@ var init_streaming_ui = __esmMin((() => {
|
|
|
387230
387322
|
init_event_payload();
|
|
387231
387323
|
init_terminal_notification();
|
|
387232
387324
|
init_transcript_id();
|
|
387325
|
+
init_transcript_window();
|
|
387233
387326
|
StreamingUIController = class {
|
|
387234
387327
|
host;
|
|
387235
387328
|
flushTimer;
|
|
@@ -387713,6 +387806,7 @@ var init_streaming_ui = __esmMin((() => {
|
|
|
387713
387806
|
state.transcriptContainer.addChild(tc);
|
|
387714
387807
|
state.ui.requestRender();
|
|
387715
387808
|
}
|
|
387809
|
+
this.host.foldTrailingToolCalls(TRANSCRIPT_KEEP_TRAILING_TOOL_CALLS);
|
|
387716
387810
|
if (toolCall.name === "ExitPlanMode" && typeof toolCall.args["plan"] !== "string") {
|
|
387717
387811
|
const session = this.host.requireSession();
|
|
387718
387812
|
(async () => {
|
|
@@ -390461,81 +390555,6 @@ var init_tmux_keyboard = __esmMin((() => {
|
|
|
390461
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.";
|
|
390462
390556
|
}));
|
|
390463
390557
|
//#endregion
|
|
390464
|
-
//#region src/tui/utils/transcript-window.ts
|
|
390465
|
-
/**
|
|
390466
|
-
* Read a non-negative integer env var, falling back to `fallback` when it is
|
|
390467
|
-
* unset, empty, negative, or not an integer. `0` is a valid value (call sites
|
|
390468
|
-
* treat it as "feature disabled").
|
|
390469
|
-
*/
|
|
390470
|
-
function readEnvInt(name, fallback) {
|
|
390471
|
-
const raw = process.env[name];
|
|
390472
|
-
if (raw === void 0 || raw.trim() === "") return fallback;
|
|
390473
|
-
const value = Number(raw);
|
|
390474
|
-
if (!Number.isInteger(value) || value < 0) return fallback;
|
|
390475
|
-
return value;
|
|
390476
|
-
}
|
|
390477
|
-
/**
|
|
390478
|
-
* Group consecutive entries into turns by `turnId`. Entries with the same
|
|
390479
|
-
* non-undefined `turnId` that are adjacent belong to the same turn.
|
|
390480
|
-
*
|
|
390481
|
-
* Entries with an undefined `turnId` are buffered and attached to the *next*
|
|
390482
|
-
* defined turn. This matters because a user message is appended (with
|
|
390483
|
-
* `turnId: undefined`) before its turn actually starts, so without this
|
|
390484
|
-
* buffering every user message would become its own single-entry turn at the
|
|
390485
|
-
* front and get trimmed first. Any undefined entries left at the tail (no
|
|
390486
|
-
* following turn) become their own turn.
|
|
390487
|
-
*/
|
|
390488
|
-
function groupTurns(entries) {
|
|
390489
|
-
const turns = [];
|
|
390490
|
-
let current;
|
|
390491
|
-
let pendingUndefined = [];
|
|
390492
|
-
for (const entry of entries) {
|
|
390493
|
-
const turnId = entry.turnId;
|
|
390494
|
-
if (turnId === void 0) {
|
|
390495
|
-
pendingUndefined.push(entry);
|
|
390496
|
-
continue;
|
|
390497
|
-
}
|
|
390498
|
-
if (current !== void 0 && current.turnId === turnId) current.entries.push(entry);
|
|
390499
|
-
else {
|
|
390500
|
-
current = {
|
|
390501
|
-
turnId,
|
|
390502
|
-
entries: [...pendingUndefined, entry]
|
|
390503
|
-
};
|
|
390504
|
-
pendingUndefined = [];
|
|
390505
|
-
turns.push(current);
|
|
390506
|
-
}
|
|
390507
|
-
}
|
|
390508
|
-
if (pendingUndefined.length > 0) turns.push({
|
|
390509
|
-
turnId: void 0,
|
|
390510
|
-
entries: pendingUndefined
|
|
390511
|
-
});
|
|
390512
|
-
return turns;
|
|
390513
|
-
}
|
|
390514
|
-
/**
|
|
390515
|
-
* Decide which entries to destroy so the remaining turns fit within
|
|
390516
|
-
* `maxTurns`. Returns an empty set when the turn count is within
|
|
390517
|
-
* `maxTurns + hysteresis`. Oldest turns are removed first; the most recent
|
|
390518
|
-
* turn is never removed (it is the active / just-finished turn).
|
|
390519
|
-
*/
|
|
390520
|
-
function turnsToTrim(turns, maxTurns, hysteresis) {
|
|
390521
|
-
const toRemove = /* @__PURE__ */ new Set();
|
|
390522
|
-
if (turns.length <= maxTurns + hysteresis) return toRemove;
|
|
390523
|
-
let remaining = turns.length;
|
|
390524
|
-
for (let i = 0; i < turns.length - 1 && remaining > maxTurns; i++) {
|
|
390525
|
-
const turn = turns[i];
|
|
390526
|
-
for (const entry of turn.entries) toRemove.add(entry);
|
|
390527
|
-
remaining--;
|
|
390528
|
-
}
|
|
390529
|
-
return toRemove;
|
|
390530
|
-
}
|
|
390531
|
-
var TRANSCRIPT_MAX_TURNS, TRANSCRIPT_EXPAND_TURNS, TRANSCRIPT_HYSTERESIS, TRANSCRIPT_KEEP_RECENT_STEPS;
|
|
390532
|
-
var init_transcript_window = __esmMin((() => {
|
|
390533
|
-
TRANSCRIPT_MAX_TURNS = readEnvInt("DIMI_CODE_TUI_MAX_TURNS", 15);
|
|
390534
|
-
TRANSCRIPT_EXPAND_TURNS = readEnvInt("DIMI_CODE_TUI_EXPAND_TURNS", 3);
|
|
390535
|
-
TRANSCRIPT_HYSTERESIS = readEnvInt("DIMI_CODE_TUI_HYSTERESIS", 5);
|
|
390536
|
-
TRANSCRIPT_KEEP_RECENT_STEPS = readEnvInt("DIMI_CODE_TUI_KEEP_RECENT_STEPS", 30);
|
|
390537
|
-
}));
|
|
390538
|
-
//#endregion
|
|
390539
390558
|
//#region src/tui/dimi-tui.ts
|
|
390540
390559
|
function loadingTipKind(mode) {
|
|
390541
390560
|
if (mode === "waiting" || mode === "tool") return "moon";
|
|
@@ -391894,6 +391913,7 @@ var init_dimi_tui = __esmMin((() => {
|
|
|
391894
391913
|
markTranscriptComponent(component, entry);
|
|
391895
391914
|
this.state.transcriptContainer.addChild(component);
|
|
391896
391915
|
}
|
|
391916
|
+
if (entry.kind === "tool_call") this.foldTrailingToolCalls(TRANSCRIPT_KEEP_TRAILING_TOOL_CALLS);
|
|
391897
391917
|
const trimmed = this.trimTranscriptWindow();
|
|
391898
391918
|
const merged = this.mergeCurrentTurnSteps();
|
|
391899
391919
|
if (component || trimmed || merged) this.state.ui.requestRender();
|
|
@@ -391998,6 +392018,21 @@ var init_dimi_tui = __esmMin((() => {
|
|
|
391998
392018
|
return this.foldCurrentTurnSteps(TRANSCRIPT_KEEP_RECENT_STEPS);
|
|
391999
392019
|
}
|
|
392000
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) {
|
|
392001
392036
|
const children = this.state.transcriptContainer.children;
|
|
392002
392037
|
let start = children.length;
|
|
392003
392038
|
const toolCalls = [];
|
|
@@ -392019,21 +392054,49 @@ var init_dimi_tui = __esmMin((() => {
|
|
|
392019
392054
|
const standaloneNames = new Set(["AllDone", "WaitFor"]);
|
|
392020
392055
|
const standaloneCalls = new Set(toolCalls.filter((call) => standaloneNames.has(call.toolCallView.name)));
|
|
392021
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;
|
|
392022
392060
|
const components = children.slice(start);
|
|
392023
392061
|
const standalone = [];
|
|
392024
392062
|
const sequenceComponents = [];
|
|
392063
|
+
const keptComponents = [];
|
|
392064
|
+
let remainingToFold = foldCount;
|
|
392065
|
+
let stoppedAtUnfinished = false;
|
|
392025
392066
|
for (const component of components) {
|
|
392026
|
-
if (
|
|
392027
|
-
|
|
392028
|
-
component.clear();
|
|
392067
|
+
if (stoppedAtUnfinished) {
|
|
392068
|
+
keptComponents.push(component);
|
|
392029
392069
|
continue;
|
|
392030
392070
|
}
|
|
392031
|
-
if (component instanceof ToolCallComponent && standaloneCalls.has(component))
|
|
392032
|
-
|
|
392033
|
-
|
|
392034
|
-
|
|
392035
|
-
|
|
392036
|
-
|
|
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);
|
|
392037
392100
|
this.state.transcriptContainer.invalidate();
|
|
392038
392101
|
}
|
|
392039
392102
|
foldCurrentTurnSteps(keepSteps) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dimi-agent/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "The Starting Point for Next-Gen Agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -60,24 +60,24 @@
|
|
|
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
63
|
"@dimi-agent/dimi-oauth": "^0.1.0",
|
|
65
64
|
"@dimi-agent/dimi-sdk": "^0.2.0",
|
|
66
|
-
"@dimi-agent/dimi-telemetry": "^0.1.0",
|
|
67
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",
|
|
68
68
|
"@dimi-agent/kap-server": "^0.1.0",
|
|
69
|
-
"@dimi-agent/
|
|
70
|
-
"@dimi-agent/
|
|
69
|
+
"@dimi-agent/pi-tui": "^0.1.0",
|
|
70
|
+
"@dimi-agent/remote": "^0.1.0"
|
|
71
71
|
},
|
|
72
72
|
"optionalDependencies": {
|
|
73
|
-
"@mariozechner/clipboard": "^0.3.9",
|
|
74
|
-
"node-pty": "^1.1.0",
|
|
75
73
|
"@dimi-agent/dimi-native-darwin-arm64": ">=0.5.3 <1",
|
|
76
74
|
"@dimi-agent/dimi-native-darwin-x64": ">=0.5.3 <1",
|
|
77
|
-
"@dimi-agent/dimi-native-linux-x64": ">=0.5.3 <1",
|
|
78
75
|
"@dimi-agent/dimi-native-linux-arm64": ">=0.5.3 <1",
|
|
76
|
+
"@dimi-agent/dimi-native-linux-x64": ">=0.5.3 <1",
|
|
77
|
+
"@dimi-agent/dimi-native-win32-arm64": ">=0.5.3 <1",
|
|
79
78
|
"@dimi-agent/dimi-native-win32-x64": ">=0.5.3 <1",
|
|
80
|
-
"@
|
|
79
|
+
"@mariozechner/clipboard": "^0.3.9",
|
|
80
|
+
"node-pty": "^1.1.0"
|
|
81
81
|
},
|
|
82
82
|
"engines": {
|
|
83
83
|
"node": ">=22.19.0"
|