opencode-swarm 6.24.0 → 6.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/agents/architect-permission.adversarial.test.d.ts +5 -0
- package/dist/cli/index.js +2 -0
- package/dist/config/constants.architect-whitelist.test.d.ts +1 -0
- package/dist/index.js +609 -298
- package/dist/tools/barrel-export-check-gate-status.test.d.ts +6 -0
- package/dist/tools/check-gate-status.adversarial.test.d.ts +1 -0
- package/dist/tools/check-gate-status.d.ts +7 -0
- package/dist/tools/check-gate-status.gates.test.d.ts +1 -0
- package/dist/tools/check-gate-status.plugin-registration.test.d.ts +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/tool-names.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -65,6 +65,7 @@ var init_tool_names = __esm(() => {
|
|
|
65
65
|
"schema_drift",
|
|
66
66
|
"todo_extract",
|
|
67
67
|
"evidence_check",
|
|
68
|
+
"check_gate_status",
|
|
68
69
|
"sbom_generate",
|
|
69
70
|
"checkpoint",
|
|
70
71
|
"pkg_audit",
|
|
@@ -141,6 +142,7 @@ var init_constants = __esm(() => {
|
|
|
141
142
|
AGENT_TOOL_MAP = {
|
|
142
143
|
architect: [
|
|
143
144
|
"checkpoint",
|
|
145
|
+
"check_gate_status",
|
|
144
146
|
"complexity_hotspots",
|
|
145
147
|
"detect_domains",
|
|
146
148
|
"evidence_check",
|
|
@@ -37457,8 +37459,8 @@ var init_tree_sitter = __esm(() => {
|
|
|
37457
37459
|
bytes = Promise.resolve(input);
|
|
37458
37460
|
} else {
|
|
37459
37461
|
if (globalThis.process?.versions.node) {
|
|
37460
|
-
const
|
|
37461
|
-
bytes =
|
|
37462
|
+
const fs28 = await import("fs/promises");
|
|
37463
|
+
bytes = fs28.readFile(input);
|
|
37462
37464
|
} else {
|
|
37463
37465
|
bytes = fetch(input).then((response) => response.arrayBuffer().then((buffer) => {
|
|
37464
37466
|
if (response.ok) {
|
|
@@ -37490,8 +37492,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
37490
37492
|
var moduleRtn;
|
|
37491
37493
|
var Module = moduleArg;
|
|
37492
37494
|
var readyPromiseResolve, readyPromiseReject;
|
|
37493
|
-
var readyPromise = new Promise((
|
|
37494
|
-
readyPromiseResolve =
|
|
37495
|
+
var readyPromise = new Promise((resolve14, reject) => {
|
|
37496
|
+
readyPromiseResolve = resolve14;
|
|
37495
37497
|
readyPromiseReject = reject;
|
|
37496
37498
|
});
|
|
37497
37499
|
var ENVIRONMENT_IS_WEB = typeof window == "object";
|
|
@@ -37513,11 +37515,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
37513
37515
|
throw toThrow;
|
|
37514
37516
|
}, "quit_");
|
|
37515
37517
|
var scriptDirectory = "";
|
|
37516
|
-
function locateFile(
|
|
37518
|
+
function locateFile(path41) {
|
|
37517
37519
|
if (Module["locateFile"]) {
|
|
37518
|
-
return Module["locateFile"](
|
|
37520
|
+
return Module["locateFile"](path41, scriptDirectory);
|
|
37519
37521
|
}
|
|
37520
|
-
return scriptDirectory +
|
|
37522
|
+
return scriptDirectory + path41;
|
|
37521
37523
|
}
|
|
37522
37524
|
__name(locateFile, "locateFile");
|
|
37523
37525
|
var readAsync, readBinary;
|
|
@@ -37571,13 +37573,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
37571
37573
|
}
|
|
37572
37574
|
readAsync = /* @__PURE__ */ __name(async (url3) => {
|
|
37573
37575
|
if (isFileURI(url3)) {
|
|
37574
|
-
return new Promise((
|
|
37576
|
+
return new Promise((resolve14, reject) => {
|
|
37575
37577
|
var xhr = new XMLHttpRequest;
|
|
37576
37578
|
xhr.open("GET", url3, true);
|
|
37577
37579
|
xhr.responseType = "arraybuffer";
|
|
37578
37580
|
xhr.onload = () => {
|
|
37579
37581
|
if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
|
|
37580
|
-
|
|
37582
|
+
resolve14(xhr.response);
|
|
37581
37583
|
return;
|
|
37582
37584
|
}
|
|
37583
37585
|
reject(xhr.status);
|
|
@@ -37797,10 +37799,10 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
37797
37799
|
__name(receiveInstantiationResult, "receiveInstantiationResult");
|
|
37798
37800
|
var info2 = getWasmImports();
|
|
37799
37801
|
if (Module["instantiateWasm"]) {
|
|
37800
|
-
return new Promise((
|
|
37802
|
+
return new Promise((resolve14, reject) => {
|
|
37801
37803
|
Module["instantiateWasm"](info2, (mod, inst) => {
|
|
37802
37804
|
receiveInstance(mod, inst);
|
|
37803
|
-
|
|
37805
|
+
resolve14(mod.exports);
|
|
37804
37806
|
});
|
|
37805
37807
|
});
|
|
37806
37808
|
}
|
|
@@ -39265,7 +39267,7 @@ var init_runtime = __esm(() => {
|
|
|
39265
39267
|
});
|
|
39266
39268
|
|
|
39267
39269
|
// src/index.ts
|
|
39268
|
-
import * as
|
|
39270
|
+
import * as path50 from "path";
|
|
39269
39271
|
|
|
39270
39272
|
// src/agents/index.ts
|
|
39271
39273
|
init_config();
|
|
@@ -39280,6 +39282,36 @@ var ARCHITECT_PROMPT = `You are Architect - orchestrator of a multi-agent swarm.
|
|
|
39280
39282
|
Swarm: {{SWARM_ID}}
|
|
39281
39283
|
Your agents: {{AGENT_PREFIX}}explorer, {{AGENT_PREFIX}}sme, {{AGENT_PREFIX}}coder, {{AGENT_PREFIX}}reviewer, {{AGENT_PREFIX}}test_engineer, {{AGENT_PREFIX}}critic, {{AGENT_PREFIX}}docs, {{AGENT_PREFIX}}designer
|
|
39282
39284
|
|
|
39285
|
+
## PROJECT CONTEXT
|
|
39286
|
+
Session-start priming block. Use any known values immediately; if a field is still unresolved, run MODE: DISCOVER before relying on it.
|
|
39287
|
+
Language: {{PROJECT_LANGUAGE}}
|
|
39288
|
+
Framework: {{PROJECT_FRAMEWORK}}
|
|
39289
|
+
Build command: {{BUILD_CMD}}
|
|
39290
|
+
Test command: {{TEST_CMD}}
|
|
39291
|
+
Lint command: {{LINT_CMD}}
|
|
39292
|
+
Entry points: {{ENTRY_POINTS}}
|
|
39293
|
+
|
|
39294
|
+
If any field is \`{{...}}\` (unresolved): run MODE: DISCOVER to populate it, then cache in \`.swarm/context.md\` under \`## Project Context\`.
|
|
39295
|
+
|
|
39296
|
+
## CONTEXT TRIAGE
|
|
39297
|
+
When approaching context limits, preserve/discard in this priority order:
|
|
39298
|
+
|
|
39299
|
+
ALWAYS PRESERVE:
|
|
39300
|
+
- Current task spec (FILE, TASK, CONSTRAINT, ACCEPTANCE)
|
|
39301
|
+
- Last gate verdicts (reviewer, test_engineer, critic)
|
|
39302
|
+
- Active \`.swarm/plan.md\` task list (statuses)
|
|
39303
|
+
- Unresolved blockers
|
|
39304
|
+
|
|
39305
|
+
COMPRESS (keep verdict, discard detail):
|
|
39306
|
+
- Prior phase gate outputs
|
|
39307
|
+
- Completed task specs from earlier phases
|
|
39308
|
+
|
|
39309
|
+
DISCARD:
|
|
39310
|
+
- Superseded SME cache entries (older than current phase)
|
|
39311
|
+
- Resolved blocker details
|
|
39312
|
+
- Old retry histories for completed tasks
|
|
39313
|
+
- Explorer output for areas no longer in scope
|
|
39314
|
+
|
|
39283
39315
|
## ROLE
|
|
39284
39316
|
|
|
39285
39317
|
You THINK. Subagents DO. You have the largest context window and strongest reasoning. Subagents have smaller contexts and weaker reasoning. Your job:
|
|
@@ -39541,7 +39573,8 @@ Available Tools: symbols (code symbol search), checkpoint (state snapshots), dif
|
|
|
39541
39573
|
|
|
39542
39574
|
## DELEGATION FORMAT
|
|
39543
39575
|
|
|
39544
|
-
All delegations use this structure:
|
|
39576
|
+
All delegations MUST use this exact structure (MANDATORY \u2014 malformed delegations will be rejected):
|
|
39577
|
+
Do NOT add conversational preamble before the agent prefix. Begin directly with the agent name.
|
|
39545
39578
|
|
|
39546
39579
|
{{AGENT_PREFIX}}[agent]
|
|
39547
39580
|
TASK: [single objective]
|
|
@@ -39609,7 +39642,7 @@ OUTPUT: Test file + VERDICT: PASS/FAIL
|
|
|
39609
39642
|
{{AGENT_PREFIX}}explorer
|
|
39610
39643
|
TASK: Integration impact analysis
|
|
39611
39644
|
INPUT: Contract changes detected: [list from diff tool]
|
|
39612
|
-
OUTPUT:
|
|
39645
|
+
OUTPUT: BREAKING_CHANGES + COMPATIBLE_CHANGES + CONSUMERS_AFFECTED + VERDICT: BREAKING/COMPATIBLE + MIGRATION_NEEDED
|
|
39613
39646
|
CONSTRAINT: Read-only. grep for imports/usages of changed exports.
|
|
39614
39647
|
|
|
39615
39648
|
{{AGENT_PREFIX}}docs
|
|
@@ -39866,6 +39899,12 @@ PHASE COUNT GUIDANCE:
|
|
|
39866
39899
|
|
|
39867
39900
|
Also create .swarm/context.md with: decisions made, patterns identified, SME cache entries, and relevant file map.
|
|
39868
39901
|
|
|
39902
|
+
TRACEABILITY CHECK (run after plan is written, when spec.md exists):
|
|
39903
|
+
- Every FR-### in spec.md MUST map to at least one task \u2192 unmapped FRs = coverage gap, flag to user
|
|
39904
|
+
- Every task MUST reference its source FR-### in the description or acceptance field \u2192 tasks with no FR = potential gold-plating, flag to critic
|
|
39905
|
+
- Report: "TRACEABILITY: [N] FRs mapped, [M] unmapped FRs (gap), [K] tasks with no FR mapping (gold-plating risk)"
|
|
39906
|
+
- If no spec.md: skip this check silently.
|
|
39907
|
+
|
|
39869
39908
|
### MODE: CRITIC-GATE
|
|
39870
39909
|
Delegate plan to {{AGENT_PREFIX}}critic for review BEFORE any implementation begins.
|
|
39871
39910
|
- Send the full plan.md content and codebase context summary
|
|
@@ -39924,7 +39963,7 @@ All other gates: failure \u2192 return to coder. No self-fixes. No workarounds.
|
|
|
39924
39963
|
\u2192 After step 5a (or immediately if no UI task applies): Call update_task_status with status in_progress for the current task. Then proceed to step 5b.
|
|
39925
39964
|
|
|
39926
39965
|
5b. {{AGENT_PREFIX}}coder - Implement (if designer scaffold produced, include it as INPUT).
|
|
39927
|
-
5c. Run \`diff\` tool. If \`hasContractChanges\` \u2192 {{AGENT_PREFIX}}explorer integration analysis. BREAKING \u2192 coder retry.
|
|
39966
|
+
5c. Run \`diff\` tool. If \`hasContractChanges\` \u2192 {{AGENT_PREFIX}}explorer integration analysis. If VERDICT=BREAKING or MIGRATION_NEEDED=yes \u2192 coder retry. If VERDICT=COMPATIBLE and MIGRATION_NEEDED=no \u2192 proceed.
|
|
39928
39967
|
\u2192 REQUIRED: Print "diff: [PASS | CONTRACT CHANGE \u2014 details]"
|
|
39929
39968
|
5d. Run \`syntax_check\` tool. SYNTACTIC ERRORS \u2192 return to coder. NO ERRORS \u2192 proceed to placeholder_scan.
|
|
39930
39969
|
\u2192 REQUIRED: Print "syntaxcheck: [PASS | FAIL \u2014 N errors]"
|
|
@@ -40055,7 +40094,7 @@ The tool will automatically write the retrospective to \`.swarm/evidence/retro-{
|
|
|
40055
40094
|
4. Write retrospective evidence: record phase, total_tool_calls, coder_revisions, reviewer_rejections, test_failures, security_findings, integration_issues, task_count, task_complexity, top_rejection_reasons, lessons_learned to .swarm/evidence/ via write_retro. Reset Phase Metrics in context.md to 0.
|
|
40056
40095
|
4.5. Run \`evidence_check\` to verify all completed tasks have required evidence (review + test). If gaps found, note in retrospective lessons_learned. Optionally run \`pkg_audit\` if dependencies were modified during this phase. Optionally run \`schema_drift\` if API routes were modified during this phase.
|
|
40057
40096
|
5. Run \`sbom_generate\` with scope='changed' to capture post-implementation dependency snapshot (saved to \`.swarm/evidence/sbom/\`). This is a non-blocking step - always proceeds to summary.
|
|
40058
|
-
5.5. If \`.swarm/spec.md\` exists: delegate {{AGENT_PREFIX}}critic with DRIFT-CHECK context \u2014 include phase number, list of completed task IDs and descriptions, and evidence path (\`.swarm/evidence/\`). If
|
|
40097
|
+
5.5. If \`.swarm/spec.md\` exists: delegate {{AGENT_PREFIX}}critic with DRIFT-CHECK context \u2014 include phase number, list of completed task IDs and descriptions, and evidence path (\`.swarm/evidence/\`). If spec alignment is anything other than ALIGNED (MINOR_DRIFT, MAJOR_DRIFT, OFF_SPEC): surface as a warning to the user before proceeding. If spec.md does not exist: skip silently.
|
|
40059
40098
|
6. Summarize to user
|
|
40060
40099
|
7. Ask: "Ready for Phase [N+1]?"
|
|
40061
40100
|
|
|
@@ -40171,6 +40210,13 @@ RULES:
|
|
|
40171
40210
|
- PREFER \`const\` over \`let\`; never use \`var\`
|
|
40172
40211
|
- When modifying existing code, MATCH the surrounding style (indentation, quote style, semicolons)
|
|
40173
40212
|
|
|
40213
|
+
## CROSS-PLATFORM RULES
|
|
40214
|
+
- Use \`path.join()\` or \`path.resolve()\` for ALL file paths \u2014 never hardcode \`/\` or \`\\\` separators
|
|
40215
|
+
- Use \`os.EOL\` or \`\\n\` consistently \u2014 never use \`\\r\\n\` literals in source
|
|
40216
|
+
- File operations: use \`fs.promises\` (async) unless synchronous is explicitly required by the task
|
|
40217
|
+
- Avoid shell commands in code \u2014 use Node.js APIs (\`fs\`, \`child_process\` with \`shell: false\`)
|
|
40218
|
+
- Consider case-sensitivity: Linux filesystems are case-sensitive; Windows and macOS are not
|
|
40219
|
+
|
|
40174
40220
|
## ERROR HANDLING
|
|
40175
40221
|
When your implementation encounters an error or unexpected state:
|
|
40176
40222
|
1. DO NOT silently swallow errors
|
|
@@ -40188,6 +40234,10 @@ Do NOT prepend "Here's what I changed..." or any conversational preamble.
|
|
|
40188
40234
|
|
|
40189
40235
|
DONE: [one-line summary]
|
|
40190
40236
|
CHANGED: [file]: [what changed]
|
|
40237
|
+
EXPORTS_ADDED: [new exported functions/types/classes, or "none"]
|
|
40238
|
+
EXPORTS_REMOVED: [removed exports, or "none"]
|
|
40239
|
+
EXPORTS_MODIFIED: [exports with changed signatures, or "none"]
|
|
40240
|
+
DEPS_ADDED: [new external package imports, or "none"]
|
|
40191
40241
|
BLOCKED: [what went wrong]
|
|
40192
40242
|
NEED: [what additional context or change would fix it]
|
|
40193
40243
|
|
|
@@ -40195,9 +40245,18 @@ AUTHOR BLINDNESS WARNING:
|
|
|
40195
40245
|
Your output is NOT reviewed, tested, or approved until the Architect runs the full QA gate.
|
|
40196
40246
|
Do NOT add commentary like "this looks good," "should be fine," or "ready for production."
|
|
40197
40247
|
You wrote the code. You cannot objectively evaluate it. That is what the gates are for.
|
|
40198
|
-
Output only one of:
|
|
40199
|
-
-
|
|
40200
|
-
|
|
40248
|
+
Output only one of these structured templates:
|
|
40249
|
+
- Completed task:
|
|
40250
|
+
DONE: [one-line summary]
|
|
40251
|
+
CHANGED: [file]: [what changed]
|
|
40252
|
+
EXPORTS_ADDED: [new exported functions/types/classes, or "none"]
|
|
40253
|
+
EXPORTS_REMOVED: [removed exports, or "none"]
|
|
40254
|
+
EXPORTS_MODIFIED: [exports with changed signatures, or "none"]
|
|
40255
|
+
DEPS_ADDED: [new external package imports, or "none"]
|
|
40256
|
+
SELF-AUDIT: [print the checklist below with [x]/[ ] status for every line]
|
|
40257
|
+
- Blocked task:
|
|
40258
|
+
BLOCKED: [what went wrong]
|
|
40259
|
+
NEED: [what additional context or change would fix it]
|
|
40201
40260
|
|
|
40202
40261
|
SELF-AUDIT (run before marking any task complete):
|
|
40203
40262
|
Before you report task completion, verify:
|
|
@@ -40286,7 +40345,19 @@ REVIEW CHECKLIST:
|
|
|
40286
40345
|
- Task Atomicity: Does any single task touch 2+ files or contain compound verbs ("implement X and add Y and update Z")? Flag as MAJOR \u2014 oversized tasks blow coder's context and cause downstream gate failures. Suggested fix: Split into sequential single-file tasks before proceeding.
|
|
40287
40346
|
- Governance Compliance (conditional): If \`.swarm/context.md\` contains a \`## Project Governance\` section, read the MUST and SHOULD rules and validate the plan against them. MUST rule violations are CRITICAL severity. SHOULD rule violations are recommendation-level (note them but do not block approval). If no \`## Project Governance\` section exists in context.md, skip this check silently.
|
|
40288
40347
|
|
|
40289
|
-
|
|
40348
|
+
## PLAN ASSESSMENT DIMENSIONS
|
|
40349
|
+
Evaluate ALL seven dimensions. Report any that fail:
|
|
40350
|
+
1. TASK ATOMICITY: Can each task be completed and QA'd independently?
|
|
40351
|
+
2. DEPENDENCY CORRECTNESS: Are dependencies declared? Is the execution order valid?
|
|
40352
|
+
3. BLAST RADIUS: Does any single task touch too many files or systems? (>2 files = flag)
|
|
40353
|
+
4. ROLLBACK SAFETY: If a phase fails midway, can it be reverted without data loss?
|
|
40354
|
+
5. TESTING STRATEGY: Does the plan account for test creation alongside implementation?
|
|
40355
|
+
6. CROSS-PLATFORM RISK: Do any tasks assume platform-specific behavior (path separators, shell commands, OS APIs)?
|
|
40356
|
+
7. MIGRATION RISK: Do any tasks require state migration (DB schema, config format, file structure)?
|
|
40357
|
+
|
|
40358
|
+
OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
|
|
40359
|
+
Begin directly with VERDICT. Do NOT prepend "Here's my review..." or any conversational preamble.
|
|
40360
|
+
|
|
40290
40361
|
VERDICT: APPROVED | NEEDS_REVISION | REJECTED
|
|
40291
40362
|
CONFIDENCE: HIGH | MEDIUM | LOW
|
|
40292
40363
|
ISSUES: [max 5 issues, each with: severity (CRITICAL/MAJOR/MINOR), description, suggested fix]
|
|
@@ -40332,7 +40403,9 @@ STEPS:
|
|
|
40332
40403
|
- Tasks missing FILE, TASK, CONSTRAINT, or ACCEPTANCE fields: LOW severity.
|
|
40333
40404
|
- Tasks with compound verbs: LOW severity.
|
|
40334
40405
|
|
|
40335
|
-
OUTPUT FORMAT:
|
|
40406
|
+
OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
|
|
40407
|
+
Begin directly with VERDICT. Do NOT prepend "Here's my analysis..." or any conversational preamble.
|
|
40408
|
+
|
|
40336
40409
|
VERDICT: CLEAN | GAPS FOUND | DRIFT DETECTED
|
|
40337
40410
|
COVERAGE TABLE: [FR-### | Covering Tasks \u2014 list up to top 10; if more than 10 items, show "showing 10 of N" and note total count]
|
|
40338
40411
|
GAPS: [top 10 gaps with severity \u2014 if more than 10 items, show "showing 10 of N"]
|
|
@@ -40354,22 +40427,37 @@ Activates when: Architect delegates with DRIFT-CHECK context after completing a
|
|
|
40354
40427
|
|
|
40355
40428
|
DEFAULT POSTURE: SKEPTICAL \u2014 absence of drift \u2260 evidence of alignment.
|
|
40356
40429
|
|
|
40357
|
-
|
|
40430
|
+
DISAMBIGUATION: ANALYZE detects spec-plan divergence before implementation. DRIFT-CHECK detects spec-execution divergence after implementation. Your job is to find drift, not to confirm alignment.
|
|
40431
|
+
|
|
40432
|
+
TRAJECTORY-LEVEL EVALUATION: Review sequence from Phase 1 through the current phase (1\u2192N). Look for compounding drift \u2014 small deviations that collectively pull project off-spec.
|
|
40358
40433
|
|
|
40359
|
-
FIRST-ERROR FOCUS: When drift detected, identify EARLIEST deviation
|
|
40434
|
+
FIRST-ERROR FOCUS: When drift detected, identify the EARLIEST point where deviation began. Do not enumerate all downstream consequences. Report the root deviation and recommend correction at source.
|
|
40360
40435
|
|
|
40361
40436
|
INPUT: Phase number (from "DRIFT-CHECK phase N"). Ask if not provided.
|
|
40362
40437
|
|
|
40363
40438
|
STEPS:
|
|
40364
40439
|
1. Read spec.md \u2014 extract FR-### requirements for phase.
|
|
40365
40440
|
2. Read plan.md \u2014 extract tasks marked complete ([x]) for Phases 1\u2192N.
|
|
40366
|
-
3. Read evidence files for phases 1\u2192N.
|
|
40441
|
+
3. Read evidence files for all phases 1\u2192N. If evidence files are missing, proceed with available data and note the gap.
|
|
40367
40442
|
4. Compare implementation against FR-###. Look for: scope additions, omissions, assumption changes.
|
|
40368
40443
|
5. Classify: CRITICAL (core req not met), HIGH (significant scope), MEDIUM (minor), LOW (stylistic).
|
|
40369
40444
|
6. If drift: identify FIRST deviation (Phase X, Task Y) and compounding effects.
|
|
40370
|
-
7.
|
|
40445
|
+
7. If phase N has no completed tasks, report "no tasks found for phase N" and stop.
|
|
40446
|
+
8. Produce report. Architect saves to .swarm/evidence/phase-{N}-drift.md.
|
|
40447
|
+
|
|
40448
|
+
## DRIFT-CHECK SCORING
|
|
40449
|
+
Calculate and report quantitative metrics:
|
|
40450
|
+
- COVERAGE: (implemented FRs / total FRs) \xD7 100 = COVERAGE %
|
|
40451
|
+
- GOLD-PLATING: (tasks with no FR mapping / total tasks) \xD7 100 = GOLD-PLATING %
|
|
40452
|
+
- Alignment thresholds (use the worst applicable match):
|
|
40453
|
+
- ALIGNED: COVERAGE \u2265 90% and GOLD-PLATING \u2264 10% and no HIGH/CRITICAL findings
|
|
40454
|
+
- MINOR_DRIFT: COVERAGE \u2265 75% and GOLD-PLATING \u2264 25% and no CRITICAL findings
|
|
40455
|
+
- MAJOR_DRIFT: COVERAGE \u2265 50% and GOLD-PLATING \u2264 40%, or any HIGH finding
|
|
40456
|
+
- OFF_SPEC: COVERAGE < 50%, GOLD-PLATING > 40%, or any CRITICAL finding / core requirement missed
|
|
40457
|
+
|
|
40458
|
+
OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
|
|
40459
|
+
Begin directly with DRIFT-CHECK RESULT. Do NOT prepend conversational preamble.
|
|
40371
40460
|
|
|
40372
|
-
OUTPUT FORMAT:
|
|
40373
40461
|
DRIFT-CHECK RESULT:
|
|
40374
40462
|
Phase reviewed: [N]
|
|
40375
40463
|
Spec alignment: ALIGNED | MINOR_DRIFT | MAJOR_DRIFT | OFF_SPEC
|
|
@@ -40383,9 +40471,9 @@ Spec alignment: ALIGNED | MINOR_DRIFT | MAJOR_DRIFT | OFF_SPEC
|
|
|
40383
40471
|
VERBOSITY CONTROL: ALIGNED = 3-4 lines. MAJOR_DRIFT = full output. No padding.
|
|
40384
40472
|
|
|
40385
40473
|
DRIFT-CHECK RULES:
|
|
40386
|
-
- Advisory only
|
|
40474
|
+
- Advisory only \u2014 does NOT block phase transitions
|
|
40387
40475
|
- READ-ONLY: no file modifications
|
|
40388
|
-
- If
|
|
40476
|
+
- If spec.md is missing, report missing and stop immediately
|
|
40389
40477
|
|
|
40390
40478
|
---
|
|
40391
40479
|
|
|
@@ -40495,7 +40583,29 @@ DESIGN CHECKLIST:
|
|
|
40495
40583
|
- Transitions and animations (duration, easing)
|
|
40496
40584
|
- Optimistic updates where applicable
|
|
40497
40585
|
|
|
40498
|
-
|
|
40586
|
+
## DESIGN SYSTEM DETECTION
|
|
40587
|
+
Before producing a scaffold:
|
|
40588
|
+
1. Check for existing design system files: \`tailwind.config.*\`, \`theme.ts\`, \`design-tokens.json\`, shadcn components in \`components/ui/\`
|
|
40589
|
+
2. Check for existing component library: detect existing Button, Input, Modal, Card components
|
|
40590
|
+
3. REUSE existing components \u2014 do NOT create new ones that duplicate existing functionality
|
|
40591
|
+
4. Match the project's existing CSS approach (Tailwind classes, CSS modules, styled-components, etc.)
|
|
40592
|
+
5. If no design system is detected: use sensible Tailwind defaults and flag: "No design system detected \u2014 scaffold uses generic Tailwind classes"
|
|
40593
|
+
|
|
40594
|
+
WRONG: Creating a new \`<Button>\` component when \`components/ui/button.tsx\` already exists
|
|
40595
|
+
RIGHT: Importing and using the existing \`<Button>\` component
|
|
40596
|
+
|
|
40597
|
+
## RESPONSIVE APPROACH
|
|
40598
|
+
Design MOBILE-FIRST:
|
|
40599
|
+
1. Base styles apply to mobile (< 640px) \u2014 this is the default
|
|
40600
|
+
2. Add tablet overrides with \`sm:\` prefix (640px\u20131024px)
|
|
40601
|
+
3. Add desktop overrides with \`lg:\` prefix (> 1024px)
|
|
40602
|
+
|
|
40603
|
+
WRONG: Desktop-first design that uses \`max-width\` media queries to shrink for mobile
|
|
40604
|
+
RIGHT: Base = mobile, \`sm:\` = tablet, \`lg:\` = desktop
|
|
40605
|
+
|
|
40606
|
+
## OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected)
|
|
40607
|
+
Begin directly with the code scaffold. Do NOT prepend "Here's the design..." or any conversational preamble.
|
|
40608
|
+
|
|
40499
40609
|
Produce a CODE SCAFFOLD in the target framework. This is a skeleton file with:
|
|
40500
40610
|
- Component structure with typed props and proper imports
|
|
40501
40611
|
- Layout structure using the project's CSS framework (Tailwind classes, CSS modules, styled-components, etc.)
|
|
@@ -40662,6 +40772,14 @@ WORKFLOW:
|
|
|
40662
40772
|
- Inline comments explaining obvious code (code should be self-documenting)
|
|
40663
40773
|
- TODO comments in code (those go through the task system, not code comments)
|
|
40664
40774
|
|
|
40775
|
+
## QUALITY RULES
|
|
40776
|
+
- Code examples in docs MUST be syntactically valid \u2014 test them mentally against the actual code
|
|
40777
|
+
- API examples MUST show both a success case AND an error/edge case
|
|
40778
|
+
- Parameter descriptions MUST include: type, required/optional, and default value (if any)
|
|
40779
|
+
- NEVER document internal implementation details in public-facing docs
|
|
40780
|
+
- MATCH existing documentation tone and style exactly \u2014 do not change voice or formatting conventions
|
|
40781
|
+
- If you find existing docs that are INCORRECT based on the code changes you're reviewing, FIX THEM \u2014 do not leave known inaccuracies
|
|
40782
|
+
|
|
40665
40783
|
RULES:
|
|
40666
40784
|
- Be accurate: documentation MUST match the actual code behavior
|
|
40667
40785
|
- Be concise: update only what changed, do not rewrite entire files
|
|
@@ -40767,6 +40885,25 @@ DOMAINS: [relevant SME domains: powershell, security, python, etc.]
|
|
|
40767
40885
|
|
|
40768
40886
|
REVIEW NEEDED:
|
|
40769
40887
|
- [path]: [why, which SME]
|
|
40888
|
+
|
|
40889
|
+
## INTEGRATION IMPACT ANALYSIS MODE
|
|
40890
|
+
Activates when delegated with "Integration impact analysis" or INPUT lists contract changes.
|
|
40891
|
+
|
|
40892
|
+
INPUT: List of contract changes (from diff tool output \u2014 changed exports, signatures, types)
|
|
40893
|
+
|
|
40894
|
+
STEPS:
|
|
40895
|
+
1. For each changed export: grep the codebase for imports and usages of that symbol
|
|
40896
|
+
2. Classify each change: BREAKING (callers must update) or COMPATIBLE (callers unaffected)
|
|
40897
|
+
3. List all files that import or use the changed exports
|
|
40898
|
+
|
|
40899
|
+
OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
|
|
40900
|
+
Begin directly with BREAKING_CHANGES. Do NOT prepend conversational preamble.
|
|
40901
|
+
|
|
40902
|
+
BREAKING_CHANGES: [list with affected consumer files, or "none"]
|
|
40903
|
+
COMPATIBLE_CHANGES: [list, or "none"]
|
|
40904
|
+
CONSUMERS_AFFECTED: [list of files that import/use changed exports, or "none"]
|
|
40905
|
+
VERDICT: BREAKING | COMPATIBLE
|
|
40906
|
+
MIGRATION_NEEDED: [yes \u2014 description of required caller updates | no]
|
|
40770
40907
|
`;
|
|
40771
40908
|
function createExplorerAgent(model, customPrompt, customAppendPrompt) {
|
|
40772
40909
|
let prompt = EXPLORER_PROMPT;
|
|
@@ -40885,6 +41022,7 @@ VERDICT: APPROVED | REJECTED
|
|
|
40885
41022
|
RISK: LOW | MEDIUM | HIGH | CRITICAL
|
|
40886
41023
|
ISSUES: list with line numbers, grouped by CHECK dimension
|
|
40887
41024
|
FIXES: required changes if rejected
|
|
41025
|
+
Use INFO only inside ISSUES for non-blocking suggestions. RISK reflects the highest blocking severity, so it never uses INFO.
|
|
40888
41026
|
|
|
40889
41027
|
## RULES
|
|
40890
41028
|
- Be specific with line numbers
|
|
@@ -40892,11 +41030,17 @@ FIXES: required changes if rejected
|
|
|
40892
41030
|
- Don't reject for style if functionally correct
|
|
40893
41031
|
- No code modifications
|
|
40894
41032
|
|
|
40895
|
-
##
|
|
40896
|
-
|
|
40897
|
-
-
|
|
40898
|
-
- HIGH:
|
|
40899
|
-
-
|
|
41033
|
+
## SEVERITY CALIBRATION
|
|
41034
|
+
Use these definitions precisely \u2014 do not inflate severity:
|
|
41035
|
+
- CRITICAL: Will crash, corrupt data, or bypass security at runtime. Blocks approval. Must fix before merge.
|
|
41036
|
+
- HIGH: Logic error that produces wrong results in realistic scenarios. Should fix before merge.
|
|
41037
|
+
- MEDIUM: Edge case that could fail under unusual but possible conditions. Recommended fix.
|
|
41038
|
+
- LOW: Code smell, readability concern, or minor optimization opportunity. Optional.
|
|
41039
|
+
- INFO: Suggestion for future improvement. Not a blocker.
|
|
41040
|
+
|
|
41041
|
+
CALIBRATION RULE \u2014 If you find NO issues, state this explicitly:
|
|
41042
|
+
"NO ISSUES FOUND \u2014 Reviewed [N] changed functions. Preconditions verified for: [list]. Edge cases considered: [list]. No logic errors, security concerns, or contract changes detected."
|
|
41043
|
+
A blank APPROVED without reasoning is NOT acceptable \u2014 it indicates you did not actually review.
|
|
40900
41044
|
|
|
40901
41045
|
`;
|
|
40902
41046
|
function createReviewerAgent(model, customPrompt, customAppendPrompt) {
|
|
@@ -40981,6 +41125,30 @@ PLATFORM: [cross-platform notes if OS-interaction APIs]
|
|
|
40981
41125
|
GOTCHAS: [common pitfalls or edge cases]
|
|
40982
41126
|
DEPS: [required dependencies/tools]
|
|
40983
41127
|
|
|
41128
|
+
## DOMAIN CHECKLISTS
|
|
41129
|
+
Apply the relevant checklist when the DOMAIN matches:
|
|
41130
|
+
|
|
41131
|
+
### SECURITY domain
|
|
41132
|
+
- [ ] OWASP Top 10 considered for the relevant attack surface
|
|
41133
|
+
- [ ] Input validation strategy defined (allowlist, not denylist)
|
|
41134
|
+
- [ ] Authentication/authorization model clear and least-privilege
|
|
41135
|
+
- [ ] Secret management approach specified (no hardcoded secrets)
|
|
41136
|
+
- [ ] Error messages do not leak internal implementation details
|
|
41137
|
+
|
|
41138
|
+
### CROSS-PLATFORM domain
|
|
41139
|
+
- [ ] Path handling: \`path.join()\` not string concatenation
|
|
41140
|
+
- [ ] Line endings: consistent handling (\`os.EOL\` or \`\\n\`)
|
|
41141
|
+
- [ ] File system: case sensitivity considered (Linux = case-sensitive)
|
|
41142
|
+
- [ ] Shell commands: cross-platform alternatives identified
|
|
41143
|
+
- [ ] Node.js APIs: no platform-specific APIs without fallbacks
|
|
41144
|
+
|
|
41145
|
+
### PERFORMANCE domain
|
|
41146
|
+
- [ ] Time complexity analyzed (O(n) vs O(n\xB2) for realistic input sizes)
|
|
41147
|
+
- [ ] Memory allocation patterns reviewed (no unnecessary object creation in hot paths)
|
|
41148
|
+
- [ ] I/O operations minimized (batch where possible)
|
|
41149
|
+
- [ ] Caching strategy considered
|
|
41150
|
+
- [ ] Streaming vs. buffering decision made for large data
|
|
41151
|
+
|
|
40984
41152
|
## RULES
|
|
40985
41153
|
- Be specific: exact names, paths, parameters, versions
|
|
40986
41154
|
- Be concise: under 1500 characters
|
|
@@ -41140,6 +41308,20 @@ COVERAGE FLOOR: If you tested fewer than 80% of public functions, report:
|
|
|
41140
41308
|
INCOMPLETE \u2014 [N] of [M] public functions tested. Missing: [list of untested functions]
|
|
41141
41309
|
Do NOT report PASS/FAIL until coverage is at least 80%.
|
|
41142
41310
|
|
|
41311
|
+
## ADVERSARIAL TEST PATTERNS
|
|
41312
|
+
When writing adversarial or security-focused tests, cover these attack categories:
|
|
41313
|
+
|
|
41314
|
+
- OVERSIZED INPUT: Strings > 10KB, arrays > 100K elements, deeply nested objects (100+ levels)
|
|
41315
|
+
- TYPE CONFUSION: Pass number where string expected, object where array expected, null where object expected
|
|
41316
|
+
- INJECTION: SQL fragments, HTML/script tags (\`<script>alert(1)</script>\`), template literals (\`\${...}\`), path traversal (\`../\`)
|
|
41317
|
+
- UNICODE: Null bytes (\`\\x00\`), RTL override characters, zero-width spaces, emoji, combining characters
|
|
41318
|
+
- BOUNDARY: \`Number.MAX_SAFE_INTEGER\`, \`-0\`, \`NaN\`, \`Infinity\`, empty string vs null vs undefined
|
|
41319
|
+
- AUTH BYPASS: Missing headers, expired tokens, tokens for wrong users, malformed JWT structure
|
|
41320
|
+
- CONCURRENCY: Simultaneous calls to same function/endpoint, race conditions on shared state
|
|
41321
|
+
- FILESYSTEM: Paths with spaces, Unicode filenames, symlinks, paths that would escape workspace
|
|
41322
|
+
|
|
41323
|
+
For each adversarial test: assert a SPECIFIC outcome (error thrown, value rejected, sanitized output) \u2014 not just "it doesn't crash."
|
|
41324
|
+
|
|
41143
41325
|
## EXECUTION VERIFICATION
|
|
41144
41326
|
|
|
41145
41327
|
After writing tests, you MUST run them. A test file that was written but never executed is NOT a deliverable.
|
|
@@ -41335,6 +41517,7 @@ function getAgentConfigs(config2) {
|
|
|
41335
41517
|
};
|
|
41336
41518
|
if (agent.name === "architect" || agent.name.endsWith("_architect")) {
|
|
41337
41519
|
sdkConfig.mode = "primary";
|
|
41520
|
+
sdkConfig.permission = { task: "allow" };
|
|
41338
41521
|
} else {
|
|
41339
41522
|
sdkConfig.mode = "subagent";
|
|
41340
41523
|
}
|
|
@@ -52800,12 +52983,139 @@ var build_check = createSwarmTool({
|
|
|
52800
52983
|
return JSON.stringify(result, null, 2);
|
|
52801
52984
|
}
|
|
52802
52985
|
});
|
|
52986
|
+
// src/tools/check-gate-status.ts
|
|
52987
|
+
init_dist();
|
|
52988
|
+
init_create_tool();
|
|
52989
|
+
import * as fs19 from "fs";
|
|
52990
|
+
import * as path32 from "path";
|
|
52991
|
+
var EVIDENCE_DIR = ".swarm/evidence";
|
|
52992
|
+
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
52993
|
+
const normalizedWorkspace = path32.resolve(workspaceRoot);
|
|
52994
|
+
const swarmPath = path32.join(normalizedWorkspace, ".swarm", "evidence");
|
|
52995
|
+
const normalizedPath = path32.resolve(filePath);
|
|
52996
|
+
return normalizedPath.startsWith(swarmPath);
|
|
52997
|
+
}
|
|
52998
|
+
function readEvidenceFile(evidencePath) {
|
|
52999
|
+
if (!fs19.existsSync(evidencePath)) {
|
|
53000
|
+
return null;
|
|
53001
|
+
}
|
|
53002
|
+
let content;
|
|
53003
|
+
try {
|
|
53004
|
+
content = fs19.readFileSync(evidencePath, "utf-8");
|
|
53005
|
+
} catch {
|
|
53006
|
+
return null;
|
|
53007
|
+
}
|
|
53008
|
+
let parsed;
|
|
53009
|
+
try {
|
|
53010
|
+
parsed = JSON.parse(content);
|
|
53011
|
+
} catch {
|
|
53012
|
+
return null;
|
|
53013
|
+
}
|
|
53014
|
+
if (parsed && typeof parsed === "object" && Array.isArray(parsed.required_gates) && typeof parsed.gates === "object" && parsed.gates !== null) {
|
|
53015
|
+
return parsed;
|
|
53016
|
+
}
|
|
53017
|
+
return null;
|
|
53018
|
+
}
|
|
53019
|
+
var check_gate_status = createSwarmTool({
|
|
53020
|
+
description: "Read-only tool to check the gate status of a specific task. Reads .swarm/evidence/{taskId}.json and returns structured JSON describing required, passed, and missing gates.",
|
|
53021
|
+
args: {
|
|
53022
|
+
task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)?$/, "Task ID must be in N.M or N.M.P format").describe('The task ID to check gate status for (e.g., "1.1", "2.3.1")')
|
|
53023
|
+
},
|
|
53024
|
+
async execute(args2, directory) {
|
|
53025
|
+
let taskIdInput;
|
|
53026
|
+
try {
|
|
53027
|
+
if (args2 && typeof args2 === "object") {
|
|
53028
|
+
const obj = args2;
|
|
53029
|
+
taskIdInput = typeof obj.task_id === "string" ? obj.task_id : undefined;
|
|
53030
|
+
}
|
|
53031
|
+
} catch {}
|
|
53032
|
+
if (!taskIdInput) {
|
|
53033
|
+
const errorResult = {
|
|
53034
|
+
taskId: "",
|
|
53035
|
+
status: "no_evidence",
|
|
53036
|
+
required_gates: [],
|
|
53037
|
+
passed_gates: [],
|
|
53038
|
+
missing_gates: [],
|
|
53039
|
+
gates: {},
|
|
53040
|
+
message: "Invalid task_id: task_id is required"
|
|
53041
|
+
};
|
|
53042
|
+
return JSON.stringify(errorResult, null, 2);
|
|
53043
|
+
}
|
|
53044
|
+
const taskIdPattern = /^\d+\.\d+(\.\d+)?$/;
|
|
53045
|
+
if (!taskIdPattern.test(taskIdInput)) {
|
|
53046
|
+
const errorResult = {
|
|
53047
|
+
taskId: taskIdInput,
|
|
53048
|
+
status: "no_evidence",
|
|
53049
|
+
required_gates: [],
|
|
53050
|
+
passed_gates: [],
|
|
53051
|
+
missing_gates: [],
|
|
53052
|
+
gates: {},
|
|
53053
|
+
message: `Invalid task_id format: "${taskIdInput}". Must match pattern N.M or N.M.P (e.g., "1.1", "1.2.3")`
|
|
53054
|
+
};
|
|
53055
|
+
return JSON.stringify(errorResult, null, 2);
|
|
53056
|
+
}
|
|
53057
|
+
const evidencePath = path32.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
53058
|
+
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
53059
|
+
const errorResult = {
|
|
53060
|
+
taskId: taskIdInput,
|
|
53061
|
+
status: "no_evidence",
|
|
53062
|
+
required_gates: [],
|
|
53063
|
+
passed_gates: [],
|
|
53064
|
+
missing_gates: [],
|
|
53065
|
+
gates: {},
|
|
53066
|
+
message: "Invalid path: evidence path validation failed"
|
|
53067
|
+
};
|
|
53068
|
+
return JSON.stringify(errorResult, null, 2);
|
|
53069
|
+
}
|
|
53070
|
+
const evidenceData = readEvidenceFile(evidencePath);
|
|
53071
|
+
if (!evidenceData) {
|
|
53072
|
+
const errorResult = {
|
|
53073
|
+
taskId: taskIdInput,
|
|
53074
|
+
status: "no_evidence",
|
|
53075
|
+
required_gates: [],
|
|
53076
|
+
passed_gates: [],
|
|
53077
|
+
missing_gates: [],
|
|
53078
|
+
gates: {},
|
|
53079
|
+
message: `No evidence file found for task "${taskIdInput}" at ${evidencePath}. Evidence file may be missing or invalid.`
|
|
53080
|
+
};
|
|
53081
|
+
return JSON.stringify(errorResult, null, 2);
|
|
53082
|
+
}
|
|
53083
|
+
const requiredGates = evidenceData.required_gates || [];
|
|
53084
|
+
const gatesMap = evidenceData.gates || {};
|
|
53085
|
+
const passedGates = [];
|
|
53086
|
+
const missingGates = [];
|
|
53087
|
+
for (const requiredGate of requiredGates) {
|
|
53088
|
+
if (gatesMap[requiredGate]) {
|
|
53089
|
+
passedGates.push(requiredGate);
|
|
53090
|
+
} else {
|
|
53091
|
+
missingGates.push(requiredGate);
|
|
53092
|
+
}
|
|
53093
|
+
}
|
|
53094
|
+
const status = missingGates.length === 0 ? "all_passed" : "incomplete";
|
|
53095
|
+
let message;
|
|
53096
|
+
if (status === "all_passed") {
|
|
53097
|
+
message = `All required gates have passed for task "${taskIdInput}".`;
|
|
53098
|
+
} else {
|
|
53099
|
+
message = `Task "${taskIdInput}" is incomplete. Missing gates: ${missingGates.join(", ")}.`;
|
|
53100
|
+
}
|
|
53101
|
+
const result = {
|
|
53102
|
+
taskId: taskIdInput,
|
|
53103
|
+
status,
|
|
53104
|
+
required_gates: requiredGates,
|
|
53105
|
+
passed_gates: passedGates,
|
|
53106
|
+
missing_gates: missingGates,
|
|
53107
|
+
gates: gatesMap,
|
|
53108
|
+
message
|
|
53109
|
+
};
|
|
53110
|
+
return JSON.stringify(result, null, 2);
|
|
53111
|
+
}
|
|
53112
|
+
});
|
|
52803
53113
|
// src/tools/checkpoint.ts
|
|
52804
53114
|
init_tool();
|
|
52805
53115
|
init_create_tool();
|
|
52806
53116
|
import { spawnSync } from "child_process";
|
|
52807
|
-
import * as
|
|
52808
|
-
import * as
|
|
53117
|
+
import * as fs20 from "fs";
|
|
53118
|
+
import * as path33 from "path";
|
|
52809
53119
|
var CHECKPOINT_LOG_PATH = ".swarm/checkpoints.json";
|
|
52810
53120
|
var MAX_LABEL_LENGTH = 100;
|
|
52811
53121
|
var GIT_TIMEOUT_MS = 30000;
|
|
@@ -52856,13 +53166,13 @@ function validateLabel(label) {
|
|
|
52856
53166
|
return null;
|
|
52857
53167
|
}
|
|
52858
53168
|
function getCheckpointLogPath(directory) {
|
|
52859
|
-
return
|
|
53169
|
+
return path33.join(directory, CHECKPOINT_LOG_PATH);
|
|
52860
53170
|
}
|
|
52861
53171
|
function readCheckpointLog(directory) {
|
|
52862
53172
|
const logPath = getCheckpointLogPath(directory);
|
|
52863
53173
|
try {
|
|
52864
|
-
if (
|
|
52865
|
-
const content =
|
|
53174
|
+
if (fs20.existsSync(logPath)) {
|
|
53175
|
+
const content = fs20.readFileSync(logPath, "utf-8");
|
|
52866
53176
|
const parsed = JSON.parse(content);
|
|
52867
53177
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
52868
53178
|
return { version: 1, checkpoints: [] };
|
|
@@ -52874,13 +53184,13 @@ function readCheckpointLog(directory) {
|
|
|
52874
53184
|
}
|
|
52875
53185
|
function writeCheckpointLog(log2, directory) {
|
|
52876
53186
|
const logPath = getCheckpointLogPath(directory);
|
|
52877
|
-
const dir =
|
|
52878
|
-
if (!
|
|
52879
|
-
|
|
53187
|
+
const dir = path33.dirname(logPath);
|
|
53188
|
+
if (!fs20.existsSync(dir)) {
|
|
53189
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
52880
53190
|
}
|
|
52881
53191
|
const tempPath = `${logPath}.tmp`;
|
|
52882
|
-
|
|
52883
|
-
|
|
53192
|
+
fs20.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
|
|
53193
|
+
fs20.renameSync(tempPath, logPath);
|
|
52884
53194
|
}
|
|
52885
53195
|
function gitExec(args2) {
|
|
52886
53196
|
const result = spawnSync("git", args2, {
|
|
@@ -53081,8 +53391,8 @@ var checkpoint = createSwarmTool({
|
|
|
53081
53391
|
// src/tools/complexity-hotspots.ts
|
|
53082
53392
|
init_dist();
|
|
53083
53393
|
init_create_tool();
|
|
53084
|
-
import * as
|
|
53085
|
-
import * as
|
|
53394
|
+
import * as fs21 from "fs";
|
|
53395
|
+
import * as path34 from "path";
|
|
53086
53396
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
53087
53397
|
var DEFAULT_DAYS = 90;
|
|
53088
53398
|
var DEFAULT_TOP_N = 20;
|
|
@@ -53211,11 +53521,11 @@ function estimateComplexity(content) {
|
|
|
53211
53521
|
}
|
|
53212
53522
|
function getComplexityForFile(filePath) {
|
|
53213
53523
|
try {
|
|
53214
|
-
const stat2 =
|
|
53524
|
+
const stat2 = fs21.statSync(filePath);
|
|
53215
53525
|
if (stat2.size > MAX_FILE_SIZE_BYTES2) {
|
|
53216
53526
|
return null;
|
|
53217
53527
|
}
|
|
53218
|
-
const content =
|
|
53528
|
+
const content = fs21.readFileSync(filePath, "utf-8");
|
|
53219
53529
|
return estimateComplexity(content);
|
|
53220
53530
|
} catch {
|
|
53221
53531
|
return null;
|
|
@@ -53226,7 +53536,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
53226
53536
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
53227
53537
|
const filteredChurn = new Map;
|
|
53228
53538
|
for (const [file3, count] of churnMap) {
|
|
53229
|
-
const ext =
|
|
53539
|
+
const ext = path34.extname(file3).toLowerCase();
|
|
53230
53540
|
if (extSet.has(ext)) {
|
|
53231
53541
|
filteredChurn.set(file3, count);
|
|
53232
53542
|
}
|
|
@@ -53236,8 +53546,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
53236
53546
|
let analyzedFiles = 0;
|
|
53237
53547
|
for (const [file3, churnCount] of filteredChurn) {
|
|
53238
53548
|
let fullPath = file3;
|
|
53239
|
-
if (!
|
|
53240
|
-
fullPath =
|
|
53549
|
+
if (!fs21.existsSync(fullPath)) {
|
|
53550
|
+
fullPath = path34.join(cwd, file3);
|
|
53241
53551
|
}
|
|
53242
53552
|
const complexity = getComplexityForFile(fullPath);
|
|
53243
53553
|
if (complexity !== null) {
|
|
@@ -53384,8 +53694,8 @@ var complexity_hotspots = createSwarmTool({
|
|
|
53384
53694
|
});
|
|
53385
53695
|
// src/tools/declare-scope.ts
|
|
53386
53696
|
init_tool();
|
|
53387
|
-
import * as
|
|
53388
|
-
import * as
|
|
53697
|
+
import * as fs22 from "fs";
|
|
53698
|
+
import * as path35 from "path";
|
|
53389
53699
|
init_create_tool();
|
|
53390
53700
|
function validateTaskIdFormat(taskId) {
|
|
53391
53701
|
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -53464,8 +53774,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
53464
53774
|
};
|
|
53465
53775
|
}
|
|
53466
53776
|
}
|
|
53467
|
-
normalizedDir =
|
|
53468
|
-
const pathParts = normalizedDir.split(
|
|
53777
|
+
normalizedDir = path35.normalize(args2.working_directory);
|
|
53778
|
+
const pathParts = normalizedDir.split(path35.sep);
|
|
53469
53779
|
if (pathParts.includes("..")) {
|
|
53470
53780
|
return {
|
|
53471
53781
|
success: false,
|
|
@@ -53475,11 +53785,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
53475
53785
|
]
|
|
53476
53786
|
};
|
|
53477
53787
|
}
|
|
53478
|
-
const resolvedDir =
|
|
53788
|
+
const resolvedDir = path35.resolve(normalizedDir);
|
|
53479
53789
|
try {
|
|
53480
|
-
const realPath =
|
|
53481
|
-
const planPath2 =
|
|
53482
|
-
if (!
|
|
53790
|
+
const realPath = fs22.realpathSync(resolvedDir);
|
|
53791
|
+
const planPath2 = path35.join(realPath, ".swarm", "plan.json");
|
|
53792
|
+
if (!fs22.existsSync(planPath2)) {
|
|
53483
53793
|
return {
|
|
53484
53794
|
success: false,
|
|
53485
53795
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -53499,8 +53809,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
53499
53809
|
}
|
|
53500
53810
|
}
|
|
53501
53811
|
const directory = normalizedDir ?? fallbackDir ?? process.cwd();
|
|
53502
|
-
const planPath =
|
|
53503
|
-
if (!
|
|
53812
|
+
const planPath = path35.resolve(directory, ".swarm", "plan.json");
|
|
53813
|
+
if (!fs22.existsSync(planPath)) {
|
|
53504
53814
|
return {
|
|
53505
53815
|
success: false,
|
|
53506
53816
|
message: "No plan found",
|
|
@@ -53509,7 +53819,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
53509
53819
|
}
|
|
53510
53820
|
let planContent;
|
|
53511
53821
|
try {
|
|
53512
|
-
planContent = JSON.parse(
|
|
53822
|
+
planContent = JSON.parse(fs22.readFileSync(planPath, "utf-8"));
|
|
53513
53823
|
} catch {
|
|
53514
53824
|
return {
|
|
53515
53825
|
success: false,
|
|
@@ -53589,20 +53899,20 @@ function validateBase(base) {
|
|
|
53589
53899
|
function validatePaths(paths) {
|
|
53590
53900
|
if (!paths)
|
|
53591
53901
|
return null;
|
|
53592
|
-
for (const
|
|
53593
|
-
if (!
|
|
53902
|
+
for (const path36 of paths) {
|
|
53903
|
+
if (!path36 || path36.length === 0) {
|
|
53594
53904
|
return "empty path not allowed";
|
|
53595
53905
|
}
|
|
53596
|
-
if (
|
|
53906
|
+
if (path36.length > MAX_PATH_LENGTH) {
|
|
53597
53907
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
53598
53908
|
}
|
|
53599
|
-
if (SHELL_METACHARACTERS2.test(
|
|
53909
|
+
if (SHELL_METACHARACTERS2.test(path36)) {
|
|
53600
53910
|
return "path contains shell metacharacters";
|
|
53601
53911
|
}
|
|
53602
|
-
if (
|
|
53912
|
+
if (path36.startsWith("-")) {
|
|
53603
53913
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
53604
53914
|
}
|
|
53605
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
53915
|
+
if (CONTROL_CHAR_PATTERN2.test(path36)) {
|
|
53606
53916
|
return "path contains control characters";
|
|
53607
53917
|
}
|
|
53608
53918
|
}
|
|
@@ -53682,8 +53992,8 @@ var diff = tool({
|
|
|
53682
53992
|
if (parts2.length >= 3) {
|
|
53683
53993
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
53684
53994
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
53685
|
-
const
|
|
53686
|
-
files.push({ path:
|
|
53995
|
+
const path36 = parts2[2];
|
|
53996
|
+
files.push({ path: path36, additions, deletions });
|
|
53687
53997
|
}
|
|
53688
53998
|
}
|
|
53689
53999
|
const contractChanges = [];
|
|
@@ -53912,11 +54222,11 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
53912
54222
|
// src/tools/evidence-check.ts
|
|
53913
54223
|
init_dist();
|
|
53914
54224
|
init_create_tool();
|
|
53915
|
-
import * as
|
|
53916
|
-
import * as
|
|
54225
|
+
import * as fs23 from "fs";
|
|
54226
|
+
import * as path36 from "path";
|
|
53917
54227
|
var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
|
|
53918
54228
|
var MAX_EVIDENCE_FILES = 1000;
|
|
53919
|
-
var
|
|
54229
|
+
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
53920
54230
|
var PLAN_FILE = ".swarm/plan.md";
|
|
53921
54231
|
var SHELL_METACHAR_REGEX2 = /[;&|%$`\\]/;
|
|
53922
54232
|
var VALID_EVIDENCE_FILENAME_REGEX = /^[a-zA-Z0-9_-]+\.json$/;
|
|
@@ -53935,10 +54245,10 @@ function validateRequiredTypes(input) {
|
|
|
53935
54245
|
}
|
|
53936
54246
|
return null;
|
|
53937
54247
|
}
|
|
53938
|
-
function
|
|
53939
|
-
const normalizedCwd =
|
|
53940
|
-
const swarmPath =
|
|
53941
|
-
const normalizedPath =
|
|
54248
|
+
function isPathWithinSwarm2(filePath, cwd) {
|
|
54249
|
+
const normalizedCwd = path36.resolve(cwd);
|
|
54250
|
+
const swarmPath = path36.join(normalizedCwd, ".swarm");
|
|
54251
|
+
const normalizedPath = path36.resolve(filePath);
|
|
53942
54252
|
return normalizedPath.startsWith(swarmPath);
|
|
53943
54253
|
}
|
|
53944
54254
|
function parseCompletedTasks(planContent) {
|
|
@@ -53954,12 +54264,12 @@ function parseCompletedTasks(planContent) {
|
|
|
53954
54264
|
}
|
|
53955
54265
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
53956
54266
|
const evidence = [];
|
|
53957
|
-
if (!
|
|
54267
|
+
if (!fs23.existsSync(evidenceDir) || !fs23.statSync(evidenceDir).isDirectory()) {
|
|
53958
54268
|
return evidence;
|
|
53959
54269
|
}
|
|
53960
54270
|
let files;
|
|
53961
54271
|
try {
|
|
53962
|
-
files =
|
|
54272
|
+
files = fs23.readdirSync(evidenceDir);
|
|
53963
54273
|
} catch {
|
|
53964
54274
|
return evidence;
|
|
53965
54275
|
}
|
|
@@ -53968,14 +54278,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
53968
54278
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
53969
54279
|
continue;
|
|
53970
54280
|
}
|
|
53971
|
-
const filePath =
|
|
54281
|
+
const filePath = path36.join(evidenceDir, filename);
|
|
53972
54282
|
try {
|
|
53973
|
-
const resolvedPath =
|
|
53974
|
-
const evidenceDirResolved =
|
|
54283
|
+
const resolvedPath = path36.resolve(filePath);
|
|
54284
|
+
const evidenceDirResolved = path36.resolve(evidenceDir);
|
|
53975
54285
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
53976
54286
|
continue;
|
|
53977
54287
|
}
|
|
53978
|
-
const stat2 =
|
|
54288
|
+
const stat2 = fs23.lstatSync(filePath);
|
|
53979
54289
|
if (!stat2.isFile()) {
|
|
53980
54290
|
continue;
|
|
53981
54291
|
}
|
|
@@ -53984,7 +54294,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
53984
54294
|
}
|
|
53985
54295
|
let fileStat;
|
|
53986
54296
|
try {
|
|
53987
|
-
fileStat =
|
|
54297
|
+
fileStat = fs23.statSync(filePath);
|
|
53988
54298
|
if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
|
|
53989
54299
|
continue;
|
|
53990
54300
|
}
|
|
@@ -53993,7 +54303,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
53993
54303
|
}
|
|
53994
54304
|
let content;
|
|
53995
54305
|
try {
|
|
53996
|
-
content =
|
|
54306
|
+
content = fs23.readFileSync(filePath, "utf-8");
|
|
53997
54307
|
} catch {
|
|
53998
54308
|
continue;
|
|
53999
54309
|
}
|
|
@@ -54078,8 +54388,8 @@ var evidence_check = createSwarmTool({
|
|
|
54078
54388
|
return JSON.stringify(errorResult, null, 2);
|
|
54079
54389
|
}
|
|
54080
54390
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
54081
|
-
const planPath =
|
|
54082
|
-
if (!
|
|
54391
|
+
const planPath = path36.join(cwd, PLAN_FILE);
|
|
54392
|
+
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
54083
54393
|
const errorResult = {
|
|
54084
54394
|
error: "plan file path validation failed",
|
|
54085
54395
|
completedTasks: [],
|
|
@@ -54092,7 +54402,7 @@ var evidence_check = createSwarmTool({
|
|
|
54092
54402
|
}
|
|
54093
54403
|
let planContent;
|
|
54094
54404
|
try {
|
|
54095
|
-
planContent =
|
|
54405
|
+
planContent = fs23.readFileSync(planPath, "utf-8");
|
|
54096
54406
|
} catch {
|
|
54097
54407
|
const result2 = {
|
|
54098
54408
|
message: "No completed tasks found in plan.",
|
|
@@ -54110,7 +54420,7 @@ var evidence_check = createSwarmTool({
|
|
|
54110
54420
|
};
|
|
54111
54421
|
return JSON.stringify(result2, null, 2);
|
|
54112
54422
|
}
|
|
54113
|
-
const evidenceDir =
|
|
54423
|
+
const evidenceDir = path36.join(cwd, EVIDENCE_DIR2);
|
|
54114
54424
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
54115
54425
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
54116
54426
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -54127,8 +54437,8 @@ var evidence_check = createSwarmTool({
|
|
|
54127
54437
|
// src/tools/file-extractor.ts
|
|
54128
54438
|
init_tool();
|
|
54129
54439
|
init_create_tool();
|
|
54130
|
-
import * as
|
|
54131
|
-
import * as
|
|
54440
|
+
import * as fs24 from "fs";
|
|
54441
|
+
import * as path37 from "path";
|
|
54132
54442
|
var EXT_MAP = {
|
|
54133
54443
|
python: ".py",
|
|
54134
54444
|
py: ".py",
|
|
@@ -54190,8 +54500,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
54190
54500
|
execute: async (args2, directory) => {
|
|
54191
54501
|
const { content, output_dir, prefix } = args2;
|
|
54192
54502
|
const targetDir = output_dir || directory;
|
|
54193
|
-
if (!
|
|
54194
|
-
|
|
54503
|
+
if (!fs24.existsSync(targetDir)) {
|
|
54504
|
+
fs24.mkdirSync(targetDir, { recursive: true });
|
|
54195
54505
|
}
|
|
54196
54506
|
if (!content) {
|
|
54197
54507
|
return "Error: content is required";
|
|
@@ -54209,16 +54519,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
54209
54519
|
if (prefix) {
|
|
54210
54520
|
filename = `${prefix}_${filename}`;
|
|
54211
54521
|
}
|
|
54212
|
-
let filepath =
|
|
54213
|
-
const base =
|
|
54214
|
-
const ext =
|
|
54522
|
+
let filepath = path37.join(targetDir, filename);
|
|
54523
|
+
const base = path37.basename(filepath, path37.extname(filepath));
|
|
54524
|
+
const ext = path37.extname(filepath);
|
|
54215
54525
|
let counter = 1;
|
|
54216
|
-
while (
|
|
54217
|
-
filepath =
|
|
54526
|
+
while (fs24.existsSync(filepath)) {
|
|
54527
|
+
filepath = path37.join(targetDir, `${base}_${counter}${ext}`);
|
|
54218
54528
|
counter++;
|
|
54219
54529
|
}
|
|
54220
54530
|
try {
|
|
54221
|
-
|
|
54531
|
+
fs24.writeFileSync(filepath, code.trim(), "utf-8");
|
|
54222
54532
|
savedFiles.push(filepath);
|
|
54223
54533
|
} catch (error93) {
|
|
54224
54534
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -54247,7 +54557,7 @@ init_dist();
|
|
|
54247
54557
|
var GITINGEST_TIMEOUT_MS = 1e4;
|
|
54248
54558
|
var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
|
|
54249
54559
|
var GITINGEST_MAX_RETRIES = 2;
|
|
54250
|
-
var delay = (ms) => new Promise((
|
|
54560
|
+
var delay = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
54251
54561
|
async function fetchGitingest(args2) {
|
|
54252
54562
|
for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
|
|
54253
54563
|
try {
|
|
@@ -54331,8 +54641,8 @@ var gitingest = tool({
|
|
|
54331
54641
|
});
|
|
54332
54642
|
// src/tools/imports.ts
|
|
54333
54643
|
init_dist();
|
|
54334
|
-
import * as
|
|
54335
|
-
import * as
|
|
54644
|
+
import * as fs25 from "fs";
|
|
54645
|
+
import * as path38 from "path";
|
|
54336
54646
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
54337
54647
|
var MAX_SYMBOL_LENGTH = 256;
|
|
54338
54648
|
var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
|
|
@@ -54386,7 +54696,7 @@ function validateSymbolInput(symbol3) {
|
|
|
54386
54696
|
return null;
|
|
54387
54697
|
}
|
|
54388
54698
|
function isBinaryFile2(filePath, buffer) {
|
|
54389
|
-
const ext =
|
|
54699
|
+
const ext = path38.extname(filePath).toLowerCase();
|
|
54390
54700
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
54391
54701
|
return false;
|
|
54392
54702
|
}
|
|
@@ -54410,15 +54720,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
54410
54720
|
const imports = [];
|
|
54411
54721
|
let _resolvedTarget;
|
|
54412
54722
|
try {
|
|
54413
|
-
_resolvedTarget =
|
|
54723
|
+
_resolvedTarget = path38.resolve(targetFile);
|
|
54414
54724
|
} catch {
|
|
54415
54725
|
_resolvedTarget = targetFile;
|
|
54416
54726
|
}
|
|
54417
|
-
const targetBasename =
|
|
54727
|
+
const targetBasename = path38.basename(targetFile, path38.extname(targetFile));
|
|
54418
54728
|
const targetWithExt = targetFile;
|
|
54419
54729
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
54420
|
-
const normalizedTargetWithExt =
|
|
54421
|
-
const normalizedTargetWithoutExt =
|
|
54730
|
+
const normalizedTargetWithExt = path38.normalize(targetWithExt).replace(/\\/g, "/");
|
|
54731
|
+
const normalizedTargetWithoutExt = path38.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
54422
54732
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
54423
54733
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
54424
54734
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -54441,9 +54751,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
54441
54751
|
}
|
|
54442
54752
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
54443
54753
|
let isMatch = false;
|
|
54444
|
-
const _targetDir =
|
|
54445
|
-
const targetExt =
|
|
54446
|
-
const targetBasenameNoExt =
|
|
54754
|
+
const _targetDir = path38.dirname(targetFile);
|
|
54755
|
+
const targetExt = path38.extname(targetFile);
|
|
54756
|
+
const targetBasenameNoExt = path38.basename(targetFile, targetExt);
|
|
54447
54757
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
54448
54758
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
54449
54759
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -54500,7 +54810,7 @@ var SKIP_DIRECTORIES2 = new Set([
|
|
|
54500
54810
|
function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
54501
54811
|
let entries;
|
|
54502
54812
|
try {
|
|
54503
|
-
entries =
|
|
54813
|
+
entries = fs25.readdirSync(dir);
|
|
54504
54814
|
} catch (e) {
|
|
54505
54815
|
stats.fileErrors.push({
|
|
54506
54816
|
path: dir,
|
|
@@ -54511,13 +54821,13 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
54511
54821
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
54512
54822
|
for (const entry of entries) {
|
|
54513
54823
|
if (SKIP_DIRECTORIES2.has(entry)) {
|
|
54514
|
-
stats.skippedDirs.push(
|
|
54824
|
+
stats.skippedDirs.push(path38.join(dir, entry));
|
|
54515
54825
|
continue;
|
|
54516
54826
|
}
|
|
54517
|
-
const fullPath =
|
|
54827
|
+
const fullPath = path38.join(dir, entry);
|
|
54518
54828
|
let stat2;
|
|
54519
54829
|
try {
|
|
54520
|
-
stat2 =
|
|
54830
|
+
stat2 = fs25.statSync(fullPath);
|
|
54521
54831
|
} catch (e) {
|
|
54522
54832
|
stats.fileErrors.push({
|
|
54523
54833
|
path: fullPath,
|
|
@@ -54528,7 +54838,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
54528
54838
|
if (stat2.isDirectory()) {
|
|
54529
54839
|
findSourceFiles2(fullPath, files, stats);
|
|
54530
54840
|
} else if (stat2.isFile()) {
|
|
54531
|
-
const ext =
|
|
54841
|
+
const ext = path38.extname(fullPath).toLowerCase();
|
|
54532
54842
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
54533
54843
|
files.push(fullPath);
|
|
54534
54844
|
}
|
|
@@ -54584,8 +54894,8 @@ var imports = tool({
|
|
|
54584
54894
|
return JSON.stringify(errorResult, null, 2);
|
|
54585
54895
|
}
|
|
54586
54896
|
try {
|
|
54587
|
-
const targetFile =
|
|
54588
|
-
if (!
|
|
54897
|
+
const targetFile = path38.resolve(file3);
|
|
54898
|
+
if (!fs25.existsSync(targetFile)) {
|
|
54589
54899
|
const errorResult = {
|
|
54590
54900
|
error: `target file not found: ${file3}`,
|
|
54591
54901
|
target: file3,
|
|
@@ -54595,7 +54905,7 @@ var imports = tool({
|
|
|
54595
54905
|
};
|
|
54596
54906
|
return JSON.stringify(errorResult, null, 2);
|
|
54597
54907
|
}
|
|
54598
|
-
const targetStat =
|
|
54908
|
+
const targetStat = fs25.statSync(targetFile);
|
|
54599
54909
|
if (!targetStat.isFile()) {
|
|
54600
54910
|
const errorResult = {
|
|
54601
54911
|
error: "target must be a file, not a directory",
|
|
@@ -54606,7 +54916,7 @@ var imports = tool({
|
|
|
54606
54916
|
};
|
|
54607
54917
|
return JSON.stringify(errorResult, null, 2);
|
|
54608
54918
|
}
|
|
54609
|
-
const baseDir =
|
|
54919
|
+
const baseDir = path38.dirname(targetFile);
|
|
54610
54920
|
const scanStats = {
|
|
54611
54921
|
skippedDirs: [],
|
|
54612
54922
|
skippedFiles: 0,
|
|
@@ -54621,12 +54931,12 @@ var imports = tool({
|
|
|
54621
54931
|
if (consumers.length >= MAX_CONSUMERS)
|
|
54622
54932
|
break;
|
|
54623
54933
|
try {
|
|
54624
|
-
const stat2 =
|
|
54934
|
+
const stat2 = fs25.statSync(filePath);
|
|
54625
54935
|
if (stat2.size > MAX_FILE_SIZE_BYTES4) {
|
|
54626
54936
|
skippedFileCount++;
|
|
54627
54937
|
continue;
|
|
54628
54938
|
}
|
|
54629
|
-
const buffer =
|
|
54939
|
+
const buffer = fs25.readFileSync(filePath);
|
|
54630
54940
|
if (isBinaryFile2(filePath, buffer)) {
|
|
54631
54941
|
skippedFileCount++;
|
|
54632
54942
|
continue;
|
|
@@ -54691,7 +55001,7 @@ var imports = tool({
|
|
|
54691
55001
|
});
|
|
54692
55002
|
// src/tools/knowledge-query.ts
|
|
54693
55003
|
init_dist();
|
|
54694
|
-
import { existsSync as
|
|
55004
|
+
import { existsSync as existsSync26 } from "fs";
|
|
54695
55005
|
init_create_tool();
|
|
54696
55006
|
var DEFAULT_LIMIT = 10;
|
|
54697
55007
|
var MAX_LESSON_LENGTH = 200;
|
|
@@ -54761,14 +55071,14 @@ function validateLimit(limit) {
|
|
|
54761
55071
|
}
|
|
54762
55072
|
async function readSwarmKnowledge(directory) {
|
|
54763
55073
|
const swarmPath = resolveSwarmKnowledgePath(directory);
|
|
54764
|
-
if (!
|
|
55074
|
+
if (!existsSync26(swarmPath)) {
|
|
54765
55075
|
return [];
|
|
54766
55076
|
}
|
|
54767
55077
|
return readKnowledge(swarmPath);
|
|
54768
55078
|
}
|
|
54769
55079
|
async function readHiveKnowledge() {
|
|
54770
55080
|
const hivePath = resolveHiveKnowledgePath();
|
|
54771
|
-
if (!
|
|
55081
|
+
if (!existsSync26(hivePath)) {
|
|
54772
55082
|
return [];
|
|
54773
55083
|
}
|
|
54774
55084
|
return readKnowledge(hivePath);
|
|
@@ -54927,8 +55237,8 @@ init_dist();
|
|
|
54927
55237
|
init_config();
|
|
54928
55238
|
init_schema();
|
|
54929
55239
|
init_manager();
|
|
54930
|
-
import * as
|
|
54931
|
-
import * as
|
|
55240
|
+
import * as fs26 from "fs";
|
|
55241
|
+
import * as path39 from "path";
|
|
54932
55242
|
init_utils2();
|
|
54933
55243
|
init_create_tool();
|
|
54934
55244
|
function safeWarn(message, error93) {
|
|
@@ -55123,7 +55433,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
55123
55433
|
}
|
|
55124
55434
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
55125
55435
|
try {
|
|
55126
|
-
const projectName =
|
|
55436
|
+
const projectName = path39.basename(dir);
|
|
55127
55437
|
const knowledgeConfig = {
|
|
55128
55438
|
enabled: true,
|
|
55129
55439
|
swarm_max_entries: 100,
|
|
@@ -55171,7 +55481,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
55171
55481
|
if (agentsMissing.length > 0) {
|
|
55172
55482
|
try {
|
|
55173
55483
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
55174
|
-
const planRaw =
|
|
55484
|
+
const planRaw = fs26.readFileSync(planPath, "utf-8");
|
|
55175
55485
|
const plan = JSON.parse(planRaw);
|
|
55176
55486
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
55177
55487
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -55212,7 +55522,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
55212
55522
|
};
|
|
55213
55523
|
try {
|
|
55214
55524
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
55215
|
-
|
|
55525
|
+
fs26.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
55216
55526
|
`, "utf-8");
|
|
55217
55527
|
} catch (writeError) {
|
|
55218
55528
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -55231,12 +55541,12 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
55231
55541
|
}
|
|
55232
55542
|
try {
|
|
55233
55543
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
55234
|
-
const planJson =
|
|
55544
|
+
const planJson = fs26.readFileSync(planPath, "utf-8");
|
|
55235
55545
|
const plan = JSON.parse(planJson);
|
|
55236
55546
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
55237
55547
|
if (phaseObj) {
|
|
55238
55548
|
phaseObj.status = "completed";
|
|
55239
|
-
|
|
55549
|
+
fs26.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
|
|
55240
55550
|
`, "utf-8");
|
|
55241
55551
|
}
|
|
55242
55552
|
} catch (error93) {
|
|
@@ -55286,8 +55596,8 @@ init_dist();
|
|
|
55286
55596
|
init_discovery();
|
|
55287
55597
|
init_utils();
|
|
55288
55598
|
init_create_tool();
|
|
55289
|
-
import * as
|
|
55290
|
-
import * as
|
|
55599
|
+
import * as fs27 from "fs";
|
|
55600
|
+
import * as path40 from "path";
|
|
55291
55601
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
55292
55602
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
55293
55603
|
function isValidEcosystem(value) {
|
|
@@ -55305,28 +55615,28 @@ function validateArgs3(args2) {
|
|
|
55305
55615
|
function detectEcosystems(directory) {
|
|
55306
55616
|
const ecosystems = [];
|
|
55307
55617
|
const cwd = directory;
|
|
55308
|
-
if (
|
|
55618
|
+
if (fs27.existsSync(path40.join(cwd, "package.json"))) {
|
|
55309
55619
|
ecosystems.push("npm");
|
|
55310
55620
|
}
|
|
55311
|
-
if (
|
|
55621
|
+
if (fs27.existsSync(path40.join(cwd, "pyproject.toml")) || fs27.existsSync(path40.join(cwd, "requirements.txt"))) {
|
|
55312
55622
|
ecosystems.push("pip");
|
|
55313
55623
|
}
|
|
55314
|
-
if (
|
|
55624
|
+
if (fs27.existsSync(path40.join(cwd, "Cargo.toml"))) {
|
|
55315
55625
|
ecosystems.push("cargo");
|
|
55316
55626
|
}
|
|
55317
|
-
if (
|
|
55627
|
+
if (fs27.existsSync(path40.join(cwd, "go.mod"))) {
|
|
55318
55628
|
ecosystems.push("go");
|
|
55319
55629
|
}
|
|
55320
55630
|
try {
|
|
55321
|
-
const files =
|
|
55631
|
+
const files = fs27.readdirSync(cwd);
|
|
55322
55632
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
55323
55633
|
ecosystems.push("dotnet");
|
|
55324
55634
|
}
|
|
55325
55635
|
} catch {}
|
|
55326
|
-
if (
|
|
55636
|
+
if (fs27.existsSync(path40.join(cwd, "Gemfile")) || fs27.existsSync(path40.join(cwd, "Gemfile.lock"))) {
|
|
55327
55637
|
ecosystems.push("ruby");
|
|
55328
55638
|
}
|
|
55329
|
-
if (
|
|
55639
|
+
if (fs27.existsSync(path40.join(cwd, "pubspec.yaml"))) {
|
|
55330
55640
|
ecosystems.push("dart");
|
|
55331
55641
|
}
|
|
55332
55642
|
return ecosystems;
|
|
@@ -55339,7 +55649,7 @@ async function runNpmAudit(directory) {
|
|
|
55339
55649
|
stderr: "pipe",
|
|
55340
55650
|
cwd: directory
|
|
55341
55651
|
});
|
|
55342
|
-
const timeoutPromise = new Promise((
|
|
55652
|
+
const timeoutPromise = new Promise((resolve14) => setTimeout(() => resolve14("timeout"), AUDIT_TIMEOUT_MS));
|
|
55343
55653
|
const result = await Promise.race([
|
|
55344
55654
|
Promise.all([
|
|
55345
55655
|
new Response(proc.stdout).text(),
|
|
@@ -55462,7 +55772,7 @@ async function runPipAudit(directory) {
|
|
|
55462
55772
|
stderr: "pipe",
|
|
55463
55773
|
cwd: directory
|
|
55464
55774
|
});
|
|
55465
|
-
const timeoutPromise = new Promise((
|
|
55775
|
+
const timeoutPromise = new Promise((resolve14) => setTimeout(() => resolve14("timeout"), AUDIT_TIMEOUT_MS));
|
|
55466
55776
|
const result = await Promise.race([
|
|
55467
55777
|
Promise.all([
|
|
55468
55778
|
new Response(proc.stdout).text(),
|
|
@@ -55593,7 +55903,7 @@ async function runCargoAudit(directory) {
|
|
|
55593
55903
|
stderr: "pipe",
|
|
55594
55904
|
cwd: directory
|
|
55595
55905
|
});
|
|
55596
|
-
const timeoutPromise = new Promise((
|
|
55906
|
+
const timeoutPromise = new Promise((resolve14) => setTimeout(() => resolve14("timeout"), AUDIT_TIMEOUT_MS));
|
|
55597
55907
|
const result = await Promise.race([
|
|
55598
55908
|
Promise.all([
|
|
55599
55909
|
new Response(proc.stdout).text(),
|
|
@@ -55720,7 +56030,7 @@ async function runGoAudit(directory) {
|
|
|
55720
56030
|
stderr: "pipe",
|
|
55721
56031
|
cwd: directory
|
|
55722
56032
|
});
|
|
55723
|
-
const timeoutPromise = new Promise((
|
|
56033
|
+
const timeoutPromise = new Promise((resolve14) => setTimeout(() => resolve14("timeout"), AUDIT_TIMEOUT_MS));
|
|
55724
56034
|
const result = await Promise.race([
|
|
55725
56035
|
Promise.all([
|
|
55726
56036
|
new Response(proc.stdout).text(),
|
|
@@ -55856,7 +56166,7 @@ async function runDotnetAudit(directory) {
|
|
|
55856
56166
|
stderr: "pipe",
|
|
55857
56167
|
cwd: directory
|
|
55858
56168
|
});
|
|
55859
|
-
const timeoutPromise = new Promise((
|
|
56169
|
+
const timeoutPromise = new Promise((resolve14) => setTimeout(() => resolve14("timeout"), AUDIT_TIMEOUT_MS));
|
|
55860
56170
|
const result = await Promise.race([
|
|
55861
56171
|
Promise.all([
|
|
55862
56172
|
new Response(proc.stdout).text(),
|
|
@@ -55975,7 +56285,7 @@ async function runBundleAudit(directory) {
|
|
|
55975
56285
|
stderr: "pipe",
|
|
55976
56286
|
cwd: directory
|
|
55977
56287
|
});
|
|
55978
|
-
const timeoutPromise = new Promise((
|
|
56288
|
+
const timeoutPromise = new Promise((resolve14) => setTimeout(() => resolve14("timeout"), AUDIT_TIMEOUT_MS));
|
|
55979
56289
|
const result = await Promise.race([
|
|
55980
56290
|
Promise.all([
|
|
55981
56291
|
new Response(proc.stdout).text(),
|
|
@@ -56122,7 +56432,7 @@ async function runDartAudit(directory) {
|
|
|
56122
56432
|
stderr: "pipe",
|
|
56123
56433
|
cwd: directory
|
|
56124
56434
|
});
|
|
56125
|
-
const timeoutPromise = new Promise((
|
|
56435
|
+
const timeoutPromise = new Promise((resolve14) => setTimeout(() => resolve14("timeout"), AUDIT_TIMEOUT_MS));
|
|
56126
56436
|
const result = await Promise.race([
|
|
56127
56437
|
Promise.all([
|
|
56128
56438
|
new Response(proc.stdout).text(),
|
|
@@ -56388,8 +56698,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
56388
56698
|
]);
|
|
56389
56699
|
// src/tools/pre-check-batch.ts
|
|
56390
56700
|
init_dist();
|
|
56391
|
-
import * as
|
|
56392
|
-
import * as
|
|
56701
|
+
import * as fs30 from "fs";
|
|
56702
|
+
import * as path43 from "path";
|
|
56393
56703
|
|
|
56394
56704
|
// node_modules/yocto-queue/index.js
|
|
56395
56705
|
class Node2 {
|
|
@@ -56480,26 +56790,26 @@ function pLimit(concurrency) {
|
|
|
56480
56790
|
activeCount--;
|
|
56481
56791
|
resumeNext();
|
|
56482
56792
|
};
|
|
56483
|
-
const run2 = async (function_,
|
|
56793
|
+
const run2 = async (function_, resolve14, arguments_2) => {
|
|
56484
56794
|
const result = (async () => function_(...arguments_2))();
|
|
56485
|
-
|
|
56795
|
+
resolve14(result);
|
|
56486
56796
|
try {
|
|
56487
56797
|
await result;
|
|
56488
56798
|
} catch {}
|
|
56489
56799
|
next();
|
|
56490
56800
|
};
|
|
56491
|
-
const enqueue = (function_,
|
|
56801
|
+
const enqueue = (function_, resolve14, reject, arguments_2) => {
|
|
56492
56802
|
const queueItem = { reject };
|
|
56493
56803
|
new Promise((internalResolve) => {
|
|
56494
56804
|
queueItem.run = internalResolve;
|
|
56495
56805
|
queue.enqueue(queueItem);
|
|
56496
|
-
}).then(run2.bind(undefined, function_,
|
|
56806
|
+
}).then(run2.bind(undefined, function_, resolve14, arguments_2));
|
|
56497
56807
|
if (activeCount < concurrency) {
|
|
56498
56808
|
resumeNext();
|
|
56499
56809
|
}
|
|
56500
56810
|
};
|
|
56501
|
-
const generator = (function_, ...arguments_2) => new Promise((
|
|
56502
|
-
enqueue(function_,
|
|
56811
|
+
const generator = (function_, ...arguments_2) => new Promise((resolve14, reject) => {
|
|
56812
|
+
enqueue(function_, resolve14, reject, arguments_2);
|
|
56503
56813
|
});
|
|
56504
56814
|
Object.defineProperties(generator, {
|
|
56505
56815
|
activeCount: {
|
|
@@ -56556,8 +56866,8 @@ init_lint();
|
|
|
56556
56866
|
init_manager();
|
|
56557
56867
|
|
|
56558
56868
|
// src/quality/metrics.ts
|
|
56559
|
-
import * as
|
|
56560
|
-
import * as
|
|
56869
|
+
import * as fs28 from "fs";
|
|
56870
|
+
import * as path41 from "path";
|
|
56561
56871
|
var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
|
|
56562
56872
|
var MIN_DUPLICATION_LINES = 10;
|
|
56563
56873
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -56595,11 +56905,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
56595
56905
|
}
|
|
56596
56906
|
function getComplexityForFile2(filePath) {
|
|
56597
56907
|
try {
|
|
56598
|
-
const stat2 =
|
|
56908
|
+
const stat2 = fs28.statSync(filePath);
|
|
56599
56909
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
56600
56910
|
return null;
|
|
56601
56911
|
}
|
|
56602
|
-
const content =
|
|
56912
|
+
const content = fs28.readFileSync(filePath, "utf-8");
|
|
56603
56913
|
return estimateCyclomaticComplexity(content);
|
|
56604
56914
|
} catch {
|
|
56605
56915
|
return null;
|
|
@@ -56609,8 +56919,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
56609
56919
|
let totalComplexity = 0;
|
|
56610
56920
|
const analyzedFiles = [];
|
|
56611
56921
|
for (const file3 of files) {
|
|
56612
|
-
const fullPath =
|
|
56613
|
-
if (!
|
|
56922
|
+
const fullPath = path41.isAbsolute(file3) ? file3 : path41.join(workingDir, file3);
|
|
56923
|
+
if (!fs28.existsSync(fullPath)) {
|
|
56614
56924
|
continue;
|
|
56615
56925
|
}
|
|
56616
56926
|
const complexity = getComplexityForFile2(fullPath);
|
|
@@ -56731,8 +57041,8 @@ function countGoExports(content) {
|
|
|
56731
57041
|
}
|
|
56732
57042
|
function getExportCountForFile(filePath) {
|
|
56733
57043
|
try {
|
|
56734
|
-
const content =
|
|
56735
|
-
const ext =
|
|
57044
|
+
const content = fs28.readFileSync(filePath, "utf-8");
|
|
57045
|
+
const ext = path41.extname(filePath).toLowerCase();
|
|
56736
57046
|
switch (ext) {
|
|
56737
57047
|
case ".ts":
|
|
56738
57048
|
case ".tsx":
|
|
@@ -56758,8 +57068,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
56758
57068
|
let totalExports = 0;
|
|
56759
57069
|
const analyzedFiles = [];
|
|
56760
57070
|
for (const file3 of files) {
|
|
56761
|
-
const fullPath =
|
|
56762
|
-
if (!
|
|
57071
|
+
const fullPath = path41.isAbsolute(file3) ? file3 : path41.join(workingDir, file3);
|
|
57072
|
+
if (!fs28.existsSync(fullPath)) {
|
|
56763
57073
|
continue;
|
|
56764
57074
|
}
|
|
56765
57075
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -56792,16 +57102,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
56792
57102
|
let duplicateLines = 0;
|
|
56793
57103
|
const analyzedFiles = [];
|
|
56794
57104
|
for (const file3 of files) {
|
|
56795
|
-
const fullPath =
|
|
56796
|
-
if (!
|
|
57105
|
+
const fullPath = path41.isAbsolute(file3) ? file3 : path41.join(workingDir, file3);
|
|
57106
|
+
if (!fs28.existsSync(fullPath)) {
|
|
56797
57107
|
continue;
|
|
56798
57108
|
}
|
|
56799
57109
|
try {
|
|
56800
|
-
const stat2 =
|
|
57110
|
+
const stat2 = fs28.statSync(fullPath);
|
|
56801
57111
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
56802
57112
|
continue;
|
|
56803
57113
|
}
|
|
56804
|
-
const content =
|
|
57114
|
+
const content = fs28.readFileSync(fullPath, "utf-8");
|
|
56805
57115
|
const lines = content.split(`
|
|
56806
57116
|
`).filter((line) => line.trim().length > 0);
|
|
56807
57117
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -56825,8 +57135,8 @@ function countCodeLines(content) {
|
|
|
56825
57135
|
return lines.length;
|
|
56826
57136
|
}
|
|
56827
57137
|
function isTestFile(filePath) {
|
|
56828
|
-
const basename8 =
|
|
56829
|
-
const _ext =
|
|
57138
|
+
const basename8 = path41.basename(filePath);
|
|
57139
|
+
const _ext = path41.extname(filePath).toLowerCase();
|
|
56830
57140
|
const testPatterns = [
|
|
56831
57141
|
".test.",
|
|
56832
57142
|
".spec.",
|
|
@@ -56907,8 +57217,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
56907
57217
|
}
|
|
56908
57218
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
56909
57219
|
}
|
|
56910
|
-
function matchesGlobSegment(
|
|
56911
|
-
const normalizedPath =
|
|
57220
|
+
function matchesGlobSegment(path42, glob) {
|
|
57221
|
+
const normalizedPath = path42.replace(/\\/g, "/");
|
|
56912
57222
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
56913
57223
|
if (normalizedPath.includes("//")) {
|
|
56914
57224
|
return false;
|
|
@@ -56939,8 +57249,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
56939
57249
|
function hasGlobstar(glob) {
|
|
56940
57250
|
return glob.includes("**");
|
|
56941
57251
|
}
|
|
56942
|
-
function globMatches(
|
|
56943
|
-
const normalizedPath =
|
|
57252
|
+
function globMatches(path42, glob) {
|
|
57253
|
+
const normalizedPath = path42.replace(/\\/g, "/");
|
|
56944
57254
|
if (!glob || glob === "") {
|
|
56945
57255
|
if (normalizedPath.includes("//")) {
|
|
56946
57256
|
return false;
|
|
@@ -56976,31 +57286,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
56976
57286
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
56977
57287
|
let testLines = 0;
|
|
56978
57288
|
let codeLines = 0;
|
|
56979
|
-
const srcDir =
|
|
56980
|
-
if (
|
|
57289
|
+
const srcDir = path41.join(workingDir, "src");
|
|
57290
|
+
if (fs28.existsSync(srcDir)) {
|
|
56981
57291
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
56982
57292
|
codeLines += lines;
|
|
56983
57293
|
});
|
|
56984
57294
|
}
|
|
56985
57295
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
56986
57296
|
for (const dir of possibleSrcDirs) {
|
|
56987
|
-
const dirPath =
|
|
56988
|
-
if (
|
|
57297
|
+
const dirPath = path41.join(workingDir, dir);
|
|
57298
|
+
if (fs28.existsSync(dirPath)) {
|
|
56989
57299
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
56990
57300
|
codeLines += lines;
|
|
56991
57301
|
});
|
|
56992
57302
|
}
|
|
56993
57303
|
}
|
|
56994
|
-
const testsDir =
|
|
56995
|
-
if (
|
|
57304
|
+
const testsDir = path41.join(workingDir, "tests");
|
|
57305
|
+
if (fs28.existsSync(testsDir)) {
|
|
56996
57306
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
56997
57307
|
testLines += lines;
|
|
56998
57308
|
});
|
|
56999
57309
|
}
|
|
57000
57310
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
57001
57311
|
for (const dir of possibleTestDirs) {
|
|
57002
|
-
const dirPath =
|
|
57003
|
-
if (
|
|
57312
|
+
const dirPath = path41.join(workingDir, dir);
|
|
57313
|
+
if (fs28.existsSync(dirPath) && dirPath !== testsDir) {
|
|
57004
57314
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
57005
57315
|
testLines += lines;
|
|
57006
57316
|
});
|
|
@@ -57012,9 +57322,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
57012
57322
|
}
|
|
57013
57323
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
57014
57324
|
try {
|
|
57015
|
-
const entries =
|
|
57325
|
+
const entries = fs28.readdirSync(dirPath, { withFileTypes: true });
|
|
57016
57326
|
for (const entry of entries) {
|
|
57017
|
-
const fullPath =
|
|
57327
|
+
const fullPath = path41.join(dirPath, entry.name);
|
|
57018
57328
|
if (entry.isDirectory()) {
|
|
57019
57329
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
57020
57330
|
continue;
|
|
@@ -57022,7 +57332,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
57022
57332
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
57023
57333
|
} else if (entry.isFile()) {
|
|
57024
57334
|
const relativePath = fullPath.replace(`${process.cwd()}/`, "");
|
|
57025
|
-
const ext =
|
|
57335
|
+
const ext = path41.extname(entry.name).toLowerCase();
|
|
57026
57336
|
const validExts = [
|
|
57027
57337
|
".ts",
|
|
57028
57338
|
".tsx",
|
|
@@ -57058,7 +57368,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
57058
57368
|
continue;
|
|
57059
57369
|
}
|
|
57060
57370
|
try {
|
|
57061
|
-
const content =
|
|
57371
|
+
const content = fs28.readFileSync(fullPath, "utf-8");
|
|
57062
57372
|
const lines = countCodeLines(content);
|
|
57063
57373
|
callback(lines);
|
|
57064
57374
|
} catch {}
|
|
@@ -57272,8 +57582,8 @@ async function qualityBudget(input, directory) {
|
|
|
57272
57582
|
init_dist();
|
|
57273
57583
|
init_manager();
|
|
57274
57584
|
init_detector();
|
|
57275
|
-
import * as
|
|
57276
|
-
import * as
|
|
57585
|
+
import * as fs29 from "fs";
|
|
57586
|
+
import * as path42 from "path";
|
|
57277
57587
|
import { extname as extname9 } from "path";
|
|
57278
57588
|
|
|
57279
57589
|
// src/sast/rules/c.ts
|
|
@@ -58021,7 +58331,7 @@ function mapSemgrepSeverity(severity) {
|
|
|
58021
58331
|
}
|
|
58022
58332
|
}
|
|
58023
58333
|
async function executeWithTimeout(command, args2, options) {
|
|
58024
|
-
return new Promise((
|
|
58334
|
+
return new Promise((resolve14) => {
|
|
58025
58335
|
const child = spawn(command, args2, {
|
|
58026
58336
|
shell: false,
|
|
58027
58337
|
cwd: options.cwd
|
|
@@ -58030,7 +58340,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
58030
58340
|
let stderr = "";
|
|
58031
58341
|
const timeout = setTimeout(() => {
|
|
58032
58342
|
child.kill("SIGTERM");
|
|
58033
|
-
|
|
58343
|
+
resolve14({
|
|
58034
58344
|
stdout,
|
|
58035
58345
|
stderr: "Process timed out",
|
|
58036
58346
|
exitCode: 124
|
|
@@ -58044,7 +58354,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
58044
58354
|
});
|
|
58045
58355
|
child.on("close", (code) => {
|
|
58046
58356
|
clearTimeout(timeout);
|
|
58047
|
-
|
|
58357
|
+
resolve14({
|
|
58048
58358
|
stdout,
|
|
58049
58359
|
stderr,
|
|
58050
58360
|
exitCode: code ?? 0
|
|
@@ -58052,7 +58362,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
58052
58362
|
});
|
|
58053
58363
|
child.on("error", (err2) => {
|
|
58054
58364
|
clearTimeout(timeout);
|
|
58055
|
-
|
|
58365
|
+
resolve14({
|
|
58056
58366
|
stdout,
|
|
58057
58367
|
stderr: err2.message,
|
|
58058
58368
|
exitCode: 1
|
|
@@ -58140,17 +58450,17 @@ var SEVERITY_ORDER = {
|
|
|
58140
58450
|
};
|
|
58141
58451
|
function shouldSkipFile(filePath) {
|
|
58142
58452
|
try {
|
|
58143
|
-
const stats =
|
|
58453
|
+
const stats = fs29.statSync(filePath);
|
|
58144
58454
|
if (stats.size > MAX_FILE_SIZE_BYTES6) {
|
|
58145
58455
|
return { skip: true, reason: "file too large" };
|
|
58146
58456
|
}
|
|
58147
58457
|
if (stats.size === 0) {
|
|
58148
58458
|
return { skip: true, reason: "empty file" };
|
|
58149
58459
|
}
|
|
58150
|
-
const fd =
|
|
58460
|
+
const fd = fs29.openSync(filePath, "r");
|
|
58151
58461
|
const buffer = Buffer.alloc(8192);
|
|
58152
|
-
const bytesRead =
|
|
58153
|
-
|
|
58462
|
+
const bytesRead = fs29.readSync(fd, buffer, 0, 8192, 0);
|
|
58463
|
+
fs29.closeSync(fd);
|
|
58154
58464
|
if (bytesRead > 0) {
|
|
58155
58465
|
let nullCount = 0;
|
|
58156
58466
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -58189,7 +58499,7 @@ function countBySeverity(findings) {
|
|
|
58189
58499
|
}
|
|
58190
58500
|
function scanFileWithTierA(filePath, language) {
|
|
58191
58501
|
try {
|
|
58192
|
-
const content =
|
|
58502
|
+
const content = fs29.readFileSync(filePath, "utf-8");
|
|
58193
58503
|
const findings = executeRulesSync(filePath, content, language);
|
|
58194
58504
|
return findings.map((f) => ({
|
|
58195
58505
|
rule_id: f.rule_id,
|
|
@@ -58236,8 +58546,8 @@ async function sastScan(input, directory, config3) {
|
|
|
58236
58546
|
_filesSkipped++;
|
|
58237
58547
|
continue;
|
|
58238
58548
|
}
|
|
58239
|
-
const resolvedPath =
|
|
58240
|
-
if (!
|
|
58549
|
+
const resolvedPath = path42.isAbsolute(filePath) ? filePath : path42.resolve(directory, filePath);
|
|
58550
|
+
if (!fs29.existsSync(resolvedPath)) {
|
|
58241
58551
|
_filesSkipped++;
|
|
58242
58552
|
continue;
|
|
58243
58553
|
}
|
|
@@ -58435,18 +58745,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
58435
58745
|
let resolved;
|
|
58436
58746
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
58437
58747
|
if (isWinAbs) {
|
|
58438
|
-
resolved =
|
|
58439
|
-
} else if (
|
|
58440
|
-
resolved =
|
|
58748
|
+
resolved = path43.win32.resolve(inputPath);
|
|
58749
|
+
} else if (path43.isAbsolute(inputPath)) {
|
|
58750
|
+
resolved = path43.resolve(inputPath);
|
|
58441
58751
|
} else {
|
|
58442
|
-
resolved =
|
|
58752
|
+
resolved = path43.resolve(baseDir, inputPath);
|
|
58443
58753
|
}
|
|
58444
|
-
const workspaceResolved =
|
|
58754
|
+
const workspaceResolved = path43.resolve(workspaceDir);
|
|
58445
58755
|
let relative5;
|
|
58446
58756
|
if (isWinAbs) {
|
|
58447
|
-
relative5 =
|
|
58757
|
+
relative5 = path43.win32.relative(workspaceResolved, resolved);
|
|
58448
58758
|
} else {
|
|
58449
|
-
relative5 =
|
|
58759
|
+
relative5 = path43.relative(workspaceResolved, resolved);
|
|
58450
58760
|
}
|
|
58451
58761
|
if (relative5.startsWith("..")) {
|
|
58452
58762
|
return "path traversal detected";
|
|
@@ -58507,13 +58817,13 @@ async function runLintWrapped(files, directory, _config) {
|
|
|
58507
58817
|
}
|
|
58508
58818
|
async function runLintOnFiles(linter, files, workspaceDir) {
|
|
58509
58819
|
const isWindows = process.platform === "win32";
|
|
58510
|
-
const binDir =
|
|
58820
|
+
const binDir = path43.join(workspaceDir, "node_modules", ".bin");
|
|
58511
58821
|
const validatedFiles = [];
|
|
58512
58822
|
for (const file3 of files) {
|
|
58513
58823
|
if (typeof file3 !== "string") {
|
|
58514
58824
|
continue;
|
|
58515
58825
|
}
|
|
58516
|
-
const resolvedPath =
|
|
58826
|
+
const resolvedPath = path43.resolve(file3);
|
|
58517
58827
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
58518
58828
|
if (validationError) {
|
|
58519
58829
|
continue;
|
|
@@ -58531,10 +58841,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
58531
58841
|
}
|
|
58532
58842
|
let command;
|
|
58533
58843
|
if (linter === "biome") {
|
|
58534
|
-
const biomeBin = isWindows ?
|
|
58844
|
+
const biomeBin = isWindows ? path43.join(binDir, "biome.EXE") : path43.join(binDir, "biome");
|
|
58535
58845
|
command = [biomeBin, "check", ...validatedFiles];
|
|
58536
58846
|
} else {
|
|
58537
|
-
const eslintBin = isWindows ?
|
|
58847
|
+
const eslintBin = isWindows ? path43.join(binDir, "eslint.cmd") : path43.join(binDir, "eslint");
|
|
58538
58848
|
command = [eslintBin, ...validatedFiles];
|
|
58539
58849
|
}
|
|
58540
58850
|
try {
|
|
@@ -58671,7 +58981,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
58671
58981
|
skippedFiles++;
|
|
58672
58982
|
continue;
|
|
58673
58983
|
}
|
|
58674
|
-
const resolvedPath =
|
|
58984
|
+
const resolvedPath = path43.resolve(file3);
|
|
58675
58985
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
58676
58986
|
if (validationError) {
|
|
58677
58987
|
skippedFiles++;
|
|
@@ -58689,14 +58999,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
58689
58999
|
};
|
|
58690
59000
|
}
|
|
58691
59001
|
for (const file3 of validatedFiles) {
|
|
58692
|
-
const ext =
|
|
59002
|
+
const ext = path43.extname(file3).toLowerCase();
|
|
58693
59003
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
58694
59004
|
skippedFiles++;
|
|
58695
59005
|
continue;
|
|
58696
59006
|
}
|
|
58697
59007
|
let stat2;
|
|
58698
59008
|
try {
|
|
58699
|
-
stat2 =
|
|
59009
|
+
stat2 = fs30.statSync(file3);
|
|
58700
59010
|
} catch {
|
|
58701
59011
|
skippedFiles++;
|
|
58702
59012
|
continue;
|
|
@@ -58707,7 +59017,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
58707
59017
|
}
|
|
58708
59018
|
let content;
|
|
58709
59019
|
try {
|
|
58710
|
-
const buffer =
|
|
59020
|
+
const buffer = fs30.readFileSync(file3);
|
|
58711
59021
|
if (buffer.includes(0)) {
|
|
58712
59022
|
skippedFiles++;
|
|
58713
59023
|
continue;
|
|
@@ -58848,7 +59158,7 @@ async function runPreCheckBatch(input, workspaceDir) {
|
|
|
58848
59158
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
58849
59159
|
continue;
|
|
58850
59160
|
}
|
|
58851
|
-
changedFiles.push(
|
|
59161
|
+
changedFiles.push(path43.resolve(directory, file3));
|
|
58852
59162
|
}
|
|
58853
59163
|
if (changedFiles.length === 0) {
|
|
58854
59164
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -58999,7 +59309,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
58999
59309
|
};
|
|
59000
59310
|
return JSON.stringify(errorResult, null, 2);
|
|
59001
59311
|
}
|
|
59002
|
-
const resolvedDirectory =
|
|
59312
|
+
const resolvedDirectory = path43.resolve(typedArgs.directory);
|
|
59003
59313
|
const workspaceAnchor = resolvedDirectory;
|
|
59004
59314
|
const dirError = validateDirectory3(resolvedDirectory, workspaceAnchor);
|
|
59005
59315
|
if (dirError) {
|
|
@@ -59106,8 +59416,8 @@ ${paginatedContent}`;
|
|
|
59106
59416
|
init_tool();
|
|
59107
59417
|
init_manager2();
|
|
59108
59418
|
init_create_tool();
|
|
59109
|
-
import * as
|
|
59110
|
-
import * as
|
|
59419
|
+
import * as fs31 from "fs";
|
|
59420
|
+
import * as path44 from "path";
|
|
59111
59421
|
function detectPlaceholderContent(args2) {
|
|
59112
59422
|
const issues = [];
|
|
59113
59423
|
const placeholderPattern = /^\[\w[\w\s]*\]$/;
|
|
@@ -59211,19 +59521,19 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
59211
59521
|
try {
|
|
59212
59522
|
await savePlan(dir, plan);
|
|
59213
59523
|
try {
|
|
59214
|
-
const markerPath =
|
|
59524
|
+
const markerPath = path44.join(dir, ".swarm", ".plan-write-marker");
|
|
59215
59525
|
const marker = JSON.stringify({
|
|
59216
59526
|
source: "save_plan",
|
|
59217
59527
|
timestamp: new Date().toISOString(),
|
|
59218
59528
|
phases_count: plan.phases.length,
|
|
59219
59529
|
tasks_count: tasksCount
|
|
59220
59530
|
});
|
|
59221
|
-
await
|
|
59531
|
+
await fs31.promises.writeFile(markerPath, marker, "utf8");
|
|
59222
59532
|
} catch {}
|
|
59223
59533
|
return {
|
|
59224
59534
|
success: true,
|
|
59225
59535
|
message: "Plan saved successfully",
|
|
59226
|
-
plan_path:
|
|
59536
|
+
plan_path: path44.join(dir, ".swarm", "plan.json"),
|
|
59227
59537
|
phases_count: plan.phases.length,
|
|
59228
59538
|
tasks_count: tasksCount
|
|
59229
59539
|
};
|
|
@@ -59261,8 +59571,8 @@ var save_plan = createSwarmTool({
|
|
|
59261
59571
|
// src/tools/sbom-generate.ts
|
|
59262
59572
|
init_dist();
|
|
59263
59573
|
init_manager();
|
|
59264
|
-
import * as
|
|
59265
|
-
import * as
|
|
59574
|
+
import * as fs32 from "fs";
|
|
59575
|
+
import * as path45 from "path";
|
|
59266
59576
|
|
|
59267
59577
|
// src/sbom/detectors/index.ts
|
|
59268
59578
|
init_utils();
|
|
@@ -60108,9 +60418,9 @@ function findManifestFiles(rootDir) {
|
|
|
60108
60418
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
60109
60419
|
function searchDir(dir) {
|
|
60110
60420
|
try {
|
|
60111
|
-
const entries =
|
|
60421
|
+
const entries = fs32.readdirSync(dir, { withFileTypes: true });
|
|
60112
60422
|
for (const entry of entries) {
|
|
60113
|
-
const fullPath =
|
|
60423
|
+
const fullPath = path45.join(dir, entry.name);
|
|
60114
60424
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
60115
60425
|
continue;
|
|
60116
60426
|
}
|
|
@@ -60119,7 +60429,7 @@ function findManifestFiles(rootDir) {
|
|
|
60119
60429
|
} else if (entry.isFile()) {
|
|
60120
60430
|
for (const pattern of patterns) {
|
|
60121
60431
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
60122
|
-
manifestFiles.push(
|
|
60432
|
+
manifestFiles.push(path45.relative(rootDir, fullPath));
|
|
60123
60433
|
break;
|
|
60124
60434
|
}
|
|
60125
60435
|
}
|
|
@@ -60135,13 +60445,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
60135
60445
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
60136
60446
|
for (const dir of directories) {
|
|
60137
60447
|
try {
|
|
60138
|
-
const entries =
|
|
60448
|
+
const entries = fs32.readdirSync(dir, { withFileTypes: true });
|
|
60139
60449
|
for (const entry of entries) {
|
|
60140
|
-
const fullPath =
|
|
60450
|
+
const fullPath = path45.join(dir, entry.name);
|
|
60141
60451
|
if (entry.isFile()) {
|
|
60142
60452
|
for (const pattern of patterns) {
|
|
60143
60453
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
60144
|
-
found.push(
|
|
60454
|
+
found.push(path45.relative(workingDir, fullPath));
|
|
60145
60455
|
break;
|
|
60146
60456
|
}
|
|
60147
60457
|
}
|
|
@@ -60154,11 +60464,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
60154
60464
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
60155
60465
|
const dirs = new Set;
|
|
60156
60466
|
for (const file3 of changedFiles) {
|
|
60157
|
-
let currentDir =
|
|
60467
|
+
let currentDir = path45.dirname(file3);
|
|
60158
60468
|
while (true) {
|
|
60159
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
60160
|
-
dirs.add(
|
|
60161
|
-
const parent =
|
|
60469
|
+
if (currentDir && currentDir !== "." && currentDir !== path45.sep) {
|
|
60470
|
+
dirs.add(path45.join(workingDir, currentDir));
|
|
60471
|
+
const parent = path45.dirname(currentDir);
|
|
60162
60472
|
if (parent === currentDir)
|
|
60163
60473
|
break;
|
|
60164
60474
|
currentDir = parent;
|
|
@@ -60172,7 +60482,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
60172
60482
|
}
|
|
60173
60483
|
function ensureOutputDir(outputDir) {
|
|
60174
60484
|
try {
|
|
60175
|
-
|
|
60485
|
+
fs32.mkdirSync(outputDir, { recursive: true });
|
|
60176
60486
|
} catch (error93) {
|
|
60177
60487
|
if (!error93 || error93.code !== "EEXIST") {
|
|
60178
60488
|
throw error93;
|
|
@@ -60242,7 +60552,7 @@ var sbom_generate = createSwarmTool({
|
|
|
60242
60552
|
const changedFiles = obj.changed_files;
|
|
60243
60553
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
60244
60554
|
const workingDir = directory;
|
|
60245
|
-
const outputDir =
|
|
60555
|
+
const outputDir = path45.isAbsolute(relativeOutputDir) ? relativeOutputDir : path45.join(workingDir, relativeOutputDir);
|
|
60246
60556
|
let manifestFiles = [];
|
|
60247
60557
|
if (scope === "all") {
|
|
60248
60558
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -60265,11 +60575,11 @@ var sbom_generate = createSwarmTool({
|
|
|
60265
60575
|
const processedFiles = [];
|
|
60266
60576
|
for (const manifestFile of manifestFiles) {
|
|
60267
60577
|
try {
|
|
60268
|
-
const fullPath =
|
|
60269
|
-
if (!
|
|
60578
|
+
const fullPath = path45.isAbsolute(manifestFile) ? manifestFile : path45.join(workingDir, manifestFile);
|
|
60579
|
+
if (!fs32.existsSync(fullPath)) {
|
|
60270
60580
|
continue;
|
|
60271
60581
|
}
|
|
60272
|
-
const content =
|
|
60582
|
+
const content = fs32.readFileSync(fullPath, "utf-8");
|
|
60273
60583
|
const components = detectComponents(manifestFile, content);
|
|
60274
60584
|
processedFiles.push(manifestFile);
|
|
60275
60585
|
if (components.length > 0) {
|
|
@@ -60282,8 +60592,8 @@ var sbom_generate = createSwarmTool({
|
|
|
60282
60592
|
const bom = generateCycloneDX(allComponents);
|
|
60283
60593
|
const bomJson = serializeCycloneDX(bom);
|
|
60284
60594
|
const filename = generateSbomFilename();
|
|
60285
|
-
const outputPath =
|
|
60286
|
-
|
|
60595
|
+
const outputPath = path45.join(outputDir, filename);
|
|
60596
|
+
fs32.writeFileSync(outputPath, bomJson, "utf-8");
|
|
60287
60597
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
60288
60598
|
try {
|
|
60289
60599
|
const timestamp = new Date().toISOString();
|
|
@@ -60325,8 +60635,8 @@ var sbom_generate = createSwarmTool({
|
|
|
60325
60635
|
// src/tools/schema-drift.ts
|
|
60326
60636
|
init_dist();
|
|
60327
60637
|
init_create_tool();
|
|
60328
|
-
import * as
|
|
60329
|
-
import * as
|
|
60638
|
+
import * as fs33 from "fs";
|
|
60639
|
+
import * as path46 from "path";
|
|
60330
60640
|
var SPEC_CANDIDATES = [
|
|
60331
60641
|
"openapi.json",
|
|
60332
60642
|
"openapi.yaml",
|
|
@@ -60358,28 +60668,28 @@ function normalizePath2(p) {
|
|
|
60358
60668
|
}
|
|
60359
60669
|
function discoverSpecFile(cwd, specFileArg) {
|
|
60360
60670
|
if (specFileArg) {
|
|
60361
|
-
const resolvedPath =
|
|
60362
|
-
const normalizedCwd = cwd.endsWith(
|
|
60671
|
+
const resolvedPath = path46.resolve(cwd, specFileArg);
|
|
60672
|
+
const normalizedCwd = cwd.endsWith(path46.sep) ? cwd : cwd + path46.sep;
|
|
60363
60673
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
60364
60674
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
60365
60675
|
}
|
|
60366
|
-
const ext =
|
|
60676
|
+
const ext = path46.extname(resolvedPath).toLowerCase();
|
|
60367
60677
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
60368
60678
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
60369
60679
|
}
|
|
60370
|
-
const stats =
|
|
60680
|
+
const stats = fs33.statSync(resolvedPath);
|
|
60371
60681
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
60372
60682
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
60373
60683
|
}
|
|
60374
|
-
if (!
|
|
60684
|
+
if (!fs33.existsSync(resolvedPath)) {
|
|
60375
60685
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
60376
60686
|
}
|
|
60377
60687
|
return resolvedPath;
|
|
60378
60688
|
}
|
|
60379
60689
|
for (const candidate of SPEC_CANDIDATES) {
|
|
60380
|
-
const candidatePath =
|
|
60381
|
-
if (
|
|
60382
|
-
const stats =
|
|
60690
|
+
const candidatePath = path46.resolve(cwd, candidate);
|
|
60691
|
+
if (fs33.existsSync(candidatePath)) {
|
|
60692
|
+
const stats = fs33.statSync(candidatePath);
|
|
60383
60693
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
60384
60694
|
return candidatePath;
|
|
60385
60695
|
}
|
|
@@ -60388,8 +60698,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
60388
60698
|
return null;
|
|
60389
60699
|
}
|
|
60390
60700
|
function parseSpec(specFile) {
|
|
60391
|
-
const content =
|
|
60392
|
-
const ext =
|
|
60701
|
+
const content = fs33.readFileSync(specFile, "utf-8");
|
|
60702
|
+
const ext = path46.extname(specFile).toLowerCase();
|
|
60393
60703
|
if (ext === ".json") {
|
|
60394
60704
|
return parseJsonSpec(content);
|
|
60395
60705
|
}
|
|
@@ -60460,12 +60770,12 @@ function extractRoutes(cwd) {
|
|
|
60460
60770
|
function walkDir(dir) {
|
|
60461
60771
|
let entries;
|
|
60462
60772
|
try {
|
|
60463
|
-
entries =
|
|
60773
|
+
entries = fs33.readdirSync(dir, { withFileTypes: true });
|
|
60464
60774
|
} catch {
|
|
60465
60775
|
return;
|
|
60466
60776
|
}
|
|
60467
60777
|
for (const entry of entries) {
|
|
60468
|
-
const fullPath =
|
|
60778
|
+
const fullPath = path46.join(dir, entry.name);
|
|
60469
60779
|
if (entry.isSymbolicLink()) {
|
|
60470
60780
|
continue;
|
|
60471
60781
|
}
|
|
@@ -60475,7 +60785,7 @@ function extractRoutes(cwd) {
|
|
|
60475
60785
|
}
|
|
60476
60786
|
walkDir(fullPath);
|
|
60477
60787
|
} else if (entry.isFile()) {
|
|
60478
|
-
const ext =
|
|
60788
|
+
const ext = path46.extname(entry.name).toLowerCase();
|
|
60479
60789
|
const baseName = entry.name.toLowerCase();
|
|
60480
60790
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
60481
60791
|
continue;
|
|
@@ -60493,7 +60803,7 @@ function extractRoutes(cwd) {
|
|
|
60493
60803
|
}
|
|
60494
60804
|
function extractRoutesFromFile(filePath) {
|
|
60495
60805
|
const routes = [];
|
|
60496
|
-
const content =
|
|
60806
|
+
const content = fs33.readFileSync(filePath, "utf-8");
|
|
60497
60807
|
const lines = content.split(/\r?\n/);
|
|
60498
60808
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
60499
60809
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -60644,8 +60954,8 @@ init_secretscan();
|
|
|
60644
60954
|
// src/tools/symbols.ts
|
|
60645
60955
|
init_tool();
|
|
60646
60956
|
init_create_tool();
|
|
60647
|
-
import * as
|
|
60648
|
-
import * as
|
|
60957
|
+
import * as fs34 from "fs";
|
|
60958
|
+
import * as path47 from "path";
|
|
60649
60959
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
60650
60960
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
60651
60961
|
function containsControlCharacters(str) {
|
|
@@ -60674,11 +60984,11 @@ function containsWindowsAttacks(str) {
|
|
|
60674
60984
|
}
|
|
60675
60985
|
function isPathInWorkspace(filePath, workspace) {
|
|
60676
60986
|
try {
|
|
60677
|
-
const resolvedPath =
|
|
60678
|
-
const realWorkspace =
|
|
60679
|
-
const realResolvedPath =
|
|
60680
|
-
const relativePath =
|
|
60681
|
-
if (relativePath.startsWith("..") ||
|
|
60987
|
+
const resolvedPath = path47.resolve(workspace, filePath);
|
|
60988
|
+
const realWorkspace = fs34.realpathSync(workspace);
|
|
60989
|
+
const realResolvedPath = fs34.realpathSync(resolvedPath);
|
|
60990
|
+
const relativePath = path47.relative(realWorkspace, realResolvedPath);
|
|
60991
|
+
if (relativePath.startsWith("..") || path47.isAbsolute(relativePath)) {
|
|
60682
60992
|
return false;
|
|
60683
60993
|
}
|
|
60684
60994
|
return true;
|
|
@@ -60690,17 +61000,17 @@ function validatePathForRead(filePath, workspace) {
|
|
|
60690
61000
|
return isPathInWorkspace(filePath, workspace);
|
|
60691
61001
|
}
|
|
60692
61002
|
function extractTSSymbols(filePath, cwd) {
|
|
60693
|
-
const fullPath =
|
|
61003
|
+
const fullPath = path47.join(cwd, filePath);
|
|
60694
61004
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
60695
61005
|
return [];
|
|
60696
61006
|
}
|
|
60697
61007
|
let content;
|
|
60698
61008
|
try {
|
|
60699
|
-
const stats =
|
|
61009
|
+
const stats = fs34.statSync(fullPath);
|
|
60700
61010
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
60701
61011
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
60702
61012
|
}
|
|
60703
|
-
content =
|
|
61013
|
+
content = fs34.readFileSync(fullPath, "utf-8");
|
|
60704
61014
|
} catch {
|
|
60705
61015
|
return [];
|
|
60706
61016
|
}
|
|
@@ -60842,17 +61152,17 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
60842
61152
|
});
|
|
60843
61153
|
}
|
|
60844
61154
|
function extractPythonSymbols(filePath, cwd) {
|
|
60845
|
-
const fullPath =
|
|
61155
|
+
const fullPath = path47.join(cwd, filePath);
|
|
60846
61156
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
60847
61157
|
return [];
|
|
60848
61158
|
}
|
|
60849
61159
|
let content;
|
|
60850
61160
|
try {
|
|
60851
|
-
const stats =
|
|
61161
|
+
const stats = fs34.statSync(fullPath);
|
|
60852
61162
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
60853
61163
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
60854
61164
|
}
|
|
60855
|
-
content =
|
|
61165
|
+
content = fs34.readFileSync(fullPath, "utf-8");
|
|
60856
61166
|
} catch {
|
|
60857
61167
|
return [];
|
|
60858
61168
|
}
|
|
@@ -60925,7 +61235,7 @@ var symbols = createSwarmTool({
|
|
|
60925
61235
|
}, null, 2);
|
|
60926
61236
|
}
|
|
60927
61237
|
const cwd = directory;
|
|
60928
|
-
const ext =
|
|
61238
|
+
const ext = path47.extname(file3);
|
|
60929
61239
|
if (containsControlCharacters(file3)) {
|
|
60930
61240
|
return JSON.stringify({
|
|
60931
61241
|
file: file3,
|
|
@@ -60996,8 +61306,8 @@ init_test_runner();
|
|
|
60996
61306
|
init_dist();
|
|
60997
61307
|
init_utils();
|
|
60998
61308
|
init_create_tool();
|
|
60999
|
-
import * as
|
|
61000
|
-
import * as
|
|
61309
|
+
import * as fs35 from "fs";
|
|
61310
|
+
import * as path48 from "path";
|
|
61001
61311
|
var MAX_TEXT_LENGTH = 200;
|
|
61002
61312
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
61003
61313
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
@@ -61068,9 +61378,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
61068
61378
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
61069
61379
|
}
|
|
61070
61380
|
try {
|
|
61071
|
-
const resolvedPath =
|
|
61072
|
-
const normalizedCwd =
|
|
61073
|
-
const normalizedResolved =
|
|
61381
|
+
const resolvedPath = path48.resolve(paths);
|
|
61382
|
+
const normalizedCwd = path48.resolve(cwd);
|
|
61383
|
+
const normalizedResolved = path48.resolve(resolvedPath);
|
|
61074
61384
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
61075
61385
|
return {
|
|
61076
61386
|
error: "paths must be within the current working directory",
|
|
@@ -61086,13 +61396,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
61086
61396
|
}
|
|
61087
61397
|
}
|
|
61088
61398
|
function isSupportedExtension(filePath) {
|
|
61089
|
-
const ext =
|
|
61399
|
+
const ext = path48.extname(filePath).toLowerCase();
|
|
61090
61400
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
61091
61401
|
}
|
|
61092
61402
|
function findSourceFiles3(dir, files = []) {
|
|
61093
61403
|
let entries;
|
|
61094
61404
|
try {
|
|
61095
|
-
entries =
|
|
61405
|
+
entries = fs35.readdirSync(dir);
|
|
61096
61406
|
} catch {
|
|
61097
61407
|
return files;
|
|
61098
61408
|
}
|
|
@@ -61101,10 +61411,10 @@ function findSourceFiles3(dir, files = []) {
|
|
|
61101
61411
|
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
61102
61412
|
continue;
|
|
61103
61413
|
}
|
|
61104
|
-
const fullPath =
|
|
61414
|
+
const fullPath = path48.join(dir, entry);
|
|
61105
61415
|
let stat2;
|
|
61106
61416
|
try {
|
|
61107
|
-
stat2 =
|
|
61417
|
+
stat2 = fs35.statSync(fullPath);
|
|
61108
61418
|
} catch {
|
|
61109
61419
|
continue;
|
|
61110
61420
|
}
|
|
@@ -61197,7 +61507,7 @@ var todo_extract = createSwarmTool({
|
|
|
61197
61507
|
return JSON.stringify(errorResult, null, 2);
|
|
61198
61508
|
}
|
|
61199
61509
|
const scanPath = resolvedPath;
|
|
61200
|
-
if (!
|
|
61510
|
+
if (!fs35.existsSync(scanPath)) {
|
|
61201
61511
|
const errorResult = {
|
|
61202
61512
|
error: `path not found: ${pathsInput}`,
|
|
61203
61513
|
total: 0,
|
|
@@ -61207,13 +61517,13 @@ var todo_extract = createSwarmTool({
|
|
|
61207
61517
|
return JSON.stringify(errorResult, null, 2);
|
|
61208
61518
|
}
|
|
61209
61519
|
const filesToScan = [];
|
|
61210
|
-
const stat2 =
|
|
61520
|
+
const stat2 = fs35.statSync(scanPath);
|
|
61211
61521
|
if (stat2.isFile()) {
|
|
61212
61522
|
if (isSupportedExtension(scanPath)) {
|
|
61213
61523
|
filesToScan.push(scanPath);
|
|
61214
61524
|
} else {
|
|
61215
61525
|
const errorResult = {
|
|
61216
|
-
error: `unsupported file extension: ${
|
|
61526
|
+
error: `unsupported file extension: ${path48.extname(scanPath)}`,
|
|
61217
61527
|
total: 0,
|
|
61218
61528
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
61219
61529
|
entries: []
|
|
@@ -61226,11 +61536,11 @@ var todo_extract = createSwarmTool({
|
|
|
61226
61536
|
const allEntries = [];
|
|
61227
61537
|
for (const filePath of filesToScan) {
|
|
61228
61538
|
try {
|
|
61229
|
-
const fileStat =
|
|
61539
|
+
const fileStat = fs35.statSync(filePath);
|
|
61230
61540
|
if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
|
|
61231
61541
|
continue;
|
|
61232
61542
|
}
|
|
61233
|
-
const content =
|
|
61543
|
+
const content = fs35.readFileSync(filePath, "utf-8");
|
|
61234
61544
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
61235
61545
|
allEntries.push(...entries);
|
|
61236
61546
|
} catch {}
|
|
@@ -61259,8 +61569,8 @@ var todo_extract = createSwarmTool({
|
|
|
61259
61569
|
init_tool();
|
|
61260
61570
|
init_schema();
|
|
61261
61571
|
init_manager2();
|
|
61262
|
-
import * as
|
|
61263
|
-
import * as
|
|
61572
|
+
import * as fs36 from "fs";
|
|
61573
|
+
import * as path49 from "path";
|
|
61264
61574
|
init_create_tool();
|
|
61265
61575
|
var VALID_STATUSES2 = [
|
|
61266
61576
|
"pending",
|
|
@@ -61285,8 +61595,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
61285
61595
|
try {
|
|
61286
61596
|
const resolvedDir = workingDirectory ?? process.cwd();
|
|
61287
61597
|
try {
|
|
61288
|
-
const evidencePath =
|
|
61289
|
-
const raw =
|
|
61598
|
+
const evidencePath = path49.join(resolvedDir, ".swarm", "evidence", `${taskId}.json`);
|
|
61599
|
+
const raw = fs36.readFileSync(evidencePath, "utf-8");
|
|
61290
61600
|
const evidence = JSON.parse(raw);
|
|
61291
61601
|
if (evidence?.required_gates && Array.isArray(evidence.required_gates) && evidence?.gates) {
|
|
61292
61602
|
const allGatesMet = evidence.required_gates.every((gate) => evidence.gates[gate] != null);
|
|
@@ -61326,8 +61636,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
61326
61636
|
}
|
|
61327
61637
|
try {
|
|
61328
61638
|
const resolvedDir2 = workingDirectory ?? process.cwd();
|
|
61329
|
-
const planPath =
|
|
61330
|
-
const planRaw =
|
|
61639
|
+
const planPath = path49.join(resolvedDir2, ".swarm", "plan.json");
|
|
61640
|
+
const planRaw = fs36.readFileSync(planPath, "utf-8");
|
|
61331
61641
|
const plan = JSON.parse(planRaw);
|
|
61332
61642
|
for (const planPhase of plan.phases ?? []) {
|
|
61333
61643
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -61437,8 +61747,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
61437
61747
|
};
|
|
61438
61748
|
}
|
|
61439
61749
|
}
|
|
61440
|
-
normalizedDir =
|
|
61441
|
-
const pathParts = normalizedDir.split(
|
|
61750
|
+
normalizedDir = path49.normalize(args2.working_directory);
|
|
61751
|
+
const pathParts = normalizedDir.split(path49.sep);
|
|
61442
61752
|
if (pathParts.includes("..")) {
|
|
61443
61753
|
return {
|
|
61444
61754
|
success: false,
|
|
@@ -61448,11 +61758,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
61448
61758
|
]
|
|
61449
61759
|
};
|
|
61450
61760
|
}
|
|
61451
|
-
const resolvedDir =
|
|
61761
|
+
const resolvedDir = path49.resolve(normalizedDir);
|
|
61452
61762
|
try {
|
|
61453
|
-
const realPath =
|
|
61454
|
-
const planPath =
|
|
61455
|
-
if (!
|
|
61763
|
+
const realPath = fs36.realpathSync(resolvedDir);
|
|
61764
|
+
const planPath = path49.join(realPath, ".swarm", "plan.json");
|
|
61765
|
+
if (!fs36.existsSync(planPath)) {
|
|
61456
61766
|
return {
|
|
61457
61767
|
success: false,
|
|
61458
61768
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -61609,7 +61919,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
61609
61919
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
61610
61920
|
preflightTriggerManager = new PTM(automationConfig);
|
|
61611
61921
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
61612
|
-
const swarmDir =
|
|
61922
|
+
const swarmDir = path50.resolve(ctx.directory, ".swarm");
|
|
61613
61923
|
statusArtifact = new ASA(swarmDir);
|
|
61614
61924
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
61615
61925
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -61703,6 +62013,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
61703
62013
|
name: "opencode-swarm",
|
|
61704
62014
|
agent: agents,
|
|
61705
62015
|
tool: {
|
|
62016
|
+
check_gate_status,
|
|
61706
62017
|
checkpoint,
|
|
61707
62018
|
complexity_hotspots,
|
|
61708
62019
|
detect_domains,
|