@mmerterden/multi-agent-pipeline 14.2.1 → 14.2.2
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 +42 -0
- package/README.md +10 -6
- package/README.tr.md +143 -0
- package/docs/architecture.md +23 -8
- package/docs/ecosystem.md +237 -0
- package/install/_plugin-skills.mjs +16 -2
- package/install/codex.mjs +9 -4
- package/install/templates/copilot-instructions.md +12 -9
- package/package.json +1 -1
- package/pipeline/commands/multi-agent/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/analysis/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/autopilot/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/channels/SKILL.md +15 -4
- package/pipeline/commands/multi-agent/create-jira/SKILL.md +4 -4
- package/pipeline/commands/multi-agent/dev/SKILL.md +10 -23
- package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +10 -2
- package/pipeline/commands/multi-agent/dev-local/SKILL.md +10 -24
- package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +10 -3
- package/pipeline/commands/multi-agent/jira/SKILL.md +13 -2
- package/pipeline/commands/multi-agent/language/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/local/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/log/SKILL.md +7 -1
- package/pipeline/commands/multi-agent/ship/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/sync/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/update/SKILL.md +1 -1
- package/pipeline/lib/extract-conventions.sh +44 -15
- package/pipeline/lib/fetch-figma-annotations.sh +8 -1
- package/pipeline/lib/fetch-fortify.sh +23 -8
- package/pipeline/lib/figma-screenshot.sh +11 -1
- package/pipeline/lib/issue-fetcher.sh +76 -9
- package/pipeline/lib/md2confluence-v3.py +16 -2
- package/pipeline/lib/plan-todos.sh +5 -2
- package/pipeline/lib/post-pr-review.sh +8 -6
- package/pipeline/lib/shadow-git.sh +50 -9
- package/pipeline/lib/submodule-detector.sh +8 -1
- package/pipeline/multi-agent-refs/_input-parser.md +1 -1
- package/pipeline/multi-agent-refs/channels/confluence.md +3 -0
- package/pipeline/multi-agent-refs/channels/issue-comment.md +2 -2
- package/pipeline/multi-agent-refs/channels/jira.md +13 -2
- package/pipeline/multi-agent-refs/channels/pr-review-actions.md +1 -1
- package/pipeline/multi-agent-refs/channels/pr.md +20 -0
- package/pipeline/multi-agent-refs/channels/wiki.md +1 -1
- package/pipeline/multi-agent-refs/cross-cli-contract.md +3 -3
- package/pipeline/multi-agent-refs/features/worktree-finalize.md +1 -1
- package/pipeline/multi-agent-refs/generate-issue.md +2 -2
- package/pipeline/multi-agent-refs/issue-jira-triad.md +3 -3
- package/pipeline/multi-agent-refs/payload-contracts.md +67 -0
- package/pipeline/multi-agent-refs/phases/modes.md +20 -0
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-6-commit.md +8 -40
- package/pipeline/multi-agent-refs/phases/phase-7-report.md +5 -3
- package/pipeline/multi-agent-refs/phases.md +6 -0
- package/pipeline/multi-agent-refs/rules.md +2 -0
- package/pipeline/schemas/prefs.schema.json +1 -1
- package/pipeline/scripts/audit-log-rotate.sh +10 -0
- package/pipeline/scripts/build-stack-plugins.mjs +8 -1
- package/pipeline/scripts/check-derived-drift.mjs +13 -1
- package/pipeline/scripts/diff-explain.mjs +41 -3
- package/pipeline/scripts/diff-risk-score.mjs +72 -8
- package/pipeline/scripts/gen-mode-dispatch.mjs +1 -1
- package/pipeline/scripts/learning-curve.mjs +8 -2
- package/pipeline/scripts/output-quality-check.sh +15 -4
- package/pipeline/scripts/phase-tracker.sh +21 -8
- package/pipeline/scripts/pre-commit-check.sh +69 -22
- package/pipeline/scripts/render-agent-log-cost.sh +8 -3
- package/pipeline/scripts/render-cost-summary.sh +42 -22
- package/pipeline/scripts/render-work-summary.sh +47 -13
- package/pipeline/scripts/review-scope.mjs +1 -1
- package/pipeline/scripts/run-aggregator.mjs +38 -14
- package/pipeline/scripts/smoke-schema-validation.sh +5 -1
- package/pipeline/scripts/test-gap-scan.mjs +45 -6
- package/pipeline/scripts/uninstall.mjs +39 -4
- package/pipeline/scripts/update-issue-progress.sh +12 -16
- package/pipeline/scripts/worktree-finalize.sh +23 -2
- package/pipeline/skills/.skills-index.json +11 -2
- package/pipeline/skills/shared/README.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +4 -0
- package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +4 -17
- package/pipeline/skills/shared/core/multi-agent-dev-autopilot/SKILL.md +8 -0
- package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +5 -18
- package/pipeline/skills/shared/core/multi-agent-dev-local-autopilot/SKILL.md +8 -0
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +4 -0
- package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +4 -0
- package/pipeline/skills/shared/core/multi-agent-ship/SKILL.md +4 -0
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +2 -2
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +302 -0
- package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +144 -0
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +156 -0
- package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +108 -0
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +175 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +865 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +335 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +344 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +130 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +264 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +298 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +529 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +187 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +171 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +184 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +26 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +173 -0
- package/pipeline/skills/skills-index.md +3 -2
|
@@ -82,14 +82,27 @@ function die(msg) {
|
|
|
82
82
|
process.exit(1);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
// phase-tracker.sh writes tracker-state.json (never phase-tracker.json) at
|
|
86
|
+
// $HOME/.claude/logs/multi-agent/<task-id>/ (no <project> segment) - the
|
|
87
|
+
// same drift render-cost-summary.sh/render-agent-log-cost.sh already guard
|
|
88
|
+
// against with a candidate list. Mirror that list here instead of assuming
|
|
89
|
+
// one fixed filename/path.
|
|
90
|
+
function resolveTrackerCandidates() {
|
|
91
|
+
const candidates = [];
|
|
92
|
+
if (flags["task-dir"]) {
|
|
93
|
+
candidates.push(join(flags["task-dir"], "tracker-state.json"));
|
|
94
|
+
}
|
|
95
|
+
if (flags["task-id"]) {
|
|
88
96
|
const HOME = process.env.HOME || process.env.USERPROFILE;
|
|
89
97
|
if (!HOME) die("neither HOME nor USERPROFILE is set - pass --task-dir");
|
|
90
|
-
|
|
98
|
+
const taskId = String(flags["task-id"]);
|
|
99
|
+
if (flags.project) {
|
|
100
|
+
candidates.push(join(HOME, ".claude", "logs", "multi-agent", flags.project, taskId, "tracker-state.json"));
|
|
101
|
+
}
|
|
102
|
+
candidates.push(join(HOME, ".claude", "logs", "multi-agent", taskId, "tracker-state.json"));
|
|
91
103
|
}
|
|
92
|
-
die("either --task-dir or --task-id
|
|
104
|
+
if (!candidates.length) die("either --task-dir or --task-id is required");
|
|
105
|
+
return candidates;
|
|
93
106
|
}
|
|
94
107
|
|
|
95
108
|
function loadJson(path) {
|
|
@@ -161,11 +174,14 @@ function tsCompare(a, b) {
|
|
|
161
174
|
}
|
|
162
175
|
|
|
163
176
|
// ─────────────────────────────────────────────────────────────────────────
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
177
|
+
const trackerCandidates = resolveTrackerCandidates();
|
|
178
|
+
const trackerPath = trackerCandidates.find((p) => existsSync(p));
|
|
179
|
+
if (!trackerPath) {
|
|
180
|
+
die(`tracker state not found, tried:\n${trackerCandidates.map((p) => ` ${p}`).join("\n")}`);
|
|
181
|
+
}
|
|
182
|
+
const taskDir = dirname(trackerPath);
|
|
183
|
+
const tracker = loadJson(trackerPath);
|
|
184
|
+
if (!tracker) die(`failed to parse tracker state at ${trackerPath}`);
|
|
169
185
|
|
|
170
186
|
const otelSpans = loadJsonl(join(taskDir, "otel-spans.jsonl"));
|
|
171
187
|
const costTable = loadCostTable();
|
|
@@ -187,7 +203,15 @@ let totalOut = 0;
|
|
|
187
203
|
let totalCost = 0;
|
|
188
204
|
let unknownModelHits = 0;
|
|
189
205
|
|
|
190
|
-
|
|
206
|
+
// tracker.phases ships in two shapes (same contract render-cost-summary.sh
|
|
207
|
+
// normalizes): an array (phase-tracker.sh's real output) or an object keyed
|
|
208
|
+
// by phase id (older fixtures / hand-built variants). Normalize once so the
|
|
209
|
+
// rest of this file can treat it as a plain array.
|
|
210
|
+
const phaseList = Array.isArray(tracker.phases)
|
|
211
|
+
? tracker.phases
|
|
212
|
+
: Object.entries(tracker.phases || {}).map(([key, value]) => ({ ...value, id: value?.id ?? key }));
|
|
213
|
+
|
|
214
|
+
for (const phase of phaseList) {
|
|
191
215
|
const tIn = phase.tokens_in || 0;
|
|
192
216
|
const tOut = phase.tokens_out || 0;
|
|
193
217
|
const model = phase.model || inferModelForPhase(phase.id);
|
|
@@ -279,9 +303,9 @@ const summary = {
|
|
|
279
303
|
kind: "summary",
|
|
280
304
|
ts: lastTs,
|
|
281
305
|
task_id: taskId,
|
|
282
|
-
phases_total:
|
|
283
|
-
phases_completed:
|
|
284
|
-
phases_failed:
|
|
306
|
+
phases_total: phaseList.length,
|
|
307
|
+
phases_completed: phaseList.filter((p) => p.status === "completed").length,
|
|
308
|
+
phases_failed: phaseList.filter((p) => p.status === "failed").length,
|
|
285
309
|
tokens_in: totalIn,
|
|
286
310
|
tokens_out: totalOut,
|
|
287
311
|
total_cost_usd: Number(totalCost.toFixed(6)),
|
|
@@ -91,10 +91,14 @@ echo "→ 4. prefs.schema.json - keychainMapping covers every resolved service
|
|
|
91
91
|
# A floor, not a pin: new credentials get added over time, and pinning the count
|
|
92
92
|
# made every addition a false failure. What matters is that the keys shipped
|
|
93
93
|
# flows resolve are all declared.
|
|
94
|
+
# process.stdout.write of a String, not console.log of a Number: console.log
|
|
95
|
+
# inspects non-string arguments, so with FORCE_COLOR set in the environment the
|
|
96
|
+
# count comes back wrapped in ANSI codes and the -ge comparison below silently
|
|
97
|
+
# fails on a value that is actually in range.
|
|
94
98
|
KM_COUNT=$(node -e "
|
|
95
99
|
const s = JSON.parse(require('fs').readFileSync('$PREFS_SCHEMA', 'utf8'));
|
|
96
100
|
const km = s.properties.global.properties.keychainMapping.properties;
|
|
97
|
-
|
|
101
|
+
process.stdout.write(String(Object.keys(km).length));
|
|
98
102
|
" 2>/dev/null)
|
|
99
103
|
if [ "${KM_COUNT:-0}" -ge 12 ] 2>/dev/null; then
|
|
100
104
|
pass "keychainMapping declares $KM_COUNT services (≥12 expected)"
|
|
@@ -141,6 +141,45 @@ function isExcluded(path) {
|
|
|
141
141
|
return false;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
// git quotes a `diff --git` path (core.quotePath, on by default) whenever it
|
|
145
|
+
// has a non-ASCII byte or other unusual character - e.g. a Turkish filename
|
|
146
|
+
// renders as `diff --git "a/\303\226deme.swift" "b/\303\226deme.swift"`, not
|
|
147
|
+
// the bare a/...b/... form. The plain regex this replaced never matched that
|
|
148
|
+
// line at all, so every non-ASCII-named file's added lines were silently
|
|
149
|
+
// dropped from the test-gap scan.
|
|
150
|
+
const DIFF_GIT_QUOTED_RE = /^diff --git "a\/((?:[^"\\]|\\.)*)" "b\/((?:[^"\\]|\\.)*)"$/;
|
|
151
|
+
const DIFF_GIT_UNQUOTED_RE = /^diff --git a\/(.+?) b\/(.+)$/;
|
|
152
|
+
|
|
153
|
+
function unquoteGitPath(s) {
|
|
154
|
+
const bytes = [];
|
|
155
|
+
for (let i = 0; i < s.length; i++) {
|
|
156
|
+
if (s[i] === "\\") {
|
|
157
|
+
const octal = s.slice(i + 1, i + 4);
|
|
158
|
+
if (/^[0-7]{3}$/.test(octal)) {
|
|
159
|
+
bytes.push(parseInt(octal, 8));
|
|
160
|
+
i += 3;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const simple = { "\\": 92, '"': 34, t: 9, n: 10, r: 13 };
|
|
164
|
+
const next = s[i + 1];
|
|
165
|
+
if (next in simple) {
|
|
166
|
+
bytes.push(simple[next]);
|
|
167
|
+
i += 1;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
bytes.push(s.charCodeAt(i));
|
|
172
|
+
}
|
|
173
|
+
return Buffer.from(bytes).toString("utf-8");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function matchDiffGitHeader(line) {
|
|
177
|
+
const q = line.match(DIFF_GIT_QUOTED_RE);
|
|
178
|
+
if (q) return unquoteGitPath(q[2]);
|
|
179
|
+
const u = line.match(DIFF_GIT_UNQUOTED_RE);
|
|
180
|
+
return u ? u[2] : null;
|
|
181
|
+
}
|
|
182
|
+
|
|
144
183
|
function isTestPath(path) {
|
|
145
184
|
if (Array.isArray(rules.testPathSuffixes) && rules.testPathSuffixes.some((s) => path.endsWith(s)))
|
|
146
185
|
return true;
|
|
@@ -190,9 +229,9 @@ function parseDiffAddedLines(diffText) {
|
|
|
190
229
|
const perFile = new Map();
|
|
191
230
|
let cur = null;
|
|
192
231
|
for (const line of diffText.split("\n")) {
|
|
193
|
-
const
|
|
194
|
-
if (
|
|
195
|
-
cur =
|
|
232
|
+
const p = matchDiffGitHeader(line);
|
|
233
|
+
if (p !== null) {
|
|
234
|
+
cur = p;
|
|
196
235
|
if (!perFile.has(cur)) perFile.set(cur, { lines: [], isNew: false });
|
|
197
236
|
continue;
|
|
198
237
|
}
|
|
@@ -300,9 +339,9 @@ function symbolMentionedInTest(diffText, symbol) {
|
|
|
300
339
|
const lines = diffText.split("\n");
|
|
301
340
|
let inTestFile = false;
|
|
302
341
|
for (const line of lines) {
|
|
303
|
-
const fm = line
|
|
304
|
-
if (fm) {
|
|
305
|
-
inTestFile = isTestPath(fm
|
|
342
|
+
const fm = matchDiffGitHeader(line);
|
|
343
|
+
if (fm !== null) {
|
|
344
|
+
inTestFile = isTestPath(fm);
|
|
306
345
|
continue;
|
|
307
346
|
}
|
|
308
347
|
if (!inTestFile) continue;
|
|
@@ -248,6 +248,31 @@ function rmMatchingFiles(parent, predicate) {
|
|
|
248
248
|
return count;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
// Copilot CLI / Codex CLI have no plugin loader, so install/_plugin-skills.mjs
|
|
252
|
+
// copies each stack plugin's authored skills straight into the flat skills/
|
|
253
|
+
// dir (~100 dirs across a typical set of enabled plugins). None of those
|
|
254
|
+
// names are in PIPELINE_CORE_SKILL_DIRS - the allowlist above only covers the
|
|
255
|
+
// pipeline's OWN skills - so they were never removed on uninstall. The
|
|
256
|
+
// installer now writes PLUGIN_SKILLS_MANIFEST listing exactly what it
|
|
257
|
+
// delivered; read it back here rather than guessing plugin skill names.
|
|
258
|
+
const PLUGIN_SKILLS_MANIFEST = ".plugin-skills-manifest.json";
|
|
259
|
+
|
|
260
|
+
function rmPluginDeliveredSkills(skillsDir) {
|
|
261
|
+
const manifestPath = join(skillsDir, PLUGIN_SKILLS_MANIFEST);
|
|
262
|
+
if (!existsSync(manifestPath)) return 0;
|
|
263
|
+
let names;
|
|
264
|
+
try {
|
|
265
|
+
names = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
266
|
+
} catch {
|
|
267
|
+
return 0;
|
|
268
|
+
}
|
|
269
|
+
if (!Array.isArray(names)) return 0;
|
|
270
|
+
const nameSet = new Set(names);
|
|
271
|
+
const count = rmMatchingDirs(skillsDir, (name) => nameSet.has(name));
|
|
272
|
+
rmIfExists(manifestPath);
|
|
273
|
+
return count;
|
|
274
|
+
}
|
|
275
|
+
|
|
251
276
|
// Explicit terminator install/copilot.mjs writes after the pipeline section
|
|
252
277
|
// (v11.4.1+). Must stay in sync with INSTRUCTIONS_END_MARKER there.
|
|
253
278
|
const COPILOT_END_MARKER = "<!-- multi-agent-pipeline:copilot-instructions:end -->";
|
|
@@ -387,13 +412,20 @@ function cleanClaudeSettings(settingsPath) {
|
|
|
387
412
|
if (settings.hooks?.PreToolUse?.length) {
|
|
388
413
|
const before = settings.hooks.PreToolUse.length;
|
|
389
414
|
// Match both the current matcher ("Bash") and the dead pre-v11.4.1 one
|
|
390
|
-
// ("Bash(git commit:*)"); the
|
|
391
|
-
//
|
|
415
|
+
// ("Bash(git commit:*)"); the command identifies the entry as ours either
|
|
416
|
+
// way. install/claude.mjs registers TWO PreToolUse gates this way -
|
|
417
|
+
// pre-commit-check.sh AND agent-guard.sh - and only the first was ever
|
|
418
|
+
// stripped here. After ~/.claude/scripts/ is deleted below, the
|
|
419
|
+
// agent-guard.sh entry pointed at a script that no longer existed, so
|
|
420
|
+
// every subsequent Bash call fired a hook error.
|
|
392
421
|
settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter(
|
|
393
422
|
(h) =>
|
|
394
423
|
!(
|
|
395
424
|
(h.matcher === "Bash" || h.matcher === "Bash(git commit:*)") &&
|
|
396
|
-
h.hooks?.some(
|
|
425
|
+
h.hooks?.some(
|
|
426
|
+
(sub) =>
|
|
427
|
+
sub.command?.includes("pre-commit-check.sh") || sub.command?.includes("agent-guard.sh"),
|
|
428
|
+
)
|
|
397
429
|
),
|
|
398
430
|
);
|
|
399
431
|
if (settings.hooks.PreToolUse.length < before) touched = true;
|
|
@@ -540,10 +572,12 @@ export async function main() {
|
|
|
540
572
|
name === "figma-to-component",
|
|
541
573
|
);
|
|
542
574
|
n += rmMatchingDirs(skills, (name) => PIPELINE_CORE_SKILL_DIRS.includes(name));
|
|
575
|
+
n += rmPluginDeliveredSkills(skills);
|
|
543
576
|
if (n > 0) console.log(` removed ${n} skill dir(s) under ${skills}`);
|
|
544
577
|
rmIfExists(join(skills, ".skills-index.json"));
|
|
545
578
|
rmIfExists(join(skills, "skills-index.md"));
|
|
546
579
|
rmIfExists(join(skills, "README.md"));
|
|
580
|
+
rmIfExists(join(COP, "rules"));
|
|
547
581
|
// Agent definitions are FILES; remove only the pipeline-shipped names so
|
|
548
582
|
// user-authored agents survive.
|
|
549
583
|
rmMatchingFiles(join(COP, "agents"), (name) => PIPELINE_AGENT_FILES.includes(name));
|
|
@@ -613,10 +647,11 @@ export async function main() {
|
|
|
613
647
|
// Codex's own `.system` set plus user skills; `prompts/` and `agents/` hold
|
|
614
648
|
// user-authored files.
|
|
615
649
|
const skills = join(CODEX, "skills");
|
|
616
|
-
|
|
650
|
+
let n = rmMatchingDirs(
|
|
617
651
|
skills,
|
|
618
652
|
(name) => name === "multi-agent" || name.startsWith("multi-agent-"),
|
|
619
653
|
);
|
|
654
|
+
n += rmPluginDeliveredSkills(skills);
|
|
620
655
|
if (n > 0) console.log(` removed ${n} skill dir(s) under ${skills}`);
|
|
621
656
|
rmIfExists(join(CODEX, "prompts", "multi-agent.md"));
|
|
622
657
|
removeGeneratedCodexAgents(join(CODEX, "agents"));
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
# update-issue-progress.sh <task-id>
|
|
15
15
|
#
|
|
16
16
|
# Inputs:
|
|
17
|
-
# $HOME/.claude/
|
|
18
|
-
# .
|
|
17
|
+
# $HOME/.claude/logs/multi-agent/{project}/{taskId}/agent-state.json
|
|
18
|
+
# .githubIssue.owner, .githubIssue.repo, .githubIssue.number
|
|
19
19
|
# .flags.implementation, .flags.testing, .flags.codeConnect, .flags.wiki
|
|
20
20
|
#
|
|
21
21
|
# Side effects:
|
|
@@ -86,11 +86,12 @@ if [ "$TASK_ID" = "--rewrite" ]; then
|
|
|
86
86
|
exit 0
|
|
87
87
|
fi
|
|
88
88
|
|
|
89
|
-
# Resolve
|
|
90
|
-
|
|
89
|
+
# Resolve agent-state.json. multi-repo-pipeline.sh writes it under a
|
|
90
|
+
# per-project directory ($HOME/.claude/logs/multi-agent/{project}/{taskId}/)
|
|
91
|
+
# - not the ~/.claude/projects/*/state/ path this used to glob, which no
|
|
92
|
+
# writer in the pipeline ever populates.
|
|
91
93
|
AGENT_STATE=""
|
|
92
|
-
for
|
|
93
|
-
candidate="$dir/state/$TASK_ID/agent-state.json"
|
|
94
|
+
for candidate in "$HOME"/.claude/logs/multi-agent/*/"$TASK_ID"/agent-state.json; do
|
|
94
95
|
if [ -f "$candidate" ]; then
|
|
95
96
|
AGENT_STATE="$candidate"
|
|
96
97
|
break
|
|
@@ -102,18 +103,13 @@ if [ -z "$AGENT_STATE" ]; then
|
|
|
102
103
|
exit 2
|
|
103
104
|
fi
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if [ -z "$ORG_REPO" ] || ! [[ "$ORG_REPO" == */* ]]; then
|
|
110
|
-
if [[ "$ISSUE_URL" =~ github\.com/([^/]+/[^/]+)/issues/ ]]; then
|
|
111
|
-
ORG_REPO="${BASH_REMATCH[1]}"
|
|
112
|
-
fi
|
|
113
|
-
fi
|
|
106
|
+
# agent-state.schema.json has no `.issue`/`.repos` properties (additionalProperties
|
|
107
|
+
# is false) - the real GitHub-issue coordinates live at `.githubIssue.{owner,repo,number}`.
|
|
108
|
+
ISSUE_NUM=$(jq -r '.githubIssue.number // empty' "$AGENT_STATE")
|
|
109
|
+
ORG_REPO=$(jq -r 'if .githubIssue then (.githubIssue.owner + "/" + .githubIssue.repo) else empty end' "$AGENT_STATE")
|
|
114
110
|
|
|
115
111
|
if [ -z "$ORG_REPO" ] || [ -z "$ISSUE_NUM" ]; then
|
|
116
|
-
echo "update-issue-progress:
|
|
112
|
+
echo "update-issue-progress: no githubIssue in state for task=$TASK_ID (Jira-originated task, or issue not yet linked)" >&2
|
|
117
113
|
exit 3
|
|
118
114
|
fi
|
|
119
115
|
|
|
@@ -202,6 +202,7 @@ fi
|
|
|
202
202
|
# copied only if present; a task that never reached Phase 4 has no triage output
|
|
203
203
|
# and that is not an error.
|
|
204
204
|
DEST="$LOGS_ROOT/${PROJECT:+$PROJECT/}$TASK_ID/artifacts"
|
|
205
|
+
LOGS_TASK_DIR="$LOGS_ROOT/${PROJECT:+$PROJECT/}$TASK_ID"
|
|
205
206
|
|
|
206
207
|
copy_one() {
|
|
207
208
|
src="$rp_wt/$1"
|
|
@@ -214,7 +215,27 @@ copy_one() {
|
|
|
214
215
|
cp -R "$src" "$DEST/$1" 2>/dev/null && SALVAGED="${SALVAGED:+$SALVAGED,}\"$1\""
|
|
215
216
|
}
|
|
216
217
|
|
|
217
|
-
|
|
218
|
+
# agent-state.json and the tracker state file are never written INSIDE the
|
|
219
|
+
# worktree checkout - multi-repo-pipeline.sh/phase-tracker.sh write both
|
|
220
|
+
# straight to $LOGS_TASK_DIR. copy_one() sourcing from $rp_wt always missed
|
|
221
|
+
# them (src never existed → silent no-op), so this salvage - and the
|
|
222
|
+
# worktreeRemovedAt stamp below, gated on the salvaged copy existing - never
|
|
223
|
+
# actually fired for either file.
|
|
224
|
+
copy_from_logs() {
|
|
225
|
+
src="$LOGS_TASK_DIR/$1"
|
|
226
|
+
[ -e "$src" ] || return 0
|
|
227
|
+
if [ "$DRY" = "1" ]; then
|
|
228
|
+
SALVAGED="${SALVAGED:+$SALVAGED,}\"$1\""
|
|
229
|
+
return 0
|
|
230
|
+
fi
|
|
231
|
+
mkdir -p "$DEST/$(dirname "$1")" 2>/dev/null
|
|
232
|
+
cp -R "$src" "$DEST/$1" 2>/dev/null && SALVAGED="${SALVAGED:+$SALVAGED,}\"$1\""
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
copy_from_logs agent-state.json
|
|
236
|
+
copy_from_logs tracker-state.json
|
|
237
|
+
|
|
238
|
+
for a in triage-output.json \
|
|
218
239
|
.review-diff.txt .build.log .test.log .pipeline; do
|
|
219
240
|
copy_one "$a"
|
|
220
241
|
done
|
|
@@ -230,7 +251,7 @@ fi
|
|
|
230
251
|
# tree. This is what keeps `--force` off the table: a refusal after this point
|
|
231
252
|
# means unexpected dirt, and forcing past unexpected dirt is how work gets lost.
|
|
232
253
|
DROPPED=""
|
|
233
|
-
for a in
|
|
254
|
+
for a in triage-output.json \
|
|
234
255
|
.review-diff.txt .build.log .test.log .pipeline; do
|
|
235
256
|
[ -e "$rp_wt/$a" ] || continue
|
|
236
257
|
case "$a" in
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
|
-
"skillCount":
|
|
3
|
+
"skillCount": 202,
|
|
4
4
|
"entries": [
|
|
5
5
|
{
|
|
6
6
|
"name": "accessibility-compliance-accessibility-audit",
|
|
@@ -695,6 +695,15 @@
|
|
|
695
695
|
"triggerPaths": [],
|
|
696
696
|
"relativePath": "shared/external/live-activities/SKILL.md"
|
|
697
697
|
},
|
|
698
|
+
{
|
|
699
|
+
"name": "localization-reuse-map",
|
|
700
|
+
"description": ">-",
|
|
701
|
+
"platform": null,
|
|
702
|
+
"group": "external",
|
|
703
|
+
"triggerKeywords": [],
|
|
704
|
+
"triggerPaths": [],
|
|
705
|
+
"relativePath": "shared/external/localization-reuse-map/SKILL.md"
|
|
706
|
+
},
|
|
698
707
|
{
|
|
699
708
|
"name": "macos-menubar-tuist-app",
|
|
700
709
|
"description": "Build, refactor, or review SwiftUI macOS menubar apps that use Tuist. Use when building, refactoring or reviewing a SwiftUI macOS menubar app that uses Tuist.",
|
|
@@ -922,7 +931,7 @@
|
|
|
922
931
|
},
|
|
923
932
|
{
|
|
924
933
|
"name": "multi-agent-language",
|
|
925
|
-
"description": "Toggle outputLanguage (assistant explanations). promptLanguage is fixed to English
|
|
934
|
+
"description": "Toggle outputLanguage (assistant explanations, picker questions, PR/Jira/Confluence bodies). promptLanguage is fixed to English; commit messages, branch names and identifiers stay English. Use when the assistant should explain itself in a different language.",
|
|
926
935
|
"platform": null,
|
|
927
936
|
"group": "core",
|
|
928
937
|
"triggerKeywords": [],
|
|
@@ -47,7 +47,7 @@ Source layout is logical grouping only - skill discovery at runtime is unchang
|
|
|
47
47
|
| [`multi-agent-issue`](./core/multi-agent-issue/) | `core` | List unassigned GitHub issues, pick one, auto-assign, and launch the multi-agent pipeline. Use when a GitHub issue should be picked up and s |
|
|
48
48
|
| [`multi-agent-jira`](./core/multi-agent-jira/) | `core` | List open Jira issues, pick one, and launch the multi-agent pipeline. Use when a Jira issue should be picked up and started without knowing |
|
|
49
49
|
| [`multi-agent-kill`](./core/multi-agent-kill/) | `core` | Stop the given task, then remove its worktree and branch. Asks for confirmation. Use when a running or stuck task should be stopped and its |
|
|
50
|
-
| [`multi-agent-language`](./core/multi-agent-language/) | `core` | Toggle outputLanguage (assistant explanations). promptLanguage is fixed to English
|
|
50
|
+
| [`multi-agent-language`](./core/multi-agent-language/) | `core` | Toggle outputLanguage (assistant explanations, picker questions, PR/Jira/Confluence bodies). promptLanguage is fixed to English; commit mess |
|
|
51
51
|
| [`multi-agent-local`](./core/multi-agent-local/) | `core` | Full pipeline in local mode - no worktree, runs directly on the current branch. Use when the full pipeline should run on the current branc |
|
|
52
52
|
| [`multi-agent-local-autopilot`](./core/multi-agent-local-autopilot/) | `core` | Full pipeline + local + autopilot - no worktree, no confirmations, all 8 phases run end-to-end on the current branch. Use when the full pi |
|
|
53
53
|
| [`multi-agent-log`](./core/multi-agent-log/) | `core` | Show the agent-log.md for the given task. With no ID, shows the most recent task. Use when asked what a task did, or to read its log. |
|
|
@@ -49,3 +49,7 @@ Run the task end-to-end with no confirmations.
|
|
|
49
49
|
2. **Set the autopilot flag** - `"autopilot": true` in `agent-state.json`
|
|
50
50
|
3. **Start the multi-agent pipeline** - All confirmations are skipped
|
|
51
51
|
4. **On failure** - After 3 retries still failing → pause, ask the user
|
|
52
|
+
|
|
53
|
+
## Required: outward-facing payload contracts
|
|
54
|
+
|
|
55
|
+
Before writing anything outward-facing - PR body, Jira comment, Confluence page, closing report - load `$HOME/.claude/multi-agent-refs/payload-contracts.md`. It names the canonical section set for each payload, the markup dialect per surface (PR body is Markdown, Jira is wiki markup - mixing them is a defect), and the token/duration numbers the closing report must carry. Improvising a payload shape from memory is the most common failure of the short modes.
|
|
@@ -12,7 +12,7 @@ argument-hint: "[\"<free-text description>\"] [figma-url] [swagger-url] - all
|
|
|
12
12
|
|
|
13
13
|
Creates exactly one Jira issue, and only after explicit approval. The issue type (Task / Bug / Story) is asked at the start of every run. No branches, no commits, no worktrees. The description comes from the type's standard template (baseline, not a mined heading set); sections auto-size - a conditional section renders only when its trigger is present, otherwise the heading is omitted.
|
|
14
14
|
|
|
15
|
-
> **Language**: issue content (summary + description) and user-facing questions follow `prefs.global.outputLanguage
|
|
15
|
+
> **Language**: issue content (summary + description) and user-facing questions follow `prefs.global.outputLanguage`, like every other user-facing payload body (`rules.md` matrix). Code identifiers and URLs stay verbatim.
|
|
16
16
|
|
|
17
17
|
## Standard templates (A = always, C = conditional)
|
|
18
18
|
|
|
@@ -64,23 +64,10 @@ Phase 7: Report → Channels (Jira / Confluence / PR / Wiki)
|
|
|
64
64
|
| Phase 7 channels (Jira / Confluence / PR / Wiki) | ✅ | ✅ (same) |
|
|
65
65
|
| Duration | ~10-15 min | ~7-10 min |
|
|
66
66
|
|
|
67
|
-
##
|
|
67
|
+
## Required: outward-facing payload contracts
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
the input references an analysis document - a Confluence URL, a local analysis file,
|
|
71
|
-
or the user says "I ran analysis for this" - there is **no phase that turns it into a
|
|
72
|
-
plan**. The doc becomes raw context for one Dev pass, and work comes out ordered by
|
|
73
|
-
whatever the model read first: the bottom of the dependency chain lands, the screen
|
|
74
|
-
wiring does not.
|
|
69
|
+
Before writing anything outward-facing - PR body, Jira comment, Confluence page, closing report - load `$HOME/.claude/multi-agent-refs/payload-contracts.md`. It names the canonical section set for each payload, the markup dialect per surface (PR body is Markdown, Jira is wiki markup - mixing them is a defect), and the token/duration numbers the closing report must carry. Improvising a payload shape from memory is the most common failure of the short modes.
|
|
75
70
|
|
|
76
|
-
|
|
71
|
+
## Intake warnings (`--dev` family)
|
|
77
72
|
|
|
78
|
-
|
|
79
|
-
This mode skips Analysis and Planning, so the analysis document will not be turned
|
|
80
|
-
into a task breakdown. For analysis-driven screen work, /multi-agent or
|
|
81
|
-
/multi-agent:local run both phases.
|
|
82
|
-
1. Continue with --dev (doc as context only)
|
|
83
|
-
2. Switch to the full pipeline
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Autopilot picks 1 and logs the warning rather than asking.
|
|
73
|
+
Two checks belong at the top of every `--dev` run and are specified once in `$HOME/.claude/multi-agent-refs/phases/modes.md` "Intake warnings shared by the whole `--dev` family": an analysis document supplied to a mode that skips Analysis and Planning, and a branch that already carries the work (which wants `/multi-agent:ship`, not a second Dev pass). Read that section rather than reasoning about it from scratch.
|
|
@@ -55,3 +55,11 @@ Phase 7: Report → Short terminal summary
|
|
|
55
55
|
| Confirmation (test/commit/PR) | Yes | Yes | No | **No** |
|
|
56
56
|
| Review | Parallel+triage (CLI-aware) | Parallel+triage (CLI-aware) | Parallel+triage (CLI-aware) | **Parallel+triage, auto-fix** |
|
|
57
57
|
| Estimated duration | ~12 min | ~7 min | ~10 min | **~5 min** |
|
|
58
|
+
|
|
59
|
+
## Required: outward-facing payload contracts
|
|
60
|
+
|
|
61
|
+
Before writing anything outward-facing - PR body, Jira comment, Confluence page, closing report - load `$HOME/.claude/multi-agent-refs/payload-contracts.md`. It names the canonical section set for each payload, the markup dialect per surface (PR body is Markdown, Jira is wiki markup - mixing them is a defect), and the token/duration numbers the closing report must carry. Improvising a payload shape from memory is the most common failure of the short modes.
|
|
62
|
+
|
|
63
|
+
## Intake warnings (`--dev` family)
|
|
64
|
+
|
|
65
|
+
Two checks belong at the top of every `--dev` run and are specified once in `$HOME/.claude/multi-agent-refs/phases/modes.md` "Intake warnings shared by the whole `--dev` family": an analysis document supplied to a mode that skips Analysis and Planning, and a branch that already carries the work (which wants `/multi-agent:ship`, not a second Dev pass). Read that section rather than reasoning about it from scratch.
|
|
@@ -21,7 +21,7 @@ Phase 7: Report → Jira/Wiki + log + knowledge/memory
|
|
|
21
21
|
|
|
22
22
|
## When to use it
|
|
23
23
|
|
|
24
|
-
- Quick bug fix or small feature -
|
|
24
|
+
- Quick bug fix or small feature - analysis and planning buy nothing here
|
|
25
25
|
- You're working on the current branch and don't want to switch worktrees
|
|
26
26
|
- Quick bug fix or small feature - analysis and planning buy nothing here
|
|
27
27
|
|
|
@@ -36,23 +36,10 @@ multi-agent-dev-local "PROJ-12345" # Jira
|
|
|
36
36
|
multi-agent-dev-local "Bug: LoginView dark mode" # Free-text
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
##
|
|
40
|
-
|
|
41
|
-
The `--dev` family skips Phase 1 (Analysis) and Phase 2 (Planning) by design. So when
|
|
42
|
-
the input references an analysis document - a Confluence URL, a local analysis file,
|
|
43
|
-
or the user says "I ran analysis for this" - there is **no phase that turns it into a
|
|
44
|
-
plan**. The doc becomes raw context for one Dev pass, and work comes out ordered by
|
|
45
|
-
whatever the model read first: the bottom of the dependency chain lands, the screen
|
|
46
|
-
wiring does not.
|
|
39
|
+
## Required: outward-facing payload contracts
|
|
47
40
|
|
|
48
|
-
|
|
41
|
+
Before writing anything outward-facing - PR body, Jira comment, Confluence page, closing report - load `$HOME/.claude/multi-agent-refs/payload-contracts.md`. It names the canonical section set for each payload, the markup dialect per surface (PR body is Markdown, Jira is wiki markup - mixing them is a defect), and the token/duration numbers the closing report must carry. Improvising a payload shape from memory is the most common failure of the short modes.
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
This mode skips Analysis and Planning, so the analysis document will not be turned
|
|
52
|
-
into a task breakdown. For analysis-driven screen work, /multi-agent or
|
|
53
|
-
/multi-agent:local run both phases.
|
|
54
|
-
1. Continue with --dev (doc as context only)
|
|
55
|
-
2. Switch to the full pipeline
|
|
56
|
-
```
|
|
43
|
+
## Intake warnings (`--dev` family)
|
|
57
44
|
|
|
58
|
-
|
|
45
|
+
Two checks belong at the top of every `--dev` run and are specified once in `$HOME/.claude/multi-agent-refs/phases/modes.md` "Intake warnings shared by the whole `--dev` family": an analysis document supplied to a mode that skips Analysis and Planning, and a branch that already carries the work (which wants `/multi-agent:ship`, not a second Dev pass). Read that section rather than reasoning about it from scratch.
|
|
@@ -41,3 +41,11 @@ Routes to the orchestrator with the `--dev --local autopilot` flags. The pipelin
|
|
|
41
41
|
multi-agent-dev-local-autopilot "PROJ-12345" # Jira
|
|
42
42
|
multi-agent-dev-local-autopilot "Add retry to HomeNetworking" # Free-text
|
|
43
43
|
```
|
|
44
|
+
|
|
45
|
+
## Required: outward-facing payload contracts
|
|
46
|
+
|
|
47
|
+
Before writing anything outward-facing - PR body, Jira comment, Confluence page, closing report - load `$HOME/.claude/multi-agent-refs/payload-contracts.md`. It names the canonical section set for each payload, the markup dialect per surface (PR body is Markdown, Jira is wiki markup - mixing them is a defect), and the token/duration numbers the closing report must carry. Improvising a payload shape from memory is the most common failure of the short modes.
|
|
48
|
+
|
|
49
|
+
## Intake warnings (`--dev` family)
|
|
50
|
+
|
|
51
|
+
Two checks belong at the top of every `--dev` run and are specified once in `$HOME/.claude/multi-agent-refs/phases/modes.md` "Intake warnings shared by the whole `--dev` family": an analysis document supplied to a mode that skips Analysis and Planning, and a branch that already carries the work (which wants `/multi-agent:ship`, not a second Dev pass). Read that section rather than reasoning about it from scratch.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: multi-agent-language
|
|
3
3
|
language: en
|
|
4
|
-
description: "Toggle outputLanguage (assistant explanations). promptLanguage is fixed to English
|
|
4
|
+
description: "Toggle outputLanguage (assistant explanations, picker questions, PR/Jira/Confluence bodies). promptLanguage is fixed to English; commit messages, branch names and identifiers stay English. Use when the assistant should explain itself in a different language."
|
|
5
5
|
user-invocable: true
|
|
6
6
|
argument-hint: "[en|tr] - sets outputLanguage; omit for interactive picker; use 'output en|tr' for explicit form"
|
|
7
7
|
---
|
|
@@ -35,3 +35,7 @@ multi-agent-local "PROJ-12345" # Jira
|
|
|
35
35
|
multi-agent-local "#42" # GitHub issue
|
|
36
36
|
multi-agent-local "LoginView dark mode fix" # Free-text
|
|
37
37
|
```
|
|
38
|
+
|
|
39
|
+
## Required: outward-facing payload contracts
|
|
40
|
+
|
|
41
|
+
Before writing anything outward-facing - PR body, Jira comment, Confluence page, closing report - load `$HOME/.claude/multi-agent-refs/payload-contracts.md`. It names the canonical section set for each payload, the markup dialect per surface (PR body is Markdown, Jira is wiki markup - mixing them is a defect), and the token/duration numbers the closing report must carry. Improvising a payload shape from memory is the most common failure of the short modes.
|
|
@@ -51,3 +51,7 @@ multi-agent-local-autopilot "#3"
|
|
|
51
51
|
## Delegation
|
|
52
52
|
|
|
53
53
|
The orchestrator skill (`multi-agent/SKILL.md`) takes the `--local` + `"autopilot": true` state flags together. Contract: `refs/phases/phase-0-init.md` Step 8 (local branch) + `refs/phases/phase-2-planning.md` Step 5 (gate skip) + Step 5c (safety classifier, v7.0.0+).
|
|
54
|
+
|
|
55
|
+
## Required: outward-facing payload contracts
|
|
56
|
+
|
|
57
|
+
Before writing anything outward-facing - PR body, Jira comment, Confluence page, closing report - load `$HOME/.claude/multi-agent-refs/payload-contracts.md`. It names the canonical section set for each payload, the markup dialect per surface (PR body is Markdown, Jira is wiki markup - mixing them is a defect), and the token/duration numbers the closing report must carry. Improvising a payload shape from memory is the most common failure of the short modes.
|
|
@@ -45,3 +45,7 @@ multi-agent ship autopilot # no gate prompts: auto-fix, auto-PR, auto-c
|
|
|
45
45
|
- Build+Test is the automated success gate (not the interactive device user-test - that is `multi-agent:manual-test`). If the repo has no tests, it reports "no tests present" - never fabricates results.
|
|
46
46
|
- Commit/PR follows house rules: conventional message, `Ref: #N` (never Closes/Fixes), NO AI/bot attribution. PR opened only if one does not already exist.
|
|
47
47
|
- Full phase contract lives in the Claude Code command `commands/multi-agent/ship/SKILL.md`; this skill is the Copilot-CLI counterpart.
|
|
48
|
+
|
|
49
|
+
## Required: outward-facing payload contracts
|
|
50
|
+
|
|
51
|
+
Before writing anything outward-facing - PR body, Jira comment, Confluence page, closing report - load `$HOME/.claude/multi-agent-refs/payload-contracts.md`. It names the canonical section set for each payload, the markup dialect per surface (PR body is Markdown, Jira is wiki markup - mixing them is a defect), and the token/duration numbers the closing report must carry. Improvising a payload shape from memory is the most common failure of the short modes.
|
|
@@ -32,7 +32,7 @@ Run all steps automatically:
|
|
|
32
32
|
```
|
|
33
33
|
Step 1: DETECT Compare timestamps, find stale targets
|
|
34
34
|
Step 2: COPILOT Claude Code -> Copilot CLI (instructions + 49 sub-command skills)
|
|
35
|
-
Step 2b: CODEX Claude Code -> Codex CLI (1 router skill +
|
|
35
|
+
Step 2b: CODEX Claude Code -> Codex CLI (1 router skill + 49 specs as refs + 8 agent TOML)
|
|
36
36
|
Step 3: REPO Claude Code -> pipeline repo (genericized, personal data scrub)
|
|
37
37
|
Step 3d: DEV-TOOLKIT Companion MCP server -> detect movement, ship gates, commit + publish
|
|
38
38
|
Step 4: WEBSITE Version + phase/model counts -> {website-host} (i18n + projects.ts)
|
|
@@ -98,7 +98,7 @@ If nothing is stale -> report "All targets up to date" and stop.
|
|
|
98
98
|
## Codex Sync (Step 2b)
|
|
99
99
|
|
|
100
100
|
This step does **not** hand-copy files. The Codex tree is a *transform* of the Claude
|
|
101
|
-
tree, not a mirror: the
|
|
101
|
+
tree, not a mirror: the 49 sub-command specs become reference files (Codex silently
|
|
102
102
|
truncates its skills block - see `cross-cli-contract.md` 2.6), every reference to a
|
|
103
103
|
CLI-owned tree is retargeted (`agents/<persona>.md` becomes `.toml`, the dispatcher
|
|
104
104
|
becomes the router skill), the 8 personas are regenerated as TOML with a model +
|