opencode-swarm 7.56.2 → 7.57.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/dist/cli/index.js +174 -33
- package/dist/commands/codebase-review.d.ts +8 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/registry.d.ts +14 -0
- package/dist/index.js +224 -42
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -52,7 +52,7 @@ var package_default;
|
|
|
52
52
|
var init_package = __esm(() => {
|
|
53
53
|
package_default = {
|
|
54
54
|
name: "opencode-swarm",
|
|
55
|
-
version: "7.
|
|
55
|
+
version: "7.57.0",
|
|
56
56
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
57
57
|
main: "dist/index.js",
|
|
58
58
|
types: "dist/index.d.ts",
|
|
@@ -39792,6 +39792,130 @@ var init_close = __esm(() => {
|
|
|
39792
39792
|
];
|
|
39793
39793
|
});
|
|
39794
39794
|
|
|
39795
|
+
// src/commands/codebase-review.ts
|
|
39796
|
+
function sanitizeText(raw, maxLen) {
|
|
39797
|
+
const stripped = raw.replace(/\[+\s*MODE\s*:[^\]]*(?:\]+|$)/gi, "");
|
|
39798
|
+
const normalized = stripped.replace(/\s+/g, " ").trim();
|
|
39799
|
+
if (normalized.length <= maxLen)
|
|
39800
|
+
return normalized;
|
|
39801
|
+
return `${normalized.slice(0, maxLen)}...`;
|
|
39802
|
+
}
|
|
39803
|
+
function hasFlagValue(args, index) {
|
|
39804
|
+
return index + 1 < args.length && !args[index + 1].startsWith("--");
|
|
39805
|
+
}
|
|
39806
|
+
function jsonForModeHeader(value) {
|
|
39807
|
+
return JSON.stringify(value).replace(/[[\]]/g, (ch) => ch === "[" ? "\\u005B" : "\\u005D");
|
|
39808
|
+
}
|
|
39809
|
+
function parseArgs(args) {
|
|
39810
|
+
const result = {
|
|
39811
|
+
mode: DEFAULT_MODE,
|
|
39812
|
+
tracks: "",
|
|
39813
|
+
continueRun: "",
|
|
39814
|
+
output: "markdown",
|
|
39815
|
+
updateMain: true,
|
|
39816
|
+
allowDirty: false,
|
|
39817
|
+
rest: []
|
|
39818
|
+
};
|
|
39819
|
+
let i = 0;
|
|
39820
|
+
while (i < args.length) {
|
|
39821
|
+
const token = args[i];
|
|
39822
|
+
if (token === "--help" || token === "-h") {
|
|
39823
|
+
result.help = true;
|
|
39824
|
+
} else if (token === "--mode") {
|
|
39825
|
+
if (!hasFlagValue(args, i)) {
|
|
39826
|
+
return { ...result, error: FLAG_VALUE_MISSING(token) };
|
|
39827
|
+
}
|
|
39828
|
+
const value = args[++i];
|
|
39829
|
+
if (!MODES.has(value)) {
|
|
39830
|
+
return {
|
|
39831
|
+
...result,
|
|
39832
|
+
error: `Invalid mode "${value}". Must be one of: ${[...MODES].join(", ")}.`
|
|
39833
|
+
};
|
|
39834
|
+
}
|
|
39835
|
+
result.mode = value;
|
|
39836
|
+
} else if (token === "--tracks") {
|
|
39837
|
+
if (!hasFlagValue(args, i)) {
|
|
39838
|
+
return { ...result, error: FLAG_VALUE_MISSING(token) };
|
|
39839
|
+
}
|
|
39840
|
+
result.tracks = sanitizeText(args[++i], MAX_TRACKS_LEN);
|
|
39841
|
+
} else if (token === "--continue") {
|
|
39842
|
+
if (!hasFlagValue(args, i)) {
|
|
39843
|
+
return { ...result, error: FLAG_VALUE_MISSING(token) };
|
|
39844
|
+
}
|
|
39845
|
+
const runId = sanitizeText(args[++i], MAX_RUN_ID_LEN);
|
|
39846
|
+
if (!/^[A-Za-z0-9_.-]+$/.test(runId)) {
|
|
39847
|
+
return {
|
|
39848
|
+
...result,
|
|
39849
|
+
error: "Invalid --continue value. Use only letters, numbers, dot, underscore, or dash."
|
|
39850
|
+
};
|
|
39851
|
+
}
|
|
39852
|
+
result.continueRun = runId;
|
|
39853
|
+
} else if (token === "--json") {
|
|
39854
|
+
result.output = "json";
|
|
39855
|
+
} else if (token === "--skip-update") {
|
|
39856
|
+
result.updateMain = false;
|
|
39857
|
+
} else if (token === "--allow-dirty") {
|
|
39858
|
+
result.allowDirty = true;
|
|
39859
|
+
} else if (token.startsWith("--")) {
|
|
39860
|
+
return { ...result, error: `Unknown flag "${token}"` };
|
|
39861
|
+
} else {
|
|
39862
|
+
result.rest.push(token);
|
|
39863
|
+
}
|
|
39864
|
+
i++;
|
|
39865
|
+
}
|
|
39866
|
+
return result;
|
|
39867
|
+
}
|
|
39868
|
+
async function handleCodebaseReviewCommand(_directory, args) {
|
|
39869
|
+
const parsed = parseArgs(args);
|
|
39870
|
+
if (parsed.help) {
|
|
39871
|
+
return USAGE;
|
|
39872
|
+
}
|
|
39873
|
+
if (parsed.error) {
|
|
39874
|
+
return `Error: ${parsed.error}
|
|
39875
|
+
|
|
39876
|
+
${USAGE}`;
|
|
39877
|
+
}
|
|
39878
|
+
const scope = sanitizeText(parsed.rest.join(" "), MAX_SCOPE_LEN) || DEFAULT_SCOPE;
|
|
39879
|
+
return [
|
|
39880
|
+
`[MODE: CODEBASE_REVIEW mode=${parsed.mode} output=${parsed.output} update_main=${parsed.updateMain} allow_dirty=${parsed.allowDirty} tracks=${jsonForModeHeader(parsed.tracks)} continue_run=${jsonForModeHeader(parsed.continueRun)}]`,
|
|
39881
|
+
`scope=${JSON.stringify(scope)}`
|
|
39882
|
+
].join(" ");
|
|
39883
|
+
}
|
|
39884
|
+
var MAX_SCOPE_LEN = 2000, MAX_TRACKS_LEN = 1000, MAX_RUN_ID_LEN = 128, CODEBASE_REVIEW_MODES, MODES, DEFAULT_MODE = "phase0", DEFAULT_SCOPE = "repository root", FLAG_VALUE_MISSING = (token) => `Flag "${token}" requires a value`, USAGE = `Usage: /swarm codebase-review [scope] [--mode phase0|complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements|custom] [--tracks <list>] [--continue <run-id>] [--json] [--skip-update] [--allow-dirty]
|
|
39885
|
+
|
|
39886
|
+
Run the codebase-review-swarm workflow in the current repository.
|
|
39887
|
+
|
|
39888
|
+
Examples:
|
|
39889
|
+
/swarm codebase-review
|
|
39890
|
+
/swarm codebase review src/auth --mode security
|
|
39891
|
+
/swarm codebase-review "frontend accessibility" --mode ui --json
|
|
39892
|
+
/swarm codebase-review --mode custom --tracks "security,testing"
|
|
39893
|
+
|
|
39894
|
+
Flags:
|
|
39895
|
+
--mode <name> phase0, complete, defect, security, correctness, testing, ui, performance, ai-slop, enhancements, or custom
|
|
39896
|
+
--tracks <list> custom selected tracks or review notes passed to the workflow
|
|
39897
|
+
--continue <run-id> continue an existing .swarm/review-v8 run
|
|
39898
|
+
--json request JSON-compatible report blocks
|
|
39899
|
+
--skip-update skip the repo update-to-main preflight
|
|
39900
|
+
--allow-dirty allow review to proceed with dirty worktree
|
|
39901
|
+
--help show this usage`;
|
|
39902
|
+
var init_codebase_review = __esm(() => {
|
|
39903
|
+
CODEBASE_REVIEW_MODES = [
|
|
39904
|
+
"phase0",
|
|
39905
|
+
"complete",
|
|
39906
|
+
"defect",
|
|
39907
|
+
"security",
|
|
39908
|
+
"correctness",
|
|
39909
|
+
"testing",
|
|
39910
|
+
"ui",
|
|
39911
|
+
"performance",
|
|
39912
|
+
"ai-slop",
|
|
39913
|
+
"enhancements",
|
|
39914
|
+
"custom"
|
|
39915
|
+
];
|
|
39916
|
+
MODES = new Set(CODEBASE_REVIEW_MODES);
|
|
39917
|
+
});
|
|
39918
|
+
|
|
39795
39919
|
// src/commands/concurrency.ts
|
|
39796
39920
|
async function handleConcurrencyCommand(directory, args, sessionID) {
|
|
39797
39921
|
if (!sessionID || sessionID.trim() === "") {
|
|
@@ -39944,7 +40068,7 @@ function sanitizePresetName(raw) {
|
|
|
39944
40068
|
return null;
|
|
39945
40069
|
return trimmed;
|
|
39946
40070
|
}
|
|
39947
|
-
function
|
|
40071
|
+
function parseArgs2(args) {
|
|
39948
40072
|
const out = { specReview: false, rest: [] };
|
|
39949
40073
|
for (let i = 0;i < args.length; i++) {
|
|
39950
40074
|
const token = args[i];
|
|
@@ -39967,10 +40091,10 @@ function parseArgs(args) {
|
|
|
39967
40091
|
return out;
|
|
39968
40092
|
}
|
|
39969
40093
|
async function handleCouncilCommand(_directory, args) {
|
|
39970
|
-
const parsed =
|
|
40094
|
+
const parsed = parseArgs2(args);
|
|
39971
40095
|
const question = sanitizeQuestion(parsed.rest.join(" "));
|
|
39972
40096
|
if (!question) {
|
|
39973
|
-
return
|
|
40097
|
+
return USAGE2;
|
|
39974
40098
|
}
|
|
39975
40099
|
const tokens = ["MODE: COUNCIL"];
|
|
39976
40100
|
if (parsed.preset) {
|
|
@@ -39981,9 +40105,9 @@ async function handleCouncilCommand(_directory, args) {
|
|
|
39981
40105
|
}
|
|
39982
40106
|
return `[${tokens.join(" ")}] ${question}`;
|
|
39983
40107
|
}
|
|
39984
|
-
var MAX_QUESTION_LEN = 2000,
|
|
40108
|
+
var MAX_QUESTION_LEN = 2000, USAGE2;
|
|
39985
40109
|
var init_council = __esm(() => {
|
|
39986
|
-
|
|
40110
|
+
USAGE2 = [
|
|
39987
40111
|
"Usage: /swarm council <question> [--preset <name>] [--spec-review]",
|
|
39988
40112
|
"",
|
|
39989
40113
|
" question The question to put to the council",
|
|
@@ -40442,9 +40566,9 @@ function sanitizeScope(raw) {
|
|
|
40442
40566
|
const collapsed = raw.replace(/\s+/g, " ").trim();
|
|
40443
40567
|
const stripped = collapsed.replace(/\[\s*MODE\s*:[^\]]*\]/gi, "");
|
|
40444
40568
|
const normalized = stripped.replace(/\s+/g, " ").trim();
|
|
40445
|
-
if (normalized.length <=
|
|
40569
|
+
if (normalized.length <= MAX_SCOPE_LEN2)
|
|
40446
40570
|
return normalized;
|
|
40447
|
-
return `${normalized.slice(0,
|
|
40571
|
+
return `${normalized.slice(0, MAX_SCOPE_LEN2)}\u2026`;
|
|
40448
40572
|
}
|
|
40449
40573
|
function isValidPositiveInteger(raw) {
|
|
40450
40574
|
if (!raw || !/^\d+$/.test(raw))
|
|
@@ -40454,7 +40578,7 @@ function isValidPositiveInteger(raw) {
|
|
|
40454
40578
|
return false;
|
|
40455
40579
|
return true;
|
|
40456
40580
|
}
|
|
40457
|
-
function
|
|
40581
|
+
function parseArgs3(args) {
|
|
40458
40582
|
const result = {
|
|
40459
40583
|
profile: DEFAULT_PROFILE,
|
|
40460
40584
|
maxExplorers: DEFAULT_MAX_EXPLORERS,
|
|
@@ -40507,15 +40631,15 @@ function parseArgs2(args) {
|
|
|
40507
40631
|
return result;
|
|
40508
40632
|
}
|
|
40509
40633
|
async function handleDeepDiveCommand(_directory, args) {
|
|
40510
|
-
const parsed =
|
|
40634
|
+
const parsed = parseArgs3(args);
|
|
40511
40635
|
if (parsed.error) {
|
|
40512
40636
|
return `Error: ${parsed.error}
|
|
40513
40637
|
|
|
40514
|
-
${
|
|
40638
|
+
${USAGE3}`;
|
|
40515
40639
|
}
|
|
40516
40640
|
const scope = sanitizeScope(parsed.rest.join(" "));
|
|
40517
40641
|
if (!scope) {
|
|
40518
|
-
return
|
|
40642
|
+
return USAGE3;
|
|
40519
40643
|
}
|
|
40520
40644
|
if (parsed.profile === "full" && !parsed.maxExplorersExplicit) {
|
|
40521
40645
|
parsed.maxExplorers = FULL_PROFILE_DEFAULT_MAX_EXPLORERS;
|
|
@@ -40523,7 +40647,7 @@ ${USAGE2}`;
|
|
|
40523
40647
|
const header = `[MODE: DEEP_DIVE profile=${parsed.profile} max_explorers=${parsed.maxExplorers} output=${parsed.output} update_main=${parsed.updateMain} allow_dirty=${parsed.allowDirty}] ${scope}`;
|
|
40524
40648
|
return header;
|
|
40525
40649
|
}
|
|
40526
|
-
var
|
|
40650
|
+
var MAX_SCOPE_LEN2 = 2000, PROFILES, DEFAULT_PROFILE = "standard", DEFAULT_MAX_EXPLORERS = 6, FULL_PROFILE_DEFAULT_MAX_EXPLORERS = 8, USAGE3 = `Usage: /swarm deep-dive <scope> [--profile standard|security|ux|architecture|full] [--max-explorers N] [--json] [--skip-update] [--allow-dirty]
|
|
40527
40651
|
|
|
40528
40652
|
Run a bounded, evidence-backed deep dive on an application section.
|
|
40529
40653
|
|
|
@@ -40566,7 +40690,7 @@ function cleanFlagValue(raw) {
|
|
|
40566
40690
|
return null;
|
|
40567
40691
|
return raw;
|
|
40568
40692
|
}
|
|
40569
|
-
function
|
|
40693
|
+
function parseArgs4(args) {
|
|
40570
40694
|
const result = {
|
|
40571
40695
|
out: "docs",
|
|
40572
40696
|
lang: "auto",
|
|
@@ -40621,30 +40745,30 @@ function parseArgs3(args) {
|
|
|
40621
40745
|
return result;
|
|
40622
40746
|
}
|
|
40623
40747
|
async function handleDesignDocsCommand(directory, args) {
|
|
40624
|
-
const parsed =
|
|
40748
|
+
const parsed = parseArgs4(args);
|
|
40625
40749
|
if (parsed.error) {
|
|
40626
40750
|
return `Error: ${parsed.error}
|
|
40627
40751
|
|
|
40628
|
-
${
|
|
40752
|
+
${USAGE4}`;
|
|
40629
40753
|
}
|
|
40630
40754
|
try {
|
|
40631
40755
|
const { config: config3 } = loadPluginConfigWithMeta(directory);
|
|
40632
40756
|
if (config3.design_docs?.enabled !== true) {
|
|
40633
40757
|
return "Error: design docs are disabled. Set `design_docs.enabled: true` in " + `opencode-swarm.json to enable the docs_design agent and this command.
|
|
40634
40758
|
|
|
40635
|
-
` +
|
|
40759
|
+
` + USAGE4;
|
|
40636
40760
|
}
|
|
40637
40761
|
} catch (configErr) {
|
|
40638
40762
|
console.warn(`[design-docs] Could not read opencode-swarm.json (${String(configErr)}). ` + "Falling through \u2014 the architect will abort if docs_design is not registered.");
|
|
40639
40763
|
}
|
|
40640
40764
|
const description = sanitizeDescription(parsed.rest.join(" "));
|
|
40641
40765
|
if (!description && !parsed.update) {
|
|
40642
|
-
return
|
|
40766
|
+
return USAGE4;
|
|
40643
40767
|
}
|
|
40644
40768
|
const header = `[MODE: DESIGN_DOCS out=${parsed.out} lang=${parsed.lang} update=${parsed.update}] ${description}`;
|
|
40645
40769
|
return header.trimEnd();
|
|
40646
40770
|
}
|
|
40647
|
-
var MAX_DESC_LEN = 2000,
|
|
40771
|
+
var MAX_DESC_LEN = 2000, USAGE4 = `Usage: /swarm design-docs <description> [--out <dir>] [--lang <name>] [--update]
|
|
40648
40772
|
|
|
40649
40773
|
Generate or sync language-agnostic design docs for the project under build:
|
|
40650
40774
|
<out>/domain.md, <out>/technical-spec.md, <out>/behavior-spec.md,
|
|
@@ -46027,7 +46151,7 @@ function validateAndSanitizeUrl(rawUrl) {
|
|
|
46027
46151
|
return { error: "Invalid URL format" };
|
|
46028
46152
|
}
|
|
46029
46153
|
}
|
|
46030
|
-
function
|
|
46154
|
+
function parseArgs5(args) {
|
|
46031
46155
|
const out = {
|
|
46032
46156
|
plan: false,
|
|
46033
46157
|
trace: false,
|
|
@@ -46118,24 +46242,24 @@ function parseGitRemoteUrl(remoteUrl) {
|
|
|
46118
46242
|
return null;
|
|
46119
46243
|
}
|
|
46120
46244
|
function handleIssueCommand(_directory, args) {
|
|
46121
|
-
const parsed =
|
|
46245
|
+
const parsed = parseArgs5(args);
|
|
46122
46246
|
const rawInput = parsed.rest.join(" ").trim();
|
|
46123
46247
|
if (!rawInput) {
|
|
46124
|
-
return
|
|
46248
|
+
return USAGE5;
|
|
46125
46249
|
}
|
|
46126
46250
|
const isFullUrl = /^https?:\/\//i.test(rawInput);
|
|
46127
46251
|
const issueInfo = parseIssueRef(isFullUrl ? sanitizeUrl(rawInput) : rawInput);
|
|
46128
46252
|
if (!issueInfo) {
|
|
46129
46253
|
return `Error: Could not parse issue reference from "${rawInput}"
|
|
46130
46254
|
|
|
46131
|
-
${
|
|
46255
|
+
${USAGE5}`;
|
|
46132
46256
|
}
|
|
46133
46257
|
const issueUrl = `https://github.com/${issueInfo.owner}/${issueInfo.repo}/issues/${issueInfo.number}`;
|
|
46134
46258
|
const result = validateAndSanitizeUrl(issueUrl);
|
|
46135
46259
|
if ("error" in result) {
|
|
46136
46260
|
return `Error: ${result.error}
|
|
46137
46261
|
|
|
46138
|
-
${
|
|
46262
|
+
${USAGE5}`;
|
|
46139
46263
|
}
|
|
46140
46264
|
const flags = [];
|
|
46141
46265
|
if (parsed.plan)
|
|
@@ -46147,9 +46271,9 @@ ${USAGE4}`;
|
|
|
46147
46271
|
const flagsStr = flags.length > 0 ? ` ${flags.join(" ")}` : "";
|
|
46148
46272
|
return `[MODE: ISSUE_INGEST issue="${result.sanitized}"${flagsStr}]`;
|
|
46149
46273
|
}
|
|
46150
|
-
var MAX_URL_LEN = 2048,
|
|
46274
|
+
var MAX_URL_LEN = 2048, USAGE5;
|
|
46151
46275
|
var init_issue = __esm(() => {
|
|
46152
|
-
|
|
46276
|
+
USAGE5 = [
|
|
46153
46277
|
"Usage: /swarm issue <url|owner/repo#N|N> [--plan] [--trace] [--no-repro]",
|
|
46154
46278
|
"",
|
|
46155
46279
|
"Ingest a GitHub issue into the swarm workflow.",
|
|
@@ -50248,7 +50372,7 @@ var init_pr_feedback = __esm(() => {
|
|
|
50248
50372
|
});
|
|
50249
50373
|
|
|
50250
50374
|
// src/commands/pr-review.ts
|
|
50251
|
-
function
|
|
50375
|
+
function parseArgs6(args) {
|
|
50252
50376
|
const out = { council: false, rest: [] };
|
|
50253
50377
|
for (const token of args) {
|
|
50254
50378
|
if (token === "--council") {
|
|
@@ -50267,29 +50391,29 @@ function parseArgs5(args) {
|
|
|
50267
50391
|
return out;
|
|
50268
50392
|
}
|
|
50269
50393
|
function handlePrReviewCommand(directory, args) {
|
|
50270
|
-
const parsed =
|
|
50394
|
+
const parsed = parseArgs6(args);
|
|
50271
50395
|
if (parsed.unknownFlag) {
|
|
50272
50396
|
return `Error: Unknown flag "${parsed.unknownFlag}"
|
|
50273
50397
|
|
|
50274
|
-
${
|
|
50398
|
+
${USAGE6}`;
|
|
50275
50399
|
}
|
|
50276
50400
|
const resolved = resolvePrCommandInput(parsed.rest, directory);
|
|
50277
50401
|
if (resolved === null) {
|
|
50278
|
-
return
|
|
50402
|
+
return USAGE6;
|
|
50279
50403
|
}
|
|
50280
50404
|
if ("error" in resolved) {
|
|
50281
50405
|
return `Error: ${resolved.error}
|
|
50282
50406
|
|
|
50283
|
-
${
|
|
50407
|
+
${USAGE6}`;
|
|
50284
50408
|
}
|
|
50285
50409
|
const councilFlag = parsed.council ? "council=true" : "council=false";
|
|
50286
50410
|
const signal = `[MODE: PR_REVIEW pr="${resolved.prUrl}" ${councilFlag}]`;
|
|
50287
50411
|
return resolved.instructions ? `${signal} ${resolved.instructions}` : signal;
|
|
50288
50412
|
}
|
|
50289
|
-
var
|
|
50413
|
+
var USAGE6;
|
|
50290
50414
|
var init_pr_review = __esm(() => {
|
|
50291
50415
|
init_pr_ref();
|
|
50292
|
-
|
|
50416
|
+
USAGE6 = [
|
|
50293
50417
|
"Usage: /swarm pr-review <url|owner/repo#N|N> [--council] [instructions...]",
|
|
50294
50418
|
"",
|
|
50295
50419
|
"Run a full swarm PR review on a GitHub pull request.",
|
|
@@ -58427,6 +58551,7 @@ __export(exports_commands, {
|
|
|
58427
58551
|
handleCouncilCommand: () => handleCouncilCommand,
|
|
58428
58552
|
handleConfigCommand: () => handleConfigCommand,
|
|
58429
58553
|
handleConcurrencyCommand: () => handleConcurrencyCommand,
|
|
58554
|
+
handleCodebaseReviewCommand: () => handleCodebaseReviewCommand,
|
|
58430
58555
|
handleCloseCommand: () => handleCloseCommand,
|
|
58431
58556
|
handleClarifyCommand: () => handleClarifyCommand,
|
|
58432
58557
|
handleCheckpointCommand: () => handleCheckpointCommand,
|
|
@@ -58684,6 +58809,7 @@ var init_commands = __esm(() => {
|
|
|
58684
58809
|
init_benchmark();
|
|
58685
58810
|
init_checkpoint2();
|
|
58686
58811
|
init_close();
|
|
58812
|
+
init_codebase_review();
|
|
58687
58813
|
init_command_dispatch();
|
|
58688
58814
|
init_command_names();
|
|
58689
58815
|
init_concurrency();
|
|
@@ -58907,6 +59033,7 @@ var init_registry = __esm(() => {
|
|
|
58907
59033
|
init_benchmark();
|
|
58908
59034
|
init_checkpoint2();
|
|
58909
59035
|
init_close();
|
|
59036
|
+
init_codebase_review();
|
|
58910
59037
|
init_concurrency();
|
|
58911
59038
|
init_config2();
|
|
58912
59039
|
init_council();
|
|
@@ -59237,6 +59364,20 @@ Subcommands:
|
|
|
59237
59364
|
category: "agent",
|
|
59238
59365
|
aliasOf: "deep-dive"
|
|
59239
59366
|
},
|
|
59367
|
+
"codebase-review": {
|
|
59368
|
+
handler: async (ctx) => handleCodebaseReviewCommand(ctx.directory, ctx.args),
|
|
59369
|
+
description: "Launch codebase-review-swarm for a quote-grounded full-repo or large-subsystem audit",
|
|
59370
|
+
args: "[scope] [--mode phase0|complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements|custom] [--tracks <list>] [--continue <run-id>] [--json] [--skip-update] [--allow-dirty]",
|
|
59371
|
+
details: "Runs the codebase-review-swarm workflow: Phase 0 inventory, selected-track depth planning, non-diluting review passes, coverage closure, reviewer validation, critic challenge, and .swarm/review-v8 artifacts. The command is side-effect free and emits a MODE signal; the architect workflow must not mutate source files.",
|
|
59372
|
+
category: "agent"
|
|
59373
|
+
},
|
|
59374
|
+
"codebase review": {
|
|
59375
|
+
handler: async (ctx) => handleCodebaseReviewCommand(ctx.directory, ctx.args),
|
|
59376
|
+
description: "Alias for /swarm codebase-review - launch codebase-review-swarm",
|
|
59377
|
+
args: "[scope] [--mode phase0|complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements|custom] [--tracks <list>] [--continue <run-id>] [--json] [--skip-update] [--allow-dirty]",
|
|
59378
|
+
category: "agent",
|
|
59379
|
+
aliasOf: "codebase-review"
|
|
59380
|
+
},
|
|
59240
59381
|
"design-docs": {
|
|
59241
59382
|
handler: async (ctx) => handleDesignDocsCommand(ctx.directory, ctx.args),
|
|
59242
59383
|
description: "Generate or sync language-agnostic design docs (domain, technical-spec, behavior-spec, reference/) for the project under build [description]",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handle /swarm codebase-review command.
|
|
3
|
+
*
|
|
4
|
+
* Emits a CODEBASE_REVIEW mode signal for the architect. The command itself is
|
|
5
|
+
* intentionally side-effect free so it can be used from any repository.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CODEBASE_REVIEW_MODES: readonly ["phase0", "complete", "defect", "security", "correctness", "testing", "ui", "performance", "ai-slop", "enhancements", "custom"];
|
|
8
|
+
export declare function handleCodebaseReviewCommand(_directory: string, args: string[]): Promise<string>;
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export { handleBrainstormCommand } from './brainstorm';
|
|
|
8
8
|
export { handleCheckpointCommand } from './checkpoint';
|
|
9
9
|
export { handleClarifyCommand } from './clarify';
|
|
10
10
|
export { handleCloseCommand } from './close';
|
|
11
|
+
export { handleCodebaseReviewCommand } from './codebase-review';
|
|
11
12
|
export { executeSwarmCommand, formatCommandNotFound, normalizeSwarmCommandInput, } from './command-dispatch.js';
|
|
12
13
|
export type { CommandName } from './command-names.js';
|
|
13
14
|
export { COMMAND_NAME_SET, COMMAND_NAMES } from './command-names.js';
|
|
@@ -329,6 +329,20 @@ export declare const COMMAND_REGISTRY: {
|
|
|
329
329
|
readonly category: "agent";
|
|
330
330
|
readonly aliasOf: "deep-dive";
|
|
331
331
|
};
|
|
332
|
+
readonly 'codebase-review': {
|
|
333
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
334
|
+
readonly description: "Launch codebase-review-swarm for a quote-grounded full-repo or large-subsystem audit";
|
|
335
|
+
readonly args: "[scope] [--mode phase0|complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements|custom] [--tracks <list>] [--continue <run-id>] [--json] [--skip-update] [--allow-dirty]";
|
|
336
|
+
readonly details: "Runs the codebase-review-swarm workflow: Phase 0 inventory, selected-track depth planning, non-diluting review passes, coverage closure, reviewer validation, critic challenge, and .swarm/review-v8 artifacts. The command is side-effect free and emits a MODE signal; the architect workflow must not mutate source files.";
|
|
337
|
+
readonly category: "agent";
|
|
338
|
+
};
|
|
339
|
+
readonly 'codebase review': {
|
|
340
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
341
|
+
readonly description: "Alias for /swarm codebase-review - launch codebase-review-swarm";
|
|
342
|
+
readonly args: "[scope] [--mode phase0|complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements|custom] [--tracks <list>] [--continue <run-id>] [--json] [--skip-update] [--allow-dirty]";
|
|
343
|
+
readonly category: "agent";
|
|
344
|
+
readonly aliasOf: "codebase-review";
|
|
345
|
+
};
|
|
332
346
|
readonly 'design-docs': {
|
|
333
347
|
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
334
348
|
readonly description: "Generate or sync language-agnostic design docs (domain, technical-spec, behavior-spec, reference/) for the project under build [description]";
|
package/dist/index.js
CHANGED
|
@@ -69,7 +69,7 @@ var package_default;
|
|
|
69
69
|
var init_package = __esm(() => {
|
|
70
70
|
package_default = {
|
|
71
71
|
name: "opencode-swarm",
|
|
72
|
-
version: "7.
|
|
72
|
+
version: "7.57.0",
|
|
73
73
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
74
74
|
main: "dist/index.js",
|
|
75
75
|
types: "dist/index.d.ts",
|
|
@@ -62173,6 +62173,130 @@ var init_close = __esm(() => {
|
|
|
62173
62173
|
];
|
|
62174
62174
|
});
|
|
62175
62175
|
|
|
62176
|
+
// src/commands/codebase-review.ts
|
|
62177
|
+
function sanitizeText(raw, maxLen) {
|
|
62178
|
+
const stripped = raw.replace(/\[+\s*MODE\s*:[^\]]*(?:\]+|$)/gi, "");
|
|
62179
|
+
const normalized = stripped.replace(/\s+/g, " ").trim();
|
|
62180
|
+
if (normalized.length <= maxLen)
|
|
62181
|
+
return normalized;
|
|
62182
|
+
return `${normalized.slice(0, maxLen)}...`;
|
|
62183
|
+
}
|
|
62184
|
+
function hasFlagValue(args2, index) {
|
|
62185
|
+
return index + 1 < args2.length && !args2[index + 1].startsWith("--");
|
|
62186
|
+
}
|
|
62187
|
+
function jsonForModeHeader(value) {
|
|
62188
|
+
return JSON.stringify(value).replace(/[[\]]/g, (ch) => ch === "[" ? "\\u005B" : "\\u005D");
|
|
62189
|
+
}
|
|
62190
|
+
function parseArgs(args2) {
|
|
62191
|
+
const result = {
|
|
62192
|
+
mode: DEFAULT_MODE,
|
|
62193
|
+
tracks: "",
|
|
62194
|
+
continueRun: "",
|
|
62195
|
+
output: "markdown",
|
|
62196
|
+
updateMain: true,
|
|
62197
|
+
allowDirty: false,
|
|
62198
|
+
rest: []
|
|
62199
|
+
};
|
|
62200
|
+
let i2 = 0;
|
|
62201
|
+
while (i2 < args2.length) {
|
|
62202
|
+
const token = args2[i2];
|
|
62203
|
+
if (token === "--help" || token === "-h") {
|
|
62204
|
+
result.help = true;
|
|
62205
|
+
} else if (token === "--mode") {
|
|
62206
|
+
if (!hasFlagValue(args2, i2)) {
|
|
62207
|
+
return { ...result, error: FLAG_VALUE_MISSING(token) };
|
|
62208
|
+
}
|
|
62209
|
+
const value = args2[++i2];
|
|
62210
|
+
if (!MODES.has(value)) {
|
|
62211
|
+
return {
|
|
62212
|
+
...result,
|
|
62213
|
+
error: `Invalid mode "${value}". Must be one of: ${[...MODES].join(", ")}.`
|
|
62214
|
+
};
|
|
62215
|
+
}
|
|
62216
|
+
result.mode = value;
|
|
62217
|
+
} else if (token === "--tracks") {
|
|
62218
|
+
if (!hasFlagValue(args2, i2)) {
|
|
62219
|
+
return { ...result, error: FLAG_VALUE_MISSING(token) };
|
|
62220
|
+
}
|
|
62221
|
+
result.tracks = sanitizeText(args2[++i2], MAX_TRACKS_LEN);
|
|
62222
|
+
} else if (token === "--continue") {
|
|
62223
|
+
if (!hasFlagValue(args2, i2)) {
|
|
62224
|
+
return { ...result, error: FLAG_VALUE_MISSING(token) };
|
|
62225
|
+
}
|
|
62226
|
+
const runId = sanitizeText(args2[++i2], MAX_RUN_ID_LEN);
|
|
62227
|
+
if (!/^[A-Za-z0-9_.-]+$/.test(runId)) {
|
|
62228
|
+
return {
|
|
62229
|
+
...result,
|
|
62230
|
+
error: "Invalid --continue value. Use only letters, numbers, dot, underscore, or dash."
|
|
62231
|
+
};
|
|
62232
|
+
}
|
|
62233
|
+
result.continueRun = runId;
|
|
62234
|
+
} else if (token === "--json") {
|
|
62235
|
+
result.output = "json";
|
|
62236
|
+
} else if (token === "--skip-update") {
|
|
62237
|
+
result.updateMain = false;
|
|
62238
|
+
} else if (token === "--allow-dirty") {
|
|
62239
|
+
result.allowDirty = true;
|
|
62240
|
+
} else if (token.startsWith("--")) {
|
|
62241
|
+
return { ...result, error: `Unknown flag "${token}"` };
|
|
62242
|
+
} else {
|
|
62243
|
+
result.rest.push(token);
|
|
62244
|
+
}
|
|
62245
|
+
i2++;
|
|
62246
|
+
}
|
|
62247
|
+
return result;
|
|
62248
|
+
}
|
|
62249
|
+
async function handleCodebaseReviewCommand(_directory, args2) {
|
|
62250
|
+
const parsed = parseArgs(args2);
|
|
62251
|
+
if (parsed.help) {
|
|
62252
|
+
return USAGE;
|
|
62253
|
+
}
|
|
62254
|
+
if (parsed.error) {
|
|
62255
|
+
return `Error: ${parsed.error}
|
|
62256
|
+
|
|
62257
|
+
${USAGE}`;
|
|
62258
|
+
}
|
|
62259
|
+
const scope = sanitizeText(parsed.rest.join(" "), MAX_SCOPE_LEN) || DEFAULT_SCOPE;
|
|
62260
|
+
return [
|
|
62261
|
+
`[MODE: CODEBASE_REVIEW mode=${parsed.mode} output=${parsed.output} update_main=${parsed.updateMain} allow_dirty=${parsed.allowDirty} tracks=${jsonForModeHeader(parsed.tracks)} continue_run=${jsonForModeHeader(parsed.continueRun)}]`,
|
|
62262
|
+
`scope=${JSON.stringify(scope)}`
|
|
62263
|
+
].join(" ");
|
|
62264
|
+
}
|
|
62265
|
+
var MAX_SCOPE_LEN = 2000, MAX_TRACKS_LEN = 1000, MAX_RUN_ID_LEN = 128, CODEBASE_REVIEW_MODES, MODES, DEFAULT_MODE = "phase0", DEFAULT_SCOPE = "repository root", FLAG_VALUE_MISSING = (token) => `Flag "${token}" requires a value`, USAGE = `Usage: /swarm codebase-review [scope] [--mode phase0|complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements|custom] [--tracks <list>] [--continue <run-id>] [--json] [--skip-update] [--allow-dirty]
|
|
62266
|
+
|
|
62267
|
+
Run the codebase-review-swarm workflow in the current repository.
|
|
62268
|
+
|
|
62269
|
+
Examples:
|
|
62270
|
+
/swarm codebase-review
|
|
62271
|
+
/swarm codebase review src/auth --mode security
|
|
62272
|
+
/swarm codebase-review "frontend accessibility" --mode ui --json
|
|
62273
|
+
/swarm codebase-review --mode custom --tracks "security,testing"
|
|
62274
|
+
|
|
62275
|
+
Flags:
|
|
62276
|
+
--mode <name> phase0, complete, defect, security, correctness, testing, ui, performance, ai-slop, enhancements, or custom
|
|
62277
|
+
--tracks <list> custom selected tracks or review notes passed to the workflow
|
|
62278
|
+
--continue <run-id> continue an existing .swarm/review-v8 run
|
|
62279
|
+
--json request JSON-compatible report blocks
|
|
62280
|
+
--skip-update skip the repo update-to-main preflight
|
|
62281
|
+
--allow-dirty allow review to proceed with dirty worktree
|
|
62282
|
+
--help show this usage`;
|
|
62283
|
+
var init_codebase_review = __esm(() => {
|
|
62284
|
+
CODEBASE_REVIEW_MODES = [
|
|
62285
|
+
"phase0",
|
|
62286
|
+
"complete",
|
|
62287
|
+
"defect",
|
|
62288
|
+
"security",
|
|
62289
|
+
"correctness",
|
|
62290
|
+
"testing",
|
|
62291
|
+
"ui",
|
|
62292
|
+
"performance",
|
|
62293
|
+
"ai-slop",
|
|
62294
|
+
"enhancements",
|
|
62295
|
+
"custom"
|
|
62296
|
+
];
|
|
62297
|
+
MODES = new Set(CODEBASE_REVIEW_MODES);
|
|
62298
|
+
});
|
|
62299
|
+
|
|
62176
62300
|
// src/commands/concurrency.ts
|
|
62177
62301
|
async function handleConcurrencyCommand(directory, args2, sessionID) {
|
|
62178
62302
|
if (!sessionID || sessionID.trim() === "") {
|
|
@@ -62325,7 +62449,7 @@ function sanitizePresetName(raw) {
|
|
|
62325
62449
|
return null;
|
|
62326
62450
|
return trimmed;
|
|
62327
62451
|
}
|
|
62328
|
-
function
|
|
62452
|
+
function parseArgs2(args2) {
|
|
62329
62453
|
const out2 = { specReview: false, rest: [] };
|
|
62330
62454
|
for (let i2 = 0;i2 < args2.length; i2++) {
|
|
62331
62455
|
const token = args2[i2];
|
|
@@ -62348,10 +62472,10 @@ function parseArgs(args2) {
|
|
|
62348
62472
|
return out2;
|
|
62349
62473
|
}
|
|
62350
62474
|
async function handleCouncilCommand(_directory, args2) {
|
|
62351
|
-
const parsed =
|
|
62475
|
+
const parsed = parseArgs2(args2);
|
|
62352
62476
|
const question = sanitizeQuestion(parsed.rest.join(" "));
|
|
62353
62477
|
if (!question) {
|
|
62354
|
-
return
|
|
62478
|
+
return USAGE2;
|
|
62355
62479
|
}
|
|
62356
62480
|
const tokens = ["MODE: COUNCIL"];
|
|
62357
62481
|
if (parsed.preset) {
|
|
@@ -62362,9 +62486,9 @@ async function handleCouncilCommand(_directory, args2) {
|
|
|
62362
62486
|
}
|
|
62363
62487
|
return `[${tokens.join(" ")}] ${question}`;
|
|
62364
62488
|
}
|
|
62365
|
-
var MAX_QUESTION_LEN = 2000,
|
|
62489
|
+
var MAX_QUESTION_LEN = 2000, USAGE2;
|
|
62366
62490
|
var init_council = __esm(() => {
|
|
62367
|
-
|
|
62491
|
+
USAGE2 = [
|
|
62368
62492
|
"Usage: /swarm council <question> [--preset <name>] [--spec-review]",
|
|
62369
62493
|
"",
|
|
62370
62494
|
" question The question to put to the council",
|
|
@@ -62834,9 +62958,9 @@ function sanitizeScope(raw) {
|
|
|
62834
62958
|
const collapsed = raw.replace(/\s+/g, " ").trim();
|
|
62835
62959
|
const stripped = collapsed.replace(/\[\s*MODE\s*:[^\]]*\]/gi, "");
|
|
62836
62960
|
const normalized = stripped.replace(/\s+/g, " ").trim();
|
|
62837
|
-
if (normalized.length <=
|
|
62961
|
+
if (normalized.length <= MAX_SCOPE_LEN2)
|
|
62838
62962
|
return normalized;
|
|
62839
|
-
return `${normalized.slice(0,
|
|
62963
|
+
return `${normalized.slice(0, MAX_SCOPE_LEN2)}…`;
|
|
62840
62964
|
}
|
|
62841
62965
|
function isValidPositiveInteger(raw) {
|
|
62842
62966
|
if (!raw || !/^\d+$/.test(raw))
|
|
@@ -62846,7 +62970,7 @@ function isValidPositiveInteger(raw) {
|
|
|
62846
62970
|
return false;
|
|
62847
62971
|
return true;
|
|
62848
62972
|
}
|
|
62849
|
-
function
|
|
62973
|
+
function parseArgs3(args2) {
|
|
62850
62974
|
const result = {
|
|
62851
62975
|
profile: DEFAULT_PROFILE,
|
|
62852
62976
|
maxExplorers: DEFAULT_MAX_EXPLORERS,
|
|
@@ -62899,15 +63023,15 @@ function parseArgs2(args2) {
|
|
|
62899
63023
|
return result;
|
|
62900
63024
|
}
|
|
62901
63025
|
async function handleDeepDiveCommand(_directory, args2) {
|
|
62902
|
-
const parsed =
|
|
63026
|
+
const parsed = parseArgs3(args2);
|
|
62903
63027
|
if (parsed.error) {
|
|
62904
63028
|
return `Error: ${parsed.error}
|
|
62905
63029
|
|
|
62906
|
-
${
|
|
63030
|
+
${USAGE3}`;
|
|
62907
63031
|
}
|
|
62908
63032
|
const scope = sanitizeScope(parsed.rest.join(" "));
|
|
62909
63033
|
if (!scope) {
|
|
62910
|
-
return
|
|
63034
|
+
return USAGE3;
|
|
62911
63035
|
}
|
|
62912
63036
|
if (parsed.profile === "full" && !parsed.maxExplorersExplicit) {
|
|
62913
63037
|
parsed.maxExplorers = FULL_PROFILE_DEFAULT_MAX_EXPLORERS;
|
|
@@ -62915,7 +63039,7 @@ ${USAGE2}`;
|
|
|
62915
63039
|
const header = `[MODE: DEEP_DIVE profile=${parsed.profile} max_explorers=${parsed.maxExplorers} output=${parsed.output} update_main=${parsed.updateMain} allow_dirty=${parsed.allowDirty}] ${scope}`;
|
|
62916
63040
|
return header;
|
|
62917
63041
|
}
|
|
62918
|
-
var
|
|
63042
|
+
var MAX_SCOPE_LEN2 = 2000, PROFILES, DEFAULT_PROFILE = "standard", DEFAULT_MAX_EXPLORERS = 6, FULL_PROFILE_DEFAULT_MAX_EXPLORERS = 8, USAGE3 = `Usage: /swarm deep-dive <scope> [--profile standard|security|ux|architecture|full] [--max-explorers N] [--json] [--skip-update] [--allow-dirty]
|
|
62919
63043
|
|
|
62920
63044
|
Run a bounded, evidence-backed deep dive on an application section.
|
|
62921
63045
|
|
|
@@ -62958,7 +63082,7 @@ function cleanFlagValue(raw) {
|
|
|
62958
63082
|
return null;
|
|
62959
63083
|
return raw;
|
|
62960
63084
|
}
|
|
62961
|
-
function
|
|
63085
|
+
function parseArgs4(args2) {
|
|
62962
63086
|
const result = {
|
|
62963
63087
|
out: "docs",
|
|
62964
63088
|
lang: "auto",
|
|
@@ -63013,30 +63137,30 @@ function parseArgs3(args2) {
|
|
|
63013
63137
|
return result;
|
|
63014
63138
|
}
|
|
63015
63139
|
async function handleDesignDocsCommand(directory, args2) {
|
|
63016
|
-
const parsed =
|
|
63140
|
+
const parsed = parseArgs4(args2);
|
|
63017
63141
|
if (parsed.error) {
|
|
63018
63142
|
return `Error: ${parsed.error}
|
|
63019
63143
|
|
|
63020
|
-
${
|
|
63144
|
+
${USAGE4}`;
|
|
63021
63145
|
}
|
|
63022
63146
|
try {
|
|
63023
63147
|
const { config: config3 } = loadPluginConfigWithMeta(directory);
|
|
63024
63148
|
if (config3.design_docs?.enabled !== true) {
|
|
63025
63149
|
return "Error: design docs are disabled. Set `design_docs.enabled: true` in " + `opencode-swarm.json to enable the docs_design agent and this command.
|
|
63026
63150
|
|
|
63027
|
-
` +
|
|
63151
|
+
` + USAGE4;
|
|
63028
63152
|
}
|
|
63029
63153
|
} catch (configErr) {
|
|
63030
63154
|
console.warn(`[design-docs] Could not read opencode-swarm.json (${String(configErr)}). ` + "Falling through — the architect will abort if docs_design is not registered.");
|
|
63031
63155
|
}
|
|
63032
63156
|
const description = sanitizeDescription(parsed.rest.join(" "));
|
|
63033
63157
|
if (!description && !parsed.update) {
|
|
63034
|
-
return
|
|
63158
|
+
return USAGE4;
|
|
63035
63159
|
}
|
|
63036
63160
|
const header = `[MODE: DESIGN_DOCS out=${parsed.out} lang=${parsed.lang} update=${parsed.update}] ${description}`;
|
|
63037
63161
|
return header.trimEnd();
|
|
63038
63162
|
}
|
|
63039
|
-
var MAX_DESC_LEN = 2000,
|
|
63163
|
+
var MAX_DESC_LEN = 2000, USAGE4 = `Usage: /swarm design-docs <description> [--out <dir>] [--lang <name>] [--update]
|
|
63040
63164
|
|
|
63041
63165
|
Generate or sync language-agnostic design docs for the project under build:
|
|
63042
63166
|
<out>/domain.md, <out>/technical-spec.md, <out>/behavior-spec.md,
|
|
@@ -68535,7 +68659,7 @@ function validateAndSanitizeUrl(rawUrl) {
|
|
|
68535
68659
|
return { error: "Invalid URL format" };
|
|
68536
68660
|
}
|
|
68537
68661
|
}
|
|
68538
|
-
function
|
|
68662
|
+
function parseArgs5(args2) {
|
|
68539
68663
|
const out2 = {
|
|
68540
68664
|
plan: false,
|
|
68541
68665
|
trace: false,
|
|
@@ -68626,24 +68750,24 @@ function parseGitRemoteUrl(remoteUrl) {
|
|
|
68626
68750
|
return null;
|
|
68627
68751
|
}
|
|
68628
68752
|
function handleIssueCommand(_directory, args2) {
|
|
68629
|
-
const parsed =
|
|
68753
|
+
const parsed = parseArgs5(args2);
|
|
68630
68754
|
const rawInput = parsed.rest.join(" ").trim();
|
|
68631
68755
|
if (!rawInput) {
|
|
68632
|
-
return
|
|
68756
|
+
return USAGE5;
|
|
68633
68757
|
}
|
|
68634
68758
|
const isFullUrl = /^https?:\/\//i.test(rawInput);
|
|
68635
68759
|
const issueInfo = parseIssueRef(isFullUrl ? sanitizeUrl(rawInput) : rawInput);
|
|
68636
68760
|
if (!issueInfo) {
|
|
68637
68761
|
return `Error: Could not parse issue reference from "${rawInput}"
|
|
68638
68762
|
|
|
68639
|
-
${
|
|
68763
|
+
${USAGE5}`;
|
|
68640
68764
|
}
|
|
68641
68765
|
const issueUrl = `https://github.com/${issueInfo.owner}/${issueInfo.repo}/issues/${issueInfo.number}`;
|
|
68642
68766
|
const result = validateAndSanitizeUrl(issueUrl);
|
|
68643
68767
|
if ("error" in result) {
|
|
68644
68768
|
return `Error: ${result.error}
|
|
68645
68769
|
|
|
68646
|
-
${
|
|
68770
|
+
${USAGE5}`;
|
|
68647
68771
|
}
|
|
68648
68772
|
const flags2 = [];
|
|
68649
68773
|
if (parsed.plan)
|
|
@@ -68655,9 +68779,9 @@ ${USAGE4}`;
|
|
|
68655
68779
|
const flagsStr = flags2.length > 0 ? ` ${flags2.join(" ")}` : "";
|
|
68656
68780
|
return `[MODE: ISSUE_INGEST issue="${result.sanitized}"${flagsStr}]`;
|
|
68657
68781
|
}
|
|
68658
|
-
var MAX_URL_LEN = 2048,
|
|
68782
|
+
var MAX_URL_LEN = 2048, USAGE5;
|
|
68659
68783
|
var init_issue = __esm(() => {
|
|
68660
|
-
|
|
68784
|
+
USAGE5 = [
|
|
68661
68785
|
"Usage: /swarm issue <url|owner/repo#N|N> [--plan] [--trace] [--no-repro]",
|
|
68662
68786
|
"",
|
|
68663
68787
|
"Ingest a GitHub issue into the swarm workflow.",
|
|
@@ -73747,7 +73871,7 @@ var init_pr_feedback = __esm(() => {
|
|
|
73747
73871
|
});
|
|
73748
73872
|
|
|
73749
73873
|
// src/commands/pr-review.ts
|
|
73750
|
-
function
|
|
73874
|
+
function parseArgs6(args2) {
|
|
73751
73875
|
const out2 = { council: false, rest: [] };
|
|
73752
73876
|
for (const token of args2) {
|
|
73753
73877
|
if (token === "--council") {
|
|
@@ -73766,29 +73890,29 @@ function parseArgs5(args2) {
|
|
|
73766
73890
|
return out2;
|
|
73767
73891
|
}
|
|
73768
73892
|
function handlePrReviewCommand(directory, args2) {
|
|
73769
|
-
const parsed =
|
|
73893
|
+
const parsed = parseArgs6(args2);
|
|
73770
73894
|
if (parsed.unknownFlag) {
|
|
73771
73895
|
return `Error: Unknown flag "${parsed.unknownFlag}"
|
|
73772
73896
|
|
|
73773
|
-
${
|
|
73897
|
+
${USAGE6}`;
|
|
73774
73898
|
}
|
|
73775
73899
|
const resolved = resolvePrCommandInput(parsed.rest, directory);
|
|
73776
73900
|
if (resolved === null) {
|
|
73777
|
-
return
|
|
73901
|
+
return USAGE6;
|
|
73778
73902
|
}
|
|
73779
73903
|
if ("error" in resolved) {
|
|
73780
73904
|
return `Error: ${resolved.error}
|
|
73781
73905
|
|
|
73782
|
-
${
|
|
73906
|
+
${USAGE6}`;
|
|
73783
73907
|
}
|
|
73784
73908
|
const councilFlag = parsed.council ? "council=true" : "council=false";
|
|
73785
73909
|
const signal = `[MODE: PR_REVIEW pr="${resolved.prUrl}" ${councilFlag}]`;
|
|
73786
73910
|
return resolved.instructions ? `${signal} ${resolved.instructions}` : signal;
|
|
73787
73911
|
}
|
|
73788
|
-
var
|
|
73912
|
+
var USAGE6;
|
|
73789
73913
|
var init_pr_review = __esm(() => {
|
|
73790
73914
|
init_pr_ref();
|
|
73791
|
-
|
|
73915
|
+
USAGE6 = [
|
|
73792
73916
|
"Usage: /swarm pr-review <url|owner/repo#N|N> [--council] [instructions...]",
|
|
73793
73917
|
"",
|
|
73794
73918
|
"Run a full swarm PR review on a GitHub pull request.",
|
|
@@ -82296,6 +82420,7 @@ __export(exports_commands, {
|
|
|
82296
82420
|
handleCouncilCommand: () => handleCouncilCommand,
|
|
82297
82421
|
handleConfigCommand: () => handleConfigCommand,
|
|
82298
82422
|
handleConcurrencyCommand: () => handleConcurrencyCommand,
|
|
82423
|
+
handleCodebaseReviewCommand: () => handleCodebaseReviewCommand,
|
|
82299
82424
|
handleCloseCommand: () => handleCloseCommand,
|
|
82300
82425
|
handleClarifyCommand: () => handleClarifyCommand,
|
|
82301
82426
|
handleCheckpointCommand: () => handleCheckpointCommand,
|
|
@@ -82553,6 +82678,7 @@ var init_commands = __esm(() => {
|
|
|
82553
82678
|
init_benchmark();
|
|
82554
82679
|
init_checkpoint2();
|
|
82555
82680
|
init_close();
|
|
82681
|
+
init_codebase_review();
|
|
82556
82682
|
init_command_dispatch();
|
|
82557
82683
|
init_command_names();
|
|
82558
82684
|
init_concurrency();
|
|
@@ -82776,6 +82902,7 @@ var init_registry = __esm(() => {
|
|
|
82776
82902
|
init_benchmark();
|
|
82777
82903
|
init_checkpoint2();
|
|
82778
82904
|
init_close();
|
|
82905
|
+
init_codebase_review();
|
|
82779
82906
|
init_concurrency();
|
|
82780
82907
|
init_config2();
|
|
82781
82908
|
init_council();
|
|
@@ -83106,6 +83233,20 @@ Subcommands:
|
|
|
83106
83233
|
category: "agent",
|
|
83107
83234
|
aliasOf: "deep-dive"
|
|
83108
83235
|
},
|
|
83236
|
+
"codebase-review": {
|
|
83237
|
+
handler: async (ctx) => handleCodebaseReviewCommand(ctx.directory, ctx.args),
|
|
83238
|
+
description: "Launch codebase-review-swarm for a quote-grounded full-repo or large-subsystem audit",
|
|
83239
|
+
args: "[scope] [--mode phase0|complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements|custom] [--tracks <list>] [--continue <run-id>] [--json] [--skip-update] [--allow-dirty]",
|
|
83240
|
+
details: "Runs the codebase-review-swarm workflow: Phase 0 inventory, selected-track depth planning, non-diluting review passes, coverage closure, reviewer validation, critic challenge, and .swarm/review-v8 artifacts. The command is side-effect free and emits a MODE signal; the architect workflow must not mutate source files.",
|
|
83241
|
+
category: "agent"
|
|
83242
|
+
},
|
|
83243
|
+
"codebase review": {
|
|
83244
|
+
handler: async (ctx) => handleCodebaseReviewCommand(ctx.directory, ctx.args),
|
|
83245
|
+
description: "Alias for /swarm codebase-review - launch codebase-review-swarm",
|
|
83246
|
+
args: "[scope] [--mode phase0|complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements|custom] [--tracks <list>] [--continue <run-id>] [--json] [--skip-update] [--allow-dirty]",
|
|
83247
|
+
category: "agent",
|
|
83248
|
+
aliasOf: "codebase-review"
|
|
83249
|
+
},
|
|
83109
83250
|
"design-docs": {
|
|
83110
83251
|
handler: async (ctx) => handleDesignDocsCommand(ctx.directory, ctx.args),
|
|
83111
83252
|
description: "Generate or sync language-agnostic design docs (domain, technical-spec, behavior-spec, reference/) for the project under build [description]",
|
|
@@ -84486,6 +84627,25 @@ HARD CONSTRAINTS (apply regardless of skill load success):
|
|
|
84486
84627
|
- Explorers generate candidate findings only — reviewers verify or reject
|
|
84487
84628
|
- Critics challenge only HIGH/CRITICAL findings — do NOT waste cycles on lower severity
|
|
84488
84629
|
|
|
84630
|
+
### MODE: CODEBASE_REVIEW
|
|
84631
|
+
Activates when: architect receives \`[MODE: CODEBASE_REVIEW mode=X output=X update_main=X allow_dirty=X tracks="..." continue_run="..."] scope="..."\` signal from the codebase-review command handler.
|
|
84632
|
+
|
|
84633
|
+
Purpose: Run codebase-review-swarm as a read-only full-repo or large-subsystem review with Phase 0 inventory, selected-track depth planning, coverage closure, reviewer validation, critic challenge, and \`.swarm/review-v8\` artifacts. This mode does NOT mutate source code, does NOT delegate to coder, and does NOT call declare_scope.
|
|
84634
|
+
|
|
84635
|
+
ACTION: Load skill file:.opencode/skills/codebase-review-swarm/SKILL.md immediately and follow its protocol.
|
|
84636
|
+
|
|
84637
|
+
HARD CONSTRAINTS (apply regardless of skill load success):
|
|
84638
|
+
- Do NOT delegate to coder
|
|
84639
|
+
- Do NOT call declare_scope
|
|
84640
|
+
- Do NOT mutate source code
|
|
84641
|
+
- Write artifacts only under \`.swarm/review-v8/runs/<run_id>/\`
|
|
84642
|
+
- Run Phase 0 inventory first
|
|
84643
|
+
- Treat \`mode=phase0\` as inventory-only: stop at 0K for review-mode selection.
|
|
84644
|
+
- Treat \`mode=complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements\` as the user's preselected authorization to continue through 0L and the selected tracks after Phase 0.
|
|
84645
|
+
- Treat \`mode=custom\` as preselected only when \`tracks\` is non-empty; otherwise stop at 0K for track selection.
|
|
84646
|
+
- Every repo-derived factual claim needs quote-grounded evidence with file path and line/range
|
|
84647
|
+
- Final report is forbidden until selected-track coverage is closed and final critic passes
|
|
84648
|
+
|
|
84489
84649
|
### MODE: DESIGN_DOCS
|
|
84490
84650
|
Activates when: architect receives \`[MODE: DESIGN_DOCS out=X lang=X update=X] <description>\` signal from the design-docs command handler (issue #1080).
|
|
84491
84651
|
|
|
@@ -114537,14 +114697,14 @@ init_knowledge_events();
|
|
|
114537
114697
|
init_knowledge_store();
|
|
114538
114698
|
init_logger();
|
|
114539
114699
|
init_create_tool();
|
|
114540
|
-
var
|
|
114700
|
+
var MODES2 = ["archive", "quarantine", "purge"];
|
|
114541
114701
|
var knowledge_archive = createSwarmTool({
|
|
114542
114702
|
description: "Archive (default), quarantine, or purge a swarm knowledge entry by ID, appending an immutable audit tombstone. 'archive'/'quarantine' set the entry status reversibly and hide it from recall; 'purge' hard-deletes and requires allow_purge:true.",
|
|
114543
114703
|
args: {
|
|
114544
114704
|
id: exports_external.string().min(1).describe("UUID of the knowledge entry"),
|
|
114545
114705
|
reason: exports_external.string().min(1).max(500).describe("Why the entry is being archived/quarantined/purged"),
|
|
114546
114706
|
evidence: exports_external.string().max(1000).optional().describe('Supporting evidence (e.g. "ignored 8 times, contradicted by tests")'),
|
|
114547
|
-
mode: exports_external.enum(
|
|
114707
|
+
mode: exports_external.enum(MODES2).optional().describe("Default 'archive'"),
|
|
114548
114708
|
allow_purge: exports_external.boolean().optional().describe("Admin flag required when mode='purge'")
|
|
114549
114709
|
},
|
|
114550
114710
|
execute: async (args2, directory, ctx) => {
|
|
@@ -118287,6 +118447,7 @@ import * as path143 from "node:path";
|
|
|
118287
118447
|
async function runFinalCouncilGate(ctx) {
|
|
118288
118448
|
const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
|
|
118289
118449
|
let finalCouncilEnabled = false;
|
|
118450
|
+
const gateWarnings = [];
|
|
118290
118451
|
try {
|
|
118291
118452
|
const plan = await loadPlan(dir);
|
|
118292
118453
|
if (plan) {
|
|
@@ -118374,11 +118535,17 @@ async function runFinalCouncilGate(ctx) {
|
|
|
118374
118535
|
warnings: []
|
|
118375
118536
|
};
|
|
118376
118537
|
}
|
|
118377
|
-
if (entry.verdict
|
|
118538
|
+
if (entry.verdict === "concerns" || entry.verdict === "CONCERNS") {
|
|
118539
|
+
const advisoryNotes = Array.isArray(entry.advisoryNotes) ? entry.advisoryNotes.filter((note) => typeof note === "string") : [];
|
|
118540
|
+
const warning = advisoryNotes.length > 0 ? `Final council returned CONCERNS (non-blocking): ${advisoryNotes.join("; ")}` : "Final council returned CONCERNS (non-blocking).";
|
|
118541
|
+
gateWarnings.push(warning);
|
|
118542
|
+
safeWarn(`[phase_complete] ${warning}`, undefined);
|
|
118543
|
+
}
|
|
118544
|
+
if (entry.verdict !== "approved" && entry.verdict !== "APPROVED" && entry.verdict !== "concerns" && entry.verdict !== "CONCERNS") {
|
|
118378
118545
|
return {
|
|
118379
118546
|
blocked: true,
|
|
118380
118547
|
reason: "FINAL_COUNCIL_INVALID_VERDICT",
|
|
118381
|
-
message: `Phase ${phase} (last phase) cannot be completed: final council evidence contains unrecognized verdict '${entry.verdict}'. Expected
|
|
118548
|
+
message: `Phase ${phase} (last phase) cannot be completed: final council evidence contains unrecognized verdict '${entry.verdict}'. Expected one of: approved, concerns, rejected.`,
|
|
118382
118549
|
agentsDispatched,
|
|
118383
118550
|
agentsMissing: [],
|
|
118384
118551
|
warnings: []
|
|
@@ -118423,7 +118590,12 @@ async function runFinalCouncilGate(ctx) {
|
|
|
118423
118590
|
safeWarn(`[phase_complete] Final council gate error (non-blocking):`, fcError);
|
|
118424
118591
|
}
|
|
118425
118592
|
}
|
|
118426
|
-
return {
|
|
118593
|
+
return {
|
|
118594
|
+
blocked: false,
|
|
118595
|
+
agentsDispatched,
|
|
118596
|
+
agentsMissing: [],
|
|
118597
|
+
warnings: gateWarnings
|
|
118598
|
+
};
|
|
118427
118599
|
}
|
|
118428
118600
|
// src/tools/phase-complete/gates/hallucination-gate.ts
|
|
118429
118601
|
init_qa_gate_profile();
|
|
@@ -130326,8 +130498,14 @@ var ArgsSchema8 = exports_external.object({
|
|
|
130326
130498
|
roundNumber: exports_external.number().int().min(1).max(10).optional(),
|
|
130327
130499
|
verdicts: exports_external.array(VerdictSchema3).min(1).max(5)
|
|
130328
130500
|
});
|
|
130329
|
-
function normalizeFinalVerdict(verdict) {
|
|
130330
|
-
|
|
130501
|
+
function normalizeFinalVerdict(verdict, requiredFixesCount) {
|
|
130502
|
+
if (verdict === "APPROVE") {
|
|
130503
|
+
return "approved";
|
|
130504
|
+
}
|
|
130505
|
+
if (verdict === "REJECT") {
|
|
130506
|
+
return "rejected";
|
|
130507
|
+
}
|
|
130508
|
+
return requiredFixesCount > 0 ? "rejected" : "concerns";
|
|
130331
130509
|
}
|
|
130332
130510
|
async function executeWriteFinalCouncilEvidence(args2, directory) {
|
|
130333
130511
|
const parsed = ArgsSchema8.safeParse(args2);
|
|
@@ -130360,7 +130538,7 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
|
|
|
130360
130538
|
const synthesis = synthesizeFinalCouncilAdvisory(input.projectSummary.trim(), input.verdicts, input.roundNumber ?? 1, config3.council);
|
|
130361
130539
|
const plan = await loadPlan(directory);
|
|
130362
130540
|
const planId = plan ? derivePlanId(plan) : "unknown";
|
|
130363
|
-
const normalizedVerdict = normalizeFinalVerdict(synthesis.overallVerdict);
|
|
130541
|
+
const normalizedVerdict = normalizeFinalVerdict(synthesis.overallVerdict, synthesis.requiredFixes.length);
|
|
130364
130542
|
const evidenceEntry = {
|
|
130365
130543
|
type: "final-council",
|
|
130366
130544
|
phase: input.phase,
|
|
@@ -131277,7 +131455,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
131277
131455
|
...opencodeConfig.command || {},
|
|
131278
131456
|
swarm: {
|
|
131279
131457
|
template: "/swarm $ARGUMENTS",
|
|
131280
|
-
description: "Swarm management commands: /swarm [status|show-plan|plan|agents|history|config|help|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|pr-review|pr-feedback|deep-dive|design-docs|issue|qa-gates|dark-matter|knowledge|memory|curate|concurrency|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor tools|finalize|close]"
|
|
131458
|
+
description: "Swarm management commands: /swarm [status|show-plan|plan|agents|history|config|help|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|pr-review|pr-feedback|deep-dive|codebase-review|design-docs|issue|qa-gates|dark-matter|knowledge|memory|curate|concurrency|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor tools|finalize|close]"
|
|
131281
131459
|
},
|
|
131282
131460
|
"swarm-status": {
|
|
131283
131461
|
template: "/swarm status",
|
|
@@ -131383,6 +131561,10 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
131383
131561
|
template: "/swarm deep-dive $ARGUMENTS",
|
|
131384
131562
|
description: "Use /swarm deep-dive to launch a read-only deep audit with parallel explorer waves, dual reviewers, and critic challenge"
|
|
131385
131563
|
},
|
|
131564
|
+
"swarm-codebase-review": {
|
|
131565
|
+
template: "/swarm codebase-review $ARGUMENTS",
|
|
131566
|
+
description: "Use /swarm codebase-review to launch codebase-review-swarm for a quote-grounded full-repo or large-subsystem audit"
|
|
131567
|
+
},
|
|
131386
131568
|
"swarm-design-docs": {
|
|
131387
131569
|
template: "/swarm design-docs $ARGUMENTS",
|
|
131388
131570
|
description: "Use /swarm design-docs to generate or sync language-agnostic design docs for the project under build"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.57.0",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|