opencode-swarm 6.20.3 → 6.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -1
- package/dist/cli/index.js +4 -2
- package/dist/config/constants.d.ts +14 -0
- package/dist/index.js +785 -342
- package/dist/state.d.ts +42 -0
- package/dist/tools/declare-scope.d.ts +49 -0
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/tool-names.d.ts +1 -1
- package/dist/tools/update-task-status.d.ts +15 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -36285,8 +36285,8 @@ var init_tree_sitter = __esm(() => {
|
|
|
36285
36285
|
bytes = Promise.resolve(input);
|
|
36286
36286
|
} else {
|
|
36287
36287
|
if (globalThis.process?.versions.node) {
|
|
36288
|
-
const
|
|
36289
|
-
bytes =
|
|
36288
|
+
const fs25 = await import("fs/promises");
|
|
36289
|
+
bytes = fs25.readFile(input);
|
|
36290
36290
|
} else {
|
|
36291
36291
|
bytes = fetch(input).then((response) => response.arrayBuffer().then((buffer) => {
|
|
36292
36292
|
if (response.ok) {
|
|
@@ -36318,8 +36318,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
36318
36318
|
var moduleRtn;
|
|
36319
36319
|
var Module = moduleArg;
|
|
36320
36320
|
var readyPromiseResolve, readyPromiseReject;
|
|
36321
|
-
var readyPromise = new Promise((
|
|
36322
|
-
readyPromiseResolve =
|
|
36321
|
+
var readyPromise = new Promise((resolve13, reject) => {
|
|
36322
|
+
readyPromiseResolve = resolve13;
|
|
36323
36323
|
readyPromiseReject = reject;
|
|
36324
36324
|
});
|
|
36325
36325
|
var ENVIRONMENT_IS_WEB = typeof window == "object";
|
|
@@ -36341,11 +36341,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
36341
36341
|
throw toThrow;
|
|
36342
36342
|
}, "quit_");
|
|
36343
36343
|
var scriptDirectory = "";
|
|
36344
|
-
function locateFile(
|
|
36344
|
+
function locateFile(path36) {
|
|
36345
36345
|
if (Module["locateFile"]) {
|
|
36346
|
-
return Module["locateFile"](
|
|
36346
|
+
return Module["locateFile"](path36, scriptDirectory);
|
|
36347
36347
|
}
|
|
36348
|
-
return scriptDirectory +
|
|
36348
|
+
return scriptDirectory + path36;
|
|
36349
36349
|
}
|
|
36350
36350
|
__name(locateFile, "locateFile");
|
|
36351
36351
|
var readAsync, readBinary;
|
|
@@ -36399,13 +36399,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
36399
36399
|
}
|
|
36400
36400
|
readAsync = /* @__PURE__ */ __name(async (url3) => {
|
|
36401
36401
|
if (isFileURI(url3)) {
|
|
36402
|
-
return new Promise((
|
|
36402
|
+
return new Promise((resolve13, reject) => {
|
|
36403
36403
|
var xhr = new XMLHttpRequest;
|
|
36404
36404
|
xhr.open("GET", url3, true);
|
|
36405
36405
|
xhr.responseType = "arraybuffer";
|
|
36406
36406
|
xhr.onload = () => {
|
|
36407
36407
|
if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
|
|
36408
|
-
|
|
36408
|
+
resolve13(xhr.response);
|
|
36409
36409
|
return;
|
|
36410
36410
|
}
|
|
36411
36411
|
reject(xhr.status);
|
|
@@ -36625,10 +36625,10 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
36625
36625
|
__name(receiveInstantiationResult, "receiveInstantiationResult");
|
|
36626
36626
|
var info2 = getWasmImports();
|
|
36627
36627
|
if (Module["instantiateWasm"]) {
|
|
36628
|
-
return new Promise((
|
|
36628
|
+
return new Promise((resolve13, reject) => {
|
|
36629
36629
|
Module["instantiateWasm"](info2, (mod, inst) => {
|
|
36630
36630
|
receiveInstance(mod, inst);
|
|
36631
|
-
|
|
36631
|
+
resolve13(mod.exports);
|
|
36632
36632
|
});
|
|
36633
36633
|
});
|
|
36634
36634
|
}
|
|
@@ -38093,7 +38093,7 @@ var init_runtime = __esm(() => {
|
|
|
38093
38093
|
});
|
|
38094
38094
|
|
|
38095
38095
|
// src/index.ts
|
|
38096
|
-
import * as
|
|
38096
|
+
import * as path45 from "path";
|
|
38097
38097
|
|
|
38098
38098
|
// src/tools/tool-names.ts
|
|
38099
38099
|
var TOOL_NAMES = [
|
|
@@ -38123,7 +38123,8 @@ var TOOL_NAMES = [
|
|
|
38123
38123
|
"phase_complete",
|
|
38124
38124
|
"save_plan",
|
|
38125
38125
|
"update_task_status",
|
|
38126
|
-
"write_retro"
|
|
38126
|
+
"write_retro",
|
|
38127
|
+
"declare_scope"
|
|
38127
38128
|
];
|
|
38128
38129
|
var TOOL_NAME_SET = new Set(TOOL_NAMES);
|
|
38129
38130
|
|
|
@@ -38163,7 +38164,8 @@ var AGENT_TOOL_MAP = {
|
|
|
38163
38164
|
"test_runner",
|
|
38164
38165
|
"todo_extract",
|
|
38165
38166
|
"update_task_status",
|
|
38166
|
-
"write_retro"
|
|
38167
|
+
"write_retro",
|
|
38168
|
+
"declare_scope"
|
|
38167
38169
|
],
|
|
38168
38170
|
explorer: [
|
|
38169
38171
|
"complexity_hotspots",
|
|
@@ -38276,6 +38278,13 @@ var DEFAULT_SCORING_CONFIG = {
|
|
|
38276
38278
|
json: 0.35
|
|
38277
38279
|
}
|
|
38278
38280
|
};
|
|
38281
|
+
var LOW_CAPABILITY_MODELS = ["mini", "nano", "small", "free"];
|
|
38282
|
+
function isLowCapabilityModel(modelId) {
|
|
38283
|
+
if (!modelId)
|
|
38284
|
+
return false;
|
|
38285
|
+
const lower = modelId.toLowerCase();
|
|
38286
|
+
return LOW_CAPABILITY_MODELS.some((substr) => lower.includes(substr));
|
|
38287
|
+
}
|
|
38279
38288
|
|
|
38280
38289
|
// src/config/index.ts
|
|
38281
38290
|
init_evidence_schema();
|
|
@@ -38942,6 +38951,7 @@ CODER'S TOOLS: write, edit, patch, apply_patch, create_file, insert, replace \u2
|
|
|
38942
38951
|
If a tool modifies a file, it is a CODER tool. Delegate.
|
|
38943
38952
|
2. ONE agent per message. Send, STOP, wait for response.
|
|
38944
38953
|
3. ONE task per {{AGENT_PREFIX}}coder call. Never batch.
|
|
38954
|
+
<!-- BEHAVIORAL_GUIDANCE_START -->
|
|
38945
38955
|
BATCHING DETECTION \u2014 you are batching if your coder delegation contains ANY of:
|
|
38946
38956
|
- The word "and" connecting two actions ("update X AND add Y")
|
|
38947
38957
|
- Multiple FILE paths ("FILE: src/a.ts, src/b.ts, src/c.ts")
|
|
@@ -38956,6 +38966,8 @@ A failure in one part blocks the entire batch, wasting all the work.
|
|
|
38956
38966
|
|
|
38957
38967
|
SPLIT RULE: If your delegation draft has "and" in the TASK line, split it.
|
|
38958
38968
|
Two small delegations with two QA gates > one large delegation with one QA gate.
|
|
38969
|
+
<!-- BEHAVIORAL_GUIDANCE_END -->
|
|
38970
|
+
<!-- BEHAVIORAL_GUIDANCE_START -->
|
|
38959
38971
|
4. ARCHITECT CODING BOUNDARIES \u2014 Only code yourself after {{QA_RETRY_LIMIT}} {{AGENT_PREFIX}}coder failures on same task.
|
|
38960
38972
|
These thoughts are WRONG and must be ignored:
|
|
38961
38973
|
\u2717 "It's just a schema change / config flag / one-liner / column / field / import" \u2192 delegate to {{AGENT_PREFIX}}coder
|
|
@@ -38972,6 +38984,7 @@ Two small delegations with two QA gates > one large delegation with one QA gate.
|
|
|
38972
38984
|
If you catch yourself reaching for a code editing tool: STOP. Delegate to {{AGENT_PREFIX}}coder.
|
|
38973
38985
|
Zero {{AGENT_PREFIX}}coder failures on this task = zero justification for self-coding.
|
|
38974
38986
|
Self-coding without {{QA_RETRY_LIMIT}} failures is a Rule 1 violation.
|
|
38987
|
+
<!-- BEHAVIORAL_GUIDANCE_END -->
|
|
38975
38988
|
5. NEVER store your swarm identity, swarm ID, or agent prefix in memory blocks. Your identity comes ONLY from your system prompt. Memory blocks are for project knowledge only (NOT .swarm/ plan/context files \u2014 those are persistent project files).
|
|
38976
38989
|
6. **CRITIC GATE (Execute BEFORE any implementation work)**:
|
|
38977
38990
|
- When you first create a plan, IMMEDIATELY delegate the full plan to {{AGENT_PREFIX}}critic for review
|
|
@@ -39128,6 +39141,7 @@ Your message MUST NOT contain:
|
|
|
39128
39141
|
|
|
39129
39142
|
Delegation is a handoff, not a negotiation. State facts, let agents decide.
|
|
39130
39143
|
|
|
39144
|
+
<!-- BEHAVIORAL_GUIDANCE_START -->
|
|
39131
39145
|
PARTIAL GATE RATIONALIZATIONS \u2014 automated gates \u2260 agent review. Running SOME gates is NOT compliance:
|
|
39132
39146
|
\u2717 "I ran pre_check_batch so the code is verified" \u2192 pre_check_batch does NOT replace {{AGENT_PREFIX}}reviewer or {{AGENT_PREFIX}}test_engineer
|
|
39133
39147
|
\u2717 "syntax_check passed, good enough" \u2192 syntax_check catches syntax. Reviewer catches logic. Test_engineer catches behavior. All three are required.
|
|
@@ -39138,6 +39152,7 @@ PARTIAL GATE RATIONALIZATIONS \u2014 automated gates \u2260 agent review. Runnin
|
|
|
39138
39152
|
|
|
39139
39153
|
Running syntax_check + pre_check_batch without reviewer + test_engineer is a PARTIAL GATE VIOLATION.
|
|
39140
39154
|
It is the same severity as skipping all gates. The QA gate is ALL steps or NONE.
|
|
39155
|
+
<!-- BEHAVIORAL_GUIDANCE_END -->
|
|
39141
39156
|
|
|
39142
39157
|
8. **COVERAGE CHECK**: After adversarial tests pass, check if test_engineer reports coverage < 70%. If so, delegate {{AGENT_PREFIX}}test_engineer for an additional test pass targeting uncovered paths. This is a soft guideline; use judgment for trivial tasks.
|
|
39143
39158
|
9. **UI/UX DESIGN GATE**: Before delegating UI tasks to {{AGENT_PREFIX}}coder, check if the task involves UI components. Trigger conditions (ANY match):
|
|
@@ -41886,7 +41901,13 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000) {
|
|
|
41886
41901
|
lastPhaseCompletePhase: 0,
|
|
41887
41902
|
phaseAgentsDispatched: new Set,
|
|
41888
41903
|
qaSkipCount: 0,
|
|
41889
|
-
qaSkipTaskIds: []
|
|
41904
|
+
qaSkipTaskIds: [],
|
|
41905
|
+
taskWorkflowStates: new Map,
|
|
41906
|
+
lastGateOutcome: null,
|
|
41907
|
+
declaredCoderScope: null,
|
|
41908
|
+
lastScopeViolation: null,
|
|
41909
|
+
scopeViolationDetected: false,
|
|
41910
|
+
modifiedFilesThisCoderTask: []
|
|
41890
41911
|
};
|
|
41891
41912
|
swarmState.agentSessions.set(sessionId, sessionState);
|
|
41892
41913
|
swarmState.activeAgent.set(sessionId, agentName);
|
|
@@ -41955,6 +41976,24 @@ function ensureAgentSession(sessionId, agentName) {
|
|
|
41955
41976
|
if (!session.qaSkipTaskIds) {
|
|
41956
41977
|
session.qaSkipTaskIds = [];
|
|
41957
41978
|
}
|
|
41979
|
+
if (!session.taskWorkflowStates) {
|
|
41980
|
+
session.taskWorkflowStates = new Map;
|
|
41981
|
+
}
|
|
41982
|
+
if (session.lastGateOutcome === undefined) {
|
|
41983
|
+
session.lastGateOutcome = null;
|
|
41984
|
+
}
|
|
41985
|
+
if (session.declaredCoderScope === undefined) {
|
|
41986
|
+
session.declaredCoderScope = null;
|
|
41987
|
+
}
|
|
41988
|
+
if (session.lastScopeViolation === undefined) {
|
|
41989
|
+
session.lastScopeViolation = null;
|
|
41990
|
+
}
|
|
41991
|
+
if (session.modifiedFilesThisCoderTask === undefined) {
|
|
41992
|
+
session.modifiedFilesThisCoderTask = [];
|
|
41993
|
+
}
|
|
41994
|
+
if (session.scopeViolationDetected === undefined) {
|
|
41995
|
+
session.scopeViolationDetected = false;
|
|
41996
|
+
}
|
|
41958
41997
|
session.lastToolCallTime = now;
|
|
41959
41998
|
return session;
|
|
41960
41999
|
}
|
|
@@ -42034,6 +42073,29 @@ function recordPhaseAgentDispatch(sessionId, agentName) {
|
|
|
42034
42073
|
const normalizedName = stripKnownSwarmPrefix(agentName);
|
|
42035
42074
|
session.phaseAgentsDispatched.add(normalizedName);
|
|
42036
42075
|
}
|
|
42076
|
+
function advanceTaskState(session, taskId, newState) {
|
|
42077
|
+
const STATE_ORDER = [
|
|
42078
|
+
"idle",
|
|
42079
|
+
"coder_delegated",
|
|
42080
|
+
"pre_check_passed",
|
|
42081
|
+
"reviewer_run",
|
|
42082
|
+
"tests_run",
|
|
42083
|
+
"complete"
|
|
42084
|
+
];
|
|
42085
|
+
const current = session.taskWorkflowStates.get(taskId) ?? "idle";
|
|
42086
|
+
const currentIndex = STATE_ORDER.indexOf(current);
|
|
42087
|
+
const newIndex = STATE_ORDER.indexOf(newState);
|
|
42088
|
+
if (newIndex <= currentIndex) {
|
|
42089
|
+
throw new Error(`INVALID_TASK_STATE_TRANSITION: ${taskId} ${current} \u2192 ${newState}`);
|
|
42090
|
+
}
|
|
42091
|
+
if (newState === "complete" && current !== "tests_run") {
|
|
42092
|
+
throw new Error(`INVALID_TASK_STATE_TRANSITION: ${taskId} cannot reach complete from ${current} \u2014 must pass through tests_run first`);
|
|
42093
|
+
}
|
|
42094
|
+
session.taskWorkflowStates.set(taskId, newState);
|
|
42095
|
+
}
|
|
42096
|
+
function getTaskState(session, taskId) {
|
|
42097
|
+
return session.taskWorkflowStates.get(taskId) ?? "idle";
|
|
42098
|
+
}
|
|
42037
42099
|
|
|
42038
42100
|
// src/commands/benchmark.ts
|
|
42039
42101
|
init_utils();
|
|
@@ -47149,9 +47211,27 @@ function createDelegationGateHook(config3) {
|
|
|
47149
47211
|
if (normalized === "Task" || normalized === "task") {
|
|
47150
47212
|
const delegationChain = swarmState.delegationChains.get(input.sessionID);
|
|
47151
47213
|
if (delegationChain && delegationChain.length > 0) {
|
|
47152
|
-
|
|
47153
|
-
|
|
47154
|
-
|
|
47214
|
+
let lastCoderIndex = -1;
|
|
47215
|
+
for (let i2 = delegationChain.length - 1;i2 >= 0; i2--) {
|
|
47216
|
+
const target = stripKnownSwarmPrefix(delegationChain[i2].to);
|
|
47217
|
+
if (target.includes("coder")) {
|
|
47218
|
+
lastCoderIndex = i2;
|
|
47219
|
+
break;
|
|
47220
|
+
}
|
|
47221
|
+
}
|
|
47222
|
+
if (lastCoderIndex === -1)
|
|
47223
|
+
return;
|
|
47224
|
+
const afterCoder = delegationChain.slice(lastCoderIndex);
|
|
47225
|
+
let hasReviewer = false;
|
|
47226
|
+
let hasTestEngineer = false;
|
|
47227
|
+
for (const delegation of afterCoder) {
|
|
47228
|
+
const target = stripKnownSwarmPrefix(delegation.to);
|
|
47229
|
+
if (target === "reviewer")
|
|
47230
|
+
hasReviewer = true;
|
|
47231
|
+
if (target === "test_engineer")
|
|
47232
|
+
hasTestEngineer = true;
|
|
47233
|
+
}
|
|
47234
|
+
if (hasReviewer && hasTestEngineer) {
|
|
47155
47235
|
session.qaSkipCount = 0;
|
|
47156
47236
|
session.qaSkipTaskIds = [];
|
|
47157
47237
|
}
|
|
@@ -47184,14 +47264,71 @@ function createDelegationGateHook(config3) {
|
|
|
47184
47264
|
return;
|
|
47185
47265
|
const textPart = lastUserMessage.parts[textPartIndex];
|
|
47186
47266
|
const text = textPart.text ?? "";
|
|
47267
|
+
const taskDisclosureSessionID = lastUserMessage.info?.sessionID;
|
|
47268
|
+
if (taskDisclosureSessionID) {
|
|
47269
|
+
const taskSession = ensureAgentSession(taskDisclosureSessionID);
|
|
47270
|
+
const currentTaskIdForWindow = taskSession.currentTaskId;
|
|
47271
|
+
if (currentTaskIdForWindow) {
|
|
47272
|
+
const taskLineRegex = /^[ \t]*-[ \t]*(?:\[[ x]\][ \t]+)?(\d+\.\d+(?:\.\d+)*)[:. ].*/gm;
|
|
47273
|
+
const taskLines = [];
|
|
47274
|
+
taskLineRegex.lastIndex = 0;
|
|
47275
|
+
let regexMatch = taskLineRegex.exec(text);
|
|
47276
|
+
while (regexMatch !== null) {
|
|
47277
|
+
taskLines.push({
|
|
47278
|
+
line: regexMatch[0],
|
|
47279
|
+
taskId: regexMatch[1],
|
|
47280
|
+
index: regexMatch.index
|
|
47281
|
+
});
|
|
47282
|
+
regexMatch = taskLineRegex.exec(text);
|
|
47283
|
+
}
|
|
47284
|
+
if (taskLines.length > 5) {
|
|
47285
|
+
const currentIdx = taskLines.findIndex((t) => t.taskId === currentTaskIdForWindow);
|
|
47286
|
+
const windowStart = Math.max(0, currentIdx - 2);
|
|
47287
|
+
const windowEnd = Math.min(taskLines.length - 1, currentIdx + 3);
|
|
47288
|
+
const visibleTasks = taskLines.slice(windowStart, windowEnd + 1);
|
|
47289
|
+
const hiddenBefore = windowStart;
|
|
47290
|
+
const hiddenAfter = taskLines.length - 1 - windowEnd;
|
|
47291
|
+
const totalTasks = taskLines.length;
|
|
47292
|
+
const visibleCount = visibleTasks.length;
|
|
47293
|
+
const firstTaskIndex = taskLines[0].index;
|
|
47294
|
+
const lastTask = taskLines[taskLines.length - 1];
|
|
47295
|
+
const lastTaskEnd = lastTask.index + lastTask.line.length;
|
|
47296
|
+
const before = text.slice(0, firstTaskIndex);
|
|
47297
|
+
const after = text.slice(lastTaskEnd);
|
|
47298
|
+
const visibleLines = visibleTasks.map((t) => t.line).join(`
|
|
47299
|
+
`);
|
|
47300
|
+
const trimComment = `[Task window: showing ${visibleCount} of ${totalTasks} tasks]`;
|
|
47301
|
+
const trimmedMiddle = (hiddenBefore > 0 ? `[...${hiddenBefore} tasks hidden...]
|
|
47302
|
+
` : "") + visibleLines + (hiddenAfter > 0 ? `
|
|
47303
|
+
[...${hiddenAfter} tasks hidden...]` : "");
|
|
47304
|
+
textPart.text = `${before}${trimmedMiddle}
|
|
47305
|
+
${trimComment}${after}`;
|
|
47306
|
+
}
|
|
47307
|
+
}
|
|
47308
|
+
}
|
|
47187
47309
|
const sessionID = lastUserMessage.info?.sessionID;
|
|
47188
47310
|
const taskIdMatch = text.match(/TASK:\s*(.+?)(?:\n|$)/i);
|
|
47189
47311
|
const currentTaskId = taskIdMatch ? taskIdMatch[1].trim() : null;
|
|
47190
47312
|
const coderDelegationPattern = /(?:^|\n)\s*(?:\w+_)?coder\s*\n\s*TASK:/i;
|
|
47191
47313
|
const isCoderDelegation = coderDelegationPattern.test(text);
|
|
47314
|
+
const priorCoderTaskId = sessionID ? ensureAgentSession(sessionID).lastCoderDelegationTaskId ?? null : null;
|
|
47192
47315
|
if (sessionID && isCoderDelegation && currentTaskId) {
|
|
47193
47316
|
const session = ensureAgentSession(sessionID);
|
|
47194
47317
|
session.lastCoderDelegationTaskId = currentTaskId;
|
|
47318
|
+
const fileDirPattern = /^FILE:\s*(.+)$/gm;
|
|
47319
|
+
const declaredFiles = [];
|
|
47320
|
+
for (const match of text.matchAll(fileDirPattern)) {
|
|
47321
|
+
const filePath = match[1].trim();
|
|
47322
|
+
if (filePath.length > 0 && !declaredFiles.includes(filePath)) {
|
|
47323
|
+
declaredFiles.push(filePath);
|
|
47324
|
+
}
|
|
47325
|
+
}
|
|
47326
|
+
session.declaredCoderScope = declaredFiles.length > 0 ? declaredFiles : null;
|
|
47327
|
+
try {
|
|
47328
|
+
advanceTaskState(session, currentTaskId, "coder_delegated");
|
|
47329
|
+
} catch (err2) {
|
|
47330
|
+
console.warn(`[delegation-gate] state machine warn: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
47331
|
+
}
|
|
47195
47332
|
}
|
|
47196
47333
|
if (sessionID && !isCoderDelegation && currentTaskId) {
|
|
47197
47334
|
const session = ensureAgentSession(sessionID);
|
|
@@ -47203,6 +47340,29 @@ Rule 1: DELEGATE all coding to coder. You do NOT write code.`;
|
|
|
47203
47340
|
${text}`;
|
|
47204
47341
|
}
|
|
47205
47342
|
}
|
|
47343
|
+
{
|
|
47344
|
+
const deliberationSessionID = lastUserMessage.info?.sessionID;
|
|
47345
|
+
if (deliberationSessionID) {
|
|
47346
|
+
if (!/^[a-zA-Z0-9_-]{1,128}$/.test(deliberationSessionID)) {} else {
|
|
47347
|
+
const deliberationSession = ensureAgentSession(deliberationSessionID);
|
|
47348
|
+
const lastGate = deliberationSession.lastGateOutcome;
|
|
47349
|
+
let preamble;
|
|
47350
|
+
if (lastGate) {
|
|
47351
|
+
const gateResult = lastGate.passed ? "PASSED" : "FAILED";
|
|
47352
|
+
const sanitizedGate = lastGate.gate.replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 64);
|
|
47353
|
+
const sanitizedTaskId = lastGate.taskId.replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 32);
|
|
47354
|
+
preamble = `[Last gate: ${sanitizedGate} ${gateResult} for task ${sanitizedTaskId}]
|
|
47355
|
+
[DELIBERATE: Before proceeding \u2014 what is the SINGLE next task? What gates must it pass?]`;
|
|
47356
|
+
} else {
|
|
47357
|
+
preamble = `[DELIBERATE: Identify the first task from the plan. What gates must it pass before marking complete?]`;
|
|
47358
|
+
}
|
|
47359
|
+
const currentText = textPart.text ?? "";
|
|
47360
|
+
textPart.text = `${preamble}
|
|
47361
|
+
|
|
47362
|
+
${currentText}`;
|
|
47363
|
+
}
|
|
47364
|
+
}
|
|
47365
|
+
}
|
|
47206
47366
|
if (!isCoderDelegation)
|
|
47207
47367
|
return;
|
|
47208
47368
|
const warnings = [];
|
|
@@ -47245,8 +47405,9 @@ ${text}`;
|
|
|
47245
47405
|
const betweenCoders = delegationChain.slice(prevCoderIndex + 1);
|
|
47246
47406
|
const hasReviewer = betweenCoders.some((d) => stripKnownSwarmPrefix(d.to) === "reviewer");
|
|
47247
47407
|
const hasTestEngineer = betweenCoders.some((d) => stripKnownSwarmPrefix(d.to) === "test_engineer");
|
|
47248
|
-
|
|
47249
|
-
|
|
47408
|
+
const session = ensureAgentSession(sessionID);
|
|
47409
|
+
const priorTaskStuckAtCoder = priorCoderTaskId !== null && getTaskState(session, priorCoderTaskId) === "coder_delegated";
|
|
47410
|
+
if (!hasReviewer || !hasTestEngineer || priorTaskStuckAtCoder) {
|
|
47250
47411
|
if (session.qaSkipCount >= 1) {
|
|
47251
47412
|
const skippedTasks = session.qaSkipTaskIds.join(", ");
|
|
47252
47413
|
throw new Error(`\uD83D\uDED1 QA GATE ENFORCEMENT: ${session.qaSkipCount + 1} consecutive coder delegations without reviewer/test_engineer. ` + `Skipped tasks: [${skippedTasks}]. ` + `DELEGATE to reviewer and test_engineer NOW before any further coder work.`);
|
|
@@ -47506,6 +47667,16 @@ function getCurrentTaskId(sessionId) {
|
|
|
47506
47667
|
const session = swarmState.agentSessions.get(sessionId);
|
|
47507
47668
|
return session?.currentTaskId ?? `${sessionId}:unknown`;
|
|
47508
47669
|
}
|
|
47670
|
+
function isInDeclaredScope(filePath, scopeEntries) {
|
|
47671
|
+
const resolvedFile = path25.resolve(filePath);
|
|
47672
|
+
return scopeEntries.some((scope) => {
|
|
47673
|
+
const resolvedScope = path25.resolve(scope);
|
|
47674
|
+
if (resolvedFile === resolvedScope)
|
|
47675
|
+
return true;
|
|
47676
|
+
const rel = path25.relative(resolvedScope, resolvedFile);
|
|
47677
|
+
return rel.length > 0 && !rel.startsWith("..") && !path25.isAbsolute(rel);
|
|
47678
|
+
});
|
|
47679
|
+
}
|
|
47509
47680
|
function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
47510
47681
|
let directory;
|
|
47511
47682
|
let guardrailsConfig;
|
|
@@ -47528,7 +47699,27 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
47528
47699
|
return {
|
|
47529
47700
|
toolBefore: async (input, output) => {
|
|
47530
47701
|
const currentSession = swarmState.agentSessions.get(input.sessionID);
|
|
47531
|
-
if (currentSession?.delegationActive) {
|
|
47702
|
+
if (currentSession?.delegationActive) {
|
|
47703
|
+
if (isWriteTool(input.tool)) {
|
|
47704
|
+
const delegArgs = output.args;
|
|
47705
|
+
const delegTargetPath = delegArgs?.filePath ?? delegArgs?.path ?? delegArgs?.file ?? delegArgs?.target;
|
|
47706
|
+
if (typeof delegTargetPath === "string" && delegTargetPath.length > 0) {
|
|
47707
|
+
if (!currentSession.modifiedFilesThisCoderTask.includes(delegTargetPath)) {
|
|
47708
|
+
currentSession.modifiedFilesThisCoderTask.push(delegTargetPath);
|
|
47709
|
+
}
|
|
47710
|
+
}
|
|
47711
|
+
}
|
|
47712
|
+
} else if (isArchitect(input.sessionID)) {
|
|
47713
|
+
const coderDelegArgs = output.args;
|
|
47714
|
+
const coderDeleg = isAgentDelegation(input.tool, coderDelegArgs);
|
|
47715
|
+
if (coderDeleg.isDelegation && coderDeleg.targetAgent === "coder") {
|
|
47716
|
+
const coderSession = swarmState.agentSessions.get(input.sessionID);
|
|
47717
|
+
if (coderSession) {
|
|
47718
|
+
coderSession.modifiedFilesThisCoderTask = [];
|
|
47719
|
+
}
|
|
47720
|
+
}
|
|
47721
|
+
}
|
|
47722
|
+
if (isArchitect(input.sessionID) && isWriteTool(input.tool)) {
|
|
47532
47723
|
const args2 = output.args;
|
|
47533
47724
|
const targetPath = args2?.filePath ?? args2?.path ?? args2?.file ?? args2?.target;
|
|
47534
47725
|
if (typeof targetPath === "string" && targetPath.length > 0) {
|
|
@@ -47766,6 +47957,15 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
47766
47957
|
if (delegation.isDelegation && delegation.targetAgent === "coder" && session.lastCoderDelegationTaskId) {
|
|
47767
47958
|
session.currentTaskId = session.lastCoderDelegationTaskId;
|
|
47768
47959
|
session.partialGateWarningsIssuedForTask?.delete(session.currentTaskId);
|
|
47960
|
+
if (session.declaredCoderScope !== null) {
|
|
47961
|
+
const undeclaredFiles = session.modifiedFilesThisCoderTask.map((f) => f.replace(/[\r\n\t]/g, "_")).filter((f) => !isInDeclaredScope(f, session.declaredCoderScope));
|
|
47962
|
+
if (undeclaredFiles.length > 2) {
|
|
47963
|
+
const safeTaskId = String(session.currentTaskId ?? "").replace(/[\r\n\t]/g, "_");
|
|
47964
|
+
session.lastScopeViolation = `Scope violation for task ${safeTaskId}: ` + `${undeclaredFiles.length} undeclared files modified: ` + undeclaredFiles.join(", ");
|
|
47965
|
+
session.scopeViolationDetected = true;
|
|
47966
|
+
}
|
|
47967
|
+
}
|
|
47968
|
+
session.modifiedFilesThisCoderTask = [];
|
|
47769
47969
|
}
|
|
47770
47970
|
}
|
|
47771
47971
|
const window2 = getActiveWindow(input.sessionID);
|
|
@@ -47789,6 +47989,26 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
47789
47989
|
if (!sessionId) {
|
|
47790
47990
|
return;
|
|
47791
47991
|
}
|
|
47992
|
+
{
|
|
47993
|
+
const { modelID } = extractModelInfo(messages);
|
|
47994
|
+
if (modelID && isLowCapabilityModel(modelID)) {
|
|
47995
|
+
for (const msg of messages) {
|
|
47996
|
+
if (msg.info?.role !== "system")
|
|
47997
|
+
continue;
|
|
47998
|
+
for (const part of msg.parts) {
|
|
47999
|
+
try {
|
|
48000
|
+
if (part == null)
|
|
48001
|
+
continue;
|
|
48002
|
+
if (part.type !== "text" || typeof part.text !== "string")
|
|
48003
|
+
continue;
|
|
48004
|
+
if (!part.text.includes("<!-- BEHAVIORAL_GUIDANCE_START -->"))
|
|
48005
|
+
continue;
|
|
48006
|
+
part.text = part.text.replace(/<!--\s*BEHAVIORAL_GUIDANCE_START\s*-->[\s\S]*?<!--\s*BEHAVIORAL_GUIDANCE_END\s*-->/g, "[Enforcement: programmatic gates active]");
|
|
48007
|
+
} catch {}
|
|
48008
|
+
}
|
|
48009
|
+
}
|
|
48010
|
+
}
|
|
48011
|
+
}
|
|
47792
48012
|
const session = swarmState.agentSessions.get(sessionId);
|
|
47793
48013
|
const activeAgent = swarmState.activeAgent.get(sessionId);
|
|
47794
48014
|
const isArchitectSession = activeAgent ? stripKnownSwarmPrefix(activeAgent) === ORCHESTRATOR_NAME : session ? stripKnownSwarmPrefix(session.agentName) === ORCHESTRATOR_NAME : false;
|
|
@@ -47861,6 +48081,16 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
47861
48081
|
}
|
|
47862
48082
|
}
|
|
47863
48083
|
}
|
|
48084
|
+
if (isArchitectSessionForGates && session && session.scopeViolationDetected) {
|
|
48085
|
+
session.scopeViolationDetected = false;
|
|
48086
|
+
const textPart2 = lastMessage.parts.find((part) => part.type === "text" && typeof part.text === "string");
|
|
48087
|
+
if (textPart2 && session.lastScopeViolation) {
|
|
48088
|
+
textPart2.text = `\u26A0\uFE0F SCOPE VIOLATION: ${session.lastScopeViolation}
|
|
48089
|
+
` + `Only modify files within your declared scope. Request scope expansion from architect if needed.
|
|
48090
|
+
|
|
48091
|
+
` + textPart2.text;
|
|
48092
|
+
}
|
|
48093
|
+
}
|
|
47864
48094
|
if (isArchitectSessionForGates && session && session.catastrophicPhaseWarnings) {
|
|
47865
48095
|
try {
|
|
47866
48096
|
const plan = await loadPlan(directory);
|
|
@@ -50700,7 +50930,12 @@ function deserializeAgentSession(s) {
|
|
|
50700
50930
|
lastPhaseCompletePhase: s.lastPhaseCompletePhase ?? 0,
|
|
50701
50931
|
phaseAgentsDispatched,
|
|
50702
50932
|
qaSkipCount: s.qaSkipCount ?? 0,
|
|
50703
|
-
qaSkipTaskIds: s.qaSkipTaskIds ?? []
|
|
50933
|
+
qaSkipTaskIds: s.qaSkipTaskIds ?? [],
|
|
50934
|
+
taskWorkflowStates: new Map,
|
|
50935
|
+
lastGateOutcome: null,
|
|
50936
|
+
declaredCoderScope: null,
|
|
50937
|
+
lastScopeViolation: null,
|
|
50938
|
+
modifiedFilesThisCoderTask: []
|
|
50704
50939
|
};
|
|
50705
50940
|
}
|
|
50706
50941
|
async function readSnapshot(directory) {
|
|
@@ -51512,6 +51747,184 @@ var complexity_hotspots = createSwarmTool({
|
|
|
51512
51747
|
}
|
|
51513
51748
|
}
|
|
51514
51749
|
});
|
|
51750
|
+
// src/tools/declare-scope.ts
|
|
51751
|
+
init_tool();
|
|
51752
|
+
import * as fs19 from "fs";
|
|
51753
|
+
import * as path30 from "path";
|
|
51754
|
+
init_create_tool();
|
|
51755
|
+
function validateTaskIdFormat(taskId) {
|
|
51756
|
+
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
51757
|
+
if (!taskIdPattern.test(taskId)) {
|
|
51758
|
+
return `Invalid taskId "${taskId}". Must match pattern N.M or N.M.P (e.g., "1.1", "1.2.3")`;
|
|
51759
|
+
}
|
|
51760
|
+
return;
|
|
51761
|
+
}
|
|
51762
|
+
function validateFiles(files) {
|
|
51763
|
+
const errors5 = [];
|
|
51764
|
+
for (const file3 of files) {
|
|
51765
|
+
if (file3.includes("\x00")) {
|
|
51766
|
+
errors5.push(`Invalid file "${file3}": null bytes are not allowed`);
|
|
51767
|
+
}
|
|
51768
|
+
if (file3.includes("..")) {
|
|
51769
|
+
errors5.push(`Invalid file "${file3}": path traversal sequences (..) are not allowed`);
|
|
51770
|
+
}
|
|
51771
|
+
if (file3.length > 4096) {
|
|
51772
|
+
errors5.push(`Invalid file "${file3}": path exceeds maximum length of 4096 characters`);
|
|
51773
|
+
}
|
|
51774
|
+
}
|
|
51775
|
+
return errors5;
|
|
51776
|
+
}
|
|
51777
|
+
async function executeDeclareScope(args2, fallbackDir) {
|
|
51778
|
+
const taskIdError = validateTaskIdFormat(args2.taskId);
|
|
51779
|
+
if (taskIdError) {
|
|
51780
|
+
return {
|
|
51781
|
+
success: false,
|
|
51782
|
+
message: "Validation failed",
|
|
51783
|
+
errors: [taskIdError]
|
|
51784
|
+
};
|
|
51785
|
+
}
|
|
51786
|
+
if (!Array.isArray(args2.files) || args2.files.length === 0) {
|
|
51787
|
+
return {
|
|
51788
|
+
success: false,
|
|
51789
|
+
message: "Validation failed",
|
|
51790
|
+
errors: ["files must be a non-empty array"]
|
|
51791
|
+
};
|
|
51792
|
+
}
|
|
51793
|
+
const fileErrors = validateFiles(args2.files);
|
|
51794
|
+
if (fileErrors.length > 0) {
|
|
51795
|
+
return {
|
|
51796
|
+
success: false,
|
|
51797
|
+
message: "Validation failed",
|
|
51798
|
+
errors: fileErrors
|
|
51799
|
+
};
|
|
51800
|
+
}
|
|
51801
|
+
if (args2.whitelist) {
|
|
51802
|
+
const whitelistErrors = validateFiles(args2.whitelist);
|
|
51803
|
+
if (whitelistErrors.length > 0) {
|
|
51804
|
+
return {
|
|
51805
|
+
success: false,
|
|
51806
|
+
message: "Validation failed",
|
|
51807
|
+
errors: whitelistErrors
|
|
51808
|
+
};
|
|
51809
|
+
}
|
|
51810
|
+
}
|
|
51811
|
+
let normalizedDir;
|
|
51812
|
+
if (args2.working_directory != null) {
|
|
51813
|
+
if (args2.working_directory.includes("\x00")) {
|
|
51814
|
+
return {
|
|
51815
|
+
success: false,
|
|
51816
|
+
message: "Invalid working_directory: null bytes are not allowed",
|
|
51817
|
+
errors: ["Invalid working_directory: null bytes are not allowed"]
|
|
51818
|
+
};
|
|
51819
|
+
}
|
|
51820
|
+
if (process.platform === "win32") {
|
|
51821
|
+
const devicePathPattern = /^\\\\|^(NUL|CON|AUX|COM[1-9]|LPT[1-9])(\..*)?$/i;
|
|
51822
|
+
if (devicePathPattern.test(args2.working_directory)) {
|
|
51823
|
+
return {
|
|
51824
|
+
success: false,
|
|
51825
|
+
message: "Invalid working_directory: Windows device paths are not allowed",
|
|
51826
|
+
errors: [
|
|
51827
|
+
"Invalid working_directory: Windows device paths are not allowed"
|
|
51828
|
+
]
|
|
51829
|
+
};
|
|
51830
|
+
}
|
|
51831
|
+
}
|
|
51832
|
+
normalizedDir = path30.normalize(args2.working_directory);
|
|
51833
|
+
const pathParts = normalizedDir.split(path30.sep);
|
|
51834
|
+
if (pathParts.includes("..")) {
|
|
51835
|
+
return {
|
|
51836
|
+
success: false,
|
|
51837
|
+
message: "Invalid working_directory: path traversal sequences (..) are not allowed",
|
|
51838
|
+
errors: [
|
|
51839
|
+
"Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
51840
|
+
]
|
|
51841
|
+
};
|
|
51842
|
+
}
|
|
51843
|
+
const resolvedDir = path30.resolve(normalizedDir);
|
|
51844
|
+
try {
|
|
51845
|
+
const realPath = fs19.realpathSync(resolvedDir);
|
|
51846
|
+
const planPath2 = path30.join(realPath, ".swarm", "plan.json");
|
|
51847
|
+
if (!fs19.existsSync(planPath2)) {
|
|
51848
|
+
return {
|
|
51849
|
+
success: false,
|
|
51850
|
+
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
51851
|
+
errors: [
|
|
51852
|
+
`Invalid working_directory: plan not found in "${realPath}"`
|
|
51853
|
+
]
|
|
51854
|
+
};
|
|
51855
|
+
}
|
|
51856
|
+
} catch {
|
|
51857
|
+
return {
|
|
51858
|
+
success: false,
|
|
51859
|
+
message: `Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`,
|
|
51860
|
+
errors: [
|
|
51861
|
+
`Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`
|
|
51862
|
+
]
|
|
51863
|
+
};
|
|
51864
|
+
}
|
|
51865
|
+
}
|
|
51866
|
+
const directory = normalizedDir ?? fallbackDir ?? process.cwd();
|
|
51867
|
+
const planPath = path30.resolve(directory, ".swarm", "plan.json");
|
|
51868
|
+
if (!fs19.existsSync(planPath)) {
|
|
51869
|
+
return {
|
|
51870
|
+
success: false,
|
|
51871
|
+
message: "No plan found",
|
|
51872
|
+
errors: ["plan.json not found"]
|
|
51873
|
+
};
|
|
51874
|
+
}
|
|
51875
|
+
let planContent;
|
|
51876
|
+
try {
|
|
51877
|
+
planContent = JSON.parse(fs19.readFileSync(planPath, "utf-8"));
|
|
51878
|
+
} catch {
|
|
51879
|
+
return {
|
|
51880
|
+
success: false,
|
|
51881
|
+
message: "Failed to parse plan.json",
|
|
51882
|
+
errors: ["plan.json is not valid JSON"]
|
|
51883
|
+
};
|
|
51884
|
+
}
|
|
51885
|
+
const allTasks = planContent.phases?.flatMap((p) => p.tasks ?? []) ?? [];
|
|
51886
|
+
const taskExists = allTasks.some((t) => t.id === args2.taskId);
|
|
51887
|
+
if (!taskExists) {
|
|
51888
|
+
return {
|
|
51889
|
+
success: false,
|
|
51890
|
+
message: `Task ${args2.taskId} not found in plan`,
|
|
51891
|
+
errors: [`Task ${args2.taskId} does not exist in plan.json`]
|
|
51892
|
+
};
|
|
51893
|
+
}
|
|
51894
|
+
for (const [_sessionId, session] of swarmState.agentSessions) {
|
|
51895
|
+
const taskState = getTaskState(session, args2.taskId);
|
|
51896
|
+
if (taskState === "complete") {
|
|
51897
|
+
return {
|
|
51898
|
+
success: false,
|
|
51899
|
+
message: `Task ${args2.taskId} is already completed`,
|
|
51900
|
+
errors: [`Cannot declare scope for completed task ${args2.taskId}`]
|
|
51901
|
+
};
|
|
51902
|
+
}
|
|
51903
|
+
}
|
|
51904
|
+
const mergedFiles = [...args2.files, ...args2.whitelist ?? []];
|
|
51905
|
+
for (const [_sessionId, session] of swarmState.agentSessions) {
|
|
51906
|
+
session.declaredCoderScope = mergedFiles;
|
|
51907
|
+
session.lastScopeViolation = null;
|
|
51908
|
+
}
|
|
51909
|
+
return {
|
|
51910
|
+
success: true,
|
|
51911
|
+
message: "Scope declared successfully",
|
|
51912
|
+
taskId: args2.taskId,
|
|
51913
|
+
fileCount: mergedFiles.length
|
|
51914
|
+
};
|
|
51915
|
+
}
|
|
51916
|
+
var declare_scope = createSwarmTool({
|
|
51917
|
+
description: "Declare the file scope for the next coder delegation. " + "Sets the list of files the coder is permitted to modify for a specific task. " + "Must be called before delegating to mega_coder to enable scope containment checking.",
|
|
51918
|
+
args: {
|
|
51919
|
+
taskId: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, "Task ID must be in N.M or N.M.P format").describe('Task ID for which scope is being declared, e.g. "1.1", "1.2.3"'),
|
|
51920
|
+
files: tool.schema.array(tool.schema.string().min(1).max(4096)).min(1).describe("Array of file paths the coder is permitted to modify"),
|
|
51921
|
+
whitelist: tool.schema.array(tool.schema.string().min(1).max(4096)).optional().describe("Additional file paths to whitelist (merged with files)"),
|
|
51922
|
+
working_directory: tool.schema.string().optional().describe("Working directory where the plan is located")
|
|
51923
|
+
},
|
|
51924
|
+
execute: async (args2, _directory) => {
|
|
51925
|
+
return JSON.stringify(await executeDeclareScope(args2, _directory), null, 2);
|
|
51926
|
+
}
|
|
51927
|
+
});
|
|
51515
51928
|
// src/tools/diff.ts
|
|
51516
51929
|
init_dist();
|
|
51517
51930
|
import { execFileSync } from "child_process";
|
|
@@ -51541,20 +51954,20 @@ function validateBase(base) {
|
|
|
51541
51954
|
function validatePaths(paths) {
|
|
51542
51955
|
if (!paths)
|
|
51543
51956
|
return null;
|
|
51544
|
-
for (const
|
|
51545
|
-
if (!
|
|
51957
|
+
for (const path31 of paths) {
|
|
51958
|
+
if (!path31 || path31.length === 0) {
|
|
51546
51959
|
return "empty path not allowed";
|
|
51547
51960
|
}
|
|
51548
|
-
if (
|
|
51961
|
+
if (path31.length > MAX_PATH_LENGTH) {
|
|
51549
51962
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
51550
51963
|
}
|
|
51551
|
-
if (SHELL_METACHARACTERS2.test(
|
|
51964
|
+
if (SHELL_METACHARACTERS2.test(path31)) {
|
|
51552
51965
|
return "path contains shell metacharacters";
|
|
51553
51966
|
}
|
|
51554
|
-
if (
|
|
51967
|
+
if (path31.startsWith("-")) {
|
|
51555
51968
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
51556
51969
|
}
|
|
51557
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
51970
|
+
if (CONTROL_CHAR_PATTERN2.test(path31)) {
|
|
51558
51971
|
return "path contains control characters";
|
|
51559
51972
|
}
|
|
51560
51973
|
}
|
|
@@ -51634,8 +52047,8 @@ var diff = tool({
|
|
|
51634
52047
|
if (parts2.length >= 3) {
|
|
51635
52048
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
51636
52049
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
51637
|
-
const
|
|
51638
|
-
files.push({ path:
|
|
52050
|
+
const path31 = parts2[2];
|
|
52051
|
+
files.push({ path: path31, additions, deletions });
|
|
51639
52052
|
}
|
|
51640
52053
|
}
|
|
51641
52054
|
const contractChanges = [];
|
|
@@ -51864,8 +52277,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
51864
52277
|
// src/tools/evidence-check.ts
|
|
51865
52278
|
init_dist();
|
|
51866
52279
|
init_create_tool();
|
|
51867
|
-
import * as
|
|
51868
|
-
import * as
|
|
52280
|
+
import * as fs20 from "fs";
|
|
52281
|
+
import * as path31 from "path";
|
|
51869
52282
|
var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
|
|
51870
52283
|
var MAX_EVIDENCE_FILES = 1000;
|
|
51871
52284
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
@@ -51888,9 +52301,9 @@ function validateRequiredTypes(input) {
|
|
|
51888
52301
|
return null;
|
|
51889
52302
|
}
|
|
51890
52303
|
function isPathWithinSwarm(filePath, cwd) {
|
|
51891
|
-
const normalizedCwd =
|
|
51892
|
-
const swarmPath =
|
|
51893
|
-
const normalizedPath =
|
|
52304
|
+
const normalizedCwd = path31.resolve(cwd);
|
|
52305
|
+
const swarmPath = path31.join(normalizedCwd, ".swarm");
|
|
52306
|
+
const normalizedPath = path31.resolve(filePath);
|
|
51894
52307
|
return normalizedPath.startsWith(swarmPath);
|
|
51895
52308
|
}
|
|
51896
52309
|
function parseCompletedTasks(planContent) {
|
|
@@ -51906,12 +52319,12 @@ function parseCompletedTasks(planContent) {
|
|
|
51906
52319
|
}
|
|
51907
52320
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
51908
52321
|
const evidence = [];
|
|
51909
|
-
if (!
|
|
52322
|
+
if (!fs20.existsSync(evidenceDir) || !fs20.statSync(evidenceDir).isDirectory()) {
|
|
51910
52323
|
return evidence;
|
|
51911
52324
|
}
|
|
51912
52325
|
let files;
|
|
51913
52326
|
try {
|
|
51914
|
-
files =
|
|
52327
|
+
files = fs20.readdirSync(evidenceDir);
|
|
51915
52328
|
} catch {
|
|
51916
52329
|
return evidence;
|
|
51917
52330
|
}
|
|
@@ -51920,14 +52333,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
51920
52333
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
51921
52334
|
continue;
|
|
51922
52335
|
}
|
|
51923
|
-
const filePath =
|
|
52336
|
+
const filePath = path31.join(evidenceDir, filename);
|
|
51924
52337
|
try {
|
|
51925
|
-
const resolvedPath =
|
|
51926
|
-
const evidenceDirResolved =
|
|
52338
|
+
const resolvedPath = path31.resolve(filePath);
|
|
52339
|
+
const evidenceDirResolved = path31.resolve(evidenceDir);
|
|
51927
52340
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
51928
52341
|
continue;
|
|
51929
52342
|
}
|
|
51930
|
-
const stat2 =
|
|
52343
|
+
const stat2 = fs20.lstatSync(filePath);
|
|
51931
52344
|
if (!stat2.isFile()) {
|
|
51932
52345
|
continue;
|
|
51933
52346
|
}
|
|
@@ -51936,7 +52349,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
51936
52349
|
}
|
|
51937
52350
|
let fileStat;
|
|
51938
52351
|
try {
|
|
51939
|
-
fileStat =
|
|
52352
|
+
fileStat = fs20.statSync(filePath);
|
|
51940
52353
|
if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
|
|
51941
52354
|
continue;
|
|
51942
52355
|
}
|
|
@@ -51945,7 +52358,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
51945
52358
|
}
|
|
51946
52359
|
let content;
|
|
51947
52360
|
try {
|
|
51948
|
-
content =
|
|
52361
|
+
content = fs20.readFileSync(filePath, "utf-8");
|
|
51949
52362
|
} catch {
|
|
51950
52363
|
continue;
|
|
51951
52364
|
}
|
|
@@ -52030,7 +52443,7 @@ var evidence_check = createSwarmTool({
|
|
|
52030
52443
|
return JSON.stringify(errorResult, null, 2);
|
|
52031
52444
|
}
|
|
52032
52445
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
52033
|
-
const planPath =
|
|
52446
|
+
const planPath = path31.join(cwd, PLAN_FILE);
|
|
52034
52447
|
if (!isPathWithinSwarm(planPath, cwd)) {
|
|
52035
52448
|
const errorResult = {
|
|
52036
52449
|
error: "plan file path validation failed",
|
|
@@ -52044,7 +52457,7 @@ var evidence_check = createSwarmTool({
|
|
|
52044
52457
|
}
|
|
52045
52458
|
let planContent;
|
|
52046
52459
|
try {
|
|
52047
|
-
planContent =
|
|
52460
|
+
planContent = fs20.readFileSync(planPath, "utf-8");
|
|
52048
52461
|
} catch {
|
|
52049
52462
|
const result2 = {
|
|
52050
52463
|
message: "No completed tasks found in plan.",
|
|
@@ -52062,7 +52475,7 @@ var evidence_check = createSwarmTool({
|
|
|
52062
52475
|
};
|
|
52063
52476
|
return JSON.stringify(result2, null, 2);
|
|
52064
52477
|
}
|
|
52065
|
-
const evidenceDir =
|
|
52478
|
+
const evidenceDir = path31.join(cwd, EVIDENCE_DIR);
|
|
52066
52479
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
52067
52480
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
52068
52481
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -52079,8 +52492,8 @@ var evidence_check = createSwarmTool({
|
|
|
52079
52492
|
// src/tools/file-extractor.ts
|
|
52080
52493
|
init_tool();
|
|
52081
52494
|
init_create_tool();
|
|
52082
|
-
import * as
|
|
52083
|
-
import * as
|
|
52495
|
+
import * as fs21 from "fs";
|
|
52496
|
+
import * as path32 from "path";
|
|
52084
52497
|
var EXT_MAP = {
|
|
52085
52498
|
python: ".py",
|
|
52086
52499
|
py: ".py",
|
|
@@ -52142,8 +52555,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
52142
52555
|
execute: async (args2, directory) => {
|
|
52143
52556
|
const { content, output_dir, prefix } = args2;
|
|
52144
52557
|
const targetDir = output_dir || directory;
|
|
52145
|
-
if (!
|
|
52146
|
-
|
|
52558
|
+
if (!fs21.existsSync(targetDir)) {
|
|
52559
|
+
fs21.mkdirSync(targetDir, { recursive: true });
|
|
52147
52560
|
}
|
|
52148
52561
|
if (!content) {
|
|
52149
52562
|
return "Error: content is required";
|
|
@@ -52161,16 +52574,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
52161
52574
|
if (prefix) {
|
|
52162
52575
|
filename = `${prefix}_${filename}`;
|
|
52163
52576
|
}
|
|
52164
|
-
let filepath =
|
|
52165
|
-
const base =
|
|
52166
|
-
const ext =
|
|
52577
|
+
let filepath = path32.join(targetDir, filename);
|
|
52578
|
+
const base = path32.basename(filepath, path32.extname(filepath));
|
|
52579
|
+
const ext = path32.extname(filepath);
|
|
52167
52580
|
let counter = 1;
|
|
52168
|
-
while (
|
|
52169
|
-
filepath =
|
|
52581
|
+
while (fs21.existsSync(filepath)) {
|
|
52582
|
+
filepath = path32.join(targetDir, `${base}_${counter}${ext}`);
|
|
52170
52583
|
counter++;
|
|
52171
52584
|
}
|
|
52172
52585
|
try {
|
|
52173
|
-
|
|
52586
|
+
fs21.writeFileSync(filepath, code.trim(), "utf-8");
|
|
52174
52587
|
savedFiles.push(filepath);
|
|
52175
52588
|
} catch (error93) {
|
|
52176
52589
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -52199,7 +52612,7 @@ init_dist();
|
|
|
52199
52612
|
var GITINGEST_TIMEOUT_MS = 1e4;
|
|
52200
52613
|
var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
|
|
52201
52614
|
var GITINGEST_MAX_RETRIES = 2;
|
|
52202
|
-
var delay = (ms) => new Promise((
|
|
52615
|
+
var delay = (ms) => new Promise((resolve12) => setTimeout(resolve12, ms));
|
|
52203
52616
|
async function fetchGitingest(args2) {
|
|
52204
52617
|
for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
|
|
52205
52618
|
try {
|
|
@@ -52278,8 +52691,8 @@ var gitingest = tool({
|
|
|
52278
52691
|
});
|
|
52279
52692
|
// src/tools/imports.ts
|
|
52280
52693
|
init_dist();
|
|
52281
|
-
import * as
|
|
52282
|
-
import * as
|
|
52694
|
+
import * as fs22 from "fs";
|
|
52695
|
+
import * as path33 from "path";
|
|
52283
52696
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
52284
52697
|
var MAX_SYMBOL_LENGTH = 256;
|
|
52285
52698
|
var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
|
|
@@ -52333,7 +52746,7 @@ function validateSymbolInput(symbol3) {
|
|
|
52333
52746
|
return null;
|
|
52334
52747
|
}
|
|
52335
52748
|
function isBinaryFile2(filePath, buffer) {
|
|
52336
|
-
const ext =
|
|
52749
|
+
const ext = path33.extname(filePath).toLowerCase();
|
|
52337
52750
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
52338
52751
|
return false;
|
|
52339
52752
|
}
|
|
@@ -52357,15 +52770,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
52357
52770
|
const imports = [];
|
|
52358
52771
|
let _resolvedTarget;
|
|
52359
52772
|
try {
|
|
52360
|
-
_resolvedTarget =
|
|
52773
|
+
_resolvedTarget = path33.resolve(targetFile);
|
|
52361
52774
|
} catch {
|
|
52362
52775
|
_resolvedTarget = targetFile;
|
|
52363
52776
|
}
|
|
52364
|
-
const targetBasename =
|
|
52777
|
+
const targetBasename = path33.basename(targetFile, path33.extname(targetFile));
|
|
52365
52778
|
const targetWithExt = targetFile;
|
|
52366
52779
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
52367
|
-
const normalizedTargetWithExt =
|
|
52368
|
-
const normalizedTargetWithoutExt =
|
|
52780
|
+
const normalizedTargetWithExt = path33.normalize(targetWithExt).replace(/\\/g, "/");
|
|
52781
|
+
const normalizedTargetWithoutExt = path33.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
52369
52782
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
52370
52783
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
52371
52784
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -52388,9 +52801,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
52388
52801
|
}
|
|
52389
52802
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
52390
52803
|
let isMatch = false;
|
|
52391
|
-
const _targetDir =
|
|
52392
|
-
const targetExt =
|
|
52393
|
-
const targetBasenameNoExt =
|
|
52804
|
+
const _targetDir = path33.dirname(targetFile);
|
|
52805
|
+
const targetExt = path33.extname(targetFile);
|
|
52806
|
+
const targetBasenameNoExt = path33.basename(targetFile, targetExt);
|
|
52394
52807
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
52395
52808
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
52396
52809
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -52447,7 +52860,7 @@ var SKIP_DIRECTORIES2 = new Set([
|
|
|
52447
52860
|
function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
52448
52861
|
let entries;
|
|
52449
52862
|
try {
|
|
52450
|
-
entries =
|
|
52863
|
+
entries = fs22.readdirSync(dir);
|
|
52451
52864
|
} catch (e) {
|
|
52452
52865
|
stats.fileErrors.push({
|
|
52453
52866
|
path: dir,
|
|
@@ -52458,13 +52871,13 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
52458
52871
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
52459
52872
|
for (const entry of entries) {
|
|
52460
52873
|
if (SKIP_DIRECTORIES2.has(entry)) {
|
|
52461
|
-
stats.skippedDirs.push(
|
|
52874
|
+
stats.skippedDirs.push(path33.join(dir, entry));
|
|
52462
52875
|
continue;
|
|
52463
52876
|
}
|
|
52464
|
-
const fullPath =
|
|
52877
|
+
const fullPath = path33.join(dir, entry);
|
|
52465
52878
|
let stat2;
|
|
52466
52879
|
try {
|
|
52467
|
-
stat2 =
|
|
52880
|
+
stat2 = fs22.statSync(fullPath);
|
|
52468
52881
|
} catch (e) {
|
|
52469
52882
|
stats.fileErrors.push({
|
|
52470
52883
|
path: fullPath,
|
|
@@ -52475,7 +52888,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
52475
52888
|
if (stat2.isDirectory()) {
|
|
52476
52889
|
findSourceFiles2(fullPath, files, stats);
|
|
52477
52890
|
} else if (stat2.isFile()) {
|
|
52478
|
-
const ext =
|
|
52891
|
+
const ext = path33.extname(fullPath).toLowerCase();
|
|
52479
52892
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
52480
52893
|
files.push(fullPath);
|
|
52481
52894
|
}
|
|
@@ -52531,8 +52944,8 @@ var imports = tool({
|
|
|
52531
52944
|
return JSON.stringify(errorResult, null, 2);
|
|
52532
52945
|
}
|
|
52533
52946
|
try {
|
|
52534
|
-
const targetFile =
|
|
52535
|
-
if (!
|
|
52947
|
+
const targetFile = path33.resolve(file3);
|
|
52948
|
+
if (!fs22.existsSync(targetFile)) {
|
|
52536
52949
|
const errorResult = {
|
|
52537
52950
|
error: `target file not found: ${file3}`,
|
|
52538
52951
|
target: file3,
|
|
@@ -52542,7 +52955,7 @@ var imports = tool({
|
|
|
52542
52955
|
};
|
|
52543
52956
|
return JSON.stringify(errorResult, null, 2);
|
|
52544
52957
|
}
|
|
52545
|
-
const targetStat =
|
|
52958
|
+
const targetStat = fs22.statSync(targetFile);
|
|
52546
52959
|
if (!targetStat.isFile()) {
|
|
52547
52960
|
const errorResult = {
|
|
52548
52961
|
error: "target must be a file, not a directory",
|
|
@@ -52553,7 +52966,7 @@ var imports = tool({
|
|
|
52553
52966
|
};
|
|
52554
52967
|
return JSON.stringify(errorResult, null, 2);
|
|
52555
52968
|
}
|
|
52556
|
-
const baseDir =
|
|
52969
|
+
const baseDir = path33.dirname(targetFile);
|
|
52557
52970
|
const scanStats = {
|
|
52558
52971
|
skippedDirs: [],
|
|
52559
52972
|
skippedFiles: 0,
|
|
@@ -52568,12 +52981,12 @@ var imports = tool({
|
|
|
52568
52981
|
if (consumers.length >= MAX_CONSUMERS)
|
|
52569
52982
|
break;
|
|
52570
52983
|
try {
|
|
52571
|
-
const stat2 =
|
|
52984
|
+
const stat2 = fs22.statSync(filePath);
|
|
52572
52985
|
if (stat2.size > MAX_FILE_SIZE_BYTES4) {
|
|
52573
52986
|
skippedFileCount++;
|
|
52574
52987
|
continue;
|
|
52575
52988
|
}
|
|
52576
|
-
const buffer =
|
|
52989
|
+
const buffer = fs22.readFileSync(filePath);
|
|
52577
52990
|
if (isBinaryFile2(filePath, buffer)) {
|
|
52578
52991
|
skippedFileCount++;
|
|
52579
52992
|
continue;
|
|
@@ -52642,8 +53055,8 @@ init_lint();
|
|
|
52642
53055
|
|
|
52643
53056
|
// src/tools/phase-complete.ts
|
|
52644
53057
|
init_dist();
|
|
52645
|
-
import * as
|
|
52646
|
-
import * as
|
|
53058
|
+
import * as fs23 from "fs";
|
|
53059
|
+
import * as path34 from "path";
|
|
52647
53060
|
init_manager();
|
|
52648
53061
|
init_utils2();
|
|
52649
53062
|
init_create_tool();
|
|
@@ -52833,7 +53246,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
52833
53246
|
}
|
|
52834
53247
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
52835
53248
|
try {
|
|
52836
|
-
const projectName =
|
|
53249
|
+
const projectName = path34.basename(dir);
|
|
52837
53250
|
const knowledgeConfig = {
|
|
52838
53251
|
enabled: true,
|
|
52839
53252
|
swarm_max_entries: 100,
|
|
@@ -52894,7 +53307,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
52894
53307
|
};
|
|
52895
53308
|
try {
|
|
52896
53309
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
52897
|
-
|
|
53310
|
+
fs23.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
52898
53311
|
`, "utf-8");
|
|
52899
53312
|
} catch (writeError) {
|
|
52900
53313
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -52952,8 +53365,8 @@ init_dist();
|
|
|
52952
53365
|
init_discovery();
|
|
52953
53366
|
init_utils();
|
|
52954
53367
|
init_create_tool();
|
|
52955
|
-
import * as
|
|
52956
|
-
import * as
|
|
53368
|
+
import * as fs24 from "fs";
|
|
53369
|
+
import * as path35 from "path";
|
|
52957
53370
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
52958
53371
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
52959
53372
|
function isValidEcosystem(value) {
|
|
@@ -52971,28 +53384,28 @@ function validateArgs3(args2) {
|
|
|
52971
53384
|
function detectEcosystems(directory) {
|
|
52972
53385
|
const ecosystems = [];
|
|
52973
53386
|
const cwd = directory;
|
|
52974
|
-
if (
|
|
53387
|
+
if (fs24.existsSync(path35.join(cwd, "package.json"))) {
|
|
52975
53388
|
ecosystems.push("npm");
|
|
52976
53389
|
}
|
|
52977
|
-
if (
|
|
53390
|
+
if (fs24.existsSync(path35.join(cwd, "pyproject.toml")) || fs24.existsSync(path35.join(cwd, "requirements.txt"))) {
|
|
52978
53391
|
ecosystems.push("pip");
|
|
52979
53392
|
}
|
|
52980
|
-
if (
|
|
53393
|
+
if (fs24.existsSync(path35.join(cwd, "Cargo.toml"))) {
|
|
52981
53394
|
ecosystems.push("cargo");
|
|
52982
53395
|
}
|
|
52983
|
-
if (
|
|
53396
|
+
if (fs24.existsSync(path35.join(cwd, "go.mod"))) {
|
|
52984
53397
|
ecosystems.push("go");
|
|
52985
53398
|
}
|
|
52986
53399
|
try {
|
|
52987
|
-
const files =
|
|
53400
|
+
const files = fs24.readdirSync(cwd);
|
|
52988
53401
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
52989
53402
|
ecosystems.push("dotnet");
|
|
52990
53403
|
}
|
|
52991
53404
|
} catch {}
|
|
52992
|
-
if (
|
|
53405
|
+
if (fs24.existsSync(path35.join(cwd, "Gemfile")) || fs24.existsSync(path35.join(cwd, "Gemfile.lock"))) {
|
|
52993
53406
|
ecosystems.push("ruby");
|
|
52994
53407
|
}
|
|
52995
|
-
if (
|
|
53408
|
+
if (fs24.existsSync(path35.join(cwd, "pubspec.yaml"))) {
|
|
52996
53409
|
ecosystems.push("dart");
|
|
52997
53410
|
}
|
|
52998
53411
|
return ecosystems;
|
|
@@ -53005,7 +53418,7 @@ async function runNpmAudit(directory) {
|
|
|
53005
53418
|
stderr: "pipe",
|
|
53006
53419
|
cwd: directory
|
|
53007
53420
|
});
|
|
53008
|
-
const timeoutPromise = new Promise((
|
|
53421
|
+
const timeoutPromise = new Promise((resolve13) => setTimeout(() => resolve13("timeout"), AUDIT_TIMEOUT_MS));
|
|
53009
53422
|
const result = await Promise.race([
|
|
53010
53423
|
Promise.all([
|
|
53011
53424
|
new Response(proc.stdout).text(),
|
|
@@ -53128,7 +53541,7 @@ async function runPipAudit(directory) {
|
|
|
53128
53541
|
stderr: "pipe",
|
|
53129
53542
|
cwd: directory
|
|
53130
53543
|
});
|
|
53131
|
-
const timeoutPromise = new Promise((
|
|
53544
|
+
const timeoutPromise = new Promise((resolve13) => setTimeout(() => resolve13("timeout"), AUDIT_TIMEOUT_MS));
|
|
53132
53545
|
const result = await Promise.race([
|
|
53133
53546
|
Promise.all([
|
|
53134
53547
|
new Response(proc.stdout).text(),
|
|
@@ -53259,7 +53672,7 @@ async function runCargoAudit(directory) {
|
|
|
53259
53672
|
stderr: "pipe",
|
|
53260
53673
|
cwd: directory
|
|
53261
53674
|
});
|
|
53262
|
-
const timeoutPromise = new Promise((
|
|
53675
|
+
const timeoutPromise = new Promise((resolve13) => setTimeout(() => resolve13("timeout"), AUDIT_TIMEOUT_MS));
|
|
53263
53676
|
const result = await Promise.race([
|
|
53264
53677
|
Promise.all([
|
|
53265
53678
|
new Response(proc.stdout).text(),
|
|
@@ -53386,7 +53799,7 @@ async function runGoAudit(directory) {
|
|
|
53386
53799
|
stderr: "pipe",
|
|
53387
53800
|
cwd: directory
|
|
53388
53801
|
});
|
|
53389
|
-
const timeoutPromise = new Promise((
|
|
53802
|
+
const timeoutPromise = new Promise((resolve13) => setTimeout(() => resolve13("timeout"), AUDIT_TIMEOUT_MS));
|
|
53390
53803
|
const result = await Promise.race([
|
|
53391
53804
|
Promise.all([
|
|
53392
53805
|
new Response(proc.stdout).text(),
|
|
@@ -53522,7 +53935,7 @@ async function runDotnetAudit(directory) {
|
|
|
53522
53935
|
stderr: "pipe",
|
|
53523
53936
|
cwd: directory
|
|
53524
53937
|
});
|
|
53525
|
-
const timeoutPromise = new Promise((
|
|
53938
|
+
const timeoutPromise = new Promise((resolve13) => setTimeout(() => resolve13("timeout"), AUDIT_TIMEOUT_MS));
|
|
53526
53939
|
const result = await Promise.race([
|
|
53527
53940
|
Promise.all([
|
|
53528
53941
|
new Response(proc.stdout).text(),
|
|
@@ -53641,7 +54054,7 @@ async function runBundleAudit(directory) {
|
|
|
53641
54054
|
stderr: "pipe",
|
|
53642
54055
|
cwd: directory
|
|
53643
54056
|
});
|
|
53644
|
-
const timeoutPromise = new Promise((
|
|
54057
|
+
const timeoutPromise = new Promise((resolve13) => setTimeout(() => resolve13("timeout"), AUDIT_TIMEOUT_MS));
|
|
53645
54058
|
const result = await Promise.race([
|
|
53646
54059
|
Promise.all([
|
|
53647
54060
|
new Response(proc.stdout).text(),
|
|
@@ -53788,7 +54201,7 @@ async function runDartAudit(directory) {
|
|
|
53788
54201
|
stderr: "pipe",
|
|
53789
54202
|
cwd: directory
|
|
53790
54203
|
});
|
|
53791
|
-
const timeoutPromise = new Promise((
|
|
54204
|
+
const timeoutPromise = new Promise((resolve13) => setTimeout(() => resolve13("timeout"), AUDIT_TIMEOUT_MS));
|
|
53792
54205
|
const result = await Promise.race([
|
|
53793
54206
|
Promise.all([
|
|
53794
54207
|
new Response(proc.stdout).text(),
|
|
@@ -54053,8 +54466,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
54053
54466
|
]);
|
|
54054
54467
|
// src/tools/pre-check-batch.ts
|
|
54055
54468
|
init_dist();
|
|
54056
|
-
import * as
|
|
54057
|
-
import * as
|
|
54469
|
+
import * as fs27 from "fs";
|
|
54470
|
+
import * as path38 from "path";
|
|
54058
54471
|
|
|
54059
54472
|
// node_modules/yocto-queue/index.js
|
|
54060
54473
|
class Node2 {
|
|
@@ -54145,26 +54558,26 @@ function pLimit(concurrency) {
|
|
|
54145
54558
|
activeCount--;
|
|
54146
54559
|
resumeNext();
|
|
54147
54560
|
};
|
|
54148
|
-
const run2 = async (function_,
|
|
54561
|
+
const run2 = async (function_, resolve13, arguments_2) => {
|
|
54149
54562
|
const result = (async () => function_(...arguments_2))();
|
|
54150
|
-
|
|
54563
|
+
resolve13(result);
|
|
54151
54564
|
try {
|
|
54152
54565
|
await result;
|
|
54153
54566
|
} catch {}
|
|
54154
54567
|
next();
|
|
54155
54568
|
};
|
|
54156
|
-
const enqueue = (function_,
|
|
54569
|
+
const enqueue = (function_, resolve13, reject, arguments_2) => {
|
|
54157
54570
|
const queueItem = { reject };
|
|
54158
54571
|
new Promise((internalResolve) => {
|
|
54159
54572
|
queueItem.run = internalResolve;
|
|
54160
54573
|
queue.enqueue(queueItem);
|
|
54161
|
-
}).then(run2.bind(undefined, function_,
|
|
54574
|
+
}).then(run2.bind(undefined, function_, resolve13, arguments_2));
|
|
54162
54575
|
if (activeCount < concurrency) {
|
|
54163
54576
|
resumeNext();
|
|
54164
54577
|
}
|
|
54165
54578
|
};
|
|
54166
|
-
const generator = (function_, ...arguments_2) => new Promise((
|
|
54167
|
-
enqueue(function_,
|
|
54579
|
+
const generator = (function_, ...arguments_2) => new Promise((resolve13, reject) => {
|
|
54580
|
+
enqueue(function_, resolve13, reject, arguments_2);
|
|
54168
54581
|
});
|
|
54169
54582
|
Object.defineProperties(generator, {
|
|
54170
54583
|
activeCount: {
|
|
@@ -54221,8 +54634,8 @@ init_lint();
|
|
|
54221
54634
|
init_manager();
|
|
54222
54635
|
|
|
54223
54636
|
// src/quality/metrics.ts
|
|
54224
|
-
import * as
|
|
54225
|
-
import * as
|
|
54637
|
+
import * as fs25 from "fs";
|
|
54638
|
+
import * as path36 from "path";
|
|
54226
54639
|
var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
|
|
54227
54640
|
var MIN_DUPLICATION_LINES = 10;
|
|
54228
54641
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -54260,11 +54673,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
54260
54673
|
}
|
|
54261
54674
|
function getComplexityForFile2(filePath) {
|
|
54262
54675
|
try {
|
|
54263
|
-
const stat2 =
|
|
54676
|
+
const stat2 = fs25.statSync(filePath);
|
|
54264
54677
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
54265
54678
|
return null;
|
|
54266
54679
|
}
|
|
54267
|
-
const content =
|
|
54680
|
+
const content = fs25.readFileSync(filePath, "utf-8");
|
|
54268
54681
|
return estimateCyclomaticComplexity(content);
|
|
54269
54682
|
} catch {
|
|
54270
54683
|
return null;
|
|
@@ -54274,8 +54687,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
54274
54687
|
let totalComplexity = 0;
|
|
54275
54688
|
const analyzedFiles = [];
|
|
54276
54689
|
for (const file3 of files) {
|
|
54277
|
-
const fullPath =
|
|
54278
|
-
if (!
|
|
54690
|
+
const fullPath = path36.isAbsolute(file3) ? file3 : path36.join(workingDir, file3);
|
|
54691
|
+
if (!fs25.existsSync(fullPath)) {
|
|
54279
54692
|
continue;
|
|
54280
54693
|
}
|
|
54281
54694
|
const complexity = getComplexityForFile2(fullPath);
|
|
@@ -54396,8 +54809,8 @@ function countGoExports(content) {
|
|
|
54396
54809
|
}
|
|
54397
54810
|
function getExportCountForFile(filePath) {
|
|
54398
54811
|
try {
|
|
54399
|
-
const content =
|
|
54400
|
-
const ext =
|
|
54812
|
+
const content = fs25.readFileSync(filePath, "utf-8");
|
|
54813
|
+
const ext = path36.extname(filePath).toLowerCase();
|
|
54401
54814
|
switch (ext) {
|
|
54402
54815
|
case ".ts":
|
|
54403
54816
|
case ".tsx":
|
|
@@ -54423,8 +54836,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
54423
54836
|
let totalExports = 0;
|
|
54424
54837
|
const analyzedFiles = [];
|
|
54425
54838
|
for (const file3 of files) {
|
|
54426
|
-
const fullPath =
|
|
54427
|
-
if (!
|
|
54839
|
+
const fullPath = path36.isAbsolute(file3) ? file3 : path36.join(workingDir, file3);
|
|
54840
|
+
if (!fs25.existsSync(fullPath)) {
|
|
54428
54841
|
continue;
|
|
54429
54842
|
}
|
|
54430
54843
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -54457,16 +54870,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
54457
54870
|
let duplicateLines = 0;
|
|
54458
54871
|
const analyzedFiles = [];
|
|
54459
54872
|
for (const file3 of files) {
|
|
54460
|
-
const fullPath =
|
|
54461
|
-
if (!
|
|
54873
|
+
const fullPath = path36.isAbsolute(file3) ? file3 : path36.join(workingDir, file3);
|
|
54874
|
+
if (!fs25.existsSync(fullPath)) {
|
|
54462
54875
|
continue;
|
|
54463
54876
|
}
|
|
54464
54877
|
try {
|
|
54465
|
-
const stat2 =
|
|
54878
|
+
const stat2 = fs25.statSync(fullPath);
|
|
54466
54879
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
54467
54880
|
continue;
|
|
54468
54881
|
}
|
|
54469
|
-
const content =
|
|
54882
|
+
const content = fs25.readFileSync(fullPath, "utf-8");
|
|
54470
54883
|
const lines = content.split(`
|
|
54471
54884
|
`).filter((line) => line.trim().length > 0);
|
|
54472
54885
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -54490,8 +54903,8 @@ function countCodeLines(content) {
|
|
|
54490
54903
|
return lines.length;
|
|
54491
54904
|
}
|
|
54492
54905
|
function isTestFile(filePath) {
|
|
54493
|
-
const basename8 =
|
|
54494
|
-
const _ext =
|
|
54906
|
+
const basename8 = path36.basename(filePath);
|
|
54907
|
+
const _ext = path36.extname(filePath).toLowerCase();
|
|
54495
54908
|
const testPatterns = [
|
|
54496
54909
|
".test.",
|
|
54497
54910
|
".spec.",
|
|
@@ -54572,8 +54985,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
54572
54985
|
}
|
|
54573
54986
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
54574
54987
|
}
|
|
54575
|
-
function matchesGlobSegment(
|
|
54576
|
-
const normalizedPath =
|
|
54988
|
+
function matchesGlobSegment(path37, glob) {
|
|
54989
|
+
const normalizedPath = path37.replace(/\\/g, "/");
|
|
54577
54990
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
54578
54991
|
if (normalizedPath.includes("//")) {
|
|
54579
54992
|
return false;
|
|
@@ -54604,8 +55017,8 @@ function simpleGlobToRegex(glob) {
|
|
|
54604
55017
|
function hasGlobstar(glob) {
|
|
54605
55018
|
return glob.includes("**");
|
|
54606
55019
|
}
|
|
54607
|
-
function globMatches(
|
|
54608
|
-
const normalizedPath =
|
|
55020
|
+
function globMatches(path37, glob) {
|
|
55021
|
+
const normalizedPath = path37.replace(/\\/g, "/");
|
|
54609
55022
|
if (!glob || glob === "") {
|
|
54610
55023
|
if (normalizedPath.includes("//")) {
|
|
54611
55024
|
return false;
|
|
@@ -54641,31 +55054,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
54641
55054
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
54642
55055
|
let testLines = 0;
|
|
54643
55056
|
let codeLines = 0;
|
|
54644
|
-
const srcDir =
|
|
54645
|
-
if (
|
|
55057
|
+
const srcDir = path36.join(workingDir, "src");
|
|
55058
|
+
if (fs25.existsSync(srcDir)) {
|
|
54646
55059
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
54647
55060
|
codeLines += lines;
|
|
54648
55061
|
});
|
|
54649
55062
|
}
|
|
54650
55063
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
54651
55064
|
for (const dir of possibleSrcDirs) {
|
|
54652
|
-
const dirPath =
|
|
54653
|
-
if (
|
|
55065
|
+
const dirPath = path36.join(workingDir, dir);
|
|
55066
|
+
if (fs25.existsSync(dirPath)) {
|
|
54654
55067
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
54655
55068
|
codeLines += lines;
|
|
54656
55069
|
});
|
|
54657
55070
|
}
|
|
54658
55071
|
}
|
|
54659
|
-
const testsDir =
|
|
54660
|
-
if (
|
|
55072
|
+
const testsDir = path36.join(workingDir, "tests");
|
|
55073
|
+
if (fs25.existsSync(testsDir)) {
|
|
54661
55074
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
54662
55075
|
testLines += lines;
|
|
54663
55076
|
});
|
|
54664
55077
|
}
|
|
54665
55078
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
54666
55079
|
for (const dir of possibleTestDirs) {
|
|
54667
|
-
const dirPath =
|
|
54668
|
-
if (
|
|
55080
|
+
const dirPath = path36.join(workingDir, dir);
|
|
55081
|
+
if (fs25.existsSync(dirPath) && dirPath !== testsDir) {
|
|
54669
55082
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
54670
55083
|
testLines += lines;
|
|
54671
55084
|
});
|
|
@@ -54677,9 +55090,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
54677
55090
|
}
|
|
54678
55091
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
54679
55092
|
try {
|
|
54680
|
-
const entries =
|
|
55093
|
+
const entries = fs25.readdirSync(dirPath, { withFileTypes: true });
|
|
54681
55094
|
for (const entry of entries) {
|
|
54682
|
-
const fullPath =
|
|
55095
|
+
const fullPath = path36.join(dirPath, entry.name);
|
|
54683
55096
|
if (entry.isDirectory()) {
|
|
54684
55097
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
54685
55098
|
continue;
|
|
@@ -54687,7 +55100,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
54687
55100
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
54688
55101
|
} else if (entry.isFile()) {
|
|
54689
55102
|
const relativePath = fullPath.replace(`${process.cwd()}/`, "");
|
|
54690
|
-
const ext =
|
|
55103
|
+
const ext = path36.extname(entry.name).toLowerCase();
|
|
54691
55104
|
const validExts = [
|
|
54692
55105
|
".ts",
|
|
54693
55106
|
".tsx",
|
|
@@ -54723,7 +55136,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
54723
55136
|
continue;
|
|
54724
55137
|
}
|
|
54725
55138
|
try {
|
|
54726
|
-
const content =
|
|
55139
|
+
const content = fs25.readFileSync(fullPath, "utf-8");
|
|
54727
55140
|
const lines = countCodeLines(content);
|
|
54728
55141
|
callback(lines);
|
|
54729
55142
|
} catch {}
|
|
@@ -54937,8 +55350,8 @@ async function qualityBudget(input, directory) {
|
|
|
54937
55350
|
init_dist();
|
|
54938
55351
|
init_manager();
|
|
54939
55352
|
init_detector();
|
|
54940
|
-
import * as
|
|
54941
|
-
import * as
|
|
55353
|
+
import * as fs26 from "fs";
|
|
55354
|
+
import * as path37 from "path";
|
|
54942
55355
|
import { extname as extname9 } from "path";
|
|
54943
55356
|
|
|
54944
55357
|
// src/sast/rules/c.ts
|
|
@@ -55686,7 +56099,7 @@ function mapSemgrepSeverity(severity) {
|
|
|
55686
56099
|
}
|
|
55687
56100
|
}
|
|
55688
56101
|
async function executeWithTimeout(command, args2, options) {
|
|
55689
|
-
return new Promise((
|
|
56102
|
+
return new Promise((resolve13) => {
|
|
55690
56103
|
const child = spawn(command, args2, {
|
|
55691
56104
|
shell: false,
|
|
55692
56105
|
cwd: options.cwd
|
|
@@ -55695,7 +56108,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
55695
56108
|
let stderr = "";
|
|
55696
56109
|
const timeout = setTimeout(() => {
|
|
55697
56110
|
child.kill("SIGTERM");
|
|
55698
|
-
|
|
56111
|
+
resolve13({
|
|
55699
56112
|
stdout,
|
|
55700
56113
|
stderr: "Process timed out",
|
|
55701
56114
|
exitCode: 124
|
|
@@ -55709,7 +56122,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
55709
56122
|
});
|
|
55710
56123
|
child.on("close", (code) => {
|
|
55711
56124
|
clearTimeout(timeout);
|
|
55712
|
-
|
|
56125
|
+
resolve13({
|
|
55713
56126
|
stdout,
|
|
55714
56127
|
stderr,
|
|
55715
56128
|
exitCode: code ?? 0
|
|
@@ -55717,7 +56130,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
55717
56130
|
});
|
|
55718
56131
|
child.on("error", (err2) => {
|
|
55719
56132
|
clearTimeout(timeout);
|
|
55720
|
-
|
|
56133
|
+
resolve13({
|
|
55721
56134
|
stdout,
|
|
55722
56135
|
stderr: err2.message,
|
|
55723
56136
|
exitCode: 1
|
|
@@ -55805,17 +56218,17 @@ var SEVERITY_ORDER = {
|
|
|
55805
56218
|
};
|
|
55806
56219
|
function shouldSkipFile(filePath) {
|
|
55807
56220
|
try {
|
|
55808
|
-
const stats =
|
|
56221
|
+
const stats = fs26.statSync(filePath);
|
|
55809
56222
|
if (stats.size > MAX_FILE_SIZE_BYTES6) {
|
|
55810
56223
|
return { skip: true, reason: "file too large" };
|
|
55811
56224
|
}
|
|
55812
56225
|
if (stats.size === 0) {
|
|
55813
56226
|
return { skip: true, reason: "empty file" };
|
|
55814
56227
|
}
|
|
55815
|
-
const fd =
|
|
56228
|
+
const fd = fs26.openSync(filePath, "r");
|
|
55816
56229
|
const buffer = Buffer.alloc(8192);
|
|
55817
|
-
const bytesRead =
|
|
55818
|
-
|
|
56230
|
+
const bytesRead = fs26.readSync(fd, buffer, 0, 8192, 0);
|
|
56231
|
+
fs26.closeSync(fd);
|
|
55819
56232
|
if (bytesRead > 0) {
|
|
55820
56233
|
let nullCount = 0;
|
|
55821
56234
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -55854,7 +56267,7 @@ function countBySeverity(findings) {
|
|
|
55854
56267
|
}
|
|
55855
56268
|
function scanFileWithTierA(filePath, language) {
|
|
55856
56269
|
try {
|
|
55857
|
-
const content =
|
|
56270
|
+
const content = fs26.readFileSync(filePath, "utf-8");
|
|
55858
56271
|
const findings = executeRulesSync(filePath, content, language);
|
|
55859
56272
|
return findings.map((f) => ({
|
|
55860
56273
|
rule_id: f.rule_id,
|
|
@@ -55901,8 +56314,8 @@ async function sastScan(input, directory, config3) {
|
|
|
55901
56314
|
_filesSkipped++;
|
|
55902
56315
|
continue;
|
|
55903
56316
|
}
|
|
55904
|
-
const resolvedPath =
|
|
55905
|
-
if (!
|
|
56317
|
+
const resolvedPath = path37.isAbsolute(filePath) ? filePath : path37.resolve(directory, filePath);
|
|
56318
|
+
if (!fs26.existsSync(resolvedPath)) {
|
|
55906
56319
|
_filesSkipped++;
|
|
55907
56320
|
continue;
|
|
55908
56321
|
}
|
|
@@ -56100,18 +56513,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
56100
56513
|
let resolved;
|
|
56101
56514
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
56102
56515
|
if (isWinAbs) {
|
|
56103
|
-
resolved =
|
|
56104
|
-
} else if (
|
|
56105
|
-
resolved =
|
|
56516
|
+
resolved = path38.win32.resolve(inputPath);
|
|
56517
|
+
} else if (path38.isAbsolute(inputPath)) {
|
|
56518
|
+
resolved = path38.resolve(inputPath);
|
|
56106
56519
|
} else {
|
|
56107
|
-
resolved =
|
|
56520
|
+
resolved = path38.resolve(baseDir, inputPath);
|
|
56108
56521
|
}
|
|
56109
|
-
const workspaceResolved =
|
|
56522
|
+
const workspaceResolved = path38.resolve(workspaceDir);
|
|
56110
56523
|
let relative4;
|
|
56111
56524
|
if (isWinAbs) {
|
|
56112
|
-
relative4 =
|
|
56525
|
+
relative4 = path38.win32.relative(workspaceResolved, resolved);
|
|
56113
56526
|
} else {
|
|
56114
|
-
relative4 =
|
|
56527
|
+
relative4 = path38.relative(workspaceResolved, resolved);
|
|
56115
56528
|
}
|
|
56116
56529
|
if (relative4.startsWith("..")) {
|
|
56117
56530
|
return "path traversal detected";
|
|
@@ -56172,13 +56585,13 @@ async function runLintWrapped(files, directory, _config) {
|
|
|
56172
56585
|
}
|
|
56173
56586
|
async function runLintOnFiles(linter, files, workspaceDir) {
|
|
56174
56587
|
const isWindows = process.platform === "win32";
|
|
56175
|
-
const binDir =
|
|
56588
|
+
const binDir = path38.join(workspaceDir, "node_modules", ".bin");
|
|
56176
56589
|
const validatedFiles = [];
|
|
56177
56590
|
for (const file3 of files) {
|
|
56178
56591
|
if (typeof file3 !== "string") {
|
|
56179
56592
|
continue;
|
|
56180
56593
|
}
|
|
56181
|
-
const resolvedPath =
|
|
56594
|
+
const resolvedPath = path38.resolve(file3);
|
|
56182
56595
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
56183
56596
|
if (validationError) {
|
|
56184
56597
|
continue;
|
|
@@ -56196,10 +56609,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
56196
56609
|
}
|
|
56197
56610
|
let command;
|
|
56198
56611
|
if (linter === "biome") {
|
|
56199
|
-
const biomeBin = isWindows ?
|
|
56612
|
+
const biomeBin = isWindows ? path38.join(binDir, "biome.EXE") : path38.join(binDir, "biome");
|
|
56200
56613
|
command = [biomeBin, "check", ...validatedFiles];
|
|
56201
56614
|
} else {
|
|
56202
|
-
const eslintBin = isWindows ?
|
|
56615
|
+
const eslintBin = isWindows ? path38.join(binDir, "eslint.cmd") : path38.join(binDir, "eslint");
|
|
56203
56616
|
command = [eslintBin, ...validatedFiles];
|
|
56204
56617
|
}
|
|
56205
56618
|
try {
|
|
@@ -56336,7 +56749,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
56336
56749
|
skippedFiles++;
|
|
56337
56750
|
continue;
|
|
56338
56751
|
}
|
|
56339
|
-
const resolvedPath =
|
|
56752
|
+
const resolvedPath = path38.resolve(file3);
|
|
56340
56753
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
56341
56754
|
if (validationError) {
|
|
56342
56755
|
skippedFiles++;
|
|
@@ -56354,14 +56767,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
56354
56767
|
};
|
|
56355
56768
|
}
|
|
56356
56769
|
for (const file3 of validatedFiles) {
|
|
56357
|
-
const ext =
|
|
56770
|
+
const ext = path38.extname(file3).toLowerCase();
|
|
56358
56771
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
56359
56772
|
skippedFiles++;
|
|
56360
56773
|
continue;
|
|
56361
56774
|
}
|
|
56362
56775
|
let stat2;
|
|
56363
56776
|
try {
|
|
56364
|
-
stat2 =
|
|
56777
|
+
stat2 = fs27.statSync(file3);
|
|
56365
56778
|
} catch {
|
|
56366
56779
|
skippedFiles++;
|
|
56367
56780
|
continue;
|
|
@@ -56372,7 +56785,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
56372
56785
|
}
|
|
56373
56786
|
let content;
|
|
56374
56787
|
try {
|
|
56375
|
-
const buffer =
|
|
56788
|
+
const buffer = fs27.readFileSync(file3);
|
|
56376
56789
|
if (buffer.includes(0)) {
|
|
56377
56790
|
skippedFiles++;
|
|
56378
56791
|
continue;
|
|
@@ -56513,7 +56926,7 @@ async function runPreCheckBatch(input, workspaceDir) {
|
|
|
56513
56926
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
56514
56927
|
continue;
|
|
56515
56928
|
}
|
|
56516
|
-
changedFiles.push(
|
|
56929
|
+
changedFiles.push(path38.resolve(directory, file3));
|
|
56517
56930
|
}
|
|
56518
56931
|
if (changedFiles.length === 0) {
|
|
56519
56932
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -56664,7 +57077,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
56664
57077
|
};
|
|
56665
57078
|
return JSON.stringify(errorResult, null, 2);
|
|
56666
57079
|
}
|
|
56667
|
-
const resolvedDirectory =
|
|
57080
|
+
const resolvedDirectory = path38.resolve(typedArgs.directory);
|
|
56668
57081
|
const workspaceAnchor = resolvedDirectory;
|
|
56669
57082
|
const dirError = validateDirectory3(resolvedDirectory, workspaceAnchor);
|
|
56670
57083
|
if (dirError) {
|
|
@@ -56735,7 +57148,7 @@ var retrieve_summary = tool({
|
|
|
56735
57148
|
init_tool();
|
|
56736
57149
|
init_manager2();
|
|
56737
57150
|
init_create_tool();
|
|
56738
|
-
import * as
|
|
57151
|
+
import * as path39 from "path";
|
|
56739
57152
|
function detectPlaceholderContent(args2) {
|
|
56740
57153
|
const issues = [];
|
|
56741
57154
|
const placeholderPattern = /^\[\w[\w\s]*\]$/;
|
|
@@ -56819,7 +57232,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
56819
57232
|
return {
|
|
56820
57233
|
success: true,
|
|
56821
57234
|
message: "Plan saved successfully",
|
|
56822
|
-
plan_path:
|
|
57235
|
+
plan_path: path39.join(dir, ".swarm", "plan.json"),
|
|
56823
57236
|
phases_count: plan.phases.length,
|
|
56824
57237
|
tasks_count: tasksCount
|
|
56825
57238
|
};
|
|
@@ -56856,8 +57269,8 @@ var save_plan = createSwarmTool({
|
|
|
56856
57269
|
// src/tools/sbom-generate.ts
|
|
56857
57270
|
init_dist();
|
|
56858
57271
|
init_manager();
|
|
56859
|
-
import * as
|
|
56860
|
-
import * as
|
|
57272
|
+
import * as fs28 from "fs";
|
|
57273
|
+
import * as path40 from "path";
|
|
56861
57274
|
|
|
56862
57275
|
// src/sbom/detectors/dart.ts
|
|
56863
57276
|
function parsePubspecLock(content) {
|
|
@@ -57703,9 +58116,9 @@ function findManifestFiles(rootDir) {
|
|
|
57703
58116
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
57704
58117
|
function searchDir(dir) {
|
|
57705
58118
|
try {
|
|
57706
|
-
const entries =
|
|
58119
|
+
const entries = fs28.readdirSync(dir, { withFileTypes: true });
|
|
57707
58120
|
for (const entry of entries) {
|
|
57708
|
-
const fullPath =
|
|
58121
|
+
const fullPath = path40.join(dir, entry.name);
|
|
57709
58122
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
57710
58123
|
continue;
|
|
57711
58124
|
}
|
|
@@ -57715,7 +58128,7 @@ function findManifestFiles(rootDir) {
|
|
|
57715
58128
|
for (const pattern of patterns) {
|
|
57716
58129
|
const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
57717
58130
|
if (new RegExp(regex, "i").test(entry.name)) {
|
|
57718
|
-
manifestFiles.push(
|
|
58131
|
+
manifestFiles.push(path40.relative(cwd, fullPath));
|
|
57719
58132
|
break;
|
|
57720
58133
|
}
|
|
57721
58134
|
}
|
|
@@ -57732,14 +58145,14 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
57732
58145
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
57733
58146
|
for (const dir of directories) {
|
|
57734
58147
|
try {
|
|
57735
|
-
const entries =
|
|
58148
|
+
const entries = fs28.readdirSync(dir, { withFileTypes: true });
|
|
57736
58149
|
for (const entry of entries) {
|
|
57737
|
-
const fullPath =
|
|
58150
|
+
const fullPath = path40.join(dir, entry.name);
|
|
57738
58151
|
if (entry.isFile()) {
|
|
57739
58152
|
for (const pattern of patterns) {
|
|
57740
58153
|
const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
57741
58154
|
if (new RegExp(regex, "i").test(entry.name)) {
|
|
57742
|
-
found.push(
|
|
58155
|
+
found.push(path40.relative(workingDir, fullPath));
|
|
57743
58156
|
break;
|
|
57744
58157
|
}
|
|
57745
58158
|
}
|
|
@@ -57752,11 +58165,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
57752
58165
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
57753
58166
|
const dirs = new Set;
|
|
57754
58167
|
for (const file3 of changedFiles) {
|
|
57755
|
-
let currentDir =
|
|
58168
|
+
let currentDir = path40.dirname(file3);
|
|
57756
58169
|
while (true) {
|
|
57757
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
57758
|
-
dirs.add(
|
|
57759
|
-
const parent =
|
|
58170
|
+
if (currentDir && currentDir !== "." && currentDir !== path40.sep) {
|
|
58171
|
+
dirs.add(path40.join(workingDir, currentDir));
|
|
58172
|
+
const parent = path40.dirname(currentDir);
|
|
57760
58173
|
if (parent === currentDir)
|
|
57761
58174
|
break;
|
|
57762
58175
|
currentDir = parent;
|
|
@@ -57770,7 +58183,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
57770
58183
|
}
|
|
57771
58184
|
function ensureOutputDir(outputDir) {
|
|
57772
58185
|
try {
|
|
57773
|
-
|
|
58186
|
+
fs28.mkdirSync(outputDir, { recursive: true });
|
|
57774
58187
|
} catch (error93) {
|
|
57775
58188
|
if (!error93 || error93.code !== "EEXIST") {
|
|
57776
58189
|
throw error93;
|
|
@@ -57862,11 +58275,11 @@ var sbom_generate = createSwarmTool({
|
|
|
57862
58275
|
const processedFiles = [];
|
|
57863
58276
|
for (const manifestFile of manifestFiles) {
|
|
57864
58277
|
try {
|
|
57865
|
-
const fullPath =
|
|
57866
|
-
if (!
|
|
58278
|
+
const fullPath = path40.isAbsolute(manifestFile) ? manifestFile : path40.join(workingDir, manifestFile);
|
|
58279
|
+
if (!fs28.existsSync(fullPath)) {
|
|
57867
58280
|
continue;
|
|
57868
58281
|
}
|
|
57869
|
-
const content =
|
|
58282
|
+
const content = fs28.readFileSync(fullPath, "utf-8");
|
|
57870
58283
|
const components = detectComponents(manifestFile, content);
|
|
57871
58284
|
processedFiles.push(manifestFile);
|
|
57872
58285
|
if (components.length > 0) {
|
|
@@ -57879,8 +58292,8 @@ var sbom_generate = createSwarmTool({
|
|
|
57879
58292
|
const bom = generateCycloneDX(allComponents);
|
|
57880
58293
|
const bomJson = serializeCycloneDX(bom);
|
|
57881
58294
|
const filename = generateSbomFilename();
|
|
57882
|
-
const outputPath =
|
|
57883
|
-
|
|
58295
|
+
const outputPath = path40.join(outputDir, filename);
|
|
58296
|
+
fs28.writeFileSync(outputPath, bomJson, "utf-8");
|
|
57884
58297
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
57885
58298
|
try {
|
|
57886
58299
|
const timestamp = new Date().toISOString();
|
|
@@ -57922,8 +58335,8 @@ var sbom_generate = createSwarmTool({
|
|
|
57922
58335
|
// src/tools/schema-drift.ts
|
|
57923
58336
|
init_dist();
|
|
57924
58337
|
init_create_tool();
|
|
57925
|
-
import * as
|
|
57926
|
-
import * as
|
|
58338
|
+
import * as fs29 from "fs";
|
|
58339
|
+
import * as path41 from "path";
|
|
57927
58340
|
var SPEC_CANDIDATES = [
|
|
57928
58341
|
"openapi.json",
|
|
57929
58342
|
"openapi.yaml",
|
|
@@ -57955,28 +58368,28 @@ function normalizePath2(p) {
|
|
|
57955
58368
|
}
|
|
57956
58369
|
function discoverSpecFile(cwd, specFileArg) {
|
|
57957
58370
|
if (specFileArg) {
|
|
57958
|
-
const resolvedPath =
|
|
57959
|
-
const normalizedCwd = cwd.endsWith(
|
|
58371
|
+
const resolvedPath = path41.resolve(cwd, specFileArg);
|
|
58372
|
+
const normalizedCwd = cwd.endsWith(path41.sep) ? cwd : cwd + path41.sep;
|
|
57960
58373
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
57961
58374
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
57962
58375
|
}
|
|
57963
|
-
const ext =
|
|
58376
|
+
const ext = path41.extname(resolvedPath).toLowerCase();
|
|
57964
58377
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
57965
58378
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
57966
58379
|
}
|
|
57967
|
-
const stats =
|
|
58380
|
+
const stats = fs29.statSync(resolvedPath);
|
|
57968
58381
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
57969
58382
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
57970
58383
|
}
|
|
57971
|
-
if (!
|
|
58384
|
+
if (!fs29.existsSync(resolvedPath)) {
|
|
57972
58385
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
57973
58386
|
}
|
|
57974
58387
|
return resolvedPath;
|
|
57975
58388
|
}
|
|
57976
58389
|
for (const candidate of SPEC_CANDIDATES) {
|
|
57977
|
-
const candidatePath =
|
|
57978
|
-
if (
|
|
57979
|
-
const stats =
|
|
58390
|
+
const candidatePath = path41.resolve(cwd, candidate);
|
|
58391
|
+
if (fs29.existsSync(candidatePath)) {
|
|
58392
|
+
const stats = fs29.statSync(candidatePath);
|
|
57980
58393
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
57981
58394
|
return candidatePath;
|
|
57982
58395
|
}
|
|
@@ -57985,8 +58398,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
57985
58398
|
return null;
|
|
57986
58399
|
}
|
|
57987
58400
|
function parseSpec(specFile) {
|
|
57988
|
-
const content =
|
|
57989
|
-
const ext =
|
|
58401
|
+
const content = fs29.readFileSync(specFile, "utf-8");
|
|
58402
|
+
const ext = path41.extname(specFile).toLowerCase();
|
|
57990
58403
|
if (ext === ".json") {
|
|
57991
58404
|
return parseJsonSpec(content);
|
|
57992
58405
|
}
|
|
@@ -58052,12 +58465,12 @@ function extractRoutes(cwd) {
|
|
|
58052
58465
|
function walkDir(dir) {
|
|
58053
58466
|
let entries;
|
|
58054
58467
|
try {
|
|
58055
|
-
entries =
|
|
58468
|
+
entries = fs29.readdirSync(dir, { withFileTypes: true });
|
|
58056
58469
|
} catch {
|
|
58057
58470
|
return;
|
|
58058
58471
|
}
|
|
58059
58472
|
for (const entry of entries) {
|
|
58060
|
-
const fullPath =
|
|
58473
|
+
const fullPath = path41.join(dir, entry.name);
|
|
58061
58474
|
if (entry.isSymbolicLink()) {
|
|
58062
58475
|
continue;
|
|
58063
58476
|
}
|
|
@@ -58067,7 +58480,7 @@ function extractRoutes(cwd) {
|
|
|
58067
58480
|
}
|
|
58068
58481
|
walkDir(fullPath);
|
|
58069
58482
|
} else if (entry.isFile()) {
|
|
58070
|
-
const ext =
|
|
58483
|
+
const ext = path41.extname(entry.name).toLowerCase();
|
|
58071
58484
|
const baseName = entry.name.toLowerCase();
|
|
58072
58485
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
58073
58486
|
continue;
|
|
@@ -58085,7 +58498,7 @@ function extractRoutes(cwd) {
|
|
|
58085
58498
|
}
|
|
58086
58499
|
function extractRoutesFromFile(filePath) {
|
|
58087
58500
|
const routes = [];
|
|
58088
|
-
const content =
|
|
58501
|
+
const content = fs29.readFileSync(filePath, "utf-8");
|
|
58089
58502
|
const lines = content.split(/\r?\n/);
|
|
58090
58503
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
58091
58504
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -58236,8 +58649,8 @@ init_secretscan();
|
|
|
58236
58649
|
// src/tools/symbols.ts
|
|
58237
58650
|
init_tool();
|
|
58238
58651
|
init_create_tool();
|
|
58239
|
-
import * as
|
|
58240
|
-
import * as
|
|
58652
|
+
import * as fs30 from "fs";
|
|
58653
|
+
import * as path42 from "path";
|
|
58241
58654
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
58242
58655
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
58243
58656
|
function containsControlCharacters(str) {
|
|
@@ -58266,11 +58679,11 @@ function containsWindowsAttacks(str) {
|
|
|
58266
58679
|
}
|
|
58267
58680
|
function isPathInWorkspace(filePath, workspace) {
|
|
58268
58681
|
try {
|
|
58269
|
-
const resolvedPath =
|
|
58270
|
-
const realWorkspace =
|
|
58271
|
-
const realResolvedPath =
|
|
58272
|
-
const relativePath =
|
|
58273
|
-
if (relativePath.startsWith("..") ||
|
|
58682
|
+
const resolvedPath = path42.resolve(workspace, filePath);
|
|
58683
|
+
const realWorkspace = fs30.realpathSync(workspace);
|
|
58684
|
+
const realResolvedPath = fs30.realpathSync(resolvedPath);
|
|
58685
|
+
const relativePath = path42.relative(realWorkspace, realResolvedPath);
|
|
58686
|
+
if (relativePath.startsWith("..") || path42.isAbsolute(relativePath)) {
|
|
58274
58687
|
return false;
|
|
58275
58688
|
}
|
|
58276
58689
|
return true;
|
|
@@ -58282,17 +58695,17 @@ function validatePathForRead(filePath, workspace) {
|
|
|
58282
58695
|
return isPathInWorkspace(filePath, workspace);
|
|
58283
58696
|
}
|
|
58284
58697
|
function extractTSSymbols(filePath, cwd) {
|
|
58285
|
-
const fullPath =
|
|
58698
|
+
const fullPath = path42.join(cwd, filePath);
|
|
58286
58699
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
58287
58700
|
return [];
|
|
58288
58701
|
}
|
|
58289
58702
|
let content;
|
|
58290
58703
|
try {
|
|
58291
|
-
const stats =
|
|
58704
|
+
const stats = fs30.statSync(fullPath);
|
|
58292
58705
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
58293
58706
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
58294
58707
|
}
|
|
58295
|
-
content =
|
|
58708
|
+
content = fs30.readFileSync(fullPath, "utf-8");
|
|
58296
58709
|
} catch {
|
|
58297
58710
|
return [];
|
|
58298
58711
|
}
|
|
@@ -58434,17 +58847,17 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
58434
58847
|
});
|
|
58435
58848
|
}
|
|
58436
58849
|
function extractPythonSymbols(filePath, cwd) {
|
|
58437
|
-
const fullPath =
|
|
58850
|
+
const fullPath = path42.join(cwd, filePath);
|
|
58438
58851
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
58439
58852
|
return [];
|
|
58440
58853
|
}
|
|
58441
58854
|
let content;
|
|
58442
58855
|
try {
|
|
58443
|
-
const stats =
|
|
58856
|
+
const stats = fs30.statSync(fullPath);
|
|
58444
58857
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
58445
58858
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
58446
58859
|
}
|
|
58447
|
-
content =
|
|
58860
|
+
content = fs30.readFileSync(fullPath, "utf-8");
|
|
58448
58861
|
} catch {
|
|
58449
58862
|
return [];
|
|
58450
58863
|
}
|
|
@@ -58517,7 +58930,7 @@ var symbols = createSwarmTool({
|
|
|
58517
58930
|
}, null, 2);
|
|
58518
58931
|
}
|
|
58519
58932
|
const cwd = directory;
|
|
58520
|
-
const ext =
|
|
58933
|
+
const ext = path42.extname(file3);
|
|
58521
58934
|
if (containsControlCharacters(file3)) {
|
|
58522
58935
|
return JSON.stringify({
|
|
58523
58936
|
file: file3,
|
|
@@ -58584,128 +58997,6 @@ var MAX_FILE_SIZE2 = 5 * 1024 * 1024;
|
|
|
58584
58997
|
// src/tools/index.ts
|
|
58585
58998
|
init_test_runner();
|
|
58586
58999
|
|
|
58587
|
-
// src/tools/update-task-status.ts
|
|
58588
|
-
init_tool();
|
|
58589
|
-
init_manager2();
|
|
58590
|
-
init_create_tool();
|
|
58591
|
-
import * as fs30 from "fs";
|
|
58592
|
-
import * as path42 from "path";
|
|
58593
|
-
var VALID_STATUSES = [
|
|
58594
|
-
"pending",
|
|
58595
|
-
"in_progress",
|
|
58596
|
-
"completed",
|
|
58597
|
-
"blocked"
|
|
58598
|
-
];
|
|
58599
|
-
function validateStatus(status) {
|
|
58600
|
-
if (!VALID_STATUSES.includes(status)) {
|
|
58601
|
-
return `Invalid status "${status}". Must be one of: ${VALID_STATUSES.join(", ")}`;
|
|
58602
|
-
}
|
|
58603
|
-
return;
|
|
58604
|
-
}
|
|
58605
|
-
function validateTaskId(taskId) {
|
|
58606
|
-
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
58607
|
-
if (!taskIdPattern.test(taskId)) {
|
|
58608
|
-
return `Invalid task_id "${taskId}". Must match pattern N.M or N.M.P (e.g., "1.1", "1.2.3")`;
|
|
58609
|
-
}
|
|
58610
|
-
return;
|
|
58611
|
-
}
|
|
58612
|
-
async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
58613
|
-
const statusError = validateStatus(args2.status);
|
|
58614
|
-
if (statusError) {
|
|
58615
|
-
return {
|
|
58616
|
-
success: false,
|
|
58617
|
-
message: "Validation failed",
|
|
58618
|
-
errors: [statusError]
|
|
58619
|
-
};
|
|
58620
|
-
}
|
|
58621
|
-
const taskIdError = validateTaskId(args2.task_id);
|
|
58622
|
-
if (taskIdError) {
|
|
58623
|
-
return {
|
|
58624
|
-
success: false,
|
|
58625
|
-
message: "Validation failed",
|
|
58626
|
-
errors: [taskIdError]
|
|
58627
|
-
};
|
|
58628
|
-
}
|
|
58629
|
-
let normalizedDir;
|
|
58630
|
-
if (args2.working_directory != null) {
|
|
58631
|
-
if (args2.working_directory.includes("\x00")) {
|
|
58632
|
-
return {
|
|
58633
|
-
success: false,
|
|
58634
|
-
message: "Invalid working_directory: null bytes are not allowed"
|
|
58635
|
-
};
|
|
58636
|
-
}
|
|
58637
|
-
if (process.platform === "win32") {
|
|
58638
|
-
const devicePathPattern = /^\\\\|^(NUL|CON|AUX|COM[1-9]|LPT[1-9])(\..*)?$/i;
|
|
58639
|
-
if (devicePathPattern.test(args2.working_directory)) {
|
|
58640
|
-
return {
|
|
58641
|
-
success: false,
|
|
58642
|
-
message: "Invalid working_directory: Windows device paths are not allowed"
|
|
58643
|
-
};
|
|
58644
|
-
}
|
|
58645
|
-
}
|
|
58646
|
-
normalizedDir = path42.normalize(args2.working_directory);
|
|
58647
|
-
const pathParts = normalizedDir.split(path42.sep);
|
|
58648
|
-
if (pathParts.includes("..")) {
|
|
58649
|
-
return {
|
|
58650
|
-
success: false,
|
|
58651
|
-
message: "Invalid working_directory: path traversal sequences (..) are not allowed",
|
|
58652
|
-
errors: [
|
|
58653
|
-
"Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
58654
|
-
]
|
|
58655
|
-
};
|
|
58656
|
-
}
|
|
58657
|
-
const resolvedDir = path42.resolve(normalizedDir);
|
|
58658
|
-
try {
|
|
58659
|
-
const realPath = fs30.realpathSync(resolvedDir);
|
|
58660
|
-
const planPath = path42.join(realPath, ".swarm", "plan.json");
|
|
58661
|
-
if (!fs30.existsSync(planPath)) {
|
|
58662
|
-
return {
|
|
58663
|
-
success: false,
|
|
58664
|
-
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
58665
|
-
errors: [
|
|
58666
|
-
`Invalid working_directory: plan not found in "${realPath}"`
|
|
58667
|
-
]
|
|
58668
|
-
};
|
|
58669
|
-
}
|
|
58670
|
-
} catch {
|
|
58671
|
-
return {
|
|
58672
|
-
success: false,
|
|
58673
|
-
message: `Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`,
|
|
58674
|
-
errors: [
|
|
58675
|
-
`Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`
|
|
58676
|
-
]
|
|
58677
|
-
};
|
|
58678
|
-
}
|
|
58679
|
-
}
|
|
58680
|
-
const directory = normalizedDir ?? fallbackDir ?? process.cwd();
|
|
58681
|
-
try {
|
|
58682
|
-
const updatedPlan = await updateTaskStatus(directory, args2.task_id, args2.status);
|
|
58683
|
-
return {
|
|
58684
|
-
success: true,
|
|
58685
|
-
message: "Task status updated successfully",
|
|
58686
|
-
task_id: args2.task_id,
|
|
58687
|
-
new_status: args2.status,
|
|
58688
|
-
current_phase: updatedPlan.current_phase
|
|
58689
|
-
};
|
|
58690
|
-
} catch (error93) {
|
|
58691
|
-
return {
|
|
58692
|
-
success: false,
|
|
58693
|
-
message: "Failed to update task status",
|
|
58694
|
-
errors: [String(error93)]
|
|
58695
|
-
};
|
|
58696
|
-
}
|
|
58697
|
-
}
|
|
58698
|
-
var update_task_status = createSwarmTool({
|
|
58699
|
-
description: "Update the status of a specific task in the implementation plan. " + "Task status can be one of: pending, in_progress, completed, blocked.",
|
|
58700
|
-
args: {
|
|
58701
|
-
task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, "Task ID must be in N.M or N.M.P format").describe('Task ID in N.M format, e.g. "1.1", "1.2.3"'),
|
|
58702
|
-
status: tool.schema.enum(["pending", "in_progress", "completed", "blocked"]).describe("New status for the task: pending, in_progress, completed, or blocked"),
|
|
58703
|
-
working_directory: tool.schema.string().optional().describe("Working directory where the plan is located")
|
|
58704
|
-
},
|
|
58705
|
-
execute: async (args2, _directory) => {
|
|
58706
|
-
return JSON.stringify(await executeUpdateTaskStatus(args2, _directory), null, 2);
|
|
58707
|
-
}
|
|
58708
|
-
});
|
|
58709
59000
|
// src/tools/todo-extract.ts
|
|
58710
59001
|
init_dist();
|
|
58711
59002
|
init_create_tool();
|
|
@@ -58968,6 +59259,157 @@ var todo_extract = createSwarmTool({
|
|
|
58968
59259
|
return JSON.stringify(result, null, 2);
|
|
58969
59260
|
}
|
|
58970
59261
|
});
|
|
59262
|
+
// src/tools/update-task-status.ts
|
|
59263
|
+
init_tool();
|
|
59264
|
+
init_manager2();
|
|
59265
|
+
import * as fs32 from "fs";
|
|
59266
|
+
import * as path44 from "path";
|
|
59267
|
+
init_create_tool();
|
|
59268
|
+
var VALID_STATUSES = [
|
|
59269
|
+
"pending",
|
|
59270
|
+
"in_progress",
|
|
59271
|
+
"completed",
|
|
59272
|
+
"blocked"
|
|
59273
|
+
];
|
|
59274
|
+
function validateStatus(status) {
|
|
59275
|
+
if (!VALID_STATUSES.includes(status)) {
|
|
59276
|
+
return `Invalid status "${status}". Must be one of: ${VALID_STATUSES.join(", ")}`;
|
|
59277
|
+
}
|
|
59278
|
+
return;
|
|
59279
|
+
}
|
|
59280
|
+
function validateTaskId(taskId) {
|
|
59281
|
+
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
59282
|
+
if (!taskIdPattern.test(taskId)) {
|
|
59283
|
+
return `Invalid task_id "${taskId}". Must match pattern N.M or N.M.P (e.g., "1.1", "1.2.3")`;
|
|
59284
|
+
}
|
|
59285
|
+
return;
|
|
59286
|
+
}
|
|
59287
|
+
function checkReviewerGate(taskId) {
|
|
59288
|
+
try {
|
|
59289
|
+
if (swarmState.agentSessions.size === 0) {
|
|
59290
|
+
return { blocked: false, reason: "" };
|
|
59291
|
+
}
|
|
59292
|
+
for (const [_sessionId, session] of swarmState.agentSessions) {
|
|
59293
|
+
const state = getTaskState(session, taskId);
|
|
59294
|
+
if (state === "tests_run" || state === "complete") {
|
|
59295
|
+
return { blocked: false, reason: "" };
|
|
59296
|
+
}
|
|
59297
|
+
}
|
|
59298
|
+
return {
|
|
59299
|
+
blocked: true,
|
|
59300
|
+
reason: `Task ${taskId} has not passed QA gates (state machine requires tests_run or complete, current state indicates gates not yet passed). Call mega_reviewer and mega_test_engineer before marking task as completed.`
|
|
59301
|
+
};
|
|
59302
|
+
} catch {
|
|
59303
|
+
return { blocked: false, reason: "" };
|
|
59304
|
+
}
|
|
59305
|
+
}
|
|
59306
|
+
async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
59307
|
+
const statusError = validateStatus(args2.status);
|
|
59308
|
+
if (statusError) {
|
|
59309
|
+
return {
|
|
59310
|
+
success: false,
|
|
59311
|
+
message: "Validation failed",
|
|
59312
|
+
errors: [statusError]
|
|
59313
|
+
};
|
|
59314
|
+
}
|
|
59315
|
+
const taskIdError = validateTaskId(args2.task_id);
|
|
59316
|
+
if (taskIdError) {
|
|
59317
|
+
return {
|
|
59318
|
+
success: false,
|
|
59319
|
+
message: "Validation failed",
|
|
59320
|
+
errors: [taskIdError]
|
|
59321
|
+
};
|
|
59322
|
+
}
|
|
59323
|
+
if (args2.status === "completed") {
|
|
59324
|
+
const reviewerCheck = checkReviewerGate(args2.task_id);
|
|
59325
|
+
if (reviewerCheck.blocked) {
|
|
59326
|
+
return {
|
|
59327
|
+
success: false,
|
|
59328
|
+
message: "Gate check failed: reviewer delegation required before marking task as completed",
|
|
59329
|
+
errors: [reviewerCheck.reason]
|
|
59330
|
+
};
|
|
59331
|
+
}
|
|
59332
|
+
}
|
|
59333
|
+
let normalizedDir;
|
|
59334
|
+
if (args2.working_directory != null) {
|
|
59335
|
+
if (args2.working_directory.includes("\x00")) {
|
|
59336
|
+
return {
|
|
59337
|
+
success: false,
|
|
59338
|
+
message: "Invalid working_directory: null bytes are not allowed"
|
|
59339
|
+
};
|
|
59340
|
+
}
|
|
59341
|
+
if (process.platform === "win32") {
|
|
59342
|
+
const devicePathPattern = /^\\\\|^(NUL|CON|AUX|COM[1-9]|LPT[1-9])(\..*)?$/i;
|
|
59343
|
+
if (devicePathPattern.test(args2.working_directory)) {
|
|
59344
|
+
return {
|
|
59345
|
+
success: false,
|
|
59346
|
+
message: "Invalid working_directory: Windows device paths are not allowed"
|
|
59347
|
+
};
|
|
59348
|
+
}
|
|
59349
|
+
}
|
|
59350
|
+
normalizedDir = path44.normalize(args2.working_directory);
|
|
59351
|
+
const pathParts = normalizedDir.split(path44.sep);
|
|
59352
|
+
if (pathParts.includes("..")) {
|
|
59353
|
+
return {
|
|
59354
|
+
success: false,
|
|
59355
|
+
message: "Invalid working_directory: path traversal sequences (..) are not allowed",
|
|
59356
|
+
errors: [
|
|
59357
|
+
"Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
59358
|
+
]
|
|
59359
|
+
};
|
|
59360
|
+
}
|
|
59361
|
+
const resolvedDir = path44.resolve(normalizedDir);
|
|
59362
|
+
try {
|
|
59363
|
+
const realPath = fs32.realpathSync(resolvedDir);
|
|
59364
|
+
const planPath = path44.join(realPath, ".swarm", "plan.json");
|
|
59365
|
+
if (!fs32.existsSync(planPath)) {
|
|
59366
|
+
return {
|
|
59367
|
+
success: false,
|
|
59368
|
+
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
59369
|
+
errors: [
|
|
59370
|
+
`Invalid working_directory: plan not found in "${realPath}"`
|
|
59371
|
+
]
|
|
59372
|
+
};
|
|
59373
|
+
}
|
|
59374
|
+
} catch {
|
|
59375
|
+
return {
|
|
59376
|
+
success: false,
|
|
59377
|
+
message: `Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`,
|
|
59378
|
+
errors: [
|
|
59379
|
+
`Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`
|
|
59380
|
+
]
|
|
59381
|
+
};
|
|
59382
|
+
}
|
|
59383
|
+
}
|
|
59384
|
+
const directory = normalizedDir ?? fallbackDir ?? process.cwd();
|
|
59385
|
+
try {
|
|
59386
|
+
const updatedPlan = await updateTaskStatus(directory, args2.task_id, args2.status);
|
|
59387
|
+
return {
|
|
59388
|
+
success: true,
|
|
59389
|
+
message: "Task status updated successfully",
|
|
59390
|
+
task_id: args2.task_id,
|
|
59391
|
+
new_status: args2.status,
|
|
59392
|
+
current_phase: updatedPlan.current_phase
|
|
59393
|
+
};
|
|
59394
|
+
} catch (error93) {
|
|
59395
|
+
return {
|
|
59396
|
+
success: false,
|
|
59397
|
+
message: "Failed to update task status",
|
|
59398
|
+
errors: [String(error93)]
|
|
59399
|
+
};
|
|
59400
|
+
}
|
|
59401
|
+
}
|
|
59402
|
+
var update_task_status = createSwarmTool({
|
|
59403
|
+
description: "Update the status of a specific task in the implementation plan. " + "Task status can be one of: pending, in_progress, completed, blocked.",
|
|
59404
|
+
args: {
|
|
59405
|
+
task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, "Task ID must be in N.M or N.M.P format").describe('Task ID in N.M format, e.g. "1.1", "1.2.3"'),
|
|
59406
|
+
status: tool.schema.enum(["pending", "in_progress", "completed", "blocked"]).describe("New status for the task: pending, in_progress, completed, or blocked"),
|
|
59407
|
+
working_directory: tool.schema.string().optional().describe("Working directory where the plan is located")
|
|
59408
|
+
},
|
|
59409
|
+
execute: async (args2, _directory) => {
|
|
59410
|
+
return JSON.stringify(await executeUpdateTaskStatus(args2, _directory), null, 2);
|
|
59411
|
+
}
|
|
59412
|
+
});
|
|
58971
59413
|
// src/index.ts
|
|
58972
59414
|
init_utils();
|
|
58973
59415
|
|
|
@@ -59051,7 +59493,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
59051
59493
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
59052
59494
|
preflightTriggerManager = new PTM(automationConfig);
|
|
59053
59495
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
59054
|
-
const swarmDir =
|
|
59496
|
+
const swarmDir = path45.resolve(ctx.directory, ".swarm");
|
|
59055
59497
|
statusArtifact = new ASA(swarmDir);
|
|
59056
59498
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
59057
59499
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -59165,7 +59607,8 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
59165
59607
|
test_runner,
|
|
59166
59608
|
todo_extract,
|
|
59167
59609
|
update_task_status,
|
|
59168
|
-
write_retro
|
|
59610
|
+
write_retro,
|
|
59611
|
+
declare_scope
|
|
59169
59612
|
},
|
|
59170
59613
|
config: async (opencodeConfig) => {
|
|
59171
59614
|
if (!opencodeConfig.agent) {
|