remote-pi 0.2.1 → 0.4.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.
Files changed (44) hide show
  1. package/README.md +44 -0
  2. package/dist/actions/handlers.d.ts +116 -0
  3. package/dist/actions/handlers.js +152 -0
  4. package/dist/actions/handlers.js.map +1 -0
  5. package/dist/actions/registry.d.ts +25 -0
  6. package/dist/actions/registry.js +34 -0
  7. package/dist/actions/registry.js.map +1 -0
  8. package/dist/bin/supervisord.js +43 -1
  9. package/dist/bin/supervisord.js.map +1 -1
  10. package/dist/commands/builtin_mirror.d.ts +58 -0
  11. package/dist/commands/builtin_mirror.js +71 -0
  12. package/dist/commands/builtin_mirror.js.map +1 -0
  13. package/dist/commands/list_commands.d.ts +60 -0
  14. package/dist/commands/list_commands.js +73 -0
  15. package/dist/commands/list_commands.js.map +1 -0
  16. package/dist/daemon/control_protocol.d.ts +8 -0
  17. package/dist/daemon/control_protocol.js.map +1 -1
  18. package/dist/daemon/rpc_child.d.ts +24 -0
  19. package/dist/daemon/rpc_child.js +41 -2
  20. package/dist/daemon/rpc_child.js.map +1 -1
  21. package/dist/daemon/supervisor.d.ts +11 -0
  22. package/dist/daemon/supervisor.js +56 -4
  23. package/dist/daemon/supervisor.js.map +1 -1
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.js +749 -208
  26. package/dist/index.js.map +1 -1
  27. package/dist/mcp/mesh_server.d.ts +16 -0
  28. package/dist/mcp/mesh_server.js +207 -0
  29. package/dist/mcp/mesh_server.js.map +1 -0
  30. package/dist/protocol/types.d.ts +103 -0
  31. package/dist/session/bridge.d.ts +39 -0
  32. package/dist/session/bridge.js +41 -0
  33. package/dist/session/bridge.js.map +1 -0
  34. package/dist/session/mesh_node.d.ts +123 -0
  35. package/dist/session/mesh_node.js +203 -0
  36. package/dist/session/mesh_node.js.map +1 -0
  37. package/dist/session/setup_wizard.d.ts +6 -23
  38. package/dist/session/setup_wizard.js +6 -15
  39. package/dist/session/setup_wizard.js.map +1 -1
  40. package/dist/transport/relay_client.d.ts +8 -0
  41. package/dist/transport/relay_client.js +50 -2
  42. package/dist/transport/relay_client.js.map +1 -1
  43. package/package.json +4 -2
  44. package/skills/claude-agent-network/SKILL.md +239 -0
package/README.md CHANGED
@@ -111,6 +111,50 @@ direct builds while public releases roll out):
111
111
 
112
112
  ---
113
113
 
114
+ ## Mobile app actions
115
+
116
+ Beyond the chat, the app surfaces a small set of typed actions you can run
117
+ on the paired Pi session. Tap the ⚙ button next to the message input (visible
118
+ when the input is empty) to open the Quick Actions sheet:
119
+
120
+ | Action | What it does |
121
+ |---|---|
122
+ | **Compact context** | Runs `ctx.compact()` — same as `/compact` in the TUI. |
123
+ | **New session** | Runs `ctx.newSession()` — equivalent to `/new`, asks for confirmation first. |
124
+ | **Model** | Opens a model picker fed by your authenticated providers (same source the TUI uses) and switches via `pi.setModel(model)`. |
125
+ | **Thinking** | Segmented control with the 6 SDK levels (`off` · `minimal` · `low` · `medium` · `high` · `xhigh`). Changes via `pi.setThinkingLevel(level)`. |
126
+
127
+ Each action gets a structured `action_ok` / `action_error` reply so the app
128
+ can show a SnackBar on failure. Visible side-effects (chat output, model
129
+ change broadcasts, compaction notice) still flow through the normal chat
130
+ channels. The wire schema is documented in [`PROTOCOL.md`](../PROTOCOL.md)
131
+ under "App actions".
132
+
133
+ It is **not** a generic slash-command picker. The Pi SDK does not expose
134
+ programmatic invocation for most builtins (those live in the TUI's
135
+ interactive loop), so the app exposes only the actions that have a clean
136
+ SDK call. The [`pi-telegram`](https://github.com/llblab/pi-telegram) adapter
137
+ follows the same pattern.
138
+
139
+ ### Images
140
+
141
+ The app can attach **one image** (camera or gallery) to a message. It's
142
+ compressed on the device and rides **inline** in the `user_message` — the
143
+ optional `images` field carries `{ data: <base64>, mime }`. The pi-extension
144
+ turns it into the SDK's multimodal content (an `ImageContent` followed by the
145
+ caption `TextContent`) and calls `sendUserMessage(content)`, so the model sees
146
+ the picture plus your text.
147
+
148
+ Whether a model accepts images is surfaced as a `vision` flag on each
149
+ `WireModel` (derived from the SDK's `Model.input` including `"image"`); the app
150
+ greys out the attach button when the active model is text-only.
151
+
152
+ The **relay is unchanged** — the image travels inside the same opaque `ct` blob
153
+ as the rest of the message, so there's no binary channel (large files are a
154
+ future track). Text-only messages are unaffected.
155
+
156
+ ---
157
+
114
158
  ## Install
