@xhulz/nina 0.28.18 → 0.28.20

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 (231) hide show
  1. package/package.json +1 -1
  2. package/releases/0.28.19/core/GAPS.md +125 -0
  3. package/releases/0.28.19/core/answered.json +29 -0
  4. package/releases/0.28.19/core/defaults/tree/.claude/agents/architect.md +1 -0
  5. package/releases/0.28.19/core/defaults/tree/.claude/agents/dba.md +3 -0
  6. package/releases/0.28.19/core/defaults/tree/.claude/agents/devops.md +1 -0
  7. package/releases/0.28.19/core/defaults/tree/.claude/agents/implementer.md +1 -0
  8. package/releases/0.28.19/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
  9. package/releases/0.28.19/core/defaults/tree/.claude/agents/qa.md +2 -0
  10. package/releases/0.28.19/core/defaults/tree/.claude/agents/reviewer.md +3 -0
  11. package/releases/0.28.19/core/defaults/tree/.claude/agents/secops.md +3 -0
  12. package/releases/0.28.19/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
  13. package/releases/0.28.19/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
  14. package/releases/0.28.19/core/tree/.claude/agents/architect.md +125 -0
  15. package/releases/0.28.19/core/tree/.claude/agents/dba.md +107 -0
  16. package/releases/0.28.19/core/tree/.claude/agents/devops.md +113 -0
  17. package/releases/0.28.19/core/tree/.claude/agents/implementer.md +155 -0
  18. package/releases/0.28.19/core/tree/.claude/agents/integration-tester.md +160 -0
  19. package/releases/0.28.19/core/tree/.claude/agents/planner.md +132 -0
  20. package/releases/0.28.19/core/tree/.claude/agents/qa.md +146 -0
  21. package/releases/0.28.19/core/tree/.claude/agents/reviewer.md +180 -0
  22. package/releases/0.28.19/core/tree/.claude/agents/secops.md +121 -0
  23. package/releases/0.28.19/core/tree/.claude/agents/solidity-auditor.md +126 -0
  24. package/releases/0.28.19/core/tree/.claude/agents/solidity-dev.md +123 -0
  25. package/releases/0.28.19/core/tree/.claude/agents-overview.md +64 -0
  26. package/releases/0.28.19/core/tree/.claude/graph.md +73 -0
  27. package/releases/0.28.19/core/tree/.claude/patterns.md +212 -0
  28. package/releases/0.28.19/core/tree/.claude/pills/README.md +145 -0
  29. package/releases/0.28.19/core/tree/.claude/pipeline.md +102 -0
  30. package/releases/0.28.19/core/tree/.claude/retrieval.md +104 -0
  31. package/releases/0.28.19/core/tree/.claude/router.md +201 -0
  32. package/releases/0.28.19/core/tree/.claude/templates/integration.md +45 -0
  33. package/releases/0.28.19/core/tree/CLAUDE.md +155 -0
  34. package/releases/0.28.19/core/tree/scripts/edit-guard.mjs +16 -0
  35. package/releases/0.28.19/core/tree/scripts/harness-check.mjs +71 -0
  36. package/releases/0.28.19/core/tree/scripts/loop-gate.mjs +19 -0
  37. package/releases/0.28.19/core/vocabulary.json +12 -0
  38. package/releases/0.28.19/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
  39. package/releases/0.28.19/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
  40. package/releases/0.28.19/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
  41. package/releases/0.28.19/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
  42. package/releases/0.28.19/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
  43. package/releases/0.28.19/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
  44. package/releases/0.28.19/surfaces/blockchain/tree/.claude/graph.md +11 -0
  45. package/releases/0.28.19/surfaces/blockchain/tree/.claude/router.md +9 -0
  46. package/releases/0.28.19/surfaces/blockchain/tree/CLAUDE.md +12 -0
  47. package/releases/0.28.19/surfaces/db/tree/.claude/agents/architect.md +8 -0
  48. package/releases/0.28.19/surfaces/db/tree/.claude/agents/dba.md +84 -0
  49. package/releases/0.28.19/surfaces/db/tree/.claude/agents/devops.md +14 -0
  50. package/releases/0.28.19/surfaces/db/tree/.claude/agents/implementer.md +5 -0
  51. package/releases/0.28.19/surfaces/db/tree/.claude/agents/integration-tester.md +13 -0
  52. package/releases/0.28.19/surfaces/db/tree/.claude/agents/planner.md +2 -0
  53. package/releases/0.28.19/surfaces/db/tree/.claude/agents/reviewer.md +25 -0
  54. package/releases/0.28.19/surfaces/db/tree/.claude/agents/secops.md +2 -0
  55. package/releases/0.28.19/surfaces/db/tree/.claude/agents-overview.md +5 -0
  56. package/releases/0.28.19/surfaces/db/tree/.claude/graph.md +8 -0
  57. package/releases/0.28.19/surfaces/db/tree/.claude/patterns.md +29 -0
  58. package/releases/0.28.19/surfaces/db/tree/.claude/pipeline.md +13 -0
  59. package/releases/0.28.19/surfaces/db/tree/.claude/retrieval.md +5 -0
  60. package/releases/0.28.19/surfaces/db/tree/.claude/router.md +10 -0
  61. package/releases/0.28.19/surfaces/db/tree/CLAUDE.md +23 -0
  62. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
  63. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
  64. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/agents/devops.md +31 -0
  65. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
  66. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
  67. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
  68. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
  69. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
  70. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
  71. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
  72. package/releases/0.28.19/surfaces/edge-cf/tree/.claude/router.md +21 -0
  73. package/releases/0.28.19/surfaces/edge-cf/tree/CLAUDE.md +27 -0
  74. package/releases/0.28.19/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
  75. package/releases/0.28.19/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
  76. package/releases/0.28.19/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
  77. package/releases/0.28.19/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
  78. package/releases/0.28.19/surfaces/frontend/tree/.claude/agents/reviewer.md +62 -0
  79. package/releases/0.28.19/surfaces/frontend/tree/.claude/patterns.md +15 -0
  80. package/releases/0.28.19/surfaces/frontend/tree/.claude/retrieval.md +5 -0
  81. package/releases/0.28.19/surfaces/frontend/tree/.claude/router.md +17 -0
  82. package/releases/0.28.19/surfaces/frontend/tree/CLAUDE.md +5 -0
  83. package/releases/0.28.19/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
  84. package/releases/0.28.19/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
  85. package/releases/0.28.19/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
  86. package/releases/0.28.19/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
  87. package/releases/0.28.19/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
  88. package/releases/0.28.19/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
  89. package/releases/0.28.19/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
  90. package/releases/0.28.19/surfaces/integrations/tree/.claude/graph.md +9 -0
  91. package/releases/0.28.19/surfaces/integrations/tree/.claude/patterns.md +38 -0
  92. package/releases/0.28.19/surfaces/integrations/tree/.claude/pipeline.md +16 -0
  93. package/releases/0.28.19/surfaces/integrations/tree/.claude/retrieval.md +16 -0
  94. package/releases/0.28.19/surfaces/integrations/tree/.claude/router.md +6 -0
  95. package/releases/0.28.19/surfaces/integrations/tree/CLAUDE.md +17 -0
  96. package/releases/0.28.19/surfaces/money/tree/.claude/agents/architect.md +12 -0
  97. package/releases/0.28.19/surfaces/money/tree/.claude/agents/dba.md +14 -0
  98. package/releases/0.28.19/surfaces/money/tree/.claude/agents/implementer.md +11 -0
  99. package/releases/0.28.19/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
  100. package/releases/0.28.19/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
  101. package/releases/0.28.19/surfaces/money/tree/.claude/agents/secops.md +5 -0
  102. package/releases/0.28.19/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
  103. package/releases/0.28.19/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
  104. package/releases/0.28.19/surfaces/money/tree/.claude/graph.md +2 -0
  105. package/releases/0.28.19/surfaces/money/tree/.claude/patterns.md +49 -0
  106. package/releases/0.28.19/surfaces/money/tree/.claude/pipeline.md +2 -0
  107. package/releases/0.28.19/surfaces/money/tree/.claude/retrieval.md +2 -0
  108. package/releases/0.28.19/surfaces/money/tree/CLAUDE.md +11 -0
  109. package/releases/0.28.19/surfaces/pii/tree/.claude/agents/dba.md +2 -0
  110. package/releases/0.28.19/surfaces/pii/tree/.claude/agents/devops.md +8 -0
  111. package/releases/0.28.19/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
  112. package/releases/0.28.19/surfaces/pii/tree/.claude/agents/secops.md +2 -0
  113. package/releases/0.28.19/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
  114. package/releases/0.28.19/surfaces/pii/tree/CLAUDE.md +5 -0
  115. package/releases/0.28.20/core/GAPS.md +125 -0
  116. package/releases/0.28.20/core/answered.json +29 -0
  117. package/releases/0.28.20/core/defaults/tree/.claude/agents/architect.md +1 -0
  118. package/releases/0.28.20/core/defaults/tree/.claude/agents/dba.md +3 -0
  119. package/releases/0.28.20/core/defaults/tree/.claude/agents/devops.md +1 -0
  120. package/releases/0.28.20/core/defaults/tree/.claude/agents/implementer.md +1 -0
  121. package/releases/0.28.20/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
  122. package/releases/0.28.20/core/defaults/tree/.claude/agents/qa.md +2 -0
  123. package/releases/0.28.20/core/defaults/tree/.claude/agents/reviewer.md +3 -0
  124. package/releases/0.28.20/core/defaults/tree/.claude/agents/secops.md +3 -0
  125. package/releases/0.28.20/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
  126. package/releases/0.28.20/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
  127. package/releases/0.28.20/core/tree/.claude/agents/architect.md +125 -0
  128. package/releases/0.28.20/core/tree/.claude/agents/dba.md +107 -0
  129. package/releases/0.28.20/core/tree/.claude/agents/devops.md +113 -0
  130. package/releases/0.28.20/core/tree/.claude/agents/implementer.md +155 -0
  131. package/releases/0.28.20/core/tree/.claude/agents/integration-tester.md +160 -0
  132. package/releases/0.28.20/core/tree/.claude/agents/planner.md +132 -0
  133. package/releases/0.28.20/core/tree/.claude/agents/qa.md +146 -0
  134. package/releases/0.28.20/core/tree/.claude/agents/reviewer.md +180 -0
  135. package/releases/0.28.20/core/tree/.claude/agents/secops.md +121 -0
  136. package/releases/0.28.20/core/tree/.claude/agents/solidity-auditor.md +126 -0
  137. package/releases/0.28.20/core/tree/.claude/agents/solidity-dev.md +123 -0
  138. package/releases/0.28.20/core/tree/.claude/agents-overview.md +64 -0
  139. package/releases/0.28.20/core/tree/.claude/graph.md +73 -0
  140. package/releases/0.28.20/core/tree/.claude/patterns.md +212 -0
  141. package/releases/0.28.20/core/tree/.claude/pills/README.md +145 -0
  142. package/releases/0.28.20/core/tree/.claude/pipeline.md +102 -0
  143. package/releases/0.28.20/core/tree/.claude/retrieval.md +104 -0
  144. package/releases/0.28.20/core/tree/.claude/router.md +201 -0
  145. package/releases/0.28.20/core/tree/.claude/templates/integration.md +45 -0
  146. package/releases/0.28.20/core/tree/CLAUDE.md +155 -0
  147. package/releases/0.28.20/core/tree/scripts/edit-guard.mjs +16 -0
  148. package/releases/0.28.20/core/tree/scripts/harness-check.mjs +71 -0
  149. package/releases/0.28.20/core/tree/scripts/loop-gate.mjs +19 -0
  150. package/releases/0.28.20/core/vocabulary.json +12 -0
  151. package/releases/0.28.20/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
  152. package/releases/0.28.20/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
  153. package/releases/0.28.20/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
  154. package/releases/0.28.20/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
  155. package/releases/0.28.20/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
  156. package/releases/0.28.20/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
  157. package/releases/0.28.20/surfaces/blockchain/tree/.claude/graph.md +11 -0
  158. package/releases/0.28.20/surfaces/blockchain/tree/.claude/router.md +9 -0
  159. package/releases/0.28.20/surfaces/blockchain/tree/CLAUDE.md +12 -0
  160. package/releases/0.28.20/surfaces/db/tree/.claude/agents/architect.md +8 -0
  161. package/releases/0.28.20/surfaces/db/tree/.claude/agents/dba.md +84 -0
  162. package/releases/0.28.20/surfaces/db/tree/.claude/agents/devops.md +14 -0
  163. package/releases/0.28.20/surfaces/db/tree/.claude/agents/implementer.md +5 -0
  164. package/releases/0.28.20/surfaces/db/tree/.claude/agents/integration-tester.md +13 -0
  165. package/releases/0.28.20/surfaces/db/tree/.claude/agents/planner.md +2 -0
  166. package/releases/0.28.20/surfaces/db/tree/.claude/agents/reviewer.md +25 -0
  167. package/releases/0.28.20/surfaces/db/tree/.claude/agents/secops.md +2 -0
  168. package/releases/0.28.20/surfaces/db/tree/.claude/agents-overview.md +5 -0
  169. package/releases/0.28.20/surfaces/db/tree/.claude/graph.md +8 -0
  170. package/releases/0.28.20/surfaces/db/tree/.claude/patterns.md +29 -0
  171. package/releases/0.28.20/surfaces/db/tree/.claude/pipeline.md +13 -0
  172. package/releases/0.28.20/surfaces/db/tree/.claude/retrieval.md +5 -0
  173. package/releases/0.28.20/surfaces/db/tree/.claude/router.md +10 -0
  174. package/releases/0.28.20/surfaces/db/tree/CLAUDE.md +23 -0
  175. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
  176. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
  177. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/agents/devops.md +31 -0
  178. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
  179. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
  180. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
  181. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
  182. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
  183. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
  184. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
  185. package/releases/0.28.20/surfaces/edge-cf/tree/.claude/router.md +21 -0
  186. package/releases/0.28.20/surfaces/edge-cf/tree/CLAUDE.md +27 -0
  187. package/releases/0.28.20/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
  188. package/releases/0.28.20/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
  189. package/releases/0.28.20/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
  190. package/releases/0.28.20/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
  191. package/releases/0.28.20/surfaces/frontend/tree/.claude/agents/reviewer.md +62 -0
  192. package/releases/0.28.20/surfaces/frontend/tree/.claude/patterns.md +15 -0
  193. package/releases/0.28.20/surfaces/frontend/tree/.claude/retrieval.md +5 -0
  194. package/releases/0.28.20/surfaces/frontend/tree/.claude/router.md +17 -0
  195. package/releases/0.28.20/surfaces/frontend/tree/CLAUDE.md +5 -0
  196. package/releases/0.28.20/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
  197. package/releases/0.28.20/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
  198. package/releases/0.28.20/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
  199. package/releases/0.28.20/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
  200. package/releases/0.28.20/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
  201. package/releases/0.28.20/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
  202. package/releases/0.28.20/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
  203. package/releases/0.28.20/surfaces/integrations/tree/.claude/graph.md +9 -0
  204. package/releases/0.28.20/surfaces/integrations/tree/.claude/patterns.md +38 -0
  205. package/releases/0.28.20/surfaces/integrations/tree/.claude/pipeline.md +16 -0
  206. package/releases/0.28.20/surfaces/integrations/tree/.claude/retrieval.md +16 -0
  207. package/releases/0.28.20/surfaces/integrations/tree/.claude/router.md +6 -0
  208. package/releases/0.28.20/surfaces/integrations/tree/CLAUDE.md +17 -0
  209. package/releases/0.28.20/surfaces/money/tree/.claude/agents/architect.md +12 -0
  210. package/releases/0.28.20/surfaces/money/tree/.claude/agents/dba.md +14 -0
  211. package/releases/0.28.20/surfaces/money/tree/.claude/agents/implementer.md +11 -0
  212. package/releases/0.28.20/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
  213. package/releases/0.28.20/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
  214. package/releases/0.28.20/surfaces/money/tree/.claude/agents/secops.md +5 -0
  215. package/releases/0.28.20/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
  216. package/releases/0.28.20/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
  217. package/releases/0.28.20/surfaces/money/tree/.claude/graph.md +2 -0
  218. package/releases/0.28.20/surfaces/money/tree/.claude/patterns.md +49 -0
  219. package/releases/0.28.20/surfaces/money/tree/.claude/pipeline.md +2 -0
  220. package/releases/0.28.20/surfaces/money/tree/.claude/retrieval.md +2 -0
  221. package/releases/0.28.20/surfaces/money/tree/CLAUDE.md +11 -0
  222. package/releases/0.28.20/surfaces/pii/tree/.claude/agents/dba.md +2 -0
  223. package/releases/0.28.20/surfaces/pii/tree/.claude/agents/devops.md +8 -0
  224. package/releases/0.28.20/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
  225. package/releases/0.28.20/surfaces/pii/tree/.claude/agents/secops.md +2 -0
  226. package/releases/0.28.20/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
  227. package/releases/0.28.20/surfaces/pii/tree/CLAUDE.md +5 -0
  228. package/src/commands/pipeline.mjs +192 -59
  229. package/src/commands/stats.mjs +83 -48
  230. package/src/graph.mjs +16 -1
  231. package/src/look.mjs +118 -0
