@mmerterden/multi-agent-pipeline 20.25.1 → 20.27.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 (47) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +1 -1
  3. package/README.tr.md +1 -1
  4. package/docs/facts.json +3 -3
  5. package/install/catalog-history.json +1 -1
  6. package/manifest.json +50 -39
  7. package/package.json +5 -5
  8. package/pipeline/commands/multi-agent/channels/SKILL.md +23 -19
  9. package/pipeline/lib/_jira-auth.sh +3 -1
  10. package/pipeline/lib/issue-fetcher.sh +40 -2
  11. package/pipeline/lib/jira-family-write.sh +339 -0
  12. package/pipeline/lib/jira-publish.sh +28 -1
  13. package/pipeline/lib/jira-remote-links.sh +99 -0
  14. package/pipeline/multi-agent-refs/analysis/intake.md +2 -0
  15. package/pipeline/multi-agent-refs/analysis/render.md +4 -2
  16. package/pipeline/multi-agent-refs/channels/jira.md +12 -8
  17. package/pipeline/multi-agent-refs/channels/pr.md +11 -8
  18. package/pipeline/multi-agent-refs/channels/test-run.md +52 -0
  19. package/pipeline/multi-agent-refs/conventions-defaults.md +2 -0
  20. package/pipeline/multi-agent-refs/features/analysis-issue-links.md +42 -0
  21. package/pipeline/multi-agent-refs/features/jira-family.md +175 -0
  22. package/pipeline/multi-agent-refs/features/localization-reuse.md +25 -0
  23. package/pipeline/multi-agent-refs/features/url-enrichment.md +11 -3
  24. package/pipeline/multi-agent-refs/features/visual-evidence.md +35 -9
  25. package/pipeline/multi-agent-refs/generate-issue.md +9 -11
  26. package/pipeline/multi-agent-refs/phases/phase-0-init.md +13 -7
  27. package/pipeline/multi-agent-refs/phases/phase-2-dev.md +2 -0
  28. package/pipeline/multi-agent-refs/phases/phase-4-commit.md +1 -1
  29. package/pipeline/multi-agent-refs/phases/phase-5-report.md +2 -1
  30. package/pipeline/multi-agent-refs/phases.md +1 -1
  31. package/pipeline/multi-agent-refs/platform-parity.md +1 -1
  32. package/pipeline/multi-agent-refs/tracker-contract.md +10 -6
  33. package/pipeline/schemas/agent-state.schema.json +86 -0
  34. package/pipeline/schemas/prefs.schema.json +34 -0
  35. package/pipeline/schemas/unattended-policy.json +1 -0
  36. package/pipeline/scripts/_sibling-root.mjs +38 -0
  37. package/pipeline/scripts/gen-facts.mjs +5 -3
  38. package/pipeline/scripts/jira-family.mjs +947 -0
  39. package/pipeline/scripts/jira-wiki-escape.mjs +3 -3
  40. package/pipeline/scripts/plan-remote-links.mjs +339 -0
  41. package/pipeline/scripts/render-flow-run.mjs +583 -0
  42. package/pipeline/scripts/render-jira-evidence.mjs +213 -0
  43. package/pipeline/skills/.skill-manifest.json +5 -5
  44. package/pipeline/skills/shared/core/multi-agent/SKILL.md +5 -0
  45. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +15 -2
  46. package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +1 -1
  47. package/pipeline/skills/shared/external/ios-localization/SKILL.md +5 -0
@@ -101,16 +101,16 @@ Register each phase:
101
101
 
102
102
  ```bash
103
103
  bash $HOME/.claude/scripts/phase-tracker.sh add 0 "Init"
104
- bash $HOME/.claude/scripts/phase-tracker.sh add 1 "Analysis"
104
+ bash $HOME/.claude/scripts/phase-tracker.sh add 1 "Plan"
105
105
  # ...
106
106
  ```
107
107
 
108
108
  ### Claude Code - also register a TaskList tile per phase
109
109
 
110
110
  ```text
111
- For each phase in the current mode, IN PHASE-NUMBER ORDER (0 → 1 → 2 → ... → 5):
111
+ For each `TaskCreate` line `phase-tracker.sh tiles` prints, IN THAT ORDER:
112
112
  TaskCreate({
113
- subject: "Phase 0: Init",
113
+ subject: "Phase 0 Init",
114
114
  description: "Repo discovery, branch, worktree, identity bind",
115
115
  activeForm: "Initializing pipeline"
116
116
  })
@@ -118,6 +118,8 @@ For each phase in the current mode, IN PHASE-NUMBER ORDER (0 → 1 → 2 → ...
118
118
  bash phase-tracker.sh meta 0 tasklist_id "<taskId>"
119
119
  ```
120
120
 
