@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.
- package/CHANGELOG.md +29 -0
- package/README.md +1 -1
- package/README.tr.md +1 -1
- package/docs/facts.json +3 -3
- package/install/catalog-history.json +1 -1
- package/manifest.json +50 -39
- package/package.json +5 -5
- package/pipeline/commands/multi-agent/channels/SKILL.md +23 -19
- package/pipeline/lib/_jira-auth.sh +3 -1
- package/pipeline/lib/issue-fetcher.sh +40 -2
- package/pipeline/lib/jira-family-write.sh +339 -0
- package/pipeline/lib/jira-publish.sh +28 -1
- package/pipeline/lib/jira-remote-links.sh +99 -0
- package/pipeline/multi-agent-refs/analysis/intake.md +2 -0
- package/pipeline/multi-agent-refs/analysis/render.md +4 -2
- package/pipeline/multi-agent-refs/channels/jira.md +12 -8
- package/pipeline/multi-agent-refs/channels/pr.md +11 -8
- package/pipeline/multi-agent-refs/channels/test-run.md +52 -0
- package/pipeline/multi-agent-refs/conventions-defaults.md +2 -0
- package/pipeline/multi-agent-refs/features/analysis-issue-links.md +42 -0
- package/pipeline/multi-agent-refs/features/jira-family.md +175 -0
- package/pipeline/multi-agent-refs/features/localization-reuse.md +25 -0
- package/pipeline/multi-agent-refs/features/url-enrichment.md +11 -3
- package/pipeline/multi-agent-refs/features/visual-evidence.md +35 -9
- package/pipeline/multi-agent-refs/generate-issue.md +9 -11
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +13 -7
- package/pipeline/multi-agent-refs/phases/phase-2-dev.md +2 -0
- package/pipeline/multi-agent-refs/phases/phase-4-commit.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-5-report.md +2 -1
- package/pipeline/multi-agent-refs/phases.md +1 -1
- package/pipeline/multi-agent-refs/platform-parity.md +1 -1
- package/pipeline/multi-agent-refs/tracker-contract.md +10 -6
- package/pipeline/schemas/agent-state.schema.json +86 -0
- package/pipeline/schemas/prefs.schema.json +34 -0
- package/pipeline/schemas/unattended-policy.json +1 -0
- package/pipeline/scripts/_sibling-root.mjs +38 -0
- package/pipeline/scripts/gen-facts.mjs +5 -3
- package/pipeline/scripts/jira-family.mjs +947 -0
- package/pipeline/scripts/jira-wiki-escape.mjs +3 -3
- package/pipeline/scripts/plan-remote-links.mjs +339 -0
- package/pipeline/scripts/render-flow-run.mjs +583 -0
- package/pipeline/scripts/render-jira-evidence.mjs +213 -0
- package/pipeline/skills/.skill-manifest.json +5 -5
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +5 -0
- package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +15 -2
- package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +1 -1
- 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 "
|
|
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
|
|
111
|
+
For each `TaskCreate` line `phase-tracker.sh tiles` prints, IN THAT ORDER:
|
|
112
112
|
TaskCreate({
|
|
113
|
-
subject: "Phase 0
|
|
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,
|
|
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
|
|
320
|
+
TaskUpdate({taskId: <phase_task>, subject: "Phase 2 Dev - sonnet - 4m 12s - 35k tok - ~$0.26"})
|
|
317
321
|
```
|
|
318
322
|
|
|
319
|
-
|
|
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
|
|
98
|
-
// names another parent directory (a
|
|
99
|
-
|
|
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 {
|