@azure-id/orc 2.0.2 → 2.1.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.
Files changed (121) hide show
  1. package/CHANGELOG.md +401 -0
  2. package/README-id.md +52 -23
  3. package/README.md +50 -22
  4. package/bin/build-agents.js +24 -25
  5. package/bin/clear-logs.js +620 -0
  6. package/bin/cli.js +1155 -158
  7. package/bin/fix.js +459 -0
  8. package/bin/gotcha.js +288 -8
  9. package/bin/habit.js +1538 -1453
  10. package/bin/mockrun-catalog.js +3 -0
  11. package/bin/onboarding-content.js +2 -1
  12. package/bin/pricing.json +28 -21
  13. package/bin/trace-write.js +869 -657
  14. package/bin/verify-contracts.js +108 -27
  15. package/bin/verify-package.js +17 -6
  16. package/bin/webui/api.js +125 -6
  17. package/bin/webui/css/panels/hookui.css +79 -0
  18. package/bin/webui/fixtures/behaviour.js +30 -0
  19. package/bin/webui/fixtures/extra.js +9 -9
  20. package/bin/webui/fixtures/flow.js +81 -81
  21. package/bin/webui/fixtures/hookui.js +506 -431
  22. package/bin/webui/fixtures/index.js +32 -3
  23. package/bin/webui/fixtures/knowledge.js +2 -2
  24. package/bin/webui/fixtures/maintenance.js +123 -42
  25. package/bin/webui/fixtures/rules.js +1007 -1002
  26. package/bin/webui/fixtures/settings.js +6 -7
  27. package/bin/webui/fixtures/stats.js +9 -6
  28. package/bin/webui/fixtures/wait.js +98 -97
  29. package/bin/webui/i18n/en/behaviour.json +13 -0
  30. package/bin/webui/i18n/en/hookui.json +290 -194
  31. package/bin/webui/i18n/en/maintenance.json +71 -52
  32. package/bin/webui/i18n/en/settings.json +60 -60
  33. package/bin/webui/i18n/id/behaviour.json +13 -0
  34. package/bin/webui/i18n/id/hookui.json +290 -194
  35. package/bin/webui/i18n/id/maintenance.json +71 -52
  36. package/bin/webui/i18n/id/settings.json +60 -60
  37. package/bin/webui/js/05-banners.js +181 -172
  38. package/bin/webui/js/06-edit.js +193 -183
  39. package/bin/webui/js/panels/behaviour.js +77 -12
  40. package/bin/webui/js/panels/hookui.js +2196 -1691
  41. package/bin/webui/js/panels/maintenance.js +336 -235
  42. package/bin/webui/js/panels/settings.js +726 -719
  43. package/mock-run/INDEX.md +1 -0
  44. package/mock-run/extra-slots.md +1 -1
  45. package/mock-run/habits.md +1 -1
  46. package/mock-run/orc-aftermath.md +392 -392
  47. package/mock-run/orc-budget.md +29 -33
  48. package/mock-run/orc-cli.md +200 -200
  49. package/mock-run/orc-explain.md +86 -86
  50. package/mock-run/orc-extra.md +389 -392
  51. package/mock-run/orc-fix.md +87 -0
  52. package/mock-run/orc-pattern.md +112 -112
  53. package/mock-run/orc.md +157 -157
  54. package/package.json +1 -1
  55. package/templates/agents/MODEL-MAPPING.md +32 -29
  56. package/templates/agents/orc-analyze-mini-sonnet-5-high.md +2 -2
  57. package/templates/agents/{orc-claude-writer-opus-5-med.md → orc-claude-writer-opus-5-low.md} +4 -4
  58. package/templates/agents/orc-executor-haiku-4-5.md +1 -1
  59. package/templates/agents/orc-executor-opus-5-low.md +1 -1
  60. package/templates/agents/orc-executor-sonnet-4-6-high.md +1 -1
  61. package/templates/agents/orc-executor-sonnet-4-6-med.md +1 -1
  62. package/templates/agents/orc-executor-sonnet-5-high.md +2 -2
  63. package/templates/agents/orc-executor-sonnet-5-low.md +155 -0
  64. package/templates/agents/orc-executor-sonnet-5-med.md +155 -0
  65. package/templates/agents/orc-pattern-codifier-sonnet-5-high.md +2 -2
  66. package/templates/agents/orc-planner-mini-sonnet-5-high.md +2 -2
  67. package/templates/agents/orc-retro-sonnet-5-high.md +2 -2
  68. package/templates/agents/{orc-reviewer-opus-5-med.md → orc-reviewer-opus-5-low.md} +4 -4
  69. package/templates/agents/{orc-wiki-scanner-opus-5-med.md → orc-wiki-scanner-opus-5-low.md} +3 -3
  70. package/templates/agents/orc-wiki-scanner-sonnet-5-high.md +2 -2
  71. package/templates/commands/orc-fix.md +18 -0
  72. package/templates/commands/orc-wiki.md +64 -64
  73. package/templates/hooks/README.md +75 -7
  74. package/templates/hooks/orc-session-hook.js +78 -3
  75. package/templates/hooks/orc-statusline-render.js +317 -23
  76. package/templates/hooks/orc-statusline.js +162 -49
  77. package/templates/hooks/orc-subagent-line.js +23 -5
  78. package/templates/hooks/orc-weather-fetch.js +123 -0
  79. package/templates/skills/_shared/extra-dispatch.md +5 -5
  80. package/templates/skills/_shared/gotchas.md +27 -7
  81. package/templates/skills/_shared/habits.md +2 -2
  82. package/templates/skills/_shared/opus5-only.md +14 -14
  83. package/templates/skills/_shared/phases/review.md +2 -2
  84. package/templates/skills/_shared/phases/trace-verbs.md +17 -3
  85. package/templates/skills/_shared/phases/trace.md +136 -136
  86. package/templates/skills/_shared/review-slice.md +28 -1
  87. package/templates/skills/_shared/wait.md +1 -0
  88. package/templates/skills/orc/README.md +2 -2
  89. package/templates/skills/orc/SKILL.md +1 -1
  90. package/templates/skills/orc/config.md +25 -27
  91. package/templates/skills/orc/examples/full-run-mock.md +2 -1
  92. package/templates/skills/orc/references/effort-and-mode.md +17 -17
  93. package/templates/skills/orc/references/preflight-report.md +3 -3
  94. package/templates/skills/orc/references/ultra-mode.md +1 -1
  95. package/templates/skills/orc/schemas/checkpoint.md +122 -122
  96. package/templates/skills/orc/subskills/orc-review-verify/SKILL.md +3 -3
  97. package/templates/skills/orc/subskills/orc-review-verify/core.md +1 -1
  98. package/templates/skills/orc-analyze/SKILL.md +4 -2
  99. package/templates/skills/orc-claude/SKILL.md +14 -14
  100. package/templates/skills/orc-claude/examples/claude-run-mock.md +65 -65
  101. package/templates/skills/orc-diy/SKILL.md +5 -5
  102. package/templates/skills/orc-fast/SKILL.md +8 -6
  103. package/templates/skills/orc-fix/SKILL.md +110 -0
  104. package/templates/skills/orc-mini/SKILL.md +4 -4
  105. package/templates/skills/orc-mini/examples/mini-run-mock.md +4 -2
  106. package/templates/skills/orc-quick/README.md +1 -1
  107. package/templates/skills/orc-quick/SKILL.md +2 -2
  108. package/templates/skills/orc-quick/references/dispatch-gate.md +3 -2
  109. package/templates/skills/orc-quick/references/gh-mode.md +4 -2
  110. package/templates/skills/orc-retro/SKILL.md +1 -1
  111. package/templates/skills/orc-retro/examples/retro-mock.md +16 -16
  112. package/templates/skills/orc-wiki/README.md +325 -325
  113. package/templates/skills/orc-wiki/SKILL.md +195 -195
  114. package/templates/skills/orc-wiki/examples/wiki-run-mock.md +37 -37
  115. package/templates/skills/orc-wiki/references/extra.md +2 -2
  116. package/templates/skills/orc-wiki/references/partial-refresh.md +276 -271
  117. package/templates/skills/orc-wiki/references/phases/phase-0.md +1 -1
  118. package/templates/skills/orc-wiki/references/phases/phase-2.md +3 -3
  119. package/templates/skills/orc-wiki/references/phases/phase-3c.md +3 -2
  120. package/templates/agents/orc-claude-writer-opus-4-8-high.md +0 -48
  121. package/templates/agents/orc-wiki-scanner-opus-4-8-high.md +0 -74