121
+ **The subject is the tracker's line, verbatim.** `phase-tracker.sh tiles` prints each subject from the phase names the command registered (`0:Init 1:Plan 2:Dev 3:Review 4:Commit 5:Report` for a full run). Copy it as printed: no task-id prefix, no renamed, merged or annotated phase (`Analysis + Plan`, `Review + Verify`). What a phase does inside goes in `activeForm` or a sub-step tile, never in the phase name. A tile that disagrees with the tracker is a second, wrong progress record.
122
+
121
123
  The `tasklist_id` meta field is persisted so that `:resume` can rebuild the TaskList from the state file in a fresh session.
122
124
 
123
125
  #### The card is not the widget
@@ -310,13 +312,15 @@ fabricating numbers.
310
312
  **Completion tile suffix (Claude Code).** The native widget cannot show
311
313
  per-phase tokens, but subject edits after creation are safe (tile order is
312
314
  fixed at TaskCreate time). So on phase completion, in addition to the
313
- narration line, append the spend to the tile subject:
315
+ narration line, set the subject to what `phase-tracker.sh subjects <N>` prints,
316
+ which is the tracker's own line with model, elapsed time and spend; the suffix is
317
+ the tracker's, never typed by hand:
314
318
 
315
319
  ```text
316
- TaskUpdate({taskId: <phase_task>, subject: "Phase 2: Dev · ~35k tok · ~$0.26"})
320
+ TaskUpdate({taskId: <phase_task>, subject: "Phase 2 Dev - sonnet - 4m 12s - 35k tok - ~$0.26"})
317
321
  ```
318
322
 
319
- Skip the suffix when the phase recorded zero tokens (subject stays clean).
323
+ A phase with no recorded tokens gets no token part from `subjects`; nothing is added by hand.
320
324
 
321
325
  **Honesty note:** on Claude Code the orchestrator does not receive its own
322
326
  usage metering, so per-phase counts are content-size estimates (chars/4 for
@@ -1863,6 +1863,17 @@
1863
1863
  }
1864
1864
  }
1865
1865
  },
1866
+ "evidence": {
1867
+ "type": "object",
1868
+ "description": "Evidence gathered during the run for the report channels. Other evidence kinds live beside flowRuns.",
1869
+ "properties": {
1870
+ "flowRuns": {
1871
+ "type": "array",
1872
+ "description": "Flow-runner run ids (the runId in <RUN_ROOT>/history.jsonl) of the UI scenario runs that verify this task. Channels renders their Xray Test Execution in the 'Test Koşumu (Xray)' block; empty means channels discovers candidate runs instead.",
1873
+ "items": { "type": "string", "minLength": 1 }
1874
+ }
1875
+ }
1876
+ },
1866
1877
  "visualEvidence": {
1867
1878
  "type": ["object", "null"],
1868
1879
  "additionalProperties": false,
@@ -1987,6 +1998,45 @@
1987
1998
  }
1988
1999
  }
1989
2000
  },
2001
+ "scenarios": {
2002
+ "type": "array",
2003
+ "description": "Per-scenario evidence: one screenshot and/or one recording for each test scenario a UI run covered, attached to the Jira issue. Rendered as one evidence line under that scenario by scripts/render-jira-evidence.mjs.",
2004
+ "items": {
2005
+ "type": "object",
2006
+ "additionalProperties": false,
2007
+ "required": ["id"],
2008
+ "properties": {
2009
+ "id": {
2010
+ "type": "string",
2011
+ "description": "Scenario id, as the test scenarios section names it."
2012
+ },
2013
+ "image": {
2014
+ "type": "object",
2015
+ "additionalProperties": true,
2016
+ "properties": {
2017
+ "file": { "type": "string" },
2018
+ "jiraFilename": { "type": "string" },
2019
+ "url": {
2020
+ "type": "string",
2021
+ "description": "Jira attachment content URL, as jira-attach.sh printed it."
2022
+ }
2023
+ }
2024
+ },
2025
+ "video": {
2026
+ "type": "object",
2027
+ "additionalProperties": true,
2028
+ "properties": {
2029
+ "file": { "type": "string" },
2030
+ "jiraFilename": { "type": "string" },
2031
+ "url": {
2032
+ "type": "string",
2033
+ "description": "Jira attachment content URL, as jira-attach.sh printed it."
2034
+ }
2035
+ }
2036
+ }
2037
+ }
2038
+ }
2039
+ },
1990
2040
  "gaps": {
1991
2041
  "type": "array",
1992
2042
  "description": "Every artefact that is required and absent, with its reason. A recorded reason satisfies the Phase 4 blocker; silence does not.",
@@ -2098,6 +2148,42 @@
2098
2148
  "sha": { "type": "string" }
2099
2149
  }
2100
2150
  },