package/src/graph.mjs CHANGED
@@ -24,6 +24,13 @@ const STAGE = /^- `([a-z][a-z-]*)` — /;
24
24
  */
25
25
  const EDGE = /^- `([a-z][a-z-]*)` → `([a-z][a-z-]*)` on `([A-Z][A-Z-]*)`(?: — (.*?))?(?: · max (\d+))?\s*$/;
26
26
 
27
+ /**
28
+ * A line under "## Concurrency" naming a stage that may run as several agents at once, each on a share of
29
+ * the work: "- `name` × many — when". Declared rather than left to the prose, so a drawing of the pipeline
30
+ * can show it and `check` can hold it to the stages.
31
+ */
32
+ const MANY = /^- `([a-z][a-z-]*)` × many — (.*)$/;
33
+
27
34
  /** Where work may end: finished, or handed to the owner. Neither needs a spec. */
28
35
  export const TERMINALS = new Set(['done', 'human']);
29
36
 
@@ -40,6 +47,8 @@ export function parseGraph(text) {
40
47
  const stages = new Set();
41
48
  const edges = [];
42
49
  const stray = [];
50
+ /** @type {Map<string, {when: string, line: number}>} */
51
+ const many = new Map();
43
52
  const sections = new Set();
44
53
  const twice = [];
45
54
  let section = '';
@@ -61,9 +70,12 @@ export function parseGraph(text) {
61
70
  return;
62
71
  }
63
72
  edges.push({ from: m[1], to: m[2], token: m[3], when: m[4] ?? '', max: m[5] ? Number(m[5]) : null, line: i + 1 });
73
+ } else if (section === 'concurrency') {
74
+ const m = MANY.exec(line);
75
+ if (m) many.set(m[1], { when: m[2].trim(), line: i + 1 });
64
76
  }