115
159
 
116
160
  Requirements: Node 20+, Pi (the host coding agent).
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Plan/28 Wave B — typed action handlers.
3
+ *
4
+ * Each handler maps one `ClientMessage` action to a public Pi SDK call,
5
+ * and replies with `action_ok` or `action_error`. Handlers take their
6
+ * dependencies as parameters so the index.ts wiring is one-liner and
7
+ * unit tests can pass fakes without touching global state.
8
+ *
9
+ * `models_list` lives next door because it shares the `ModelRegistry`
10
+ * helper and the same wire vocabulary.
11
+ *
12
+ * SDK API surface used (see plan/28 Wave 0 for the full table):
13
+ *
14
+ * - `ctx.compact()` — non-blocking, fires `session_compact`
15
+ * event when done
16
+ * - `ctx.newSession()` — only on `ExtensionCommandContext`;
17
+ * resolves with `{cancelled}` flag
18
+ * - `pi.setModel(model)` — returns `false` if no auth configured
19
+ * - `pi.setThinkingLevel(lvl)` — synchronous
20
+ * - `ctx.getModel()` — optional, undefined before first turn
21
+ * - `ModelRegistry.{refresh,getAvailable,find}` — see `registry.ts`
22
+ */
23
+ import type { ClientMessage, ServerMessage, WireModel } from "../protocol/types.js";
24
+ /**
25
+ * Structural subset of the SDK's `Model<Api>` interface (defined in
26
+ * `@mariozechner/pi-ai`, which is a transitive dep — not re-exported by
27
+ * `@mariozechner/pi-coding-agent`'s main entry). Capturing just the
28
+ * fields we touch keeps the handler decoupled from the SDK's full Model
29
+ * surface and avoids a direct dep on `pi-ai`.
30
+ */
31
+ export interface SdkModelLike {
32
+ id: string;
33
+ name: string;
34
+ provider: string;
35
+ reasoning: boolean;
36
+ contextWindow: number;
37
+ /** Plan/30: accepted input modalities. The SDK's `Model.input` is
38
+ * `("text" | "image")[]`; we read `includes("image")` for the `vision`
39
+ * flag. Optional here so tests can omit it (treated as text-only). */
40
+ input?: ("text" | "image")[];
41
+ }
42
+ type Model<_TApi = unknown> = SdkModelLike;
43
+ /**
44
+ * Minimal channel surface needed to reply. Mirrors `PlainPeerChannel`'s
45
+ * `.send` signature; tests pass an array-backed fake.
46
+ */
47
+ export interface ActionReplySender {
48
+ send(msg: ServerMessage): void;
49
+ }
50
+ /**
51
+ * Narrow shape of the `ExtensionAPI` surface action handlers actually
52
+ * call. Lets the test layer stub just these without rebuilding the full
53
+ * SDK type (which has 30+ methods we don't use here).
54
+ */
55
+ export interface ActionPi {
56
+ setModel(model: Model<any>): Promise<boolean>;
57
+ setThinkingLevel(level: import("../protocol/types.js").ThinkingLevel): void;
58
+ }
59
+ /**
60
+ * Narrow shape of the per-call context. Drawn from the union of
61
+ * `ExtensionContextActions` (compact, getModel) and
62
+ * `ExtensionCommandContextActions` (newSession), since index.ts caches
63
+ * the most-recent ctx and that's typically the command one.
64
+ *
65
+ * All fields are optional so a missing method (e.g. when only a plain
66
+ * `ExtensionContext` was seen) becomes a typed `action_error` instead of
67
+ * a runtime TypeError.
68
+ */
69
+ export interface ActionCtx {
70
+ compact?: (options?: object) => void;
71
+ /**
72
+ * Starts a new session. `withSession` is the SDK's blessed hook for
73
+ * post-replacement work: it receives a FRESH, command-capable ctx bound to
74
+ * the new session. The SDK marks any ctx captured BEFORE this call stale, so
75
+ * callers must re-capture via `withSession` rather than reuse the old ctx.
76
+ */
77
+ newSession?: (options?: {
78
+ withSession?: (ctx: ActionCtx) => Promise<void>;
79
+ }) => Promise<{
80
+ cancelled: boolean;
81
+ }>;
82
+ getModel?: () => Model<any> | undefined;
83
+ }
84
+ /**
85
+ * Minimal shape of the registry surface. Maps 1:1 onto `ModelRegistry`
86
+ * but lets tests fake catalogs without instantiating the real one.
87
+ */
88
+ export interface ActionModelRegistry {
89
+ refresh(): void;
90
+ getAvailable(): Model<any>[];
91
+ find(provider: string, modelId: string): Model<any> | undefined;
92
+ }
93
+ /** Project a SDK `Model<Api>` onto the wire schema. Shared by list_models
94
+ * and the `current` echo, so both stay in lockstep. */
95
+ export declare function wireFromModel(model: Model<any>): WireModel;
96
+ type SessionCompactMsg = Extract<ClientMessage, {
97
+ type: "session_compact";
98
+ }>;
99
+ type SessionNewMsg = Extract<ClientMessage, {
100
+ type: "session_new";
101
+ }>;
102
+ type ModelSetMsg = Extract<ClientMessage, {
103
+ type: "model_set";
104
+ }>;
105
+ type ThinkingSetMsg = Extract<ClientMessage, {
106
+ type: "thinking_set";
107
+ }>;
108
+ type ListModelsMsg = Extract<ClientMessage, {
109
+ type: "list_models";
110
+ }>;
111
+ export declare function handleSessionCompact(ctx: ActionCtx | null, sender: ActionReplySender, msg: SessionCompactMsg): void;
112
+ export declare function handleSessionNew(ctx: ActionCtx | null, sender: ActionReplySender, msg: SessionNewMsg, onReplaced?: (freshCtx: ActionCtx) => void): Promise<boolean>;
113
+ export declare function handleThinkingSet(pi: ActionPi, sender: ActionReplySender, msg: ThinkingSetMsg): void;
114
+ export declare function handleModelSet(pi: ActionPi, reg: ActionModelRegistry, sender: ActionReplySender, msg: ModelSetMsg, onPersist?: (provider: string, modelId: string) => void): Promise<void>;
115
+ export declare function handleListModels(ctx: ActionCtx | null, reg: ActionModelRegistry, sender: ActionReplySender, msg: ListModelsMsg): void;
116
+ export {};
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Plan/28 Wave B — typed action handlers.
3
+ *
4
+ * Each handler maps one `ClientMessage` action to a public Pi SDK call,
5
+ * and replies with `action_ok` or `action_error`. Handlers take their
6
+ * dependencies as parameters so the index.ts wiring is one-liner and
7
+ * unit tests can pass fakes without touching global state.
8
+ *
9
+ * `models_list` lives next door because it shares the `ModelRegistry`
10
+ * helper and the same wire vocabulary.
11
+ *
12
+ * SDK API surface used (see plan/28 Wave 0 for the full table):
13
+ *
14
+ * - `ctx.compact()` — non-blocking, fires `session_compact`
15
+ * event when done
16
+ * - `ctx.newSession()` — only on `ExtensionCommandContext`;
17
+ * resolves with `{cancelled}` flag
18
+ * - `pi.setModel(model)` — returns `false` if no auth configured
19
+ * - `pi.setThinkingLevel(lvl)` — synchronous
20
+ * - `ctx.getModel()` — optional, undefined before first turn
21
+ * - `ModelRegistry.{refresh,getAvailable,find}` — see `registry.ts`
22
+ */
23
+ /** Project a SDK `Model<Api>` onto the wire schema. Shared by list_models
24
+ * and the `current` echo, so both stay in lockstep. */
25
+ export function wireFromModel(model) {
26
+ return {
27
+ id: model.id,
28
+ name: model.name,
29
+ provider: model.provider,
30
+ reasoning: model.reasoning,
31
+ context_window: model.contextWindow,
32
+ // Plan/30: vision = model accepts image input. `Model.input` is
33
+ // `("text" | "image")[]` at runtime (confirmed against pi-ai). `?.` guards
34
+ // a fake/partial model in tests → treated as text-only.
35
+ vision: model.input?.includes("image") ?? false,
36
+ };
37
+ }
38
+ // ── ack helpers ────────────────────────────────────────────────────────────
39
+ function ok(sender, msg, action) {
40
+ sender.send({ type: "action_ok", in_reply_to: msg.id, action });
41
+ }
42
+ function fail(sender, msg, action, err) {
43
+ const error = err instanceof Error ? err.message : String(err);
44
+ sender.send({ type: "action_error", in_reply_to: msg.id, action, error });
45
+ }
46
+ /** Run a synchronous action with uniform success/failure replies. */
47
+ function runSync(sender, msg, action, body) {
48
+ try {
49
+ body();
50
+ ok(sender, msg, action);
51
+ }
52
+ catch (e) {
53
+ fail(sender, msg, action, e);
54
+ }
55
+ }
56
+ /** Run an async action with uniform success/failure replies. */
57
+ async function runAsync(sender, msg, action, body) {
58
+ try {
59
+ await body();
60
+ ok(sender, msg, action);
61
+ return true;
62
+ }
63
+ catch (e) {
64
+ fail(sender, msg, action, e);
65
+ return false;
66
+ }
67
+ }
68
+ export function handleSessionCompact(ctx, sender, msg) {
69
+ runSync(sender, msg, "session_compact", () => {
70
+ if (!ctx?.compact)
71
+ throw new Error("compact unavailable (no active session ctx)");
72
+ // Force the summary to English regardless of the conversation language —
73
+ // the summary is surfaced to the app via the `compaction` message, which
74
+ // is an English-only surface. `customInstructions` is appended to the SDK's
75
+ // compaction prompt (best-effort: the model writes the summary).
76
+ ctx.compact({
77
+ customInstructions: "Always write the compaction summary in English, even if the conversation is in another language.",
78
+ });
79
+ });
80
+ }
81
+ export async function handleSessionNew(ctx, sender, msg, onReplaced) {
82
+ // Returns true only when a fresh session was actually created. index.ts
83
+ // keys the Pi-side reset (clear _messageBuffer, restamp _sessionStartedAt,
84
+ // fan out an empty session_history) off this signal — a `cancelled`/errored
85
+ // new-session must NOT reset, so we return runAsync's success boolean.
86
+ return runAsync(sender, msg, "session_new", async () => {
87
+ if (!ctx?.newSession)
88
+ throw new Error("newSession unavailable (no command ctx yet)");
89
+ // newSession marks the caller's captured ctx (index.ts's `_lastCtx`) STALE
90
+ // — reusing it later throws "stale after session replacement" (the
91
+ // compact-after-New-session crash). `withSession` hands back a fresh,
92
+ // command-capable ctx bound to the new session; forward it via onReplaced
93
+ // so the caller re-captures and keeps later actions off the stale ctx.
94
+ const result = await ctx.newSession({
95
+ withSession: async (freshCtx) => { onReplaced?.(freshCtx); },
96
+ });
97
+ // `cancelled: true` happens when the SDK's hook chain vetoes the new
98
+ // session (e.g. an extension's `session_before_switch` returned a
99
+ // refusal). Surface as a typed error rather than silent success.
100
+ if (result.cancelled)
101
+ throw new Error("cancelled by extension hook");
102
+ });
103
+ }
104
+ export function handleThinkingSet(pi, sender, msg) {
105
+ runSync(sender, msg, "thinking_set", () => {
106
+ pi.setThinkingLevel(msg.level);
107
+ });
108
+ }
109
+ export async function handleModelSet(pi, reg, sender, msg, onPersist) {
110
+ await runAsync(sender, msg, "model_set", async () => {
111
+ // Refresh first so a model just-added via `/login` is visible.
112
+ reg.refresh();
113
+ const model = reg.find(msg.provider, msg.model_id);
114
+ if (!model) {
115
+ throw new Error(`model "${msg.provider}/${msg.model_id}" not in registry`);
116
+ }
117
+ const success = await pi.setModel(model);
118
+ if (!success)
119
+ throw new Error("no auth configured for this model");
120
+ // `pi.setModel` only sets the LIVE model — it does NOT persist. Without
121
+ // this, a model picked from the app reverts to the saved default on the
122
+ // next Pi/daemon restart (the TUI persists because AgentSession.setModel
123
+ // writes the default; this path doesn't). `onPersist` writes the new
124
+ // default so the app's choice survives. Best-effort — the caller's writer
125
+ // must not throw, so a failed settings write never fails the model change.
126
+ onPersist?.(model.provider, model.id);
127
+ });
128
+ }
129
+ export function handleListModels(ctx, reg, sender, msg) {
130
+ // refresh() can throw if `models.json` is malformed — wrap in try so the
131
+ // app gets an explicit error reply instead of a silent drop.
132
+ try {
133
+ reg.refresh();
134
+ const models = reg.getAvailable().map(wireFromModel);
135
+ const current = ctx?.getModel?.();
136
+ sender.send({
137
+ type: "models_list",
138
+ in_reply_to: msg.id,
139
+ models,
140
+ current: current ? wireFromModel(current) : undefined,
141
+ });
142
+ }
143
+ catch (e) {
144
+ sender.send({
145
+ type: "error",
146
+ in_reply_to: msg.id,
147
+ code: "internal_error",
148
+ message: e instanceof Error ? e.message : String(e),
149
+ });
150
+ }
151
+ }
152
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/actions/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAqFH;wDACwD;AACxD,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,cAAc,EAAE,KAAK,CAAC,aAAa;QACnC,gEAAgE;QAChE,2EAA2E;QAC3E,wDAAwD;QACxD,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK;KAChD,CAAC;AACJ,CAAC;AAED,8EAA8E;AAE9E,SAAS,EAAE,CAAC,MAAyB,EAAE,GAAmB,EAAE,MAAkB;IAC5E,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,IAAI,CACX,MAAyB,EACzB,GAAmB,EACnB,MAAkB,EAClB,GAAY;IAEZ,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,qEAAqE;AACrE,SAAS,OAAO,CACd,MAAyB,EACzB,GAAmB,EACnB,MAAkB,EAClB,IAAgB;IAEhB,IAAI,CAAC;QACH,IAAI,EAAE,CAAC;QACP,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,KAAK,UAAU,QAAQ,CACrB,MAAyB,EACzB,GAAmB,EACnB,MAAkB,EAClB,IAAyB;IAEzB,IAAI,CAAC;QACH,MAAM,IAAI,EAAE,CAAC;QACb,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAUD,MAAM,UAAU,oBAAoB,CAClC,GAAqB,EACrB,MAAyB,EACzB,GAAsB;IAEtB,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE;QAC3C,IAAI,CAAC,GAAG,EAAE,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAClF,yEAAyE;QACzE,yEAAyE;QACzE,4EAA4E;QAC5E,iEAAiE;QACjE,GAAG,CAAC,OAAO,CAAC;YACV,kBAAkB,EAChB,kGAAkG;SACrG,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAqB,EACrB,MAAyB,EACzB,GAAkB,EAClB,UAA0C;IAE1C,wEAAwE;IACxE,2EAA2E;IAC3E,4EAA4E;IAC5E,uEAAuE;IACvE,OAAO,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,IAAI,EAAE;QACrD,IAAI,CAAC,GAAG,EAAE,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACrF,2EAA2E;QAC3E,mEAAmE;QACnE,sEAAsE;QACtE,0EAA0E;QAC1E,uEAAuE;QACvE,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC;YAClC,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,GAAG,UAAU,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;SAC7D,CAAC,CAAC;QACH,qEAAqE;QACrE,kEAAkE;QAClE,iEAAiE;QACjE,IAAI,MAAM,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,EAAY,EACZ,MAAyB,EACzB,GAAmB;IAEnB,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAY,EACZ,GAAwB,EACxB,MAAyB,EACzB,GAAgB,EAChB,SAAuD;IAEvD,MAAM,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE;QAClD,+DAA+D;QAC/D,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,UAAU,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,mBAAmB,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACnE,wEAAwE;QACxE,wEAAwE;QACxE,yEAAyE;QACzE,qEAAqE;QACrE,0EAA0E;QAC1E,2EAA2E;QAC3E,SAAS,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,GAAqB,EACrB,GAAwB,EACxB,MAAyB,EACzB,GAAkB;IAElB,yEAAyE;IACzE,6DAA6D;IAC7D,IAAI,CAAC;QACH,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,GAAG,CAAC,EAAE;YACnB,MAAM;YACN,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;SACtD,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,GAAG,CAAC,EAAE;YACnB,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;SACpD,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Plan/28 — ModelRegistry instance shared by the action handlers.
3
+ *
4
+ * pi-extension creates its **own** `ModelRegistry` instance alongside the
5
+ * one `AgentSession` instantiates internally. Both read the same on-disk
6
+ * sources (`~/.pi/auth/*`, `~/.pi/models.json`), so they stay in sync —
7
+ * we just call `refresh()` before each `list_models` request to capture
8
+ * changes the user makes via `/login` or `/scoped-models` in the TUI.
9
+ *
10
+ * Why a fresh instance instead of accessing Pi's: the `ExtensionAPI`
11
+ * surface does not expose `AgentSession`'s registry, and the public
12
+ * factories (`ModelRegistry.create`, `AuthStorage.create`) are the
13
+ * documented way for extensions to read the same catalog. No deep
14
+ * imports, no internal-state coupling — see the probe note in
15
+ * `plan/28-pi-commands.md` Wave 0.
16
+ */
17
+ import { ModelRegistry } from "@mariozechner/pi-coding-agent";
18
+ /**
19
+ * Lazily instantiate the shared `ModelRegistry`. Subsequent calls return
20
+ * the same instance — keep it cached so `refresh()` cycles are cheap and
21
+ * the underlying `models.json` parse is amortized across requests.
22
+ */
23
+ export declare function ensureModelRegistry(): ModelRegistry;
24
+ /** Test seam — drop the cached registry so tests can rebuild with fakes. */
25
+ export declare function _resetModelRegistryForTests(): void;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Plan/28 — ModelRegistry instance shared by the action handlers.
3
+ *
4
+ * pi-extension creates its **own** `ModelRegistry` instance alongside the
5
+ * one `AgentSession` instantiates internally. Both read the same on-disk
6
+ * sources (`~/.pi/auth/*`, `~/.pi/models.json`), so they stay in sync —
7
+ * we just call `refresh()` before each `list_models` request to capture
8
+ * changes the user makes via `/login` or `/scoped-models` in the TUI.
9
+ *
10
+ * Why a fresh instance instead of accessing Pi's: the `ExtensionAPI`
11
+ * surface does not expose `AgentSession`'s registry, and the public
12
+ * factories (`ModelRegistry.create`, `AuthStorage.create`) are the
13
+ * documented way for extensions to read the same catalog. No deep
14
+ * imports, no internal-state coupling — see the probe note in
15
+ * `plan/28-pi-commands.md` Wave 0.
16
+ */
17
+ import { ModelRegistry, AuthStorage } from "@mariozechner/pi-coding-agent";
18
+ let _registry = null;
19
+ /**
20
+ * Lazily instantiate the shared `ModelRegistry`. Subsequent calls return
21
+ * the same instance — keep it cached so `refresh()` cycles are cheap and
22
+ * the underlying `models.json` parse is amortized across requests.
23
+ */
24
+ export function ensureModelRegistry() {
25
+ if (!_registry) {
26
+ _registry = ModelRegistry.create(AuthStorage.create());
27
+ }
28
+ return _registry;
29
+ }
30
+ /** Test seam — drop the cached registry so tests can rebuild with fakes. */
31
+ export function _resetModelRegistryForTests() {
32
+ _registry = null;
33
+ }
34
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/actions/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAE3E,IAAI,SAAS,GAAyB,IAAI,CAAC;AAE3C;;;;GAIG;AACH,MAAM,UAAU,mBAAmB;IACjC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,2BAA2B;IACzC,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC"}
@@ -18,8 +18,43 @@
18
18
  */