2151
+ "jiraFamily": {
2152
+ "type": ["object", "null"],
2153
+ "additionalProperties": false,
2154
+ "description": "The issue family of a run that started from a Jira story or sub-task (multi-agent-refs/features/jira-family.md), written by Phase 0 from scripts/jira-family.mjs resolve and read by the channels Jira adapter. writes[] is the outcome of lib/jira-family-write.sh apply.",
2155
+ "properties": {
2156
+ "inputKey": { "type": ["string", "null"] },
2157
+ "inputRole": { "enum": ["subtask", "story"] },
2158
+ "storyKey": { "type": ["string", "null"] },
2159
+ "devTaskKey": { "type": ["string", "null"] },
2160
+ "devCandidates": { "type": "array", "items": { "type": "string" } },
2161
+ "testTaskKey": { "type": ["string", "null"] },
2162
+ "testCandidates": { "type": "array", "items": { "type": "string" } },
2163
+ "storyFormat": {
2164
+ "type": "object",
2165
+ "additionalProperties": false,
2166
+ "properties": {
2167
+ "status": { "enum": ["conforms", "nonconforming", "empty", "unknown", "not-a-story"] },
2168
+ "reasons": { "type": "array", "items": { "type": "string" } }
2169
+ }
2170
+ },
2171
+ "writes": {
2172
+ "type": "array",
2173
+ "items": {
2174
+ "type": "object",
2175
+ "additionalProperties": false,
2176
+ "required": ["id", "issue", "status"],
2177
+ "properties": {
2178
+ "id": { "enum": ["story", "dev", "test", "story-tests"] },
2179
+ "issue": { "type": "string" },
2180
+ "status": { "enum": ["written", "exists", "skipped", "failed", "dry-run"] },
2181
+ "reason": { "type": "string" }
2182
+ }
2183
+ }
2184
+ }
2185
+ }
2186
+ },
2101
2187
  "decisions": {
2102
2188
  "type": "array",
2103
2189
  "description": "Choices an autopilot run made where an attended run would have asked (multi-agent-refs/features/autopilot-decisions.md): parks (gate-ledger.mjs), blockers lowered to important (review-decision-gate.mjs), rework escalations (rework-escalation.mjs), pickers resolved without asking, split consensus taken on the triage verdict, a date-gate model fallback (decisions-log.mjs add). Written only while the quality gates are active. Rendered, redacted, in the Phase 5 report and appended to the autopilot PR body; an empty or absent list renders nothing.",
@@ -829,6 +829,11 @@
829
829
  "default": false,
830
830
  "description": "v6.1.0+ - Per-phase token cost summary (phase name, tokens_in, tokens_out, est. USD). Source: phase-tracker.sh token tallies + optional OTel spans (MULTI_AGENT_OTEL_SPANS=1). Greyed out if tracker has no token data for the task. Opt-in - off by default so baseline PR body stays unchanged."
831
831
  },
832
+ "testRun": {
833
+ "type": "boolean",
834
+ "default": false,
835
+ "description": "'Test Koşumu (Xray)' block: the Xray Test Execution of the task's UI scenario run, read from the flow runner's history.jsonl by render-flow-run.mjs. Ticked automatically when the run comes from --flow-run or state.evidence.flowRuns; greyed out when no run resolves."
836
+ },
832
837
  "workSummary": {
833
838
  "type": "boolean",
834
839
  "default": false,
@@ -2231,6 +2236,12 @@
2231
2236
  "default": true,
2232
2237
  "description": "Off disables capture, upload and both render sections. The Phase 4 blocker goes with it."
2233
2238
  },
2239
+ "jiraMedia": {
2240
+ "type": "string",
2241
+ "enum": ["links", "thumbnails"],
2242
+ "default": "links",
2243
+ "description": "How the Jira comment references screenshots: links (one evidence line per scenario, default) or thumbnails (small embedded images). Recordings are always links. Consumed by scripts/render-jira-evidence.mjs --mode."
2244
+ },
2234
2245
  "maxAttachmentMb": {
2235
2246
  "type": "integer",
2236
2247
  "minimum": 1,
@@ -2372,6 +2383,29 @@
2372
2383
  "type": "string",
2373
2384
  "default": "Blocks",
2374
2385
  "description": "The link type written from a prerequisite story to the story that depends on it (a `Depends on:` clause in the analysis document), by this site's name. The prerequisite is the link's source."
2386
+ },
2387
+ "familyWrites": {
2388
+ "type": "boolean",
2389
+ "default": true,
2390
+ "description": "When a run starts from a Jira story or one of its sub-tasks, write to the whole family (features/jira-family.md): the story description reformatted into the story format, the Phase 5 comment on the development sub-task, the test scenarios on the test sub-task. false keeps the single Phase 5 comment on the issue the run started from."
2391
+ },
2392
+ "storyIssueTypes": {
2393
+ "type": "array",
2394
+ "items": { "type": "string" },
2395
+ "default": [],
2396
+ "description": "Issue type names, by this site's own name, that count as a story for the issue family: only such an issue's description is reformatted into the story format. Empty means storyIssueType (Story when unset)."
2397
+ },
2398
+ "testSubtaskTypes": {
2399
+ "type": "array",
2400
+ "items": { "type": "string" },
2401
+ "default": [],
2402
+ "description": "Sub-task type names, by this site's own name, that mark a test sub-task. Empty means discover: the project's sub-task types from createmeta whose name carries the word test (e.g. Sub Test Execution, Test Task)."
2403
+ },
2404
+ "devSubtaskTypes": {
2405
+ "type": "array",
2406
+ "items": { "type": "string" },
2407
+ "default": [],
2408
+ "description": "Sub-task type names that mark a development sub-task, used when a run starts from the story. Empty means a type whose name carries dev, development or geliştirme."
2375
2409
  }
