@rsaglobaltech/specgate 0.25.0 → 0.27.1

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.
Files changed (97) hide show
  1. package/CHANGELOG.md +87 -42
  2. package/README.md +6 -0
  3. package/dist/packages/core/src/domain/AgentPrompt.js +12 -0
  4. package/dist/packages/core/src/domain/AgentPrompt.js.map +1 -1
  5. package/dist/packages/core/src/domain/ChangeMeasures.js +198 -0
  6. package/dist/packages/core/src/domain/ChangeMeasures.js.map +1 -0
  7. package/dist/packages/core/src/domain/Clarification.js +5 -0
  8. package/dist/packages/core/src/domain/Clarification.js.map +1 -1
  9. package/dist/packages/core/src/domain/ConventionalCommit.js +73 -0
  10. package/dist/packages/core/src/domain/ConventionalCommit.js.map +1 -0
  11. package/dist/packages/core/src/domain/HarnessConfig.js.map +1 -1
  12. package/dist/packages/core/src/domain/HarnessReport.js +2 -0
  13. package/dist/packages/core/src/domain/HarnessReport.js.map +1 -1
  14. package/dist/packages/core/src/domain/QualityChecks.js +218 -0
  15. package/dist/packages/core/src/domain/QualityChecks.js.map +1 -0
  16. package/dist/packages/core/src/domain/QualitySummary.js +58 -0
  17. package/dist/packages/core/src/domain/QualitySummary.js.map +1 -0
  18. package/dist/packages/core/src/domain/RequirementPlan.js +11 -0
  19. package/dist/packages/core/src/domain/RequirementPlan.js.map +1 -1
  20. package/dist/packages/core/src/domain/Sarif.js +121 -0
  21. package/dist/packages/core/src/domain/Sarif.js.map +1 -0
  22. package/dist/packages/core/src/infrastructure/ChangeWorkspace.js +15 -3
  23. package/dist/packages/core/src/infrastructure/ChangeWorkspace.js.map +1 -1
  24. package/dist/packages/core/src/infrastructure/GitContributionStager.js +1 -1
  25. package/dist/packages/core/src/infrastructure/GitContributionStager.js.map +1 -1
  26. package/dist/packages/core/src/infrastructure/HarnessConfigFile.js +26 -0
  27. package/dist/packages/core/src/infrastructure/HarnessConfigFile.js.map +1 -1
  28. package/dist/packages/core/src/infrastructure/IdsAcrossBranches.js +4 -1
  29. package/dist/packages/core/src/infrastructure/IdsAcrossBranches.js.map +1 -1
  30. package/dist/packages/core/src/infrastructure/QualityBaselineFile.js +67 -0
  31. package/dist/packages/core/src/infrastructure/QualityBaselineFile.js.map +1 -0
  32. package/dist/packages/core/test/unit/rework.test.js +62 -0
  33. package/dist/packages/core/test/unit/rework.test.js.map +1 -0
  34. package/dist/scripts/cli/commands/change/ChangeCommand.js +38 -1
  35. package/dist/scripts/cli/commands/change/ChangeCommand.js.map +1 -1
  36. package/dist/scripts/cli/commands/change/TicketCommand.js +1 -1
  37. package/dist/scripts/cli/commands/change/TicketCommand.js.map +1 -1
  38. package/dist/scripts/cli/commands/harness/RunCommand.js +269 -17
  39. package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
  40. package/dist/scripts/cli/commands/quality/CheckCommand.js +54 -3
  41. package/dist/scripts/cli/commands/quality/CheckCommand.js.map +1 -1
  42. package/dist/scripts/cli/commands/quality/QualityCommand.js +314 -0
  43. package/dist/scripts/cli/commands/quality/QualityCommand.js.map +1 -0
  44. package/dist/scripts/cli/commands/spec/DoneCommand.js +4 -1
  45. package/dist/scripts/cli/commands/spec/DoneCommand.js.map +1 -1
  46. package/dist/scripts/cli/commands/spec/DraftCommand.js +44 -4
  47. package/dist/scripts/cli/commands/spec/DraftCommand.js.map +1 -1
  48. package/dist/scripts/cli/commands/spec/StatusCommand.js +5 -1
  49. package/dist/scripts/cli/commands/spec/StatusCommand.js.map +1 -1
  50. package/dist/scripts/cli/commands/spec/StudioCommand.js +208 -1
  51. package/dist/scripts/cli/commands/spec/StudioCommand.js.map +1 -1
  52. package/dist/scripts/docs/nav.js +13 -2
  53. package/dist/scripts/docs/nav.js.map +1 -1
  54. package/dist/scripts/docs/record-journey.js +1 -0
  55. package/dist/scripts/docs/record-journey.js.map +1 -1
  56. package/dist/scripts/docs/record-terminal.js +18 -0
  57. package/dist/scripts/docs/record-terminal.js.map +1 -1
  58. package/dist/scripts/draft/drafting-guide.js +11 -1
  59. package/dist/scripts/draft/drafting-guide.js.map +1 -1
  60. package/dist/scripts/harness/prompt.js +4 -0
  61. package/dist/scripts/harness/prompt.js.map +1 -1
  62. package/dist/scripts/harness/report.js +13 -0
  63. package/dist/scripts/harness/report.js.map +1 -1
  64. package/dist/scripts/lib/change-review.js +145 -0
  65. package/dist/scripts/lib/change-review.js.map +1 -0
  66. package/dist/scripts/lib/clarification.js +24 -5
  67. package/dist/scripts/lib/clarification.js.map +1 -1
  68. package/dist/scripts/lib/harness-guard.js +18 -0
  69. package/dist/scripts/lib/harness-guard.js.map +1 -1
  70. package/dist/scripts/lib/in-flight.js +17 -11
  71. package/dist/scripts/lib/in-flight.js.map +1 -1
  72. package/dist/scripts/lib/live-model.js +7 -1
  73. package/dist/scripts/lib/live-model.js.map +1 -1
  74. package/dist/scripts/lib/live-page.js +72 -11
  75. package/dist/scripts/lib/live-page.js.map +1 -1
  76. package/dist/scripts/lib/quality-presets.js +378 -0
  77. package/dist/scripts/lib/quality-presets.js.map +1 -0
  78. package/dist/scripts/lib/quality-run.js +579 -0
  79. package/dist/scripts/lib/quality-run.js.map +1 -0
  80. package/dist/scripts/lib/screen-requirements.js +149 -0
  81. package/dist/scripts/lib/screen-requirements.js.map +1 -0
  82. package/dist/scripts/lib/sonar-local.js +308 -0
  83. package/dist/scripts/lib/sonar-local.js.map +1 -0
  84. package/dist/scripts/lib/studio-app-page.js +1023 -0
  85. package/dist/scripts/lib/studio-app-page.js.map +1 -0
  86. package/dist/scripts/lib/studio-app.js +442 -0
  87. package/dist/scripts/lib/studio-app.js.map +1 -0
  88. package/dist/scripts/lib/studio-route.js +996 -0
  89. package/dist/scripts/lib/studio-route.js.map +1 -0
  90. package/dist/scripts/lib/surface.js +11 -0
  91. package/dist/scripts/lib/surface.js.map +1 -1
  92. package/dist/scripts/lib/ticket-keys.js +1 -1
  93. package/dist/scripts/lib/ticket-keys.js.map +1 -1
  94. package/dist/scripts/quality.js +10 -0
  95. package/dist/scripts/quality.js.map +1 -0
  96. package/package.json +1 -1
  97. package/templates/harness/harness.config.yaml.tpl +10 -1
