@duckmind/dm-darwin-arm64 0.33.2 → 0.33.4

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.
@@ -1,152 +0,0 @@
1
- import type { Api, Model } from "@mariozechner/pi-ai";
2
- import { createMockCtx, createMockDM } from "@juicesharp/rpiv-test-utils";
3
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
-
5
- vi.mock("./ask-ui.js", () => ({
6
- showAskOverlay: vi.fn(),
7
- }));
8
-
9
- vi.mock("@mariozechner/pi-ai", async (importOriginal) => {
10
- const actual = await importOriginal<typeof import("@mariozechner/pi-ai")>();
11
- return {
12
- ...actual,
13
- completeSimple: vi.fn(),
14
- getSupportedThinkingLevels: vi.fn(() => ["off", "minimal", "low", "medium", "high"]),
15
- };
16
- });
17
-
18
- import { completeSimple } from "@mariozechner/pi-ai";
19
- import { ASK_COMMAND_NAME, ASK_STATE_KEY, registerAskCommand } from "./ask.js";
20
- import { showAskOverlay } from "./ask-ui.js";
21
-
22
- const model = { provider: "a", id: "m" } as unknown as Model<Api>;
23
-
24
- type OverlayCtl = { setAnswer: ReturnType<typeof vi.fn>; setError: ReturnType<typeof vi.fn> };
25
-
26
- function stubOverlay(): OverlayCtl {
27
- const ctl: OverlayCtl = { setAnswer: vi.fn(), setError: vi.fn() };
28
- vi.mocked(showAskOverlay).mockReturnValueOnce({
29
- overlayPromise: Promise.resolve(),
30
- controllerReady: Promise.resolve(ctl as never),
31
- } as never);
32
- return ctl;
33
- }
34
-
35
- function doneResponse(text: string) {
36
- return {
37
- role: "assistant",
38
- content: [{ type: "text", text }],
39
- timestamp: Date.now(),
40
- stopReason: "done",
41
- };
42
- }
43
-
44
- beforeEach(() => {
45
- vi.mocked(showAskOverlay).mockReset();
46
- vi.mocked(completeSimple).mockReset();
47
- });
48
-
49
- afterEach(() => {
50
- delete (globalThis as Record<symbol, unknown>)[ASK_STATE_KEY];
51
- });
52
-
53
- function register() {
54
- const { DM, captured } = createMockDM();
55
- registerAskCommand(pi);
56
- return captured.commands.get(ASK_COMMAND_NAME)!;
57
- }
58
-
59
- describe("/ask — early-return branches", () => {
60
- it("!hasUI notifies error and skips overlay", async () => {
61
- const cmd = register();
62
- const ctx = createMockCtx({ hasUI: false, model });
63
- await cmd.handler("anything", ctx as never);
64
- expect(ctx.ui.notify).toHaveBeenCalledWith(expect.stringContaining("interactive"), "error");
65
- expect(showAskOverlay).not.toHaveBeenCalled();
66
- });
67
-
68
- it("empty question emits usage warning", async () => {
69
- const cmd = register();
70
- const ctx = createMockCtx({ hasUI: true, model });
71
- await cmd.handler(" ", ctx as never);
72
- expect(ctx.ui.notify).toHaveBeenCalledWith(expect.stringContaining("Usage"), "warning");
73
- expect(showAskOverlay).not.toHaveBeenCalled();
74
- });
75
-
76
- it("missing model notifies error", async () => {
77
- const cmd = register();
78
- const ctx = createMockCtx({ hasUI: true });
79
- await cmd.handler("hello?", ctx as never);
80
- expect(ctx.ui.notify).toHaveBeenCalledWith(expect.stringContaining("active model"), "error");
81
- expect(showAskOverlay).not.toHaveBeenCalled();
82
- });
83
- });
84
-
85
- describe("/ask — happy path", () => {
86
- it("invokes overlay, awaits executor, pipes answer to setAnswer", async () => {
87
- const ctl = stubOverlay();
88
- vi.mocked(completeSimple).mockResolvedValueOnce(doneResponse("42") as never);
89
- const cmd = register();
90
- const ctx = createMockCtx({ hasUI: true, model });
91
- await cmd.handler("what is 6 times 7?", ctx as never);
92
- expect(showAskOverlay).toHaveBeenCalledTimes(1);
93
- const params = vi.mocked(showAskOverlay).mock.calls[0][0];
94
- expect(params.question).toBe("what is 6 times 7?");
95
- expect(params.history).toEqual([]);
96
- expect(ctl.setAnswer).toHaveBeenCalledWith("42");
97
- expect(ctl.setError).not.toHaveBeenCalled();
98
- });
99
- });
100
-
101
- describe("/ask — aborted", () => {
102
- it("does not touch the overlay controller", async () => {
103
- const ctl = stubOverlay();
104
- vi.mocked(completeSimple).mockResolvedValueOnce({
105
- role: "assistant",
106
- content: [],
107
- timestamp: Date.now(),
108
- stopReason: "aborted",
109
- } as never);
110
- const cmd = register();
111
- const ctx = createMockCtx({ hasUI: true, model });
112
- await cmd.handler("q", ctx as never);
113
- expect(ctl.setAnswer).not.toHaveBeenCalled();
114
- expect(ctl.setError).not.toHaveBeenCalled();
115
- });
116
- });
117
-
118
- describe("/ask — executor failure", () => {
119
- it("pipes error into setError", async () => {
120
- const ctl = stubOverlay();
121
- vi.mocked(completeSimple).mockResolvedValueOnce({
122
- role: "assistant",
123
- content: [],
124
- timestamp: Date.now(),
125
- stopReason: "error",
126
- errorMessage: "upstream 502",
127
- } as never);
128
- const cmd = register();
129
- const ctx = createMockCtx({ hasUI: true, model });
130
- await cmd.handler("q", ctx as never);
131
- expect(ctl.setError).toHaveBeenCalledWith(expect.stringContaining("upstream 502"));
132
- expect(ctl.setAnswer).not.toHaveBeenCalled();
133
- });
134
- });
135
-
136
- describe("/ask — cross-session hint is rendered after turns accumulate", () => {
137
- it("second invocation's systemPrompt contains the recent-questions section", async () => {
138
- stubOverlay();
139
- vi.mocked(completeSimple).mockResolvedValueOnce(doneResponse("ans1") as never);
140
- const cmd = register();
141
- const ctx = createMockCtx({ hasUI: true, model });
142
- await cmd.handler("first question", ctx as never);
143
-
144
- stubOverlay();
145
- vi.mocked(completeSimple).mockResolvedValueOnce(doneResponse("ans2") as never);
146
- await cmd.handler("second question", ctx as never);
147
-
148
- const secondSystemPrompt = vi.mocked(completeSimple).mock.calls[1][1].systemPrompt ?? "";
149
- expect(secondSystemPrompt).toContain("Recent /ask questions across sessions");
150
- expect(secondSystemPrompt).toContain("first question");
151
- });
152
- });
@@ -1,340 +0,0 @@
1
- import {
2
- buildSessionEntries,
3
- createMockCtx,
4
- createMockDM,
5
- makeAssistantMessage,
6
- makeUserMessage,
7
- } from "@juicesharp/rpiv-test-utils";
8
- import { beforeEach, describe, expect, it, vi } from "vitest";
9
-
10
- vi.mock("@mariozechner/pi-ai", async (importOriginal) => {
11
- const actual = await importOriginal<typeof import("@mariozechner/pi-ai")>();
12
- return {
13
- ...actual,
14
- completeSimple: vi.fn(),
15
- getSupportedThinkingLevels: vi.fn(() => ["off", "minimal", "low", "medium", "high"]),
16
- };
17
- });
18
-
19
- import { type AssistantMessage, completeSimple, type UserMessage } from "@mariozechner/pi-ai";
20
- import {
21
- assistantMessageText,
22
- ASK_STATE_KEY,
23
- ASK_SYSTEM_PROMPT,
24
- CROSS_SESSION_HINT_LIMIT,
25
- clearSessionHistory,
26
- executeAsk,
27
- invalidateSnapshot,
28
- registerAskCommand,
29
- registerInvalidationHooks,
30
- registerMessageEndSnapshot,
31
- userMessageText,
32
- } from "./ask.js";
33
-
34
- function makeCompletionResponse(input: {
35
- text?: string;
36
- stopReason?: "done" | "aborted" | "error" | "toolUse";
37
- errorMessage?: string;
38
- }): AssistantMessage {
39
- return {
40
- role: "assistant",
41
- content: input.text ? [{ type: "text", text: input.text }] : [],
42
- timestamp: Date.now(),
43
- stopReason: input.stopReason ?? "done",
44
- errorMessage: input.errorMessage,
45
- } as unknown as AssistantMessage;
46
- }
47
-
48
- beforeEach(() => {
49
- vi.mocked(completeSimple).mockReset();
50
- delete (globalThis as Record<symbol, unknown>)[ASK_STATE_KEY];
51
- });
52
-
53
- describe("userMessageText", () => {
54
- it("returns string content as-is", () => {
55
- const msg = { role: "user", content: "hi", timestamp: 0 } as unknown as UserMessage;
56
- expect(userMessageText(msg)).toBe("hi");
57
- });
58
- it("joins text parts from array content", () => {
59
- expect(
60
- userMessageText({
61
- role: "user",
62
- content: [
63
- { type: "text", text: "a" },
64
- { type: "text", text: "b" },
65
- ],
66
- timestamp: 0,
67
- } as unknown as UserMessage),
68
- ).toBe("a\nb");
69
- });
70
- it("ignores non-text parts", () => {
71
- expect(
72
- userMessageText({
73
- role: "user",
74
- content: [
75
- { type: "text", text: "a" },
76
- { type: "image", data: "..." } as unknown as { type: "text"; text: string },
77
- ],
78
- timestamp: 0,
79
- } as unknown as UserMessage),
80
- ).toBe("a");
81
- });
82
- });
83
-
84
- describe("assistantMessageText", () => {
85
- it("joins text parts only, skips toolCalls", () => {
86
- const msg = makeAssistantMessage({
87
- text: "hello",
88
- toolCalls: [{ id: "c1", name: "web_search", arguments: {} }],
89
- });
90
- expect(assistantMessageText(msg)).toBe("hello");
91
- });
92
- it("returns empty string for content without text parts", () => {
93
- const msg = makeAssistantMessage({
94
- toolCalls: [{ id: "c1", name: "t", arguments: {} }],
95
- });
96
- expect(assistantMessageText(msg)).toBe("");
97
- });
98
- });
99
-
100
- describe("ASK_SYSTEM_PROMPT + ASK_STATE_KEY + CROSS_SESSION_HINT_LIMIT", () => {
101
- it("ASK_SYSTEM_PROMPT is a non-empty string loaded from prompts dir", () => {
102
- expect(typeof ASK_SYSTEM_PROMPT).toBe("string");
103
- expect(ASK_SYSTEM_PROMPT.length).toBeGreaterThan(0);
104
- });
105
- it("ASK_STATE_KEY is the shared Symbol.for('dm-ask')", () => {
106
- expect(ASK_STATE_KEY).toBe(Symbol.for("dm-ask"));
107
- });
108
- it("CROSS_SESSION_HINT_LIMIT is 10", () => {
109
- expect(CROSS_SESSION_HINT_LIMIT).toBe(10);
110
- });
111
- });
112
-
113
- describe("clearSessionHistory + invalidateSnapshot", () => {
114
- it("clearSessionHistory resets per-session history list", async () => {
115
- const ctx = createMockCtx();
116
- vi.mocked(completeSimple).mockResolvedValueOnce(makeCompletionResponse({ text: "answer" }) as never);
117
- ctx.model = { provider: "anthropic", id: "sonnet-4.6" } as never;
118
- await executeAsk("q", ctx, new AbortController());
119
- clearSessionHistory(ctx);
120
- const state = (globalThis as Record<symbol, { histories: Map<string, unknown[]> }>)[ASK_STATE_KEY];
121
- expect(state.histories.get("/tmp/test-session.jsonl")).toEqual([]);
122
- });
123
- it("invalidateSnapshot deletes the session's snapshot entry", () => {
124
- const ctx = createMockCtx();
125
- (globalThis as Record<symbol, { snapshots: Map<string, unknown> }>)[ASK_STATE_KEY] = {
126
- histories: new Map(),
127
- snapshots: new Map([["/tmp/test-session.jsonl", { messages: [] }]]),
128
- } as never;
129
- invalidateSnapshot(ctx);
130
- const state = (globalThis as Record<symbol, { snapshots: Map<string, unknown> }>)[ASK_STATE_KEY];
131
- expect(state.snapshots.has("/tmp/test-session.jsonl")).toBe(false);
132
- });
133
- });
134
-
135
- describe("executeAsk — ok path", () => {
136
- it("returns ok=true with answer + userMessage + assistantMessage", async () => {
137
- const ctx = createMockCtx();
138
- ctx.model = { provider: "a", id: "m" } as never;
139
- vi.mocked(completeSimple).mockResolvedValueOnce(makeCompletionResponse({ text: "answer text" }) as never);
140
- const r = await executeAsk("question", ctx, new AbortController());
141
- expect(r.ok).toBe(true);
142
- expect(r.answer).toBe("answer text");
143
- expect(r.userMessage?.content).toEqual([{ type: "text", text: "question" }]);
144
- expect(r.assistantMessage).toBeDefined();
145
- });
146
- });
147
-
148
- describe("executeAsk — error branches", () => {
149
- it("returns error when no model", async () => {
150
- const ctx = createMockCtx();
151
- ctx.model = undefined;
152
- const r = await executeAsk("q", ctx, new AbortController());
153
- expect(r).toMatchObject({ ok: false, error: "/ask requires an active model" });
154
- });
155
- it("returns error when getApiKeyAndHeaders is not ok", async () => {
156
- const ctx = createMockCtx();
157
- ctx.model = { provider: "a", id: "m" } as never;
158
- ctx.modelRegistry = {
159
- ...ctx.modelRegistry,
160
- getApiKeyAndHeaders: vi.fn(async () => ({ ok: false, error: "bad creds" })),
161
- } as never;
162
- const r = await executeAsk("q", ctx, new AbortController());
163
- expect(r.ok).toBe(false);
164
- expect(r.error).toContain("misconfigured");
165
- expect(r.error).toContain("bad creds");
166
- });
167
- it("returns error when apiKey absent", async () => {
168
- const ctx = createMockCtx();
169
- ctx.model = { provider: "a", id: "m" } as never;
170
- ctx.modelRegistry = {
171
- ...ctx.modelRegistry,
172
- getApiKeyAndHeaders: vi.fn(async () => ({ ok: true, apiKey: "", headers: {} })),
173
- } as never;
174
- const r = await executeAsk("q", ctx, new AbortController());
175
- expect(r.ok).toBe(false);
176
- expect(r.error).toContain("no API key");
177
- });
178
- it("returns aborted when stopReason=aborted", async () => {
179
- const ctx = createMockCtx();
180
- ctx.model = { provider: "a", id: "m" } as never;
181
- vi.mocked(completeSimple).mockResolvedValueOnce(makeCompletionResponse({ stopReason: "aborted" }) as never);
182
- const r = await executeAsk("q", ctx, new AbortController());
183
- expect(r).toMatchObject({ ok: false, aborted: true });
184
- });
185
- it("returns error when stopReason=error", async () => {
186
- const ctx = createMockCtx();
187
- ctx.model = { provider: "a", id: "m" } as never;
188
- vi.mocked(completeSimple).mockResolvedValueOnce(
189
- makeCompletionResponse({ stopReason: "error", errorMessage: "remote 500" }) as never,
190
- );
191
- const r = await executeAsk("q", ctx, new AbortController());
192
- expect(r.ok).toBe(false);
193
- expect(r.error).toContain("remote 500");
194
- });
195
- it("returns error when response has no text content", async () => {
196
- const ctx = createMockCtx();
197
- ctx.model = { provider: "a", id: "m" } as never;
198
- vi.mocked(completeSimple).mockResolvedValueOnce(makeCompletionResponse({ stopReason: "done" }) as never);
199
- const r = await executeAsk("q", ctx, new AbortController());
200
- expect(r.ok).toBe(false);
201
- expect(r.error).toContain("no text content");
202
- });
203
- it("translates controller.signal.aborted on thrown error to aborted=true", async () => {
204
- const ctx = createMockCtx();
205
- ctx.model = { provider: "a", id: "m" } as never;
206
- const controller = new AbortController();
207
- controller.abort();
208
- vi.mocked(completeSimple).mockRejectedValueOnce(new Error("abort"));
209
- const r = await executeAsk("q", ctx, controller);
210
- expect(r).toMatchObject({ ok: false, aborted: true });
211
- });
212
- it("wraps unknown throws as errCallThrew", async () => {
213
- const ctx = createMockCtx();
214
- ctx.model = { provider: "a", id: "m" } as never;
215
- vi.mocked(completeSimple).mockRejectedValueOnce(new Error("boom"));
216
- const r = await executeAsk("q", ctx, new AbortController());
217
- expect(r.ok).toBe(false);
218
- expect(r.error).toContain("call threw");
219
- expect(r.error).toContain("boom");
220
- });
221
- });
222
-
223
- describe("executeAsk — cross-session hint", () => {
224
- it("appends cross-session question list to systemPrompt", async () => {
225
- const ctx = createMockCtx();
226
- ctx.model = { provider: "a", id: "m" } as never;
227
-
228
- vi.mocked(completeSimple).mockResolvedValueOnce(makeCompletionResponse({ text: "first" }) as never);
229
- await executeAsk("first-question", ctx, new AbortController());
230
-
231
- vi.mocked(completeSimple).mockImplementationOnce((async (_model: unknown, req: { systemPrompt: string }) => {
232
- expect(req.systemPrompt).toContain("## Recent /ask questions across sessions");
233
- expect(req.systemPrompt).toContain("first-question");
234
- return makeCompletionResponse({ text: "second" });
235
- }) as never);
236
- await executeAsk("second-question", ctx, new AbortController());
237
- });
238
- it("caps cross-session list to CROSS_SESSION_HINT_LIMIT=10", async () => {
239
- const ctx = createMockCtx();
240
- ctx.model = { provider: "a", id: "m" } as never;
241
- for (let i = 0; i < 12; i++) {
242
- vi.mocked(completeSimple).mockResolvedValueOnce(makeCompletionResponse({ text: `a${i}` }) as never);
243
- await executeAsk(`q${i}`, ctx, new AbortController());
244
- }
245
- vi.mocked(completeSimple).mockImplementationOnce((async (_m: unknown, req: { systemPrompt: string }) => {
246
- const lines = req.systemPrompt.match(/^\d+\. /gm) ?? [];
247
- expect(lines.length).toBe(10);
248
- expect(req.systemPrompt).toContain("q11");
249
- expect(req.systemPrompt).not.toContain("q0.");
250
- return makeCompletionResponse({ text: "ok" });
251
- }) as never);
252
- await executeAsk("final", ctx, new AbortController());
253
- });
254
- });
255
-
256
- describe("executeAsk — branch threading", () => {
257
- it("prepends live branch messages when no snapshot exists", async () => {
258
- const ctx = createMockCtx({
259
- branch: buildSessionEntries([makeUserMessage("earlier user turn")]),
260
- });
261
- ctx.model = { provider: "a", id: "m" } as never;
262
- vi.mocked(completeSimple).mockImplementationOnce((async (_m: unknown, req: { messages: unknown[] }) => {
263
- expect(req.messages[0]).toMatchObject({
264
- role: "user",
265
- content: [{ type: "text", text: "earlier user turn" }],
266
- });
267
- return makeCompletionResponse({ text: "ok" });
268
- }) as never);
269
- await executeAsk("q", ctx, new AbortController());
270
- });
271
- });
272
-
273
- describe("registerMessageEndSnapshot", () => {
274
- it("writes a snapshot on non-toolUse assistant message_end", async () => {
275
- const { DM, captured } = createMockDM();
276
- registerMessageEndSnapshot(pi);
277
- const handler = captured.events.get("message_end")?.[0];
278
- expect(handler).toBeDefined();
279
- const ctx = createMockCtx({
280
- branch: buildSessionEntries([makeUserMessage("u1"), makeAssistantMessage({ text: "a1" })]),
281
- });
282
- await handler?.({ message: makeAssistantMessage({ text: "a1" }) } as never, ctx as never);
283
- const state = (globalThis as Record<symbol, { snapshots: Map<string, unknown> }>)[ASK_STATE_KEY];
284
- expect(state.snapshots.has("/tmp/test-session.jsonl")).toBe(true);
285
- });
286
- it("skips snapshot when stopReason=toolUse", async () => {
287
- const { DM, captured } = createMockDM();
288
- registerMessageEndSnapshot(pi);
289
- const handler = captured.events.get("message_end")?.[0];
290
- const msg = { ...makeAssistantMessage({ text: "x" }), stopReason: "toolUse" };
291
- const ctx = createMockCtx();
292
- await handler?.({ message: msg } as never, ctx as never);
293
- const state = (globalThis as unknown as Record<symbol, { snapshots?: Map<string, unknown> } | undefined>)[
294
- ASK_STATE_KEY
295
- ];
296
- expect(state?.snapshots?.has("/tmp/test-session.jsonl") ?? false).toBe(false);
297
- });
298
- it("skips snapshot for user role", async () => {
299
- const { DM, captured } = createMockDM();
300
- registerMessageEndSnapshot(pi);
301
- const handler = captured.events.get("message_end")?.[0];
302
- await handler?.({ message: makeUserMessage("u") } as never, createMockCtx() as never);
303
- const state = (globalThis as unknown as Record<symbol, { snapshots?: Map<string, unknown> } | undefined>)[
304
- ASK_STATE_KEY
305
- ];
306
- expect(state?.snapshots?.has("/tmp/test-session.jsonl") ?? false).toBe(false);
307
- });
308
- });
309
-
310
- describe("registerInvalidationHooks", () => {
311
- it("wires session_compact + session_tree", () => {
312
- const { DM, captured } = createMockDM();
313
- registerInvalidationHooks(pi);
314
- expect(captured.events.has("session_compact")).toBe(true);
315
- expect(captured.events.has("session_tree")).toBe(true);
316
- });
317
- it("handlers clear the snapshot for the session", async () => {
318
- const { DM, captured } = createMockDM();
319
- registerInvalidationHooks(pi);
320
- (globalThis as Record<symbol, { snapshots: Map<string, unknown> }>)[ASK_STATE_KEY] = {
321
- histories: new Map(),
322
- snapshots: new Map([["/tmp/test-session.jsonl", { messages: [] }]]),
323
- } as never;
324
- const compactHandler = captured.events.get("session_compact")?.[0];
325
- await compactHandler?.({} as never, createMockCtx() as never);
326
- const state = (globalThis as Record<symbol, { snapshots: Map<string, unknown> }>)[ASK_STATE_KEY];
327
- expect(state.snapshots.has("/tmp/test-session.jsonl")).toBe(false);
328
- });
329
- });
330
-
331
- describe("registerAskCommand", () => {
332
- it("registers /ask with handler", () => {
333
- const { DM, captured } = createMockDM();
334
- registerAskCommand(pi);
335
- expect(captured.commands.has("ask")).toBe(true);
336
- const cmd = captured.commands.get("ask");
337
- expect(cmd?.description).toContain("side question");
338
- expect(typeof cmd?.handler).toBe("function");
339
- });
340
- });
Binary file
@@ -1,70 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 800" role="img" aria-label="dm-ask — Side questions without polluting the main conversation" preserveAspectRatio="xMidYMid meet">
2
- <title>dm-ask — Side questions without polluting the main conversation</title>
3
- <defs>
4
- <style>
5
- .mono { font-family: 'JetBrains Mono', 'Fira Code', 'SFMono-Regular', ui-monospace, Menlo, Consolas, monospace; }
6
- .ink { fill: #F4EFE6; }
7
- .muted { fill: #7A7468; }
8
- .dim { fill: #4A463F; }
9
- .accent { fill: #FF7A3D; }
10
- .mint { fill: #6FD0B8; }
11
- </style>
12
- <filter id="grain" x="0" y="0" width="100%" height="100%">
13
- <feTurbulence type="fractalNoise" baseFrequency="1.4" numOctaves="2" seed="19"/>
14
- <feColorMatrix values="0 0 0 0 0.96 0 0 0 0 0.94 0 0 0 0 0.88 0 0 0 0.04 0"/>
15
- </filter>
16
- <radialGradient id="vignette" cx="50%" cy="50%" r="70%">
17
- <stop offset="55%" stop-color="#070605" stop-opacity="0"/>
18
- <stop offset="100%" stop-color="#000" stop-opacity="0.7"/>
19
- </radialGradient>
20
- <filter id="winShadow" x="-10%" y="-10%" width="120%" height="130%">
21
- <feDropShadow dx="0" dy="14" stdDeviation="22" flood-color="#000" flood-opacity="0.6"/>
22
- </filter>
23
- <clipPath id="wclip"><rect x="64" y="56" width="1152" height="688" rx="12"/></clipPath>
24
- </defs>
25
-
26
- <rect width="1280" height="800" fill="#070605"/>
27
- <rect width="1280" height="800" filter="url(#grain)" opacity="0.45"/>
28
- <rect width="1280" height="800" fill="url(#vignette)"/>
29
-
30
- <rect x="64" y="56" width="1152" height="688" rx="12" fill="#0E0D0B" filter="url(#winShadow)"/>
31
-
32
- <g clip-path="url(#wclip)">
33
- <rect x="64" y="56" width="1152" height="44" fill="#16120E"/>
34
- <line x1="64" y1="100" x2="1216" y2="100" stroke="#2A2620"/>
35
- <circle cx="92" cy="78" r="7" fill="#FF5F57"/>
36
- <circle cx="120" cy="78" r="7" fill="#FFBD2E"/>
37
- <circle cx="148" cy="78" r="7" fill="#28C840"/>
38
- <text class="mono muted" x="640" y="84" font-size="14" letter-spacing="1.4" text-anchor="middle">~/rpiv-mono &#8212; DM &#8212; dm-ask</text>
39
-
40
- <text class="mono mint" x="120" y="184" font-size="46" font-weight="700"># dm-ask</text>
41
- <text class="mono muted" x="120" y="222" font-size="20" letter-spacing="0.5">Side question. Zero pollution.</text>
42
-
43
- <g opacity="0.6">
44
- <text class="mono" x="120" y="296" font-size="20"><tspan class="muted">user &#8250;</tspan> <tspan class="muted">let&#8217;s migrate the websocket layer to SSE</tspan></text>
45
- <text class="mono" x="120" y="328" font-size="20"><tspan class="muted">assistant &#8250;</tspan> <tspan class="muted">on it &#8212; reading current transport&#8230;</tspan></text>
46
- </g>
47
- <line x1="120" y1="362" x2="1160" y2="362" stroke="#2A2620" stroke-dasharray="2 6"/>
48
-
49
- <text class="mono" x="120" y="408" font-size="22"><tspan class="mint" font-weight="700">&#10095;</tspan> <tspan class="accent" font-weight="700">/ask</tspan> <tspan class="ink">why did we switch from sockets to SSE?</tspan></text>
50
- <text class="mono" x="120" y="464" font-size="20"><tspan class="muted"> &#8250; resilience: SSE survives proxies that drop ws,</tspan></text>
51
- <text class="mono" x="120" y="494" font-size="20"><tspan class="muted"> and the team was tired of the ping-pong reconnect.</tspan></text>
52
- <text class="mono" x="120" y="540" font-size="20"><tspan class="dim"> &#8250;</tspan> <tspan class="mint" font-weight="700">EPHEMERAL &#183; NEVER WRITTEN</tspan></text>
53
-
54
- <text class="mono muted" x="120" y="618" font-size="14" letter-spacing="2.2">READ-ONLY BRANCH CLONE &#183; OWN AbortController &#183; tools: []</text>
55
-
56
- <rect x="64" y="708" width="1152" height="36" fill="#16120E"/>
57
- <line x1="64" y1="708" x2="1216" y2="708" stroke="#2A2620"/>
58
- <text class="mono" font-size="14" y="731" letter-spacing="1">
59
- <tspan x="92" class="accent" font-weight="700">&#9612; dm-ask</tspan>
60
- <tspan dx="14" class="dim">&#9474;</tspan>
61
- <tspan dx="14" class="mint">ephemeral</tspan>
62
- <tspan dx="14" class="dim">&#9474;</tspan>
63
- <tspan dx="14" class="muted">pi 0.9.4</tspan>
64
- <tspan dx="14" class="dim">&#9474;</tspan>
65
- <tspan dx="14" class="muted">npm:dm-ask</tspan>
66
- </text>
67
- </g>
68
-
69
- <rect x="64" y="56" width="1152" height="688" rx="12" fill="none" stroke="#3A352D" stroke-width="1"/>
70
- </svg>
Binary file