@hellcoder/companion 0.116.0 → 0.116.1-preview.20260814041931.d191f06
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AgentsPage-BBi92OuO.js → AgentsPage-BAalV1v6.js} +5 -5
- package/dist/assets/CronManager-B2Vo1YmB.js +1 -0
- package/dist/assets/{DashboardPage-BvuDoRlp.js → DashboardPage-BOvDiP1W.js} +1 -1
- package/dist/assets/{IntegrationsPage-CK_ThzWg.js → IntegrationsPage-kOXLH5KU.js} +1 -1
- package/dist/assets/{LinearOAuthSettingsPage-InTf-E7u.js → LinearOAuthSettingsPage-H-uUJ-ub.js} +1 -1
- package/dist/assets/{LinearSettingsPage-BwjC9Vd-.js → LinearSettingsPage-CD_x4AGr.js} +1 -1
- package/dist/assets/MagicUIDashboard-9Jgiv4rb.js +1119 -0
- package/dist/assets/MagicUIView-BLEcS9XO.js +1 -0
- package/dist/assets/{Playground-DlzomEOu.js → Playground-QLrd9q16.js} +10 -9
- package/dist/assets/{PromptsPage-hRZhLUYR.js → PromptsPage-11eJ6ak7.js} +1 -1
- package/dist/assets/{RunsPage-zsVmbFoi.js → RunsPage-Bz3udIL2.js} +1 -1
- package/dist/assets/{SandboxManager-Bq_aXA1z.js → SandboxManager-Dv47pbC6.js} +1 -1
- package/dist/assets/SettingsPage-C_2ftG-C.js +1 -0
- package/dist/assets/{TailscalePage-fE7Z9uiF.js → TailscalePage-DzMX_7XA.js} +1 -1
- package/dist/assets/index-DSCRqqpK.css +1 -0
- package/dist/assets/index-DspbwgSL.js +140 -0
- package/dist/assets/{sw-register-Cjt2BQTW.js → sw-register-CarYQEeI.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/package.json +4 -1
- package/server/async-message-queue.ts +38 -0
- package/server/auto-namer.test.ts +8 -0
- package/server/claude-sdk-adapter.ts +1 -36
- package/server/event-bus-types.ts +32 -1
- package/server/index.ts +7 -0
- package/server/linear-agent-bridge.ts +6 -72
- package/server/linear-connections.test.ts +8 -0
- package/server/magic-ui-ops.test.ts +239 -0
- package/server/magic-ui-ops.ts +365 -0
- package/server/magic-ui-settings.test.ts +56 -0
- package/server/magic-ui-settings.ts +38 -0
- package/server/magic-ui-store.ts +94 -0
- package/server/magic-ui-types.ts +138 -0
- package/server/magic-ui-watcher.test.ts +288 -0
- package/server/magic-ui-watcher.ts +623 -0
- package/server/message-extract.ts +79 -0
- package/server/routes/settings-routes.ts +22 -0
- package/server/routes.test.ts +59 -0
- package/server/session-types.ts +15 -1
- package/server/settings-manager.test.ts +6 -0
- package/server/settings-manager.ts +24 -1
- package/server/ws-bridge-browser-ingest.ts +1 -0
- package/server/ws-bridge-codex.test.ts +12 -0
- package/server/ws-bridge-controls.ts +9 -0
- package/server/ws-bridge.ts +65 -0
- package/dist/assets/CronManager-DxLaNh9T.js +0 -1
- package/dist/assets/SettingsPage-BvrrlEKj.js +0 -1
- package/dist/assets/index--SnXduR0.js +0 -139
- package/dist/assets/index-DcQxHfE7.css +0 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// ─── Shared BrowserIncomingMessage extraction helpers ────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Pure functions for pulling text / tool activity out of the bridge's
|
|
4
|
+
// message stream. Used by consumers that tap companionBus message events
|
|
5
|
+
// (linear-agent-bridge, magic-ui-watcher).
|
|
6
|
+
|
|
7
|
+
import type { BrowserIncomingMessage } from "./session-types.js";
|
|
8
|
+
|
|
9
|
+
/** Content blocks of an assistant message, or null. */
|
|
10
|
+
export function getAssistantContent(msg: BrowserIncomingMessage): unknown[] | null {
|
|
11
|
+
if (msg.type !== "assistant") return null;
|
|
12
|
+
// Assistant messages carry content blocks at msg.message.content
|
|
13
|
+
const raw = msg as Record<string, unknown>;
|
|
14
|
+
const message = raw.message;
|
|
15
|
+
if (!message || typeof message !== "object") return null;
|
|
16
|
+
const content = (message as Record<string, unknown>).content;
|
|
17
|
+
return Array.isArray(content) ? content : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Extract text from assistant message content blocks */
|
|
21
|
+
export function extractTextFromAssistant(msg: BrowserIncomingMessage): string {
|
|
22
|
+
const content = getAssistantContent(msg);
|
|
23
|
+
if (!content) return "";
|
|
24
|
+
return content
|
|
25
|
+
.filter((b): b is { type: string; text: string } =>
|
|
26
|
+
typeof b === "object" && b !== null && (b as Record<string, unknown>).type === "text" && typeof (b as Record<string, unknown>).text === "string")
|
|
27
|
+
.map((b) => b.text)
|
|
28
|
+
.join("\n");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Extract text deltas from stream events. */
|
|
32
|
+
export function extractTextDeltaFromStreamEvent(msg: BrowserIncomingMessage): string {
|
|
33
|
+
if (msg.type !== "stream_event") return "";
|
|
34
|
+
const event = msg.event as Record<string, unknown> | undefined;
|
|
35
|
+
if (!event || event.type !== "content_block_delta") return "";
|
|
36
|
+
const delta = event.delta as Record<string, unknown> | undefined;
|
|
37
|
+
if (!delta || delta.type !== "text_delta" || typeof delta.text !== "string") return "";
|
|
38
|
+
return delta.text;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Extract all tool use blocks from assistant message content (with raw input for plan extraction) */
|
|
42
|
+
export function extractToolUses(msg: BrowserIncomingMessage): Array<{ id?: string; name: string; input: string; rawInput?: Record<string, unknown> }> {
|
|
43
|
+
const content = getAssistantContent(msg);
|
|
44
|
+
if (!content) return [];
|
|
45
|
+
return content
|
|
46
|
+
.filter((b): b is { type: string; id?: string; name: string; input?: Record<string, unknown> } =>
|
|
47
|
+
typeof b === "object" && b !== null
|
|
48
|
+
&& (b as Record<string, unknown>).type === "tool_use"
|
|
49
|
+
&& typeof (b as Record<string, unknown>).name === "string")
|
|
50
|
+
.map((toolBlock) => ({
|
|
51
|
+
id: typeof toolBlock.id === "string" ? toolBlock.id : undefined,
|
|
52
|
+
name: toolBlock.name,
|
|
53
|
+
input: toolBlock.input ? JSON.stringify(toolBlock.input).slice(0, 200) : "",
|
|
54
|
+
rawInput: toolBlock.input,
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Extract tool_result blocks from assistant message content. */
|
|
59
|
+
export function extractToolResults(msg: BrowserIncomingMessage): Array<{ tool_use_id: string; content: string }> {
|
|
60
|
+
const content = getAssistantContent(msg);
|
|
61
|
+
if (!content) return [];
|
|
62
|
+
return content
|
|
63
|
+
.filter((b): b is { type: string; tool_use_id: string; content?: unknown } =>
|
|
64
|
+
typeof b === "object" && b !== null
|
|
65
|
+
&& (b as Record<string, unknown>).type === "tool_result"
|
|
66
|
+
&& typeof (b as Record<string, unknown>).tool_use_id === "string")
|
|
67
|
+
.map((block) => ({
|
|
68
|
+
tool_use_id: block.tool_use_id,
|
|
69
|
+
content: typeof block.content === "string"
|
|
70
|
+
? block.content.slice(0, 500)
|
|
71
|
+
: Array.isArray(block.content)
|
|
72
|
+
? (block.content as Array<{ type?: string; text?: string }>)
|
|
73
|
+
.filter((c) => c.type === "text" && typeof c.text === "string")
|
|
74
|
+
.map((c) => c.text)
|
|
75
|
+
.join("\n")
|
|
76
|
+
.slice(0, 500)
|
|
77
|
+
: "",
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
@@ -3,6 +3,7 @@ import { DASHBOARD_MODEL_OPTIONS, DEFAULT_ANTHROPIC_MODEL, getSettings, updateSe
|
|
|
3
3
|
import { linearCache } from "../linear-cache.js";
|
|
4
4
|
import { listConnections } from "../linear-connections.js";
|
|
5
5
|
import { hasContainerCodexAuth } from "../codex-container-auth.js";
|
|
6
|
+
import { isClaudeCliAvailable } from "../claude-cli-runner.js";
|
|
6
7
|
|
|
7
8
|
export function registerSettingsRoutes(api: Hono): void {
|
|
8
9
|
api.get("/settings", (c) => {
|
|
@@ -30,6 +31,9 @@ export function registerSettingsRoutes(api: Hono): void {
|
|
|
30
31
|
dashboardModel: settings.dashboardModel,
|
|
31
32
|
dashboardRunHour: settings.dashboardRunHour,
|
|
32
33
|
dashboardMaxSessionsPerRun: settings.dashboardMaxSessionsPerRun,
|
|
34
|
+
magicUiEnabled: settings.magicUiEnabled,
|
|
35
|
+
magicUiModel: settings.magicUiModel,
|
|
36
|
+
claudeCliAvailable: isClaudeCliAvailable(),
|
|
33
37
|
publicUrl: settings.publicUrl,
|
|
34
38
|
updateChannel: settings.updateChannel,
|
|
35
39
|
dockerAutoUpdate: settings.dockerAutoUpdate,
|
|
@@ -100,6 +104,12 @@ export function registerSettingsRoutes(api: Hono): void {
|
|
|
100
104
|
) {
|
|
101
105
|
return c.json({ error: "dashboardMaxSessionsPerRun must be an integer between 1 and 200" }, 400);
|
|
102
106
|
}
|
|
107
|
+
if (body.magicUiEnabled !== undefined && typeof body.magicUiEnabled !== "boolean") {
|
|
108
|
+
return c.json({ error: "magicUiEnabled must be a boolean" }, 400);
|
|
109
|
+
}
|
|
110
|
+
if (body.magicUiModel !== undefined && !DASHBOARD_MODEL_OPTIONS.includes(body.magicUiModel)) {
|
|
111
|
+
return c.json({ error: `magicUiModel must be one of: ${DASHBOARD_MODEL_OPTIONS.join(", ")}` }, 400);
|
|
112
|
+
}
|
|
103
113
|
if (body.publicUrl !== undefined) {
|
|
104
114
|
if (typeof body.publicUrl !== "string") {
|
|
105
115
|
return c.json({ error: "publicUrl must be a string" }, 400);
|
|
@@ -164,6 +174,7 @@ export function registerSettingsRoutes(api: Hono): void {
|
|
|
164
174
|
|| body.aiValidationAutoDeny !== undefined
|
|
165
175
|
|| body.dashboardEnabled !== undefined || body.dashboardModel !== undefined
|
|
166
176
|
|| body.dashboardRunHour !== undefined || body.dashboardMaxSessionsPerRun !== undefined
|
|
177
|
+
|| body.magicUiEnabled !== undefined || body.magicUiModel !== undefined
|
|
167
178
|
|| body.publicUrl !== undefined
|
|
168
179
|
|| body.updateChannel !== undefined
|
|
169
180
|
|| body.dockerAutoUpdate !== undefined
|
|
@@ -270,6 +281,14 @@ export function registerSettingsRoutes(api: Hono): void {
|
|
|
270
281
|
typeof body.dashboardMaxSessionsPerRun === "number"
|
|
271
282
|
? body.dashboardMaxSessionsPerRun
|
|
272
283
|
: undefined,
|
|
284
|
+
magicUiEnabled:
|
|
285
|
+
typeof body.magicUiEnabled === "boolean"
|
|
286
|
+
? body.magicUiEnabled
|
|
287
|
+
: undefined,
|
|
288
|
+
magicUiModel:
|
|
289
|
+
typeof body.magicUiModel === "string"
|
|
290
|
+
? body.magicUiModel
|
|
291
|
+
: undefined,
|
|
273
292
|
publicUrl:
|
|
274
293
|
typeof body.publicUrl === "string"
|
|
275
294
|
? body.publicUrl.trim().replace(/\/+$/, "")
|
|
@@ -331,6 +350,9 @@ export function registerSettingsRoutes(api: Hono): void {
|
|
|
331
350
|
dashboardModel: settings.dashboardModel,
|
|
332
351
|
dashboardRunHour: settings.dashboardRunHour,
|
|
333
352
|
dashboardMaxSessionsPerRun: settings.dashboardMaxSessionsPerRun,
|
|
353
|
+
magicUiEnabled: settings.magicUiEnabled,
|
|
354
|
+
magicUiModel: settings.magicUiModel,
|
|
355
|
+
claudeCliAvailable: isClaudeCliAvailable(),
|
|
334
356
|
publicUrl: settings.publicUrl,
|
|
335
357
|
updateChannel: settings.updateChannel,
|
|
336
358
|
dockerAutoUpdate: settings.dockerAutoUpdate,
|
package/server/routes.test.ts
CHANGED
|
@@ -106,6 +106,8 @@ vi.mock("./settings-manager.js", () => ({
|
|
|
106
106
|
dashboardModel: "claude-haiku-4-5",
|
|
107
107
|
dashboardRunHour: 3,
|
|
108
108
|
dashboardMaxSessionsPerRun: 30,
|
|
109
|
+
magicUiEnabled: false,
|
|
110
|
+
magicUiModel: "claude-haiku-4-5",
|
|
109
111
|
publicUrl: "",
|
|
110
112
|
updateChannel: "stable",
|
|
111
113
|
dockerAutoUpdate: false,
|
|
@@ -1154,6 +1156,8 @@ describe("GET /api/sessions/:id/archive-info", () => {
|
|
|
1154
1156
|
dashboardModel: "claude-haiku-4-5",
|
|
1155
1157
|
dashboardRunHour: 3,
|
|
1156
1158
|
dashboardMaxSessionsPerRun: 30,
|
|
1159
|
+
magicUiEnabled: false,
|
|
1160
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1157
1161
|
publicUrl: "",
|
|
1158
1162
|
updateChannel: "stable",
|
|
1159
1163
|
dockerAutoUpdate: false,
|
|
@@ -1533,6 +1537,8 @@ describe("GET /api/settings", () => {
|
|
|
1533
1537
|
dashboardModel: "claude-haiku-4-5",
|
|
1534
1538
|
dashboardRunHour: 3,
|
|
1535
1539
|
dashboardMaxSessionsPerRun: 30,
|
|
1540
|
+
magicUiEnabled: false,
|
|
1541
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1536
1542
|
publicUrl: "",
|
|
1537
1543
|
updateChannel: "stable",
|
|
1538
1544
|
dockerAutoUpdate: false,
|
|
@@ -1570,6 +1576,9 @@ describe("GET /api/settings", () => {
|
|
|
1570
1576
|
dashboardModel: "claude-haiku-4-5",
|
|
1571
1577
|
dashboardRunHour: 3,
|
|
1572
1578
|
dashboardMaxSessionsPerRun: 30,
|
|
1579
|
+
magicUiEnabled: false,
|
|
1580
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1581
|
+
claudeCliAvailable: false,
|
|
1573
1582
|
publicUrl: "",
|
|
1574
1583
|
updateChannel: "stable",
|
|
1575
1584
|
dockerAutoUpdate: false,
|
|
@@ -1607,6 +1616,8 @@ describe("GET /api/settings", () => {
|
|
|
1607
1616
|
dashboardModel: "claude-haiku-4-5",
|
|
1608
1617
|
dashboardRunHour: 3,
|
|
1609
1618
|
dashboardMaxSessionsPerRun: 30,
|
|
1619
|
+
magicUiEnabled: false,
|
|
1620
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1610
1621
|
publicUrl: "",
|
|
1611
1622
|
updateChannel: "stable",
|
|
1612
1623
|
dockerAutoUpdate: false,
|
|
@@ -1644,6 +1655,9 @@ describe("GET /api/settings", () => {
|
|
|
1644
1655
|
dashboardModel: "claude-haiku-4-5",
|
|
1645
1656
|
dashboardRunHour: 3,
|
|
1646
1657
|
dashboardMaxSessionsPerRun: 30,
|
|
1658
|
+
magicUiEnabled: false,
|
|
1659
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1660
|
+
claudeCliAvailable: false,
|
|
1647
1661
|
publicUrl: "",
|
|
1648
1662
|
updateChannel: "stable",
|
|
1649
1663
|
dockerAutoUpdate: false,
|
|
@@ -1682,6 +1696,8 @@ describe("GET /api/settings", () => {
|
|
|
1682
1696
|
dashboardModel: "claude-haiku-4-5",
|
|
1683
1697
|
dashboardRunHour: 3,
|
|
1684
1698
|
dashboardMaxSessionsPerRun: 30,
|
|
1699
|
+
magicUiEnabled: false,
|
|
1700
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1685
1701
|
publicUrl: "https://example.com",
|
|
1686
1702
|
updateChannel: "stable",
|
|
1687
1703
|
dockerAutoUpdate: false,
|
|
@@ -1728,6 +1744,8 @@ describe("PUT /api/settings", () => {
|
|
|
1728
1744
|
dashboardModel: "claude-haiku-4-5",
|
|
1729
1745
|
dashboardRunHour: 3,
|
|
1730
1746
|
dashboardMaxSessionsPerRun: 30,
|
|
1747
|
+
magicUiEnabled: false,
|
|
1748
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1731
1749
|
publicUrl: "",
|
|
1732
1750
|
updateChannel: "stable",
|
|
1733
1751
|
dockerAutoUpdate: false,
|
|
@@ -1787,6 +1805,9 @@ describe("PUT /api/settings", () => {
|
|
|
1787
1805
|
dashboardModel: "claude-haiku-4-5",
|
|
1788
1806
|
dashboardRunHour: 3,
|
|
1789
1807
|
dashboardMaxSessionsPerRun: 30,
|
|
1808
|
+
magicUiEnabled: false,
|
|
1809
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1810
|
+
claudeCliAvailable: false,
|
|
1790
1811
|
publicUrl: "",
|
|
1791
1812
|
updateChannel: "stable",
|
|
1792
1813
|
dockerAutoUpdate: false,
|
|
@@ -1824,6 +1845,8 @@ describe("PUT /api/settings", () => {
|
|
|
1824
1845
|
dashboardModel: "claude-haiku-4-5",
|
|
1825
1846
|
dashboardRunHour: 3,
|
|
1826
1847
|
dashboardMaxSessionsPerRun: 30,
|
|
1848
|
+
magicUiEnabled: false,
|
|
1849
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1827
1850
|
publicUrl: "",
|
|
1828
1851
|
updateChannel: "stable",
|
|
1829
1852
|
dockerAutoUpdate: false,
|
|
@@ -1878,6 +1901,8 @@ describe("PUT /api/settings", () => {
|
|
|
1878
1901
|
dashboardModel: "claude-haiku-4-5",
|
|
1879
1902
|
dashboardRunHour: 3,
|
|
1880
1903
|
dashboardMaxSessionsPerRun: 30,
|
|
1904
|
+
magicUiEnabled: false,
|
|
1905
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1881
1906
|
publicUrl: "",
|
|
1882
1907
|
updateChannel: "stable",
|
|
1883
1908
|
dockerAutoUpdate: false,
|
|
@@ -2032,6 +2057,8 @@ describe("PUT /api/settings", () => {
|
|
|
2032
2057
|
dashboardModel: "claude-haiku-4-5",
|
|
2033
2058
|
dashboardRunHour: 3,
|
|
2034
2059
|
dashboardMaxSessionsPerRun: 30,
|
|
2060
|
+
magicUiEnabled: false,
|
|
2061
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2035
2062
|
publicUrl: "https://my-server.com",
|
|
2036
2063
|
updateChannel: "stable",
|
|
2037
2064
|
dockerAutoUpdate: false,
|
|
@@ -2292,6 +2319,8 @@ describe("GET /api/linear/issues", () => {
|
|
|
2292
2319
|
dashboardModel: "claude-haiku-4-5",
|
|
2293
2320
|
dashboardRunHour: 3,
|
|
2294
2321
|
dashboardMaxSessionsPerRun: 30,
|
|
2322
|
+
magicUiEnabled: false,
|
|
2323
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2295
2324
|
publicUrl: "",
|
|
2296
2325
|
updateChannel: "stable",
|
|
2297
2326
|
dockerAutoUpdate: false,
|
|
@@ -2336,6 +2365,8 @@ describe("GET /api/linear/issues", () => {
|
|
|
2336
2365
|
dashboardModel: "claude-haiku-4-5",
|
|
2337
2366
|
dashboardRunHour: 3,
|
|
2338
2367
|
dashboardMaxSessionsPerRun: 30,
|
|
2368
|
+
magicUiEnabled: false,
|
|
2369
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2339
2370
|
publicUrl: "",
|
|
2340
2371
|
updateChannel: "stable",
|
|
2341
2372
|
dockerAutoUpdate: false,
|
|
@@ -2433,6 +2464,8 @@ describe("GET /api/linear/issues", () => {
|
|
|
2433
2464
|
dashboardModel: "claude-haiku-4-5",
|
|
2434
2465
|
dashboardRunHour: 3,
|
|
2435
2466
|
dashboardMaxSessionsPerRun: 30,
|
|
2467
|
+
magicUiEnabled: false,
|
|
2468
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2436
2469
|
publicUrl: "",
|
|
2437
2470
|
updateChannel: "stable",
|
|
2438
2471
|
dockerAutoUpdate: false,
|
|
@@ -2537,6 +2570,8 @@ describe("GET /api/linear/issues", () => {
|
|
|
2537
2570
|
dashboardModel: "claude-haiku-4-5",
|
|
2538
2571
|
dashboardRunHour: 3,
|
|
2539
2572
|
dashboardMaxSessionsPerRun: 30,
|
|
2573
|
+
magicUiEnabled: false,
|
|
2574
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2540
2575
|
publicUrl: "",
|
|
2541
2576
|
updateChannel: "stable",
|
|
2542
2577
|
dockerAutoUpdate: false,
|
|
@@ -2606,6 +2641,8 @@ describe("GET /api/linear/connection", () => {
|
|
|
2606
2641
|
dashboardModel: "claude-haiku-4-5",
|
|
2607
2642
|
dashboardRunHour: 3,
|
|
2608
2643
|
dashboardMaxSessionsPerRun: 30,
|
|
2644
|
+
magicUiEnabled: false,
|
|
2645
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2609
2646
|
publicUrl: "",
|
|
2610
2647
|
updateChannel: "stable",
|
|
2611
2648
|
dockerAutoUpdate: false,
|
|
@@ -2650,6 +2687,8 @@ describe("GET /api/linear/connection", () => {
|
|
|
2650
2687
|
dashboardModel: "claude-haiku-4-5",
|
|
2651
2688
|
dashboardRunHour: 3,
|
|
2652
2689
|
dashboardMaxSessionsPerRun: 30,
|
|
2690
|
+
magicUiEnabled: false,
|
|
2691
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2653
2692
|
publicUrl: "",
|
|
2654
2693
|
updateChannel: "stable",
|
|
2655
2694
|
dockerAutoUpdate: false,
|
|
@@ -2716,6 +2755,8 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2716
2755
|
dashboardModel: "claude-haiku-4-5",
|
|
2717
2756
|
dashboardRunHour: 3,
|
|
2718
2757
|
dashboardMaxSessionsPerRun: 30,
|
|
2758
|
+
magicUiEnabled: false,
|
|
2759
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2719
2760
|
publicUrl: "",
|
|
2720
2761
|
updateChannel: "stable",
|
|
2721
2762
|
dockerAutoUpdate: false,
|
|
@@ -2764,6 +2805,8 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2764
2805
|
dashboardModel: "claude-haiku-4-5",
|
|
2765
2806
|
dashboardRunHour: 3,
|
|
2766
2807
|
dashboardMaxSessionsPerRun: 30,
|
|
2808
|
+
magicUiEnabled: false,
|
|
2809
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2767
2810
|
publicUrl: "",
|
|
2768
2811
|
updateChannel: "stable",
|
|
2769
2812
|
dockerAutoUpdate: false,
|
|
@@ -2811,6 +2854,8 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2811
2854
|
dashboardModel: "claude-haiku-4-5",
|
|
2812
2855
|
dashboardRunHour: 3,
|
|
2813
2856
|
dashboardMaxSessionsPerRun: 30,
|
|
2857
|
+
magicUiEnabled: false,
|
|
2858
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2814
2859
|
publicUrl: "",
|
|
2815
2860
|
updateChannel: "stable",
|
|
2816
2861
|
dockerAutoUpdate: false,
|
|
@@ -2860,6 +2905,8 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2860
2905
|
dashboardModel: "claude-haiku-4-5",
|
|
2861
2906
|
dashboardRunHour: 3,
|
|
2862
2907
|
dashboardMaxSessionsPerRun: 30,
|
|
2908
|
+
magicUiEnabled: false,
|
|
2909
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2863
2910
|
publicUrl: "",
|
|
2864
2911
|
updateChannel: "stable",
|
|
2865
2912
|
dockerAutoUpdate: false,
|
|
@@ -2943,6 +2990,8 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2943
2990
|
dashboardModel: "claude-haiku-4-5",
|
|
2944
2991
|
dashboardRunHour: 3,
|
|
2945
2992
|
dashboardMaxSessionsPerRun: 30,
|
|
2993
|
+
magicUiEnabled: false,
|
|
2994
|
+
magicUiModel: "claude-haiku-4-5",
|
|
2946
2995
|
publicUrl: "",
|
|
2947
2996
|
updateChannel: "stable",
|
|
2948
2997
|
dockerAutoUpdate: false,
|
|
@@ -3005,6 +3054,8 @@ describe("GET /api/linear/projects", () => {
|
|
|
3005
3054
|
dashboardModel: "claude-haiku-4-5",
|
|
3006
3055
|
dashboardRunHour: 3,
|
|
3007
3056
|
dashboardMaxSessionsPerRun: 30,
|
|
3057
|
+
magicUiEnabled: false,
|
|
3058
|
+
magicUiModel: "claude-haiku-4-5",
|
|
3008
3059
|
publicUrl: "",
|
|
3009
3060
|
updateChannel: "stable",
|
|
3010
3061
|
dockerAutoUpdate: false,
|
|
@@ -3049,6 +3100,8 @@ describe("GET /api/linear/projects", () => {
|
|
|
3049
3100
|
dashboardModel: "claude-haiku-4-5",
|
|
3050
3101
|
dashboardRunHour: 3,
|
|
3051
3102
|
dashboardMaxSessionsPerRun: 30,
|
|
3103
|
+
magicUiEnabled: false,
|
|
3104
|
+
magicUiModel: "claude-haiku-4-5",
|
|
3052
3105
|
publicUrl: "",
|
|
3053
3106
|
updateChannel: "stable",
|
|
3054
3107
|
dockerAutoUpdate: false,
|
|
@@ -3123,6 +3176,8 @@ describe("GET /api/linear/project-issues", () => {
|
|
|
3123
3176
|
dashboardModel: "claude-haiku-4-5",
|
|
3124
3177
|
dashboardRunHour: 3,
|
|
3125
3178
|
dashboardMaxSessionsPerRun: 30,
|
|
3179
|
+
magicUiEnabled: false,
|
|
3180
|
+
magicUiModel: "claude-haiku-4-5",
|
|
3126
3181
|
publicUrl: "",
|
|
3127
3182
|
updateChannel: "stable",
|
|
3128
3183
|
dockerAutoUpdate: false,
|
|
@@ -3167,6 +3222,8 @@ describe("GET /api/linear/project-issues", () => {
|
|
|
3167
3222
|
dashboardModel: "claude-haiku-4-5",
|
|
3168
3223
|
dashboardRunHour: 3,
|
|
3169
3224
|
dashboardMaxSessionsPerRun: 30,
|
|
3225
|
+
magicUiEnabled: false,
|
|
3226
|
+
magicUiModel: "claude-haiku-4-5",
|
|
3170
3227
|
publicUrl: "",
|
|
3171
3228
|
updateChannel: "stable",
|
|
3172
3229
|
dockerAutoUpdate: false,
|
|
@@ -3256,6 +3313,8 @@ describe("GET /api/linear/project-issues", () => {
|
|
|
3256
3313
|
dashboardModel: "claude-haiku-4-5",
|
|
3257
3314
|
dashboardRunHour: 3,
|
|
3258
3315
|
dashboardMaxSessionsPerRun: 30,
|
|
3316
|
+
magicUiEnabled: false,
|
|
3317
|
+
magicUiModel: "claude-haiku-4-5",
|
|
3259
3318
|
publicUrl: "",
|
|
3260
3319
|
updateChannel: "stable",
|
|
3261
3320
|
dockerAutoUpdate: false,
|
package/server/session-types.ts
CHANGED
|
@@ -400,6 +400,8 @@ export type BrowserOutgoingMessage =
|
|
|
400
400
|
| { type: "mcp_reconnect"; serverName: string; client_msg_id?: string }
|
|
401
401
|
| { type: "mcp_set_servers"; servers: Record<string, McpServerConfig>; client_msg_id?: string }
|
|
402
402
|
| { type: "set_ai_validation"; aiValidationEnabled?: boolean | null; aiValidationAutoApprove?: boolean | null; aiValidationAutoDeny?: boolean | null; client_msg_id?: string }
|
|
403
|
+
| { type: "set_magic_ui"; magicUiActive?: boolean | null; client_msg_id?: string }
|
|
404
|
+
| { type: "magic_ui_sync"; client_msg_id?: string }
|
|
403
405
|
| { type: "end_session"; reason?: string; client_msg_id?: string }
|
|
404
406
|
| { type: "stop_task"; task_id: string; client_msg_id?: string }
|
|
405
407
|
| { type: "update_environment_variables"; variables: Record<string, string>; client_msg_id?: string };
|
|
@@ -442,7 +444,12 @@ export type BrowserIncomingMessageBase =
|
|
|
442
444
|
| { type: "session_phase"; phase: SessionPhase; previousPhase: SessionPhase }
|
|
443
445
|
| { type: "prompt_suggestion"; suggestions: string[] }
|
|
444
446
|
| { type: "streamlined_text"; text: string }
|
|
445
|
-
| { type: "streamlined_tool_use_summary"; tool_summary: string }
|
|
447
|
+
| { type: "streamlined_tool_use_summary"; tool_summary: string }
|
|
448
|
+
// MagicUI: the server always sends the full canonical dashboard state
|
|
449
|
+
// (small by construction — capped slots/logs). The iframe runtime diffs
|
|
450
|
+
// against its DOM via per-slot updatedAt, so no client-side reducer and no
|
|
451
|
+
// version-gap protocol is needed; late joiners are trivially correct.
|
|
452
|
+
| { type: "magic_ui_state"; state: import("./magic-ui-types.js").MagicUiDashboardState };
|
|
446
453
|
|
|
447
454
|
export type BrowserIncomingMessage = BrowserIncomingMessageBase & { seq?: number };
|
|
448
455
|
|
|
@@ -508,6 +515,13 @@ export interface SessionState {
|
|
|
508
515
|
aiValidationAutoApprove?: boolean | null;
|
|
509
516
|
/** Per-session auto-deny override. null/undefined = use global default */
|
|
510
517
|
aiValidationAutoDeny?: boolean | null;
|
|
518
|
+
/**
|
|
519
|
+
* Per-session MagicUI opt-in. null/undefined = use the global
|
|
520
|
+
* magicUiEnabled default. When effective-true (and the Claude CLI is
|
|
521
|
+
* available), browsers render the MagicUI dashboard view and the server
|
|
522
|
+
* runs a Haiku watcher for this session.
|
|
523
|
+
*/
|
|
524
|
+
magicUiActive?: boolean | null;
|
|
511
525
|
/** If this session is linked to a Linear agent session */
|
|
512
526
|
linearSessionId?: string;
|
|
513
527
|
}
|
|
@@ -49,6 +49,8 @@ describe("settings-manager", () => {
|
|
|
49
49
|
dashboardModel: "claude-haiku-4-5",
|
|
50
50
|
dashboardRunHour: 3,
|
|
51
51
|
dashboardMaxSessionsPerRun: 30,
|
|
52
|
+
magicUiEnabled: false,
|
|
53
|
+
magicUiModel: "claude-haiku-4-5",
|
|
52
54
|
publicUrl: "",
|
|
53
55
|
updateChannel: "stable",
|
|
54
56
|
dockerAutoUpdate: false,
|
|
@@ -117,6 +119,8 @@ describe("settings-manager", () => {
|
|
|
117
119
|
dashboardModel: "claude-haiku-4-5",
|
|
118
120
|
dashboardRunHour: 3,
|
|
119
121
|
dashboardMaxSessionsPerRun: 30,
|
|
122
|
+
magicUiEnabled: false,
|
|
123
|
+
magicUiModel: "claude-haiku-4-5",
|
|
120
124
|
publicUrl: "",
|
|
121
125
|
updateChannel: "stable",
|
|
122
126
|
dockerAutoUpdate: false,
|
|
@@ -211,6 +215,8 @@ describe("settings-manager", () => {
|
|
|
211
215
|
dashboardModel: "claude-haiku-4-5",
|
|
212
216
|
dashboardRunHour: 3,
|
|
213
217
|
dashboardMaxSessionsPerRun: 30,
|
|
218
|
+
magicUiEnabled: false,
|
|
219
|
+
magicUiModel: "claude-haiku-4-5",
|
|
214
220
|
publicUrl: "",
|
|
215
221
|
updateChannel: "stable",
|
|
216
222
|
dockerAutoUpdate: false,
|
|
@@ -20,6 +20,12 @@ export const DASHBOARD_MODEL_OPTIONS = [
|
|
|
20
20
|
"claude-sonnet-5",
|
|
21
21
|
] as const;
|
|
22
22
|
export const DEFAULT_DASHBOARD_RUN_HOUR = 3;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The MagicUI watcher streams many small turns per session, so it defaults to
|
|
26
|
+
* the cheapest capable model. Shares the dashboard model option list.
|
|
27
|
+
*/
|
|
28
|
+
export const DEFAULT_MAGIC_UI_MODEL = DEFAULT_DASHBOARD_MODEL;
|
|
23
29
|
export const DEFAULT_DASHBOARD_MAX_SESSIONS_PER_RUN = 30;
|
|
24
30
|
|
|
25
31
|
export type UpdateChannel = "stable" | "prerelease";
|
|
@@ -83,6 +89,14 @@ export interface CompanionSettings {
|
|
|
83
89
|
dashboardRunHour: number;
|
|
84
90
|
/** Cost safety valve: max sessions summarized per run. */
|
|
85
91
|
dashboardMaxSessionsPerRun: number;
|
|
92
|
+
/**
|
|
93
|
+
* Makes the MagicUI session view available to users (default off). Users
|
|
94
|
+
* still opt in per session; see SessionState.magicUiActive. Requires the
|
|
95
|
+
* Claude CLI login — the watcher runs on the subscription, never an API key.
|
|
96
|
+
*/
|
|
97
|
+
magicUiEnabled: boolean;
|
|
98
|
+
/** Model used by the MagicUI watcher. Cheap-by-default (Haiku). */
|
|
99
|
+
magicUiModel: string;
|
|
86
100
|
publicUrl: string;
|
|
87
101
|
updateChannel: UpdateChannel;
|
|
88
102
|
dockerAutoUpdate: boolean;
|
|
@@ -176,6 +190,8 @@ let settings: CompanionSettings = {
|
|
|
176
190
|
dashboardModel: DEFAULT_DASHBOARD_MODEL,
|
|
177
191
|
dashboardRunHour: DEFAULT_DASHBOARD_RUN_HOUR,
|
|
178
192
|
dashboardMaxSessionsPerRun: DEFAULT_DASHBOARD_MAX_SESSIONS_PER_RUN,
|
|
193
|
+
magicUiEnabled: false,
|
|
194
|
+
magicUiModel: DEFAULT_MAGIC_UI_MODEL,
|
|
179
195
|
publicUrl: "",
|
|
180
196
|
updateChannel: "stable",
|
|
181
197
|
dockerAutoUpdate: false,
|
|
@@ -231,6 +247,11 @@ function normalize(raw: Partial<CompanionSettings> | null | undefined): Companio
|
|
|
231
247
|
&& raw.dashboardMaxSessionsPerRun >= 1 && raw.dashboardMaxSessionsPerRun <= 200
|
|
232
248
|
? raw.dashboardMaxSessionsPerRun
|
|
233
249
|
: DEFAULT_DASHBOARD_MAX_SESSIONS_PER_RUN,
|
|
250
|
+
magicUiEnabled: typeof raw?.magicUiEnabled === "boolean" ? raw.magicUiEnabled : false,
|
|
251
|
+
magicUiModel:
|
|
252
|
+
typeof raw?.magicUiModel === "string" && raw.magicUiModel.trim()
|
|
253
|
+
? raw.magicUiModel.trim()
|
|
254
|
+
: DEFAULT_MAGIC_UI_MODEL,
|
|
234
255
|
publicUrl: typeof raw?.publicUrl === "string" ? raw.publicUrl.trim().replace(/\/+$/, "") : "",
|
|
235
256
|
updateChannel: raw?.updateChannel === "prerelease" ? "prerelease" : "stable",
|
|
236
257
|
dockerAutoUpdate: typeof raw?.dockerAutoUpdate === "boolean" ? raw.dockerAutoUpdate : false,
|
|
@@ -272,7 +293,7 @@ export function getSettings(): CompanionSettings {
|
|
|
272
293
|
}
|
|
273
294
|
|
|
274
295
|
export function updateSettings(
|
|
275
|
-
patch: Partial<Pick<CompanionSettings, "anthropicApiKey" | "anthropicModel" | "claudeCodeOAuthToken" | "openaiApiKey" | "onboardingCompleted" | "linearApiKey" | "linearAutoTransition" | "linearAutoTransitionStateId" | "linearAutoTransitionStateName" | "linearArchiveTransition" | "linearArchiveTransitionStateId" | "linearArchiveTransitionStateName" | "linearOAuthClientId" | "linearOAuthClientSecret" | "linearOAuthWebhookSecret" | "linearOAuthAccessToken" | "linearOAuthRefreshToken" | "aiValidationEnabled" | "aiValidationAutoApprove" | "aiValidationAutoDeny" | "dashboardEnabled" | "dashboardModel" | "dashboardRunHour" | "dashboardMaxSessionsPerRun" | "publicUrl" | "updateChannel" | "dockerAutoUpdate" | "proactiveKeepaliveEnabled" | "keepaliveDetachedSessions" | "wedgeKillEnabled" | "silenceProbeEnabled" | "claudeTransport" | "cliBridgeMode" | "claudeBridgeMode" | "claudeBridgeIngressUrl" | "claudeCompatBannerDismissedVersion">>,
|
|
296
|
+
patch: Partial<Pick<CompanionSettings, "anthropicApiKey" | "anthropicModel" | "claudeCodeOAuthToken" | "openaiApiKey" | "onboardingCompleted" | "linearApiKey" | "linearAutoTransition" | "linearAutoTransitionStateId" | "linearAutoTransitionStateName" | "linearArchiveTransition" | "linearArchiveTransitionStateId" | "linearArchiveTransitionStateName" | "linearOAuthClientId" | "linearOAuthClientSecret" | "linearOAuthWebhookSecret" | "linearOAuthAccessToken" | "linearOAuthRefreshToken" | "aiValidationEnabled" | "aiValidationAutoApprove" | "aiValidationAutoDeny" | "dashboardEnabled" | "dashboardModel" | "dashboardRunHour" | "dashboardMaxSessionsPerRun" | "magicUiEnabled" | "magicUiModel" | "publicUrl" | "updateChannel" | "dockerAutoUpdate" | "proactiveKeepaliveEnabled" | "keepaliveDetachedSessions" | "wedgeKillEnabled" | "silenceProbeEnabled" | "claudeTransport" | "cliBridgeMode" | "claudeBridgeMode" | "claudeBridgeIngressUrl" | "claudeCompatBannerDismissedVersion">>,
|
|
276
297
|
): CompanionSettings {
|
|
277
298
|
ensureLoaded();
|
|
278
299
|
settings = normalize({
|
|
@@ -300,6 +321,8 @@ export function updateSettings(
|
|
|
300
321
|
dashboardModel: patch.dashboardModel ?? settings.dashboardModel,
|
|
301
322
|
dashboardRunHour: patch.dashboardRunHour ?? settings.dashboardRunHour,
|
|
302
323
|
dashboardMaxSessionsPerRun: patch.dashboardMaxSessionsPerRun ?? settings.dashboardMaxSessionsPerRun,
|
|
324
|
+
magicUiEnabled: patch.magicUiEnabled ?? settings.magicUiEnabled,
|
|
325
|
+
magicUiModel: patch.magicUiModel ?? settings.magicUiModel,
|
|
303
326
|
publicUrl: patch.publicUrl ?? settings.publicUrl,
|
|
304
327
|
updateChannel: patch.updateChannel ?? settings.updateChannel,
|
|
305
328
|
dockerAutoUpdate: patch.dockerAutoUpdate ?? settings.dockerAutoUpdate,
|
|
@@ -136,6 +136,8 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
136
136
|
dashboardModel: "claude-haiku-4-5",
|
|
137
137
|
dashboardRunHour: 3,
|
|
138
138
|
dashboardMaxSessionsPerRun: 30,
|
|
139
|
+
magicUiEnabled: false,
|
|
140
|
+
magicUiModel: "claude-haiku-4-5",
|
|
139
141
|
publicUrl: "",
|
|
140
142
|
updateChannel: "stable",
|
|
141
143
|
dockerAutoUpdate: false,
|
|
@@ -1130,6 +1132,8 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1130
1132
|
dashboardModel: "claude-haiku-4-5",
|
|
1131
1133
|
dashboardRunHour: 3,
|
|
1132
1134
|
dashboardMaxSessionsPerRun: 30,
|
|
1135
|
+
magicUiEnabled: false,
|
|
1136
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1133
1137
|
publicUrl: "",
|
|
1134
1138
|
updateChannel: "stable",
|
|
1135
1139
|
dockerAutoUpdate: false,
|
|
@@ -1314,6 +1318,8 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1314
1318
|
dashboardModel: "claude-haiku-4-5",
|
|
1315
1319
|
dashboardRunHour: 3,
|
|
1316
1320
|
dashboardMaxSessionsPerRun: 30,
|
|
1321
|
+
magicUiEnabled: false,
|
|
1322
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1317
1323
|
publicUrl: "",
|
|
1318
1324
|
updateChannel: "stable",
|
|
1319
1325
|
dockerAutoUpdate: false,
|
|
@@ -1368,6 +1374,8 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1368
1374
|
dashboardModel: "claude-haiku-4-5",
|
|
1369
1375
|
dashboardRunHour: 3,
|
|
1370
1376
|
dashboardMaxSessionsPerRun: 30,
|
|
1377
|
+
magicUiEnabled: false,
|
|
1378
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1371
1379
|
publicUrl: "",
|
|
1372
1380
|
updateChannel: "stable",
|
|
1373
1381
|
dockerAutoUpdate: false,
|
|
@@ -1487,6 +1495,8 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1487
1495
|
dashboardModel: "claude-haiku-4-5",
|
|
1488
1496
|
dashboardRunHour: 3,
|
|
1489
1497
|
dashboardMaxSessionsPerRun: 30,
|
|
1498
|
+
magicUiEnabled: false,
|
|
1499
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1490
1500
|
publicUrl: "",
|
|
1491
1501
|
updateChannel: "stable",
|
|
1492
1502
|
dockerAutoUpdate: false,
|
|
@@ -1625,6 +1635,8 @@ describe("attachCodexAdapterHandlers", () => {
|
|
|
1625
1635
|
dashboardModel: "claude-haiku-4-5",
|
|
1626
1636
|
dashboardRunHour: 3,
|
|
1627
1637
|
dashboardMaxSessionsPerRun: 30,
|
|
1638
|
+
magicUiEnabled: false,
|
|
1639
|
+
magicUiModel: "claude-haiku-4-5",
|
|
1628
1640
|
publicUrl: "",
|
|
1629
1641
|
updateChannel: "stable",
|
|
1630
1642
|
dockerAutoUpdate: false,
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import type { Session } from "./ws-bridge-types.js";
|
|
2
2
|
|
|
3
|
+
export function handleSetMagicUi(
|
|
4
|
+
session: Session,
|
|
5
|
+
msg: { magicUiActive?: boolean | null },
|
|
6
|
+
): void {
|
|
7
|
+
if (msg.magicUiActive !== undefined) {
|
|
8
|
+
session.state.magicUiActive = msg.magicUiActive;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
3
12
|
export function handleSetAiValidation(
|
|
4
13
|
session: Session,
|
|
5
14
|
msg: {
|