opencode-swarm 6.33.0 → 6.33.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -7
- package/dist/cli/index.js +147 -33
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/registry.d.ts +4 -0
- package/dist/commands/reset-session.d.ts +7 -0
- package/dist/config/evidence-schema.d.ts +79 -0
- package/dist/config/schema.d.ts +13 -0
- package/dist/evidence/manager.d.ts +8 -4
- package/dist/hooks/delegation-gate.d.ts +7 -0
- package/dist/hooks/delegation-gate.getEvidenceTaskId.test.d.ts +20 -0
- package/dist/hooks/scope-guard.d.ts +2 -2
- package/dist/index.js +987 -345
- package/dist/model-fallback.adversarial.test.d.ts +22 -0
- package/dist/model-fallback.test.d.ts +12 -0
- package/dist/session/snapshot-writer.d.ts +14 -0
- package/dist/state.d.ts +8 -0
- package/dist/tools/doc-scan.d.ts +38 -0
- package/dist/tools/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14146,7 +14146,7 @@ var init_zod = __esm(() => {
|
|
|
14146
14146
|
});
|
|
14147
14147
|
|
|
14148
14148
|
// src/config/evidence-schema.ts
|
|
14149
|
-
var EVIDENCE_MAX_JSON_BYTES, EVIDENCE_MAX_PATCH_BYTES, EVIDENCE_MAX_TASK_BYTES, EvidenceTypeSchema, EvidenceVerdictSchema, BaseEvidenceSchema, ReviewEvidenceSchema, TestEvidenceSchema, DiffEvidenceSchema, ApprovalEvidenceSchema, NoteEvidenceSchema, RetrospectiveEvidenceSchema, SyntaxEvidenceSchema, PlaceholderEvidenceSchema, SastEvidenceSchema, SbomEvidenceSchema, BuildEvidenceSchema, QualityBudgetEvidenceSchema, EvidenceSchema, EvidenceBundleSchema;
|
|
14149
|
+
var EVIDENCE_MAX_JSON_BYTES, EVIDENCE_MAX_PATCH_BYTES, EVIDENCE_MAX_TASK_BYTES, EvidenceTypeSchema, EvidenceVerdictSchema, BaseEvidenceSchema, ReviewEvidenceSchema, TestEvidenceSchema, DiffEvidenceSchema, ApprovalEvidenceSchema, NoteEvidenceSchema, RetrospectiveEvidenceSchema, SyntaxEvidenceSchema, PlaceholderEvidenceSchema, SastEvidenceSchema, SbomEvidenceSchema, BuildEvidenceSchema, QualityBudgetEvidenceSchema, SecretscanEvidenceSchema, EvidenceSchema, EvidenceBundleSchema;
|
|
14150
14150
|
var init_evidence_schema = __esm(() => {
|
|
14151
14151
|
init_zod();
|
|
14152
14152
|
EVIDENCE_MAX_JSON_BYTES = 500 * 1024;
|
|
@@ -14164,7 +14164,8 @@ var init_evidence_schema = __esm(() => {
|
|
|
14164
14164
|
"sast",
|
|
14165
14165
|
"sbom",
|
|
14166
14166
|
"build",
|
|
14167
|
-
"quality_budget"
|
|
14167
|
+
"quality_budget",
|
|
14168
|
+
"secretscan"
|
|
14168
14169
|
]);
|
|
14169
14170
|
EvidenceVerdictSchema = exports_external.enum([
|
|
14170
14171
|
"pass",
|
|
@@ -14245,7 +14246,14 @@ var init_evidence_schema = __esm(() => {
|
|
|
14245
14246
|
approach: exports_external.string().min(1),
|
|
14246
14247
|
result: exports_external.enum(["success", "failure", "partial"]),
|
|
14247
14248
|
abandoned_reason: exports_external.string().optional()
|
|
14248
|
-
})).max(10).default([])
|
|
14249
|
+
})).max(10).default([]),
|
|
14250
|
+
error_taxonomy: exports_external.array(exports_external.enum([
|
|
14251
|
+
"planning_error",
|
|
14252
|
+
"interface_mismatch",
|
|
14253
|
+
"logic_error",
|
|
14254
|
+
"scope_creep",
|
|
14255
|
+
"gate_evasion"
|
|
14256
|
+
])).default([])
|
|
14249
14257
|
});
|
|
14250
14258
|
SyntaxEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14251
14259
|
type: exports_external.literal("syntax"),
|
|
@@ -14356,6 +14364,13 @@ var init_evidence_schema = __esm(() => {
|
|
|
14356
14364
|
})).default([]),
|
|
14357
14365
|
files_analyzed: exports_external.array(exports_external.string())
|
|
14358
14366
|
});
|
|
14367
|
+
SecretscanEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14368
|
+
type: exports_external.literal("secretscan"),
|
|
14369
|
+
findings_count: exports_external.number().int().min(0).default(0),
|
|
14370
|
+
scan_directory: exports_external.string().optional(),
|
|
14371
|
+
files_scanned: exports_external.number().int().min(0).default(0),
|
|
14372
|
+
skipped_files: exports_external.number().int().min(0).default(0)
|
|
14373
|
+
});
|
|
14359
14374
|
EvidenceSchema = exports_external.discriminatedUnion("type", [
|
|
14360
14375
|
ReviewEvidenceSchema,
|
|
14361
14376
|
TestEvidenceSchema,
|
|
@@ -14368,7 +14383,8 @@ var init_evidence_schema = __esm(() => {
|
|
|
14368
14383
|
SastEvidenceSchema,
|
|
14369
14384
|
SbomEvidenceSchema,
|
|
14370
14385
|
BuildEvidenceSchema,
|
|
14371
|
-
QualityBudgetEvidenceSchema
|
|
14386
|
+
QualityBudgetEvidenceSchema,
|
|
14387
|
+
SecretscanEvidenceSchema
|
|
14372
14388
|
]);
|
|
14373
14389
|
EvidenceBundleSchema = exports_external.object({
|
|
14374
14390
|
schema_version: exports_external.literal("1.0.0"),
|
|
@@ -14458,7 +14474,8 @@ var init_schema = __esm(() => {
|
|
|
14458
14474
|
AgentOverrideConfigSchema = exports_external.object({
|
|
14459
14475
|
model: exports_external.string().optional(),
|
|
14460
14476
|
temperature: exports_external.number().min(0).max(2).optional(),
|
|
14461
|
-
disabled: exports_external.boolean().optional()
|
|
14477
|
+
disabled: exports_external.boolean().optional(),
|
|
14478
|
+
fallback_models: exports_external.array(exports_external.string()).max(3).optional()
|
|
14462
14479
|
});
|
|
14463
14480
|
SwarmConfigSchema = exports_external.object({
|
|
14464
14481
|
name: exports_external.string().optional(),
|
|
@@ -14798,6 +14815,8 @@ var init_schema = __esm(() => {
|
|
|
14798
14815
|
max_consecutive_errors: exports_external.number().min(2).max(20).default(5),
|
|
14799
14816
|
warning_threshold: exports_external.number().min(0.1).max(0.9).default(0.75),
|
|
14800
14817
|
idle_timeout_minutes: exports_external.number().min(5).max(240).default(60),
|
|
14818
|
+
no_op_warning_threshold: exports_external.number().min(1).max(100).default(15),
|
|
14819
|
+
max_coder_revisions: exports_external.number().int().min(1).max(20).default(5),
|
|
14801
14820
|
qa_gates: exports_external.object({
|
|
14802
14821
|
required_tools: exports_external.array(exports_external.string().min(1)).default([
|
|
14803
14822
|
"diff",
|
|
@@ -14913,6 +14932,7 @@ var init_schema = __esm(() => {
|
|
|
14913
14932
|
pipeline: PipelineConfigSchema.optional(),
|
|
14914
14933
|
phase_complete: PhaseCompleteConfigSchema.optional(),
|
|
14915
14934
|
qa_retry_limit: exports_external.number().min(1).max(10).default(3),
|
|
14935
|
+
execution_mode: exports_external.enum(["strict", "balanced", "fast"]).default("balanced"),
|
|
14916
14936
|
inject_phase_reminders: exports_external.boolean().default(true),
|
|
14917
14937
|
hooks: HooksConfigSchema.optional(),
|
|
14918
14938
|
gates: GateConfigSchema.optional(),
|
|
@@ -15398,6 +15418,9 @@ import * as path4 from "path";
|
|
|
15398
15418
|
function isValidEvidenceType(type) {
|
|
15399
15419
|
return VALID_EVIDENCE_TYPES.includes(type);
|
|
15400
15420
|
}
|
|
15421
|
+
function isSecretscanEvidence(evidence) {
|
|
15422
|
+
return evidence.type === "secretscan";
|
|
15423
|
+
}
|
|
15401
15424
|
function sanitizeTaskId(taskId) {
|
|
15402
15425
|
if (!taskId || taskId.length === 0) {
|
|
15403
15426
|
throw new Error("Invalid task ID: empty string");
|
|
@@ -15650,11 +15673,12 @@ var init_manager = __esm(() => {
|
|
|
15650
15673
|
"sast",
|
|
15651
15674
|
"sbom",
|
|
15652
15675
|
"build",
|
|
15653
|
-
"quality_budget"
|
|
15676
|
+
"quality_budget",
|
|
15677
|
+
"secretscan"
|
|
15654
15678
|
];
|
|
15655
15679
|
TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
|
|
15656
15680
|
RETRO_TASK_ID_REGEX = /^retro-\d+$/;
|
|
15657
|
-
INTERNAL_TOOL_ID_REGEX = /^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build)$/;
|
|
15681
|
+
INTERNAL_TOOL_ID_REGEX = /^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build|secretscan)$/;
|
|
15658
15682
|
LEGACY_TASK_COMPLEXITY_MAP = {
|
|
15659
15683
|
low: "simple",
|
|
15660
15684
|
medium: "moderate",
|
|
@@ -36248,7 +36272,7 @@ __export(exports_gate_evidence, {
|
|
|
36248
36272
|
deriveRequiredGates: () => deriveRequiredGates,
|
|
36249
36273
|
DEFAULT_REQUIRED_GATES: () => DEFAULT_REQUIRED_GATES
|
|
36250
36274
|
});
|
|
36251
|
-
import { mkdirSync as mkdirSync9, readFileSync as readFileSync14, renameSync as
|
|
36275
|
+
import { mkdirSync as mkdirSync9, readFileSync as readFileSync14, renameSync as renameSync9, unlinkSync as unlinkSync5 } from "fs";
|
|
36252
36276
|
import * as path30 from "path";
|
|
36253
36277
|
function isValidTaskId2(taskId) {
|
|
36254
36278
|
if (!taskId)
|
|
@@ -36313,10 +36337,10 @@ async function atomicWrite(targetPath, content) {
|
|
|
36313
36337
|
const tempPath = `${targetPath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
|
|
36314
36338
|
try {
|
|
36315
36339
|
await Bun.write(tempPath, content);
|
|
36316
|
-
|
|
36340
|
+
renameSync9(tempPath, targetPath);
|
|
36317
36341
|
} finally {
|
|
36318
36342
|
try {
|
|
36319
|
-
|
|
36343
|
+
unlinkSync5(tempPath);
|
|
36320
36344
|
} catch {}
|
|
36321
36345
|
}
|
|
36322
36346
|
}
|
|
@@ -37908,11 +37932,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
37908
37932
|
throw toThrow;
|
|
37909
37933
|
}, "quit_");
|
|
37910
37934
|
var scriptDirectory = "";
|
|
37911
|
-
function locateFile(
|
|
37935
|
+
function locateFile(path48) {
|
|
37912
37936
|
if (Module["locateFile"]) {
|
|
37913
|
-
return Module["locateFile"](
|
|
37937
|
+
return Module["locateFile"](path48, scriptDirectory);
|
|
37914
37938
|
}
|
|
37915
|
-
return scriptDirectory +
|
|
37939
|
+
return scriptDirectory + path48;
|
|
37916
37940
|
}
|
|
37917
37941
|
__name(locateFile, "locateFile");
|
|
37918
37942
|
var readAsync, readBinary;
|
|
@@ -39660,7 +39684,7 @@ var init_runtime = __esm(() => {
|
|
|
39660
39684
|
});
|
|
39661
39685
|
|
|
39662
39686
|
// src/index.ts
|
|
39663
|
-
import * as
|
|
39687
|
+
import * as path58 from "path";
|
|
39664
39688
|
|
|
39665
39689
|
// src/agents/index.ts
|
|
39666
39690
|
init_config();
|
|
@@ -39727,6 +39751,10 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, dire
|
|
|
39727
39751
|
scopeViolationDetected: false,
|
|
39728
39752
|
modifiedFilesThisCoderTask: [],
|
|
39729
39753
|
turboMode: false,
|
|
39754
|
+
model_fallback_index: 0,
|
|
39755
|
+
modelFallbackExhausted: false,
|
|
39756
|
+
coderRevisions: 0,
|
|
39757
|
+
revisionLimitHit: false,
|
|
39730
39758
|
loopDetectionWindow: [],
|
|
39731
39759
|
pendingAdvisoryMessages: []
|
|
39732
39760
|
};
|
|
@@ -39835,6 +39863,12 @@ function ensureAgentSession(sessionId, agentName, directory) {
|
|
|
39835
39863
|
if (session.turboMode === undefined) {
|
|
39836
39864
|
session.turboMode = false;
|
|
39837
39865
|
}
|
|
39866
|
+
if (session.model_fallback_index === undefined) {
|
|
39867
|
+
session.model_fallback_index = 0;
|
|
39868
|
+
}
|
|
39869
|
+
if (session.modelFallbackExhausted === undefined) {
|
|
39870
|
+
session.modelFallbackExhausted = false;
|
|
39871
|
+
}
|
|
39838
39872
|
if (session.loopDetectionWindow === undefined) {
|
|
39839
39873
|
session.loopDetectionWindow = [];
|
|
39840
39874
|
}
|
|
@@ -44110,14 +44144,18 @@ async function readCuratorSummary(directory) {
|
|
|
44110
44144
|
}
|
|
44111
44145
|
return parsed;
|
|
44112
44146
|
} catch {
|
|
44113
|
-
|
|
44147
|
+
if (process.env.DEBUG_SWARM) {
|
|
44148
|
+
console.warn("Failed to parse curator-summary.json: invalid JSON");
|
|
44149
|
+
}
|
|
44114
44150
|
return null;
|
|
44115
44151
|
}
|
|
44116
44152
|
}
|
|
44117
44153
|
async function writeCuratorSummary(directory, summary) {
|
|
44118
44154
|
const resolvedPath = validateSwarmPath(directory, "curator-summary.json");
|
|
44119
44155
|
fs7.mkdirSync(path12.dirname(resolvedPath), { recursive: true });
|
|
44120
|
-
|
|
44156
|
+
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
44157
|
+
await Bun.write(tempPath, JSON.stringify(summary, null, 2));
|
|
44158
|
+
fs7.renameSync(tempPath, resolvedPath);
|
|
44121
44159
|
}
|
|
44122
44160
|
function normalizeAgentName(name2) {
|
|
44123
44161
|
return name2.toLowerCase().replace(/^(mega|paid|local|lowtier|modelrelay)_/, "");
|
|
@@ -44141,7 +44179,9 @@ function filterPhaseEvents(eventsJsonl, phase, sinceTimestamp) {
|
|
|
44141
44179
|
}
|
|
44142
44180
|
}
|
|
44143
44181
|
} catch {
|
|
44144
|
-
|
|
44182
|
+
if (process.env.DEBUG_SWARM) {
|
|
44183
|
+
console.warn("filterPhaseEvents: skipping malformed line");
|
|
44184
|
+
}
|
|
44145
44185
|
}
|
|
44146
44186
|
}
|
|
44147
44187
|
return filtered;
|
|
@@ -46471,7 +46511,7 @@ async function handleExportCommand(directory, _args) {
|
|
|
46471
46511
|
// src/commands/handoff.ts
|
|
46472
46512
|
init_utils2();
|
|
46473
46513
|
import crypto3 from "crypto";
|
|
46474
|
-
import { renameSync as
|
|
46514
|
+
import { renameSync as renameSync6 } from "fs";
|
|
46475
46515
|
|
|
46476
46516
|
// src/services/handoff-service.ts
|
|
46477
46517
|
init_utils2();
|
|
@@ -46772,8 +46812,10 @@ function formatHandoffMarkdown(data) {
|
|
|
46772
46812
|
|
|
46773
46813
|
// src/session/snapshot-writer.ts
|
|
46774
46814
|
init_utils2();
|
|
46775
|
-
import { mkdirSync as mkdirSync7, renameSync as
|
|
46815
|
+
import { mkdirSync as mkdirSync7, renameSync as renameSync5 } from "fs";
|
|
46776
46816
|
import * as path19 from "path";
|
|
46817
|
+
var pendingWrite = null;
|
|
46818
|
+
var lastWritePromise = Promise.resolve();
|
|
46777
46819
|
function serializeAgentSession(s) {
|
|
46778
46820
|
const gateLog = {};
|
|
46779
46821
|
const rawGateLog = s.gateLog ?? new Map;
|
|
@@ -46835,7 +46877,11 @@ function serializeAgentSession(s) {
|
|
|
46835
46877
|
taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map),
|
|
46836
46878
|
...s.scopeViolationDetected !== undefined && {
|
|
46837
46879
|
scopeViolationDetected: s.scopeViolationDetected
|
|
46838
|
-
}
|
|
46880
|
+
},
|
|
46881
|
+
model_fallback_index: s.model_fallback_index ?? 0,
|
|
46882
|
+
modelFallbackExhausted: s.modelFallbackExhausted ?? false,
|
|
46883
|
+
coderRevisions: s.coderRevisions ?? 0,
|
|
46884
|
+
revisionLimitHit: s.revisionLimitHit ?? false
|
|
46839
46885
|
};
|
|
46840
46886
|
}
|
|
46841
46887
|
async function writeSnapshot(directory, state) {
|
|
@@ -46857,15 +46903,31 @@ async function writeSnapshot(directory, state) {
|
|
|
46857
46903
|
mkdirSync7(dir, { recursive: true });
|
|
46858
46904
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
46859
46905
|
await Bun.write(tempPath, content);
|
|
46860
|
-
|
|
46861
|
-
} catch {
|
|
46906
|
+
renameSync5(tempPath, resolvedPath);
|
|
46907
|
+
} catch (error93) {
|
|
46908
|
+
if (process.env.DEBUG_SWARM) {
|
|
46909
|
+
console.warn("[snapshot-writer] write failed:", error93 instanceof Error ? error93.message : String(error93));
|
|
46910
|
+
}
|
|
46911
|
+
}
|
|
46862
46912
|
}
|
|
46863
46913
|
function createSnapshotWriterHook(directory) {
|
|
46864
46914
|
return async (_input, _output) => {
|
|
46865
|
-
|
|
46866
|
-
|
|
46867
|
-
|
|
46868
|
-
|
|
46915
|
+
if (pendingWrite)
|
|
46916
|
+
clearTimeout(pendingWrite);
|
|
46917
|
+
pendingWrite = setTimeout(() => {
|
|
46918
|
+
pendingWrite = null;
|
|
46919
|
+
lastWritePromise = writeSnapshot(directory, swarmState).catch(() => {});
|
|
46920
|
+
}, 2000);
|
|
46921
|
+
};
|
|
46922
|
+
}
|
|
46923
|
+
async function flushPendingSnapshot(directory) {
|
|
46924
|
+
if (pendingWrite) {
|
|
46925
|
+
clearTimeout(pendingWrite);
|
|
46926
|
+
pendingWrite = null;
|
|
46927
|
+
await writeSnapshot(directory, swarmState).catch(() => {});
|
|
46928
|
+
} else {
|
|
46929
|
+
await lastWritePromise;
|
|
46930
|
+
}
|
|
46869
46931
|
}
|
|
46870
46932
|
|
|
46871
46933
|
// src/commands/handoff.ts
|
|
@@ -46875,8 +46937,9 @@ async function handleHandoffCommand(directory, _args) {
|
|
|
46875
46937
|
const resolvedPath = validateSwarmPath(directory, "handoff.md");
|
|
46876
46938
|
const tempPath = `${resolvedPath}.tmp.${crypto3.randomUUID()}`;
|
|
46877
46939
|
await Bun.write(tempPath, markdown);
|
|
46878
|
-
|
|
46940
|
+
renameSync6(tempPath, resolvedPath);
|
|
46879
46941
|
await writeSnapshot(directory, swarmState);
|
|
46942
|
+
await flushPendingSnapshot(directory);
|
|
46880
46943
|
return `## Handoff Brief Written
|
|
46881
46944
|
|
|
46882
46945
|
Brief written to \`.swarm/handoff.md\`.
|
|
@@ -47586,10 +47649,41 @@ async function handleResetCommand(directory, args2) {
|
|
|
47586
47649
|
`);
|
|
47587
47650
|
}
|
|
47588
47651
|
|
|
47652
|
+
// src/commands/reset-session.ts
|
|
47653
|
+
init_utils2();
|
|
47654
|
+
import * as fs15 from "fs";
|
|
47655
|
+
async function handleResetSessionCommand(directory, _args) {
|
|
47656
|
+
const results = [];
|
|
47657
|
+
try {
|
|
47658
|
+
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
47659
|
+
if (fs15.existsSync(statePath)) {
|
|
47660
|
+
fs15.unlinkSync(statePath);
|
|
47661
|
+
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
47662
|
+
} else {
|
|
47663
|
+
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
47664
|
+
}
|
|
47665
|
+
} catch {
|
|
47666
|
+
results.push("\u274C Failed to delete state.json");
|
|
47667
|
+
}
|
|
47668
|
+
const sessionCount = swarmState.agentSessions.size;
|
|
47669
|
+
swarmState.agentSessions.clear();
|
|
47670
|
+
results.push(`\u2705 Cleared ${sessionCount} in-memory agent session(s)`);
|
|
47671
|
+
return [
|
|
47672
|
+
"## Session State Reset",
|
|
47673
|
+
"",
|
|
47674
|
+
...results,
|
|
47675
|
+
"",
|
|
47676
|
+
"Session state cleared. Plan, evidence, and knowledge preserved.",
|
|
47677
|
+
"",
|
|
47678
|
+
"**Next step:** Start a new OpenCode session. The plugin will initialize fresh session state on startup."
|
|
47679
|
+
].join(`
|
|
47680
|
+
`);
|
|
47681
|
+
}
|
|
47682
|
+
|
|
47589
47683
|
// src/summaries/manager.ts
|
|
47590
47684
|
init_utils2();
|
|
47591
47685
|
init_utils();
|
|
47592
|
-
import { mkdirSync as mkdirSync8, readdirSync as readdirSync7, renameSync as
|
|
47686
|
+
import { mkdirSync as mkdirSync8, readdirSync as readdirSync7, renameSync as renameSync7, rmSync as rmSync3, statSync as statSync7 } from "fs";
|
|
47593
47687
|
import * as path26 from "path";
|
|
47594
47688
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
47595
47689
|
function sanitizeSummaryId(id) {
|
|
@@ -47633,7 +47727,7 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
|
|
|
47633
47727
|
const tempPath = path26.join(summaryDir, `${sanitizedId}.json.tmp.${Date.now()}.${process.pid}`);
|
|
47634
47728
|
try {
|
|
47635
47729
|
await Bun.write(tempPath, entryJson);
|
|
47636
|
-
|
|
47730
|
+
renameSync7(tempPath, summaryPath);
|
|
47637
47731
|
} catch (error93) {
|
|
47638
47732
|
try {
|
|
47639
47733
|
rmSync3(tempPath, { force: true });
|
|
@@ -47696,18 +47790,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
|
47696
47790
|
|
|
47697
47791
|
// src/commands/rollback.ts
|
|
47698
47792
|
init_utils2();
|
|
47699
|
-
import * as
|
|
47793
|
+
import * as fs16 from "fs";
|
|
47700
47794
|
import * as path27 from "path";
|
|
47701
47795
|
async function handleRollbackCommand(directory, args2) {
|
|
47702
47796
|
const phaseArg = args2[0];
|
|
47703
47797
|
if (!phaseArg) {
|
|
47704
47798
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
47705
|
-
if (!
|
|
47799
|
+
if (!fs16.existsSync(manifestPath2)) {
|
|
47706
47800
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
47707
47801
|
}
|
|
47708
47802
|
let manifest2;
|
|
47709
47803
|
try {
|
|
47710
|
-
manifest2 = JSON.parse(
|
|
47804
|
+
manifest2 = JSON.parse(fs16.readFileSync(manifestPath2, "utf-8"));
|
|
47711
47805
|
} catch {
|
|
47712
47806
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
47713
47807
|
}
|
|
@@ -47729,12 +47823,12 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
47729
47823
|
return "Error: Phase number must be a positive integer.";
|
|
47730
47824
|
}
|
|
47731
47825
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
47732
|
-
if (!
|
|
47826
|
+
if (!fs16.existsSync(manifestPath)) {
|
|
47733
47827
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
47734
47828
|
}
|
|
47735
47829
|
let manifest;
|
|
47736
47830
|
try {
|
|
47737
|
-
manifest = JSON.parse(
|
|
47831
|
+
manifest = JSON.parse(fs16.readFileSync(manifestPath, "utf-8"));
|
|
47738
47832
|
} catch {
|
|
47739
47833
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
47740
47834
|
}
|
|
@@ -47744,10 +47838,10 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
47744
47838
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
47745
47839
|
}
|
|
47746
47840
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
47747
|
-
if (!
|
|
47841
|
+
if (!fs16.existsSync(checkpointDir)) {
|
|
47748
47842
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
47749
47843
|
}
|
|
47750
|
-
const checkpointFiles =
|
|
47844
|
+
const checkpointFiles = fs16.readdirSync(checkpointDir);
|
|
47751
47845
|
if (checkpointFiles.length === 0) {
|
|
47752
47846
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
47753
47847
|
}
|
|
@@ -47758,7 +47852,7 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
47758
47852
|
const src = path27.join(checkpointDir, file3);
|
|
47759
47853
|
const dest = path27.join(swarmDir, file3);
|
|
47760
47854
|
try {
|
|
47761
|
-
|
|
47855
|
+
fs16.cpSync(src, dest, { recursive: true, force: true });
|
|
47762
47856
|
successes.push(file3);
|
|
47763
47857
|
} catch (error93) {
|
|
47764
47858
|
failures.push({ file: file3, error: error93.message });
|
|
@@ -47775,7 +47869,7 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
47775
47869
|
timestamp: new Date().toISOString()
|
|
47776
47870
|
};
|
|
47777
47871
|
try {
|
|
47778
|
-
|
|
47872
|
+
fs16.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
47779
47873
|
`);
|
|
47780
47874
|
} catch (error93) {
|
|
47781
47875
|
console.error("Failed to write rollback event:", error93);
|
|
@@ -47818,11 +47912,11 @@ async function handleSimulateCommand(directory, args2) {
|
|
|
47818
47912
|
];
|
|
47819
47913
|
const report = reportLines.filter(Boolean).join(`
|
|
47820
47914
|
`);
|
|
47821
|
-
const
|
|
47915
|
+
const fs17 = await import("fs/promises");
|
|
47822
47916
|
const path28 = await import("path");
|
|
47823
47917
|
const reportPath = path28.join(directory, ".swarm", "simulate-report.md");
|
|
47824
|
-
await
|
|
47825
|
-
await
|
|
47918
|
+
await fs17.mkdir(path28.dirname(reportPath), { recursive: true });
|
|
47919
|
+
await fs17.writeFile(reportPath, report, "utf-8");
|
|
47826
47920
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
47827
47921
|
}
|
|
47828
47922
|
|
|
@@ -48179,7 +48273,7 @@ init_utils2();
|
|
|
48179
48273
|
init_manager2();
|
|
48180
48274
|
|
|
48181
48275
|
// src/services/compaction-service.ts
|
|
48182
|
-
import * as
|
|
48276
|
+
import * as fs17 from "fs";
|
|
48183
48277
|
import * as path28 from "path";
|
|
48184
48278
|
function makeInitialState() {
|
|
48185
48279
|
return {
|
|
@@ -48201,7 +48295,7 @@ function appendSnapshot(directory, tier, budgetPct, message) {
|
|
|
48201
48295
|
## [${tier.toUpperCase()}] ${timestamp} \u2014 ${budgetPct.toFixed(1)}% used
|
|
48202
48296
|
${message}
|
|
48203
48297
|
`;
|
|
48204
|
-
|
|
48298
|
+
fs17.appendFileSync(snapshotPath, entry, "utf-8");
|
|
48205
48299
|
} catch {}
|
|
48206
48300
|
}
|
|
48207
48301
|
function buildObservationMessage(budgetPct) {
|
|
@@ -48813,8 +48907,46 @@ async function executeWriteRetro(args2, directory) {
|
|
|
48813
48907
|
top_rejection_reasons: args2.top_rejection_reasons ?? [],
|
|
48814
48908
|
lessons_learned: (args2.lessons_learned ?? []).slice(0, 5),
|
|
48815
48909
|
user_directives: [],
|
|
48816
|
-
approaches_tried: []
|
|
48910
|
+
approaches_tried: [],
|
|
48911
|
+
error_taxonomy: []
|
|
48817
48912
|
};
|
|
48913
|
+
const taxonomy = [];
|
|
48914
|
+
try {
|
|
48915
|
+
for (const taskSuffix of ["1", "2", "3", "4", "5"]) {
|
|
48916
|
+
const phaseTaskId = `${phase}.${taskSuffix}`;
|
|
48917
|
+
const result = await loadEvidence(directory, phaseTaskId);
|
|
48918
|
+
if (result.status !== "found")
|
|
48919
|
+
continue;
|
|
48920
|
+
const bundle = result.bundle;
|
|
48921
|
+
for (const entry of bundle.entries) {
|
|
48922
|
+
const e = entry;
|
|
48923
|
+
if (e.type === "review" && e.verdict === "fail") {
|
|
48924
|
+
const reasonParts = [];
|
|
48925
|
+
if (typeof e.summary === "string")
|
|
48926
|
+
reasonParts.push(e.summary);
|
|
48927
|
+
if (Array.isArray(e.issues)) {
|
|
48928
|
+
for (const iss of e.issues) {
|
|
48929
|
+
if (typeof iss.message === "string")
|
|
48930
|
+
reasonParts.push(iss.message);
|
|
48931
|
+
}
|
|
48932
|
+
}
|
|
48933
|
+
const reason = reasonParts.join(" ");
|
|
48934
|
+
if (/signature|type|contract|interface/i.test(reason)) {
|
|
48935
|
+
taxonomy.push("interface_mismatch");
|
|
48936
|
+
} else {
|
|
48937
|
+
taxonomy.push("logic_error");
|
|
48938
|
+
}
|
|
48939
|
+
} else if (e.type === "test" && e.verdict === "fail") {
|
|
48940
|
+
taxonomy.push("logic_error");
|
|
48941
|
+
} else if (e.agent === "scope_guard" && e.verdict === "fail") {
|
|
48942
|
+
taxonomy.push("scope_creep");
|
|
48943
|
+
} else if (e.agent === "loop_detector" && e.verdict === "fail") {
|
|
48944
|
+
taxonomy.push("gate_evasion");
|
|
48945
|
+
}
|
|
48946
|
+
}
|
|
48947
|
+
}
|
|
48948
|
+
} catch {}
|
|
48949
|
+
retroEntry.error_taxonomy = [...new Set(taxonomy)];
|
|
48818
48950
|
try {
|
|
48819
48951
|
await saveEvidence(directory, taskId, retroEntry);
|
|
48820
48952
|
return JSON.stringify({
|
|
@@ -49029,6 +49161,10 @@ var COMMAND_REGISTRY = {
|
|
|
49029
49161
|
handler: (ctx) => handleResetCommand(ctx.directory, ctx.args),
|
|
49030
49162
|
description: "Clear swarm state files [--confirm]"
|
|
49031
49163
|
},
|
|
49164
|
+
"reset-session": {
|
|
49165
|
+
handler: (ctx) => handleResetSessionCommand(ctx.directory, ctx.args),
|
|
49166
|
+
description: "Clear session state while preserving plan, evidence, and knowledge"
|
|
49167
|
+
},
|
|
49032
49168
|
rollback: {
|
|
49033
49169
|
handler: (ctx) => handleRollbackCommand(ctx.directory, ctx.args),
|
|
49034
49170
|
description: "Restore swarm state to a checkpoint <phase>"
|
|
@@ -49133,7 +49269,7 @@ init_constants();
|
|
|
49133
49269
|
init_schema();
|
|
49134
49270
|
|
|
49135
49271
|
// src/hooks/agent-activity.ts
|
|
49136
|
-
import { renameSync as
|
|
49272
|
+
import { renameSync as renameSync8, unlinkSync as unlinkSync4 } from "fs";
|
|
49137
49273
|
init_utils();
|
|
49138
49274
|
init_utils2();
|
|
49139
49275
|
function createAgentActivityHooks(config3, directory) {
|
|
@@ -49207,10 +49343,10 @@ async function doFlush(directory) {
|
|
|
49207
49343
|
const tempPath = `${path29}.tmp`;
|
|
49208
49344
|
try {
|
|
49209
49345
|
await Bun.write(tempPath, updated);
|
|
49210
|
-
|
|
49346
|
+
renameSync8(tempPath, path29);
|
|
49211
49347
|
} catch (writeError) {
|
|
49212
49348
|
try {
|
|
49213
|
-
|
|
49349
|
+
unlinkSync4(tempPath);
|
|
49214
49350
|
} catch {}
|
|
49215
49351
|
throw writeError;
|
|
49216
49352
|
}
|
|
@@ -49256,7 +49392,7 @@ ${content.substring(endIndex + 1)}`;
|
|
|
49256
49392
|
}
|
|
49257
49393
|
// src/hooks/compaction-customizer.ts
|
|
49258
49394
|
init_manager2();
|
|
49259
|
-
import * as
|
|
49395
|
+
import * as fs18 from "fs";
|
|
49260
49396
|
import { join as join25 } from "path";
|
|
49261
49397
|
init_utils2();
|
|
49262
49398
|
function createCompactionCustomizerHook(config3, directory) {
|
|
@@ -49304,7 +49440,7 @@ function createCompactionCustomizerHook(config3, directory) {
|
|
|
49304
49440
|
}
|
|
49305
49441
|
try {
|
|
49306
49442
|
const summariesDir = join25(directory, ".swarm", "summaries");
|
|
49307
|
-
const files = await
|
|
49443
|
+
const files = await fs18.promises.readdir(summariesDir);
|
|
49308
49444
|
if (files.length > 0) {
|
|
49309
49445
|
const count = files.length;
|
|
49310
49446
|
output.context.push(`[CONTEXT OPTIMIZATION] Tool outputs from earlier in this session have been stored to disk. When compacting, replace any large tool output blocks (bash, test_runner, lint, diff results) with a one-line reference: "[Output stored \u2014 use /swarm retrieve to access full content]". Preserve the tool name, exit status, and any error messages. Discard raw output lines.`);
|
|
@@ -49789,7 +49925,7 @@ function maskToolOutput(msg, _threshold) {
|
|
|
49789
49925
|
}
|
|
49790
49926
|
// src/hooks/delegation-gate.ts
|
|
49791
49927
|
init_schema();
|
|
49792
|
-
import * as
|
|
49928
|
+
import * as fs19 from "fs";
|
|
49793
49929
|
import * as path31 from "path";
|
|
49794
49930
|
|
|
49795
49931
|
// src/hooks/guardrails.ts
|
|
@@ -49841,6 +49977,7 @@ function detectLoop(sessionId, toolName, args2) {
|
|
|
49841
49977
|
|
|
49842
49978
|
// src/hooks/guardrails.ts
|
|
49843
49979
|
var storedInputArgs = new Map;
|
|
49980
|
+
var TRANSIENT_MODEL_ERROR_PATTERN = /rate.?limit|429|503|timeout|overloaded|model.?not.?found|temporarily unavailable|server error/i;
|
|
49844
49981
|
function getStoredInputArgs(callID) {
|
|
49845
49982
|
return storedInputArgs.get(callID);
|
|
49846
49983
|
}
|
|
@@ -49850,6 +49987,8 @@ function setStoredInputArgs(callID, args2) {
|
|
|
49850
49987
|
function deleteStoredInputArgs(callID) {
|
|
49851
49988
|
storedInputArgs.delete(callID);
|
|
49852
49989
|
}
|
|
49990
|
+
var toolCallsSinceLastWrite = new Map;
|
|
49991
|
+
var noOpWarningIssued = new Set;
|
|
49853
49992
|
function extractPhaseNumber(phaseString) {
|
|
49854
49993
|
if (!phaseString)
|
|
49855
49994
|
return 1;
|
|
@@ -50016,6 +50155,9 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
|
50016
50155
|
const coderSession = swarmState.agentSessions.get(input.sessionID);
|
|
50017
50156
|
if (coderSession) {
|
|
50018
50157
|
coderSession.modifiedFilesThisCoderTask = [];
|
|
50158
|
+
if (!coderSession.revisionLimitHit) {
|
|
50159
|
+
coderSession.coderRevisions = 0;
|
|
50160
|
+
}
|
|
50019
50161
|
}
|
|
50020
50162
|
}
|
|
50021
50163
|
}
|
|
@@ -50024,7 +50166,7 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
|
50024
50166
|
const loopResult = detectLoop(input.sessionID, input.tool, loopArgs);
|
|
50025
50167
|
if (loopResult.count >= 5) {
|
|
50026
50168
|
throw new Error(`CIRCUIT BREAKER: Delegation loop detected (${loopResult.count} identical patterns). Session paused. Ask the user for guidance.`);
|
|
50027
|
-
} else if (loopResult.count
|
|
50169
|
+
} else if (loopResult.count >= 3 && loopResult.count < 5) {
|
|
50028
50170
|
const agentName2 = typeof loopArgs?.subagent_type === "string" ? loopArgs.subagent_type : "agent";
|
|
50029
50171
|
const loopSession = swarmState.agentSessions.get(input.sessionID);
|
|
50030
50172
|
if (loopSession) {
|
|
@@ -50355,6 +50497,16 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
|
50355
50497
|
}
|
|
50356
50498
|
if (delegation.isDelegation && delegation.targetAgent === "coder" && session.lastCoderDelegationTaskId) {
|
|
50357
50499
|
session.currentTaskId = session.lastCoderDelegationTaskId;
|
|
50500
|
+
if (!session.revisionLimitHit) {
|
|
50501
|
+
session.coderRevisions++;
|
|
50502
|
+
const maxRevisions = cfg.max_coder_revisions ?? 5;
|
|
50503
|
+
if (session.coderRevisions >= maxRevisions) {
|
|
50504
|
+
session.revisionLimitHit = true;
|
|
50505
|
+
session.pendingAdvisoryMessages ??= [];
|
|
50506
|
+
session.pendingAdvisoryMessages.push(`CODER REVISION LIMIT: Agent has been revised ${session.coderRevisions} times ` + `(max: ${maxRevisions}) for task ${session.currentTaskId ?? "unknown"}. ` + `Escalate to user or consider a fundamentally different approach.`);
|
|
50507
|
+
swarmState.pendingEvents++;
|
|
50508
|
+
}
|
|
50509
|
+
}
|
|
50358
50510
|
session.partialGateWarningsIssuedForTask?.delete(session.currentTaskId);
|
|
50359
50511
|
if (session.declaredCoderScope !== null) {
|
|
50360
50512
|
const undeclaredFiles = session.modifiedFilesThisCoderTask.map((f) => f.replace(/[\r\n\t]/g, "_")).filter((f) => !isInDeclaredScope(f, session.declaredCoderScope));
|
|
@@ -50367,15 +50519,45 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
|
50367
50519
|
session.modifiedFilesThisCoderTask = [];
|
|
50368
50520
|
}
|
|
50369
50521
|
}
|
|
50522
|
+
const sessionId = input.sessionID;
|
|
50523
|
+
const normalizedToolName = input.tool.replace(/^[^:]+[:.]/, "");
|
|
50524
|
+
if (isWriteTool(normalizedToolName)) {
|
|
50525
|
+
toolCallsSinceLastWrite.set(sessionId, 0);
|
|
50526
|
+
} else {
|
|
50527
|
+
const count = (toolCallsSinceLastWrite.get(sessionId) ?? 0) + 1;
|
|
50528
|
+
toolCallsSinceLastWrite.set(sessionId, count);
|
|
50529
|
+
const threshold = cfg.no_op_warning_threshold ?? 15;
|
|
50530
|
+
if (count >= threshold && !noOpWarningIssued.has(sessionId) && session?.pendingAdvisoryMessages) {
|
|
50531
|
+
noOpWarningIssued.add(sessionId);
|
|
50532
|
+
session.pendingAdvisoryMessages.push(`WARNING: Agent has made ${count} tool calls with no file modifications. If you are stuck, use /swarm handoff to reset or /swarm turbo to reduce overhead.`);
|
|
50533
|
+
}
|
|
50534
|
+
}
|
|
50370
50535
|
const window2 = getActiveWindow(input.sessionID);
|
|
50371
50536
|
if (!window2)
|
|
50372
50537
|
return;
|
|
50373
50538
|
const hasError = output.output === null || output.output === undefined;
|
|
50374
50539
|
if (hasError) {
|
|
50375
50540
|
window2.consecutiveErrors++;
|
|
50541
|
+
if (session) {
|
|
50542
|
+
const outputStr = typeof output.output === "string" ? output.output : "";
|
|
50543
|
+
const errorContent = output.error ?? outputStr;
|
|
50544
|
+
if (typeof errorContent === "string" && TRANSIENT_MODEL_ERROR_PATTERN.test(errorContent) && !session.modelFallbackExhausted) {
|
|
50545
|
+
session.model_fallback_index++;
|
|
50546
|
+
session.modelFallbackExhausted = true;
|
|
50547
|
+
session.pendingAdvisoryMessages ??= [];
|
|
50548
|
+
session.pendingAdvisoryMessages.push(`MODEL FALLBACK: Transient model error detected (attempt ${session.model_fallback_index}). ` + `The agent model may be rate-limited, overloaded, or temporarily unavailable. ` + `Consider retrying with a fallback model or waiting before retrying.`);
|
|
50549
|
+
swarmState.pendingEvents++;
|
|
50550
|
+
}
|
|
50551
|
+
}
|
|
50376
50552
|
} else {
|
|
50377
50553
|
window2.consecutiveErrors = 0;
|
|
50378
50554
|
window2.lastSuccessTimeMs = Date.now();
|
|
50555
|
+
if (session) {
|
|
50556
|
+
if (session.model_fallback_index > 0) {
|
|
50557
|
+
session.model_fallback_index = 0;
|
|
50558
|
+
session.modelFallbackExhausted = false;
|
|
50559
|
+
}
|
|
50560
|
+
}
|
|
50379
50561
|
}
|
|
50380
50562
|
},
|
|
50381
50563
|
messagesTransform: async (_input, output) => {
|
|
@@ -50652,6 +50834,7 @@ function hashArgs(args2) {
|
|
|
50652
50834
|
|
|
50653
50835
|
// src/hooks/delegation-gate.ts
|
|
50654
50836
|
init_utils2();
|
|
50837
|
+
var pendingCoderScopeByTaskId = new Map;
|
|
50655
50838
|
function extractTaskLine(text) {
|
|
50656
50839
|
const match = text.match(/TASK:\s*(.+?)(?:\n|$)/i);
|
|
50657
50840
|
return match ? match[1].trim() : null;
|
|
@@ -50670,7 +50853,7 @@ function extractPlanTaskId(text) {
|
|
|
50670
50853
|
function getSeedTaskId(session) {
|
|
50671
50854
|
return session.currentTaskId ?? session.lastCoderDelegationTaskId;
|
|
50672
50855
|
}
|
|
50673
|
-
function getEvidenceTaskId(session, directory) {
|
|
50856
|
+
async function getEvidenceTaskId(session, directory) {
|
|
50674
50857
|
const primary = session.currentTaskId ?? session.lastCoderDelegationTaskId;
|
|
50675
50858
|
if (primary)
|
|
50676
50859
|
return primary;
|
|
@@ -50687,7 +50870,7 @@ function getEvidenceTaskId(session, directory) {
|
|
|
50687
50870
|
if (!resolvedPlanPath.startsWith(resolvedDirectory + path31.sep) && resolvedPlanPath !== resolvedDirectory) {
|
|
50688
50871
|
return null;
|
|
50689
50872
|
}
|
|
50690
|
-
const planContent =
|
|
50873
|
+
const planContent = await fs19.promises.readFile(resolvedPlanPath, "utf-8");
|
|
50691
50874
|
const plan = JSON.parse(planContent);
|
|
50692
50875
|
if (!plan || !Array.isArray(plan.phases)) {
|
|
50693
50876
|
return null;
|
|
@@ -50807,7 +50990,7 @@ function createDelegationGateHook(config3, directory) {
|
|
|
50807
50990
|
}
|
|
50808
50991
|
if (typeof subagentType === "string") {
|
|
50809
50992
|
const rawTaskId = directArgs?.task_id;
|
|
50810
|
-
const evidenceTaskId = typeof rawTaskId === "string" && rawTaskId.length <= 20 && /^\d+\.\d+$/.test(rawTaskId.trim()) ? rawTaskId.trim() : getEvidenceTaskId(session, directory);
|
|
50993
|
+
const evidenceTaskId = typeof rawTaskId === "string" && rawTaskId.length <= 20 && /^\d+\.\d+$/.test(rawTaskId.trim()) ? rawTaskId.trim() : await getEvidenceTaskId(session, directory);
|
|
50811
50994
|
if (evidenceTaskId) {
|
|
50812
50995
|
try {
|
|
50813
50996
|
const turbo = hasActiveTurboMode();
|
|
@@ -50927,7 +51110,7 @@ function createDelegationGateHook(config3, directory) {
|
|
|
50927
51110
|
}
|
|
50928
51111
|
{
|
|
50929
51112
|
const rawTaskId = directArgs?.task_id;
|
|
50930
|
-
const evidenceTaskId = typeof rawTaskId === "string" && rawTaskId.length <= 20 && /^\d+\.\d+$/.test(rawTaskId.trim()) ? rawTaskId.trim() : getEvidenceTaskId(session, directory);
|
|
51113
|
+
const evidenceTaskId = typeof rawTaskId === "string" && rawTaskId.length <= 20 && /^\d+\.\d+$/.test(rawTaskId.trim()) ? rawTaskId.trim() : await getEvidenceTaskId(session, directory);
|
|
50931
51114
|
if (evidenceTaskId) {
|
|
50932
51115
|
try {
|
|
50933
51116
|
const turbo = hasActiveTurboMode();
|
|
@@ -51024,7 +51207,7 @@ ${trimComment}${after}`;
|
|
|
51024
51207
|
const currentTaskId = planTaskId ?? taskIdFromLine;
|
|
51025
51208
|
const coderDelegationPattern = /(?:^|\n)\s*(?:\w+_)?coder\s*\n\s*TASK:/i;
|
|
51026
51209
|
const isCoderDelegation = coderDelegationPattern.test(text);
|
|
51027
|
-
const priorCoderTaskId = sessionID ?
|
|
51210
|
+
const priorCoderTaskId = sessionID ? swarmState.agentSessions.get(sessionID)?.lastCoderDelegationTaskId ?? null : null;
|
|
51028
51211
|
if (sessionID && isCoderDelegation && currentTaskId) {
|
|
51029
51212
|
const session = ensureAgentSession(sessionID);
|
|
51030
51213
|
session.lastCoderDelegationTaskId = currentTaskId;
|
|
@@ -51037,6 +51220,11 @@ ${trimComment}${after}`;
|
|
|
51037
51220
|
}
|
|
51038
51221
|
}
|
|
51039
51222
|
session.declaredCoderScope = declaredFiles.length > 0 ? declaredFiles : null;
|
|
51223
|
+
if (declaredFiles.length > 0 && currentTaskId) {
|
|
51224
|
+
pendingCoderScopeByTaskId.set(currentTaskId, declaredFiles);
|
|
51225
|
+
} else {
|
|
51226
|
+
pendingCoderScopeByTaskId.delete(currentTaskId);
|
|
51227
|
+
}
|
|
51040
51228
|
try {
|
|
51041
51229
|
advanceTaskState(session, currentTaskId, "coder_delegated");
|
|
51042
51230
|
} catch (err2) {
|
|
@@ -51164,7 +51352,7 @@ ${warningLines.join(`
|
|
|
51164
51352
|
}
|
|
51165
51353
|
// src/hooks/delegation-sanitizer.ts
|
|
51166
51354
|
init_utils2();
|
|
51167
|
-
import * as
|
|
51355
|
+
import * as fs20 from "fs";
|
|
51168
51356
|
var SANITIZATION_PATTERNS = [
|
|
51169
51357
|
/\b\d+(st|nd|rd|th)\s+(attempt|try|time)\b/gi,
|
|
51170
51358
|
/\b(5th|fifth|final|last)\s+attempt\b/gi,
|
|
@@ -51235,7 +51423,7 @@ function createDelegationSanitizerHook(directory) {
|
|
|
51235
51423
|
stripped_patterns: result.stripped,
|
|
51236
51424
|
timestamp: new Date().toISOString()
|
|
51237
51425
|
};
|
|
51238
|
-
|
|
51426
|
+
fs20.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
51239
51427
|
`, "utf-8");
|
|
51240
51428
|
} catch {}
|
|
51241
51429
|
}
|
|
@@ -51492,12 +51680,12 @@ init_schema();
|
|
|
51492
51680
|
init_manager();
|
|
51493
51681
|
init_detector();
|
|
51494
51682
|
init_manager2();
|
|
51495
|
-
import * as
|
|
51683
|
+
import * as fs22 from "fs";
|
|
51496
51684
|
|
|
51497
51685
|
// src/services/decision-drift-analyzer.ts
|
|
51498
51686
|
init_utils2();
|
|
51499
51687
|
init_manager2();
|
|
51500
|
-
import * as
|
|
51688
|
+
import * as fs21 from "fs";
|
|
51501
51689
|
import * as path33 from "path";
|
|
51502
51690
|
var DEFAULT_DRIFT_CONFIG = {
|
|
51503
51691
|
staleThresholdPhases: 1,
|
|
@@ -51655,8 +51843,8 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
|
|
|
51655
51843
|
const contextPath = path33.join(directory, ".swarm", "context.md");
|
|
51656
51844
|
let contextContent = "";
|
|
51657
51845
|
try {
|
|
51658
|
-
if (
|
|
51659
|
-
contextContent =
|
|
51846
|
+
if (fs21.existsSync(contextPath)) {
|
|
51847
|
+
contextContent = fs21.readFileSync(contextPath, "utf-8");
|
|
51660
51848
|
}
|
|
51661
51849
|
} catch {
|
|
51662
51850
|
return {
|
|
@@ -52150,11 +52338,11 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
52150
52338
|
if (handoffContent) {
|
|
52151
52339
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
52152
52340
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
52153
|
-
if (
|
|
52341
|
+
if (fs22.existsSync(consumedPath)) {
|
|
52154
52342
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
52155
|
-
|
|
52343
|
+
fs22.unlinkSync(consumedPath);
|
|
52156
52344
|
}
|
|
52157
|
-
|
|
52345
|
+
fs22.renameSync(handoffPath, consumedPath);
|
|
52158
52346
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
52159
52347
|
The previous model's session ended. Here is your starting context:
|
|
52160
52348
|
|
|
@@ -52434,11 +52622,11 @@ ${budgetWarning}`);
|
|
|
52434
52622
|
if (handoffContent) {
|
|
52435
52623
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
52436
52624
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
52437
|
-
if (
|
|
52625
|
+
if (fs22.existsSync(consumedPath)) {
|
|
52438
52626
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
52439
|
-
|
|
52627
|
+
fs22.unlinkSync(consumedPath);
|
|
52440
52628
|
}
|
|
52441
|
-
|
|
52629
|
+
fs22.renameSync(handoffPath, consumedPath);
|
|
52442
52630
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
52443
52631
|
The previous model's session ended. Here is your starting context:
|
|
52444
52632
|
|
|
@@ -53207,7 +53395,7 @@ function isReadTool(toolName) {
|
|
|
53207
53395
|
}
|
|
53208
53396
|
|
|
53209
53397
|
// src/hooks/incremental-verify.ts
|
|
53210
|
-
import * as
|
|
53398
|
+
import * as fs23 from "fs";
|
|
53211
53399
|
import * as path34 from "path";
|
|
53212
53400
|
|
|
53213
53401
|
// src/hooks/spawn-helper.ts
|
|
@@ -53283,21 +53471,21 @@ function spawnAsync(command, cwd, timeoutMs) {
|
|
|
53283
53471
|
// src/hooks/incremental-verify.ts
|
|
53284
53472
|
var emittedSkipAdvisories = new Set;
|
|
53285
53473
|
function detectPackageManager(projectDir) {
|
|
53286
|
-
if (
|
|
53474
|
+
if (fs23.existsSync(path34.join(projectDir, "bun.lockb")))
|
|
53287
53475
|
return "bun";
|
|
53288
|
-
if (
|
|
53476
|
+
if (fs23.existsSync(path34.join(projectDir, "pnpm-lock.yaml")))
|
|
53289
53477
|
return "pnpm";
|
|
53290
|
-
if (
|
|
53478
|
+
if (fs23.existsSync(path34.join(projectDir, "yarn.lock")))
|
|
53291
53479
|
return "yarn";
|
|
53292
|
-
if (
|
|
53480
|
+
if (fs23.existsSync(path34.join(projectDir, "package-lock.json")))
|
|
53293
53481
|
return "npm";
|
|
53294
53482
|
return "bun";
|
|
53295
53483
|
}
|
|
53296
53484
|
function detectTypecheckCommand(projectDir) {
|
|
53297
53485
|
const pkgPath = path34.join(projectDir, "package.json");
|
|
53298
|
-
if (
|
|
53486
|
+
if (fs23.existsSync(pkgPath)) {
|
|
53299
53487
|
try {
|
|
53300
|
-
const pkg = JSON.parse(
|
|
53488
|
+
const pkg = JSON.parse(fs23.readFileSync(pkgPath, "utf8"));
|
|
53301
53489
|
const scripts = pkg.scripts;
|
|
53302
53490
|
if (scripts?.typecheck) {
|
|
53303
53491
|
const pm = detectPackageManager(projectDir);
|
|
@@ -53311,8 +53499,8 @@ function detectTypecheckCommand(projectDir) {
|
|
|
53311
53499
|
...pkg.dependencies,
|
|
53312
53500
|
...pkg.devDependencies
|
|
53313
53501
|
};
|
|
53314
|
-
if (!deps?.typescript && !
|
|
53315
|
-
const hasTSMarkers = deps?.typescript ||
|
|
53502
|
+
if (!deps?.typescript && !fs23.existsSync(path34.join(projectDir, "tsconfig.json"))) {}
|
|
53503
|
+
const hasTSMarkers = deps?.typescript || fs23.existsSync(path34.join(projectDir, "tsconfig.json"));
|
|
53316
53504
|
if (hasTSMarkers) {
|
|
53317
53505
|
return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
|
|
53318
53506
|
}
|
|
@@ -53320,17 +53508,17 @@ function detectTypecheckCommand(projectDir) {
|
|
|
53320
53508
|
return null;
|
|
53321
53509
|
}
|
|
53322
53510
|
}
|
|
53323
|
-
if (
|
|
53511
|
+
if (fs23.existsSync(path34.join(projectDir, "go.mod"))) {
|
|
53324
53512
|
return { command: ["go", "vet", "./..."], language: "go" };
|
|
53325
53513
|
}
|
|
53326
|
-
if (
|
|
53514
|
+
if (fs23.existsSync(path34.join(projectDir, "Cargo.toml"))) {
|
|
53327
53515
|
return { command: ["cargo", "check"], language: "rust" };
|
|
53328
53516
|
}
|
|
53329
|
-
if (
|
|
53517
|
+
if (fs23.existsSync(path34.join(projectDir, "pyproject.toml")) || fs23.existsSync(path34.join(projectDir, "requirements.txt")) || fs23.existsSync(path34.join(projectDir, "setup.py"))) {
|
|
53330
53518
|
return { command: null, language: "python" };
|
|
53331
53519
|
}
|
|
53332
53520
|
try {
|
|
53333
|
-
const entries =
|
|
53521
|
+
const entries = fs23.readdirSync(projectDir);
|
|
53334
53522
|
if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
53335
53523
|
return {
|
|
53336
53524
|
command: ["dotnet", "build", "--no-restore"],
|
|
@@ -53399,7 +53587,7 @@ ${errorSummary}`);
|
|
|
53399
53587
|
}
|
|
53400
53588
|
|
|
53401
53589
|
// src/hooks/knowledge-reader.ts
|
|
53402
|
-
import { existsSync as
|
|
53590
|
+
import { existsSync as existsSync21 } from "fs";
|
|
53403
53591
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
53404
53592
|
import * as path35 from "path";
|
|
53405
53593
|
var JACCARD_THRESHOLD = 0.6;
|
|
@@ -53452,7 +53640,7 @@ async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
|
53452
53640
|
const shownFile = path35.join(directory, ".swarm", ".knowledge-shown.json");
|
|
53453
53641
|
try {
|
|
53454
53642
|
let shownData = {};
|
|
53455
|
-
if (
|
|
53643
|
+
if (existsSync21(shownFile)) {
|
|
53456
53644
|
const content = await readFile5(shownFile, "utf-8");
|
|
53457
53645
|
shownData = JSON.parse(content);
|
|
53458
53646
|
}
|
|
@@ -53554,7 +53742,7 @@ async function readMergedKnowledge(directory, config3, context) {
|
|
|
53554
53742
|
async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
|
|
53555
53743
|
const shownFile = path35.join(directory, ".swarm", ".knowledge-shown.json");
|
|
53556
53744
|
try {
|
|
53557
|
-
if (!
|
|
53745
|
+
if (!existsSync21(shownFile)) {
|
|
53558
53746
|
return;
|
|
53559
53747
|
}
|
|
53560
53748
|
const content = await readFile5(shownFile, "utf-8");
|
|
@@ -54024,12 +54212,12 @@ Use this data to avoid repeating known failure patterns.`;
|
|
|
54024
54212
|
// src/hooks/curator-drift.ts
|
|
54025
54213
|
init_event_bus();
|
|
54026
54214
|
init_utils2();
|
|
54027
|
-
import * as
|
|
54215
|
+
import * as fs24 from "fs";
|
|
54028
54216
|
import * as path36 from "path";
|
|
54029
54217
|
var DRIFT_REPORT_PREFIX = "drift-report-phase-";
|
|
54030
54218
|
async function readPriorDriftReports(directory) {
|
|
54031
54219
|
const swarmDir = path36.join(directory, ".swarm");
|
|
54032
|
-
const entries = await
|
|
54220
|
+
const entries = await fs24.promises.readdir(swarmDir).catch(() => null);
|
|
54033
54221
|
if (entries === null)
|
|
54034
54222
|
return [];
|
|
54035
54223
|
const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
|
|
@@ -54056,9 +54244,9 @@ async function writeDriftReport(directory, report) {
|
|
|
54056
54244
|
const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
|
|
54057
54245
|
const filePath = validateSwarmPath(directory, filename);
|
|
54058
54246
|
const swarmDir = path36.dirname(filePath);
|
|
54059
|
-
await
|
|
54247
|
+
await fs24.promises.mkdir(swarmDir, { recursive: true });
|
|
54060
54248
|
try {
|
|
54061
|
-
await
|
|
54249
|
+
await fs24.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
|
|
54062
54250
|
} catch (err2) {
|
|
54063
54251
|
throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
|
|
54064
54252
|
}
|
|
@@ -54344,7 +54532,7 @@ var WRITE_TOOLS = new Set([
|
|
|
54344
54532
|
"append",
|
|
54345
54533
|
"prepend"
|
|
54346
54534
|
]);
|
|
54347
|
-
function createScopeGuardHook(config3,
|
|
54535
|
+
function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
54348
54536
|
const enabled = config3.enabled ?? true;
|
|
54349
54537
|
const _skipInTurbo = config3.skip_in_turbo ?? false;
|
|
54350
54538
|
return {
|
|
@@ -54361,7 +54549,7 @@ function createScopeGuardHook(config3, _directory, injectAdvisory) {
|
|
|
54361
54549
|
const isArchitect2 = stripKnownSwarmPrefix(agentName) === ORCHESTRATOR_NAME;
|
|
54362
54550
|
if (isArchitect2)
|
|
54363
54551
|
return;
|
|
54364
|
-
const declaredScope = session?.declaredCoderScope;
|
|
54552
|
+
const declaredScope = session?.declaredCoderScope ?? (session?.currentTaskId ? pendingCoderScopeByTaskId.get(session.currentTaskId) : null);
|
|
54365
54553
|
if (!declaredScope || declaredScope.length === 0)
|
|
54366
54554
|
return;
|
|
54367
54555
|
const argsObj = output.args;
|
|
@@ -54369,7 +54557,7 @@ function createScopeGuardHook(config3, _directory, injectAdvisory) {
|
|
|
54369
54557
|
if (typeof rawFilePath !== "string" || !rawFilePath)
|
|
54370
54558
|
return;
|
|
54371
54559
|
const filePath = rawFilePath.replace(/[\r\n\t]/g, "_").split(String.fromCharCode(27)).join("_").replace(/\[[\d;]*m/g, "");
|
|
54372
|
-
if (!isFileInScope(filePath, declaredScope)) {
|
|
54560
|
+
if (!isFileInScope(filePath, declaredScope, directory)) {
|
|
54373
54561
|
const taskId = session?.currentTaskId ?? "unknown";
|
|
54374
54562
|
const violationMessage = `SCOPE VIOLATION: ${agentName} attempted to modify '${filePath}' which is not in declared scope for task ${taskId}. Declared scope: [${declaredScope.slice(0, 3).join(", ")}${declaredScope.length > 3 ? "..." : ""}]`;
|
|
54375
54563
|
if (session) {
|
|
@@ -54392,10 +54580,11 @@ function createScopeGuardHook(config3, _directory, injectAdvisory) {
|
|
|
54392
54580
|
}
|
|
54393
54581
|
};
|
|
54394
54582
|
}
|
|
54395
|
-
function isFileInScope(filePath, scopeEntries) {
|
|
54396
|
-
const
|
|
54583
|
+
function isFileInScope(filePath, scopeEntries, directory) {
|
|
54584
|
+
const dir = directory ?? process.cwd();
|
|
54585
|
+
const resolvedFile = path37.resolve(dir, filePath);
|
|
54397
54586
|
return scopeEntries.some((scope) => {
|
|
54398
|
-
const resolvedScope = path37.resolve(scope);
|
|
54587
|
+
const resolvedScope = path37.resolve(dir, scope);
|
|
54399
54588
|
if (resolvedFile === resolvedScope)
|
|
54400
54589
|
return true;
|
|
54401
54590
|
const rel = path37.relative(resolvedScope, resolvedFile);
|
|
@@ -54448,7 +54637,7 @@ function createSelfReviewHook(config3, injectAdvisory) {
|
|
|
54448
54637
|
}
|
|
54449
54638
|
|
|
54450
54639
|
// src/hooks/slop-detector.ts
|
|
54451
|
-
import * as
|
|
54640
|
+
import * as fs25 from "fs";
|
|
54452
54641
|
import * as path38 from "path";
|
|
54453
54642
|
var WRITE_EDIT_TOOLS = new Set([
|
|
54454
54643
|
"write",
|
|
@@ -54494,7 +54683,7 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
|
|
|
54494
54683
|
function walkFiles(dir, exts, deadline) {
|
|
54495
54684
|
const results = [];
|
|
54496
54685
|
try {
|
|
54497
|
-
for (const entry of
|
|
54686
|
+
for (const entry of fs25.readdirSync(dir, { withFileTypes: true })) {
|
|
54498
54687
|
if (deadline !== undefined && Date.now() > deadline)
|
|
54499
54688
|
break;
|
|
54500
54689
|
if (entry.isSymbolicLink())
|
|
@@ -54514,7 +54703,7 @@ function walkFiles(dir, exts, deadline) {
|
|
|
54514
54703
|
return results;
|
|
54515
54704
|
}
|
|
54516
54705
|
function checkDeadExports(content, projectDir, startTime) {
|
|
54517
|
-
const hasPackageJson =
|
|
54706
|
+
const hasPackageJson = fs25.existsSync(path38.join(projectDir, "package.json"));
|
|
54518
54707
|
if (!hasPackageJson)
|
|
54519
54708
|
return null;
|
|
54520
54709
|
const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
|
|
@@ -54537,7 +54726,7 @@ function checkDeadExports(content, projectDir, startTime) {
|
|
|
54537
54726
|
if (found || Date.now() - startTime > 480)
|
|
54538
54727
|
break;
|
|
54539
54728
|
try {
|
|
54540
|
-
const text =
|
|
54729
|
+
const text = fs25.readFileSync(file3, "utf-8");
|
|
54541
54730
|
if (importPattern.test(text))
|
|
54542
54731
|
found = true;
|
|
54543
54732
|
importPattern.lastIndex = 0;
|
|
@@ -54670,7 +54859,7 @@ Review before proceeding.`;
|
|
|
54670
54859
|
|
|
54671
54860
|
// src/hooks/steering-consumed.ts
|
|
54672
54861
|
init_utils2();
|
|
54673
|
-
import * as
|
|
54862
|
+
import * as fs26 from "fs";
|
|
54674
54863
|
function recordSteeringConsumed(directory, directiveId) {
|
|
54675
54864
|
try {
|
|
54676
54865
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
@@ -54679,7 +54868,7 @@ function recordSteeringConsumed(directory, directiveId) {
|
|
|
54679
54868
|
directiveId,
|
|
54680
54869
|
timestamp: new Date().toISOString()
|
|
54681
54870
|
};
|
|
54682
|
-
|
|
54871
|
+
fs26.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
54683
54872
|
`, "utf-8");
|
|
54684
54873
|
} catch {}
|
|
54685
54874
|
}
|
|
@@ -54796,7 +54985,11 @@ function deserializeAgentSession(s) {
|
|
|
54796
54985
|
lastScopeViolation: null,
|
|
54797
54986
|
scopeViolationDetected: s.scopeViolationDetected,
|
|
54798
54987
|
modifiedFilesThisCoderTask: [],
|
|
54799
|
-
pendingAdvisoryMessages: s.pendingAdvisoryMessages ?? []
|
|
54988
|
+
pendingAdvisoryMessages: s.pendingAdvisoryMessages ?? [],
|
|
54989
|
+
model_fallback_index: s.model_fallback_index ?? 0,
|
|
54990
|
+
modelFallbackExhausted: s.modelFallbackExhausted ?? false,
|
|
54991
|
+
coderRevisions: s.coderRevisions ?? 0,
|
|
54992
|
+
revisionLimitHit: s.revisionLimitHit ?? false
|
|
54800
54993
|
};
|
|
54801
54994
|
}
|
|
54802
54995
|
async function readSnapshot(directory) {
|
|
@@ -54845,6 +55038,10 @@ async function rehydrateState(snapshot) {
|
|
|
54845
55038
|
}
|
|
54846
55039
|
if (snapshot.agentSessions) {
|
|
54847
55040
|
for (const [sessionId, serializedSession] of Object.entries(snapshot.agentSessions)) {
|
|
55041
|
+
if (!serializedSession || typeof serializedSession !== "object" || typeof serializedSession.agentName !== "string" || typeof serializedSession.lastToolCallTime !== "number" || typeof serializedSession.delegationActive !== "boolean") {
|
|
55042
|
+
console.warn("[snapshot-reader] Skipping malformed session %s: missing required fields (agentName, lastToolCallTime, delegationActive)", sessionId);
|
|
55043
|
+
continue;
|
|
55044
|
+
}
|
|
54848
55045
|
swarmState.agentSessions.set(sessionId, deserializeAgentSession(serializedSession));
|
|
54849
55046
|
}
|
|
54850
55047
|
}
|
|
@@ -55035,8 +55232,9 @@ var build_check = createSwarmTool({
|
|
|
55035
55232
|
});
|
|
55036
55233
|
// src/tools/check-gate-status.ts
|
|
55037
55234
|
init_dist();
|
|
55235
|
+
init_manager();
|
|
55038
55236
|
init_create_tool();
|
|
55039
|
-
import * as
|
|
55237
|
+
import * as fs27 from "fs";
|
|
55040
55238
|
import * as path39 from "path";
|
|
55041
55239
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
55042
55240
|
var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -55060,12 +55258,12 @@ function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
|
55060
55258
|
return normalizedPath.startsWith(swarmPath);
|
|
55061
55259
|
}
|
|
55062
55260
|
function readEvidenceFile(evidencePath) {
|
|
55063
|
-
if (!
|
|
55261
|
+
if (!fs27.existsSync(evidencePath)) {
|
|
55064
55262
|
return null;
|
|
55065
55263
|
}
|
|
55066
55264
|
let content;
|
|
55067
55265
|
try {
|
|
55068
|
-
content =
|
|
55266
|
+
content = fs27.readFileSync(evidencePath, "utf-8");
|
|
55069
55267
|
} catch {
|
|
55070
55268
|
return null;
|
|
55071
55269
|
}
|
|
@@ -55158,13 +55356,37 @@ var check_gate_status = createSwarmTool({
|
|
|
55158
55356
|
missingGates.push(requiredGate);
|
|
55159
55357
|
}
|
|
55160
55358
|
}
|
|
55161
|
-
|
|
55359
|
+
let status = missingGates.length === 0 ? "all_passed" : "incomplete";
|
|
55162
55360
|
let message;
|
|
55163
55361
|
if (status === "all_passed") {
|
|
55164
55362
|
message = `All required gates have passed for task "${taskIdInput}".`;
|
|
55165
55363
|
} else {
|
|
55166
55364
|
message = `Task "${taskIdInput}" is incomplete. Missing gates: ${missingGates.join(", ")}.`;
|
|
55167
55365
|
}
|
|
55366
|
+
let secretscanVerdict = "not_run";
|
|
55367
|
+
try {
|
|
55368
|
+
const evidenceResult = await loadEvidence(directory, taskIdInput);
|
|
55369
|
+
if (evidenceResult.status === "found") {
|
|
55370
|
+
const secretscanEntries = evidenceResult.bundle.entries.filter((entry) => entry.type === "secretscan");
|
|
55371
|
+
if (secretscanEntries.length > 0) {
|
|
55372
|
+
const lastSecretscan = secretscanEntries[secretscanEntries.length - 1];
|
|
55373
|
+
if (isSecretscanEvidence(lastSecretscan)) {
|
|
55374
|
+
if (lastSecretscan.verdict === "fail" || lastSecretscan.verdict === "rejected") {
|
|
55375
|
+
secretscanVerdict = "fail";
|
|
55376
|
+
missingGates.push("secretscan (BLOCKED \u2014 secrets detected)");
|
|
55377
|
+
if (status === "all_passed") {
|
|
55378
|
+
status = "incomplete";
|
|
55379
|
+
}
|
|
55380
|
+
message = `BLOCKED: Secretscan found secrets in prior scan. ${message}`;
|
|
55381
|
+
} else if (lastSecretscan.verdict === "pass" || lastSecretscan.verdict === "approved" || lastSecretscan.verdict === "info") {
|
|
55382
|
+
secretscanVerdict = "pass";
|
|
55383
|
+
}
|
|
55384
|
+
}
|
|
55385
|
+
} else {
|
|
55386
|
+
message += " Advisory: No secretscan evidence found for this task. Consider running secretscan.";
|
|
55387
|
+
}
|
|
55388
|
+
}
|
|
55389
|
+
} catch {}
|
|
55168
55390
|
const todoScan = evidenceData.todo_scan;
|
|
55169
55391
|
const result = {
|
|
55170
55392
|
taskId: taskIdInput,
|
|
@@ -55174,7 +55396,8 @@ var check_gate_status = createSwarmTool({
|
|
|
55174
55396
|
missing_gates: missingGates,
|
|
55175
55397
|
gates: gatesMap,
|
|
55176
55398
|
message,
|
|
55177
|
-
todo_scan: todoScan ?? null
|
|
55399
|
+
todo_scan: todoScan ?? null,
|
|
55400
|
+
secretscan_verdict: secretscanVerdict
|
|
55178
55401
|
};
|
|
55179
55402
|
return JSON.stringify(result, null, 2);
|
|
55180
55403
|
}
|
|
@@ -55186,7 +55409,7 @@ init_checkpoint();
|
|
|
55186
55409
|
// src/tools/complexity-hotspots.ts
|
|
55187
55410
|
init_dist();
|
|
55188
55411
|
init_create_tool();
|
|
55189
|
-
import * as
|
|
55412
|
+
import * as fs28 from "fs";
|
|
55190
55413
|
import * as path40 from "path";
|
|
55191
55414
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
55192
55415
|
var DEFAULT_DAYS = 90;
|
|
@@ -55316,11 +55539,11 @@ function estimateComplexity(content) {
|
|
|
55316
55539
|
}
|
|
55317
55540
|
function getComplexityForFile(filePath) {
|
|
55318
55541
|
try {
|
|
55319
|
-
const stat2 =
|
|
55542
|
+
const stat2 = fs28.statSync(filePath);
|
|
55320
55543
|
if (stat2.size > MAX_FILE_SIZE_BYTES2) {
|
|
55321
55544
|
return null;
|
|
55322
55545
|
}
|
|
55323
|
-
const content =
|
|
55546
|
+
const content = fs28.readFileSync(filePath, "utf-8");
|
|
55324
55547
|
return estimateComplexity(content);
|
|
55325
55548
|
} catch {
|
|
55326
55549
|
return null;
|
|
@@ -55341,7 +55564,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
55341
55564
|
let analyzedFiles = 0;
|
|
55342
55565
|
for (const [file3, churnCount] of filteredChurn) {
|
|
55343
55566
|
let fullPath = file3;
|
|
55344
|
-
if (!
|
|
55567
|
+
if (!fs28.existsSync(fullPath)) {
|
|
55345
55568
|
fullPath = path40.join(cwd, file3);
|
|
55346
55569
|
}
|
|
55347
55570
|
const complexity = getComplexityForFile(fullPath);
|
|
@@ -55550,7 +55773,7 @@ var curator_analyze = createSwarmTool({
|
|
|
55550
55773
|
});
|
|
55551
55774
|
// src/tools/declare-scope.ts
|
|
55552
55775
|
init_tool();
|
|
55553
|
-
import * as
|
|
55776
|
+
import * as fs29 from "fs";
|
|
55554
55777
|
import * as path41 from "path";
|
|
55555
55778
|
init_create_tool();
|
|
55556
55779
|
function validateTaskIdFormat(taskId) {
|
|
@@ -55643,9 +55866,9 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
55643
55866
|
}
|
|
55644
55867
|
const resolvedDir = path41.resolve(normalizedDir);
|
|
55645
55868
|
try {
|
|
55646
|
-
const realPath =
|
|
55869
|
+
const realPath = fs29.realpathSync(resolvedDir);
|
|
55647
55870
|
const planPath2 = path41.join(realPath, ".swarm", "plan.json");
|
|
55648
|
-
if (!
|
|
55871
|
+
if (!fs29.existsSync(planPath2)) {
|
|
55649
55872
|
return {
|
|
55650
55873
|
success: false,
|
|
55651
55874
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -55669,7 +55892,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
55669
55892
|
}
|
|
55670
55893
|
const directory = normalizedDir || fallbackDir;
|
|
55671
55894
|
const planPath = path41.resolve(directory, ".swarm", "plan.json");
|
|
55672
|
-
if (!
|
|
55895
|
+
if (!fs29.existsSync(planPath)) {
|
|
55673
55896
|
return {
|
|
55674
55897
|
success: false,
|
|
55675
55898
|
message: "No plan found",
|
|
@@ -55678,7 +55901,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
55678
55901
|
}
|
|
55679
55902
|
let planContent;
|
|
55680
55903
|
try {
|
|
55681
|
-
planContent = JSON.parse(
|
|
55904
|
+
planContent = JSON.parse(fs29.readFileSync(planPath, "utf-8"));
|
|
55682
55905
|
} catch {
|
|
55683
55906
|
return {
|
|
55684
55907
|
success: false,
|
|
@@ -55900,6 +56123,391 @@ var diff = createSwarmTool({
|
|
|
55900
56123
|
}
|
|
55901
56124
|
}
|
|
55902
56125
|
});
|
|
56126
|
+
// src/tools/doc-scan.ts
|
|
56127
|
+
init_dist();
|
|
56128
|
+
init_schema();
|
|
56129
|
+
import * as crypto4 from "crypto";
|
|
56130
|
+
import * as fs30 from "fs";
|
|
56131
|
+
import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
56132
|
+
import * as path42 from "path";
|
|
56133
|
+
init_create_tool();
|
|
56134
|
+
var SKIP_DIRECTORIES2 = new Set([
|
|
56135
|
+
"node_modules",
|
|
56136
|
+
".git",
|
|
56137
|
+
".swarm",
|
|
56138
|
+
"dist",
|
|
56139
|
+
"build",
|
|
56140
|
+
".next",
|
|
56141
|
+
"vendor"
|
|
56142
|
+
]);
|
|
56143
|
+
var SKIP_PATTERNS = [/\.test\./, /\.spec\./, /\.d\.ts$/];
|
|
56144
|
+
var MAX_SUMMARY_LENGTH = 200;
|
|
56145
|
+
var MAX_INDEXED_FILES = 100;
|
|
56146
|
+
var READ_LINES_LIMIT = 30;
|
|
56147
|
+
var MIN_LESSON_LENGTH = 15;
|
|
56148
|
+
var MAX_CONSTRAINTS_PER_DOC = 5;
|
|
56149
|
+
var MAX_CONSTRAINT_LENGTH = 200;
|
|
56150
|
+
var RELEVANCE_THRESHOLD = 0.1;
|
|
56151
|
+
var DEDUP_THRESHOLD = 0.6;
|
|
56152
|
+
function normalizeSeparators(filePath) {
|
|
56153
|
+
return filePath.replace(/\\/g, "/");
|
|
56154
|
+
}
|
|
56155
|
+
function matchesDocPattern(filePath, patterns) {
|
|
56156
|
+
const normalizedPath = normalizeSeparators(filePath);
|
|
56157
|
+
const basename5 = path42.basename(filePath);
|
|
56158
|
+
for (const pattern of patterns) {
|
|
56159
|
+
if (!pattern.includes("/") && !pattern.includes("\\")) {
|
|
56160
|
+
if (basename5 === pattern) {
|
|
56161
|
+
return true;
|
|
56162
|
+
}
|
|
56163
|
+
continue;
|
|
56164
|
+
}
|
|
56165
|
+
if (pattern.startsWith("**/")) {
|
|
56166
|
+
const filenamePattern = pattern.slice(3);
|
|
56167
|
+
if (basename5 === filenamePattern) {
|
|
56168
|
+
return true;
|
|
56169
|
+
}
|
|
56170
|
+
continue;
|
|
56171
|
+
}
|
|
56172
|
+
const patternNormalized = normalizeSeparators(pattern);
|
|
56173
|
+
const dirPrefix = patternNormalized.replace(/\/\*\*.*$/, "").replace(/\/\*.*$/, "");
|
|
56174
|
+
if (normalizedPath.startsWith(dirPrefix + "/") || normalizedPath === dirPrefix) {
|
|
56175
|
+
return true;
|
|
56176
|
+
}
|
|
56177
|
+
}
|
|
56178
|
+
return false;
|
|
56179
|
+
}
|
|
56180
|
+
function extractTitleAndSummary(content, filename) {
|
|
56181
|
+
const lines = content.split(`
|
|
56182
|
+
`);
|
|
56183
|
+
let title = filename;
|
|
56184
|
+
let summary = "";
|
|
56185
|
+
let foundTitle = false;
|
|
56186
|
+
const potentialSummaryLines = [];
|
|
56187
|
+
for (let i2 = 0;i2 < lines.length && i2 < READ_LINES_LIMIT; i2++) {
|
|
56188
|
+
const line = lines[i2].trim();
|
|
56189
|
+
if (!foundTitle && line.startsWith("# ")) {
|
|
56190
|
+
title = line.slice(2).trim();
|
|
56191
|
+
foundTitle = true;
|
|
56192
|
+
continue;
|
|
56193
|
+
}
|
|
56194
|
+
if (line && !line.startsWith("#")) {
|
|
56195
|
+
potentialSummaryLines.push(line);
|
|
56196
|
+
}
|
|
56197
|
+
}
|
|
56198
|
+
for (const line of potentialSummaryLines) {
|
|
56199
|
+
summary += (summary ? " " : "") + line;
|
|
56200
|
+
if (summary.length >= MAX_SUMMARY_LENGTH) {
|
|
56201
|
+
break;
|
|
56202
|
+
}
|
|
56203
|
+
}
|
|
56204
|
+
if (summary.length > MAX_SUMMARY_LENGTH) {
|
|
56205
|
+
summary = summary.slice(0, MAX_SUMMARY_LENGTH - 3) + "...";
|
|
56206
|
+
}
|
|
56207
|
+
return { title, summary };
|
|
56208
|
+
}
|
|
56209
|
+
function stripMarkdown(text) {
|
|
56210
|
+
return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*\u2022]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
|
|
56211
|
+
}
|
|
56212
|
+
async function scanDocIndex(directory) {
|
|
56213
|
+
const manifestPath = path42.join(directory, ".swarm", "doc-manifest.json");
|
|
56214
|
+
const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
|
|
56215
|
+
const extraPatterns = [
|
|
56216
|
+
"ARCHITECTURE.md",
|
|
56217
|
+
"CLAUDE.md",
|
|
56218
|
+
"AGENTS.md",
|
|
56219
|
+
".github/*.md",
|
|
56220
|
+
"doc/**/*.md"
|
|
56221
|
+
];
|
|
56222
|
+
const allPatterns = [...defaultPatterns, ...extraPatterns];
|
|
56223
|
+
try {
|
|
56224
|
+
const manifestContent = await readFile6(manifestPath, "utf-8");
|
|
56225
|
+
const existingManifest = JSON.parse(manifestContent);
|
|
56226
|
+
if (existingManifest.schema_version === 1 && existingManifest.files) {
|
|
56227
|
+
let cacheValid = true;
|
|
56228
|
+
for (const file3 of existingManifest.files) {
|
|
56229
|
+
try {
|
|
56230
|
+
const fullPath = path42.join(directory, file3.path);
|
|
56231
|
+
const stat2 = fs30.statSync(fullPath);
|
|
56232
|
+
if (stat2.mtimeMs > new Date(existingManifest.scanned_at).getTime()) {
|
|
56233
|
+
cacheValid = false;
|
|
56234
|
+
break;
|
|
56235
|
+
}
|
|
56236
|
+
} catch {
|
|
56237
|
+
cacheValid = false;
|
|
56238
|
+
break;
|
|
56239
|
+
}
|
|
56240
|
+
}
|
|
56241
|
+
if (cacheValid) {
|
|
56242
|
+
return { manifest: existingManifest, cached: true };
|
|
56243
|
+
}
|
|
56244
|
+
}
|
|
56245
|
+
} catch {}
|
|
56246
|
+
const discoveredFiles = [];
|
|
56247
|
+
let rawEntries;
|
|
56248
|
+
try {
|
|
56249
|
+
rawEntries = fs30.readdirSync(directory, { recursive: true });
|
|
56250
|
+
} catch {
|
|
56251
|
+
const manifest2 = {
|
|
56252
|
+
schema_version: 1,
|
|
56253
|
+
scanned_at: new Date().toISOString(),
|
|
56254
|
+
files: []
|
|
56255
|
+
};
|
|
56256
|
+
return { manifest: manifest2, cached: false };
|
|
56257
|
+
}
|
|
56258
|
+
const entries = rawEntries.filter((e) => typeof e === "string");
|
|
56259
|
+
for (const entry of entries) {
|
|
56260
|
+
const fullPath = path42.join(directory, entry);
|
|
56261
|
+
let stat2;
|
|
56262
|
+
try {
|
|
56263
|
+
stat2 = fs30.statSync(fullPath);
|
|
56264
|
+
} catch {
|
|
56265
|
+
continue;
|
|
56266
|
+
}
|
|
56267
|
+
if (!stat2.isFile())
|
|
56268
|
+
continue;
|
|
56269
|
+
const pathParts = normalizeSeparators(entry).split("/");
|
|
56270
|
+
let skipThisFile = false;
|
|
56271
|
+
for (const part of pathParts) {
|
|
56272
|
+
if (SKIP_DIRECTORIES2.has(part)) {
|
|
56273
|
+
skipThisFile = true;
|
|
56274
|
+
break;
|
|
56275
|
+
}
|
|
56276
|
+
}
|
|
56277
|
+
if (skipThisFile)
|
|
56278
|
+
continue;
|
|
56279
|
+
for (const pattern of SKIP_PATTERNS) {
|
|
56280
|
+
if (pattern.test(entry)) {
|
|
56281
|
+
skipThisFile = true;
|
|
56282
|
+
break;
|
|
56283
|
+
}
|
|
56284
|
+
}
|
|
56285
|
+
if (skipThisFile)
|
|
56286
|
+
continue;
|
|
56287
|
+
if (!matchesDocPattern(entry, allPatterns)) {
|
|
56288
|
+
continue;
|
|
56289
|
+
}
|
|
56290
|
+
let content;
|
|
56291
|
+
try {
|
|
56292
|
+
content = fs30.readFileSync(fullPath, "utf-8");
|
|
56293
|
+
} catch {
|
|
56294
|
+
continue;
|
|
56295
|
+
}
|
|
56296
|
+
const { title, summary } = extractTitleAndSummary(content, path42.basename(entry));
|
|
56297
|
+
const lineCount = content.split(`
|
|
56298
|
+
`).length;
|
|
56299
|
+
discoveredFiles.push({
|
|
56300
|
+
path: entry,
|
|
56301
|
+
title,
|
|
56302
|
+
summary,
|
|
56303
|
+
lines: lineCount,
|
|
56304
|
+
mtime: stat2.mtimeMs
|
|
56305
|
+
});
|
|
56306
|
+
}
|
|
56307
|
+
discoveredFiles.sort((a, b) => a.path.toLowerCase().localeCompare(b.path.toLowerCase()));
|
|
56308
|
+
let truncated = false;
|
|
56309
|
+
if (discoveredFiles.length > MAX_INDEXED_FILES) {
|
|
56310
|
+
discoveredFiles.splice(MAX_INDEXED_FILES);
|
|
56311
|
+
truncated = true;
|
|
56312
|
+
}
|
|
56313
|
+
if (truncated && discoveredFiles.length > 0) {
|
|
56314
|
+
discoveredFiles[0].summary = `[Warning: ${MAX_INDEXED_FILES}+ docs found, listing first ${MAX_INDEXED_FILES}] ` + discoveredFiles[0].summary;
|
|
56315
|
+
}
|
|
56316
|
+
const manifest = {
|
|
56317
|
+
schema_version: 1,
|
|
56318
|
+
scanned_at: new Date().toISOString(),
|
|
56319
|
+
files: discoveredFiles
|
|
56320
|
+
};
|
|
56321
|
+
try {
|
|
56322
|
+
await mkdir5(path42.dirname(manifestPath), { recursive: true });
|
|
56323
|
+
await writeFile5(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
56324
|
+
} catch {}
|
|
56325
|
+
return { manifest, cached: false };
|
|
56326
|
+
}
|
|
56327
|
+
var CONSTRAINT_PATTERNS = [
|
|
56328
|
+
/\bMUST\b/,
|
|
56329
|
+
/\bMUST NOT\b/,
|
|
56330
|
+
/\bSHOULD\b/,
|
|
56331
|
+
/\bSHOULD NOT\b/,
|
|
56332
|
+
/\bDO NOT\b/,
|
|
56333
|
+
/\bALWAYS\b/,
|
|
56334
|
+
/\bNEVER\b/,
|
|
56335
|
+
/\bREQUIRED\b/
|
|
56336
|
+
];
|
|
56337
|
+
var ACTION_WORDS = /\b(must|should|don't|avoid|ensure|use|follow)\b/i;
|
|
56338
|
+
function isConstraintLine(line) {
|
|
56339
|
+
const upperLine = line.toUpperCase();
|
|
56340
|
+
for (const pattern of CONSTRAINT_PATTERNS) {
|
|
56341
|
+
if (pattern.test(upperLine)) {
|
|
56342
|
+
return true;
|
|
56343
|
+
}
|
|
56344
|
+
}
|
|
56345
|
+
if (/^\s*[-*\u2022]/.test(line) && ACTION_WORDS.test(line)) {
|
|
56346
|
+
return true;
|
|
56347
|
+
}
|
|
56348
|
+
return false;
|
|
56349
|
+
}
|
|
56350
|
+
function extractConstraintsFromContent(content) {
|
|
56351
|
+
const lines = content.split(`
|
|
56352
|
+
`);
|
|
56353
|
+
const constraints = [];
|
|
56354
|
+
for (const line of lines) {
|
|
56355
|
+
if (constraints.length >= MAX_CONSTRAINTS_PER_DOC) {
|
|
56356
|
+
break;
|
|
56357
|
+
}
|
|
56358
|
+
const trimmed = line.trim();
|
|
56359
|
+
if (!trimmed)
|
|
56360
|
+
continue;
|
|
56361
|
+
if (isConstraintLine(trimmed)) {
|
|
56362
|
+
const cleaned = stripMarkdown(trimmed);
|
|
56363
|
+
const len = cleaned.length;
|
|
56364
|
+
if (len >= MIN_LESSON_LENGTH && len <= MAX_CONSTRAINT_LENGTH) {
|
|
56365
|
+
constraints.push(cleaned);
|
|
56366
|
+
}
|
|
56367
|
+
}
|
|
56368
|
+
}
|
|
56369
|
+
return constraints;
|
|
56370
|
+
}
|
|
56371
|
+
async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
56372
|
+
const manifestPath = path42.join(directory, ".swarm", "doc-manifest.json");
|
|
56373
|
+
let manifest;
|
|
56374
|
+
try {
|
|
56375
|
+
const content = await readFile6(manifestPath, "utf-8");
|
|
56376
|
+
manifest = JSON.parse(content);
|
|
56377
|
+
} catch {
|
|
56378
|
+
const result = await scanDocIndex(directory);
|
|
56379
|
+
manifest = result.manifest;
|
|
56380
|
+
}
|
|
56381
|
+
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
56382
|
+
const existingEntries = await readKnowledge(knowledgePath);
|
|
56383
|
+
const taskContext = [...taskFiles, taskDescription].join(" ");
|
|
56384
|
+
const taskBigrams = wordBigrams(normalize2(taskContext));
|
|
56385
|
+
let extractedCount = 0;
|
|
56386
|
+
let skippedCount = 0;
|
|
56387
|
+
const details = [];
|
|
56388
|
+
for (const docFile of manifest.files) {
|
|
56389
|
+
const docContext = `${docFile.path} ${docFile.title} ${docFile.summary}`;
|
|
56390
|
+
const docBigrams = wordBigrams(normalize2(docContext));
|
|
56391
|
+
const score = jaccardBigram(taskBigrams, docBigrams);
|
|
56392
|
+
if (score <= RELEVANCE_THRESHOLD) {
|
|
56393
|
+
skippedCount++;
|
|
56394
|
+
continue;
|
|
56395
|
+
}
|
|
56396
|
+
let fullContent;
|
|
56397
|
+
try {
|
|
56398
|
+
fullContent = await readFile6(path42.join(directory, docFile.path), "utf-8");
|
|
56399
|
+
} catch {
|
|
56400
|
+
skippedCount++;
|
|
56401
|
+
continue;
|
|
56402
|
+
}
|
|
56403
|
+
const constraints = extractConstraintsFromContent(fullContent);
|
|
56404
|
+
if (constraints.length === 0) {
|
|
56405
|
+
skippedCount++;
|
|
56406
|
+
continue;
|
|
56407
|
+
}
|
|
56408
|
+
const docDetails = {
|
|
56409
|
+
path: docFile.path,
|
|
56410
|
+
score,
|
|
56411
|
+
constraints: []
|
|
56412
|
+
};
|
|
56413
|
+
for (const constraint of constraints) {
|
|
56414
|
+
const duplicate = findNearDuplicate(constraint, existingEntries, DEDUP_THRESHOLD);
|
|
56415
|
+
if (!duplicate) {
|
|
56416
|
+
const entry = {
|
|
56417
|
+
id: crypto4.randomUUID(),
|
|
56418
|
+
tier: "swarm",
|
|
56419
|
+
lesson: constraint,
|
|
56420
|
+
category: "architecture",
|
|
56421
|
+
tags: ["doc-scan", path42.basename(docFile.path)],
|
|
56422
|
+
scope: "global",
|
|
56423
|
+
confidence: 0.5,
|
|
56424
|
+
status: "candidate",
|
|
56425
|
+
confirmed_by: [],
|
|
56426
|
+
project_name: "",
|
|
56427
|
+
retrieval_outcomes: {
|
|
56428
|
+
applied_count: 0,
|
|
56429
|
+
succeeded_after_count: 0,
|
|
56430
|
+
failed_after_count: 0
|
|
56431
|
+
},
|
|
56432
|
+
schema_version: 1,
|
|
56433
|
+
created_at: new Date().toISOString(),
|
|
56434
|
+
updated_at: new Date().toISOString(),
|
|
56435
|
+
auto_generated: true,
|
|
56436
|
+
hive_eligible: false
|
|
56437
|
+
};
|
|
56438
|
+
await appendKnowledge(knowledgePath, entry);
|
|
56439
|
+
existingEntries.push(entry);
|
|
56440
|
+
extractedCount++;
|
|
56441
|
+
docDetails.constraints.push(constraint);
|
|
56442
|
+
}
|
|
56443
|
+
}
|
|
56444
|
+
if (docDetails.constraints.length > 0) {
|
|
56445
|
+
details.push(docDetails);
|
|
56446
|
+
} else {
|
|
56447
|
+
skippedCount++;
|
|
56448
|
+
}
|
|
56449
|
+
}
|
|
56450
|
+
return { extracted: extractedCount, skipped: skippedCount, details };
|
|
56451
|
+
}
|
|
56452
|
+
var doc_scan = createSwarmTool({
|
|
56453
|
+
description: "Scan project documentation files and build an index manifest. Caches results in .swarm/doc-manifest.json for fast subsequent scans.",
|
|
56454
|
+
args: {
|
|
56455
|
+
force: tool.schema.boolean().optional().describe("Force re-scan even if cache is valid")
|
|
56456
|
+
},
|
|
56457
|
+
execute: async (args2, directory) => {
|
|
56458
|
+
let force = false;
|
|
56459
|
+
try {
|
|
56460
|
+
if (args2 && typeof args2 === "object") {
|
|
56461
|
+
const obj = args2;
|
|
56462
|
+
if (obj.force === true)
|
|
56463
|
+
force = true;
|
|
56464
|
+
}
|
|
56465
|
+
} catch {}
|
|
56466
|
+
if (force) {
|
|
56467
|
+
const manifestPath = path42.join(directory, ".swarm", "doc-manifest.json");
|
|
56468
|
+
try {
|
|
56469
|
+
fs30.unlinkSync(manifestPath);
|
|
56470
|
+
} catch {}
|
|
56471
|
+
}
|
|
56472
|
+
const { manifest, cached: cached3 } = await scanDocIndex(directory);
|
|
56473
|
+
return JSON.stringify({
|
|
56474
|
+
success: true,
|
|
56475
|
+
files_count: manifest.files.length,
|
|
56476
|
+
cached: cached3,
|
|
56477
|
+
manifest
|
|
56478
|
+
}, null, 2);
|
|
56479
|
+
}
|
|
56480
|
+
});
|
|
56481
|
+
var doc_extract = createSwarmTool({
|
|
56482
|
+
description: "Extract actionable constraints from project documentation relevant to the current task. Scans docs via doc-manifest, scores relevance via Jaccard bigram similarity, and stores non-duplicate constraints in .swarm/knowledge.jsonl.",
|
|
56483
|
+
args: {
|
|
56484
|
+
task_files: tool.schema.array(tool.schema.string()).describe("List of file paths involved in the current task"),
|
|
56485
|
+
task_description: tool.schema.string().describe("Description of the current task")
|
|
56486
|
+
},
|
|
56487
|
+
execute: async (args2, directory) => {
|
|
56488
|
+
let taskFiles = [];
|
|
56489
|
+
let taskDescription = "";
|
|
56490
|
+
try {
|
|
56491
|
+
if (args2 && typeof args2 === "object") {
|
|
56492
|
+
const obj = args2;
|
|
56493
|
+
if (Array.isArray(obj.task_files)) {
|
|
56494
|
+
taskFiles = obj.task_files.filter((f) => typeof f === "string");
|
|
56495
|
+
}
|
|
56496
|
+
if (typeof obj.task_description === "string") {
|
|
56497
|
+
taskDescription = obj.task_description;
|
|
56498
|
+
}
|
|
56499
|
+
}
|
|
56500
|
+
} catch {}
|
|
56501
|
+
if (taskFiles.length === 0 && !taskDescription) {
|
|
56502
|
+
return JSON.stringify({
|
|
56503
|
+
success: false,
|
|
56504
|
+
error: "task_files or task_description is required"
|
|
56505
|
+
});
|
|
56506
|
+
}
|
|
56507
|
+
const result = await extractDocConstraints(directory, taskFiles, taskDescription);
|
|
56508
|
+
return JSON.stringify({ success: true, ...result }, null, 2);
|
|
56509
|
+
}
|
|
56510
|
+
});
|
|
55903
56511
|
// src/tools/domain-detector.ts
|
|
55904
56512
|
init_tool();
|
|
55905
56513
|
var DOMAIN_PATTERNS = {
|
|
@@ -56083,8 +56691,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
56083
56691
|
// src/tools/evidence-check.ts
|
|
56084
56692
|
init_dist();
|
|
56085
56693
|
init_create_tool();
|
|
56086
|
-
import * as
|
|
56087
|
-
import * as
|
|
56694
|
+
import * as fs31 from "fs";
|
|
56695
|
+
import * as path43 from "path";
|
|
56088
56696
|
var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
|
|
56089
56697
|
var MAX_EVIDENCE_FILES = 1000;
|
|
56090
56698
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
@@ -56114,9 +56722,9 @@ function validateRequiredTypes(input) {
|
|
|
56114
56722
|
return null;
|
|
56115
56723
|
}
|
|
56116
56724
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
56117
|
-
const normalizedCwd =
|
|
56118
|
-
const swarmPath =
|
|
56119
|
-
const normalizedPath =
|
|
56725
|
+
const normalizedCwd = path43.resolve(cwd);
|
|
56726
|
+
const swarmPath = path43.join(normalizedCwd, ".swarm");
|
|
56727
|
+
const normalizedPath = path43.resolve(filePath);
|
|
56120
56728
|
return normalizedPath.startsWith(swarmPath);
|
|
56121
56729
|
}
|
|
56122
56730
|
function parseCompletedTasks(planContent) {
|
|
@@ -56132,12 +56740,12 @@ function parseCompletedTasks(planContent) {
|
|
|
56132
56740
|
}
|
|
56133
56741
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
56134
56742
|
const evidence = [];
|
|
56135
|
-
if (!
|
|
56743
|
+
if (!fs31.existsSync(evidenceDir) || !fs31.statSync(evidenceDir).isDirectory()) {
|
|
56136
56744
|
return evidence;
|
|
56137
56745
|
}
|
|
56138
56746
|
let files;
|
|
56139
56747
|
try {
|
|
56140
|
-
files =
|
|
56748
|
+
files = fs31.readdirSync(evidenceDir);
|
|
56141
56749
|
} catch {
|
|
56142
56750
|
return evidence;
|
|
56143
56751
|
}
|
|
@@ -56146,14 +56754,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
56146
56754
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
56147
56755
|
continue;
|
|
56148
56756
|
}
|
|
56149
|
-
const filePath =
|
|
56757
|
+
const filePath = path43.join(evidenceDir, filename);
|
|
56150
56758
|
try {
|
|
56151
|
-
const resolvedPath =
|
|
56152
|
-
const evidenceDirResolved =
|
|
56759
|
+
const resolvedPath = path43.resolve(filePath);
|
|
56760
|
+
const evidenceDirResolved = path43.resolve(evidenceDir);
|
|
56153
56761
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
56154
56762
|
continue;
|
|
56155
56763
|
}
|
|
56156
|
-
const stat2 =
|
|
56764
|
+
const stat2 = fs31.lstatSync(filePath);
|
|
56157
56765
|
if (!stat2.isFile()) {
|
|
56158
56766
|
continue;
|
|
56159
56767
|
}
|
|
@@ -56162,7 +56770,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
56162
56770
|
}
|
|
56163
56771
|
let fileStat;
|
|
56164
56772
|
try {
|
|
56165
|
-
fileStat =
|
|
56773
|
+
fileStat = fs31.statSync(filePath);
|
|
56166
56774
|
if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
|
|
56167
56775
|
continue;
|
|
56168
56776
|
}
|
|
@@ -56171,7 +56779,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
56171
56779
|
}
|
|
56172
56780
|
let content;
|
|
56173
56781
|
try {
|
|
56174
|
-
content =
|
|
56782
|
+
content = fs31.readFileSync(filePath, "utf-8");
|
|
56175
56783
|
} catch {
|
|
56176
56784
|
continue;
|
|
56177
56785
|
}
|
|
@@ -56267,7 +56875,7 @@ var evidence_check = createSwarmTool({
|
|
|
56267
56875
|
return JSON.stringify(errorResult, null, 2);
|
|
56268
56876
|
}
|
|
56269
56877
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
56270
|
-
const planPath =
|
|
56878
|
+
const planPath = path43.join(cwd, PLAN_FILE);
|
|
56271
56879
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
56272
56880
|
const errorResult = {
|
|
56273
56881
|
error: "plan file path validation failed",
|
|
@@ -56281,7 +56889,7 @@ var evidence_check = createSwarmTool({
|
|
|
56281
56889
|
}
|
|
56282
56890
|
let planContent;
|
|
56283
56891
|
try {
|
|
56284
|
-
planContent =
|
|
56892
|
+
planContent = fs31.readFileSync(planPath, "utf-8");
|
|
56285
56893
|
} catch {
|
|
56286
56894
|
const result2 = {
|
|
56287
56895
|
message: "No completed tasks found in plan.",
|
|
@@ -56299,7 +56907,7 @@ var evidence_check = createSwarmTool({
|
|
|
56299
56907
|
};
|
|
56300
56908
|
return JSON.stringify(result2, null, 2);
|
|
56301
56909
|
}
|
|
56302
|
-
const evidenceDir =
|
|
56910
|
+
const evidenceDir = path43.join(cwd, EVIDENCE_DIR2);
|
|
56303
56911
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
56304
56912
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
56305
56913
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -56316,8 +56924,8 @@ var evidence_check = createSwarmTool({
|
|
|
56316
56924
|
// src/tools/file-extractor.ts
|
|
56317
56925
|
init_tool();
|
|
56318
56926
|
init_create_tool();
|
|
56319
|
-
import * as
|
|
56320
|
-
import * as
|
|
56927
|
+
import * as fs32 from "fs";
|
|
56928
|
+
import * as path44 from "path";
|
|
56321
56929
|
var EXT_MAP = {
|
|
56322
56930
|
python: ".py",
|
|
56323
56931
|
py: ".py",
|
|
@@ -56379,8 +56987,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
56379
56987
|
execute: async (args2, directory) => {
|
|
56380
56988
|
const { content, output_dir, prefix } = args2;
|
|
56381
56989
|
const targetDir = output_dir || directory;
|
|
56382
|
-
if (!
|
|
56383
|
-
|
|
56990
|
+
if (!fs32.existsSync(targetDir)) {
|
|
56991
|
+
fs32.mkdirSync(targetDir, { recursive: true });
|
|
56384
56992
|
}
|
|
56385
56993
|
if (!content) {
|
|
56386
56994
|
return "Error: content is required";
|
|
@@ -56398,16 +57006,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
56398
57006
|
if (prefix) {
|
|
56399
57007
|
filename = `${prefix}_${filename}`;
|
|
56400
57008
|
}
|
|
56401
|
-
let filepath =
|
|
56402
|
-
const base =
|
|
56403
|
-
const ext =
|
|
57009
|
+
let filepath = path44.join(targetDir, filename);
|
|
57010
|
+
const base = path44.basename(filepath, path44.extname(filepath));
|
|
57011
|
+
const ext = path44.extname(filepath);
|
|
56404
57012
|
let counter = 1;
|
|
56405
|
-
while (
|
|
56406
|
-
filepath =
|
|
57013
|
+
while (fs32.existsSync(filepath)) {
|
|
57014
|
+
filepath = path44.join(targetDir, `${base}_${counter}${ext}`);
|
|
56407
57015
|
counter++;
|
|
56408
57016
|
}
|
|
56409
57017
|
try {
|
|
56410
|
-
|
|
57018
|
+
fs32.writeFileSync(filepath, code.trim(), "utf-8");
|
|
56411
57019
|
savedFiles.push(filepath);
|
|
56412
57020
|
} catch (error93) {
|
|
56413
57021
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -56523,8 +57131,8 @@ var gitingest = createSwarmTool({
|
|
|
56523
57131
|
// src/tools/imports.ts
|
|
56524
57132
|
init_dist();
|
|
56525
57133
|
init_create_tool();
|
|
56526
|
-
import * as
|
|
56527
|
-
import * as
|
|
57134
|
+
import * as fs33 from "fs";
|
|
57135
|
+
import * as path45 from "path";
|
|
56528
57136
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
56529
57137
|
var MAX_SYMBOL_LENGTH = 256;
|
|
56530
57138
|
var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
|
|
@@ -56578,7 +57186,7 @@ function validateSymbolInput(symbol3) {
|
|
|
56578
57186
|
return null;
|
|
56579
57187
|
}
|
|
56580
57188
|
function isBinaryFile2(filePath, buffer) {
|
|
56581
|
-
const ext =
|
|
57189
|
+
const ext = path45.extname(filePath).toLowerCase();
|
|
56582
57190
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
56583
57191
|
return false;
|
|
56584
57192
|
}
|
|
@@ -56602,15 +57210,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
56602
57210
|
const imports = [];
|
|
56603
57211
|
let _resolvedTarget;
|
|
56604
57212
|
try {
|
|
56605
|
-
_resolvedTarget =
|
|
57213
|
+
_resolvedTarget = path45.resolve(targetFile);
|
|
56606
57214
|
} catch {
|
|
56607
57215
|
_resolvedTarget = targetFile;
|
|
56608
57216
|
}
|
|
56609
|
-
const targetBasename =
|
|
57217
|
+
const targetBasename = path45.basename(targetFile, path45.extname(targetFile));
|
|
56610
57218
|
const targetWithExt = targetFile;
|
|
56611
57219
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
56612
|
-
const normalizedTargetWithExt =
|
|
56613
|
-
const normalizedTargetWithoutExt =
|
|
57220
|
+
const normalizedTargetWithExt = path45.normalize(targetWithExt).replace(/\\/g, "/");
|
|
57221
|
+
const normalizedTargetWithoutExt = path45.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
56614
57222
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
56615
57223
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
56616
57224
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -56633,9 +57241,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
56633
57241
|
}
|
|
56634
57242
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
56635
57243
|
let isMatch = false;
|
|
56636
|
-
const _targetDir =
|
|
56637
|
-
const targetExt =
|
|
56638
|
-
const targetBasenameNoExt =
|
|
57244
|
+
const _targetDir = path45.dirname(targetFile);
|
|
57245
|
+
const targetExt = path45.extname(targetFile);
|
|
57246
|
+
const targetBasenameNoExt = path45.basename(targetFile, targetExt);
|
|
56639
57247
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
56640
57248
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
56641
57249
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -56675,7 +57283,7 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
56675
57283
|
}
|
|
56676
57284
|
return imports;
|
|
56677
57285
|
}
|
|
56678
|
-
var
|
|
57286
|
+
var SKIP_DIRECTORIES3 = new Set([
|
|
56679
57287
|
"node_modules",
|
|
56680
57288
|
".git",
|
|
56681
57289
|
"dist",
|
|
@@ -56692,7 +57300,7 @@ var SKIP_DIRECTORIES2 = new Set([
|
|
|
56692
57300
|
function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
56693
57301
|
let entries;
|
|
56694
57302
|
try {
|
|
56695
|
-
entries =
|
|
57303
|
+
entries = fs33.readdirSync(dir);
|
|
56696
57304
|
} catch (e) {
|
|
56697
57305
|
stats.fileErrors.push({
|
|
56698
57306
|
path: dir,
|
|
@@ -56702,14 +57310,14 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
56702
57310
|
}
|
|
56703
57311
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
56704
57312
|
for (const entry of entries) {
|
|
56705
|
-
if (
|
|
56706
|
-
stats.skippedDirs.push(
|
|
57313
|
+
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
57314
|
+
stats.skippedDirs.push(path45.join(dir, entry));
|
|
56707
57315
|
continue;
|
|
56708
57316
|
}
|
|
56709
|
-
const fullPath =
|
|
57317
|
+
const fullPath = path45.join(dir, entry);
|
|
56710
57318
|
let stat2;
|
|
56711
57319
|
try {
|
|
56712
|
-
stat2 =
|
|
57320
|
+
stat2 = fs33.statSync(fullPath);
|
|
56713
57321
|
} catch (e) {
|
|
56714
57322
|
stats.fileErrors.push({
|
|
56715
57323
|
path: fullPath,
|
|
@@ -56720,7 +57328,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
56720
57328
|
if (stat2.isDirectory()) {
|
|
56721
57329
|
findSourceFiles(fullPath, files, stats);
|
|
56722
57330
|
} else if (stat2.isFile()) {
|
|
56723
|
-
const ext =
|
|
57331
|
+
const ext = path45.extname(fullPath).toLowerCase();
|
|
56724
57332
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
56725
57333
|
files.push(fullPath);
|
|
56726
57334
|
}
|
|
@@ -56777,8 +57385,8 @@ var imports = createSwarmTool({
|
|
|
56777
57385
|
return JSON.stringify(errorResult, null, 2);
|
|
56778
57386
|
}
|
|
56779
57387
|
try {
|
|
56780
|
-
const targetFile =
|
|
56781
|
-
if (!
|
|
57388
|
+
const targetFile = path45.resolve(file3);
|
|
57389
|
+
if (!fs33.existsSync(targetFile)) {
|
|
56782
57390
|
const errorResult = {
|
|
56783
57391
|
error: `target file not found: ${file3}`,
|
|
56784
57392
|
target: file3,
|
|
@@ -56788,7 +57396,7 @@ var imports = createSwarmTool({
|
|
|
56788
57396
|
};
|
|
56789
57397
|
return JSON.stringify(errorResult, null, 2);
|
|
56790
57398
|
}
|
|
56791
|
-
const targetStat =
|
|
57399
|
+
const targetStat = fs33.statSync(targetFile);
|
|
56792
57400
|
if (!targetStat.isFile()) {
|
|
56793
57401
|
const errorResult = {
|
|
56794
57402
|
error: "target must be a file, not a directory",
|
|
@@ -56799,7 +57407,7 @@ var imports = createSwarmTool({
|
|
|
56799
57407
|
};
|
|
56800
57408
|
return JSON.stringify(errorResult, null, 2);
|
|
56801
57409
|
}
|
|
56802
|
-
const baseDir =
|
|
57410
|
+
const baseDir = path45.dirname(targetFile);
|
|
56803
57411
|
const scanStats = {
|
|
56804
57412
|
skippedDirs: [],
|
|
56805
57413
|
skippedFiles: 0,
|
|
@@ -56814,12 +57422,12 @@ var imports = createSwarmTool({
|
|
|
56814
57422
|
if (consumers.length >= MAX_CONSUMERS)
|
|
56815
57423
|
break;
|
|
56816
57424
|
try {
|
|
56817
|
-
const stat2 =
|
|
57425
|
+
const stat2 = fs33.statSync(filePath);
|
|
56818
57426
|
if (stat2.size > MAX_FILE_SIZE_BYTES4) {
|
|
56819
57427
|
skippedFileCount++;
|
|
56820
57428
|
continue;
|
|
56821
57429
|
}
|
|
56822
|
-
const buffer =
|
|
57430
|
+
const buffer = fs33.readFileSync(filePath);
|
|
56823
57431
|
if (isBinaryFile2(filePath, buffer)) {
|
|
56824
57432
|
skippedFileCount++;
|
|
56825
57433
|
continue;
|
|
@@ -56991,7 +57599,7 @@ var knowledgeAdd = createSwarmTool({
|
|
|
56991
57599
|
});
|
|
56992
57600
|
// src/tools/knowledge-query.ts
|
|
56993
57601
|
init_dist();
|
|
56994
|
-
import { existsSync as
|
|
57602
|
+
import { existsSync as existsSync29 } from "fs";
|
|
56995
57603
|
init_create_tool();
|
|
56996
57604
|
var DEFAULT_LIMIT = 10;
|
|
56997
57605
|
var MAX_LESSON_LENGTH = 200;
|
|
@@ -57061,14 +57669,14 @@ function validateLimit(limit) {
|
|
|
57061
57669
|
}
|
|
57062
57670
|
async function readSwarmKnowledge(directory) {
|
|
57063
57671
|
const swarmPath = resolveSwarmKnowledgePath(directory);
|
|
57064
|
-
if (!
|
|
57672
|
+
if (!existsSync29(swarmPath)) {
|
|
57065
57673
|
return [];
|
|
57066
57674
|
}
|
|
57067
57675
|
return readKnowledge(swarmPath);
|
|
57068
57676
|
}
|
|
57069
57677
|
async function readHiveKnowledge() {
|
|
57070
57678
|
const hivePath = resolveHiveKnowledgePath();
|
|
57071
|
-
if (!
|
|
57679
|
+
if (!existsSync29(hivePath)) {
|
|
57072
57680
|
return [];
|
|
57073
57681
|
}
|
|
57074
57682
|
return readKnowledge(hivePath);
|
|
@@ -57368,8 +57976,8 @@ init_dist();
|
|
|
57368
57976
|
init_config();
|
|
57369
57977
|
init_schema();
|
|
57370
57978
|
init_manager();
|
|
57371
|
-
import * as
|
|
57372
|
-
import * as
|
|
57979
|
+
import * as fs34 from "fs";
|
|
57980
|
+
import * as path46 from "path";
|
|
57373
57981
|
init_utils2();
|
|
57374
57982
|
init_create_tool();
|
|
57375
57983
|
function safeWarn(message, error93) {
|
|
@@ -57588,7 +58196,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
57588
58196
|
};
|
|
57589
58197
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
57590
58198
|
try {
|
|
57591
|
-
const projectName =
|
|
58199
|
+
const projectName = path46.basename(dir);
|
|
57592
58200
|
await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
57593
58201
|
} catch (error93) {
|
|
57594
58202
|
safeWarn("[phase_complete] Failed to curate lessons from retrospective:", error93);
|
|
@@ -57628,7 +58236,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
57628
58236
|
if (agentsMissing.length > 0) {
|
|
57629
58237
|
try {
|
|
57630
58238
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
57631
|
-
const planRaw =
|
|
58239
|
+
const planRaw = fs34.readFileSync(planPath, "utf-8");
|
|
57632
58240
|
const plan = JSON.parse(planRaw);
|
|
57633
58241
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
57634
58242
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -57659,7 +58267,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
57659
58267
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
57660
58268
|
try {
|
|
57661
58269
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
57662
|
-
const planRaw =
|
|
58270
|
+
const planRaw = fs34.readFileSync(planPath, "utf-8");
|
|
57663
58271
|
const plan = JSON.parse(planRaw);
|
|
57664
58272
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
57665
58273
|
if (targetPhase) {
|
|
@@ -57697,7 +58305,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
57697
58305
|
};
|
|
57698
58306
|
try {
|
|
57699
58307
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
57700
|
-
|
|
58308
|
+
fs34.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
57701
58309
|
`, "utf-8");
|
|
57702
58310
|
} catch (writeError) {
|
|
57703
58311
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -57716,12 +58324,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
57716
58324
|
}
|
|
57717
58325
|
try {
|
|
57718
58326
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
57719
|
-
const planJson =
|
|
58327
|
+
const planJson = fs34.readFileSync(planPath, "utf-8");
|
|
57720
58328
|
const plan = JSON.parse(planJson);
|
|
57721
58329
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
57722
58330
|
if (phaseObj) {
|
|
57723
58331
|
phaseObj.status = "completed";
|
|
57724
|
-
|
|
58332
|
+
fs34.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
|
|
57725
58333
|
`, "utf-8");
|
|
57726
58334
|
}
|
|
57727
58335
|
} catch (error93) {
|
|
@@ -57740,6 +58348,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
57740
58348
|
agentsMissing,
|
|
57741
58349
|
warnings
|
|
57742
58350
|
};
|
|
58351
|
+
await flushPendingSnapshot(dir);
|
|
57743
58352
|
return JSON.stringify({ ...result, timestamp: event.timestamp, duration_ms: durationMs }, null, 2);
|
|
57744
58353
|
}
|
|
57745
58354
|
var phase_complete = createSwarmTool({
|
|
@@ -57774,8 +58383,8 @@ init_dist();
|
|
|
57774
58383
|
init_discovery();
|
|
57775
58384
|
init_utils();
|
|
57776
58385
|
init_create_tool();
|
|
57777
|
-
import * as
|
|
57778
|
-
import * as
|
|
58386
|
+
import * as fs35 from "fs";
|
|
58387
|
+
import * as path47 from "path";
|
|
57779
58388
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
57780
58389
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
57781
58390
|
function isValidEcosystem(value) {
|
|
@@ -57793,28 +58402,28 @@ function validateArgs3(args2) {
|
|
|
57793
58402
|
function detectEcosystems(directory) {
|
|
57794
58403
|
const ecosystems = [];
|
|
57795
58404
|
const cwd = directory;
|
|
57796
|
-
if (
|
|
58405
|
+
if (fs35.existsSync(path47.join(cwd, "package.json"))) {
|
|
57797
58406
|
ecosystems.push("npm");
|
|
57798
58407
|
}
|
|
57799
|
-
if (
|
|
58408
|
+
if (fs35.existsSync(path47.join(cwd, "pyproject.toml")) || fs35.existsSync(path47.join(cwd, "requirements.txt"))) {
|
|
57800
58409
|
ecosystems.push("pip");
|
|
57801
58410
|
}
|
|
57802
|
-
if (
|
|
58411
|
+
if (fs35.existsSync(path47.join(cwd, "Cargo.toml"))) {
|
|
57803
58412
|
ecosystems.push("cargo");
|
|
57804
58413
|
}
|
|
57805
|
-
if (
|
|
58414
|
+
if (fs35.existsSync(path47.join(cwd, "go.mod"))) {
|
|
57806
58415
|
ecosystems.push("go");
|
|
57807
58416
|
}
|
|
57808
58417
|
try {
|
|
57809
|
-
const files =
|
|
58418
|
+
const files = fs35.readdirSync(cwd);
|
|
57810
58419
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
57811
58420
|
ecosystems.push("dotnet");
|
|
57812
58421
|
}
|
|
57813
58422
|
} catch {}
|
|
57814
|
-
if (
|
|
58423
|
+
if (fs35.existsSync(path47.join(cwd, "Gemfile")) || fs35.existsSync(path47.join(cwd, "Gemfile.lock"))) {
|
|
57815
58424
|
ecosystems.push("ruby");
|
|
57816
58425
|
}
|
|
57817
|
-
if (
|
|
58426
|
+
if (fs35.existsSync(path47.join(cwd, "pubspec.yaml"))) {
|
|
57818
58427
|
ecosystems.push("dart");
|
|
57819
58428
|
}
|
|
57820
58429
|
return ecosystems;
|
|
@@ -58876,8 +59485,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
58876
59485
|
]);
|
|
58877
59486
|
// src/tools/pre-check-batch.ts
|
|
58878
59487
|
init_dist();
|
|
58879
|
-
import * as
|
|
58880
|
-
import * as
|
|
59488
|
+
import * as fs38 from "fs";
|
|
59489
|
+
import * as path50 from "path";
|
|
58881
59490
|
|
|
58882
59491
|
// node_modules/yocto-queue/index.js
|
|
58883
59492
|
class Node2 {
|
|
@@ -59022,8 +59631,8 @@ function pLimit(concurrency) {
|
|
|
59022
59631
|
},
|
|
59023
59632
|
map: {
|
|
59024
59633
|
async value(iterable, function_) {
|
|
59025
|
-
const
|
|
59026
|
-
return Promise.all(
|
|
59634
|
+
const promises4 = Array.from(iterable, (value, index) => this(function_, value, index));
|
|
59635
|
+
return Promise.all(promises4);
|
|
59027
59636
|
}
|
|
59028
59637
|
}
|
|
59029
59638
|
});
|
|
@@ -59036,6 +59645,7 @@ function validateConcurrency(concurrency) {
|
|
|
59036
59645
|
}
|
|
59037
59646
|
|
|
59038
59647
|
// src/tools/pre-check-batch.ts
|
|
59648
|
+
init_manager();
|
|
59039
59649
|
init_utils();
|
|
59040
59650
|
init_create_tool();
|
|
59041
59651
|
init_lint();
|
|
@@ -59044,8 +59654,8 @@ init_lint();
|
|
|
59044
59654
|
init_manager();
|
|
59045
59655
|
|
|
59046
59656
|
// src/quality/metrics.ts
|
|
59047
|
-
import * as
|
|
59048
|
-
import * as
|
|
59657
|
+
import * as fs36 from "fs";
|
|
59658
|
+
import * as path48 from "path";
|
|
59049
59659
|
var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
|
|
59050
59660
|
var MIN_DUPLICATION_LINES = 10;
|
|
59051
59661
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -59083,11 +59693,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
59083
59693
|
}
|
|
59084
59694
|
function getComplexityForFile2(filePath) {
|
|
59085
59695
|
try {
|
|
59086
|
-
const stat2 =
|
|
59696
|
+
const stat2 = fs36.statSync(filePath);
|
|
59087
59697
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
59088
59698
|
return null;
|
|
59089
59699
|
}
|
|
59090
|
-
const content =
|
|
59700
|
+
const content = fs36.readFileSync(filePath, "utf-8");
|
|
59091
59701
|
return estimateCyclomaticComplexity(content);
|
|
59092
59702
|
} catch {
|
|
59093
59703
|
return null;
|
|
@@ -59097,8 +59707,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
59097
59707
|
let totalComplexity = 0;
|
|
59098
59708
|
const analyzedFiles = [];
|
|
59099
59709
|
for (const file3 of files) {
|
|
59100
|
-
const fullPath =
|
|
59101
|
-
if (!
|
|
59710
|
+
const fullPath = path48.isAbsolute(file3) ? file3 : path48.join(workingDir, file3);
|
|
59711
|
+
if (!fs36.existsSync(fullPath)) {
|
|
59102
59712
|
continue;
|
|
59103
59713
|
}
|
|
59104
59714
|
const complexity = getComplexityForFile2(fullPath);
|
|
@@ -59219,8 +59829,8 @@ function countGoExports(content) {
|
|
|
59219
59829
|
}
|
|
59220
59830
|
function getExportCountForFile(filePath) {
|
|
59221
59831
|
try {
|
|
59222
|
-
const content =
|
|
59223
|
-
const ext =
|
|
59832
|
+
const content = fs36.readFileSync(filePath, "utf-8");
|
|
59833
|
+
const ext = path48.extname(filePath).toLowerCase();
|
|
59224
59834
|
switch (ext) {
|
|
59225
59835
|
case ".ts":
|
|
59226
59836
|
case ".tsx":
|
|
@@ -59246,8 +59856,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
59246
59856
|
let totalExports = 0;
|
|
59247
59857
|
const analyzedFiles = [];
|
|
59248
59858
|
for (const file3 of files) {
|
|
59249
|
-
const fullPath =
|
|
59250
|
-
if (!
|
|
59859
|
+
const fullPath = path48.isAbsolute(file3) ? file3 : path48.join(workingDir, file3);
|
|
59860
|
+
if (!fs36.existsSync(fullPath)) {
|
|
59251
59861
|
continue;
|
|
59252
59862
|
}
|
|
59253
59863
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -59280,16 +59890,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
59280
59890
|
let duplicateLines = 0;
|
|
59281
59891
|
const analyzedFiles = [];
|
|
59282
59892
|
for (const file3 of files) {
|
|
59283
|
-
const fullPath =
|
|
59284
|
-
if (!
|
|
59893
|
+
const fullPath = path48.isAbsolute(file3) ? file3 : path48.join(workingDir, file3);
|
|
59894
|
+
if (!fs36.existsSync(fullPath)) {
|
|
59285
59895
|
continue;
|
|
59286
59896
|
}
|
|
59287
59897
|
try {
|
|
59288
|
-
const stat2 =
|
|
59898
|
+
const stat2 = fs36.statSync(fullPath);
|
|
59289
59899
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
59290
59900
|
continue;
|
|
59291
59901
|
}
|
|
59292
|
-
const content =
|
|
59902
|
+
const content = fs36.readFileSync(fullPath, "utf-8");
|
|
59293
59903
|
const lines = content.split(`
|
|
59294
59904
|
`).filter((line) => line.trim().length > 0);
|
|
59295
59905
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -59313,8 +59923,8 @@ function countCodeLines(content) {
|
|
|
59313
59923
|
return lines.length;
|
|
59314
59924
|
}
|
|
59315
59925
|
function isTestFile(filePath) {
|
|
59316
|
-
const
|
|
59317
|
-
const _ext =
|
|
59926
|
+
const basename9 = path48.basename(filePath);
|
|
59927
|
+
const _ext = path48.extname(filePath).toLowerCase();
|
|
59318
59928
|
const testPatterns = [
|
|
59319
59929
|
".test.",
|
|
59320
59930
|
".spec.",
|
|
@@ -59329,7 +59939,7 @@ function isTestFile(filePath) {
|
|
|
59329
59939
|
".spec.jsx"
|
|
59330
59940
|
];
|
|
59331
59941
|
for (const pattern of testPatterns) {
|
|
59332
|
-
if (
|
|
59942
|
+
if (basename9.includes(pattern)) {
|
|
59333
59943
|
return true;
|
|
59334
59944
|
}
|
|
59335
59945
|
}
|
|
@@ -59395,8 +60005,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
59395
60005
|
}
|
|
59396
60006
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
59397
60007
|
}
|
|
59398
|
-
function matchesGlobSegment(
|
|
59399
|
-
const normalizedPath =
|
|
60008
|
+
function matchesGlobSegment(path49, glob) {
|
|
60009
|
+
const normalizedPath = path49.replace(/\\/g, "/");
|
|
59400
60010
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
59401
60011
|
if (normalizedPath.includes("//")) {
|
|
59402
60012
|
return false;
|
|
@@ -59427,8 +60037,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
59427
60037
|
function hasGlobstar(glob) {
|
|
59428
60038
|
return glob.includes("**");
|
|
59429
60039
|
}
|
|
59430
|
-
function globMatches(
|
|
59431
|
-
const normalizedPath =
|
|
60040
|
+
function globMatches(path49, glob) {
|
|
60041
|
+
const normalizedPath = path49.replace(/\\/g, "/");
|
|
59432
60042
|
if (!glob || glob === "") {
|
|
59433
60043
|
if (normalizedPath.includes("//")) {
|
|
59434
60044
|
return false;
|
|
@@ -59464,31 +60074,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
59464
60074
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
59465
60075
|
let testLines = 0;
|
|
59466
60076
|
let codeLines = 0;
|
|
59467
|
-
const srcDir =
|
|
59468
|
-
if (
|
|
60077
|
+
const srcDir = path48.join(workingDir, "src");
|
|
60078
|
+
if (fs36.existsSync(srcDir)) {
|
|
59469
60079
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
59470
60080
|
codeLines += lines;
|
|
59471
60081
|
});
|
|
59472
60082
|
}
|
|
59473
60083
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
59474
60084
|
for (const dir of possibleSrcDirs) {
|
|
59475
|
-
const dirPath =
|
|
59476
|
-
if (
|
|
60085
|
+
const dirPath = path48.join(workingDir, dir);
|
|
60086
|
+
if (fs36.existsSync(dirPath)) {
|
|
59477
60087
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
59478
60088
|
codeLines += lines;
|
|
59479
60089
|
});
|
|
59480
60090
|
}
|
|
59481
60091
|
}
|
|
59482
|
-
const testsDir =
|
|
59483
|
-
if (
|
|
60092
|
+
const testsDir = path48.join(workingDir, "tests");
|
|
60093
|
+
if (fs36.existsSync(testsDir)) {
|
|
59484
60094
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
59485
60095
|
testLines += lines;
|
|
59486
60096
|
});
|
|
59487
60097
|
}
|
|
59488
60098
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
59489
60099
|
for (const dir of possibleTestDirs) {
|
|
59490
|
-
const dirPath =
|
|
59491
|
-
if (
|
|
60100
|
+
const dirPath = path48.join(workingDir, dir);
|
|
60101
|
+
if (fs36.existsSync(dirPath) && dirPath !== testsDir) {
|
|
59492
60102
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
59493
60103
|
testLines += lines;
|
|
59494
60104
|
});
|
|
@@ -59500,9 +60110,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
59500
60110
|
}
|
|
59501
60111
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
59502
60112
|
try {
|
|
59503
|
-
const entries =
|
|
60113
|
+
const entries = fs36.readdirSync(dirPath, { withFileTypes: true });
|
|
59504
60114
|
for (const entry of entries) {
|
|
59505
|
-
const fullPath =
|
|
60115
|
+
const fullPath = path48.join(dirPath, entry.name);
|
|
59506
60116
|
if (entry.isDirectory()) {
|
|
59507
60117
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
59508
60118
|
continue;
|
|
@@ -59510,7 +60120,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
59510
60120
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
59511
60121
|
} else if (entry.isFile()) {
|
|
59512
60122
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
59513
|
-
const ext =
|
|
60123
|
+
const ext = path48.extname(entry.name).toLowerCase();
|
|
59514
60124
|
const validExts = [
|
|
59515
60125
|
".ts",
|
|
59516
60126
|
".tsx",
|
|
@@ -59546,7 +60156,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
59546
60156
|
continue;
|
|
59547
60157
|
}
|
|
59548
60158
|
try {
|
|
59549
|
-
const content =
|
|
60159
|
+
const content = fs36.readFileSync(fullPath, "utf-8");
|
|
59550
60160
|
const lines = countCodeLines(content);
|
|
59551
60161
|
callback(lines);
|
|
59552
60162
|
} catch {}
|
|
@@ -59760,8 +60370,8 @@ async function qualityBudget(input, directory) {
|
|
|
59760
60370
|
init_dist();
|
|
59761
60371
|
init_manager();
|
|
59762
60372
|
init_detector();
|
|
59763
|
-
import * as
|
|
59764
|
-
import * as
|
|
60373
|
+
import * as fs37 from "fs";
|
|
60374
|
+
import * as path49 from "path";
|
|
59765
60375
|
import { extname as extname9 } from "path";
|
|
59766
60376
|
|
|
59767
60377
|
// src/sast/rules/c.ts
|
|
@@ -60628,17 +61238,17 @@ var SEVERITY_ORDER = {
|
|
|
60628
61238
|
};
|
|
60629
61239
|
function shouldSkipFile(filePath) {
|
|
60630
61240
|
try {
|
|
60631
|
-
const stats =
|
|
61241
|
+
const stats = fs37.statSync(filePath);
|
|
60632
61242
|
if (stats.size > MAX_FILE_SIZE_BYTES6) {
|
|
60633
61243
|
return { skip: true, reason: "file too large" };
|
|
60634
61244
|
}
|
|
60635
61245
|
if (stats.size === 0) {
|
|
60636
61246
|
return { skip: true, reason: "empty file" };
|
|
60637
61247
|
}
|
|
60638
|
-
const fd =
|
|
61248
|
+
const fd = fs37.openSync(filePath, "r");
|
|
60639
61249
|
const buffer = Buffer.alloc(8192);
|
|
60640
|
-
const bytesRead =
|
|
60641
|
-
|
|
61250
|
+
const bytesRead = fs37.readSync(fd, buffer, 0, 8192, 0);
|
|
61251
|
+
fs37.closeSync(fd);
|
|
60642
61252
|
if (bytesRead > 0) {
|
|
60643
61253
|
let nullCount = 0;
|
|
60644
61254
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -60677,7 +61287,7 @@ function countBySeverity(findings) {
|
|
|
60677
61287
|
}
|
|
60678
61288
|
function scanFileWithTierA(filePath, language) {
|
|
60679
61289
|
try {
|
|
60680
|
-
const content =
|
|
61290
|
+
const content = fs37.readFileSync(filePath, "utf-8");
|
|
60681
61291
|
const findings = executeRulesSync(filePath, content, language);
|
|
60682
61292
|
return findings.map((f) => ({
|
|
60683
61293
|
rule_id: f.rule_id,
|
|
@@ -60724,8 +61334,8 @@ async function sastScan(input, directory, config3) {
|
|
|
60724
61334
|
_filesSkipped++;
|
|
60725
61335
|
continue;
|
|
60726
61336
|
}
|
|
60727
|
-
const resolvedPath =
|
|
60728
|
-
if (!
|
|
61337
|
+
const resolvedPath = path49.isAbsolute(filePath) ? filePath : path49.resolve(directory, filePath);
|
|
61338
|
+
if (!fs37.existsSync(resolvedPath)) {
|
|
60729
61339
|
_filesSkipped++;
|
|
60730
61340
|
continue;
|
|
60731
61341
|
}
|
|
@@ -60923,18 +61533,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
60923
61533
|
let resolved;
|
|
60924
61534
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
60925
61535
|
if (isWinAbs) {
|
|
60926
|
-
resolved =
|
|
60927
|
-
} else if (
|
|
60928
|
-
resolved =
|
|
61536
|
+
resolved = path50.win32.resolve(inputPath);
|
|
61537
|
+
} else if (path50.isAbsolute(inputPath)) {
|
|
61538
|
+
resolved = path50.resolve(inputPath);
|
|
60929
61539
|
} else {
|
|
60930
|
-
resolved =
|
|
61540
|
+
resolved = path50.resolve(baseDir, inputPath);
|
|
60931
61541
|
}
|
|
60932
|
-
const workspaceResolved =
|
|
61542
|
+
const workspaceResolved = path50.resolve(workspaceDir);
|
|
60933
61543
|
let relative6;
|
|
60934
61544
|
if (isWinAbs) {
|
|
60935
|
-
relative6 =
|
|
61545
|
+
relative6 = path50.win32.relative(workspaceResolved, resolved);
|
|
60936
61546
|
} else {
|
|
60937
|
-
relative6 =
|
|
61547
|
+
relative6 = path50.relative(workspaceResolved, resolved);
|
|
60938
61548
|
}
|
|
60939
61549
|
if (relative6.startsWith("..")) {
|
|
60940
61550
|
return "path traversal detected";
|
|
@@ -60995,13 +61605,13 @@ async function runLintWrapped(files, directory, _config) {
|
|
|
60995
61605
|
}
|
|
60996
61606
|
async function runLintOnFiles(linter, files, workspaceDir) {
|
|
60997
61607
|
const isWindows = process.platform === "win32";
|
|
60998
|
-
const binDir =
|
|
61608
|
+
const binDir = path50.join(workspaceDir, "node_modules", ".bin");
|
|
60999
61609
|
const validatedFiles = [];
|
|
61000
61610
|
for (const file3 of files) {
|
|
61001
61611
|
if (typeof file3 !== "string") {
|
|
61002
61612
|
continue;
|
|
61003
61613
|
}
|
|
61004
|
-
const resolvedPath =
|
|
61614
|
+
const resolvedPath = path50.resolve(file3);
|
|
61005
61615
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
61006
61616
|
if (validationError) {
|
|
61007
61617
|
continue;
|
|
@@ -61019,10 +61629,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
61019
61629
|
}
|
|
61020
61630
|
let command;
|
|
61021
61631
|
if (linter === "biome") {
|
|
61022
|
-
const biomeBin = isWindows ?
|
|
61632
|
+
const biomeBin = isWindows ? path50.join(binDir, "biome.EXE") : path50.join(binDir, "biome");
|
|
61023
61633
|
command = [biomeBin, "check", ...validatedFiles];
|
|
61024
61634
|
} else {
|
|
61025
|
-
const eslintBin = isWindows ?
|
|
61635
|
+
const eslintBin = isWindows ? path50.join(binDir, "eslint.cmd") : path50.join(binDir, "eslint");
|
|
61026
61636
|
command = [eslintBin, ...validatedFiles];
|
|
61027
61637
|
}
|
|
61028
61638
|
try {
|
|
@@ -61159,7 +61769,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
61159
61769
|
skippedFiles++;
|
|
61160
61770
|
continue;
|
|
61161
61771
|
}
|
|
61162
|
-
const resolvedPath =
|
|
61772
|
+
const resolvedPath = path50.resolve(file3);
|
|
61163
61773
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
61164
61774
|
if (validationError) {
|
|
61165
61775
|
skippedFiles++;
|
|
@@ -61177,14 +61787,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
61177
61787
|
};
|
|
61178
61788
|
}
|
|
61179
61789
|
for (const file3 of validatedFiles) {
|
|
61180
|
-
const ext =
|
|
61790
|
+
const ext = path50.extname(file3).toLowerCase();
|
|
61181
61791
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
61182
61792
|
skippedFiles++;
|
|
61183
61793
|
continue;
|
|
61184
61794
|
}
|
|
61185
61795
|
let stat2;
|
|
61186
61796
|
try {
|
|
61187
|
-
stat2 =
|
|
61797
|
+
stat2 = fs38.statSync(file3);
|
|
61188
61798
|
} catch {
|
|
61189
61799
|
skippedFiles++;
|
|
61190
61800
|
continue;
|
|
@@ -61195,7 +61805,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
61195
61805
|
}
|
|
61196
61806
|
let content;
|
|
61197
61807
|
try {
|
|
61198
|
-
const buffer =
|
|
61808
|
+
const buffer = fs38.readFileSync(file3);
|
|
61199
61809
|
if (buffer.includes(0)) {
|
|
61200
61810
|
skippedFiles++;
|
|
61201
61811
|
continue;
|
|
@@ -61336,7 +61946,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
61336
61946
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
61337
61947
|
continue;
|
|
61338
61948
|
}
|
|
61339
|
-
changedFiles.push(
|
|
61949
|
+
changedFiles.push(path50.resolve(directory, file3));
|
|
61340
61950
|
}
|
|
61341
61951
|
if (changedFiles.length === 0) {
|
|
61342
61952
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -61383,6 +61993,26 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
61383
61993
|
gatesPassed = false;
|
|
61384
61994
|
warn(`pre_check_batch: Secretscan error - GATE FAILED: ${secretscanResult.error}`);
|
|
61385
61995
|
}
|
|
61996
|
+
if (secretscanResult.ran && secretscanResult.result) {
|
|
61997
|
+
try {
|
|
61998
|
+
const scanResult = secretscanResult.result;
|
|
61999
|
+
const secretscanEvidence = {
|
|
62000
|
+
task_id: "secretscan",
|
|
62001
|
+
type: "secretscan",
|
|
62002
|
+
timestamp: new Date().toISOString(),
|
|
62003
|
+
agent: "pre_check_batch",
|
|
62004
|
+
verdict: scanResult.count > 0 ? "fail" : "pass",
|
|
62005
|
+
summary: `Secretscan: ${scanResult.count} finding(s), ${scanResult.files_scanned ?? 0} files scanned, ${scanResult.skipped_files ?? 0} skipped`,
|
|
62006
|
+
findings_count: scanResult.count,
|
|
62007
|
+
scan_directory: scanResult.scan_dir,
|
|
62008
|
+
files_scanned: scanResult.files_scanned,
|
|
62009
|
+
skipped_files: scanResult.skipped_files
|
|
62010
|
+
};
|
|
62011
|
+
await saveEvidence(directory, "secretscan", secretscanEvidence);
|
|
62012
|
+
} catch (e) {
|
|
62013
|
+
warn(`Failed to persist secretscan evidence: ${e instanceof Error ? e.message : String(e)}`);
|
|
62014
|
+
}
|
|
62015
|
+
}
|
|
61386
62016
|
if (sastScanResult.ran && sastScanResult.result) {
|
|
61387
62017
|
if (sastScanResult.result.verdict === "fail") {
|
|
61388
62018
|
gatesPassed = false;
|
|
@@ -61487,7 +62117,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
61487
62117
|
};
|
|
61488
62118
|
return JSON.stringify(errorResult, null, 2);
|
|
61489
62119
|
}
|
|
61490
|
-
const resolvedDirectory =
|
|
62120
|
+
const resolvedDirectory = path50.resolve(typedArgs.directory);
|
|
61491
62121
|
const workspaceAnchor = resolvedDirectory;
|
|
61492
62122
|
const dirError = validateDirectory3(resolvedDirectory, workspaceAnchor);
|
|
61493
62123
|
if (dirError) {
|
|
@@ -61595,8 +62225,8 @@ ${paginatedContent}`;
|
|
|
61595
62225
|
init_tool();
|
|
61596
62226
|
init_manager2();
|
|
61597
62227
|
init_create_tool();
|
|
61598
|
-
import * as
|
|
61599
|
-
import * as
|
|
62228
|
+
import * as fs39 from "fs";
|
|
62229
|
+
import * as path51 from "path";
|
|
61600
62230
|
function detectPlaceholderContent(args2) {
|
|
61601
62231
|
const issues = [];
|
|
61602
62232
|
const placeholderPattern = /^\[\w[\w\s]*\]$/;
|
|
@@ -61700,19 +62330,19 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
61700
62330
|
try {
|
|
61701
62331
|
await savePlan(dir, plan);
|
|
61702
62332
|
try {
|
|
61703
|
-
const markerPath =
|
|
62333
|
+
const markerPath = path51.join(dir, ".swarm", ".plan-write-marker");
|
|
61704
62334
|
const marker = JSON.stringify({
|
|
61705
62335
|
source: "save_plan",
|
|
61706
62336
|
timestamp: new Date().toISOString(),
|
|
61707
62337
|
phases_count: plan.phases.length,
|
|
61708
62338
|
tasks_count: tasksCount
|
|
61709
62339
|
});
|
|
61710
|
-
await
|
|
62340
|
+
await fs39.promises.writeFile(markerPath, marker, "utf8");
|
|
61711
62341
|
} catch {}
|
|
61712
62342
|
return {
|
|
61713
62343
|
success: true,
|
|
61714
62344
|
message: "Plan saved successfully",
|
|
61715
|
-
plan_path:
|
|
62345
|
+
plan_path: path51.join(dir, ".swarm", "plan.json"),
|
|
61716
62346
|
phases_count: plan.phases.length,
|
|
61717
62347
|
tasks_count: tasksCount
|
|
61718
62348
|
};
|
|
@@ -61750,8 +62380,8 @@ var save_plan = createSwarmTool({
|
|
|
61750
62380
|
// src/tools/sbom-generate.ts
|
|
61751
62381
|
init_dist();
|
|
61752
62382
|
init_manager();
|
|
61753
|
-
import * as
|
|
61754
|
-
import * as
|
|
62383
|
+
import * as fs40 from "fs";
|
|
62384
|
+
import * as path52 from "path";
|
|
61755
62385
|
|
|
61756
62386
|
// src/sbom/detectors/index.ts
|
|
61757
62387
|
init_utils();
|
|
@@ -62597,9 +63227,9 @@ function findManifestFiles(rootDir) {
|
|
|
62597
63227
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
62598
63228
|
function searchDir(dir) {
|
|
62599
63229
|
try {
|
|
62600
|
-
const entries =
|
|
63230
|
+
const entries = fs40.readdirSync(dir, { withFileTypes: true });
|
|
62601
63231
|
for (const entry of entries) {
|
|
62602
|
-
const fullPath =
|
|
63232
|
+
const fullPath = path52.join(dir, entry.name);
|
|
62603
63233
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
62604
63234
|
continue;
|
|
62605
63235
|
}
|
|
@@ -62608,7 +63238,7 @@ function findManifestFiles(rootDir) {
|
|
|
62608
63238
|
} else if (entry.isFile()) {
|
|
62609
63239
|
for (const pattern of patterns) {
|
|
62610
63240
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
62611
|
-
manifestFiles.push(
|
|
63241
|
+
manifestFiles.push(path52.relative(rootDir, fullPath));
|
|
62612
63242
|
break;
|
|
62613
63243
|
}
|
|
62614
63244
|
}
|
|
@@ -62624,13 +63254,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
62624
63254
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
62625
63255
|
for (const dir of directories) {
|
|
62626
63256
|
try {
|
|
62627
|
-
const entries =
|
|
63257
|
+
const entries = fs40.readdirSync(dir, { withFileTypes: true });
|
|
62628
63258
|
for (const entry of entries) {
|
|
62629
|
-
const fullPath =
|
|
63259
|
+
const fullPath = path52.join(dir, entry.name);
|
|
62630
63260
|
if (entry.isFile()) {
|
|
62631
63261
|
for (const pattern of patterns) {
|
|
62632
63262
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
62633
|
-
found.push(
|
|
63263
|
+
found.push(path52.relative(workingDir, fullPath));
|
|
62634
63264
|
break;
|
|
62635
63265
|
}
|
|
62636
63266
|
}
|
|
@@ -62643,11 +63273,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
62643
63273
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
62644
63274
|
const dirs = new Set;
|
|
62645
63275
|
for (const file3 of changedFiles) {
|
|
62646
|
-
let currentDir =
|
|
63276
|
+
let currentDir = path52.dirname(file3);
|
|
62647
63277
|
while (true) {
|
|
62648
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
62649
|
-
dirs.add(
|
|
62650
|
-
const parent =
|
|
63278
|
+
if (currentDir && currentDir !== "." && currentDir !== path52.sep) {
|
|
63279
|
+
dirs.add(path52.join(workingDir, currentDir));
|
|
63280
|
+
const parent = path52.dirname(currentDir);
|
|
62651
63281
|
if (parent === currentDir)
|
|
62652
63282
|
break;
|
|
62653
63283
|
currentDir = parent;
|
|
@@ -62661,7 +63291,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
62661
63291
|
}
|
|
62662
63292
|
function ensureOutputDir(outputDir) {
|
|
62663
63293
|
try {
|
|
62664
|
-
|
|
63294
|
+
fs40.mkdirSync(outputDir, { recursive: true });
|
|
62665
63295
|
} catch (error93) {
|
|
62666
63296
|
if (!error93 || error93.code !== "EEXIST") {
|
|
62667
63297
|
throw error93;
|
|
@@ -62731,7 +63361,7 @@ var sbom_generate = createSwarmTool({
|
|
|
62731
63361
|
const changedFiles = obj.changed_files;
|
|
62732
63362
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
62733
63363
|
const workingDir = directory;
|
|
62734
|
-
const outputDir =
|
|
63364
|
+
const outputDir = path52.isAbsolute(relativeOutputDir) ? relativeOutputDir : path52.join(workingDir, relativeOutputDir);
|
|
62735
63365
|
let manifestFiles = [];
|
|
62736
63366
|
if (scope === "all") {
|
|
62737
63367
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -62754,11 +63384,11 @@ var sbom_generate = createSwarmTool({
|
|
|
62754
63384
|
const processedFiles = [];
|
|
62755
63385
|
for (const manifestFile of manifestFiles) {
|
|
62756
63386
|
try {
|
|
62757
|
-
const fullPath =
|
|
62758
|
-
if (!
|
|
63387
|
+
const fullPath = path52.isAbsolute(manifestFile) ? manifestFile : path52.join(workingDir, manifestFile);
|
|
63388
|
+
if (!fs40.existsSync(fullPath)) {
|
|
62759
63389
|
continue;
|
|
62760
63390
|
}
|
|
62761
|
-
const content =
|
|
63391
|
+
const content = fs40.readFileSync(fullPath, "utf-8");
|
|
62762
63392
|
const components = detectComponents(manifestFile, content);
|
|
62763
63393
|
processedFiles.push(manifestFile);
|
|
62764
63394
|
if (components.length > 0) {
|
|
@@ -62771,8 +63401,8 @@ var sbom_generate = createSwarmTool({
|
|
|
62771
63401
|
const bom = generateCycloneDX(allComponents);
|
|
62772
63402
|
const bomJson = serializeCycloneDX(bom);
|
|
62773
63403
|
const filename = generateSbomFilename();
|
|
62774
|
-
const outputPath =
|
|
62775
|
-
|
|
63404
|
+
const outputPath = path52.join(outputDir, filename);
|
|
63405
|
+
fs40.writeFileSync(outputPath, bomJson, "utf-8");
|
|
62776
63406
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
62777
63407
|
try {
|
|
62778
63408
|
const timestamp = new Date().toISOString();
|
|
@@ -62814,8 +63444,8 @@ var sbom_generate = createSwarmTool({
|
|
|
62814
63444
|
// src/tools/schema-drift.ts
|
|
62815
63445
|
init_dist();
|
|
62816
63446
|
init_create_tool();
|
|
62817
|
-
import * as
|
|
62818
|
-
import * as
|
|
63447
|
+
import * as fs41 from "fs";
|
|
63448
|
+
import * as path53 from "path";
|
|
62819
63449
|
var SPEC_CANDIDATES = [
|
|
62820
63450
|
"openapi.json",
|
|
62821
63451
|
"openapi.yaml",
|
|
@@ -62847,28 +63477,28 @@ function normalizePath2(p) {
|
|
|
62847
63477
|
}
|
|
62848
63478
|
function discoverSpecFile(cwd, specFileArg) {
|
|
62849
63479
|
if (specFileArg) {
|
|
62850
|
-
const resolvedPath =
|
|
62851
|
-
const normalizedCwd = cwd.endsWith(
|
|
63480
|
+
const resolvedPath = path53.resolve(cwd, specFileArg);
|
|
63481
|
+
const normalizedCwd = cwd.endsWith(path53.sep) ? cwd : cwd + path53.sep;
|
|
62852
63482
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
62853
63483
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
62854
63484
|
}
|
|
62855
|
-
const ext =
|
|
63485
|
+
const ext = path53.extname(resolvedPath).toLowerCase();
|
|
62856
63486
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
62857
63487
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
62858
63488
|
}
|
|
62859
|
-
const stats =
|
|
63489
|
+
const stats = fs41.statSync(resolvedPath);
|
|
62860
63490
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
62861
63491
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
62862
63492
|
}
|
|
62863
|
-
if (!
|
|
63493
|
+
if (!fs41.existsSync(resolvedPath)) {
|
|
62864
63494
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
62865
63495
|
}
|
|
62866
63496
|
return resolvedPath;
|
|
62867
63497
|
}
|
|
62868
63498
|
for (const candidate of SPEC_CANDIDATES) {
|
|
62869
|
-
const candidatePath =
|
|
62870
|
-
if (
|
|
62871
|
-
const stats =
|
|
63499
|
+
const candidatePath = path53.resolve(cwd, candidate);
|
|
63500
|
+
if (fs41.existsSync(candidatePath)) {
|
|
63501
|
+
const stats = fs41.statSync(candidatePath);
|
|
62872
63502
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
62873
63503
|
return candidatePath;
|
|
62874
63504
|
}
|
|
@@ -62877,8 +63507,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
62877
63507
|
return null;
|
|
62878
63508
|
}
|
|
62879
63509
|
function parseSpec(specFile) {
|
|
62880
|
-
const content =
|
|
62881
|
-
const ext =
|
|
63510
|
+
const content = fs41.readFileSync(specFile, "utf-8");
|
|
63511
|
+
const ext = path53.extname(specFile).toLowerCase();
|
|
62882
63512
|
if (ext === ".json") {
|
|
62883
63513
|
return parseJsonSpec(content);
|
|
62884
63514
|
}
|
|
@@ -62949,12 +63579,12 @@ function extractRoutes(cwd) {
|
|
|
62949
63579
|
function walkDir(dir) {
|
|
62950
63580
|
let entries;
|
|
62951
63581
|
try {
|
|
62952
|
-
entries =
|
|
63582
|
+
entries = fs41.readdirSync(dir, { withFileTypes: true });
|
|
62953
63583
|
} catch {
|
|
62954
63584
|
return;
|
|
62955
63585
|
}
|
|
62956
63586
|
for (const entry of entries) {
|
|
62957
|
-
const fullPath =
|
|
63587
|
+
const fullPath = path53.join(dir, entry.name);
|
|
62958
63588
|
if (entry.isSymbolicLink()) {
|
|
62959
63589
|
continue;
|
|
62960
63590
|
}
|
|
@@ -62964,7 +63594,7 @@ function extractRoutes(cwd) {
|
|
|
62964
63594
|
}
|
|
62965
63595
|
walkDir(fullPath);
|
|
62966
63596
|
} else if (entry.isFile()) {
|
|
62967
|
-
const ext =
|
|
63597
|
+
const ext = path53.extname(entry.name).toLowerCase();
|
|
62968
63598
|
const baseName = entry.name.toLowerCase();
|
|
62969
63599
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
62970
63600
|
continue;
|
|
@@ -62982,7 +63612,7 @@ function extractRoutes(cwd) {
|
|
|
62982
63612
|
}
|
|
62983
63613
|
function extractRoutesFromFile(filePath) {
|
|
62984
63614
|
const routes = [];
|
|
62985
|
-
const content =
|
|
63615
|
+
const content = fs41.readFileSync(filePath, "utf-8");
|
|
62986
63616
|
const lines = content.split(/\r?\n/);
|
|
62987
63617
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
62988
63618
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -63133,8 +63763,8 @@ init_secretscan();
|
|
|
63133
63763
|
// src/tools/symbols.ts
|
|
63134
63764
|
init_tool();
|
|
63135
63765
|
init_create_tool();
|
|
63136
|
-
import * as
|
|
63137
|
-
import * as
|
|
63766
|
+
import * as fs42 from "fs";
|
|
63767
|
+
import * as path54 from "path";
|
|
63138
63768
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
63139
63769
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
63140
63770
|
function containsControlCharacters(str) {
|
|
@@ -63163,11 +63793,11 @@ function containsWindowsAttacks(str) {
|
|
|
63163
63793
|
}
|
|
63164
63794
|
function isPathInWorkspace(filePath, workspace) {
|
|
63165
63795
|
try {
|
|
63166
|
-
const resolvedPath =
|
|
63167
|
-
const realWorkspace =
|
|
63168
|
-
const realResolvedPath =
|
|
63169
|
-
const relativePath =
|
|
63170
|
-
if (relativePath.startsWith("..") ||
|
|
63796
|
+
const resolvedPath = path54.resolve(workspace, filePath);
|
|
63797
|
+
const realWorkspace = fs42.realpathSync(workspace);
|
|
63798
|
+
const realResolvedPath = fs42.realpathSync(resolvedPath);
|
|
63799
|
+
const relativePath = path54.relative(realWorkspace, realResolvedPath);
|
|
63800
|
+
if (relativePath.startsWith("..") || path54.isAbsolute(relativePath)) {
|
|
63171
63801
|
return false;
|
|
63172
63802
|
}
|
|
63173
63803
|
return true;
|
|
@@ -63179,17 +63809,17 @@ function validatePathForRead(filePath, workspace) {
|
|
|
63179
63809
|
return isPathInWorkspace(filePath, workspace);
|
|
63180
63810
|
}
|
|
63181
63811
|
function extractTSSymbols(filePath, cwd) {
|
|
63182
|
-
const fullPath =
|
|
63812
|
+
const fullPath = path54.join(cwd, filePath);
|
|
63183
63813
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
63184
63814
|
return [];
|
|
63185
63815
|
}
|
|
63186
63816
|
let content;
|
|
63187
63817
|
try {
|
|
63188
|
-
const stats =
|
|
63818
|
+
const stats = fs42.statSync(fullPath);
|
|
63189
63819
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
63190
63820
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
63191
63821
|
}
|
|
63192
|
-
content =
|
|
63822
|
+
content = fs42.readFileSync(fullPath, "utf-8");
|
|
63193
63823
|
} catch {
|
|
63194
63824
|
return [];
|
|
63195
63825
|
}
|
|
@@ -63331,17 +63961,17 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
63331
63961
|
});
|
|
63332
63962
|
}
|
|
63333
63963
|
function extractPythonSymbols(filePath, cwd) {
|
|
63334
|
-
const fullPath =
|
|
63964
|
+
const fullPath = path54.join(cwd, filePath);
|
|
63335
63965
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
63336
63966
|
return [];
|
|
63337
63967
|
}
|
|
63338
63968
|
let content;
|
|
63339
63969
|
try {
|
|
63340
|
-
const stats =
|
|
63970
|
+
const stats = fs42.statSync(fullPath);
|
|
63341
63971
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
63342
63972
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
63343
63973
|
}
|
|
63344
|
-
content =
|
|
63974
|
+
content = fs42.readFileSync(fullPath, "utf-8");
|
|
63345
63975
|
} catch {
|
|
63346
63976
|
return [];
|
|
63347
63977
|
}
|
|
@@ -63414,7 +64044,7 @@ var symbols = createSwarmTool({
|
|
|
63414
64044
|
}, null, 2);
|
|
63415
64045
|
}
|
|
63416
64046
|
const cwd = directory;
|
|
63417
|
-
const ext =
|
|
64047
|
+
const ext = path54.extname(file3);
|
|
63418
64048
|
if (containsControlCharacters(file3)) {
|
|
63419
64049
|
return JSON.stringify({
|
|
63420
64050
|
file: file3,
|
|
@@ -63485,8 +64115,8 @@ init_test_runner();
|
|
|
63485
64115
|
init_dist();
|
|
63486
64116
|
init_utils();
|
|
63487
64117
|
init_create_tool();
|
|
63488
|
-
import * as
|
|
63489
|
-
import * as
|
|
64118
|
+
import * as fs43 from "fs";
|
|
64119
|
+
import * as path55 from "path";
|
|
63490
64120
|
var MAX_TEXT_LENGTH = 200;
|
|
63491
64121
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
63492
64122
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
@@ -63508,7 +64138,7 @@ var SUPPORTED_EXTENSIONS2 = new Set([
|
|
|
63508
64138
|
".swift",
|
|
63509
64139
|
".kt"
|
|
63510
64140
|
]);
|
|
63511
|
-
var
|
|
64141
|
+
var SKIP_DIRECTORIES4 = new Set([
|
|
63512
64142
|
"node_modules",
|
|
63513
64143
|
"dist",
|
|
63514
64144
|
"build",
|
|
@@ -63557,9 +64187,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
63557
64187
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
63558
64188
|
}
|
|
63559
64189
|
try {
|
|
63560
|
-
const resolvedPath =
|
|
63561
|
-
const normalizedCwd =
|
|
63562
|
-
const normalizedResolved =
|
|
64190
|
+
const resolvedPath = path55.resolve(paths);
|
|
64191
|
+
const normalizedCwd = path55.resolve(cwd);
|
|
64192
|
+
const normalizedResolved = path55.resolve(resolvedPath);
|
|
63563
64193
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
63564
64194
|
return {
|
|
63565
64195
|
error: "paths must be within the current working directory",
|
|
@@ -63575,25 +64205,25 @@ function validatePathsInput(paths, cwd) {
|
|
|
63575
64205
|
}
|
|
63576
64206
|
}
|
|
63577
64207
|
function isSupportedExtension(filePath) {
|
|
63578
|
-
const ext =
|
|
64208
|
+
const ext = path55.extname(filePath).toLowerCase();
|
|
63579
64209
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
63580
64210
|
}
|
|
63581
64211
|
function findSourceFiles2(dir, files = []) {
|
|
63582
64212
|
let entries;
|
|
63583
64213
|
try {
|
|
63584
|
-
entries =
|
|
64214
|
+
entries = fs43.readdirSync(dir);
|
|
63585
64215
|
} catch {
|
|
63586
64216
|
return files;
|
|
63587
64217
|
}
|
|
63588
64218
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
63589
64219
|
for (const entry of entries) {
|
|
63590
|
-
if (
|
|
64220
|
+
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
63591
64221
|
continue;
|
|
63592
64222
|
}
|
|
63593
|
-
const fullPath =
|
|
64223
|
+
const fullPath = path55.join(dir, entry);
|
|
63594
64224
|
let stat2;
|
|
63595
64225
|
try {
|
|
63596
|
-
stat2 =
|
|
64226
|
+
stat2 = fs43.statSync(fullPath);
|
|
63597
64227
|
} catch {
|
|
63598
64228
|
continue;
|
|
63599
64229
|
}
|
|
@@ -63686,7 +64316,7 @@ var todo_extract = createSwarmTool({
|
|
|
63686
64316
|
return JSON.stringify(errorResult, null, 2);
|
|
63687
64317
|
}
|
|
63688
64318
|
const scanPath = resolvedPath;
|
|
63689
|
-
if (!
|
|
64319
|
+
if (!fs43.existsSync(scanPath)) {
|
|
63690
64320
|
const errorResult = {
|
|
63691
64321
|
error: `path not found: ${pathsInput}`,
|
|
63692
64322
|
total: 0,
|
|
@@ -63696,13 +64326,13 @@ var todo_extract = createSwarmTool({
|
|
|
63696
64326
|
return JSON.stringify(errorResult, null, 2);
|
|
63697
64327
|
}
|
|
63698
64328
|
const filesToScan = [];
|
|
63699
|
-
const stat2 =
|
|
64329
|
+
const stat2 = fs43.statSync(scanPath);
|
|
63700
64330
|
if (stat2.isFile()) {
|
|
63701
64331
|
if (isSupportedExtension(scanPath)) {
|
|
63702
64332
|
filesToScan.push(scanPath);
|
|
63703
64333
|
} else {
|
|
63704
64334
|
const errorResult = {
|
|
63705
|
-
error: `unsupported file extension: ${
|
|
64335
|
+
error: `unsupported file extension: ${path55.extname(scanPath)}`,
|
|
63706
64336
|
total: 0,
|
|
63707
64337
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
63708
64338
|
entries: []
|
|
@@ -63715,11 +64345,11 @@ var todo_extract = createSwarmTool({
|
|
|
63715
64345
|
const allEntries = [];
|
|
63716
64346
|
for (const filePath of filesToScan) {
|
|
63717
64347
|
try {
|
|
63718
|
-
const fileStat =
|
|
64348
|
+
const fileStat = fs43.statSync(filePath);
|
|
63719
64349
|
if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
|
|
63720
64350
|
continue;
|
|
63721
64351
|
}
|
|
63722
|
-
const content =
|
|
64352
|
+
const content = fs43.readFileSync(filePath, "utf-8");
|
|
63723
64353
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
63724
64354
|
allEntries.push(...entries);
|
|
63725
64355
|
} catch {}
|
|
@@ -63747,18 +64377,18 @@ var todo_extract = createSwarmTool({
|
|
|
63747
64377
|
// src/tools/update-task-status.ts
|
|
63748
64378
|
init_tool();
|
|
63749
64379
|
init_schema();
|
|
63750
|
-
import * as
|
|
63751
|
-
import * as
|
|
64380
|
+
import * as fs45 from "fs";
|
|
64381
|
+
import * as path57 from "path";
|
|
63752
64382
|
|
|
63753
64383
|
// src/hooks/diff-scope.ts
|
|
63754
|
-
import * as
|
|
63755
|
-
import * as
|
|
64384
|
+
import * as fs44 from "fs";
|
|
64385
|
+
import * as path56 from "path";
|
|
63756
64386
|
function getDeclaredScope(taskId, directory) {
|
|
63757
64387
|
try {
|
|
63758
|
-
const planPath =
|
|
63759
|
-
if (!
|
|
64388
|
+
const planPath = path56.join(directory, ".swarm", "plan.json");
|
|
64389
|
+
if (!fs44.existsSync(planPath))
|
|
63760
64390
|
return null;
|
|
63761
|
-
const raw =
|
|
64391
|
+
const raw = fs44.readFileSync(planPath, "utf-8");
|
|
63762
64392
|
const plan = JSON.parse(raw);
|
|
63763
64393
|
for (const phase of plan.phases ?? []) {
|
|
63764
64394
|
for (const task of phase.tasks ?? []) {
|
|
@@ -63870,7 +64500,7 @@ var TIER_3_PATTERNS = [
|
|
|
63870
64500
|
];
|
|
63871
64501
|
function matchesTier3Pattern(files) {
|
|
63872
64502
|
for (const file3 of files) {
|
|
63873
|
-
const fileName =
|
|
64503
|
+
const fileName = path57.basename(file3);
|
|
63874
64504
|
for (const pattern of TIER_3_PATTERNS) {
|
|
63875
64505
|
if (pattern.test(fileName)) {
|
|
63876
64506
|
return true;
|
|
@@ -63892,8 +64522,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
63892
64522
|
if (hasActiveTurboMode2()) {
|
|
63893
64523
|
const resolvedDir2 = workingDirectory;
|
|
63894
64524
|
try {
|
|
63895
|
-
const planPath =
|
|
63896
|
-
const planRaw =
|
|
64525
|
+
const planPath = path57.join(resolvedDir2, ".swarm", "plan.json");
|
|
64526
|
+
const planRaw = fs45.readFileSync(planPath, "utf-8");
|
|
63897
64527
|
const plan = JSON.parse(planRaw);
|
|
63898
64528
|
for (const planPhase of plan.phases ?? []) {
|
|
63899
64529
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -63912,8 +64542,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
63912
64542
|
}
|
|
63913
64543
|
const resolvedDir = workingDirectory;
|
|
63914
64544
|
try {
|
|
63915
|
-
const evidencePath =
|
|
63916
|
-
const raw =
|
|
64545
|
+
const evidencePath = path57.join(resolvedDir, ".swarm", "evidence", `${taskId}.json`);
|
|
64546
|
+
const raw = fs45.readFileSync(evidencePath, "utf-8");
|
|
63917
64547
|
const evidence = JSON.parse(raw);
|
|
63918
64548
|
if (evidence?.required_gates && Array.isArray(evidence.required_gates) && evidence?.gates) {
|
|
63919
64549
|
const allGatesMet = evidence.required_gates.every((gate) => evidence.gates[gate] != null);
|
|
@@ -63953,8 +64583,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
63953
64583
|
}
|
|
63954
64584
|
try {
|
|
63955
64585
|
const resolvedDir2 = workingDirectory;
|
|
63956
|
-
const planPath =
|
|
63957
|
-
const planRaw =
|
|
64586
|
+
const planPath = path57.join(resolvedDir2, ".swarm", "plan.json");
|
|
64587
|
+
const planRaw = fs45.readFileSync(planPath, "utf-8");
|
|
63958
64588
|
const plan = JSON.parse(planRaw);
|
|
63959
64589
|
for (const planPhase of plan.phases ?? []) {
|
|
63960
64590
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -64135,8 +64765,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
64135
64765
|
};
|
|
64136
64766
|
}
|
|
64137
64767
|
}
|
|
64138
|
-
normalizedDir =
|
|
64139
|
-
const pathParts = normalizedDir.split(
|
|
64768
|
+
normalizedDir = path57.normalize(args2.working_directory);
|
|
64769
|
+
const pathParts = normalizedDir.split(path57.sep);
|
|
64140
64770
|
if (pathParts.includes("..")) {
|
|
64141
64771
|
return {
|
|
64142
64772
|
success: false,
|
|
@@ -64146,11 +64776,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
64146
64776
|
]
|
|
64147
64777
|
};
|
|
64148
64778
|
}
|
|
64149
|
-
const resolvedDir =
|
|
64779
|
+
const resolvedDir = path57.resolve(normalizedDir);
|
|
64150
64780
|
try {
|
|
64151
|
-
const realPath =
|
|
64152
|
-
const planPath =
|
|
64153
|
-
if (!
|
|
64781
|
+
const realPath = fs45.realpathSync(resolvedDir);
|
|
64782
|
+
const planPath = path57.join(realPath, ".swarm", "plan.json");
|
|
64783
|
+
if (!fs45.existsSync(planPath)) {
|
|
64154
64784
|
return {
|
|
64155
64785
|
success: false,
|
|
64156
64786
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -64372,7 +65002,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
64372
65002
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
64373
65003
|
preflightTriggerManager = new PTM(automationConfig);
|
|
64374
65004
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
64375
|
-
const swarmDir =
|
|
65005
|
+
const swarmDir = path58.resolve(ctx.directory, ".swarm");
|
|
64376
65006
|
statusArtifact = new ASA(swarmDir);
|
|
64377
65007
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
64378
65008
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -64664,6 +65294,9 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
64664
65294
|
await safeHook(activityHooks.toolBefore)(input, output);
|
|
64665
65295
|
},
|
|
64666
65296
|
"tool.execute.after": async (input, output) => {
|
|
65297
|
+
if (process.env.DEBUG_SWARM) {
|
|
65298
|
+
console.debug("[hook-chain] toolAfter start sessionID=%s agent=%s tool=%s", input.sessionID, input.agent, input.tool?.name);
|
|
65299
|
+
}
|
|
64667
65300
|
await activityHooks.toolAfter(input, output);
|
|
64668
65301
|
await guardrailsHooks.toolAfter(input, output);
|
|
64669
65302
|
await safeHook(delegationLedgerHook.toolAfter)(input, output);
|
|
@@ -64678,12 +65311,15 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
64678
65311
|
await safeHook(darkMatterDetectorHook)(input, output);
|
|
64679
65312
|
await snapshotWriterHook(input, output);
|
|
64680
65313
|
await toolSummarizerHook?.(input, output);
|
|
64681
|
-
|
|
64682
|
-
|
|
64683
|
-
|
|
64684
|
-
|
|
64685
|
-
|
|
64686
|
-
|
|
65314
|
+
const execMode = config3.execution_mode ?? "balanced";
|
|
65315
|
+
if (execMode === "strict") {
|
|
65316
|
+
if (slopDetectorHook)
|
|
65317
|
+
await slopDetectorHook.toolAfter(input, output);
|
|
65318
|
+
if (incrementalVerifyHook)
|
|
65319
|
+
await incrementalVerifyHook.toolAfter(input, output);
|
|
65320
|
+
if (compactionServiceHook)
|
|
65321
|
+
await compactionServiceHook.toolAfter(input, output);
|
|
65322
|
+
}
|
|
64687
65323
|
const toolOutputConfig = config3.tool_output;
|
|
64688
65324
|
if (toolOutputConfig && toolOutputConfig.truncation_enabled !== false && typeof output.output === "string") {
|
|
64689
65325
|
const defaultTruncatableTools = new Set([
|
|
@@ -64717,8 +65353,14 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
64717
65353
|
session.lastAgentEventTime = Date.now();
|
|
64718
65354
|
}
|
|
64719
65355
|
}
|
|
65356
|
+
deleteStoredInputArgs(input.callID);
|
|
64720
65357
|
},
|
|
64721
|
-
"chat.message": safeHook(
|
|
65358
|
+
"chat.message": safeHook(async (input, output) => {
|
|
65359
|
+
if (process.env.DEBUG_SWARM) {
|
|
65360
|
+
console.debug("[session] chat.message sessionID=%s agent=%s", input.sessionID, input.agent);
|
|
65361
|
+
}
|
|
65362
|
+
await delegationHandler(input, output);
|
|
65363
|
+
}),
|
|
64722
65364
|
automation: automationManager
|
|
64723
65365
|
};
|
|
64724
65366
|
};
|