@xhulz/nina 0.28.16 → 0.28.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/nina.mjs +2 -0
- package/package.json +1 -1
- package/releases/0.28.17/core/GAPS.md +125 -0
- package/releases/0.28.17/core/answered.json +29 -0
- package/releases/0.28.17/core/defaults/tree/.claude/agents/architect.md +1 -0
- package/releases/0.28.17/core/defaults/tree/.claude/agents/dba.md +3 -0
- package/releases/0.28.17/core/defaults/tree/.claude/agents/devops.md +1 -0
- package/releases/0.28.17/core/defaults/tree/.claude/agents/implementer.md +1 -0
- package/releases/0.28.17/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.28.17/core/defaults/tree/.claude/agents/qa.md +2 -0
- package/releases/0.28.17/core/defaults/tree/.claude/agents/reviewer.md +3 -0
- package/releases/0.28.17/core/defaults/tree/.claude/agents/secops.md +3 -0
- package/releases/0.28.17/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
- package/releases/0.28.17/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
- package/releases/0.28.17/core/tree/.claude/agents/architect.md +125 -0
- package/releases/0.28.17/core/tree/.claude/agents/dba.md +107 -0
- package/releases/0.28.17/core/tree/.claude/agents/devops.md +113 -0
- package/releases/0.28.17/core/tree/.claude/agents/implementer.md +155 -0
- package/releases/0.28.17/core/tree/.claude/agents/integration-tester.md +160 -0
- package/releases/0.28.17/core/tree/.claude/agents/planner.md +132 -0
- package/releases/0.28.17/core/tree/.claude/agents/qa.md +146 -0
- package/releases/0.28.17/core/tree/.claude/agents/reviewer.md +180 -0
- package/releases/0.28.17/core/tree/.claude/agents/secops.md +121 -0
- package/releases/0.28.17/core/tree/.claude/agents/solidity-auditor.md +126 -0
- package/releases/0.28.17/core/tree/.claude/agents/solidity-dev.md +123 -0
- package/releases/0.28.17/core/tree/.claude/agents-overview.md +64 -0
- package/releases/0.28.17/core/tree/.claude/graph.md +72 -0
- package/releases/0.28.17/core/tree/.claude/patterns.md +212 -0
- package/releases/0.28.17/core/tree/.claude/pills/README.md +145 -0
- package/releases/0.28.17/core/tree/.claude/pipeline.md +102 -0
- package/releases/0.28.17/core/tree/.claude/retrieval.md +104 -0
- package/releases/0.28.17/core/tree/.claude/router.md +201 -0
- package/releases/0.28.17/core/tree/.claude/templates/integration.md +45 -0
- package/releases/0.28.17/core/tree/CLAUDE.md +155 -0
- package/releases/0.28.17/core/tree/scripts/edit-guard.mjs +16 -0
- package/releases/0.28.17/core/tree/scripts/harness-check.mjs +71 -0
- package/releases/0.28.17/core/tree/scripts/loop-gate.mjs +19 -0
- package/releases/0.28.17/core/vocabulary.json +12 -0
- package/releases/0.28.17/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
- package/releases/0.28.17/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
- package/releases/0.28.17/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
- package/releases/0.28.17/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
- package/releases/0.28.17/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
- package/releases/0.28.17/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
- package/releases/0.28.17/surfaces/blockchain/tree/.claude/graph.md +11 -0
- package/releases/0.28.17/surfaces/blockchain/tree/.claude/router.md +9 -0
- package/releases/0.28.17/surfaces/blockchain/tree/CLAUDE.md +12 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/agents/architect.md +8 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/agents/dba.md +84 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/agents/devops.md +14 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/agents/implementer.md +5 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/agents/integration-tester.md +13 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/agents/planner.md +2 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/agents/reviewer.md +25 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/agents/secops.md +2 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/agents-overview.md +5 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/graph.md +8 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/patterns.md +29 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/pipeline.md +13 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/retrieval.md +5 -0
- package/releases/0.28.17/surfaces/db/tree/.claude/router.md +10 -0
- package/releases/0.28.17/surfaces/db/tree/CLAUDE.md +23 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/agents/devops.md +31 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/.claude/router.md +21 -0
- package/releases/0.28.17/surfaces/edge-cf/tree/CLAUDE.md +27 -0
- package/releases/0.28.17/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
- package/releases/0.28.17/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
- package/releases/0.28.17/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
- package/releases/0.28.17/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
- package/releases/0.28.17/surfaces/frontend/tree/.claude/agents/reviewer.md +62 -0
- package/releases/0.28.17/surfaces/frontend/tree/.claude/patterns.md +15 -0
- package/releases/0.28.17/surfaces/frontend/tree/.claude/retrieval.md +5 -0
- package/releases/0.28.17/surfaces/frontend/tree/.claude/router.md +17 -0
- package/releases/0.28.17/surfaces/frontend/tree/CLAUDE.md +5 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/graph.md +9 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/patterns.md +38 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/pipeline.md +16 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/retrieval.md +16 -0
- package/releases/0.28.17/surfaces/integrations/tree/.claude/router.md +6 -0
- package/releases/0.28.17/surfaces/integrations/tree/CLAUDE.md +17 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/agents/architect.md +12 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/agents/dba.md +14 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/agents/implementer.md +11 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/agents/secops.md +5 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/graph.md +2 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/patterns.md +49 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/pipeline.md +2 -0
- package/releases/0.28.17/surfaces/money/tree/.claude/retrieval.md +2 -0
- package/releases/0.28.17/surfaces/money/tree/CLAUDE.md +11 -0
- package/releases/0.28.17/surfaces/pii/tree/.claude/agents/dba.md +2 -0
- package/releases/0.28.17/surfaces/pii/tree/.claude/agents/devops.md +8 -0
- package/releases/0.28.17/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.28.17/surfaces/pii/tree/.claude/agents/secops.md +2 -0
- package/releases/0.28.17/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
- package/releases/0.28.17/surfaces/pii/tree/CLAUDE.md +5 -0
- package/releases/0.28.18/core/GAPS.md +125 -0
- package/releases/0.28.18/core/answered.json +29 -0
- package/releases/0.28.18/core/defaults/tree/.claude/agents/architect.md +1 -0
- package/releases/0.28.18/core/defaults/tree/.claude/agents/dba.md +3 -0
- package/releases/0.28.18/core/defaults/tree/.claude/agents/devops.md +1 -0
- package/releases/0.28.18/core/defaults/tree/.claude/agents/implementer.md +1 -0
- package/releases/0.28.18/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.28.18/core/defaults/tree/.claude/agents/qa.md +2 -0
- package/releases/0.28.18/core/defaults/tree/.claude/agents/reviewer.md +3 -0
- package/releases/0.28.18/core/defaults/tree/.claude/agents/secops.md +3 -0
- package/releases/0.28.18/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
- package/releases/0.28.18/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
- package/releases/0.28.18/core/tree/.claude/agents/architect.md +125 -0
- package/releases/0.28.18/core/tree/.claude/agents/dba.md +107 -0
- package/releases/0.28.18/core/tree/.claude/agents/devops.md +113 -0
- package/releases/0.28.18/core/tree/.claude/agents/implementer.md +155 -0
- package/releases/0.28.18/core/tree/.claude/agents/integration-tester.md +160 -0
- package/releases/0.28.18/core/tree/.claude/agents/planner.md +132 -0
- package/releases/0.28.18/core/tree/.claude/agents/qa.md +146 -0
- package/releases/0.28.18/core/tree/.claude/agents/reviewer.md +180 -0
- package/releases/0.28.18/core/tree/.claude/agents/secops.md +121 -0
- package/releases/0.28.18/core/tree/.claude/agents/solidity-auditor.md +126 -0
- package/releases/0.28.18/core/tree/.claude/agents/solidity-dev.md +123 -0
- package/releases/0.28.18/core/tree/.claude/agents-overview.md +64 -0
- package/releases/0.28.18/core/tree/.claude/graph.md +72 -0
- package/releases/0.28.18/core/tree/.claude/patterns.md +212 -0
- package/releases/0.28.18/core/tree/.claude/pills/README.md +145 -0
- package/releases/0.28.18/core/tree/.claude/pipeline.md +102 -0
- package/releases/0.28.18/core/tree/.claude/retrieval.md +104 -0
- package/releases/0.28.18/core/tree/.claude/router.md +201 -0
- package/releases/0.28.18/core/tree/.claude/templates/integration.md +45 -0
- package/releases/0.28.18/core/tree/CLAUDE.md +155 -0
- package/releases/0.28.18/core/tree/scripts/edit-guard.mjs +16 -0
- package/releases/0.28.18/core/tree/scripts/harness-check.mjs +71 -0
- package/releases/0.28.18/core/tree/scripts/loop-gate.mjs +19 -0
- package/releases/0.28.18/core/vocabulary.json +12 -0
- package/releases/0.28.18/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
- package/releases/0.28.18/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
- package/releases/0.28.18/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
- package/releases/0.28.18/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
- package/releases/0.28.18/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
- package/releases/0.28.18/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
- package/releases/0.28.18/surfaces/blockchain/tree/.claude/graph.md +11 -0
- package/releases/0.28.18/surfaces/blockchain/tree/.claude/router.md +9 -0
- package/releases/0.28.18/surfaces/blockchain/tree/CLAUDE.md +12 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/agents/architect.md +8 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/agents/dba.md +84 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/agents/devops.md +14 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/agents/implementer.md +5 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/agents/integration-tester.md +13 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/agents/planner.md +2 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/agents/reviewer.md +25 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/agents/secops.md +2 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/agents-overview.md +5 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/graph.md +8 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/patterns.md +29 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/pipeline.md +13 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/retrieval.md +5 -0
- package/releases/0.28.18/surfaces/db/tree/.claude/router.md +10 -0
- package/releases/0.28.18/surfaces/db/tree/CLAUDE.md +23 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/agents/devops.md +31 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/.claude/router.md +21 -0
- package/releases/0.28.18/surfaces/edge-cf/tree/CLAUDE.md +27 -0
- package/releases/0.28.18/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
- package/releases/0.28.18/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
- package/releases/0.28.18/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
- package/releases/0.28.18/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
- package/releases/0.28.18/surfaces/frontend/tree/.claude/agents/reviewer.md +62 -0
- package/releases/0.28.18/surfaces/frontend/tree/.claude/patterns.md +15 -0
- package/releases/0.28.18/surfaces/frontend/tree/.claude/retrieval.md +5 -0
- package/releases/0.28.18/surfaces/frontend/tree/.claude/router.md +17 -0
- package/releases/0.28.18/surfaces/frontend/tree/CLAUDE.md +5 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/graph.md +9 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/patterns.md +38 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/pipeline.md +16 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/retrieval.md +16 -0
- package/releases/0.28.18/surfaces/integrations/tree/.claude/router.md +6 -0
- package/releases/0.28.18/surfaces/integrations/tree/CLAUDE.md +17 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/agents/architect.md +12 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/agents/dba.md +14 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/agents/implementer.md +11 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/agents/secops.md +5 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/graph.md +2 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/patterns.md +49 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/pipeline.md +2 -0
- package/releases/0.28.18/surfaces/money/tree/.claude/retrieval.md +2 -0
- package/releases/0.28.18/surfaces/money/tree/CLAUDE.md +11 -0
- package/releases/0.28.18/surfaces/pii/tree/.claude/agents/dba.md +2 -0
- package/releases/0.28.18/surfaces/pii/tree/.claude/agents/devops.md +8 -0
- package/releases/0.28.18/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.28.18/surfaces/pii/tree/.claude/agents/secops.md +2 -0
- package/releases/0.28.18/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
- package/releases/0.28.18/surfaces/pii/tree/CLAUDE.md +5 -0
- package/src/commands/pipeline.mjs +232 -0
- package/src/commands/wire.mjs +1 -1
- package/src/wiring.mjs +5 -2
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nina pipeline` — draws a project's agent chain: the line work moves along, the gates it passes on the
|
|
3
|
+
* way, where each stage sends work back and how many rounds it may, each stage's model, effort and skills,
|
|
4
|
+
* and which chain a task of each shape takes.
|
|
5
|
+
*
|
|
6
|
+
* Opening a project, the pipeline was a graph, a router, ten specs and a table in CLAUDE.md to read before
|
|
7
|
+
* anyone could say which stage came after which, on which model, with which skills. Every fact here is
|
|
8
|
+
* already composed, and `nina check` already holds it to the graph; this only reads it back and draws it.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
12
|
+
import { basename, join, resolve } from 'node:path';
|
|
13
|
+
import { PINK, useColor } from '../banner.mjs';
|
|
14
|
+
import { HARNESS } from '../paths.mjs';
|
|
15
|
+
import { TERMINALS, parseGraph } from '../graph.mjs';
|
|
16
|
+
import { required } from '../tools.mjs';
|
|
17
|
+
import { isLoopBack } from '../transcripts.mjs';
|
|
18
|
+
import { frontmatter } from './pills.mjs';
|
|
19
|
+
|
|
20
|
+
/** A stage line under "## Stages": "- `name` — what it does". */
|
|
21
|
+
const STAGE_LINE = /^- `([a-z][a-z-]*)` — (.*)$/;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* What each stage does, in the graph's own words: shorter than a spec's `description:`, which is written
|
|
25
|
+
* for Claude Code to choose an agent by.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} text - The composed `.claude/graph.md`.
|
|
28
|
+
* @returns {Map<string, string>}
|
|
29
|
+
*/
|
|
30
|
+
export function stageWords(text) {
|
|
31
|
+
const out = new Map();
|
|
32
|
+
let inStages = false;
|
|
33
|
+
for (const line of text.split('\n')) {
|
|
34
|
+
if (line.startsWith('## ')) inStages = line.slice(3).trim().toLowerCase() === 'stages';
|
|
35
|
+
else if (inStages) {
|
|
36
|
+
const m = STAGE_LINE.exec(line);
|
|
37
|
+
if (m) out.set(m[1], m[2].trim());
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The shape of the pipeline, read from its edges.
|
|
45
|
+
*
|
|
46
|
+
* - The line: from the first stage no forward edge reaches, the one forward edge each stage takes with no
|
|
47
|
+
* condition, until a stage has none.
|
|
48
|
+
* - The gates: a stage off the line that a line stage sends work to on a condition, and that hands it on
|
|
49
|
+
* to the next stage of the line.
|
|
50
|
+
* - The ends: where the line's last stage sends work on a condition, followed forward to a terminal.
|
|
51
|
+
* - The loop-backs: every edge on a verdict that sends work back, to a stage or to the owner.
|
|
52
|
+
*
|
|
53
|
+
* @param {{stages: Set<string>, edges: object[]}} graph - A parsed graph.
|
|
54
|
+
* @returns {{line: string[], gates: object[], ends: object[], back: object[]}}
|
|
55
|
+
*/
|
|
56
|
+
export function shapeOf(graph) {
|
|
57
|
+
const forward = graph.edges.filter((e) => !isLoopBack(e.token));
|
|
58
|
+
const order = [...graph.stages];
|
|
59
|
+
const start = order.find((s) => !forward.some((e) => e.to === s)) ?? order[0];
|
|
60
|
+
const line = start ? [start] : [];
|
|
61
|
+
for (;;) {
|
|
62
|
+
const next = forward.filter((e) => e.from === line.at(-1) && !e.when && !line.includes(e.to) && !TERMINALS.has(e.to));
|
|
63
|
+
if (next.length !== 1) break;
|
|
64
|
+
line.push(next[0].to);
|
|
65
|
+
}
|
|
66
|
+
const gates = [];
|
|
67
|
+
line.forEach((stage, i) => {
|
|
68
|
+
for (const e of forward.filter((e) => e.from === stage && e.when && !line.includes(e.to) && !TERMINALS.has(e.to))) {
|
|
69
|
+
if (i + 1 < line.length && forward.some((f) => f.from === e.to && f.to === line[i + 1])) gates.push({ from: stage, gate: e.to, to: line[i + 1], when: e.when });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
const last = line.at(-1);
|
|
73
|
+
const ends = forward
|
|
74
|
+
.filter((e) => e.from === last && e.when)
|
|
75
|
+
.map((e) => {
|
|
76
|
+
const path = [e.to];
|
|
77
|
+
while (!TERMINALS.has(path.at(-1))) {
|
|
78
|
+
const on = forward.filter((f) => f.from === path.at(-1) && !path.includes(f.to));
|
|
79
|
+
if (on.length !== 1) break;
|
|
80
|
+
path.push(on[0].to);
|
|
81
|
+
}
|
|
82
|
+
return { path, when: e.when };
|
|
83
|
+
});
|
|
84
|
+
// Grouped by the stage that sends the work back, in the order the stages are listed.
|
|
85
|
+
const back = graph.edges.filter((e) => isLoopBack(e.token)).sort((a, b) => order.indexOf(a.from) - order.indexOf(b.from));
|
|
86
|
+
return { line, gates, ends, back };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The rows of the "Required chain by task shape" table in a composed CLAUDE.md: the shape, and the chain it
|
|
91
|
+
* takes — the part the table sets in bold, where it does.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} text - The composed CLAUDE.md.
|
|
94
|
+
* @returns {{shape: string, chain: string}[]}
|
|
95
|
+
*/
|
|
96
|
+
export function chainsByShape(text) {
|
|
97
|
+
const at = text.indexOf('| Task shape |');
|
|
98
|
+
if (at === -1) return [];
|
|
99
|
+
const rows = [];
|
|
100
|
+
for (const row of text.slice(at).split('\n').slice(2)) {
|
|
101
|
+
if (!row.startsWith('|')) break;
|
|
102
|
+
const [shape = '', chain = ''] = row.split('|').slice(1).map((c) => c.trim());
|
|
103
|
+
const bold = /\*\*(.+?)\*\*/.exec(chain)?.[1];
|
|
104
|
+
const plain = (s) => s.replace(/\*\*/g, '').replace(/`/g, '').trim();
|
|
105
|
+
rows.push({ shape: plain(shape), chain: plain(bold ?? chain) });
|
|
106
|
+
}
|
|
107
|
+
return rows;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Runs the command.
|
|
112
|
+
*
|
|
113
|
+
* @param {string[]} argv - `[--project <dir>]`.
|
|
114
|
+
* @returns {Promise<number>} Process exit code.
|
|
115
|
+
*/
|
|
116
|
+
export async function pipeline(argv) {
|
|
117
|
+
const dir = resolve(argv.includes('--project') ? argv[argv.indexOf('--project') + 1] : process.cwd());
|
|
118
|
+
const graphPath = join(dir, '.claude', 'graph.md');
|
|
119
|
+
if (!existsSync(graphPath)) {
|
|
120
|
+
console.error(` no .claude/graph.md in ${dir} — this draws a composed pipeline: \`nina compose\` writes one`);
|
|
121
|
+
return 1;
|
|
122
|
+
}
|
|
123
|
+
const graph = parseGraph(readFileSync(graphPath, 'utf8'));
|
|
124
|
+
const words = stageWords(readFileSync(graphPath, 'utf8'));
|
|
125
|
+
const { line, gates, ends, back } = shapeOf(graph);
|
|
126
|
+
|
|
127
|
+
const color = useColor();
|
|
128
|
+
const name = (s) => (color && !TERMINALS.has(s) ? `\x1b[38;2;${PINK.join(';')}m${s}\x1b[0m` : s);
|
|
129
|
+
const dim = (s) => (color ? `\x1b[2m${s}\x1b[0m` : s);
|
|
130
|
+
const width = Math.max(80, Math.min(process.stdout.columns ?? 110, 140));
|
|
131
|
+
const fit = (s, room) => (s.length > room ? `${s.slice(0, Math.max(room - 1, 1))}…` : s);
|
|
132
|
+
const arrow = ' ─▶ ';
|
|
133
|
+
|
|
134
|
+
let profile = {};
|
|
135
|
+
try {
|
|
136
|
+
profile = JSON.parse(readFileSync(join(dir, HARNESS, 'profile.json'), 'utf8'));
|
|
137
|
+
} catch {
|
|
138
|
+
// A pipeline composed by hand draws all the same; only the header has less to say.
|
|
139
|
+
}
|
|
140
|
+
const surfaces = (profile.surfaces ?? []).slice().sort();
|
|
141
|
+
console.log(` pipeline · ${basename(dir)}${profile.core ? ` · core ${profile.core}` : ''}${surfaces.length ? ` · surfaces ${surfaces.join(', ')}` : ''}\n`);
|
|
142
|
+
|
|
143
|
+
// Alignment is counted on the plain text, and the names are painted after.
|
|
144
|
+
const padName = (s, n) => `${name(s)}${' '.repeat(Math.max(n - s.length, 1))}`;
|
|
145
|
+
|
|
146
|
+
// The line, and where its last stage sends work.
|
|
147
|
+
const plainHead = ` ${line.join(arrow)}`;
|
|
148
|
+
const head = ` ${line.map(name).join(arrow)}`;
|
|
149
|
+
if (ends.length === 0) console.log(head);
|
|
150
|
+
const lead = ' '.repeat(plainHead.length + 1);
|
|
151
|
+
const joint = (i) => (ends.length === 1 ? '──▶ ' : i === 0 ? '─┬─▶ ' : i === ends.length - 1 ? ' └─▶ ' : ' ├─▶ ');
|
|
152
|
+
const endCol = Math.max(0, ...ends.map((end, i) => `${lead}${joint(i)}${end.path.join(arrow)}`.length)) + 3;
|
|
153
|
+
ends.forEach((end, i) => {
|
|
154
|
+
const plain = `${lead}${joint(i)}${end.path.join(arrow)}`;
|
|
155
|
+
console.log(`${i === 0 ? `${head} ` : lead}${joint(i)}${end.path.map(name).join(arrow)}${' '.repeat(endCol - plain.length)}${dim(fit(end.when, width - endCol))}`);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
if (gates.length > 0) {
|
|
159
|
+
console.log(`\n ${dim('gates on the way, when the diff calls for them')}`);
|
|
160
|
+
const chain = (g) => `${g.from}${arrow}${g.gate}${arrow}${g.to}`;
|
|
161
|
+
const col = Math.max(...gates.map((g) => chain(g).length)) + 4;
|
|
162
|
+
for (const g of gates) {
|
|
163
|
+
console.log(` ${name(g.from)}${arrow}${name(g.gate)}${arrow}${name(g.to)}${' '.repeat(col - chain(g).length)}${dim(fit(g.when, width - col - 6))}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (back.length > 0) {
|
|
168
|
+
console.log(`\n ${dim('sent back: to whom, on which verdict, and how many rounds per issue')}`);
|
|
169
|
+
const fromCol = Math.max(...back.map((e) => e.from.length)) + 2;
|
|
170
|
+
const toCol = Math.max(...back.map((e) => e.to.length)) + 2;
|
|
171
|
+
const tokenCol = Math.max(...back.map((e) => e.token.length)) + 2;
|
|
172
|
+
let previous = '';
|
|
173
|
+
for (const e of back) {
|
|
174
|
+
const from = e.from === previous ? '' : e.from;
|
|
175
|
+
previous = e.from;
|
|
176
|
+
const rounds = e.to === 'human' ? '—' : e.max === null ? '?' : String(e.max);
|
|
177
|
+
const tail = `${e.token.padEnd(tokenCol)}${rounds.padStart(2)} `;
|
|
178
|
+
const used = 4 + fromCol + 2 + toCol + tail.length;
|
|
179
|
+
console.log(` ${from ? padName(from, fromCol) : ' '.repeat(fromCol)}↩ ${padName(e.to, toCol)}${tail}${dim(fit(e.when ?? '', width - used))}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Each stage: what it does, on which model and effort, with which skills.
|
|
184
|
+
const agentsDir = join(dir, '.claude', 'agents');
|
|
185
|
+
const specs = new Map();
|
|
186
|
+
for (const file of existsSync(agentsDir) ? readdirSync(agentsDir).filter((f) => f.endsWith('.md')).sort() : []) {
|
|
187
|
+
specs.set(file.replace(/\.md$/, ''), readFileSync(join(agentsDir, file), 'utf8'));
|
|
188
|
+
}
|
|
189
|
+
const stages = [...graph.stages];
|
|
190
|
+
const col = Math.max(...stages.map((s) => s.length), 10) + 2;
|
|
191
|
+
console.log(`\n ${dim('stages')}`);
|
|
192
|
+
for (const stage of stages) {
|
|
193
|
+
const spec = specs.get(stage) ?? '';
|
|
194
|
+
const front = frontmatter(spec) ?? {};
|
|
195
|
+
const runs = [front.model, front.effort].filter(Boolean).join(' · ') || 'no spec';
|
|
196
|
+
console.log(` ${padName(stage, col)}${runs.padEnd(26)}${dim(fit(words.get(stage) ?? '', width - col - 32))}`);
|
|
197
|
+
const skills = [...required(spec).skills].sort();
|
|
198
|
+
if (skills.length > 0) {
|
|
199
|
+
const lines = [];
|
|
200
|
+
let current = '';
|
|
201
|
+
for (const skill of skills) {
|
|
202
|
+
const next = current ? `${current} · ${skill}` : skill;
|
|
203
|
+
if (next.length > width - col - 16 && current) {
|
|
204
|
+
lines.push(current);
|
|
205
|
+
current = skill;
|
|
206
|
+
} else current = next;
|
|
207
|
+
}
|
|
208
|
+
lines.push(current);
|
|
209
|
+
lines.forEach((l, i) => console.log(` ${' '.repeat(col)}${dim(i === 0 ? 'skills ' : ' ')}${l}`));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// An agent the project wrote for itself is not a stage, and the graph does not route to it.
|
|
214
|
+
const own = [...specs.keys()].filter((role) => !graph.stages.has(role));
|
|
215
|
+
if (own.length > 0) {
|
|
216
|
+
console.log(`\n ${dim("the project's own agents, outside the pipeline")}`);
|
|
217
|
+
for (const role of own) {
|
|
218
|
+
const front = frontmatter(specs.get(role)) ?? {};
|
|
219
|
+
console.log(` ${role}${' '.repeat(Math.max(col - role.length, 2))}${dim(fit(front.description ?? '', width - col - 6))}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const claude = join(dir, 'CLAUDE.md');
|
|
224
|
+
const shapes = existsSync(claude) ? chainsByShape(readFileSync(claude, 'utf8')) : [];
|
|
225
|
+
if (shapes.length > 0) {
|
|
226
|
+
console.log(`\n ${dim('which chain a task takes, by its shape (CLAUDE.md)')}`);
|
|
227
|
+
const shapeCol = Math.min(Math.max(...shapes.map((r) => r.shape.length)), 58) + 2;
|
|
228
|
+
for (const r of shapes) console.log(` ${fit(r.shape, shapeCol - 2).padEnd(shapeCol)}${fit(r.chain, width - shapeCol - 6)}`);
|
|
229
|
+
}
|
|
230
|
+
console.log('');
|
|
231
|
+
return 0;
|
|
232
|
+
}
|
package/src/commands/wire.mjs
CHANGED
|
@@ -62,7 +62,7 @@ export async function wire(argv, ctx) {
|
|
|
62
62
|
if (missing.length > 0) console.log(` core ${version} needs, and this project does not have:\n`);
|
|
63
63
|
for (const m of missing) console.log(` ✗ ${m}`);
|
|
64
64
|
if (stale.length > 0) {
|
|
65
|
-
console.log(`\n ${stale.length} hook(s) run
|
|
65
|
+
console.log(`\n ${stale.length} hook(s) run a command an earlier version wrote, which does not say, or says wrongly, what to do when its script cannot start:`);
|
|
66
66
|
for (const s of stale) console.log(` · ${s}`);
|
|
67
67
|
}
|
|
68
68
|
const fragment = await missingFragment(target, shipped);
|
package/src/wiring.mjs
CHANGED
|
@@ -85,10 +85,13 @@ export function packageExports(target, module) {
|
|
|
85
85
|
const CANNOT_START = 'is @xhulz/nina installed in this project, and no older than the version .nina/profile.json pins? (pnpm add -D -E @xhulz/nina)';
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
*
|
|
89
|
-
* that file, which a project installing from npm has no copy of.
|
|
88
|
+
* Every sentence the hooks said before, oldest first. While NINA reached a project as a vendored `.tgz`, the
|
|
89
|
+
* command was to install that file, which a project installing from npm has no copy of. The first one was
|
|
90
|
+
* left out when the second replaced it, and the first project to be wired kept three hooks saying it through
|
|
91
|
+
* every `wire` after, until a move to npm looked for any hook that still named the `.tgz`.
|
|
90
92
|
*/
|
|
91
93
|
const EARLIER_CANNOT_START = [
|
|
94
|
+
'is @xhulz/nina installed in this project? (pnpm add -D file:vendor/xhulz-nina-<version>.tgz)',
|
|
92
95
|
'is @xhulz/nina installed in this project, and no older than the version .nina/profile.json pins? (pnpm add -D file:vendor/xhulz-nina-<version>.tgz)',
|
|
93
96
|
];
|
|
94
97
|
|