2376
2410
  }
2377
2411
  },
@@ -128,6 +128,7 @@
128
128
  "update-issue-progress.sh": null,
129
129
  "analysis-jira-write.sh": null,
130
130
  "jira-attach.sh": null,
131
+ "jira-remote-links.sh": ["apply"],
131
132
  "md2confluence-v3.py": ["create", "update"],
132
133
  "multi-repo-pipeline.sh": ["push", "pr"],
133
134
  "keychain-save.sh": null,
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @file _sibling-root.mjs - the directory that holds this repo's sibling
3
+ * checkouts (multi-agent-toolkit-mcp, multi-agent-plugins).
4
+ *
5
+ * Siblings sit beside the MAIN checkout. A linked worktree lives inside it, at
6
+ * `<main>/.worktrees/<name>`, so `<root>/..` from there is `.worktrees/` and no
7
+ * sibling is found. The main checkout is the directory that holds the shared
8
+ * git dir, so its parent is the answer for every worktree of the repo.
9
+ *
10
+ * Outside git, or when the shared git dir is not a `.git` directory (a bare
11
+ * repo, a submodule's `.git/modules/<name>`), it falls back to `<root>/..`.
12
+ *
13
+ * Usage as a command: `node _sibling-root.mjs <root>` prints the directory.
14
+ *
15
+ * Zero runtime dependencies (ADR-0004).
16
+ */
17
+
18
+ import { spawnSync } from "node:child_process";
19
+ import { basename, dirname, resolve } from "node:path";
20
+ import { invokedDirectly } from "../lib/invoked-directly.mjs";
21
+
22
+ /** @param {string} root */
23
+ export function siblingsParent(root) {
24
+ const fallback = resolve(root, "..");
25
+ const r = spawnSync(
26
+ "git",
27
+ ["-C", root, "rev-parse", "--path-format=absolute", "--git-common-dir"],
28
+ { encoding: "utf8" },
29
+ );
30
+ if (r.status !== 0) return fallback;
31
+ const commonDir = r.stdout.trim();
32
+ if (basename(commonDir) !== ".git") return fallback;
33
+ return dirname(dirname(commonDir));
34
+ }
35
+
36
+ if (invokedDirectly(import.meta.url)) {
37
+ process.stdout.write(`${siblingsParent(process.argv[2] || process.cwd())}\n`);
38
+ }
@@ -37,6 +37,7 @@ import { readFileSync, writeFileSync, readdirSync, existsSync } from "node:fs";
37
37
  import { join, dirname } from "node:path";
38
38
  import { fileURLToPath } from "node:url";
39
39
  import { spawnSync } from "node:child_process";
40
+ import { siblingsParent } from "./_sibling-root.mjs";
40
41
 
41
42
  const HERE = dirname(fileURLToPath(import.meta.url));
42
43
  const ROOT = join(HERE, "..", "..");
@@ -94,9 +95,10 @@ try {
94
95
  let toolCount = null;
95
96
  let toolCategories = null;
96
97
  let toolkitVersion = null;
97
- // Sibling checkouts are looked up beside this repo; GEN_FACTS_SIBLINGS_DIR
98
- // names another parent directory (a test points it at an empty one).
99
- const siblingsDir = process.env.GEN_FACTS_SIBLINGS_DIR || join(ROOT, "..");
98
+ // Sibling checkouts are looked up beside the main checkout, also from a worktree
99
+ // under .worktrees/; GEN_FACTS_SIBLINGS_DIR names another parent directory (a
100
+ // test points it at an empty one).
101
+ const siblingsDir = process.env.GEN_FACTS_SIBLINGS_DIR || siblingsParent(ROOT);
100
102
  const toolkitDir = join(siblingsDir, "multi-agent-toolkit-mcp");
101
103
  if (existsSync(join(toolkitDir, "package.json"))) {
102
104
  try {