package/bin/webui/api.js CHANGED
@@ -284,6 +284,9 @@ const READS = {
284
284
  // applies these to a copy of the saved layout before it compiles.
285
285
  if (q.theme) argv.push("--theme", String(q.theme));
286
286
  if (q.glyphs) argv.push("--glyphs", String(q.glyphs));
287
+ // v2.0.4 — an animated preview: N frames, M ms apart. Render-only.
288
+ if (q.frames) argv.push("--frames", String(q.frames));
289
+ if (q.frame_ms) argv.push("--frame-ms", String(q.frame_ms));
287
290
  return argv;
288
291
  },
289
292
  "/api/statusline/explain": (q) => ["statusline", "explain", String(q.at || "1:1"), ...slBoard(q)],
@@ -527,17 +530,41 @@ const WRITES = {
527
530
  ["width", "--width"], ["precision", "--precision"],
528
531
  ["min_width", "--min-width"], ["min_cols", "--min-cols"],
529
532
  ["max_cols", "--max-cols"], ["priority", "--priority"],
533
+ // v2.0.4 — the design fields. Same rule: absent sends nothing, "" clears.
534
+ ["label_pos", "--label-pos"], ["value_pos", "--value-pos"],
535
+ ["caption", "--caption"], ["caption_pos", "--caption-pos"],
536
+ ["caption_align", "--caption-align"], ["caption_color", "--caption-color"],
537
+ ["caption_case", "--caption-case"], ["fill_color", "--fill-color"],
538
+ ["empty_color", "--empty-color"], ["ramp_colors", "--ramp-colors"],
539
+ ["ramp_stops", "--ramp-stops"], ["fill_char", "--fill-char"],
540
+ ["empty_char", "--empty-char"], ["brackets", "--brackets"],
541
+ ["threshold", "--threshold"], ["pad_left", "--pad-left"],
542
+ ["pad_right", "--pad-right"], ["align", "--align"], ["sign", "--sign"],
543
+ ["max_len", "--max-len"], ["unknown", "--unknown"],
544
+ ["color_by_state", "--state-color"], ["glyph_by_state", "--state-glyph"],
530
545
  ]) {
531
- if (b[k] !== undefined && b[k] !== null && b[k] !== "") argv.push(f, String(b[k]));
546
+ // An absent key sends nothing; a PRESENT "" or null sends `<flag> ""`,
547
+ // which the CLI reads as "delete the key" (inherit). Dropping it made a
548
+ // clear "succeed" while it changed nothing.
549
+ if (b[k] === undefined) continue;
550
+ argv.push(f, b[k] === null ? "" : String(b[k]));
532
551
  }
533
552
  if (b.draw_empty) argv.push("--draw-empty");
553
+ // `params` is an OBJECT, one `--param k=v` per key. The CLI scans every
554
+ // `--param`, and `k=` (a null or "" value) deletes that key.
555
+ if (b.params && typeof b.params === "object")
556
+ for (const [k, v] of Object.entries(b.params)) argv.push("--param", String(k) + "=" + (v === null || v === undefined ? "" : String(v)));
534
557
  return argv.concat(slBoard(b));
535
558
  },
536
559
  "/api/statusline/move": (b) => ["statusline", "move", String(b.from), String(b.to), ...slBoard(b)],
537
560
  "/api/statusline/remove": (b) => ["statusline", "remove", String(b.at), ...slBoard(b)],
