@crouton-kit/crouter 0.3.8 → 0.3.12

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.
Files changed (184) hide show
  1. package/bin/crtrd +2 -0
  2. package/dist/builtin-personas/design/base.md +9 -0
  3. package/dist/builtin-personas/design/orchestrator.md +10 -0
  4. package/dist/builtin-personas/developer/base.md +9 -0
  5. package/dist/builtin-personas/developer/orchestrator.md +12 -0
  6. package/dist/builtin-personas/explore/base.md +9 -0
  7. package/dist/builtin-personas/explore/orchestrator.md +9 -0
  8. package/dist/builtin-personas/general/base.md +5 -0
  9. package/dist/builtin-personas/general/orchestrator.md +7 -0
  10. package/dist/builtin-personas/orchestration-kernel.md +71 -0
  11. package/dist/builtin-personas/plan/base.md +7 -0
  12. package/dist/builtin-personas/plan/orchestrator.md +12 -0
  13. package/dist/builtin-personas/review/base.md +7 -0
  14. package/dist/builtin-personas/review/orchestrator.md +9 -0
  15. package/dist/builtin-personas/runtime-base.md +39 -0
  16. package/dist/builtin-personas/spec/base.md +7 -0
  17. package/dist/builtin-personas/spec/orchestrator.md +10 -0
  18. package/dist/builtin-skills/skills/design/SKILL.md +51 -0
  19. package/dist/builtin-skills/skills/development/SKILL.md +109 -0
  20. package/dist/builtin-skills/skills/planning/SKILL.md +59 -0
  21. package/dist/builtin-skills/skills/spec/SKILL.md +83 -0
  22. package/dist/cli.js +25 -27
  23. package/dist/commands/{job.d.ts → attention.d.ts} +1 -1
  24. package/dist/commands/attention.js +152 -0
  25. package/dist/commands/canvas.d.ts +2 -0
  26. package/dist/commands/canvas.js +35 -0
  27. package/dist/commands/{agent.d.ts → daemon.d.ts} +1 -1
  28. package/dist/commands/daemon.js +111 -0
  29. package/dist/commands/dashboard.d.ts +2 -0
  30. package/dist/commands/dashboard.js +65 -0
  31. package/dist/commands/human/prompts.d.ts +5 -0
  32. package/dist/commands/human/prompts.js +269 -0
  33. package/dist/commands/human/queue.d.ts +3 -0
  34. package/dist/commands/human/queue.js +133 -0
  35. package/dist/commands/human/shared.d.ts +43 -0
  36. package/dist/commands/human/shared.js +107 -0
  37. package/dist/commands/human.js +15 -427
  38. package/dist/commands/node.d.ts +2 -0
  39. package/dist/commands/node.js +354 -0
  40. package/dist/commands/pkg/market-inspect.d.ts +1 -0
  41. package/dist/commands/pkg/market-inspect.js +157 -0
  42. package/dist/commands/pkg/market-manage.d.ts +1 -0
  43. package/dist/commands/pkg/market-manage.js +316 -0
  44. package/dist/commands/pkg/market.d.ts +1 -0
  45. package/dist/commands/pkg/market.js +16 -0
  46. package/dist/commands/pkg/plugin-inspect.d.ts +1 -0
  47. package/dist/commands/pkg/plugin-inspect.js +142 -0
  48. package/dist/commands/pkg/plugin-manage.d.ts +1 -0
  49. package/dist/commands/pkg/plugin-manage.js +294 -0
  50. package/dist/commands/pkg/plugin.d.ts +1 -0
  51. package/dist/commands/pkg/plugin.js +16 -0
  52. package/dist/commands/pkg/shared.d.ts +5 -0
  53. package/dist/commands/pkg/shared.js +61 -0
  54. package/dist/commands/pkg.js +8 -1004
  55. package/dist/commands/push.d.ts +3 -0
  56. package/dist/commands/push.js +159 -0
  57. package/dist/commands/revive.d.ts +2 -0
  58. package/dist/commands/revive.js +64 -0
  59. package/dist/commands/skill/author.d.ts +3 -0
  60. package/dist/commands/skill/author.js +147 -0
  61. package/dist/commands/skill/find.d.ts +4 -0
  62. package/dist/commands/skill/find.js +254 -0
  63. package/dist/commands/skill/read.d.ts +1 -0
  64. package/dist/commands/skill/read.js +89 -0
  65. package/dist/commands/skill/shared.d.ts +19 -0
  66. package/dist/commands/skill/shared.js +207 -0
  67. package/dist/commands/skill/state.d.ts +3 -0
  68. package/dist/commands/skill/state.js +69 -0
  69. package/dist/commands/skill.js +12 -681
  70. package/dist/commands/sys/config.d.ts +1 -0
  71. package/dist/commands/sys/config.js +186 -0
  72. package/dist/commands/sys/doctor.d.ts +1 -0
  73. package/dist/commands/sys/doctor.js +369 -0
  74. package/dist/commands/sys/shared.d.ts +3 -0
  75. package/dist/commands/sys/shared.js +24 -0
  76. package/dist/commands/sys/update.d.ts +2 -0
  77. package/dist/commands/sys/update.js +114 -0
  78. package/dist/commands/sys.js +9 -694
  79. package/dist/core/__tests__/argv-parser.test.js +19 -1
  80. package/dist/core/__tests__/canvas-inbox-watcher.test.js +100 -0
  81. package/dist/core/__tests__/canvas.test.js +154 -0
  82. package/dist/core/__tests__/reset.test.js +105 -0
  83. package/dist/core/__tests__/resolver.test.js +69 -1
  84. package/dist/core/__tests__/unknown-path.test.d.ts +1 -0
  85. package/dist/core/__tests__/unknown-path.test.js +52 -0
  86. package/dist/core/bootstrap.d.ts +2 -0
  87. package/dist/core/bootstrap.js +66 -0
  88. package/dist/core/canvas/attention.d.ts +24 -0
  89. package/dist/core/canvas/attention.js +94 -0
  90. package/dist/core/canvas/canvas.d.ts +40 -0
  91. package/dist/core/canvas/canvas.js +210 -0
  92. package/dist/core/canvas/db.d.ts +7 -0
  93. package/dist/core/canvas/db.js +61 -0
  94. package/dist/core/canvas/index.d.ts +4 -0
  95. package/dist/core/canvas/index.js +6 -0
  96. package/dist/core/canvas/paths.d.ts +16 -0
  97. package/dist/core/canvas/paths.js +62 -0
  98. package/dist/core/canvas/render.d.ts +30 -0
  99. package/dist/core/canvas/render.js +186 -0
  100. package/dist/core/canvas/types.d.ts +87 -0
  101. package/dist/core/canvas/types.js +8 -0
  102. package/dist/core/command.d.ts +63 -2
  103. package/dist/core/command.js +97 -24
  104. package/dist/core/feed/feed.d.ts +43 -0
  105. package/dist/core/feed/feed.js +116 -0
  106. package/dist/core/feed/inbox.d.ts +50 -0
  107. package/dist/core/feed/inbox.js +124 -0
  108. package/dist/core/frontmatter.d.ts +10 -0
  109. package/dist/core/frontmatter.js +24 -9
  110. package/dist/core/help.d.ts +39 -8
  111. package/dist/core/help.js +69 -35
  112. package/dist/core/io.d.ts +15 -1
  113. package/dist/core/io.js +56 -6
  114. package/dist/core/personas/index.d.ts +12 -0
  115. package/dist/core/personas/index.js +10 -0
  116. package/dist/core/personas/loader.d.ts +44 -0
  117. package/dist/core/personas/loader.js +157 -0
  118. package/dist/core/personas/resolve.d.ts +36 -0
  119. package/dist/core/personas/resolve.js +110 -0
  120. package/dist/core/render.d.ts +11 -0
  121. package/dist/core/render.js +126 -0
  122. package/dist/core/resolver.d.ts +10 -0
  123. package/dist/core/resolver.js +160 -2
  124. package/dist/core/runtime/front-door.d.ts +10 -0
  125. package/dist/core/runtime/front-door.js +97 -0
  126. package/dist/core/runtime/kickoff.d.ts +23 -0
  127. package/dist/core/runtime/kickoff.js +134 -0
  128. package/dist/core/runtime/launch.d.ts +34 -0
  129. package/dist/core/runtime/launch.js +85 -0
  130. package/dist/core/runtime/nodes.d.ts +38 -0
  131. package/dist/core/runtime/nodes.js +95 -0
  132. package/dist/core/runtime/presence.d.ts +38 -0
  133. package/dist/core/runtime/presence.js +152 -0
  134. package/dist/core/runtime/promote.d.ts +30 -0
  135. package/dist/core/runtime/promote.js +105 -0
  136. package/dist/core/runtime/reset.d.ts +13 -0
  137. package/dist/core/runtime/reset.js +97 -0
  138. package/dist/core/runtime/revive.d.ts +26 -0
  139. package/dist/core/runtime/revive.js +89 -0
  140. package/dist/core/runtime/roadmap.d.ts +12 -0
  141. package/dist/core/runtime/roadmap.js +52 -0
  142. package/dist/core/runtime/spawn.d.ts +33 -0
  143. package/dist/core/runtime/spawn.js +118 -0
  144. package/dist/core/runtime/stop-guard.d.ts +18 -0
  145. package/dist/core/runtime/stop-guard.js +33 -0
  146. package/dist/core/runtime/tmux.d.ts +88 -0
  147. package/dist/core/runtime/tmux.js +198 -0
  148. package/dist/core/spawn.d.ts +17 -80
  149. package/dist/core/spawn.js +15 -219
  150. package/dist/daemon/crtrd-cli.d.ts +1 -0
  151. package/dist/daemon/crtrd-cli.js +4 -0
  152. package/dist/daemon/crtrd.d.ts +20 -0
  153. package/dist/daemon/crtrd.js +200 -0
  154. package/dist/daemon/manage.d.ts +17 -0
  155. package/dist/daemon/manage.js +57 -0
  156. package/dist/pi-extensions/canvas-inbox-watcher.d.ts +16 -0
  157. package/dist/pi-extensions/canvas-inbox-watcher.js +229 -0
  158. package/dist/pi-extensions/canvas-nav.d.ts +32 -0
  159. package/dist/pi-extensions/canvas-nav.js +536 -0
  160. package/dist/pi-extensions/canvas-stophook.d.ts +17 -0
  161. package/dist/pi-extensions/canvas-stophook.js +373 -0
  162. package/dist/types.d.ts +21 -0
  163. package/dist/types.js +3 -0
  164. package/package.json +6 -5
  165. package/dist/commands/agent.js +0 -384
  166. package/dist/commands/debug.d.ts +0 -3
  167. package/dist/commands/debug.js +0 -179
  168. package/dist/commands/job.js +0 -344
  169. package/dist/commands/plan.d.ts +0 -4
  170. package/dist/commands/plan.js +0 -309
  171. package/dist/commands/spec.d.ts +0 -3
  172. package/dist/commands/spec.js +0 -286
  173. package/dist/core/__tests__/flow-leaves.test.js +0 -248
  174. package/dist/core/__tests__/job.test.js +0 -310
  175. package/dist/core/__tests__/jobs.test.js +0 -66
  176. package/dist/core/jobs.d.ts +0 -101
  177. package/dist/core/jobs.js +0 -462
  178. package/dist/prompts/agent.d.ts +0 -18
  179. package/dist/prompts/agent.js +0 -153
  180. package/dist/prompts/debug.d.ts +0 -8
  181. package/dist/prompts/debug.js +0 -44
  182. /package/dist/core/__tests__/{flow-leaves.test.d.ts → canvas-inbox-watcher.test.d.ts} +0 -0
  183. /package/dist/core/__tests__/{job.test.d.ts → canvas.test.d.ts} +0 -0
  184. /package/dist/core/__tests__/{jobs.test.d.ts → reset.test.d.ts} +0 -0
