@matthugh1/conductor-cli 0.2.2 → 0.2.3
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/agent.js +166 -90
- package/dist/{chunk-7S5HKGS5.js → branch-overview-RRHX3XGY.js} +114 -9
- package/dist/{chunk-FAZ7FCZQ.js → chunk-N2KKNG4C.js} +15 -3
- package/dist/{chunk-B2WDTKD7.js → cli-config-LEERSU5N.js} +6 -7
- package/dist/{daemon-GGOJDZDB.js → daemon-ZJDZIP3R.js} +24 -15
- package/dist/{daemon-client-BE64H437.js → daemon-client-CTYOJMJP.js} +124 -1
- package/dist/{git-hooks-UZJ6AER4.js → git-hooks-RQ6WJQS4.js} +1 -2
- package/dist/{git-wrapper-DVJ46TMA.js → git-wrapper-QRZYTYCZ.js} +1 -2
- package/package.json +2 -2
- package/dist/branch-overview-DSSCUE5F.js +0 -18
- package/dist/chunk-3MJBQK2F.js +0 -75
- package/dist/chunk-4YEHSYVN.js +0 -17
- package/dist/chunk-6VMREHG4.js +0 -22
- package/dist/chunk-KB2DTST2.js +0 -482
- package/dist/chunk-PANC6BTV.js +0 -151
- package/dist/cli-config-2ZDXUUQN.js +0 -21
- package/dist/cli-tasks-NM5D5PIZ.js +0 -180
- package/dist/db-U6Y3QJDD.js +0 -16
- package/dist/git-snapshots-N3FBS7T3.js +0 -90
- package/dist/health-UFK7YCKQ.js +0 -147
- package/dist/health-snapshots-6MUVHE3G.js +0 -39
- package/dist/work-queue-U3JYHLX2.js +0 -758
- package/dist/worktree-manager-2ZUJEL3L.js +0 -31
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
logGitActivity,
|
|
4
|
-
removeWorktree
|
|
5
|
-
} from "./chunk-KB2DTST2.js";
|
|
6
|
-
import "./chunk-3MJBQK2F.js";
|
|
7
|
-
import {
|
|
8
|
-
getProjectPathById
|
|
9
|
-
} from "./chunk-6VMREHG4.js";
|
|
10
|
-
import {
|
|
11
|
-
runGit
|
|
12
|
-
} from "./chunk-FAZ7FCZQ.js";
|
|
13
|
-
import {
|
|
14
|
-
query
|
|
15
|
-
} from "./chunk-PANC6BTV.js";
|
|
16
|
-
import "./chunk-4YEHSYVN.js";
|
|
17
|
-
|
|
18
|
-
// ../../src/core/cli-tasks.ts
|
|
19
|
-
function rowToCliTask(row) {
|
|
20
|
-
return {
|
|
21
|
-
id: row.id,
|
|
22
|
-
projectId: row.project_id,
|
|
23
|
-
taskType: row.task_type,
|
|
24
|
-
payload: row.payload,
|
|
25
|
-
status: row.status,
|
|
26
|
-
result: row.result,
|
|
27
|
-
createdAt: new Date(row.created_at).toISOString(),
|
|
28
|
-
startedAt: row.started_at ? new Date(row.started_at).toISOString() : null,
|
|
29
|
-
completedAt: row.completed_at ? new Date(row.completed_at).toISOString() : null
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
var ALLOWED_TASK_TYPES = /* @__PURE__ */ new Set([
|
|
33
|
-
"remove_worktree",
|
|
34
|
-
"delete_branch"
|
|
35
|
-
]);
|
|
36
|
-
async function createCliTask(projectId, taskType, payload) {
|
|
37
|
-
if (!ALLOWED_TASK_TYPES.has(taskType)) {
|
|
38
|
-
throw new Error(`Unknown task type: ${taskType}`);
|
|
39
|
-
}
|
|
40
|
-
const rows = await query(
|
|
41
|
-
`INSERT INTO cli_tasks (project_id, task_type, payload)
|
|
42
|
-
VALUES ($1, $2, $3)
|
|
43
|
-
RETURNING *`,
|
|
44
|
-
[projectId, taskType, JSON.stringify(payload)]
|
|
45
|
-
);
|
|
46
|
-
return rowToCliTask(rows[0]);
|
|
47
|
-
}
|
|
48
|
-
async function claimNextTask(projectId) {
|
|
49
|
-
const rows = await query(
|
|
50
|
-
`UPDATE cli_tasks
|
|
51
|
-
SET status = 'running', started_at = now()
|
|
52
|
-
WHERE id = (
|
|
53
|
-
SELECT id FROM cli_tasks
|
|
54
|
-
WHERE project_id = $1 AND status = 'pending'
|
|
55
|
-
ORDER BY created_at ASC
|
|
56
|
-
LIMIT 1
|
|
57
|
-
FOR UPDATE SKIP LOCKED
|
|
58
|
-
)
|
|
59
|
-
RETURNING *`,
|
|
60
|
-
[projectId]
|
|
61
|
-
);
|
|
62
|
-
return rows.length > 0 ? rowToCliTask(rows[0]) : null;
|
|
63
|
-
}
|
|
64
|
-
async function completeTask(taskId, result = {}) {
|
|
65
|
-
await query(
|
|
66
|
-
`UPDATE cli_tasks
|
|
67
|
-
SET status = 'done', result = $2, completed_at = now()
|
|
68
|
-
WHERE id = $1`,
|
|
69
|
-
[taskId, JSON.stringify(result)]
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
async function failTask(taskId, error) {
|
|
73
|
-
await query(
|
|
74
|
-
`UPDATE cli_tasks
|
|
75
|
-
SET status = 'failed', result = $2, completed_at = now()
|
|
76
|
-
WHERE id = $1`,
|
|
77
|
-
[taskId, JSON.stringify({ error })]
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
async function listCliTasks(projectId, options) {
|
|
81
|
-
const limit = options?.limit ?? 50;
|
|
82
|
-
if (options?.status) {
|
|
83
|
-
const rows2 = await query(
|
|
84
|
-
`SELECT * FROM cli_tasks
|
|
85
|
-
WHERE project_id = $1 AND status = $2
|
|
86
|
-
ORDER BY created_at DESC
|
|
87
|
-
LIMIT $3`,
|
|
88
|
-
[projectId, options.status, limit]
|
|
89
|
-
);
|
|
90
|
-
return rows2.map(rowToCliTask);
|
|
91
|
-
}
|
|
92
|
-
const rows = await query(
|
|
93
|
-
`SELECT * FROM cli_tasks
|
|
94
|
-
WHERE project_id = $1
|
|
95
|
-
ORDER BY created_at DESC
|
|
96
|
-
LIMIT $2`,
|
|
97
|
-
[projectId, limit]
|
|
98
|
-
);
|
|
99
|
-
return rows.map(rowToCliTask);
|
|
100
|
-
}
|
|
101
|
-
async function failStaleTasks(projectId) {
|
|
102
|
-
const rows = await query(
|
|
103
|
-
`UPDATE cli_tasks
|
|
104
|
-
SET status = 'failed',
|
|
105
|
-
result = '{"error": "Task timed out \u2014 pending for more than 24 hours"}'::jsonb,
|
|
106
|
-
completed_at = now()
|
|
107
|
-
WHERE project_id = $1
|
|
108
|
-
AND status = 'pending'
|
|
109
|
-
AND created_at < now() - interval '24 hours'
|
|
110
|
-
RETURNING id`,
|
|
111
|
-
[projectId]
|
|
112
|
-
);
|
|
113
|
-
return rows.length;
|
|
114
|
-
}
|
|
115
|
-
async function executeTask(task) {
|
|
116
|
-
const projectRoot = await getProjectPathById(task.projectId);
|
|
117
|
-
if (!projectRoot) {
|
|
118
|
-
const msg = "Project path not found in database.";
|
|
119
|
-
await failTask(task.id, msg);
|
|
120
|
-
return msg;
|
|
121
|
-
}
|
|
122
|
-
try {
|
|
123
|
-
switch (task.taskType) {
|
|
124
|
-
case "remove_worktree":
|
|
125
|
-
return await handleRemoveWorktree(task, projectRoot);
|
|
126
|
-
case "delete_branch":
|
|
127
|
-
return await handleDeleteBranch(task, projectRoot);
|
|
128
|
-
default: {
|
|
129
|
-
const msg = `Unknown task type: ${task.taskType}`;
|
|
130
|
-
await failTask(task.id, msg);
|
|
131
|
-
return msg;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
} catch (err) {
|
|
135
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
136
|
-
await failTask(task.id, msg);
|
|
137
|
-
return `Failed: ${msg}`;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
async function handleRemoveWorktree(task, projectRoot) {
|
|
141
|
-
const worktreeId = task.payload.worktreeId;
|
|
142
|
-
if (!worktreeId) {
|
|
143
|
-
const msg = "Missing worktreeId in task payload.";
|
|
144
|
-
await failTask(task.id, msg);
|
|
145
|
-
return msg;
|
|
146
|
-
}
|
|
147
|
-
await removeWorktree(task.projectId, projectRoot, worktreeId);
|
|
148
|
-
await completeTask(task.id, { worktreeId });
|
|
149
|
-
return `Removed worktree ${worktreeId}`;
|
|
150
|
-
}
|
|
151
|
-
async function handleDeleteBranch(task, projectRoot) {
|
|
152
|
-
const branchName = task.payload.branchName;
|
|
153
|
-
if (!branchName) {
|
|
154
|
-
const msg = "Missing branchName in task payload.";
|
|
155
|
-
await failTask(task.id, msg);
|
|
156
|
-
return msg;
|
|
157
|
-
}
|
|
158
|
-
await runGit(projectRoot, ["branch", "-D", branchName]);
|
|
159
|
-
await logGitActivity({
|
|
160
|
-
projectId: task.projectId,
|
|
161
|
-
initiativeId: null,
|
|
162
|
-
worktreeId: null,
|
|
163
|
-
eventType: "branch_delete",
|
|
164
|
-
summary: `Deleted branch "${branchName}"`,
|
|
165
|
-
plainEnglish: `Deleted the branch "${branchName}" from the local repository.`,
|
|
166
|
-
branch: branchName,
|
|
167
|
-
source: "system"
|
|
168
|
-
});
|
|
169
|
-
await completeTask(task.id, { branchName });
|
|
170
|
-
return `Deleted branch "${branchName}"`;
|
|
171
|
-
}
|
|
172
|
-
export {
|
|
173
|
-
claimNextTask,
|
|
174
|
-
completeTask,
|
|
175
|
-
createCliTask,
|
|
176
|
-
executeTask,
|
|
177
|
-
failStaleTasks,
|
|
178
|
-
failTask,
|
|
179
|
-
listCliTasks
|
|
180
|
-
};
|
package/dist/db-U6Y3QJDD.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
query
|
|
4
|
-
} from "./chunk-PANC6BTV.js";
|
|
5
|
-
import "./chunk-4YEHSYVN.js";
|
|
6
|
-
|
|
7
|
-
// ../../src/core/git-snapshots.ts
|
|
8
|
-
async function saveGitStatusSnapshot(projectId, data) {
|
|
9
|
-
await query(
|
|
10
|
-
`INSERT INTO git_status_snapshots
|
|
11
|
-
(project_id, branch, branch_line, status, recent_commits, hook_status, worktree_commits, checked_at)
|
|
12
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, now())
|
|
13
|
-
ON CONFLICT (project_id)
|
|
14
|
-
DO UPDATE SET
|
|
15
|
-
branch = $2, branch_line = $3, status = $4,
|
|
16
|
-
recent_commits = $5, hook_status = $6, worktree_commits = $7,
|
|
17
|
-
checked_at = now()`,
|
|
18
|
-
[
|
|
19
|
-
projectId,
|
|
20
|
-
data.branch,
|
|
21
|
-
data.branchLine,
|
|
22
|
-
data.status,
|
|
23
|
-
JSON.stringify(data.recentCommits),
|
|
24
|
-
data.hookStatus ? JSON.stringify(data.hookStatus) : null,
|
|
25
|
-
JSON.stringify(data.worktreeCommits)
|
|
26
|
-
]
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
async function getGitStatusSnapshot(projectId) {
|
|
30
|
-
const rows = await query(
|
|
31
|
-
`SELECT branch, branch_line, status, recent_commits, hook_status,
|
|
32
|
-
worktree_commits, checked_at::text AS checked_at
|
|
33
|
-
FROM git_status_snapshots
|
|
34
|
-
WHERE project_id = $1`,
|
|
35
|
-
[projectId]
|
|
36
|
-
);
|
|
37
|
-
if (rows.length === 0) return null;
|
|
38
|
-
const r = rows[0];
|
|
39
|
-
return {
|
|
40
|
-
branch: r.branch,
|
|
41
|
-
branchLine: r.branch_line,
|
|
42
|
-
status: r.status,
|
|
43
|
-
recentCommits: r.recent_commits,
|
|
44
|
-
hookStatus: r.hook_status,
|
|
45
|
-
worktreeCommits: r.worktree_commits,
|
|
46
|
-
checkedAt: r.checked_at
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
async function saveBranchOverviewSnapshot(projectId, data) {
|
|
50
|
-
await query(
|
|
51
|
-
`INSERT INTO branch_overview_snapshots
|
|
52
|
-
(project_id, default_branch, current_branch, hide_overview, branches, checked_at)
|
|
53
|
-
VALUES ($1, $2, $3, $4, $5, now())
|
|
54
|
-
ON CONFLICT (project_id)
|
|
55
|
-
DO UPDATE SET
|
|
56
|
-
default_branch = $2, current_branch = $3, hide_overview = $4,
|
|
57
|
-
branches = $5, checked_at = now()`,
|
|
58
|
-
[
|
|
59
|
-
projectId,
|
|
60
|
-
data.defaultBranch,
|
|
61
|
-
data.currentBranch,
|
|
62
|
-
data.hideOverview,
|
|
63
|
-
JSON.stringify(data.branches)
|
|
64
|
-
]
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
async function getBranchOverviewSnapshot(projectId) {
|
|
68
|
-
const rows = await query(
|
|
69
|
-
`SELECT default_branch, current_branch, hide_overview, branches,
|
|
70
|
-
checked_at::text AS checked_at
|
|
71
|
-
FROM branch_overview_snapshots
|
|
72
|
-
WHERE project_id = $1`,
|
|
73
|
-
[projectId]
|
|
74
|
-
);
|
|
75
|
-
if (rows.length === 0) return null;
|
|
76
|
-
const r = rows[0];
|
|
77
|
-
return {
|
|
78
|
-
defaultBranch: r.default_branch,
|
|
79
|
-
currentBranch: r.current_branch,
|
|
80
|
-
hideOverview: r.hide_overview,
|
|
81
|
-
branches: r.branches,
|
|
82
|
-
checkedAt: r.checked_at
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
export {
|
|
86
|
-
getBranchOverviewSnapshot,
|
|
87
|
-
getGitStatusSnapshot,
|
|
88
|
-
saveBranchOverviewSnapshot,
|
|
89
|
-
saveGitStatusSnapshot
|
|
90
|
-
};
|
package/dist/health-UFK7YCKQ.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
getProjectPathById
|
|
4
|
-
} from "./chunk-6VMREHG4.js";
|
|
5
|
-
import {
|
|
6
|
-
runGit
|
|
7
|
-
} from "./chunk-FAZ7FCZQ.js";
|
|
8
|
-
import {
|
|
9
|
-
isDbReachable,
|
|
10
|
-
query
|
|
11
|
-
} from "./chunk-PANC6BTV.js";
|
|
12
|
-
import "./chunk-4YEHSYVN.js";
|
|
13
|
-
|
|
14
|
-
// ../../src/core/health.ts
|
|
15
|
-
import { existsSync } from "fs";
|
|
16
|
-
import path from "path";
|
|
17
|
-
var processStartedAt = /* @__PURE__ */ new Date();
|
|
18
|
-
function getDatabaseHost() {
|
|
19
|
-
const raw = process.env.DATABASE_URL;
|
|
20
|
-
if (!raw) return "localhost";
|
|
21
|
-
try {
|
|
22
|
-
const parsed = new URL(raw);
|
|
23
|
-
return parsed.hostname;
|
|
24
|
-
} catch {
|
|
25
|
-
return "unknown";
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
async function getHealthReport(transport) {
|
|
29
|
-
const host = getDatabaseHost();
|
|
30
|
-
const connected = await isDbReachable();
|
|
31
|
-
let projectCount = 0;
|
|
32
|
-
if (connected) {
|
|
33
|
-
try {
|
|
34
|
-
const rows = await query(
|
|
35
|
-
"SELECT count(*)::text AS count FROM projects"
|
|
36
|
-
);
|
|
37
|
-
projectCount = rows.length > 0 ? parseInt(rows[0].count, 10) : 0;
|
|
38
|
-
} catch {
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
const now = /* @__PURE__ */ new Date();
|
|
42
|
-
const uptimeSeconds = Math.floor(
|
|
43
|
-
(now.getTime() - processStartedAt.getTime()) / 1e3
|
|
44
|
-
);
|
|
45
|
-
const status = connected ? "healthy" : "unhealthy";
|
|
46
|
-
return {
|
|
47
|
-
status,
|
|
48
|
-
database: {
|
|
49
|
-
host,
|
|
50
|
-
connected,
|
|
51
|
-
projectCount
|
|
52
|
-
},
|
|
53
|
-
server: {
|
|
54
|
-
startedAt: processStartedAt.toISOString(),
|
|
55
|
-
uptimeSeconds,
|
|
56
|
-
transport
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
var CONDUCTOR_HOOK_MARKER = "# Conductor narration hook";
|
|
61
|
-
async function runProbe(name, fn) {
|
|
62
|
-
const start = performance.now();
|
|
63
|
-
try {
|
|
64
|
-
const result = await fn();
|
|
65
|
-
return { name, ...result, durationMs: Math.round(performance.now() - start) };
|
|
66
|
-
} catch (err) {
|
|
67
|
-
const message = err instanceof Error ? err.message : "Unknown error";
|
|
68
|
-
return {
|
|
69
|
-
name,
|
|
70
|
-
status: "fail",
|
|
71
|
-
message,
|
|
72
|
-
durationMs: Math.round(performance.now() - start)
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
async function getEnvironmentHealthReport(projectId) {
|
|
77
|
-
const reportStart = performance.now();
|
|
78
|
-
const [dbCheck, projectRoot] = await Promise.all([
|
|
79
|
-
runProbe("Database", async () => {
|
|
80
|
-
await query("SELECT 1");
|
|
81
|
-
return { status: "pass", message: "Supabase connected" };
|
|
82
|
-
}),
|
|
83
|
-
getProjectPathById(projectId).catch(() => null)
|
|
84
|
-
]);
|
|
85
|
-
const projectCheck = await runProbe("Project", async () => {
|
|
86
|
-
if (projectRoot) {
|
|
87
|
-
return { status: "pass", message: "Project registered" };
|
|
88
|
-
}
|
|
89
|
-
return {
|
|
90
|
-
status: "fail",
|
|
91
|
-
message: "Project not found in database",
|
|
92
|
-
fixAction: { label: "Register project", href: "/settings" }
|
|
93
|
-
};
|
|
94
|
-
});
|
|
95
|
-
let gitCheck;
|
|
96
|
-
let hookCheck;
|
|
97
|
-
if (projectRoot) {
|
|
98
|
-
[gitCheck, hookCheck] = await Promise.all([
|
|
99
|
-
runProbe("Git", async () => {
|
|
100
|
-
const output = await runGit(projectRoot, ["--version"]);
|
|
101
|
-
const version = output.trim().replace("git version ", "");
|
|
102
|
-
return { status: "pass", message: `Git ${version} found` };
|
|
103
|
-
}),
|
|
104
|
-
runProbe("Hooks", async () => {
|
|
105
|
-
const hookPath = path.join(projectRoot, ".git", "hooks", "post-commit");
|
|
106
|
-
if (!existsSync(hookPath)) {
|
|
107
|
-
return {
|
|
108
|
-
status: "warn",
|
|
109
|
-
message: "Hooks not installed",
|
|
110
|
-
fixAction: { label: "Install hooks", href: "/git" }
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
const { readFile } = await import("fs/promises");
|
|
114
|
-
const content = await readFile(hookPath, "utf-8");
|
|
115
|
-
if (!content.includes(CONDUCTOR_HOOK_MARKER)) {
|
|
116
|
-
return {
|
|
117
|
-
status: "warn",
|
|
118
|
-
message: "Hook file exists but is not a Conductor hook",
|
|
119
|
-
fixAction: { label: "Install hooks", href: "/git" }
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
return { status: "pass", message: "Hooks installed" };
|
|
123
|
-
})
|
|
124
|
-
]);
|
|
125
|
-
} else {
|
|
126
|
-
gitCheck = { name: "Git", status: "warn", message: "Skipped \u2014 no project path", durationMs: 0 };
|
|
127
|
-
hookCheck = { name: "Hooks", status: "warn", message: "Skipped \u2014 no project path", durationMs: 0 };
|
|
128
|
-
}
|
|
129
|
-
const checks = [dbCheck, projectCheck, gitCheck, hookCheck];
|
|
130
|
-
checks.sort((a, b) => {
|
|
131
|
-
const order = { fail: 0, warn: 1, pass: 2 };
|
|
132
|
-
return order[a.status] - order[b.status];
|
|
133
|
-
});
|
|
134
|
-
const hasFail = checks.some((c) => c.status === "fail");
|
|
135
|
-
const hasWarn = checks.some((c) => c.status === "warn");
|
|
136
|
-
const overall = hasFail ? "unhealthy" : hasWarn ? "degraded" : "healthy";
|
|
137
|
-
return {
|
|
138
|
-
checks,
|
|
139
|
-
overall,
|
|
140
|
-
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
141
|
-
totalDurationMs: Math.round(performance.now() - reportStart)
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
export {
|
|
145
|
-
getEnvironmentHealthReport,
|
|
146
|
-
getHealthReport
|
|
147
|
-
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
query
|
|
4
|
-
} from "./chunk-PANC6BTV.js";
|
|
5
|
-
import "./chunk-4YEHSYVN.js";
|
|
6
|
-
|
|
7
|
-
// ../../src/core/health-snapshots.ts
|
|
8
|
-
async function saveHealthSnapshot(projectId, report) {
|
|
9
|
-
await query(
|
|
10
|
-
`INSERT INTO health_snapshots (project_id, checks, overall, checked_at)
|
|
11
|
-
VALUES ($1, $2, $3, $4)
|
|
12
|
-
ON CONFLICT (project_id)
|
|
13
|
-
DO UPDATE SET checks = $2, overall = $3, checked_at = $4`,
|
|
14
|
-
[
|
|
15
|
-
projectId,
|
|
16
|
-
JSON.stringify(report.checks),
|
|
17
|
-
report.overall,
|
|
18
|
-
report.checkedAt
|
|
19
|
-
]
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
async function getHealthSnapshot(projectId) {
|
|
23
|
-
const rows = await query(
|
|
24
|
-
`SELECT checks, overall, checked_at FROM health_snapshots WHERE project_id = $1`,
|
|
25
|
-
[projectId]
|
|
26
|
-
);
|
|
27
|
-
if (rows.length === 0) return null;
|
|
28
|
-
const row = rows[0];
|
|
29
|
-
return {
|
|
30
|
-
checks: row.checks,
|
|
31
|
-
overall: row.overall,
|
|
32
|
-
checkedAt: row.checked_at,
|
|
33
|
-
totalDurationMs: 0
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
export {
|
|
37
|
-
getHealthSnapshot,
|
|
38
|
-
saveHealthSnapshot
|
|
39
|
-
};
|