opencode-swarm 6.86.11 → 6.86.13
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 +69 -20
- package/dist/commands/knowledge.d.ts +2 -0
- package/dist/config/schema.d.ts +2 -0
- package/dist/index.js +87 -36
- package/dist/utils/gitignore-warning.d.ts +2 -2
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -18580,7 +18580,7 @@ import * as path33 from "path";
|
|
|
18580
18580
|
// package.json
|
|
18581
18581
|
var package_default = {
|
|
18582
18582
|
name: "opencode-swarm",
|
|
18583
|
-
version: "6.86.
|
|
18583
|
+
version: "6.86.13",
|
|
18584
18584
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
18585
18585
|
main: "dist/index.js",
|
|
18586
18586
|
types: "dist/index.d.ts",
|
|
@@ -19472,7 +19472,8 @@ var PlanCursorConfigSchema = exports_external.object({
|
|
|
19472
19472
|
});
|
|
19473
19473
|
var CheckpointConfigSchema = exports_external.object({
|
|
19474
19474
|
enabled: exports_external.boolean().default(true),
|
|
19475
|
-
auto_checkpoint_threshold: exports_external.number().int().min(1).max(20).default(3)
|
|
19475
|
+
auto_checkpoint_threshold: exports_external.number().int().min(1).max(20).default(3),
|
|
19476
|
+
allow_empty_commits: exports_external.boolean().default(false)
|
|
19476
19477
|
}).strict();
|
|
19477
19478
|
var AutomationModeSchema = exports_external.enum(["manual", "hybrid", "auto"]);
|
|
19478
19479
|
var AutomationCapabilitiesSchema = exports_external.object({
|
|
@@ -19683,7 +19684,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
19683
19684
|
council: CouncilConfigSchema.optional(),
|
|
19684
19685
|
parallelization: ParallelizationConfigSchema.optional(),
|
|
19685
19686
|
turbo_mode: exports_external.boolean().default(false).optional(),
|
|
19686
|
-
quiet: exports_external.boolean().default(
|
|
19687
|
+
quiet: exports_external.boolean().default(true).optional(),
|
|
19687
19688
|
version_check: exports_external.boolean().default(true).optional(),
|
|
19688
19689
|
full_auto: exports_external.object({
|
|
19689
19690
|
enabled: exports_external.boolean().default(false),
|
|
@@ -33500,9 +33501,11 @@ function isGitRepo() {
|
|
|
33500
33501
|
function handleSave(label, directory) {
|
|
33501
33502
|
try {
|
|
33502
33503
|
let maxCheckpoints = 20;
|
|
33504
|
+
let allowEmptyCommits = false;
|
|
33503
33505
|
try {
|
|
33504
33506
|
const { config: config3 } = loadPluginConfigWithMeta(directory);
|
|
33505
33507
|
maxCheckpoints = config3.checkpoint?.auto_checkpoint_threshold ?? maxCheckpoints;
|
|
33508
|
+
allowEmptyCommits = config3.checkpoint?.allow_empty_commits === true;
|
|
33506
33509
|
} catch {}
|
|
33507
33510
|
const log2 = readCheckpointLog(directory);
|
|
33508
33511
|
const existingCheckpoint = log2.checkpoints.find((c) => c.label === label);
|
|
@@ -33513,9 +33516,21 @@ function handleSave(label, directory) {
|
|
|
33513
33516
|
error: `duplicate label: "${label}" already exists. Use a different label or delete the existing checkpoint first.`
|
|
33514
33517
|
}, null, 2);
|
|
33515
33518
|
}
|
|
33516
|
-
const _sha = getCurrentSha();
|
|
33517
33519
|
const timestamp = new Date().toISOString();
|
|
33518
|
-
gitExec(["
|
|
33520
|
+
gitExec(["add", "--all", "--", ":!.swarm/"]);
|
|
33521
|
+
const hasStagedChanges = (() => {
|
|
33522
|
+
try {
|
|
33523
|
+
gitExec(["diff", "--cached", "--quiet"]);
|
|
33524
|
+
return false;
|
|
33525
|
+
} catch {
|
|
33526
|
+
return true;
|
|
33527
|
+
}
|
|
33528
|
+
})();
|
|
33529
|
+
if (hasStagedChanges) {
|
|
33530
|
+
gitExec(["commit", "-m", `checkpoint: ${label}`]);
|
|
33531
|
+
} else if (allowEmptyCommits) {
|
|
33532
|
+
gitExec(["commit", "--allow-empty", "-m", `checkpoint: ${label}`]);
|
|
33533
|
+
}
|
|
33519
33534
|
const newSha = getCurrentSha();
|
|
33520
33535
|
log2.checkpoints.push({
|
|
33521
33536
|
label,
|
|
@@ -33594,7 +33609,7 @@ function handleDelete(label, directory) {
|
|
|
33594
33609
|
action: "delete",
|
|
33595
33610
|
success: true,
|
|
33596
33611
|
label,
|
|
33597
|
-
message: `Checkpoint deleted: "${label}"
|
|
33612
|
+
message: `Checkpoint deleted: "${label}"`
|
|
33598
33613
|
}, null, 2);
|
|
33599
33614
|
} catch (e) {
|
|
33600
33615
|
const errorMessage = e instanceof Error ? `delete failed: ${e.message}` : "delete failed: unknown error";
|
|
@@ -39480,6 +39495,9 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
39480
39495
|
const historyData = await getHistoryData(directory);
|
|
39481
39496
|
return formatHistoryMarkdown(historyData);
|
|
39482
39497
|
}
|
|
39498
|
+
// src/commands/knowledge.ts
|
|
39499
|
+
import { join as join21 } from "path";
|
|
39500
|
+
|
|
39483
39501
|
// src/hooks/knowledge-migrator.ts
|
|
39484
39502
|
init_logger();
|
|
39485
39503
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -39710,34 +39728,65 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
39710
39728
|
}
|
|
39711
39729
|
|
|
39712
39730
|
// src/commands/knowledge.ts
|
|
39731
|
+
function resolveEntryByPrefix(entries, inputId) {
|
|
39732
|
+
const exact = entries.find((e) => e.id === inputId);
|
|
39733
|
+
if (exact)
|
|
39734
|
+
return { entry: exact };
|
|
39735
|
+
const matches = entries.filter((e) => e.id.startsWith(inputId));
|
|
39736
|
+
if (matches.length === 0) {
|
|
39737
|
+
return { error: `No entry found matching '${inputId}'.` };
|
|
39738
|
+
}
|
|
39739
|
+
if (matches.length === 1) {
|
|
39740
|
+
return { entry: matches[0] };
|
|
39741
|
+
}
|
|
39742
|
+
const candidates = matches.map((e) => e.id).join(`
|
|
39743
|
+
`);
|
|
39744
|
+
return {
|
|
39745
|
+
error: `Ambiguous prefix '${inputId}' matches ${matches.length} entries:
|
|
39746
|
+
${candidates}`
|
|
39747
|
+
};
|
|
39748
|
+
}
|
|
39713
39749
|
async function handleKnowledgeQuarantineCommand(directory, args) {
|
|
39714
|
-
const
|
|
39715
|
-
if (!
|
|
39750
|
+
const inputId = args[0];
|
|
39751
|
+
if (!inputId) {
|
|
39716
39752
|
return "Usage: /swarm knowledge quarantine <id> [reason]";
|
|
39717
39753
|
}
|
|
39718
|
-
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(
|
|
39754
|
+
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId)) {
|
|
39719
39755
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
39720
39756
|
}
|
|
39721
39757
|
const reason = args.slice(1).join(" ") || "Quarantined via /swarm knowledge quarantine command";
|
|
39722
39758
|
try {
|
|
39723
|
-
await
|
|
39724
|
-
|
|
39759
|
+
const entries = await readKnowledge(resolveSwarmKnowledgePath(directory));
|
|
39760
|
+
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
39761
|
+
if ("error" in resolved) {
|
|
39762
|
+
return `\u274C ${resolved.error}`;
|
|
39763
|
+
}
|
|
39764
|
+
const fullId = resolved.entry.id;
|
|
39765
|
+
await quarantineEntry(directory, fullId, reason, "user");
|
|
39766
|
+
return `\u2705 Entry ${fullId} quarantined successfully.`;
|
|
39725
39767
|
} catch (error93) {
|
|
39726
39768
|
console.warn("[knowledge-command] quarantineEntry error:", error93 instanceof Error ? error93.message : String(error93));
|
|
39727
39769
|
return `\u274C Failed to quarantine entry. Check the entry ID and try again.`;
|
|
39728
39770
|
}
|
|
39729
39771
|
}
|
|
39730
39772
|
async function handleKnowledgeRestoreCommand(directory, args) {
|
|
39731
|
-
const
|
|
39732
|
-
if (!
|
|
39773
|
+
const inputId = args[0];
|
|
39774
|
+
if (!inputId) {
|
|
39733
39775
|
return "Usage: /swarm knowledge restore <id>";
|
|
39734
39776
|
}
|
|
39735
|
-
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(
|
|
39777
|
+
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId)) {
|
|
39736
39778
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
39737
39779
|
}
|
|
39738
39780
|
try {
|
|
39739
|
-
|
|
39740
|
-
|
|
39781
|
+
const quarantinePath = join21(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
39782
|
+
const entries = await readKnowledge(quarantinePath);
|
|
39783
|
+
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
39784
|
+
if ("error" in resolved) {
|
|
39785
|
+
return `\u274C ${resolved.error}`;
|
|
39786
|
+
}
|
|
39787
|
+
const fullId = resolved.entry.id;
|
|
39788
|
+
await restoreEntry(directory, fullId);
|
|
39789
|
+
return `\u2705 Entry ${fullId} restored successfully.`;
|
|
39741
39790
|
} catch (error93) {
|
|
39742
39791
|
console.warn("[knowledge-command] restoreEntry error:", error93 instanceof Error ? error93.message : String(error93));
|
|
39743
39792
|
return `\u274C Failed to restore entry. Check the entry ID and try again.`;
|
|
@@ -39775,16 +39824,16 @@ async function handleKnowledgeListCommand(directory, _args) {
|
|
|
39775
39824
|
const lines = [
|
|
39776
39825
|
`## Knowledge Entries (${entries.length} total)`,
|
|
39777
39826
|
"",
|
|
39778
|
-
"| ID | Category | Confidence | Lesson (truncated) |",
|
|
39779
|
-
"
|
|
39827
|
+
"| ID (prefix) | Category | Confidence | Lesson (truncated) |",
|
|
39828
|
+
"|--------------|----------|------------|---------------------|"
|
|
39780
39829
|
];
|
|
39781
39830
|
for (const entry of entries) {
|
|
39782
39831
|
const truncatedLesson = entry.lesson.length > 60 ? `${entry.lesson.slice(0, 57)}...` : entry.lesson;
|
|
39783
39832
|
const confidencePct = Math.round(entry.confidence * 100);
|
|
39784
|
-
lines.push(`| ${entry.id.slice(0,
|
|
39833
|
+
lines.push(`| ${entry.id.slice(0, 12)}\u2026 | ${entry.category} | ${confidencePct}% | ${truncatedLesson} |`);
|
|
39785
39834
|
}
|
|
39786
39835
|
lines.push("");
|
|
39787
|
-
lines.push("Use `/swarm knowledge quarantine <id>` to hide an entry.");
|
|
39836
|
+
lines.push("Use `/swarm knowledge quarantine <id-prefix>` to hide an entry. Prefix matching is supported \u2014 the 12-character prefix shown is unique in most stores.");
|
|
39788
39837
|
return lines.join(`
|
|
39789
39838
|
`);
|
|
39790
39839
|
} catch (error93) {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Handles /swarm knowledge quarantine <id> [reason] command.
|
|
3
3
|
* Moves a knowledge entry to quarantine with optional reason.
|
|
4
|
+
* Accepts a full ID or a unique prefix.
|
|
4
5
|
*/
|
|
5
6
|
export declare function handleKnowledgeQuarantineCommand(directory: string, args: string[]): Promise<string>;
|
|
6
7
|
/**
|
|
7
8
|
* Handles /swarm knowledge restore <id> command.
|
|
8
9
|
* Restores a quarantined knowledge entry.
|
|
10
|
+
* Accepts a full ID or a unique prefix.
|
|
9
11
|
*/
|
|
10
12
|
export declare function handleKnowledgeRestoreCommand(directory: string, args: string[]): Promise<string>;
|
|
11
13
|
/**
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -380,6 +380,7 @@ export type PlanCursorConfig = z.infer<typeof PlanCursorConfigSchema>;
|
|
|
380
380
|
export declare const CheckpointConfigSchema: z.ZodObject<{
|
|
381
381
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
382
382
|
auto_checkpoint_threshold: z.ZodDefault<z.ZodNumber>;
|
|
383
|
+
allow_empty_commits: z.ZodDefault<z.ZodBoolean>;
|
|
383
384
|
}, z.core.$strict>;
|
|
384
385
|
export type CheckpointConfig = z.infer<typeof CheckpointConfigSchema>;
|
|
385
386
|
export declare const AutomationModeSchema: z.ZodEnum<{
|
|
@@ -885,6 +886,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
885
886
|
checkpoint: z.ZodOptional<z.ZodObject<{
|
|
886
887
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
887
888
|
auto_checkpoint_threshold: z.ZodDefault<z.ZodNumber>;
|
|
889
|
+
allow_empty_commits: z.ZodDefault<z.ZodBoolean>;
|
|
888
890
|
}, z.core.$strict>>;
|
|
889
891
|
automation: z.ZodOptional<z.ZodType<{
|
|
890
892
|
mode: "auto" | "manual" | "hybrid";
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var package_default;
|
|
|
33
33
|
var init_package = __esm(() => {
|
|
34
34
|
package_default = {
|
|
35
35
|
name: "opencode-swarm",
|
|
36
|
-
version: "6.86.
|
|
36
|
+
version: "6.86.13",
|
|
37
37
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
38
38
|
main: "dist/index.js",
|
|
39
39
|
types: "dist/index.d.ts",
|
|
@@ -15179,7 +15179,8 @@ var init_schema = __esm(() => {
|
|
|
15179
15179
|
});
|
|
15180
15180
|
CheckpointConfigSchema = exports_external.object({
|
|
15181
15181
|
enabled: exports_external.boolean().default(true),
|
|
15182
|
-
auto_checkpoint_threshold: exports_external.number().int().min(1).max(20).default(3)
|
|
15182
|
+
auto_checkpoint_threshold: exports_external.number().int().min(1).max(20).default(3),
|
|
15183
|
+
allow_empty_commits: exports_external.boolean().default(false)
|
|
15183
15184
|
}).strict();
|
|
15184
15185
|
AutomationModeSchema = exports_external.enum(["manual", "hybrid", "auto"]);
|
|
15185
15186
|
AutomationCapabilitiesSchema = exports_external.object({
|
|
@@ -15390,7 +15391,7 @@ var init_schema = __esm(() => {
|
|
|
15390
15391
|
council: CouncilConfigSchema.optional(),
|
|
15391
15392
|
parallelization: ParallelizationConfigSchema.optional(),
|
|
15392
15393
|
turbo_mode: exports_external.boolean().default(false).optional(),
|
|
15393
|
-
quiet: exports_external.boolean().default(
|
|
15394
|
+
quiet: exports_external.boolean().default(true).optional(),
|
|
15394
15395
|
version_check: exports_external.boolean().default(true).optional(),
|
|
15395
15396
|
full_auto: exports_external.object({
|
|
15396
15397
|
enabled: exports_external.boolean().default(false),
|
|
@@ -39551,9 +39552,11 @@ function isGitRepo() {
|
|
|
39551
39552
|
function handleSave(label, directory) {
|
|
39552
39553
|
try {
|
|
39553
39554
|
let maxCheckpoints = 20;
|
|
39555
|
+
let allowEmptyCommits = false;
|
|
39554
39556
|
try {
|
|
39555
39557
|
const { config: config3 } = loadPluginConfigWithMeta(directory);
|
|
39556
39558
|
maxCheckpoints = config3.checkpoint?.auto_checkpoint_threshold ?? maxCheckpoints;
|
|
39559
|
+
allowEmptyCommits = config3.checkpoint?.allow_empty_commits === true;
|
|
39557
39560
|
} catch {}
|
|
39558
39561
|
const log2 = readCheckpointLog(directory);
|
|
39559
39562
|
const existingCheckpoint = log2.checkpoints.find((c) => c.label === label);
|
|
@@ -39564,9 +39567,21 @@ function handleSave(label, directory) {
|
|
|
39564
39567
|
error: `duplicate label: "${label}" already exists. Use a different label or delete the existing checkpoint first.`
|
|
39565
39568
|
}, null, 2);
|
|
39566
39569
|
}
|
|
39567
|
-
const _sha = getCurrentSha();
|
|
39568
39570
|
const timestamp = new Date().toISOString();
|
|
39569
|
-
gitExec(["
|
|
39571
|
+
gitExec(["add", "--all", "--", ":!.swarm/"]);
|
|
39572
|
+
const hasStagedChanges = (() => {
|
|
39573
|
+
try {
|
|
39574
|
+
gitExec(["diff", "--cached", "--quiet"]);
|
|
39575
|
+
return false;
|
|
39576
|
+
} catch {
|
|
39577
|
+
return true;
|
|
39578
|
+
}
|
|
39579
|
+
})();
|
|
39580
|
+
if (hasStagedChanges) {
|
|
39581
|
+
gitExec(["commit", "-m", `checkpoint: ${label}`]);
|
|
39582
|
+
} else if (allowEmptyCommits) {
|
|
39583
|
+
gitExec(["commit", "--allow-empty", "-m", `checkpoint: ${label}`]);
|
|
39584
|
+
}
|
|
39570
39585
|
const newSha = getCurrentSha();
|
|
39571
39586
|
log2.checkpoints.push({
|
|
39572
39587
|
label,
|
|
@@ -39645,7 +39660,7 @@ function handleDelete(label, directory) {
|
|
|
39645
39660
|
action: "delete",
|
|
39646
39661
|
success: true,
|
|
39647
39662
|
label,
|
|
39648
|
-
message: `Checkpoint deleted: "${label}"
|
|
39663
|
+
message: `Checkpoint deleted: "${label}"`
|
|
39649
39664
|
}, null, 2);
|
|
39650
39665
|
} catch (e) {
|
|
39651
39666
|
const errorMessage = e instanceof Error ? `delete failed: ${e.message}` : "delete failed: unknown error";
|
|
@@ -48396,34 +48411,66 @@ var init_knowledge_migrator = __esm(() => {
|
|
|
48396
48411
|
});
|
|
48397
48412
|
|
|
48398
48413
|
// src/commands/knowledge.ts
|
|
48414
|
+
import { join as join28 } from "node:path";
|
|
48415
|
+
function resolveEntryByPrefix(entries, inputId) {
|
|
48416
|
+
const exact = entries.find((e) => e.id === inputId);
|
|
48417
|
+
if (exact)
|
|
48418
|
+
return { entry: exact };
|
|
48419
|
+
const matches = entries.filter((e) => e.id.startsWith(inputId));
|
|
48420
|
+
if (matches.length === 0) {
|
|
48421
|
+
return { error: `No entry found matching '${inputId}'.` };
|
|
48422
|
+
}
|
|
48423
|
+
if (matches.length === 1) {
|
|
48424
|
+
return { entry: matches[0] };
|
|
48425
|
+
}
|
|
48426
|
+
const candidates = matches.map((e) => e.id).join(`
|
|
48427
|
+
`);
|
|
48428
|
+
return {
|
|
48429
|
+
error: `Ambiguous prefix '${inputId}' matches ${matches.length} entries:
|
|
48430
|
+
${candidates}`
|
|
48431
|
+
};
|
|
48432
|
+
}
|
|
48399
48433
|
async function handleKnowledgeQuarantineCommand(directory, args2) {
|
|
48400
|
-
const
|
|
48401
|
-
if (!
|
|
48434
|
+
const inputId = args2[0];
|
|
48435
|
+
if (!inputId) {
|
|
48402
48436
|
return "Usage: /swarm knowledge quarantine <id> [reason]";
|
|
48403
48437
|
}
|
|
48404
|
-
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(
|
|
48438
|
+
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId)) {
|
|
48405
48439
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
48406
48440
|
}
|
|
48407
48441
|
const reason = args2.slice(1).join(" ") || "Quarantined via /swarm knowledge quarantine command";
|
|
48408
48442
|
try {
|
|
48409
|
-
await
|
|
48410
|
-
|
|
48443
|
+
const entries = await readKnowledge(resolveSwarmKnowledgePath(directory));
|
|
48444
|
+
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
48445
|
+
if ("error" in resolved) {
|
|
48446
|
+
return `❌ ${resolved.error}`;
|
|
48447
|
+
}
|
|
48448
|
+
const fullId = resolved.entry.id;
|
|
48449
|
+
await quarantineEntry(directory, fullId, reason, "user");
|
|
48450
|
+
return `✅ Entry ${fullId} quarantined successfully.`;
|
|
48411
48451
|
} catch (error93) {
|
|
48412
48452
|
console.warn("[knowledge-command] quarantineEntry error:", error93 instanceof Error ? error93.message : String(error93));
|
|
48413
48453
|
return `❌ Failed to quarantine entry. Check the entry ID and try again.`;
|
|
48414
48454
|
}
|
|
48415
48455
|
}
|
|
48416
48456
|
async function handleKnowledgeRestoreCommand(directory, args2) {
|
|
48417
|
-
const
|
|
48418
|
-
if (!
|
|
48457
|
+
const inputId = args2[0];
|
|
48458
|
+
if (!inputId) {
|
|
48419
48459
|
return "Usage: /swarm knowledge restore <id>";
|
|
48420
48460
|
}
|
|
48421
|
-
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(
|
|
48461
|
+
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId)) {
|
|
48422
48462
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
48423
48463
|
}
|
|
48424
48464
|
try {
|
|
48425
|
-
|
|
48426
|
-
|
|
48465
|
+
const quarantinePath = join28(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
48466
|
+
const entries = await readKnowledge(quarantinePath);
|
|
48467
|
+
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
48468
|
+
if ("error" in resolved) {
|
|
48469
|
+
return `❌ ${resolved.error}`;
|
|
48470
|
+
}
|
|
48471
|
+
const fullId = resolved.entry.id;
|
|
48472
|
+
await restoreEntry(directory, fullId);
|
|
48473
|
+
return `✅ Entry ${fullId} restored successfully.`;
|
|
48427
48474
|
} catch (error93) {
|
|
48428
48475
|
console.warn("[knowledge-command] restoreEntry error:", error93 instanceof Error ? error93.message : String(error93));
|
|
48429
48476
|
return `❌ Failed to restore entry. Check the entry ID and try again.`;
|
|
@@ -48461,16 +48508,16 @@ async function handleKnowledgeListCommand(directory, _args) {
|
|
|
48461
48508
|
const lines = [
|
|
48462
48509
|
`## Knowledge Entries (${entries.length} total)`,
|
|
48463
48510
|
"",
|
|
48464
|
-
"| ID | Category | Confidence | Lesson (truncated) |",
|
|
48465
|
-
"
|
|
48511
|
+
"| ID (prefix) | Category | Confidence | Lesson (truncated) |",
|
|
48512
|
+
"|--------------|----------|------------|---------------------|"
|
|
48466
48513
|
];
|
|
48467
48514
|
for (const entry of entries) {
|
|
48468
48515
|
const truncatedLesson = entry.lesson.length > 60 ? `${entry.lesson.slice(0, 57)}...` : entry.lesson;
|
|
48469
48516
|
const confidencePct = Math.round(entry.confidence * 100);
|
|
48470
|
-
lines.push(`| ${entry.id.slice(0,
|
|
48517
|
+
lines.push(`| ${entry.id.slice(0, 12)}… | ${entry.category} | ${confidencePct}% | ${truncatedLesson} |`);
|
|
48471
48518
|
}
|
|
48472
48519
|
lines.push("");
|
|
48473
|
-
lines.push("Use `/swarm knowledge quarantine <id>` to hide an entry.");
|
|
48520
|
+
lines.push("Use `/swarm knowledge quarantine <id-prefix>` to hide an entry. Prefix matching is supported — the 12-character prefix shown is unique in most stores.");
|
|
48474
48521
|
return lines.join(`
|
|
48475
48522
|
`);
|
|
48476
48523
|
} catch (error93) {
|
|
@@ -58152,7 +58199,7 @@ function createSwarmAgents(swarmId, swarmConfig, isDefault, pluginConfig) {
|
|
|
58152
58199
|
const prefix = isDefault ? "" : `${swarmId}_`;
|
|
58153
58200
|
const swarmPrefix = isDefault ? undefined : swarmId;
|
|
58154
58201
|
const qaRetryLimit = pluginConfig?.qa_retry_limit ?? 3;
|
|
58155
|
-
const quiet = pluginConfig?.quiet ??
|
|
58202
|
+
const quiet = pluginConfig?.quiet ?? true;
|
|
58156
58203
|
const getModel = (baseName) => getModelForAgent(baseName, swarmAgents, swarmPrefix, quiet);
|
|
58157
58204
|
const getPrompts = (name2) => loadAgentPrompt(name2);
|
|
58158
58205
|
const prefixName = (name2) => `${prefix}${name2}`;
|
|
@@ -58302,7 +58349,7 @@ function getAgentConfigs(config3, directory, sessionId) {
|
|
|
58302
58349
|
const agents = createAgents(config3);
|
|
58303
58350
|
const toolFilterEnabled = config3?.tool_filter?.enabled ?? true;
|
|
58304
58351
|
const toolFilterOverrides = config3?.tool_filter?.overrides ?? {};
|
|
58305
|
-
const quiet = config3?.quiet ??
|
|
58352
|
+
const quiet = config3?.quiet ?? true;
|
|
58306
58353
|
const warnedMissingWhitelist = new Set;
|
|
58307
58354
|
const agentToolSnapshot = {};
|
|
58308
58355
|
const result = Object.fromEntries(agents.map((agent) => {
|
|
@@ -63841,7 +63888,7 @@ ${content.substring(endIndex + 1)}`;
|
|
|
63841
63888
|
init_manager();
|
|
63842
63889
|
init_utils2();
|
|
63843
63890
|
import * as fs31 from "node:fs";
|
|
63844
|
-
import { join as
|
|
63891
|
+
import { join as join42 } from "node:path";
|
|
63845
63892
|
function createCompactionCustomizerHook(config3, directory) {
|
|
63846
63893
|
const enabled = config3.hooks?.compaction !== false;
|
|
63847
63894
|
if (!enabled) {
|
|
@@ -63886,7 +63933,7 @@ function createCompactionCustomizerHook(config3, directory) {
|
|
|
63886
63933
|
}
|
|
63887
63934
|
}
|
|
63888
63935
|
try {
|
|
63889
|
-
const summariesDir =
|
|
63936
|
+
const summariesDir = join42(directory, ".swarm", "summaries");
|
|
63890
63937
|
const files = await fs31.promises.readdir(summariesDir);
|
|
63891
63938
|
if (files.length > 0) {
|
|
63892
63939
|
const count = files.length;
|
|
@@ -74619,7 +74666,7 @@ import {
|
|
|
74619
74666
|
readFileSync as readFileSync36,
|
|
74620
74667
|
writeFileSync as writeFileSync11
|
|
74621
74668
|
} from "node:fs";
|
|
74622
|
-
import { join as
|
|
74669
|
+
import { join as join66 } from "node:path";
|
|
74623
74670
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
74624
74671
|
var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
|
|
74625
74672
|
var COUNCIL_GATE_NAME = "council";
|
|
@@ -74653,9 +74700,9 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
74653
74700
|
if (!VALID_TASK_ID.test(synthesis.taskId)) {
|
|
74654
74701
|
throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" — must match N.M or N.M.P format`);
|
|
74655
74702
|
}
|
|
74656
|
-
const dir =
|
|
74703
|
+
const dir = join66(workingDir, EVIDENCE_DIR2);
|
|
74657
74704
|
mkdirSync18(dir, { recursive: true });
|
|
74658
|
-
const filePath =
|
|
74705
|
+
const filePath = join66(dir, `${synthesis.taskId}.json`);
|
|
74659
74706
|
const existingRoot = Object.create(null);
|
|
74660
74707
|
if (existsSync37(filePath)) {
|
|
74661
74708
|
try {
|
|
@@ -74689,7 +74736,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
74689
74736
|
updated.required_gates = [];
|
|
74690
74737
|
writeFileSync11(filePath, JSON.stringify(updated, null, 2));
|
|
74691
74738
|
try {
|
|
74692
|
-
const councilDir =
|
|
74739
|
+
const councilDir = join66(workingDir, ".swarm", "council");
|
|
74693
74740
|
mkdirSync18(councilDir, { recursive: true });
|
|
74694
74741
|
const auditLine = JSON.stringify({
|
|
74695
74742
|
round: synthesis.roundNumber,
|
|
@@ -74697,7 +74744,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
74697
74744
|
timestamp: synthesis.timestamp,
|
|
74698
74745
|
vetoedBy: synthesis.vetoedBy
|
|
74699
74746
|
});
|
|
74700
|
-
appendFileSync6(
|
|
74747
|
+
appendFileSync6(join66(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
|
|
74701
74748
|
`);
|
|
74702
74749
|
} catch (auditError) {
|
|
74703
74750
|
console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
|
|
@@ -74830,20 +74877,20 @@ function buildUnifiedFeedback(taskId, verdict, vetoedBy, requiredFixes, advisory
|
|
|
74830
74877
|
|
|
74831
74878
|
// src/council/criteria-store.ts
|
|
74832
74879
|
import { existsSync as existsSync38, mkdirSync as mkdirSync19, readFileSync as readFileSync37, writeFileSync as writeFileSync12 } from "node:fs";
|
|
74833
|
-
import { join as
|
|
74880
|
+
import { join as join67 } from "node:path";
|
|
74834
74881
|
var COUNCIL_DIR = ".swarm/council";
|
|
74835
74882
|
function writeCriteria(workingDir, taskId, criteria) {
|
|
74836
|
-
const dir =
|
|
74883
|
+
const dir = join67(workingDir, COUNCIL_DIR);
|
|
74837
74884
|
mkdirSync19(dir, { recursive: true });
|
|
74838
74885
|
const payload = {
|
|
74839
74886
|
taskId,
|
|
74840
74887
|
criteria,
|
|
74841
74888
|
declaredAt: new Date().toISOString()
|
|
74842
74889
|
};
|
|
74843
|
-
writeFileSync12(
|
|
74890
|
+
writeFileSync12(join67(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
|
|
74844
74891
|
}
|
|
74845
74892
|
function readCriteria(workingDir, taskId) {
|
|
74846
|
-
const filePath =
|
|
74893
|
+
const filePath = join67(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
|
|
74847
74894
|
if (!existsSync38(filePath))
|
|
74848
74895
|
return null;
|
|
74849
74896
|
try {
|
|
@@ -77388,6 +77435,7 @@ var VALID_CATEGORIES2 = [
|
|
|
77388
77435
|
"debugging",
|
|
77389
77436
|
"performance",
|
|
77390
77437
|
"integration",
|
|
77438
|
+
"todo",
|
|
77391
77439
|
"other"
|
|
77392
77440
|
];
|
|
77393
77441
|
var knowledge_add = createSwarmTool({
|
|
@@ -77532,6 +77580,7 @@ var VALID_CATEGORIES3 = [
|
|
|
77532
77580
|
"debugging",
|
|
77533
77581
|
"performance",
|
|
77534
77582
|
"integration",
|
|
77583
|
+
"todo",
|
|
77535
77584
|
"other"
|
|
77536
77585
|
];
|
|
77537
77586
|
var VALID_STATUSES = ["candidate", "established", "promoted"];
|
|
@@ -88668,7 +88717,7 @@ function readFileSafe(filePath) {
|
|
|
88668
88717
|
return null;
|
|
88669
88718
|
}
|
|
88670
88719
|
}
|
|
88671
|
-
function warnIfSwarmNotGitignored(directory) {
|
|
88720
|
+
function warnIfSwarmNotGitignored(directory, quiet = false) {
|
|
88672
88721
|
if (_gitignoreWarningEmitted)
|
|
88673
88722
|
return;
|
|
88674
88723
|
try {
|
|
@@ -88686,7 +88735,9 @@ function warnIfSwarmNotGitignored(directory) {
|
|
|
88686
88735
|
return;
|
|
88687
88736
|
}
|
|
88688
88737
|
_gitignoreWarningEmitted = true;
|
|
88689
|
-
|
|
88738
|
+
if (!quiet) {
|
|
88739
|
+
console.warn('[opencode-swarm] WARNING: .swarm/ is not in your .gitignore. Shell audit logs may contain API keys. Add ".swarm/" to your .gitignore to prevent accidental commits.');
|
|
88740
|
+
}
|
|
88690
88741
|
} catch {}
|
|
88691
88742
|
}
|
|
88692
88743
|
|
|
@@ -88802,7 +88853,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
88802
88853
|
await loadSnapshot(ctx.directory);
|
|
88803
88854
|
initTelemetry(ctx.directory);
|
|
88804
88855
|
writeSwarmConfigExampleIfNew(ctx.directory);
|
|
88805
|
-
warnIfSwarmNotGitignored(ctx.directory);
|
|
88856
|
+
warnIfSwarmNotGitignored(ctx.directory, config3.quiet);
|
|
88806
88857
|
if (config3.version_check !== false) {
|
|
88807
88858
|
scheduleVersionCheck(package_default.version, (msg) => {
|
|
88808
88859
|
if (config3.quiet) {
|
|
@@ -10,8 +10,8 @@ export declare function resetGitignoreWarningState(): void;
|
|
|
10
10
|
/**
|
|
11
11
|
* Checks whether `.swarm/` is covered by `.gitignore` or `.git/info/exclude`
|
|
12
12
|
* in the git repo rooted at or above `directory`. If not covered, emits a
|
|
13
|
-
* single `console.warn
|
|
13
|
+
* single `console.warn` (unless `quiet` is true). Fires at most once per process.
|
|
14
14
|
*
|
|
15
15
|
* Never throws — any file-system error silently skips the check.
|
|
16
16
|
*/
|
|
17
|
-
export declare function warnIfSwarmNotGitignored(directory: string): void;
|
|
17
|
+
export declare function warnIfSwarmNotGitignored(directory: string, quiet?: boolean): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.86.
|
|
3
|
+
"version": "6.86.13",
|
|
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",
|