@moxxy/sdk 0.11.0 → 0.13.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 (73) hide show
  1. package/dist/assert.d.ts +19 -0
  2. package/dist/assert.d.ts.map +1 -0
  3. package/dist/assert.js +29 -0
  4. package/dist/assert.js.map +1 -0
  5. package/dist/elision-state.d.ts.map +1 -1
  6. package/dist/elision-state.js +6 -0
  7. package/dist/elision-state.js.map +1 -1
  8. package/dist/events.d.ts +33 -1
  9. package/dist/events.d.ts.map +1 -1
  10. package/dist/fs-utils.d.ts +8 -0
  11. package/dist/fs-utils.d.ts.map +1 -1
  12. package/dist/fs-utils.js +29 -0
  13. package/dist/fs-utils.js.map +1 -1
  14. package/dist/index.d.ts +11 -3
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +7 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/mode-helpers.d.ts +12 -0
  19. package/dist/mode-helpers.d.ts.map +1 -1
  20. package/dist/mode-helpers.js +105 -3
  21. package/dist/mode-helpers.js.map +1 -1
  22. package/dist/mode.d.ts +9 -0
  23. package/dist/mode.d.ts.map +1 -1
  24. package/dist/mode.js.map +1 -1
  25. package/dist/plugin.d.ts +10 -1
  26. package/dist/plugin.d.ts.map +1 -1
  27. package/dist/provider-login-bridge.d.ts +53 -0
  28. package/dist/provider-login-bridge.d.ts.map +1 -0
  29. package/dist/provider-login-bridge.js +95 -0
  30. package/dist/provider-login-bridge.js.map +1 -0
  31. package/dist/provider.d.ts +53 -0
  32. package/dist/provider.d.ts.map +1 -1
  33. package/dist/semver.d.ts +16 -0
  34. package/dist/semver.d.ts.map +1 -0
  35. package/dist/semver.js +28 -0
  36. package/dist/semver.js.map +1 -0
  37. package/dist/subagent.d.ts +6 -0
  38. package/dist/subagent.d.ts.map +1 -1
  39. package/dist/surface.d.ts +159 -0
  40. package/dist/surface.d.ts.map +1 -0
  41. package/dist/surface.js +27 -0
  42. package/dist/surface.js.map +1 -0
  43. package/dist/tool-display.d.ts +73 -0
  44. package/dist/tool-display.d.ts.map +1 -0
  45. package/dist/tool-display.js +66 -0
  46. package/dist/tool-display.js.map +1 -0
  47. package/dist/view-renderer.d.ts +6 -0
  48. package/dist/view-renderer.d.ts.map +1 -1
  49. package/dist/view-renderer.js +18 -1
  50. package/dist/view-renderer.js.map +1 -1
  51. package/package.json +7 -3
  52. package/src/assert.test.ts +35 -0
  53. package/src/assert.ts +28 -0
  54. package/src/elision-state.ts +5 -0
  55. package/src/events.ts +36 -0
  56. package/src/fs-utils.test.ts +47 -1
  57. package/src/fs-utils.ts +31 -0
  58. package/src/index.ts +51 -2
  59. package/src/loop-helpers.test.ts +40 -0
  60. package/src/mode-helpers.ts +114 -3
  61. package/src/mode.ts +7 -0
  62. package/src/plugin.ts +10 -1
  63. package/src/provider-login-bridge.test.ts +78 -0
  64. package/src/provider-login-bridge.ts +105 -0
  65. package/src/provider.ts +45 -2
  66. package/src/semver.test.ts +43 -0
  67. package/src/semver.ts +27 -0
  68. package/src/subagent.ts +6 -0
  69. package/src/surface.ts +173 -0
  70. package/src/tool-display.test.ts +71 -0
  71. package/src/tool-display.ts +118 -0
  72. package/src/view-renderer.test.ts +57 -0
  73. package/src/view-renderer.ts +18 -1
