opencode-swarm 6.13.1 → 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 +23 -0
- package/dist/config/evidence-schema.d.ts +75 -3
- package/dist/config/index.d.ts +2 -2
- package/dist/config/schema.d.ts +48 -0
- package/dist/hooks/adversarial-detector.d.ts +15 -0
- package/dist/hooks/system-enhancer.d.ts +7 -0
- package/dist/index.js +824 -247
- package/dist/state.d.ts +13 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/phase-complete.d.ts +9 -0
- package/dist/tools/tool-names.d.ts +1 -1
- 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 = [
|
|
@@ -31449,7 +31465,8 @@ var TOOL_NAMES = [
|
|
|
31449
31465
|
"detect_domains",
|
|
31450
31466
|
"gitingest",
|
|
31451
31467
|
"retrieve_summary",
|
|
31452
|
-
"extract_code_blocks"
|
|
31468
|
+
"extract_code_blocks",
|
|
31469
|
+
"phase_complete"
|
|
31453
31470
|
];
|
|
31454
31471
|
var TOOL_NAME_SET = new Set(TOOL_NAMES);
|
|
31455
31472
|
|
|
@@ -31785,12 +31802,19 @@ var GateConfigSchema = exports_external.object({
|
|
|
31785
31802
|
var PipelineConfigSchema = exports_external.object({
|
|
31786
31803
|
parallel_precheck: exports_external.boolean().default(true)
|
|
31787
31804
|
});
|
|
31805
|
+
var PhaseCompleteConfigSchema = exports_external.object({
|
|
31806
|
+
enabled: exports_external.boolean().default(true),
|
|
31807
|
+
required_agents: exports_external.array(exports_external.enum(["coder", "reviewer", "test_engineer"])).default(["coder", "reviewer", "test_engineer"]),
|
|
31808
|
+
require_docs: exports_external.boolean().default(true),
|
|
31809
|
+
policy: exports_external.enum(["enforce", "warn"]).default("enforce")
|
|
31810
|
+
});
|
|
31788
31811
|
var SummaryConfigSchema = exports_external.object({
|
|
31789
31812
|
enabled: exports_external.boolean().default(true),
|
|
31790
31813
|
threshold_bytes: exports_external.number().min(1024).max(1048576).default(20480),
|
|
31791
31814
|
max_summary_chars: exports_external.number().min(100).max(5000).default(1000),
|
|
31792
31815
|
max_stored_bytes: exports_external.number().min(10240).max(104857600).default(10485760),
|
|
31793
|
-
retention_days: exports_external.number().min(1).max(365).default(7)
|
|
31816
|
+
retention_days: exports_external.number().min(1).max(365).default(7),
|
|
31817
|
+
exempt_tools: exports_external.array(exports_external.string()).default(["retrieve_summary", "task"])
|
|
31794
31818
|
});
|
|
31795
31819
|
var ReviewPassesConfigSchema = exports_external.object({
|
|
31796
31820
|
always_security_review: exports_external.boolean().default(false),
|
|
@@ -31804,6 +31828,11 @@ var ReviewPassesConfigSchema = exports_external.object({
|
|
|
31804
31828
|
"**/token/**"
|
|
31805
31829
|
])
|
|
31806
31830
|
});
|
|
31831
|
+
var AdversarialDetectionConfigSchema = exports_external.object({
|
|
31832
|
+
enabled: exports_external.boolean().default(true),
|
|
31833
|
+
policy: exports_external.enum(["warn", "gate", "ignore"]).default("warn"),
|
|
31834
|
+
pairs: exports_external.array(exports_external.tuple([exports_external.string(), exports_external.string()])).default([["coder", "reviewer"]])
|
|
31835
|
+
});
|
|
31807
31836
|
var IntegrationAnalysisConfigSchema = exports_external.object({
|
|
31808
31837
|
enabled: exports_external.boolean().default(true)
|
|
31809
31838
|
});
|
|
@@ -32035,6 +32064,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
32035
32064
|
swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
|
|
32036
32065
|
max_iterations: exports_external.number().min(1).max(10).default(5),
|
|
32037
32066
|
pipeline: PipelineConfigSchema.optional(),
|
|
32067
|
+
phase_complete: PhaseCompleteConfigSchema.optional(),
|
|
32038
32068
|
qa_retry_limit: exports_external.number().min(1).max(10).default(3),
|
|
32039
32069
|
inject_phase_reminders: exports_external.boolean().default(true),
|
|
32040
32070
|
hooks: HooksConfigSchema.optional(),
|
|
@@ -32046,6 +32076,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
32046
32076
|
evidence: EvidenceConfigSchema.optional(),
|
|
32047
32077
|
summaries: SummaryConfigSchema.optional(),
|
|
32048
32078
|
review_passes: ReviewPassesConfigSchema.optional(),
|
|
32079
|
+
adversarial_detection: AdversarialDetectionConfigSchema.optional(),
|
|
32049
32080
|
integration_analysis: IntegrationAnalysisConfigSchema.optional(),
|
|
32050
32081
|
docs: DocsConfigSchema.optional(),
|
|
32051
32082
|
ui_review: UIReviewConfigSchema.optional(),
|
|
@@ -32466,6 +32497,37 @@ Identify 1-3 relevant domains from the task requirements.
|
|
|
32466
32497
|
Call {{AGENT_PREFIX}}sme once per domain, serially. Max 3 SME calls per project phase.
|
|
32467
32498
|
Re-consult if a new domain emerges or if significant changes require fresh evaluation.
|
|
32468
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.
|
|
32469
32531
|
|
|
32470
32532
|
### MODE: PLAN
|
|
32471
32533
|
|
|
@@ -32482,6 +32544,15 @@ TASK GRANULARITY RULES:
|
|
|
32482
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.
|
|
32483
32545
|
- Coder receives ONE task. You make ALL scope decisions in the plan. Coder makes zero scope decisions.
|
|
32484
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
|
+
|
|
32485
32556
|
Create .swarm/context.md
|
|
32486
32557
|
- Decisions, patterns, SME cache, file map
|
|
32487
32558
|
|
|
@@ -32619,6 +32690,54 @@ PRE-COMMIT RULE \u2014 Before ANY commit or push:
|
|
|
32619
32690
|
|
|
32620
32691
|
5o. Update plan.md [x], proceed to next task.
|
|
32621
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
|
+
|
|
32622
32741
|
### MODE: PHASE-WRAP
|
|
32623
32742
|
1. {{AGENT_PREFIX}}explorer - Rescan
|
|
32624
32743
|
2. {{AGENT_PREFIX}}docs - Update documentation for all changes in this phase. Provide:
|
|
@@ -34451,7 +34570,10 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000) {
|
|
|
34451
34570
|
lastGateFailure: null,
|
|
34452
34571
|
partialGateWarningIssued: false,
|
|
34453
34572
|
selfFixAttempted: false,
|
|
34454
|
-
catastrophicPhaseWarnings: new Set
|
|
34573
|
+
catastrophicPhaseWarnings: new Set,
|
|
34574
|
+
lastPhaseCompleteTimestamp: 0,
|
|
34575
|
+
lastPhaseCompletePhase: 0,
|
|
34576
|
+
phaseAgentsDispatched: new Set
|
|
34455
34577
|
};
|
|
34456
34578
|
swarmState.agentSessions.set(sessionId, sessionState);
|
|
34457
34579
|
swarmState.activeAgent.set(sessionId, agentName);
|
|
@@ -34502,6 +34624,15 @@ function ensureAgentSession(sessionId, agentName) {
|
|
|
34502
34624
|
if (!session.catastrophicPhaseWarnings) {
|
|
34503
34625
|
session.catastrophicPhaseWarnings = new Set;
|
|
34504
34626
|
}
|
|
34627
|
+
if (session.lastPhaseCompleteTimestamp === undefined) {
|
|
34628
|
+
session.lastPhaseCompleteTimestamp = 0;
|
|
34629
|
+
}
|
|
34630
|
+
if (session.lastPhaseCompletePhase === undefined) {
|
|
34631
|
+
session.lastPhaseCompletePhase = 0;
|
|
34632
|
+
}
|
|
34633
|
+
if (!session.phaseAgentsDispatched) {
|
|
34634
|
+
session.phaseAgentsDispatched = new Set;
|
|
34635
|
+
}
|
|
34505
34636
|
session.lastToolCallTime = now;
|
|
34506
34637
|
return session;
|
|
34507
34638
|
}
|
|
@@ -34570,6 +34701,17 @@ function pruneOldWindows(sessionId, maxAgeMs = 24 * 60 * 60 * 1000, maxWindows =
|
|
|
34570
34701
|
const toKeep = sorted.slice(0, maxWindows);
|
|
34571
34702
|
session.windows = Object.fromEntries(toKeep);
|
|
34572
34703
|
}
|
|
34704
|
+
function recordPhaseAgentDispatch(sessionId, agentName) {
|
|
34705
|
+
const session = swarmState.agentSessions.get(sessionId);
|
|
34706
|
+
if (!session) {
|
|
34707
|
+
return;
|
|
34708
|
+
}
|
|
34709
|
+
if (!session.phaseAgentsDispatched) {
|
|
34710
|
+
session.phaseAgentsDispatched = new Set;
|
|
34711
|
+
}
|
|
34712
|
+
const normalizedName = stripKnownSwarmPrefix(agentName);
|
|
34713
|
+
session.phaseAgentsDispatched.add(normalizedName);
|
|
34714
|
+
}
|
|
34573
34715
|
|
|
34574
34716
|
// src/commands/benchmark.ts
|
|
34575
34717
|
init_utils();
|
|
@@ -36680,6 +36822,7 @@ function createDelegationTrackerHook(config3, guardrailsEnabled = true) {
|
|
|
36680
36822
|
const isArchitect = strippedAgent === ORCHESTRATOR_NAME;
|
|
36681
36823
|
const session = ensureAgentSession(input.sessionID, agentName);
|
|
36682
36824
|
session.delegationActive = !isArchitect;
|
|
36825
|
+
recordPhaseAgentDispatch(input.sessionID, agentName);
|
|
36683
36826
|
if (!isArchitect && guardrailsEnabled) {
|
|
36684
36827
|
beginInvocation(input.sessionID, agentName);
|
|
36685
36828
|
}
|
|
@@ -37131,8 +37274,8 @@ function hashArgs(args2) {
|
|
|
37131
37274
|
// src/hooks/messages-transform.ts
|
|
37132
37275
|
function consolidateSystemMessages(messages) {
|
|
37133
37276
|
if (messages.length > 0 && messages[0].role === "system" && messages[0].content !== undefined && typeof messages[0].content === "string" && messages[0].content.trim().length > 0) {
|
|
37134
|
-
const
|
|
37135
|
-
if (
|
|
37277
|
+
const totalSystemCount = messages.filter((m) => m.role === "system").length;
|
|
37278
|
+
if (totalSystemCount === 1) {
|
|
37136
37279
|
return [...messages];
|
|
37137
37280
|
}
|
|
37138
37281
|
}
|
|
@@ -37140,34 +37283,31 @@ function consolidateSystemMessages(messages) {
|
|
|
37140
37283
|
const systemContents = [];
|
|
37141
37284
|
for (let i2 = 0;i2 < messages.length; i2++) {
|
|
37142
37285
|
const message = messages[i2];
|
|
37143
|
-
if (message.role !== "system")
|
|
37286
|
+
if (message.role !== "system")
|
|
37144
37287
|
continue;
|
|
37145
|
-
|
|
37146
|
-
if (message.tool_call_id !== undefined || message.name !== undefined) {
|
|
37147
|
-
continue;
|
|
37148
|
-
}
|
|
37149
|
-
if (typeof message.content !== "string") {
|
|
37150
|
-
continue;
|
|
37151
|
-
}
|
|
37152
|
-
const trimmedContent = message.content.trim();
|
|
37153
|
-
if (trimmedContent.length === 0) {
|
|
37288
|
+
if (message.tool_call_id !== undefined || message.name !== undefined)
|
|
37154
37289
|
continue;
|
|
37290
|
+
let textContent = null;
|
|
37291
|
+
if (typeof message.content === "string") {
|
|
37292
|
+
const trimmed = message.content.trim();
|
|
37293
|
+
if (trimmed.length > 0)
|
|
37294
|
+
textContent = trimmed;
|
|
37295
|
+
} else if (Array.isArray(message.content)) {
|
|
37296
|
+
const texts = message.content.filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text.trim()).filter((t) => t.length > 0);
|
|
37297
|
+
if (texts.length > 0)
|
|
37298
|
+
textContent = texts.join(`
|
|
37299
|
+
`);
|
|
37155
37300
|
}
|
|
37156
37301
|
systemMessageIndices.push(i2);
|
|
37157
|
-
|
|
37302
|
+
if (textContent) {
|
|
37303
|
+
systemContents.push(textContent);
|
|
37304
|
+
}
|
|
37158
37305
|
}
|
|
37159
37306
|
if (systemContents.length === 0) {
|
|
37160
|
-
return messages.filter((m) => {
|
|
37161
|
-
if (m.role !== "system")
|
|
37162
|
-
return true;
|
|
37163
|
-
}
|
|
37164
|
-
if (typeof m.content !== "string" || m.name !== undefined || m.tool_call_id !== undefined) {
|
|
37307
|
+
return messages.filter((m, idx) => {
|
|
37308
|
+
if (m.role !== "system")
|
|
37165
37309
|
return true;
|
|
37166
|
-
|
|
37167
|
-
if (m.content.trim().length > 0) {
|
|
37168
|
-
return true;
|
|
37169
|
-
}
|
|
37170
|
-
return false;
|
|
37310
|
+
return idx === 0;
|
|
37171
37311
|
});
|
|
37172
37312
|
}
|
|
37173
37313
|
const mergedSystemContent = systemContents.join(`
|
|
@@ -37178,7 +37318,7 @@ function consolidateSystemMessages(messages) {
|
|
|
37178
37318
|
result.push({
|
|
37179
37319
|
role: "system",
|
|
37180
37320
|
content: mergedSystemContent,
|
|
37181
|
-
...Object.fromEntries(Object.entries(firstSystemMessage).filter(([key]) => key !== "role" && key !== "content"))
|
|
37321
|
+
...Object.fromEntries(Object.entries(firstSystemMessage).filter(([key]) => key !== "role" && key !== "content" && key !== "name" && key !== "tool_call_id"))
|
|
37182
37322
|
});
|
|
37183
37323
|
for (let i2 = 0;i2 < messages.length; i2++) {
|
|
37184
37324
|
const message = messages[i2];
|
|
@@ -37190,7 +37330,11 @@ function consolidateSystemMessages(messages) {
|
|
|
37190
37330
|
}
|
|
37191
37331
|
result.push({ ...message });
|
|
37192
37332
|
}
|
|
37193
|
-
return result
|
|
37333
|
+
return result.filter((msg, idx) => {
|
|
37334
|
+
if (idx === 0)
|
|
37335
|
+
return true;
|
|
37336
|
+
return msg.role !== "system";
|
|
37337
|
+
});
|
|
37194
37338
|
}
|
|
37195
37339
|
// src/hooks/phase-monitor.ts
|
|
37196
37340
|
init_manager2();
|
|
@@ -37304,8 +37448,7 @@ ${originalText}`;
|
|
|
37304
37448
|
};
|
|
37305
37449
|
}
|
|
37306
37450
|
// src/hooks/system-enhancer.ts
|
|
37307
|
-
|
|
37308
|
-
import * as path17 from "path";
|
|
37451
|
+
init_manager();
|
|
37309
37452
|
init_manager2();
|
|
37310
37453
|
|
|
37311
37454
|
// src/services/decision-drift-analyzer.ts
|
|
@@ -37585,6 +37728,39 @@ init_preflight_service();
|
|
|
37585
37728
|
// src/hooks/system-enhancer.ts
|
|
37586
37729
|
init_utils();
|
|
37587
37730
|
|
|
37731
|
+
// src/hooks/adversarial-detector.ts
|
|
37732
|
+
function safeGet(obj, key) {
|
|
37733
|
+
if (!obj || !Object.hasOwn(obj, key))
|
|
37734
|
+
return;
|
|
37735
|
+
return obj[key];
|
|
37736
|
+
}
|
|
37737
|
+
function resolveAgentModel(agentName, config3) {
|
|
37738
|
+
const baseName = stripKnownSwarmPrefix(agentName).toLowerCase();
|
|
37739
|
+
const agentOverride = safeGet(config3.agents, baseName)?.model;
|
|
37740
|
+
if (agentOverride)
|
|
37741
|
+
return agentOverride;
|
|
37742
|
+
if (config3.swarms) {
|
|
37743
|
+
for (const swarm of Object.values(config3.swarms)) {
|
|
37744
|
+
const swarmModel = safeGet(swarm.agents, baseName)?.model;
|
|
37745
|
+
if (swarmModel)
|
|
37746
|
+
return swarmModel;
|
|
37747
|
+
}
|
|
37748
|
+
}
|
|
37749
|
+
const defaultModel = safeGet(DEFAULT_MODELS, baseName);
|
|
37750
|
+
return defaultModel ?? DEFAULT_MODELS.default;
|
|
37751
|
+
}
|
|
37752
|
+
function detectAdversarialPair(agentA, agentB, config3) {
|
|
37753
|
+
const modelA = resolveAgentModel(agentA, config3).toLowerCase();
|
|
37754
|
+
const modelB = resolveAgentModel(agentB, config3).toLowerCase();
|
|
37755
|
+
return modelA === modelB ? modelA : null;
|
|
37756
|
+
}
|
|
37757
|
+
function formatAdversarialWarning(agentA, agentB, sharedModel, policy) {
|
|
37758
|
+
if (policy === "gate") {
|
|
37759
|
+
return `\u26A0\uFE0F GATE POLICY: Same-model adversarial pair detected. Agent ${agentA} and checker ${agentB} both use model ${sharedModel}. This requires extra scrutiny \u2014 escalate if issues are found.`;
|
|
37760
|
+
}
|
|
37761
|
+
return `\u26A0\uFE0F Same-model adversarial pair detected. Agent ${agentA} and checker ${agentB} both use model ${sharedModel}. Review may lack independence.`;
|
|
37762
|
+
}
|
|
37763
|
+
|
|
37588
37764
|
// src/hooks/context-scoring.ts
|
|
37589
37765
|
function calculateAgeFactor(ageHours, config3) {
|
|
37590
37766
|
if (ageHours <= 0) {
|
|
@@ -37649,6 +37825,170 @@ function estimateContentType(text) {
|
|
|
37649
37825
|
}
|
|
37650
37826
|
return "prose";
|
|
37651
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
|
+
}
|
|
37652
37992
|
function createSystemEnhancerHook(config3, directory) {
|
|
37653
37993
|
const enabled = config3.hooks?.system_enhancer !== false;
|
|
37654
37994
|
if (!enabled) {
|
|
@@ -37727,6 +38067,35 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
37727
38067
|
if (config3.secretscan?.enabled === false) {
|
|
37728
38068
|
tryInject("[SWARM CONFIG] Secretscan gate is DISABLED. Skip secretscan in QA sequence.");
|
|
37729
38069
|
}
|
|
38070
|
+
const activeAgent_hf1 = swarmState.activeAgent.get(_input.sessionID ?? "");
|
|
38071
|
+
const baseRole = activeAgent_hf1 ? stripKnownSwarmPrefix(activeAgent_hf1) : null;
|
|
38072
|
+
if (baseRole === "coder" || baseRole === "test_engineer") {
|
|
38073
|
+
tryInject("[SWARM CONFIG] You must NOT run build, test, lint, or type-check commands (npm run build, bun test, npx tsc, eslint, etc.). Make ONLY the code changes specified in your task. Verification is handled by the reviewer agent \u2014 do not self-verify. If your task explicitly asks you to run a specific command, that is the only exception.");
|
|
38074
|
+
}
|
|
38075
|
+
if (baseRole === "architect" || baseRole === null) {
|
|
38076
|
+
tryInject("[SWARM CONFIG] You must NEVER run the full test suite or batch test files. If you need to verify changes, run ONLY the specific test files for code YOU modified in this session \u2014 one file at a time, strictly serial. Do not run tests from directories or files unrelated to your changes. Do not run bun test without an explicit file path. When possible, delegate test execution to the test_engineer agent instead of running tests yourself.");
|
|
38077
|
+
}
|
|
38078
|
+
if (config3.adversarial_detection?.enabled !== false) {
|
|
38079
|
+
const activeAgent_adv = swarmState.activeAgent.get(_input.sessionID ?? "");
|
|
38080
|
+
if (activeAgent_adv) {
|
|
38081
|
+
const baseRole_adv = stripKnownSwarmPrefix(activeAgent_adv);
|
|
38082
|
+
const pairs_adv = config3.adversarial_detection?.pairs ?? [
|
|
38083
|
+
["coder", "reviewer"]
|
|
38084
|
+
];
|
|
38085
|
+
const policy_adv = config3.adversarial_detection?.policy ?? "warn";
|
|
38086
|
+
for (const [agentA, agentB] of pairs_adv) {
|
|
38087
|
+
if (baseRole_adv === agentB) {
|
|
38088
|
+
const sharedModel = detectAdversarialPair(agentA, agentB, config3);
|
|
38089
|
+
if (sharedModel) {
|
|
38090
|
+
const warningText = formatAdversarialWarning(agentA, agentB, sharedModel, policy_adv);
|
|
38091
|
+
if (policy_adv !== "ignore") {
|
|
38092
|
+
tryInject(`[SWARM CONFIG] ${warningText}`);
|
|
38093
|
+
}
|
|
38094
|
+
}
|
|
38095
|
+
}
|
|
38096
|
+
}
|
|
38097
|
+
}
|
|
38098
|
+
}
|
|
37730
38099
|
if (mode !== "DISCOVER") {
|
|
37731
38100
|
const sessionId_preflight = _input.sessionID;
|
|
37732
38101
|
const activeAgent_preflight = swarmState.activeAgent.get(sessionId_preflight ?? "");
|
|
@@ -37739,43 +38108,27 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
37739
38108
|
}
|
|
37740
38109
|
}
|
|
37741
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
|
+
}
|
|
37742
38120
|
const sessionId_retro = _input.sessionID;
|
|
37743
38121
|
const activeAgent_retro = swarmState.activeAgent.get(sessionId_retro ?? "");
|
|
37744
38122
|
const isArchitect2 = !activeAgent_retro || stripKnownSwarmPrefix(activeAgent_retro) === "architect";
|
|
37745
38123
|
if (isArchitect2) {
|
|
37746
38124
|
try {
|
|
37747
|
-
const
|
|
37748
|
-
|
|
37749
|
-
|
|
37750
|
-
|
|
37751
|
-
|
|
37752
|
-
|
|
37753
|
-
|
|
37754
|
-
} catch {
|
|
37755
|
-
continue;
|
|
37756
|
-
}
|
|
37757
|
-
if (content !== null && typeof content === "object" && content.type === "retrospective") {
|
|
37758
|
-
const retro = content;
|
|
37759
|
-
const hints = [];
|
|
37760
|
-
if (retro.reviewer_rejections > 2) {
|
|
37761
|
-
hints.push(`Phase ${retro.phase_number} had ${retro.reviewer_rejections} reviewer rejections.`);
|
|
37762
|
-
}
|
|
37763
|
-
if (retro.top_rejection_reasons.length > 0) {
|
|
37764
|
-
hints.push(`Common rejection reasons: ${retro.top_rejection_reasons.join(", ")}.`);
|
|
37765
|
-
}
|
|
37766
|
-
if (retro.lessons_learned.length > 0) {
|
|
37767
|
-
hints.push(`Lessons: ${retro.lessons_learned.join("; ")}.`);
|
|
37768
|
-
}
|
|
37769
|
-
if (hints.length > 0) {
|
|
37770
|
-
const retroHint = `[SWARM RETROSPECTIVE] From Phase ${retro.phase_number}: ${hints.join(" ")}`;
|
|
37771
|
-
if (retroHint.length <= 800) {
|
|
37772
|
-
tryInject(retroHint);
|
|
37773
|
-
} else {
|
|
37774
|
-
tryInject(`${retroHint.substring(0, 800)}...`);
|
|
37775
|
-
}
|
|
37776
|
-
}
|
|
37777
|
-
break;
|
|
37778
|
-
}
|
|
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)}...`);
|
|
37779
38132
|
}
|
|
37780
38133
|
}
|
|
37781
38134
|
} catch {}
|
|
@@ -37988,6 +38341,34 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
37988
38341
|
metadata: { contentType: "prose" }
|
|
37989
38342
|
});
|
|
37990
38343
|
}
|
|
38344
|
+
if (config3.adversarial_detection?.enabled !== false) {
|
|
38345
|
+
const activeAgent_adv_b = swarmState.activeAgent.get(_input.sessionID ?? "");
|
|
38346
|
+
if (activeAgent_adv_b) {
|
|
38347
|
+
const baseRole_adv_b = stripKnownSwarmPrefix(activeAgent_adv_b);
|
|
38348
|
+
const pairs_adv_b = config3.adversarial_detection?.pairs ?? [
|
|
38349
|
+
["coder", "reviewer"]
|
|
38350
|
+
];
|
|
38351
|
+
const policy_adv_b = config3.adversarial_detection?.policy ?? "warn";
|
|
38352
|
+
for (const [agentA_b, agentB_b] of pairs_adv_b) {
|
|
38353
|
+
if (baseRole_adv_b === agentB_b) {
|
|
38354
|
+
const sharedModel_b = detectAdversarialPair(agentA_b, agentB_b, config3);
|
|
38355
|
+
if (sharedModel_b) {
|
|
38356
|
+
const warningText_b = formatAdversarialWarning(agentA_b, agentB_b, sharedModel_b, policy_adv_b);
|
|
38357
|
+
if (policy_adv_b !== "ignore") {
|
|
38358
|
+
candidates.push({
|
|
38359
|
+
id: `candidate-${idCounter++}`,
|
|
38360
|
+
kind: "agent_context",
|
|
38361
|
+
text: `[SWARM CONFIG] ${warningText_b}`,
|
|
38362
|
+
tokens: estimateTokens(warningText_b),
|
|
38363
|
+
priority: 2,
|
|
38364
|
+
metadata: { contentType: "prose" }
|
|
38365
|
+
});
|
|
38366
|
+
}
|
|
38367
|
+
}
|
|
38368
|
+
}
|
|
38369
|
+
}
|
|
38370
|
+
}
|
|
38371
|
+
}
|
|
37991
38372
|
const sessionId_preflight_b = _input.sessionID;
|
|
37992
38373
|
const activeAgent_preflight_b = swarmState.activeAgent.get(sessionId_preflight_b ?? "");
|
|
37993
38374
|
const isArchitectForPreflight_b = !activeAgent_preflight_b || stripKnownSwarmPrefix(activeAgent_preflight_b) === "architect";
|
|
@@ -38007,43 +38388,18 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
38007
38388
|
const isArchitect_b = !activeAgent_retro_b || stripKnownSwarmPrefix(activeAgent_retro_b) === "architect";
|
|
38008
38389
|
if (isArchitect_b) {
|
|
38009
38390
|
try {
|
|
38010
|
-
const
|
|
38011
|
-
|
|
38012
|
-
|
|
38013
|
-
|
|
38014
|
-
|
|
38015
|
-
|
|
38016
|
-
|
|
38017
|
-
|
|
38018
|
-
|
|
38019
|
-
|
|
38020
|
-
|
|
38021
|
-
|
|
38022
|
-
const hints_b = [];
|
|
38023
|
-
if (retro_b.reviewer_rejections > 2) {
|
|
38024
|
-
hints_b.push(`Phase ${retro_b.phase_number} had ${retro_b.reviewer_rejections} reviewer rejections.`);
|
|
38025
|
-
}
|
|
38026
|
-
if (retro_b.top_rejection_reasons.length > 0) {
|
|
38027
|
-
hints_b.push(`Common rejection reasons: ${retro_b.top_rejection_reasons.join(", ")}.`);
|
|
38028
|
-
}
|
|
38029
|
-
if (retro_b.lessons_learned.length > 0) {
|
|
38030
|
-
hints_b.push(`Lessons: ${retro_b.lessons_learned.join("; ")}.`);
|
|
38031
|
-
}
|
|
38032
|
-
if (hints_b.length > 0) {
|
|
38033
|
-
const retroHint_b = `[SWARM RETROSPECTIVE] From Phase ${retro_b.phase_number}: ${hints_b.join(" ")}`;
|
|
38034
|
-
const retroText = retroHint_b.length <= 800 ? retroHint_b : `${retroHint_b.substring(0, 800)}...`;
|
|
38035
|
-
candidates.push({
|
|
38036
|
-
id: `candidate-${idCounter++}`,
|
|
38037
|
-
kind: "phase",
|
|
38038
|
-
text: retroText,
|
|
38039
|
-
tokens: estimateTokens(retroText),
|
|
38040
|
-
priority: 2,
|
|
38041
|
-
metadata: { contentType: "prose" }
|
|
38042
|
-
});
|
|
38043
|
-
}
|
|
38044
|
-
break;
|
|
38045
|
-
}
|
|
38046
|
-
}
|
|
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
|
+
});
|
|
38047
38403
|
}
|
|
38048
38404
|
} catch {}
|
|
38049
38405
|
if (mode_b !== "DISCOVER") {
|
|
@@ -38081,6 +38437,24 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
38081
38437
|
}
|
|
38082
38438
|
}
|
|
38083
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
|
+
}
|
|
38084
38458
|
const automationCapabilities_b = config3.automation?.capabilities;
|
|
38085
38459
|
if (automationCapabilities_b?.decision_drift_detection === true && sessionId_retro_b) {
|
|
38086
38460
|
const activeAgentForDrift_b = swarmState.activeAgent.get(sessionId_retro_b ?? "");
|
|
@@ -38306,6 +38680,10 @@ function createToolSummarizerHook(config3, directory) {
|
|
|
38306
38680
|
if (typeof output.output !== "string" || output.output.length === 0) {
|
|
38307
38681
|
return;
|
|
38308
38682
|
}
|
|
38683
|
+
const exemptTools = config3.exempt_tools ?? ["retrieve_summary", "task"];
|
|
38684
|
+
if (exemptTools.includes(input.tool)) {
|
|
38685
|
+
return;
|
|
38686
|
+
}
|
|
38309
38687
|
if (!shouldSummarize(output.output, config3.threshold_bytes)) {
|
|
38310
38688
|
return;
|
|
38311
38689
|
}
|
|
@@ -38331,8 +38709,8 @@ init_dist();
|
|
|
38331
38709
|
|
|
38332
38710
|
// src/build/discovery.ts
|
|
38333
38711
|
init_dist();
|
|
38334
|
-
import * as
|
|
38335
|
-
import * as
|
|
38712
|
+
import * as fs11 from "fs";
|
|
38713
|
+
import * as path17 from "path";
|
|
38336
38714
|
var ECOSYSTEMS = [
|
|
38337
38715
|
{
|
|
38338
38716
|
ecosystem: "node",
|
|
@@ -38444,18 +38822,18 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
38444
38822
|
if (pattern.includes("*")) {
|
|
38445
38823
|
const dir = workingDir;
|
|
38446
38824
|
try {
|
|
38447
|
-
const files =
|
|
38825
|
+
const files = fs11.readdirSync(dir);
|
|
38448
38826
|
const matches = files.filter((f) => {
|
|
38449
38827
|
const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
|
|
38450
38828
|
return regex.test(f);
|
|
38451
38829
|
});
|
|
38452
38830
|
if (matches.length > 0) {
|
|
38453
|
-
return
|
|
38831
|
+
return path17.join(dir, matches[0]);
|
|
38454
38832
|
}
|
|
38455
38833
|
} catch {}
|
|
38456
38834
|
} else {
|
|
38457
|
-
const filePath =
|
|
38458
|
-
if (
|
|
38835
|
+
const filePath = path17.join(workingDir, pattern);
|
|
38836
|
+
if (fs11.existsSync(filePath)) {
|
|
38459
38837
|
return filePath;
|
|
38460
38838
|
}
|
|
38461
38839
|
}
|
|
@@ -38463,12 +38841,12 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
38463
38841
|
return null;
|
|
38464
38842
|
}
|
|
38465
38843
|
function getRepoDefinedScripts(workingDir, scripts) {
|
|
38466
|
-
const packageJsonPath =
|
|
38467
|
-
if (!
|
|
38844
|
+
const packageJsonPath = path17.join(workingDir, "package.json");
|
|
38845
|
+
if (!fs11.existsSync(packageJsonPath)) {
|
|
38468
38846
|
return [];
|
|
38469
38847
|
}
|
|
38470
38848
|
try {
|
|
38471
|
-
const content =
|
|
38849
|
+
const content = fs11.readFileSync(packageJsonPath, "utf-8");
|
|
38472
38850
|
const pkg = JSON.parse(content);
|
|
38473
38851
|
if (!pkg.scripts || typeof pkg.scripts !== "object") {
|
|
38474
38852
|
return [];
|
|
@@ -38504,8 +38882,8 @@ function findAllBuildFiles(workingDir) {
|
|
|
38504
38882
|
const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
|
|
38505
38883
|
findFilesRecursive(workingDir, regex, allBuildFiles);
|
|
38506
38884
|
} else {
|
|
38507
|
-
const filePath =
|
|
38508
|
-
if (
|
|
38885
|
+
const filePath = path17.join(workingDir, pattern);
|
|
38886
|
+
if (fs11.existsSync(filePath)) {
|
|
38509
38887
|
allBuildFiles.add(filePath);
|
|
38510
38888
|
}
|
|
38511
38889
|
}
|
|
@@ -38515,9 +38893,9 @@ function findAllBuildFiles(workingDir) {
|
|
|
38515
38893
|
}
|
|
38516
38894
|
function findFilesRecursive(dir, regex, results) {
|
|
38517
38895
|
try {
|
|
38518
|
-
const entries =
|
|
38896
|
+
const entries = fs11.readdirSync(dir, { withFileTypes: true });
|
|
38519
38897
|
for (const entry of entries) {
|
|
38520
|
-
const fullPath =
|
|
38898
|
+
const fullPath = path17.join(dir, entry.name);
|
|
38521
38899
|
if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
|
|
38522
38900
|
findFilesRecursive(fullPath, regex, results);
|
|
38523
38901
|
} else if (entry.isFile() && regex.test(entry.name)) {
|
|
@@ -38758,8 +39136,8 @@ var build_check = tool({
|
|
|
38758
39136
|
// src/tools/checkpoint.ts
|
|
38759
39137
|
init_tool();
|
|
38760
39138
|
import { spawnSync } from "child_process";
|
|
38761
|
-
import * as
|
|
38762
|
-
import * as
|
|
39139
|
+
import * as fs12 from "fs";
|
|
39140
|
+
import * as path18 from "path";
|
|
38763
39141
|
var CHECKPOINT_LOG_PATH = ".swarm/checkpoints.json";
|
|
38764
39142
|
var MAX_LABEL_LENGTH = 100;
|
|
38765
39143
|
var GIT_TIMEOUT_MS = 30000;
|
|
@@ -38810,13 +39188,13 @@ function validateLabel(label) {
|
|
|
38810
39188
|
return null;
|
|
38811
39189
|
}
|
|
38812
39190
|
function getCheckpointLogPath() {
|
|
38813
|
-
return
|
|
39191
|
+
return path18.join(process.cwd(), CHECKPOINT_LOG_PATH);
|
|
38814
39192
|
}
|
|
38815
39193
|
function readCheckpointLog() {
|
|
38816
39194
|
const logPath = getCheckpointLogPath();
|
|
38817
39195
|
try {
|
|
38818
|
-
if (
|
|
38819
|
-
const content =
|
|
39196
|
+
if (fs12.existsSync(logPath)) {
|
|
39197
|
+
const content = fs12.readFileSync(logPath, "utf-8");
|
|
38820
39198
|
const parsed = JSON.parse(content);
|
|
38821
39199
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
38822
39200
|
return { version: 1, checkpoints: [] };
|
|
@@ -38828,13 +39206,13 @@ function readCheckpointLog() {
|
|
|
38828
39206
|
}
|
|
38829
39207
|
function writeCheckpointLog(log2) {
|
|
38830
39208
|
const logPath = getCheckpointLogPath();
|
|
38831
|
-
const dir =
|
|
38832
|
-
if (!
|
|
38833
|
-
|
|
39209
|
+
const dir = path18.dirname(logPath);
|
|
39210
|
+
if (!fs12.existsSync(dir)) {
|
|
39211
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
38834
39212
|
}
|
|
38835
39213
|
const tempPath = `${logPath}.tmp`;
|
|
38836
|
-
|
|
38837
|
-
|
|
39214
|
+
fs12.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
|
|
39215
|
+
fs12.renameSync(tempPath, logPath);
|
|
38838
39216
|
}
|
|
38839
39217
|
function gitExec(args2) {
|
|
38840
39218
|
const result = spawnSync("git", args2, {
|
|
@@ -39034,8 +39412,8 @@ var checkpoint = tool({
|
|
|
39034
39412
|
});
|
|
39035
39413
|
// src/tools/complexity-hotspots.ts
|
|
39036
39414
|
init_dist();
|
|
39037
|
-
import * as
|
|
39038
|
-
import * as
|
|
39415
|
+
import * as fs13 from "fs";
|
|
39416
|
+
import * as path19 from "path";
|
|
39039
39417
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
39040
39418
|
var DEFAULT_DAYS = 90;
|
|
39041
39419
|
var DEFAULT_TOP_N = 20;
|
|
@@ -39163,11 +39541,11 @@ function estimateComplexity(content) {
|
|
|
39163
39541
|
}
|
|
39164
39542
|
function getComplexityForFile(filePath) {
|
|
39165
39543
|
try {
|
|
39166
|
-
const stat =
|
|
39544
|
+
const stat = fs13.statSync(filePath);
|
|
39167
39545
|
if (stat.size > MAX_FILE_SIZE_BYTES2) {
|
|
39168
39546
|
return null;
|
|
39169
39547
|
}
|
|
39170
|
-
const content =
|
|
39548
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
39171
39549
|
return estimateComplexity(content);
|
|
39172
39550
|
} catch {
|
|
39173
39551
|
return null;
|
|
@@ -39178,7 +39556,7 @@ async function analyzeHotspots(days, topN, extensions) {
|
|
|
39178
39556
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
39179
39557
|
const filteredChurn = new Map;
|
|
39180
39558
|
for (const [file3, count] of churnMap) {
|
|
39181
|
-
const ext =
|
|
39559
|
+
const ext = path19.extname(file3).toLowerCase();
|
|
39182
39560
|
if (extSet.has(ext)) {
|
|
39183
39561
|
filteredChurn.set(file3, count);
|
|
39184
39562
|
}
|
|
@@ -39188,8 +39566,8 @@ async function analyzeHotspots(days, topN, extensions) {
|
|
|
39188
39566
|
let analyzedFiles = 0;
|
|
39189
39567
|
for (const [file3, churnCount] of filteredChurn) {
|
|
39190
39568
|
let fullPath = file3;
|
|
39191
|
-
if (!
|
|
39192
|
-
fullPath =
|
|
39569
|
+
if (!fs13.existsSync(fullPath)) {
|
|
39570
|
+
fullPath = path19.join(cwd, file3);
|
|
39193
39571
|
}
|
|
39194
39572
|
const complexity = getComplexityForFile(fullPath);
|
|
39195
39573
|
if (complexity !== null) {
|
|
@@ -39347,14 +39725,14 @@ function validateBase(base) {
|
|
|
39347
39725
|
function validatePaths(paths) {
|
|
39348
39726
|
if (!paths)
|
|
39349
39727
|
return null;
|
|
39350
|
-
for (const
|
|
39351
|
-
if (!
|
|
39728
|
+
for (const path20 of paths) {
|
|
39729
|
+
if (!path20 || path20.length === 0) {
|
|
39352
39730
|
return "empty path not allowed";
|
|
39353
39731
|
}
|
|
39354
|
-
if (
|
|
39732
|
+
if (path20.length > MAX_PATH_LENGTH) {
|
|
39355
39733
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
39356
39734
|
}
|
|
39357
|
-
if (SHELL_METACHARACTERS2.test(
|
|
39735
|
+
if (SHELL_METACHARACTERS2.test(path20)) {
|
|
39358
39736
|
return "path contains shell metacharacters";
|
|
39359
39737
|
}
|
|
39360
39738
|
}
|
|
@@ -39417,8 +39795,8 @@ var diff = tool({
|
|
|
39417
39795
|
if (parts2.length >= 3) {
|
|
39418
39796
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
39419
39797
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
39420
|
-
const
|
|
39421
|
-
files.push({ path:
|
|
39798
|
+
const path20 = parts2[2];
|
|
39799
|
+
files.push({ path: path20, additions, deletions });
|
|
39422
39800
|
}
|
|
39423
39801
|
}
|
|
39424
39802
|
const contractChanges = [];
|
|
@@ -39646,8 +40024,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
39646
40024
|
});
|
|
39647
40025
|
// src/tools/evidence-check.ts
|
|
39648
40026
|
init_dist();
|
|
39649
|
-
import * as
|
|
39650
|
-
import * as
|
|
40027
|
+
import * as fs14 from "fs";
|
|
40028
|
+
import * as path20 from "path";
|
|
39651
40029
|
var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
|
|
39652
40030
|
var MAX_EVIDENCE_FILES = 1000;
|
|
39653
40031
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
@@ -39670,9 +40048,9 @@ function validateRequiredTypes(input) {
|
|
|
39670
40048
|
return null;
|
|
39671
40049
|
}
|
|
39672
40050
|
function isPathWithinSwarm(filePath, cwd) {
|
|
39673
|
-
const normalizedCwd =
|
|
39674
|
-
const swarmPath =
|
|
39675
|
-
const normalizedPath =
|
|
40051
|
+
const normalizedCwd = path20.resolve(cwd);
|
|
40052
|
+
const swarmPath = path20.join(normalizedCwd, ".swarm");
|
|
40053
|
+
const normalizedPath = path20.resolve(filePath);
|
|
39676
40054
|
return normalizedPath.startsWith(swarmPath);
|
|
39677
40055
|
}
|
|
39678
40056
|
function parseCompletedTasks(planContent) {
|
|
@@ -39688,12 +40066,12 @@ function parseCompletedTasks(planContent) {
|
|
|
39688
40066
|
}
|
|
39689
40067
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
39690
40068
|
const evidence = [];
|
|
39691
|
-
if (!
|
|
40069
|
+
if (!fs14.existsSync(evidenceDir) || !fs14.statSync(evidenceDir).isDirectory()) {
|
|
39692
40070
|
return evidence;
|
|
39693
40071
|
}
|
|
39694
40072
|
let files;
|
|
39695
40073
|
try {
|
|
39696
|
-
files =
|
|
40074
|
+
files = fs14.readdirSync(evidenceDir);
|
|
39697
40075
|
} catch {
|
|
39698
40076
|
return evidence;
|
|
39699
40077
|
}
|
|
@@ -39702,14 +40080,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
39702
40080
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
39703
40081
|
continue;
|
|
39704
40082
|
}
|
|
39705
|
-
const filePath =
|
|
40083
|
+
const filePath = path20.join(evidenceDir, filename);
|
|
39706
40084
|
try {
|
|
39707
|
-
const resolvedPath =
|
|
39708
|
-
const evidenceDirResolved =
|
|
40085
|
+
const resolvedPath = path20.resolve(filePath);
|
|
40086
|
+
const evidenceDirResolved = path20.resolve(evidenceDir);
|
|
39709
40087
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
39710
40088
|
continue;
|
|
39711
40089
|
}
|
|
39712
|
-
const stat =
|
|
40090
|
+
const stat = fs14.lstatSync(filePath);
|
|
39713
40091
|
if (!stat.isFile()) {
|
|
39714
40092
|
continue;
|
|
39715
40093
|
}
|
|
@@ -39718,7 +40096,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
39718
40096
|
}
|
|
39719
40097
|
let fileStat;
|
|
39720
40098
|
try {
|
|
39721
|
-
fileStat =
|
|
40099
|
+
fileStat = fs14.statSync(filePath);
|
|
39722
40100
|
if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
|
|
39723
40101
|
continue;
|
|
39724
40102
|
}
|
|
@@ -39727,7 +40105,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
39727
40105
|
}
|
|
39728
40106
|
let content;
|
|
39729
40107
|
try {
|
|
39730
|
-
content =
|
|
40108
|
+
content = fs14.readFileSync(filePath, "utf-8");
|
|
39731
40109
|
} catch {
|
|
39732
40110
|
continue;
|
|
39733
40111
|
}
|
|
@@ -39812,7 +40190,7 @@ var evidence_check = tool({
|
|
|
39812
40190
|
return JSON.stringify(errorResult, null, 2);
|
|
39813
40191
|
}
|
|
39814
40192
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
39815
|
-
const planPath =
|
|
40193
|
+
const planPath = path20.join(cwd, PLAN_FILE);
|
|
39816
40194
|
if (!isPathWithinSwarm(planPath, cwd)) {
|
|
39817
40195
|
const errorResult = {
|
|
39818
40196
|
error: "plan file path validation failed",
|
|
@@ -39826,7 +40204,7 @@ var evidence_check = tool({
|
|
|
39826
40204
|
}
|
|
39827
40205
|
let planContent;
|
|
39828
40206
|
try {
|
|
39829
|
-
planContent =
|
|
40207
|
+
planContent = fs14.readFileSync(planPath, "utf-8");
|
|
39830
40208
|
} catch {
|
|
39831
40209
|
const result2 = {
|
|
39832
40210
|
message: "No completed tasks found in plan.",
|
|
@@ -39844,7 +40222,7 @@ var evidence_check = tool({
|
|
|
39844
40222
|
};
|
|
39845
40223
|
return JSON.stringify(result2, null, 2);
|
|
39846
40224
|
}
|
|
39847
|
-
const evidenceDir =
|
|
40225
|
+
const evidenceDir = path20.join(cwd, EVIDENCE_DIR);
|
|
39848
40226
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
39849
40227
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
39850
40228
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -39860,8 +40238,8 @@ var evidence_check = tool({
|
|
|
39860
40238
|
});
|
|
39861
40239
|
// src/tools/file-extractor.ts
|
|
39862
40240
|
init_tool();
|
|
39863
|
-
import * as
|
|
39864
|
-
import * as
|
|
40241
|
+
import * as fs15 from "fs";
|
|
40242
|
+
import * as path21 from "path";
|
|
39865
40243
|
var EXT_MAP = {
|
|
39866
40244
|
python: ".py",
|
|
39867
40245
|
py: ".py",
|
|
@@ -39923,8 +40301,8 @@ var extract_code_blocks = tool({
|
|
|
39923
40301
|
execute: async (args2) => {
|
|
39924
40302
|
const { content, output_dir, prefix } = args2;
|
|
39925
40303
|
const targetDir = output_dir || process.cwd();
|
|
39926
|
-
if (!
|
|
39927
|
-
|
|
40304
|
+
if (!fs15.existsSync(targetDir)) {
|
|
40305
|
+
fs15.mkdirSync(targetDir, { recursive: true });
|
|
39928
40306
|
}
|
|
39929
40307
|
const pattern = /```(\w*)\n([\s\S]*?)```/g;
|
|
39930
40308
|
const matches = [...content.matchAll(pattern)];
|
|
@@ -39939,16 +40317,16 @@ var extract_code_blocks = tool({
|
|
|
39939
40317
|
if (prefix) {
|
|
39940
40318
|
filename = `${prefix}_${filename}`;
|
|
39941
40319
|
}
|
|
39942
|
-
let filepath =
|
|
39943
|
-
const base =
|
|
39944
|
-
const ext =
|
|
40320
|
+
let filepath = path21.join(targetDir, filename);
|
|
40321
|
+
const base = path21.basename(filepath, path21.extname(filepath));
|
|
40322
|
+
const ext = path21.extname(filepath);
|
|
39945
40323
|
let counter = 1;
|
|
39946
|
-
while (
|
|
39947
|
-
filepath =
|
|
40324
|
+
while (fs15.existsSync(filepath)) {
|
|
40325
|
+
filepath = path21.join(targetDir, `${base}_${counter}${ext}`);
|
|
39948
40326
|
counter++;
|
|
39949
40327
|
}
|
|
39950
40328
|
try {
|
|
39951
|
-
|
|
40329
|
+
fs15.writeFileSync(filepath, code.trim(), "utf-8");
|
|
39952
40330
|
savedFiles.push(filepath);
|
|
39953
40331
|
} catch (error93) {
|
|
39954
40332
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -40056,8 +40434,8 @@ var gitingest = tool({
|
|
|
40056
40434
|
});
|
|
40057
40435
|
// src/tools/imports.ts
|
|
40058
40436
|
init_dist();
|
|
40059
|
-
import * as
|
|
40060
|
-
import * as
|
|
40437
|
+
import * as fs16 from "fs";
|
|
40438
|
+
import * as path22 from "path";
|
|
40061
40439
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
40062
40440
|
var MAX_SYMBOL_LENGTH = 256;
|
|
40063
40441
|
var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
|
|
@@ -40111,7 +40489,7 @@ function validateSymbolInput(symbol3) {
|
|
|
40111
40489
|
return null;
|
|
40112
40490
|
}
|
|
40113
40491
|
function isBinaryFile2(filePath, buffer) {
|
|
40114
|
-
const ext =
|
|
40492
|
+
const ext = path22.extname(filePath).toLowerCase();
|
|
40115
40493
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
40116
40494
|
return false;
|
|
40117
40495
|
}
|
|
@@ -40135,15 +40513,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
40135
40513
|
const imports = [];
|
|
40136
40514
|
let _resolvedTarget;
|
|
40137
40515
|
try {
|
|
40138
|
-
_resolvedTarget =
|
|
40516
|
+
_resolvedTarget = path22.resolve(targetFile);
|
|
40139
40517
|
} catch {
|
|
40140
40518
|
_resolvedTarget = targetFile;
|
|
40141
40519
|
}
|
|
40142
|
-
const targetBasename =
|
|
40520
|
+
const targetBasename = path22.basename(targetFile, path22.extname(targetFile));
|
|
40143
40521
|
const targetWithExt = targetFile;
|
|
40144
40522
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
40145
|
-
const normalizedTargetWithExt =
|
|
40146
|
-
const normalizedTargetWithoutExt =
|
|
40523
|
+
const normalizedTargetWithExt = path22.normalize(targetWithExt).replace(/\\/g, "/");
|
|
40524
|
+
const normalizedTargetWithoutExt = path22.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
40147
40525
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
40148
40526
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
40149
40527
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -40166,9 +40544,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
40166
40544
|
}
|
|
40167
40545
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
40168
40546
|
let isMatch = false;
|
|
40169
|
-
const _targetDir =
|
|
40170
|
-
const targetExt =
|
|
40171
|
-
const targetBasenameNoExt =
|
|
40547
|
+
const _targetDir = path22.dirname(targetFile);
|
|
40548
|
+
const targetExt = path22.extname(targetFile);
|
|
40549
|
+
const targetBasenameNoExt = path22.basename(targetFile, targetExt);
|
|
40172
40550
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
40173
40551
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
40174
40552
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -40225,7 +40603,7 @@ var SKIP_DIRECTORIES2 = new Set([
|
|
|
40225
40603
|
function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
40226
40604
|
let entries;
|
|
40227
40605
|
try {
|
|
40228
|
-
entries =
|
|
40606
|
+
entries = fs16.readdirSync(dir);
|
|
40229
40607
|
} catch (e) {
|
|
40230
40608
|
stats.fileErrors.push({
|
|
40231
40609
|
path: dir,
|
|
@@ -40236,13 +40614,13 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
40236
40614
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
40237
40615
|
for (const entry of entries) {
|
|
40238
40616
|
if (SKIP_DIRECTORIES2.has(entry)) {
|
|
40239
|
-
stats.skippedDirs.push(
|
|
40617
|
+
stats.skippedDirs.push(path22.join(dir, entry));
|
|
40240
40618
|
continue;
|
|
40241
40619
|
}
|
|
40242
|
-
const fullPath =
|
|
40620
|
+
const fullPath = path22.join(dir, entry);
|
|
40243
40621
|
let stat;
|
|
40244
40622
|
try {
|
|
40245
|
-
stat =
|
|
40623
|
+
stat = fs16.statSync(fullPath);
|
|
40246
40624
|
} catch (e) {
|
|
40247
40625
|
stats.fileErrors.push({
|
|
40248
40626
|
path: fullPath,
|
|
@@ -40253,7 +40631,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
40253
40631
|
if (stat.isDirectory()) {
|
|
40254
40632
|
findSourceFiles2(fullPath, files, stats);
|
|
40255
40633
|
} else if (stat.isFile()) {
|
|
40256
|
-
const ext =
|
|
40634
|
+
const ext = path22.extname(fullPath).toLowerCase();
|
|
40257
40635
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
40258
40636
|
files.push(fullPath);
|
|
40259
40637
|
}
|
|
@@ -40309,8 +40687,8 @@ var imports = tool({
|
|
|
40309
40687
|
return JSON.stringify(errorResult, null, 2);
|
|
40310
40688
|
}
|
|
40311
40689
|
try {
|
|
40312
|
-
const targetFile =
|
|
40313
|
-
if (!
|
|
40690
|
+
const targetFile = path22.resolve(file3);
|
|
40691
|
+
if (!fs16.existsSync(targetFile)) {
|
|
40314
40692
|
const errorResult = {
|
|
40315
40693
|
error: `target file not found: ${file3}`,
|
|
40316
40694
|
target: file3,
|
|
@@ -40320,7 +40698,7 @@ var imports = tool({
|
|
|
40320
40698
|
};
|
|
40321
40699
|
return JSON.stringify(errorResult, null, 2);
|
|
40322
40700
|
}
|
|
40323
|
-
const targetStat =
|
|
40701
|
+
const targetStat = fs16.statSync(targetFile);
|
|
40324
40702
|
if (!targetStat.isFile()) {
|
|
40325
40703
|
const errorResult = {
|
|
40326
40704
|
error: "target must be a file, not a directory",
|
|
@@ -40331,7 +40709,7 @@ var imports = tool({
|
|
|
40331
40709
|
};
|
|
40332
40710
|
return JSON.stringify(errorResult, null, 2);
|
|
40333
40711
|
}
|
|
40334
|
-
const baseDir =
|
|
40712
|
+
const baseDir = path22.dirname(targetFile);
|
|
40335
40713
|
const scanStats = {
|
|
40336
40714
|
skippedDirs: [],
|
|
40337
40715
|
skippedFiles: 0,
|
|
@@ -40346,12 +40724,12 @@ var imports = tool({
|
|
|
40346
40724
|
if (consumers.length >= MAX_CONSUMERS)
|
|
40347
40725
|
break;
|
|
40348
40726
|
try {
|
|
40349
|
-
const stat =
|
|
40727
|
+
const stat = fs16.statSync(filePath);
|
|
40350
40728
|
if (stat.size > MAX_FILE_SIZE_BYTES4) {
|
|
40351
40729
|
skippedFileCount++;
|
|
40352
40730
|
continue;
|
|
40353
40731
|
}
|
|
40354
|
-
const buffer =
|
|
40732
|
+
const buffer = fs16.readFileSync(filePath);
|
|
40355
40733
|
if (isBinaryFile2(filePath, buffer)) {
|
|
40356
40734
|
skippedFileCount++;
|
|
40357
40735
|
continue;
|
|
@@ -40418,10 +40796,208 @@ var imports = tool({
|
|
|
40418
40796
|
// src/tools/index.ts
|
|
40419
40797
|
init_lint();
|
|
40420
40798
|
|
|
40799
|
+
// src/tools/phase-complete.ts
|
|
40800
|
+
init_tool();
|
|
40801
|
+
import * as fs17 from "fs";
|
|
40802
|
+
init_manager();
|
|
40803
|
+
init_utils2();
|
|
40804
|
+
function getDelegationsSince(sessionID, sinceTimestamp) {
|
|
40805
|
+
const chain = swarmState.delegationChains.get(sessionID);
|
|
40806
|
+
if (!chain) {
|
|
40807
|
+
return [];
|
|
40808
|
+
}
|
|
40809
|
+
if (sinceTimestamp === 0) {
|
|
40810
|
+
return chain;
|
|
40811
|
+
}
|
|
40812
|
+
return chain.filter((entry) => entry.timestamp > sinceTimestamp);
|
|
40813
|
+
}
|
|
40814
|
+
function normalizeAgentsFromDelegations(delegations) {
|
|
40815
|
+
const agents = new Set;
|
|
40816
|
+
for (const delegation of delegations) {
|
|
40817
|
+
const normalizedFrom = stripKnownSwarmPrefix(delegation.from);
|
|
40818
|
+
const normalizedTo = stripKnownSwarmPrefix(delegation.to);
|
|
40819
|
+
agents.add(normalizedFrom);
|
|
40820
|
+
agents.add(normalizedTo);
|
|
40821
|
+
}
|
|
40822
|
+
return agents;
|
|
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
|
+
}
|
|
40827
|
+
async function executePhaseComplete(args2) {
|
|
40828
|
+
const phase = Number(args2.phase);
|
|
40829
|
+
const summary = args2.summary;
|
|
40830
|
+
const sessionID = args2.sessionID;
|
|
40831
|
+
if (Number.isNaN(phase) || phase < 1) {
|
|
40832
|
+
return JSON.stringify({
|
|
40833
|
+
success: false,
|
|
40834
|
+
phase,
|
|
40835
|
+
message: "Invalid phase number",
|
|
40836
|
+
agentsDispatched: [],
|
|
40837
|
+
warnings: ["Phase must be a positive number"]
|
|
40838
|
+
}, null, 2);
|
|
40839
|
+
}
|
|
40840
|
+
if (!sessionID) {
|
|
40841
|
+
return JSON.stringify({
|
|
40842
|
+
success: false,
|
|
40843
|
+
phase,
|
|
40844
|
+
message: "Session ID is required",
|
|
40845
|
+
agentsDispatched: [],
|
|
40846
|
+
warnings: [
|
|
40847
|
+
"sessionID parameter is required for phase completion tracking"
|
|
40848
|
+
]
|
|
40849
|
+
}, null, 2);
|
|
40850
|
+
}
|
|
40851
|
+
const session = ensureAgentSession(sessionID);
|
|
40852
|
+
const lastCompletionTimestamp = session.lastPhaseCompleteTimestamp ?? 0;
|
|
40853
|
+
const recentDelegations = getDelegationsSince(sessionID, lastCompletionTimestamp);
|
|
40854
|
+
const delegationAgents = normalizeAgentsFromDelegations(recentDelegations);
|
|
40855
|
+
const trackedAgents = session.phaseAgentsDispatched ?? new Set;
|
|
40856
|
+
const allAgents = new Set([...delegationAgents, ...trackedAgents]);
|
|
40857
|
+
const agentsDispatched = Array.from(allAgents).sort();
|
|
40858
|
+
const directory = process.cwd();
|
|
40859
|
+
const { config: config3 } = loadPluginConfigWithMeta(directory);
|
|
40860
|
+
let phaseCompleteConfig;
|
|
40861
|
+
try {
|
|
40862
|
+
phaseCompleteConfig = PhaseCompleteConfigSchema.parse(config3.phase_complete ?? {});
|
|
40863
|
+
} catch (parseError) {
|
|
40864
|
+
return JSON.stringify({
|
|
40865
|
+
success: false,
|
|
40866
|
+
phase,
|
|
40867
|
+
status: "incomplete",
|
|
40868
|
+
message: `Invalid phase_complete configuration: ${parseError instanceof Error ? parseError.message : "Unknown error"}`,
|
|
40869
|
+
agentsDispatched,
|
|
40870
|
+
agentsMissing: [],
|
|
40871
|
+
warnings: ["Configuration validation failed"]
|
|
40872
|
+
}, null, 2);
|
|
40873
|
+
}
|
|
40874
|
+
if (phaseCompleteConfig.enabled === false) {
|
|
40875
|
+
return JSON.stringify({
|
|
40876
|
+
success: true,
|
|
40877
|
+
phase,
|
|
40878
|
+
status: "disabled",
|
|
40879
|
+
message: `Phase ${phase} complete (enforcement disabled)`,
|
|
40880
|
+
agentsDispatched,
|
|
40881
|
+
agentsMissing: [],
|
|
40882
|
+
warnings: []
|
|
40883
|
+
}, null, 2);
|
|
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
|
+
}
|
|
40916
|
+
const effectiveRequired = [...phaseCompleteConfig.required_agents];
|
|
40917
|
+
if (phaseCompleteConfig.require_docs && !effectiveRequired.includes("docs")) {
|
|
40918
|
+
effectiveRequired.push("docs");
|
|
40919
|
+
}
|
|
40920
|
+
const agentsMissing = effectiveRequired.filter((req) => !allAgents.has(req));
|
|
40921
|
+
const warnings = [];
|
|
40922
|
+
let success3 = true;
|
|
40923
|
+
let status = "success";
|
|
40924
|
+
const safeSummary = summary?.trim().slice(0, 500);
|
|
40925
|
+
let message = safeSummary ? `Phase ${phase} completed: ${safeSummary}` : `Phase ${phase} completed`;
|
|
40926
|
+
if (agentsMissing.length > 0) {
|
|
40927
|
+
if (phaseCompleteConfig.policy === "enforce") {
|
|
40928
|
+
success3 = false;
|
|
40929
|
+
status = "incomplete";
|
|
40930
|
+
message = `Phase ${phase} incomplete: missing required agents: ${agentsMissing.join(", ")}`;
|
|
40931
|
+
} else {
|
|
40932
|
+
status = "warned";
|
|
40933
|
+
warnings.push(`Warning: phase ${phase} missing required agents: ${agentsMissing.join(", ")}`);
|
|
40934
|
+
}
|
|
40935
|
+
}
|
|
40936
|
+
const now = Date.now();
|
|
40937
|
+
const durationMs = now - lastCompletionTimestamp;
|
|
40938
|
+
const event = {
|
|
40939
|
+
event: "phase_complete",
|
|
40940
|
+
phase,
|
|
40941
|
+
timestamp: new Date(now).toISOString(),
|
|
40942
|
+
agents_dispatched: agentsDispatched,
|
|
40943
|
+
agents_missing: agentsMissing,
|
|
40944
|
+
status,
|
|
40945
|
+
summary: safeSummary ?? null
|
|
40946
|
+
};
|
|
40947
|
+
try {
|
|
40948
|
+
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
40949
|
+
fs17.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
40950
|
+
`, "utf-8");
|
|
40951
|
+
} catch (writeError) {
|
|
40952
|
+
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
40953
|
+
}
|
|
40954
|
+
if (success3) {
|
|
40955
|
+
session.phaseAgentsDispatched = new Set;
|
|
40956
|
+
session.lastPhaseCompleteTimestamp = now;
|
|
40957
|
+
session.lastPhaseCompletePhase = phase;
|
|
40958
|
+
}
|
|
40959
|
+
const result = {
|
|
40960
|
+
success: success3,
|
|
40961
|
+
phase,
|
|
40962
|
+
status,
|
|
40963
|
+
message,
|
|
40964
|
+
agentsDispatched,
|
|
40965
|
+
agentsMissing,
|
|
40966
|
+
warnings
|
|
40967
|
+
};
|
|
40968
|
+
return JSON.stringify({ ...result, timestamp: event.timestamp, duration_ms: durationMs }, null, 2);
|
|
40969
|
+
}
|
|
40970
|
+
var phase_complete = tool({
|
|
40971
|
+
description: "Mark a phase as complete and track which agents were dispatched. " + "Used for phase completion gating and tracking. " + "Accepts phase number and optional summary. Returns list of agents that were dispatched.",
|
|
40972
|
+
args: {
|
|
40973
|
+
phase: tool.schema.number().describe("The phase number being completed (e.g., 1, 2, 3)"),
|
|
40974
|
+
summary: tool.schema.string().optional().describe("Optional summary of what was accomplished in this phase"),
|
|
40975
|
+
sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)")
|
|
40976
|
+
},
|
|
40977
|
+
execute: async (args2) => {
|
|
40978
|
+
let phaseCompleteArgs;
|
|
40979
|
+
try {
|
|
40980
|
+
phaseCompleteArgs = {
|
|
40981
|
+
phase: Number(args2.phase),
|
|
40982
|
+
summary: args2.summary !== undefined ? String(args2.summary) : undefined,
|
|
40983
|
+
sessionID: args2.sessionID !== undefined ? String(args2.sessionID) : undefined
|
|
40984
|
+
};
|
|
40985
|
+
} catch {
|
|
40986
|
+
return JSON.stringify({
|
|
40987
|
+
success: false,
|
|
40988
|
+
phase: 0,
|
|
40989
|
+
message: "Invalid arguments",
|
|
40990
|
+
agentsDispatched: [],
|
|
40991
|
+
warnings: ["Failed to parse arguments"]
|
|
40992
|
+
}, null, 2);
|
|
40993
|
+
}
|
|
40994
|
+
return executePhaseComplete(phaseCompleteArgs);
|
|
40995
|
+
}
|
|
40996
|
+
});
|
|
40421
40997
|
// src/tools/pkg-audit.ts
|
|
40422
40998
|
init_dist();
|
|
40423
40999
|
import * as fs18 from "fs";
|
|
40424
|
-
import * as
|
|
41000
|
+
import * as path23 from "path";
|
|
40425
41001
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
40426
41002
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
40427
41003
|
function isValidEcosystem(value) {
|
|
@@ -40439,13 +41015,13 @@ function validateArgs3(args2) {
|
|
|
40439
41015
|
function detectEcosystems() {
|
|
40440
41016
|
const ecosystems = [];
|
|
40441
41017
|
const cwd = process.cwd();
|
|
40442
|
-
if (fs18.existsSync(
|
|
41018
|
+
if (fs18.existsSync(path23.join(cwd, "package.json"))) {
|
|
40443
41019
|
ecosystems.push("npm");
|
|
40444
41020
|
}
|
|
40445
|
-
if (fs18.existsSync(
|
|
41021
|
+
if (fs18.existsSync(path23.join(cwd, "pyproject.toml")) || fs18.existsSync(path23.join(cwd, "requirements.txt"))) {
|
|
40446
41022
|
ecosystems.push("pip");
|
|
40447
41023
|
}
|
|
40448
|
-
if (fs18.existsSync(
|
|
41024
|
+
if (fs18.existsSync(path23.join(cwd, "Cargo.toml"))) {
|
|
40449
41025
|
ecosystems.push("cargo");
|
|
40450
41026
|
}
|
|
40451
41027
|
return ecosystems;
|
|
@@ -42353,11 +42929,11 @@ var Module2 = (() => {
|
|
|
42353
42929
|
throw toThrow;
|
|
42354
42930
|
}, "quit_");
|
|
42355
42931
|
var scriptDirectory = "";
|
|
42356
|
-
function locateFile(
|
|
42932
|
+
function locateFile(path24) {
|
|
42357
42933
|
if (Module["locateFile"]) {
|
|
42358
|
-
return Module["locateFile"](
|
|
42934
|
+
return Module["locateFile"](path24, scriptDirectory);
|
|
42359
42935
|
}
|
|
42360
|
-
return scriptDirectory +
|
|
42936
|
+
return scriptDirectory + path24;
|
|
42361
42937
|
}
|
|
42362
42938
|
__name(locateFile, "locateFile");
|
|
42363
42939
|
var readAsync, readBinary;
|
|
@@ -44171,7 +44747,7 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
44171
44747
|
]);
|
|
44172
44748
|
// src/tools/pre-check-batch.ts
|
|
44173
44749
|
init_dist();
|
|
44174
|
-
import * as
|
|
44750
|
+
import * as path26 from "path";
|
|
44175
44751
|
|
|
44176
44752
|
// node_modules/yocto-queue/index.js
|
|
44177
44753
|
class Node2 {
|
|
@@ -44338,7 +44914,7 @@ init_manager();
|
|
|
44338
44914
|
|
|
44339
44915
|
// src/quality/metrics.ts
|
|
44340
44916
|
import * as fs19 from "fs";
|
|
44341
|
-
import * as
|
|
44917
|
+
import * as path24 from "path";
|
|
44342
44918
|
var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
|
|
44343
44919
|
var MIN_DUPLICATION_LINES = 10;
|
|
44344
44920
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -44390,7 +44966,7 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
44390
44966
|
let totalComplexity = 0;
|
|
44391
44967
|
const analyzedFiles = [];
|
|
44392
44968
|
for (const file3 of files) {
|
|
44393
|
-
const fullPath =
|
|
44969
|
+
const fullPath = path24.isAbsolute(file3) ? file3 : path24.join(workingDir, file3);
|
|
44394
44970
|
if (!fs19.existsSync(fullPath)) {
|
|
44395
44971
|
continue;
|
|
44396
44972
|
}
|
|
@@ -44513,7 +45089,7 @@ function countGoExports(content) {
|
|
|
44513
45089
|
function getExportCountForFile(filePath) {
|
|
44514
45090
|
try {
|
|
44515
45091
|
const content = fs19.readFileSync(filePath, "utf-8");
|
|
44516
|
-
const ext =
|
|
45092
|
+
const ext = path24.extname(filePath).toLowerCase();
|
|
44517
45093
|
switch (ext) {
|
|
44518
45094
|
case ".ts":
|
|
44519
45095
|
case ".tsx":
|
|
@@ -44539,7 +45115,7 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
44539
45115
|
let totalExports = 0;
|
|
44540
45116
|
const analyzedFiles = [];
|
|
44541
45117
|
for (const file3 of files) {
|
|
44542
|
-
const fullPath =
|
|
45118
|
+
const fullPath = path24.isAbsolute(file3) ? file3 : path24.join(workingDir, file3);
|
|
44543
45119
|
if (!fs19.existsSync(fullPath)) {
|
|
44544
45120
|
continue;
|
|
44545
45121
|
}
|
|
@@ -44573,7 +45149,7 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
44573
45149
|
let duplicateLines = 0;
|
|
44574
45150
|
const analyzedFiles = [];
|
|
44575
45151
|
for (const file3 of files) {
|
|
44576
|
-
const fullPath =
|
|
45152
|
+
const fullPath = path24.isAbsolute(file3) ? file3 : path24.join(workingDir, file3);
|
|
44577
45153
|
if (!fs19.existsSync(fullPath)) {
|
|
44578
45154
|
continue;
|
|
44579
45155
|
}
|
|
@@ -44606,8 +45182,8 @@ function countCodeLines(content) {
|
|
|
44606
45182
|
return lines.length;
|
|
44607
45183
|
}
|
|
44608
45184
|
function isTestFile(filePath) {
|
|
44609
|
-
const basename5 =
|
|
44610
|
-
const _ext =
|
|
45185
|
+
const basename5 = path24.basename(filePath);
|
|
45186
|
+
const _ext = path24.extname(filePath).toLowerCase();
|
|
44611
45187
|
const testPatterns = [
|
|
44612
45188
|
".test.",
|
|
44613
45189
|
".spec.",
|
|
@@ -44649,7 +45225,7 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
44649
45225
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
44650
45226
|
let testLines = 0;
|
|
44651
45227
|
let codeLines = 0;
|
|
44652
|
-
const srcDir =
|
|
45228
|
+
const srcDir = path24.join(workingDir, "src");
|
|
44653
45229
|
if (fs19.existsSync(srcDir)) {
|
|
44654
45230
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
44655
45231
|
codeLines += lines;
|
|
@@ -44657,14 +45233,14 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
44657
45233
|
}
|
|
44658
45234
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
44659
45235
|
for (const dir of possibleSrcDirs) {
|
|
44660
|
-
const dirPath =
|
|
45236
|
+
const dirPath = path24.join(workingDir, dir);
|
|
44661
45237
|
if (fs19.existsSync(dirPath)) {
|
|
44662
45238
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
44663
45239
|
codeLines += lines;
|
|
44664
45240
|
});
|
|
44665
45241
|
}
|
|
44666
45242
|
}
|
|
44667
|
-
const testsDir =
|
|
45243
|
+
const testsDir = path24.join(workingDir, "tests");
|
|
44668
45244
|
if (fs19.existsSync(testsDir)) {
|
|
44669
45245
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
44670
45246
|
testLines += lines;
|
|
@@ -44672,7 +45248,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
44672
45248
|
}
|
|
44673
45249
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
44674
45250
|
for (const dir of possibleTestDirs) {
|
|
44675
|
-
const dirPath =
|
|
45251
|
+
const dirPath = path24.join(workingDir, dir);
|
|
44676
45252
|
if (fs19.existsSync(dirPath) && dirPath !== testsDir) {
|
|
44677
45253
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
44678
45254
|
testLines += lines;
|
|
@@ -44687,7 +45263,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
44687
45263
|
try {
|
|
44688
45264
|
const entries = fs19.readdirSync(dirPath, { withFileTypes: true });
|
|
44689
45265
|
for (const entry of entries) {
|
|
44690
|
-
const fullPath =
|
|
45266
|
+
const fullPath = path24.join(dirPath, entry.name);
|
|
44691
45267
|
if (entry.isDirectory()) {
|
|
44692
45268
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
44693
45269
|
continue;
|
|
@@ -44695,7 +45271,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
44695
45271
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
44696
45272
|
} else if (entry.isFile()) {
|
|
44697
45273
|
const relativePath = fullPath.replace(`${process.cwd()}/`, "");
|
|
44698
|
-
const ext =
|
|
45274
|
+
const ext = path24.extname(entry.name).toLowerCase();
|
|
44699
45275
|
const validExts = [
|
|
44700
45276
|
".ts",
|
|
44701
45277
|
".tsx",
|
|
@@ -44950,7 +45526,7 @@ async function qualityBudget(input, directory) {
|
|
|
44950
45526
|
// src/tools/sast-scan.ts
|
|
44951
45527
|
init_manager();
|
|
44952
45528
|
import * as fs20 from "fs";
|
|
44953
|
-
import * as
|
|
45529
|
+
import * as path25 from "path";
|
|
44954
45530
|
import { extname as extname7 } from "path";
|
|
44955
45531
|
|
|
44956
45532
|
// src/sast/rules/c.ts
|
|
@@ -45905,7 +46481,7 @@ async function sastScan(input, directory, config3) {
|
|
|
45905
46481
|
const engine = semgrepAvailable ? "tier_a+tier_b" : "tier_a";
|
|
45906
46482
|
const filesByLanguage = new Map;
|
|
45907
46483
|
for (const filePath of changed_files) {
|
|
45908
|
-
const resolvedPath =
|
|
46484
|
+
const resolvedPath = path25.isAbsolute(filePath) ? filePath : path25.resolve(directory, filePath);
|
|
45909
46485
|
if (!fs20.existsSync(resolvedPath)) {
|
|
45910
46486
|
_filesSkipped++;
|
|
45911
46487
|
continue;
|
|
@@ -46014,10 +46590,10 @@ function validatePath(inputPath, baseDir) {
|
|
|
46014
46590
|
if (!inputPath || inputPath.length === 0) {
|
|
46015
46591
|
return "path is required";
|
|
46016
46592
|
}
|
|
46017
|
-
const resolved =
|
|
46018
|
-
const baseResolved =
|
|
46019
|
-
const relative3 =
|
|
46020
|
-
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)) {
|
|
46021
46597
|
return "path traversal detected";
|
|
46022
46598
|
}
|
|
46023
46599
|
return null;
|
|
@@ -46139,7 +46715,7 @@ async function runPreCheckBatch(input) {
|
|
|
46139
46715
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
46140
46716
|
continue;
|
|
46141
46717
|
}
|
|
46142
|
-
changedFiles.push(
|
|
46718
|
+
changedFiles.push(path26.resolve(directory, file3));
|
|
46143
46719
|
}
|
|
46144
46720
|
} else {
|
|
46145
46721
|
changedFiles = [];
|
|
@@ -46330,7 +46906,7 @@ var retrieve_summary = tool({
|
|
|
46330
46906
|
init_dist();
|
|
46331
46907
|
init_manager();
|
|
46332
46908
|
import * as fs21 from "fs";
|
|
46333
|
-
import * as
|
|
46909
|
+
import * as path27 from "path";
|
|
46334
46910
|
|
|
46335
46911
|
// src/sbom/detectors/dart.ts
|
|
46336
46912
|
function parsePubspecLock(content) {
|
|
@@ -47177,7 +47753,7 @@ function findManifestFiles(rootDir) {
|
|
|
47177
47753
|
try {
|
|
47178
47754
|
const entries = fs21.readdirSync(dir, { withFileTypes: true });
|
|
47179
47755
|
for (const entry of entries) {
|
|
47180
|
-
const fullPath =
|
|
47756
|
+
const fullPath = path27.join(dir, entry.name);
|
|
47181
47757
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
47182
47758
|
continue;
|
|
47183
47759
|
}
|
|
@@ -47187,7 +47763,7 @@ function findManifestFiles(rootDir) {
|
|
|
47187
47763
|
for (const pattern of patterns) {
|
|
47188
47764
|
const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
47189
47765
|
if (new RegExp(regex, "i").test(entry.name)) {
|
|
47190
|
-
manifestFiles.push(
|
|
47766
|
+
manifestFiles.push(path27.relative(cwd, fullPath));
|
|
47191
47767
|
break;
|
|
47192
47768
|
}
|
|
47193
47769
|
}
|
|
@@ -47206,12 +47782,12 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
47206
47782
|
try {
|
|
47207
47783
|
const entries = fs21.readdirSync(dir, { withFileTypes: true });
|
|
47208
47784
|
for (const entry of entries) {
|
|
47209
|
-
const fullPath =
|
|
47785
|
+
const fullPath = path27.join(dir, entry.name);
|
|
47210
47786
|
if (entry.isFile()) {
|
|
47211
47787
|
for (const pattern of patterns) {
|
|
47212
47788
|
const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
47213
47789
|
if (new RegExp(regex, "i").test(entry.name)) {
|
|
47214
|
-
found.push(
|
|
47790
|
+
found.push(path27.relative(workingDir, fullPath));
|
|
47215
47791
|
break;
|
|
47216
47792
|
}
|
|
47217
47793
|
}
|
|
@@ -47224,11 +47800,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
47224
47800
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
47225
47801
|
const dirs = new Set;
|
|
47226
47802
|
for (const file3 of changedFiles) {
|
|
47227
|
-
let currentDir =
|
|
47803
|
+
let currentDir = path27.dirname(file3);
|
|
47228
47804
|
while (true) {
|
|
47229
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
47230
|
-
dirs.add(
|
|
47231
|
-
const parent =
|
|
47805
|
+
if (currentDir && currentDir !== "." && currentDir !== path27.sep) {
|
|
47806
|
+
dirs.add(path27.join(workingDir, currentDir));
|
|
47807
|
+
const parent = path27.dirname(currentDir);
|
|
47232
47808
|
if (parent === currentDir)
|
|
47233
47809
|
break;
|
|
47234
47810
|
currentDir = parent;
|
|
@@ -47335,7 +47911,7 @@ var sbom_generate = tool({
|
|
|
47335
47911
|
const processedFiles = [];
|
|
47336
47912
|
for (const manifestFile of manifestFiles) {
|
|
47337
47913
|
try {
|
|
47338
|
-
const fullPath =
|
|
47914
|
+
const fullPath = path27.isAbsolute(manifestFile) ? manifestFile : path27.join(workingDir, manifestFile);
|
|
47339
47915
|
if (!fs21.existsSync(fullPath)) {
|
|
47340
47916
|
continue;
|
|
47341
47917
|
}
|
|
@@ -47352,7 +47928,7 @@ var sbom_generate = tool({
|
|
|
47352
47928
|
const bom = generateCycloneDX(allComponents);
|
|
47353
47929
|
const bomJson = serializeCycloneDX(bom);
|
|
47354
47930
|
const filename = generateSbomFilename();
|
|
47355
|
-
const outputPath =
|
|
47931
|
+
const outputPath = path27.join(outputDir, filename);
|
|
47356
47932
|
fs21.writeFileSync(outputPath, bomJson, "utf-8");
|
|
47357
47933
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
47358
47934
|
try {
|
|
@@ -47395,7 +47971,7 @@ var sbom_generate = tool({
|
|
|
47395
47971
|
// src/tools/schema-drift.ts
|
|
47396
47972
|
init_dist();
|
|
47397
47973
|
import * as fs22 from "fs";
|
|
47398
|
-
import * as
|
|
47974
|
+
import * as path28 from "path";
|
|
47399
47975
|
var SPEC_CANDIDATES = [
|
|
47400
47976
|
"openapi.json",
|
|
47401
47977
|
"openapi.yaml",
|
|
@@ -47427,12 +48003,12 @@ function normalizePath(p) {
|
|
|
47427
48003
|
}
|
|
47428
48004
|
function discoverSpecFile(cwd, specFileArg) {
|
|
47429
48005
|
if (specFileArg) {
|
|
47430
|
-
const resolvedPath =
|
|
47431
|
-
const normalizedCwd = cwd.endsWith(
|
|
48006
|
+
const resolvedPath = path28.resolve(cwd, specFileArg);
|
|
48007
|
+
const normalizedCwd = cwd.endsWith(path28.sep) ? cwd : cwd + path28.sep;
|
|
47432
48008
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
47433
48009
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
47434
48010
|
}
|
|
47435
|
-
const ext =
|
|
48011
|
+
const ext = path28.extname(resolvedPath).toLowerCase();
|
|
47436
48012
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
47437
48013
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
47438
48014
|
}
|
|
@@ -47446,7 +48022,7 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
47446
48022
|
return resolvedPath;
|
|
47447
48023
|
}
|
|
47448
48024
|
for (const candidate of SPEC_CANDIDATES) {
|
|
47449
|
-
const candidatePath =
|
|
48025
|
+
const candidatePath = path28.resolve(cwd, candidate);
|
|
47450
48026
|
if (fs22.existsSync(candidatePath)) {
|
|
47451
48027
|
const stats = fs22.statSync(candidatePath);
|
|
47452
48028
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
@@ -47458,7 +48034,7 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
47458
48034
|
}
|
|
47459
48035
|
function parseSpec(specFile) {
|
|
47460
48036
|
const content = fs22.readFileSync(specFile, "utf-8");
|
|
47461
|
-
const ext =
|
|
48037
|
+
const ext = path28.extname(specFile).toLowerCase();
|
|
47462
48038
|
if (ext === ".json") {
|
|
47463
48039
|
return parseJsonSpec(content);
|
|
47464
48040
|
}
|
|
@@ -47529,7 +48105,7 @@ function extractRoutes(cwd) {
|
|
|
47529
48105
|
return;
|
|
47530
48106
|
}
|
|
47531
48107
|
for (const entry of entries) {
|
|
47532
|
-
const fullPath =
|
|
48108
|
+
const fullPath = path28.join(dir, entry.name);
|
|
47533
48109
|
if (entry.isSymbolicLink()) {
|
|
47534
48110
|
continue;
|
|
47535
48111
|
}
|
|
@@ -47539,7 +48115,7 @@ function extractRoutes(cwd) {
|
|
|
47539
48115
|
}
|
|
47540
48116
|
walkDir(fullPath);
|
|
47541
48117
|
} else if (entry.isFile()) {
|
|
47542
|
-
const ext =
|
|
48118
|
+
const ext = path28.extname(entry.name).toLowerCase();
|
|
47543
48119
|
const baseName = entry.name.toLowerCase();
|
|
47544
48120
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
47545
48121
|
continue;
|
|
@@ -47708,7 +48284,7 @@ init_secretscan();
|
|
|
47708
48284
|
// src/tools/symbols.ts
|
|
47709
48285
|
init_tool();
|
|
47710
48286
|
import * as fs23 from "fs";
|
|
47711
|
-
import * as
|
|
48287
|
+
import * as path29 from "path";
|
|
47712
48288
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
47713
48289
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
47714
48290
|
function containsControlCharacters(str) {
|
|
@@ -47737,11 +48313,11 @@ function containsWindowsAttacks(str) {
|
|
|
47737
48313
|
}
|
|
47738
48314
|
function isPathInWorkspace(filePath, workspace) {
|
|
47739
48315
|
try {
|
|
47740
|
-
const resolvedPath =
|
|
48316
|
+
const resolvedPath = path29.resolve(workspace, filePath);
|
|
47741
48317
|
const realWorkspace = fs23.realpathSync(workspace);
|
|
47742
48318
|
const realResolvedPath = fs23.realpathSync(resolvedPath);
|
|
47743
|
-
const relativePath =
|
|
47744
|
-
if (relativePath.startsWith("..") ||
|
|
48319
|
+
const relativePath = path29.relative(realWorkspace, realResolvedPath);
|
|
48320
|
+
if (relativePath.startsWith("..") || path29.isAbsolute(relativePath)) {
|
|
47745
48321
|
return false;
|
|
47746
48322
|
}
|
|
47747
48323
|
return true;
|
|
@@ -47753,7 +48329,7 @@ function validatePathForRead(filePath, workspace) {
|
|
|
47753
48329
|
return isPathInWorkspace(filePath, workspace);
|
|
47754
48330
|
}
|
|
47755
48331
|
function extractTSSymbols(filePath, cwd) {
|
|
47756
|
-
const fullPath =
|
|
48332
|
+
const fullPath = path29.join(cwd, filePath);
|
|
47757
48333
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
47758
48334
|
return [];
|
|
47759
48335
|
}
|
|
@@ -47905,7 +48481,7 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
47905
48481
|
});
|
|
47906
48482
|
}
|
|
47907
48483
|
function extractPythonSymbols(filePath, cwd) {
|
|
47908
|
-
const fullPath =
|
|
48484
|
+
const fullPath = path29.join(cwd, filePath);
|
|
47909
48485
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
47910
48486
|
return [];
|
|
47911
48487
|
}
|
|
@@ -47987,7 +48563,7 @@ var symbols = tool({
|
|
|
47987
48563
|
}, null, 2);
|
|
47988
48564
|
}
|
|
47989
48565
|
const cwd = process.cwd();
|
|
47990
|
-
const ext =
|
|
48566
|
+
const ext = path29.extname(file3);
|
|
47991
48567
|
if (containsControlCharacters(file3)) {
|
|
47992
48568
|
return JSON.stringify({
|
|
47993
48569
|
file: file3,
|
|
@@ -48056,7 +48632,7 @@ init_test_runner();
|
|
|
48056
48632
|
// src/tools/todo-extract.ts
|
|
48057
48633
|
init_dist();
|
|
48058
48634
|
import * as fs24 from "fs";
|
|
48059
|
-
import * as
|
|
48635
|
+
import * as path30 from "path";
|
|
48060
48636
|
var MAX_TEXT_LENGTH = 200;
|
|
48061
48637
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
48062
48638
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
@@ -48127,9 +48703,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
48127
48703
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
48128
48704
|
}
|
|
48129
48705
|
try {
|
|
48130
|
-
const resolvedPath =
|
|
48131
|
-
const normalizedCwd =
|
|
48132
|
-
const normalizedResolved =
|
|
48706
|
+
const resolvedPath = path30.resolve(paths);
|
|
48707
|
+
const normalizedCwd = path30.resolve(cwd);
|
|
48708
|
+
const normalizedResolved = path30.resolve(resolvedPath);
|
|
48133
48709
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
48134
48710
|
return {
|
|
48135
48711
|
error: "paths must be within the current working directory",
|
|
@@ -48145,7 +48721,7 @@ function validatePathsInput(paths, cwd) {
|
|
|
48145
48721
|
}
|
|
48146
48722
|
}
|
|
48147
48723
|
function isSupportedExtension(filePath) {
|
|
48148
|
-
const ext =
|
|
48724
|
+
const ext = path30.extname(filePath).toLowerCase();
|
|
48149
48725
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
48150
48726
|
}
|
|
48151
48727
|
function findSourceFiles3(dir, files = []) {
|
|
@@ -48160,7 +48736,7 @@ function findSourceFiles3(dir, files = []) {
|
|
|
48160
48736
|
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
48161
48737
|
continue;
|
|
48162
48738
|
}
|
|
48163
|
-
const fullPath =
|
|
48739
|
+
const fullPath = path30.join(dir, entry);
|
|
48164
48740
|
let stat;
|
|
48165
48741
|
try {
|
|
48166
48742
|
stat = fs24.statSync(fullPath);
|
|
@@ -48272,7 +48848,7 @@ var todo_extract = tool({
|
|
|
48272
48848
|
filesToScan.push(scanPath);
|
|
48273
48849
|
} else {
|
|
48274
48850
|
const errorResult = {
|
|
48275
|
-
error: `unsupported file extension: ${
|
|
48851
|
+
error: `unsupported file extension: ${path30.extname(scanPath)}`,
|
|
48276
48852
|
total: 0,
|
|
48277
48853
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
48278
48854
|
entries: []
|
|
@@ -48387,7 +48963,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
48387
48963
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
48388
48964
|
preflightTriggerManager = new PTM(automationConfig);
|
|
48389
48965
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
48390
|
-
const swarmDir =
|
|
48966
|
+
const swarmDir = path31.resolve(ctx.directory, ".swarm");
|
|
48391
48967
|
statusArtifact = new ASA(swarmDir);
|
|
48392
48968
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
48393
48969
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -48490,6 +49066,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
48490
49066
|
lint,
|
|
48491
49067
|
diff,
|
|
48492
49068
|
pkg_audit,
|
|
49069
|
+
phase_complete,
|
|
48493
49070
|
pre_check_batch,
|
|
48494
49071
|
retrieve_summary,
|
|
48495
49072
|
schema_drift,
|
|
@@ -48507,7 +49084,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
48507
49084
|
opencodeConfig.command = {
|
|
48508
49085
|
...opencodeConfig.command || {},
|
|
48509
49086
|
swarm: {
|
|
48510
|
-
template:
|
|
49087
|
+
template: "/swarm $ARGUMENTS",
|
|
48511
49088
|
description: "Swarm management commands"
|
|
48512
49089
|
}
|
|
48513
49090
|
};
|