@north-light/crouter 0.3.342 → 0.3.344

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.
@@ -435,7 +435,7 @@ async function streamProviderAttempt(state, providerId, model, context, options,
435
435
  },
436
436
  };
437
437
  const provider = state.runtimeContext?.modelRegistry.getProvider?.(model.provider);
438
- const inner = credential
438
+ const inner = isManagedProvider(providerId)
439
439
  ? streamForProvider(model, context, streamOptions)
440
440
  : state.delegatedProviderStreams.get(providerId)?.(model, context, streamOptions)
441
441
  ?? provider?.streamSimple(model, context, streamOptions)
@@ -598,7 +598,14 @@ async function runManagedProvider(state, model, context, options, stream) {
598
598
  const isLiveRoute = (candidate) => candidate.providerId === model.provider && candidate.model.id === model.id && candidate.thinkingLevel === liveThinking;
599
599
  // A cooling or unauthenticated managed route contributes its diagnostic and may
600
600
  // later re-enter when a credential becomes ready, but it is never selected now.
601
- const candidates = routeCandidates.filter((candidate) => isLiveRoute(candidate) || !isManagedProvider(candidate.providerId) || readSubscriptionPool(candidate.providerId).some((entry) => entry.authFailure === undefined && (entry.rateLimitedUntil || 0) <= Date.now()));
601
+ const candidates = routeCandidates.filter((candidate) => {
602
+ if (isLiveRoute(candidate) || !isManagedProvider(candidate.providerId))
603
+ return true;
604
+ const pool = readSubscriptionPool(candidate.providerId);
605
+ return pool.length === 0
606
+ ? state.runtimeContext.modelRegistry.hasConfiguredAuth(candidate.model)
607
+ : pool.some((entry) => entry.authFailure === undefined && (entry.rateLimitedUntil || 0) <= Date.now());
608
+ });
602
609
  if (!candidates.some(isLiveRoute)) {
603
610
  candidates.unshift({ routeId: `live:${model.provider}/${model.id}`, credentialSource: 'live', rank: liveRank, providerId: model.provider, model, thinkingLevel: liveThinking });
604
611
  }
@@ -625,8 +632,25 @@ async function runManagedProvider(state, model, context, options, stream) {
625
632
  emitTerminalError(stream, candidateModel, `Provider route ${routeId} is unavailable: failed to select ${providerId}/${candidateModel.id}`);
626
633
  return;
627
634
  }
628
- if (!isManagedProvider(providerId)) {
629
- const result = await streamProviderAttempt(state, providerId, candidateModel, context, options, undefined, stream);
635
+ const rawPool = isManagedProvider(providerId) ? readSubscriptionPool(providerId) : [];
636
+ if (!isManagedProvider(providerId) || rawPool.length === 0) {
637
+ const liveKey = isLiveRoute(candidate) ? options?.apiKey : undefined;
638
+ if (isManagedProvider(providerId) && !liveKey && !state.runtimeContext.modelRegistry.hasConfiguredAuth(candidateModel))
639
+ continue;
640
+ const auth = isManagedProvider(providerId) && !liveKey
641
+ ? await state.runtimeContext.modelRegistry.getApiKeyAndHeaders(candidateModel)
642
+ : undefined;
643
+ if (isManagedProvider(providerId) && !liveKey && (!auth?.ok || !auth.apiKey))
644
+ continue;
645
+ const headers = { ...options?.headers };
646
+ for (const [name, value] of Object.entries(auth?.ok ? auth.headers ?? {} : {})) {
647
+ for (const existing of Object.keys(headers))
648
+ if (existing.toLowerCase() === name.toLowerCase())
649
+ delete headers[existing];
650
+ headers[name] = value;
651
+ }
652
+ const attemptOptions = auth?.ok ? { ...options, apiKey: auth.apiKey, headers } : options;
653
+ const result = await streamProviderAttempt(state, providerId, candidateModel, context, attemptOptions, undefined, stream);
630
654
  if (result.result === 'success' || result.result === 'fatal') {
631
655
  state.transportOnlyExhaustedPasses = 0;
632
656
  stream.end();
@@ -641,7 +665,6 @@ async function runManagedProvider(state, model, context, options, stream) {
641
665
  logRouteQueueAdvance(candidate, candidates[0], result);
642
666
  continue;
643
667
  }
644
- const rawPool = readSubscriptionPool(providerId);
645
668
  for (const entry of rawPool)
646
669
  if (entry.authFailure === 'invalid_grant')
647
670
  authFailures.add(`${providerId}/${entry.label}`);
@@ -600,7 +600,7 @@ async function streamProviderAttempt(
600
600
  },
601
601
  };
602
602
  const provider = state.runtimeContext?.modelRegistry.getProvider?.(model.provider);
603
- const inner = credential
603
+ const inner = isManagedProvider(providerId)
604
604
  ? streamForProvider(model, context, streamOptions)
605
605
  : state.delegatedProviderStreams.get(providerId)?.(model, context, streamOptions)
606
606
  ?? provider?.streamSimple(model, context, streamOptions)
@@ -802,7 +802,13 @@ async function runManagedProvider(
802
802
  candidate.providerId === model.provider && candidate.model.id === model.id && candidate.thinkingLevel === liveThinking;
803
803
  // A cooling or unauthenticated managed route contributes its diagnostic and may
804
804
  // later re-enter when a credential becomes ready, but it is never selected now.
805
- const candidates = routeCandidates.filter((candidate) => isLiveRoute(candidate) || !isManagedProvider(candidate.providerId) || readSubscriptionPool(candidate.providerId).some((entry) => entry.authFailure === undefined && (entry.rateLimitedUntil || 0) <= Date.now()));
805
+ const candidates = routeCandidates.filter((candidate) => {
806
+ if (isLiveRoute(candidate) || !isManagedProvider(candidate.providerId)) return true;
807
+ const pool = readSubscriptionPool(candidate.providerId);
808
+ return pool.length === 0
809
+ ? state.runtimeContext!.modelRegistry.hasConfiguredAuth(candidate.model)
810
+ : pool.some((entry) => entry.authFailure === undefined && (entry.rateLimitedUntil || 0) <= Date.now());
811
+ });
806
812
  if (!candidates.some(isLiveRoute)) {
807
813
  candidates.unshift({ routeId: `live:${model.provider}/${model.id}`, credentialSource: 'live', rank: liveRank, providerId: model.provider, model, thinkingLevel: liveThinking });
808
814
  }
@@ -833,8 +839,21 @@ async function runManagedProvider(
833
839
  return;
834
840
  }
835
841
 
836
- if (!isManagedProvider(providerId)) {
837
- const result = await streamProviderAttempt(state, providerId, candidateModel, context, options, undefined, stream);
842
+ const rawPool = isManagedProvider(providerId) ? readSubscriptionPool(providerId) : [];
843
+ if (!isManagedProvider(providerId) || rawPool.length === 0) {
844
+ const liveKey = isLiveRoute(candidate) ? options?.apiKey : undefined;
845
+ if (isManagedProvider(providerId) && !liveKey && !state.runtimeContext!.modelRegistry.hasConfiguredAuth(candidateModel)) continue;
846
+ const auth = isManagedProvider(providerId) && !liveKey
847
+ ? await state.runtimeContext!.modelRegistry.getApiKeyAndHeaders(candidateModel)
848
+ : undefined;
849
+ if (isManagedProvider(providerId) && !liveKey && (!auth?.ok || !auth.apiKey)) continue;
850
+ const headers = { ...options?.headers };
851
+ for (const [name, value] of Object.entries(auth?.ok ? auth.headers ?? {} : {})) {
852
+ for (const existing of Object.keys(headers)) if (existing.toLowerCase() === name.toLowerCase()) delete headers[existing];
853
+ headers[name] = value;
854
+ }
855
+ const attemptOptions = auth?.ok ? { ...options, apiKey: auth.apiKey, headers } : options;
856
+ const result = await streamProviderAttempt(state, providerId, candidateModel, context, attemptOptions, undefined, stream);
838
857
  if (result.result === 'success' || result.result === 'fatal') { state.transportOnlyExhaustedPasses = 0; stream.end(); return; }
839
858
  if (result.result === 'rate_limited' || result.classification?.status !== undefined || result.classification?.hadRetryAfterHeader === true) sawHttpEvidence = true;
840
859
  const cooldownMs = result.result === 'rate_limited' ? result.retryAfterMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS : TRANSIENT_ROTATE_COOLDOWN_MS;
@@ -843,8 +862,6 @@ async function runManagedProvider(
843
862
  logRouteQueueAdvance(candidate, candidates[0], result);
844
863
  continue;
845
864
  }
846
-
847
- const rawPool = readSubscriptionPool(providerId);
848
865
  for (const entry of rawPool) if (entry.authFailure === 'invalid_grant') authFailures.add(`${providerId}/${entry.label}`);
849
866
  const available = rawPool.filter((entry) => entry.authFailure === undefined && (!entry.rateLimitedUntil || entry.rateLimitedUntil <= Date.now()));
850
867
  const seenLabels = seenReadyLabels.get(routeId) ?? new Set<string>();
@@ -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
- `}a(Ze,"renderSetupStaticInstructions");class v extends Error{static{a(this,"SetupCommandError")}output;constructor(t,n){super(t),this.output=n}}function et(e){return`${e.stdout?.toString()??""}${e.stderr?.toString()??""}`}a(et,"commandOutput");function M(e,t,n){return new Promise((r,o)=>{const i=W(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 v(`${e} failed: ${c.message}`,u))),i.on("close",c=>{c===0?r():o(new v(`${e} failed with status ${c??"unknown"}`,u))})})}a(M,"runCapturedCommand");function x(e,t){return M("sh",["-lc",e],t)}a(x,"runShellCommand");function Ce(e,t=ie()){return M(process.execPath,[t,"install",e])}a(Ce,"installPiPackage");async function K(){m("capture")||await x("npm install -g @crouton-kit/capture")}a(K,"installCaptureCliIfMissing");function F(e){return e instanceof v?e.output:void 0}a(F,"capturedFailureOutput");function Se(e){const n=F(e)?.split(/\r?\n/).find(r=>r.trim()!=="");return n!==void 0?n.trim():e instanceof Error?e.message:String(e)}a(Se,"firstFailureLine");function Ae(e){const t=F(e);t===void 0||t.length===0||process.stderr.write(t.endsWith(`
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
- `)}a(Ae,"printCapturedFailure");class $e{static{a(this,"SetupProgress")}interactive;bar=null;constructor(t=!!process.stdout.isTTY){this.interactive=t}start(t){return this.interactive?(this.bar=he(`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 ${Se(n)}
7
- `),Ae(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 j(e,t){return A()?"current":(e?.(),fe(t),A()?"provisioned":"unavailable")}a(j,"ensureManagedRenderer");async function Ee(){try{ae()}catch{}}a(Ee,"reconcileInboxFrontDoor");function B(e,t){return t.length===0?[`${e}: none`]:[`${e}:`,...t.map(n=>` - ${n}`)]}a(B,"summarySection");function tt(e){return["crtr sys setup complete",...B("installed",e.installed),...B("skipped",e.skipped),"New to crouter? Ask for the tutorial in your first conversation, or run /tutorial any time."].join(`
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
- `}a(tt,"formatSetupExecutionSummary");function G(e,t){const n=[];for(const r of e)try{r.sourceKind==="marketplace-source"?E(r.name,t)!==null&&n.push(r.id):r.sourceKind==="marketplace-plugin"&&ge(r.name,t)!==null&&n.push(r.id)}catch{}return n}a(G,"detectInstalledMarketplaceEntries");function Re(e,t="user"){if(E(e,t)!==null)return null;if(e!==R)throw new Error(`marketplace not registered: ${e}`);return $({url:D,ref:O,scope:t}),e}a(Re,"ensureMarketplaceRegistered");async function U(e){if(e.sourceKind==="marketplace-source")return $({url:e.installSource,ref:O,scope:"user"}),[e.name];if(e.sourceKind==="marketplace-plugin"){const[t,n]=e.installSource.split("/"),r=Re(t);return await me({marketplace:t,plugin:n},"user"),e.id==="capture-plugin"&&await K(),r===null?[e.name]:[r,e.name]}return await Ce(e.installSource),[e.name]}a(U,"installSetupPackage");async function nt(e){const t=P(b),n=L(re(_()),t);for(const i of G(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 U(u)}catch(c){e(u.name,c)}}try{j(void 0,()=>{})==="unavailable"&&e("termrender renderer",new Error("unavailable \u2014 install uv"))}catch(i){e("termrender renderer",i)}return se()}a(nt,"reconcileFirstRun");async function rt(e){const t=[],n=[],r=[],o=[],i=new $e;for(const s of e.packages){if(e.installedPackageIds.has(s.id)){if(n.push(`${s.name} (already installed)`),s.id==="capture-plugin"&&!m("capture"))try{await i.run("Capture CLI",()=>K()),t.push("Capture CLI")}catch(d){n.push(`Capture CLI (${d instanceof Error?d.message:String(d)})`)}continue}try{t.push(...await i.run(s.name,()=>U(s)))}catch(d){if(s.sourceKind!=="marketplace-source"&&s.sourceKind!=="marketplace-plugin")throw d;n.push(`${s.name} (${d instanceof Error?d.message:String(d)})`)}}for(const s of e.systemDeps){if(s.installed){o.push(`${s.tool} (already installed)`);continue}if(!s.autoInstall||!s.command){o.push(`${s.tool} (${s.hint})`);continue}const d=s.command,p=d===de;await i.run(s.tool,f=>{if(!p||f===null)return x(d);const Y=le();return x(d,z=>{const C=Y(z);C!==null&&f.setFraction(C/100)})}),r.push(s.tool)}const u=[];let c=!1,l;try{l=j(()=>{c=!0,i.start("termrender renderer")},s=>u.push(s))}catch(s){throw c&&await i.fail("termrender renderer",s),s}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 s=new v("unavailable \u2014 install uv",u.join(""));c&&await i.fail("termrender renderer",s),n.push("termrender renderer (unavailable \u2014 install uv)");break}}return await Ee(),{installed:[...t,...r],skipped:[...n,...o]}}a(rt,"executeSetupSubmission");export{R as OFFICIAL_MARKETPLACE_NAME,O as OFFICIAL_MARKETPLACE_REF,D as OFFICIAL_MARKETPLACE_URL,Je as SetupKeybindingsDraft,Qe as buildSetupInitialState,P as buildSetupManifest,xe as buildSystemInstallPlan,m as detectCommandOnPath,L as detectInstalledSetupPackageIds,Ie as detectPackageManager,rt as executeSetupSubmission,tt as formatSetupExecutionSummary,N as normalizePackageIdentity,Xe as packagePlanAction,nt as reconcileFirstRun,Ee as reconcileInboxFrontDoor,Ze as renderSetupStaticInstructions,_ as resolveSettingsPath};
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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.342",
3
+ "version": "0.3.344",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.342",
3
+ "version": "0.3.344",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.342",
9
+ "version": "0.3.344",
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.342",
10862
+ "version": "0.3.344",
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.342",
10867
+ "version": "0.3.344",
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.342",
10872
+ "version": "0.3.344",
10873
10873
  "license": "GPL-3.0-only",
10874
10874
  "dependencies": {
10875
- "@north-light/crouter-api": "^0.3.342"
10875
+ "@north-light/crouter-api": "^0.3.344"
10876
10876
  }
10877
10877
  },
10878
10878
  "packages/crouter-sdk": {
10879
10879
  "name": "@north-light/crouter-sdk",
10880
- "version": "0.3.342",
10880
+ "version": "0.3.344",
10881
10881
  "license": "GPL-3.0-only",
10882
10882
  "dependencies": {
10883
- "@north-light/crouter-api": "^0.3.342"
10883
+ "@north-light/crouter-api": "^0.3.344"
10884
10884
  }
10885
10885
  }
10886
10886
  }