opencode-swarm 6.82.0 → 6.82.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/background/evidence-summary-integration.d.ts +2 -2
- package/dist/cli/index.js +35 -2
- package/dist/index.js +84 -21
- package/dist/tools/resolve-working-directory.test.d.ts +1 -0
- package/dist/tools/save-plan.d.ts +5 -0
- package/dist/tools/save-plan.subdirectory-rejection.test.d.ts +1 -0
- package/package.json +1 -1
|
@@ -15,8 +15,8 @@ export interface EvidenceSummaryIntegrationConfig {
|
|
|
15
15
|
automationConfig: AutomationConfig;
|
|
16
16
|
/** Directory to run evidence analysis in */
|
|
17
17
|
directory: string;
|
|
18
|
-
/**
|
|
19
|
-
|
|
18
|
+
/** Project root directory for persisting summary artifacts under .swarm/ */
|
|
19
|
+
projectDir: string;
|
|
20
20
|
/** Filename for the summary artifact (default: evidence-summary.json) */
|
|
21
21
|
summaryFilename?: string;
|
|
22
22
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -41139,15 +41139,48 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
41139
41139
|
};
|
|
41140
41140
|
}
|
|
41141
41141
|
const resolvedDir = path26.resolve(normalizedDir);
|
|
41142
|
+
let statResult;
|
|
41142
41143
|
try {
|
|
41143
|
-
|
|
41144
|
-
return { success: true, directory: realPath };
|
|
41144
|
+
statResult = fs16.statSync(resolvedDir);
|
|
41145
41145
|
} catch {
|
|
41146
41146
|
return {
|
|
41147
41147
|
success: false,
|
|
41148
41148
|
message: `Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`
|
|
41149
41149
|
};
|
|
41150
41150
|
}
|
|
41151
|
+
if (!statResult.isDirectory()) {
|
|
41152
|
+
return {
|
|
41153
|
+
success: false,
|
|
41154
|
+
message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
|
|
41155
|
+
};
|
|
41156
|
+
}
|
|
41157
|
+
const resolvedFallback = path26.resolve(fallbackDirectory);
|
|
41158
|
+
let fallbackExists = false;
|
|
41159
|
+
try {
|
|
41160
|
+
fs16.statSync(resolvedFallback);
|
|
41161
|
+
fallbackExists = true;
|
|
41162
|
+
} catch {
|
|
41163
|
+
fallbackExists = false;
|
|
41164
|
+
}
|
|
41165
|
+
if (workingDirectory != null && workingDirectory !== "") {
|
|
41166
|
+
if (fallbackExists) {
|
|
41167
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path26.sep);
|
|
41168
|
+
if (isSubdirectory) {
|
|
41169
|
+
return {
|
|
41170
|
+
success: false,
|
|
41171
|
+
message: `Invalid working_directory: "${workingDirectory}" resolves to "${resolvedDir}" ` + `which is a subdirectory of fallback "${resolvedFallback}". ` + `Pass the project root path or omit working_directory entirely.`
|
|
41172
|
+
};
|
|
41173
|
+
}
|
|
41174
|
+
}
|
|
41175
|
+
return { success: true, directory: resolvedDir };
|
|
41176
|
+
}
|
|
41177
|
+
if (resolvedDir !== resolvedFallback) {
|
|
41178
|
+
return {
|
|
41179
|
+
success: false,
|
|
41180
|
+
message: `Invalid working_directory: path resolves to "${resolvedDir}" but fallbackDirectory ` + `"${resolvedFallback}" is not the project root. ` + `This may indicate CWD mismatch. Pass the project root path explicitly.`
|
|
41181
|
+
};
|
|
41182
|
+
}
|
|
41183
|
+
return { success: true, directory: resolvedDir };
|
|
41151
41184
|
}
|
|
41152
41185
|
|
|
41153
41186
|
// src/tools/test-runner.ts
|
package/dist/index.js
CHANGED
|
@@ -23083,7 +23083,13 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
|
|
|
23083
23083
|
} else {
|
|
23084
23084
|
guardrailsConfig = config2;
|
|
23085
23085
|
}
|
|
23086
|
-
const effectiveDirectory =
|
|
23086
|
+
const effectiveDirectory = (() => {
|
|
23087
|
+
if (typeof directory === "string")
|
|
23088
|
+
return directory;
|
|
23089
|
+
const cwd = process.cwd();
|
|
23090
|
+
console.warn(`[guardrails] effectiveDirectory resolved to process.cwd() "${cwd}" \u2014 ` + "pass an explicit directory string to createGuardrailsHooks to avoid .swarm artifacts in wrong locations");
|
|
23091
|
+
return cwd;
|
|
23092
|
+
})();
|
|
23087
23093
|
if (guardrailsConfig?.enabled === false) {
|
|
23088
23094
|
return {
|
|
23089
23095
|
toolBefore: async () => {},
|
|
@@ -23545,7 +23551,7 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
|
|
|
23545
23551
|
const planMdPath = path9.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
|
|
23546
23552
|
const planJsonPath = path9.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
|
|
23547
23553
|
if (resolvedTarget === planMdPath || resolvedTarget === planJsonPath) {
|
|
23548
|
-
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
|
|
23554
|
+
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 save_plan for ALL structural plan changes (adding/removing tasks, updating descriptions, dependencies, or phase names). " + "Use update_task_status() for task status only. " + "Use phase_complete() for phase transitions only.");
|
|
23549
23555
|
}
|
|
23550
23556
|
}
|
|
23551
23557
|
if (!targetPath && (tool === "apply_patch" || tool === "patch")) {
|
|
@@ -23554,7 +23560,7 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
|
|
|
23554
23560
|
const planMdPath = path9.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
|
|
23555
23561
|
const planJsonPath = path9.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
|
|
23556
23562
|
if (resolvedP.toLowerCase() === planMdPath || resolvedP.toLowerCase() === planJsonPath) {
|
|
23557
|
-
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
|
|
23563
|
+
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 save_plan for ALL structural plan changes (adding/removing tasks, updating descriptions, dependencies, or phase names). " + "Use update_task_status() for task status only. " + "Use phase_complete() for phase transitions only.");
|
|
23558
23564
|
}
|
|
23559
23565
|
if (isOutsideSwarmDir(p, effectiveDirectory) && (isSourceCodePath(p) || hasTraversalSegments(p))) {
|
|
23560
23566
|
const session = swarmState.agentSessions.get(sessionID);
|
|
@@ -49822,15 +49828,48 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
49822
49828
|
};
|
|
49823
49829
|
}
|
|
49824
49830
|
const resolvedDir = path34.resolve(normalizedDir);
|
|
49831
|
+
let statResult;
|
|
49825
49832
|
try {
|
|
49826
|
-
|
|
49827
|
-
return { success: true, directory: realPath };
|
|
49833
|
+
statResult = fs23.statSync(resolvedDir);
|
|
49828
49834
|
} catch {
|
|
49829
49835
|
return {
|
|
49830
49836
|
success: false,
|
|
49831
49837
|
message: `Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`
|
|
49832
49838
|
};
|
|
49833
49839
|
}
|
|
49840
|
+
if (!statResult.isDirectory()) {
|
|
49841
|
+
return {
|
|
49842
|
+
success: false,
|
|
49843
|
+
message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
|
|
49844
|
+
};
|
|
49845
|
+
}
|
|
49846
|
+
const resolvedFallback = path34.resolve(fallbackDirectory);
|
|
49847
|
+
let fallbackExists = false;
|
|
49848
|
+
try {
|
|
49849
|
+
fs23.statSync(resolvedFallback);
|
|
49850
|
+
fallbackExists = true;
|
|
49851
|
+
} catch {
|
|
49852
|
+
fallbackExists = false;
|
|
49853
|
+
}
|
|
49854
|
+
if (workingDirectory != null && workingDirectory !== "") {
|
|
49855
|
+
if (fallbackExists) {
|
|
49856
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path34.sep);
|
|
49857
|
+
if (isSubdirectory) {
|
|
49858
|
+
return {
|
|
49859
|
+
success: false,
|
|
49860
|
+
message: `Invalid working_directory: "${workingDirectory}" resolves to "${resolvedDir}" ` + `which is a subdirectory of fallback "${resolvedFallback}". ` + `Pass the project root path or omit working_directory entirely.`
|
|
49861
|
+
};
|
|
49862
|
+
}
|
|
49863
|
+
}
|
|
49864
|
+
return { success: true, directory: resolvedDir };
|
|
49865
|
+
}
|
|
49866
|
+
if (resolvedDir !== resolvedFallback) {
|
|
49867
|
+
return {
|
|
49868
|
+
success: false,
|
|
49869
|
+
message: `Invalid working_directory: path resolves to "${resolvedDir}" but fallbackDirectory ` + `"${resolvedFallback}" is not the project root. ` + `This may indicate CWD mismatch. Pass the project root path explicitly.`
|
|
49870
|
+
};
|
|
49871
|
+
}
|
|
49872
|
+
return { success: true, directory: resolvedDir };
|
|
49834
49873
|
}
|
|
49835
49874
|
var init_resolve_working_directory = () => {};
|
|
49836
49875
|
|
|
@@ -52941,7 +52980,7 @@ var init_reset_session = __esm(() => {
|
|
|
52941
52980
|
});
|
|
52942
52981
|
|
|
52943
52982
|
// src/summaries/manager.ts
|
|
52944
|
-
import { mkdirSync as mkdirSync13, readdirSync as readdirSync10, renameSync as renameSync10, rmSync as rmSync4, statSync as
|
|
52983
|
+
import { mkdirSync as mkdirSync13, readdirSync as readdirSync10, renameSync as renameSync10, rmSync as rmSync4, statSync as statSync10 } from "fs";
|
|
52945
52984
|
import * as path39 from "path";
|
|
52946
52985
|
function sanitizeSummaryId(id) {
|
|
52947
52986
|
if (!id || id.length === 0) {
|
|
@@ -54521,7 +54560,7 @@ The correct tools: save_plan to create or restructure a plan (writes plan.json \
|
|
|
54521
54560
|
.swarm/plan.md and .swarm/plan.json are READABLE but NOT DIRECTLY WRITABLE for state transitions.
|
|
54522
54561
|
Task-level status changes (marking individual tasks as "completed") must use update_task_status().
|
|
54523
54562
|
Phase-level completion (marking an entire phase as done) must use phase_complete().
|
|
54524
|
-
|
|
54563
|
+
For STRUCTURAL changes (adding tasks, updating descriptions, changing dependencies), use save_plan \u2014 do NOT write plan.md/plan.json directly.
|
|
54525
54564
|
You may NOT write to plan.md/plan.json to change task completion status or phase status directly.
|
|
54526
54565
|
"I'll just mark it done directly" is a bypass \u2014 equivalent to GATE_DELEGATION_BYPASS.
|
|
54527
54566
|
|
|
@@ -57437,8 +57476,8 @@ __export(exports_evidence_summary_integration, {
|
|
|
57437
57476
|
});
|
|
57438
57477
|
import { existsSync as existsSync24, mkdirSync as mkdirSync14, writeFileSync as writeFileSync6 } from "fs";
|
|
57439
57478
|
import * as path43 from "path";
|
|
57440
|
-
function persistSummary(
|
|
57441
|
-
const swarmPath = path43.join(
|
|
57479
|
+
function persistSummary(projectDir, artifact, filename) {
|
|
57480
|
+
const swarmPath = path43.join(projectDir, ".swarm");
|
|
57442
57481
|
if (!existsSync24(swarmPath)) {
|
|
57443
57482
|
mkdirSync14(swarmPath, { recursive: true });
|
|
57444
57483
|
}
|
|
@@ -57498,7 +57537,7 @@ class EvidenceSummaryIntegration {
|
|
|
57498
57537
|
return null;
|
|
57499
57538
|
}
|
|
57500
57539
|
const filename = this.config.summaryFilename ?? "evidence-summary.json";
|
|
57501
|
-
const artifactPath = persistSummary(this.config.
|
|
57540
|
+
const artifactPath = persistSummary(this.config.projectDir, artifact, filename);
|
|
57502
57541
|
log("[EvidenceSummaryIntegration] Summary generated and persisted", {
|
|
57503
57542
|
path: artifactPath,
|
|
57504
57543
|
completionRatio: artifact.overallCompletionRatio,
|
|
@@ -61565,8 +61604,8 @@ async function isGrammarAvailable(languageId) {
|
|
|
61565
61604
|
try {
|
|
61566
61605
|
const wasmFileName = getWasmFileName(normalizedId);
|
|
61567
61606
|
const wasmPath = path57.join(getGrammarsDirAbsolute(), wasmFileName);
|
|
61568
|
-
const { statSync:
|
|
61569
|
-
|
|
61607
|
+
const { statSync: statSync18 } = await import("fs");
|
|
61608
|
+
statSync18(wasmPath);
|
|
61570
61609
|
return true;
|
|
61571
61610
|
} catch {
|
|
61572
61611
|
return false;
|
|
@@ -64311,7 +64350,7 @@ import * as path50 from "path";
|
|
|
64311
64350
|
init_utils2();
|
|
64312
64351
|
init_path_security();
|
|
64313
64352
|
import * as fsSync2 from "fs";
|
|
64314
|
-
import { constants as constants3, existsSync as existsSync28, realpathSync as
|
|
64353
|
+
import { constants as constants3, existsSync as existsSync28, realpathSync as realpathSync6 } from "fs";
|
|
64315
64354
|
import * as fsPromises3 from "fs/promises";
|
|
64316
64355
|
import * as path49 from "path";
|
|
64317
64356
|
|
|
@@ -64765,13 +64804,13 @@ function resolveModuleSpecifier(workspaceRoot, sourceFile, specifier) {
|
|
|
64765
64804
|
let resolved = path49.resolve(sourceDir, specifier);
|
|
64766
64805
|
let realResolved;
|
|
64767
64806
|
try {
|
|
64768
|
-
realResolved =
|
|
64807
|
+
realResolved = realpathSync6(resolved);
|
|
64769
64808
|
} catch {
|
|
64770
64809
|
realResolved = resolved;
|
|
64771
64810
|
}
|
|
64772
64811
|
let realRoot;
|
|
64773
64812
|
try {
|
|
64774
|
-
realRoot =
|
|
64813
|
+
realRoot = realpathSync6(workspaceRoot);
|
|
64775
64814
|
} catch {
|
|
64776
64815
|
realRoot = path49.normalize(workspaceRoot);
|
|
64777
64816
|
}
|
|
@@ -64796,7 +64835,7 @@ function resolveModuleSpecifier(workspaceRoot, sourceFile, specifier) {
|
|
|
64796
64835
|
}
|
|
64797
64836
|
if (found) {
|
|
64798
64837
|
try {
|
|
64799
|
-
realResolved =
|
|
64838
|
+
realResolved = realpathSync6(found);
|
|
64800
64839
|
} catch {
|
|
64801
64840
|
realResolved = found;
|
|
64802
64841
|
}
|
|
@@ -64978,14 +65017,14 @@ async function saveGraph(workspace, graph, options) {
|
|
|
64978
65017
|
const normalizedWorkspace = path49.normalize(workspace);
|
|
64979
65018
|
let realWorkspace;
|
|
64980
65019
|
try {
|
|
64981
|
-
realWorkspace =
|
|
65020
|
+
realWorkspace = realpathSync6(workspace);
|
|
64982
65021
|
} catch {
|
|
64983
65022
|
realWorkspace = normalizedWorkspace;
|
|
64984
65023
|
}
|
|
64985
65024
|
const normalizedGraphRoot = path49.normalize(graph.workspaceRoot);
|
|
64986
65025
|
let realGraphRoot;
|
|
64987
65026
|
try {
|
|
64988
|
-
realGraphRoot =
|
|
65027
|
+
realGraphRoot = realpathSync6(graph.workspaceRoot);
|
|
64989
65028
|
} catch {
|
|
64990
65029
|
realGraphRoot = normalizedGraphRoot;
|
|
64991
65030
|
}
|
|
@@ -82030,6 +82069,30 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
82030
82069
|
recovery_guidance: "Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."
|
|
82031
82070
|
};
|
|
82032
82071
|
}
|
|
82072
|
+
if (args2.working_directory && fallbackDir) {
|
|
82073
|
+
const resolvedTarget = path87.resolve(args2.working_directory);
|
|
82074
|
+
const resolvedRoot = path87.resolve(fallbackDir);
|
|
82075
|
+
let fallbackExists = false;
|
|
82076
|
+
try {
|
|
82077
|
+
fs72.accessSync(resolvedRoot, fs72.constants.F_OK);
|
|
82078
|
+
fallbackExists = true;
|
|
82079
|
+
} catch {
|
|
82080
|
+
fallbackExists = false;
|
|
82081
|
+
}
|
|
82082
|
+
if (fallbackExists) {
|
|
82083
|
+
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path87.sep);
|
|
82084
|
+
if (isSubdirectory) {
|
|
82085
|
+
return {
|
|
82086
|
+
success: false,
|
|
82087
|
+
message: `working_directory must be the project root. ` + `Got "${args2.working_directory}" (resolves to "${resolvedTarget}"), ` + `which is a subdirectory of fallback "${resolvedRoot}". ` + `Omit working_directory or pass the project root explicitly.`,
|
|
82088
|
+
errors: [
|
|
82089
|
+
`working_directory "${resolvedTarget}" is a subdirectory of fallback "${resolvedRoot}"`
|
|
82090
|
+
],
|
|
82091
|
+
recovery_guidance: `Pass working_directory: "${resolvedRoot}" or omit the field entirely.`
|
|
82092
|
+
};
|
|
82093
|
+
}
|
|
82094
|
+
}
|
|
82095
|
+
}
|
|
82033
82096
|
let specMtime;
|
|
82034
82097
|
let specHash;
|
|
82035
82098
|
if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
|
|
@@ -82217,7 +82280,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
82217
82280
|
}
|
|
82218
82281
|
}
|
|
82219
82282
|
var save_plan = createSwarmTool({
|
|
82220
|
-
description: "Save a structured implementation plan to .swarm/plan.json and .swarm/plan.md. " + "Task descriptions and phase names MUST contain real content from the spec \u2014 " + "bracket placeholders like [task] or [Project] will be rejected.",
|
|
82283
|
+
description: "Save or revise a structured implementation plan to .swarm/plan.json and .swarm/plan.md. " + "Use this tool for all structural plan changes on an existing plan (adding/removing tasks, updating descriptions, dependencies, or phase names) \u2014 existing task statuses are preserved by default (set reset_statuses: true to start fresh). " + "Task descriptions and phase names MUST contain real content from the spec \u2014 " + "bracket placeholders like [task] or [Project] will be rejected.",
|
|
82221
82284
|
args: {
|
|
82222
82285
|
title: tool.schema.string().min(1).describe("Plan title \u2014 the REAL project name from the spec. NOT a placeholder like [Project]."),
|
|
82223
82286
|
swarm_id: tool.schema.string().min(1).describe('Swarm identifier (e.g. "mega")'),
|
|
@@ -83743,7 +83806,7 @@ async function ripgrepSearch(opts) {
|
|
|
83743
83806
|
stderr: "pipe",
|
|
83744
83807
|
cwd: opts.workspace
|
|
83745
83808
|
});
|
|
83746
|
-
const timeout = new Promise((
|
|
83809
|
+
const timeout = new Promise((resolve38) => setTimeout(() => resolve38("timeout"), REGEX_TIMEOUT_MS));
|
|
83747
83810
|
const exitPromise = proc.exited;
|
|
83748
83811
|
const result = await Promise.race([exitPromise, timeout]);
|
|
83749
83812
|
if (result === "timeout") {
|
|
@@ -86956,7 +87019,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
86956
87019
|
createEvidenceSummaryIntegration2({
|
|
86957
87020
|
automationConfig,
|
|
86958
87021
|
directory: ctx.directory,
|
|
86959
|
-
|
|
87022
|
+
projectDir: ctx.directory,
|
|
86960
87023
|
summaryFilename: "evidence-summary.json"
|
|
86961
87024
|
});
|
|
86962
87025
|
log("Evidence summary integration initialized", {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -20,6 +20,11 @@ export interface SavePlanArgs {
|
|
|
20
20
|
acceptance?: string;
|
|
21
21
|
}>;
|
|
22
22
|
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Must be the project root directory. When provided, it anchors all .swarm directory
|
|
25
|
+
* creation and plan file operations to the project root (issue #577).
|
|
26
|
+
* Omit to use the fallback directory (injected by createSwarmTool, typically process.cwd()).
|
|
27
|
+
*/
|
|
23
28
|
working_directory?: string;
|
|
24
29
|
/**
|
|
25
30
|
* When true, all task statuses are reset to 'pending' and existing completed
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.82.
|
|
3
|
+
"version": "6.82.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",
|