opencode-swarm 6.23.1 → 6.24.0
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 +0 -3
- package/dist/cli/index.js +33 -0
- package/dist/config/schema.d.ts +2 -2
- package/dist/gate-evidence.d.ts +56 -0
- package/dist/gate-evidence.test.d.ts +1 -0
- package/dist/hooks/delegation-gate.evidence.test.d.ts +4 -0
- package/dist/index.js +581 -256
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15749,6 +15749,39 @@ async function savePlan(directory, plan) {
|
|
|
15749
15749
|
throw new Error(`Invalid directory: directory must be a non-empty string`);
|
|
15750
15750
|
}
|
|
15751
15751
|
const validated = PlanSchema.parse(plan);
|
|
15752
|
+
try {
|
|
15753
|
+
const currentPlan = await loadPlanJsonOnly(directory);
|
|
15754
|
+
if (currentPlan) {
|
|
15755
|
+
const completedTaskIds = new Set;
|
|
15756
|
+
for (const phase of currentPlan.phases) {
|
|
15757
|
+
for (const task of phase.tasks) {
|
|
15758
|
+
if (task.status === "completed")
|
|
15759
|
+
completedTaskIds.add(task.id);
|
|
15760
|
+
}
|
|
15761
|
+
}
|
|
15762
|
+
if (completedTaskIds.size > 0) {
|
|
15763
|
+
for (const phase of validated.phases) {
|
|
15764
|
+
for (const task of phase.tasks) {
|
|
15765
|
+
if (completedTaskIds.has(task.id) && task.status !== "completed") {
|
|
15766
|
+
task.status = "completed";
|
|
15767
|
+
}
|
|
15768
|
+
}
|
|
15769
|
+
}
|
|
15770
|
+
}
|
|
15771
|
+
}
|
|
15772
|
+
} catch {}
|
|
15773
|
+
for (const phase of validated.phases) {
|
|
15774
|
+
const tasks = phase.tasks;
|
|
15775
|
+
if (tasks.length > 0 && tasks.every((t) => t.status === "completed")) {
|
|
15776
|
+
phase.status = "complete";
|
|
15777
|
+
} else if (tasks.some((t) => t.status === "in_progress")) {
|
|
15778
|
+
phase.status = "in_progress";
|
|
15779
|
+
} else if (tasks.some((t) => t.status === "blocked")) {
|
|
15780
|
+
phase.status = "blocked";
|
|
15781
|
+
} else {
|
|
15782
|
+
phase.status = "pending";
|
|
15783
|
+
}
|
|
15784
|
+
}
|
|
15752
15785
|
const swarmDir = path4.resolve(directory, ".swarm");
|
|
15753
15786
|
const planPath = path4.join(swarmDir, "plan.json");
|
|
15754
15787
|
const tempPath = path4.join(swarmDir, `plan.json.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
@@ -35824,6 +35857,133 @@ var init_preflight_service = __esm(() => {
|
|
|
35824
35857
|
};
|
|
35825
35858
|
});
|
|
35826
35859
|
|
|
35860
|
+
// src/gate-evidence.ts
|
|
35861
|
+
var exports_gate_evidence = {};
|
|
35862
|
+
__export(exports_gate_evidence, {
|
|
35863
|
+
recordGateEvidence: () => recordGateEvidence,
|
|
35864
|
+
recordAgentDispatch: () => recordAgentDispatch,
|
|
35865
|
+
readTaskEvidence: () => readTaskEvidence,
|
|
35866
|
+
hasPassedAllGates: () => hasPassedAllGates,
|
|
35867
|
+
expandRequiredGates: () => expandRequiredGates,
|
|
35868
|
+
deriveRequiredGates: () => deriveRequiredGates,
|
|
35869
|
+
DEFAULT_REQUIRED_GATES: () => DEFAULT_REQUIRED_GATES
|
|
35870
|
+
});
|
|
35871
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync13, renameSync as renameSync7, unlinkSync as unlinkSync4 } from "fs";
|
|
35872
|
+
import * as path27 from "path";
|
|
35873
|
+
function assertValidTaskId(taskId) {
|
|
35874
|
+
if (!taskId || taskId.includes("..") || taskId.includes("/") || taskId.includes("\\") || taskId.includes("\x00") || !TASK_ID_PATTERN.test(taskId)) {
|
|
35875
|
+
throw new Error(`Invalid taskId: "${taskId}". Must match N.M or N.M.P (e.g. "1.1", "1.2.3").`);
|
|
35876
|
+
}
|
|
35877
|
+
}
|
|
35878
|
+
function deriveRequiredGates(agentType) {
|
|
35879
|
+
switch (agentType) {
|
|
35880
|
+
case "coder":
|
|
35881
|
+
return ["reviewer", "test_engineer"];
|
|
35882
|
+
case "docs":
|
|
35883
|
+
return ["docs"];
|
|
35884
|
+
case "designer":
|
|
35885
|
+
return ["designer", "reviewer", "test_engineer"];
|
|
35886
|
+
case "explorer":
|
|
35887
|
+
return ["explorer"];
|
|
35888
|
+
case "sme":
|
|
35889
|
+
return ["sme"];
|
|
35890
|
+
case "reviewer":
|
|
35891
|
+
return ["reviewer"];
|
|
35892
|
+
case "test_engineer":
|
|
35893
|
+
return ["test_engineer"];
|
|
35894
|
+
case "critic":
|
|
35895
|
+
return ["critic"];
|
|
35896
|
+
default:
|
|
35897
|
+
return ["reviewer", "test_engineer"];
|
|
35898
|
+
}
|
|
35899
|
+
}
|
|
35900
|
+
function expandRequiredGates(existingGates, newAgentType) {
|
|
35901
|
+
const newGates = deriveRequiredGates(newAgentType);
|
|
35902
|
+
const combined = [...new Set([...existingGates, ...newGates])];
|
|
35903
|
+
return combined.sort();
|
|
35904
|
+
}
|
|
35905
|
+
function getEvidenceDir(directory) {
|
|
35906
|
+
return path27.join(directory, ".swarm", "evidence");
|
|
35907
|
+
}
|
|
35908
|
+
function getEvidencePath(directory, taskId) {
|
|
35909
|
+
return path27.join(getEvidenceDir(directory), `${taskId}.json`);
|
|
35910
|
+
}
|
|
35911
|
+
function readExisting(evidencePath) {
|
|
35912
|
+
try {
|
|
35913
|
+
const raw = readFileSync13(evidencePath, "utf-8");
|
|
35914
|
+
return JSON.parse(raw);
|
|
35915
|
+
} catch {
|
|
35916
|
+
return null;
|
|
35917
|
+
}
|
|
35918
|
+
}
|
|
35919
|
+
async function atomicWrite(targetPath, content) {
|
|
35920
|
+
const tempPath = `${targetPath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
|
|
35921
|
+
try {
|
|
35922
|
+
await Bun.write(tempPath, content);
|
|
35923
|
+
renameSync7(tempPath, targetPath);
|
|
35924
|
+
} finally {
|
|
35925
|
+
try {
|
|
35926
|
+
unlinkSync4(tempPath);
|
|
35927
|
+
} catch {}
|
|
35928
|
+
}
|
|
35929
|
+
}
|
|
35930
|
+
async function recordGateEvidence(directory, taskId, gate, sessionId) {
|
|
35931
|
+
assertValidTaskId(taskId);
|
|
35932
|
+
const evidenceDir = getEvidenceDir(directory);
|
|
35933
|
+
const evidencePath = getEvidencePath(directory, taskId);
|
|
35934
|
+
mkdirSync8(evidenceDir, { recursive: true });
|
|
35935
|
+
const existing = readExisting(evidencePath);
|
|
35936
|
+
const requiredGates = existing ? expandRequiredGates(existing.required_gates, gate) : deriveRequiredGates(gate);
|
|
35937
|
+
const updated = {
|
|
35938
|
+
taskId,
|
|
35939
|
+
required_gates: requiredGates,
|
|
35940
|
+
gates: {
|
|
35941
|
+
...existing?.gates ?? {},
|
|
35942
|
+
[gate]: {
|
|
35943
|
+
sessionId,
|
|
35944
|
+
timestamp: new Date().toISOString(),
|
|
35945
|
+
agent: gate
|
|
35946
|
+
}
|
|
35947
|
+
}
|
|
35948
|
+
};
|
|
35949
|
+
await atomicWrite(evidencePath, JSON.stringify(updated, null, 2));
|
|
35950
|
+
}
|
|
35951
|
+
async function recordAgentDispatch(directory, taskId, agentType) {
|
|
35952
|
+
assertValidTaskId(taskId);
|
|
35953
|
+
const evidenceDir = getEvidenceDir(directory);
|
|
35954
|
+
const evidencePath = getEvidencePath(directory, taskId);
|
|
35955
|
+
mkdirSync8(evidenceDir, { recursive: true });
|
|
35956
|
+
const existing = readExisting(evidencePath);
|
|
35957
|
+
const requiredGates = existing ? expandRequiredGates(existing.required_gates, agentType) : deriveRequiredGates(agentType);
|
|
35958
|
+
const updated = {
|
|
35959
|
+
taskId,
|
|
35960
|
+
required_gates: requiredGates,
|
|
35961
|
+
gates: existing?.gates ?? {}
|
|
35962
|
+
};
|
|
35963
|
+
await atomicWrite(evidencePath, JSON.stringify(updated, null, 2));
|
|
35964
|
+
}
|
|
35965
|
+
async function readTaskEvidence(directory, taskId) {
|
|
35966
|
+
try {
|
|
35967
|
+
assertValidTaskId(taskId);
|
|
35968
|
+
return readExisting(getEvidencePath(directory, taskId));
|
|
35969
|
+
} catch {
|
|
35970
|
+
return null;
|
|
35971
|
+
}
|
|
35972
|
+
}
|
|
35973
|
+
async function hasPassedAllGates(directory, taskId) {
|
|
35974
|
+
const evidence = await readTaskEvidence(directory, taskId);
|
|
35975
|
+
if (!evidence)
|
|
35976
|
+
return false;
|
|
35977
|
+
if (!Array.isArray(evidence.required_gates) || evidence.required_gates.length === 0)
|
|
35978
|
+
return false;
|
|
35979
|
+
return evidence.required_gates.every((gate) => evidence.gates[gate] != null);
|
|
35980
|
+
}
|
|
35981
|
+
var DEFAULT_REQUIRED_GATES, TASK_ID_PATTERN;
|
|
35982
|
+
var init_gate_evidence = __esm(() => {
|
|
35983
|
+
DEFAULT_REQUIRED_GATES = ["reviewer", "test_engineer"];
|
|
35984
|
+
TASK_ID_PATTERN = /^\d+\.\d+(\.\d+)*$/;
|
|
35985
|
+
});
|
|
35986
|
+
|
|
35827
35987
|
// src/services/preflight-integration.ts
|
|
35828
35988
|
var exports_preflight_integration = {};
|
|
35829
35989
|
__export(exports_preflight_integration, {
|
|
@@ -37353,11 +37513,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
37353
37513
|
throw toThrow;
|
|
37354
37514
|
}, "quit_");
|
|
37355
37515
|
var scriptDirectory = "";
|
|
37356
|
-
function locateFile(
|
|
37516
|
+
function locateFile(path40) {
|
|
37357
37517
|
if (Module["locateFile"]) {
|
|
37358
|
-
return Module["locateFile"](
|
|
37518
|
+
return Module["locateFile"](path40, scriptDirectory);
|
|
37359
37519
|
}
|
|
37360
|
-
return scriptDirectory +
|
|
37520
|
+
return scriptDirectory + path40;
|
|
37361
37521
|
}
|
|
37362
37522
|
__name(locateFile, "locateFile");
|
|
37363
37523
|
var readAsync, readBinary;
|
|
@@ -39105,7 +39265,7 @@ var init_runtime = __esm(() => {
|
|
|
39105
39265
|
});
|
|
39106
39266
|
|
|
39107
39267
|
// src/index.ts
|
|
39108
|
-
import * as
|
|
39268
|
+
import * as path49 from "path";
|
|
39109
39269
|
|
|
39110
39270
|
// src/agents/index.ts
|
|
39111
39271
|
init_config();
|
|
@@ -39945,15 +40105,6 @@ Swarm: {{SWARM_ID}}
|
|
|
39945
40105
|
## Patterns
|
|
39946
40106
|
- <pattern name>: <how and when to use it in this codebase>
|
|
39947
40107
|
|
|
39948
|
-
ROLE-RELEVANCE TAGGING
|
|
39949
|
-
When writing output consumed by other agents, prefix with:
|
|
39950
|
-
[FOR: agent1, agent2] \u2014 relevant to specific agents
|
|
39951
|
-
[FOR: ALL] \u2014 relevant to all agents
|
|
39952
|
-
Examples:
|
|
39953
|
-
[FOR: reviewer, test_engineer] "Added validation \u2014 needs safety check"
|
|
39954
|
-
[FOR: architect] "Research: Tree-sitter supports TypeScript AST"
|
|
39955
|
-
[FOR: ALL] "Breaking change: StateManager renamed"
|
|
39956
|
-
This tag is informational in v6.19; v6.20 will use for context filtering.
|
|
39957
40108
|
`;
|
|
39958
40109
|
function createArchitectAgent(model, customPrompt, customAppendPrompt, adversarialTesting) {
|
|
39959
40110
|
let prompt = ARCHITECT_PROMPT;
|
|
@@ -40009,15 +40160,44 @@ RULES:
|
|
|
40009
40160
|
- No research, no web searches, no documentation lookups
|
|
40010
40161
|
- Use training knowledge for APIs
|
|
40011
40162
|
|
|
40012
|
-
|
|
40163
|
+
## DEFENSIVE CODING RULES
|
|
40164
|
+
- NEVER use \`any\` type in TypeScript \u2014 always use specific types
|
|
40165
|
+
- NEVER leave empty catch blocks \u2014 at minimum log the error
|
|
40166
|
+
- NEVER use string concatenation for paths \u2014 use \`path.join()\` or \`path.resolve()\`
|
|
40167
|
+
- NEVER use platform-specific path separators \u2014 use \`path.join()\` for all path construction
|
|
40168
|
+
- NEVER import from relative paths traversing more than 2 levels (\`../../..\`) \u2014 use path aliases
|
|
40169
|
+
- NEVER use synchronous fs methods in async contexts unless explicitly required by the task
|
|
40170
|
+
- PREFER early returns over deeply nested conditionals
|
|
40171
|
+
- PREFER \`const\` over \`let\`; never use \`var\`
|
|
40172
|
+
- When modifying existing code, MATCH the surrounding style (indentation, quote style, semicolons)
|
|
40173
|
+
|
|
40174
|
+
## ERROR HANDLING
|
|
40175
|
+
When your implementation encounters an error or unexpected state:
|
|
40176
|
+
1. DO NOT silently swallow errors
|
|
40177
|
+
2. DO NOT invent workarounds not specified in the task
|
|
40178
|
+
3. DO NOT modify files outside the CONSTRAINT boundary to "fix" the issue
|
|
40179
|
+
4. Report the blocker using this format:
|
|
40180
|
+
BLOCKED: [what went wrong]
|
|
40181
|
+
NEED: [what additional context or change would fix it]
|
|
40182
|
+
The architect will re-scope or provide additional context. You are not authorized to make scope decisions.
|
|
40183
|
+
|
|
40184
|
+
OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
|
|
40185
|
+
For a completed task, begin directly with DONE.
|
|
40186
|
+
If the task is blocked, begin directly with BLOCKED.
|
|
40187
|
+
Do NOT prepend "Here's what I changed..." or any conversational preamble.
|
|
40188
|
+
|
|
40013
40189
|
DONE: [one-line summary]
|
|
40014
40190
|
CHANGED: [file]: [what changed]
|
|
40191
|
+
BLOCKED: [what went wrong]
|
|
40192
|
+
NEED: [what additional context or change would fix it]
|
|
40015
40193
|
|
|
40016
40194
|
AUTHOR BLINDNESS WARNING:
|
|
40017
40195
|
Your output is NOT reviewed, tested, or approved until the Architect runs the full QA gate.
|
|
40018
40196
|
Do NOT add commentary like "this looks good," "should be fine," or "ready for production."
|
|
40019
40197
|
You wrote the code. You cannot objectively evaluate it. That is what the gates are for.
|
|
40020
|
-
Output only
|
|
40198
|
+
Output only one of:
|
|
40199
|
+
- DONE [one-line summary] / CHANGED [file] [what changed]
|
|
40200
|
+
- BLOCKED [what went wrong] / NEED [what additional context or change would fix it]
|
|
40021
40201
|
|
|
40022
40202
|
SELF-AUDIT (run before marking any task complete):
|
|
40023
40203
|
Before you report task completion, verify:
|
|
@@ -40040,15 +40220,6 @@ META.SUMMARY CONVENTION \u2014 When reporting task completion, include:
|
|
|
40040
40220
|
|
|
40041
40221
|
Write for the next agent reading the event log, not for a human.
|
|
40042
40222
|
|
|
40043
|
-
ROLE-RELEVANCE TAGGING
|
|
40044
|
-
When writing output consumed by other agents, prefix with:
|
|
40045
|
-
[FOR: agent1, agent2] \u2014 relevant to specific agents
|
|
40046
|
-
[FOR: ALL] \u2014 relevant to all agents
|
|
40047
|
-
Examples:
|
|
40048
|
-
[FOR: reviewer, test_engineer] "Added validation \u2014 needs safety check"
|
|
40049
|
-
[FOR: architect] "Research: Tree-sitter supports TypeScript AST"
|
|
40050
|
-
[FOR: ALL] "Breaking change: StateManager renamed"
|
|
40051
|
-
This tag is informational in v6.19; v6.20 will use for context filtering.
|
|
40052
40223
|
`;
|
|
40053
40224
|
function createCoderAgent(model, customPrompt, customAppendPrompt) {
|
|
40054
40225
|
let prompt = CODER_PROMPT;
|
|
@@ -40249,15 +40420,6 @@ SOUNDING_BOARD RULES:
|
|
|
40249
40420
|
- Do not use Task tool \u2014 evaluate directly
|
|
40250
40421
|
- Read-only: do not create, modify, or delete any file
|
|
40251
40422
|
|
|
40252
|
-
ROLE-RELEVANCE TAGGING
|
|
40253
|
-
When writing output consumed by other agents, prefix with:
|
|
40254
|
-
[FOR: agent1, agent2] \u2014 relevant to specific agents
|
|
40255
|
-
[FOR: ALL] \u2014 relevant to all agents
|
|
40256
|
-
Examples:
|
|
40257
|
-
[FOR: reviewer, test_engineer] "Added validation \u2014 needs safety check"
|
|
40258
|
-
[FOR: architect] "Research: Tree-sitter supports TypeScript AST"
|
|
40259
|
-
[FOR: ALL] "Breaking change: StateManager renamed"
|
|
40260
|
-
This tag is informational in v6.19; v6.20 will use for context filtering.
|
|
40261
40423
|
`;
|
|
40262
40424
|
function createCriticAgent(model, customPrompt, customAppendPrompt) {
|
|
40263
40425
|
let prompt = CRITIC_PROMPT;
|
|
@@ -40417,15 +40579,6 @@ RULES:
|
|
|
40417
40579
|
- Do NOT implement business logic \u2014 leave that for the coder
|
|
40418
40580
|
- Keep output under 3000 characters per component
|
|
40419
40581
|
|
|
40420
|
-
ROLE-RELEVANCE TAGGING
|
|
40421
|
-
When writing output consumed by other agents, prefix with:
|
|
40422
|
-
[FOR: agent1, agent2] \u2014 relevant to specific agents
|
|
40423
|
-
[FOR: ALL] \u2014 relevant to all agents
|
|
40424
|
-
Examples:
|
|
40425
|
-
[FOR: reviewer, test_engineer] "Added validation \u2014 needs safety check"
|
|
40426
|
-
[FOR: architect] "Research: Tree-sitter supports TypeScript AST"
|
|
40427
|
-
[FOR: ALL] "Breaking change: StateManager renamed"
|
|
40428
|
-
This tag is informational in v6.19; v6.20 will use for context filtering.
|
|
40429
40582
|
`;
|
|
40430
40583
|
function createDesignerAgent(model, customPrompt, customAppendPrompt) {
|
|
40431
40584
|
let prompt = DESIGNER_PROMPT;
|
|
@@ -40487,6 +40640,28 @@ WORKFLOW:
|
|
|
40487
40640
|
b. Update JSDoc/docstring comments to match new signatures and behavior
|
|
40488
40641
|
c. Add missing documentation for new exports
|
|
40489
40642
|
|
|
40643
|
+
## DOCUMENTATION SCOPE
|
|
40644
|
+
|
|
40645
|
+
### ALWAYS update (when present):
|
|
40646
|
+
- README.md: If public API changed, update usage examples
|
|
40647
|
+
- CHANGELOG.md: Add entry under \`## [Unreleased]\` using Keep a Changelog format:
|
|
40648
|
+
## [Unreleased]
|
|
40649
|
+
### Added
|
|
40650
|
+
- New feature description
|
|
40651
|
+
### Changed
|
|
40652
|
+
- Existing behavior that was modified
|
|
40653
|
+
### Fixed
|
|
40654
|
+
- Bug that was resolved
|
|
40655
|
+
### Removed
|
|
40656
|
+
- Feature or code that was removed
|
|
40657
|
+
- API docs: If function signatures changed, update JSDoc/TSDoc in source files
|
|
40658
|
+
- Type definitions: If exported types changed, ensure documentation is current
|
|
40659
|
+
|
|
40660
|
+
### NEVER create:
|
|
40661
|
+
- New documentation files not requested by the architect
|
|
40662
|
+
- Inline comments explaining obvious code (code should be self-documenting)
|
|
40663
|
+
- TODO comments in code (those go through the task system, not code comments)
|
|
40664
|
+
|
|
40490
40665
|
RULES:
|
|
40491
40666
|
- Be accurate: documentation MUST match the actual code behavior
|
|
40492
40667
|
- Be concise: update only what changed, do not rewrite entire files
|
|
@@ -40495,21 +40670,13 @@ RULES:
|
|
|
40495
40670
|
- No fabrication: if you cannot determine behavior from the code, say so explicitly
|
|
40496
40671
|
- Update version references if package.json version changed
|
|
40497
40672
|
|
|
40498
|
-
OUTPUT FORMAT:
|
|
40673
|
+
OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
|
|
40674
|
+
Begin directly with UPDATED. Do NOT prepend "Here's what I updated..." or any conversational preamble.
|
|
40675
|
+
|
|
40499
40676
|
UPDATED: [list of files modified]
|
|
40500
40677
|
ADDED: [list of new sections/files created]
|
|
40501
40678
|
REMOVED: [list of deprecated sections removed]
|
|
40502
40679
|
SUMMARY: [one-line description of doc changes]
|
|
40503
|
-
|
|
40504
|
-
ROLE-RELEVANCE TAGGING
|
|
40505
|
-
When writing output consumed by other agents, prefix with:
|
|
40506
|
-
[FOR: agent1, agent2] \u2014 relevant to specific agents
|
|
40507
|
-
[FOR: ALL] \u2014 relevant to all agents
|
|
40508
|
-
Examples:
|
|
40509
|
-
[FOR: reviewer, test_engineer] "Added validation \u2014 needs safety check"
|
|
40510
|
-
[FOR: architect] "Research: Tree-sitter supports TypeScript AST"
|
|
40511
|
-
[FOR: ALL] "Breaking change: StateManager renamed"
|
|
40512
|
-
This tag is informational in v6.19; v6.20 will use for context filtering.
|
|
40513
40680
|
`;
|
|
40514
40681
|
function createDocsAgent(model, customPrompt, customAppendPrompt) {
|
|
40515
40682
|
let prompt = DOCS_PROMPT;
|
|
@@ -40554,7 +40721,36 @@ RULES:
|
|
|
40554
40721
|
- No code modifications
|
|
40555
40722
|
- Output under 2000 chars
|
|
40556
40723
|
|
|
40557
|
-
|
|
40724
|
+
## ANALYSIS PROTOCOL
|
|
40725
|
+
When exploring a codebase area, systematically report all four dimensions:
|
|
40726
|
+
|
|
40727
|
+
### STRUCTURE
|
|
40728
|
+
- Entry points and their call chains (max 3 levels deep)
|
|
40729
|
+
- Public API surface: exported functions/classes/types with signatures
|
|
40730
|
+
- Internal dependencies: what this module imports and from where
|
|
40731
|
+
- External dependencies: third-party packages used
|
|
40732
|
+
|
|
40733
|
+
### PATTERNS
|
|
40734
|
+
- Design patterns in use (factory, observer, strategy, etc.)
|
|
40735
|
+
- Error handling pattern (throw, Result type, error callbacks, etc.)
|
|
40736
|
+
- State management approach (global, module-level, passed through)
|
|
40737
|
+
- Configuration pattern (env vars, config files, hardcoded)
|
|
40738
|
+
|
|
40739
|
+
### RISKS
|
|
40740
|
+
- Files with high cyclomatic complexity or deep nesting
|
|
40741
|
+
- Circular dependencies
|
|
40742
|
+
- Missing error handling paths
|
|
40743
|
+
- Dead code or unreachable branches
|
|
40744
|
+
- Platform-specific assumptions (path separators, line endings, OS APIs)
|
|
40745
|
+
|
|
40746
|
+
### RELEVANT CONTEXT FOR TASK
|
|
40747
|
+
- Existing tests that cover this area (paths and what they test)
|
|
40748
|
+
- Related documentation files
|
|
40749
|
+
- Similar implementations elsewhere in the codebase that should be consistent
|
|
40750
|
+
|
|
40751
|
+
OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
|
|
40752
|
+
Begin directly with PROJECT. Do NOT prepend "Here's my analysis..." or any conversational preamble.
|
|
40753
|
+
|
|
40558
40754
|
PROJECT: [name/type]
|
|
40559
40755
|
LANGUAGES: [list]
|
|
40560
40756
|
FRAMEWORK: [if any]
|
|
@@ -40571,16 +40767,6 @@ DOMAINS: [relevant SME domains: powershell, security, python, etc.]
|
|
|
40571
40767
|
|
|
40572
40768
|
REVIEW NEEDED:
|
|
40573
40769
|
- [path]: [why, which SME]
|
|
40574
|
-
|
|
40575
|
-
ROLE-RELEVANCE TAGGING
|
|
40576
|
-
When writing output consumed by other agents, prefix with:
|
|
40577
|
-
[FOR: agent1, agent2] \u2014 relevant to specific agents
|
|
40578
|
-
[FOR: ALL] \u2014 relevant to all agents
|
|
40579
|
-
Examples:
|
|
40580
|
-
[FOR: reviewer, test_engineer] "Added validation \u2014 needs safety check"
|
|
40581
|
-
[FOR: architect] "Research: Tree-sitter supports TypeScript AST"
|
|
40582
|
-
[FOR: ALL] "Breaking change: StateManager renamed"
|
|
40583
|
-
This tag is informational in v6.19; v6.20 will use for context filtering.
|
|
40584
40770
|
`;
|
|
40585
40771
|
function createExplorerAgent(model, customPrompt, customAppendPrompt) {
|
|
40586
40772
|
let prompt = EXPLORER_PROMPT;
|
|
@@ -40632,6 +40818,30 @@ Your verdict is based ONLY on code quality, never on urgency or social pressure.
|
|
|
40632
40818
|
You are Reviewer. You verify code correctness and find vulnerabilities directly \u2014 you do NOT delegate.
|
|
40633
40819
|
DO NOT use the Task tool to delegate to other agents. You ARE the agent that does the work.
|
|
40634
40820
|
|
|
40821
|
+
## REVIEW FOCUS
|
|
40822
|
+
You are reviewing a CHANGE, not a FILE.
|
|
40823
|
+
1. WHAT CHANGED: Focus on the diff \u2014 the new or modified code
|
|
40824
|
+
2. WHAT IT AFFECTS: Code paths that interact with the changed code (callers, consumers, dependents)
|
|
40825
|
+
3. WHAT COULD BREAK: Callers, consumers, and dependents of changed interfaces
|
|
40826
|
+
|
|
40827
|
+
DO NOT:
|
|
40828
|
+
- Report pre-existing issues in unchanged code (that is a separate task)
|
|
40829
|
+
- Re-review code that passed review in a prior task
|
|
40830
|
+
- Flag style issues the linter should catch (automated gates handle that)
|
|
40831
|
+
|
|
40832
|
+
Your unique value is catching LOGIC ERRORS, EDGE CASES, and SECURITY FLAWS that automated tools cannot detect. If your review only catches things a linter would catch, you are not adding value.
|
|
40833
|
+
|
|
40834
|
+
## REVIEW REASONING
|
|
40835
|
+
For each changed function or method, answer these before formulating issues:
|
|
40836
|
+
1. PRECONDITIONS: What must be true for this code to work correctly?
|
|
40837
|
+
2. POSTCONDITIONS: What should be true after this code runs?
|
|
40838
|
+
3. INVARIANTS: What should NEVER change regardless of input?
|
|
40839
|
+
4. EDGE CASES: What happens with empty/null/undefined/max/concurrent inputs?
|
|
40840
|
+
5. CONTRACT: Does this change any public API signatures or return types?
|
|
40841
|
+
|
|
40842
|
+
Only formulate ISSUES based on violations of these properties.
|
|
40843
|
+
Do NOT generate issues from vibes or pattern-matching alone.
|
|
40844
|
+
|
|
40635
40845
|
## REVIEW STRUCTURE \u2014 THREE TIERS
|
|
40636
40846
|
|
|
40637
40847
|
STEP 0: INTENT RECONSTRUCTION (mandatory, before Tier 1)
|
|
@@ -40663,10 +40873,14 @@ VERBOSITY CONTROL: Token budget \u2264800 tokens. TRIVIAL APPROVED = 2-3 lines.
|
|
|
40663
40873
|
|
|
40664
40874
|
## INPUT FORMAT
|
|
40665
40875
|
TASK: Review [description]
|
|
40666
|
-
FILE: [
|
|
40876
|
+
FILE: [primary changed file or diff entry point]
|
|
40877
|
+
DIFF: [changed files/functions, or "infer from FILE" if omitted]
|
|
40878
|
+
AFFECTS: [callers/consumers/dependents to inspect, or "infer from diff"]
|
|
40667
40879
|
CHECK: [list of dimensions to evaluate]
|
|
40668
40880
|
|
|
40669
|
-
## OUTPUT FORMAT
|
|
40881
|
+
## OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected)
|
|
40882
|
+
Begin directly with VERDICT. Do NOT prepend "Here's my review..." or any conversational preamble.
|
|
40883
|
+
|
|
40670
40884
|
VERDICT: APPROVED | REJECTED
|
|
40671
40885
|
RISK: LOW | MEDIUM | HIGH | CRITICAL
|
|
40672
40886
|
ISSUES: list with line numbers, grouped by CHECK dimension
|
|
@@ -40684,15 +40898,6 @@ FIXES: required changes if rejected
|
|
|
40684
40898
|
- HIGH: must fix
|
|
40685
40899
|
- CRITICAL: blocks approval
|
|
40686
40900
|
|
|
40687
|
-
ROLE-RELEVANCE TAGGING
|
|
40688
|
-
When writing output consumed by other agents, prefix with:
|
|
40689
|
-
[FOR: agent1, agent2] \u2014 relevant to specific agents
|
|
40690
|
-
[FOR: ALL] \u2014 relevant to all agents
|
|
40691
|
-
Examples:
|
|
40692
|
-
[FOR: reviewer, test_engineer] "Added validation \u2014 needs safety check"
|
|
40693
|
-
[FOR: architect] "Research: Tree-sitter supports TypeScript AST"
|
|
40694
|
-
[FOR: ALL] "Breaking change: StateManager renamed"
|
|
40695
|
-
This tag is informational in v6.19; v6.20 will use for context filtering.
|
|
40696
40901
|
`;
|
|
40697
40902
|
function createReviewerAgent(model, customPrompt, customAppendPrompt) {
|
|
40698
40903
|
let prompt = REVIEWER_PROMPT;
|
|
@@ -40724,6 +40929,23 @@ var SME_PROMPT = `## IDENTITY
|
|
|
40724
40929
|
You are SME (Subject Matter Expert). You provide deep domain-specific technical guidance directly \u2014 you do NOT delegate.
|
|
40725
40930
|
DO NOT use the Task tool to delegate to other agents. You ARE the agent that does the work.
|
|
40726
40931
|
|
|
40932
|
+
## RESEARCH PROTOCOL
|
|
40933
|
+
When consulting on a domain question, follow these steps in order:
|
|
40934
|
+
1. FRAME: Restate the question in one sentence to confirm understanding
|
|
40935
|
+
2. CONTEXT: What you already know from training about this domain
|
|
40936
|
+
3. CONSTRAINTS: Platform, language, or framework constraints that apply
|
|
40937
|
+
4. RECOMMENDATION: Your specific, actionable recommendation
|
|
40938
|
+
5. ALTERNATIVES: Other viable approaches (max 2) with trade-offs
|
|
40939
|
+
6. RISKS: What could go wrong with the recommended approach
|
|
40940
|
+
7. CONFIDENCE: HIGH / MEDIUM / LOW (see calibration below)
|
|
40941
|
+
|
|
40942
|
+
## CONFIDENCE CALIBRATION
|
|
40943
|
+
- HIGH: You can cite specific documentation, RFCs, or well-established patterns
|
|
40944
|
+
- MEDIUM: You are reasoning from general principles and similar patterns
|
|
40945
|
+
- LOW: You are speculating, or the domain is rapidly evolving \u2014 use this honestly
|
|
40946
|
+
|
|
40947
|
+
DO NOT inflate confidence. A LOW-confidence honest answer is MORE VALUABLE than a HIGH-confidence wrong answer. The architect routes decisions based on your confidence level.
|
|
40948
|
+
|
|
40727
40949
|
## RESEARCH DEPTH & CONFIDENCE
|
|
40728
40950
|
State confidence level with EVERY finding:
|
|
40729
40951
|
- HIGH: verified from multiple sources or direct documentation
|
|
@@ -40734,7 +40956,8 @@ State confidence level with EVERY finding:
|
|
|
40734
40956
|
If returning cached result, check cachedAt timestamp against TTL. If approaching TTL, flag as STALE_RISK.
|
|
40735
40957
|
|
|
40736
40958
|
## SCOPE BOUNDARY
|
|
40737
|
-
You research and report. You
|
|
40959
|
+
You research and report. You MAY recommend domain-specific approaches, APIs, constraints, and trade-offs that the implementation should follow.
|
|
40960
|
+
You do NOT make final architecture decisions, choose product scope, or write code. Those are the Architect's and Coder's domains.
|
|
40738
40961
|
|
|
40739
40962
|
## PLATFORM AWARENESS
|
|
40740
40963
|
When researching file system operations, Node.js APIs, path handling, process management, or any OS-interaction pattern, explicitly verify cross-platform compatibility (Windows, macOS, Linux). Flag any API where behavior differs across platforms (e.g., fs.renameSync cannot atomically overwrite existing directories on Windows).
|
|
@@ -40747,7 +40970,9 @@ TASK: [what guidance is needed]
|
|
|
40747
40970
|
DOMAIN: [the domain - e.g., security, ios, android, rust, kubernetes]
|
|
40748
40971
|
INPUT: [context/requirements]
|
|
40749
40972
|
|
|
40750
|
-
## OUTPUT FORMAT
|
|
40973
|
+
## OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected)
|
|
40974
|
+
Begin directly with CONFIDENCE. Do NOT prepend "Here's my research..." or any conversational preamble.
|
|
40975
|
+
|
|
40751
40976
|
CONFIDENCE: HIGH | MEDIUM | LOW
|
|
40752
40977
|
CRITICAL: [key domain-specific considerations]
|
|
40753
40978
|
APPROACH: [recommended implementation approach]
|
|
@@ -40770,15 +40995,6 @@ Before fetching URL, check .swarm/context.md for ## Research Sources.
|
|
|
40770
40995
|
- Cache bypass: if user requests fresh research
|
|
40771
40996
|
- SME is read-only. Cache persistence is Architect's responsibility.
|
|
40772
40997
|
|
|
40773
|
-
ROLE-RELEVANCE TAGGING
|
|
40774
|
-
When writing output consumed by other agents, prefix with:
|
|
40775
|
-
[FOR: agent1, agent2] \u2014 relevant to specific agents
|
|
40776
|
-
[FOR: ALL] \u2014 relevant to all agents
|
|
40777
|
-
Examples:
|
|
40778
|
-
[FOR: reviewer, test_engineer] "Added validation \u2014 needs safety check"
|
|
40779
|
-
[FOR: architect] "Research: Tree-sitter supports TypeScript AST"
|
|
40780
|
-
[FOR: ALL] "Breaking change: StateManager renamed"
|
|
40781
|
-
This tag is informational in v6.19; v6.20 will use for context filtering.
|
|
40782
40998
|
`;
|
|
40783
40999
|
function createSMEAgent(model, customPrompt, customAppendPrompt) {
|
|
40784
41000
|
let prompt = SME_PROMPT;
|
|
@@ -40875,27 +41091,79 @@ SECURITY GUIDANCE (MANDATORY):
|
|
|
40875
41091
|
- SANITIZE sensitive absolute paths and stack traces before reporting (replace with [REDACTED] or generic paths)
|
|
40876
41092
|
- Apply redaction to any failure output that may contain credentials, keys, tokens, or sensitive system paths
|
|
40877
41093
|
|
|
40878
|
-
|
|
40879
|
-
|
|
41094
|
+
## ASSERTION QUALITY RULES
|
|
41095
|
+
|
|
41096
|
+
### BANNED \u2014 These are test theater. NEVER use:
|
|
41097
|
+
- \`expect(result).toBeTruthy()\` \u2014 USE: \`expect(result).toBe(specificValue)\`
|
|
41098
|
+
- \`expect(result).toBeDefined()\` \u2014 USE: \`expect(result).toEqual(expectedShape)\`
|
|
41099
|
+
- \`expect(array).toBeInstanceOf(Array)\` \u2014 USE: \`expect(array).toEqual([specific, items])\`
|
|
41100
|
+
- \`expect(fn).not.toThrow()\` alone \u2014 USE: \`expect(fn()).toBe(expectedReturn)\`
|
|
41101
|
+
- Tests that only check "it doesn't crash" \u2014 that is not a test, it is hope
|
|
41102
|
+
|
|
41103
|
+
### REQUIRED \u2014 Every test MUST have at least one of:
|
|
41104
|
+
1. EXACT VALUE: \`expect(result).toBe(42)\` or \`expect(result).toEqual({specific: 'shape'})\`
|
|
41105
|
+
2. STATE CHANGE: \`expect(countAfter - countBefore).toBe(1)\`
|
|
41106
|
+
3. ERROR WITH MESSAGE: \`expect(() => fn()).toThrow('specific message')\`
|
|
41107
|
+
4. CALL VERIFICATION: \`expect(mock).toHaveBeenCalledWith(specific, args)\`
|
|
41108
|
+
|
|
41109
|
+
### TEST STRUCTURE \u2014 Every test file MUST include:
|
|
41110
|
+
1. HAPPY PATH: Normal inputs \u2192 expected exact output values
|
|
41111
|
+
2. ERROR PATH: Invalid inputs \u2192 specific error behavior
|
|
41112
|
+
3. BOUNDARY: Empty input, null/undefined, max values, Unicode, special characters
|
|
41113
|
+
4. STATE MUTATION: If function modifies state, assert the value before AND after
|
|
41114
|
+
|
|
41115
|
+
## PROPERTY-BASED TESTING
|
|
41116
|
+
|
|
41117
|
+
For functions with mathematical or logical properties, define INVARIANTS rather than only example-based tests:
|
|
41118
|
+
- IDEMPOTENCY: f(f(x)) === f(x) for operations that should be stable
|
|
41119
|
+
- ROUND-TRIP: decode(encode(x)) === x for serialization
|
|
41120
|
+
- MONOTONICITY: if a < b then f(a) <= f(b) for sorting/ordering
|
|
41121
|
+
- PRESERVATION: output.length === input.length for transformations
|
|
41122
|
+
|
|
41123
|
+
Property tests are MORE VALUABLE than example tests because they:
|
|
41124
|
+
1. Test invariants the code author might not have considered
|
|
41125
|
+
2. Use varied inputs that bypass confirmation bias
|
|
41126
|
+
3. Catch edge cases that hand-picked examples miss
|
|
41127
|
+
|
|
41128
|
+
When a function has a clear mathematical property, write at least one property-based test alongside your example tests.
|
|
41129
|
+
|
|
41130
|
+
## SELF-REVIEW (mandatory before reporting verdict)
|
|
41131
|
+
|
|
41132
|
+
Before reporting your VERDICT, run this checklist:
|
|
41133
|
+
1. Re-read the SOURCE file being tested
|
|
41134
|
+
2. Count the public functions/methods/exports
|
|
41135
|
+
3. Confirm EVERY public function has at least one test
|
|
41136
|
+
4. Confirm every test has at least one EXACT VALUE assertion (not toBeTruthy/toBeDefined)
|
|
41137
|
+
5. If any gap: write the missing test before reporting
|
|
41138
|
+
|
|
41139
|
+
COVERAGE FLOOR: If you tested fewer than 80% of public functions, report:
|
|
41140
|
+
INCOMPLETE \u2014 [N] of [M] public functions tested. Missing: [list of untested functions]
|
|
41141
|
+
Do NOT report PASS/FAIL until coverage is at least 80%.
|
|
41142
|
+
|
|
41143
|
+
## EXECUTION VERIFICATION
|
|
41144
|
+
|
|
41145
|
+
After writing tests, you MUST run them. A test file that was written but never executed is NOT a deliverable.
|
|
41146
|
+
|
|
41147
|
+
When tests fail:
|
|
41148
|
+
- FIRST: Check if the failure reveals a bug in the SOURCE code (this is a GOOD outcome \u2014 report it)
|
|
41149
|
+
- SECOND: Check if the failure reveals a bug in your TEST (fix the test)
|
|
41150
|
+
- NEVER: Weaken assertions to make tests pass (e.g., changing toBe(42) to toBeTruthy())
|
|
41151
|
+
Weakening assertions to pass is the definition of test theater.
|
|
41152
|
+
|
|
41153
|
+
OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
|
|
41154
|
+
Begin directly with the VERDICT line. Do NOT prepend "Here's my analysis..." or any conversational preamble.
|
|
41155
|
+
|
|
41156
|
+
VERDICT: PASS [N/N tests passed] | FAIL [N passed, M failed]
|
|
40880
41157
|
TESTS: [total count] tests, [pass count] passed, [fail count] failed
|
|
40881
41158
|
FAILURES: [list of failed test names + error messages, if any]
|
|
40882
|
-
COVERAGE: [areas covered]
|
|
41159
|
+
COVERAGE: [X]% of public functions \u2014 [areas covered]
|
|
41160
|
+
BUGS FOUND: [list any source code bugs discovered during testing, or "none"]
|
|
40883
41161
|
|
|
40884
41162
|
COVERAGE REPORTING:
|
|
40885
41163
|
- After running tests, report the line/branch coverage percentage if the test runner provides it.
|
|
40886
41164
|
- Format: COVERAGE_PCT: [N]% (or "N/A" if not available)
|
|
40887
41165
|
- If COVERAGE_PCT < 70%, add a note: "COVERAGE_WARNING: Below 70% threshold \u2014 consider additional test cases for uncovered paths."
|
|
40888
41166
|
- The architect uses this to decide whether to request an additional test pass (Rule 10 / Phase 5 step 5h).
|
|
40889
|
-
|
|
40890
|
-
ROLE-RELEVANCE TAGGING
|
|
40891
|
-
When writing output consumed by other agents, prefix with:
|
|
40892
|
-
[FOR: agent1, agent2] \u2014 relevant to specific agents
|
|
40893
|
-
[FOR: ALL] \u2014 relevant to all agents
|
|
40894
|
-
Examples:
|
|
40895
|
-
[FOR: reviewer, test_engineer] "Added validation \u2014 needs safety check"
|
|
40896
|
-
[FOR: architect] "Research: Tree-sitter supports TypeScript AST"
|
|
40897
|
-
[FOR: ALL] "Breaking change: StateManager renamed"
|
|
40898
|
-
This tag is informational in v6.19; v6.20 will use for context filtering.
|
|
40899
41167
|
`;
|
|
40900
41168
|
function createTestEngineerAgent(model, customPrompt, customAppendPrompt) {
|
|
40901
41169
|
let prompt = TEST_ENGINEER_PROMPT;
|
|
@@ -48774,6 +49042,28 @@ function createDelegationGateHook(config3) {
|
|
|
48774
49042
|
}
|
|
48775
49043
|
}
|
|
48776
49044
|
}
|
|
49045
|
+
if (typeof subagentType === "string") {
|
|
49046
|
+
const evidenceTaskId = session.currentTaskId ?? session.lastCoderDelegationTaskId;
|
|
49047
|
+
if (evidenceTaskId) {
|
|
49048
|
+
try {
|
|
49049
|
+
const gateAgents = [
|
|
49050
|
+
"reviewer",
|
|
49051
|
+
"test_engineer",
|
|
49052
|
+
"docs",
|
|
49053
|
+
"designer",
|
|
49054
|
+
"critic"
|
|
49055
|
+
];
|
|
49056
|
+
const targetAgentForEvidence = stripKnownSwarmPrefix(subagentType);
|
|
49057
|
+
if (gateAgents.includes(targetAgentForEvidence)) {
|
|
49058
|
+
const { recordGateEvidence: recordGateEvidence2 } = await Promise.resolve().then(() => (init_gate_evidence(), exports_gate_evidence));
|
|
49059
|
+
await recordGateEvidence2(process.cwd(), evidenceTaskId, targetAgentForEvidence, input.sessionID);
|
|
49060
|
+
} else {
|
|
49061
|
+
const { recordAgentDispatch: recordAgentDispatch2 } = await Promise.resolve().then(() => (init_gate_evidence(), exports_gate_evidence));
|
|
49062
|
+
await recordAgentDispatch2(process.cwd(), evidenceTaskId, targetAgentForEvidence);
|
|
49063
|
+
}
|
|
49064
|
+
} catch {}
|
|
49065
|
+
}
|
|
49066
|
+
}
|
|
48777
49067
|
if (storedArgs !== undefined) {
|
|
48778
49068
|
deleteStoredInputArgs(input.callID);
|
|
48779
49069
|
}
|
|
@@ -48866,6 +49156,21 @@ function createDelegationGateHook(config3) {
|
|
|
48866
49156
|
}
|
|
48867
49157
|
}
|
|
48868
49158
|
}
|
|
49159
|
+
{
|
|
49160
|
+
const evidenceTaskId = session.currentTaskId ?? session.lastCoderDelegationTaskId;
|
|
49161
|
+
if (evidenceTaskId) {
|
|
49162
|
+
try {
|
|
49163
|
+
if (hasReviewer) {
|
|
49164
|
+
const { recordGateEvidence: recordGateEvidence2 } = await Promise.resolve().then(() => (init_gate_evidence(), exports_gate_evidence));
|
|
49165
|
+
await recordGateEvidence2(process.cwd(), evidenceTaskId, "reviewer", input.sessionID);
|
|
49166
|
+
}
|
|
49167
|
+
if (hasTestEngineer) {
|
|
49168
|
+
const { recordGateEvidence: recordGateEvidence2 } = await Promise.resolve().then(() => (init_gate_evidence(), exports_gate_evidence));
|
|
49169
|
+
await recordGateEvidence2(process.cwd(), evidenceTaskId, "test_engineer", input.sessionID);
|
|
49170
|
+
}
|
|
49171
|
+
} catch {}
|
|
49172
|
+
}
|
|
49173
|
+
}
|
|
48869
49174
|
}
|
|
48870
49175
|
}
|
|
48871
49176
|
};
|
|
@@ -49057,11 +49362,11 @@ ${trimComment}${after}`;
|
|
|
49057
49362
|
if (!hasReviewer || !hasTestEngineer || priorTaskStuckAtCoder) {
|
|
49058
49363
|
if (session.qaSkipCount >= 1) {
|
|
49059
49364
|
const skippedTasks = session.qaSkipTaskIds.join(", ");
|
|
49060
|
-
throw new Error(`\uD83D\uDED1 QA GATE ENFORCEMENT: ${session.qaSkipCount + 1} consecutive coder delegations without reviewer/test_engineer.
|
|
49365
|
+
throw new Error(`\uD83D\uDED1 QA GATE ENFORCEMENT: ${session.qaSkipCount + 1} consecutive coder delegations without reviewer/test_engineer. Skipped tasks: [${skippedTasks}]. DELEGATE to reviewer and test_engineer NOW before any further coder work.`);
|
|
49061
49366
|
}
|
|
49062
49367
|
session.qaSkipCount++;
|
|
49063
49368
|
session.qaSkipTaskIds.push(currentTaskId ?? "unknown");
|
|
49064
|
-
warnings.push(`\u26A0\uFE0F PROTOCOL VIOLATION: Previous coder task completed, but QA gate was skipped. ` + `You MUST delegate to reviewer (code review) and test_engineer (test execution)
|
|
49369
|
+
warnings.push(`\u26A0\uFE0F PROTOCOL VIOLATION: Previous coder task completed, but QA gate was skipped. ` + `You MUST delegate to reviewer (code review) and test_engineer (test execution) before starting a new coder task. Review RULES 7-8 in your system prompt.`);
|
|
49065
49370
|
}
|
|
49066
49371
|
}
|
|
49067
49372
|
}
|
|
@@ -49413,7 +49718,7 @@ import * as fs16 from "fs";
|
|
|
49413
49718
|
init_utils2();
|
|
49414
49719
|
init_manager2();
|
|
49415
49720
|
import * as fs15 from "fs";
|
|
49416
|
-
import * as
|
|
49721
|
+
import * as path28 from "path";
|
|
49417
49722
|
var DEFAULT_DRIFT_CONFIG = {
|
|
49418
49723
|
staleThresholdPhases: 1,
|
|
49419
49724
|
detectContradictions: true,
|
|
@@ -49567,7 +49872,7 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
|
|
|
49567
49872
|
currentPhase = legacyPhase;
|
|
49568
49873
|
}
|
|
49569
49874
|
}
|
|
49570
|
-
const contextPath =
|
|
49875
|
+
const contextPath = path28.join(directory, ".swarm", "context.md");
|
|
49571
49876
|
let contextContent = "";
|
|
49572
49877
|
try {
|
|
49573
49878
|
if (fs15.existsSync(contextPath)) {
|
|
@@ -51190,7 +51495,7 @@ function createDarkMatterDetectorHook(directory) {
|
|
|
51190
51495
|
// src/hooks/knowledge-reader.ts
|
|
51191
51496
|
import { existsSync as existsSync18 } from "fs";
|
|
51192
51497
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
51193
|
-
import * as
|
|
51498
|
+
import * as path29 from "path";
|
|
51194
51499
|
var JACCARD_THRESHOLD = 0.6;
|
|
51195
51500
|
var HIVE_TIER_BOOST = 0.05;
|
|
51196
51501
|
var SAME_PROJECT_PENALTY = -0.05;
|
|
@@ -51238,7 +51543,7 @@ function inferCategoriesFromPhase(phaseDescription) {
|
|
|
51238
51543
|
return ["process", "tooling"];
|
|
51239
51544
|
}
|
|
51240
51545
|
async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
51241
|
-
const shownFile =
|
|
51546
|
+
const shownFile = path29.join(directory, ".swarm", ".knowledge-shown.json");
|
|
51242
51547
|
try {
|
|
51243
51548
|
let shownData = {};
|
|
51244
51549
|
if (existsSync18(shownFile)) {
|
|
@@ -51246,7 +51551,7 @@ async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
|
51246
51551
|
shownData = JSON.parse(content);
|
|
51247
51552
|
}
|
|
51248
51553
|
shownData[currentPhase] = lessonIds;
|
|
51249
|
-
await mkdir4(
|
|
51554
|
+
await mkdir4(path29.dirname(shownFile), { recursive: true });
|
|
51250
51555
|
await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
|
|
51251
51556
|
} catch {
|
|
51252
51557
|
console.warn("[swarm] Knowledge: failed to record shown lessons");
|
|
@@ -51341,7 +51646,7 @@ async function readMergedKnowledge(directory, config3, context) {
|
|
|
51341
51646
|
return topN;
|
|
51342
51647
|
}
|
|
51343
51648
|
async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
|
|
51344
|
-
const shownFile =
|
|
51649
|
+
const shownFile = path29.join(directory, ".swarm", ".knowledge-shown.json");
|
|
51345
51650
|
try {
|
|
51346
51651
|
if (!existsSync18(shownFile)) {
|
|
51347
51652
|
return;
|
|
@@ -51814,10 +52119,10 @@ Use this data to avoid repeating known failure patterns.`;
|
|
|
51814
52119
|
init_event_bus();
|
|
51815
52120
|
init_utils2();
|
|
51816
52121
|
import * as fs17 from "fs";
|
|
51817
|
-
import * as
|
|
52122
|
+
import * as path30 from "path";
|
|
51818
52123
|
var DRIFT_REPORT_PREFIX = "drift-report-phase-";
|
|
51819
52124
|
async function readPriorDriftReports(directory) {
|
|
51820
|
-
const swarmDir =
|
|
52125
|
+
const swarmDir = path30.join(directory, ".swarm");
|
|
51821
52126
|
const entries = await fs17.promises.readdir(swarmDir).catch(() => null);
|
|
51822
52127
|
if (entries === null)
|
|
51823
52128
|
return [];
|
|
@@ -51844,7 +52149,7 @@ async function readPriorDriftReports(directory) {
|
|
|
51844
52149
|
async function writeDriftReport(directory, report) {
|
|
51845
52150
|
const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
|
|
51846
52151
|
const filePath = validateSwarmPath(directory, filename);
|
|
51847
|
-
const swarmDir =
|
|
52152
|
+
const swarmDir = path30.dirname(filePath);
|
|
51848
52153
|
await fs17.promises.mkdir(swarmDir, { recursive: true });
|
|
51849
52154
|
try {
|
|
51850
52155
|
await fs17.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
|
|
@@ -52153,7 +52458,7 @@ init_config_doctor();
|
|
|
52153
52458
|
|
|
52154
52459
|
// src/session/snapshot-reader.ts
|
|
52155
52460
|
init_utils2();
|
|
52156
|
-
import
|
|
52461
|
+
import path31 from "path";
|
|
52157
52462
|
var VALID_TASK_WORKFLOW_STATES = [
|
|
52158
52463
|
"idle",
|
|
52159
52464
|
"coder_delegated",
|
|
@@ -52276,7 +52581,7 @@ function rehydrateState(snapshot) {
|
|
|
52276
52581
|
async function reconcileTaskStatesFromPlan(directory) {
|
|
52277
52582
|
let raw;
|
|
52278
52583
|
try {
|
|
52279
|
-
raw = await Bun.file(
|
|
52584
|
+
raw = await Bun.file(path31.join(directory, ".swarm/plan.json")).text();
|
|
52280
52585
|
} catch {
|
|
52281
52586
|
return;
|
|
52282
52587
|
}
|
|
@@ -52500,7 +52805,7 @@ init_tool();
|
|
|
52500
52805
|
init_create_tool();
|
|
52501
52806
|
import { spawnSync } from "child_process";
|
|
52502
52807
|
import * as fs19 from "fs";
|
|
52503
|
-
import * as
|
|
52808
|
+
import * as path32 from "path";
|
|
52504
52809
|
var CHECKPOINT_LOG_PATH = ".swarm/checkpoints.json";
|
|
52505
52810
|
var MAX_LABEL_LENGTH = 100;
|
|
52506
52811
|
var GIT_TIMEOUT_MS = 30000;
|
|
@@ -52551,7 +52856,7 @@ function validateLabel(label) {
|
|
|
52551
52856
|
return null;
|
|
52552
52857
|
}
|
|
52553
52858
|
function getCheckpointLogPath(directory) {
|
|
52554
|
-
return
|
|
52859
|
+
return path32.join(directory, CHECKPOINT_LOG_PATH);
|
|
52555
52860
|
}
|
|
52556
52861
|
function readCheckpointLog(directory) {
|
|
52557
52862
|
const logPath = getCheckpointLogPath(directory);
|
|
@@ -52569,7 +52874,7 @@ function readCheckpointLog(directory) {
|
|
|
52569
52874
|
}
|
|
52570
52875
|
function writeCheckpointLog(log2, directory) {
|
|
52571
52876
|
const logPath = getCheckpointLogPath(directory);
|
|
52572
|
-
const dir =
|
|
52877
|
+
const dir = path32.dirname(logPath);
|
|
52573
52878
|
if (!fs19.existsSync(dir)) {
|
|
52574
52879
|
fs19.mkdirSync(dir, { recursive: true });
|
|
52575
52880
|
}
|
|
@@ -52777,7 +53082,7 @@ var checkpoint = createSwarmTool({
|
|
|
52777
53082
|
init_dist();
|
|
52778
53083
|
init_create_tool();
|
|
52779
53084
|
import * as fs20 from "fs";
|
|
52780
|
-
import * as
|
|
53085
|
+
import * as path33 from "path";
|
|
52781
53086
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
52782
53087
|
var DEFAULT_DAYS = 90;
|
|
52783
53088
|
var DEFAULT_TOP_N = 20;
|
|
@@ -52921,7 +53226,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
52921
53226
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
52922
53227
|
const filteredChurn = new Map;
|
|
52923
53228
|
for (const [file3, count] of churnMap) {
|
|
52924
|
-
const ext =
|
|
53229
|
+
const ext = path33.extname(file3).toLowerCase();
|
|
52925
53230
|
if (extSet.has(ext)) {
|
|
52926
53231
|
filteredChurn.set(file3, count);
|
|
52927
53232
|
}
|
|
@@ -52932,7 +53237,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
52932
53237
|
for (const [file3, churnCount] of filteredChurn) {
|
|
52933
53238
|
let fullPath = file3;
|
|
52934
53239
|
if (!fs20.existsSync(fullPath)) {
|
|
52935
|
-
fullPath =
|
|
53240
|
+
fullPath = path33.join(cwd, file3);
|
|
52936
53241
|
}
|
|
52937
53242
|
const complexity = getComplexityForFile(fullPath);
|
|
52938
53243
|
if (complexity !== null) {
|
|
@@ -53080,7 +53385,7 @@ var complexity_hotspots = createSwarmTool({
|
|
|
53080
53385
|
// src/tools/declare-scope.ts
|
|
53081
53386
|
init_tool();
|
|
53082
53387
|
import * as fs21 from "fs";
|
|
53083
|
-
import * as
|
|
53388
|
+
import * as path34 from "path";
|
|
53084
53389
|
init_create_tool();
|
|
53085
53390
|
function validateTaskIdFormat(taskId) {
|
|
53086
53391
|
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -53159,8 +53464,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
53159
53464
|
};
|
|
53160
53465
|
}
|
|
53161
53466
|
}
|
|
53162
|
-
normalizedDir =
|
|
53163
|
-
const pathParts = normalizedDir.split(
|
|
53467
|
+
normalizedDir = path34.normalize(args2.working_directory);
|
|
53468
|
+
const pathParts = normalizedDir.split(path34.sep);
|
|
53164
53469
|
if (pathParts.includes("..")) {
|
|
53165
53470
|
return {
|
|
53166
53471
|
success: false,
|
|
@@ -53170,10 +53475,10 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
53170
53475
|
]
|
|
53171
53476
|
};
|
|
53172
53477
|
}
|
|
53173
|
-
const resolvedDir =
|
|
53478
|
+
const resolvedDir = path34.resolve(normalizedDir);
|
|
53174
53479
|
try {
|
|
53175
53480
|
const realPath = fs21.realpathSync(resolvedDir);
|
|
53176
|
-
const planPath2 =
|
|
53481
|
+
const planPath2 = path34.join(realPath, ".swarm", "plan.json");
|
|
53177
53482
|
if (!fs21.existsSync(planPath2)) {
|
|
53178
53483
|
return {
|
|
53179
53484
|
success: false,
|
|
@@ -53194,7 +53499,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
53194
53499
|
}
|
|
53195
53500
|
}
|
|
53196
53501
|
const directory = normalizedDir ?? fallbackDir ?? process.cwd();
|
|
53197
|
-
const planPath =
|
|
53502
|
+
const planPath = path34.resolve(directory, ".swarm", "plan.json");
|
|
53198
53503
|
if (!fs21.existsSync(planPath)) {
|
|
53199
53504
|
return {
|
|
53200
53505
|
success: false,
|
|
@@ -53284,20 +53589,20 @@ function validateBase(base) {
|
|
|
53284
53589
|
function validatePaths(paths) {
|
|
53285
53590
|
if (!paths)
|
|
53286
53591
|
return null;
|
|
53287
|
-
for (const
|
|
53288
|
-
if (!
|
|
53592
|
+
for (const path35 of paths) {
|
|
53593
|
+
if (!path35 || path35.length === 0) {
|
|
53289
53594
|
return "empty path not allowed";
|
|
53290
53595
|
}
|
|
53291
|
-
if (
|
|
53596
|
+
if (path35.length > MAX_PATH_LENGTH) {
|
|
53292
53597
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
53293
53598
|
}
|
|
53294
|
-
if (SHELL_METACHARACTERS2.test(
|
|
53599
|
+
if (SHELL_METACHARACTERS2.test(path35)) {
|
|
53295
53600
|
return "path contains shell metacharacters";
|
|
53296
53601
|
}
|
|
53297
|
-
if (
|
|
53602
|
+
if (path35.startsWith("-")) {
|
|
53298
53603
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
53299
53604
|
}
|
|
53300
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
53605
|
+
if (CONTROL_CHAR_PATTERN2.test(path35)) {
|
|
53301
53606
|
return "path contains control characters";
|
|
53302
53607
|
}
|
|
53303
53608
|
}
|
|
@@ -53377,8 +53682,8 @@ var diff = tool({
|
|
|
53377
53682
|
if (parts2.length >= 3) {
|
|
53378
53683
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
53379
53684
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
53380
|
-
const
|
|
53381
|
-
files.push({ path:
|
|
53685
|
+
const path35 = parts2[2];
|
|
53686
|
+
files.push({ path: path35, additions, deletions });
|
|
53382
53687
|
}
|
|
53383
53688
|
}
|
|
53384
53689
|
const contractChanges = [];
|
|
@@ -53608,7 +53913,7 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
53608
53913
|
init_dist();
|
|
53609
53914
|
init_create_tool();
|
|
53610
53915
|
import * as fs22 from "fs";
|
|
53611
|
-
import * as
|
|
53916
|
+
import * as path35 from "path";
|
|
53612
53917
|
var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
|
|
53613
53918
|
var MAX_EVIDENCE_FILES = 1000;
|
|
53614
53919
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
@@ -53631,9 +53936,9 @@ function validateRequiredTypes(input) {
|
|
|
53631
53936
|
return null;
|
|
53632
53937
|
}
|
|
53633
53938
|
function isPathWithinSwarm(filePath, cwd) {
|
|
53634
|
-
const normalizedCwd =
|
|
53635
|
-
const swarmPath =
|
|
53636
|
-
const normalizedPath =
|
|
53939
|
+
const normalizedCwd = path35.resolve(cwd);
|
|
53940
|
+
const swarmPath = path35.join(normalizedCwd, ".swarm");
|
|
53941
|
+
const normalizedPath = path35.resolve(filePath);
|
|
53637
53942
|
return normalizedPath.startsWith(swarmPath);
|
|
53638
53943
|
}
|
|
53639
53944
|
function parseCompletedTasks(planContent) {
|
|
@@ -53663,10 +53968,10 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
53663
53968
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
53664
53969
|
continue;
|
|
53665
53970
|
}
|
|
53666
|
-
const filePath =
|
|
53971
|
+
const filePath = path35.join(evidenceDir, filename);
|
|
53667
53972
|
try {
|
|
53668
|
-
const resolvedPath =
|
|
53669
|
-
const evidenceDirResolved =
|
|
53973
|
+
const resolvedPath = path35.resolve(filePath);
|
|
53974
|
+
const evidenceDirResolved = path35.resolve(evidenceDir);
|
|
53670
53975
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
53671
53976
|
continue;
|
|
53672
53977
|
}
|
|
@@ -53773,7 +54078,7 @@ var evidence_check = createSwarmTool({
|
|
|
53773
54078
|
return JSON.stringify(errorResult, null, 2);
|
|
53774
54079
|
}
|
|
53775
54080
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
53776
|
-
const planPath =
|
|
54081
|
+
const planPath = path35.join(cwd, PLAN_FILE);
|
|
53777
54082
|
if (!isPathWithinSwarm(planPath, cwd)) {
|
|
53778
54083
|
const errorResult = {
|
|
53779
54084
|
error: "plan file path validation failed",
|
|
@@ -53805,7 +54110,7 @@ var evidence_check = createSwarmTool({
|
|
|
53805
54110
|
};
|
|
53806
54111
|
return JSON.stringify(result2, null, 2);
|
|
53807
54112
|
}
|
|
53808
|
-
const evidenceDir =
|
|
54113
|
+
const evidenceDir = path35.join(cwd, EVIDENCE_DIR);
|
|
53809
54114
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
53810
54115
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
53811
54116
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -53823,7 +54128,7 @@ var evidence_check = createSwarmTool({
|
|
|
53823
54128
|
init_tool();
|
|
53824
54129
|
init_create_tool();
|
|
53825
54130
|
import * as fs23 from "fs";
|
|
53826
|
-
import * as
|
|
54131
|
+
import * as path36 from "path";
|
|
53827
54132
|
var EXT_MAP = {
|
|
53828
54133
|
python: ".py",
|
|
53829
54134
|
py: ".py",
|
|
@@ -53904,12 +54209,12 @@ var extract_code_blocks = createSwarmTool({
|
|
|
53904
54209
|
if (prefix) {
|
|
53905
54210
|
filename = `${prefix}_${filename}`;
|
|
53906
54211
|
}
|
|
53907
|
-
let filepath =
|
|
53908
|
-
const base =
|
|
53909
|
-
const ext =
|
|
54212
|
+
let filepath = path36.join(targetDir, filename);
|
|
54213
|
+
const base = path36.basename(filepath, path36.extname(filepath));
|
|
54214
|
+
const ext = path36.extname(filepath);
|
|
53910
54215
|
let counter = 1;
|
|
53911
54216
|
while (fs23.existsSync(filepath)) {
|
|
53912
|
-
filepath =
|
|
54217
|
+
filepath = path36.join(targetDir, `${base}_${counter}${ext}`);
|
|
53913
54218
|
counter++;
|
|
53914
54219
|
}
|
|
53915
54220
|
try {
|
|
@@ -54027,7 +54332,7 @@ var gitingest = tool({
|
|
|
54027
54332
|
// src/tools/imports.ts
|
|
54028
54333
|
init_dist();
|
|
54029
54334
|
import * as fs24 from "fs";
|
|
54030
|
-
import * as
|
|
54335
|
+
import * as path37 from "path";
|
|
54031
54336
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
54032
54337
|
var MAX_SYMBOL_LENGTH = 256;
|
|
54033
54338
|
var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
|
|
@@ -54081,7 +54386,7 @@ function validateSymbolInput(symbol3) {
|
|
|
54081
54386
|
return null;
|
|
54082
54387
|
}
|
|
54083
54388
|
function isBinaryFile2(filePath, buffer) {
|
|
54084
|
-
const ext =
|
|
54389
|
+
const ext = path37.extname(filePath).toLowerCase();
|
|
54085
54390
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
54086
54391
|
return false;
|
|
54087
54392
|
}
|
|
@@ -54105,15 +54410,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
54105
54410
|
const imports = [];
|
|
54106
54411
|
let _resolvedTarget;
|
|
54107
54412
|
try {
|
|
54108
|
-
_resolvedTarget =
|
|
54413
|
+
_resolvedTarget = path37.resolve(targetFile);
|
|
54109
54414
|
} catch {
|
|
54110
54415
|
_resolvedTarget = targetFile;
|
|
54111
54416
|
}
|
|
54112
|
-
const targetBasename =
|
|
54417
|
+
const targetBasename = path37.basename(targetFile, path37.extname(targetFile));
|
|
54113
54418
|
const targetWithExt = targetFile;
|
|
54114
54419
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
54115
|
-
const normalizedTargetWithExt =
|
|
54116
|
-
const normalizedTargetWithoutExt =
|
|
54420
|
+
const normalizedTargetWithExt = path37.normalize(targetWithExt).replace(/\\/g, "/");
|
|
54421
|
+
const normalizedTargetWithoutExt = path37.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
54117
54422
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
54118
54423
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
54119
54424
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -54136,9 +54441,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
54136
54441
|
}
|
|
54137
54442
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
54138
54443
|
let isMatch = false;
|
|
54139
|
-
const _targetDir =
|
|
54140
|
-
const targetExt =
|
|
54141
|
-
const targetBasenameNoExt =
|
|
54444
|
+
const _targetDir = path37.dirname(targetFile);
|
|
54445
|
+
const targetExt = path37.extname(targetFile);
|
|
54446
|
+
const targetBasenameNoExt = path37.basename(targetFile, targetExt);
|
|
54142
54447
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
54143
54448
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
54144
54449
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -54206,10 +54511,10 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
54206
54511
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
54207
54512
|
for (const entry of entries) {
|
|
54208
54513
|
if (SKIP_DIRECTORIES2.has(entry)) {
|
|
54209
|
-
stats.skippedDirs.push(
|
|
54514
|
+
stats.skippedDirs.push(path37.join(dir, entry));
|
|
54210
54515
|
continue;
|
|
54211
54516
|
}
|
|
54212
|
-
const fullPath =
|
|
54517
|
+
const fullPath = path37.join(dir, entry);
|
|
54213
54518
|
let stat2;
|
|
54214
54519
|
try {
|
|
54215
54520
|
stat2 = fs24.statSync(fullPath);
|
|
@@ -54223,7 +54528,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
54223
54528
|
if (stat2.isDirectory()) {
|
|
54224
54529
|
findSourceFiles2(fullPath, files, stats);
|
|
54225
54530
|
} else if (stat2.isFile()) {
|
|
54226
|
-
const ext =
|
|
54531
|
+
const ext = path37.extname(fullPath).toLowerCase();
|
|
54227
54532
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
54228
54533
|
files.push(fullPath);
|
|
54229
54534
|
}
|
|
@@ -54279,7 +54584,7 @@ var imports = tool({
|
|
|
54279
54584
|
return JSON.stringify(errorResult, null, 2);
|
|
54280
54585
|
}
|
|
54281
54586
|
try {
|
|
54282
|
-
const targetFile =
|
|
54587
|
+
const targetFile = path37.resolve(file3);
|
|
54283
54588
|
if (!fs24.existsSync(targetFile)) {
|
|
54284
54589
|
const errorResult = {
|
|
54285
54590
|
error: `target file not found: ${file3}`,
|
|
@@ -54301,7 +54606,7 @@ var imports = tool({
|
|
|
54301
54606
|
};
|
|
54302
54607
|
return JSON.stringify(errorResult, null, 2);
|
|
54303
54608
|
}
|
|
54304
|
-
const baseDir =
|
|
54609
|
+
const baseDir = path37.dirname(targetFile);
|
|
54305
54610
|
const scanStats = {
|
|
54306
54611
|
skippedDirs: [],
|
|
54307
54612
|
skippedFiles: 0,
|
|
@@ -54623,7 +54928,7 @@ init_config();
|
|
|
54623
54928
|
init_schema();
|
|
54624
54929
|
init_manager();
|
|
54625
54930
|
import * as fs25 from "fs";
|
|
54626
|
-
import * as
|
|
54931
|
+
import * as path38 from "path";
|
|
54627
54932
|
init_utils2();
|
|
54628
54933
|
init_create_tool();
|
|
54629
54934
|
function safeWarn(message, error93) {
|
|
@@ -54818,7 +55123,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
54818
55123
|
}
|
|
54819
55124
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
54820
55125
|
try {
|
|
54821
|
-
const projectName =
|
|
55126
|
+
const projectName = path38.basename(dir);
|
|
54822
55127
|
const knowledgeConfig = {
|
|
54823
55128
|
enabled: true,
|
|
54824
55129
|
swarm_max_entries: 100,
|
|
@@ -54982,7 +55287,7 @@ init_discovery();
|
|
|
54982
55287
|
init_utils();
|
|
54983
55288
|
init_create_tool();
|
|
54984
55289
|
import * as fs26 from "fs";
|
|
54985
|
-
import * as
|
|
55290
|
+
import * as path39 from "path";
|
|
54986
55291
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
54987
55292
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
54988
55293
|
function isValidEcosystem(value) {
|
|
@@ -55000,16 +55305,16 @@ function validateArgs3(args2) {
|
|
|
55000
55305
|
function detectEcosystems(directory) {
|
|
55001
55306
|
const ecosystems = [];
|
|
55002
55307
|
const cwd = directory;
|
|
55003
|
-
if (fs26.existsSync(
|
|
55308
|
+
if (fs26.existsSync(path39.join(cwd, "package.json"))) {
|
|
55004
55309
|
ecosystems.push("npm");
|
|
55005
55310
|
}
|
|
55006
|
-
if (fs26.existsSync(
|
|
55311
|
+
if (fs26.existsSync(path39.join(cwd, "pyproject.toml")) || fs26.existsSync(path39.join(cwd, "requirements.txt"))) {
|
|
55007
55312
|
ecosystems.push("pip");
|
|
55008
55313
|
}
|
|
55009
|
-
if (fs26.existsSync(
|
|
55314
|
+
if (fs26.existsSync(path39.join(cwd, "Cargo.toml"))) {
|
|
55010
55315
|
ecosystems.push("cargo");
|
|
55011
55316
|
}
|
|
55012
|
-
if (fs26.existsSync(
|
|
55317
|
+
if (fs26.existsSync(path39.join(cwd, "go.mod"))) {
|
|
55013
55318
|
ecosystems.push("go");
|
|
55014
55319
|
}
|
|
55015
55320
|
try {
|
|
@@ -55018,10 +55323,10 @@ function detectEcosystems(directory) {
|
|
|
55018
55323
|
ecosystems.push("dotnet");
|
|
55019
55324
|
}
|
|
55020
55325
|
} catch {}
|
|
55021
|
-
if (fs26.existsSync(
|
|
55326
|
+
if (fs26.existsSync(path39.join(cwd, "Gemfile")) || fs26.existsSync(path39.join(cwd, "Gemfile.lock"))) {
|
|
55022
55327
|
ecosystems.push("ruby");
|
|
55023
55328
|
}
|
|
55024
|
-
if (fs26.existsSync(
|
|
55329
|
+
if (fs26.existsSync(path39.join(cwd, "pubspec.yaml"))) {
|
|
55025
55330
|
ecosystems.push("dart");
|
|
55026
55331
|
}
|
|
55027
55332
|
return ecosystems;
|
|
@@ -56084,7 +56389,7 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
56084
56389
|
// src/tools/pre-check-batch.ts
|
|
56085
56390
|
init_dist();
|
|
56086
56391
|
import * as fs29 from "fs";
|
|
56087
|
-
import * as
|
|
56392
|
+
import * as path42 from "path";
|
|
56088
56393
|
|
|
56089
56394
|
// node_modules/yocto-queue/index.js
|
|
56090
56395
|
class Node2 {
|
|
@@ -56252,7 +56557,7 @@ init_manager();
|
|
|
56252
56557
|
|
|
56253
56558
|
// src/quality/metrics.ts
|
|
56254
56559
|
import * as fs27 from "fs";
|
|
56255
|
-
import * as
|
|
56560
|
+
import * as path40 from "path";
|
|
56256
56561
|
var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
|
|
56257
56562
|
var MIN_DUPLICATION_LINES = 10;
|
|
56258
56563
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -56304,7 +56609,7 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
56304
56609
|
let totalComplexity = 0;
|
|
56305
56610
|
const analyzedFiles = [];
|
|
56306
56611
|
for (const file3 of files) {
|
|
56307
|
-
const fullPath =
|
|
56612
|
+
const fullPath = path40.isAbsolute(file3) ? file3 : path40.join(workingDir, file3);
|
|
56308
56613
|
if (!fs27.existsSync(fullPath)) {
|
|
56309
56614
|
continue;
|
|
56310
56615
|
}
|
|
@@ -56427,7 +56732,7 @@ function countGoExports(content) {
|
|
|
56427
56732
|
function getExportCountForFile(filePath) {
|
|
56428
56733
|
try {
|
|
56429
56734
|
const content = fs27.readFileSync(filePath, "utf-8");
|
|
56430
|
-
const ext =
|
|
56735
|
+
const ext = path40.extname(filePath).toLowerCase();
|
|
56431
56736
|
switch (ext) {
|
|
56432
56737
|
case ".ts":
|
|
56433
56738
|
case ".tsx":
|
|
@@ -56453,7 +56758,7 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
56453
56758
|
let totalExports = 0;
|
|
56454
56759
|
const analyzedFiles = [];
|
|
56455
56760
|
for (const file3 of files) {
|
|
56456
|
-
const fullPath =
|
|
56761
|
+
const fullPath = path40.isAbsolute(file3) ? file3 : path40.join(workingDir, file3);
|
|
56457
56762
|
if (!fs27.existsSync(fullPath)) {
|
|
56458
56763
|
continue;
|
|
56459
56764
|
}
|
|
@@ -56487,7 +56792,7 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
56487
56792
|
let duplicateLines = 0;
|
|
56488
56793
|
const analyzedFiles = [];
|
|
56489
56794
|
for (const file3 of files) {
|
|
56490
|
-
const fullPath =
|
|
56795
|
+
const fullPath = path40.isAbsolute(file3) ? file3 : path40.join(workingDir, file3);
|
|
56491
56796
|
if (!fs27.existsSync(fullPath)) {
|
|
56492
56797
|
continue;
|
|
56493
56798
|
}
|
|
@@ -56520,8 +56825,8 @@ function countCodeLines(content) {
|
|
|
56520
56825
|
return lines.length;
|
|
56521
56826
|
}
|
|
56522
56827
|
function isTestFile(filePath) {
|
|
56523
|
-
const basename8 =
|
|
56524
|
-
const _ext =
|
|
56828
|
+
const basename8 = path40.basename(filePath);
|
|
56829
|
+
const _ext = path40.extname(filePath).toLowerCase();
|
|
56525
56830
|
const testPatterns = [
|
|
56526
56831
|
".test.",
|
|
56527
56832
|
".spec.",
|
|
@@ -56602,8 +56907,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
56602
56907
|
}
|
|
56603
56908
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
56604
56909
|
}
|
|
56605
|
-
function matchesGlobSegment(
|
|
56606
|
-
const normalizedPath =
|
|
56910
|
+
function matchesGlobSegment(path41, glob) {
|
|
56911
|
+
const normalizedPath = path41.replace(/\\/g, "/");
|
|
56607
56912
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
56608
56913
|
if (normalizedPath.includes("//")) {
|
|
56609
56914
|
return false;
|
|
@@ -56634,8 +56939,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
56634
56939
|
function hasGlobstar(glob) {
|
|
56635
56940
|
return glob.includes("**");
|
|
56636
56941
|
}
|
|
56637
|
-
function globMatches(
|
|
56638
|
-
const normalizedPath =
|
|
56942
|
+
function globMatches(path41, glob) {
|
|
56943
|
+
const normalizedPath = path41.replace(/\\/g, "/");
|
|
56639
56944
|
if (!glob || glob === "") {
|
|
56640
56945
|
if (normalizedPath.includes("//")) {
|
|
56641
56946
|
return false;
|
|
@@ -56671,7 +56976,7 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
56671
56976
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
56672
56977
|
let testLines = 0;
|
|
56673
56978
|
let codeLines = 0;
|
|
56674
|
-
const srcDir =
|
|
56979
|
+
const srcDir = path40.join(workingDir, "src");
|
|
56675
56980
|
if (fs27.existsSync(srcDir)) {
|
|
56676
56981
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
56677
56982
|
codeLines += lines;
|
|
@@ -56679,14 +56984,14 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
56679
56984
|
}
|
|
56680
56985
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
56681
56986
|
for (const dir of possibleSrcDirs) {
|
|
56682
|
-
const dirPath =
|
|
56987
|
+
const dirPath = path40.join(workingDir, dir);
|
|
56683
56988
|
if (fs27.existsSync(dirPath)) {
|
|
56684
56989
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
56685
56990
|
codeLines += lines;
|
|
56686
56991
|
});
|
|
56687
56992
|
}
|
|
56688
56993
|
}
|
|
56689
|
-
const testsDir =
|
|
56994
|
+
const testsDir = path40.join(workingDir, "tests");
|
|
56690
56995
|
if (fs27.existsSync(testsDir)) {
|
|
56691
56996
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
56692
56997
|
testLines += lines;
|
|
@@ -56694,7 +56999,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
56694
56999
|
}
|
|
56695
57000
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
56696
57001
|
for (const dir of possibleTestDirs) {
|
|
56697
|
-
const dirPath =
|
|
57002
|
+
const dirPath = path40.join(workingDir, dir);
|
|
56698
57003
|
if (fs27.existsSync(dirPath) && dirPath !== testsDir) {
|
|
56699
57004
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
56700
57005
|
testLines += lines;
|
|
@@ -56709,7 +57014,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
56709
57014
|
try {
|
|
56710
57015
|
const entries = fs27.readdirSync(dirPath, { withFileTypes: true });
|
|
56711
57016
|
for (const entry of entries) {
|
|
56712
|
-
const fullPath =
|
|
57017
|
+
const fullPath = path40.join(dirPath, entry.name);
|
|
56713
57018
|
if (entry.isDirectory()) {
|
|
56714
57019
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
56715
57020
|
continue;
|
|
@@ -56717,7 +57022,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
56717
57022
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
56718
57023
|
} else if (entry.isFile()) {
|
|
56719
57024
|
const relativePath = fullPath.replace(`${process.cwd()}/`, "");
|
|
56720
|
-
const ext =
|
|
57025
|
+
const ext = path40.extname(entry.name).toLowerCase();
|
|
56721
57026
|
const validExts = [
|
|
56722
57027
|
".ts",
|
|
56723
57028
|
".tsx",
|
|
@@ -56968,7 +57273,7 @@ init_dist();
|
|
|
56968
57273
|
init_manager();
|
|
56969
57274
|
init_detector();
|
|
56970
57275
|
import * as fs28 from "fs";
|
|
56971
|
-
import * as
|
|
57276
|
+
import * as path41 from "path";
|
|
56972
57277
|
import { extname as extname9 } from "path";
|
|
56973
57278
|
|
|
56974
57279
|
// src/sast/rules/c.ts
|
|
@@ -57931,7 +58236,7 @@ async function sastScan(input, directory, config3) {
|
|
|
57931
58236
|
_filesSkipped++;
|
|
57932
58237
|
continue;
|
|
57933
58238
|
}
|
|
57934
|
-
const resolvedPath =
|
|
58239
|
+
const resolvedPath = path41.isAbsolute(filePath) ? filePath : path41.resolve(directory, filePath);
|
|
57935
58240
|
if (!fs28.existsSync(resolvedPath)) {
|
|
57936
58241
|
_filesSkipped++;
|
|
57937
58242
|
continue;
|
|
@@ -58130,18 +58435,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
58130
58435
|
let resolved;
|
|
58131
58436
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
58132
58437
|
if (isWinAbs) {
|
|
58133
|
-
resolved =
|
|
58134
|
-
} else if (
|
|
58135
|
-
resolved =
|
|
58438
|
+
resolved = path42.win32.resolve(inputPath);
|
|
58439
|
+
} else if (path42.isAbsolute(inputPath)) {
|
|
58440
|
+
resolved = path42.resolve(inputPath);
|
|
58136
58441
|
} else {
|
|
58137
|
-
resolved =
|
|
58442
|
+
resolved = path42.resolve(baseDir, inputPath);
|
|
58138
58443
|
}
|
|
58139
|
-
const workspaceResolved =
|
|
58444
|
+
const workspaceResolved = path42.resolve(workspaceDir);
|
|
58140
58445
|
let relative5;
|
|
58141
58446
|
if (isWinAbs) {
|
|
58142
|
-
relative5 =
|
|
58447
|
+
relative5 = path42.win32.relative(workspaceResolved, resolved);
|
|
58143
58448
|
} else {
|
|
58144
|
-
relative5 =
|
|
58449
|
+
relative5 = path42.relative(workspaceResolved, resolved);
|
|
58145
58450
|
}
|
|
58146
58451
|
if (relative5.startsWith("..")) {
|
|
58147
58452
|
return "path traversal detected";
|
|
@@ -58202,13 +58507,13 @@ async function runLintWrapped(files, directory, _config) {
|
|
|
58202
58507
|
}
|
|
58203
58508
|
async function runLintOnFiles(linter, files, workspaceDir) {
|
|
58204
58509
|
const isWindows = process.platform === "win32";
|
|
58205
|
-
const binDir =
|
|
58510
|
+
const binDir = path42.join(workspaceDir, "node_modules", ".bin");
|
|
58206
58511
|
const validatedFiles = [];
|
|
58207
58512
|
for (const file3 of files) {
|
|
58208
58513
|
if (typeof file3 !== "string") {
|
|
58209
58514
|
continue;
|
|
58210
58515
|
}
|
|
58211
|
-
const resolvedPath =
|
|
58516
|
+
const resolvedPath = path42.resolve(file3);
|
|
58212
58517
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
58213
58518
|
if (validationError) {
|
|
58214
58519
|
continue;
|
|
@@ -58226,10 +58531,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
58226
58531
|
}
|
|
58227
58532
|
let command;
|
|
58228
58533
|
if (linter === "biome") {
|
|
58229
|
-
const biomeBin = isWindows ?
|
|
58534
|
+
const biomeBin = isWindows ? path42.join(binDir, "biome.EXE") : path42.join(binDir, "biome");
|
|
58230
58535
|
command = [biomeBin, "check", ...validatedFiles];
|
|
58231
58536
|
} else {
|
|
58232
|
-
const eslintBin = isWindows ?
|
|
58537
|
+
const eslintBin = isWindows ? path42.join(binDir, "eslint.cmd") : path42.join(binDir, "eslint");
|
|
58233
58538
|
command = [eslintBin, ...validatedFiles];
|
|
58234
58539
|
}
|
|
58235
58540
|
try {
|
|
@@ -58366,7 +58671,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
58366
58671
|
skippedFiles++;
|
|
58367
58672
|
continue;
|
|
58368
58673
|
}
|
|
58369
|
-
const resolvedPath =
|
|
58674
|
+
const resolvedPath = path42.resolve(file3);
|
|
58370
58675
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
58371
58676
|
if (validationError) {
|
|
58372
58677
|
skippedFiles++;
|
|
@@ -58384,7 +58689,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
58384
58689
|
};
|
|
58385
58690
|
}
|
|
58386
58691
|
for (const file3 of validatedFiles) {
|
|
58387
|
-
const ext =
|
|
58692
|
+
const ext = path42.extname(file3).toLowerCase();
|
|
58388
58693
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
58389
58694
|
skippedFiles++;
|
|
58390
58695
|
continue;
|
|
@@ -58543,7 +58848,7 @@ async function runPreCheckBatch(input, workspaceDir) {
|
|
|
58543
58848
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
58544
58849
|
continue;
|
|
58545
58850
|
}
|
|
58546
|
-
changedFiles.push(
|
|
58851
|
+
changedFiles.push(path42.resolve(directory, file3));
|
|
58547
58852
|
}
|
|
58548
58853
|
if (changedFiles.length === 0) {
|
|
58549
58854
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -58694,7 +58999,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
58694
58999
|
};
|
|
58695
59000
|
return JSON.stringify(errorResult, null, 2);
|
|
58696
59001
|
}
|
|
58697
|
-
const resolvedDirectory =
|
|
59002
|
+
const resolvedDirectory = path42.resolve(typedArgs.directory);
|
|
58698
59003
|
const workspaceAnchor = resolvedDirectory;
|
|
58699
59004
|
const dirError = validateDirectory3(resolvedDirectory, workspaceAnchor);
|
|
58700
59005
|
if (dirError) {
|
|
@@ -58802,7 +59107,7 @@ init_tool();
|
|
|
58802
59107
|
init_manager2();
|
|
58803
59108
|
init_create_tool();
|
|
58804
59109
|
import * as fs30 from "fs";
|
|
58805
|
-
import * as
|
|
59110
|
+
import * as path43 from "path";
|
|
58806
59111
|
function detectPlaceholderContent(args2) {
|
|
58807
59112
|
const issues = [];
|
|
58808
59113
|
const placeholderPattern = /^\[\w[\w\s]*\]$/;
|
|
@@ -58906,7 +59211,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
58906
59211
|
try {
|
|
58907
59212
|
await savePlan(dir, plan);
|
|
58908
59213
|
try {
|
|
58909
|
-
const markerPath =
|
|
59214
|
+
const markerPath = path43.join(dir, ".swarm", ".plan-write-marker");
|
|
58910
59215
|
const marker = JSON.stringify({
|
|
58911
59216
|
source: "save_plan",
|
|
58912
59217
|
timestamp: new Date().toISOString(),
|
|
@@ -58918,7 +59223,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
58918
59223
|
return {
|
|
58919
59224
|
success: true,
|
|
58920
59225
|
message: "Plan saved successfully",
|
|
58921
|
-
plan_path:
|
|
59226
|
+
plan_path: path43.join(dir, ".swarm", "plan.json"),
|
|
58922
59227
|
phases_count: plan.phases.length,
|
|
58923
59228
|
tasks_count: tasksCount
|
|
58924
59229
|
};
|
|
@@ -58957,7 +59262,7 @@ var save_plan = createSwarmTool({
|
|
|
58957
59262
|
init_dist();
|
|
58958
59263
|
init_manager();
|
|
58959
59264
|
import * as fs31 from "fs";
|
|
58960
|
-
import * as
|
|
59265
|
+
import * as path44 from "path";
|
|
58961
59266
|
|
|
58962
59267
|
// src/sbom/detectors/index.ts
|
|
58963
59268
|
init_utils();
|
|
@@ -59805,7 +60110,7 @@ function findManifestFiles(rootDir) {
|
|
|
59805
60110
|
try {
|
|
59806
60111
|
const entries = fs31.readdirSync(dir, { withFileTypes: true });
|
|
59807
60112
|
for (const entry of entries) {
|
|
59808
|
-
const fullPath =
|
|
60113
|
+
const fullPath = path44.join(dir, entry.name);
|
|
59809
60114
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
59810
60115
|
continue;
|
|
59811
60116
|
}
|
|
@@ -59814,7 +60119,7 @@ function findManifestFiles(rootDir) {
|
|
|
59814
60119
|
} else if (entry.isFile()) {
|
|
59815
60120
|
for (const pattern of patterns) {
|
|
59816
60121
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
59817
|
-
manifestFiles.push(
|
|
60122
|
+
manifestFiles.push(path44.relative(rootDir, fullPath));
|
|
59818
60123
|
break;
|
|
59819
60124
|
}
|
|
59820
60125
|
}
|
|
@@ -59832,11 +60137,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
59832
60137
|
try {
|
|
59833
60138
|
const entries = fs31.readdirSync(dir, { withFileTypes: true });
|
|
59834
60139
|
for (const entry of entries) {
|
|
59835
|
-
const fullPath =
|
|
60140
|
+
const fullPath = path44.join(dir, entry.name);
|
|
59836
60141
|
if (entry.isFile()) {
|
|
59837
60142
|
for (const pattern of patterns) {
|
|
59838
60143
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
59839
|
-
found.push(
|
|
60144
|
+
found.push(path44.relative(workingDir, fullPath));
|
|
59840
60145
|
break;
|
|
59841
60146
|
}
|
|
59842
60147
|
}
|
|
@@ -59849,11 +60154,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
59849
60154
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
59850
60155
|
const dirs = new Set;
|
|
59851
60156
|
for (const file3 of changedFiles) {
|
|
59852
|
-
let currentDir =
|
|
60157
|
+
let currentDir = path44.dirname(file3);
|
|
59853
60158
|
while (true) {
|
|
59854
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
59855
|
-
dirs.add(
|
|
59856
|
-
const parent =
|
|
60159
|
+
if (currentDir && currentDir !== "." && currentDir !== path44.sep) {
|
|
60160
|
+
dirs.add(path44.join(workingDir, currentDir));
|
|
60161
|
+
const parent = path44.dirname(currentDir);
|
|
59857
60162
|
if (parent === currentDir)
|
|
59858
60163
|
break;
|
|
59859
60164
|
currentDir = parent;
|
|
@@ -59937,7 +60242,7 @@ var sbom_generate = createSwarmTool({
|
|
|
59937
60242
|
const changedFiles = obj.changed_files;
|
|
59938
60243
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
59939
60244
|
const workingDir = directory;
|
|
59940
|
-
const outputDir =
|
|
60245
|
+
const outputDir = path44.isAbsolute(relativeOutputDir) ? relativeOutputDir : path44.join(workingDir, relativeOutputDir);
|
|
59941
60246
|
let manifestFiles = [];
|
|
59942
60247
|
if (scope === "all") {
|
|
59943
60248
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -59960,7 +60265,7 @@ var sbom_generate = createSwarmTool({
|
|
|
59960
60265
|
const processedFiles = [];
|
|
59961
60266
|
for (const manifestFile of manifestFiles) {
|
|
59962
60267
|
try {
|
|
59963
|
-
const fullPath =
|
|
60268
|
+
const fullPath = path44.isAbsolute(manifestFile) ? manifestFile : path44.join(workingDir, manifestFile);
|
|
59964
60269
|
if (!fs31.existsSync(fullPath)) {
|
|
59965
60270
|
continue;
|
|
59966
60271
|
}
|
|
@@ -59977,7 +60282,7 @@ var sbom_generate = createSwarmTool({
|
|
|
59977
60282
|
const bom = generateCycloneDX(allComponents);
|
|
59978
60283
|
const bomJson = serializeCycloneDX(bom);
|
|
59979
60284
|
const filename = generateSbomFilename();
|
|
59980
|
-
const outputPath =
|
|
60285
|
+
const outputPath = path44.join(outputDir, filename);
|
|
59981
60286
|
fs31.writeFileSync(outputPath, bomJson, "utf-8");
|
|
59982
60287
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
59983
60288
|
try {
|
|
@@ -60021,7 +60326,7 @@ var sbom_generate = createSwarmTool({
|
|
|
60021
60326
|
init_dist();
|
|
60022
60327
|
init_create_tool();
|
|
60023
60328
|
import * as fs32 from "fs";
|
|
60024
|
-
import * as
|
|
60329
|
+
import * as path45 from "path";
|
|
60025
60330
|
var SPEC_CANDIDATES = [
|
|
60026
60331
|
"openapi.json",
|
|
60027
60332
|
"openapi.yaml",
|
|
@@ -60053,12 +60358,12 @@ function normalizePath2(p) {
|
|
|
60053
60358
|
}
|
|
60054
60359
|
function discoverSpecFile(cwd, specFileArg) {
|
|
60055
60360
|
if (specFileArg) {
|
|
60056
|
-
const resolvedPath =
|
|
60057
|
-
const normalizedCwd = cwd.endsWith(
|
|
60361
|
+
const resolvedPath = path45.resolve(cwd, specFileArg);
|
|
60362
|
+
const normalizedCwd = cwd.endsWith(path45.sep) ? cwd : cwd + path45.sep;
|
|
60058
60363
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
60059
60364
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
60060
60365
|
}
|
|
60061
|
-
const ext =
|
|
60366
|
+
const ext = path45.extname(resolvedPath).toLowerCase();
|
|
60062
60367
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
60063
60368
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
60064
60369
|
}
|
|
@@ -60072,7 +60377,7 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
60072
60377
|
return resolvedPath;
|
|
60073
60378
|
}
|
|
60074
60379
|
for (const candidate of SPEC_CANDIDATES) {
|
|
60075
|
-
const candidatePath =
|
|
60380
|
+
const candidatePath = path45.resolve(cwd, candidate);
|
|
60076
60381
|
if (fs32.existsSync(candidatePath)) {
|
|
60077
60382
|
const stats = fs32.statSync(candidatePath);
|
|
60078
60383
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
@@ -60084,7 +60389,7 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
60084
60389
|
}
|
|
60085
60390
|
function parseSpec(specFile) {
|
|
60086
60391
|
const content = fs32.readFileSync(specFile, "utf-8");
|
|
60087
|
-
const ext =
|
|
60392
|
+
const ext = path45.extname(specFile).toLowerCase();
|
|
60088
60393
|
if (ext === ".json") {
|
|
60089
60394
|
return parseJsonSpec(content);
|
|
60090
60395
|
}
|
|
@@ -60160,7 +60465,7 @@ function extractRoutes(cwd) {
|
|
|
60160
60465
|
return;
|
|
60161
60466
|
}
|
|
60162
60467
|
for (const entry of entries) {
|
|
60163
|
-
const fullPath =
|
|
60468
|
+
const fullPath = path45.join(dir, entry.name);
|
|
60164
60469
|
if (entry.isSymbolicLink()) {
|
|
60165
60470
|
continue;
|
|
60166
60471
|
}
|
|
@@ -60170,7 +60475,7 @@ function extractRoutes(cwd) {
|
|
|
60170
60475
|
}
|
|
60171
60476
|
walkDir(fullPath);
|
|
60172
60477
|
} else if (entry.isFile()) {
|
|
60173
|
-
const ext =
|
|
60478
|
+
const ext = path45.extname(entry.name).toLowerCase();
|
|
60174
60479
|
const baseName = entry.name.toLowerCase();
|
|
60175
60480
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
60176
60481
|
continue;
|
|
@@ -60340,7 +60645,7 @@ init_secretscan();
|
|
|
60340
60645
|
init_tool();
|
|
60341
60646
|
init_create_tool();
|
|
60342
60647
|
import * as fs33 from "fs";
|
|
60343
|
-
import * as
|
|
60648
|
+
import * as path46 from "path";
|
|
60344
60649
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
60345
60650
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
60346
60651
|
function containsControlCharacters(str) {
|
|
@@ -60369,11 +60674,11 @@ function containsWindowsAttacks(str) {
|
|
|
60369
60674
|
}
|
|
60370
60675
|
function isPathInWorkspace(filePath, workspace) {
|
|
60371
60676
|
try {
|
|
60372
|
-
const resolvedPath =
|
|
60677
|
+
const resolvedPath = path46.resolve(workspace, filePath);
|
|
60373
60678
|
const realWorkspace = fs33.realpathSync(workspace);
|
|
60374
60679
|
const realResolvedPath = fs33.realpathSync(resolvedPath);
|
|
60375
|
-
const relativePath =
|
|
60376
|
-
if (relativePath.startsWith("..") ||
|
|
60680
|
+
const relativePath = path46.relative(realWorkspace, realResolvedPath);
|
|
60681
|
+
if (relativePath.startsWith("..") || path46.isAbsolute(relativePath)) {
|
|
60377
60682
|
return false;
|
|
60378
60683
|
}
|
|
60379
60684
|
return true;
|
|
@@ -60385,7 +60690,7 @@ function validatePathForRead(filePath, workspace) {
|
|
|
60385
60690
|
return isPathInWorkspace(filePath, workspace);
|
|
60386
60691
|
}
|
|
60387
60692
|
function extractTSSymbols(filePath, cwd) {
|
|
60388
|
-
const fullPath =
|
|
60693
|
+
const fullPath = path46.join(cwd, filePath);
|
|
60389
60694
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
60390
60695
|
return [];
|
|
60391
60696
|
}
|
|
@@ -60537,7 +60842,7 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
60537
60842
|
});
|
|
60538
60843
|
}
|
|
60539
60844
|
function extractPythonSymbols(filePath, cwd) {
|
|
60540
|
-
const fullPath =
|
|
60845
|
+
const fullPath = path46.join(cwd, filePath);
|
|
60541
60846
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
60542
60847
|
return [];
|
|
60543
60848
|
}
|
|
@@ -60620,7 +60925,7 @@ var symbols = createSwarmTool({
|
|
|
60620
60925
|
}, null, 2);
|
|
60621
60926
|
}
|
|
60622
60927
|
const cwd = directory;
|
|
60623
|
-
const ext =
|
|
60928
|
+
const ext = path46.extname(file3);
|
|
60624
60929
|
if (containsControlCharacters(file3)) {
|
|
60625
60930
|
return JSON.stringify({
|
|
60626
60931
|
file: file3,
|
|
@@ -60692,7 +60997,7 @@ init_dist();
|
|
|
60692
60997
|
init_utils();
|
|
60693
60998
|
init_create_tool();
|
|
60694
60999
|
import * as fs34 from "fs";
|
|
60695
|
-
import * as
|
|
61000
|
+
import * as path47 from "path";
|
|
60696
61001
|
var MAX_TEXT_LENGTH = 200;
|
|
60697
61002
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
60698
61003
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
@@ -60763,9 +61068,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
60763
61068
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
60764
61069
|
}
|
|
60765
61070
|
try {
|
|
60766
|
-
const resolvedPath =
|
|
60767
|
-
const normalizedCwd =
|
|
60768
|
-
const normalizedResolved =
|
|
61071
|
+
const resolvedPath = path47.resolve(paths);
|
|
61072
|
+
const normalizedCwd = path47.resolve(cwd);
|
|
61073
|
+
const normalizedResolved = path47.resolve(resolvedPath);
|
|
60769
61074
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
60770
61075
|
return {
|
|
60771
61076
|
error: "paths must be within the current working directory",
|
|
@@ -60781,7 +61086,7 @@ function validatePathsInput(paths, cwd) {
|
|
|
60781
61086
|
}
|
|
60782
61087
|
}
|
|
60783
61088
|
function isSupportedExtension(filePath) {
|
|
60784
|
-
const ext =
|
|
61089
|
+
const ext = path47.extname(filePath).toLowerCase();
|
|
60785
61090
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
60786
61091
|
}
|
|
60787
61092
|
function findSourceFiles3(dir, files = []) {
|
|
@@ -60796,7 +61101,7 @@ function findSourceFiles3(dir, files = []) {
|
|
|
60796
61101
|
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
60797
61102
|
continue;
|
|
60798
61103
|
}
|
|
60799
|
-
const fullPath =
|
|
61104
|
+
const fullPath = path47.join(dir, entry);
|
|
60800
61105
|
let stat2;
|
|
60801
61106
|
try {
|
|
60802
61107
|
stat2 = fs34.statSync(fullPath);
|
|
@@ -60908,7 +61213,7 @@ var todo_extract = createSwarmTool({
|
|
|
60908
61213
|
filesToScan.push(scanPath);
|
|
60909
61214
|
} else {
|
|
60910
61215
|
const errorResult = {
|
|
60911
|
-
error: `unsupported file extension: ${
|
|
61216
|
+
error: `unsupported file extension: ${path47.extname(scanPath)}`,
|
|
60912
61217
|
total: 0,
|
|
60913
61218
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
60914
61219
|
entries: []
|
|
@@ -60955,7 +61260,7 @@ init_tool();
|
|
|
60955
61260
|
init_schema();
|
|
60956
61261
|
init_manager2();
|
|
60957
61262
|
import * as fs35 from "fs";
|
|
60958
|
-
import * as
|
|
61263
|
+
import * as path48 from "path";
|
|
60959
61264
|
init_create_tool();
|
|
60960
61265
|
var VALID_STATUSES2 = [
|
|
60961
61266
|
"pending",
|
|
@@ -60978,6 +61283,23 @@ function validateTaskId(taskId) {
|
|
|
60978
61283
|
}
|
|
60979
61284
|
function checkReviewerGate(taskId, workingDirectory) {
|
|
60980
61285
|
try {
|
|
61286
|
+
const resolvedDir = workingDirectory ?? process.cwd();
|
|
61287
|
+
try {
|
|
61288
|
+
const evidencePath = path48.join(resolvedDir, ".swarm", "evidence", `${taskId}.json`);
|
|
61289
|
+
const raw = fs35.readFileSync(evidencePath, "utf-8");
|
|
61290
|
+
const evidence = JSON.parse(raw);
|
|
61291
|
+
if (evidence?.required_gates && Array.isArray(evidence.required_gates) && evidence?.gates) {
|
|
61292
|
+
const allGatesMet = evidence.required_gates.every((gate) => evidence.gates[gate] != null);
|
|
61293
|
+
if (allGatesMet) {
|
|
61294
|
+
return { blocked: false, reason: "" };
|
|
61295
|
+
}
|
|
61296
|
+
const missingGates = evidence.required_gates.filter((gate) => evidence.gates[gate] == null);
|
|
61297
|
+
return {
|
|
61298
|
+
blocked: true,
|
|
61299
|
+
reason: `Task ${taskId} is missing required gates: [${missingGates.join(", ")}]. ` + `Required: [${evidence.required_gates.join(", ")}]. ` + `Completed: [${Object.keys(evidence.gates).join(", ")}]. ` + `Delegate the missing gate agents before marking task as completed.`
|
|
61300
|
+
};
|
|
61301
|
+
}
|
|
61302
|
+
} catch {}
|
|
60981
61303
|
if (swarmState.agentSessions.size === 0) {
|
|
60982
61304
|
return { blocked: false, reason: "" };
|
|
60983
61305
|
}
|
|
@@ -61003,8 +61325,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
61003
61325
|
stateEntries.push(`${sessionId}: ${state}`);
|
|
61004
61326
|
}
|
|
61005
61327
|
try {
|
|
61006
|
-
const
|
|
61007
|
-
const planPath =
|
|
61328
|
+
const resolvedDir2 = workingDirectory ?? process.cwd();
|
|
61329
|
+
const planPath = path48.join(resolvedDir2, ".swarm", "plan.json");
|
|
61008
61330
|
const planRaw = fs35.readFileSync(planPath, "utf-8");
|
|
61009
61331
|
const plan = JSON.parse(planRaw);
|
|
61010
61332
|
for (const planPhase of plan.phases ?? []) {
|
|
@@ -61027,13 +61349,16 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
61027
61349
|
function recoverTaskStateFromDelegations(taskId) {
|
|
61028
61350
|
let hasReviewer = false;
|
|
61029
61351
|
let hasTestEngineer = false;
|
|
61030
|
-
for (const [, chain] of swarmState.delegationChains) {
|
|
61031
|
-
|
|
61032
|
-
|
|
61033
|
-
|
|
61034
|
-
|
|
61035
|
-
|
|
61036
|
-
|
|
61352
|
+
for (const [sessionId, chain] of swarmState.delegationChains) {
|
|
61353
|
+
const session = swarmState.agentSessions.get(sessionId);
|
|
61354
|
+
if (session && (session.currentTaskId === taskId || session.lastCoderDelegationTaskId === taskId)) {
|
|
61355
|
+
for (const delegation of chain) {
|
|
61356
|
+
const target = stripKnownSwarmPrefix(delegation.to);
|
|
61357
|
+
if (target === "reviewer")
|
|
61358
|
+
hasReviewer = true;
|
|
61359
|
+
if (target === "test_engineer")
|
|
61360
|
+
hasTestEngineer = true;
|
|
61361
|
+
}
|
|
61037
61362
|
}
|
|
61038
61363
|
}
|
|
61039
61364
|
if (!hasReviewer && !hasTestEngineer)
|
|
@@ -61112,8 +61437,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
61112
61437
|
};
|
|
61113
61438
|
}
|
|
61114
61439
|
}
|
|
61115
|
-
normalizedDir =
|
|
61116
|
-
const pathParts = normalizedDir.split(
|
|
61440
|
+
normalizedDir = path48.normalize(args2.working_directory);
|
|
61441
|
+
const pathParts = normalizedDir.split(path48.sep);
|
|
61117
61442
|
if (pathParts.includes("..")) {
|
|
61118
61443
|
return {
|
|
61119
61444
|
success: false,
|
|
@@ -61123,10 +61448,10 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
61123
61448
|
]
|
|
61124
61449
|
};
|
|
61125
61450
|
}
|
|
61126
|
-
const resolvedDir =
|
|
61451
|
+
const resolvedDir = path48.resolve(normalizedDir);
|
|
61127
61452
|
try {
|
|
61128
61453
|
const realPath = fs35.realpathSync(resolvedDir);
|
|
61129
|
-
const planPath =
|
|
61454
|
+
const planPath = path48.join(realPath, ".swarm", "plan.json");
|
|
61130
61455
|
if (!fs35.existsSync(planPath)) {
|
|
61131
61456
|
return {
|
|
61132
61457
|
success: false,
|
|
@@ -61284,7 +61609,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
61284
61609
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
61285
61610
|
preflightTriggerManager = new PTM(automationConfig);
|
|
61286
61611
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
61287
|
-
const swarmDir =
|
|
61612
|
+
const swarmDir = path49.resolve(ctx.directory, ".swarm");
|
|
61288
61613
|
statusArtifact = new ASA(swarmDir);
|
|
61289
61614
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
61290
61615
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|