@hellcoder/companion 0.107.0 → 0.107.1-preview.20260719040931.f983b4d
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-t4s7ZO2P.js → AgentsPage-DI5hdCnz.js} +5 -5
- package/dist/assets/{CronManager-C_0weC_z.js → CronManager-yX8i4C_S.js} +1 -1
- package/dist/assets/DashboardPage-D1nc0wHf.js +1 -0
- package/dist/assets/{IntegrationsPage-Gte53t7Z.js → IntegrationsPage-iSfvR9vX.js} +1 -1
- package/dist/assets/{LinearOAuthSettingsPage-DHJ73rFh.js → LinearOAuthSettingsPage-omExXsGc.js} +1 -1
- package/dist/assets/{LinearSettingsPage-D7ZHYkum.js → LinearSettingsPage-C4oBf1iO.js} +1 -1
- package/dist/assets/{Playground-DBWsv4R6.js → Playground-CjiZI9QY.js} +1 -1
- package/dist/assets/{PromptsPage-Cnjs3hD9.js → PromptsPage-CU6z49U6.js} +1 -1
- package/dist/assets/{RunsPage-B5PsNevy.js → RunsPage-mcU7OUoZ.js} +1 -1
- package/dist/assets/{SandboxManager-DpFA1it7.js → SandboxManager-BkYS-dK5.js} +1 -1
- package/dist/assets/SettingsPage-CyHMmTBB.js +1 -0
- package/dist/assets/{TailscalePage-CMG1g7e2.js → TailscalePage-CRyiyMcJ.js} +1 -1
- package/dist/assets/index-DMoY-FDD.css +1 -0
- package/dist/assets/index-DOle27vf.js +136 -0
- package/dist/assets/{sw-register-CS-6kwSW.js → sw-register-Dqdfho7x.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/package.json +1 -1
- package/server/auto-namer.test.ts +16 -0
- package/server/claude-cli-runner.ts +92 -0
- package/server/dashboard-scheduler.test.ts +73 -0
- package/server/dashboard-scheduler.ts +46 -0
- package/server/dashboard-store.test.ts +101 -0
- package/server/dashboard-store.ts +121 -0
- package/server/dashboard-summarizer.test.ts +216 -0
- package/server/dashboard-summarizer.ts +290 -0
- package/server/dashboard-types.ts +70 -0
- package/server/index.ts +4 -0
- package/server/linear-connections.test.ts +16 -0
- package/server/routes/dashboard-routes.test.ts +139 -0
- package/server/routes/dashboard-routes.ts +101 -0
- package/server/routes/settings-routes.ts +47 -1
- package/server/routes.test.ts +112 -0
- package/server/routes.ts +4 -0
- package/server/settings-manager.test.ts +12 -0
- package/server/settings-manager.ts +45 -1
- package/server/ws-bridge-codex.test.ts +24 -0
- package/dist/assets/SettingsPage-v8ndyXOz.js +0 -1
- package/dist/assets/index-Bp3e_166.js +0 -136
- package/dist/assets/index-D4AeOLki.css +0 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { Hono } from "hono";
|
|
6
|
+
import { registerDashboardRoutes } from "./dashboard-routes.js";
|
|
7
|
+
import { DashboardStore } from "../dashboard-store.js";
|
|
8
|
+
import { _resetForTest } from "../settings-manager.js";
|
|
9
|
+
import { _resetDashboardRunStateForTest } from "../dashboard-summarizer.js";
|
|
10
|
+
import type { DashboardRunMeta, DashboardSessionSummary } from "../dashboard-types.js";
|
|
11
|
+
|
|
12
|
+
// Validates the dashboard REST surface: GET serves purely from the stored
|
|
13
|
+
// nightly data (never live sessions), joins companion-managed sessions via
|
|
14
|
+
// cliSessionId, and the manual run trigger requires the Claude Code CLI
|
|
15
|
+
// (the summarizer authenticates via the CLI login, not an API key).
|
|
16
|
+
|
|
17
|
+
const CLI_SESSION_ID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee";
|
|
18
|
+
|
|
19
|
+
function makeSummary(overrides: Partial<DashboardSessionSummary> = {}): DashboardSessionSummary {
|
|
20
|
+
return {
|
|
21
|
+
sessionId: CLI_SESSION_ID,
|
|
22
|
+
cwd: "/root/projects/demo",
|
|
23
|
+
gitBranch: "main",
|
|
24
|
+
slug: "demo-task",
|
|
25
|
+
summary: "Work is underway.",
|
|
26
|
+
status: "in_progress",
|
|
27
|
+
openItems: ["finish tests"],
|
|
28
|
+
archivable: false,
|
|
29
|
+
transcriptMtimeMs: 1000,
|
|
30
|
+
lastActivityAt: 1000,
|
|
31
|
+
summarizedAt: 2000,
|
|
32
|
+
model: "claude-haiku-4-5",
|
|
33
|
+
...overrides,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function buildApp(store: DashboardStore, cliAvailable: boolean): Hono {
|
|
38
|
+
const app = new Hono();
|
|
39
|
+
registerDashboardRoutes(app, {
|
|
40
|
+
store,
|
|
41
|
+
isCliAvailable: () => cliAvailable,
|
|
42
|
+
listCompanionSessions: () => [
|
|
43
|
+
{
|
|
44
|
+
sessionId: "companion-1",
|
|
45
|
+
cliSessionId: CLI_SESSION_ID,
|
|
46
|
+
name: "Fix login",
|
|
47
|
+
userName: "Moritz",
|
|
48
|
+
archived: false,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
return app;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
describe("dashboard routes", () => {
|
|
56
|
+
let storeDir: string;
|
|
57
|
+
let store: DashboardStore;
|
|
58
|
+
let app: Hono;
|
|
59
|
+
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
storeDir = mkdtempSync(join(tmpdir(), "dashboard-routes-test-"));
|
|
62
|
+
store = new DashboardStore(storeDir);
|
|
63
|
+
_resetForTest(join(storeDir, "settings.json"));
|
|
64
|
+
_resetDashboardRunStateForTest();
|
|
65
|
+
app = buildApp(store, true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
afterEach(() => {
|
|
69
|
+
_resetForTest();
|
|
70
|
+
rmSync(storeDir, { recursive: true, force: true });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("GET /dashboard returns stored summaries joined with companion sessions", async () => {
|
|
74
|
+
store.saveSummary(makeSummary());
|
|
75
|
+
const meta: DashboardRunMeta = {
|
|
76
|
+
lastRunAt: 1,
|
|
77
|
+
lastRunCompletedAt: 2,
|
|
78
|
+
lastRunStatus: "success",
|
|
79
|
+
trigger: "scheduled",
|
|
80
|
+
model: "claude-haiku-4-5",
|
|
81
|
+
sessionsProcessed: 1,
|
|
82
|
+
sessionsSkipped: 0,
|
|
83
|
+
sessionsFailed: 0,
|
|
84
|
+
};
|
|
85
|
+
store.saveRunMeta(meta);
|
|
86
|
+
|
|
87
|
+
const res = await app.request("/dashboard");
|
|
88
|
+
expect(res.status).toBe(200);
|
|
89
|
+
const data = await res.json();
|
|
90
|
+
|
|
91
|
+
expect(data.enabled).toBe(false); // opt-in defaults to off
|
|
92
|
+
expect(data.claudeCliAvailable).toBe(true);
|
|
93
|
+
expect(data.runMeta).toEqual(meta);
|
|
94
|
+
expect(data.progress.state).toBe("idle");
|
|
95
|
+
expect(data.sessions).toHaveLength(1);
|
|
96
|
+
expect(data.sessions[0].companionSessionId).toBe("companion-1");
|
|
97
|
+
expect(data.sessions[0].displayName).toBe("Fix login");
|
|
98
|
+
expect(data.sessions[0].userName).toBe("Moritz");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("GET /dashboard leaves external (non-companion) sessions unlinked", async () => {
|
|
102
|
+
store.saveSummary(makeSummary({ sessionId: "11111111-2222-3333-4444-555555555555" }));
|
|
103
|
+
const res = await app.request("/dashboard");
|
|
104
|
+
const data = await res.json();
|
|
105
|
+
expect(data.sessions[0].companionSessionId).toBeUndefined();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("POST /dashboard/run returns 400 when the Claude CLI is unavailable", async () => {
|
|
109
|
+
const noCliApp = buildApp(store, false);
|
|
110
|
+
const res = await noCliApp.request("/dashboard/run", { method: "POST" });
|
|
111
|
+
expect(res.status).toBe(400);
|
|
112
|
+
const data = await res.json();
|
|
113
|
+
expect(data.error).toContain("Claude Code CLI");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("POST /dashboard/run starts a background run when the CLI is available", async () => {
|
|
117
|
+
// Point discovery at an empty dir so the background run finds no sessions
|
|
118
|
+
// (and therefore never actually invokes the CLI).
|
|
119
|
+
const emptyProjects = mkdtempSync(join(tmpdir(), "dashboard-empty-projects-"));
|
|
120
|
+
const prevProjectsDir = process.env.CLAUDE_PROJECTS_DIR;
|
|
121
|
+
process.env.CLAUDE_PROJECTS_DIR = emptyProjects;
|
|
122
|
+
try {
|
|
123
|
+
const res = await app.request("/dashboard/run", { method: "POST" });
|
|
124
|
+
expect(res.status).toBe(200);
|
|
125
|
+
expect((await res.json()).started).toBe(true);
|
|
126
|
+
|
|
127
|
+
// Wait for the fire-and-forget run to finish and write run meta.
|
|
128
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
129
|
+
const status = await app.request("/dashboard/run/status");
|
|
130
|
+
const statusData = await status.json();
|
|
131
|
+
expect(statusData.progress.state).toBe("idle");
|
|
132
|
+
expect(statusData.runMeta?.trigger).toBe("manual");
|
|
133
|
+
} finally {
|
|
134
|
+
if (prevProjectsDir === undefined) delete process.env.CLAUDE_PROJECTS_DIR;
|
|
135
|
+
else process.env.CLAUDE_PROJECTS_DIR = prevProjectsDir;
|
|
136
|
+
rmSync(emptyProjects, { recursive: true, force: true });
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Hono } from "hono";
|
|
2
|
+
import { getSettings } from "../settings-manager.js";
|
|
3
|
+
import { isClaudeCliAvailable } from "../claude-cli-runner.js";
|
|
4
|
+
import { getDashboardStore, type DashboardStore } from "../dashboard-store.js";
|
|
5
|
+
import {
|
|
6
|
+
getDashboardRunProgress,
|
|
7
|
+
isDashboardRunActive,
|
|
8
|
+
runDashboardUpdate,
|
|
9
|
+
} from "../dashboard-summarizer.js";
|
|
10
|
+
import type { DashboardSessionSummary } from "../dashboard-types.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Minimal slice of SdkSessionInfo needed to join companion-managed sessions
|
|
14
|
+
* onto discovered Claude transcripts (matched via cliSessionId).
|
|
15
|
+
*/
|
|
16
|
+
export interface CompanionSessionLink {
|
|
17
|
+
sessionId: string;
|
|
18
|
+
cliSessionId?: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
userName?: string;
|
|
21
|
+
archived?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface DashboardRouteDeps {
|
|
25
|
+
listCompanionSessions?: () => CompanionSessionLink[];
|
|
26
|
+
store?: DashboardStore;
|
|
27
|
+
/** Override the Claude CLI availability check (tests). */
|
|
28
|
+
isCliAvailable?: () => boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface DashboardSessionEntry extends DashboardSessionSummary {
|
|
32
|
+
/** Companion session id when this transcript belongs to a companion-managed session. */
|
|
33
|
+
companionSessionId?: string;
|
|
34
|
+
companionArchived?: boolean;
|
|
35
|
+
displayName?: string;
|
|
36
|
+
userName?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function registerDashboardRoutes(api: Hono, deps: DashboardRouteDeps = {}): void {
|
|
40
|
+
const store = () => deps.store || getDashboardStore();
|
|
41
|
+
const cliAvailable = () => (deps.isCliAvailable ? deps.isCliAvailable() : isClaudeCliAvailable());
|
|
42
|
+
|
|
43
|
+
// Dashboard data — served purely from the nightly store, never from live sessions.
|
|
44
|
+
api.get("/dashboard", (c) => {
|
|
45
|
+
const settings = getSettings();
|
|
46
|
+
const summaries = store().loadAllSummaries();
|
|
47
|
+
|
|
48
|
+
const links = new Map<string, CompanionSessionLink>();
|
|
49
|
+
try {
|
|
50
|
+
for (const session of deps.listCompanionSessions?.() ?? []) {
|
|
51
|
+
if (session.cliSessionId) links.set(session.cliSessionId, session);
|
|
52
|
+
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.warn("[dashboard] Failed to enumerate companion sessions:", err);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const sessions: DashboardSessionEntry[] = summaries.map((summary) => {
|
|
58
|
+
const link = links.get(summary.sessionId);
|
|
59
|
+
return {
|
|
60
|
+
...summary,
|
|
61
|
+
companionSessionId: link?.sessionId,
|
|
62
|
+
companionArchived: link?.archived === true ? true : undefined,
|
|
63
|
+
displayName: link?.name,
|
|
64
|
+
userName: link?.userName,
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return c.json({
|
|
69
|
+
enabled: settings.dashboardEnabled,
|
|
70
|
+
model: settings.dashboardModel,
|
|
71
|
+
runHour: settings.dashboardRunHour,
|
|
72
|
+
claudeCliAvailable: cliAvailable(),
|
|
73
|
+
runMeta: store().loadRunMeta(),
|
|
74
|
+
progress: getDashboardRunProgress(),
|
|
75
|
+
sessions,
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Manual "Update now" trigger. Runs in the background; poll run/status for progress.
|
|
80
|
+
api.post("/dashboard/run", (c) => {
|
|
81
|
+
if (isDashboardRunActive()) {
|
|
82
|
+
return c.json({ error: "A dashboard update is already running", progress: getDashboardRunProgress() }, 409);
|
|
83
|
+
}
|
|
84
|
+
if (!cliAvailable()) {
|
|
85
|
+
return c.json({ error: "Claude Code CLI not found — the summarizer uses your Claude Code login" }, 400);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
runDashboardUpdate({ trigger: "manual", store: deps.store }).catch((err) => {
|
|
89
|
+
console.warn("[dashboard] Manual update failed:", err);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return c.json({ started: true });
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
api.get("/dashboard/run/status", (c) => {
|
|
96
|
+
return c.json({
|
|
97
|
+
progress: getDashboardRunProgress(),
|
|
98
|
+
runMeta: store().loadRunMeta(),
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Hono } from "hono";
|
|
2
|
-
import { DEFAULT_ANTHROPIC_MODEL, getSettings, updateSettings, type UpdateChannel, type CliBridgeMode } from "../settings-manager.js";
|
|
2
|
+
import { DASHBOARD_MODEL_OPTIONS, DEFAULT_ANTHROPIC_MODEL, getSettings, updateSettings, type UpdateChannel, type CliBridgeMode } from "../settings-manager.js";
|
|
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";
|
|
@@ -26,6 +26,10 @@ export function registerSettingsRoutes(api: Hono): void {
|
|
|
26
26
|
aiValidationEnabled: settings.aiValidationEnabled,
|
|
27
27
|
aiValidationAutoApprove: settings.aiValidationAutoApprove,
|
|
28
28
|
aiValidationAutoDeny: settings.aiValidationAutoDeny,
|
|
29
|
+
dashboardEnabled: settings.dashboardEnabled,
|
|
30
|
+
dashboardModel: settings.dashboardModel,
|
|
31
|
+
dashboardRunHour: settings.dashboardRunHour,
|
|
32
|
+
dashboardMaxSessionsPerRun: settings.dashboardMaxSessionsPerRun,
|
|
29
33
|
publicUrl: settings.publicUrl,
|
|
30
34
|
updateChannel: settings.updateChannel,
|
|
31
35
|
dockerAutoUpdate: settings.dockerAutoUpdate,
|
|
@@ -72,6 +76,26 @@ export function registerSettingsRoutes(api: Hono): void {
|
|
|
72
76
|
if (body.aiValidationAutoDeny !== undefined && typeof body.aiValidationAutoDeny !== "boolean") {
|
|
73
77
|
return c.json({ error: "aiValidationAutoDeny must be a boolean" }, 400);
|
|
74
78
|
}
|
|
79
|
+
if (body.dashboardEnabled !== undefined && typeof body.dashboardEnabled !== "boolean") {
|
|
80
|
+
return c.json({ error: "dashboardEnabled must be a boolean" }, 400);
|
|
81
|
+
}
|
|
82
|
+
if (body.dashboardModel !== undefined && !DASHBOARD_MODEL_OPTIONS.includes(body.dashboardModel)) {
|
|
83
|
+
return c.json({ error: `dashboardModel must be one of: ${DASHBOARD_MODEL_OPTIONS.join(", ")}` }, 400);
|
|
84
|
+
}
|
|
85
|
+
if (
|
|
86
|
+
body.dashboardRunHour !== undefined
|
|
87
|
+
&& (typeof body.dashboardRunHour !== "number" || !Number.isInteger(body.dashboardRunHour)
|
|
88
|
+
|| body.dashboardRunHour < 0 || body.dashboardRunHour > 23)
|
|
89
|
+
) {
|
|
90
|
+
return c.json({ error: "dashboardRunHour must be an integer between 0 and 23" }, 400);
|
|
91
|
+
}
|
|
92
|
+
if (
|
|
93
|
+
body.dashboardMaxSessionsPerRun !== undefined
|
|
94
|
+
&& (typeof body.dashboardMaxSessionsPerRun !== "number" || !Number.isInteger(body.dashboardMaxSessionsPerRun)
|
|
95
|
+
|| body.dashboardMaxSessionsPerRun < 1 || body.dashboardMaxSessionsPerRun > 200)
|
|
96
|
+
) {
|
|
97
|
+
return c.json({ error: "dashboardMaxSessionsPerRun must be an integer between 1 and 200" }, 400);
|
|
98
|
+
}
|
|
75
99
|
if (body.publicUrl !== undefined) {
|
|
76
100
|
if (typeof body.publicUrl !== "string") {
|
|
77
101
|
return c.json({ error: "publicUrl must be a string" }, 400);
|
|
@@ -122,6 +146,8 @@ export function registerSettingsRoutes(api: Hono): void {
|
|
|
122
146
|
|| body.linearOAuthWebhookSecret !== undefined
|
|
123
147
|
|| body.aiValidationEnabled !== undefined || body.aiValidationAutoApprove !== undefined
|
|
124
148
|
|| body.aiValidationAutoDeny !== undefined
|
|
149
|
+
|| body.dashboardEnabled !== undefined || body.dashboardModel !== undefined
|
|
150
|
+
|| body.dashboardRunHour !== undefined || body.dashboardMaxSessionsPerRun !== undefined
|
|
125
151
|
|| body.publicUrl !== undefined
|
|
126
152
|
|| body.updateChannel !== undefined
|
|
127
153
|
|| body.dockerAutoUpdate !== undefined
|
|
@@ -208,6 +234,22 @@ export function registerSettingsRoutes(api: Hono): void {
|
|
|
208
234
|
typeof body.aiValidationAutoDeny === "boolean"
|
|
209
235
|
? body.aiValidationAutoDeny
|
|
210
236
|
: undefined,
|
|
237
|
+
dashboardEnabled:
|
|
238
|
+
typeof body.dashboardEnabled === "boolean"
|
|
239
|
+
? body.dashboardEnabled
|
|
240
|
+
: undefined,
|
|
241
|
+
dashboardModel:
|
|
242
|
+
typeof body.dashboardModel === "string"
|
|
243
|
+
? body.dashboardModel
|
|
244
|
+
: undefined,
|
|
245
|
+
dashboardRunHour:
|
|
246
|
+
typeof body.dashboardRunHour === "number"
|
|
247
|
+
? body.dashboardRunHour
|
|
248
|
+
: undefined,
|
|
249
|
+
dashboardMaxSessionsPerRun:
|
|
250
|
+
typeof body.dashboardMaxSessionsPerRun === "number"
|
|
251
|
+
? body.dashboardMaxSessionsPerRun
|
|
252
|
+
: undefined,
|
|
211
253
|
publicUrl:
|
|
212
254
|
typeof body.publicUrl === "string"
|
|
213
255
|
? body.publicUrl.trim().replace(/\/+$/, "")
|
|
@@ -249,6 +291,10 @@ export function registerSettingsRoutes(api: Hono): void {
|
|
|
249
291
|
aiValidationEnabled: settings.aiValidationEnabled,
|
|
250
292
|
aiValidationAutoApprove: settings.aiValidationAutoApprove,
|
|
251
293
|
aiValidationAutoDeny: settings.aiValidationAutoDeny,
|
|
294
|
+
dashboardEnabled: settings.dashboardEnabled,
|
|
295
|
+
dashboardModel: settings.dashboardModel,
|
|
296
|
+
dashboardRunHour: settings.dashboardRunHour,
|
|
297
|
+
dashboardMaxSessionsPerRun: settings.dashboardMaxSessionsPerRun,
|
|
252
298
|
publicUrl: settings.publicUrl,
|
|
253
299
|
updateChannel: settings.updateChannel,
|
|
254
300
|
dockerAutoUpdate: settings.dockerAutoUpdate,
|
package/server/routes.test.ts
CHANGED
|
@@ -102,6 +102,10 @@ vi.mock("./settings-manager.js", () => ({
|
|
|
102
102
|
aiValidationEnabled: false,
|
|
103
103
|
aiValidationAutoApprove: true,
|
|
104
104
|
aiValidationAutoDeny: false,
|
|
105
|
+
dashboardEnabled: false,
|
|
106
|
+
dashboardModel: "claude-haiku-4-5",
|
|
107
|
+
dashboardRunHour: 3,
|
|
108
|
+
dashboardMaxSessionsPerRun: 30,
|
|
105
109
|
publicUrl: "",
|
|
106
110
|
updateChannel: "stable",
|
|
107
111
|
dockerAutoUpdate: false,
|
|
@@ -1146,6 +1150,10 @@ describe("GET /api/sessions/:id/archive-info", () => {
|
|
|
1146
1150
|
aiValidationEnabled: false,
|
|
1147
1151
|
aiValidationAutoApprove: true,
|
|
1148
1152
|
aiValidationAutoDeny: false,
|
|
1153
|
+
dashboardEnabled: false,
|
|
1154
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1155
|
+
dashboardRunHour: 3,
|
|
1156
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1149
1157
|
publicUrl: "",
|
|
1150
1158
|
updateChannel: "stable",
|
|
1151
1159
|
dockerAutoUpdate: false,
|
|
@@ -1517,6 +1525,10 @@ describe("GET /api/settings", () => {
|
|
|
1517
1525
|
aiValidationEnabled: false,
|
|
1518
1526
|
aiValidationAutoApprove: true,
|
|
1519
1527
|
aiValidationAutoDeny: false,
|
|
1528
|
+
dashboardEnabled: false,
|
|
1529
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1530
|
+
dashboardRunHour: 3,
|
|
1531
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1520
1532
|
publicUrl: "",
|
|
1521
1533
|
updateChannel: "stable",
|
|
1522
1534
|
dockerAutoUpdate: false,
|
|
@@ -1546,6 +1558,10 @@ describe("GET /api/settings", () => {
|
|
|
1546
1558
|
aiValidationEnabled: false,
|
|
1547
1559
|
aiValidationAutoApprove: true,
|
|
1548
1560
|
aiValidationAutoDeny: false,
|
|
1561
|
+
dashboardEnabled: false,
|
|
1562
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1563
|
+
dashboardRunHour: 3,
|
|
1564
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1549
1565
|
publicUrl: "",
|
|
1550
1566
|
updateChannel: "stable",
|
|
1551
1567
|
dockerAutoUpdate: false,
|
|
@@ -1575,6 +1591,10 @@ describe("GET /api/settings", () => {
|
|
|
1575
1591
|
aiValidationEnabled: false,
|
|
1576
1592
|
aiValidationAutoApprove: true,
|
|
1577
1593
|
aiValidationAutoDeny: false,
|
|
1594
|
+
dashboardEnabled: false,
|
|
1595
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1596
|
+
dashboardRunHour: 3,
|
|
1597
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1578
1598
|
publicUrl: "",
|
|
1579
1599
|
updateChannel: "stable",
|
|
1580
1600
|
dockerAutoUpdate: false,
|
|
@@ -1604,6 +1624,10 @@ describe("GET /api/settings", () => {
|
|
|
1604
1624
|
aiValidationEnabled: false,
|
|
1605
1625
|
aiValidationAutoApprove: true,
|
|
1606
1626
|
aiValidationAutoDeny: false,
|
|
1627
|
+
dashboardEnabled: false,
|
|
1628
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1629
|
+
dashboardRunHour: 3,
|
|
1630
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1607
1631
|
publicUrl: "",
|
|
1608
1632
|
updateChannel: "stable",
|
|
1609
1633
|
dockerAutoUpdate: false,
|
|
@@ -1634,6 +1658,10 @@ describe("GET /api/settings", () => {
|
|
|
1634
1658
|
aiValidationEnabled: false,
|
|
1635
1659
|
aiValidationAutoApprove: true,
|
|
1636
1660
|
aiValidationAutoDeny: false,
|
|
1661
|
+
dashboardEnabled: false,
|
|
1662
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1663
|
+
dashboardRunHour: 3,
|
|
1664
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1637
1665
|
publicUrl: "https://example.com",
|
|
1638
1666
|
updateChannel: "stable",
|
|
1639
1667
|
dockerAutoUpdate: false,
|
|
@@ -1672,6 +1700,10 @@ describe("PUT /api/settings", () => {
|
|
|
1672
1700
|
aiValidationEnabled: false,
|
|
1673
1701
|
aiValidationAutoApprove: true,
|
|
1674
1702
|
aiValidationAutoDeny: false,
|
|
1703
|
+
dashboardEnabled: false,
|
|
1704
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1705
|
+
dashboardRunHour: 3,
|
|
1706
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1675
1707
|
publicUrl: "",
|
|
1676
1708
|
updateChannel: "stable",
|
|
1677
1709
|
dockerAutoUpdate: false,
|
|
@@ -1723,6 +1755,10 @@ describe("PUT /api/settings", () => {
|
|
|
1723
1755
|
aiValidationEnabled: false,
|
|
1724
1756
|
aiValidationAutoApprove: true,
|
|
1725
1757
|
aiValidationAutoDeny: false,
|
|
1758
|
+
dashboardEnabled: false,
|
|
1759
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1760
|
+
dashboardRunHour: 3,
|
|
1761
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1726
1762
|
publicUrl: "",
|
|
1727
1763
|
updateChannel: "stable",
|
|
1728
1764
|
dockerAutoUpdate: false,
|
|
@@ -1752,6 +1788,10 @@ describe("PUT /api/settings", () => {
|
|
|
1752
1788
|
aiValidationEnabled: false,
|
|
1753
1789
|
aiValidationAutoApprove: true,
|
|
1754
1790
|
aiValidationAutoDeny: false,
|
|
1791
|
+
dashboardEnabled: false,
|
|
1792
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1793
|
+
dashboardRunHour: 3,
|
|
1794
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1755
1795
|
publicUrl: "",
|
|
1756
1796
|
updateChannel: "stable",
|
|
1757
1797
|
dockerAutoUpdate: false,
|
|
@@ -1798,6 +1838,10 @@ describe("PUT /api/settings", () => {
|
|
|
1798
1838
|
aiValidationEnabled: false,
|
|
1799
1839
|
aiValidationAutoApprove: true,
|
|
1800
1840
|
aiValidationAutoDeny: false,
|
|
1841
|
+
dashboardEnabled: false,
|
|
1842
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1843
|
+
dashboardRunHour: 3,
|
|
1844
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1801
1845
|
publicUrl: "",
|
|
1802
1846
|
updateChannel: "stable",
|
|
1803
1847
|
dockerAutoUpdate: false,
|
|
@@ -1895,6 +1939,10 @@ describe("PUT /api/settings", () => {
|
|
|
1895
1939
|
aiValidationEnabled: false,
|
|
1896
1940
|
aiValidationAutoApprove: true,
|
|
1897
1941
|
aiValidationAutoDeny: false,
|
|
1942
|
+
dashboardEnabled: false,
|
|
1943
|
+
dashboardModel: "claude-haiku-4-5",
|
|
1944
|
+
dashboardRunHour: 3,
|
|
1945
|
+
dashboardMaxSessionsPerRun: 30,
|
|
1898
1946
|
publicUrl: "https://my-server.com",
|
|
1899
1947
|
updateChannel: "stable",
|
|
1900
1948
|
dockerAutoUpdate: false,
|
|
@@ -2147,6 +2195,10 @@ describe("GET /api/linear/issues", () => {
|
|
|
2147
2195
|
aiValidationEnabled: false,
|
|
2148
2196
|
aiValidationAutoApprove: true,
|
|
2149
2197
|
aiValidationAutoDeny: false,
|
|
2198
|
+
dashboardEnabled: false,
|
|
2199
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2200
|
+
dashboardRunHour: 3,
|
|
2201
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2150
2202
|
publicUrl: "",
|
|
2151
2203
|
updateChannel: "stable",
|
|
2152
2204
|
dockerAutoUpdate: false,
|
|
@@ -2183,6 +2235,10 @@ describe("GET /api/linear/issues", () => {
|
|
|
2183
2235
|
aiValidationEnabled: false,
|
|
2184
2236
|
aiValidationAutoApprove: true,
|
|
2185
2237
|
aiValidationAutoDeny: false,
|
|
2238
|
+
dashboardEnabled: false,
|
|
2239
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2240
|
+
dashboardRunHour: 3,
|
|
2241
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2186
2242
|
publicUrl: "",
|
|
2187
2243
|
updateChannel: "stable",
|
|
2188
2244
|
dockerAutoUpdate: false,
|
|
@@ -2272,6 +2328,10 @@ describe("GET /api/linear/issues", () => {
|
|
|
2272
2328
|
aiValidationEnabled: false,
|
|
2273
2329
|
aiValidationAutoApprove: true,
|
|
2274
2330
|
aiValidationAutoDeny: false,
|
|
2331
|
+
dashboardEnabled: false,
|
|
2332
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2333
|
+
dashboardRunHour: 3,
|
|
2334
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2275
2335
|
publicUrl: "",
|
|
2276
2336
|
updateChannel: "stable",
|
|
2277
2337
|
dockerAutoUpdate: false,
|
|
@@ -2368,6 +2428,10 @@ describe("GET /api/linear/issues", () => {
|
|
|
2368
2428
|
aiValidationEnabled: false,
|
|
2369
2429
|
aiValidationAutoApprove: true,
|
|
2370
2430
|
aiValidationAutoDeny: false,
|
|
2431
|
+
dashboardEnabled: false,
|
|
2432
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2433
|
+
dashboardRunHour: 3,
|
|
2434
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2371
2435
|
publicUrl: "",
|
|
2372
2436
|
updateChannel: "stable",
|
|
2373
2437
|
dockerAutoUpdate: false,
|
|
@@ -2429,6 +2493,10 @@ describe("GET /api/linear/connection", () => {
|
|
|
2429
2493
|
aiValidationEnabled: false,
|
|
2430
2494
|
aiValidationAutoApprove: true,
|
|
2431
2495
|
aiValidationAutoDeny: false,
|
|
2496
|
+
dashboardEnabled: false,
|
|
2497
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2498
|
+
dashboardRunHour: 3,
|
|
2499
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2432
2500
|
publicUrl: "",
|
|
2433
2501
|
updateChannel: "stable",
|
|
2434
2502
|
dockerAutoUpdate: false,
|
|
@@ -2465,6 +2533,10 @@ describe("GET /api/linear/connection", () => {
|
|
|
2465
2533
|
aiValidationEnabled: false,
|
|
2466
2534
|
aiValidationAutoApprove: true,
|
|
2467
2535
|
aiValidationAutoDeny: false,
|
|
2536
|
+
dashboardEnabled: false,
|
|
2537
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2538
|
+
dashboardRunHour: 3,
|
|
2539
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2468
2540
|
publicUrl: "",
|
|
2469
2541
|
updateChannel: "stable",
|
|
2470
2542
|
dockerAutoUpdate: false,
|
|
@@ -2523,6 +2595,10 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2523
2595
|
aiValidationEnabled: false,
|
|
2524
2596
|
aiValidationAutoApprove: true,
|
|
2525
2597
|
aiValidationAutoDeny: false,
|
|
2598
|
+
dashboardEnabled: false,
|
|
2599
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2600
|
+
dashboardRunHour: 3,
|
|
2601
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2526
2602
|
publicUrl: "",
|
|
2527
2603
|
updateChannel: "stable",
|
|
2528
2604
|
dockerAutoUpdate: false,
|
|
@@ -2563,6 +2639,10 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2563
2639
|
aiValidationEnabled: false,
|
|
2564
2640
|
aiValidationAutoApprove: true,
|
|
2565
2641
|
aiValidationAutoDeny: false,
|
|
2642
|
+
dashboardEnabled: false,
|
|
2643
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2644
|
+
dashboardRunHour: 3,
|
|
2645
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2566
2646
|
publicUrl: "",
|
|
2567
2647
|
updateChannel: "stable",
|
|
2568
2648
|
dockerAutoUpdate: false,
|
|
@@ -2602,6 +2682,10 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2602
2682
|
aiValidationEnabled: false,
|
|
2603
2683
|
aiValidationAutoApprove: true,
|
|
2604
2684
|
aiValidationAutoDeny: false,
|
|
2685
|
+
dashboardEnabled: false,
|
|
2686
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2687
|
+
dashboardRunHour: 3,
|
|
2688
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2605
2689
|
publicUrl: "",
|
|
2606
2690
|
updateChannel: "stable",
|
|
2607
2691
|
dockerAutoUpdate: false,
|
|
@@ -2643,6 +2727,10 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2643
2727
|
aiValidationEnabled: false,
|
|
2644
2728
|
aiValidationAutoApprove: true,
|
|
2645
2729
|
aiValidationAutoDeny: false,
|
|
2730
|
+
dashboardEnabled: false,
|
|
2731
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2732
|
+
dashboardRunHour: 3,
|
|
2733
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2646
2734
|
publicUrl: "",
|
|
2647
2735
|
updateChannel: "stable",
|
|
2648
2736
|
dockerAutoUpdate: false,
|
|
@@ -2718,6 +2806,10 @@ describe("POST /api/linear/issues/:id/transition", () => {
|
|
|
2718
2806
|
aiValidationEnabled: false,
|
|
2719
2807
|
aiValidationAutoApprove: true,
|
|
2720
2808
|
aiValidationAutoDeny: false,
|
|
2809
|
+
dashboardEnabled: false,
|
|
2810
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2811
|
+
dashboardRunHour: 3,
|
|
2812
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2721
2813
|
publicUrl: "",
|
|
2722
2814
|
updateChannel: "stable",
|
|
2723
2815
|
dockerAutoUpdate: false,
|
|
@@ -2772,6 +2864,10 @@ describe("GET /api/linear/projects", () => {
|
|
|
2772
2864
|
aiValidationEnabled: false,
|
|
2773
2865
|
aiValidationAutoApprove: true,
|
|
2774
2866
|
aiValidationAutoDeny: false,
|
|
2867
|
+
dashboardEnabled: false,
|
|
2868
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2869
|
+
dashboardRunHour: 3,
|
|
2870
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2775
2871
|
publicUrl: "",
|
|
2776
2872
|
updateChannel: "stable",
|
|
2777
2873
|
dockerAutoUpdate: false,
|
|
@@ -2808,6 +2904,10 @@ describe("GET /api/linear/projects", () => {
|
|
|
2808
2904
|
aiValidationEnabled: false,
|
|
2809
2905
|
aiValidationAutoApprove: true,
|
|
2810
2906
|
aiValidationAutoDeny: false,
|
|
2907
|
+
dashboardEnabled: false,
|
|
2908
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2909
|
+
dashboardRunHour: 3,
|
|
2910
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2811
2911
|
publicUrl: "",
|
|
2812
2912
|
updateChannel: "stable",
|
|
2813
2913
|
dockerAutoUpdate: false,
|
|
@@ -2874,6 +2974,10 @@ describe("GET /api/linear/project-issues", () => {
|
|
|
2874
2974
|
aiValidationEnabled: false,
|
|
2875
2975
|
aiValidationAutoApprove: true,
|
|
2876
2976
|
aiValidationAutoDeny: false,
|
|
2977
|
+
dashboardEnabled: false,
|
|
2978
|
+
dashboardModel: "claude-haiku-4-5",
|
|
2979
|
+
dashboardRunHour: 3,
|
|
2980
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2877
2981
|
publicUrl: "",
|
|
2878
2982
|
updateChannel: "stable",
|
|
2879
2983
|
dockerAutoUpdate: false,
|
|
@@ -2910,6 +3014,10 @@ describe("GET /api/linear/project-issues", () => {
|
|
|
2910
3014
|
aiValidationEnabled: false,
|
|
2911
3015
|
aiValidationAutoApprove: true,
|
|
2912
3016
|
aiValidationAutoDeny: false,
|
|
3017
|
+
dashboardEnabled: false,
|
|
3018
|
+
dashboardModel: "claude-haiku-4-5",
|
|
3019
|
+
dashboardRunHour: 3,
|
|
3020
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2913
3021
|
publicUrl: "",
|
|
2914
3022
|
updateChannel: "stable",
|
|
2915
3023
|
dockerAutoUpdate: false,
|
|
@@ -2991,6 +3099,10 @@ describe("GET /api/linear/project-issues", () => {
|
|
|
2991
3099
|
aiValidationEnabled: false,
|
|
2992
3100
|
aiValidationAutoApprove: true,
|
|
2993
3101
|
aiValidationAutoDeny: false,
|
|
3102
|
+
dashboardEnabled: false,
|
|
3103
|
+
dashboardModel: "claude-haiku-4-5",
|
|
3104
|
+
dashboardRunHour: 3,
|
|
3105
|
+
dashboardMaxSessionsPerRun: 30,
|
|
2994
3106
|
publicUrl: "",
|
|
2995
3107
|
updateChannel: "stable",
|
|
2996
3108
|
dockerAutoUpdate: false,
|
package/server/routes.ts
CHANGED
|
@@ -26,6 +26,7 @@ import { registerMetricsRoutes } from "./routes/metrics-routes.js";
|
|
|
26
26
|
import { registerLinearAgentWebhookRoute, registerLinearAgentProtectedRoutes } from "./routes/linear-agent-routes.js";
|
|
27
27
|
import { registerPromptRoutes } from "./routes/prompt-routes.js";
|
|
28
28
|
import { registerSettingsRoutes } from "./routes/settings-routes.js";
|
|
29
|
+
import { registerDashboardRoutes } from "./routes/dashboard-routes.js";
|
|
29
30
|
import { registerTailscaleRoutes } from "./routes/tailscale-routes.js";
|
|
30
31
|
import { registerGitRoutes } from "./routes/git-routes.js";
|
|
31
32
|
import { registerSystemRoutes } from "./routes/system-routes.js";
|
|
@@ -1275,6 +1276,9 @@ export function createRoutes(
|
|
|
1275
1276
|
|
|
1276
1277
|
registerPromptRoutes(api);
|
|
1277
1278
|
registerSettingsRoutes(api);
|
|
1279
|
+
registerDashboardRoutes(api, {
|
|
1280
|
+
listCompanionSessions: () => launcher.listSessions(),
|
|
1281
|
+
});
|
|
1278
1282
|
|
|
1279
1283
|
// ─── Tailscale ──────────────────────────────────────────────────────
|
|
1280
1284
|
|
|
@@ -45,6 +45,10 @@ describe("settings-manager", () => {
|
|
|
45
45
|
aiValidationEnabled: false,
|
|
46
46
|
aiValidationAutoApprove: true,
|
|
47
47
|
aiValidationAutoDeny: false,
|
|
48
|
+
dashboardEnabled: false,
|
|
49
|
+
dashboardModel: "claude-haiku-4-5",
|
|
50
|
+
dashboardRunHour: 3,
|
|
51
|
+
dashboardMaxSessionsPerRun: 30,
|
|
48
52
|
publicUrl: "",
|
|
49
53
|
updateChannel: "stable",
|
|
50
54
|
dockerAutoUpdate: false,
|
|
@@ -105,6 +109,10 @@ describe("settings-manager", () => {
|
|
|
105
109
|
aiValidationEnabled: false,
|
|
106
110
|
aiValidationAutoApprove: true,
|
|
107
111
|
aiValidationAutoDeny: false,
|
|
112
|
+
dashboardEnabled: false,
|
|
113
|
+
dashboardModel: "claude-haiku-4-5",
|
|
114
|
+
dashboardRunHour: 3,
|
|
115
|
+
dashboardMaxSessionsPerRun: 30,
|
|
108
116
|
publicUrl: "",
|
|
109
117
|
updateChannel: "stable",
|
|
110
118
|
dockerAutoUpdate: false,
|
|
@@ -189,6 +197,10 @@ describe("settings-manager", () => {
|
|
|
189
197
|
aiValidationEnabled: false,
|
|
190
198
|
aiValidationAutoApprove: true,
|
|
191
199
|
aiValidationAutoDeny: false,
|
|
200
|
+
dashboardEnabled: false,
|
|
201
|
+
dashboardModel: "claude-haiku-4-5",
|
|
202
|
+
dashboardRunHour: 3,
|
|
203
|
+
dashboardMaxSessionsPerRun: 30,
|
|
192
204
|
publicUrl: "",
|
|
193
205
|
updateChannel: "stable",
|
|
194
206
|
dockerAutoUpdate: false,
|