@north-light/crouter 0.3.320 → 0.3.321
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +2 -1
- package/dist/api/client.js +1 -1
- package/dist/api/dto/broker-ops.d.ts +0 -1
- package/dist/api/dto/node-outcomes.d.ts +6 -0
- package/dist/api/dto/nodes.d.ts +4 -3
- package/dist/api/dto/review-comments.d.ts +8 -0
- package/dist/api/routes.d.ts +1 -0
- package/dist/api/routes.js +1 -1
- package/dist/clients/attach/viewer.js +582 -582
- package/dist/clients/inbox/review/comments-client.d.ts +8 -1
- package/dist/clients/inbox/review/comments-client.js +1 -1
- package/dist/clients/inbox/review/companion-pane.d.ts +17 -0
- package/dist/clients/inbox/review/companion-pane.js +1 -1
- package/dist/clients/inbox/review/document-surface.d.ts +10 -0
- package/dist/clients/inbox/review/document-surface.js +2 -2
- package/dist/clients/inbox/review/frame.js +1 -1
- package/dist/clients/inbox/review/keys.d.ts +2 -0
- package/dist/clients/inbox/review/keys.js +1 -1
- package/dist/commands/human/prompts.js +1 -1
- package/dist/core/canvas/browse/app.js +3 -3
- package/dist/core/canvas/canvas.d.ts +3 -3
- package/dist/core/canvas/canvas.js +17 -14
- package/dist/core/canvas/migrations.js +34 -27
- package/dist/core/canvas/node-sql-migration.d.ts +1 -0
- package/dist/core/canvas/node-sql-migration.js +28 -2
- package/dist/core/canvas/paths.d.ts +4 -0
- package/dist/core/canvas/paths.js +1 -1
- package/dist/core/canvas/recovery.d.ts +1 -0
- package/dist/core/canvas/recovery.js +1 -1
- package/dist/core/canvas/worktrees.d.ts +1 -0
- package/dist/core/canvas/worktrees.js +1 -1
- package/dist/core/human/requests.d.ts +1 -0
- package/dist/core/human/requests.js +17 -13
- package/dist/core/review/fork.d.ts +8 -0
- package/dist/core/review/fork.js +5 -0
- package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
- package/dist/core/runtime/broker/extension-abort.js +1 -1
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/spawn.d.ts +5 -1
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/stop-guard.d.ts +1 -3
- package/dist/core/runtime/stop-guard.js +2 -2
- package/dist/core/runtime/stop-signals.d.ts +0 -1
- package/dist/core/runtime/stop-signals.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/health.js +14 -1
- package/dist/daemon/api/handlers/inbox.js +1 -1
- package/dist/daemon/api/handlers/review-comments.js +1 -1
- package/dist/daemon/api/map.d.ts +4 -2
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/companion-retire.d.ts +3 -1
- package/dist/daemon/companion-retire.js +1 -1
- package/dist/daemon/crtrd.js +7 -7
- package/dist/daemon/human/finish.d.ts +4 -1
- package/dist/daemon/human/finish.js +7 -7
- package/dist/daemon/human/settle.d.ts +8 -6
- package/dist/daemon/human/settle.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +1 -1
- package/dist/pi-extensions/canvas-stophook.js +1 -1
- package/package.json +1 -1
- package/runtime.lock.json +5 -5
|
@@ -33,12 +33,13 @@ export type ReviewRequest = <T>(operation: () => Promise<T>) => Promise<T>;
|
|
|
33
33
|
export interface CommentAuthority {
|
|
34
34
|
anchorBase(): Promise<AnchorBase>;
|
|
35
35
|
list(): Promise<AnchoredComment[]>;
|
|
36
|
+
/** Resolves to the new comment's id, which forking it needs. */
|
|
36
37
|
create(p: {
|
|
37
38
|
line: number;
|
|
38
39
|
endLine: number;
|
|
39
40
|
text: string;
|
|
40
41
|
docHash: string;
|
|
41
|
-
}): Promise<
|
|
42
|
+
}): Promise<string>;
|
|
42
43
|
edit(p: {
|
|
43
44
|
id: string;
|
|
44
45
|
text: string;
|
|
@@ -61,6 +62,12 @@ export interface CommentAuthority {
|
|
|
61
62
|
detached: true;
|
|
62
63
|
}>;
|
|
63
64
|
}): Promise<void>;
|
|
65
|
+
/** Hand one comment to its own fork of the review companion; resolves to the
|
|
66
|
+
* newborn fork and the cwd a viewer for it runs in. */
|
|
67
|
+
fork(commentId: string): Promise<{
|
|
68
|
+
nodeId: string;
|
|
69
|
+
cwd: string;
|
|
70
|
+
}>;
|
|
64
71
|
onChanged(fn: () => void): () => void;
|
|
65
72
|
}
|
|
66
73
|
/** The terminal's complete daemon seam for one review's comment projection. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var c=Object.defineProperty;var
|
|
1
|
+
var c=Object.defineProperty;var i=(t,n)=>c(t,"name",{value:n,configurable:!0});import{ApiError as s}from"../../../api/errors.js";import{cliClient as o}from"../../../commands/api-client.js";import{watchReviewActivity as d}from"../../../core/review/signal.js";class l extends Error{static{i(this,"ReviewDocumentError")}code;details;constructor(n,e,a){super(e),this.name="ReviewDocumentError",this.code=n,this.details=a}}function v(t,n){return{async anchorBase(){const e=await n(()=>o().getReviewDocumentBase(t));return{file:e.file,text:e.anchor_base_text,docHash:e.anchor_base_sha256}},async list(){return(await n(()=>o().listReviewComments(t,{status:"all"}))).comments.map(h)},async create(e){return(await r(()=>n(()=>o().createReviewComment(t,{text:e.text,anchor:{line:e.line,end_line:e.endLine},doc_hash:e.docHash,actor_node_id:null})))).comment.comment_id},async edit(e){await r(()=>n(()=>o().editReviewComment(e.id,{text:e.text,if_revision:e.ifRevision,actor_node_id:null})))},async resolve(e){await r(()=>n(()=>o().resolveReviewComment(e,{actor_node_id:null})))},async reopen(e){await r(()=>n(()=>o().reopenReviewComment(e,{actor_node_id:null})))},async remove(e){await r(()=>n(()=>o().deleteReviewComment(e,{actor_node_id:null})))},async remapRanges(e){await r(()=>n(()=>o().updateReviewCommentRanges(t,{from_doc_hash:e.fromDocHash,to_doc_hash:e.toDocHash,entries:e.entries.map(a=>"detached"in a?{comment_id:a.id,detached:!0}:{comment_id:a.id,anchor:{line:a.anchor.line,end_line:a.anchor.endLine}})})))},async fork(e){const a=await n(()=>o().forkReviewComment(e));return{nodeId:a.node_id,cwd:a.cwd}},onChanged(e){return d(e)}}}i(v,"createCommentAuthority");function h(t){const n={line:t.anchor.line,endLine:t.anchor.end_line};return{id:t.comment_id,revision:t.revision,...n,lineText:t.anchor_line_text,comment:t.text,status:t.status,authorKind:t.author.kind,createdAt:t.created_at,anchorStatus:t.anchor_state==="detached"?"detached":"live",...t.anchor_state==="detached"?{originalRange:n}:{}}}i(h,"projectComment");async function r(t){try{return await t()}catch(n){throw n instanceof s&&_(n.code)?new l(n.code,n.message,n.details):n}}i(r,"translateDocumentError");function _(t){return t==="stale_document"||t==="stale_comment"||t==="range_batch_incomplete"||t==="range_batch_stale"}i(_,"isDocumentErrorCode");export{l as ReviewDocumentError,v as createCommentAuthority};
|
|
@@ -3,6 +3,9 @@ export declare const MIN_COMPANION_COLS = 40;
|
|
|
3
3
|
export declare const MIN_COMPANION_ROWS = 12;
|
|
4
4
|
export declare const COMPANION_WIDTH_RATIO = 0.42;
|
|
5
5
|
export declare const COMPANION_HEIGHT_RATIO = 0.4;
|
|
6
|
+
/** A fork column narrower than this cannot hold a readable conversation, so the
|
|
7
|
+
* split is refused rather than shipping an unusable pane. */
|
|
8
|
+
export declare const MIN_FORK_COLS = 52;
|
|
6
9
|
export type CompanionPaneOrigin = 'opened' | 'adopted';
|
|
7
10
|
export type CompanionPaneResult = {
|
|
8
11
|
ok: true;
|
|
@@ -20,6 +23,20 @@ export declare function openCompanionPane(args: {
|
|
|
20
23
|
cwd: string;
|
|
21
24
|
callerPane: string | undefined;
|
|
22
25
|
}): CompanionPaneResult;
|
|
26
|
+
/** Open a column for a comment's fork, splitting the rightmost review pane —
|
|
27
|
+
* the newest fork, else the companion — so columns accumulate to the right and
|
|
28
|
+
* the document keeps its width. */
|
|
29
|
+
export declare function openForkPane(args: {
|
|
30
|
+
nodeId: string;
|
|
31
|
+
cwd: string;
|
|
32
|
+
splitFrom: string | undefined;
|
|
33
|
+
}): {
|
|
34
|
+
ok: true;
|
|
35
|
+
paneId: string;
|
|
36
|
+
} | {
|
|
37
|
+
ok: false;
|
|
38
|
+
reason: 'no_tmux' | 'no_caller_pane' | 'split_refused' | 'no_room';
|
|
39
|
+
};
|
|
23
40
|
/** True while tmux can still describe `paneId` and its process is alive.
|
|
24
41
|
* Deliberately tag-free: a companion pane carries `@crtr_node` only once its
|
|
25
42
|
* viewer has connected, so a tag check would call a still-booting pane dead
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var M=Object.defineProperty;var a=(e,o)=>M(e,"name",{value:o,configurable:!0});import{inTmux as p,liveViewerPanes as O,paneRunning as d,paneSize as _,splitWindow as m,paneExists as I,getPaneOption as N,closePane as k}from"../../../core/runtime/placement-tmux.js";import{viewerEnv as P}from"../../../commands/surface/node/placement.js";const h=99,C=40,v=12,w=.42,S=.4,z=52;function L(e){const{companionNodeId:o,cwd:s,callerPane:n}=e;if(!p())return{ok:!1,reason:"no_tmux"};const t=O().filter(r=>r.nodeId===o&&d(r.pane)).sort((r,x)=>x.stampMs-r.stampMs);if(t.length>0)return{ok:!0,paneId:t[0].pane,origin:"adopted"};if(n===void 0||n==="")return{ok:!1,reason:"no_caller_pane"};const l=_(n);if(l===null)return{ok:!1,reason:"split_refused"};let c,u;l.cols>=h?(c=!1,u=Math.max(C,Math.round(l.cols*w))):(c=!0,u=Math.max(v,Math.round(l.rows*S)));const f=m(n,{cwd:s,env:P(),command:`crtr surface attach to ${o}`,vertical:c,size:u});return f===null?{ok:!1,reason:"split_refused"}:{ok:!0,paneId:f,origin:"opened"}}a(L,"openCompanionPane");function R(e){const{nodeId:o,cwd:s,splitFrom:n}=e;if(!p())return{ok:!1,reason:"no_tmux"};if(n===void 0||n==="")return{ok:!1,reason:"no_caller_pane"};const i=_(n);if(i===null)return{ok:!1,reason:"split_refused"};if(Math.floor(i.cols/2)<z)return{ok:!1,reason:"no_room"};const t=m(n,{cwd:s,env:P(),command:`crtr surface attach to ${o}`,vertical:!1,size:Math.floor(i.cols/2)});return t===null?{ok:!1,reason:"split_refused"}:{ok:!0,paneId:t}}a(R,"openForkPane");function E(e){return I(e)&&d(e)}a(E,"companionPaneLive");function F(e,o){!I(e)||N(e,"@crtr_node")!==o||k(e)}a(F,"closeCompanionPane");export{S as COMPANION_HEIGHT_RATIO,w as COMPANION_WIDTH_RATIO,C as MIN_COMPANION_COLS,v as MIN_COMPANION_ROWS,z as MIN_FORK_COLS,h as SPLIT_MIN_COLS,F as closeCompanionPane,E as companionPaneLive,L as openCompanionPane,R as openForkPane};
|
|
@@ -62,6 +62,9 @@ export declare class ReviewDocumentSurface implements SurfaceComponent {
|
|
|
62
62
|
* `paneOrigin` is status-row copy only: teardown reads `paneId`. */
|
|
63
63
|
private paneId;
|
|
64
64
|
private paneOrigin;
|
|
65
|
+
/** Fork columns this surface opened, oldest first. The newest live one is
|
|
66
|
+
* what the next fork splits against, so columns accumulate rightward. */
|
|
67
|
+
private forkPanes;
|
|
65
68
|
/** Row increments of a half-page move still to be painted, and the timer
|
|
66
69
|
* walking them. A fresh press settles whatever is in flight before starting
|
|
67
70
|
* its own move, so a held key cannot pile up overlapping animations. */
|
|
@@ -126,6 +129,13 @@ export declare class ReviewDocumentSurface implements SurfaceComponent {
|
|
|
126
129
|
* live pane already and there is no live companion viewer to adopt. A second
|
|
127
130
|
* call therefore keeps the bound pane, whatever state its viewer is in. */
|
|
128
131
|
openCompanion(): void;
|
|
132
|
+
/** The pane a new fork column splits from: the newest live fork, else the
|
|
133
|
+
* companion, else this viewer. */
|
|
134
|
+
private rightmostReviewPane;
|
|
135
|
+
/** Hand one comment to its own fork of the companion and place its column.
|
|
136
|
+
* The comment is already saved by the time this runs, so every failure here
|
|
137
|
+
* is stated as a notice rather than failing the comment. */
|
|
138
|
+
private forkComment;
|
|
129
139
|
/** The one path out of a review that has reached a terminal state — approved,
|
|
130
140
|
* canceled here, or decided elsewhere. The pane goes with the review, never
|
|
131
141
|
* with Esc: closing the document leaves the conversation standing so the
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var J=Object.defineProperty;var d=(o,e)=>J(o,"name",{value:e,configurable:!0});import{relative as Q,resolve as E}from"node:path";import{CURSOR_MARKER as H,Key as Z,matchesKey as k}from"@earendil-works/pi-tui";import{documentLines as ee}from"../../../core/document-lines.js";import{codeRenderedDoc as te}from"../../../core/termrender/code-doc.js";import{deriveAnchorUnits as $,remapUnitIndex as j,unitIndexForLine as se,unitRangeForSpan as T}from"./anchors.js";import{centerHorizontal as W,clipLine as w,CYAN as A,DIM as p,RESET as l,REVERSE as ie,sanitize as N,truncate as ne,visibleWidth as b,YELLOW as O}from"../tui/ansi.js";import{ReviewDocumentError as oe}from"./comments-client.js";import{closeCompanionPane as re,companionPaneLive as ce,openCompanionPane as ae}from"./companion-pane.js";import{PAN_STEP as he,docSurface as de,maxHScroll as le,panBy as ue,renderReviewDoc as fe,renderReviewFrame as me,renderWidthForCols as pe,reservedRows as F}from"./frame.js";import{matchReviewKey as B,reviewKeyText as C}from"./keys.js";import{renderInputBuffer as ge}from"../tui/render.js";import{openReviewedFileInEditor as we}from"./nvim.js";import{buildLineMap as K,remapRange as ve}from"./remap.js";import{cleanPastedText as be,closeCompose as Le,closeHelp as _,closeList as Re,commitCompose as xe,ensureAnchorVisible as g,halfPageRows as Se,initReviewState as $e,moveActiveUnit as V,moveListIndex as q,moveViewRows as Ae,openComposeEdit as Ce,openComposeNew as Me,openHelp as ye,openList as Ie,scrollBy as De,textBackspace as Pe,textDelete as Ue,textEnd as Ee,textHome as He,textInsert as M,textVerticalWrapped as je,textWordBackspace as Te,textWordLeft as We,textWordRight as Ne,deleteAtListIndex as Oe,undoLast as Fe}from"./state.js";const Be=126,Ke=4,_e=24;class ut{static{d(this,"ReviewDocumentSurface")}absFile;fileLabel;companionNodeId;companionCwd;callerPane;kind;source;comments;services;unsubscribeComments;ready;cols=0;hostRows=0;flowedRows=-1;_focused=!1;closed=!1;spaceArmed=!1;escapeConfirmArmed=!1;cancelArmed=!1;tornDown=!1;tornDownNotice;handle;paneId;paneOrigin;scrollSteps=[];scrollTimer;state;cache;projection=[];status="preparing";problem;composeAnchorLost=!1;remapChain=Promise.resolve();constructor(e){this.absFile=e.review.file,this.fileLabel=Ge(e.review.cwd,e.review.file),this.companionNodeId=e.review.companionNodeId,this.companionCwd=e.review.cwd,this.callerPane=e.callerPane,this.kind=de(e.review.file),this.source=e.source,this.comments=e.comments,this.services=e.services,this.source.onChange((t,s)=>{this.onSourceChanged(t,s)}),this.unsubscribeComments=this.comments.onChanged(()=>{this.refreshProjection()}),this.ready=this.align().catch(t=>{this.closed||(this.status="refused",this.problem=R(t),this.repaint())})}open(){return this.ready}hasUnsentCompose(){const e=this.state;return e?.mode==="compose"&&e.compose!==null&&e.compose.buffer.length>0}get focused(){return this._focused}set focused(e){this._focused!==e&&(this._focused=e,this.repaint())}setRows(e){this.hostRows=Math.max(0,Math.floor(e))}render(e){const t=Math.max(0,Math.floor(e));if(this.hostRows<=0)return[];const s=Math.min(t,Be);(s!==this.cols||this.hostRows!==this.flowedRows)&&(this.cols=s,this.flowedRows=this.hostRows,this.reflow());const i=this.rows<=0||this.cols<=0?[]:this.renderDocument();return[...qe(i,this.rows,t),this.statusRow(t)]}get rows(){return Math.max(0,this.hostRows-1)}renderDocument(){if(this.status!=="ready"||this.state===void 0)return this.renderPlaceholder();const e=this.document(this.cols,this.state.sourceRevision),t=me(this.state,this.fileLabel,e,this.cols,this.rows,{lineNumbers:this.kind.doc==="code",...this.footerLine()===void 0?{}:{notice:this.footerLine()}}),s=this.state.mode==="list"&&this.state.comments.some(n=>n.anchorStatus==="detached")?this.renderGroupedList(t):t,i=this.state.mode==="compose"&&this.composeAnchorLost?this.statedComposeAnchor(s):s;return this.focused?this.markCursorLocation(i,this.state):i}handleInput(e){if(!this.closed){if(this.cancelArmed){this.cancelArmed=!1;const t=B(e);if(t!==null&&C(t)==="x"){this.services.cancel();return}}if(k(e,Z.escape)){if(this.escapeConfirmArmed){if(this.escapeConfirmArmed=!1,this.consume(e))return;this.services.requestClose();return}if(this.hasUnsentCompose()){this.escapeConfirmArmed=!0,this.services.notice("unsent comment \u2014 press esc again to discard"),this.repaint();return}if(this.consume(e))return;this.services.requestClose();return}this.escapeConfirmArmed&&(this.escapeConfirmArmed=!1),this.consume(e)}}consume(e){if(this.status!=="ready")return!1;const t=this.state;if(t===void 0)return!1;const s=B(e);if(s===null)return!1;if(t.mode==="compose")return this.handleComposeKey(s),this.repaint(),!0;if(this.spaceArmed)return this.handleLeaderKey(s),!0;if(t.mode==="list"){const i=this.handleListKey(s);return this.repaint(),i}return t.mode==="help"?s.type==="help"||s.type==="cancel"&&s.text===void 0?(this.state=_(t),this.repaint(),!0):s.type==="cancel"?(this.state=_(t),this.repaint(),!0):!1:this.handleViewKey(s)}handleWheel(e,t){if(this.closed)return!1;const s=this.state;if(this.status!=="ready"||s===void 0)return!0;this.settleScrollAnimation();const i=this.state??s,n=this.document(this.cols,i.sourceRevision),r=(e==="up"?-1:1)*Math.max(1,Math.floor(t));return this.state=De(i,r,this.bodyHeight(i),n.lines.length),this.repaint(),!0}startScrollAnimation(e){this.settleScrollAnimation();const t=Ve(e),s=t.shift();s!==void 0&&(this.applyScrollRows(s),this.scrollSteps=t,this.scheduleScrollStep())}scheduleScrollStep(){this.scrollSteps.length!==0&&(this.scrollTimer=setTimeout(()=>{this.scrollTimer=void 0;const e=this.scrollSteps.shift();e===void 0||this.closed||(this.applyScrollRows(e),this.repaint(),this.scheduleScrollStep())},_e))}settleScrollAnimation(){this.stopScrollAnimation();const e=this.scrollSteps;this.scrollSteps=[];for(const t of e)this.applyScrollRows(t)}stopScrollAnimation(){this.scrollTimer!==void 0&&(clearTimeout(this.scrollTimer),this.scrollTimer=void 0)}applyScrollRows(e){const t=this.state;if(this.status!=="ready"||t===void 0)return;const s=this.document(this.cols,t.sourceRevision);this.state=Ae(t,e,this.bodyHeight(t),s.lines.length)}invalidate(){this.closed||this.handle?.invalidate()}setHandle(e){if(this.handle===void 0&&(this.handle=e,e.onClose(()=>this.close()),this.tornDown)){e.close();const t=this.tornDownNotice;this.tornDownNotice=void 0,t!==void 0&&this.services.notice(t.text,t.opts)}}summary(){if(this.status==="refused")return`${this.fileLabel} \u2014 unavailable`;if(this.status==="preparing")return`${this.fileLabel} \u2014 preparing`;const e=this.projection.filter(i=>i.status==="open").length,t=this.projection.filter(i=>i.anchorStatus==="detached").length,s=[this.fileLabel,`${e} open`];return t>0&&s.push(`${t} detached`),this.source.current().status==="stale"&&s.push(`stale (${this.source.current().staleReason??"unreadable"})`),s.join(" \xB7 ")}companionSegment(){return this.paneOrigin===void 0?"companion none":`companion ${this.paneOrigin}`}statusRow(e){if(e<=0)return"";const t=w(this.companionSegment(),e),s=w(this.summary(),Math.max(0,e-b(t)-1)),i=Math.max(0,e-b(s)-b(t));return`${p}${s}${" ".repeat(i)}${t}${l}`}openCompanion(){if(this.closed||this.tornDown||this.paneId!==void 0&&ce(this.paneId))return;const e=ae({companionNodeId:this.companionNodeId,cwd:this.companionCwd,callerPane:this.callerPane});if(e.ok){this.paneId=e.paneId,this.paneOrigin=e.origin,this.repaint();return}if(e.reason==="split_refused"){this.services.notice("tmux refused the companion split \u2014 press space a to retry");return}this.services.notice(`The review companion needs tmux \u2014 run: crtr surface attach to ${this.companionNodeId}`,{sticky:!0})}teardown(e,t){this.tornDown||(this.tornDown=!0,this.paneId!==void 0&&re(this.paneId,this.companionNodeId),this.paneId=void 0,this.paneOrigin=void 0,this.handle===void 0&&(this.tornDownNotice={text:e,...t===void 0?{}:{opts:t}}),this.handle?.close(),this.services.notice(e,t))}close(){this.closed||(this.source.close(),this.closed=!0,this.stopScrollAnimation(),this.scrollSteps=[],this.unsubscribeComments(),this.cache=void 0)}async align(){for(;;){const e=await this.comments.anchorBase();if(this.closed)return;if(E(e.file)!==E(this.absFile))throw new Error(`review document mismatch \u2014 the daemon's canonical file is ${e.file}, not ${this.absFile}`);const t=this.source.current();if(t.status==="stale")throw new Error(`the reviewed file cannot be read (${t.staleReason??"unreadable"})`);if(e.docHash!==t.sha256){const i=await this.comments.list();if(this.closed)return;if(this.movedSince(t))continue;const n=K(ee(e.text),t.lines);if(await this.comments.remapRanges({fromDocHash:e.docHash,toDocHash:t.sha256,entries:Je(y(i),n)}),this.closed)return}const s=await this.comments.list();if(this.closed)return;if(!this.movedSince(t)){this.projection=y(s),this.status="ready",this.buildState(t),this.repaint();return}}}movedSince(e){const t=this.source.current();return t.status==="live"&&t.sha256!==e.sha256}async realign(){if(!this.closed)try{await this.align()}catch(e){if(this.closed)return;this.status="refused",this.problem=R(e),this.repaint()}}buildState(e){const t=this.document(this.cols,e.revision);this.state=$e(e.lines,$(t),I(this.projection),e.revision),this.state=g(this.state,t,this.bodyHeight(this.state))}onSourceChanged(e,t){if(this.closed||this.status!=="ready")return;const s=this.state;if(s===void 0)return;if(e.status==="stale"){this.problem=void 0,this.repaint();return}if(e.text===t.text){this.problem=void 0,this.repaint();return}const i=K(t.lines,e.lines),n=new Map;for(const a of this.projection)n.set(a.id,a.anchorStatus==="detached"?{range:a.originalRange??{line:a.line,endLine:a.endLine},detached:!0}:L(i,{line:a.line,endLine:a.endLine}));const r=s.compose===null||this.composeAnchorLost?void 0:L(i,s.compose.anchor),c=L(i,z(s,s.activeUnit)),u=s.selectionAnchor===null?void 0:L(i,z(s,s.selectionAnchor)),m=Ye(i,this.topVisibleSourceLine(s),t.lines.length),v=this.document(this.cols,e.revision),{units:f,rowUnits:h}=$(v),G=T(f,c.range.line,c.range.endLine).hi,Y=u===void 0?null:T(f,u.range.line,u.range.endLine).lo,x=this.projection.map(a=>{const U=n.get(a.id);return U===void 0?a:Xe(a,U)});this.projection=x;const P={};for(const a of x)a.anchorStatus==="detached"&&(P[a.id]=a.originalRange??{line:a.line,endLine:a.endLine});this.composeAnchorLost=this.composeAnchorLost||r?.detached===!0;const X=s.compose===null||r===void 0?s.compose:{...s.compose,anchor:r.range};let S={...s,sourceLines:e.lines,units:f,rowUnits:h,comments:I(x),sourceRevision:e.revision,detached:P,activeUnit:G,selectionAnchor:Y,compose:X,listIndex:Math.max(0,Math.min(s.listIndex,x.length-1)),scroll:f[se(f,m)]?.firstRow??0};S=g(S,v,this.bodyHeight(S)),this.state=S,this.problem=this.composeAnchorLost?"the commented lines were removed \u2014 this comment has no anchor":void 0,this.repaint(),this.remapChain=this.remapChain.then(()=>this.submitBatch(t.sha256,e.sha256,n),()=>this.submitBatch(t.sha256,e.sha256,n))}async submitBatch(e,t,s){if(this.closed)return;const i=[...s].map(([n,r])=>r.detached?{id:n,detached:!0}:{id:n,anchor:r.range});try{if(await this.comments.remapRanges({fromDocHash:e,toDocHash:t,entries:i}),this.closed)return;await this.refreshProjection()}catch(n){if(this.closed)return;this.problem=`comment ranges were rejected \u2014 ${R(n)}`,this.repaint(),await this.realign()}}async refreshProjection(){if(!(this.closed||this.status==="refused"))try{const e=y(await this.comments.list());if(this.closed)return;this.projection=e;const t=this.state;if(t!==void 0){const s=I(e);this.state={...t,comments:s,detached:Object.fromEntries(s.flatMap(i=>i.anchorStatus==="detached"?[[i.id,i.originalRange??{line:i.line,endLine:i.endLine}]]:[])),listIndex:Math.max(0,Math.min(t.listIndex,s.length-1))}}this.repaint()}catch(e){if(this.closed)return;this.problem=`comments could not be read \u2014 ${R(e)}`,this.repaint()}}async mutate(e){if(!this.closed){try{if(await e(),this.closed)return;this.problem=void 0}catch(t){if(this.closed)return;this.problem=t instanceof oe?`${t.code.replace(/_/g," ")} \u2014 the document moved under this comment`:R(t),this.repaint()}await this.refreshProjection()}}handleComposeKey(e){const t=this.state,s=t?.compose;if(t===void 0||s===null||s===void 0)return;if(e.type==="cancel"&&e.text===void 0){this.composeAnchorLost=!1,this.state=Le(t);return}if(e.type==="confirm"){if(this.composeAnchorLost){this.problem="comment not saved \u2014 its anchored lines were removed";return}const n=xe(t);this.composeAnchorLost=!1,this.state=n.state;const r=n.commit;if(r===null)return;const c=this.source.current().sha256;if(r.editingId===null){this.mutate(()=>this.comments.create({line:r.anchor.line,endLine:r.anchor.endLine,text:r.text,docHash:c}));return}const u=this.projection.find(m=>m.id===r.editingId);if(u===void 0){this.problem="that comment no longer exists";return}this.mutate(()=>this.comments.edit({id:u.id,text:r.text,ifRevision:u.revision}));return}if(e.type==="composeNewline"){this.state={...t,compose:{...s,...M(s.buffer,s.cursor,`
|
|
2
|
-
`)}};return}if(e.type==="composeWordBackspace"){this.state={...t,compose:{...s,...Te(s.buffer,s.cursor)}};return}if(e.type==="composeBackspace"){this.state={...t,compose:{...s,...
|
|
1
|
+
var Z=Object.defineProperty;var d=(o,e)=>Z(o,"name",{value:e,configurable:!0});import{relative as k,resolve as H}from"node:path";import{CURSOR_MARKER as j,Key as ee,matchesKey as te}from"@earendil-works/pi-tui";import{documentLines as se}from"../../../core/document-lines.js";import{codeRenderedDoc as ie}from"../../../core/termrender/code-doc.js";import{deriveAnchorUnits as $,remapUnitIndex as F,unitIndexForLine as ne,unitRangeForSpan as T}from"./anchors.js";import{centerHorizontal as W,clipLine as v,CYAN as A,DIM as g,RESET as l,REVERSE as oe,sanitize as N,truncate as re,visibleWidth as L,YELLOW as O}from"../tui/ansi.js";import{ReviewDocumentError as ce}from"./comments-client.js";import{closeCompanionPane as _,companionPaneLive as C,openCompanionPane as ae,openForkPane as he}from"./companion-pane.js";import{PAN_STEP as de,docSurface as le,maxHScroll as ue,panBy as fe,renderReviewDoc as me,renderReviewFrame as pe,renderWidthForCols as ge,reservedRows as B}from"./frame.js";import{matchReviewKey as K,reviewKeyText as I}from"./keys.js";import{renderInputBuffer as we}from"../tui/render.js";import{openReviewedFileInEditor as ve}from"./nvim.js";import{buildLineMap as V,remapRange as be}from"./remap.js";import{cleanPastedText as Le,closeCompose as Re,closeHelp as q,closeList as xe,commitCompose as Se,ensureAnchorVisible as w,halfPageRows as $e,initReviewState as Ae,moveActiveUnit as z,moveListIndex as G,moveViewRows as Ce,openComposeEdit as Ie,openComposeNew as ye,openHelp as Me,openList as Pe,scrollBy as De,textBackspace as Ue,textDelete as Ee,textEnd as He,textHome as je,textInsert as y,textVerticalWrapped as Fe,textWordBackspace as Te,textWordLeft as We,textWordRight as Ne,deleteAtListIndex as Oe,undoLast as _e}from"./state.js";const Be=126,Ke=4,Ve=24;class ft{static{d(this,"ReviewDocumentSurface")}absFile;fileLabel;companionNodeId;companionCwd;callerPane;kind;source;comments;services;unsubscribeComments;ready;cols=0;hostRows=0;flowedRows=-1;_focused=!1;closed=!1;spaceArmed=!1;escapeConfirmArmed=!1;cancelArmed=!1;tornDown=!1;tornDownNotice;handle;paneId;paneOrigin;forkPanes=[];scrollSteps=[];scrollTimer;state;cache;projection=[];status="preparing";problem;composeAnchorLost=!1;remapChain=Promise.resolve();constructor(e){this.absFile=e.review.file,this.fileLabel=Ye(e.review.cwd,e.review.file),this.companionNodeId=e.review.companionNodeId,this.companionCwd=e.review.cwd,this.callerPane=e.callerPane,this.kind=le(e.review.file),this.source=e.source,this.comments=e.comments,this.services=e.services,this.source.onChange((t,s)=>{this.onSourceChanged(t,s)}),this.unsubscribeComments=this.comments.onChanged(()=>{this.refreshProjection()}),this.ready=this.align().catch(t=>{this.closed||(this.status="refused",this.problem=b(t),this.repaint())})}open(){return this.ready}hasUnsentCompose(){const e=this.state;return e?.mode==="compose"&&e.compose!==null&&e.compose.buffer.length>0}get focused(){return this._focused}set focused(e){this._focused!==e&&(this._focused=e,this.repaint())}setRows(e){this.hostRows=Math.max(0,Math.floor(e))}render(e){const t=Math.max(0,Math.floor(e));if(this.hostRows<=0)return[];const s=Math.min(t,Be);(s!==this.cols||this.hostRows!==this.flowedRows)&&(this.cols=s,this.flowedRows=this.hostRows,this.reflow());const i=this.rows<=0||this.cols<=0?[]:this.renderDocument();return[...ze(i,this.rows,t),this.statusRow(t)]}get rows(){return Math.max(0,this.hostRows-1)}renderDocument(){if(this.status!=="ready"||this.state===void 0)return this.renderPlaceholder();const e=this.document(this.cols,this.state.sourceRevision),t=pe(this.state,this.fileLabel,e,this.cols,this.rows,{lineNumbers:this.kind.doc==="code",...this.footerLine()===void 0?{}:{notice:this.footerLine()}}),s=this.state.mode==="list"&&this.state.comments.some(n=>n.anchorStatus==="detached")?this.renderGroupedList(t):t,i=this.state.mode==="compose"&&this.composeAnchorLost?this.statedComposeAnchor(s):s;return this.focused?this.markCursorLocation(i,this.state):i}handleInput(e){if(!this.closed){if(this.cancelArmed){this.cancelArmed=!1;const t=K(e);if(t!==null&&I(t)==="x"){this.services.cancel();return}}if(te(e,ee.escape)){if(this.escapeConfirmArmed){if(this.escapeConfirmArmed=!1,this.consume(e))return;this.services.requestClose();return}if(this.hasUnsentCompose()){this.escapeConfirmArmed=!0,this.services.notice("unsent comment \u2014 press esc again to discard"),this.repaint();return}if(this.consume(e))return;this.services.requestClose();return}this.escapeConfirmArmed&&(this.escapeConfirmArmed=!1),this.consume(e)}}consume(e){if(this.status!=="ready")return!1;const t=this.state;if(t===void 0)return!1;const s=K(e);if(s===null)return!1;if(t.mode==="compose")return this.handleComposeKey(s),this.repaint(),!0;if(this.spaceArmed)return this.handleLeaderKey(s),!0;if(t.mode==="list"){const i=this.handleListKey(s);return this.repaint(),i}return t.mode==="help"?s.type==="help"||s.type==="cancel"&&s.text===void 0?(this.state=q(t),this.repaint(),!0):s.type==="cancel"?(this.state=q(t),this.repaint(),!0):!1:this.handleViewKey(s)}handleWheel(e,t){if(this.closed)return!1;const s=this.state;if(this.status!=="ready"||s===void 0)return!0;this.settleScrollAnimation();const i=this.state??s,n=this.document(this.cols,i.sourceRevision),r=(e==="up"?-1:1)*Math.max(1,Math.floor(t));return this.state=De(i,r,this.bodyHeight(i),n.lines.length),this.repaint(),!0}startScrollAnimation(e){this.settleScrollAnimation();const t=qe(e),s=t.shift();s!==void 0&&(this.applyScrollRows(s),this.scrollSteps=t,this.scheduleScrollStep())}scheduleScrollStep(){this.scrollSteps.length!==0&&(this.scrollTimer=setTimeout(()=>{this.scrollTimer=void 0;const e=this.scrollSteps.shift();e===void 0||this.closed||(this.applyScrollRows(e),this.repaint(),this.scheduleScrollStep())},Ve))}settleScrollAnimation(){this.stopScrollAnimation();const e=this.scrollSteps;this.scrollSteps=[];for(const t of e)this.applyScrollRows(t)}stopScrollAnimation(){this.scrollTimer!==void 0&&(clearTimeout(this.scrollTimer),this.scrollTimer=void 0)}applyScrollRows(e){const t=this.state;if(this.status!=="ready"||t===void 0)return;const s=this.document(this.cols,t.sourceRevision);this.state=Ce(t,e,this.bodyHeight(t),s.lines.length)}invalidate(){this.closed||this.handle?.invalidate()}setHandle(e){if(this.handle===void 0&&(this.handle=e,e.onClose(()=>this.close()),this.tornDown)){e.close();const t=this.tornDownNotice;this.tornDownNotice=void 0,t!==void 0&&this.services.notice(t.text,t.opts)}}summary(){if(this.status==="refused")return`${this.fileLabel} \u2014 unavailable`;if(this.status==="preparing")return`${this.fileLabel} \u2014 preparing`;const e=this.projection.filter(i=>i.status==="open").length,t=this.projection.filter(i=>i.anchorStatus==="detached").length,s=[this.fileLabel,`${e} open`];return t>0&&s.push(`${t} detached`),this.source.current().status==="stale"&&s.push(`stale (${this.source.current().staleReason??"unreadable"})`),s.join(" \xB7 ")}companionSegment(){const e=this.paneOrigin===void 0?"companion none":`companion ${this.paneOrigin}`,t=this.forkPanes.length;return t===0?e:`${e} \xB7 ${t} fork${t===1?"":"s"}`}statusRow(e){if(e<=0)return"";const t=v(this.companionSegment(),e),s=v(this.summary(),Math.max(0,e-L(t)-1)),i=Math.max(0,e-L(s)-L(t));return`${g}${s}${" ".repeat(i)}${t}${l}`}openCompanion(){if(this.closed||this.tornDown||this.paneId!==void 0&&C(this.paneId))return;const e=ae({companionNodeId:this.companionNodeId,cwd:this.companionCwd,callerPane:this.callerPane});if(e.ok){this.paneId=e.paneId,this.paneOrigin=e.origin,this.repaint();return}if(e.reason==="split_refused"){this.services.notice("tmux refused the companion split \u2014 press space a to retry");return}this.services.notice(`The review companion needs tmux \u2014 run: crtr surface attach to ${this.companionNodeId}`,{sticky:!0})}rightmostReviewPane(){for(let e=this.forkPanes.length-1;e>=0;e-=1){const t=this.forkPanes[e];if(C(t.paneId))return t.paneId}return this.paneId!==void 0&&C(this.paneId)?this.paneId:this.callerPane}async forkComment(e){if(this.closed||this.tornDown)return;let t;try{t=await this.comments.fork(e)}catch(i){this.services.notice(`the comment was saved, but its fork could not start \u2014 ${b(i)}`);return}if(this.closed||this.tornDown)return;const s=he({nodeId:t.nodeId,cwd:t.cwd,splitFrom:this.rightmostReviewPane()});if(s.ok){this.forkPanes.push({paneId:s.paneId,nodeId:t.nodeId}),this.repaint();return}this.services.notice(s.reason==="no_room"?`no room for another fork column \u2014 the fork is running: crtr surface attach to ${t.nodeId}`:`the fork is running, but tmux gave it no column \u2014 run: crtr surface attach to ${t.nodeId}`,{sticky:!0})}teardown(e,t){if(!this.tornDown){this.tornDown=!0;for(const s of this.forkPanes)_(s.paneId,s.nodeId);this.forkPanes=[],this.paneId!==void 0&&_(this.paneId,this.companionNodeId),this.paneId=void 0,this.paneOrigin=void 0,this.handle===void 0&&(this.tornDownNotice={text:e,...t===void 0?{}:{opts:t}}),this.handle?.close(),this.services.notice(e,t)}}close(){this.closed||(this.source.close(),this.closed=!0,this.stopScrollAnimation(),this.scrollSteps=[],this.unsubscribeComments(),this.cache=void 0)}async align(){for(;;){const e=await this.comments.anchorBase();if(this.closed)return;if(H(e.file)!==H(this.absFile))throw new Error(`review document mismatch \u2014 the daemon's canonical file is ${e.file}, not ${this.absFile}`);const t=this.source.current();if(t.status==="stale")throw new Error(`the reviewed file cannot be read (${t.staleReason??"unreadable"})`);if(e.docHash!==t.sha256){const i=await this.comments.list();if(this.closed)return;if(this.movedSince(t))continue;const n=V(se(e.text),t.lines);if(await this.comments.remapRanges({fromDocHash:e.docHash,toDocHash:t.sha256,entries:Qe(M(i),n)}),this.closed)return}const s=await this.comments.list();if(this.closed)return;if(!this.movedSince(t)){this.projection=M(s),this.status="ready",this.buildState(t),this.repaint();return}}}movedSince(e){const t=this.source.current();return t.status==="live"&&t.sha256!==e.sha256}async realign(){if(!this.closed)try{await this.align()}catch(e){if(this.closed)return;this.status="refused",this.problem=b(e),this.repaint()}}buildState(e){const t=this.document(this.cols,e.revision);this.state=Ae(e.lines,$(t),P(this.projection),e.revision),this.state=w(this.state,t,this.bodyHeight(this.state))}onSourceChanged(e,t){if(this.closed||this.status!=="ready")return;const s=this.state;if(s===void 0)return;if(e.status==="stale"){this.problem=void 0,this.repaint();return}if(e.text===t.text){this.problem=void 0,this.repaint();return}const i=V(t.lines,e.lines),n=new Map;for(const a of this.projection)n.set(a.id,a.anchorStatus==="detached"?{range:a.originalRange??{line:a.line,endLine:a.endLine},detached:!0}:R(i,{line:a.line,endLine:a.endLine}));const r=s.compose===null||this.composeAnchorLost?void 0:R(i,s.compose.anchor),c=R(i,Y(s,s.activeUnit)),f=s.selectionAnchor===null?void 0:R(i,Y(s,s.selectionAnchor)),u=Xe(i,this.topVisibleSourceLine(s),t.lines.length),m=this.document(this.cols,e.revision),{units:p,rowUnits:h}=$(m),X=T(p,c.range.line,c.range.endLine).hi,J=f===void 0?null:T(p,f.range.line,f.range.endLine).lo,x=this.projection.map(a=>{const E=n.get(a.id);return E===void 0?a:Je(a,E)});this.projection=x;const U={};for(const a of x)a.anchorStatus==="detached"&&(U[a.id]=a.originalRange??{line:a.line,endLine:a.endLine});this.composeAnchorLost=this.composeAnchorLost||r?.detached===!0;const Q=s.compose===null||r===void 0?s.compose:{...s.compose,anchor:r.range};let S={...s,sourceLines:e.lines,units:p,rowUnits:h,comments:P(x),sourceRevision:e.revision,detached:U,activeUnit:X,selectionAnchor:J,compose:Q,listIndex:Math.max(0,Math.min(s.listIndex,x.length-1)),scroll:p[ne(p,u)]?.firstRow??0};S=w(S,m,this.bodyHeight(S)),this.state=S,this.problem=this.composeAnchorLost?"the commented lines were removed \u2014 this comment has no anchor":void 0,this.repaint(),this.remapChain=this.remapChain.then(()=>this.submitBatch(t.sha256,e.sha256,n),()=>this.submitBatch(t.sha256,e.sha256,n))}async submitBatch(e,t,s){if(this.closed)return;const i=[...s].map(([n,r])=>r.detached?{id:n,detached:!0}:{id:n,anchor:r.range});try{if(await this.comments.remapRanges({fromDocHash:e,toDocHash:t,entries:i}),this.closed)return;await this.refreshProjection()}catch(n){if(this.closed)return;this.problem=`comment ranges were rejected \u2014 ${b(n)}`,this.repaint(),await this.realign()}}async refreshProjection(){if(!(this.closed||this.status==="refused"))try{const e=M(await this.comments.list());if(this.closed)return;this.projection=e;const t=this.state;if(t!==void 0){const s=P(e);this.state={...t,comments:s,detached:Object.fromEntries(s.flatMap(i=>i.anchorStatus==="detached"?[[i.id,i.originalRange??{line:i.line,endLine:i.endLine}]]:[])),listIndex:Math.max(0,Math.min(t.listIndex,s.length-1))}}this.repaint()}catch(e){if(this.closed)return;this.problem=`comments could not be read \u2014 ${b(e)}`,this.repaint()}}async mutate(e){if(!this.closed){try{if(await e(),this.closed)return;this.problem=void 0}catch(t){if(this.closed)return;this.problem=t instanceof ce?`${t.code.replace(/_/g," ")} \u2014 the document moved under this comment`:b(t),this.repaint()}await this.refreshProjection()}}handleComposeKey(e){const t=this.state,s=t?.compose;if(t===void 0||s===null||s===void 0)return;if(e.type==="cancel"&&e.text===void 0){this.composeAnchorLost=!1,this.state=Re(t);return}if(e.type==="confirm"||e.type==="confirmFork"){if(this.composeAnchorLost){this.problem="comment not saved \u2014 its anchored lines were removed";return}const n=Se(t);this.composeAnchorLost=!1,this.state=n.state;const r=n.commit;if(r===null)return;const c=e.type==="confirmFork",f=this.source.current().sha256;if(r.editingId===null){this.mutate(async()=>{const m=await this.comments.create({line:r.anchor.line,endLine:r.anchor.endLine,text:r.text,docHash:f});c&&await this.forkComment(m)});return}const u=this.projection.find(m=>m.id===r.editingId);if(u===void 0){this.problem="that comment no longer exists";return}this.mutate(async()=>{await this.comments.edit({id:u.id,text:r.text,ifRevision:u.revision}),c&&await this.forkComment(u.id)});return}if(e.type==="composeNewline"){this.state={...t,compose:{...s,...y(s.buffer,s.cursor,`
|
|
2
|
+
`)}};return}if(e.type==="composeWordBackspace"){this.state={...t,compose:{...s,...Te(s.buffer,s.cursor)}};return}if(e.type==="composeBackspace"){this.state={...t,compose:{...s,...Ue(s.buffer,s.cursor)}};return}if(e.type==="composeDelete"){this.state={...t,compose:{...s,...Ee(s.buffer,s.cursor)}};return}if(e.type==="composeMove"){const n=e.direction==="wordLeft"?We(s.buffer,s.cursor):Ne(s.buffer,s.cursor);this.state={...t,compose:{...s,cursor:n}};return}if(e.type==="arrow"&&e.direction==="left"){this.state={...t,compose:{...s,cursor:Math.max(0,s.cursor-1)}};return}if(e.type==="arrow"&&e.direction==="right"){this.state={...t,compose:{...s,cursor:Math.min([...s.buffer].length,s.cursor+1)}};return}if(e.type==="composeHome"){this.state={...t,compose:{...s,cursor:je(s.buffer,s.cursor)}};return}if(e.type==="composeEnd"){this.state={...t,compose:{...s,cursor:He(s.buffer,s.cursor)}};return}if(e.type==="arrow"&&(e.direction==="up"||e.direction==="down")){const n=e.direction==="up"?-1:1;this.state={...t,compose:{...s,cursor:Fe(s.buffer,s.cursor,n,this.composeWidth())}};return}const i=I(e);if(i!==void 0){if(e.type==="paste"){const n=Le(i);if(n.length===0)return;this.state={...t,compose:{...s,...y(s.buffer,s.cursor,n)}};return}this.state={...t,compose:{...s,...y(s.buffer,s.cursor,i)}}}}handleLeaderKey(e){const t=this.state;if(this.spaceArmed=!1,t===void 0)return;const s=I(e);if(s==="c"){const i=ye(t);this.composeAnchorLost=!1,this.state=w(i,this.document(this.cols,i.sourceRevision),this.bodyHeight(i))}else if(s==="l")this.state=Pe(t);else if(s==="u"){const i=_e(t);if(i.id!==null){const n=i.id;this.mutate(()=>this.comments.remove(n))}}else if(s==="e")this.editInEditor();else if(s==="s"){const i=this.source.current();i.status==="stale"?this.problem=`approval refused while the source is ${i.staleReason??"unreadable"}`:this.services.submit()}else s==="a"?this.openCompanion():s==="x"&&this.armCancel();this.repaint()}armCancel(){this.cancelArmed=!0,this.services.notice("cancel this review? press x again to confirm")}handleListKey(e){const t=this.state;if(t===void 0)return!1;if(e.type==="cancel")return this.state=xe(t),!0;if(e.type==="moveUnit"&&e.text==="j"||e.type==="arrow"&&e.direction==="down")return this.state=G(t,1),!0;if(e.type==="moveUnit"&&e.text==="k"||e.type==="arrow"&&e.direction==="up")return this.state=G(t,-1),!0;if(e.type==="listEdit"||e.type==="confirm"){if(t.comments.length>0){const s=Ie(t,t.listIndex);this.composeAnchorLost=!1,this.state=w(s,this.document(this.cols,s.sourceRevision),this.bodyHeight(s))}return!0}if(e.type==="scrollPage"&&e.text==="d"&&t.comments.length>0){const s=Oe(t);if(s.id!==null){const i=s.id;this.mutate(()=>this.comments.remove(i))}return!0}return e.type==="leader"?(this.spaceArmed=!0,!0):!1}handleViewKey(e){const t=this.state;if(t===void 0)return!1;const s=this.document(this.cols,t.sourceRevision),i=this.bodyHeight(t);if(e.type==="leader")return this.spaceArmed=!0,!0;if(e.type==="moveUnit"||e.type==="arrow"&&(e.direction==="up"||e.direction==="down")){const n=e.type==="moveUnit"?e.delta:e.direction==="down"?1:-1;this.state=w(z(t,n,!1),s,i)}else if(e.type==="extendUnit")this.state=w(z(t,e.delta,!0),s,i);else if(e.type==="scrollPage")this.startScrollAnimation(e.delta*$e(i));else if((e.type==="pan"||e.type==="arrow"&&(e.direction==="left"||e.direction==="right"))&&ue(t,s,this.cols,this.rows,this.gutterWidth())>0){const n=e.type==="pan"?e.delta:e.direction==="right"?1:-1;this.state=fe(t,n*de,s,this.cols,this.rows,this.gutterWidth())}else if(e.type==="help")this.state=Me(t);else return e.type==="cancel"&&e.text===void 0||e.type==="cancel",!1;return this.repaint(),!0}editInEditor(){const e=this.state;if(e===void 0)return;const t=e.units[e.activeUnit]?.start??1,s=this.services.suspendForChild();try{const i=ve(this.absFile,t);i.error!==void 0&&(this.problem=`editor failed \u2014 ${i.error}`)}finally{s()}this.source.refreshNow()}markCursorLocation(e,t){if(t.mode==="compose")return D(e,oe);if(t.mode==="list"){const i=D(e,`${A}\u25B8${l}`);if(i!==e)return i}const s=this.activeAnchorFrameRow(t);return s===void 0?e:D(e,`${A}\u258C${l}`,s)}activeAnchorFrameRow(e){const t=Math.max(1,this.rows-B(e,this.cols)),s=e.rowUnits.length,i=Math.max(0,Math.min(e.scroll,Math.max(0,s-t)));for(let n=0;n<t;n++){const r=i+n;if(!(n===0&&i>0||n===t-1&&r<s-1)&&e.rowUnits[r]===e.activeUnit)return 3+n}}reflow(){const e=this.state;if(e===void 0||this.cols<=0)return;const t=e.units[e.activeUnit],s=e.selectionAnchor===null?void 0:e.units[e.selectionAnchor],i=this.document(this.cols,e.sourceRevision),{units:n,rowUnits:r}=$(i),c={...e,units:n,rowUnits:r,activeUnit:t===void 0?0:F(n,t),selectionAnchor:s===void 0?null:F(n,s)};this.state=w(c,i,this.bodyHeight(c))}document(e,t){const s=this.cache;if(s!==void 0&&s.width===e&&s.sourceRevision===t)return s.doc;const i=this.source.current().text,n=this.kind.doc==="code"?ie(i,this.kind.language??"text",ge(e)):me(i,e);return this.cache={width:e,sourceRevision:t,doc:n},n}bodyHeight(e){const t=e.mode==="list"&&e.comments.some(s=>s.anchorStatus==="detached")?1+(e.comments.some(s=>s.anchorStatus!=="detached")?1:0):0;return Math.max(1,this.rows-B(e,this.cols)-t)}composeWidth(){return Math.max(10,Math.min(Math.max(20,this.cols-4),120)-2)}gutterWidth(){return this.kind.doc==="code"?String(this.source.current().lines.length).length:0}footerLine(){if(this.problem!==void 0)return this.problem;const e=this.source.current();if(e.status==="stale")return`source ${e.staleReason??"unreadable"} \u2014 showing the last good read; approval is refused`}renderPlaceholder(){const t=["",` ${this.status==="refused"?`Review unavailable \u2014 ${this.problem??"the document could not be prepared"}`:`Preparing ${this.fileLabel}\u2026`}`];for(;t.length<this.rows;)t.push("");return t.slice(0,this.rows).map(s=>v(s,this.cols))}renderGroupedList(e){const t=this.state,s=Math.min(Math.max(20,this.cols-4),120),i=t.comments.filter(h=>h.anchorStatus==="detached"),n=t.comments.filter(h=>h.anchorStatus!=="detached"),r=[` ${O}Detached${l}`];for(const h of i)r.push(this.commentListRow(h,t.comments.indexOf(h),s,!0));if(n.length>0){r.push(` ${g}Comments${l}`);for(const h of n)r.push(this.commentListRow(h,t.comments.indexOf(h),s,!1))}r.push(""),r.push(` ${g}j/k${l} move ${g}enter/e${l} edit ${g}d${l} delete ${g}q/esc${l} close`);const c=Math.max(0,this.rows-3),f=r.slice(0,c),u=Math.max(3,this.rows-f.length),m=[...e],p=W(f,this.cols,Math.min(this.cols,s+2));for(let h=0;h<p.length;h++)m[u+h]=v(p[h]??"",this.cols);return m.slice(0,this.rows)}statedComposeAnchor(e){const t=this.state;if(t?.compose==null)return e;const s=Math.min(Math.max(20,this.cols-4),120),i=we(t.compose.buffer,t.compose.cursor,Math.max(10,s-2)).length,n=this.rows-(i+3);if(n<0||n>=e.length)return e;const r=[...e];return r[n]=v(W([` ${O}Comment anchor removed by an edit \u2014 esc, then re-anchor:${l}`],this.cols,Math.min(this.cols,s+2))[0]??"",this.cols),r}commentListRow(e,t,s,i){const n=i?e.originalRange??{line:e.line,endLine:e.endLine}:{line:e.line,endLine:e.endLine},r=n.line===n.endLine?`L${n.line}`:`L${n.line}-${n.endLine}`,c=t===this.state.listIndex?`${A}\u25B8${l}`:" ",u=`${i?`\u201C${N(e.lineText).replace(/\s+/g," ").trim()}\u201D \xB7 `:""}${N(e.comment).replace(/\s+/g," ").trim()}`;return` ${c} ${g}[${r}]${l} ${re(u,Math.max(10,s-14))}`}topVisibleSourceLine(e){const t=e.rowUnits[e.scroll];if(t!=null)return e.units[t]?.start??1;for(let s=e.scroll;s<e.rowUnits.length;s++){const i=e.rowUnits[s];if(i!=null)return e.units[i]?.start??1}return 1}repaint(){this.invalidate()}}function qe(o){const e=Math.abs(o);if(e===0)return[];const t=Math.sign(o),s=Math.min(Ke,e),i=[];let n=0;for(let r=1;r<=s;r++){const c=Math.round(e*r/s);i.push((c-n)*t),n=c}return i}d(qe,"splitScrollSteps");function ze(o,e,t){const s=o.slice(0,e).map(i=>Ge(i,t));for(;s.length<e;)s.push(" ".repeat(t));return s}d(ze,"exactRows");function Ge(o,e){const t=o.split(j).join(""),s=L(t);if(s>e){const i=v(t,e);return i+" ".repeat(Math.max(0,e-L(i)))}return o+" ".repeat(e-s)}d(Ge,"padTo");function Ye(o,e){const t=k(o,e);return t===""||t.startsWith("..")?e:t}d(Ye,"labelFor");function M(o){return o.filter(e=>e.status!=="deleted")}d(M,"nonDeleted");function P(o){const e=o.filter(s=>s.anchorStatus==="detached"),t=o.filter(s=>s.anchorStatus!=="detached");return[...e,...t]}d(P,"orderedForDisplay");function Y(o,e){const t=o.units[e];return t===void 0?{line:1,endLine:1}:{line:t.start,endLine:t.end}}d(Y,"unitRange");function R(o,e){const t=be(o,{line:e.line-1,endLine:e.endLine});return t.kind==="detached"?{range:e,detached:!0}:{range:{line:t.line+1,endLine:Math.max(t.line+1,t.endLine)},detached:!1}}d(R,"mapRange");function Xe(o,e,t){const s=e-1,i=o.get(s);if(i!==void 0)return i+1;for(let n=1;n<t;n++){const r=o.get(s+n);if(r!==void 0)return r+1;const c=o.get(s-n);if(c!==void 0)return c+1}return 1}d(Xe,"mapLine");function Je(o,e){if(e.detached)return{...o,anchorStatus:"detached",originalRange:o.originalRange??{line:o.line,endLine:o.endLine}};if(o.anchorStatus==="detached")return o;const t=e.range.line!==o.line||e.range.endLine!==o.endLine;return{...o,line:e.range.line,endLine:e.range.endLine,anchorStatus:t?"shifted":o.anchorStatus}}d(Je,"applyMappedRange");function Qe(o,e){return o.map(t=>{if(t.anchorStatus==="detached")return{id:t.id,detached:!0};const s=R(e,{line:t.line,endLine:t.endLine});return s.detached?{id:t.id,detached:!0}:{id:t.id,anchor:s.range}})}d(Qe,"batchEntries");function D(o,e,t){const s=t??o.findIndex(c=>c.includes(e)),i=o[s];if(i===void 0)return o;const n=i.indexOf(e);if(n===-1)return o;const r=[...o];return r[s]=`${i.slice(0,n)}${j}${i.slice(n)}`,r}d(D,"markAtToken");function b(o){return o instanceof Error?o.message:String(o)}d(b,"describe");export{ft as ReviewDocumentSurface};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var q=Object.defineProperty;var $=(e,s)=>q(e,"name",{value:s,configurable:!0});import G from"string-width";import{renderMarkdownBlockAware as J}from"../../../core/termrender/termrender.js";import{fenceLanguageFor as K,isMarkdownFile as V}from"../../../core/termrender/code-doc.js";import{renderInputBuffer as
|
|
1
|
+
var q=Object.defineProperty;var $=(e,s)=>q(e,"name",{value:s,configurable:!0});import G from"string-width";import{renderMarkdownBlockAware as J}from"../../../core/termrender/termrender.js";import{fenceLanguageFor as K,isMarkdownFile as V}from"../../../core/termrender/code-doc.js";import{renderInputBuffer as B}from"../tui/render.js";import{BOLD as Q,CYAN as L,DIM as o,ESC as X,RESET as n,YELLOW as W,centerHorizontal as S,clipLine as Z,hline as ee,panLine as ne,sanitize as oe,truncate as te,visibleWidth as k}from"../tui/ansi.js";import{commentedUnitSet as re,selectedUnitBounds as se}from"./state.js";function E(e){return Math.min(Math.max(20,e-6),120)}$(E,"renderWidthForCols");function F(e){return Math.max(20,e-4)}$(F,"contentWidthForCols");function I(e,s=0){return Math.max(1,F(e)-(s>0?s+1:0))}$(I,"bodyWidth");function fe(e,s){return J(e,E(s),F(s))}$(fe,"renderReviewDoc");function C(e,s,c){const t=[];for(let l=0;l<c;l++){const h=s+l;t.push(h<e.lines.length?{abs:h,line:e.lines[h]}:{abs:null,line:""})}s>0&&t.length>0&&(t[0]={abs:null,line:` ${o}\u2191 ${s} more above${n}`});const a=e.lines.length-(s+c);return a>0&&t.length>0&&(t[t.length-1]={abs:null,line:` ${o}\u2193 ${a} more below${n}`}),t}$(C,"paintedBodyRows");function T(e,s,c){let t=0;for(const a of C(e,s,c))t=Math.max(t,k(a.line));return t}$(T,"widestVisibleRow");function ie(e,s,c,t,a=0){const l=Math.max(1,t-ae(e,c)),h=Math.max(0,s.lines.length-l),d=Math.max(0,Math.min(e.scroll,h));return Math.max(0,T(s,d,l)-I(c,a))}$(ie,"maxHScroll");function xe(e,s,c,t,a,l=0){const h=ie(e,c,t,a,l),d=Math.max(0,Math.min(e.hscroll+s,h));return d===e.hscroll?e:{...e,hscroll:d}}$(xe,"panBy");const ge=8,A=`${X}48;5;236m`;function ce(e,s){const c=Math.max(0,s-G(oe(e)));return A+e.replaceAll(n,n+A)+" ".repeat(c)+n}$(ce,"tintRow");function ae(e,s){if(e.mode==="view")return 4;if(e.mode==="compose"){const t=e.compose,a=Math.min(Math.max(20,s-4),120);return 6+(t?B(t.buffer,t.cursor,Math.max(10,a-2)).length:1)}return e.mode==="list"?3+Math.max(1,e.comments.length)+2:12}$(ae,"reservedRows");function Me(e,s,c,t,a,l){const h=Math.min(Math.max(20,t-4),120),d=E(t),R=["",` ${Q}${L}Review \u2014 ${s}${n} ${o}${e.comments.length} comment${e.comments.length===1?"":"s"}${n}`,` ${o}${ee(h)}${n}`],i=[];if(e.mode==="compose"&&e.compose){const r=e.compose,m=r.anchor.line===r.anchor.endLine?`L${r.anchor.line}`:`L${r.anchor.line}-${r.anchor.endLine}`;i.push(` ${W}${r.editingId!==null?"Edit comment":"Comment"} on ${m}:${n}`);for(const u of B(r.buffer,r.cursor,Math.max(10,h-2)))i.push(` ${u}`);i.push(""),i.push(` ${o}enter${n} save ${o}^\u23CE/^F${n} save + fork ${o}^J/\u2325\u23CE${n} newline ${o}esc${n} cancel`)}else e.mode==="list"?(e.comments.length===0?i.push(` ${o}(no comments yet \u2014 space c to add one)${n}`):e.comments.forEach((r,m)=>{const u=r.line===r.endLine?`L${r.line}`:`L${r.line}-${r.endLine}`,w=m===e.listIndex?`${L}\u25B8${n}`:" ",x=te(r.comment.replace(/\n/g," / "),Math.max(10,h-14));i.push(` ${w} ${o}[${u}]${n} ${x}`)}),i.push(""),i.push(` ${o}j/k${n} move ${o}enter/e${n} edit ${o}d${n} delete ${o}q/esc${n} close`)):e.mode==="help"?(i.push(" Keys:"),i.push(` ${o}j/k${n} move anchor ${o}shift-j/k${n} extend selection`),i.push(` ${o}u/d${n} move half a page ${o}h/l${n} pan visible wide diagrams`),i.push(` ${o}space c${n} compose comment ${o}space l${n} list comments`),i.push(` ${o}space u${n} undo last comment ${o}space e${n} edit in $EDITOR`),i.push(` ${o}space s${n} submit review`),i.push(` ${o}space a${n} open the companion pane`),i.push(` ${o}^\u23CE/^F${n} while composing: save the comment and hand it to its own fork`),i.push(` ${o}space x${n} cancel review`),i.push(` ${o}?${n} toggle this help ${o}esc${n} close/cancel`)):i.push(` ${o}space c${n} \xB7 ${o}space l${n} \xB7 ${o}space u${n} \xB7 ${o}space e${n} \xB7 ${o}space a${n} companion \xB7 ${o}space s${n} submit \xB7 ${o}space x${n} cancel \xB7 ${o}?${n} \xB7 ${o}esc${n}`);l?.notice!==void 0&&i.length>0&&(i[i.length-1]=` ${W}${l.notice}${n}`);const D=R.length+i.length,g=Math.max(1,a-D),N=Math.max(0,c.lines.length-g),y=Math.max(0,Math.min(e.scroll,N)),p=l?.lineNumbers===!0?String(c.lines.length).length:0,b=I(t,p),j=T(c,y,g),H=Math.max(0,j-b),O=Math.max(0,Math.min(e.hscroll,H)),{lo:U,hi:z}=se(e),P=re(e),f=[];for(const r of C(c,y,g)){if(r.abs===null){f.push(` ${" ".repeat(p>0?p+1:0)}${r.line}`);continue}const m=ne(r.line,O,b),u=e.rowUnits[r.abs]??null,w=c.spans[r.abs]?.[0],x=p>0?w===void 0?" ".repeat(p+1):`${o}${String(w).padStart(p)}${n} `:"",_=Math.min(b,Math.max(d,k(m)));u!==null&&u>=U&&u<=z?f.push(` ${L}\u258C${n} ${x}${ce(m,_)}`):u!==null&&P.has(u)?f.push(` ${W}\u258E${n} ${x}${m}`):f.push(` ${x}${m}`)}for(;f.length<g;)f.push("");const M=Math.min(t,Math.max(h+2,d+4+(p>0?p+1:0))),Y=f.map(r=>{const m=k(r)>M?t:M;return S([r],t,m)[0]??""}),v=[...S(R,t,M),...Y,...S(i,t,M)];for(;v.length<a;)v.push("");return v.slice(0,a).map(r=>Z(r,t))}$(Me,"renderReviewFrame");function we(e){return V(e)?{doc:"markdown"}:{doc:"code",language:K(e)}}$(we,"docSurface");export{ge as PAN_STEP,I as bodyWidth,F as contentWidthForCols,we as docSurface,ie as maxHScroll,xe as panBy,fe as renderReviewDoc,Me as renderReviewFrame,E as renderWidthForCols,ae as reservedRows,T as widestVisibleRow};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var o=Object.defineProperty;var c=(n,e)=>o(n,"name",{value:e,configurable:!0});import{Key as r,decodeKittyPrintable as a,matchesKey as t,parseKey as u}from"@earendil-works/pi-tui";import{normalizeShiftedMeta as s}from"../../../core/keybindings/index.js";function x(n){switch(n.type){case"moveUnit":case"extendUnit":case"leader":case"help":case"listEdit":case"printable":case"paste":return n.text;case"scrollPage":case"pan":case"cancel":return n.text;default:return}}c(x,"reviewKeyText");function g(n){const e=s(n);if(t(e,r.ctrl("j"))||t(e,r.alt("enter")))return{type:"composeNewline"};if(t(e,r.alt("backspace"))||t(e,r.ctrl("w")))return{type:"composeWordBackspace"};if(t(e,r.backspace))return{type:"composeBackspace"};if(t(e,r.delete))return{type:"composeDelete"};if(t(e,r.alt("left"))||t(e,r.ctrl("left"))||t(e,r.super("left"))||t(e,r.alt("b")))return{type:"composeMove",direction:"wordLeft"};if(t(e,r.alt("right"))||t(e,r.ctrl("right"))||t(e,r.super("right"))||t(e,r.alt("f")))return{type:"composeMove",direction:"wordRight"};if(t(e,r.home)||t(e,r.ctrl("a")))return{type:"composeHome"};if(t(e,r.end)||t(e,r.ctrl("e")))return{type:"composeEnd"};if(t(e,r.shift("tab")))return{type:"tab",reverse:!0};if(t(e,r.tab))return{type:"tab",reverse:!1};if(t(e,r.ctrl("enter"))||t(e,r.ctrl("f")))return{type:"confirmFork"};if(t(e,r.enter))return{type:"confirm"};if(t(e,r.escape))return{type:"cancel"};if(t(e,r.up))return{type:"arrow",direction:"up"};if(t(e,r.down))return{type:"arrow",direction:"down"};if(t(e,r.left))return{type:"arrow",direction:"left"};if(t(e,r.right))return{type:"arrow",direction:"right"};if(t(e,r.pageUp))return{type:"scrollPage",delta:-1};if(t(e,r.pageDown))return{type:"scrollPage",delta:1};if(t(e,r.shift("j")))return{type:"extendUnit",delta:1,text:"J"};if(t(e,r.shift("k")))return{type:"extendUnit",delta:-1,text:"K"};if(t(e,"j"))return{type:"moveUnit",delta:1,text:"j"};if(t(e,"k"))return{type:"moveUnit",delta:-1,text:"k"};if(t(e,"u"))return{type:"scrollPage",delta:-1,text:"u"};if(t(e,"d"))return{type:"scrollPage",delta:1,text:"d"};if(t(e,"h"))return{type:"pan",delta:-1,text:"h"};if(t(e,"l"))return{type:"pan",delta:1,text:"l"};if(t(e,r.space))return{type:"leader",text:" "};if(t(e,r.question))return{type:"help",text:"?"};if(t(e,"e"))return{type:"listEdit",text:"e"};if(t(e,"q"))return{type:"cancel",text:"q"};const p=u(e),i=d(n,p);return i==="?"?{type:"help",text:i}:i!==void 0?{type:"printable",text:i}:p!==void 0?null:[...n].length>1?{type:"paste",text:n}:null}c(g,"matchReviewKey");function d(n,e){const p=a(n);if(p!==void 0&&f(p))return p;if(e!==void 0){const i=e.startsWith("shift+"),l=i?e.slice(6):e;if([...l].length===1&&f(l))return i&&/^[a-z]$/.test(l)?l.toUpperCase():l}return[...n].length===1&&f(n)?n:void 0}c(d,"printableText");function f(n){return!new RegExp("\\p{C}","u").test(n)}c(f,"isPrintable");export{g as matchReviewKey,x as reviewKeyText};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var A=Object.defineProperty;var i=(n,e)=>A(n,"name",{value:e,configurable:!0});import{envNodeId as S}from"../../shared/env.js";import{defineLeaf as v}from"../../core/command.js";import{InputError as o}from"../../core/io.js";import{cliClient as l,rethrowAsCliError as N}from"../api-client.js";import{join as _}from"node:path";import{mkdtempSync as j,rmSync as F,writeFileSync as W}from"node:fs";import{tmpdir as C}from"node:os";import{resolvePageComponents as E}from"../../core/config.js";import{markStopSignal as D}from"../../core/runtime/stop-signals.js";import{preparePage as q}from"../../core/human/page-authoring.js";import{PageAuthoringError as K}from"../../core/human/page.js";import{isResponseBearingSlot as U,validateAuthoredPageManifest as $}from"../../core/human/page-schema.js";import{display as M}from"../../core/termrender/display.js";import{pageHelpText as P,resolveMaxPanes as Q}from"./shared.js";const B=P().pageHint;function k(){return S()??null}i(k,"askingNode");async function G(){const n=k();if(n===null||n==="")return{source:{},lifecycle:null};try{const e=l(),t=await e.getNode(n),a=t.name.trim(),r=t.profile_id===null?void 0:(await e.getProfile(t.profile_id)).name;return{source:{nodeId:n,...a===""?{}:{sessionName:a},...r===void 0?{}:{profileName:r}},lifecycle:t.lifecycle}}catch{return{source:{nodeId:n},lifecycle:null}}}i(G,"sender");function R(){return E()}i(R,"pageProductKinds");function L(n,e,t){const a=t==="terminal"||n.inbox===!0?!0:n.noInbox===!0?!1:e;return{placement:n.placement??"inline",inbox:a,reply:e}}i(L,"deliveryFrom");function g(n){try{return n()}catch(e){throw e instanceof K?new o({error:"invalid_page",message:e.message,field:"page",next:"Fix the authored page and submit again; the reported location is in the authored `.tsx` source."}):e}}i(g,"submitAuthoredPage");async function z(n){try{const e=await l().getHumanRequest(n);if(e.kind!=="page")throw new o({error:"unknown_page",message:`no page ${n} on this canvas`,field:"replace",next:"Pass the page_id a previous send returned, or omit --replace to raise a new page."});return(await l().getHumanInboxPage(e.inbox_ticket_id)).page}catch(e){if(e instanceof o)throw e;N(e,"Pass the page_id a previous send returned, or omit --replace to raise a new page.")}}i(z,"replacedPage");function J(n){const e=j(_(C(),"crtr-human-page-")),t=_(e,"page.tsx");return W(t,n,{encoding:"utf8",mode:384}),{dir:e,path:t}}i(J,"writePipedPage");function O(n){const e=n.page,t=n.document,a=typeof t=="string"&&t.trim()!==""?t:void 0;if(e!==void 0&&a!==void 0)throw new o({error:"bad_invocation",message:"received both --page and a piped page document",field:"page, document",next:"Pass exactly one page source: --page PATH or the document on stdin."});if(e===void 0&&a===void 0)throw new o({error:"missing_parameter",message:"a page source is required",field:"page, document",next:"Pass exactly one page source: --page PATH or the document on stdin."});if(e!==void 0){if(typeof e!="string")throw new o({error:"invalid_type",message:"--page must be a path",field:"page",next:"Retry with --page PATH."});return{sourceFile:e}}if(typeof a!="string")throw new o({error:"invalid_type",message:"stdin must contain a page document",field:"document",next:"Pipe the page document on stdin."});const r=J(a);return{sourceFile:r.path,tempDir:r.dir}}i(O,"pageInput");function V(){return"Queued for the user. Their answer is pushed to your inbox and wakes you when they respond \u2014 never poll, verify it opened, or block."}i(V,"queuedFollowUp");function pe(n=!1){const e=P(n);return v({name:"send",description:"send a durable page with explicit delivery",whenToUse:e.sendWhenToUse,help:{name:"human send",summary:e.sendSummary,guide:"Page authoring: `crtr human -h`.",params:[{kind:"stdin",name:"document",required:!1,allowPositional:!1,constraint:e.stdinConstraint},{kind:"flag",name:"page",type:"path",required:!1,constraint:`${B} ${e.pageFlagConstraint}`},{kind:"flag",name:"placement",type:"enum",choices:["inline","panel"],required:!1,default:"inline",constraint:"Where the page is delivered. inline renders in this conversation's transcript; panel opens from the inbox beside it."},{kind:"flag",name:"inbox",type:"bool",required:!1,constraint:"Project this page into the inbox. Mutually exclusive with --no-inbox."},{kind:"flag",name:"no-inbox",type:"bool",required:!1,constraint:"Do not project this page into the inbox, leaving this conversation's transcript as its only route to the user. Mutually exclusive with --inbox, and refused from a terminal node, whose transcript nobody reads once it finishes."},{kind:"flag",name:"replace",type:"string",required:!1,constraint:"Page id returned by an earlier send. Rewrites source in place while retaining its delivery and transcript anchor. Refused once the page is settled or canceled. Not combinable with delivery flags."}],output:[{name:"page_id",type:"string",required:!0,constraint:"Identifier for the page; pass it as --replace to revise source in place."},{name:"dir",type:"string",required:!0,constraint:e.dirConstraint},{name:"placement",type:"inline | panel",required:!0,constraint:"Resolved page placement."},{name:"inbox",type:"boolean",required:!0,constraint:"Whether the page is projected into the inbox."},{name:"reply",type:"boolean",required:!0,constraint:"Whether completion is delivered to the asking request identity. Not a flag: true exactly when the page has response-bearing components."},{name:"follow_up",type:"string",required:!0,constraint:"What happens next; never instructs the caller to poll."}],outputKind:"object",effects:["Writes one durable page request. Inbox projection follows the delivery flags, except from a terminal node, which always projects; completion delivery follows the page's own components.","A display-only page's inbox entry is a notice, not a task: it clears itself once the person has actually seen the page, wherever they see it.","A reply-bearing page records the asking node on the request and delivers completion directly to that node.","--replace rewrites source in place while retaining delivery and emitted time; open surfaces reload it without creating another page."]},run:i(async(t,a)=>{const{sourceFile:r,tempDir:f}=O(t),c=t.replace,T=["placement","inbox","noInbox"];if(t.inbox===!0&&t.noInbox===!0)throw new o({error:"bad_invocation",message:"received conflicting delivery flags",field:"inbox",next:"Pass at most one of --inbox and --no-inbox."});if(c!==void 0&&T.some(h=>a?.providedParams.has(h)===!0))throw new o({error:"bad_invocation",message:"--replace cannot change delivery",field:"replace",next:"Remove delivery flags: replacement retains the page placement, inbox, reply, and emitted time."});try{if(c!==void 0){const u=await z(c);if((await l().getHumanRequest(c)).state!=="pending")throw new o({error:"page_settled",message:`page ${c} already has a terminal outcome`,field:"replace",next:"The page was answered or canceled; nothing on it can change now. Raise a new page if more is needed."});const m=g(()=>q({sourceFile:r,source:u.source,productKinds:R(),delivery:u.delivery})),I=await l().replaceHumanRequest(c,{page:{dialect:m.manifest.dialect,source:m.document}});return{page_id:c,dir:I.request_dir,...u.delivery,follow_up:"Replaced in place. Every open surface reloads it; delivery and emitted time are unchanged."}}const{source:h,lifecycle:w}=await G();if(w==="terminal"&&t.noInbox===!0)throw new o({error:"invalid_page_delivery",message:"a terminal node cannot send a page --no-inbox",field:"inbox",next:"Drop --no-inbox. This node finishes, and nobody reads a finished node's transcript, so a page kept out of the inbox reaches no one."});const y=R(),d=g(()=>q({sourceFile:r,source:h,productKinds:y})),H=d.manifest.slots.some(U),s=L(t,H,w);if(d.manifest=g(()=>$({...d.manifest,delivery:s},y)),!s.reply){const u=await l().createHumanRequest({page:{dialect:d.manifest.dialect,source:d.document},delivery:s,source:d.manifest.source,requester_node_id:null,creator_cwd:process.cwd()}),x=u.request_dir,m=s.placement==="inline"&&s.inbox?"Shown in this conversation and queued in the user's inbox.":s.placement==="inline"?"Shown in this conversation as passive page content with no inbox entry.":s.inbox?"Queued in the inbox; it opens in the panel and waits until dismissed.":"Published as passive page content with no inbox or response lifecycle.";return{page_id:u.request_id,dir:x,...s,follow_up:m}}const p=k();if(p===null||p==="")throw new o({error:"no_requester",message:"a response-bearing page must be sent from a crouter node",field:"page",next:"Run `crtr human send` from the node that should receive the answer."});const b=await l().createHumanRequest({page:{dialect:d.manifest.dialect,source:d.document},delivery:s,source:d.manifest.source,requester_node_id:p,creator_cwd:process.cwd()});return D(p,"requestedHumanReply"),{page_id:b.request_id,dir:b.request_dir,...s,follow_up:V()}}finally{f!==void 0&&F(f,{recursive:!0,force:!0})}},"run")})}i(pe,"humanSend");const me=v({name:"show",description:"put a file live on the user's screen",whenToUse:"displaying a doc on screen while the user comments",help:{name:"human show",summary:"put a file live on screen in a tmux pane with crouter's renderer",guide:"The pane always watches the file and live-updates on every save \u2014 a displayed doc is a live view by definition, so point it at a file something keeps rewriting (a status board, a running summary) and it stays current. The file is directive-flavored markdown rendered by termrender (panels, columns, trees, callouts, mermaid). To put a rich document in front of the user as a durable inbox page, use `crtr human send --page PATH`; a page with no response-bearing components is a standalone announcement.",params:[{kind:"positional",name:"path",type:"path",required:!0,constraint:"Path to the file to render."},{kind:"flag",name:"window",type:"enum",choices:["auto","split","new"],required:!1,default:"auto",constraint:"Placement. Default auto."}],output:[{name:"pane_id",type:"string | null",required:!0,constraint:"Tmux pane id, or null when not displayed."},{name:"reason",type:"string | null",required:!0,constraint:"Why no pane was created, or null on success."}],outputKind:"object",effects:["Spawns a live-watch tmux pane when possible. No job. Always exits 0."]},run:i(async n=>{const e=n.path,t=n.window,a=t!==void 0?t:"auto";try{const r=M(e,{window:a,maxPanes:Q()});return r.paneId!==void 0?{pane_id:r.paneId,reason:null}:{pane_id:null,reason:r.reason}}catch(r){return{pane_id:null,reason:`display failed: ${r instanceof Error?r.message:String(r)}`}}},"run")});export{pe as humanSend,me as humanShow,G as sender};
|
|
1
|
+
var A=Object.defineProperty;var i=(n,e)=>A(n,"name",{value:e,configurable:!0});import{envNodeId as S}from"../../shared/env.js";import{defineLeaf as v}from"../../core/command.js";import{InputError as o}from"../../core/io.js";import{cliClient as l,rethrowAsCliError as N}from"../api-client.js";import{join as _}from"node:path";import{mkdtempSync as j,rmSync as F,writeFileSync as W}from"node:fs";import{tmpdir as C}from"node:os";import{resolvePageComponents as E}from"../../core/config.js";import{preparePage as q}from"../../core/human/page-authoring.js";import{PageAuthoringError as D}from"../../core/human/page.js";import{isResponseBearingSlot as K,validateAuthoredPageManifest as U}from"../../core/human/page-schema.js";import{display as $}from"../../core/termrender/display.js";import{pageHelpText as P,resolveMaxPanes as M}from"./shared.js";const Q=P().pageHint;function k(){return S()??null}i(k,"askingNode");async function B(){const n=k();if(n===null||n==="")return{source:{},lifecycle:null};try{const e=l(),t=await e.getNode(n),a=t.name.trim(),r=t.profile_id===null?void 0:(await e.getProfile(t.profile_id)).name;return{source:{nodeId:n,...a===""?{}:{sessionName:a},...r===void 0?{}:{profileName:r}},lifecycle:t.lifecycle}}catch{return{source:{nodeId:n},lifecycle:null}}}i(B,"sender");function T(){return E()}i(T,"pageProductKinds");function G(n,e,t){const a=t==="terminal"||n.inbox===!0?!0:n.noInbox===!0?!1:e;return{placement:n.placement??"inline",inbox:a,reply:e}}i(G,"deliveryFrom");function g(n){try{return n()}catch(e){throw e instanceof D?new o({error:"invalid_page",message:e.message,field:"page",next:"Fix the authored page and submit again; the reported location is in the authored `.tsx` source."}):e}}i(g,"submitAuthoredPage");async function L(n){try{const e=await l().getHumanRequest(n);if(e.kind!=="page")throw new o({error:"unknown_page",message:`no page ${n} on this canvas`,field:"replace",next:"Pass the page_id a previous send returned, or omit --replace to raise a new page."});return(await l().getHumanInboxPage(e.inbox_ticket_id)).page}catch(e){if(e instanceof o)throw e;N(e,"Pass the page_id a previous send returned, or omit --replace to raise a new page.")}}i(L,"replacedPage");function z(n){const e=j(_(C(),"crtr-human-page-")),t=_(e,"page.tsx");return W(t,n,{encoding:"utf8",mode:384}),{dir:e,path:t}}i(z,"writePipedPage");function J(n){const e=n.page,t=n.document,a=typeof t=="string"&&t.trim()!==""?t:void 0;if(e!==void 0&&a!==void 0)throw new o({error:"bad_invocation",message:"received both --page and a piped page document",field:"page, document",next:"Pass exactly one page source: --page PATH or the document on stdin."});if(e===void 0&&a===void 0)throw new o({error:"missing_parameter",message:"a page source is required",field:"page, document",next:"Pass exactly one page source: --page PATH or the document on stdin."});if(e!==void 0){if(typeof e!="string")throw new o({error:"invalid_type",message:"--page must be a path",field:"page",next:"Retry with --page PATH."});return{sourceFile:e}}if(typeof a!="string")throw new o({error:"invalid_type",message:"stdin must contain a page document",field:"document",next:"Pipe the page document on stdin."});const r=z(a);return{sourceFile:r.path,tempDir:r.dir}}i(J,"pageInput");function O(){return"Queued for the user. Their answer is pushed to your inbox and wakes you when they respond \u2014 never poll, verify it opened, or block."}i(O,"queuedFollowUp");function le(n=!1){const e=P(n);return v({name:"send",description:"send a durable page with explicit delivery",whenToUse:e.sendWhenToUse,help:{name:"human send",summary:e.sendSummary,guide:"Page authoring: `crtr human -h`.",params:[{kind:"stdin",name:"document",required:!1,allowPositional:!1,constraint:e.stdinConstraint},{kind:"flag",name:"page",type:"path",required:!1,constraint:`${Q} ${e.pageFlagConstraint}`},{kind:"flag",name:"placement",type:"enum",choices:["inline","panel"],required:!1,default:"inline",constraint:"Where the page is delivered. inline renders in this conversation's transcript; panel opens from the inbox beside it."},{kind:"flag",name:"inbox",type:"bool",required:!1,constraint:"Project this page into the inbox. Mutually exclusive with --no-inbox."},{kind:"flag",name:"no-inbox",type:"bool",required:!1,constraint:"Do not project this page into the inbox, leaving this conversation's transcript as its only route to the user. Mutually exclusive with --inbox, and refused from a terminal node, whose transcript nobody reads once it finishes."},{kind:"flag",name:"replace",type:"string",required:!1,constraint:"Page id returned by an earlier send. Rewrites source in place while retaining its delivery and transcript anchor. Refused once the page is settled or canceled. Not combinable with delivery flags."}],output:[{name:"page_id",type:"string",required:!0,constraint:"Identifier for the page; pass it as --replace to revise source in place."},{name:"dir",type:"string",required:!0,constraint:e.dirConstraint},{name:"placement",type:"inline | panel",required:!0,constraint:"Resolved page placement."},{name:"inbox",type:"boolean",required:!0,constraint:"Whether the page is projected into the inbox."},{name:"reply",type:"boolean",required:!0,constraint:"Whether completion is delivered to the asking request identity. Not a flag: true exactly when the page has response-bearing components."},{name:"follow_up",type:"string",required:!0,constraint:"What happens next; never instructs the caller to poll."}],outputKind:"object",effects:["Writes one durable page request. Inbox projection follows the delivery flags, except from a terminal node, which always projects; completion delivery follows the page's own components.","A display-only page's inbox entry is a notice, not a task: it clears itself once the person has actually seen the page, wherever they see it.","A reply-bearing page records the asking node on the request and delivers completion directly to that node.","--replace rewrites source in place while retaining delivery and emitted time; open surfaces reload it without creating another page."]},run:i(async(t,a)=>{const{sourceFile:r,tempDir:m}=J(t),c=t.replace,R=["placement","inbox","noInbox"];if(t.inbox===!0&&t.noInbox===!0)throw new o({error:"bad_invocation",message:"received conflicting delivery flags",field:"inbox",next:"Pass at most one of --inbox and --no-inbox."});if(c!==void 0&&R.some(f=>a?.providedParams.has(f)===!0))throw new o({error:"bad_invocation",message:"--replace cannot change delivery",field:"replace",next:"Remove delivery flags: replacement retains the page placement, inbox, reply, and emitted time."});try{if(c!==void 0){const u=await L(c);if((await l().getHumanRequest(c)).state!=="pending")throw new o({error:"page_settled",message:`page ${c} already has a terminal outcome`,field:"replace",next:"The page was answered or canceled; nothing on it can change now. Raise a new page if more is needed."});const p=g(()=>q({sourceFile:r,source:u.source,productKinds:T(),delivery:u.delivery})),I=await l().replaceHumanRequest(c,{page:{dialect:p.manifest.dialect,source:p.document}});return{page_id:c,dir:I.request_dir,...u.delivery,follow_up:"Replaced in place. Every open surface reloads it; delivery and emitted time are unchanged."}}const{source:f,lifecycle:w}=await B();if(w==="terminal"&&t.noInbox===!0)throw new o({error:"invalid_page_delivery",message:"a terminal node cannot send a page --no-inbox",field:"inbox",next:"Drop --no-inbox. This node finishes, and nobody reads a finished node's transcript, so a page kept out of the inbox reaches no one."});const y=T(),d=g(()=>q({sourceFile:r,source:f,productKinds:y})),H=d.manifest.slots.some(K),s=G(t,H,w);if(d.manifest=g(()=>U({...d.manifest,delivery:s},y)),!s.reply){const u=await l().createHumanRequest({page:{dialect:d.manifest.dialect,source:d.document},delivery:s,source:d.manifest.source,requester_node_id:null,creator_cwd:process.cwd()}),x=u.request_dir,p=s.placement==="inline"&&s.inbox?"Shown in this conversation and queued in the user's inbox.":s.placement==="inline"?"Shown in this conversation as passive page content with no inbox entry.":s.inbox?"Queued in the inbox; it opens in the panel and waits until dismissed.":"Published as passive page content with no inbox or response lifecycle.";return{page_id:u.request_id,dir:x,...s,follow_up:p}}const h=k();if(h===null||h==="")throw new o({error:"no_requester",message:"a response-bearing page must be sent from a crouter node",field:"page",next:"Run `crtr human send` from the node that should receive the answer."});const b=await l().createHumanRequest({page:{dialect:d.manifest.dialect,source:d.document},delivery:s,source:d.manifest.source,requester_node_id:h,creator_cwd:process.cwd()});return{page_id:b.request_id,dir:b.request_dir,...s,follow_up:O()}}finally{m!==void 0&&F(m,{recursive:!0,force:!0})}},"run")})}i(le,"humanSend");const ue=v({name:"show",description:"put a file live on the user's screen",whenToUse:"displaying a doc on screen while the user comments",help:{name:"human show",summary:"put a file live on screen in a tmux pane with crouter's renderer",guide:"The pane always watches the file and live-updates on every save \u2014 a displayed doc is a live view by definition, so point it at a file something keeps rewriting (a status board, a running summary) and it stays current. The file is directive-flavored markdown rendered by termrender (panels, columns, trees, callouts, mermaid). To put a rich document in front of the user as a durable inbox page, use `crtr human send --page PATH`; a page with no response-bearing components is a standalone announcement.",params:[{kind:"positional",name:"path",type:"path",required:!0,constraint:"Path to the file to render."},{kind:"flag",name:"window",type:"enum",choices:["auto","split","new"],required:!1,default:"auto",constraint:"Placement. Default auto."}],output:[{name:"pane_id",type:"string | null",required:!0,constraint:"Tmux pane id, or null when not displayed."},{name:"reason",type:"string | null",required:!0,constraint:"Why no pane was created, or null on success."}],outputKind:"object",effects:["Spawns a live-watch tmux pane when possible. No job. Always exits 0."]},run:i(async n=>{const e=n.path,t=n.window,a=t!==void 0?t:"auto";try{const r=$(e,{window:a,maxPanes:M()});return r.paneId!==void 0?{pane_id:r.paneId,reason:null}:{pane_id:null,reason:r.reason}}catch(r){return{pane_id:null,reason:`display failed: ${r instanceof Error?r.message:String(r)}`}}},"run")});export{le as humanSend,ue as humanShow,B as sender};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var Se=Object.defineProperty;var c=(a,
|
|
2
|
-
`);return}let y,
|
|
3
|
-
`)},"logAsyncFailure"),re=c(r=>{try{
|
|
1
|
+
var Se=Object.defineProperty;var c=(a,l)=>Se(a,"name",{value:l,configurable:!0});import{envNodeId as Y}from"../../../shared/env.js";import{execFileSync as S}from"node:child_process";import{resolve as xe}from"node:path";import{dashboardRowsAllFromSource as Oe,enrichRowsFromSource as D,loadPreviewFromSource as G,loadTranscriptFromSource as Ie,renderForestFromSource as Ce}from"../render-source.js";import{fullName as Te}from"../labels.js";import{setupTerminal as Re,restoreTerminal as Be,getTerminalSize as Ne,parseKeypress as Pe}from"../../tui/terminal.js";import{buildTree as qe,flatten as Me,pruneNode as ke,TABS as x}from"./model.js";import{loadPins as Fe,savePins as Ae}from"./pins.js";import{matchesTerminalInput as Q,resolveUserKeybindings as _e}from"../../keybindings/index.js";const Ke=["crtr.browse.quit","crtr.browse.down","crtr.browse.up","crtr.browse.first","crtr.browse.last","crtr.browse.expand-or-child","crtr.browse.collapse-or-parent","crtr.browse.toggle-fold","crtr.browse.tab-next","crtr.browse.tab-previous","crtr.browse.tab.1","crtr.browse.tab.2","crtr.browse.tab.3","crtr.browse.tab.4","crtr.browse.tab.5","crtr.browse.close-subtree","crtr.browse.sort","crtr.browse.scope","crtr.browse.profile","crtr.browse.residents","crtr.browse.preview","crtr.browse.report","crtr.browse.pin","crtr.browse.search","crtr.browse.revive-now","crtr.browse.focus","crtr.browse.focus-background","crtr.browse.yank-id"],Ee=["crtr.browse.search.cancel","crtr.browse.search.commit","crtr.browse.search.delete","crtr.browse.search.quit"];function J(a,l,h){return l.find(y=>Q(a,y,h))??null}c(J,"firstMatching");function He(a,l){return J(a,Ke,l)}c(He,"resolveBrowseNavAction");function We(a,l){return J(a,Ee,l)}c(We,"resolveBrowseSearchAction");const _=["attention","tree","relevance","recency"];import{renderFrame as $e,detectColorCaps as ze,headerHeight as Le,previewLayout as X,PREVIEW_HEIGHT as je}from"./render.js";import{writeClipboardTextEverywhere as Ue}from"../../clipboard-text.js";function Ve(a,l,h){const y=Math.max(8,a.rows),v=X(a.cols,h).mode==="bottom"?je:0;return Math.max(1,y-Le(l)-1-v)}c(Ve,"viewportHeight");async function ir(a){const l=a.source,h=_e();if(!process.stdin.isTTY){process.stdout.write(await Ce(l)+`
|
|
2
|
+
`);return}let y,v,N,K,u,E,P={};await c(async()=>{let r=new Set;if(a.viewedNodeIds!==void 0)try{r=await a.viewedNodeIds()}catch{}v=await l.listNodes(),y=(await Oe(l,r,!1,v)).filter(n=>n.kind!=="human"),N=v.filter(n=>n.parent===null&&n.kind!=="human").map(n=>n.node_id);const s=new Map;await Promise.all(v.map(async n=>{s.set(n.node_id,(await l.subscriptionsOf(n.node_id).catch(()=>[])).map(o=>o.node_id))})),K=s,u=qe(y,N,n=>K.get(n)??[]),E=u.nodes.size,P=await Promise.all(N.map(async n=>[n,...await l.view(n)])).then(n=>l.ticketCountsForNodes([...new Set(n.flat())])).catch(()=>({}))},"rebuildSnapshot")();const Z=a.cwd!==void 0&&a.cwd.trim()!==""?xe(a.cwd):null,q=a.profileId,e={tab:"Live",cursor:0,collapsed:new Set([...u.nodes.entries()].filter(([,r])=>r.childIds.length>0).map(([r])=>r)),query:"",search:!1,scrollOffset:0,cwdScope:null,profileScope:q,sort:"attention",preview:!0,showReport:!1,residentsOnly:!0,pendingClose:null,flash:null,pinned:Fe(),help:!1,rename:!1,renameBuf:"",renameTarget:null,message:!1,messageBuf:"",messageTarget:null};let w=[];const R=c(r=>u.nodes.get(r)?.row,"rowOf"),ee=ze();let O=!1;const I=c(()=>{if(!O){O=!0;try{Be()}catch{}}},"cleanup");process.once("exit",I);const H=c((r,s)=>{process.stderr.write(`[crtr browse] ${r}: ${String(s?.message??s)}
|
|
3
|
+
`)},"logAsyncFailure"),re=c(r=>{try{S("crtr",["node","lifecycle","revive",r,"--now"],{stdio:"ignore"})}catch{}},"reviveNow"),te=c(r=>{I();const s=a.returnPane!==void 0&&a.returnPane!==""?a.returnPane:void 0;try{s!==void 0?S("tmux",["run-shell","-b",`crtr surface node focus ${r} --pane ${s} --in-place >/dev/null 2>&1`],{stdio:"ignore"}):S("crtr",["surface","node","focus",r],{stdio:"inherit"})}catch{}process.exit(0)},"selectAndFocus"),se=c(r=>{const s=["surface","node","focus",r,...a.returnPane!==void 0&&a.returnPane!==""?["--pane",a.returnPane]:[]];try{S("crtr",s,{stdio:"ignore"})}catch{}},"selectAndFocusKeepOpen"),f=c(r=>{if(w=Me(u,{collapsed:e.collapsed,tab:e.tab,query:e.query,cwdScope:e.cwdScope,profileScope:e.profileScope,residentsOnly:e.residentsOnly,sort:e.sort,pinned:e.pinned}),r!==void 0){const s=w.findIndex(n=>n.id===r);s>=0&&(e.cursor=s)}e.cursor>w.length-1&&(e.cursor=Math.max(0,w.length-1)),e.cursor<0&&(e.cursor=0)},"recompute"),W=c(async()=>{const r=Ne(),s=e.preview&&w.length>0,n=e.search||e.rename||e.message,o=Ve(r,n,s);e.cursor<e.scrollOffset&&(e.scrollOffset=e.cursor),e.cursor>=e.scrollOffset+o&&(e.scrollOffset=e.cursor-o+1),e.scrollOffset<0&&(e.scrollOffset=0);const t=e.scrollOffset,d=Math.min(w.length,t+o),p=[];for(let g=t;g<d;g++){const V=R(w[g].id);V!==void 0&&p.push(V)}const b=m()?.id,A=c(()=>m()?.id!==b,"stale");if(await D(l,p,P),A())return;if(b!==void 0){const g=R(b);if(g!==void 0&&(await G(l,g),A()||(X(r.cols,s).mode==="side"&&await Ie(l,g),A())))return}const ve=$e({tree:u,visible:w,tab:e.tab,cursor:e.cursor,scrollOffset:e.scrollOffset,query:e.query,search:e.search,totalNodes:E,cwdScope:e.cwdScope,profileScope:e.profileScope,sort:e.sort,preview:e.preview,showReport:e.showReport,residentsOnly:e.residentsOnly,pendingClose:e.pendingClose,flash:e.flash,pinned:e.pinned,help:e.help,rename:e.rename,renameBuf:e.renameBuf,message:e.message,messageBuf:e.messageBuf,readOnly:!1},r,ee);process.stdout.write(ve)},"flush"),C=c(()=>{I(),process.exit(0)},"quit"),m=c(()=>w[e.cursor],"curRow"),M=c(r=>!e.collapsed.has(r),"isExpanded"),ne=c(r=>{const s=[],n=[r],o=new Set;for(;n.length>0;){const t=n.pop();if(!o.has(t)){o.add(t),s.push(t);for(const d of u.nodes.get(t)?.childIds??[])n.push(d)}}return s},"subtreeIds"),oe=c(r=>ne(r).some(s=>u.nodes.get(s)?.row.streaming===!0),"anyStreaming"),$=c(async r=>{e.pendingClose=null;let s=[];try{s=(await a.closeNode(r)).closed}catch{return}for(const n of s){const o=await l.getNode(n);if(o===null){ke(u,n);continue}const t=u.nodes.get(n);t!==void 0&&(t.row.status=o.status,t.row.streaming=!1,t.row.viewed=!1,t.row.hanging=null,t.row.asks=0)}f()},"doClose"),z=c(r=>{const s=x.indexOf(e.tab);e.tab=x[(s+r+x.length)%x.length],e.cursor=0,e.scrollOffset=0,f()},"cycleTab"),ie=c(()=>{const r=m()?.id,s=_.indexOf(e.sort);e.sort=_[(s+1)%_.length],f(r)},"cycleSort"),ce=c(()=>{const r=m()?.id;e.cwdScope=e.cwdScope===null?Z:null,f(r)},"toggleScope"),ae=c(()=>{if(q===void 0)return;const r=m()?.id;e.profileScope=e.profileScope===void 0?q:void 0,f(r)},"toggleProfile"),le=c(()=>{const r=m()?.id;e.residentsOnly=!e.residentsOnly,f(r)},"toggleResidents");let k=!1,F=!1,B=!1;const i=c(()=>{B=!0,!F&&(F=!0,(async()=>{try{for(;B&&!O;)B=!1,await W()}finally{F=!1,B&&!O&&i()}})().catch(()=>{I(),process.exit(1)}))},"scheduleFlush"),L=c(()=>{k||(k=!0,setImmediate(()=>{k=!1,f(),i()}))},"scheduleSearchRepaint"),de=c((r,s)=>{const n=We(h,{input:r,...s});if(n==="crtr.browse.search.cancel"){e.search=!1,e.query="",e.sort="tree",f(),i();return}if(n==="crtr.browse.search.commit"){e.search=!1,f();const t=w.findIndex(d=>d.matched);t>=0&&(e.cursor=t),i();return}if(n==="crtr.browse.search.delete"){e.query=e.query.slice(0,-1),L();return}if(n==="crtr.browse.search.quit"&&C(),s.ctrl)return;const o=[...r].filter(t=>t>=" ").join("");o.length>0&&(e.query+=o,L())},"onKeySearch"),fe=c(()=>{const r=Y();if(!(r===void 0||r===""||!u.nodes.has(r))){for(let s=u.nodes.get(r)?.parentId??null;s!==null;s=u.nodes.get(s)?.parentId??null)e.collapsed.delete(s);f(r)}},"recenterOnSelf"),ue=c(r=>{e.pinned.has(r)?e.pinned.delete(r):e.pinned.add(r),Ae(e.pinned),f(r)},"togglePin"),we=c(()=>{const r=e.renameTarget,s=e.renameBuf.trim();if(e.rename=!1,r!==null&&s!==""){try{S("crtr",["node","config",r,"--name",s],{stdio:"ignore"})}catch{}const n=u.nodes.get(r);n!==void 0&&(n.row.handle=s,n.row.name=Te({name:s,kind:n.row.kind,description:n.row.description}))}f(e.renameTarget??void 0),i()},"commitRename"),pe=c(()=>{const r=e.messageTarget,s=e.messageBuf.trim();if(e.message=!1,r!==null&&s!=="")try{S("crtr",["node","message","send","--to",r,s],{stdio:"ignore"})}catch{}i()},"commitMessage"),j=c((r,s,n,o,t,d)=>{if(s.escape){d();return}if(s.return){t();return}if(s.backspace){o(n().slice(0,-1)),i();return}if(s.ctrl){r==="c"&&C();return}const p=[...r].filter(b=>b>=" ").join("");p.length>0&&(o(n()+p),i())},"onKeyText"),me=c((r,s)=>j(r,s,()=>e.renameBuf,n=>{e.renameBuf=n},we,()=>{e.rename=!1,i()}),"onKeyRename"),he=c((r,s)=>j(r,s,()=>e.messageBuf,n=>{e.messageBuf=n},pe,()=>{e.message=!1,i()}),"onKeyMessage"),be=c((r,s)=>{if(s.ctrl&&r==="c"){C();return}e.help=!1,i()},"onKeyHelp"),ge=c((r,s)=>{const n={input:r,...s},o=He(h,n);if(e.flash=null,s.ctrl&&o===null)return;if(e.pendingClose!==null&&o==="crtr.browse.quit"&&s.ctrl&&C(),e.pendingClose!==null){if(Q(h,"crtr.browse.confirm-close",n)){const d=e.pendingClose;$(d).then(()=>i()).catch(()=>i());return}e.pendingClose=null,i();return}const t=m();if(o==="crtr.browse.quit"&&C(),o==="crtr.browse.up"){e.cursor=Math.max(0,e.cursor-1),i();return}if(o==="crtr.browse.down"){e.cursor=Math.max(0,Math.min(w.length-1,e.cursor+1)),i();return}if(o==="crtr.browse.first"){e.cursor=0,i();return}if(o==="crtr.browse.last"){e.cursor=Math.max(0,w.length-1),i();return}if(o==="crtr.browse.expand-or-child"){t!==void 0&&t.hasChildren&&(M(t.id)?e.cursor+1<w.length&&w[e.cursor+1].depth>t.depth&&(e.cursor+=1):(e.collapsed.delete(t.id),f(t.id))),i();return}if(o==="crtr.browse.collapse-or-parent"){if(t!==void 0&&t.hasChildren&&M(t.id))e.collapsed.add(t.id),f(t.id);else if(t!==void 0){const d=u.nodes.get(t.id)?.parentId??null;if(d!==null){const p=w.findIndex(b=>b.id===d);p>=0&&(e.cursor=p)}}i();return}if(o==="crtr.browse.toggle-fold"){t!==void 0&&t.hasChildren&&(M(t.id)?e.collapsed.add(t.id):e.collapsed.delete(t.id),f(t.id)),i();return}if(o==="crtr.browse.tab-next"){z(1),i();return}if(o==="crtr.browse.tab-previous"){z(-1),i();return}if(o?.startsWith("crtr.browse.tab.")){const d=Number(o.slice(-1))-1;d<x.length&&(e.tab=x[d],e.cursor=0,e.scrollOffset=0,f()),i();return}if(o==="crtr.browse.close-subtree"){if(t===void 0){i();return}if(oe(t.id)){e.pendingClose=t.id,i();return}$(t.id).then(()=>i()).catch(()=>i());return}if(o==="crtr.browse.sort"){ie(),i();return}if(o==="crtr.browse.scope"){ce(),i();return}if(o==="crtr.browse.profile"){ae(),i();return}if(o==="crtr.browse.residents"){le(),i();return}if(o==="crtr.browse.preview"){e.preview=!e.preview,i();return}if(o==="crtr.browse.report"){e.showReport=!e.showReport,i();return}if(r==="?"){e.help=!0,i();return}if(o==="crtr.browse.pin"){t!==void 0&&ue(t.id),i();return}if(r==="."){fe(),i();return}if(r==="R"){t!==void 0&&(e.rename=!0,e.renameTarget=t.id,e.renameBuf=R(t.id)?.name??""),i();return}if(r==="m"){t!==void 0&&(e.message=!0,e.messageTarget=t.id,e.messageBuf=""),i();return}if(o==="crtr.browse.search"){ye(),e.search=!0,e.query="",e.sort="relevance",e.cursor=0,e.scrollOffset=0,f(),i();return}if(o==="crtr.browse.revive-now"){t!==void 0&&R(t.id)?.hanging!=null&&re(t.id),i();return}if(o==="crtr.browse.yank-id"){if(t!==void 0){const{system:d,tmux:p}=Ue(t.id);e.flash=d||p?`Copied ${t.id}${d?"":" to the tmux buffer"}`:"No clipboard tool available \u2014 nothing copied"}i();return}if(o==="crtr.browse.focus"){t!==void 0&&te(t.id);return}if(o==="crtr.browse.focus-background"){t!==void 0&&se(t.id),i();return}},"onKeyNav");f(),w.length===0&&e.residentsOnly&&(e.residentsOnly=!1,f());const T=Y();if(T!==void 0&&T!==""&&u.nodes.has(T)){for(let r=u.nodes.get(T)?.parentId??null;r!==null;r=u.nodes.get(r)?.parentId??null)e.collapsed.delete(r);f(T)}Re(),await W();let U=!1;const ye=c(()=>{if(U)return;U=!0;const r=[...u.nodes.values()].map(t=>t.row);let s=0;const n=30,o=c(async()=>{if(O)return;const t=Math.min(s+n,r.length),d=r.slice(s,t);await D(l,d,P),await Promise.all(d.map(p=>G(l,p))),s=t,e.search&&e.query!==""&&(f(m()?.id),i()),s<r.length&&setImmediate(()=>{o().catch(p=>H("background warm failed",p))})},"warmChunk");setImmediate(()=>{o().catch(t=>H("background warm failed",t))})},"startWarm");await new Promise(()=>{const r=c(s=>{try{const{input:n,key:o}=Pe(s);e.help?be(n,o):e.search?de(n,o):e.rename?me(n,o):e.message?he(n,o):ge(n,o)}catch{I(),process.exit(1)}},"onData");process.stdin.on("data",r),process.stdout.on("resize",i)})}c(ir,"runBrowse");export{He as resolveBrowseNavAction,We as resolveBrowseSearchAction,ir as runBrowse};
|
|
@@ -88,9 +88,6 @@ export declare function recordRespawnAttempt(nodeId: string, attempt: {
|
|
|
88
88
|
failures: number;
|
|
89
89
|
notBefore: string | null;
|
|
90
90
|
}): void;
|
|
91
|
-
/** Every hydrated node whose durable profile identity equals `profileId`.
|
|
92
|
-
* Unlike `listNodes`, this includes unclaimed warm-pool spares: profile
|
|
93
|
-
* deletion owns every matching row, whether or not it is user-visible. */
|
|
94
91
|
export declare function listNodesByProfile(profileId: string): NodeMeta[];
|
|
95
92
|
/** All rows, optionally filtered by status and terminal execution traces. Unclaimed warm spares are excluded. */
|
|
96
93
|
/** Every node's durable memory-resolution coordinates, including unclaimed warm-pool spares. */
|
|
@@ -100,6 +97,9 @@ export declare function listNodes(filter?: {
|
|
|
100
97
|
withRecordedPid?: boolean;
|
|
101
98
|
withRecordedPidOrFrozen?: boolean;
|
|
102
99
|
}): NodeRow[];
|
|
100
|
+
/** The daemon's complete supervision set. Live rows participate regardless of
|
|
101
|
+
* PID; terminal rows participate only while they retain a PID or freeze mark. */
|
|
102
|
+
export declare function listNodesForSupervision(): NodeRow[];
|
|
103
103
|
/** Identity-only projection of every user-visible row: the broker's report
|
|
104
104
|
* resolver needs only "does this sender exist, and what is it called", and a
|
|
105
105
|
* three-column read stays cheap against a canvas of thousands of rows where a
|