@@ -0,0 +1,159 @@
1
+ /**
2
+ * A Surface is a long-lived, interactive pane that BOTH a human viewer (a
3
+ * desktop panel) and the agent drive together: an embedded terminal (a shared
4
+ * PTY) or an in-window browser (a shared page). Unlike a {@link Channel} — which
5
+ * is a whole conversation transport — a Surface is a single resource attached to
6
+ * an existing Session, streaming opaque output frames out and accepting opaque
7
+ * input messages in.
8
+ *
9
+ * Surfaces are RUNNER-OWNED: the underlying resource (PTY, Playwright page) lives
10
+ * in the same process as the agent's tools, so the agent reads/writes the exact
11
+ * same instance the user watches. A thin client (the desktop) renders the
12
+ * streamed frames and relays the user's input back over the runner protocol —
13
+ * there is no reverse RPC. Plugins contribute surfaces via
14
+ * `definePlugin({ surfaces: [defineSurface(...)] })`; the plugin's own tools
15
+ * (e.g. `terminal`, `browser_session`) share the resource through module state.
16
+ *
17
+ * The payloads (`SurfaceDataMessage.payload`, `SurfaceInputMessage`) are
18
+ * deliberately opaque (`unknown` / open record): they cross the JSON-RPC wire
19
+ * verbatim and each surface kind defines its own shape (PTY bytes, a base64
20
+ * frame, a navigate request). Keeping them untyped here means a new surface kind
21
+ * never has to touch this file or the protocol.
22
+ */
23
+ /**
24
+ * Surface kind discriminator. Open string union so plugins add kinds without
25
+ * editing the SDK; the built-ins are `'terminal'` and `'browser'`.
26
+ */
27
+ export type SurfaceKind = 'terminal' | 'browser' | (string & {});
28
+ /** One outbound frame from a surface instance to its viewers. */
29
+ export interface SurfaceDataMessage {
30
+ /** The instance this frame belongs to (a viewer may watch several). */
31
+ readonly surfaceId: string;
32
+ readonly kind: SurfaceKind;
33
+ /** Surface-specific payload (PTY text, a base64 frame, a url/title update). */
34
+ readonly payload: unknown;
35
+ }
36
+ /**
37
+ * One inbound message from a viewer to a surface instance — a keystroke, a
38
+ * mouse event, a navigate request, a resize. `type` discriminates; the rest is
39
+ * surface-specific.
40
+ */
41
+ export interface SurfaceInputMessage {
42
+ readonly type: string;
43
+ readonly [key: string]: unknown;
44
+ }
45
+ /** Viewport hint for a resize (terminal cols/rows or pixel width/height). */
46
+ export interface SurfaceSize {
47
+ readonly cols?: number;
48
+ readonly rows?: number;
49
+ readonly width?: number;
50
+ readonly height?: number;
51
+ }
52
+ /**
53
+ * A live, attached surface instance — the running PTY or browser page. Opening
54
+ * the same kind twice returns the SAME instance (surfaces are shared), so a
55
+ * viewer that joins late gets the existing resource plus its {@link snapshot}.
56
+ */
57
+ export interface SurfaceInstance {
58
+ readonly id: string;
59
+ readonly kind: SurfaceKind;
60
+ /** Subscribe to outbound frames. Returns an unsubscribe fn. */
61
+ onData(cb: (payload: unknown) => void): () => void;
62
+ /**
63
+ * A catch-up payload for a late-joining viewer (terminal scrollback, the last
64
+ * browser frame, the current url). Optional — a surface with no replayable
65
+ * state omits it.
66
+ */
67
+ snapshot?(): unknown;
68
+ /** Apply an inbound message from a viewer (or the agent's tool). */
69
+ input(msg: SurfaceInputMessage): void | Promise<void>;
70
+ /** Re-size the viewport, when the surface is size-aware. */
71
+ resize?(size: SurfaceSize): void | Promise<void>;
72
+ /**
73
+ * Detach this instance. The underlying shared resource MAY persist (the
74
+ * agent's tool can still use the PTY/page); `close` just tears down streaming
75
+ * + viewer state. A surface that owns its resource exclusively disposes it.
76
+ */
77
+ close(): void | Promise<void>;
78
+ }
79
+ /** Whether a surface kind can run right now (e.g. node-pty present). */
80
+ export interface SurfaceAvailability {
81
+ readonly ok: boolean;
82
+ /** Human-readable explanation when `ok` is false (shown in the empty pane). */
83
+ readonly reason?: string;
84
+ }
85
+ /** Context handed to a surface when it opens. */
86
+ export interface SurfaceContext {
87
+ /** Working directory of the owning Session. */
88
+ readonly cwd: string;
89
+ readonly logger?: {
90
+ debug?(msg: string, meta?: Record<string, unknown>): void;
91
+ info?(msg: string, meta?: Record<string, unknown>): void;
92
+ warn?(msg: string, meta?: Record<string, unknown>): void;
93
+ error?(msg: string, meta?: Record<string, unknown>): void;
94
+ };
95
+ }
96
+ /**
97
+ * A registered, named factory for a Surface. `open` is idempotent per kind: a
98
+ * second `open` attaches to the resource the first one created (the host
99
+ * enforces this), so the agent's tool and the user's pane share one instance.
100
+ */
101
+ export interface SurfaceDef {
102
+ readonly kind: SurfaceKind;
103
+ readonly description?: string;
104
+ open(ctx: SurfaceContext): Promise<SurfaceInstance> | SurfaceInstance;
105
+ /** Optional runtime gate (default: always available). */
106
+ isAvailable?(ctx: SurfaceContext): Promise<SurfaceAvailability> | SurfaceAvailability;
107
+ }
108
+ /** Identity helper mirroring `defineTool` / `defineChannel`. */
109
+ export declare function defineSurface(def: SurfaceDef): SurfaceDef;
110
+ /**
111
+ * Read-only registry of surface defs contributed by plugins. Implementation
112
+ * lives in @moxxy/core.
113
+ */
114
+ export interface SurfaceRegistry {
115
+ list(): ReadonlyArray<SurfaceDef>;
116
+ get(kind: SurfaceKind): SurfaceDef | undefined;
117
+ has(kind: SurfaceKind): boolean;
118
+ }
119
+ /** Wire-friendly surface descriptor for `surface.list` (no functions). */
120
+ export interface SurfaceInfo {
121
+ readonly kind: SurfaceKind;
122
+ readonly description?: string;
123
+ readonly available: boolean;
124
+ /** Why it is unavailable, when `available` is false. */
125
+ readonly reason?: string;
126
+ }
127
+ /** Result of opening a surface — its id + a catch-up snapshot for the viewer. */
128
+ export interface OpenSurfaceResult {
129
+ readonly surfaceId: string;
130
+ readonly kind: SurfaceKind;
131
+ readonly snapshot?: unknown;
132
+ }
133
+ /**
134
+ * The runtime manager of open surface instances, present on an in-process
135
+ * `Session`. The runner server drives it on behalf of attached clients; the
136
+ * agent's tools reach the SAME underlying resources through plugin module state.
137
+ * Output from every open instance is multiplexed through {@link onData}.
138
+ */
139
+ export interface SurfaceHost {
140
+ /** Available surface kinds with their current availability. */
141
+ list(): Promise<ReadonlyArray<SurfaceInfo>>;
142
+ /** Open (or attach to the shared) instance for a kind. */
143
+ open(kind: SurfaceKind): Promise<OpenSurfaceResult>;
144
+ /** Route a viewer message to an open instance. No-op if it isn't open. */
145
+ input(surfaceId: string, msg: SurfaceInputMessage): Promise<void>;
146
+ /** Resize an open instance. No-op if it isn't open or isn't size-aware. */
147
+ resize(surfaceId: string, size: SurfaceSize): Promise<void>;
148
+ /** Close one open instance. */
149
+ close(surfaceId: string): Promise<void>;
150
+ /**
151
+ * Subscribe to outbound frames from EVERY open instance (multiplexed by
152
+ * `surfaceId`). Returns an unsubscribe fn. The runner subscribes once and
153
+ * broadcasts each frame as a `surface.data` notification.
154
+ */
155
+ onData(cb: (msg: SurfaceDataMessage) => void): () => void;
156
+ /** Close every open instance (session teardown). */
157
+ closeAll(): Promise<void>;
158
+ }
159
+ //# sourceMappingURL=surface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * A Surface is a long-lived, interactive pane that BOTH a human viewer (a
3
+ * desktop panel) and the agent drive together: an embedded terminal (a shared
4
+ * PTY) or an in-window browser (a shared page). Unlike a {@link Channel} — which
5
+ * is a whole conversation transport — a Surface is a single resource attached to
6
+ * an existing Session, streaming opaque output frames out and accepting opaque
7
+ * input messages in.
8
+ *
9
+ * Surfaces are RUNNER-OWNED: the underlying resource (PTY, Playwright page) lives
10
+ * in the same process as the agent's tools, so the agent reads/writes the exact
11
+ * same instance the user watches. A thin client (the desktop) renders the
12
+ * streamed frames and relays the user's input back over the runner protocol —
13
+ * there is no reverse RPC. Plugins contribute surfaces via
14
+ * `definePlugin({ surfaces: [defineSurface(...)] })`; the plugin's own tools
15
+ * (e.g. `terminal`, `browser_session`) share the resource through module state.
16
+ *
17
+ * The payloads (`SurfaceDataMessage.payload`, `SurfaceInputMessage`) are
18
+ * deliberately opaque (`unknown` / open record): they cross the JSON-RPC wire
19
+ * verbatim and each surface kind defines its own shape (PTY bytes, a base64
20
+ * frame, a navigate request). Keeping them untyped here means a new surface kind
21
+ * never has to touch this file or the protocol.
22
+ */
23
+ /** Identity helper mirroring `defineTool` / `defineChannel`. */
24
+ export function defineSurface(def) {
25
+ return def;
26
+ }
27
+ //# sourceMappingURL=surface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface.js","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AA+FH,gEAAgE;AAChE,MAAM,UAAU,aAAa,CAAC,GAAe;IAC3C,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Channel-agnostic "rich tool result" payloads.
3
+ *
4
+ * A tool whose result is more than a line of text (a file diff, eventually a
5
+ * table or chart) returns a `ToolDisplayResult`: a short `forModel` string the
6
+ * model sees, plus a structured `display` every channel can render natively.
7
+ * The projection layer (see `mode-helpers.ts`) sends ONLY `forModel` to the
8
+ * model, so the rich payload never bloats the context window.
9
+ *
10
+ * The first (and currently only) display kind is `file-diff`, emitted by the
11
+ * built-in Write/Edit tools. It carries the changed slices of a file (a few
12
+ * lines of context around each edit) — never the whole file — so the payload
13
+ * stays bounded regardless of file size. Channels render it as a classic diff:
14
+ * line numbers, +/- markers, green/red line backgrounds.
15
+ */
16
+ /** One rendered line of a diff. */
17
+ export interface DiffLine {
18
+ readonly kind: 'context' | 'add' | 'del';
19
+ readonly text: string;
20
+ /** 1-based line number in the OLD file (del + context lines). */
21
+ readonly oldNo?: number;
22
+ /** 1-based line number in the NEW file (add + context lines). */
23
+ readonly newNo?: number;
24
+ }
25
+ /** A contiguous changed region plus its surrounding context lines. */
26
+ export interface DiffHunk {
27
+ readonly oldStart: number;
28
+ readonly oldLines: number;
29
+ readonly newStart: number;
30
+ readonly newLines: number;
31
+ readonly lines: ReadonlyArray<DiffLine>;
32
+ }
33
+ /** Structured diff for a single file write/edit. */
34
+ export interface FileDiffDisplay {
35
+ readonly kind: 'file-diff';
36
+ /** Display path — relative to cwd when possible, else absolute. */
37
+ readonly path: string;
38
+ readonly mode: 'create' | 'update';
39
+ readonly added: number;
40
+ readonly removed: number;
41
+ readonly hunks: ReadonlyArray<DiffHunk>;
42
+ /** Set when a very large diff was capped (some hunks/lines dropped). */
43
+ readonly truncated?: boolean;
44
+ }
45
+ /** Extensible union of structured tool-result payloads. */
46
+ export type ToolDisplay = FileDiffDisplay;
47
+ /**
48
+ * The shape a tool returns when it wants a rich, channel-rendered result.
49
+ * `forModel` is the only thing the model sees; `display` is for channels.
50
+ */
51
+ export interface ToolDisplayResult {
52
+ readonly forModel: string;
53
+ readonly display: ToolDisplay;
54
+ }
55
+ export declare function isToolDisplayResult(x: unknown): x is ToolDisplayResult;
56
+ export declare function isToolDisplay(x: unknown): x is ToolDisplay;
57
+ export declare function isFileDiffDisplay(x: unknown): x is FileDiffDisplay;
58
+ /** Human summary, e.g. "Added 10 lines, removed 1 line". */
59
+ export declare function fileDiffSummary(d: FileDiffDisplay): string;
60
+ /** Verb for the diff header — "Create" for new files, else "Update". */
61
+ export declare function fileDiffVerb(d: FileDiffDisplay): string;
62
+ /** Gutter number a renderer should show for a line (new number, or old for deletions). */
63
+ export declare function diffGutterNo(line: DiffLine): number | undefined;
64
+ /** A renderable row: either a diff line or a gap marker between hunks. */
65
+ export type DiffRow = DiffLine | {
66
+ readonly kind: 'gap';
67
+ };
68
+ /**
69
+ * Flatten a file diff's hunks into a single row list, inserting a `gap` marker
70
+ * between non-contiguous hunks (channels render it as a `⋯` separator).
71
+ */
72
+ export declare function toDiffRows(d: FileDiffDisplay): DiffRow[];
73
+ //# sourceMappingURL=tool-display.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-display.d.ts","sourceRoot":"","sources":["../src/tool-display.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,mCAAmC;AACnC,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,KAAK,GAAG,KAAK,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,sEAAsE;AACtE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;CACzC;AAED,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IACxC,wEAAwE;IACxE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,2DAA2D;AAC3D,MAAM,MAAM,WAAW,GAAG,eAAe,CAAC;AAE1C;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;CAC/B;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,iBAAiB,CAOtE;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,WAAW,CAE1D;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,eAAe,CAOlE;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAQ1D;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAEvD;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAE/D;AAED,0EAA0E;AAC1E,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,eAAe,GAAG,OAAO,EAAE,CAOxD"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Channel-agnostic "rich tool result" payloads.
3
+ *
4
+ * A tool whose result is more than a line of text (a file diff, eventually a
5
+ * table or chart) returns a `ToolDisplayResult`: a short `forModel` string the
6
+ * model sees, plus a structured `display` every channel can render natively.
7
+ * The projection layer (see `mode-helpers.ts`) sends ONLY `forModel` to the
8
+ * model, so the rich payload never bloats the context window.
9
+ *
10
+ * The first (and currently only) display kind is `file-diff`, emitted by the
11
+ * built-in Write/Edit tools. It carries the changed slices of a file (a few
12
+ * lines of context around each edit) — never the whole file — so the payload
13
+ * stays bounded regardless of file size. Channels render it as a classic diff:
14
+ * line numbers, +/- markers, green/red line backgrounds.
15
+ */
16
+ export function isToolDisplayResult(x) {
17
+ return (typeof x === 'object' &&
18
+ x !== null &&
19
+ typeof x.forModel === 'string' &&
20
+ isToolDisplay(x.display));
21
+ }
22
+ export function isToolDisplay(x) {
23
+ return isFileDiffDisplay(x);
24
+ }
25
+ export function isFileDiffDisplay(x) {
26
+ return (typeof x === 'object' &&
27
+ x !== null &&
28
+ x.kind === 'file-diff' &&
29
+ Array.isArray(x.hunks));
30
+ }
31
+ /** Human summary, e.g. "Added 10 lines, removed 1 line". */
32
+ export function fileDiffSummary(d) {
33
+ const plural = (n, w) => `${n} ${w}${n === 1 ? '' : 's'}`;
34
+ const parts = [];
35
+ if (d.added > 0 || d.removed === 0)
36
+ parts.push(`Added ${plural(d.added, 'line')}`);
37
+ if (d.removed > 0)
38
+ parts.push(`${parts.length ? 'removed' : 'Removed'} ${plural(d.removed, 'line')}`);
39
+ let summary = parts.join(', ');
40
+ if (d.truncated)
41
+ summary += ' (diff truncated)';
42
+ return summary;
43
+ }
44
+ /** Verb for the diff header — "Create" for new files, else "Update". */
45
+ export function fileDiffVerb(d) {
46
+ return d.mode === 'create' ? 'Create' : 'Update';
47
+ }
48
+ /** Gutter number a renderer should show for a line (new number, or old for deletions). */
49
+ export function diffGutterNo(line) {
50
+ return line.kind === 'del' ? line.oldNo : line.newNo;
51
+ }
52
+ /**
53
+ * Flatten a file diff's hunks into a single row list, inserting a `gap` marker
54
+ * between non-contiguous hunks (channels render it as a `⋯` separator).
55
+ */
56
+ export function toDiffRows(d) {
57
+ const rows = [];
58
+ d.hunks.forEach((hunk, i) => {
59
+ if (i > 0)
60
+ rows.push({ kind: 'gap' });
61
+ for (const line of hunk.lines)
62
+ rows.push(line);
63
+ });
64
+ return rows;
65
+ }
66
+ //# sourceMappingURL=tool-display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-display.js","sourceRoot":"","sources":["../src/tool-display.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA8CH,MAAM,UAAU,mBAAmB,CAAC,CAAU;IAC5C,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACV,OAAQ,CAA4B,CAAC,QAAQ,KAAK,QAAQ;QAC1D,aAAa,CAAE,CAA2B,CAAC,OAAO,CAAC,CACpD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAU;IACtC,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,CAAU;IAC1C,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACT,CAAwB,CAAC,IAAI,KAAK,WAAW;QAC9C,KAAK,CAAC,OAAO,CAAE,CAAyB,CAAC,KAAK,CAAC,CAChD,CAAC;AACJ,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,eAAe,CAAC,CAAkB;IAChD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAClF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACnF,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACtG,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC,SAAS;QAAE,OAAO,IAAI,mBAAmB,CAAC;IAChD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,YAAY,CAAC,CAAkB;IAC7C,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AACnD,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,OAAO,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AACvD,CAAC;AAKD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,CAAkB;IAC3C,MAAM,IAAI,GAAc,EAAE,CAAC;IAC3B,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QAC1B,IAAI,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -109,4 +109,10 @@ export declare const VIEW_PRIMITIVES: ReadonlyArray<ViewTagSpec>;
109
109
  export declare const VIEW_COMPONENTS: ReadonlyArray<ViewTagSpec>;
