@mmerterden/multi-agent-pipeline 20.30.0 → 20.33.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 +80 -0
- package/README.md +45 -0
- package/README.tr.md +59 -0
- package/docs/facts.json +3 -3
- package/install/_unattended-profile.mjs +61 -0
- package/install/catalog-history.json +1 -1
- package/install/claude.mjs +9 -2
- package/install/index.mjs +10 -1
- package/install/templates/claude-hooks.json +12 -1
- package/manifest.json +123 -82
- package/package.json +2 -1
- package/pipeline/commands/multi-agent/analysis/SKILL.md +4 -4
- package/pipeline/commands/multi-agent/office-on/SKILL.md +8 -7
- package/pipeline/commands/multi-agent/office-status/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/prune-logs/SKILL.md +4 -1
- package/pipeline/commands/multi-agent/review/SKILL.md +4 -3
- package/pipeline/commands/multi-agent/scenario-audit/SKILL.md +4 -2
- package/pipeline/commands/multi-agent/sync/SKILL.md +12 -0
- package/pipeline/commands/multi-agent/test-gen/SKILL.md +29 -3
- package/pipeline/contract/CHANGELOG.md +46 -0
- package/pipeline/contract/README.md +22 -8
- package/pipeline/contract/fixtures/error-invalid-request.json +1 -1
- package/pipeline/contract/fixtures/error-unauthorized.json +1 -1
- package/pipeline/contract/fixtures/error-unsigned.json +1 -1
- package/pipeline/contract/fixtures/launch-plan.json +1 -1
- package/pipeline/contract/fixtures/runs-awaiting-question.json +6 -1
- package/pipeline/contract/fixtures/runs-empty.json +1 -1
- package/pipeline/contract/fixtures/runs-failed.json +6 -1
- package/pipeline/contract/fixtures/runs-old-schema.json +6 -1
- package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +5 -1
- package/pipeline/contract/fixtures/runs-pr-opened.json +6 -1
- package/pipeline/contract/fixtures/runs-running.json +6 -1
- package/pipeline/contract/manifest.json +153 -19
- package/pipeline/contract/types/index.d.ts +304 -6
- package/pipeline/lib/bg-launch.mjs +106 -0
- package/pipeline/lib/code-digest.mjs +49 -0
- package/pipeline/lib/credential-resolve.mjs +42 -2
- package/pipeline/multi-agent-refs/features/office-threat-model.md +24 -6
- package/pipeline/multi-agent-refs/features/unattended-security.md +1 -1
- package/pipeline/multi-agent-refs/help/en.md +2 -2
- package/pipeline/multi-agent-refs/help/tr.md +2 -2
- package/pipeline/multi-agent-refs/phases/modes.md +7 -7
- package/pipeline/multi-agent-refs/phases/phase-5-report.md +16 -10
- package/pipeline/multi-agent-refs/review-standalone-tracker.md +37 -0
- package/pipeline/multi-agent-refs/tracker-contract.md +8 -3
- package/pipeline/office/NOTICE.md +4 -1
- package/pipeline/office/assets/ARCHIVE_BOXES.png +0 -0
- package/pipeline/office/assets/COFFEE_MACHINE.png +0 -0
- package/pipeline/office/assets/COUNTER_SINK.png +0 -0
- package/pipeline/office/assets/DEVICE_STAND.png +0 -0
- package/pipeline/office/assets/FILING_CABINET.png +0 -0
- package/pipeline/office/assets/FRIDGE.png +0 -0
- package/pipeline/office/assets/MAILBOX.png +0 -0
- package/pipeline/office/assets/MOP_BUCKET.png +0 -0
- package/pipeline/office/assets/PRINTER.png +0 -0
- package/pipeline/office/assets/RECEPTION_DESK.png +0 -0
- package/pipeline/office/assets/SERVER_RACK.png +0 -0
- package/pipeline/office/assets/SERVER_RACK_2.png +0 -0
- package/pipeline/office/assets/TOILET_STALL.png +0 -0
- package/pipeline/office/assets/VENDING.png +0 -0
- package/pipeline/office/assets/WASHBASIN.png +0 -0
- package/pipeline/office/assets/WATER_COOLER.png +0 -0
- package/pipeline/office/index.html +3996 -884
- package/pipeline/office/toolkit.json +3 -0
- package/pipeline/schemas/activity.schema.json +188 -4
- package/pipeline/schemas/agent-state.schema.json +493 -115
- package/pipeline/schemas/contract-error.schema.json +12 -1
- package/pipeline/schemas/job-change.schema.json +72 -0
- package/pipeline/schemas/job-request.schema.json +38 -0
- package/pipeline/schemas/launch.json +4 -4
- package/pipeline/schemas/office-credentials.schema.json +71 -0
- package/pipeline/schemas/office-jobs.json +253 -0
- package/pipeline/schemas/office-jobs.schema.json +62 -0
- package/pipeline/schemas/office-memory.schema.json +105 -0
- package/pipeline/schemas/office-settings-request.schema.json +30 -0
- package/pipeline/schemas/office-settings.schema.json +67 -0
- package/pipeline/schemas/phases.json +10 -2
- package/pipeline/schemas/phases.schema.json +86 -19
- package/pipeline/schemas/prs.schema.json +5 -0
- package/pipeline/schemas/prune-logs-request.schema.json +26 -0
- package/pipeline/schemas/prune-logs.schema.json +52 -0
- package/pipeline/schemas/repo-change.schema.json +54 -0
- package/pipeline/schemas/repo-request.schema.json +29 -0
- package/pipeline/schemas/repos.schema.json +49 -1
- package/pipeline/schemas/runs-index.schema.json +257 -46
- package/pipeline/schemas/system-status.schema.json +111 -0
- package/pipeline/schemas/tools.schema.json +5 -0
- package/pipeline/schemas/unattended-profile.json +7 -2
- package/pipeline/scripts/_active-run.mjs +2 -1
- package/pipeline/scripts/_spawn-async.mjs +9 -5
- package/pipeline/scripts/activity-snapshot.mjs +219 -23
- package/pipeline/scripts/autopilot-runner.mjs +7 -5
- package/pipeline/scripts/contract-server.mjs +551 -25
- package/pipeline/scripts/gen-mode-dispatch.mjs +3 -1
- package/pipeline/scripts/job-launch.mjs +477 -0
- package/pipeline/scripts/launch-request.mjs +94 -9
- package/pipeline/scripts/office-build.mjs +148 -11
- package/pipeline/scripts/office-control.mjs +34 -7
- package/pipeline/scripts/office-credentials.mjs +106 -0
- package/pipeline/scripts/office-memory.mjs +200 -0
- package/pipeline/scripts/office-prune.mjs +125 -0
- package/pipeline/scripts/office-settings.mjs +145 -0
- package/pipeline/scripts/phase-tracker.sh +12 -5
- package/pipeline/scripts/prune-logs.sh +53 -2
- package/pipeline/scripts/runs-index.mjs +62 -2
- package/pipeline/scripts/system-status.mjs +196 -0
- package/pipeline/scripts/task-mirror.mjs +150 -0
- package/pipeline/scripts/task-mirror.sh +20 -0
- package/pipeline/scripts/toolkit-tools.mjs +33 -7
- package/pipeline/scripts/transcript-index.mjs +4 -1
- package/pipeline/scripts/work-items.mjs +191 -22
- package/pipeline/skills/.skill-manifest.json +6 -6
- package/pipeline/skills/.skills-index.json +1 -1
- package/pipeline/skills/shared/README.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-office-on/SKILL.md +3 -4
- package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +4 -1
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +19 -0
- package/pipeline/skills/shared/core/multi-agent-scenario-audit/SKILL.md +4 -2
- package/pipeline/skills/shared/core/multi-agent-test-gen/SKILL.md +26 -3
- package/pipeline/skills/skills-index.md +1 -1
|
@@ -55,8 +55,10 @@ import { spawnAsync } from "./_spawn-async.mjs";
|
|
|
55
55
|
import { readRegularJson } from "../lib/regular-file.mjs";
|
|
56
56
|
import { runMain } from "../lib/fatal.mjs";
|
|
57
57
|
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
58
|
+
import { resolveTokenAsync } from "../lib/credential-resolve.mjs";
|
|
59
|
+
import { homedir } from "node:os";
|
|
58
60
|
|
|
59
|
-
export const CONTRACT_VERSION = "1.
|
|
61
|
+
export const CONTRACT_VERSION = "1.1.0";
|
|
60
62
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
61
63
|
/** A Jira key, `owner/repo#N` or `#N`: the structured inputs launch accepts too. */
|
|
62
64
|
export const ISSUE_KEY =
|
|
@@ -114,7 +116,130 @@ export async function issueMaturity(key, env = process.env) {
|
|
|
114
116
|
};
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
|
|
119
|
+
/**
|
|
120
|
+
* The GitHub accounts `gh` is logged in to, as host and login: a personal and
|
|
121
|
+
* a corporate account are asked one by one, each with its own token, so a
|
|
122
|
+
* review request on either shows. Empty when `gh auth status` says nothing
|
|
123
|
+
* readable; the caller then asks with gh's active account alone.
|
|
124
|
+
*/
|
|
125
|
+
async function ghAccounts(env) {
|
|
126
|
+
const gh = env.MA_GH_BIN || "gh";
|
|
127
|
+
const r = await spawnAsync(gh, ["auth", "status"], {
|
|
128
|
+
env,
|
|
129
|
+
timeoutMs: TIMEOUT_MS,
|
|
130
|
+
withStderr: true,
|
|
131
|
+
});
|
|
132
|
+
const text = r.stdout || "";
|
|
133
|
+
const out = [];
|
|
134
|
+
for (const m of text.matchAll(/Logged in to (\S+) account ([A-Za-z0-9_.-]+)/g))
|
|
135
|
+
if (!out.some((a) => a.host === m[1] && a.login === m[2]))
|
|
136
|
+
out.push({ host: m[1], login: m[2] });
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* gh's token for one account, carried in the environment only (GH_TOKEN, and
|
|
142
|
+
* GH_ENTERPRISE_TOKEN for an Enterprise Server host), never on a command line.
|
|
143
|
+
*/
|
|
144
|
+
async function accountEnv(env, account) {
|
|
145
|
+
const gh = env.MA_GH_BIN || "gh";
|
|
146
|
+
const r = await spawnAsync(
|
|
147
|
+
gh,
|
|
148
|
+
["auth", "token", "--hostname", account.host, "--user", account.login],
|
|
149
|
+
{ env, timeoutMs: TIMEOUT_MS },
|
|
150
|
+
);
|
|
151
|
+
const token = (r.stdout || "").trim();
|
|
152
|
+
if (r.status !== 0 || !token) return null;
|
|
153
|
+
// gh reads GH_TOKEN for github.com and GH_ENTERPRISE_TOKEN for a GitHub
|
|
154
|
+
// Enterprise Server host, so an enterprise account gets both.
|
|
155
|
+
const enterprise = !/^(github\.com|[a-z0-9-]+\.ghe\.com)$/i.test(account.host);
|
|
156
|
+
return {
|
|
157
|
+
...env,
|
|
158
|
+
GH_TOKEN: token,
|
|
159
|
+
GH_HOST: account.host,
|
|
160
|
+
...(enterprise ? { GH_ENTERPRISE_TOKEN: token } : {}),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Open pull requests on the configured Bitbucket Server where this user is a
|
|
166
|
+
* reviewer or the author, from its dashboard API. The token comes from the
|
|
167
|
+
* credential store and travels in the request header only.
|
|
168
|
+
*/
|
|
169
|
+
async function bitbucketPrs(env) {
|
|
170
|
+
let host = env.MA_BITBUCKET_HOST || null;
|
|
171
|
+
if (!host) {
|
|
172
|
+
try {
|
|
173
|
+
const prefs = readRegularJson(
|
|
174
|
+
env.MULTI_AGENT_PREFS ||
|
|
175
|
+
join(env.HOME || homedir(), ".claude", "multi-agent-preferences.json"),
|
|
176
|
+
null,
|
|
177
|
+
);
|
|
178
|
+
host = prefs?.global?.hosts?.bitbucket ?? null;
|
|
179
|
+
} catch {
|
|
180
|
+
host = null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (typeof host !== "string" || !host) return { ok: false, items: [], reason: "not configured" };
|
|
184
|
+
// The token travels in a header, so only over TLS: a host written with
|
|
185
|
+
// http:// is refused unless it is this machine's own loopback.
|
|
186
|
+
const loopback = /^http:\/\/(127\.0\.0\.1|localhost)(:\d+)?(\/|$)/i.test(host);
|
|
187
|
+
if (/^http:\/\//i.test(host) && !loopback)
|
|
188
|
+
return { ok: false, items: [], reason: "https required" };
|
|
189
|
+
const base = /^https?:\/\//i.test(host) ? host.replace(/\/+$/, "") : `https://${host}`;
|
|
190
|
+
const token =
|
|
191
|
+
env.MA_BITBUCKET_TOKEN ||
|
|
192
|
+
(await resolveTokenAsync("bitbucket_token", "BITBUCKET_TOKEN", { env }));
|
|
193
|
+
if (!token) return { ok: false, items: [], reason: "no token in the credential store" };
|
|
194
|
+
// The same rule as credential-inventory.sh: Basic with the stored user (an
|
|
195
|
+
// app password), else the token as a bearer.
|
|
196
|
+
const user =
|
|
197
|
+
env.MA_BITBUCKET_USER || (await resolveTokenAsync("bitbucket_user", "BITBUCKET_USER", { env }));
|
|
198
|
+
const authorization = user
|
|
199
|
+
? "Basic " + Buffer.from(`${user}:${token}`).toString("base64")
|
|
200
|
+
: `Bearer ${token}`;
|
|
201
|
+
const items = [];
|
|
202
|
+
try {
|
|
203
|
+
for (const role of ["REVIEWER", "AUTHOR"]) {
|
|
204
|
+
const res = await fetch(
|
|
205
|
+
`${base}/rest/api/1.0/dashboard/pull-requests?state=OPEN&role=${role}&limit=50`,
|
|
206
|
+
{
|
|
207
|
+
headers: { Authorization: authorization, Accept: "application/json" },
|
|
208
|
+
redirect: "error",
|
|
209
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
if (res.status === 401 || res.status === 403)
|
|
213
|
+
return { ok: false, items: [], reason: "the token was refused" };
|
|
214
|
+
if (!res.ok) return { ok: false, items: [], reason: `Bitbucket answered ${res.status}` };
|
|
215
|
+
const doc = await res.json();
|
|
216
|
+
for (const p of Array.isArray(doc?.values) ? doc.values : []) {
|
|
217
|
+
const repo = p?.toRef?.repository;
|
|
218
|
+
items.push({
|
|
219
|
+
source: "bitbucket",
|
|
220
|
+
account: null,
|
|
221
|
+
repo: String(repo ? `${repo.project?.key ?? ""}/${repo.slug ?? ""}` : ""),
|
|
222
|
+
number: Number(p?.id) || 0,
|
|
223
|
+
title: scrub(String(p?.title ?? "")),
|
|
224
|
+
url: typeof p?.links?.self?.[0]?.href === "string" ? p.links.self[0].href : null,
|
|
225
|
+
author: p?.author?.user?.name ? String(p.author.user.name) : null,
|
|
226
|
+
updatedAt: Number.isFinite(p?.updatedDate) ? new Date(p.updatedDate).toISOString() : null,
|
|
227
|
+
role: role === "REVIEWER" ? "reviewer" : "author",
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
} catch (e) {
|
|
232
|
+
const why = String(e?.cause?.message ?? e?.message ?? "");
|
|
233
|
+
return {
|
|
234
|
+
ok: false,
|
|
235
|
+
items: [],
|
|
236
|
+
reason: /redirect/i.test(why) ? "redirect refused" : "unreachable (VPN?)",
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return { ok: true, items };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function ghSearch(env, role, account = null) {
|
|
118
243
|
const gh = env.MA_GH_BIN || "gh";
|
|
119
244
|
const flag = role === "reviewer" ? "--review-requested=@me" : "--author=@me";
|
|
120
245
|
const r = await spawnAsync(
|
|
@@ -139,6 +264,7 @@ async function ghSearch(env, role) {
|
|
|
139
264
|
ok: true,
|
|
140
265
|
items: (Array.isArray(rows) ? rows : []).map((p) => ({
|
|
141
266
|
source: "github",
|
|
267
|
+
account,
|
|
142
268
|
repo: String(p?.repository?.nameWithOwner ?? p?.repository?.name ?? ""),
|
|
143
269
|
number: Number(p?.number) || 0,
|
|
144
270
|
title: scrub(String(p?.title ?? "")),
|
|
@@ -153,31 +279,74 @@ async function ghSearch(env, role) {
|
|
|
153
279
|
}
|
|
154
280
|
}
|
|
155
281
|
|
|
156
|
-
/**
|
|
282
|
+
/**
|
|
283
|
+
* Open pull requests on every host the pipeline can list, one list: every
|
|
284
|
+
* GitHub account gh is logged in to (personal and corporate alike) and the
|
|
285
|
+
* configured Bitbucket Server.
|
|
286
|
+
*/
|
|
157
287
|
export async function pullRequests({ env = process.env, redact = false } = {}) {
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
288
|
+
const accounts = await ghAccounts(env);
|
|
289
|
+
// gh before `auth token --user` hands out no token per account; then the
|
|
290
|
+
// active account answers alone, as a plain `gh search` does.
|
|
291
|
+
const envs = await Promise.all(accounts.map((a) => accountEnv(env, a)));
|
|
292
|
+
const perAccount = envs.some(Boolean);
|
|
293
|
+
const github = [];
|
|
294
|
+
if (accounts.length && perAccount) {
|
|
295
|
+
for (const [i, a] of accounts.entries()) {
|
|
296
|
+
const aEnv = envs[i];
|
|
297
|
+
if (!aEnv) {
|
|
298
|
+
github.push({
|
|
299
|
+
source: `github:${a.login}`,
|
|
300
|
+
ok: false,
|
|
301
|
+
items: [],
|
|
302
|
+
reason: "gh has no token for it",
|
|
303
|
+
});
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
const [rv, au] = await Promise.all([
|
|
307
|
+
ghSearch(aEnv, "reviewer", a.login),
|
|
308
|
+
ghSearch(aEnv, "author", a.login),
|
|
309
|
+
]);
|
|
310
|
+
github.push({
|
|
311
|
+
source: `github:${a.login}`,
|
|
312
|
+
ok: rv.ok || au.ok,
|
|
313
|
+
items: [...rv.items, ...au.items],
|
|
314
|
+
reason: rv.ok || au.ok ? undefined : "gh could not list pull requests",
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
} else {
|
|
318
|
+
const [rv, au] = await Promise.all([ghSearch(env, "reviewer"), ghSearch(env, "author")]);
|
|
319
|
+
github.push({
|
|
320
|
+
source: "github",
|
|
321
|
+
ok: rv.ok || au.ok,
|
|
322
|
+
items: [...rv.items, ...au.items],
|
|
323
|
+
reason: rv.ok || au.ok ? undefined : "gh could not list pull requests",
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
const bitbucket = { source: "bitbucket", ...(await bitbucketPrs(env)) };
|
|
162
327
|
const seen = new Set();
|
|
163
328
|
const items = [];
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
329
|
+
const sources = [];
|
|
330
|
+
// A redacted answer (the phone's) names no login: accounts become numbers.
|
|
331
|
+
let accountNo = 0;
|
|
332
|
+
for (const src of [...github, bitbucket]) {
|
|
333
|
+
const label = redact && src.source.startsWith("github:") ? `github:${++accountNo}` : src.source;
|
|
334
|
+
let count = 0;
|
|
335
|
+
for (const p of src.items) {
|
|
336
|
+
const k = `${p.source}:${p.repo}#${p.number}`;
|
|
337
|
+
if (seen.has(k)) continue;
|
|
338
|
+
seen.add(k);
|
|
339
|
+
count++;
|
|
340
|
+
items.push(redact ? { ...p, url: null, account: null, author: null } : p);
|
|
341
|
+
}
|
|
342
|
+
sources.push(
|
|
343
|
+
src.ok
|
|
344
|
+
? { source: label, ok: true, count }
|
|
345
|
+
: { source: label, ok: false, count: 0, reason: src.reason || "unreadable" },
|
|
346
|
+
);
|
|
169
347
|
}
|
|
170
348
|
items.sort((a, b) => ((a.updatedAt ?? "") < (b.updatedAt ?? "") ? 1 : -1));
|
|
171
|
-
return {
|
|
172
|
-
contractVersion: CONTRACT_VERSION,
|
|
173
|
-
items,
|
|
174
|
-
sources: [
|
|
175
|
-
reviewer.ok || author.ok
|
|
176
|
-
? { source: "github", ok: true, count: items.length }
|
|
177
|
-
: { source: "github", ok: false, count: 0, reason: "gh could not list pull requests" },
|
|
178
|
-
{ source: "bitbucket", ok: false, count: 0, reason: "not-implemented" },
|
|
179
|
-
],
|
|
180
|
-
};
|
|
349
|
+
return { contractVersion: CONTRACT_VERSION, items, sources };
|
|
181
350
|
}
|
|
182
351
|
|
|
183
352
|
function stateOf(taskId) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-25T17:09:06Z",
|
|
4
4
|
"skillCount": 237,
|
|
5
5
|
"entries": [
|
|
6
6
|
{
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"path": "shared/core/multi-agent-office-on/SKILL.md",
|
|
136
|
-
"sha256": "
|
|
136
|
+
"sha256": "b46a2f79beeee65ae7ad6cbfc58b4631c5146a7761e91a99b8a056d6f49c690d"
|
|
137
137
|
},
|
|
138
138
|
{
|
|
139
139
|
"path": "shared/core/multi-agent-office-status/SKILL.md",
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
},
|
|
146
146
|
{
|
|
147
147
|
"path": "shared/core/multi-agent-prune-logs/SKILL.md",
|
|
148
|
-
"sha256": "
|
|
148
|
+
"sha256": "649622e6f18887f986e0acd8b743df0a345a3adf89ccab58d6c4b191b770c1ac"
|
|
149
149
|
},
|
|
150
150
|
{
|
|
151
151
|
"path": "shared/core/multi-agent-prune-prompts/SKILL.md",
|
|
@@ -181,7 +181,7 @@
|
|
|
181
181
|
},
|
|
182
182
|
{
|
|
183
183
|
"path": "shared/core/multi-agent-review/SKILL.md",
|
|
184
|
-
"sha256": "
|
|
184
|
+
"sha256": "4a110e0cc6c36185d76e1a99d7a397a937460377c6bc426714a236a5371a26b0"
|
|
185
185
|
},
|
|
186
186
|
{
|
|
187
187
|
"path": "shared/core/multi-agent-route-off/SKILL.md",
|
|
@@ -213,7 +213,7 @@
|
|
|
213
213
|
},
|
|
214
214
|
{
|
|
215
215
|
"path": "shared/core/multi-agent-scenario-audit/SKILL.md",
|
|
216
|
-
"sha256": "
|
|
216
|
+
"sha256": "b8bc2de0e889007ae64d615e291ea6d369c96dbed0b62fed47cf19c372af4f1b"
|
|
217
217
|
},
|
|
218
218
|
{
|
|
219
219
|
"path": "shared/core/multi-agent-search/SKILL.md",
|
|
@@ -265,7 +265,7 @@
|
|
|
265
265
|
},
|
|
266
266
|
{
|
|
267
267
|
"path": "shared/core/multi-agent-test-gen/SKILL.md",
|
|
268
|
-
"sha256": "
|
|
268
|
+
"sha256": "a66d1171455d95df92a367095eeec11f50033d86c53a7d0032597cebd40d6f21"
|
|
269
269
|
},
|
|
270
270
|
{
|
|
271
271
|
"path": "shared/core/multi-agent-test-screenshots/SKILL.md",
|
|
@@ -1368,7 +1368,7 @@
|
|
|
1368
1368
|
},
|
|
1369
1369
|
{
|
|
1370
1370
|
"name": "multi-agent-office-on",
|
|
1371
|
-
"description": "Open the office
|
|
1371
|
+
"description": "Open the office: a local browser page that shows runs and agents live and drives the ecosystem (new runs, jobs, PRs, keys, memory, system, cleanup). Use when you want to watch or drive runs from a browser.",
|
|
1372
1372
|
"platform": null,
|
|
1373
1373
|
"group": "core",
|
|
1374
1374
|
"plugin": null,
|
|
@@ -58,7 +58,7 @@ Source layout is logical grouping only - skill discovery at runtime is unchang
|
|
|
58
58
|
| [`multi-agent-manual-test`](./core/multi-agent-manual-test/) | `core` | Switch to the active task's branch and prepare it for manual testing in Xcode. Phase 3 user-test step, standalone (the UI Bug Hunter lives a |
|
|
59
59
|
| [`multi-agent-model`](./core/multi-agent-model/) | `core` | Turn the top model rung on or off and keep the cost ledger's pricing in step with it. Use when asked to enable or disable Fable, or which mo |
|
|
60
60
|
| [`multi-agent-office-off`](./core/multi-agent-office-off/) | `core` | Close the office panel and stop its local server. Use when done with the panel. |
|
|
61
|
-
| [`multi-agent-office-on`](./core/multi-agent-office-on/) | `core` | Open the office
|
|
61
|
+
| [`multi-agent-office-on`](./core/multi-agent-office-on/) | `core` | Open the office: a local browser page that shows runs and agents live and drives the ecosystem (new runs, jobs, PRs, keys, memory, system, c |
|
|
62
62
|
| [`multi-agent-office-status`](./core/multi-agent-office-status/) | `core` | Whether the office panel is running, its URL (never the token) and its last actions. Use when unsure if the panel is open. |
|
|
63
63
|
| [`multi-agent-postmortem`](./core/multi-agent-postmortem/) | `core` | Post-mortem of a run from its session transcripts: loops, stalls, root-cause hypotheses on file:line, fixes. Read-only, redacted. Use when a |
|
|
64
64
|
| [`multi-agent-prune-logs`](./core/multi-agent-prune-logs/) | `core` | Delete per-task project logs under ~/.claude/logs/multi-agent (filter by age/project/task). Audit trail + metrics are preserved. Dry-run fir |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: multi-agent-office-on
|
|
3
|
-
description: "Open the office
|
|
3
|
+
description: "Open the office: a local browser page that shows runs and agents live and drives the ecosystem (new runs, jobs, PRs, keys, memory, system, cleanup). Use when you want to watch or drive runs from a browser."
|
|
4
4
|
user-invocable: true
|
|
5
5
|
metadata:
|
|
6
6
|
language: en
|
|
@@ -14,9 +14,8 @@ and opens the browser at `/office` with a one-time code in the URL fragment
|
|
|
14
14
|
|
|
15
15
|
1. `node "$HOME/.copilot/scripts/office-control.mjs" on --json`
|
|
16
16
|
2. Report in `outputLanguage`: `url` (it carries no code), whether the server
|
|
17
|
-
was started or `reused`, that it
|
|
18
|
-
|
|
19
|
-
now. If `opened` is false, say to run it again from a desktop session.
|
|
17
|
+
was started or `reused`, and that it runs until `/multi-agent-office-off`
|
|
18
|
+
stops it. If `opened` is false, say to run it again from a desktop session.
|
|
20
19
|
|
|
21
20
|
Never print the token, read the token file or pass `--print-token`. The server
|
|
22
21
|
listens on 127.0.0.1 only; remote access is not part of this installation.
|
|
@@ -17,7 +17,10 @@ whole task dirs, with optional age / project / task filters.
|
|
|
17
17
|
Backed by `$HOME/.claude/scripts/prune-logs.sh`. Safe by default: it previews
|
|
18
18
|
and deletes nothing until you confirm. The audit trail (`audit.jsonl` +
|
|
19
19
|
rotations) and the metrics corpus (`metrics.jsonl`, `metrics-summary.md`) live
|
|
20
|
-
at the log-root top level and are never removed; `.counter` files survive too.
|
|
20
|
+
at the log-root top level and are never removed; `.counter` files survive too. A run that can still be resumed (its `agent-state.json` status is not
|
|
21
|
+
finished, abandoned or cancelled) keeps its log however old it is, and
|
|
22
|
+
so does a folder written in the last 10 minutes; `--task` names one dir and
|
|
23
|
+
bypasses both.
|
|
21
24
|
|
|
22
25
|
Unlike `/multi-agent:purge` (which wipes worktrees, branches, logs, and state
|
|
23
26
|
together), this only removes log dirs and leaves your worktrees and branches
|
|
@@ -20,6 +20,25 @@ Skip Phase 0-3 and review a diff only. Input shapes: a PR (`#N`, `repo#N`, GitHu
|
|
|
20
20
|
|
|
21
21
|
## Steps
|
|
22
22
|
|
|
23
|
+
0. **Session id and tracker record.** A pipeline run passes its own `TASK_ID`; a standalone review seeds a `review-` one and registers a tracker record, so the review shows wherever runs are read (the office panel, `multi-agent-status`):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
: "${TASK_ID:=review-$(date +%s)-$$}"
|
|
27
|
+
case "$TASK_ID" in review-*)
|
|
28
|
+
S="${LOGS_ROOT:-$HOME/.claude/logs/multi-agent}/$TASK_ID"; mkdir -p "$S"
|
|
29
|
+
printf '{"taskId":"%s","mode":"review","status":"in_progress","currentPhase":0}' "$TASK_ID" \
|
|
30
|
+
| node "$HOME/.copilot/scripts/write-state.mjs" "$S/agent-state.json" >/dev/null
|
|
31
|
+
export MULTI_AGENT_TASK_ID="$TASK_ID"
|
|
32
|
+
bash "$HOME/.copilot/scripts/phase-tracker.sh" init "$TASK_ID"
|
|
33
|
+
for p in "0:Input" "1:Diff" "2:Reviewers" "3:Triage" "4:Report"; do
|
|
34
|
+
bash "$HOME/.copilot/scripts/phase-tracker.sh" add "${p%%:*}" "${p#*:}"
|
|
35
|
+
done
|
|
36
|
+
bash "$HOME/.copilot/scripts/phase-tracker.sh" update 0 in_progress ;;
|
|
37
|
+
esac
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The steps map to tracker steps as in `$HOME/.claude/multi-agent-refs/review-standalone-tracker.md` (1/1a is 0, 2 is 1, 3-4 are 2, 5 is 3, 6-7 are 4), each call prefixed `MULTI_AGENT_TASK_ID=<the review- id> MULTI_AGENT_STRICT_TASK_ID=1`; there is no task widget, so call `phase-tracker.sh render` after each change. After step 7 close the record with `"status":"complete","currentPhase":4` through the same `write-state.mjs` call.
|
|
41
|
+
|
|
23
42
|
1. **Resolve the input** (`{kind, provider}`):
|
|
24
43
|
- PR URL / `#N` / `repo#N` -> `kind=pr` (`github` or `bitbucket-server`).
|
|
25
44
|
- branch name -> `kind=branch` (local).
|
|
@@ -53,7 +53,9 @@ Read the candidate lines it returns. A term nothing matched is listed under
|
|
|
53
53
|
|
|
54
54
|
## Step 3 - Verdict
|
|
55
55
|
|
|
56
|
-
Write
|
|
56
|
+
Write the verdicts to a file in a folder of this run's own
|
|
57
|
+
(`VERDICTS="$(mktemp -d)/verdicts.json"`, never a fixed `/tmp` name another
|
|
58
|
+
user or a second audit could share): `[{id, status, citations, searched, note}]`.
|
|
57
59
|
|
|
58
60
|
| Status | When | Needs |
|
|
59
61
|
|---|---|---|
|
|
@@ -64,7 +66,7 @@ Write `/tmp/ma-verdicts.json`: `[{id, status, citations, searched, note}]`.
|
|
|
64
66
|
|
|
65
67
|
```bash
|
|
66
68
|
node "$HOME/.claude/scripts/scenario-audit.mjs" verify --csv "<scenarios.csv>" \
|
|
67
|
-
--verdicts
|
|
69
|
+
--verdicts "$VERDICTS" --repo "<repo>" --lang "<outputLanguage>"
|
|
68
70
|
```
|
|
69
71
|
|
|
70
72
|
## Step 4 - Report
|
|
@@ -43,9 +43,32 @@ Scripts: `test-gen-gate.mjs` (artefact, handle and write gates),
|
|
|
43
43
|
## Step 1 - Prepare
|
|
44
44
|
|
|
45
45
|
1. Repo: `--repo`, else the current directory; confirm it in one line.
|
|
46
|
-
Platform: `--platform`, else detect as `multi-agent-test` does.
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
Platform: `--platform`, else detect as `multi-agent-test` does. One
|
|
47
|
+
timestamp names the run everywhere: `TS="$(date +%Y%m%d%H%M%S)"`, run id
|
|
48
|
+
`tg-$TS`, `RUN="$HOME/.claude/logs/test-gen/<repo>/$TS"`, created with
|
|
49
|
+
`mkdir -p "$RUN"`.
|
|
50
|
+
Register the run so its progress shows wherever runs are read (the office
|
|
51
|
+
panel, `multi-agent-status`), with one step per stage below:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
TG_ID="tg-$TS"
|
|
55
|
+
S="${LOGS_ROOT:-$HOME/.claude/logs/multi-agent}/$TG_ID"; mkdir -p "$S"
|
|
56
|
+
printf '{"taskId":"%s","mode":"test-gen","status":"in_progress","currentPhase":0}' "$TG_ID" \
|
|
57
|
+
| node "$HOME/.copilot/scripts/write-state.mjs" "$S/agent-state.json" >/dev/null
|
|
58
|
+
export MULTI_AGENT_TASK_ID="$TG_ID"
|
|
59
|
+
bash "$HOME/.copilot/scripts/phase-tracker.sh" init "$TG_ID"
|
|
60
|
+
for p in "0:Prepare" "1:Inventory" "2:Discovery" "3:Handles" "4:Tests" "5:Report"; do
|
|
61
|
+
bash "$HOME/.copilot/scripts/phase-tracker.sh" add "${p%%:*}" "${p#*:}"
|
|
62
|
+
done
|
|
63
|
+
bash "$HOME/.copilot/scripts/phase-tracker.sh" update 0 in_progress
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Each step below starts with `update <N> in_progress` and ends with
|
|
67
|
+
`update <N> completed` (Step 5 and Step 6 share step 4), every call prefixed
|
|
68
|
+
`MULTI_AGENT_TASK_ID=<the tg- id, written out> MULTI_AGENT_STRICT_TASK_ID=1`.
|
|
69
|
+
There is no task widget here: call `phase-tracker.sh render` after each
|
|
70
|
+
change, and close the record with `"status":"complete","currentPhase":5`
|
|
71
|
+
through the same `write-state.mjs` call when the report is written.
|
|
49
72
|
2. Toolkit: `test_results_classify`, `coverage_gap` and `ui_locator_codegen`
|
|
50
73
|
need `@mmerterden/multi-agent-toolkit-mcp` >= v3.25.0. Check the tool list
|
|
51
74
|
once. Each missing tool has a fallback in `stages.md` (classify from the
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
| core | `multi-agent-manual-test` | - | Switch to the active task's branch and prepare it for manual testing in Xcode. Phase 3 user-test step, standalone (the UI Bug Hunter lives a |
|
|
132
132
|
| core | `multi-agent-model` | - | Turn the top model rung on or off and keep the cost ledger's pricing in step with it. Use when asked to enable or disable Fable, or which mo |
|
|
133
133
|
| core | `multi-agent-office-off` | - | Close the office panel and stop its local server. Use when done with the panel. |
|
|
134
|
-
| core | `multi-agent-office-on` | - | Open the office
|
|
134
|
+
| core | `multi-agent-office-on` | - | Open the office: a local browser page that shows runs and agents live and drives the ecosystem (new runs, jobs, PRs, keys, memory, system, c |
|
|
135
135
|
| core | `multi-agent-office-status` | - | Whether the office panel is running, its URL (never the token) and its last actions. Use when unsure if the panel is open. |
|
|
136
136
|
| core | `multi-agent-postmortem` | - | Post-mortem of a run from its session transcripts: loops, stalls, root-cause hypotheses on file:line, fixes. Read-only, redacted. Use when a |
|
|
137
137
|
| core | `multi-agent-prune-logs` | - | Delete per-task project logs under ~/.claude/logs/multi-agent (filter by age/project/task). Audit trail + metrics are preserved. Dry-run fir |
|