@north-light/crouter 0.3.196 → 0.3.198
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +2 -2
- package/dist/api/dto/inbox.d.ts +46 -0
- package/dist/builtin-memory/00-runtime-base.md +3 -3
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-memory/internal/storage-tiers.md +1 -1
- package/dist/builtin-memory/wedged-child-on-runaway-bash.md +1 -1
- package/dist/clients/attach/render/chat-view.d.ts +3 -8
- package/dist/clients/attach/render/chat-view.js +3 -24
- package/dist/clients/attach/render/markdown-source.js +0 -6
- package/dist/clients/attach/render/tool-calls.js +16 -2
- package/dist/clients/attach/viewer.js +613 -602
- package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +2 -2
- package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +11 -4
- package/dist/clients/inbox/controller.js +4 -4
- package/dist/clients/inbox/page-adapter.d.ts +2 -1
- package/dist/clients/inbox/tui/render.js +46 -25
- package/dist/clients/inbox/tui/slots.d.ts +1 -3
- package/dist/clients/inbox/tui/slots.js +8 -37
- package/dist/clients/inbox/tui/types.d.ts +4 -3
- package/dist/commands/__tests__/human.test.js +160 -23
- package/dist/commands/canvas-browse.js +1 -1
- package/dist/commands/human/doc.js +21 -74
- package/dist/commands/human/html.d.ts +2 -0
- package/dist/commands/human/html.js +81 -0
- package/dist/commands/human/prompts.d.ts +5 -4
- package/dist/commands/human/prompts.js +90 -168
- package/dist/commands/human/shared.d.ts +5 -6
- package/dist/commands/human/shared.js +13 -61
- package/dist/commands/human.js +7 -2
- package/dist/core/__tests__/daemon-boot.test.js +7 -4
- package/dist/core/__tests__/dead-node-policy-table.test.js +20 -36
- package/dist/core/__tests__/human-deliver.test.js +28 -37
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +13 -11
- package/dist/core/__tests__/seam/dormancy-release.test.js +63 -4
- package/dist/core/__tests__/serial/human-deliver-e2e.test.js +3 -13
- package/dist/core/canvas/__tests__/attention.test.js +2 -2
- package/dist/core/canvas/__tests__/render-remote.test.js +2 -2
- package/dist/core/canvas/browse/app.d.ts +1 -1
- package/dist/core/canvas/browse/app.js +21 -3
- package/dist/core/canvas/browse/render.d.ts +4 -0
- package/dist/core/canvas/browse/render.js +5 -1
- package/dist/core/canvas/canvas.d.ts +26 -0
- package/dist/core/canvas/canvas.js +55 -0
- package/dist/core/command.js +6 -11
- package/dist/core/config.js +3 -2
- package/dist/core/help.d.ts +3 -0
- package/dist/core/human/__tests__/html-markdown.test.d.ts +1 -0
- package/dist/core/human/__tests__/html-markdown.test.js +52 -0
- package/dist/core/human/__tests__/page-catalog.test.d.ts +1 -0
- package/dist/core/human/__tests__/page-catalog.test.js +16 -0
- package/dist/core/human/__tests__/page-render.test.js +40 -23
- package/dist/core/human/__tests__/page-tickets.test.js +48 -27
- package/dist/core/human/__tests__/page.test.js +48 -65
- package/dist/core/human/__tests__/serial/inbox-core.test.js +5 -15
- package/dist/core/human/answer-text.d.ts +3 -0
- package/dist/core/human/answer-text.js +98 -0
- package/dist/core/human/answer.d.ts +51 -0
- package/dist/core/human/answer.js +125 -0
- package/dist/core/human/component-docs.d.ts +14 -0
- package/dist/core/human/component-docs.js +161 -0
- package/dist/core/human/html-markdown.d.ts +3 -0
- package/dist/core/human/html-markdown.js +288 -0
- package/dist/core/human/page-catalog.d.ts +19 -3
- package/dist/core/human/page-catalog.js +73 -16
- package/dist/core/human/page-render.d.ts +3 -2
- package/dist/core/human/page-render.js +19 -45
- package/dist/core/human/page-schema.d.ts +108 -8
- package/dist/core/human/page-schema.js +88 -31
- package/dist/core/human/page-synth.d.ts +2 -4
- package/dist/core/human/page-synth.js +23 -7
- package/dist/core/human/page.d.ts +14 -7
- package/dist/core/human/page.js +178 -90
- package/dist/core/human/review-schema.d.ts +1 -0
- package/dist/core/human/review-schema.js +1 -1
- package/dist/core/human/scan.d.ts +3 -2
- package/dist/core/human/scan.js +7 -8
- package/dist/core/human/summary.d.ts +4 -7
- package/dist/core/human/summary.js +4 -60
- package/dist/core/human/tickets.d.ts +10 -9
- package/dist/core/human/tickets.js +5 -3
- package/dist/core/human/types.d.ts +4 -0
- package/dist/core/keybindings/catalog.d.ts +2 -2
- package/dist/core/keybindings/catalog.js +1 -0
- package/dist/core/review/realize.js +9 -1
- package/dist/core/runtime/boot-root.js +6 -1
- package/dist/core/runtime/broker.js +8 -6
- package/dist/core/runtime/busy.d.ts +4 -3
- package/dist/core/runtime/busy.js +4 -3
- package/dist/core/runtime/spawn.js +4 -4
- package/dist/core/termrender/display.d.ts +7 -3
- package/dist/core/termrender/display.js +45 -9
- package/dist/core/termrender/termrender.d.ts +3 -12
- package/dist/core/termrender/termrender.js +6 -37
- package/dist/core/user-settings.d.ts +17 -2
- package/dist/core/user-settings.js +32 -11
- package/dist/daemon/api/handlers/human.js +1 -1
- package/dist/daemon/api/handlers/inbox.js +22 -7
- package/dist/daemon/cron-run.js +16 -2
- package/dist/daemon/crtrd.js +1 -1
- package/dist/daemon/fleet.d.ts +22 -10
- package/dist/daemon/fleet.js +43 -24
- package/dist/daemon/human/finish.d.ts +2 -1
- package/dist/daemon/human/finish.js +45 -28
- package/dist/daemon/human/sweep.js +4 -2
- package/dist/daemon/reconcilers/broker-supervision.js +11 -8
- package/dist/daemon/reconcilers/dormant-inbox.js +11 -6
- package/dist/daemon/reconcilers/live-obligation.d.ts +21 -1
- package/dist/daemon/reconcilers/live-obligation.js +30 -2
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -0
- package/dist/daemon/reconcilers/storage-maintenance.js +28 -1
- package/dist/daemon/review/sweep.js +12 -1
- package/dist/pages/bundle.css +1 -1
- package/dist/pages/bundle.js +1008 -577
- package/dist/pages/comments.d.ts +29 -0
- package/dist/pages/comments.js +51 -0
- package/dist/pages/controls.d.ts +98 -0
- package/dist/pages/controls.js +261 -0
- package/dist/pages/elements/cards.d.ts +15 -4
- package/dist/pages/elements/cards.js +299 -186
- package/dist/pages/elements/chart.d.ts +22 -0
- package/dist/pages/elements/chart.js +107 -91
- package/dist/pages/elements/options.d.ts +9 -0
- package/dist/pages/elements/options.js +268 -155
- package/dist/pages/elements/pages.d.ts +6 -0
- package/dist/pages/elements/pages.js +60 -38
- package/dist/pages/elements/slot.d.ts +5 -0
- package/dist/pages/elements/slot.js +17 -10
- package/dist/pages/elements/table.d.ts +17 -0
- package/dist/pages/elements/table.js +336 -228
- package/dist/pages/elements/text.d.ts +9 -3
- package/dist/pages/elements/text.js +350 -143
- package/dist/pages/host.d.ts +0 -24
- package/dist/pages/host.js +0 -17
- package/dist/pages/readonly.d.ts +24 -0
- package/dist/pages/readonly.js +31 -0
- package/dist/pages/responses.d.ts +37 -0
- package/dist/pages/responses.js +56 -0
- package/dist/pi-extensions/canvas-bash-valve.d.ts +9 -1
- package/dist/pi-extensions/canvas-bash-valve.js +12 -8
- package/dist/types.d.ts +19 -5
- package/dist/types.js +2 -1
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
- package/scripts/install-runtime.mjs +19 -24
- package/dist/clients/attach/render/html-markdown.d.ts +0 -13
- package/dist/clients/attach/render/html-markdown.js +0 -206
- package/dist/core/human/markdown-html.d.ts +0 -8
- package/dist/core/human/markdown-html.js +0 -581
package/dist/api/client.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ import type { CredentialRemovalResultDTO, CredentialResultDTO, InstallCredential
|
|
|
16
16
|
import type { CreateHumanBridgeRequest, HumanBridgeResultDTO, HumanCancelRequest, HumanCancelResultDTO, HumanResolveRequest, HumanResolveResultDTO } from './dto/human.js';
|
|
17
17
|
import type { CancelReviewRequest, CreateReviewRequest, ListReviewsQuery, ReviewCancelResultDTO, ReviewDocumentBaseDTO, ReviewDTO, ReviewListDTO, ReviewSubmitResultDTO } from './dto/reviews.js';
|
|
18
18
|
import type { CreateReviewCommentRequest, EditReviewCommentRequest, ListReviewCommentsQuery, ReadReviewCommentEventsQuery, ReviewCommentActionRequest, ReviewCommentDetailDTO, ReviewCommentEventsDTO, ReviewCommentListDTO, ReviewCommentMutationDTO, ReviewCommentRangeBatchRequest, ReviewCommentRangeBatchResultDTO } from './dto/review-comments.js';
|
|
19
|
-
import type { CancelInboxTicketRequest, CanceledTicketResultDTO, InboxListDTO, InboxPageDTO, InboxPageHistoryDTO, InboxPageRenderDTO, PagesBundleAssetDTO, InboxTicketIdDTO, PageResponsesDTO, PageTicketResultDTO, RespondInboxPageRequest } from './dto/inbox.js';
|
|
19
|
+
import type { CancelInboxTicketRequest, CanceledTicketResultDTO, InboxListDTO, InboxPageDTO, InboxPageHistoryDTO, InboxPageRenderDTO, PagesBundleAssetDTO, InboxPageResponseDTO, InboxTicketIdDTO, PageResponsesDTO, PageTicketResultDTO, RespondInboxPageRequest } from './dto/inbox.js';
|
|
20
20
|
import type { AttentionCountsDTO, AttentionDTO, DashboardDTO, DashboardQuery, HistoryGrepQuery, HistoryGrepResultDTO, HistoryReadQuery, HistoryReadResultDTO, HistorySearchQuery, HistorySearchResultDTO, PruneRequest, PruneResultDTO, RebuildIndexResultDTO, RosterDTO, SnapshotDTO } from './dto/canvas.js';
|
|
21
21
|
import type { CloseWorktreeResultDTO } from './dto/worktree.js';
|
|
22
22
|
import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerInboxCursorDirective, BrokerInboxCursorRequest, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerPersonaAckRequest, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest } from './dto/broker-ops.js';
|
|
@@ -204,7 +204,7 @@ export declare class CrtrClient {
|
|
|
204
204
|
/** Autosave partial page work. Omitted slots are permitted in progress updates. */
|
|
205
205
|
postInboxProgress(ticketId: InboxTicketIdDTO, responses: PageResponsesDTO): Promise<void>;
|
|
206
206
|
/** Get the published response for a resolved page ticket. 404 if pending or canceled. */
|
|
207
|
-
getInboxResponse(ticketId: InboxTicketIdDTO): Promise<
|
|
207
|
+
getInboxResponse(ticketId: InboxTicketIdDTO): Promise<InboxPageResponseDTO>;
|
|
208
208
|
/** The page's body-level HTML payload, for pending, resolved, and canceled
|
|
209
209
|
* tickets alike. The host wraps it and injects the page runtime bundle. */
|
|
210
210
|
renderHumanInboxPage(ticketId: InboxTicketIdDTO): Promise<InboxPageRenderDTO>;
|
package/dist/api/dto/inbox.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface TicketSourceDTO {
|
|
|
5
5
|
sessionName?: string;
|
|
6
6
|
askedBy?: string;
|
|
7
7
|
blockedSince?: IsoTime;
|
|
8
|
+
profileName?: string;
|
|
8
9
|
nodeId?: string;
|
|
9
10
|
}
|
|
10
11
|
export interface ReviewTicketSummaryDTO {
|
|
@@ -28,6 +29,8 @@ export interface PageTicketSummaryDTO {
|
|
|
28
29
|
slot_kinds: string[];
|
|
29
30
|
awaits_response: boolean;
|
|
30
31
|
state?: 'pending' | 'resolved' | 'canceled';
|
|
32
|
+
/** Present only on resolved history entries; the stored one-line answer digest. */
|
|
33
|
+
answer_digest?: string;
|
|
31
34
|
}
|
|
32
35
|
export type InboxTicketSummaryDTO = PageTicketSummaryDTO | ReviewTicketSummaryDTO;
|
|
33
36
|
export interface InboxListDTO {
|
|
@@ -39,6 +42,7 @@ export interface PageSlotDTO {
|
|
|
39
42
|
step: number;
|
|
40
43
|
config: Record<string, unknown>;
|
|
41
44
|
unvalidated?: true;
|
|
45
|
+
display?: true;
|
|
42
46
|
}
|
|
43
47
|
/** The nested protocol object is deliberately camelCase on the wire. */
|
|
44
48
|
export interface PageManifestDTO {
|
|
@@ -131,6 +135,48 @@ export interface PageTicketResultDTO {
|
|
|
131
135
|
summary: string;
|
|
132
136
|
completedAt: IsoTime;
|
|
133
137
|
}
|
|
138
|
+
export interface PageAnswerGroupDTO {
|
|
139
|
+
group: 'option' | 'card' | 'row' | 'column';
|
|
140
|
+
mode: 'single' | 'multi';
|
|
141
|
+
total: number;
|
|
142
|
+
picked: {
|
|
143
|
+
id: string;
|
|
144
|
+
label: string;
|
|
145
|
+
}[];
|
|
146
|
+
}
|
|
147
|
+
export interface PageAnswerCommentDTO {
|
|
148
|
+
anchor: PageCommentAnchorDTO;
|
|
149
|
+
anchorLabel: string;
|
|
150
|
+
text: string;
|
|
151
|
+
}
|
|
152
|
+
export interface PageAnswerSlotDTO {
|
|
153
|
+
id: string;
|
|
154
|
+
kind: string;
|
|
155
|
+
label?: string;
|
|
156
|
+
state: 'answered' | 'unanswered';
|
|
157
|
+
blank: boolean;
|
|
158
|
+
groups: PageAnswerGroupDTO[];
|
|
159
|
+
freetext?: string;
|
|
160
|
+
text?: {
|
|
161
|
+
value: string;
|
|
162
|
+
edited: boolean;
|
|
163
|
+
singleLine?: boolean;
|
|
164
|
+
};
|
|
165
|
+
comments: PageAnswerCommentDTO[];
|
|
166
|
+
raw?: Record<string, unknown>;
|
|
167
|
+
}
|
|
168
|
+
/** The camelCase protocol object shipped only by GET .../response. */
|
|
169
|
+
export interface PageAnswerDTO {
|
|
170
|
+
title: string;
|
|
171
|
+
subtitle?: string;
|
|
172
|
+
completedAt: IsoTime;
|
|
173
|
+
kind: 'answer' | 'acknowledgement';
|
|
174
|
+
digest: string;
|
|
175
|
+
slots: PageAnswerSlotDTO[];
|
|
176
|
+
}
|
|
177
|
+
export interface InboxPageResponseDTO extends PageTicketResultDTO {
|
|
178
|
+
answer: PageAnswerDTO;
|
|
179
|
+
}
|
|
134
180
|
/** `POST /v1/human/inbox/:ticket_id/cancel` body. */
|
|
135
181
|
export interface CancelInboxTicketRequest {
|
|
136
182
|
reason?: string;
|
|
@@ -10,7 +10,7 @@ rationale: >-
|
|
|
10
10
|
|
|
11
11
|
"Waiting is a way to end a turn" lived in its own ungated all-node doc until 2026-07-28. Same gate, same audience, never independently readable — so the split bought no routing and cost a stub cross-reference in this file pointing at a section spliced a few hundred tokens later. Split it back out only if it ever needs a gate of its own.
|
|
12
12
|
|
|
13
|
-
The
|
|
13
|
+
The Mermaid line exists because the viewer's inline diagram affordance is otherwise invisible to an agent working from ordinary Markdown defaults.
|
|
14
14
|
lint-ignore: length
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -41,8 +41,8 @@ Two different moves; don't conflate them. **Promote** when worthwhile independen
|
|
|
41
41
|
|
|
42
42
|
Never yield carrying an unasked question: put anything you're still wondering for the human through `crtr human ask` BEFORE you yield — an in-flight ask survives the refresh, and its answer wakes your fresh window like any child's report.
|
|
43
43
|
|
|
44
|
-
##
|
|
45
|
-
When visual structure
|
|
44
|
+
## Mermaid diagrams
|
|
45
|
+
When visual structure would land faster than prose, use a Mermaid fence; the human's terminal viewer renders it inline. Reach for it when the shape is the point, not for everything.
|
|
46
46
|
|
|
47
47
|
## Waiting is a way to end a turn
|
|
48
48
|
|
|
@@ -48,4 +48,4 @@ Tear-down: `node lifecycle close` cascade-cancels a node + its exclusive subtree
|
|
|
48
48
|
|
|
49
49
|
Use `node lifecycle revive <id>` to reopen one dormant or terminal node. It resumes an existing saved conversation by default; `--fresh` starts a new cycle on its existing session file, or a truly fresh session if no file exists. A finalized node requires `--reopen` before it can take a new mandate. Mass-reconnecting every eligible disconnected node after a reboot or outage is `canvas revive --all` instead. `reviveNode()` is the **only** sanctioned launcher of a node's broker engine — it builds the pi invocation, sets `CRTR_NODE_ID` + canvas extensions, runs `transition('revive')`, and starts the headless broker host, keeping the db row and broker process in lockstep. Never spawn `pi --session` raw, and never open a node by spawning pi directly — UIs go through `surface node focus` / `node lifecycle revive`.
|
|
50
50
|
|
|
51
|
-
The daemon (`crtrd`, managed via `sys daemon start/stop/status`) supervises live broker exits. It releases an unattended broker after 15 minutes: residents with no live obligation become `done` and pruning-eligible, while terminal nodes and residents awaiting a live child, controller, human, deadline, or structured output become `idle` and remain wakeable. It applies a bounded respawn policy to interrupted nonterminal nodes:
|
|
51
|
+
The daemon (`crtrd`, managed via `sys daemon start/stop/status`) supervises live broker exits. It releases an unattended broker after 15 minutes: residents with no live obligation become `done` and pruning-eligible, while terminal nodes and residents awaiting a live child, controller, human, deadline, or structured output become `idle` and remain wakeable. It applies a bounded respawn policy to interrupted nonterminal nodes: an interrupted saved turn resumes in the same conversation with a continuation, whether the broker persisted a clean abort or died abruptly. A pending refresh or pending cycle still starts a fresh cycle from the saved session. Repeated short-lived exits and boot failures terminalize the node as `dead`; no automatic recovery occurs after terminalization, so use an explicit lifecycle revive or an inbox wake. It does not host agents or open viewers. When activating source changes, build, run `npm run install-runtime`, then restart the daemon because new daemon/brokers select the atomically switched, immutable generation while live brokers retain their own. Restarting is safe: it never signals running nodes.
|
|
@@ -22,7 +22,7 @@ User-wide content with no cwd dimension also belongs here: `~/.crouter/profile-d
|
|
|
22
22
|
|
|
23
23
|
## 2. Canvas home — node-graph runtime state, node artifacts, and bounded diagnostics
|
|
24
24
|
|
|
25
|
-
`~/.crouter/canvas/` (overridable with `CRTR_HOME`) is the cwd-agnostic node-graph home. `canvas.db` is the SQLite WAL topology store for nodes and edges, including durable tmux-pane focus. `nodes/<node_id>/` owns `meta.json`, `context/`, `reports/`, `messages/`, `inbox.jsonl`, `transcript.jsonl`, `session.ptr`, and `job/` state. Human ticket files (`page.json`, `page.
|
|
25
|
+
`~/.crouter/canvas/` (overridable with `CRTR_HOME`) is the cwd-agnostic node-graph home. `canvas.db` is the SQLite WAL topology store for nodes and edges, including durable tmux-pane focus. `nodes/<node_id>/` owns `meta.json`, `context/`, `reports/`, `messages/`, `inbox.jsonl`, `transcript.jsonl`, `session.ptr`, and `job/` state. Human ticket files (`page.json`, `page.html`, `run.json`, `response.json`, `review.json`, and `branch-point.jsonl`) live directly in a terminal human bridge node directory; `nodes/` is the single ticket root, derived rather than registered.
|
|
26
26
|
|
|
27
27
|
Specifications and plans are ordinary node-context artifacts. They share the node's lifetime and are removed when that node is reaped.
|
|
28
28
|
|
|
@@ -13,7 +13,7 @@ A base node can wedge mid-turn on a runaway bash command (for example, an unboun
|
|
|
13
13
|
## Recover the process that is actually stuck
|
|
14
14
|
|
|
15
15
|
- **A subprocess exists.** The daemon leaves the broker alone because a runaway bash/find/grep is the likely cause. Inspect the broker process tree, kill the scanner subprocess rather than its shell wrapper or node, and let the tool call return. The pi turn then resumes with its context intact. Tell the owning orchestrator if you discovered the wedge before its doctrine wake.
|
|
16
|
-
- **No subprocess exists.** The broker itself is stalled. The daemon SIGTERMs it; its live-exit policy then makes a bounded recovery attempt.
|
|
16
|
+
- **No subprocess exists.** The broker itself is stalled. The daemon SIGTERMs it; its live-exit policy then makes a bounded recovery attempt. An interrupted saved turn resumes in the same conversation with a continuation, whether the broker persisted a clean abort or died abruptly. A pending refresh or pending cycle starts a new cycle from the saved session instead. A broker that never established a session terminalizes rather than entering a respawn loop.
|
|
17
17
|
|
|
18
18
|
Recovery is not unconditional. Repeated short-lived exits or a boot failure terminalize the node as `dead`; no daemon respawn follows that terminal state. Reopen it explicitly with `crtr node lifecycle revive <id>` (use `--reopen` if it finalized), or deliver an inbox wake where that is the intended control path. If the daemon is down, it cannot detect, signal, or respawn a wedge; restore the daemon before relying on lifecycle recovery.
|
|
19
19
|
|
|
@@ -111,15 +111,11 @@ export declare class ChatView {
|
|
|
111
111
|
private readonly recapPalette;
|
|
112
112
|
/** Bold accent for the expanded crtr-context label. */
|
|
113
113
|
private readonly labelStyle;
|
|
114
|
-
/** Undefined honors each `<details open>` attribute until Ctrl+O establishes
|
|
115
|
-
* one viewer-wide disclosure state. */
|
|
116
|
-
private detailsExpandedOverride;
|
|
117
114
|
/** Viewer-local Markdown projection, handed to pi's message components so
|
|
118
115
|
* THEY apply it at render time with the exact content width. The viewer keeps
|
|
119
116
|
* no projected copy: the components hold canonical source, and each
|
|
120
|
-
* transformer reads live viewer state
|
|
121
|
-
*
|
|
122
|
-
* Markdown. */
|
|
117
|
+
* transformer reads live viewer state on every call. Diagrams apply only to
|
|
118
|
+
* assistant-authored Markdown. */
|
|
123
119
|
private readonly markdownTransformers;
|
|
124
120
|
/** The assistant message component currently being streamed (between
|
|
125
121
|
* message_start and message_end for an assistant turn). */
|
|
@@ -204,8 +200,7 @@ export declare class ChatView {
|
|
|
204
200
|
* one process it should call this on detach to avoid a leaked interval. */
|
|
205
201
|
dispose(): void;
|
|
206
202
|
/** Ctrl+O prefers summaries when the user enabled both folding and summary
|
|
207
|
-
* generation.
|
|
208
|
-
* sections, so the transcript has one reveal-more action rather than two. */
|
|
203
|
+
* generation. */
|
|
209
204
|
toggleToolsExpanded(): ToolDisplayToggle;
|
|
210
205
|
/** The `fold finished tool calls` view setting (`/fold-tools`, Alt+C → z → f).
|
|
211
206
|
* Returns the new state so the caller can surface a notice. */
|
|
@@ -29,7 +29,6 @@ import { CRTR_CYCLE_DIVIDER_CUSTOM_TYPE } from '../../../core/runtime/session-cy
|
|
|
29
29
|
import { generatedContextExpandedBody, generatedContextPresentation, isRuntimeRestartContinuation, } from '../../../shared/generated-context.js';
|
|
30
30
|
import { assistantVisibleText, isTrueUserMessage, } from '../../../shared/tool-groups.js';
|
|
31
31
|
import { transformDiagramFences } from './diagram.js';
|
|
32
|
-
import { transformHtmlMarkdown } from './html-markdown.js';
|
|
33
32
|
import { styleAttachAgentMarkdown, styleAttachMarkdownSource, styleAttachMessageMarkdown, styleAttachSummaryMarkdown, } from './markdown-source.js';
|
|
34
33
|
import { createCrtrEditToolDefinition } from './edit-diff.js';
|
|
35
34
|
import { GroupActivityRecorder } from './group-activity.js';
|
|
@@ -305,27 +304,13 @@ export class ChatView {
|
|
|
305
304
|
recapPalette;
|
|
306
305
|
/** Bold accent for the expanded crtr-context label. */
|
|
307
306
|
labelStyle = (s) => `\x1b[1m${s}\x1b[22m`;
|
|
308
|
-
/** Undefined honors each `<details open>` attribute until Ctrl+O establishes
|
|
309
|
-
* one viewer-wide disclosure state. */
|
|
310
|
-
detailsExpandedOverride;
|
|
311
307
|
/** Viewer-local Markdown projection, handed to pi's message components so
|
|
312
308
|
* THEY apply it at render time with the exact content width. The viewer keeps
|
|
313
309
|
* no projected copy: the components hold canonical source, and each
|
|
314
|
-
* transformer reads live viewer state
|
|
315
|
-
*
|
|
316
|
-
* Markdown. */
|
|
310
|
+
* transformer reads live viewer state on every call. Diagrams apply only to
|
|
311
|
+
* assistant-authored Markdown. */
|
|
317
312
|
markdownTransformers = [
|
|
318
313
|
(markdown, { messageType, availableWidth }) => (messageType === 'assistant' ? transformDiagramFences(markdown, availableWidth) : markdown),
|
|
319
|
-
(markdown, { messageType }) => (messageType === 'assistant'
|
|
320
|
-
? transformHtmlMarkdown(markdown, {
|
|
321
|
-
detailsExpanded: this.detailsExpandedOverride,
|
|
322
|
-
styles: {
|
|
323
|
-
kbd: (text) => this.recapPalette.active(this.recapPalette.bold(`‹${text}›`)),
|
|
324
|
-
mark: (text) => `\x1b[7m${this.recapPalette.bold(this.recapPalette.accent(text))}\x1b[27m`,
|
|
325
|
-
hint: this.dimStyle,
|
|
326
|
-
},
|
|
327
|
-
})
|
|
328
|
-
: markdown),
|
|
329
314
|
(markdown, { messageType }) => (messageType === 'user' ? styleAttachMarkdownSource(markdown) : styleAttachAgentMarkdown(markdown)),
|
|
330
315
|
];
|
|
331
316
|
/** The assistant message component currently being streamed (between
|
|
@@ -674,8 +659,7 @@ export class ChatView {
|
|
|
674
659
|
// `setToolsExpanded` / `toggleThinkingBlockVisibility`.
|
|
675
660
|
// -------------------------------------------------------------------------
|
|
676
661
|
/** Ctrl+O prefers summaries when the user enabled both folding and summary
|
|
677
|
-
* generation.
|
|
678
|
-
* sections, so the transcript has one reveal-more action rather than two. */
|
|
662
|
+
* generation. */
|
|
679
663
|
toggleToolsExpanded() {
|
|
680
664
|
let result;
|
|
681
665
|
if (this.summarizeToolCalls && this.foldSettledTools) {
|
|
@@ -687,11 +671,6 @@ export class ChatView {
|
|
|
687
671
|
this.toolOutputExpanded = !this.toolOutputExpanded;
|
|
688
672
|
result = { kind: 'output', expanded: this.toolOutputExpanded };
|
|
689
673
|
}
|
|
690
|
-
this.detailsExpandedOverride = this.toolOutputExpanded;
|
|
691
|
-
// The disclosure state lives in the transformer closure, so the transcript
|
|
692
|
-
// only has to drop its projections: pi's message components rebuild their
|
|
693
|
-
// Markdown on invalidate() and re-run the transformer on the next render.
|
|
694
|
-
this.historyContainer.invalidate();
|
|
695
674
|
this.applyToolDisplay();
|
|
696
675
|
return result;
|
|
697
676
|
}
|
|
@@ -30,10 +30,6 @@ const FENCE_OPEN = /^\s{0,3}(`{3,}|~{3,})/;
|
|
|
30
30
|
* a literal `>` stays untouched rather than being mis-split. */
|
|
31
31
|
const XML_TAG_LINE = /^([ \t]{0,3})(<\/?)([A-Za-z][\w.:-]*)((?:[ \t]+[^<>]*?)?)(\/?)>[ \t]*$/;
|
|
32
32
|
const XML_ATTRIBUTE = /([^\s=]+)(?:=("[^"]*"|'[^']*'|[^\s]*))?/g;
|
|
33
|
-
/** Tags the HTML allowlist owns (see html-markdown.ts). A `<details>` block
|
|
34
|
-
* that reaches this pass is one that failed validation there and is meant to
|
|
35
|
-
* stay literal. */
|
|
36
|
-
const HTML_ALLOWLIST_TAGS = new Set(['details', 'summary', 'kbd', 'mark']);
|
|
37
33
|
// A constant-lightness ramp from warm yellow to cool blue, with saturation
|
|
38
34
|
// deliberately reduced at each step so the hierarchy recedes rather than
|
|
39
35
|
// becoming a tour of unrelated accent colors.
|
|
@@ -85,8 +81,6 @@ function styleXmlTagLine(line) {
|
|
|
85
81
|
if (!match)
|
|
86
82
|
return undefined;
|
|
87
83
|
const [, indent, open, name, attributes, selfClose] = match;
|
|
88
|
-
if (HTML_ALLOWLIST_TAGS.has(name.toLowerCase()))
|
|
89
|
-
return undefined;
|
|
90
84
|
return indent
|
|
91
85
|
+ paint(XML_PUNCTUATION, open)
|
|
92
86
|
+ paint(XML_NAME, name)
|
|
@@ -15,6 +15,7 @@ import { Text, getCapabilities, hyperlink, truncateToWidth, visibleWidth, wrapTe
|
|
|
15
15
|
import { homedir } from 'node:os';
|
|
16
16
|
import { isAbsolute, resolve } from 'node:path';
|
|
17
17
|
import { pathToFileURL } from 'node:url';
|
|
18
|
+
import { normalizeBashJobPurpose } from '../../../core/bash-jobs.js';
|
|
18
19
|
import { TOOL_ICON } from '../../../core/preview-registry.js';
|
|
19
20
|
function str(value) {
|
|
20
21
|
return typeof value === 'string' ? value : '';
|
|
@@ -216,18 +217,25 @@ function styleCommandLine(line, theme) {
|
|
|
216
217
|
* there is more. Expanded (ctrl+o) it prints every line of the command, wrapped
|
|
217
218
|
* (never clipped — expanded is the raw truth) into the pane with continuations
|
|
218
219
|
* hanging under the icon. A line wider than the pane would desync pi-tui's line
|
|
219
|
-
* accounting against the terminal's own wrapping and garble the frame.
|
|
220
|
+
* accounting against the terminal's own wrapping and garble the frame.
|
|
221
|
+
*
|
|
222
|
+
* FOLDED, a call that supplied a `purpose` shows that clause INSTEAD of the
|
|
223
|
+
* command: the fold is a dense index of what the turn did, and the agent's own
|
|
224
|
+
* words for why it ran this read better there than `rg -n … | head -30`. The
|
|
225
|
+
* command itself is never lost — unfolding (or ctrl+o) shows it verbatim. */
|
|
220
226
|
class BashCallComponent {
|
|
221
227
|
command = '';
|
|
228
|
+
purpose;
|
|
222
229
|
expanded = false;
|
|
223
230
|
timeout;
|
|
224
231
|
theme;
|
|
225
232
|
/** Nothing is cached across paints (render recomputes from the fields), so
|
|
226
233
|
* pi's cache-drop hook has nothing to do here. */
|
|
227
234
|
invalidate() { }
|
|
228
|
-
update(theme, command, expanded, timeout) {
|
|
235
|
+
update(theme, command, purpose, expanded, timeout) {
|
|
229
236
|
this.theme = theme;
|
|
230
237
|
this.command = command;
|
|
238
|
+
this.purpose = purpose;
|
|
231
239
|
this.expanded = expanded;
|
|
232
240
|
this.timeout = timeout;
|
|
233
241
|
}
|
|
@@ -236,6 +244,9 @@ class BashCallComponent {
|
|
|
236
244
|
if (!theme)
|
|
237
245
|
return [];
|
|
238
246
|
const icon = theme.fg('accent', TOOL_ICON.bash);
|
|
247
|
+
if (this.purpose !== undefined) {
|
|
248
|
+
return [truncateToWidth(`${icon} ${theme.fg('toolOutput', this.purpose)}`, width, '…')];
|
|
249
|
+
}
|
|
239
250
|
const lines = this.command.split('\n').map((line) => line.trim()).filter((line) => line.length > 0);
|
|
240
251
|
const suffix = this.timeout ? theme.fg('muted', ` (timeout ${this.timeout}s)`) : '';
|
|
241
252
|
if (lines.length === 0)
|
|
@@ -286,6 +297,9 @@ export function createCrtrPlainBashToolDefinition(cwd, fold = new FoldedToolCall
|
|
|
286
297
|
}
|
|
287
298
|
const component = context.lastComponent instanceof BashCallComponent ? context.lastComponent : new BashCallComponent();
|
|
288
299
|
component.update(theme, str(a?.command),
|
|
300
|
+
// The purpose stands in for the command only while folded; it is normalized
|
|
301
|
+
// here because it is model-supplied text painted straight into the frame.
|
|
302
|
+
fold.folded ? normalizeBashJobPurpose(a?.purpose) ?? undefined : undefined,
|
|
289
303
|
// Folded wins over ctrl+o expansion: a folded bash is always its one-line form.
|
|
290
304
|
Boolean(context.expanded) && !fold.folded, typeof a?.timeout === 'number' ? a.timeout : undefined);
|
|
291
305
|
return fold.capture(component);
|