@@ -0,0 +1,229 @@
1
+ // canvas-inbox-watcher.ts — pi extension for pi-native canvas agent nodes.
2
+ //
3
+ // Loaded into every canvas node's pi process via the node's launch.extensions
4
+ // list. INERT when CRTR_NODE_ID is absent (plain pi session or legacy job agent).
5
+ //
6
+ // The canvas model: each node is a long-lived resident that alternates between
7
+ // "working" (pi actively generating) and "dormant" (pi idle, waiting for a
8
+ // subscribed worker to push a report). This watcher bridges the dormant→working
9
+ // transition automatically: it polls the node's inbox.jsonl every 800ms and,
10
+ // when new entries arrive, coalesces them into a single digest and injects it as
11
+ // a pi user message — waking the node to react.
12
+ //
13
+ // Key differences from the legacy agent-inbox-watcher:
14
+ // • Target resolution is trivial. CRTR_NODE_ID IS the node; its inbox lives at
15
+ // nodes/<CRTR_NODE_ID>/inbox.jsonl. No session-dir scanning, no pi_session_id
16
+ // matching, no spawned-vs-top-level branching.
17
+ // • readInboxSince / readCursor / writeCursor from the canvas inbox primitive
18
+ // replace the hand-rolled JSONL scanner and cursor-file helpers.
19
+ // • coalesce() renders the digest (pointer list, not job-status prose).
20
+ // • No crtr root-init or spawnSync bootstrap — the canvas runtime wires up the
21
+ // node before launching pi; CRTR_NODE_ID is always present when we activate.
22
+ // • Deliver-as decision is driven by InboxEntry.tier (and kind): critical →
23
+ // true preempt (ctx.abort() the live turn, redeliver next tick), urgent →
24
+ // steer at the turn boundary, normal|deferred → followUp. A finished node
25
+ // (kind 'final') ALSO steers — a completion the subscriber may be blocked on
26
+ // must interrupt the current turn, not wait behind it as a follow-up.
27
+ //
28
+ // Double-notify prevention (copied from legacy watcher):
29
+ // A module-level `liveTimer` ensures that a /reload re-init clears the previous
30
+ // setInterval before starting a new one — exactly one watcher is live at a time.
31
+ //
32
+ // Plain TS-with-types — no imports from @earendil-works/* so this compiles inside
33
+ // crouter's own tsc build without a dep on the pi packages.
34
+ import { readInboxSince, readCursor, writeCursor, coalesce, } from '../core/feed/inbox.js';
35
+ // ---------------------------------------------------------------------------
36
+ // Module-level timer — prevents stacking on /reload (the double-notify bug).
37
+ //
38
+ // pi ignores an extension factory's returned disposer, so a /reload re-enters
39
+ // this module and would ADD a new setInterval on top of any running one.
40
+ // N reloads → N live watchers, each with its own in-memory cursor → N deliveries
41
+ // of the same entry. Clearing the prior timer on each re-init ensures exactly
42
+ // one watcher is live. Pattern copied verbatim from agent-inbox-watcher.ts.
43
+ // ---------------------------------------------------------------------------
44
+ let liveTimer;
45
+ const TICK_MS = 800; // polling cadence
46
+ const DEBOUNCE_MS = 1000; // flush once the burst has been quiet for this long
47
+ // ---------------------------------------------------------------------------
48
+ // Extension
49
+ // ---------------------------------------------------------------------------
50
+ /**
51
+ * Register the canvas inbox watcher on `pi`.
52
+ *
53
+ * CRTR_NODE_ID is re-read each tick so late-injected env (edge case) is
54
+ * handled gracefully. Returns a disposer for testability; pi ignores it —
55
+ * the module-level liveTimer guard is the actual stacking prevention.
56
+ */
57
+ export function registerCanvasInboxWatcher(pi) {
58
+ // Capture the latest event context so isIdle() is readable inside the timer
59
+ // callback, which has no ctx of its own.
60
+ let lastCtx;
61
+ let streaming = false;
62
+ const captureCtx = (_event, ctx) => {
63
+ if (ctx !== undefined)
64
+ lastCtx = ctx;
65
+ };
66
+ pi.on('session_start', captureCtx);
67
+ pi.on('turn_end', captureCtx);
68
+ pi.on('agent_start', (_e, ctx) => {
69
+ captureCtx(_e, ctx);
70
+ streaming = true;
71
+ });
72
+ pi.on('agent_end', (_e, ctx) => {
73
+ captureCtx(_e, ctx);
74
+ streaming = false;
75
+ });
76
+ /**
77
+ * True when pi is not currently streaming a response.
78
+ * When idle, sendUserMessage triggers a new turn immediately.
79
+ * When streaming, steer (interrupt) on urgency or a finished node, else follow up.
80
+ */
81
+ const isIdle = () => {
82
+ try {
83
+ if (typeof lastCtx?.isIdle === 'function')
84
+ return lastCtx.isIdle() === true;
85
+ }
86
+ catch {
87
+ /* fall through to the streaming flag */
88
+ }
89
+ return !streaming;
90
+ };
91
+ // ---------------------------------------------------------------------------
92
+ // Debounce state
93
+ // ---------------------------------------------------------------------------
94
+ /** Entries received since the last flush — coalesced into one message. */
95
+ let buffer = [];
96
+ /** Epoch-ms of the most recent entry arrival. Used to detect burst-quiet. */
97
+ let lastArrival = 0;
98
+ /**
99
+ * Durable cursor — ISO 8601 of the last entry we've consumed.
100
+ * Seeded from the persisted cursor file on first resolution; undefined means
101
+ * "read from the beginning" (no prior cursor → process all existing entries).
102
+ * NOT reset to `now` on first tick: that would silently drop entries that
103
+ * arrived between node creation and watcher startup (the startup race).
104
+ */
105
+ let cursor;
106
+ let seeded = false;
107
+ // ---------------------------------------------------------------------------
108
+ // Flush: deliver the buffered entries as a single pi user message.
109
+ // ---------------------------------------------------------------------------
110
+ const flush = () => {
111
+ if (buffer.length === 0)
112
+ return;
113
+ // Deferred-tier entries must never WAKE an idle node — by contract they ride
114
+ // the next natural turn, never interrupt. If everything buffered is deferred
115
+ // and the node is idle, hold them (leave buffered, cheap re-check each tick)
116
+ // and return without delivering. They flush the moment the node is next
117
+ // streaming, or a higher-tier entry joins the batch (every() turns false).
118
+ if (isIdle() && buffer.every((e) => e.tier === 'deferred'))
119
+ return;
120
+ const batch = buffer;
121
+ buffer = [];
122
+ const digest = coalesce(batch);
123
+ // Tier (and kind) drive delivery mode. Critical is a TRUE preempt; urgent —
124
+ // and a finished node (kind 'final') — steers at the turn boundary;
125
+ // normal/deferred ride the next turn (followUp). (A purely-deferred idle
126
+ // batch was already held above and never reaches here.) A completion a
127
+ // subscriber is likely blocked on must not drain as a follow-up, so 'final'
128
+ // steers exactly like 'urgent'.
129
+ const anyCritical = batch.some((e) => e.tier === 'critical');
130
+ const steerMidStream = anyCritical || batch.some((e) => e.tier === 'urgent' || e.kind === 'final');
131
+ try {
132
+ if (isIdle()) {
133
+ // Idle → trigger a new turn immediately (sendUserMessage always triggers).
134
+ pi.sendUserMessage(digest);
135
+ }
136
+ else if (anyCritical) {
137
+ // Critical mid-stream → TRUE preempt. ctx.abort() cancels the live LLM
138
+ // stream right now (stopReason becomes 'aborted'; the stophook stays alive
139
+ // on that). We then re-buffer and let the next tick deliver via the idle
140
+ // path — by then the turn has torn down and sendUserMessage starts a fresh
141
+ // turn. Relying on the proven idle path (not steer-after-abort semantics)
142
+ // keeps this robust; if abort hasn't settled by the next tick we simply
143
+ // abort again and retry — idempotent and self-healing.
144
+ try {
145
+ lastCtx?.abort?.();
146
+ }
147
+ catch { /* abort is best-effort */ }
148
+ buffer = batch.concat(buffer);
149
+ }
150
+ else {
151
+ // Mid-stream → steer on urgency or a finished node, else enqueue for the
152
+ // turn after this one.
153
+ pi.sendUserMessage(digest, { deliverAs: steerMidStream ? 'steer' : 'followUp' });
154
+ }
155
+ }
156
+ catch {
157
+ // Re-queue on delivery failure so a transient error doesn't silently drop
158
+ // inbox entries. They will be retried on the next flush.
159
+ buffer = batch.concat(buffer);
160
+ }
161
+ };
162
+ // ---------------------------------------------------------------------------
163
+ // Tick: poll the node's inbox and buffer new arrivals.
164
+ // ---------------------------------------------------------------------------
165
+ const tick = () => {
166
+ try {
167
+ // Re-read env each tick: CRTR_NODE_ID could theoretically be set after the
168
+ // extension factory runs (e.g. the runtime injects it just before the first
169
+ // turn). In practice it is always present before turn_end fires, but the
170
+ // check is cheap and keeps the watcher robust.
171
+ const nodeId = process.env['CRTR_NODE_ID'];
172
+ if (nodeId === undefined || nodeId.trim() === '')
173
+ return;
174
+ // Seed the cursor once, on the first tick that resolves a nodeId.
175
+ // readCursor returns undefined when no cursor file exists → readInboxSince
176
+ // with undefined returns ALL entries (no truncation to `now`).
177
+ if (!seeded) {
178
+ cursor = readCursor(nodeId);
179
+ seeded = true;
180
+ }
181
+ const newEntries = readInboxSince(nodeId, cursor);
182
+ if (newEntries.length > 0) {
183
+ // Advance and persist the cursor BEFORE buffering, so a crash after this
184
+ // point loses at most one coalesced message rather than re-injecting
185
+ // already-delivered entries on restart (exactly-once over restart contract).
186
+ const latest = newEntries.reduce((a, b) => (a.ts > b.ts ? a : b));
187
+ cursor = latest.ts;
188
+ writeCursor(nodeId, cursor);
189
+ buffer.push(...newEntries);
190
+ lastArrival = Date.now();
191
+ }
192
+ // Flush only once the burst has settled (no new entry within DEBOUNCE_MS)
193
+ // so near-simultaneous pushes from multiple workers arrive as one message.
194
+ if (buffer.length > 0 && Date.now() - lastArrival >= DEBOUNCE_MS) {
195
+ flush();
196
+ }
197
+ }
198
+ catch {
199
+ /* watcher is best-effort; a tick must never crash the host session */
200
+ }
201
+ };
202
+ // ---------------------------------------------------------------------------
203
+ // Timer management — clear any leftover timer from a prior /reload.
204
+ // ---------------------------------------------------------------------------
205
+ if (liveTimer !== undefined)
206
+ clearInterval(liveTimer);
207
+ const timer = setInterval(tick, TICK_MS);
208
+ // unref() so the watcher doesn't keep the Node process alive when everything
209
+ // else has finished (matches legacy watcher behaviour).
210
+ if (typeof timer.unref === 'function')
211
+ timer.unref();
212
+ liveTimer = timer;
213
+ // pi DOES fire session_shutdown — use it as the authoritative teardown so a
214
+ // re-init (e.g. /reload) never discovers a live sibling timer.
215
+ pi.on('session_shutdown', () => {
216
+ clearInterval(timer);
217
+ if (liveTimer === timer)
218
+ liveTimer = undefined;
219
+ });
220
+ // Disposer: returned for testability + explicit teardown in test harnesses.
221
+ // pi ignores the factory return value, so the module-level guard above is what
222
+ // actually prevents stacking in production.
223
+ return () => {
224
+ clearInterval(timer);
225
+ if (liveTimer === timer)
226
+ liveTimer = undefined;
227
+ };
228
+ }
229
+ export default registerCanvasInboxWatcher;
@@ -0,0 +1,32 @@
1
+ type PiEvents = 'session_start' | 'turn_end' | 'session_shutdown';
2
+ interface ExtensionWidgetOptions {
3
+ /** Where the widget is rendered. "aboveEditor" | "belowEditor" */
4
+ placement?: 'aboveEditor' | 'belowEditor';
5
+ }
6
+ interface UIContext {
7
+ setWidget(key: string, content: string[] | undefined, options?: ExtensionWidgetOptions): void;
8
+ /** Raw key tap that fires BEFORE the editor. Return {consume:true} to swallow
9
+ * the key (so e.g. UP doesn't trigger pi's history recall). Returns unsub. */
10
+ onTerminalInput?(handler: (data: string) => {
11
+ consume?: boolean;
12
+ data?: string;
13
+ } | undefined): () => void;
14
+ /** Current editor buffer text — used to only hijack keys on an empty editor. */
15
+ getEditorText?(): string;
16
+ /** Transient toast, used to report a failed focus. */
17
+ notify?(message: string, type?: 'info' | 'warning' | 'error'): void;
18
+ }
19
+ interface ExtensionCtx {
20
+ ui: UIContext;
21
+ }
22
+ interface PiLike {
23
+ on(event: PiEvents, handler: (event: any, ctx: ExtensionCtx) => void | Promise<void>): void;
24
+ }
25
+ /**
26
+ * Register the canvas nav chrome on `pi`.
27
+ *
28
+ * Returns immediately when CRTR_NODE_ID is absent — the extension is fully
29
+ * inert in a non-canvas pi session.
30
+ */
31
+ export declare function registerCanvasNav(pi: PiLike): void;
32
+ export default registerCanvasNav;