@@ -25,12 +25,13 @@ exports.livePage = livePage;
25
25
  * The script lives inside this template literal: it uses no backticks, no
26
26
  * dollar-brace, and no backslash escapes.
27
27
  */
28
- function livePage(projectName) {
28
+ function livePage(projectName, token = "") {
29
29
  const title = String(projectName).replace(/[&<>"']/g, "");
30
30
  return `<!doctype html>
31
31
  <html lang="en"><head><meta charset="utf-8"/>
32
32
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
33
33
  <title>Harness live — ${title}</title>
34
+ <meta name="specgate-token" content="${String(token).replace(/[^0-9a-f]/g, "")}"/>
34
35
  <style>
35
36
  :root{--bg:#f6f8fa;--panel:#ffffff;--line:#d1d9e0;--soft:#eff2f5;--ink:#1f2328;--muted:#59636e;--faint:#8c959f;
36
37
  --pass:#1a7f37;--fail:#cf222e;--run:#9a6700;--run-bg:#fff8c5;--accent:#0969da;--sel:#ddf4ff;
@@ -65,8 +66,12 @@ function livePage(projectName) {
65
66
  .summary-btn{padding-left:10px;margin-bottom:6px;font-weight:600}
66
67
  .qsec{margin:10px 0 14px} .qsec h2{display:flex;align-items:center;gap:8px;margin:0 0 4px;padding:0 10px;font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}
67
68
  .qsec h2 .count{margin-left:auto;font-weight:400;font-variant-numeric:tabular-nums} .qsec .job{padding-left:10px;align-items:flex-start}
68
- .qsec .job .ic{margin-top:3px} .job small{display:block;font-size:11.5px;color:var(--muted);font-weight:400}
69
+ .qsec .job .ic{margin-top:3px} .job small{display:block;font-size:11.5px;color:var(--muted);font-weight:400;white-space:normal;overflow-wrap:anywhere}
69
70
  .qsec p{margin:2px 10px 6px;font-size:12.5px} .muted{color:var(--muted)}
71
+ form.answer{display:flex;flex-wrap:wrap;gap:6px;margin:2px 10px 10px 30px} form.answer textarea{flex:1 1 100%;font:inherit;font-size:12.5px;padding:6px 8px;border:1px solid var(--line);border-radius:6px;background:var(--panel);color:var(--ink);resize:vertical}
72
+ .oq{margin:4px 10px 12px} .oqh{font-size:12.5px} .oqh b{font-weight:600} .oqt{font-size:13px;margin:2px 0 4px;overflow-wrap:anywhere}
73
+ .oq form.answer{margin:0}
74
+ form.answer button{border:1px solid var(--line);background:var(--soft);border-radius:6px;padding:3px 10px;cursor:pointer;font-size:12.5px} form.answer small{flex:1 1 100%}
70
75
  .now{border:1px solid var(--run);border-radius:6px;padding:4px 0 8px;background:var(--panel)}
71
76
  .kv{display:grid;grid-template-columns:62px minmax(0,1fr);gap:4px 10px;margin:4px 10px 0;font-size:12.5px} .kv dt{color:var(--muted)} .kv dd{margin:0;min-width:0;overflow-wrap:anywhere}
72
77
  .ctx{display:flex;flex-direction:column;gap:3px} .ctx .d{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
@@ -256,6 +261,41 @@ function livePage(projectName) {
256
261
  b.addEventListener("click", function(){ pick(r.req); });
257
262
  return b;
258
263
  }
264
+ /**
265
+ * Answer the agent's question from here (REQ-201): the same write as
266
+ * specgate answer, through studio's one POST, with this page's token.
267
+ */
268
+ function answerForm(q){
269
+ var f = el("form", "answer"), ta = el("textarea"), go = el("button", "", "Answer"), msg = el("small", "muted");
270
+ ta.placeholder = "Your answer to " + q.id; ta.rows = 2; go.type = "submit";
271
+ f.append(ta, go, msg);
272
+ var post = function(body){
273
+ var tok = (document.querySelector('meta[name="specgate-token"]') || {}).content || "";
274
+ return fetch("live/answer", {method:"POST", headers:{"content-type":"application/json", "x-specgate-token":tok}, body:JSON.stringify(body)})
275
+ .then(function(x){ return x.json(); });
276
+ };
277
+ f.addEventListener("submit", function(ev){
278
+ ev.preventDefault();
279
+ if (!ta.value.trim()) return;
280
+ go.disabled = true;
281
+ post({question:q.id, change:q.change === "project" ? undefined : q.change, answer:ta.value}).then(function(r){
282
+ go.disabled = false;
283
+ if (!r.ok) { msg.textContent = r.message || "Not answered."; return; }
284
+ msg.textContent = q.id + " answered; " + r.assumption + " to review" + (r.revise && r.revise.length ? " — revise " + r.revise.join(", ") : "") + ".";
285
+ ta.remove(); go.remove();
286
+ var rv = el("button", "", "Mark reviewed"); rv.type = "button";
287
+ rv.addEventListener("click", function(){
288
+ post({question:q.id, change:q.change === "project" ? undefined : q.change, reviewed:true}).then(function(x){
289
+ msg.textContent = x.ok ? q.id + " reviewed: the specification reflects it." : (x.message || "Not reviewed.");
290
+ if (x.ok) rv.remove();
291
+ });
292
+ });
293
+ f.appendChild(rv);
294
+ }).catch(function(){ go.disabled = false; msg.textContent = "Studio did not answer."; });
295
+ });
296
+ return f;
297
+ }
298
+
259
299
  function block(title, count){
260
300
  var d = el("section", "qsec"), h = el("h2"); h.append(el("span", "", title));
261
301
  if (count !== undefined) h.appendChild(el("span", "count", String(count)));
@@ -299,7 +339,7 @@ function livePage(projectName) {
299
339
  matrix.forEach(function(m){ if (m.status === "Needs Clarification" && !byReq[m.requirement] && !seenB[m.requirement]) { seenB[m.requirement] = 1;
300
340
  need.push({r:{req:m.requirement, title:m.title, state:"idle"}, note:"blocked · needs clarification", st:"idle"}); } });
301
341
  var n1 = block("Needs attention", need.length);
302
- need.forEach(function(x){ n1.appendChild(jobBtn(x.r, sel, x.note, x.st)); });
342
+ need.forEach(function(x){ n1.appendChild(jobBtn(x.r, sel, x.note, x.st)); if (x.st === "question" && x.r.question && x.r.question.id) n1.appendChild(answerForm(x.r.question)); });
303
343
  if (!need.length) n1.appendChild(el("p", "muted", "Nothing failed or blocked."));
304
344
  box.appendChild(n1);
305
345
 
@@ -314,6 +354,26 @@ function livePage(projectName) {
314
354
  if (!next.length) n2.appendChild(el("p", "muted", (model.queue || []).length ? "The queue is done." : "No queue recorded for this run."));
315
355
  box.appendChild(n2);
316
356
 
357
+ // REQ-203: every open question, not only the agent's, answered from here.
358
+ var shown = {};
359
+ need.forEach(function(x){ if (x.r.question && x.r.question.id) shown[x.r.question.change + ":" + x.r.question.id] = 1; });
360
+ var oq = (model.questions && model.questions.open || []).filter(function(q){ return !shown[q.change + ":" + q.id]; });
361
+ var wq = model.questions && model.questions.waitingWithoutQuestion || [];
362
+ var n4 = block("Open questions", oq.length + wq.length);
363
+ oq.forEach(function(q){
364
+ var row = el("div", "oq"), h = el("div", "oqh");
365
+ h.append(el("b", "", q.id), el("span", "muted", " " + (q.change === "project" ? "project" : q.change) + (q.blocks.length ? " · blocks " + q.blocks.join(", ") : "")));
366
+ row.append(h, el("div", "oqt", q.text), answerForm(q));
367
+ n4.appendChild(row);
368
+ });
369
+ wq.forEach(function(r){
370
+ var row = el("div", "oq");
371
+ row.append(el("div", "oqh", r.requirement + " " + (r.title || "")), el("small", "muted", "Needs Clarification with no question: specgate ask " + r.requirement + ' "…"'));
372
+ n4.appendChild(row);
373
+ });
374
+ if (!oq.length && !wq.length) n4.appendChild(el("p", "muted", "Nothing waits for an answer."));
375
+ box.appendChild(n4);
376
+
317
377
  var recent = list.filter(function(r){ return r.state === "pass"; }).sort(function(a, b){ return b.updated - a.updated; }).slice(0, 5);
318
378
  var n3 = block("Finished recently");
319
379
  recent.forEach(function(r){ n3.appendChild(jobBtn(r, sel, dur(r.elapsed) + (r.usage && r.usage.cost !== null ? " · " + usd(r.usage.cost) : ""), "pass")); });
@@ -323,17 +383,18 @@ function livePage(projectName) {
323
383
  }
324
384
 
325
385
  function summary(list){
326
- var p = 0, f = 0, run = 0, first = 0, last = 0;
327
- list.forEach(function(r){ if (r.state === "pass") p++; else if (r.state === "fail" || r.state === "question") f++; else run++;
386
+ var p = 0, f = 0, run = 0, asks = 0, first = 0, last = 0;
387
+ // A question waits for a person: neither a failure nor work in progress (REQ-201).
388
+ list.forEach(function(r){ if (r.state === "pass") p++; else if (r.state === "fail") f++; else if (r.state === "question") asks++; else run++;
328
389
  if (!first || r.started < first) first = r.started; last = Math.max(last, r.state === "running" ? now() : r.updated); });
329
- var state = run ? "running" : f ? "fail" : list.length ? "pass" : "running";
390
+ var state = run ? "running" : f ? "fail" : asks ? "running" : list.length ? "pass" : "running";
330
391
  $("runBadge").className = "badge " + state;
331
- $("runState").textContent = run ? "In progress" : f ? "Failed" : list.length ? "Completed" : "Waiting";
392
+ $("runState").textContent = run ? "In progress" : f ? "Failed" : asks ? "Waiting for an answer" : list.length ? "Completed" : "Waiting";
332
393
  var cur = list.filter(function(r){ return r.state === "running"; })[0];
333
394
  $("runTitle").textContent = cur ? cap(cur.group) + " · " + cur.req + " " + (cur.title || "") : groups(list).map(function(g){ return cap(g.name); }).join(", ") || "Harness run";
334
395
  var box = $("progress"); box.replaceChildren();
335
396
  [["Started", first ? stamp(first) : "—"], ["Duration", first ? dur(last - first) : "—"],
336
- ["Requirements", p + " passed · " + run + " running · " + f + " failed"],
397
+ ["Requirements", p + " passed · " + run + " running · " + f + " failed" + (asks ? " · " + asks + " waiting for an answer" : "")],
337
398
  ["Agent time", dur(list.reduce(function(a, r){ return a + elapsed(r); }, 0))]].concat(model.totals && (model.totals.input || model.totals.output) ? [
338
399
  ["Tokens", kt(model.totals.input + model.totals.cacheRead + model.totals.cacheWrite) + " in · " + kt(model.totals.output) + " out"],
339
400
  ["Cost", usd(model.totals.cost)]] : []).forEach(function(x){
@@ -368,12 +429,12 @@ function livePage(projectName) {
368
429
  ["", "Module", "Requirements", "Passed", "Time"].forEach(function(h, i){ var c = el("span", i >= 3 ? "num" : "", h); head.appendChild(c); });
369
430
  box.appendChild(head);
370
431
  order.forEach(function(g){
371
- var rs = rowsBy[g], pass = 0, fail = 0, run = 0, time = 0;
432
+ var rs = rowsBy[g], pass = 0, fail = 0, run = 0, asked = 0, time = 0;
372
433
  var row = el("div", "mm-row"), bar = el("span", "mm-bar");
373
434
  rs.forEach(function(q){
374
435
  var ev = byReq[q.req], st = ev ? ev.state : (q.status === "Implemented" || q.status === "Verified" || q.status === "Released") ? "pass"
375
436
  : q.status === "Needs Clarification" ? "blocked" : "queued";
376
- if (st === "pass") pass++; else if (st === "fail" || st === "question") fail++; else if (st === "running") run++;
437
+ if (st === "pass") pass++; else if (st === "fail") fail++; else if (st === "running") run++; else if (st === "question") asked++;
377
438
  if (ev) time += elapsed(ev);
378
439
  var seg = el("button", "seg " + st + (sel && sel.req === q.req ? " on" : "")); seg.type = "button";
379
440
  seg.title = q.req + " — " + (q.title || "") + " · " + (ev ? st + " · " + dur(elapsed(ev)) : st);
@@ -381,7 +442,7 @@ function livePage(projectName) {
381
442
  seg.addEventListener("click", function(){ pick(q.req); });
382
443
  bar.appendChild(seg);
383
444
  });
384
- var state = fail ? "fail" : run ? "running" : pass === rs.length ? "pass" : "idle";
445
+ var state = fail ? "fail" : asked ? "question" : run ? "running" : pass === rs.length ? "pass" : "idle";
385
446
  if (fail) row.classList.add("has-fail"); else if (run) row.classList.add("has-run"); else if (state === "idle" && !pass) row.classList.add("queued");
386
447
  row.append(icon(state), el("b", "", cap(g === "spec" ? "" : g)), bar, el("span", "num", pass + "/" + rs.length), el("span", "num muted", time ? dur(time) : pass === rs.length ? "earlier" : "queued"));
387
448
  box.appendChild(row);
@@ -1 +1 @@
1
- {"version":3,"file":"live-page.js","sourceRoot":"","sources":["../../../scripts/lib/live-page.ts"],"names":[],"mappings":";;AAwBA,4BAolBC;AA5mBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAgB,QAAQ,CAAC,WAAmB;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC1D,OAAO;;;wBAGe,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBA+Gb,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eA+dN,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"live-page.js","sourceRoot":"","sources":["../../../scripts/lib/live-page.ts"],"names":[],"mappings":";;AAwBA,4BAipBC;AAzqBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAgB,QAAQ,CAAC,WAAmB,EAAE,KAAK,GAAG,EAAE;IACtD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC1D,OAAO;;;wBAGe,KAAK;uCACU,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAmH9D,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAuhBN,CAAC;AAChB,CAAC"}
@@ -0,0 +1,378 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.IMAGES = void 0;
37
+ exports.detectStacks = detectStacks;
38
+ exports.javaVersion = javaVersion;
39
+ exports.presetYaml = presetYaml;
40
+ exports.withPreset = withPreset;
41
+ const fs = __importStar(require("node:fs"));
42
+ const path = __importStar(require("node:path"));
43
+ /** Images, pinned. Refreshed with the presets, in a release. */
44
+ exports.IMAGES = {
45
+ gitleaks: "ghcr.io/gitleaks/gitleaks:v8.24.3",
46
+ semgrep: "semgrep/semgrep:1.99.0",
47
+ osv: "ghcr.io/google/osv-scanner:v2.0.2",
48
+ node: "node:22",
49
+ };
50
+ const read = (dir, rel) => {
51
+ try {
52
+ return fs.readFileSync(path.join(dir, rel), "utf8");
53
+ }
54
+ catch {
55
+ return "";
56
+ }
57
+ };
58
+ /** The stacks a project's build files give away, in the order presets are written. */
59
+ function detectStacks(projectDir) {
60
+ const has = (rel) => fs.existsSync(path.join(projectDir, rel));
61
+ const out = [];
62
+ if (has("pom.xml"))
63
+ out.push("maven");
64
+ if (has("build.gradle") || has("build.gradle.kts"))
65
+ out.push("gradle");
66
+ if (has("package.json"))
67
+ out.push("node");
68
+ return out;
69
+ }
70
+ /** The JDK a Java build declares (release, source or java.version), 21 when it says none. */
71
+ function javaVersion(projectDir) {
72
+ const text = `${read(projectDir, "pom.xml")}\n${read(projectDir, "build.gradle")}\n${read(projectDir, "build.gradle.kts")}`;
73
+ const m = /<maven\.compiler\.(?:release|source)>(\d+)</.exec(text) ||
74
+ /<java\.version>(\d+)</.exec(text) ||
75
+ /languageVersion\s*(?:=|\.set\()\s*JavaLanguageVersion\.of\((\d+)\)/.exec(text) ||
76
+ /sourceCompatibility\s*=\s*(?:JavaVersion\.VERSION_)?['"]?(\d+)/.exec(text);
77
+ const v = m ? Number(m[1]) : 21;
78
+ return [17, 21, 25].includes(v) ? v : v < 17 ? 17 : 21;
79
+ }
80
+ /** The lockfile and how to install in a node container. */
81
+ function nodeInstall(projectDir) {
82
+ const has = (rel) => fs.existsSync(path.join(projectDir, rel));
83
+ if (has("pnpm-lock.yaml"))
84
+ return {
85
+ lock: "pnpm-lock.yaml",
86
+ install: "corepack enable && pnpm install --frozen-lockfile --reporter=silent",
87
+ };
88
+ if (has("yarn.lock"))
89
+ return {
90
+ lock: "yarn.lock",
91
+ install: "corepack enable && yarn install --frozen-lockfile --silent",
92
+ };
93
+ return { lock: "package-lock.json", install: "npm ci --no-audit --no-fund --silent" };
94
+ }
95
+ const q = (s) => JSON.stringify(s);
96
+ function render(c) {
97
+ const lines = [
98
+ ` - name: ${c.name}`,
99
+ ` run: ${q(c.run)}`,
100
+ ` when: ${c.when}`,
101
+ ...(c.gate === false ? [" gate: false"] : []),
102
+ " runner: docker",
103
+ ` image: ${c.image}`,
104
+ ...(c.network === false ? [" network: false"] : []),
105
+ ...(c.volumes && c.volumes.length ? [` volumes: [${c.volumes.join(", ")}]`] : []),
106
+ ...(c.sarif ? [` sarif: ${c.sarif}`] : []),
107
+ ...(c.report ? [` report: ${c.report}`] : []),
108
+ ...(c.scope ? [` scope: ${c.scope}`] : []),
109
+ ...(c.timeout ? [` timeout: ${c.timeout}`] : []),
110
+ ];
111
+ return c.missing ? [` # ${c.missing}`, ...lines.map((l) => ` #${l.slice(1)}`)] : lines;
112
+ }
113
+ /** The secrets and dependency checks every stack shares. */
114
+ function shared(projectDir, level, depsLock) {
115
+ // osv-scanner reads a lockfile (or pom.xml); without one it finds nothing to
116
+ // scan and writes no SARIF, so the check would fail on every run.
117
+ const lockMissing = !fs.existsSync(path.join(projectDir, depsLock))
118
+ ? `Dependencies need ${depsLock}, which this project does not have yet; once it does, uncomment:`
119
+ : undefined;
120
+ return [
121
+ {
122
+ name: "secrets",
123
+ run: "gitleaks dir . --no-banner --report-format sarif --report-path .specgate/quality/gitleaks.sarif",
124
+ when: "attempt",
125
+ image: exports.IMAGES.gitleaks,
126
+ network: false,
127
+ sarif: ".specgate/quality/gitleaks.sarif",
128
+ },
129
+ {
130
+ name: "dependencies",
131
+ run: `/osv-scanner scan source -L ${depsLock} --format sarif --output .specgate/quality/osv.sarif`,
132
+ when: level === "strict" ? "attempt" : "end",
133
+ image: exports.IMAGES.osv,
134
+ sarif: ".specgate/quality/osv.sarif",
135
+ scope: "all",
136
+ missing: lockMissing,
137
+ },
138
+ ];
139
+ }
140
+ function maven(projectDir, level) {
141
+ const pom = read(projectDir, "pom.xml");
142
+ const image = `maven:3.9-eclipse-temurin-${javaVersion(projectDir)}`;
143
+ const m2 = ["specgate-m2:/root/.m2"];
144
+ const mvn = "mvn -B -q";
145
+ const checks = [
146
+ ...shared(projectDir, level, "pom.xml"),
147
+ {
148
+ name: "coverage",
149
+ run: `${mvn} org.jacoco:jacoco-maven-plugin:0.8.12:prepare-agent test org.jacoco:jacoco-maven-plugin:0.8.12:report`,
150
+ when: "attempt",
151
+ image,
152
+ volumes: m2,
153
+ report: "jacoco:target/site/jacoco/jacoco.xml",
154
+ timeout: 1800,
155
+ },
156
+ {
157
+ name: "spotbugs",
158
+ run: `${mvn} compile com.github.spotbugs:spotbugs-maven-plugin:4.8.6.6:spotbugs -Dspotbugs.sarifOutput=true`,
159
+ when: level === "strict" ? "attempt" : "end",
160
+ image,
161
+ volumes: m2,
162
+ sarif: "target/spotbugsSarif.json",
163
+ },
164
+ ];
165
+ if (level === "strict") {
166
+ checks.push({
167
+ name: "pmd",
168
+ run: `${mvn} org.apache.maven.plugins:maven-pmd-plugin:3.26.0:pmd -Dformat=net.sourceforge.pmd.renderers.SarifRenderer -DlinkXRef=false`,
169
+ when: "attempt",
170
+ image,
171
+ volumes: m2,
172
+ sarif: "target/pmd.sarif.json",
173
+ }, {
174
+ name: "semgrep",
175
+ run: "semgrep scan --config p/java --sarif --output .specgate/quality/semgrep.sarif --metrics off --quiet",
176
+ when: "end",
177
+ image: exports.IMAGES.semgrep,
178
+ sarif: ".specgate/quality/semgrep.sarif",
179
+ }, {
180
+ name: "mutation",
181
+ run: `${mvn} test-compile org.pitest:pitest-maven:mutationCoverage -DtargetClasses={changed_classes} -DoutputFormats=XML -DtimestampedReports=false`,
182
+ when: "end",
183
+ image,
184
+ volumes: m2,
185
+ report: "pit:target/pit-reports/mutations.xml",
186
+ timeout: 3600,
187
+ missing: /pitest-maven/.test(pom)
188
+ ? undefined
189
+ : "Mutation needs pitest-maven with pitest-junit5-plugin declared in pom.xml (JUnit 5 cannot be added from the command line); add them and uncomment:",
190
+ });
191
+ }
192
+ return checks;
193
+ }
194
+ function gradle(projectDir, level) {
195
+ const build = `${read(projectDir, "build.gradle")}\n${read(projectDir, "build.gradle.kts")}`;
196
+ // osv-scanner reads Gradle's lockfile, not the build script: dependency locking must be on.
197
+ const lock = "gradle.lockfile";
198
+ const image = `gradle:8-jdk${javaVersion(projectDir)}`;
199
+ const cache = ["specgate-gradle:/home/gradle/.gradle"];
200
+ const checks = [
201
+ ...shared(projectDir, level, lock),
202
+ {
203
+ name: "coverage",
204
+ run: "gradle --no-daemon -q test jacocoTestReport",
205
+ when: "attempt",
206
+ image,
207
+ volumes: cache,
208
+ report: "jacoco:build/reports/jacoco/test/jacocoTestReport.xml",
209
+ timeout: 1800,
210
+ missing: /\bjacoco\b/.test(build)
211
+ ? undefined
212
+ : "Coverage needs the jacoco plugin applied, with reports { xml.required = true }; add it and uncomment:",
213
+ },
214
+ ];
215
+ if (level === "strict") {
216
+ checks.push({
217
+ name: "semgrep",
218
+ run: "semgrep scan --config p/java --sarif --output .specgate/quality/semgrep.sarif --metrics off --quiet",
219
+ when: "end",
220
+ image: exports.IMAGES.semgrep,
221
+ sarif: ".specgate/quality/semgrep.sarif",
222
+ });
223
+ }
224
+ return checks;
225
+ }
226
+ function node(projectDir, level) {
227
+ let pkg = {};
228
+ try {
229
+ pkg = JSON.parse(read(projectDir, "package.json") || "{}");
230
+ }
231
+ catch {
232
+ pkg = {};
233
+ }
234
+ const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
235
+ const { lock, install } = nodeInstall(projectDir);
236
+ const slug = path
237
+ .basename(projectDir)
238
+ .toLowerCase()
239
+ .replace(/[^a-z0-9]+/g, "-")
240
+ .replace(/^-|-$/g, "") || "project";
241
+ // node_modules lives in a volume: the host's may hold another platform's binaries.
242
+ const volumes = [`specgate-nm-${slug}:/src/node_modules`, "specgate-npm:/root/.npm"];
243
+ const inNode = (cmd) => `${install} && ${cmd}`;
244
+ const tsconfig = fs.existsSync(path.join(projectDir, "tsconfig.json"));
245
+ const runner = deps.vitest ? "vitest" : deps.jest ? "jest" : "";
246
+ const checks = [...shared(projectDir, level, lock)];
247
+ if (tsconfig) {
248
+ checks.push({
249
+ name: "types",
250
+ run: inNode("npx --no-install tsc --noEmit"),
251
+ when: "attempt",
252
+ image: exports.IMAGES.node,
253
+ volumes,
254
+ });
255
+ }
256
+ if (deps.eslint) {
257
+ checks.push({
258
+ name: "lint",
259
+ run: inNode("npx --no-install eslint ."),
260
+ when: "attempt",
261
+ image: exports.IMAGES.node,
262
+ volumes,
263
+ });
264
+ }
265
+ checks.push({
266
+ name: "coverage",
267
+ run: inNode(runner === "jest"
268
+ ? "npx --no-install jest --coverage --coverageReporters=lcov"
269
+ : "npx --no-install vitest run --coverage --coverage.reporter=lcov"),
270
+ when: "attempt",
271
+ image: exports.IMAGES.node,
272
+ volumes,
273
+ report: "lcov:coverage/lcov.info",
274
+ timeout: 1800,
275
+ missing: runner
276
+ ? runner === "vitest" && !deps["@vitest/coverage-v8"] && !deps["@vitest/coverage-istanbul"]
277
+ ? "Coverage needs @vitest/coverage-v8 in devDependencies; add it and uncomment:"
278
+ : undefined
279
+ : "Coverage needs Vitest or Jest; with one installed, uncomment:",
280
+ });
281
+ if (level === "strict") {
282
+ checks.push({
283
+ name: "semgrep",
284
+ run: "semgrep scan --config p/typescript --config p/react --sarif --output .specgate/quality/semgrep.sarif --metrics off --quiet",
285
+ when: "end",
286
+ image: exports.IMAGES.semgrep,
287
+ sarif: ".specgate/quality/semgrep.sarif",
288
+ }, {
289
+ name: "mutation",
290
+ run: inNode("npx --no-install stryker run --mutate {changed_src} --reporters json"),
291
+ when: "end",
292
+ image: exports.IMAGES.node,
293
+ volumes,
294
+ report: "stryker:reports/mutation/mutation.json",
295
+ timeout: 3600,
296
+ missing: deps["@stryker-mutator/core"]
297
+ ? undefined
298
+ : "Mutation needs @stryker-mutator/core and its runner in devDependencies; add them and uncomment:",
299
+ });
300
+ }
301
+ return checks;
302
+ }
303
+ /** The `quality:` block a level writes for a project, as YAML lines. */
304
+ function presetYaml(projectDir, level) {
305
+ const stacks = detectStacks(projectDir);
306
+ const lines = [
307
+ "# Quality and security checks (ADR-0040), written by `specgate quality init`.",
308
+ "# Every check runs in Docker, with tools that need no account. Take the",
309
+ "# baseline once (`specgate quality baseline`) so only new findings fail.",
310
+ `quality: ${level}`,
311
+ "checks:",
312
+ // REQ-234: Specgate checks this itself — no tool, so no container either.
313
+ " - name: commits",
314
+ ' run: "builtin:commits"',
315
+ " when: attempt",
316
+ " runner: local",
317
+ ];
318
+ const sonar = [
319
+ " # SonarQube Community in Docker (REQ-226): starts a local server on first use",
320
+ " # (about 2 GB of memory) at http://127.0.0.1:9123, login admin/admin. Uncomment:",
321
+ " # - name: sonar",
322
+ ' # run: "builtin:sonar"',
323
+ " # when: end",
324
+ " # runner: docker",
325
+ " # sarif: .specgate/quality/sonar.sarif",
326
+ " # timeout: 1800",
327
+ // REQ-227: a second agent reads the change against the requirement; it advises.
328
+ " - name: review",
329
+ ' run: "builtin:review"',
330
+ " when: end",
331
+ " gate: false",
332
+ " runner: local",
333
+ ];
334
+ const seen = new Set(["commits"]);
335
+ for (const stack of stacks.length ? stacks : ["node"]) {
336
+ const checks = stack === "maven"
337
+ ? maven(projectDir, level)
338
+ : stack === "gradle"
339
+ ? gradle(projectDir, level)
340
+ : node(projectDir, level);
341
+ for (const c of checks) {
342
+ // One secrets scan for the whole repository; per-stack checks get the stack's name.
343
+ const name = seen.has(c.name) ? `${c.name}-${stack}` : c.name;
344
+ if (seen.has(c.name) && (c.name === "secrets" || c.name === "semgrep"))
345
+ continue;
346
+ seen.add(name);
347
+ lines.push(...render({ ...c, name }));
348
+ }
349
+ }
350
+ if (level === "strict")
351
+ lines.push(...sonar);
352
+ return lines.join("\n") + "\n";
353
+ }
354
+ /** Keys the quality block owns in harness.config.yaml. */
355
+ const OWNED = ["quality", "diff_coverage", "mutation_score", "checks"];
356
+ /**
357
+ * harness.config.yaml with its quality block replaced by this one: every
358
+ * other line kept, the block's own comment lines dropped with it.
359
+ */
360
+ function withPreset(config, preset) {
361
+ const lines = config.replace(/\r\n/g, "\n").split("\n");
362
+ const out = [];
363
+ let skipping = false;
364
+ for (const line of lines) {
365
+ const top = /^([a-z_]+):/.exec(line);
366
+ if (top)
367
+ skipping = OWNED.includes(top[1]);
368
+ else if (skipping && !/^(\s|#|$)/.test(line))
369
+ skipping = false;
370
+ if (skipping)
371
+ continue;
372
+ if (/^# (Quality and security checks|Every check runs in Docker|baseline once)/.test(line))
373
+ continue;
374
+ out.push(line);
375
+ }
376
+ return `${out.join("\n").trimEnd()}\n\n${preset}`;
377
+ }
378
+ //# sourceMappingURL=quality-presets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality-presets.js","sourceRoot":"","sources":["../../../scripts/lib/quality-presets.ts"],"names":[],"mappings":"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"}