@gobing-ai/spur 0.4.1 → 0.4.2
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/.claude-plugin/marketplace.json +1 -1
- package/config/config.global.yaml +4 -2
- package/config/templates/AGENTS.md +1 -1
- package/config/workflows/wrapup-pipeline.yaml +1 -1
- package/package.json +10 -10
- package/plugins/sp/README.md +1 -2
- package/plugins/sp/agents/super-planner.md +5 -6
- package/plugins/sp/commands/dev-review-session.md +2 -1
- package/plugins/sp/commands/dev-runall.md +18 -9
- package/plugins/sp/hooks/context-owner.ts +56 -0
- package/plugins/sp/hooks/context-post-tool.ts +23 -0
- package/plugins/sp/hooks/context-session-start.ts +49 -27
- package/plugins/sp/hooks/context-session-stop.ts +131 -30
- package/plugins/sp/hooks/pi/guard-extension.ts +21 -8
- package/plugins/sp/lib/idea-handoff.generated.mjs +4 -2
- package/plugins/sp/lib/inline-run.generated.mjs +47 -30
- package/plugins/sp/lib/plan-projection.generated.d.mts +19 -0
- package/plugins/sp/lib/plan-projection.generated.mjs +113 -0
- package/plugins/sp/lib/quality-gate.generated.d.mts +0 -12
- package/plugins/sp/lib/quality-gate.generated.mjs +48 -230
- package/plugins/sp/lib/transcript.ts +49 -21
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/roles.md +1 -1
- package/plugins/sp/scripts/batch-plan.mjs +154 -1
- package/plugins/sp/scripts/batch-plan.ts +48 -3
- package/plugins/sp/scripts/inline-run-setup.mjs +24 -13
- package/plugins/sp/scripts/pr-reviewing.mjs +19 -5
- package/plugins/sp/scripts/pr-reviewing.ts +34 -9
- package/plugins/sp/scripts/quality-gate.mjs +25 -207
- package/plugins/sp/scripts/run-summary.mjs +24 -13
- package/plugins/sp/scripts/session-timeline.mjs +26 -25
- package/plugins/sp/scripts/session-timeline.ts +4 -18
- package/plugins/sp/scripts/task-diffstat.mjs +32 -29
- package/plugins/sp/scripts/task-diffstat.ts +34 -34
- package/plugins/sp/skills/indexed-context/SKILL.md +14 -7
- package/plugins/sp/skills/parallel-execution/SKILL.md +2 -2
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +1 -1
- package/plugins/sp/skills/parallel-execution/references/fan-out-patterns.md +2 -2
- package/plugins/sp/skills/pr-reviewing/SKILL.md +7 -3
- package/plugins/sp/skills/session-review/SKILL.md +5 -3
- package/plugins/sp/skills/spur-cli/references/decision.md +9 -2
- package/plugins/sp/skills/spur-cli/references/projects.md +7 -5
- package/plugins/sp/skills/spur-dev/SKILL.md +2 -0
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +27 -0
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +2 -3
- package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +5 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +43 -4
- package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +4 -1
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +13 -11
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +8 -13
- package/spur.js +14261 -2846
- package/web/_astro/{BoardApp.D66k_s_T.js → BoardApp.B3GQZvj8.js} +1 -1
- package/web/_astro/{BoardApp.D6sjAJr_.js → BoardApp.BT7L2kSb.js} +192 -192
- package/web/_astro/TaskDetail.Cxov1_N_.js +1 -0
- package/web/_astro/{arc._BUadrdH.js → arc.vaT7tPOB.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.Dh7xS1Pp.js → architectureDiagram-3BPJPVTR.DRMmTjkN.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.DFDVpfXm.js → blockDiagram-GPEHLZMM.cla0LO_q.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.V7_3_glh.js → c4Diagram-AAUBKEIU.D4YAIBKn.js} +1 -1
- package/web/_astro/channel.D4nG9YLf.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.De1yx7Jz.js → chunk-2J33WTMH.BrSJbMRZ.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.BDhHFuxx.js → chunk-4BX2VUAB.CuLMgKF5.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.DDLkWnmC.js → chunk-55IACEB6.zkvgu54F.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.CwfiLnA7.js → chunk-727SXJPM.DxWkACh8.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.CtGDmUnM.js → chunk-AQP2D5EJ.42XrmIlH.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.BOLjpw73.js → chunk-FMBD7UC4.Bao2wMK9.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.BDhQls6O.js → chunk-ND2GUHAM.BhydojD1.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.76qBynDF.js → chunk-QZHKN3VN.CmZ82g-H.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.N0mpPHT0.js → classDiagram-4FO5ZUOK.Blr83Gt_.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.N0mpPHT0.js → classDiagram-v2-Q7XG4LA2.Blr83Gt_.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CKknFfjB.js → cose-bilkent-S5V4N54A.qmfv0SPn.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.Cw3ZWBAh.js → cynefin-OW5HDTMX.BtELhXPR.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.D3yIKCRD.js → dagre-BM42HDAG.AWmaAvXo.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.D51dO83Z.js → diagram-2AECGRRQ.DdH34KDi.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.Bb-FViDj.js → diagram-5GNKFQAL.BmNPix1k.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.D3mN8S6x.js → diagram-KO2AKTUF.BNQd_Ppo.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.dMMyPcbJ.js → diagram-LMA3HP47.BAPgDi0e.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.AzbvzY4C.js → diagram-OG6HWLK6.DZ4zyLdC.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.BR5I4OZb.js → erDiagram-TEJ5UH35.Q1TySMmw.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.DFqvhGkn.js → flowDiagram-I6XJVG4X.BXhFBicG.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.ByJbhH6J.js → ganttDiagram-6RSMTGT7.vHSgcuo2.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.CInHjQR3.js → gitGraphDiagram-PVQCEYII.Bi1f73C7.js} +1 -1
- package/web/_astro/{index.COh_kBxN.css → index.BhSwN8yY.css} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.Cm0dGVjJ.js → infoDiagram-5YYISTIA.DPvXZEWm.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.C3nOP6Sj.js → ishikawaDiagram-YF4QCWOH.Cz829fsV.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.4IvLa2MW.js → journeyDiagram-JHISSGLW.enRnB9Me.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.DS87Cl-k.js → kanban-definition-UN3LZRKU.DnTNk6d2.js} +1 -1
- package/web/_astro/{linear.MzmRrNER.js → linear.BzGnBwNL.js} +1 -1
- package/web/_astro/{mermaid.core.fK-WNswS.js → mermaid.core.CSbTpIVz.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.BqipOHhY.js → mindmap-definition-RKZ34NQL.DGJDy8zT.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.0nBiPqFG.js → pieDiagram-4H26LBE5.HSPdi5_8.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.Szj7Zpx5.js → quadrantDiagram-W4KKPZXB.6Gv8mz2Y.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.D4UR6TWo.js → requirementDiagram-4Y6WPE33.CnBCtFwa.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.DAE7BdOs.js → sankeyDiagram-5OEKKPKP.5M8VWAu8.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.BP9ZVq25.js → sequenceDiagram-3UESZ5HK.DN41XN-U.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.BQW7mIxk.js → stateDiagram-AJRCARHV.ErOO3W8j.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.PbK4nDih.js → stateDiagram-v2-BHNVJYJU.B_ZHICM-.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.Ci_GvUpo.js → timeline-definition-PNZ67QCA.CWdosr07.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DNw1Y5qx.js → vennDiagram-CIIHVFJN.BHzYjNV5.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.CwlkaaNe.js → wardleyDiagram-YWT4CUSO.h8x4IwPX.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.MI6ZuiH_.js → xychartDiagram-2RQKCTM6.RTapW2X8.js} +1 -1
- package/web/index.html +2 -2
- package/plugins/sp/commands/dev-parallel.md +0 -37
- package/web/_astro/TaskDetail.BynLnMNc.js +0 -1
- package/web/_astro/channel.DZVfto-r.js +0 -1
|
@@ -21,6 +21,25 @@ export declare function buildPhasedPlan(def: unknown): PhasedPlanItem[] | null;
|
|
|
21
21
|
export declare function validatePhaseTable(def: unknown): string[];
|
|
22
22
|
export declare function insertOnEntry(items: PhasedPlanItem[], stateId: string, def: unknown): PhasedPlanItem[];
|
|
23
23
|
export declare function buildBatchPlan(tasks: BatchTask[]): PhasedPlanItem[][];
|
|
24
|
+
export declare interface ScheduleTask {
|
|
25
|
+
wbs: string;
|
|
26
|
+
dependencies?: string[];
|
|
27
|
+
files?: string[];
|
|
28
|
+
}
|
|
29
|
+
export declare interface ScheduleOverlap {
|
|
30
|
+
before: string;
|
|
31
|
+
after: string;
|
|
32
|
+
files: string[];
|
|
33
|
+
}
|
|
34
|
+
export declare interface BatchSchedule {
|
|
35
|
+
order: string[];
|
|
36
|
+
waves: string[][];
|
|
37
|
+
cycle: string[] | null;
|
|
38
|
+
overlaps: ScheduleOverlap[];
|
|
39
|
+
mode: 'sequential' | 'parallel';
|
|
40
|
+
reason: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function scheduleBatch(tasks: ScheduleTask[], opts?: { concurrency?: number }): BatchSchedule;
|
|
24
43
|
export declare function taskPhaseChildren(taskLetter: string, plan: PhasedPlanItem[]): PhasedPlanItem[];
|
|
25
44
|
export declare function hostStatus(
|
|
26
45
|
outcome: 'pending' | 'active' | 'completed' | 'skipped' | 'failed' | 'blocked' | 'unattempted',
|
|
@@ -216,6 +216,118 @@ function buildBatchPlan(tasks) {
|
|
|
216
216
|
}
|
|
217
217
|
return waves;
|
|
218
218
|
}
|
|
219
|
+
var byWbs = (a, b) => a.localeCompare(b, "en", { numeric: true });
|
|
220
|
+
function kahnOrder(nodes, preds) {
|
|
221
|
+
const indegree = new Map(nodes.map((n) => [n, preds.get(n)?.size ?? 0]));
|
|
222
|
+
const succ = new Map(nodes.map((n) => [n, []]));
|
|
223
|
+
for (const [n, ps] of preds)
|
|
224
|
+
for (const p of ps)
|
|
225
|
+
succ.get(p)?.push(n);
|
|
226
|
+
const ready = nodes.filter((n) => indegree.get(n) === 0).sort(byWbs);
|
|
227
|
+
const order = [];
|
|
228
|
+
for (let n = ready.shift();n !== undefined; n = ready.shift()) {
|
|
229
|
+
order.push(n);
|
|
230
|
+
for (const s of succ.get(n) ?? []) {
|
|
231
|
+
const d = (indegree.get(s) ?? 0) - 1;
|
|
232
|
+
indegree.set(s, d);
|
|
233
|
+
if (d === 0) {
|
|
234
|
+
ready.push(s);
|
|
235
|
+
ready.sort(byWbs);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return order;
|
|
240
|
+
}
|
|
241
|
+
function findCycle(remaining, preds) {
|
|
242
|
+
const state = new Map;
|
|
243
|
+
const stack = [];
|
|
244
|
+
const visit = (n) => {
|
|
245
|
+
state.set(n, "visiting");
|
|
246
|
+
stack.push(n);
|
|
247
|
+
for (const p of [...preds.get(n) ?? []].sort(byWbs)) {
|
|
248
|
+
if (!remaining.has(p))
|
|
249
|
+
continue;
|
|
250
|
+
if (state.get(p) === "visiting")
|
|
251
|
+
return [...stack.slice(stack.indexOf(p)), p];
|
|
252
|
+
if (!state.has(p)) {
|
|
253
|
+
const cycle = visit(p);
|
|
254
|
+
if (cycle)
|
|
255
|
+
return cycle;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
stack.pop();
|
|
259
|
+
state.set(n, "done");
|
|
260
|
+
return null;
|
|
261
|
+
};
|
|
262
|
+
for (const n of [...remaining].sort(byWbs)) {
|
|
263
|
+
if (state.has(n))
|
|
264
|
+
continue;
|
|
265
|
+
const cycle = visit(n);
|
|
266
|
+
if (cycle)
|
|
267
|
+
return cycle;
|
|
268
|
+
}
|
|
269
|
+
return [];
|
|
270
|
+
}
|
|
271
|
+
function scheduleBatch(tasks, opts = {}) {
|
|
272
|
+
const byId = new Map;
|
|
273
|
+
for (const t of tasks)
|
|
274
|
+
if (!byId.has(t.wbs))
|
|
275
|
+
byId.set(t.wbs, t);
|
|
276
|
+
const nodes = [...byId.keys()].sort(byWbs);
|
|
277
|
+
const preds = new Map(nodes.map((n) => [n, new Set((byId.get(n)?.dependencies ?? []).filter((d) => byId.has(d)))]));
|
|
278
|
+
const depOrder = kahnOrder(nodes, preds);
|
|
279
|
+
if (depOrder.length < nodes.length) {
|
|
280
|
+
const cycle = findCycle(new Set(nodes.filter((n) => !depOrder.includes(n))), preds);
|
|
281
|
+
return {
|
|
282
|
+
order: [],
|
|
283
|
+
waves: [],
|
|
284
|
+
cycle,
|
|
285
|
+
overlaps: [],
|
|
286
|
+
mode: "sequential",
|
|
287
|
+
reason: `dependency cycle ${cycle.join(" → ")}`
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
const files = new Map(nodes.map((n) => [n, new Set((byId.get(n)?.files ?? []).map(normalizeTaskPath))]));
|
|
291
|
+
const overlaps = [];
|
|
292
|
+
for (let i = 0;i < depOrder.length; i++) {
|
|
293
|
+
const before = depOrder[i];
|
|
294
|
+
const beforeFiles = files.get(before) ?? new Set;
|
|
295
|
+
for (const after of depOrder.slice(i + 1)) {
|
|
296
|
+
const shared = [...beforeFiles].filter((f) => files.get(after)?.has(f)).sort();
|
|
297
|
+
if (shared.length === 0)
|
|
298
|
+
continue;
|
|
299
|
+
overlaps.push({ before, after, files: shared });
|
|
300
|
+
preds.get(after)?.add(before);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const order = kahnOrder(nodes, preds);
|
|
304
|
+
const level = new Map;
|
|
305
|
+
for (const n of order) {
|
|
306
|
+
let l = 0;
|
|
307
|
+
for (const p of preds.get(n) ?? [])
|
|
308
|
+
l = Math.max(l, (level.get(p) ?? 0) + 1);
|
|
309
|
+
level.set(n, l);
|
|
310
|
+
}
|
|
311
|
+
const waves = [];
|
|
312
|
+
for (const n of order) {
|
|
313
|
+
const l = level.get(n) ?? 0;
|
|
314
|
+
waves[l] = [...waves[l] ?? [], n].sort(byWbs);
|
|
315
|
+
}
|
|
316
|
+
const widest = Math.max(0, ...waves.map((w) => w.length));
|
|
317
|
+
const concurrency = opts.concurrency ?? 2;
|
|
318
|
+
let reason = `widest wave holds ${widest} independent tasks`;
|
|
319
|
+
if (nodes.length < 2)
|
|
320
|
+
reason = "fewer than two tasks";
|
|
321
|
+
else if (concurrency < 2)
|
|
322
|
+
reason = "concurrency is 1";
|
|
323
|
+
else if (widest < 2)
|
|
324
|
+
reason = "every wave holds one task (dependency or file-overlap chain)";
|
|
325
|
+
const mode = nodes.length >= 2 && concurrency >= 2 && widest >= 2 ? "parallel" : "sequential";
|
|
326
|
+
return { order, waves, cycle: null, overlaps, mode, reason };
|
|
327
|
+
}
|
|
328
|
+
function normalizeTaskPath(path) {
|
|
329
|
+
return path.trim().replace(/^\.\//, "");
|
|
330
|
+
}
|
|
219
331
|
function taskPhaseChildren(taskLetter, plan) {
|
|
220
332
|
if (!Array.isArray(plan))
|
|
221
333
|
return [];
|
|
@@ -245,6 +357,7 @@ function hostText(item) {
|
|
|
245
357
|
export {
|
|
246
358
|
validatePhaseTable,
|
|
247
359
|
taskPhaseChildren,
|
|
360
|
+
scheduleBatch,
|
|
248
361
|
planLetter,
|
|
249
362
|
planChild,
|
|
250
363
|
insertOnEntry,
|
|
@@ -10,18 +10,6 @@ export declare const LOCKED_PATTERN: RegExp;
|
|
|
10
10
|
export declare const FINDINGS_PATTERN: RegExp;
|
|
11
11
|
export declare const COVERAGE_ROW_PATTERN: RegExp;
|
|
12
12
|
export declare const RECEIPT_SCHEMA_VERSION: 'check-receipt/v1';
|
|
13
|
-
export declare const GATE_LOCK_DIR_ENV: string;
|
|
14
|
-
export declare const GATE_LOCK_POLL_MS_ENV: string;
|
|
15
|
-
export declare const GATE_LOCK_OFF_ENV: string;
|
|
16
|
-
export declare const GATE_LOCK_TOKEN_ENV: string;
|
|
17
|
-
export declare const GATE_LOCK_POLL_MS_DEFAULT: number;
|
|
18
|
-
export declare const GATE_LOCK_MKDIR_HOLD_MS_ENV: string;
|
|
19
|
-
export declare interface GateLock {
|
|
20
|
-
release(): void;
|
|
21
|
-
queueWaitMs: number;
|
|
22
|
-
token: string;
|
|
23
|
-
}
|
|
24
|
-
export declare function acquireGateLock(env: QualityGateEnv, logLine?: (line: string) => void): GateLock;
|
|
25
13
|
export declare interface QualityGateEnv {
|
|
26
14
|
wbs: string;
|
|
27
15
|
qualityGateCmd?: string;
|
|
@@ -17,7 +17,7 @@ var __export = (target, all) => {
|
|
|
17
17
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
18
18
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
19
|
|
|
20
|
-
// node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
20
|
+
// node_modules/.bun/@gobing-ai+ts-utils@0.5.22/node_modules/@gobing-ai/ts-utils/dist/errors.js
|
|
21
21
|
var ErrorCode;
|
|
22
22
|
var init_errors = __esm(() => {
|
|
23
23
|
ErrorCode = {
|
|
@@ -28,7 +28,7 @@ var init_errors = __esm(() => {
|
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
// node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
31
|
+
// node_modules/.bun/@gobing-ai+ts-utils@0.5.22/node_modules/@gobing-ai/ts-utils/dist/api-response.js
|
|
32
32
|
var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
|
|
33
33
|
var init_api_response = __esm(() => {
|
|
34
34
|
init_errors();
|
|
@@ -51,28 +51,18 @@ var init_api_response = __esm(() => {
|
|
|
51
51
|
CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
// node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
54
|
+
// node_modules/.bun/@gobing-ai+ts-utils@0.5.22/node_modules/@gobing-ai/ts-utils/dist/cursor.js
|
|
55
55
|
var init_cursor = () => {};
|
|
56
56
|
|
|
57
|
-
// node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
58
|
-
function getEnvVar(name, fallback) {
|
|
59
|
-
const raw = process.env[name];
|
|
60
|
-
return raw === undefined ? fallback : raw;
|
|
61
|
-
}
|
|
57
|
+
// node_modules/.bun/@gobing-ai+ts-utils@0.5.22/node_modules/@gobing-ai/ts-utils/dist/env.js
|
|
62
58
|
function getEnvVars() {
|
|
63
59
|
return process.env;
|
|
64
60
|
}
|
|
65
|
-
function setEnvVar(name, value) {
|
|
66
|
-
if (value === undefined)
|
|
67
|
-
delete process.env[name];
|
|
68
|
-
else
|
|
69
|
-
process.env[name] = value;
|
|
70
|
-
}
|
|
71
61
|
|
|
72
|
-
// node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
62
|
+
// node_modules/.bun/@gobing-ai+ts-utils@0.5.22/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
|
|
73
63
|
var init_event_severity = () => {};
|
|
74
64
|
|
|
75
|
-
// node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
65
|
+
// node_modules/.bun/@gobing-ai+ts-utils@0.5.22/node_modules/@gobing-ai/ts-utils/dist/index.js
|
|
76
66
|
var init_dist = __esm(() => {
|
|
77
67
|
init_api_response();
|
|
78
68
|
init_cursor();
|
|
@@ -23896,7 +23886,7 @@ var init_dist2 = __esm(() => {
|
|
|
23896
23886
|
$visitAsync = visit.visitAsync;
|
|
23897
23887
|
});
|
|
23898
23888
|
|
|
23899
|
-
// node_modules/.bun/@gobing-ai+ts-db@0.5.
|
|
23889
|
+
// node_modules/.bun/@gobing-ai+ts-db@0.5.22+4e07478ab737d0a0/node_modules/@gobing-ai/ts-db/dist/schema/common.js
|
|
23900
23890
|
function nowTimestamp() {
|
|
23901
23891
|
return Date.now();
|
|
23902
23892
|
}
|
|
@@ -23925,7 +23915,7 @@ var init_common3 = __esm(() => {
|
|
|
23925
23915
|
appendOnlyColumns = buildAppendOnlyColumns();
|
|
23926
23916
|
});
|
|
23927
23917
|
|
|
23928
|
-
// node_modules/.bun/@gobing-ai+ts-db@0.5.
|
|
23918
|
+
// node_modules/.bun/@gobing-ai+ts-db@0.5.22+4e07478ab737d0a0/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
|
|
23929
23919
|
function sqlExpressionToText(value) {
|
|
23930
23920
|
if (typeof value !== "object" || value === null || !("queryChunks" in value)) {
|
|
23931
23921
|
return;
|
|
@@ -23948,7 +23938,7 @@ function getDrizzleTableName(table3) {
|
|
|
23948
23938
|
return String(table3[nameSym]);
|
|
23949
23939
|
}
|
|
23950
23940
|
|
|
23951
|
-
// node_modules/.bun/@gobing-ai+ts-db@0.5.
|
|
23941
|
+
// node_modules/.bun/@gobing-ai+ts-db@0.5.22+4e07478ab737d0a0/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
|
|
23952
23942
|
function quoteIdent(name) {
|
|
23953
23943
|
return `"${name.replace(/"/g, '""')}"`;
|
|
23954
23944
|
}
|
|
@@ -24320,7 +24310,7 @@ var init_drizzle_zod = __esm(() => {
|
|
|
24320
24310
|
};
|
|
24321
24311
|
});
|
|
24322
24312
|
|
|
24323
|
-
// node_modules/.bun/@gobing-ai+ts-db@0.5.
|
|
24313
|
+
// node_modules/.bun/@gobing-ai+ts-db@0.5.22+4e07478ab737d0a0/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
|
|
24324
24314
|
function defineTable(name, columns2) {
|
|
24325
24315
|
const table3 = sqliteTable(name, columns2);
|
|
24326
24316
|
let insert2;
|
|
@@ -24354,7 +24344,7 @@ var init_define_table = __esm(() => {
|
|
|
24354
24344
|
init_ddl();
|
|
24355
24345
|
});
|
|
24356
24346
|
|
|
24357
|
-
// node_modules/.bun/@gobing-ai+ts-db@0.5.
|
|
24347
|
+
// node_modules/.bun/@gobing-ai+ts-db@0.5.22+4e07478ab737d0a0/node_modules/@gobing-ai/ts-db/dist/schema/index.js
|
|
24358
24348
|
var init_schema = __esm(() => {
|
|
24359
24349
|
init_sqlite_core();
|
|
24360
24350
|
init_define_table();
|
|
@@ -24372,16 +24362,14 @@ import {
|
|
|
24372
24362
|
mkdirSync,
|
|
24373
24363
|
mkdtempSync,
|
|
24374
24364
|
openSync,
|
|
24375
|
-
readdirSync,
|
|
24376
24365
|
readFileSync,
|
|
24377
|
-
rmdirSync,
|
|
24378
24366
|
rmSync,
|
|
24379
24367
|
statSync,
|
|
24380
24368
|
unlinkSync,
|
|
24381
24369
|
writeFileSync
|
|
24382
24370
|
} from "node:fs";
|
|
24383
|
-
import {
|
|
24384
|
-
import {
|
|
24371
|
+
import { tmpdir } from "node:os";
|
|
24372
|
+
import { join, resolve } from "node:path";
|
|
24385
24373
|
|
|
24386
24374
|
// packages/app/src/workflow/composition-baseline.ts
|
|
24387
24375
|
function canonicalJsonStringify(obj) {
|
|
@@ -24926,8 +24914,8 @@ var POST_WATERMARK_TABLES = [
|
|
|
24926
24914
|
"history_daily_stats",
|
|
24927
24915
|
"history_board_source_daily"
|
|
24928
24916
|
];
|
|
24929
|
-
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.
|
|
24930
|
-
var HISTORY_IMPORT_SCHEMA_VERSION = "0.5.
|
|
24917
|
+
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.22+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
|
|
24918
|
+
var HISTORY_IMPORT_SCHEMA_VERSION = "0.5.22";
|
|
24931
24919
|
var HISTORY_IMPORT_SCHEMA_SQL = `
|
|
24932
24920
|
CREATE TABLE IF NOT EXISTS history_import_checkpoint (
|
|
24933
24921
|
source TEXT NOT NULL,
|
|
@@ -25054,13 +25042,13 @@ CREATE INDEX IF NOT EXISTS idx_history_skill_call_invocation_kind
|
|
|
25054
25042
|
ON history_skill_call(invocation_kind);
|
|
25055
25043
|
`.trim();
|
|
25056
25044
|
|
|
25057
|
-
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.
|
|
25045
|
+
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.22+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
|
|
25058
25046
|
init_zod();
|
|
25059
25047
|
|
|
25060
|
-
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.
|
|
25048
|
+
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.22+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/mappers.js
|
|
25061
25049
|
init_zod();
|
|
25062
25050
|
|
|
25063
|
-
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.
|
|
25051
|
+
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.22+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
|
|
25064
25052
|
import { createHash } from "node:crypto";
|
|
25065
25053
|
function stableJson(value) {
|
|
25066
25054
|
if (Array.isArray(value)) {
|
|
@@ -25079,7 +25067,7 @@ function sha256Text(text) {
|
|
|
25079
25067
|
return createHash("sha256").update(text, "utf8").digest("hex");
|
|
25080
25068
|
}
|
|
25081
25069
|
|
|
25082
|
-
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.
|
|
25070
|
+
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.22+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/capability.js
|
|
25083
25071
|
function matchCapabilityOrigin(origins, source, canonicalName, observable) {
|
|
25084
25072
|
let candidates = origins.filter((origin2) => origin2.source === source && origin2.skillName === canonicalName);
|
|
25085
25073
|
if (candidates.length === 0)
|
|
@@ -25344,7 +25332,7 @@ function extractNestedExecCommandLiterals(payloadText) {
|
|
|
25344
25332
|
return literals;
|
|
25345
25333
|
}
|
|
25346
25334
|
|
|
25347
|
-
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.
|
|
25335
|
+
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.22+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
|
|
25348
25336
|
var DEFAULT_REDACTION_RULES = [
|
|
25349
25337
|
{
|
|
25350
25338
|
name: "api-key",
|
|
@@ -25386,7 +25374,7 @@ function applyRules(value, rules = DEFAULT_REDACTION_RULES) {
|
|
|
25386
25374
|
return rules.reduce((current, rule) => current.replace(rule.pattern, rule.replacement), value);
|
|
25387
25375
|
}
|
|
25388
25376
|
|
|
25389
|
-
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.
|
|
25377
|
+
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.22+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/mappers.js
|
|
25390
25378
|
var MESSAGE_MAPPER_KEYS = [
|
|
25391
25379
|
"_codexUsageCarrier",
|
|
25392
25380
|
"session_id",
|
|
@@ -27492,7 +27480,7 @@ var GROK_SCHEMA = passthroughSchema;
|
|
|
27492
27480
|
var GEMINI_SCHEMA = passthroughSchema;
|
|
27493
27481
|
var DSH_SCHEMA = passthroughSchema;
|
|
27494
27482
|
|
|
27495
|
-
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.
|
|
27483
|
+
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.22+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
|
|
27496
27484
|
var sourceRecordSchema = exports_external.object({
|
|
27497
27485
|
source_record_id: exports_external.string().min(1),
|
|
27498
27486
|
created_at: exports_external.string().min(1),
|
|
@@ -27596,10 +27584,10 @@ var SOURCE_DEFINITIONS = {
|
|
|
27596
27584
|
openclaw: sourceDefinition("openclaw", "OpenClaw", [".openclaw"], ["*.jsonl"])
|
|
27597
27585
|
};
|
|
27598
27586
|
|
|
27599
|
-
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.
|
|
27587
|
+
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.22+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/jsonl-importer-dao.js
|
|
27600
27588
|
var TYPED_HISTORY_TABLES = ["history_message", "history_tool_call", "history_skill_call"];
|
|
27601
27589
|
var TYPED_IGNORED_KEYS = new Set(["_meta", "split_index", "source_record_id", "_capabilityConflict"]);
|
|
27602
|
-
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.
|
|
27590
|
+
// node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.5.22+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/tables.js
|
|
27603
27591
|
var BOOKKEEPING_HISTORY_TABLES = ["history_import_checkpoint", "history_import_ledger"];
|
|
27604
27592
|
var IMPORTER_OWNED_TABLES = [
|
|
27605
27593
|
...TYPED_HISTORY_TABLES,
|
|
@@ -27713,7 +27701,7 @@ var workflowStatesTable = defineTable("workflow_states", {
|
|
|
27713
27701
|
...standardColumns
|
|
27714
27702
|
});
|
|
27715
27703
|
var workflowStates = workflowStatesTable.table;
|
|
27716
|
-
// node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.5.
|
|
27704
|
+
// node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.5.22+df32fe902834add3/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
|
|
27717
27705
|
var WORKFLOW_ENGINE_SCHEMA_SQL = `
|
|
27718
27706
|
CREATE TABLE IF NOT EXISTS runs (
|
|
27719
27707
|
id TEXT PRIMARY KEY,
|
|
@@ -27812,7 +27800,7 @@ ALTER TABLE runs ADD COLUMN owner_pid INTEGER;
|
|
|
27812
27800
|
ALTER TABLE runs ADD COLUMN interrupt_reason TEXT;
|
|
27813
27801
|
ALTER TABLE runs ADD COLUMN terminal_reason TEXT;
|
|
27814
27802
|
`.trim();
|
|
27815
|
-
// node_modules/.bun/@gobing-ai+ts-rule-engine@0.5.
|
|
27803
|
+
// node_modules/.bun/@gobing-ai+ts-rule-engine@0.5.22+df32fe902834add3/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
|
|
27816
27804
|
var RULE_ENGINE_SCHEMA_SQL = `
|
|
27817
27805
|
CREATE TABLE IF NOT EXISTS rule_runs (
|
|
27818
27806
|
id TEXT PRIMARY KEY,
|
|
@@ -27922,6 +27910,9 @@ var INBOX_MESSAGES_REQUEST_KEY_SCHEMA_SQL = `
|
|
|
27922
27910
|
ALTER TABLE inbox_messages ADD COLUMN request_key TEXT;
|
|
27923
27911
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_inbox_messages_request_key ON inbox_messages (request_key) WHERE request_key IS NOT NULL;
|
|
27924
27912
|
`;
|
|
27913
|
+
var INBOX_MESSAGES_READ_AT_SCHEMA_SQL = `
|
|
27914
|
+
ALTER TABLE inbox_messages ADD COLUMN read_at INTEGER;
|
|
27915
|
+
`;
|
|
27925
27916
|
var QUEUE_JOBS_SCHEMA_SQL = `
|
|
27926
27917
|
CREATE TABLE IF NOT EXISTS queue_jobs (
|
|
27927
27918
|
id TEXT PRIMARY KEY,
|
|
@@ -28934,6 +28925,11 @@ var CLI_MIGRATIONS = [
|
|
|
28934
28925
|
{
|
|
28935
28926
|
id: "0052_spur_cli_decision_logs",
|
|
28936
28927
|
sql: DECISION_LOGS_SCHEMA_SQL
|
|
28928
|
+
},
|
|
28929
|
+
{
|
|
28930
|
+
id: "0053_spur_cli_inbox_messages_read_at",
|
|
28931
|
+
sql: INBOX_MESSAGES_READ_AT_SCHEMA_SQL,
|
|
28932
|
+
addColumnIfMissing: { table: "inbox_messages", column: "read_at" }
|
|
28937
28933
|
}
|
|
28938
28934
|
];
|
|
28939
28935
|
// packages/domain/src/envelope/schema.ts
|
|
@@ -30436,159 +30432,6 @@ function runShellCommand(cmd, cwd, extraEnv) {
|
|
|
30436
30432
|
rmSync(dir, { recursive: true, force: true });
|
|
30437
30433
|
}
|
|
30438
30434
|
}
|
|
30439
|
-
var GATE_LOCK_DIR_ENV = "SPUR_GATE_LOCK_DIR";
|
|
30440
|
-
var GATE_LOCK_POLL_MS_ENV = "SPUR_GATE_LOCK_POLL_MS";
|
|
30441
|
-
var GATE_LOCK_OFF_ENV = "SPUR_GATE_LOCK";
|
|
30442
|
-
var GATE_LOCK_TOKEN_ENV = "SPUR_GATE_LOCK_TOKEN";
|
|
30443
|
-
var GATE_LOCK_POLL_MS_DEFAULT = 5000;
|
|
30444
|
-
var GATE_LOCK_MKDIR_HOLD_MS_ENV = "SPUR_GATE_LOCK_TEST_MKDIR_HOLD_MS";
|
|
30445
|
-
var GATE_LOCK_LOST_RACE_SLEEP_MS = 20;
|
|
30446
|
-
var GATE_LOCK_LOST_RACE_LOG_AT = 250;
|
|
30447
|
-
function gateLockDir() {
|
|
30448
|
-
const raw = getEnvVar(GATE_LOCK_DIR_ENV);
|
|
30449
|
-
return raw !== undefined && raw.length > 0 ? raw : join(homedir(), ".config", "spur", "run", "full-gate.lock");
|
|
30450
|
-
}
|
|
30451
|
-
function gateLockPollMs() {
|
|
30452
|
-
const raw = Number.parseInt(getEnvVar(GATE_LOCK_POLL_MS_ENV) ?? "", 10);
|
|
30453
|
-
return Number.isFinite(raw) && raw > 0 ? raw : GATE_LOCK_POLL_MS_DEFAULT;
|
|
30454
|
-
}
|
|
30455
|
-
function isProcessAlive(pid) {
|
|
30456
|
-
try {
|
|
30457
|
-
process.kill(pid, 0);
|
|
30458
|
-
return true;
|
|
30459
|
-
} catch (error51) {
|
|
30460
|
-
return error51.code !== "ESRCH";
|
|
30461
|
-
}
|
|
30462
|
-
}
|
|
30463
|
-
function readGateLockClaim(dir) {
|
|
30464
|
-
let markers;
|
|
30465
|
-
try {
|
|
30466
|
-
markers = readdirSync(dir).sort();
|
|
30467
|
-
} catch {
|
|
30468
|
-
return null;
|
|
30469
|
-
}
|
|
30470
|
-
for (const marker of markers) {
|
|
30471
|
-
try {
|
|
30472
|
-
const claim = JSON.parse(readFileSync(join(dir, marker), "utf8"));
|
|
30473
|
-
if (typeof claim.pid === "number")
|
|
30474
|
-
return { claim, marker };
|
|
30475
|
-
} catch {
|
|
30476
|
-
const pid = Number.parseInt(/^(\d+)-/.exec(marker)?.[1] ?? "", 10);
|
|
30477
|
-
if (pid > 0) {
|
|
30478
|
-
return { claim: { pid, startedAt: Date.now(), wbs: "?", runId: "?", cwd: "?" }, marker };
|
|
30479
|
-
}
|
|
30480
|
-
}
|
|
30481
|
-
}
|
|
30482
|
-
return null;
|
|
30483
|
-
}
|
|
30484
|
-
function acquireGateLock(env2, logLine = () => {}) {
|
|
30485
|
-
if ((getEnvVar(GATE_LOCK_OFF_ENV) ?? "") === "off") {
|
|
30486
|
-
return { release() {}, queueWaitMs: 0, token: "" };
|
|
30487
|
-
}
|
|
30488
|
-
const dir = gateLockDir();
|
|
30489
|
-
mkdirSync(dirname(dir), { recursive: true });
|
|
30490
|
-
const pollMs = gateLockPollMs();
|
|
30491
|
-
const claim = {
|
|
30492
|
-
pid: process.pid,
|
|
30493
|
-
startedAt: Date.now(),
|
|
30494
|
-
wbs: env2.wbs,
|
|
30495
|
-
runId: receiptRunId(env2),
|
|
30496
|
-
cwd: process.cwd()
|
|
30497
|
-
};
|
|
30498
|
-
const marker = `${process.pid}-${randomUUID()}`;
|
|
30499
|
-
const startedWaitingAt = Date.now();
|
|
30500
|
-
let holderLogged = false;
|
|
30501
|
-
let graceLogged = false;
|
|
30502
|
-
let lostRaces = 0;
|
|
30503
|
-
let lostRaceLogged = false;
|
|
30504
|
-
const mkdirHoldMs = Number.parseInt(getEnvVar(GATE_LOCK_MKDIR_HOLD_MS_ENV) ?? "", 10);
|
|
30505
|
-
for (;; ) {
|
|
30506
|
-
let dirIno = null;
|
|
30507
|
-
try {
|
|
30508
|
-
mkdirSync(dir);
|
|
30509
|
-
dirIno = statSync(dir).ino;
|
|
30510
|
-
if (Number.isFinite(mkdirHoldMs) && mkdirHoldMs > 0)
|
|
30511
|
-
gateSleep(mkdirHoldMs);
|
|
30512
|
-
writeFileSync(join(dir, marker), JSON.stringify(claim), { flag: "wx" });
|
|
30513
|
-
} catch (error51) {
|
|
30514
|
-
const code = error51.code;
|
|
30515
|
-
if (code === "ENOENT" || code === "EINVAL") {
|
|
30516
|
-
lostRaces += 1;
|
|
30517
|
-
if (lostRaces === GATE_LOCK_LOST_RACE_LOG_AT && !lostRaceLogged) {
|
|
30518
|
-
lostRaceLogged = true;
|
|
30519
|
-
logLine(`quality gate lock: still losing the claim race after ${lostRaces} attempts (dir ${dir})
|
|
30520
|
-
`);
|
|
30521
|
-
}
|
|
30522
|
-
gateSleep(GATE_LOCK_LOST_RACE_SLEEP_MS);
|
|
30523
|
-
continue;
|
|
30524
|
-
}
|
|
30525
|
-
if (code !== "EEXIST") {
|
|
30526
|
-
throw error51;
|
|
30527
|
-
}
|
|
30528
|
-
}
|
|
30529
|
-
if (dirIno !== null) {
|
|
30530
|
-
let currentIno = null;
|
|
30531
|
-
let entries = [];
|
|
30532
|
-
try {
|
|
30533
|
-
currentIno = statSync(dir).ino;
|
|
30534
|
-
entries = readdirSync(dir);
|
|
30535
|
-
} catch {}
|
|
30536
|
-
if (currentIno !== dirIno || entries.length !== 1 || entries[0] !== marker) {
|
|
30537
|
-
try {
|
|
30538
|
-
unlinkSync(join(dir, marker));
|
|
30539
|
-
} catch {}
|
|
30540
|
-
lostRaces += 1;
|
|
30541
|
-
gateSleep(GATE_LOCK_LOST_RACE_SLEEP_MS);
|
|
30542
|
-
continue;
|
|
30543
|
-
}
|
|
30544
|
-
return {
|
|
30545
|
-
release() {
|
|
30546
|
-
try {
|
|
30547
|
-
rmSync(join(dir, marker), { force: true });
|
|
30548
|
-
rmdirSync(dir);
|
|
30549
|
-
} catch {}
|
|
30550
|
-
},
|
|
30551
|
-
queueWaitMs: Date.now() - startedWaitingAt,
|
|
30552
|
-
token: marker
|
|
30553
|
-
};
|
|
30554
|
-
}
|
|
30555
|
-
const held = readGateLockClaim(dir);
|
|
30556
|
-
if (held !== null && isProcessAlive(held.claim.pid)) {
|
|
30557
|
-
if (getEnvVar(GATE_LOCK_TOKEN_ENV) === held.marker) {
|
|
30558
|
-
return { release() {}, queueWaitMs: Date.now() - startedWaitingAt, token: held.marker };
|
|
30559
|
-
}
|
|
30560
|
-
if (!holderLogged) {
|
|
30561
|
-
holderLogged = true;
|
|
30562
|
-
logLine(`quality gate lock: waiting for holder (wbs ${held.claim.wbs}, run ${held.claim.runId}, pid ${held.claim.pid}, cwd ${held.claim.cwd}, held ${Date.now() - held.claim.startedAt}ms)
|
|
30563
|
-
`);
|
|
30564
|
-
}
|
|
30565
|
-
} else if (held !== null) {
|
|
30566
|
-
logLine(`quality gate lock: reclaimed stale claim (pid ${held.claim.pid})
|
|
30567
|
-
`);
|
|
30568
|
-
try {
|
|
30569
|
-
unlinkSync(join(dir, held.marker));
|
|
30570
|
-
rmdirSync(dir);
|
|
30571
|
-
} catch {}
|
|
30572
|
-
} else {
|
|
30573
|
-
try {
|
|
30574
|
-
rmdirSync(dir);
|
|
30575
|
-
graceLogged = false;
|
|
30576
|
-
} catch {
|
|
30577
|
-
gateSleep(pollMs);
|
|
30578
|
-
try {
|
|
30579
|
-
rmdirSync(dir);
|
|
30580
|
-
graceLogged = false;
|
|
30581
|
-
} catch {
|
|
30582
|
-
if (!graceLogged) {
|
|
30583
|
-
graceLogged = true;
|
|
30584
|
-
logLine(`quality gate lock: dir has no readable claim and is not empty — waiting
|
|
30585
|
-
`);
|
|
30586
|
-
}
|
|
30587
|
-
}
|
|
30588
|
-
}
|
|
30589
|
-
}
|
|
30590
|
-
}
|
|
30591
|
-
}
|
|
30592
30435
|
function recomputeGateProofFingerprint(cwd, env2) {
|
|
30593
30436
|
const taskSpecPath = env2.taskSpecPath ?? env2.taskFile;
|
|
30594
30437
|
if (!taskSpecPath || taskSpecPath.trim() === "") {
|
|
@@ -30712,44 +30555,27 @@ function runQualityGate(mode, env2, options = {}) {
|
|
|
30712
30555
|
appendFileSync(abs(logFile), probe.output);
|
|
30713
30556
|
rmSync(abs(`${logFile}.probe`), { force: true });
|
|
30714
30557
|
}
|
|
30715
|
-
let queueWaitMs = 0;
|
|
30716
30558
|
let gateRuntimeMs = 0;
|
|
30717
30559
|
if (gateRc === 0) {
|
|
30718
30560
|
const delayMs = retryDelayMs(env2);
|
|
30719
|
-
const
|
|
30561
|
+
const gateRuntimeStartMs = Date.now();
|
|
30562
|
+
for (gateAttempt = 1;gateAttempt <= MAX_GATE_ATTEMPTS; gateAttempt++) {
|
|
30563
|
+
const attemptLogPath = `${logFile}.attempt-${gateAttempt}`;
|
|
30564
|
+
const attempt = runShellCommand(env2.qualityGateCmd ?? "", cwd);
|
|
30565
|
+
writeFileSync(abs(attemptLogPath), attempt.output);
|
|
30566
|
+
const locked = isTransientLock(attempt.output);
|
|
30567
|
+
appendFileSync(abs(logFile), attempt.output);
|
|
30568
|
+
rmSync(abs(attemptLogPath), { force: true });
|
|
30569
|
+
gateRc = attempt.code;
|
|
30570
|
+
if (gateRc === 0 || !locked || gateAttempt >= MAX_GATE_ATTEMPTS)
|
|
30571
|
+
break;
|
|
30572
|
+
const line = retryMessage(gateAttempt);
|
|
30720
30573
|
process.stdout.write(line);
|
|
30721
30574
|
appendFileSync(abs(logFile), line);
|
|
30722
|
-
|
|
30723
|
-
const lock = acquireGateLock(env2, lockLine);
|
|
30724
|
-
queueWaitMs = lock.queueWaitMs;
|
|
30725
|
-
lockLine(`quality gate lock: queueWaitMs=${queueWaitMs}
|
|
30726
|
-
`);
|
|
30727
|
-
const gateRuntimeStartMs = Date.now();
|
|
30728
|
-
const previousToken = getEnvVar(GATE_LOCK_TOKEN_ENV);
|
|
30729
|
-
if (lock.token.length > 0)
|
|
30730
|
-
setEnvVar(GATE_LOCK_TOKEN_ENV, lock.token);
|
|
30731
|
-
try {
|
|
30732
|
-
for (gateAttempt = 1;gateAttempt <= MAX_GATE_ATTEMPTS; gateAttempt++) {
|
|
30733
|
-
const attemptLogPath = `${logFile}.attempt-${gateAttempt}`;
|
|
30734
|
-
const attempt = runShellCommand(env2.qualityGateCmd ?? "", cwd, lock.token.length > 0 ? { [GATE_LOCK_TOKEN_ENV]: lock.token } : undefined);
|
|
30735
|
-
writeFileSync(abs(attemptLogPath), attempt.output);
|
|
30736
|
-
const locked = isTransientLock(attempt.output);
|
|
30737
|
-
appendFileSync(abs(logFile), attempt.output);
|
|
30738
|
-
rmSync(abs(attemptLogPath), { force: true });
|
|
30739
|
-
gateRc = attempt.code;
|
|
30740
|
-
if (gateRc === 0 || !locked || gateAttempt >= MAX_GATE_ATTEMPTS)
|
|
30741
|
-
break;
|
|
30742
|
-
const line = retryMessage(gateAttempt);
|
|
30743
|
-
process.stdout.write(line);
|
|
30744
|
-
appendFileSync(abs(logFile), line);
|
|
30745
|
-
gateSleep(delayMs);
|
|
30746
|
-
}
|
|
30747
|
-
} finally {
|
|
30748
|
-
setEnvVar(GATE_LOCK_TOKEN_ENV, previousToken);
|
|
30749
|
-
lock.release();
|
|
30575
|
+
gateSleep(delayMs);
|
|
30750
30576
|
}
|
|
30751
30577
|
gateRuntimeMs = Date.now() - gateRuntimeStartMs;
|
|
30752
|
-
appendFileSync(abs(logFile), `
|
|
30578
|
+
appendFileSync(abs(logFile), `gate runtime: ${gateRuntimeMs}ms
|
|
30753
30579
|
`);
|
|
30754
30580
|
}
|
|
30755
30581
|
if (gateRc !== 0) {
|
|
@@ -30802,7 +30628,6 @@ function runQualityGate(mode, env2, options = {}) {
|
|
|
30802
30628
|
}
|
|
30803
30629
|
],
|
|
30804
30630
|
completedAt: new Date().toISOString(),
|
|
30805
|
-
queueWaitMs,
|
|
30806
30631
|
gateRuntimeMs
|
|
30807
30632
|
});
|
|
30808
30633
|
writeFileSync(abs(receiptFile), `${JSON.stringify(receipt, null, 2)}
|
|
@@ -30834,19 +30659,12 @@ export {
|
|
|
30834
30659
|
isTransientLock,
|
|
30835
30660
|
extractFindings,
|
|
30836
30661
|
buildReceipt,
|
|
30837
|
-
acquireGateLock,
|
|
30838
30662
|
RETRY_DELAY_MS_ENV,
|
|
30839
30663
|
RETRY_DELAY_MS_DEFAULT,
|
|
30840
30664
|
RECEIPT_SCHEMA_VERSION,
|
|
30841
30665
|
MAX_GATE_ATTEMPTS,
|
|
30842
30666
|
MAX_FINDINGS,
|
|
30843
30667
|
LOCKED_PATTERN,
|
|
30844
|
-
GATE_LOCK_TOKEN_ENV,
|
|
30845
|
-
GATE_LOCK_POLL_MS_ENV,
|
|
30846
|
-
GATE_LOCK_POLL_MS_DEFAULT,
|
|
30847
|
-
GATE_LOCK_OFF_ENV,
|
|
30848
|
-
GATE_LOCK_MKDIR_HOLD_MS_ENV,
|
|
30849
|
-
GATE_LOCK_DIR_ENV,
|
|
30850
30668
|
FINDINGS_PATTERN,
|
|
30851
30669
|
COVERAGE_ROW_PATTERN
|
|
30852
30670
|
};
|