ghostrail 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/board/page.d.ts.map +1 -1
- package/dist/board/page.js +68 -13
- package/dist/board/page.js.map +1 -1
- package/dist/board/server.d.ts +10 -0
- package/dist/board/server.d.ts.map +1 -1
- package/dist/board/server.js +24 -0
- package/dist/board/server.js.map +1 -1
- package/dist/cli/commands.d.ts +49 -0
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +125 -11
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +7 -0
- package/dist/commands/help.js.map +1 -1
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +19 -0
- package/dist/config/load.js.map +1 -1
- package/dist/config/schema.d.ts +13 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/dashboard/page.d.ts.map +1 -1
- package/dist/dashboard/page.js +104 -9
- package/dist/dashboard/page.js.map +1 -1
- package/dist/dashboard/routes.d.ts +4 -0
- package/dist/dashboard/routes.d.ts.map +1 -1
- package/dist/dashboard/routes.js +4 -0
- package/dist/dashboard/routes.js.map +1 -1
- package/dist/dashboard/server.d.ts +29 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +75 -4
- package/dist/dashboard/server.js.map +1 -1
- package/dist/factory/build.d.ts +6 -0
- package/dist/factory/build.d.ts.map +1 -1
- package/dist/factory/build.js +23 -0
- package/dist/factory/build.js.map +1 -1
- package/dist/loop/next-tick.d.ts +43 -5
- package/dist/loop/next-tick.d.ts.map +1 -1
- package/dist/loop/next-tick.js +68 -18
- package/dist/loop/next-tick.js.map +1 -1
- package/dist/loop/schedule.d.ts +11 -2
- package/dist/loop/schedule.d.ts.map +1 -1
- package/dist/loop/schedule.js +3 -1
- package/dist/loop/schedule.js.map +1 -1
- package/dist/publish/gh.d.ts +43 -2
- package/dist/publish/gh.d.ts.map +1 -1
- package/dist/publish/gh.js +80 -2
- package/dist/publish/gh.js.map +1 -1
- package/dist/publish/githost.d.ts +18 -1
- package/dist/publish/githost.d.ts.map +1 -1
- package/dist/publish/githost.js +13 -0
- package/dist/publish/githost.js.map +1 -1
- package/dist/publish/index.d.ts +1 -1
- package/dist/publish/index.d.ts.map +1 -1
- package/dist/publish/index.js +1 -1
- package/dist/publish/index.js.map +1 -1
- package/dist/release/index.d.ts +2 -0
- package/dist/release/index.d.ts.map +1 -0
- package/dist/release/index.js +2 -0
- package/dist/release/index.js.map +1 -0
- package/dist/release/release.d.ts +67 -0
- package/dist/release/release.d.ts.map +1 -0
- package/dist/release/release.js +193 -0
- package/dist/release/release.js.map +1 -0
- package/dist/respond/ci-fix-queue.d.ts +40 -0
- package/dist/respond/ci-fix-queue.d.ts.map +1 -0
- package/dist/respond/ci-fix-queue.js +74 -0
- package/dist/respond/ci-fix-queue.js.map +1 -0
- package/dist/respond/index.d.ts +2 -1
- package/dist/respond/index.d.ts.map +1 -1
- package/dist/respond/index.js +2 -1
- package/dist/respond/index.js.map +1 -1
- package/dist/respond/merge.d.ts.map +1 -1
- package/dist/respond/merge.js +14 -1
- package/dist/respond/merge.js.map +1 -1
- package/dist/respond/respond.d.ts +26 -1
- package/dist/respond/respond.d.ts.map +1 -1
- package/dist/respond/respond.js +154 -9
- package/dist/respond/respond.js.map +1 -1
- package/package.json +1 -1
- package/skill/ghostrail/SKILL.md +15 -4
- package/templates/code/ghostrail.toml +3 -0
- package/templates/code/prompts/release.md +40 -0
- package/templates/code/prompts/respond.md +2 -1
- package/templates/content/prompts/respond.md +3 -1
package/dist/board/page.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../src/board/page.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,eAAO,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../src/board/page.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,eAAO,MAAM,SAAS,QAgXd,CAAC"}
|
package/dist/board/page.js
CHANGED
|
@@ -20,6 +20,12 @@ export const PAGE_HTML = `<!doctype html>
|
|
|
20
20
|
.row-err { font-size: 12px; color: #b3261e; margin-top: 2px; overflow-wrap: anywhere; }
|
|
21
21
|
.done, .merged, .responded { color: #2a9d3a; } .failed { color: #d33; } .blocked, .abandoned { color: #d90; }
|
|
22
22
|
.noop, .skipped, .closed { opacity: .6; } .muted { opacity: .6; }
|
|
23
|
+
.ci-failed { color: #d33; }
|
|
24
|
+
.fix-ci {
|
|
25
|
+
font: inherit; font-size: .8em; margin-left: .4rem; padding: .05rem .4rem;
|
|
26
|
+
border-radius: 4px; border: 1px solid currentColor; background: none; cursor: pointer;
|
|
27
|
+
}
|
|
28
|
+
.fix-ci:disabled { cursor: default; opacity: .6; }
|
|
23
29
|
a { color: inherit; }
|
|
24
30
|
.twirl {
|
|
25
31
|
background: none; border: none; cursor: pointer; font: inherit; padding: 0 .3rem;
|
|
@@ -52,11 +58,50 @@ const link = (href, label) => '<a href="' + esc(href) + '" ' + NEW_TAB + '>' + l
|
|
|
52
58
|
const expanded = new Set();
|
|
53
59
|
const detailHtml = new Map();
|
|
54
60
|
const prStatusCache = new Map();
|
|
61
|
+
const queuedCi = new Set();
|
|
55
62
|
|
|
56
63
|
function fmtWhen(ts) {
|
|
57
64
|
return ts ? new Date(ts).toLocaleString() : "";
|
|
58
65
|
}
|
|
59
66
|
|
|
67
|
+
// Same rule as publish/githost.ts's hasFailingCheck: at least one check has
|
|
68
|
+
// concluded and did not succeed. Restated here because this inline script
|
|
69
|
+
// cannot import that module.
|
|
70
|
+
function ciFailed(status) {
|
|
71
|
+
return !!(
|
|
72
|
+
status && status.available && status.state === "open" &&
|
|
73
|
+
(status.checks || []).some((c) => c.conclusion && c.conclusion !== "success")
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The summary table's State cell: the live PR status once it resolves to
|
|
78
|
+
// something terminal (e.g. "merged" instead of "done"); otherwise a "done"
|
|
79
|
+
// row with a still-open PR shows "ci-failed" once its live status confirms a
|
|
80
|
+
// failing check; every other row keeps its stored/fallback state.
|
|
81
|
+
function deriveState(r) {
|
|
82
|
+
const status = prStatusCache.get(r.runId);
|
|
83
|
+
if (isTerminalPrStatus(status)) return status.state;
|
|
84
|
+
if (r.state === "done" && r.prNumber !== undefined && ciFailed(status)) {
|
|
85
|
+
return "ci-failed";
|
|
86
|
+
}
|
|
87
|
+
return r.state || ${JSON.stringify(IN_PROGRESS_STATE)};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function queueCiFix(runId, btn) {
|
|
91
|
+
if (queuedCi.has(runId)) return;
|
|
92
|
+
btn.disabled = true;
|
|
93
|
+
try {
|
|
94
|
+
const res = await fetch("api/runs/" + encodeURIComponent(runId) + "/queue-ci-fix", {
|
|
95
|
+
method: "POST",
|
|
96
|
+
});
|
|
97
|
+
if (!res.ok) throw new Error("queue failed");
|
|
98
|
+
queuedCi.add(runId);
|
|
99
|
+
btn.textContent = "queued";
|
|
100
|
+
} catch {
|
|
101
|
+
btn.disabled = false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
60
105
|
function gateStepsHtml(gate) {
|
|
61
106
|
if (!gate || gate.length === 0) return "<div class=muted>no gate steps</div>";
|
|
62
107
|
const rows = gate.map((s) =>
|
|
@@ -186,15 +231,6 @@ function isTerminalPrStatus(status) {
|
|
|
186
231
|
return Boolean(status && status.available && status.state !== "open");
|
|
187
232
|
}
|
|
188
233
|
|
|
189
|
-
// What the summary table's State cell shows: the live PR status once it
|
|
190
|
-
// resolves to something other than "open" (e.g. "merged" instead of "done"),
|
|
191
|
-
// falling back to the run's own state exactly like before.
|
|
192
|
-
function mainLineState(r) {
|
|
193
|
-
const status = prStatusCache.get(r.runId);
|
|
194
|
-
if (isTerminalPrStatus(status)) return status.state;
|
|
195
|
-
return r.state || ${JSON.stringify(IN_PROGRESS_STATE)};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
234
|
function paintDetail(runId) {
|
|
199
235
|
const cell = document.getElementById("detail-" + runId);
|
|
200
236
|
if (cell) cell.innerHTML = detailHtml.get(runId) || "<div class=muted>loading…</div>";
|
|
@@ -234,12 +270,18 @@ function rowHtml(r) {
|
|
|
234
270
|
const when = fmtWhen(r.startedAt);
|
|
235
271
|
const itemLabel = esc(r.title || r.itemId || "");
|
|
236
272
|
const item = (r.url ? link(r.url, itemLabel) : itemLabel) + errLine(r);
|
|
237
|
-
const state =
|
|
273
|
+
const state = deriveState(r);
|
|
274
|
+
const stateLabel = state === "ci-failed" ? "CI failed" : state;
|
|
275
|
+
const fixCi = state === "ci-failed"
|
|
276
|
+
? "<button class='fix-ci' data-run-id='" + esc(r.runId) + "'" +
|
|
277
|
+
(queuedCi.has(r.runId) ? " disabled" : "") + ">" +
|
|
278
|
+
(queuedCi.has(r.runId) ? "queued" : "fix CI") + "</button>"
|
|
279
|
+
: "";
|
|
238
280
|
const main = "<tr class=run-row>" +
|
|
239
281
|
"<td><button class='twirl" + (isOpen ? " open" : "") + "' data-run-id='" + esc(r.runId) + "'>▶</button></td>" +
|
|
240
282
|
"<td class=muted>" + esc(r.runId.slice(0, 8)) + "</td>" +
|
|
241
283
|
"<td>" + item + "</td>" +
|
|
242
|
-
"<td class='state " + state + "'>" +
|
|
284
|
+
"<td class='state " + esc(state) + "'>" + esc(stateLabel) + fixCi + "</td>" +
|
|
243
285
|
"<td>" + esc(r.backend || "") + "</td>" +
|
|
244
286
|
"<td>" + gate + "</td>" +
|
|
245
287
|
"<td>" + pr + "</td>" +
|
|
@@ -252,8 +294,13 @@ function rowHtml(r) {
|
|
|
252
294
|
}
|
|
253
295
|
|
|
254
296
|
document.getElementById("rows").addEventListener("click", (e) => {
|
|
255
|
-
const
|
|
256
|
-
if (
|
|
297
|
+
const twirl = e.target.closest(".twirl");
|
|
298
|
+
if (twirl) {
|
|
299
|
+
toggle(twirl.dataset.runId);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const fixCi = e.target.closest(".fix-ci");
|
|
303
|
+
if (fixCi) queueCiFix(fixCi.dataset.runId, fixCi);
|
|
257
304
|
});
|
|
258
305
|
|
|
259
306
|
const runningBox = document.getElementById("running");
|
|
@@ -308,6 +355,14 @@ async function refresh() {
|
|
|
308
355
|
].map(([k, v]) => '<div class="stat"><b>' + esc(v) + "</b>" + esc(k) + "</div>").join("");
|
|
309
356
|
document.getElementById("rows").innerHTML = runs.map(rowHtml).join("");
|
|
310
357
|
for (const runId of expanded) loadDetail(runId);
|
|
358
|
+
// A collapsed "done" row with an open PR still needs its live status polled,
|
|
359
|
+
// so "CI failed" can show up without expanding anything; an expanded one
|
|
360
|
+
// already gets this via loadDetail above.
|
|
361
|
+
for (const r of runs) {
|
|
362
|
+
if (r.state === "done" && r.prNumber !== undefined && !expanded.has(r.runId)) {
|
|
363
|
+
loadPrStatus(r.runId);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
311
366
|
}
|
|
312
367
|
refresh();
|
|
313
368
|
setInterval(refresh, 5000);
|
package/dist/board/page.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/board/page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,kFAAkF;AAClF,MAAM,CAAC,MAAM,SAAS,GAAG
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/board/page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,kFAAkF;AAClF,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAoFH,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA4R/C,CAAC"}
|
package/dist/board/server.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Server } from "node:http";
|
|
2
2
|
import type { RunControl } from "../loop/control.js";
|
|
3
3
|
import type { PrStatus } from "../publish/githost.js";
|
|
4
|
+
import type { CiFixQueueStore } from "../respond/ci-fix-queue.js";
|
|
4
5
|
import { type RunStore } from "../store/port.js";
|
|
5
6
|
export type Route = {
|
|
6
7
|
kind: "page";
|
|
@@ -15,6 +16,9 @@ export type Route = {
|
|
|
15
16
|
} | {
|
|
16
17
|
kind: "prStatus";
|
|
17
18
|
id: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: "queueCiFix";
|
|
21
|
+
id: string;
|
|
18
22
|
} | {
|
|
19
23
|
kind: "stats";
|
|
20
24
|
} | {
|
|
@@ -51,6 +55,12 @@ export interface BoardOptions {
|
|
|
51
55
|
* say so rather than claim a pause it did not perform.
|
|
52
56
|
*/
|
|
53
57
|
control?: RunControl;
|
|
58
|
+
/**
|
|
59
|
+
* Where a "Fix CI" click queues a PR number for the next respond tick.
|
|
60
|
+
* Without it, `/api/runs/:id/queue-ci-fix` refuses the request rather than
|
|
61
|
+
* claiming a request it cannot actually queue.
|
|
62
|
+
*/
|
|
63
|
+
ciFixQueue?: CiFixQueueStore;
|
|
54
64
|
}
|
|
55
65
|
/** True for an address only this machine can reach, where a token is optional. */
|
|
56
66
|
export declare function isLoopback(bind: string): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,MAAM,EAAqC,MAAM,WAAW,CAAC;AACjG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAkB,KAAK,QAAQ,EAAkB,MAAM,kBAAkB,CAAC;AAIjF,MAAM,MAAM,KAAK,GACb;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC3B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzB,qDAAqD;AACrD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,MAAM,EAAqC,MAAM,WAAW,CAAC;AACjG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAkB,KAAK,QAAQ,EAAkB,MAAM,kBAAkB,CAAC;AAIjF,MAAM,MAAM,KAAK,GACb;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC3B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzB,qDAAqD;AACrD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAyBlD;AAED,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClD;AAuBD,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4FAA4F;IAC5F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oGAAoG;IACpG,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAED,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAQD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAqBrF;AAED,4EAA4E;AAC5E;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG5E"}
|
package/dist/board/server.js
CHANGED
|
@@ -19,6 +19,8 @@ export function parseRoute(pathname) {
|
|
|
19
19
|
return { kind: "events", id };
|
|
20
20
|
if (parts.length === 4 && parts[3] === "pr-status")
|
|
21
21
|
return { kind: "prStatus", id };
|
|
22
|
+
if (parts.length === 4 && parts[3] === "queue-ci-fix")
|
|
23
|
+
return { kind: "queueCiFix", id };
|
|
22
24
|
return { kind: "notfound" };
|
|
23
25
|
}
|
|
24
26
|
if (parts[1] === "stats" && parts.length === 2)
|
|
@@ -167,6 +169,28 @@ async function handle(store, options, req, res) {
|
|
|
167
169
|
}
|
|
168
170
|
return;
|
|
169
171
|
}
|
|
172
|
+
case "queueCiFix": {
|
|
173
|
+
if (req.method !== "POST") {
|
|
174
|
+
sendJson(res, 405, { error: "use POST" });
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const row = await store.getRun(route.id);
|
|
178
|
+
if (row === undefined) {
|
|
179
|
+
sendJson(res, 404, { error: "not found" });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (row.prNumber === undefined) {
|
|
183
|
+
sendJson(res, 404, { error: "no pull request for this run" });
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (options.ciFixQueue === undefined) {
|
|
187
|
+
sendJson(res, 503, { error: "this board cannot queue a CI fix" });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
await options.ciFixQueue.add(row.prNumber);
|
|
191
|
+
sendJson(res, 200, { queued: true });
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
170
194
|
case "stats":
|
|
171
195
|
sendJson(res, 200, computeStats(await store.listRuns()));
|
|
172
196
|
return;
|
package/dist/board/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0D,YAAY,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/board/server.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/commands.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { ExecResult } from "../backend/types.js";
|
|
2
|
+
import type { GhostrailConfig } from "../config/schema.js";
|
|
2
3
|
import { type DoctorDeps } from "../doctor/index.js";
|
|
4
|
+
import { type BuildContext } from "../factory/build.js";
|
|
5
|
+
import { type LoopDeps } from "../loop/engine.js";
|
|
6
|
+
import type { Logger } from "../loop/ports.js";
|
|
3
7
|
import { type ServiceManager } from "../service/index.js";
|
|
4
8
|
import type { Scope } from "../vendor/skilltend/paths.js";
|
|
5
9
|
import { type Asker } from "./prompt.js";
|
|
@@ -20,6 +24,42 @@ export declare function parseCommandFlags(argv: readonly string[], defaults: Com
|
|
|
20
24
|
interface CommandEnv {
|
|
21
25
|
[key: string]: string | undefined;
|
|
22
26
|
}
|
|
27
|
+
interface LoopSetup {
|
|
28
|
+
config: GhostrailConfig;
|
|
29
|
+
deps: LoopDeps;
|
|
30
|
+
secrets: string[];
|
|
31
|
+
/** This repo's state directory, so `watch` reads its pause flag from it. */
|
|
32
|
+
stateDir: string;
|
|
33
|
+
/**
|
|
34
|
+
* The context the loop deps were built from, so `watch` can assemble the
|
|
35
|
+
* respond and triage passes from the same state dir, lock, and credentials
|
|
36
|
+
* instead of redoing the setup (TJ-1664).
|
|
37
|
+
*/
|
|
38
|
+
ctx: BuildContext;
|
|
39
|
+
/**
|
|
40
|
+
* The very logger `deps` were built with. `watch` narrates through this one
|
|
41
|
+
* rather than a second logger of its own, so its lines and the engine's land
|
|
42
|
+
* in the same places (TJ-1682).
|
|
43
|
+
*/
|
|
44
|
+
logger: Logger;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Builds the logger the loop deps get, given the state directory `prepareLoop`
|
|
48
|
+
* resolved and the secrets to redact. Only `watch` overrides it, to persist a
|
|
49
|
+
* copy of every line (see {@link watchLogger}).
|
|
50
|
+
*/
|
|
51
|
+
type LoggerFactory = (stateDir: string, secrets: readonly string[]) => Logger;
|
|
52
|
+
/**
|
|
53
|
+
* Shared setup for the run/watch loops: apply secrets, load the merged config,
|
|
54
|
+
* require the Linear key, and assemble the loop deps. Prints errors and returns
|
|
55
|
+
* undefined on failure.
|
|
56
|
+
*
|
|
57
|
+
* `loggerFor` is the seam TJ-1682 turned on: the logger the deps are built with
|
|
58
|
+
* is decided here, because only here is the state directory known, and a caller
|
|
59
|
+
* that builds its own afterwards cannot reach the engine's narration. Exported
|
|
60
|
+
* so that invariant can be tested directly rather than inferred from a tick.
|
|
61
|
+
*/
|
|
62
|
+
export declare function prepareLoop(flags: CommandFlags, streams: CommandStreams, env: CommandEnv, loggerFor?: LoggerFactory): Promise<LoopSetup | undefined>;
|
|
23
63
|
/** `ghostrail run`: drain eligible work once. */
|
|
24
64
|
export declare function cmdRun(argv: readonly string[], streams: CommandStreams, env?: CommandEnv, cwd?: string): Promise<number>;
|
|
25
65
|
interface WatchFlags {
|
|
@@ -37,6 +77,8 @@ export declare function cmdWatch(argv: readonly string[], streams: CommandStream
|
|
|
37
77
|
export declare function cmdTriage(argv: readonly string[], streams: CommandStreams, env?: CommandEnv, cwd?: string): Promise<number>;
|
|
38
78
|
/** `ghostrail respond`: fold new human PR comments back into their branches. */
|
|
39
79
|
export declare function cmdRespond(argv: readonly string[], streams: CommandStreams, env?: CommandEnv, cwd?: string): Promise<number>;
|
|
80
|
+
/** `ghostrail release`: cut one release now. What "release" means is entirely [release].prompt's business. */
|
|
81
|
+
export declare function cmdRelease(argv: readonly string[], streams: CommandStreams, env?: CommandEnv, cwd?: string): Promise<number>;
|
|
40
82
|
interface BoardFlags {
|
|
41
83
|
repo: string;
|
|
42
84
|
port: number;
|
|
@@ -72,6 +114,13 @@ export declare function cmdArtifacts(argv: readonly string[], streams: CommandSt
|
|
|
72
114
|
export type GhostrailHealth = "ok" | "no config" | "missing";
|
|
73
115
|
/** Check one registered path without trusting the registry's own claims. */
|
|
74
116
|
export declare function ghostrailHealth(path: string): Promise<GhostrailHealth>;
|
|
117
|
+
/**
|
|
118
|
+
* Whether a registered ghostrail has `[release]` configured — the dashboard's
|
|
119
|
+
* gate for showing the release button. False for anything that cannot be
|
|
120
|
+
* read or parsed, the same leniency `ghostrailHealth` already has: a config
|
|
121
|
+
* problem hides the button rather than erroring the whole listing.
|
|
122
|
+
*/
|
|
123
|
+
export declare function releaseEnabledFor(path: string): Promise<boolean>;
|
|
75
124
|
/** `ghostrail ls`: the ghostrails this account knows about. */
|
|
76
125
|
export declare function cmdLs(_argv: readonly string[], streams: CommandStreams, env?: CommandEnv): Promise<number>;
|
|
77
126
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAatD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAO3D,OAAO,EACL,KAAK,UAAU,EAKhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,YAAY,EAOlB,MAAM,qBAAqB,CAAC;AAmD7B,OAAO,EAAE,KAAK,QAAQ,EAAW,MAAM,mBAAmB,CAAC;AAE3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AA4B/C,OAAO,EAGL,KAAK,cAAc,EAOpB,MAAM,qBAAqB,CAAC;AAU7B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAE1D,OAAO,EAAE,KAAK,KAAK,EAAqC,MAAM,aAAa,CAAC;AAG5E,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,YAAY,GAAG,YAAY,CAc/F;AAED,UAAU,UAAU;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC;AAwJD,UAAU,SAAS;IACjB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,GAAG,EAAE,YAAY,CAAC;IAClB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,KAAK,aAAa,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;AAE9E;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,UAAU,EACf,SAAS,GAAE,aAA+D,GACzE,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CA6ChC;AAED,iDAAiD;AACjD,wBAAsB,MAAM,CAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,GAAG,SAAgB,GAClB,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,UAAU,UAAU;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,GAAG,SAAS,CAoB/E;AAkED,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,GAAG,SAAgB,GAClB,OAAO,CAAC,MAAM,CAAC,CA+FjB;AAED,sFAAsF;AACtF,wBAAsB,SAAS,CAC7B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,GAAG,SAAgB,GAClB,OAAO,CAAC,MAAM,CAAC,CA0CjB;AAED,gFAAgF;AAChF,wBAAsB,UAAU,CAC9B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,GAAG,SAAgB,GAClB,OAAO,CAAC,MAAM,CAAC,CA6CjB;AAED,8GAA8G;AAC9G,wBAAsB,UAAU,CAC9B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,GAAG,SAAgB,GAClB,OAAO,CAAC,MAAM,CAAC,CAmCjB;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,YAAY,EAAE,OAAO,CAAC;IACtB,gFAAgF;IAChF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,UAAU,GAAG,UAAU,CAyBzF;AAcD,iFAAiF;AACjF,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,GAAG,SAAgB,GAClB,OAAO,CAAC,MAAM,CAAC,CAqFjB;AAED,2EAA2E;AAC3E,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAiF3C;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,OAAO,GAAE,cAAyD,GACjE,OAAO,CAAC,MAAM,CAAC,CAoDjB;AAED,sFAAsF;AACtF,wBAAsB,YAAY,CAChC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAejB;AAED;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,WAAW,GAAG,SAAS,CAAC;AAE7D,4EAA4E;AAC5E,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAG5E;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUtE;AAED,+DAA+D;AAC/D,wBAAsB,KAAK,CACzB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,GAC5B,OAAO,CAAC,MAAM,CAAC,CA+BjB;AA0ID;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,GAAG,GAAE,KAAqB,EAC1B,KAAK,GAAE,OAAsC,EAC7C,OAAO,GAAE,cAAyD,GACjE,OAAO,CAAC,MAAM,CAAC,CAmKjB;AAED,+EAA+E;AAC/E,wBAAsB,OAAO,CAC3B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,OAAO,GAAE,cAAyD,GACjE,OAAO,CAAC,MAAM,CAAC,CAkDjB;AAED,qFAAqF;AACrF,wBAAsB,SAAS,CAC7B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,OAAO,GAAE,cAAyD,GACjE,OAAO,CAAC,MAAM,CAAC,CA+BjB;AAED,yDAAyD;AACzD,eAAO,MAAM,SAAS,8BAA+B,CAAC;AA4gBtD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,SAAgB,EACnB,GAAG,GAAE,UAAwB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAgLjB;AAwBD,UAAU,UAAU;IAClB,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,EAAE,OAAO,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CA8BnE;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,GAAG,SAAgB,GAClB,OAAO,CAAC,MAAM,CAAC,CAoDjB;AAiBD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,GAAG,SAAgB,EACnB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,UAAU,EACf,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAkEf;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,MAAM,CAAC,CAoEjB;AA0BD,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClD,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACtD,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5D,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjE;AAgED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAoDjB;AAED,4EAA4E;AAC5E,MAAM,WAAW,WAAY,SAAQ,gBAAgB;IACnD,qEAAqE;IACrE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,+CAA+C;IAC/C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iEAAiE;IACjE,GAAG,CAAC,EAAE,KAAK,CAAC;IACZ;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,MAAM,CAAC,CAyBjB;AAwBD,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7E,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,IAAI,GAAE,gBAAqB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAsCjB;AAwED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,cAAc,EACvB,GAAG,GAAE,UAAwB,EAC7B,IAAI,GAAE,UAAe,GACpB,OAAO,CAAC,MAAM,CAAC,CAgCjB"}
|
package/dist/cli/commands.js
CHANGED
|
@@ -12,7 +12,7 @@ import { parseDuration } from "../config/duration.js";
|
|
|
12
12
|
import { parseConfig, parseMergedConfig } from "../config/load.js";
|
|
13
13
|
import { MERGE_TRIGGER_COMMENT, createDashboardServer, defaultStateDir, } from "../dashboard/index.js";
|
|
14
14
|
import { hasFailure, renderDoctorJson, renderDoctorText, runDoctor, } from "../doctor/index.js";
|
|
15
|
-
import { buildLoopDeps, buildRespondDeps, buildTriageDeps, repoGhRunner, resolveRepoSlug, } from "../factory/build.js";
|
|
15
|
+
import { buildLoopDeps, buildReleaseDeps, buildRespondDeps, buildTriageDeps, repoGhRunner, resolveRepoSlug, } from "../factory/build.js";
|
|
16
16
|
import { describeMigration, migrateLegacyStore, resolveWorkRepo, stateDirFor, } from "../factory/state.js";
|
|
17
17
|
import { entryKey, findByPath, findForRepoResolving, replaceEntry, upsert, } from "../global/registry.js";
|
|
18
18
|
import { canonicalRepoId, localRepoId, repoKey } from "../global/repo-id.js";
|
|
@@ -28,12 +28,14 @@ import { concurrencyAdvice } from "../loop/advice.js";
|
|
|
28
28
|
import { fileControl } from "../loop/control.js";
|
|
29
29
|
import { readControl } from "../loop/control.js";
|
|
30
30
|
import { runTick } from "../loop/engine.js";
|
|
31
|
-
import { writeNextTickAt } from "../loop/next-tick.js";
|
|
31
|
+
import { clearTickStarted, markTickStarted, writeNextTickAt } from "../loop/next-tick.js";
|
|
32
32
|
import { duePasses, } from "../loop/schedule.js";
|
|
33
33
|
import { appendLog } from "../loop/tick-log.js";
|
|
34
34
|
import { watchLoop } from "../loop/watch.js";
|
|
35
35
|
import { GhHost, parseRepoSlug } from "../publish/gh.js";
|
|
36
|
+
import { releaseNow, releaseTick, requestRelease } from "../release/release.js";
|
|
36
37
|
import { resolveIgnoredAuthors } from "../respond/authors.js";
|
|
38
|
+
import { FileCiFixQueueStore } from "../respond/ci-fix-queue.js";
|
|
37
39
|
import { respondTick } from "../respond/respond.js";
|
|
38
40
|
import { GLOBAL_SECRETS_FILE, appendPlaceholders, applyOverrides, launchEditor as defaultLaunchEditor, loadEnvOverrides, missingSecrets, readSecretsFile, redactSecrets, renderFile, resolveEditor, secretValuesOf, writeSecretsFile, } from "../secrets/index.js";
|
|
39
41
|
import { DASHBOARD_UNIT, renderDashboardUnit, servicePath, stopTimeoutSeconds, systemdManager, unitName, } from "../service/index.js";
|
|
@@ -187,8 +189,13 @@ async function resolveClaudeProfile(env) {
|
|
|
187
189
|
* Shared setup for the run/watch loops: apply secrets, load the merged config,
|
|
188
190
|
* require the Linear key, and assemble the loop deps. Prints errors and returns
|
|
189
191
|
* undefined on failure.
|
|
192
|
+
*
|
|
193
|
+
* `loggerFor` is the seam TJ-1682 turned on: the logger the deps are built with
|
|
194
|
+
* is decided here, because only here is the state directory known, and a caller
|
|
195
|
+
* that builds its own afterwards cannot reach the engine's narration. Exported
|
|
196
|
+
* so that invariant can be tested directly rather than inferred from a tick.
|
|
190
197
|
*/
|
|
191
|
-
async function prepareLoop(flags, streams, env) {
|
|
198
|
+
export async function prepareLoop(flags, streams, env, loggerFor = (_dir, secrets) => makeLogger(streams, secrets)) {
|
|
192
199
|
const secrets = await applySecrets(flags, env);
|
|
193
200
|
const loaded = await loadConfig(flags, streams, env);
|
|
194
201
|
if (loaded === undefined)
|
|
@@ -212,6 +219,9 @@ async function prepareLoop(flags, streams, env) {
|
|
|
212
219
|
// of one repo running overlapping ticks: while the store lived inside each
|
|
213
220
|
// checkout they took different locks and nothing serialized them.
|
|
214
221
|
const lock = new FileLock(join(state.dir, "lock"), config.guardrails.claimTtlMs);
|
|
222
|
+
// Keyed on the state dir because that is what a persisting logger needs and
|
|
223
|
+
// only `prepareLoop` knows it: the caller cannot build this itself (TJ-1682).
|
|
224
|
+
const logger = loggerFor(state.dir, secrets);
|
|
215
225
|
const ctx = {
|
|
216
226
|
repoPath: flags.repo,
|
|
217
227
|
...(work.path === undefined ? {} : { workRepoPath: work.path }),
|
|
@@ -227,10 +237,10 @@ async function prepareLoop(flags, streams, env) {
|
|
|
227
237
|
...(claudeProfileDir === undefined ? {} : { claudeProfileDir }),
|
|
228
238
|
...(promptSourceDir === undefined ? {} : { promptSourceDir }),
|
|
229
239
|
...(repoSlug === undefined ? {} : { repoSlug }),
|
|
230
|
-
logger
|
|
240
|
+
logger,
|
|
231
241
|
};
|
|
232
242
|
const deps = buildLoopDeps(config, ctx);
|
|
233
|
-
return { config, deps, secrets, stateDir: state.dir, ctx };
|
|
243
|
+
return { config, deps, secrets, stateDir: state.dir, ctx, logger };
|
|
234
244
|
}
|
|
235
245
|
/** `ghostrail run`: drain eligible work once. */
|
|
236
246
|
export async function cmdRun(argv, streams, env = process.env, cwd = process.cwd()) {
|
|
@@ -293,6 +303,10 @@ function schedulablePasses(setup, streams) {
|
|
|
293
303
|
streams.err(`not watching triage: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
294
304
|
}
|
|
295
305
|
}
|
|
306
|
+
if (setup.config.release !== undefined) {
|
|
307
|
+
const { deps, config: releaseConfig } = buildReleaseDeps(setup.config, setup.ctx);
|
|
308
|
+
passes.release = () => releaseTick(deps, releaseConfig);
|
|
309
|
+
}
|
|
296
310
|
return passes;
|
|
297
311
|
}
|
|
298
312
|
/** The intervals for the passes that are actually wired up. */
|
|
@@ -304,11 +318,14 @@ function intervalsOf(config, passes) {
|
|
|
304
318
|
if (passes.triage !== undefined && config.triage?.everyMs !== undefined) {
|
|
305
319
|
intervals.triage = config.triage.everyMs;
|
|
306
320
|
}
|
|
321
|
+
if (passes.release !== undefined) {
|
|
322
|
+
intervals.release = true;
|
|
323
|
+
}
|
|
307
324
|
return intervals;
|
|
308
325
|
}
|
|
309
|
-
/** The ", plus respond
|
|
326
|
+
/** The ", plus respond and triage" tail of the watch banner. */
|
|
310
327
|
function describeSchedule(passes) {
|
|
311
|
-
const extra = ["respond", "triage"].filter((pass) => passes[pass] !== undefined);
|
|
328
|
+
const extra = ["respond", "triage", "release"].filter((pass) => passes[pass] !== undefined);
|
|
312
329
|
return extra.length === 0 ? "" : `, plus ${extra.join(" and ")}`;
|
|
313
330
|
}
|
|
314
331
|
export async function cmdWatch(argv, streams, env = process.env, cwd = process.cwd()) {
|
|
@@ -318,14 +335,26 @@ export async function cmdWatch(argv, streams, env = process.env, cwd = process.c
|
|
|
318
335
|
streams.err('invalid --interval (use e.g. "30s", "5m", "1h")\n');
|
|
319
336
|
return 1;
|
|
320
337
|
}
|
|
321
|
-
|
|
338
|
+
// The persisting logger has to be the one the loop deps are built with, not a
|
|
339
|
+
// second one made afterwards: the engine narrates through `ctx.logger`, and a
|
|
340
|
+
// logger `watch` keeps to itself only ever sees pause, resume, and a thrown
|
|
341
|
+
// tick, which is why the log stayed empty (TJ-1682).
|
|
342
|
+
const setup = await prepareLoop(flags, streams, env, (dir, secrets) => watchLogger(streams, secrets, dir));
|
|
322
343
|
if (setup === undefined)
|
|
323
344
|
return 1;
|
|
324
345
|
const controller = new AbortController();
|
|
325
346
|
const onSignal = () => controller.abort();
|
|
326
347
|
process.once("SIGINT", onSignal);
|
|
327
348
|
process.once("SIGTERM", onSignal);
|
|
328
|
-
const logger =
|
|
349
|
+
const logger = setup.logger;
|
|
350
|
+
// A process killed mid-tick leaves its marker behind; starting up is the one
|
|
351
|
+
// moment we can be certain no tick of ours is running (TJ-1683).
|
|
352
|
+
try {
|
|
353
|
+
await clearTickStarted(setup.stateDir);
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
// Display state only. Never worth refusing to start over.
|
|
357
|
+
}
|
|
329
358
|
const passes = schedulablePasses(setup, streams);
|
|
330
359
|
streams.err(`watching every ${watch.intervalLabel}${describeSchedule(passes)}; press Ctrl-C to stop\n`);
|
|
331
360
|
try {
|
|
@@ -340,6 +369,15 @@ export async function cmdWatch(argv, streams, env = process.env, cwd = process.c
|
|
|
340
369
|
isEnabled: async () => (await readControl(controlDir)).enabled,
|
|
341
370
|
...(watch.maxTicks === undefined ? {} : { maxTicks: watch.maxTicks }),
|
|
342
371
|
tick: async () => {
|
|
372
|
+
// Best-effort and for display only (specs/dashboard-log.spec.md): a
|
|
373
|
+
// tick that outlasts the interval is ordinary here, and without this
|
|
374
|
+
// the countdown reaches zero and has nothing left to say (TJ-1683).
|
|
375
|
+
try {
|
|
376
|
+
await markTickStarted(setup.stateDir, Date.now());
|
|
377
|
+
}
|
|
378
|
+
catch {
|
|
379
|
+
// the countdown is a convenience, not something the loop depends on
|
|
380
|
+
}
|
|
343
381
|
const due = duePasses({
|
|
344
382
|
now: Date.now(),
|
|
345
383
|
intervals: intervalsOf(setup.config, passes),
|
|
@@ -351,7 +389,11 @@ export async function cmdWatch(argv, streams, env = process.env, cwd = process.c
|
|
|
351
389
|
continue;
|
|
352
390
|
try {
|
|
353
391
|
const result = await run();
|
|
354
|
-
streams.out
|
|
392
|
+
// Through the logger, not `streams.out`: this is the most useful
|
|
393
|
+
// line a tick produces, and writing it straight to stdout kept it
|
|
394
|
+
// out of the log the dashboard shows (TJ-1682). `watchLogger`
|
|
395
|
+
// redacts, so this no longer redacts a second time.
|
|
396
|
+
logger.info(`${pass}: ${JSON.stringify(result, null, 2)}`);
|
|
355
397
|
}
|
|
356
398
|
catch (error) {
|
|
357
399
|
// One broken pass must not disable the other two, and must not
|
|
@@ -360,7 +402,8 @@ export async function cmdWatch(argv, streams, env = process.env, cwd = process.c
|
|
|
360
402
|
// an agent-backed pass means spending money in a loop.
|
|
361
403
|
logger.warn(`${pass} pass failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
362
404
|
}
|
|
363
|
-
|
|
405
|
+
// `release` has no interval to stamp (see PassIntervals), same as `fix`.
|
|
406
|
+
if (pass !== "fix" && pass !== "release")
|
|
364
407
|
lastRunAt[pass] = Date.now();
|
|
365
408
|
}
|
|
366
409
|
// Best-effort and for display only (specs/dashboard-log.spec.md): the
|
|
@@ -471,6 +514,43 @@ export async function cmdRespond(argv, streams, env = process.env, cwd = process
|
|
|
471
514
|
streams.out(`${redactSecrets(JSON.stringify(results, null, 2), secrets)}\n`);
|
|
472
515
|
return results.some((r) => r.state === "failed") ? 1 : 0;
|
|
473
516
|
}
|
|
517
|
+
/** `ghostrail release`: cut one release now. What "release" means is entirely [release].prompt's business. */
|
|
518
|
+
export async function cmdRelease(argv, streams, env = process.env, cwd = process.cwd()) {
|
|
519
|
+
const flags = parseCommandFlags(argv, { config: "ghostrail.toml", repo: cwd });
|
|
520
|
+
const secrets = await applySecrets(flags, env);
|
|
521
|
+
const loaded = await loadConfig(flags, streams, env);
|
|
522
|
+
if (loaded === undefined)
|
|
523
|
+
return 1;
|
|
524
|
+
const { config, promptSourceDir } = loaded;
|
|
525
|
+
if (config.release === undefined) {
|
|
526
|
+
streams.err("no [release] section in the config; add one to use `ghostrail release`\n");
|
|
527
|
+
return 1;
|
|
528
|
+
}
|
|
529
|
+
const claudeProfileDir = await resolveClaudeProfile(env);
|
|
530
|
+
const releaseState = await prepareState(flags.repo, config, env, streams);
|
|
531
|
+
const releaseWork = await resolveWorkRepo({
|
|
532
|
+
repoPath: flags.repo,
|
|
533
|
+
stateDir: releaseState.dir,
|
|
534
|
+
config,
|
|
535
|
+
env,
|
|
536
|
+
});
|
|
537
|
+
if (releaseWork.note !== undefined)
|
|
538
|
+
streams.err(`${releaseWork.note}\n`);
|
|
539
|
+
// No LINEAR_API_KEY requirement: a release touches no tracker item.
|
|
540
|
+
const { deps, config: releaseConfig } = buildReleaseDeps(config, {
|
|
541
|
+
repoPath: flags.repo,
|
|
542
|
+
...(releaseWork.path === undefined ? {} : { workRepoPath: releaseWork.path }),
|
|
543
|
+
stateDir: releaseState.dir,
|
|
544
|
+
linearApiKey: env.LINEAR_API_KEY ?? "",
|
|
545
|
+
lock: { acquire: async () => true, release: async () => { } },
|
|
546
|
+
...(claudeProfileDir === undefined ? {} : { claudeProfileDir }),
|
|
547
|
+
...(promptSourceDir === undefined ? {} : { promptSourceDir }),
|
|
548
|
+
logger: makeLogger(streams, secrets),
|
|
549
|
+
});
|
|
550
|
+
const result = await releaseNow(deps, releaseConfig);
|
|
551
|
+
streams.out(`${redactSecrets(JSON.stringify(result, null, 2), secrets)}\n`);
|
|
552
|
+
return result.state === "failed" ? 1 : 0;
|
|
553
|
+
}
|
|
474
554
|
/** Parse `board` flags: `--repo`, `--port`, `--bind`, `--token`. */
|
|
475
555
|
export function parseBoardFlags(argv, defaults) {
|
|
476
556
|
const flags = { ...defaults };
|
|
@@ -546,6 +626,10 @@ export async function cmdBoard(argv, streams, env = process.env, cwd = process.c
|
|
|
546
626
|
bind: flags.bind,
|
|
547
627
|
gitHost,
|
|
548
628
|
control: fileControl(store.dir),
|
|
629
|
+
// Same directory `buildRespondDeps` resolves for this repo and config
|
|
630
|
+
// (`stateDirFor`), so a "Fix CI" click here is what the next
|
|
631
|
+
// `ghostrail respond` tick actually reads.
|
|
632
|
+
ciFixQueue: new FileCiFixQueueStore(join(store.dir, "ci-fix-queue.json")),
|
|
549
633
|
...(flags.token === undefined ? {} : { token: flags.token }),
|
|
550
634
|
...(unauthenticated ? { allowNoToken: true } : {}),
|
|
551
635
|
});
|
|
@@ -636,12 +720,23 @@ function dashboardDeps(env, manager) {
|
|
|
636
720
|
// subprocess. A machine with no `gh` and no credentials still serves the
|
|
637
721
|
// whole dashboard, with PR status reported as unavailable.
|
|
638
722
|
prStatus: async (entry, prNumber) => new GhHost(repoGhRunner(entry.path), await slugFor(entry)).getPrStatus(prNumber),
|
|
723
|
+
// The same directory `buildRespondDeps` resolves for this repo and
|
|
724
|
+
// config, so a "Fix CI" click here is what that ghostrail's next
|
|
725
|
+
// `ghostrail respond` tick actually reads.
|
|
726
|
+
ciFixQueue: async (entry) => new FileCiFixQueueStore(join(await defaultStateDir(entry), "ci-fix-queue.json")),
|
|
639
727
|
// Posts the same trigger comment a human typing "resolve conflicts and
|
|
640
728
|
// merge" by hand would; the next respond pass does the actual work (see
|
|
641
729
|
// specs/dashboard-review-mode.spec.md). A machine with no `gh` and no
|
|
642
730
|
// credentials still serves the whole dashboard; the route just answers
|
|
643
731
|
// 503 rather than failing to start.
|
|
644
732
|
mergeTrigger: async (entry, prNumber) => new GhHost(repoGhRunner(entry.path), await slugFor(entry)).postComment(prNumber, MERGE_TRIGGER_COMMENT),
|
|
733
|
+
releaseEnabled: (path) => releaseEnabledFor(path),
|
|
734
|
+
// Queuing a release is a local file write plus a store event, not a `gh`
|
|
735
|
+
// call, so this never needs the "no credentials" fallback mergeTrigger has.
|
|
736
|
+
releaseTrigger: async (entry) => {
|
|
737
|
+
const dir = await defaultStateDir(entry);
|
|
738
|
+
return requestRelease(dir, new FileStore(dir));
|
|
739
|
+
},
|
|
645
740
|
readRegistry: () => store.readRegistry(),
|
|
646
741
|
writeRegistry: (entries) => store.writeRegistry(entries),
|
|
647
742
|
health: ghostrailHealth,
|
|
@@ -728,6 +823,25 @@ export async function ghostrailHealth(path) {
|
|
|
728
823
|
return "missing";
|
|
729
824
|
return (await resolveConfigPath(path)) !== undefined ? "ok" : "no config";
|
|
730
825
|
}
|
|
826
|
+
/**
|
|
827
|
+
* Whether a registered ghostrail has `[release]` configured — the dashboard's
|
|
828
|
+
* gate for showing the release button. False for anything that cannot be
|
|
829
|
+
* read or parsed, the same leniency `ghostrailHealth` already has: a config
|
|
830
|
+
* problem hides the button rather than erroring the whole listing.
|
|
831
|
+
*/
|
|
832
|
+
export async function releaseEnabledFor(path) {
|
|
833
|
+
const configPath = await resolveConfigPath(path);
|
|
834
|
+
if (configPath === undefined)
|
|
835
|
+
return false;
|
|
836
|
+
try {
|
|
837
|
+
const toml = await readFile(configPath, "utf8");
|
|
838
|
+
const parsed = parseConfig(toml);
|
|
839
|
+
return parsed.ok && parsed.value.release !== undefined;
|
|
840
|
+
}
|
|
841
|
+
catch {
|
|
842
|
+
return false;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
731
845
|
/** `ghostrail ls`: the ghostrails this account knows about. */
|
|
732
846
|
export async function cmdLs(_argv, streams, env = process.env) {
|
|
733
847
|
const store = globalStoreFor(env);
|