19
19
  import { fileURLToPath } from "node:url";
20
20
  import { dirname, join } from "node:path";
21
- import { Supervisor } from "../daemon/supervisor.js";
21
+ import { Supervisor, SupervisorAlreadyRunningError } from "../daemon/supervisor.js";
22
+ const HELP_TEXT = `pi-supervisord — Remote Pi daemon supervisor
23
+
24
+ Usage: pi-supervisord
25
+
26
+ Runs the long-lived supervisor: reads ~/.pi/remote/daemons.json, spawns one
27
+ \`pi --mode rpc\` child per entry, and listens on ~/.pi/remote/supervisor.sock
28
+ for control requests from the \`remote-pi\` CLI.
29
+
30
+ This binary takes NO arguments — it is normally launched by systemd/launchd
31
+ (via \`remote-pi install\`), not by hand. Manage the fleet with:
32
+ remote-pi daemon start | stop | restart | status
33
+ remote-pi daemons
34
+
35
+ Options:
36
+ -h, --help Show this help and exit
37
+ -v, --version Print version and exit
38
+ `;
22
39
  async function main() {
40
+ // Guard: any stray argument used to fall through and start a FULL
41
+ // supervisor (a `pi-supervisord --help` once ran for days). Handle the
42
+ // conventional flags explicitly and reject unknown args instead of
43
+ // silently spawning the daemon fleet.
44
+ const args = process.argv.slice(2);
45
+ if (args.includes("-h") || args.includes("--help")) {
46
+ process.stdout.write(HELP_TEXT);
47
+ return;
48
+ }
49
+ if (args.includes("-v") || args.includes("--version")) {
50
+ process.stdout.write("pi-supervisord (remote-pi)\n");
51
+ return;
52
+ }
53
+ if (args.length > 0) {
54
+ process.stderr.write(`pi-supervisord: unexpected argument(s): ${args.join(" ")}\n` +
55
+ "This binary takes no arguments. Run `pi-supervisord --help`.\n");
56
+ process.exit(2);
57
+ }
23
58
  // The supervisor needs to point each spawned Pi at the extension
24
59
  // entry it's bundled with. We're at `dist/bin/supervisord.js` after
25
60
  // build; the extension is the sibling `dist/index.js`.
@@ -38,6 +73,13 @@ async function main() {
38
73
  process.on("SIGINT", () => void shutdown("SIGINT"));
39
74
  }
40
75
  main().catch((err) => {
76
+ // "Already running" is a normal, expected condition (systemd/launchd may
77
+ // race a manual start, or the user double-launches) — not a crash. Report
78
+ // it calmly and exit 0 so service managers don't flag a failure loop.
79
+ if (err instanceof SupervisorAlreadyRunningError) {
80
+ process.stderr.write(`[pi-supervisord] ${err.message}\n`);
81
+ process.exit(0);
82
+ }
41
83
  process.stderr.write(`[pi-supervisord] fatal: ${String(err)}\n`);
42
84
  process.exit(1);
43
85
  });
@@ -1 +1 @@
1
- {"version":3,"file":"supervisord.js","sourceRoot":"","sources":["../../src/bin/supervisord.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,KAAK,UAAU,IAAI;IACjB,iEAAiE;IACjE,oEAAoE;IACpE,uDAAuD;IACvD,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,kBAAkB;IAC5D,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAEjD,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC;IACrD,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;IACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,uEAAuE,aAAa,IAAI,CACzF,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,MAAM,mBAAmB,CAAC,CAAC;QAC7E,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACtD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"supervisord.js","sourceRoot":"","sources":["../../src/bin/supervisord.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Plan/28 — Mirror of the Pi SDK's built-in slash commands.
3
+ *
4
+ * The SDK `@mariozechner/pi-coding-agent` defines `BUILTIN_SLASH_COMMANDS`
5
+ * in `dist/core/slash-commands.js` but does NOT re-export it from the main
6
+ * package entry, and the `exports` field of its `package.json` blocks deep
7
+ * imports. So pi-extension carries this manually-maintained mirror until
8
+ * an upstream PR exposes the constant publicly.
9
+ *
10
+ * **Maintenance**: when bumping `@mariozechner/pi-coding-agent`, diff the
11
+ * runtime's `BUILTIN_SLASH_COMMANDS` against this file and update names,
12
+ * descriptions, and the invokable / takes_args flags. The Wave 0 scout of
13
+ * plan/28 captured the 0.73.1 baseline; later bumps should leave a
14
+ * one-liner note here documenting which SDK version was synced.
15
+ *
16
+ * Synced from SDK version: **0.73.1**.
17
+ *
18
+ * **Invokability**: a builtin is `invokable: true` only when an entry in
19
+ * `ExtensionContextActions` lets the extension run it without simulating
20
+ * keyboard input in the TUI. The full mapping lives in `dispatcher.ts`
21
+ * (Wave B Slice 2). When more upstream APIs land, flip more flags to
22
+ * `true` here and add the corresponding dispatch in `dispatcher.ts`.
23
+ */
24
+ import type { WireCommand } from "../protocol/types.js";
25
+ /**
26
+ * A built-in slash command as exposed by the Pi TUI. Mirror of the SDK's
27
+ * `BuiltinSlashCommand` interface, kept local to avoid the deep-import.
28
+ */
29
+ export interface BuiltinMirrorEntry {
30
+ /** Slash name without the leading `/`. */
31
+ name: string;
32
+ /** One-line description shown in the app picker. */
33
+ description: string;
34
+ /**
35
+ * Whether the extension API can invoke this builtin programmatically
36
+ * via `ExtensionContextActions`. Stays `false` until plan/28 Wave B
37
+ * Slice 2 wires the dispatcher AND the underlying SDK action exists.
38
+ */
39
+ invokable: boolean;
40
+ /**
41
+ * Whether the builtin meaningfully accepts free-text arguments after
42
+ * its name (e.g. `/model claude-opus-4-7`, `/name <session-name>`).
43
+ * Used by the app to decide whether to keep the input editable after
44
+ * the chip is placed.
45
+ */
46
+ takes_args: boolean;
47
+ }
48
+ export declare const BUILTIN_SLASH_COMMANDS_MIRROR: readonly BuiltinMirrorEntry[];
49
+ /**
50
+ * Lookup helper used by the dispatcher. Returns the mirror entry for a
51
+ * builtin name, or `undefined` if `name` is not a known builtin.
52
+ */
53
+ export declare function findBuiltin(name: string): BuiltinMirrorEntry | undefined;
54
+ /**
55
+ * Project a mirror entry to the wire schema. Shared by the list_commands
56
+ * handler so the mirror and the wire stay in lockstep.
57
+ */
58
+ export declare function builtinToWire(entry: BuiltinMirrorEntry): WireCommand;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Plan/28 — Mirror of the Pi SDK's built-in slash commands.
3
+ *
4
+ * The SDK `@mariozechner/pi-coding-agent` defines `BUILTIN_SLASH_COMMANDS`
5
+ * in `dist/core/slash-commands.js` but does NOT re-export it from the main
6
+ * package entry, and the `exports` field of its `package.json` blocks deep
7
+ * imports. So pi-extension carries this manually-maintained mirror until
8
+ * an upstream PR exposes the constant publicly.
9
+ *
10
+ * **Maintenance**: when bumping `@mariozechner/pi-coding-agent`, diff the
11
+ * runtime's `BUILTIN_SLASH_COMMANDS` against this file and update names,
12
+ * descriptions, and the invokable / takes_args flags. The Wave 0 scout of
13
+ * plan/28 captured the 0.73.1 baseline; later bumps should leave a
14
+ * one-liner note here documenting which SDK version was synced.
15
+ *
16
+ * Synced from SDK version: **0.73.1**.
17
+ *
18
+ * **Invokability**: a builtin is `invokable: true` only when an entry in
19
+ * `ExtensionContextActions` lets the extension run it without simulating
20
+ * keyboard input in the TUI. The full mapping lives in `dispatcher.ts`
21
+ * (Wave B Slice 2). When more upstream APIs land, flip more flags to
22
+ * `true` here and add the corresponding dispatch in `dispatcher.ts`.
23
+ */
24
+ export const BUILTIN_SLASH_COMMANDS_MIRROR = [
25
+ // Session lifecycle
26
+ { name: "compact", description: "Manually compact the session context", invokable: true, takes_args: false },
27
+ { name: "new", description: "Start a new session", invokable: false, takes_args: false },
28
+ { name: "resume", description: "Resume a different session", invokable: false, takes_args: false },
29
+ { name: "fork", description: "Create a new fork from a previous user message", invokable: false, takes_args: false },
30
+ { name: "clone", description: "Duplicate the current session at the current position", invokable: false, takes_args: false },
31
+ { name: "tree", description: "Navigate session tree (switch branches)", invokable: false, takes_args: false },
32
+ { name: "name", description: "Set session display name", invokable: false, takes_args: true },
33
+ { name: "session", description: "Show session info and stats", invokable: false, takes_args: false },
34
+ // Model / providers
35
+ { name: "model", description: "Select model", invokable: true, takes_args: true },
36
+ { name: "scoped-models", description: "Enable/disable models for Ctrl+P cycling", invokable: false, takes_args: false },
37
+ { name: "login", description: "Configure provider authentication", invokable: false, takes_args: false },
38
+ { name: "logout", description: "Remove provider authentication", invokable: false, takes_args: false },
39
+ // Import / export / share
40
+ { name: "export", description: "Export session (HTML default, or specify path)", invokable: false, takes_args: true },
41
+ { name: "import", description: "Import and resume a session from a JSONL file", invokable: false, takes_args: true },
42
+ { name: "share", description: "Share session as a secret GitHub gist", invokable: false, takes_args: false },
43
+ { name: "copy", description: "Copy last agent message to clipboard", invokable: false, takes_args: false },
44
+ // UI / settings
45
+ { name: "settings", description: "Open settings menu", invokable: false, takes_args: false },
46
+ { name: "hotkeys", description: "Show all keyboard shortcuts", invokable: false, takes_args: false },
47
+ { name: "changelog", description: "Show changelog entries", invokable: false, takes_args: false },
48
+ { name: "reload", description: "Reload keybindings, extensions, skills, prompts, themes", invokable: false, takes_args: false },
49
+ { name: "quit", description: "Quit pi", invokable: true, takes_args: false },
50
+ ];
51
+ /**
52
+ * Lookup helper used by the dispatcher. Returns the mirror entry for a
53
+ * builtin name, or `undefined` if `name` is not a known builtin.
54
+ */
55
+ export function findBuiltin(name) {
56
+ return BUILTIN_SLASH_COMMANDS_MIRROR.find((c) => c.name === name);
57
+ }
58
+ /**
59
+ * Project a mirror entry to the wire schema. Shared by the list_commands
60
+ * handler so the mirror and the wire stay in lockstep.
61
+ */
62
+ export function builtinToWire(entry) {
63
+ return {
64
+ name: entry.name,
65
+ description: entry.description,
66
+ source: "builtin",
67
+ invokable: entry.invokable,
68
+ takes_args: entry.takes_args,
69
+ };
70
+ }
71
+ //# sourceMappingURL=builtin_mirror.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin_mirror.js","sourceRoot":"","sources":["../../src/commands/builtin_mirror.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AA4BH,MAAM,CAAC,MAAM,6BAA6B,GAAkC;IAC1E,oBAAoB;IACpB,EAAE,IAAI,EAAE,SAAS,EAAQ,WAAW,EAAE,sCAAsC,EAAiB,SAAS,EAAE,IAAI,EAAG,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,KAAK,EAAY,WAAW,EAAE,qBAAqB,EAAkC,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,QAAQ,EAAS,WAAW,EAAE,4BAA4B,EAA2B,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,MAAM,EAAW,WAAW,EAAE,gDAAgD,EAAO,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,OAAO,EAAU,WAAW,EAAE,uDAAuD,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IACpI,EAAE,IAAI,EAAE,MAAM,EAAW,WAAW,EAAE,yCAAyC,EAAc,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,MAAM,EAAW,WAAW,EAAE,0BAA0B,EAA6B,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAG;IAClI,EAAE,IAAI,EAAE,SAAS,EAAQ,WAAW,EAAE,6BAA6B,EAA0B,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAElI,oBAAoB;IACpB,EAAE,IAAI,EAAE,OAAO,EAAU,WAAW,EAAE,cAAc,EAAyC,SAAS,EAAE,IAAI,EAAG,UAAU,EAAE,IAAI,EAAG;IAClI,EAAE,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,0CAA0C,EAAa,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,OAAO,EAAU,WAAW,EAAE,mCAAmC,EAAoB,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,QAAQ,EAAS,WAAW,EAAE,gCAAgC,EAAuB,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAElI,0BAA0B;IAC1B,EAAE,IAAI,EAAE,QAAQ,EAAS,WAAW,EAAE,gDAAgD,EAAO,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAG;IAClI,EAAE,IAAI,EAAE,QAAQ,EAAS,WAAW,EAAE,+CAA+C,EAAQ,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAG;IAClI,EAAE,IAAI,EAAE,OAAO,EAAU,WAAW,EAAE,uCAAuC,EAAgB,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,MAAM,EAAW,WAAW,EAAE,sCAAsC,EAAiB,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAElI,gBAAgB;IAChB,EAAE,IAAI,EAAE,UAAU,EAAO,WAAW,EAAE,oBAAoB,EAAmC,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,SAAS,EAAQ,WAAW,EAAE,6BAA6B,EAA0B,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,WAAW,EAAM,WAAW,EAAE,wBAAwB,EAA+B,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IAClI,EAAE,IAAI,EAAE,QAAQ,EAAS,WAAW,EAAE,yDAAyD,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;IACtI,EAAE,IAAI,EAAE,MAAM,EAAW,WAAW,EAAE,SAAS,EAA8C,SAAS,EAAE,IAAI,EAAG,UAAU,EAAE,KAAK,EAAE;CAC1H,CAAC;AAEX;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,6BAA6B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACpE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAC;AACJ,CAAC"}