65
77
  });
66
- return { stages, edges, stray, sections, twice };
78
+ return { stages, edges, stray, sections, twice, many };
67
79
  }
68
80
 
69
81
  /**
@@ -122,6 +134,9 @@ export function validateGraph(graph, specs, roles = new Set()) {
122
134
  for (const s of graph.twice ?? []) problems.push(`stage \`${s}\` is listed more than once`);
123
135
 
124
136
  for (const s of stray) problems.push(`graph.md:${s.line} is under "## Edges" but is not an edge: ${s.text}`);
137
+ for (const [s, { line }] of graph.many ?? []) {
138
+ if (!stages.has(s)) problems.push(`graph.md:${line} says \`${s}\` runs as several agents, and it is not a stage here`);
139
+ }
125
140
 
126
141
  // Every stage is a spec on disk and every spec on disk is a stage — the profile decides both, so
127
142
  // a mismatch means a layer named a stage the profile does not compose, or composed one no edge
package/src/look.mjs ADDED
@@ -0,0 +1,118 @@
1
+ /**
2
+ * How a report looks on a terminal: the banner's pink for stage names and section marks, dim for what
3
+ * explains, amber for what needs looking at, bars for shares, and lines wrapped to the window.
4
+ *
5
+ * Only on a terminal, and never under `NO_COLOR`. Piped, a report is the same lines, uncoloured and
6
+ * unwrapped, so `grep` still finds a whole sentence and a test still reads it; the bars stay, since a
7
+ * block character reads the same anywhere.
8
+ */
9
+
10
+ import { PINK, useColor } from './banner.mjs';
11
+
12
+ /** An amber for what needs looking at, and a green for what is sound: bright enough on dark and light. */
13
+ const AMBER = [230, 160, 40];
14
+ const GREEN = [90, 180, 110];
15
+
16
+ const rgb = ([r, g, b], s) => (useColor() ? `\x1b[38;2;${r};${g};${b}m${s}\x1b[0m` : String(s));
17
+
18
+ /** Text in the banner's pink: a stage's name, a section's mark. */
19
+ export const pink = (s) => rgb(PINK, s);
20
+ /** Text that explains rather than reports. */
21
+ export const dim = (s) => (useColor() ? `\x1b[2m${s}\x1b[0m` : String(s));
22
+ /** Text that carries the number a line is about. */
23
+ export const bold = (s) => (useColor() ? `\x1b[1m${s}\x1b[0m` : String(s));
24
+ /** Text that needs looking at. */
25
+ export const amber = (s) => rgb(AMBER, s);
26
+ /** Text that says something is sound. */
27
+ export const green = (s) => rgb(GREEN, s);
28
+
29
+ /** The width lines wrap at on a terminal; a pipe is never wrapped. */
30
+ const width = () => Math.max(80, Math.min(process.stdout.columns ?? 120, 140));
31
+
32
+ /**
33
+ * A section's heading: its name, and what the section is about. Printed plain it reads as it always did,
34
+ * "name — what"; on a terminal the name is marked and the explanation dimmed.
35
+ *
36
+ * @param {string} name - The section.
37
+ * @param {string} [about] - What it covers.
38
+ * @returns {string}
39
+ */
40
+ export function heading(name, about = '') {
41
+ if (!useColor()) return `\n ${name}${about ? ` — ${about}` : ''}`;
42
+ const lead = ` ▌ ${name} `;
43
+ return `\n${pink(' ▌')} ${bold(pink(name))}${about ? ` ${dim(wrapped(`— ${about}`, lead.length, lead.length + 2))}` : ''}`;
44
+ }
45
+
46
+ /**
47
+ * A line of prose under a section, wrapped to the window on a terminal with its continuation indented
48
+ * under its first word, and marked: `·` for what it reports, `!` in amber for what needs looking at, `✓`
49
+ * in green for what is sound.
50
+ *
51
+ * @param {string} text - The sentence.
52
+ * @param {'info'|'warn'|'ok'} [kind] - What it is.
53
+ * @returns {string}
54
+ */
55
+ export function note(text, kind = 'info') {
56
+ if (!useColor()) return ` ${text}`;
57
+ const mark = kind === 'warn' ? amber('!') : kind === 'ok' ? green('✓') : dim('·');
58
+ const body = wrapped(text, 6, 6);
59
+ return ` ${mark} ${kind === 'warn' ? amber(body) : body}`;
60
+ }
61
+
62
+ /**
63
+ * Wraps text at the window's width. The first line starts `first` columns in; the rest are indented by
64
+ * `rest`. Words are never split.
65
+ *
66
+ * @param {string} text - The text.
67
+ * @param {number} first - Where the first line starts.
68
+ * @param {number} rest - The indent of every other line.
69
+ * @returns {string}
70
+ */
71
+ export function wrapped(text, first, rest) {
72
+ const room = width();
73
+ const lines = [];
74
+ let line = '';
75
+ let at = first;
76
+ for (const word of text.split(' ')) {
77
+ if (line && at + line.length + 1 + word.length > room) {
78
+ lines.push(line);
79
+ line = word;
80
+ at = rest;
81
+ } else line = line ? `${line} ${word}` : word;
82
+ }
83
+ lines.push(line);
84
+ return lines.join(`\n${' '.repeat(rest)}`);
85
+ }
86
+
87
+ /** Eighths of a block, for the fraction a bar ends on. */
88
+ const EIGHTHS = ['', '▏', '▎', '▍', '▌', '▋', '▊', '▉'];
89
+
90
+ /**
91
+ * A bar as long as a share of `cells`, ending on an eighth of a block.
92
+ *
93
+ * @param {number} fraction - From 0 to 1.
94
+ * @param {number} cells - How long a whole one is.
95
+ * @returns {string}
96
+ */
97
+ export function bar(fraction, cells) {
98
+ const eighths = Math.round(Math.max(0, Math.min(1, fraction)) * cells * 8);
99
+ return `${'█'.repeat(Math.floor(eighths / 8))}${EIGHTHS[eighths % 8]}`;
100
+ }
101
+
102
+ /**
103
+ * A bar split into parts, one character per part so it reads uncoloured: `█` for what went forward, `▓`
104
+ * for what was sent back, `░` for what said nothing readable. Each part is at least one cell when it is
105
+ * not zero, so a single run sent back in a hundred still shows.
106
+ *
107
+ * @param {{n: number, char: string, paint: (s: string) => string}[]} parts - In order.
108
+ * @param {number} cells - How long the bar is.
109
+ * @returns {string}
110
+ */
111
+ export function stacked(parts, cells) {
112
+ const total = parts.reduce((a, p) => a + p.n, 0);
113
+ if (total === 0 || cells <= 0) return '';
114
+ const sizes = parts.map((p) => (p.n > 0 ? Math.max(1, Math.round((p.n / total) * cells)) : 0));
115
+ // Trim the rounding back to the length asked for, from the largest part.
116
+ while (sizes.reduce((a, b) => a + b, 0) > cells) sizes[sizes.indexOf(Math.max(...sizes))] -= 1;
117
+ return parts.map((p, i) => p.paint(p.char.repeat(sizes[i]))).join('');
118
+ }