@ashlr/hub 3.5.1 → 3.8.0
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/CHANGELOG.md +165 -0
- package/README.md +3 -0
- package/dist/build-identity.json +2 -2
- package/dist/cli/activation.d.ts +41 -0
- package/dist/cli/activation.js +485 -0
- package/dist/cli/activation.js.map +1 -0
- package/dist/core/daemon/cutoff-checkpoint-scheduler.js +7 -0
- package/dist/core/daemon/cutoff-checkpoint-scheduler.js.map +1 -1
- package/dist/core/daemon/loop.d.ts +19 -0
- package/dist/core/daemon/loop.js +235 -5
- package/dist/core/daemon/loop.js.map +1 -1
- package/dist/core/daemon/overnight-status.d.ts +152 -0
- package/dist/core/daemon/overnight-status.js +275 -0
- package/dist/core/daemon/overnight-status.js.map +1 -0
- package/dist/core/daemon/post-merge-halt.d.ts +212 -0
- package/dist/core/daemon/post-merge-halt.js +503 -0
- package/dist/core/daemon/post-merge-halt.js.map +1 -0
- package/dist/core/daemon/run-window.d.ts +218 -0
- package/dist/core/daemon/run-window.js +420 -0
- package/dist/core/daemon/run-window.js.map +1 -0
- package/dist/core/fleet/generated-repair-resolution.d.ts +36 -0
- package/dist/core/fleet/generated-repair-resolution.js +245 -0
- package/dist/core/fleet/generated-repair-resolution.js.map +1 -0
- package/dist/core/local-runtime/llama/port.d.ts +17 -0
- package/dist/core/local-runtime/llama/port.js +47 -0
- package/dist/core/local-runtime/llama/port.js.map +1 -0
- package/dist/core/local-runtime/llama/proxy-host.d.ts +54 -0
- package/dist/core/local-runtime/llama/proxy-host.js +159 -0
- package/dist/core/local-runtime/llama/proxy-host.js.map +1 -0
- package/dist/core/local-runtime/llama/proxy-process.d.ts +148 -0
- package/dist/core/local-runtime/llama/proxy-process.js +250 -0
- package/dist/core/local-runtime/llama/proxy-process.js.map +1 -0
- package/dist/core/local-runtime/llama/proxy-record.d.ts +40 -0
- package/dist/core/local-runtime/llama/proxy-record.js +133 -0
- package/dist/core/local-runtime/llama/proxy-record.js.map +1 -0
- package/dist/core/local-runtime/llama/proxy-supervisor.d.ts +118 -0
- package/dist/core/local-runtime/llama/proxy-supervisor.js +511 -0
- package/dist/core/local-runtime/llama/proxy-supervisor.js.map +1 -0
- package/dist/core/policy/local-only.d.ts +142 -2
- package/dist/core/policy/local-only.js +204 -15
- package/dist/core/policy/local-only.js.map +1 -1
- package/dist/core/run/budget.d.ts +22 -8
- package/dist/core/run/budget.js +80 -12
- package/dist/core/run/budget.js.map +1 -1
- package/dist/core/run/sandboxed-engine.js +3 -3
- package/dist/core/run/sandboxed-engine.js.map +1 -1
- package/dist/core/universe/builtins/preparation/manifest.json +1 -1
- package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +61 -9
- package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +60 -8
- package/dist/core/verse/session-engine.d.ts +42 -1
- package/dist/core/verse/session-engine.js +79 -2
- package/dist/core/verse/session-engine.js.map +1 -1
- package/dist/core/web/public/next/assets/{App-BbVoUCIi.js → App-BsbJFA2j.js} +2 -2
- package/dist/core/web/public/next/assets/{App-BbVoUCIi.js.map → App-BsbJFA2j.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ApprovalsSection-BW9iVjUa.js → ApprovalsSection-2CCSoBTJ.js} +2 -2
- package/dist/core/web/public/next/assets/{ApprovalsSection-BW9iVjUa.js.map → ApprovalsSection-2CCSoBTJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{AutonomySection-Cpk_oEhc.css → AutonomySection-CHjxJt2z.css} +1 -1
- package/dist/core/web/public/next/assets/AutonomySection-yeNNUPur.js +2 -0
- package/dist/core/web/public/next/assets/AutonomySection-yeNNUPur.js.map +1 -0
- package/dist/core/web/public/next/assets/ChatSection-BfnLe5dT.css +1 -0
- package/dist/core/web/public/next/assets/ChatSection-DwDDnCZQ.js +80 -0
- package/dist/core/web/public/next/assets/ChatSection-DwDDnCZQ.js.map +1 -0
- package/dist/core/web/public/next/assets/{ConfirmDialog-CXevY3Au.js → ConfirmDialog-C363ty_c.js} +2 -2
- package/dist/core/web/public/next/assets/{ConfirmDialog-CXevY3Au.js.map → ConfirmDialog-C363ty_c.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Dialog-Bn0CgEGz.js → Dialog-nK15L1M0.js} +2 -2
- package/dist/core/web/public/next/assets/{Dialog-Bn0CgEGz.js.map → Dialog-nK15L1M0.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DiffViewer-QKyisN2L.js → DiffViewer-D369eZe8.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffViewer-QKyisN2L.js.map → DiffViewer-D369eZe8.js.map} +1 -1
- package/dist/core/web/public/next/assets/McpSection-D88QlDpG.css +1 -0
- package/dist/core/web/public/next/assets/McpSection-DVgiSYG1.js +2 -0
- package/dist/core/web/public/next/assets/McpSection-DVgiSYG1.js.map +1 -0
- package/dist/core/web/public/next/assets/Meter-CLcr-4wS.css +1 -0
- package/dist/core/web/public/next/assets/Meter-Cmo1pLbk.js +2 -0
- package/dist/core/web/public/next/assets/Meter-Cmo1pLbk.js.map +1 -0
- package/dist/core/web/public/next/assets/{MutationTokenDialog-DbSHPy3w.js → MutationTokenDialog-B9I4PAcp.js} +2 -2
- package/dist/core/web/public/next/assets/{MutationTokenDialog-DbSHPy3w.js.map → MutationTokenDialog-B9I4PAcp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-C-PCgCzo.js → ResourcePoolConsoleApp-z6tJj3s9.js} +2 -2
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-C-PCgCzo.js.map → ResourcePoolConsoleApp-z6tJj3s9.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-Dw8ZjmkS.js → RouteErrorBoundary-OSajL45F.js} +2 -2
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-Dw8ZjmkS.js.map → RouteErrorBoundary-OSajL45F.js.map} +1 -1
- package/dist/core/web/public/next/assets/SettingsSection-B3YH2Npi.js +2 -0
- package/dist/core/web/public/next/assets/SettingsSection-B3YH2Npi.js.map +1 -0
- package/dist/core/web/public/next/assets/{UniverseConsoleApp-Bk5HipM0.js → UniverseConsoleApp-wEKIzl1M.js} +2 -2
- package/dist/core/web/public/next/assets/{UniverseConsoleApp-Bk5HipM0.js.map → UniverseConsoleApp-wEKIzl1M.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UniverseView-D8k9q0ce.js → UniverseView-CQVpJqqI.js} +2 -2
- package/dist/core/web/public/next/assets/{UniverseView-D8k9q0ce.js.map → UniverseView-CQVpJqqI.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UsageSection-B2E06ZH1.js → UsageSection-dToBThXe.js} +2 -2
- package/dist/core/web/public/next/assets/{UsageSection-B2E06ZH1.js.map → UsageSection-dToBThXe.js.map} +1 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-CMkCizvL.css +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-DHU32JCQ.js +3 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-DHU32JCQ.js.map +1 -0
- package/dist/core/web/public/next/assets/{charts-DSUpczxG.js → charts-BopViIha.js} +2 -2
- package/dist/core/web/public/next/assets/{charts-DSUpczxG.js.map → charts-BopViIha.js.map} +1 -1
- package/dist/core/web/public/next/assets/global-DMWakEhP.js +2 -0
- package/dist/core/web/public/next/assets/global-DMWakEhP.js.map +1 -0
- package/dist/core/web/public/next/assets/global-z-JfD3ow.css +1 -0
- package/dist/core/web/public/next/assets/{icons-BxOX8-XB.js → icons-L06pQH6j.js} +2 -2
- package/dist/core/web/public/next/assets/{icons-BxOX8-XB.js.map → icons-L06pQH6j.js.map} +1 -1
- package/dist/core/web/public/next/assets/{index-BMRIET7F.js → index-CXgVQHek.js} +3 -3
- package/dist/core/web/public/next/assets/{index-BMRIET7F.js.map → index-CXgVQHek.js.map} +1 -1
- package/dist/core/web/public/next/assets/{queries-AxnVa02h.js → queries-D3sSlan1.js} +2 -2
- package/dist/core/web/public/next/assets/{queries-AxnVa02h.js.map → queries-D3sSlan1.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-guarded-action-BO6c94Wp.js → use-guarded-action-BxfJ9E-n.js} +2 -2
- package/dist/core/web/public/next/assets/{use-guarded-action-BO6c94Wp.js.map → use-guarded-action-BxfJ9E-n.js.map} +1 -1
- package/dist/core/web/public/next/assets/workspace-model-v0a1gl-C.js +2 -0
- package/dist/core/web/public/next/assets/workspace-model-v0a1gl-C.js.map +1 -0
- package/dist/core/web/public/next/index.html +1 -1
- package/dist/release-dependency-inventory.json +1 -1
- package/package.json +1 -1
- package/dist/core/web/public/next/assets/AutonomySection-CRqHUhED.js +0 -2
- package/dist/core/web/public/next/assets/AutonomySection-CRqHUhED.js.map +0 -1
- package/dist/core/web/public/next/assets/ChatSection-5irrh6Jw.js +0 -80
- package/dist/core/web/public/next/assets/ChatSection-5irrh6Jw.js.map +0 -1
- package/dist/core/web/public/next/assets/ChatSection-LQiAn6Eu.css +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-CWxtTNlD.js +0 -2
- package/dist/core/web/public/next/assets/SettingsSection-CWxtTNlD.js.map +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-CRfZUV-T.js +0 -3
- package/dist/core/web/public/next/assets/VerseConsoleApp-CRfZUV-T.js.map +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-D2E3mU9a.css +0 -1
- package/dist/core/web/public/next/assets/global-C4jfYHrj.js +0 -2
- package/dist/core/web/public/next/assets/global-C4jfYHrj.js.map +0 -1
- package/dist/core/web/public/next/assets/global-D463gG1X.css +0 -1
- package/dist/core/web/public/next/assets/workspace-model-cE4LkKpE.js +0 -2
- package/dist/core/web/public/next/assets/workspace-model-cE4LkKpE.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{l as e}from"./global-
|
|
2
|
-
//# sourceMappingURL=queries-
|
|
1
|
+
import{l as e}from"./global-DMWakEhP.js";var t={key:`dashboard-snapshot`,fetch:t=>e(`/api/snapshot`,t)},n={key:`control-snapshot`,fetch:t=>e(`/api/control`,t)},r={key:`agent-os-snapshot`,fetch:t=>e(`/api/agent-os`,t)},i={key:`universe-overview`,fetch:t=>e(`/api/universe`,t)};function a(t){return{key:`universe-graph-${t}`,fetch:n=>e(`/api/universe/graph?universeId=${encodeURIComponent(t)}`,n)}}var o={key:`runs`,fetch:t=>e(`/api/runs`,t)};function s(t){return{key:`run-detail-${t}`,fetch:n=>e(`/api/run/${encodeURIComponent(t)}`,n)}}var c={key:`swarms`,fetch:t=>e(`/api/swarms`,t)};function l(t){return{key:`swarm-detail-${t}`,fetch:n=>e(`/api/swarm/${encodeURIComponent(t)}`,n)}}var u={key:`daemon`,fetch:t=>e(`/api/daemon-observation`,t)},d={key:`fleet`,fetch:t=>e(`/api/fleet`,t)},f={key:`fleet-activity`,fetch:t=>e(`/api/fleet-activity`,t)},p={key:`goals`,fetch:t=>e(`/api/goals`,t)},m={key:`vision-mission`,fetch:t=>e(`/api/vision/mission`,t)},h={key:`inbox`,fetch:t=>e(`/api/inbox`,t)};function g(t={}){let n=new URLSearchParams;t.status!==void 0&&n.set(`status`,t.status),t.since!==void 0&&n.set(`since`,t.since),t.limit!==void 0&&n.set(`limit`,String(t.limit));let r=n.toString();return{key:`inbox-list:${t.status??`pending`}:${t.since??``}:${t.limit??``}`,fetch:t=>e(`/api/inbox${r?`?${r}`:``}`,t)}}function _(t){return{key:`proposal-detail-${t}`,fetch:n=>e(`/api/inbox/${encodeURIComponent(t)}`,n)}}var v={key:`control-logs-observation`,fetch:t=>e(`/api/logs-observation?tail=200`,t)};function y(t){return{key:`pulse-${t}`,fetch:n=>e(`/api/pulse?window=${t}`,n)}}function b(e){return typeof e==`object`&&!!e&&`entry`in e&&`score`in e}function x(t){let n=t.trim();return{key:n?`genome-search-${n}`:`genome-list`,fetch:t=>e(n?`/api/genome?q=${encodeURIComponent(n)}`:`/api/genome`,t)}}function S(t){return{key:`models-${t}`,fetch:n=>e(`/api/models?window=${t}`,n)}}var C={key:`portfolio`,fetch:t=>e(`/api/portfolio`,t)};export{m as C,i as S,s as _,t as a,c as b,x as c,h as d,b as f,y as g,_ as h,u as i,p as l,C as m,v as n,f as o,S as p,n as r,d as s,r as t,g as u,o as v,a as x,l as y};
|
|
2
|
+
//# sourceMappingURL=queries-D3sSlan1.js.map
|
package/dist/core/web/public/next/assets/{queries-AxnVa02h.js.map → queries-D3sSlan1.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries-AxnVa02h.js","names":[],"sources":["../../../../../../src/web-ui/data/queries.ts"],"sourcesContent":["/**\n * data/queries.ts — one typed accessor per backend resource. Each pairs a\n * stable cache key (also the SSE invalidation target — see sse.ts's\n * EVENT_TO_CACHE_KEYS) with the exact GET call and response type. Views\n * never call apiGet directly; they call these through useQuery (hooks.ts)\n * so caching, de-dupe, and SSE-driven refresh are automatic.\n */\nimport { apiGet } from './client.js';\nimport type { UniverseGraph } from '../../core/universe/graph-types.js';\nimport type {\n AgentOsSnapshotResponse,\n UniverseOverview,\n ControlLogEntry,\n ControlSnapshot,\n DashboardSnapshot,\n DecisionEntry,\n FleetActivitySnapshot,\n FleetStatus,\n Proposal,\n ProposalStatus,\n PublicDaemonObservation,\n RunState,\n SwarmRun,\n ActivityRollup,\n GenomeEntry,\n RecallHit,\n PortfolioSummary,\n ModelStatsReadResult,\n} from './api-types.js';\nimport type { SourceQuality } from './api-types.js';\n\nexport interface QueryDef<T> {\n key: string;\n fetch: (signal?: AbortSignal) => Promise<T>;\n}\n\nexport const dashboardSnapshotQuery: QueryDef<DashboardSnapshot> = {\n key: 'dashboard-snapshot',\n fetch: (signal) => apiGet<DashboardSnapshot>('/api/snapshot', signal),\n};\n\nexport const controlSnapshotQuery: QueryDef<ControlSnapshot> = {\n key: 'control-snapshot',\n fetch: (signal) => apiGet<ControlSnapshot>('/api/control', signal),\n};\n\nexport const agentOsSnapshotQuery: QueryDef<AgentOsSnapshotResponse> = {\n key: 'agent-os-snapshot',\n fetch: (signal) => apiGet<AgentOsSnapshotResponse>('/api/agent-os', signal),\n};\n\nexport const universeOverviewQuery: QueryDef<UniverseOverview> = {\n key: 'universe-overview',\n fetch: (signal) => apiGet<UniverseOverview>('/api/universe', signal),\n};\n\n/** Read only on demand; never invalidate this alongside the overview poll. */\nexport function universeGraphQuery(universeId: string): QueryDef<UniverseGraph> {\n return {\n key: `universe-graph-${universeId}`,\n fetch: (signal) => apiGet<UniverseGraph>(`/api/universe/graph?universeId=${encodeURIComponent(universeId)}`, signal),\n };\n}\n\n// NOTE: there is no standalone GET /api/visibility route — VisibilitySnapshot\n// is an optional field on DashboardSnapshot (`.visibility`), populated by\n// buildSnapshot() server-side. Read it off dashboardSnapshotQuery's data\n// rather than issuing a second request for it.\n\n/**\n * GET /api/runs returns the bare array (see src/core/web/api.ts:1121-1125,\n * `listRuns({limit:200})` -> `RunState[]`) — NOT `{runs: [...]}`. The prior\n * `RunSummary`/`runsQuery` pair here was speculative and didn't match the\n * real response shape; it was unused (FleetDashboardView reads its compact\n * run summaries off `DashboardSnapshot['runs']` instead, a different,\n * deliberately-thin shape). Replaced with the real, fully-typed contract.\n */\nexport const runsQuery: QueryDef<RunState[]> = {\n key: 'runs',\n fetch: (signal) => apiGet<RunState[]>('/api/runs', signal),\n};\n\nexport function runDetailQuery(id: string): QueryDef<RunState> {\n return {\n key: `run-detail-${id}`,\n fetch: (signal) => apiGet<RunState>(`/api/run/${encodeURIComponent(id)}`, signal),\n };\n}\n\nexport const swarmsQuery: QueryDef<SwarmRun[]> = {\n key: 'swarms',\n fetch: (signal) => apiGet<SwarmRun[]>('/api/swarms', signal),\n};\n\nexport function swarmDetailQuery(id: string): QueryDef<SwarmRun> {\n return {\n key: `swarm-detail-${id}`,\n fetch: (signal) => apiGet<SwarmRun>(`/api/swarm/${encodeURIComponent(id)}`, signal),\n };\n}\n\n/**\n * Same PublicDaemonObservation the backend embeds at ControlSnapshot.daemonObservation\n * — fetched standalone here because /control/daemon renders a fuller detail page\n * than DaemonPanel's dashboard-compact view and wants the raw observation\n * (including `ticks`) independent of whether the rest of /api/control succeeds.\n * Cache key 'daemon' deliberately matches sse.ts's existing (previously orphaned)\n * `daemon` / `daemon-observation` -> ['daemon'] mapping so this now actually\n * live-updates.\n */\nexport const daemonObservationQuery: QueryDef<PublicDaemonObservation> = {\n key: 'daemon',\n fetch: (signal) => apiGet<PublicDaemonObservation>('/api/daemon-observation', signal),\n};\n\nexport const fleetStatusQuery: QueryDef<FleetStatus> = {\n key: 'fleet',\n fetch: (signal) => apiGet<FleetStatus>('/api/fleet', signal),\n};\n\nexport const fleetActivityQuery: QueryDef<FleetActivitySnapshot> = {\n key: 'fleet-activity',\n fetch: (signal) => apiGet<FleetActivitySnapshot>('/api/fleet-activity', signal),\n};\n\n/**\n * GET /api/goals returns a bare array of ad-hoc per-goal projections built\n * inline in src/core/web/api.ts (`path === '/api/goals'`, ~line 1654) — there\n * is no exported backend type for this shape (unlike every other resource\n * here), so this interface is hand-written to match that handler exactly\n * rather than re-exported. Keep it in sync with api.ts if that handler's\n * shape changes.\n */\nexport interface GoalMilestoneSummary {\n title: string;\n status: string;\n order: number;\n}\n\nexport interface GoalSummary {\n id: string;\n objective: string;\n status: string;\n milestones: GoalMilestoneSummary[];\n progress: {\n fractionDone: number;\n counts: Record<string, number>;\n nextActionableId: string | null;\n };\n}\n\nexport const goalsQuery: QueryDef<GoalSummary[]> = {\n key: 'goals',\n fetch: (signal) => apiGet<GoalSummary[]>('/api/goals', signal),\n};\n\n/**\n * GET /api/vision/mission — buildVisionMissionSnapshot() in src/core/web/api.ts\n * is itself typed `Promise<Record<string, unknown>>` on the backend (no\n * exported interface to import), so this is a narrow hand-written contract\n * covering only the fields the Goals view actually reads: top-level `state`\n * (mirrors the SourceQuality.sourceState vocabulary) and the per-source\n * epistemic breakdown under `sources`. `briefing`/`preview`/`shadow` are\n * deliberately left as `unknown` — the view does not render briefing prose.\n */\nexport interface VisionMissionSourceStatus {\n sourceState: 'healthy' | 'degraded' | 'missing' | 'unknown';\n sourcePresent?: boolean;\n complete: boolean;\n reason?: string;\n}\n\nexport interface VisionMissionSnapshot {\n schemaVersion: number;\n state: string;\n authority: string;\n briefing: unknown;\n sources: {\n briefing: VisionMissionSourceStatus | null;\n goals: VisionMissionSourceStatus | null;\n enrollment: VisionMissionSourceStatus | null;\n proposals: VisionMissionSourceStatus | null;\n };\n}\n\nexport const visionMissionQuery: QueryDef<VisionMissionSnapshot> = {\n key: 'vision-mission',\n fetch: (signal) => apiGet<VisionMissionSnapshot>('/api/vision/mission', signal),\n};\n\nexport interface InboxProposal {\n id: string;\n title: string;\n kind: string;\n repo: string;\n origin: string;\n createdAt: string;\n}\n\nexport const inboxQuery: QueryDef<{ pending: number; proposals: InboxProposal[] }> = {\n key: 'inbox',\n fetch: (signal) => apiGet('/api/inbox', signal),\n};\n\n/**\n * `?status=&since=&limit=` view over GET /api/inbox (src/core/web/api.ts\n * INBOX_STATUS_QUERY_VALUES) — the history surface `inboxQuery` above never\n * had: it's hardcoded pending-only. `status: undefined` = server default\n * (pending); `'all'` = every status. Keyed per filter combo so switching\n * status/since/limit doesn't fight over one cache entry, and so sse.ts can\n * sweep every live combo (`invalidatePrefix('inbox-list:')`) on the 'inbox'\n * SSE event without knowing which combos are mounted.\n */\nexport type InboxHistoryStatus = ProposalStatus | 'all';\n\nexport interface InboxListFilters {\n status?: InboxHistoryStatus;\n /** ISO timestamp or YYYY-MM-DD, passed straight through to the server. */\n since?: string;\n limit?: number;\n}\n\nexport interface InboxListResponse {\n pending: number;\n total: number;\n /**\n * Full `Proposal[]`, not the narrow `InboxProposal` shape above — the\n * server has always sent full sanitized Proposal records here\n * (`listProposals()`); `InboxProposal` just under-typed it for the\n * original pending-badge use case. The history view needs `status` and\n * `decisionReason` per row (triage: \"why was this rejected\") without an\n * N+1 decisions-ledger read per row, and both live directly on Proposal.\n */\n proposals: Proposal[];\n /** True when more rows matched than were returned (hit the server cap). */\n truncated: boolean;\n filters: { status: InboxHistoryStatus; since: string | null; limit: number | null };\n}\n\nexport function inboxListQuery(filters: InboxListFilters = {}): QueryDef<InboxListResponse> {\n const params = new URLSearchParams();\n if (filters.status !== undefined) params.set('status', filters.status);\n if (filters.since !== undefined) params.set('since', filters.since);\n if (filters.limit !== undefined) params.set('limit', String(filters.limit));\n const qs = params.toString();\n return {\n key: `inbox-list:${filters.status ?? 'pending'}:${filters.since ?? ''}:${filters.limit ?? ''}`,\n fetch: (signal) => apiGet<InboxListResponse>(`/api/inbox${qs ? `?${qs}` : ''}`, signal),\n };\n}\n\n/**\n * Evidence behind a judge's verdict for one proposal — joined server-side\n * (src/core/web/api.ts GET /api/inbox/:id) from the decisions ledger, which\n * is the ONLY place `judgeReasonCode` lives (Proposal itself never carries\n * it). `judge-parse-failure`/`judge-network-failure` are infra failures,\n * never a considered `judge-review` — render them distinctly, never folded\n * together. When the ledger read is degraded or no row matches this\n * proposal, `sourceQuality` says so; render \"unknown\" via <Epistemic/>\n * rather than treating an empty `decisions` array as \"never judged\".\n */\nexport interface InboxDecisionEvidence {\n sourceQuality: SourceQuality;\n decisions: DecisionEntry[];\n}\n\n/**\n * GET /api/inbox/:id — full proposal detail including diff/taste/verdict\n * (src/core/web/api.ts:1240-1255, `loadProposal(id)`) plus `decisionEvidence`\n * (readDecisionsDetailed({proposalId}), added alongside the inbox history\n * view). Used by the work journal's \"why did it do that\" drill-in (M416) —\n * `/api/inbox` only ever returns pending proposals, but a decided\n * proposal's id (surfaced via fleet-activity's recentMerges/recentActions,\n * or via inboxListQuery's history view) still resolves here as long as its\n * on-disk record hasn't been pruned.\n */\nexport function proposalDetailQuery(id: string): QueryDef<Proposal & { decisionEvidence: InboxDecisionEvidence }> {\n return {\n key: `proposal-detail-${id}`,\n fetch: (signal) =>\n apiGet<Proposal & { decisionEvidence: InboxDecisionEvidence }>(`/api/inbox/${encodeURIComponent(id)}`, signal),\n };\n}\n\n/**\n * GET /api/logs-observation?tail=200 — the provenance-bearing sibling of\n * GET /api/logs (src/core/web/api.ts:~1543-1560): same daemon tick/merge\n * log, plus `sourceQuality` so a degraded/incomplete log can be rendered\n * honestly via <Epistemic/> instead of silently showing a truncated or\n * stale list as complete. `entries` is `null` when the source itself is not\n * healthy+complete (server-side contract, not a client guess). Used by the\n * work journal (M416) as one of several merged history sources — NOT a\n * substitute for full on-disk history: this is capped at 200 entries\n * server-side and only carries daemon tick/merge/info/dispatch events, not\n * raw run stdout or the ~672 historical proposals living only on disk.\n */\nexport interface ControlLogsObservation {\n entries: ControlLogEntry[] | null;\n sourceQuality: SourceQuality;\n}\n\nexport const controlLogsObservationQuery: QueryDef<ControlLogsObservation> = {\n key: 'control-logs-observation',\n fetch: (signal) => apiGet<ControlLogsObservation>('/api/logs-observation?tail=200', signal),\n};\n\n// ---------------------------------------------------------------------------\n// Intelligence + Portfolio (charts/dataviz work)\n// ---------------------------------------------------------------------------\n\nexport type PulseWindow = '1d' | '7d' | '30d';\n\n/** GET /api/pulse?window= — buildRollup() (src/core/observability/rollup.ts).\n * Parameterized like runDetailQuery/swarmDetailQuery above: a distinct cache\n * key per window so switching windows doesn't fight over one cache entry. */\nexport function pulseQuery(window: PulseWindow): QueryDef<ActivityRollup> {\n return {\n key: `pulse-${window}`,\n fetch: (signal) => apiGet<ActivityRollup>(`/api/pulse?window=${window}`, signal),\n };\n}\n\n/**\n * GET /api/genome[?q=] — src/core/web/api.ts:1189-1201. Two response shapes\n * depending on `q`: empty/absent `q` returns `GenomeEntry[]` (list mode,\n * `loadGenome()`); a non-empty `q` returns `RecallHit[]` (query mode,\n * `recall()`, `{entry, score, method}`). Use `isRecallHit` to discriminate —\n * the view can't know which shape it got from the type alone since both are\n * arrays. Keyed per query string so a debounced search doesn't stomp the\n * browse-mode cache entry.\n */\nexport type GenomeResult = GenomeEntry[] | RecallHit[];\n\nexport function isRecallHit(item: GenomeEntry | RecallHit): item is RecallHit {\n return typeof item === 'object' && item !== null && 'entry' in item && 'score' in item;\n}\n\nexport function genomeQuery(q: string): QueryDef<GenomeResult> {\n const trimmed = q.trim();\n return {\n key: trimmed ? `genome-search-${trimmed}` : 'genome-list',\n fetch: (signal) =>\n apiGet<GenomeResult>(trimmed ? `/api/genome?q=${encodeURIComponent(trimmed)}` : '/api/genome', signal),\n };\n}\n\nexport type ModelStatsWindow = '7d' | '30d' | 'all';\n\n/** GET /api/models?window= — computeModelStatsDetailed() joined per-model\n * economics (src/core/fleet/model-stats.ts). NOTE: a second, dead\n * `/api/models` handler later in api.ts's if-chain (local-model provider\n * probe off ControlSnapshot.models) is unreachable — this one always wins\n * since route matching is first-match. */\nexport function modelsQuery(window: ModelStatsWindow): QueryDef<ModelStatsReadResult & { window: ModelStatsWindow }> {\n return {\n key: `models-${window}`,\n fetch: (signal) => apiGet(`/api/models?window=${window}`, signal),\n };\n}\n\n/**\n * GET /api/portfolio — src/core/web/api.ts:1105-1109. Returns\n * `DashboardSnapshot.portfolio ?? null`: `null` on an older producer or\n * empty enrollment, not an error — render that as an honest \"not available\"\n * state, never as a zeroed chart.\n */\nexport const portfolioQuery: QueryDef<PortfolioSummary | null> = {\n key: 'portfolio',\n fetch: (signal) => apiGet<PortfolioSummary | null>('/api/portfolio', signal),\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"queries-D3sSlan1.js","names":[],"sources":["../../../../../../src/web-ui/data/queries.ts"],"sourcesContent":["/**\n * data/queries.ts — one typed accessor per backend resource. Each pairs a\n * stable cache key (also the SSE invalidation target — see sse.ts's\n * EVENT_TO_CACHE_KEYS) with the exact GET call and response type. Views\n * never call apiGet directly; they call these through useQuery (hooks.ts)\n * so caching, de-dupe, and SSE-driven refresh are automatic.\n */\nimport { apiGet } from './client.js';\nimport type { UniverseGraph } from '../../core/universe/graph-types.js';\nimport type {\n AgentOsSnapshotResponse,\n UniverseOverview,\n ControlLogEntry,\n ControlSnapshot,\n DashboardSnapshot,\n DecisionEntry,\n FleetActivitySnapshot,\n FleetStatus,\n Proposal,\n ProposalStatus,\n PublicDaemonObservation,\n RunState,\n SwarmRun,\n ActivityRollup,\n GenomeEntry,\n RecallHit,\n PortfolioSummary,\n ModelStatsReadResult,\n} from './api-types.js';\nimport type { SourceQuality } from './api-types.js';\n\nexport interface QueryDef<T> {\n key: string;\n fetch: (signal?: AbortSignal) => Promise<T>;\n}\n\nexport const dashboardSnapshotQuery: QueryDef<DashboardSnapshot> = {\n key: 'dashboard-snapshot',\n fetch: (signal) => apiGet<DashboardSnapshot>('/api/snapshot', signal),\n};\n\nexport const controlSnapshotQuery: QueryDef<ControlSnapshot> = {\n key: 'control-snapshot',\n fetch: (signal) => apiGet<ControlSnapshot>('/api/control', signal),\n};\n\nexport const agentOsSnapshotQuery: QueryDef<AgentOsSnapshotResponse> = {\n key: 'agent-os-snapshot',\n fetch: (signal) => apiGet<AgentOsSnapshotResponse>('/api/agent-os', signal),\n};\n\nexport const universeOverviewQuery: QueryDef<UniverseOverview> = {\n key: 'universe-overview',\n fetch: (signal) => apiGet<UniverseOverview>('/api/universe', signal),\n};\n\n/** Read only on demand; never invalidate this alongside the overview poll. */\nexport function universeGraphQuery(universeId: string): QueryDef<UniverseGraph> {\n return {\n key: `universe-graph-${universeId}`,\n fetch: (signal) => apiGet<UniverseGraph>(`/api/universe/graph?universeId=${encodeURIComponent(universeId)}`, signal),\n };\n}\n\n// NOTE: there is no standalone GET /api/visibility route — VisibilitySnapshot\n// is an optional field on DashboardSnapshot (`.visibility`), populated by\n// buildSnapshot() server-side. Read it off dashboardSnapshotQuery's data\n// rather than issuing a second request for it.\n\n/**\n * GET /api/runs returns the bare array (see src/core/web/api.ts:1121-1125,\n * `listRuns({limit:200})` -> `RunState[]`) — NOT `{runs: [...]}`. The prior\n * `RunSummary`/`runsQuery` pair here was speculative and didn't match the\n * real response shape; it was unused (FleetDashboardView reads its compact\n * run summaries off `DashboardSnapshot['runs']` instead, a different,\n * deliberately-thin shape). Replaced with the real, fully-typed contract.\n */\nexport const runsQuery: QueryDef<RunState[]> = {\n key: 'runs',\n fetch: (signal) => apiGet<RunState[]>('/api/runs', signal),\n};\n\nexport function runDetailQuery(id: string): QueryDef<RunState> {\n return {\n key: `run-detail-${id}`,\n fetch: (signal) => apiGet<RunState>(`/api/run/${encodeURIComponent(id)}`, signal),\n };\n}\n\nexport const swarmsQuery: QueryDef<SwarmRun[]> = {\n key: 'swarms',\n fetch: (signal) => apiGet<SwarmRun[]>('/api/swarms', signal),\n};\n\nexport function swarmDetailQuery(id: string): QueryDef<SwarmRun> {\n return {\n key: `swarm-detail-${id}`,\n fetch: (signal) => apiGet<SwarmRun>(`/api/swarm/${encodeURIComponent(id)}`, signal),\n };\n}\n\n/**\n * Same PublicDaemonObservation the backend embeds at ControlSnapshot.daemonObservation\n * — fetched standalone here because /control/daemon renders a fuller detail page\n * than DaemonPanel's dashboard-compact view and wants the raw observation\n * (including `ticks`) independent of whether the rest of /api/control succeeds.\n * Cache key 'daemon' deliberately matches sse.ts's existing (previously orphaned)\n * `daemon` / `daemon-observation` -> ['daemon'] mapping so this now actually\n * live-updates.\n */\nexport const daemonObservationQuery: QueryDef<PublicDaemonObservation> = {\n key: 'daemon',\n fetch: (signal) => apiGet<PublicDaemonObservation>('/api/daemon-observation', signal),\n};\n\nexport const fleetStatusQuery: QueryDef<FleetStatus> = {\n key: 'fleet',\n fetch: (signal) => apiGet<FleetStatus>('/api/fleet', signal),\n};\n\nexport const fleetActivityQuery: QueryDef<FleetActivitySnapshot> = {\n key: 'fleet-activity',\n fetch: (signal) => apiGet<FleetActivitySnapshot>('/api/fleet-activity', signal),\n};\n\n/**\n * GET /api/goals returns a bare array of ad-hoc per-goal projections built\n * inline in src/core/web/api.ts (`path === '/api/goals'`, ~line 1654) — there\n * is no exported backend type for this shape (unlike every other resource\n * here), so this interface is hand-written to match that handler exactly\n * rather than re-exported. Keep it in sync with api.ts if that handler's\n * shape changes.\n */\nexport interface GoalMilestoneSummary {\n title: string;\n status: string;\n order: number;\n}\n\nexport interface GoalSummary {\n id: string;\n objective: string;\n status: string;\n milestones: GoalMilestoneSummary[];\n progress: {\n fractionDone: number;\n counts: Record<string, number>;\n nextActionableId: string | null;\n };\n}\n\nexport const goalsQuery: QueryDef<GoalSummary[]> = {\n key: 'goals',\n fetch: (signal) => apiGet<GoalSummary[]>('/api/goals', signal),\n};\n\n/**\n * GET /api/vision/mission — buildVisionMissionSnapshot() in src/core/web/api.ts\n * is itself typed `Promise<Record<string, unknown>>` on the backend (no\n * exported interface to import), so this is a narrow hand-written contract\n * covering only the fields the Goals view actually reads: top-level `state`\n * (mirrors the SourceQuality.sourceState vocabulary) and the per-source\n * epistemic breakdown under `sources`. `briefing`/`preview`/`shadow` are\n * deliberately left as `unknown` — the view does not render briefing prose.\n */\nexport interface VisionMissionSourceStatus {\n sourceState: 'healthy' | 'degraded' | 'missing' | 'unknown';\n sourcePresent?: boolean;\n complete: boolean;\n reason?: string;\n}\n\nexport interface VisionMissionSnapshot {\n schemaVersion: number;\n state: string;\n authority: string;\n briefing: unknown;\n sources: {\n briefing: VisionMissionSourceStatus | null;\n goals: VisionMissionSourceStatus | null;\n enrollment: VisionMissionSourceStatus | null;\n proposals: VisionMissionSourceStatus | null;\n };\n}\n\nexport const visionMissionQuery: QueryDef<VisionMissionSnapshot> = {\n key: 'vision-mission',\n fetch: (signal) => apiGet<VisionMissionSnapshot>('/api/vision/mission', signal),\n};\n\nexport interface InboxProposal {\n id: string;\n title: string;\n kind: string;\n repo: string;\n origin: string;\n createdAt: string;\n}\n\nexport const inboxQuery: QueryDef<{ pending: number; proposals: InboxProposal[] }> = {\n key: 'inbox',\n fetch: (signal) => apiGet('/api/inbox', signal),\n};\n\n/**\n * `?status=&since=&limit=` view over GET /api/inbox (src/core/web/api.ts\n * INBOX_STATUS_QUERY_VALUES) — the history surface `inboxQuery` above never\n * had: it's hardcoded pending-only. `status: undefined` = server default\n * (pending); `'all'` = every status. Keyed per filter combo so switching\n * status/since/limit doesn't fight over one cache entry, and so sse.ts can\n * sweep every live combo (`invalidatePrefix('inbox-list:')`) on the 'inbox'\n * SSE event without knowing which combos are mounted.\n */\nexport type InboxHistoryStatus = ProposalStatus | 'all';\n\nexport interface InboxListFilters {\n status?: InboxHistoryStatus;\n /** ISO timestamp or YYYY-MM-DD, passed straight through to the server. */\n since?: string;\n limit?: number;\n}\n\nexport interface InboxListResponse {\n pending: number;\n total: number;\n /**\n * Full `Proposal[]`, not the narrow `InboxProposal` shape above — the\n * server has always sent full sanitized Proposal records here\n * (`listProposals()`); `InboxProposal` just under-typed it for the\n * original pending-badge use case. The history view needs `status` and\n * `decisionReason` per row (triage: \"why was this rejected\") without an\n * N+1 decisions-ledger read per row, and both live directly on Proposal.\n */\n proposals: Proposal[];\n /** True when more rows matched than were returned (hit the server cap). */\n truncated: boolean;\n filters: { status: InboxHistoryStatus; since: string | null; limit: number | null };\n}\n\nexport function inboxListQuery(filters: InboxListFilters = {}): QueryDef<InboxListResponse> {\n const params = new URLSearchParams();\n if (filters.status !== undefined) params.set('status', filters.status);\n if (filters.since !== undefined) params.set('since', filters.since);\n if (filters.limit !== undefined) params.set('limit', String(filters.limit));\n const qs = params.toString();\n return {\n key: `inbox-list:${filters.status ?? 'pending'}:${filters.since ?? ''}:${filters.limit ?? ''}`,\n fetch: (signal) => apiGet<InboxListResponse>(`/api/inbox${qs ? `?${qs}` : ''}`, signal),\n };\n}\n\n/**\n * Evidence behind a judge's verdict for one proposal — joined server-side\n * (src/core/web/api.ts GET /api/inbox/:id) from the decisions ledger, which\n * is the ONLY place `judgeReasonCode` lives (Proposal itself never carries\n * it). `judge-parse-failure`/`judge-network-failure` are infra failures,\n * never a considered `judge-review` — render them distinctly, never folded\n * together. When the ledger read is degraded or no row matches this\n * proposal, `sourceQuality` says so; render \"unknown\" via <Epistemic/>\n * rather than treating an empty `decisions` array as \"never judged\".\n */\nexport interface InboxDecisionEvidence {\n sourceQuality: SourceQuality;\n decisions: DecisionEntry[];\n}\n\n/**\n * GET /api/inbox/:id — full proposal detail including diff/taste/verdict\n * (src/core/web/api.ts:1240-1255, `loadProposal(id)`) plus `decisionEvidence`\n * (readDecisionsDetailed({proposalId}), added alongside the inbox history\n * view). Used by the work journal's \"why did it do that\" drill-in (M416) —\n * `/api/inbox` only ever returns pending proposals, but a decided\n * proposal's id (surfaced via fleet-activity's recentMerges/recentActions,\n * or via inboxListQuery's history view) still resolves here as long as its\n * on-disk record hasn't been pruned.\n */\nexport function proposalDetailQuery(id: string): QueryDef<Proposal & { decisionEvidence: InboxDecisionEvidence }> {\n return {\n key: `proposal-detail-${id}`,\n fetch: (signal) =>\n apiGet<Proposal & { decisionEvidence: InboxDecisionEvidence }>(`/api/inbox/${encodeURIComponent(id)}`, signal),\n };\n}\n\n/**\n * GET /api/logs-observation?tail=200 — the provenance-bearing sibling of\n * GET /api/logs (src/core/web/api.ts:~1543-1560): same daemon tick/merge\n * log, plus `sourceQuality` so a degraded/incomplete log can be rendered\n * honestly via <Epistemic/> instead of silently showing a truncated or\n * stale list as complete. `entries` is `null` when the source itself is not\n * healthy+complete (server-side contract, not a client guess). Used by the\n * work journal (M416) as one of several merged history sources — NOT a\n * substitute for full on-disk history: this is capped at 200 entries\n * server-side and only carries daemon tick/merge/info/dispatch events, not\n * raw run stdout or the ~672 historical proposals living only on disk.\n */\nexport interface ControlLogsObservation {\n entries: ControlLogEntry[] | null;\n sourceQuality: SourceQuality;\n}\n\nexport const controlLogsObservationQuery: QueryDef<ControlLogsObservation> = {\n key: 'control-logs-observation',\n fetch: (signal) => apiGet<ControlLogsObservation>('/api/logs-observation?tail=200', signal),\n};\n\n// ---------------------------------------------------------------------------\n// Intelligence + Portfolio (charts/dataviz work)\n// ---------------------------------------------------------------------------\n\nexport type PulseWindow = '1d' | '7d' | '30d';\n\n/** GET /api/pulse?window= — buildRollup() (src/core/observability/rollup.ts).\n * Parameterized like runDetailQuery/swarmDetailQuery above: a distinct cache\n * key per window so switching windows doesn't fight over one cache entry. */\nexport function pulseQuery(window: PulseWindow): QueryDef<ActivityRollup> {\n return {\n key: `pulse-${window}`,\n fetch: (signal) => apiGet<ActivityRollup>(`/api/pulse?window=${window}`, signal),\n };\n}\n\n/**\n * GET /api/genome[?q=] — src/core/web/api.ts:1189-1201. Two response shapes\n * depending on `q`: empty/absent `q` returns `GenomeEntry[]` (list mode,\n * `loadGenome()`); a non-empty `q` returns `RecallHit[]` (query mode,\n * `recall()`, `{entry, score, method}`). Use `isRecallHit` to discriminate —\n * the view can't know which shape it got from the type alone since both are\n * arrays. Keyed per query string so a debounced search doesn't stomp the\n * browse-mode cache entry.\n */\nexport type GenomeResult = GenomeEntry[] | RecallHit[];\n\nexport function isRecallHit(item: GenomeEntry | RecallHit): item is RecallHit {\n return typeof item === 'object' && item !== null && 'entry' in item && 'score' in item;\n}\n\nexport function genomeQuery(q: string): QueryDef<GenomeResult> {\n const trimmed = q.trim();\n return {\n key: trimmed ? `genome-search-${trimmed}` : 'genome-list',\n fetch: (signal) =>\n apiGet<GenomeResult>(trimmed ? `/api/genome?q=${encodeURIComponent(trimmed)}` : '/api/genome', signal),\n };\n}\n\nexport type ModelStatsWindow = '7d' | '30d' | 'all';\n\n/** GET /api/models?window= — computeModelStatsDetailed() joined per-model\n * economics (src/core/fleet/model-stats.ts). NOTE: a second, dead\n * `/api/models` handler later in api.ts's if-chain (local-model provider\n * probe off ControlSnapshot.models) is unreachable — this one always wins\n * since route matching is first-match. */\nexport function modelsQuery(window: ModelStatsWindow): QueryDef<ModelStatsReadResult & { window: ModelStatsWindow }> {\n return {\n key: `models-${window}`,\n fetch: (signal) => apiGet(`/api/models?window=${window}`, signal),\n };\n}\n\n/**\n * GET /api/portfolio — src/core/web/api.ts:1105-1109. Returns\n * `DashboardSnapshot.portfolio ?? null`: `null` on an older producer or\n * empty enrollment, not an error — render that as an honest \"not available\"\n * state, never as a zeroed chart.\n */\nexport const portfolioQuery: QueryDef<PortfolioSummary | null> = {\n key: 'portfolio',\n fetch: (signal) => apiGet<PortfolioSummary | null>('/api/portfolio', signal),\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,o as t}from"./index-
|
|
2
|
-
//# sourceMappingURL=use-guarded-action-
|
|
1
|
+
import{a as e,o as t}from"./index-CXgVQHek.js";import{I as n,N as r,W as i,c as a,j as o,l as s,s as c,u as l}from"./global-DMWakEhP.js";import{a as u,r as d}from"./ConfirmDialog-C363ty_c.js";var f={dailyBudgetUsd:{min:0,max:1e3},perTickItems:{min:1,max:50},parallel:{min:1,max:16},intervalMs:{min:3e4,max:864e5},maxConcurrent:{min:1,max:32},concurrency:{min:1,max:32},subscriptionMaxPercent:{min:1,max:100},foundryLimitMax:{min:0,max:1e6}},p=t(e(),1),m=`verse-control`,h=`verse-caps`,g=`verse-scope`,_=`verse-safety`,v=`verse-audit:`,y=500,b={key:m,fetch:e=>s(`/api/verse/control`,e)},x={key:h,fetch:e=>s(`/api/verse/caps`,e)},S={key:_,fetch:e=>s(`/api/verse/safety`,e)};function C(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}var w={key:g,fetch:e=>s(`/api/verse/scope`,e)};function T(e={}){let t=Math.min(e.limit??200,y),n=new URLSearchParams;return n.set(`limit`,String(t)),e.action&&n.set(`action`,e.action),e.result&&n.set(`result`,e.result),{key:`${v}${t}:${e.action??``}:${e.result??``}`,fetch:e=>s(`/api/verse/audit?${n.toString()}`,e)}}var E={key:`goals`,fetch:e=>s(`/api/goals`,e)};function D(e){return e==null?{items:[],absent:!0}:Array.isArray(e)?{items:e,absent:!1}:C(e)&&Array.isArray(e.items)?{items:e.items,absent:!1}:{items:[],absent:!0}}var O={key:`backlog`,fetch:e=>s(`/api/backlog`,e).then(D)},k=class extends Error{constructor(){super(`Unlock actions with the mutation token before changing the loop.`),this.name=`VerseControlLockedError`}};async function A(e,t){let r=o();if(!r)throw new k;let i=await l(e,t,r);return n(),i}function j(){i(m)}async function M(e){let t=await A(`/api/verse/caps`,e);return i(h),j(),t}async function N(e){await A(`/api/verse/scope`,e),i(g),j()}async function P(e){let t=await A(`/api/verse/daemon`,{action:e});return j(),i(`daemon`),t}async function F(){await d(),j()}async function I(){await u(),j()}function L(e){return e instanceof a?`This server runs without dispatch, so that action is unavailable.`:e instanceof k?e.message:e instanceof c?e.status===401?"The mutation token was rejected. Unlock again with the token `ashlr verse` printed.":e.detail?e.detail:e.status===400?e.message:e.status===409?`The server refused the action, and sent no reason.`:e.message:e instanceof Error?e.message:`That action failed. Try again.`}function R(){let[e,t]=(0,p.useState)(!1),[n,i]=(0,p.useState)(null),[o,s]=(0,p.useState)(!1),[c,l]=(0,p.useState)(!1),[u,d]=(0,p.useState)(``),f=(0,p.useRef)(null),m=(0,p.useCallback)(async(e,n)=>{t(!0),i(null);try{let t=await e();n?.(t)}catch(e){e instanceof a?s(!0):i(L(e))}finally{t(!1)}},[]),h=(0,p.useCallback)((e,t,n)=>{i(null);let a=n;if(r()){m(e,a);return}f.current={fn:e,onResult:a},d(t),l(!0)},[m]),g=(0,p.useCallback)(()=>{l(!1);let e=f.current;f.current=null,e&&r()&&m(e.fn,e.onResult)},[m]);return{request:h,busy:e,error:n,clearError:(0,p.useCallback)(()=>i(null),[]),readOnly:o,tokenOpen:c,tokenReason:u,closeToken:g}}export{f as _,F as a,M as c,O as d,x as f,w as g,S as h,k as i,N as l,E as m,R as n,I as o,b as p,m as r,P as s,L as t,T as u};
|
|
2
|
+
//# sourceMappingURL=use-guarded-action-BxfJ9E-n.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-guarded-action-BO6c94Wp.js","names":[],"sources":["../../../../../../src/core/verse/control-types.ts","../../../../../../src/web-ui/routes/verse/autonomy/control-queries.ts","../../../../../../src/web-ui/routes/verse/autonomy/use-guarded-action.ts"],"sourcesContent":["/**\n * Ashlr Verse — autonomy control-plane contract (V2).\n *\n * V1 (`./types.ts`) is frozen: it describes interactive chat sessions. This\n * module adds the shapes the Autonomy cockpit needs to run the hub's existing\n * autonomous fleet without a terminal — the CONFIGURED caps, the enrollment\n * scope, the audit trail, the kill switch, and the daemon lifecycle.\n *\n * Two hard rules are encoded here rather than left to the UI:\n *\n * 1. The global kill switch (`~/.ashlr/KILL`) is an EMERGENCY STOP, not a\n * pause. It also refuses the agent's own `mcp-native` write tools. Every\n * shape that carries it is named `killSwitch`, and the action that engages\n * it is named `emergencyStop`. It is never called \"pause\".\n *\n * V2.1 adds the control that name was being withheld from: the\n * DAEMON-SCOPED pause (`~/.ashlr/daemon.paused`, see core/daemon/pause.ts).\n * It halts autonomous dispatch and NOTHING else — `assertMayMutate`,\n * `mcp-native`, and `mcp-native-engineer` do not read it. It travels as\n * `pause: VerseDaemonPause`, always a FIELD OF ITS OWN, never merged into\n * `killSwitch`, because the whole point is that the two have different\n * blast radii and the operator must be able to see which one is on.\n * 2. Nothing in this module is a secret. Launcher commands, tokens, and env\n * values never appear in any of these shapes — the daemon lifecycle result\n * carries a pid, never an argv.\n *\n * Everything is a projection of state the hub already computes; nothing here\n * introduces a new source of truth.\n */\n\nimport type { AuditEntry } from '../types.js';\nimport type { PublicDaemonObservation } from '../daemon/public-observation.js';\nimport type { FrontierEngineUsage } from '../usage/frontier-usage.js';\nimport type { SafetyReport } from '../../cli/verify-safety.js';\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/**\n * Error codes for `/api/verse/{control,caps,scope,audit,daemon,safety}`.\n * `VERSE_INVALID` / `VERSE_TOO_LARGE` are deliberately the SAME codes V1 uses,\n * so one client error mapper covers both halves of the Verse API.\n */\nexport type VerseControlErrorCode =\n | 'VERSE_INVALID'\n | 'VERSE_REFUSED'\n | 'VERSE_TOO_LARGE'\n | 'VERSE_UNAVAILABLE';\n\n/** Every error body on these routes. */\nexport interface VerseControlError {\n error: string;\n code: VerseControlErrorCode;\n}\n\n// ---------------------------------------------------------------------------\n// Caps — the CONFIGURED limits (GET/POST /api/verse/caps)\n// ---------------------------------------------------------------------------\n\n/** One `cfg.foundry.limits[engine]` entry, flattened for transport. */\nexport interface VerseFoundryLimit {\n /** EngineId key, e.g. 'claude' | 'codex'. */\n engine: string;\n /** Rolling window label, e.g. '1m' | '5m' | '1h' | '1d'. */\n window: string;\n /** Max dispatches per window. 0 means \"no dispatches allowed\". */\n max: number;\n}\n\n/** `cfg.daemon.concurrency` — null per tier means \"not configured, using the default\". */\nexport interface VerseCapsConcurrency {\n local: number | null;\n cloud: number | null;\n total: number | null;\n}\n\n/**\n * The configured autonomy limits. These are the values the daemon actually\n * reads — no route exposed them before V2, which is why the cockpit could not\n * show a cap next to the usage burning against it.\n */\nexport interface VerseCaps {\n /** HARD daily spend ceiling (USD). 0 means the daemon is stopped by budget. */\n dailyBudgetUsd: number;\n /** Backlog items processed per tick. */\n perTickItems: number;\n /** Concurrent sandboxed swarms per tick (batch mode). */\n parallel: number;\n /** Tick interval in loop mode (ms). */\n intervalMs: number;\n /** Daemon execution mode. */\n mode: 'batch' | 'continuous';\n /** Ceiling on in-flight dispatches in continuous mode; null when unset. */\n maxConcurrent: number | null;\n /** Per-tier concurrency budgets; null per tier when unset. */\n concurrency: VerseCapsConcurrency;\n /** Subscription-window throttle percentage (1–100). */\n subscriptionMaxPercent: number;\n /** Per-engine dispatch limits, sorted by engine id. */\n foundryLimits: VerseFoundryLimit[];\n /**\n * HONEST STATE: the cap keys whose value is a built-in default rather than\n * something configured on disk. The UI renders these as \"default\", never as\n * a deliberate choice the operator made. Sorted, stable.\n */\n defaulted: VerseCapKey[];\n}\n\n/** The scalar cap keys a client may update. `foundryLimits` is handled separately. */\nexport type VerseCapKey =\n | 'dailyBudgetUsd'\n | 'perTickItems'\n | 'parallel'\n | 'intervalMs'\n | 'mode'\n | 'maxConcurrent'\n | 'concurrency'\n | 'subscriptionMaxPercent'\n | 'foundryLimits';\n\n/** POST /api/verse/caps — a partial update. Unknown keys are rejected. */\nexport interface VerseCapsUpdate {\n dailyBudgetUsd?: number;\n perTickItems?: number;\n parallel?: number;\n intervalMs?: number;\n mode?: 'batch' | 'continuous';\n maxConcurrent?: number;\n concurrency?: { local?: number; cloud?: number; total?: number };\n subscriptionMaxPercent?: number;\n /** Replaces the named engines' limits; engines not listed are left alone. */\n foundryLimits?: VerseFoundryLimit[];\n}\n\n/**\n * POST /api/verse/caps result. `live: true` is not decoration — the daemon\n * re-reads config at the top of every tick, so a saved cap binds on the next\n * tick without a restart.\n */\nexport interface VerseCapsUpdateResult {\n ok: true;\n /** The cap keys this request actually changed, in request order. */\n applied: VerseCapKey[];\n live: true;\n /** The full caps AFTER the write, re-read from disk. */\n caps: VerseCaps;\n}\n\n// ---------------------------------------------------------------------------\n// Scope — the enrollment registry (GET/POST /api/verse/scope)\n// ---------------------------------------------------------------------------\n\nexport interface VerseScopeRepo {\n path: string;\n name: string;\n /** False when the registry still lists a directory that is gone. */\n exists: boolean;\n}\n\n/**\n * GET /api/verse/scope. An EMPTY `repos` with no `degradedReason` is the\n * valid default state and means the daemon will do nothing at all — the UI\n * must say that plainly rather than rendering an innocuous empty list.\n */\nexport interface VerseScope {\n repos: VerseScopeRepo[];\n /** Present only when enrollment authority could not be read at all. */\n degradedReason?: string;\n}\n\nexport type VerseScopeAction = 'enroll' | 'unenroll';\n\n/** POST /api/verse/scope body. */\nexport interface VerseScopeRequest {\n action: VerseScopeAction;\n path: string;\n}\n\nexport interface VerseScopeResult {\n ok: boolean;\n action: VerseScopeAction;\n /** The canonical (realpath'd) registry path this acted on. */\n path: string;\n /** False when the registry already had the requested state (idempotent). */\n changed: boolean;\n /** Policy reason string, e.g. 'enrolled' | 'already-unenrolled'. */\n reason: string;\n /** The scope AFTER the mutation. */\n scope: VerseScope;\n}\n\n// ---------------------------------------------------------------------------\n// Audit (GET /api/verse/audit)\n// ---------------------------------------------------------------------------\n\nexport type VerseAuditResult = AuditEntry['result'];\n\n/** GET /api/verse/audit?limit=&action=&result= */\nexport interface VerseAuditResponse {\n /** Newest first, already filtered, at most `limit` entries. */\n entries: AuditEntry[];\n /** The effective cap applied to `entries` (never above 500). */\n limit: number;\n /** Echo of the applied filter so the UI cannot drift from what it shows. */\n filter: { action: string | null; result: VerseAuditResult | null };\n /** How many raw entries were scanned before filtering. */\n scanned: number;\n /**\n * True when the scan filled its own ceiling, so older entries MAY exist\n * beyond what was read. Conservative by design: it never claims the reader\n * reached the end of history when it cannot prove that.\n */\n truncated: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Kill switch\n// ---------------------------------------------------------------------------\n\n/**\n * The GLOBAL kill switch (`~/.ashlr/KILL`). `state: 'unknown'` is a real,\n * distinct outcome — the sentinel was uninspectable — and must never be\n * rendered as \"off\".\n */\nexport interface VerseKillSwitch {\n state: 'active' | 'inactive' | 'unknown';\n sourceState: 'healthy' | 'degraded';\n reason: string;\n /**\n * Plain-language statement of blast radius, shipped with the state so no\n * surface can show the switch without the warning.\n */\n note: string;\n}\n\n// ---------------------------------------------------------------------------\n// Daemon pause — the NARROW stop (POST /api/verse/daemon {action:'pause'})\n// ---------------------------------------------------------------------------\n\n/**\n * The DAEMON-SCOPED pause sentinel (`~/.ashlr/daemon.paused`), projected for\n * transport. Shares `VerseKillSwitch`'s shape on purpose — both are sentinels\n * read the same way, and both keep `'unknown'` as a real third state that must\n * never render as \"off\".\n *\n * `state: 'unknown'` is treated by the daemon as PAUSED (fail safe), so the UI\n * must say \"paused — the sentinel could not be read\", not \"running\".\n *\n * The sentinel PATH is deliberately absent: it is machine-local detail the\n * cockpit has no use for, the same omission `VerseKillSwitch` makes.\n */\nexport interface VerseDaemonPause {\n /** 'paused' = dispatch halted. 'running' = proven not paused. */\n state: 'paused' | 'running' | 'unknown';\n sourceState: 'healthy' | 'degraded';\n reason: string;\n /** ISO time the pause was requested; null when not paused or unknown. */\n pausedAt: string | null;\n /** Which surface paused it ('cli' | 'verse-control-plane' | 'unknown'). */\n by: string | null;\n /** Plain-language statement of the NARROW blast radius, shipped with the state. */\n note: string;\n}\n\n// ---------------------------------------------------------------------------\n// Daemon lifecycle (POST /api/verse/daemon)\n// ---------------------------------------------------------------------------\n\n/**\n * 'start' launches the autonomous loop detached (exactly `ashlr daemon start`).\n * 'once' runs a single tick the same way.\n *\n * Three stops, three honestly different scopes:\n * - 'pause' — halts autonomous DISPATCH only. Reversible with 'resume'.\n * Leaves the agent's own write tools alone. The default choice.\n * - 'stop' — the ordinary stop, which today engages the GLOBAL kill switch\n * (`stopDaemon()` is `setKill(true)`), so it is wider than a\n * pause and the result's `note` says so.\n * - emergency stop — not on this route at all (`POST /api/fleet/pause`).\n */\nexport type VerseDaemonAction = 'start' | 'stop' | 'once' | 'pause' | 'resume';\n\n/** Non-secret projection of `~/.ashlr/daemon.json`. */\nexport interface VerseDaemonStateProjection {\n running: boolean;\n pid: number | null;\n startedAt: string | null;\n lastTickAt: string | null;\n todayDate: string | null;\n todaySpentUsd: number;\n itemsProcessed: number;\n}\n\n/**\n * POST /api/verse/daemon result. `pid` is the only thing that ever escapes the\n * spawn — the argv, the env, and the resolved launcher path never do.\n */\nexport interface VerseDaemonActionResult {\n ok: boolean;\n action: VerseDaemonAction;\n /** True when a detached child was launched by this request. */\n spawned: boolean;\n /** The detached child's pid for 'start'/'once'; null otherwise. */\n pid: number | null;\n state: VerseDaemonStateProjection;\n killSwitch: VerseKillSwitch;\n /** The daemon-scoped pause AFTER this action. Never folded into killSwitch. */\n pause: VerseDaemonPause;\n /** One line of plain language about what just happened, for the UI to echo. */\n note: string;\n}\n\n// ---------------------------------------------------------------------------\n// Fleet essentials + control aggregate (GET /api/verse/control)\n// ---------------------------------------------------------------------------\n\n/**\n * The small honest slice of FleetStatus/ControlSnapshot the cockpit needs.\n * Deliberately excludes service file paths and error-log paths: the cockpit\n * does not need them, and keeping them out keeps this payload trivially\n * provable as free of machine-local command detail.\n */\nexport interface VerseFleetEssentials {\n /** Mode the autonomy control loop last directed, when known. */\n directionMode: string | null;\n directionAt: string | null;\n directionReason: string | null;\n autonomyControlLoop: boolean;\n autonomyControlMode: string;\n service: {\n registrationState: 'present' | 'absent' | 'unknown';\n installed: boolean;\n running: boolean;\n runtimeState: string | null;\n };\n /** Freshness of the shared fleet-status cache backing these values. */\n freshness: { stale: boolean; ageMs: number };\n}\n\n/** Today's spend against the configured ceiling. */\nexport interface VerseSpend {\n /** null when the daemon ledger could not be read (NOT zero). */\n todayUsd: number | null;\n /** Calendar day the counter applies to; null before the first tick. */\n todayDate: string | null;\n dailyBudgetUsd: number;\n}\n\n/**\n * GET /api/verse/control — the ONE aggregate the Autonomy view reads.\n * Every field is a projection of an existing snapshot; nothing is recomputed.\n */\nexport interface VerseControlSnapshot {\n generatedAt: string;\n daemon: PublicDaemonObservation;\n fleet: VerseFleetEssentials;\n caps: VerseCaps;\n scope: VerseScope;\n killSwitch: VerseKillSwitch;\n /**\n * The DAEMON-SCOPED pause, as its own field. A cockpit that folded this into\n * `killSwitch` would be back to one control with two names; keeping them\n * separate is what lets the Autonomy view render \"paused\" and \"kill switch\n * engaged\" as the different situations they are.\n */\n pause: VerseDaemonPause;\n /** Pending inbox proposals awaiting a human decision. */\n pendingApprovals: number;\n spend: VerseSpend;\n /** Per-engine quota usage against the configured foundry limits. */\n quota: FrontierEngineUsage[];\n /** False when this server was started without --allow-dispatch: all POSTs 404. */\n dispatchEnabled: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Safety (GET /api/verse/safety)\n// ---------------------------------------------------------------------------\n\n/** GET /api/verse/safety — the `ashlr verify-safety --json` report, unmodified. */\nexport type VerseSafetyReport = SafetyReport;\n\n// ---------------------------------------------------------------------------\n// Bounds (single source of truth — the API validator and the UI share these)\n// ---------------------------------------------------------------------------\n\nexport const VERSE_CAPS_BOUNDS = {\n dailyBudgetUsd: { min: 0, max: 1_000 },\n perTickItems: { min: 1, max: 50 },\n parallel: { min: 1, max: 16 },\n intervalMs: { min: 30_000, max: 86_400_000 },\n maxConcurrent: { min: 1, max: 32 },\n /**\n * DELIBERATE DEVIATION from VERSE-CONTRACT-V2's \"concurrency 0-32 each\".\n *\n * The daemon cannot honour a zero tier. `resolveCfg` (daemon/loop.ts) only\n * adopts a tier when it is `> 0`, and `TieredPool`'s constructor floors\n * every cap at `Math.max(1, …)` on top of that — so a stored 0 came back as\n * the built-in 2/6/8 while the cockpit displayed 0. Teaching the pool to\n * accept 0 is not a fix either: `tieredBounded` would then never start a\n * task on that tier and never resolve, i.e. a hung tick.\n *\n * A floor of 1 is therefore the only value that is true in both places. To\n * stop dispatch entirely, the honest lever is `dailyBudgetUsd: 0`, which the\n * daemon now really does obey.\n */\n concurrency: { min: 1, max: 32 },\n subscriptionMaxPercent: { min: 1, max: 100 },\n foundryLimitMax: { min: 0, max: 1_000_000 },\n} as const;\n\n/** Hard ceiling on GET /api/verse/audit `limit`. */\nexport const VERSE_AUDIT_MAX_LIMIT = 500;\n/** Default `limit` when the query omits one. */\nexport const VERSE_AUDIT_DEFAULT_LIMIT = 100;\n/**\n * Hard ceiling on how many raw audit entries a single request will read before\n * filtering. Bounds the work a filtered query can ask of the disk.\n */\nexport const VERSE_AUDIT_MAX_SCAN = 5_000;\n\n/** The kill switch's blast-radius warning — one string, used everywhere. */\nexport const VERSE_KILL_SWITCH_NOTE =\n 'Emergency stop: the global kill switch also refuses the agent\\'s own write tools, not just the daemon. Use the daemon pause action for an ordinary, reversible halt.';\n\n/**\n * The pause's blast-radius statement — the counterpart to\n * VERSE_KILL_SWITCH_NOTE, shipped with every pause projection so no surface\n * can show the state without the scope. Says what it does NOT do, because\n * that is the entire difference from the control next to it.\n */\nexport const VERSE_DAEMON_PAUSE_NOTE =\n 'Pause: halts autonomous dispatch only. Your own write tools keep working, nothing in flight is rolled back, and Resume restores the loop without a restart.';\n","/**\n * routes/verse/autonomy/control-queries.ts — every `/api/verse/{control,caps,\n * scope,audit,daemon,safety}` call the Autonomy cockpit makes, plus the two\n * existing read-only feeds it borrows (`/api/goals`, `/api/backlog`).\n *\n * Same contract as routes/verse/verse-queries.ts: reads are QueryDefs consumed\n * through useQuery (cache-backed, so a background refresh never blanks a\n * populated panel); writes pull the held mutation token from auth-store, touch\n * the hold on success, and invalidate exactly the keys they affect.\n *\n * Two deliberate choices worth knowing before editing:\n *\n * 1. **The envelopes are now fixed, so nothing is normalized.**\n * `/api/verse/scope` and `/api/verse/audit` are declared in\n * `src/core/verse/control-types.ts` (`VerseScope`, `VerseAuditResponse`)\n * and the handlers serialize exactly those, so these fetchers are typed\n * straight through. The speculative bare-array/wrapper normalization that\n * let this surface ship before the routes existed has been deleted.\n * `/api/backlog` keeps its normalizer — that route really does answer\n * `loadBacklog() ?? null` and is not part of the V2 contract.\n * 2. **Emergency stop is not a route of its own.** The global kill switch is\n * `POST /api/fleet/pause` (and `/resume` to clear), already wrapped in\n * data/mutations.ts. It is re-exported here under honest names so no call\n * site in this folder can accidentally call it \"pause\".\n */\nimport { VERSE_AUDIT_MAX_LIMIT } from './control-types.js';\nimport type { GoalSummary, QueryDef } from '../../../data/queries.js';\nimport { getMutationToken, touchMutationHold } from '../../../data/auth-store.js';\nimport { apiGet, apiPost } from '../../../data/client.js';\nimport { invalidate } from '../../../data/cache.js';\nimport { pauseFleet, resumeFleet } from '../../../data/mutations.js';\nimport type {\n VerseAuditFilters,\n VerseAuditPage,\n VerseCaps,\n VerseCapsApplyResult,\n VerseCapsPatch,\n VerseControlSnapshot,\n VerseDaemonAction,\n VerseDaemonActionResult,\n VerseSafetyReport,\n VerseScope,\n VerseScopePatch,\n} from './control-types.js';\n\nexport const VERSE_CONTROL_KEY = 'verse-control';\nexport const VERSE_CAPS_KEY = 'verse-caps';\nexport const VERSE_SCOPE_KEY = 'verse-scope';\nexport const VERSE_SAFETY_KEY = 'verse-safety';\nexport const VERSE_AUDIT_PREFIX = 'verse-audit:';\n\n/**\n * Server-side cap on `/api/verse/audit`, re-exported from the backend\n * contract module so the client cannot drift from the value the route\n * actually clamps to.\n */\nexport const VERSE_AUDIT_MAX = VERSE_AUDIT_MAX_LIMIT;\n/** Enough rows that the table is the real \"while I was asleep\" view. */\nexport const VERSE_AUDIT_DEFAULT_LIMIT = 200;\n\nexport const verseControlQuery: QueryDef<VerseControlSnapshot> = {\n key: VERSE_CONTROL_KEY,\n fetch: (signal) => apiGet<VerseControlSnapshot>('/api/verse/control', signal),\n};\n\nexport const verseCapsQuery: QueryDef<VerseCaps> = {\n key: VERSE_CAPS_KEY,\n fetch: (signal) => apiGet<VerseCaps>('/api/verse/caps', signal),\n};\n\nexport const verseSafetyQuery: QueryDef<VerseSafetyReport> = {\n key: VERSE_SAFETY_KEY,\n fetch: (signal) => apiGet<VerseSafetyReport>('/api/verse/safety', signal),\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport const verseScopeQuery: QueryDef<VerseScope> = {\n key: VERSE_SCOPE_KEY,\n fetch: (signal) => apiGet<VerseScope>('/api/verse/scope', signal),\n};\n\nexport function verseAuditQuery(filters: VerseAuditFilters = {}): QueryDef<VerseAuditPage> {\n const limit = Math.min(filters.limit ?? VERSE_AUDIT_DEFAULT_LIMIT, VERSE_AUDIT_MAX);\n const params = new URLSearchParams();\n params.set('limit', String(limit));\n if (filters.action) params.set('action', filters.action);\n if (filters.result) params.set('result', filters.result);\n return {\n key: `${VERSE_AUDIT_PREFIX}${limit}:${filters.action ?? ''}:${filters.result ?? ''}`,\n fetch: (signal) => apiGet<VerseAuditPage>(`/api/verse/audit?${params.toString()}`, signal),\n };\n}\n\n/**\n * Read-only in V2 — the contract is explicit that no goal-mutation routes get\n * built here. `/api/goals` returns a bare array; `/api/backlog` returns\n * `loadBacklog() ?? null`, i.e. `null` is \"no backlog on disk\", not an error.\n */\nexport const verseGoalsQuery: QueryDef<GoalSummary[]> = {\n key: 'goals',\n fetch: (signal) => apiGet<GoalSummary[]>('/api/goals', signal),\n};\n\n/** One backlog row, narrowed to what the read-only summary renders. */\nexport interface VerseBacklogItem {\n id?: string;\n title?: string;\n repo?: string;\n score?: number;\n source?: string;\n}\n\nexport interface VerseBacklogSummary {\n items: VerseBacklogItem[];\n /** True when the server answered `null` — no backlog has been built yet. */\n absent: boolean;\n}\n\nexport function normalizeBacklog(raw: unknown): VerseBacklogSummary {\n if (raw === null || raw === undefined) return { items: [], absent: true };\n if (Array.isArray(raw)) return { items: raw as VerseBacklogItem[], absent: false };\n if (isRecord(raw) && Array.isArray(raw['items'])) {\n return { items: raw['items'] as VerseBacklogItem[], absent: false };\n }\n return { items: [], absent: true };\n}\n\nexport const verseBacklogQuery: QueryDef<VerseBacklogSummary> = {\n key: 'backlog',\n fetch: (signal) => apiGet<unknown>('/api/backlog', signal).then(normalizeBacklog),\n};\n\n// ---------------------------------------------------------------------------\n// Writes\n// ---------------------------------------------------------------------------\n\n/** Thrown before any network call when no mutation token is held. */\nexport class VerseControlLockedError extends Error {\n constructor() {\n super('Unlock actions with the mutation token before changing the loop.');\n this.name = 'VerseControlLockedError';\n }\n}\n\nasync function post<T>(path: string, body: unknown): Promise<T> {\n const token = getMutationToken();\n if (!token) throw new VerseControlLockedError();\n const result = await apiPost<T>(path, body, token);\n touchMutationHold();\n return result;\n}\n\n/** Every panel in the cockpit reads through one of these three. */\nexport function invalidateControl(): void {\n invalidate(VERSE_CONTROL_KEY);\n}\n\nexport async function updateVerseCaps(patch: VerseCapsPatch): Promise<VerseCapsApplyResult> {\n const result = await post<VerseCapsApplyResult>('/api/verse/caps', patch);\n invalidate(VERSE_CAPS_KEY);\n invalidateControl();\n return result;\n}\n\nexport async function updateVerseScope(patch: VerseScopePatch): Promise<void> {\n await post<unknown>('/api/verse/scope', patch);\n invalidate(VERSE_SCOPE_KEY);\n invalidateControl();\n}\n\nexport async function runDaemonAction(action: VerseDaemonAction): Promise<VerseDaemonActionResult> {\n const result = await post<VerseDaemonActionResult>('/api/verse/daemon', { action });\n invalidateControl();\n invalidate('daemon');\n return result;\n}\n\n/**\n * ENGAGE the global kill switch (`~/.ashlr/KILL`). This is `POST\n * /api/fleet/pause` under its honest name: it stops the daemon AND refuses\n * the agent's own mcp-native write tools. Never surface it as \"pause\".\n */\nexport async function engageEmergencyStop(): Promise<void> {\n await pauseFleet();\n invalidateControl();\n}\n\n/** Clear the kill switch — writes become possible again fleet-wide. */\nexport async function releaseEmergencyStop(): Promise<void> {\n await resumeFleet();\n invalidateControl();\n}\n","/**\n * routes/verse/autonomy/use-guarded-action.ts — the one place a Verse control\n * surface turns \"the operator clicked something destructive\" into an actual\n * request. Shared by the Autonomy cockpit and the Approvals surface.\n *\n * It folds together the three things every mutating click in this app has to\n * do, which were previously re-implemented per call site:\n *\n * - **Token hand-off.** No mutation hold yet → remember the action, open\n * MutationTokenDialog, and run it once the token lands. The hold is read\n * LIVE on dialog close, never from a render-time snapshot, because\n * MutationTokenDialog's onClose fires before this component re-renders.\n * - **Read-only sessions.** Every POST 404s when the server was started\n * without dispatch. That is a session mode, not a failure, so it flips a\n * `readOnly` flag the surface renders as an explanation — never as an error\n * toast and never as a crash.\n * - **Busy + error state** for exactly one in-flight action at a time.\n */\nimport { useCallback, useRef, useState } from 'react';\nimport { hasMutationHold } from '../../../data/auth-store.js';\nimport { ApiError, DispatchDisabledError } from '../../../data/client.js';\nimport { VerseControlLockedError } from './control-queries.js';\n\nexport function describeControlError(err: unknown): string {\n if (err instanceof DispatchDisabledError) return 'This server runs without dispatch, so that action is unavailable.';\n if (err instanceof VerseControlLockedError) return err.message;\n if (err instanceof ApiError) {\n if (err.status === 401) return 'The mutation token was rejected. Unlock again with the token `ashlr verse` printed.';\n // The control plane writes a careful refusal ladder — \"no repositories are\n // enrolled, so the loop would do nothing. Add scope first.\" — and returns\n // it as `note` on the 409 body. A blanket \"something else is already\n // running\" replaced every one of those with a sentence that was usually\n // false and never actionable. Show the server's own words whenever it\n // sent any; the generic line is now only the last resort.\n if (err.detail) return err.detail;\n if (err.status === 400) return err.message;\n if (err.status === 409) return 'The server refused the action, and sent no reason.';\n return err.message;\n }\n return err instanceof Error ? err.message : 'That action failed. Try again.';\n}\n\nexport interface GuardedAction {\n /**\n * Run `fn`, prompting for the mutation token first when none is held.\n *\n * `onResult` receives `fn`'s resolved value when it succeeds. It exists\n * because the value was previously dropped on the floor, and for the daemon\n * routes that value carries the server's own account of what just happened\n * (`VerseDaemonActionResult.note` — e.g. that an ordinary stop also engaged\n * the global kill switch). It is not called when `fn` throws.\n */\n request: <T>(fn: () => Promise<T>, reason: string, onResult?: (result: T) => void) => void;\n busy: boolean;\n error: string | null;\n clearError: () => void;\n /** True once a POST 404'd — the server has no dispatch enabled. */\n readOnly: boolean;\n /** Bind these three to <MutationTokenDialog/>. */\n tokenOpen: boolean;\n tokenReason: string;\n closeToken: () => void;\n}\n\nexport function useGuardedAction(): GuardedAction {\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [readOnly, setReadOnly] = useState(false);\n const [tokenOpen, setTokenOpen] = useState(false);\n const [tokenReason, setTokenReason] = useState('');\n // The deferred action and the callback that wants its result travel together\n // — the token dialog may run it a render later, long after `request` returned.\n const pending = useRef<{ fn: () => Promise<unknown>; onResult?: (result: never) => void } | null>(null);\n\n const perform = useCallback(\n async (fn: () => Promise<unknown>, onResult?: (result: never) => void) => {\n setBusy(true);\n setError(null);\n try {\n const result = await fn();\n onResult?.(result as never);\n } catch (err) {\n if (err instanceof DispatchDisabledError) setReadOnly(true);\n else setError(describeControlError(err));\n } finally {\n setBusy(false);\n }\n },\n [],\n );\n\n const request = useCallback(\n <T,>(fn: () => Promise<T>, reason: string, onResult?: (result: T) => void) => {\n setError(null);\n const handler = onResult as ((result: never) => void) | undefined;\n if (hasMutationHold()) {\n void perform(fn, handler);\n return;\n }\n pending.current = { fn, onResult: handler };\n setTokenReason(reason);\n setTokenOpen(true);\n },\n [perform],\n );\n\n const closeToken = useCallback(() => {\n setTokenOpen(false);\n const next = pending.current;\n pending.current = null;\n // Live read: the dialog closes synchronously after setToken().\n if (next && hasMutationHold()) void perform(next.fn, next.onResult);\n }, [perform]);\n\n const clearError = useCallback(() => setError(null), []);\n\n return { request, busy, error, clearError, readOnly, tokenOpen, tokenReason, closeToken };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-guarded-action-BxfJ9E-n.js","names":[],"sources":["../../../../../../src/core/verse/control-types.ts","../../../../../../src/web-ui/routes/verse/autonomy/control-queries.ts","../../../../../../src/web-ui/routes/verse/autonomy/use-guarded-action.ts"],"sourcesContent":["/**\n * Ashlr Verse — autonomy control-plane contract (V2).\n *\n * V1 (`./types.ts`) is frozen: it describes interactive chat sessions. This\n * module adds the shapes the Autonomy cockpit needs to run the hub's existing\n * autonomous fleet without a terminal — the CONFIGURED caps, the enrollment\n * scope, the audit trail, the kill switch, and the daemon lifecycle.\n *\n * Two hard rules are encoded here rather than left to the UI:\n *\n * 1. The global kill switch (`~/.ashlr/KILL`) is an EMERGENCY STOP, not a\n * pause. It also refuses the agent's own `mcp-native` write tools. Every\n * shape that carries it is named `killSwitch`, and the action that engages\n * it is named `emergencyStop`. It is never called \"pause\".\n *\n * V2.1 adds the control that name was being withheld from: the\n * DAEMON-SCOPED pause (`~/.ashlr/daemon.paused`, see core/daemon/pause.ts).\n * It halts autonomous dispatch and NOTHING else — `assertMayMutate`,\n * `mcp-native`, and `mcp-native-engineer` do not read it. It travels as\n * `pause: VerseDaemonPause`, always a FIELD OF ITS OWN, never merged into\n * `killSwitch`, because the whole point is that the two have different\n * blast radii and the operator must be able to see which one is on.\n * 2. Nothing in this module is a secret. Launcher commands, tokens, and env\n * values never appear in any of these shapes — the daemon lifecycle result\n * carries a pid, never an argv.\n *\n * Everything is a projection of state the hub already computes; nothing here\n * introduces a new source of truth.\n */\n\nimport type { AuditEntry } from '../types.js';\nimport type { PublicDaemonObservation } from '../daemon/public-observation.js';\nimport type { FrontierEngineUsage } from '../usage/frontier-usage.js';\nimport type { SafetyReport } from '../../cli/verify-safety.js';\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/**\n * Error codes for `/api/verse/{control,caps,scope,audit,daemon,safety}`.\n * `VERSE_INVALID` / `VERSE_TOO_LARGE` are deliberately the SAME codes V1 uses,\n * so one client error mapper covers both halves of the Verse API.\n */\nexport type VerseControlErrorCode =\n | 'VERSE_INVALID'\n | 'VERSE_REFUSED'\n | 'VERSE_TOO_LARGE'\n | 'VERSE_UNAVAILABLE';\n\n/** Every error body on these routes. */\nexport interface VerseControlError {\n error: string;\n code: VerseControlErrorCode;\n}\n\n// ---------------------------------------------------------------------------\n// Caps — the CONFIGURED limits (GET/POST /api/verse/caps)\n// ---------------------------------------------------------------------------\n\n/** One `cfg.foundry.limits[engine]` entry, flattened for transport. */\nexport interface VerseFoundryLimit {\n /** EngineId key, e.g. 'claude' | 'codex'. */\n engine: string;\n /** Rolling window label, e.g. '1m' | '5m' | '1h' | '1d'. */\n window: string;\n /** Max dispatches per window. 0 means \"no dispatches allowed\". */\n max: number;\n}\n\n/** `cfg.daemon.concurrency` — null per tier means \"not configured, using the default\". */\nexport interface VerseCapsConcurrency {\n local: number | null;\n cloud: number | null;\n total: number | null;\n}\n\n/**\n * The configured autonomy limits. These are the values the daemon actually\n * reads — no route exposed them before V2, which is why the cockpit could not\n * show a cap next to the usage burning against it.\n */\nexport interface VerseCaps {\n /** HARD daily spend ceiling (USD). 0 means the daemon is stopped by budget. */\n dailyBudgetUsd: number;\n /** Backlog items processed per tick. */\n perTickItems: number;\n /** Concurrent sandboxed swarms per tick (batch mode). */\n parallel: number;\n /** Tick interval in loop mode (ms). */\n intervalMs: number;\n /** Daemon execution mode. */\n mode: 'batch' | 'continuous';\n /** Ceiling on in-flight dispatches in continuous mode; null when unset. */\n maxConcurrent: number | null;\n /** Per-tier concurrency budgets; null per tier when unset. */\n concurrency: VerseCapsConcurrency;\n /** Subscription-window throttle percentage (1–100). */\n subscriptionMaxPercent: number;\n /** Per-engine dispatch limits, sorted by engine id. */\n foundryLimits: VerseFoundryLimit[];\n /**\n * HONEST STATE: the cap keys whose value is a built-in default rather than\n * something configured on disk. The UI renders these as \"default\", never as\n * a deliberate choice the operator made. Sorted, stable.\n */\n defaulted: VerseCapKey[];\n}\n\n/** The scalar cap keys a client may update. `foundryLimits` is handled separately. */\nexport type VerseCapKey =\n | 'dailyBudgetUsd'\n | 'perTickItems'\n | 'parallel'\n | 'intervalMs'\n | 'mode'\n | 'maxConcurrent'\n | 'concurrency'\n | 'subscriptionMaxPercent'\n | 'foundryLimits';\n\n/** POST /api/verse/caps — a partial update. Unknown keys are rejected. */\nexport interface VerseCapsUpdate {\n dailyBudgetUsd?: number;\n perTickItems?: number;\n parallel?: number;\n intervalMs?: number;\n mode?: 'batch' | 'continuous';\n maxConcurrent?: number;\n concurrency?: { local?: number; cloud?: number; total?: number };\n subscriptionMaxPercent?: number;\n /** Replaces the named engines' limits; engines not listed are left alone. */\n foundryLimits?: VerseFoundryLimit[];\n}\n\n/**\n * POST /api/verse/caps result. `live: true` is not decoration — the daemon\n * re-reads config at the top of every tick, so a saved cap binds on the next\n * tick without a restart.\n */\nexport interface VerseCapsUpdateResult {\n ok: true;\n /** The cap keys this request actually changed, in request order. */\n applied: VerseCapKey[];\n live: true;\n /** The full caps AFTER the write, re-read from disk. */\n caps: VerseCaps;\n}\n\n// ---------------------------------------------------------------------------\n// Scope — the enrollment registry (GET/POST /api/verse/scope)\n// ---------------------------------------------------------------------------\n\nexport interface VerseScopeRepo {\n path: string;\n name: string;\n /** False when the registry still lists a directory that is gone. */\n exists: boolean;\n}\n\n/**\n * GET /api/verse/scope. An EMPTY `repos` with no `degradedReason` is the\n * valid default state and means the daemon will do nothing at all — the UI\n * must say that plainly rather than rendering an innocuous empty list.\n */\nexport interface VerseScope {\n repos: VerseScopeRepo[];\n /** Present only when enrollment authority could not be read at all. */\n degradedReason?: string;\n}\n\nexport type VerseScopeAction = 'enroll' | 'unenroll';\n\n/** POST /api/verse/scope body. */\nexport interface VerseScopeRequest {\n action: VerseScopeAction;\n path: string;\n}\n\nexport interface VerseScopeResult {\n ok: boolean;\n action: VerseScopeAction;\n /** The canonical (realpath'd) registry path this acted on. */\n path: string;\n /** False when the registry already had the requested state (idempotent). */\n changed: boolean;\n /** Policy reason string, e.g. 'enrolled' | 'already-unenrolled'. */\n reason: string;\n /** The scope AFTER the mutation. */\n scope: VerseScope;\n}\n\n// ---------------------------------------------------------------------------\n// Audit (GET /api/verse/audit)\n// ---------------------------------------------------------------------------\n\nexport type VerseAuditResult = AuditEntry['result'];\n\n/** GET /api/verse/audit?limit=&action=&result= */\nexport interface VerseAuditResponse {\n /** Newest first, already filtered, at most `limit` entries. */\n entries: AuditEntry[];\n /** The effective cap applied to `entries` (never above 500). */\n limit: number;\n /** Echo of the applied filter so the UI cannot drift from what it shows. */\n filter: { action: string | null; result: VerseAuditResult | null };\n /** How many raw entries were scanned before filtering. */\n scanned: number;\n /**\n * True when the scan filled its own ceiling, so older entries MAY exist\n * beyond what was read. Conservative by design: it never claims the reader\n * reached the end of history when it cannot prove that.\n */\n truncated: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Kill switch\n// ---------------------------------------------------------------------------\n\n/**\n * The GLOBAL kill switch (`~/.ashlr/KILL`). `state: 'unknown'` is a real,\n * distinct outcome — the sentinel was uninspectable — and must never be\n * rendered as \"off\".\n */\nexport interface VerseKillSwitch {\n state: 'active' | 'inactive' | 'unknown';\n sourceState: 'healthy' | 'degraded';\n reason: string;\n /**\n * Plain-language statement of blast radius, shipped with the state so no\n * surface can show the switch without the warning.\n */\n note: string;\n}\n\n// ---------------------------------------------------------------------------\n// Daemon pause — the NARROW stop (POST /api/verse/daemon {action:'pause'})\n// ---------------------------------------------------------------------------\n\n/**\n * The DAEMON-SCOPED pause sentinel (`~/.ashlr/daemon.paused`), projected for\n * transport. Shares `VerseKillSwitch`'s shape on purpose — both are sentinels\n * read the same way, and both keep `'unknown'` as a real third state that must\n * never render as \"off\".\n *\n * `state: 'unknown'` is treated by the daemon as PAUSED (fail safe), so the UI\n * must say \"paused — the sentinel could not be read\", not \"running\".\n *\n * The sentinel PATH is deliberately absent: it is machine-local detail the\n * cockpit has no use for, the same omission `VerseKillSwitch` makes.\n */\nexport interface VerseDaemonPause {\n /** 'paused' = dispatch halted. 'running' = proven not paused. */\n state: 'paused' | 'running' | 'unknown';\n sourceState: 'healthy' | 'degraded';\n reason: string;\n /** ISO time the pause was requested; null when not paused or unknown. */\n pausedAt: string | null;\n /** Which surface paused it ('cli' | 'verse-control-plane' | 'unknown'). */\n by: string | null;\n /** Plain-language statement of the NARROW blast radius, shipped with the state. */\n note: string;\n}\n\n// ---------------------------------------------------------------------------\n// Daemon lifecycle (POST /api/verse/daemon)\n// ---------------------------------------------------------------------------\n\n/**\n * 'start' launches the autonomous loop detached (exactly `ashlr daemon start`).\n * 'once' runs a single tick the same way.\n *\n * Three stops, three honestly different scopes:\n * - 'pause' — halts autonomous DISPATCH only. Reversible with 'resume'.\n * Leaves the agent's own write tools alone. The default choice.\n * - 'stop' — the ordinary stop, which today engages the GLOBAL kill switch\n * (`stopDaemon()` is `setKill(true)`), so it is wider than a\n * pause and the result's `note` says so.\n * - emergency stop — not on this route at all (`POST /api/fleet/pause`).\n */\nexport type VerseDaemonAction = 'start' | 'stop' | 'once' | 'pause' | 'resume';\n\n/** Non-secret projection of `~/.ashlr/daemon.json`. */\nexport interface VerseDaemonStateProjection {\n running: boolean;\n pid: number | null;\n startedAt: string | null;\n lastTickAt: string | null;\n todayDate: string | null;\n todaySpentUsd: number;\n itemsProcessed: number;\n}\n\n/**\n * POST /api/verse/daemon result. `pid` is the only thing that ever escapes the\n * spawn — the argv, the env, and the resolved launcher path never do.\n */\nexport interface VerseDaemonActionResult {\n ok: boolean;\n action: VerseDaemonAction;\n /** True when a detached child was launched by this request. */\n spawned: boolean;\n /** The detached child's pid for 'start'/'once'; null otherwise. */\n pid: number | null;\n state: VerseDaemonStateProjection;\n killSwitch: VerseKillSwitch;\n /** The daemon-scoped pause AFTER this action. Never folded into killSwitch. */\n pause: VerseDaemonPause;\n /** One line of plain language about what just happened, for the UI to echo. */\n note: string;\n}\n\n// ---------------------------------------------------------------------------\n// Fleet essentials + control aggregate (GET /api/verse/control)\n// ---------------------------------------------------------------------------\n\n/**\n * The small honest slice of FleetStatus/ControlSnapshot the cockpit needs.\n * Deliberately excludes service file paths and error-log paths: the cockpit\n * does not need them, and keeping them out keeps this payload trivially\n * provable as free of machine-local command detail.\n */\nexport interface VerseFleetEssentials {\n /** Mode the autonomy control loop last directed, when known. */\n directionMode: string | null;\n directionAt: string | null;\n directionReason: string | null;\n autonomyControlLoop: boolean;\n autonomyControlMode: string;\n service: {\n registrationState: 'present' | 'absent' | 'unknown';\n installed: boolean;\n running: boolean;\n runtimeState: string | null;\n };\n /** Freshness of the shared fleet-status cache backing these values. */\n freshness: { stale: boolean; ageMs: number };\n}\n\n/** Today's spend against the configured ceiling. */\nexport interface VerseSpend {\n /** null when the daemon ledger could not be read (NOT zero). */\n todayUsd: number | null;\n /** Calendar day the counter applies to; null before the first tick. */\n todayDate: string | null;\n dailyBudgetUsd: number;\n}\n\n/**\n * GET /api/verse/control — the ONE aggregate the Autonomy view reads.\n * Every field is a projection of an existing snapshot; nothing is recomputed.\n */\nexport interface VerseControlSnapshot {\n generatedAt: string;\n daemon: PublicDaemonObservation;\n fleet: VerseFleetEssentials;\n caps: VerseCaps;\n scope: VerseScope;\n killSwitch: VerseKillSwitch;\n /**\n * The DAEMON-SCOPED pause, as its own field. A cockpit that folded this into\n * `killSwitch` would be back to one control with two names; keeping them\n * separate is what lets the Autonomy view render \"paused\" and \"kill switch\n * engaged\" as the different situations they are.\n */\n pause: VerseDaemonPause;\n /** Pending inbox proposals awaiting a human decision. */\n pendingApprovals: number;\n spend: VerseSpend;\n /** Per-engine quota usage against the configured foundry limits. */\n quota: FrontierEngineUsage[];\n /** False when this server was started without --allow-dispatch: all POSTs 404. */\n dispatchEnabled: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Safety (GET /api/verse/safety)\n// ---------------------------------------------------------------------------\n\n/** GET /api/verse/safety — the `ashlr verify-safety --json` report, unmodified. */\nexport type VerseSafetyReport = SafetyReport;\n\n// ---------------------------------------------------------------------------\n// Bounds (single source of truth — the API validator and the UI share these)\n// ---------------------------------------------------------------------------\n\nexport const VERSE_CAPS_BOUNDS = {\n dailyBudgetUsd: { min: 0, max: 1_000 },\n perTickItems: { min: 1, max: 50 },\n parallel: { min: 1, max: 16 },\n intervalMs: { min: 30_000, max: 86_400_000 },\n maxConcurrent: { min: 1, max: 32 },\n /**\n * DELIBERATE DEVIATION from VERSE-CONTRACT-V2's \"concurrency 0-32 each\".\n *\n * The daemon cannot honour a zero tier. `resolveCfg` (daemon/loop.ts) only\n * adopts a tier when it is `> 0`, and `TieredPool`'s constructor floors\n * every cap at `Math.max(1, …)` on top of that — so a stored 0 came back as\n * the built-in 2/6/8 while the cockpit displayed 0. Teaching the pool to\n * accept 0 is not a fix either: `tieredBounded` would then never start a\n * task on that tier and never resolve, i.e. a hung tick.\n *\n * A floor of 1 is therefore the only value that is true in both places. To\n * stop dispatch entirely, the honest lever is `dailyBudgetUsd: 0`, which the\n * daemon now really does obey.\n */\n concurrency: { min: 1, max: 32 },\n subscriptionMaxPercent: { min: 1, max: 100 },\n foundryLimitMax: { min: 0, max: 1_000_000 },\n} as const;\n\n/** Hard ceiling on GET /api/verse/audit `limit`. */\nexport const VERSE_AUDIT_MAX_LIMIT = 500;\n/** Default `limit` when the query omits one. */\nexport const VERSE_AUDIT_DEFAULT_LIMIT = 100;\n/**\n * Hard ceiling on how many raw audit entries a single request will read before\n * filtering. Bounds the work a filtered query can ask of the disk.\n */\nexport const VERSE_AUDIT_MAX_SCAN = 5_000;\n\n/** The kill switch's blast-radius warning — one string, used everywhere. */\nexport const VERSE_KILL_SWITCH_NOTE =\n 'Emergency stop: the global kill switch also refuses the agent\\'s own write tools, not just the daemon. Use the daemon pause action for an ordinary, reversible halt.';\n\n/**\n * The pause's blast-radius statement — the counterpart to\n * VERSE_KILL_SWITCH_NOTE, shipped with every pause projection so no surface\n * can show the state without the scope. Says what it does NOT do, because\n * that is the entire difference from the control next to it.\n */\nexport const VERSE_DAEMON_PAUSE_NOTE =\n 'Pause: halts autonomous dispatch only. Your own write tools keep working, nothing in flight is rolled back, and Resume restores the loop without a restart.';\n","/**\n * routes/verse/autonomy/control-queries.ts — every `/api/verse/{control,caps,\n * scope,audit,daemon,safety}` call the Autonomy cockpit makes, plus the two\n * existing read-only feeds it borrows (`/api/goals`, `/api/backlog`).\n *\n * Same contract as routes/verse/verse-queries.ts: reads are QueryDefs consumed\n * through useQuery (cache-backed, so a background refresh never blanks a\n * populated panel); writes pull the held mutation token from auth-store, touch\n * the hold on success, and invalidate exactly the keys they affect.\n *\n * Two deliberate choices worth knowing before editing:\n *\n * 1. **The envelopes are now fixed, so nothing is normalized.**\n * `/api/verse/scope` and `/api/verse/audit` are declared in\n * `src/core/verse/control-types.ts` (`VerseScope`, `VerseAuditResponse`)\n * and the handlers serialize exactly those, so these fetchers are typed\n * straight through. The speculative bare-array/wrapper normalization that\n * let this surface ship before the routes existed has been deleted.\n * `/api/backlog` keeps its normalizer — that route really does answer\n * `loadBacklog() ?? null` and is not part of the V2 contract.\n * 2. **Emergency stop is not a route of its own.** The global kill switch is\n * `POST /api/fleet/pause` (and `/resume` to clear), already wrapped in\n * data/mutations.ts. It is re-exported here under honest names so no call\n * site in this folder can accidentally call it \"pause\".\n */\nimport { VERSE_AUDIT_MAX_LIMIT } from './control-types.js';\nimport type { GoalSummary, QueryDef } from '../../../data/queries.js';\nimport { getMutationToken, touchMutationHold } from '../../../data/auth-store.js';\nimport { apiGet, apiPost } from '../../../data/client.js';\nimport { invalidate } from '../../../data/cache.js';\nimport { pauseFleet, resumeFleet } from '../../../data/mutations.js';\nimport type {\n VerseAuditFilters,\n VerseAuditPage,\n VerseCaps,\n VerseCapsApplyResult,\n VerseCapsPatch,\n VerseControlSnapshot,\n VerseDaemonAction,\n VerseDaemonActionResult,\n VerseSafetyReport,\n VerseScope,\n VerseScopePatch,\n} from './control-types.js';\n\nexport const VERSE_CONTROL_KEY = 'verse-control';\nexport const VERSE_CAPS_KEY = 'verse-caps';\nexport const VERSE_SCOPE_KEY = 'verse-scope';\nexport const VERSE_SAFETY_KEY = 'verse-safety';\nexport const VERSE_AUDIT_PREFIX = 'verse-audit:';\n\n/**\n * Server-side cap on `/api/verse/audit`, re-exported from the backend\n * contract module so the client cannot drift from the value the route\n * actually clamps to.\n */\nexport const VERSE_AUDIT_MAX = VERSE_AUDIT_MAX_LIMIT;\n/** Enough rows that the table is the real \"while I was asleep\" view. */\nexport const VERSE_AUDIT_DEFAULT_LIMIT = 200;\n\nexport const verseControlQuery: QueryDef<VerseControlSnapshot> = {\n key: VERSE_CONTROL_KEY,\n fetch: (signal) => apiGet<VerseControlSnapshot>('/api/verse/control', signal),\n};\n\nexport const verseCapsQuery: QueryDef<VerseCaps> = {\n key: VERSE_CAPS_KEY,\n fetch: (signal) => apiGet<VerseCaps>('/api/verse/caps', signal),\n};\n\nexport const verseSafetyQuery: QueryDef<VerseSafetyReport> = {\n key: VERSE_SAFETY_KEY,\n fetch: (signal) => apiGet<VerseSafetyReport>('/api/verse/safety', signal),\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport const verseScopeQuery: QueryDef<VerseScope> = {\n key: VERSE_SCOPE_KEY,\n fetch: (signal) => apiGet<VerseScope>('/api/verse/scope', signal),\n};\n\nexport function verseAuditQuery(filters: VerseAuditFilters = {}): QueryDef<VerseAuditPage> {\n const limit = Math.min(filters.limit ?? VERSE_AUDIT_DEFAULT_LIMIT, VERSE_AUDIT_MAX);\n const params = new URLSearchParams();\n params.set('limit', String(limit));\n if (filters.action) params.set('action', filters.action);\n if (filters.result) params.set('result', filters.result);\n return {\n key: `${VERSE_AUDIT_PREFIX}${limit}:${filters.action ?? ''}:${filters.result ?? ''}`,\n fetch: (signal) => apiGet<VerseAuditPage>(`/api/verse/audit?${params.toString()}`, signal),\n };\n}\n\n/**\n * Read-only in V2 — the contract is explicit that no goal-mutation routes get\n * built here. `/api/goals` returns a bare array; `/api/backlog` returns\n * `loadBacklog() ?? null`, i.e. `null` is \"no backlog on disk\", not an error.\n */\nexport const verseGoalsQuery: QueryDef<GoalSummary[]> = {\n key: 'goals',\n fetch: (signal) => apiGet<GoalSummary[]>('/api/goals', signal),\n};\n\n/** One backlog row, narrowed to what the read-only summary renders. */\nexport interface VerseBacklogItem {\n id?: string;\n title?: string;\n repo?: string;\n score?: number;\n source?: string;\n}\n\nexport interface VerseBacklogSummary {\n items: VerseBacklogItem[];\n /** True when the server answered `null` — no backlog has been built yet. */\n absent: boolean;\n}\n\nexport function normalizeBacklog(raw: unknown): VerseBacklogSummary {\n if (raw === null || raw === undefined) return { items: [], absent: true };\n if (Array.isArray(raw)) return { items: raw as VerseBacklogItem[], absent: false };\n if (isRecord(raw) && Array.isArray(raw['items'])) {\n return { items: raw['items'] as VerseBacklogItem[], absent: false };\n }\n return { items: [], absent: true };\n}\n\nexport const verseBacklogQuery: QueryDef<VerseBacklogSummary> = {\n key: 'backlog',\n fetch: (signal) => apiGet<unknown>('/api/backlog', signal).then(normalizeBacklog),\n};\n\n// ---------------------------------------------------------------------------\n// Writes\n// ---------------------------------------------------------------------------\n\n/** Thrown before any network call when no mutation token is held. */\nexport class VerseControlLockedError extends Error {\n constructor() {\n super('Unlock actions with the mutation token before changing the loop.');\n this.name = 'VerseControlLockedError';\n }\n}\n\nasync function post<T>(path: string, body: unknown): Promise<T> {\n const token = getMutationToken();\n if (!token) throw new VerseControlLockedError();\n const result = await apiPost<T>(path, body, token);\n touchMutationHold();\n return result;\n}\n\n/** Every panel in the cockpit reads through one of these three. */\nexport function invalidateControl(): void {\n invalidate(VERSE_CONTROL_KEY);\n}\n\nexport async function updateVerseCaps(patch: VerseCapsPatch): Promise<VerseCapsApplyResult> {\n const result = await post<VerseCapsApplyResult>('/api/verse/caps', patch);\n invalidate(VERSE_CAPS_KEY);\n invalidateControl();\n return result;\n}\n\nexport async function updateVerseScope(patch: VerseScopePatch): Promise<void> {\n await post<unknown>('/api/verse/scope', patch);\n invalidate(VERSE_SCOPE_KEY);\n invalidateControl();\n}\n\nexport async function runDaemonAction(action: VerseDaemonAction): Promise<VerseDaemonActionResult> {\n const result = await post<VerseDaemonActionResult>('/api/verse/daemon', { action });\n invalidateControl();\n invalidate('daemon');\n return result;\n}\n\n/**\n * ENGAGE the global kill switch (`~/.ashlr/KILL`). This is `POST\n * /api/fleet/pause` under its honest name: it stops the daemon AND refuses\n * the agent's own mcp-native write tools. Never surface it as \"pause\".\n */\nexport async function engageEmergencyStop(): Promise<void> {\n await pauseFleet();\n invalidateControl();\n}\n\n/** Clear the kill switch — writes become possible again fleet-wide. */\nexport async function releaseEmergencyStop(): Promise<void> {\n await resumeFleet();\n invalidateControl();\n}\n","/**\n * routes/verse/autonomy/use-guarded-action.ts — the one place a Verse control\n * surface turns \"the operator clicked something destructive\" into an actual\n * request. Shared by the Autonomy cockpit and the Approvals surface.\n *\n * It folds together the three things every mutating click in this app has to\n * do, which were previously re-implemented per call site:\n *\n * - **Token hand-off.** No mutation hold yet → remember the action, open\n * MutationTokenDialog, and run it once the token lands. The hold is read\n * LIVE on dialog close, never from a render-time snapshot, because\n * MutationTokenDialog's onClose fires before this component re-renders.\n * - **Read-only sessions.** Every POST 404s when the server was started\n * without dispatch. That is a session mode, not a failure, so it flips a\n * `readOnly` flag the surface renders as an explanation — never as an error\n * toast and never as a crash.\n * - **Busy + error state** for exactly one in-flight action at a time.\n */\nimport { useCallback, useRef, useState } from 'react';\nimport { hasMutationHold } from '../../../data/auth-store.js';\nimport { ApiError, DispatchDisabledError } from '../../../data/client.js';\nimport { VerseControlLockedError } from './control-queries.js';\n\nexport function describeControlError(err: unknown): string {\n if (err instanceof DispatchDisabledError) return 'This server runs without dispatch, so that action is unavailable.';\n if (err instanceof VerseControlLockedError) return err.message;\n if (err instanceof ApiError) {\n if (err.status === 401) return 'The mutation token was rejected. Unlock again with the token `ashlr verse` printed.';\n // The control plane writes a careful refusal ladder — \"no repositories are\n // enrolled, so the loop would do nothing. Add scope first.\" — and returns\n // it as `note` on the 409 body. A blanket \"something else is already\n // running\" replaced every one of those with a sentence that was usually\n // false and never actionable. Show the server's own words whenever it\n // sent any; the generic line is now only the last resort.\n if (err.detail) return err.detail;\n if (err.status === 400) return err.message;\n if (err.status === 409) return 'The server refused the action, and sent no reason.';\n return err.message;\n }\n return err instanceof Error ? err.message : 'That action failed. Try again.';\n}\n\nexport interface GuardedAction {\n /**\n * Run `fn`, prompting for the mutation token first when none is held.\n *\n * `onResult` receives `fn`'s resolved value when it succeeds. It exists\n * because the value was previously dropped on the floor, and for the daemon\n * routes that value carries the server's own account of what just happened\n * (`VerseDaemonActionResult.note` — e.g. that an ordinary stop also engaged\n * the global kill switch). It is not called when `fn` throws.\n */\n request: <T>(fn: () => Promise<T>, reason: string, onResult?: (result: T) => void) => void;\n busy: boolean;\n error: string | null;\n clearError: () => void;\n /** True once a POST 404'd — the server has no dispatch enabled. */\n readOnly: boolean;\n /** Bind these three to <MutationTokenDialog/>. */\n tokenOpen: boolean;\n tokenReason: string;\n closeToken: () => void;\n}\n\nexport function useGuardedAction(): GuardedAction {\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [readOnly, setReadOnly] = useState(false);\n const [tokenOpen, setTokenOpen] = useState(false);\n const [tokenReason, setTokenReason] = useState('');\n // The deferred action and the callback that wants its result travel together\n // — the token dialog may run it a render later, long after `request` returned.\n const pending = useRef<{ fn: () => Promise<unknown>; onResult?: (result: never) => void } | null>(null);\n\n const perform = useCallback(\n async (fn: () => Promise<unknown>, onResult?: (result: never) => void) => {\n setBusy(true);\n setError(null);\n try {\n const result = await fn();\n onResult?.(result as never);\n } catch (err) {\n if (err instanceof DispatchDisabledError) setReadOnly(true);\n else setError(describeControlError(err));\n } finally {\n setBusy(false);\n }\n },\n [],\n );\n\n const request = useCallback(\n <T,>(fn: () => Promise<T>, reason: string, onResult?: (result: T) => void) => {\n setError(null);\n const handler = onResult as ((result: never) => void) | undefined;\n if (hasMutationHold()) {\n void perform(fn, handler);\n return;\n }\n pending.current = { fn, onResult: handler };\n setTokenReason(reason);\n setTokenOpen(true);\n },\n [perform],\n );\n\n const closeToken = useCallback(() => {\n setTokenOpen(false);\n const next = pending.current;\n pending.current = null;\n // Live read: the dialog closes synchronously after setToken().\n if (next && hasMutationHold()) void perform(next.fn, next.onResult);\n }, [perform]);\n\n const clearError = useCallback(() => setError(null), []);\n\n return { request, busy, error, clearError, readOnly, tokenOpen, tokenReason, closeToken };\n}\n"],"mappings":"gMAmYA,IAAa,EAAoB,CAC/B,eAAgB,CAAE,IAAK,EAAG,IAAK,GAAM,EACrC,aAAc,CAAE,IAAK,EAAG,IAAK,EAAG,EAChC,SAAU,CAAE,IAAK,EAAG,IAAK,EAAG,EAC5B,WAAY,CAAE,IAAK,IAAQ,IAAK,KAAW,EAC3C,cAAe,CAAE,IAAK,EAAG,IAAK,EAAG,EAejC,YAAa,CAAE,IAAK,EAAG,IAAK,EAAG,EAC/B,uBAAwB,CAAE,IAAK,EAAG,IAAK,GAAI,EAC3C,gBAAiB,CAAE,IAAK,EAAG,IAAK,GAAU,CAC5C,aC7Wa,EAAoB,gBACpB,EAAiB,aACjB,EAAkB,cAClB,EAAmB,eACnB,EAAqB,eAOrB,EAAA,IAIA,EAAoD,CAC/D,IAAK,EACL,MAAQ,GAAW,EAA6B,qBAAsB,CAAM,CAC9E,EAEa,EAAsC,CACjD,IAAK,EACL,MAAQ,GAAW,EAAkB,kBAAmB,CAAM,CAChE,EAEa,EAAgD,CAC3D,IAAK,EACL,MAAQ,GAAW,EAA0B,oBAAqB,CAAM,CAC1E,EAEA,SAAS,EAAS,EAAkD,CAClE,OAAO,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,CAAK,CAC5E,CAEA,IAAa,EAAwC,CACnD,IAAK,EACL,MAAQ,GAAW,EAAmB,mBAAoB,CAAM,CAClE,EAEA,SAAgB,EAAgB,EAA6B,CAAC,EAA6B,CACzF,IAAM,EAAQ,KAAK,IAAI,EAAQ,OAAA,IAAoC,CAAe,EAC5E,EAAS,IAAI,gBAInB,OAHA,EAAO,IAAI,QAAS,OAAO,CAAK,CAAC,EAC7B,EAAQ,QAAQ,EAAO,IAAI,SAAU,EAAQ,MAAM,EACnD,EAAQ,QAAQ,EAAO,IAAI,SAAU,EAAQ,MAAM,EAChD,CACL,IAAK,GAAG,IAAqB,EAAM,GAAG,EAAQ,QAAU,GAAG,GAAG,EAAQ,QAAU,KAChF,MAAQ,GAAW,EAAuB,oBAAoB,EAAO,SAAS,IAAK,CAAM,CAC3F,CACF,CAOA,IAAa,EAA2C,CACtD,IAAK,QACL,MAAQ,GAAW,EAAsB,aAAc,CAAM,CAC/D,EAiBA,SAAgB,EAAiB,EAAmC,CAMlE,OALI,GAAQ,KAAkC,CAAE,MAAO,CAAC,EAAG,OAAQ,EAAK,EACpE,MAAM,QAAQ,CAAG,EAAU,CAAE,MAAO,EAA2B,OAAQ,EAAM,EAC7E,EAAS,CAAG,GAAK,MAAM,QAAQ,EAAI,KAAQ,EACtC,CAAE,MAAO,EAAI,MAAgC,OAAQ,EAAM,EAE7D,CAAE,MAAO,CAAC,EAAG,OAAQ,EAAK,CACnC,CAEA,IAAa,EAAmD,CAC9D,IAAK,UACL,MAAQ,GAAW,EAAgB,eAAgB,CAAM,CAAC,CAAC,KAAK,CAAgB,CAClF,EAOa,EAAb,cAA6C,KAAM,CACjD,aAAc,CACZ,MAAM,kEAAkE,EACxE,KAAK,KAAO,yBACd,CACF,EAEA,eAAe,EAAQ,EAAc,EAA2B,CAC9D,IAAM,EAAQ,EAAiB,EAC/B,GAAI,CAAC,EAAO,MAAM,IAAI,EACtB,IAAM,EAAS,MAAM,EAAW,EAAM,EAAM,CAAK,EAEjD,OADA,EAAkB,EACX,CACT,CAGA,SAAgB,GAA0B,CACxC,EAAW,CAAiB,CAC9B,CAEA,eAAsB,EAAgB,EAAsD,CAC1F,IAAM,EAAS,MAAM,EAA2B,kBAAmB,CAAK,EAGxE,OAFA,EAAW,CAAc,EACzB,EAAkB,EACX,CACT,CAEA,eAAsB,EAAiB,EAAuC,CAC5E,MAAM,EAAc,mBAAoB,CAAK,EAC7C,EAAW,CAAe,EAC1B,EAAkB,CACpB,CAEA,eAAsB,EAAgB,EAA6D,CACjG,IAAM,EAAS,MAAM,EAA8B,oBAAqB,CAAE,QAAO,CAAC,EAGlF,OAFA,EAAkB,EAClB,EAAW,QAAQ,EACZ,CACT,CAOA,eAAsB,GAAqC,CACzD,MAAM,EAAW,EACjB,EAAkB,CACpB,CAGA,eAAsB,GAAsC,CAC1D,MAAM,EAAY,EAClB,EAAkB,CACpB,CC3KA,SAAgB,EAAqB,EAAsB,CAgBzD,OAfI,aAAe,EAA8B,oEAC7C,aAAe,EAAgC,EAAI,QACnD,aAAe,EACb,EAAI,SAAW,IAAY,sFAO3B,EAAI,OAAe,EAAI,OACvB,EAAI,SAAW,IAAY,EAAI,QAC/B,EAAI,SAAW,IAAY,qDACxB,EAAI,QAEN,aAAe,MAAQ,EAAI,QAAU,gCAC9C,CAwBA,SAAgB,GAAkC,CAChD,GAAM,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAS,EAAK,EAChC,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAwB,IAAI,EAChD,CAAC,EAAU,IAAA,EAAe,EAAA,SAAA,CAAS,EAAK,EACxC,CAAC,EAAW,IAAA,EAAgB,EAAA,SAAA,CAAS,EAAK,EAC1C,CAAC,EAAa,IAAA,EAAkB,EAAA,SAAA,CAAS,EAAE,EAG3C,GAAA,EAAU,EAAA,OAAA,CAAkF,IAAI,EAEhG,GAAA,EAAU,EAAA,YAAA,CACd,MAAO,EAA4B,IAAuC,CACxE,EAAQ,EAAI,EACZ,EAAS,IAAI,EACb,GAAI,CACF,IAAM,EAAS,MAAM,EAAG,EACxB,IAAW,CAAe,CAC5B,OAAS,EAAK,CACR,aAAe,EAAuB,EAAY,EAAI,EACrD,EAAS,EAAqB,CAAG,CAAC,CACzC,QAAU,CACR,EAAQ,EAAK,CACf,CACF,EACA,CAAC,CACH,EAEM,GAAA,EAAU,EAAA,YAAA,EACT,EAAsB,EAAgB,IAAmC,CAC5E,EAAS,IAAI,EACb,IAAM,EAAU,EAChB,GAAI,EAAgB,EAAG,CACrB,EAAa,EAAI,CAAO,EACxB,MACF,CACA,EAAQ,QAAU,CAAE,KAAI,SAAU,CAAQ,EAC1C,EAAe,CAAM,EACrB,EAAa,EAAI,CACnB,EACA,CAAC,CAAO,CACV,EAEM,GAAA,EAAa,EAAA,YAAA,KAAkB,CACnC,EAAa,EAAK,EAClB,IAAM,EAAO,EAAQ,QACrB,EAAQ,QAAU,KAEd,GAAQ,EAAgB,GAAG,EAAa,EAAK,GAAI,EAAK,QAAQ,CACpE,EAAG,CAAC,CAAO,CAAC,EAIZ,MAAO,CAAE,UAAS,OAAM,QAAO,YAAA,EAFZ,EAAA,YAAA,KAAkB,EAAS,IAAI,EAAG,CAAC,CAEvB,EAAY,WAAU,YAAW,cAAa,YAAW,CAC1F"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{u as e}from"./verse-model-CvtK6vP6.js";function t(e){if(e.git===null)return null;let t=[e.git.branch];return t.push(e.git.dirty===0?`clean`:`${e.git.dirty} changed`),e.git.ahead>0&&t.push(`${e.git.ahead} ahead`),e.git.behind>0&&t.push(`${e.git.behind} behind`),t.join(` · `)}function n(e){return e.exists?e.reachable?e.primary?`primary`:`extra`:`unreachable`:`missing`}function r(e){return e.exists?e.reachable?e.enrolled?null:`not enrolled — autonomous lane refuses it`:`this engine cannot reach it`:`missing on disk`}var i={critical:`Critical`,high:`High`,normal:`Normal`,low:`Low`},a=[`critical`,`high`,`normal`,`low`],o=`Priority orders the repositories the fleet already has. It never adds one — a repository that is not enrolled stays out of reach at every priority.`;function s(e,t){return t?.[e]??`normal`}function c(t,n){let r=t.trim();if(r.length===0)return{ok:!1,error:`Pick a primary folder.`,roots:[]};if(!e(r))return{ok:!1,error:`The primary folder must be an absolute path on this machine.`,roots:[]};let i=[r];for(let t of n){let n=t.trim();if(n.length!==0){if(!e(n))return{ok:!1,error:`Not an absolute path: ${n}`,roots:[]};i.includes(n)||i.push(n)}}return i.length>8?{ok:!1,error:`A workspace holds at most 8 folders.`,roots:[]}:{ok:!0,error:null,roots:i}}function l(e){return(e.roots.find(e=>e.primary)??e.roots[0])?.path??null}function u(e){return e.roots.length-1<=0?`1 folder`:`${e.roots.length} folders`}function d(e){let t=e.roots.find(e=>e.primary);return t?[t,...e.roots.filter(e=>e!==t)]:[...e.roots]}function f(e){return d(e).map(e=>e.path)}function p(e){return e==null||e===`claude`||e===`codex`||e===`local`}var m=`This seat’s CLI takes no additional-directory flag, so it will reach only the primary folder. The other folders will be unreachable — pick a Claude, Codex or local seat to use more than one.`;function h(e,t){return t<=1||p(e)?null:m}function g(e,t){return t<=1?null:h(e,t)??`The agent can read and write these folders for the life of this chat. Enrolment is separate — an unenrolled folder stays out of reach of the autonomous lane.`}var _=`Claude, Codex and local seats reach every folder here. A Grok seat reaches only the primary one.`;function v(e){let t=e.trim().replace(/[/\\]+$/,``),n=t.split(/[/\\]/).pop()??``;return n.length>0?n:t}function y(e,t){let[n=``,...r]=t,i=c(n,r);if(!i.ok)return{ok:!1,error:i.error,name:``,roots:[]};let a=e.trim(),o=a.length>0?a:v(i.roots[0]);return o.length===0?{ok:!1,error:`Give this project a name.`,name:``,roots:[]}:{ok:!0,error:null,name:o,roots:i.roots}}function b(e,t,n){let r=[...e],i=n===`up`?t-1:t+1;if(t<0||t>=r.length||i<0||i>=r.length)return r;let a=r[t];return r[t]=r[i],r[i]=a,r}function x(e){return e===0?`Primary folder`:`Folder ${e+1}`}export{f as _,v as a,b as c,t as d,x as f,l as g,y as h,a as i,s as l,c as m,i as n,h as o,n as p,o as r,g as s,_ as t,r as u,u as v};
|
|
2
|
+
//# sourceMappingURL=workspace-model-v0a1gl-C.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-model-v0a1gl-C.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/workspace-model.ts"],"sourcesContent":["/**\n * routes/verse/workspace-model.ts — pure helpers for multi-root sessions.\n * No React, no I/O, so every rule below is testable without a DOM.\n *\n * The honesty rules these encode, and why each exists:\n *\n * - A root with no git repo shows \"not a git repo\", never a blank space where\n * a branch would be. An empty slot reads as \"clean on the default branch\".\n * - `dirty` is a COUNT of changed entries, so it is rendered as a count.\n * \"modified\" alone hides whether that is one file or forty.\n * - An unenrolled root says the autonomous lane refuses it, rather than\n * showing a warning that could be read as \"this chat cannot use it\" — it\n * can, and does.\n * - An unreachable root (a Grok seat, which has no additional-directory flag)\n * is listed and marked, never hidden. Hiding it would misrepresent the\n * workspace the operator chose.\n */\nimport type {\n VerseEngine,\n VerseRootPriority,\n VerseRootStatus,\n VerseSession,\n VerseWorkspace,\n VerseWorkspaceRoot,\n} from '../../data/api-types.js';\nimport { isAbsolutePath } from './verse-model.js';\n\n/** Hard cap, mirroring VERSE_MAX_WORKSPACE_ROOTS on the server. */\nexport const MAX_WORKSPACE_ROOTS = 8;\n\n/** Every root a session can reach, primary first. Mirrors `verseSessionRoots`. */\nexport function sessionRootPaths(session: Pick<VerseSession, 'projectPath' | 'extraRoots'>): string[] {\n const out = [session.projectPath];\n for (const root of session.extraRoots ?? []) {\n if (typeof root === 'string' && root.length > 0 && !out.includes(root)) out.push(root);\n }\n return out;\n}\n\n/** True when this session reaches more than its primary folder. */\nexport function isMultiRoot(session: Pick<VerseSession, 'projectPath' | 'extraRoots'>): boolean {\n return sessionRootPaths(session).length > 1;\n}\n\n/**\n * Short label for a session's folder scope: the primary's name, plus how many\n * more it carries. Used where only one line fits (a sidebar row, a pill).\n */\nexport function rootScopeLabel(\n session: Pick<VerseSession, 'projectPath' | 'extraRoots'>,\n primaryName: string,\n): string {\n const extra = sessionRootPaths(session).length - 1;\n return extra > 0 ? `${primaryName} +${extra}` : primaryName;\n}\n\n/**\n * One line of git identity for a root.\n *\n * Returns null when the root is not a repo, so the caller renders the \"not a\n * git repo\" wording ONCE rather than each caller inventing its own.\n */\nexport function rootGitLine(root: VerseRootStatus): string | null {\n if (root.git === null) return null;\n const parts = [root.git.branch];\n parts.push(root.git.dirty === 0 ? 'clean' : `${root.git.dirty} changed`);\n if (root.git.ahead > 0) parts.push(`${root.git.ahead} ahead`);\n if (root.git.behind > 0) parts.push(`${root.git.behind} behind`);\n return parts.join(' · ');\n}\n\nexport type RootTone = 'primary' | 'extra' | 'unreachable' | 'missing';\n\n/** Which visual treatment a root row gets. Missing beats unreachable. */\nexport function rootTone(root: VerseRootStatus): RootTone {\n if (!root.exists) return 'missing';\n if (!root.reachable) return 'unreachable';\n return root.primary ? 'primary' : 'extra';\n}\n\n/**\n * The plain-language caveat for one root, or null when there is nothing to\n * say. Word, never colour alone (DESIGN-V2 §6).\n */\nexport function rootCaveat(root: VerseRootStatus): string | null {\n if (!root.exists) return 'missing on disk';\n if (!root.reachable) return 'this engine cannot reach it';\n if (!root.enrolled) return 'not enrolled — autonomous lane refuses it';\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Priority\n// ---------------------------------------------------------------------------\n\nexport const ROOT_PRIORITY_LABEL: Record<VerseRootPriority, string> = {\n critical: 'Critical',\n high: 'High',\n normal: 'Normal',\n low: 'Low',\n};\n\nexport const ROOT_PRIORITY_ORDER: readonly VerseRootPriority[] =\n ['critical', 'high', 'normal', 'low'];\n\n/**\n * How a priority must be explained wherever it is offered.\n *\n * Priority orders what the autonomous lane already reaches. It is NOT a grant,\n * and the copy has to say so at the point of the choice — otherwise ranking a\n * repo `critical` reads as turning it on.\n */\nexport const ROOT_PRIORITY_NOTE =\n 'Priority orders the repositories the fleet already has. It never adds one — a repository that is not enrolled stays out of reach at every priority.';\n\n/**\n * Sort weight; lower sorts first. Mirrors `VERSE_ROOT_PRIORITY_RANK` on the\n * server so the list the operator re-ranks here and the list the autonomous\n * lane walks cannot be ordered differently.\n */\nexport const ROOT_PRIORITY_RANK: Record<VerseRootPriority, number> = {\n critical: 0,\n high: 1,\n normal: 2,\n low: 3,\n};\n\n/** A path's priority, treating an absent key as `normal` (as the server does). */\nexport function priorityOf(\n path: string,\n priorities: Readonly<Record<string, VerseRootPriority>> | undefined,\n): VerseRootPriority {\n return priorities?.[path] ?? 'normal';\n}\n\n/**\n * Paths most-important-first.\n *\n * STABLE: two paths at the same priority keep the order they were given, so\n * re-ranking one repo never silently shuffles the rest. Ordering only — this\n * neither adds nor removes a path.\n */\nexport function rankPathsByPriority(\n paths: readonly string[],\n priorities: Readonly<Record<string, VerseRootPriority>> | undefined,\n): string[] {\n return paths\n .map((path, index) => ({ path, index, rank: ROOT_PRIORITY_RANK[priorityOf(path, priorities)] }))\n .sort((a, b) => a.rank - b.rank || a.index - b.index)\n .map((entry) => entry.path);\n}\n\n// ---------------------------------------------------------------------------\n// Root-set editing (the new-chat dialog and the workspace editor share this)\n// ---------------------------------------------------------------------------\n\nexport interface RootSetValidation {\n ok: boolean;\n /** One message, or null when the set is usable. */\n error: string | null;\n /** The set as it would be sent: trimmed, de-duplicated, primary first. */\n roots: string[];\n}\n\n/**\n * Validate a root set typed by hand.\n *\n * COURTESY ONLY. The server re-checks every path against the same deny roots\n * the enrollment registry uses, and it is the authority — this cannot know the\n * real home directory behind a `~`, and it must not pretend to.\n */\nexport function validateRootSet(primary: string, extras: readonly string[]): RootSetValidation {\n const trimmedPrimary = primary.trim();\n if (trimmedPrimary.length === 0) {\n return { ok: false, error: 'Pick a primary folder.', roots: [] };\n }\n if (!isAbsolutePath(trimmedPrimary)) {\n return { ok: false, error: 'The primary folder must be an absolute path on this machine.', roots: [] };\n }\n const roots = [trimmedPrimary];\n for (const raw of extras) {\n const root = raw.trim();\n if (root.length === 0) continue;\n if (!isAbsolutePath(root)) {\n return { ok: false, error: `Not an absolute path: ${root}`, roots: [] };\n }\n if (roots.includes(root)) continue;\n roots.push(root);\n }\n if (roots.length > MAX_WORKSPACE_ROOTS) {\n return { ok: false, error: `A workspace holds at most ${MAX_WORKSPACE_ROOTS} folders.`, roots: [] };\n }\n return { ok: true, error: null, roots };\n}\n\n/** The primary root of a stored workspace (the one a session uses as its cwd). */\nexport function workspacePrimary(workspace: VerseWorkspace): string | null {\n return (workspace.roots.find((r) => r.primary) ?? workspace.roots[0])?.path ?? null;\n}\n\n/** \"service +2 folders\" — how a workspace reads in a picker. */\nexport function workspaceSummary(workspace: VerseWorkspace): string {\n const extra = workspace.roots.length - 1;\n if (extra <= 0) return '1 folder';\n return `${workspace.roots.length} folders`;\n}\n\n/**\n * A workspace's roots in SEND order: the primary first, then the rest as\n * stored.\n *\n * `VerseWorkspace.roots` is documented primary-first, but the flag is the\n * authority and an update replaces the set wholesale with \"first entry is\n * primary\". Normalising here means a reorder can never accidentally demote\n * the primary because a stored record listed it second.\n */\nexport function orderedWorkspaceRoots(workspace: VerseWorkspace): VerseWorkspaceRoot[] {\n const primary = workspace.roots.find((r) => r.primary);\n if (!primary) return [...workspace.roots];\n return [primary, ...workspace.roots.filter((r) => r !== primary)];\n}\n\n/** The same order, as the bare paths `updateVerseWorkspace` takes. */\nexport function workspaceRootPaths(workspace: VerseWorkspace): string[] {\n return orderedWorkspaceRoots(workspace).map((r) => r.path);\n}\n\n// ---------------------------------------------------------------------------\n// Which engines reach more than the primary folder\n// ---------------------------------------------------------------------------\n\n/**\n * Whether this engine's CLI takes an additional-directory flag.\n *\n * Mirrors `engineSupportsExtraRoots` in src/core/verse/workspaces.ts. Grok\n * exposes no such flag at all (checked on grok 0.2.118), so a Grok seat gets\n * its primary root and nothing else — and the UI has to SAY that at the point\n * the seat is chosen rather than let the operator discover it from a diff that\n * never applies.\n *\n * `null` (no seat picked yet) reaches everything: there is nothing to warn\n * about until a seat exists.\n */\nexport function engineReachesExtraRoots(engine: VerseEngine | null | undefined): boolean {\n if (engine === null || engine === undefined) return true;\n return engine === 'claude' || engine === 'codex' || engine === 'local';\n}\n\nexport const EXTRA_ROOTS_REACHABLE_NOTE =\n 'The agent can read and write these folders for the life of this chat. Enrolment is separate — an unenrolled folder stays out of reach of the autonomous lane.';\n\nexport const EXTRA_ROOTS_UNREACHABLE_NOTE =\n 'This seat’s CLI takes no additional-directory flag, so it will reach only the primary folder. The other folders will be unreachable — pick a Claude, Codex or local seat to use more than one.';\n\n/**\n * The caveat for handing `rootCount` folders to a seat, or null when there is\n * nothing to warn about. Only ever the BAD news, so a caller can render it as\n * a warning without having to decide which sentence it got.\n */\nexport function extraRootsCaveat(\n engine: VerseEngine | null | undefined,\n rootCount: number,\n): string | null {\n if (rootCount <= 1) return null;\n return engineReachesExtraRoots(engine) ? null : EXTRA_ROOTS_UNREACHABLE_NOTE;\n}\n\n/** The full note for a multi-folder set: the caveat when there is one, the\n * enrolment reminder otherwise. Null when only one folder is in play. */\nexport function extraRootsNote(\n engine: VerseEngine | null | undefined,\n rootCount: number,\n): string | null {\n if (rootCount <= 1) return null;\n return extraRootsCaveat(engine, rootCount) ?? EXTRA_ROOTS_REACHABLE_NOTE;\n}\n\n/** Said once wherever a multi-folder project is DEFINED, where no seat is\n * chosen yet and so no per-seat caveat can be given. */\nexport const MULTI_ROOT_ENGINE_NOTE =\n 'Claude, Codex and local seats reach every folder here. A Grok seat reaches only the primary one.';\n\n// ---------------------------------------------------------------------------\n// Saved projects (the create/edit form behind the workspace routes)\n// ---------------------------------------------------------------------------\n\n/** The folder's own name, used when the operator names nothing. */\nexport function defaultWorkspaceName(primaryPath: string): string {\n const trimmed = primaryPath.trim().replace(/[/\\\\]+$/, '');\n const base = trimmed.split(/[/\\\\]/).pop() ?? '';\n return base.length > 0 ? base : trimmed;\n}\n\nexport interface WorkspaceDraftValidation {\n ok: boolean;\n /** One message, or null when the draft is sendable. */\n error: string | null;\n /** The name as it would be sent — never empty when `ok`. */\n name: string;\n /** Trimmed, de-duplicated, primary first. */\n roots: string[];\n}\n\n/**\n * Validate a saved project before it is sent.\n *\n * COURTESY ONLY, exactly like `validateRootSet`: the server re-checks every\n * path against the enrollment registry's deny roots and is the authority.\n */\nexport function validateWorkspaceDraft(\n name: string,\n roots: readonly string[],\n): WorkspaceDraftValidation {\n const [primary = '', ...extras] = roots;\n const set = validateRootSet(primary, extras);\n if (!set.ok) return { ok: false, error: set.error, name: '', roots: [] };\n const trimmed = name.trim();\n const resolved = trimmed.length > 0 ? trimmed : defaultWorkspaceName(set.roots[0]!);\n if (resolved.length === 0) {\n return { ok: false, error: 'Give this project a name.', name: '', roots: [] };\n }\n return { ok: true, error: null, name: resolved, roots: set.roots };\n}\n\n/**\n * Move one entry up or down by one place.\n *\n * Returns a NEW array, and returns the order unchanged when the move would\n * fall off either end — so a caller can wire it to a button that is disabled\n * at the ends without the two disagreeing.\n */\nexport function moveRoot<T>(roots: readonly T[], index: number, direction: 'up' | 'down'): T[] {\n const next = [...roots];\n const target = direction === 'up' ? index - 1 : index + 1;\n if (index < 0 || index >= next.length || target < 0 || target >= next.length) return next;\n const moved = next[index]!;\n next[index] = next[target]!;\n next[target] = moved;\n return next;\n}\n\n/**\n * How the first row must be described. The first root IS the primary — it is\n * the session's cwd and the only folder a Grok seat reaches — so the reorder\n * control is not cosmetic and the label has to say what it does.\n */\nexport function rootRowLabel(index: number): string {\n return index === 0 ? 'Primary folder' : `Folder ${index + 1}`;\n}\n"],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta name="color-scheme" content="light dark" />
|
|
7
7
|
<title>Ashlrverse — operator console</title>
|
|
8
8
|
<meta name="referrer" content="no-referrer" />
|
|
9
|
-
<script type="module" crossorigin src="/next/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/next/assets/index-CXgVQHek.js"></script>
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"algorithm":"sha256","assurance":"packaged-build-byte-observation","inventoryDigest":"0906fdb4857a4049126696d6ec90feb130341380bce8161bec0e99e6ba7dc5e7","package":{"manifestSha256":"62f3230dcc6e865d8f3929e0b6aaf8d10086b4a606f2501d4ada2496378dc4ef","name":"@ashlr/hub","version":"3.5.1"},"packages":[{"archiveModeSha256":"e593537ea027a53342e9c95325f3823e507298732511cd61c314537000cb008c","contentSha256":"39703185cd013059db3eb5ac351625fa9dfd1eef0509fb47ff04fcc0a4cec6f5","fileCount":25,"name":"@hono/node-server","path":"@hono/node-server","size":120353,"version":"2.0.12"},{"archiveModeSha256":"f331e808f8ff6d9d2e9cbf1ad1bc05f35c36b7ac1489084d24460c345a354819","contentSha256":"ef4367c4587f87b13b688ecafe7010c2764623bfbf1f386a1943d7392f545551","fileCount":13,"name":"@isaacs/fs-minipass","path":"@isaacs/fs-minipass","size":100617,"version":"4.0.1"},{"archiveModeSha256":"212ef6ab48b10cfc61481fdb4d517d5aefa8a9e78f321c9483e13f8f0854aade","contentSha256":"54ecfe6624026e35139d2f943de8626043145c82c1d6580882a4adf4ee6b3c90","fileCount":693,"name":"@modelcontextprotocol/sdk","path":"@modelcontextprotocol/sdk","size":4322438,"version":"1.30.0"},{"archiveModeSha256":"30bd56bd2c26086e14f1b0c58123fc916fea96c6c86f7bd8e7e2fba1526cb30f","contentSha256":"78052c66ba1f5f3d3310d2685ee84af5b060c6960c06eba5cb1d08da860019ff","fileCount":466,"name":"ajv","path":"@modelcontextprotocol/sdk/node_modules/ajv","size":1033496,"version":"8.20.0"},{"archiveModeSha256":"0e9ff2b53d7e42a61c51248833683dfc6b09c9726c3f0c50663af0a6b6f83fea","contentSha256":"18bc9ecab93292b6f357a0bef6b26e39e8d7b14c46fb9b1adc8a0826f7ad419b","fileCount":12,"name":"json-schema-traverse","path":"@modelcontextprotocol/sdk/node_modules/json-schema-traverse","size":22220,"version":"1.0.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"93bc4d919570486c9dac1184c65d89802a5d7e5e51d2ad2c9c79e9229b0d2bfd","fileCount":5,"name":"accepts","path":"accepts","size":16917,"version":"2.0.0"},{"archiveModeSha256":"338fe03444b2468ffb84fa0a62e4ad26985fbe9063f5b6500fc00baab52687a7","contentSha256":"a570e5cd740441f9e2ad9e20aab09d6ff5f01c54b5ca63889fb9cc65aa22ed38","fileCount":15,"name":"ajv-formats","path":"ajv-formats","size":56763,"version":"3.0.1"},{"archiveModeSha256":"30bd56bd2c26086e14f1b0c58123fc916fea96c6c86f7bd8e7e2fba1526cb30f","contentSha256":"78052c66ba1f5f3d3310d2685ee84af5b060c6960c06eba5cb1d08da860019ff","fileCount":466,"name":"ajv","path":"ajv-formats/node_modules/ajv","size":1033496,"version":"8.20.0"},{"archiveModeSha256":"0e9ff2b53d7e42a61c51248833683dfc6b09c9726c3f0c50663af0a6b6f83fea","contentSha256":"18bc9ecab93292b6f357a0bef6b26e39e8d7b14c46fb9b1adc8a0826f7ad419b","fileCount":12,"name":"json-schema-traverse","path":"ajv-formats/node_modules/json-schema-traverse","size":22220,"version":"1.0.0"},{"archiveModeSha256":"99258e0ccfd899459bc7f95949a5bec9039234f80f0a96cfbf7de4cfd9deaad9","contentSha256":"e6f71097d1bf22309cc2010ba116320dbe0b37b53af324631969ccef03817448","fileCount":10,"name":"body-parser","path":"body-parser","size":42536,"version":"2.3.0"},{"archiveModeSha256":"b06c6eaf0b12f13ca2978123c3bc1ee1a6f8bacabea1533868e34accee2145ec","contentSha256":"a90e26ff6b282c4ec28742358f45cffa2a4736aceb4abc7cb558bd6fc740f73b","fileCount":6,"name":"content-type","path":"body-parser/node_modules/content-type","size":20751,"version":"2.0.0"},{"archiveModeSha256":"51df0d122ab1b5f510d0a80e73a4d33fcb1ab44cf00e903f505c384be80528c8","contentSha256":"048d4140095d01f76e5d5a576d5a10de4e1cebcc64cab6ea49f14afc54939be6","fileCount":5,"name":"bytes","path":"bytes","size":12270,"version":"3.1.2"},{"archiveModeSha256":"df415aae8a21af7234f013c4d934c5074b07e617f6189084a43c78a49bafcb78","contentSha256":"870b383c07315fef9619399c2450297d079b1398583984a5ccb9cd2b1005cb59","fileCount":21,"name":"call-bind-apply-helpers","path":"call-bind-apply-helpers","size":15952,"version":"1.0.2"},{"archiveModeSha256":"fd4de57fefcfd077cce1a9e57bd1b208bf59a7da3ae9f25a7e787ab17b10490f","contentSha256":"01be39d7156b173ffe2869dcd589e2080dcf2f1bcbcfa2f20409582ccb21cfaf","fileCount":11,"name":"call-bound","path":"call-bound","size":17106,"version":"1.0.4"},{"archiveModeSha256":"155b84d16e5a3094314970a26a6b1a157604be8a208c32a0562ce579ec994c2c","contentSha256":"e1ec1eb1cc0367f01e1e8a9a8366d040942612a277ba4034707a130d6d70a0ce","fileCount":13,"name":"chownr","path":"chownr","size":22048,"version":"3.0.0"},{"archiveModeSha256":"9838afc4a08f6acf39bb46bba0c8cb523556b2fc61d2958c7bdcb1ae66ca13dd","contentSha256":"4f967d79760cd06bcfdbf918d30b3a77752d03e6e76582aeac4b3a81dcd6a6a9","fileCount":4,"name":"content-disposition","path":"content-disposition","size":19928,"version":"1.1.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"1ad93015c6082464b41e63397fc9ee739d6bb7cb93755c9fbef749cff39b8675","fileCount":5,"name":"content-type","path":"content-type","size":10471,"version":"1.0.5"},{"archiveModeSha256":"2048aee59eb971a928e2fcac3881a222b2c9140ec980dfd14756de04a3885902","contentSha256":"ca8dd7ddd6a3970df6e3efff74247cd6f985dfdcc596ac0f58cd50c5b88555e8","fileCount":5,"name":"cookie","path":"cookie","size":23382,"version":"0.7.2"},{"archiveModeSha256":"51df0d122ab1b5f510d0a80e73a4d33fcb1ab44cf00e903f505c384be80528c8","contentSha256":"360601ff3d56cfdb8de7d836940caa5d74a437474129017697aab4696fc84e03","fileCount":5,"name":"cookie-signature","path":"cookie-signature","size":4993,"version":"1.2.2"},{"archiveModeSha256":"3bf3b01496f9ce98ec5c58c595c317975f470de6da6599d5d405c60c294f12c6","contentSha256":"9a628bd867c40f8bd4753d84f5f364a5ce92fcdd73fb164977d566275580786e","fileCount":4,"name":"cors","path":"cors","size":19956,"version":"2.8.6"},{"archiveModeSha256":"0c4b2570bd695c455ca6e9f67aaabdf88b1d486e39e9e52f4b8cc0c595e08f33","contentSha256":"9666a5f3074e7ff71dab89ccc0fecd79699b6c68e85087cc3416e9b220e9369e","fileCount":9,"name":"cross-spawn","path":"cross-spawn","size":16094,"version":"7.0.6"},{"archiveModeSha256":"fd7ec5fdf7ea41f349416d375406faf41b35702e2e23f02d2c015acb72adc8f2","contentSha256":"e9f41fdd4e55dc936295270bdb7c994d9ad85dd2bd6f2fb3d46767a16ee1a03e","fileCount":7,"name":"debug","path":"debug","size":42793,"version":"4.4.3"},{"archiveModeSha256":"bb32a6d3c5b9088943cd629938024c4c8d207814db8194313063fe3844cbbc8c","contentSha256":"cfc74892a99b215bdc61d9817f90b235318267ddbf8a29ef52b2906d8b26e980","fileCount":6,"name":"depd","path":"depd","size":27117,"version":"2.0.0"},{"archiveModeSha256":"305af32d2ba2d5fe89c9acaa17537f1a06e7e131bf81112cb11d623fdbb9c6f1","contentSha256":"5c4728d83554a1fc2fd51c01cf2d30bb89adbe1c6469a52201eed72b68af0f91","fileCount":15,"name":"dunder-proto","path":"dunder-proto","size":13003,"version":"1.0.1"},{"archiveModeSha256":"9838afc4a08f6acf39bb46bba0c8cb523556b2fc61d2958c7bdcb1ae66ca13dd","contentSha256":"bae9f4988b2d279e16b4bb3e5527647300137f2978aef97f40acd1b453a8d5a7","fileCount":4,"name":"ee-first","path":"ee-first","size":6259,"version":"1.1.1"},{"archiveModeSha256":"9838afc4a08f6acf39bb46bba0c8cb523556b2fc61d2958c7bdcb1ae66ca13dd","contentSha256":"1c50e3d3cd38c66e1e462f0004781f789e59959aec798aef31f9a2f049d216e5","fileCount":4,"name":"encodeurl","path":"encodeurl","size":6980,"version":"2.0.0"},{"archiveModeSha256":"fd4de57fefcfd077cce1a9e57bd1b208bf59a7da3ae9f25a7e787ab17b10490f","contentSha256":"a2dd73d6e2d58eda48469112f2eacae1fec583f84f72643b3593c6092bd3e877","fileCount":11,"name":"es-define-property","path":"es-define-property","size":10217,"version":"1.0.1"},{"archiveModeSha256":"23a440c46333c31a4ae0a1ffdc2ec6db818da1c36a039abc189b118e1bcdc625","contentSha256":"fd08a46013bf09d90a2240c6a8a97f12ff7106507456c73e7db53f608b41214e","fileCount":22,"name":"es-errors","path":"es-errors","size":12324,"version":"1.3.0"},{"archiveModeSha256":"b6b95f08bcc5f254eddbff61393e6efa09637b9fe2996a163d3c2c71c28bb681","contentSha256":"893e26d760872fd0c233391eff242a717320d6b2d6ab004ad827d1dd6c517ea5","fileCount":16,"name":"es-object-atoms","path":"es-object-atoms","size":11967,"version":"1.1.2"},{"archiveModeSha256":"764d64b5de2e2faa2387d92a5ed5dcbc1822797787a67ee46e827d4d353a2cb5","contentSha256":"27b564cee7701979ecc9ba3ad9b57c4eb185ddfe14f6fbef7961b9d95fc51789","fileCount":4,"name":"escape-html","path":"escape-html","size":3660,"version":"1.0.3"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"53b09a946276069cc9e202851404809b0b27f9616f6398ba1ba053cf27a9b61f","fileCount":5,"name":"etag","path":"etag","size":10809,"version":"1.8.1"},{"archiveModeSha256":"15cc21147f13500c581198be8a82187d7d2cd38a2c23b9459c89f22990a5b971","contentSha256":"fda71ef638beebe2ebae12fe705f63cb2276d6b35564064714ad352727e6f0a9","fileCount":13,"name":"eventsource","path":"eventsource","size":147304,"version":"3.0.7"},{"archiveModeSha256":"57e54f8cb946a2072d2c928cce29ff71a0383916edbb50e97042f859f043677f","contentSha256":"57456c2bbbfd8965c4466cf8a120581c6de9c67c1e04bf815189370f5f76ec3f","fileCount":21,"name":"eventsource-parser","path":"eventsource-parser","size":123218,"version":"3.1.0"},{"archiveModeSha256":"e882878862f5bfd4ff0cb5120df0b9e29758544fabad522563cc91a5102513a0","contentSha256":"c4cccb2f6077128bc31e51f7f772663988796261352298821eea234de1f42281","fileCount":10,"name":"express","path":"express","size":75429,"version":"5.2.1"},{"archiveModeSha256":"0f783761dfb7c14c80535b5a3d2f282398f8621985ed04be794ef3144740784e","contentSha256":"332479fcc3eaa25713fa7df0d4e3a953b7a008fde6413d4278aa667d7e4473e1","fileCount":9,"name":"express-rate-limit","path":"express-rate-limit","size":146332,"version":"8.5.2"},{"archiveModeSha256":"78e09d25ac30efc25d5604344654f3158820dbd9d45a1900b9f44e0e500839cf","contentSha256":"5ca43c0737026213eee30eb17e40859c918af2ae30f16d3882fdfbd8bcb03afd","fileCount":11,"name":"fast-deep-equal","path":"fast-deep-equal","size":12966,"version":"3.1.3"},{"archiveModeSha256":"f75ddef45cc69b6bfbcad49bde00345a7e27f27d03cd67d1083d2a334122fc1a","contentSha256":"36e796ba92bcc878b9b3c6b939c0aa1dba25e4c2ed8609f0ed748aa17c80347e","fileCount":44,"name":"fast-uri","path":"fast-uri","size":215561,"version":"3.1.6"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"a184198d4d20e0177fd4f9e5d82bc40d34143c3a8279e7200511905b08e91d1a","fileCount":5,"name":"finalhandler","path":"finalhandler","size":18111,"version":"2.1.1"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"5a3882ea4acfd16ac4851f43587d6ab87fd08de45665981db6e8ee5944486118","fileCount":5,"name":"forwarded","path":"forwarded","size":5876,"version":"0.2.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"c3d3cc5e56026a726c20ed1d516509608bddb667d5cc999f01cd3971a92e4406","fileCount":5,"name":"fresh","path":"fresh","size":10289,"version":"2.0.0"},{"archiveModeSha256":"6f10ab8235c8a46f648cd17681016bf68595208a48d01f1351bd0b19bcb4301c","contentSha256":"8afcdc5f094efcac14509859ce70157ec7daff89642bc5d604b235f6917dd5b0","fileCount":12,"name":"function-bind","path":"function-bind","size":31427,"version":"1.1.2"},{"archiveModeSha256":"2d4c82c10091157e0f33c6a4a049ef4b2609c8f2a6d70882fa538122b54c1ce3","contentSha256":"1b862b6fe457cd272bb8bce8407ac7f972c857ac317189afe7a29ba378f0f6ac","fileCount":9,"name":"get-intrinsic","path":"get-intrinsic","size":46542,"version":"1.3.0"},{"archiveModeSha256":"995b5a61ce2e3cb963405de061067b699b48e90eb6ce2ac0d88e88bd9c38549a","contentSha256":"3dc759afa7e26cd60cc642b39bffcbd22dd574469e4ac2174cc9b57b97599f82","fileCount":15,"name":"get-proto","path":"get-proto","size":10840,"version":"1.0.1"},{"archiveModeSha256":"169ecf4d0c444e719e5bcd4e912e3ceb193138b5ab7eef8f727798759a4331d3","contentSha256":"6f2eeeb1483b34581df01b15d1b80b2b45be2c7ce06496c72a90351194858738","fileCount":12,"name":"gopd","path":"gopd","size":9869,"version":"1.2.0"},{"archiveModeSha256":"2f2262ae382d511cef7d373ff151a1a662ae623e50cb17d3a920d9e87593011d","contentSha256":"617f42cde01c4ca5a0bdab28f544a70e5f52c8707daad05016cb789193ba0554","fileCount":16,"name":"has-symbols","path":"has-symbols","size":23409,"version":"1.1.0"},{"archiveModeSha256":"35386dc8ee83de6dc1f61324623e1d9907205a1bd2fa66b02bc7c0429bdf85cc","contentSha256":"e6b281a2b3f6100d9b44f0916c797da53c254e8a38cb357134e80eddf5181a48","fileCount":10,"name":"hasown","path":"hasown","size":10332,"version":"2.0.4"},{"archiveModeSha256":"6c607d433127ab8aa7eae155e5777360167dc436457ed7fbfe66ff391f0988fa","contentSha256":"ab285a621121201b7aed9fa2a4447836246643db498bf1a4b71888d5fce36f83","fileCount":568,"name":"hono","path":"hono","size":1386244,"version":"4.13.5"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"b34d2d8fdbf41450767591b746eb2adaa4a22b59aa55c94ef0ce65ff1ba6fe6d","fileCount":5,"name":"http-errors","path":"http-errors","size":19064,"version":"2.0.1"},{"archiveModeSha256":"086f9d977a09c672ced4c2d703944875d8db454fe8fdd7fe8882f0888ed7c20f","contentSha256":"762b205b641d142557d0b3fb5d376d571e7823473661004f6cb319b7c0603976","fileCount":27,"name":"iconv-lite","path":"iconv-lite","size":343635,"version":"0.7.2"},{"archiveModeSha256":"7b3e1bd04c00f38ad3e4f4fb20e65a4eeb707527b4fd7c84ea7764cef9cebdff","contentSha256":"7c50865fdccbf6c6b44600a997d13c0c5c215ded131f0a4c98acd8d15694e632","fileCount":5,"name":"inherits","path":"inherits","size":3958,"version":"2.0.4"},{"archiveModeSha256":"3ef444401f83c959cfda73e7e9fd50d0796f6f141f36f458a3f132b362e6c375","contentSha256":"0e8533c4762708d8f61d9a21b3fa5f10d7f4907a36609490e71edaadb1186c1e","fileCount":30,"name":"ip-address","path":"ip-address","size":299533,"version":"10.4.0"},{"archiveModeSha256":"a710aacb72996fbfa6d514e678b50cfe4d17619a71648b516a3a09a96479c2c8","contentSha256":"272599141de35d28a1e92b1aec64154c866998a44310163040e6499b6ec1d9c3","fileCount":6,"name":"ipaddr.js","path":"ipaddr.js","size":42145,"version":"1.9.1"},{"archiveModeSha256":"969b492deb1f22a61f85cf9f98cc0f7c1984c3c0fd162d3ba5a600f0f6181ed8","contentSha256":"31aa30a6fbd5f134714c0ae7bc1e4c7a00b1c5bfabd2931e92618a4121bd6fa8","fileCount":6,"name":"is-promise","path":"is-promise","size":2958,"version":"4.0.0"},{"archiveModeSha256":"8f22f331a576ff070646bb75a80918007ff2b93be80520594930dd04865a6e44","contentSha256":"a560d4935c162172bd5feede21bc62536cec616c166de516cd5c367a7ca23f98","fileCount":8,"name":"isexe","path":"isexe","size":10956,"version":"2.0.0"},{"archiveModeSha256":"ec3d3c0b513b0905f208bc029bc355c1cf7038f95e2e7b1e2d19ddac26e374ea","contentSha256":"e3633b6af5ec16f6448989dd91dad2798a190e52e7a3d16d90ceca23d52c5b35","fileCount":88,"name":"jose","path":"jose","size":257736,"version":"6.2.3"},{"archiveModeSha256":"bdba5b2b7f19b131522a9af3d6cd30db94ee97690d535e5c3c84d1bce068c2a9","contentSha256":"efcb8d289875749e930bf8f745c132edf832c0f9a25768fcd97e129851288174","fileCount":9,"name":"json-schema-typed","path":"json-schema-typed","size":197188,"version":"8.0.2"},{"archiveModeSha256":"3353a1cbd727174e11aa6b1a8b1163caeb467c3ac3cad2ddb7d4c230da64bdd8","contentSha256":"251a6d99cfc3364a8732128487bbd422d3964f990fe1755b0b78046b65328731","fileCount":12,"name":"marked","path":"marked","size":469664,"version":"18.0.10"},{"archiveModeSha256":"74a40513091b687e690f49f4110e314302d0b8b3c9f196cf587c9d702c4cd7e9","contentSha256":"a4884adbf4399adaff50d30983c4afa402a1d15b56a371824ea5c7c7cab385fa","fileCount":38,"name":"math-intrinsics","path":"math-intrinsics","size":17323,"version":"1.1.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"1ec2d844bc07543d41a6ab6d78008dd2998877609cc16ba532204995fb4339c5","fileCount":5,"name":"media-typer","path":"media-typer","size":9256,"version":"1.1.0"},{"archiveModeSha256":"320af631be54ba1ce035560718a037511184c1d85329f83345fbe80f2527e8c9","contentSha256":"983f0d7028b74df8828007fabcab26e7f36e42fc7db74e321a110f6f40aa3fa7","fileCount":5,"name":"merge-descriptors","path":"merge-descriptors","size":4373,"version":"2.0.0"},{"archiveModeSha256":"2cb256014f7e1eda905b4809694ab3b06e8c1f1c5b78cb4de5da514e4e57659a","contentSha256":"c979d86230ca6688633d5ef7c89397f312c6d556a1964cb8dfe33596b8b548b9","fileCount":6,"name":"mime-db","path":"mime-db","size":225566,"version":"1.54.0"},{"archiveModeSha256":"20c4497e7b68189571962123cabb12dc852bb2346c45deed91c081c899659249","contentSha256":"28ee29177b736969ce0a555c11ae5275280510007a2670dcdd7ea6b1868f46c3","fileCount":6,"name":"mime-types","path":"mime-types","size":22871,"version":"3.0.2"},{"archiveModeSha256":"155b84d16e5a3094314970a26a6b1a157604be8a208c32a0562ce579ec994c2c","contentSha256":"46d898fe1f0594d49333d4bc32bce63349d6f124c78dfc3eda96c9f9b2f796fe","fileCount":13,"name":"minipass","path":"minipass","size":366791,"version":"7.1.3"},{"archiveModeSha256":"78b1977130401dbbba561837630370f3061275bb5a1963454b5f092e3cf208fe","contentSha256":"19c7cff62b036e6f0aad440e776cc94134bb6434c0c96939de864df88e2b0f21","fileCount":21,"name":"minizlib","path":"minizlib","size":117811,"version":"3.1.0"},{"archiveModeSha256":"20014b85b0431588ccd9c0e6c6afeffc10e21d0ee7de53e2ba2296fd52bb1a7c","contentSha256":"667f3d7d170cb303a69e67dc3a69a08255a3e5cfb8703f4904417b0362bc0d28","fileCount":4,"name":"ms","path":"ms","size":6721,"version":"2.1.3"},{"archiveModeSha256":"5602cdc50f925bdc25002fe3756f55c3e1117229d22c2b2c600e8ffca90295f6","contentSha256":"84851509ca06e7b5b721720762592fa23f696ba1d72172dbc1e692c1dfa7b567","fileCount":9,"name":"negotiator","path":"negotiator","size":28710,"version":"1.0.0"},{"archiveModeSha256":"99458992876825b1bc4dca80d075db820436a88fcf71baefbc25db39f52760e9","contentSha256":"501ecc61ad148476eb5316bad6418e95bb6ed9bfc794c23fcec15bc2c592ccf1","fileCount":4,"name":"object-assign","path":"object-assign","size":5493,"version":"4.1.1"},{"archiveModeSha256":"e3c2f2fe74f79d600564d5d6af9a6bd278aee46db5e0ec18493cdc9d895e0bbf","contentSha256":"7d76d46a138318bcabde842b6a8b994da11a2e3d2e8ecbc0f8780f50e17f2ca8","fileCount":34,"name":"object-inspect","path":"object-inspect","size":102920,"version":"1.13.4"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"ffb31d328870b95d8218c54f26f73d6e122847c7289052f57bf1569b0027593b","fileCount":5,"name":"on-finished","path":"on-finished","size":13679,"version":"2.4.1"},{"archiveModeSha256":"71f44c60c38bc2c3e17382504bf0dae39045eeec535cf6f4e1283e0514e8c2f4","contentSha256":"dc238bfc47820f9fb5bb56f1f3aae901657074482f52f91545784f041efb0210","fileCount":4,"name":"once","path":"once","size":4046,"version":"1.4.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"ca67e36d858cdb2f3a4eefd00d0bf7284143c1241b9ad06feec17799fc587638","fileCount":5,"name":"parseurl","path":"parseurl","size":10299,"version":"1.3.3"},{"archiveModeSha256":"320af631be54ba1ce035560718a037511184c1d85329f83345fbe80f2527e8c9","contentSha256":"a3945cbf1aaf19b6dba601c948b6522566517f9b9f4181c964d5a0d8ee34270e","fileCount":5,"name":"path-key","path":"path-key","size":4553,"version":"3.1.1"},{"archiveModeSha256":"1514e7595cbbb9d1902c24ce60454e544df780b8fc73b7967218c3491dd3cefb","contentSha256":"17d110a00db54cd903aba2283f1d027f5acfbf7ce0003590c3abeb6059b5d221","fileCount":6,"name":"path-to-regexp","path":"path-to-regexp","size":59680,"version":"8.4.2"},{"archiveModeSha256":"f0a8527de334749bd26e70302ee03517ec50ff590e93cb3ea9a45ce4124a3829","contentSha256":"d5a9fd4846acac4b5ce086c88eca29de645c535aeee06df4a99a69cf4317e397","fileCount":10,"name":"pkce-challenge","path":"pkce-challenge","size":18211,"version":"5.0.1"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"d05e2db9e9d803ea440dd46461d51f482ed09978f2688eeda51a5711f1f41320","fileCount":5,"name":"proxy-addr","path":"proxy-addr","size":15399,"version":"2.0.7"},{"archiveModeSha256":"5ab250cd90dfced7c9429dd43d78846951b7b961947594e9f5175faee4c88a56","contentSha256":"fc8bdb9e912132fa5d83b22283d4f7f816f2e24a36761387e13cd942024186c1","fileCount":20,"name":"qs","path":"qs","size":374851,"version":"6.16.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"d12cb812790fa7b85393df185775b6c9ad8d05fd313f2b31cfb817d6296b1888","fileCount":5,"name":"range-parser","path":"range-parser","size":8457,"version":"1.2.1"},{"archiveModeSha256":"42cc208595e23f148383e3b4292ce5922102522b8bfd5f77417b06d1306d7aa1","contentSha256":"8f8dedbaf8d48e5de26e87910168aa505b7403e4c7739edc953cf5b25240839c","fileCount":5,"name":"raw-body","path":"raw-body","size":18495,"version":"3.0.2"},{"archiveModeSha256":"99458992876825b1bc4dca80d075db820436a88fcf71baefbc25db39f52760e9","contentSha256":"4d281fcce32339c1f532a6e128db448b5d4c02ff371243a5c5696b40c86d3680","fileCount":4,"name":"require-from-string","path":"require-from-string","size":3422,"version":"2.0.2"},{"archiveModeSha256":"e09f32c46d1a5885aae361e487ce603fd60a9fbff1d5dcaab0f6236f971a9837","contentSha256":"99b97f87c5ffc0951428a30eea4a95cbe83f9a70122dbcc8a4b2e7634f8e8dcd","fileCount":7,"name":"router","path":"router","size":46851,"version":"2.2.0"},{"archiveModeSha256":"a462b8a4b54a0e6b8dcfc3d87612450f34478e7dc5845d4b16f239a578821a2c","contentSha256":"e075173c0c6569f0b806c5802462e19b25ed330b11040151ca5e0d8ea9e276d1","fileCount":7,"name":"safer-buffer","path":"safer-buffer","size":42299,"version":"2.1.2"},{"archiveModeSha256":"9838afc4a08f6acf39bb46bba0c8cb523556b2fc61d2958c7bdcb1ae66ca13dd","contentSha256":"3a396c8597fbbc013b13e4cf5dd7f05f798ee9809ad21d3966616d4f50964f02","fileCount":4,"name":"send","path":"send","size":32200,"version":"1.2.1"},{"archiveModeSha256":"9838afc4a08f6acf39bb46bba0c8cb523556b2fc61d2958c7bdcb1ae66ca13dd","contentSha256":"1724d9fc1a50078597419e4a1014f0d179522a46ed0e2a3a94b71f2f78575513","fileCount":4,"name":"serve-static","path":"serve-static","size":14335,"version":"2.2.1"},{"archiveModeSha256":"e1fd687bea7843794dae9ff84fa5a22ca00f6bea6583da85ed3e27d3d8444230","contentSha256":"db27148aba2fa1340dc867179dbccee745a7311c870a68bee4cea1e3fe2f3f8a","fileCount":6,"name":"setprototypeof","path":"setprototypeof","size":4025,"version":"1.2.0"},{"archiveModeSha256":"99458992876825b1bc4dca80d075db820436a88fcf71baefbc25db39f52760e9","contentSha256":"6754ac701a5f6a41aface06678b945984b2c4088d9c81a9beae10d2f236ebbad","fileCount":4,"name":"shebang-command","path":"shebang-command","size":2556,"version":"2.0.0"},{"archiveModeSha256":"320af631be54ba1ce035560718a037511184c1d85329f83345fbe80f2527e8c9","contentSha256":"a793c341e7bf38ef241be3075c0420da5b2c2df9c71b3aa64f16e8d80751acac","fileCount":5,"name":"shebang-regex","path":"shebang-regex","size":2828,"version":"3.0.0"},{"archiveModeSha256":"0e4409f8c28db8f2663ca9ff448e6029ee7e54e7d9d11f23f416dd0b83289589","contentSha256":"28e3e44b391a232fea118591ef73556f7f3bd207d35a4fa6c2d8b04bf11be322","fileCount":12,"name":"side-channel","path":"side-channel","size":22864,"version":"1.1.1"},{"archiveModeSha256":"d7170194465bf2624edfb7844fea886827d0f714bb09d49567d5c7a1c3ce78c0","contentSha256":"6959587507edce3ca38987daa64c966a2f802e6ef85b8c9f96e36b51b7d63752","fileCount":13,"name":"side-channel-list","path":"side-channel-list","size":16973,"version":"1.0.1"},{"archiveModeSha256":"0e4409f8c28db8f2663ca9ff448e6029ee7e54e7d9d11f23f416dd0b83289589","contentSha256":"c69ec67d49924576f5b78d598fe950d7a9464c1c61ad256cbebcda7641e1630a","fileCount":12,"name":"side-channel-map","path":"side-channel-map","size":13348,"version":"1.0.1"},{"archiveModeSha256":"0e4409f8c28db8f2663ca9ff448e6029ee7e54e7d9d11f23f416dd0b83289589","contentSha256":"3f830eae8141c06d7395d4c9ae072ae767e98aace4720762ebded0ae32fca96c","fileCount":12,"name":"side-channel-weakmap","path":"side-channel-weakmap","size":14667,"version":"1.0.2"},{"archiveModeSha256":"c0228c165b333628d8971a1ebdeb334786829db2fa1c9cb6ba374a9214cd4d11","contentSha256":"0b9e6a3e2e50328afbb9254550c688707172bd481eb1084c02af1456aa803249","fileCount":6,"name":"statuses","path":"statuses","size":12505,"version":"2.0.2"},{"archiveModeSha256":"fbfe9587c1875404cd616f4b49a10531431b12aed0b44210e21f3459beb3eacd","contentSha256":"6d854be5694f54f83a7cec190bcd141318a1c8a78df8b42ab64fbae2c5dc4518","fileCount":249,"name":"tar","path":"tar","size":2298662,"version":"7.5.22"},{"archiveModeSha256":"155b84d16e5a3094314970a26a6b1a157604be8a208c32a0562ce579ec994c2c","contentSha256":"7db31cac4d54315057535dd080e4423ab16e09e9161e8b83191c58e2a90f7ea5","fileCount":13,"name":"yallist","path":"tar/node_modules/yallist","size":80297,"version":"5.0.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"0c7b3b8db791f787793c0968ec6f6b9dc48d14783c4c34ada0e0475eb3c011d4","fileCount":5,"name":"toidentifier","path":"toidentifier","size":4685,"version":"1.0.1"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"79ce0363e01b714db55735699052b2534d0f6ef84d785b137323647cf779657a","fileCount":5,"name":"type-is","path":"type-is","size":21269,"version":"2.1.0"},{"archiveModeSha256":"b06c6eaf0b12f13ca2978123c3bc1ee1a6f8bacabea1533868e34accee2145ec","contentSha256":"a90e26ff6b282c4ec28742358f45cffa2a4736aceb4abc7cb558bd6fc740f73b","fileCount":6,"name":"content-type","path":"type-is/node_modules/content-type","size":20751,"version":"2.0.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"99534b97972283845db4ef41d39156d6720030a2307f2f0649a7f1c8fabf68c6","fileCount":5,"name":"unpipe","path":"unpipe","size":4311,"version":"1.0.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"880e12feeb6220ce4cdb0bd7f19ddb9d693666a77059502e9d667e06b3e04ce8","fileCount":5,"name":"vary","path":"vary","size":8747,"version":"1.1.2"},{"archiveModeSha256":"8fc892f4d8b9a44a1bfc252b556ebb01d424366ec71fb56f8b0fc2b81bbb5897","contentSha256":"dbe8a52a4c488ed54e7b60f93f89947ff828f9786a804b40a049152c35a47132","fileCount":5,"name":"which","path":"which","size":7308,"version":"2.0.2"},{"archiveModeSha256":"4b84777e08ccbe4ad45474b4248dc37be2c73b6467d369958cc06ca38507a13f","contentSha256":"4f5c30f228b020aca343e88dc0b15af855173a168663e687afd72c58cf586b99","fileCount":4,"name":"wrappy","path":"wrappy","size":2961,"version":"1.0.2"},{"archiveModeSha256":"b98a45815677c477e01457344c56184f50841e90f1f78c98f47d4f631140c4f3","contentSha256":"eaed4b517e605755ecde1e008133c5418c238657a3236735a1053f00b4a7e58b","fileCount":718,"name":"zod","path":"zod","size":4558122,"version":"4.4.3"},{"archiveModeSha256":"224107ce4653d3b406ca40837a05712425b14ff999773673d516eb31d8e9a34d","contentSha256":"d45857bb67c09b95d65c081b1afc095fcfd8d3e8d8bc3b57f645a1f369b1ea04","fileCount":130,"name":"zod-to-json-schema","path":"zod-to-json-schema","size":219264,"version":"3.25.2"}],"portability":"platform-independent-no-native-or-install-variance","rootDependencies":[{"name":"@modelcontextprotocol/sdk","requested":"^1.30.0"},{"name":"marked","requested":"18.0.10"},{"name":"tar","requested":"7.5.22"}],"schemaVersion":2}
|
|
1
|
+
{"algorithm":"sha256","assurance":"packaged-build-byte-observation","inventoryDigest":"f768b41ae02c586bb8ef0b543c31839acdc693be0feed32063da08e30b01f0e1","package":{"manifestSha256":"e87edbda31fd9f04c9764f932b9dbe5ee9a93d083435f0386f94d8201f562b0a","name":"@ashlr/hub","version":"3.8.0"},"packages":[{"archiveModeSha256":"e593537ea027a53342e9c95325f3823e507298732511cd61c314537000cb008c","contentSha256":"39703185cd013059db3eb5ac351625fa9dfd1eef0509fb47ff04fcc0a4cec6f5","fileCount":25,"name":"@hono/node-server","path":"@hono/node-server","size":120353,"version":"2.0.12"},{"archiveModeSha256":"f331e808f8ff6d9d2e9cbf1ad1bc05f35c36b7ac1489084d24460c345a354819","contentSha256":"ef4367c4587f87b13b688ecafe7010c2764623bfbf1f386a1943d7392f545551","fileCount":13,"name":"@isaacs/fs-minipass","path":"@isaacs/fs-minipass","size":100617,"version":"4.0.1"},{"archiveModeSha256":"212ef6ab48b10cfc61481fdb4d517d5aefa8a9e78f321c9483e13f8f0854aade","contentSha256":"54ecfe6624026e35139d2f943de8626043145c82c1d6580882a4adf4ee6b3c90","fileCount":693,"name":"@modelcontextprotocol/sdk","path":"@modelcontextprotocol/sdk","size":4322438,"version":"1.30.0"},{"archiveModeSha256":"30bd56bd2c26086e14f1b0c58123fc916fea96c6c86f7bd8e7e2fba1526cb30f","contentSha256":"78052c66ba1f5f3d3310d2685ee84af5b060c6960c06eba5cb1d08da860019ff","fileCount":466,"name":"ajv","path":"@modelcontextprotocol/sdk/node_modules/ajv","size":1033496,"version":"8.20.0"},{"archiveModeSha256":"0e9ff2b53d7e42a61c51248833683dfc6b09c9726c3f0c50663af0a6b6f83fea","contentSha256":"18bc9ecab93292b6f357a0bef6b26e39e8d7b14c46fb9b1adc8a0826f7ad419b","fileCount":12,"name":"json-schema-traverse","path":"@modelcontextprotocol/sdk/node_modules/json-schema-traverse","size":22220,"version":"1.0.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"93bc4d919570486c9dac1184c65d89802a5d7e5e51d2ad2c9c79e9229b0d2bfd","fileCount":5,"name":"accepts","path":"accepts","size":16917,"version":"2.0.0"},{"archiveModeSha256":"338fe03444b2468ffb84fa0a62e4ad26985fbe9063f5b6500fc00baab52687a7","contentSha256":"a570e5cd740441f9e2ad9e20aab09d6ff5f01c54b5ca63889fb9cc65aa22ed38","fileCount":15,"name":"ajv-formats","path":"ajv-formats","size":56763,"version":"3.0.1"},{"archiveModeSha256":"30bd56bd2c26086e14f1b0c58123fc916fea96c6c86f7bd8e7e2fba1526cb30f","contentSha256":"78052c66ba1f5f3d3310d2685ee84af5b060c6960c06eba5cb1d08da860019ff","fileCount":466,"name":"ajv","path":"ajv-formats/node_modules/ajv","size":1033496,"version":"8.20.0"},{"archiveModeSha256":"0e9ff2b53d7e42a61c51248833683dfc6b09c9726c3f0c50663af0a6b6f83fea","contentSha256":"18bc9ecab93292b6f357a0bef6b26e39e8d7b14c46fb9b1adc8a0826f7ad419b","fileCount":12,"name":"json-schema-traverse","path":"ajv-formats/node_modules/json-schema-traverse","size":22220,"version":"1.0.0"},{"archiveModeSha256":"99258e0ccfd899459bc7f95949a5bec9039234f80f0a96cfbf7de4cfd9deaad9","contentSha256":"e6f71097d1bf22309cc2010ba116320dbe0b37b53af324631969ccef03817448","fileCount":10,"name":"body-parser","path":"body-parser","size":42536,"version":"2.3.0"},{"archiveModeSha256":"b06c6eaf0b12f13ca2978123c3bc1ee1a6f8bacabea1533868e34accee2145ec","contentSha256":"a90e26ff6b282c4ec28742358f45cffa2a4736aceb4abc7cb558bd6fc740f73b","fileCount":6,"name":"content-type","path":"body-parser/node_modules/content-type","size":20751,"version":"2.0.0"},{"archiveModeSha256":"51df0d122ab1b5f510d0a80e73a4d33fcb1ab44cf00e903f505c384be80528c8","contentSha256":"048d4140095d01f76e5d5a576d5a10de4e1cebcc64cab6ea49f14afc54939be6","fileCount":5,"name":"bytes","path":"bytes","size":12270,"version":"3.1.2"},{"archiveModeSha256":"df415aae8a21af7234f013c4d934c5074b07e617f6189084a43c78a49bafcb78","contentSha256":"870b383c07315fef9619399c2450297d079b1398583984a5ccb9cd2b1005cb59","fileCount":21,"name":"call-bind-apply-helpers","path":"call-bind-apply-helpers","size":15952,"version":"1.0.2"},{"archiveModeSha256":"fd4de57fefcfd077cce1a9e57bd1b208bf59a7da3ae9f25a7e787ab17b10490f","contentSha256":"01be39d7156b173ffe2869dcd589e2080dcf2f1bcbcfa2f20409582ccb21cfaf","fileCount":11,"name":"call-bound","path":"call-bound","size":17106,"version":"1.0.4"},{"archiveModeSha256":"155b84d16e5a3094314970a26a6b1a157604be8a208c32a0562ce579ec994c2c","contentSha256":"e1ec1eb1cc0367f01e1e8a9a8366d040942612a277ba4034707a130d6d70a0ce","fileCount":13,"name":"chownr","path":"chownr","size":22048,"version":"3.0.0"},{"archiveModeSha256":"9838afc4a08f6acf39bb46bba0c8cb523556b2fc61d2958c7bdcb1ae66ca13dd","contentSha256":"4f967d79760cd06bcfdbf918d30b3a77752d03e6e76582aeac4b3a81dcd6a6a9","fileCount":4,"name":"content-disposition","path":"content-disposition","size":19928,"version":"1.1.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"1ad93015c6082464b41e63397fc9ee739d6bb7cb93755c9fbef749cff39b8675","fileCount":5,"name":"content-type","path":"content-type","size":10471,"version":"1.0.5"},{"archiveModeSha256":"2048aee59eb971a928e2fcac3881a222b2c9140ec980dfd14756de04a3885902","contentSha256":"ca8dd7ddd6a3970df6e3efff74247cd6f985dfdcc596ac0f58cd50c5b88555e8","fileCount":5,"name":"cookie","path":"cookie","size":23382,"version":"0.7.2"},{"archiveModeSha256":"51df0d122ab1b5f510d0a80e73a4d33fcb1ab44cf00e903f505c384be80528c8","contentSha256":"360601ff3d56cfdb8de7d836940caa5d74a437474129017697aab4696fc84e03","fileCount":5,"name":"cookie-signature","path":"cookie-signature","size":4993,"version":"1.2.2"},{"archiveModeSha256":"3bf3b01496f9ce98ec5c58c595c317975f470de6da6599d5d405c60c294f12c6","contentSha256":"9a628bd867c40f8bd4753d84f5f364a5ce92fcdd73fb164977d566275580786e","fileCount":4,"name":"cors","path":"cors","size":19956,"version":"2.8.6"},{"archiveModeSha256":"0c4b2570bd695c455ca6e9f67aaabdf88b1d486e39e9e52f4b8cc0c595e08f33","contentSha256":"9666a5f3074e7ff71dab89ccc0fecd79699b6c68e85087cc3416e9b220e9369e","fileCount":9,"name":"cross-spawn","path":"cross-spawn","size":16094,"version":"7.0.6"},{"archiveModeSha256":"fd7ec5fdf7ea41f349416d375406faf41b35702e2e23f02d2c015acb72adc8f2","contentSha256":"e9f41fdd4e55dc936295270bdb7c994d9ad85dd2bd6f2fb3d46767a16ee1a03e","fileCount":7,"name":"debug","path":"debug","size":42793,"version":"4.4.3"},{"archiveModeSha256":"bb32a6d3c5b9088943cd629938024c4c8d207814db8194313063fe3844cbbc8c","contentSha256":"cfc74892a99b215bdc61d9817f90b235318267ddbf8a29ef52b2906d8b26e980","fileCount":6,"name":"depd","path":"depd","size":27117,"version":"2.0.0"},{"archiveModeSha256":"305af32d2ba2d5fe89c9acaa17537f1a06e7e131bf81112cb11d623fdbb9c6f1","contentSha256":"5c4728d83554a1fc2fd51c01cf2d30bb89adbe1c6469a52201eed72b68af0f91","fileCount":15,"name":"dunder-proto","path":"dunder-proto","size":13003,"version":"1.0.1"},{"archiveModeSha256":"9838afc4a08f6acf39bb46bba0c8cb523556b2fc61d2958c7bdcb1ae66ca13dd","contentSha256":"bae9f4988b2d279e16b4bb3e5527647300137f2978aef97f40acd1b453a8d5a7","fileCount":4,"name":"ee-first","path":"ee-first","size":6259,"version":"1.1.1"},{"archiveModeSha256":"9838afc4a08f6acf39bb46bba0c8cb523556b2fc61d2958c7bdcb1ae66ca13dd","contentSha256":"1c50e3d3cd38c66e1e462f0004781f789e59959aec798aef31f9a2f049d216e5","fileCount":4,"name":"encodeurl","path":"encodeurl","size":6980,"version":"2.0.0"},{"archiveModeSha256":"fd4de57fefcfd077cce1a9e57bd1b208bf59a7da3ae9f25a7e787ab17b10490f","contentSha256":"a2dd73d6e2d58eda48469112f2eacae1fec583f84f72643b3593c6092bd3e877","fileCount":11,"name":"es-define-property","path":"es-define-property","size":10217,"version":"1.0.1"},{"archiveModeSha256":"23a440c46333c31a4ae0a1ffdc2ec6db818da1c36a039abc189b118e1bcdc625","contentSha256":"fd08a46013bf09d90a2240c6a8a97f12ff7106507456c73e7db53f608b41214e","fileCount":22,"name":"es-errors","path":"es-errors","size":12324,"version":"1.3.0"},{"archiveModeSha256":"b6b95f08bcc5f254eddbff61393e6efa09637b9fe2996a163d3c2c71c28bb681","contentSha256":"893e26d760872fd0c233391eff242a717320d6b2d6ab004ad827d1dd6c517ea5","fileCount":16,"name":"es-object-atoms","path":"es-object-atoms","size":11967,"version":"1.1.2"},{"archiveModeSha256":"764d64b5de2e2faa2387d92a5ed5dcbc1822797787a67ee46e827d4d353a2cb5","contentSha256":"27b564cee7701979ecc9ba3ad9b57c4eb185ddfe14f6fbef7961b9d95fc51789","fileCount":4,"name":"escape-html","path":"escape-html","size":3660,"version":"1.0.3"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"53b09a946276069cc9e202851404809b0b27f9616f6398ba1ba053cf27a9b61f","fileCount":5,"name":"etag","path":"etag","size":10809,"version":"1.8.1"},{"archiveModeSha256":"15cc21147f13500c581198be8a82187d7d2cd38a2c23b9459c89f22990a5b971","contentSha256":"fda71ef638beebe2ebae12fe705f63cb2276d6b35564064714ad352727e6f0a9","fileCount":13,"name":"eventsource","path":"eventsource","size":147304,"version":"3.0.7"},{"archiveModeSha256":"57e54f8cb946a2072d2c928cce29ff71a0383916edbb50e97042f859f043677f","contentSha256":"57456c2bbbfd8965c4466cf8a120581c6de9c67c1e04bf815189370f5f76ec3f","fileCount":21,"name":"eventsource-parser","path":"eventsource-parser","size":123218,"version":"3.1.0"},{"archiveModeSha256":"e882878862f5bfd4ff0cb5120df0b9e29758544fabad522563cc91a5102513a0","contentSha256":"c4cccb2f6077128bc31e51f7f772663988796261352298821eea234de1f42281","fileCount":10,"name":"express","path":"express","size":75429,"version":"5.2.1"},{"archiveModeSha256":"0f783761dfb7c14c80535b5a3d2f282398f8621985ed04be794ef3144740784e","contentSha256":"332479fcc3eaa25713fa7df0d4e3a953b7a008fde6413d4278aa667d7e4473e1","fileCount":9,"name":"express-rate-limit","path":"express-rate-limit","size":146332,"version":"8.5.2"},{"archiveModeSha256":"78e09d25ac30efc25d5604344654f3158820dbd9d45a1900b9f44e0e500839cf","contentSha256":"5ca43c0737026213eee30eb17e40859c918af2ae30f16d3882fdfbd8bcb03afd","fileCount":11,"name":"fast-deep-equal","path":"fast-deep-equal","size":12966,"version":"3.1.3"},{"archiveModeSha256":"f75ddef45cc69b6bfbcad49bde00345a7e27f27d03cd67d1083d2a334122fc1a","contentSha256":"36e796ba92bcc878b9b3c6b939c0aa1dba25e4c2ed8609f0ed748aa17c80347e","fileCount":44,"name":"fast-uri","path":"fast-uri","size":215561,"version":"3.1.6"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"a184198d4d20e0177fd4f9e5d82bc40d34143c3a8279e7200511905b08e91d1a","fileCount":5,"name":"finalhandler","path":"finalhandler","size":18111,"version":"2.1.1"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"5a3882ea4acfd16ac4851f43587d6ab87fd08de45665981db6e8ee5944486118","fileCount":5,"name":"forwarded","path":"forwarded","size":5876,"version":"0.2.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"c3d3cc5e56026a726c20ed1d516509608bddb667d5cc999f01cd3971a92e4406","fileCount":5,"name":"fresh","path":"fresh","size":10289,"version":"2.0.0"},{"archiveModeSha256":"6f10ab8235c8a46f648cd17681016bf68595208a48d01f1351bd0b19bcb4301c","contentSha256":"8afcdc5f094efcac14509859ce70157ec7daff89642bc5d604b235f6917dd5b0","fileCount":12,"name":"function-bind","path":"function-bind","size":31427,"version":"1.1.2"},{"archiveModeSha256":"2d4c82c10091157e0f33c6a4a049ef4b2609c8f2a6d70882fa538122b54c1ce3","contentSha256":"1b862b6fe457cd272bb8bce8407ac7f972c857ac317189afe7a29ba378f0f6ac","fileCount":9,"name":"get-intrinsic","path":"get-intrinsic","size":46542,"version":"1.3.0"},{"archiveModeSha256":"995b5a61ce2e3cb963405de061067b699b48e90eb6ce2ac0d88e88bd9c38549a","contentSha256":"3dc759afa7e26cd60cc642b39bffcbd22dd574469e4ac2174cc9b57b97599f82","fileCount":15,"name":"get-proto","path":"get-proto","size":10840,"version":"1.0.1"},{"archiveModeSha256":"169ecf4d0c444e719e5bcd4e912e3ceb193138b5ab7eef8f727798759a4331d3","contentSha256":"6f2eeeb1483b34581df01b15d1b80b2b45be2c7ce06496c72a90351194858738","fileCount":12,"name":"gopd","path":"gopd","size":9869,"version":"1.2.0"},{"archiveModeSha256":"2f2262ae382d511cef7d373ff151a1a662ae623e50cb17d3a920d9e87593011d","contentSha256":"617f42cde01c4ca5a0bdab28f544a70e5f52c8707daad05016cb789193ba0554","fileCount":16,"name":"has-symbols","path":"has-symbols","size":23409,"version":"1.1.0"},{"archiveModeSha256":"35386dc8ee83de6dc1f61324623e1d9907205a1bd2fa66b02bc7c0429bdf85cc","contentSha256":"e6b281a2b3f6100d9b44f0916c797da53c254e8a38cb357134e80eddf5181a48","fileCount":10,"name":"hasown","path":"hasown","size":10332,"version":"2.0.4"},{"archiveModeSha256":"6c607d433127ab8aa7eae155e5777360167dc436457ed7fbfe66ff391f0988fa","contentSha256":"ab285a621121201b7aed9fa2a4447836246643db498bf1a4b71888d5fce36f83","fileCount":568,"name":"hono","path":"hono","size":1386244,"version":"4.13.5"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"b34d2d8fdbf41450767591b746eb2adaa4a22b59aa55c94ef0ce65ff1ba6fe6d","fileCount":5,"name":"http-errors","path":"http-errors","size":19064,"version":"2.0.1"},{"archiveModeSha256":"086f9d977a09c672ced4c2d703944875d8db454fe8fdd7fe8882f0888ed7c20f","contentSha256":"762b205b641d142557d0b3fb5d376d571e7823473661004f6cb319b7c0603976","fileCount":27,"name":"iconv-lite","path":"iconv-lite","size":343635,"version":"0.7.2"},{"archiveModeSha256":"7b3e1bd04c00f38ad3e4f4fb20e65a4eeb707527b4fd7c84ea7764cef9cebdff","contentSha256":"7c50865fdccbf6c6b44600a997d13c0c5c215ded131f0a4c98acd8d15694e632","fileCount":5,"name":"inherits","path":"inherits","size":3958,"version":"2.0.4"},{"archiveModeSha256":"3ef444401f83c959cfda73e7e9fd50d0796f6f141f36f458a3f132b362e6c375","contentSha256":"0e8533c4762708d8f61d9a21b3fa5f10d7f4907a36609490e71edaadb1186c1e","fileCount":30,"name":"ip-address","path":"ip-address","size":299533,"version":"10.4.0"},{"archiveModeSha256":"a710aacb72996fbfa6d514e678b50cfe4d17619a71648b516a3a09a96479c2c8","contentSha256":"272599141de35d28a1e92b1aec64154c866998a44310163040e6499b6ec1d9c3","fileCount":6,"name":"ipaddr.js","path":"ipaddr.js","size":42145,"version":"1.9.1"},{"archiveModeSha256":"969b492deb1f22a61f85cf9f98cc0f7c1984c3c0fd162d3ba5a600f0f6181ed8","contentSha256":"31aa30a6fbd5f134714c0ae7bc1e4c7a00b1c5bfabd2931e92618a4121bd6fa8","fileCount":6,"name":"is-promise","path":"is-promise","size":2958,"version":"4.0.0"},{"archiveModeSha256":"8f22f331a576ff070646bb75a80918007ff2b93be80520594930dd04865a6e44","contentSha256":"a560d4935c162172bd5feede21bc62536cec616c166de516cd5c367a7ca23f98","fileCount":8,"name":"isexe","path":"isexe","size":10956,"version":"2.0.0"},{"archiveModeSha256":"ec3d3c0b513b0905f208bc029bc355c1cf7038f95e2e7b1e2d19ddac26e374ea","contentSha256":"e3633b6af5ec16f6448989dd91dad2798a190e52e7a3d16d90ceca23d52c5b35","fileCount":88,"name":"jose","path":"jose","size":257736,"version":"6.2.3"},{"archiveModeSha256":"bdba5b2b7f19b131522a9af3d6cd30db94ee97690d535e5c3c84d1bce068c2a9","contentSha256":"efcb8d289875749e930bf8f745c132edf832c0f9a25768fcd97e129851288174","fileCount":9,"name":"json-schema-typed","path":"json-schema-typed","size":197188,"version":"8.0.2"},{"archiveModeSha256":"3353a1cbd727174e11aa6b1a8b1163caeb467c3ac3cad2ddb7d4c230da64bdd8","contentSha256":"251a6d99cfc3364a8732128487bbd422d3964f990fe1755b0b78046b65328731","fileCount":12,"name":"marked","path":"marked","size":469664,"version":"18.0.10"},{"archiveModeSha256":"74a40513091b687e690f49f4110e314302d0b8b3c9f196cf587c9d702c4cd7e9","contentSha256":"a4884adbf4399adaff50d30983c4afa402a1d15b56a371824ea5c7c7cab385fa","fileCount":38,"name":"math-intrinsics","path":"math-intrinsics","size":17323,"version":"1.1.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"1ec2d844bc07543d41a6ab6d78008dd2998877609cc16ba532204995fb4339c5","fileCount":5,"name":"media-typer","path":"media-typer","size":9256,"version":"1.1.0"},{"archiveModeSha256":"320af631be54ba1ce035560718a037511184c1d85329f83345fbe80f2527e8c9","contentSha256":"983f0d7028b74df8828007fabcab26e7f36e42fc7db74e321a110f6f40aa3fa7","fileCount":5,"name":"merge-descriptors","path":"merge-descriptors","size":4373,"version":"2.0.0"},{"archiveModeSha256":"2cb256014f7e1eda905b4809694ab3b06e8c1f1c5b78cb4de5da514e4e57659a","contentSha256":"c979d86230ca6688633d5ef7c89397f312c6d556a1964cb8dfe33596b8b548b9","fileCount":6,"name":"mime-db","path":"mime-db","size":225566,"version":"1.54.0"},{"archiveModeSha256":"20c4497e7b68189571962123cabb12dc852bb2346c45deed91c081c899659249","contentSha256":"28ee29177b736969ce0a555c11ae5275280510007a2670dcdd7ea6b1868f46c3","fileCount":6,"name":"mime-types","path":"mime-types","size":22871,"version":"3.0.2"},{"archiveModeSha256":"155b84d16e5a3094314970a26a6b1a157604be8a208c32a0562ce579ec994c2c","contentSha256":"46d898fe1f0594d49333d4bc32bce63349d6f124c78dfc3eda96c9f9b2f796fe","fileCount":13,"name":"minipass","path":"minipass","size":366791,"version":"7.1.3"},{"archiveModeSha256":"78b1977130401dbbba561837630370f3061275bb5a1963454b5f092e3cf208fe","contentSha256":"19c7cff62b036e6f0aad440e776cc94134bb6434c0c96939de864df88e2b0f21","fileCount":21,"name":"minizlib","path":"minizlib","size":117811,"version":"3.1.0"},{"archiveModeSha256":"20014b85b0431588ccd9c0e6c6afeffc10e21d0ee7de53e2ba2296fd52bb1a7c","contentSha256":"667f3d7d170cb303a69e67dc3a69a08255a3e5cfb8703f4904417b0362bc0d28","fileCount":4,"name":"ms","path":"ms","size":6721,"version":"2.1.3"},{"archiveModeSha256":"5602cdc50f925bdc25002fe3756f55c3e1117229d22c2b2c600e8ffca90295f6","contentSha256":"84851509ca06e7b5b721720762592fa23f696ba1d72172dbc1e692c1dfa7b567","fileCount":9,"name":"negotiator","path":"negotiator","size":28710,"version":"1.0.0"},{"archiveModeSha256":"99458992876825b1bc4dca80d075db820436a88fcf71baefbc25db39f52760e9","contentSha256":"501ecc61ad148476eb5316bad6418e95bb6ed9bfc794c23fcec15bc2c592ccf1","fileCount":4,"name":"object-assign","path":"object-assign","size":5493,"version":"4.1.1"},{"archiveModeSha256":"e3c2f2fe74f79d600564d5d6af9a6bd278aee46db5e0ec18493cdc9d895e0bbf","contentSha256":"7d76d46a138318bcabde842b6a8b994da11a2e3d2e8ecbc0f8780f50e17f2ca8","fileCount":34,"name":"object-inspect","path":"object-inspect","size":102920,"version":"1.13.4"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"ffb31d328870b95d8218c54f26f73d6e122847c7289052f57bf1569b0027593b","fileCount":5,"name":"on-finished","path":"on-finished","size":13679,"version":"2.4.1"},{"archiveModeSha256":"71f44c60c38bc2c3e17382504bf0dae39045eeec535cf6f4e1283e0514e8c2f4","contentSha256":"dc238bfc47820f9fb5bb56f1f3aae901657074482f52f91545784f041efb0210","fileCount":4,"name":"once","path":"once","size":4046,"version":"1.4.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"ca67e36d858cdb2f3a4eefd00d0bf7284143c1241b9ad06feec17799fc587638","fileCount":5,"name":"parseurl","path":"parseurl","size":10299,"version":"1.3.3"},{"archiveModeSha256":"320af631be54ba1ce035560718a037511184c1d85329f83345fbe80f2527e8c9","contentSha256":"a3945cbf1aaf19b6dba601c948b6522566517f9b9f4181c964d5a0d8ee34270e","fileCount":5,"name":"path-key","path":"path-key","size":4553,"version":"3.1.1"},{"archiveModeSha256":"1514e7595cbbb9d1902c24ce60454e544df780b8fc73b7967218c3491dd3cefb","contentSha256":"17d110a00db54cd903aba2283f1d027f5acfbf7ce0003590c3abeb6059b5d221","fileCount":6,"name":"path-to-regexp","path":"path-to-regexp","size":59680,"version":"8.4.2"},{"archiveModeSha256":"f0a8527de334749bd26e70302ee03517ec50ff590e93cb3ea9a45ce4124a3829","contentSha256":"d5a9fd4846acac4b5ce086c88eca29de645c535aeee06df4a99a69cf4317e397","fileCount":10,"name":"pkce-challenge","path":"pkce-challenge","size":18211,"version":"5.0.1"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"d05e2db9e9d803ea440dd46461d51f482ed09978f2688eeda51a5711f1f41320","fileCount":5,"name":"proxy-addr","path":"proxy-addr","size":15399,"version":"2.0.7"},{"archiveModeSha256":"5ab250cd90dfced7c9429dd43d78846951b7b961947594e9f5175faee4c88a56","contentSha256":"fc8bdb9e912132fa5d83b22283d4f7f816f2e24a36761387e13cd942024186c1","fileCount":20,"name":"qs","path":"qs","size":374851,"version":"6.16.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"d12cb812790fa7b85393df185775b6c9ad8d05fd313f2b31cfb817d6296b1888","fileCount":5,"name":"range-parser","path":"range-parser","size":8457,"version":"1.2.1"},{"archiveModeSha256":"42cc208595e23f148383e3b4292ce5922102522b8bfd5f77417b06d1306d7aa1","contentSha256":"8f8dedbaf8d48e5de26e87910168aa505b7403e4c7739edc953cf5b25240839c","fileCount":5,"name":"raw-body","path":"raw-body","size":18495,"version":"3.0.2"},{"archiveModeSha256":"99458992876825b1bc4dca80d075db820436a88fcf71baefbc25db39f52760e9","contentSha256":"4d281fcce32339c1f532a6e128db448b5d4c02ff371243a5c5696b40c86d3680","fileCount":4,"name":"require-from-string","path":"require-from-string","size":3422,"version":"2.0.2"},{"archiveModeSha256":"e09f32c46d1a5885aae361e487ce603fd60a9fbff1d5dcaab0f6236f971a9837","contentSha256":"99b97f87c5ffc0951428a30eea4a95cbe83f9a70122dbcc8a4b2e7634f8e8dcd","fileCount":7,"name":"router","path":"router","size":46851,"version":"2.2.0"},{"archiveModeSha256":"a462b8a4b54a0e6b8dcfc3d87612450f34478e7dc5845d4b16f239a578821a2c","contentSha256":"e075173c0c6569f0b806c5802462e19b25ed330b11040151ca5e0d8ea9e276d1","fileCount":7,"name":"safer-buffer","path":"safer-buffer","size":42299,"version":"2.1.2"},{"archiveModeSha256":"9838afc4a08f6acf39bb46bba0c8cb523556b2fc61d2958c7bdcb1ae66ca13dd","contentSha256":"3a396c8597fbbc013b13e4cf5dd7f05f798ee9809ad21d3966616d4f50964f02","fileCount":4,"name":"send","path":"send","size":32200,"version":"1.2.1"},{"archiveModeSha256":"9838afc4a08f6acf39bb46bba0c8cb523556b2fc61d2958c7bdcb1ae66ca13dd","contentSha256":"1724d9fc1a50078597419e4a1014f0d179522a46ed0e2a3a94b71f2f78575513","fileCount":4,"name":"serve-static","path":"serve-static","size":14335,"version":"2.2.1"},{"archiveModeSha256":"e1fd687bea7843794dae9ff84fa5a22ca00f6bea6583da85ed3e27d3d8444230","contentSha256":"db27148aba2fa1340dc867179dbccee745a7311c870a68bee4cea1e3fe2f3f8a","fileCount":6,"name":"setprototypeof","path":"setprototypeof","size":4025,"version":"1.2.0"},{"archiveModeSha256":"99458992876825b1bc4dca80d075db820436a88fcf71baefbc25db39f52760e9","contentSha256":"6754ac701a5f6a41aface06678b945984b2c4088d9c81a9beae10d2f236ebbad","fileCount":4,"name":"shebang-command","path":"shebang-command","size":2556,"version":"2.0.0"},{"archiveModeSha256":"320af631be54ba1ce035560718a037511184c1d85329f83345fbe80f2527e8c9","contentSha256":"a793c341e7bf38ef241be3075c0420da5b2c2df9c71b3aa64f16e8d80751acac","fileCount":5,"name":"shebang-regex","path":"shebang-regex","size":2828,"version":"3.0.0"},{"archiveModeSha256":"0e4409f8c28db8f2663ca9ff448e6029ee7e54e7d9d11f23f416dd0b83289589","contentSha256":"28e3e44b391a232fea118591ef73556f7f3bd207d35a4fa6c2d8b04bf11be322","fileCount":12,"name":"side-channel","path":"side-channel","size":22864,"version":"1.1.1"},{"archiveModeSha256":"d7170194465bf2624edfb7844fea886827d0f714bb09d49567d5c7a1c3ce78c0","contentSha256":"6959587507edce3ca38987daa64c966a2f802e6ef85b8c9f96e36b51b7d63752","fileCount":13,"name":"side-channel-list","path":"side-channel-list","size":16973,"version":"1.0.1"},{"archiveModeSha256":"0e4409f8c28db8f2663ca9ff448e6029ee7e54e7d9d11f23f416dd0b83289589","contentSha256":"c69ec67d49924576f5b78d598fe950d7a9464c1c61ad256cbebcda7641e1630a","fileCount":12,"name":"side-channel-map","path":"side-channel-map","size":13348,"version":"1.0.1"},{"archiveModeSha256":"0e4409f8c28db8f2663ca9ff448e6029ee7e54e7d9d11f23f416dd0b83289589","contentSha256":"3f830eae8141c06d7395d4c9ae072ae767e98aace4720762ebded0ae32fca96c","fileCount":12,"name":"side-channel-weakmap","path":"side-channel-weakmap","size":14667,"version":"1.0.2"},{"archiveModeSha256":"c0228c165b333628d8971a1ebdeb334786829db2fa1c9cb6ba374a9214cd4d11","contentSha256":"0b9e6a3e2e50328afbb9254550c688707172bd481eb1084c02af1456aa803249","fileCount":6,"name":"statuses","path":"statuses","size":12505,"version":"2.0.2"},{"archiveModeSha256":"fbfe9587c1875404cd616f4b49a10531431b12aed0b44210e21f3459beb3eacd","contentSha256":"6d854be5694f54f83a7cec190bcd141318a1c8a78df8b42ab64fbae2c5dc4518","fileCount":249,"name":"tar","path":"tar","size":2298662,"version":"7.5.22"},{"archiveModeSha256":"155b84d16e5a3094314970a26a6b1a157604be8a208c32a0562ce579ec994c2c","contentSha256":"7db31cac4d54315057535dd080e4423ab16e09e9161e8b83191c58e2a90f7ea5","fileCount":13,"name":"yallist","path":"tar/node_modules/yallist","size":80297,"version":"5.0.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"0c7b3b8db791f787793c0968ec6f6b9dc48d14783c4c34ada0e0475eb3c011d4","fileCount":5,"name":"toidentifier","path":"toidentifier","size":4685,"version":"1.0.1"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"79ce0363e01b714db55735699052b2534d0f6ef84d785b137323647cf779657a","fileCount":5,"name":"type-is","path":"type-is","size":21269,"version":"2.1.0"},{"archiveModeSha256":"b06c6eaf0b12f13ca2978123c3bc1ee1a6f8bacabea1533868e34accee2145ec","contentSha256":"a90e26ff6b282c4ec28742358f45cffa2a4736aceb4abc7cb558bd6fc740f73b","fileCount":6,"name":"content-type","path":"type-is/node_modules/content-type","size":20751,"version":"2.0.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"99534b97972283845db4ef41d39156d6720030a2307f2f0649a7f1c8fabf68c6","fileCount":5,"name":"unpipe","path":"unpipe","size":4311,"version":"1.0.0"},{"archiveModeSha256":"6deab79d9a3bed680c53dd7207c0797080f88a1f668db456501aed3105c7eea5","contentSha256":"880e12feeb6220ce4cdb0bd7f19ddb9d693666a77059502e9d667e06b3e04ce8","fileCount":5,"name":"vary","path":"vary","size":8747,"version":"1.1.2"},{"archiveModeSha256":"8fc892f4d8b9a44a1bfc252b556ebb01d424366ec71fb56f8b0fc2b81bbb5897","contentSha256":"dbe8a52a4c488ed54e7b60f93f89947ff828f9786a804b40a049152c35a47132","fileCount":5,"name":"which","path":"which","size":7308,"version":"2.0.2"},{"archiveModeSha256":"4b84777e08ccbe4ad45474b4248dc37be2c73b6467d369958cc06ca38507a13f","contentSha256":"4f5c30f228b020aca343e88dc0b15af855173a168663e687afd72c58cf586b99","fileCount":4,"name":"wrappy","path":"wrappy","size":2961,"version":"1.0.2"},{"archiveModeSha256":"b98a45815677c477e01457344c56184f50841e90f1f78c98f47d4f631140c4f3","contentSha256":"eaed4b517e605755ecde1e008133c5418c238657a3236735a1053f00b4a7e58b","fileCount":718,"name":"zod","path":"zod","size":4558122,"version":"4.4.3"},{"archiveModeSha256":"224107ce4653d3b406ca40837a05712425b14ff999773673d516eb31d8e9a34d","contentSha256":"d45857bb67c09b95d65c081b1afc095fcfd8d3e8d8bc3b57f645a1f369b1ea04","fileCount":130,"name":"zod-to-json-schema","path":"zod-to-json-schema","size":219264,"version":"3.25.2"}],"portability":"platform-independent-no-native-or-install-variance","rootDependencies":[{"name":"@modelcontextprotocol/sdk","requested":"^1.30.0"},{"name":"marked","requested":"18.0.10"},{"name":"tar","requested":"7.5.22"}],"schemaVersion":2}
|