opencode-swarm 6.21.0 → 6.21.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/README.md +19 -1
- package/dist/background/plan-sync-worker.d.ts +5 -0
- package/dist/cli/index.js +13 -2
- package/dist/index.js +224 -56
- package/dist/tools/save-plan.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -688,6 +688,24 @@ When truncation is active, a footer is appended:
|
|
|
688
688
|
[output truncated to {maxLines} lines – use `tool_output.per_tool.<tool>` to adjust]
|
|
689
689
|
```
|
|
690
690
|
|
|
691
|
+
## Summarization Settings
|
|
692
|
+
|
|
693
|
+
Control how tool outputs are summarized for LLM context.
|
|
694
|
+
|
|
695
|
+
```json
|
|
696
|
+
{
|
|
697
|
+
"summaries": {
|
|
698
|
+
"threshold_bytes": 102400,
|
|
699
|
+
"exempt_tools": ["retrieve_summary", "task", "read"]
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
- **threshold_bytes** – Output size threshold in bytes before summarization is triggered (default 102400 = 100KB).
|
|
705
|
+
- **exempt_tools** – Tools whose outputs are never summarized. Defaults to `["retrieve_summary", "task", "read"]` to prevent re-summarization loops.
|
|
706
|
+
|
|
707
|
+
> **Note:** The `retrieve_summary` tool supports paginated retrieval via `offset` and `limit` parameters to fetch large summarized outputs in chunks.
|
|
708
|
+
|
|
691
709
|
---
|
|
692
710
|
|
|
693
711
|
### Disabling Agents
|
|
@@ -717,7 +735,7 @@ When truncation is active, a footer is appended:
|
|
|
717
735
|
| `/swarm evidence [task]` | Evidence bundles for a task or all tasks |
|
|
718
736
|
| `/swarm archive [--dry-run]` | Archive old evidence with retention policy |
|
|
719
737
|
| `/swarm benchmark` | Performance benchmarks |
|
|
720
|
-
| `/swarm retrieve [id]` | Retrieve auto-summarized tool outputs |
|
|
738
|
+
| `/swarm retrieve [id]` | Retrieve auto-summarized tool outputs (supports offset/limit pagination) |
|
|
721
739
|
| `/swarm reset --confirm` | Clear swarm state files |
|
|
722
740
|
| `/swarm preflight` | Run phase preflight checks |
|
|
723
741
|
| `/swarm config doctor [--fix]` | Config validation with optional auto-fix |
|
|
@@ -110,6 +110,11 @@ export declare class PlanSyncWorker {
|
|
|
110
110
|
* to prevent callback errors from affecting worker stability
|
|
111
111
|
*/
|
|
112
112
|
private safeCallback;
|
|
113
|
+
/**
|
|
114
|
+
* Advisory: check for unauthorized writes to plan.json outside of save_plan/savePlan
|
|
115
|
+
* Logs a warning if plan.json appears to have been modified after the write marker
|
|
116
|
+
*/
|
|
117
|
+
private checkForUnauthorizedWrite;
|
|
113
118
|
/**
|
|
114
119
|
* Wrap a promise with a timeout
|
|
115
120
|
*/
|
package/dist/cli/index.js
CHANGED
|
@@ -16231,6 +16231,17 @@ ${markdown}`;
|
|
|
16231
16231
|
unlinkSync(mdTempPath);
|
|
16232
16232
|
} catch {}
|
|
16233
16233
|
}
|
|
16234
|
+
try {
|
|
16235
|
+
const markerPath = path6.join(swarmDir, ".plan-write-marker");
|
|
16236
|
+
const tasksCount = validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
|
16237
|
+
const marker = JSON.stringify({
|
|
16238
|
+
source: "plan_manager",
|
|
16239
|
+
timestamp: new Date().toISOString(),
|
|
16240
|
+
phases_count: validated.phases.length,
|
|
16241
|
+
tasks_count: tasksCount
|
|
16242
|
+
});
|
|
16243
|
+
await Bun.write(markerPath, marker);
|
|
16244
|
+
} catch {}
|
|
16234
16245
|
}
|
|
16235
16246
|
function derivePlanMarkdown(plan) {
|
|
16236
16247
|
const statusMap = {
|
|
@@ -16865,11 +16876,11 @@ var PhaseCompleteConfigSchema = exports_external.object({
|
|
|
16865
16876
|
});
|
|
16866
16877
|
var SummaryConfigSchema = exports_external.object({
|
|
16867
16878
|
enabled: exports_external.boolean().default(true),
|
|
16868
|
-
threshold_bytes: exports_external.number().min(1024).max(1048576).default(
|
|
16879
|
+
threshold_bytes: exports_external.number().min(1024).max(1048576).default(102400),
|
|
16869
16880
|
max_summary_chars: exports_external.number().min(100).max(5000).default(1000),
|
|
16870
16881
|
max_stored_bytes: exports_external.number().min(10240).max(104857600).default(10485760),
|
|
16871
16882
|
retention_days: exports_external.number().min(1).max(365).default(7),
|
|
16872
|
-
exempt_tools: exports_external.array(exports_external.string()).default(["retrieve_summary", "task"])
|
|
16883
|
+
exempt_tools: exports_external.array(exports_external.string()).default(["retrieve_summary", "task", "read"])
|
|
16873
16884
|
});
|
|
16874
16885
|
var ReviewPassesConfigSchema = exports_external.object({
|
|
16875
16886
|
always_security_review: exports_external.boolean().default(false),
|
package/dist/index.js
CHANGED
|
@@ -14841,6 +14841,17 @@ ${markdown}`;
|
|
|
14841
14841
|
unlinkSync(mdTempPath);
|
|
14842
14842
|
} catch {}
|
|
14843
14843
|
}
|
|
14844
|
+
try {
|
|
14845
|
+
const markerPath = path4.join(swarmDir, ".plan-write-marker");
|
|
14846
|
+
const tasksCount = validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
|
14847
|
+
const marker = JSON.stringify({
|
|
14848
|
+
source: "plan_manager",
|
|
14849
|
+
timestamp: new Date().toISOString(),
|
|
14850
|
+
phases_count: validated.phases.length,
|
|
14851
|
+
tasks_count: tasksCount
|
|
14852
|
+
});
|
|
14853
|
+
await Bun.write(markerPath, marker);
|
|
14854
|
+
} catch {}
|
|
14844
14855
|
}
|
|
14845
14856
|
async function updateTaskStatus(directory, taskId, status) {
|
|
14846
14857
|
const plan = await loadPlan(directory);
|
|
@@ -38485,11 +38496,11 @@ var PhaseCompleteConfigSchema = exports_external.object({
|
|
|
38485
38496
|
});
|
|
38486
38497
|
var SummaryConfigSchema = exports_external.object({
|
|
38487
38498
|
enabled: exports_external.boolean().default(true),
|
|
38488
|
-
threshold_bytes: exports_external.number().min(1024).max(1048576).default(
|
|
38499
|
+
threshold_bytes: exports_external.number().min(1024).max(1048576).default(102400),
|
|
38489
38500
|
max_summary_chars: exports_external.number().min(100).max(5000).default(1000),
|
|
38490
38501
|
max_stored_bytes: exports_external.number().min(10240).max(104857600).default(10485760),
|
|
38491
38502
|
retention_days: exports_external.number().min(1).max(365).default(7),
|
|
38492
|
-
exempt_tools: exports_external.array(exports_external.string()).default(["retrieve_summary", "task"])
|
|
38503
|
+
exempt_tools: exports_external.array(exports_external.string()).default(["retrieve_summary", "task", "read"])
|
|
38493
38504
|
});
|
|
38494
38505
|
var ReviewPassesConfigSchema = exports_external.object({
|
|
38495
38506
|
always_security_review: exports_external.boolean().default(false),
|
|
@@ -41666,6 +41677,7 @@ class PlanSyncWorker {
|
|
|
41666
41677
|
this.syncing = true;
|
|
41667
41678
|
try {
|
|
41668
41679
|
log("[PlanSyncWorker] Syncing plan...");
|
|
41680
|
+
this.checkForUnauthorizedWrite();
|
|
41669
41681
|
const plan = await this.withTimeout(loadPlan(this.directory), this.syncTimeoutMs, "Sync operation timed out");
|
|
41670
41682
|
if (plan) {
|
|
41671
41683
|
log("[PlanSyncWorker] Sync complete", {
|
|
@@ -41707,6 +41719,21 @@ class PlanSyncWorker {
|
|
|
41707
41719
|
}
|
|
41708
41720
|
}
|
|
41709
41721
|
}
|
|
41722
|
+
checkForUnauthorizedWrite() {
|
|
41723
|
+
try {
|
|
41724
|
+
const swarmDir = this.getSwarmDir();
|
|
41725
|
+
const planJsonPath = path6.join(swarmDir, "plan.json");
|
|
41726
|
+
const markerPath = path6.join(swarmDir, ".plan-write-marker");
|
|
41727
|
+
const planStats = fs3.statSync(planJsonPath);
|
|
41728
|
+
const planMtimeMs = planStats.mtimeMs;
|
|
41729
|
+
const markerContent = fs3.readFileSync(markerPath, "utf8");
|
|
41730
|
+
const marker = JSON.parse(markerContent);
|
|
41731
|
+
const markerTimestampMs = new Date(marker.timestamp).getTime();
|
|
41732
|
+
if (planMtimeMs > markerTimestampMs + 5000) {
|
|
41733
|
+
log("[PlanSyncWorker] WARNING: plan.json may have been written outside save_plan/savePlan - unauthorized direct write suspected", { planMtimeMs, markerTimestampMs });
|
|
41734
|
+
}
|
|
41735
|
+
} catch {}
|
|
41736
|
+
}
|
|
41710
41737
|
withTimeout(promise2, ms, timeoutMessage) {
|
|
41711
41738
|
return new Promise((resolve4, reject) => {
|
|
41712
41739
|
const timer = setTimeout(() => {
|
|
@@ -42074,6 +42101,9 @@ function recordPhaseAgentDispatch(sessionId, agentName) {
|
|
|
42074
42101
|
session.phaseAgentsDispatched.add(normalizedName);
|
|
42075
42102
|
}
|
|
42076
42103
|
function advanceTaskState(session, taskId, newState) {
|
|
42104
|
+
if (!session.taskWorkflowStates) {
|
|
42105
|
+
session.taskWorkflowStates = new Map;
|
|
42106
|
+
}
|
|
42077
42107
|
const STATE_ORDER = [
|
|
42078
42108
|
"idle",
|
|
42079
42109
|
"coder_delegated",
|
|
@@ -42094,6 +42124,9 @@ function advanceTaskState(session, taskId, newState) {
|
|
|
42094
42124
|
session.taskWorkflowStates.set(taskId, newState);
|
|
42095
42125
|
}
|
|
42096
42126
|
function getTaskState(session, taskId) {
|
|
42127
|
+
if (!session.taskWorkflowStates) {
|
|
42128
|
+
session.taskWorkflowStates = new Map;
|
|
42129
|
+
}
|
|
42097
42130
|
return session.taskWorkflowStates.get(taskId) ?? "idle";
|
|
42098
42131
|
}
|
|
42099
42132
|
|
|
@@ -42985,7 +43018,7 @@ async function handleDarkMatterCommand(directory, args2) {
|
|
|
42985
43018
|
|
|
42986
43019
|
// src/services/diagnose-service.ts
|
|
42987
43020
|
import { execSync } from "child_process";
|
|
42988
|
-
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as
|
|
43021
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
|
|
42989
43022
|
import path12 from "path";
|
|
42990
43023
|
init_manager();
|
|
42991
43024
|
init_utils2();
|
|
@@ -43291,7 +43324,7 @@ async function checkConfigParseability(directory) {
|
|
|
43291
43324
|
};
|
|
43292
43325
|
}
|
|
43293
43326
|
try {
|
|
43294
|
-
const content =
|
|
43327
|
+
const content = readFileSync4(configPath, "utf-8");
|
|
43295
43328
|
JSON.parse(content);
|
|
43296
43329
|
return {
|
|
43297
43330
|
name: "Config Parseability",
|
|
@@ -43358,7 +43391,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
43358
43391
|
};
|
|
43359
43392
|
}
|
|
43360
43393
|
try {
|
|
43361
|
-
const content =
|
|
43394
|
+
const content = readFileSync4(manifestPath, "utf-8");
|
|
43362
43395
|
const parsed = JSON.parse(content);
|
|
43363
43396
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
43364
43397
|
return {
|
|
@@ -43410,7 +43443,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
43410
43443
|
};
|
|
43411
43444
|
}
|
|
43412
43445
|
try {
|
|
43413
|
-
const content =
|
|
43446
|
+
const content = readFileSync4(eventsPath, "utf-8");
|
|
43414
43447
|
const lines = content.split(`
|
|
43415
43448
|
`).filter((line) => line.trim() !== "");
|
|
43416
43449
|
let malformedCount = 0;
|
|
@@ -43451,7 +43484,7 @@ async function checkSteeringDirectives(directory) {
|
|
|
43451
43484
|
};
|
|
43452
43485
|
}
|
|
43453
43486
|
try {
|
|
43454
|
-
const content =
|
|
43487
|
+
const content = readFileSync4(eventsPath, "utf-8");
|
|
43455
43488
|
const lines = content.split(`
|
|
43456
43489
|
`).filter((line) => line.trim() !== "");
|
|
43457
43490
|
const directivesIssued = [];
|
|
@@ -44419,7 +44452,7 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
44419
44452
|
}
|
|
44420
44453
|
// src/hooks/knowledge-migrator.ts
|
|
44421
44454
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
44422
|
-
import { existsSync as existsSync8, readFileSync as
|
|
44455
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
44423
44456
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
44424
44457
|
import * as path16 from "path";
|
|
44425
44458
|
|
|
@@ -44976,7 +45009,7 @@ function inferProjectName(directory) {
|
|
|
44976
45009
|
const packageJsonPath = path16.join(directory, "package.json");
|
|
44977
45010
|
if (existsSync8(packageJsonPath)) {
|
|
44978
45011
|
try {
|
|
44979
|
-
const pkg = JSON.parse(
|
|
45012
|
+
const pkg = JSON.parse(readFileSync6(packageJsonPath, "utf-8"));
|
|
44980
45013
|
if (pkg.name && typeof pkg.name === "string") {
|
|
44981
45014
|
return pkg.name;
|
|
44982
45015
|
}
|
|
@@ -47161,7 +47194,7 @@ function shouldMaskToolOutput(msg, index, totalMessages, recentWindowSize, thres
|
|
|
47161
47194
|
return false;
|
|
47162
47195
|
}
|
|
47163
47196
|
const toolName = extractToolName(text);
|
|
47164
|
-
if (toolName && ["retrieve_summary", "task"].includes(toolName.toLowerCase())) {
|
|
47197
|
+
if (toolName && ["retrieve_summary", "task", "read"].includes(toolName.toLowerCase())) {
|
|
47165
47198
|
return false;
|
|
47166
47199
|
}
|
|
47167
47200
|
const age = totalMessages - 1 - index;
|
|
@@ -47235,6 +47268,16 @@ function createDelegationGateHook(config3) {
|
|
|
47235
47268
|
session.qaSkipCount = 0;
|
|
47236
47269
|
session.qaSkipTaskIds = [];
|
|
47237
47270
|
}
|
|
47271
|
+
if (hasReviewer && session.currentTaskId) {
|
|
47272
|
+
try {
|
|
47273
|
+
advanceTaskState(session, session.currentTaskId, "reviewer_run");
|
|
47274
|
+
} catch {}
|
|
47275
|
+
}
|
|
47276
|
+
if (hasReviewer && hasTestEngineer && session.currentTaskId) {
|
|
47277
|
+
try {
|
|
47278
|
+
advanceTaskState(session, session.currentTaskId, "tests_run");
|
|
47279
|
+
} catch {}
|
|
47280
|
+
}
|
|
47238
47281
|
}
|
|
47239
47282
|
}
|
|
47240
47283
|
};
|
|
@@ -47725,13 +47768,14 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
47725
47768
|
if (typeof targetPath === "string" && targetPath.length > 0) {
|
|
47726
47769
|
const resolvedTarget = path25.resolve(directory, targetPath).toLowerCase();
|
|
47727
47770
|
const planMdPath = path25.resolve(directory, ".swarm", "plan.md").toLowerCase();
|
|
47728
|
-
|
|
47729
|
-
|
|
47771
|
+
const planJsonPath = path25.resolve(directory, ".swarm", "plan.json").toLowerCase();
|
|
47772
|
+
if (resolvedTarget === planMdPath || resolvedTarget === planJsonPath) {
|
|
47773
|
+
throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md and .swarm/plan.json are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
|
|
47730
47774
|
}
|
|
47731
47775
|
}
|
|
47732
47776
|
if (!targetPath && (input.tool === "apply_patch" || input.tool === "patch")) {
|
|
47733
47777
|
const patchText = args2?.input ?? args2?.patch ?? (Array.isArray(args2?.cmd) ? args2.cmd[1] : undefined);
|
|
47734
|
-
if (typeof patchText === "string") {
|
|
47778
|
+
if (typeof patchText === "string" && patchText.length <= 1e6) {
|
|
47735
47779
|
const patchPathPattern = /\*\*\*\s+(?:Update|Add|Delete)\s+File:\s*(.+)/gi;
|
|
47736
47780
|
const diffPathPattern = /\+\+\+\s+b\/(.+)/gm;
|
|
47737
47781
|
const paths = new Set;
|
|
@@ -47743,11 +47787,41 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
47743
47787
|
if (p !== "/dev/null")
|
|
47744
47788
|
paths.add(p);
|
|
47745
47789
|
}
|
|
47790
|
+
const gitDiffPathPattern = /^diff --git a\/(.+?) b\/(.+?)$/gm;
|
|
47791
|
+
for (const match of patchText.matchAll(gitDiffPathPattern)) {
|
|
47792
|
+
const aPath = match[1].trim();
|
|
47793
|
+
const bPath = match[2].trim();
|
|
47794
|
+
if (aPath !== "/dev/null")
|
|
47795
|
+
paths.add(aPath);
|
|
47796
|
+
if (bPath !== "/dev/null")
|
|
47797
|
+
paths.add(bPath);
|
|
47798
|
+
}
|
|
47799
|
+
const minusPathPattern = /^---\s+a\/(.+)$/gm;
|
|
47800
|
+
for (const match of patchText.matchAll(minusPathPattern)) {
|
|
47801
|
+
const p = match[1].trim();
|
|
47802
|
+
if (p !== "/dev/null")
|
|
47803
|
+
paths.add(p);
|
|
47804
|
+
}
|
|
47805
|
+
const traditionalMinusPattern = /^---\s+([^\s].+?)(?:\t.*)?$/gm;
|
|
47806
|
+
const traditionalPlusPattern = /^\+\+\+\s+([^\s].+?)(?:\t.*)?$/gm;
|
|
47807
|
+
for (const match of patchText.matchAll(traditionalMinusPattern)) {
|
|
47808
|
+
const p = match[1].trim();
|
|
47809
|
+
if (p !== "/dev/null" && !p.startsWith("a/") && !p.startsWith("b/")) {
|
|
47810
|
+
paths.add(p);
|
|
47811
|
+
}
|
|
47812
|
+
}
|
|
47813
|
+
for (const match of patchText.matchAll(traditionalPlusPattern)) {
|
|
47814
|
+
const p = match[1].trim();
|
|
47815
|
+
if (p !== "/dev/null" && !p.startsWith("a/") && !p.startsWith("b/")) {
|
|
47816
|
+
paths.add(p);
|
|
47817
|
+
}
|
|
47818
|
+
}
|
|
47746
47819
|
for (const p of paths) {
|
|
47747
47820
|
const resolvedP = path25.resolve(directory, p);
|
|
47748
|
-
const planMdPath = path25.resolve(directory, ".swarm", "plan.md");
|
|
47749
|
-
|
|
47750
|
-
|
|
47821
|
+
const planMdPath = path25.resolve(directory, ".swarm", "plan.md").toLowerCase();
|
|
47822
|
+
const planJsonPath = path25.resolve(directory, ".swarm", "plan.json").toLowerCase();
|
|
47823
|
+
if (resolvedP.toLowerCase() === planMdPath || resolvedP.toLowerCase() === planJsonPath) {
|
|
47824
|
+
throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md and .swarm/plan.json are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
|
|
47751
47825
|
}
|
|
47752
47826
|
if (isOutsideSwarmDir(p, directory) && (isSourceCodePath(p) || hasTraversalSegments(p))) {
|
|
47753
47827
|
const session2 = swarmState.agentSessions.get(input.sessionID);
|
|
@@ -47937,6 +48011,26 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
47937
48011
|
};
|
|
47938
48012
|
} else {
|
|
47939
48013
|
session.lastGateFailure = null;
|
|
48014
|
+
if (input.tool === "pre_check_batch") {
|
|
48015
|
+
const successStr = typeof output.output === "string" ? output.output : "";
|
|
48016
|
+
let isPassed = false;
|
|
48017
|
+
try {
|
|
48018
|
+
const result = JSON.parse(successStr);
|
|
48019
|
+
isPassed = result.gates_passed === true;
|
|
48020
|
+
} catch {
|
|
48021
|
+
isPassed = false;
|
|
48022
|
+
}
|
|
48023
|
+
if (isPassed && session.currentTaskId) {
|
|
48024
|
+
try {
|
|
48025
|
+
advanceTaskState(session, session.currentTaskId, "pre_check_passed");
|
|
48026
|
+
} catch (err2) {
|
|
48027
|
+
warn("Failed to advance task state after pre_check_batch pass", {
|
|
48028
|
+
taskId: session.currentTaskId,
|
|
48029
|
+
error: String(err2)
|
|
48030
|
+
});
|
|
48031
|
+
}
|
|
48032
|
+
}
|
|
48033
|
+
}
|
|
47940
48034
|
}
|
|
47941
48035
|
}
|
|
47942
48036
|
const inputArgs = inputArgsByCallID.get(input.callID);
|
|
@@ -49937,7 +50031,11 @@ function createToolSummarizerHook(config3, directory) {
|
|
|
49937
50031
|
if (typeof output.output !== "string" || output.output.length === 0) {
|
|
49938
50032
|
return;
|
|
49939
50033
|
}
|
|
49940
|
-
const exemptTools = config3.exempt_tools ?? [
|
|
50034
|
+
const exemptTools = config3.exempt_tools ?? [
|
|
50035
|
+
"retrieve_summary",
|
|
50036
|
+
"task",
|
|
50037
|
+
"read"
|
|
50038
|
+
];
|
|
49941
50039
|
if (exemptTools.includes(input.tool)) {
|
|
49942
50040
|
return;
|
|
49943
50041
|
}
|
|
@@ -57119,10 +57217,14 @@ var RETRIEVE_MAX_BYTES = 10 * 1024 * 1024;
|
|
|
57119
57217
|
var retrieve_summary = tool({
|
|
57120
57218
|
description: "Retrieve the full content of a stored tool output summary by its ID (e.g. S1, S2). Use this when a prior tool output was summarized and you need the full content.",
|
|
57121
57219
|
args: {
|
|
57122
|
-
id: tool.schema.string().describe("The summary ID to retrieve (e.g. S1, S2, S99). Must match pattern S followed by digits.")
|
|
57220
|
+
id: tool.schema.string().describe("The summary ID to retrieve (e.g. S1, S2, S99). Must match pattern S followed by digits."),
|
|
57221
|
+
offset: tool.schema.number().min(0).default(0).describe("Line offset to start from (default: 0)."),
|
|
57222
|
+
limit: tool.schema.number().min(1).max(500).default(100).describe("Number of lines to return (default: 100, max: 500).")
|
|
57123
57223
|
},
|
|
57124
57224
|
async execute(args2, context) {
|
|
57125
57225
|
const directory = context.directory;
|
|
57226
|
+
const offset = args2.offset ?? 0;
|
|
57227
|
+
const limit = Math.min(args2.limit ?? 100, 500);
|
|
57126
57228
|
let sanitizedId;
|
|
57127
57229
|
try {
|
|
57128
57230
|
sanitizedId = sanitizeSummaryId(args2.id);
|
|
@@ -57141,13 +57243,46 @@ var retrieve_summary = tool({
|
|
|
57141
57243
|
if (fullOutput.length > RETRIEVE_MAX_BYTES) {
|
|
57142
57244
|
return `Error: summary content exceeds maximum size limit (10 MB).`;
|
|
57143
57245
|
}
|
|
57144
|
-
|
|
57246
|
+
if (fullOutput.length === 0) {
|
|
57247
|
+
return `--- No content (0 lines) ---
|
|
57248
|
+
|
|
57249
|
+
(Summary is empty)`;
|
|
57250
|
+
}
|
|
57251
|
+
const lines = fullOutput.split(`
|
|
57252
|
+
`);
|
|
57253
|
+
const totalLines = lines.length;
|
|
57254
|
+
const clampedOffset = Math.max(0, offset);
|
|
57255
|
+
if (clampedOffset >= totalLines) {
|
|
57256
|
+
const response2 = `--- Offset beyond range ---
|
|
57257
|
+
|
|
57258
|
+
(Range exhausted. Valid offset range: 0-${totalLines - 1})
|
|
57259
|
+
(Content has ${totalLines} line${totalLines === 1 ? "" : "s"})`;
|
|
57260
|
+
return response2;
|
|
57261
|
+
}
|
|
57262
|
+
const startLine = Math.min(clampedOffset, totalLines);
|
|
57263
|
+
const endLine = Math.min(startLine + limit, totalLines);
|
|
57264
|
+
const paginatedLines = lines.slice(startLine, endLine);
|
|
57265
|
+
const paginatedContent = paginatedLines.join(`
|
|
57266
|
+
`);
|
|
57267
|
+
const headerStart = startLine + 1;
|
|
57268
|
+
const headerEnd = endLine;
|
|
57269
|
+
const rangeHeader = `--- Lines ${headerStart}-${headerEnd} of ${totalLines} ---`;
|
|
57270
|
+
let response = `${rangeHeader}
|
|
57271
|
+
${paginatedContent}`;
|
|
57272
|
+
if (endLine < totalLines) {
|
|
57273
|
+
const remaining = totalLines - endLine;
|
|
57274
|
+
response += `
|
|
57275
|
+
|
|
57276
|
+
... ${remaining} more line${remaining === 1 ? "" : "s"}. Use offset=${endLine} to retrieve more.`;
|
|
57277
|
+
}
|
|
57278
|
+
return response;
|
|
57145
57279
|
}
|
|
57146
57280
|
});
|
|
57147
57281
|
// src/tools/save-plan.ts
|
|
57148
57282
|
init_tool();
|
|
57149
57283
|
init_manager2();
|
|
57150
57284
|
init_create_tool();
|
|
57285
|
+
import * as fs28 from "fs";
|
|
57151
57286
|
import * as path39 from "path";
|
|
57152
57287
|
function detectPlaceholderContent(args2) {
|
|
57153
57288
|
const issues = [];
|
|
@@ -57182,12 +57317,33 @@ function validateTargetWorkspace(target, source) {
|
|
|
57182
57317
|
return;
|
|
57183
57318
|
}
|
|
57184
57319
|
async function executeSavePlan(args2, fallbackDir) {
|
|
57320
|
+
const validationErrors = [];
|
|
57321
|
+
for (const phase of args2.phases) {
|
|
57322
|
+
if (!Number.isInteger(phase.id) || phase.id <= 0) {
|
|
57323
|
+
validationErrors.push(`Phase ${phase.id} has invalid id: must be a positive integer`);
|
|
57324
|
+
}
|
|
57325
|
+
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
57326
|
+
for (const task of phase.tasks) {
|
|
57327
|
+
if (!taskIdPattern.test(task.id)) {
|
|
57328
|
+
validationErrors.push(`Task '${task.id}' in phase ${phase.id} has invalid id format: must match N.M pattern (e.g. '1.1', '2.3')`);
|
|
57329
|
+
}
|
|
57330
|
+
}
|
|
57331
|
+
}
|
|
57332
|
+
if (validationErrors.length > 0) {
|
|
57333
|
+
return {
|
|
57334
|
+
success: false,
|
|
57335
|
+
message: "Plan rejected: invalid phase or task IDs",
|
|
57336
|
+
errors: validationErrors,
|
|
57337
|
+
recovery_guidance: "Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."
|
|
57338
|
+
};
|
|
57339
|
+
}
|
|
57185
57340
|
const placeholderIssues = detectPlaceholderContent(args2);
|
|
57186
57341
|
if (placeholderIssues.length > 0) {
|
|
57187
57342
|
return {
|
|
57188
57343
|
success: false,
|
|
57189
57344
|
message: "Plan rejected: contains template placeholder content",
|
|
57190
|
-
errors: placeholderIssues
|
|
57345
|
+
errors: placeholderIssues,
|
|
57346
|
+
recovery_guidance: "Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."
|
|
57191
57347
|
};
|
|
57192
57348
|
}
|
|
57193
57349
|
const targetWorkspace = args2.working_directory ?? fallbackDir;
|
|
@@ -57195,8 +57351,9 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
57195
57351
|
if (workspaceError) {
|
|
57196
57352
|
return {
|
|
57197
57353
|
success: false,
|
|
57198
|
-
message: "Target workspace validation failed",
|
|
57199
|
-
errors: [workspaceError]
|
|
57354
|
+
message: "Target workspace validation failed: provide working_directory parameter to save_plan",
|
|
57355
|
+
errors: [workspaceError],
|
|
57356
|
+
recovery_guidance: "Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."
|
|
57200
57357
|
};
|
|
57201
57358
|
}
|
|
57202
57359
|
const plan = {
|
|
@@ -57229,6 +57386,16 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
57229
57386
|
const dir = targetWorkspace;
|
|
57230
57387
|
try {
|
|
57231
57388
|
await savePlan(dir, plan);
|
|
57389
|
+
try {
|
|
57390
|
+
const markerPath = path39.join(dir, ".swarm", ".plan-write-marker");
|
|
57391
|
+
const marker = JSON.stringify({
|
|
57392
|
+
source: "save_plan",
|
|
57393
|
+
timestamp: new Date().toISOString(),
|
|
57394
|
+
phases_count: plan.phases.length,
|
|
57395
|
+
tasks_count: tasksCount
|
|
57396
|
+
});
|
|
57397
|
+
await fs28.promises.writeFile(markerPath, marker, "utf8");
|
|
57398
|
+
} catch {}
|
|
57232
57399
|
return {
|
|
57233
57400
|
success: true,
|
|
57234
57401
|
message: "Plan saved successfully",
|
|
@@ -57239,8 +57406,9 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
57239
57406
|
} catch (error93) {
|
|
57240
57407
|
return {
|
|
57241
57408
|
success: false,
|
|
57242
|
-
message: "Failed to save plan",
|
|
57243
|
-
errors: [String(error93)]
|
|
57409
|
+
message: "Failed to save plan: retry with save_plan after resolving the error above",
|
|
57410
|
+
errors: [String(error93)],
|
|
57411
|
+
recovery_guidance: "Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."
|
|
57244
57412
|
};
|
|
57245
57413
|
}
|
|
57246
57414
|
}
|
|
@@ -57269,7 +57437,7 @@ var save_plan = createSwarmTool({
|
|
|
57269
57437
|
// src/tools/sbom-generate.ts
|
|
57270
57438
|
init_dist();
|
|
57271
57439
|
init_manager();
|
|
57272
|
-
import * as
|
|
57440
|
+
import * as fs29 from "fs";
|
|
57273
57441
|
import * as path40 from "path";
|
|
57274
57442
|
|
|
57275
57443
|
// src/sbom/detectors/dart.ts
|
|
@@ -58116,7 +58284,7 @@ function findManifestFiles(rootDir) {
|
|
|
58116
58284
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
58117
58285
|
function searchDir(dir) {
|
|
58118
58286
|
try {
|
|
58119
|
-
const entries =
|
|
58287
|
+
const entries = fs29.readdirSync(dir, { withFileTypes: true });
|
|
58120
58288
|
for (const entry of entries) {
|
|
58121
58289
|
const fullPath = path40.join(dir, entry.name);
|
|
58122
58290
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
@@ -58145,7 +58313,7 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
58145
58313
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
58146
58314
|
for (const dir of directories) {
|
|
58147
58315
|
try {
|
|
58148
|
-
const entries =
|
|
58316
|
+
const entries = fs29.readdirSync(dir, { withFileTypes: true });
|
|
58149
58317
|
for (const entry of entries) {
|
|
58150
58318
|
const fullPath = path40.join(dir, entry.name);
|
|
58151
58319
|
if (entry.isFile()) {
|
|
@@ -58183,7 +58351,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
58183
58351
|
}
|
|
58184
58352
|
function ensureOutputDir(outputDir) {
|
|
58185
58353
|
try {
|
|
58186
|
-
|
|
58354
|
+
fs29.mkdirSync(outputDir, { recursive: true });
|
|
58187
58355
|
} catch (error93) {
|
|
58188
58356
|
if (!error93 || error93.code !== "EEXIST") {
|
|
58189
58357
|
throw error93;
|
|
@@ -58276,10 +58444,10 @@ var sbom_generate = createSwarmTool({
|
|
|
58276
58444
|
for (const manifestFile of manifestFiles) {
|
|
58277
58445
|
try {
|
|
58278
58446
|
const fullPath = path40.isAbsolute(manifestFile) ? manifestFile : path40.join(workingDir, manifestFile);
|
|
58279
|
-
if (!
|
|
58447
|
+
if (!fs29.existsSync(fullPath)) {
|
|
58280
58448
|
continue;
|
|
58281
58449
|
}
|
|
58282
|
-
const content =
|
|
58450
|
+
const content = fs29.readFileSync(fullPath, "utf-8");
|
|
58283
58451
|
const components = detectComponents(manifestFile, content);
|
|
58284
58452
|
processedFiles.push(manifestFile);
|
|
58285
58453
|
if (components.length > 0) {
|
|
@@ -58293,7 +58461,7 @@ var sbom_generate = createSwarmTool({
|
|
|
58293
58461
|
const bomJson = serializeCycloneDX(bom);
|
|
58294
58462
|
const filename = generateSbomFilename();
|
|
58295
58463
|
const outputPath = path40.join(outputDir, filename);
|
|
58296
|
-
|
|
58464
|
+
fs29.writeFileSync(outputPath, bomJson, "utf-8");
|
|
58297
58465
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
58298
58466
|
try {
|
|
58299
58467
|
const timestamp = new Date().toISOString();
|
|
@@ -58335,7 +58503,7 @@ var sbom_generate = createSwarmTool({
|
|
|
58335
58503
|
// src/tools/schema-drift.ts
|
|
58336
58504
|
init_dist();
|
|
58337
58505
|
init_create_tool();
|
|
58338
|
-
import * as
|
|
58506
|
+
import * as fs30 from "fs";
|
|
58339
58507
|
import * as path41 from "path";
|
|
58340
58508
|
var SPEC_CANDIDATES = [
|
|
58341
58509
|
"openapi.json",
|
|
@@ -58377,19 +58545,19 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
58377
58545
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
58378
58546
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
58379
58547
|
}
|
|
58380
|
-
const stats =
|
|
58548
|
+
const stats = fs30.statSync(resolvedPath);
|
|
58381
58549
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
58382
58550
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
58383
58551
|
}
|
|
58384
|
-
if (!
|
|
58552
|
+
if (!fs30.existsSync(resolvedPath)) {
|
|
58385
58553
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
58386
58554
|
}
|
|
58387
58555
|
return resolvedPath;
|
|
58388
58556
|
}
|
|
58389
58557
|
for (const candidate of SPEC_CANDIDATES) {
|
|
58390
58558
|
const candidatePath = path41.resolve(cwd, candidate);
|
|
58391
|
-
if (
|
|
58392
|
-
const stats =
|
|
58559
|
+
if (fs30.existsSync(candidatePath)) {
|
|
58560
|
+
const stats = fs30.statSync(candidatePath);
|
|
58393
58561
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
58394
58562
|
return candidatePath;
|
|
58395
58563
|
}
|
|
@@ -58398,7 +58566,7 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
58398
58566
|
return null;
|
|
58399
58567
|
}
|
|
58400
58568
|
function parseSpec(specFile) {
|
|
58401
|
-
const content =
|
|
58569
|
+
const content = fs30.readFileSync(specFile, "utf-8");
|
|
58402
58570
|
const ext = path41.extname(specFile).toLowerCase();
|
|
58403
58571
|
if (ext === ".json") {
|
|
58404
58572
|
return parseJsonSpec(content);
|
|
@@ -58465,7 +58633,7 @@ function extractRoutes(cwd) {
|
|
|
58465
58633
|
function walkDir(dir) {
|
|
58466
58634
|
let entries;
|
|
58467
58635
|
try {
|
|
58468
|
-
entries =
|
|
58636
|
+
entries = fs30.readdirSync(dir, { withFileTypes: true });
|
|
58469
58637
|
} catch {
|
|
58470
58638
|
return;
|
|
58471
58639
|
}
|
|
@@ -58498,7 +58666,7 @@ function extractRoutes(cwd) {
|
|
|
58498
58666
|
}
|
|
58499
58667
|
function extractRoutesFromFile(filePath) {
|
|
58500
58668
|
const routes = [];
|
|
58501
|
-
const content =
|
|
58669
|
+
const content = fs30.readFileSync(filePath, "utf-8");
|
|
58502
58670
|
const lines = content.split(/\r?\n/);
|
|
58503
58671
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
58504
58672
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -58649,7 +58817,7 @@ init_secretscan();
|
|
|
58649
58817
|
// src/tools/symbols.ts
|
|
58650
58818
|
init_tool();
|
|
58651
58819
|
init_create_tool();
|
|
58652
|
-
import * as
|
|
58820
|
+
import * as fs31 from "fs";
|
|
58653
58821
|
import * as path42 from "path";
|
|
58654
58822
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
58655
58823
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
@@ -58680,8 +58848,8 @@ function containsWindowsAttacks(str) {
|
|
|
58680
58848
|
function isPathInWorkspace(filePath, workspace) {
|
|
58681
58849
|
try {
|
|
58682
58850
|
const resolvedPath = path42.resolve(workspace, filePath);
|
|
58683
|
-
const realWorkspace =
|
|
58684
|
-
const realResolvedPath =
|
|
58851
|
+
const realWorkspace = fs31.realpathSync(workspace);
|
|
58852
|
+
const realResolvedPath = fs31.realpathSync(resolvedPath);
|
|
58685
58853
|
const relativePath = path42.relative(realWorkspace, realResolvedPath);
|
|
58686
58854
|
if (relativePath.startsWith("..") || path42.isAbsolute(relativePath)) {
|
|
58687
58855
|
return false;
|
|
@@ -58701,11 +58869,11 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
58701
58869
|
}
|
|
58702
58870
|
let content;
|
|
58703
58871
|
try {
|
|
58704
|
-
const stats =
|
|
58872
|
+
const stats = fs31.statSync(fullPath);
|
|
58705
58873
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
58706
58874
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
58707
58875
|
}
|
|
58708
|
-
content =
|
|
58876
|
+
content = fs31.readFileSync(fullPath, "utf-8");
|
|
58709
58877
|
} catch {
|
|
58710
58878
|
return [];
|
|
58711
58879
|
}
|
|
@@ -58853,11 +59021,11 @@ function extractPythonSymbols(filePath, cwd) {
|
|
|
58853
59021
|
}
|
|
58854
59022
|
let content;
|
|
58855
59023
|
try {
|
|
58856
|
-
const stats =
|
|
59024
|
+
const stats = fs31.statSync(fullPath);
|
|
58857
59025
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
58858
59026
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
58859
59027
|
}
|
|
58860
|
-
content =
|
|
59028
|
+
content = fs31.readFileSync(fullPath, "utf-8");
|
|
58861
59029
|
} catch {
|
|
58862
59030
|
return [];
|
|
58863
59031
|
}
|
|
@@ -59000,7 +59168,7 @@ init_test_runner();
|
|
|
59000
59168
|
// src/tools/todo-extract.ts
|
|
59001
59169
|
init_dist();
|
|
59002
59170
|
init_create_tool();
|
|
59003
|
-
import * as
|
|
59171
|
+
import * as fs32 from "fs";
|
|
59004
59172
|
import * as path43 from "path";
|
|
59005
59173
|
var MAX_TEXT_LENGTH = 200;
|
|
59006
59174
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
@@ -59096,7 +59264,7 @@ function isSupportedExtension(filePath) {
|
|
|
59096
59264
|
function findSourceFiles3(dir, files = []) {
|
|
59097
59265
|
let entries;
|
|
59098
59266
|
try {
|
|
59099
|
-
entries =
|
|
59267
|
+
entries = fs32.readdirSync(dir);
|
|
59100
59268
|
} catch {
|
|
59101
59269
|
return files;
|
|
59102
59270
|
}
|
|
@@ -59108,7 +59276,7 @@ function findSourceFiles3(dir, files = []) {
|
|
|
59108
59276
|
const fullPath = path43.join(dir, entry);
|
|
59109
59277
|
let stat2;
|
|
59110
59278
|
try {
|
|
59111
|
-
stat2 =
|
|
59279
|
+
stat2 = fs32.statSync(fullPath);
|
|
59112
59280
|
} catch {
|
|
59113
59281
|
continue;
|
|
59114
59282
|
}
|
|
@@ -59201,7 +59369,7 @@ var todo_extract = createSwarmTool({
|
|
|
59201
59369
|
return JSON.stringify(errorResult, null, 2);
|
|
59202
59370
|
}
|
|
59203
59371
|
const scanPath = resolvedPath;
|
|
59204
|
-
if (!
|
|
59372
|
+
if (!fs32.existsSync(scanPath)) {
|
|
59205
59373
|
const errorResult = {
|
|
59206
59374
|
error: `path not found: ${pathsInput}`,
|
|
59207
59375
|
total: 0,
|
|
@@ -59211,7 +59379,7 @@ var todo_extract = createSwarmTool({
|
|
|
59211
59379
|
return JSON.stringify(errorResult, null, 2);
|
|
59212
59380
|
}
|
|
59213
59381
|
const filesToScan = [];
|
|
59214
|
-
const stat2 =
|
|
59382
|
+
const stat2 = fs32.statSync(scanPath);
|
|
59215
59383
|
if (stat2.isFile()) {
|
|
59216
59384
|
if (isSupportedExtension(scanPath)) {
|
|
59217
59385
|
filesToScan.push(scanPath);
|
|
@@ -59230,11 +59398,11 @@ var todo_extract = createSwarmTool({
|
|
|
59230
59398
|
const allEntries = [];
|
|
59231
59399
|
for (const filePath of filesToScan) {
|
|
59232
59400
|
try {
|
|
59233
|
-
const fileStat =
|
|
59401
|
+
const fileStat = fs32.statSync(filePath);
|
|
59234
59402
|
if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
|
|
59235
59403
|
continue;
|
|
59236
59404
|
}
|
|
59237
|
-
const content =
|
|
59405
|
+
const content = fs32.readFileSync(filePath, "utf-8");
|
|
59238
59406
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
59239
59407
|
allEntries.push(...entries);
|
|
59240
59408
|
} catch {}
|
|
@@ -59262,7 +59430,7 @@ var todo_extract = createSwarmTool({
|
|
|
59262
59430
|
// src/tools/update-task-status.ts
|
|
59263
59431
|
init_tool();
|
|
59264
59432
|
init_manager2();
|
|
59265
|
-
import * as
|
|
59433
|
+
import * as fs33 from "fs";
|
|
59266
59434
|
import * as path44 from "path";
|
|
59267
59435
|
init_create_tool();
|
|
59268
59436
|
var VALID_STATUSES = [
|
|
@@ -59360,9 +59528,9 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
59360
59528
|
}
|
|
59361
59529
|
const resolvedDir = path44.resolve(normalizedDir);
|
|
59362
59530
|
try {
|
|
59363
|
-
const realPath =
|
|
59531
|
+
const realPath = fs33.realpathSync(resolvedDir);
|
|
59364
59532
|
const planPath = path44.join(realPath, ".swarm", "plan.json");
|
|
59365
|
-
if (!
|
|
59533
|
+
if (!fs33.existsSync(planPath)) {
|
|
59366
59534
|
return {
|
|
59367
59535
|
success: false,
|
|
59368
59536
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.21.
|
|
3
|
+
"version": "6.21.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",
|