@north-light/crouter 0.3.354 → 0.3.355

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/api/dto/docs.d.ts +2 -0
  2. package/dist/api/dto/objects.d.ts +1 -0
  3. package/dist/api/dto/reviews.d.ts +6 -4
  4. package/dist/builtin-memory/02-turn-lifecycle/02-resident.md +1 -0
  5. package/dist/builtin-memory/04-orchestration-kernel.md +10 -31
  6. package/dist/builtin-memory/internal/memory-loading.md +1 -1
  7. package/dist/clients/attach/overlays/file-review.d.ts +1 -0
  8. package/dist/clients/attach/overlays/file-review.js +2 -2
  9. package/dist/clients/attach/render/chat-view.d.ts +6 -0
  10. package/dist/clients/attach/render/chat-view.js +2 -2
  11. package/dist/clients/attach/render/doc-links.d.ts +34 -0
  12. package/dist/clients/attach/render/doc-links.js +1 -0
  13. package/dist/clients/attach/render/markdown-source.js +5 -5
  14. package/dist/clients/attach/session/doc-materialize.d.ts +53 -0
  15. package/dist/clients/attach/session/doc-materialize.js +3 -0
  16. package/dist/clients/attach/session/document-links.d.ts +21 -0
  17. package/dist/clients/attach/session/document-links.js +1 -0
  18. package/dist/clients/attach/session/file-links.d.ts +2 -0
  19. package/dist/clients/attach/session/file-links.js +1 -1
  20. package/dist/clients/attach/viewer.js +622 -620
  21. package/dist/clients/inbox/review/review-client.d.ts +5 -1
  22. package/dist/clients/inbox/review/review-client.js +1 -1
  23. package/dist/commands/canvas/read.js +4 -4
  24. package/dist/commands/doc/write.js +1 -1
  25. package/dist/commands/node/lifecycle.js +2 -2
  26. package/dist/core/graph/deletion.d.ts +5 -4
  27. package/dist/core/graph/deletion.js +3 -3
  28. package/dist/core/graph/documents.d.ts +8 -1
  29. package/dist/core/graph/documents.js +9 -6
  30. package/dist/core/graph/edges.d.ts +3 -2
  31. package/dist/core/graph/edges.js +1 -1
  32. package/dist/core/graph/events.d.ts +2 -2
  33. package/dist/core/graph/events.js +5 -4
  34. package/dist/core/graph/names.d.ts +3 -1
  35. package/dist/core/graph/names.js +3 -3
  36. package/dist/core/graph/repo-sync/exchange.js +2 -2
  37. package/dist/core/runs/operations.js +5 -5
  38. package/dist/core/runtime/broker-persona-guidance.js +2 -2
  39. package/dist/core/runtime/persona.js +2 -2
  40. package/dist/core/runtime/roadmap.d.ts +3 -0
  41. package/dist/core/runtime/roadmap.js +8 -4
  42. package/dist/core/substrate/delivery/deliver.js +1 -1
  43. package/dist/core/substrate/delivery/listings.d.ts +3 -0
  44. package/dist/core/substrate/delivery/listings.js +5 -2
  45. package/dist/core/substrate/delivery/render-boot.js +26 -26
  46. package/dist/core/substrate/delivery/render-event.d.ts +13 -6
  47. package/dist/core/substrate/delivery/render-event.js +6 -4
  48. package/dist/daemon/api/handlers/docs.js +1 -1
  49. package/dist/daemon/api/handlers/objects.js +5 -5
  50. package/dist/daemon/api/handlers/reviews.d.ts +4 -1
  51. package/dist/daemon/api/handlers/reviews.js +1 -1
  52. package/dist/shared/inbox-entry-body.js +7 -7
  53. package/package.json +2 -2
  54. package/packages/crouter-identity/package.json +1 -1
  55. package/runtime.lock.json +11 -11
  56. package/scripts/lib/isolation-env.mjs +8 -2
@@ -50,6 +50,8 @@ export interface DocEditRequest {
50
50
  new: string;
51
51
  }>;
52
52
  rationale: string;
53
+ /** The heads key the edit was made from. Absent → the caller's last read of the document. */
54
+ base?: string;
53
55
  verbatim?: boolean;
54
56
  preview?: string;
55
57
  summary?: string;
