@stigmer/ink 3.1.2 → 3.1.3
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/app/SessionView.d.ts.map +1 -1
- package/app/SessionView.js +2 -1
- package/app/SessionView.js.map +1 -1
- package/components/FileChangeProgressBar.d.ts +46 -0
- package/components/FileChangeProgressBar.d.ts.map +1 -0
- package/components/FileChangeProgressBar.js +55 -0
- package/components/FileChangeProgressBar.js.map +1 -0
- package/file-review.d.ts +10 -3
- package/file-review.d.ts.map +1 -1
- package/file-review.js +25 -6
- package/file-review.js.map +1 -1
- package/index.d.ts +2 -1
- package/index.d.ts.map +1 -1
- package/index.js +2 -1
- package/index.js.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/file-change-progress.test.tsx +295 -0
- package/src/app/SessionView.tsx +12 -0
- package/src/components/FileChangeProgressBar.tsx +122 -0
- package/src/file-review.ts +32 -6
- package/src/index.ts +5 -0
package/app/SessionView.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionView.d.ts","sourceRoot":"","sources":["../../src/app/SessionView.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SessionView.d.ts","sourceRoot":"","sources":["../../src/app/SessionView.tsx"],"names":[],"mappings":"AAYA,2DAA2D;AAC3D,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,MAAM,CAAC;AAE/C,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;;;;;;OASG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,eAAe,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CAyLrE"}
|
package/app/SessionView.js
CHANGED
|
@@ -8,6 +8,7 @@ import { TodoList } from "../components/TodoList.js";
|
|
|
8
8
|
import { FollowUpInput } from "../components/FollowUpInput.js";
|
|
9
9
|
import { UsageWidget } from "../components/UsageWidget.js";
|
|
10
10
|
import { ExecutionProgress } from "../components/ExecutionProgress.js";
|
|
11
|
+
import { FileChangeProgressBar } from "../components/FileChangeProgressBar.js";
|
|
11
12
|
import { FileReviewPrompt } from "../components/FileReviewPrompt.js";
|
|
12
13
|
/**
|
|
13
14
|
* Full-featured session conversation view for the terminal.
|
|
@@ -67,7 +68,7 @@ export function SessionView({ sessionId, org, mode }) {
|
|
|
67
68
|
// for review (it lives on FileChangeSet.status), so the phase would
|
|
68
69
|
// otherwise read as an active "Running" spinner while the agent is
|
|
69
70
|
// idle awaiting the reviewer — the FileReviewPrompt is the honest cue.
|
|
70
|
-
_jsx(ExecutionProgress, { phase: conv.activePhase })), _jsx(MessageThread, { executions: conv.completedExecutions, activeStreamExecution: conv.activeStreamExecution, pendingUserMessage: conv.pendingUserMessage, onApprovalSubmit: conv.submitApproval, submittingApprovalIds: conv.submittingApprovalIds, expandToolCalls: expandTools, showFileReviewRecords: true }), activeTodos && Object.keys(activeTodos).length > 0 && (_jsx(Box, { marginTop: 1, paddingLeft: 1, children: _jsx(TodoList, { todos: activeTodos }) })), conv.approvalError && (_jsx(Box, { paddingLeft: 1, children: _jsxs(Text, { color: "red", children: ["Approval error: ", conv.approvalError.message] }) })), conv.sendError && (_jsx(Box, { paddingLeft: 1, children: _jsxs(Text, { color: "red", children: ["Send error: ", conv.sendError.message] }) })), _jsx(UsageWidget, { executions: allExecutions }), conv.fileChangeSets.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsx(FileReviewPrompt, { changeSet: conv.fileChangeSets[0], onSubmit: conv.submitFileDecision, submittingDecisionKeys: conv.submittingFileDecisionKeys, decisionErrors: conv.fileDecisionErrors,
|
|
71
|
+
_jsx(ExecutionProgress, { phase: conv.activePhase })), _jsx(MessageThread, { executions: conv.completedExecutions, activeStreamExecution: conv.activeStreamExecution, pendingUserMessage: conv.pendingUserMessage, onApprovalSubmit: conv.submitApproval, submittingApprovalIds: conv.submittingApprovalIds, expandToolCalls: expandTools, showFileReviewRecords: true }), activeTodos && Object.keys(activeTodos).length > 0 && (_jsx(Box, { marginTop: 1, paddingLeft: 1, children: _jsx(TodoList, { todos: activeTodos }) })), conv.approvalError && (_jsx(Box, { paddingLeft: 1, children: _jsxs(Text, { color: "red", children: ["Approval error: ", conv.approvalError.message] }) })), conv.sendError && (_jsx(Box, { paddingLeft: 1, children: _jsxs(Text, { color: "red", children: ["Send error: ", conv.sendError.message] }) })), _jsx(UsageWidget, { executions: allExecutions }), _jsx(FileChangeProgressBar, { progress: conv.fileChangeProgress, expanded: expandTools }), conv.fileChangeSets.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsx(FileReviewPrompt, { changeSet: conv.fileChangeSets[0], onSubmit: conv.submitFileDecision, submittingDecisionKeys: conv.submittingFileDecisionKeys, decisionErrors: conv.fileDecisionErrors,
|
|
71
72
|
// Single active decision surface: yield to a pending tool approval.
|
|
72
73
|
isActive: conv.pendingApprovals.length === 0 }), conv.fileChangeSets.length > 1 && (_jsx(Box, { paddingLeft: 2, children: _jsxs(Text, { dimColor: true, children: [conv.fileChangeSets.length - 1, " more awaiting review"] }) }))] })), conv.fileReviewError && (_jsx(Box, { paddingLeft: 1, children: _jsxs(Text, { color: "red", children: ["File review error: ", conv.fileReviewError.message] }) })), conv.canSendFollowUp && (_jsx(Box, { paddingLeft: 1, children: _jsx(Text, { color: activeMode === "plan" ? "yellow" : "cyan", dimColor: true, children: activeMode === "plan"
|
|
73
74
|
? "Plan mode — read-only analysis, no file mutations"
|
package/app/SessionView.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionView.js","sourceRoot":"","sources":["../../src/app/SessionView.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SessionView.js","sourceRoot":"","sources":["../../src/app/SessionView.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { FileChangeProgress } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
|
|
2
|
+
/** Props for {@link FileChangeProgressBar}. */
|
|
3
|
+
export interface FileChangeProgressBarProps {
|
|
4
|
+
/**
|
|
5
|
+
* The transient mid-run progress snapshot for the active turn (DD-32). Feed
|
|
6
|
+
* this from `useSessionConversation().fileChangeProgress`. Renders nothing when
|
|
7
|
+
* undefined or when no files have changed yet — the server clears it once the
|
|
8
|
+
* turn's change set leaves CAPTURING, so the strip disappears exactly when the
|
|
9
|
+
* decision surface (`FileReviewPrompt`) takes over.
|
|
10
|
+
*/
|
|
11
|
+
readonly progress: FileChangeProgress | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Whether to reveal the per-file list. The compact one-line summary always
|
|
14
|
+
* shows; the list is progressive disclosure. `SessionView` binds this to its
|
|
15
|
+
* existing Ctrl+O "expand" toggle so no new keybinding is introduced. Defaults
|
|
16
|
+
* to `false`.
|
|
17
|
+
*/
|
|
18
|
+
readonly expanded?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The terminal analogue of the web's non-interactive "N files changing…" strip
|
|
22
|
+
* (`@stigmer/react` `FileChangeProgressBar`), for a turn that is still running.
|
|
23
|
+
*
|
|
24
|
+
* WHY IT EXISTS. The transcript streams per-edit tool rows, but a change made by
|
|
25
|
+
* a shell command (a `sed`, a build step) has no tool row, and there is no
|
|
26
|
+
* running net-of-many-edits rollup until the turn ends. This strip fills that
|
|
27
|
+
* gap: a compact, non-interactive count of the workspace delta accumulating
|
|
28
|
+
* during the turn, sitting where the `FileReviewPrompt` will later appear. The
|
|
29
|
+
* two are mutually exclusive per turn (progress shows while CAPTURING; the prompt
|
|
30
|
+
* once AWAITING_REVIEW), so the strip hands off cleanly to the prompt.
|
|
31
|
+
*
|
|
32
|
+
* NEVER A DECISION SURFACE. Progress is non-authoritative and carries no file
|
|
33
|
+
* bodies — it is never reviewable or decidable, and it owns no keyboard input.
|
|
34
|
+
* The reviewed diff is the turn-boundary candidate (`FileReviewPrompt`). A
|
|
35
|
+
* secret-like path is surfaced by name with its counts withheld (zeroed), so the
|
|
36
|
+
* `+N −M` stat renders nothing for it. The quiet/dim register (no border)
|
|
37
|
+
* distinguishes it from the loud, bordered decision prompt.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* const conv = useSessionConversation(sessionId, org);
|
|
42
|
+
* <FileChangeProgressBar progress={conv.fileChangeProgress} expanded={expandTools} />
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function FileChangeProgressBar({ progress, expanded, }: FileChangeProgressBarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
46
|
+
//# sourceMappingURL=FileChangeProgressBar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileChangeProgressBar.d.ts","sourceRoot":"","sources":["../../src/components/FileChangeProgressBar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oEAAoE,CAAC;AAG7G,+CAA+C;AAC/C,MAAM,WAAW,0BAA0B;IACzC;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAClD;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EACR,QAAgB,GACjB,EAAE,0BAA0B,kDA0C5B"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { kindLetter, progressEntryDisplayPath } from "../file-review.js";
|
|
4
|
+
/**
|
|
5
|
+
* The terminal analogue of the web's non-interactive "N files changing…" strip
|
|
6
|
+
* (`@stigmer/react` `FileChangeProgressBar`), for a turn that is still running.
|
|
7
|
+
*
|
|
8
|
+
* WHY IT EXISTS. The transcript streams per-edit tool rows, but a change made by
|
|
9
|
+
* a shell command (a `sed`, a build step) has no tool row, and there is no
|
|
10
|
+
* running net-of-many-edits rollup until the turn ends. This strip fills that
|
|
11
|
+
* gap: a compact, non-interactive count of the workspace delta accumulating
|
|
12
|
+
* during the turn, sitting where the `FileReviewPrompt` will later appear. The
|
|
13
|
+
* two are mutually exclusive per turn (progress shows while CAPTURING; the prompt
|
|
14
|
+
* once AWAITING_REVIEW), so the strip hands off cleanly to the prompt.
|
|
15
|
+
*
|
|
16
|
+
* NEVER A DECISION SURFACE. Progress is non-authoritative and carries no file
|
|
17
|
+
* bodies — it is never reviewable or decidable, and it owns no keyboard input.
|
|
18
|
+
* The reviewed diff is the turn-boundary candidate (`FileReviewPrompt`). A
|
|
19
|
+
* secret-like path is surfaced by name with its counts withheld (zeroed), so the
|
|
20
|
+
* `+N −M` stat renders nothing for it. The quiet/dim register (no border)
|
|
21
|
+
* distinguishes it from the loud, bordered decision prompt.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* const conv = useSessionConversation(sessionId, org);
|
|
26
|
+
* <FileChangeProgressBar progress={conv.fileChangeProgress} expanded={expandTools} />
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function FileChangeProgressBar({ progress, expanded = false, }) {
|
|
30
|
+
if (!progress || progress.filesChanged === 0)
|
|
31
|
+
return null;
|
|
32
|
+
const { filesChanged, linesAdded, linesRemoved, entries } = progress;
|
|
33
|
+
const hiddenCount = filesChanged - entries.length;
|
|
34
|
+
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: "\u270E" }), _jsxs(Text, { dimColor: true, children: [filesChanged, " file", filesChanged === 1 ? "" : "s", " changing\u2026"] }), _jsx(LineStats, { linesAdded: linesAdded, linesRemoved: linesRemoved })] }), expanded && (_jsxs(Box, { flexDirection: "column", paddingLeft: 2, children: [entries.map((entry, idx) => {
|
|
35
|
+
const path = progressEntryDisplayPath(entry);
|
|
36
|
+
return (_jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: kindLetter(entry.kind) }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: path }), _jsx(LineStats, { linesAdded: entry.linesAdded, linesRemoved: entry.linesRemoved })] }, `${path}-${idx}`));
|
|
37
|
+
}), hiddenCount > 0 && (_jsx(Box, { children: _jsxs(Text, { dimColor: true, children: ["\u2026 and ", hiddenCount, " more"] }) }))] }))] }));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The `+N −M` stat for one file (or the whole turn), in the diff colour
|
|
41
|
+
* vocabulary. Renders nothing when both counts are zero — the honest signal that
|
|
42
|
+
* no count exists (binary or secret-withheld changes) — rather than a misleading
|
|
43
|
+
* `+0 -0`, matching the web `FileLineStats` contract.
|
|
44
|
+
*
|
|
45
|
+
* Kept module-local: this is the only consumer today. When `FileReviewPrompt`
|
|
46
|
+
* and `FileReviewRecord` gain `+N −M` (the deferred "CLI +N −M parity"
|
|
47
|
+
* follow-up), lift this into a shared ink atom (the analogue of `sdk/react`'s
|
|
48
|
+
* `FileReviewAtoms`) so the three surfaces cannot drift — do not copy it.
|
|
49
|
+
*/
|
|
50
|
+
function LineStats({ linesAdded, linesRemoved, }) {
|
|
51
|
+
if (linesAdded === 0 && linesRemoved === 0)
|
|
52
|
+
return null;
|
|
53
|
+
return (_jsxs(Text, { children: [_jsxs(Text, { color: "green", children: ["+", linesAdded] }), _jsxs(Text, { color: "red", children: [" -", linesRemoved] })] }));
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=FileChangeProgressBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileChangeProgressBar.js","sourceRoot":"","sources":["../../src/components/FileChangeProgressBar.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAqBzE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,qBAAqB,CAAC,EACpC,QAAQ,EACR,QAAQ,GAAG,KAAK,GACW;IAC3B,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,YAAY,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1D,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC;IACrE,MAAM,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAElD,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACxC,MAAC,GAAG,IAAC,GAAG,EAAE,CAAC,aACT,KAAC,IAAI,IAAC,QAAQ,6BAAS,EACvB,MAAC,IAAI,IAAC,QAAQ,mBACX,YAAY,WAAO,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,uBAC5C,EACP,KAAC,SAAS,IAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,GAAI,IAC7D,EAEL,QAAQ,IAAI,CACX,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACvC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;wBAC1B,MAAM,IAAI,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;wBAC7C,OAAO,CACL,MAAC,GAAG,IAAwB,GAAG,EAAE,CAAC,aAChC,KAAC,IAAI,IAAC,QAAQ,kBAAE,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,GAAQ,EAC9C,KAAC,IAAI,IAAC,QAAQ,QAAC,IAAI,EAAC,cAAc,YAC/B,IAAI,GACA,EACP,KAAC,SAAS,IACR,UAAU,EAAE,KAAK,CAAC,UAAU,EAC5B,YAAY,EAAE,KAAK,CAAC,YAAY,GAChC,KARM,GAAG,IAAI,IAAI,GAAG,EAAE,CASpB,CACP,CAAC;oBACJ,CAAC,CAAC,EACD,WAAW,GAAG,CAAC,IAAI,CAClB,KAAC,GAAG,cACF,MAAC,IAAI,IAAC,QAAQ,kCAAQ,WAAW,aAAa,GAC1C,CACP,IACG,CACP,IACG,CACP,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,SAAS,CAAC,EACjB,UAAU,EACV,YAAY,GAIb;IACC,IAAI,UAAU,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,OAAO,CACL,MAAC,IAAI,eACH,MAAC,IAAI,IAAC,KAAK,EAAC,OAAO,kBAAG,UAAU,IAAQ,EACxC,MAAC,IAAI,IAAC,KAAK,EAAC,KAAK,mBAAI,YAAY,IAAQ,IACpC,CACR,CAAC;AACJ,CAAC"}
|
package/file-review.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CapturedFileChange, FileChangeSet } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
|
|
1
|
+
import type { CapturedFileChange, FileChangeProgressEntry, FileChangeSet } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
|
|
2
2
|
import { FileChangeKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
3
3
|
/**
|
|
4
4
|
* Single-letter badge for a file change's kind, matching the web review card:
|
|
@@ -8,10 +8,17 @@ import { FileChangeKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecutio
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function kindLetter(kind: FileChangeKind): string;
|
|
10
10
|
/**
|
|
11
|
-
* The path to show for a change: the post-edit path, or the pre-edit
|
|
12
|
-
* deletion. A rename shows `before → after` so both sides are visible.
|
|
11
|
+
* The path to show for a reviewable change: the post-edit path, or the pre-edit
|
|
12
|
+
* path for a deletion. A rename shows `before → after` so both sides are visible.
|
|
13
13
|
*/
|
|
14
14
|
export declare function changeDisplayPath(change: CapturedFileChange): string;
|
|
15
|
+
/**
|
|
16
|
+
* The path to show for a mid-run progress entry (DD-32), using the same
|
|
17
|
+
* rename-aware rule as {@link changeDisplayPath}. The slim entry carries no
|
|
18
|
+
* bodies or digests, only the same before/after/kind triple, so the terminal
|
|
19
|
+
* renders its path identically to the reviewable surfaces.
|
|
20
|
+
*/
|
|
21
|
+
export declare function progressEntryDisplayPath(entry: FileChangeProgressEntry): string;
|
|
15
22
|
/**
|
|
16
23
|
* The honest, one-line reason a change cannot be kept as-is, or `null` when it
|
|
17
24
|
* is fully reviewable. Mirrors the web card's per-file block-reason copy so the
|
package/file-review.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-review.d.ts","sourceRoot":"","sources":["../src/file-review.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,aAAa,EACd,MAAM,oEAAoE,CAAC;AAC5E,OAAO,EACL,cAAc,EAEf,MAAM,8DAA8D,CAAC;AAGtE;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAWvD;
|
|
1
|
+
{"version":3,"file":"file-review.d.ts","sourceRoot":"","sources":["../src/file-review.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACd,MAAM,oEAAoE,CAAC;AAC5E,OAAO,EACL,cAAc,EAEf,MAAM,8DAA8D,CAAC;AAGtE;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAWvD;AAoBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,uBAAuB,GAAG,MAAM,CAE/E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAiBzE;AAED,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,aAAa,CAc/D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CASzD"}
|
package/file-review.js
CHANGED
|
@@ -19,14 +19,33 @@ export function kindLetter(kind) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* The path
|
|
23
|
-
*
|
|
22
|
+
* The one rename-aware path-display rule for the terminal, over the raw
|
|
23
|
+
* before/after/kind triple shared by every file-change shape (reviewable
|
|
24
|
+
* `CapturedFileChange` and slim `FileChangeProgressEntry` alike). Kept private
|
|
25
|
+
* and fed by the typed adapters below so the two surfaces can never grow
|
|
26
|
+
* divergent rename formatting.
|
|
24
27
|
*/
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
return `${
|
|
28
|
+
function displayChangePath(pathBefore, pathAfter, kind) {
|
|
29
|
+
if (kind === FileChangeKind.RENAME && pathBefore && pathAfter) {
|
|
30
|
+
return `${pathBefore} → ${pathAfter}`;
|
|
28
31
|
}
|
|
29
|
-
return
|
|
32
|
+
return pathAfter || pathBefore;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The path to show for a reviewable change: the post-edit path, or the pre-edit
|
|
36
|
+
* path for a deletion. A rename shows `before → after` so both sides are visible.
|
|
37
|
+
*/
|
|
38
|
+
export function changeDisplayPath(change) {
|
|
39
|
+
return displayChangePath(change.pathBefore, change.pathAfter, change.kind);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The path to show for a mid-run progress entry (DD-32), using the same
|
|
43
|
+
* rename-aware rule as {@link changeDisplayPath}. The slim entry carries no
|
|
44
|
+
* bodies or digests, only the same before/after/kind triple, so the terminal
|
|
45
|
+
* renders its path identically to the reviewable surfaces.
|
|
46
|
+
*/
|
|
47
|
+
export function progressEntryDisplayPath(entry) {
|
|
48
|
+
return displayChangePath(entry.pathBefore, entry.pathAfter, entry.kind);
|
|
30
49
|
}
|
|
31
50
|
/**
|
|
32
51
|
* The honest, one-line reason a change cannot be kept as-is, or `null` when it
|
package/file-review.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-review.js","sourceRoot":"","sources":["../src/file-review.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"file-review.js","sourceRoot":"","sources":["../src/file-review.ts"],"names":[],"mappings":"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"}
|
package/index.d.ts
CHANGED
|
@@ -10,7 +10,8 @@ export { TodoList, type TodoListProps } from "./components/TodoList.js";
|
|
|
10
10
|
export { ApprovalPrompt, type ApprovalPromptProps } from "./components/ApprovalPrompt.js";
|
|
11
11
|
export { FileReviewPrompt, type FileReviewPromptProps } from "./components/FileReviewPrompt.js";
|
|
12
12
|
export { FileReviewRecord, type FileReviewRecordProps } from "./components/FileReviewRecord.js";
|
|
13
|
-
export {
|
|
13
|
+
export { FileChangeProgressBar, type FileChangeProgressBarProps, } from "./components/FileChangeProgressBar.js";
|
|
14
|
+
export { kindLetter, changeDisplayPath, progressEntryDisplayPath, blockReasonNote, settledCounts, settledSummary, type SettledCounts, } from "./file-review.js";
|
|
14
15
|
export { ExecutionProgress, type ExecutionProgressProps } from "./components/ExecutionProgress.js";
|
|
15
16
|
export { FollowUpInput, type FollowUpInputProps } from "./components/FollowUpInput.js";
|
|
16
17
|
export { UsageWidget, type UsageWidgetProps } from "./components/UsageWidget.js";
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAGjF,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,gBAAgB,GACtB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAGjF,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,gBAAgB,GACtB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAChG,OAAO,EACL,qBAAqB,EACrB,KAAK,0BAA0B,GAChC,MAAM,uCAAuC,CAAC;AAG/C,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,wBAAwB,EACxB,eAAe,EACf,aAAa,EACb,cAAc,EACd,KAAK,aAAa,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AACnG,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGpF,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,KAAK,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC3G,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGvF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAChG,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC"}
|
package/index.js
CHANGED
|
@@ -14,8 +14,9 @@ export { TodoList } from "./components/TodoList.js";
|
|
|
14
14
|
export { ApprovalPrompt } from "./components/ApprovalPrompt.js";
|
|
15
15
|
export { FileReviewPrompt } from "./components/FileReviewPrompt.js";
|
|
16
16
|
export { FileReviewRecord } from "./components/FileReviewRecord.js";
|
|
17
|
+
export { FileChangeProgressBar, } from "./components/FileChangeProgressBar.js";
|
|
17
18
|
// File-review pure helpers (kind letters, paths, block reasons, settled counts)
|
|
18
|
-
export { kindLetter, changeDisplayPath, blockReasonNote, settledCounts, settledSummary, } from "./file-review.js";
|
|
19
|
+
export { kindLetter, changeDisplayPath, progressEntryDisplayPath, blockReasonNote, settledCounts, settledSummary, } from "./file-review.js";
|
|
19
20
|
export { ExecutionProgress } from "./components/ExecutionProgress.js";
|
|
20
21
|
export { FollowUpInput } from "./components/FollowUpInput.js";
|
|
21
22
|
export { UsageWidget } from "./components/UsageWidget.js";
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,OAAO,EAAE,kBAAkB,EAAgC,MAAM,eAAe,CAAC;AAEjF,iDAAiD;AACjD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,GAEpB,MAAM,mBAAmB,CAAC;AAE3B,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,aAAa;AACb,OAAO,EAAE,YAAY,EAA0B,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,YAAY,EAA0B,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,cAAc,EAA4B,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAA8B,MAAM,kCAAkC,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAA8B,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,OAAO,EAAE,kBAAkB,EAAgC,MAAM,eAAe,CAAC;AAEjF,iDAAiD;AACjD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,GAEpB,MAAM,mBAAmB,CAAC;AAE3B,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,aAAa;AACb,OAAO,EAAE,YAAY,EAA0B,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,YAAY,EAA0B,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,cAAc,EAA4B,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAA8B,MAAM,kCAAkC,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAA8B,MAAM,kCAAkC,CAAC;AAChG,OAAO,EACL,qBAAqB,GAEtB,MAAM,uCAAuC,CAAC;AAE/C,gFAAgF;AAChF,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,wBAAwB,EACxB,eAAe,EACf,aAAa,EACb,cAAc,GAEf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAA+B,MAAM,mCAAmC,CAAC;AACnG,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,WAAW,EAAyB,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,YAAY,EAA0B,MAAM,8BAA8B,CAAC;AAEpF,0CAA0C;AAC1C,OAAO,EAAE,cAAc,EAA6C,MAAM,gCAAgC,CAAC;AAC3G,OAAO,EAAE,WAAW,EAAyB,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,aAAa,EAA2B,MAAM,+BAA+B,CAAC;AAEvF,iBAAiB;AACjB,OAAO,EAAE,WAAW,EAA+C,MAAM,sBAAsB,CAAC;AAChG,OAAO,EAAE,UAAU,EAAwB,MAAM,qBAAqB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/ink",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"description": "Ink (React for terminals) components for rendering Stigmer agent sessions in the terminal",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@connectrpc/connect-node": "^2.1.1",
|
|
38
|
-
"@stigmer/react": "3.1.
|
|
38
|
+
"@stigmer/react": "3.1.3",
|
|
39
39
|
"ink-spinner": "^5.0.0",
|
|
40
40
|
"ink-text-input": "^6.0.0",
|
|
41
41
|
"marked": "^15.0.7",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@bufbuild/protobuf": "^2.0.0",
|
|
46
|
-
"@stigmer/protos": "3.1.
|
|
47
|
-
"@stigmer/sdk": "3.1.
|
|
46
|
+
"@stigmer/protos": "3.1.3",
|
|
47
|
+
"@stigmer/sdk": "3.1.3",
|
|
48
48
|
"ink": "^7.0.0",
|
|
49
49
|
"react": ">=19.0.0"
|
|
50
50
|
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
import { render } from "ink-testing-library";
|
|
4
|
+
import { create } from "@bufbuild/protobuf";
|
|
5
|
+
import {
|
|
6
|
+
FileChangeProgressSchema,
|
|
7
|
+
FileChangeProgressEntrySchema,
|
|
8
|
+
CapturedFileChangeSchema,
|
|
9
|
+
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
|
|
10
|
+
import type {
|
|
11
|
+
FileChangeProgress,
|
|
12
|
+
FileChangeProgressEntry,
|
|
13
|
+
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
|
|
14
|
+
import { FileChangeKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
15
|
+
import { FileChangeProgressBar } from "../components/FileChangeProgressBar.js";
|
|
16
|
+
import { changeDisplayPath, progressEntryDisplayPath } from "../file-review.js";
|
|
17
|
+
|
|
18
|
+
// --- fixtures -------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
interface EntryOpts {
|
|
21
|
+
readonly pathBefore?: string;
|
|
22
|
+
readonly pathAfter?: string;
|
|
23
|
+
readonly kind?: FileChangeKind;
|
|
24
|
+
readonly linesAdded?: number;
|
|
25
|
+
readonly linesRemoved?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function makeEntry(opts: EntryOpts): FileChangeProgressEntry {
|
|
29
|
+
return create(FileChangeProgressEntrySchema, {
|
|
30
|
+
pathBefore: opts.pathBefore ?? "",
|
|
31
|
+
pathAfter: opts.pathAfter ?? "",
|
|
32
|
+
kind: opts.kind ?? FileChangeKind.MODIFY,
|
|
33
|
+
linesAdded: opts.linesAdded ?? 0,
|
|
34
|
+
linesRemoved: opts.linesRemoved ?? 0,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface ProgressOpts {
|
|
39
|
+
readonly filesChanged?: number;
|
|
40
|
+
readonly linesAdded?: number;
|
|
41
|
+
readonly linesRemoved?: number;
|
|
42
|
+
readonly entries?: FileChangeProgressEntry[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function makeProgress(opts: ProgressOpts): FileChangeProgress {
|
|
46
|
+
const entries = opts.entries ?? [];
|
|
47
|
+
return create(FileChangeProgressSchema, {
|
|
48
|
+
changeSetId: "cs-1",
|
|
49
|
+
filesChanged: opts.filesChanged ?? entries.length,
|
|
50
|
+
linesAdded: opts.linesAdded ?? 0,
|
|
51
|
+
linesRemoved: opts.linesRemoved ?? 0,
|
|
52
|
+
entries,
|
|
53
|
+
capturedAt: "2026-07-05T00:00:00Z",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// --- FileChangeProgressBar: visibility ------------------------------------
|
|
58
|
+
|
|
59
|
+
describe("FileChangeProgressBar — visibility", () => {
|
|
60
|
+
it("renders nothing when progress is undefined", () => {
|
|
61
|
+
const { lastFrame } = render(<FileChangeProgressBar progress={undefined} />);
|
|
62
|
+
expect((lastFrame() ?? "").trim()).toBe("");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("renders nothing when no files have changed yet", () => {
|
|
66
|
+
const { lastFrame } = render(
|
|
67
|
+
<FileChangeProgressBar progress={makeProgress({ filesChanged: 0 })} />,
|
|
68
|
+
);
|
|
69
|
+
expect((lastFrame() ?? "").trim()).toBe("");
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// --- FileChangeProgressBar: compact summary -------------------------------
|
|
74
|
+
|
|
75
|
+
describe("FileChangeProgressBar — compact summary", () => {
|
|
76
|
+
it("uses the singular noun for a single file", () => {
|
|
77
|
+
const { lastFrame } = render(
|
|
78
|
+
<FileChangeProgressBar
|
|
79
|
+
progress={makeProgress({
|
|
80
|
+
filesChanged: 1,
|
|
81
|
+
entries: [makeEntry({ pathAfter: "one.ts" })],
|
|
82
|
+
})}
|
|
83
|
+
/>,
|
|
84
|
+
);
|
|
85
|
+
expect(lastFrame() ?? "").toContain("1 file changing");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("uses the plural noun for multiple files", () => {
|
|
89
|
+
const { lastFrame } = render(
|
|
90
|
+
<FileChangeProgressBar
|
|
91
|
+
progress={makeProgress({
|
|
92
|
+
filesChanged: 3,
|
|
93
|
+
entries: [makeEntry({ pathAfter: "one.ts" })],
|
|
94
|
+
})}
|
|
95
|
+
/>,
|
|
96
|
+
);
|
|
97
|
+
expect(lastFrame() ?? "").toContain("3 files changing");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("shows the aggregate +N -M when counts exist", () => {
|
|
101
|
+
const { lastFrame } = render(
|
|
102
|
+
<FileChangeProgressBar
|
|
103
|
+
progress={makeProgress({
|
|
104
|
+
filesChanged: 2,
|
|
105
|
+
linesAdded: 12,
|
|
106
|
+
linesRemoved: 4,
|
|
107
|
+
entries: [makeEntry({ pathAfter: "one.ts" })],
|
|
108
|
+
})}
|
|
109
|
+
/>,
|
|
110
|
+
);
|
|
111
|
+
const out = lastFrame() ?? "";
|
|
112
|
+
expect(out).toContain("+12");
|
|
113
|
+
expect(out).toContain("-4");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("hides the aggregate stat when both counts are zero (never +0 -0)", () => {
|
|
117
|
+
const { lastFrame } = render(
|
|
118
|
+
<FileChangeProgressBar
|
|
119
|
+
progress={makeProgress({
|
|
120
|
+
filesChanged: 1,
|
|
121
|
+
linesAdded: 0,
|
|
122
|
+
linesRemoved: 0,
|
|
123
|
+
entries: [makeEntry({ pathAfter: "one.ts" })],
|
|
124
|
+
})}
|
|
125
|
+
/>,
|
|
126
|
+
);
|
|
127
|
+
// No "+" anywhere means no stat rendered; the count copy carries none.
|
|
128
|
+
expect(lastFrame() ?? "").not.toContain("+");
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// --- FileChangeProgressBar: expansion -------------------------------------
|
|
133
|
+
|
|
134
|
+
describe("FileChangeProgressBar — expansion", () => {
|
|
135
|
+
const progress = makeProgress({
|
|
136
|
+
filesChanged: 2,
|
|
137
|
+
linesAdded: 8,
|
|
138
|
+
linesRemoved: 1,
|
|
139
|
+
entries: [
|
|
140
|
+
makeEntry({ pathAfter: "src/app.ts", linesAdded: 5, linesRemoved: 1 }),
|
|
141
|
+
makeEntry({ pathAfter: "src/util.ts", linesAdded: 3, linesRemoved: 0 }),
|
|
142
|
+
],
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("hides the per-file list when collapsed (default)", () => {
|
|
146
|
+
const { lastFrame } = render(<FileChangeProgressBar progress={progress} />);
|
|
147
|
+
const out = lastFrame() ?? "";
|
|
148
|
+
expect(out).toContain("2 files changing");
|
|
149
|
+
expect(out).not.toContain("src/app.ts");
|
|
150
|
+
expect(out).not.toContain("src/util.ts");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("shows the per-file list with kind letter, path, and stats when expanded", () => {
|
|
154
|
+
const { lastFrame } = render(
|
|
155
|
+
<FileChangeProgressBar progress={progress} expanded />,
|
|
156
|
+
);
|
|
157
|
+
const out = lastFrame() ?? "";
|
|
158
|
+
expect(out).toContain("src/app.ts");
|
|
159
|
+
expect(out).toContain("src/util.ts");
|
|
160
|
+
expect(out).toContain("M"); // MODIFY kind letter
|
|
161
|
+
expect(out).toContain("+5");
|
|
162
|
+
expect(out).toContain("+3");
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("shows '… and K more' when the entry list is capped below the true total", () => {
|
|
166
|
+
const capped = makeProgress({
|
|
167
|
+
filesChanged: 5,
|
|
168
|
+
entries: [
|
|
169
|
+
makeEntry({ pathAfter: "a.ts" }),
|
|
170
|
+
makeEntry({ pathAfter: "b.ts" }),
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
const { lastFrame } = render(
|
|
174
|
+
<FileChangeProgressBar progress={capped} expanded />,
|
|
175
|
+
);
|
|
176
|
+
expect(lastFrame() ?? "").toContain("and 3 more");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("renders a rename entry as 'before → after'", () => {
|
|
180
|
+
const renamed = makeProgress({
|
|
181
|
+
filesChanged: 1,
|
|
182
|
+
entries: [
|
|
183
|
+
makeEntry({
|
|
184
|
+
pathBefore: "old/name.ts",
|
|
185
|
+
pathAfter: "new/name.ts",
|
|
186
|
+
kind: FileChangeKind.RENAME,
|
|
187
|
+
}),
|
|
188
|
+
],
|
|
189
|
+
});
|
|
190
|
+
const { lastFrame } = render(
|
|
191
|
+
<FileChangeProgressBar progress={renamed} expanded />,
|
|
192
|
+
);
|
|
193
|
+
expect(lastFrame() ?? "").toContain("old/name.ts → new/name.ts");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("hides per-file stats for a withheld entry (zero counts)", () => {
|
|
197
|
+
const secretish = makeProgress({
|
|
198
|
+
filesChanged: 1,
|
|
199
|
+
entries: [makeEntry({ pathAfter: ".env", linesAdded: 0, linesRemoved: 0 })],
|
|
200
|
+
});
|
|
201
|
+
const { lastFrame } = render(
|
|
202
|
+
<FileChangeProgressBar progress={secretish} expanded />,
|
|
203
|
+
);
|
|
204
|
+
const out = lastFrame() ?? "";
|
|
205
|
+
expect(out).toContain(".env");
|
|
206
|
+
expect(out).not.toContain("+");
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// --- path helpers (direct unit coverage) ----------------------------------
|
|
211
|
+
|
|
212
|
+
interface ChangeOpts {
|
|
213
|
+
readonly pathBefore?: string;
|
|
214
|
+
readonly pathAfter?: string;
|
|
215
|
+
readonly kind: FileChangeKind;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function makeChange(opts: ChangeOpts) {
|
|
219
|
+
return create(CapturedFileChangeSchema, {
|
|
220
|
+
id: "c-1",
|
|
221
|
+
pathBefore: opts.pathBefore ?? "",
|
|
222
|
+
pathAfter: opts.pathAfter ?? "",
|
|
223
|
+
kind: opts.kind,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
describe("changeDisplayPath", () => {
|
|
228
|
+
it("shows the after-path for an add", () => {
|
|
229
|
+
expect(
|
|
230
|
+
changeDisplayPath(makeChange({ pathAfter: "new.ts", kind: FileChangeKind.ADD })),
|
|
231
|
+
).toBe("new.ts");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("shows the after-path for a modify", () => {
|
|
235
|
+
expect(
|
|
236
|
+
changeDisplayPath(
|
|
237
|
+
makeChange({ pathAfter: "app.ts", kind: FileChangeKind.MODIFY }),
|
|
238
|
+
),
|
|
239
|
+
).toBe("app.ts");
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("falls back to the before-path for a delete", () => {
|
|
243
|
+
expect(
|
|
244
|
+
changeDisplayPath(
|
|
245
|
+
makeChange({ pathBefore: "gone.ts", kind: FileChangeKind.DELETE }),
|
|
246
|
+
),
|
|
247
|
+
).toBe("gone.ts");
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("shows 'before → after' for a rename", () => {
|
|
251
|
+
expect(
|
|
252
|
+
changeDisplayPath(
|
|
253
|
+
makeChange({
|
|
254
|
+
pathBefore: "old.ts",
|
|
255
|
+
pathAfter: "new.ts",
|
|
256
|
+
kind: FileChangeKind.RENAME,
|
|
257
|
+
}),
|
|
258
|
+
),
|
|
259
|
+
).toBe("old.ts → new.ts");
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
describe("progressEntryDisplayPath", () => {
|
|
264
|
+
it("shows the after-path for an add", () => {
|
|
265
|
+
expect(
|
|
266
|
+
progressEntryDisplayPath(makeEntry({ pathAfter: "new.ts", kind: FileChangeKind.ADD })),
|
|
267
|
+
).toBe("new.ts");
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("shows the after-path for a modify", () => {
|
|
271
|
+
expect(
|
|
272
|
+
progressEntryDisplayPath(makeEntry({ pathAfter: "app.ts" })),
|
|
273
|
+
).toBe("app.ts");
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it("falls back to the before-path for a delete", () => {
|
|
277
|
+
expect(
|
|
278
|
+
progressEntryDisplayPath(
|
|
279
|
+
makeEntry({ pathBefore: "gone.ts", kind: FileChangeKind.DELETE }),
|
|
280
|
+
),
|
|
281
|
+
).toBe("gone.ts");
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("shows 'before → after' for a rename — identical to changeDisplayPath", () => {
|
|
285
|
+
expect(
|
|
286
|
+
progressEntryDisplayPath(
|
|
287
|
+
makeEntry({
|
|
288
|
+
pathBefore: "old.ts",
|
|
289
|
+
pathAfter: "new.ts",
|
|
290
|
+
kind: FileChangeKind.RENAME,
|
|
291
|
+
}),
|
|
292
|
+
),
|
|
293
|
+
).toBe("old.ts → new.ts");
|
|
294
|
+
});
|
|
295
|
+
});
|
package/src/app/SessionView.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import { TodoList } from "../components/TodoList.js";
|
|
|
7
7
|
import { FollowUpInput } from "../components/FollowUpInput.js";
|
|
8
8
|
import { UsageWidget } from "../components/UsageWidget.js";
|
|
9
9
|
import { ExecutionProgress } from "../components/ExecutionProgress.js";
|
|
10
|
+
import { FileChangeProgressBar } from "../components/FileChangeProgressBar.js";
|
|
10
11
|
import { FileReviewPrompt } from "../components/FileReviewPrompt.js";
|
|
11
12
|
|
|
12
13
|
/** Interaction mode type used for follow-up executions. */
|
|
@@ -180,6 +181,17 @@ export function SessionView({ sessionId, org, mode }: SessionViewProps) {
|
|
|
180
181
|
|
|
181
182
|
<UsageWidget executions={allExecutions} />
|
|
182
183
|
|
|
184
|
+
{/* Mid-run live capture (DD-32): the transient "N files changing…" strip
|
|
185
|
+
for a still-running turn, covering shell-made changes with no tool row.
|
|
186
|
+
Mutually exclusive with the FileReviewPrompt below — progress shows
|
|
187
|
+
while CAPTURING, the prompt once AWAITING_REVIEW — so it hands off
|
|
188
|
+
cleanly when review opens. Non-interactive; the per-file list reuses the
|
|
189
|
+
existing Ctrl+O expand toggle. */}
|
|
190
|
+
<FileChangeProgressBar
|
|
191
|
+
progress={conv.fileChangeProgress}
|
|
192
|
+
expanded={expandTools}
|
|
193
|
+
/>
|
|
194
|
+
|
|
183
195
|
{conv.fileChangeSets.length > 0 && (
|
|
184
196
|
<Box flexDirection="column">
|
|
185
197
|
<FileReviewPrompt
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import type { FileChangeProgress } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
|
|
4
|
+
import { kindLetter, progressEntryDisplayPath } from "../file-review.js";
|
|
5
|
+
|
|
6
|
+
/** Props for {@link FileChangeProgressBar}. */
|
|
7
|
+
export interface FileChangeProgressBarProps {
|
|
8
|
+
/**
|
|
9
|
+
* The transient mid-run progress snapshot for the active turn (DD-32). Feed
|
|
10
|
+
* this from `useSessionConversation().fileChangeProgress`. Renders nothing when
|
|
11
|
+
* undefined or when no files have changed yet — the server clears it once the
|
|
12
|
+
* turn's change set leaves CAPTURING, so the strip disappears exactly when the
|
|
13
|
+
* decision surface (`FileReviewPrompt`) takes over.
|
|
14
|
+
*/
|
|
15
|
+
readonly progress: FileChangeProgress | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Whether to reveal the per-file list. The compact one-line summary always
|
|
18
|
+
* shows; the list is progressive disclosure. `SessionView` binds this to its
|
|
19
|
+
* existing Ctrl+O "expand" toggle so no new keybinding is introduced. Defaults
|
|
20
|
+
* to `false`.
|
|
21
|
+
*/
|
|
22
|
+
readonly expanded?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The terminal analogue of the web's non-interactive "N files changing…" strip
|
|
27
|
+
* (`@stigmer/react` `FileChangeProgressBar`), for a turn that is still running.
|
|
28
|
+
*
|
|
29
|
+
* WHY IT EXISTS. The transcript streams per-edit tool rows, but a change made by
|
|
30
|
+
* a shell command (a `sed`, a build step) has no tool row, and there is no
|
|
31
|
+
* running net-of-many-edits rollup until the turn ends. This strip fills that
|
|
32
|
+
* gap: a compact, non-interactive count of the workspace delta accumulating
|
|
33
|
+
* during the turn, sitting where the `FileReviewPrompt` will later appear. The
|
|
34
|
+
* two are mutually exclusive per turn (progress shows while CAPTURING; the prompt
|
|
35
|
+
* once AWAITING_REVIEW), so the strip hands off cleanly to the prompt.
|
|
36
|
+
*
|
|
37
|
+
* NEVER A DECISION SURFACE. Progress is non-authoritative and carries no file
|
|
38
|
+
* bodies — it is never reviewable or decidable, and it owns no keyboard input.
|
|
39
|
+
* The reviewed diff is the turn-boundary candidate (`FileReviewPrompt`). A
|
|
40
|
+
* secret-like path is surfaced by name with its counts withheld (zeroed), so the
|
|
41
|
+
* `+N −M` stat renders nothing for it. The quiet/dim register (no border)
|
|
42
|
+
* distinguishes it from the loud, bordered decision prompt.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* const conv = useSessionConversation(sessionId, org);
|
|
47
|
+
* <FileChangeProgressBar progress={conv.fileChangeProgress} expanded={expandTools} />
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function FileChangeProgressBar({
|
|
51
|
+
progress,
|
|
52
|
+
expanded = false,
|
|
53
|
+
}: FileChangeProgressBarProps) {
|
|
54
|
+
if (!progress || progress.filesChanged === 0) return null;
|
|
55
|
+
|
|
56
|
+
const { filesChanged, linesAdded, linesRemoved, entries } = progress;
|
|
57
|
+
const hiddenCount = filesChanged - entries.length;
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Box flexDirection="column" paddingLeft={1}>
|
|
61
|
+
<Box gap={1}>
|
|
62
|
+
<Text dimColor>✎</Text>
|
|
63
|
+
<Text dimColor>
|
|
64
|
+
{filesChanged} file{filesChanged === 1 ? "" : "s"} changing…
|
|
65
|
+
</Text>
|
|
66
|
+
<LineStats linesAdded={linesAdded} linesRemoved={linesRemoved} />
|
|
67
|
+
</Box>
|
|
68
|
+
|
|
69
|
+
{expanded && (
|
|
70
|
+
<Box flexDirection="column" paddingLeft={2}>
|
|
71
|
+
{entries.map((entry, idx) => {
|
|
72
|
+
const path = progressEntryDisplayPath(entry);
|
|
73
|
+
return (
|
|
74
|
+
<Box key={`${path}-${idx}`} gap={1}>
|
|
75
|
+
<Text dimColor>{kindLetter(entry.kind)}</Text>
|
|
76
|
+
<Text dimColor wrap="truncate-end">
|
|
77
|
+
{path}
|
|
78
|
+
</Text>
|
|
79
|
+
<LineStats
|
|
80
|
+
linesAdded={entry.linesAdded}
|
|
81
|
+
linesRemoved={entry.linesRemoved}
|
|
82
|
+
/>
|
|
83
|
+
</Box>
|
|
84
|
+
);
|
|
85
|
+
})}
|
|
86
|
+
{hiddenCount > 0 && (
|
|
87
|
+
<Box>
|
|
88
|
+
<Text dimColor>… and {hiddenCount} more</Text>
|
|
89
|
+
</Box>
|
|
90
|
+
)}
|
|
91
|
+
</Box>
|
|
92
|
+
)}
|
|
93
|
+
</Box>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The `+N −M` stat for one file (or the whole turn), in the diff colour
|
|
99
|
+
* vocabulary. Renders nothing when both counts are zero — the honest signal that
|
|
100
|
+
* no count exists (binary or secret-withheld changes) — rather than a misleading
|
|
101
|
+
* `+0 -0`, matching the web `FileLineStats` contract.
|
|
102
|
+
*
|
|
103
|
+
* Kept module-local: this is the only consumer today. When `FileReviewPrompt`
|
|
104
|
+
* and `FileReviewRecord` gain `+N −M` (the deferred "CLI +N −M parity"
|
|
105
|
+
* follow-up), lift this into a shared ink atom (the analogue of `sdk/react`'s
|
|
106
|
+
* `FileReviewAtoms`) so the three surfaces cannot drift — do not copy it.
|
|
107
|
+
*/
|
|
108
|
+
function LineStats({
|
|
109
|
+
linesAdded,
|
|
110
|
+
linesRemoved,
|
|
111
|
+
}: {
|
|
112
|
+
readonly linesAdded: number;
|
|
113
|
+
readonly linesRemoved: number;
|
|
114
|
+
}) {
|
|
115
|
+
if (linesAdded === 0 && linesRemoved === 0) return null;
|
|
116
|
+
return (
|
|
117
|
+
<Text>
|
|
118
|
+
<Text color="green">+{linesAdded}</Text>
|
|
119
|
+
<Text color="red"> -{linesRemoved}</Text>
|
|
120
|
+
</Text>
|
|
121
|
+
);
|
|
122
|
+
}
|
package/src/file-review.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CapturedFileChange,
|
|
3
|
+
FileChangeProgressEntry,
|
|
3
4
|
FileChangeSet,
|
|
4
5
|
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
|
|
5
6
|
import {
|
|
@@ -28,14 +29,39 @@ export function kindLetter(kind: FileChangeKind): string {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
|
-
* The path
|
|
32
|
-
*
|
|
32
|
+
* The one rename-aware path-display rule for the terminal, over the raw
|
|
33
|
+
* before/after/kind triple shared by every file-change shape (reviewable
|
|
34
|
+
* `CapturedFileChange` and slim `FileChangeProgressEntry` alike). Kept private
|
|
35
|
+
* and fed by the typed adapters below so the two surfaces can never grow
|
|
36
|
+
* divergent rename formatting.
|
|
33
37
|
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
function displayChangePath(
|
|
39
|
+
pathBefore: string,
|
|
40
|
+
pathAfter: string,
|
|
41
|
+
kind: FileChangeKind,
|
|
42
|
+
): string {
|
|
43
|
+
if (kind === FileChangeKind.RENAME && pathBefore && pathAfter) {
|
|
44
|
+
return `${pathBefore} → ${pathAfter}`;
|
|
37
45
|
}
|
|
38
|
-
return
|
|
46
|
+
return pathAfter || pathBefore;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The path to show for a reviewable change: the post-edit path, or the pre-edit
|
|
51
|
+
* path for a deletion. A rename shows `before → after` so both sides are visible.
|
|
52
|
+
*/
|
|
53
|
+
export function changeDisplayPath(change: CapturedFileChange): string {
|
|
54
|
+
return displayChangePath(change.pathBefore, change.pathAfter, change.kind);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The path to show for a mid-run progress entry (DD-32), using the same
|
|
59
|
+
* rename-aware rule as {@link changeDisplayPath}. The slim entry carries no
|
|
60
|
+
* bodies or digests, only the same before/after/kind triple, so the terminal
|
|
61
|
+
* renders its path identically to the reviewable surfaces.
|
|
62
|
+
*/
|
|
63
|
+
export function progressEntryDisplayPath(entry: FileChangeProgressEntry): string {
|
|
64
|
+
return displayChangePath(entry.pathBefore, entry.pathAfter, entry.kind);
|
|
39
65
|
}
|
|
40
66
|
|
|
41
67
|
/**
|
package/src/index.ts
CHANGED
|
@@ -21,11 +21,16 @@ export { TodoList, type TodoListProps } from "./components/TodoList.js";
|
|
|
21
21
|
export { ApprovalPrompt, type ApprovalPromptProps } from "./components/ApprovalPrompt.js";
|
|
22
22
|
export { FileReviewPrompt, type FileReviewPromptProps } from "./components/FileReviewPrompt.js";
|
|
23
23
|
export { FileReviewRecord, type FileReviewRecordProps } from "./components/FileReviewRecord.js";
|
|
24
|
+
export {
|
|
25
|
+
FileChangeProgressBar,
|
|
26
|
+
type FileChangeProgressBarProps,
|
|
27
|
+
} from "./components/FileChangeProgressBar.js";
|
|
24
28
|
|
|
25
29
|
// File-review pure helpers (kind letters, paths, block reasons, settled counts)
|
|
26
30
|
export {
|
|
27
31
|
kindLetter,
|
|
28
32
|
changeDisplayPath,
|
|
33
|
+
progressEntryDisplayPath,
|
|
29
34
|
blockReasonNote,
|
|
30
35
|
settledCounts,
|
|
31
36
|
settledSummary,
|