opencode-swarm 7.98.0 → 7.98.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{evidence-summary-service-g4x5e3e3.js → evidence-summary-service-559nas1m.js} +2 -2
- package/dist/cli/{guardrail-explain-xdv74tfk.js → guardrail-explain-xktjjh53.js} +5 -5
- package/dist/cli/{index-pc10e4d7.js → index-72k57f21.js} +72 -65
- package/dist/cli/{index-sf08zj91.js → index-a0dv2c7k.js} +1 -1
- package/dist/cli/{index-h6h8qfsh.js → index-chan9mkv.js} +5 -5
- package/dist/cli/{index-wmm21nsk.js → index-rvweaxsd.js} +1 -1
- package/dist/cli/{index-gn8n22th.js → index-we94wkty.js} +19 -3
- package/dist/cli/{index-4c5jpmn9.js → index-yrzfbqqh.js} +8 -8
- package/dist/cli/index.js +4 -4
- package/dist/cli/{pending-delegations-shqbvfjc.js → pending-delegations-8b2js1vq.js} +1 -1
- package/dist/cli/{pr-subscriptions-2565fpsc.js → pr-subscriptions-ttvr1ta9.js} +2 -2
- package/dist/commands/close.d.ts +2 -1
- package/dist/hooks/knowledge-curator.d.ts +1 -0
- package/dist/hooks/system-enhancer.d.ts +1 -1
- package/dist/hooks/utils.d.ts +3 -1
- package/dist/index.js +229 -95
- package/dist/plan/manager.d.ts +1 -1
- package/dist/services/external-skill-validator.d.ts +10 -2
- package/dist/state.d.ts +3 -3
- package/package.json +1 -1
package/dist/cli/{evidence-summary-service-g4x5e3e3.js → evidence-summary-service-559nas1m.js}
RENAMED
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
loadPlanJsonOnly,
|
|
7
7
|
mergeDurableGateEntriesFromEvidence,
|
|
8
8
|
readDurableGateEvidence
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-yrzfbqqh.js";
|
|
10
10
|
import"./index-mh1ej70w.js";
|
|
11
11
|
import"./index-kv4dd5c5.js";
|
|
12
|
-
import"./index-
|
|
12
|
+
import"./index-we94wkty.js";
|
|
13
13
|
import"./index-jtqkh8jf.js";
|
|
14
14
|
import"./index-5e4e2hvv.js";
|
|
15
15
|
import"./index-p0arc26j.js";
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
handleGuardrailExplain
|
|
4
|
-
} from "./index-
|
|
5
|
-
import"./index-
|
|
4
|
+
} from "./index-rvweaxsd.js";
|
|
5
|
+
import"./index-72k57f21.js";
|
|
6
6
|
import"./index-5z2e78tv.js";
|
|
7
7
|
import"./index-2a6ppa65.js";
|
|
8
8
|
import"./index-fjxjb66n.js";
|
|
9
9
|
import"./index-hb10a2g8.js";
|
|
10
10
|
import"./index-zy22fg5h.js";
|
|
11
11
|
import"./index-471qxz9g.js";
|
|
12
|
-
import"./index-
|
|
12
|
+
import"./index-yrzfbqqh.js";
|
|
13
13
|
import"./index-adz3nk9b.js";
|
|
14
14
|
import"./index-v4fcn4tr.js";
|
|
15
15
|
import"./index-mh1ej70w.js";
|
|
16
16
|
import"./index-kv4dd5c5.js";
|
|
17
|
-
import"./index-
|
|
18
|
-
import"./index-
|
|
17
|
+
import"./index-a0dv2c7k.js";
|
|
18
|
+
import"./index-we94wkty.js";
|
|
19
19
|
import"./index-jtqkh8jf.js";
|
|
20
20
|
import"./index-5e4e2hvv.js";
|
|
21
21
|
import"./index-p0arc26j.js";
|
|
@@ -114,7 +114,7 @@ import {
|
|
|
114
114
|
transientBackoff,
|
|
115
115
|
validateProjectRoot,
|
|
116
116
|
writeProjectedSpecSync
|
|
117
|
-
} from "./index-
|
|
117
|
+
} from "./index-yrzfbqqh.js";
|
|
118
118
|
import {
|
|
119
119
|
_internals as _internals2,
|
|
120
120
|
_internals1 as _internals3,
|
|
@@ -138,12 +138,12 @@ import {
|
|
|
138
138
|
listActive,
|
|
139
139
|
subscribe,
|
|
140
140
|
unsubscribe
|
|
141
|
-
} from "./index-
|
|
141
|
+
} from "./index-a0dv2c7k.js";
|
|
142
142
|
import {
|
|
143
143
|
readSwarmFileAsync,
|
|
144
144
|
safeHook,
|
|
145
145
|
validateSwarmPath
|
|
146
|
-
} from "./index-
|
|
146
|
+
} from "./index-we94wkty.js";
|
|
147
147
|
import {
|
|
148
148
|
deepMerge
|
|
149
149
|
} from "./index-p0arc26j.js";
|
|
@@ -909,7 +909,7 @@ var init_executor = __esm(() => {
|
|
|
909
909
|
// package.json
|
|
910
910
|
var package_default = {
|
|
911
911
|
name: "opencode-swarm",
|
|
912
|
-
version: "7.98.
|
|
912
|
+
version: "7.98.2",
|
|
913
913
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
914
914
|
main: "dist/index.js",
|
|
915
915
|
types: "dist/index.d.ts",
|
|
@@ -5474,6 +5474,9 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, dire
|
|
|
5474
5474
|
swarmState.pendingRehydrations.add(rehydrationPromise);
|
|
5475
5475
|
}
|
|
5476
5476
|
}
|
|
5477
|
+
function endAgentSession(sessionId) {
|
|
5478
|
+
swarmState.agentSessions.delete(sessionId);
|
|
5479
|
+
}
|
|
5477
5480
|
function getAgentSession(sessionId) {
|
|
5478
5481
|
return swarmState.agentSessions.get(sessionId);
|
|
5479
5482
|
}
|
|
@@ -5978,7 +5981,7 @@ function hasActiveEpicMode(sessionID) {
|
|
|
5978
5981
|
async function rehydratePrSubscriptions(sessionID, directory) {
|
|
5979
5982
|
const map = new Map;
|
|
5980
5983
|
try {
|
|
5981
|
-
const { listActive: listActive2 } = await import("./pr-subscriptions-
|
|
5984
|
+
const { listActive: listActive2 } = await import("./pr-subscriptions-ttvr1ta9.js");
|
|
5982
5985
|
const records = await listActive2(directory);
|
|
5983
5986
|
for (const record of records) {
|
|
5984
5987
|
if (record.sessionID !== sessionID)
|
|
@@ -10193,48 +10196,49 @@ function recordSeenRetroSection(key, value, timestamp) {
|
|
|
10193
10196
|
function hashContent(content) {
|
|
10194
10197
|
return createHash3("sha1").update(content).digest("hex");
|
|
10195
10198
|
}
|
|
10196
|
-
function isWriteToSwarmPlan(input) {
|
|
10197
|
-
if (typeof input !== "object" || input === null)
|
|
10198
|
-
return false;
|
|
10199
|
-
const record = input;
|
|
10200
|
-
const toolName = record.toolName;
|
|
10201
|
-
if (typeof toolName !== "string")
|
|
10202
|
-
return false;
|
|
10203
|
-
if (!["write", "edit", "apply_patch", "swarm_apply_patch"].includes(toolName))
|
|
10204
|
-
return false;
|
|
10205
|
-
const rawPath = record.path;
|
|
10206
|
-
const rawFile = record.file;
|
|
10207
|
-
const pathField = typeof rawPath === "string" ? rawPath.replace(/\\/g, "/") : undefined;
|
|
10208
|
-
const fileField = typeof rawFile === "string" ? rawFile.replace(/\\/g, "/") : undefined;
|
|
10209
|
-
if (typeof pathField === "string" && pathField.includes(".swarm/plan.md")) {
|
|
10210
|
-
return true;
|
|
10211
|
-
}
|
|
10212
|
-
if (typeof fileField === "string" && fileField.includes(".swarm/plan.md")) {
|
|
10213
|
-
return true;
|
|
10214
|
-
}
|
|
10215
|
-
return false;
|
|
10216
|
-
}
|
|
10217
10199
|
function isWriteToEvidenceFile(input) {
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10200
|
+
const trigger = normalizeWriteTrigger(input);
|
|
10201
|
+
return isEvidencePath(trigger?.filePath);
|
|
10202
|
+
}
|
|
10203
|
+
var WRITE_TOOLS = new Set([
|
|
10204
|
+
"write",
|
|
10205
|
+
"edit",
|
|
10206
|
+
"apply_patch",
|
|
10207
|
+
"swarm_apply_patch"
|
|
10208
|
+
]);
|
|
10209
|
+
function isRecord(value) {
|
|
10210
|
+
return typeof value === "object" && value !== null;
|
|
10211
|
+
}
|
|
10212
|
+
function normalizePathField(value) {
|
|
10213
|
+
return typeof value === "string" ? value.replace(/\\/g, "/") : null;
|
|
10214
|
+
}
|
|
10215
|
+
function firstPathFromRecord(record) {
|
|
10216
|
+
return normalizePathField(record.path) ?? normalizePathField(record.filePath) ?? normalizePathField(record.file);
|
|
10217
|
+
}
|
|
10218
|
+
function normalizeWriteTrigger(input, output) {
|
|
10219
|
+
if (!isRecord(input))
|
|
10220
|
+
return null;
|
|
10221
|
+
const toolName = typeof input.toolName === "string" ? input.toolName : typeof input.tool === "string" ? input.tool : null;
|
|
10222
|
+
if (!toolName || !WRITE_TOOLS.has(toolName))
|
|
10223
|
+
return null;
|
|
10224
|
+
const inputArgs = isRecord(input.args) ? input.args : null;
|
|
10225
|
+
const outputArgs = isRecord(output) && isRecord(output.args) ? output.args : null;
|
|
10226
|
+
const filePath = firstPathFromRecord(input) ?? (inputArgs ? firstPathFromRecord(inputArgs) : null) ?? (outputArgs ? firstPathFromRecord(outputArgs) : null);
|
|
10227
|
+
if (!filePath)
|
|
10228
|
+
return null;
|
|
10229
|
+
return {
|
|
10230
|
+
toolName,
|
|
10231
|
+
filePath,
|
|
10232
|
+
sessionID: typeof input.sessionID === "string" ? input.sessionID : "default"
|
|
10233
|
+
};
|
|
10234
|
+
}
|
|
10235
|
+
function isEvidencePath(filePath) {
|
|
10236
|
+
if (!filePath)
|
|
10225
10237
|
return false;
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
const evidenceRegex = /\.swarm\/+evidence\/+/i;
|
|
10231
|
-
if (typeof pathField === "string" && evidenceRegex.test(pathField)) {
|
|
10232
|
-
return true;
|
|
10233
|
-
}
|
|
10234
|
-
if (typeof fileField === "string" && evidenceRegex.test(fileField)) {
|
|
10235
|
-
return true;
|
|
10236
|
-
}
|
|
10237
|
-
return false;
|
|
10238
|
+
return /(?:^|\/)\.swarm\/+evidence\//i.test(filePath);
|
|
10239
|
+
}
|
|
10240
|
+
function isPlanPath(filePath) {
|
|
10241
|
+
return filePath?.includes(".swarm/plan.md") ?? false;
|
|
10238
10242
|
}
|
|
10239
10243
|
function extractRetrospectiveSection(planContent) {
|
|
10240
10244
|
const headingRegex = /^###\s+Lessons\s+Learned$/m;
|
|
@@ -10941,24 +10945,22 @@ async function runAutoPromotion(directory, config) {
|
|
|
10941
10945
|
}
|
|
10942
10946
|
}
|
|
10943
10947
|
function createKnowledgeCuratorHook(directory, config, options = {}) {
|
|
10944
|
-
const handler = async (input,
|
|
10948
|
+
const handler = async (input, output) => {
|
|
10945
10949
|
pruneSeenRetroSections();
|
|
10946
10950
|
if (!config.enabled)
|
|
10947
10951
|
return;
|
|
10948
|
-
|
|
10952
|
+
const trigger = normalizeWriteTrigger(input, output);
|
|
10953
|
+
if (!trigger)
|
|
10954
|
+
return;
|
|
10955
|
+
const isPlanTrigger = isPlanPath(trigger.filePath);
|
|
10956
|
+
const isEvidenceTrigger = isEvidencePath(trigger.filePath) && !isPlanTrigger;
|
|
10957
|
+
if (!isPlanTrigger && !isEvidenceTrigger)
|
|
10949
10958
|
return;
|
|
10950
|
-
const sessionID = input?.sessionID ?? "default";
|
|
10951
|
-
const isEvidenceTrigger = isWriteToEvidenceFile(input) && !isWriteToSwarmPlan(input);
|
|
10952
10959
|
if (isEvidenceTrigger) {
|
|
10953
|
-
const
|
|
10954
|
-
const
|
|
10955
|
-
const rawFile = record.file;
|
|
10956
|
-
const filePath = typeof rawPath === "string" ? rawPath.replace(/\\/g, "/") : typeof rawFile === "string" ? rawFile.replace(/\\/g, "/") : null;
|
|
10957
|
-
if (!filePath)
|
|
10958
|
-
return;
|
|
10959
|
-
const evidenceKey = `evidence:${sessionID}:${filePath}`;
|
|
10960
|
+
const relativeEvidencePath = trigger.filePath.replace(/^.*\.swarm\//, "");
|
|
10961
|
+
const evidenceKey = `evidence:${trigger.sessionID}:${relativeEvidencePath}`;
|
|
10960
10962
|
const lastSeenEvidence = seenRetroSections.get(evidenceKey);
|
|
10961
|
-
const evidenceContent = await readSwarmFileAsync(directory,
|
|
10963
|
+
const evidenceContent = await readSwarmFileAsync(directory, relativeEvidencePath);
|
|
10962
10964
|
if (!evidenceContent)
|
|
10963
10965
|
return;
|
|
10964
10966
|
let evidenceData;
|
|
@@ -10986,7 +10988,7 @@ function createKnowledgeCuratorHook(directory, config, options = {}) {
|
|
|
10986
10988
|
const projectName2 = evidenceData.project_name ?? "unknown";
|
|
10987
10989
|
const phaseNumber2 = typeof evidenceData.phase_number === "number" ? evidenceData.phase_number : 1;
|
|
10988
10990
|
await _internals17.curateAndStoreSwarm(lessons, projectName2, { phase_number: phaseNumber2 }, directory, config, {
|
|
10989
|
-
llmDelegate: options.llmDelegateFactory?.(sessionID),
|
|
10991
|
+
llmDelegate: options.llmDelegateFactory?.(trigger.sessionID),
|
|
10990
10992
|
enrichmentQuota: options.enrichmentQuota
|
|
10991
10993
|
});
|
|
10992
10994
|
return;
|
|
@@ -10997,7 +10999,7 @@ function createKnowledgeCuratorHook(directory, config, options = {}) {
|
|
|
10997
10999
|
const section = extractRetrospectiveSection(planContent);
|
|
10998
11000
|
if (!section)
|
|
10999
11001
|
return;
|
|
11000
|
-
if (!checkRetroChanged(sessionID, section))
|
|
11002
|
+
if (!checkRetroChanged(trigger.sessionID, section))
|
|
11001
11003
|
return;
|
|
11002
11004
|
const allLessons = extractLessonsFromRetro(section);
|
|
11003
11005
|
if (allLessons.length === 0)
|
|
@@ -11011,7 +11013,7 @@ function createKnowledgeCuratorHook(directory, config, options = {}) {
|
|
|
11011
11013
|
const phaseMatch = /^Phase:\s*(\d+)/m.exec(planContent);
|
|
11012
11014
|
const phaseNumber = phaseMatch ? parseInt(phaseMatch[1], 10) : 1;
|
|
11013
11015
|
await _internals17.curateAndStoreSwarm(normalLessons, projectName, { phase_number: phaseNumber }, directory, config, {
|
|
11014
|
-
llmDelegate: options.llmDelegateFactory?.(sessionID),
|
|
11016
|
+
llmDelegate: options.llmDelegateFactory?.(trigger.sessionID),
|
|
11015
11017
|
enrichmentQuota: options.enrichmentQuota
|
|
11016
11018
|
});
|
|
11017
11019
|
};
|
|
@@ -13653,6 +13655,10 @@ This project was already finalized in a previous /swarm close run. The plan has
|
|
|
13653
13655
|
ctx.warnings.push(`Failed to write close-summary.md: ${msg}`);
|
|
13654
13656
|
console.warn("[close-command] Failed to write close-summary.md:", error2);
|
|
13655
13657
|
}
|
|
13658
|
+
const sessionIdsToEnd = [...swarmState.agentSessions.keys()];
|
|
13659
|
+
for (const sessionId of sessionIdsToEnd) {
|
|
13660
|
+
_internals20.endAgentSession(sessionId);
|
|
13661
|
+
}
|
|
13656
13662
|
_internals20.resetSwarmStatePreservingSingletons();
|
|
13657
13663
|
const retroWarnings = ctx.warnings.filter((w) => w.includes("Retrospective write") || w.includes("retrospective write") || w.includes("Session retrospective"));
|
|
13658
13664
|
const otherWarnings = ctx.warnings.filter((w) => !w.includes("Retrospective write") && !w.includes("retrospective write") && !w.includes("Session retrospective"));
|
|
@@ -13745,7 +13751,8 @@ var _internals20 = {
|
|
|
13745
13751
|
runCleanStage,
|
|
13746
13752
|
runAlignStage,
|
|
13747
13753
|
archiveEvidence,
|
|
13748
|
-
closePlanTerminalState
|
|
13754
|
+
closePlanTerminalState,
|
|
13755
|
+
endAgentSession
|
|
13749
13756
|
};
|
|
13750
13757
|
|
|
13751
13758
|
// src/commands/codebase-review.ts
|
|
@@ -17606,7 +17613,7 @@ async function handleEvidenceCommand(directory, args) {
|
|
|
17606
17613
|
return formatTaskEvidenceMarkdown(evidenceData);
|
|
17607
17614
|
}
|
|
17608
17615
|
async function handleEvidenceSummaryCommand(directory) {
|
|
17609
|
-
const { buildEvidenceSummary } = await import("./evidence-summary-service-
|
|
17616
|
+
const { buildEvidenceSummary } = await import("./evidence-summary-service-559nas1m.js");
|
|
17610
17617
|
const artifact = await buildEvidenceSummary(directory);
|
|
17611
17618
|
if (!artifact) {
|
|
17612
17619
|
return "No plan found. Run `/swarm plan` to check plan status.";
|
|
@@ -31857,7 +31864,7 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
31857
31864
|
async function handleHelpCommand(ctx) {
|
|
31858
31865
|
const targetCommand = ctx.args.join(" ");
|
|
31859
31866
|
if (!targetCommand) {
|
|
31860
|
-
const { buildHelpText } = await import("./index-
|
|
31867
|
+
const { buildHelpText } = await import("./index-chan9mkv.js");
|
|
31861
31868
|
return buildHelpText();
|
|
31862
31869
|
}
|
|
31863
31870
|
const tokens = targetCommand.split(/\s+/);
|
|
@@ -31866,7 +31873,7 @@ async function handleHelpCommand(ctx) {
|
|
|
31866
31873
|
return _internals45.buildDetailedHelp(resolved.key, resolved.entry);
|
|
31867
31874
|
}
|
|
31868
31875
|
const similar = _internals45.findSimilarCommands(targetCommand);
|
|
31869
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
31876
|
+
const { buildHelpText: fullHelp } = await import("./index-chan9mkv.js");
|
|
31870
31877
|
if (similar.length > 0) {
|
|
31871
31878
|
return `Command '/swarm ${targetCommand}' not found.
|
|
31872
31879
|
|
|
@@ -31999,7 +32006,7 @@ var COMMAND_REGISTRY = {
|
|
|
31999
32006
|
},
|
|
32000
32007
|
"guardrail explain": {
|
|
32001
32008
|
handler: async (ctx) => {
|
|
32002
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
32009
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-xktjjh53.js");
|
|
32003
32010
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
32004
32011
|
},
|
|
32005
32012
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
handleGuardrailExplain
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-rvweaxsd.js";
|
|
5
5
|
import {
|
|
6
6
|
handleGuardrailLog
|
|
7
7
|
} from "./index-gnd1280x.js";
|
|
@@ -78,7 +78,7 @@ import {
|
|
|
78
78
|
handleWriteRetroCommand,
|
|
79
79
|
normalizeSwarmCommandInput,
|
|
80
80
|
resolveCommand
|
|
81
|
-
} from "./index-
|
|
81
|
+
} from "./index-72k57f21.js";
|
|
82
82
|
import"./index-5z2e78tv.js";
|
|
83
83
|
import"./index-2a6ppa65.js";
|
|
84
84
|
import"./index-fjxjb66n.js";
|
|
@@ -89,13 +89,13 @@ import {
|
|
|
89
89
|
ORCHESTRATOR_NAME,
|
|
90
90
|
stripKnownSwarmPrefix
|
|
91
91
|
} from "./index-471qxz9g.js";
|
|
92
|
-
import"./index-
|
|
92
|
+
import"./index-yrzfbqqh.js";
|
|
93
93
|
import"./index-adz3nk9b.js";
|
|
94
94
|
import"./index-v4fcn4tr.js";
|
|
95
95
|
import"./index-mh1ej70w.js";
|
|
96
96
|
import"./index-kv4dd5c5.js";
|
|
97
|
-
import"./index-
|
|
98
|
-
import"./index-
|
|
97
|
+
import"./index-a0dv2c7k.js";
|
|
98
|
+
import"./index-we94wkty.js";
|
|
99
99
|
import"./index-jtqkh8jf.js";
|
|
100
100
|
import"./index-5e4e2hvv.js";
|
|
101
101
|
import"./index-p0arc26j.js";
|
|
@@ -14,7 +14,13 @@ import {
|
|
|
14
14
|
|
|
15
15
|
// src/hooks/utils.ts
|
|
16
16
|
import * as path from "path";
|
|
17
|
-
var _internals = {
|
|
17
|
+
var _internals = {
|
|
18
|
+
safeHook,
|
|
19
|
+
composeHandlers,
|
|
20
|
+
validateSwarmPath,
|
|
21
|
+
readSwarmFileAsync,
|
|
22
|
+
readCachedTextFile
|
|
23
|
+
};
|
|
18
24
|
function safeHook(fn) {
|
|
19
25
|
return async (input, output) => {
|
|
20
26
|
try {
|
|
@@ -67,13 +73,23 @@ function validateSwarmPath(directory, filename) {
|
|
|
67
73
|
}
|
|
68
74
|
return resolved;
|
|
69
75
|
}
|
|
70
|
-
async function readSwarmFileAsync(directory, filename) {
|
|
76
|
+
async function readSwarmFileAsync(directory, filename, cache) {
|
|
77
|
+
if (cache !== undefined) {
|
|
78
|
+
const key = `${directory}::${filename}`;
|
|
79
|
+
const cached = cache.get(key);
|
|
80
|
+
if (cached !== undefined) {
|
|
81
|
+
return cached;
|
|
82
|
+
}
|
|
83
|
+
const promise = readSwarmFileAsync(directory, filename);
|
|
84
|
+
cache.set(key, promise);
|
|
85
|
+
return promise;
|
|
86
|
+
}
|
|
71
87
|
const maxAttempts = 5;
|
|
72
88
|
const retryDelayMs = 10;
|
|
73
89
|
for (let attempt = 0;attempt < maxAttempts; attempt++) {
|
|
74
90
|
try {
|
|
75
91
|
const resolvedPath = _internals.validateSwarmPath(directory, filename);
|
|
76
|
-
return await readCachedTextFile(resolvedPath, async () => {
|
|
92
|
+
return await _internals.readCachedTextFile(resolvedPath, async () => {
|
|
77
93
|
const file = bunFile(resolvedPath);
|
|
78
94
|
return await file.text();
|
|
79
95
|
});
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
readSwarmFileAsync,
|
|
10
10
|
validateSwarmPath
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-we94wkty.js";
|
|
12
12
|
import {
|
|
13
13
|
readCachedParsedFile
|
|
14
14
|
} from "./index-jtqkh8jf.js";
|
|
@@ -2162,8 +2162,8 @@ function extractPlanHashFromMarkdown(markdown) {
|
|
|
2162
2162
|
const match = markdown.match(/<!--\s*PLAN_HASH:\s*(\S+)\s*-->/);
|
|
2163
2163
|
return match ? match[1] : null;
|
|
2164
2164
|
}
|
|
2165
|
-
async function isPlanMdInSync(directory, plan) {
|
|
2166
|
-
const planMdContent = await readSwarmFileAsync(directory, "plan.md");
|
|
2165
|
+
async function isPlanMdInSync(directory, plan, cache) {
|
|
2166
|
+
const planMdContent = await readSwarmFileAsync(directory, "plan.md", cache);
|
|
2167
2167
|
if (planMdContent === null) {
|
|
2168
2168
|
return false;
|
|
2169
2169
|
}
|
|
@@ -2197,8 +2197,8 @@ ${markdown}`;
|
|
|
2197
2197
|
} catch {}
|
|
2198
2198
|
}
|
|
2199
2199
|
}
|
|
2200
|
-
async function loadPlan(directory) {
|
|
2201
|
-
const planJsonContent = await readSwarmFileAsync(directory, "plan.json");
|
|
2200
|
+
async function loadPlan(directory, cache) {
|
|
2201
|
+
const planJsonContent = await readSwarmFileAsync(directory, "plan.json", cache);
|
|
2202
2202
|
if (planJsonContent !== null) {
|
|
2203
2203
|
if (planJsonContent.includes("\x00") || planJsonContent.includes("\uFFFD")) {
|
|
2204
2204
|
warn("Plan rejected: .swarm/plan.json contains null bytes or invalid encoding");
|
|
@@ -2208,7 +2208,7 @@ async function loadPlan(directory) {
|
|
|
2208
2208
|
if (validated === null) {
|
|
2209
2209
|
warn("[loadPlan] plan.json disappeared during cached parse. Falling back to plan.md migration or ledger recovery.");
|
|
2210
2210
|
} else {
|
|
2211
|
-
const inSync = await isPlanMdInSync(directory, validated);
|
|
2211
|
+
const inSync = await isPlanMdInSync(directory, validated, cache);
|
|
2212
2212
|
if (!inSync) {
|
|
2213
2213
|
try {
|
|
2214
2214
|
await _internals4.regeneratePlanMarkdown(directory, validated);
|
|
@@ -2331,7 +2331,7 @@ async function loadPlan(directory) {
|
|
|
2331
2331
|
}
|
|
2332
2332
|
}
|
|
2333
2333
|
}
|
|
2334
|
-
const planMdContent2 = await readSwarmFileAsync(directory, "plan.md");
|
|
2334
|
+
const planMdContent2 = await readSwarmFileAsync(directory, "plan.md", cache);
|
|
2335
2335
|
if (planMdContent2 !== null) {
|
|
2336
2336
|
const migrated = migrateLegacyPlan(planMdContent2);
|
|
2337
2337
|
const { removedCount } = await savePlanWithAutoAcknowledgedRemovals(directory, migrated, "load_plan_migration_from_md", "migrate legacy plan.md to plan.json");
|
|
@@ -2346,7 +2346,7 @@ async function loadPlan(directory) {
|
|
|
2346
2346
|
}
|
|
2347
2347
|
}
|
|
2348
2348
|
}
|
|
2349
|
-
const planMdContent = await readSwarmFileAsync(directory, "plan.md");
|
|
2349
|
+
const planMdContent = await readSwarmFileAsync(directory, "plan.md", cache);
|
|
2350
2350
|
if (planMdContent !== null) {
|
|
2351
2351
|
const migrated = migrateLegacyPlan(planMdContent);
|
|
2352
2352
|
await savePlan(directory, migrated);
|
package/dist/cli/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getPluginLockFilePaths,
|
|
8
8
|
package_default,
|
|
9
9
|
resolveCommand
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-72k57f21.js";
|
|
11
11
|
import"./index-5z2e78tv.js";
|
|
12
12
|
import"./index-2a6ppa65.js";
|
|
13
13
|
import"./index-fjxjb66n.js";
|
|
@@ -16,13 +16,13 @@ import"./index-zy22fg5h.js";
|
|
|
16
16
|
import {
|
|
17
17
|
DEFAULT_AGENT_CONFIGS
|
|
18
18
|
} from "./index-471qxz9g.js";
|
|
19
|
-
import"./index-
|
|
19
|
+
import"./index-yrzfbqqh.js";
|
|
20
20
|
import"./index-adz3nk9b.js";
|
|
21
21
|
import"./index-v4fcn4tr.js";
|
|
22
22
|
import"./index-mh1ej70w.js";
|
|
23
23
|
import"./index-kv4dd5c5.js";
|
|
24
|
-
import"./index-
|
|
25
|
-
import"./index-
|
|
24
|
+
import"./index-a0dv2c7k.js";
|
|
25
|
+
import"./index-we94wkty.js";
|
|
26
26
|
import"./index-jtqkh8jf.js";
|
|
27
27
|
import"./index-5e4e2hvv.js";
|
|
28
28
|
import"./index-p0arc26j.js";
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
sweepStale,
|
|
10
10
|
unsubscribe,
|
|
11
11
|
updateSnapshot
|
|
12
|
-
} from "./index-
|
|
13
|
-
import"./index-
|
|
12
|
+
} from "./index-a0dv2c7k.js";
|
|
13
|
+
import"./index-we94wkty.js";
|
|
14
14
|
import"./index-jtqkh8jf.js";
|
|
15
15
|
import"./index-5e4e2hvv.js";
|
|
16
16
|
import"./index-p0arc26j.js";
|
package/dist/commands/close.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { checkHivePromotions } from '../hooks/hive-promoter';
|
|
|
8
8
|
import { curateAndStoreSwarm } from '../hooks/knowledge-curator';
|
|
9
9
|
import { closePlanTerminalState } from '../plan/manager';
|
|
10
10
|
import { type SessionReflectionResult } from '../services/session-reflection';
|
|
11
|
-
import { resetSwarmStatePreservingSingletons } from '../state';
|
|
11
|
+
import { endAgentSession, resetSwarmStatePreservingSingletons } from '../state';
|
|
12
12
|
interface PlanPhase {
|
|
13
13
|
id: number;
|
|
14
14
|
name: string;
|
|
@@ -197,5 +197,6 @@ export declare const _internals: {
|
|
|
197
197
|
runAlignStage: typeof runAlignStage;
|
|
198
198
|
archiveEvidence: typeof archiveEvidence;
|
|
199
199
|
closePlanTerminalState: typeof closePlanTerminalState;
|
|
200
|
+
endAgentSession: typeof endAgentSession;
|
|
200
201
|
};
|
|
201
202
|
export {};
|
|
@@ -21,6 +21,7 @@ declare function hashContent(content: string): string;
|
|
|
21
21
|
* Exported for testing purposes only.
|
|
22
22
|
*/
|
|
23
23
|
export declare function isWriteToEvidenceFile(input: unknown): boolean;
|
|
24
|
+
export declare function isEvidencePath(filePath: string | undefined | null): boolean;
|
|
24
25
|
/** Build the v3-schema enrichment prompt for a single prose lesson. */
|
|
25
26
|
export declare function buildV3EnrichmentPrompt(lesson: string, category: string, tags: string[]): string;
|
|
26
27
|
/**
|
|
@@ -46,4 +46,4 @@ export type ArchitectMode = 'DISCOVER' | 'PLAN' | 'EXECUTE' | 'PHASE-WRAP' | 'UN
|
|
|
46
46
|
* @param directory - The project directory to check
|
|
47
47
|
* @returns The current architect mode based on plan state
|
|
48
48
|
*/
|
|
49
|
-
export declare function detectArchitectMode(directory: string): Promise<ArchitectMode>;
|
|
49
|
+
export declare function detectArchitectMode(directory: string, cache?: Map<string, Promise<string | null>>): Promise<ArchitectMode>;
|
package/dist/hooks/utils.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* including error handling, handler composition, file I/O, and
|
|
6
6
|
* token estimation for swarm-related operations.
|
|
7
7
|
*/
|
|
8
|
+
import { readCachedTextFile } from '../utils/swarm-artifact-cache';
|
|
8
9
|
/**
|
|
9
10
|
* Test-only dependency-injection seam. Production code calls
|
|
10
11
|
* `_internals.<fn>(...)` so tests can replace the function on this object
|
|
@@ -18,6 +19,7 @@ export declare const _internals: {
|
|
|
18
19
|
composeHandlers: typeof composeHandlers;
|
|
19
20
|
validateSwarmPath: typeof validateSwarmPath;
|
|
20
21
|
readSwarmFileAsync: typeof readSwarmFileAsync;
|
|
22
|
+
readCachedTextFile: typeof readCachedTextFile;
|
|
21
23
|
};
|
|
22
24
|
export declare function safeHook<I, O>(fn: (input: I, output: O) => Promise<void>): (input: I, output: O) => Promise<void>;
|
|
23
25
|
/**
|
|
@@ -70,5 +72,5 @@ export declare function composeBlockingHandlers<I, O>(...fns: Array<(input: I, o
|
|
|
70
72
|
* @throws Error if the filename is invalid or attempts path traversal
|
|
71
73
|
*/
|
|
72
74
|
export declare function validateSwarmPath(directory: string, filename: string): string;
|
|
73
|
-
export declare function readSwarmFileAsync(directory: string, filename: string): Promise<string | null>;
|
|
75
|
+
export declare function readSwarmFileAsync(directory: string, filename: string, cache?: Map<string, Promise<string | null>>): Promise<string | null>;
|
|
74
76
|
export declare function estimateTokens(text: string): number;
|
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.98.
|
|
72
|
+
version: "7.98.2",
|
|
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",
|
|
@@ -18167,13 +18167,23 @@ function validateSwarmPath(directory, filename) {
|
|
|
18167
18167
|
}
|
|
18168
18168
|
return resolved;
|
|
18169
18169
|
}
|
|
18170
|
-
async function readSwarmFileAsync(directory, filename) {
|
|
18170
|
+
async function readSwarmFileAsync(directory, filename, cache) {
|
|
18171
|
+
if (cache !== undefined) {
|
|
18172
|
+
const key = `${directory}::${filename}`;
|
|
18173
|
+
const cached2 = cache.get(key);
|
|
18174
|
+
if (cached2 !== undefined) {
|
|
18175
|
+
return cached2;
|
|
18176
|
+
}
|
|
18177
|
+
const promise2 = readSwarmFileAsync(directory, filename);
|
|
18178
|
+
cache.set(key, promise2);
|
|
18179
|
+
return promise2;
|
|
18180
|
+
}
|
|
18171
18181
|
const maxAttempts = 5;
|
|
18172
18182
|
const retryDelayMs = 10;
|
|
18173
18183
|
for (let attempt = 0;attempt < maxAttempts; attempt++) {
|
|
18174
18184
|
try {
|
|
18175
18185
|
const resolvedPath = _internals3.validateSwarmPath(directory, filename);
|
|
18176
|
-
return await readCachedTextFile(resolvedPath, async () => {
|
|
18186
|
+
return await _internals3.readCachedTextFile(resolvedPath, async () => {
|
|
18177
18187
|
const file2 = bunFile(resolvedPath);
|
|
18178
18188
|
return await file2.text();
|
|
18179
18189
|
});
|
|
@@ -18198,7 +18208,13 @@ var init_utils2 = __esm(() => {
|
|
|
18198
18208
|
init_utils();
|
|
18199
18209
|
init_bun_compat();
|
|
18200
18210
|
init_swarm_artifact_cache();
|
|
18201
|
-
_internals3 = {
|
|
18211
|
+
_internals3 = {
|
|
18212
|
+
safeHook,
|
|
18213
|
+
composeHandlers,
|
|
18214
|
+
validateSwarmPath,
|
|
18215
|
+
readSwarmFileAsync,
|
|
18216
|
+
readCachedTextFile
|
|
18217
|
+
};
|
|
18202
18218
|
});
|
|
18203
18219
|
|
|
18204
18220
|
// src/utils/git-binary-missing-error.ts
|
|
@@ -20452,8 +20468,8 @@ function extractPlanHashFromMarkdown(markdown) {
|
|
|
20452
20468
|
const match = markdown.match(/<!--\s*PLAN_HASH:\s*(\S+)\s*-->/);
|
|
20453
20469
|
return match ? match[1] : null;
|
|
20454
20470
|
}
|
|
20455
|
-
async function isPlanMdInSync(directory, plan) {
|
|
20456
|
-
const planMdContent = await readSwarmFileAsync(directory, "plan.md");
|
|
20471
|
+
async function isPlanMdInSync(directory, plan, cache) {
|
|
20472
|
+
const planMdContent = await readSwarmFileAsync(directory, "plan.md", cache);
|
|
20457
20473
|
if (planMdContent === null) {
|
|
20458
20474
|
return false;
|
|
20459
20475
|
}
|
|
@@ -20487,8 +20503,8 @@ ${markdown}`;
|
|
|
20487
20503
|
} catch {}
|
|
20488
20504
|
}
|
|
20489
20505
|
}
|
|
20490
|
-
async function loadPlan(directory) {
|
|
20491
|
-
const planJsonContent = await readSwarmFileAsync(directory, "plan.json");
|
|
20506
|
+
async function loadPlan(directory, cache) {
|
|
20507
|
+
const planJsonContent = await readSwarmFileAsync(directory, "plan.json", cache);
|
|
20492
20508
|
if (planJsonContent !== null) {
|
|
20493
20509
|
if (planJsonContent.includes("\x00") || planJsonContent.includes("�")) {
|
|
20494
20510
|
warn("Plan rejected: .swarm/plan.json contains null bytes or invalid encoding");
|
|
@@ -20498,7 +20514,7 @@ async function loadPlan(directory) {
|
|
|
20498
20514
|
if (validated === null) {
|
|
20499
20515
|
warn("[loadPlan] plan.json disappeared during cached parse. Falling back to plan.md migration or ledger recovery.");
|
|
20500
20516
|
} else {
|
|
20501
|
-
const inSync = await isPlanMdInSync(directory, validated);
|
|
20517
|
+
const inSync = await isPlanMdInSync(directory, validated, cache);
|
|
20502
20518
|
if (!inSync) {
|
|
20503
20519
|
try {
|
|
20504
20520
|
await _internals8.regeneratePlanMarkdown(directory, validated);
|
|
@@ -20621,7 +20637,7 @@ async function loadPlan(directory) {
|
|
|
20621
20637
|
}
|
|
20622
20638
|
}
|
|
20623
20639
|
}
|
|
20624
|
-
const planMdContent2 = await readSwarmFileAsync(directory, "plan.md");
|
|
20640
|
+
const planMdContent2 = await readSwarmFileAsync(directory, "plan.md", cache);
|
|
20625
20641
|
if (planMdContent2 !== null) {
|
|
20626
20642
|
const migrated = migrateLegacyPlan(planMdContent2);
|
|
20627
20643
|
const { removedCount } = await savePlanWithAutoAcknowledgedRemovals(directory, migrated, "load_plan_migration_from_md", "migrate legacy plan.md to plan.json");
|
|
@@ -20636,7 +20652,7 @@ async function loadPlan(directory) {
|
|
|
20636
20652
|
}
|
|
20637
20653
|
}
|
|
20638
20654
|
}
|
|
20639
|
-
const planMdContent = await readSwarmFileAsync(directory, "plan.md");
|
|
20655
|
+
const planMdContent = await readSwarmFileAsync(directory, "plan.md", cache);
|
|
20640
20656
|
if (planMdContent !== null) {
|
|
20641
20657
|
const migrated = migrateLegacyPlan(planMdContent);
|
|
20642
20658
|
await savePlan(directory, migrated);
|
|
@@ -70430,48 +70446,43 @@ function recordSeenRetroSection(key, value, timestamp) {
|
|
|
70430
70446
|
function hashContent2(content) {
|
|
70431
70447
|
return createHash9("sha1").update(content).digest("hex");
|
|
70432
70448
|
}
|
|
70433
|
-
function isWriteToSwarmPlan(input) {
|
|
70434
|
-
if (typeof input !== "object" || input === null)
|
|
70435
|
-
return false;
|
|
70436
|
-
const record3 = input;
|
|
70437
|
-
const toolName = record3.toolName;
|
|
70438
|
-
if (typeof toolName !== "string")
|
|
70439
|
-
return false;
|
|
70440
|
-
if (!["write", "edit", "apply_patch", "swarm_apply_patch"].includes(toolName))
|
|
70441
|
-
return false;
|
|
70442
|
-
const rawPath = record3.path;
|
|
70443
|
-
const rawFile = record3.file;
|
|
70444
|
-
const pathField = typeof rawPath === "string" ? rawPath.replace(/\\/g, "/") : undefined;
|
|
70445
|
-
const fileField = typeof rawFile === "string" ? rawFile.replace(/\\/g, "/") : undefined;
|
|
70446
|
-
if (typeof pathField === "string" && pathField.includes(".swarm/plan.md")) {
|
|
70447
|
-
return true;
|
|
70448
|
-
}
|
|
70449
|
-
if (typeof fileField === "string" && fileField.includes(".swarm/plan.md")) {
|
|
70450
|
-
return true;
|
|
70451
|
-
}
|
|
70452
|
-
return false;
|
|
70453
|
-
}
|
|
70454
70449
|
function isWriteToEvidenceFile(input) {
|
|
70455
|
-
|
|
70456
|
-
|
|
70457
|
-
|
|
70458
|
-
|
|
70459
|
-
|
|
70460
|
-
|
|
70461
|
-
|
|
70450
|
+
const trigger = normalizeWriteTrigger(input);
|
|
70451
|
+
return isEvidencePath(trigger?.filePath);
|
|
70452
|
+
}
|
|
70453
|
+
function isRecord(value) {
|
|
70454
|
+
return typeof value === "object" && value !== null;
|
|
70455
|
+
}
|
|
70456
|
+
function normalizePathField(value) {
|
|
70457
|
+
return typeof value === "string" ? value.replace(/\\/g, "/") : null;
|
|
70458
|
+
}
|
|
70459
|
+
function firstPathFromRecord(record3) {
|
|
70460
|
+
return normalizePathField(record3.path) ?? normalizePathField(record3.filePath) ?? normalizePathField(record3.file);
|
|
70461
|
+
}
|
|
70462
|
+
function normalizeWriteTrigger(input, output) {
|
|
70463
|
+
if (!isRecord(input))
|
|
70464
|
+
return null;
|
|
70465
|
+
const toolName = typeof input.toolName === "string" ? input.toolName : typeof input.tool === "string" ? input.tool : null;
|
|
70466
|
+
if (!toolName || !WRITE_TOOLS.has(toolName))
|
|
70467
|
+
return null;
|
|
70468
|
+
const inputArgs = isRecord(input.args) ? input.args : null;
|
|
70469
|
+
const outputArgs = isRecord(output) && isRecord(output.args) ? output.args : null;
|
|
70470
|
+
const filePath = firstPathFromRecord(input) ?? (inputArgs ? firstPathFromRecord(inputArgs) : null) ?? (outputArgs ? firstPathFromRecord(outputArgs) : null);
|
|
70471
|
+
if (!filePath)
|
|
70472
|
+
return null;
|
|
70473
|
+
return {
|
|
70474
|
+
toolName,
|
|
70475
|
+
filePath,
|
|
70476
|
+
sessionID: typeof input.sessionID === "string" ? input.sessionID : "default"
|
|
70477
|
+
};
|
|
70478
|
+
}
|
|
70479
|
+
function isEvidencePath(filePath) {
|
|
70480
|
+
if (!filePath)
|
|
70462
70481
|
return false;
|
|
70463
|
-
|
|
70464
|
-
|
|
70465
|
-
|
|
70466
|
-
|
|
70467
|
-
const evidenceRegex = /\.swarm\/+evidence\/+/i;
|
|
70468
|
-
if (typeof pathField === "string" && evidenceRegex.test(pathField)) {
|
|
70469
|
-
return true;
|
|
70470
|
-
}
|
|
70471
|
-
if (typeof fileField === "string" && evidenceRegex.test(fileField)) {
|
|
70472
|
-
return true;
|
|
70473
|
-
}
|
|
70474
|
-
return false;
|
|
70482
|
+
return /(?:^|\/)\.swarm\/+evidence\//i.test(filePath);
|
|
70483
|
+
}
|
|
70484
|
+
function isPlanPath(filePath) {
|
|
70485
|
+
return filePath?.includes(".swarm/plan.md") ?? false;
|
|
70475
70486
|
}
|
|
70476
70487
|
function extractRetrospectiveSection(planContent) {
|
|
70477
70488
|
const headingRegex = /^###\s+Lessons\s+Learned$/m;
|
|
@@ -71153,24 +71164,22 @@ async function runAutoPromotion(directory, config3) {
|
|
|
71153
71164
|
}
|
|
71154
71165
|
}
|
|
71155
71166
|
function createKnowledgeCuratorHook(directory, config3, options = {}) {
|
|
71156
|
-
const handler = async (input,
|
|
71167
|
+
const handler = async (input, output) => {
|
|
71157
71168
|
pruneSeenRetroSections();
|
|
71158
71169
|
if (!config3.enabled)
|
|
71159
71170
|
return;
|
|
71160
|
-
|
|
71171
|
+
const trigger = normalizeWriteTrigger(input, output);
|
|
71172
|
+
if (!trigger)
|
|
71173
|
+
return;
|
|
71174
|
+
const isPlanTrigger = isPlanPath(trigger.filePath);
|
|
71175
|
+
const isEvidenceTrigger = isEvidencePath(trigger.filePath) && !isPlanTrigger;
|
|
71176
|
+
if (!isPlanTrigger && !isEvidenceTrigger)
|
|
71161
71177
|
return;
|
|
71162
|
-
const sessionID = input?.sessionID ?? "default";
|
|
71163
|
-
const isEvidenceTrigger = isWriteToEvidenceFile(input) && !isWriteToSwarmPlan(input);
|
|
71164
71178
|
if (isEvidenceTrigger) {
|
|
71165
|
-
const
|
|
71166
|
-
const
|
|
71167
|
-
const rawFile = record3.file;
|
|
71168
|
-
const filePath = typeof rawPath === "string" ? rawPath.replace(/\\/g, "/") : typeof rawFile === "string" ? rawFile.replace(/\\/g, "/") : null;
|
|
71169
|
-
if (!filePath)
|
|
71170
|
-
return;
|
|
71171
|
-
const evidenceKey = `evidence:${sessionID}:${filePath}`;
|
|
71179
|
+
const relativeEvidencePath = trigger.filePath.replace(/^.*\.swarm\//, "");
|
|
71180
|
+
const evidenceKey = `evidence:${trigger.sessionID}:${relativeEvidencePath}`;
|
|
71172
71181
|
const lastSeenEvidence = seenRetroSections.get(evidenceKey);
|
|
71173
|
-
const evidenceContent = await readSwarmFileAsync(directory,
|
|
71182
|
+
const evidenceContent = await readSwarmFileAsync(directory, relativeEvidencePath);
|
|
71174
71183
|
if (!evidenceContent)
|
|
71175
71184
|
return;
|
|
71176
71185
|
let evidenceData;
|
|
@@ -71198,7 +71207,7 @@ function createKnowledgeCuratorHook(directory, config3, options = {}) {
|
|
|
71198
71207
|
const projectName2 = evidenceData.project_name ?? "unknown";
|
|
71199
71208
|
const phaseNumber2 = typeof evidenceData.phase_number === "number" ? evidenceData.phase_number : 1;
|
|
71200
71209
|
await _internals35.curateAndStoreSwarm(lessons, projectName2, { phase_number: phaseNumber2 }, directory, config3, {
|
|
71201
|
-
llmDelegate: options.llmDelegateFactory?.(sessionID),
|
|
71210
|
+
llmDelegate: options.llmDelegateFactory?.(trigger.sessionID),
|
|
71202
71211
|
enrichmentQuota: options.enrichmentQuota
|
|
71203
71212
|
});
|
|
71204
71213
|
return;
|
|
@@ -71209,7 +71218,7 @@ function createKnowledgeCuratorHook(directory, config3, options = {}) {
|
|
|
71209
71218
|
const section = extractRetrospectiveSection(planContent);
|
|
71210
71219
|
if (!section)
|
|
71211
71220
|
return;
|
|
71212
|
-
if (!checkRetroChanged(sessionID, section))
|
|
71221
|
+
if (!checkRetroChanged(trigger.sessionID, section))
|
|
71213
71222
|
return;
|
|
71214
71223
|
const allLessons = extractLessonsFromRetro(section);
|
|
71215
71224
|
if (allLessons.length === 0)
|
|
@@ -71223,13 +71232,13 @@ function createKnowledgeCuratorHook(directory, config3, options = {}) {
|
|
|
71223
71232
|
const phaseMatch = /^Phase:\s*(\d+)/m.exec(planContent);
|
|
71224
71233
|
const phaseNumber = phaseMatch ? parseInt(phaseMatch[1], 10) : 1;
|
|
71225
71234
|
await _internals35.curateAndStoreSwarm(normalLessons, projectName, { phase_number: phaseNumber }, directory, config3, {
|
|
71226
|
-
llmDelegate: options.llmDelegateFactory?.(sessionID),
|
|
71235
|
+
llmDelegate: options.llmDelegateFactory?.(trigger.sessionID),
|
|
71227
71236
|
enrichmentQuota: options.enrichmentQuota
|
|
71228
71237
|
});
|
|
71229
71238
|
};
|
|
71230
71239
|
return safeHook(handler);
|
|
71231
71240
|
}
|
|
71232
|
-
var seenRetroSections, MAX_TRACKED_RETRO_SECTIONS = 500, ENRICHMENT_ALLOWED_FIELDS, ENRICHMENT_LLM_TIMEOUT_MS = 60000, ENRICHMENT_BATCH_SIZE = 6, MESO_INSIGHT_BATCH_LIMIT = 20, KNOWLEDGE_CATEGORIES, OUTCOME_PROMOTION_BLOCK = -0.3, _internals35;
|
|
71241
|
+
var seenRetroSections, MAX_TRACKED_RETRO_SECTIONS = 500, WRITE_TOOLS, ENRICHMENT_ALLOWED_FIELDS, ENRICHMENT_LLM_TIMEOUT_MS = 60000, ENRICHMENT_BATCH_SIZE = 6, MESO_INSIGHT_BATCH_LIMIT = 20, KNOWLEDGE_CATEGORIES, OUTCOME_PROMOTION_BLOCK = -0.3, _internals35;
|
|
71233
71242
|
var init_knowledge_curator = __esm(() => {
|
|
71234
71243
|
init_skill_improver_quota();
|
|
71235
71244
|
init_synonym_map();
|
|
@@ -71241,6 +71250,12 @@ var init_knowledge_curator = __esm(() => {
|
|
|
71241
71250
|
init_micro_reflector();
|
|
71242
71251
|
init_utils2();
|
|
71243
71252
|
seenRetroSections = new Map;
|
|
71253
|
+
WRITE_TOOLS = new Set([
|
|
71254
|
+
"write",
|
|
71255
|
+
"edit",
|
|
71256
|
+
"apply_patch",
|
|
71257
|
+
"swarm_apply_patch"
|
|
71258
|
+
]);
|
|
71244
71259
|
ENRICHMENT_ALLOWED_FIELDS = [
|
|
71245
71260
|
"triggers",
|
|
71246
71261
|
"required_actions",
|
|
@@ -73876,6 +73891,10 @@ This project was already finalized in a previous /swarm close run. The plan has
|
|
|
73876
73891
|
ctx.warnings.push(`Failed to write close-summary.md: ${msg}`);
|
|
73877
73892
|
console.warn("[close-command] Failed to write close-summary.md:", error93);
|
|
73878
73893
|
}
|
|
73894
|
+
const sessionIdsToEnd = [...swarmState.agentSessions.keys()];
|
|
73895
|
+
for (const sessionId of sessionIdsToEnd) {
|
|
73896
|
+
_internals38.endAgentSession(sessionId);
|
|
73897
|
+
}
|
|
73879
73898
|
_internals38.resetSwarmStatePreservingSingletons();
|
|
73880
73899
|
const retroWarnings = ctx.warnings.filter((w) => w.includes("Retrospective write") || w.includes("retrospective write") || w.includes("Session retrospective"));
|
|
73881
73900
|
const otherWarnings = ctx.warnings.filter((w) => !w.includes("Retrospective write") && !w.includes("retrospective write") && !w.includes("Session retrospective"));
|
|
@@ -74042,7 +74061,8 @@ var init_close = __esm(() => {
|
|
|
74042
74061
|
runCleanStage,
|
|
74043
74062
|
runAlignStage,
|
|
74044
74063
|
archiveEvidence,
|
|
74045
|
-
closePlanTerminalState
|
|
74064
|
+
closePlanTerminalState,
|
|
74065
|
+
endAgentSession
|
|
74046
74066
|
};
|
|
74047
74067
|
});
|
|
74048
74068
|
|
|
@@ -119726,6 +119746,7 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
119726
119746
|
return;
|
|
119727
119747
|
}
|
|
119728
119748
|
}
|
|
119749
|
+
const planReadCache = new Map;
|
|
119729
119750
|
const maxInjectionTokens = config3.context_budget?.max_injection_tokens ?? 4000;
|
|
119730
119751
|
let injectedTokens = 0;
|
|
119731
119752
|
let actualDemand = 0;
|
|
@@ -119740,7 +119761,7 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
119740
119761
|
} else {
|
|
119741
119762
|
seAllocation = maxInjectionTokens;
|
|
119742
119763
|
}
|
|
119743
|
-
const contextContent = await readSwarmFileAsync(directory, "context.md");
|
|
119764
|
+
const contextContent = await readSwarmFileAsync(directory, "context.md", planReadCache);
|
|
119744
119765
|
try {
|
|
119745
119766
|
const { scanDocIndex: scanDocIndex2 } = await Promise.resolve().then(() => (init_doc_scan(), exports_doc_scan));
|
|
119746
119767
|
const { manifest, cached: cached3 } = await scanDocIndex2(directory);
|
|
@@ -119800,19 +119821,19 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
119800
119821
|
if (!scoringEnabled) {
|
|
119801
119822
|
let plan2 = null;
|
|
119802
119823
|
try {
|
|
119803
|
-
plan2 = await loadPlan(directory);
|
|
119824
|
+
plan2 = await loadPlan(directory, planReadCache);
|
|
119804
119825
|
} catch (error93) {
|
|
119805
119826
|
warn(`Failed to load plan: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
119806
119827
|
}
|
|
119807
119828
|
maybeAppendSpecDriftAdvisory(output, directory, plan2);
|
|
119808
|
-
const mode = await detectArchitectMode(directory);
|
|
119829
|
+
const mode = await detectArchitectMode(directory, planReadCache);
|
|
119809
119830
|
let planContent = null;
|
|
119810
119831
|
let phaseHeader = "";
|
|
119811
119832
|
if (plan2 && plan2.migration_status !== "migration_failed") {
|
|
119812
119833
|
phaseHeader = extractCurrentPhaseFromPlan(plan2) || "";
|
|
119813
|
-
planContent = await readSwarmFileAsync(directory, "plan.md");
|
|
119834
|
+
planContent = await readSwarmFileAsync(directory, "plan.md", planReadCache);
|
|
119814
119835
|
} else {
|
|
119815
|
-
planContent = await readSwarmFileAsync(directory, "plan.md");
|
|
119836
|
+
planContent = await readSwarmFileAsync(directory, "plan.md", planReadCache);
|
|
119816
119837
|
phaseHeader = planContent ? extractCurrentPhase(planContent) || "" : "";
|
|
119817
119838
|
}
|
|
119818
119839
|
if (phaseHeader) {
|
|
@@ -119824,7 +119845,7 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
119824
119845
|
}
|
|
119825
119846
|
if (mode !== "DISCOVER") {
|
|
119826
119847
|
try {
|
|
119827
|
-
const handoffContent = await readSwarmFileAsync(directory, "handoff.md");
|
|
119848
|
+
const handoffContent = await readSwarmFileAsync(directory, "handoff.md", planReadCache);
|
|
119828
119849
|
if (handoffContent) {
|
|
119829
119850
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
119830
119851
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
@@ -120188,7 +120209,7 @@ ${budgetWarning}`);
|
|
|
120188
120209
|
} else {}
|
|
120189
120210
|
return;
|
|
120190
120211
|
}
|
|
120191
|
-
const mode_b = await detectArchitectMode(directory);
|
|
120212
|
+
const mode_b = await detectArchitectMode(directory, planReadCache);
|
|
120192
120213
|
const userScoringConfig = config3.context_budget?.scoring;
|
|
120193
120214
|
const candidates = [];
|
|
120194
120215
|
let idCounter = 0;
|
|
@@ -120200,7 +120221,7 @@ ${budgetWarning}`);
|
|
|
120200
120221
|
} : DEFAULT_SCORING_CONFIG;
|
|
120201
120222
|
let plan = null;
|
|
120202
120223
|
try {
|
|
120203
|
-
plan = await loadPlan(directory);
|
|
120224
|
+
plan = await loadPlan(directory, planReadCache);
|
|
120204
120225
|
} catch (error93) {
|
|
120205
120226
|
warn(`Failed to load plan: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
120206
120227
|
}
|
|
@@ -120211,7 +120232,7 @@ ${budgetWarning}`);
|
|
|
120211
120232
|
currentPhase = extractCurrentPhaseFromPlan(plan);
|
|
120212
120233
|
currentTask = extractCurrentTaskFromPlan(plan);
|
|
120213
120234
|
} else {
|
|
120214
|
-
planContentForCursor = await readSwarmFileAsync(directory, "plan.md");
|
|
120235
|
+
planContentForCursor = await readSwarmFileAsync(directory, "plan.md", planReadCache);
|
|
120215
120236
|
if (planContentForCursor) {
|
|
120216
120237
|
currentPhase = extractCurrentPhase(planContentForCursor);
|
|
120217
120238
|
currentTask = extractCurrentTask(planContentForCursor);
|
|
@@ -120255,7 +120276,7 @@ ${budgetWarning}`);
|
|
|
120255
120276
|
}
|
|
120256
120277
|
if (mode_b !== "DISCOVER") {
|
|
120257
120278
|
try {
|
|
120258
|
-
const handoffContent = await readSwarmFileAsync(directory, "handoff.md");
|
|
120279
|
+
const handoffContent = await readSwarmFileAsync(directory, "handoff.md", planReadCache);
|
|
120259
120280
|
if (handoffContent) {
|
|
120260
120281
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
120261
120282
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
@@ -120754,9 +120775,9 @@ ${activitySection}`;
|
|
|
120754
120775
|
}
|
|
120755
120776
|
return contextSummary;
|
|
120756
120777
|
}
|
|
120757
|
-
async function detectArchitectMode(directory) {
|
|
120778
|
+
async function detectArchitectMode(directory, cache4) {
|
|
120758
120779
|
try {
|
|
120759
|
-
const plan = await loadPlan(directory);
|
|
120780
|
+
const plan = await loadPlan(directory, cache4);
|
|
120760
120781
|
if (!plan) {
|
|
120761
120782
|
return "DISCOVER";
|
|
120762
120783
|
}
|
|
@@ -125232,7 +125253,7 @@ init_state2();
|
|
|
125232
125253
|
init_delegation_gate();
|
|
125233
125254
|
init_normalize_tool_name();
|
|
125234
125255
|
import * as path154 from "node:path";
|
|
125235
|
-
var
|
|
125256
|
+
var WRITE_TOOLS2 = new Set(WRITE_TOOL_NAMES);
|
|
125236
125257
|
function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
125237
125258
|
const enabled = config3.enabled ?? true;
|
|
125238
125259
|
const _skipInTurbo = config3.skip_in_turbo ?? false;
|
|
@@ -125241,7 +125262,7 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
|
125241
125262
|
if (!enabled)
|
|
125242
125263
|
return;
|
|
125243
125264
|
const toolName = normalizeToolName(input.tool);
|
|
125244
|
-
if (!
|
|
125265
|
+
if (!WRITE_TOOLS2.has(toolName))
|
|
125245
125266
|
return;
|
|
125246
125267
|
const sessionId = input.sessionID;
|
|
125247
125268
|
const activeAgent = swarmState.activeAgent.get(sessionId);
|
|
@@ -135730,8 +135751,99 @@ function scanInvisibleFormatChars(text, fieldName) {
|
|
|
135730
135751
|
}
|
|
135731
135752
|
return findings;
|
|
135732
135753
|
}
|
|
135733
|
-
|
|
135734
|
-
|
|
135754
|
+
var CODE_SPAN_OR_FENCE_REGEX = /```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]*`/g;
|
|
135755
|
+
var CODE_WARNING_ONLY_PATTERNS = new Set([
|
|
135756
|
+
"backtick_execution",
|
|
135757
|
+
"shell_substitution",
|
|
135758
|
+
"disk_format",
|
|
135759
|
+
"force_kill",
|
|
135760
|
+
"process_group_kill",
|
|
135761
|
+
"kill_all_processes"
|
|
135762
|
+
]);
|
|
135763
|
+
function splitMarkdownCodeSegments(text) {
|
|
135764
|
+
const segments = [];
|
|
135765
|
+
let cursor = 0;
|
|
135766
|
+
for (const match of text.matchAll(CODE_SPAN_OR_FENCE_REGEX)) {
|
|
135767
|
+
const index = match.index ?? 0;
|
|
135768
|
+
if (index > cursor) {
|
|
135769
|
+
segments.push({ value: text.slice(cursor, index), isCode: false });
|
|
135770
|
+
}
|
|
135771
|
+
segments.push({ value: match[0], isCode: true });
|
|
135772
|
+
cursor = index + match[0].length;
|
|
135773
|
+
}
|
|
135774
|
+
if (cursor < text.length) {
|
|
135775
|
+
segments.push({ value: text.slice(cursor), isCode: false });
|
|
135776
|
+
}
|
|
135777
|
+
return segments.length === 0 ? [{ value: text, isCode: false }] : segments;
|
|
135778
|
+
}
|
|
135779
|
+
function getUnsafeInstructionMetadata(name) {
|
|
135780
|
+
const entry = UNSAFE_INSTRUCTION_PATTERNS.find((item) => item.name === name);
|
|
135781
|
+
return {
|
|
135782
|
+
description: entry?.description ?? "Destructive file removal command",
|
|
135783
|
+
severity: entry?.severity ?? "error"
|
|
135784
|
+
};
|
|
135785
|
+
}
|
|
135786
|
+
function tokenizeShellArgs(input) {
|
|
135787
|
+
const tokens = [];
|
|
135788
|
+
const tokenRegex = /"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|[^\s]+/g;
|
|
135789
|
+
for (const match of input.matchAll(tokenRegex)) {
|
|
135790
|
+
const token = match[1] ?? match[2] ?? match[0];
|
|
135791
|
+
if (token.length > 0)
|
|
135792
|
+
tokens.push(token);
|
|
135793
|
+
}
|
|
135794
|
+
return tokens;
|
|
135795
|
+
}
|
|
135796
|
+
function rmFlagHasShortOption(token, option) {
|
|
135797
|
+
return /^-[A-Za-z]+$/.test(token) && token.slice(1).includes(option);
|
|
135798
|
+
}
|
|
135799
|
+
function isRmOption(token) {
|
|
135800
|
+
return token.startsWith("-") && token !== "-";
|
|
135801
|
+
}
|
|
135802
|
+
function isDangerousRemovalTarget(rawTarget) {
|
|
135803
|
+
const target = rawTarget.replace(/\\/g, "/");
|
|
135804
|
+
if (/^[A-Za-z]:[/\\]?$/.test(target))
|
|
135805
|
+
return true;
|
|
135806
|
+
return target === "/" || target === "/*" || target === "." || target === ".." || target.startsWith(".swarm") || target.startsWith("/.swarm") || target.startsWith("~") || target.startsWith("$") || target.startsWith("${") || target.startsWith("%") || target.startsWith("/home") || target.startsWith("/Users") || target.startsWith("/etc") || target.startsWith("/bin") || target.startsWith("/sbin") || target.startsWith("/usr") || target.startsWith("/var") || /^[A-Za-z]:\/(?:Users|Windows)(?:\/|$)/.test(target);
|
|
135807
|
+
}
|
|
135808
|
+
function findDangerousRemovalCommands(text) {
|
|
135809
|
+
const commands = [];
|
|
135810
|
+
const rmCommandRegex = /\b(?<sudo>sudo\s+)?rm\b(?<args>[^\r\n`;&|]*)/gi;
|
|
135811
|
+
for (const match of text.matchAll(rmCommandRegex)) {
|
|
135812
|
+
const args2 = tokenizeShellArgs(match.groups?.args ?? "");
|
|
135813
|
+
const hasRecursive = args2.some((token) => token === "--recursive" || token === "-R" || rmFlagHasShortOption(token, "r") || rmFlagHasShortOption(token, "R"));
|
|
135814
|
+
const hasForce = args2.some((token) => token === "--force" || token === "-f" || rmFlagHasShortOption(token, "f"));
|
|
135815
|
+
if (!hasRecursive || !hasForce)
|
|
135816
|
+
continue;
|
|
135817
|
+
if (!args2.some((token) => !isRmOption(token) && isDangerousRemovalTarget(token))) {
|
|
135818
|
+
continue;
|
|
135819
|
+
}
|
|
135820
|
+
const pattern = match.groups?.sudo === undefined ? "destructive_file_removal" : "privileged_file_removal";
|
|
135821
|
+
commands.push({
|
|
135822
|
+
pattern,
|
|
135823
|
+
description: getUnsafeInstructionMetadata(pattern).description,
|
|
135824
|
+
match: match[0].trim().slice(0, 100)
|
|
135825
|
+
});
|
|
135826
|
+
}
|
|
135827
|
+
return commands;
|
|
135828
|
+
}
|
|
135829
|
+
function hasDangerousRemovalTarget(text) {
|
|
135830
|
+
return findDangerousRemovalCommands(text).length > 0;
|
|
135831
|
+
}
|
|
135832
|
+
function shouldScanUnsafePatternInSegment(entry, segment) {
|
|
135833
|
+
if (!segment.isCode)
|
|
135834
|
+
return true;
|
|
135835
|
+
if (CODE_WARNING_ONLY_PATTERNS.has(entry.name))
|
|
135836
|
+
return false;
|
|
135837
|
+
if (entry.name === "destructive_file_removal" || entry.name === "privileged_file_removal") {
|
|
135838
|
+
return false;
|
|
135839
|
+
}
|
|
135840
|
+
return true;
|
|
135841
|
+
}
|
|
135842
|
+
function getUnsafeScanSegments(field, value) {
|
|
135843
|
+
if (field !== "skill_body") {
|
|
135844
|
+
return [{ value, isCode: false }];
|
|
135845
|
+
}
|
|
135846
|
+
return splitMarkdownCodeSegments(value);
|
|
135735
135847
|
}
|
|
135736
135848
|
function scanPromptInjection(candidate, trustLevel = "low") {
|
|
135737
135849
|
const fields = extractCandidateFields(candidate);
|
|
@@ -135799,17 +135911,37 @@ function scanUnsafeInstructions(candidate, trustLevel = "low") {
|
|
|
135799
135911
|
const fieldsScanned = [];
|
|
135800
135912
|
for (const { field, value } of fields) {
|
|
135801
135913
|
fieldsScanned.push(field);
|
|
135802
|
-
const
|
|
135914
|
+
const scanSegments = getUnsafeScanSegments(field, value);
|
|
135915
|
+
if (field === "skill_body") {
|
|
135916
|
+
for (const segment of scanSegments) {
|
|
135917
|
+
if (!segment.isCode)
|
|
135918
|
+
continue;
|
|
135919
|
+
for (const command of findDangerousRemovalCommands(segment.value)) {
|
|
135920
|
+
findings.push({
|
|
135921
|
+
pattern: command.pattern,
|
|
135922
|
+
field,
|
|
135923
|
+
description: command.description,
|
|
135924
|
+
severity: "error",
|
|
135925
|
+
match: command.match
|
|
135926
|
+
});
|
|
135927
|
+
}
|
|
135928
|
+
}
|
|
135929
|
+
}
|
|
135803
135930
|
for (const entry of UNSAFE_INSTRUCTION_PATTERNS) {
|
|
135804
|
-
const
|
|
135805
|
-
|
|
135806
|
-
|
|
135807
|
-
|
|
135808
|
-
|
|
135809
|
-
|
|
135810
|
-
|
|
135811
|
-
|
|
135812
|
-
|
|
135931
|
+
for (const segment of scanSegments) {
|
|
135932
|
+
if (!shouldScanUnsafePatternInSegment(entry, segment))
|
|
135933
|
+
continue;
|
|
135934
|
+
const match = entry.pattern.exec(segment.value);
|
|
135935
|
+
if (match !== null) {
|
|
135936
|
+
findings.push({
|
|
135937
|
+
pattern: entry.name,
|
|
135938
|
+
field,
|
|
135939
|
+
description: entry.description,
|
|
135940
|
+
severity: entry.severity,
|
|
135941
|
+
match: match[0].slice(0, 100)
|
|
135942
|
+
});
|
|
135943
|
+
break;
|
|
135944
|
+
}
|
|
135813
135945
|
}
|
|
135814
135946
|
}
|
|
135815
135947
|
}
|
|
@@ -135973,7 +136105,9 @@ function evaluateCandidate(candidate, options) {
|
|
|
135973
136105
|
var _internals103 = {
|
|
135974
136106
|
getTimestamp: () => new Date().toISOString(),
|
|
135975
136107
|
computeSha256: (content) => createHash21("sha256").update(content).digest("hex"),
|
|
135976
|
-
|
|
136108
|
+
splitMarkdownCodeSegments,
|
|
136109
|
+
hasDangerousRemovalTarget,
|
|
136110
|
+
isDangerousRemovalTarget
|
|
135977
136111
|
};
|
|
135978
136112
|
|
|
135979
136113
|
// src/tools/external-skill-discover.ts
|
package/dist/plan/manager.d.ts
CHANGED
|
@@ -108,7 +108,7 @@ export declare function regeneratePlanMarkdown(directory: string, plan: Plan): P
|
|
|
108
108
|
* 3. .swarm/plan.md exists only -> migrate from plan.md, save both files, return Plan
|
|
109
109
|
* 4. Neither exists -> return null
|
|
110
110
|
*/
|
|
111
|
-
export declare function loadPlan(directory: string): Promise<RuntimePlan | null>;
|
|
111
|
+
export declare function loadPlan(directory: string, cache?: Map<string, Promise<string | null>>): Promise<RuntimePlan | null>;
|
|
112
112
|
/**
|
|
113
113
|
* Recovery-path helper for callers that legitimately need to replace the
|
|
114
114
|
* plan task set without explicit per-id acknowledgement (e.g. rebuilding
|
|
@@ -105,7 +105,13 @@ export declare const VALIDATION_RATE_LIMITS: {
|
|
|
105
105
|
/** Timeout for individual fetch operations in milliseconds. */
|
|
106
106
|
readonly fetch_timeout_ms: 30000;
|
|
107
107
|
};
|
|
108
|
-
|
|
108
|
+
interface MarkdownSegment {
|
|
109
|
+
value: string;
|
|
110
|
+
isCode: boolean;
|
|
111
|
+
}
|
|
112
|
+
declare function splitMarkdownCodeSegments(text: string): MarkdownSegment[];
|
|
113
|
+
declare function isDangerousRemovalTarget(rawTarget: string): boolean;
|
|
114
|
+
declare function hasDangerousRemovalTarget(text: string): boolean;
|
|
109
115
|
/**
|
|
110
116
|
* Scan an external skill candidate for prompt-injection patterns.
|
|
111
117
|
*
|
|
@@ -158,6 +164,8 @@ export declare function evaluateCandidate(candidate: ExternalSkillCandidate, opt
|
|
|
158
164
|
export declare const _internals: {
|
|
159
165
|
getTimestamp: () => string;
|
|
160
166
|
computeSha256: (content: string) => string;
|
|
161
|
-
|
|
167
|
+
splitMarkdownCodeSegments: typeof splitMarkdownCodeSegments;
|
|
168
|
+
hasDangerousRemovalTarget: typeof hasDangerousRemovalTarget;
|
|
169
|
+
isDangerousRemovalTarget: typeof isDangerousRemovalTarget;
|
|
162
170
|
};
|
|
163
171
|
export {};
|
package/dist/state.d.ts
CHANGED
|
@@ -391,9 +391,9 @@ export declare function resetSwarmStatePreservingSingletons(): void;
|
|
|
391
391
|
export declare function startAgentSession(sessionId: string, agentName: string, staleDurationMs?: number, directory?: string): void;
|
|
392
392
|
/**
|
|
393
393
|
* End an agent session by removing it from the state.
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
* a
|
|
394
|
+
* Called at session terminal state transitions (task completion, error, or session
|
|
395
|
+
* teardown) to prevent unbounded Map growth. Double-calls are safe: Map.delete is
|
|
396
|
+
* a no-op for missing keys (FR-010).
|
|
397
397
|
* @param sessionId - The session identifier to remove
|
|
398
398
|
*/
|
|
399
399
|
export declare function endAgentSession(sessionId: string): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.98.
|
|
3
|
+
"version": "7.98.2",
|
|
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",
|