opencode-swarm 7.62.0 → 7.62.1
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 +73 -38
- package/dist/commands/close.d.ts +26 -0
- package/dist/index.js +77 -41
- package/dist/state.d.ts +17 -0
- 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.62.
|
|
55
|
+
version: "7.62.1",
|
|
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",
|
|
@@ -22486,6 +22486,23 @@ function resetSwarmState() {
|
|
|
22486
22486
|
resetStandardWorktreeIsolationState();
|
|
22487
22487
|
_councilDisagreementWarned.clear();
|
|
22488
22488
|
}
|
|
22489
|
+
function resetSwarmStatePreservingSingletons() {
|
|
22490
|
+
const preservedOpencodeClient = swarmState.opencodeClient;
|
|
22491
|
+
const preservedFullAutoEnabledInConfig = swarmState.fullAutoEnabledInConfig;
|
|
22492
|
+
const preservedCuratorInitAgentNames = swarmState.curatorInitAgentNames;
|
|
22493
|
+
const preservedCuratorPhaseAgentNames = swarmState.curatorPhaseAgentNames;
|
|
22494
|
+
const preservedSkillImproverAgentNames = swarmState.skillImproverAgentNames;
|
|
22495
|
+
const preservedSpecWriterAgentNames = swarmState.specWriterAgentNames;
|
|
22496
|
+
const preservedGeneratedAgentNames = swarmState.generatedAgentNames;
|
|
22497
|
+
resetSwarmState();
|
|
22498
|
+
swarmState.opencodeClient = preservedOpencodeClient;
|
|
22499
|
+
swarmState.fullAutoEnabledInConfig = preservedFullAutoEnabledInConfig;
|
|
22500
|
+
swarmState.curatorInitAgentNames = preservedCuratorInitAgentNames;
|
|
22501
|
+
swarmState.curatorPhaseAgentNames = preservedCuratorPhaseAgentNames;
|
|
22502
|
+
swarmState.skillImproverAgentNames = preservedSkillImproverAgentNames;
|
|
22503
|
+
swarmState.specWriterAgentNames = preservedSpecWriterAgentNames;
|
|
22504
|
+
swarmState.generatedAgentNames = preservedGeneratedAgentNames;
|
|
22505
|
+
}
|
|
22489
22506
|
function getAgentSession(sessionId) {
|
|
22490
22507
|
return swarmState.agentSessions.get(sessionId);
|
|
22491
22508
|
}
|
|
@@ -39826,6 +39843,7 @@ var init_write_retro = __esm(() => {
|
|
|
39826
39843
|
});
|
|
39827
39844
|
|
|
39828
39845
|
// src/commands/close.ts
|
|
39846
|
+
import * as fsSync2 from "fs";
|
|
39829
39847
|
import { promises as fs10 } from "fs";
|
|
39830
39848
|
import path21 from "path";
|
|
39831
39849
|
async function runAbortableSkillReview(req, timeoutMs) {
|
|
@@ -39861,6 +39879,28 @@ function countSessionKnowledgeEntries(entries, sessionStart, fallbackCount) {
|
|
|
39861
39879
|
return Number.isFinite(createdAtMs) && createdAtMs >= sessionStartMs;
|
|
39862
39880
|
}).length;
|
|
39863
39881
|
}
|
|
39882
|
+
async function copyDirRecursive(src, dest) {
|
|
39883
|
+
let count = 0;
|
|
39884
|
+
const entries = await fs10.readdir(src);
|
|
39885
|
+
await fs10.mkdir(dest, { recursive: true });
|
|
39886
|
+
for (const entry of entries) {
|
|
39887
|
+
const srcEntry = path21.join(src, entry);
|
|
39888
|
+
const destEntry = path21.join(dest, entry);
|
|
39889
|
+
try {
|
|
39890
|
+
const stat2 = await fs10.stat(srcEntry);
|
|
39891
|
+
if (stat2.isDirectory()) {
|
|
39892
|
+
const subCount = await copyDirRecursive(srcEntry, destEntry).catch(() => 0);
|
|
39893
|
+
count += subCount;
|
|
39894
|
+
} else {
|
|
39895
|
+
try {
|
|
39896
|
+
await fs10.copyFile(srcEntry, destEntry);
|
|
39897
|
+
count++;
|
|
39898
|
+
} catch {}
|
|
39899
|
+
}
|
|
39900
|
+
} catch {}
|
|
39901
|
+
}
|
|
39902
|
+
return count;
|
|
39903
|
+
}
|
|
39864
39904
|
function guaranteeAllPlansComplete(planData) {
|
|
39865
39905
|
const closedPhaseIds = [];
|
|
39866
39906
|
const closedTaskIds = [];
|
|
@@ -39882,8 +39922,18 @@ function guaranteeAllPlansComplete(planData) {
|
|
|
39882
39922
|
return { closedPhaseIds, closedTaskIds };
|
|
39883
39923
|
}
|
|
39884
39924
|
async function handleCloseCommand(directory, args, options = {}) {
|
|
39885
|
-
const planPath = validateSwarmPath(directory, "plan.json");
|
|
39886
39925
|
const swarmDir = path21.join(directory, ".swarm");
|
|
39926
|
+
try {
|
|
39927
|
+
const stat2 = fsSync2.lstatSync(swarmDir);
|
|
39928
|
+
if (stat2.isSymbolicLink()) {
|
|
39929
|
+
return `\u274C Refused: .swarm/ is a symlink or junction. Refusing to operate on a redirected directory for safety.`;
|
|
39930
|
+
}
|
|
39931
|
+
} catch (err) {
|
|
39932
|
+
if (err?.code !== "ENOENT") {
|
|
39933
|
+
throw err;
|
|
39934
|
+
}
|
|
39935
|
+
}
|
|
39936
|
+
const planPath = validateSwarmPath(directory, "plan.json");
|
|
39887
39937
|
let planExists = false;
|
|
39888
39938
|
let planData = {
|
|
39889
39939
|
title: path21.basename(directory) || "Ad-hoc session",
|
|
@@ -40165,31 +40215,12 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
40165
40215
|
const srcDir = path21.join(swarmDir, dirName);
|
|
40166
40216
|
const destDir = path21.join(archiveDir, dirName);
|
|
40167
40217
|
try {
|
|
40168
|
-
const
|
|
40169
|
-
|
|
40170
|
-
await fs10.mkdir(destDir, { recursive: true });
|
|
40171
|
-
for (const entry of entries) {
|
|
40172
|
-
const srcEntry = path21.join(srcDir, entry);
|
|
40173
|
-
const destEntry = path21.join(destDir, entry);
|
|
40174
|
-
try {
|
|
40175
|
-
const stat2 = await fs10.stat(srcEntry);
|
|
40176
|
-
if (stat2.isDirectory()) {
|
|
40177
|
-
await fs10.mkdir(destEntry, { recursive: true });
|
|
40178
|
-
const subEntries = await fs10.readdir(srcEntry);
|
|
40179
|
-
for (const sub of subEntries) {
|
|
40180
|
-
await fs10.copyFile(path21.join(srcEntry, sub), path21.join(destEntry, sub)).catch(() => {});
|
|
40181
|
-
}
|
|
40182
|
-
} else {
|
|
40183
|
-
await fs10.copyFile(srcEntry, destEntry);
|
|
40184
|
-
}
|
|
40185
|
-
archivedFileCount++;
|
|
40186
|
-
} catch {}
|
|
40187
|
-
}
|
|
40188
|
-
}
|
|
40218
|
+
const copied = await copyDirRecursive(srcDir, destDir);
|
|
40219
|
+
archivedFileCount += copied;
|
|
40189
40220
|
archivedActiveStateDirs.add(dirName);
|
|
40190
40221
|
} catch {}
|
|
40191
40222
|
}
|
|
40192
|
-
archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}/`;
|
|
40223
|
+
archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}-${suffix}/`;
|
|
40193
40224
|
} catch (archiveError) {
|
|
40194
40225
|
warnings.push(`Archive creation failed: ${archiveError instanceof Error ? archiveError.message : String(archiveError)}`);
|
|
40195
40226
|
archiveResult = "Archive creation failed (see warnings)";
|
|
@@ -40261,6 +40292,20 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
40261
40292
|
}
|
|
40262
40293
|
}
|
|
40263
40294
|
}
|
|
40295
|
+
let tmpFilesRemoved = 0;
|
|
40296
|
+
try {
|
|
40297
|
+
const swarmFiles = await fs10.readdir(swarmDir);
|
|
40298
|
+
const tmpFiles = swarmFiles.filter((f) => f.startsWith(".tmp."));
|
|
40299
|
+
for (const tmp of tmpFiles) {
|
|
40300
|
+
try {
|
|
40301
|
+
await fs10.unlink(path21.join(swarmDir, tmp));
|
|
40302
|
+
tmpFilesRemoved++;
|
|
40303
|
+
} catch {}
|
|
40304
|
+
}
|
|
40305
|
+
} catch {}
|
|
40306
|
+
if (tmpFilesRemoved > 0) {
|
|
40307
|
+
cleanedFiles.push(`${tmpFilesRemoved} .tmp.* file(s)`);
|
|
40308
|
+
}
|
|
40264
40309
|
clearAllScopes(directory);
|
|
40265
40310
|
const contextPath = path21.join(swarmDir, "context.md");
|
|
40266
40311
|
const contextContent = [
|
|
@@ -40367,17 +40412,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
40367
40412
|
warnings.push(`Failed to write close-summary.md: ${msg}`);
|
|
40368
40413
|
console.warn("[close-command] Failed to write close-summary.md:", error93);
|
|
40369
40414
|
}
|
|
40370
|
-
|
|
40371
|
-
const preservedFullAutoFlag = swarmState.fullAutoEnabledInConfig;
|
|
40372
|
-
const preservedCuratorInitNames = swarmState.curatorInitAgentNames;
|
|
40373
|
-
const preservedCuratorPhaseNames = swarmState.curatorPhaseAgentNames;
|
|
40374
|
-
const preservedSkillImproverAgentNames = swarmState.skillImproverAgentNames;
|
|
40375
|
-
resetSwarmState();
|
|
40376
|
-
swarmState.opencodeClient = preservedClient;
|
|
40377
|
-
swarmState.fullAutoEnabledInConfig = preservedFullAutoFlag;
|
|
40378
|
-
swarmState.curatorInitAgentNames = preservedCuratorInitNames;
|
|
40379
|
-
swarmState.curatorPhaseAgentNames = preservedCuratorPhaseNames;
|
|
40380
|
-
swarmState.skillImproverAgentNames = preservedSkillImproverAgentNames;
|
|
40415
|
+
resetSwarmStatePreservingSingletons();
|
|
40381
40416
|
const retroWarnings = warnings.filter((w) => w.includes("Retrospective write") || w.includes("retrospective write") || w.includes("Session retrospective"));
|
|
40382
40417
|
const otherWarnings = warnings.filter((w) => !w.includes("Retrospective write") && !w.includes("retrospective write") && !w.includes("Session retrospective"));
|
|
40383
40418
|
let warningMsg = "";
|
|
@@ -58504,14 +58539,14 @@ var init_context_budget_service = __esm(() => {
|
|
|
58504
58539
|
});
|
|
58505
58540
|
|
|
58506
58541
|
// src/services/status-service.ts
|
|
58507
|
-
import * as
|
|
58542
|
+
import * as fsSync3 from "fs";
|
|
58508
58543
|
import * as path55 from "path";
|
|
58509
58544
|
function readSpecStalenessSnapshot(directory) {
|
|
58510
58545
|
try {
|
|
58511
58546
|
const p = path55.join(directory, ".swarm", "spec-staleness.json");
|
|
58512
|
-
if (!
|
|
58547
|
+
if (!fsSync3.existsSync(p))
|
|
58513
58548
|
return { stale: false };
|
|
58514
|
-
const raw =
|
|
58549
|
+
const raw = fsSync3.readFileSync(p, "utf-8");
|
|
58515
58550
|
const parsed = JSON.parse(raw);
|
|
58516
58551
|
return {
|
|
58517
58552
|
stale: true,
|
package/dist/commands/close.d.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
interface PlanPhase {
|
|
2
|
+
id: number;
|
|
3
|
+
name: string;
|
|
4
|
+
status: string;
|
|
5
|
+
tasks: Array<{
|
|
6
|
+
id: string;
|
|
7
|
+
status: string;
|
|
8
|
+
close_reason?: string;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
interface PlanData {
|
|
12
|
+
title: string;
|
|
13
|
+
phases: PlanPhase[];
|
|
14
|
+
}
|
|
1
15
|
interface CloseCommandOptions {
|
|
2
16
|
sessionID?: string;
|
|
3
17
|
skillReviewTimeoutMs?: number;
|
|
@@ -6,6 +20,16 @@ interface CloseKnowledgeEntry {
|
|
|
6
20
|
created_at?: string;
|
|
7
21
|
}
|
|
8
22
|
declare function countSessionKnowledgeEntries(entries: CloseKnowledgeEntry[], sessionStart: string | undefined, fallbackCount: number): number;
|
|
23
|
+
declare function copyDirRecursive(src: string, dest: string): Promise<number>;
|
|
24
|
+
/**
|
|
25
|
+
* Guarantee all phases and tasks in a plan are marked complete/closed.
|
|
26
|
+
* Mutates planData in place. Returns actual IDs of newly closed phases and
|
|
27
|
+
* tasks so the caller can track only genuinely new closures (idempotent).
|
|
28
|
+
*/
|
|
29
|
+
declare function guaranteeAllPlansComplete(planData: PlanData): {
|
|
30
|
+
closedPhaseIds: number[];
|
|
31
|
+
closedTaskIds: string[];
|
|
32
|
+
};
|
|
9
33
|
/**
|
|
10
34
|
* Handles /swarm close command - performs full terminal session finalization:
|
|
11
35
|
* 0. Guarantee: mark all incomplete phases/tasks as closed
|
|
@@ -20,5 +44,7 @@ export declare function handleCloseCommand(directory: string, args: string[], op
|
|
|
20
44
|
export declare const _internals: {
|
|
21
45
|
countSessionKnowledgeEntries: typeof countSessionKnowledgeEntries;
|
|
22
46
|
CLOSE_SKILL_REVIEW_TIMEOUT_MS: number;
|
|
47
|
+
guaranteeAllPlansComplete: typeof guaranteeAllPlansComplete;
|
|
48
|
+
copyDirRecursive: typeof copyDirRecursive;
|
|
23
49
|
};
|
|
24
50
|
export {};
|
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.62.
|
|
72
|
+
version: "7.62.1",
|
|
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",
|
|
@@ -42974,6 +42974,7 @@ __export(exports_state, {
|
|
|
42974
42974
|
startAgentSession: () => startAgentSession,
|
|
42975
42975
|
setSessionEnvironment: () => setSessionEnvironment,
|
|
42976
42976
|
setCriticalShownIds: () => setCriticalShownIds,
|
|
42977
|
+
resetSwarmStatePreservingSingletons: () => resetSwarmStatePreservingSingletons,
|
|
42977
42978
|
resetSwarmState: () => resetSwarmState,
|
|
42978
42979
|
rehydrateSessionFromDisk: () => rehydrateSessionFromDisk,
|
|
42979
42980
|
recordStageBCompletion: () => recordStageBCompletion,
|
|
@@ -43038,6 +43039,23 @@ function resetSwarmState() {
|
|
|
43038
43039
|
resetStandardWorktreeIsolationState();
|
|
43039
43040
|
_councilDisagreementWarned.clear();
|
|
43040
43041
|
}
|
|
43042
|
+
function resetSwarmStatePreservingSingletons() {
|
|
43043
|
+
const preservedOpencodeClient = swarmState.opencodeClient;
|
|
43044
|
+
const preservedFullAutoEnabledInConfig = swarmState.fullAutoEnabledInConfig;
|
|
43045
|
+
const preservedCuratorInitAgentNames = swarmState.curatorInitAgentNames;
|
|
43046
|
+
const preservedCuratorPhaseAgentNames = swarmState.curatorPhaseAgentNames;
|
|
43047
|
+
const preservedSkillImproverAgentNames = swarmState.skillImproverAgentNames;
|
|
43048
|
+
const preservedSpecWriterAgentNames = swarmState.specWriterAgentNames;
|
|
43049
|
+
const preservedGeneratedAgentNames = swarmState.generatedAgentNames;
|
|
43050
|
+
resetSwarmState();
|
|
43051
|
+
swarmState.opencodeClient = preservedOpencodeClient;
|
|
43052
|
+
swarmState.fullAutoEnabledInConfig = preservedFullAutoEnabledInConfig;
|
|
43053
|
+
swarmState.curatorInitAgentNames = preservedCuratorInitAgentNames;
|
|
43054
|
+
swarmState.curatorPhaseAgentNames = preservedCuratorPhaseAgentNames;
|
|
43055
|
+
swarmState.skillImproverAgentNames = preservedSkillImproverAgentNames;
|
|
43056
|
+
swarmState.specWriterAgentNames = preservedSpecWriterAgentNames;
|
|
43057
|
+
swarmState.generatedAgentNames = preservedGeneratedAgentNames;
|
|
43058
|
+
}
|
|
43041
43059
|
function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, directory) {
|
|
43042
43060
|
const now = Date.now();
|
|
43043
43061
|
const staleIds = [];
|
|
@@ -62745,6 +62763,7 @@ var init_write_retro = __esm(() => {
|
|
|
62745
62763
|
});
|
|
62746
62764
|
|
|
62747
62765
|
// src/commands/close.ts
|
|
62766
|
+
import * as fsSync3 from "node:fs";
|
|
62748
62767
|
import { promises as fs20 } from "node:fs";
|
|
62749
62768
|
import path35 from "node:path";
|
|
62750
62769
|
async function runAbortableSkillReview(req, timeoutMs) {
|
|
@@ -62780,6 +62799,28 @@ function countSessionKnowledgeEntries(entries, sessionStart, fallbackCount) {
|
|
|
62780
62799
|
return Number.isFinite(createdAtMs) && createdAtMs >= sessionStartMs;
|
|
62781
62800
|
}).length;
|
|
62782
62801
|
}
|
|
62802
|
+
async function copyDirRecursive(src, dest) {
|
|
62803
|
+
let count = 0;
|
|
62804
|
+
const entries = await fs20.readdir(src);
|
|
62805
|
+
await fs20.mkdir(dest, { recursive: true });
|
|
62806
|
+
for (const entry of entries) {
|
|
62807
|
+
const srcEntry = path35.join(src, entry);
|
|
62808
|
+
const destEntry = path35.join(dest, entry);
|
|
62809
|
+
try {
|
|
62810
|
+
const stat3 = await fs20.stat(srcEntry);
|
|
62811
|
+
if (stat3.isDirectory()) {
|
|
62812
|
+
const subCount = await copyDirRecursive(srcEntry, destEntry).catch(() => 0);
|
|
62813
|
+
count += subCount;
|
|
62814
|
+
} else {
|
|
62815
|
+
try {
|
|
62816
|
+
await fs20.copyFile(srcEntry, destEntry);
|
|
62817
|
+
count++;
|
|
62818
|
+
} catch {}
|
|
62819
|
+
}
|
|
62820
|
+
} catch {}
|
|
62821
|
+
}
|
|
62822
|
+
return count;
|
|
62823
|
+
}
|
|
62783
62824
|
function guaranteeAllPlansComplete(planData) {
|
|
62784
62825
|
const closedPhaseIds = [];
|
|
62785
62826
|
const closedTaskIds = [];
|
|
@@ -62801,8 +62842,18 @@ function guaranteeAllPlansComplete(planData) {
|
|
|
62801
62842
|
return { closedPhaseIds, closedTaskIds };
|
|
62802
62843
|
}
|
|
62803
62844
|
async function handleCloseCommand(directory, args2, options = {}) {
|
|
62804
|
-
const planPath = validateSwarmPath(directory, "plan.json");
|
|
62805
62845
|
const swarmDir = path35.join(directory, ".swarm");
|
|
62846
|
+
try {
|
|
62847
|
+
const stat3 = fsSync3.lstatSync(swarmDir);
|
|
62848
|
+
if (stat3.isSymbolicLink()) {
|
|
62849
|
+
return `❌ Refused: .swarm/ is a symlink or junction. Refusing to operate on a redirected directory for safety.`;
|
|
62850
|
+
}
|
|
62851
|
+
} catch (err2) {
|
|
62852
|
+
if (err2?.code !== "ENOENT") {
|
|
62853
|
+
throw err2;
|
|
62854
|
+
}
|
|
62855
|
+
}
|
|
62856
|
+
const planPath = validateSwarmPath(directory, "plan.json");
|
|
62806
62857
|
let planExists = false;
|
|
62807
62858
|
let planData = {
|
|
62808
62859
|
title: path35.basename(directory) || "Ad-hoc session",
|
|
@@ -63084,31 +63135,12 @@ async function handleCloseCommand(directory, args2, options = {}) {
|
|
|
63084
63135
|
const srcDir = path35.join(swarmDir, dirName);
|
|
63085
63136
|
const destDir = path35.join(archiveDir, dirName);
|
|
63086
63137
|
try {
|
|
63087
|
-
const
|
|
63088
|
-
|
|
63089
|
-
await fs20.mkdir(destDir, { recursive: true });
|
|
63090
|
-
for (const entry of entries) {
|
|
63091
|
-
const srcEntry = path35.join(srcDir, entry);
|
|
63092
|
-
const destEntry = path35.join(destDir, entry);
|
|
63093
|
-
try {
|
|
63094
|
-
const stat3 = await fs20.stat(srcEntry);
|
|
63095
|
-
if (stat3.isDirectory()) {
|
|
63096
|
-
await fs20.mkdir(destEntry, { recursive: true });
|
|
63097
|
-
const subEntries = await fs20.readdir(srcEntry);
|
|
63098
|
-
for (const sub of subEntries) {
|
|
63099
|
-
await fs20.copyFile(path35.join(srcEntry, sub), path35.join(destEntry, sub)).catch(() => {});
|
|
63100
|
-
}
|
|
63101
|
-
} else {
|
|
63102
|
-
await fs20.copyFile(srcEntry, destEntry);
|
|
63103
|
-
}
|
|
63104
|
-
archivedFileCount++;
|
|
63105
|
-
} catch {}
|
|
63106
|
-
}
|
|
63107
|
-
}
|
|
63138
|
+
const copied = await copyDirRecursive(srcDir, destDir);
|
|
63139
|
+
archivedFileCount += copied;
|
|
63108
63140
|
archivedActiveStateDirs.add(dirName);
|
|
63109
63141
|
} catch {}
|
|
63110
63142
|
}
|
|
63111
|
-
archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}/`;
|
|
63143
|
+
archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}-${suffix}/`;
|
|
63112
63144
|
} catch (archiveError) {
|
|
63113
63145
|
warnings.push(`Archive creation failed: ${archiveError instanceof Error ? archiveError.message : String(archiveError)}`);
|
|
63114
63146
|
archiveResult = "Archive creation failed (see warnings)";
|
|
@@ -63180,6 +63212,20 @@ async function handleCloseCommand(directory, args2, options = {}) {
|
|
|
63180
63212
|
}
|
|
63181
63213
|
}
|
|
63182
63214
|
}
|
|
63215
|
+
let tmpFilesRemoved = 0;
|
|
63216
|
+
try {
|
|
63217
|
+
const swarmFiles = await fs20.readdir(swarmDir);
|
|
63218
|
+
const tmpFiles = swarmFiles.filter((f) => f.startsWith(".tmp."));
|
|
63219
|
+
for (const tmp of tmpFiles) {
|
|
63220
|
+
try {
|
|
63221
|
+
await fs20.unlink(path35.join(swarmDir, tmp));
|
|
63222
|
+
tmpFilesRemoved++;
|
|
63223
|
+
} catch {}
|
|
63224
|
+
}
|
|
63225
|
+
} catch {}
|
|
63226
|
+
if (tmpFilesRemoved > 0) {
|
|
63227
|
+
cleanedFiles.push(`${tmpFilesRemoved} .tmp.* file(s)`);
|
|
63228
|
+
}
|
|
63183
63229
|
clearAllScopes(directory);
|
|
63184
63230
|
const contextPath = path35.join(swarmDir, "context.md");
|
|
63185
63231
|
const contextContent = [
|
|
@@ -63286,17 +63332,7 @@ async function handleCloseCommand(directory, args2, options = {}) {
|
|
|
63286
63332
|
warnings.push(`Failed to write close-summary.md: ${msg}`);
|
|
63287
63333
|
console.warn("[close-command] Failed to write close-summary.md:", error93);
|
|
63288
63334
|
}
|
|
63289
|
-
|
|
63290
|
-
const preservedFullAutoFlag = swarmState.fullAutoEnabledInConfig;
|
|
63291
|
-
const preservedCuratorInitNames = swarmState.curatorInitAgentNames;
|
|
63292
|
-
const preservedCuratorPhaseNames = swarmState.curatorPhaseAgentNames;
|
|
63293
|
-
const preservedSkillImproverAgentNames = swarmState.skillImproverAgentNames;
|
|
63294
|
-
resetSwarmState();
|
|
63295
|
-
swarmState.opencodeClient = preservedClient;
|
|
63296
|
-
swarmState.fullAutoEnabledInConfig = preservedFullAutoFlag;
|
|
63297
|
-
swarmState.curatorInitAgentNames = preservedCuratorInitNames;
|
|
63298
|
-
swarmState.curatorPhaseAgentNames = preservedCuratorPhaseNames;
|
|
63299
|
-
swarmState.skillImproverAgentNames = preservedSkillImproverAgentNames;
|
|
63335
|
+
resetSwarmStatePreservingSingletons();
|
|
63300
63336
|
const retroWarnings = warnings.filter((w) => w.includes("Retrospective write") || w.includes("retrospective write") || w.includes("Session retrospective"));
|
|
63301
63337
|
const otherWarnings = warnings.filter((w) => !w.includes("Retrospective write") && !w.includes("retrospective write") && !w.includes("Session retrospective"));
|
|
63302
63338
|
let warningMsg = "";
|
|
@@ -82911,14 +82947,14 @@ var init_context_budget_service = __esm(() => {
|
|
|
82911
82947
|
});
|
|
82912
82948
|
|
|
82913
82949
|
// src/services/status-service.ts
|
|
82914
|
-
import * as
|
|
82950
|
+
import * as fsSync4 from "node:fs";
|
|
82915
82951
|
import * as path73 from "node:path";
|
|
82916
82952
|
function readSpecStalenessSnapshot(directory) {
|
|
82917
82953
|
try {
|
|
82918
82954
|
const p = path73.join(directory, ".swarm", "spec-staleness.json");
|
|
82919
|
-
if (!
|
|
82955
|
+
if (!fsSync4.existsSync(p))
|
|
82920
82956
|
return { stale: false };
|
|
82921
|
-
const raw =
|
|
82957
|
+
const raw = fsSync4.readFileSync(p, "utf-8");
|
|
82922
82958
|
const parsed = JSON.parse(raw);
|
|
82923
82959
|
return {
|
|
82924
82960
|
stale: true,
|
|
@@ -98885,7 +98921,7 @@ import * as path97 from "node:path";
|
|
|
98885
98921
|
// src/tools/repo-graph/builder.ts
|
|
98886
98922
|
init_logger();
|
|
98887
98923
|
init_path_security();
|
|
98888
|
-
import * as
|
|
98924
|
+
import * as fsSync5 from "node:fs";
|
|
98889
98925
|
import { existsSync as existsSync56, realpathSync as realpathSync12 } from "node:fs";
|
|
98890
98926
|
import * as fsPromises5 from "node:fs/promises";
|
|
98891
98927
|
import * as os14 from "node:os";
|
|
@@ -99891,11 +99927,11 @@ function scanFile(filePath, absoluteRoot, maxFileSize) {
|
|
|
99891
99927
|
let content;
|
|
99892
99928
|
let fileStats;
|
|
99893
99929
|
try {
|
|
99894
|
-
fileStats =
|
|
99930
|
+
fileStats = fsSync5.statSync(filePath);
|
|
99895
99931
|
if (fileStats.size > maxFileSize) {
|
|
99896
99932
|
return { node: null, edges: [] };
|
|
99897
99933
|
}
|
|
99898
|
-
content =
|
|
99934
|
+
content = fsSync5.readFileSync(filePath, "utf-8");
|
|
99899
99935
|
} catch {
|
|
99900
99936
|
return { node: null, edges: [] };
|
|
99901
99937
|
}
|
package/dist/state.d.ts
CHANGED
|
@@ -334,6 +334,23 @@ export declare const swarmState: {
|
|
|
334
334
|
* Reset all state to initial values - useful for testing
|
|
335
335
|
*/
|
|
336
336
|
export declare function resetSwarmState(): void;
|
|
337
|
+
/**
|
|
338
|
+
* Reset swarm state while preserving the 7 module-scoped singletons that are
|
|
339
|
+
* populated once at plugin init and must survive a /swarm close + re-init
|
|
340
|
+
* within the same process lifetime.
|
|
341
|
+
*
|
|
342
|
+
* The preserved fields are:
|
|
343
|
+
* - opencodeClient (SDK client for curator/full-auto delegation)
|
|
344
|
+
* - fullAutoEnabledInConfig (config flag read at init)
|
|
345
|
+
* - curatorInitAgentNames, curatorPhaseAgentNames (curator registry)
|
|
346
|
+
* - skillImproverAgentNames, specWriterAgentNames (skill/spec registry)
|
|
347
|
+
* - generatedAgentNames (full-auto delegation guard registry)
|
|
348
|
+
*
|
|
349
|
+
* Implementation: save all 7 to locals, call resetSwarmState(), restore all 7.
|
|
350
|
+
* Synchronous (matches resetSwarmState contract). Errors from resetSwarmState
|
|
351
|
+
* propagate to caller (no try/catch wrapper).
|
|
352
|
+
*/
|
|
353
|
+
export declare function resetSwarmStatePreservingSingletons(): void;
|
|
337
354
|
/**
|
|
338
355
|
* Start a new agent session with initialized guardrail state.
|
|
339
356
|
* Also removes any stale sessions older than staleDurationMs.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.62.
|
|
3
|
+
"version": "7.62.1",
|
|
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",
|