@north-light/cli 0.3.512 → 0.3.513
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/command-manifest/object-kinds.js +1 -1
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/canvas.d.ts +12 -0
- package/dist/api/dto/custom-objects.d.ts +1 -0
- package/dist/api/dto/objects.d.ts +1 -0
- package/dist/builtin-memory/crouter-sdk/release-notes.md +5 -0
- package/dist/clients/attach/chrome/canvas-panels.d.ts +5 -0
- package/dist/clients/attach/chrome/canvas-panels.js +1 -1
- package/dist/clients/attach/chrome/object-wait.d.ts +4 -0
- package/dist/clients/attach/chrome/object-wait.js +1 -0
- package/dist/clients/attach/chrome/roster.d.ts +3 -0
- package/dist/clients/attach/chrome/roster.js +4 -4
- package/dist/clients/attach/session/editor-inventory.js +2 -2
- package/dist/clients/attach/session/readonly-popup.d.ts +15 -0
- package/dist/clients/attach/session/readonly-popup.js +1 -0
- package/dist/clients/attach/viewer.js +603 -603
- package/dist/commands/custom-object/register.js +1 -1
- package/dist/core/canvas/canvas.d.ts +0 -13
- package/dist/core/canvas/canvas.js +16 -18
- package/dist/core/canvas/migrations.js +40 -22
- package/dist/core/canvas/remote-canvas-source.js +1 -1
- package/dist/core/canvas/render-source.d.ts +1 -1
- package/dist/core/canvas/types.d.ts +0 -4
- package/dist/core/canvas/waits.d.ts +23 -2
- package/dist/core/canvas/waits.js +9 -4
- package/dist/core/graph/custom.d.ts +1 -0
- package/dist/core/graph/custom.js +2 -2
- package/dist/core/graph/events.js +6 -6
- package/dist/core/graph/kinds/custom.d.ts +1 -0
- package/dist/core/graph/kinds/custom.js +1 -1
- package/dist/core/graph/kinds/kind.d.ts +3 -0
- package/dist/core/graph/object-waits.d.ts +11 -0
- package/dist/core/graph/object-waits.js +1 -0
- package/dist/core/runtime/lifecycle.js +2 -2
- package/dist/core/runtime/stop-guard.js +3 -3
- package/dist/daemon/api/handlers/canvas.js +5 -5
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.js +3 -3
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/reconcilers/live-obligation.js +1 -1
- package/dist/types.d.ts +1 -0
- package/docs/sdk/release-notes.md +5 -0
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var p=Object.defineProperty;var f=(t,n)=>p(t,"name",{value:n,configurable:!0});const m=/^[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*$/,E=/^[a-z][a-z0-9-]*$/,b=["report","notice","node","job","document","person","app","repo","profile","action"],h=64,N=1,k=10,l=new Set(["description","events","read"]),y=new Set(["level","supersedes","ends_wait"]);function d(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}f(d,"isRecord");function _(t,n){if(!d(t))return[`${n} events must be an object`];const o=[],c=Object.entries(t);c.length>64&&o.push(`${n} declares more than 64 events`);for(const[i,s]of c){const e=`${n} event ${JSON.stringify(i)}`;if(E.test(i)||o.push(`${e} is not a valid event name`),!d(s)){o.push(`${e} must be an object { level, supersedes?, ends_wait? }`);continue}for(const a of Object.keys(s))y.has(a)||o.push(`${e} has unknown key ${JSON.stringify(a)}`);const r=s.level;(typeof r!="number"||!Number.isInteger(r)||r<1||r>10)&&o.push(`${e} level must be an integer 1-10`),s.supersedes!==void 0&&typeof s.supersedes!="boolean"&&o.push(`${e} supersedes must be a boolean`),s.ends_wait!==void 0&&typeof s.ends_wait!="boolean"&&o.push(`${e} ends_wait must be a boolean`)}return o}f(_,"eventCatalogReasons");function j(t){const n=[],o=t.object_kinds;if(o!==void 0)if(!d(o))n.push("object_kinds must be an object keyed by kind name");else for(const[i,s]of Object.entries(o)){const e=`object_kinds ${JSON.stringify(i)}`;if(m.test(i)?b.includes(i.split(".")[0])&&n.push(`${e} uses a reserved first segment`):n.push(`${e} is not a valid kind name (<plugin>.<name>, lowercase)`),!d(s)){n.push(`${e} must be an object { description, events, read? }`);continue}for(const a of Object.keys(s))l.has(a)||n.push(`${e} has unknown key ${JSON.stringify(a)}`);(typeof s.description!="string"||s.description.trim()==="")&&n.push(`${e} description must be non-empty text`),n.push(..._(s.events,e));const r=s.read;if(r!==void 0){const a=d(r)?r.command:void 0;!d(r)||Object.keys(r).some(u=>u!=="command")?n.push(`${e} read must be { command: [leaf path] }`):(!Array.isArray(a)||a.length===0||a.some(u=>typeof u!="string"||u===""))&&n.push(`${e} read.command must be a non-empty array of command names`)}}const c=t.scopes;return c!==void 0&&(!Array.isArray(c)||c.some(i=>typeof i!="string"))&&n.push("scopes must be an array of scope strings"),n}f(j,"objectBlocksShapeReasons");function g(t,n,o,c,i){const s=n.read?.command;if(s===void 0)return[];const e=s.join(" ");return c.has(e)?i.has(e)?[`object_kinds ${JSON.stringify(t)} read.command "${e}" streams; a read is one {markdown} answer`]:[]:[`object_kinds ${JSON.stringify(t)} read.command "${e}" is not a leaf of plugin "${o}"`]}f(g,"objectKindReadReasons");export{m as KIND,E as LOCAL,k as MAX_EVENT_LEVEL,h as MAX_KIND_EVENTS,N as MIN_EVENT_LEVEL,b as RESERVED_KIND_ROOTS,_ as eventCatalogReasons,j as objectBlocksShapeReasons,g as objectKindReadReasons};
|
package/dist/api/contract.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** The contract level this build serves and requires. Written by `scripts/contract.mjs release`; never edit by hand. */
|
|
2
|
-
export declare const CONTRACT_LEVEL = "1.
|
|
2
|
+
export declare const CONTRACT_LEVEL = "1.23";
|
|
3
3
|
/** Request header naming the one contract level the caller needs, e.g. `1.3`. Optional: absent means no check. */
|
|
4
4
|
export declare const REQUIRED_CONTRACT_HEADER = "Crouter-Required-Contract";
|
|
5
5
|
/** Response header listing the contract levels the server serves, comma-separated, one per major, e.g. `1.3`. */
|
package/dist/api/contract.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var c=Object.defineProperty;var e=(r,t)=>c(r,"name",{value:t,configurable:!0});const f="1.
|
|
1
|
+
var c=Object.defineProperty;var e=(r,t)=>c(r,"name",{value:t,configurable:!0});const f="1.23",i="Crouter-Required-Contract",p="Crouter-Contract";function l(r){const t=/^(\d+)\.(\d+)$/.exec(r.trim());return t===null?null:{major:Number(t[1]),minor:Number(t[2])}}e(l,"parseContractLevel");function a(r){return r==null?[]:r.split(",").map(t=>l(t)).filter(t=>t!==null)}e(a,"parseServedContracts");function s(r,t){const n=l(r);return n===null?!1:(typeof t=="string"||t===null||t===void 0?a(t):t).some(u=>u.major===n.major&&u.minor>=n.minor)}e(s,"contractSatisfies");function C(r,t,n={}){if(r===void 0)return null;if(l(r)===null)return{status:400,code:"invalid_request",param:i,message:`${i} must be a contract level like 1.0.`};if(s(r,t))return null;const o=r.trim();return{status:426,code:"runtime_version_unsupported",message:t===null||a(t).length===0?`The runtime did not name its contract level; the caller requires contract ${o} or later. Roll the runtime forward.`:`The runtime serves contract ${t}; the caller requires contract ${o} or later within the same major. Roll the runtime forward, or pin an SDK whose crouterContract the runtime serves.`,details:{sdk_version:(n.legacyMinimum??"").trim(),runtime_version:n.runtimeVersion??null,required_contract:o,runtime_contract:t}}}e(C,"contractRefusal");export{p as CONTRACT_HEADER,f as CONTRACT_LEVEL,i as REQUIRED_CONTRACT_HEADER,C as contractRefusal,s as contractSatisfies,l as parseContractLevel,a as parseServedContracts};
|
package/dist/api/dto/canvas.d.ts
CHANGED
|
@@ -276,6 +276,18 @@ export interface RosterDTO {
|
|
|
276
276
|
generated_at: IsoTime;
|
|
277
277
|
nodes: RosterNodeDTO[];
|
|
278
278
|
edges: RosterEdgeDTO[];
|
|
279
|
+
/** Every live wait a node holds on a watched canvas object (a workflow run until it completes), oldest
|
|
280
|
+
* first per node. The attach viewer lists this node's below the editor beside its child and cron rows. */
|
|
281
|
+
object_waits?: RosterObjectWaitDTO[];
|
|
282
|
+
}
|
|
283
|
+
/** One node's live wait on a watched object: the object's kind (`github.run`) and name identify it to a
|
|
284
|
+
* person; `crtr canvas read <object_id>` reads it. */
|
|
285
|
+
export interface RosterObjectWaitDTO {
|
|
286
|
+
node_id: NodeIdDTO;
|
|
287
|
+
object_id: string;
|
|
288
|
+
object_type: string;
|
|
289
|
+
object_name: string;
|
|
290
|
+
created: IsoTime;
|
|
279
291
|
}
|
|
280
292
|
/** Browse's initial frame needs the dashboard fields and topology, not the full
|
|
281
293
|
* node detail/list projection. Transported as gzip JSON (application/gzip) over
|
|
@@ -16,6 +16,11 @@ The runtime serves `GET /v1/ready` on its owner API and its app listener. Additi
|
|
|
16
16
|
- `GET /v1/ready` answers 200 `{ready: true}` once the runtime can admit ordinary work, otherwise 503 `{ready: false, reason, message}` (`startup_pending`, `jwks_pending`, `grant_snapshot_missing`). It needs no credential. `GET /v1/health` and `GET /healthz` answer as before.
|
|
17
17
|
- On a joined runtime that has not yet committed its first grant snapshot from the directory, creating a terminal node answers 503 `runtime_starting` (retry) instead of 403 `scope_missing`. After the first snapshot a missing terminal grant is still 403.
|
|
18
18
|
|
|
19
|
+
A node that watches a canvas object whose kind declares an event with `ends_wait: true` (a workflow run's `completed`) holds a wait on that object until the event lands, the node stops watching, or the node ends. Additive: no request or response an existing app sends or reads changes.
|
|
20
|
+
|
|
21
|
+
- `ObjectKindEvent.ends_wait` (optional) in a plugin's `objectKinds`; the bundle validator accepts the key.
|
|
22
|
+
- `RosterDTO.object_waits` (optional) lists every live object wait with the object's id, kind and name.
|
|
23
|
+
|
|
19
24
|
## 0.3.510
|
|
20
25
|
|
|
21
26
|
`providers.call` takes an optional `machine`. Additive: no request or response an existing app sends or reads changes.
|
|
@@ -21,6 +21,11 @@ export type CanvasPanelItem = {
|
|
|
21
21
|
key: 'crons';
|
|
22
22
|
kind: 'crons';
|
|
23
23
|
line: string;
|
|
24
|
+
} | {
|
|
25
|
+
key: string;
|
|
26
|
+
kind: 'object-wait';
|
|
27
|
+
objectId: string;
|
|
28
|
+
line: string;
|
|
24
29
|
};
|
|
25
30
|
export interface CanvasPanelLines {
|
|
26
31
|
/** Below-editor relationship and wait rows, in render order. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var Y=Object.defineProperty;var i=(s,a)=>Y(s,"name",{value:a,configurable:!0});import{navLabel as H,nodeGlyph as Z,truncate as nn,tokensCell as tn,cycleBadge as en,askBadge as on,activityCell as sn,fillWidth as M,RESET as m,DIM as an,GREEN as cn}from"../../../core/canvas/nav-render.js";const rn=34,dn=30,un=40;import{RemoteCanvasSource as ln}from"../../../core/canvas/remote-canvas-source.js";import{cronWaitSummary as fn}from"./cron-wait.js";import{bashJobsWaitSummary as mn}from"./bash-jobs.js";import{reviewWaitSummary as hn}from"./review-wait.js";import{objectWaitSummary as wn}from"./object-wait.js";const $n=12,pn=6,P=22;function D(s,a){return s.length>a?`${s.slice(0,a-1)}\u2026`:s+" ".repeat(a-s.length)}i(D,"nameCell");function gn(s,a){return s.length>=a?s.slice(0,a):" ".repeat(a-s.length)+s}i(gn,"padStartVisible");async function Rn(s,a,c,f,T=[],O=[],F=[]){const R=f instanceof ln,h=await f.panelRoster?.(),$=h===void 0?null:new Map(h.nodes.map(n=>[n.node_id,n])),y=new Map,_=new Map;if(h!==void 0)for(const n of h.edges){const t=y.get(n.from_id)??[];t.push(n.to_id),y.set(n.from_id,t),_.has(n.to_id)||_.set(n.to_id,n.from_id)}const W=new Map,C=new Map,S=new Map,p=i(n=>{const t=W.get(n);if(t!==void 0)return t;const e=$===null?f.getNode(n).catch(()=>null):Promise.resolve($.get(n)??null);return W.set(n,e),e},"node"),G=i(n=>f.getNode(n).catch(()=>null),"detail"),v=i(n=>{const t=C.get(n);if(t!==void 0)return t;const e=(async()=>{const o=$===null?(await f.subscriptionsOf(n).catch(()=>[])).map(r=>r.node_id):y.get(n)??[],l=[];for(const r of o)(await p(r))?.kind!=="human"&&l.push(r);return l})();return C.set(n,e),e},"convoChildIds"),E=i(n=>{const t=S.get(n);if(t!==void 0)return t;const e=$===null?f.subscribersOf(n).then(o=>o[0]?.node_id).catch(()=>{}):Promise.resolve(_.get(n));return S.set(n,e),e},"managerOf"),J=i(async n=>{const t=[];for(const e of await v(n)){const o=(await p(e))?.status;(o==="active"||o==="idle")&&t.push(e)}return t},"liveReports"),K=i(async n=>{let t=n;const e=new Set([t]);for(;;){const o=await E(t);if(o===void 0||e.has(o))break;e.add(o),t=o}return t},"climbRoot"),I=new Map,L=i(async n=>{const t=new Set,e=i(async o=>{const l=(await p(o))?.status==="active";if(t.has(o))return l?1:0;t.add(o);let r=0;for(const k of await v(o))r+=await e(k);return I.set(o,r),r+(l?1:0)},"visit");await e(n)},"computeActivity"),V=i(async n=>{if(n===null||n.mode!=="orchestrator")return"";const t=(await v(n.node_id)).length;return t>0?` ${an}\u2933${t}${m}`:""},"childBadgeFor"),q=i(n=>{if(n===null||n.status==="active")return"";const t=I.get(n.node_id)??0;return t>0?` ${cn}\u21E3${t}${m}`:""},"liveBelowBadgeFor"),w=c?.muted??(n=>n),z=c?.faint??(n=>n);await L(await K(s));const d=await E(s),b=await J(s),g=[...d!==void 0?[d]:[],...b],B=await Promise.all(g.map(async n=>await G(n)??await p(n))),Q=g.length>0?Math.min(P,Math.max(...g.map((n,t)=>H(B[t]??null,n).length))):P,N=i(async(n,t)=>{const e=B[g.indexOf(n)]??null,o=D(H(e,n),Q),l=z(D(e?.kind??"",$n)),r=w(gn(tn(e,R),pn)),k=`${en(e)}${await V(e)}${q(e)}${on(n,a)}${sn(e,R)}`,X=` ${t} ${Z(e)} ${o} ${l} ${r}${k}`;return nn(X)},"row"),U=[...d!==void 0?[d]:[],...b],u=[];d!==void 0&&u.push({key:`node:${d}`,kind:"node",nodeId:d,line:await N(d,"\u2191")});for(const n of b)u.push({key:`node:${n}`,kind:"node",nodeId:n,line:await N(n,"\u2193")});for(const n of F){const t=c?c.info("\u270E"):"\u270E",e=hn(n,Math.max(8,M()-un));u.push({key:`review:${n.review_id}`,kind:"review",companionNodeId:n.companion_node_id,line:` ${t} ${w(`${e} \xB7 \u21B5 companion`)}${m}`})}const j=O.length===1?" \xB7 x stop":"",x=mn(O,Date.now(),M()-(rn+j.length));if(x!==void 0){const n=c?c.info("\u2699"):"\u2699";u.push({key:"bash",kind:"bash",line:` ${n} ${w(`${x} \xB7 \u21B5 details${j}`)}${m}`})}const A=fn(T);if(A!==void 0){const n=c?c.info("\u25F7"):"\u25F7";u.push({key:"crons",kind:"crons",line:` ${n} ${w(`${A} \xB7 \u21B5 details`)}${m}`})}for(const n of h?.object_waits??[]){if(n.node_id!==s)continue;const t=c?c.info("\u25C7"):"\u25C7",e=wn(n,Date.now(),Math.max(8,M()-dn));u.push({key:`object:${n.object_id}`,kind:"object-wait",objectId:n.object_id,line:` ${t} ${w(`${e} \xB7 \u21B5 details`)}${m}`})}return{reports:u.map(n=>n.line),reportIds:U,items:u}}i(Rn,"buildCanvasPanelLines");export{Rn as buildCanvasPanelLines};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { RosterObjectWaitDTO } from '../../../api/dto/canvas.js';
|
|
2
|
+
/** Compact cockpit row for one object wait: the kind first (matching the other
|
|
3
|
+
* wait rows' state-first shape), how long the node has waited, then the object. */
|
|
4
|
+
export declare function objectWaitSummary(wait: RosterObjectWaitDTO, nowMs?: number, nameCap?: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var a=Object.defineProperty;var n=(t,e)=>a(t,"name",{value:e,configurable:!0});import{formatBashElapsed as l}from"../../../core/bash-jobs.js";function c(t,e){return t.length<=e?t:`\u2026${t.slice(t.length-Math.max(1,e-1))}`}n(c,"nameCell");function s(t){const e=t.lastIndexOf(".");return e===-1?t:t.slice(e+1)}n(s,"kindCell");function f(t,e=Date.now(),o=28){const r=l(e-Date.parse(t.created));return`${s(t.object_type)} \xB7 ${r} \xB7 ${c(t.object_name,Math.max(8,o))}`}n(f,"objectWaitSummary");export{f as objectWaitSummary};
|
|
@@ -19,6 +19,9 @@ export interface RosterHooks {
|
|
|
19
19
|
* the cron wait row routes to `schedule` and the bash row to `jobs`; the
|
|
20
20
|
* native Inspector owns details for both. */
|
|
21
21
|
openInspector: (section: 'overview' | 'schedule' | 'jobs') => void;
|
|
22
|
+
/** Open a watched canvas object's `crtr canvas read` in a popup — the
|
|
23
|
+
* object-wait row's detail surface (a workflow run, a pull request). */
|
|
24
|
+
openObject: (objectId: string) => void;
|
|
22
25
|
/** Recompute the editor's hollow-cursor state (session/pane-focus.ts). */
|
|
23
26
|
syncCursor: () => void;
|
|
24
27
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var q=Object.defineProperty;var s=(y,n)=>q(y,"name",{value:n,configurable:!0});import{execFile as _}from"node:child_process";import{Text as
|
|
2
|
-
`)[0]??"").replace(/\s+/g," ").trim();return d.length>t?`${d.slice(0,t-1)}\u2026`:d},"commandHead"),B=s(()=>{if(
|
|
3
|
-
`)[0]}`),n.requestChromeRefresh()}))},"confirmKill");S.onCursorDownAtBottom=a?void 0:()=>{r!==void 0||c.length===0||(r=c[0].key,m())};const P=s(()=>{const e=c.find(o=>o.key===r);if(e===void 0||a)return;if(e.kind==="crons"){
|
|
4
|
-
`)[0]}`));return}if(e.kind==="bash"){if(w(
|
|
1
|
+
var q=Object.defineProperty;var s=(y,n)=>q(y,"name",{value:n,configurable:!0});import{execFile as _}from"node:child_process";import{Text as O,decodeKittyPrintable as k,matchesKey as R}from"@earendil-works/pi-tui";import{cliClient as C}from"../../../commands/api-client.js";import{focusNode as H}from"../../../core/runtime/focus-viewer.js";import{daemonErrorMessage as U}from"../../inbox/resolve.js";import{activeBackgroundBashJobs as w}from"../../../core/bash-jobs.js";import{contextDir as j}from"../../../core/canvas/node-agent-paths.js";import{fillBar as D,fillWidth as J,stripSgr as X,REVERSE as F}from"../../../core/canvas/nav-render.js";import{buildCanvasPanelLines as L}from"./canvas-panels.js";const V=15e3;function oe(y,n){const{editor:S,tui:x,pal:E,nodeId:l,remote:a,role:N,canvasSource:K}=y,I=y.containers.reports;let c=[],r,g=process.env.CRTR_ATTACH_ROSTER;g!==void 0&&delete process.env.CRTR_ATTACH_ROSTER;let f,v;const m=s(()=>{n.syncCursor(),I.clear();for(const e of c){const t=e.key===r;I.addChild(new O(t?D(X(e.line),J(),F):e.line,1,0))}x.requestRender()},"paint"),$=s(async()=>{const e=a?[]:(await C().listCrons()).filter(i=>i.created_by===l),t=a?[]:w(j(l)),d=a?[]:(await C().listReviews({state:"open",origin_node_id:l})).reviews;if(c=(await L(l,n.asks(),E,K,e,t,d)).items,g!==void 0){const i=g;g=void 0;const p=c.find(h=>h.kind==="node"&&h.nodeId===i);p!==void 0&&(r=p.key)}r!==void 0&&!c.some(i=>i.key===r)&&(r=void 0),f!==void 0&&!t.some(i=>i.jobId===f?.jobId)&&b(!0),m()},"refresh"),b=s(e=>{v!==void 0&&(clearTimeout(v),v=void 0),f!==void 0&&(f=void 0,e&&n.setNotice(""))},"disarmKill"),u=s(()=>{b(!0),r!==void 0&&(r=void 0,m())},"exit"),T=s(e=>k(e)??(e.length===1?e:void 0),"typed"),A=s((e,t=40)=>{const d=(e.split(`
|
|
2
|
+
`)[0]??"").replace(/\s+/g," ").trim();return d.length>t?`${d.slice(0,t-1)}\u2026`:d},"commandHead"),B=s(()=>{if(N!=="controller"){n.setNotice("Read-only observer attach \u2014 cannot stop background jobs");return}const e=w(j(l));if(e.length===0){n.setNotice("Background job already finished"),n.requestChromeRefresh();return}if(e.length>1){n.setNotice(`${e.length} background jobs \u2014 press \u21B5 to pick one in the Inspector`);return}const t=e[0];f={jobId:t.jobId,label:A(t.command)},n.setNotice(`Stop \u201C${f.label}\u201D? Press y to confirm.`,{sticky:!0}),v=setTimeout(()=>b(!0),V)},"armKill"),M=s(()=>{const e=f;e!==void 0&&(b(!1),n.setNotice(`Stopping \u201C${e.label}\u201D\u2026`),_("crtr",["node","bash","kill",e.jobId,"--node",l],t=>{n.setNotice(t===null?`Stopped \u201C${e.label}\u201D.`:`Could not stop the job: ${t.message.split(`
|
|
3
|
+
`)[0]}`),n.requestChromeRefresh()}))},"confirmKill");S.onCursorDownAtBottom=a?void 0:()=>{r!==void 0||c.length===0||(r=c[0].key,m())};const P=s(()=>{const e=c.find(o=>o.key===r);if(e===void 0||a)return;if(e.kind==="crons"){u(),n.openInspector("schedule");return}if(e.kind==="review"){if(N!=="controller"){n.setNotice("Read-only observer attach \u2014 cannot open the review companion");return}u();const o=process.env.TMUX_PANE;if(o===void 0||o===""){n.setNotice("Could not open the companion: no tmux pane");return}(async()=>{const i=C(),p=await i.getNode(e.companionNodeId);(await H(i,p,{pane:o})).focused||n.setNotice("Could not open the companion")})().catch(i=>n.setNotice(`Could not open the companion: ${U(i).split(`
|
|
4
|
+
`)[0]}`));return}if(e.kind==="bash"){if(w(j(l)).length===0){n.setNotice("Background job already finished"),n.requestChromeRefresh();return}u(),n.openInspector("jobs");return}if(e.kind==="object-wait"){u(),n.openObject(e.objectId);return}const t=e.nodeId;if(t===l){u();return}if(N!=="controller"){n.setNotice("Read-only observer attach \u2014 cannot focus nodes");return}const d=process.env.TMUX_PANE;if(d===void 0||d===""){n.setNotice("cannot swap \u2014 no tmux pane");return}_("tmux",["run-shell","-b",`crtr surface node focus ${t} --pane ${d} --in-place >/dev/null 2>&1`],()=>{})},"openSelected");return{refresh:$,handleKey:s(e=>{if(a)return!1;const t=R(e,"down"),d=R(e,"up");if(r===void 0)return!1;const o=c.findIndex(p=>p.key===r),i=c[o];if(f!==void 0){if(T(e)==="y")return M(),!0;b(!0)}return i?.kind==="bash"&&T(e)==="x"?(B(),!0):d?(o<=0?u():(r=c[o-1].key,m()),!0):t?(o>=0&&o<c.length-1&&(r=c[o+1].key,m()),!0):R(e,"enter")?(P(),!0):R(e,"escape")?(u(),!0):(u(),!1)},"handleKey"),active:s(()=>r!==void 0,"active"),exit:u}}s(oe,"createRoster");export{oe as createRoster};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var R=Object.defineProperty;var n=(m,
|
|
1
|
+
var R=Object.defineProperty;var n=(m,i)=>R(m,"name",{value:i,configurable:!0});import{CombinedAutocompleteProvider as A}from"@earendil-works/pi-tui";import{formatBinding as P}from"../../../core/keybindings/index.js";import{inTmux as h}from"../../../core/runtime/placement-tmux.js";import{RefAwareAutocompleteProvider as b}from"../input/ref-autocomplete.js";import{CANVAS_SLASH_COMMANDS as w,locallyConsumedCommandNames as L,slashCommandList as _}from"../slash/dispatch.js";import{loadedCommandPreview as x}from"../slash/prompt-preview.js";import{openReadonlyPopup as I}from"./readonly-popup.js";function M(m,i,t,d,s=(p,r,a)=>new A([...p],r,a)){return s([..._(t,d)],m,i)}n(M,"buildAttachAutocompleteProvider");function q(m,i){let t=0;return{reset:n(()=>{const d=++t;m([],[]),i({type:"list_memory_refs"}).then(s=>{d===t&&s.kind==="list_memory_refs"&&m(s.refs,s.engineLeadingCommandNames)}).catch(()=>{})},"reset")}}n(q,"createMemoryRefRefreshCoordinator");function z(m,i,t){const{meta:d,socket:s,tui:p,editor:r}=m;let a=[],o,f,l=[],u=[];const y=n(()=>{const e=t.bindings();return e.gestures("crtr.attach.command.inspect").length>0?`${P(e,"crtr.attach.command.inspect")} inspect`:"inspect binding disabled"},"commandInspectHint"),C=n(e=>{o=x(e,a),r.loadedCommand=o===void 0?void 0:{name:o.name,content:o.content,inspectHint:y()}},"syncCommandPreview"),v=n(()=>{const e=M(d.cwd,t.fdPath,f,i);r.setAutocompleteProvider(new b(l,e,t.frecency)),r.setResolvedRefNames(l.map(c=>c.name)),r.setLocalCommandNames(L()),r.setEngineCommandNames(u),C(r.getText())},"syncEditorInventories"),N=n(e=>{f=e,a=[...w.map(c=>({...c,source:"builtin"})),...e??[]],v()},"setCommands"),g=q(n((e,c)=>{l=e,u=c,v(),p.requestRender()},"setMemoryRefs"),e=>s.request(e));return{setCommands:N,resetMemoryRefs:n(()=>g.reset(),"resetMemoryRefs"),syncCommandPreview:C,inspectLoadedCommand:n(()=>{if(o===void 0){t.setNotice("No prompt-template command is loaded in the editor");return}if(!h()){t.setNotice("Command inspection requires tmux");return}I({name:o.name,content:`# /${o.name}
|
|
2
2
|
|
|
3
3
|
Invocation: \`${o.invocation.replaceAll("`","\\`")}\`
|
|
4
4
|
|
|
5
5
|
${o.content}
|
|
6
|
-
`,"
|
|
6
|
+
`,noNvim:"nvim is required to inspect loaded commands. Install Neovim and retry."})},"inspectLoadedCommand")}}n(z,"createEditorInventory");export{M as buildAttachAutocompleteProvider,z as createEditorInventory,q as createMemoryRefRefreshCoordinator};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ReadonlyPopup {
|
|
2
|
+
/** The file name inside the temp dir; non-portable characters are replaced. */
|
|
3
|
+
name: string;
|
|
4
|
+
/** Page content written before the popup opens. Omit it when `produce` writes the file. */
|
|
5
|
+
content?: string;
|
|
6
|
+
/** A shell fragment run inside the popup that writes the page to `$PAGE` (e.g. `crtr canvas read x > "$PAGE"`). */
|
|
7
|
+
produce?: (page: string) => string;
|
|
8
|
+
/** Popup title; omitted leaves tmux's default. */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** What the person sees when nvim is not installed. */
|
|
11
|
+
noNvim: string;
|
|
12
|
+
onClose?: () => void;
|
|
13
|
+
}
|
|
14
|
+
/** Open the page in a read-only nvim popup (90% × 85%). Requires tmux — callers gate on `inTmux()` first. */
|
|
15
|
+
export declare function openReadonlyPopup(spec: ReadonlyPopup): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var f=Object.defineProperty;var n=(e,o)=>f(e,"name",{value:o,configurable:!0});import{execFile as l}from"node:child_process";import{mkdtempSync as u,rmSync as c,writeFileSync as p}from"node:fs";import{tmpdir as a}from"node:os";import{join as i}from"node:path";import{nvimShellCommand as s}from"../../../core/nvim-launch.js";import{shellQuote as r}from"../../../core/runtime/placement-tmux.js";import{surfaceTmuxStyleArgs as y}from"../../../core/runtime/surface-bg.js";function E(e){const o=u(i(a(),"crtr-page-")),t=i(o,`${e.name.replace(/[^A-Za-z0-9_.-]/g,"-")}.md`);e.content!==void 0&&p(t,e.content,"utf8");const m=`${e.produce===void 0?"":`${e.produce(r(t))}; `}if command -v nvim >/dev/null 2>&1; then exec ${s("readonly",[t])}; else cat ${r(t)}; printf '%s\\n' ${r(e.noNvim)}; printf 'Press Enter to close.'; read _; fi`,d=e.title===void 0?[]:["-T",` ${e.title} `];l("tmux",["display-popup","-E",...d,"-w","90%","-h","85%",...y(),m],()=>{c(o,{recursive:!0,force:!0}),e.onClose?.()})}n(E,"openReadonlyPopup");export{E as openReadonlyPopup};
|