@mmerterden/multi-agent-pipeline 16.27.0 → 16.29.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 (65) hide show
  1. package/CHANGELOG.md +144 -1
  2. package/README.md +4 -4
  3. package/README.tr.md +3 -3
  4. package/docs/architecture.md +3 -3
  5. package/docs/ecosystem.md +5 -5
  6. package/install/claude.mjs +17 -0
  7. package/package.json +4 -4
  8. package/pipeline/commands/multi-agent/SKILL.md +1 -1
  9. package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +93 -0
  10. package/pipeline/commands/multi-agent/doctor/SKILL.md +78 -0
  11. package/pipeline/commands/multi-agent/help/SKILL.md +2 -0
  12. package/pipeline/commands/multi-agent/issue/SKILL.md +1 -0
  13. package/pipeline/commands/multi-agent/jira/SKILL.md +3 -0
  14. package/pipeline/commands/multi-agent/log/SKILL.md +7 -1
  15. package/pipeline/commands/multi-agent/review-issue/SKILL.md +1 -0
  16. package/pipeline/commands/multi-agent/setup/SKILL.md +14 -1
  17. package/pipeline/commands/multi-agent/sync/SKILL.md +12 -9
  18. package/pipeline/commands/multi-agent/update/SKILL.md +12 -0
  19. package/pipeline/lib/_jira-auth.sh +99 -0
  20. package/pipeline/lib/analysis-jira-write.sh +203 -0
  21. package/pipeline/lib/issue-fetcher.sh +138 -9
  22. package/pipeline/lib/multi-repo-pipeline.sh +8 -0
  23. package/pipeline/multi-agent-refs/analysis/evidence.md +1 -1
  24. package/pipeline/multi-agent-refs/analysis/intake.md +11 -2
  25. package/pipeline/multi-agent-refs/analysis/locked.md +1 -0
  26. package/pipeline/multi-agent-refs/analysis/redesign.md +112 -0
  27. package/pipeline/multi-agent-refs/analysis/render.md +6 -1
  28. package/pipeline/multi-agent-refs/analysis/resolve.md +1 -0
  29. package/pipeline/multi-agent-refs/analysis/review.md +15 -0
  30. package/pipeline/multi-agent-refs/analysis/synthesis.md +1 -1
  31. package/pipeline/multi-agent-refs/analysis-template-corporate.md +3 -3
  32. package/pipeline/multi-agent-refs/analysis-template.md +36 -0
  33. package/pipeline/multi-agent-refs/cross-cli-contract.md +6 -3
  34. package/pipeline/multi-agent-refs/features/analysis-jira.md +128 -0
  35. package/pipeline/multi-agent-refs/features/doctor.md +197 -0
  36. package/pipeline/multi-agent-refs/features/jira-context.md +101 -0
  37. package/pipeline/multi-agent-refs/features/model-fallback.md +2 -2
  38. package/pipeline/multi-agent-refs/phases/phase-0-init.md +9 -7
  39. package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +1 -1
  40. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +1 -1
  41. package/pipeline/multi-agent-refs/phases/phase-4-review.md +1 -1
  42. package/pipeline/multi-agent-refs/picker-contract.md +35 -0
  43. package/pipeline/multi-agent-refs/readiness-review.md +1 -1
  44. package/pipeline/multi-agent-refs/tracker-contract.md +5 -1
  45. package/pipeline/preferences-template.json +1 -1
  46. package/pipeline/schemas/agent-state.schema.json +24 -0
  47. package/pipeline/schemas/analysis-spec.schema.json +336 -95
  48. package/pipeline/schemas/prefs.schema.json +86 -2
  49. package/pipeline/scripts/analysis-story-tree.mjs +441 -0
  50. package/pipeline/scripts/anonymize-findings.mjs +24 -0
  51. package/pipeline/scripts/build-references.mjs +10 -6
  52. package/pipeline/scripts/council-view.mjs +144 -0
  53. package/pipeline/scripts/doctor.mjs +758 -0
  54. package/pipeline/scripts/phase-tracker.sh +100 -3
  55. package/pipeline/scripts/scan-agent-config.sh +48 -10
  56. package/pipeline/scripts/skill-siblings.mjs +42 -9
  57. package/pipeline/scripts/validate-analysis-doc.mjs +371 -7
  58. package/pipeline/scripts/validate-analysis.mjs +7 -5
  59. package/pipeline/skills/shared/core/multi-agent-analysis-jira/SKILL.md +94 -0
  60. package/pipeline/skills/shared/core/multi-agent-doctor/SKILL.md +79 -0
  61. package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +1 -0
  62. package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +1 -0
  63. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +13 -0
  64. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +9 -6
  65. package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +18 -0
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ // council-view.mjs - what each reviewer found, and what triage did with it.
3
+ //
4
+ // Phase 4 dispatches three reviewers, anonymizes their findings so the judge
5
+ // cannot mark its own homework, and reports the verdict. Everything needed to
6
+ // answer "which model found this, and was it kept" is already on the state -
7
+ // reviewers[].findings, anonymizationMap.labelToModel, triage.accepted - and
8
+ // nothing ever renders it. run-metrics.mjs reduces it to a ratio; the rows
9
+ // behind the ratio are not visible anywhere.
10
+ //
11
+ // This is the panel view llm-council shows as its stage-1 tabs, built from
12
+ // state that already exists. No model call, no new field, no new phase.
13
+ //
14
+ // De-anonymization is deliberate and safe here: the map is read AFTER triage
15
+ // has ruled, so nothing this prints can bias the judgement it describes. The
16
+ // map never goes into a prompt; this is a report.
17
+ //
18
+ // Usage:
19
+ // council-view.mjs <agent-state.json> [--json] [--iteration N]
20
+ //
21
+ // Exit codes: 0 rendered, 2 nothing to render (no review iterations), 64 usage.
22
+
23
+ import { readFileSync } from "node:fs";
24
+
25
+ const argv = process.argv.slice(2);
26
+ const JSON_OUT = argv.includes("--json");
27
+ const iterFlag = argv.indexOf("--iteration");
28
+ const ONLY = iterFlag !== -1 ? Number(argv[iterFlag + 1]) : null;
29
+ const file = argv.find((a) => !a.startsWith("--") && a !== String(ONLY));
30
+ // `--iteration` with nothing after it made ONLY NaN, and `it.iteration === NaN`
31
+ // is never true, so a state full of iterations exited 2 - which /multi-agent:log
32
+ // is told to read as "the run never reached Phase 4" and quietly omit. A usage
33
+ // error has to look like one.
34
+ const BAD_ITERATION = iterFlag !== -1 && !Number.isInteger(ONLY);
35
+
36
+ function die(msg, code) {
37
+ process.stderr.write(msg + "\n");
38
+ process.exitCode = code;
39
+ }
40
+
41
+ function verdictOf(triage, fingerprint, issue, fileName) {
42
+ for (const bucket of ["accepted", "deferred", "rejected"]) {
43
+ for (const entry of Array.isArray(triage?.[bucket]) ? triage[bucket] : []) {
44
+ // Only `accepted[]` is a flat finding. triage-output.schema.json defines a
45
+ // deferred or rejected item as `{ finding, reason }` - the reason is the
46
+ // point of those buckets - so reading the id off the wrapper made every
47
+ // ruled-out finding render as `unruled`, which is exactly the column this
48
+ // view exists to show.
49
+ const f = entry?.finding ?? entry;
50
+ if (fingerprint && f?.fingerprint === fingerprint) return bucket;
51
+ if (!fingerprint && f?.file === fileName && f?.issue === issue) return bucket;
52
+ }
53
+ }
54
+ return "unruled";
55
+ }
56
+
57
+ function main() {
58
+ if (!file) return die("usage: council-view.mjs <agent-state.json> [--json] [--iteration N]", 64);
59
+ if (BAD_ITERATION) return die("council-view: --iteration needs an integer", 64);
60
+ let state;
61
+ try {
62
+ state = JSON.parse(readFileSync(file, "utf8"));
63
+ } catch (e) {
64
+ return die(`council-view: cannot read ${file}: ${e.message}`, 64);
65
+ }
66
+
67
+ const iterations = Array.isArray(state?.reviewIterations) ? state.reviewIterations : [];
68
+ const wanted = ONLY == null ? iterations : iterations.filter((it) => it?.iteration === ONLY);
69
+ if (wanted.length === 0) return die("council-view: no review iterations on this state", 2);
70
+
71
+ const out = [];
72
+ for (const it of wanted) {
73
+ // Absent map is the normal state for a run written before anonymization,
74
+ // and for one where every reviewer timed out. Say "unknown" rather than
75
+ // guessing a model, the same way run-metrics.mjs degrades.
76
+ const map = it?.anonymizationMap?.labelToModel || {};
77
+ const triage = it?.triage || {};
78
+ const rows = [];
79
+ for (const r of Array.isArray(it?.reviewers) ? it.reviewers : []) {
80
+ const model = typeof r?.model === "string" && r.model ? r.model : "unknown";
81
+ for (const f of Array.isArray(r?.findings) ? r.findings : []) {
82
+ rows.push({
83
+ model,
84
+ severity: f?.severity || "",
85
+ file: f?.file || "",
86
+ line: f?.line ?? "",
87
+ issue: f?.issue || "",
88
+ fingerprint: f?.fingerprint || null,
89
+ corroboration: f?.corroboration?.count ?? null,
90
+ of: f?.corroboration?.of ?? null,
91
+ verdict: verdictOf(triage, f?.fingerprint, f?.issue, f?.file),
92
+ });
93
+ }
94
+ }
95
+ out.push({
96
+ iteration: it?.iteration ?? null,
97
+ reviewers: Object.keys(map).length ? map : null,
98
+ findings: rows,
99
+ });
100
+ }
101
+
102
+ if (JSON_OUT) {
103
+ process.stdout.write(JSON.stringify(out, null, 2) + "\n");
104
+ return;
105
+ }
106
+
107
+ const lines = [];
108
+ for (const block of out) {
109
+ lines.push(`## Council view - iteration ${block.iteration ?? "?"}`);
110
+ lines.push("");
111
+ if (block.findings.length === 0) {
112
+ lines.push("No reviewer returned a finding in this iteration.");
113
+ lines.push("");
114
+ continue;
115
+ }
116
+ // Per-model totals first: the ratio is the summary, the rows are the evidence.
117
+ const byModel = new Map();
118
+ for (const r of block.findings) {
119
+ const e = byModel.get(r.model) || { raw: 0, accepted: 0 };
120
+ e.raw += 1;
121
+ if (r.verdict === "accepted") e.accepted += 1;
122
+ byModel.set(r.model, e);
123
+ }
124
+ lines.push("| Reviewer | Raised | Accepted |");
125
+ lines.push("| -------- | ------ | -------- |");
126
+ for (const [m, e] of byModel) lines.push(`| ${m} | ${e.raw} | ${e.accepted} |`);
127
+ lines.push("");
128
+ lines.push("| Reviewer | Severity | Where | Finding | Seen by | Triage |");
129
+ lines.push("| -------- | -------- | ----- | ------- | ------- | ------ |");
130
+ for (const r of block.findings) {
131
+ const seen = r.corroboration == null ? "-" : `${r.corroboration}/${r.of}`;
132
+ const where = r.file ? `${r.file}:${r.line}` : "-";
133
+ lines.push(
134
+ `| ${r.model} | ${r.severity} | ${where} | ${r.issue.replace(/\|/g, "\\|")} | ${seen} | ${r.verdict} |`,
135
+ );
136
+ }
137
+ lines.push("");
138
+ }
139
+ // `process.exitCode`, never `process.exit()`: stdout to a pipe is async and
140
+ // exiting on the next line truncates a long table at the pipe buffer.
141
+ process.stdout.write(lines.join("\n"));
142
+ }
143
+
144
+ main();