@@ -43,6 +43,7 @@ export interface DocumentReadDTO {
43
43
  /** One body per head, in `heads` order. */
44
44
  bodies: string[];
45
45
  needs_merge: boolean;
46
+ /** Documents named under it, then the documents it links to not already in your context at preview, each once. */
46
47
  listing?: ObjectDTO[];
47
48
  /** One `<auto-loaded-context>` block: enclosing listings and documents the read's `document-read` rules delivered. */
48
49
  attachments?: string;
@@ -9,11 +9,13 @@ export interface CreateReviewRequest {
9
9
  origin_kind: ReviewOriginKindDTO;
10
10
  /** Caller-selected node whose persisted session is forked. */
11
11
  origin_node_id: NodeIdDTO;
12
- /** Ticket reviews: the document to review, as a canvas ref (`[[ ]]` optional). The daemon
13
- * reads it as the caller, snapshots its head to `<review_dir>/document.md`, and on submit
14
- * saves the reviewed text as a new revision (refused as `stale_revision` if it moved). */
12
+ /** The document to review, as a canvas ref (`[[ ]]` optional) — required for ticket reviews,
13
+ * and the alternative to `file` for inline ones. The daemon reads it as the caller, snapshots
14
+ * its head to `<review_dir>/document.md`, and on submit saves the reviewed text as a new
15
+ * revision (refused as `stale_revision` if it moved). */
15
16
  document?: string;
16
- /** Inline reviews: an absolute file path; the daemon canonicalizes and validates it. */
17
+ /** Inline reviews of a file: an absolute path; the daemon canonicalizes and validates it.
18
+ * An inline review takes exactly one of `file` or `document`. */
17
19
  file?: string;
18
20
  /** Caller-minted invocation key; the daemon enforces its uniqueness. */
19
21
  idempotency_key: string;
@@ -13,6 +13,7 @@ surfaces:
13
13
  - Keep replies short by being selective about what you include — drop details that don't change what the reader would do next — not by compressing into fragments, arrow chains, or coined shorthand. Readable beats short.
14
14
  - After a long working stretch, your reply is their first look at any of it: write it as a re-grounding, not a continuation of your working thread, and leave the vocabulary you built up while working behind unless you re-introduce it.
15
15
  - Use plain, proportionate language — cut praise, clichés, faux urgency, and repetition.
16
+ - Link a document you mention as `[[<node-id>/<name>]]`, not a file path: the person's viewer renders it as a readable link they can open, edit and review.
16
17
 
17
18
  ## How you end
18
19
  You are **resident** and interactable: you are never forced to submit a final result. Stopping is legitimate — the runtime keeps live waits wakeable and completes an unattended conversation after nothing remains to wake it. Do **not** `crtr push final` to "finish" (it would close you mid-conversation); you end by yielding or by being closed. End your turn whenever you have nothing in hand — the runtime owns what happens next.
@@ -5,7 +5,9 @@ gate: {mode: orchestrator}
5
5
  rationale: >-
6
6
  Two observed orchestration failures set this kernel's stopping rules. A sole-writer feature lane produced a 5-deep 1:1 developer/orchestrator chain by repeatedly delegating the whole assignment; separately, the kernel's “idle capacity,” “maximum agents,” and “when in doubt, more rigor” objective helped produce review-only subtrees as large as 87 nodes and five levels deep. Coordination must optimize new evidence toward the goal rather than node count or process length.
7
7
 
8
- Prompt-writing guidance (outcome framing, intent context, artifact pointers, report shape) is deliberately absent because `node new -h` owns it — the forced read at the spawn moment for every spawner, base and orchestrator alike; the kernel keeps only decomposition and cross-child routing. Waiting guidance is deliberately absent: 02-turn-lifecycle/00-ending-a-turn owns waiting for every node, including the auto-wake on a child's report, so a kernel copy only duplicated it. Likewise the roadmap-curation paragraph leans on 00-runtime-base/00-authoring's "Living documents" for the fold-in/rewrite discipline and keeps only what is roadmap-specific, and memory guidance is absent because the substrate's always-present boot rendering already carries read-before-act, capture, and staleness rules for every node. Promotion guidance is absent because the promote boundary is a base-node decision 04-base-worker owns; here only the sub-orchestrator-child threshold matters, and "Delegating" carries it. User-engagement calibration is absent because 00-runtime-base/01-escalation's "When blocked" section owns it for every node, and the yield-with-unasked-question rule already lives in 02-turn-lifecycle/00-ending-a-turn; the kernel keeps only the stakeholder framing and the roadmap note about pending answers.
8
+ Prompt-writing guidance (outcome framing, intent context, artifact pointers, report shape) is deliberately absent because `node new -h` owns it — the forced read at the spawn moment for every spawner, base and orchestrator alike; the kernel keeps only decomposition and cross-child routing. Waiting guidance is deliberately absent: 02-turn-lifecycle/00-ending-a-turn owns waiting for every node, including the auto-wake on a child's report, so a kernel copy only duplicated it. Likewise roadmap curation leans on 00-runtime-base/00-authoring's "Living documents" for the fold-in/rewrite discipline, and memory guidance is absent because the substrate's always-present boot rendering already carries read-before-act, capture, and staleness rules for every node. Promotion guidance is absent because the promote boundary is a base-node decision 04-base-worker owns; here only the sub-orchestrator-child threshold matters, and "Delegating" carries it. User-engagement calibration is absent because 00-runtime-base/01-escalation's "When blocked" section owns it for every node, and the yield-with-unasked-question rule already lives in 02-turn-lifecycle/00-ending-a-turn; the kernel keeps only the stakeholder framing.
9
+
10
+ The roadmap's shape lives on `crtr node yield -h`, the help every yielding node reads at the moment it yields; the kernel keeps only the level-of-abstraction rule. An audit of 12 long-lived nodes across about 290 refresh cycles found fresh windows read about 30% of the links their roadmaps carried, and only 11% of links pointing at evidence of finished work; roadmaps grew from about 4k to 14k characters; and the decision and scope sections the old scaffold prescribed were used 0–5% of the time. Phases were removed because they asked the orchestrator to plan and track its own sequential stages, which pulled strategic nodes into step-level detail that belongs to the child holding each unit; a node now tracks units at its own level and links to the documents that hold everything finer.
9
11
  lint-ignore: length
10
12
  surfaces:
11
13
  - on: boot
@@ -18,47 +20,24 @@ You own a goal whose worthwhile parallel work makes coordination your primary jo
18
20
 
19
21
  You set the quality ceiling for everything under you. A conservative orchestrator produces conservative output no matter how good its agents are. You do not accept deferred Critical or Major findings, or anything that violates an acceptance criterion — deferring those becomes permanent debt. A Minor or cosmetic finding closed with a one-line reason is resolved, not deferred. You do not accept "good enough" understanding — shallow understanding is the root cause of bad delegation, because you cannot write a sharp task for work you do not understand.
20
22
 
21
- When your context fills you yield (`crtr node yield`) and revive in a clean window oriented by your roadmap (your document `roadmap`, loaded at every new session of yours; edit it with `crtr doc edit roadmap`) and the durable context artifacts it lists. Use refreshes to continue an open phase, not to add cycles after its exit criterion is met.
23
+ When your context fills you yield (`crtr node yield`) and revive in a clean window oriented by your roadmap (your document `roadmap`, loaded at every new session of yours; edit it with `crtr doc edit roadmap`) and the documents in its Working set. Use refreshes to continue open work, not to add cycles after the goal's exit criteria are met.
22
24
 
23
25
  ## The loop
24
26
 
25
- Every wake advances the same loop, but orientation follows the wake: a fresh window starts from the roadmap and its active artifacts; an ordinary child or inbox wake resumes the live conversation and the delivered report pointers.
27
+ Every wake advances the same loop, but orientation follows the wake: a fresh window starts from the roadmap and its Working set; an ordinary child or inbox wake resumes the live conversation and the delivered report pointers.
26
28
 
27
- 1. **Orient.** After a yield, read your roadmap and the artifacts under `## Active context`. After an ordinary wake, continue from the live conversation and dereference the child reports that matter — the wake already delivered their digest and paths, so read the detail with `crtr canvas read` rather than acting on a one-line summary.
29
+ 1. **Orient.** After a yield, start from your roadmap; the previews of its Working set arrive with it, so open only the documents the next decision depends on. After an ordinary wake, continue from the live conversation and dereference the child reports that matter — the wake already delivered their digest and paths, so read the detail with `crtr canvas read` rather than acting on a one-line summary.
28
30
  2. **Assess.** What landed? What failed? What did a report reveal that changes the plan — a blocker, scope drift, a wrong assumption?
29
31
  3. **Understand before you delegate.** If you are missing current-state facts about the code, spawn an `explore` scout; once the facts land, give diagnosis or target-state decisions to the matching specialist. You write a sharp task only from evidence — asking a cheap scout to make the decision puts judgment on the wrong model tier.
30
- 4. **Find useful parallel work.** Delegate genuinely independent units that already belong to the current phase; spare capacity is not a reason to create another task or review.
32
+ 4. **Find useful parallel work.** Delegate genuinely independent units the current state calls for; spare capacity is not a reason to create another task or review.
31
33
  5. **Resolve what you noticed.** Address actionable in-role issues in the same pass. Route material out-of-scope defects to their owner; optional polish does not earn another node.
32
34
  6. **Act, then settle the turn.** Spawn the children, then settle the turn according to your lifecycle. When work remains and context is filling, yield; when the goal is met and verified, follow the lifecycle-specific completion contract. Bringing the roadmap current belongs to *yielding* (see below), not to every wake — when you delegate and simply end the turn, your live context still holds the state, so leave the roadmap untouched.
33
35
 
34
- Be proactive — look ahead. If the current phase is wrapping up, prepare the next one. If a review found issues, spawn the fix agents in the same wake. Leave only children whose outcomes advance the current phase; idle capacity is correct when the remaining work is serial or complete.
35
-
36
- ## The roadmap is your strategic handoff
37
-
38
- Your roadmap carries strategy and present state into a fresh window; the documents it points to remain durable too. Every ordinary wake (a child's report, an inbox message) resumes this same conversation, so the roadmap stays unread and unchanged while the live context still holds the work. Bring it fully current as the last thing you do before yielding, because that is when the fresh you needs it to continue — including what each pending `crtr human send` answer will settle, so the fresh window knows what to do when it arrives. It holds exactly two things: **how you intend to reach the goal, and where you are right now.** It is not a journal of what you did, a queue of what you'll do next, or a log of which agents you spawned.
39
-
40
- **The roadmap has exactly these sections. Nothing else belongs in it.** A **frozen core** you set once and rarely touch:
41
- - `## Goal` — one paragraph: what "done" looks like, who and what is affected.
42
- - `## Exit criteria` — concrete, evaluable conditions for finishing.
43
-
44
- And an **evolving body** you bring current right before you yield:
45
- - `## Scope assumptions / non-goals` — what's settled and what's out, so children inherit the framing.
46
- - `## Strategy / phases` — your high-level shape of how you reach the goal: the ordered phases from here to done, the current one carrying a one-line status of what's happening right now. A phase with enough independent parallel work to need its own coordinator becomes a sub-orchestrator; a merely long sequential phase stays with one base child across yields.
47
- - `## Active context` — the `[[<node-id>/<name>]]` pointers of the documents currently relevant to the work.
48
-
49
- **Present state and strategic shape only — never tactical plans.** Don't list the agents you're about to spawn, "next steps," or an upcoming-action queue; what to delegate next is decided live each wake from the feed and the phases, not stored here. Don't record the status of children you've spawned; the feed carries their live status every wake, so a copy here only goes stale. Don't keep a dated history of what landed; that lives in your reports (`crtr push`), not the roadmap.
50
-
51
- Delete completed items entirely rather than marking them done — no `[done]` markers, no completion log; the roadmap should get *shorter* as work completes. Keep decisions, rationale, and design detail out of it: when a question resolves or the approach shifts, fold the outcome into the relevant context artifact — the spec, plan, or design — and let the roadmap merely point at it. The roadmap never carries the decision itself, only the current shape it produced. A bloated roadmap degrades every wake, including the ones far from the detail it carries.
52
-
53
- You shape the roadmap once at the start and revise it rarely afterward. When you write or reshape it, read the methodology named by your kind prompt first. It carries the roadmap shapes, styles, and decomposition patterns for your kind of work; this kernel describes only the roadmap's *structure*, not how to shape it for your domain.
54
-
55
- Larger artifacts — specs, plans, exploration findings, test recipes — are documents their authors own. Children report each as `[[<node-id>/<name>]]`, and your roadmap points at it in `## Active context`. When a report makes an active document stale, bring it current before the next child relies on it (`crtr doc edit`), so the roadmap points only to current truth.
56
-
57
- ## Working in phases
36
+ Be proactive — look ahead: when in-flight units are closing, line up the units that depend on them. If a review found issues, spawn the fix agents in the same wake. Leave only children whose outcomes advance the goal; idle capacity is correct when the remaining work is serial or complete.
58
37
 
59
- Your `## Strategy / phases` is an ordered commitment, not a menu. Commit to the current phase and drive it until its exit condition is genuinely met — resist the pull to half-finish three phases at once, or to skip ahead because the next one looks easier. A phase is done when it works, not when you are tired of it.
38
+ ## Stay at your level
60
39
 
61
- Then advance. Reshape the phases themselves only when reality invalidates the plan — a discovery moves a boundary, a phase has to split, an assumption proved wrong — never to dodge a phase that turned out to be hard. When you do reshape, rewrite the roadmap so the fresh you inherits the new shape and never re-litigates the old one.
40
+ Your roadmap and your attention hold what you decide and track: direction, the units you have handed out, and how they fit together. They hold nothing finer. Each unit's detail lives with the node holding it, in its reports and documents, and your roadmap links to the documents it depends on. Name units by what they are and how they fit, never by child node id or status: your bearings already list every direct child with its status. A unit you work hands-on keeps its step-level detail in a document of its own, linked from the Working set, not in the roadmap. Bring the roadmap current only as you yield; an ordinary wake resumes the live conversation. `crtr node yield -h` carries the roadmap's shape.
62
41
 
63
42
  ## Delegating
64
43
 
@@ -41,7 +41,7 @@ A rule's `if` is the eligibility predicate over the receiving node — kind, mod
41
41
 
42
42
  ## Listings and dedup
43
43
 
44
- A full-body delivery is a read: `crtr canvas read <name>` and every content delivery expose, once per loaded context, the listing of each prefix of the document's name — one preview per document, one bare name per prefix that has names under it — then fire matching `document-read` rules. A document named `x` and documents named `x/…` coexist; reading `x` returns its body and the names under it. Content-delivered companions are read in turn until nothing new is delivered. `unlisted: true` suppresses a document from every listing. An owner's top level is never auto-listed — `crtr canvas list --type document` is the deliberate browse. Every content delivery, like every read, records a watch, so later edits reach the reader as pushes.
44
+ A full-body delivery is a read: `crtr canvas read <name>` and every content delivery expose, once per loaded context, the listing of each prefix of the document's name — one preview per document, one bare name per prefix that has names under it — then fire matching `document-read` rules. A document named `x` and documents named `x/…` coexist; reading `x` returns its body and one listing of the names under it and the documents its body links to — previews only, not reads, never recursing. Content-delivered companions are read in turn until nothing new is delivered. `unlisted: true` suppresses a document from every listing. An owner's top level is never auto-listed — `crtr canvas list --type document` is the deliberate browse. Every content delivery, like every read, records a watch, so later edits reach the reader as pushes.
45
45
 
46
46
  Every delivery registers the document or listing and its level in the loaded context's exposure ledger, kept in canvas.db. System and transcript ranks max-fold, so a higher level pierces a lower one while a content delivery silences later lower-level deliveries and duplicate read attachments. A strict resume preserves that ledger and the byte-stable preference snapshot; yield or another new-session boundary clears it and replaces them with exactly the new system and first-message snapshots.
47
47
 
@@ -2,6 +2,7 @@ import type { SurfaceHost } from '../../surfaces/host.js';
2
2
  import type { Picker } from './pickers.js';
3
3
  import { extractFilePaths } from '#core/human/visible-paths';
4
4
  export declare function buildFileReviewPicker(candidates: readonly string[], cwd: string, onChoose: (file: string) => void, close: () => void, notify: (message: string) => void): Picker;
5
+ /** Open an inline review of a file path, or of a document given as `[[ref]]`. */
5
6
  export declare function launchFileReview(host: SurfaceHost, file: string, opts: {
6
7
  originNodeId: string;
7
8
  onNotice: (message: string) => void;
@@ -1,2 +1,2 @@
1
- var w=Object.defineProperty;var c=(n,e)=>w(n,"name",{value:e,configurable:!0});import{homedir as h}from"node:os";import{isAbsolute as v,join as g,relative as b,resolve as S}from"node:path";import{Input as y,SelectList as a,getKeybindings as I}from"@earendil-works/pi-tui";import{getSelectListTheme as l}from"@earendil-works/pi-coding-agent";import{openReviewWindow as R}from"../../inbox/review/launch.js";import{createReviewClient as C,ReviewTerminalError as L,terminalRefusalNotice as k}from"../../inbox/review/review-client.js";import{checkReviewableFile as x,extractFilePaths as P}from"#core/human/visible-paths";const u=12;function d(n,e){const t=b(e,n);if(t!==""&&!t.startsWith("..")&&!v(t))return t;const i=h();return n===i||n.startsWith(`${i}/`)?`~${n.slice(i.length)}`:n}c(d,"labelForPath");function p(n,e){const t=n==="~"?h():n.startsWith("~/")?g(h(),n.slice(2)):n;return S(e,t)}c(p,"resolveTypedPath");class F{static{c(this,"FileReviewPicker")}candidates;cwd;onChoose;close;notify;focused=!1;input=new y;list=new a([],u,l());constructor(e,t,i,s,o){this.candidates=e,this.cwd=t,this.onChoose=i,this.close=s,this.notify=o,this.input.onEscape=s,this.input.onSubmit=()=>this.chooseSelected(),this.refreshList()}render(e){this.input.focused=this.focused;const t=Math.max(1,e-8);return["Review a file named in this transcript",...this.input.render(t).map(i=>`Path: ${i}`),...this.list.render(e)]}handleInput(e){const t=I();if(t.matches(e,"tui.select.up")||t.matches(e,"tui.select.down")){this.list.handleInput(e);return}if(t.matches(e,"tui.select.confirm")||e===`
2
- `){this.chooseSelected();return}const i=this.input.getValue();this.input.handleInput(e),this.input.getValue()!==i&&this.refreshList()}invalidate(){this.input.invalidate(),this.list.invalidate()}refreshList(){const e=this.input.getValue(),t=e.toLowerCase(),i=this.candidates.filter(r=>{const f=d(r,this.cwd).toLowerCase();return t===""||f.includes(t)||r.toLowerCase().includes(t)}),s=e===""?void 0:p(e,this.cwd),o=s!==void 0&&this.candidates.some(r=>r===s),m=[...i.map(r=>({value:r,label:d(r,this.cwd)})),...s!==void 0&&!o?[{value:s,label:`use ${JSON.stringify(e)}`,description:s}]:[]];this.list=new a(m,u,l()),this.list.onSelect=()=>this.chooseSelected(),this.list.onCancel=this.close}chooseSelected(){const e=this.input.getValue(),i=this.list.getSelectedItem()?.value??e;if(i==="")return;const s=p(i,this.cwd),o=x(s);if(!o.ok){this.notify(o.reason);return}this.onChoose(s),this.close()}}function O(n,e,t,i,s){const o=new F(n,e,t,i,s);return{component:o,focus:o}}c(O,"buildFileReviewPicker");async function _(n,e,t){if(n.capabilities.remote){t.onNotice("The review is unavailable in a remote attach \u2014 the file and companion live on the host.");return}let i;try{i=await C().createInline({originNodeId:t.originNodeId,file:e})}catch(s){t.onNotice(s instanceof L?k(s):s instanceof Error?s.message:String(s));return}R(n,i)}c(_,"launchFileReview");export{O as buildFileReviewPicker,P as extractFilePaths,_ as launchFileReview};
1
+ var v=Object.defineProperty;var c=(n,e)=>v(n,"name",{value:e,configurable:!0});import{homedir as a}from"node:os";import{isAbsolute as g,join as b,relative as S,resolve as y}from"node:path";import{Input as I,SelectList as d,getKeybindings as R}from"@earendil-works/pi-tui";import{getSelectListTheme as u}from"@earendil-works/pi-coding-agent";import{openReviewWindow as C}from"../../inbox/review/launch.js";import{createReviewClient as L,ReviewTerminalError as k,terminalRefusalNotice as x}from"../../inbox/review/review-client.js";import{checkReviewableFile as N,extractFilePaths as P}from"#core/human/visible-paths";import{docLinkText as F}from"../render/doc-links.js";const l=12;function h(n){const e=/^\[\[([^[\]\n]+)\]\]$/.exec(n.trim());return e===null?void 0:e[1].trim()}c(h,"documentRef");function m(n,e){const t=h(n);if(t!==void 0)return`${F(t)} (document)`;const i=S(e,n);if(i!==""&&!i.startsWith("..")&&!g(i))return i;const s=a();return n===s||n.startsWith(`${s}/`)?`~${n.slice(s.length)}`:n}c(m,"labelForPath");function f(n,e){const t=n==="~"?a():n.startsWith("~/")?b(a(),n.slice(2)):n;return y(e,t)}c(f,"resolveTypedPath");class W{static{c(this,"FileReviewPicker")}candidates;cwd;onChoose;close;notify;focused=!1;input=new I;list=new d([],l,u());constructor(e,t,i,s,o){this.candidates=e,this.cwd=t,this.onChoose=i,this.close=s,this.notify=o,this.input.onEscape=s,this.input.onSubmit=()=>this.chooseSelected(),this.refreshList()}render(e){this.input.focused=this.focused;const t=Math.max(1,e-8);return["Review a file or document named in this transcript",...this.input.render(t).map(i=>`Path: ${i}`),...this.list.render(e)]}handleInput(e){const t=R();if(t.matches(e,"tui.select.up")||t.matches(e,"tui.select.down")){this.list.handleInput(e);return}if(t.matches(e,"tui.select.confirm")||e===`
2
+ `){this.chooseSelected();return}const i=this.input.getValue();this.input.handleInput(e),this.input.getValue()!==i&&this.refreshList()}invalidate(){this.input.invalidate(),this.list.invalidate()}refreshList(){const e=this.input.getValue(),t=e.toLowerCase(),i=this.candidates.filter(r=>{const w=m(r,this.cwd).toLowerCase();return t===""||w.includes(t)||r.toLowerCase().includes(t)}),s=e===""?void 0:h(e)!==void 0?e.trim():f(e,this.cwd),o=s!==void 0&&this.candidates.some(r=>r===s),p=[...i.map(r=>({value:r,label:m(r,this.cwd)})),...s!==void 0&&!o?[{value:s,label:`use ${JSON.stringify(e)}`,description:s}]:[]];this.list=new d(p,l,u()),this.list.onSelect=()=>this.chooseSelected(),this.list.onCancel=this.close}chooseSelected(){const e=this.input.getValue(),i=this.list.getSelectedItem()?.value??e;if(i==="")return;if(h(i)!==void 0){this.onChoose(i),this.close();return}const s=f(i,this.cwd),o=N(s);if(!o.ok){this.notify(o.reason);return}this.onChoose(s),this.close()}}function q(n,e,t,i,s){const o=new W(n,e,t,i,s);return{component:o,focus:o}}c(q,"buildFileReviewPicker");async function B(n,e,t){if(n.capabilities.remote){t.onNotice("The review is unavailable in a remote attach \u2014 the file and companion live on the host.");return}const i=h(e);let s;try{s=await L().createInline(i===void 0?{originNodeId:t.originNodeId,file:e}:{originNodeId:t.originNodeId,document:i})}catch(o){t.onNotice(o instanceof k?x(o):o instanceof Error?o.message:String(o));return}C(n,s)}c(B,"launchFileReview");export{q as buildFileReviewPicker,P as extractFilePaths,B as launchFileReview};
@@ -173,6 +173,8 @@ export declare class ChatView {
173
173
  private lastAssistantText;
174
174
  /** Existing file paths found anywhere in the rendered transcript, newest first. */
175
175
  private readonly transcriptFilePaths;
176
+ /** `[[ref]]` document references from the transcript, newest first. */
177
+ private readonly transcriptDocRefs;
176
178
  /** Canonical copyable transcript blocks, in their rendered visual order. */
177
179
  private readonly copyBlockRecords;
178
180
  private readonly copyIndex;
@@ -327,6 +329,10 @@ export declare class ChatView {
327
329
  private assistantToolCalls;
328
330
  /** Existing file paths from the rendered transcript, newest first. */
329
331
  getTranscriptFilePathsNewestFirst(): string[];
332
+ /** `[[ref]]` document references from the transcript, newest first, deduped. */
333
+ getTranscriptDocRefsNewestFirst(): string[];
334
+ /** Re-run every Markdown transform: a document link's rendered target changed. */
335
+ refreshMarkdown(): void;
330
336
  /** The text of the most recent assistant message, for `/copy`. Undefined when
331
337
  * no assistant message has been seen (or it had no text content). */
332
338
  getLastAssistantText(): string | undefined;
@@ -1,5 +1,5 @@
1
- var j=Object.defineProperty;var p=(a,t)=>j(a,"name",{value:t,configurable:!0});import{Container as v,Loader as F,Spacer as d,Text as x}from"@earendil-works/pi-tui";import{AssistantMessageComponent as L,BashExecutionComponent as E,BranchSummaryMessageComponent as H,CompactionSummaryMessageComponent as W,CustomMessageComponent as $,parseSkillBlock as q,SkillInvocationMessageComponent as V,ToolExecutionComponent as N,UserMessageComponent as S}from"@earendil-works/pi-coding-agent";import{attachMarkdownTheme as u}from"../config.js";import{ContextMessageComponent as U}from"./context-message.js";import{presentationFor as z}from"./card-presentation.js";import{detectInlinePageResult as Y,PageBlockComponent as J}from"./page-block.js";import{CRTR_OUTPUT_CUSTOM_TYPE as K,CrtrOutputMessageComponent as X,createCrtrBashToolDefinition as Q}from"./crtr-output.js";import{CRTR_CYCLE_DIVIDER_CUSTOM_TYPE as Z,endedByAbort as w}from"../../../core/runtime/session-cycles.js";import{parseCard as tt}from"../../../shared/generated-context.js";import{assistantVisibleText as c,isGroupBoundaryKind as et,isTrueUserMessage as C}from"../../../shared/tool-groups.js";import{transformDiagramFences as st}from"./diagram.js";import{styleAttachAgentMarkdown as it,styleAttachMarkdownSource as M,styleAttachMessageMarkdown as ot,styleAttachSummaryMarkdown as O}from"./markdown-source.js";import{createCrtrEditToolDefinition as nt}from"./edit-diff.js";import{GroupActivityRecorder as rt}from"./group-activity.js";import{GroupRecapComponent as at}from"./group-recap.js";import{FoldedToolCallController as ht,bashCallBackgroundHintLines as pt,createCrtrPlainBashToolDefinition as lt,createCrtrReadToolDefinition as dt,createCrtrWriteToolDefinition as ct}from"./tool-calls.js";import{ringCompletionBell as ut}from"../chrome/completion-bell.js";import{extractFilePaths as mt}from"#core/human/visible-paths";import{keepWhenCondensed as ft,liveRegionStart as gt}from"./condensed-history.js";import{ViewerAssistantMessageComponent as B}from"./assistant-message.js";import{CompositeViewportSource as yt,MeasuredContainer as A}from"./measured-container.js";import{readConfig as T,updateRawConfigAtomically as Ct}from"../../../core/config.js";import{DEFAULT_CONDENSED_HISTORY as Tt,DEFAULT_LIVE_CYCLES as kt}from"../../../types.js";import{applySnapshot as bt,applyToolGroupSummary as xt,applyWorkingActivity as St,bashEnd as wt,bashOutput as Bt,bashStart as At,initialConvState as Rt,reduce as Gt}from"../../conversation/projection.js";const I=p(a=>`\x1B[2m${a}\x1B[22m`,"defaultDimStyle"),_=50;function Et(){try{return T("user").live_cycles}catch{return kt}}p(Et,"readLiveCycles");function Mt(){try{return T("user").condensed_history}catch{return Tt}}p(Mt,"readCondensedHistory");function Ot(){try{return T("user").fold_finished_tools}catch{return!1}}p(Ot,"readFoldFinishedTools");function It(){try{return T("user").summarize_tool_calls}catch{return!1}}p(It,"readSummarizeToolCalls");function _t(){try{return T("user").detailed_tool_recaps}catch{return!0}}p(_t,"readDetailedToolRecaps");function Pt(a){try{Ct("user",t=>({...t,fold_finished_tools:a}))}catch{}}p(Pt,"persistFoldFinishedTools");function Dt(a){return typeof a=="object"&&a!==null&&"setExpanded"in a&&typeof a.setExpanded=="function"}p(Dt,"isExpandable");const jt=/\x1b\[[0-9;]*m/g,vt=/\x1b\[([0-9;]*)m/g;function Ft(a){return a.replace(vt,(t,e)=>{const s=e.split(";"),i=[];for(let o=0;o<s.length;o++){const n=Number(s[o]===""?0:s[o]);if(n===38||n===48||n===58){const r=Number(s[o+1]),h=o+(r===5?2:r===2?4:1);n!==48&&i.push(...s.slice(o,h+1)),o=h;continue}n>=40&&n<=47||n>=100&&n<=107||i.push(String(n))}return i.length>0?`\x1B[${i.join(";")}m`:""})}p(Ft,"stripBackground");const Lt=/<from\b[^>]*>[\s\S]*?<\/from>/g;class R extends d{static{p(this,"FoldedToolSeparator")}folded=!1;separatesToolGroup=!1;setFolded(t){this.folded=t,this.refresh()}setSeparatesToolGroup(t){this.separatesToolGroup=t,this.refresh()}refresh(){this.setLines(this.folded&&this.separatesToolGroup?1:0)}}class G extends N{static{p(this,"MinimizableToolComponent")}activityCallId;minimized=!1;expandedState=!1;foldController;resultObserver;setToolView(t,e){this.foldController=t,this.resultObserver=e}updateResult(...t){this.resultObserver?.(t[0],t[1]??!1),super.updateResult(...t)}setExpanded(t){this.expandedState=t,super.setExpanded(t)}setMinimized(t){!this.foldController||this.minimized===t||(this.minimized=t,this.foldController.setFolded(t),super.setExpanded(this.expandedState))}render(t){if(!this.minimized)return[...super.render(t),...pt(this.foldController?.callComponent(),t)];const e=this.foldController?.callComponent();return e?e.render(t).filter(s=>s.replace(jt,"").trim().length>0).map(s=>Ft(s).trimEnd()):super.render(t)}}const Ht=p(a=>`\x1B[31m${a}\x1B[39m`,"defaultErrorStyle"),Wt={accent:p(a=>`\x1B[33m${a}\x1B[39m`,"accent"),active:p(a=>`\x1B[36m${a}\x1B[39m`,"active"),info:p(a=>`\x1B[34m${a}\x1B[39m`,"info"),muted:I,faint:I,border:p(a=>a,"border"),surface:p(a=>a,"surface"),bold:p(a=>`\x1B[1m${a}\x1B[22m`,"bold"),error:Ht,warning:p(a=>`\x1B[33m${a}\x1B[39m`,"warning"),diffAdded:p(a=>`\x1B[32m${a}\x1B[39m`,"diffAdded"),diffRemoved:p(a=>`\x1B[91m${a}\x1B[39m`,"diffRemoved"),bashMode:p(a=>`\x1B[32m${a}\x1B[39m`,"bashMode"),bashModeAlt:p(a=>`\x1B[92m${a}\x1B[39m`,"bashModeAlt")};class ue{static{p(this,"ChatView")}tui;container;historyContainer=new A;statusContainer=new A;bannerContainer;transcript;appendTarget=this.historyContainer;pageBlocks=new Map;inlinePageBlocks;pageOpenHint;backgroundBashHint;liveCycles;condensedHistory;cwd;showImages;imageWidthCells;hideThinking;hiddenThinkingLabel;toolOutputExpanded;foldSettledTools=Ot();summarizeToolCalls=It();detailedToolRecaps=_t();showGroupSummaries=this.summarizeToolCalls&&this.foldSettledTools;groups=[];openGroup;groupSummaries=new Map;nodeRoster=new Map;streamingWasGroupMember=!1;onFooterEvent;onActivityChange;spinnerStyle;dimStyle;errorStyle;recapPalette;labelStyle=p(t=>`\x1B[1m${t}\x1B[22m`,"labelStyle");markdownTransformers=[(t,{messageType:e,availableWidth:s})=>e==="assistant"?st(t,s):t,(t,{messageType:e})=>e==="user"?M(t):it(t)];streamingComponent;streamingToolSeparator;foldedToolSeparatorContents=new Map;pendingTools=new Map;bashComponent;activityLoader;projection=Rt();workingActivity=this.projection.workingActivity;runActive=!1;applyingSnapshot=!1;snapshotGeneration=0;deferredFrames=[];lastAssistantText;transcriptFilePaths=[];copyBlockRecords=[];copyIndex=new Map;condensedCopyBlocks=new WeakMap;constructor(t,e,s={}){if(this.tui=t,this.container=e,this.cwd=s.cwd??process.cwd(),this.showImages=s.showImages??!0,this.imageWidthCells=s.imageWidthCells??60,this.hideThinking=s.hideThinking??!1,this.hiddenThinkingLabel=s.hiddenThinkingLabel??"Thinking...",this.toolOutputExpanded=s.toolOutputExpanded??!1,this.liveCycles=s.liveCycles??Et(),this.condensedHistory=s.condensedHistory??Mt(),this.onFooterEvent=s.onFooterEvent,this.onActivityChange=s.onActivityChange,this.inlinePageBlocks=s.inlinePageBlocks??!1,this.pageOpenHint=s.pageOpenHint??(()=>"crtr human list"),this.backgroundBashHint=s.backgroundBashHint??(()=>null),this.recapPalette=s.palette??Wt,this.spinnerStyle=this.recapPalette.active,this.dimStyle=this.recapPalette.muted,this.errorStyle=this.recapPalette.error,s.banner&&s.banner.length>0){const i=new A;i.addChild(new d(1));for(const o of s.banner)i.addChild(new x(o,1,0));i.addChild(new d(1)),this.bannerContainer=i,this.container.addChild(i)}this.container.addChild(this.historyContainer),this.onActivityChange||this.container.addChild(this.statusContainer),this.transcript=new yt([...this.bannerContainer?[this.bannerContainer]:[],this.historyContainer,...this.onActivityChange?[]:[this.statusContainer]])}transcriptSource(){return this.transcript}async applySnapshot(t){const e=++this.snapshotGeneration;this.applyingSnapshot=!0,this.deferredFrames.length=0,this.resetChat(),this.projection=bt(t,this.projection),this.workingActivity=this.projection.workingActivity,this.runActive=this.projection.isStreaming,this.seedToolGroupSummaries(this.projection.toolGroupSummaryDetails);const s=new Map,i=this.projection.messages,o=i.length-1,n=gt(i,this.liveCycles);if(n>0){const r=await this.buildCondensedBlock(i.slice(0,n),e);if(e!==this.snapshotGeneration)return;r&&this.appendCondensedBlock(r)}for(let r=n;r<i.length;r++){if(!this.projection.isStreaming&&r>n&&(r-n)%_===0&&(await new Promise(l=>setImmediate(l)),e!==this.snapshotGeneration))return;const h=i[r];if(h.role==="assistant"){const l=c(h);l.trim()&&(this.lastAssistantText=l,this.pushTranscriptText(l));const P=r===o&&this.projection.isStreaming&&h.stopReason!=="aborted"&&h.stopReason!=="error",g=c(h).trim()!=="",D=this.assistantToolCalls(h),k=h.stopReason==="aborted"||h.stopReason==="error",y=w(h)?"Interrupted":h.errorMessage??"Error";if(k){for(const m of s.values()){const f={content:[{type:"text",text:y}],isError:!0};m.updateResult(f),this.registerCopyBlock(m,"tool",y),this.settleGroupTool(m,f,!0)}s.clear()}(g||k)&&this.closeOpenGroup();let b;P?(this.streamingComponent=new B(void 0,this.hideThinking,u(),this.hiddenThinkingLabel,this.markdownTransformers),this.appendAssistantPart(this.streamingComponent,!g),this.registerCopyBlock(this.streamingComponent,"assistant",""),this.streamingWasGroupMember=!g,this.streamingComponent.updateContent(h),this.registerCopyBlock(this.streamingComponent,"assistant",c(h)),b=this.streamingToolSeparator=this.appendAssistantSeparator(!g)):b=this.appendAssistantMessage(h,!g&&!k),b&&this.setAssistantSeparatorContent(b,h);for(const m of D){this.pushTranscriptValue(m.arguments);const f=this.appendToolComponent(m.name,m.id,m.arguments);h.stopReason==="aborted"||h.stopReason==="error"?(f.updateResult({content:[{type:"text",text:y}],isError:!0}),this.registerCopyBlock(f,"tool",y),this.settleGroupTool(f,{content:[{type:"text",text:y}],isError:!0},!0)):s.set(m.id,f)}k&&this.closeOpenGroup()}else if(h.role==="toolResult"){this.pushTranscriptText(this.userMessageText(h));const l=s.get(h.toolCallId);l&&(l.updateResult(h),this.registerCopyBlock(l,"tool",this.toolResultText(h)),this.historyContainer.markDirty(l),this.settleGroupTool(l,h,h.isError===!0),s.delete(h.toolCallId),this.maybeAppendPageBlock(h))}else this.addMessageToChat(h)}for(const[r,h]of s)this.pendingTools.set(r,h);this.applyToolDisplay(),this.projection.isStreaming&&this.setActivity(this.makeLoader(this.workingActivity)),this.tui.requestRender(),this.applyingSnapshot=!1,this.replayDeferredFrames()}async buildCondensedBlock(t,e){const s=new v,i=this.appendTarget,o=[];this.appendTarget=s,this.condensedCopyBlocks.set(s,o);try{let n=0;for(const r of t)if(ft(r,this.condensedHistory)){if(n>0&&n%_===0&&(await new Promise(h=>setImmediate(h)),e!==this.snapshotGeneration))return;n++,this.pushTranscriptText(this.userMessageText(r)),this.addMessageToChat(r)}}finally{this.appendTarget=i,this.condensedCopyBlocks.delete(s)}return s.children.length>0?{component:s,copyBlocks:o}:void 0}deferIfBuilding(t){return this.applyingSnapshot?(this.deferredFrames.push(t),!0):!1}replayDeferredFrames(){const t=this.deferredFrames.splice(0);for(const e of t)e()}setWorkingActivity(t){if(this.deferIfBuilding(()=>this.setWorkingActivity(t)))return;const e=this.projection.activity===this.workingActivity;this.projection=St(this.projection,t),this.workingActivity=this.projection.workingActivity,this.runActive&&e&&this.setActivity(this.makeLoader(this.workingActivity))}settleRun(){this.runActive=!1;for(const t of this.pendingTools.values())this.settleGroupTool(t);this.streamingComponent&&(this.historyContainer.removeChild(this.streamingComponent),this.unregisterCopyBlock(this.streamingComponent),this.streamingComponent=void 0),this.streamingToolSeparator=void 0,this.pendingTools.clear(),this.applyToolDisplay(),this.setActivity(void 0),this.settleBashComponent()}dispose(){this.settleRun()}toggleToolsExpanded(){let t;return this.summarizeToolCalls&&this.foldSettledTools?(this.showGroupSummaries=!this.showGroupSummaries,this.toolOutputExpanded=!this.showGroupSummaries,t={kind:"summaries",shown:this.showGroupSummaries}):(this.toolOutputExpanded=!this.toolOutputExpanded,t={kind:"output",expanded:this.toolOutputExpanded}),this.applyToolDisplay(),t}toggleFoldSettledTools(){return this.foldSettledTools=!this.foldSettledTools,Pt(this.foldSettledTools),this.summarizeToolCalls&&this.foldSettledTools&&(this.showGroupSummaries=!0),this.applyToolDisplay(),this.foldSettledTools}applyToolDisplay(){const t=new Set(this.pendingTools.values());for(const e of this.groups)for(const s of e.inFlight)t.add(s);for(const e of this.historyContainer.children)e instanceof G&&e.setMinimized(this.foldSettledTools&&!t.has(e)),Dt(e)&&e.setExpanded(this.toolOutputExpanded);for(const e of this.groups)this.applyGroupDisplay(e);this.updateFoldedToolSeparators(t),this.historyContainer.markDirty(),this.tui.requestRender()}toggleThinking(){this.hideThinking=!this.hideThinking;for(const t of this.historyContainer.children)t instanceof L&&t.setHideThinkingBlock(this.hideThinking);for(const[t,e]of this.foldedToolSeparatorContents)t.setSeparatesToolGroup(e.hasText||!this.hideThinking&&e.hasThinking);return this.historyContainer.markDirty(),this.tui.requestRender(),this.hideThinking}handleEvent(t){if(!this.deferIfBuilding(()=>this.handleEvent(t))){switch(this.projection=Gt(this.projection,t),t.type){case"agent_start":{this.runActive=this.projection.isStreaming;for(const e of this.pendingTools.values())this.settleGroupTool(e);this.pendingTools.clear(),this.setActivity(this.makeLoader(this.workingActivity));break}case"agent_end":{this.settleRun(),ut();break}case"agent_settled":{this.settleRun();break}case"message_start":{if(t.message.role==="custom"||t.message.role==="user")this.addMessageToChat(t.message);else if(t.message.role==="assistant"){const e=c(t.message).trim()!=="";e&&this.closeOpenGroup(),this.streamingComponent=new B(void 0,this.hideThinking,u(),this.hiddenThinkingLabel,this.markdownTransformers),this.streamingWasGroupMember=!e,this.appendAssistantPart(this.streamingComponent,!e),this.registerCopyBlock(this.streamingComponent,"assistant",""),this.streamingComponent.updateContent(t.message),this.registerCopyBlock(this.streamingComponent,"assistant",c(t.message)),this.streamingToolSeparator=this.appendAssistantSeparator(!e),this.setAssistantSeparatorContent(this.streamingToolSeparator,t.message)}break}case"message_update":{if(this.streamingComponent&&t.message.role==="assistant"){this.promoteStreamingAssistantToBoundary(t.message),this.streamingComponent.updateContent(t.message),this.registerCopyBlock(this.streamingComponent,"assistant",c(t.message)),this.historyContainer.markDirty(this.streamingComponent);const e=this.assistantToolCalls(t.message);this.streamingToolSeparator&&this.setAssistantSeparatorContent(this.streamingToolSeparator,t.message);for(const s of e){this.pushTranscriptValue(s.arguments);const i=this.pendingTools.get(s.id);if(i)i.updateArgs(s.arguments),this.noteGroupTool(i,s.name,s.arguments),this.historyContainer.markDirty(i);else{const o=this.appendToolComponent(s.name,s.id,s.arguments);this.pendingTools.set(s.id,o)}}}break}case"message_end":{if(t.message.role!=="assistant")break;const e=t.message.stopReason==="aborted"||t.message.stopReason==="error";if(this.promoteStreamingAssistantToBoundary(t.message,e),this.streamingComponent&&this.registerCopyBlock(this.streamingComponent,"assistant",c(t.message)),t.message.stopReason!=="aborted"&&t.message.stopReason!=="error"){const s=c(t.message);s.trim()&&(this.lastAssistantText=s,this.pushTranscriptText(s))}if(this.streamingComponent){const s=t.message.stopReason;let i=t.message.errorMessage;if(w(t.message)&&(i="Interrupted",t.message.errorMessage=i,t.message.stopReason="aborted"),this.streamingComponent.updateContent(t.message),s==="aborted"||s==="error"){const o=i??"Error";for(const n of this.pendingTools.values())n.updateResult({content:[{type:"text",text:o}],isError:!0}),this.registerCopyBlock(n,"tool",o),this.settleGroupTool(n,{content:[{type:"text",text:o}],isError:!0},!0),this.historyContainer.markDirty(n);this.pendingTools.clear()}else for(const o of this.pendingTools.values())o.setArgsComplete(),this.historyContainer.markDirty(o);this.historyContainer.markDirty(this.streamingComponent),this.streamingComponent=void 0,this.streamingToolSeparator=void 0}e&&(this.closeOpenGroup(),this.applyToolDisplay());break}case"tool_execution_start":{this.pushTranscriptValue(t.args);let e=this.pendingTools.get(t.toolCallId);e?this.noteGroupTool(e,t.toolName,t.args):(e=this.appendToolComponent(t.toolName,t.toolCallId,t.args),this.pendingTools.set(t.toolCallId,e)),e.markExecutionStarted(),this.historyContainer.markDirty(e);break}case"tool_execution_update":{const e=this.projection.partialToolResults.get(t.toolCallId)??t.partialResult;this.pushTranscriptValue(e);const s=this.pendingTools.get(t.toolCallId);s&&(s.updateResult(e,!0),this.registerCopyBlock(s,"tool",this.toolResultText(e)),this.historyContainer.markDirty(s));break}case"tool_execution_end":{const e=this.projection.partialToolResults.get(t.toolCallId)??t.result;this.pushTranscriptValue(e);const s=this.pendingTools.get(t.toolCallId);s&&(s.updateResult(e),this.registerCopyBlock(s,"tool",this.toolResultText(e)),this.pendingTools.delete(t.toolCallId),this.settleGroupTool(s,e,t.isError),this.applyToolDisplay(),this.historyContainer.markDirty(s),this.maybeAppendPageBlock(e));break}case"compaction_start":{const e=t.reason==="manual"?"Compacting context...":"Auto-compacting...";this.setActivity(this.makeLoader(e));break}case"compaction_end":{this.setActivity(this.runActive?this.makeLoader(this.workingActivity):void 0),t.aborted?this.showStatus(t.reason==="manual"?"Compaction cancelled":"Auto-compaction cancelled"):t.result?this.addMessageToChat({role:"compactionSummary",summary:t.result.summary,tokensBefore:t.result.tokensBefore,timestamp:Date.now()}):t.errorMessage&&this.showError(t.errorMessage);break}case"auto_retry_start":{const e=Math.ceil(t.delayMs/1e3);this.setActivity(this.makeLoader(`Retrying (${t.attempt}/${t.maxAttempts}) in ${e}s...`));break}case"auto_retry_end":{this.setActivity(this.runActive?this.makeLoader(this.workingActivity):void 0),t.success||this.showError(`Retry failed after ${t.attempt} attempts: ${t.finalError??"Unknown error"}`);break}case"queue_update":case"session_info_changed":case"thinking_level_changed":this.onFooterEvent?.(t);break;default:break}this.tui.requestRender()}}bashStart(t,e){if(this.deferIfBuilding(()=>this.bashStart(t,e)))return;this.projection=At(this.projection,t,e),this.closeOpenGroup(),this.settleBashComponent();let s;s=new E(t,this.componentTui(()=>s),e),this.bashComponent=s,this.append(s),this.tui.requestRender()}bashOutput(t){this.deferIfBuilding(()=>this.bashOutput(t))||(this.projection=Bt(this.projection,t),this.pushTranscriptText(t),this.bashComponent&&(this.bashComponent.appendOutput(t),this.historyContainer.markDirty(this.bashComponent)),this.tui.requestRender())}bashEnd(t){this.deferIfBuilding(()=>this.bashEnd(t))||(this.projection=wt(this.projection,t),this.settleBashComponent(t),this.tui.requestRender())}addMessageToChat(t){const e=tt(t);if(e!==null&&(t.role!=="custom"||t.display===!0)){this.pushTranscriptText(e.body);const s=e.senders.flatMap(o=>o.entries).filter(o=>o.disposition==="human-answer").map(o=>o.body.trim()).filter(o=>o!=="");if(!(s.length>0&&e.body.replace(Lt,"").trim()===""&&e.senders.every(o=>o.entries.every(n=>n.disposition==="human-answer")))){const o=z(e.kind),n=new U(e,o,this.toolOutputExpanded,this.dimStyle,r=>this.spinnerStyle(this.labelStyle(r)));et(e.kind)?(this.closeOpenGroup(),this.append(n)):this.appendGroupMember(n)?.activity.noteCard(e,o)}for(const o of s)this.appendHumanAnswer(o);return}switch(t.role){case"bashExecution":{this.closeOpenGroup(),this.pushTranscriptText(t.output??"");const s=new E(t.command,this.tui,t.excludeFromContext);t.output&&s.appendOutput(t.output),s.setComplete(t.exitCode,t.cancelled,t.truncated?{truncated:!0}:void 0,t.fullOutputPath),this.append(s);break}case"custom":{if(t.display){if(this.pushTranscriptText(this.userMessageText(t)),t.customType===K){this.appendGroupMember(new X(this.userMessageText(t),this.toolOutputExpanded,this.crtrOutputTheme()));break}if(t.customType===Z){this.closeOpenGroup(),this.append(new d(1)),this.append(new x(this.dimStyle(`\u2500\u2500 ${this.userMessageText(t)} \u2500\u2500`),1,0)),this.append(new d(1));break}const s=new $(ot(t),void 0,u());s.setExpanded(this.toolOutputExpanded),this.appendGroupMember(s)}break}case"compactionSummary":{this.closeOpenGroup(),this.append(new d(1));const s=new W(O(t),u());s.setExpanded(this.toolOutputExpanded),this.append(s);break}case"branchSummary":{this.closeOpenGroup(),this.append(new d(1));const s=new H(O(t),u());s.setExpanded(this.toolOutputExpanded),this.append(s),this.registerCopyBlock(s,"assistant",t.summary);break}case"user":{C(t)&&this.closeOpenGroup();const s=this.userMessageText(t);if(!s)break;this.pushTranscriptText(s),this.chatChildCount()>0&&this.appendUserPart(new d(1),!C(t));const i=q(s);if(i){const o=new V({...i,content:M(i.content)},u());if(o.setExpanded(this.toolOutputExpanded),this.appendUserPart(o,!C(t)),this.registerCopyBlock(o,"user",s),i.userMessage){const n=new S(i.userMessage,u(),void 0,this.markdownTransformers);this.appendUserPart(n,!C(t)),this.registerCopyBlock(n,"user",i.userMessage)}}else{const o=new S(s,u(),void 0,this.markdownTransformers);this.appendUserPart(o,!C(t)),this.registerCopyBlock(o,"user",s)}break}case"assistant":{const s=c(t).trim()!=="";s&&this.closeOpenGroup(),this.appendAssistantMessage(t,!s);break}default:break}}appendAssistantMessage(t,e=!1){const s=new B(void 0,this.hideThinking,u(),this.hiddenThinkingLabel,this.markdownTransformers),i=w(t)?{...t,stopReason:"aborted",errorMessage:"Interrupted"}:t;s.updateContent(i),this.appendAssistantPart(s,e),this.registerCopyBlock(s,"assistant",c(t));const o=this.appendAssistantSeparator(e);return this.setAssistantSeparatorContent(o,t),o}appendAssistantSeparator(t=!1){const e=new R;return t?this.appendGroupMember(e):this.append(e),e}appendAssistantPart(t,e){e?this.appendGroupMember(t):this.append(t)}appendUserPart(t,e){e?this.appendGroupMember(t):this.append(t)}appendHumanAnswer(t){this.closeOpenGroup(),this.chatChildCount()>0&&this.append(new d(1));const e=new S(t,u(),void 0,this.markdownTransformers);this.append(e),this.registerCopyBlock(e,"user",t)}isLiveGroupRegion(){return this.appendTarget===this.historyContainer}ensureGroup(){if(!this.isLiveGroupRegion())return;if(this.openGroup)return this.openGroup;const t=new at,e={members:[],recap:t,activity:new rt(this.cwd,this.nodeRoster),toolCount:0,inFlight:new Set};return this.append(t),this.historyContainer.setHidden(t,!0),this.groups.push(e),this.openGroup=e,e}closeOpenGroup(){this.openGroup=void 0}appendGroupMember(t){const e=this.ensureGroup();return this.append(t),e&&e.members.push(t),e}removeGroupMember(t){for(const e of this.groups){const s=e.members.indexOf(t);s!==-1&&e.members.splice(s,1)}this.historyContainer.setHidden(t,!1)}appendToolComponent(t,e,s){const i=this.isLiveGroupRegion()&&!this.openGroup&&this.historyContainer.children.at(-1)instanceof R?this.historyContainer.children.at(-1):void 0;i&&this.historyContainer.removeChild(i);const o=this.ensureGroup();i&&(this.append(i),o?.members.push(i));const n=this.makeToolComponent(t,e,s);return n.activityCallId=e,this.appendGroupMember(n),this.registerCopyBlock(n,"tool",""),o&&(o.key??=e,o.toolCount++,o.inFlight.add(n),o.activity.noteCall(e,t,s)),n}noteGroupTool(t,e,s){if(t.activityCallId)for(const i of this.groups)i.members.includes(t)&&i.activity.noteCall(t.activityCallId,e,s)}settleGroupTool(t,e,s=!1){for(const i of this.groups)i.inFlight.delete(t),!(!t.activityCallId||!i.members.includes(t))&&(e===void 0?i.activity.resolveWithoutResult(t.activityCallId):i.activity.settle(t.activityCallId,e,s))}promoteStreamingAssistantToBoundary(t,e=!1){!this.streamingWasGroupMember||!e&&c(t).trim()===""||(this.streamingComponent&&this.removeGroupMember(this.streamingComponent),this.streamingToolSeparator&&this.removeGroupMember(this.streamingToolSeparator),this.streamingWasGroupMember=!1,this.closeOpenGroup())}seedToolGroupSummaries(t){this.groupSummaries.clear();for(const[e,s]of Object.entries(t))this.groupSummaries.set(e,s)}applyToolGroupSummary(t,e){if(this.deferIfBuilding(()=>this.applyToolGroupSummary(t,e)))return;this.projection=xt(this.projection,t,e);const s=this.projection.toolGroupSummaryDetails[t];s!==void 0&&(this.groupSummaries.set(t,s),this.applyToolDisplay())}applyGroupDisplay(t){const e=t.key===void 0?void 0:this.groupSummaries.get(t.key),s=this.foldSettledTools&&this.showGroupSummaries&&t.toolCount>0&&t.inFlight.size===0&&e!==void 0;t.recap.setRecap(s?e:void 0,t.toolCount,t.activity.activity(),this.detailedToolRecaps,this.recapPalette),this.historyContainer.setHidden(t.recap,!s);for(const i of t.members)this.historyContainer.setHidden(i,s)}updateFoldedToolSeparators(t=new Set(this.pendingTools.values())){const e=this.historyContainer.children;for(let s=0;s<e.length;s++){const i=e[s];if(!(i instanceof R))continue;const o=e[s+1];i.setFolded(this.foldSettledTools&&!this.historyContainer.hiddenChildren.has(i)&&o instanceof G&&!this.historyContainer.hiddenChildren.has(o)&&!t.has(o)),this.historyContainer.markDirty(i)}}setAssistantSeparatorContent(t,e){const s=e.content,i=Array.isArray(s)?s:[],o=i.some(r=>typeof r=="object"&&r!==null&&r.type==="text"&&typeof r.text=="string"&&r.text.trim()!==""),n=i.some(r=>typeof r=="object"&&r!==null&&r.type==="thinking"&&typeof r.thinking=="string"&&r.thinking.trim()!=="");this.foldedToolSeparatorContents.set(t,{hasText:o,hasThinking:n}),t.setSeparatesToolGroup(o||!this.hideThinking&&n)}makeToolComponent(t,e,s){const i=new ht;let o,n;if(t==="bash"){const h=Q(s,i);h===void 0?n=lt(this.cwd,i,this.backgroundBashHint):n=h.definition}else if(t==="edit"){const h=nt(this.cwd,i);n=h.definition,o=h.observeResult}else t==="read"?n=dt(this.cwd,i):t==="write"&&(n=ct(this.cwd,i));let r;return r=new G(t,e,s,{showImages:this.showImages,imageWidthCells:this.imageWidthCells},n,this.componentTui(()=>r),this.cwd),r.setToolView(n===void 0?void 0:i,o),r.setExpanded(this.toolOutputExpanded),r}append(t){this.appendTarget.addChild(t)}chatChildCount(){return this.appendTarget.children.length}resetChat(){this.setActivity(void 0),this.settleBashComponent(),this.streamingComponent=void 0,this.streamingToolSeparator=void 0,this.streamingWasGroupMember=!1,this.foldedToolSeparatorContents.clear(),this.groups.length=0,this.openGroup=void 0,this.groupSummaries.clear(),this.nodeRoster.clear(),this.pendingTools.clear(),this.lastAssistantText=void 0,this.copyBlockRecords.length=0,this.copyIndex.clear(),this.transcriptFilePaths.length=0,this.pageBlocks.clear(),this.historyContainer.clear()}maybeAppendPageBlock(t){if(!this.inlinePageBlocks||this.appendTarget!==this.historyContainer)return;const e=Y(t);if(e===void 0||this.pageBlocks.has(e.pageId))return;const s=new J(e.pageId,this.pageOpenHint);this.pageBlocks.set(e.pageId,s),this.append(s),this.loadPageBlock(s)}async loadPageBlock(t){await t.refresh()&&(this.historyContainer.markDirty(t),this.tui.requestRender())}refreshInFlightTools(){if(this.pendingTools.size!==0){for(const t of this.pendingTools.values())this.historyContainer.markDirty(t);this.tui.requestRender()}}async refreshPageBlocks(){const t=[...this.pageBlocks.values()];(await Promise.all(t.map(async s=>{const i=await s.refresh();return i&&this.historyContainer.markDirty(s),i}))).some(Boolean)&&this.tui.requestRender()}makeLoader(t){let e;const s={requestRender:p(i=>{e&&!this.onActivityChange&&this.statusContainer.markDirty(e),this.tui.requestRender(i)},"requestRender"),terminal:this.tui.terminal};return e=new F(s,this.spinnerStyle,this.dimStyle,t),e}componentTui(t){return{requestRender:p(e=>{this.historyContainer.markDirty(t()),this.tui.requestRender(e)},"requestRender"),terminal:this.tui.terminal}}settleBashComponent(t){if(!this.bashComponent)return;const e=this.bashComponent;e.setComplete(t?.exitCode,t?.cancelled??!0,t?.truncated?{truncated:!0}:void 0,t?.fullOutputPath),this.historyContainer.markDirty(e),this.bashComponent=void 0}setActivity(t){if(this.activityLoader?.stop(),this.activityLoader=t,this.onActivityChange){this.onActivityChange(t);return}this.statusContainer.clear(),t&&this.statusContainer.addChild(t)}showStatus(t){this.closeOpenGroup(),this.append(new d(1)),this.append(new x(this.dimStyle(t),1,0))}showError(t){this.deferIfBuilding(()=>this.showError(t))||(this.closeOpenGroup(),this.append(new d(1)),this.append(new x(this.errorStyle(t),1,0)),this.tui.requestRender())}crtrOutputTheme(){return{fg:p((t,e)=>t==="error"?this.errorStyle(e):t==="warning"||t==="accent"||t==="toolTitle"||t==="success"?this.spinnerStyle(e):t==="muted"?this.dimStyle(e):e,"fg"),bg:p((t,e)=>e,"bg"),bold:p(t=>this.labelStyle(t),"bold")}}assistantToolCalls(t){const e=t.content;return Array.isArray(e)?e.filter(s=>typeof s=="object"&&s!==null&&s.type==="toolCall"):[]}getTranscriptFilePathsNewestFirst(){return[...this.transcriptFilePaths]}getLastAssistantText(){const t=this.lastAssistantText?.trim();return t||void 0}blockText(t){const e=this.copyIndex.get(t);return e===void 0?void 0:this.copyBlockRecords[e]?.text}copyBlocks(){return this.copyBlockRecords}getLastToolOutputText(){for(let t=this.copyBlockRecords.length-1;t>=0;t--){const e=this.copyBlockRecords[t];if(e.kind==="tool")return e.text.trim()===""?void 0:e.text}}getTranscriptPlainText(){return this.copyBlockRecords.map(t=>t.text).filter(t=>t.trim()!=="").join(`
1
+ var v=Object.defineProperty;var p=(a,t)=>v(a,"name",{value:t,configurable:!0});import{Container as j,Loader as F,Spacer as d,Text as x}from"@earendil-works/pi-tui";import{AssistantMessageComponent as L,BashExecutionComponent as M,BranchSummaryMessageComponent as H,CompactionSummaryMessageComponent as W,CustomMessageComponent as $,parseSkillBlock as q,SkillInvocationMessageComponent as N,ToolExecutionComponent as V,UserMessageComponent as S}from"@earendil-works/pi-coding-agent";import{attachMarkdownTheme as u}from"../config.js";import{ContextMessageComponent as U}from"./context-message.js";import{presentationFor as z}from"./card-presentation.js";import{detectInlinePageResult as Y,PageBlockComponent as J}from"./page-block.js";import{CRTR_OUTPUT_CUSTOM_TYPE as K,CrtrOutputMessageComponent as X,createCrtrBashToolDefinition as Q}from"./crtr-output.js";import{CRTR_CYCLE_DIVIDER_CUSTOM_TYPE as Z,endedByAbort as w}from"../../../core/runtime/session-cycles.js";import{parseCard as tt}from"../../../shared/generated-context.js";import{assistantVisibleText as c,isGroupBoundaryKind as et,isTrueUserMessage as C}from"../../../shared/tool-groups.js";import{transformDiagramFences as st}from"./diagram.js";import{styleAttachAgentMarkdown as it,styleAttachMarkdownSource as E,styleAttachMessageMarkdown as ot,styleAttachSummaryMarkdown as O}from"./markdown-source.js";import{createCrtrEditToolDefinition as nt}from"./edit-diff.js";import{GroupActivityRecorder as rt}from"./group-activity.js";import{GroupRecapComponent as at}from"./group-recap.js";import{FoldedToolCallController as ht,bashCallBackgroundHintLines as pt,createCrtrPlainBashToolDefinition as lt,createCrtrReadToolDefinition as dt,createCrtrWriteToolDefinition as ct}from"./tool-calls.js";import{ringCompletionBell as ut}from"../chrome/completion-bell.js";import{extractFilePaths as mt}from"#core/human/visible-paths";import{extractDocRefs as ft}from"./doc-links.js";import{keepWhenCondensed as gt,liveRegionStart as yt}from"./condensed-history.js";import{ViewerAssistantMessageComponent as B}from"./assistant-message.js";import{CompositeViewportSource as Ct,MeasuredContainer as R}from"./measured-container.js";import{readConfig as T,updateRawConfigAtomically as Tt}from"../../../core/config.js";import{DEFAULT_CONDENSED_HISTORY as kt,DEFAULT_LIVE_CYCLES as bt}from"../../../types.js";import{applySnapshot as xt,applyToolGroupSummary as St,applyWorkingActivity as wt,bashEnd as Bt,bashOutput as Rt,bashStart as At,initialConvState as Gt,reduce as Mt}from"../../conversation/projection.js";const I=p(a=>`\x1B[2m${a}\x1B[22m`,"defaultDimStyle"),D=50;function Et(){try{return T("user").live_cycles}catch{return bt}}p(Et,"readLiveCycles");function Ot(){try{return T("user").condensed_history}catch{return kt}}p(Ot,"readCondensedHistory");function It(){try{return T("user").fold_finished_tools}catch{return!1}}p(It,"readFoldFinishedTools");function Dt(){try{return T("user").summarize_tool_calls}catch{return!1}}p(Dt,"readSummarizeToolCalls");function _t(){try{return T("user").detailed_tool_recaps}catch{return!0}}p(_t,"readDetailedToolRecaps");function Pt(a){try{Tt("user",t=>({...t,fold_finished_tools:a}))}catch{}}p(Pt,"persistFoldFinishedTools");function vt(a){return typeof a=="object"&&a!==null&&"setExpanded"in a&&typeof a.setExpanded=="function"}p(vt,"isExpandable");const jt=/\x1b\[[0-9;]*m/g,Ft=/\x1b\[([0-9;]*)m/g;function Lt(a){return a.replace(Ft,(t,e)=>{const s=e.split(";"),i=[];for(let o=0;o<s.length;o++){const n=Number(s[o]===""?0:s[o]);if(n===38||n===48||n===58){const r=Number(s[o+1]),h=o+(r===5?2:r===2?4:1);n!==48&&i.push(...s.slice(o,h+1)),o=h;continue}n>=40&&n<=47||n>=100&&n<=107||i.push(String(n))}return i.length>0?`\x1B[${i.join(";")}m`:""})}p(Lt,"stripBackground");const Ht=/<from\b[^>]*>[\s\S]*?<\/from>/g;class A extends d{static{p(this,"FoldedToolSeparator")}folded=!1;separatesToolGroup=!1;setFolded(t){this.folded=t,this.refresh()}setSeparatesToolGroup(t){this.separatesToolGroup=t,this.refresh()}refresh(){this.setLines(this.folded&&this.separatesToolGroup?1:0)}}class G extends V{static{p(this,"MinimizableToolComponent")}activityCallId;minimized=!1;expandedState=!1;foldController;resultObserver;setToolView(t,e){this.foldController=t,this.resultObserver=e}updateResult(...t){this.resultObserver?.(t[0],t[1]??!1),super.updateResult(...t)}setExpanded(t){this.expandedState=t,super.setExpanded(t)}setMinimized(t){!this.foldController||this.minimized===t||(this.minimized=t,this.foldController.setFolded(t),super.setExpanded(this.expandedState))}render(t){if(!this.minimized)return[...super.render(t),...pt(this.foldController?.callComponent(),t)];const e=this.foldController?.callComponent();return e?e.render(t).filter(s=>s.replace(jt,"").trim().length>0).map(s=>Lt(s).trimEnd()):super.render(t)}}const Wt=p(a=>`\x1B[31m${a}\x1B[39m`,"defaultErrorStyle"),$t={accent:p(a=>`\x1B[33m${a}\x1B[39m`,"accent"),active:p(a=>`\x1B[36m${a}\x1B[39m`,"active"),info:p(a=>`\x1B[34m${a}\x1B[39m`,"info"),muted:I,faint:I,border:p(a=>a,"border"),surface:p(a=>a,"surface"),bold:p(a=>`\x1B[1m${a}\x1B[22m`,"bold"),error:Wt,warning:p(a=>`\x1B[33m${a}\x1B[39m`,"warning"),diffAdded:p(a=>`\x1B[32m${a}\x1B[39m`,"diffAdded"),diffRemoved:p(a=>`\x1B[91m${a}\x1B[39m`,"diffRemoved"),bashMode:p(a=>`\x1B[32m${a}\x1B[39m`,"bashMode"),bashModeAlt:p(a=>`\x1B[92m${a}\x1B[39m`,"bashModeAlt")};class fe{static{p(this,"ChatView")}tui;container;historyContainer=new R;statusContainer=new R;bannerContainer;transcript;appendTarget=this.historyContainer;pageBlocks=new Map;inlinePageBlocks;pageOpenHint;backgroundBashHint;liveCycles;condensedHistory;cwd;showImages;imageWidthCells;hideThinking;hiddenThinkingLabel;toolOutputExpanded;foldSettledTools=It();summarizeToolCalls=Dt();detailedToolRecaps=_t();showGroupSummaries=this.summarizeToolCalls&&this.foldSettledTools;groups=[];openGroup;groupSummaries=new Map;nodeRoster=new Map;streamingWasGroupMember=!1;onFooterEvent;onActivityChange;spinnerStyle;dimStyle;errorStyle;recapPalette;labelStyle=p(t=>`\x1B[1m${t}\x1B[22m`,"labelStyle");markdownTransformers=[(t,{messageType:e,availableWidth:s})=>e==="assistant"?st(t,s):t,(t,{messageType:e})=>e==="user"?E(t):it(t)];streamingComponent;streamingToolSeparator;foldedToolSeparatorContents=new Map;pendingTools=new Map;bashComponent;activityLoader;projection=Gt();workingActivity=this.projection.workingActivity;runActive=!1;applyingSnapshot=!1;snapshotGeneration=0;deferredFrames=[];lastAssistantText;transcriptFilePaths=[];transcriptDocRefs=[];copyBlockRecords=[];copyIndex=new Map;condensedCopyBlocks=new WeakMap;constructor(t,e,s={}){if(this.tui=t,this.container=e,this.cwd=s.cwd??process.cwd(),this.showImages=s.showImages??!0,this.imageWidthCells=s.imageWidthCells??60,this.hideThinking=s.hideThinking??!1,this.hiddenThinkingLabel=s.hiddenThinkingLabel??"Thinking...",this.toolOutputExpanded=s.toolOutputExpanded??!1,this.liveCycles=s.liveCycles??Et(),this.condensedHistory=s.condensedHistory??Ot(),this.onFooterEvent=s.onFooterEvent,this.onActivityChange=s.onActivityChange,this.inlinePageBlocks=s.inlinePageBlocks??!1,this.pageOpenHint=s.pageOpenHint??(()=>"crtr human list"),this.backgroundBashHint=s.backgroundBashHint??(()=>null),this.recapPalette=s.palette??$t,this.spinnerStyle=this.recapPalette.active,this.dimStyle=this.recapPalette.muted,this.errorStyle=this.recapPalette.error,s.banner&&s.banner.length>0){const i=new R;i.addChild(new d(1));for(const o of s.banner)i.addChild(new x(o,1,0));i.addChild(new d(1)),this.bannerContainer=i,this.container.addChild(i)}this.container.addChild(this.historyContainer),this.onActivityChange||this.container.addChild(this.statusContainer),this.transcript=new Ct([...this.bannerContainer?[this.bannerContainer]:[],this.historyContainer,...this.onActivityChange?[]:[this.statusContainer]])}transcriptSource(){return this.transcript}async applySnapshot(t){const e=++this.snapshotGeneration;this.applyingSnapshot=!0,this.deferredFrames.length=0,this.resetChat(),this.projection=xt(t,this.projection),this.workingActivity=this.projection.workingActivity,this.runActive=this.projection.isStreaming,this.seedToolGroupSummaries(this.projection.toolGroupSummaryDetails);const s=new Map,i=this.projection.messages,o=i.length-1,n=yt(i,this.liveCycles);if(n>0){const r=await this.buildCondensedBlock(i.slice(0,n),e);if(e!==this.snapshotGeneration)return;r&&this.appendCondensedBlock(r)}for(let r=n;r<i.length;r++){if(!this.projection.isStreaming&&r>n&&(r-n)%D===0&&(await new Promise(l=>setImmediate(l)),e!==this.snapshotGeneration))return;const h=i[r];if(h.role==="assistant"){const l=c(h);l.trim()&&(this.lastAssistantText=l,this.pushTranscriptText(l));const _=r===o&&this.projection.isStreaming&&h.stopReason!=="aborted"&&h.stopReason!=="error",g=c(h).trim()!=="",P=this.assistantToolCalls(h),k=h.stopReason==="aborted"||h.stopReason==="error",y=w(h)?"Interrupted":h.errorMessage??"Error";if(k){for(const m of s.values()){const f={content:[{type:"text",text:y}],isError:!0};m.updateResult(f),this.registerCopyBlock(m,"tool",y),this.settleGroupTool(m,f,!0)}s.clear()}(g||k)&&this.closeOpenGroup();let b;_?(this.streamingComponent=new B(void 0,this.hideThinking,u(),this.hiddenThinkingLabel,this.markdownTransformers),this.appendAssistantPart(this.streamingComponent,!g),this.registerCopyBlock(this.streamingComponent,"assistant",""),this.streamingWasGroupMember=!g,this.streamingComponent.updateContent(h),this.registerCopyBlock(this.streamingComponent,"assistant",c(h)),b=this.streamingToolSeparator=this.appendAssistantSeparator(!g)):b=this.appendAssistantMessage(h,!g&&!k),b&&this.setAssistantSeparatorContent(b,h);for(const m of P){this.pushTranscriptValue(m.arguments);const f=this.appendToolComponent(m.name,m.id,m.arguments);h.stopReason==="aborted"||h.stopReason==="error"?(f.updateResult({content:[{type:"text",text:y}],isError:!0}),this.registerCopyBlock(f,"tool",y),this.settleGroupTool(f,{content:[{type:"text",text:y}],isError:!0},!0)):s.set(m.id,f)}k&&this.closeOpenGroup()}else if(h.role==="toolResult"){this.pushTranscriptText(this.userMessageText(h));const l=s.get(h.toolCallId);l&&(l.updateResult(h),this.registerCopyBlock(l,"tool",this.toolResultText(h)),this.historyContainer.markDirty(l),this.settleGroupTool(l,h,h.isError===!0),s.delete(h.toolCallId),this.maybeAppendPageBlock(h))}else this.addMessageToChat(h)}for(const[r,h]of s)this.pendingTools.set(r,h);this.applyToolDisplay(),this.projection.isStreaming&&this.setActivity(this.makeLoader(this.workingActivity)),this.tui.requestRender(),this.applyingSnapshot=!1,this.replayDeferredFrames()}async buildCondensedBlock(t,e){const s=new j,i=this.appendTarget,o=[];this.appendTarget=s,this.condensedCopyBlocks.set(s,o);try{let n=0;for(const r of t)if(gt(r,this.condensedHistory)){if(n>0&&n%D===0&&(await new Promise(h=>setImmediate(h)),e!==this.snapshotGeneration))return;n++,this.pushTranscriptText(this.userMessageText(r)),this.addMessageToChat(r)}}finally{this.appendTarget=i,this.condensedCopyBlocks.delete(s)}return s.children.length>0?{component:s,copyBlocks:o}:void 0}deferIfBuilding(t){return this.applyingSnapshot?(this.deferredFrames.push(t),!0):!1}replayDeferredFrames(){const t=this.deferredFrames.splice(0);for(const e of t)e()}setWorkingActivity(t){if(this.deferIfBuilding(()=>this.setWorkingActivity(t)))return;const e=this.projection.activity===this.workingActivity;this.projection=wt(this.projection,t),this.workingActivity=this.projection.workingActivity,this.runActive&&e&&this.setActivity(this.makeLoader(this.workingActivity))}settleRun(){this.runActive=!1;for(const t of this.pendingTools.values())this.settleGroupTool(t);this.streamingComponent&&(this.historyContainer.removeChild(this.streamingComponent),this.unregisterCopyBlock(this.streamingComponent),this.streamingComponent=void 0),this.streamingToolSeparator=void 0,this.pendingTools.clear(),this.applyToolDisplay(),this.setActivity(void 0),this.settleBashComponent()}dispose(){this.settleRun()}toggleToolsExpanded(){let t;return this.summarizeToolCalls&&this.foldSettledTools?(this.showGroupSummaries=!this.showGroupSummaries,this.toolOutputExpanded=!this.showGroupSummaries,t={kind:"summaries",shown:this.showGroupSummaries}):(this.toolOutputExpanded=!this.toolOutputExpanded,t={kind:"output",expanded:this.toolOutputExpanded}),this.applyToolDisplay(),t}toggleFoldSettledTools(){return this.foldSettledTools=!this.foldSettledTools,Pt(this.foldSettledTools),this.summarizeToolCalls&&this.foldSettledTools&&(this.showGroupSummaries=!0),this.applyToolDisplay(),this.foldSettledTools}applyToolDisplay(){const t=new Set(this.pendingTools.values());for(const e of this.groups)for(const s of e.inFlight)t.add(s);for(const e of this.historyContainer.children)e instanceof G&&e.setMinimized(this.foldSettledTools&&!t.has(e)),vt(e)&&e.setExpanded(this.toolOutputExpanded);for(const e of this.groups)this.applyGroupDisplay(e);this.updateFoldedToolSeparators(t),this.historyContainer.markDirty(),this.tui.requestRender()}toggleThinking(){this.hideThinking=!this.hideThinking;for(const t of this.historyContainer.children)t instanceof L&&t.setHideThinkingBlock(this.hideThinking);for(const[t,e]of this.foldedToolSeparatorContents)t.setSeparatesToolGroup(e.hasText||!this.hideThinking&&e.hasThinking);return this.historyContainer.markDirty(),this.tui.requestRender(),this.hideThinking}handleEvent(t){if(!this.deferIfBuilding(()=>this.handleEvent(t))){switch(this.projection=Mt(this.projection,t),t.type){case"agent_start":{this.runActive=this.projection.isStreaming;for(const e of this.pendingTools.values())this.settleGroupTool(e);this.pendingTools.clear(),this.setActivity(this.makeLoader(this.workingActivity));break}case"agent_end":{this.settleRun(),ut();break}case"agent_settled":{this.settleRun();break}case"message_start":{if(t.message.role==="custom"||t.message.role==="user")this.addMessageToChat(t.message);else if(t.message.role==="assistant"){const e=c(t.message).trim()!=="";e&&this.closeOpenGroup(),this.streamingComponent=new B(void 0,this.hideThinking,u(),this.hiddenThinkingLabel,this.markdownTransformers),this.streamingWasGroupMember=!e,this.appendAssistantPart(this.streamingComponent,!e),this.registerCopyBlock(this.streamingComponent,"assistant",""),this.streamingComponent.updateContent(t.message),this.registerCopyBlock(this.streamingComponent,"assistant",c(t.message)),this.streamingToolSeparator=this.appendAssistantSeparator(!e),this.setAssistantSeparatorContent(this.streamingToolSeparator,t.message)}break}case"message_update":{if(this.streamingComponent&&t.message.role==="assistant"){this.promoteStreamingAssistantToBoundary(t.message),this.streamingComponent.updateContent(t.message),this.registerCopyBlock(this.streamingComponent,"assistant",c(t.message)),this.historyContainer.markDirty(this.streamingComponent);const e=this.assistantToolCalls(t.message);this.streamingToolSeparator&&this.setAssistantSeparatorContent(this.streamingToolSeparator,t.message);for(const s of e){this.pushTranscriptValue(s.arguments);const i=this.pendingTools.get(s.id);if(i)i.updateArgs(s.arguments),this.noteGroupTool(i,s.name,s.arguments),this.historyContainer.markDirty(i);else{const o=this.appendToolComponent(s.name,s.id,s.arguments);this.pendingTools.set(s.id,o)}}}break}case"message_end":{if(t.message.role!=="assistant")break;const e=t.message.stopReason==="aborted"||t.message.stopReason==="error";if(this.promoteStreamingAssistantToBoundary(t.message,e),this.streamingComponent&&this.registerCopyBlock(this.streamingComponent,"assistant",c(t.message)),t.message.stopReason!=="aborted"&&t.message.stopReason!=="error"){const s=c(t.message);s.trim()&&(this.lastAssistantText=s,this.pushTranscriptText(s))}if(this.streamingComponent){const s=t.message.stopReason;let i=t.message.errorMessage;if(w(t.message)&&(i="Interrupted",t.message.errorMessage=i,t.message.stopReason="aborted"),this.streamingComponent.updateContent(t.message),s==="aborted"||s==="error"){const o=i??"Error";for(const n of this.pendingTools.values())n.updateResult({content:[{type:"text",text:o}],isError:!0}),this.registerCopyBlock(n,"tool",o),this.settleGroupTool(n,{content:[{type:"text",text:o}],isError:!0},!0),this.historyContainer.markDirty(n);this.pendingTools.clear()}else for(const o of this.pendingTools.values())o.setArgsComplete(),this.historyContainer.markDirty(o);this.historyContainer.markDirty(this.streamingComponent),this.streamingComponent=void 0,this.streamingToolSeparator=void 0}e&&(this.closeOpenGroup(),this.applyToolDisplay());break}case"tool_execution_start":{this.pushTranscriptValue(t.args);let e=this.pendingTools.get(t.toolCallId);e?this.noteGroupTool(e,t.toolName,t.args):(e=this.appendToolComponent(t.toolName,t.toolCallId,t.args),this.pendingTools.set(t.toolCallId,e)),e.markExecutionStarted(),this.historyContainer.markDirty(e);break}case"tool_execution_update":{const e=this.projection.partialToolResults.get(t.toolCallId)??t.partialResult;this.pushTranscriptValue(e);const s=this.pendingTools.get(t.toolCallId);s&&(s.updateResult(e,!0),this.registerCopyBlock(s,"tool",this.toolResultText(e)),this.historyContainer.markDirty(s));break}case"tool_execution_end":{const e=this.projection.partialToolResults.get(t.toolCallId)??t.result;this.pushTranscriptValue(e);const s=this.pendingTools.get(t.toolCallId);s&&(s.updateResult(e),this.registerCopyBlock(s,"tool",this.toolResultText(e)),this.pendingTools.delete(t.toolCallId),this.settleGroupTool(s,e,t.isError),this.applyToolDisplay(),this.historyContainer.markDirty(s),this.maybeAppendPageBlock(e));break}case"compaction_start":{const e=t.reason==="manual"?"Compacting context...":"Auto-compacting...";this.setActivity(this.makeLoader(e));break}case"compaction_end":{this.setActivity(this.runActive?this.makeLoader(this.workingActivity):void 0),t.aborted?this.showStatus(t.reason==="manual"?"Compaction cancelled":"Auto-compaction cancelled"):t.result?this.addMessageToChat({role:"compactionSummary",summary:t.result.summary,tokensBefore:t.result.tokensBefore,timestamp:Date.now()}):t.errorMessage&&this.showError(t.errorMessage);break}case"auto_retry_start":{const e=Math.ceil(t.delayMs/1e3);this.setActivity(this.makeLoader(`Retrying (${t.attempt}/${t.maxAttempts}) in ${e}s...`));break}case"auto_retry_end":{this.setActivity(this.runActive?this.makeLoader(this.workingActivity):void 0),t.success||this.showError(`Retry failed after ${t.attempt} attempts: ${t.finalError??"Unknown error"}`);break}case"queue_update":case"session_info_changed":case"thinking_level_changed":this.onFooterEvent?.(t);break;default:break}this.tui.requestRender()}}bashStart(t,e){if(this.deferIfBuilding(()=>this.bashStart(t,e)))return;this.projection=At(this.projection,t,e),this.closeOpenGroup(),this.settleBashComponent();let s;s=new M(t,this.componentTui(()=>s),e),this.bashComponent=s,this.append(s),this.tui.requestRender()}bashOutput(t){this.deferIfBuilding(()=>this.bashOutput(t))||(this.projection=Rt(this.projection,t),this.pushTranscriptText(t),this.bashComponent&&(this.bashComponent.appendOutput(t),this.historyContainer.markDirty(this.bashComponent)),this.tui.requestRender())}bashEnd(t){this.deferIfBuilding(()=>this.bashEnd(t))||(this.projection=Bt(this.projection,t),this.settleBashComponent(t),this.tui.requestRender())}addMessageToChat(t){const e=tt(t);if(e!==null&&(t.role!=="custom"||t.display===!0)){this.pushTranscriptText(e.body);const s=e.senders.flatMap(o=>o.entries).filter(o=>o.disposition==="human-answer").map(o=>o.body.trim()).filter(o=>o!=="");if(!(s.length>0&&e.body.replace(Ht,"").trim()===""&&e.senders.every(o=>o.entries.every(n=>n.disposition==="human-answer")))){const o=z(e.kind),n=new U(e,o,this.toolOutputExpanded,this.dimStyle,r=>this.spinnerStyle(this.labelStyle(r)));et(e.kind)?(this.closeOpenGroup(),this.append(n)):this.appendGroupMember(n)?.activity.noteCard(e,o)}for(const o of s)this.appendHumanAnswer(o);return}switch(t.role){case"bashExecution":{this.closeOpenGroup(),this.pushTranscriptText(t.output??"");const s=new M(t.command,this.tui,t.excludeFromContext);t.output&&s.appendOutput(t.output),s.setComplete(t.exitCode,t.cancelled,t.truncated?{truncated:!0}:void 0,t.fullOutputPath),this.append(s);break}case"custom":{if(t.display){if(this.pushTranscriptText(this.userMessageText(t)),t.customType===K){this.appendGroupMember(new X(this.userMessageText(t),this.toolOutputExpanded,this.crtrOutputTheme()));break}if(t.customType===Z){this.closeOpenGroup(),this.append(new d(1)),this.append(new x(this.dimStyle(`\u2500\u2500 ${this.userMessageText(t)} \u2500\u2500`),1,0)),this.append(new d(1));break}const s=new $(ot(t),void 0,u());s.setExpanded(this.toolOutputExpanded),this.appendGroupMember(s)}break}case"compactionSummary":{this.closeOpenGroup(),this.append(new d(1));const s=new W(O(t),u());s.setExpanded(this.toolOutputExpanded),this.append(s);break}case"branchSummary":{this.closeOpenGroup(),this.append(new d(1));const s=new H(O(t),u());s.setExpanded(this.toolOutputExpanded),this.append(s),this.registerCopyBlock(s,"assistant",t.summary);break}case"user":{C(t)&&this.closeOpenGroup();const s=this.userMessageText(t);if(!s)break;this.pushTranscriptText(s),this.chatChildCount()>0&&this.appendUserPart(new d(1),!C(t));const i=q(s);if(i){const o=new N({...i,content:E(i.content)},u());if(o.setExpanded(this.toolOutputExpanded),this.appendUserPart(o,!C(t)),this.registerCopyBlock(o,"user",s),i.userMessage){const n=new S(i.userMessage,u(),void 0,this.markdownTransformers);this.appendUserPart(n,!C(t)),this.registerCopyBlock(n,"user",i.userMessage)}}else{const o=new S(s,u(),void 0,this.markdownTransformers);this.appendUserPart(o,!C(t)),this.registerCopyBlock(o,"user",s)}break}case"assistant":{const s=c(t).trim()!=="";s&&this.closeOpenGroup(),this.appendAssistantMessage(t,!s);break}default:break}}appendAssistantMessage(t,e=!1){const s=new B(void 0,this.hideThinking,u(),this.hiddenThinkingLabel,this.markdownTransformers),i=w(t)?{...t,stopReason:"aborted",errorMessage:"Interrupted"}:t;s.updateContent(i),this.appendAssistantPart(s,e),this.registerCopyBlock(s,"assistant",c(t));const o=this.appendAssistantSeparator(e);return this.setAssistantSeparatorContent(o,t),o}appendAssistantSeparator(t=!1){const e=new A;return t?this.appendGroupMember(e):this.append(e),e}appendAssistantPart(t,e){e?this.appendGroupMember(t):this.append(t)}appendUserPart(t,e){e?this.appendGroupMember(t):this.append(t)}appendHumanAnswer(t){this.closeOpenGroup(),this.chatChildCount()>0&&this.append(new d(1));const e=new S(t,u(),void 0,this.markdownTransformers);this.append(e),this.registerCopyBlock(e,"user",t)}isLiveGroupRegion(){return this.appendTarget===this.historyContainer}ensureGroup(){if(!this.isLiveGroupRegion())return;if(this.openGroup)return this.openGroup;const t=new at,e={members:[],recap:t,activity:new rt(this.cwd,this.nodeRoster),toolCount:0,inFlight:new Set};return this.append(t),this.historyContainer.setHidden(t,!0),this.groups.push(e),this.openGroup=e,e}closeOpenGroup(){this.openGroup=void 0}appendGroupMember(t){const e=this.ensureGroup();return this.append(t),e&&e.members.push(t),e}removeGroupMember(t){for(const e of this.groups){const s=e.members.indexOf(t);s!==-1&&e.members.splice(s,1)}this.historyContainer.setHidden(t,!1)}appendToolComponent(t,e,s){const i=this.isLiveGroupRegion()&&!this.openGroup&&this.historyContainer.children.at(-1)instanceof A?this.historyContainer.children.at(-1):void 0;i&&this.historyContainer.removeChild(i);const o=this.ensureGroup();i&&(this.append(i),o?.members.push(i));const n=this.makeToolComponent(t,e,s);return n.activityCallId=e,this.appendGroupMember(n),this.registerCopyBlock(n,"tool",""),o&&(o.key??=e,o.toolCount++,o.inFlight.add(n),o.activity.noteCall(e,t,s)),n}noteGroupTool(t,e,s){if(t.activityCallId)for(const i of this.groups)i.members.includes(t)&&i.activity.noteCall(t.activityCallId,e,s)}settleGroupTool(t,e,s=!1){for(const i of this.groups)i.inFlight.delete(t),!(!t.activityCallId||!i.members.includes(t))&&(e===void 0?i.activity.resolveWithoutResult(t.activityCallId):i.activity.settle(t.activityCallId,e,s))}promoteStreamingAssistantToBoundary(t,e=!1){!this.streamingWasGroupMember||!e&&c(t).trim()===""||(this.streamingComponent&&this.removeGroupMember(this.streamingComponent),this.streamingToolSeparator&&this.removeGroupMember(this.streamingToolSeparator),this.streamingWasGroupMember=!1,this.closeOpenGroup())}seedToolGroupSummaries(t){this.groupSummaries.clear();for(const[e,s]of Object.entries(t))this.groupSummaries.set(e,s)}applyToolGroupSummary(t,e){if(this.deferIfBuilding(()=>this.applyToolGroupSummary(t,e)))return;this.projection=St(this.projection,t,e);const s=this.projection.toolGroupSummaryDetails[t];s!==void 0&&(this.groupSummaries.set(t,s),this.applyToolDisplay())}applyGroupDisplay(t){const e=t.key===void 0?void 0:this.groupSummaries.get(t.key),s=this.foldSettledTools&&this.showGroupSummaries&&t.toolCount>0&&t.inFlight.size===0&&e!==void 0;t.recap.setRecap(s?e:void 0,t.toolCount,t.activity.activity(),this.detailedToolRecaps,this.recapPalette),this.historyContainer.setHidden(t.recap,!s);for(const i of t.members)this.historyContainer.setHidden(i,s)}updateFoldedToolSeparators(t=new Set(this.pendingTools.values())){const e=this.historyContainer.children;for(let s=0;s<e.length;s++){const i=e[s];if(!(i instanceof A))continue;const o=e[s+1];i.setFolded(this.foldSettledTools&&!this.historyContainer.hiddenChildren.has(i)&&o instanceof G&&!this.historyContainer.hiddenChildren.has(o)&&!t.has(o)),this.historyContainer.markDirty(i)}}setAssistantSeparatorContent(t,e){const s=e.content,i=Array.isArray(s)?s:[],o=i.some(r=>typeof r=="object"&&r!==null&&r.type==="text"&&typeof r.text=="string"&&r.text.trim()!==""),n=i.some(r=>typeof r=="object"&&r!==null&&r.type==="thinking"&&typeof r.thinking=="string"&&r.thinking.trim()!=="");this.foldedToolSeparatorContents.set(t,{hasText:o,hasThinking:n}),t.setSeparatesToolGroup(o||!this.hideThinking&&n)}makeToolComponent(t,e,s){const i=new ht;let o,n;if(t==="bash"){const h=Q(s,i);h===void 0?n=lt(this.cwd,i,this.backgroundBashHint):n=h.definition}else if(t==="edit"){const h=nt(this.cwd,i);n=h.definition,o=h.observeResult}else t==="read"?n=dt(this.cwd,i):t==="write"&&(n=ct(this.cwd,i));let r;return r=new G(t,e,s,{showImages:this.showImages,imageWidthCells:this.imageWidthCells},n,this.componentTui(()=>r),this.cwd),r.setToolView(n===void 0?void 0:i,o),r.setExpanded(this.toolOutputExpanded),r}append(t){this.appendTarget.addChild(t)}chatChildCount(){return this.appendTarget.children.length}resetChat(){this.setActivity(void 0),this.settleBashComponent(),this.streamingComponent=void 0,this.streamingToolSeparator=void 0,this.streamingWasGroupMember=!1,this.foldedToolSeparatorContents.clear(),this.groups.length=0,this.openGroup=void 0,this.groupSummaries.clear(),this.nodeRoster.clear(),this.pendingTools.clear(),this.lastAssistantText=void 0,this.copyBlockRecords.length=0,this.copyIndex.clear(),this.transcriptFilePaths.length=0,this.transcriptDocRefs.length=0,this.pageBlocks.clear(),this.historyContainer.clear()}maybeAppendPageBlock(t){if(!this.inlinePageBlocks||this.appendTarget!==this.historyContainer)return;const e=Y(t);if(e===void 0||this.pageBlocks.has(e.pageId))return;const s=new J(e.pageId,this.pageOpenHint);this.pageBlocks.set(e.pageId,s),this.append(s),this.loadPageBlock(s)}async loadPageBlock(t){await t.refresh()&&(this.historyContainer.markDirty(t),this.tui.requestRender())}refreshInFlightTools(){if(this.pendingTools.size!==0){for(const t of this.pendingTools.values())this.historyContainer.markDirty(t);this.tui.requestRender()}}async refreshPageBlocks(){const t=[...this.pageBlocks.values()];(await Promise.all(t.map(async s=>{const i=await s.refresh();return i&&this.historyContainer.markDirty(s),i}))).some(Boolean)&&this.tui.requestRender()}makeLoader(t){let e;const s={requestRender:p(i=>{e&&!this.onActivityChange&&this.statusContainer.markDirty(e),this.tui.requestRender(i)},"requestRender"),terminal:this.tui.terminal};return e=new F(s,this.spinnerStyle,this.dimStyle,t),e}componentTui(t){return{requestRender:p(e=>{this.historyContainer.markDirty(t()),this.tui.requestRender(e)},"requestRender"),terminal:this.tui.terminal}}settleBashComponent(t){if(!this.bashComponent)return;const e=this.bashComponent;e.setComplete(t?.exitCode,t?.cancelled??!0,t?.truncated?{truncated:!0}:void 0,t?.fullOutputPath),this.historyContainer.markDirty(e),this.bashComponent=void 0}setActivity(t){if(this.activityLoader?.stop(),this.activityLoader=t,this.onActivityChange){this.onActivityChange(t);return}this.statusContainer.clear(),t&&this.statusContainer.addChild(t)}showStatus(t){this.closeOpenGroup(),this.append(new d(1)),this.append(new x(this.dimStyle(t),1,0))}showError(t){this.deferIfBuilding(()=>this.showError(t))||(this.closeOpenGroup(),this.append(new d(1)),this.append(new x(this.errorStyle(t),1,0)),this.tui.requestRender())}crtrOutputTheme(){return{fg:p((t,e)=>t==="error"?this.errorStyle(e):t==="warning"||t==="accent"||t==="toolTitle"||t==="success"?this.spinnerStyle(e):t==="muted"?this.dimStyle(e):e,"fg"),bg:p((t,e)=>e,"bg"),bold:p(t=>this.labelStyle(t),"bold")}}assistantToolCalls(t){const e=t.content;return Array.isArray(e)?e.filter(s=>typeof s=="object"&&s!==null&&s.type==="toolCall"):[]}getTranscriptFilePathsNewestFirst(){return[...this.transcriptFilePaths]}getTranscriptDocRefsNewestFirst(){return[...this.transcriptDocRefs]}refreshMarkdown(){this.historyContainer.invalidate(),this.tui.requestRender()}getLastAssistantText(){const t=this.lastAssistantText?.trim();return t||void 0}blockText(t){const e=this.copyIndex.get(t);return e===void 0?void 0:this.copyBlockRecords[e]?.text}copyBlocks(){return this.copyBlockRecords}getLastToolOutputText(){for(let t=this.copyBlockRecords.length-1;t>=0;t--){const e=this.copyBlockRecords[t];if(e.kind==="tool")return e.text.trim()===""?void 0:e.text}}getTranscriptPlainText(){return this.copyBlockRecords.map(t=>t.text).filter(t=>t.trim()!=="").join(`
2
2
 
3
3
  `)}registerCopyBlock(t,e,s){const i=this.condensedCopyBlocks.get(this.appendTarget);if(i){const n=i.findIndex(r=>r.block===t);n===-1?i.push({block:t,kind:e,text:s}):i[n].text=s;return}const o=this.copyIndex.get(t);o===void 0?(this.copyIndex.set(t,this.copyBlockRecords.length),this.copyBlockRecords.push({block:t,kind:e,text:s})):this.copyBlockRecords[o].text=s}unregisterCopyBlock(t){const e=this.condensedCopyBlocks.get(this.appendTarget);if(e){const i=e.findIndex(o=>o.block===t);i!==-1&&e.splice(i,1);return}const s=this.copyIndex.get(t);if(s!==void 0){this.copyBlockRecords.splice(s,1),this.copyIndex.delete(t);for(let i=s;i<this.copyBlockRecords.length;i++)this.copyIndex.set(this.copyBlockRecords[i].block,i)}}appendCondensedBlock({component:t,copyBlocks:e}){this.append(t),this.registerCopyBlock(t,"condensed",e.map(s=>s.text).filter(s=>s.trim()!=="").join(`
4
4
 
5
- `))}toolResultText(t){if(typeof t=="string")return t;if(typeof t=="object"&&t!==null&&"content"in t){const e=t.content;if(typeof e=="string")return e;if(Array.isArray(e))return e.filter(s=>typeof s=="object"&&s!==null&&s.type==="text"&&typeof s.text=="string").map(s=>s.text).join("")}try{const e=JSON.stringify(t);return typeof e=="string"?e:""}catch{return""}}pushTranscriptText(t){const e=t.trim();if(e==="")return;const s=mt([e],this.cwd);if(s.length===0)return;const i=[...s,...this.transcriptFilePaths.filter(o=>!s.includes(o))].slice(0,50);this.transcriptFilePaths.splice(0,this.transcriptFilePaths.length,...i)}pushTranscriptValue(t){try{const e=typeof t=="string"?t:JSON.stringify(t);typeof e=="string"&&this.pushTranscriptText(e)}catch{}}userMessageText(t){const e=t.content;return typeof e=="string"?e:Array.isArray(e)?e.filter(s=>typeof s=="object"&&s!==null&&s.type==="text").map(s=>s.text).join(""):""}}export{ue as ChatView};
5
+ `))}toolResultText(t){if(typeof t=="string")return t;if(typeof t=="object"&&t!==null&&"content"in t){const e=t.content;if(typeof e=="string")return e;if(Array.isArray(e))return e.filter(s=>typeof s=="object"&&s!==null&&s.type==="text"&&typeof s.text=="string").map(s=>s.text).join("")}try{const e=JSON.stringify(t);return typeof e=="string"?e:""}catch{return""}}pushTranscriptText(t){const e=t.trim();if(e==="")return;const s=[...new Set(ft(e).reverse())];if(s.length>0){const n=[...s,...this.transcriptDocRefs.filter(r=>!s.includes(r))].slice(0,50);this.transcriptDocRefs.splice(0,this.transcriptDocRefs.length,...n)}const i=mt([e],this.cwd);if(i.length===0)return;const o=[...i,...this.transcriptFilePaths.filter(n=>!i.includes(n))].slice(0,50);this.transcriptFilePaths.splice(0,this.transcriptFilePaths.length,...o)}pushTranscriptValue(t){try{const e=typeof t=="string"?t:JSON.stringify(t);typeof e=="string"&&this.pushTranscriptText(e)}catch{}}userMessageText(t){const e=t.content;return typeof e=="string"?e:Array.isArray(e)?e.filter(s=>typeof s=="object"&&s!==null&&s.type==="text").map(s=>s.text).join(""):""}}export{fe as ChatView};
@@ -0,0 +1,34 @@
1
+ /** The fragment a rendered document link carries. iTerm strips it before
2
+ * invoking Semantic History; the viewer recognizes a document by its path. */
3
+ export declare const DOC_OPEN_FRAGMENT = "crtr-doc-open";
4
+ /** What the renderer needs from the viewer. Every call is synchronous and reads
5
+ * live viewer state; a miss may schedule a fetch that re-renders later. */
6
+ export interface DocLinkContext {
7
+ /** The node this viewer is attached to. */
8
+ selfNodeId: string;
9
+ /** A node's display name, when known. */
10
+ nodeName(nodeId: string): string | undefined;
11
+ /** The local materialized file for a document ref, when one exists. */
12
+ pathFor(ref: string): string | undefined;
13
+ }
14
+ /** Install (or clear) the viewer's document-link context. */
15
+ export declare function setDocLinkContext(context: DocLinkContext | undefined): void;
16
+ /** The node-id owner and remaining name of a ref, when its first segment is a node id. */
17
+ export declare function splitDocRef(ref: string, context?: DocLinkContext): {
18
+ nodeId?: string;
19
+ name: string;
20
+ };
21
+ /** A readable name for a document ref: `name`, plus the owning node's name
22
+ * when another node owns it. Plain text, for pickers and notices. */
23
+ export declare function docLinkLabel(ref: string, context?: DocLinkContext | undefined): {
24
+ name: string;
25
+ owner?: string;
26
+ };
27
+ /** One-line plain-text label: `name` or `name · owner`. */
28
+ export declare function docLinkText(ref: string, context?: DocLinkContext | undefined): string;
29
+ /** Every `[[ref]]` in `text`, in order of appearance, without brackets. */
30
+ export declare function extractDocRefs(text: string): string[];
31
+ /** Rewrite each `[[ref]]` in a prose fragment (never a code span or fence —
32
+ * the caller skips those) into its readable, openable display form. Without
33
+ * an installed context the prose is returned unchanged. */
34
+ export declare function rewriteProseDocLinks(prose: string, context?: DocLinkContext | undefined): string;
@@ -0,0 +1 @@
1
+ var p=Object.defineProperty;var r=(e,n)=>p(e,"name",{value:n,configurable:!0});import{pathToFileURL as $}from"node:url";const x="crtr-doc-open",f=/\[\[([^[\]\n]+?)\]\]/g,N=/^[a-z0-9]+-[a-z0-9]+-[a-z0-9]+$/,D=r(e=>`\x1B[2m${e}\x1B[22m`,"DIM"),b=r(e=>`\x1B[4m${e}\x1B[24m`,"UNDERLINE");let c;function E(e){c=e}r(E,"setDocLinkContext");function I(e,n){const t=e.indexOf("/");if(t<=0)return{name:e};const o=e.slice(0,t);return o===n?.selfNodeId||n?.nodeName(o)!==void 0||N.test(o)?{nodeId:o,name:e.slice(t+1)}:{name:e}}r(I,"splitDocRef");function l(e,n=c){const{nodeId:t,name:o}=I(e,n);return t===void 0?{name:o}:t===n?.selfNodeId?{name:o}:{name:o,owner:n?.nodeName(t)??t.slice(t.lastIndexOf("-")+1)}}r(l,"docLinkLabel");function w(e,n=c){const t=l(e,n);return t.owner===void 0?t.name:`${t.name} \xB7 ${t.owner}`}r(w,"docLinkText");function O(e){return[...e.matchAll(f)].map(n=>n[1].trim()).filter(n=>n!=="")}r(O,"extractDocRefs");function R(e,n=c){return n===void 0||!e.includes("[[")?e:e.replace(f,(t,o)=>{const i=o.trim();if(i==="")return t;const d=l(i,n),s=n.pathFor(i),a=m(d.name),u=s===void 0?b(a):`[${a}](${$(s).href}#${x})`;return d.owner===void 0?u:`${u}${D(` \xB7 ${m(d.owner)}`)}`})}r(R,"rewriteProseDocLinks");function m(e){return e.replace(/([\\[\]*_`<>])/g,"\\$1")}r(m,"escapeLabel");export{x as DOC_OPEN_FRAGMENT,l as docLinkLabel,w as docLinkText,O as extractDocRefs,R as rewriteProseDocLinks,E as setDocLinkContext,I as splitDocRef};
@@ -1,5 +1,5 @@
1
- var x=Object.defineProperty;var c=(t,i)=>x(t,"name",{value:i,configurable:!0});import{pathToFileURL as y}from"node:url";import{expandGlyphCodepoints as m}from"./glyph-codepoints.js";const $=/^(\s{0,3})(#{3,6})(?:[ \t]+|$)(.*?)([ \t]+#+[ \t]*)?$/,h=/^\s{0,3}(`{3,}|~{3,})/,A=/^([ \t]{0,3})(<\/?)([A-Za-z][\w.:-]*)((?:[ \t]+[^<>]*?)?)(\/?)>[ \t]*$/,b=/([^\s=]+)(?:=("[^"]*"|'[^']*'|[^\s]*))?/g,L=[[232,194,104],[207,194,145],[181,184,174],[157,170,180],[135,153,164],[116,135,147]],d=[104,112,124],k=[138,166,196],a=[124,146,164],M=[168,142,118];function f(t,i){return`\x1B[38;2;${t[0]};${t[1]};${t[2]}m${i}\x1B[39m`}c(f,"paint");function E(t){const[i,n,e]=L[t-1];return o=>`\x1B[1;38;2;${i};${n};${e}m${o}\x1B[22;39m`}c(E,"headingColor");function T(t){const i=$.exec(t);if(!i)return;const[,n,e,o]=i;if(o!=="")return`${n}${E(e.length)(o)}`}c(T,"styleHeadingLine");function _(t){return t.replace(b,(i,n,e)=>e===void 0?f(a,i):`${f(a,n)}${f(d,"=")}${f(M,e)}`)}c(_,"styleAttributes");function w(t){const i=A.exec(t);if(!i)return;const[,n,e,o,r,u]=i;return n+f(d,e)+f(k,o)+_(r)+f(d,`${u}>`)}c(w,"styleXmlTagLine");function N(t){const i=t.split(`
2
- `),n=[];let e;for(let o=0;o<i.length;o++){const r=i[o],u=h.exec(r);if(e!==void 0){u?.[1][0]===e&&(e=void 0),n.push(r);continue}if(u){e=u[1][0],n.push(r);continue}const l=w(r);if(l!==void 0){n.length>0&&n[n.length-1].trim()!==""&&n.push(""),n.push(l),i[o+1]!==void 0&&i[o+1].trim()!==""&&n.push("");continue}n.push(T(r)??r)}return n.join(`
3
- `)}c(N,"styleAttachMarkdownSource");function s(t){return m(N(I(t)))}c(s,"styleAttachAgentMarkdown");function I(t){let i;return t.split(`
4
- `).map(n=>{const e=h.exec(n);return i!==void 0?(e?.[1][0]===i&&(i=void 0),n):e?(i=e[1][0],n):X(n)}).join(`
5
- `)}c(I,"rewriteAbsoluteFileLinks");function X(t){let i="",n=t;for(;n!=="";){const e=n.match(/`+/),o=e===null?n:n.slice(0,e.index);if(i+=C(o),e===null)break;const r=e[0],u=n.indexOf(r,o.length+r.length);if(u===-1)return i+n.slice(o.length);i+=n.slice(o.length,u+r.length),n=n.slice(u+r.length)}return i}c(X,"rewriteInlineFileLinks");function C(t){let i="",n=0;for(;n<t.length;){const e=t.indexOf("[",n);if(e===-1)return i+t.slice(n);const o=U(t,e);if(o===void 0){i+=t.slice(n,e+1),n=e+1;continue}i+=t.slice(n,e)+`[${o.label}](${y(o.path).href}#crtr-file-open)`,n=o.end}return i}c(C,"rewriteProseFileLinks");function U(t,i){const n=p(t,i+1,"]");if(n===void 0||t[n+1]!=="(")return;const e=n+2;if(t[e]==="<"){const r=p(t,e+1,">");if(r===void 0||t[r+1]!==")")return;const u=g(t.slice(e+1,r));return u===void 0?void 0:{label:t.slice(i+1,n),path:u,end:r+2}}let o=0;for(let r=e;r<t.length;r++){if(t[r]==="\\"){r++;continue}if(t[r]==="("){o++;continue}if(t[r]!==")"||o-- >0)continue;const u=g(t.slice(e,r));return u===void 0?void 0:{label:t.slice(i+1,n),path:u,end:r+1}}}c(U,"parseLocalMarkdownLink");function p(t,i,n){for(let e=i;e<t.length;e++){if(t[e]==="\\"){e++;continue}if(t[e]===n)return e}}c(p,"closingDelimiter");function g(t){const i=t.replace(/\\([!"#$%&'()*+,./:;<=>?@[\\\]^_`{|}~-])/g,"$1");let n=i;try{n=decodeURIComponent(i)}catch{}return n.startsWith("/")?n:void 0}c(g,"localPathFromDestination");function j(t){if(typeof t!="object"||t===null||!("content"in t))return t;const i=t;return typeof i.content=="string"?{...i,content:s(i.content)}:Array.isArray(i.content)?{...i,content:i.content.map(n=>{if(typeof n!="object"||n===null)return n;const e=n;return e.type==="text"&&typeof e.text=="string"?{...e,text:s(e.text)}:e.type==="thinking"&&typeof e.thinking=="string"?{...e,thinking:s(e.thinking)}:n})}:t}c(j,"styleAttachMessageMarkdown");function D(t){return{...t,summary:s(t.summary)}}c(D,"styleAttachSummaryMarkdown");export{s as styleAttachAgentMarkdown,N as styleAttachMarkdownSource,j as styleAttachMessageMarkdown,D as styleAttachSummaryMarkdown};
1
+ var m=Object.defineProperty;var c=(t,i)=>m(t,"name",{value:i,configurable:!0});import{pathToFileURL as x}from"node:url";import{expandGlyphCodepoints as y}from"./glyph-codepoints.js";import{rewriteProseDocLinks as $}from"./doc-links.js";const A=/^(\s{0,3})(#{3,6})(?:[ \t]+|$)(.*?)([ \t]+#+[ \t]*)?$/,h=/^\s{0,3}(`{3,}|~{3,})/,L=/^([ \t]{0,3})(<\/?)([A-Za-z][\w.:-]*)((?:[ \t]+[^<>]*?)?)(\/?)>[ \t]*$/,b=/([^\s=]+)(?:=("[^"]*"|'[^']*'|[^\s]*))?/g,k=[[232,194,104],[207,194,145],[181,184,174],[157,170,180],[135,153,164],[116,135,147]],d=[104,112,124],M=[138,166,196],a=[124,146,164],E=[168,142,118];function f(t,i){return`\x1B[38;2;${t[0]};${t[1]};${t[2]}m${i}\x1B[39m`}c(f,"paint");function w(t){const[i,n,e]=k[t-1];return o=>`\x1B[1;38;2;${i};${n};${e}m${o}\x1B[22;39m`}c(w,"headingColor");function T(t){const i=A.exec(t);if(!i)return;const[,n,e,o]=i;if(o!=="")return`${n}${w(e.length)(o)}`}c(T,"styleHeadingLine");function _(t){return t.replace(b,(i,n,e)=>e===void 0?f(a,i):`${f(a,n)}${f(d,"=")}${f(E,e)}`)}c(_,"styleAttributes");function N(t){const i=L.exec(t);if(!i)return;const[,n,e,o,r,u]=i;return n+f(d,e)+f(M,o)+_(r)+f(d,`${u}>`)}c(N,"styleXmlTagLine");function I(t){const i=t.split(`
2
+ `),n=[];let e;for(let o=0;o<i.length;o++){const r=i[o],u=h.exec(r);if(e!==void 0){u?.[1][0]===e&&(e=void 0),n.push(r);continue}if(u){e=u[1][0],n.push(r);continue}const l=N(r);if(l!==void 0){n.length>0&&n[n.length-1].trim()!==""&&n.push(""),n.push(l),i[o+1]!==void 0&&i[o+1].trim()!==""&&n.push("");continue}n.push(T(r)??r)}return n.join(`
3
+ `)}c(I,"styleAttachMarkdownSource");function s(t){return y(I(X(t)))}c(s,"styleAttachAgentMarkdown");function X(t){let i;return t.split(`
4
+ `).map(n=>{const e=h.exec(n);return i!==void 0?(e?.[1][0]===i&&(i=void 0),n):e?(i=e[1][0],n):C(n)}).join(`
5
+ `)}c(X,"rewriteAbsoluteFileLinks");function C(t){let i="",n=t;for(;n!=="";){const e=n.match(/`+/),o=e===null?n:n.slice(0,e.index);if(i+=U($(o)),e===null)break;const r=e[0],u=n.indexOf(r,o.length+r.length);if(u===-1)return i+n.slice(o.length);i+=n.slice(o.length,u+r.length),n=n.slice(u+r.length)}return i}c(C,"rewriteInlineFileLinks");function U(t){let i="",n=0;for(;n<t.length;){const e=t.indexOf("[",n);if(e===-1)return i+t.slice(n);const o=F(t,e);if(o===void 0){i+=t.slice(n,e+1),n=e+1;continue}i+=t.slice(n,e)+`[${o.label}](${x(o.path).href}#crtr-file-open)`,n=o.end}return i}c(U,"rewriteProseFileLinks");function F(t,i){const n=p(t,i+1,"]");if(n===void 0||t[n+1]!=="(")return;const e=n+2;if(t[e]==="<"){const r=p(t,e+1,">");if(r===void 0||t[r+1]!==")")return;const u=g(t.slice(e+1,r));return u===void 0?void 0:{label:t.slice(i+1,n),path:u,end:r+2}}let o=0;for(let r=e;r<t.length;r++){if(t[r]==="\\"){r++;continue}if(t[r]==="("){o++;continue}if(t[r]!==")"||o-- >0)continue;const u=g(t.slice(e,r));return u===void 0?void 0:{label:t.slice(i+1,n),path:u,end:r+1}}}c(F,"parseLocalMarkdownLink");function p(t,i,n){for(let e=i;e<t.length;e++){if(t[e]==="\\"){e++;continue}if(t[e]===n)return e}}c(p,"closingDelimiter");function g(t){const i=t.replace(/\\([!"#$%&'()*+,./:;<=>?@[\\\]^_`{|}~-])/g,"$1");let n=i;try{n=decodeURIComponent(i)}catch{}return n.startsWith("/")?n:void 0}c(g,"localPathFromDestination");function j(t){if(typeof t!="object"||t===null||!("content"in t))return t;const i=t;return typeof i.content=="string"?{...i,content:s(i.content)}:Array.isArray(i.content)?{...i,content:i.content.map(n=>{if(typeof n!="object"||n===null)return n;const e=n;return e.type==="text"&&typeof e.text=="string"?{...e,text:s(e.text)}:e.type==="thinking"&&typeof e.thinking=="string"?{...e,thinking:s(e.thinking)}:n})}:t}c(j,"styleAttachMessageMarkdown");function G(t){return{...t,summary:s(t.summary)}}c(G,"styleAttachSummaryMarkdown");export{s as styleAttachAgentMarkdown,I as styleAttachMarkdownSource,j as styleAttachMessageMarkdown,G as styleAttachSummaryMarkdown};
@@ -0,0 +1,53 @@
1
+ /** Environment variable carrying the edited document path to the reattached viewer. */
2
+ export declare const DOC_SAVEBACK_ENV = "CRTR_ATTACH_DOC_SAVEBACK";
3
+ /** The document a materialized file was read from. */
4
+ export interface MaterializedDoc {
5
+ /** The ref as the transcript wrote it (no brackets). */
6
+ ref: string;
7
+ id: string;
8
+ /** Canonical `<owner>/<name>` (or the ref when no owner). */
9
+ name: string;
10
+ revision: number;
11
+ /** The heads the body was read at — the base a save-back is made from. */
12
+ heads_key: string;
13
+ /** sha256 of the body as written. */
14
+ sha256: string;
15
+ }
16
+ /** The subset of a document read this module needs. */
17
+ export interface DocumentSnapshot {
18
+ id: string;
19
+ name: string;
20
+ revision: number;
21
+ heads_key: string;
22
+ body: string;
23
+ }
24
+ export declare function docMaterializeRoot(): string;
25
+ /** Write the snapshot's body to its stable path (idempotent) and return the path.
26
+ * An existing file at that path is kept: it may hold the person's unsaved edit. */
27
+ export declare function materializeDocument(ref: string, snap: DocumentSnapshot, root?: string): string;
28
+ /** The document a local path was materialized from, or undefined for a plain file. */
29
+ export declare function documentForPath(path: string, root?: string): MaterializedDoc | undefined;
30
+ /** Save a person's edit of a materialized document. */
31
+ export type DocSaveOutcome = {
32
+ outcome: 'unchanged';
33
+ } | {
34
+ outcome: 'saved';
35
+ revision: number;
36
+ } | {
37
+ outcome: 'stale';
38
+ path: string;
39
+ } | {
40
+ outcome: 'missing';
41
+ } | {
42
+ outcome: 'failed';
43
+ message: string;
44
+ };
45
+ /** The document write the save-back uses: `crtr doc edit`'s body replacement,
46
+ * made from an explicit base. Resolves `stale` rather than throwing on a
47
+ * moved document. */
48
+ export type DocEditFn = (id: string, body: string, base: string) => Promise<{
49
+ revision: number;
50
+ } | 'stale'>;
51
+ export declare function saveDocumentEdit(path: string, edit: DocEditFn, root?: string): Promise<DocSaveOutcome>;
52
+ /** The notice a save-back outcome shows, or undefined for none. */
53
+ export declare function saveOutcomeNotice(name: string, outcome: DocSaveOutcome): string | undefined;
@@ -0,0 +1,3 @@
1
+ var l=Object.defineProperty;var o=(e,t)=>l(e,"name",{value:t,configurable:!0});import{createHash as S}from"node:crypto";import{existsSync as d,mkdirSync as $,readFileSync as y,renameSync as _,writeFileSync as p}from"node:fs";import{tmpdir as x}from"node:os";import{basename as A,dirname as g,join as c}from"node:path";const N="CRTR_ATTACH_DOC_SAVEBACK",a=".crtr-doc.json";function u(){return c(x(),"crtr-docs")}o(u,"docMaterializeRoot");const f=o(e=>S("sha256").update(e).digest("hex"),"sha");function h(e){return e.replace(/[^A-Za-z0-9._-]/g,"_").slice(0,120)||"doc"}o(h,"safeSegment");function b(e,t,r=u()){const n=c(r,h(t.id),`r${t.revision}`),s=c(n,`${h(A(t.name))}.md`),i=c(n,a);if(d(s)&&d(i))return s;$(n,{recursive:!0});const v={ref:e,id:t.id,name:t.name,revision:t.revision,heads_key:t.heads_key,sha256:f(t.body)};return m(s,t.body),m(i,`${JSON.stringify(v)}
2
+ `),s}o(b,"materializeDocument");function m(e,t){const r=`${e}.${process.pid}.tmp`;p(r,t),_(r,e)}o(m,"writeAtomic");function C(e,t=u()){if(e.startsWith(`${t}/`))try{const r=JSON.parse(y(c(g(e),a),"utf8"));return typeof r.id=="string"&&typeof r.heads_key=="string"?r:void 0}catch{return}}o(C,"documentForPath");async function R(e,t,r=u()){const n=C(e,r);if(n===void 0||!d(e))return{outcome:"missing"};const s=y(e,"utf8");if(f(s)===n.sha256)return{outcome:"unchanged"};try{const i=await t(n.id,s,n.heads_key);return i==="stale"?{outcome:"stale",path:e}:(m(c(g(e),a),`${JSON.stringify({...n,sha256:f(s)})}
3
+ `),{outcome:"saved",revision:i.revision})}catch(i){return{outcome:"failed",message:i instanceof Error?i.message:String(i)}}}o(R,"saveDocumentEdit");function z(e,t){switch(t.outcome){case"unchanged":return;case"saved":return`Saved ${e} as revision ${t.revision}`;case"stale":return`${e} changed while you edited it \u2014 not saved; your text is kept at ${t.path}`;case"missing":return`Could not find the edited copy of ${e}`;case"failed":return`Could not save ${e}: ${t.message}`}}o(z,"saveOutcomeNotice");export{N as DOC_SAVEBACK_ENV,u as docMaterializeRoot,C as documentForPath,b as materializeDocument,R as saveDocumentEdit,z as saveOutcomeNotice};
@@ -0,0 +1,21 @@
1
+ import type { CanvasSource } from '../../../core/canvas/source.js';
2
+ export interface DocumentLinks {
3
+ /** Whether a clicked local path is a materialized document. */
4
+ isDocumentPath(path: string): boolean;
5
+ /** Re-read a clicked document and return the path to open (its current revision). */
6
+ prepareOpen(path: string): Promise<{
7
+ path: string;
8
+ } | {
9
+ notice: string;
10
+ }>;
11
+ /** The save-back a reattaching viewer was handed, if any. */
12
+ consumeSaveBack(notify: (message: string) => void): Promise<void>;
13
+ dispose(): void;
14
+ }
15
+ export declare function createDocumentLinks(opts: {
16
+ selfNodeId: string;
17
+ remote: boolean;
18
+ canvasSource: CanvasSource;
19
+ /** Re-render the transcript's Markdown after a name or path lands. */
20
+ refresh: () => void;
21
+ }): DocumentLinks;
@@ -0,0 +1 @@
1
+ var k=Object.defineProperty;var i=(o,r)=>k(o,"name",{value:r,configurable:!0});import{APIError as C}from"../../../api/errors.js";import{cliClient as v}from"../../../commands/api-client.js";import{setDocLinkContext as y}from"../render/doc-links.js";import{DOC_SAVEBACK_ENV as g,documentForPath as h,materializeDocument as b,saveDocumentEdit as E,saveOutcomeNotice as L}from"./doc-materialize.js";async function w(o){const r=await v().objects.read(o);if(r.state!=="object"||r.type!=="document")return`${o} is not a readable document`;const n=r;if(n.needs_merge||n.bodies.length!==1)return`${o} has ${n.heads.length} heads and needs a merge`;const s=n.object.owner?.handle;return{id:n.object.id,name:s===void 0?n.object.name:`${s}/${n.object.name}`,revision:n.revision,heads_key:n.heads.map(d=>d.rev_id).sort().join(","),body:n.bodies[0]}}i(w,"readSnapshot");function z(o){const r=new Map,n=new Map,s=new Set,d=new Set;let m=!1,f=!1,l=!1;const j=i(()=>{m||f||(f=!0,o.canvasSource.listNodes().then(t=>{for(const e of t)r.set(e.node_id,e.name);m=!0,l||o.refresh()}).catch(()=>{m=!0}).finally(()=>{f=!1}))},"loadRoster"),N=i(t=>{o.remote||s.has(t)||d.has(t)||(s.add(t),w(t).then(e=>{if(typeof e=="string"){d.add(t);return}n.set(t,b(t,e)),l||o.refresh()}).catch(()=>{d.add(t)}).finally(()=>{s.delete(t)}))},"materialize"),S={selfNodeId:o.selfNodeId,nodeName:i(t=>{const e=r.get(t);return e===void 0&&j(),e},"nodeName"),pathFor:i(t=>{const e=n.get(t);return e===void 0&&N(t),e},"pathFor")};return y(S),{isDocumentPath:i(t=>h(t)!==void 0,"isDocumentPath"),async prepareOpen(t){if(o.remote)return{notice:"Opening a document is unavailable in a remote attach"};const e=h(t);if(e===void 0)return{notice:"Not a document link"};try{const a=await w(e.id);if(typeof a=="string")return{notice:a};const c=b(e.ref,a);return n.set(e.ref,c),{path:c}}catch(a){return{notice:`Could not read ${e.name}: ${a instanceof Error?a.message:String(a)}`}}},async consumeSaveBack(t){const e=process.env[g];if(e===void 0||e==="")return;delete process.env[g];const a=h(e),c=await E(e,async(_,$,D)=>{try{return{revision:(await v().docs.edit(_,{body:$,base:D,rationale:"edited by the person in the attach viewer"})).revision}}catch(u){if(u instanceof C&&u.code==="stale_revision")return"stale";throw u}}),p=L(a?.name??e,c);p!==void 0&&t(p)},dispose(){l=!0,y(void 0)}}}i(z,"createDocumentLinks");export{z as createDocumentLinks};
@@ -17,6 +17,8 @@ export declare function openLinkedFileInPane(opts: {
17
17
  cwd: string;
18
18
  nodeId: string;
19
19
  observer: boolean;
20
+ /** A materialized canvas document: the reattaching viewer saves its edit back. */
21
+ saveBackEnv?: string;
20
22
  /** Clear viewer-local pane identity immediately before the pane runs Neovim. */
21
23
  beforeRespawn: () => void;
22
24
  }): LinkedFileOpenResult;
@@ -1 +1 @@
1
- var o=Object.defineProperty;var r=(e,n)=>o(e,"name",{value:n,configurable:!0});import{existsSync as s}from"node:fs";import{respawnPaneInBackground as u,shellQuote as c,viewerSplitEnv as l}from"../../../core/runtime/placement-tmux.js";const d="\x1B_crtr-file-open;",f="\x1B\\";function P(e){const n=e.indexOf(d);if(n===-1)return;const t=n+d.length,i=e.indexOf(f,t);return i===-1?void 0:{file:h(e.slice(t,i)),remaining:e.slice(0,n)+e.slice(i+f.length)}}r(P,"extractFileOpenInput");function h(e){const n=e.startsWith("'")?x(e):a(e);return n!==void 0&&n.startsWith("/")&&!/[\x00-\x1f\x7f]/.test(n)?n:void 0}r(h,"decodeShellEscapedPath");function x(e){let n="",t=1;for(;;){const i=e.indexOf("'",t);if(i===-1)return;if(n+=e.slice(t,i),t=i+1,t===e.length)return n;if(e.slice(t,t+3)!=="\\''")return;n+="'",t+=3}}r(x,"decodeSingleQuotedPath");function a(e){let n="";for(let t=0;t<e.length;t++){if(e[t]!=="\\"){n+=e[t];continue}const i=e[++t];if(i===void 0)return;n+=i}return n}r(a,"decodeBackslashPath");function w(e){if(!s(e.file))return"missing";const n=`crtr surface attach to ${c(e.nodeId)}${e.observer?" --observer":""}`,t=`nvim ${c(e.file)} || :; exec ${n}`;return e.beforeRespawn(),u({pane:e.pane,cwd:e.cwd,env:l(),command:t})?"opened":"failed"}r(w,"openLinkedFileInPane");export{P as extractFileOpenInput,w as openLinkedFileInPane};
1
+ var s=Object.defineProperty;var r=(e,n)=>s(e,"name",{value:n,configurable:!0});import{existsSync as o}from"node:fs";import{respawnPaneInBackground as u,shellQuote as c,viewerSplitEnv as l}from"../../../core/runtime/placement-tmux.js";const d="\x1B_crtr-file-open;",f="\x1B\\";function I(e){const n=e.indexOf(d);if(n===-1)return;const t=n+d.length,i=e.indexOf(f,t);return i===-1?void 0:{file:a(e.slice(t,i)),remaining:e.slice(0,n)+e.slice(i+f.length)}}r(I,"extractFileOpenInput");function a(e){const n=e.startsWith("'")?h(e):x(e);return n!==void 0&&n.startsWith("/")&&!/[\x00-\x1f\x7f]/.test(n)?n:void 0}r(a,"decodeShellEscapedPath");function h(e){let n="",t=1;for(;;){const i=e.indexOf("'",t);if(i===-1)return;if(n+=e.slice(t,i),t=i+1,t===e.length)return n;if(e.slice(t,t+3)!=="\\''")return;n+="'",t+=3}}r(h,"decodeSingleQuotedPath");function x(e){let n="";for(let t=0;t<e.length;t++){if(e[t]!=="\\"){n+=e[t];continue}const i=e[++t];if(i===void 0)return;n+=i}return n}r(x,"decodeBackslashPath");function P(e){if(!o(e.file))return"missing";const n=`crtr surface attach to ${c(e.nodeId)}${e.observer?" --observer":""}`,t=e.saveBackEnv===void 0?"":`env ${e.saveBackEnv}=${c(e.file)} `,i=`nvim ${c(e.file)} || :; exec ${t}${n}`;return e.beforeRespawn(),u({pane:e.pane,cwd:e.cwd,env:l(),command:i})?"opened":"failed"}r(P,"openLinkedFileInPane");export{I as extractFileOpenInput,P as openLinkedFileInPane};