538
561
  "/api/statusline/line": (b) => {
539
562
  const argv = ["statusline", "line", String(b.line)];
540
- if (b.separator !== undefined) argv.push("--separator", String(b.separator));
563
+ // A PRESENT key is forwarded even when it is "" — that is the clear.
564
+ for (const [k, f] of [["separator", "--separator"], ["prefix", "--prefix"], ["align", "--align"], ["sep_color", "--sep-color"]]) {
565
+ if (b[k] === undefined) continue;
566
+ argv.push(f, b[k] === null ? "" : String(b[k]));
567
+ }
541
568
  if (b.theme) argv.push("--theme", String(b.theme));
542
569
  if (b.max_width !== undefined) argv.push("--max-width", String(b.max_width));
543
570
  return argv.concat(slBoard(b));
@@ -564,6 +591,8 @@ const WRITES = {
564
591
  "/api/statusline/clone": (b) => ["statusline", "clone", String(b.at), ...slBoard(b)],
565
592
  "/api/statusline/reset": (b) => ["statusline", "reset", ...slBoard(b)],
566
593
  "/api/statusline/compile": (b) => ["statusline", "compile", ...slBoard(b)],
594
+ // v2.0.4 — the redraw timer: a settings write, not a layout op.
595
+ "/api/statusline/refresh": (b) => ["statusline", "refresh", String(b.seconds), ...slBoard(b)],
567
596
  "/api/wait/unblock": (b) => (b.slug ? ["wait", "unblock", String(b.slug)] : ["wait", "unblock"]),
568
597
  "/api/wait/cancel": (b) => (b.slug ? ["wait", "cancel", String(b.slug)] : ["wait", "cancel"]),
569
598
  "/api/wiki/sync": () => ["wiki", "sync"],
@@ -836,6 +865,20 @@ const MAINTENANCE = {
836
865
  label: "Recompile AGENTS.md from the wiki, patterns, PACT.md and boundary cards",
837
866
  preview: ["export", "--check"],
838
867
  },
868
+ // v2.1.0 W7 — clear old logs. The preview is the CLI's own print mode, which
869
+ // names EVERY file it would delete and every file it keeps, with the reason
870
+ // (a count is not consent). The day value comes from config
871
+ // (`log_retention_days`): the panel sends only this id. `status` is the
872
+ // no-scan summary the row shows before any preview (days, last sweep).
873
+ "clear-logs": {
874
+ apply: ["clear", "logs", "--apply"],
875
+ restarts_ui: false,
876
+ label: "Delete finished traces and run folders older than log_retention_days (never user data, never a waiting run)",
877
+ preview: ["clear", "logs"],
878
+ status: ["clear", "logs", "--summary"],
879
+ names_files: true,
880
+ danger: true,
881
+ },
839
882
  // ADVANCED (v0.44.0) — the one action on this panel that does not target the
840
883
  // project. Every other route pins `--dir <projectRoot>`; `--global` outranks
841
884
  // `--dir` in `resolveClaudeDir`, so this pair reaches ~/.claude and its
@@ -1146,7 +1189,11 @@ async function handleApi(req, res, url, ctx) {
1146
1189
  try {
1147
1190
  body = await readBody(req);
1148
1191
  } catch (_) {}
1149
- const canned = fixtures.post(route, body);
1192
+ // The staged preview has nothing to replay here, so it answers with the
1193
+ // canned picture — the shape the panel reads, not "nothing ran".
1194
+ if (route === "/api/statusline/stage-preview")
1195
+ return json(res, 200, { ok: true, preview: fixtures.get("/api/statusline/preview", body), show: fixtures.get("/api/statusline/show", body) });
1196
+ const canned = fixtures.post(route, body);
1150
1197
  if (canned)
1151
1198
  return json(res, 200, {
1152
1199
  ok: true,
@@ -1209,6 +1256,9 @@ async function handleApi(req, res, url, ctx) {
1209
1256
  names_files: !!m.names_files,
1210
1257
  advanced: !!m.advanced,
1211
1258
  restarts_ui: !!m.restarts_ui,
1259
+ danger: !!m.danger,
1260
+ // The CLI's own no-scan summary (v2.1.0 W7) — never a number the panel computes.
1261
+ status: m.status ? readCli(m.status, ctx).data || null : null,
1212
1262
  }));
1213
1263
  return json(res, 200, { ok: true, exit_code: 0, data: { actions } });
1214
1264
  }
@@ -1226,6 +1276,7 @@ async function handleApi(req, res, url, ctx) {
1226
1276
  network: !!m.network,
1227
1277
  names_files: !!m.names_files,
1228
1278
  advanced: !!m.advanced,
1279
+ danger: !!m.danger,
1229
1280
  // Said in the confirmation, not discovered afterwards. A panel that
1230
1281
  // reloads itself without warning reads as a crash.
1231
1282
  restarts_ui: !!m.restarts_ui,
@@ -1408,6 +1459,10 @@ async function handleApi(req, res, url, ctx) {
1408
1459
  return json(res, 200, { ok: true, ...started });
1409
1460
  }
1410
1461
 
1462
+ // v2.0.4 — the staged preview. NOT a mutation of this project: it runs in a
1463
+ // throwaway copy, so it neither waits on nor blocks a running job.
1464
+ if (route === "/api/statusline/stage-preview") return json(res, 200, stagePreview(body, ctx));
1465
+
1411
1466
  const build = WRITES[route];
1412
1467
  if (!build) return json(res, 404, { error: "unknown endpoint " + route });
1413
1468
  if (job && job.running) return json(res, 409, { error: "busy", job: jobView() });
@@ -1417,8 +1472,7 @@ async function handleApi(req, res, url, ctx) {
1417
1472
  } catch (_) {
1418
1473
  return json(res, 400, { error: "bad request body" });
1419
1474
  }
1420
- if (argv.some((a) => a === "undefined" || a === "null" || a === ""))
1421
- return json(res, 400, { error: "missing argument" });
1475
+ if (!argvComplete(argv)) return json(res, 400, { error: "missing argument" });
1422
1476
  const out = runCli(argv, ctx);
1423
1477
  clearCache();
1424
1478
  // A write's exit code is a REAL failure signal (validators exit 1), unlike a
@@ -1432,6 +1486,71 @@ async function handleApi(req, res, url, ctx) {
1432
1486
  });
1433
1487
  }
1434
1488
 
1489
+ // A write's argv is complete when no element is a lost value. `""` is a real
1490
+ // value right after a `--flag` — it is how a v2.0.3 clear is spelled — and is
1491
+ // refused only as a positional, together with "undefined" and "null".
1492
+ function argvComplete(argv) {
1493
+ return !argv.some((a, i) => {
1494
+ if (a === "undefined" || a === "null") return true;
1495
+ if (a !== "") return false;
1496
+ const prev = argv[i - 1];
1497
+ return !(typeof prev === "string" && prev.startsWith("--"));
1498
+ });
1499
+ }
1500
+
1501
+ // The files a board's layout lives in, under `.claude/orc/`. The CLI's own
1502
+ // names; only the AUTHORED file is copied — the rest is compiled from it.
1503
+ const SL_LAYOUT_FILE = { status: "statusline-layout.json", subagent: "subagent-layout.json" };
1504
+
1505
+ // v2.0.4 — THE STAGED PREVIEW. The staged writes are replayed through the SAME
1506
+ // `WRITES` builders against a throwaway copy of this project's layout, then
1507
+ // the copy is previewed by the hook's own engine. Nothing touches the real
1508
+ // project, and the copy is always deleted.
1509
+ function stagePreview(body, ctx) {
1510
+ const b = body || {};
1511
+ const board = b.board === "subagent" ? "subagent" : "status";
1512
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "orc-stage-"));
1513
+ const sub = { ...ctx, projectRoot: tmp };
1514
+ try {
1515
+ const orcDir = path.join(tmp, ".claude", "orc");
1516
+ fs.mkdirSync(orcDir, { recursive: true });
1517
+ const src = path.join(ctx.projectRoot || "", ".claude", "orc", SL_LAYOUT_FILE[board]);
1518
+ if (ctx.projectRoot && fs.existsSync(src)) fs.copyFileSync(src, path.join(orcDir, SL_LAYOUT_FILE[board]));
1519
+ const actions = Array.isArray(b.actions) ? b.actions : [];
1520
+ for (let i = 0; i < actions.length; i++) {
1521
+ const a = actions[i] || {};
1522
+ const route = String(a.route || "");
1523
+ const build = route.startsWith("/api/statusline/") ? WRITES[route] : null;
1524
+ let argv = null;
1525
+ try {
1526
+ argv = build ? build(Object.assign({}, a.body || {}, { board: board })) : null;
1527
+ } catch (_) {
1528
+ argv = null;
1529
+ }
1530
+ if (!argv || !argvComplete(argv)) return { ok: false, failed: { index: i, output: "refused: " + route } };
1531
+ const out = runCli(argv, sub);
1532
+ if (out.exit_code !== 0)
1533
+ return { ok: false, failed: { index: i, output: (out.stdout + (out.stderr ? chr10 + out.stderr : "")).trim() } };
1534
+ }
1535
+ const q = { board };
1536
+ if (b.width) q.width = b.width;
1537
+ if (b.state) q.state = b.state;
1538
+ if (b.frames) q.frames = b.frames;
1539
+ if (b.frame_ms) q.frame_ms = b.frame_ms;
1540
+ const preview = runCli(READS["/api/statusline/preview"](q), sub, { json: true });
1541
+ const show = runCli(READS["/api/statusline/show"](q), sub, { json: true });
1542
+ return { ok: true, preview: preview.data, show: show.data };
1543
+ } finally {
1544
+ rmTree(tmp);
1545
+ }
1546
+ }
1547
+
1548
+ function rmTree(dir) {
1549
+ try {
1550
+ fs.rmSync(dir, { recursive: true, force: true });
1551
+ } catch (_) {}
1552
+ }
1553
+
1435
1554
  // `orc upgrade` replaces the package while your working tree may hold changes.
