opencode-swarm 6.13.2 → 6.13.3
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 -1
- package/dist/config/evidence-schema.d.ts +75 -3
- package/dist/hooks/system-enhancer.d.ts +7 -0
- package/dist/index.js +551 -272
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14001,7 +14001,23 @@ var init_evidence_schema = __esm(() => {
|
|
|
14001
14001
|
task_count: exports_external.number().int().min(1),
|
|
14002
14002
|
task_complexity: exports_external.enum(["trivial", "simple", "moderate", "complex"]),
|
|
14003
14003
|
top_rejection_reasons: exports_external.array(exports_external.string()).default([]),
|
|
14004
|
-
lessons_learned: exports_external.array(exports_external.string()).max(5).default([])
|
|
14004
|
+
lessons_learned: exports_external.array(exports_external.string()).max(5).default([]),
|
|
14005
|
+
user_directives: exports_external.array(exports_external.object({
|
|
14006
|
+
directive: exports_external.string().min(1),
|
|
14007
|
+
category: exports_external.enum([
|
|
14008
|
+
"tooling",
|
|
14009
|
+
"code_style",
|
|
14010
|
+
"architecture",
|
|
14011
|
+
"process",
|
|
14012
|
+
"other"
|
|
14013
|
+
]),
|
|
14014
|
+
scope: exports_external.enum(["session", "project", "global"])
|
|
14015
|
+
})).default([]),
|
|
14016
|
+
approaches_tried: exports_external.array(exports_external.object({
|
|
14017
|
+
approach: exports_external.string().min(1),
|
|
14018
|
+
result: exports_external.enum(["success", "failure", "partial"]),
|
|
14019
|
+
abandoned_reason: exports_external.string().optional()
|
|
14020
|
+
})).max(10).default([])
|
|
14005
14021
|
});
|
|
14006
14022
|
SyntaxEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14007
14023
|
type: exports_external.literal("syntax"),
|
|
@@ -31423,7 +31439,7 @@ var init_preflight_integration = __esm(() => {
|
|
|
31423
31439
|
});
|
|
31424
31440
|
|
|
31425
31441
|
// src/index.ts
|
|
31426
|
-
import * as
|
|
31442
|
+
import * as path31 from "path";
|
|
31427
31443
|
|
|
31428
31444
|
// src/tools/tool-names.ts
|
|
31429
31445
|
var TOOL_NAMES = [
|
|
@@ -32481,6 +32497,37 @@ Identify 1-3 relevant domains from the task requirements.
|
|
|
32481
32497
|
Call {{AGENT_PREFIX}}sme once per domain, serially. Max 3 SME calls per project phase.
|
|
32482
32498
|
Re-consult if a new domain emerges or if significant changes require fresh evaluation.
|
|
32483
32499
|
Cache guidance in context.md.
|
|
32500
|
+
### MODE: PRE-PHASE BRIEFING (Required Before Starting Any Phase)
|
|
32501
|
+
|
|
32502
|
+
Before creating or resuming any plan, you MUST read the previous phase's retrospective.
|
|
32503
|
+
|
|
32504
|
+
**Phase 2+ (continuing a multi-phase project):**
|
|
32505
|
+
1. Check \`.swarm/evidence/retro-{N-1}/evidence.json\` for the previous phase's retrospective
|
|
32506
|
+
2. If it exists: read and internalize \`lessons_learned\` and \`top_rejection_reasons\`
|
|
32507
|
+
3. If it does NOT exist: note this as a process gap, but proceed
|
|
32508
|
+
4. Print a briefing acknowledgment:
|
|
32509
|
+
\`\`\`
|
|
32510
|
+
\u2192 BRIEFING: Read Phase {N-1} retrospective.
|
|
32511
|
+
Key lessons: {list 1-3 most relevant lessons}
|
|
32512
|
+
Applying to Phase {N}: {one sentence on how you'll apply them}
|
|
32513
|
+
\`\`\`
|
|
32514
|
+
|
|
32515
|
+
**Phase 1 (starting any new project):**
|
|
32516
|
+
1. Scan \`.swarm/evidence/\` for any \`retro-*\` bundles from prior projects
|
|
32517
|
+
2. If found: review the 1-3 most recent retrospectives for relevant lessons
|
|
32518
|
+
3. Pay special attention to \`user_directives\` \u2014 these carry across projects
|
|
32519
|
+
4. Print a briefing acknowledgment:
|
|
32520
|
+
\`\`\`
|
|
32521
|
+
\u2192 BRIEFING: Reviewed {N} historical retrospectives from this workspace.
|
|
32522
|
+
Relevant lessons: {list applicable lessons}
|
|
32523
|
+
User directives carried forward: {list any persistent directives}
|
|
32524
|
+
\`\`\`
|
|
32525
|
+
OR if no historical retros exist:
|
|
32526
|
+
\`\`\`
|
|
32527
|
+
\u2192 BRIEFING: No historical retrospectives found. Starting fresh.
|
|
32528
|
+
\`\`\`
|
|
32529
|
+
|
|
32530
|
+
This briefing is a HARD REQUIREMENT for ALL phases. Skipping it is a process violation.
|
|
32484
32531
|
|
|
32485
32532
|
### MODE: PLAN
|
|
32486
32533
|
|
|
@@ -32497,6 +32544,15 @@ TASK GRANULARITY RULES:
|
|
|
32497
32544
|
- NEVER write a task with compound verbs: "implement X and add Y and update Z" = 3 tasks, not 1. Split before writing to plan.
|
|
32498
32545
|
- Coder receives ONE task. You make ALL scope decisions in the plan. Coder makes zero scope decisions.
|
|
32499
32546
|
|
|
32547
|
+
PHASE COUNT GUIDANCE:
|
|
32548
|
+
- Plans with 5+ tasks SHOULD be split into at least 2 phases.
|
|
32549
|
+
- Plans with 10+ tasks MUST be split into at least 3 phases.
|
|
32550
|
+
- Each phase should be a coherent unit of work that can be reviewed and learned from
|
|
32551
|
+
before proceeding to the next.
|
|
32552
|
+
- Single-phase plans are acceptable ONLY for small projects (1-4 tasks).
|
|
32553
|
+
- Rationale: Retrospectives at phase boundaries capture lessons that improve subsequent
|
|
32554
|
+
phases. A single-phase plan gets zero iterative learning benefit.
|
|
32555
|
+
|
|
32500
32556
|
Create .swarm/context.md
|
|
32501
32557
|
- Decisions, patterns, SME cache, file map
|
|
32502
32558
|
|
|
@@ -32634,6 +32690,54 @@ PRE-COMMIT RULE \u2014 Before ANY commit or push:
|
|
|
32634
32690
|
|
|
32635
32691
|
5o. Update plan.md [x], proceed to next task.
|
|
32636
32692
|
|
|
32693
|
+
## \u26D4 RETROSPECTIVE GATE
|
|
32694
|
+
|
|
32695
|
+
**MANDATORY before calling phase_complete.** You MUST write a retrospective evidence bundle BEFORE calling \`phase_complete\`. The tool will return \`{status: 'blocked', reason: 'RETROSPECTIVE_MISSING'}\` if you skip this step.
|
|
32696
|
+
|
|
32697
|
+
**How to write the retrospective:**
|
|
32698
|
+
|
|
32699
|
+
Use the evidence manager tool to write a bundle at \`retro-{N}\` (where N is the phase number being completed):
|
|
32700
|
+
|
|
32701
|
+
\`\`\`json
|
|
32702
|
+
{
|
|
32703
|
+
"type": "retrospective",
|
|
32704
|
+
"phase_number": <N>,
|
|
32705
|
+
"verdict": "pass",
|
|
32706
|
+
"reviewer_rejections": <count>,
|
|
32707
|
+
"coder_revisions": <count>,
|
|
32708
|
+
"test_failures": <count>,
|
|
32709
|
+
"security_findings": <count>,
|
|
32710
|
+
"lessons_learned": ["lesson 1 (max 5)", "lesson 2"],
|
|
32711
|
+
"top_rejection_reasons": ["reason 1"],
|
|
32712
|
+
"user_directives": [],
|
|
32713
|
+
"approaches_tried": [],
|
|
32714
|
+
"task_complexity": "low|medium|high",
|
|
32715
|
+
"timestamp": "<ISO 8601>",
|
|
32716
|
+
"agent": "architect",
|
|
32717
|
+
"metadata": { "plan_id": "<current plan title from .swarm/plan.json>" }
|
|
32718
|
+
}
|
|
32719
|
+
\`\`\`
|
|
32720
|
+
|
|
32721
|
+
**Required field rules:**
|
|
32722
|
+
- \`verdict\` MUST be \`"pass"\` \u2014 a verdict of \`"fail"\` or missing verdict blocks phase_complete
|
|
32723
|
+
- \`phase_number\` MUST match the phase number you are completing
|
|
32724
|
+
- \`lessons_learned\` should be 3-5 concrete, actionable items from this phase
|
|
32725
|
+
- Write the bundle as task_id \`retro-{N}\` (e.g., \`retro-1\` for Phase 1, \`retro-2\` for Phase 2)
|
|
32726
|
+
- \`metadata.plan_id\` should be set to the current project's plan title (from \`.swarm/plan.json\` header). This enables cross-project filtering in the retrospective injection system.
|
|
32727
|
+
|
|
32728
|
+
### Additional retrospective fields (capture when applicable):
|
|
32729
|
+
- \`user_directives\`: Any corrections or preferences the user expressed during this phase
|
|
32730
|
+
- \`directive\`: what the user said (non-empty string)
|
|
32731
|
+
- \`category\`: \`tooling\` | \`code_style\` | \`architecture\` | \`process\` | \`other\`
|
|
32732
|
+
- \`scope\`: \`session\` (one-time, do not carry forward) | \`project\` (persist to context.md) | \`global\` (user preference)
|
|
32733
|
+
- \`approaches_tried\`: Approaches attempted during this phase (max 10)
|
|
32734
|
+
- \`approach\`: what was tried (non-empty string)
|
|
32735
|
+
- \`result\`: \`success\` | \`failure\` | \`partial\`
|
|
32736
|
+
- \`abandoned_reason\`: why it was abandoned (required when result is \`failure\` or \`partial\`)
|
|
32737
|
+
|
|
32738
|
+
**\u26A0\uFE0F WARNING:** Calling \`phase_complete(N)\` without a valid \`retro-N\` bundle will be BLOCKED. The error response will be:
|
|
32739
|
+
\`{ "status": "blocked", "reason": "RETROSPECTIVE_MISSING" }\`
|
|
32740
|
+
|
|
32637
32741
|
### MODE: PHASE-WRAP
|
|
32638
32742
|
1. {{AGENT_PREFIX}}explorer - Rescan
|
|
32639
32743
|
2. {{AGENT_PREFIX}}docs - Update documentation for all changes in this phase. Provide:
|
|
@@ -37344,8 +37448,7 @@ ${originalText}`;
|
|
|
37344
37448
|
};
|
|
37345
37449
|
}
|
|
37346
37450
|
// src/hooks/system-enhancer.ts
|
|
37347
|
-
|
|
37348
|
-
import * as path17 from "path";
|
|
37451
|
+
init_manager();
|
|
37349
37452
|
init_manager2();
|
|
37350
37453
|
|
|
37351
37454
|
// src/services/decision-drift-analyzer.ts
|
|
@@ -37722,6 +37825,170 @@ function estimateContentType(text) {
|
|
|
37722
37825
|
}
|
|
37723
37826
|
return "prose";
|
|
37724
37827
|
}
|
|
37828
|
+
async function buildRetroInjection(directory, currentPhaseNumber, currentPlanTitle) {
|
|
37829
|
+
try {
|
|
37830
|
+
const prevPhase = currentPhaseNumber - 1;
|
|
37831
|
+
if (prevPhase >= 1) {
|
|
37832
|
+
const bundle = await loadEvidence(directory, `retro-${prevPhase}`);
|
|
37833
|
+
if (bundle && bundle.entries.length > 0) {
|
|
37834
|
+
const retroEntry = bundle.entries.find((entry) => entry.type === "retrospective");
|
|
37835
|
+
if (retroEntry && retroEntry.verdict !== "fail") {
|
|
37836
|
+
const lessons = retroEntry.lessons_learned ?? [];
|
|
37837
|
+
const rejections = retroEntry.top_rejection_reasons ?? [];
|
|
37838
|
+
const nonSessionDirectives = (retroEntry.user_directives ?? []).filter((d) => d.scope !== "session");
|
|
37839
|
+
let block = `## Previous Phase Retrospective (Phase ${prevPhase})
|
|
37840
|
+
**Outcome:** ${retroEntry.summary ?? "Phase completed."}
|
|
37841
|
+
**Rejection reasons:** ${rejections.join(", ") || "None"}
|
|
37842
|
+
**Lessons learned:**
|
|
37843
|
+
${lessons.map((l) => `- ${l}`).join(`
|
|
37844
|
+
`)}
|
|
37845
|
+
|
|
37846
|
+
\u26A0\uFE0F Apply these lessons to the current phase. Do not repeat the same mistakes.`;
|
|
37847
|
+
if (nonSessionDirectives.length > 0) {
|
|
37848
|
+
const top5 = nonSessionDirectives.slice(0, 5);
|
|
37849
|
+
block += `
|
|
37850
|
+
|
|
37851
|
+
## User Directives (from Phase ${prevPhase})
|
|
37852
|
+
${top5.map((d) => `- [${d.category}] ${d.directive}`).join(`
|
|
37853
|
+
`)}`;
|
|
37854
|
+
}
|
|
37855
|
+
return block;
|
|
37856
|
+
}
|
|
37857
|
+
}
|
|
37858
|
+
const taskIds = await listEvidenceTaskIds(directory);
|
|
37859
|
+
const retroIds = taskIds.filter((id) => id.startsWith("retro-"));
|
|
37860
|
+
let latestRetro = null;
|
|
37861
|
+
for (const taskId of retroIds) {
|
|
37862
|
+
const b = await loadEvidence(directory, taskId);
|
|
37863
|
+
if (b && b.entries.length > 0) {
|
|
37864
|
+
for (const entry of b.entries) {
|
|
37865
|
+
if (entry.type === "retrospective") {
|
|
37866
|
+
const retro = entry;
|
|
37867
|
+
if (retro.verdict !== "fail") {
|
|
37868
|
+
if (latestRetro === null || retro.phase_number > latestRetro.phase) {
|
|
37869
|
+
latestRetro = { entry: retro, phase: retro.phase_number };
|
|
37870
|
+
}
|
|
37871
|
+
}
|
|
37872
|
+
}
|
|
37873
|
+
}
|
|
37874
|
+
}
|
|
37875
|
+
}
|
|
37876
|
+
if (latestRetro) {
|
|
37877
|
+
const { entry, phase } = latestRetro;
|
|
37878
|
+
const lessons = entry.lessons_learned ?? [];
|
|
37879
|
+
const rejections = entry.top_rejection_reasons ?? [];
|
|
37880
|
+
const nonSessionDirectives = (entry.user_directives ?? []).filter((d) => d.scope !== "session");
|
|
37881
|
+
let block = `## Previous Phase Retrospective (Phase ${phase})
|
|
37882
|
+
**Outcome:** ${entry.summary ?? "Phase completed."}
|
|
37883
|
+
**Rejection reasons:** ${rejections.join(", ") || "None"}
|
|
37884
|
+
**Lessons learned:**
|
|
37885
|
+
${lessons.map((l) => `- ${l}`).join(`
|
|
37886
|
+
`)}
|
|
37887
|
+
|
|
37888
|
+
\u26A0\uFE0F Apply these lessons to the current phase. Do not repeat the same mistakes.`;
|
|
37889
|
+
if (nonSessionDirectives.length > 0) {
|
|
37890
|
+
const top5 = nonSessionDirectives.slice(0, 5);
|
|
37891
|
+
block += `
|
|
37892
|
+
|
|
37893
|
+
## User Directives (from Phase ${phase})
|
|
37894
|
+
${top5.map((d) => `- [${d.category}] ${d.directive}`).join(`
|
|
37895
|
+
`)}`;
|
|
37896
|
+
}
|
|
37897
|
+
return block;
|
|
37898
|
+
}
|
|
37899
|
+
return null;
|
|
37900
|
+
}
|
|
37901
|
+
const allTaskIds = await listEvidenceTaskIds(directory);
|
|
37902
|
+
const allRetroIds = allTaskIds.filter((id) => id.startsWith("retro-"));
|
|
37903
|
+
if (allRetroIds.length === 0) {
|
|
37904
|
+
return null;
|
|
37905
|
+
}
|
|
37906
|
+
const allRetros = [];
|
|
37907
|
+
const cutoffMs = 30 * 24 * 60 * 60 * 1000;
|
|
37908
|
+
const now = Date.now();
|
|
37909
|
+
for (const taskId of allRetroIds) {
|
|
37910
|
+
const b = await loadEvidence(directory, taskId);
|
|
37911
|
+
if (!b)
|
|
37912
|
+
continue;
|
|
37913
|
+
for (const e of b.entries) {
|
|
37914
|
+
if (e.type === "retrospective") {
|
|
37915
|
+
const retro = e;
|
|
37916
|
+
if (retro.verdict === "fail")
|
|
37917
|
+
continue;
|
|
37918
|
+
if (currentPlanTitle && typeof retro.metadata === "object" && retro.metadata !== null && "plan_id" in retro.metadata && retro.metadata.plan_id === currentPlanTitle)
|
|
37919
|
+
continue;
|
|
37920
|
+
const ts = retro.timestamp ?? b.created_at;
|
|
37921
|
+
const ageMs = now - new Date(ts).getTime();
|
|
37922
|
+
if (isNaN(ageMs) || ageMs > cutoffMs)
|
|
37923
|
+
continue;
|
|
37924
|
+
allRetros.push({ entry: retro, timestamp: ts });
|
|
37925
|
+
}
|
|
37926
|
+
}
|
|
37927
|
+
}
|
|
37928
|
+
if (allRetros.length === 0) {
|
|
37929
|
+
return null;
|
|
37930
|
+
}
|
|
37931
|
+
allRetros.sort((a, b) => {
|
|
37932
|
+
const ta = new Date(a.timestamp).getTime();
|
|
37933
|
+
const tb = new Date(b.timestamp).getTime();
|
|
37934
|
+
if (isNaN(ta) && isNaN(tb))
|
|
37935
|
+
return 0;
|
|
37936
|
+
if (isNaN(ta))
|
|
37937
|
+
return 1;
|
|
37938
|
+
if (isNaN(tb))
|
|
37939
|
+
return -1;
|
|
37940
|
+
return tb - ta;
|
|
37941
|
+
});
|
|
37942
|
+
const top3 = allRetros.slice(0, 3);
|
|
37943
|
+
const lines = [
|
|
37944
|
+
"## Historical Lessons (from recent prior projects)"
|
|
37945
|
+
];
|
|
37946
|
+
lines.push("Most recent retrospectives in this workspace:");
|
|
37947
|
+
const allCarriedDirectives = [];
|
|
37948
|
+
for (const { entry, timestamp } of top3) {
|
|
37949
|
+
const date9 = timestamp.split("T")[0] ?? "unknown";
|
|
37950
|
+
const summary = entry.summary ?? `Phase ${entry.phase_number} completed`;
|
|
37951
|
+
const topLesson = entry.lessons_learned?.[0] ?? "No lessons recorded";
|
|
37952
|
+
lines.push(`- Phase ${entry.phase_number} (${date9}): ${summary}`);
|
|
37953
|
+
lines.push(` Key lesson: ${topLesson}`);
|
|
37954
|
+
const nonSession = (entry.user_directives ?? []).filter((d) => d.scope !== "session");
|
|
37955
|
+
allCarriedDirectives.push(...nonSession);
|
|
37956
|
+
}
|
|
37957
|
+
if (allCarriedDirectives.length > 0) {
|
|
37958
|
+
const top5 = allCarriedDirectives.slice(0, 5);
|
|
37959
|
+
lines.push("User directives carried forward:");
|
|
37960
|
+
for (const d of top5) {
|
|
37961
|
+
lines.push(`- [${d.category}] ${d.directive}`);
|
|
37962
|
+
}
|
|
37963
|
+
}
|
|
37964
|
+
const tier2Block = lines.join(`
|
|
37965
|
+
`);
|
|
37966
|
+
return tier2Block.length <= 800 ? tier2Block : `${tier2Block.substring(0, 797)}...`;
|
|
37967
|
+
} catch {
|
|
37968
|
+
return null;
|
|
37969
|
+
}
|
|
37970
|
+
}
|
|
37971
|
+
async function buildCoderRetroInjection(directory, currentPhaseNumber) {
|
|
37972
|
+
try {
|
|
37973
|
+
const prevPhase = currentPhaseNumber - 1;
|
|
37974
|
+
if (prevPhase < 1)
|
|
37975
|
+
return null;
|
|
37976
|
+
const bundle = await loadEvidence(directory, `retro-${prevPhase}`);
|
|
37977
|
+
if (!bundle || bundle.entries.length === 0)
|
|
37978
|
+
return null;
|
|
37979
|
+
const retroEntry = bundle.entries.find((entry) => entry.type === "retrospective");
|
|
37980
|
+
if (!retroEntry || retroEntry.verdict === "fail")
|
|
37981
|
+
return null;
|
|
37982
|
+
const lessons = retroEntry.lessons_learned ?? [];
|
|
37983
|
+
const summaryLine = `[SWARM RETROSPECTIVE] From Phase ${prevPhase}:${retroEntry.summary ? " " + retroEntry.summary : ""}`;
|
|
37984
|
+
const allLines = [summaryLine, ...lessons];
|
|
37985
|
+
const text = allLines.join(`
|
|
37986
|
+
`);
|
|
37987
|
+
return text.length <= 400 ? text : `${text.substring(0, 397)}...`;
|
|
37988
|
+
} catch {
|
|
37989
|
+
return null;
|
|
37990
|
+
}
|
|
37991
|
+
}
|
|
37725
37992
|
function createSystemEnhancerHook(config3, directory) {
|
|
37726
37993
|
const enabled = config3.hooks?.system_enhancer !== false;
|
|
37727
37994
|
if (!enabled) {
|
|
@@ -37841,43 +38108,27 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
37841
38108
|
}
|
|
37842
38109
|
}
|
|
37843
38110
|
}
|
|
38111
|
+
if (baseRole === "coder") {
|
|
38112
|
+
try {
|
|
38113
|
+
const currentPhaseNum_coder = plan2?.current_phase ?? 1;
|
|
38114
|
+
const coderRetro = await buildCoderRetroInjection(directory, currentPhaseNum_coder);
|
|
38115
|
+
if (coderRetro) {
|
|
38116
|
+
tryInject(coderRetro);
|
|
38117
|
+
}
|
|
38118
|
+
} catch {}
|
|
38119
|
+
}
|
|
37844
38120
|
const sessionId_retro = _input.sessionID;
|
|
37845
38121
|
const activeAgent_retro = swarmState.activeAgent.get(sessionId_retro ?? "");
|
|
37846
38122
|
const isArchitect2 = !activeAgent_retro || stripKnownSwarmPrefix(activeAgent_retro) === "architect";
|
|
37847
38123
|
if (isArchitect2) {
|
|
37848
38124
|
try {
|
|
37849
|
-
const
|
|
37850
|
-
|
|
37851
|
-
|
|
37852
|
-
|
|
37853
|
-
|
|
37854
|
-
|
|
37855
|
-
|
|
37856
|
-
} catch {
|
|
37857
|
-
continue;
|
|
37858
|
-
}
|
|
37859
|
-
if (content !== null && typeof content === "object" && content.type === "retrospective") {
|
|
37860
|
-
const retro = content;
|
|
37861
|
-
const hints = [];
|
|
37862
|
-
if (retro.reviewer_rejections > 2) {
|
|
37863
|
-
hints.push(`Phase ${retro.phase_number} had ${retro.reviewer_rejections} reviewer rejections.`);
|
|
37864
|
-
}
|
|
37865
|
-
if (retro.top_rejection_reasons.length > 0) {
|
|
37866
|
-
hints.push(`Common rejection reasons: ${retro.top_rejection_reasons.join(", ")}.`);
|
|
37867
|
-
}
|
|
37868
|
-
if (retro.lessons_learned.length > 0) {
|
|
37869
|
-
hints.push(`Lessons: ${retro.lessons_learned.join("; ")}.`);
|
|
37870
|
-
}
|
|
37871
|
-
if (hints.length > 0) {
|
|
37872
|
-
const retroHint = `[SWARM RETROSPECTIVE] From Phase ${retro.phase_number}: ${hints.join(" ")}`;
|
|
37873
|
-
if (retroHint.length <= 800) {
|
|
37874
|
-
tryInject(retroHint);
|
|
37875
|
-
} else {
|
|
37876
|
-
tryInject(`${retroHint.substring(0, 800)}...`);
|
|
37877
|
-
}
|
|
37878
|
-
}
|
|
37879
|
-
break;
|
|
37880
|
-
}
|
|
38125
|
+
const currentPhaseNum = plan2?.current_phase ?? 1;
|
|
38126
|
+
const retroText = await buildRetroInjection(directory, currentPhaseNum, plan2?.title ?? undefined);
|
|
38127
|
+
if (retroText) {
|
|
38128
|
+
if (retroText.length <= 1600) {
|
|
38129
|
+
tryInject(retroText);
|
|
38130
|
+
} else {
|
|
38131
|
+
tryInject(`${retroText.substring(0, 1600)}...`);
|
|
37881
38132
|
}
|
|
37882
38133
|
}
|
|
37883
38134
|
} catch {}
|
|
@@ -38137,43 +38388,18 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
38137
38388
|
const isArchitect_b = !activeAgent_retro_b || stripKnownSwarmPrefix(activeAgent_retro_b) === "architect";
|
|
38138
38389
|
if (isArchitect_b) {
|
|
38139
38390
|
try {
|
|
38140
|
-
const
|
|
38141
|
-
|
|
38142
|
-
|
|
38143
|
-
|
|
38144
|
-
|
|
38145
|
-
|
|
38146
|
-
|
|
38147
|
-
|
|
38148
|
-
|
|
38149
|
-
|
|
38150
|
-
|
|
38151
|
-
|
|
38152
|
-
const hints_b = [];
|
|
38153
|
-
if (retro_b.reviewer_rejections > 2) {
|
|
38154
|
-
hints_b.push(`Phase ${retro_b.phase_number} had ${retro_b.reviewer_rejections} reviewer rejections.`);
|
|
38155
|
-
}
|
|
38156
|
-
if (retro_b.top_rejection_reasons.length > 0) {
|
|
38157
|
-
hints_b.push(`Common rejection reasons: ${retro_b.top_rejection_reasons.join(", ")}.`);
|
|
38158
|
-
}
|
|
38159
|
-
if (retro_b.lessons_learned.length > 0) {
|
|
38160
|
-
hints_b.push(`Lessons: ${retro_b.lessons_learned.join("; ")}.`);
|
|
38161
|
-
}
|
|
38162
|
-
if (hints_b.length > 0) {
|
|
38163
|
-
const retroHint_b = `[SWARM RETROSPECTIVE] From Phase ${retro_b.phase_number}: ${hints_b.join(" ")}`;
|
|
38164
|
-
const retroText = retroHint_b.length <= 800 ? retroHint_b : `${retroHint_b.substring(0, 800)}...`;
|
|
38165
|
-
candidates.push({
|
|
38166
|
-
id: `candidate-${idCounter++}`,
|
|
38167
|
-
kind: "phase",
|
|
38168
|
-
text: retroText,
|
|
38169
|
-
tokens: estimateTokens(retroText),
|
|
38170
|
-
priority: 2,
|
|
38171
|
-
metadata: { contentType: "prose" }
|
|
38172
|
-
});
|
|
38173
|
-
}
|
|
38174
|
-
break;
|
|
38175
|
-
}
|
|
38176
|
-
}
|
|
38391
|
+
const currentPhaseNum_b = plan?.current_phase ?? 1;
|
|
38392
|
+
const retroText_b = await buildRetroInjection(directory, currentPhaseNum_b, plan?.title ?? undefined);
|
|
38393
|
+
if (retroText_b) {
|
|
38394
|
+
const text = retroText_b.length <= 1600 ? retroText_b : `${retroText_b.substring(0, 1597)}...`;
|
|
38395
|
+
candidates.push({
|
|
38396
|
+
id: `candidate-${idCounter++}`,
|
|
38397
|
+
kind: "phase",
|
|
38398
|
+
text,
|
|
38399
|
+
tokens: estimateTokens(text),
|
|
38400
|
+
priority: 2,
|
|
38401
|
+
metadata: { contentType: "prose" }
|
|
38402
|
+
});
|
|
38177
38403
|
}
|
|
38178
38404
|
} catch {}
|
|
38179
38405
|
if (mode_b !== "DISCOVER") {
|
|
@@ -38211,6 +38437,24 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
38211
38437
|
}
|
|
38212
38438
|
}
|
|
38213
38439
|
}
|
|
38440
|
+
const activeAgent_coder_b = swarmState.activeAgent.get(_input.sessionID ?? "");
|
|
38441
|
+
const isCoder_b = activeAgent_coder_b && stripKnownSwarmPrefix(activeAgent_coder_b) === "coder";
|
|
38442
|
+
if (isCoder_b) {
|
|
38443
|
+
try {
|
|
38444
|
+
const currentPhaseNum_coder_b = plan?.current_phase ?? 1;
|
|
38445
|
+
const coderRetro_b = await buildCoderRetroInjection(directory, currentPhaseNum_coder_b);
|
|
38446
|
+
if (coderRetro_b) {
|
|
38447
|
+
candidates.push({
|
|
38448
|
+
id: `candidate-${idCounter++}`,
|
|
38449
|
+
kind: "agent_context",
|
|
38450
|
+
text: coderRetro_b,
|
|
38451
|
+
tokens: estimateTokens(coderRetro_b),
|
|
38452
|
+
priority: 2,
|
|
38453
|
+
metadata: { contentType: "prose" }
|
|
38454
|
+
});
|
|
38455
|
+
}
|
|
38456
|
+
} catch {}
|
|
38457
|
+
}
|
|
38214
38458
|
const automationCapabilities_b = config3.automation?.capabilities;
|
|
38215
38459
|
if (automationCapabilities_b?.decision_drift_detection === true && sessionId_retro_b) {
|
|
38216
38460
|
const activeAgentForDrift_b = swarmState.activeAgent.get(sessionId_retro_b ?? "");
|
|
@@ -38465,8 +38709,8 @@ init_dist();
|
|
|
38465
38709
|
|
|
38466
38710
|
// src/build/discovery.ts
|
|
38467
38711
|
init_dist();
|
|
38468
|
-
import * as
|
|
38469
|
-
import * as
|
|
38712
|
+
import * as fs11 from "fs";
|
|
38713
|
+
import * as path17 from "path";
|
|
38470
38714
|
var ECOSYSTEMS = [
|
|
38471
38715
|
{
|
|
38472
38716
|
ecosystem: "node",
|
|
@@ -38578,18 +38822,18 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
38578
38822
|
if (pattern.includes("*")) {
|
|
38579
38823
|
const dir = workingDir;
|
|
38580
38824
|
try {
|
|
38581
|
-
const files =
|
|
38825
|
+
const files = fs11.readdirSync(dir);
|
|
38582
38826
|
const matches = files.filter((f) => {
|
|
38583
38827
|
const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
|
|
38584
38828
|
return regex.test(f);
|
|
38585
38829
|
});
|
|
38586
38830
|
if (matches.length > 0) {
|
|
38587
|
-
return
|
|
38831
|
+
return path17.join(dir, matches[0]);
|
|
38588
38832
|
}
|
|
38589
38833
|
} catch {}
|
|
38590
38834
|
} else {
|
|
38591
|
-
const filePath =
|
|
38592
|
-
if (
|
|
38835
|
+
const filePath = path17.join(workingDir, pattern);
|
|
38836
|
+
if (fs11.existsSync(filePath)) {
|
|
38593
38837
|
return filePath;
|
|
38594
38838
|
}
|
|
38595
38839
|
}
|
|
@@ -38597,12 +38841,12 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
38597
38841
|
return null;
|
|
38598
38842
|
}
|
|
38599
38843
|
function getRepoDefinedScripts(workingDir, scripts) {
|
|
38600
|
-
const packageJsonPath =
|
|
38601
|
-
if (!
|
|
38844
|
+
const packageJsonPath = path17.join(workingDir, "package.json");
|
|
38845
|
+
if (!fs11.existsSync(packageJsonPath)) {
|
|
38602
38846
|
return [];
|
|
38603
38847
|
}
|
|
38604
38848
|
try {
|
|
38605
|
-
const content =
|
|
38849
|
+
const content = fs11.readFileSync(packageJsonPath, "utf-8");
|
|
38606
38850
|
const pkg = JSON.parse(content);
|
|
38607
38851
|
if (!pkg.scripts || typeof pkg.scripts !== "object") {
|
|
38608
38852
|
return [];
|
|
@@ -38638,8 +38882,8 @@ function findAllBuildFiles(workingDir) {
|
|
|
38638
38882
|
const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
|
|
38639
38883
|
findFilesRecursive(workingDir, regex, allBuildFiles);
|
|
38640
38884
|
} else {
|
|
38641
|
-
const filePath =
|
|
38642
|
-
if (
|
|
38885
|
+
const filePath = path17.join(workingDir, pattern);
|
|
38886
|
+
if (fs11.existsSync(filePath)) {
|
|
38643
38887
|
allBuildFiles.add(filePath);
|
|
38644
38888
|
}
|
|
38645
38889
|
}
|
|
@@ -38649,9 +38893,9 @@ function findAllBuildFiles(workingDir) {
|
|
|
38649
38893
|
}
|
|
38650
38894
|
function findFilesRecursive(dir, regex, results) {
|
|
38651
38895
|
try {
|
|
38652
|
-
const entries =
|
|
38896
|
+
const entries = fs11.readdirSync(dir, { withFileTypes: true });
|
|
38653
38897
|
for (const entry of entries) {
|
|
38654
|
-
const fullPath =
|
|
38898
|
+
const fullPath = path17.join(dir, entry.name);
|
|
38655
38899
|
if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
|
|
38656
38900
|
findFilesRecursive(fullPath, regex, results);
|
|
38657
38901
|
} else if (entry.isFile() && regex.test(entry.name)) {
|
|
@@ -38892,8 +39136,8 @@ var build_check = tool({
|
|
|
38892
39136
|
// src/tools/checkpoint.ts
|
|
38893
39137
|
init_tool();
|
|
38894
39138
|
import { spawnSync } from "child_process";
|
|
38895
|
-
import * as
|
|
38896
|
-
import * as
|
|
39139
|
+
import * as fs12 from "fs";
|
|
39140
|
+
import * as path18 from "path";
|
|
38897
39141
|
var CHECKPOINT_LOG_PATH = ".swarm/checkpoints.json";
|
|
38898
39142
|
var MAX_LABEL_LENGTH = 100;
|
|
38899
39143
|
var GIT_TIMEOUT_MS = 30000;
|
|
@@ -38944,13 +39188,13 @@ function validateLabel(label) {
|
|
|
38944
39188
|
return null;
|
|
38945
39189
|
}
|
|
38946
39190
|
function getCheckpointLogPath() {
|
|
38947
|
-
return
|
|
39191
|
+
return path18.join(process.cwd(), CHECKPOINT_LOG_PATH);
|
|
38948
39192
|
}
|
|
38949
39193
|
function readCheckpointLog() {
|
|
38950
39194
|
const logPath = getCheckpointLogPath();
|
|
38951
39195
|
try {
|
|
38952
|
-
if (
|
|
38953
|
-
const content =
|
|
39196
|
+
if (fs12.existsSync(logPath)) {
|
|
39197
|
+
const content = fs12.readFileSync(logPath, "utf-8");
|
|
38954
39198
|
const parsed = JSON.parse(content);
|
|
38955
39199
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
38956
39200
|
return { version: 1, checkpoints: [] };
|
|
@@ -38962,13 +39206,13 @@ function readCheckpointLog() {
|
|
|
38962
39206
|
}
|
|
38963
39207
|
function writeCheckpointLog(log2) {
|
|
38964
39208
|
const logPath = getCheckpointLogPath();
|
|
38965
|
-
const dir =
|
|
38966
|
-
if (!
|
|
38967
|
-
|
|
39209
|
+
const dir = path18.dirname(logPath);
|
|
39210
|
+
if (!fs12.existsSync(dir)) {
|
|
39211
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
38968
39212
|
}
|
|
38969
39213
|
const tempPath = `${logPath}.tmp`;
|
|
38970
|
-
|
|
38971
|
-
|
|
39214
|
+
fs12.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
|
|
39215
|
+
fs12.renameSync(tempPath, logPath);
|
|
38972
39216
|
}
|
|
38973
39217
|
function gitExec(args2) {
|
|
38974
39218
|
const result = spawnSync("git", args2, {
|
|
@@ -39168,8 +39412,8 @@ var checkpoint = tool({
|
|
|
39168
39412
|
});
|
|
39169
39413
|
// src/tools/complexity-hotspots.ts
|
|
39170
39414
|
init_dist();
|
|
39171
|
-
import * as
|
|
39172
|
-
import * as
|
|
39415
|
+
import * as fs13 from "fs";
|
|
39416
|
+
import * as path19 from "path";
|
|
39173
39417
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
39174
39418
|
var DEFAULT_DAYS = 90;
|
|
39175
39419
|
var DEFAULT_TOP_N = 20;
|
|
@@ -39297,11 +39541,11 @@ function estimateComplexity(content) {
|
|
|
39297
39541
|
}
|
|
39298
39542
|
function getComplexityForFile(filePath) {
|
|
39299
39543
|
try {
|
|
39300
|
-
const stat =
|
|
39544
|
+
const stat = fs13.statSync(filePath);
|
|
39301
39545
|
if (stat.size > MAX_FILE_SIZE_BYTES2) {
|
|
39302
39546
|
return null;
|
|
39303
39547
|
}
|
|
39304
|
-
const content =
|
|
39548
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
39305
39549
|
return estimateComplexity(content);
|
|
39306
39550
|
} catch {
|
|
39307
39551
|
return null;
|
|
@@ -39312,7 +39556,7 @@ async function analyzeHotspots(days, topN, extensions) {
|
|
|
39312
39556
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
39313
39557
|
const filteredChurn = new Map;
|
|
39314
39558
|
for (const [file3, count] of churnMap) {
|
|
39315
|
-
const ext =
|
|
39559
|
+
const ext = path19.extname(file3).toLowerCase();
|
|
39316
39560
|
if (extSet.has(ext)) {
|
|
39317
39561
|
filteredChurn.set(file3, count);
|
|
39318
39562
|
}
|
|
@@ -39322,8 +39566,8 @@ async function analyzeHotspots(days, topN, extensions) {
|
|
|
39322
39566
|
let analyzedFiles = 0;
|
|
39323
39567
|
for (const [file3, churnCount] of filteredChurn) {
|
|
39324
39568
|
let fullPath = file3;
|
|
39325
|
-
if (!
|
|
39326
|
-
fullPath =
|
|
39569
|
+
if (!fs13.existsSync(fullPath)) {
|
|
39570
|
+
fullPath = path19.join(cwd, file3);
|
|
39327
39571
|
}
|
|
39328
39572
|
const complexity = getComplexityForFile(fullPath);
|
|
39329
39573
|
if (complexity !== null) {
|
|
@@ -39481,14 +39725,14 @@ function validateBase(base) {
|
|
|
39481
39725
|
function validatePaths(paths) {
|
|
39482
39726
|
if (!paths)
|
|
39483
39727
|
return null;
|
|
39484
|
-
for (const
|
|
39485
|
-
if (!
|
|
39728
|
+
for (const path20 of paths) {
|
|
39729
|
+
if (!path20 || path20.length === 0) {
|
|
39486
39730
|
return "empty path not allowed";
|
|
39487
39731
|
}
|
|
39488
|
-
if (
|
|
39732
|
+
if (path20.length > MAX_PATH_LENGTH) {
|
|
39489
39733
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
39490
39734
|
}
|
|
39491
|
-
if (SHELL_METACHARACTERS2.test(
|
|
39735
|
+
if (SHELL_METACHARACTERS2.test(path20)) {
|
|
39492
39736
|
return "path contains shell metacharacters";
|
|
39493
39737
|
}
|
|
39494
39738
|
}
|
|
@@ -39551,8 +39795,8 @@ var diff = tool({
|
|
|
39551
39795
|
if (parts2.length >= 3) {
|
|
39552
39796
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
39553
39797
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
39554
|
-
const
|
|
39555
|
-
files.push({ path:
|
|
39798
|
+
const path20 = parts2[2];
|
|
39799
|
+
files.push({ path: path20, additions, deletions });
|
|
39556
39800
|
}
|
|
39557
39801
|
}
|
|
39558
39802
|
const contractChanges = [];
|
|
@@ -39780,8 +40024,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
39780
40024
|
});
|
|
39781
40025
|
// src/tools/evidence-check.ts
|
|
39782
40026
|
init_dist();
|
|
39783
|
-
import * as
|
|
39784
|
-
import * as
|
|
40027
|
+
import * as fs14 from "fs";
|
|
40028
|
+
import * as path20 from "path";
|
|
39785
40029
|
var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
|
|
39786
40030
|
var MAX_EVIDENCE_FILES = 1000;
|
|
39787
40031
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
@@ -39804,9 +40048,9 @@ function validateRequiredTypes(input) {
|
|
|
39804
40048
|
return null;
|
|
39805
40049
|
}
|
|
39806
40050
|
function isPathWithinSwarm(filePath, cwd) {
|
|
39807
|
-
const normalizedCwd =
|
|
39808
|
-
const swarmPath =
|
|
39809
|
-
const normalizedPath =
|
|
40051
|
+
const normalizedCwd = path20.resolve(cwd);
|
|
40052
|
+
const swarmPath = path20.join(normalizedCwd, ".swarm");
|
|
40053
|
+
const normalizedPath = path20.resolve(filePath);
|
|
39810
40054
|
return normalizedPath.startsWith(swarmPath);
|
|
39811
40055
|
}
|
|
39812
40056
|
function parseCompletedTasks(planContent) {
|
|
@@ -39822,12 +40066,12 @@ function parseCompletedTasks(planContent) {
|
|
|
39822
40066
|
}
|
|
39823
40067
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
39824
40068
|
const evidence = [];
|
|
39825
|
-
if (!
|
|
40069
|
+
if (!fs14.existsSync(evidenceDir) || !fs14.statSync(evidenceDir).isDirectory()) {
|
|
39826
40070
|
return evidence;
|
|
39827
40071
|
}
|
|
39828
40072
|
let files;
|
|
39829
40073
|
try {
|
|
39830
|
-
files =
|
|
40074
|
+
files = fs14.readdirSync(evidenceDir);
|
|
39831
40075
|
} catch {
|
|
39832
40076
|
return evidence;
|
|
39833
40077
|
}
|
|
@@ -39836,14 +40080,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
39836
40080
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
39837
40081
|
continue;
|
|
39838
40082
|
}
|
|
39839
|
-
const filePath =
|
|
40083
|
+
const filePath = path20.join(evidenceDir, filename);
|
|
39840
40084
|
try {
|
|
39841
|
-
const resolvedPath =
|
|
39842
|
-
const evidenceDirResolved =
|
|
40085
|
+
const resolvedPath = path20.resolve(filePath);
|
|
40086
|
+
const evidenceDirResolved = path20.resolve(evidenceDir);
|
|
39843
40087
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
39844
40088
|
continue;
|
|
39845
40089
|
}
|
|
39846
|
-
const stat =
|
|
40090
|
+
const stat = fs14.lstatSync(filePath);
|
|
39847
40091
|
if (!stat.isFile()) {
|
|
39848
40092
|
continue;
|
|
39849
40093
|
}
|
|
@@ -39852,7 +40096,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
39852
40096
|
}
|
|
39853
40097
|
let fileStat;
|
|
39854
40098
|
try {
|
|
39855
|
-
fileStat =
|
|
40099
|
+
fileStat = fs14.statSync(filePath);
|
|
39856
40100
|
if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
|
|
39857
40101
|
continue;
|
|
39858
40102
|
}
|
|
@@ -39861,7 +40105,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
39861
40105
|
}
|
|
39862
40106
|
let content;
|
|
39863
40107
|
try {
|
|
39864
|
-
content =
|
|
40108
|
+
content = fs14.readFileSync(filePath, "utf-8");
|
|
39865
40109
|
} catch {
|
|
39866
40110
|
continue;
|
|
39867
40111
|
}
|
|
@@ -39946,7 +40190,7 @@ var evidence_check = tool({
|
|
|
39946
40190
|
return JSON.stringify(errorResult, null, 2);
|
|
39947
40191
|
}
|
|
39948
40192
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
39949
|
-
const planPath =
|
|
40193
|
+
const planPath = path20.join(cwd, PLAN_FILE);
|
|
39950
40194
|
if (!isPathWithinSwarm(planPath, cwd)) {
|
|
39951
40195
|
const errorResult = {
|
|
39952
40196
|
error: "plan file path validation failed",
|
|
@@ -39960,7 +40204,7 @@ var evidence_check = tool({
|
|
|
39960
40204
|
}
|
|
39961
40205
|
let planContent;
|
|
39962
40206
|
try {
|
|
39963
|
-
planContent =
|
|
40207
|
+
planContent = fs14.readFileSync(planPath, "utf-8");
|
|
39964
40208
|
} catch {
|
|
39965
40209
|
const result2 = {
|
|
39966
40210
|
message: "No completed tasks found in plan.",
|
|
@@ -39978,7 +40222,7 @@ var evidence_check = tool({
|
|
|
39978
40222
|
};
|
|
39979
40223
|
return JSON.stringify(result2, null, 2);
|
|
39980
40224
|
}
|
|
39981
|
-
const evidenceDir =
|
|
40225
|
+
const evidenceDir = path20.join(cwd, EVIDENCE_DIR);
|
|
39982
40226
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
39983
40227
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
39984
40228
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -39994,8 +40238,8 @@ var evidence_check = tool({
|
|
|
39994
40238
|
});
|
|
39995
40239
|
// src/tools/file-extractor.ts
|
|
39996
40240
|
init_tool();
|
|
39997
|
-
import * as
|
|
39998
|
-
import * as
|
|
40241
|
+
import * as fs15 from "fs";
|
|
40242
|
+
import * as path21 from "path";
|
|
39999
40243
|
var EXT_MAP = {
|
|
40000
40244
|
python: ".py",
|
|
40001
40245
|
py: ".py",
|
|
@@ -40057,8 +40301,8 @@ var extract_code_blocks = tool({
|
|
|
40057
40301
|
execute: async (args2) => {
|
|
40058
40302
|
const { content, output_dir, prefix } = args2;
|
|
40059
40303
|
const targetDir = output_dir || process.cwd();
|
|
40060
|
-
if (!
|
|
40061
|
-
|
|
40304
|
+
if (!fs15.existsSync(targetDir)) {
|
|
40305
|
+
fs15.mkdirSync(targetDir, { recursive: true });
|
|
40062
40306
|
}
|
|
40063
40307
|
const pattern = /```(\w*)\n([\s\S]*?)```/g;
|
|
40064
40308
|
const matches = [...content.matchAll(pattern)];
|
|
@@ -40073,16 +40317,16 @@ var extract_code_blocks = tool({
|
|
|
40073
40317
|
if (prefix) {
|
|
40074
40318
|
filename = `${prefix}_${filename}`;
|
|
40075
40319
|
}
|
|
40076
|
-
let filepath =
|
|
40077
|
-
const base =
|
|
40078
|
-
const ext =
|
|
40320
|
+
let filepath = path21.join(targetDir, filename);
|
|
40321
|
+
const base = path21.basename(filepath, path21.extname(filepath));
|
|
40322
|
+
const ext = path21.extname(filepath);
|
|
40079
40323
|
let counter = 1;
|
|
40080
|
-
while (
|
|
40081
|
-
filepath =
|
|
40324
|
+
while (fs15.existsSync(filepath)) {
|
|
40325
|
+
filepath = path21.join(targetDir, `${base}_${counter}${ext}`);
|
|
40082
40326
|
counter++;
|
|
40083
40327
|
}
|
|
40084
40328
|
try {
|
|
40085
|
-
|
|
40329
|
+
fs15.writeFileSync(filepath, code.trim(), "utf-8");
|
|
40086
40330
|
savedFiles.push(filepath);
|
|
40087
40331
|
} catch (error93) {
|
|
40088
40332
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -40190,8 +40434,8 @@ var gitingest = tool({
|
|
|
40190
40434
|
});
|
|
40191
40435
|
// src/tools/imports.ts
|
|
40192
40436
|
init_dist();
|
|
40193
|
-
import * as
|
|
40194
|
-
import * as
|
|
40437
|
+
import * as fs16 from "fs";
|
|
40438
|
+
import * as path22 from "path";
|
|
40195
40439
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
40196
40440
|
var MAX_SYMBOL_LENGTH = 256;
|
|
40197
40441
|
var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
|
|
@@ -40245,7 +40489,7 @@ function validateSymbolInput(symbol3) {
|
|
|
40245
40489
|
return null;
|
|
40246
40490
|
}
|
|
40247
40491
|
function isBinaryFile2(filePath, buffer) {
|
|
40248
|
-
const ext =
|
|
40492
|
+
const ext = path22.extname(filePath).toLowerCase();
|
|
40249
40493
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
40250
40494
|
return false;
|
|
40251
40495
|
}
|
|
@@ -40269,15 +40513,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
40269
40513
|
const imports = [];
|
|
40270
40514
|
let _resolvedTarget;
|
|
40271
40515
|
try {
|
|
40272
|
-
_resolvedTarget =
|
|
40516
|
+
_resolvedTarget = path22.resolve(targetFile);
|
|
40273
40517
|
} catch {
|
|
40274
40518
|
_resolvedTarget = targetFile;
|
|
40275
40519
|
}
|
|
40276
|
-
const targetBasename =
|
|
40520
|
+
const targetBasename = path22.basename(targetFile, path22.extname(targetFile));
|
|
40277
40521
|
const targetWithExt = targetFile;
|
|
40278
40522
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
40279
|
-
const normalizedTargetWithExt =
|
|
40280
|
-
const normalizedTargetWithoutExt =
|
|
40523
|
+
const normalizedTargetWithExt = path22.normalize(targetWithExt).replace(/\\/g, "/");
|
|
40524
|
+
const normalizedTargetWithoutExt = path22.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
40281
40525
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
40282
40526
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
40283
40527
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -40300,9 +40544,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
40300
40544
|
}
|
|
40301
40545
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
40302
40546
|
let isMatch = false;
|
|
40303
|
-
const _targetDir =
|
|
40304
|
-
const targetExt =
|
|
40305
|
-
const targetBasenameNoExt =
|
|
40547
|
+
const _targetDir = path22.dirname(targetFile);
|
|
40548
|
+
const targetExt = path22.extname(targetFile);
|
|
40549
|
+
const targetBasenameNoExt = path22.basename(targetFile, targetExt);
|
|
40306
40550
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
40307
40551
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
40308
40552
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -40359,7 +40603,7 @@ var SKIP_DIRECTORIES2 = new Set([
|
|
|
40359
40603
|
function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
40360
40604
|
let entries;
|
|
40361
40605
|
try {
|
|
40362
|
-
entries =
|
|
40606
|
+
entries = fs16.readdirSync(dir);
|
|
40363
40607
|
} catch (e) {
|
|
40364
40608
|
stats.fileErrors.push({
|
|
40365
40609
|
path: dir,
|
|
@@ -40370,13 +40614,13 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
40370
40614
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
40371
40615
|
for (const entry of entries) {
|
|
40372
40616
|
if (SKIP_DIRECTORIES2.has(entry)) {
|
|
40373
|
-
stats.skippedDirs.push(
|
|
40617
|
+
stats.skippedDirs.push(path22.join(dir, entry));
|
|
40374
40618
|
continue;
|
|
40375
40619
|
}
|
|
40376
|
-
const fullPath =
|
|
40620
|
+
const fullPath = path22.join(dir, entry);
|
|
40377
40621
|
let stat;
|
|
40378
40622
|
try {
|
|
40379
|
-
stat =
|
|
40623
|
+
stat = fs16.statSync(fullPath);
|
|
40380
40624
|
} catch (e) {
|
|
40381
40625
|
stats.fileErrors.push({
|
|
40382
40626
|
path: fullPath,
|
|
@@ -40387,7 +40631,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
40387
40631
|
if (stat.isDirectory()) {
|
|
40388
40632
|
findSourceFiles2(fullPath, files, stats);
|
|
40389
40633
|
} else if (stat.isFile()) {
|
|
40390
|
-
const ext =
|
|
40634
|
+
const ext = path22.extname(fullPath).toLowerCase();
|
|
40391
40635
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
40392
40636
|
files.push(fullPath);
|
|
40393
40637
|
}
|
|
@@ -40443,8 +40687,8 @@ var imports = tool({
|
|
|
40443
40687
|
return JSON.stringify(errorResult, null, 2);
|
|
40444
40688
|
}
|
|
40445
40689
|
try {
|
|
40446
|
-
const targetFile =
|
|
40447
|
-
if (!
|
|
40690
|
+
const targetFile = path22.resolve(file3);
|
|
40691
|
+
if (!fs16.existsSync(targetFile)) {
|
|
40448
40692
|
const errorResult = {
|
|
40449
40693
|
error: `target file not found: ${file3}`,
|
|
40450
40694
|
target: file3,
|
|
@@ -40454,7 +40698,7 @@ var imports = tool({
|
|
|
40454
40698
|
};
|
|
40455
40699
|
return JSON.stringify(errorResult, null, 2);
|
|
40456
40700
|
}
|
|
40457
|
-
const targetStat =
|
|
40701
|
+
const targetStat = fs16.statSync(targetFile);
|
|
40458
40702
|
if (!targetStat.isFile()) {
|
|
40459
40703
|
const errorResult = {
|
|
40460
40704
|
error: "target must be a file, not a directory",
|
|
@@ -40465,7 +40709,7 @@ var imports = tool({
|
|
|
40465
40709
|
};
|
|
40466
40710
|
return JSON.stringify(errorResult, null, 2);
|
|
40467
40711
|
}
|
|
40468
|
-
const baseDir =
|
|
40712
|
+
const baseDir = path22.dirname(targetFile);
|
|
40469
40713
|
const scanStats = {
|
|
40470
40714
|
skippedDirs: [],
|
|
40471
40715
|
skippedFiles: 0,
|
|
@@ -40480,12 +40724,12 @@ var imports = tool({
|
|
|
40480
40724
|
if (consumers.length >= MAX_CONSUMERS)
|
|
40481
40725
|
break;
|
|
40482
40726
|
try {
|
|
40483
|
-
const stat =
|
|
40727
|
+
const stat = fs16.statSync(filePath);
|
|
40484
40728
|
if (stat.size > MAX_FILE_SIZE_BYTES4) {
|
|
40485
40729
|
skippedFileCount++;
|
|
40486
40730
|
continue;
|
|
40487
40731
|
}
|
|
40488
|
-
const buffer =
|
|
40732
|
+
const buffer = fs16.readFileSync(filePath);
|
|
40489
40733
|
if (isBinaryFile2(filePath, buffer)) {
|
|
40490
40734
|
skippedFileCount++;
|
|
40491
40735
|
continue;
|
|
@@ -40554,7 +40798,8 @@ init_lint();
|
|
|
40554
40798
|
|
|
40555
40799
|
// src/tools/phase-complete.ts
|
|
40556
40800
|
init_tool();
|
|
40557
|
-
import * as
|
|
40801
|
+
import * as fs17 from "fs";
|
|
40802
|
+
init_manager();
|
|
40558
40803
|
init_utils2();
|
|
40559
40804
|
function getDelegationsSince(sessionID, sinceTimestamp) {
|
|
40560
40805
|
const chain = swarmState.delegationChains.get(sessionID);
|
|
@@ -40576,6 +40821,9 @@ function normalizeAgentsFromDelegations(delegations) {
|
|
|
40576
40821
|
}
|
|
40577
40822
|
return agents;
|
|
40578
40823
|
}
|
|
40824
|
+
function isValidRetroEntry(entry, phase) {
|
|
40825
|
+
return entry.type === "retrospective" && "phase_number" in entry && entry.phase_number === phase && "verdict" in entry && entry.verdict === "pass";
|
|
40826
|
+
}
|
|
40579
40827
|
async function executePhaseComplete(args2) {
|
|
40580
40828
|
const phase = Number(args2.phase);
|
|
40581
40829
|
const summary = args2.summary;
|
|
@@ -40634,6 +40882,37 @@ async function executePhaseComplete(args2) {
|
|
|
40634
40882
|
warnings: []
|
|
40635
40883
|
}, null, 2);
|
|
40636
40884
|
}
|
|
40885
|
+
const retroBundle = await loadEvidence(directory, `retro-${phase}`);
|
|
40886
|
+
let retroFound = false;
|
|
40887
|
+
if (retroBundle !== null) {
|
|
40888
|
+
retroFound = retroBundle.entries?.some((entry) => isValidRetroEntry(entry, phase)) ?? false;
|
|
40889
|
+
}
|
|
40890
|
+
if (!retroFound) {
|
|
40891
|
+
const allTaskIds = await listEvidenceTaskIds(directory);
|
|
40892
|
+
const retroTaskIds = allTaskIds.filter((id) => id.startsWith("retro-"));
|
|
40893
|
+
for (const taskId of retroTaskIds) {
|
|
40894
|
+
const bundle = await loadEvidence(directory, taskId);
|
|
40895
|
+
if (bundle === null)
|
|
40896
|
+
continue;
|
|
40897
|
+
retroFound = bundle.entries?.some((entry) => isValidRetroEntry(entry, phase)) ?? false;
|
|
40898
|
+
if (retroFound)
|
|
40899
|
+
break;
|
|
40900
|
+
}
|
|
40901
|
+
}
|
|
40902
|
+
if (!retroFound) {
|
|
40903
|
+
return JSON.stringify({
|
|
40904
|
+
success: false,
|
|
40905
|
+
phase,
|
|
40906
|
+
status: "blocked",
|
|
40907
|
+
reason: "RETROSPECTIVE_MISSING",
|
|
40908
|
+
message: `Phase ${phase} cannot be completed: no valid retrospective evidence found. Write a retrospective bundle at .swarm/evidence/retro-${phase}/evidence.json with type='retrospective', phase_number=${phase}, verdict='pass' before calling phase_complete.`,
|
|
40909
|
+
agentsDispatched: [],
|
|
40910
|
+
agentsMissing: [],
|
|
40911
|
+
warnings: [
|
|
40912
|
+
`Retrospective missing for phase ${phase}. Write a retro bundle with verdict='pass' at .swarm/evidence/retro-${phase}/evidence.json`
|
|
40913
|
+
]
|
|
40914
|
+
}, null, 2);
|
|
40915
|
+
}
|
|
40637
40916
|
const effectiveRequired = [...phaseCompleteConfig.required_agents];
|
|
40638
40917
|
if (phaseCompleteConfig.require_docs && !effectiveRequired.includes("docs")) {
|
|
40639
40918
|
effectiveRequired.push("docs");
|
|
@@ -40667,7 +40946,7 @@ async function executePhaseComplete(args2) {
|
|
|
40667
40946
|
};
|
|
40668
40947
|
try {
|
|
40669
40948
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
40670
|
-
|
|
40949
|
+
fs17.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
40671
40950
|
`, "utf-8");
|
|
40672
40951
|
} catch (writeError) {
|
|
40673
40952
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -40717,8 +40996,8 @@ var phase_complete = tool({
|
|
|
40717
40996
|
});
|
|
40718
40997
|
// src/tools/pkg-audit.ts
|
|
40719
40998
|
init_dist();
|
|
40720
|
-
import * as
|
|
40721
|
-
import * as
|
|
40999
|
+
import * as fs18 from "fs";
|
|
41000
|
+
import * as path23 from "path";
|
|
40722
41001
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
40723
41002
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
40724
41003
|
function isValidEcosystem(value) {
|
|
@@ -40736,13 +41015,13 @@ function validateArgs3(args2) {
|
|
|
40736
41015
|
function detectEcosystems() {
|
|
40737
41016
|
const ecosystems = [];
|
|
40738
41017
|
const cwd = process.cwd();
|
|
40739
|
-
if (
|
|
41018
|
+
if (fs18.existsSync(path23.join(cwd, "package.json"))) {
|
|
40740
41019
|
ecosystems.push("npm");
|
|
40741
41020
|
}
|
|
40742
|
-
if (
|
|
41021
|
+
if (fs18.existsSync(path23.join(cwd, "pyproject.toml")) || fs18.existsSync(path23.join(cwd, "requirements.txt"))) {
|
|
40743
41022
|
ecosystems.push("pip");
|
|
40744
41023
|
}
|
|
40745
|
-
if (
|
|
41024
|
+
if (fs18.existsSync(path23.join(cwd, "Cargo.toml"))) {
|
|
40746
41025
|
ecosystems.push("cargo");
|
|
40747
41026
|
}
|
|
40748
41027
|
return ecosystems;
|
|
@@ -42650,11 +42929,11 @@ var Module2 = (() => {
|
|
|
42650
42929
|
throw toThrow;
|
|
42651
42930
|
}, "quit_");
|
|
42652
42931
|
var scriptDirectory = "";
|
|
42653
|
-
function locateFile(
|
|
42932
|
+
function locateFile(path24) {
|
|
42654
42933
|
if (Module["locateFile"]) {
|
|
42655
|
-
return Module["locateFile"](
|
|
42934
|
+
return Module["locateFile"](path24, scriptDirectory);
|
|
42656
42935
|
}
|
|
42657
|
-
return scriptDirectory +
|
|
42936
|
+
return scriptDirectory + path24;
|
|
42658
42937
|
}
|
|
42659
42938
|
__name(locateFile, "locateFile");
|
|
42660
42939
|
var readAsync, readBinary;
|
|
@@ -44468,7 +44747,7 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
44468
44747
|
]);
|
|
44469
44748
|
// src/tools/pre-check-batch.ts
|
|
44470
44749
|
init_dist();
|
|
44471
|
-
import * as
|
|
44750
|
+
import * as path26 from "path";
|
|
44472
44751
|
|
|
44473
44752
|
// node_modules/yocto-queue/index.js
|
|
44474
44753
|
class Node2 {
|
|
@@ -44634,8 +44913,8 @@ init_lint();
|
|
|
44634
44913
|
init_manager();
|
|
44635
44914
|
|
|
44636
44915
|
// src/quality/metrics.ts
|
|
44637
|
-
import * as
|
|
44638
|
-
import * as
|
|
44916
|
+
import * as fs19 from "fs";
|
|
44917
|
+
import * as path24 from "path";
|
|
44639
44918
|
var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
|
|
44640
44919
|
var MIN_DUPLICATION_LINES = 10;
|
|
44641
44920
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -44673,11 +44952,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
44673
44952
|
}
|
|
44674
44953
|
function getComplexityForFile2(filePath) {
|
|
44675
44954
|
try {
|
|
44676
|
-
const stat =
|
|
44955
|
+
const stat = fs19.statSync(filePath);
|
|
44677
44956
|
if (stat.size > MAX_FILE_SIZE_BYTES5) {
|
|
44678
44957
|
return null;
|
|
44679
44958
|
}
|
|
44680
|
-
const content =
|
|
44959
|
+
const content = fs19.readFileSync(filePath, "utf-8");
|
|
44681
44960
|
return estimateCyclomaticComplexity(content);
|
|
44682
44961
|
} catch {
|
|
44683
44962
|
return null;
|
|
@@ -44687,8 +44966,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
44687
44966
|
let totalComplexity = 0;
|
|
44688
44967
|
const analyzedFiles = [];
|
|
44689
44968
|
for (const file3 of files) {
|
|
44690
|
-
const fullPath =
|
|
44691
|
-
if (!
|
|
44969
|
+
const fullPath = path24.isAbsolute(file3) ? file3 : path24.join(workingDir, file3);
|
|
44970
|
+
if (!fs19.existsSync(fullPath)) {
|
|
44692
44971
|
continue;
|
|
44693
44972
|
}
|
|
44694
44973
|
const complexity = getComplexityForFile2(fullPath);
|
|
@@ -44809,8 +45088,8 @@ function countGoExports(content) {
|
|
|
44809
45088
|
}
|
|
44810
45089
|
function getExportCountForFile(filePath) {
|
|
44811
45090
|
try {
|
|
44812
|
-
const content =
|
|
44813
|
-
const ext =
|
|
45091
|
+
const content = fs19.readFileSync(filePath, "utf-8");
|
|
45092
|
+
const ext = path24.extname(filePath).toLowerCase();
|
|
44814
45093
|
switch (ext) {
|
|
44815
45094
|
case ".ts":
|
|
44816
45095
|
case ".tsx":
|
|
@@ -44836,8 +45115,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
44836
45115
|
let totalExports = 0;
|
|
44837
45116
|
const analyzedFiles = [];
|
|
44838
45117
|
for (const file3 of files) {
|
|
44839
|
-
const fullPath =
|
|
44840
|
-
if (!
|
|
45118
|
+
const fullPath = path24.isAbsolute(file3) ? file3 : path24.join(workingDir, file3);
|
|
45119
|
+
if (!fs19.existsSync(fullPath)) {
|
|
44841
45120
|
continue;
|
|
44842
45121
|
}
|
|
44843
45122
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -44870,16 +45149,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
44870
45149
|
let duplicateLines = 0;
|
|
44871
45150
|
const analyzedFiles = [];
|
|
44872
45151
|
for (const file3 of files) {
|
|
44873
|
-
const fullPath =
|
|
44874
|
-
if (!
|
|
45152
|
+
const fullPath = path24.isAbsolute(file3) ? file3 : path24.join(workingDir, file3);
|
|
45153
|
+
if (!fs19.existsSync(fullPath)) {
|
|
44875
45154
|
continue;
|
|
44876
45155
|
}
|
|
44877
45156
|
try {
|
|
44878
|
-
const stat =
|
|
45157
|
+
const stat = fs19.statSync(fullPath);
|
|
44879
45158
|
if (stat.size > MAX_FILE_SIZE_BYTES5) {
|
|
44880
45159
|
continue;
|
|
44881
45160
|
}
|
|
44882
|
-
const content =
|
|
45161
|
+
const content = fs19.readFileSync(fullPath, "utf-8");
|
|
44883
45162
|
const lines = content.split(`
|
|
44884
45163
|
`).filter((line) => line.trim().length > 0);
|
|
44885
45164
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -44903,8 +45182,8 @@ function countCodeLines(content) {
|
|
|
44903
45182
|
return lines.length;
|
|
44904
45183
|
}
|
|
44905
45184
|
function isTestFile(filePath) {
|
|
44906
|
-
const basename5 =
|
|
44907
|
-
const _ext =
|
|
45185
|
+
const basename5 = path24.basename(filePath);
|
|
45186
|
+
const _ext = path24.extname(filePath).toLowerCase();
|
|
44908
45187
|
const testPatterns = [
|
|
44909
45188
|
".test.",
|
|
44910
45189
|
".spec.",
|
|
@@ -44946,31 +45225,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
44946
45225
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
44947
45226
|
let testLines = 0;
|
|
44948
45227
|
let codeLines = 0;
|
|
44949
|
-
const srcDir =
|
|
44950
|
-
if (
|
|
45228
|
+
const srcDir = path24.join(workingDir, "src");
|
|
45229
|
+
if (fs19.existsSync(srcDir)) {
|
|
44951
45230
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
44952
45231
|
codeLines += lines;
|
|
44953
45232
|
});
|
|
44954
45233
|
}
|
|
44955
45234
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
44956
45235
|
for (const dir of possibleSrcDirs) {
|
|
44957
|
-
const dirPath =
|
|
44958
|
-
if (
|
|
45236
|
+
const dirPath = path24.join(workingDir, dir);
|
|
45237
|
+
if (fs19.existsSync(dirPath)) {
|
|
44959
45238
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
44960
45239
|
codeLines += lines;
|
|
44961
45240
|
});
|
|
44962
45241
|
}
|
|
44963
45242
|
}
|
|
44964
|
-
const testsDir =
|
|
44965
|
-
if (
|
|
45243
|
+
const testsDir = path24.join(workingDir, "tests");
|
|
45244
|
+
if (fs19.existsSync(testsDir)) {
|
|
44966
45245
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
44967
45246
|
testLines += lines;
|
|
44968
45247
|
});
|
|
44969
45248
|
}
|
|
44970
45249
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
44971
45250
|
for (const dir of possibleTestDirs) {
|
|
44972
|
-
const dirPath =
|
|
44973
|
-
if (
|
|
45251
|
+
const dirPath = path24.join(workingDir, dir);
|
|
45252
|
+
if (fs19.existsSync(dirPath) && dirPath !== testsDir) {
|
|
44974
45253
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
44975
45254
|
testLines += lines;
|
|
44976
45255
|
});
|
|
@@ -44982,9 +45261,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
44982
45261
|
}
|
|
44983
45262
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
44984
45263
|
try {
|
|
44985
|
-
const entries =
|
|
45264
|
+
const entries = fs19.readdirSync(dirPath, { withFileTypes: true });
|
|
44986
45265
|
for (const entry of entries) {
|
|
44987
|
-
const fullPath =
|
|
45266
|
+
const fullPath = path24.join(dirPath, entry.name);
|
|
44988
45267
|
if (entry.isDirectory()) {
|
|
44989
45268
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
44990
45269
|
continue;
|
|
@@ -44992,7 +45271,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
44992
45271
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
44993
45272
|
} else if (entry.isFile()) {
|
|
44994
45273
|
const relativePath = fullPath.replace(`${process.cwd()}/`, "");
|
|
44995
|
-
const ext =
|
|
45274
|
+
const ext = path24.extname(entry.name).toLowerCase();
|
|
44996
45275
|
const validExts = [
|
|
44997
45276
|
".ts",
|
|
44998
45277
|
".tsx",
|
|
@@ -45030,7 +45309,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
45030
45309
|
continue;
|
|
45031
45310
|
}
|
|
45032
45311
|
try {
|
|
45033
|
-
const content =
|
|
45312
|
+
const content = fs19.readFileSync(fullPath, "utf-8");
|
|
45034
45313
|
const lines = countCodeLines(content);
|
|
45035
45314
|
callback(lines);
|
|
45036
45315
|
} catch {}
|
|
@@ -45246,8 +45525,8 @@ async function qualityBudget(input, directory) {
|
|
|
45246
45525
|
|
|
45247
45526
|
// src/tools/sast-scan.ts
|
|
45248
45527
|
init_manager();
|
|
45249
|
-
import * as
|
|
45250
|
-
import * as
|
|
45528
|
+
import * as fs20 from "fs";
|
|
45529
|
+
import * as path25 from "path";
|
|
45251
45530
|
import { extname as extname7 } from "path";
|
|
45252
45531
|
|
|
45253
45532
|
// src/sast/rules/c.ts
|
|
@@ -46110,17 +46389,17 @@ var SEVERITY_ORDER = {
|
|
|
46110
46389
|
};
|
|
46111
46390
|
function shouldSkipFile(filePath) {
|
|
46112
46391
|
try {
|
|
46113
|
-
const stats =
|
|
46392
|
+
const stats = fs20.statSync(filePath);
|
|
46114
46393
|
if (stats.size > MAX_FILE_SIZE_BYTES6) {
|
|
46115
46394
|
return { skip: true, reason: "file too large" };
|
|
46116
46395
|
}
|
|
46117
46396
|
if (stats.size === 0) {
|
|
46118
46397
|
return { skip: true, reason: "empty file" };
|
|
46119
46398
|
}
|
|
46120
|
-
const fd =
|
|
46399
|
+
const fd = fs20.openSync(filePath, "r");
|
|
46121
46400
|
const buffer = Buffer.alloc(8192);
|
|
46122
|
-
const bytesRead =
|
|
46123
|
-
|
|
46401
|
+
const bytesRead = fs20.readSync(fd, buffer, 0, 8192, 0);
|
|
46402
|
+
fs20.closeSync(fd);
|
|
46124
46403
|
if (bytesRead > 0) {
|
|
46125
46404
|
let nullCount = 0;
|
|
46126
46405
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -46159,7 +46438,7 @@ function countBySeverity(findings) {
|
|
|
46159
46438
|
}
|
|
46160
46439
|
function scanFileWithTierA(filePath, language) {
|
|
46161
46440
|
try {
|
|
46162
|
-
const content =
|
|
46441
|
+
const content = fs20.readFileSync(filePath, "utf-8");
|
|
46163
46442
|
const findings = executeRulesSync(filePath, content, language);
|
|
46164
46443
|
return findings.map((f) => ({
|
|
46165
46444
|
rule_id: f.rule_id,
|
|
@@ -46202,8 +46481,8 @@ async function sastScan(input, directory, config3) {
|
|
|
46202
46481
|
const engine = semgrepAvailable ? "tier_a+tier_b" : "tier_a";
|
|
46203
46482
|
const filesByLanguage = new Map;
|
|
46204
46483
|
for (const filePath of changed_files) {
|
|
46205
|
-
const resolvedPath =
|
|
46206
|
-
if (!
|
|
46484
|
+
const resolvedPath = path25.isAbsolute(filePath) ? filePath : path25.resolve(directory, filePath);
|
|
46485
|
+
if (!fs20.existsSync(resolvedPath)) {
|
|
46207
46486
|
_filesSkipped++;
|
|
46208
46487
|
continue;
|
|
46209
46488
|
}
|
|
@@ -46311,10 +46590,10 @@ function validatePath(inputPath, baseDir) {
|
|
|
46311
46590
|
if (!inputPath || inputPath.length === 0) {
|
|
46312
46591
|
return "path is required";
|
|
46313
46592
|
}
|
|
46314
|
-
const resolved =
|
|
46315
|
-
const baseResolved =
|
|
46316
|
-
const relative3 =
|
|
46317
|
-
if (relative3.startsWith("..") ||
|
|
46593
|
+
const resolved = path26.resolve(baseDir, inputPath);
|
|
46594
|
+
const baseResolved = path26.resolve(baseDir);
|
|
46595
|
+
const relative3 = path26.relative(baseResolved, resolved);
|
|
46596
|
+
if (relative3.startsWith("..") || path26.isAbsolute(relative3)) {
|
|
46318
46597
|
return "path traversal detected";
|
|
46319
46598
|
}
|
|
46320
46599
|
return null;
|
|
@@ -46436,7 +46715,7 @@ async function runPreCheckBatch(input) {
|
|
|
46436
46715
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
46437
46716
|
continue;
|
|
46438
46717
|
}
|
|
46439
|
-
changedFiles.push(
|
|
46718
|
+
changedFiles.push(path26.resolve(directory, file3));
|
|
46440
46719
|
}
|
|
46441
46720
|
} else {
|
|
46442
46721
|
changedFiles = [];
|
|
@@ -46626,8 +46905,8 @@ var retrieve_summary = tool({
|
|
|
46626
46905
|
// src/tools/sbom-generate.ts
|
|
46627
46906
|
init_dist();
|
|
46628
46907
|
init_manager();
|
|
46629
|
-
import * as
|
|
46630
|
-
import * as
|
|
46908
|
+
import * as fs21 from "fs";
|
|
46909
|
+
import * as path27 from "path";
|
|
46631
46910
|
|
|
46632
46911
|
// src/sbom/detectors/dart.ts
|
|
46633
46912
|
function parsePubspecLock(content) {
|
|
@@ -47472,9 +47751,9 @@ function findManifestFiles(rootDir) {
|
|
|
47472
47751
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
47473
47752
|
function searchDir(dir) {
|
|
47474
47753
|
try {
|
|
47475
|
-
const entries =
|
|
47754
|
+
const entries = fs21.readdirSync(dir, { withFileTypes: true });
|
|
47476
47755
|
for (const entry of entries) {
|
|
47477
|
-
const fullPath =
|
|
47756
|
+
const fullPath = path27.join(dir, entry.name);
|
|
47478
47757
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
47479
47758
|
continue;
|
|
47480
47759
|
}
|
|
@@ -47484,7 +47763,7 @@ function findManifestFiles(rootDir) {
|
|
|
47484
47763
|
for (const pattern of patterns) {
|
|
47485
47764
|
const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
47486
47765
|
if (new RegExp(regex, "i").test(entry.name)) {
|
|
47487
|
-
manifestFiles.push(
|
|
47766
|
+
manifestFiles.push(path27.relative(cwd, fullPath));
|
|
47488
47767
|
break;
|
|
47489
47768
|
}
|
|
47490
47769
|
}
|
|
@@ -47501,14 +47780,14 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
47501
47780
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
47502
47781
|
for (const dir of directories) {
|
|
47503
47782
|
try {
|
|
47504
|
-
const entries =
|
|
47783
|
+
const entries = fs21.readdirSync(dir, { withFileTypes: true });
|
|
47505
47784
|
for (const entry of entries) {
|
|
47506
|
-
const fullPath =
|
|
47785
|
+
const fullPath = path27.join(dir, entry.name);
|
|
47507
47786
|
if (entry.isFile()) {
|
|
47508
47787
|
for (const pattern of patterns) {
|
|
47509
47788
|
const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
47510
47789
|
if (new RegExp(regex, "i").test(entry.name)) {
|
|
47511
|
-
found.push(
|
|
47790
|
+
found.push(path27.relative(workingDir, fullPath));
|
|
47512
47791
|
break;
|
|
47513
47792
|
}
|
|
47514
47793
|
}
|
|
@@ -47521,11 +47800,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
47521
47800
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
47522
47801
|
const dirs = new Set;
|
|
47523
47802
|
for (const file3 of changedFiles) {
|
|
47524
|
-
let currentDir =
|
|
47803
|
+
let currentDir = path27.dirname(file3);
|
|
47525
47804
|
while (true) {
|
|
47526
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
47527
|
-
dirs.add(
|
|
47528
|
-
const parent =
|
|
47805
|
+
if (currentDir && currentDir !== "." && currentDir !== path27.sep) {
|
|
47806
|
+
dirs.add(path27.join(workingDir, currentDir));
|
|
47807
|
+
const parent = path27.dirname(currentDir);
|
|
47529
47808
|
if (parent === currentDir)
|
|
47530
47809
|
break;
|
|
47531
47810
|
currentDir = parent;
|
|
@@ -47539,7 +47818,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
47539
47818
|
}
|
|
47540
47819
|
function ensureOutputDir(outputDir) {
|
|
47541
47820
|
try {
|
|
47542
|
-
|
|
47821
|
+
fs21.mkdirSync(outputDir, { recursive: true });
|
|
47543
47822
|
} catch (error93) {
|
|
47544
47823
|
if (!error93 || error93.code !== "EEXIST") {
|
|
47545
47824
|
throw error93;
|
|
@@ -47632,11 +47911,11 @@ var sbom_generate = tool({
|
|
|
47632
47911
|
const processedFiles = [];
|
|
47633
47912
|
for (const manifestFile of manifestFiles) {
|
|
47634
47913
|
try {
|
|
47635
|
-
const fullPath =
|
|
47636
|
-
if (!
|
|
47914
|
+
const fullPath = path27.isAbsolute(manifestFile) ? manifestFile : path27.join(workingDir, manifestFile);
|
|
47915
|
+
if (!fs21.existsSync(fullPath)) {
|
|
47637
47916
|
continue;
|
|
47638
47917
|
}
|
|
47639
|
-
const content =
|
|
47918
|
+
const content = fs21.readFileSync(fullPath, "utf-8");
|
|
47640
47919
|
const components = detectComponents(manifestFile, content);
|
|
47641
47920
|
processedFiles.push(manifestFile);
|
|
47642
47921
|
if (components.length > 0) {
|
|
@@ -47649,8 +47928,8 @@ var sbom_generate = tool({
|
|
|
47649
47928
|
const bom = generateCycloneDX(allComponents);
|
|
47650
47929
|
const bomJson = serializeCycloneDX(bom);
|
|
47651
47930
|
const filename = generateSbomFilename();
|
|
47652
|
-
const outputPath =
|
|
47653
|
-
|
|
47931
|
+
const outputPath = path27.join(outputDir, filename);
|
|
47932
|
+
fs21.writeFileSync(outputPath, bomJson, "utf-8");
|
|
47654
47933
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
47655
47934
|
try {
|
|
47656
47935
|
const timestamp = new Date().toISOString();
|
|
@@ -47691,8 +47970,8 @@ var sbom_generate = tool({
|
|
|
47691
47970
|
});
|
|
47692
47971
|
// src/tools/schema-drift.ts
|
|
47693
47972
|
init_dist();
|
|
47694
|
-
import * as
|
|
47695
|
-
import * as
|
|
47973
|
+
import * as fs22 from "fs";
|
|
47974
|
+
import * as path28 from "path";
|
|
47696
47975
|
var SPEC_CANDIDATES = [
|
|
47697
47976
|
"openapi.json",
|
|
47698
47977
|
"openapi.yaml",
|
|
@@ -47724,28 +48003,28 @@ function normalizePath(p) {
|
|
|
47724
48003
|
}
|
|
47725
48004
|
function discoverSpecFile(cwd, specFileArg) {
|
|
47726
48005
|
if (specFileArg) {
|
|
47727
|
-
const resolvedPath =
|
|
47728
|
-
const normalizedCwd = cwd.endsWith(
|
|
48006
|
+
const resolvedPath = path28.resolve(cwd, specFileArg);
|
|
48007
|
+
const normalizedCwd = cwd.endsWith(path28.sep) ? cwd : cwd + path28.sep;
|
|
47729
48008
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
47730
48009
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
47731
48010
|
}
|
|
47732
|
-
const ext =
|
|
48011
|
+
const ext = path28.extname(resolvedPath).toLowerCase();
|
|
47733
48012
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
47734
48013
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
47735
48014
|
}
|
|
47736
|
-
const stats =
|
|
48015
|
+
const stats = fs22.statSync(resolvedPath);
|
|
47737
48016
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
47738
48017
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
47739
48018
|
}
|
|
47740
|
-
if (!
|
|
48019
|
+
if (!fs22.existsSync(resolvedPath)) {
|
|
47741
48020
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
47742
48021
|
}
|
|
47743
48022
|
return resolvedPath;
|
|
47744
48023
|
}
|
|
47745
48024
|
for (const candidate of SPEC_CANDIDATES) {
|
|
47746
|
-
const candidatePath =
|
|
47747
|
-
if (
|
|
47748
|
-
const stats =
|
|
48025
|
+
const candidatePath = path28.resolve(cwd, candidate);
|
|
48026
|
+
if (fs22.existsSync(candidatePath)) {
|
|
48027
|
+
const stats = fs22.statSync(candidatePath);
|
|
47749
48028
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
47750
48029
|
return candidatePath;
|
|
47751
48030
|
}
|
|
@@ -47754,8 +48033,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
47754
48033
|
return null;
|
|
47755
48034
|
}
|
|
47756
48035
|
function parseSpec(specFile) {
|
|
47757
|
-
const content =
|
|
47758
|
-
const ext =
|
|
48036
|
+
const content = fs22.readFileSync(specFile, "utf-8");
|
|
48037
|
+
const ext = path28.extname(specFile).toLowerCase();
|
|
47759
48038
|
if (ext === ".json") {
|
|
47760
48039
|
return parseJsonSpec(content);
|
|
47761
48040
|
}
|
|
@@ -47821,12 +48100,12 @@ function extractRoutes(cwd) {
|
|
|
47821
48100
|
function walkDir(dir) {
|
|
47822
48101
|
let entries;
|
|
47823
48102
|
try {
|
|
47824
|
-
entries =
|
|
48103
|
+
entries = fs22.readdirSync(dir, { withFileTypes: true });
|
|
47825
48104
|
} catch {
|
|
47826
48105
|
return;
|
|
47827
48106
|
}
|
|
47828
48107
|
for (const entry of entries) {
|
|
47829
|
-
const fullPath =
|
|
48108
|
+
const fullPath = path28.join(dir, entry.name);
|
|
47830
48109
|
if (entry.isSymbolicLink()) {
|
|
47831
48110
|
continue;
|
|
47832
48111
|
}
|
|
@@ -47836,7 +48115,7 @@ function extractRoutes(cwd) {
|
|
|
47836
48115
|
}
|
|
47837
48116
|
walkDir(fullPath);
|
|
47838
48117
|
} else if (entry.isFile()) {
|
|
47839
|
-
const ext =
|
|
48118
|
+
const ext = path28.extname(entry.name).toLowerCase();
|
|
47840
48119
|
const baseName = entry.name.toLowerCase();
|
|
47841
48120
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
47842
48121
|
continue;
|
|
@@ -47854,7 +48133,7 @@ function extractRoutes(cwd) {
|
|
|
47854
48133
|
}
|
|
47855
48134
|
function extractRoutesFromFile(filePath) {
|
|
47856
48135
|
const routes = [];
|
|
47857
|
-
const content =
|
|
48136
|
+
const content = fs22.readFileSync(filePath, "utf-8");
|
|
47858
48137
|
const lines = content.split(/\r?\n/);
|
|
47859
48138
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
47860
48139
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -48004,8 +48283,8 @@ init_secretscan();
|
|
|
48004
48283
|
|
|
48005
48284
|
// src/tools/symbols.ts
|
|
48006
48285
|
init_tool();
|
|
48007
|
-
import * as
|
|
48008
|
-
import * as
|
|
48286
|
+
import * as fs23 from "fs";
|
|
48287
|
+
import * as path29 from "path";
|
|
48009
48288
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
48010
48289
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
48011
48290
|
function containsControlCharacters(str) {
|
|
@@ -48034,11 +48313,11 @@ function containsWindowsAttacks(str) {
|
|
|
48034
48313
|
}
|
|
48035
48314
|
function isPathInWorkspace(filePath, workspace) {
|
|
48036
48315
|
try {
|
|
48037
|
-
const resolvedPath =
|
|
48038
|
-
const realWorkspace =
|
|
48039
|
-
const realResolvedPath =
|
|
48040
|
-
const relativePath =
|
|
48041
|
-
if (relativePath.startsWith("..") ||
|
|
48316
|
+
const resolvedPath = path29.resolve(workspace, filePath);
|
|
48317
|
+
const realWorkspace = fs23.realpathSync(workspace);
|
|
48318
|
+
const realResolvedPath = fs23.realpathSync(resolvedPath);
|
|
48319
|
+
const relativePath = path29.relative(realWorkspace, realResolvedPath);
|
|
48320
|
+
if (relativePath.startsWith("..") || path29.isAbsolute(relativePath)) {
|
|
48042
48321
|
return false;
|
|
48043
48322
|
}
|
|
48044
48323
|
return true;
|
|
@@ -48050,17 +48329,17 @@ function validatePathForRead(filePath, workspace) {
|
|
|
48050
48329
|
return isPathInWorkspace(filePath, workspace);
|
|
48051
48330
|
}
|
|
48052
48331
|
function extractTSSymbols(filePath, cwd) {
|
|
48053
|
-
const fullPath =
|
|
48332
|
+
const fullPath = path29.join(cwd, filePath);
|
|
48054
48333
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
48055
48334
|
return [];
|
|
48056
48335
|
}
|
|
48057
48336
|
let content;
|
|
48058
48337
|
try {
|
|
48059
|
-
const stats =
|
|
48338
|
+
const stats = fs23.statSync(fullPath);
|
|
48060
48339
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
48061
48340
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
48062
48341
|
}
|
|
48063
|
-
content =
|
|
48342
|
+
content = fs23.readFileSync(fullPath, "utf-8");
|
|
48064
48343
|
} catch {
|
|
48065
48344
|
return [];
|
|
48066
48345
|
}
|
|
@@ -48202,17 +48481,17 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
48202
48481
|
});
|
|
48203
48482
|
}
|
|
48204
48483
|
function extractPythonSymbols(filePath, cwd) {
|
|
48205
|
-
const fullPath =
|
|
48484
|
+
const fullPath = path29.join(cwd, filePath);
|
|
48206
48485
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
48207
48486
|
return [];
|
|
48208
48487
|
}
|
|
48209
48488
|
let content;
|
|
48210
48489
|
try {
|
|
48211
|
-
const stats =
|
|
48490
|
+
const stats = fs23.statSync(fullPath);
|
|
48212
48491
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
48213
48492
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
48214
48493
|
}
|
|
48215
|
-
content =
|
|
48494
|
+
content = fs23.readFileSync(fullPath, "utf-8");
|
|
48216
48495
|
} catch {
|
|
48217
48496
|
return [];
|
|
48218
48497
|
}
|
|
@@ -48284,7 +48563,7 @@ var symbols = tool({
|
|
|
48284
48563
|
}, null, 2);
|
|
48285
48564
|
}
|
|
48286
48565
|
const cwd = process.cwd();
|
|
48287
|
-
const ext =
|
|
48566
|
+
const ext = path29.extname(file3);
|
|
48288
48567
|
if (containsControlCharacters(file3)) {
|
|
48289
48568
|
return JSON.stringify({
|
|
48290
48569
|
file: file3,
|
|
@@ -48352,8 +48631,8 @@ init_test_runner();
|
|
|
48352
48631
|
|
|
48353
48632
|
// src/tools/todo-extract.ts
|
|
48354
48633
|
init_dist();
|
|
48355
|
-
import * as
|
|
48356
|
-
import * as
|
|
48634
|
+
import * as fs24 from "fs";
|
|
48635
|
+
import * as path30 from "path";
|
|
48357
48636
|
var MAX_TEXT_LENGTH = 200;
|
|
48358
48637
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
48359
48638
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
@@ -48424,9 +48703,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
48424
48703
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
48425
48704
|
}
|
|
48426
48705
|
try {
|
|
48427
|
-
const resolvedPath =
|
|
48428
|
-
const normalizedCwd =
|
|
48429
|
-
const normalizedResolved =
|
|
48706
|
+
const resolvedPath = path30.resolve(paths);
|
|
48707
|
+
const normalizedCwd = path30.resolve(cwd);
|
|
48708
|
+
const normalizedResolved = path30.resolve(resolvedPath);
|
|
48430
48709
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
48431
48710
|
return {
|
|
48432
48711
|
error: "paths must be within the current working directory",
|
|
@@ -48442,13 +48721,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
48442
48721
|
}
|
|
48443
48722
|
}
|
|
48444
48723
|
function isSupportedExtension(filePath) {
|
|
48445
|
-
const ext =
|
|
48724
|
+
const ext = path30.extname(filePath).toLowerCase();
|
|
48446
48725
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
48447
48726
|
}
|
|
48448
48727
|
function findSourceFiles3(dir, files = []) {
|
|
48449
48728
|
let entries;
|
|
48450
48729
|
try {
|
|
48451
|
-
entries =
|
|
48730
|
+
entries = fs24.readdirSync(dir);
|
|
48452
48731
|
} catch {
|
|
48453
48732
|
return files;
|
|
48454
48733
|
}
|
|
@@ -48457,10 +48736,10 @@ function findSourceFiles3(dir, files = []) {
|
|
|
48457
48736
|
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
48458
48737
|
continue;
|
|
48459
48738
|
}
|
|
48460
|
-
const fullPath =
|
|
48739
|
+
const fullPath = path30.join(dir, entry);
|
|
48461
48740
|
let stat;
|
|
48462
48741
|
try {
|
|
48463
|
-
stat =
|
|
48742
|
+
stat = fs24.statSync(fullPath);
|
|
48464
48743
|
} catch {
|
|
48465
48744
|
continue;
|
|
48466
48745
|
}
|
|
@@ -48553,7 +48832,7 @@ var todo_extract = tool({
|
|
|
48553
48832
|
return JSON.stringify(errorResult, null, 2);
|
|
48554
48833
|
}
|
|
48555
48834
|
const scanPath = resolvedPath;
|
|
48556
|
-
if (!
|
|
48835
|
+
if (!fs24.existsSync(scanPath)) {
|
|
48557
48836
|
const errorResult = {
|
|
48558
48837
|
error: `path not found: ${pathsInput}`,
|
|
48559
48838
|
total: 0,
|
|
@@ -48563,13 +48842,13 @@ var todo_extract = tool({
|
|
|
48563
48842
|
return JSON.stringify(errorResult, null, 2);
|
|
48564
48843
|
}
|
|
48565
48844
|
const filesToScan = [];
|
|
48566
|
-
const stat =
|
|
48845
|
+
const stat = fs24.statSync(scanPath);
|
|
48567
48846
|
if (stat.isFile()) {
|
|
48568
48847
|
if (isSupportedExtension(scanPath)) {
|
|
48569
48848
|
filesToScan.push(scanPath);
|
|
48570
48849
|
} else {
|
|
48571
48850
|
const errorResult = {
|
|
48572
|
-
error: `unsupported file extension: ${
|
|
48851
|
+
error: `unsupported file extension: ${path30.extname(scanPath)}`,
|
|
48573
48852
|
total: 0,
|
|
48574
48853
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
48575
48854
|
entries: []
|
|
@@ -48582,11 +48861,11 @@ var todo_extract = tool({
|
|
|
48582
48861
|
const allEntries = [];
|
|
48583
48862
|
for (const filePath of filesToScan) {
|
|
48584
48863
|
try {
|
|
48585
|
-
const fileStat =
|
|
48864
|
+
const fileStat = fs24.statSync(filePath);
|
|
48586
48865
|
if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
|
|
48587
48866
|
continue;
|
|
48588
48867
|
}
|
|
48589
|
-
const content =
|
|
48868
|
+
const content = fs24.readFileSync(filePath, "utf-8");
|
|
48590
48869
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
48591
48870
|
allEntries.push(...entries);
|
|
48592
48871
|
} catch {}
|
|
@@ -48684,7 +48963,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
48684
48963
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
48685
48964
|
preflightTriggerManager = new PTM(automationConfig);
|
|
48686
48965
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
48687
|
-
const swarmDir =
|
|
48966
|
+
const swarmDir = path31.resolve(ctx.directory, ".swarm");
|
|
48688
48967
|
statusArtifact = new ASA(swarmDir);
|
|
48689
48968
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
48690
48969
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|