110
110
  /** The default renderer's full allow-list (primitives + components). */
111
111
  export declare const DEFAULT_VIEW_TAGS: ReadonlyArray<ViewTagSpec>;
112
+ /**
113
+ * Count element + text nodes in a view tree (the `nodeCount` a `present_view`
114
+ * tool reports). Single source of truth: core's parser and the plugin-view tool
115
+ * both import this rather than re-implementing the recursion.
116
+ */
117
+ export declare function countNodes(node: ViewNode): number;
112
118
  //# sourceMappingURL=view-renderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"view-renderer.d.ts","sourceRoot":"","sources":["../src/view-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,+EAA+E;AAC/E,MAAM,MAAM,QAAQ,GAChB;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IACpE,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC3C,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;CAAE,GAC5C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,CAAA;CAAE,CAAC;AAM3E,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAEhE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,iDAAiD;IACjD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IACnD,yEAAyE;IACzE,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC;IACjE,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC/C,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAAC;IACvC,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAMhE;AAKD,gFAAgF;AAChF,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC,WAAW,CA+BtD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC,WAAW,CAetD,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,WAAW,CAA4C,CAAC"}
1
+ {"version":3,"file":"view-renderer.d.ts","sourceRoot":"","sources":["../src/view-renderer.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,14 @@
26
26
  * parties, so a `javascript:` link is click-XSS on a shared surface.
27
27
  */
28
28
  export function isSafeViewUrl(url, attr) {
29
- const u = url.trim().toLowerCase();
29
+ // Strip ALL ASCII whitespace + C0 control chars (U+0000–U+0020) anywhere in
30
+ // the URL before the scheme check — the HTML URL parser removes tab/newline/CR
31
+ // before resolving the scheme, so `java\tscript:` would otherwise pass this
32
+ // gate and then execute as `javascript:` on click (audit u72-1). The frontend
33
+ // copy in @moxxy/plugin-channel-web/src/frontend/url-safety.ts is a verbatim
34
+ // lockstep duplicate (the browser bundle can't import this root) — keep both
35
+ // in sync.
36
+ const u = url.replace(/[\u0000-\u0020]/g, '').toLowerCase();
30
37
  if (u.startsWith('javascript:') || u.startsWith('vbscript:'))
31
38
  return false;
32
39
  if (u.startsWith('data:'))
@@ -93,4 +100,14 @@ export const VIEW_COMPONENTS = [
93
100
  ];
94
101
  /** The default renderer's full allow-list (primitives + components). */
95
102
  export const DEFAULT_VIEW_TAGS = [...VIEW_PRIMITIVES, ...VIEW_COMPONENTS];
103
+ /**
104
+ * Count element + text nodes in a view tree (the `nodeCount` a `present_view`
105
+ * tool reports). Single source of truth: core's parser and the plugin-view tool
106
+ * both import this rather than re-implementing the recursion.
107
+ */
108
+ export function countNodes(node) {
109
+ if (node.kind === 'text')
110
+ return 1;
111
+ return 1 + node.children.reduce((sum, child) => sum + countNodes(child), 0);
112
+ }
96
113
  //# sourceMappingURL=view-renderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"view-renderer.js","sourceRoot":"","sources":["../src/view-renderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"view-renderer.js","sourceRoot":"","sources":["../src/view-renderer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moxxy/sdk",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Typed public surface for the moxxy framework: event types, define* factories, lifecycle hook signatures.",
5
5
  "keywords": [
6
6
  "moxxy",
@@ -44,6 +44,10 @@
44
44
  ".": {
45
45
  "types": "./dist/index.d.ts",
46
46
  "import": "./dist/index.js"
47
+ },
48
+ "./tool-display": {
49
+ "types": "./dist/tool-display.d.ts",
50
+ "import": "./dist/tool-display.js"
47
51
  }
48
52
  },
49
53
  "files": [
@@ -61,8 +65,8 @@
61
65
  "typescript": "^5.7.3",
62
66
  "vitest": "^2.1.8",
63
67
  "zod": "^3.24.0",
64
- "@moxxy/vitest-preset": "0.0.0",
65
- "@moxxy/tsconfig": "0.0.0"
68
+ "@moxxy/tsconfig": "0.0.0",
69
+ "@moxxy/vitest-preset": "0.0.0"
66
70
  },
67
71
  "scripts": {
68
72
  "build": "tsc -p tsconfig.json",
@@ -0,0 +1,35 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { assertNever } from './assert.js';
3
+
4
+ describe('assertNever', () => {
5
+ it('throws with the offending value embedded', () => {
6
+ // Cast through unknown: simulate an untyped caller defeating the never narrowing.
7
+ expect(() => assertNever('surprise' as unknown as never)).toThrow(/surprise/);
8
+ });
9
+
10
+ it('uses a custom message when provided', () => {
11
+ expect(() => assertNever(3 as unknown as never, 'bad kind')).toThrow('bad kind');
12
+ });
13
+
14
+ it('survives a value that cannot be JSON-stringified', () => {
15
+ const circular: Record<string, unknown> = {};
16
+ circular.self = circular;
17
+ expect(() => assertNever(circular as unknown as never)).toThrow(/assertNever/);
18
+ });
19
+
20
+ it('narrows exhaustively at compile time', () => {
21
+ type Shape = { kind: 'a' } | { kind: 'b' };
22
+ const area = (s: Shape): string => {
23
+ switch (s.kind) {
24
+ case 'a':
25
+ return 'a';
26
+ case 'b':
27
+ return 'b';
28
+ default:
29
+ return assertNever(s);
30
+ }
31
+ };
32
+ expect(area({ kind: 'a' })).toBe('a');
33
+ expect(area({ kind: 'b' })).toBe('b');
34
+ });
35
+ });
package/src/assert.ts ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Exhaustiveness guard for discriminated unions. Put it in the `default:` branch
3
+ * (or any spot the type system has narrowed to `never`): if a new union member
4
+ * is added without a matching case, the call becomes a **compile error** instead
5
+ * of a silent runtime no-op.
6
+ *
7
+ * ```ts
8
+ * switch (action.kind) {
9
+ * case 'a': return handleA(action);
10
+ * case 'b': return handleB(action);
11
+ * default: return assertNever(action);
12
+ * }
13
+ * ```
14
+ *
15
+ * At runtime — should the narrowing be defeated by an untyped caller — it throws
16
+ * with the offending value, surfacing the bug rather than swallowing it.
17
+ */
18
+ export function assertNever(value: never, message?: string): never {
19
+ throw new Error(message ?? `assertNever: unexpected value ${stringify(value)}`);
20
+ }
21
+
22
+ function stringify(value: unknown): string {
23
+ try {
24
+ return JSON.stringify(value) ?? String(value);
25
+ } catch {
26
+ return String(value);
27
+ }
28
+ }
@@ -1,4 +1,5 @@
1
1
  import type { MoxxyEvent } from './events.js';
2
+ import { isToolDisplayResult } from './tool-display.js';
2
3
 
3
4
  /**
4
5
  * Shared elision decision logic — the single source of truth for "is this event
@@ -16,6 +17,10 @@ export const TINY_TURN_CHARS = 200;
16
17
  export function toolResultBytes(output: unknown, errorMessage?: string): number {
17
18
  if (errorMessage !== undefined) return errorMessage.length;
18
19
  if (typeof output === 'string') return output.length;
20
+ // Rich results (e.g. file diffs) only ever send their short `forModel`
21
+ // string to the model — measure THAT so the estimate matches projection
22
+ // and the bulky `display` payload never trips elision.
23
+ if (isToolDisplayResult(output)) return output.forModel.length;
19
24
  try {
20
25
  return JSON.stringify(output ?? '').length;
21
26
  } catch {
package/src/events.ts CHANGED
@@ -49,6 +49,40 @@ export interface AssistantMessageEvent extends EventBase {
49
49
  readonly stopReason: 'end_turn' | 'tool_use' | 'max_tokens' | 'stop_sequence' | 'error';
50
50
  }
51
51
 
52
+ /**
53
+ * A live reasoning/thinking delta. Parallels {@link AssistantChunkEvent}: it is
54
+ * streamed for the UI's live "thinking…" preview and is NOT retained in the
55
+ * display log (renderers accumulate it ephemerally, clearing on the matching
56
+ * {@link ReasoningMessageEvent} or the turn's `assistant_message`). Only
57
+ * emitted when the active provider+model supports reasoning AND it is enabled
58
+ * in that provider's config.
59
+ */
60
+ export interface ReasoningChunkEvent extends EventBase {
61
+ readonly type: 'reasoning_chunk';
62
+ readonly delta: string;
63
+ }
64
+
65
+ /**
66
+ * A finalized reasoning summary for ONE provider call. Parallels
67
+ * {@link AssistantMessageEvent}: it is persisted + replayed, and because
68
+ * `collectProviderStream` runs once per loop round these land between tool
69
+ * batches (the "summary of the work done between calls" behavior). The
70
+ * `signature`/`redacted`/`encrypted` fields exist purely for history
71
+ * round-trip — Anthropic requires the signed `thinking` block be replayed
72
+ * first on a tool-use continuation; Codex/Anthropic redacted thinking carries
73
+ * an opaque blob replayed verbatim and never shown.
74
+ */
75
+ export interface ReasoningMessageEvent extends EventBase {
76
+ readonly type: 'reasoning_message';
77
+ readonly content: string;
78
+ /** Anthropic thinking-block signature; absent for providers that don't sign. */
79
+ readonly signature?: string;
80
+ /** True when the reasoning is redacted/encrypted and must not be displayed. */
81
+ readonly redacted?: boolean;
82
+ /** Opaque provider blob (Anthropic redacted_thinking data / Codex encrypted_content) replayed as-is. */
83
+ readonly encrypted?: string;
84
+ }
85
+
52
86
  export interface ToolCallRequestedEvent extends EventBase {
53
87
  readonly type: 'tool_call_requested';
54
88
  readonly callId: ToolCallId;
@@ -226,6 +260,8 @@ export type MoxxyEvent =
226
260
  | UserPromptEvent
227
261
  | AssistantChunkEvent
228
262
  | AssistantMessageEvent
263
+ | ReasoningChunkEvent
264
+ | ReasoningMessageEvent
229
265
  | ToolCallRequestedEvent
230
266
  | ToolCallApprovedEvent
231
267
  | ToolCallDeniedEvent