@dsh-cc/tui 0.5.0
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/LICENSE +201 -0
- package/README.md +144 -0
- package/lib/bash-history.d.ts +31 -0
- package/lib/bash-history.d.ts.map +1 -0
- package/lib/bash-history.js +94 -0
- package/lib/bash-history.js.map +1 -0
- package/lib/compact-fold.d.ts +35 -0
- package/lib/compact-fold.d.ts.map +1 -0
- package/lib/compact-fold.js +60 -0
- package/lib/compact-fold.js.map +1 -0
- package/lib/components/arg-completers.d.ts +22 -0
- package/lib/components/arg-completers.d.ts.map +1 -0
- package/lib/components/arg-completers.js +75 -0
- package/lib/components/arg-completers.js.map +1 -0
- package/lib/components/code-theme.d.ts +25 -0
- package/lib/components/code-theme.d.ts.map +1 -0
- package/lib/components/code-theme.js +137 -0
- package/lib/components/code-theme.js.map +1 -0
- package/lib/components/completion.d.ts +50 -0
- package/lib/components/completion.d.ts.map +1 -0
- package/lib/components/completion.js +279 -0
- package/lib/components/completion.js.map +1 -0
- package/lib/components/diff-card.d.ts +29 -0
- package/lib/components/diff-card.d.ts.map +1 -0
- package/lib/components/diff-card.js +175 -0
- package/lib/components/diff-card.js.map +1 -0
- package/lib/components/diff-hunks.d.ts +44 -0
- package/lib/components/diff-hunks.d.ts.map +1 -0
- package/lib/components/diff-hunks.js +188 -0
- package/lib/components/diff-hunks.js.map +1 -0
- package/lib/components/editor-history.d.ts +23 -0
- package/lib/components/editor-history.d.ts.map +1 -0
- package/lib/components/editor-history.js +29 -0
- package/lib/components/editor-history.js.map +1 -0
- package/lib/components/markdown-theme.d.ts +11 -0
- package/lib/components/markdown-theme.d.ts.map +1 -0
- package/lib/components/markdown-theme.js +29 -0
- package/lib/components/markdown-theme.js.map +1 -0
- package/lib/components/masked-input.d.ts +24 -0
- package/lib/components/masked-input.d.ts.map +1 -0
- package/lib/components/masked-input.js +168 -0
- package/lib/components/masked-input.js.map +1 -0
- package/lib/components/overlay-host.d.ts +31 -0
- package/lib/components/overlay-host.d.ts.map +1 -0
- package/lib/components/overlay-host.js +128 -0
- package/lib/components/overlay-host.js.map +1 -0
- package/lib/components/overlays.d.ts +94 -0
- package/lib/components/overlays.d.ts.map +1 -0
- package/lib/components/overlays.js +450 -0
- package/lib/components/overlays.js.map +1 -0
- package/lib/components/provider-box.d.ts +23 -0
- package/lib/components/provider-box.d.ts.map +1 -0
- package/lib/components/provider-box.js +164 -0
- package/lib/components/provider-box.js.map +1 -0
- package/lib/components/read-group.d.ts +51 -0
- package/lib/components/read-group.d.ts.map +1 -0
- package/lib/components/read-group.js +105 -0
- package/lib/components/read-group.js.map +1 -0
- package/lib/components/root-bash.d.ts +36 -0
- package/lib/components/root-bash.d.ts.map +1 -0
- package/lib/components/root-bash.js +112 -0
- package/lib/components/root-bash.js.map +1 -0
- package/lib/components/root-types.d.ts +42 -0
- package/lib/components/root-types.d.ts.map +1 -0
- package/lib/components/root-types.js +8 -0
- package/lib/components/root-types.js.map +1 -0
- package/lib/components/root-utils.d.ts +22 -0
- package/lib/components/root-utils.d.ts.map +1 -0
- package/lib/components/root-utils.js +45 -0
- package/lib/components/root-utils.js.map +1 -0
- package/lib/components/root.d.ts +25 -0
- package/lib/components/root.d.ts.map +1 -0
- package/lib/components/root.js +357 -0
- package/lib/components/root.js.map +1 -0
- package/lib/components/theme.d.ts +61 -0
- package/lib/components/theme.d.ts.map +1 -0
- package/lib/components/theme.js +99 -0
- package/lib/components/theme.js.map +1 -0
- package/lib/components/transcript.d.ts +43 -0
- package/lib/components/transcript.d.ts.map +1 -0
- package/lib/components/transcript.js +203 -0
- package/lib/components/transcript.js.map +1 -0
- package/lib/components/working-line.d.ts +35 -0
- package/lib/components/working-line.d.ts.map +1 -0
- package/lib/components/working-line.js +66 -0
- package/lib/components/working-line.js.map +1 -0
- package/lib/effort-catalog.d.ts +27 -0
- package/lib/effort-catalog.d.ts.map +1 -0
- package/lib/effort-catalog.js +36 -0
- package/lib/effort-catalog.js.map +1 -0
- package/lib/export-markdown.d.ts +18 -0
- package/lib/export-markdown.d.ts.map +1 -0
- package/lib/export-markdown.js +124 -0
- package/lib/export-markdown.js.map +1 -0
- package/lib/harness/approval-preview.d.ts +33 -0
- package/lib/harness/approval-preview.d.ts.map +1 -0
- package/lib/harness/approval-preview.js +179 -0
- package/lib/harness/approval-preview.js.map +1 -0
- package/lib/harness/boot-banner.d.ts +14 -0
- package/lib/harness/boot-banner.d.ts.map +1 -0
- package/lib/harness/boot-banner.js +89 -0
- package/lib/harness/boot-banner.js.map +1 -0
- package/lib/harness/driver-agent.d.ts +78 -0
- package/lib/harness/driver-agent.d.ts.map +1 -0
- package/lib/harness/driver-agent.js +314 -0
- package/lib/harness/driver-agent.js.map +1 -0
- package/lib/harness/driver-agents.d.ts +20 -0
- package/lib/harness/driver-agents.d.ts.map +1 -0
- package/lib/harness/driver-agents.js +123 -0
- package/lib/harness/driver-agents.js.map +1 -0
- package/lib/harness/driver-approvals.d.ts +38 -0
- package/lib/harness/driver-approvals.d.ts.map +1 -0
- package/lib/harness/driver-approvals.js +277 -0
- package/lib/harness/driver-approvals.js.map +1 -0
- package/lib/harness/driver-bash.d.ts +15 -0
- package/lib/harness/driver-bash.d.ts.map +1 -0
- package/lib/harness/driver-bash.js +73 -0
- package/lib/harness/driver-bash.js.map +1 -0
- package/lib/harness/driver-catalog.d.ts +84 -0
- package/lib/harness/driver-catalog.d.ts.map +1 -0
- package/lib/harness/driver-catalog.js +256 -0
- package/lib/harness/driver-catalog.js.map +1 -0
- package/lib/harness/driver-ctx.d.ts +462 -0
- package/lib/harness/driver-ctx.d.ts.map +1 -0
- package/lib/harness/driver-ctx.js +11 -0
- package/lib/harness/driver-ctx.js.map +1 -0
- package/lib/harness/driver-hud.d.ts +31 -0
- package/lib/harness/driver-hud.d.ts.map +1 -0
- package/lib/harness/driver-hud.js +204 -0
- package/lib/harness/driver-hud.js.map +1 -0
- package/lib/harness/driver-live.d.ts +36 -0
- package/lib/harness/driver-live.d.ts.map +1 -0
- package/lib/harness/driver-live.js +44 -0
- package/lib/harness/driver-live.js.map +1 -0
- package/lib/harness/driver-modal.d.ts +52 -0
- package/lib/harness/driver-modal.d.ts.map +1 -0
- package/lib/harness/driver-modal.js +78 -0
- package/lib/harness/driver-modal.js.map +1 -0
- package/lib/harness/driver-mode.d.ts +35 -0
- package/lib/harness/driver-mode.d.ts.map +1 -0
- package/lib/harness/driver-mode.js +84 -0
- package/lib/harness/driver-mode.js.map +1 -0
- package/lib/harness/driver-pickers.d.ts +48 -0
- package/lib/harness/driver-pickers.d.ts.map +1 -0
- package/lib/harness/driver-pickers.js +249 -0
- package/lib/harness/driver-pickers.js.map +1 -0
- package/lib/harness/driver-promote.d.ts +29 -0
- package/lib/harness/driver-promote.d.ts.map +1 -0
- package/lib/harness/driver-promote.js +36 -0
- package/lib/harness/driver-promote.js.map +1 -0
- package/lib/harness/driver-queue.d.ts +19 -0
- package/lib/harness/driver-queue.d.ts.map +1 -0
- package/lib/harness/driver-queue.js +281 -0
- package/lib/harness/driver-queue.js.map +1 -0
- package/lib/harness/driver-run-local.d.ts +32 -0
- package/lib/harness/driver-run-local.d.ts.map +1 -0
- package/lib/harness/driver-run-local.js +366 -0
- package/lib/harness/driver-run-local.js.map +1 -0
- package/lib/harness/driver-sessions.d.ts +28 -0
- package/lib/harness/driver-sessions.d.ts.map +1 -0
- package/lib/harness/driver-sessions.js +386 -0
- package/lib/harness/driver-sessions.js.map +1 -0
- package/lib/harness/driver.d.ts +22 -0
- package/lib/harness/driver.d.ts.map +1 -0
- package/lib/harness/driver.js +459 -0
- package/lib/harness/driver.js.map +1 -0
- package/lib/harness/preset.d.ts +32 -0
- package/lib/harness/preset.d.ts.map +1 -0
- package/lib/harness/preset.js +34 -0
- package/lib/harness/preset.js.map +1 -0
- package/lib/harness/session-list.d.ts +65 -0
- package/lib/harness/session-list.d.ts.map +1 -0
- package/lib/harness/session-list.js +91 -0
- package/lib/harness/session-list.js.map +1 -0
- package/lib/harness/shell-output.d.ts +44 -0
- package/lib/harness/shell-output.d.ts.map +1 -0
- package/lib/harness/shell-output.js +90 -0
- package/lib/harness/shell-output.js.map +1 -0
- package/lib/harness/statusline-cc-transcript.d.ts +51 -0
- package/lib/harness/statusline-cc-transcript.d.ts.map +1 -0
- package/lib/harness/statusline-cc-transcript.js +191 -0
- package/lib/harness/statusline-cc-transcript.js.map +1 -0
- package/lib/harness/statusline-command.d.ts +54 -0
- package/lib/harness/statusline-command.d.ts.map +1 -0
- package/lib/harness/statusline-command.js +161 -0
- package/lib/harness/statusline-command.js.map +1 -0
- package/lib/harness/statusline-payload.d.ts +79 -0
- package/lib/harness/statusline-payload.d.ts.map +1 -0
- package/lib/harness/statusline-payload.js +93 -0
- package/lib/harness/statusline-payload.js.map +1 -0
- package/lib/harness/statusline-settings.d.ts +47 -0
- package/lib/harness/statusline-settings.d.ts.map +1 -0
- package/lib/harness/statusline-settings.js +57 -0
- package/lib/harness/statusline-settings.js.map +1 -0
- package/lib/harness/statusline-wiring.d.ts +45 -0
- package/lib/harness/statusline-wiring.d.ts.map +1 -0
- package/lib/harness/statusline-wiring.js +247 -0
- package/lib/harness/statusline-wiring.js.map +1 -0
- package/lib/harness/usage-view.d.ts +84 -0
- package/lib/harness/usage-view.d.ts.map +1 -0
- package/lib/harness/usage-view.js +199 -0
- package/lib/harness/usage-view.js.map +1 -0
- package/lib/harness/worktree-exit.d.ts +105 -0
- package/lib/harness/worktree-exit.d.ts.map +1 -0
- package/lib/harness/worktree-exit.js +168 -0
- package/lib/harness/worktree-exit.js.map +1 -0
- package/lib/history.d.ts +50 -0
- package/lib/history.d.ts.map +1 -0
- package/lib/history.js +139 -0
- package/lib/history.js.map +1 -0
- package/lib/index.d.ts +63 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +54 -0
- package/lib/index.js.map +1 -0
- package/lib/input.d.ts +158 -0
- package/lib/input.d.ts.map +1 -0
- package/lib/input.js +400 -0
- package/lib/input.js.map +1 -0
- package/lib/invariant.d.ts +14 -0
- package/lib/invariant.d.ts.map +1 -0
- package/lib/invariant.js +20 -0
- package/lib/invariant.js.map +1 -0
- package/lib/mode-cycle.d.ts +22 -0
- package/lib/mode-cycle.d.ts.map +1 -0
- package/lib/mode-cycle.js +32 -0
- package/lib/mode-cycle.js.map +1 -0
- package/lib/model-catalog.d.ts +22 -0
- package/lib/model-catalog.d.ts.map +1 -0
- package/lib/model-catalog.js +45 -0
- package/lib/model-catalog.js.map +1 -0
- package/lib/packaged-preset.d.ts +32 -0
- package/lib/packaged-preset.d.ts.map +1 -0
- package/lib/packaged-preset.js +94 -0
- package/lib/packaged-preset.js.map +1 -0
- package/lib/plugin.d.ts +11 -0
- package/lib/plugin.d.ts.map +1 -0
- package/lib/plugin.js +88 -0
- package/lib/plugin.js.map +1 -0
- package/lib/profile.d.ts +4 -0
- package/lib/profile.d.ts.map +1 -0
- package/lib/profile.js +7 -0
- package/lib/profile.js.map +1 -0
- package/lib/project-sessions.d.ts +29 -0
- package/lib/project-sessions.d.ts.map +1 -0
- package/lib/project-sessions.js +60 -0
- package/lib/project-sessions.js.map +1 -0
- package/lib/project.d.ts +75 -0
- package/lib/project.d.ts.map +1 -0
- package/lib/project.js +196 -0
- package/lib/project.js.map +1 -0
- package/lib/provider-actions.d.ts +37 -0
- package/lib/provider-actions.d.ts.map +1 -0
- package/lib/provider-actions.js +417 -0
- package/lib/provider-actions.js.map +1 -0
- package/lib/provider-command.d.ts +109 -0
- package/lib/provider-command.d.ts.map +1 -0
- package/lib/provider-command.js +220 -0
- package/lib/provider-command.js.map +1 -0
- package/lib/provider-detail.d.ts +15 -0
- package/lib/provider-detail.d.ts.map +1 -0
- package/lib/provider-detail.js +201 -0
- package/lib/provider-detail.js.map +1 -0
- package/lib/provider-flow.d.ts +191 -0
- package/lib/provider-flow.d.ts.map +1 -0
- package/lib/provider-flow.js +192 -0
- package/lib/provider-flow.js.map +1 -0
- package/lib/provider-presets.d.ts +32 -0
- package/lib/provider-presets.d.ts.map +1 -0
- package/lib/provider-presets.js +105 -0
- package/lib/provider-presets.js.map +1 -0
- package/lib/provider-read.d.ts +63 -0
- package/lib/provider-read.d.ts.map +1 -0
- package/lib/provider-read.js +115 -0
- package/lib/provider-read.js.map +1 -0
- package/lib/provider-settings.d.ts +30 -0
- package/lib/provider-settings.d.ts.map +1 -0
- package/lib/provider-settings.js +65 -0
- package/lib/provider-settings.js.map +1 -0
- package/lib/resume-target.d.ts +59 -0
- package/lib/resume-target.d.ts.map +1 -0
- package/lib/resume-target.js +143 -0
- package/lib/resume-target.js.map +1 -0
- package/lib/slash.d.ts +44 -0
- package/lib/slash.d.ts.map +1 -0
- package/lib/slash.js +81 -0
- package/lib/slash.js.map +1 -0
- package/lib/state/driver-types.d.ts +505 -0
- package/lib/state/driver-types.d.ts.map +1 -0
- package/lib/state/driver-types.js +8 -0
- package/lib/state/driver-types.js.map +1 -0
- package/lib/state/driver-usage-types.d.ts +59 -0
- package/lib/state/driver-usage-types.d.ts.map +1 -0
- package/lib/state/driver-usage-types.js +8 -0
- package/lib/state/driver-usage-types.js.map +1 -0
- package/lib/statusline.d.ts +63 -0
- package/lib/statusline.d.ts.map +1 -0
- package/lib/statusline.js +97 -0
- package/lib/statusline.js.map +1 -0
- package/lib/store/pickers.d.ts +34 -0
- package/lib/store/pickers.d.ts.map +1 -0
- package/lib/store/pickers.js +111 -0
- package/lib/store/pickers.js.map +1 -0
- package/lib/store/provider-panel.d.ts +107 -0
- package/lib/store/provider-panel.d.ts.map +1 -0
- package/lib/store/provider-panel.js +151 -0
- package/lib/store/provider-panel.js.map +1 -0
- package/lib/store/question.d.ts +21 -0
- package/lib/store/question.d.ts.map +1 -0
- package/lib/store/question.js +59 -0
- package/lib/store/question.js.map +1 -0
- package/lib/store/queue.d.ts +27 -0
- package/lib/store/queue.d.ts.map +1 -0
- package/lib/store/queue.js +34 -0
- package/lib/store/queue.js.map +1 -0
- package/lib/store/session.d.ts +73 -0
- package/lib/store/session.d.ts.map +1 -0
- package/lib/store/session.js +172 -0
- package/lib/store/session.js.map +1 -0
- package/lib/store/subagents.d.ts +16 -0
- package/lib/store/subagents.d.ts.map +1 -0
- package/lib/store/subagents.js +44 -0
- package/lib/store/subagents.js.map +1 -0
- package/lib/store/todos.d.ts +35 -0
- package/lib/store/todos.d.ts.map +1 -0
- package/lib/store/todos.js +68 -0
- package/lib/store/todos.js.map +1 -0
- package/lib/store/usage.d.ts +15 -0
- package/lib/store/usage.d.ts.map +1 -0
- package/lib/store/usage.js +27 -0
- package/lib/store/usage.js.map +1 -0
- package/lib/store/views.d.ts +419 -0
- package/lib/store/views.d.ts.map +1 -0
- package/lib/store/views.js +3 -0
- package/lib/store/views.js.map +1 -0
- package/lib/store.d.ts +19 -0
- package/lib/store.d.ts.map +1 -0
- package/lib/store.js +10 -0
- package/lib/store.js.map +1 -0
- package/lib/terminal/lease.d.ts +33 -0
- package/lib/terminal/lease.d.ts.map +1 -0
- package/lib/terminal/lease.js +99 -0
- package/lib/terminal/lease.js.map +1 -0
- package/lib/tool-card.d.ts +75 -0
- package/lib/tool-card.d.ts.map +1 -0
- package/lib/tool-card.js +109 -0
- package/lib/tool-card.js.map +1 -0
- package/lib/tool-verbs.d.ts +12 -0
- package/lib/tool-verbs.d.ts.map +1 -0
- package/lib/tool-verbs.js +29 -0
- package/lib/tool-verbs.js.map +1 -0
- package/lib/transcript.d.ts +40 -0
- package/lib/transcript.d.ts.map +1 -0
- package/lib/transcript.js +413 -0
- package/lib/transcript.js.map +1 -0
- package/lib/working-line.d.ts +44 -0
- package/lib/working-line.d.ts.map +1 -0
- package/lib/working-line.js +56 -0
- package/lib/working-line.js.map +1 -0
- package/package.json +72 -0
- package/presets/cc/.dsh-cc-managed.json +5 -0
- package/presets/cc/agent.cordis.yml +524 -0
- package/presets/cc/preset.yml +3 -0
- package/scripts/stage-preset.mjs +26 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure session-list helpers for the /resume picker: last-activity sort,
|
|
3
|
+
* scope/query filtering, and row formatting. No imports — shared by the
|
|
4
|
+
* driver, the overlay renderer, and the specs.
|
|
5
|
+
* @module @dsh-cc/tui/harness/session-list
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Order sessions by last activity: `(updatedAtMs ?? createdAt)` descending,
|
|
9
|
+
* ties broken by createdAt then id (so the order is stable across reloads).
|
|
10
|
+
* Returns a new list; the input is untouched.
|
|
11
|
+
*/
|
|
12
|
+
export function sortByActivity(entries) {
|
|
13
|
+
return entries.slice().sort((a, b) => {
|
|
14
|
+
const activeA = a.updatedAtMs ?? a.createdAt;
|
|
15
|
+
const activeB = b.updatedAtMs ?? b.createdAt;
|
|
16
|
+
if (activeA !== activeB)
|
|
17
|
+
return activeB - activeA;
|
|
18
|
+
if (a.createdAt !== b.createdAt)
|
|
19
|
+
return b.createdAt - a.createdAt;
|
|
20
|
+
return a.id.localeCompare(b.id);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Filter sessions for the picker: child/fork sessions (those with
|
|
25
|
+
* `parentSession`) are hidden unless they are the live session; cwd scope
|
|
26
|
+
* keeps only entries the `isMember` predicate accepts (the driver builds it
|
|
27
|
+
* from the session's *project* — sidecar index ∪ cwd-prefix heuristic — so
|
|
28
|
+
* worktree and subdirectory sessions of the same repo stay visible; a
|
|
29
|
+
* missing predicate disables the scope); then a non-empty query keeps
|
|
30
|
+
* entries whose title, id, or cwd contains it case-insensitively. Never
|
|
31
|
+
* re-sorts — the caller controls order.
|
|
32
|
+
*/
|
|
33
|
+
export function filterSessions(entries, opts) {
|
|
34
|
+
let result = entries.slice();
|
|
35
|
+
result = result.filter(entry => entry.parentSession === undefined || entry.id === opts.currentId);
|
|
36
|
+
if (opts.scope === 'cwd' && opts.isMember !== undefined) {
|
|
37
|
+
result = result.filter(opts.isMember);
|
|
38
|
+
}
|
|
39
|
+
const query = opts.query.trim().toLowerCase();
|
|
40
|
+
if (query.length > 0) {
|
|
41
|
+
result = result.filter(entry => (entry.title ?? '').toLowerCase().includes(query)
|
|
42
|
+
|| entry.id.toLowerCase().includes(query)
|
|
43
|
+
|| (entry.cwd ?? '').toLowerCase().includes(query));
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
/** Short relative-time label for a session timestamp: "2m ago", "1h ago", "3d ago", or `M/D`. */
|
|
48
|
+
export function relativeDate(ts, now = Date.now()) {
|
|
49
|
+
const seconds = Math.floor((now - ts) / 1000);
|
|
50
|
+
if (seconds < 60)
|
|
51
|
+
return 'just now';
|
|
52
|
+
const minutes = Math.floor(seconds / 60);
|
|
53
|
+
if (minutes < 60)
|
|
54
|
+
return `${minutes}m ago`;
|
|
55
|
+
const hours = Math.floor(minutes / 60);
|
|
56
|
+
if (hours < 24)
|
|
57
|
+
return `${hours}h ago`;
|
|
58
|
+
const days = Math.floor(hours / 24);
|
|
59
|
+
if (days < 7)
|
|
60
|
+
return `${days}d ago`;
|
|
61
|
+
const d = new Date(ts);
|
|
62
|
+
return `${d.getMonth() + 1}/${d.getDate()}`;
|
|
63
|
+
}
|
|
64
|
+
/** First 8 chars of a session id — enough to distinguish in a short list. */
|
|
65
|
+
export function shortId(id) {
|
|
66
|
+
return id.length > 8 ? id.slice(0, 8) : id;
|
|
67
|
+
}
|
|
68
|
+
/** Last path segment of a directory, accepting both `/` and `\` separators. */
|
|
69
|
+
function basename(path) {
|
|
70
|
+
const segments = path.split(/[\\/]/);
|
|
71
|
+
return segments[segments.length - 1] ?? path;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Compute one picker row: relative time from last activity, the title (or
|
|
75
|
+
* short id when untitled), the 8-char short id, the cwd basename when the
|
|
76
|
+
* row should surface it (all-projects scope), and whether the entry is the
|
|
77
|
+
* session the user is currently in.
|
|
78
|
+
*/
|
|
79
|
+
export function formatSessionRow(entry, opts) {
|
|
80
|
+
const time = relativeDate(entry.updatedAtMs ?? entry.createdAt, opts.now);
|
|
81
|
+
const short = shortId(entry.id);
|
|
82
|
+
const label = entry.title !== undefined && entry.title.length > 0 ? entry.title : short;
|
|
83
|
+
return {
|
|
84
|
+
time,
|
|
85
|
+
label,
|
|
86
|
+
shortId: short,
|
|
87
|
+
...opts.showCwd && entry.cwd !== undefined ? { cwdPart: basename(entry.cwd) } : {},
|
|
88
|
+
current: entry.id === opts.currentId,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=session-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-list.js","sourceRoot":"","sources":["../../src/harness/session-list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell/output helpers extracted from harness/driver.ts: `!` command budget
|
|
3
|
+
* constants, git-branch probing, default `/export-md` path stamping, and
|
|
4
|
+
* bash-output row assembly. Node builtins only — no store or harness imports.
|
|
5
|
+
* @module @dsh-cc/tui/harness/shell-output
|
|
6
|
+
*/
|
|
7
|
+
import { execFile } from 'node:child_process';
|
|
8
|
+
/** Wall-clock lifetime of a `!` shell command. */
|
|
9
|
+
export declare const BASH_TIMEOUT_MS = 120000;
|
|
10
|
+
/** Foreground stdout byte budget handed to the shell executor for a `!` run. */
|
|
11
|
+
export declare const BASH_STDOUT_MAX_BYTES = 64000;
|
|
12
|
+
/** Lines of command output shown under the `$ cmd` echo row (rest is elided). */
|
|
13
|
+
export declare const BASH_OUTPUT_LINE_CAP = 20;
|
|
14
|
+
/** Notice parked above the composer while a `!` command runs. */
|
|
15
|
+
export declare const BASH_RUNNING_NOTICE = "\u280B running\u2026";
|
|
16
|
+
export declare const execFileAsync: typeof execFile.__promisify__;
|
|
17
|
+
/**
|
|
18
|
+
* Default `/export-md` output directory: `$DSH_HOME/tui/exports` (or
|
|
19
|
+
* `~/.dsh/tui/exports`), mirroring the `resume-target` data-dir
|
|
20
|
+
* resolution one level deeper.
|
|
21
|
+
*/
|
|
22
|
+
export declare function defaultExportDir(): string;
|
|
23
|
+
/** Filesystem-safe timestamp for default export filenames (ISO, `:`/`.` dashed). */
|
|
24
|
+
export declare function exportStamp(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Best-effort git branch probe: `git -C <cwd> rev-parse --abbrev-ref HEAD`
|
|
27
|
+
* with a short timeout. Never throws — errors (no git, no repo, detached
|
|
28
|
+
* head) resolve to undefined and the statusline simply omits the segment.
|
|
29
|
+
*/
|
|
30
|
+
export declare function gitBranchOf(cwd: string): Promise<string | undefined>;
|
|
31
|
+
/**
|
|
32
|
+
* Assemble the bash-command output row: combined stdout/stderr (line-capped)
|
|
33
|
+
* plus a failure trailer. The row is error-marked for a non-zero exit, a
|
|
34
|
+
* signal death, or an executor timeout.
|
|
35
|
+
*/
|
|
36
|
+
export declare function shellOutputRow(stdout: string, stderr: string, outcome: {
|
|
37
|
+
exitCode: number | null;
|
|
38
|
+
timedOut: boolean;
|
|
39
|
+
}): {
|
|
40
|
+
kind: 'status';
|
|
41
|
+
text: string;
|
|
42
|
+
error?: boolean;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=shell-output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-output.d.ts","sourceRoot":"","sources":["../../src/harness/shell-output.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAK7C,kDAAkD;AAClD,eAAO,MAAM,eAAe,SAAU,CAAA;AAEtC,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,QAAS,CAAA;AAE3C,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,KAAK,CAAA;AAEtC,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,yBAAe,CAAA;AAE/C,eAAO,MAAM,aAAa,+BAAsB,CAAA;AAEhD;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAGzC;AAED,oFAAoF;AACpF,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAU1E;AAeD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAiBnD"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell/output helpers extracted from harness/driver.ts: `!` command budget
|
|
3
|
+
* constants, git-branch probing, default `/export-md` path stamping, and
|
|
4
|
+
* bash-output row assembly. Node builtins only — no store or harness imports.
|
|
5
|
+
* @module @dsh-cc/tui/harness/shell-output
|
|
6
|
+
*/
|
|
7
|
+
import { execFile } from 'node:child_process';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { promisify } from 'node:util';
|
|
11
|
+
/** Wall-clock lifetime of a `!` shell command. */
|
|
12
|
+
export const BASH_TIMEOUT_MS = 120_000;
|
|
13
|
+
/** Foreground stdout byte budget handed to the shell executor for a `!` run. */
|
|
14
|
+
export const BASH_STDOUT_MAX_BYTES = 64_000;
|
|
15
|
+
/** Lines of command output shown under the `$ cmd` echo row (rest is elided). */
|
|
16
|
+
export const BASH_OUTPUT_LINE_CAP = 20;
|
|
17
|
+
/** Notice parked above the composer while a `!` command runs. */
|
|
18
|
+
export const BASH_RUNNING_NOTICE = '⠋ running…';
|
|
19
|
+
export const execFileAsync = promisify(execFile);
|
|
20
|
+
/**
|
|
21
|
+
* Default `/export-md` output directory: `$DSH_HOME/tui/exports` (or
|
|
22
|
+
* `~/.dsh/tui/exports`), mirroring the `resume-target` data-dir
|
|
23
|
+
* resolution one level deeper.
|
|
24
|
+
*/
|
|
25
|
+
export function defaultExportDir() {
|
|
26
|
+
const dshHome = process.env.DSH_HOME ?? join(homedir(), '.dsh');
|
|
27
|
+
return join(dshHome, 'tui', 'exports');
|
|
28
|
+
}
|
|
29
|
+
/** Filesystem-safe timestamp for default export filenames (ISO, `:`/`.` dashed). */
|
|
30
|
+
export function exportStamp() {
|
|
31
|
+
return new Date().toISOString().replace(/[:.]/g, '-');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Best-effort git branch probe: `git -C <cwd> rev-parse --abbrev-ref HEAD`
|
|
35
|
+
* with a short timeout. Never throws — errors (no git, no repo, detached
|
|
36
|
+
* head) resolve to undefined and the statusline simply omits the segment.
|
|
37
|
+
*/
|
|
38
|
+
export async function gitBranchOf(cwd) {
|
|
39
|
+
try {
|
|
40
|
+
const { stdout } = await execFileAsync('git', ['-C', cwd, 'rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
41
|
+
timeout: 2000,
|
|
42
|
+
});
|
|
43
|
+
const branch = stdout.trim();
|
|
44
|
+
return branch.length > 0 ? branch : undefined;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Cap combined command output at {@link BASH_OUTPUT_LINE_CAP} lines. Leading
|
|
52
|
+
* and trailing blank edges (from an empty stream or a trailing newline) are
|
|
53
|
+
* trimmed; interior blank lines are preserved.
|
|
54
|
+
*/
|
|
55
|
+
function capShellOutput(text) {
|
|
56
|
+
const lines = text.replace(/^\n+/, '').replace(/\n+$/, '').split('\n');
|
|
57
|
+
if (lines.length === 1 && lines[0] === '')
|
|
58
|
+
return '';
|
|
59
|
+
if (lines.length <= BASH_OUTPUT_LINE_CAP)
|
|
60
|
+
return lines.join('\n');
|
|
61
|
+
const hidden = lines.length - BASH_OUTPUT_LINE_CAP;
|
|
62
|
+
return `${lines.slice(0, BASH_OUTPUT_LINE_CAP).join('\n')}\n… +${hidden} more line${hidden === 1 ? '' : 's'}`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Assemble the bash-command output row: combined stdout/stderr (line-capped)
|
|
66
|
+
* plus a failure trailer. The row is error-marked for a non-zero exit, a
|
|
67
|
+
* signal death, or an executor timeout.
|
|
68
|
+
*/
|
|
69
|
+
export function shellOutputRow(stdout, stderr, outcome) {
|
|
70
|
+
const parts = [];
|
|
71
|
+
const capped = capShellOutput(`${stdout}\n${stderr}`);
|
|
72
|
+
if (capped.length > 0)
|
|
73
|
+
parts.push(capped);
|
|
74
|
+
if (outcome.timedOut) {
|
|
75
|
+
parts.push(`timed out after ${BASH_TIMEOUT_MS / 1000}s`);
|
|
76
|
+
}
|
|
77
|
+
else if (outcome.exitCode === null) {
|
|
78
|
+
parts.push('killed by a signal');
|
|
79
|
+
}
|
|
80
|
+
else if (outcome.exitCode !== 0) {
|
|
81
|
+
parts.push(`exit code ${outcome.exitCode}`);
|
|
82
|
+
}
|
|
83
|
+
const failed = outcome.timedOut || outcome.exitCode === null || outcome.exitCode !== 0;
|
|
84
|
+
return {
|
|
85
|
+
kind: 'status',
|
|
86
|
+
text: parts.join('\n'),
|
|
87
|
+
...(failed ? { error: true } : {}),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=shell-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-output.js","sourceRoot":"","sources":["../../src/harness/shell-output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CC-shape plaintext JSONL transcript mirror (statusline Slice C): a per-session
|
|
3
|
+
* mirror of the harness session events translated into the line shape
|
|
4
|
+
* ccstatusline reads (`message.usage` with the four token fields, ISO
|
|
5
|
+
* `timestamp`, `type` of 'assistant'/'user'). The statusline payload advertises
|
|
6
|
+
* the mirror as `transcript_path` ONLY while it is `ready` — a readable-but-
|
|
7
|
+
* empty file would make ccstatusline's fail-soft produce an all-zeros metrics
|
|
8
|
+
* object, and those zeros shadow truthful stdin fallbacks (`??` passes zeros
|
|
9
|
+
* through), so a mirror with no assistant usage is never created. Writes are
|
|
10
|
+
* atomic per rebuild (tmp file + rename; multi-TUI last-writer-wins yields
|
|
11
|
+
* complete files) and append-only per live event under a seq watermark. Any fs
|
|
12
|
+
* error permanently disables the mirror: appends run on the synchronous
|
|
13
|
+
* session-append hot path, so no retries, and later appends to a corrupt
|
|
14
|
+
* stream are worse than silence. This module never imports harness types —
|
|
15
|
+
* events are consumed structurally, matching the sibling modules' convention.
|
|
16
|
+
* @module @dsh-cc/tui/harness/statusline-cc-transcript
|
|
17
|
+
*/
|
|
18
|
+
/** Structural view of a harness session event ({type, data, seq, time}). */
|
|
19
|
+
export type CcSessionEventLike = {
|
|
20
|
+
type?: unknown;
|
|
21
|
+
data?: unknown;
|
|
22
|
+
seq?: unknown;
|
|
23
|
+
time?: unknown;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Translate harness session events into CC transcript lines. Only
|
|
27
|
+
* `assistant/message` events with finite input/output usage and a finite time
|
|
28
|
+
* produce assistant lines (with EXPLICIT cache zeros when the source omits the
|
|
29
|
+
* cache fields — the token-meter projection also normalizes them to 0, keeping
|
|
30
|
+
* mirror totals ≡ projection totals); `user/message` events with a finite time
|
|
31
|
+
* produce speed-anchor lines. Everything else is dropped. `stop_reason` is
|
|
32
|
+
* NEVER emitted: if ccstatusline ever sees an own-property `stop_reason` on a
|
|
33
|
+
* message its accumulator switches semantics, so the key is banned outright.
|
|
34
|
+
*/
|
|
35
|
+
export declare function translateEventsToCcTranscript(events: readonly unknown[], sessionId: string): string[];
|
|
36
|
+
/** The mirror state the wiring consults. */
|
|
37
|
+
export type CcTranscriptMirror = {
|
|
38
|
+
/** Whether the mirror currently has a written, non-empty file. */
|
|
39
|
+
isReady(): boolean;
|
|
40
|
+
/** The mirror file path when ready, else undefined. */
|
|
41
|
+
getPath(): string | undefined;
|
|
42
|
+
/** Full rebuild from the session's event log (atomic rename, GC sweep). */
|
|
43
|
+
rebind(sessionId: string, events: readonly unknown[]): void;
|
|
44
|
+
/** Best-effort live append of one event; no-op while not ready. */
|
|
45
|
+
append(event: unknown): void;
|
|
46
|
+
};
|
|
47
|
+
/** Create a CC transcript mirror rooted under `dir` (default the tui dir). */
|
|
48
|
+
export declare function createCcTranscriptMirror(options?: {
|
|
49
|
+
dir?: string;
|
|
50
|
+
}): CcTranscriptMirror;
|
|
51
|
+
//# sourceMappingURL=statusline-cc-transcript.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statusline-cc-transcript.d.ts","sourceRoot":"","sources":["../../src/harness/statusline-cc-transcript.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAkBH,4EAA4E;AAC5E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AA0BD;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,SAAS,EAAE,MAAM,GAChB,MAAM,EAAE,CAuCV;AAOD,4CAA4C;AAC5C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kEAAkE;IAClE,OAAO,IAAI,OAAO,CAAA;IAClB,uDAAuD;IACvD,OAAO,IAAI,MAAM,GAAG,SAAS,CAAA;IAC7B,2EAA2E;IAC3E,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CAAA;IAC3D,mEAAmE;IACnE,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;CAC7B,CAAA;AAED,8EAA8E;AAC9E,wBAAgB,wBAAwB,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,kBAAkB,CA8E3F"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CC-shape plaintext JSONL transcript mirror (statusline Slice C): a per-session
|
|
3
|
+
* mirror of the harness session events translated into the line shape
|
|
4
|
+
* ccstatusline reads (`message.usage` with the four token fields, ISO
|
|
5
|
+
* `timestamp`, `type` of 'assistant'/'user'). The statusline payload advertises
|
|
6
|
+
* the mirror as `transcript_path` ONLY while it is `ready` — a readable-but-
|
|
7
|
+
* empty file would make ccstatusline's fail-soft produce an all-zeros metrics
|
|
8
|
+
* object, and those zeros shadow truthful stdin fallbacks (`??` passes zeros
|
|
9
|
+
* through), so a mirror with no assistant usage is never created. Writes are
|
|
10
|
+
* atomic per rebuild (tmp file + rename; multi-TUI last-writer-wins yields
|
|
11
|
+
* complete files) and append-only per live event under a seq watermark. Any fs
|
|
12
|
+
* error permanently disables the mirror: appends run on the synchronous
|
|
13
|
+
* session-append hot path, so no retries, and later appends to a corrupt
|
|
14
|
+
* stream are worse than silence. This module never imports harness types —
|
|
15
|
+
* events are consumed structurally, matching the sibling modules' convention.
|
|
16
|
+
* @module @dsh-cc/tui/harness/statusline-cc-transcript
|
|
17
|
+
*/
|
|
18
|
+
import { appendFileSync, mkdirSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
19
|
+
import { randomBytes } from 'node:crypto';
|
|
20
|
+
import { join } from 'node:path';
|
|
21
|
+
import { defaultTuiDir } from "../history.js";
|
|
22
|
+
/** Maximum age (ms) a mirrored file survives the GC sweep. */
|
|
23
|
+
const GC_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;
|
|
24
|
+
/** Whether a value is a finite number. */
|
|
25
|
+
function isFiniteNumber(value) {
|
|
26
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
27
|
+
}
|
|
28
|
+
/** Structural read of a usage record; all four fields normalize to 0. */
|
|
29
|
+
function usageOf(data) {
|
|
30
|
+
if (typeof data !== 'object' || data === null)
|
|
31
|
+
return undefined;
|
|
32
|
+
const usage = data.usage;
|
|
33
|
+
if (typeof usage !== 'object' || usage === null)
|
|
34
|
+
return undefined;
|
|
35
|
+
const u = usage;
|
|
36
|
+
return {
|
|
37
|
+
inputTokens: u.inputTokens,
|
|
38
|
+
outputTokens: u.outputTokens,
|
|
39
|
+
cacheReadTokens: u.cacheReadTokens,
|
|
40
|
+
cacheWriteTokens: u.cacheWriteTokens,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Translate harness session events into CC transcript lines. Only
|
|
45
|
+
* `assistant/message` events with finite input/output usage and a finite time
|
|
46
|
+
* produce assistant lines (with EXPLICIT cache zeros when the source omits the
|
|
47
|
+
* cache fields — the token-meter projection also normalizes them to 0, keeping
|
|
48
|
+
* mirror totals ≡ projection totals); `user/message` events with a finite time
|
|
49
|
+
* produce speed-anchor lines. Everything else is dropped. `stop_reason` is
|
|
50
|
+
* NEVER emitted: if ccstatusline ever sees an own-property `stop_reason` on a
|
|
51
|
+
* message its accumulator switches semantics, so the key is banned outright.
|
|
52
|
+
*/
|
|
53
|
+
export function translateEventsToCcTranscript(events, sessionId) {
|
|
54
|
+
const lines = [];
|
|
55
|
+
for (const raw of events) {
|
|
56
|
+
if (typeof raw !== 'object' || raw === null)
|
|
57
|
+
continue;
|
|
58
|
+
const event = raw;
|
|
59
|
+
const { type, data, time } = event;
|
|
60
|
+
if (!isFiniteNumber(time))
|
|
61
|
+
continue;
|
|
62
|
+
const timestamp = new Date(time).toISOString();
|
|
63
|
+
if (type === 'assistant/message') {
|
|
64
|
+
const usage = usageOf(data);
|
|
65
|
+
if (usage === undefined)
|
|
66
|
+
continue;
|
|
67
|
+
if (!isFiniteNumber(usage.inputTokens) || !isFiniteNumber(usage.outputTokens))
|
|
68
|
+
continue;
|
|
69
|
+
lines.push(JSON.stringify({
|
|
70
|
+
type: 'assistant',
|
|
71
|
+
timestamp,
|
|
72
|
+
isSidechain: false,
|
|
73
|
+
sessionId,
|
|
74
|
+
message: {
|
|
75
|
+
usage: {
|
|
76
|
+
input_tokens: usage.inputTokens,
|
|
77
|
+
output_tokens: usage.outputTokens,
|
|
78
|
+
// Explicit zeros for absent cache fields are intentional: the
|
|
79
|
+
// token-meter normalizes them to 0 too, keeping the mirror totals
|
|
80
|
+
// identical to the projection totals the payload carries.
|
|
81
|
+
cache_creation_input_tokens: isFiniteNumber(usage.cacheWriteTokens) ? usage.cacheWriteTokens : 0,
|
|
82
|
+
cache_read_input_tokens: isFiniteNumber(usage.cacheReadTokens) ? usage.cacheReadTokens : 0,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
else if (type === 'user/message') {
|
|
88
|
+
lines.push(JSON.stringify({
|
|
89
|
+
type: 'user',
|
|
90
|
+
timestamp,
|
|
91
|
+
isSidechain: false,
|
|
92
|
+
sessionId,
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return lines;
|
|
97
|
+
}
|
|
98
|
+
/** The sanitized file name stem for a session id. */
|
|
99
|
+
function sanitizeSessionId(sessionId) {
|
|
100
|
+
return sessionId.replace(/[^A-Za-z0-9._-]/g, '_');
|
|
101
|
+
}
|
|
102
|
+
/** Create a CC transcript mirror rooted under `dir` (default the tui dir). */
|
|
103
|
+
export function createCcTranscriptMirror(options = {}) {
|
|
104
|
+
const dir = options.dir ?? defaultTuiDir();
|
|
105
|
+
let ready = false;
|
|
106
|
+
let path;
|
|
107
|
+
let watermark = 0;
|
|
108
|
+
let sessionId = '';
|
|
109
|
+
let dead = false;
|
|
110
|
+
/** Permanently disable the mirror after any fs failure (no retries). */
|
|
111
|
+
function fail() {
|
|
112
|
+
dead = true;
|
|
113
|
+
ready = false;
|
|
114
|
+
path = undefined;
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
isReady() {
|
|
118
|
+
return ready;
|
|
119
|
+
},
|
|
120
|
+
getPath() {
|
|
121
|
+
return path;
|
|
122
|
+
},
|
|
123
|
+
rebind(nextSessionId, events) {
|
|
124
|
+
if (dead)
|
|
125
|
+
return;
|
|
126
|
+
sessionId = nextSessionId;
|
|
127
|
+
watermark = 0;
|
|
128
|
+
const lines = translateEventsToCcTranscript(events, sessionId);
|
|
129
|
+
for (const raw of events) {
|
|
130
|
+
const seq = raw?.seq;
|
|
131
|
+
if (isFiniteNumber(seq) && seq > watermark)
|
|
132
|
+
watermark = seq;
|
|
133
|
+
}
|
|
134
|
+
// A mirror with zero assistant-usage lines would render as an all-zeros
|
|
135
|
+
// metrics object in ccstatusline and shadow truthful stdin values, so
|
|
136
|
+
// nothing is written and the payload stays without a transcript_path.
|
|
137
|
+
if (lines.every((line) => !line.includes('"type":"assistant"'))) {
|
|
138
|
+
ready = false;
|
|
139
|
+
path = undefined;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const ccDir = join(dir, 'cc-transcripts');
|
|
144
|
+
mkdirSync(ccDir, { recursive: true });
|
|
145
|
+
// GC sweep: drop mirrored files older than 30 days (best-effort).
|
|
146
|
+
try {
|
|
147
|
+
for (const name of readdirSync(ccDir)) {
|
|
148
|
+
if (!name.endsWith('.jsonl'))
|
|
149
|
+
continue;
|
|
150
|
+
const filePath = join(ccDir, name);
|
|
151
|
+
try {
|
|
152
|
+
if (Date.now() - statSync(filePath).mtimeMs > GC_MAX_AGE_MS)
|
|
153
|
+
unlinkSync(filePath);
|
|
154
|
+
}
|
|
155
|
+
catch { /* per-entry errors are ignored */ }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch { /* sweep failures never break the rebind */ }
|
|
159
|
+
const finalPath = join(ccDir, `${sanitizeSessionId(sessionId)}.jsonl`);
|
|
160
|
+
const tmpPath = `${finalPath}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
|
|
161
|
+
writeFileSync(tmpPath, lines.map((line) => `${line}\n`).join(''));
|
|
162
|
+
renameSync(tmpPath, finalPath);
|
|
163
|
+
ready = true;
|
|
164
|
+
path = finalPath;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
fail();
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
append(event) {
|
|
171
|
+
if (!ready || path === undefined)
|
|
172
|
+
return;
|
|
173
|
+
if (typeof event !== 'object' || event === null)
|
|
174
|
+
return;
|
|
175
|
+
const seq = event.seq;
|
|
176
|
+
if (!isFiniteNumber(seq) || seq <= watermark)
|
|
177
|
+
return;
|
|
178
|
+
watermark = seq;
|
|
179
|
+
const lines = translateEventsToCcTranscript([event], sessionId);
|
|
180
|
+
if (lines.length === 0)
|
|
181
|
+
return;
|
|
182
|
+
try {
|
|
183
|
+
appendFileSync(path, lines.map((line) => `${line}\n`).join(''));
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
fail();
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=statusline-cc-transcript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statusline-cc-transcript.js","sourceRoot":"","sources":["../../src/harness/statusline-cc-transcript.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status-line command runner: 300 ms-debounced execution of the configured
|
|
3
|
+
* command with the CC-shaped JSON payload on stdin. Kill-in-flight on every
|
|
4
|
+
* new trigger, generation-guarded settles (a superseded run's late result is
|
|
5
|
+
* discarded), update({ immediate: true }) bypass for settings-driven command
|
|
6
|
+
* changes, blank-on-failure (non-zero exit, killed, timeout, overrun, spawn
|
|
7
|
+
* throw, empty stdout), COLUMNS/LINES from the terminal-size getter at spawn
|
|
8
|
+
* time, a 60 s hard cap with a 64 KiB stdout cap, and a dispose that aborts,
|
|
9
|
+
* clears, and quiets.
|
|
10
|
+
* @module @dsh-cc/tui/harness/statusline-command
|
|
11
|
+
*/
|
|
12
|
+
import type { ShellExecutorLike } from '../state/driver-types.ts';
|
|
13
|
+
/** Injectable collaborators of the status-line runner. */
|
|
14
|
+
export type StatusLineCommandDeps = {
|
|
15
|
+
/** The deployment's shell executor (resolve→run seam). */
|
|
16
|
+
executor: ShellExecutorLike;
|
|
17
|
+
/** Current terminal dimensions, read at spawn time for COLUMNS/LINES. */
|
|
18
|
+
terminalSize: () => {
|
|
19
|
+
columns: number;
|
|
20
|
+
rows: number;
|
|
21
|
+
};
|
|
22
|
+
/** Notified after every generation that lands (success or blank). */
|
|
23
|
+
onSettled: (line: string) => void;
|
|
24
|
+
/** Debounce delay in ms (default 300); overridable for tests. */
|
|
25
|
+
debounceMs?: number;
|
|
26
|
+
/** Hard per-run cap in ms (default 60_000). */
|
|
27
|
+
timeoutMs?: number;
|
|
28
|
+
/** Stdout cap in bytes (default 64 KiB). */
|
|
29
|
+
stdoutMaxBytes?: number;
|
|
30
|
+
};
|
|
31
|
+
/** Options of {@link StatusLineCommand.update}. */
|
|
32
|
+
export type StatusLineUpdateOptions = {
|
|
33
|
+
/** Skip the debounce (settings-driven `command` changes). */
|
|
34
|
+
immediate?: boolean;
|
|
35
|
+
/** Working directory for the child (defaults to the driver cwd). */
|
|
36
|
+
workdir?: string;
|
|
37
|
+
};
|
|
38
|
+
/** Handle of the running status-line command. */
|
|
39
|
+
export type StatusLineCommand = {
|
|
40
|
+
/** Trigger a (debounced by default) run with a fresh payload. */
|
|
41
|
+
update(config: {
|
|
42
|
+
command: string;
|
|
43
|
+
}, payload: unknown, options?: StatusLineUpdateOptions): void;
|
|
44
|
+
/** The last settled rows (0–3, '\n'-joined; empty string until a run succeeds). */
|
|
45
|
+
latest(): string;
|
|
46
|
+
/** Abort in-flight, clear all timers, and make later settles no-ops. */
|
|
47
|
+
dispose(): void;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Create the status-line command runner. Pure with respect to the injected
|
|
51
|
+
* executor; owns exactly one debounce timer and one hard-cap timer at a time.
|
|
52
|
+
*/
|
|
53
|
+
export declare function createStatusLineCommand(deps: StatusLineCommandDeps): StatusLineCommand;
|
|
54
|
+
//# sourceMappingURL=statusline-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statusline-command.d.ts","sourceRoot":"","sources":["../../src/harness/statusline-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAsB,MAAM,0BAA0B,CAAA;AAErF,0DAA0D;AAC1D,MAAM,MAAM,qBAAqB,GAAG;IAClC,0DAA0D;IAC1D,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,yEAAyE;IACzE,YAAY,EAAE,MAAM;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACrD,qEAAqE;IACrE,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAAG;IACpC,6DAA6D;IAC7D,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,iDAAiD;AACjD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iEAAiE;IACjE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAA;IAC9F,mFAAmF;IACnF,MAAM,IAAI,MAAM,CAAA;IAChB,wEAAwE;IACxE,OAAO,IAAI,IAAI,CAAA;CAChB,CAAA;AAWD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,GAAG,iBAAiB,CAsItF"}
|