1436
1555
  // Worth a warning before, not a surprise after.
1437
1556
  function isDirtyTree(ctx) {
@@ -1448,4 +1567,4 @@ function isDirtyTree(ctx) {
1448
1567
  }
1449
1568
  }
1450
1569
 
1451
- module.exports = { handleApi, clearCache, encodeBody, READS, WRITES, MAINTENANCE };
1570
+ module.exports = { handleApi, clearCache, encodeBody, READS, WRITES, MAINTENANCE, argvComplete, stagePreview };
@@ -772,3 +772,82 @@ button.hk-pick-row:hover {
772
772
  .hk-boards {
773
773
  margin-bottom: 4px;
774
774
  }
775
+
776
+ /* v2.0.4 — the line head's options and the editor's new controls. All flex,
777
+ so each one wraps on a narrow screen by itself. */
778
+ .hk-line-opts-wrap {
779
+ display: flex;
780
+ align-items: center;
781
+ flex-wrap: wrap;
782
+ gap: 8px 14px;
783
+ }
784
+ .hk-input.hk-short {
785
+ width: 7em;
786
+ }
787
+ .hk-input.hk-char {
788
+ width: 3.5em;
789
+ text-align: center;
790
+ }
791
+ .hk-colour,
792
+ .hk-hex,
793
+ .hk-pair,
794
+ .hk-state-row {
795
+ display: flex;
796
+ align-items: center;
797
+ flex-wrap: wrap;
798
+ gap: 6px;
799
+ }
800
+ .hk-colour {
801
+ flex-direction: column;
802
+ align-items: flex-start;
803
+ }
804
+ .hk-hex-pick {
805
+ width: 32px;
806
+ height: 26px;
807
+ padding: 0;
808
+ border: 1px solid var(--line);
809
+ border-radius: 6px;
810
+ background: none;
811
+ cursor: pointer;
812
+ }
813
+ .hk-state-row {
814
+ margin: 4px 0;
815
+ }
816
+ .hk-state-name {
817
+ min-width: 8em;
818
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
819
+ font-size: 12px;
820
+ }
821
+ /* A case button's sample, under its name. */
822
+ .hk-pick-tip {
823
+ display: block;
824
+ font-size: 11px;
825
+ color: var(--text-dim);
826
+ }
827
+ /* The CLI's own refusal text for a staged change. */
828
+ .hk-stage-out {
829
+ margin: 0;
830
+ padding: 8px 10px;
831
+ white-space: pre-wrap;
832
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
833
+ font-size: 12px;
834
+ border: 1px solid var(--line);
835
+ border-radius: 6px;
836
+ background: var(--surface-2);
837
+ }
838
+ .hk-staged-tag {
839
+ color: var(--ok);
840
+ }
841
+
842
+ /* v2.0.4 — the redraw timer, under the advanced card. */
843
+ .hk-anim {
844
+ display: flex;
845
+ flex-direction: column;
846
+ gap: 6px;
847
+ margin-top: 10px;
848
+ padding-top: 10px;
849
+ border-top: 1px solid var(--line);
850
+ }
851
+ .hk-anim-head {
852
+ font-weight: 600;
853
+ }
@@ -451,6 +451,29 @@ const gotchaQuality = {
451
451
  ok: true,
452
452
  window_days: 90,
453
453
  reviews: 12,
454
+ reviews_traced: 12,
455
+ reviews_observed: 9,
456
+ by_reviewer: { orc: 12, "/code-review": 2 },
457
+ project_reviews: 2,
458
+ // v2.1.0 W6 — `orc fix record`: the fixes made after a review, and the misses.
459
+ fixes: {
460
+ total: 5,
461
+ by_introduced_by: { orc: 2, ai: 1, human: 1, unknown: 1 },
462
+ by_source: { sonar: 2, defect: 2, ci: 1 },
463
+ causes: [
464
+ { id: "sonar", n: 2, share: 0.4 },
465
+ { id: "orc", n: 1, share: 0.2 },
466
+ { id: "ai", n: 1, share: 0.2 },
467
+ { id: "other", n: 1, share: 0.2 },
468
+ ],
469
+ },
470
+ misses: {
471
+ total: 1,
472
+ by_category: [{ category: "functional.logic", n: 1 }],
473
+ list: [
474
+ { obs: "9f2c41ab", at: new Date(NOW - 3 * DAY).toISOString().slice(0, 10), path: "src/orders/total.ts", lines: [40, 58], source: "sonar", rule: "sonar:typescript:S3776", category: "functional.logic", introduced_by: "orc", missed_by: "run-mini-total-290926-101500", fix_run: "run-quick-total-fix-021026-091200" },
475
+ ],
476
+ },
454
477
  floor: 5,
455
478
  below_floor: false,
456
479
  findings: 118,
@@ -473,6 +496,13 @@ const gotchaQualityLow = {
473
496
  ok: true,
474
497
  window_days: 30,
475
498
  reviews: 3,
499
+ // v2.1.0 — one review counted from its trace only (a clean review).
500
+ reviews_traced: 3,
501
+ reviews_observed: 2,
502
+ by_reviewer: { orc: 3 },
503
+ project_reviews: 0,
504
+ fixes: { total: 0, by_introduced_by: { orc: 0, ai: 0, human: 0, unknown: 0 }, by_source: {}, causes: [{ id: "sonar", n: 0, share: 0 }, { id: "orc", n: 0, share: 0 }, { id: "ai", n: 0, share: 0 }, { id: "other", n: 0, share: 0 }] },
505
+ misses: { total: 0, by_category: [], list: [] },
476
506
  floor: 5,
477
507
  below_floor: true,
478
508
  findings: 19,
@@ -780,7 +780,7 @@ const extraRoute = {
780
780
  profile: "glm", model: "glm-4.6", small_model: null, max_turns: null,
781
781
  engine: "claude-shim", provider: "zai", verify_state: "STALE", model_known: true,
782
782
  },
783
- { from: 55, to: 65, band: "[55,65)", range: "scores 55 to 64", meaning: "several files, or a new surface, or logic that carries state", via: "claude", agent: "orc-executor-sonnet-5-high" },
783
+ { from: 55, to: 65, band: "[55,65)", range: "scores 55 to 64", meaning: "several files, or a new surface, or logic that carries state", via: "claude", agent: "orc-executor-opus-5-low" },
784
784
  {
785
785
  // A routed model the last ping did not list — the state that becomes a
786
786
  // 404 in the middle of a wave if nothing shows it first.
@@ -788,9 +788,9 @@ const extraRoute = {
788
788
  profile: "cheap", model: "deepseek-coder", small_model: null, max_turns: null,
789
789
  engine: "api", provider: "deepseek", verify_state: "VERIFIED", model_known: false,
790
790
  },
791
- // v1.0.0 W4 — the route row above splits the default table's [65,90) band,
792
- // so the Claude remainder is [70,90) and it resolves to the SAME agent the
793
- // routed part displaced. That is the honest picture of an overlay: a row
791
+ // v1.0.0 W4 — the route rows above split the default table's [41,90) band
792
+ // (v2.1.0: it was [65,90)), so the Claude remainders are [55,65) and [70,90).
793
+ // Both resolve to the SAME agent the routed parts displaced. That is the honest picture of an overlay: a row
794
794
  // takes a slice of a band, and what it did not take falls through.
795
795
  { from: 70, to: 90, band: "[70,90)", range: "scores 70 to 89", meaning: "wide reach or genuinely new work (a cited risk floors a task to 70, so it lands here or above)", via: "claude", agent: "orc-executor-opus-5-low" },
796
796
  { from: 90, to: 100, band: "[90,100]", range: "scores 90 to 100", meaning: "the hardest work: a novel algorithm, or wide reach with deep logic", via: "claude", agent: "orc-executor-opus-5-med" },
@@ -890,9 +890,9 @@ const extraRole = {
890
890
  provider: null, engine: null, verify_state: null, verify_age_days: null, model_known: null,
891
891
  meaning: "a scanner returns an evidence-anchored doc body the orchestrator writes; every claim in it is anchored to a file you can open.",
892
892
  asks: false, announce_point: "per scan-batch, beside the resolved tier",
893
- claude: { via: "claude", agent: "orc-wiki-scanner-opus-4-8-high", agents: ["orc-wiki-scanner-opus-4-8-high"], table: "shipped" },
893
+ claude: { via: "claude", agent: "orc-wiki-scanner-opus-5-low", agents: ["orc-wiki-scanner-opus-5-low"], table: "shipped" },
894
894
  resolved: "claude", held_back: null,
895
- why: "no slot row holds wiki-scanner-deep — Extra is an OVERLAY, so an unrouted position falls straight through to orc-wiki-scanner-opus-4-8-high.",
895
+ why: "no slot row holds wiki-scanner-deep — Extra is an OVERLAY, so an unrouted position falls straight through to orc-wiki-scanner-opus-5-low.",
896
896
  announce: null,
897
897
  next: "orc extra role set wiki-scanner-deep <profile>/<model>",
898
898
  },
@@ -956,8 +956,8 @@ const extraLanes = {
956
956
  },
957
957
  {
958
958
  lane: "/orc-mini", shape: "fixed-executor", agent: "orc-executor-sonnet-5-high",
959
- band: "[55,65)", edges: [55, 64], agree: false, routes: "claude", resolved: null,
960
- detail: "one edge routes foreign and the other does not, so the lane stays on Claude. Row [30,55) covers only part of this band.",
959
+ band: "[31,41)", edges: [31, 40], agree: true, routes: "claude", resolved: null,
960
+ detail: "both edges resolve to Claude: row [30,55) covers this band, but its profile is STALE, so it does not route.",
961
961
  },
962
962
  {
963
963
  lane: "/orc-fast", shape: "slot", agent: null, routes: "roles",
@@ -999,7 +999,7 @@ const extraLanes = {
999
999
  // answering honestly instead of blaming a role name nobody could set.
1000
1000
  lane: "/orc-wiki", shape: "slot", agent: null, routes: "claude",
1001
1001
  slots: [
1002
- { slot: "wiki-scanner-deep", routes: false, profile: null, model: null, claude: "orc-wiki-scanner-opus-4-8-high", held_back: null, why: "no slot row holds wiki-scanner-deep — Extra is an OVERLAY, so an unrouted position falls straight through to orc-wiki-scanner-opus-4-8-high." },
1002
+ { slot: "wiki-scanner-deep", routes: false, profile: null, model: null, claude: "orc-wiki-scanner-opus-5-low", held_back: null, why: "no slot row holds wiki-scanner-deep — Extra is an OVERLAY, so an unrouted position falls straight through to orc-wiki-scanner-opus-5-low." },
1003
1003
  { slot: "wiki-scanner-light", routes: false, profile: null, model: null, claude: "orc-wiki-scanner-sonnet-5-high", held_back: null, why: "no slot row holds wiki-scanner-light — Extra is an OVERLAY, so an unrouted position falls straight through to orc-wiki-scanner-sonnet-5-high." },
1004
1004
  ],
1005
1005
  detail: "no position in this lane is held, so every one of them stays on its pinned Claude agent.",
@@ -1,81 +1,81 @@
1
- "use strict";
2
- /* fixtures/flow.js — canned data for `orc ui --fixtures`.
3
- A compiled DIY flow with an OFF phase, so the red struck-through step is
4
- designable.
5
-
6
- THE RULE FOR EVERY FILE IN HERE: carry ONE OF EVERY STATE, including the
7
- ugly ones. You cannot DESIGN a STALE chip on a fresh wiki, and a state
8
- with no fixture is a state nobody has ever looked at. A per-state count
9
- test asserts this, so a new state cannot ship without one.
10
-
11
- Shapes MUST match what `bin/cli.js --json` really emits — a drifted
12
- fixture is worse than no fixture. */
13
-
14
- const { PROJECT } = require("./shell.js");
15
-
16
- const diy = {
17
- state: "STALE",
18
- reason: "config changed since the last compile; orc updated 0.41.0 → 0.43.0 — run `orc diy compile`",
19
- triggers: ["config changed since the last compile", "orc updated 0.41.0 → 0.43.0"],
20
- configured: true,
21
- paths: { config: PROJECT + "/.claude/orc-diy.config.yaml", compiled: PROJECT + "/.claude/orc/diy/FLOW-COMPILED.md", lock: PROJECT + "/.claude/orc/diy/flow.lock.json" },
22
- // `options` is the key's closed set (v0.44.0) and the panel turns it into a
23
- // dropdown. The fixture carries all three shapes on purpose: an ordinary
24
- // enum, a NUMERIC set (rubric_bands — every band, not just the current one),
25
- // `options: null` free text (flow_name), and the ugly one — `fixed_executor`
26
- // holding the empty value, which is NOT in its own option list.
27
- keys: [
28
- { key: "flow_name", value: "my-lean", default: "custom", is_set: true, desc: "Name shown in the compiled flow.", options: null },
29
- { key: "wiki_gate", value: "notice", default: "notice", is_set: false, desc: "Wiki freshness at preflight.", options: ["notice", "off", "hard"] },
30
- { key: "analyze", value: "off", default: "full", is_set: true, desc: "Analyst phase.", options: ["auto", "off", "mini", "full"] },
31
- { key: "planning", value: "own-planner", default: "auto", is_set: true, desc: "Planning route.", options: ["auto", "own-planner", "superpowers", "openspec"] },
32
- { key: "pattern", value: "ask", default: "ask", is_set: false, desc: "Code-pattern gate on a cache miss.", options: ["ask", "off", "on"] },
33
- { key: "scoring", value: "on", default: "on", is_set: false, desc: "Rubric scoring.", options: ["on", "off"] },
34
- { key: "fixed_executor", value: "", default: "", is_set: false, desc: "Executor used for every task when scoring is off.", options: ["orc-executor-haiku-4-5", "orc-executor-sonnet-4-6-med", "orc-executor-sonnet-5-high", "orc-executor-opus-4-8-high", "orc-executor-opus-5-high"] },
35
- { key: "review", value: "blocking-only", default: "full", is_set: true, desc: "Review phase depth.", options: ["on", "off", "blocking-only"] },
36
- { key: "security", value: "off", default: "off", is_set: false, desc: "Security pass.", options: ["off", "ask", "on", "always"] },
37
- { key: "verify", value: "smoke", default: "full", is_set: true, desc: "Verification depth.", options: ["full", "off", "smoke"] },
38
- { key: "testgen", value: "off", default: "off", is_set: false, desc: "Test-authoring phase.", options: ["off", "ask", "on"] },
39
- { key: "mock_example", value: "ask", default: "ask", is_set: false, desc: "Post-verify mocked example.", options: ["ask", "on", "off"] },
40
- { key: "ship_mode", value: "ask", default: "ask", is_set: false, desc: "Terminal ship behavior.", options: ["ask", "commit", "pr", "report-only"] },
41
- { key: "summary", value: "short", default: "full", is_set: true, desc: "Summary depth.", options: ["full", "off", "short"] },
42
- { key: "tdd", value: "on", default: "on", is_set: false, desc: "TDD gate.", options: ["on", "off"] },
43
- { key: "rubric_bands", value: 5, default: 5, is_set: false, desc: "Scoring granularity (scoring on only).", options: [2, 3, 4, 5, 6, 7, 8] },
44
- { key: "session_tier", value: "opus-4-8-high", default: "opus-5-high", is_set: true, desc: "Declared main-session tier.", options: ["sonnet-4-6-high", "opus-4-7-high", "opus-4-8-high", "opus-5-high", "opus-5-max", "fable-5-high"] },
45
- ],
46
- // The bootstrap catalog, empty name first (= full-lane defaults, no --preset
47
- // flag). `lean` is ACTIVE here even though this flow was renamed away from
48
- // it — that is the state the "in use" chip exists for, and you cannot design
49
- // it against a catalog where nothing matches.
50
- presets: [
51
- { name: "", changes: {}, active: false },
52
- { name: "lean", changes: { analyze: "off", review: "blocking-only", verify: "smoke", summary: "short", flow_name: "lean" }, active: true },
53
- { name: "paranoid", changes: { analyze: "full", security: "always", testgen: "on", verify: "full", flow_name: "paranoid" }, active: false },
54
- { name: "solo-fast", changes: { scoring: "off", fixed_executor: "orc-executor-sonnet-5-high", review: "off", verify: "smoke", autonomy: "semi", flow_name: "solo-fast" }, active: false },
55
- ],
56
- errors: [],
57
- warnings: ["tdd is on but verify is smoke — the red proof gates less than it could"],
58
- // The stepper's data. A lean flow is the useful fixture here precisely
59
- // because it is half switched off — you cannot design the red OFF state
60
- // against a pipeline where every phase is on.
61
- steps: [
62
- { block: "header", label: "intake", key: null, value: "", on: true, note: "self-gate" },
63
- { block: "trace", label: "trace", key: null, value: "", on: true, note: "always on" },
64
- { block: "wiki", label: "wiki", key: "wiki_gate", value: "notice", on: true, note: "notice" },
65
- { block: "analyze", label: "analyze", key: "analyze", value: "off", on: false, note: "off" },
66
- { block: "planning", label: "plan", key: "planning", value: "own-planner", on: true, note: "own-planner" },
67
- { block: "pattern", label: "pattern", key: "pattern", value: "ask", on: true, note: "ask" },
68
- { block: "scoring", label: "score", key: "scoring", value: "on", on: true, note: "on" },
69
- { block: "execution", label: "execute", key: null, value: "", on: true, note: "scored" },
70
- { block: "review", label: "review", key: "review", value: "blocking-only", on: true, note: "blocking-only" },
71
- { block: "security", label: "security", key: "security", value: "off", on: false, note: "off" },
72
- { block: "verify", label: "verify", key: "verify", value: "smoke", on: true, note: "smoke" },
73
- { block: "testgen", label: "testgen", key: "testgen", value: "off", on: false, note: "off" },
74
- { block: "mock-example", label: "mock", key: "mock_example", value: "ask", on: true, note: "ask" },
75
- { block: "ship", label: "ship", key: "ship_mode", value: "ask", on: true, note: "ask" },
76
- { block: "summary", label: "summary", key: "summary", value: "short", on: true, note: "short" },
77
- ],
78
- score_table: "| Score | Executor agent |\n|-------|----------------|\n| [0,30) | orc-executor-haiku-4-5 |\n| [90,100] | orc-executor-opus-5-med |",
79
- };
80
-
81
- module.exports = { diy };
1
+ "use strict";
2
+ /* fixtures/flow.js — canned data for `orc ui --fixtures`.
3
+ A compiled DIY flow with an OFF phase, so the red struck-through step is
4
+ designable.
5
+
6
+ THE RULE FOR EVERY FILE IN HERE: carry ONE OF EVERY STATE, including the
7
+ ugly ones. You cannot DESIGN a STALE chip on a fresh wiki, and a state
8
+ with no fixture is a state nobody has ever looked at. A per-state count
9
+ test asserts this, so a new state cannot ship without one.
10
+
11
+ Shapes MUST match what `bin/cli.js --json` really emits — a drifted
12
+ fixture is worse than no fixture. */
13
+
14
+ const { PROJECT } = require("./shell.js");
15
+
16
+ const diy = {
17
+ state: "STALE",
18
+ reason: "config changed since the last compile; orc updated 0.41.0 → 0.43.0 — run `orc diy compile`",
19
+ triggers: ["config changed since the last compile", "orc updated 0.41.0 → 0.43.0"],
20
+ configured: true,
21
+ paths: { config: PROJECT + "/.claude/orc-diy.config.yaml", compiled: PROJECT + "/.claude/orc/diy/FLOW-COMPILED.md", lock: PROJECT + "/.claude/orc/diy/flow.lock.json" },
22
+ // `options` is the key's closed set (v0.44.0) and the panel turns it into a
23
+ // dropdown. The fixture carries all three shapes on purpose: an ordinary
24
+ // enum, a NUMERIC set (rubric_bands — every band, not just the current one),
25
+ // `options: null` free text (flow_name), and the ugly one — `fixed_executor`
26
+ // holding the empty value, which is NOT in its own option list.
27
+ keys: [
28
+ { key: "flow_name", value: "my-lean", default: "custom", is_set: true, desc: "Name shown in the compiled flow.", options: null },
29
+ { key: "wiki_gate", value: "notice", default: "notice", is_set: false, desc: "Wiki freshness at preflight.", options: ["notice", "off", "hard"] },
30
+ { key: "analyze", value: "off", default: "full", is_set: true, desc: "Analyst phase.", options: ["auto", "off", "mini", "full"] },
31
+ { key: "planning", value: "own-planner", default: "auto", is_set: true, desc: "Planning route.", options: ["auto", "own-planner", "superpowers", "openspec"] },
32
+ { key: "pattern", value: "ask", default: "ask", is_set: false, desc: "Code-pattern gate on a cache miss.", options: ["ask", "off", "on"] },
33
+ { key: "scoring", value: "on", default: "on", is_set: false, desc: "Rubric scoring.", options: ["on", "off"] },
34
+ { key: "fixed_executor", value: "", default: "", is_set: false, desc: "Executor used for every task when scoring is off.", options: ["orc-executor-haiku-4-5", "orc-executor-sonnet-4-6-med", "orc-executor-sonnet-5-high", "orc-executor-opus-4-8-high", "orc-executor-opus-5-high"] },
35
+ { key: "review", value: "blocking-only", default: "full", is_set: true, desc: "Review phase depth.", options: ["on", "off", "blocking-only"] },
36
+ { key: "security", value: "off", default: "off", is_set: false, desc: "Security pass.", options: ["off", "ask", "on", "always"] },
37
+ { key: "verify", value: "smoke", default: "full", is_set: true, desc: "Verification depth.", options: ["full", "off", "smoke"] },
38
+ { key: "testgen", value: "off", default: "off", is_set: false, desc: "Test-authoring phase.", options: ["off", "ask", "on"] },
39
+ { key: "mock_example", value: "ask", default: "ask", is_set: false, desc: "Post-verify mocked example.", options: ["ask", "on", "off"] },
40
+ { key: "ship_mode", value: "ask", default: "ask", is_set: false, desc: "Terminal ship behavior.", options: ["ask", "commit", "pr", "report-only"] },
41
+ { key: "summary", value: "short", default: "full", is_set: true, desc: "Summary depth.", options: ["full", "off", "short"] },
42
+ { key: "tdd", value: "on", default: "on", is_set: false, desc: "TDD gate.", options: ["on", "off"] },
43
+ { key: "rubric_bands", value: 5, default: 5, is_set: false, desc: "Scoring granularity (scoring on only).", options: [2, 3, 4, 5, 6, 7, 8] },
44
+ { key: "session_tier", value: "opus-4-8-high", default: "opus-5-high", is_set: true, desc: "Declared main-session tier.", options: ["sonnet-4-6-high", "opus-4-7-high", "opus-4-8-high", "opus-5-high", "opus-5-max", "fable-5-high"] },
45
+ ],
46
+ // The bootstrap catalog, empty name first (= full-lane defaults, no --preset
47
+ // flag). `lean` is ACTIVE here even though this flow was renamed away from
48
+ // it — that is the state the "in use" chip exists for, and you cannot design
49
+ // it against a catalog where nothing matches.
50
+ presets: [
51
+ { name: "", changes: {}, active: false },
52
+ { name: "lean", changes: { analyze: "off", review: "blocking-only", verify: "smoke", summary: "short", flow_name: "lean" }, active: true },
53
+ { name: "paranoid", changes: { analyze: "full", security: "always", testgen: "on", verify: "full", flow_name: "paranoid" }, active: false },
54
+ { name: "solo-fast", changes: { scoring: "off", fixed_executor: "orc-executor-sonnet-5-high", review: "off", verify: "smoke", autonomy: "semi", flow_name: "solo-fast" }, active: false },
55
+ ],
56
+ errors: [],
57
+ warnings: ["tdd is on but verify is smoke — the red proof gates less than it could"],
58
+ // The stepper's data. A lean flow is the useful fixture here precisely
59
+ // because it is half switched off — you cannot design the red OFF state
60
+ // against a pipeline where every phase is on.
61
+ steps: [
62
+ { block: "header", label: "intake", key: null, value: "", on: true, note: "self-gate" },
63
+ { block: "trace", label: "trace", key: null, value: "", on: true, note: "always on" },
64
+ { block: "wiki", label: "wiki", key: "wiki_gate", value: "notice", on: true, note: "notice" },
65
+ { block: "analyze", label: "analyze", key: "analyze", value: "off", on: false, note: "off" },
66
+ { block: "planning", label: "plan", key: "planning", value: "own-planner", on: true, note: "own-planner" },
67
+ { block: "pattern", label: "pattern", key: "pattern", value: "ask", on: true, note: "ask" },
68
+ { block: "scoring", label: "score", key: "scoring", value: "on", on: true, note: "on" },
69
+ { block: "execution", label: "execute", key: null, value: "", on: true, note: "scored" },
70
+ { block: "review", label: "review", key: "review", value: "blocking-only", on: true, note: "blocking-only" },
71
+ { block: "security", label: "security", key: "security", value: "off", on: false, note: "off" },
72
+ { block: "verify", label: "verify", key: "verify", value: "smoke", on: true, note: "smoke" },
73
+ { block: "testgen", label: "testgen", key: "testgen", value: "off", on: false, note: "off" },
74
+ { block: "mock-example", label: "mock", key: "mock_example", value: "ask", on: true, note: "ask" },
75
+ { block: "ship", label: "ship", key: "ship_mode", value: "ask", on: true, note: "ask" },
76
+ { block: "summary", label: "summary", key: "summary", value: "short", on: true, note: "short" },
77
+ ],
78
+ score_table: "| Score | Executor agent |\n|-------|----------------|\n| [0,21) | orc-executor-sonnet-5-low |\n| [90,100] | orc-executor-opus-5-med |",
79
+ };
80
+
81
+ module.exports = { diy };