@north-light/crouter 0.3.343 → 0.3.345
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/builtin-memory/internal/plugins.md +4 -0
- package/dist/clients/attach/viewer.js +129 -129
- package/dist/commands/memory/read.js +3 -3
- package/dist/commands/sys/context/expose.d.ts +0 -1
- package/dist/commands/sys/context/expose.js +1 -2
- package/dist/commands/sys/context.js +1 -1
- package/dist/commands/sys/setup-core.js +6 -6
- package/dist/core/substrate/cli-context-delivery.d.ts +22 -0
- package/dist/core/substrate/cli-context-delivery.js +1 -0
- package/dist/core/substrate/on-read.d.ts +2 -0
- package/dist/core/substrate/on-read.js +4 -4
- package/dist/daemon/reconcilers/broker-supervision.js +4 -4
- package/package.json +1 -1
- package/runtime.lock.json +8 -8
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var
|
|
2
|
-
${
|
|
1
|
+
var D=Object.defineProperty;var a=(t,i)=>D(t,"name",{value:i,configurable:!0});import{envNodeId as E}from"../../shared/env.js";import{diag as v}from"../../core/io.js";import{defineLeaf as S}from"../../core/command.js";import{memoryExtensionEffectiveCatalog as N,projectEffectiveMemoryExtensions as M}from"../../core/memory/extensions.js";import{ambientMemoryTarget as P,createMemoryDocSnapshot as C,memoryStoresInPrecedence as I,readMemoryDocContent as L,resolveMemoryDocs as B}from"../../core/memory-resolver.js";import{candidateLocation as F,readDoc as T}from"../../core/memory/service.js";import{expandShellBlocks as K,hasShellBlocks as U,makeNodeShellRunner as O}from"../../core/runtime/shell-expansion.js";import{registerDocumentExposure as Y,registerExposure as X}from"../../core/substrate/injected-store.js";import{renderCliContextDelivery as x}from"../../core/substrate/cli-context-delivery.js";import{dirDedupKey as $,renderDirListing as W}from"../../core/substrate/listings.js";import{contentReadAttachments as z}from"../../core/substrate/on-read.js";import{renderResult as G}from"../../core/render.js";import{effectiveDocKind as H}from"../../core/substrate/schema.js";import{MEMORY_KINDS as J,resolveReadSelector as Q,selectorParam as q}from"./shared.js";import{candidateLocation as fe}from"../../core/memory/service.js";const V=S({name:"read",description:"load a memory document body by name",whenToUse:"a task in front of you matches a stored document and you already know its canonical name \u2014 read it before improvising. Resolution is exact and takes the full canonical name (a project document is `<namespace>/<local name>`); among documents sharing one name the winner is the nearest scope (node > project stack > profile > user > builtin). A directory name is a valid target too: it answers with that directory\u2019s own document, when it has one, together with its immediate listing, and walking directories is the sanctioned browse move. You name the document by its crtr identifier, never a file path \u2014 do not cat or find the markdown off disk. Reach for `crtr memory find` first when you do not yet know which document applies.",help:{name:"memory read",summary:"resolve an exact canonical name to its document body (frontmatter stripped unless --frontmatter), plus the directory listing when that name has members",params:[{kind:"positional",name:"name",required:!0,constraint:"Full canonical memory name \u2014 a project document is `<namespace>/<local name>`, every other store\u2019s local names are already canonical, where a nested store's namespace includes its path under the repository root. Resolution is exact: a file path, a bare leaf, a `<scope>/<name>` spelling, and a trailing `/INDEX` all fail. A name that carries members returns its listing alongside its body; a name that is only a directory returns the listing alone."},{kind:"flag",name:"kind",type:"enum",choices:[...J],required:!1,constraint:"Narrows resolution when the name is ambiguous across kinds."},{kind:"flag",name:"frontmatter",type:"bool",required:!1,constraint:"When present, includes the YAML frontmatter in the returned body. Off by default \u2014 only the body is returned."},q("scope-read"),q("dir",{},"Reads that store alone: the name resolves against its documents only, and the listing shows its members only.")],output:[{name:"name",type:"string",required:!0,constraint:"Resolved canonical document name, or the directory name on a directory read."},{name:"local_name",type:"string",required:!1,constraint:"Store-local identity, before the store namespace composed the canonical name. Absent on a directory read."},{name:"kind",type:"string",required:!1,constraint:"Resolved kind: knowledge or preference. Absent on a directory read."},{name:"scope",type:"string",required:!1,constraint:"Scope the document was resolved from: node, project, profile, user, or builtin. Absent on a directory read."},{name:"path",type:"string",required:!1,constraint:"Absolute path to the document on disk. Revise it with `crtr memory edit`, never by editing this file \u2014 an edit records why the change happened and lands in the doc\u2019s revision history. Absent on a directory read."},{name:"store_root",type:"string",required:!1,constraint:"Absolute memory store root the document loaded from. Absent on a directory read."},{name:"physical_relative_path",type:"string",required:!1,constraint:"Store-relative physical markdown path, ordering prefixes and any `INDEX.md` kept. Absent on a directory read."},{name:"representation",type:"string",required:!1,constraint:"Physical representation of this identity: leaf-file or directory-index. Absent on a directory read."},{name:"candidates",type:"object[]",required:!1,constraint:"Present only when several physical documents share this canonical name: one row per candidate in source order, {winner, scope, store_root, physical_relative_path, path}. The winner is what this read returned; reach a non-winning one with `--dir <its project>`."},{name:"content",type:"string",required:!1,constraint:"Document body. Frontmatter stripped unless --frontmatter is set. A document may embed shell as `!`cmd`` or a ```! fenced block; each runs once per read, in the current working directory, and is replaced by its output. Read `path` off disk when you need the literal unexecuted text. May be preceded by one `<auto-loaded-context>` block carrying the doc\u2019s neighborhood listings and any docs routed to this read. Absent on a directory read."},{name:"listing",type:"string[]",required:!1,constraint:"Present when the name has members \u2014 a directory document returns its body AND this listing, a bare directory returns the listing alone: one `[[name]]: <when-and-why>` line per member doc, one bare `[[name]]` per subdirectory. Follow any line with `crtr memory read <name>`."},{name:"extensions",type:"object",required:!1,constraint:"Effective valid plugin-owned metadata, keyed by plugin namespace then field. Includes enabled declaration defaults without writing them to frontmatter; disabled and unresolved namespaces are omitted. Present only on a document read."},{name:"links",type:"string[]",required:!1,constraint:"Canonical names this document links to via `[[name]]` that resolve in the current corpus \u2014 further reading, loaded only on demand with `crtr memory read <name>`. A directory link returns that directory\u2019s listing. Omitted when the body carries no resolvable links."},{name:"follow_up",type:"string",required:!1,constraint:"Present whenever the read returned a listing or resolvable body links."}],outputKind:"object",effects:["Reads the document. A document that embeds shell (`!`cmd`` or a ```! block) runs those commands once, in the current working directory.","Records a content delivery for this node: a document whose profile project caps automatic boot and workspace-open disclosure below content is still returned whole here, and unsolicited channels stay quiet about it afterwards."]},run:a(async t=>{const i=t.name,c=t.kind,A=t.frontmatter,s=Q({scope:t.scope,dir:t.dir}),l=P();s.store===null&&I(l,s.scope,!0,!0);const n=T({target:l,scope:s.scope,store:s.store,name:i,kind:c,frontmatter:A}),f=E()||void 0;if(n.kind==="directory"){const o=await x({nodeId:f,allowUnavailableSubject:!0,render:a((u,r)=>{const p=W(n.listingByName,n.name,r,!1);return X(r,$(n.name),"preview"),{name:n.name,listing:p,follow_up:"Each line is readable with `crtr memory read <name>` \u2014 a `[[name]]: <line>` entry is a doc, a bare `[[name]]` is a subdirectory whose read browses deeper. Browse the whole inventory with `crtr memory list`."}},"render")});return o.diagnostic!==void 0&&v(o.diagnostic),o.result}const{doc:e,candidates:w,content:m,links:d,listingByName:R}=n,_=H(e),b=U(m)?await K(m,O({cwd:process.cwd()})):m,h=await x({nodeId:f,allowUnavailableSubject:!0,render:a((o,u)=>{Y(u,e.path,e.body,"content");const r=z(e,{subject:o,target:u,byName:R,memoryTarget:l,listings:"blocks",explicit:!0}),p=r.blocks.length===0?b:`<auto-loaded-context>
|
|
2
|
+
${r.blocks.join(`
|
|
3
3
|
`)}
|
|
4
4
|
</auto-loaded-context>
|
|
5
5
|
|
|
6
|
-
${
|
|
6
|
+
${b}`,y=r.listing,g=y!==void 0&&y.length>0,k=g?d.length>0?"Each `[[name]]` line in `listing` is one of this directory\u2019s immediate members, and the `[[name]]` links in the body are further reading \u2014 follow either with `crtr memory read <name>` only when the task needs that depth.":"Each `[[name]]` line in `listing` is one of this directory\u2019s immediate members, readable with `crtr memory read <name>` \u2014 follow one only when the task needs that depth.":d.length>0?"The `[[name]]` links in the body are further reading \u2014 follow one with `crtr memory read <name>` only when the task needs that depth.":null;return{name:e.name,local_name:e.localName,kind:_,scope:e.scope,path:e.path,store_root:e.root,physical_relative_path:e.physicalRelativePath,representation:e.representation,...w.length>1?{candidates:w.map(j=>F(j,e))}:{},content:p,...g?{listing:y}:{},extensions:M(e.frontmatter?.extensions,N(e)),...d.length>0?{links:d}:{},...k===null?{}:{follow_up:k}}},"render")});return h.diagnostic!==void 0&&v(h.diagnostic),h.result},"run"),render:a(t=>{const{extensions:i,...c}=t;return G(c,V.help)},"render")});export{fe as candidateRow,C as createMemoryDocSnapshot,V as readLeaf,L as readMemoryDocContent,B as resolveMemoryDocs};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
var
|
|
2
|
-
`);return v(e,t),s===""?{}:{content:s}},"run"),render:a(n=>n.content??"","render")});export{O as exposeLeaf};
|
|
1
|
+
var d=Object.defineProperty;var a=(n,e)=>d(n,"name",{value:e,configurable:!0});import{accessSync as l,realpathSync as c,statSync as u,constants as m}from"node:fs";import{resolve as p}from"node:path";import{defineLeaf as f}from"../../../core/command.js";import{diag as h}from"../../../core/io.js";import{expandTilde as y}from"../../../core/fs-utils.js";import{renderAutoLoadedContext as g,renderOnReadDocBlocksForSubject as b}from"../../../core/substrate/on-read.js";import{renderCliContextDelivery as x}from"../../../core/substrate/cli-context-delivery.js";import{envNodeId as w}from"../../../shared/env.js";function R(n){const e=[],r=new Set;for(const o of n)try{const t=c(p(y(o)));if(l(t,m.R_OK),!u(t).isFile()||r.has(t))continue;r.add(t),e.push(t)}catch{}return e}a(R,"readableRegularFiles");const F=f({name:"expose",description:"attach read-routed memory to file content a local command displays",whenToUse:"a local command has successfully rendered file contents and must place the matching Read-routed memory in that same output",help:{name:"sys context expose",summary:"return read-routed memory for files displayed by a command",params:[{kind:"flag",name:"file",type:"path",required:!0,repeatable:!0,constraint:"Files whose contents the caller displays. Relative paths resolve against this process\u2019s cwd; leading ~ expands as for Read. Symlinks resolve to their target. Missing, unreadable, and non-file paths contribute nothing."}],output:[{name:"content",type:"string",required:!1,constraint:"One <auto-loaded-context> block. Absent when nothing new matches or CRTR_NODE_ID is unset. Prose output is the block alone, without a field label or acknowledgement."}],outputKind:"object",effects:["Records the returned memory documents at their matched rungs in this node\u2019s transcript exposure ledger. Inherits node identity from CRTR_NODE_ID; does not start the daemon. The caller must include the returned block in the same output as the displayed files; this is not a preview operation."]},run:a(async n=>{const e=w()?.trim();if(e===void 0||e==="")return{};const r=R(n.file);if(r.length===0)return{};const o=await x({nodeId:e,render:a((t,s)=>{if(t===null)throw new Error("context subject unexpectedly unavailable");return g(r.flatMap(i=>b(t,i,s)))},"render")});return o.diagnostic!==void 0&&h(o.diagnostic),o.result===""?{}:{content:o.result}},"run"),render:a(n=>n.content??"","render")});export{F as exposeLeaf};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineBranch as e}from"../../core/command.js";import{resolveLeaf as o}from"./context/resolve.js";import{docLeaf as a}from"./context/doc.js";import{sysSyspromptLeaf as
|
|
1
|
+
import{defineBranch as e}from"../../core/command.js";import{resolveLeaf as o}from"./context/resolve.js";import{docLeaf as a}from"./context/doc.js";import{sysSyspromptLeaf as r}from"./context/sysprompt.js";import{promptReviewLeaf as t}from"./context/prompt-review.js";import{adminLeaf as n}from"./context/admin.js";import{exposeLeaf as s}from"./context/expose.js";const l=e({name:"context",description:"inspect and shape what a node\u2019s memory context surface delivers",whenToUse:"you are asking what a node loads, why a document does or does not reach it, or you want to change the surfaces and caps that decide it",help:{name:"sys context",summary:"inspect and shape the memory context a node\u2019s configuration delivers",model:"A document reaches a node when one of its authored surface entries fires for an event (boot, workspace-open, read, memory-read, command, pre-command), its gates pass, and it wins its canonical name against nearer stores; the profile relationship caps the rung at boot and workspace-open only. resolve simulates that delivery from a snapshot and event; expose delivers Read-routed memory for files a local command displays. doc answers in reverse \u2014 one document across every event. sysprompt and prompt-review read assembled prompts (a live node\u2019s captured one, and a hypothetical configuration\u2019s). admin is the interactive surface over all of it."},children:[o,s,a,r,t,n]});export{l as contextBranch};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var q=Object.defineProperty;var a=(e,t)=>q(e,"name",{value:t,configurable:!0});import{spawn as W,spawnSync as H}from"node:child_process";import{homedir as g}from"node:os";import{basename as V,dirname as J,join as S,resolve as X}from"node:path";import{isDeepStrictEqual as k}from"node:util";import{BINDING_CATALOG as Q,normalizeGesture as Z,splitGestureExpression as ee,inboxShortcut as te,resolveKeybindings as w}from"../../core/keybindings/index.js";import{builtinPiPackageDir as b}from"../../core/scope.js";import{readJsonIfExists as ne,readJsonOrNull as re}from"../../core/fs-utils.js";import{resolveBundledPiCliPath as ie}from"../../core/runtime/pi-cli.js";import{crtrVersion as se}from"../../shared/crtr-version.js";import{installTmuxBindings as ae}from"../../core/runtime/tmux-chrome.js";import{normalizeTmuxPassthrough as oe}from"../../core/config.js";import{detectNerdFont as ce,nerdFontInstallCommand as ue,createCurlPercentReader as le,NERD_FONT_MANUAL_LINUX_COMMAND as de,NERD_FONT_SELECT_HINT as pe}from"../../core/runtime/nerd-font.js";import{startProgressBar as he}from"../../core/runtime/progress-bar.js";import{ensureRenderer as fe,isRendererReady as A}from"../../core/termrender/termrender.js";import{installFromMarketplace as me}from"../pkg/plugin-manage.js";import{addMarketplace as $}from"../pkg/market-manage.js";import{findPluginByName as ge,findMarketplaceByName as E}from"../../core/resolver.js";import{expandTilde as ke}from"../../core/fs-utils.js";const R="crouter-official-marketplace",D="https://github.com/crouton-labs/crouter-official-marketplace.git",O="main";function T(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}a(T,"isKeybindingsObject");function h(e){return T(e)?Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Array.isArray(n)?[...n]:n])):{}}a(h,"cloneKeybindings");class Je{static{a(this,"SetupKeybindingsDraft")}expected;baseline;current;baselineInvalidRoot;invalidRoot;resolutionCache;expectedPassthrough;baselinePassthrough;currentPassthrough;constructor(t,n=void 0){this.expected=t,this.baseline=h(t),this.current=h(t),this.baselineInvalidRoot=t!==void 0&&!T(t)?t:void 0,this.invalidRoot=this.baselineInvalidRoot,this.expectedPassthrough=n,this.baselinePassthrough=oe(n),this.currentPassthrough=[...this.baselinePassthrough]}get dirty(){return!k(this.current,this.baseline)||!k(this.invalidRoot,this.baselineInvalidRoot)||!k(this.currentPassthrough,this.baselinePassthrough)}overrides(){return h(this.current)}expectedKeybindings(){return this.expected}tmuxPassthrough(){return[...this.currentPassthrough]}expectedTmuxPassthrough(){return this.expectedPassthrough}usesTmuxPassthrough(t){return this.currentPassthrough.includes(t)}toggleTmuxPassthrough(t){this.currentPassthrough=this.currentPassthrough.includes(t)?this.currentPassthrough.filter(n=>n!==t):[...this.currentPassthrough,t]}resolution(){return this.resolutionCache===void 0&&(this.resolutionCache=w(this.invalidRoot===void 0?this.current:this.invalidRoot)),this.resolutionCache}hasInvalidRoot(){return this.invalidRoot!==void 0}expression(t){return this.resolution().gestures(t).join(", ")}edit(t,n){if(this.invalidRoot!==void 0)return{ok:!1,diagnostics:[{severity:"error",code:"invalid-keybindings",offendingValue:this.invalidRoot,message:"Reset all before editing: the saved keybindings root is invalid."}]};const r=Q.find(p=>p.id===t);let o;try{o=n.trim()===""?[]:ee(n).map(p=>Z(p.trim(),r))}catch(p){return{ok:!1,diagnostics:[{severity:"error",code:"invalid-override",bindingId:t,offendingValue:n,message:p instanceof Error?p.message:String(p)}]}}const i=[...new Set(o)],u={...this.current};delete u[t];const c=[...w(u).gestures(t)],l=k(i,c)?u:{...this.current,[t]:i},s=w(l),d=s.diagnostics.filter(p=>p.bindingId===t||p.relatedBindingIds?.includes(t));return d.length>0?{ok:!1,diagnostics:d}:(this.current=l,this.resolutionCache=void 0,{ok:!0,diagnostics:s.diagnostics})}unbind(t){return this.edit(t,"")}resetRow(t){delete this.current[t],this.resolutionCache=void 0}resetAll(){this.current={},this.currentPassthrough=[],this.invalidRoot=void 0,this.resolutionCache=void 0}discard(){this.current=h(this.baseline),this.currentPassthrough=[...this.baselinePassthrough],this.invalidRoot=this.baselineInvalidRoot,this.resolutionCache=void 0}markSaved(t,n=[]){this.expected=Object.keys(t).length===0?void 0:h(t),this.baseline=h(t),this.current=h(t),this.expectedPassthrough=n.length===0?void 0:[...n],this.baselinePassthrough=[...n],this.currentPassthrough=[...n],this.baselineInvalidRoot=void 0,this.invalidRoot=void 0,this.resolutionCache=void 0}}const be={"official-marketplace":{name:R,shortDescription:"the official crtr plugin catalog \u2014 registered as a source so its plugins are installable by ref.",longDescription:"Shallow-clones github.com/crouton-labs/crouter-official-marketplace into the user scope and registers it, which is what makes `crtr pkg plugin install crouter-official-marketplace/<name>` resolve and what fills `crtr pkg market browse`. Registering the source installs no plugin by itself. Uncheck it on a machine that should reach no external catalog \u2014 a plugin selected below still registers the marketplace it comes from, because its ref cannot resolve otherwise."},"crtr-extensions":{name:"pi-crtr-extensions",shortDescription:"crtr companion extensions \u2014 command palette, help gating, subscription/OAuth rotation, nested context.",longDescription:"Bundles the extensions built for crtr: a crtr slash-command palette, crtr/crouter help gating, surfacing of Claude Code marketplace plugin commands, nested AGENTS.md/CLAUDE.md loading, OAuth login + rotation across multiple Claude subscriptions (provider-rotation), and system-prompt trimming. The OAuth/rotation piece is what lets crtr authenticate your Claude account."},"oauth-adapter":{name:"pi-claude-oauth-adapter",shortDescription:"Anthropic OAuth / Claude Code credential compatibility for pi.",longDescription:"Third-party adapter (minzique/dotfiles-agents) letting pi authenticate with Claude using Claude Code OAuth credentials. Installed from npm, pinned to 0.1.2."},"capture-plugin":{name:"capture",shortDescription:"crtr plugin mounting `crtr capture` \u2014 browser automation and UI measurement over CDP.",longDescription:"Installs the `capture` plugin from the official crtr marketplace. It mounts `crtr capture` as a transparent passthrough to the external Capture CLI (`npm install -g @crouton-kit/capture`) for CDP screenshots, rendered-geometry measurement, HAR, accessibility trees, and JS execution against a live page. Uncheck it on a machine where agents never drive a browser \u2014 the command then costs nothing in their root prompt."},"search-plugin":{name:"search",shortDescription:"crtr plugin mounting `crtr search` \u2014 public-web discovery, grounded answers, and content extraction.",longDescription:"Installs the `search` plugin from the official crtr marketplace. It mounts `crtr search` and calls Exa directly, resolving its own API key from EXA_API_KEY or ~/.crouter/exa.key \u2014 crouter never handles that credential. Uncheck it on a machine whose agents get web search from somewhere else, such as a Northlight home where the platform serves `crtr search` from its own plugin."},"dev-plugin":{name:"dev",shortDescription:"crtr plugin mounting the development workflow \u2014 repository setup, worktrees, pull requests, and a dev track in the tutorial.",longDescription:"Installs the dev plugin from the official crtr marketplace. It adds the /dev: workflow commands (init, spec, design, plan, pr-loop), mounts crtr dev for a repository's own lifecycle commands and Grove instances, and contributes the crtr sys tutorial dev track. Uncheck it on a machine whose agents do not work in source repositories."}},y={"official-marketplace":{kind:"marketplace-source",source:D},"crtr-extensions":{kind:"local-path",source:b("pi-crtr-extensions")},"oauth-adapter":{kind:"npm",source:"npm:pi-claude-oauth-adapter@0.1.2"},"capture-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/capture"},"search-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/search"},"dev-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/dev"}},ve={"official-marketplace":[],"crtr-extensions":["pi-crtr-extensions"],"oauth-adapter":[],"capture-plugin":[],"search-plugin":[],"dev-plugin":[]};function P(e=b){return["official-marketplace","crtr-extensions","oauth-adapter","capture-plugin","search-plugin","dev-plugin"].map(t=>{const n=be[t],r=y[t].kind==="local-path"?e(n.name):y[t].source;return{id:t,name:n.name,sourceKind:y[t].kind,installSource:r,shortDescription:n.shortDescription,longDescription:n.longDescription}})}a(P,"buildSetupManifest");function Xe(e){switch(e.sourceKind){case"marketplace-source":return`clone + register ${e.installSource}`;case"marketplace-plugin":return`crtr pkg plugin install ${e.installSource}`;default:return`pi install ${e.installSource}`}}a(Xe,"packagePlanAction");function we(e){if(!e.startsWith("npm:"))return null;const t=e.slice(4),n=t.startsWith("@")?t.indexOf("@",1):t.lastIndexOf("@");return n>0?t.slice(0,n):t}a(we,"npmPackageName");function N(e,t,n){const r=we(e);if(r!==null)return`npm:${r}`;const o=ke(e,n);return X(t,o)}a(N,"normalizePackageIdentity");function I(e){return`package:${e}`}a(I,"packageNameIdentity");function ye(e){return e.startsWith("npm:")?[]:[I(V(e))]}a(ye,"localPackageNameIdentities");function Pe(e,t,n){const r=[N(e.installSource,t,n)];if(e.sourceKind==="local-path"){r.push(I(e.name));for(const o of ve[e.id])r.push(I(o))}return r}a(Pe,"manifestIdentities");function L(e,t=P(),n=S(g(),".pi","agent","settings.json"),r=g()){const o=J(n),i=new Set,u=new Map;for(const l of t)for(const s of Pe(l,o,r))u.set(s,l.id);const c=e&&typeof e=="object"?e.packages:void 0;if(!Array.isArray(c))return i;for(const l of c){const s=typeof l=="string"?l:l&&typeof l=="object"&&typeof l.source=="string"?l.source:null;if(s===null)continue;const d=[N(s,o,r),...ye(s)];for(const p of d){const f=u.get(p);f!==void 0&&i.add(f)}}return i}a(L,"detectInstalledSetupPackageIds");function m(e){return H("sh",["-lc",`command -v ${e} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}a(m,"detectCommandOnPath");function Ie(e=process.platform,t=m){switch(e){case"darwin":return t("brew")?"brew":"manual";case"linux":return t("apt-get")?"apt-get":t("dnf")?"dnf":t("pacman")?"pacman":"manual";default:return"manual"}}a(Ie,"detectPackageManager");function xe(e,t,n=m){if(e==="nerd-font"?ce().installed:n(e))return{tool:e,installed:!0,command:null,hint:"already installed",autoInstall:!1};if(e==="nerd-font"){const i=ue(t);return{tool:e,installed:!1,command:i.command,hint:`${i.hint} \u2014 ${pe}`,autoInstall:i.autoInstall}}const o=e==="nvim"?"neovim":"tmux";switch(t){case"brew":return{tool:e,installed:!1,command:`brew install ${o}`,hint:"Homebrew install",autoInstall:!0};case"apt-get":return{tool:e,installed:!1,command:`sudo apt-get update && sudo apt-get install -y ${o}`,hint:"apt-get install",autoInstall:!0};case"dnf":return{tool:e,installed:!1,command:`sudo dnf install -y ${o}`,hint:"dnf install",autoInstall:!0};case"pacman":return{tool:e,installed:!1,command:`sudo pacman -S --noconfirm ${o}`,hint:"pacman install",autoInstall:!0};default:return{tool:e,installed:!1,command:null,hint:`manual install required for ${e}`,autoInstall:!1}}}a(xe,"buildSystemInstallPlan");function _(e=g()){return S(e,".pi","agent","settings.json")}a(_,"resolveSettingsPath");function Qe(e={}){const t=e.homeDir??g(),n=e.settingsPath??_(t),r=e.manifest??P(b),o=ne(n),i=L(o,r,n,t);for(const s of G(r))i.add(s);const u=e.commandExists??m,c=e.packageManager??Ie(process.platform,u),l=["tmux","nvim","nerd-font"].map(s=>xe(s,c,u));return{manifest:r,installedPackageIds:i,systemPlans:l}}a(Qe,"buildSetupInitialState");function Ze(e){const t=e.manifest.map(r=>{const o=e.installedPackageIds.has(r.id)?"installed":"not installed";return`- ${r.name} \u2014 ${r.shortDescription} (${o})`}),n=e.systemPlans.map(r=>r.installed?`- ${r.tool}: \u2713 installed`:r.command?`- ${r.tool}: ${r.command}`:`- ${r.tool}: ${r.hint}`);return["crtr sys setup (non-interactive)","","Provider login: open the wizard in a TTY and use the Providers tab (same flow as /login) to authenticate a model provider.","","Packages:",...t,"","System deps:",...n,"",`Inbox: the inbox-toggle key (${te()??"disabled"}) is a crouter keybinding \u2014 view or rebind it in \`crtr sys settings\`; it is installed on the same tmux server as every other crouter binding.`,"Run `crtr sys setup` in a TTY to open the wizard."].join(`
|
|
1
|
+
var V=Object.defineProperty;var s=(e,t)=>V(e,"name",{value:t,configurable:!0});import{spawn as X,spawnSync as Q}from"node:child_process";import{homedir as k}from"node:os";import{basename as Z,dirname as R,join as P,relative as ee,resolve as te}from"node:path";import{isDeepStrictEqual as m}from"node:util";import{BINDING_CATALOG as ne,normalizeGesture as re,splitGestureExpression as ie,inboxShortcut as se,resolveKeybindings as I}from"../../core/keybindings/index.js";import{runtimeManifest as ae}from"./shared.js";import{atomicWriteJson as oe,readJsonIfExists as ce,readJsonOrNull as D}from"../../core/fs-utils.js";import{resolveBundledPiCliPath as ue}from"../../core/runtime/pi-cli.js";import{crtrVersion as le}from"../../shared/crtr-version.js";import{installTmuxBindings as de}from"../../core/runtime/tmux-chrome.js";import{normalizeTmuxPassthrough as pe}from"../../core/config.js";import{detectNerdFont as he,nerdFontInstallCommand as fe,createCurlPercentReader as me,NERD_FONT_MANUAL_LINUX_COMMAND as ge,NERD_FONT_SELECT_HINT as ke}from"../../core/runtime/nerd-font.js";import{startProgressBar as be}from"../../core/runtime/progress-bar.js";import{ensureRenderer as ve,isRendererReady as O}from"../../core/termrender/termrender.js";import{installFromMarketplace as we}from"../pkg/plugin-manage.js";import{addMarketplace as T}from"../pkg/market-manage.js";import{findPluginByName as xe,findMarketplaceByName as N}from"../../core/resolver.js";import{expandTilde as ye}from"../../core/fs-utils.js";const L="crouter-official-marketplace",_="https://github.com/crouton-labs/crouter-official-marketplace.git",M="main";function K(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}s(K,"isKeybindingsObject");function f(e){return K(e)?Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Array.isArray(n)?[...n]:n])):{}}s(f,"cloneKeybindings");class tt{static{s(this,"SetupKeybindingsDraft")}expected;baseline;current;baselineInvalidRoot;invalidRoot;resolutionCache;expectedPassthrough;baselinePassthrough;currentPassthrough;constructor(t,n=void 0){this.expected=t,this.baseline=f(t),this.current=f(t),this.baselineInvalidRoot=t!==void 0&&!K(t)?t:void 0,this.invalidRoot=this.baselineInvalidRoot,this.expectedPassthrough=n,this.baselinePassthrough=pe(n),this.currentPassthrough=[...this.baselinePassthrough]}get dirty(){return!m(this.current,this.baseline)||!m(this.invalidRoot,this.baselineInvalidRoot)||!m(this.currentPassthrough,this.baselinePassthrough)}overrides(){return f(this.current)}expectedKeybindings(){return this.expected}tmuxPassthrough(){return[...this.currentPassthrough]}expectedTmuxPassthrough(){return this.expectedPassthrough}usesTmuxPassthrough(t){return this.currentPassthrough.includes(t)}toggleTmuxPassthrough(t){this.currentPassthrough=this.currentPassthrough.includes(t)?this.currentPassthrough.filter(n=>n!==t):[...this.currentPassthrough,t]}resolution(){return this.resolutionCache===void 0&&(this.resolutionCache=I(this.invalidRoot===void 0?this.current:this.invalidRoot)),this.resolutionCache}hasInvalidRoot(){return this.invalidRoot!==void 0}expression(t){return this.resolution().gestures(t).join(", ")}edit(t,n){if(this.invalidRoot!==void 0)return{ok:!1,diagnostics:[{severity:"error",code:"invalid-keybindings",offendingValue:this.invalidRoot,message:"Reset all before editing: the saved keybindings root is invalid."}]};const r=ne.find(p=>p.id===t);let o;try{o=n.trim()===""?[]:ie(n).map(p=>re(p.trim(),r))}catch(p){return{ok:!1,diagnostics:[{severity:"error",code:"invalid-override",bindingId:t,offendingValue:n,message:p instanceof Error?p.message:String(p)}]}}const i=[...new Set(o)],u={...this.current};delete u[t];const c=[...I(u).gestures(t)],l=m(i,c)?u:{...this.current,[t]:i},a=I(l),d=a.diagnostics.filter(p=>p.bindingId===t||p.relatedBindingIds?.includes(t));return d.length>0?{ok:!1,diagnostics:d}:(this.current=l,this.resolutionCache=void 0,{ok:!0,diagnostics:a.diagnostics})}unbind(t){return this.edit(t,"")}resetRow(t){delete this.current[t],this.resolutionCache=void 0}resetAll(){this.current={},this.currentPassthrough=[],this.invalidRoot=void 0,this.resolutionCache=void 0}discard(){this.current=f(this.baseline),this.currentPassthrough=[...this.baselinePassthrough],this.invalidRoot=this.baselineInvalidRoot,this.resolutionCache=void 0}markSaved(t,n=[]){this.expected=Object.keys(t).length===0?void 0:f(t),this.baseline=f(t),this.current=f(t),this.expectedPassthrough=n.length===0?void 0:[...n],this.baselinePassthrough=[...n],this.currentPassthrough=[...n],this.baselineInvalidRoot=void 0,this.invalidRoot=void 0,this.resolutionCache=void 0}}const Pe={"official-marketplace":{name:L,shortDescription:"the official crtr plugin catalog \u2014 registered as a source so its plugins are installable by ref.",longDescription:"Shallow-clones github.com/crouton-labs/crouter-official-marketplace into the user scope and registers it, which is what makes `crtr pkg plugin install crouter-official-marketplace/<name>` resolve and what fills `crtr pkg market browse`. Registering the source installs no plugin by itself. Uncheck it on a machine that should reach no external catalog \u2014 a plugin selected below still registers the marketplace it comes from, because its ref cannot resolve otherwise."},"crtr-extensions":{name:"pi-crtr-extensions",shortDescription:"crtr companion extensions \u2014 command palette, help gating, subscription/OAuth rotation, nested context.",longDescription:"Bundles the extensions built for crtr: a crtr slash-command palette, crtr/crouter help gating, surfacing of Claude Code marketplace plugin commands, nested AGENTS.md/CLAUDE.md loading, OAuth login + rotation across multiple Claude subscriptions (provider-rotation), and system-prompt trimming. The OAuth/rotation piece is what lets crtr authenticate your Claude account."},"oauth-adapter":{name:"pi-claude-oauth-adapter",shortDescription:"Anthropic OAuth / Claude Code credential compatibility for pi.",longDescription:"Third-party adapter (minzique/dotfiles-agents) letting pi authenticate with Claude using Claude Code OAuth credentials. Installed from npm, pinned to 0.1.2."},"capture-plugin":{name:"capture",shortDescription:"crtr plugin mounting `crtr capture` \u2014 browser automation and UI measurement over CDP.",longDescription:"Installs the `capture` plugin from the official crtr marketplace. It mounts `crtr capture` as a transparent passthrough to the external Capture CLI (`npm install -g @crouton-kit/capture`) for CDP screenshots, rendered-geometry measurement, HAR, accessibility trees, and JS execution against a live page. Uncheck it on a machine where agents never drive a browser \u2014 the command then costs nothing in their root prompt."},"search-plugin":{name:"search",shortDescription:"crtr plugin mounting `crtr search` \u2014 public-web discovery, grounded answers, and content extraction.",longDescription:"Installs the `search` plugin from the official crtr marketplace. It mounts `crtr search` and calls Exa directly, resolving its own API key from EXA_API_KEY or ~/.crouter/exa.key \u2014 crouter never handles that credential. Uncheck it on a machine whose agents get web search from somewhere else, such as a Northlight home where the platform serves `crtr search` from its own plugin."},"dev-plugin":{name:"dev",shortDescription:"crtr plugin mounting the development workflow \u2014 repository setup, worktrees, pull requests, and a dev track in the tutorial.",longDescription:"Installs the dev plugin from the official crtr marketplace. It adds the /dev: workflow commands (init, spec, design, plan, pr-loop), mounts crtr dev for a repository's own lifecycle commands and Grove instances, and contributes the crtr sys tutorial dev track. Uncheck it on a machine whose agents do not work in source repositories."}},C={"official-marketplace":{kind:"marketplace-source",source:_},"crtr-extensions":{kind:"local-path",source:F("pi-crtr-extensions")},"oauth-adapter":{kind:"npm",source:"npm:pi-claude-oauth-adapter@0.1.2"},"capture-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/capture"},"search-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/search"},"dev-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/dev"}},j=["extensions/*.ts","extensions/*/index.ts","!extensions/**/*.d.ts"],Ie={"official-marketplace":[],"crtr-extensions":["pi-crtr-extensions"],"oauth-adapter":[],"capture-plugin":[],"search-plugin":[],"dev-plugin":[]};function F(e){return P(ae.runtimeHome(),"selected","dist","builtin-pi-packages",e)}s(F,"selectedPiPackageDir");function S(e=F){return["official-marketplace","crtr-extensions","oauth-adapter","capture-plugin","search-plugin","dev-plugin"].map(t=>{const n=Pe[t],r=C[t].kind==="local-path"?e(n.name):C[t].source;return{id:t,name:n.name,sourceKind:C[t].kind,installSource:r,shortDescription:n.shortDescription,longDescription:n.longDescription}})}s(S,"buildSetupManifest");function nt(e){switch(e.sourceKind){case"marketplace-source":return`clone + register ${e.installSource}`;case"marketplace-plugin":return`crtr pkg plugin install ${e.installSource}`;default:return`pi install ${e.installSource}`}}s(nt,"packagePlanAction");function Ce(e){if(!e.startsWith("npm:"))return null;const t=e.slice(4),n=t.startsWith("@")?t.indexOf("@",1):t.lastIndexOf("@");return n>0?t.slice(0,n):t}s(Ce,"npmPackageName");function b(e,t,n){const r=Ce(e);if(r!==null)return`npm:${r}`;const o=ye(e,n);return te(t,o)}s(b,"normalizePackageIdentity");function v(e){return`package:${e}`}s(v,"packageNameIdentity");function B(e){return e.startsWith("npm:")?[]:[v(Z(e))]}s(B,"localPackageNameIdentities");function Se(e,t,n){const r=[b(e.installSource,t,n)];if(e.sourceKind==="local-path"){r.push(v(e.name));for(const o of Ie[e.id])r.push(v(o))}return r}s(Se,"manifestIdentities");function G(e,t=S(),n=P(k(),".pi","agent","settings.json"),r=k()){const o=R(n),i=new Set,u=new Map;for(const l of t)for(const a of Se(l,o,r))u.set(a,l.id);const c=e&&typeof e=="object"?e.packages:void 0;if(!Array.isArray(c))return i;for(const l of c){const a=typeof l=="string"?l:l&&typeof l=="object"&&typeof l.source=="string"?l.source:null;if(a===null)continue;const d=[b(a,o,r),...B(a)];for(const p of d){const h=u.get(p);if(h==="crtr-extensions"){const x=t.find(y=>y.id===h);if(b(a,o,r)!==b(x.installSource,o,r)||!l||typeof l!="object"||!m(l.extensions,j))continue}h!==void 0&&i.add(h)}}return i}s(G,"detectInstalledSetupPackageIds");function g(e){return Q("sh",["-lc",`command -v ${e} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}s(g,"detectCommandOnPath");function Ae(e=process.platform,t=g){switch(e){case"darwin":return t("brew")?"brew":"manual";case"linux":return t("apt-get")?"apt-get":t("dnf")?"dnf":t("pacman")?"pacman":"manual";default:return"manual"}}s(Ae,"detectPackageManager");function $e(e,t,n=g){if(e==="nerd-font"?he().installed:n(e))return{tool:e,installed:!0,command:null,hint:"already installed",autoInstall:!1};if(e==="nerd-font"){const i=fe(t);return{tool:e,installed:!1,command:i.command,hint:`${i.hint} \u2014 ${ke}`,autoInstall:i.autoInstall}}const o=e==="nvim"?"neovim":"tmux";switch(t){case"brew":return{tool:e,installed:!1,command:`brew install ${o}`,hint:"Homebrew install",autoInstall:!0};case"apt-get":return{tool:e,installed:!1,command:`sudo apt-get update && sudo apt-get install -y ${o}`,hint:"apt-get install",autoInstall:!0};case"dnf":return{tool:e,installed:!1,command:`sudo dnf install -y ${o}`,hint:"dnf install",autoInstall:!0};case"pacman":return{tool:e,installed:!1,command:`sudo pacman -S --noconfirm ${o}`,hint:"pacman install",autoInstall:!0};default:return{tool:e,installed:!1,command:null,hint:`manual install required for ${e}`,autoInstall:!1}}}s($e,"buildSystemInstallPlan");function A(e=k()){return P(e,".pi","agent","settings.json")}s(A,"resolveSettingsPath");function rt(e={}){const t=e.homeDir??k(),n=e.settingsPath??A(t),r=e.manifest??S(),o=ce(n),i=G(o,r,n,t);for(const a of H(r))i.add(a);const u=e.commandExists??g,c=e.packageManager??Ae(process.platform,u),l=["tmux","nvim","nerd-font"].map(a=>$e(a,c,u));return{manifest:r,installedPackageIds:i,systemPlans:l}}s(rt,"buildSetupInitialState");function it(e){const t=e.manifest.map(r=>{const o=e.installedPackageIds.has(r.id)?"installed":"not installed";return`- ${r.name} \u2014 ${r.shortDescription} (${o})`}),n=e.systemPlans.map(r=>r.installed?`- ${r.tool}: \u2713 installed`:r.command?`- ${r.tool}: ${r.command}`:`- ${r.tool}: ${r.hint}`);return["crtr sys setup (non-interactive)","","Provider login: open the wizard in a TTY and use the Providers tab (same flow as /login) to authenticate a model provider.","","Packages:",...t,"","System deps:",...n,"",`Inbox: the inbox-toggle key (${se()??"disabled"}) is a crouter keybinding \u2014 view or rebind it in \`crtr sys settings\`; it is installed on the same tmux server as every other crouter binding.`,"Run `crtr sys setup` in a TTY to open the wizard."].join(`
|
|
2
2
|
`)+`
|
|
3
|
-
`}
|
|
3
|
+
`}s(it,"renderSetupStaticInstructions");class w extends Error{static{s(this,"SetupCommandError")}output;constructor(t,n){super(t),this.output=n}}function st(e){return`${e.stdout?.toString()??""}${e.stderr?.toString()??""}`}s(st,"commandOutput");function U(e,t,n){return new Promise((r,o)=>{const i=X(e,t,{stdio:["ignore","pipe","pipe"]});let u="";i.stdout.setEncoding("utf8"),i.stderr.setEncoding("utf8"),i.stdout.on("data",c=>{u+=c}),i.stderr.on("data",c=>{u+=c,n?.(c)}),i.on("error",c=>o(new w(`${e} failed: ${c.message}`,u))),i.on("close",c=>{c===0?r():o(new w(`${e} failed with status ${c??"unknown"}`,u))})})}s(U,"runCapturedCommand");function $(e,t){return U("sh",["-lc",e],t)}s($,"runShellCommand");function Ee(e,t=ue()){return U(process.execPath,[t,"install",e])}s(Ee,"installPiPackage");async function Y(){g("capture")||await $("npm install -g @crouton-kit/capture")}s(Y,"installCaptureCliIfMissing");function z(e){return e instanceof w?e.output:void 0}s(z,"capturedFailureOutput");function Re(e){const n=z(e)?.split(/\r?\n/).find(r=>r.trim()!=="");return n!==void 0?n.trim():e instanceof Error?e.message:String(e)}s(Re,"firstFailureLine");function De(e){const t=z(e);t===void 0||t.length===0||process.stderr.write(t.endsWith(`
|
|
4
4
|
`)?t:`${t}
|
|
5
|
-
`)}
|
|
6
|
-
`)}async fail(t,n){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2717 ${t} \u2014 ${
|
|
7
|
-
`),
|
|
5
|
+
`)}s(De,"printCapturedFailure");class Oe{static{s(this,"SetupProgress")}interactive;bar=null;constructor(t=!!process.stdout.isTTY){this.interactive=t}start(t){return this.interactive?(this.bar=be(`Installing ${t}\u2026`),this.bar):null}async clear(){await this.bar?.stop(),this.bar=null}async succeed(t){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2713 ${t}
|
|
6
|
+
`)}async fail(t,n){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2717 ${t} \u2014 ${Re(n)}
|
|
7
|
+
`),De(n)}async run(t,n){const r=this.start(t);try{const o=await n(r);return await this.succeed(t),o}catch(o){throw await this.fail(t,o),o}}}function W(e,t){return O()?"current":(e?.(),ve(t),O()?"provisioned":"unavailable")}s(W,"ensureManagedRenderer");async function Te(){try{de()}catch{}}s(Te,"reconcileInboxFrontDoor");function q(e,t){return t.length===0?[`${e}: none`]:[`${e}:`,...t.map(n=>` - ${n}`)]}s(q,"summarySection");function at(e){return["crtr sys setup complete",...q("installed",e.installed),...q("skipped",e.skipped),"New to crouter? Ask for the tutorial in your first conversation, or run /tutorial any time."].join(`
|
|
8
8
|
`)+`
|
|
9
|
-
`}
|
|
9
|
+
`}s(at,"formatSetupExecutionSummary");function H(e,t){const n=[];for(const r of e)try{r.sourceKind==="marketplace-source"?N(r.name,t)!==null&&n.push(r.id):r.sourceKind==="marketplace-plugin"&&xe(r.name,t)!==null&&n.push(r.id)}catch{}return n}s(H,"detectInstalledMarketplaceEntries");function Ne(e,t="user"){if(N(e,t)!==null)return null;if(e!==L)throw new Error(`marketplace not registered: ${e}`);return T({url:_,ref:M,scope:t}),e}s(Ne,"ensureMarketplaceRegistered");function Le(e){const t=A(),n=D(t);if(!n||typeof n!="object"||Array.isArray(n))throw new Error(`invalid pi settings: ${t}`);const r=n.packages;if(!Array.isArray(r))throw new Error(`invalid pi packages: ${t}`);const o=s(c=>{const l=typeof c=="string"?c:c&&typeof c=="object"?c.source:void 0;return typeof l=="string"&&B(l).includes(v("pi-crtr-extensions"))},"isCrtrExtensions"),i=r.findIndex(o),u=r.filter(c=>!o(c));u.splice(i<0?u.length:i,0,{source:ee(R(t),e),extensions:j}),oe(t,{...n,packages:u})}s(Le,"configureCrtrExtensions");async function J(e){if(e.sourceKind==="marketplace-source")return T({url:e.installSource,ref:M,scope:"user"}),[e.name];if(e.sourceKind==="marketplace-plugin"){const[t,n]=e.installSource.split("/"),r=Ne(t);return await we({marketplace:t,plugin:n},"user"),e.id==="capture-plugin"&&await Y(),r===null?[e.name]:[r,e.name]}return await Ee(e.installSource),e.id==="crtr-extensions"&&Le(e.installSource),[e.name]}s(J,"installSetupPackage");async function ot(e){const t=S(),n=G(D(A()),t);for(const i of H(t,"user"))n.add(i);const r=new Map(t.map(i=>[i.id,i])),o=process.stdin.isTTY&&process.stdout.isTTY?["crtr-extensions","official-marketplace","oauth-adapter","capture-plugin","search-plugin"]:["crtr-extensions","official-marketplace","capture-plugin","search-plugin"];for(const i of o){const u=r.get(i);if(!n.has(i))try{await J(u)}catch(c){e(u.name,c)}}try{W(void 0,()=>{})==="unavailable"&&e("termrender renderer",new Error("unavailable \u2014 install uv"))}catch(i){e("termrender renderer",i)}return le()}s(ot,"reconcileFirstRun");async function ct(e){const t=[],n=[],r=[],o=[],i=new Oe;for(const a of e.packages){if(e.installedPackageIds.has(a.id)){if(n.push(`${a.name} (already installed)`),a.id==="capture-plugin"&&!g("capture"))try{await i.run("Capture CLI",()=>Y()),t.push("Capture CLI")}catch(d){n.push(`Capture CLI (${d instanceof Error?d.message:String(d)})`)}continue}try{t.push(...await i.run(a.name,()=>J(a)))}catch(d){if(a.sourceKind!=="marketplace-source"&&a.sourceKind!=="marketplace-plugin")throw d;n.push(`${a.name} (${d instanceof Error?d.message:String(d)})`)}}for(const a of e.systemDeps){if(a.installed){o.push(`${a.tool} (already installed)`);continue}if(!a.autoInstall||!a.command){o.push(`${a.tool} (${a.hint})`);continue}const d=a.command,p=d===ge;await i.run(a.tool,h=>{if(!p||h===null)return $(d);const x=me();return $(d,y=>{const E=x(y);E!==null&&h.setFraction(E/100)})}),r.push(a.tool)}const u=[];let c=!1,l;try{l=W(()=>{c=!0,i.start("termrender renderer")},a=>u.push(a))}catch(a){throw c&&await i.fail("termrender renderer",a),a}switch(l){case"provisioned":c&&await i.succeed("termrender renderer"),t.push("termrender renderer");break;case"current":n.push("termrender renderer (current)");break;case"unavailable":{const a=new w("unavailable \u2014 install uv",u.join(""));c&&await i.fail("termrender renderer",a),n.push("termrender renderer (unavailable \u2014 install uv)");break}}return await Te(),{installed:[...t,...r],skipped:[...n,...o]}}s(ct,"executeSetupSubmission");export{L as OFFICIAL_MARKETPLACE_NAME,M as OFFICIAL_MARKETPLACE_REF,_ as OFFICIAL_MARKETPLACE_URL,tt as SetupKeybindingsDraft,rt as buildSetupInitialState,S as buildSetupManifest,$e as buildSystemInstallPlan,g as detectCommandOnPath,G as detectInstalledSetupPackageIds,Ae as detectPackageManager,ct as executeSetupSubmission,at as formatSetupExecutionSummary,b as normalizePackageIdentity,nt as packagePlanAction,ot as reconcileFirstRun,Te as reconcileInboxFrontDoor,it as renderSetupStaticInstructions,A as resolveSettingsPath};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ContextExposureState, type ExposureTarget } from './injected-store.js';
|
|
2
|
+
import type { NodeConfigSubject } from './subject-fields.js';
|
|
3
|
+
export type CliContextDeliveryOutcome = 'stateless' | 'recorded' | 'unrecorded';
|
|
4
|
+
export interface CliContextDelivery<T> {
|
|
5
|
+
result: T;
|
|
6
|
+
outcome: CliContextDeliveryOutcome;
|
|
7
|
+
diagnostic?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface CliContextDeliveryOptions<T> {
|
|
10
|
+
nodeId: string | undefined;
|
|
11
|
+
/** Explicit memory reads remain useful without a daemon: gated attachments
|
|
12
|
+
* skip while ungated ones render, exactly as before this shared boundary. */
|
|
13
|
+
allowUnavailableSubject?: boolean;
|
|
14
|
+
loadSubject?: (nodeId: string) => Promise<NodeConfigSubject | null>;
|
|
15
|
+
loadState?: (nodeId: string) => ContextExposureState;
|
|
16
|
+
saveState?: (nodeId: string, state: ContextExposureState) => void;
|
|
17
|
+
render: (subject: NodeConfigSubject | null, target: ExposureTarget) => T | Promise<T>;
|
|
18
|
+
}
|
|
19
|
+
/** Render one CLI-owned delivery batch. The renderer owns event routing and
|
|
20
|
+
* exposure registration; this boundary owns subject lookup and the one
|
|
21
|
+
* load/clone/render/save ledger transaction shared by CLI callers. */
|
|
22
|
+
export declare function renderCliContextDelivery<T>(opts: CliContextDeliveryOptions<T>): Promise<CliContextDelivery<T>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var s=Object.defineProperty;var n=(t,e)=>s(t,"name",{value:e,configurable:!0});import{localClient as f}from"../../api/node-transport.js";import{CrtrError as x}from"../errors.js";import{cloneContextExposureState as m,emptyContextExposureState as S,exposureTarget as c,loadContextExposureState as b,saveContextExposureState as w}from"./injected-store.js";function a(t,e){const r=e instanceof Error?e.message:e===void 0?void 0:String(e);return new x("context_delivery_failed",r===void 0?t:`${t}: ${r}`,void 0,{next:"The displayed file content remains available; retry context delivery in a live node when the runtime is reachable."})}n(a,"deliveryError");async function y(t){return await f({autostart:!1,coldStartPollWindowMs:0}).nodeSubject(t)}n(y,"nodeSubject");async function E(t){const e=t.nodeId?.trim();if(e===void 0||e==="")return{result:await t.render(null,c(S(),"transcript")),outcome:"stateless"};let r;try{r=await(t.loadSubject??y)(e)}catch(o){if(t.allowUnavailableSubject!==!0)throw a(`could not load context subject for node ${e}`,o);r=null}if(r===null&&t.allowUnavailableSubject!==!0)throw a(`could not load context subject for node ${e}`);let d;try{d=(t.loadState??b)(e)}catch(o){throw a(`could not load context exposure state for node ${e}`,o)}const l=m(d),i=await t.render(r,c(l,"transcript"));try{return(t.saveState??w)(e,l),{result:i,outcome:"recorded"}}catch(o){const u=o instanceof Error?o.message:String(o);return{result:i,outcome:"unrecorded",diagnostic:`Context was delivered but not recorded for node ${e}: ${u}`}}}n(E,"renderCliContextDelivery");export{E as renderCliContextDelivery};
|
|
@@ -54,8 +54,10 @@ export declare function contentReadAttachments(doc: Pick<SubstrateDoc, 'name' |
|
|
|
54
54
|
blocks: string[];
|
|
55
55
|
listing?: string[];
|
|
56
56
|
};
|
|
57
|
+
export declare function renderAutoLoadedContext(blocks: readonly string[]): string;
|
|
57
58
|
/** Surface docs whose `read` entries match a successfully read file, using
|
|
58
59
|
* the caller-supplied daemon snapshot subject. */
|
|
60
|
+
export declare function renderOnReadDocBlocksForSubject(subject: NodeConfigSubject, readFilePath: string, target?: ExposureTarget, accounting?: DeliveryAccounting): string[];
|
|
59
61
|
export declare function renderOnReadDocsForSubject(subject: NodeConfigSubject, readFilePath: string, target?: ExposureTarget, accounting?: DeliveryAccounting): string;
|
|
60
62
|
/** Workspace boot docs using the snapshot's cwd/profile instead of a canvas
|
|
61
63
|
* lookup. The shared exposure target prevents a later read from repeating a
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var T=Object.defineProperty;var i=(e,n)=>T(e,"name",{value:n,configurable:!0});import{sep as
|
|
1
|
+
var T=Object.defineProperty;var i=(e,n)=>T(e,"name",{value:n,configurable:!0});import{sep as w}from"node:path";import{realpathOrSelf as E}from"../fs-utils.js";import{ambientMemoryTarget as B,listAllMemoryDocs as M,loadMemoryTargetView as P}from"../memory-resolver.js";import{commandEntryMatches as j,owningRootOf as S,preCommandEntryMatches as L}from"./surface-match.js";import{demoteDocumentTranscriptExposure as W,documentExposedAtOrAbove as q,emptyContextExposureState as H,exposedAtOrAbove as I,exposureTarget as K,registerDocumentExposure as V,registerExposure as z}from"./injected-store.js";import{planDelivery as b}from"./plan.js";import{parseSubstrateDoc as G,previewLine as J,rungRank as O}from"./schema.js";import{dirDedupKey as A,docListingDirs as Q,docsByName as F,isDirName as U,renderDirListing as X}from"./listings.js";import{cachedEventCorpusInclusive as Y}from"./session-cache.js";function h(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}i(h,"attr");function C(){try{return Y(M,G)}catch{return[]}}i(C,"resolvedDocs");function Z(e,n){if(n==="none")return null;let r=`kind="${h(e.kind)}" name="${h(e.name)}"`;if(n==="content"){const t=e.body.trim();if(t!=="")return`<memory ${r}>
|
|
2
2
|
${t}
|
|
3
|
-
</memory>`}else if(n==="preview"){const t=J(e);t!==""&&(r+=` readWhen="${
|
|
3
|
+
</memory>`}else if(n==="preview"){const t=J(e);t!==""&&(r+=` readWhen="${h(t)}"`)}return`<memory ${r} />`}i(Z,"renderDocEnvelope");function l(e){return e.docs.filter(n=>n.winner).map(n=>({doc:n.doc,rung:n.finalRung,source:n.source}))}i(l,"planWinners");function R(e){return F(e.docs.map(({source:n})=>n))}i(R,"planListingCorpus");function _(e,n){return`<memory-listing dir="${h(e)}">
|
|
4
4
|
${n.join(`
|
|
5
5
|
`)}
|
|
6
|
-
</memory-listing>`}i(_,"listingBlock");function
|
|
6
|
+
</memory-listing>`}i(_,"listingBlock");function fe(){return{deliveries:new Map}}i(fe,"deliveryAccounting");function $(e,n,r,t,o){if(e===void 0||r==="none")return;const c=E(n.path),a=e.deliveries.get(c);a!==void 0&&O(a.rung)>=O(r)||e.deliveries.set(c,{rung:r,...t===void 0?{}:{cause:t},...o===void 0?{}:{source:o}})}i($,"accountDelivery");function ee(e,n){const{target:r,byName:t}=n,o=Q(t,e.name),c=o[0]===e.name,a=[];let s;for(const[y,u]of o.entries()){if(!U(t,u))continue;const m=c&&y===0;if(!m&&I(r.state,A(u),"preview"))continue;if(n.listings==="tree"){n.dirs?.push(u);continue}const d=m&&n.explicit===!0,g=X(t,u,r,!d,k=>$(n.accounting,k,"preview","directory listing attached to content delivery",k));g.length!==0&&(z(r,A(u),"preview"),d?s=g:a.push(_(u,g)))}return a.push(...re(E(e.path),e.name,{...n,deliveryCause:"memory-read companion of content delivery"})),{blocks:a,...s===void 0?{}:{listing:s}}}i(ee,"contentReadAttachments");function p(e,n){const{target:r}=n,t=[];for(const{doc:o,rung:c,source:a}of e){if(q(r.state,o.path,o.body,c))continue;const s=Z(o,c);s!==null&&(V(r,o.path,o.body,c),$(n.accounting,o,c,n.deliveryCause,a),c==="content"&&t.push(...ee(o,{...n,deliveryCause:"memory-read companion of content delivery"}).blocks),t.push(s))}return t}i(p,"renderWinnerBlocks");function D(e,n,r,t){return{subject:e,target:n,byName:R(r),listings:"blocks",accounting:t}}i(D,"eventAttachmentOptions");function f(){return K(H(),"transcript")}i(f,"transientTranscriptTarget");function x(e){return e.length===0?"":`<auto-loaded-context>
|
|
7
7
|
${e.join(`
|
|
8
8
|
`)}
|
|
9
|
-
</auto-loaded-context>`}i(
|
|
9
|
+
</auto-loaded-context>`}i(x,"renderAutoLoadedContext");function v(e,n,r,t){return t===void 0?b(e,B(),n,r,C()):b(e,t,n,r)}i(v,"eventPlan");function ne(e,n,r=f(),t){const o=v(e,"read",{absoluteFile:n});return p(l(o),D(o.subject,r,o,t))}i(ne,"renderOnReadDocBlocksForSubject");function ye(e,n,r=f(),t){return x(ne(e,n,r,t))}i(ye,"renderOnReadDocsForSubject");function ge(e,n,r,t=f(),o){const c={cwd:n,profileId:r,nodeId:null};let a,s;try{a=l(b(e,c,"workspace-open")),s=F(P(c,{quiet:!0}).docs)}catch{return""}return a.sort((y,u)=>{const m=S(y.doc)??"",d=S(u.doc)??"";return m.split(w).filter(Boolean).length-d.split(w).filter(Boolean).length||m.localeCompare(d)||y.doc.path.localeCompare(u.doc.path)}),x(p(a,{subject:e,target:t,byName:s,memoryTarget:c,listings:"blocks",accounting:o}))}i(ge,"renderWorkspaceOpenDocsForSubject");function re(e,n,r){const t=v(r.subject,"memory-read",{resolvedCanonicalName:n,resolvedDocPath:e},r.memoryTarget);return p(l(t),{...r,byName:r.byName??R(t)})}i(re,"memoryReadDocBlocks");function he(e,n,r=f(),t){const o=v(e,"command",{command:n});return x(p(l(o),D(e,r,o,t)))}i(he,"renderOnCommandDocsForSubject");function xe(e,n,r=f(),t){const o=v(e,"pre-command",{command:n});return x(p(l(o),D(e,r,o,t)))}i(xe,"renderPreCommandDocsForSubject");function te(e){return e.surfaces.some(n=>n.on==="pre-command")}i(te,"carriesPreCommandEntry");function N(e,n){const r=n==="command"?j:L;return C().some(({doc:t})=>t.surfaces.some(o=>r(o,e)))}i(N,"hasCommandSurfaceForCommand");function ve(e){return N(e,"command")}i(ve,"corpusHasCommandSurfaceForCommand");function be(e){return N(e,"pre-command")}i(be,"corpusHasPreCommandSurfaceForCommand");function Ce(e){for(const{doc:n}of C())te(n)&&W(e,n.path,n.body)}i(Ce,"demotePreCommandExposures");export{$ as accountDelivery,ee as contentReadAttachments,ve as corpusHasCommandSurfaceForCommand,be as corpusHasPreCommandSurfaceForCommand,fe as deliveryAccounting,Ce as demotePreCommandExposures,re as memoryReadDocBlocks,x as renderAutoLoadedContext,he as renderOnCommandDocsForSubject,ne as renderOnReadDocBlocksForSubject,ye as renderOnReadDocsForSubject,xe as renderPreCommandDocsForSubject,ge as renderWorkspaceOpenDocsForSubject};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var H=Object.defineProperty;var p=(
|
|
2
|
-
`)){const i=
|
|
3
|
-
`).map(async m=>{if(m!=="")try{await
|
|
4
|
-
`)[0]??"").slice(0,200),r=t.providerError,d=r===void 0?"":` Provider: ${r.provider}/${r.model}.`+(r.status===void 0?"":` HTTP status: ${r.status}.`)+(r.errno===void 0?"":` Errno: ${r.errno}.`)+(r.code===void 0?"":` Code: ${r.code}.`)+(r.body===void 0?"":` Body: ${r.body.slice(0,200)}.`),c=t.kind==="context-overflow",l=c?`Child failed \u2014 ${i} (${e}) exceeded its model context window and is now dead. Shrink the task or loaded context, or choose a larger-context model before spawning it again. Error: ${o}`:`Child hit a fatal provider fault \u2014 ${i} (${e}) got a non-retryable ${t.kind} error and will NOT recover on its own; it stays alive, and waking it clears the fault as soon as one turn completes \u2014 a wake that hits the same cause fails again.
|
|
1
|
+
var H=Object.defineProperty;var p=(s,e)=>H(s,"name",{value:e,configurable:!0});import{statSync as V}from"node:fs";import{join as k}from"node:path";import{homedir as I}from"node:os";import{execFile as K}from"node:child_process";import{promisify as z}from"node:util";import{getNode as A,isWarmSpare as J,subscribersOf as x}from"../../core/canvas/index.js";import{contextDir as Q,isSafeNodeId as u}from"../../core/canvas/paths.js";import{fullName as O}from"../../core/canvas/labels.js";import{recordedPidLiveness as G}from"../../core/canvas/pid.js";import{transition as X}from"../../core/runtime/lifecycle.js";import{readFault as L,readLiveTurn as C,recordFault as Z}from"../../core/canvas/recovery.js";import{errorClassFromFault as ee}from"../../core/fault-classifier.js";import{nextFaultRetry as te}from"../../core/runtime/fault-recovery.js";import{fanDoctrineWake as W}from"../../core/runtime/close.js";import{headlessBrokerHost as y}from"../../core/runtime/host.js";import{reloadAuthLive as ne}from"../../core/runtime/auth-reload.js";import{emitEvent as f}from"../../core/events/emit.js";import{operationIdContext as R}from"../../core/events/operation-id.js";import{hasUnseenWakeMail as re,resetStaleExecutionMail as ie}from"../../core/canvas/deliveries.js";import{activeBackgroundBashJobs as ae}from"../../core/bash-jobs.js";import{focusOf as se}from"../../core/runtime/placement.js";import{hasAttachedBrokerViewers as oe}from"../../core/runtime/broker/client-registry.js";import{deliverLive as le}from"../../core/runtime/interactive-deliver.js";import{BrokerUnreachableError as de}from"../../core/runtime/broker-request.js";import{formatCard as ce,PARK_SUMMARY_PROMPT as ue}from"../../shared/generated-context.js";import{brokerThresholdsForDaemon as fe}from"../../core/runtime/fleet.js";import{readConfig as pe}from"../../core/config.js";import{scopedStoreExists as me}from"../../core/scoped-state/db.js";import{providerStore as he}from"../../core/scoped-state/paths.js";import{providerRevision as _e}from"../../core/scoped-state/providers.js";import{beginPendingPark as ge,consumePendingPark as b,pendingParkIds as ve,pendingParkStartedAt as ke}from"../park-pending.js";import{shouldParkAfterSummary as ye}from"../park-activity.js";import{applyParkEvent as N,parkEvent as be}from"./live-obligation.js";import{envNoDaemonAutostart as we,envTestUnattendedParkMs as Se,parkSummaryGraceMs as Ae,envUnattendedParkMs as Ne}from"../../shared/env.js";const P=z(K);function Pe(s){return C(s)?.busy===!0}p(Pe,"liveBusy");function gt(s){const e=C(s)?.progressAt;if(e==null)return null;const t=Date.parse(e);return Number.isNaN(t)?null:t}p(gt,"liveTurnProgressMs");function B(s,e){return e===null?null:`${s}:${e}`}p(B,"incarnationOf");function F(s){const e=C(s.node_id),t=e?.busy===!0&&e.progressAt!==null?Date.parse(e.progressAt):Number.NaN,a=s.launched_at===null||s.launched_at===void 0?Number.NaN:Date.parse(s.launched_at);return!Number.isFinite(t)||!Number.isFinite(a)||t<a?null:t}p(F,"busySinceForIncarnation");const U=3*6e4,q=2e4,D=20*6e4,Me=2,Te=5*6e4;function $e(){const s=Ne();if(s!==void 0)return s;const e=pe("user").lifecycle.unattendedParkMs;return we()?Se()??e:e}p($e,"unattendedParkMsForDaemon");function Y(){return Ae()}p(Y,"parkSummaryGraceMsForDaemon");function Ee(s,e,t,a){return s!==!0||e!=="refresh"||t?"leave":a===null||a<U?"pending":"kill"}p(Ee,"yieldStallVerdict");function Ce(s){return!s.busy||s.quietForMs===null||s.quietForMs<D?"leave":s.cpuPercent===null||s.hasDescendants!==!1&&s.cpuPercent>Me?"pending":"wedged"}p(Ce,"wedgeVerdict");function j(s){const e=new Map,t=new Map;for(const a of s.split(`
|
|
2
|
+
`)){const i=a.trim();if(i==="")continue;const n=i.split(/\s+/);if(n.length<3)continue;const o=Number(n[0]),r=Number(n[1]),d=Number(n[2]);if(!Number.isFinite(o)||!Number.isFinite(r)||!Number.isFinite(d))continue;e.set(o,d);const c=t.get(r);c===void 0?t.set(r,[o]):c.push(o)}return{byPid:e,childrenOf:t}}p(j,"parsePsTree");function Re(s,e){const{byPid:t,childrenOf:a}=j(s);if(!t.has(e))return null;let i=0;const n=[e],o=new Set;for(;n.length>0;){const r=n.pop();if(o.has(r))continue;o.add(r),i+=t.get(r)??0;const d=a.get(r);d!==void 0&&n.push(...d)}return i}p(Re,"sumTreeCpu");function Fe(s,e){const{byPid:t,childrenOf:a}=j(s);return t.has(e)?(a.get(e)??[]).length>0:null}p(Fe,"treeHasDescendants");function De(){const s=process.env.PI_CODING_AGENT_DIR;return s!==void 0&&s!==""?s==="~"||s.startsWith("~/")?k(I(),s.slice(1)):s:k(I(),".pi","agent")}p(De,"piAgentDir");function Ie(s){return[k(s,"auth.json"),k(s,"anthropic-credentials.json"),k(s,"openai-codex-credentials.json")]}p(Ie,"piCredentialPaths");class vt{static{p(this,"BrokerSupervisionReconciler")}yieldStalls=new Map;wedgeNotifiedAt=new Map;fatalFaultNotifiedAt=new Map;unattendedSince=new Map;sampleTree;signal;knownCredentialRevision=null;lastOverCapWarnAt=Number.NEGATIVE_INFINITY;constructor(e={}){this.sampleTree=e.readTreeSample??(t=>this.readTreeSample(t)),this.signal=e.signal??((t,a)=>process.kill(t,a))}async runFleetPreamble(e){return await this.handleAuthReload(e),fe()}warnIfSaturated(e){if(e.fleet.size()<e.thresholds.warning||!e.lifecycle.acceptsDetachedWork())return;const t=R.fresh(()=>this.warnOverCapInTmux(e.fleet.size(),e.thresholds,e.frozen));e.lifecycle.registerDetached(t)}async run(e,t){const a=$e();for(const i of t.rows){const n=i.node_id,o=t.fleet.get(n);if(o===void 0||i.status!=="active"&&i.status!=="idle"){this.unattendedSince.delete(n);continue}await R.fresh(async()=>{try{this.handleYieldStall(i,o,t.fleet,e),await this.handleWedgeDetection(i,o,t.fleet,e),this.handleFatalFault(n),this.handleUnattendedParking(n,A(n),o.pid,e,t,a)}catch(r){this.unattendedSince.delete(n),f({level:"error",event:"broker.supervision.failed",...u(n)?{node_id:n}:{fields:{affected_node_id:n}},error:r})}})}for(const i of this.unattendedSince.keys())t.fleet.has(i)||this.unattendedSince.delete(i);for(const i of ve())t.fleet.has(i)||b(i);ie(e)}parkResetCondition(e,t,a,i){if(t.pi_session_id==null||t.pi_pid!==a||t.status==="done"||t.status==="canceled"||t.status==="dead"||t.intent!==null||ae(Q(e)).length>0||se(e)!==null||oe(e))return!0;const n=L(e);return n!==null&&n.retry.disposition==="auto"&&n.retry.by==="daemon"&&(n.kind==="connection"||n.kind==="rate-limit"||n.kind==="overloaded")&&(n.retry.nextAt!==void 0||te(n,i)!==null)?!0:re(e)}handleUnattendedParking(e,t,a,i,n,o){if(J(e)){this.unattendedSince.delete(e),b(e);return}if(t===null){this.unattendedSince.delete(e),b(e);return}const r=this.parkResetCondition(e,t,a,i),d=ke(e);if(d!==void 0){if(i-d<Y())return;const m=b(e);if(m===void 0||(this.unattendedSince.delete(e),!ye(e,t,m)))return;f({level:"warn",event:"broker.park.summary_expired",...u(e)?{node_id:e}:{},fields:{...u(e)?{}:{affected_node_id:e},grace_ms:Y()}}),N(e,"park"),y.teardown(e);return}if(r||Pe(e)){this.unattendedSince.delete(e);return}const c=this.unattendedSince.get(e);if(c===void 0){this.unattendedSince.set(e,i);return}if(i-c<o)return;this.unattendedSince.delete(e);const l=be(e,t.lifecycle);if(l==="release"){N(e,l),y.teardown(e);return}if(l==="cancel"){N(e,l),y.teardown(e);return}n.lifecycle.acceptsDetachedWork()&&(ge(e,i),n.lifecycle.registerDetached(this.requestParkSummary(e)))}async requestParkSummary(e){try{const t=await le(e,ce("park",{},ue),{origin:{type:"runtime",kind:"park"}});f({level:"info",event:"broker.park.summary_requested",...u(e)?{node_id:e}:{},fields:{...u(e)?{}:{affected_node_id:e},route:t}})}catch(t){if(b(e)===void 0)return;if(t instanceof de){N(e,"park"),y.teardown(e);return}f({level:"error",event:"broker.park.summary_failed",...u(e)?{node_id:e}:{fields:{affected_node_id:e}},error:t})}}async warnOverCapInTmux(e,t,a){const i=Date.now();if(i-this.lastOverCapWarnAt<Te)return;this.lastOverCapWarnAt=i;const{warning:n,automaticReviveCap:o}=t,r=a.stalled+a.waitingOnMail;f({level:"warn",event:"broker.capacity.warning",fields:{live_count:e,warning_threshold:n,hard_cap:o,frozen_stalled:a.stalled,frozen_waiting_on_mail:a.waitingOnMail}});const d=r===0?"":` \u2014 ${r} frozen (${a.stalled} stalled, ${a.waitingOnMail} waiting on mail)`,c=`\u26A0 crtrd: ${e} live brokers (warning ${n}; hard cap ${o})${d} \u2014 possible broker leak. ps -ax | grep broker-cli.js`;try{const l=await P("tmux",["list-clients","-F","#{client_name}"],{encoding:"utf8",timeout:2e3});if(typeof l.stdout!="string")return;await Promise.allSettled(l.stdout.split(`
|
|
3
|
+
`).map(async m=>{if(m!=="")try{await P("tmux",["display-message","-C","-d","10000","-c",m,c],{encoding:"utf8",timeout:2e3})}catch{try{await P("tmux",["display-message","-c",m,c],{encoding:"utf8",timeout:2e3})}catch(h){f({level:"error",event:"broker.capacity.tmux_display_failed",error:h,fields:{client:m}})}}}))}catch(l){f({level:"error",event:"broker.capacity.tmux_list_clients_failed",error:l})}}handleYieldStall(e,t,a,i){const n=e.node_id,o=B(t.pid,e.pi_pid_identity);if(e.intent!=="refresh"||F(e)!==null||o===null){o!==null&&this.yieldStalls.delete(o);return}let r=this.yieldStalls.get(o);if(r===void 0){r={since:i},this.yieldStalls.set(o,r);return}if(Ee(!0,e.intent,!1,i-r.since)!=="kill")return;const d=A(n);if(!(a.get(n)!==t||d?.pi_pid!==t.pid||d.pi_pid_identity!==e.pi_pid_identity||G(t.pid,e.pi_pid_identity)!=="alive"))if(r.termedAt===void 0){if(!this.signalYieldStall(n,t.pid,"SIGTERM"))return;r.termedAt=i,f({level:"warn",event:"broker.yield_stall.sigterm",...u(n)?{node_id:n}:{},fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,elapsed_ms:i-r.since,grace_ms:U}})}else i-r.termedAt>=q&&this.signalYieldStall(n,t.pid,"SIGKILL")&&f({level:"warn",event:"broker.yield_stall.sigkill",...u(n)?{node_id:n}:{},fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,elapsed_ms:i-r.termedAt,grace_ms:q,stall_elapsed_ms:i-r.since}})}signalYieldStall(e,t,a){try{return this.signal(t,a),!0}catch(i){return f({level:"error",event:"broker.yield_stall.signal_failed",...u(e)?{node_id:e}:{},error:i,fields:{...u(e)?{}:{affected_node_id:e},pid:t,signal:a}}),!1}}async readTreeSample(e){try{const{stdout:t}=await P("ps",["-ax","-o","pid=,ppid=,pcpu="],{encoding:"utf8",timeout:2e3});if(typeof t!="string")return null;const a=Re(t,e),i=Fe(t,e);return a===null||i===null?null:{cpuPercent:a,hasDescendants:i}}catch{return null}}async handleWedgeDetection(e,t,a,i){const n=e.node_id,o=B(t.pid,e.pi_pid_identity),r=F(e);if(r===null||o===null){o!==null&&this.wedgeNotifiedAt.delete(o);return}const d=i-r,c=d>=D?await this.sampleTree(t.pid):null,l=A(n),m=l===null?null:F(l);if(a.get(n)!==t||l===null||l.pi_pid!==t.pid||l.pi_pid_identity!==e.pi_pid_identity||m!==r)return;const h=c?.cpuPercent??null,_=c?.hasDescendants??null;if(Ce({busy:!0,quietForMs:d,cpuPercent:h,hasDescendants:_})!=="wedged"||this.wedgeNotifiedAt.get(o)===r)return;this.wedgeNotifiedAt.set(o,r);const w=O(l),S=Math.round((d??D)/6e4),M=_??!0,v=!M&&G(t.pid,e.pi_pid_identity)!=="alive"?"pid_identity_unproven":null;let T=!1,$=!1,g;if(M)g=`Child wedged \u2014 ${w} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and its process is near-idle. It will NOT recover on its own \u2014 read \`crtr memory read wedged-child-on-runaway-bash\` and kill the runaway SUBPROCESS (not this node) so its turn can resume with no lost context.`;else if(v!==null)g=`Child wedged \u2014 ${w} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon did not SIGTERM the broker because its PID identity cannot be confirmed alive.`;else{T=!0;try{this.signal(t.pid,"SIGTERM"),$=!0,g=`Child wedged \u2014 ${w} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon sent SIGTERM to the broker and will resume a cleanly aborted session with a continuation, or start a recovery cycle if the abort cannot settle.`}catch(E){f({level:"error",event:"broker.wedge.signal_failed",...u(n)?{node_id:n}:{},error:E,fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,signal:"SIGTERM"}}),g=`Child wedged \u2014 ${w} (${n}) is alive and mid-turn but has shown NO engine progress for ${S}+ minutes and it has no subprocess to kill (the engine itself stalled). The daemon attempted SIGTERM to the broker, but the signal call failed.`}}f({level:"error",event:"broker.wedge.detected",...u(n)?{node_id:n}:{},fields:{...u(n)?{}:{affected_node_id:n},pid:t.pid,quiet_ms:d,cpu_percent:h,has_descendants:M,kick_attempted:T,kicked:$,...v===null?{}:{kick_suppression_reason:v}}});try{Z(n,{link:"daemon\u2192node",op:"engine wedge",kind:"wedged",retry:{disposition:"manual"},message:g})}catch(E){f({level:"error",event:"broker.wedge.fault_record_failed",...u(n)?{node_id:n}:{fields:{affected_node_id:n}},error:E})}W(n,x(n),g,{reason:"child-wedged",child:n,quiet_ms:d,cpu_percent:h,kick_attempted:T,kicked:$,...v===null?{}:{kick_suppression_reason:v}})}handleFatalFault(e){const t=L(e);if(t===null){this.fatalFaultNotifiedAt.delete(e);return}if(t.retry.disposition!=="fatal"||t.link!=="pi\u2192provider"||this.fatalFaultNotifiedAt.get(e)===t.since)return;const a=A(e),i=a!==null?O(a):e,n=t.kind==="auth",o=(t.message.split(`
|
|
4
|
+
`)[0]??"").slice(0,200),r=t.providerError,d=r===void 0?"":` Provider: ${r.provider}/${r.model}.`+(r.status===void 0?"":` HTTP status: ${r.status}.`)+(r.errno===void 0?"":` Errno: ${r.errno}.`)+(r.code===void 0?"":` Code: ${r.code}.`)+(r.body===void 0?"":` Body: ${r.body.slice(0,200)}.`),c=t.kind==="context-overflow",l=a?.parent==null&&a?.lifecycle==="terminal",m=c||l,h=c?`Child failed \u2014 ${i} (${e}) exceeded its model context window and is now dead. Shrink the task or loaded context, or choose a larger-context model before spawning it again. Error: ${o}`:`Child hit a fatal provider fault \u2014 ${i} (${e}) got a non-retryable ${t.kind} error and will NOT recover on its own; `+(l?"its terminal run has failed. ":"it stays alive, and waking it clears the fault as soon as one turn completes \u2014 a wake that hits the same cause fails again. "+(n?"Its provider credential is dead \u2014 re-authenticate (`/login`, or re-auth crtr); the child recovers on its next wake once the auth reloads. ":""))+`Error: ${o}.${d}`;m&&(X(e,"crash",{reason:c?"context_overflow":"provider_fatal",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:t.message,fault_kind:t.kind,error_class:ee(t).class}}}),y.teardown(e).then(_=>{_.confirmed||f({level:"error",event:"fault.fatal.teardown_failed",node_id:e,error:_.error??new Error("Broker teardown not confirmed")})},_=>f({level:"error",event:"fault.fatal.teardown_failed",node_id:e,error:_}))),this.fatalFaultNotifiedAt.set(e,t.since),f({level:"error",event:"fault.fatal.fanout",...u(e)?{node_id:e}:{},fields:{...u(e)?{}:{affected_node_id:e},kind:t.kind,link:t.link,terminal_overflow:c,terminal_provider_fault:l}}),W(e,x(e),h,{reason:c?"child-context-overflow":"child-fault-fatal",child:e,kind:t.kind,message:o,...r===void 0?{}:{provider_error:r}})}async handleAuthReload(e){const t=De();let a=0;for(const r of Ie(t))try{a=Math.max(a,V(r).mtimeMs)}catch{}let i=0;const n=he(t);me(n)&&(i=_e(t));const o=`${a}:${i}`;if(this.knownCredentialRevision===null){this.knownCredentialRevision=o;return}o!==this.knownCredentialRevision&&(this.knownCredentialRevision=o,await R.fresh(async()=>{try{const r=Array.from(e.entries(),([l])=>l);if(r.length===0)return;const c=(await Promise.allSettled(r.map(async l=>{try{await ne(l)}catch(m){throw f({level:"error",event:"auth.reload.broker_failed",...u(l)?{node_id:l}:{fields:{broker_id:l}},error:m}),m}}))).filter(l=>l.status==="fulfilled").length;f({level:"info",event:"auth.reload.completed",outcome:c===r.length?"succeeded":"failed",fields:{broker_count:r.length,succeeded_count:c,failed_count:r.length-c}})}catch(r){f({level:"error",event:"auth.reload.failed",error:r})}}))}}export{vt as BrokerSupervisionReconciler,Me as WEDGE_CPU_MAX_PERCENT,D as WEDGE_QUIET_MS,U as YIELD_STALL_GRACE_MS,Y as parkSummaryGraceMsForDaemon,Re as sumTreeCpu,Fe as treeHasDescendants,$e as unattendedParkMsForDaemon,Ce as wedgeVerdict,Ee as yieldStallVerdict};
|
package/package.json
CHANGED
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.345",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/crouter",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.345",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "GPL-3.0-only",
|
|
12
12
|
"workspaces": [
|
|
@@ -10859,28 +10859,28 @@
|
|
|
10859
10859
|
},
|
|
10860
10860
|
"packages/crouter-api": {
|
|
10861
10861
|
"name": "@north-light/crouter-api",
|
|
10862
|
-
"version": "0.3.
|
|
10862
|
+
"version": "0.3.345",
|
|
10863
10863
|
"license": "GPL-3.0-only"
|
|
10864
10864
|
},
|
|
10865
10865
|
"packages/crouter-env-docker": {
|
|
10866
10866
|
"name": "@north-light/crouter-env-docker",
|
|
10867
|
-
"version": "0.3.
|
|
10867
|
+
"version": "0.3.345",
|
|
10868
10868
|
"license": "GPL-3.0-only"
|
|
10869
10869
|
},
|
|
10870
10870
|
"packages/crouter-plugin": {
|
|
10871
10871
|
"name": "@north-light/crouter-plugin",
|
|
10872
|
-
"version": "0.3.
|
|
10872
|
+
"version": "0.3.345",
|
|
10873
10873
|
"license": "GPL-3.0-only",
|
|
10874
10874
|
"dependencies": {
|
|
10875
|
-
"@north-light/crouter-api": "^0.3.
|
|
10875
|
+
"@north-light/crouter-api": "^0.3.345"
|
|
10876
10876
|
}
|
|
10877
10877
|
},
|
|
10878
10878
|
"packages/crouter-sdk": {
|
|
10879
10879
|
"name": "@north-light/crouter-sdk",
|
|
10880
|
-
"version": "0.3.
|
|
10880
|
+
"version": "0.3.345",
|
|
10881
10881
|
"license": "GPL-3.0-only",
|
|
10882
10882
|
"dependencies": {
|
|
10883
|
-
"@north-light/crouter-api": "^0.3.
|
|
10883
|
+
"@north-light/crouter-api": "^0.3.345"
|
|
10884
10884
|
}
|
|
10885
10885
|
}
|
|
10886
10886
|
}
|