opencode-swarm 7.118.0 → 7.118.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{createRequire}from"node:module";var __create=Object.create;var{getPrototypeOf:__getProtoOf,defineProperty:__defProp,getOwnPropertyNames:__getOwnPropNames,getOwnPropertyDescriptor:__getOwnPropDesc}=Object,__hasOwnProp=Object.prototype.hasOwnProperty;function __accessProp(key){return this[key]}var __toESMCache_node,__toESMCache_esm,__toESM=(mod,isNodeMode,target)=>{var canCache=mod!=null&&typeof mod==="object";if(canCache){var cache=isNodeMode?__toESMCache_node??=new WeakMap:__toESMCache_esm??=new WeakMap,cached=cache.get(mod);if(cached)return cached}target=mod!=null?__create(__getProtoOf(mod)):{};let to=isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target;for(let key of __getOwnPropNames(mod))if(!__hasOwnProp.call(to,key))__defProp(to,key,{get:__accessProp.bind(mod,key),enumerable:!0});if(canCache)cache.set(mod,to);return to},__toCommonJS=(from)=>{var entry=(__moduleCache??=new WeakMap).get(from),desc;if(entry)return entry;if(entry=__defProp({},"__esModule",{value:!0}),from&&typeof from==="object"||typeof from==="function"){for(var key of __getOwnPropNames(from))if(!__hasOwnProp.call(entry,key))__defProp(entry,key,{get:__accessProp.bind(from,key),enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return __moduleCache.set(from,entry),entry},__moduleCache,__commonJS=(cb,mod)=>()=>(mod||cb((mod={exports:{}}).exports,mod),mod.exports);var __returnValue=(v)=>v;function __exportSetter(name,newValue){this[name]=__returnValue.bind(null,newValue)}var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0,configurable:!0,set:__exportSetter.bind(all,name)})};var __esm=(fn2,res)=>()=>(fn2&&(res=fn2(fn2=0)),res);var __require=createRequire(import.meta.url);var package_default;var init_package=__esm(()=>{package_default={name:"opencode-swarm",version:"7.118.0",description:"Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",main:"dist/index.js",types:"dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",default:"./dist/index.js"},"./package.json":"./package.json"},bin:{"opencode-swarm":"./dist/cli/index.js"},type:"module",engines:{bun:">=1.3.13"},license:"MIT",repository:{type:"git",url:"https://github.com/ZaxbyHub/opencode-swarm.git"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"},keywords:["opencode","opencode-plugin","ai","agents","orchestration","swarm","multi-agent","llm"],files:["dist","dist/lang/grammars","binaries","evaluation-fixtures",".opencode/skills/brainstorm",".opencode/skills/specify",".opencode/skills/clarify-spec",".opencode/skills/resume",".opencode/skills/clarify",".opencode/skills/discover",".opencode/skills/consult",".opencode/skills/pre-phase-briefing",".opencode/skills/council",".opencode/skills/deep-dive",".opencode/skills/deep-research",".opencode/skills/codebase-review-swarm",".opencode/skills/swarm-implement",".opencode/skills/design-docs",".opencode/skills/swarm-pr-review",".opencode/skills/swarm",".opencode/skills/swarm-pr-feedback",".opencode/skills/swarm-pr-subscribe",".opencode/skills/swarm-ci-monitor",".opencode/skills/issue-ingest",".opencode/skills/plan",".opencode/skills/critic-gate",".opencode/skills/execute",".opencode/skills/phase-wrap",".opencode/skills/loop",".opencode/skills/writing-tests",".opencode/skills/running-tests",".opencode/skills/engineering-conventions",".opencode/skills/commit-pr",".opencode/skills/ci-failure-batching",".opencode/skills/gate-attribution",".opencode/skills/merge-queue-readiness",".opencode/skills/skill-edit-validation",".opencode/skills/worktree-retry-cleanup",".opencode/skills/test-file-split",".opencode/skills/fork-pr-operations",".opencode/skills/parallel-work-check",".opencode/skills/ci-fix-monitor","tests/fixtures/memory-recall","README.md","LICENSE"],scripts:{clean:`bun -e "require('fs').rmSync('dist',{recursive:true,force:true})"`,build:"bun run clean && bun run scripts/copy-grammars.ts && bun build src/index.ts --outdir dist --target node --format esm --external web-tree-sitter --minify-whitespace --minify-syntax && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external bash-parser --splitting && bun run scripts/copy-grammars.ts --to-dist && tsc --emitDeclarationOnly",typecheck:"tsc --noEmit",test:"bun test",lint:"biome lint .","lint:ci":"biome ci .","test:unit:ci":"bun scripts/ci/run-unit-tests-local.ts","drift:check":"bun run scripts/drift-check.ts","drift:fix":"bun run scripts/drift-check.ts --fix --confirm",format:"biome format . --write",check:"biome check --write .",dev:"bun run build && opencode","package:smoke":"node scripts/package-smoke.mjs",prepare:"bun run build","repro:704":"node scripts/repro-704.mjs","repro:1144":"bun scripts/repro-1144.mjs"},dependencies:{"@opencode-ai/plugin":"^1.1.53","@opencode-ai/sdk":"^1.1.53","@vscode/tree-sitter-wasm":"^0.3.0","bash-parser":"^0.5.0","p-limit":"^7.3.0",picomatch:"^4.0.4","proper-lockfile":"^4.1.2","quick-lru":"^7.3.0","web-tree-sitter":"^0.25.0",zod:"^4.1.8"},devDependencies:{"@biomejs/biome":"2.3.14","@types/picomatch":"^4.0.3","bun-types":"1.3.8","js-yaml":"^4.1.1",typescript:"^5.7.3"}}});var QA_AGENTS,PIPELINE_AGENTS,ORCHESTRATOR_NAME="architect",ALL_SUBAGENT_NAMES,ALL_AGENT_NAMES;var init_agent_names=__esm(()=>{QA_AGENTS=["reviewer","critic","critic_oversight"],PIPELINE_AGENTS=["explorer","coder","test_engineer"],ALL_SUBAGENT_NAMES=["sme","researcher","docs","docs_design","designer","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic_architecture_supervisor","curator_init","curator_phase","curator_postmortem","curator_consolidation","council_generalist","council_skeptic","council_domain_expert","skill_improver","spec_writer",...QA_AGENTS,...PIPELINE_AGENTS],ALL_AGENT_NAMES=["architect",...ALL_SUBAGENT_NAMES]});var TOOL_METADATA,TOOL_NAMES,TOOL_NAME_SET,TOOL_DESCRIPTIONS,AGENT_TOOL_MAP;var init_tool_metadata=__esm(()=>{init_agent_names();TOOL_METADATA={diff:{description:"structured git diff with contract change detection",agents:["architect","reviewer","critic_oversight","coder","test_engineer"]},diff_summary:{description:"filter classified AST changes by category, risk level, or file for reviewer drill-down",agents:["architect","reviewer","critic_oversight"]},syntax_check:{description:"check syntax of source files using tree-sitter parsers across multiple languages, returning per-file errors",agents:["architect","coder","test_engineer"]},placeholder_scan:{description:"todo and FIXME comment detection",agents:["architect","reviewer"]},imports:{description:"find all consumers that import from a given file — use before refactoring shared modules to avoid breaking unseen dependents",agents:["architect","sme","researcher","docs","docs_design","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","reviewer","critic","coder","test_engineer"]},lint:{description:"run project linter in check or fix mode; supports biome, eslint, ruff, clippy, and more, returns structured results",agents:["architect","reviewer","coder"]},secretscan:{description:"scan for secrets (API keys, tokens, passwords) via regex and entropy; returns redacted previews, excludes common dirs",agents:["architect","reviewer","critic_oversight"]},sast_scan:{description:"static analysis security scan",agents:["architect","reviewer","critic_oversight"]},build_check:{description:"discover and run build, typecheck, and test commands for various project ecosystems in the working directory",agents:["architect","coder","test_engineer"]},pre_check_batch:{description:"parallel verification: lint:check + secretscan + sast_scan + quality_budget",agents:["architect","reviewer"]},quality_budget:{description:"code quality budget check",agents:["architect"]},symbols:{description:"extract exported symbols (functions, classes, interfaces, types) from source files; supports TypeScript, JavaScript, and Python",agents:["architect","sme","researcher","docs","docs_design","designer","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","spec_writer","reviewer","critic","coder","test_engineer"]},complexity_hotspots:{description:"git churn × complexity risk map",agents:["architect","sme","researcher","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","reviewer","critic","critic_oversight","explorer","test_engineer"]},schema_drift:{description:"OpenAPI spec vs route drift",agents:["architect","sme","researcher","docs","explorer"]},todo_extract:{description:"structured TODO/FIXME extraction",agents:["architect","researcher","docs","explorer"]},evidence_check:{description:"verify task evidence completeness",agents:["architect","critic_oversight"]},check_gate_status:{description:"check the gate status of a specific task",agents:["architect","critic_oversight"]},completion_verify:{description:"verify completed tasks have required evidence",agents:["architect","critic_oversight"]},submit_council_verdicts:{description:"submit pre-collected council member verdicts for synthesis (architect MUST dispatch critic/reviewer/sme/test_engineer/explorer as Agent tasks first; this tool synthesizes only, it does not contact members)",agents:[]},submit_phase_council_verdicts:{description:"submit pre-collected phase-level council member verdicts for holistic phase synthesis (architect MUST dispatch all 5 council members with phase-scoped context first; this tool synthesizes only, it does not contact members)",agents:[]},declare_council_criteria:{description:"pre-declare acceptance criteria for a task before the coder starts work; criteria are read back during council evaluation",agents:[]},sbom_generate:{description:"SBOM generation for dependency inventory",agents:["architect"]},checkpoint:{description:"create named git checkpoints for save, restore, and delete — use before risky operations to enable rollback",agents:["architect"]},pkg_audit:{description:"dependency vulnerability scan — npm/pip/cargo",agents:["architect","critic_hallucination_verifier","reviewer","critic_oversight","test_engineer"]},parse_lane_candidates:{description:"Parse [CANDIDATE] rows from a dispatch_lanes or collect_lane_results artifact (by output_ref), produce structured records with provenance, optionally persist to a per-batch sidecar JSONL. Pure-parser variant exists as internal module.",agents:["architect"]},write_pr_review_trigger_eval:{description:"persist the complete PR-review trigger evaluation with exact-set validation and dispatch provenance",agents:["architect"]},test_runner:{description:"auto-detect and run tests",agents:["architect","reviewer","test_engineer"]},test_impact:{description:"identify test files impacted by changed source files via import analysis",agents:["architect","reviewer","critic_oversight","test_engineer"]},mutation_test:{description:"executes pre-generated mutation patches against tests, evaluates kill rate against quality gate thresholds",agents:["architect","test_engineer"]},generate_mutants:{description:"generate LLM-based mutation testing patches for source files; returns MutationPatch[] for direct consumption by the mutation_test tool",agents:["architect"]},detect_domains:{description:"detect which SME domains are relevant for a given text",agents:["architect","sme","docs","docs_design","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic","critic_oversight","explorer"]},git_blame:{description:"per-line git blame metadata: sha, author, date, summary for each line in a file",agents:["reviewer","explorer","architect"]},gitingest:{description:"fetch a GitHub repository full content via gitingest.com",agents:["architect","docs","explorer"]},retrieve_summary:{description:"retrieve the full content of a stored tool output summary",agents:["architect","sme","docs","docs_design","designer","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic_architecture_supervisor","spec_writer","reviewer","critic","coder","test_engineer"]},retrieve_lane_output:{description:"retrieve paged full dispatch lane output by output_ref; use before consuming truncated lane previews or routing candidates from lane results",agents:["architect"]},extract_code_blocks:{description:"extract code blocks from text content and save them to files",agents:["docs","docs_design","designer","spec_writer","coder","test_engineer"]},phase_complete:{description:"mark a phase as complete and track dispatched agents",agents:["architect"]},save_plan:{description:"save a structured implementation plan",agents:["architect"]},update_task_status:{description:"mark tasks complete, track phase progress",agents:["architect"]},lint_spec:{description:"validate .swarm/spec.md format and required fields",agents:["architect","spec_writer"]},write_retro:{description:"document phase retrospectives via phase_complete workflow, capture lessons learned",agents:["architect"]},write_drift_evidence:{description:"write drift verification evidence for a completed phase",agents:["architect"]},write_hallucination_evidence:{description:"write hallucination verification evidence for a completed phase",agents:["architect"]},write_mutation_evidence:{description:"write mutation gate evidence for a completed phase; normalizes PASS/WARN/FAIL/SKIP verdicts and writes .swarm/evidence/{phase}/mutation-gate.json",agents:["architect"]},declare_scope:{description:"declare file scope for next coder delegation",agents:["architect"]},knowledge_query:{description:"query swarm or hive knowledge with optional filters",agents:["architect","skill_improver","spec_writer"]},doc_scan:{description:"scan project documentation files and build an index manifest",agents:["architect","docs_design","skill_improver","spec_writer","explorer"]},doc_extract:{description:"extract actionable constraints from project documentation",agents:["architect","docs_design","skill_improver","spec_writer"]},curator_analyze:{description:"run curator phase analysis and optionally apply knowledge recommendations",agents:["architect"]},knowledge_add:{description:"store a new lesson in the knowledge base",agents:["architect","coder"]},knowledge_recall:{description:"search the knowledge base for relevant past decisions",agents:["architect","sme","docs","docs_design","designer","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic_architecture_supervisor","curator_init","curator_phase","skill_improver","spec_writer","reviewer","critic","critic_oversight","explorer","coder","test_engineer"]},knowledge_remove:{description:"delete an outdated swarm knowledge entry by ID (swarm tier only)",agents:["architect"]},co_change_analyzer:{description:"detect hidden couplings by analyzing git history",agents:["architect"]},context_status:{description:"report current context-window headroom for the active session — returns tokens-used, model-limit, usage-percent, threshold-state (none/warn/critical), model name, and provider. Pure read-only: no state mutation, no warning injection. Works whether context_budget.enabled is true or false.",agents:["architect"]},search:{description:"Workspace-scoped ripgrep-style text search with structured JSON output. Supports literal and regex modes, glob filtering, and result limits. NOTE: This is text search, not structural AST search — use symbols and imports tools for structural queries.",agents:["architect","sme","docs","docs_design","designer","critic_hallucination_verifier","skill_improver","spec_writer","reviewer","critic_oversight","explorer","coder","test_engineer","researcher"]},ast_grep:{description:"Read-only structural AST search using ast-grep patterns with optional language and glob filters. Use for syntax-aware code pattern searches; does not rewrite files.",agents:["architect","sme","docs","docs_design","critic_hallucination_verifier","spec_writer","explorer","coder","test_engineer","researcher"]},actionlint_scan:{description:"Run actionlint against GitHub Actions workflow YAML files with structured findings. Resolves actionlint lazily and does not modify files.",agents:["architect","test_engineer"]},osv_scan:{description:"Run OSV-Scanner against a workspace path and return structured dependency vulnerability findings. Resolves osv-scanner lazily and does not modify files.",agents:["architect","test_engineer"]},gh_evidence:{description:"Fetch bounded GitHub pull request or issue metadata through gh for review and CI evidence. Resolves gh lazily and is read-only.",agents:["architect","researcher"]},batch_symbols:{description:"Batched symbol extraction across multiple files. Returns per-file symbol summaries with isolated error handling.",agents:["architect","critic_hallucination_verifier","reviewer","critic_oversight","explorer"]},suggest_patch:{description:"Reviewer-safe structured patch suggestion tool. Produces context-anchored patch artifacts without file modification. Returns structured diagnostics on context mismatch.",agents:["architect","reviewer"]},req_coverage:{description:"query requirement coverage status for tracked functional requirements",agents:["critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","spec_writer","critic","critic_oversight"]},get_approved_plan:{description:"retrieve the last critic-approved immutable plan snapshot for baseline drift comparison",agents:["critic_drift_verifier","critic","critic_oversight"]},repo_map:{description:"query the repo code graph: importers, dependencies, blast radius, localization, ontology facts, package boundaries, and heuristic preflight packets before refactoring; ontology findings are advisory, not formal proofs",agents:["architect","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic_architecture_supervisor","reviewer","critic","critic_oversight","explorer","coder"]},get_qa_gate_profile:{description:"retrieve the QA gate profile for the current plan: gates (reviewer, test_engineer, sme_enabled, critic_pre_plan, sast_enabled, council_mode, hallucination_guard, mutation_test, phase_council, drift_check, final_council), lock state, and profile hash. Read-only.",agents:["architect"]},set_qa_gates:{description:"configure the QA gate profile for the current plan. Architect-only. Ratchet-tighter only — rejected once the profile is locked after critic approval. Supports: reviewer, test_engineer, sme_enabled, critic_pre_plan, sast_enabled, council_mode, hallucination_guard, mutation_test, phase_council, drift_check, final_council.",agents:["architect"]},web_search:{description:"External web search (Tavily or Brave) for architect-driven council research, SME domain research, researcher auto-research, and skill-improver research. Returns titled results with snippets, URLs, normalized query metadata, temporal intent, freshness, and removed stale years. Config-gated on council.general.enabled in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides. Requires a search API key. Used by the architect in MODE: COUNCIL to gather a RESEARCH CONTEXT before dispatching council agents, by SME for opt-in external skill/source evaluation, and by the researcher agent for multi-source auto-research.",agents:["sme","researcher","skill_improver"]},web_fetch:{description:"Fetch the readable text of a single http(s) URL (architect-only). Returns decoded page text, document title, final URL after redirects, and an evidence reference. Reads primary sources that web_search only surfaces as snippets. Config-gated on council.general.enabled. Blocks private/loopback/link-local/metadata addresses (re-validated and re-pinned across redirects); enforces timeout and body size cap.",agents:[]},convene_general_council:{description:"Synthesize responses from a multi-model General Council. Accepts parallel member responses (Round 1, optionally Round 2), detects disagreements, and returns consensus points, persisting disagreements, and a structured synthesis. Architect-only. Config-gated on council.general.enabled in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides.",agents:[]},write_final_council_evidence:{description:"Persist project-scoped final council evidence to .swarm/evidence/final-council.json. PREREQUISITE: dispatch critic, reviewer, sme, test_engineer, and explorer as project-scoped Agent tasks and collect their CouncilMemberVerdict JSON — this tool synthesizes only. Rejects on insufficient quorum or CONCERNS with unresolved requiredFixes; normalizes verdicts to approved/concerns/rejected. Architect-only.",agents:[]},skill_generate:{description:"compile knowledge entries into a structured SKILL.md draft",agents:["skill_improver"]},skill_list:{description:"list generated skill files and their status",agents:["skill_improver"]},skill_apply:{description:"activate a draft skill proposal",agents:[]},skill_inspect:{description:"inspect the content and source entries of a skill file",agents:["skill_improver"]},run_stale_reconciliation:{description:"reconcile skills against the knowledge store: mark skills stale when source knowledge is archived or deleted, or clear stale markers",agents:["architect"]},skill_regenerate:{description:"regenerate an active skill by re-clustering its source knowledge entries and updating the SKILL.md in place",agents:[]},skill_retire:{description:"retire a generated skill by adding a retired.marker file; retired skills are excluded from scoring and injection",agents:[]},skill_improve:{description:"run the skill_improver agent to review and refine skills",agents:["skill_improver"]},spec_write:{description:"author or update .swarm/spec.md for the current project",agents:["spec_writer"]},knowledge_receipt:{description:"file a receipt for retrieved knowledge (applied/ignored/contradicted + new lessons), recorded as immutable knowledge events",agents:["architect","sme","docs","docs_design","designer","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic_architecture_supervisor","curator_init","curator_phase","skill_improver","spec_writer","reviewer","critic","coder","test_engineer"]},knowledge_archive:{description:"archive (default), quarantine, or purge a swarm or hive knowledge entry by ID with an immutable audit tombstone; purge requires an admin flag",agents:["architect"]},swarm_memory_recall:{description:"recall scoped Swarm memory for the current repository as untrusted background",agents:[]},swarm_memory_propose:{description:"create a pending Swarm memory proposal; does not write durable memory directly",agents:[]},swarm_command:{description:"run supported /swarm commands through the canonical command registry",agents:["architect","sme","researcher","docs","docs_design","designer","reviewer","critic","explorer","coder","test_engineer"]},dispatch_lanes:{description:"dispatch read-only exploration/review lanes concurrently and BLOCK until all finish; prefer dispatch_lanes_async for non-blocking dispatch, use this only when promptAsync is unavailable",agents:["architect"]},dispatch_lanes_async:{description:"launch read-only advisory lanes non-blockingly and return a batch id plus lane session handles immediately so you can keep working; launch_timeout_ms is only a promptAsync acceptance budget, not a lane runtime timeout; poll incrementally with collect_lane_results (wait omitted or false) while doing independent investigation, or join with wait: true when you need all results",agents:["architect"]},collect_lane_results:{description:"collect or poll results for a dispatch_lanes_async batch; supports both non-blocking polling (wait omitted or false) and blocking join (wait: true). Non-blocking polls include pending lane identities by default and process settled lanes incrementally while continuing independent work; busy/retry lanes are not timed out just because they run for a long time. Does not advance workflow gates.",agents:["architect"]},summarize_work:{description:"emit a short structured summary of completed work (key decisions, assumptions, risks, constraints) at task completion; rolls up per phase for architecture-supervisor review. Advisory, never blocks.",agents:["architect","sme","researcher","docs","docs_design","designer","explorer","coder","test_engineer"]},write_architecture_supervisor_evidence:{description:"persist the architecture supervisor verdict for a phase (architect MUST dispatch critic_architecture_supervisor first and collect its JSON verdict; this tool persists only, it does not contact the supervisor)",agents:["architect"]},lean_turbo_plan_lanes:{description:"partition phase tasks into parallel lanes based on file-scope conflicts for Lean Turbo execution",agents:[]},lean_turbo_acquire_locks:{description:"acquire file locks for all files in a lane (all-or-nothing) before lane execution",agents:[]},lean_turbo_runner_status:{description:"read Lean Turbo run state from .swarm/turbo-state.json",agents:[]},lean_turbo_review:{description:"dispatch a read-only reviewer agent to evaluate a completed Lean Turbo phase",agents:[]},lean_turbo_run_phase:{description:"Execute a phase using Lean Turbo parallel lane execution. Plans lanes, acquires file locks, and dispatches coder agents concurrently. Use when Lean Turbo is active and you want to execute all tasks in a phase in parallel lanes.",agents:[]},lean_turbo_status:{description:"returns Lean Turbo configuration and active status for the current session",agents:[]},swarm_apply_patch:{description:"Apply a unified diff patch to workspace files with exact context matching, atomic writes, and path validation. Use standard unified diff format only — does NOT support *** Begin Patch / *** Update File payloads (use native apply_patch for those).",agents:["coder","test_engineer"]},external_skill_discover:{description:"Discover external skill candidates from configured sources. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_list:{description:"List external skill candidates in the quarantine store. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_inspect:{description:"Inspect a specific external skill candidate by ID. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_promote:{description:"Promote a validated external skill candidate to an active generated skill. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_reject:{description:"Reject an external skill candidate after evaluation. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_delete:{description:"Delete an external skill candidate from the quarantine store. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_revoke:{description:"Revoke a previously promoted external skill. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},epic_decide_phase:{description:"Compute the Epic Mode verdict for a phase WITHOUT dispatching coders. Runs preflight + calibration + the three gates (p-threshold, hot-module, greenfield), persists the decision, and returns the verdict so the architect can dispatch waves via the visible Task tool (promote) or fall back to per-task serial (demote). Pair with `epic_plan_waves` to get the wave plan when promoted. Use when /swarm epic is on for the session.",agents:["architect"]},epic_plan_waves:{description:"Partition a phase's pending tasks into ordered concurrent waves for Epic Mode dispatch. A wave is a set of tasks with mutually disjoint declared scopes and all dependencies satisfied by prior waves. Returns `{ waves: [{ waveId, taskIds, files }, ...], serializedTasks, degradedTasks }`. "+'For each wave in order, the architect dispatches one `Task(subagent_type="coder", ...)` per `taskId` — all in one assistant message — so the wave runs concurrently and each coder appears as a visible subagent. '+"Wait for the wave to finish before dispatching the next. Pair with `epic_decide_phase` (called first; this tool is only relevant on a `promote` verdict). "+"Preflight reject reasons: `no-plan`, `no-phase`, `phase-empty`, `phase-already-complete`, `scopes-missing` (call `declare_scope` for `missingScopes`), `git-failed` (transient — retry), `planner-error`.",agents:["architect"]},epic_record_divergence:{description:"After every `update_task_status(completed)`, record the task's declared-vs-actual divergence to .swarm/epic/divergence.jsonl. Feeds Epic Mode's self-calibration loop (Capability D). Best-effort: never blocks.",agents:["architect"]}},TOOL_NAMES=Object.keys(TOOL_METADATA),TOOL_NAME_SET=new Set(TOOL_NAMES),TOOL_DESCRIPTIONS=Object.fromEntries(Object.entries(TOOL_METADATA).map(([name,meta])=>[name,meta.description])),AGENT_TOOL_MAP=(()=>{let map=Object.fromEntries(ALL_AGENT_NAMES.map((agent)=>[agent,[]]));for(let[name,meta]of Object.entries(TOOL_METADATA))for(let agent of meta.agents)map[agent].push(name);return map})()});function deepMergeInternal(base,override,depth){if(depth>=10)throw Error("deepMerge exceeded maximum depth of 10");let result={...base};for(let key of Object.keys(override)){let baseVal=base[key],overrideVal=override[key];if(typeof baseVal==="object"&&baseVal!==null&&typeof overrideVal==="object"&&overrideVal!==null&&!Array.isArray(baseVal)&&!Array.isArray(overrideVal))result[key]=deepMergeInternal(baseVal,overrideVal,depth+1);else result[key]=overrideVal}return result}function deepMerge(base,override){if(!base)return override;if(!override)return base;return deepMergeInternal(base,override,0)}function freezeSet(items){let set=new Set(items),proxy=new Proxy(set,{get(target,prop){if(prop==="add"||prop==="delete"||prop==="clear")return()=>{throw TypeError("CLAUDE_CODE_NATIVE_COMMANDS is readonly")};if(prop==="forEach")return(callback,thisArg)=>{let wrapped=(v,k)=>callback.call(thisArg??void 0,v,k,proxy);return set.forEach(wrapped)};let value=Reflect.get(target,prop);return typeof value==="function"?value.bind(target):value},set(){throw TypeError("CLAUDE_CODE_NATIVE_COMMANDS is readonly")},deleteProperty(){throw TypeError("CLAUDE_CODE_NATIVE_COMMANDS is readonly")},defineProperty(){throw TypeError("CLAUDE_CODE_NATIVE_COMMANDS is readonly")},setPrototypeOf(){throw TypeError("CLAUDE_CODE_NATIVE_COMMANDS is readonly")}});return proxy}function isQAAgent(name){return QA_AGENTS.includes(name)}function isSubagent(name){return ALL_SUBAGENT_NAMES.includes(name)}function isLowCapabilityModel(modelId){let lower=(modelId||"").toLowerCase();return LOW_CAPABILITY_MODELS.some((substr)=>lower.includes(substr))}var OPENCODE_NATIVE_AGENTS,CLAUDE_CODE_NATIVE_COMMANDS,MEMORY_AGENT_TOOL_MAP,EXTERNAL_SKILL_TOOL_NAMES,EXTERNAL_SKILL_AGENT_TOOL_MAP,COUNCIL_TOOL_NAMES,COUNCIL_AGENT_TOOL_MAP,GENERAL_COUNCIL_TOOL_NAMES,GENERAL_COUNCIL_AGENT_TOOL_MAP,TURBO_TOOL_NAMES,TURBO_AGENT_TOOL_MAP,SKILL_TOOL_NAMES,SKILL_AGENT_TOOL_MAP,WRITE_TOOL_NAMES,DEFAULT_MODELS,DEFAULT_SCORING_CONFIG,LOW_CAPABILITY_MODELS,TURBO_MODE_BANNER=`## \uD83D\uDE80 TURBO MODE ACTIVE
1
+ import{createRequire}from"node:module";var __create=Object.create;var{getPrototypeOf:__getProtoOf,defineProperty:__defProp,getOwnPropertyNames:__getOwnPropNames,getOwnPropertyDescriptor:__getOwnPropDesc}=Object,__hasOwnProp=Object.prototype.hasOwnProperty;function __accessProp(key){return this[key]}var __toESMCache_node,__toESMCache_esm,__toESM=(mod,isNodeMode,target)=>{var canCache=mod!=null&&typeof mod==="object";if(canCache){var cache=isNodeMode?__toESMCache_node??=new WeakMap:__toESMCache_esm??=new WeakMap,cached=cache.get(mod);if(cached)return cached}target=mod!=null?__create(__getProtoOf(mod)):{};let to=isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target;for(let key of __getOwnPropNames(mod))if(!__hasOwnProp.call(to,key))__defProp(to,key,{get:__accessProp.bind(mod,key),enumerable:!0});if(canCache)cache.set(mod,to);return to},__toCommonJS=(from)=>{var entry=(__moduleCache??=new WeakMap).get(from),desc;if(entry)return entry;if(entry=__defProp({},"__esModule",{value:!0}),from&&typeof from==="object"||typeof from==="function"){for(var key of __getOwnPropNames(from))if(!__hasOwnProp.call(entry,key))__defProp(entry,key,{get:__accessProp.bind(from,key),enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return __moduleCache.set(from,entry),entry},__moduleCache,__commonJS=(cb,mod)=>()=>(mod||cb((mod={exports:{}}).exports,mod),mod.exports);var __returnValue=(v)=>v;function __exportSetter(name,newValue){this[name]=__returnValue.bind(null,newValue)}var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0,configurable:!0,set:__exportSetter.bind(all,name)})};var __esm=(fn2,res)=>()=>(fn2&&(res=fn2(fn2=0)),res);var __require=createRequire(import.meta.url);var package_default;var init_package=__esm(()=>{package_default={name:"opencode-swarm",version:"7.118.1",description:"Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",main:"dist/index.js",types:"dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",default:"./dist/index.js"},"./package.json":"./package.json"},bin:{"opencode-swarm":"./dist/cli/index.js"},type:"module",engines:{bun:">=1.3.13"},license:"MIT",repository:{type:"git",url:"https://github.com/ZaxbyHub/opencode-swarm.git"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"},keywords:["opencode","opencode-plugin","ai","agents","orchestration","swarm","multi-agent","llm"],files:["dist","dist/lang/grammars","binaries","evaluation-fixtures",".opencode/skills/brainstorm",".opencode/skills/specify",".opencode/skills/clarify-spec",".opencode/skills/resume",".opencode/skills/clarify",".opencode/skills/discover",".opencode/skills/consult",".opencode/skills/pre-phase-briefing",".opencode/skills/council",".opencode/skills/deep-dive",".opencode/skills/deep-research",".opencode/skills/codebase-review-swarm",".opencode/skills/swarm-implement",".opencode/skills/design-docs",".opencode/skills/swarm-pr-review",".opencode/skills/swarm",".opencode/skills/swarm-pr-feedback",".opencode/skills/swarm-pr-subscribe",".opencode/skills/swarm-ci-monitor",".opencode/skills/issue-ingest",".opencode/skills/plan",".opencode/skills/critic-gate",".opencode/skills/execute",".opencode/skills/phase-wrap",".opencode/skills/loop",".opencode/skills/writing-tests",".opencode/skills/running-tests",".opencode/skills/engineering-conventions",".opencode/skills/commit-pr",".opencode/skills/ci-failure-batching",".opencode/skills/gate-attribution",".opencode/skills/merge-queue-readiness",".opencode/skills/skill-edit-validation",".opencode/skills/worktree-retry-cleanup",".opencode/skills/test-file-split",".opencode/skills/fork-pr-operations",".opencode/skills/parallel-work-check",".opencode/skills/ci-fix-monitor","tests/fixtures/memory-recall","README.md","LICENSE"],scripts:{clean:`bun -e "require('fs').rmSync('dist',{recursive:true,force:true})"`,build:"bun run clean && bun run scripts/copy-grammars.ts && bun build src/index.ts --outdir dist --target node --format esm --external web-tree-sitter --minify-whitespace --minify-syntax && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external bash-parser --splitting && bun run scripts/copy-grammars.ts --to-dist && tsc --emitDeclarationOnly",typecheck:"tsc --noEmit",test:"bun test",lint:"biome lint .","lint:ci":"biome ci .","test:unit:ci":"bun scripts/ci/run-unit-tests-local.ts","drift:check":"bun run scripts/drift-check.ts","drift:fix":"bun run scripts/drift-check.ts --fix --confirm",format:"biome format . --write",check:"biome check --write .",dev:"bun run build && opencode","package:smoke":"node scripts/package-smoke.mjs",prepare:"bun run build","repro:704":"node scripts/repro-704.mjs","repro:1144":"bun scripts/repro-1144.mjs"},dependencies:{"@opencode-ai/plugin":"^1.1.53","@opencode-ai/sdk":"^1.1.53","@vscode/tree-sitter-wasm":"^0.3.0","bash-parser":"^0.5.0","p-limit":"^7.3.0",picomatch:"^4.0.4","proper-lockfile":"^4.1.2","quick-lru":"^7.3.0","web-tree-sitter":"^0.25.0",zod:"^4.1.8"},devDependencies:{"@biomejs/biome":"2.3.14","@types/picomatch":"^4.0.3","bun-types":"1.3.8","js-yaml":"^4.1.1",typescript:"^5.7.3"}}});var QA_AGENTS,PIPELINE_AGENTS,ORCHESTRATOR_NAME="architect",ALL_SUBAGENT_NAMES,ALL_AGENT_NAMES;var init_agent_names=__esm(()=>{QA_AGENTS=["reviewer","critic","critic_oversight"],PIPELINE_AGENTS=["explorer","coder","test_engineer"],ALL_SUBAGENT_NAMES=["sme","researcher","docs","docs_design","designer","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic_architecture_supervisor","curator_init","curator_phase","curator_postmortem","curator_consolidation","council_generalist","council_skeptic","council_domain_expert","skill_improver","spec_writer",...QA_AGENTS,...PIPELINE_AGENTS],ALL_AGENT_NAMES=["architect",...ALL_SUBAGENT_NAMES]});var TOOL_METADATA,TOOL_NAMES,TOOL_NAME_SET,TOOL_DESCRIPTIONS,AGENT_TOOL_MAP;var init_tool_metadata=__esm(()=>{init_agent_names();TOOL_METADATA={diff:{description:"structured git diff with contract change detection",agents:["architect","reviewer","critic_oversight","coder","test_engineer"]},diff_summary:{description:"filter classified AST changes by category, risk level, or file for reviewer drill-down",agents:["architect","reviewer","critic_oversight"]},syntax_check:{description:"check syntax of source files using tree-sitter parsers across multiple languages, returning per-file errors",agents:["architect","coder","test_engineer"]},placeholder_scan:{description:"todo and FIXME comment detection",agents:["architect","reviewer"]},imports:{description:"find all consumers that import from a given file — use before refactoring shared modules to avoid breaking unseen dependents",agents:["architect","sme","researcher","docs","docs_design","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","reviewer","critic","coder","test_engineer"]},lint:{description:"run project linter in check or fix mode; supports biome, eslint, ruff, clippy, and more, returns structured results",agents:["architect","reviewer","coder"]},secretscan:{description:"scan for secrets (API keys, tokens, passwords) via regex and entropy; returns redacted previews, excludes common dirs",agents:["architect","reviewer","critic_oversight"]},sast_scan:{description:"static analysis security scan",agents:["architect","reviewer","critic_oversight"]},build_check:{description:"discover and run build, typecheck, and test commands for various project ecosystems in the working directory",agents:["architect","coder","test_engineer"]},pre_check_batch:{description:"parallel verification: lint:check + secretscan + sast_scan + quality_budget",agents:["architect","reviewer"]},quality_budget:{description:"code quality budget check",agents:["architect"]},symbols:{description:"extract exported symbols (functions, classes, interfaces, types) from source files; supports TypeScript, JavaScript, and Python",agents:["architect","sme","researcher","docs","docs_design","designer","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","spec_writer","reviewer","critic","coder","test_engineer"]},complexity_hotspots:{description:"git churn × complexity risk map",agents:["architect","sme","researcher","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","reviewer","critic","critic_oversight","explorer","test_engineer"]},schema_drift:{description:"OpenAPI spec vs route drift",agents:["architect","sme","researcher","docs","explorer"]},todo_extract:{description:"structured TODO/FIXME extraction",agents:["architect","researcher","docs","explorer"]},evidence_check:{description:"verify task evidence completeness",agents:["architect","critic_oversight"]},check_gate_status:{description:"check the gate status of a specific task",agents:["architect","critic_oversight"]},completion_verify:{description:"verify completed tasks have required evidence",agents:["architect","critic_oversight"]},submit_council_verdicts:{description:"submit pre-collected council member verdicts for synthesis (architect MUST dispatch critic/reviewer/sme/test_engineer/explorer as Agent tasks first; this tool synthesizes only, it does not contact members)",agents:[]},submit_phase_council_verdicts:{description:"submit pre-collected phase-level council member verdicts for holistic phase synthesis (architect MUST dispatch all 5 council members with phase-scoped context first; this tool synthesizes only, it does not contact members)",agents:[]},declare_council_criteria:{description:"pre-declare acceptance criteria for a task before the coder starts work; criteria are read back during council evaluation",agents:[]},sbom_generate:{description:"SBOM generation for dependency inventory",agents:["architect"]},checkpoint:{description:"create named git checkpoints for save, restore, and delete — use before risky operations to enable rollback",agents:["architect"]},pkg_audit:{description:"dependency vulnerability scan — npm/pip/cargo",agents:["architect","critic_hallucination_verifier","reviewer","critic_oversight","test_engineer"]},parse_lane_candidates:{description:"Parse [CANDIDATE] rows from a dispatch_lanes or collect_lane_results artifact (by output_ref), produce structured records with provenance, optionally persist to a per-batch sidecar JSONL. Pure-parser variant exists as internal module.",agents:["architect"]},write_pr_review_trigger_eval:{description:"persist the complete PR-review trigger evaluation with exact-set validation and dispatch provenance",agents:["architect"]},test_runner:{description:"auto-detect and run tests",agents:["architect","reviewer","test_engineer"]},test_impact:{description:"identify test files impacted by changed source files via import analysis",agents:["architect","reviewer","critic_oversight","test_engineer"]},mutation_test:{description:"executes pre-generated mutation patches against tests, evaluates kill rate against quality gate thresholds",agents:["architect","test_engineer"]},generate_mutants:{description:"generate LLM-based mutation testing patches for source files; returns MutationPatch[] for direct consumption by the mutation_test tool",agents:["architect"]},detect_domains:{description:"detect which SME domains are relevant for a given text",agents:["architect","sme","docs","docs_design","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic","critic_oversight","explorer"]},git_blame:{description:"per-line git blame metadata: sha, author, date, summary for each line in a file",agents:["reviewer","explorer","architect"]},gitingest:{description:"fetch a GitHub repository full content via gitingest.com",agents:["architect","docs","explorer"]},retrieve_summary:{description:"retrieve the full content of a stored tool output summary",agents:["architect","sme","docs","docs_design","designer","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic_architecture_supervisor","spec_writer","reviewer","critic","coder","test_engineer"]},retrieve_lane_output:{description:"retrieve paged full dispatch lane output by output_ref; use before consuming truncated lane previews or routing candidates from lane results",agents:["architect"]},extract_code_blocks:{description:"extract code blocks from text content and save them to files",agents:["docs","docs_design","designer","spec_writer","coder","test_engineer"]},phase_complete:{description:"mark a phase as complete and track dispatched agents",agents:["architect"]},save_plan:{description:"save a structured implementation plan",agents:["architect"]},update_task_status:{description:"mark tasks complete, track phase progress",agents:["architect"]},lint_spec:{description:"validate .swarm/spec.md format and required fields",agents:["architect","spec_writer"]},write_retro:{description:"document phase retrospectives via phase_complete workflow, capture lessons learned",agents:["architect"]},write_drift_evidence:{description:"write drift verification evidence for a completed phase",agents:["architect"]},write_hallucination_evidence:{description:"write hallucination verification evidence for a completed phase",agents:["architect"]},write_mutation_evidence:{description:"write mutation gate evidence for a completed phase; normalizes PASS/WARN/FAIL/SKIP verdicts and writes .swarm/evidence/{phase}/mutation-gate.json",agents:["architect"]},declare_scope:{description:"declare file scope for next coder delegation",agents:["architect"]},knowledge_query:{description:"query swarm or hive knowledge with optional filters",agents:["architect","skill_improver","spec_writer"]},doc_scan:{description:"scan project documentation files and build an index manifest",agents:["architect","docs_design","skill_improver","spec_writer","explorer"]},doc_extract:{description:"extract actionable constraints from project documentation",agents:["architect","docs_design","skill_improver","spec_writer"]},curator_analyze:{description:"run curator phase analysis and optionally apply knowledge recommendations",agents:["architect"]},knowledge_add:{description:"store a new lesson in the knowledge base",agents:["architect","coder"]},knowledge_recall:{description:"search the knowledge base for relevant past decisions",agents:["architect","sme","docs","docs_design","designer","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic_architecture_supervisor","curator_init","curator_phase","skill_improver","spec_writer","reviewer","critic","critic_oversight","explorer","coder","test_engineer"]},knowledge_remove:{description:"delete an outdated swarm knowledge entry by ID (swarm tier only)",agents:["architect"]},co_change_analyzer:{description:"detect hidden couplings by analyzing git history",agents:["architect"]},context_status:{description:"report current context-window headroom for the active session — returns tokens-used, model-limit, usage-percent, threshold-state (none/warn/critical), model name, and provider. Pure read-only: no state mutation, no warning injection. Works whether context_budget.enabled is true or false.",agents:["architect"]},search:{description:"Workspace-scoped ripgrep-style text search with structured JSON output. Supports literal and regex modes, glob filtering, and result limits. NOTE: This is text search, not structural AST search — use symbols and imports tools for structural queries.",agents:["architect","sme","docs","docs_design","designer","critic_hallucination_verifier","skill_improver","spec_writer","reviewer","critic_oversight","explorer","coder","test_engineer","researcher"]},ast_grep:{description:"Read-only structural AST search using ast-grep patterns with optional language and glob filters. Use for syntax-aware code pattern searches; does not rewrite files.",agents:["architect","sme","docs","docs_design","critic_hallucination_verifier","spec_writer","explorer","coder","test_engineer","researcher"]},actionlint_scan:{description:"Run actionlint against GitHub Actions workflow YAML files with structured findings. Resolves actionlint lazily and does not modify files.",agents:["architect","test_engineer"]},osv_scan:{description:"Run OSV-Scanner against a workspace path and return structured dependency vulnerability findings. Resolves osv-scanner lazily and does not modify files.",agents:["architect","test_engineer"]},gh_evidence:{description:"Fetch bounded GitHub pull request or issue metadata through gh for review and CI evidence. Resolves gh lazily and is read-only.",agents:["architect","researcher"]},batch_symbols:{description:"Batched symbol extraction across multiple files. Returns per-file symbol summaries with isolated error handling.",agents:["architect","critic_hallucination_verifier","reviewer","critic_oversight","explorer"]},suggest_patch:{description:"Reviewer-safe structured patch suggestion tool. Produces context-anchored patch artifacts without file modification. Returns structured diagnostics on context mismatch.",agents:["architect","reviewer"]},req_coverage:{description:"query requirement coverage status for tracked functional requirements",agents:["critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","spec_writer","critic","critic_oversight"]},get_approved_plan:{description:"retrieve the last critic-approved immutable plan snapshot for baseline drift comparison",agents:["critic_drift_verifier","critic","critic_oversight"]},repo_map:{description:"query the repo code graph: importers, dependencies, blast radius, localization, ontology facts, package boundaries, and heuristic preflight packets before refactoring; ontology findings are advisory, not formal proofs",agents:["architect","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic_architecture_supervisor","reviewer","critic","critic_oversight","explorer","coder"]},get_qa_gate_profile:{description:"retrieve the QA gate profile for the current plan: gates (reviewer, test_engineer, sme_enabled, critic_pre_plan, sast_enabled, council_mode, hallucination_guard, mutation_test, phase_council, drift_check, final_council), lock state, and profile hash. Read-only.",agents:["architect"]},set_qa_gates:{description:"configure the QA gate profile for the current plan. Architect-only. Ratchet-tighter only — rejected once the profile is locked after critic approval. Supports: reviewer, test_engineer, sme_enabled, critic_pre_plan, sast_enabled, council_mode, hallucination_guard, mutation_test, phase_council, drift_check, final_council.",agents:["architect"]},web_search:{description:"External web search (Tavily or Brave) for architect-driven council research, SME domain research, researcher auto-research, and skill-improver research. Returns titled results with snippets, URLs, normalized query metadata, temporal intent, freshness, and removed stale years. Config-gated on council.general.enabled in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides. Requires a search API key. Used by the architect in MODE: COUNCIL to gather a RESEARCH CONTEXT before dispatching council agents, by SME for opt-in external skill/source evaluation, and by the researcher agent for multi-source auto-research.",agents:["sme","researcher","skill_improver"]},web_fetch:{description:"Fetch the readable text of a single http(s) URL (architect-only). Returns decoded page text, document title, final URL after redirects, and an evidence reference. Reads primary sources that web_search only surfaces as snippets. Config-gated on council.general.enabled. Blocks private/loopback/link-local/metadata addresses (re-validated and re-pinned across redirects); enforces timeout and body size cap.",agents:[]},convene_general_council:{description:"Synthesize responses from a multi-model General Council. Accepts parallel member responses (Round 1, optionally Round 2), detects disagreements, and returns consensus points, persisting disagreements, and a structured synthesis. Architect-only. Config-gated on council.general.enabled in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project .opencode/opencode-swarm.json overrides.",agents:[]},write_final_council_evidence:{description:"Persist project-scoped final council evidence to .swarm/evidence/final-council.json. PREREQUISITE: dispatch critic, reviewer, sme, test_engineer, and explorer as project-scoped Agent tasks and collect their CouncilMemberVerdict JSON — this tool synthesizes only. Rejects on insufficient quorum or CONCERNS with unresolved requiredFixes; normalizes verdicts to approved/concerns/rejected. Architect-only.",agents:[]},skill_generate:{description:"compile knowledge entries into a structured SKILL.md draft",agents:["skill_improver"]},skill_list:{description:"list generated skill files and their status",agents:["skill_improver"]},skill_apply:{description:"activate a draft skill proposal",agents:[]},skill_inspect:{description:"inspect the content and source entries of a skill file",agents:["skill_improver"]},run_stale_reconciliation:{description:"reconcile skills against the knowledge store: mark skills stale when source knowledge is archived or deleted, or clear stale markers",agents:["architect"]},skill_regenerate:{description:"regenerate an active skill by re-clustering its source knowledge entries and updating the SKILL.md in place",agents:[]},skill_retire:{description:"retire a generated skill by adding a retired.marker file; retired skills are excluded from scoring and injection",agents:[]},skill_improve:{description:"run the skill_improver agent to review and refine skills",agents:["skill_improver"]},spec_write:{description:"author or update .swarm/spec.md for the current project",agents:["spec_writer"]},knowledge_receipt:{description:"file a receipt for retrieved knowledge (applied/ignored/contradicted + new lessons), recorded as immutable knowledge events",agents:["architect","sme","docs","docs_design","designer","critic_sounding_board","critic_drift_verifier","critic_hallucination_verifier","critic_architecture_supervisor","curator_init","curator_phase","skill_improver","spec_writer","reviewer","critic","coder","test_engineer"]},knowledge_archive:{description:"archive (default), quarantine, or purge a swarm or hive knowledge entry by ID with an immutable audit tombstone; purge requires an admin flag",agents:["architect"]},swarm_memory_recall:{description:"recall scoped Swarm memory for the current repository as untrusted background",agents:[]},swarm_memory_propose:{description:"create a pending Swarm memory proposal; does not write durable memory directly",agents:[]},swarm_command:{description:"run supported /swarm commands through the canonical command registry",agents:["architect","sme","researcher","docs","docs_design","designer","reviewer","critic","explorer","coder","test_engineer"]},dispatch_lanes:{description:"dispatch read-only exploration/review lanes concurrently and BLOCK until all finish; prefer dispatch_lanes_async for non-blocking dispatch, use this only when promptAsync is unavailable",agents:["architect"]},dispatch_lanes_async:{description:"launch read-only advisory lanes non-blockingly and return a batch id plus lane session handles immediately so you can keep working; launch_timeout_ms is only a promptAsync acceptance budget, not a lane runtime timeout; poll incrementally with collect_lane_results (wait omitted or false) while doing independent investigation, or join with wait: true when you need all results",agents:["architect"]},collect_lane_results:{description:"collect or poll results for a dispatch_lanes_async batch; supports both non-blocking polling (wait omitted or false) and blocking join (wait: true). Non-blocking polls include pending lane identities by default and process settled lanes incrementally while continuing independent work; busy/retry lanes are not timed out just because they run for a long time. Does not advance workflow gates.",agents:["architect"]},summarize_work:{description:"emit a short structured summary of completed work (key decisions, assumptions, risks, constraints) at task completion; rolls up per phase for architecture-supervisor review. Advisory, never blocks.",agents:["architect","sme","researcher","docs","docs_design","designer","explorer","coder","test_engineer"]},write_architecture_supervisor_evidence:{description:"persist the architecture supervisor verdict for a phase (architect MUST dispatch critic_architecture_supervisor first and collect its JSON verdict; this tool persists only, it does not contact the supervisor)",agents:["architect"]},lean_turbo_plan_lanes:{description:"partition phase tasks into parallel lanes based on file-scope conflicts for Lean Turbo execution",agents:[]},lean_turbo_acquire_locks:{description:"acquire file locks for all files in a lane (all-or-nothing) before lane execution",agents:[]},lean_turbo_runner_status:{description:"read Lean Turbo run state from .swarm/turbo-state.json",agents:[]},lean_turbo_review:{description:"dispatch a read-only reviewer agent to evaluate a completed Lean Turbo phase",agents:[]},lean_turbo_run_phase:{description:"Execute a phase using Lean Turbo parallel lane execution. Plans lanes, acquires file locks, and dispatches coder agents concurrently. Use when Lean Turbo is active and you want to execute all tasks in a phase in parallel lanes.",agents:[]},lean_turbo_status:{description:"returns Lean Turbo configuration and active status for the current session",agents:[]},swarm_apply_patch:{description:"Apply a unified diff patch to workspace files with exact context matching, atomic writes, and path validation. Use standard unified diff format only — does NOT support *** Begin Patch / *** Update File payloads (use native apply_patch for those).",agents:["coder","test_engineer"]},external_skill_discover:{description:"Discover external skill candidates from configured sources. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_list:{description:"List external skill candidates in the quarantine store. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_inspect:{description:"Inspect a specific external skill candidate by ID. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_promote:{description:"Promote a validated external skill candidate to an active generated skill. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_reject:{description:"Reject an external skill candidate after evaluation. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_delete:{description:"Delete an external skill candidate from the quarantine store. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},external_skill_revoke:{description:"Revoke a previously promoted external skill. Returns a disabled message when external_skills.curation_enabled is false.",agents:[]},epic_decide_phase:{description:"Compute the Epic Mode verdict for a phase WITHOUT dispatching coders. Runs preflight + calibration + the three gates (p-threshold, hot-module, greenfield), persists the decision, and returns the verdict so the architect can dispatch waves via the visible Task tool (promote) or fall back to per-task serial (demote). Pair with `epic_plan_waves` to get the wave plan when promoted. Use when /swarm epic is on for the session.",agents:["architect"]},epic_plan_waves:{description:"Partition a phase's pending tasks into ordered concurrent waves for Epic Mode dispatch. A wave is a set of tasks with mutually disjoint declared scopes and all dependencies satisfied by prior waves. Returns `{ waves: [{ waveId, taskIds, files }, ...], serializedTasks, degradedTasks }`. "+'For each wave in order, the architect dispatches one `Task(subagent_type="coder", ...)` per `taskId` — all in one assistant message — so the wave runs concurrently and each coder appears as a visible subagent. '+"Wait for the wave to finish before dispatching the next. Pair with `epic_decide_phase` (called first; this tool is only relevant on a `promote` verdict). "+"Preflight reject reasons: `no-plan`, `no-phase`, `phase-empty`, `phase-already-complete`, `scopes-missing` (call `declare_scope` for `missingScopes`), `git-failed` (transient — retry), `planner-error`.",agents:["architect"]},epic_record_divergence:{description:"After every `update_task_status(completed)`, record the task's declared-vs-actual divergence to .swarm/epic/divergence.jsonl. Feeds Epic Mode's self-calibration loop (Capability D). Best-effort: never blocks.",agents:["architect"]}},TOOL_NAMES=Object.keys(TOOL_METADATA),TOOL_NAME_SET=new Set(TOOL_NAMES),TOOL_DESCRIPTIONS=Object.fromEntries(Object.entries(TOOL_METADATA).map(([name,meta])=>[name,meta.description])),AGENT_TOOL_MAP=(()=>{let map=Object.fromEntries(ALL_AGENT_NAMES.map((agent)=>[agent,[]]));for(let[name,meta]of Object.entries(TOOL_METADATA))for(let agent of meta.agents)map[agent].push(name);return map})()});function deepMergeInternal(base,override,depth){if(depth>=10)throw Error("deepMerge exceeded maximum depth of 10");let result={...base};for(let key of Object.keys(override)){let baseVal=base[key],overrideVal=override[key];if(typeof baseVal==="object"&&baseVal!==null&&typeof overrideVal==="object"&&overrideVal!==null&&!Array.isArray(baseVal)&&!Array.isArray(overrideVal))result[key]=deepMergeInternal(baseVal,overrideVal,depth+1);else result[key]=overrideVal}return result}function deepMerge(base,override){if(!base)return override;if(!override)return base;return deepMergeInternal(base,override,0)}function freezeSet(items){let set=new Set(items),proxy=new Proxy(set,{get(target,prop){if(prop==="add"||prop==="delete"||prop==="clear")return()=>{throw TypeError("CLAUDE_CODE_NATIVE_COMMANDS is readonly")};if(prop==="forEach")return(callback,thisArg)=>{let wrapped=(v,k)=>callback.call(thisArg??void 0,v,k,proxy);return set.forEach(wrapped)};let value=Reflect.get(target,prop);return typeof value==="function"?value.bind(target):value},set(){throw TypeError("CLAUDE_CODE_NATIVE_COMMANDS is readonly")},deleteProperty(){throw TypeError("CLAUDE_CODE_NATIVE_COMMANDS is readonly")},defineProperty(){throw TypeError("CLAUDE_CODE_NATIVE_COMMANDS is readonly")},setPrototypeOf(){throw TypeError("CLAUDE_CODE_NATIVE_COMMANDS is readonly")}});return proxy}function isQAAgent(name){return QA_AGENTS.includes(name)}function isSubagent(name){return ALL_SUBAGENT_NAMES.includes(name)}function isLowCapabilityModel(modelId){let lower=(modelId||"").toLowerCase();return LOW_CAPABILITY_MODELS.some((substr)=>lower.includes(substr))}var OPENCODE_NATIVE_AGENTS,CLAUDE_CODE_NATIVE_COMMANDS,MEMORY_AGENT_TOOL_MAP,EXTERNAL_SKILL_TOOL_NAMES,EXTERNAL_SKILL_AGENT_TOOL_MAP,COUNCIL_TOOL_NAMES,COUNCIL_AGENT_TOOL_MAP,GENERAL_COUNCIL_TOOL_NAMES,GENERAL_COUNCIL_AGENT_TOOL_MAP,TURBO_TOOL_NAMES,TURBO_AGENT_TOOL_MAP,SKILL_TOOL_NAMES,SKILL_AGENT_TOOL_MAP,WRITE_TOOL_NAMES,DEFAULT_MODELS,DEFAULT_SCORING_CONFIG,LOW_CAPABILITY_MODELS,TURBO_MODE_BANNER=`## \uD83D\uDE80 TURBO MODE ACTIVE
2
2
 
3
3
  **Speed optimization enabled for this session.**
4
4
 
@@ -222,11 +222,11 @@ try {
222
222
  `)}
223
223
  `;if(projected.length>MAX_SPEC_BYTES)return{kind:"too_large",feature:selectedFeature.featureId,bytes:projected.length};let validation=validateSpecContent(projected);if(!validation.valid)warnings.push(...validation.issues.map((issue2)=>`Projection line ${issue2.line}: ${issue2.message}`));return{kind:"ok",spec:{source:"speckit_projection",content:projected,hash:hash2(projected),mtime:mtimeMs>0?new Date(mtimeMs).toISOString():null,sourcePaths:[selectedFeature.specRelPath],warnings},feature:selectedFeature.featureId}}function buildSpeckitProjectionSync(directory,options={}){let resolution=resolveSpeckitProjection(directory,options);return resolution.kind==="ok"?resolution.spec:null}function loadSddStatusSync(directory,opts){let root=path15.resolve(directory),swSpecPath=path15.join(root,SWARM_SPEC_REL),openSpecPath=path15.join(root,OPENSPEC_ROOT),errors3=[],warnings=[],swSpecExists=fs10.existsSync(swSpecPath),openSpecExists=fs10.existsSync(openSpecPath),currentSpecs=walkSpecFiles(root,path15.join(OPENSPEC_ROOT,"specs")),changes=listOpenSpecChanges(root),effectiveSpec=readEffectiveSpecSync(root,opts);if(openSpecExists&&currentSpecs.length===0&&changes.length===0)errors3.push("openspec/ exists but contains no specs or active changes.");for(let change of changes){if(!change.proposal)warnings.push(`Change ${change.id} is missing proposal.md.`);if(!change.tasks)warnings.push(`Change ${change.id} is missing tasks.md; tasks remain proposal input, not plan state.`);if(change.specs.length===0)errors3.push(`Change ${change.id} has no specs/**/spec.md delta files.`)}return{provider:effectiveSpec?.source??"none",swSpecExists,openSpecExists,currentSpecs,changes,effectiveSpec,errors:errors3,warnings}}function buildOpenSpecProjectionSync(directory,options={}){let root=path15.resolve(directory),currentSpecs=walkSpecFiles(root,path15.join(OPENSPEC_ROOT,"specs")),allChanges=listOpenSpecChanges(root),changes=options.changeId?allChanges.filter((change)=>change.id===options.changeId):allChanges,sourcePaths=[],warnings=[],usedIds=new Set,currentRequirements=[],changeRequirements=new Map,parsedRequirementCount=0,mtimeMs=0;if(options.changeId&&changes.length===0)return null;if(currentSpecs.length===0&&changes.length===0)return null;for(let artifact of currentSpecs){let abs=path15.join(root,artifact.relPath),content2=readTextBounded(abs);if(content2===null){warnings.push(`Skipped unreadable or oversized spec ${artifact.relPath}.`);continue}sourcePaths.push(artifact.relPath),mtimeMs=Math.max(mtimeMs,artifact.mtimeMs);let parsed=parseRequirements(content2,artifact.relPath,"CURRENT");currentRequirements.push(...parsed),parsedRequirementCount+=parsed.length}for(let change of changes){let reqs=[];for(let artifact of change.specs){let abs=path15.join(root,artifact.relPath),content2=readTextBounded(abs);if(content2===null){warnings.push(`Skipped unreadable or oversized spec ${artifact.relPath}.`);continue}sourcePaths.push(artifact.relPath),mtimeMs=Math.max(mtimeMs,artifact.mtimeMs);let parsed=parseRequirements(content2,artifact.relPath,"ADDED");reqs.push(...parsed),parsedRequirementCount+=parsed.length}changeRequirements.set(change.id,reqs)}if(sourcePaths.length>0&&parsedRequirementCount===0)return null;let lines=["# Specification: Effective SDD Projection","","Generated from OpenSpec-compatible artifacts. Update the source artifacts, then run `/swarm sdd project` to refresh this projection.","","## Source Artifacts",...sourcePaths.map((rel)=>`- ${rel}`),"","## Current Requirements"];if(currentRequirements.length===0)lines.push("- No current OpenSpec requirements found in source artifacts."),warnings.push("No current requirements found; projection includes an advisory note only.");else for(let req of currentRequirements)lines.push(renderRequirement(req,usedIds,warnings));for(let[changeId,reqs]of changeRequirements.entries()){if(lines.push("",`## Pending Change: ${changeId}`),reqs.length===0){lines.push(`- ${nextFrId(usedIds,warnings)} SHOULD add OpenSpec delta requirements for change ${changeId}.`),warnings.push(`Change ${changeId} contains no parsable requirements.`);continue}for(let req of reqs)lines.push(renderRequirement(req,usedIds,warnings));lines.push(...renderSuccessCriteriaScaffold(changeId,usedIds))}if(currentRequirements.length>0)lines.push(...renderSuccessCriteriaScaffold("current-requirements",usedIds));let content=`${lines.join(`
224
224
  `)}
225
- `;if(content.length>MAX_SPEC_BYTES)return warnings.push(`Projected spec exceeds ${MAX_SPEC_BYTES} bytes; refusing to use projection.`),null;let validation=validateSpecContent(content);if(!validation.valid)warnings.push(...validation.issues.map((issue2)=>`Projection line ${issue2.line}: ${issue2.message}`));return{source:"openspec_projection",content,hash:hash2(content),mtime:mtimeMs>0?new Date(mtimeMs).toISOString():null,sourcePaths,warnings}}function readEffectiveSpecSync(directory,opts){if(directory.includes("\x00"))return null;let root=path15.resolve(directory),swSpecPath=path15.join(root,SWARM_SPEC_REL);try{let stat5=fs10.lstatSync(swSpecPath);if(stat5.isFile()&&stat5.size<=MAX_SPEC_BYTES){let content=fs10.readFileSync(swSpecPath,"utf-8");return{source:"swarm",content,hash:hash2(content),mtime:stat5.mtime.toISOString(),sourcePaths:[toPosix(SWARM_SPEC_REL)],warnings:[]}}}catch(error49){let code=error49.code;if(code!=="ENOENT"&&code!=="ENOTDIR"&&code!=="EACCES"&&code!=="EPERM"&&code!=="EUNKNOWN")throw error49}if(opts?.source)switch(opts.source){case"openspec":return buildOpenSpecProjectionSync(root);case"speckit":return buildSpeckitProjectionSync(root,{feature:opts.feature});case"swarm":return null}let speckitDetection=detectSpeckit(root);if(!speckitDetection.markerPresent)return buildOpenSpecProjectionSync(root);if(!(speckitDetection.features.length>0))return buildOpenSpecProjectionSync(root);if(buildOpenSpecProjectionSync(root)!==null)return console.warn("[opencode-swarm] Multiple SDD sources detected (openspec and speckit). Enforcement/projection is suppressed until you disambiguate. Pass --source openspec or --source speckit to select a provider."),null;return buildSpeckitProjectionSync(root,{feature:opts?.feature})}function writeProjectedSpecSync(directory,options={}){let root=path15.resolve(directory),projection=options.source==="speckit"?buildSpeckitProjectionSync(root,{feature:options.feature}):buildOpenSpecProjectionSync(root,{changeId:options.changeId}),target=path15.join(root,SWARM_SPEC_REL);if(!projection||options.dryRun)return{written:!1,projection,path:target};if(fs10.mkdirSync(path15.dirname(target),{recursive:!0}),!options.overwrite){try{fs10.writeFileSync(target,projection.content,{flag:"wx"})}catch(err){if(err.code==="EEXIST")return{written:!1,projection,path:target,error:".swarm/spec.md already exists; pass --overwrite to replace it"};throw err}return{written:!0,projection,path:target}}let archivePath;if(fs10.existsSync(target)){let prior=fs10.readFileSync(target,"utf-8");if(prior!==projection.content){let archiveDir=path15.join(root,".swarm","spec-archive");fs10.mkdirSync(archiveDir,{recursive:!0});let stamp=new Date().toISOString().replace(/[:.]/g,"-");archivePath=path15.join(archiveDir,`sdd-projection-${stamp}.md`),fs10.writeFileSync(archivePath,prior,"utf-8")}}let tmp=`${target}.tmp-${process.pid}-${Date.now()}`;return fs10.writeFileSync(tmp,projection.content,"utf-8"),fs10.renameSync(tmp,target),{written:!0,projection,archivePath,path:target}}function validateSpeckit(directory,options={}){let root=path15.resolve(directory),resolution=resolveSpeckitProjection(root,options),problems=[];if(resolution.kind!=="ok"&&resolution.kind!=="zero_requirements")return{resolution,problems};if(resolution.kind==="zero_requirements")problems.push(`Feature '${resolution.feature}' contains no parsable functional requirements.`);let featureEntry=detectSpeckit(root).features.find((f)=>f.featureId===resolution.feature);if(!featureEntry)return{resolution,problems};let specAbs=path15.join(root,featureEntry.specRelPath),specContent=null;try{specContent=readTextBounded(specAbs)}catch{}if(specContent!==null){let specLines=specContent.replace(/\r\n/g,`
225
+ `;if(content.length>MAX_SPEC_BYTES)return warnings.push(`Projected spec exceeds ${MAX_SPEC_BYTES} bytes; refusing to use projection.`),null;let validation=validateSpecContent(content);if(!validation.valid)warnings.push(...validation.issues.map((issue2)=>`Projection line ${issue2.line}: ${issue2.message}`));return{source:"openspec_projection",content,hash:hash2(content),mtime:mtimeMs>0?new Date(mtimeMs).toISOString():null,sourcePaths,warnings}}function readEffectiveSpecSync(directory,opts){if(directory.includes("\x00"))return null;let root=path15.resolve(directory),swSpecPath=path15.join(root,SWARM_SPEC_REL);try{let stat5=fs10.lstatSync(swSpecPath);if(stat5.isFile()&&stat5.size<=MAX_SPEC_BYTES){let content=fs10.readFileSync(swSpecPath,"utf-8");return{source:"swarm",content,hash:hash2(content),mtime:stat5.mtime.toISOString(),sourcePaths:[toPosix(SWARM_SPEC_REL)],warnings:[]}}}catch(error49){let code=error49.code;if(code!=="ENOENT"&&code!=="ENOTDIR"&&code!=="EACCES"&&code!=="EPERM"&&code!=="EUNKNOWN")throw error49}if(opts?.source)switch(opts.source){case"openspec":return buildOpenSpecProjectionSync(root);case"speckit":return buildSpeckitProjectionSync(root,{feature:opts.feature});case"swarm":return null}let speckitDetection=detectSpeckit(root);if(!speckitDetection.markerPresent)return buildOpenSpecProjectionSync(root);if(!(speckitDetection.features.length>0))return buildOpenSpecProjectionSync(root);if(buildOpenSpecProjectionSync(root)!==null)return advisoryWarn("[opencode-swarm] Multiple SDD sources detected (openspec and speckit). Enforcement/projection is suppressed until you disambiguate. Pass --source openspec or --source speckit to select a provider."),null;return buildSpeckitProjectionSync(root,{feature:opts?.feature})}function writeProjectedSpecSync(directory,options={}){let root=path15.resolve(directory),projection=options.source==="speckit"?buildSpeckitProjectionSync(root,{feature:options.feature}):buildOpenSpecProjectionSync(root,{changeId:options.changeId}),target=path15.join(root,SWARM_SPEC_REL);if(!projection||options.dryRun)return{written:!1,projection,path:target};if(fs10.mkdirSync(path15.dirname(target),{recursive:!0}),!options.overwrite){try{fs10.writeFileSync(target,projection.content,{flag:"wx"})}catch(err){if(err.code==="EEXIST")return{written:!1,projection,path:target,error:".swarm/spec.md already exists; pass --overwrite to replace it"};throw err}return{written:!0,projection,path:target}}let archivePath;if(fs10.existsSync(target)){let prior=fs10.readFileSync(target,"utf-8");if(prior!==projection.content){let archiveDir=path15.join(root,".swarm","spec-archive");fs10.mkdirSync(archiveDir,{recursive:!0});let stamp=new Date().toISOString().replace(/[:.]/g,"-");archivePath=path15.join(archiveDir,`sdd-projection-${stamp}.md`),fs10.writeFileSync(archivePath,prior,"utf-8")}}let tmp=`${target}.tmp-${process.pid}-${Date.now()}`;return fs10.writeFileSync(tmp,projection.content,"utf-8"),fs10.renameSync(tmp,target),{written:!0,projection,archivePath,path:target}}function validateSpeckit(directory,options={}){let root=path15.resolve(directory),resolution=resolveSpeckitProjection(root,options),problems=[];if(resolution.kind!=="ok"&&resolution.kind!=="zero_requirements")return{resolution,problems};if(resolution.kind==="zero_requirements")problems.push(`Feature '${resolution.feature}' contains no parsable functional requirements.`);let featureEntry=detectSpeckit(root).features.find((f)=>f.featureId===resolution.feature);if(!featureEntry)return{resolution,problems};let specAbs=path15.join(root,featureEntry.specRelPath),specContent=null;try{specContent=readTextBounded(specAbs)}catch{}if(specContent!==null){let specLines=specContent.replace(/\r\n/g,`
226
226
  `).split(`
227
227
  `);for(let requiredHeader of SPECKIT_REQUIRED_SECTIONS)if(!specLines.some((line)=>line.trimEnd()===requiredHeader))problems.push(`Missing required spec.md section: ${requiredHeader}`)}let tasksAbs=path15.join(path15.dirname(specAbs),"tasks.md"),tasksContent=null;try{tasksContent=readTextBounded(tasksAbs)}catch{}if(tasksContent!==null){let tasksLines=tasksContent.replace(/\r\n/g,`
228
228
  `).split(`
229
- `);for(let line of tasksLines){let taskMatch=line.match(/^\s*-\s+\[[ xX]\]\s+(T\d+)/);if(!taskMatch)continue;let taskId=taskMatch[1],hasStoryRef=/\[US\d+\]/i.test(line),hasReqRef=/\bFR-(?!000)\d{3}\b/i.test(line);if(!hasStoryRef&&!hasReqRef)problems.push(`Task ${taskId} has no spec/requirement reference.`)}}return{resolution,problems}}var SWARM_SPEC_REL,OPENSPEC_ROOT="openspec",SPECKIT_MARKER=".specify",SPECKIT_SPECS_DIR="specs",MAX_SPEC_BYTES=262144,MAX_SOURCE_BYTES=524288,MAX_SPEC_FILES=100,MAX_WALK_DEPTH=10,SPECKIT_REQUIRED_SECTIONS;var init_effective_spec=__esm(()=>{init_spec_schema();SWARM_SPEC_REL=path15.join(".swarm","spec.md"),SPECKIT_REQUIRED_SECTIONS=["## Functional Requirements","## Success Criteria"]});import{createHash as createHash2}from"node:crypto";import*as fsSync4 from"node:fs";import{join as join12}from"node:path";async function computeSpecHash(directory){let spec=_internals11.readEffectiveSpecSync(directory);if(!spec)return null;return createHash2("sha256").update(spec.content,"utf-8").digest("hex")}async function isSpecStale(directory,plan){let currentHash=await _internals11.computeSpecHash(directory);if(!plan.specHash)return{stale:!1};if(currentHash===null)return{stale:!0,reason:"effective spec has been deleted",currentHash:null};if(currentHash!==plan.specHash)return{stale:!0,reason:"effective spec has been modified since plan was saved",currentHash};return{stale:!1}}function isObligationPreserving(directory){let snapshotPath=join12(directory,".swarm","spec-snapshot.md");try{let recordedContent;try{recordedContent=fsSync4.readFileSync(snapshotPath,"utf-8")}catch{return!1}let currentResult=_internals11.readEffectiveSpecSync(directory);if(!currentResult||!currentResult.content)return!1;let currentContent=currentResult.content,normalize2=(text)=>text.replace(/\r\n/g,`
229
+ `);for(let line of tasksLines){let taskMatch=line.match(/^\s*-\s+\[[ xX]\]\s+(T\d+)/);if(!taskMatch)continue;let taskId=taskMatch[1],hasStoryRef=/\[US\d+\]/i.test(line),hasReqRef=/\bFR-(?!000)\d{3}\b/i.test(line);if(!hasStoryRef&&!hasReqRef)problems.push(`Task ${taskId} has no spec/requirement reference.`)}}return{resolution,problems}}var SWARM_SPEC_REL,OPENSPEC_ROOT="openspec",SPECKIT_MARKER=".specify",SPECKIT_SPECS_DIR="specs",MAX_SPEC_BYTES=262144,MAX_SOURCE_BYTES=524288,MAX_SPEC_FILES=100,MAX_WALK_DEPTH=10,SPECKIT_REQUIRED_SECTIONS;var init_effective_spec=__esm(()=>{init_spec_schema();init_warning_buffer();SWARM_SPEC_REL=path15.join(".swarm","spec.md"),SPECKIT_REQUIRED_SECTIONS=["## Functional Requirements","## Success Criteria"]});import{createHash as createHash2}from"node:crypto";import*as fsSync4 from"node:fs";import{join as join12}from"node:path";async function computeSpecHash(directory){let spec=_internals11.readEffectiveSpecSync(directory);if(!spec)return null;return createHash2("sha256").update(spec.content,"utf-8").digest("hex")}async function isSpecStale(directory,plan){let currentHash=await _internals11.computeSpecHash(directory);if(!plan.specHash)return{stale:!1};if(currentHash===null)return{stale:!0,reason:"effective spec has been deleted",currentHash:null};if(currentHash!==plan.specHash)return{stale:!0,reason:"effective spec has been modified since plan was saved",currentHash};return{stale:!1}}function isObligationPreserving(directory){let snapshotPath=join12(directory,".swarm","spec-snapshot.md");try{let recordedContent;try{recordedContent=fsSync4.readFileSync(snapshotPath,"utf-8")}catch{return!1}let currentResult=_internals11.readEffectiveSpecSync(directory);if(!currentResult||!currentResult.content)return!1;let currentContent=currentResult.content,normalize2=(text)=>text.replace(/\r\n/g,`
230
230
  `),recordedNorm=normalize2(recordedContent),currentNorm=normalize2(currentContent),splitParagraphs=(text)=>text.split(/\n\s*\n/).map((p)=>p.trim()).filter((p)=>p.length>0),recordedParagraphs=splitParagraphs(recordedNorm),currentParagraphs=splitParagraphs(currentNorm),isObligationLine=(line)=>/\bSC-\d+/.test(line)||/\bFR-\d+/.test(line)||/\bMUST\b/i.test(line)||/\bSHALL\b/i.test(line),isObligationParagraph=(para)=>para.split(`
231
231
  `).some(isObligationLine),recordedObligationParas=recordedParagraphs.filter(isObligationParagraph).sort(),currentObligationParas=currentParagraphs.filter(isObligationParagraph).sort();if(recordedObligationParas.length!==currentObligationParas.length)return!1;for(let i=0;i<recordedObligationParas.length;i++)if(recordedObligationParas[i]!==currentObligationParas[i])return!1;return!0}catch{return!1}}function computeSpecDiff(directory){let snapshotPath=join12(directory,".swarm","spec-snapshot.md"),recordedContent;try{let snapshotSize=fsSync4.statSync(snapshotPath).size,MAX_SNAPSHOT_BYTES=524288;if(snapshotSize>524288)return null;recordedContent=fsSync4.readFileSync(snapshotPath,"utf-8")}catch{return null}let spec=_internals11.readEffectiveSpecSync(directory);if(!spec)return null;let currentContent=spec.content,normalize2=(text)=>text.replace(/\r\n/g,`
232
232
  `),recordedLines=normalize2(recordedContent).split(`
@@ -237,12 +237,12 @@ try {
237
237
  ... (diff truncated — `+String(diffLines.length-MAX_DIFF_LINES)+" more lines)",changedSectionsSet=new Set,currentSection="";for(let line of diffLines){let headingMatch=line.slice(1).match(/^##\s+(.+)$/);if(headingMatch)currentSection=headingMatch[1].trim();if(line.length>0&&(line[0]==="+"||line[0]==="-")){if(currentSection)changedSectionsSet.add(currentSection)}}return{diff:diffText,changedSections:Array.from(changedSectionsSet)}}function computeLcsDiff(oldLines,newLines){let m=oldLines.length,n=newLines.length,dp=Array.from({length:m+1},()=>Array(n+1).fill(0));for(let i2=1;i2<=m;i2++)for(let j2=1;j2<=n;j2++)if(oldLines[i2-1]===newLines[j2-1])dp[i2][j2]=dp[i2-1][j2-1]+1;else dp[i2][j2]=Math.max(dp[i2-1][j2],dp[i2][j2-1]);let entries=[],i=m,j=n;while(i>0||j>0)if(i>0&&j>0&&oldLines[i-1]===newLines[j-1])entries.unshift({type:"unchanged",line:oldLines[i-1]}),i--,j--;else if(j>0&&(i===0||dp[i][j-1]>=dp[i-1][j]))entries.unshift({type:"add",line:newLines[j-1]}),j--;else entries.unshift({type:"remove",line:oldLines[i-1]}),i--;return entries.map((entry)=>{if(entry.type==="unchanged")return` ${entry.line}`;if(entry.type==="add")return`+${entry.line}`;return`-${entry.line}`})}var _internals11;var init_spec_hash=__esm(()=>{init_effective_spec();_internals11={computeSpecDiff,computeSpecHash,isObligationPreserving,isSpecStale,readEffectiveSpecSync}});var require_polyfills=__commonJS((exports,module)=>{var constants2=__require("constants"),origCwd=process.cwd,cwd=null,platform=process.env.GRACEFUL_FS_PLATFORM||process.platform;process.cwd=function(){if(!cwd)cwd=origCwd.call(process);return cwd};try{process.cwd()}catch(er){}if(typeof process.chdir==="function"){if(chdir=process.chdir,process.chdir=function(d){cwd=null,chdir.call(process,d)},Object.setPrototypeOf)Object.setPrototypeOf(process.chdir,chdir)}var chdir;module.exports=patch;function patch(fs11){if(constants2.hasOwnProperty("O_SYMLINK")&&process.version.match(/^v0\.6\.[0-2]|^v0\.5\./))patchLchmod(fs11);if(!fs11.lutimes)patchLutimes(fs11);if(fs11.chown=chownFix(fs11.chown),fs11.fchown=chownFix(fs11.fchown),fs11.lchown=chownFix(fs11.lchown),fs11.chmod=chmodFix(fs11.chmod),fs11.fchmod=chmodFix(fs11.fchmod),fs11.lchmod=chmodFix(fs11.lchmod),fs11.chownSync=chownFixSync(fs11.chownSync),fs11.fchownSync=chownFixSync(fs11.fchownSync),fs11.lchownSync=chownFixSync(fs11.lchownSync),fs11.chmodSync=chmodFixSync(fs11.chmodSync),fs11.fchmodSync=chmodFixSync(fs11.fchmodSync),fs11.lchmodSync=chmodFixSync(fs11.lchmodSync),fs11.stat=statFix(fs11.stat),fs11.fstat=statFix(fs11.fstat),fs11.lstat=statFix(fs11.lstat),fs11.statSync=statFixSync(fs11.statSync),fs11.fstatSync=statFixSync(fs11.fstatSync),fs11.lstatSync=statFixSync(fs11.lstatSync),fs11.chmod&&!fs11.lchmod)fs11.lchmod=function(path16,mode,cb){if(cb)process.nextTick(cb)},fs11.lchmodSync=function(){};if(fs11.chown&&!fs11.lchown)fs11.lchown=function(path16,uid,gid,cb){if(cb)process.nextTick(cb)},fs11.lchownSync=function(){};if(platform==="win32")fs11.rename=typeof fs11.rename!=="function"?fs11.rename:function(fs$rename){function rename3(from,to,cb){var start=Date.now(),backoff=0;fs$rename(from,to,function CB(er){if(er&&(er.code==="EACCES"||er.code==="EPERM"||er.code==="EBUSY")&&Date.now()-start<60000){if(setTimeout(function(){fs11.stat(to,function(stater,st){if(stater&&stater.code==="ENOENT")fs$rename(from,to,CB);else cb(er)})},backoff),backoff<100)backoff+=10;return}if(cb)cb(er)})}if(Object.setPrototypeOf)Object.setPrototypeOf(rename3,fs$rename);return rename3}(fs11.rename);fs11.read=typeof fs11.read!=="function"?fs11.read:function(fs$read){function read(fd,buffer,offset,length,position,callback_){var callback;if(callback_&&typeof callback_==="function"){var eagCounter=0;callback=function(er,_,__){if(er&&er.code==="EAGAIN"&&eagCounter<10)return eagCounter++,fs$read.call(fs11,fd,buffer,offset,length,position,callback);callback_.apply(this,arguments)}}return fs$read.call(fs11,fd,buffer,offset,length,position,callback)}if(Object.setPrototypeOf)Object.setPrototypeOf(read,fs$read);return read}(fs11.read),fs11.readSync=typeof fs11.readSync!=="function"?fs11.readSync:function(fs$readSync){return function(fd,buffer,offset,length,position){var eagCounter=0;while(!0)try{return fs$readSync.call(fs11,fd,buffer,offset,length,position)}catch(er){if(er.code==="EAGAIN"&&eagCounter<10){eagCounter++;continue}throw er}}}(fs11.readSync);function patchLchmod(fs12){fs12.lchmod=function(path16,mode,callback){fs12.open(path16,constants2.O_WRONLY|constants2.O_SYMLINK,mode,function(err,fd){if(err){if(callback)callback(err);return}fs12.fchmod(fd,mode,function(err2){fs12.close(fd,function(err22){if(callback)callback(err2||err22)})})})},fs12.lchmodSync=function(path16,mode){var fd=fs12.openSync(path16,constants2.O_WRONLY|constants2.O_SYMLINK,mode),threw=!0,ret;try{ret=fs12.fchmodSync(fd,mode),threw=!1}finally{if(threw)try{fs12.closeSync(fd)}catch(er){}else fs12.closeSync(fd)}return ret}}function patchLutimes(fs12){if(constants2.hasOwnProperty("O_SYMLINK")&&fs12.futimes)fs12.lutimes=function(path16,at,mt,cb){fs12.open(path16,constants2.O_SYMLINK,function(er,fd){if(er){if(cb)cb(er);return}fs12.futimes(fd,at,mt,function(er2){fs12.close(fd,function(er22){if(cb)cb(er2||er22)})})})},fs12.lutimesSync=function(path16,at,mt){var fd=fs12.openSync(path16,constants2.O_SYMLINK),ret,threw=!0;try{ret=fs12.futimesSync(fd,at,mt),threw=!1}finally{if(threw)try{fs12.closeSync(fd)}catch(er){}else fs12.closeSync(fd)}return ret};else if(fs12.futimes)fs12.lutimes=function(_a2,_b,_c,cb){if(cb)process.nextTick(cb)},fs12.lutimesSync=function(){}}function chmodFix(orig){if(!orig)return orig;return function(target,mode,cb){return orig.call(fs11,target,mode,function(er){if(chownErOk(er))er=null;if(cb)cb.apply(this,arguments)})}}function chmodFixSync(orig){if(!orig)return orig;return function(target,mode){try{return orig.call(fs11,target,mode)}catch(er){if(!chownErOk(er))throw er}}}function chownFix(orig){if(!orig)return orig;return function(target,uid,gid,cb){return orig.call(fs11,target,uid,gid,function(er){if(chownErOk(er))er=null;if(cb)cb.apply(this,arguments)})}}function chownFixSync(orig){if(!orig)return orig;return function(target,uid,gid){try{return orig.call(fs11,target,uid,gid)}catch(er){if(!chownErOk(er))throw er}}}function statFix(orig){if(!orig)return orig;return function(target,options,cb){if(typeof options==="function")cb=options,options=null;function callback(er,stats2){if(stats2){if(stats2.uid<0)stats2.uid+=4294967296;if(stats2.gid<0)stats2.gid+=4294967296}if(cb)cb.apply(this,arguments)}return options?orig.call(fs11,target,options,callback):orig.call(fs11,target,callback)}}function statFixSync(orig){if(!orig)return orig;return function(target,options){var stats2=options?orig.call(fs11,target,options):orig.call(fs11,target);if(stats2){if(stats2.uid<0)stats2.uid+=4294967296;if(stats2.gid<0)stats2.gid+=4294967296}return stats2}}function chownErOk(er){if(!er)return!0;if(er.code==="ENOSYS")return!0;var nonroot=!process.getuid||process.getuid()!==0;if(nonroot){if(er.code==="EINVAL"||er.code==="EPERM")return!0}return!1}}});var require_legacy_streams=__commonJS((exports,module)=>{var Stream=__require("stream").Stream;module.exports=legacy;function legacy(fs11){return{ReadStream,WriteStream};function ReadStream(path16,options){if(!(this instanceof ReadStream))return new ReadStream(path16,options);Stream.call(this);var self=this;this.path=path16,this.fd=null,this.readable=!0,this.paused=!1,this.flags="r",this.mode=438,this.bufferSize=65536,options=options||{};var keys=Object.keys(options);for(var index=0,length=keys.length;index<length;index++){var key=keys[index];this[key]=options[key]}if(this.encoding)this.setEncoding(this.encoding);if(this.start!==void 0){if(typeof this.start!=="number")throw TypeError("start must be a Number");if(this.end===void 0)this.end=1/0;else if(typeof this.end!=="number")throw TypeError("end must be a Number");if(this.start>this.end)throw Error("start must be <= end");this.pos=this.start}if(this.fd!==null){process.nextTick(function(){self._read()});return}fs11.open(this.path,this.flags,this.mode,function(err,fd){if(err){self.emit("error",err),self.readable=!1;return}self.fd=fd,self.emit("open",fd),self._read()})}function WriteStream(path16,options){if(!(this instanceof WriteStream))return new WriteStream(path16,options);Stream.call(this),this.path=path16,this.fd=null,this.writable=!0,this.flags="w",this.encoding="binary",this.mode=438,this.bytesWritten=0,options=options||{};var keys=Object.keys(options);for(var index=0,length=keys.length;index<length;index++){var key=keys[index];this[key]=options[key]}if(this.start!==void 0){if(typeof this.start!=="number")throw TypeError("start must be a Number");if(this.start<0)throw Error("start must be >= zero");this.pos=this.start}if(this.busy=!1,this._queue=[],this.fd===null)this._open=fs11.open,this._queue.push([this._open,this.path,this.flags,this.mode,void 0]),this.flush()}}});var require_clone=__commonJS((exports,module)=>{module.exports=clone2;var getPrototypeOf=Object.getPrototypeOf||function(obj){return obj.__proto__};function clone2(obj){if(obj===null||typeof obj!=="object")return obj;if(obj instanceof Object)var copy={__proto__:getPrototypeOf(obj)};else var copy=Object.create(null);return Object.getOwnPropertyNames(obj).forEach(function(key){Object.defineProperty(copy,key,Object.getOwnPropertyDescriptor(obj,key))}),copy}});var require_graceful_fs=__commonJS((exports,module)=>{var fs11=__require("fs"),polyfills=require_polyfills(),legacy=require_legacy_streams(),clone2=require_clone(),util=__require("util"),gracefulQueue,previousSymbol;if(typeof Symbol==="function"&&typeof Symbol.for==="function")gracefulQueue=Symbol.for("graceful-fs.queue"),previousSymbol=Symbol.for("graceful-fs.previous");else gracefulQueue="___graceful-fs.queue",previousSymbol="___graceful-fs.previous";function noop(){}function publishQueue(context,queue2){Object.defineProperty(context,gracefulQueue,{get:function(){return queue2}})}var debug=noop;if(util.debuglog)debug=util.debuglog("gfs4");else if(/\bgfs4\b/i.test(process.env.NODE_DEBUG||""))debug=function(){var m=util.format.apply(util,arguments);m="GFS4: "+m.split(/\n/).join(`
238
238
  GFS4: `),console.error(m)};if(!fs11[gracefulQueue]){if(queue=global[gracefulQueue]||[],publishQueue(fs11,queue),fs11.close=function(fs$close){function close(fd,cb){return fs$close.call(fs11,fd,function(err){if(!err)resetQueue();if(typeof cb==="function")cb.apply(this,arguments)})}return Object.defineProperty(close,previousSymbol,{value:fs$close}),close}(fs11.close),fs11.closeSync=function(fs$closeSync){function closeSync(fd){fs$closeSync.apply(fs11,arguments),resetQueue()}return Object.defineProperty(closeSync,previousSymbol,{value:fs$closeSync}),closeSync}(fs11.closeSync),/\bgfs4\b/i.test(process.env.NODE_DEBUG||""))process.on("exit",function(){debug(fs11[gracefulQueue]),__require("assert").equal(fs11[gracefulQueue].length,0)})}var queue;if(!global[gracefulQueue])publishQueue(global,fs11[gracefulQueue]);module.exports=patch(clone2(fs11));if(process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH&&!fs11.__patched)module.exports=patch(fs11),fs11.__patched=!0;function patch(fs12){polyfills(fs12),fs12.gracefulify=patch,fs12.createReadStream=createReadStream,fs12.createWriteStream=createWriteStream2;var fs$readFile=fs12.readFile;fs12.readFile=readFile4;function readFile4(path16,options,cb){if(typeof options==="function")cb=options,options=null;return go$readFile(path16,options,cb);function go$readFile(path17,options2,cb2,startTime){return fs$readFile(path17,options2,function(err){if(err&&(err.code==="EMFILE"||err.code==="ENFILE"))enqueue([go$readFile,[path17,options2,cb2],err,startTime||Date.now(),Date.now()]);else if(typeof cb2==="function")cb2.apply(this,arguments)})}}var fs$writeFile=fs12.writeFile;fs12.writeFile=writeFile3;function writeFile3(path16,data,options,cb){if(typeof options==="function")cb=options,options=null;return go$writeFile(path16,data,options,cb);function go$writeFile(path17,data2,options2,cb2,startTime){return fs$writeFile(path17,data2,options2,function(err){if(err&&(err.code==="EMFILE"||err.code==="ENFILE"))enqueue([go$writeFile,[path17,data2,options2,cb2],err,startTime||Date.now(),Date.now()]);else if(typeof cb2==="function")cb2.apply(this,arguments)})}}var fs$appendFile=fs12.appendFile;if(fs$appendFile)fs12.appendFile=appendFile;function appendFile(path16,data,options,cb){if(typeof options==="function")cb=options,options=null;return go$appendFile(path16,data,options,cb);function go$appendFile(path17,data2,options2,cb2,startTime){return fs$appendFile(path17,data2,options2,function(err){if(err&&(err.code==="EMFILE"||err.code==="ENFILE"))enqueue([go$appendFile,[path17,data2,options2,cb2],err,startTime||Date.now(),Date.now()]);else if(typeof cb2==="function")cb2.apply(this,arguments)})}}var fs$copyFile=fs12.copyFile;if(fs$copyFile)fs12.copyFile=copyFile2;function copyFile2(src,dest,flags,cb){if(typeof flags==="function")cb=flags,flags=0;return go$copyFile(src,dest,flags,cb);function go$copyFile(src2,dest2,flags2,cb2,startTime){return fs$copyFile(src2,dest2,flags2,function(err){if(err&&(err.code==="EMFILE"||err.code==="ENFILE"))enqueue([go$copyFile,[src2,dest2,flags2,cb2],err,startTime||Date.now(),Date.now()]);else if(typeof cb2==="function")cb2.apply(this,arguments)})}}var fs$readdir=fs12.readdir;fs12.readdir=readdir2;var noReaddirOptionVersions=/^v[0-5]\./;function readdir2(path16,options,cb){if(typeof options==="function")cb=options,options=null;var go$readdir=noReaddirOptionVersions.test(process.version)?function(path17,options2,cb2,startTime){return fs$readdir(path17,fs$readdirCallback(path17,options2,cb2,startTime))}:function(path17,options2,cb2,startTime){return fs$readdir(path17,options2,fs$readdirCallback(path17,options2,cb2,startTime))};return go$readdir(path16,options,cb);function fs$readdirCallback(path17,options2,cb2,startTime){return function(err,files){if(err&&(err.code==="EMFILE"||err.code==="ENFILE"))enqueue([go$readdir,[path17,options2,cb2],err,startTime||Date.now(),Date.now()]);else{if(files&&files.sort)files.sort();if(typeof cb2==="function")cb2.call(this,err,files)}}}}if(process.version.substr(0,4)==="v0.8"){var legStreams=legacy(fs12);ReadStream=legStreams.ReadStream,WriteStream=legStreams.WriteStream}var fs$ReadStream=fs12.ReadStream;if(fs$ReadStream)ReadStream.prototype=Object.create(fs$ReadStream.prototype),ReadStream.prototype.open=ReadStream$open;var fs$WriteStream=fs12.WriteStream;if(fs$WriteStream)WriteStream.prototype=Object.create(fs$WriteStream.prototype),WriteStream.prototype.open=WriteStream$open;Object.defineProperty(fs12,"ReadStream",{get:function(){return ReadStream},set:function(val){ReadStream=val},enumerable:!0,configurable:!0}),Object.defineProperty(fs12,"WriteStream",{get:function(){return WriteStream},set:function(val){WriteStream=val},enumerable:!0,configurable:!0});var FileReadStream=ReadStream;Object.defineProperty(fs12,"FileReadStream",{get:function(){return FileReadStream},set:function(val){FileReadStream=val},enumerable:!0,configurable:!0});var FileWriteStream=WriteStream;Object.defineProperty(fs12,"FileWriteStream",{get:function(){return FileWriteStream},set:function(val){FileWriteStream=val},enumerable:!0,configurable:!0});function ReadStream(path16,options){if(this instanceof ReadStream)return fs$ReadStream.apply(this,arguments),this;else return ReadStream.apply(Object.create(ReadStream.prototype),arguments)}function ReadStream$open(){var that=this;open2(that.path,that.flags,that.mode,function(err,fd){if(err){if(that.autoClose)that.destroy();that.emit("error",err)}else that.fd=fd,that.emit("open",fd),that.read()})}function WriteStream(path16,options){if(this instanceof WriteStream)return fs$WriteStream.apply(this,arguments),this;else return WriteStream.apply(Object.create(WriteStream.prototype),arguments)}function WriteStream$open(){var that=this;open2(that.path,that.flags,that.mode,function(err,fd){if(err)that.destroy(),that.emit("error",err);else that.fd=fd,that.emit("open",fd)})}function createReadStream(path16,options){return new fs12.ReadStream(path16,options)}function createWriteStream2(path16,options){return new fs12.WriteStream(path16,options)}var fs$open=fs12.open;fs12.open=open2;function open2(path16,flags,mode,cb){if(typeof mode==="function")cb=mode,mode=null;return go$open(path16,flags,mode,cb);function go$open(path17,flags2,mode2,cb2,startTime){return fs$open(path17,flags2,mode2,function(err,fd){if(err&&(err.code==="EMFILE"||err.code==="ENFILE"))enqueue([go$open,[path17,flags2,mode2,cb2],err,startTime||Date.now(),Date.now()]);else if(typeof cb2==="function")cb2.apply(this,arguments)})}}return fs12}function enqueue(elem){debug("ENQUEUE",elem[0].name,elem[1]),fs11[gracefulQueue].push(elem),retry()}var retryTimer;function resetQueue(){var now=Date.now();for(var i=0;i<fs11[gracefulQueue].length;++i)if(fs11[gracefulQueue][i].length>2)fs11[gracefulQueue][i][3]=now,fs11[gracefulQueue][i][4]=now;retry()}function retry(){if(clearTimeout(retryTimer),retryTimer=void 0,fs11[gracefulQueue].length===0)return;var elem=fs11[gracefulQueue].shift(),fn2=elem[0],args2=elem[1],err=elem[2],startTime=elem[3],lastTime=elem[4];if(startTime===void 0)debug("RETRY",fn2.name,args2),fn2.apply(null,args2);else if(Date.now()-startTime>=60000){debug("TIMEOUT",fn2.name,args2);var cb=args2.pop();if(typeof cb==="function")cb.call(null,err)}else{var sinceAttempt=Date.now()-lastTime,sinceStart=Math.max(lastTime-startTime,1),desiredDelay=Math.min(sinceStart*1.2,100);if(sinceAttempt>=desiredDelay)debug("RETRY",fn2.name,args2),fn2.apply(null,args2.concat([startTime]));else fs11[gracefulQueue].push(elem)}if(retryTimer===void 0)retryTimer=setTimeout(retry,0)}});var require_retry_operation=__commonJS((exports,module)=>{function RetryOperation(timeouts,options){if(typeof options==="boolean")options={forever:options};if(this._originalTimeouts=JSON.parse(JSON.stringify(timeouts)),this._timeouts=timeouts,this._options=options||{},this._maxRetryTime=options&&options.maxRetryTime||1/0,this._fn=null,this._errors=[],this._attempts=1,this._operationTimeout=null,this._operationTimeoutCb=null,this._timeout=null,this._operationStart=null,this._options.forever)this._cachedTimeouts=this._timeouts.slice(0)}module.exports=RetryOperation;RetryOperation.prototype.reset=function(){this._attempts=1,this._timeouts=this._originalTimeouts};RetryOperation.prototype.stop=function(){if(this._timeout)clearTimeout(this._timeout);this._timeouts=[],this._cachedTimeouts=null};RetryOperation.prototype.retry=function(err){if(this._timeout)clearTimeout(this._timeout);if(!err)return!1;var currentTime=new Date().getTime();if(err&&currentTime-this._operationStart>=this._maxRetryTime)return this._errors.unshift(Error("RetryOperation timeout occurred")),!1;this._errors.push(err);var timeout=this._timeouts.shift();if(timeout===void 0)if(this._cachedTimeouts)this._errors.splice(this._errors.length-1,this._errors.length),this._timeouts=this._cachedTimeouts.slice(0),timeout=this._timeouts.shift();else return!1;var self=this,timer=setTimeout(function(){if(self._attempts++,self._operationTimeoutCb){if(self._timeout=setTimeout(function(){self._operationTimeoutCb(self._attempts)},self._operationTimeout),self._options.unref)self._timeout.unref()}self._fn(self._attempts)},timeout);if(this._options.unref)timer.unref();return!0};RetryOperation.prototype.attempt=function(fn2,timeoutOps){if(this._fn=fn2,timeoutOps){if(timeoutOps.timeout)this._operationTimeout=timeoutOps.timeout;if(timeoutOps.cb)this._operationTimeoutCb=timeoutOps.cb}var self=this;if(this._operationTimeoutCb)this._timeout=setTimeout(function(){self._operationTimeoutCb()},self._operationTimeout);this._operationStart=new Date().getTime(),this._fn(this._attempts)};RetryOperation.prototype.try=function(fn2){console.log("Using RetryOperation.try() is deprecated"),this.attempt(fn2)};RetryOperation.prototype.start=function(fn2){console.log("Using RetryOperation.start() is deprecated"),this.attempt(fn2)};RetryOperation.prototype.start=RetryOperation.prototype.try;RetryOperation.prototype.errors=function(){return this._errors};RetryOperation.prototype.attempts=function(){return this._attempts};RetryOperation.prototype.mainError=function(){if(this._errors.length===0)return null;var counts={},mainError=null,mainErrorCount=0;for(var i=0;i<this._errors.length;i++){var error49=this._errors[i],message=error49.message,count=(counts[message]||0)+1;if(counts[message]=count,count>=mainErrorCount)mainError=error49,mainErrorCount=count}return mainError}});var require_retry=__commonJS((exports)=>{var RetryOperation=require_retry_operation();exports.operation=function(options){var timeouts=exports.timeouts(options);return new RetryOperation(timeouts,{forever:options&&options.forever,unref:options&&options.unref,maxRetryTime:options&&options.maxRetryTime})};exports.timeouts=function(options){if(options instanceof Array)return[].concat(options);var opts={retries:10,factor:2,minTimeout:1000,maxTimeout:1/0,randomize:!1};for(var key in options)opts[key]=options[key];if(opts.minTimeout>opts.maxTimeout)throw Error("minTimeout is greater than maxTimeout");var timeouts=[];for(var i=0;i<opts.retries;i++)timeouts.push(this.createTimeout(i,opts));if(options&&options.forever&&!timeouts.length)timeouts.push(this.createTimeout(i,opts));return timeouts.sort(function(a,b){return a-b}),timeouts};exports.createTimeout=function(attempt,opts){var random=opts.randomize?Math.random()+1:1,timeout=Math.round(random*opts.minTimeout*Math.pow(opts.factor,attempt));return timeout=Math.min(timeout,opts.maxTimeout),timeout};exports.wrap=function(obj,options,methods){if(options instanceof Array)methods=options,options=null;if(!methods){methods=[];for(var key in obj)if(typeof obj[key]==="function")methods.push(key)}for(var i=0;i<methods.length;i++){var method=methods[i],original=obj[method];obj[method]=function(original2){var op=exports.operation(options),args2=Array.prototype.slice.call(arguments,1),callback=args2.pop();args2.push(function(err){if(op.retry(err))return;if(err)arguments[0]=op.mainError();callback.apply(this,arguments)}),op.attempt(function(){original2.apply(obj,args2)})}.bind(obj,original),obj[method].options=options}}});var require_signals=__commonJS((exports,module)=>{module.exports=["SIGABRT","SIGALRM","SIGHUP","SIGINT","SIGTERM"];if(process.platform!=="win32")module.exports.push("SIGVTALRM","SIGXCPU","SIGXFSZ","SIGUSR2","SIGTRAP","SIGSYS","SIGQUIT","SIGIOT");if(process.platform==="linux")module.exports.push("SIGIO","SIGPOLL","SIGPWR","SIGSTKFLT","SIGUNUSED")});var require_signal_exit=__commonJS((exports,module)=>{var process3=global.process,processOk=function(process4){return process4&&typeof process4==="object"&&typeof process4.removeListener==="function"&&typeof process4.emit==="function"&&typeof process4.reallyExit==="function"&&typeof process4.listeners==="function"&&typeof process4.kill==="function"&&typeof process4.pid==="number"&&typeof process4.on==="function"};if(!processOk(process3))module.exports=function(){return function(){}};else{if(assert2=__require("assert"),signals=require_signals(),isWin=/^win/i.test(process3.platform),EE=__require("events"),typeof EE!=="function")EE=EE.EventEmitter;if(process3.__signal_exit_emitter__)emitter=process3.__signal_exit_emitter__;else emitter=process3.__signal_exit_emitter__=new EE,emitter.count=0,emitter.emitted={};if(!emitter.infinite)emitter.setMaxListeners(1/0),emitter.infinite=!0;module.exports=function(cb,opts){if(!processOk(global.process))return function(){};if(assert2.equal(typeof cb,"function","a callback must be provided for exit handler"),loaded===!1)load();var ev="exit";if(opts&&opts.alwaysLast)ev="afterexit";var remove=function(){if(emitter.removeListener(ev,cb),emitter.listeners("exit").length===0&&emitter.listeners("afterexit").length===0)unload()};return emitter.on(ev,cb),remove},unload=function(){if(!loaded||!processOk(global.process))return;loaded=!1,signals.forEach(function(sig){try{process3.removeListener(sig,sigListeners[sig])}catch(er){}}),process3.emit=originalProcessEmit,process3.reallyExit=originalProcessReallyExit,emitter.count-=1},module.exports.unload=unload,emit2=function(event,code,signal){if(emitter.emitted[event])return;emitter.emitted[event]=!0,emitter.emit(event,code,signal)},sigListeners={},signals.forEach(function(sig){sigListeners[sig]=function(){if(!processOk(global.process))return;var listeners=process3.listeners(sig);if(listeners.length===emitter.count){if(unload(),emit2("exit",null,sig),emit2("afterexit",null,sig),isWin&&sig==="SIGHUP")sig="SIGINT";process3.kill(process3.pid,sig)}}}),module.exports.signals=function(){return signals},loaded=!1,load=function(){if(loaded||!processOk(global.process))return;loaded=!0,emitter.count+=1,signals=signals.filter(function(sig){try{return process3.on(sig,sigListeners[sig]),!0}catch(er){return!1}}),process3.emit=processEmit,process3.reallyExit=processReallyExit},module.exports.load=load,originalProcessReallyExit=process3.reallyExit,processReallyExit=function(code){if(!processOk(global.process))return;process3.exitCode=code||0,emit2("exit",process3.exitCode,null),emit2("afterexit",process3.exitCode,null),originalProcessReallyExit.call(process3,process3.exitCode)},originalProcessEmit=process3.emit,processEmit=function(ev,arg){if(ev==="exit"&&processOk(global.process)){if(arg!==void 0)process3.exitCode=arg;var ret=originalProcessEmit.apply(this,arguments);return emit2("exit",process3.exitCode,null),emit2("afterexit",process3.exitCode,null),ret}else return originalProcessEmit.apply(this,arguments)}}var assert2,signals,isWin,EE,emitter,unload,emit2,sigListeners,loaded,load,originalProcessReallyExit,processReallyExit,originalProcessEmit,processEmit});var require_mtime_precision=__commonJS((exports,module)=>{var cacheSymbol=Symbol();function probe2(file2,fs11,callback){let cachedPrecision=fs11[cacheSymbol];if(cachedPrecision)return fs11.stat(file2,(err,stat5)=>{if(err)return callback(err);callback(null,stat5.mtime,cachedPrecision)});let mtime=new Date(Math.ceil(Date.now()/1000)*1000+5);fs11.utimes(file2,mtime,mtime,(err)=>{if(err)return callback(err);fs11.stat(file2,(err2,stat5)=>{if(err2)return callback(err2);let precision=stat5.mtime.getTime()%1000===0?"s":"ms";Object.defineProperty(fs11,cacheSymbol,{value:precision}),callback(null,stat5.mtime,precision)})})}function getMtime(precision){let now=Date.now();if(precision==="s")now=Math.ceil(now/1000)*1000;return new Date(now)}exports.probe=probe2;exports.getMtime=getMtime});var require_lockfile=__commonJS((exports,module)=>{var path16=__require("path"),fs11=require_graceful_fs(),retry=require_retry(),onExit=require_signal_exit(),mtimePrecision=require_mtime_precision(),locks={};function getLockFile(file2,options){return options.lockfilePath||`${file2}.lock`}function resolveCanonicalPath(file2,options,callback){if(!options.realpath)return callback(null,path16.resolve(file2));options.fs.realpath(file2,callback)}function acquireLock(file2,options,callback){let lockfilePath=getLockFile(file2,options);options.fs.mkdir(lockfilePath,(err)=>{if(!err)return mtimePrecision.probe(lockfilePath,options.fs,(err2,mtime,mtimePrecision2)=>{if(err2)return options.fs.rmdir(lockfilePath,()=>{}),callback(err2);callback(null,mtime,mtimePrecision2)});if(err.code!=="EEXIST")return callback(err);if(options.stale<=0)return callback(Object.assign(Error("Lock file is already being held"),{code:"ELOCKED",file:file2}));options.fs.stat(lockfilePath,(err2,stat5)=>{if(err2){if(err2.code==="ENOENT")return acquireLock(file2,{...options,stale:0},callback);return callback(err2)}if(!isLockStale(stat5,options))return callback(Object.assign(Error("Lock file is already being held"),{code:"ELOCKED",file:file2}));removeLock(file2,options,(err3)=>{if(err3)return callback(err3);acquireLock(file2,{...options,stale:0},callback)})})})}function isLockStale(stat5,options){return stat5.mtime.getTime()<Date.now()-options.stale}function removeLock(file2,options,callback){options.fs.rmdir(getLockFile(file2,options),(err)=>{if(err&&err.code!=="ENOENT")return callback(err);callback()})}function updateLock(file2,options){let lock2=locks[file2];if(lock2.updateTimeout)return;if(lock2.updateDelay=lock2.updateDelay||options.update,lock2.updateTimeout=setTimeout(()=>{lock2.updateTimeout=null,options.fs.stat(lock2.lockfilePath,(err,stat5)=>{let isOverThreshold=lock2.lastUpdate+options.stale<Date.now();if(err){if(err.code==="ENOENT"||isOverThreshold)return setLockAsCompromised(file2,lock2,Object.assign(err,{code:"ECOMPROMISED"}));return lock2.updateDelay=1000,updateLock(file2,options)}if(lock2.mtime.getTime()!==stat5.mtime.getTime())return setLockAsCompromised(file2,lock2,Object.assign(Error("Unable to update lock within the stale threshold"),{code:"ECOMPROMISED"}));let mtime=mtimePrecision.getMtime(lock2.mtimePrecision);options.fs.utimes(lock2.lockfilePath,mtime,mtime,(err2)=>{let isOverThreshold2=lock2.lastUpdate+options.stale<Date.now();if(lock2.released)return;if(err2){if(err2.code==="ENOENT"||isOverThreshold2)return setLockAsCompromised(file2,lock2,Object.assign(err2,{code:"ECOMPROMISED"}));return lock2.updateDelay=1000,updateLock(file2,options)}lock2.mtime=mtime,lock2.lastUpdate=Date.now(),lock2.updateDelay=null,updateLock(file2,options)})})},lock2.updateDelay),lock2.updateTimeout.unref)lock2.updateTimeout.unref()}function setLockAsCompromised(file2,lock2,err){if(lock2.released=!0,lock2.updateTimeout)clearTimeout(lock2.updateTimeout);if(locks[file2]===lock2)delete locks[file2];lock2.options.onCompromised(err)}function lock(file2,options,callback){options={stale:1e4,update:null,realpath:!0,retries:0,fs:fs11,onCompromised:(err)=>{throw err},...options},options.retries=options.retries||0,options.retries=typeof options.retries==="number"?{retries:options.retries}:options.retries,options.stale=Math.max(options.stale||0,2000),options.update=options.update==null?options.stale/2:options.update||0,options.update=Math.max(Math.min(options.update,options.stale/2),1000),resolveCanonicalPath(file2,options,(err,file3)=>{if(err)return callback(err);let operation=retry.operation(options.retries);operation.attempt(()=>{acquireLock(file3,options,(err2,mtime,mtimePrecision2)=>{if(operation.retry(err2))return;if(err2)return callback(operation.mainError());let lock2=locks[file3]={lockfilePath:getLockFile(file3,options),mtime,mtimePrecision:mtimePrecision2,options,lastUpdate:Date.now()};updateLock(file3,options),callback(null,(releasedCallback)=>{if(lock2.released)return releasedCallback&&releasedCallback(Object.assign(Error("Lock is already released"),{code:"ERELEASED"}));unlock(file3,{...options,realpath:!1},releasedCallback)})})})})}function unlock(file2,options,callback){options={fs:fs11,realpath:!0,...options},resolveCanonicalPath(file2,options,(err,file3)=>{if(err)return callback(err);let lock2=locks[file3];if(!lock2)return callback(Object.assign(Error("Lock is not acquired/owned by you"),{code:"ENOTACQUIRED"}));lock2.updateTimeout&&clearTimeout(lock2.updateTimeout),lock2.released=!0,delete locks[file3],removeLock(file3,options,callback)})}function check2(file2,options,callback){options={stale:1e4,realpath:!0,fs:fs11,...options},options.stale=Math.max(options.stale||0,2000),resolveCanonicalPath(file2,options,(err,file3)=>{if(err)return callback(err);options.fs.stat(getLockFile(file3,options),(err2,stat5)=>{if(err2)return err2.code==="ENOENT"?callback(null,!1):callback(err2);return callback(null,!isLockStale(stat5,options))})})}function getLocks(){return locks}onExit(()=>{for(let file2 in locks){let options=locks[file2].options;try{options.fs.rmdirSync(getLockFile(file2,options))}catch(e){}}});exports.lock=lock;exports.unlock=unlock;exports.check=check2;exports.getLocks=getLocks});var require_adapter=__commonJS((exports,module)=>{var fs11=require_graceful_fs();function createSyncFs(fs12){let methods=["mkdir","realpath","stat","rmdir","utimes"],newFs={...fs12};return methods.forEach((method)=>{newFs[method]=(...args2)=>{let callback=args2.pop(),ret;try{ret=fs12[`${method}Sync`](...args2)}catch(err){return callback(err)}callback(null,ret)}}),newFs}function toPromise(method){return(...args2)=>new Promise((resolve7,reject)=>{args2.push((err,result)=>{if(err)reject(err);else resolve7(result)}),method(...args2)})}function toSync(method){return(...args2)=>{let err,result;if(args2.push((_err,_result)=>{err=_err,result=_result}),method(...args2),err)throw err;return result}}function toSyncOptions(options){if(options={...options},options.fs=createSyncFs(options.fs||fs11),typeof options.retries==="number"&&options.retries>0||options.retries&&typeof options.retries.retries==="number"&&options.retries.retries>0)throw Object.assign(Error("Cannot use retries with the sync api"),{code:"ESYNC"});return options}module.exports={toPromise,toSync,toSyncOptions}});var require_proper_lockfile=__commonJS((exports,module)=>{var lockfile=require_lockfile(),{toPromise,toSync,toSyncOptions}=require_adapter();async function lock(file2,options){let release=await toPromise(lockfile.lock)(file2,options);return toPromise(release)}function lockSync(file2,options){let release=toSync(lockfile.lock)(file2,toSyncOptions(options));return toSync(release)}function unlock(file2,options){return toPromise(lockfile.unlock)(file2,options)}function unlockSync(file2,options){return toSync(lockfile.unlock)(file2,toSyncOptions(options))}function check2(file2,options){return toPromise(lockfile.check)(file2,options)}function checkSync(file2,options){return toSync(lockfile.check)(file2,toSyncOptions(options))}module.exports=lock;module.exports.lock=lock;module.exports.unlock=unlock;module.exports.lockSync=lockSync;module.exports.unlockSync=unlockSync;module.exports.check=check2;module.exports.checkSync=checkSync});import*as crypto4 from"node:crypto";import*as fs11 from"node:fs";import*as path16 from"node:path";function getLockFilePath(directory,filePath){let normalized=path16.resolve(directory,filePath),baseDir=path16.resolve(directory)+path16.sep;if(!(process.platform==="win32"?normalized.toLowerCase().startsWith(baseDir.toLowerCase()):normalized.startsWith(baseDir)))throw Error("Invalid file path: path traversal not allowed");let pathForHash=process.platform==="win32"?normalized.toLowerCase():normalized,hash3=crypto4.createHash("sha256").update(pathForHash).digest("hex"),lockPath=path16.join(directory,LOCKS_DIR,`${hash3}.lock`),legacyPaths=[pathForHash];if(process.platform==="win32"&&normalized!==pathForHash)legacyPaths.push(normalized);for(let legacyPath of legacyPaths){let oldHash=Buffer.from(legacyPath).toString("base64").replace(/[/+=]/g,"_"),oldLockPath=path16.join(directory,LOCKS_DIR,`${oldHash}.lock`);if(fs11.existsSync(oldLockPath))return oldLockPath}return lockPath}function getMetaPath(lockPath){return`${lockPath.replace(/\.lock$/,"")}.meta`}async function writeMetaFile(metaPath,metadata){let tmpPath=`${metaPath}.tmp`;try{await _internals12.writeFile(tmpPath,JSON.stringify(metadata),"utf-8"),await fs11.promises.rename(tmpPath,metaPath)}catch(err){try{await fs11.promises.unlink(tmpPath)}catch{}throw err}}function readMetaFile(metaPath){try{let content=fs11.readFileSync(metaPath,"utf-8");return JSON.parse(content)}catch{return null}}async function tryAcquireLock(directory,filePath,agent,taskId){let lockPath=getLockFilePath(directory,filePath),locksDir=path16.dirname(lockPath);if(!fs11.existsSync(locksDir))fs11.mkdirSync(locksDir,{recursive:!0});if(!fs11.existsSync(lockPath))fs11.writeFileSync(lockPath,"","utf-8");let release;try{release=await import_proper_lockfile.default.lock(lockPath,{stale:LOCK_TIMEOUT_MS,retries:{retries:5,minTimeout:10,maxTimeout:500,factor:2},realpath:!1})}catch(err){let code=err.code;if(code==="ELOCKED"||code==="EEXIST")return{acquired:!1};throw err}return{acquired:!0,lock:{filePath,agent,taskId,timestamp:new Date().toISOString(),expiresAt:Date.now()+LOCK_TIMEOUT_MS,_release:release}}}function isLocked(directory,filePath){let plLockDir=`${getLockFilePath(directory,filePath)}.lock`;if(fs11.existsSync(plLockDir)){let acquiredAt=Date.now();try{acquiredAt=fs11.statSync(plLockDir).mtimeMs}catch{}return{filePath,agent:"unknown",taskId:"unknown",timestamp:new Date(acquiredAt).toISOString(),expiresAt:acquiredAt+LOCK_TIMEOUT_MS}}return null}function listActiveLocks(directory){let locksDir=path16.join(directory,LOCKS_DIR),locks=[];if(!fs11.existsSync(locksDir))return locks;let files=fs11.readdirSync(locksDir),now=Date.now();for(let file2 of files){if(!file2.endsWith(".lock"))continue;let lockPath=path16.join(locksDir,file2);try{if(fs11.statSync(lockPath).isFile()){let plLockDir=`${lockPath}.lock`;if(fs11.existsSync(plLockDir)){let metaPath=getMetaPath(lockPath),meta3=readMetaFile(metaPath);if(meta3){if(meta3.expiresAt<now)continue;locks.push({filePath:meta3.originalPath,agent:meta3.agent,taskId:meta3.taskId,timestamp:meta3.acquiredAt,expiresAt:meta3.expiresAt,laneId:meta3.laneId})}else{let acquiredAt=Date.now();try{acquiredAt=fs11.statSync(plLockDir).mtimeMs}catch{}let expiresAt=acquiredAt+LOCK_TIMEOUT_MS;if(expiresAt<now)continue;locks.push({filePath:file2,agent:"unknown",taskId:"unknown",timestamp:new Date(acquiredAt).toISOString(),expiresAt})}}}}catch{}}return locks}async function acquireLaneLocks(directory,laneId,files,agent,taskId,sessionID){let acquiredLocks=[],conflicts=[];for(let file2 of files){let result=await tryAcquireLock(directory,file2,agent,taskId);if(!result.acquired){for(let lock of acquiredLocks)try{if(lock._release)await lock._release();let lockPath2=getLockFilePath(directory,lock.filePath),metaPath2=getMetaPath(lockPath2);try{fs11.unlinkSync(metaPath2)}catch{}try{fs11.unlinkSync(lockPath2)}catch{}}catch{}return conflicts.push(file2),{acquired:!1,conflicts}}let lockPath=getLockFilePath(directory,file2),metaPath=getMetaPath(lockPath),meta3={originalPath:file2,laneId,taskId,agent,sessionID,acquiredAt:result.lock.timestamp,expiresAt:result.lock.expiresAt};try{await writeMetaFile(metaPath,meta3)}catch(err){for(let lock of acquiredLocks)try{if(lock._release)await lock._release();let lp=getLockFilePath(directory,lock.filePath),mp=getMetaPath(lp);try{fs11.unlinkSync(mp)}catch{}try{fs11.unlinkSync(lp)}catch{}}catch{}if(result.lock._release)await result.lock._release();try{fs11.unlinkSync(lockPath)}catch{}throw err}result.lock.laneId=laneId,acquiredLocks.push(result.lock)}return{acquired:!0,locks:acquiredLocks}}async function releaseLaneLocks(directory,laneId){let locksDir=path16.join(directory,LOCKS_DIR);if(!fs11.existsSync(locksDir))return 0;let files=fs11.readdirSync(locksDir),releasedCount=0;for(let file2 of files){if(!file2.endsWith(".meta"))continue;let metaPath=path16.join(locksDir,file2),meta3=readMetaFile(metaPath);if(!meta3||meta3.laneId!==laneId)continue;let lockPath=metaPath.replace(/\.meta$/,".lock");try{try{await import_proper_lockfile.default.unlock(lockPath,{realpath:!1})}catch{}try{fs11.unlinkSync(lockPath)}catch{}try{fs11.unlinkSync(metaPath)}catch{}releasedCount++}catch{}}return releasedCount}var import_proper_lockfile,LOCKS_DIR=".swarm/locks",LOCK_TIMEOUT_MS=300000,_internals12;var init_file_locks=__esm(()=>{import_proper_lockfile=__toESM(require_proper_lockfile(),1),_internals12={tryAcquireLock,writeFile:fs11.promises.writeFile}});function backoffMs(attempt){let base=Math.min(BACKOFF_START_MS*2**attempt,BACKOFF_MAX_MS),jitter=base*BACKOFF_JITTER_RATIO*(Math.random()*2-1);return Math.max(1,Math.round(base+jitter))}async function withEvidenceLock(directory,evidencePath,agent,taskId,fn2,timeoutMs=60000){let deadline=Date.now()+timeoutMs,attempt=0;while(!0){let result=await tryAcquireLock(directory,evidencePath,agent,taskId);if(result.acquired){let lock=result.lock;if(attempt>0)emit("evidence_lock_stale_recovered",{directory,evidencePath,agent,taskId,attempt});emit("evidence_lock_acquired",{directory,evidencePath,agent,taskId,attempt});try{return await fn2()}finally{if(lock._release)try{await lock._release()}catch{}}}if(Date.now()>=deadline)throw new EvidenceLockTimeoutError(directory,evidencePath,agent,taskId,timeoutMs);emit("evidence_lock_contended",{directory,evidencePath,agent,taskId,attempt});let delay=Math.min(backoffMs(attempt),deadline-Date.now());if(delay>0)await new Promise((resolve8)=>setTimeout(resolve8,delay));attempt++}}var EvidenceLockTimeoutError,BACKOFF_START_MS=50,BACKOFF_MAX_MS=2000,BACKOFF_JITTER_RATIO=0.25;var init_lock=__esm(()=>{init_file_locks();init_telemetry();EvidenceLockTimeoutError=class EvidenceLockTimeoutError extends Error{directory;evidencePath;agent;taskId;constructor(directory,evidencePath,agent,taskId,timeoutMs){super(`Evidence lock timeout after ${timeoutMs}ms for ${evidencePath} (agent=${agent}, task=${taskId})`);this.name="EvidenceLockTimeoutError",this.directory=directory,this.evidencePath=evidencePath,this.agent=agent,this.taskId=taskId}}});import{createHash as createHash4}from"node:crypto";function derivePlanId(plan){return`${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g,"_")}function derivePlanIdentityHash(plan){return createHash4("sha256").update(JSON.stringify([plan.swarm,plan.title]),"utf8").digest("hex")}var init_utils3=()=>{};import*as crypto5 from"node:crypto";import*as fs12 from"node:fs";import*as path17 from"node:path";function getLedgerPath(directory){return path17.join(directory,".swarm",LEDGER_FILENAME)}function getPlanJsonPath(directory){return path17.join(directory,".swarm",PLAN_JSON_FILENAME)}function writeFileFsyncedThenRename(tempPath,targetPath,data){let fd=fs12.openSync(tempPath,"w");try{fs12.writeFileSync(fd,data,"utf8"),fs12.fsyncSync(fd)}finally{fs12.closeSync(fd)}fs12.renameSync(tempPath,targetPath)}function computePlanHash(plan){let normalized={schema_version:plan.schema_version,title:plan.title,swarm:plan.swarm,current_phase:plan.current_phase,migration_status:plan.migration_status,execution_profile:plan.execution_profile,phases:plan.phases.map((phase)=>({id:phase.id,name:phase.name,status:phase.status,required_agents:phase.required_agents?[...phase.required_agents].sort():void 0,tasks:phase.tasks.map((task)=>({id:task.id,phase:task.phase,status:task.status,size:task.size,description:task.description,depends:[...task.depends].sort(),acceptance:task.acceptance,files_touched:[...task.files_touched].sort(),evidence_path:task.evidence_path,blocked_reason:task.blocked_reason}))}))},jsonString=JSON.stringify(normalized);return crypto5.createHash("sha256").update(jsonString,"utf8").digest("hex")}function computePlanStructureHash(plan){let normalized={schema_version:plan.schema_version,title:plan.title,swarm:plan.swarm,current_phase:plan.current_phase,migration_status:plan.migration_status,execution_profile:plan.execution_profile,phases:plan.phases.map((phase)=>({id:phase.id,name:phase.name,required_agents:phase.required_agents?[...phase.required_agents].sort():void 0,tasks:phase.tasks.map((task)=>({id:task.id,phase:task.phase,size:task.size,description:task.description,depends:[...task.depends].sort(),acceptance:task.acceptance,files_touched:[...task.files_touched].sort(),evidence_path:task.evidence_path,blocked_reason:task.blocked_reason}))}))},jsonString=JSON.stringify(normalized);return crypto5.createHash("sha256").update(jsonString,"utf8").digest("hex")}function computeCurrentPlanHash(directory){let planPath=getPlanJsonPath(directory);try{let content=fs12.readFileSync(planPath,"utf8"),plan=JSON.parse(content);return computePlanHash(plan)}catch{return""}}async function ledgerExists(directory){let ledgerPath=getLedgerPath(directory);return fs12.existsSync(ledgerPath)}async function getLatestLedgerSeq(directory){let ledgerPath=getLedgerPath(directory);if(!fs12.existsSync(ledgerPath))return 0;try{let lines=fs12.readFileSync(ledgerPath,"utf8").trim().split(`
239
239
  `).filter((line)=>line.trim()!=="");if(lines.length===0)return 0;let maxSeq=0;for(let line of lines)try{let event=JSON.parse(line);if(event.seq>maxSeq)maxSeq=event.seq}catch{}return maxSeq}catch{return 0}}async function readLedgerEvents(directory){let ledgerPath=getLedgerPath(directory);if(!fs12.existsSync(ledgerPath))return[];try{let lines=fs12.readFileSync(ledgerPath,"utf8").trim().split(`
240
- `).filter((line)=>line.trim()!==""),events=[],skippedCount=0;for(let line of lines)try{let event=JSON.parse(line);events.push(event)}catch{skippedCount++}if(skippedCount>0)console.warn(`[ledger] Skipped ${skippedCount} malformed line(s) in plan-ledger.jsonl`);return events.sort((a,b)=>a.seq-b.seq),events}catch{return[]}}async function initLedger(directory,planId,initialPlanHash,initialPlan){let ledgerPath=getLedgerPath(directory),planJsonPath=getPlanJsonPath(directory);if(fs12.existsSync(ledgerPath))throw Error("Ledger already initialized. Use appendLedgerEvent to add events.");let planHashAfter=initialPlanHash??"",embeddedPlan=initialPlan;if(!initialPlanHash)try{if(fs12.existsSync(planJsonPath)){let content=fs12.readFileSync(planJsonPath,"utf8"),plan=JSON.parse(content);if(planHashAfter=computePlanHash(plan),!embeddedPlan)embeddedPlan=plan}}catch{}let payload=embeddedPlan?{plan:embeddedPlan,payload_hash:planHashAfter}:void 0,event={seq:1,timestamp:new Date().toISOString(),plan_id:planId,event_type:"plan_created",source:"initLedger",plan_hash_before:"",plan_hash_after:planHashAfter,schema_version:LEDGER_SCHEMA_VERSION,...payload?{payload}:{}};fs12.mkdirSync(path17.join(directory,".swarm"),{recursive:!0});let tempPath=`${ledgerPath}.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`,line=`${JSON.stringify(event)}
240
+ `).filter((line)=>line.trim()!==""),events=[],skippedCount=0;for(let line of lines)try{let event=JSON.parse(line);events.push(event)}catch{skippedCount++}if(skippedCount>0)log(`[ledger] Skipped ${skippedCount} malformed line(s) in plan-ledger.jsonl`);return events.sort((a,b)=>a.seq-b.seq),events}catch{return[]}}async function initLedger(directory,planId,initialPlanHash,initialPlan){let ledgerPath=getLedgerPath(directory),planJsonPath=getPlanJsonPath(directory);if(fs12.existsSync(ledgerPath))throw Error("Ledger already initialized. Use appendLedgerEvent to add events.");let planHashAfter=initialPlanHash??"",embeddedPlan=initialPlan;if(!initialPlanHash)try{if(fs12.existsSync(planJsonPath)){let content=fs12.readFileSync(planJsonPath,"utf8"),plan=JSON.parse(content);if(planHashAfter=computePlanHash(plan),!embeddedPlan)embeddedPlan=plan}}catch{}let payload=embeddedPlan?{plan:embeddedPlan,payload_hash:planHashAfter}:void 0,event={seq:1,timestamp:new Date().toISOString(),plan_id:planId,event_type:"plan_created",source:"initLedger",plan_hash_before:"",plan_hash_after:planHashAfter,schema_version:LEDGER_SCHEMA_VERSION,...payload?{payload}:{}};fs12.mkdirSync(path17.join(directory,".swarm"),{recursive:!0});let tempPath=`${ledgerPath}.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`,line=`${JSON.stringify(event)}
241
241
  `;writeFileFsyncedThenRename(tempPath,ledgerPath,line)}async function appendLedgerEvent(directory,eventInput,options){return withEvidenceLock(directory,LEDGER_LOCK_PATH,"plan-ledger","append-ledger-event",async()=>{let ledgerPath=getLedgerPath(directory),latestSeq=await getLatestLedgerSeq(directory),nextSeq=latestSeq+1,planHashBefore=computeCurrentPlanHash(directory);if(options?.expectedSeq!==void 0&&options.expectedSeq!==latestSeq)throw new LedgerStaleWriterError(`Stale writer: expected seq ${options.expectedSeq} but found ${latestSeq}`);if(options?.expectedHash!==void 0&&options.expectedHash!==planHashBefore)throw new LedgerStaleWriterError(`Stale writer: expected hash ${options.expectedHash} but found ${planHashBefore}`);let planHashAfter=options?.planHashAfter??planHashBefore,event={...eventInput,seq:nextSeq,timestamp:new Date().toISOString(),plan_hash_before:planHashBefore,plan_hash_after:planHashAfter,schema_version:LEDGER_SCHEMA_VERSION};fs12.mkdirSync(path17.join(directory,".swarm"),{recursive:!0});let tempPath=`${ledgerPath}.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`,line=`${JSON.stringify(event)}
242
- `;if(!fs12.existsSync(ledgerPath))throw Error("Ledger not initialized. Call initLedger() first.");let existingContent=fs12.readFileSync(ledgerPath,"utf8");return writeFileFsyncedThenRename(tempPath,ledgerPath,existingContent+line),event})}async function takeSnapshotWithRetry(directory,plan,options){let telemetrySource=options?.source??"save_plan_tool",snapshotOptions={planHashAfter:options?.planHashAfter},lastError;for(let attempt=1;attempt<=4;attempt++)try{await takeSnapshotEvent(directory,plan,snapshotOptions);return}catch(err){if(lastError=err instanceof Error?err:Error(String(err)),attempt<4)await new Promise((r)=>setTimeout(r,10*2**(attempt-1)))}console.warn(`[takeSnapshotWithRetry] Snapshot failed after 3 retries (4 attempts): ${lastError.message}`);try{emit("snapshot_failed",{error:lastError.message,retries:3,source:telemetrySource})}catch{}}async function takeSnapshotEvent(directory,plan,options){let payloadHash=options?.payloadHashOverride??computePlanHash(plan),snapshotPayload={plan,payload_hash:payloadHash};if(options?.approvalMetadata)snapshotPayload.approval=options.approvalMetadata;let planId=derivePlanId(plan);return appendLedgerEvent(directory,{event_type:"snapshot",source:options?.source??"takeSnapshotEvent",plan_id:planId,payload:snapshotPayload},{planHashAfter:options?.planHashAfter})}async function replayFromLedger(directory,options){let{plan}=await replayFromLedgerWithStatus(directory,options);return plan}async function replayFromLedgerWithStatus(directory,_options){let{events,truncated,badSuffix}=await readLedgerEventsWithIntegrity(directory);if(events.length===0)return{plan:null,truncated,badSuffix};if(truncated&&badSuffix!==null)await quarantineLedgerSuffix(directory,badSuffix);return{plan:reconstructPlanFromEvents(directory,events),truncated,badSuffix}}function reconstructPlanFromEvents(directory,events){let targetPlanId=events[0].plan_id,relevantEvents=events.filter((e)=>e.plan_id===targetPlanId);{let snapshotEvents=relevantEvents.filter((e)=>e.event_type==="snapshot");if(snapshotEvents.length>0){let latestSnapshotEvent=snapshotEvents[snapshotEvents.length-1],plan2=latestSnapshotEvent.payload.plan,eventsAfterSnapshot=relevantEvents.filter((e)=>e.seq>latestSnapshotEvent.seq);for(let event of eventsAfterSnapshot)if(plan2=applyEventToPlan(plan2,event),plan2===null)return null;return plan2}}let createdEvent=relevantEvents.find((e)=>e.event_type==="plan_created");if(createdEvent?.payload&&typeof createdEvent.payload==="object"&&"plan"in createdEvent.payload){let parseResult=PlanSchema.safeParse(createdEvent.payload.plan);if(parseResult.success){let plan2=parseResult.data,eventsAfterCreated=relevantEvents.filter((e)=>e.seq>createdEvent.seq);for(let event of eventsAfterCreated){if(plan2===null)return null;plan2=applyEventToPlan(plan2,event)}return plan2}}let planJsonPath=getPlanJsonPath(directory);if(!fs12.existsSync(planJsonPath))return null;let plan;try{let content=fs12.readFileSync(planJsonPath,"utf8");plan=JSON.parse(content)}catch{return null}for(let event of relevantEvents){if(plan===null)return null;plan=applyEventToPlan(plan,event)}return plan}function applyEventToPlan(plan,event){switch(event.event_type){case"plan_created":if(event.payload&&typeof event.payload==="object"&&"plan"in event.payload){let parsed=PlanSchema.safeParse(event.payload.plan);if(parsed.success)return parsed.data}return plan;case"task_status_changed":if(event.task_id&&event.to_status){let parseResult=TaskStatusSchema.safeParse(event.to_status);if(!parseResult.success)return plan;for(let phase of plan.phases){let task=phase.tasks.find((t)=>t.id===event.task_id);if(task){task.status=parseResult.data;break}}}return plan;case"phase_completed":if(event.phase_id){let phase=plan.phases.find((p)=>p.id===event.phase_id);if(phase)phase.status="complete"}return plan;case"plan_exported":return plan;case"task_added":return plan;case"task_removed":if(event.task_id)for(let phase of plan.phases){let idx=phase.tasks.findIndex((t)=>t.id===event.task_id);if(idx!==-1){phase.tasks.splice(idx,1);break}}return plan;case"task_updated":return plan;case"plan_rebuilt":return plan;case"task_reordered":return plan;case"snapshot":return plan;case"plan_reset":return null;case"execution_profile_set":{let rawProfile=event.payload?.execution_profile;if(rawProfile!==void 0){let parsed=ExecutionProfileSchema.safeParse(rawProfile);if(parsed.success)return{...plan,execution_profile:parsed.data}}return plan}case"execution_profile_locked":{if(plan.execution_profile)return{...plan,execution_profile:{...plan.execution_profile,locked:!0}};return plan}default:throw Error(`applyEventToPlan: unhandled event type "${event.event_type}" at seq ${event.seq}`)}}async function readLedgerEventsWithIntegrity(directory){let ledgerPath=getLedgerPath(directory);if(!fs12.existsSync(ledgerPath))return{events:[],truncated:!1,badSuffix:null};try{let lines=fs12.readFileSync(ledgerPath,"utf8").split(`
242
+ `;if(!fs12.existsSync(ledgerPath))throw Error("Ledger not initialized. Call initLedger() first.");let existingContent=fs12.readFileSync(ledgerPath,"utf8");return writeFileFsyncedThenRename(tempPath,ledgerPath,existingContent+line),event})}async function takeSnapshotWithRetry(directory,plan,options){let telemetrySource=options?.source??"save_plan_tool",snapshotOptions={planHashAfter:options?.planHashAfter},lastError;for(let attempt=1;attempt<=4;attempt++)try{await takeSnapshotEvent(directory,plan,snapshotOptions);return}catch(err){if(lastError=err instanceof Error?err:Error(String(err)),attempt<4)await new Promise((r)=>setTimeout(r,10*2**(attempt-1)))}criticalWarn(`[takeSnapshotWithRetry] Snapshot failed after 3 retries (4 attempts): ${lastError.message}`);try{emit("snapshot_failed",{error:lastError.message,retries:3,source:telemetrySource})}catch{}}async function takeSnapshotEvent(directory,plan,options){let payloadHash=options?.payloadHashOverride??computePlanHash(plan),snapshotPayload={plan,payload_hash:payloadHash};if(options?.approvalMetadata)snapshotPayload.approval=options.approvalMetadata;let planId=derivePlanId(plan);return appendLedgerEvent(directory,{event_type:"snapshot",source:options?.source??"takeSnapshotEvent",plan_id:planId,payload:snapshotPayload},{planHashAfter:options?.planHashAfter})}async function replayFromLedger(directory,options){let{plan}=await replayFromLedgerWithStatus(directory,options);return plan}async function replayFromLedgerWithStatus(directory,_options){let{events,truncated,badSuffix}=await readLedgerEventsWithIntegrity(directory);if(events.length===0)return{plan:null,truncated,badSuffix};if(truncated&&badSuffix!==null)await quarantineLedgerSuffix(directory,badSuffix);return{plan:reconstructPlanFromEvents(directory,events),truncated,badSuffix}}function reconstructPlanFromEvents(directory,events){let targetPlanId=events[0].plan_id,relevantEvents=events.filter((e)=>e.plan_id===targetPlanId);{let snapshotEvents=relevantEvents.filter((e)=>e.event_type==="snapshot");if(snapshotEvents.length>0){let latestSnapshotEvent=snapshotEvents[snapshotEvents.length-1],plan2=latestSnapshotEvent.payload.plan,eventsAfterSnapshot=relevantEvents.filter((e)=>e.seq>latestSnapshotEvent.seq);for(let event of eventsAfterSnapshot)if(plan2=applyEventToPlan(plan2,event),plan2===null)return null;return plan2}}let createdEvent=relevantEvents.find((e)=>e.event_type==="plan_created");if(createdEvent?.payload&&typeof createdEvent.payload==="object"&&"plan"in createdEvent.payload){let parseResult=PlanSchema.safeParse(createdEvent.payload.plan);if(parseResult.success){let plan2=parseResult.data,eventsAfterCreated=relevantEvents.filter((e)=>e.seq>createdEvent.seq);for(let event of eventsAfterCreated){if(plan2===null)return null;plan2=applyEventToPlan(plan2,event)}return plan2}}let planJsonPath=getPlanJsonPath(directory);if(!fs12.existsSync(planJsonPath))return null;let plan;try{let content=fs12.readFileSync(planJsonPath,"utf8");plan=JSON.parse(content)}catch{return null}for(let event of relevantEvents){if(plan===null)return null;plan=applyEventToPlan(plan,event)}return plan}function applyEventToPlan(plan,event){switch(event.event_type){case"plan_created":if(event.payload&&typeof event.payload==="object"&&"plan"in event.payload){let parsed=PlanSchema.safeParse(event.payload.plan);if(parsed.success)return parsed.data}return plan;case"task_status_changed":if(event.task_id&&event.to_status){let parseResult=TaskStatusSchema.safeParse(event.to_status);if(!parseResult.success)return plan;for(let phase of plan.phases){let task=phase.tasks.find((t)=>t.id===event.task_id);if(task){task.status=parseResult.data;break}}}return plan;case"phase_completed":if(event.phase_id){let phase=plan.phases.find((p)=>p.id===event.phase_id);if(phase)phase.status="complete"}return plan;case"plan_exported":return plan;case"task_added":return plan;case"task_removed":if(event.task_id)for(let phase of plan.phases){let idx=phase.tasks.findIndex((t)=>t.id===event.task_id);if(idx!==-1){phase.tasks.splice(idx,1);break}}return plan;case"task_updated":return plan;case"plan_rebuilt":return plan;case"task_reordered":return plan;case"snapshot":return plan;case"plan_reset":return null;case"execution_profile_set":{let rawProfile=event.payload?.execution_profile;if(rawProfile!==void 0){let parsed=ExecutionProfileSchema.safeParse(rawProfile);if(parsed.success)return{...plan,execution_profile:parsed.data}}return plan}case"execution_profile_locked":{if(plan.execution_profile)return{...plan,execution_profile:{...plan.execution_profile,locked:!0}};return plan}default:throw Error(`applyEventToPlan: unhandled event type "${event.event_type}" at seq ${event.seq}`)}}async function readLedgerEventsWithIntegrity(directory){let ledgerPath=getLedgerPath(directory);if(!fs12.existsSync(ledgerPath))return{events:[],truncated:!1,badSuffix:null};try{let lines=fs12.readFileSync(ledgerPath,"utf8").split(`
243
243
  `),events=[],truncated=!1,badSuffix=null;for(let i=0;i<lines.length;i++){let line=lines[i];if(line.trim()==="")continue;try{let event=JSON.parse(line);events.push(event)}catch{truncated=!0,badSuffix=lines.slice(i).join(`
244
244
  `);break}}return events.sort((a,b)=>a.seq-b.seq),{events,truncated,badSuffix}}catch{return{events:[],truncated:!1,badSuffix:null}}}async function quarantineLedgerSuffix(directory,badSuffix){let salvagedCount=0;for(let line of badSuffix.split(`
245
- `)){if(line.trim()==="")continue;try{JSON.parse(line),salvagedCount++}catch{}}try{let hash3=crypto5.createHash("sha256").update(badSuffix,"utf8").digest("hex").slice(0,12),swarmDir=path17.join(directory,".swarm");try{let existing=fs12.readdirSync(swarmDir).filter((name)=>name.startsWith("plan-ledger.quarantine.")&&name.endsWith(`.${hash3}`));for(let name of existing){let existingPath=path17.join(swarmDir,name);if(fs12.readFileSync(existingPath,"utf8")===badSuffix)return{path:existingPath,salvagedCount}}}catch{}let quarantinePath=path17.join(swarmDir,`plan-ledger.quarantine.${Date.now()}.${hash3}`);return fs12.writeFileSync(quarantinePath,badSuffix,"utf8"),console.warn(`[ledger] Corrupted suffix quarantined to ${path17.relative(directory,quarantinePath)} (salvageable events: ${salvagedCount})`),{path:quarantinePath,salvagedCount}}catch{return{path:null,salvagedCount}}}async function loadLastApprovedPlan(directory,expectedPlanId){let events=await readLedgerEvents(directory);return findLastApprovedSnapshot(events,expectedPlanId)}async function loadLastPlanCriticApprovedSnapshot(directory,expectedPlanId){let events=await readLedgerEvents(directory);return findLastApprovedSnapshot(events,expectedPlanId,(payload)=>payload.approval?.source==="plan_critic_gate")}function findLastApprovedSnapshot(events,expectedPlanId,extraFilter){if(events.length===0)return null;for(let i=events.length-1;i>=0;i--){let event=events[i];if(event.event_type!=="snapshot")continue;if(event.source!=="critic_approved")continue;if(expectedPlanId!==void 0&&event.plan_id!==expectedPlanId)continue;let payload=event.payload;if(!payload||typeof payload!=="object"||!payload.plan)continue;if(expectedPlanId!==void 0){if(derivePlanId(payload.plan)!==expectedPlanId)continue}if(extraFilter&&!extraFilter(payload))continue;return{plan:payload.plan,seq:event.seq,timestamp:event.timestamp,approval:payload.approval,payloadHash:payload.payload_hash}}return null}var LEDGER_SCHEMA_VERSION="1.1.0",LEDGER_FILENAME="plan-ledger.jsonl",LEDGER_LOCK_PATH,PLAN_JSON_FILENAME="plan.json",LedgerStaleWriterError;var init_ledger=__esm(()=>{init_plan_schema();init_lock();init_telemetry();init_utils3();LEDGER_LOCK_PATH=path17.join(".swarm",LEDGER_FILENAME);LedgerStaleWriterError=class LedgerStaleWriterError extends Error{constructor(message){super(message);this.name="LedgerStaleWriterError"}}});import{closeSync as closeSync2,copyFileSync,existsSync as existsSync11,fsyncSync as fsyncSync2,mkdirSync as mkdirSync8,openSync as openSync2,readdirSync as readdirSync4,renameSync as renameSync6,unlinkSync as unlinkSync4,writeFileSync as writeFileSync8}from"node:fs";import*as fsPromises3 from"node:fs/promises";import*as path18 from"node:path";function derivePhaseStatusesInPlace(plan){for(let phase of plan.phases){let tasks=phase.tasks;if(tasks.length>0&&tasks.every((t)=>t.status==="completed"))phase.status="complete";else if(tasks.some((t)=>t.status==="in_progress"))phase.status="in_progress";else if(tasks.some((t)=>t.status==="blocked"))phase.status="blocked";else phase.status="pending"}}function statusRank(s){switch(s){case"closed":return 5;case"completed":return 4;case"blocked":return 3;case"in_progress":return 2;case"pending":return 1;default:return 0}}function mergeStatusesTakingPrecedence(validated,replayed,ledgerStatusTaskIds){let projected=structuredClone(validated),replayedByTaskId=new Map;for(let phase of replayed.phases)for(let task of phase.tasks)if(ledgerStatusTaskIds.has(task.id))replayedByTaskId.set(task.id,task.status);for(let phase of projected.phases)for(let task of phase.tasks){let replayedStatus=replayedByTaskId.get(task.id);if(replayedStatus&&statusRank(replayedStatus)>statusRank(task.status))task.status=replayedStatus}return derivePhaseStatusesInPlace(projected),projected}function collectLedgerStatusTaskIds(events){let statusTaskIds=new Set;for(let event of events)if(event.event_type==="task_status_changed"&&typeof event.task_id==="string")statusTaskIds.add(event.task_id);return statusTaskIds}async function retryCasWithBackoff(directory,eventInput,options){let maxRetries=options.maxRetries??CAS_MAX_RETRIES,currentExpected=options.expectedHash,attempt=0;while(!0)try{return await appendLedgerEvent(directory,eventInput,{expectedHash:currentExpected,planHashAfter:options.planHashAfter})}catch(error49){if(!(error49 instanceof LedgerStaleWriterError)||attempt>=maxRetries)throw error49;attempt++;let base=Math.min(CAS_BACKOFF_START_MS*2**(attempt-1),CAS_BACKOFF_CAP_MS),jitter=base*CAS_BACKOFF_JITTER*(Math.random()*2-1),delayMs=Math.max(1,Math.round(base+jitter));if(emit("plan_ledger_cas_retry",{attempt,expectedHashPrefix:currentExpected.slice(0,8),delayMs}),await new Promise((resolve9)=>setTimeout(resolve9,delayMs)),options.verifyValid){if(!await options.verifyValid())return null}currentExpected=computeCurrentPlanHash(directory)}}async function loadPlanJsonOnly(directory){try{return await parsePlanJsonCached(directory)}catch(error49){warn(`Plan validation failed for .swarm/plan.json: ${error49 instanceof Error?error49.message:String(error49)}`)}return null}function compareTaskIds(a,b){let partsA=a.split(".").map((n)=>parseInt(n,10)),partsB=b.split(".").map((n)=>parseInt(n,10)),maxLen=Math.max(partsA.length,partsB.length);for(let i=0;i<maxLen;i++){let numA=partsA[i]??0,numB=partsB[i]??0;if(numA!==numB)return numA-numB}return 0}async function getLatestLedgerHash(directory){try{let events=await readLedgerEvents(directory);if(events.length===0)return"";return events[events.length-1].plan_hash_after}catch{return""}}async function surfaceLedgerStaleIfPersisted(directory,plan){let resolvedWorkspace=path18.resolve(directory);if(!ledgerStaleWorkspaces.has(resolvedWorkspace))return plan;try{let planHash=computePlanHash(plan),ledgerHash=await getLatestLedgerHash(directory);if(ledgerHash!==""&&planHash===ledgerHash)return ledgerStaleWorkspaces.delete(resolvedWorkspace),plan}catch{}if(plan._ledgerReplayStale=!0,typeof plan._ledgerReplayStaleReason!=="string"||plan._ledgerReplayStaleReason.length===0)plan._ledgerReplayStaleReason="plan.json still hash-mismatches the ledger after a startup ledger-replay failure (replay could not be applied and no critic-approved snapshot was available). Run /swarm reset-session if this persists.";return plan}async function parsePlanJsonCached(directory){let planJsonPath=path18.resolve(directory,".swarm","plan.json");return readCachedParsedFile(planJsonPath,PLAN_JSON_CACHE_NAMESPACE,()=>readSwarmFileAsync(directory,"plan.json"),(planJsonContent)=>{if(planJsonContent.includes("\x00")||planJsonContent.includes("�"))throw Error("Plan rejected: .swarm/plan.json contains null bytes or invalid encoding");let parsed=JSON.parse(planJsonContent);return PlanSchema.parse(parsed)})}function computePlanContentHash(plan){let content={schema_version:plan.schema_version,title:plan.title,swarm:plan.swarm,current_phase:plan.current_phase,migration_status:plan.migration_status,phases:plan.phases.map((phase)=>({id:phase.id,name:phase.name,status:phase.status,tasks:phase.tasks.map((task)=>({id:task.id,phase:task.phase,status:task.status,size:task.size,description:task.description,depends:[...task.depends].sort(compareTaskIds),acceptance:task.acceptance,files_touched:[...task.files_touched].sort(),evidence_path:task.evidence_path,blocked_reason:task.blocked_reason})).sort((a,b)=>compareTaskIds(a.id,b.id))})).sort((a,b)=>a.id-b.id)},jsonString=JSON.stringify(content);return bunHash(jsonString).toString(36)}function extractPlanHashFromMarkdown(markdown){let match=markdown.match(/<!--\s*PLAN_HASH:\s*(\S+)\s*-->/);return match?match[1]:null}async function isPlanMdInSync(directory,plan,cache){let planMdContent=await readSwarmFileAsync(directory,"plan.md",cache);if(planMdContent===null)return!1;let expectedHash=computePlanContentHash(plan);if(extractPlanHashFromMarkdown(planMdContent)===expectedHash)return!0;let normalizedExpected=derivePlanMarkdown(plan).trim();if(planMdContent.trim()===normalizedExpected)return!0;return!1}async function regeneratePlanMarkdown(directory,plan){let swarmDir=path18.resolve(directory,".swarm"),contentHash=computePlanContentHash(plan),markdown=derivePlanMarkdown(plan),markdownWithHash=`<!-- PLAN_HASH: ${contentHash} -->
245
+ `)){if(line.trim()==="")continue;try{JSON.parse(line),salvagedCount++}catch{}}try{let hash3=crypto5.createHash("sha256").update(badSuffix,"utf8").digest("hex").slice(0,12),swarmDir=path17.join(directory,".swarm");try{let existing=fs12.readdirSync(swarmDir).filter((name)=>name.startsWith("plan-ledger.quarantine.")&&name.endsWith(`.${hash3}`));for(let name of existing){let existingPath=path17.join(swarmDir,name);if(fs12.readFileSync(existingPath,"utf8")===badSuffix)return{path:existingPath,salvagedCount}}}catch{}let quarantinePath=path17.join(swarmDir,`plan-ledger.quarantine.${Date.now()}.${hash3}`);return fs12.writeFileSync(quarantinePath,badSuffix,"utf8"),log(`[ledger] Corrupted suffix quarantined to ${path17.relative(directory,quarantinePath)} (salvageable events: ${salvagedCount})`),{path:quarantinePath,salvagedCount}}catch{return{path:null,salvagedCount}}}async function loadLastApprovedPlan(directory,expectedPlanId){let events=await readLedgerEvents(directory);return findLastApprovedSnapshot(events,expectedPlanId)}async function loadLastPlanCriticApprovedSnapshot(directory,expectedPlanId){let events=await readLedgerEvents(directory);return findLastApprovedSnapshot(events,expectedPlanId,(payload)=>payload.approval?.source==="plan_critic_gate")}function findLastApprovedSnapshot(events,expectedPlanId,extraFilter){if(events.length===0)return null;for(let i=events.length-1;i>=0;i--){let event=events[i];if(event.event_type!=="snapshot")continue;if(event.source!=="critic_approved")continue;if(expectedPlanId!==void 0&&event.plan_id!==expectedPlanId)continue;let payload=event.payload;if(!payload||typeof payload!=="object"||!payload.plan)continue;if(expectedPlanId!==void 0){if(derivePlanId(payload.plan)!==expectedPlanId)continue}if(extraFilter&&!extraFilter(payload))continue;return{plan:payload.plan,seq:event.seq,timestamp:event.timestamp,approval:payload.approval,payloadHash:payload.payload_hash}}return null}var LEDGER_SCHEMA_VERSION="1.1.0",LEDGER_FILENAME="plan-ledger.jsonl",LEDGER_LOCK_PATH,PLAN_JSON_FILENAME="plan.json",LedgerStaleWriterError;var init_ledger=__esm(()=>{init_plan_schema();init_lock();init_telemetry();init_logger();init_utils3();LEDGER_LOCK_PATH=path17.join(".swarm",LEDGER_FILENAME);LedgerStaleWriterError=class LedgerStaleWriterError extends Error{constructor(message){super(message);this.name="LedgerStaleWriterError"}}});import{closeSync as closeSync2,copyFileSync,existsSync as existsSync11,fsyncSync as fsyncSync2,mkdirSync as mkdirSync8,openSync as openSync2,readdirSync as readdirSync4,renameSync as renameSync6,unlinkSync as unlinkSync4,writeFileSync as writeFileSync8}from"node:fs";import*as fsPromises3 from"node:fs/promises";import*as path18 from"node:path";function derivePhaseStatusesInPlace(plan){for(let phase of plan.phases){let tasks=phase.tasks;if(tasks.length>0&&tasks.every((t)=>t.status==="completed"))phase.status="complete";else if(tasks.some((t)=>t.status==="in_progress"))phase.status="in_progress";else if(tasks.some((t)=>t.status==="blocked"))phase.status="blocked";else phase.status="pending"}}function statusRank(s){switch(s){case"closed":return 5;case"completed":return 4;case"blocked":return 3;case"in_progress":return 2;case"pending":return 1;default:return 0}}function mergeStatusesTakingPrecedence(validated,replayed,ledgerStatusTaskIds){let projected=structuredClone(validated),replayedByTaskId=new Map;for(let phase of replayed.phases)for(let task of phase.tasks)if(ledgerStatusTaskIds.has(task.id))replayedByTaskId.set(task.id,task.status);for(let phase of projected.phases)for(let task of phase.tasks){let replayedStatus=replayedByTaskId.get(task.id);if(replayedStatus&&statusRank(replayedStatus)>statusRank(task.status))task.status=replayedStatus}return derivePhaseStatusesInPlace(projected),projected}function collectLedgerStatusTaskIds(events){let statusTaskIds=new Set;for(let event of events)if(event.event_type==="task_status_changed"&&typeof event.task_id==="string")statusTaskIds.add(event.task_id);return statusTaskIds}async function retryCasWithBackoff(directory,eventInput,options){let maxRetries=options.maxRetries??CAS_MAX_RETRIES,currentExpected=options.expectedHash,attempt=0;while(!0)try{return await appendLedgerEvent(directory,eventInput,{expectedHash:currentExpected,planHashAfter:options.planHashAfter})}catch(error49){if(!(error49 instanceof LedgerStaleWriterError)||attempt>=maxRetries)throw error49;attempt++;let base=Math.min(CAS_BACKOFF_START_MS*2**(attempt-1),CAS_BACKOFF_CAP_MS),jitter=base*CAS_BACKOFF_JITTER*(Math.random()*2-1),delayMs=Math.max(1,Math.round(base+jitter));if(emit("plan_ledger_cas_retry",{attempt,expectedHashPrefix:currentExpected.slice(0,8),delayMs}),await new Promise((resolve9)=>setTimeout(resolve9,delayMs)),options.verifyValid){if(!await options.verifyValid())return null}currentExpected=computeCurrentPlanHash(directory)}}async function loadPlanJsonOnly(directory){try{return await parsePlanJsonCached(directory)}catch(error49){warn(`Plan validation failed for .swarm/plan.json: ${error49 instanceof Error?error49.message:String(error49)}`)}return null}function compareTaskIds(a,b){let partsA=a.split(".").map((n)=>parseInt(n,10)),partsB=b.split(".").map((n)=>parseInt(n,10)),maxLen=Math.max(partsA.length,partsB.length);for(let i=0;i<maxLen;i++){let numA=partsA[i]??0,numB=partsB[i]??0;if(numA!==numB)return numA-numB}return 0}async function getLatestLedgerHash(directory){try{let events=await readLedgerEvents(directory);if(events.length===0)return"";return events[events.length-1].plan_hash_after}catch{return""}}async function surfaceLedgerStaleIfPersisted(directory,plan){let resolvedWorkspace=path18.resolve(directory);if(!ledgerStaleWorkspaces.has(resolvedWorkspace))return plan;try{let planHash=computePlanHash(plan),ledgerHash=await getLatestLedgerHash(directory);if(ledgerHash!==""&&planHash===ledgerHash)return ledgerStaleWorkspaces.delete(resolvedWorkspace),plan}catch{}if(plan._ledgerReplayStale=!0,typeof plan._ledgerReplayStaleReason!=="string"||plan._ledgerReplayStaleReason.length===0)plan._ledgerReplayStaleReason="plan.json still hash-mismatches the ledger after a startup ledger-replay failure (replay could not be applied and no critic-approved snapshot was available). Run /swarm reset-session if this persists.";return plan}async function parsePlanJsonCached(directory){let planJsonPath=path18.resolve(directory,".swarm","plan.json");return readCachedParsedFile(planJsonPath,PLAN_JSON_CACHE_NAMESPACE,()=>readSwarmFileAsync(directory,"plan.json"),(planJsonContent)=>{if(planJsonContent.includes("\x00")||planJsonContent.includes("�"))throw Error("Plan rejected: .swarm/plan.json contains null bytes or invalid encoding");let parsed=JSON.parse(planJsonContent);return PlanSchema.parse(parsed)})}function computePlanContentHash(plan){let content={schema_version:plan.schema_version,title:plan.title,swarm:plan.swarm,current_phase:plan.current_phase,migration_status:plan.migration_status,phases:plan.phases.map((phase)=>({id:phase.id,name:phase.name,status:phase.status,tasks:phase.tasks.map((task)=>({id:task.id,phase:task.phase,status:task.status,size:task.size,description:task.description,depends:[...task.depends].sort(compareTaskIds),acceptance:task.acceptance,files_touched:[...task.files_touched].sort(),evidence_path:task.evidence_path,blocked_reason:task.blocked_reason})).sort((a,b)=>compareTaskIds(a.id,b.id))})).sort((a,b)=>a.id-b.id)},jsonString=JSON.stringify(content);return bunHash(jsonString).toString(36)}function extractPlanHashFromMarkdown(markdown){let match=markdown.match(/<!--\s*PLAN_HASH:\s*(\S+)\s*-->/);return match?match[1]:null}async function isPlanMdInSync(directory,plan,cache){let planMdContent=await readSwarmFileAsync(directory,"plan.md",cache);if(planMdContent===null)return!1;let expectedHash=computePlanContentHash(plan);if(extractPlanHashFromMarkdown(planMdContent)===expectedHash)return!0;let normalizedExpected=derivePlanMarkdown(plan).trim();if(planMdContent.trim()===normalizedExpected)return!0;return!1}async function regeneratePlanMarkdown(directory,plan){let swarmDir=path18.resolve(directory,".swarm"),contentHash=computePlanContentHash(plan),markdown=derivePlanMarkdown(plan),markdownWithHash=`<!-- PLAN_HASH: ${contentHash} -->
246
246
  ${markdown}`,mdPath=path18.join(swarmDir,"plan.md"),mdTempPath=path18.join(swarmDir,`plan.md.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`);try{await bunWrite(mdTempPath,markdownWithHash),renameSync6(mdTempPath,mdPath)}finally{try{unlinkSync4(mdTempPath)}catch{}}}async function loadPlan(directory,cache){let planJsonContent=await readSwarmFileAsync(directory,"plan.json",cache);if(planJsonContent!==null)if(planJsonContent.includes("\x00")||planJsonContent.includes("�"))warn("Plan rejected: .swarm/plan.json contains null bytes or invalid encoding");else try{let validated=await parsePlanJsonCached(directory);if(validated===null)warn("[loadPlan] plan.json disappeared during cached parse. Falling back to plan.md migration or ledger recovery.");else{if(!await isPlanMdInSync(directory,validated,cache))try{await _internals13.regeneratePlanMarkdown(directory,validated)}catch(regenError){warn(`Failed to regenerate plan.md: ${regenError instanceof Error?regenError.message:String(regenError)}. Proceeding with plan.json only.`)}if(await ledgerExists(directory)){let planHash=computePlanHash(validated),ledgerHash=await getLatestLedgerHash(directory),resolvedWorkspace=path18.resolve(directory);if(!startupLedgerCheckedWorkspaces.has(resolvedWorkspace)){if(startupLedgerCheckedWorkspaces.add(resolvedWorkspace),ledgerHash!==""&&planHash!==ledgerHash){let currentPlanId=derivePlanId(validated),ledgerEvents=await readLedgerEvents(directory),firstEvent=ledgerEvents.length>0?ledgerEvents[0]:null;if(firstEvent&&firstEvent.plan_id!==currentPlanId)warn(`[loadPlan] Ledger identity mismatch (ledger: ${firstEvent.plan_id}, plan: ${currentPlanId}) — skipping ledger rebuild (migration detected). Use /swarm reset-session to reinitialize the ledger.`);else{warn("[loadPlan] plan.json is stale (hash mismatch with ledger) — rebuilding from ledger. If this recurs, run /swarm reset-session to clear stale session state.");try{let{plan:rebuilt,truncated}=await replayFromLedgerWithStatus(directory);if(truncated){let runtimeStale=validated;return runtimeStale._ledgerReplayStale=!0,runtimeStale._ledgerReplayStaleReason="Ledger truncated: a malformed line stopped replay before the tail, so the ledger could only be reconstructed up to the corruption. plan.json was PRESERVED (not rolled back to the prefix-only projection) and the corrupted suffix was quarantined to .swarm/plan-ledger.quarantine.*. Verify state, then run /swarm reset-session if this persists.",ledgerStaleWorkspaces.add(resolvedWorkspace),criticalWarn("[loadPlan] Ledger truncated (poison line detected) — preserving plan.json instead of rolling back to the prefix-only ledger projection. Durable post-poison events remain in plan.json. Corrupted suffix quarantined to .swarm/plan-ledger.quarantine.*. Run /swarm reset-session after verifying state if this persists."),runtimeStale}if(rebuilt)return await rebuildPlan(directory,rebuilt,{reason:"ledger_hash_mismatch_recovery"}),warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at .swarm/plan-export/SWARM_PLAN.md if it exists."),rebuilt}catch(replayError){try{let approved=await loadLastApprovedPlan(directory,currentPlanId);if(approved){await rebuildPlan(directory,approved.plan,{reason:"approved_snapshot_fallback"});try{await takeSnapshotEvent(directory,approved.plan,{source:"recovery_from_approved_snapshot",approvalMetadata:approved.approval})}catch(healError){warn(`[loadPlan] Recovery-heal snapshot append failed: ${healError instanceof Error?healError.message:String(healError)}. Next loadPlan may re-enter recovery path.`)}let approvedPhase=approved.approval&&typeof approved.approval==="object"&&"phase"in approved.approval?approved.approval.phase:void 0;return warn(`[loadPlan] Ledger replay failed (${replayError instanceof Error?replayError.message:String(replayError)}) — recovered from critic-approved snapshot seq=${approved.seq} (approval phase=${approvedPhase??"unknown"}, timestamp=${approved.timestamp}). This may roll the plan back to an earlier phase — verify before continuing.`),approved.plan}}catch{}{let runtimeStale=validated;runtimeStale._ledgerReplayStale=!0,runtimeStale._ledgerReplayStaleReason=`Ledger replay failed during hash-mismatch rebuild and no approved snapshot was available: ${replayError instanceof Error?replayError.message:String(replayError)}`,ledgerStaleWorkspaces.add(resolvedWorkspace)}warn(`[loadPlan] Ledger replay failed during hash-mismatch rebuild: ${replayError instanceof Error?replayError.message:String(replayError)}. Returning stale plan.json. To recover: check .swarm/plan-export/SWARM_PLAN.md for a checkpoint, or run /swarm reset-session.`)}}}}else if(ledgerHash!==""&&planHash!==ledgerHash){if(process.env.DEBUG_SWARM)console.warn(`[loadPlan] Ledger hash mismatch during active session for ${resolvedWorkspace} — skipping rebuild (startup check already performed).`)}}if(validated.specHash){let staleResult=await isSpecStale(directory,validated);if(staleResult.stale){let runtimePlan=validated;if(runtimePlan._specStale=!0,runtimePlan._specStaleReason=staleResult.reason,!await isObligationPreserving(directory)){try{let diffInfo=computeSpecDiff(directory),specStalenessPath=path18.join(directory,".swarm","spec-staleness.json");await fsPromises3.writeFile(specStalenessPath,JSON.stringify({type:"spec_stale_detected",timestamp:new Date().toISOString(),phase:validated.current_phase??1,specHash_plan:validated.specHash,specHash_current:staleResult.currentHash??null,reason:staleResult.reason,planTitle:validated.title,diff:diffInfo?.diff??null,changedSections:diffInfo?.changedSections??[]},null,2),"utf-8")}catch{}try{let eventsPath=path18.join(directory,".swarm","events.jsonl"),event={type:"spec_stale_detected",timestamp:new Date().toISOString(),phase:validated.current_phase??1,specHash_plan:validated.specHash,specHash_current:staleResult.currentHash??null,reason:staleResult.reason??"unknown",planTitle:validated.title};await fsPromises3.appendFile(eventsPath,`${JSON.stringify(event)}
247
247
  `,"utf-8")}catch{}}}}return await surfaceLedgerStaleIfPersisted(directory,validated)}}catch(error49){warn(`[loadPlan] plan.json validation failed: ${error49 instanceof Error?error49.message:String(error49)}. Attempting rebuild from ledger. If rebuild fails, check .swarm/plan-export/SWARM_PLAN.md for a checkpoint.`);let rawPlanId=null;try{let rawParsed=JSON.parse(planJsonContent);if(typeof rawParsed?.swarm==="string"&&typeof rawParsed?.title==="string")rawPlanId=derivePlanId(rawParsed)}catch{}if(await ledgerExists(directory)){let ledgerEventsForCatch=await readLedgerEvents(directory),catchFirstEvent=ledgerEventsForCatch.length>0?ledgerEventsForCatch[0]:null;if(!(rawPlanId===null||catchFirstEvent===null||catchFirstEvent.plan_id===rawPlanId))warn(`[loadPlan] Ledger identity mismatch in validation-failure path (ledger: ${catchFirstEvent?.plan_id}, plan: ${rawPlanId}) — skipping ledger rebuild (migration detected).`);else if(catchFirstEvent!==null&&rawPlanId!==null){let rebuilt=await replayFromLedger(directory);if(rebuilt)return await rebuildPlan(directory,rebuilt,{reason:"validation_failure_recovery"}),warn("[loadPlan] Rebuilt plan from ledger after validation failure. Projection was stale."),rebuilt}}let planMdContent2=await readSwarmFileAsync(directory,"plan.md",cache);if(planMdContent2!==null){let migrated=migrateLegacyPlan(planMdContent2),{removedCount}=await savePlanWithAutoAcknowledgedRemovals(directory,migrated,"load_plan_migration_from_md","migrate legacy plan.md to plan.json");if(removedCount>0)migrated._midLoadRemovals={count:removedCount,source:"load_plan_migration_from_md"};return migrated}}let planMdContent=await readSwarmFileAsync(directory,"plan.md",cache);if(planMdContent!==null){let migrated=migrateLegacyPlan(planMdContent);return await savePlan(directory,migrated),migrated}if(await ledgerExists(directory)){let resolvedDir=path18.resolve(directory),existingMutex=recoveryMutexes.get(resolvedDir);if(existingMutex){await existingMutex;let postRecoveryPlan=await _internals13.loadPlanJsonOnly(directory);if(postRecoveryPlan)return postRecoveryPlan}let resolveRecovery,mutex=new Promise((r)=>{resolveRecovery=r});recoveryMutexes.set(resolvedDir,mutex);try{let rebuilt=await replayFromLedger(directory);if(rebuilt){let{removedCount}=await savePlanWithAutoAcknowledgedRemovals(directory,rebuilt,"load_plan_rebuild_from_ledger","rebuild plan from ledger replay");if(removedCount>0)rebuilt._midLoadRemovals={count:removedCount,source:"load_plan_rebuild_from_ledger"};return rebuilt}try{let anchorEvents=await readLedgerEvents(directory);if(anchorEvents.length===0)return warn("[loadPlan] Ledger present but no events readable — refusing approved-snapshot recovery (cannot verify plan identity)."),null;let expectedPlanId=anchorEvents[0].plan_id,approved=await loadLastApprovedPlan(directory,expectedPlanId);if(approved){let approvedPhase=approved.approval&&typeof approved.approval==="object"&&"phase"in approved.approval?approved.approval.phase:void 0;warn(`[loadPlan] Ledger replay returned no plan — recovered from critic-approved snapshot seq=${approved.seq} timestamp=${approved.timestamp} (approval phase=${approvedPhase??"unknown"}). This may roll the plan back to an earlier phase — verify before continuing.`);let{removedCount:snapshotRemovedCount}=await savePlanWithAutoAcknowledgedRemovals(directory,approved.plan,"load_plan_recovery_from_approved_snapshot","restore from critic-approved snapshot");if(snapshotRemovedCount>0)approved.plan._midLoadRemovals={count:snapshotRemovedCount,source:"load_plan_recovery_from_approved_snapshot"};try{await takeSnapshotEvent(directory,approved.plan,{source:"recovery_from_approved_snapshot",approvalMetadata:approved.approval})}catch(healError){warn(`[loadPlan] Recovery-heal snapshot append failed: ${healError instanceof Error?healError.message:String(healError)}. Next loadPlan may re-enter recovery path.`)}return approved.plan}}catch(recoveryError){warn(`[loadPlan] Approved-snapshot recovery failed: ${recoveryError instanceof Error?recoveryError.message:String(recoveryError)}`)}}finally{resolveRecovery(),recoveryMutexes.delete(resolvedDir)}}return null}async function savePlanWithAutoAcknowledgedRemovals(directory,plan,source,reason,options){let existing=await _internals13.loadPlanJsonOnly(directory),newIds=new Set;for(let phase of plan.phases)for(let task of phase.tasks)newIds.add(task.id);let removedIds=[];if(existing){for(let phase of existing.phases)for(let task of phase.tasks)if(!newIds.has(task.id))removedIds.push(task.id)}return await savePlan(directory,plan,{...options??{},acknowledged_removals:{ids:removedIds,reason,source}}),{removedCount:removedIds.length}}async function savePlan(directory,plan,options){if(directory===null||directory===void 0||typeof directory!=="string"||directory.trim().length===0)throw Error("Invalid directory: directory must be a non-empty string");let validated=PlanSchema.parse(plan);if(options?.preserveCompletedStatuses!==!1)try{let currentPlan2=await _internals13.loadPlanJsonOnly(directory);if(currentPlan2){let completedTaskIds=new Set;for(let phase of currentPlan2.phases)for(let task of phase.tasks)if(task.status==="completed")completedTaskIds.add(task.id);if(completedTaskIds.size>0){for(let phase of validated.phases)for(let task of phase.tasks)if(completedTaskIds.has(task.id)&&task.status!=="completed")task.status="completed"}}}catch{}derivePhaseStatusesInPlace(validated);let currentPlan=await _internals13.loadPlanJsonOnly(directory),planId=derivePlanId(validated),planHashForInit=computePlanHash(validated);if(!await ledgerExists(directory))try{await initLedger(directory,planId,planHashForInit,validated)}catch(initErr){let msg=initErr instanceof Error?initErr.message:String(initErr);if(!/already initialized/i.test(msg))throw initErr}else{let existingEvents=await readLedgerEvents(directory);if(existingEvents.length>0&&existingEvents[0].plan_id!==planId){let swarmDir2=path18.resolve(directory,".swarm"),oldLedgerPath=path18.join(swarmDir2,"plan-ledger.jsonl"),oldLedgerBackupPath=path18.join(swarmDir2,`plan-ledger.backup-${Date.now()}-${Math.floor(Math.random()*1e9)}.jsonl`),backupExists=!1;if(existsSync11(oldLedgerPath))try{renameSync6(oldLedgerPath,oldLedgerBackupPath),backupExists=!0}catch(renameErr){throw Error(`[savePlan] Cannot reinitialize ledger: could not move old ledger aside (rename failed: ${renameErr instanceof Error?renameErr.message:String(renameErr)}). The existing ledger has plan_id="${existingEvents[0].plan_id}" which does not match the current plan="${planId}". To proceed, close any programs that may have the ledger file open, or run /swarm reset-session to clear the ledger.`)}let initSucceeded=!1;if(backupExists)try{await initLedger(directory,planId,planHashForInit,validated),initSucceeded=!0}catch(initErr){if(String(initErr).includes("already initialized"))try{if(existsSync11(oldLedgerBackupPath))unlinkSync4(oldLedgerBackupPath)}catch{}else{if(existsSync11(oldLedgerBackupPath))try{renameSync6(oldLedgerBackupPath,oldLedgerPath)}catch{copyFileSync(oldLedgerBackupPath,oldLedgerPath);try{unlinkSync4(oldLedgerBackupPath)}catch{}}throw initErr}}if(initSucceeded&&backupExists){let archivePath=path18.join(swarmDir2,`plan-ledger.archived-${Date.now()}-${Math.floor(Math.random()*1e9)}.jsonl`);try{renameSync6(oldLedgerBackupPath,archivePath),warn(`[savePlan] Ledger identity mismatch (was "${existingEvents[0].plan_id}", now "${planId}") — archived old ledger to ${archivePath} and reinitializing.`)}catch(renameErr){warn(`[savePlan] Could not archive old ledger (rename failed: ${renameErr instanceof Error?renameErr.message:String(renameErr)}). Old ledger may still exist at ${oldLedgerBackupPath}.`);try{if(existsSync11(oldLedgerBackupPath))unlinkSync4(oldLedgerBackupPath)}catch{}}}else if(!initSucceeded&&backupExists)try{if(existsSync11(oldLedgerBackupPath))unlinkSync4(oldLedgerBackupPath)}catch{}let MAX_ARCHIVED_SIBLINGS=5;try{let archivedSiblings=readdirSync4(swarmDir2).filter((f)=>f.startsWith("plan-ledger.archived-")&&f.endsWith(".jsonl")).sort();if(archivedSiblings.length>MAX_ARCHIVED_SIBLINGS){let toRemove=archivedSiblings.slice(0,archivedSiblings.length-MAX_ARCHIVED_SIBLINGS);for(let file2 of toRemove)try{unlinkSync4(path18.join(swarmDir2,file2))}catch{}}}catch{}}}let currentHash=computeCurrentPlanHash(directory),hashAfter=computePlanHash(validated);if(currentPlan){let oldTaskMap=new Map;for(let phase of currentPlan.phases)for(let task of phase.tasks)oldTaskMap.set(task.id,{phase:task.phase,status:task.status});let newTaskIds=new Set;for(let phase of validated.phases)for(let task of phase.tasks)newTaskIds.add(task.id);let missingTasks=[];for(let[id,info]of oldTaskMap.entries())if(!newTaskIds.has(id))missingTasks.push({id,phase:info.phase,status:info.status});let ack=options?.acknowledged_removals;if(missingTasks.length>0){if(!ack)throw new PlanTaskRemovalNotAcknowledgedError(missingTasks);if(typeof ack.reason!=="string"||ack.reason.trim().length===0)throw Error("PLAN_ACKNOWLEDGED_REMOVAL_INVALID: acknowledged_removals.reason must be a non-empty string.");if(typeof ack.source!=="string"||ack.source.trim().length===0)throw Error("PLAN_ACKNOWLEDGED_REMOVAL_INVALID: acknowledged_removals.source must be a non-empty string.");let ackSet=new Set(ack.ids),missingIdsSet=new Set(missingTasks.map((t)=>t.id)),unacked=missingTasks.filter((t)=>!ackSet.has(t.id));if(unacked.length>0)throw new PlanTaskRemovalNotAcknowledgedError(unacked);for(let id of ack.ids)if(!missingIdsSet.has(id))throw Error(`PLAN_ACKNOWLEDGED_REMOVAL_INVALID: acknowledged_removals contains "${id}" but that task is not missing from the plan.`);try{for(let missing of missingTasks){let eventInput={plan_id:derivePlanId(validated),event_type:"task_removed",task_id:missing.id,phase_id:missing.phase,from_status:missing.status,source:ack.source,payload:{reason:ack.reason,source:ack.source}},capturedTaskId=missing.id;await retryCasWithBackoff(directory,eventInput,{expectedHash:currentHash,planHashAfter:hashAfter,verifyValid:async()=>{let onDisk=await _internals13.loadPlanJsonOnly(directory);if(!onDisk)return!0;for(let p of onDisk.phases)if(p.tasks.some((x)=>x.id===capturedTaskId))return!0;return!1}})}}catch(error49){if(error49 instanceof LedgerStaleWriterError)throw new PlanConcurrentModificationError(`Concurrent plan modification detected after retries: ${error49.message}. Please retry the operation.`);throw error49}}try{for(let phase of validated.phases)for(let task of phase.tasks){let oldTask=oldTaskMap.get(task.id);if(oldTask&&oldTask.status!==task.status){let eventInput={plan_id:derivePlanId(validated),event_type:"task_status_changed",task_id:task.id,phase_id:phase.id,from_status:oldTask.status,to_status:task.status,source:"savePlan"},capturedFromStatus=oldTask.status,capturedTaskId=task.id;await retryCasWithBackoff(directory,eventInput,{expectedHash:currentHash,planHashAfter:hashAfter,verifyValid:async()=>{let onDisk=await _internals13.loadPlanJsonOnly(directory);if(!onDisk)return!0;for(let p of onDisk.phases){let t=p.tasks.find((x)=>x.id===capturedTaskId);if(t)return t.status===capturedFromStatus}return!1}})}}}catch(error49){if(error49 instanceof LedgerStaleWriterError)throw new PlanConcurrentModificationError(`Concurrent plan modification detected after retries: ${error49.message}. Please retry the operation.`);throw error49}}let ledgerStatusTaskIds=collectLedgerStatusTaskIds(await readLedgerEvents(directory)),replayedBeforeProjection=await replayFromLedger(directory),projectionCandidate=replayedBeforeProjection?mergeStatusesTakingPrecedence(validated,replayedBeforeProjection,ledgerStatusTaskIds):validated;if(replayedBeforeProjection&&computePlanHash(replayedBeforeProjection)!==computePlanHash(projectionCandidate))await takeSnapshotEvent(directory,projectionCandidate,{planHashAfter:computePlanHash(projectionCandidate),source:"savePlan_structural_projection"});let projectedPlan=projectionCandidate,SNAPSHOT_INTERVAL=50,latestSeq=await getLatestLedgerSeq(directory);if(latestSeq>0&&latestSeq%SNAPSHOT_INTERVAL===0)await takeSnapshotWithRetry(directory,projectedPlan,{planHashAfter:computePlanHash(projectedPlan),source:"savePlan_manager"});let swarmDir=path18.resolve(directory,".swarm"),planPath=path18.join(swarmDir,"plan.json"),tempPath=path18.join(swarmDir,`plan.json.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`);try{await bunWrite(tempPath,JSON.stringify(projectedPlan,null,2)),renameSync6(tempPath,planPath)}finally{try{unlinkSync4(tempPath)}catch{}}try{let markerPath=path18.join(swarmDir,".plan-write-marker"),inProgressMarker=JSON.stringify({source:"plan_manager",timestamp:new Date().toISOString(),phases_count:projectedPlan.phases.length,tasks_count:projectedPlan.phases.reduce((sum,p)=>sum+p.tasks.length,0),in_progress:!0});await bunWrite(markerPath,inProgressMarker)}catch{}try{let contentHash=computePlanContentHash(projectedPlan),markdown=derivePlanMarkdown(projectedPlan),markdownWithHash=`<!-- PLAN_HASH: ${contentHash} -->
248
248
  ${markdown}`,mdPath=path18.join(swarmDir,"plan.md"),mdTempPath=path18.join(swarmDir,`plan.md.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`);try{await bunWrite(mdTempPath,markdownWithHash),renameSync6(mdTempPath,mdPath)}finally{try{unlinkSync4(mdTempPath)}catch{}}}catch(mdError){let message=mdError instanceof Error?mdError.message:String(mdError);warn(`[savePlan] plan.md write failed (non-fatal, plan.json is authoritative): ${message}`);try{emit("plan_md_write_failed",{directory,error:message,timestamp:new Date().toISOString()})}catch{}}try{let markerPath=path18.join(swarmDir,".plan-write-marker"),tasksCount=projectedPlan.phases.reduce((sum,phase)=>sum+phase.tasks.length,0),marker=JSON.stringify({source:"plan_manager",timestamp:new Date().toISOString(),phases_count:projectedPlan.phases.length,tasks_count:tasksCount,in_progress:!1});await bunWrite(markerPath,marker)}catch{}}async function rebuildPlan(directory,plan,options){let targetPlan=plan??await replayFromLedger(directory);if(!targetPlan)return null;let swarmDir=path18.join(directory,".swarm"),planPath=path18.join(swarmDir,"plan.json"),mdPath=path18.join(swarmDir,"plan.md");mkdirSync8(swarmDir,{recursive:!0});let tempPlanPath=path18.join(swarmDir,`plan.json.rebuild.${Date.now()}.${Math.floor(Math.random()*1e9)}`);{let fd=openSync2(tempPlanPath,"w");try{writeFileSync8(fd,JSON.stringify(targetPlan,null,2),"utf8"),fsyncSync2(fd)}finally{closeSync2(fd)}}renameSync6(tempPlanPath,planPath);try{let markerPath=path18.join(swarmDir,".plan-write-marker"),inProgressMarker=JSON.stringify({source:"plan_manager",timestamp:new Date().toISOString(),phases_count:targetPlan.phases.length,tasks_count:targetPlan.phases.reduce((sum,phase)=>sum+phase.tasks.length,0),in_progress:!0});await bunWrite(markerPath,inProgressMarker)}catch{}try{let contentHash=computePlanContentHash(targetPlan),markdown=derivePlanMarkdown(targetPlan),markdownWithHash=`<!-- PLAN_HASH: ${contentHash} -->
@@ -260,17 +260,17 @@ ${phases.join(`
260
260
  ---
261
261
  `)}`}return`${markdown.trim()}
262
262
  `}function getCurrentTaskId(plan){if(!plan)return;let currentPhase=plan.current_phase??1,phase=plan.phases.find((p)=>p.id===currentPhase);if(!phase)return;let sortedTasks=[...phase.tasks].sort((a,b)=>compareTaskIds(a.id,b.id)),inProgress=sortedTasks.find((t)=>t.status==="in_progress");if(inProgress)return inProgress.id;return sortedTasks.find((t)=>t.status!=="completed"&&t.status!=="closed")?.id}function migrateLegacyPlan(planContent,swarmId){let lines=planContent.split(`
263
- `),title="Untitled Plan",swarm=swarmId||"default-swarm",currentPhaseNum=1,phases=[],currentPhase=null;for(let line of lines){let trimmed=line.trim();if(trimmed.startsWith("# ")&&title==="Untitled Plan"){title=trimmed.substring(2).trim();continue}if(trimmed.startsWith("Swarm:")){swarm=trimmed.substring(6).trim();continue}if(trimmed.startsWith("Phase:")){let match=trimmed.match(/Phase:\s*(\d+)/i);if(match)currentPhaseNum=parseInt(match[1],10);continue}let phaseMatch=trimmed.match(/^#{2,3}\s*Phase\s+(\d+)(?::\s*([^[]+))?\s*(?:\[([^\]]+)\])?/i);if(phaseMatch){if(currentPhase!==null)phases.push(currentPhase);let phaseId=parseInt(phaseMatch[1],10),phaseName=phaseMatch[2]?.trim()||`Phase ${phaseId}`,statusText=phaseMatch[3]?.toLowerCase()||"pending";currentPhase={id:phaseId,name:phaseName,status:{complete:"complete",completed:"complete","in progress":"in_progress",in_progress:"in_progress",inprogress:"in_progress",pending:"pending",blocked:"blocked"}[statusText]||"pending",tasks:[]};continue}let taskMatch=trimmed.match(/^-\s*\[([^\]]+)\]\s+(\d+\.\d+):\s*(.+?)(?:\s*\[(\w+)\])?(?:\s*-\s*(.+))?$/i);if(taskMatch&&currentPhase!==null){let checkbox=taskMatch[1].toLowerCase(),taskId=taskMatch[2],description=taskMatch[3].trim(),sizeText=taskMatch[4]?.toLowerCase()||"small",blockedReason,dependsMatch=description.match(/\s*\(depends:\s*([^)]+)\)$/i),depends=[];if(dependsMatch){let depsText=dependsMatch[1];depends.push(...depsText.split(",").map((d)=>d.trim())),description=description.substring(0,dependsMatch.index).trim()}let status="pending";if(checkbox==="x")status="completed";else if(checkbox==="blocked"){status="blocked";let blockedReasonMatch=taskMatch[5];if(blockedReasonMatch)blockedReason=blockedReasonMatch.trim()}let sizeMap={small:"small",medium:"medium",large:"large"},task={id:taskId,phase:currentPhase.id,status,size:sizeMap[sizeText]||"small",description,depends,acceptance:void 0,files_touched:[],evidence_path:void 0,blocked_reason:blockedReason};currentPhase.tasks.push(task)}let numberedTaskMatch=trimmed.match(/^(\d+)\.\s+(.+?)(?:\s*\[(\w+)\])?$/);if(numberedTaskMatch&&currentPhase!==null){let taskId=`${currentPhase.id}.${currentPhase.tasks.length+1}`,description=numberedTaskMatch[2].trim(),sizeText=numberedTaskMatch[3]?.toLowerCase()||"small",dependsMatch=description.match(/\s*\(depends:\s*([^)]+)\)$/i),depends=[];if(dependsMatch){let depsText=dependsMatch[1];depends.push(...depsText.split(",").map((d)=>d.trim())),description=description.substring(0,dependsMatch.index).trim()}let sizeMap={small:"small",medium:"medium",large:"large"},task={id:taskId,phase:currentPhase.id,status:"pending",size:sizeMap[sizeText]||"small",description,depends,acceptance:void 0,files_touched:[],evidence_path:void 0,blocked_reason:void 0};currentPhase.tasks.push(task)}let noPrefixTaskMatch=trimmed.match(/^-\s*\[([^\]]+)\]\s+(?!\d+\.\d+:)(.+?)(?:\s*\[(\w+)\])?(?:\s*-\s*(.+))?$/i);if(noPrefixTaskMatch&&currentPhase!==null){let checkbox=noPrefixTaskMatch[1].toLowerCase(),taskId=`${currentPhase.id}.${currentPhase.tasks.length+1}`,description=noPrefixTaskMatch[2].trim(),sizeText=noPrefixTaskMatch[3]?.toLowerCase()||"small",blockedReason,dependsMatch=description.match(/\s*\(depends:\s*([^)]+)\)$/i),depends=[];if(dependsMatch){let depsText=dependsMatch[1];depends.push(...depsText.split(",").map((d)=>d.trim())),description=description.substring(0,dependsMatch.index).trim()}let status="pending";if(checkbox==="x")status="completed";else if(checkbox==="blocked"){status="blocked";let blockedReasonMatch=noPrefixTaskMatch[4];if(blockedReasonMatch)blockedReason=blockedReasonMatch.trim()}let sizeMap={small:"small",medium:"medium",large:"large"},task={id:taskId,phase:currentPhase.id,status,size:sizeMap[sizeText]||"small",description,depends,acceptance:void 0,files_touched:[],evidence_path:void 0,blocked_reason:blockedReason};currentPhase.tasks.push(task)}}if(currentPhase!==null)phases.push(currentPhase);let migrationStatus="migrated";if(phases.length===0)console.warn(`migrateLegacyPlan: 0 phases parsed from ${lines.length} lines. First 3 lines: ${lines.slice(0,3).join(" | ")}`),migrationStatus="migration_failed",phases.push({id:1,name:"Migration Failed",status:"blocked",tasks:[{id:"1.1",phase:1,status:"blocked",size:"large",description:"Review and restructure plan manually",depends:[],files_touched:[],blocked_reason:"Legacy plan could not be parsed automatically"}]});return phases.sort((a,b)=>a.id-b.id),{schema_version:"1.0.0",title,swarm,current_phase:currentPhaseNum,phases,migration_status:migrationStatus}}var PlanConcurrentModificationError,PlanTaskRemovalNotAcknowledgedError,startupLedgerCheckedWorkspaces,ledgerStaleWorkspaces,recoveryMutexes,PLAN_JSON_CACHE_NAMESPACE="plan-json:validated:v1",_internals13,CAS_BACKOFF_START_MS=5,CAS_BACKOFF_CAP_MS=250,CAS_BACKOFF_JITTER=0.25,CAS_MAX_RETRIES=3;var init_manager=__esm(()=>{init_plan_schema();init_branch();init_worktree_merge_status();init_utils2();init_telemetry();init_state();init_task_commit();init_conflicts();init_utils();init_bun_compat();init_spec_hash();init_swarm_artifact_cache();init_ledger();init_utils3();PlanConcurrentModificationError=class PlanConcurrentModificationError extends Error{constructor(message){super(message);this.name="PlanConcurrentModificationError"}};PlanTaskRemovalNotAcknowledgedError=class PlanTaskRemovalNotAcknowledgedError extends Error{missingTasks;constructor(missingTasks){let idList=missingTasks.map((t)=>`${t.id}(${t.status})`).join(", ");super(`PLAN_TASK_REMOVAL_NOT_ACKNOWLEDGED: the following tasks were present in the prior plan but missing from the new save: ${idList}. Pass acknowledged_removals.ids covering all missing task IDs with a non-empty reason to proceed.`);this.name="PlanTaskRemovalNotAcknowledgedError",this.missingTasks=missingTasks}};startupLedgerCheckedWorkspaces=new Set,ledgerStaleWorkspaces=new Set,recoveryMutexes=new Map,_internals13={loadPlan,loadPlanJsonOnly,regeneratePlanMarkdown,isGitRepo,isEpicModeActiveForProject,readTaskScopes,commitTaskCompletion,getWorktreeMergeFailure}});import{promises as fsPromises4}from"node:fs";import*as path19 from"node:path";async function handleAcknowledgeSpecDriftCommand(directory,_args,acknowledgedBy="unknown"){let specStalenessPath=validateSwarmPath(directory,"spec-staleness.json"),stalenessContent;try{stalenessContent=await fsPromises4.readFile(specStalenessPath,"utf-8")}catch(error49){if(error49?.code==="ENOENT")return"No spec drift detected.";throw error49}let stalenessData;try{stalenessData=JSON.parse(stalenessContent)}catch{return await fsPromises4.unlink(specStalenessPath).catch(()=>{}),"Spec staleness file was corrupted. It has been removed."}let{planTitle,phase}=stalenessData,currentHash=null,planUpdateSkipped=!1;try{let plan=await loadPlanJsonOnly(directory);if(plan?.specHash){if(stalenessData.specHash_plan!==plan.specHash)return`Spec drift acknowledgment rejected: The spec has changed since the staleness was detected.
263
+ `),title="Untitled Plan",swarm=swarmId||"default-swarm",currentPhaseNum=1,phases=[],currentPhase=null;for(let line of lines){let trimmed=line.trim();if(trimmed.startsWith("# ")&&title==="Untitled Plan"){title=trimmed.substring(2).trim();continue}if(trimmed.startsWith("Swarm:")){swarm=trimmed.substring(6).trim();continue}if(trimmed.startsWith("Phase:")){let match=trimmed.match(/Phase:\s*(\d+)/i);if(match)currentPhaseNum=parseInt(match[1],10);continue}let phaseMatch=trimmed.match(/^#{2,3}\s*Phase\s+(\d+)(?::\s*([^[]+))?\s*(?:\[([^\]]+)\])?/i);if(phaseMatch){if(currentPhase!==null)phases.push(currentPhase);let phaseId=parseInt(phaseMatch[1],10),phaseName=phaseMatch[2]?.trim()||`Phase ${phaseId}`,statusText=phaseMatch[3]?.toLowerCase()||"pending";currentPhase={id:phaseId,name:phaseName,status:{complete:"complete",completed:"complete","in progress":"in_progress",in_progress:"in_progress",inprogress:"in_progress",pending:"pending",blocked:"blocked"}[statusText]||"pending",tasks:[]};continue}let taskMatch=trimmed.match(/^-\s*\[([^\]]+)\]\s+(\d+\.\d+):\s*(.+?)(?:\s*\[(\w+)\])?(?:\s*-\s*(.+))?$/i);if(taskMatch&&currentPhase!==null){let checkbox=taskMatch[1].toLowerCase(),taskId=taskMatch[2],description=taskMatch[3].trim(),sizeText=taskMatch[4]?.toLowerCase()||"small",blockedReason,dependsMatch=description.match(/\s*\(depends:\s*([^)]+)\)$/i),depends=[];if(dependsMatch){let depsText=dependsMatch[1];depends.push(...depsText.split(",").map((d)=>d.trim())),description=description.substring(0,dependsMatch.index).trim()}let status="pending";if(checkbox==="x")status="completed";else if(checkbox==="blocked"){status="blocked";let blockedReasonMatch=taskMatch[5];if(blockedReasonMatch)blockedReason=blockedReasonMatch.trim()}let sizeMap={small:"small",medium:"medium",large:"large"},task={id:taskId,phase:currentPhase.id,status,size:sizeMap[sizeText]||"small",description,depends,acceptance:void 0,files_touched:[],evidence_path:void 0,blocked_reason:blockedReason};currentPhase.tasks.push(task)}let numberedTaskMatch=trimmed.match(/^(\d+)\.\s+(.+?)(?:\s*\[(\w+)\])?$/);if(numberedTaskMatch&&currentPhase!==null){let taskId=`${currentPhase.id}.${currentPhase.tasks.length+1}`,description=numberedTaskMatch[2].trim(),sizeText=numberedTaskMatch[3]?.toLowerCase()||"small",dependsMatch=description.match(/\s*\(depends:\s*([^)]+)\)$/i),depends=[];if(dependsMatch){let depsText=dependsMatch[1];depends.push(...depsText.split(",").map((d)=>d.trim())),description=description.substring(0,dependsMatch.index).trim()}let sizeMap={small:"small",medium:"medium",large:"large"},task={id:taskId,phase:currentPhase.id,status:"pending",size:sizeMap[sizeText]||"small",description,depends,acceptance:void 0,files_touched:[],evidence_path:void 0,blocked_reason:void 0};currentPhase.tasks.push(task)}let noPrefixTaskMatch=trimmed.match(/^-\s*\[([^\]]+)\]\s+(?!\d+\.\d+:)(.+?)(?:\s*\[(\w+)\])?(?:\s*-\s*(.+))?$/i);if(noPrefixTaskMatch&&currentPhase!==null){let checkbox=noPrefixTaskMatch[1].toLowerCase(),taskId=`${currentPhase.id}.${currentPhase.tasks.length+1}`,description=noPrefixTaskMatch[2].trim(),sizeText=noPrefixTaskMatch[3]?.toLowerCase()||"small",blockedReason,dependsMatch=description.match(/\s*\(depends:\s*([^)]+)\)$/i),depends=[];if(dependsMatch){let depsText=dependsMatch[1];depends.push(...depsText.split(",").map((d)=>d.trim())),description=description.substring(0,dependsMatch.index).trim()}let status="pending";if(checkbox==="x")status="completed";else if(checkbox==="blocked"){status="blocked";let blockedReasonMatch=noPrefixTaskMatch[4];if(blockedReasonMatch)blockedReason=blockedReasonMatch.trim()}let sizeMap={small:"small",medium:"medium",large:"large"},task={id:taskId,phase:currentPhase.id,status,size:sizeMap[sizeText]||"small",description,depends,acceptance:void 0,files_touched:[],evidence_path:void 0,blocked_reason:blockedReason};currentPhase.tasks.push(task)}}if(currentPhase!==null)phases.push(currentPhase);let migrationStatus="migrated";if(phases.length===0)criticalWarn(`migrateLegacyPlan: 0 phases parsed from ${lines.length} lines. First 3 lines: ${lines.slice(0,3).join(" | ")}`),migrationStatus="migration_failed",phases.push({id:1,name:"Migration Failed",status:"blocked",tasks:[{id:"1.1",phase:1,status:"blocked",size:"large",description:"Review and restructure plan manually",depends:[],files_touched:[],blocked_reason:"Legacy plan could not be parsed automatically"}]});return phases.sort((a,b)=>a.id-b.id),{schema_version:"1.0.0",title,swarm,current_phase:currentPhaseNum,phases,migration_status:migrationStatus}}var PlanConcurrentModificationError,PlanTaskRemovalNotAcknowledgedError,startupLedgerCheckedWorkspaces,ledgerStaleWorkspaces,recoveryMutexes,PLAN_JSON_CACHE_NAMESPACE="plan-json:validated:v1",_internals13,CAS_BACKOFF_START_MS=5,CAS_BACKOFF_CAP_MS=250,CAS_BACKOFF_JITTER=0.25,CAS_MAX_RETRIES=3;var init_manager=__esm(()=>{init_plan_schema();init_branch();init_worktree_merge_status();init_utils2();init_telemetry();init_state();init_task_commit();init_conflicts();init_utils();init_bun_compat();init_spec_hash();init_swarm_artifact_cache();init_ledger();init_utils3();PlanConcurrentModificationError=class PlanConcurrentModificationError extends Error{constructor(message){super(message);this.name="PlanConcurrentModificationError"}};PlanTaskRemovalNotAcknowledgedError=class PlanTaskRemovalNotAcknowledgedError extends Error{missingTasks;constructor(missingTasks){let idList=missingTasks.map((t)=>`${t.id}(${t.status})`).join(", ");super(`PLAN_TASK_REMOVAL_NOT_ACKNOWLEDGED: the following tasks were present in the prior plan but missing from the new save: ${idList}. Pass acknowledged_removals.ids covering all missing task IDs with a non-empty reason to proceed.`);this.name="PlanTaskRemovalNotAcknowledgedError",this.missingTasks=missingTasks}};startupLedgerCheckedWorkspaces=new Set,ledgerStaleWorkspaces=new Set,recoveryMutexes=new Map,_internals13={loadPlan,loadPlanJsonOnly,regeneratePlanMarkdown,isGitRepo,isEpicModeActiveForProject,readTaskScopes,commitTaskCompletion,getWorktreeMergeFailure}});import{promises as fsPromises4}from"node:fs";import*as path19 from"node:path";async function handleAcknowledgeSpecDriftCommand(directory,_args,acknowledgedBy="unknown"){let specStalenessPath=validateSwarmPath(directory,"spec-staleness.json"),stalenessContent;try{stalenessContent=await fsPromises4.readFile(specStalenessPath,"utf-8")}catch(error49){if(error49?.code==="ENOENT")return"No spec drift detected.";throw error49}let stalenessData;try{stalenessData=JSON.parse(stalenessContent)}catch{return await fsPromises4.unlink(specStalenessPath).catch(()=>{}),"Spec staleness file was corrupted. It has been removed."}let{planTitle,phase}=stalenessData,currentHash=null,planUpdateSkipped=!1;try{let plan=await loadPlanJsonOnly(directory);if(plan?.specHash){if(stalenessData.specHash_plan!==plan.specHash)return`Spec drift acknowledgment rejected: The spec has changed since the staleness was detected.
264
264
  Current plan specHash: ${plan.specHash}
265
265
  Staleness file specHash: ${stalenessData.specHash_plan}
266
- Please re-run the relevant phase to detect current drift status.`;currentHash=await computeSpecHash(directory),plan.specHash=currentHash??void 0,await savePlan(directory,plan);try{let currentSpec=readEffectiveSpecSync(directory);if(currentSpec){let snapshotPath=path19.join(directory,".swarm","spec-snapshot.md");await fsPromises4.writeFile(snapshotPath,currentSpec.content,"utf-8")}}catch{}}}catch(planError){console.error("[acknowledge-spec-drift] Failed to update plan specHash:",planError instanceof Error?planError.message:String(planError)),planUpdateSkipped=!0}if(!planUpdateSkipped)await fsPromises4.unlink(specStalenessPath);let eventsPath=validateSwarmPath(directory,"events.jsonl"),acknowledgmentEvent={type:"spec_drift_acknowledged",timestamp:new Date().toISOString(),phase,planTitle,acknowledgedBy,previousHash:stalenessData.specHash_plan,newHash:currentHash},eventWriteFailed=!1;try{await fsPromises4.appendFile(eventsPath,`${JSON.stringify(acknowledgmentEvent)}
267
- `,"utf-8")}catch(appendError){console.error("[acknowledge-spec-drift] Failed to write acknowledgment event:",appendError instanceof Error?appendError.message:String(appendError)),eventWriteFailed=!0}let warnings=[];if(planUpdateSkipped)warnings.push("Plan specHash update was skipped due to an error.");if(eventWriteFailed)warnings.push("Event logging failed — audit trail may be incomplete.");let baseMessage=`Spec drift acknowledged for plan "${planTitle}" (phase ${phase}).`,warningMessage=warnings.length>0?`
266
+ Please re-run the relevant phase to detect current drift status.`;currentHash=await computeSpecHash(directory),plan.specHash=currentHash??void 0,await savePlan(directory,plan);try{let currentSpec=readEffectiveSpecSync(directory);if(currentSpec){let snapshotPath=path19.join(directory,".swarm","spec-snapshot.md");await fsPromises4.writeFile(snapshotPath,currentSpec.content,"utf-8")}}catch{}}}catch(planError){log("[acknowledge-spec-drift] Failed to update plan specHash:",planError instanceof Error?planError.message:String(planError)),planUpdateSkipped=!0}if(!planUpdateSkipped)await fsPromises4.unlink(specStalenessPath);let eventsPath=validateSwarmPath(directory,"events.jsonl"),acknowledgmentEvent={type:"spec_drift_acknowledged",timestamp:new Date().toISOString(),phase,planTitle,acknowledgedBy,previousHash:stalenessData.specHash_plan,newHash:currentHash},eventWriteFailed=!1;try{await fsPromises4.appendFile(eventsPath,`${JSON.stringify(acknowledgmentEvent)}
267
+ `,"utf-8")}catch(appendError){log("[acknowledge-spec-drift] Failed to write acknowledgment event:",appendError instanceof Error?appendError.message:String(appendError)),eventWriteFailed=!0}let warnings=[];if(planUpdateSkipped)warnings.push("Plan specHash update was skipped due to an error.");if(eventWriteFailed)warnings.push("Event logging failed — audit trail may be incomplete.");let baseMessage=`Spec drift acknowledged for plan "${planTitle}" (phase ${phase}).`,warningMessage=warnings.length>0?`
268
268
 
269
269
  ⚠️ Warnings:
270
270
  ${warnings.map((w)=>` - ${w}`).join(`
271
271
  `)}`:"",cautionMessage=`
272
272
 
273
- ⚠️ Warning: Spec drift was acknowledged — verify that the implementation still matches the spec before proceeding.`;return baseMessage+warningMessage+cautionMessage}var init_acknowledge_spec_drift=__esm(()=>{init_utils2();init_manager();init_effective_spec();init_spec_hash()});function handleAgentsCommand(agents,guardrails){let entries=Object.entries(agents);if(entries.length===0)return"No agents registered.";let registeredBaseNames=entries.map(([key])=>key).map((key)=>stripKnownSwarmPrefix(key)).filter((stripped)=>ALL_SUBAGENT_NAMES.includes(stripped)),unregistered=ALL_SUBAGENT_NAMES.filter((name)=>!registeredBaseNames.includes(name)),hasUnregistered=unregistered.length>0,lines=[`## Registered Agents (${hasUnregistered?`${entries.length} registered + ${unregistered.length} unregistered`:`${entries.length} total`})`,""];for(let[key,agent]of entries){let model=agent.config.model||"default",temp=agent.config.temperature!==void 0?agent.config.temperature.toString():"default",tools=agent.config.tools||{},access3=tools.write===!1||tools.edit===!1?"\uD83D\uDD12 read-only":"✏️ read-write",desc=agent.description||agent.config.description||"",profileIndicator=guardrails?.profiles?.[key]!==void 0?" | ⚡ custom limits":"";if(lines.push(`- **${key}** | model: \`${model}\` | temp: ${temp} | ${access3}${profileIndicator}`),desc)lines.push(` ${desc}`)}if(hasUnregistered){lines.push("","### Unregistered Subagents");for(let name of unregistered)lines.push(`- **${name}** (requires configuration)`)}if(guardrails?.profiles&&Object.keys(guardrails.profiles).length>0){lines.push("","### Guardrail Profiles","");for(let[profileName,profile]of Object.entries(guardrails.profiles)){let overrides=[];if(profile.max_tool_calls!==void 0)overrides.push(`max_tool_calls=${profile.max_tool_calls}`);if(profile.max_duration_minutes!==void 0)overrides.push(`max_duration_minutes=${profile.max_duration_minutes}`);if(profile.max_repetitions!==void 0)overrides.push(`max_repetitions=${profile.max_repetitions}`);if(profile.max_consecutive_errors!==void 0)overrides.push(`max_consecutive_errors=${profile.max_consecutive_errors}`);if(profile.warning_threshold!==void 0)overrides.push(`warning_threshold=${profile.warning_threshold}`);let overrideStr=overrides.length>0?overrides.join(", "):"no overrides";lines.push(`- **${profileName}**: ${overrideStr}`)}}return lines.join(`
273
+ ⚠️ Warning: Spec drift was acknowledged — verify that the implementation still matches the spec before proceeding.`;return baseMessage+warningMessage+cautionMessage}var init_acknowledge_spec_drift=__esm(()=>{init_utils2();init_manager();init_effective_spec();init_logger();init_spec_hash()});function handleAgentsCommand(agents,guardrails){let entries=Object.entries(agents);if(entries.length===0)return"No agents registered.";let registeredBaseNames=entries.map(([key])=>key).map((key)=>stripKnownSwarmPrefix(key)).filter((stripped)=>ALL_SUBAGENT_NAMES.includes(stripped)),unregistered=ALL_SUBAGENT_NAMES.filter((name)=>!registeredBaseNames.includes(name)),hasUnregistered=unregistered.length>0,lines=[`## Registered Agents (${hasUnregistered?`${entries.length} registered + ${unregistered.length} unregistered`:`${entries.length} total`})`,""];for(let[key,agent]of entries){let model=agent.config.model||"default",temp=agent.config.temperature!==void 0?agent.config.temperature.toString():"default",tools=agent.config.tools||{},access3=tools.write===!1||tools.edit===!1?"\uD83D\uDD12 read-only":"✏️ read-write",desc=agent.description||agent.config.description||"",profileIndicator=guardrails?.profiles?.[key]!==void 0?" | ⚡ custom limits":"";if(lines.push(`- **${key}** | model: \`${model}\` | temp: ${temp} | ${access3}${profileIndicator}`),desc)lines.push(` ${desc}`)}if(hasUnregistered){lines.push("","### Unregistered Subagents");for(let name of unregistered)lines.push(`- **${name}** (requires configuration)`)}if(guardrails?.profiles&&Object.keys(guardrails.profiles).length>0){lines.push("","### Guardrail Profiles","");for(let[profileName,profile]of Object.entries(guardrails.profiles)){let overrides=[];if(profile.max_tool_calls!==void 0)overrides.push(`max_tool_calls=${profile.max_tool_calls}`);if(profile.max_duration_minutes!==void 0)overrides.push(`max_duration_minutes=${profile.max_duration_minutes}`);if(profile.max_repetitions!==void 0)overrides.push(`max_repetitions=${profile.max_repetitions}`);if(profile.max_consecutive_errors!==void 0)overrides.push(`max_consecutive_errors=${profile.max_consecutive_errors}`);if(profile.warning_threshold!==void 0)overrides.push(`warning_threshold=${profile.warning_threshold}`);let overrideStr=overrides.length>0?overrides.join(", "):"no overrides";lines.push(`- **${profileName}**: ${overrideStr}`)}}return lines.join(`
274
274
  `)}var init_agents=__esm(()=>{init_constants();init_schema()});async function handleAnalyzeCommand(_directory,args2){let description=args2.join(" ").trim();if(description)return`[MODE: ANALYZE] ${description}`;return"[MODE: ANALYZE] Please analyze the spec against the plan using MODE: ANALYZE."}var IdentifierSchema,Sha256Schema,IsoDateSchema,RelativePathSchema,EvaluationSplitSchema,CostRecordSchema,HumanReviewReceiptSchema,EvaluationTaskV1Schema,EvaluationCandidateV1Schema,EvaluationOutcomeSchema,EvaluationResultV1Schema,EvaluationBudgetsV1Schema,EnvironmentFingerprintV1Schema,EvaluationRunV1Schema,PromotionPolicyV1Schema,PromotionComparisonSchema,PromotionDecisionV1Schema,GateNameSchema,GateAuditManifestV1Schema,GateAuditCellV1Schema,GateAuditResultV1Schema,TestConsumptionClaimV1Schema,TaskSetSnapshotV1Schema;var init_contracts=__esm(()=>{init_zod();IdentifierSchema=exports_external.string().min(1).max(160).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/),Sha256Schema=exports_external.string().regex(/^[a-f0-9]{64}$/),IsoDateSchema=exports_external.iso.datetime({offset:!0}),RelativePathSchema=exports_external.string().min(1).max(1024).refine((value)=>!value.includes("\x00"),"path contains a NUL byte").refine((value)=>!/^(?:[A-Za-z]:[\\/]|[\\/]{1,2})/.test(value),{message:"path must be project-relative"}).refine((value)=>!value.replace(/\\/g,"/").split("/").some((segment)=>segment===".."),"path must not traverse outside its root"),EvaluationSplitSchema=exports_external.enum(["train","validation","test"]),CostRecordSchema=exports_external.object({source:exports_external.enum(["reported","estimated","unavailable"]),usd:exports_external.number().finite().nonnegative().optional()}).strict().superRefine((value,ctx)=>{if(value.source==="unavailable"&&value.usd!==void 0)ctx.addIssue({code:"custom",path:["usd"],message:"unavailable costs cannot declare a USD value"});if(value.source!=="unavailable"&&value.usd===void 0)ctx.addIssue({code:"custom",path:["usd"],message:"reported and estimated costs require a USD value"})}),HumanReviewReceiptSchema=exports_external.object({reviewer:exports_external.string().min(1).max(200),reviewedAt:IsoDateSchema,instruction:exports_external.literal(!0),fixture:exports_external.literal(!0),scorer:exports_external.literal(!0),secretsPrivacy:exports_external.literal(!0),license:exports_external.literal(!0),split:exports_external.literal(!0)}).strict(),EvaluationTaskV1Schema=exports_external.object({v:exports_external.literal(1),id:IdentifierSchema,derivedFromTaskId:IdentifierSchema.optional(),source:exports_external.enum(["curated","trace-proposal"]),split:EvaluationSplitSchema,category:IdentifierSchema,protected:exports_external.boolean().default(!1),instructionPath:RelativePathSchema,environment:exports_external.discriminatedUnion("kind",[exports_external.object({kind:exports_external.literal("fixture"),path:RelativePathSchema}).strict(),exports_external.object({kind:exports_external.literal("container"),path:RelativePathSchema}).strict()]),scorer:exports_external.object({kind:exports_external.enum(["builtin","project"]),argv:exports_external.array(exports_external.string().min(1).max(4096)).min(1).max(64),timeoutMs:exports_external.number().int().min(100).max(600000),scoreRange:exports_external.tuple([exports_external.number().finite(),exports_external.number().finite()]).refine(([minimum,maximum])=>maximum>minimum,{message:"score range maximum must be greater than minimum"})}).strict(),provenance:exports_external.object({origin:exports_external.string().min(1).max(2048),license:exports_external.string().min(1).max(200),collectedAt:IsoDateSchema.optional(),review:HumanReviewReceiptSchema.optional()}).strict(),contentHash:Sha256Schema}).strict().superRefine((task,ctx)=>{if(task.derivedFromTaskId===task.id)ctx.addIssue({code:"custom",path:["derivedFromTaskId"],message:"a derived task must reference a different parent task"});if(task.source==="trace-proposal"&&!task.provenance.review)ctx.addIssue({code:"custom",path:["provenance","review"],message:"trace-derived tasks require an explicit human review receipt"});if(task.scorer.kind==="project"&&!RelativePathSchema.safeParse(task.scorer.argv[0]).success)ctx.addIssue({code:"custom",path:["scorer","argv",0],message:"project scorer executable must be project-relative"})}),EvaluationCandidateV1Schema=exports_external.object({v:exports_external.literal(1),id:IdentifierSchema,kind:exports_external.enum(["baseline","skill","harness"]),payloadPath:RelativePathSchema,model:exports_external.string().min(1).max(300),agent:exports_external.string().min(1).max(160).optional(),contentHash:Sha256Schema}).strict(),EvaluationOutcomeSchema=exports_external.enum(["scored","infrastructure_failure","timeout","cancelled","malformed","unsupported","integrity_failure"]),EvaluationResultV1Schema=exports_external.object({v:exports_external.literal(1),taskId:IdentifierSchema,category:IdentifierSchema,protected:exports_external.boolean().default(!1),repetition:exports_external.number().int().nonnegative(),candidateId:IdentifierSchema,seed:exports_external.string().min(1).max(500),outcome:EvaluationOutcomeSchema,score:exports_external.number().finite().optional(),scoreRange:exports_external.tuple([exports_external.number().finite(),exports_external.number().finite()]),cost:CostRecordSchema,durationMs:exports_external.number().int().nonnegative(),retries:exports_external.number().int().nonnegative().default(0),failureCode:exports_external.string().min(1).max(160).optional(),metadata:exports_external.record(exports_external.string(),exports_external.unknown()).optional()}).strict().superRefine((result,ctx)=>{let[minimum,maximum]=result.scoreRange;if(maximum<=minimum)ctx.addIssue({code:"custom",path:["scoreRange"],message:"score range maximum must be greater than minimum"});if(result.outcome==="scored"){if(result.score===void 0||result.score<minimum||result.score>maximum)ctx.addIssue({code:"custom",path:["score"],message:"scored outcomes require an in-range score"})}else if(result.score!==void 0)ctx.addIssue({code:"custom",path:["score"],message:"non-score outcomes must not be imputed with a score"})}),EvaluationBudgetsV1Schema=exports_external.object({maxTasks:exports_external.number().int().positive(),maxRepetitions:exports_external.number().int().positive(),maxConcurrency:exports_external.number().int().positive(),maxTaskTimeMs:exports_external.number().int().positive(),maxRetries:exports_external.number().int().nonnegative(),maxOutputBytes:exports_external.number().int().positive(),maxSpendUsd:exports_external.number().finite().nonnegative().optional()}).strict(),EnvironmentFingerprintV1Schema=exports_external.object({platform:exports_external.string().min(1),arch:exports_external.string().min(1),runtime:exports_external.string().min(1),baseSha:exports_external.string().regex(/^[a-f0-9]{40,64}$/),activeTreeHash:Sha256Schema,taskSetHash:Sha256Schema}).strict(),EvaluationRunV1Schema=exports_external.object({v:exports_external.literal(1),runId:IdentifierSchema,createdAt:IsoDateSchema,status:exports_external.enum(["complete","inconclusive","cancelled"]),baseline:EvaluationCandidateV1Schema,candidate:EvaluationCandidateV1Schema,taskSet:exports_external.object({id:IdentifierSchema,contentHash:Sha256Schema,taskIds:exports_external.array(IdentifierSchema).min(1)}).strict(),split:EvaluationSplitSchema,seed:exports_external.string().min(1).max(500),models:exports_external.array(exports_external.string().min(1).max(300)).min(1),environment:EnvironmentFingerprintV1Schema,budgets:EvaluationBudgetsV1Schema,results:exports_external.array(EvaluationResultV1Schema),cost:CostRecordSchema,integrityHash:Sha256Schema}).strict().superRefine((run,ctx)=>{if(run.environment.taskSetHash!==run.taskSet.contentHash)ctx.addIssue({code:"custom",path:["environment","taskSetHash"],message:"environment and task-set hashes must agree"});let allowed=new Set([run.baseline.id,run.candidate.id]);if(allowed.size!==2)ctx.addIssue({code:"custom",path:["candidate","id"],message:"baseline and candidate ids must differ"});if(run.results.some((result)=>!allowed.has(result.candidateId)))ctx.addIssue({code:"custom",path:["results"],message:"results may only reference the declared baseline and candidate"});let taskIds=new Set(run.taskSet.taskIds);if(run.results.some((result)=>!taskIds.has(result.taskId)))ctx.addIssue({code:"custom",path:["results"],message:"results may only reference tasks in the frozen task set"});let resultKeys=run.results.map((result)=>`${result.candidateId}\x00${result.taskId}\x00${result.repetition}`);if(new Set(resultKeys).size!==resultKeys.length)ctx.addIssue({code:"custom",path:["results"],message:"run contains duplicate candidate/task/repetition results"});if(run.results.some((result)=>result.repetition>=run.budgets.maxRepetitions))ctx.addIssue({code:"custom",path:["results"],message:"result repetition exceeds the declared run budget"})}),PromotionPolicyV1Schema=exports_external.object({v:exports_external.literal(1),minValidPairs:exports_external.number().int().positive().default(6),minCoverage:exports_external.number().min(0).max(1).default(0.8),deadband:exports_external.number().min(0).max(1).default(0),confidence:exports_external.literal(0.95).default(0.95),bootstrapResamples:exports_external.literal(1e4).default(1e4),requireAvailableCosts:exports_external.boolean().default(!0),protectedCategoryTolerances:exports_external.record(exports_external.string(),exports_external.number().min(0).max(1)).default({})}).strict(),PromotionComparisonSchema=exports_external.object({baselineRunId:IdentifierSchema,baselineCandidateId:IdentifierSchema,baselineMean:exports_external.number().min(0).max(1),candidateMean:exports_external.number().min(0).max(1),pairedDelta:exports_external.number().min(-1).max(1),confidenceInterval:exports_external.tuple([exports_external.number().min(-1).max(1),exports_external.number().min(-1).max(1)]),validPairs:exports_external.number().int().nonnegative(),missingPairs:exports_external.number().int().nonnegative(),coverage:exports_external.number().min(0).max(1)}).strict(),PromotionDecisionV1Schema=exports_external.object({v:exports_external.literal(1),decisionId:IdentifierSchema,runId:IdentifierSchema,decidedAt:IsoDateSchema,status:exports_external.enum(["accept","reject","inconclusive"]),reasons:exports_external.array(exports_external.string().min(1).max(300)),baseline:PromotionComparisonSchema,historicalBest:PromotionComparisonSchema,deadband:exports_external.number().min(0).max(1),bootstrap:exports_external.object({resamples:exports_external.literal(1e4),confidence:exports_external.literal(0.95),seedHash:Sha256Schema}).strict(),categories:exports_external.array(exports_external.object({category:IdentifierSchema,protected:exports_external.boolean(),tolerance:exports_external.number().min(0).max(1),baselineMean:exports_external.number().min(0).max(1),candidateMean:exports_external.number().min(0).max(1),pairedDelta:exports_external.number().min(-1).max(1),regression:exports_external.boolean()}).strict()),lineage:exports_external.object({baselineRunId:IdentifierSchema,historicalBestRunId:IdentifierSchema,taskSetHash:Sha256Schema,baselineHash:Sha256Schema,candidateHash:Sha256Schema,historicalBestHash:Sha256Schema}).strict(),policyHash:Sha256Schema,unavailableQualityMetrics:exports_external.array(exports_external.enum(["complexity_delta","public_api_delta"])).default(["complexity_delta","public_api_delta"])}).strict(),GateNameSchema=exports_external.enum(["reviewer","test-engineer","sast","mutation","quality"]),GateAuditManifestV1Schema=exports_external.object({v:exports_external.literal(1),id:IdentifierSchema,createdAt:IsoDateSchema,taskIds:exports_external.array(IdentifierSchema).min(1),gates:exports_external.array(GateNameSchema).min(1),models:exports_external.array(exports_external.string().min(1).max(300)).min(1),preferredSwarm:IdentifierSchema.optional(),repetitions:exports_external.number().int().positive().max(100),seed:exports_external.string().min(1).max(500),maxConcurrency:exports_external.number().int().positive().max(64),maxRetries:exports_external.number().int().nonnegative().max(20),maxTimeMs:exports_external.number().int().positive(),maxCostUsd:exports_external.number().finite().nonnegative().optional(),contentHash:Sha256Schema}).strict(),GateAuditCellV1Schema=exports_external.object({v:exports_external.literal(1),taskId:IdentifierSchema,candidateId:IdentifierSchema.optional(),defectType:IdentifierSchema,gate:GateNameSchema,model:exports_external.string().min(1).max(300),repetition:exports_external.number().int().nonnegative(),outcome:exports_external.enum(["caught","missed","false_rejection","unsupported","infrastructure_failure"]),retries:exports_external.number().int().nonnegative(),cost:CostRecordSchema,durationMs:exports_external.number().int().nonnegative(),failureClassification:exports_external.enum(["clean","pre_existing_failure","new_regression","flaky_failure","infrastructure_failure","unknown_failure"]).optional(),failureCode:exports_external.string().min(1).max(160).optional()}).strict(),GateAuditResultV1Schema=exports_external.object({v:exports_external.literal(1),runId:IdentifierSchema,manifestHash:Sha256Schema,createdAt:IsoDateSchema,status:exports_external.enum(["complete","inconclusive","cancelled"]),cells:exports_external.array(GateAuditCellV1Schema),cost:CostRecordSchema,qualityMetricAvailability:exports_external.object({complexity_delta:exports_external.literal("unavailable"),public_api_delta:exports_external.literal("unavailable")}).strict()}).strict(),TestConsumptionClaimV1Schema=exports_external.object({v:exports_external.literal(1),runId:IdentifierSchema,taskSetHash:Sha256Schema,baselineHash:Sha256Schema,candidateHash:Sha256Schema,claimedAt:IsoDateSchema}).strict(),TaskSetSnapshotV1Schema=exports_external.object({v:exports_external.literal(1),id:IdentifierSchema,split:EvaluationSplitSchema,tasks:exports_external.array(EvaluationTaskV1Schema).min(1),contentHash:Sha256Schema,createdAt:IsoDateSchema}).strict()});import{renameSync as renameSync7,unlinkSync as unlinkSync5}from"node:fs";import*as path20 from"node:path";function taskEvidenceRelPath(taskId){return path20.join("evidence",`${taskId}.json`)}function taskEvidencePath(directory,taskId){return path20.join(directory,".swarm",taskEvidenceRelPath(taskId))}async function atomicWriteFile(targetPath,content){let tempPath=`${targetPath}.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`;try{await bunWrite(tempPath,content),_internals14.renameSync(tempPath,targetPath)}finally{try{_internals14.unlinkSync(tempPath)}catch{}}invalidateCachedArtifact(targetPath)}function withTaskEvidenceLock(directory,taskId,agent,fn2){return withEvidenceLock(directory,taskEvidenceRelPath(taskId),agent,taskId,fn2)}var _internals14;var init_task_file=__esm(()=>{init_bun_compat();init_swarm_artifact_cache();init_lock();_internals14={renameSync:renameSync7,unlinkSync:unlinkSync5}});import{createHash as createHash6}from"node:crypto";import{lstatSync as lstatSync3,realpathSync as realpathSync2}from"node:fs";import{lstat as lstat2,opendir,readFile as readFile4,realpath}from"node:fs/promises";import*as path21 from"node:path";function canonicalize(value,ancestors){if(value===null||typeof value==="string"||typeof value==="boolean")return value;if(typeof value==="number"){if(!Number.isFinite(value))throw TypeError("canonical JSON rejects non-finite numbers");return Object.is(value,-0)?0:value}if(value===void 0)return;if(typeof value!=="object")throw TypeError(`canonical JSON cannot encode ${typeof value}`);if(ancestors.has(value))throw TypeError("canonical JSON rejects cyclic values");ancestors.add(value);try{if(Array.isArray(value))return value.map((entry)=>{let encoded=canonicalize(entry,ancestors);return encoded===void 0?null:encoded});let record2=value,result={};for(let key of Object.keys(record2).sort()){let encoded=canonicalize(record2[key],ancestors);if(encoded!==void 0)result[key]=encoded}return result}finally{ancestors.delete(value)}}function canonicalJson(value){return JSON.stringify(canonicalize(value,new Set))}function sha256(value){return createHash6("sha256").update(value).digest("hex")}function canonicalHash(value){return sha256(canonicalJson(value))}function contentHashWithout(value,keys){let copy={...value};for(let key of keys)delete copy[key];return canonicalHash(copy)}async function computeCandidateInputContentHash(projectRoot,candidate){let payload=await hashTree(projectRoot,candidate.payloadPath,createHashBudget({maxFiles:5000,maxBytes:52428800}));return canonicalHash({candidate:JSON.parse(canonicalJson({...candidate,contentHash:void 0})),payload})}function createHashBudget(limits){return{entries:0,bytes:0,limits}}function chargeHashEntry(budget){if(budget.entries++,budget.entries>budget.limits.maxFiles)throw Error("evaluation input exceeds the canonical hashing budget")}async function closeDirectory(directory){try{await directory.close()}catch(error49){if(typeof error49!=="object"||error49===null||!("code"in error49)||error49.code!=="ERR_DIR_CLOSED")throw error49}}function resolveTaskInputHashLimits(limits){let bounded={maxFiles:limits.maxFiles??5000,maxBytes:limits.maxBytes??52428800};if(!Number.isSafeInteger(bounded.maxFiles)||bounded.maxFiles<=0||!Number.isSafeInteger(bounded.maxBytes)||bounded.maxBytes<=0)throw Error("task input hash limits must be positive safe integers");return bounded}async function hashTree(projectRoot,relativePath,budget){let target=await resolveContainedExistingPathAsync(projectRoot,relativePath),canonicalRoot=await _internals15.realpath(projectRoot),entries=[],visit=async(absolutePath,entryAlreadyCharged=!1)=>{let stat5=await _internals15.lstat(absolutePath);if(stat5.isSymbolicLink())throw Error(`evaluation input contains a symlink or reparse point: ${relativePath}`);if(!entryAlreadyCharged)chargeHashEntry(budget);let relative5=path21.relative(canonicalRoot,absolutePath).replace(/\\/g,"/");if(stat5.isDirectory()){entries.push({path:relative5,type:"directory"});let children=[],directory=await _internals15.opendir(absolutePath);try{while(!0){let child=await directory.read();if(!child)break;chargeHashEntry(budget),children.push(child.name)}}finally{await closeDirectory(directory)}for(let child of children.sort())await visit(path21.join(absolutePath,child),!0);return}if(!stat5.isFile())throw Error(`evaluation input must contain only regular files: ${relative5}`);if(budget.bytes+=stat5.size,budget.bytes>budget.limits.maxBytes)throw Error("evaluation input exceeds the canonical hashing budget");let content=await _internals15.readFile(absolutePath);entries.push({path:relative5,type:"file",bytes:content.byteLength,sha256:sha256(content)})};return await visit(target),entries}async function computeTaskInputContentHash(projectRoot,task,limits={}){let bounded=resolveTaskInputHashLimits(limits),budget=createHashBudget(bounded),inputTrees=[...await hashTree(projectRoot,task.instructionPath,budget),...await hashTree(projectRoot,task.environment.path,budget)];if(task.scorer.kind==="project"&&task.scorer.argv[0])inputTrees.push(...await hashTree(projectRoot,task.scorer.argv[0],budget));return canonicalHash({task:JSON.parse(canonicalJson({...task,contentHash:void 0})),inputs:inputTrees.sort((left,right)=>`${left.path}\x00${left.type}`.localeCompare(`${right.path}\x00${right.type}`))})}async function computeTaskLineageInputHash(projectRoot,task,limits={}){let bounded=resolveTaskInputHashLimits(limits),budget=createHashBudget(bounded),normalizedTree=async(relativePath)=>{let canonicalRoot=await _internals15.realpath(projectRoot),target=await resolveContainedExistingPathAsync(projectRoot,relativePath),targetRelative=path21.relative(canonicalRoot,target).replace(/\\/g,"/");return(await hashTree(projectRoot,relativePath,budget)).map((entry)=>({...entry,path:path21.posix.relative(targetRelative,entry.path)||"."}))},scorerArgv=[...task.scorer.argv],projectScorer=task.scorer.kind==="project"&&scorerArgv[0]?await normalizedTree(scorerArgv[0]):void 0;if(projectScorer)scorerArgv[0]="<project-scorer>";return canonicalHash({instruction:await normalizedTree(task.instructionPath),environment:{kind:task.environment.kind,tree:await normalizedTree(task.environment.path)},scorer:{kind:task.scorer.kind,argv:scorerArgv,timeoutMs:task.scorer.timeoutMs,scoreRange:task.scorer.scoreRange,projectScorer}})}function computeTaskSetContentHash(snapshot){return contentHashWithout(snapshot,["contentHash","createdAt"])}function computeRunIntegrityHash(run){return contentHashWithout(run,["integrityHash"])}function computeManifestContentHash(manifest){return contentHashWithout(manifest,["contentHash"])}function isWithin(root,candidate){let relative5=path21.relative(root,candidate);return relative5===""||!relative5.startsWith("..")&&!path21.isAbsolute(relative5)}function resolveContainedExistingPath(root,relativePath){if(path21.isAbsolute(relativePath)||/^(?:[A-Za-z]:[\\/]|[\\/]{1,2})/.test(relativePath)||relativePath.includes("\x00"))throw Error("evaluation path must be a non-NUL relative path");let segments=relativePath.replace(/\\/g,"/").split("/").filter(Boolean);if(segments.length===0||segments.some((segment)=>segment===".."))throw Error("evaluation path traversal is not allowed");let canonicalRoot=realpathSync2(root),cursor=canonicalRoot;for(let segment of segments){if(segment===".")continue;if(cursor=path21.join(cursor,segment),lstatSync3(cursor).isSymbolicLink())throw Error(`evaluation path contains a symlink or reparse point: ${relativePath}`)}let canonicalCandidate=realpathSync2(cursor);if(!isWithin(canonicalRoot,canonicalCandidate))throw Error("evaluation path escapes its admitted root");return canonicalCandidate}async function resolveContainedExistingPathAsync(root,relativePath){if(path21.isAbsolute(relativePath)||/^(?:[A-Za-z]:[\\/]|[\\/]{1,2})/.test(relativePath)||relativePath.includes("\x00"))throw Error("evaluation path must be a non-NUL relative path");let segments=relativePath.replace(/\\/g,"/").split("/").filter(Boolean);if(segments.length===0||segments.some((segment)=>segment===".."))throw Error("evaluation path traversal is not allowed");let canonicalRoot=await _internals15.realpath(root),cursor=canonicalRoot;for(let segment of segments){if(segment===".")continue;if(cursor=path21.join(cursor,segment),(await _internals15.lstat(cursor)).isSymbolicLink())throw Error(`evaluation path contains a symlink or reparse point: ${relativePath}`)}let canonicalCandidate=await _internals15.realpath(cursor);if(!isWithin(canonicalRoot,canonicalCandidate))throw Error("evaluation path escapes its admitted root");return canonicalCandidate}var _internals15;var init_hashing=__esm(()=>{_internals15={lstat:lstat2,opendir,readFile:readFile4,realpath}});import{mkdir as mkdir3,readdir as readdir2,readFile as readFile5}from"node:fs/promises";import*as path22 from"node:path";function swarmPath(directory,...segments){return path22.join(directory,".swarm",...segments)}function serialized(value){return`${canonicalJson(value)}
275
275
  `}function parseTaskSplitRegistry(content){if(content===void 0)return{v:1,entries:[]};let value;try{value=JSON.parse(content)}catch(error49){throw new EvaluationConflictError(`task split registry is corrupt: ${String(error49)}`)}if(!value||typeof value!=="object"||Array.isArray(value))throw new EvaluationConflictError("task split registry is corrupt");let record2=value;if(record2.v!==1||!Array.isArray(record2.entries))throw new EvaluationConflictError("task split registry is corrupt");return{v:1,entries:record2.entries.map((candidate)=>{if(!candidate||typeof candidate!=="object"||Array.isArray(candidate))throw new EvaluationConflictError("task split registry is corrupt");let entry=candidate;if(typeof entry.lineageHash!=="string"||!["train","validation","test"].includes(String(entry.split))||!Array.isArray(entry.taskIds)||!entry.taskIds.every((id)=>typeof id==="string")||!Array.isArray(entry.inputHashes)||!entry.inputHashes.every((hash3)=>typeof hash3==="string"))throw new EvaluationConflictError("task split registry is corrupt");return{lineageHash:entry.lineageHash,split:entry.split,taskIds:[...new Set(entry.taskIds)].sort(),inputHashes:[...new Set(entry.inputHashes)].sort()}})}}async function readOptional(filePath){try{return await readFile5(filePath,"utf8")}catch(error49){if(error49.code==="ENOENT")return;throw error49}}async function writeImmutable(options){return await mkdir3(path22.dirname(options.filePath),{recursive:!0}),withEvidenceLock(options.directory,options.relativeLockPath,AGENT,options.taskId,async()=>{let desired=serialized(options.value),existing=await readOptional(options.filePath);if(existing!==void 0){let parsed;try{parsed=options.parse(JSON.parse(existing))}catch(error49){throw new EvaluationConflictError(`existing evaluation artifact is corrupt: ${options.filePath}: ${String(error49)}`)}if(serialized(parsed)===desired||options.isEquivalent?.(parsed,options.value))return parsed;throw new EvaluationConflictError(`immutable evaluation artifact conflicts with existing content: ${options.filePath}`)}return await atomicWriteFile(options.filePath,desired),options.value})}function validateTaskInputs(directory,task){resolveContainedExistingPath(directory,task.instructionPath);let environmentRoot=resolveContainedExistingPath(directory,task.environment.path);if(task.scorer.kind==="project"){let executable=task.scorer.argv[0];if(!executable)throw Error("project scorer requires an executable");let scorerPath=resolveContainedExistingPath(directory,executable),relative6=path22.relative(environmentRoot,scorerPath);if(!relative6||relative6===".."||relative6.startsWith(`..${path22.sep}`)||path22.isAbsolute(relative6))throw Error("project scorer executable must be inside the admitted task environment")}}async function admitEvaluationTask(directory,input,inputRoot=directory){let task=EvaluationTaskV1Schema.parse(input);if(await computeTaskInputContentHash(inputRoot,task)!==task.contentHash)throw Error(`task ${task.id} content hash does not match its canonical inputs`);validateTaskInputs(inputRoot,task);let lineageInputHash=await computeTaskLineageInputHash(inputRoot,task),relative6=path22.join("evolution","tasks",task.split,`${task.id}.json`),admissionLock=TASK_SPLIT_REGISTRY_RELATIVE,filePath=swarmPath(directory,relative6);return await mkdir3(path22.dirname(filePath),{recursive:!0}),withEvidenceLock(directory,admissionLock,AGENT,task.id,async()=>{let registryPath=swarmPath(directory,TASK_SPLIT_REGISTRY_RELATIVE),registry2=parseTaskSplitRegistry(await readOptional(registryPath)),existingTaskEntry=registry2.entries.find((entry)=>entry.taskIds.includes(task.id));if(existingTaskEntry&&existingTaskEntry.split!==task.split)throw new EvaluationConflictError(`task ${task.id} is already admitted to a different split`);let parentEntry=task.derivedFromTaskId?registry2.entries.find((entry)=>entry.taskIds.includes(task.derivedFromTaskId)):void 0;if(task.derivedFromTaskId&&!parentEntry)throw new EvaluationConflictError(`derived task ${task.id} references an unadmitted parent ${task.derivedFromTaskId}`);let lineageEntry=parentEntry??registry2.entries.find((entry)=>entry.lineageHash===lineageInputHash||entry.inputHashes.includes(lineageInputHash));if(lineageEntry&&lineageEntry.split!==task.split)throw new EvaluationConflictError(`task ${task.id} lineage is already admitted to ${lineageEntry.split}; derived and aliased tasks must inherit that split`);for(let split of["train","validation","test"]){if(split===task.split)continue;if(await readOptional(swarmPath(directory,"evolution","tasks",split,`${task.id}.json`)))throw new EvaluationConflictError(`task ${task.id} is already admitted to a different split`)}let desired=serialized(task),existing=await readOptional(filePath);if(existing!==void 0){let parsed=EvaluationTaskV1Schema.parse(JSON.parse(existing));if(serialized(parsed)===desired){if(lineageEntry)lineageEntry.taskIds=[...new Set([...lineageEntry.taskIds,task.id])].sort(),lineageEntry.inputHashes=[...new Set([...lineageEntry.inputHashes,lineageInputHash])].sort();else registry2.entries.push({lineageHash:lineageInputHash,split:task.split,taskIds:[task.id],inputHashes:[lineageInputHash]});return registry2.entries.sort((left,right)=>left.lineageHash.localeCompare(right.lineageHash)),await atomicWriteFile(registryPath,serialized(registry2)),parsed}if(task.split!=="train")throw new EvaluationConflictError(`${task.split} task ${task.id} is immutable after admission`)}if(await atomicWriteFile(filePath,desired),lineageEntry)lineageEntry.taskIds=[...new Set([...lineageEntry.taskIds,task.id])].sort(),lineageEntry.inputHashes=[...new Set([...lineageEntry.inputHashes,lineageInputHash])].sort();else registry2.entries.push({lineageHash:lineageInputHash,split:task.split,taskIds:[task.id],inputHashes:[lineageInputHash]});return registry2.entries.sort((left,right)=>left.lineageHash.localeCompare(right.lineageHash)),await atomicWriteFile(registryPath,serialized(registry2)),task})}async function saveTaskSetSnapshot(directory,input,inputRoot=directory){let snapshot=TaskSetSnapshotV1Schema.parse(input),ids=snapshot.tasks.map((task)=>task.id);if(new Set(ids).size!==ids.length)throw Error("task-set contains duplicate task ids");if(snapshot.tasks.some((task)=>task.split!==snapshot.split))throw Error("task-set tasks must all belong to the declared split");for(let task of snapshot.tasks)if(await computeTaskInputContentHash(inputRoot,task)!==task.contentHash)throw Error(`task ${task.id} content hash is invalid`);if(computeTaskSetContentHash(snapshot)!==snapshot.contentHash)throw Error("task-set content hash does not match its canonical inputs");let relative6=path22.join("evolution","task-sets",`${snapshot.contentHash}.json`);return writeImmutable({directory,relativeLockPath:relative6,filePath:swarmPath(directory,relative6),taskId:snapshot.id,value:snapshot,parse:(value)=>TaskSetSnapshotV1Schema.parse(value),isEquivalent:(existing,desired)=>existing.contentHash===desired.contentHash})}async function saveEvaluationRun(directory,input){let run=EvaluationRunV1Schema.parse(input);if(computeRunIntegrityHash(run)!==run.integrityHash)throw Error(`run ${run.runId} integrity hash is invalid`);let relative6=path22.join("evolution","runs",`${run.runId}.json`);return writeImmutable({directory,relativeLockPath:relative6,filePath:swarmPath(directory,relative6),taskId:run.runId,value:run,parse:(value)=>EvaluationRunV1Schema.parse(value)})}async function readEvaluationRun(directory,runId){let content=await readOptional(swarmPath(directory,"evolution","runs",`${runId}.json`));return content===void 0?void 0:EvaluationRunV1Schema.parse(JSON.parse(content))}async function savePromotionDecision(directory,input){let decision=PromotionDecisionV1Schema.parse(input),relative6=path22.join("evolution","decisions",`${decision.decisionId}.json`);return writeImmutable({directory,relativeLockPath:relative6,filePath:swarmPath(directory,relative6),taskId:decision.runId,value:decision,parse:(value)=>PromotionDecisionV1Schema.parse(value),isEquivalent:(existing,desired)=>{let{decidedAt:_existingTimestamp,...existingCore}=existing,{decidedAt:_desiredTimestamp,...desiredCore}=desired;return canonicalJson(existingCore)===canonicalJson(desiredCore)}})}async function saveGateAuditResult(directory,input){let result=GateAuditResultV1Schema.parse(input),relative6=path22.join("evidence","gate-audit",result.runId,"results.json");return writeImmutable({directory,relativeLockPath:relative6,filePath:swarmPath(directory,relative6),taskId:result.runId,value:result,parse:(value)=>GateAuditResultV1Schema.parse(value)})}async function saveGateAuditManifest(directory,input){let manifest=GateAuditManifestV1Schema.parse(input),relative6=path22.join("evolution","gate-audit-manifests",`${manifest.id}.json`);return writeImmutable({directory,relativeLockPath:relative6,filePath:swarmPath(directory,relative6),taskId:manifest.id,value:manifest,parse:(value)=>GateAuditManifestV1Schema.parse(value)})}async function readGateAuditManifest(directory,runId){let content=await readOptional(swarmPath(directory,"evolution","gate-audit-manifests",`${runId}.json`));return content===void 0?void 0:GateAuditManifestV1Schema.parse(JSON.parse(content))}async function readGateAuditResult(directory,runId){let content=await readOptional(swarmPath(directory,"evidence","gate-audit",runId,"results.json"));return content===void 0?void 0:GateAuditResultV1Schema.parse(JSON.parse(content))}async function listGateAuditResults(directory){let root=swarmPath(directory,"evidence","gate-audit"),entries=[];try{entries=await readdir2(root,{withFileTypes:!0})}catch(error49){if(error49.code==="ENOENT")return{results:[],corruptRunIds:[]};throw error49}let results=[],corruptRunIds=[];for(let entry of entries.sort((left,right)=>left.name.localeCompare(right.name))){if(!entry.isDirectory()||!/^[A-Za-z0-9][A-Za-z0-9._-]{0,159}$/.test(entry.name))continue;try{let parsed=GateAuditResultV1Schema.parse(JSON.parse(await readFile5(path22.join(root,entry.name,"results.json"),"utf8")));if(parsed.runId!==entry.name)throw Error("run id/path mismatch");results.push(parsed)}catch{corruptRunIds.push(entry.name)}}return{results,corruptRunIds}}function parseTestLedger(content){return content.split(/\r?\n/).filter((line)=>line.trim().length>0).map((line,index)=>{try{return TestConsumptionClaimV1Schema.parse(JSON.parse(line))}catch(error49){throw new EvaluationConflictError(`test-consumption ledger is corrupt at line ${index+1}: ${String(error49)}`)}})}async function claimHeldOutTest(directory,input){let claim=TestConsumptionClaimV1Schema.parse(input),filePath=swarmPath(directory,TEST_LEDGER_RELATIVE);return await mkdir3(path22.dirname(filePath),{recursive:!0}),withEvidenceLock(directory,TEST_LEDGER_RELATIVE,AGENT,claim.runId,async()=>{let content=await readOptional(filePath)??"",claims=parseTestLedger(content),identicalRun=claims.find((entry)=>entry.runId===claim.runId);if(identicalRun){if(identicalRun.taskSetHash===claim.taskSetHash&&identicalRun.baselineHash===claim.baselineHash&&identicalRun.candidateHash===claim.candidateHash)return identicalRun;throw new EvaluationConflictError(`run ${claim.runId} conflicts with its prior held-out test claim`)}let prior=claims.find((entry)=>entry.taskSetHash===claim.taskSetHash);if(prior)throw new TestAlreadyConsumedError(prior);return await atomicWriteFile(filePath,`${content.replace(/\s*$/,"")}${content.trim()?`
276
276
  `:""}${serialized(claim)}`),claim})}async function getProtectedEvaluationRunIds(directory){let protectedIds=new Set,ledger=await readOptional(swarmPath(directory,TEST_LEDGER_RELATIVE));for(let claim of parseTestLedger(ledger??""))protectedIds.add(claim.runId);let decisionsDirectory=swarmPath(directory,"evolution","decisions"),files=[];try{files=await readdir2(decisionsDirectory)}catch(error49){if(error49.code!=="ENOENT")throw error49}for(let filename of files.filter((value)=>value.endsWith(".json")).sort()){let decision=PromotionDecisionV1Schema.parse(JSON.parse(await readFile5(path22.join(decisionsDirectory,filename),"utf8")));if(protectedIds.add(decision.runId),protectedIds.add(decision.lineage.baselineRunId),decision.lineage.historicalBestRunId!=="unavailable")protectedIds.add(decision.lineage.historicalBestRunId)}return protectedIds}var AGENT="evaluation-store",TEST_LEDGER_RELATIVE,TASK_SPLIT_REGISTRY_RELATIVE,EvaluationConflictError,TestAlreadyConsumedError;var init_store=__esm(()=>{init_lock();init_task_file();init_contracts();init_hashing();TEST_LEDGER_RELATIVE=path22.join("evolution","test-consumption.jsonl"),TASK_SPLIT_REGISTRY_RELATIVE=path22.join("evolution","tasks","split-registry.json");EvaluationConflictError=class EvaluationConflictError extends Error{constructor(message){super(message);this.name="EvaluationConflictError"}};TestAlreadyConsumedError=class TestAlreadyConsumedError extends Error{priorClaim;constructor(priorClaim){super(`held-out test task set ${priorClaim.taskSetHash} was already consumed by run ${priorClaim.runId}`);this.name="TestAlreadyConsumedError",this.priorClaim=priorClaim}}});import*as fs13 from"node:fs/promises";import*as path23 from"node:path";function artifactKey(artifact){return`${artifact.namespace}/${artifact.id}`}function validId(value){return/^[A-Za-z0-9][A-Za-z0-9._-]{0,159}$/.test(value)}async function evaluationRunCandidates(directory){let root=path23.join(directory,".swarm","evolution","runs"),entries=[];try{entries=await fs13.readdir(root,{withFileTypes:!0})}catch(error49){if(error49.code==="ENOENT")return{candidates:[],corrupt:[]};throw error49}let candidates=[],corrupt=[];for(let entry of entries.sort((a,b)=>a.name.localeCompare(b.name))){if(!entry.isFile()||!entry.name.endsWith(".json"))continue;let id=entry.name.slice(0,-5);if(!validId(id))continue;let artifact={namespace:"evaluation-run",id},target=path23.join(root,entry.name);try{let run=EvaluationRunV1Schema.parse(JSON.parse(await fs13.readFile(target,"utf8")));if(run.runId!==id)throw Error("run id/path mismatch");candidates.push({artifact,createdAt:run.createdAt,target,kind:"file"})}catch{corrupt.push(artifact)}}return{candidates,corrupt}}async function gateAuditCandidates(directory){let root=path23.join(directory,".swarm","evidence","gate-audit"),entries=[];try{entries=await fs13.readdir(root,{withFileTypes:!0})}catch(error49){if(error49.code==="ENOENT")return{candidates:[],corrupt:[]};throw error49}let candidates=[],corrupt=[];for(let entry of entries.sort((a,b)=>a.name.localeCompare(b.name))){if(!entry.isDirectory()||!validId(entry.name))continue;let artifact={namespace:"gate-audit",id:entry.name},target=path23.join(root,entry.name);try{let result=GateAuditResultV1Schema.parse(JSON.parse(await fs13.readFile(path23.join(target,"results.json"),"utf8")));if(result.runId!==entry.name)throw Error("run id/path mismatch");candidates.push({artifact,createdAt:result.createdAt,target,kind:"directory"})}catch{corrupt.push(artifact)}}return{candidates,corrupt}}async function retentionCandidates(directory){let[runs,audits]=await Promise.all([evaluationRunCandidates(directory),gateAuditCandidates(directory)]);return{candidates:[...runs.candidates,...audits.candidates].sort((a,b)=>artifactKey(a.artifact).localeCompare(artifactKey(b.artifact))),corrupt:[...runs.corrupt,...audits.corrupt].sort((a,b)=>artifactKey(a).localeCompare(artifactKey(b)))}}async function protectedArtifacts(directory){let ids=await getProtectedEvaluationRunIds(directory);return new Set([...ids].map((id)=>`evaluation-run/${id}`))}async function removeCandidate(candidate){if(candidate.kind==="directory"){await fs13.rm(candidate.target,{recursive:!0,force:!0});return}await fs13.unlink(candidate.target)}async function archiveEvaluationArtifacts(args2){return withEvidenceLock(args2.directory,path23.join("evolution","retention-index"),"evaluation-retention","archive",async()=>{let inventory=await retentionCandidates(args2.directory),protectedKeys=await _retentionInternals.protectedArtifacts(args2.directory),protectedRefs=inventory.candidates.filter((candidate)=>protectedKeys.has(artifactKey(candidate.artifact))).map((candidate)=>candidate.artifact),eligible=inventory.candidates.filter((candidate)=>!protectedKeys.has(artifactKey(candidate.artifact))),now=args2.now??new Date,cutoff=new Date(now.getTime()-args2.maxAgeDays*86400000).toISOString(),selectedKeys=new Set(eligible.filter((candidate)=>candidate.createdAt<cutoff).map((candidate)=>artifactKey(candidate.artifact))),remaining=eligible.filter((candidate)=>!selectedKeys.has(artifactKey(candidate.artifact))).sort((a,b)=>a.createdAt===b.createdAt?artifactKey(a.artifact).localeCompare(artifactKey(b.artifact)):a.createdAt.localeCompare(b.createdAt));if(args2.maxBundles!==void 0&&remaining.length>args2.maxBundles)for(let candidate of remaining.slice(0,remaining.length-args2.maxBundles))selectedKeys.add(artifactKey(candidate.artifact));let selectedCandidates=eligible.filter((candidate)=>selectedKeys.has(artifactKey(candidate.artifact))).sort((a,b)=>artifactKey(a.artifact).localeCompare(artifactKey(b.artifact))),archived=[],failed=[];if(!args2.dryRun)for(let candidate of selectedCandidates){if(protectedKeys=await _retentionInternals.protectedArtifacts(args2.directory),protectedKeys.has(artifactKey(candidate.artifact))){protectedRefs.push(candidate.artifact);continue}try{await _retentionInternals.removeCandidate(candidate),archived.push(candidate.artifact)}catch(error49){failed.push({artifact:candidate.artifact,error:error49 instanceof Error?error49.message:String(error49)})}}return{inventory:inventory.candidates.map((candidate)=>candidate.artifact),selected:selectedCandidates.map((candidate)=>candidate.artifact),archived,corrupt:inventory.corrupt,protected:[...new Map(protectedRefs.map((artifact)=>[artifactKey(artifact),artifact])).values()].sort((a,b)=>artifactKey(a).localeCompare(artifactKey(b))),failed}})}var _retentionInternals;var init_retention=__esm(()=>{init_lock();init_contracts();init_store();_retentionInternals={protectedArtifacts,removeCandidate}});function checkUnsafeChars(taskId){if(!taskId||taskId.length===0)return"Invalid task ID: empty string";if(/\0/.test(taskId))return"Invalid task ID: contains null bytes";for(let i=0;i<taskId.length;i++)if(taskId.charCodeAt(i)<32)return"Invalid task ID: contains control characters";if(taskId.includes("..")||taskId.includes("/")||taskId.includes("\\"))return"Invalid task ID: path traversal detected";return}function isStrictTaskId(taskId){if(!taskId)return!1;if(checkUnsafeChars(taskId))return!1;return STRICT_TASK_ID_PATTERN.test(taskId)}function assertStrictTaskId(taskId){if(!isStrictTaskId(taskId))throw Error(`Invalid taskId: "${taskId}". Must match N.M or N.M.P (e.g. "1.1", "1.2.3").`)}function sanitizeTaskId(taskId){let unsafeMsg=checkUnsafeChars(taskId);if(unsafeMsg)throw Error(unsafeMsg);if(STRICT_TASK_ID_PATTERN.test(taskId)||RETRO_TASK_ID_REGEX.test(taskId)||INTERNAL_TOOL_ID_REGEX.test(taskId)||GENERAL_TASK_ID_REGEX.test(taskId))return taskId;throw Error(`Invalid task ID: must be alphanumeric (ASCII) with optional hyphens, underscores, or dots, got "${taskId}"`)}function validateTaskIdFormat(taskId){if(!STRICT_TASK_ID_PATTERN.test(taskId))return`Invalid taskId "${taskId}". Must match pattern N.M or N.M.P (e.g., "1.1", "1.2.3")`;return}var STRICT_TASK_ID_PATTERN,RETRO_TASK_ID_REGEX,INTERNAL_TOOL_ID_REGEX,GENERAL_TASK_ID_REGEX;var init_task_id=__esm(()=>{STRICT_TASK_ID_PATTERN=/^\d+\.\d+(\.\d+)*$/,RETRO_TASK_ID_REGEX=/^retro-\d+$/,INTERNAL_TOOL_ID_REGEX=/^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build|secretscan)$/,GENERAL_TASK_ID_REGEX=/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/});import{mkdirSync as mkdirSync9,readdirSync as readdirSync5,realpathSync as realpathSync3,rmSync,statSync as statSync8}from"node:fs";import*as fs14 from"node:fs/promises";import*as os8 from"node:os";import*as path24 from"node:path";function isValidEvidenceType(type){return VALID_EVIDENCE_TYPES.includes(type)}function isSecretscanEvidence(evidence){return evidence.type==="secretscan"}function isWeakConfigContainerRoot(directory){try{let resolved=realpathSync3(directory);return resolved===realpathSync3(os8.tmpdir())||resolved===realpathSync3(os8.homedir())}catch{let resolved=path24.resolve(directory);return resolved===path24.resolve(os8.tmpdir())||resolved===path24.resolve(os8.homedir())}}function hasAccessibleProjectIndicator(directory,options={}){let allowConfigOnly=options.allowConfigOnly??!0;for(let indicator of PROJECT_INDICATORS){if(!allowConfigOnly&&indicator===".opencode")continue;try{let indicatorStat=statSync8(path24.join(directory,indicator));if(indicatorStat.isFile()||indicatorStat.isDirectory())return!0}catch{}}return!1}function validateProjectRoot(directory){let resolved;try{resolved=realpathSync3(directory)}catch{throw warn(`[evidence] Cannot canonicalize directory "${directory}" — failing closed`),Error(`Cannot verify project root for "${directory}" — directory may not exist or is inaccessible`)}let current=resolved,depth=0;while(!0){if(depth>=MAX_DEPTH)break;depth++;let parent=path24.dirname(current);if(parent===current)break;if(path24.dirname(parent)===parent){current=parent;continue}let parentSwarm=path24.join(parent,".swarm");try{if(statSync8(parentSwarm).isDirectory()){if(hasAccessibleProjectIndicator(parent,{allowConfigOnly:!isWeakConfigContainerRoot(parent)}))throw warn(`[evidence] Rejecting write to subdirectory "${resolved}" — parent "${parent}" already contains .swarm/`),Error(`Cannot write evidence in "${resolved}" — parent directory "${parent}" already contains a .swarm/ folder. Evidence must be written to the project root.`)}}catch(error49){if(error49 instanceof Error&&error49.message.startsWith("Cannot write evidence"))throw error49}current=parent}}async function saveEvidence(directory,taskId,evidence){_internals16.validateProjectRoot(directory);let sanitizedTaskId=sanitizeTaskId2(taskId),relativePath=path24.join("evidence",sanitizedTaskId,"evidence.json");return validateSwarmPath(directory,relativePath),_internals16.validateEvidence(evidence),withEvidenceLock(directory,relativePath,"evidence-manager",sanitizedTaskId,async()=>{let evidencePath=validateSwarmPath(directory,relativePath),evidenceDir=path24.dirname(evidencePath),bundle,existingContent=await readSwarmFileAsync(directory,relativePath);if(existingContent!==null)try{let parsed=JSON.parse(existingContent);bundle=EvidenceBundleSchema.parse(parsed)}catch(error49){warn(`Existing evidence bundle invalid for task ${sanitizedTaskId}, creating new: ${error49 instanceof Error?error49.message:String(error49)}`);let now=new Date().toISOString();bundle={schema_version:"1.0.0",task_id:sanitizedTaskId,entries:[],created_at:now,updated_at:now}}else{let now=new Date().toISOString();bundle={schema_version:"1.0.0",task_id:sanitizedTaskId,entries:[],created_at:now,updated_at:now}}let MAX_BUNDLE_ENTRIES=100,entries=[...bundle.entries,evidence];if(entries.length>MAX_BUNDLE_ENTRIES)entries=entries.slice(entries.length-MAX_BUNDLE_ENTRIES);let updatedBundle={...bundle,entries,updated_at:new Date().toISOString()},bundleJson=JSON.stringify(updatedBundle);if(bundleJson.length>EVIDENCE_MAX_JSON_BYTES)throw Error(`Evidence bundle size (${bundleJson.length} bytes) exceeds maximum (${EVIDENCE_MAX_JSON_BYTES} bytes)`);mkdirSync9(evidenceDir,{recursive:!0});let tempPath=path24.join(evidenceDir,`evidence.json.tmp.${Date.now()}.${process.pid}`);try{await bunWrite(tempPath,bundleJson),await fs14.rename(tempPath,evidencePath)}catch(error49){try{rmSync(tempPath,{force:!0})}catch{}throw error49}return updatedBundle})}function isFlatRetrospective(parsed){return parsed!==null&&typeof parsed==="object"&&!Array.isArray(parsed)&&parsed.type==="retrospective"&&!parsed.schema_version}function remapLegacyTaskComplexity(entry){let taskComplexity=entry.task_complexity;if(typeof taskComplexity==="string"&&taskComplexity in LEGACY_TASK_COMPLEXITY_MAP)return{...entry,task_complexity:LEGACY_TASK_COMPLEXITY_MAP[taskComplexity]};return entry}function wrapFlatRetrospective(flatEntry,taskId){let now=new Date().toISOString(),remappedEntry=remapLegacyTaskComplexity(flatEntry);return{schema_version:"1.0.0",task_id:remappedEntry.task_id??taskId,created_at:remappedEntry.timestamp??now,updated_at:remappedEntry.timestamp??now,entries:[remappedEntry]}}async function loadEvidence(directory,taskId){let sanitizedTaskId=sanitizeTaskId2(taskId),relativePath=path24.join("evidence",sanitizedTaskId,"evidence.json");if(relativePath.length>4096)return{status:"not_found"};let evidencePath=validateSwarmPath(directory,relativePath),content=await readSwarmFileAsync(directory,relativePath);if(content===null)return{status:"not_found"};let parsed;try{parsed=JSON.parse(content)}catch{return{status:"invalid_schema",errors:["Invalid JSON"]}}if(isFlatRetrospective(parsed)){let wrappedBundle=_internals16.wrapFlatRetrospective(parsed,sanitizedTaskId);try{let validated=EvidenceBundleSchema.parse(wrappedBundle);try{await withEvidenceLock(directory,relativePath,"evidence-loader",sanitizedTaskId,async()=>{let evidenceDir=path24.dirname(evidencePath),bundleJson=JSON.stringify(validated),tempPath=path24.join(evidenceDir,`evidence.json.tmp.${Date.now()}.${process.pid}`);try{await bunWrite(tempPath,bundleJson),await fs14.rename(tempPath,evidencePath)}catch(writeError){try{rmSync(tempPath,{force:!0})}catch{}warn(`Failed to persist repaired flat retrospective for task ${sanitizedTaskId}: ${writeError instanceof Error?writeError.message:String(writeError)}`)}})}catch(lockErr){warn(`Evidence lock failed during flat-retrospective write-back for task ${sanitizedTaskId}: ${lockErr instanceof Error?lockErr.message:String(lockErr)}`)}return{status:"found",bundle:validated}}catch(error49){return warn(`Wrapped flat retrospective failed validation for task ${sanitizedTaskId}: ${error49 instanceof Error?error49.message:String(error49)}`),{status:"invalid_schema",errors:error49 instanceof ZodError?error49.issues.map((e)=>`${e.path.join(".")}: ${e.message}`):[error49 instanceof Error?error49.message:String(error49)]}}}try{return{status:"found",bundle:EvidenceBundleSchema.parse(parsed)}}catch(error49){return warn(`Evidence bundle validation failed for task ${sanitizedTaskId}: ${error49 instanceof Error?error49.message:String(error49)}`),{status:"invalid_schema",errors:error49 instanceof ZodError?error49.issues.map((e)=>`${e.path.join(".")}: ${e.message}`):[error49 instanceof Error?error49.message:String(error49)]}}}async function listEvidenceTaskIds(directory){let evidenceBasePath=validateSwarmPath(directory,"evidence");try{statSync8(evidenceBasePath)}catch{return[]}let entries;try{entries=readdirSync5(evidenceBasePath)}catch{return[]}let taskIds=[];for(let entry of entries){let entryPath=path24.join(evidenceBasePath,entry);try{if(!statSync8(entryPath).isDirectory())continue;sanitizeTaskId2(entry),taskIds.push(entry)}catch(error49){if(error49 instanceof Error&&!error49.message.startsWith("Invalid task ID"))warn(`Error reading evidence entry '${entry}': ${error49.message}`)}}return taskIds.sort()}async function deleteEvidence(directory,taskId){let sanitizedTaskId=sanitizeTaskId2(taskId),relativePath=path24.join("evidence",sanitizedTaskId),evidenceDir=validateSwarmPath(directory,relativePath);try{statSync8(evidenceDir)}catch{return!1}try{return rmSync(evidenceDir,{recursive:!0,force:!0}),!0}catch(error49){return warn(`Failed to delete evidence for task ${sanitizedTaskId}: ${error49 instanceof Error?error49.message:String(error49)}`),!1}}async function checkRequirementCoverage(phase,directory){let relativePath=path24.join("evidence",`req-coverage-phase-${phase}.json`),absolutePath=path24.resolve(directory,".swarm",relativePath);try{return await fs14.access(absolutePath),{exists:!0,path:absolutePath}}catch{return{exists:!1,path:absolutePath}}}async function archiveEvidence(directory,maxAgeDays,maxBundles,options){let taskIds=await _internals16.listEvidenceTaskIds(directory),cutoffDate=options?.now?new Date(options.now):_internals16.now();cutoffDate.setDate(cutoffDate.getDate()-maxAgeDays);let cutoffIso=cutoffDate.toISOString(),selected=new Set,selectedByAge=new Set,selectedByCount=new Set,archived=[],failed=[],remainingBundles=[];for(let taskId of taskIds){let result;try{result=await _internals16.loadEvidence(directory,taskId)}catch{warn("archive: skipping corrupt or unreadable evidence for task",taskId);continue}if(result.status!=="found")continue;if(result.bundle.updated_at<cutoffIso)selected.add(taskId),selectedByAge.add(taskId);else remainingBundles.push({taskId,updatedAt:result.bundle.updated_at})}if(maxBundles!==void 0&&remainingBundles.length>maxBundles){remainingBundles.sort((a,b)=>a.updatedAt.localeCompare(b.updatedAt));let toDelete=remainingBundles.length-maxBundles;for(let i=0;i<toDelete;i++)selected.add(remainingBundles[i].taskId),selectedByCount.add(remainingBundles[i].taskId)}if(!options?.dryRun)for(let taskId of[...selected].sort())if(await _internals16.deleteEvidence(directory,taskId))archived.push(taskId);else failed.push(taskId);let evaluation=await archiveEvaluationArtifacts({directory,maxAgeDays,maxBundles,dryRun:options?.dryRun,now:options?.now});if(options?.report)return{inventoryEvidence:[...taskIds].sort(),selectedEvidence:[...selected].sort(),selectedEvidenceByAge:[...selectedByAge].sort(),selectedEvidenceByCount:[...selectedByCount].sort(),archivedEvidence:archived.sort(),failedEvidence:failed.sort(),evaluation};return archived.sort()}function validateEvidence(evidence){return EvidenceSchema.parse(evidence)}var VALID_EVIDENCE_TYPES,sanitizeTaskId2,MAX_DEPTH=20,PROJECT_INDICATORS,LEGACY_TASK_COMPLEXITY_MAP,_internals16;var init_manager2=__esm(()=>{init_zod();init_evidence_schema();init_retention();init_utils2();init_utils();init_bun_compat();init_lock();init_task_id();VALID_EVIDENCE_TYPES=["review","test","diff","approval","note","retrospective","syntax","placeholder","sast","sbom","build","quality_budget","secretscan"];sanitizeTaskId2=sanitizeTaskId,PROJECT_INDICATORS=["package.json",".git",".opencode","Cargo.toml","go.mod","pyproject.toml","Gemfile","composer.json","pom.xml","build.gradle","CMakeLists.txt"];LEGACY_TASK_COMPLEXITY_MAP={low:"simple",medium:"moderate",high:"complex"};_internals16={wrapFlatRetrospective,loadEvidence,listEvidenceTaskIds,validateProjectRoot,validateEvidence,saveEvidence,deleteEvidence,now:()=>new Date}});function artifactLabel(artifact){return`${artifact.namespace}/${artifact.id}`}async function handleArchiveCommand(directory,args2){let config2=loadPluginConfig(directory),maxAgeDays=config2?.evidence?.max_age_days??90,maxBundles=config2?.evidence?.max_bundles??1000,dryRun=args2.includes("--dry-run"),report=await archiveEvidence(directory,maxAgeDays,maxBundles,{report:!0,dryRun,now:_internals17.now()}),evaluationSelected=report.evaluation.selected.map(artifactLabel),evaluationArchived=report.evaluation.archived.map(artifactLabel),selectedCount=report.selectedEvidence.length+evaluationSelected.length,archivedCount=report.archivedEvidence.length+evaluationArchived.length,corruptCount=report.evaluation.corrupt.length,inventoryCount=report.inventoryEvidence.length+report.evaluation.inventory.length;if(dryRun){if(selectedCount===0){if(corruptCount>0)return`No valid evidence bundles to archive. Preserved ${corruptCount} corrupt evaluation artifact(s) for data-quality review.`;if(inventoryCount===0)return"No evidence bundles to archive.";return`No evidence bundles older than ${maxAgeDays} days found, and bundle count (${inventoryCount}) is within max_bundles limit (${maxBundles}).`}let lines2=["## Archive Preview (dry run)","",`**Retention**: ${maxAgeDays} days`,`**Max bundles**: ${maxBundles}`,`**Would archive**: ${selectedCount} bundle(s)`];if(report.selectedEvidenceByAge.length>0)lines2.push("",`**Age-based (${report.selectedEvidenceByAge.length})**:`,...report.selectedEvidenceByAge.map((id)=>`- ${id}`));if(report.selectedEvidenceByCount.length>0)lines2.push("",`**Max bundles limit (${report.selectedEvidenceByCount.length})**:`,...report.selectedEvidenceByCount.map((id)=>`- ${id}`));let selectedRuns=report.evaluation.selected.filter((artifact)=>artifact.namespace==="evaluation-run"),selectedAudits=report.evaluation.selected.filter((artifact)=>artifact.namespace==="gate-audit");if(selectedRuns.length>0)lines2.push("",`**Evaluation runs (${selectedRuns.length})**:`,...selectedRuns.map((artifact)=>`- ${artifactLabel(artifact)}`));if(selectedAudits.length>0)lines2.push("",`**Gate-audit runs (${selectedAudits.length})**:`,...selectedAudits.map((artifact)=>`- ${artifactLabel(artifact)}`));if(report.evaluation.protected.length>0||corruptCount>0)lines2.push("",`**Evaluation artifacts preserved**: ${report.evaluation.protected.length} lineage-protected, ${corruptCount} corrupt/data-quality`);return lines2.join(`
@@ -301,12 +301,12 @@ ${warnings.map((w)=>` - ${w}`).join(`
301
301
  `).length,estimatedChanges=Math.min(lines/10,50);astChangeCount+=estimatedChanges;let fileComplexity=fileFunctionCount+lines/100;maxFileComplexity=Math.max(maxFileComplexity,fileComplexity)}catch{}}return{fileCount:changedFiles.length,functionCount,astChangeCount:Math.round(astChangeCount),maxFileComplexity:Math.round(maxFileComplexity*10)/10}}function routeReview(metrics){if(metrics.fileCount>=5||metrics.functionCount>=10||metrics.astChangeCount>=30||metrics.maxFileComplexity>=15)return{reviewerCount:2,testEngineerCount:2,depth:"double",reason:`High complexity: ${metrics.fileCount} files, ${metrics.functionCount} functions, complexity score ${metrics.maxFileComplexity}`};return{reviewerCount:1,testEngineerCount:1,depth:"single",reason:`Standard complexity: ${metrics.fileCount} files, ${metrics.functionCount} functions`}}async function routeReviewForChanges(directory,changedFiles){let metrics=await computeComplexity(directory,changedFiles);return routeReview(metrics)}function shouldParallelizeReview(routing){return routing.depth==="double"}var exports_scope_persistence={};__export(exports_scope_persistence,{writeScopeToDisk:()=>writeScopeToDisk,resolveScopeWithFallbacks:()=>resolveScopeWithFallbacks,readScopeFromDisk:()=>readScopeFromDisk,readPlanScope:()=>readPlanScope,clearScopeForTask:()=>clearScopeForTask,clearAllScopes:()=>clearAllScopes});import*as fs15 from"node:fs";import*as path27 from"node:path";function getScopesDir(directory){return path27.join(directory,SCOPES_DIR)}function isSafeTaskId(taskId){if(typeof taskId!=="string")return!1;if(!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(taskId))return!1;let head=taskId.replace(/\.+$/,"").split(".")[0].toUpperCase();if(WINDOWS_RESERVED.has(head))return!1;return!0}function isScopesDirSafe(directory,scopesDir){try{let resolvedWorkspace=fs15.realpathSync(directory),resolvedScopes=fs15.realpathSync(scopesDir),rel=path27.relative(resolvedWorkspace,resolvedScopes);return rel.length>0&&!rel.startsWith("..")&&!path27.isAbsolute(rel)}catch{return!1}}function getScopeFilePath(directory,taskId){if(!isSafeTaskId(taskId))throw Error(`Invalid taskId for scope persistence: ${taskId}`);return path27.join(getScopesDir(directory),`scope-${taskId}.json`)}async function writeScopeToDisk(directory,taskId,files,ttlMs=DEFAULT_TTL_MS){if(!isSafeTaskId(taskId))return;if(!Array.isArray(files)||files.length===0)return;if(files.length>MAX_FILES_PER_SCOPE)return;let scopesDir=getScopesDir(directory),scopePath=getScopeFilePath(directory,taskId);try{fs15.mkdirSync(scopesDir,{recursive:!0})}catch{return}if(!isScopesDirSafe(directory,scopesDir))return;let now=Date.now(),payload={version:SCOPE_SCHEMA_VERSION,taskId,declaredAt:now,expiresAt:now+ttlMs,files:[...files]},content=JSON.stringify(payload,null,2);try{let flags=fs15.constants.O_WRONLY|fs15.constants.O_CREAT,nofollow=fs15.constants.O_NOFOLLOW??0,fd=fs15.openSync(scopePath,flags|nofollow);fs15.closeSync(fd)}catch{return}let release;try{release=await import_proper_lockfile2.default.lock(scopePath,{stale:LOCK_STALE_MS,retries:{retries:3,minTimeout:50,maxTimeout:200},realpath:!1}),await atomicWrite(scopePath,content)}catch{}finally{if(release)try{await release()}catch{}}}async function atomicWrite(targetPath,content){let tempPath=`${targetPath}.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`;try{await bunWrite(tempPath,content),fs15.renameSync(tempPath,targetPath)}finally{try{fs15.unlinkSync(tempPath)}catch{}}}function readScopeFromDisk(directory,taskId){if(!isSafeTaskId(taskId))return null;let scopesDir=getScopesDir(directory);if(!isScopesDirSafe(directory,scopesDir))return null;let scopePath=getScopeFilePath(directory,taskId),nofollow=fs15.constants.O_NOFOLLOW??0,fd;try{fd=fs15.openSync(scopePath,fs15.constants.O_RDONLY|nofollow)}catch{return null}let raw;try{let stat5=fs15.fstatSync(fd);if(!stat5.isFile())return null;if(stat5.size>MAX_SCOPE_BYTES)return null;let buf=Buffer.alloc(stat5.size);fs15.readSync(fd,buf,0,stat5.size,0),raw=buf.toString("utf-8")}catch{return null}finally{try{fs15.closeSync(fd)}catch{}}if(!raw.trim())return null;let parsed;try{parsed=JSON.parse(raw)}catch{return null}if(parsed.version!==SCOPE_SCHEMA_VERSION)return null;if(parsed.taskId!==taskId)return null;let now=Date.now();if(typeof parsed.declaredAt!=="number"||parsed.declaredAt>now)return null;if(typeof parsed.expiresAt!=="number"||now>=parsed.expiresAt)return null;if(!Array.isArray(parsed.files))return null;if(parsed.files.length>MAX_FILES_PER_SCOPE)return null;let files=parsed.files.filter((f)=>typeof f==="string");return files.length>0?files:null}function readPlanScope(directory,taskId){if(!isSafeTaskId(taskId))return null;try{let planPath=path27.join(directory,".swarm","plan.json"),stat5=fs15.statSync(planPath);if(!stat5.isFile())return null;if(stat5.size>MAX_PLAN_BYTES)return null;let raw=fs15.readFileSync(planPath,"utf-8"),plan=JSON.parse(raw);for(let phase of plan.phases??[])for(let task of phase.tasks??[]){if(task.id!==taskId)continue;let ft=task.files_touched;if(Array.isArray(ft)&&ft.length>0){if(ft.length>MAX_FILES_PER_SCOPE)return null;return ft.filter((f)=>typeof f==="string")}if(typeof ft==="string"&&ft.length>0)return[ft];return null}return null}catch{return null}}function clearScopeForTask(directory,taskId){if(!isSafeTaskId(taskId))return;try{fs15.unlinkSync(getScopeFilePath(directory,taskId))}catch{}}function clearAllScopes(directory){try{fs15.rmSync(getScopesDir(directory),{recursive:!0,force:!0})}catch{}}function resolveScopeWithFallbacks(input){let{directory,taskId,inMemoryScope,pendingMapScope}=input;if(inMemoryScope&&inMemoryScope.length>0)return inMemoryScope;if(taskId){let disk=readScopeFromDisk(directory,taskId);if(disk&&disk.length>0)return disk;let plan=readPlanScope(directory,taskId);if(plan&&plan.length>0)return plan}if(pendingMapScope&&pendingMapScope.length>0)return pendingMapScope;return null}var import_proper_lockfile2,SCOPE_SCHEMA_VERSION=1,DEFAULT_TTL_MS=86400000,LOCK_STALE_MS=30000,SCOPES_DIR=".swarm/scopes",MAX_FILES_PER_SCOPE=1e4,MAX_PLAN_BYTES=10485760,MAX_SCOPE_BYTES=2097152,WINDOWS_RESERVED;var init_scope_persistence=__esm(()=>{init_bun_compat();import_proper_lockfile2=__toESM(require_proper_lockfile(),1),WINDOWS_RESERVED=new Set(["CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"])});var exports_core3={};__export(exports_core3,{writeLaneProfileToDiskReal:()=>writeLaneProfileToDiskReal,shortenWorktreePath:()=>shortenWorktreePath,resolveWorktreeBaseDir:()=>resolveWorktreeBaseDir,removeWorktree:()=>removeWorktree,removeLaneProfileFromDiskReal:()=>removeLaneProfileFromDiskReal,provisionWorktree:()=>provisionWorktree,makeWorktreeBranchName:()=>makeWorktreeBranchName,isPathUnderSwarmWorktreeBase:()=>isPathUnderSwarmWorktreeBase,isCleanWorktree:()=>isCleanWorktree,cleanUntrackedFiles:()=>cleanUntrackedFiles,checkPathBudget:()=>checkPathBudget,autoCommitDirty:()=>autoCommitDirty,assertCleanWorkingTree:()=>assertCleanWorkingTree,_internals:()=>_internals20});import*as fs16 from"node:fs";import*as fsPromises5 from"node:fs/promises";import*as os9 from"node:os";import*as path28 from"node:path";async function writeLaneProfileToDiskReal(worktreePath,laneIndex,envOverrides){let lines=[];for(let[key,value]of Object.entries(envOverrides)){if(value===null)continue;if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key))continue;if(value.includes(`
302
302
  `)||value.includes("\r")){log("writeLaneProfileToDisk: skipping env var with newline in value",{key});continue}lines.push(`${key}=${value}`)}if(lines.length===0)return;let lanesDir=path28.join(worktreePath,".swarm","lanes");await fs16.promises.mkdir(lanesDir,{recursive:!0});let envPath=path28.join(lanesDir,`${laneIndex}.env`);await fs16.promises.writeFile(envPath,`${lines.join(`
303
303
  `)}
304
- `,"utf-8")}async function removeLaneProfileFromDiskReal(worktreePath,laneIndex){let envPath=path28.join(worktreePath,".swarm","lanes",`${laneIndex}.env`);try{await fs16.promises.unlink(envPath)}catch(err){if(err.code!=="ENOENT")console.warn(`[worktree] Failed to remove lane profile ${envPath}: ${err.message}`)}}async function runGit2(args2,cwd,timeoutMs=WORKTREE_TIMEOUT_MS){let proc=_internals20.bunSpawn(["git",...args2],{cwd,timeout:timeoutMs,stdin:"ignore",stdout:"pipe",stderr:"pipe",env:{...process.env,LC_ALL:"C"}});try{let exitCode=await proc.exited,stdout=await proc.stdout.text(),stderr=await proc.stderr.text();return{exitCode,stdout,stderr}}finally{try{proc.kill()}catch{}}}async function checkPathBudget(worktreeRoot,directory){if(_internals20.platform!=="win32")return{ok:!0};let longPaths;try{longPaths=await _internals20.getCoreLongPaths(directory)}catch{}if(longPaths==="true")return{ok:!0};let proc=_internals20.bunSpawn(["git","ls-files"],{cwd:directory,timeout:WORKTREE_TIMEOUT_MS,stdin:"ignore",stdout:"pipe",stderr:"ignore",env:{...process.env,LC_ALL:"C"}});try{let exitCode=await proc.exited,stdout=await proc.stdout.text();if(exitCode!==0||stdout.trim().length===0)return{ok:!0};let files=stdout.split(/\r?\n/),longest=0;for(let file2 of files)if(file2.length>longest)longest=file2.length;let totalPathLength=worktreeRoot.length+1+longest;if(totalPathLength>=WIN_PATH_BUDGET)return{ok:!1,error:`Total path budget exceeded: worktree root "${worktreeRoot}" (${worktreeRoot.length} chars) + longest file "${files.find((f)=>f.length===longest)}" (${longest} chars) = ${totalPathLength} chars (budget: ${WIN_PATH_BUDGET})`,suggestion:"Set config.worktree_dir to a shorter absolute path, or let the auto-shorten feature relocate the worktree to the system temp directory."};return{ok:!0}}finally{try{proc.kill()}catch{}}}function shortenWorktreePath(_directory,sessionId,laneId){let tmp=_internals20.osTmpdir();try{tmp=fs16.realpathSync(tmp)}catch{}return path28.join(tmp,"swwt",sessionId,laneId)}function makeWorktreeBranchName(sessionId,id,options){if(options.branchStyle==="legacy-lane"&&options.purpose==="lane")return`swarm-lane/${sessionId}/${id}`;return`swarm/${options.purpose}/${sessionId}/${id}`}function resolveWorktreeBaseDir(directory,worktreeDir){return worktreeDir?path28.resolve(directory,worktreeDir):path28.resolve(path28.dirname(directory),".swarm-worktrees")}function isPathUnderSwarmWorktreeBase(targetPath,directory,worktreeDirOverrides=[]){let caseInsensitive=process.platform==="win32",realTarget;try{realTarget=fs16.realpathSync(path28.resolve(directory,targetPath))}catch{return!1}let bases=[resolveWorktreeBaseDir(directory),...worktreeDirOverrides.map((d)=>resolveWorktreeBaseDir(directory,d))],cmpTarget=caseInsensitive?realTarget.toLowerCase():realTarget;return bases.some((base)=>{let realBase;try{realBase=fs16.realpathSync(base)}catch{realBase=path28.resolve(base)}let cmpBase=caseInsensitive?realBase.toLowerCase():realBase;if(cmpTarget===cmpBase)return!0;let rel=path28.relative(cmpBase,cmpTarget);return rel.length>0&&!rel.startsWith("..")&&!path28.isAbsolute(rel)})}async function provisionWorktree(directory,id,sessionId,options){let branchName=makeWorktreeBranchName(sessionId,id,options),worktreePath=path28.resolve(resolveWorktreeBaseDir(directory,options.worktreeDir),sessionId,id),budgetResult=await checkPathBudget(worktreePath,directory);if(budgetResult.ok===!1)if(options.worktreeDir)console.warn(`[swarm] Path budget warning: ${budgetResult.error} ${budgetResult.suggestion}`);else{let shortPath=shortenWorktreePath(directory,sessionId,id);if((await checkPathBudget(shortPath,directory)).ok===!1)return{error:budgetResult.error};worktreePath=shortPath}if((await runGit2(["show-ref","--verify","--quiet",`refs/heads/${branchName}`],directory)).exitCode===0){let listResult=await runGit2(["worktree","list","--porcelain"],directory),normalizeGitPath=(p)=>{let lexical=p.replace(/\\/g,"/").replace(/\/+$/,"");try{return fs16.realpathSync(p).replace(/\\/g,"/").replace(/\/+$/,"")}catch{return lexical}},expectedPath=normalizeGitPath(worktreePath),entries=[],current={path:"",branch:void 0};if(listResult.exitCode!==0){let raw=listResult.stderr.trim()||listResult.stdout.trim();return{error:`worktree enumeration failed: ${raw.length>500?`${raw.slice(0,500)}... (truncated)`:raw}`}}for(let rawLine of listResult.stdout.split(`
305
- `)){let line=rawLine.trim();if(line.startsWith("worktree ")){if(current.path)entries.push(current);current={path:normalizeGitPath(line.slice(9)),branch:void 0}}else if(line.startsWith("branch "))current.branch=line.slice(7)}if(current.path)entries.push(current);let expectedPathIsRegistered=entries.some((e)=>e.path===expectedPath),branchIsActiveAtExpectedPath=entries.some((e)=>e.branch===`refs/heads/${branchName}`&&e.path===expectedPath);if(entries.some((e)=>e.branch===`refs/heads/${branchName}`&&e.path!==expectedPath)||expectedPathIsRegistered&&!branchIsActiveAtExpectedPath)return{error:`Branch already exists and worktree is active: ${branchName} (owned by another session)`};let aheadResult=await runGit2(["rev-list","--count",`HEAD..${branchName}`],directory);if(aheadResult.exitCode!==0)return{error:`Failed to inspect stale worktree branch: ${aheadResult.stderr.trim()||aheadResult.stdout.trim()}`};let aheadCount=Number.parseInt(aheadResult.stdout.trim(),10);if(!Number.isFinite(aheadCount)||aheadCount>0)return{error:`Branch already exists and has unmerged commits: ${branchName}`};if(branchIsActiveAtExpectedPath){if(!await isCleanWorktree(worktreePath))return{error:`Branch already exists and expected worktree is dirty: ${branchName}`};let removeResult=await removeWorktree(worktreePath,directory,{force:!0,worktreeDir:options.worktreeDir});if(!("success"in removeResult))return{error:removeResult.error}}let deleteResult=await runGit2(["branch","-d",branchName],directory);if(deleteResult.exitCode!==0)return{error:`Failed to delete stale worktree branch: ${deleteResult.stderr.trim()||deleteResult.stdout.trim()}`};await runGit2(["worktree","prune"],directory)}let addResult=await runGit2(["worktree","add","-b",branchName,worktreePath,"HEAD"],directory);if(addResult.exitCode!==0)return{error:`Failed to create worktree: ${addResult.stderr.trim()||addResult.stdout.trim()}`};let strategy=options.depsStrategy??"skip";if(strategy!=="skip"){let hostDepDir=path28.join(directory,"node_modules"),laneDepDir=path28.join(worktreePath,"node_modules");if(_internals20.fs.existsSync(hostDepDir))try{if(strategy==="copy")await _internals20.fs.cp(hostDepDir,laneDepDir,{recursive:!0,force:!0});else if(strategy==="link"){let isWindows=_internals20.platform==="win32";_internals20.fs.symlinkSync(hostDepDir,laneDepDir,isWindows?"junction":"dir")}}catch(e){console.warn(`[swarm] deps_strategy '${strategy}' preparation failed for ${id}: ${e instanceof Error?e.message:String(e)}`)}else return{error:`WORKTREE_DEPS_STRATEGY_HOST_DIR_MISSING: deps_strategy ${strategy} requires node_modules at ${hostDepDir} but it does not exist`}}if(options.scope?.taskId&&Array.isArray(options.scope.files))try{await _internals20.writeScopeToDisk(worktreePath,options.scope.taskId,options.scope.files)}catch{}if(options.laneProfile)try{await _internals20.writeLaneProfileToDisk(worktreePath,options.laneProfile.laneIndex,options.laneProfile.envOverrides)}catch{}return{worktreePath,branchName,purpose:options.purpose,id,sessionId}}async function removeWorktree(worktreePath,projectRoot,options){let isWindows=_internals20.platform==="win32",MAX_RETRIES=4,RETRY_DELAY_MS=2000,lastError="";for(let attempt=0;attempt<4;attempt++){let result=await runGit2(["worktree","remove",worktreePath],projectRoot);if(result.exitCode===0)return{success:!0};if(lastError=result.stderr.trim()||result.stdout.trim(),isWindows&&(lastError.includes("EBUSY")||lastError.includes("EPERM"))&&attempt<3){await _internals20.sleep(2000);continue}if(options?.force&&isPathUnderSwarmWorktreeBase(worktreePath,projectRoot,options.worktreeDir?[options.worktreeDir]:[])){let forced=await runGit2(["worktree","remove","--force",worktreePath],projectRoot);if(forced.exitCode===0)return{success:!0};return{error:forced.stderr.trim()||forced.stdout.trim()}}return{error:lastError}}return{error:lastError}}async function isCleanWorktree(worktreePath){let[statusResult,untrackedResult]=await Promise.all([runGit2(["status","--porcelain"],worktreePath),runGit2(["ls-files","--others","--exclude-standard"],worktreePath)]);if(statusResult.exitCode!==0||untrackedResult.exitCode!==0)return!1;let hasChanges=statusResult.stdout.trim().length>0,hasUntracked=untrackedResult.stdout.trim().length>0;return!hasChanges&&!hasUntracked}async function autoCommitDirty(worktreePath){let addResult=await runGit2(["add","-A"],worktreePath);if(addResult.exitCode!==0)return{committed:!1,reason:`git add failed: ${addResult.stderr.trim()||addResult.stdout.trim()}`};let commitResult=await runGit2(["commit","-m","swarm-lane: auto-commit before cleanup"],worktreePath);if(commitResult.exitCode!==0){let stderr=commitResult.stderr.trim(),stdout=commitResult.stdout.trim();if(stderr.includes("nothing to commit")||stdout.includes("nothing to commit")||stderr.includes("nothing added to commit"))return{committed:!1,reason:"Nothing to commit"};return{committed:!1,reason:`git commit failed: ${stderr||stdout}`}}return{committed:!0,message:"swarm-lane: auto-commit before cleanup"}}function isSafeToClean(candidatePath){let normalized=candidatePath.replace(/\\/g,"/").toLowerCase();return SAFE_CLEAN_PATTERNS.some((pattern)=>{let p=pattern.toLowerCase();if(p.endsWith("/"))return normalized.startsWith(p)||normalized.includes(`/${p}`);return normalized.endsWith(p)})}async function cleanUntrackedFiles(worktreePath){let dryRun=await runGit2(["clean","-fdn"],worktreePath);if(dryRun.exitCode===0){let unsafePaths=dryRun.stdout.trim().split(`
306
- `).map((line)=>{let match=line.match(/^Would remove (.+)$/);return match?match[1].trim():""}).filter((p)=>p.length>0).filter((p)=>!isSafeToClean(p));if(unsafePaths.length>0)return console.warn(`[swarm:cleanUntrackedFiles] Skipping clean — untracked source files detected: ${unsafePaths.join(", ")}`),{cleaned:!1,error:"untracked source files detected — skipping clean to prevent data loss"}}let result=await runGit2(["clean","-fd"],worktreePath);if(result.exitCode!==0)return{cleaned:!1,error:result.stderr.trim()||result.stdout.trim()};return{cleaned:!0}}async function assertCleanWorkingTree(directory){let[statusResult,untrackedResult]=await Promise.all([runGit2(["status","--porcelain"],directory),runGit2(["ls-files","--others","--exclude-standard"],directory)]);if(statusResult.exitCode!==0)return{clean:!1,error:`Unable to verify working tree cleanliness: ${statusResult.stderr.trim()||statusResult.stdout.trim()}`};if(untrackedResult.exitCode!==0)return{clean:!1,error:`Unable to verify working tree cleanliness: ${untrackedResult.stderr.trim()||untrackedResult.stdout.trim()}`};let hasChanges=statusResult.stdout.trim().length>0,hasUntracked=untrackedResult.stdout.trim().length>0;if(hasChanges||hasUntracked)return{clean:!1,error:"Working tree has uncommitted changes. Please commit or stash before provisioning worktrees. Run 'git status' for details."};return{clean:!0}}var _internals20,WORKTREE_TIMEOUT_MS=30000,WIN_PATH_BUDGET=250,SAFE_CLEAN_PATTERNS;var init_core3=__esm(()=>{init_utils();init_bun_compat();_internals20={bunSpawn,platform:process.platform,sleep:(ms)=>new Promise((resolve13)=>setTimeout(resolve13,ms)),osTmpdir:()=>os9.tmpdir(),getCoreLongPaths:async(directory)=>{let result=await runGit2(["config","core.longpaths"],directory);if(result.exitCode!==0)return;let value=result.stdout.trim().toLowerCase();return value===""?void 0:value},fs:{existsSync:fs16.existsSync,cp:fsPromises5.cp,cpSync:fs16.cpSync,symlinkSync:fs16.symlinkSync},writeScopeToDisk:async(directory,taskId,files)=>{let{writeScopeToDisk:realWrite}=await Promise.resolve().then(() => (init_scope_persistence(),exports_scope_persistence));return realWrite(directory,taskId,files)},writeLaneProfileToDisk:async(_worktreePath,_laneIndex,_envOverrides)=>{return writeLaneProfileToDiskReal(_worktreePath,_laneIndex,_envOverrides)},removeLaneProfileFromDisk:async(_worktreePath,_laneIndex)=>{return removeLaneProfileFromDiskReal(_worktreePath,_laneIndex)},removeWorktree};SAFE_CLEAN_PATTERNS=["dist/","build/",".turbo/","coverage/","node_modules/.cache/",".log",".tmp",".o",".pyc",".class"]});async function runGit3(args2,cwd,timeoutMs=MERGE_TIMEOUT_MS){let proc=_internals21.bunSpawn(["git",...args2],{cwd,timeout:timeoutMs,stdin:"ignore",stdout:"pipe",stderr:"pipe",env:{...process.env,LC_ALL:"C"}});try{let exitCode=await proc.exited,stdout=await proc.stdout.text(),stderr=await proc.stderr.text();return{exitCode,stdout,stderr}}finally{try{proc.kill()}catch{}}}function parseConflictFiles(output){let files=[],lines=output.split(`
307
- `);for(let line of lines){let match=line.match(/CONFLICT\b.*(?:Merge conflict in |in )(.+)/);if(match?.[1])files.push(match[1].trim())}return files}function getMergeStrategy(config2){return config2.mergeStrategy??config2.merge_strategy??"merge"}async function mergeLaneBranch(primaryDir,branchName,strategy){let result;switch(strategy){case"merge":result=await runGit3(["merge","--no-edit",branchName],primaryDir);break;case"rebase":result=await runGit3(["rebase",branchName],primaryDir);break;case"cherry-pick":{let mergeBaseResult=await runGit3(["merge-base","HEAD",branchName],primaryDir);if(mergeBaseResult.exitCode===0&&mergeBaseResult.stdout.trim()){let mergeBase=mergeBaseResult.stdout.trim();result=await runGit3(["cherry-pick",`${mergeBase}..${branchName}`],primaryDir)}else console.warn("[worktree] mergeLaneBranch: git merge-base failed for cherry-pick; falling back to tip-only cherry-pick"),result=await runGit3(["cherry-pick",branchName],primaryDir);break}}if(result.exitCode===0)return{merged:!0,strategy};let combinedOutput=`${result.stderr}
308
- ${result.stdout}`;if(/CONFLICT/i.test(combinedOutput)||/conflict/i.test(combinedOutput)){let files=parseConflictFiles(combinedOutput);return await runGit3(strategy==="rebase"?["rebase","--abort"]:strategy==="cherry-pick"?["cherry-pick","--abort"]:["merge","--abort"],primaryDir),{conflict:!0,files,message:result.stderr.trim()}}return{error:result.stderr.trim()||result.stdout.trim()}}async function postMergeCleanup(directory,branchName){let deleteResult=await runGit3(["branch","-D",branchName],directory),deleteOk=deleteResult.exitCode===0,pruneResult=await runGit3(["worktree","prune"],directory),pruneOk=pruneResult.exitCode===0;if(deleteOk&&pruneOk)return{cleaned:!0};if(!deleteOk&&pruneOk)return{error:`Branch delete failed: ${deleteResult.stderr.trim()||deleteResult.stdout.trim()}`,partial:!0};return{error:deleteOk?`Worktree prune failed: ${pruneResult.stderr.trim()||pruneResult.stdout.trim()}`:`Branch delete failed: ${deleteResult.stderr.trim()||deleteResult.stdout.trim()}; worktree prune failed: ${pruneResult.stderr.trim()||pruneResult.stdout.trim()}`}}async function attemptMergeBackFromDirty(worktreePath,branchName,primaryDir,strategy){let autoCommitted=!1,cleaned=!1,autoCommitFailed=!1,cleanFailed=!1,commitResult=await autoCommitDirty(worktreePath);if(commitResult.committed)autoCommitted=!0;else if(commitResult.reason!=="Nothing to commit")autoCommitFailed=!0,console.warn(`[worktree] attemptMergeBackFromDirty: auto-commit failed for worktree "${worktreePath}" branch "${branchName}": ${commitResult.reason}`);let cleanResult=await cleanUntrackedFiles(worktreePath);if(cleanResult.cleaned)cleaned=!0;else cleanFailed=!0,console.warn(`[worktree] attemptMergeBackFromDirty: clean untracked failed for worktree "${worktreePath}" branch "${branchName}": ${cleanResult.error}`);if(autoCommitFailed&&cleanFailed)return{failed:!0,stage:"cleanup",message:"Auto-commit and clean both failed; abandoning worktree"};let mergeResult=await mergeLaneBranch(primaryDir,branchName,strategy);if("merged"in mergeResult&&mergeResult.merged)return{merged:!0,strategy,autoCommitted,cleaned};if("conflict"in mergeResult)return{partial:!0,stage:"merge",autoCommitted,cleaned,message:mergeResult.message,conflictFiles:mergeResult.files};if("error"in mergeResult)return{failed:!0,stage:"merge",message:mergeResult.error};return{failed:!0,stage:"merge",message:"Merge failed with unexpected result"}}function extractSessionId(branchName){let segments=branchName.trim().split("/");if(segments.length>=3&&segments[0]==="swarm-lane")return segments[1];if(segments.length>=4&&segments[0]==="swarm"&&segments[1]==="lane")return segments[2];return null}async function listLaneBranches(directory){let branches=new Set,result=await runGit3(["branch","--format=%(refname:short)"],directory);if(result.exitCode===0)for(let line of result.stdout.split(`
309
- `)){let branch=line.trim();if(branch.length>0&&(branch.startsWith("swarm-lane/")||branch.startsWith("swarm/lane/")))branches.add(branch)}return[...branches]}async function cleanupOrphanedBranches(directory,activeSessionIds=[]){let removed=[],skipped=[],errors3=[],branches=await listLaneBranches(directory);for(let branch of branches){let sessionId=extractSessionId(branch);if(sessionId!==null&&activeSessionIds.includes(sessionId)){skipped.push(branch);continue}let deleteResult=await runGit3(["branch","-D",branch],directory);if(deleteResult.exitCode===0)removed.push(branch);else errors3.push({branch,error:deleteResult.stderr.trim()||deleteResult.stdout.trim()})}return await runGit3(["worktree","prune"],directory),{removed,skipped,errors:errors3}}async function startupOrphanRecovery(directory,activeSessionIds=[]){let warnings=[],pruneResult=await runGit3(["worktree","prune"],directory);if(pruneResult.exitCode!==0)warnings.push(`git worktree prune failed: ${pruneResult.stderr.trim()||pruneResult.stdout.trim()}`);let allBranches=await listLaneBranches(directory),orphanBranches=[];for(let branch of allBranches){let sessionId=extractSessionId(branch);if(sessionId===null||!activeSessionIds.includes(sessionId))orphanBranches.push(branch),warnings.push(`Orphaned swarm-lane branch "${branch}" detected in "${directory}"`)}for(let warning of warnings)console.warn(warning);return{prunedWorktrees:pruneResult.exitCode===0,remainingBranches:orphanBranches,warnings}}var _internals21,MERGE_TIMEOUT_MS=30000;var init_merge=__esm(()=>{init_bun_compat();init_core3();_internals21={bunSpawn,platform:process.platform,sleep:(ms)=>new Promise((resolve13)=>setTimeout(resolve13,ms)),cleanupOrphanedBranches,startupOrphanRecovery,extractSessionId}});var init_worktree=__esm(()=>{init_core3();init_merge()});import*as fs17 from"node:fs/promises";import*as path29 from"node:path";function parseLeanLaneIndex(laneId){let match=/^lane-(\d+)$/.exec(laneId);if(match){let n=parseInt(match[1],10);return Number.isNaN(n)?0:n-1}return 0}function computeLaneRuntimeProfile(runtime,laneIndex,worktreePath){if(!runtime?.enabled)return;let portStride=runtime.port_stride??1,envOverrides={};if(runtime.port_base!==void 0){let portBase=runtime.port_base,port=Math.min(portBase+laneIndex*portStride,65535);envOverrides.PORT=String(port)}if(runtime.env_overrides)Object.assign(envOverrides,runtime.env_overrides);if(runtime.cache_redirects)for(let[envName,basePath]of Object.entries(runtime.cache_redirects)){let laneSuffix=path29.join(basePath,`lane-${laneIndex}`);envOverrides[envName]=laneSuffix}return{laneIndex,worktreePath,envOverrides}}function allocateStandardLaneIndex(parentSessionID){let current=standardWorktreeLaneIndexBySession.get(parentSessionID)??0;return standardWorktreeLaneIndexBySession.set(parentSessionID,current+1),current}function rememberStandardWorktreeDispatch(dispatch){standardWorktreeByCallID.set(dispatch.callID,dispatch)}function hasStandardWorktreeDispatchCapacity(){return standardWorktreeByCallID.size<MAX_TRACKED_STANDARD_WORKTREE_CALLS}function hasInFlightStandardWorktreeDispatch(parentSessionID){for(let dispatch of standardWorktreeByCallID.values())if(dispatch.parentSessionID===parentSessionID)return!0;for(let record2 of awaitingMergeByCallID.values())if(record2.parentSessionID===parentSessionID)return!0;return!1}function handleStandardWorktreeFailure(parentSessionID,policy,message){if(policy==="required")throw Error(message);if(hasInFlightStandardWorktreeDispatch(parentSessionID))throw Error(`STANDARD_WORKTREE_ISOLATION_UNSAFE: ${message} Sibling coder task(s) are isolated in worktrees for this session, so dispatching this coder un-isolated in the main tree would risk a merge-back collision. Wait for in-flight coder task(s) to be reviewed and merged, then retry.`);serializeStandardWorktreeDispatches(parentSessionID,message)}function serializeStandardWorktreeDispatches(sessionID,message){if(!rememberStandardWorktreeSerializationSession(sessionID)){let session2=ensureAgentSession(sessionID);session2.pendingAdvisoryMessages??=[],session2.pendingAdvisoryMessages.push(`${message} Serialization tracking is at capacity (256 sessions active); continuing in normal parallel mode.`);return}let session=ensureAgentSession(sessionID);session.maxConcurrencyOverride=1,session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`${message} Serializing standard coder dispatches for this session.`)}function resetStandardWorktreeIsolationState(){standardWorktreeByCallID.clear(),standardWorktreeSerializationSessions.clear(),serializationStateBySessionID.clear(),awaitingMergeByCallID.clear(),standardWorktreeMergeQueue=Promise.resolve(),standardWorktreeLaneIndexBySession.clear()}function releaseStandardWorktreeSerialization(sessionID){if(!standardWorktreeSerializationSessions.has(sessionID))return!1;standardWorktreeSerializationSessions.delete(sessionID),serializationStateBySessionID.delete(sessionID);let session=ensureAgentSession(sessionID);return session.maxConcurrencyOverride=void 0,session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`WORKTREE_SERIALIZATION_RELEASED: ${sessionID} regains parallel dispatch eligibility (release-after-dispatches or TTL).`),!0}function checkStandardWorktreeSerializationRelease(sessionID,config2){let state=serializationStateBySessionID.get(sessionID);if(!state)return;let count=config2.serialization_release_after_dispatches??5,ttl=config2.serialization_release_after_ms??60000;if(state.successfulDispatchesSince>=count){releaseStandardWorktreeSerialization(sessionID);return}if(Date.now()-state.serializedAt>=ttl)releaseStandardWorktreeSerialization(sessionID)}function rememberStandardWorktreeSerializationSession(sessionID){if(standardWorktreeSerializationSessions.size>=MAX_TRACKED_STANDARD_WORKTREE_CALLS){let evicted=!1;for(let key of serializationStateBySessionID.keys())if(!hasInFlightStandardWorktreeDispatch(key)){standardWorktreeSerializationSessions.delete(key),serializationStateBySessionID.delete(key),evicted=!0;break}if(!evicted)return log(`[worktree-isolation] serialization set at cap with all sessions active; refusing eviction for ${sessionID}`),!1}if(standardWorktreeSerializationSessions.add(sessionID),!serializationStateBySessionID.has(sessionID))serializationStateBySessionID.set(sessionID,{sessionID,serializedAt:Date.now(),successfulDispatchesSince:0});return!0}function sanitizeWorktreeTaskId(raw){return raw.replace(/[^A-Za-z0-9._-]/g,"-").slice(0,64)||"task"}async function preProvisionCollisionCheck(taskId,directory,_sessionId){let proc=_internals22.bunSpawn(["git","-C",directory,"worktree","list","--porcelain"],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:WORKTREE_LIST_TIMEOUT_MS}),stdout="",stderr="";try{let exitCode=await proc.exited;if(stdout=await proc.stdout.text(),stderr=await proc.stderr.text(),exitCode!==0)return log(`[swarm] preProvisionCollisionCheck: git worktree list failed (exit ${exitCode}): ${stderr}`),{collision:!1}}finally{try{proc.kill()}catch{}}let entries=[],current={path:"",branch:void 0};for(let rawLine of stdout.split(`
304
+ `,"utf-8")}async function removeLaneProfileFromDiskReal(worktreePath,laneIndex){let envPath=path28.join(worktreePath,".swarm","lanes",`${laneIndex}.env`);try{await fs16.promises.unlink(envPath)}catch(err){if(err.code!=="ENOENT")log(`[worktree] Failed to remove lane profile ${envPath}: ${err.message}`)}}async function runGit2(args2,cwd,timeoutMs=WORKTREE_TIMEOUT_MS){let proc=_internals20.bunSpawn(["git",...args2],{cwd,timeout:timeoutMs,stdin:"ignore",stdout:"pipe",stderr:"pipe",env:{...process.env,LC_ALL:"C"}});try{let exitCode=await proc.exited,stdout=await proc.stdout.text(),stderr=await proc.stderr.text();return{exitCode,stdout,stderr}}finally{try{proc.kill()}catch{}}}async function checkPathBudget(worktreeRoot,directory){if(_internals20.platform!=="win32")return{ok:!0};let longPaths;try{longPaths=await _internals20.getCoreLongPaths(directory)}catch{}if(longPaths==="true")return{ok:!0};let proc=_internals20.bunSpawn(["git","ls-files"],{cwd:directory,timeout:WORKTREE_TIMEOUT_MS,stdin:"ignore",stdout:"pipe",stderr:"ignore",env:{...process.env,LC_ALL:"C"}});try{let exitCode=await proc.exited,stdout=await proc.stdout.text();if(exitCode!==0||stdout.trim().length===0)return{ok:!0};let files=stdout.split(/\r?\n/),longest=0;for(let file2 of files)if(file2.length>longest)longest=file2.length;let totalPathLength=worktreeRoot.length+1+longest;if(totalPathLength>=WIN_PATH_BUDGET)return{ok:!1,error:`Total path budget exceeded: worktree root "${worktreeRoot}" (${worktreeRoot.length} chars) + longest file "${files.find((f)=>f.length===longest)}" (${longest} chars) = ${totalPathLength} chars (budget: ${WIN_PATH_BUDGET})`,suggestion:"Set config.worktree_dir to a shorter absolute path, or let the auto-shorten feature relocate the worktree to the system temp directory."};return{ok:!0}}finally{try{proc.kill()}catch{}}}function shortenWorktreePath(_directory,sessionId,laneId){let tmp=_internals20.osTmpdir();try{tmp=fs16.realpathSync(tmp)}catch{}return path28.join(tmp,"swwt",sessionId,laneId)}function makeWorktreeBranchName(sessionId,id,options){if(options.branchStyle==="legacy-lane"&&options.purpose==="lane")return`swarm-lane/${sessionId}/${id}`;return`swarm/${options.purpose}/${sessionId}/${id}`}function resolveWorktreeBaseDir(directory,worktreeDir){return worktreeDir?path28.resolve(directory,worktreeDir):path28.resolve(path28.dirname(directory),".swarm-worktrees")}function isPathUnderSwarmWorktreeBase(targetPath,directory,worktreeDirOverrides=[]){let caseInsensitive=process.platform==="win32",realTarget;try{realTarget=fs16.realpathSync(path28.resolve(directory,targetPath))}catch{return!1}let bases=[resolveWorktreeBaseDir(directory),...worktreeDirOverrides.map((d)=>resolveWorktreeBaseDir(directory,d))],cmpTarget=caseInsensitive?realTarget.toLowerCase():realTarget;return bases.some((base)=>{let realBase;try{realBase=fs16.realpathSync(base)}catch{realBase=path28.resolve(base)}let cmpBase=caseInsensitive?realBase.toLowerCase():realBase;if(cmpTarget===cmpBase)return!0;let rel=path28.relative(cmpBase,cmpTarget);return rel.length>0&&!rel.startsWith("..")&&!path28.isAbsolute(rel)})}async function provisionWorktree(directory,id,sessionId,options){let branchName=makeWorktreeBranchName(sessionId,id,options),worktreePath=path28.resolve(resolveWorktreeBaseDir(directory,options.worktreeDir),sessionId,id),budgetResult=await checkPathBudget(worktreePath,directory);if(budgetResult.ok===!1)if(options.worktreeDir)advisoryWarn(`[swarm] Path budget warning: ${budgetResult.error} ${budgetResult.suggestion}`);else{let shortPath=shortenWorktreePath(directory,sessionId,id);if((await checkPathBudget(shortPath,directory)).ok===!1)return{error:budgetResult.error};worktreePath=shortPath}if((await runGit2(["show-ref","--verify","--quiet",`refs/heads/${branchName}`],directory)).exitCode===0){let listResult=await runGit2(["worktree","list","--porcelain"],directory),normalizeGitPath=(p)=>{let lexical=p.replace(/\\/g,"/").replace(/\/+$/,"");try{return fs16.realpathSync(p).replace(/\\/g,"/").replace(/\/+$/,"")}catch{return lexical}},expectedPath=normalizeGitPath(worktreePath),entries=[],current={path:"",branch:void 0};if(listResult.exitCode!==0){let raw=listResult.stderr.trim()||listResult.stdout.trim();return{error:`worktree enumeration failed: ${raw.length>500?`${raw.slice(0,500)}... (truncated)`:raw}`}}for(let rawLine of listResult.stdout.split(`
305
+ `)){let line=rawLine.trim();if(line.startsWith("worktree ")){if(current.path)entries.push(current);current={path:normalizeGitPath(line.slice(9)),branch:void 0}}else if(line.startsWith("branch "))current.branch=line.slice(7)}if(current.path)entries.push(current);let expectedPathIsRegistered=entries.some((e)=>e.path===expectedPath),branchIsActiveAtExpectedPath=entries.some((e)=>e.branch===`refs/heads/${branchName}`&&e.path===expectedPath);if(entries.some((e)=>e.branch===`refs/heads/${branchName}`&&e.path!==expectedPath)||expectedPathIsRegistered&&!branchIsActiveAtExpectedPath)return{error:`Branch already exists and worktree is active: ${branchName} (owned by another session)`};let aheadResult=await runGit2(["rev-list","--count",`HEAD..${branchName}`],directory);if(aheadResult.exitCode!==0)return{error:`Failed to inspect stale worktree branch: ${aheadResult.stderr.trim()||aheadResult.stdout.trim()}`};let aheadCount=Number.parseInt(aheadResult.stdout.trim(),10);if(!Number.isFinite(aheadCount)||aheadCount>0)return{error:`Branch already exists and has unmerged commits: ${branchName}`};if(branchIsActiveAtExpectedPath){if(!await isCleanWorktree(worktreePath))return{error:`Branch already exists and expected worktree is dirty: ${branchName}`};let removeResult=await removeWorktree(worktreePath,directory,{force:!0,worktreeDir:options.worktreeDir});if(!("success"in removeResult))return{error:removeResult.error}}let deleteResult=await runGit2(["branch","-d",branchName],directory);if(deleteResult.exitCode!==0)return{error:`Failed to delete stale worktree branch: ${deleteResult.stderr.trim()||deleteResult.stdout.trim()}`};await runGit2(["worktree","prune"],directory)}let addResult=await runGit2(["worktree","add","-b",branchName,worktreePath,"HEAD"],directory);if(addResult.exitCode!==0)return{error:`Failed to create worktree: ${addResult.stderr.trim()||addResult.stdout.trim()}`};let strategy=options.depsStrategy??"skip";if(strategy!=="skip"){let hostDepDir=path28.join(directory,"node_modules"),laneDepDir=path28.join(worktreePath,"node_modules");if(_internals20.fs.existsSync(hostDepDir))try{if(strategy==="copy")await _internals20.fs.cp(hostDepDir,laneDepDir,{recursive:!0,force:!0});else if(strategy==="link"){let isWindows=_internals20.platform==="win32";_internals20.fs.symlinkSync(hostDepDir,laneDepDir,isWindows?"junction":"dir")}}catch(e){log(`[swarm] deps_strategy '${strategy}' preparation failed for ${id}: ${e instanceof Error?e.message:String(e)}`)}else return{error:`WORKTREE_DEPS_STRATEGY_HOST_DIR_MISSING: deps_strategy ${strategy} requires node_modules at ${hostDepDir} but it does not exist`}}if(options.scope?.taskId&&Array.isArray(options.scope.files))try{await _internals20.writeScopeToDisk(worktreePath,options.scope.taskId,options.scope.files)}catch{}if(options.laneProfile)try{await _internals20.writeLaneProfileToDisk(worktreePath,options.laneProfile.laneIndex,options.laneProfile.envOverrides)}catch{}return{worktreePath,branchName,purpose:options.purpose,id,sessionId}}async function removeWorktree(worktreePath,projectRoot,options){let isWindows=_internals20.platform==="win32",MAX_RETRIES=4,RETRY_DELAY_MS=2000,lastError="";for(let attempt=0;attempt<4;attempt++){let result=await runGit2(["worktree","remove",worktreePath],projectRoot);if(result.exitCode===0)return{success:!0};if(lastError=result.stderr.trim()||result.stdout.trim(),isWindows&&(lastError.includes("EBUSY")||lastError.includes("EPERM"))&&attempt<3){await _internals20.sleep(2000);continue}if(options?.force&&isPathUnderSwarmWorktreeBase(worktreePath,projectRoot,options.worktreeDir?[options.worktreeDir]:[])){let forced=await runGit2(["worktree","remove","--force",worktreePath],projectRoot);if(forced.exitCode===0)return{success:!0};return{error:forced.stderr.trim()||forced.stdout.trim()}}return{error:lastError}}return{error:lastError}}async function isCleanWorktree(worktreePath){let[statusResult,untrackedResult]=await Promise.all([runGit2(["status","--porcelain"],worktreePath),runGit2(["ls-files","--others","--exclude-standard"],worktreePath)]);if(statusResult.exitCode!==0||untrackedResult.exitCode!==0)return!1;let hasChanges=statusResult.stdout.trim().length>0,hasUntracked=untrackedResult.stdout.trim().length>0;return!hasChanges&&!hasUntracked}async function autoCommitDirty(worktreePath){let addResult=await runGit2(["add","-A"],worktreePath);if(addResult.exitCode!==0)return{committed:!1,reason:`git add failed: ${addResult.stderr.trim()||addResult.stdout.trim()}`};let commitResult=await runGit2(["commit","-m","swarm-lane: auto-commit before cleanup"],worktreePath);if(commitResult.exitCode!==0){let stderr=commitResult.stderr.trim(),stdout=commitResult.stdout.trim();if(stderr.includes("nothing to commit")||stdout.includes("nothing to commit")||stderr.includes("nothing added to commit"))return{committed:!1,reason:"Nothing to commit"};return{committed:!1,reason:`git commit failed: ${stderr||stdout}`}}return{committed:!0,message:"swarm-lane: auto-commit before cleanup"}}function isSafeToClean(candidatePath){let normalized=candidatePath.replace(/\\/g,"/").toLowerCase();return SAFE_CLEAN_PATTERNS.some((pattern)=>{let p=pattern.toLowerCase();if(p.endsWith("/"))return normalized.startsWith(p)||normalized.includes(`/${p}`);return normalized.endsWith(p)})}async function cleanUntrackedFiles(worktreePath){let dryRun=await runGit2(["clean","-fdn"],worktreePath);if(dryRun.exitCode===0){let unsafePaths=dryRun.stdout.trim().split(`
306
+ `).map((line)=>{let match=line.match(/^Would remove (.+)$/);return match?match[1].trim():""}).filter((p)=>p.length>0).filter((p)=>!isSafeToClean(p));if(unsafePaths.length>0)return advisoryWarn(`[swarm:cleanUntrackedFiles] Skipping clean — untracked source files detected: ${unsafePaths.join(", ")}`),{cleaned:!1,error:"untracked source files detected — skipping clean to prevent data loss"}}let result=await runGit2(["clean","-fd"],worktreePath);if(result.exitCode!==0)return{cleaned:!1,error:result.stderr.trim()||result.stdout.trim()};return{cleaned:!0}}async function assertCleanWorkingTree(directory){let[statusResult,untrackedResult]=await Promise.all([runGit2(["status","--porcelain"],directory),runGit2(["ls-files","--others","--exclude-standard"],directory)]);if(statusResult.exitCode!==0)return{clean:!1,error:`Unable to verify working tree cleanliness: ${statusResult.stderr.trim()||statusResult.stdout.trim()}`};if(untrackedResult.exitCode!==0)return{clean:!1,error:`Unable to verify working tree cleanliness: ${untrackedResult.stderr.trim()||untrackedResult.stdout.trim()}`};let hasChanges=statusResult.stdout.trim().length>0,hasUntracked=untrackedResult.stdout.trim().length>0;if(hasChanges||hasUntracked)return{clean:!1,error:"Working tree has uncommitted changes. Please commit or stash before provisioning worktrees. Run 'git status' for details."};return{clean:!0}}var _internals20,WORKTREE_TIMEOUT_MS=30000,WIN_PATH_BUDGET=250,SAFE_CLEAN_PATTERNS;var init_core3=__esm(()=>{init_warning_buffer();init_utils();init_bun_compat();_internals20={bunSpawn,platform:process.platform,sleep:(ms)=>new Promise((resolve13)=>setTimeout(resolve13,ms)),osTmpdir:()=>os9.tmpdir(),getCoreLongPaths:async(directory)=>{let result=await runGit2(["config","core.longpaths"],directory);if(result.exitCode!==0)return;let value=result.stdout.trim().toLowerCase();return value===""?void 0:value},fs:{existsSync:fs16.existsSync,cp:fsPromises5.cp,cpSync:fs16.cpSync,symlinkSync:fs16.symlinkSync},writeScopeToDisk:async(directory,taskId,files)=>{let{writeScopeToDisk:realWrite}=await Promise.resolve().then(() => (init_scope_persistence(),exports_scope_persistence));return realWrite(directory,taskId,files)},writeLaneProfileToDisk:async(_worktreePath,_laneIndex,_envOverrides)=>{return writeLaneProfileToDiskReal(_worktreePath,_laneIndex,_envOverrides)},removeLaneProfileFromDisk:async(_worktreePath,_laneIndex)=>{return removeLaneProfileFromDiskReal(_worktreePath,_laneIndex)},removeWorktree};SAFE_CLEAN_PATTERNS=["dist/","build/",".turbo/","coverage/","node_modules/.cache/",".log",".tmp",".o",".pyc",".class"]});async function runGit3(args2,cwd,timeoutMs=MERGE_TIMEOUT_MS){let proc=_internals21.bunSpawn(["git",...args2],{cwd,timeout:timeoutMs,stdin:"ignore",stdout:"pipe",stderr:"pipe",env:{...process.env,LC_ALL:"C"}});try{let exitCode=await proc.exited,stdout=await proc.stdout.text(),stderr=await proc.stderr.text();return{exitCode,stdout,stderr}}finally{try{proc.kill()}catch{}}}function parseConflictFiles(output){let files=[],lines=output.split(`
307
+ `);for(let line of lines){let match=line.match(/CONFLICT\b.*(?:Merge conflict in |in )(.+)/);if(match?.[1])files.push(match[1].trim())}return files}function getMergeStrategy(config2){return config2.mergeStrategy??config2.merge_strategy??"merge"}async function mergeLaneBranch(primaryDir,branchName,strategy){let result;switch(strategy){case"merge":result=await runGit3(["merge","--no-edit",branchName],primaryDir);break;case"rebase":result=await runGit3(["rebase",branchName],primaryDir);break;case"cherry-pick":{let mergeBaseResult=await runGit3(["merge-base","HEAD",branchName],primaryDir);if(mergeBaseResult.exitCode===0&&mergeBaseResult.stdout.trim()){let mergeBase=mergeBaseResult.stdout.trim();result=await runGit3(["cherry-pick",`${mergeBase}..${branchName}`],primaryDir)}else log("[worktree] mergeLaneBranch: git merge-base failed for cherry-pick; falling back to tip-only cherry-pick"),result=await runGit3(["cherry-pick",branchName],primaryDir);break}}if(result.exitCode===0)return{merged:!0,strategy};let combinedOutput=`${result.stderr}
308
+ ${result.stdout}`;if(/CONFLICT/i.test(combinedOutput)||/conflict/i.test(combinedOutput)){let files=parseConflictFiles(combinedOutput);return await runGit3(strategy==="rebase"?["rebase","--abort"]:strategy==="cherry-pick"?["cherry-pick","--abort"]:["merge","--abort"],primaryDir),{conflict:!0,files,message:result.stderr.trim()}}return{error:result.stderr.trim()||result.stdout.trim()}}async function postMergeCleanup(directory,branchName){let deleteResult=await runGit3(["branch","-D",branchName],directory),deleteOk=deleteResult.exitCode===0,pruneResult=await runGit3(["worktree","prune"],directory),pruneOk=pruneResult.exitCode===0;if(deleteOk&&pruneOk)return{cleaned:!0};if(!deleteOk&&pruneOk)return{error:`Branch delete failed: ${deleteResult.stderr.trim()||deleteResult.stdout.trim()}`,partial:!0};return{error:deleteOk?`Worktree prune failed: ${pruneResult.stderr.trim()||pruneResult.stdout.trim()}`:`Branch delete failed: ${deleteResult.stderr.trim()||deleteResult.stdout.trim()}; worktree prune failed: ${pruneResult.stderr.trim()||pruneResult.stdout.trim()}`}}async function attemptMergeBackFromDirty(worktreePath,branchName,primaryDir,strategy){let autoCommitted=!1,cleaned=!1,autoCommitFailed=!1,cleanFailed=!1,commitResult=await autoCommitDirty(worktreePath);if(commitResult.committed)autoCommitted=!0;else if(commitResult.reason!=="Nothing to commit")autoCommitFailed=!0,log(`[worktree] attemptMergeBackFromDirty: auto-commit failed for worktree "${worktreePath}" branch "${branchName}": ${commitResult.reason}`);let cleanResult=await cleanUntrackedFiles(worktreePath);if(cleanResult.cleaned)cleaned=!0;else cleanFailed=!0,log(`[worktree] attemptMergeBackFromDirty: clean untracked failed for worktree "${worktreePath}" branch "${branchName}": ${cleanResult.error}`);if(autoCommitFailed&&cleanFailed)return{failed:!0,stage:"cleanup",message:"Auto-commit and clean both failed; abandoning worktree"};let mergeResult=await mergeLaneBranch(primaryDir,branchName,strategy);if("merged"in mergeResult&&mergeResult.merged)return{merged:!0,strategy,autoCommitted,cleaned};if("conflict"in mergeResult)return{partial:!0,stage:"merge",autoCommitted,cleaned,message:mergeResult.message,conflictFiles:mergeResult.files};if("error"in mergeResult)return{failed:!0,stage:"merge",message:mergeResult.error};return{failed:!0,stage:"merge",message:"Merge failed with unexpected result"}}function extractSessionId(branchName){let segments=branchName.trim().split("/");if(segments.length>=3&&segments[0]==="swarm-lane")return segments[1];if(segments.length>=4&&segments[0]==="swarm"&&segments[1]==="lane")return segments[2];return null}async function listLaneBranches(directory){let branches=new Set,result=await runGit3(["branch","--format=%(refname:short)"],directory);if(result.exitCode===0)for(let line of result.stdout.split(`
309
+ `)){let branch=line.trim();if(branch.length>0&&(branch.startsWith("swarm-lane/")||branch.startsWith("swarm/lane/")))branches.add(branch)}return[...branches]}async function cleanupOrphanedBranches(directory,activeSessionIds=[]){let removed=[],skipped=[],errors3=[],branches=await listLaneBranches(directory);for(let branch of branches){let sessionId=extractSessionId(branch);if(sessionId!==null&&activeSessionIds.includes(sessionId)){skipped.push(branch);continue}let deleteResult=await runGit3(["branch","-D",branch],directory);if(deleteResult.exitCode===0)removed.push(branch);else errors3.push({branch,error:deleteResult.stderr.trim()||deleteResult.stdout.trim()})}return await runGit3(["worktree","prune"],directory),{removed,skipped,errors:errors3}}async function startupOrphanRecovery(directory,activeSessionIds=[]){let warnings=[],pruneResult=await runGit3(["worktree","prune"],directory);if(pruneResult.exitCode!==0)warnings.push(`git worktree prune failed: ${pruneResult.stderr.trim()||pruneResult.stdout.trim()}`);let allBranches=await listLaneBranches(directory),orphanBranches=[];for(let branch of allBranches){let sessionId=extractSessionId(branch);if(sessionId===null||!activeSessionIds.includes(sessionId))orphanBranches.push(branch),warnings.push(`Orphaned swarm-lane branch "${branch}" detected in "${directory}"`)}for(let warning of warnings)log(warning);return{prunedWorktrees:pruneResult.exitCode===0,remainingBranches:orphanBranches,warnings}}var _internals21,MERGE_TIMEOUT_MS=30000;var init_merge=__esm(()=>{init_utils();init_bun_compat();init_core3();_internals21={bunSpawn,platform:process.platform,sleep:(ms)=>new Promise((resolve13)=>setTimeout(resolve13,ms)),cleanupOrphanedBranches,startupOrphanRecovery,extractSessionId}});var init_worktree=__esm(()=>{init_core3();init_merge()});import*as fs17 from"node:fs/promises";import*as path29 from"node:path";function parseLeanLaneIndex(laneId){let match=/^lane-(\d+)$/.exec(laneId);if(match){let n=parseInt(match[1],10);return Number.isNaN(n)?0:n-1}return 0}function computeLaneRuntimeProfile(runtime,laneIndex,worktreePath){if(!runtime?.enabled)return;let portStride=runtime.port_stride??1,envOverrides={};if(runtime.port_base!==void 0){let portBase=runtime.port_base,port=Math.min(portBase+laneIndex*portStride,65535);envOverrides.PORT=String(port)}if(runtime.env_overrides)Object.assign(envOverrides,runtime.env_overrides);if(runtime.cache_redirects)for(let[envName,basePath]of Object.entries(runtime.cache_redirects)){let laneSuffix=path29.join(basePath,`lane-${laneIndex}`);envOverrides[envName]=laneSuffix}return{laneIndex,worktreePath,envOverrides}}function allocateStandardLaneIndex(parentSessionID){let current=standardWorktreeLaneIndexBySession.get(parentSessionID)??0;return standardWorktreeLaneIndexBySession.set(parentSessionID,current+1),current}function rememberStandardWorktreeDispatch(dispatch){standardWorktreeByCallID.set(dispatch.callID,dispatch)}function hasStandardWorktreeDispatchCapacity(){return standardWorktreeByCallID.size<MAX_TRACKED_STANDARD_WORKTREE_CALLS}function hasInFlightStandardWorktreeDispatch(parentSessionID){for(let dispatch of standardWorktreeByCallID.values())if(dispatch.parentSessionID===parentSessionID)return!0;for(let record2 of awaitingMergeByCallID.values())if(record2.parentSessionID===parentSessionID)return!0;return!1}function handleStandardWorktreeFailure(parentSessionID,policy,message){if(policy==="required")throw Error(message);if(hasInFlightStandardWorktreeDispatch(parentSessionID))throw Error(`STANDARD_WORKTREE_ISOLATION_UNSAFE: ${message} Sibling coder task(s) are isolated in worktrees for this session, so dispatching this coder un-isolated in the main tree would risk a merge-back collision. Wait for in-flight coder task(s) to be reviewed and merged, then retry.`);serializeStandardWorktreeDispatches(parentSessionID,message)}function serializeStandardWorktreeDispatches(sessionID,message){if(!rememberStandardWorktreeSerializationSession(sessionID)){let session2=ensureAgentSession(sessionID);session2.pendingAdvisoryMessages??=[],session2.pendingAdvisoryMessages.push(`${message} Serialization tracking is at capacity (256 sessions active); continuing in normal parallel mode.`);return}let session=ensureAgentSession(sessionID);session.maxConcurrencyOverride=1,session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`${message} Serializing standard coder dispatches for this session.`)}function resetStandardWorktreeIsolationState(){standardWorktreeByCallID.clear(),standardWorktreeSerializationSessions.clear(),serializationStateBySessionID.clear(),awaitingMergeByCallID.clear(),standardWorktreeMergeQueue=Promise.resolve(),standardWorktreeLaneIndexBySession.clear()}function releaseStandardWorktreeSerialization(sessionID){if(!standardWorktreeSerializationSessions.has(sessionID))return!1;standardWorktreeSerializationSessions.delete(sessionID),serializationStateBySessionID.delete(sessionID);let session=ensureAgentSession(sessionID);return session.maxConcurrencyOverride=void 0,session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`WORKTREE_SERIALIZATION_RELEASED: ${sessionID} regains parallel dispatch eligibility (release-after-dispatches or TTL).`),!0}function checkStandardWorktreeSerializationRelease(sessionID,config2){let state=serializationStateBySessionID.get(sessionID);if(!state)return;let count=config2.serialization_release_after_dispatches??5,ttl=config2.serialization_release_after_ms??60000;if(state.successfulDispatchesSince>=count){releaseStandardWorktreeSerialization(sessionID);return}if(Date.now()-state.serializedAt>=ttl)releaseStandardWorktreeSerialization(sessionID)}function rememberStandardWorktreeSerializationSession(sessionID){if(standardWorktreeSerializationSessions.size>=MAX_TRACKED_STANDARD_WORKTREE_CALLS){let evicted=!1;for(let key of serializationStateBySessionID.keys())if(!hasInFlightStandardWorktreeDispatch(key)){standardWorktreeSerializationSessions.delete(key),serializationStateBySessionID.delete(key),evicted=!0;break}if(!evicted)return log(`[worktree-isolation] serialization set at cap with all sessions active; refusing eviction for ${sessionID}`),!1}if(standardWorktreeSerializationSessions.add(sessionID),!serializationStateBySessionID.has(sessionID))serializationStateBySessionID.set(sessionID,{sessionID,serializedAt:Date.now(),successfulDispatchesSince:0});return!0}function sanitizeWorktreeTaskId(raw){return raw.replace(/[^A-Za-z0-9._-]/g,"-").slice(0,64)||"task"}async function preProvisionCollisionCheck(taskId,directory,_sessionId){let proc=_internals22.bunSpawn(["git","-C",directory,"worktree","list","--porcelain"],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:WORKTREE_LIST_TIMEOUT_MS}),stdout="",stderr="";try{let exitCode=await proc.exited;if(stdout=await proc.stdout.text(),stderr=await proc.stderr.text(),exitCode!==0)return log(`[swarm] preProvisionCollisionCheck: git worktree list failed (exit ${exitCode}): ${stderr}`),{collision:!1}}finally{try{proc.kill()}catch{}}let entries=[],current={path:"",branch:void 0};for(let rawLine of stdout.split(`
310
310
  `)){let line=rawLine.trim();if(line.startsWith("worktree ")){if(current.path)entries.push(current);current={path:line.slice(9),branch:void 0}}else if(line.startsWith("branch "))current.branch=line.slice(7)}if(current.path)entries.push(current);for(let entry of entries){if(!entry.branch)continue;let branchName=entry.branch.startsWith("refs/heads/")?entry.branch.slice(11):entry.branch,segments=branchName.split("/");if(segments.length>=4&&segments[0]==="swarm"&&segments[1]==="lane"){if(segments[3]===taskId){let ownerSessionId=segments[2];return{collision:!0,existingBranch:branchName,ownerSessionId,worktreePath:entry.path}}}if(segments.length>=3&&segments[0]==="swarm-lane"){if(segments[2]===taskId){let ownerSessionId=segments[1];return{collision:!0,existingBranch:branchName,ownerSessionId,worktreePath:entry.path}}}}return{collision:!1}}function isLaneOwnedByCurrentSession(branchName,expectedSessionId){return _internals21.extractSessionId(branchName)===expectedSessionId}async function precreateStandardWorktreeSession(args2){let worktreeConfig=resolveWorktreeIsolationConfig(args2.config);if(worktreeConfig.policy==="disabled")return;if(standardWorktreeSerializationSessions.has(args2.parentSessionID)){if(checkStandardWorktreeSerializationRelease(args2.parentSessionID,worktreeConfig),!standardWorktreeSerializationSessions.has(args2.parentSessionID))return}if(!hasStandardWorktreeDispatchCapacity()){if(worktreeConfig.policy==="required")throw Error("STANDARD_WORKTREE_TRACKING_CAP_EXCEEDED: too many standard worktree coder dispatches are already awaiting merge-back.");serializeStandardWorktreeDispatches(args2.parentSessionID,"STANDARD_WORKTREE_TRACKING_CAP_EXCEEDED: too many standard worktree coder dispatches are already awaiting merge-back.");return}let client=swarmState.opencodeClient;if(!client){handleStandardWorktreeFailure(args2.parentSessionID,worktreeConfig.policy,"STANDARD_WORKTREE_ISOLATION_UNAVAILABLE: OpenCode SDK client is unavailable; standard parallel coder work cannot be isolated.");return}try{await _internals22.startupOrphanRecovery(args2.directory,[args2.parentSessionID])}catch(recoveryError){log(`[swarm] startup orphan recovery failed: ${recoveryError}`)}try{await _internals22.cleanupOrphanedBranches(args2.directory,[args2.parentSessionID])}catch(cleanupError){log(`[swarm] orphaned branch cleanup failed: ${cleanupError}`)}let collision=await preProvisionCollisionCheck(args2.taskId,args2.directory,args2.parentSessionID);if(collision.collision)if(collision.existingBranch?isLaneOwnedByCurrentSession(collision.existingBranch,args2.parentSessionID):!1){let session=ensureAgentSession(args2.parentSessionID);session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`FR-001b PREPROVISION: stale lane detected for task ${args2.taskId} (session ${args2.parentSessionID}); cleaning up before re-provisioning.`);try{let callID=null;for(let[id,dispatch]of _internals22.standardWorktreeByCallID)if(dispatch.handle.branchName===collision.existingBranch){callID=id;break}if(!callID){for(let[id,record2]of _internals22.awaitingMergeByCallID)if(record2.branch===collision.existingBranch){callID=id;break}}if(callID)await _internals22.cleanupStandardWorktreeForCallId(callID,"denied",args2.directory,worktreeConfig.worktree_dir);else{if(collision.worktreePath){let preserveResult=await _internals22.preserveDirtyWorktreeAtPath(collision.worktreePath,collision.existingBranch,"denied",args2.directory,worktreeConfig.worktree_dir);if(preserveResult.outcome==="preserve-failed"){let session2=ensureAgentSession(args2.parentSessionID);session2.pendingAdvisoryMessages??=[],session2.pendingAdvisoryMessages.push(`STANDARD_WORKTREE_PRESERVATION_FAILED_ABORT_CLEANUP: pre-provision collision for task ${args2.taskId} has dirty uncommitted work but preservation failed (${preserveResult.error}). Cleanup aborted to protect uncommitted work. Worktree=${collision.worktreePath}; branch=${collision.existingBranch}.`);return}await _internals22.removeWorktree(collision.worktreePath,args2.directory,{force:!0,worktreeDir:worktreeConfig.worktree_dir})}await _internals22.postMergeCleanup(args2.directory,collision.existingBranch)}}catch(cleanupError){log(`[swarm] preProvision collision cleanup failed: ${cleanupError}; proceeding with provisioning anyway`)}}else{let ownerInfo=collision.ownerSessionId?` (owned by session ${collision.ownerSessionId})`:"",message=`FR-001b PREPROVISION_COLLISION: task ${args2.taskId} already has an active lane on branch ${collision.existingBranch}${ownerInfo}. Waiting for the owning session to complete and merge before retrying.`,session=ensureAgentSession(args2.parentSessionID);session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(message),handleStandardWorktreeFailure(args2.parentSessionID,worktreeConfig.policy,`PREPROVISION_COLLISION: ${message}`);return}let laneIndex=allocateStandardLaneIndex(args2.parentSessionID),provisionResult=await _internals22.provisionWorktree(args2.directory,args2.taskId,args2.parentSessionID,{purpose:"lane",worktreeDir:worktreeConfig.worktree_dir,mergeStrategy:worktreeConfig.merge_strategy,depsStrategy:worktreeConfig.deps_strategy,scope:args2.scope});if("error"in provisionResult){let message=`STANDARD_WORKTREE_PROVISION_FAILED: ${provisionResult.error}.`;handleStandardWorktreeFailure(args2.parentSessionID,worktreeConfig.policy,message);return}let laneProfile=computeLaneRuntimeProfile(worktreeConfig.runtime_isolation,laneIndex,provisionResult.worktreePath);if(laneProfile)try{let{writeLaneProfileToDiskReal:writeLaneProfileToDiskReal2}=await Promise.resolve().then(() => (init_core3(),exports_core3));await writeLaneProfileToDiskReal2(provisionResult.worktreePath,laneProfile.laneIndex,laneProfile.envOverrides)}catch{}if((worktreeConfig.deps_strategy??"skip")==="skip"){let desc=(args2.description??args2.taskId??"").toLowerCase();if(desc.includes("test")||desc.includes("build")||desc.includes("lint")||desc.includes("check")){let session=ensureAgentSession(args2.parentSessionID);session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`WORKTREE_DEPS_SKIP: task ${args2.taskId} was provisioned with deps_strategy: 'skip' (default). This task's gates appear to include test/build commands; the lane may lack node_modules. Set worktree.deps_strategy to 'copy' or 'link' (or use a non-worktree lane) if the task requires host dependencies.`)}}let createResult=await client.session.create({body:{parentID:args2.parentSessionID,title:`${args2.description??args2.taskId} (worktree lane)`},query:{directory:provisionResult.worktreePath}});if(!createResult.data?.id){await _internals22.removeWorktree(provisionResult.worktreePath,args2.directory,{force:!0,worktreeDir:worktreeConfig.worktree_dir}).catch(()=>{});let createError=createResult.error,message=`STANDARD_WORKTREE_SESSION_CREATE_FAILED: ${typeof createError==="string"?createError:JSON.stringify(createError??"missing session id")}.`;handleStandardWorktreeFailure(args2.parentSessionID,worktreeConfig.policy,message);return}args2.outputArgs.task_id=createResult.data.id,rememberStandardWorktreeDispatch({callID:args2.callID,parentSessionID:args2.parentSessionID,taskId:args2.taskId,planTaskId:args2.planTaskId,handle:provisionResult,mergeStrategy:worktreeConfig.merge_strategy,laneIndex,worktree_dir:worktreeConfig.worktree_dir})}async function preserveDirtyWorktreeForCallId(callID,reason,_directory,_worktree_dir){let dispatch=standardWorktreeByCallID.get(callID),worktreePath,parentSessionID;if(dispatch)worktreePath=dispatch.handle.worktreePath,parentSessionID=dispatch.parentSessionID;else{let awaiting=awaitingMergeByCallID.get(callID);if(!awaiting)return{outcome:"clean",preserved:!1};worktreePath=awaiting.worktreePath,parentSessionID=awaiting.parentSessionID}let statusProc=_internals22.bunSpawn(["git","-C",worktreePath,"status","--porcelain"],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:PRESERVE_COMMIT_TIMEOUT_MS}),statusStdout="",statusStderr="";try{let exitCode=await statusProc.exited;if(statusStdout=await statusProc.stdout.text(),statusStderr=await statusProc.stderr.text(),exitCode!==0)return log(`[swarm] preserveDirtyWorktreeForCallId: git status failed for ${callID}: ${statusStderr}`),{outcome:"preserve-failed",preserved:!1,error:`git status failed: ${statusStderr||`exit ${exitCode}`}`}}finally{try{statusProc.kill()}catch{}}if(statusStdout.trim()==="")return{outcome:"clean",preserved:!1};let addProc=_internals22.bunSpawn(["git","-C",worktreePath,"add","-A"],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:PRESERVE_COMMIT_TIMEOUT_MS});try{let addExit=await addProc.exited;if(addExit!==0){let addErr=await addProc.stderr.text();return log(`[swarm] preserveDirtyWorktreeForCallId: git add failed for ${callID}: ${addErr}`),{outcome:"preserve-failed",preserved:!1,error:`git add failed: ${addErr||`exit ${addExit}`}`}}}finally{try{addProc.kill()}catch{}}let isoDate=new Date().toISOString(),sanitizedCallID=callID.replace(/[^A-Za-z0-9._-]/g,"-").slice(0,64),commitMessage=`swarm-preserved: ${reason} for callID ${sanitizedCallID} at ${isoDate}`,commitProc=_internals22.bunSpawn(["git","-C",worktreePath,"commit","-m",commitMessage],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:PRESERVE_COMMIT_TIMEOUT_MS}),commitHash="";try{let commitExit=await commitProc.exited;if(commitExit!==0){let commitErr=await commitProc.stderr.text();return log(`[swarm] preserveDirtyWorktreeForCallId: git commit failed for ${callID}: ${commitErr}`),{outcome:"preserve-failed",preserved:!1,error:`git commit failed: ${commitErr||`exit ${commitExit}`}`}}}finally{try{commitProc.kill()}catch{}}let hashProc=_internals22.bunSpawn(["git","-C",worktreePath,"rev-parse","HEAD"],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:PRESERVE_COMMIT_TIMEOUT_MS});try{let hashExit=await hashProc.exited;if(hashExit!==0){let hashErr=await hashProc.stderr.text();return log(`[swarm] preserveDirtyWorktreeForCallId: git rev-parse failed for ${callID}: ${hashErr}`),{outcome:"preserve-failed",preserved:!1,error:`git rev-parse failed: ${hashErr||`exit ${hashExit}`}`}}commitHash=(await hashProc.stdout.text()).trim()}finally{try{hashProc.kill()}catch{}}if(!commitHash)return{outcome:"preserve-failed",preserved:!1,error:"git rev-parse returned empty hash"};let shortHash=commitHash.slice(0,8),tagName=`swarm-preserved-${sanitizedCallID}-${shortHash}`,tagProc=_internals22.bunSpawn(["git","-C",worktreePath,"tag",tagName],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:PRESERVE_COMMIT_TIMEOUT_MS});try{let tagExit=await tagProc.exited;if(tagExit!==0){let tagErr=await tagProc.stderr.text();return log(`[swarm] preserveDirtyWorktreeForCallId: git tag failed for ${callID}: ${tagErr}`),{outcome:"preserve-failed",preserved:!1,error:`git tag failed: ${tagErr||`exit ${tagExit}`}`}}}finally{try{tagProc.kill()}catch{}}let session=ensureAgentSession(parentSessionID);return session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`STANDARD_WORKTREE_PRESERVED: dispatch ${callID} dirty work preserved as commit ${commitHash} (tag: ${tagName}; reason: ${reason}); worktree will be cleaned.`),{outcome:"preserved",preserved:!0,ref:commitHash}}async function preserveDirtyWorktreeAtPath(worktreePath,branchName,reason,_directory,_worktree_dir){let statusProc=_internals22.bunSpawn(["git","-C",worktreePath,"status","--porcelain"],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:PRESERVE_COMMIT_TIMEOUT_MS}),statusStdout="",statusStderr="";try{let exitCode=await statusProc.exited;if(statusStdout=await statusProc.stdout.text(),statusStderr=await statusProc.stderr.text(),exitCode!==0)return log(`[swarm] preserveDirtyWorktreeAtPath: git status failed for ${worktreePath}: ${statusStderr}`),{outcome:"preserve-failed",preserved:!1,error:`git status failed: ${statusStderr||`exit ${exitCode}`}`}}finally{try{statusProc.kill()}catch{}}if(statusStdout.trim()==="")return{outcome:"clean",preserved:!1};let addProc=_internals22.bunSpawn(["git","-C",worktreePath,"add","-A"],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:PRESERVE_COMMIT_TIMEOUT_MS});try{let addExit=await addProc.exited;if(addExit!==0){let addErr=await addProc.stderr.text();return log(`[swarm] preserveDirtyWorktreeAtPath: git add failed for ${worktreePath}: ${addErr}`),{outcome:"preserve-failed",preserved:!1,error:`git add failed: ${addErr||`exit ${addExit}`}`}}}finally{try{addProc.kill()}catch{}}let isoDate=new Date().toISOString(),sanitizedPath=worktreePath.replace(/[^A-Za-z0-9._-]/g,"-").slice(0,64),sanitizedBranch=branchName.replace(/[^A-Za-z0-9._-]/g,"-").slice(0,64),commitMessage=`swarm-preserved: ${reason} for worktree ${sanitizedPath} at ${isoDate}`,commitProc=_internals22.bunSpawn(["git","-C",worktreePath,"commit","-m",commitMessage],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:PRESERVE_COMMIT_TIMEOUT_MS}),commitHash="";try{let commitExit=await commitProc.exited;if(commitExit!==0){let commitErr=await commitProc.stderr.text();return log(`[swarm] preserveDirtyWorktreeAtPath: git commit failed for ${worktreePath}: ${commitErr}`),{outcome:"preserve-failed",preserved:!1,error:`git commit failed: ${commitErr||`exit ${commitExit}`}`}}}finally{try{commitProc.kill()}catch{}}let hashProc=_internals22.bunSpawn(["git","-C",worktreePath,"rev-parse","HEAD"],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:PRESERVE_COMMIT_TIMEOUT_MS});try{let hashExit=await hashProc.exited;if(hashExit!==0){let hashErr=await hashProc.stderr.text();return log(`[swarm] preserveDirtyWorktreeAtPath: git rev-parse failed for ${worktreePath}: ${hashErr}`),{outcome:"preserve-failed",preserved:!1,error:`git rev-parse failed: ${hashErr||`exit ${hashExit}`}`}}commitHash=(await hashProc.stdout.text()).trim()}finally{try{hashProc.kill()}catch{}}if(!commitHash)return{outcome:"preserve-failed",preserved:!1,error:"git rev-parse returned empty hash"};let shortHash=commitHash.slice(0,8),tagName=`swarm-preserved-worktree-${sanitizedBranch}-${shortHash}`,tagProc=_internals22.bunSpawn(["git","-C",worktreePath,"tag",tagName],{stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:PRESERVE_COMMIT_TIMEOUT_MS});try{let tagExit=await tagProc.exited;if(tagExit!==0){let tagErr=await tagProc.stderr.text();return log(`[swarm] preserveDirtyWorktreeAtPath: git tag failed for ${worktreePath}: ${tagErr}`),{outcome:"preserve-failed",preserved:!1,error:`git tag failed: ${tagErr||`exit ${tagExit}`}`}}}finally{try{tagProc.kill()}catch{}}return{outcome:"preserved",preserved:!0,ref:commitHash}}async function cleanupStandardWorktreeForCallId(callID,reason,directory,worktree_dir){let dispatch=standardWorktreeByCallID.get(callID),worktreePath,branchName,parentSessionID;if(dispatch)worktreePath=dispatch.handle.worktreePath,branchName=dispatch.handle.branchName,parentSessionID=dispatch.parentSessionID;else{let awaiting=awaitingMergeByCallID.get(callID);if(!awaiting)return;worktreePath=awaiting.worktreePath,branchName=awaiting.branch,parentSessionID=awaiting.parentSessionID}let preserveResult;if(reason==="denied"||reason==="cancelled"){try{preserveResult=await _internals22.preserveDirtyWorktreeForCallId(callID,reason,directory,worktree_dir)}catch(err){log(`[swarm] cleanupStandardWorktreeForCallId: preserveDirtyWorktreeForCallId threw for ${callID}: ${err}`),preserveResult={outcome:"preserve-failed",preserved:!1,error:String(err)}}if(preserveResult.outcome==="clean")try{preserveResult=await _internals22.preserveDirtyWorktreeForCallId(callID,reason,directory,worktree_dir)}catch(err){log(`[swarm] cleanupStandardWorktreeForCallId: final preservation check threw for ${callID}: ${err}`),preserveResult={outcome:"preserve-failed",preserved:!1,error:String(err)}}}if(preserveResult&&preserveResult.outcome==="preserve-failed"){standardWorktreeByCallID.delete(callID),awaitingMergeByCallID.delete(callID);let session2=ensureAgentSession(parentSessionID);session2.pendingAdvisoryMessages??=[],session2.pendingAdvisoryMessages.push(`STANDARD_WORKTREE_PRESERVATION_FAILED_ABORT_CLEANUP: dispatch ${callID} has dirty uncommitted work but preservation failed (${preserveResult.error}). Cleanup aborted to protect uncommitted work. Investigate and resolve manually. Worktree=${worktreePath}; branch=${branchName}.`);return}await _internals22.removeWorktree(worktreePath,directory,{force:!0,worktreeDir:worktree_dir}).catch((err)=>log(`[swarm] cleanupStandardWorktreeForCallId: removeWorktree failed for ${callID}: ${err}`)),await _internals22.postMergeCleanup(directory,branchName).catch((err)=>log(`[swarm] cleanupStandardWorktreeForCallId: postMergeCleanup failed for ${callID}: ${err}`)),standardWorktreeByCallID.delete(callID),awaitingMergeByCallID.delete(callID);let session=ensureAgentSession(parentSessionID);session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`STANDARD_WORKTREE_CLEANUP: dispatch ${callID} cleaned up (reason: ${reason}); worktree=${worktreePath}; branch=${branchName}.`)}async function abortStandardWorktreeDispatch(callID,reason,directory){let dispatch=standardWorktreeByCallID.get(callID);if(!dispatch){let session=ensureAgentSession("unknown");session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`STANDARD_WORKTREE_ABORT_NOOP: dispatch ${callID} has no tracked worktree to abort (reason: ${reason}).`);return}await cleanupStandardWorktreeForCallId(callID,reason,directory,dispatch.worktree_dir)}async function finishStandardWorktreeDispatch(directory,dispatch,config2,callID){let wtConfig=config2?resolveWorktreeIsolationConfig(config2):DEFAULT_WORKTREE_ISOLATION_CONFIG,resolvedCallID=callID??dispatch.callID,run=async()=>{let mergeResult=await _internals22.attemptMergeBackFromDirty(dispatch.handle.worktreePath,dispatch.handle.branchName,directory,getMergeStrategy({merge_strategy:dispatch.mergeStrategy})),statusKey=dispatch.planTaskId??dispatch.taskId;if("merged"in mergeResult&&mergeResult.merged){clearWorktreeMergeStatus(statusKey);try{let{removeLaneProfileFromDiskReal:removeLaneProfileFromDiskReal2}=await Promise.resolve().then(() => (init_core3(),exports_core3));await removeLaneProfileFromDiskReal2(dispatch.handle.worktreePath,dispatch.laneIndex)}catch{}let state=serializationStateBySessionID.get(dispatch.parentSessionID);if(state)state.successfulDispatchesSince++,checkStandardWorktreeSerializationRelease(dispatch.parentSessionID,wtConfig);await cleanupStandardWorktreeForCallId(resolvedCallID,"success",directory,dispatch.worktree_dir);return}if("partial"in mergeResult){recordWorktreeMergeFailure(statusKey,{outcome:"partial",stage:mergeResult.stage,message:mergeResult.message,worktreePath:dispatch.handle.worktreePath,branch:dispatch.handle.branchName,completedAt:Date.now()});let session=ensureAgentSession(dispatch.parentSessionID);session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`STANDARD_WORKTREE_MERGE_PARTIAL: task ${dispatch.taskId} preserved at ${dispatch.handle.worktreePath}; stage: ${mergeResult.stage}; ${mergeResult.message}`);return}if("failed"in mergeResult){recordWorktreeMergeFailure(statusKey,{outcome:"failed",stage:mergeResult.stage,message:mergeResult.message,worktreePath:dispatch.handle.worktreePath,branch:dispatch.handle.branchName,completedAt:Date.now()});let session=ensureAgentSession(dispatch.parentSessionID);session.pendingAdvisoryMessages??=[],session.pendingAdvisoryMessages.push(`STANDARD_WORKTREE_MERGE_FAILED: task ${dispatch.taskId} preserved at ${dispatch.handle.worktreePath}; stage: ${mergeResult.stage}; ${mergeResult.message}.`)}};if(standardWorktreeMergeQueue=standardWorktreeMergeQueue.then(run,run),await standardWorktreeMergeQueue,resolvedCallID)awaitingMergeByCallID.delete(resolvedCallID)}async function readLaneEnvFileFromDisk(worktreePath,laneIndex){let envPath=path29.join(worktreePath,".swarm","lanes",`${laneIndex}.env`),content;try{content=await fs17.readFile(envPath,"utf-8")}catch(err){if(err.code==="ENOENT")return{};return log(`[worktree-isolation] failed to read lane env file ${envPath}: ${err.message}`),{}}let result={};for(let rawLine of content.split(`
311
311
  `)){let line=rawLine.trim();if(!line||line.startsWith("#"))continue;let eqIdx=line.indexOf("=");if(eqIdx<0)continue;let k=line.slice(0,eqIdx),v=line.slice(eqIdx+1);if(!isValidEnvKey(k))continue;result[k]=v}return result}var MAX_TRACKED_STANDARD_WORKTREE_CALLS=256,awaitingMergeByCallID,standardWorktreeByCallID,standardWorktreeSerializationSessions,standardWorktreeMergeQueue,standardWorktreeLaneIndexBySession,serializationStateBySessionID,WORKTREE_LIST_TIMEOUT_MS=15000,PRESERVE_COMMIT_TIMEOUT_MS=30000,_internals22;var init_worktree_isolation=__esm(()=>{init_constants();init_executor();init_state2();init_bun_compat();init_logger();init_worktree();init_worktree_merge_status();init_worktree_isolation_config();awaitingMergeByCallID=new Map,standardWorktreeByCallID=new Map,standardWorktreeSerializationSessions=new Set,standardWorktreeMergeQueue=Promise.resolve(),standardWorktreeLaneIndexBySession=new Map,serializationStateBySessionID=new Map;_internals22={provisionWorktree,removeWorktree,attemptMergeBackFromDirty,postMergeCleanup,readLaneEnvFileFromDisk,serializationStateBySessionID,rememberStandardWorktreeSerializationSession,awaitingMergeByCallID,startupOrphanRecovery,cleanupOrphanedBranches,cleanupStandardWorktreeForCallId,preserveDirtyWorktreeForCallId,preserveDirtyWorktreeAtPath,abortStandardWorktreeDispatch,standardWorktreeByCallID,preProvisionCollisionCheck,isLaneOwnedByCurrentSession,bunSpawn}});function resolveMemoryConfig(input){return{...DEFAULT_MEMORY_CONFIG,...input??{},sqlite:{...DEFAULT_MEMORY_CONFIG.sqlite,...input?.sqlite??{}},recall:{...DEFAULT_MEMORY_CONFIG.recall,...input?.recall??{},injection:{...DEFAULT_MEMORY_CONFIG.recall.injection,...input?.recall?.injection??{}}},learning:{...DEFAULT_MEMORY_CONFIG.learning,...input?.learning??{}},writes:{...DEFAULT_MEMORY_CONFIG.writes,...input?.writes??{}},redaction:{...DEFAULT_MEMORY_CONFIG.redaction,...input?.redaction??{}},maintenance:{...DEFAULT_MEMORY_CONFIG.maintenance,...input?.maintenance??{},importance:{...DEFAULT_MEMORY_CONFIG.maintenance.importance,...input?.maintenance?.importance??{}}},consolidation:{...DEFAULT_MEMORY_CONFIG.consolidation,...input?.consolidation??{},decayHalfLifeDays:{...DEFAULT_MEMORY_CONFIG.consolidation.decayHalfLifeDays,...input?.consolidation?.decayHalfLifeDays??{}}},embeddings:{...DEFAULT_MEMORY_CONFIG.embeddings,...input?.embeddings??{}},retrieval:{...DEFAULT_MEMORY_CONFIG.retrieval,...input?.retrieval??{},weights:{...DEFAULT_MEMORY_CONFIG.retrieval.weights,...input?.retrieval?.weights??{}},rerank:{...DEFAULT_MEMORY_CONFIG.retrieval.rerank,...input?.retrieval?.rerank??{}}},qLearning:{...DEFAULT_MEMORY_CONFIG.qLearning,...input?.qLearning??{}}}}var DEFAULT_DECAY_HALF_LIFE_DAYS,DEFAULT_IMPORTANCE_CONFIG,DEFAULT_QLEARNING_CONFIG,COUNCIL_VERDICT_REWARDS,DEFAULT_CONSOLIDATION_CONFIG,DEFAULT_MEMORY_LEARNING_CONFIG,DEFAULT_EMBEDDINGS_CONFIG,DEFAULT_RETRIEVAL_CONFIG,DEFAULT_MEMORY_CONFIG,DURABLE_MEMORY_KINDS,EVIDENCE_REQUIRED_KINDS;var init_config2=__esm(()=>{DEFAULT_DECAY_HALF_LIFE_DAYS={scratch:7,todo:30,code_pattern:90,test_pattern:90,failure_pattern:90,api_finding:180,evidence:180,architecture_decision:0,repo_convention:0,project_fact:0,security_note:0,user_preference:0},DEFAULT_IMPORTANCE_CONFIG={wRecency:0.2,wFrequency:0.2,wFreshness:0.15,wConfidence:0.25,lambda:0.05,mu:0.01,n:50,threshold:0.2},DEFAULT_QLEARNING_CONFIG={learningRate:0.1,qValueBoostWeight:0.1,suppressionThreshold:0.15,promotionThreshold:0.85,promotionMinRetrievals:5,propagationFraction:0.3,propagationFanoutCap:20,propagationWindowDays:30,propagationRelatednessThreshold:0.7,explorationRate:0.05,verdictPayloadCapBytes:8192,initialQValue:0.5},COUNCIL_VERDICT_REWARDS={APPROVE:1,CONCERNS:0.5,REJECT:0},DEFAULT_CONSOLIDATION_CONFIG={enabled:!1,maxClustersPerPass:10,jaccardThreshold:0.3,autoApplyMinConfidence:0.6,decayHalfLifeDays:{...DEFAULT_DECAY_HALF_LIFE_DAYS}},DEFAULT_MEMORY_LEARNING_CONFIG={learningRate:0.1,propagationFactor:0.3,qValueBoostWeight:0.1,suppressionThreshold:0.15,promotionThreshold:0.85,propagationTokenOverlapThreshold:0.4,propagationEmbeddingCosineThreshold:0.7,propagationFanout:20,propagationLookbackDays:30},DEFAULT_EMBEDDINGS_CONFIG={enabled:!1,model:"Xenova/all-MiniLM-L6-v2",dimension:384,cacheSize:256},DEFAULT_RETRIEVAL_CONFIG={rrfK:60,weights:{lexical:0.5,dense:0.4,metadata:0.1},rerank:{enabled:!1},latencyBudgetMs:250},DEFAULT_MEMORY_CONFIG={enabled:!1,provider:"sqlite",storageDir:".swarm/memory",sqlite:{path:".swarm/memory/memory.db",busyTimeoutMs:5000},recall:{defaultMaxItems:8,defaultTokenBudget:1200,minScore:0.05,injection:{enabled:!0,minScore:0.25,requireQuerySignal:!0,maxItems:6,tokenBudget:1000}},learning:{...DEFAULT_MEMORY_LEARNING_CONFIG},writes:{mode:"propose"},redaction:{rejectDurableSecrets:!0},maintenance:{lowUtilityMaxConfidence:0.45,lowUtilityMinAgeDays:30,autoCompactEveryNRecalls:50,importance:{...DEFAULT_IMPORTANCE_CONFIG}},consolidation:{...DEFAULT_CONSOLIDATION_CONFIG,decayHalfLifeDays:{...DEFAULT_DECAY_HALF_LIFE_DAYS}},embeddings:{...DEFAULT_EMBEDDINGS_CONFIG},retrieval:{...DEFAULT_RETRIEVAL_CONFIG},qLearning:{...DEFAULT_QLEARNING_CONFIG},hardDelete:!1},DURABLE_MEMORY_KINDS=new Set(["user_preference","project_fact","architecture_decision","repo_convention","code_pattern","test_pattern","failure_pattern","security_note"]),EVIDENCE_REQUIRED_KINDS=new Set(["api_finding","evidence","security_note"])});var MemoryValidationError,MemoryDisabledError;var init_errors4=__esm(()=>{MemoryValidationError=class MemoryValidationError extends Error{code;constructor(message,code="memory_validation_error"){super(message);this.name="MemoryValidationError",this.code=code}};MemoryDisabledError=class MemoryDisabledError extends Error{constructor(message="Swarm memory is disabled"){super(message);this.name="MemoryDisabledError"}}});function findSecrets(text){let findings=[];for(let{type,pattern}of SECRET_PATTERNS){pattern.lastIndex=0;for(let match of text.matchAll(pattern))if(match[0])findings.push({type,match:match[0]})}return findings}function containsSecret(text){return findSecrets(text).length>0}function redactSecrets(text){let redacted=text;for(let{type,pattern}of SECRET_PATTERNS)pattern.lastIndex=0,redacted=redacted.replace(pattern,`[REDACTED:${type}]`);return redacted}var SECRET_PATTERNS;var init_redaction=__esm(()=>{SECRET_PATTERNS=[{type:"openai_api_key",pattern:/\bsk-[A-Za-z0-9_-]{20,}\b/g},{type:"github_token",pattern:/\b(?:ghp|gho|ghu|ghs|ghr|github_pat)_[A-Za-z0-9_]{20,}\b/g},{type:"aws_access_key_id",pattern:/\bAKIA[0-9A-Z]{16}\b/g},{type:"private_key_block",pattern:/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g},{type:"authorization_bearer",pattern:/\bAuthorization\s*:\s*Bearer\s+[A-Za-z0-9._~+/=-]{12,}/gi},{type:"env_secret",pattern:/\b(?:[A-Z][A-Z0-9]+_)+(?:KEY|TOKEN|SECRET|PASSWORD)\b\s*=\s*["']?[^\s"'`]{8,}["']?/gi},{type:"gitlab_token",pattern:/\bgl(?:pat|ptt)-[A-Za-z0-9_-]{15,}\b/g},{type:"slack_token",pattern:/\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g},{type:"jwt_token",pattern:/\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g},{type:"aws_secret_access_key",pattern:/\b(?:aws_secret_access_key|AWS_SECRET_ACCESS_KEY)\s*[=:]\s*[A-Za-z0-9/+=]{40}\b/g},{type:"stripe_secret_key",pattern:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{24,}\b/g},{type:"google_api_key",pattern:/\bAIza[0-9A-Za-z_-]{35}\b/g},{type:"openssh_private_key_block",pattern:/-----BEGIN[ ]OPENSSH[ ]PRIVATE[ ]KEY-----[\s\S]*?-----END[ ]OPENSSH[ ]PRIVATE[ ]KEY-----/g}]});var MEMORY_RECALL_SENTINEL="## Retrieved Swarm Memory";import{createHash as createHash9}from"node:crypto";function normalizeMemoryText(text){return text.replace(/\s+/g," ").trim()}function stableScopeKey(scope){let ordered={type:scope.type},keys=scope.type==="repository"?["repoId"]:["userId","workspaceId","projectId","repoId","repoRoot","runId","agentId"];for(let key of keys){let value=scope[key];if(value)ordered[key]=value}return JSON.stringify(ordered)}function computeMemoryContentHash(recordLike){let normalized=normalizeMemoryText(recordLike.text).toLowerCase();return createHash9("sha256").update(`${stableScopeKey(recordLike.scope)}
312
312
  ${recordLike.kind}
@@ -685,12 +685,12 @@ ${USAGE}`;if(resolved.instructions)return`Error: /swarm ci-monitor takes only a
685
685
  ${USAGE}`;return`[MODE: CI_MONITOR pr="${resolved.prUrl}"]`}var USAGE;var init_ci_monitor=__esm(()=>{init_pr_ref();USAGE=["Usage: /swarm ci-monitor <pr-url|owner/repo#N|N>","","Drive an already human-reviewed, approved pull request to green and","merged: monitors CI, exhaustively researches and fixes each failure,","iterates until all required checks are green (max 5 fix cycles), then","merges. Only invoke after human review is complete.",""," /swarm ci-monitor https://github.com/owner/repo/pull/42"," /swarm ci-monitor owner/repo#42"," /swarm ci-monitor 42"].join(`
686
686
  `)});import*as fs28 from"node:fs";import*as path57 from"node:path";function isExecutableFile(candidate){try{return fs28.statSync(candidate).isFile()}catch{return!1}}function resolveExecutableFromPath(names,envPath=process.env.PATH??"",platform=process.platform){let pathEntries=envPath.split(path57.delimiter).filter(Boolean),isWindows=platform==="win32";for(let rawName of names){if(!rawName)continue;if(path57.isAbsolute(rawName)&&isExecutableFile(rawName))return rawName;let extensions=isWindows&&path57.extname(rawName)===""?DEFAULT_WINDOWS_EXTENSIONS:[""];for(let dir of pathEntries)for(let ext of extensions){let candidate=path57.join(dir,`${rawName}${ext}`);if(isExecutableFile(candidate))return candidate}}return null}async function readBoundedStream(stream,maxBytes){let reader=stream.getReader(),lockReleased=!1,releaseLock=()=>{if(lockReleased)return;lockReleased=!0;try{reader.releaseLock()}catch{}},cancelAndRelease=async()=>{try{await reader.cancel()}catch{}finally{releaseLock()}};if(maxBytes<=0)return await cancelAndRelease(),{text:"",truncated:!0};let chunks=[],total=0,truncated=!1;try{for(;;){let{done,value}=await reader.read();if(done)break;if(!value)continue;let remaining=maxBytes-total;if(value.byteLength>remaining){if(remaining>0)chunks.push(value.slice(0,remaining)),total+=remaining;truncated=!0,await cancelAndRelease();break}chunks.push(value),total+=value.byteLength}}finally{releaseLock()}let out=new Uint8Array(total),offset=0;for(let chunk of chunks)out.set(chunk,offset),offset+=chunk.byteLength;return{text:new TextDecoder().decode(out),truncated}}function timeoutKillSignal(platform){return platform==="win32"?"SIGTERM":"SIGKILL"}function killProcess(proc){try{proc?.kill(timeoutKillSignal(_internals30.platform()))}catch{}}async function runExternalTool(options){if(!path57.isAbsolute(options.cwd))return{status:"spawn-error",exitCode:null,stdout:"",stderr:"",stdoutTruncated:!1,stderrTruncated:!1,message:"external tool cwd must be absolute"};if(options.abortSignal?.aborted)return{status:"cancelled",exitCode:null,stdout:"",stderr:"",stdoutTruncated:!1,stderrTruncated:!1,message:"external tool execution cancelled before spawn"};let proc,timeoutHandle,abortListener,exitSettled=!1,settledExitCode=null;try{proc=_internals30.bunSpawn([options.executable,...options.args],{cwd:options.cwd,env:options.env,stdin:"ignore",stdout:"pipe",stderr:"pipe",timeout:options.timeoutMs});let exitPromise=proc.exited.then((exitCode)=>{return exitSettled=!0,settledExitCode=exitCode,{kind:"exit",exitCode}}),timeout=new Promise((resolve26)=>{timeoutHandle=setTimeout(()=>{if(exitSettled){resolve26({kind:"exit",exitCode:settledExitCode??proc?.exitCode??0});return}killProcess(proc),resolve26({kind:"timeout"})},options.timeoutMs)}),cancelled=new Promise((resolve26)=>{if(!options.abortSignal)return;let handled=!1;if(abortListener=()=>{if(handled)return;handled=!0,killProcess(proc),resolve26({kind:"cancelled"})},options.abortSignal.addEventListener("abort",abortListener,{once:!0}),options.abortSignal.aborted)abortListener()}),stdoutPromise=readBoundedStream(proc.stdout,options.maxStdoutBytes),stderrPromise=readBoundedStream(proc.stderr,options.maxStderrBytes),exitResult=await Promise.race([exitPromise,timeout,cancelled]);if(exitResult.kind==="timeout")return{status:"timeout",exitCode:proc.exitCode,stdout:"",stderr:"",stdoutTruncated:!1,stderrTruncated:!1};if(exitResult.kind==="cancelled")return{status:"cancelled",exitCode:proc.exitCode,stdout:"",stderr:"",stdoutTruncated:!1,stderrTruncated:!1,message:"external tool execution cancelled"};let[stdout,stderr]=await Promise.all([stdoutPromise,stderrPromise]);return{status:"completed",exitCode:exitResult.exitCode,stdout:stdout.text,stderr:stderr.text,stdoutTruncated:stdout.truncated,stderrTruncated:stderr.truncated}}catch(err){return{status:"spawn-error",exitCode:proc?.exitCode??null,stdout:"",stderr:"",stdoutTruncated:!1,stderrTruncated:!1,message:err instanceof Error?err.message:String(err)}}finally{if(timeoutHandle!==void 0)clearTimeout(timeoutHandle);if(abortListener&&options.abortSignal)options.abortSignal.removeEventListener("abort",abortListener);if(proc)try{proc.kill()}catch{}}}var DEFAULT_WINDOWS_EXTENSIONS,_internals30;var init_external_tool_runner=__esm(()=>{init_bun_compat();DEFAULT_WINDOWS_EXTENSIONS=[".exe",".cmd",".bat"];_internals30={bunSpawn,platform:()=>process.platform}});import*as fs29 from"node:fs";import*as fsPromises6 from"node:fs/promises";import*as os14 from"node:os";import*as path58 from"node:path";async function runGit4(args2,cwd,timeoutMs=GIT_TIMEOUT_MS4){let result=await _internals31.runExternalTool({executable:"git",args:args2,cwd,timeoutMs,maxStdoutBytes:OUTPUT_LIMIT_BYTES,maxStderrBytes:OUTPUT_LIMIT_BYTES});return{exitCode:result.exitCode??1,stdout:result.message?[result.message,result.stdout].filter(Boolean).join(`
687
687
  `):result.stdout,stderr:result.stderr,outputTruncated:result.stdoutTruncated||result.stderrTruncated}}async function runValidationCommand(cmd,cwd,timeoutMs=VALIDATION_TIMEOUT_MS){let[executable,...args2]=cmd,result=await _internals31.runExternalTool({executable,args:args2,cwd,timeoutMs,maxStdoutBytes:OUTPUT_LIMIT_BYTES,maxStderrBytes:OUTPUT_LIMIT_BYTES});return{exitCode:result.exitCode??1,stdout:result.message?[result.message,result.stdout].filter(Boolean).join(`
688
- `):result.stdout,stderr:result.stderr,outputTruncated:result.stdoutTruncated||result.stderrTruncated}}function isSafeGitRef(ref){return ref.length>0&&ref.length<=255&&/^[A-Za-z0-9][A-Za-z0-9._/@-]*$/.test(ref)&&!ref.includes("..")&&!ref.includes("//")&&!ref.includes("@{")&&!ref.endsWith(".")}async function getCurrentBranchOrRef(directory){let result=await runGit4(["branch","--show-current"],directory);if(result.exitCode===0&&result.stdout.trim())return result.stdout.trim();return(await runGit4(["rev-parse","HEAD"],directory)).stdout.trim()}async function setupWorktree(projectRoot,prRef,baseBranch,onWorktreeCreated){let worktreeBase=path58.join(_internals31.osTmpdir(),"swarm-ci-simulate"),worktreeName=`pr-${Date.now()}-${Math.floor(Math.random()*1e6)}`,worktreePath=path58.join(worktreeBase,worktreeName);await fsPromises6.mkdir(worktreeBase,{recursive:!0});let addResult=await runGit4(["worktree","add","--detach",worktreePath,baseBranch],projectRoot);if(addResult.exitCode!==0)throw Error(`Failed to create worktree: ${addResult.stderr.trim()||addResult.stdout.trim()}`);onWorktreeCreated(worktreePath);let mergeResult=await runGit4(["merge","--no-ff","--no-edit","--",prRef],worktreePath,GIT_TIMEOUT_MS4*2);if(mergeResult.exitCode!==0)throw Error(`Merge failed for '${prRef}': ${mergeResult.stderr.trim()||mergeResult.stdout.trim()}`);return worktreePath}async function cleanupWorktree(worktreePath,projectRoot){let removeResult=await runGit4(["worktree","remove","--force",worktreePath],projectRoot);try{if(_internals31.fs.existsSync(worktreePath))_internals31.fs.rmSync(worktreePath,{recursive:!0,force:!0})}catch{}if(removeResult.exitCode!==0)console.warn(`[ci-simulate] git worktree remove failed: ${removeResult.stderr.trim()||removeResult.stdout.trim()}`)}async function runValidationSuite(worktreePath){let steps=[],commands=[{step:"typecheck",cmd:["bun","run","typecheck"]},{step:"lint",cmd:["bun","run","lint"]},{step:"build",cmd:["bun","run","build"]},{step:"test",cmd:["bun","test"]}];for(let{step,cmd}of commands){let start=Date.now(),result=await runValidationCommand(cmd,worktreePath),durationMs=Date.now()-start;steps.push({step,command:cmd.join(" "),exitCode:result.exitCode,stdout:result.stdout,stderr:result.stderr,durationMs,outputTruncated:result.outputTruncated})}return steps}function formatStepOutput(stdout,stderr,outputTruncated,maxLength=2000){let output=stdout;if(stderr)output+=output?`
688
+ `):result.stdout,stderr:result.stderr,outputTruncated:result.stdoutTruncated||result.stderrTruncated}}function isSafeGitRef(ref){return ref.length>0&&ref.length<=255&&/^[A-Za-z0-9][A-Za-z0-9._/@-]*$/.test(ref)&&!ref.includes("..")&&!ref.includes("//")&&!ref.includes("@{")&&!ref.endsWith(".")}async function getCurrentBranchOrRef(directory){let result=await runGit4(["branch","--show-current"],directory);if(result.exitCode===0&&result.stdout.trim())return result.stdout.trim();return(await runGit4(["rev-parse","HEAD"],directory)).stdout.trim()}async function setupWorktree(projectRoot,prRef,baseBranch,onWorktreeCreated){let worktreeBase=path58.join(_internals31.osTmpdir(),"swarm-ci-simulate"),worktreeName=`pr-${Date.now()}-${Math.floor(Math.random()*1e6)}`,worktreePath=path58.join(worktreeBase,worktreeName);await fsPromises6.mkdir(worktreeBase,{recursive:!0});let addResult=await runGit4(["worktree","add","--detach",worktreePath,baseBranch],projectRoot);if(addResult.exitCode!==0)throw Error(`Failed to create worktree: ${addResult.stderr.trim()||addResult.stdout.trim()}`);onWorktreeCreated(worktreePath);let mergeResult=await runGit4(["merge","--no-ff","--no-edit","--",prRef],worktreePath,GIT_TIMEOUT_MS4*2);if(mergeResult.exitCode!==0)throw Error(`Merge failed for '${prRef}': ${mergeResult.stderr.trim()||mergeResult.stdout.trim()}`);return worktreePath}async function cleanupWorktree(worktreePath,projectRoot){let removeResult=await runGit4(["worktree","remove","--force",worktreePath],projectRoot);try{if(_internals31.fs.existsSync(worktreePath))_internals31.fs.rmSync(worktreePath,{recursive:!0,force:!0})}catch{}if(removeResult.exitCode!==0)log(`[ci-simulate] git worktree remove failed: ${removeResult.stderr.trim()||removeResult.stdout.trim()}`)}async function runValidationSuite(worktreePath){let steps=[],commands=[{step:"typecheck",cmd:["bun","run","typecheck"]},{step:"lint",cmd:["bun","run","lint"]},{step:"build",cmd:["bun","run","build"]},{step:"test",cmd:["bun","test"]}];for(let{step,cmd}of commands){let start=Date.now(),result=await runValidationCommand(cmd,worktreePath),durationMs=Date.now()-start;steps.push({step,command:cmd.join(" "),exitCode:result.exitCode,stdout:result.stdout,stderr:result.stderr,durationMs,outputTruncated:result.outputTruncated})}return steps}function formatStepOutput(stdout,stderr,outputTruncated,maxLength=2000){let output=stdout;if(stderr)output+=output?`
689
689
  ${stderr}`:stderr;if(output.length>maxLength)output=`${output.slice(0,maxLength)}
690
690
  ... (output truncated)`;if(outputTruncated)output=`${output}
691
691
  ... (child output truncated to bounded limit)`;return output}function extractFileLineReferences(output){let lines=[],patterns=[/([A-Za-z]:[\\/])?[^\s:]+\.(ts|tsx|js|jsx):(\d+):(\d+)/g,/(?:error|Error|FAIL|Failed)[:\s]+([^\s]+\.(ts|tsx|js|jsx)?:?:\d+)/gi,/FAIL\s+([^\s]+\.(test|spec)\.(ts|tsx|js|jsx))/gi];for(let pattern of patterns){let matches=Array.from(output.matchAll(pattern));for(let match of matches)if(match[0])lines.push(match[0])}return Array.from(new Set(lines))}async function handleCiSimulateCommand(directory,args2){let prRef=args2[0]??await getCurrentBranchOrRef(directory);if(!isSafeGitRef(prRef))return"CI simulation failed: PR ref must be a safe git branch or commit reference.";let lines=[];lines.push("# CI Simulation Report"),lines.push(""),lines.push(`PR ref: **${prRef}**`),lines.push(`Started: ${new Date().toISOString()}`),lines.push("");let worktreePath,result={success:!1,worktreePath:"",steps:[]};try{let baseBranch=_internals31.getDefaultBaseBranch(directory);if(!isSafeGitRef(baseBranch))throw Error("Detected default branch is not a safe git reference.");lines.push("## Setup"),lines.push(""),lines.push(`Creating temporary worktree from ${baseBranch}...`),worktreePath=await setupWorktree(directory,prRef,baseBranch,(createdPath)=>{worktreePath=createdPath}),result.worktreePath=worktreePath,lines.push(`Worktree: \`${worktreePath}\``),lines.push("");let lastCommit=(await runGit4(["log","--oneline","-1","--format=%s"],worktreePath)).stdout.trim();lines.push(`Last commit in worktree: \`${lastCommit}\``),lines.push(""),lines.push("## Validation Suite"),lines.push(""),result.steps=await runValidationSuite(worktreePath);for(let step of result.steps){let status=step.exitCode===0?"✅ PASS":"❌ FAIL";if(lines.push(`### ${status}: ${step.step}`),lines.push(""),lines.push(`Command: \`${step.command}\``),lines.push(`Duration: ${(step.durationMs/1000).toFixed(1)}s`),step.exitCode!==0){lines.push(`Exit code: ${step.exitCode}`);let fileRefs=extractFileLineReferences(`${step.stdout}
692
692
  ${step.stderr}`);if(fileRefs.length>0){lines.push(""),lines.push("**Failure locations:**");for(let ref of fileRefs.slice(0,20))lines.push(` - \`${ref}\``)}lines.push(""),lines.push("**Output:**"),lines.push("```"),lines.push(formatStepOutput(step.stdout,step.stderr,step.outputTruncated)),lines.push("```")}lines.push("")}let allPassed=result.steps.every((s)=>s.exitCode===0);result.success=allPassed,lines.push("## Summary"),lines.push("");let passed=result.steps.filter((s)=>s.exitCode===0).length,failed=result.steps.filter((s)=>s.exitCode!==0).length;if(lines.push(`Validation: ${passed}/${result.steps.length} steps passed, ${failed} failed`),lines.push(""),allPassed)lines.push("✅ **All checks passed — CI simulation succeeded**");else{lines.push("❌ **CI simulation failed — these failures would cause a merge-queue kick-out**"),lines.push(""),lines.push("To reproduce locally, run in the worktree:"),lines.push("```bash"),lines.push(`cd "${worktreePath}"`);for(let step of result.steps.filter((s)=>s.exitCode!==0))lines.push(`# ${step.step}: ${step.command}`);lines.push("```")}}catch(err){let errMsg=err instanceof Error?err.message:String(err);result.error=errMsg,lines.push(""),lines.push("## Error"),lines.push(""),lines.push("```"),lines.push(errMsg),lines.push("```")}finally{if(worktreePath)lines.push(""),lines.push("---"),lines.push(""),lines.push("*Cleaning up temporary worktree...*"),await cleanupWorktree(worktreePath,directory),lines.push(`Worktree removed: \`${worktreePath}\``)}return lines.join(`
693
- `)}var GIT_TIMEOUT_MS4=30000,VALIDATION_TIMEOUT_MS=300000,OUTPUT_LIMIT_BYTES=12000,_internals31;var init_ci_simulate=__esm(()=>{init_branch();init_external_tool_runner();_internals31={runExternalTool,getDefaultBaseBranch,platform:process.platform,osTmpdir:()=>os14.tmpdir(),fs:{existsSync:fs29.existsSync,rmSync:fs29.rmSync}}});async function handleClarifyCommand(_directory,args2){let description=args2.join(" ").trim();if(description)return`[MODE: CLARIFY-SPEC] ${description}`;return"[MODE: CLARIFY-SPEC] Please enter MODE: CLARIFY-SPEC and clarify the existing spec."}function isAbortError(err){if(typeof err!=="object"||err===null)return!1;let name=err.name;return name==="AbortError"||name==="TimeoutError"}var exports_curator_llm_factory={};__export(exports_curator_llm_factory,{createCuratorLLMDelegate:()=>createCuratorLLMDelegate});function resolveCuratorAgentName(mode,sessionId){let suffix={init:"curator_init",phase:"curator_phase",postmortem:"curator_postmortem",consolidation:"curator_consolidation"}[mode],registeredNames={init:swarmState.curatorInitAgentNames,phase:swarmState.curatorPhaseAgentNames,postmortem:swarmState.curatorPostmortemAgentNames,consolidation:swarmState.curatorConsolidationAgentNames}[mode];if(registeredNames.length===1)return registeredNames[0];if(registeredNames.length===0)return suffix;let prefixMap=new Map;for(let name of registeredNames){let prefix=name.endsWith(suffix)?name.slice(0,name.length-suffix.length):"";prefixMap.set(prefix,name)}let matchForAgent=(agentName)=>{let bestPrefix="",bestName="";for(let[prefix,name]of prefixMap)if(prefix&&agentName.startsWith(prefix)){if(prefix.length>bestPrefix.length)bestPrefix=prefix,bestName=name}return bestName};if(sessionId){let callingAgent=swarmState.activeAgent.get(sessionId);if(callingAgent){let match=matchForAgent(callingAgent);if(match)return match;let defaultCurator=prefixMap.get("");if(defaultCurator)return defaultCurator}}for(let activeAgentName of swarmState.activeAgent.values()){let match=matchForAgent(activeAgentName);if(match)return match}return prefixMap.get("")??registeredNames[0]}function createCuratorLLMDelegate(directory,mode="init",sessionId){let client=swarmState.opencodeClient;if(!client)return;return async(_systemPrompt,userInput,signal)=>{let ephemeralSessionId,cleanup=()=>{if(ephemeralSessionId){let id=ephemeralSessionId;ephemeralSessionId=void 0,client.session.delete({path:{id}}).catch(()=>{})}};if(signal?.aborted)throw Error("CURATOR_LLM_TIMEOUT");let sdkOpts=signal?{signal}:{};try{let createResult=await client.session.create({...sessionId?{body:{parentID:sessionId,title:`curator_${mode} background`}}:{},query:{directory},...sdkOpts});if(!createResult.data)throw Error(`Failed to create curator session: ${JSON.stringify(createResult.error)}`);if(ephemeralSessionId=createResult.data.id,signal?.aborted)throw Error("CURATOR_LLM_TIMEOUT");let agentName=resolveCuratorAgentName(mode,sessionId),promptResult=await client.session.prompt({path:{id:ephemeralSessionId},body:{agent:agentName,tools:{write:!1,edit:!1,patch:!1},parts:[{type:"text",text:userInput}]},...sdkOpts});if(!promptResult.data)throw Error(`Curator LLM prompt failed: ${JSON.stringify(promptResult.error)}`);return promptResult.data.parts.filter((p)=>p.type==="text").map((p)=>p.text).join(`
693
+ `)}var GIT_TIMEOUT_MS4=30000,VALIDATION_TIMEOUT_MS=300000,OUTPUT_LIMIT_BYTES=12000,_internals31;var init_ci_simulate=__esm(()=>{init_branch();init_external_tool_runner();init_logger();_internals31={runExternalTool,getDefaultBaseBranch,platform:process.platform,osTmpdir:()=>os14.tmpdir(),fs:{existsSync:fs29.existsSync,rmSync:fs29.rmSync}}});async function handleClarifyCommand(_directory,args2){let description=args2.join(" ").trim();if(description)return`[MODE: CLARIFY-SPEC] ${description}`;return"[MODE: CLARIFY-SPEC] Please enter MODE: CLARIFY-SPEC and clarify the existing spec."}function isAbortError(err){if(typeof err!=="object"||err===null)return!1;let name=err.name;return name==="AbortError"||name==="TimeoutError"}var exports_curator_llm_factory={};__export(exports_curator_llm_factory,{createCuratorLLMDelegate:()=>createCuratorLLMDelegate});function resolveCuratorAgentName(mode,sessionId){let suffix={init:"curator_init",phase:"curator_phase",postmortem:"curator_postmortem",consolidation:"curator_consolidation"}[mode],registeredNames={init:swarmState.curatorInitAgentNames,phase:swarmState.curatorPhaseAgentNames,postmortem:swarmState.curatorPostmortemAgentNames,consolidation:swarmState.curatorConsolidationAgentNames}[mode];if(registeredNames.length===1)return registeredNames[0];if(registeredNames.length===0)return suffix;let prefixMap=new Map;for(let name of registeredNames){let prefix=name.endsWith(suffix)?name.slice(0,name.length-suffix.length):"";prefixMap.set(prefix,name)}let matchForAgent=(agentName)=>{let bestPrefix="",bestName="";for(let[prefix,name]of prefixMap)if(prefix&&agentName.startsWith(prefix)){if(prefix.length>bestPrefix.length)bestPrefix=prefix,bestName=name}return bestName};if(sessionId){let callingAgent=swarmState.activeAgent.get(sessionId);if(callingAgent){let match=matchForAgent(callingAgent);if(match)return match;let defaultCurator=prefixMap.get("");if(defaultCurator)return defaultCurator}}for(let activeAgentName of swarmState.activeAgent.values()){let match=matchForAgent(activeAgentName);if(match)return match}return prefixMap.get("")??registeredNames[0]}function createCuratorLLMDelegate(directory,mode="init",sessionId){let client=swarmState.opencodeClient;if(!client)return;return async(_systemPrompt,userInput,signal)=>{let ephemeralSessionId,cleanup=()=>{if(ephemeralSessionId){let id=ephemeralSessionId;ephemeralSessionId=void 0,client.session.delete({path:{id}}).catch(()=>{})}};if(signal?.aborted)throw Error("CURATOR_LLM_TIMEOUT");let sdkOpts=signal?{signal}:{};try{let createResult=await client.session.create({...sessionId?{body:{parentID:sessionId,title:`curator_${mode} background`}}:{},query:{directory},...sdkOpts});if(!createResult.data)throw Error(`Failed to create curator session: ${JSON.stringify(createResult.error)}`);if(ephemeralSessionId=createResult.data.id,signal?.aborted)throw Error("CURATOR_LLM_TIMEOUT");let agentName=resolveCuratorAgentName(mode,sessionId),promptResult=await client.session.prompt({path:{id:ephemeralSessionId},body:{agent:agentName,tools:{write:!1,edit:!1,patch:!1},parts:[{type:"text",text:userInput}]},...sdkOpts});if(!promptResult.data)throw Error(`Curator LLM prompt failed: ${JSON.stringify(promptResult.error)}`);return promptResult.data.parts.filter((p)=>p.type==="text").map((p)=>p.text).join(`
694
694
  `)}catch(err){if(isAbortError(err))throw Error("CURATOR_LLM_TIMEOUT");throw err}finally{cleanup()}}}var init_curator_llm_factory=__esm(()=>{init_state2()});var READ_ONLY_LANE_GUIDANCE=`## READ-ONLY ADVISORY LANE CONTEXT
695
695
 
696
696
  You may be invoked through dispatch_lanes or dispatch_lanes_async as a read-only advisory lane. In that context, your job is to inspect, reason, and report only.
@@ -1268,11 +1268,11 @@ ${trajectorySummary}`,"",`TRANSCRIPT TAIL:
1268
1268
  ${transcriptTail}`].join(`
1269
1269
  `).slice(0,MICRO_PROMPT_INPUT_CAP)}function parseMicroCandidates(response,meta3){let parsed;try{let start=response.indexOf("["),end=response.lastIndexOf("]");if(start<0||end<=start)return[];parsed=JSON.parse(response.slice(start,end+1))}catch{return[]}if(!Array.isArray(parsed))return[];let out=[];for(let item of parsed){if(out.length>=MAX_CANDIDATES)break;if(!item||typeof item!=="object")continue;let rec=item,lesson=typeof rec.lesson==="string"?rec.lesson.trim():"";if(lesson.length<15||lesson.length>280)continue;let fields={};for(let key of CANDIDATE_ALLOWED_FIELDS){let v=rec[key];if(Array.isArray(v)){let arr=v.filter((x)=>typeof x==="string").map((x)=>x.slice(0,200)).slice(0,20);if(arr.length>0)fields[key]=arr}}let priority=rec.directive_priority;if(priority==="low"||priority==="medium"||priority==="high"||priority==="critical")fields.directive_priority=priority;if(!validateActionableFields(fields).valid)continue;if(!validateActionability(fields).actionable)continue;let category=typeof rec.category==="string"?rec.category:"process";out.push({lesson,category,tags:[],...fields,source:{kind:"micro_reflection",task_id:meta3.taskId,agent:meta3.agent,outcome:meta3.outcome,trajectory_steps:meta3.steps},created_at:new Date().toISOString()})}return out}async function runMicroReflection(params){let outcome=classifyOutcome(params.transcript,params.trajectory),result={outcome,reflected:!1,candidates:0};try{if(!REFLECT_OUTCOMES.has(outcome))return result;if(!params.llmDelegate)return result;let quota=params.quota??{maxCalls:10,window:"utc"};if(!(await reserveQuota(params.directory,{nCalls:1,maxCalls:quota.maxCalls,window:quota.window,scope:"knowledge-enrichment"})).allowed)return result;let prompt=buildMicroPrompt({agent:params.agent,outcome,transcript:params.transcript,trajectory:params.trajectory}),response=await params.llmDelegate("",prompt,AbortSignal.timeout(MICRO_LLM_TIMEOUT_MS));result.reflected=!0;let candidates=parseMicroCandidates(response,{agent:params.agent,outcome,taskId:params.taskId,steps:params.trajectory.length});return await appendInsightCandidates(params.directory,candidates),result.candidates=candidates.length,result}catch(err){return warn(`[micro-reflector] reflection failed (non-fatal): ${err instanceof Error?err.message:String(err)}`),result}}function extractTaskId(prompt){let m=/\btask[_-]?id\s*[:=]\s*([A-Za-z0-9._-]{1,80})/i.exec(prompt);return m?m[1]:void 0}function isTaskTool(tool3){return tool3==="Task"||tool3==="task"}async function microReflectorAfter(directory,input,output,llmDelegate,quota){if(!isTaskTool(input.tool))return;let transcript=typeof output.output==="string"?output.output:"";if(!transcript)return;let argsRecord=input.args&&typeof input.args==="object"?input.args:null,prompt=argsRecord&&typeof argsRecord.prompt==="string"?argsRecord.prompt:"",parsed=parseDelegationArgs(input.args),agent=parsed?stripKnownSwarmPrefix(parsed.targetAgent):"unknown",taskId=extractTaskId(prompt),trajectory=taskId?await readTaskTrajectory(directory,taskId):[];await runMicroReflection({directory,taskId,agent,transcript,trajectory,llmDelegate,quota})}var REFLECT_OUTCOMES,MICRO_PROMPT_INPUT_CAP=1800,MICRO_LLM_TIMEOUT_MS=60000,MAX_CANDIDATES=2,TEST_FAIL_RE,LINT_FAIL_RE,REVERT_RE,PARTIAL_RE,INSIGHT_CANDIDATES_MAX_ENTRIES=500,CANDIDATE_ALLOWED_FIELDS;var init_micro_reflector=__esm(()=>{init_schema();init_manager2();init_skill_improver_quota();init_logger();init_knowledge_store();init_knowledge_validator();init_skill_propagation_gate();init_utils2();REFLECT_OUTCOMES=new Set(["failure_test","failure_lint","failure_revert","partial"]);TEST_FAIL_RE=/\b(\d+\s+fail(?:ed|ing|s)?|test(?:s)?\s+fail|failing\s+test|assertion\s+fail|FAIL\b|✗|✘)/i,LINT_FAIL_RE=/\b(lint\s+(?:error|fail)|biome\s+error|eslint\s+error|type\s*error|tsc\s+error|TS\d{3,})/i,REVERT_RE=/\b(revert(?:ed|ing)?|rolled?\s*back|restore[d]?\s+from\s+checkpoint|undo(?:ne)?\s+the\s+change)/i,PARTIAL_RE=/\b(partial(?:ly)\s+complete|did\s+not\s+(?:finish|complete)|could\s+not\s+(?:finish|complete)|ran\s+out\s+of\s+(?:time|context|budget)|remaining\s+work|blocked\s+on|unable\s+to\s+complete|task\s+incomplete)/i;CANDIDATE_ALLOWED_FIELDS=["applies_to_agents","applies_to_tools","forbidden_actions","required_actions","verification_checks","triggers"]});import{createHash as createHash16}from"node:crypto";import{existsSync as existsSync36}from"node:fs";import{appendFile as appendFile10,mkdir as mkdir19,readFile as readFile22,realpath as realpath3,writeFile as writeFile14}from"node:fs/promises";import*as path79 from"node:path";function pruneSeenRetroSections(){let cutoff=Date.now()-86400000;for(let[key,entry]of seenRetroSections)if(entry.timestamp<cutoff)seenRetroSections.delete(key)}function capSeenRetroSections(){let overflow=seenRetroSections.size-MAX_TRACKED_RETRO_SECTIONS;if(overflow<=0)return;let byAge=Array.from(seenRetroSections.entries()).sort((a,b)=>a[1].timestamp-b[1].timestamp);for(let i=0;i<overflow;i++)seenRetroSections.delete(byAge[i][0])}function recordSeenRetroSection(key,value,timestamp){seenRetroSections.set(key,{value,timestamp}),capSeenRetroSections()}function hashContent2(content){return createHash16("sha1").update(content).digest("hex")}async function canonicalExistingPath(candidate){let resolved=path79.resolve(candidate);try{resolved=await _internals46.realpath(resolved)}catch{}return resolved}function isPathContained(root,candidate){let relative18=path79.relative(root,candidate);return relative18===""||!relative18.startsWith(`..${path79.sep}`)&&relative18!==".."&&!path79.isAbsolute(relative18)}function physicalPathIdentity(candidate){let normalized=candidate.replaceAll("\\","/").normalize("NFC");return process.platform==="win32"?normalized.toLowerCase():normalized}async function resolveEvidencePathScope(directory,relativeEvidencePath){let projectRoot=await canonicalExistingPath(directory),swarmRoot=await canonicalExistingPath(path79.join(projectRoot,".swarm"));if(!isPathContained(projectRoot,swarmRoot))return null;let evidenceRoot=await canonicalExistingPath(path79.join(swarmRoot,"evidence"));if(!isPathContained(swarmRoot,evidenceRoot))return null;let evidenceTarget=await canonicalExistingPath(path79.join(swarmRoot,...relativeEvidencePath.split("/")));if(!isPathContained(evidenceRoot,evidenceTarget))return null;return{projectIdentity:hashContent2(physicalPathIdentity(projectRoot)),evidenceIdentity:hashContent2(physicalPathIdentity(evidenceTarget))}}function sanitizeEvidenceLessons(value){if(!Array.isArray(value))return[];return value.filter((lesson)=>typeof lesson==="string").map((lesson)=>lesson.trim()).filter((lesson)=>lesson.length>0&&lesson.length<=280)}function evidenceProjectName(entry,root){let metadata=isRecord2(entry.metadata)?entry.metadata:null;return typeof entry.project_name==="string"?entry.project_name:typeof metadata?.project_name==="string"?metadata.project_name:typeof root.project_name==="string"?root.project_name:"unknown"}function evidencePhaseNumber(entry,root){return typeof entry.phase_number==="number"?entry.phase_number:typeof root.phase_number==="number"?root.phase_number:1}function extractEvidenceLessonBatches(evidenceData){let rawEntries=Array.isArray(evidenceData.entries)?evidenceData.entries:[evidenceData],batches=[];for(let rawEntry of rawEntries){if(!isRecord2(rawEntry))continue;if(Object.hasOwn(rawEntry,"type")&&rawEntry.type!=="retrospective")continue;let lessons=sanitizeEvidenceLessons(rawEntry.lessons_learned);if(lessons.length===0)continue;let phaseNumber=evidencePhaseNumber(rawEntry,evidenceData),projectName=evidenceProjectName(rawEntry,evidenceData),identity=hashContent2(JSON.stringify([rawEntry.type??"legacy-retrospective",rawEntry.task_id??evidenceData.task_id??"",rawEntry.timestamp??"",rawEntry.agent??"",phaseNumber,projectName,lessons]));batches.push({identity,lessons,projectName,phaseNumber})}return batches}function isWriteToEvidenceFile(input){let trigger=normalizeWriteTrigger(input);return isEvidencePath(trigger?.filePath)}function isRecord2(value){return typeof value==="object"&&value!==null}function normalizePathField(value){return typeof value==="string"?value.replace(/\\/g,"/"):null}function firstPathFromRecord(record3){return normalizePathField(record3.path)??normalizePathField(record3.filePath)??normalizePathField(record3.file)}function normalizeWriteTrigger(input,output){if(!isRecord2(input))return null;let toolName=typeof input.toolName==="string"?input.toolName:typeof input.tool==="string"?input.tool:null;if(!toolName||!WRITE_TOOLS.has(toolName))return null;let inputArgs=isRecord2(input.args)?input.args:null,outputArgs=isRecord2(output)&&isRecord2(output.args)?output.args:null,filePath=firstPathFromRecord(input)??(inputArgs?firstPathFromRecord(inputArgs):null)??(outputArgs?firstPathFromRecord(outputArgs):null);if(!filePath)return null;return{toolName,filePath,sessionID:typeof input.sessionID==="string"?input.sessionID:"default"}}function isEvidencePath(filePath){if(!filePath)return!1;return/(?:^|\/)\.swarm\/+evidence\//i.test(filePath)}function isPlanPath(filePath){return filePath?.includes(".swarm/plan.md")??!1}function extractRetrospectiveSection(planContent){let match=/^###\s+Lessons\s+Learned$/m.exec(planContent);if(!match)return null;let startIndex=match.index,restOfContent=planContent.slice(startIndex),firstNewline=restOfContent.indexOf(`
1270
1270
  `),contentAfterHeading=firstNewline===-1?"":restOfContent.slice(firstNewline+1),nextMatch=/^#{1,2}\s+/m.exec(contentAfterHeading),endIndex;if(nextMatch)endIndex=startIndex+firstNewline+1+nextMatch.index;else endIndex=planContent.length;return planContent.slice(startIndex,endIndex).trim()}function checkRetroChanged(sessionID,section){let hash4=hashContent2(section);if(seenRetroSections.get(sessionID)?.value===hash4)return!1;return recordSeenRetroSection(sessionID,hash4,Date.now()),!0}function extractLessonsFromRetro(section){let lessons=[],lines=section.split(`
1271
- `);for(let line of lines){let trimmed=line.trim(),bulletMatch=/^[-*]\s+(.+)$/.exec(trimmed);if(bulletMatch){let content=bulletMatch[1].trim();if(content)lessons.push(content)}}return lessons}function extractRetractionsAndLessons(allLessons){let retractions=[],normalLessons=[];for(let lesson of allLessons){let upper=lesson.trimStart().toUpperCase();if(upper.startsWith("RETRACT:")||upper.startsWith("BAD RULE:")){let colonIdx=lesson.indexOf(":"),text=colonIdx!==-1?lesson.slice(colonIdx+1).trim():"";if(text)retractions.push(text)}else normalLessons.push(lesson)}return{retractions,normalLessons}}async function processRetractions(retractions,directory){if(retractions.length===0)return;let swarmEntries=await readKnowledge(resolveSwarmKnowledgePath(directory))??[],hiveEntries=await readKnowledge(resolveHiveKnowledgePath2())??[],existingRetractions=await readRetractionRecords(directory),existingSuppressedLessons=new Set(existingRetractions.map((record3)=>record3.normalized_lesson).filter((value)=>typeof value==="string"&&value.length>0));for(let retractionText of retractions){let normalizedRetraction=normalize5(retractionText),matchedSwarmIds=[],matchedHiveIds=[];for(let entry of swarmEntries)if(normalize5(entry.lesson)===normalizedRetraction)matchedSwarmIds.push(entry.id),await quarantineEntry(directory,entry.id,`Retracted by architect: ${retractionText}`,"architect"),console.info(`[knowledge-curator] Quarantined entry ${entry.id}: "${entry.lesson}"`);for(let entry of hiveEntries)if(normalize5(entry.lesson)===normalizedRetraction)matchedHiveIds.push(entry.id);if(!existingSuppressedLessons.has(normalizedRetraction))await appendRetractionRecord(directory,{id:crypto.randomUUID(),retracted_lesson:retractionText,normalized_lesson:normalizedRetraction,recorded_at:new Date().toISOString(),reported_by:"architect",matched_swarm_ids:matchedSwarmIds,matched_hive_ids:matchedHiveIds}),existingSuppressedLessons.add(normalizedRetraction)}}function buildV3EnrichmentPrompt(lesson,category,tags){return["Convert this prose lesson into an actionable knowledge directive.","Output ONLY a single JSON object no code fences, no commentary.","","MANDATORY fields (the directive is rejected without them):","- At least ONE scope field non-empty:",' "applies_to_agents": string[] roles from: architect, coder, reviewer, test_engineer, sme, docs, designer, critic, curator',' "applies_to_tools": string[] tool names from: edit, write, patch, bash, read, grep, glob',"- At least ONE predicate field non-empty:",' "forbidden_actions": string[] concrete actions to never take',' "required_actions": string[] concrete actions to always take',' "verification_checks": string[] checks a reviewer can run',"","OPTIONAL fields:",' "triggers": string[] short phrases that should surface this lesson',' "directive_priority": "low" | "medium" | "high" | "critical"',"","Example output:",'{"applies_to_agents":["coder"],"forbidden_actions":["use async iterators in hot paths"],"required_actions":["use a plain for loop in hot paths"],"triggers":["hot path","async iterator"],"directive_priority":"high"}',"",`LESSON: ${lesson}`,`CATEGORY: ${category}`,`TAGS: ${tags.join(", ")}`].join(`
1271
+ `);for(let line of lines){let trimmed=line.trim(),bulletMatch=/^[-*]\s+(.+)$/.exec(trimmed);if(bulletMatch){let content=bulletMatch[1].trim();if(content)lessons.push(content)}}return lessons}function extractRetractionsAndLessons(allLessons){let retractions=[],normalLessons=[];for(let lesson of allLessons){let upper=lesson.trimStart().toUpperCase();if(upper.startsWith("RETRACT:")||upper.startsWith("BAD RULE:")){let colonIdx=lesson.indexOf(":"),text=colonIdx!==-1?lesson.slice(colonIdx+1).trim():"";if(text)retractions.push(text)}else normalLessons.push(lesson)}return{retractions,normalLessons}}async function processRetractions(retractions,directory){if(retractions.length===0)return;let swarmEntries=await readKnowledge(resolveSwarmKnowledgePath(directory))??[],hiveEntries=await readKnowledge(resolveHiveKnowledgePath2())??[],existingRetractions=await readRetractionRecords(directory),existingSuppressedLessons=new Set(existingRetractions.map((record3)=>record3.normalized_lesson).filter((value)=>typeof value==="string"&&value.length>0));for(let retractionText of retractions){let normalizedRetraction=normalize5(retractionText),matchedSwarmIds=[],matchedHiveIds=[];for(let entry of swarmEntries)if(normalize5(entry.lesson)===normalizedRetraction)matchedSwarmIds.push(entry.id),await quarantineEntry(directory,entry.id,`Retracted by architect: ${retractionText}`,"architect"),console.info(`[knowledge-curator] Quarantined entry ${entry.id}: "${entry.lesson}"`);for(let entry of hiveEntries)if(normalize5(entry.lesson)===normalizedRetraction)matchedHiveIds.push(entry.id);if(!existingSuppressedLessons.has(normalizedRetraction))await appendRetractionRecord(directory,{id:crypto.randomUUID(),retracted_lesson:retractionText,normalized_lesson:normalizedRetraction,recorded_at:new Date().toISOString(),reported_by:"architect",matched_swarm_ids:matchedSwarmIds,matched_hive_ids:matchedHiveIds}),existingSuppressedLessons.add(normalizedRetraction)}}function buildV3EnrichmentPrompt(lesson,category,tags){return["Convert this prose lesson into an actionable knowledge directive.","Output ONLY a single JSON object — no code fences, no commentary.","","MANDATORY fields (the directive is rejected without them):","- At least ONE scope field non-empty:",' "applies_to_agents": string[] — roles from: architect, coder, reviewer, test_engineer, sme, docs, designer, critic, curator',' "applies_to_tools": string[] — tool names from: edit, write, patch, bash, read, grep, glob',"- At least ONE predicate field non-empty:",' "forbidden_actions": string[] — concrete actions to never take',' "required_actions": string[] — concrete actions to always take',' "verification_checks": string[] — checks a reviewer can run',"","OPTIONAL fields:",' "triggers": string[] — short phrases that should surface this lesson',' "directive_priority": "low" | "medium" | "high" | "critical"',"","Example output:",'{"applies_to_agents":["coder"],"forbidden_actions":["use async iterators in hot paths"],"required_actions":["use a plain for loop in hot paths"],"triggers":["hot path","async iterator"],"directive_priority":"high"}',"",`LESSON: ${lesson}`,`CATEGORY: ${category}`,`TAGS: ${tags.join(", ")}`].join(`
1272
1272
  `)}function buildV3BatchEnrichmentPrompt(lessons){let lessonLines=lessons.map((item,idx)=>`${idx+1}. LESSON: ${item.lesson}
1273
1273
  CATEGORY: ${item.category}
1274
1274
  TAGS: ${item.tags.join(", ")}`).join(`
1275
- `);return["Convert each prose lesson below into an actionable knowledge directive.","Output ONLY a JSON array (no code fences, no commentary).",`The array length MUST be exactly ${lessons.length}.`,"Each array element at position i maps to lesson i (1-indexed above).","","For EACH element, mandatory requirements:","- At least ONE scope field non-empty:",' "applies_to_agents": string[] roles from: architect, coder, reviewer, test_engineer, sme, docs, designer, critic, curator',' "applies_to_tools": string[] tool names from: edit, write, patch, bash, read, grep, glob',"- At least ONE predicate field non-empty:",' "forbidden_actions": string[] | "required_actions": string[] | "verification_checks": string[]',"","Optional per element:",'"triggers": string[], "directive_priority": "low" | "medium" | "high" | "critical"',"","Example array:",'[{"applies_to_agents":["coder"],"required_actions":["run focused tests before commit"],"directive_priority":"high"}]',"","LESSONS:",lessonLines].join(`
1275
+ `);return["Convert each prose lesson below into an actionable knowledge directive.","Output ONLY a JSON array (no code fences, no commentary).",`The array length MUST be exactly ${lessons.length}.`,"Each array element at position i maps to lesson i (1-indexed above).","","For EACH element, mandatory requirements:","- At least ONE scope field non-empty:",' "applies_to_agents": string[] — roles from: architect, coder, reviewer, test_engineer, sme, docs, designer, critic, curator',' "applies_to_tools": string[] — tool names from: edit, write, patch, bash, read, grep, glob',"- At least ONE predicate field non-empty:",' "forbidden_actions": string[] | "required_actions": string[] | "verification_checks": string[]',"","Optional per element:",'"triggers": string[], "directive_priority": "low" | "medium" | "high" | "critical"',"","Example array:",'[{"applies_to_agents":["coder"],"required_actions":["run focused tests before commit"],"directive_priority":"high"}]',"","LESSONS:",lessonLines].join(`
1276
1276
  `)}function parseV3EnrichmentResponse(text){if(!text||typeof text!=="string")return{missing:["valid JSON object"]};let start=text.indexOf("{"),end=text.lastIndexOf("}");if(start<0||end<=start)return{missing:["valid JSON object"]};let parsed;try{parsed=JSON.parse(text.slice(start,end+1))}catch{return{missing:["valid JSON object"]}}if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return{missing:["valid JSON object"]};let raw=parsed,fields={};for(let key of ENRICHMENT_ALLOWED_FIELDS)if(raw[key]!==void 0)fields[key]=raw[key];let shape=validateActionableFields(fields);if(!shape.valid)return{missing:shape.errors};let actionability=validateActionability(fields);if(!actionability.actionable){let missing=[];if(actionability.reason==="missing_predicate"||actionability.reason==="missing_predicate_and_scope")missing.push("a non-empty predicate field (forbidden_actions, required_actions, or verification_checks)");if(actionability.reason==="missing_scope"||actionability.reason==="missing_predicate_and_scope")missing.push("a non-empty scope field (applies_to_agents or applies_to_tools)");return{missing}}return{fields}}function parseV3BatchEnrichmentResponse(text,expectedLength){let empty=Array.from({length:expectedLength},()=>null);if(!text||typeof text!=="string")return{fields:empty,missing:["valid JSON array"]};let start=text.indexOf("["),end=text.lastIndexOf("]");if(start<0||end<=start)return{fields:empty,missing:["valid JSON array"]};let parsed;try{parsed=JSON.parse(text.slice(start,end+1))}catch{return{fields:empty,missing:["valid JSON array"]}}if(!Array.isArray(parsed))return{fields:empty,missing:["valid JSON array"]};let fields=Array.from({length:expectedLength},()=>null),missing=[];for(let i=0;i<expectedLength;i++){let item=parsed[i];if(!item||typeof item!=="object"||Array.isArray(item)){missing.push(`item ${i+1}: valid JSON object`);continue}let raw=item,candidate={};for(let key of ENRICHMENT_ALLOWED_FIELDS)if(raw[key]!==void 0)candidate[key]=raw[key];let shape=validateActionableFields(candidate);if(!shape.valid){missing.push(`item ${i+1}: ${shape.errors.join("; ")}`);continue}let actionability=validateActionability(candidate);if(!actionability.actionable){let expected=[];if(actionability.reason==="missing_predicate"||actionability.reason==="missing_predicate_and_scope")expected.push("a non-empty predicate field (forbidden_actions, required_actions, or verification_checks)");if(actionability.reason==="missing_scope"||actionability.reason==="missing_predicate_and_scope")expected.push("a non-empty scope field (applies_to_agents or applies_to_tools)");missing.push(`item ${i+1}: ${expected.join("; ")}`);continue}fields[i]=candidate}if(parsed.length<expectedLength)missing.push(`expected ${expectedLength} items but got ${parsed.length}`);else if(parsed.length>expectedLength)warn(`[knowledge-curator] parseV3BatchEnrichmentResponse received ${parsed.length} items but expected ${expectedLength}; extras will be discarded`),missing.push(`got ${parsed.length} items but only first ${expectedLength} will be used; extras discarded`);return{fields,missing}}async function enrichLessonsToV3Batched(params){let quota=params.quota??{maxCalls:10,window:"utc"},out=Array.from({length:params.lessons.length},()=>null),batchSize=params.batchSize??ENRICHMENT_BATCH_SIZE;for(let start=0;start<params.lessons.length;start+=batchSize){let batch=params.lessons.slice(start,start+batchSize),prompt=buildV3BatchEnrichmentPrompt(batch),userInput=prompt,best=Array.from({length:batch.length},()=>null),retryHint="";for(let attempt=0;attempt<2;attempt++)try{if(!(await reserveQuota(params.directory,{nCalls:1,maxCalls:quota.maxCalls,window:quota.window,scope:"knowledge-enrichment"})).allowed)break;let response=await params.llmDelegate("",userInput,AbortSignal.timeout(ENRICHMENT_LLM_TIMEOUT_MS)),parsed=parseV3BatchEnrichmentResponse(response,batch.length);best=best.map((current,idx)=>current??parsed.fields[idx]);let unresolved=best.map((fields,idx)=>({fields,idx})).filter((item)=>item.fields===null).map((item)=>item.idx+1);if(unresolved.length===0)break;retryHint=parsed.missing.join("; ");let resolvedList=best.map((fields,idx)=>({fields,idx})).filter((item)=>item.fields!==null).map((item)=>item.idx+1),preserveClause=resolvedList.length>0?`Preserve the already-valid entries for items ${resolvedList.join(", ")} exactly as you returned them previously. `:"";userInput=`${prompt}
1277
1277
 
1278
1278
  RETRY: your last output still missed valid directives for items ${unresolved.join(", ")}. ${retryHint} ${preserveClause}Return a full JSON array with valid entries for every item.`}catch(err){warn(`[knowledge-curator] v3 batch enrichment attempt ${attempt+1} failed: ${err instanceof Error?err.message:String(err)}`)}for(let i=0;i<best.length;i++)out[start+i]=best[i]}return out}async function enrichLessonToV3(params){let quota=params.quota??{maxCalls:10,window:"utc"},prompt=buildV3EnrichmentPrompt(params.lesson,params.category,params.tags),userInput=prompt;for(let attempt=0;attempt<2;attempt++)try{if(!(await reserveQuota(params.directory,{nCalls:1,maxCalls:quota.maxCalls,window:quota.window,scope:"knowledge-enrichment"})).allowed)return null;let response=await params.llmDelegate("",userInput,AbortSignal.timeout(ENRICHMENT_LLM_TIMEOUT_MS)),result=parseV3EnrichmentResponse(response);if("fields"in result)return result.fields;userInput=`${prompt}
@@ -1342,16 +1342,16 @@ ${inv.staleActiveSkills.slice(0,10).map((s)=>`- ${s.slug} | ${s.reasons.join(",
1342
1342
  `}function isAbortError2(err){return err instanceof Error&&(err.name==="AbortError"||err.message==="skill_improver_aborted")}function throwIfAborted2(signal){if(!signal?.aborted)return;let err=Error("skill_improver_aborted");throw err.name="AbortError",err}function buildDeterministicProposal(args2){let lines=[];if(lines.push("---"),lines.push("source: deterministic_fallback"),lines.push(`generated_at: ${args2.now.toISOString()}`),lines.push(`targets: [${args2.targets.join(", ")}]`),lines.push(`model: ${args2.model??"(none — deterministic body)"}`),lines.push("---"),lines.push(""),lines.push("# Skill Improvement Proposal (deterministic fallback)"),lines.push(""),lines.push("> No OpenCode LLM client was available when this proposal was generated. The body below is a deterministic inventory summary, not an LLM-derived analysis. To produce a real LLM proposal, run `skill_improve` from a session where the OpenCode runtime has wired `swarmState.opencodeClient`, or set `skill_improver.allow_deterministic_fallback: false` to force a hard failure instead of this fallback."),lines.push(""),lines.push("## Inventory snapshot"),lines.push(`- Knowledge entries: swarm=${args2.inventory.knowledge.swarm}, hive=${args2.inventory.knowledge.hive}, archived=${args2.inventory.knowledge.archived}`),lines.push(`- Generated skills: proposals=${args2.inventory.skills.proposals}, active=${args2.inventory.skills.active}`),lines.push(`- Active skills with readable metadata: ${args2.inventory.skills.metadataReadable} (stale=${args2.inventory.skills.stale})`),lines.push(`- High-confidence un-skill'd clusters: ${args2.inventory.highConfidenceClusters}`),args2.inventory.staleActiveSkills.length>0)lines.push(`- Stale active skills: ${args2.inventory.staleActiveSkills.map((s)=>s.slug).join(", ")}`);if(lines.push(""),lines.push("## Recommendations"),args2.inventory.highConfidenceClusters>0)lines.push(`- Run \`skill_generate { mode: "draft" }\` to emit ${args2.inventory.highConfidenceClusters} draft SKILL.md proposal(s).`);if(args2.targets.includes("architect_prompt"))lines.push("- Manually review architect prompt against current high-priority directives.");if(args2.targets.includes("spec"))lines.push("- Audit `.swarm/spec.md` for drift.");if(args2.targets.includes("knowledge"))lines.push("- Archive low-confidence (< 0.3) entries with applied_explicit_count == 0 and shown_count > 5.");return lines.push(""),lines.join(`
1343
1343
  `)}function buildLLMProposalFrame(args2){let lines=[];if(lines.push("---"),lines.push("source: llm"),lines.push(`generated_at: ${args2.now.toISOString()}`),lines.push(`targets: [${args2.targets.join(", ")}]`),args2.model)lines.push(`model: ${args2.model}`);return lines.push("---"),lines.push(""),lines.push(args2.body.trim()),lines.push(""),lines.join(`
1344
1344
  `)}async function reconcileStaleActiveSkills(directory,options={}){let result={regenerated:[],retired:[],skipped:[],checked:0},skills;try{skills=await listSkills(directory)}catch{return result}for(let skill of skills.active){let content;try{content=await readFile23(skill.path,"utf-8")}catch{continue}let fm=parseDraftFrontmatter(content);if(fm?.skillOrigin==="shim"){result.skipped.push(skill.slug);continue}if(!(!fm||fm.sourceKnowledgeIds.length===0||!fm.generatedAt))continue;if(result.checked+=1,options.dryRun){result.retired.push(skill.slug);continue}try{let regen=await _internals48.regenerateSkill(directory,skill.slug,{evaluate:!1});if(regen.regenerated)result.regenerated.push(skill.slug);else if(regen.retired)result.retired.push(skill.slug);else if((await retireSkill(directory,skill.slug,"stale_no_source_knowledge")).retired)result.retired.push(skill.slug)}catch(err){warn(`[skill-improver] reconcileStaleActiveSkills: failed to reconcile '${skill.slug}': ${err instanceof Error?err.message:String(err)}`),result.skipped.push(skill.slug)}}return result}async function runSkillImprover(req){let cfg=req.config,now=req.now??new Date,targets=req.targets&&req.targets.length>0?req.targets:cfg.targets,writeMode=req.mode??cfg.write_mode,maxCalls=Math.max(1,Math.min(cfg.max_calls_per_day,req.maxCalls??1)),noQuota={date:now.toISOString().slice(0,10),calls_used:0,max_calls:cfg.max_calls_per_day};if(!cfg.enabled)return{ran:!1,reason:"skill_improver.enabled is false",quota:noQuota};if(req.signal?.aborted)return{ran:!1,reason:"skill_improver aborted",quota:noQuota};let delegate=req.delegate??createSkillImproverLLMDelegate(req.directory,req.sessionId);if(!delegate&&!cfg.allow_deterministic_fallback)return{ran:!1,reason:"no_llm_client: skill_improver.allow_deterministic_fallback is false and no OpenCode client is wired. Run from a session where swarmState.opencodeClient is available, or enable allow_deterministic_fallback to use the offline path.",quota:noQuota};let reservation=await reserveQuota(req.directory,{nCalls:maxCalls,maxCalls:cfg.max_calls_per_day,window:cfg.quota_window,now});if(!reservation.allowed)return{ran:!1,reason:reservation.reason??"quota exhausted",quota:{date:reservation.state.date,calls_used:reservation.state.calls_used,max_calls:reservation.state.max_calls}};let networkStarted=!1,sideEffectsStarted=!1,reservationQuota={date:reservation.state.date,calls_used:reservation.state.calls_used,max_calls:reservation.state.max_calls},releaseReservedQuota=async()=>{let released=await releaseQuota(req.directory,{nCalls:maxCalls,maxCalls:cfg.max_calls_per_day,window:cfg.quota_window,now}).catch(()=>({...reservation.state,calls_used:Math.max(0,reservation.state.calls_used-maxCalls)}));return{date:released.date,calls_used:released.calls_used,max_calls:released.max_calls}},abortResult=async()=>({ran:!1,reason:"skill_improver aborted",quota:networkStarted||sideEffectsStarted?reservationQuota:await releaseReservedQuota()}),inventory;try{throwIfAborted2(req.signal),inventory=await gatherInventory(req.directory),throwIfAborted2(req.signal)}catch(err){if(isAbortError2(err))return await abortResult();return await releaseQuota(req.directory,{nCalls:maxCalls,maxCalls:cfg.max_calls_per_day,window:cfg.quota_window,now}).catch(()=>{}),{ran:!1,reason:`inventory_failed: ${err instanceof Error?err.message:String(err)}`,quota:{date:reservation.state.date,calls_used:reservation.state.calls_used-maxCalls,max_calls:reservation.state.max_calls}}}let body,source;if(delegate)try{if(throwIfAborted2(req.signal),networkStarted=!0,body=await delegate(buildSystemPrompt(targets,{...cfg,write_mode:writeMode}),buildUserPrompt(inventory),req.signal),throwIfAborted2(req.signal),!body||body.trim().length===0)throw Error("empty LLM response");source="llm"}catch(err){if(isAbortError2(err))return await abortResult();return{ran:!1,reason:`llm_call_failed: ${err instanceof Error?err.message:String(err)}`,quota:{date:reservation.state.date,calls_used:reservation.state.calls_used,max_calls:reservation.state.max_calls}}}else{try{throwIfAborted2(req.signal)}catch(err){if(isAbortError2(err))return await abortResult();throw err}body="",source="deterministic_fallback"}let draftSkillsWritten;if(writeMode==="draft_skills"&&inventory.matureCandidates.length>0){try{throwIfAborted2(req.signal)}catch(err){if(isAbortError2(err))return await abortResult();throw err}sideEffectsStarted=!0,draftSkillsWritten=(await generateSkills({directory:req.directory,mode:"draft",minConfidence:DEFAULT_SKILL_MIN_CONFIDENCE,minConfirmations:DEFAULT_SKILL_MIN_CONFIRMATIONS,evaluate:req.evaluateDrafts??!1})).written.map((w)=>({slug:w.slug,path:w.path,sourceKnowledgeIds:w.sourceKnowledgeIds}))}try{throwIfAborted2(req.signal)}catch(err){if(isAbortError2(err))return await abortResult();throw err}let proposalDir=path82.join(req.directory,".swarm","skill-improver","proposals"),proposalFile=path82.join(proposalDir,`${timestampSlug(now)}.md`),finalBody=source==="llm"?buildLLMProposalFrame({body,targets,model:cfg.model,now}):buildDeterministicProposal({targets,inventory,model:cfg.model,now});sideEffectsStarted=!0,await atomicWrite4(proposalFile,finalBody);let unactionableHardening;if(delegate)unactionableHardening=await hardenUnactionableEntries({directory:req.directory,llmDelegate:delegate,quota:req.enrichmentQuota});let motifResult=await writeMotifProposals(req.directory),macroMotifs={motifs:motifResult.motifs,proposalsWritten:motifResult.proposalsWritten.length},successMotifResult=await writeSuccessMotifProposals(req.directory),successMotifs={motifs:successMotifResult.motifs,proposalsWritten:successMotifResult.proposalsWritten.length},staleSkillReconciliation=await reconcileStaleActiveSkills(req.directory,{dryRun:writeMode!=="draft_skills"}),autoApply;if(req.allowAutoApply!==!1&&delegate&&req.sessionId&&hasActiveFullAuto(req.sessionId))try{autoApply=await autoApplyProposals(req.directory,delegate)}catch{}return{ran:!0,proposalPath:proposalFile,source,quota:{date:reservation.state.date,calls_used:reservation.state.calls_used,max_calls:reservation.state.max_calls},draftSkillsWritten,model:cfg.model??void 0,unactionableHardening,macroMotifs,successMotifs,staleSkillReconciliation,autoApply}}var _internals48;var init_skill_improver=__esm(()=>{init_knowledge_store();init_skill_improver_llm_factory();init_state2();init_logger();init_skill_generator();init_skill_improver_quota();init_trajectory_cluster();init_unactionable_hardening();_internals48={runSkillImprover,buildDeterministicProposal,buildLLMProposalFrame,buildSystemPrompt,buildUserPrompt,gatherInventory,reconcileStaleActiveSkills,regenerateSkill}});import{existsSync as existsSync39}from"node:fs";import path83 from"node:path";async function executeWriteRetro(args2,directory){if(/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])(:|$)/i.test(directory))return JSON.stringify({success:!1,message:"Invalid directory: reserved device name"},null,2);if(!existsSync39(path83.join(directory,".swarm")))return JSON.stringify({success:!1,message:`Cannot write evidence in "${directory}" — no .swarm/ folder was found. Run write_retro from an initialized project root.`},null,2);let phase=args2.phase;if(!Number.isInteger(phase)||phase<1)return JSON.stringify({success:!1,phase,message:"Invalid phase: must be a positive integer"},null,2);if(!["trivial","simple","moderate","complex"].includes(args2.task_complexity))return JSON.stringify({success:!1,phase,message:"Invalid task_complexity: must be one of 'trivial'|'simple'|'moderate'|'complex'"},null,2);if(!Number.isInteger(args2.task_count)||args2.task_count<1)return JSON.stringify({success:!1,phase,message:"Invalid task_count: must be a positive integer >= 1"},null,2);if(!Number.isInteger(args2.total_tool_calls)||args2.total_tool_calls<0)return JSON.stringify({success:!1,phase,message:"Invalid total_tool_calls: must be a non-negative integer"},null,2);if(!Number.isInteger(args2.coder_revisions)||args2.coder_revisions<0)return JSON.stringify({success:!1,phase,message:"Invalid coder_revisions: must be a non-negative integer"},null,2);if(!Number.isInteger(args2.reviewer_rejections)||args2.reviewer_rejections<0)return JSON.stringify({success:!1,phase,message:"Invalid reviewer_rejections: must be a non-negative integer"},null,2);if(!Number.isInteger(args2.test_failures)||args2.test_failures<0)return JSON.stringify({success:!1,phase,message:"Invalid test_failures: must be a non-negative integer"},null,2);if(!Number.isInteger(args2.security_findings)||args2.security_findings<0)return JSON.stringify({success:!1,phase,message:"Invalid security_findings: must be a non-negative integer"},null,2);if(!Number.isInteger(args2.integration_issues)||args2.integration_issues<0)return JSON.stringify({success:!1,phase,message:"Invalid integration_issues: must be a non-negative integer"},null,2);if(args2.loop_detections!==void 0&&(!Number.isInteger(args2.loop_detections)||args2.loop_detections<0))return JSON.stringify({success:!1,phase,message:"Invalid loop_detections: must be a non-negative integer"},null,2);if(args2.circuit_breaker_trips!==void 0&&(!Number.isInteger(args2.circuit_breaker_trips)||args2.circuit_breaker_trips<0))return JSON.stringify({success:!1,phase,message:"Invalid circuit_breaker_trips: must be a non-negative integer"},null,2);if(args2.phase>99)return JSON.stringify({success:!1,phase,message:"Invalid phase: must be <= 99"},null,2);if(args2.task_count>9999)return JSON.stringify({success:!1,phase,message:"Invalid task_count: must be <= 9999"},null,2);if(args2.total_tool_calls>9999)return JSON.stringify({success:!1,phase,message:"Invalid total_tool_calls: must be <= 9999"},null,2);if(args2.coder_revisions>999)return JSON.stringify({success:!1,phase,message:"Invalid coder_revisions: must be <= 999"},null,2);if(args2.reviewer_rejections>999)return JSON.stringify({success:!1,phase,message:"Invalid reviewer_rejections: must be <= 999"},null,2);if(args2.loop_detections!==void 0&&args2.loop_detections>9999)return JSON.stringify({success:!1,phase,message:"Invalid loop_detections: must be <= 9999"},null,2);if(args2.circuit_breaker_trips!==void 0&&args2.circuit_breaker_trips>9999)return JSON.stringify({success:!1,phase,message:"Invalid circuit_breaker_trips: must be <= 9999"},null,2);if(args2.test_failures>9999)return JSON.stringify({success:!1,phase,message:"Invalid test_failures: must be <= 9999"},null,2);if(args2.security_findings>999)return JSON.stringify({success:!1,phase,message:"Invalid security_findings: must be <= 999"},null,2);if(args2.integration_issues>999)return JSON.stringify({success:!1,phase,message:"Invalid integration_issues: must be <= 999"},null,2);let summary=args2.summary;if(typeof summary!=="string"||summary.trim().length===0)return JSON.stringify({success:!1,phase,message:"Invalid summary: must be a non-empty string"},null,2);if(args2.task_id!==void 0){let tid=args2.task_id;if(!tid||tid.length===0||tid.length>200)return JSON.stringify({success:!1,phase,message:"Invalid task ID: must match pattern"},null,2);if(/\0/.test(tid))return JSON.stringify({success:!1,phase,message:"Invalid task ID: contains null bytes"},null,2);for(let i=0;i<tid.length;i++)if(tid.charCodeAt(i)<32)return JSON.stringify({success:!1,phase,message:"Invalid task ID: contains control characters"},null,2);if(tid.includes("..")||tid.includes("/")||tid.includes("\\"))return JSON.stringify({success:!1,phase,message:"Invalid task ID: path traversal detected"},null,2);if(!/^(retro-[a-zA-Z0-9][a-zA-Z0-9_-]*|\d+\.\d+(\.\d+)*)$/.test(tid))return JSON.stringify({success:!1,phase,message:"Invalid task ID: must match pattern"},null,2)}let taskId=args2.task_id??`retro-${phase}`,retroEntry={task_id:taskId,type:"retrospective",timestamp:new Date().toISOString(),agent:"architect",verdict:"pass",summary,metadata:args2.metadata,phase_number:phase,total_tool_calls:args2.total_tool_calls,coder_revisions:args2.coder_revisions,reviewer_rejections:args2.reviewer_rejections,loop_detections:args2.loop_detections,circuit_breaker_trips:args2.circuit_breaker_trips,test_failures:args2.test_failures,security_findings:args2.security_findings,integration_issues:args2.integration_issues,task_count:args2.task_count,task_complexity:args2.task_complexity,top_rejection_reasons:args2.top_rejection_reasons??[],lessons_learned:(args2.lessons_learned??[]).slice(0,5),user_directives:[],approaches_tried:[],error_taxonomy:[]},taxonomy=[];try{let phaseTaskIds=(await listEvidenceTaskIds(directory)).filter((id)=>id.startsWith(`${phase}.`)),sessionStart=args2.metadata&&typeof args2.metadata.session_start==="string"?args2.metadata.session_start:void 0;for(let phaseTaskId of phaseTaskIds){let result=await loadEvidence(directory,phaseTaskId);if(result.status!=="found")continue;let bundle=result.bundle;if(sessionStart&&bundle.updated_at<sessionStart)continue;for(let entry of bundle.entries){let e=entry;if(e.type==="review"&&e.verdict==="fail"){let reasonParts=[];if(typeof e.summary==="string")reasonParts.push(e.summary);if(Array.isArray(e.issues)){for(let iss of e.issues)if(typeof iss.message==="string")reasonParts.push(iss.message)}let reason=reasonParts.join(" ");if(/signature|type|contract|interface/i.test(reason))taxonomy.push("interface_mismatch");else taxonomy.push("logic_error")}else if(e.type==="test"&&e.verdict==="fail")taxonomy.push("logic_error");else if(e.agent==="scope_guard"&&e.verdict==="fail")taxonomy.push("scope_creep");else if(e.agent==="loop_detector"&&e.verdict==="fail")taxonomy.push("gate_evasion")}}}catch{}retroEntry.error_taxonomy=[...new Set(taxonomy)];let validationResult=RetrospectiveEvidenceSchema.safeParse(retroEntry);if(!validationResult.success)return JSON.stringify({success:!1,error:`Retrospective entry failed validation: ${validationResult.error.message}`},null,2);try{return await saveEvidence(directory,taskId,retroEntry),JSON.stringify({success:!0,task_id:taskId,phase,message:`Retrospective evidence written to .swarm/evidence/${taskId}/evidence.json`},null,2)}catch(error93){return JSON.stringify({success:!1,phase,message:error93 instanceof Error?error93.message:String(error93)},null,2)}}var write_retro,_internals49;var init_write_retro=__esm(()=>{init_zod();init_evidence_schema();init_manager2();init_create_tool();write_retro=createSwarmTool({description:"Write a retrospective evidence bundle for a completed phase. Accepts flat retro fields and writes a correctly-wrapped EvidenceBundle to .swarm/evidence/retro-{phase}/evidence.json. Use this instead of manually writing retro JSON to avoid schema validation failures in phase_complete.",args:{phase:exports_external.number().int().min(1).max(99).describe("The phase number being completed (e.g., 1, 2, 3)"),summary:exports_external.string().describe("Human-readable summary of the phase"),task_count:exports_external.number().int().min(1).max(9999).describe("Count of tasks completed in this phase"),task_complexity:exports_external.enum(["trivial","simple","moderate","complex"]).describe("Complexity level of the completed tasks"),total_tool_calls:exports_external.number().int().min(0).max(9999).describe("Total number of tool calls in this phase"),coder_revisions:exports_external.number().int().min(0).max(999).describe("Number of coder revisions made"),reviewer_rejections:exports_external.number().int().min(0).max(999).describe("Number of reviewer rejections received"),loop_detections:exports_external.number().int().min(0).max(9999).optional().describe("Number of loop detection events in this phase"),circuit_breaker_trips:exports_external.number().int().min(0).max(9999).optional().describe("Number of circuit breaker trips in this phase"),test_failures:exports_external.number().int().min(0).max(9999).describe("Number of test failures encountered"),security_findings:exports_external.number().int().min(0).max(999).describe("Number of security findings"),integration_issues:exports_external.number().int().min(0).max(999).describe("Number of integration issues"),lessons_learned:exports_external.array(exports_external.string()).max(5).optional().describe("Key lessons learned from this phase (max 5)"),top_rejection_reasons:exports_external.array(exports_external.string()).optional().describe("Top reasons for reviewer rejections"),task_id:exports_external.string().optional().describe("Optional custom task ID (defaults to retro-{phase})"),metadata:exports_external.record(exports_external.string(),exports_external.unknown()).optional().describe("Optional additional metadata")},execute:async(args2,directory)=>{let rawPhase=args2.phase!==void 0?Number(args2.phase):0;try{let writeRetroArgs={phase:Number(args2.phase),summary:String(args2.summary??""),task_count:Number(args2.task_count),task_complexity:args2.task_complexity,total_tool_calls:Number(args2.total_tool_calls),coder_revisions:Number(args2.coder_revisions),reviewer_rejections:Number(args2.reviewer_rejections),loop_detections:args2.loop_detections!=null?Number(args2.loop_detections):void 0,circuit_breaker_trips:args2.circuit_breaker_trips!=null?Number(args2.circuit_breaker_trips):void 0,test_failures:Number(args2.test_failures),security_findings:Number(args2.security_findings),integration_issues:Number(args2.integration_issues),lessons_learned:Array.isArray(args2.lessons_learned)?args2.lessons_learned.map(String):void 0,top_rejection_reasons:Array.isArray(args2.top_rejection_reasons)?args2.top_rejection_reasons.map(String):void 0,task_id:args2.task_id!==void 0?String(args2.task_id):void 0,metadata:args2.metadata};return await _internals49.executeWriteRetro(writeRetroArgs,directory)}catch{return JSON.stringify({success:!1,phase:rawPhase,message:"Invalid arguments"},null,2)}}}),_internals49={executeWriteRetro,write_retro}});import*as child_process5 from"node:child_process";import*as fsSync8 from"node:fs";import{promises as fs36}from"node:fs";import path84 from"node:path";async function runAbortableReflection(input,timeoutMs){let controller=new AbortController,timeout,reflectionPromise=runSessionReflection({...input,signal:controller.signal}),timeoutPromise=new Promise((_,reject)=>{timeout=setTimeout(()=>{reject(Error(`session_reflection exceeded ${timeoutMs}ms budget`)),controller.abort()},timeoutMs)});try{return await Promise.race([reflectionPromise,timeoutPromise])}finally{if(timeout)clearTimeout(timeout)}}async function runAbortableSkillReview(req,timeoutMs){let controller=new AbortController,timeout,skillReviewPromise=runSkillImprover({...req,signal:controller.signal}),timeoutPromise=new Promise((_,reject)=>{timeout=setTimeout(()=>{reject(Error(`skill_review exceeded ${timeoutMs}ms budget`)),controller.abort()},timeoutMs)});try{return await Promise.race([skillReviewPromise,timeoutPromise])}finally{if(timeout)clearTimeout(timeout)}}function normalizeLessonText(text){return(text??"").trim().toLowerCase()}function countSessionKnowledgeEntries(entries,sessionStart,fallbackCount){if(!sessionStart)return fallbackCount;let sessionStartMs=Date.parse(sessionStart);if(!Number.isFinite(sessionStartMs))return fallbackCount;return entries.filter((entry)=>{if(typeof entry.created_at!=="string")return!1;let createdAtMs=Date.parse(entry.created_at);return Number.isFinite(createdAtMs)&&createdAtMs>=sessionStartMs}).length}async function copyDirRecursiveWithFailures(src,dest){let count=0,failures=[],entries=await fs36.readdir(src);await fs36.mkdir(dest,{recursive:!0});for(let entry of entries){let srcEntry=path84.join(src,entry),destEntry=path84.join(dest,entry);try{if((await fs36.stat(srcEntry)).isDirectory()){let subResult=await copyDirRecursiveWithFailures(srcEntry,destEntry);count+=subResult.copied,failures.push(...subResult.failures)}else try{await fs36.copyFile(srcEntry,destEntry),count++}catch(err){if(err?.code!=="ENOENT")failures.push(`${srcEntry}: ${err instanceof Error?err.message:String(err)}`)}}catch(err){if(err?.code!=="ENOENT")failures.push(`${srcEntry}: ${err instanceof Error?err.message:String(err)}`)}}return{copied:count,failures}}async function copyDirRecursive(src,dest){return(await copyDirRecursiveWithFailures(src,dest)).copied}function guaranteeAllPlansComplete(planData){let closedPhaseIds=[],closedTaskIds=[];for(let phase of planData.phases??[]){if(!(phase.status==="complete"||phase.status==="completed"||phase.status==="closed"))phase.status="closed",closedPhaseIds.push(phase.id);for(let task of phase.tasks??[])if(!(task.status==="completed"||task.status==="complete"||task.status==="closed"))task.status="closed",task.close_reason="session_terminated",closedTaskIds.push(task.id)}return{closedPhaseIds,closedTaskIds}}async function runFinalizeStage(ctx){if(!ctx.planAlreadyDone)for(let phase of ctx.inProgressPhases){ctx.closedPhases.push(phase.id);let retroResult;try{retroResult=await executeWriteRetro({phase:phase.id,summary:ctx.isForced?"Phase force-closed via /swarm close --force":"Phase closed via /swarm close",task_count:Math.max(1,(phase.tasks??[]).length),task_complexity:"simple",total_tool_calls:0,coder_revisions:0,reviewer_rejections:0,test_failures:0,security_findings:0,integration_issues:0},ctx.directory)}catch(retroError){ctx.warnings.push(`Retrospective write threw for phase ${phase.id}: ${retroError instanceof Error?retroError.message:String(retroError)}`)}if(retroResult!==void 0)try{if(JSON.parse(retroResult).success!==!0)ctx.warnings.push(`Retrospective write failed for phase ${phase.id}`)}catch{}for(let task of phase.tasks??[])if(task.status!=="completed"&&task.status!=="complete")ctx.closedTasks.push(task.id)}{let earliest=1/0;for(let[,session]of swarmState.agentSessions)if(session.lastAgentEventTime>0&&session.lastAgentEventTime<earliest)earliest=session.lastAgentEventTime;if(earliest<1/0)ctx.sessionStart=new Date(earliest).toISOString()}if(!ctx.sessionStart)ctx.sessionStart=readEarliestSessionStart(ctx.directory)??void 0;if(!(ctx.closedPhases.length>0)&&!ctx.planExists)try{let sessionRetroResult=await executeWriteRetro({phase:1,task_id:"retro-session",summary:ctx.isForced?"Plan-free session force-closed via /swarm close --force":"Plan-free session closed via /swarm close",task_count:1,task_complexity:"simple",total_tool_calls:0,coder_revisions:0,reviewer_rejections:0,test_failures:0,security_findings:0,integration_issues:0,metadata:{session_scope:"plan_free",...ctx.sessionStart?{session_start:ctx.sessionStart}:{}}},ctx.directory);try{let parsed=JSON.parse(sessionRetroResult);if(parsed.success!==!0)ctx.warnings.push(`Session retrospective write failed: ${parsed.message??"unknown"}`)}catch{}}catch(retroError){ctx.warnings.push(`Session retrospective write threw: ${retroError instanceof Error?retroError.message:String(retroError)}`)}let lessonsFilePath=path84.join(ctx.swarmDir,"close-lessons.md");try{let lessonsText=await fs36.readFile(lessonsFilePath,"utf-8");ctx.explicitLessons=lessonsText.split(`
1345
- `).map((line)=>line.trim()).filter((line)=>line.length>0&&!line.startsWith("#"))}catch{}try{let evidenceDir=path84.join(ctx.swarmDir,"evidence"),retroDirs=(await fs36.readdir(evidenceDir)).filter((e)=>e.startsWith("retro-")).sort((a,b)=>a.localeCompare(b,void 0,{numeric:!0}));for(let retroDir of retroDirs){let evidencePath=path84.join(evidenceDir,retroDir,"evidence.json");try{let content=await fs36.readFile(evidencePath,"utf-8"),parsed=JSON.parse(content),entries=parsed.entries??[parsed];for(let entry of entries)if(Array.isArray(entry.lessons_learned)){for(let lesson of entry.lessons_learned)if(typeof lesson==="string"&&lesson.trim().length>0)ctx.retroLessons.push(lesson.trim())}}catch{}}}catch{}let dedupedRetroLessons=ctx.retroLessons;try{let existingEntries=await readKnowledge(resolveSwarmKnowledgePath(ctx.directory)),existingLessonTexts=new Set(existingEntries.map((e)=>normalizeLessonText(e.lesson)).filter((t)=>t.length>0));if(existingLessonTexts.size>0)dedupedRetroLessons=ctx.retroLessons.filter((l)=>!existingLessonTexts.has(normalizeLessonText(l)))}catch{dedupedRetroLessons=ctx.retroLessons}ctx.allLessons=[...new Set([...ctx.explicitLessons,...dedupedRetroLessons])],ctx.curationSucceeded=!1;try{ctx.curationResult=await _internals50.curateAndStoreSwarm(ctx.allLessons,ctx.projectName,{phase_number:0},ctx.directory,ctx.config,{llmDelegate:_internals50.createCuratorLLMDelegate(ctx.directory,"phase",ctx.options.sessionID),enrichmentQuota:{maxCalls:ctx.config.enrichment.max_calls_per_day,window:ctx.config.enrichment.quota_window}}),ctx.curationSucceeded=!0}catch(error93){let msg=error93 instanceof Error?error93.message:String(error93);ctx.warnings.push(`Lessons curation failed: ${msg}`),console.warn("[close-command] curateAndStoreSwarm error:",error93)}if(ctx.curationSucceeded&&ctx.allLessons.length>0)await fs36.unlink(lessonsFilePath).catch(()=>{});if(ctx.curationSucceeded)if(ctx.config.hive_enabled===!1);else try{let entries=await readKnowledge(resolveSwarmKnowledgePath(ctx.directory)),result=await _internals50.checkHivePromotions(entries,ctx.config,ctx.directory);ctx.hivePromoted=result.new_promotions}catch(hiveErr){let msg=hiveErr instanceof Error?hiveErr.message:String(hiveErr);ctx.warnings.push(`Hive promotion failed: ${msg}`)}ctx.fallbackKnowledgeCreated=ctx.curationResult?.stored??0,ctx.sessionKnowledgeCreated=ctx.fallbackKnowledgeCreated;try{let knowledgePath=resolveSwarmKnowledgePath(ctx.directory),entries=await readKnowledge(knowledgePath);ctx.sessionKnowledgeCreated=countSessionKnowledgeEntries(entries,ctx.sessionStart,ctx.fallbackKnowledgeCreated)}catch(knowledgeErr){let msg=knowledgeErr instanceof Error?knowledgeErr.message:String(knowledgeErr);ctx.warnings.push(`Knowledge session count failed: ${msg}`)}if(ctx.knowledgeSkillHint=ctx.sessionKnowledgeCreated>0?`${ctx.sessionKnowledgeCreated} knowledge entries created this session. Consider running skill_improve or skill_generate to compile mature entries into skills.`:"",ctx.runSkillReview)try{let{config:loadedConfig}=_internals50.loadPluginConfigWithMeta(ctx.directory),skillImproverConfig=SkillImproverConfigSchema.parse(loadedConfig.skill_improver??{}),skillReviewResult=await runAbortableSkillReview({directory:ctx.directory,config:skillImproverConfig,targets:["skills","knowledge"],mode:"proposal",sessionId:ctx.options.sessionID,enrichmentQuota:{maxCalls:ctx.config.enrichment.max_calls_per_day,window:ctx.config.enrichment.quota_window}},ctx.options.skillReviewTimeoutMs??CLOSE_SKILL_REVIEW_TIMEOUT_MS);if(skillReviewResult.ran){let proposal=skillReviewResult.proposalPath?` Proposal: ${skillReviewResult.proposalPath}.`:"",source=skillReviewResult.source?` Source: ${skillReviewResult.source}.`:"";ctx.skillReviewSummary=`Skill review proposal generated.${proposal}${source}`}else{let reason=skillReviewResult.reason??"unknown reason";ctx.skillReviewSummary=`Skill review skipped: ${reason}`,ctx.warnings.push(ctx.skillReviewSummary)}}catch(skillReviewErr){let msg=skillReviewErr instanceof Error?skillReviewErr.message:String(skillReviewErr);ctx.skillReviewSummary=`Skill review failed: ${msg}`,ctx.warnings.push(ctx.skillReviewSummary)}try{ctx.sessionReflection=await runAbortableReflection({directory:ctx.directory,toolAggregates:swarmState.toolAggregates,agentSessions:swarmState.agentSessions,sessionId:ctx.options.sessionID},CLOSE_REFLECTION_TIMEOUT_MS),await writeSessionReflection(ctx.directory,ctx.sessionReflection)}catch(reflectionErr){let msg=reflectionErr instanceof Error?reflectionErr.message:String(reflectionErr);ctx.warnings.push(`Session reflection failed: ${msg}`)}if(ctx.planExists){ctx.originalStatuses=new Map;for(let phase of ctx.planData.phases??[])for(let task of phase.tasks??[])ctx.originalStatuses.set(task.id,task.status);let planDataSnapshot=structuredClone(ctx.planData),closedPhasesLenBefore=ctx.closedPhases.length,closedTasksLenBefore=ctx.closedTasks.length;ctx.guaranteeResult=guaranteeAllPlansComplete(ctx.planData);for(let phaseId of ctx.guaranteeResult.closedPhaseIds)if(!ctx.closedPhases.includes(phaseId))ctx.closedPhases.push(phaseId);for(let taskId of ctx.guaranteeResult.closedTaskIds)if(!ctx.closedTasks.includes(taskId))ctx.closedTasks.push(taskId);if(!ctx.planAlreadyDone||ctx.guaranteeResult.closedPhaseIds.length>0||ctx.guaranteeResult.closedTaskIds.length>0)try{await _internals50.closePlanTerminalState(ctx.directory,ctx.planData,{closedPhaseIds:ctx.guaranteeResult.closedPhaseIds,closedTaskIds:ctx.guaranteeResult.closedTaskIds,originalStatuses:ctx.originalStatuses})}catch(error93){let msg=error93 instanceof Error?error93.message:String(error93);ctx.warnings.push(`Failed to persist terminal plan state: ${msg}`),console.warn("[close-command] Failed to write terminal plan state:",error93),ctx.planData=planDataSnapshot,ctx.closedPhases.length=closedPhasesLenBefore,ctx.closedTasks.length=closedTasksLenBefore}}try{let{CuratorConfigSchema:CCS}=await Promise.resolve().then(() => (init_schema(),exports_schema)),{config:pmLoadedConfig}=_internals50.loadPluginConfigWithMeta(ctx.directory),curatorCfg=CCS.parse(pmLoadedConfig.curator??{});if(curatorCfg.enabled&&curatorCfg.postmortem_enabled){let pmResult=await _internals50.runCuratorPostMortem(ctx.directory,{llmDelegate:_internals50.createCuratorLLMDelegate(ctx.directory,"postmortem",ctx.options.sessionID),scope:"project",sessionID:ctx.options.sessionID});if(pmResult.success&&pmResult.summary)ctx.postMortemSummary=pmResult.summary;for(let w of pmResult.warnings)ctx.warnings.push(`[POST-MORTEM] ${w}`)}}catch(err){let msg=err instanceof Error?err.message:String(err);ctx.warnings.push(`Post-mortem failed: ${msg}`)}}async function copySqliteSafe(srcPath,destPath,laneEnv){if(!fsSync8.existsSync(srcPath))return{success:!0,skipped:!0,reason:"source does not exist (ENOENT)"};let checkpointVerified=!1;try{let result=_internals50.spawnSync("sqlite3",[srcPath,"PRAGMA wal_checkpoint(TRUNCATE);"],{cwd:path84.dirname(srcPath),encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:1e4,windowsHide:!0,maxBuffer:1024,envOverrides:laneEnv});if(result.error){if(result.error.code==="ENOENT")try{return await fs36.copyFile(srcPath,destPath),{success:!0,reason:"copied without WAL checkpoint (sqlite3 CLI unavailable)"}}catch(copyErr){return{success:!1,reason:`fallback copy failed: ${copyErr instanceof Error?copyErr.message:String(copyErr)}`}}return{success:!1,reason:`wal_checkpoint failed: ${result.error instanceof Error?result.error.message:String(result.error)}`}}if(result.status!==0)return{success:!1,reason:`wal_checkpoint exited with code ${result.status}`};let lines=(result.stdout||"").trim().split(`
1346
- `).filter((l)=>l.trim());if(lines.length>=1){let columns=lines[0].split("|"),busyFlag=parseInt(columns[0],10);checkpointVerified=!Number.isNaN(busyFlag)&&busyFlag===0}}catch(err){return{success:!1,reason:`wal_checkpoint error: ${err instanceof Error?err.message:String(err)}`}}try{if(await fs36.copyFile(srcPath,destPath),checkpointVerified)return{success:!0};return{success:!0,reason:"WAL checkpoint incomplete (busy) — archive copy may be stale, original preserved"}}catch(err){return{success:!1,reason:`copy failed: ${err instanceof Error?err.message:String(err)}`}}}async function runArchiveStage(ctx){ctx.timestamp=new Date().toISOString().replace(/[:.]/g,"-"),ctx.archiveSuffix=Math.random().toString(36).slice(2,8),ctx.archiveDir=path84.join(ctx.swarmDir,"archive",`swarm-${ctx.timestamp}-${ctx.archiveSuffix}`);try{await fs36.mkdir(ctx.archiveDir,{recursive:!0});let linkedKnowledgeShared=isLinked(ctx.directory);if(linkedKnowledgeShared)ctx.warnings.push("Worktree is linked: shared knowledge (knowledge.jsonl, knowledge-rejected.jsonl) lives in the link store and is not archived or cleaned by /swarm close. Manage it via the link.");for(let artifact of ARCHIVE_ARTIFACTS){if(linkedKnowledgeShared&&KNOWLEDGE_FAMILY_ARTIFACTS.has(artifact))continue;let srcPath=path84.join(ctx.swarmDir,artifact),destPath=path84.join(ctx.archiveDir,artifact);if(artifact==="swarm.db"){let result=await copySqliteSafe(srcPath,destPath,void 0);if(result.skipped);else if(result.success)if(ctx.archivedFileCount++,result.reason)ctx.warnings.push(`Archived ${artifact}: ${result.reason}. Original preserved to prevent data loss.`);else ctx.archivedActiveStateFiles.add(artifact);else ctx.archiveFailureReasons.set(artifact,result.reason),ctx.warnings.push(`Failed to archive ${artifact}: ${result.reason}. File preserved (not cleaned up).`)}else try{if(await fs36.copyFile(srcPath,destPath),ctx.archivedFileCount++,ACTIVE_STATE_TO_CLEAN.includes(artifact))ctx.archivedActiveStateFiles.add(artifact)}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.archiveFailureReasons.set(artifact,`${errno??"unknown"}: ${reason}`),ctx.warnings.push(`Failed to archive ${artifact} [${errno??"unknown"}]: ${reason}. File preserved (not cleaned up).`)}}}let dynamicArchiveArtifacts=(await fs36.readdir(ctx.swarmDir).catch(()=>[])).filter((name)=>/^post-mortem-[^/\\]+\.md$/.test(name)||/^drift-report-phase-\d+\.json$/.test(name));for(let artifact of dynamicArchiveArtifacts){let srcPath=path84.join(ctx.swarmDir,artifact),destPath=path84.join(ctx.archiveDir,artifact);try{await fs36.copyFile(srcPath,destPath),ctx.archivedFileCount++,ctx.archivedActiveStateFiles.add(artifact)}catch(err){let errno=err?.code;if(errno!=="ENOENT"){let reason=err instanceof Error?err.message:String(err);ctx.archiveFailureReasons.set(artifact,`${errno??"unknown"}: ${reason}`),ctx.warnings.push(`Failed to archive ${artifact} [${errno??"unknown"}]: ${reason}. File preserved (not cleaned up).`)}}}for(let dirName of ACTIVE_STATE_DIRS_TO_CLEAN){let srcDir=path84.join(ctx.swarmDir,dirName),destDir=path84.join(ctx.archiveDir,dirName);try{let result=await copyDirRecursiveWithFailures(srcDir,destDir);if(ctx.archivedFileCount+=result.copied,result.failures.length===0)ctx.archivedActiveStateDirs.add(dirName);else{ctx.warnings.push(`Directory ${dirName} not fully archived (${result.failures.length} failure(s)). Source preserved.`);for(let failure of result.failures)ctx.warnings.push(` - ${failure}`)}}catch(err){let code=err.code;if(code!=="ENOENT")ctx.warnings.push(`Failed to archive directory ${dirName} [${code??"unknown"}]: ${err.message}. Source preserved.`)}}ctx.archiveResult=`Archived ${ctx.archivedFileCount} artifact(s) to .swarm/archive/swarm-${ctx.timestamp}-${ctx.archiveSuffix}/`}catch(archiveError){ctx.warnings.push(`Archive creation failed: ${archiveError instanceof Error?archiveError.message:String(archiveError)}`),ctx.archiveResult="Archive creation failed (see warnings)"}await runArchiveEvidenceRetention({directory:ctx.directory,swarmDir:ctx.swarmDir,config:ctx.config,warnings:ctx.warnings})}async function runArchiveEvidenceRetention(ctx){let maxAgeDays=30,maxBundles=10;try{let{config:evidenceLoadedConfig}=_internals50.loadPluginConfigWithMeta(ctx.directory),evidenceCfg=evidenceLoadedConfig.evidence??{};if(typeof evidenceCfg.max_age_days==="number")maxAgeDays=evidenceCfg.max_age_days;if(typeof evidenceCfg.max_bundles==="number")maxBundles=evidenceCfg.max_bundles}catch{}try{await _internals50.archiveEvidence(ctx.directory,maxAgeDays,maxBundles)}catch(error93){let msg=error93 instanceof Error?error93.message:String(error93);ctx.warnings.push(`Evidence retention archive failed: ${msg}`),console.warn("[close-command] archiveEvidence error:",error93)}}async function runCleanStage(ctx){let configBackupsRemoved=0,cleanedFiles=[],linkedKnowledgeShared=isLinked(ctx.directory);if(linkedKnowledgeShared){for(let artifact of KNOWLEDGE_FAMILY_ARTIFACTS)if(ctx.archivedActiveStateFiles.has(artifact))ctx.warnings.push(`[link-guard] Shared knowledge artifact "${artifact}" appears in `+"the archive set while this worktree is linked — archive stage "+"should have skipped it. Artifact will NOT be deleted.")}if(ctx.archivedActiveStateFiles.size>0)for(let artifact of ACTIVE_STATE_TO_CLEAN){if(linkedKnowledgeShared&&KNOWLEDGE_FAMILY_ARTIFACTS.has(artifact))continue;if(!ctx.archivedActiveStateFiles.has(artifact)){let reason=ctx.archiveFailureReasons?.get(artifact);if(TERMINAL_STATE_FILES.includes(artifact)){ctx.warnings.push(reason?`${artifact} was not archived (${reason}); removing it anyway to prevent CLOSED-plan resurrection next session — no archive copy retained.`:`${artifact} was not archived; removing it anyway to prevent CLOSED-plan resurrection next session — no archive copy retained.`);continue}if(reason)ctx.warnings.push(`Preserved ${artifact} because it was not successfully archived: ${reason}.`);continue}let filePath=path84.join(ctx.swarmDir,artifact);try{await fs36.unlink(filePath),cleanedFiles.push(artifact)}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to clean active-state file ${artifact} [${errno??"unknown"}]: ${reason}`)}}}else ctx.warnings.push("Skipped active-state cleanup because no active-state files were archived. Files preserved to prevent data loss.");for(let artifact of ctx.archivedActiveStateFiles){if(!/^post-mortem-[^/\\]+\.md$/.test(artifact)&&!/^drift-report-phase-\d+\.json$/.test(artifact))continue;try{await fs36.unlink(path84.join(ctx.swarmDir,artifact)),cleanedFiles.push(artifact)}catch(err){let errno=err?.code;if(errno!=="ENOENT"){let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to clean active-state file ${artifact} [${errno??"unknown"}]: ${reason}`)}}}for(let dirName of ACTIVE_STATE_DIRS_TO_CLEAN){if(!ctx.archivedActiveStateDirs.has(dirName))continue;let dirPath=path84.join(ctx.swarmDir,dirName);try{await fs36.rm(dirPath,{recursive:!0,force:!0}),cleanedFiles.push(`${dirName}/`)}catch{}}try{let swarmFiles=await fs36.readdir(ctx.swarmDir),configBackups=swarmFiles.filter((f)=>f.startsWith("config-backup-")&&f.endsWith(".json"));for(let backup of configBackups)try{await fs36.unlink(path84.join(ctx.swarmDir,backup)),configBackupsRemoved++}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to clean config-backup ${backup} [${errno??"unknown"}]: ${reason}`)}}let ledgerSiblings=swarmFiles.filter((f)=>(f.startsWith("plan-ledger.archived-")||f.startsWith("plan-ledger.backup-"))&&f.endsWith(".jsonl"));for(let sibling of ledgerSiblings)try{await fs36.unlink(path84.join(ctx.swarmDir,sibling))}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to clean ledger sibling ${sibling} [${errno??"unknown"}]: ${reason}`)}}}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to read ${ctx.swarmDir} for stale-file cleanup [${errno??"unknown"}]: ${reason}`)}}let swarmPlanFilesRemoved=0,candidates=[path84.join(ctx.directory,".swarm","plan-export","SWARM_PLAN.json"),path84.join(ctx.directory,".swarm","plan-export","SWARM_PLAN.md"),path84.join(ctx.directory,".swarm","SWARM_PLAN.json"),path84.join(ctx.directory,".swarm","SWARM_PLAN.md"),path84.join(ctx.directory,"SWARM_PLAN.json"),path84.join(ctx.directory,"SWARM_PLAN.md")];for(let candidate of candidates)try{await fs36.unlink(candidate),swarmPlanFilesRemoved++}catch(err){if(err?.code!=="ENOENT")ctx.warnings.push(`Failed to remove ${candidate}: ${err instanceof Error?err.message:String(err)}`)}let tmpFilesRemoved=0;try{let tmpFiles=(await fs36.readdir(ctx.swarmDir)).filter((f)=>f.startsWith(".tmp."));for(let tmp of tmpFiles)try{await fs36.unlink(path84.join(ctx.swarmDir,tmp)),tmpFilesRemoved++}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to clean tmp file ${tmp} [${errno??"unknown"}]: ${reason}`)}}}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to read ${ctx.swarmDir} for tmp-file cleanup [${errno??"unknown"}]: ${reason}`)}}if(tmpFilesRemoved>0)cleanedFiles.push(`${tmpFilesRemoved} .tmp.* file(s)`);for(let terminalFile of TERMINAL_STATE_FILES)try{if(await fs36.unlink(path84.join(ctx.swarmDir,terminalFile)),!cleanedFiles.includes(terminalFile))cleanedFiles.push(terminalFile)}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to remove terminal-state file ${terminalFile} [${errno??"unknown"}]: ${reason}`)}}clearAllScopes(ctx.directory);let contextPath=path84.join(ctx.swarmDir,"context.md"),contextContent=["# Context","","## Status",`Session closed after: ${ctx.projectName}`,`Closed: ${new Date().toISOString()}`,`Finalization: ${ctx.isForced?"forced":ctx.planAlreadyDone?"plan-already-done":"normal"}`,"No active plan. Next session starts fresh.",""].join(`
1347
- `),contextTempPath=path84.join(path84.dirname(contextPath),`${path84.basename(contextPath)}.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`);try{await fs36.writeFile(contextTempPath,contextContent,"utf-8"),fsSync8.renameSync(contextTempPath,contextPath)}catch(error93){try{fsSync8.unlinkSync(contextTempPath)}catch{}let msg=error93 instanceof Error?error93.message:String(error93);ctx.warnings.push(`Failed to reset context.md: ${msg}`),console.warn("[close-command] Failed to write context.md:",error93)}return{cleanedFiles,configBackupsRemoved,swarmPlanFilesRemoved,tmpFilesRemoved}}async function runAlignStage(ctx){let pruneBranches=ctx.args.includes("--prune-branches"),gitAlignResult="",prunedBranches=[],gitStatus=_internals50.getGitRepositoryStatus(ctx.directory);if(gitStatus.isRepo){let aggressiveResult=await _internals50.resetToMainAfterMerge(ctx.directory,{pruneBranches});if(aggressiveResult.success){gitAlignResult=aggressiveResult.message;for(let w of aggressiveResult.warnings)ctx.warnings.push(w);if(aggressiveResult.changesDiscarded)ctx.warnings.push("Uncommitted changes were discarded during git alignment")}else{let alignResult=await _internals50.resetToRemoteBranch(ctx.directory,{pruneBranches});if(gitAlignResult=alignResult.message,prunedBranches.push(...alignResult.prunedBranches),!alignResult.success)ctx.warnings.push(`Git alignment: ${alignResult.message}`);if(alignResult.alreadyAligned)gitAlignResult=`Already aligned with ${alignResult.targetBranch}`;for(let w of alignResult.warnings)ctx.warnings.push(w)}}else if(gitStatus.reason==="git_unavailable")gitAlignResult=`Git executable unavailable — skipped git alignment: ${gitStatus.message}`,ctx.warnings.push(gitAlignResult);else if(gitStatus.reason==="git_error")gitAlignResult=`Git repository check failed — skipped git alignment: ${gitStatus.message}`,ctx.warnings.push(gitAlignResult);else gitAlignResult="Not a git repository — skipped git alignment";return{gitAlignResult,prunedBranches}}async function runFinalizeDryRun(directory,swarmDir,planData,planExists){let existsInSwarm=(name)=>fsSync8.existsSync(path84.join(swarmDir,name)),phases=planData.phases??[],nonTerminalPhases=phases.filter((p)=>p.status!=="complete"&&p.status!=="completed"&&p.status!=="blocked"&&p.status!=="closed"),planAlreadyDone=planExists&&phases.length>0&&nonTerminalPhases.length===0,wouldArchive=ARCHIVE_ARTIFACTS.filter(existsInSwarm),dynamicArchive=(await fs36.readdir(swarmDir).catch(()=>[])).filter((name)=>/^post-mortem-[^/\\]+\.md$/.test(name)||/^drift-report-phase-\d+\.json$/.test(name)),wouldArchiveDirs=ACTIVE_STATE_DIRS_TO_CLEAN.filter(existsInSwarm),wouldRemoveTerminal=TERMINAL_STATE_FILES.filter(existsInSwarm),wouldCleanFiles=ACTIVE_STATE_TO_CLEAN.filter((f)=>existsInSwarm(f)&&!TERMINAL_STATE_FILES.includes(f)),gitNote=_internals50.getGitRepositoryStatus(directory).isRepo?"would align the working tree to main/remote (git reset), pruning merged branches only with --prune-branches":"would skip git alignment (not a git repository / git unavailable)";return["## /swarm finalize — DRY RUN (no changes made)","","No lock is taken, no files are archived or deleted, no git command runs.","","### Plan",planExists?planAlreadyDone?"- Plan is already terminal — no phases/tasks would be force-closed.":nonTerminalPhases.length>0?`- Would mark ${nonTerminalPhases.length} non-terminal phase(s) as closed: ${nonTerminalPhases.map((p)=>`#${p.id} ${p.name}`).join(", ")}`:"- No phases present; nothing to close.":"- No plan.json — plan-free session; cleanup-only.","","### Would archive",wouldArchive.length>0||dynamicArchive.length>0||wouldArchiveDirs.length>0?[...wouldArchive.map((f)=>`- ${f}`),...dynamicArchive.map((f)=>`- ${f}`),...wouldArchiveDirs.map((d)=>`- ${d}/`)].join(`
1345
+ `).map((line)=>line.trim()).filter((line)=>line.length>0&&!line.startsWith("#"))}catch{}try{let evidenceDir=path84.join(ctx.swarmDir,"evidence"),retroDirs=(await fs36.readdir(evidenceDir)).filter((e)=>e.startsWith("retro-")).sort((a,b)=>a.localeCompare(b,void 0,{numeric:!0}));for(let retroDir of retroDirs){let evidencePath=path84.join(evidenceDir,retroDir,"evidence.json");try{let content=await fs36.readFile(evidencePath,"utf-8"),parsed=JSON.parse(content),entries=parsed.entries??[parsed];for(let entry of entries)if(Array.isArray(entry.lessons_learned)){for(let lesson of entry.lessons_learned)if(typeof lesson==="string"&&lesson.trim().length>0)ctx.retroLessons.push(lesson.trim())}}catch{}}}catch{}let dedupedRetroLessons=ctx.retroLessons;try{let existingEntries=await readKnowledge(resolveSwarmKnowledgePath(ctx.directory)),existingLessonTexts=new Set(existingEntries.map((e)=>normalizeLessonText(e.lesson)).filter((t)=>t.length>0));if(existingLessonTexts.size>0)dedupedRetroLessons=ctx.retroLessons.filter((l)=>!existingLessonTexts.has(normalizeLessonText(l)))}catch{dedupedRetroLessons=ctx.retroLessons}ctx.allLessons=[...new Set([...ctx.explicitLessons,...dedupedRetroLessons])],ctx.curationSucceeded=!1;try{ctx.curationResult=await _internals50.curateAndStoreSwarm(ctx.allLessons,ctx.projectName,{phase_number:0},ctx.directory,ctx.config,{llmDelegate:_internals50.createCuratorLLMDelegate(ctx.directory,"phase",ctx.options.sessionID),enrichmentQuota:{maxCalls:ctx.config.enrichment.max_calls_per_day,window:ctx.config.enrichment.quota_window}}),ctx.curationSucceeded=!0}catch(error93){let msg=error93 instanceof Error?error93.message:String(error93);ctx.warnings.push(`Lessons curation failed: ${msg}`),log("[close-command] curateAndStoreSwarm error:",error93)}if(ctx.curationSucceeded&&ctx.allLessons.length>0)await fs36.unlink(lessonsFilePath).catch(()=>{});if(ctx.curationSucceeded)if(ctx.config.hive_enabled===!1);else try{let entries=await readKnowledge(resolveSwarmKnowledgePath(ctx.directory)),result=await _internals50.checkHivePromotions(entries,ctx.config,ctx.directory);ctx.hivePromoted=result.new_promotions}catch(hiveErr){let msg=hiveErr instanceof Error?hiveErr.message:String(hiveErr);ctx.warnings.push(`Hive promotion failed: ${msg}`)}ctx.fallbackKnowledgeCreated=ctx.curationResult?.stored??0,ctx.sessionKnowledgeCreated=ctx.fallbackKnowledgeCreated;try{let knowledgePath=resolveSwarmKnowledgePath(ctx.directory),entries=await readKnowledge(knowledgePath);ctx.sessionKnowledgeCreated=countSessionKnowledgeEntries(entries,ctx.sessionStart,ctx.fallbackKnowledgeCreated)}catch(knowledgeErr){let msg=knowledgeErr instanceof Error?knowledgeErr.message:String(knowledgeErr);ctx.warnings.push(`Knowledge session count failed: ${msg}`)}if(ctx.knowledgeSkillHint=ctx.sessionKnowledgeCreated>0?`${ctx.sessionKnowledgeCreated} knowledge entries created this session. Consider running skill_improve or skill_generate to compile mature entries into skills.`:"",ctx.runSkillReview)try{let{config:loadedConfig}=_internals50.loadPluginConfigWithMeta(ctx.directory),skillImproverConfig=SkillImproverConfigSchema.parse(loadedConfig.skill_improver??{}),skillReviewResult=await runAbortableSkillReview({directory:ctx.directory,config:skillImproverConfig,targets:["skills","knowledge"],mode:"proposal",sessionId:ctx.options.sessionID,enrichmentQuota:{maxCalls:ctx.config.enrichment.max_calls_per_day,window:ctx.config.enrichment.quota_window}},ctx.options.skillReviewTimeoutMs??CLOSE_SKILL_REVIEW_TIMEOUT_MS);if(skillReviewResult.ran){let proposal=skillReviewResult.proposalPath?` Proposal: ${skillReviewResult.proposalPath}.`:"",source=skillReviewResult.source?` Source: ${skillReviewResult.source}.`:"";ctx.skillReviewSummary=`Skill review proposal generated.${proposal}${source}`}else{let reason=skillReviewResult.reason??"unknown reason";ctx.skillReviewSummary=`Skill review skipped: ${reason}`,ctx.warnings.push(ctx.skillReviewSummary)}}catch(skillReviewErr){let msg=skillReviewErr instanceof Error?skillReviewErr.message:String(skillReviewErr);ctx.skillReviewSummary=`Skill review failed: ${msg}`,ctx.warnings.push(ctx.skillReviewSummary)}try{ctx.sessionReflection=await runAbortableReflection({directory:ctx.directory,toolAggregates:swarmState.toolAggregates,agentSessions:swarmState.agentSessions,sessionId:ctx.options.sessionID},CLOSE_REFLECTION_TIMEOUT_MS),await writeSessionReflection(ctx.directory,ctx.sessionReflection)}catch(reflectionErr){let msg=reflectionErr instanceof Error?reflectionErr.message:String(reflectionErr);ctx.warnings.push(`Session reflection failed: ${msg}`)}if(ctx.planExists){ctx.originalStatuses=new Map;for(let phase of ctx.planData.phases??[])for(let task of phase.tasks??[])ctx.originalStatuses.set(task.id,task.status);let planDataSnapshot=structuredClone(ctx.planData),closedPhasesLenBefore=ctx.closedPhases.length,closedTasksLenBefore=ctx.closedTasks.length;ctx.guaranteeResult=guaranteeAllPlansComplete(ctx.planData);for(let phaseId of ctx.guaranteeResult.closedPhaseIds)if(!ctx.closedPhases.includes(phaseId))ctx.closedPhases.push(phaseId);for(let taskId of ctx.guaranteeResult.closedTaskIds)if(!ctx.closedTasks.includes(taskId))ctx.closedTasks.push(taskId);if(!ctx.planAlreadyDone||ctx.guaranteeResult.closedPhaseIds.length>0||ctx.guaranteeResult.closedTaskIds.length>0)try{await _internals50.closePlanTerminalState(ctx.directory,ctx.planData,{closedPhaseIds:ctx.guaranteeResult.closedPhaseIds,closedTaskIds:ctx.guaranteeResult.closedTaskIds,originalStatuses:ctx.originalStatuses})}catch(error93){let msg=error93 instanceof Error?error93.message:String(error93);ctx.warnings.push(`Failed to persist terminal plan state: ${msg}`),log("[close-command] Failed to write terminal plan state:",error93),ctx.planData=planDataSnapshot,ctx.closedPhases.length=closedPhasesLenBefore,ctx.closedTasks.length=closedTasksLenBefore}}try{let{CuratorConfigSchema:CCS}=await Promise.resolve().then(() => (init_schema(),exports_schema)),{config:pmLoadedConfig}=_internals50.loadPluginConfigWithMeta(ctx.directory),curatorCfg=CCS.parse(pmLoadedConfig.curator??{});if(curatorCfg.enabled&&curatorCfg.postmortem_enabled){let pmResult=await _internals50.runCuratorPostMortem(ctx.directory,{llmDelegate:_internals50.createCuratorLLMDelegate(ctx.directory,"postmortem",ctx.options.sessionID),scope:"project",sessionID:ctx.options.sessionID});if(pmResult.success&&pmResult.summary)ctx.postMortemSummary=pmResult.summary;for(let w of pmResult.warnings)ctx.warnings.push(`[POST-MORTEM] ${w}`)}}catch(err){let msg=err instanceof Error?err.message:String(err);ctx.warnings.push(`Post-mortem failed: ${msg}`)}}async function copySqliteSafe(srcPath,destPath,laneEnv){if(!fsSync8.existsSync(srcPath))return{success:!0,skipped:!0,reason:"source does not exist (ENOENT)"};let checkpointVerified=!1;try{let result=_internals50.spawnSync("sqlite3",[srcPath,"PRAGMA wal_checkpoint(TRUNCATE);"],{cwd:path84.dirname(srcPath),encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:1e4,windowsHide:!0,maxBuffer:1024,envOverrides:laneEnv});if(result.error){if(result.error.code==="ENOENT")try{return await fs36.copyFile(srcPath,destPath),{success:!0,reason:"copied without WAL checkpoint (sqlite3 CLI unavailable)"}}catch(copyErr){return{success:!1,reason:`fallback copy failed: ${copyErr instanceof Error?copyErr.message:String(copyErr)}`}}return{success:!1,reason:`wal_checkpoint failed: ${result.error instanceof Error?result.error.message:String(result.error)}`}}if(result.status!==0)return{success:!1,reason:`wal_checkpoint exited with code ${result.status}`};let lines=(result.stdout||"").trim().split(`
1346
+ `).filter((l)=>l.trim());if(lines.length>=1){let columns=lines[0].split("|"),busyFlag=parseInt(columns[0],10);checkpointVerified=!Number.isNaN(busyFlag)&&busyFlag===0}}catch(err){return{success:!1,reason:`wal_checkpoint error: ${err instanceof Error?err.message:String(err)}`}}try{if(await fs36.copyFile(srcPath,destPath),checkpointVerified)return{success:!0};return{success:!0,reason:"WAL checkpoint incomplete (busy) — archive copy may be stale, original preserved"}}catch(err){return{success:!1,reason:`copy failed: ${err instanceof Error?err.message:String(err)}`}}}async function runArchiveStage(ctx){ctx.timestamp=new Date().toISOString().replace(/[:.]/g,"-"),ctx.archiveSuffix=Math.random().toString(36).slice(2,8),ctx.archiveDir=path84.join(ctx.swarmDir,"archive",`swarm-${ctx.timestamp}-${ctx.archiveSuffix}`);try{await fs36.mkdir(ctx.archiveDir,{recursive:!0});let linkedKnowledgeShared=isLinked(ctx.directory);if(linkedKnowledgeShared)ctx.warnings.push("Worktree is linked: shared knowledge (knowledge.jsonl, knowledge-rejected.jsonl) lives in the link store and is not archived or cleaned by /swarm close. Manage it via the link.");for(let artifact of ARCHIVE_ARTIFACTS){if(linkedKnowledgeShared&&KNOWLEDGE_FAMILY_ARTIFACTS.has(artifact))continue;let srcPath=path84.join(ctx.swarmDir,artifact),destPath=path84.join(ctx.archiveDir,artifact);if(artifact==="swarm.db"){let result=await copySqliteSafe(srcPath,destPath,void 0);if(result.skipped);else if(result.success)if(ctx.archivedFileCount++,result.reason)ctx.warnings.push(`Archived ${artifact}: ${result.reason}. Original preserved to prevent data loss.`);else ctx.archivedActiveStateFiles.add(artifact);else ctx.archiveFailureReasons.set(artifact,result.reason),ctx.warnings.push(`Failed to archive ${artifact}: ${result.reason}. File preserved (not cleaned up).`)}else try{if(await fs36.copyFile(srcPath,destPath),ctx.archivedFileCount++,ACTIVE_STATE_TO_CLEAN.includes(artifact))ctx.archivedActiveStateFiles.add(artifact)}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.archiveFailureReasons.set(artifact,`${errno??"unknown"}: ${reason}`),ctx.warnings.push(`Failed to archive ${artifact} [${errno??"unknown"}]: ${reason}. File preserved (not cleaned up).`)}}}let dynamicArchiveArtifacts=(await fs36.readdir(ctx.swarmDir).catch(()=>[])).filter((name)=>/^post-mortem-[^/\\]+\.md$/.test(name)||/^drift-report-phase-\d+\.json$/.test(name));for(let artifact of dynamicArchiveArtifacts){let srcPath=path84.join(ctx.swarmDir,artifact),destPath=path84.join(ctx.archiveDir,artifact);try{await fs36.copyFile(srcPath,destPath),ctx.archivedFileCount++,ctx.archivedActiveStateFiles.add(artifact)}catch(err){let errno=err?.code;if(errno!=="ENOENT"){let reason=err instanceof Error?err.message:String(err);ctx.archiveFailureReasons.set(artifact,`${errno??"unknown"}: ${reason}`),ctx.warnings.push(`Failed to archive ${artifact} [${errno??"unknown"}]: ${reason}. File preserved (not cleaned up).`)}}}for(let dirName of ACTIVE_STATE_DIRS_TO_CLEAN){let srcDir=path84.join(ctx.swarmDir,dirName),destDir=path84.join(ctx.archiveDir,dirName);try{let result=await copyDirRecursiveWithFailures(srcDir,destDir);if(ctx.archivedFileCount+=result.copied,result.failures.length===0)ctx.archivedActiveStateDirs.add(dirName);else{ctx.warnings.push(`Directory ${dirName} not fully archived (${result.failures.length} failure(s)). Source preserved.`);for(let failure of result.failures)ctx.warnings.push(` - ${failure}`)}}catch(err){let code=err.code;if(code!=="ENOENT")ctx.warnings.push(`Failed to archive directory ${dirName} [${code??"unknown"}]: ${err.message}. Source preserved.`)}}ctx.archiveResult=`Archived ${ctx.archivedFileCount} artifact(s) to .swarm/archive/swarm-${ctx.timestamp}-${ctx.archiveSuffix}/`}catch(archiveError){ctx.warnings.push(`Archive creation failed: ${archiveError instanceof Error?archiveError.message:String(archiveError)}`),ctx.archiveResult="Archive creation failed (see warnings)"}await runArchiveEvidenceRetention({directory:ctx.directory,swarmDir:ctx.swarmDir,config:ctx.config,warnings:ctx.warnings})}async function runArchiveEvidenceRetention(ctx){let maxAgeDays=30,maxBundles=10;try{let{config:evidenceLoadedConfig}=_internals50.loadPluginConfigWithMeta(ctx.directory),evidenceCfg=evidenceLoadedConfig.evidence??{};if(typeof evidenceCfg.max_age_days==="number")maxAgeDays=evidenceCfg.max_age_days;if(typeof evidenceCfg.max_bundles==="number")maxBundles=evidenceCfg.max_bundles}catch{}try{await _internals50.archiveEvidence(ctx.directory,maxAgeDays,maxBundles)}catch(error93){let msg=error93 instanceof Error?error93.message:String(error93);ctx.warnings.push(`Evidence retention archive failed: ${msg}`),log("[close-command] archiveEvidence error:",error93)}}async function runCleanStage(ctx){let configBackupsRemoved=0,cleanedFiles=[],linkedKnowledgeShared=isLinked(ctx.directory);if(linkedKnowledgeShared){for(let artifact of KNOWLEDGE_FAMILY_ARTIFACTS)if(ctx.archivedActiveStateFiles.has(artifact))ctx.warnings.push(`[link-guard] Shared knowledge artifact "${artifact}" appears in `+"the archive set while this worktree is linked — archive stage "+"should have skipped it. Artifact will NOT be deleted.")}if(ctx.archivedActiveStateFiles.size>0)for(let artifact of ACTIVE_STATE_TO_CLEAN){if(linkedKnowledgeShared&&KNOWLEDGE_FAMILY_ARTIFACTS.has(artifact))continue;if(!ctx.archivedActiveStateFiles.has(artifact)){let reason=ctx.archiveFailureReasons?.get(artifact);if(TERMINAL_STATE_FILES.includes(artifact)){ctx.warnings.push(reason?`${artifact} was not archived (${reason}); removing it anyway to prevent CLOSED-plan resurrection next session — no archive copy retained.`:`${artifact} was not archived; removing it anyway to prevent CLOSED-plan resurrection next session — no archive copy retained.`);continue}if(reason)ctx.warnings.push(`Preserved ${artifact} because it was not successfully archived: ${reason}.`);continue}let filePath=path84.join(ctx.swarmDir,artifact);try{await fs36.unlink(filePath),cleanedFiles.push(artifact)}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to clean active-state file ${artifact} [${errno??"unknown"}]: ${reason}`)}}}else ctx.warnings.push("Skipped active-state cleanup because no active-state files were archived. Files preserved to prevent data loss.");for(let artifact of ctx.archivedActiveStateFiles){if(!/^post-mortem-[^/\\]+\.md$/.test(artifact)&&!/^drift-report-phase-\d+\.json$/.test(artifact))continue;try{await fs36.unlink(path84.join(ctx.swarmDir,artifact)),cleanedFiles.push(artifact)}catch(err){let errno=err?.code;if(errno!=="ENOENT"){let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to clean active-state file ${artifact} [${errno??"unknown"}]: ${reason}`)}}}for(let dirName of ACTIVE_STATE_DIRS_TO_CLEAN){if(!ctx.archivedActiveStateDirs.has(dirName))continue;let dirPath=path84.join(ctx.swarmDir,dirName);try{await fs36.rm(dirPath,{recursive:!0,force:!0}),cleanedFiles.push(`${dirName}/`)}catch{}}try{let swarmFiles=await fs36.readdir(ctx.swarmDir),configBackups=swarmFiles.filter((f)=>f.startsWith("config-backup-")&&f.endsWith(".json"));for(let backup of configBackups)try{await fs36.unlink(path84.join(ctx.swarmDir,backup)),configBackupsRemoved++}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to clean config-backup ${backup} [${errno??"unknown"}]: ${reason}`)}}let ledgerSiblings=swarmFiles.filter((f)=>(f.startsWith("plan-ledger.archived-")||f.startsWith("plan-ledger.backup-"))&&f.endsWith(".jsonl"));for(let sibling of ledgerSiblings)try{await fs36.unlink(path84.join(ctx.swarmDir,sibling))}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to clean ledger sibling ${sibling} [${errno??"unknown"}]: ${reason}`)}}}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to read ${ctx.swarmDir} for stale-file cleanup [${errno??"unknown"}]: ${reason}`)}}let swarmPlanFilesRemoved=0,candidates=[path84.join(ctx.directory,".swarm","plan-export","SWARM_PLAN.json"),path84.join(ctx.directory,".swarm","plan-export","SWARM_PLAN.md"),path84.join(ctx.directory,".swarm","SWARM_PLAN.json"),path84.join(ctx.directory,".swarm","SWARM_PLAN.md"),path84.join(ctx.directory,"SWARM_PLAN.json"),path84.join(ctx.directory,"SWARM_PLAN.md")];for(let candidate of candidates)try{await fs36.unlink(candidate),swarmPlanFilesRemoved++}catch(err){if(err?.code!=="ENOENT")ctx.warnings.push(`Failed to remove ${candidate}: ${err instanceof Error?err.message:String(err)}`)}let tmpFilesRemoved=0;try{let tmpFiles=(await fs36.readdir(ctx.swarmDir)).filter((f)=>f.startsWith(".tmp."));for(let tmp of tmpFiles)try{await fs36.unlink(path84.join(ctx.swarmDir,tmp)),tmpFilesRemoved++}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to clean tmp file ${tmp} [${errno??"unknown"}]: ${reason}`)}}}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to read ${ctx.swarmDir} for tmp-file cleanup [${errno??"unknown"}]: ${reason}`)}}if(tmpFilesRemoved>0)cleanedFiles.push(`${tmpFilesRemoved} .tmp.* file(s)`);for(let terminalFile of TERMINAL_STATE_FILES)try{if(await fs36.unlink(path84.join(ctx.swarmDir,terminalFile)),!cleanedFiles.includes(terminalFile))cleanedFiles.push(terminalFile)}catch(err){let errno=err?.code;if(errno==="ENOENT");else{let reason=err instanceof Error?err.message:String(err);ctx.warnings.push(`Failed to remove terminal-state file ${terminalFile} [${errno??"unknown"}]: ${reason}`)}}clearAllScopes(ctx.directory);let contextPath=path84.join(ctx.swarmDir,"context.md"),contextContent=["# Context","","## Status",`Session closed after: ${ctx.projectName}`,`Closed: ${new Date().toISOString()}`,`Finalization: ${ctx.isForced?"forced":ctx.planAlreadyDone?"plan-already-done":"normal"}`,"No active plan. Next session starts fresh.",""].join(`
1347
+ `),contextTempPath=path84.join(path84.dirname(contextPath),`${path84.basename(contextPath)}.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`);try{await fs36.writeFile(contextTempPath,contextContent,"utf-8"),fsSync8.renameSync(contextTempPath,contextPath)}catch(error93){try{fsSync8.unlinkSync(contextTempPath)}catch{}let msg=error93 instanceof Error?error93.message:String(error93);ctx.warnings.push(`Failed to reset context.md: ${msg}`),log("[close-command] Failed to write context.md:",error93)}return{cleanedFiles,configBackupsRemoved,swarmPlanFilesRemoved,tmpFilesRemoved}}async function runAlignStage(ctx){let pruneBranches=ctx.args.includes("--prune-branches"),gitAlignResult="",prunedBranches=[],gitStatus=_internals50.getGitRepositoryStatus(ctx.directory);if(gitStatus.isRepo){let aggressiveResult=await _internals50.resetToMainAfterMerge(ctx.directory,{pruneBranches});if(aggressiveResult.success){gitAlignResult=aggressiveResult.message;for(let w of aggressiveResult.warnings)ctx.warnings.push(w);if(aggressiveResult.changesDiscarded)ctx.warnings.push("Uncommitted changes were discarded during git alignment")}else{let alignResult=await _internals50.resetToRemoteBranch(ctx.directory,{pruneBranches});if(gitAlignResult=alignResult.message,prunedBranches.push(...alignResult.prunedBranches),!alignResult.success)ctx.warnings.push(`Git alignment: ${alignResult.message}`);if(alignResult.alreadyAligned)gitAlignResult=`Already aligned with ${alignResult.targetBranch}`;for(let w of alignResult.warnings)ctx.warnings.push(w)}}else if(gitStatus.reason==="git_unavailable")gitAlignResult=`Git executable unavailable — skipped git alignment: ${gitStatus.message}`,ctx.warnings.push(gitAlignResult);else if(gitStatus.reason==="git_error")gitAlignResult=`Git repository check failed — skipped git alignment: ${gitStatus.message}`,ctx.warnings.push(gitAlignResult);else gitAlignResult="Not a git repository — skipped git alignment";return{gitAlignResult,prunedBranches}}async function runFinalizeDryRun(directory,swarmDir,planData,planExists){let existsInSwarm=(name)=>fsSync8.existsSync(path84.join(swarmDir,name)),phases=planData.phases??[],nonTerminalPhases=phases.filter((p)=>p.status!=="complete"&&p.status!=="completed"&&p.status!=="blocked"&&p.status!=="closed"),planAlreadyDone=planExists&&phases.length>0&&nonTerminalPhases.length===0,wouldArchive=ARCHIVE_ARTIFACTS.filter(existsInSwarm),dynamicArchive=(await fs36.readdir(swarmDir).catch(()=>[])).filter((name)=>/^post-mortem-[^/\\]+\.md$/.test(name)||/^drift-report-phase-\d+\.json$/.test(name)),wouldArchiveDirs=ACTIVE_STATE_DIRS_TO_CLEAN.filter(existsInSwarm),wouldRemoveTerminal=TERMINAL_STATE_FILES.filter(existsInSwarm),wouldCleanFiles=ACTIVE_STATE_TO_CLEAN.filter((f)=>existsInSwarm(f)&&!TERMINAL_STATE_FILES.includes(f)),gitNote=_internals50.getGitRepositoryStatus(directory).isRepo?"would align the working tree to main/remote (git reset), pruning merged branches only with --prune-branches":"would skip git alignment (not a git repository / git unavailable)";return["## /swarm finalize — DRY RUN (no changes made)","","No lock is taken, no files are archived or deleted, no git command runs.","","### Plan",planExists?planAlreadyDone?"- Plan is already terminal — no phases/tasks would be force-closed.":nonTerminalPhases.length>0?`- Would mark ${nonTerminalPhases.length} non-terminal phase(s) as closed: ${nonTerminalPhases.map((p)=>`#${p.id} ${p.name}`).join(", ")}`:"- No phases present; nothing to close.":"- No plan.json — plan-free session; cleanup-only.","","### Would archive",wouldArchive.length>0||dynamicArchive.length>0||wouldArchiveDirs.length>0?[...wouldArchive.map((f)=>`- ${f}`),...dynamicArchive.map((f)=>`- ${f}`),...wouldArchiveDirs.map((d)=>`- ${d}/`)].join(`
1348
1348
  `):"- (nothing present to archive)","","### Would clean (removed after successful archive)",wouldCleanFiles.length>0||wouldArchiveDirs.length>0?[...wouldCleanFiles.map((f)=>`- ${f}`),...wouldArchiveDirs.map((d)=>`- ${d}/`)].join(`
1349
1349
  `):"- (nothing present to clean)",...wouldRemoveTerminal.length>0?["","### Would remove unconditionally (terminal plan-state)",...wouldRemoveTerminal.map((f)=>`- ${f}`)]:[],"","### Git",`- ${gitNote}`,"","_Note: swarm.db-shm / swarm.db-wal are transient SQLite sidecars — they are never archived or cleaned. The clean list is an approximation of the archive-first guard._","","Run `/swarm finalize` (without `--dry-run`) to apply."].join(`
1350
1350
  `)}async function handleCloseCommand(directory,args2,options={}){let swarmDir=path84.join(directory,".swarm");try{if(fsSync8.lstatSync(swarmDir).isSymbolicLink())return"❌ Refused: .swarm/ is a symlink or junction. Refusing to operate on a redirected directory for safety."}catch(err){if(err?.code!=="ENOENT")throw err}let planPath=validateSwarmPath(directory,"plan.json"),planExists=!1,planData={title:path84.basename(directory)||"Ad-hoc session",phases:[]};try{let content=await fs36.readFile(planPath,"utf-8");planData=JSON.parse(content),planExists=!0}catch(error93){if(error93?.code!=="ENOENT")return`❌ Failed to read plan.json: ${error93 instanceof Error?error93.message:String(error93)}`;if(!await fs36.access(swarmDir).then(()=>!0).catch(()=>!1))return`❌ No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`}if(args2.includes("--dry-run"))return _internals50.runFinalizeDryRun(directory,swarmDir,planData,planExists);let finalizeLock={acquired:!1};if(finalizeLock=await _internals50.acquireFinalizeLock(directory),!finalizeLock.acquired)return"❌ Another /swarm finalize is already running for this project. If you are certain no other run is active, wait for the lock to expire or remove the stale lock and retry.";try{if(!planExists){let archiveDir=path84.join(swarmDir,"archive");try{if((await fs36.readdir(archiveDir)).some((entry)=>entry.startsWith("swarm-"))){if(![...ACTIVE_STATE_TO_CLEAN,...ACTIVE_STATE_DIRS_TO_CLEAN].some((entry)=>fsSync8.existsSync(path84.join(swarmDir,entry))))return`✅ Already finalized — nothing to do.
1351
1351
 
1352
1352
  This project was already finalized in a previous /swarm close run. The plan has been archived and cleaned up. No further action is needed.`}}catch{}}let phases=planData.phases??[],inProgressPhases=phases.filter((p)=>p.status==="in_progress"),isForced=args2.includes("--force"),runSkillReview=args2.includes("--skill-review"),planAlreadyDone=!1;if(planExists)planAlreadyDone=phases.length>0&&phases.every((p)=>p.status==="complete"||p.status==="completed"||p.status==="blocked"||p.status==="closed");let{config:loadedConfig}=_internals50.loadPluginConfigWithMeta(directory),config3=KnowledgeConfigSchema.parse(loadedConfig.knowledge??{}),ctx={directory,swarmDir,planData,planExists,planAlreadyDone,config:config3,projectName:planData.title??"Unknown Project",warnings:[],closedPhases:[],closedTasks:[],sessionStart:void 0,isForced,runSkillReview,options,phases,inProgressPhases,curationSucceeded:!1,curationResult:void 0,allLessons:[],explicitLessons:[],retroLessons:[],knowledgeSkillHint:"",skillReviewSummary:"",postMortemSummary:"",sessionReflection:void 0,hivePromoted:0,sessionKnowledgeCreated:0,fallbackKnowledgeCreated:0,originalStatuses:new Map,guaranteeResult:{closedPhaseIds:[],closedTaskIds:[]},archiveResult:"",archivedFileCount:0,archivedActiveStateFiles:new Set,archivedActiveStateDirs:new Set,archiveFailureReasons:new Map,timestamp:"",archiveDir:"",archiveSuffix:"",args:args2};await runFinalizeStage(ctx),await _internals50.runFinalizeRewardSweep({directory,closedTaskIds:ctx.guaranteeResult.closedTaskIds,memoryConfig:loadedConfig.memory}),await runArchiveStage(ctx);let cleanResult=await runCleanStage(ctx),{gitAlignResult,prunedBranches}=await runAlignStage(ctx),closeSummaryPath=validateSwarmPath(ctx.directory,"close-summary.md"),finalizationType=ctx.isForced?"Forced closure":ctx.planAlreadyDone?"Plan already terminal — cleanup only":"Normal finalization",summaryContent=["# Swarm Close Summary","",`**Project:** ${ctx.projectName}`,`**Closed:** ${new Date().toISOString()}`,`**Finalization:** ${finalizationType}`,"","## Retrospective",!ctx.planExists?"_No plan — ad-hoc session_":ctx.closedPhases.length>0?ctx.closedPhases.map((id)=>`- Phase ${id} closed`).join(`
1353
1353
  `):"_No phases closed this run_",...ctx.closedTasks.length>0?["",`**Tasks marked closed:** ${ctx.closedTasks.length}`,...ctx.closedTasks.map((id)=>`- ${id}`)]:[],"","## Lessons Committed",ctx.allLessons.length>0?"| # | Lesson |":"_No lessons committed_",...ctx.allLessons.length>0?["| --- | --- |",...ctx.allLessons.map((l,i)=>`| ${i+1} | ${l} |`)]:[],...ctx.knowledgeSkillHint?["",ctx.knowledgeSkillHint]:[],...ctx.runSkillReview?["","## Skill Review",ctx.skillReviewSummary||"Skill review completed without details."]:[],...ctx.sessionReflection?["",`## Session Reflection (${ctx.sessionReflection.source})`,"",ctx.sessionReflection.architectReport]:[],"","## Local Repo State",...gitAlignResult?[`- **Git:** ${gitAlignResult}`]:["- Git alignment skipped"],...prunedBranches.length>0?[`- **Pruned branches:** ${prunedBranches.join(", ")}`]:[],`- **Archive:** ${ctx.archiveResult}`,...cleanResult.cleanedFiles.length>0?[`- **Cleaned:** ${cleanResult.cleanedFiles.length} file(s)`]:[],"","## Context","- Reset context.md for next session","- Cleared agent sessions and delegation chains",...cleanResult.configBackupsRemoved>0?[`- Removed ${cleanResult.configBackupsRemoved} stale config backup file(s)`]:[],...cleanResult.swarmPlanFilesRemoved>0?[`- Removed ${cleanResult.swarmPlanFilesRemoved} SWARM_PLAN checkpoint artifact(s) from .swarm/plan-export/ and legacy locations`]:[],...ctx.planExists&&!ctx.planAlreadyDone?["- Set non-completed phases/tasks to closed status"]:[],...ctx.curationSucceeded&&ctx.allLessons.length>0?[`- Committed ${ctx.allLessons.length} lesson(s) to knowledge store`]:[],...ctx.hivePromoted>0?[`- Promoted ${ctx.hivePromoted} lesson(s) to hive knowledge`]:[],"",...ctx.warnings.length>0?["## Warnings",...ctx.warnings.map((w)=>`- ${w}`),""]:[]].join(`
1354
- `),closeSummaryTempPath=path84.join(path84.dirname(closeSummaryPath),`${path84.basename(closeSummaryPath)}.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`);try{await fs36.writeFile(closeSummaryTempPath,summaryContent,"utf-8"),fsSync8.renameSync(closeSummaryTempPath,closeSummaryPath)}catch(error93){try{fsSync8.unlinkSync(closeSummaryTempPath)}catch{}let msg=error93 instanceof Error?error93.message:String(error93);ctx.warnings.push(`Failed to write close-summary.md: ${msg}`),console.warn("[close-command] Failed to write close-summary.md:",error93)}try{let sessionIdsToEnd=[...swarmState.agentSessions.keys()];for(let sessionId of sessionIdsToEnd)_internals50.endAgentSession(sessionId);_internals50.resetSwarmStatePreservingSingletons()}catch(teardownError){let msg=teardownError instanceof Error?teardownError.message:String(teardownError);ctx.warnings.push(`Session teardown encountered an error after finalization completed (state may not be fully reset): ${msg}`),console.warn("[close-command] teardown error:",teardownError)}let retroWarnings=ctx.warnings.filter((w)=>w.includes("Retrospective write")||w.includes("retrospective write")||w.includes("Session retrospective")),otherWarnings=ctx.warnings.filter((w)=>!w.includes("Retrospective write")&&!w.includes("retrospective write")&&!w.includes("Session retrospective")),warningMsg="";if(retroWarnings.length>0)warningMsg+=`
1354
+ `),closeSummaryTempPath=path84.join(path84.dirname(closeSummaryPath),`${path84.basename(closeSummaryPath)}.tmp.${Date.now()}.${Math.floor(Math.random()*1e9)}`);try{await fs36.writeFile(closeSummaryTempPath,summaryContent,"utf-8"),fsSync8.renameSync(closeSummaryTempPath,closeSummaryPath)}catch(error93){try{fsSync8.unlinkSync(closeSummaryTempPath)}catch{}let msg=error93 instanceof Error?error93.message:String(error93);ctx.warnings.push(`Failed to write close-summary.md: ${msg}`),log("[close-command] Failed to write close-summary.md:",error93)}try{let sessionIdsToEnd=[...swarmState.agentSessions.keys()];for(let sessionId of sessionIdsToEnd)_internals50.endAgentSession(sessionId);_internals50.resetSwarmStatePreservingSingletons()}catch(teardownError){let msg=teardownError instanceof Error?teardownError.message:String(teardownError);ctx.warnings.push(`Session teardown encountered an error after finalization completed (state may not be fully reset): ${msg}`),log("[close-command] teardown error:",teardownError)}let retroWarnings=ctx.warnings.filter((w)=>w.includes("Retrospective write")||w.includes("retrospective write")||w.includes("Session retrospective")),otherWarnings=ctx.warnings.filter((w)=>!w.includes("Retrospective write")&&!w.includes("retrospective write")&&!w.includes("Session retrospective")),warningMsg="";if(retroWarnings.length>0)warningMsg+=`
1355
1355
 
1356
1356
  **⚠ Retrospective evidence incomplete:**
1357
1357
  ${retroWarnings.map((w)=>`- ${w}`).join(`
@@ -1379,7 +1379,7 @@ ${ctx.sessionReflection.architectReport}`}if(ctx.planAlreadyDone)return`✅ Sess
1379
1379
  **Git:** ${gitAlignResult}${lessonSummary}${knowledgeHintSummary}${skillReviewOutput}${postMortemOutput}${reflectionOutput}${warningMsg}`;return`✅ Swarm finalized. ${ctx.closedPhases.length} phase(s) closed, ${ctx.closedTasks.length} incomplete task(s) marked closed.
1380
1380
 
1381
1381
  **Archive:** ${ctx.archiveResult}
1382
- **Git:** ${gitAlignResult}${lessonSummary}${knowledgeHintSummary}${skillReviewOutput}${postMortemOutput}${reflectionOutput}${warningMsg}`}finally{if(finalizeLock.release)try{await finalizeLock.release()}catch{}}}async function acquireFinalizeLock(directory){let result=await tryAcquireLock(directory,"finalize.lock","close-command","finalize");if(result.acquired)return{acquired:!0,release:result.lock._release};return{acquired:!1}}var CLOSE_SKILL_REVIEW_TIMEOUT_MS=120000,CLOSE_REFLECTION_TIMEOUT_MS=90000,ARCHIVE_ARTIFACTS,ACTIVE_STATE_TO_CLEAN,TERMINAL_STATE_FILES,KNOWLEDGE_FAMILY_ARTIFACTS,ACTIVE_STATE_DIRS_TO_CLEAN,_internals50;var init_close=__esm(()=>{init_config();init_schema();init_manager2();init_branch();init_curator_llm_factory();init_curator_postmortem();init_hive_promoter();init_knowledge_curator();init_knowledge_link();init_knowledge_store();init_utils2();init_finalize_reward_sweep();init_file_locks();init_manager();init_scope_persistence();init_session_reflection();init_skill_improver();init_session_start_store();init_state2();init_write_retro();init_bun_compat();ARCHIVE_ARTIFACTS=["plan.json","plan.md","plan-ledger.jsonl","context.md","events.jsonl","handoff.md","handoff-prompt.md","handoff-consumed.md","escalation-report.md","close-lessons.md","knowledge.jsonl","knowledge-rejected.jsonl","repo-graph.json","doc-manifest.json","dark-matter.md","telemetry.jsonl","swarm.db","close-summary.md","session-reflection.md","spec.md","spec-staleness.json","spec-snapshot.md"],ACTIVE_STATE_TO_CLEAN=["plan.json","plan.md","plan-ledger.jsonl","events.jsonl","handoff.md","handoff-prompt.md","handoff-consumed.md","escalation-report.md","knowledge-rejected.jsonl","repo-graph.json","doc-manifest.json","dark-matter.md","telemetry.jsonl","session-reflection.md","spec.md","spec-staleness.json","spec-snapshot.md","swarm.db"],TERMINAL_STATE_FILES=["plan.json","plan-ledger.jsonl","spec-staleness.json","spec-snapshot.md"],KNOWLEDGE_FAMILY_ARTIFACTS=new Set(["knowledge.jsonl","knowledge-rejected.jsonl"]),ACTIVE_STATE_DIRS_TO_CLEAN=["evidence","session","scopes","spec-archive"];_internals50={ACTIVE_STATE_DIRS_TO_CLEAN,countSessionKnowledgeEntries,CLOSE_SKILL_REVIEW_TIMEOUT_MS,CLOSE_REFLECTION_TIMEOUT_MS,guaranteeAllPlansComplete,getGitRepositoryStatus,resetToMainAfterMerge,resetToRemoteBranch,copyDirRecursive,loadPluginConfigWithMeta,curateAndStoreSwarm,checkHivePromotions,runCuratorPostMortem,createCuratorLLMDelegate,resetSwarmStatePreservingSingletons,runFinalizeStage,runFinalizeRewardSweep,acquireFinalizeLock,runArchiveStage,runArchiveEvidenceRetention,runCleanStage,runAlignStage,runFinalizeDryRun,archiveEvidence,closePlanTerminalState,endAgentSession,spawnSync:(cmd,args2,options)=>{let mergedEnv=mergeEnvForChild(options?.env,options?.envOverrides);return child_process5.spawnSync(cmd,args2,{...options,env:mergedEnv})}}});function sanitizeText(raw,maxLen){let normalized=raw.replace(/\[+\s*MODE\s*:[^\]]*(?:\]+|$)/gi,"").replace(/\s+/g," ").trim();if(normalized.length<=maxLen)return normalized;return`${normalized.slice(0,maxLen)}...`}function hasFlagValue(args2,index){return index+1<args2.length&&!args2[index+1].startsWith("--")}function jsonForModeHeader(value){return JSON.stringify(value).replace(/[[\]]/g,(ch)=>ch==="["?"\\u005B":"\\u005D")}function parseArgs(args2){let result={mode:"phase0",tracks:"",continueRun:"",output:"markdown",updateMain:!0,allowDirty:!1,rest:[]},i=0;while(i<args2.length){let token=args2[i];if(token==="--help"||token==="-h")result.help=!0;else if(token==="--mode"){if(!hasFlagValue(args2,i))return{...result,error:FLAG_VALUE_MISSING(token)};let value=args2[++i];if(!MODES.has(value))return{...result,error:`Invalid mode "${value}". Must be one of: ${[...MODES].join(", ")}.`};result.mode=value}else if(token==="--tracks"){if(!hasFlagValue(args2,i))return{...result,error:FLAG_VALUE_MISSING(token)};result.tracks=sanitizeText(args2[++i],1000)}else if(token==="--continue"){if(!hasFlagValue(args2,i))return{...result,error:FLAG_VALUE_MISSING(token)};let runId=sanitizeText(args2[++i],128);if(!/^[A-Za-z0-9_.-]+$/.test(runId))return{...result,error:"Invalid --continue value. Use only letters, numbers, dot, underscore, or dash."};result.continueRun=runId}else if(token==="--json")result.output="json";else if(token==="--skip-update")result.updateMain=!1;else if(token==="--allow-dirty")result.allowDirty=!0;else if(token.startsWith("--"))return{...result,error:`Unknown flag "${token}"`};else result.rest.push(token);i++}return result}async function handleCodebaseReviewCommand(_directory,args2){let parsed=parseArgs(args2);if(parsed.help)return`Usage: /swarm codebase-review [scope] [--mode phase0|complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements|custom] [--tracks <list>] [--continue <run-id>] [--json] [--skip-update] [--allow-dirty]
1382
+ **Git:** ${gitAlignResult}${lessonSummary}${knowledgeHintSummary}${skillReviewOutput}${postMortemOutput}${reflectionOutput}${warningMsg}`}finally{if(finalizeLock.release)try{await finalizeLock.release()}catch{}}}async function acquireFinalizeLock(directory){let result=await tryAcquireLock(directory,"finalize.lock","close-command","finalize");if(result.acquired)return{acquired:!0,release:result.lock._release};return{acquired:!1}}var CLOSE_SKILL_REVIEW_TIMEOUT_MS=120000,CLOSE_REFLECTION_TIMEOUT_MS=90000,ARCHIVE_ARTIFACTS,ACTIVE_STATE_TO_CLEAN,TERMINAL_STATE_FILES,KNOWLEDGE_FAMILY_ARTIFACTS,ACTIVE_STATE_DIRS_TO_CLEAN,_internals50;var init_close=__esm(()=>{init_config();init_schema();init_manager2();init_branch();init_curator_llm_factory();init_curator_postmortem();init_hive_promoter();init_knowledge_curator();init_knowledge_link();init_knowledge_store();init_utils2();init_finalize_reward_sweep();init_file_locks();init_manager();init_scope_persistence();init_session_reflection();init_skill_improver();init_session_start_store();init_state2();init_write_retro();init_bun_compat();init_logger();ARCHIVE_ARTIFACTS=["plan.json","plan.md","plan-ledger.jsonl","context.md","events.jsonl","handoff.md","handoff-prompt.md","handoff-consumed.md","escalation-report.md","close-lessons.md","knowledge.jsonl","knowledge-rejected.jsonl","repo-graph.json","doc-manifest.json","dark-matter.md","telemetry.jsonl","swarm.db","close-summary.md","session-reflection.md","spec.md","spec-staleness.json","spec-snapshot.md"],ACTIVE_STATE_TO_CLEAN=["plan.json","plan.md","plan-ledger.jsonl","events.jsonl","handoff.md","handoff-prompt.md","handoff-consumed.md","escalation-report.md","knowledge-rejected.jsonl","repo-graph.json","doc-manifest.json","dark-matter.md","telemetry.jsonl","session-reflection.md","spec.md","spec-staleness.json","spec-snapshot.md","swarm.db"],TERMINAL_STATE_FILES=["plan.json","plan-ledger.jsonl","spec-staleness.json","spec-snapshot.md"],KNOWLEDGE_FAMILY_ARTIFACTS=new Set(["knowledge.jsonl","knowledge-rejected.jsonl"]),ACTIVE_STATE_DIRS_TO_CLEAN=["evidence","session","scopes","spec-archive"];_internals50={ACTIVE_STATE_DIRS_TO_CLEAN,countSessionKnowledgeEntries,CLOSE_SKILL_REVIEW_TIMEOUT_MS,CLOSE_REFLECTION_TIMEOUT_MS,guaranteeAllPlansComplete,getGitRepositoryStatus,resetToMainAfterMerge,resetToRemoteBranch,copyDirRecursive,loadPluginConfigWithMeta,curateAndStoreSwarm,checkHivePromotions,runCuratorPostMortem,createCuratorLLMDelegate,resetSwarmStatePreservingSingletons,runFinalizeStage,runFinalizeRewardSweep,acquireFinalizeLock,runArchiveStage,runArchiveEvidenceRetention,runCleanStage,runAlignStage,runFinalizeDryRun,archiveEvidence,closePlanTerminalState,endAgentSession,spawnSync:(cmd,args2,options)=>{let mergedEnv=mergeEnvForChild(options?.env,options?.envOverrides);return child_process5.spawnSync(cmd,args2,{...options,env:mergedEnv})}}});function sanitizeText(raw,maxLen){let normalized=raw.replace(/\[+\s*MODE\s*:[^\]]*(?:\]+|$)/gi,"").replace(/\s+/g," ").trim();if(normalized.length<=maxLen)return normalized;return`${normalized.slice(0,maxLen)}...`}function hasFlagValue(args2,index){return index+1<args2.length&&!args2[index+1].startsWith("--")}function jsonForModeHeader(value){return JSON.stringify(value).replace(/[[\]]/g,(ch)=>ch==="["?"\\u005B":"\\u005D")}function parseArgs(args2){let result={mode:"phase0",tracks:"",continueRun:"",output:"markdown",updateMain:!0,allowDirty:!1,rest:[]},i=0;while(i<args2.length){let token=args2[i];if(token==="--help"||token==="-h")result.help=!0;else if(token==="--mode"){if(!hasFlagValue(args2,i))return{...result,error:FLAG_VALUE_MISSING(token)};let value=args2[++i];if(!MODES.has(value))return{...result,error:`Invalid mode "${value}". Must be one of: ${[...MODES].join(", ")}.`};result.mode=value}else if(token==="--tracks"){if(!hasFlagValue(args2,i))return{...result,error:FLAG_VALUE_MISSING(token)};result.tracks=sanitizeText(args2[++i],1000)}else if(token==="--continue"){if(!hasFlagValue(args2,i))return{...result,error:FLAG_VALUE_MISSING(token)};let runId=sanitizeText(args2[++i],128);if(!/^[A-Za-z0-9_.-]+$/.test(runId))return{...result,error:"Invalid --continue value. Use only letters, numbers, dot, underscore, or dash."};result.continueRun=runId}else if(token==="--json")result.output="json";else if(token==="--skip-update")result.updateMain=!1;else if(token==="--allow-dirty")result.allowDirty=!0;else if(token.startsWith("--"))return{...result,error:`Unknown flag "${token}"`};else result.rest.push(token);i++}return result}async function handleCodebaseReviewCommand(_directory,args2){let parsed=parseArgs(args2);if(parsed.help)return`Usage: /swarm codebase-review [scope] [--mode phase0|complete|defect|security|correctness|testing|ui|performance|ai-slop|enhancements|custom] [--tracks <list>] [--continue <run-id>] [--json] [--skip-update] [--allow-dirty]
1383
1383
 
1384
1384
  Run the codebase-review-swarm workflow in the current repository.
1385
1385
 
@@ -1458,7 +1458,7 @@ Error analyzing git history: ${err instanceof Error?err.message:String(err)}
1458
1458
 
1459
1459
  Ensure this is a git repository with commit history.`}let output=formatDarkMatterOutput(pairs);if(pairs.length>0)try{let projectName=path89.basename(path89.resolve(directory)),entries=darkMatterToKnowledgeEntries(pairs,projectName);if(entries.length>0){let knowledgePath=resolveSwarmKnowledgePath(directory);for(let entry of entries)await appendKnowledge(knowledgePath,entry);return`${output}
1460
1460
 
1461
- [${entries.length} dark matter finding(s) saved to .swarm/knowledge.jsonl]`}}catch(err){return console.warn("dark-matter: failed to save knowledge entries:",err),output}return output}var init_dark_matter=__esm(()=>{init_knowledge_store();init_co_change_analyzer()});function sanitizeScope(raw){let normalized=raw.replace(/\s+/g," ").trim().replace(/\[\s*MODE\s*:[^\]]*\]/gi,"").replace(/\s+/g," ").trim();if(normalized.length<=2000)return normalized;return`${normalized.slice(0,2000)}…`}function isValidPositiveInteger(raw){if(!raw||!/^\d+$/.test(raw))return!1;let n=Number(raw);if(!Number.isFinite(n)||!Number.isInteger(n)||n<0)return!1;return!0}function parseArgs4(args2){let result={profile:"standard",maxExplorers:6,output:"markdown",updateMain:!0,allowDirty:!1,rest:[]},i=0;while(i<args2.length){let token=args2[i];if(token==="--profile"){if(i+1>=args2.length)return{...result,error:`Flag "${token}" requires a value`};let value=args2[++i];if(!PROFILES.has(value))return{...result,error:`Invalid profile "${value}". Must be one of: standard, security, ux, architecture, full.`};result.profile=value}else if(token==="--max-explorers"){if(i+1>=args2.length)return{...result,error:`Flag "${token}" requires a value`};let value=args2[++i];if(!isValidPositiveInteger(value)||value.includes(".")||value.startsWith("0x")||value.startsWith("0X")||Number(value)<1||Number(value)>8)return{...result,error:`Invalid --max-explorers value "${value}". Must be an integer between 1 and 8.`};result.maxExplorers=Number(value),result.maxExplorersExplicit=!0}else if(token==="--json")result.output="json";else if(token==="--skip-update")result.updateMain=!1;else if(token==="--allow-dirty")result.allowDirty=!0;else if(token.startsWith("--"))return{...result,error:`Unknown flag "${token}"`};else result.rest.push(token);i++}return result}async function handleDeepDiveCommand(_directory,args2){let parsed=parseArgs4(args2);if(parsed.error)return`Error: ${parsed.error}
1461
+ [${entries.length} dark matter finding(s) saved to .swarm/knowledge.jsonl]`}}catch(err){return log("dark-matter: failed to save knowledge entries:",err),output}return output}var init_dark_matter=__esm(()=>{init_knowledge_store();init_co_change_analyzer();init_logger()});function sanitizeScope(raw){let normalized=raw.replace(/\s+/g," ").trim().replace(/\[\s*MODE\s*:[^\]]*\]/gi,"").replace(/\s+/g," ").trim();if(normalized.length<=2000)return normalized;return`${normalized.slice(0,2000)}…`}function isValidPositiveInteger(raw){if(!raw||!/^\d+$/.test(raw))return!1;let n=Number(raw);if(!Number.isFinite(n)||!Number.isInteger(n)||n<0)return!1;return!0}function parseArgs4(args2){let result={profile:"standard",maxExplorers:6,output:"markdown",updateMain:!0,allowDirty:!1,rest:[]},i=0;while(i<args2.length){let token=args2[i];if(token==="--profile"){if(i+1>=args2.length)return{...result,error:`Flag "${token}" requires a value`};let value=args2[++i];if(!PROFILES.has(value))return{...result,error:`Invalid profile "${value}". Must be one of: standard, security, ux, architecture, full.`};result.profile=value}else if(token==="--max-explorers"){if(i+1>=args2.length)return{...result,error:`Flag "${token}" requires a value`};let value=args2[++i];if(!isValidPositiveInteger(value)||value.includes(".")||value.startsWith("0x")||value.startsWith("0X")||Number(value)<1||Number(value)>8)return{...result,error:`Invalid --max-explorers value "${value}". Must be an integer between 1 and 8.`};result.maxExplorers=Number(value),result.maxExplorersExplicit=!0}else if(token==="--json")result.output="json";else if(token==="--skip-update")result.updateMain=!1;else if(token==="--allow-dirty")result.allowDirty=!0;else if(token.startsWith("--"))return{...result,error:`Unknown flag "${token}"`};else result.rest.push(token);i++}return result}async function handleDeepDiveCommand(_directory,args2){let parsed=parseArgs4(args2);if(parsed.error)return`Error: ${parsed.error}
1462
1462
 
1463
1463
  Usage: /swarm deep-dive <scope> [--profile standard|security|ux|architecture|full] [--max-explorers N] [--json] [--skip-update] [--allow-dirty]
1464
1464
 
@@ -1528,7 +1528,7 @@ Requires council.general.enabled: true and a configured search API key (Tavily o
1528
1528
  in the resolved config: global ~/.config/opencode/opencode-swarm.json, then project
1529
1529
  .opencode/opencode-swarm.json overrides.`;if(parsed.depth==="exhaustive"){if(!parsed.maxResearchersExplicit)parsed.maxResearchers=5;if(!parsed.roundsExplicit)parsed.rounds=3}return`[MODE: DEEP_RESEARCH depth=${parsed.depth} max_researchers=${parsed.maxResearchers} rounds=${parsed.rounds} output=${parsed.output}] ${question}`}var DEPTHS;var init_deep_research=__esm(()=>{DEPTHS=new Set(["standard","exhaustive"])});function sanitizeDescription(raw){let normalized=raw.replace(/\s+/g," ").trim().replace(/\[\s*MODE\s*:[^\]]*\]/gi,"").replace(/\[\s*MODE\s*:.*$/gi,"").replace(/\s+/g," ").trim();if(normalized.length<=MAX_DESC_LEN)return normalized;return`${normalized.slice(0,MAX_DESC_LEN)}…`}function cleanFlagValue(raw){if(raw.includes("[")||raw.includes("]")||/\s/.test(raw))return null;if(/\[\s*MODE\s*:/i.test(raw))return null;return raw}function parseArgs6(args2){let result={out:"docs",lang:"auto",update:!1,rest:[]},i=0;while(i<args2.length){let token=args2[i];if(token==="--out"){if(i+1>=args2.length||args2[i+1].startsWith("--"))return{...result,error:`Flag "${token}" requires a value`};let value=args2[++i],clean=cleanFlagValue(value);if(clean===null||value.includes("..")||value.startsWith("/")||value.startsWith("\\")||/^[A-Za-z]:/.test(value))return{...result,error:`Invalid --out value "${value}". Must be a project-relative directory with no brackets or spaces.`};let trimmed=clean.replace(/[/\\]+$/,"");if(!trimmed||trimmed===".")return{...result,error:`Invalid --out value "${value}". Must name a non-empty subdirectory.`};result.out=trimmed}else if(token==="--lang"){if(i+1>=args2.length||args2[i+1].startsWith("--"))return{...result,error:`Flag "${token}" requires a value`};let value=args2[++i],clean=cleanFlagValue(value);if(clean===null)return{...result,error:`Invalid --lang value "${value}". Must be a single token with no brackets or spaces.`};result.lang=clean}else if(token==="--update")result.update=!0;else if(token.startsWith("--"))return{...result,error:`Unknown flag "${token}"`};else result.rest.push(token);i++}return result}async function handleDesignDocsCommand(directory,args2){let parsed=parseArgs6(args2);if(parsed.error)return`Error: ${parsed.error}
1530
1530
 
1531
- ${USAGE3}`;try{let{config:config3}=loadPluginConfigWithMeta(directory);if(config3.design_docs?.enabled!==!0)return"Error: design docs are disabled. Set `design_docs.enabled: true` in opencode-swarm.json to enable the docs_design agent and this command.\n\n"+USAGE3}catch(configErr){console.warn(`[design-docs] Could not read opencode-swarm.json (${String(configErr)}). `+"Falling through — the architect will abort if docs_design is not registered.")}let description=sanitizeDescription(parsed.rest.join(" "));if(!description&&!parsed.update)return USAGE3;return`[MODE: DESIGN_DOCS out=${parsed.out} lang=${parsed.lang} update=${parsed.update}] ${description}`.trimEnd()}var MAX_DESC_LEN=2000,USAGE3=`Usage: /swarm design-docs <description> [--out <dir>] [--lang <name>] [--update]
1531
+ ${USAGE3}`;try{let{config:config3}=loadPluginConfigWithMeta(directory);if(config3.design_docs?.enabled!==!0)return"Error: design docs are disabled. Set `design_docs.enabled: true` in opencode-swarm.json to enable the docs_design agent and this command.\n\n"+USAGE3}catch(configErr){log(`[design-docs] Could not read opencode-swarm.json (${String(configErr)}). `+"Falling through — the architect will abort if docs_design is not registered.")}let description=sanitizeDescription(parsed.rest.join(" "));if(!description&&!parsed.update)return USAGE3;return`[MODE: DESIGN_DOCS out=${parsed.out} lang=${parsed.lang} update=${parsed.update}] ${description}`.trimEnd()}var MAX_DESC_LEN=2000,USAGE3=`Usage: /swarm design-docs <description> [--out <dir>] [--lang <name>] [--update]
1532
1532
 
1533
1533
  Generate or sync language-agnostic design docs for the project under build:
1534
1534
  <out>/domain.md, <out>/technical-spec.md, <out>/behavior-spec.md,
@@ -1544,7 +1544,7 @@ Examples:
1544
1544
  Flags:
1545
1545
  --out <dir> output directory (default "docs")
1546
1546
  --lang <name> target language for the reference/ docs (default: inferred)
1547
- --update sync existing docs to current code/spec instead of generating fresh`;var init_design_docs=__esm(()=>{init_config()});import*as os18 from"node:os";import*as path90 from"node:path";function getPluginConfigDir(){return path90.join(process.env.XDG_CONFIG_HOME||path90.join(os18.homedir(),".config"),"opencode")}function getPluginCachePaths(){let cacheBase=process.env.XDG_CACHE_HOME||path90.join(os18.homedir(),".cache"),configDir=getPluginConfigDir(),paths=[path90.join(cacheBase,"opencode","node_modules","opencode-swarm"),path90.join(cacheBase,"opencode","packages","opencode-swarm@latest"),path90.join(configDir,"node_modules","opencode-swarm")];if(process.platform==="darwin"){let libCaches=path90.join(os18.homedir(),"Library","Caches");paths.push(path90.join(libCaches,"opencode","node_modules","opencode-swarm"),path90.join(libCaches,"opencode","packages","opencode-swarm@latest"))}if(process.platform==="win32"){let localAppData=process.env.LOCALAPPDATA||path90.join(os18.homedir(),"AppData","Local"),appData=process.env.APPDATA||path90.join(os18.homedir(),"AppData","Roaming");paths.push(path90.join(localAppData,"opencode","node_modules","opencode-swarm"),path90.join(localAppData,"opencode","packages","opencode-swarm@latest"),path90.join(appData,"opencode","node_modules","opencode-swarm"))}return paths}var init_cache_paths=()=>{};async function readDurableGateEvidence(directory,taskId){try{return await readTaskEvidence(directory,taskId)}catch{return null}}function getDurableGateEvidenceStatus(evidence){if(!evidence?.gates||typeof evidence.gates!=="object")return{isComplete:!1,missingGates:[],evidenceExists:evidence!=null,invalid:!1};if(!Array.isArray(evidence.required_gates)||evidence.required_gates.length===0)return{isComplete:!1,missingGates:["required_gates"],evidenceExists:!0,invalid:!1};let missingGates=evidence.required_gates.filter((gate)=>evidence.gates[gate]==null);return{isComplete:missingGates.length===0,missingGates,evidenceExists:!0,invalid:!1}}async function getDurableGateEvidenceStatusForTask(directory,taskId){if(!isValidTaskId(taskId))return{isComplete:!1,missingGates:[],evidenceExists:!1,invalid:!1};try{return getDurableGateEvidenceStatus(readTaskEvidenceRaw(directory,taskId))}catch{return{isComplete:!1,missingGates:["invalid_gate_evidence"],evidenceExists:!0,invalid:!0}}}function gateEvidenceToEntry(taskId,gate,type,evidence){let gateRecord=evidence.gates[gate];if(!gateRecord)return null;let base={task_id:taskId,timestamp:gateRecord.timestamp,agent:gateRecord.agent||gate,verdict:"pass",summary:`Gate evidence recorded by ${gate}`,metadata:{source:"durable_gate_evidence",gate}};if(type==="review")return{...base,type,risk:"low",issues:[]};if(type==="approval")return{...base,type};return{...base,type,tests_passed:0,tests_failed:0,failures:[]}}function mergeDurableGateEntriesFromEvidence(taskId,entries,evidence){if(!evidence?.gates)return entries;let merged=[...entries];for(let gate of Object.keys(evidence.gates).sort()){let type=GATE_EVIDENCE_TYPE_BY_GATE[gate]??"approval";if((type==="review"||type==="test")&&merged.some((entry2)=>entry2.type===type))continue;let entry=gateEvidenceToEntry(taskId,gate,type,evidence);if(entry)merged.push(entry)}return merged}var GATE_EVIDENCE_TYPE_BY_GATE;var init_gate_bridge=__esm(()=>{init_gate_evidence();GATE_EVIDENCE_TYPE_BY_GATE={reviewer:"review",test_engineer:"test"}});import{existsSync as existsSync42,mkdirSync as mkdirSync25,readFileSync as readFileSync24,writeFileSync as writeFileSync14}from"node:fs";import{homedir as homedir11}from"node:os";import{join as join70}from"node:path";function isStrictSemver(value){return typeof value==="string"&&STRICT_SEMVER.test(value)}function cacheDir(){let xdg=process.env.XDG_CACHE_HOME,base=xdg&&xdg.length>0?xdg:join70(homedir11(),".cache");return join70(base,"opencode-swarm")}function cacheFile(){return join70(cacheDir(),"version-check.json")}function readVersionCache(){try{let path91=cacheFile();if(!existsSync42(path91))return null;let raw=readFileSync24(path91,"utf-8"),parsed=JSON.parse(raw);if(typeof parsed?.checkedAt!=="number")return null;let npmLatest=typeof parsed.npmLatest==="string"?parsed.npmLatest:null;return{checkedAt:parsed.checkedAt,npmLatest}}catch{return null}}function writeVersionCache(entry){try{let dir=cacheDir();mkdirSync25(dir,{recursive:!0}),writeFileSync14(cacheFile(),JSON.stringify(entry,null,2),"utf-8")}catch{}}function parseVersion(version3){let trimmed=version3.trim(),match=SEMVER_REGEX.exec(trimmed);if(!match)return null;return{major:Number.parseInt(match[1],10),minor:Number.parseInt(match[2],10),patch:Number.parseInt(match[3],10),prerelease:match[4]??null}}function normalizeVersionCandidate(version3){if(typeof version3!=="string")return null;let trimmed=version3.trim();return SEMVER_REGEX.test(trimmed)?trimmed:null}function compareVersions(a,b){let aParsed=parseVersion(a),bParsed=parseVersion(b);if(!aParsed||!bParsed)return 0;if(aParsed.major!==bParsed.major)return aParsed.major>bParsed.major?1:-1;if(aParsed.minor!==bParsed.minor)return aParsed.minor>bParsed.minor?1:-1;if(aParsed.patch!==bParsed.patch)return aParsed.patch>bParsed.patch?1:-1;if(aParsed.prerelease&&!bParsed.prerelease)return-1;if(!aParsed.prerelease&&bParsed.prerelease)return 1;if(aParsed.prerelease&&bParsed.prerelease)return aParsed.prerelease<bParsed.prerelease?-1:aParsed.prerelease>bParsed.prerelease?1:0;return 0}async function fetchLatestVersion(signal){try{let res=await _internals56.fetch(NPM_REGISTRY_URL,{signal,headers:{Accept:"application/json"}});if(!res.ok)return null;if(!(res.headers.get("content-type")??"").toLowerCase().includes("json"))return null;let lengthHeader=res.headers.get("content-length");if(lengthHeader){let advertised=Number.parseInt(lengthHeader,10);if(Number.isFinite(advertised)&&advertised>MAX_RESPONSE_BYTES)return null}let text=await res.text();if(text.length>MAX_RESPONSE_BYTES)return null;let body;try{body=JSON.parse(text)}catch{return null}return isStrictSemver(body.version)?body.version:null}catch{return null}}function scheduleVersionCheck(runningVersion,emitWarning,options){if(_checkLatched)return;_checkLatched=!0;let now=options?.now??(()=>Date.now()),fetchImpl=options?.fetchImpl??fetchLatestVersion;queueMicrotask(()=>{runVersionCheck(runningVersion,emitWarning,now,fetchImpl).catch(()=>{})})}async function runVersionCheck(runningVersion,emitWarning,now,fetchImpl){let cached3=readVersionCache(),t=now();if(cached3&&t-cached3.checkedAt<CHECK_INTERVAL_MS){if(cached3.npmLatest)maybeWarn(runningVersion,cached3.npmLatest,emitWarning);return}let controller=new AbortController,timeout=setTimeout(()=>controller.abort(),FETCH_TIMEOUT_MS),npmLatest=null;try{let fetchedVersion=await fetchImpl(controller.signal);npmLatest=normalizeVersionCandidate(fetchedVersion)}finally{clearTimeout(timeout)}if(writeVersionCache({checkedAt:t,npmLatest}),npmLatest)maybeWarn(runningVersion,npmLatest,emitWarning)}function maybeWarn(runningVersion,npmLatest,emitWarning){if(compareVersions(npmLatest,runningVersion)>0)emitWarning(`[opencode-swarm] Update available: ${runningVersion} → ${npmLatest}. OpenCode caches plugins indefinitely. Run \`bunx opencode-swarm update\` to refresh.`)}var NPM_REGISTRY_URL="https://registry.npmjs.org/opencode-swarm/latest",CHECK_INTERVAL_MS=86400000,FETCH_TIMEOUT_MS=5000,SEMVER_REGEX,MAX_RESPONSE_BYTES=262144,STRICT_SEMVER,_checkLatched=!1,_internals56;var init_version_check=__esm(()=>{SEMVER_REGEX=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/,STRICT_SEMVER=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;_internals56={fetch:(input,init)=>fetch(input,init)}});import{existsSync as existsSync43}from"node:fs";import{readFile as readFile26}from"node:fs/promises";async function readRawLines(filePath){if(!existsSync43(filePath))return{entries:[],corrupt:0};let content=await readFile26(filePath,"utf-8"),entries=[],corrupt=0;for(let line of content.split(`
1547
+ --update sync existing docs to current code/spec instead of generating fresh`;var init_design_docs=__esm(()=>{init_config();init_logger()});import*as os18 from"node:os";import*as path90 from"node:path";function getPluginConfigDir(){return path90.join(process.env.XDG_CONFIG_HOME||path90.join(os18.homedir(),".config"),"opencode")}function getPluginCachePaths(){let cacheBase=process.env.XDG_CACHE_HOME||path90.join(os18.homedir(),".cache"),configDir=getPluginConfigDir(),paths=[path90.join(cacheBase,"opencode","node_modules","opencode-swarm"),path90.join(cacheBase,"opencode","packages","opencode-swarm@latest"),path90.join(configDir,"node_modules","opencode-swarm")];if(process.platform==="darwin"){let libCaches=path90.join(os18.homedir(),"Library","Caches");paths.push(path90.join(libCaches,"opencode","node_modules","opencode-swarm"),path90.join(libCaches,"opencode","packages","opencode-swarm@latest"))}if(process.platform==="win32"){let localAppData=process.env.LOCALAPPDATA||path90.join(os18.homedir(),"AppData","Local"),appData=process.env.APPDATA||path90.join(os18.homedir(),"AppData","Roaming");paths.push(path90.join(localAppData,"opencode","node_modules","opencode-swarm"),path90.join(localAppData,"opencode","packages","opencode-swarm@latest"),path90.join(appData,"opencode","node_modules","opencode-swarm"))}return paths}var init_cache_paths=()=>{};async function readDurableGateEvidence(directory,taskId){try{return await readTaskEvidence(directory,taskId)}catch{return null}}function getDurableGateEvidenceStatus(evidence){if(!evidence?.gates||typeof evidence.gates!=="object")return{isComplete:!1,missingGates:[],evidenceExists:evidence!=null,invalid:!1};if(!Array.isArray(evidence.required_gates)||evidence.required_gates.length===0)return{isComplete:!1,missingGates:["required_gates"],evidenceExists:!0,invalid:!1};let missingGates=evidence.required_gates.filter((gate)=>evidence.gates[gate]==null);return{isComplete:missingGates.length===0,missingGates,evidenceExists:!0,invalid:!1}}async function getDurableGateEvidenceStatusForTask(directory,taskId){if(!isValidTaskId(taskId))return{isComplete:!1,missingGates:[],evidenceExists:!1,invalid:!1};try{return getDurableGateEvidenceStatus(readTaskEvidenceRaw(directory,taskId))}catch{return{isComplete:!1,missingGates:["invalid_gate_evidence"],evidenceExists:!0,invalid:!0}}}function gateEvidenceToEntry(taskId,gate,type,evidence){let gateRecord=evidence.gates[gate];if(!gateRecord)return null;let base={task_id:taskId,timestamp:gateRecord.timestamp,agent:gateRecord.agent||gate,verdict:"pass",summary:`Gate evidence recorded by ${gate}`,metadata:{source:"durable_gate_evidence",gate}};if(type==="review")return{...base,type,risk:"low",issues:[]};if(type==="approval")return{...base,type};return{...base,type,tests_passed:0,tests_failed:0,failures:[]}}function mergeDurableGateEntriesFromEvidence(taskId,entries,evidence){if(!evidence?.gates)return entries;let merged=[...entries];for(let gate of Object.keys(evidence.gates).sort()){let type=GATE_EVIDENCE_TYPE_BY_GATE[gate]??"approval";if((type==="review"||type==="test")&&merged.some((entry2)=>entry2.type===type))continue;let entry=gateEvidenceToEntry(taskId,gate,type,evidence);if(entry)merged.push(entry)}return merged}var GATE_EVIDENCE_TYPE_BY_GATE;var init_gate_bridge=__esm(()=>{init_gate_evidence();GATE_EVIDENCE_TYPE_BY_GATE={reviewer:"review",test_engineer:"test"}});import{existsSync as existsSync42,mkdirSync as mkdirSync25,readFileSync as readFileSync24,writeFileSync as writeFileSync14}from"node:fs";import{homedir as homedir11}from"node:os";import{join as join70}from"node:path";function isStrictSemver(value){return typeof value==="string"&&STRICT_SEMVER.test(value)}function cacheDir(){let xdg=process.env.XDG_CACHE_HOME,base=xdg&&xdg.length>0?xdg:join70(homedir11(),".cache");return join70(base,"opencode-swarm")}function cacheFile(){return join70(cacheDir(),"version-check.json")}function readVersionCache(){try{let path91=cacheFile();if(!existsSync42(path91))return null;let raw=readFileSync24(path91,"utf-8"),parsed=JSON.parse(raw);if(typeof parsed?.checkedAt!=="number")return null;let npmLatest=typeof parsed.npmLatest==="string"?parsed.npmLatest:null;return{checkedAt:parsed.checkedAt,npmLatest}}catch{return null}}function writeVersionCache(entry){try{let dir=cacheDir();mkdirSync25(dir,{recursive:!0}),writeFileSync14(cacheFile(),JSON.stringify(entry,null,2),"utf-8")}catch{}}function parseVersion(version3){let trimmed=version3.trim(),match=SEMVER_REGEX.exec(trimmed);if(!match)return null;return{major:Number.parseInt(match[1],10),minor:Number.parseInt(match[2],10),patch:Number.parseInt(match[3],10),prerelease:match[4]??null}}function normalizeVersionCandidate(version3){if(typeof version3!=="string")return null;let trimmed=version3.trim();return SEMVER_REGEX.test(trimmed)?trimmed:null}function compareVersions(a,b){let aParsed=parseVersion(a),bParsed=parseVersion(b);if(!aParsed||!bParsed)return 0;if(aParsed.major!==bParsed.major)return aParsed.major>bParsed.major?1:-1;if(aParsed.minor!==bParsed.minor)return aParsed.minor>bParsed.minor?1:-1;if(aParsed.patch!==bParsed.patch)return aParsed.patch>bParsed.patch?1:-1;if(aParsed.prerelease&&!bParsed.prerelease)return-1;if(!aParsed.prerelease&&bParsed.prerelease)return 1;if(aParsed.prerelease&&bParsed.prerelease)return aParsed.prerelease<bParsed.prerelease?-1:aParsed.prerelease>bParsed.prerelease?1:0;return 0}async function fetchLatestVersion(signal){try{let res=await _internals56.fetch(NPM_REGISTRY_URL,{signal,headers:{Accept:"application/json"}});if(!res.ok)return null;if(!(res.headers.get("content-type")??"").toLowerCase().includes("json"))return null;let lengthHeader=res.headers.get("content-length");if(lengthHeader){let advertised=Number.parseInt(lengthHeader,10);if(Number.isFinite(advertised)&&advertised>MAX_RESPONSE_BYTES)return null}let text=await res.text();if(text.length>MAX_RESPONSE_BYTES)return null;let body;try{body=JSON.parse(text)}catch{return null}return isStrictSemver(body.version)?body.version:null}catch{return null}}function scheduleVersionCheck(runningVersion,emitWarning,options){if(_checkLatched)return;_checkLatched=!0;let now=options?.now??(()=>Date.now()),fetchImpl=options?.fetchImpl??fetchLatestVersion;queueMicrotask(()=>{runVersionCheck(runningVersion,emitWarning,now,fetchImpl).catch(()=>{})})}async function runVersionCheck(runningVersion,emitWarning,now,fetchImpl){let cached3=readVersionCache(),t=now();if(cached3&&t-cached3.checkedAt<CHECK_INTERVAL_MS){if(cached3.npmLatest)maybeWarn(runningVersion,cached3.npmLatest,emitWarning);return}let controller=new AbortController,timeout=setTimeout(()=>controller.abort(),FETCH_TIMEOUT_MS),npmLatest=null;try{let fetchedVersion=await fetchImpl(controller.signal);npmLatest=normalizeVersionCandidate(fetchedVersion)}finally{clearTimeout(timeout)}if(writeVersionCache({checkedAt:t,npmLatest}),npmLatest)maybeWarn(runningVersion,npmLatest,emitWarning)}function maybeWarn(runningVersion,npmLatest,emitWarning){if(compareVersions(npmLatest,runningVersion)>0)emitWarning(`[opencode-swarm] Update available: ${runningVersion} → ${npmLatest}. OpenCode caches plugins indefinitely. Run \`bunx opencode-swarm update\` to refresh.`)}var NPM_REGISTRY_URL="https://registry.npmjs.org/opencode-swarm/latest",CHECK_INTERVAL_MS=86400000,FETCH_TIMEOUT_MS=5000,SEMVER_REGEX,MAX_RESPONSE_BYTES=262144,STRICT_SEMVER,_checkLatched=!1,_internals56;var init_version_check=__esm(()=>{SEMVER_REGEX=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/,STRICT_SEMVER=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;_internals56={fetch:(input,init)=>fetch(input,init)}});import{existsSync as existsSync43}from"node:fs";import{readFile as readFile26}from"node:fs/promises";async function readRawLines(filePath){if(!existsSync43(filePath))return{entries:[],corrupt:0};let content=await readFile26(filePath,"utf-8"),entries=[],corrupt=0;for(let line of content.split(`
1548
1548
  `)){let trimmed=line.trim();if(!trimmed)continue;try{entries.push(JSON.parse(trimmed))}catch{corrupt++}}return{entries,corrupt}}function hasV2Counters(entry){let ro=entry.retrieval_outcomes;if(!ro||typeof ro!=="object")return!1;return typeof ro.shown_count==="number"&&typeof ro.applied_explicit_count==="number"&&typeof ro.ignored_count==="number"}function cacheStatus(){let cache2=readVersionCache();if(!cache2?.npmLatest)return"unknown";return compareVersions(cache2.npmLatest,version3)>0?"stale":"fresh"}async function computeKnowledgeDebug(directory){let swarmPath2=resolveSwarmKnowledgePath(directory),hivePath=resolveHiveKnowledgePath2(),eventsPath=resolveKnowledgeEventsPath(directory),[swarmRaw,hiveRaw]=await Promise.all([readRawLines(swarmPath2),readRawLines(hivePath)]),rawEntries=[...swarmRaw.entries,...hiveRaw.entries],corrupt=swarmRaw.corrupt+hiveRaw.corrupt,schemaVersions={},missingV2=0;for(let e of rawEntries){let sv=String(typeof e.schema_version==="number"?e.schema_version:"unknown");if(schemaVersions[sv]=(schemaVersions[sv]??0)+1,!hasV2Counters(e))missingV2++}let normalizedCount=0,active=0,archived=0,quarantined=0,enforcedDirectives=0,escalatedDirectives=0;try{let swarm=await readKnowledge(swarmPath2),hive=await readKnowledge(hivePath);for(let e of[...swarm,...hive]){if(normalizedCount++,e.status==="archived")archived++;else if(e.status==="quarantined")quarantined++;else active++;if(e.status!=="archived"&&e.status!=="quarantined"){if(e.enforcement_mode==="enforce")enforcedDirectives++;if(Array.isArray(e.escalation_history)&&e.escalation_history.length>0)escalatedDirectives++}}}catch{}let rejected=0;try{rejected=(await readRejectedLessons(directory)).length}catch{}let eventCount=0,retrieval7d=0,eventsByType={};try{let events=await readKnowledgeEvents(directory);eventCount=events.length;let cutoff=Date.now()-SEVEN_DAYS_MS2;for(let ev of events){if(eventsByType[ev.type]=(eventsByType[ev.type]??0)+1,ev.type!=="retrieved")continue;let t=Date.parse(ev.timestamp);if(!Number.isNaN(t)&&t>=cutoff)retrieval7d++}}catch{}let unactionableQueueDepth=await safeJsonlCount(resolveUnactionablePathSafe(directory)),insightCandidatesPending=await safeJsonlCount(resolveInsightCandidatesPathSafe(directory)),synonymPairs=0;try{synonymPairs=Object.keys((await readSynonymMap(directory)).pairs).length}catch{}let cohortLinked=!1,cohortPointerVersion=null,cohortLinkId=null,cohortId=null,cohortIdentitySource=null,cohortDegraded=!1,cohortSharedRoot=null,cohortGeneration=null,cohortLocalOrphaned=!1;try{let pointer=readLinkPointer(directory);if(pointer)cohortLinked=!0,cohortPointerVersion=pointer.version,cohortLinkId=pointer.linkId,cohortId=pointer.cohortId??null,cohortIdentitySource=pointer.identitySource??null,cohortDegraded=pointer.degraded??!1,cohortSharedRoot=resolveLinkDir(pointer.linkId),cohortGeneration=pointer.generation??null,cohortLocalOrphaned=getLinkedLocalKnowledgeStatus(directory).orphaned}catch{}let hiveEntriesWithLineage=0,hiveOverridePromotions=0,hiveOverrideEntries=[];try{let hive=await readKnowledge(hivePath);for(let e of hive)if(e.lineage){if(hiveEntriesWithLineage++,e.lineage.actor==="manual-override"){if(hiveOverridePromotions++,hiveOverrideEntries.length<20)hiveOverrideEntries.push({id:e.id,lesson_excerpt:e.lesson.slice(0,80),override_failed_gates:e.lineage.override_failed_gates,reason:e.lineage.reason,promotion_event_id:e.lineage.promotion_event_id})}}}catch{}return{plugin_version:version3,directory,swarm_path:swarmPath2,hive_path:hivePath,events_path:eventsPath,raw_entry_count:rawEntries.length,normalized_entry_count:normalizedCount,corrupt_line_count:corrupt,schema_versions:schemaVersions,entries_missing_v2_counters:missingV2,status_breakdown:{active,archived,quarantined,rejected},event_count:eventCount,retrieval_events_7d:retrieval7d,cache_status:cacheStatus(),learning:{unactionable_queue_depth:unactionableQueueDepth,insight_candidates_pending:insightCandidatesPending,synonym_pairs:synonymPairs,enforced_directives:enforcedDirectives,escalated_directives:escalatedDirectives,events_by_type:eventsByType},cohort:{linked:cohortLinked,pointer_version:cohortPointerVersion,link_id:cohortLinkId,cohort_id:cohortId,identity_source:cohortIdentitySource,degraded:cohortDegraded,shared_root:cohortSharedRoot,generation:cohortGeneration,local_orphaned:cohortLocalOrphaned},hive:{entries_with_lineage:hiveEntriesWithLineage,override_promotions:hiveOverridePromotions,override_entries:hiveOverrideEntries}}}async function safeJsonlCount(filePath){if(!filePath||!existsSync43(filePath))return 0;try{let content=await readFile26(filePath,"utf-8"),n=0;for(let line of content.split(`
1549
1549
  `))if(line.trim())n++;return n}catch{return 0}}function resolveUnactionablePathSafe(directory){try{return resolveUnactionablePath(directory)}catch{return null}}function resolveInsightCandidatesPathSafe(directory){try{return resolveInsightCandidatesPath(directory)}catch{return null}}async function checkKnowledgeHealth(directory){let debug;try{debug=await computeKnowledgeDebug(directory)}catch{return{name:"Knowledge health",status:"⚠️",detail:"Could not compute knowledge diagnostics"}}let{status_breakdown:sb,learning:lr,cohort:co,hive:hv}=debug,cohortTag=co.linked?` | cohort[linked id=${co.link_id}${co.cohort_id?` cohort=${co.cohort_id}`:""}${co.identity_source?` via=${co.identity_source}`:""}${co.degraded?" DEGRADED":""}${co.local_orphaned?" local-orphan":""}${co.generation!==null?` gen=${co.generation}`:""}]`:" | cohort[local]",hiveTag=hv.entries_with_lineage>0||hv.override_promotions>0?` | hive[lineage=${hv.entries_with_lineage} overrides=${hv.override_promotions}]`:" | hive[local]",summary=`active=${sb.active} archived=${sb.archived} quarantined=${sb.quarantined} rejected=${sb.rejected} | events=${debug.event_count} (retrieved/7d=${debug.retrieval_events_7d}) | learning[enforce=${lr.enforced_directives} escalated=${lr.escalated_directives} synonyms=${lr.synonym_pairs} unactionable=${lr.unactionable_queue_depth} insights_pending=${lr.insight_candidates_pending}] | schema=${JSON.stringify(debug.schema_versions)}`+cohortTag+hiveTag,warnings=[];if(co.linked&&co.degraded)warnings.push(`cohort identity is degraded (via ${co.identity_source}): shared store is machine-local, not portable across machines`);if(co.linked&&co.local_orphaned)warnings.push("local .swarm/knowledge.jsonl is orphaned by the link store (benign; resolver ignores it)");if(lr.unactionable_queue_depth>UNACTIONABLE_BACKLOG_WARN)warnings.push(`${lr.unactionable_queue_depth} lessons stuck in the unactionable queue (curator may not be draining)`);if(lr.insight_candidates_pending>INSIGHT_BACKLOG_WARN)warnings.push(`${lr.insight_candidates_pending} micro-reflection insight candidates pending (curator may not be folding them in)`);if(debug.corrupt_line_count>0)warnings.push(`${debug.corrupt_line_count} corrupt JSONL line(s) (raw=${debug.raw_entry_count} vs normalized=${debug.normalized_entry_count})`);if(debug.entries_missing_v2_counters>0)warnings.push(`${debug.entries_missing_v2_counters} entr(y/ies) missing v2 counters (normalized on read)`);if(debug.cache_status==="stale")warnings.push("stale plugin cache — run `bunx opencode-swarm update` (knowledge tools may be running old code)");if(hv.override_promotions>0){let sample=hv.override_entries[0],gates=sample?.override_failed_gates?.join(",")??"?";warnings.push(`${hv.override_promotions} hive entr(y/ies) promoted via --force override (failed gates: ${gates}${sample?.reason?`; reason: "${sample.reason.slice(0,60)}"`:""})`)}if(warnings.length>0)return{name:"Knowledge health",status:"⚠️",detail:`${summary} — ${warnings.join("; ")}`};return{name:"Knowledge health",status:"✅",detail:summary}}var version3,SEVEN_DAYS_MS2=604800000,UNACTIONABLE_BACKLOG_WARN=100,INSIGHT_BACKLOG_WARN=50;var init_knowledge_diagnostics=__esm(()=>{init_package();init_knowledge_events();init_knowledge_link();init_knowledge_store();init_knowledge_validator();init_micro_reflector();init_synonym_map();init_version_check();({version:version3}=package_default)});import*as child_process8 from"node:child_process";import{existsSync as existsSync44,readdirSync as readdirSync9,readFileSync as readFileSync25,statSync as statSync16}from"node:fs";import*as path91 from"node:path";import{fileURLToPath as fileURLToPath2}from"node:url";function resolveCachePackageRoot(cachePath){let nestedPackageRoot=path91.join(cachePath,"node_modules","opencode-swarm");return existsSync44(nestedPackageRoot)?nestedPackageRoot:cachePath}function validateTaskDag(plan){let allTaskIds=new Set;for(let phase of plan.phases)for(let task of phase.tasks)allTaskIds.add(task.id);let missingDeps=[];for(let phase of plan.phases)for(let task of phase.tasks)for(let dep of task.depends)if(!allTaskIds.has(dep))missingDeps.push(`${task.id} depends on missing ${dep}`);return{valid:missingDeps.length===0,missingDeps}}async function checkEvidenceCompleteness(directory,plan){let completedTaskIds=[];for(let phase of plan.phases)for(let task of phase.tasks)if(task.status==="completed")completedTaskIds.push(task.id);if(completedTaskIds.length>0){let evidenceTaskIds=new Set(await listEvidenceTaskIds(directory)),missingEvidence=[];for(let id of completedTaskIds){let gateStatus=await getDurableGateEvidenceStatusForTask(directory,id);if(gateStatus.isComplete)continue;if(gateStatus.evidenceExists&&gateStatus.missingGates.length>0){missingEvidence.push(id);continue}if(evidenceTaskIds.has(id))continue;missingEvidence.push(id)}if(missingEvidence.length===0)return{name:"Evidence",status:"✅",detail:`All ${completedTaskIds.length} completed tasks have evidence`};else return{name:"Evidence",status:"❌",detail:`${missingEvidence.length} completed task(s) missing evidence: ${missingEvidence.join(", ")}`}}return{name:"Evidence",status:"✅",detail:"No completed tasks yet"}}async function checkSwarmIdentity(plan){let activeSwarmId=process.env.OPENCODE_SWARM_ID;if(plan&&!activeSwarmId)return{name:"Swarm Identity",status:"❌",detail:"Plan exists but OPENCODE_SWARM_ID not set in environment"};if(!plan&&!activeSwarmId)return{name:"Swarm Identity",status:"✅",detail:"No conflict detected"};if(!plan)return{name:"Swarm Identity",status:"✅",detail:`No plan, but OPENCODE_SWARM_ID is '${activeSwarmId}'`};if(plan&&plan.swarm!==activeSwarmId)return{name:"Swarm Identity",status:"❌",detail:`Swarm identity mismatch: plan says '${plan.swarm}', active is '${activeSwarmId}'`};return{name:"Swarm Identity",status:"✅",detail:`Swarm identity consistent: '${plan.swarm}'`}}async function checkPhaseBoundaries(plan){if(!plan)return{name:"Phase Boundaries",status:"✅",detail:"No plan to validate"};let mismatches=[];for(let phase of plan.phases)for(let task of phase.tasks){let taskPhaseNum=parseInt(task.id.split(".")[0],10);if(Number.isNaN(taskPhaseNum))mismatches.push(`Task ${task.id} has invalid phase number`);else if(taskPhaseNum!==phase.id)mismatches.push(`Task ${task.id} found under Phase ${phase.id}`)}if(mismatches.length===0)return{name:"Phase Boundaries",status:"✅",detail:"All tasks correctly aligned to phases"};return{name:"Phase Boundaries",status:"❌",detail:mismatches.join("; ")}}async function checkOrphanedEvidence(directory,plan){if(!plan)return{name:"Orphaned Evidence",status:"✅",detail:"No plan to cross-reference"};let planTaskIds=new Set;for(let phase of plan.phases)for(let task of phase.tasks)planTaskIds.add(task.id);try{let orphaned=(await listEvidenceTaskIds(directory)).filter((id)=>!planTaskIds.has(id)&&!/^retro-/.test(id));if(orphaned.length===0)return{name:"Orphaned Evidence",status:"✅",detail:"All evidence entries reference valid plan tasks"};return{name:"Orphaned Evidence",status:"❌",detail:`Evidence for [${orphaned.join(", ")}] not in plan`}}catch{return{name:"Orphaned Evidence",status:"❌",detail:"Could not read evidence directory"}}}async function checkPlanSync(directory,plan){if(!plan)return{name:"Plan Sync",status:"✅",detail:"No plan.json present"};try{let jsonTaskCount=0;for(let phase of plan.phases)jsonTaskCount+=phase.tasks.length;let planMdContent=await readSwarmFileAsync(directory,"plan.md");if(!planMdContent)return{name:"Plan Sync",status:"✅",detail:"plan.md not present"};let mdTaskCount=(planMdContent.match(/^- \[[ xX~]/gm)||[]).length;if(jsonTaskCount===mdTaskCount)return{name:"Plan Sync",status:"✅",detail:`plan.json and plan.md both have ${jsonTaskCount} tasks`};return{name:"Plan Sync",status:"❌",detail:`plan.json: ${jsonTaskCount} tasks, plan.md: ${mdTaskCount} — run /swarm sync-plan`}}catch{return{name:"Plan Sync",status:"❌",detail:"Could not compare plan files"}}}async function checkConfigBackups(directory){try{let backupCount=readdirSync9(directory).filter((f)=>/\.opencode-swarm\.yaml\.bak/.test(f)).length;if(backupCount<=5)return{name:"Config Backups",status:"✅",detail:`${backupCount} backup file(s) — within acceptable range`};if(backupCount<=19)return{name:"Config Backups",status:"❌",detail:`${backupCount} backup config files found — consider cleanup`};return{name:"Config Backups",status:"❌",detail:`${backupCount} backup config files found — cleanup required`}}catch{return{name:"Config Backups",status:"✅",detail:"Could not check backup files"}}}async function checkGitRepository(directory){try{if(!existsSync44(directory)||!statSync16(directory).isDirectory())return{name:"Git Repository",status:"❌",detail:"Invalid directory — cannot check git status"};return child_process8.execSync("git rev-parse --git-dir",{cwd:directory,stdio:"pipe"}),{name:"Git Repository",status:"✅",detail:"Git repository detected"}}catch{return{name:"Git Repository",status:"❌",detail:"Not a git repository — version control recommended"}}}async function checkSpecStaleness(directory,plan){let specContent=readEffectiveSpecSync(directory)?.content??null;if(!specContent)return{name:"Spec Staleness",status:"✅",detail:"No effective spec present"};if(!plan)return{name:"Spec Staleness",status:"✅",detail:"No plan to compare spec against"};let titleMatch=specContent.match(/^#\s+(.+)$/m);if(!titleMatch)return{name:"Spec Staleness",status:"✅",detail:"Spec title not detectable"};let specTitle=titleMatch[1].trim(),planTitle=plan.title.trim();if(specTitle.toLowerCase()===planTitle.toLowerCase())return{name:"Spec Staleness",status:"✅",detail:"Spec and plan titles are aligned"};return{name:"Spec Staleness",status:"❌",detail:`Spec/plan title mismatch: spec says '${specTitle}', plan says '${planTitle}'`}}async function checkConfigParseability(directory){let configPath=path91.join(directory,".opencode/opencode-swarm.json");if(!existsSync44(configPath))return{name:"Config Parseability",status:"✅",detail:"No project config file present (using defaults)"};try{let content=readFileSync25(configPath,"utf-8");return JSON.parse(content),{name:"Config Parseability",status:"✅",detail:"Project config is valid JSON"}}catch(err){return{name:"Config Parseability",status:"❌",detail:`Project config at .opencode/opencode-swarm.json is not valid JSON: ${err instanceof Error?err.message:"Unknown error"}`}}}function resolveGrammarDir(thisDir){let normalized=thisDir.replace(/\\/g,"/"),isSource=normalized.endsWith("/src/services"),isCliBundle=normalized.endsWith("/cli");return isSource||isCliBundle?path91.join(thisDir,"..","lang","grammars"):path91.join(thisDir,"lang","grammars")}async function checkGrammarWasmFiles(){let grammarFiles=["tree-sitter-javascript.wasm","tree-sitter-typescript.wasm","tree-sitter-tsx.wasm","tree-sitter-python.wasm","tree-sitter-go.wasm","tree-sitter-rust.wasm","tree-sitter-cpp.wasm","tree-sitter-c-sharp.wasm","tree-sitter-css.wasm","tree-sitter-bash.wasm","tree-sitter-ruby.wasm","tree-sitter-php.wasm","tree-sitter-java.wasm","tree-sitter-kotlin.wasm","tree-sitter-swift.wasm","tree-sitter-dart.wasm","tree-sitter-powershell.wasm","tree-sitter-ini.wasm","tree-sitter-regex.wasm"],thisDir=path91.dirname(fileURLToPath2(import.meta.url)),grammarDir=resolveGrammarDir(thisDir),missing=[];if(!existsSync44(path91.join(grammarDir,"tree-sitter.wasm")))missing.push("tree-sitter.wasm (core runtime)");for(let file3 of grammarFiles)if(!existsSync44(path91.join(grammarDir,file3)))missing.push(file3);if(missing.length===0)return{name:"Grammar WASM Files",status:"✅",detail:`Core runtime + all ${grammarFiles.length} grammar WASM files present`};return{name:"Grammar WASM Files",status:"❌",detail:`${missing.length} WASM file(s) missing: ${missing.join(", ")}`}}async function checkCheckpointManifest(directory){let manifestPath=path91.join(directory,".swarm/checkpoints.json");if(!existsSync44(manifestPath))return{name:"Checkpoint Manifest",status:"✅",detail:"No checkpoint manifest (no checkpoints saved)"};try{let content=readFileSync25(manifestPath,"utf-8"),parsed=JSON.parse(content);if(!parsed.checkpoints||!Array.isArray(parsed.checkpoints))return{name:"Checkpoint Manifest",status:"❌",detail:"checkpoints.json missing 'checkpoints' array"};let invalidCount=0;for(let cp2 of parsed.checkpoints)if(typeof cp2.label!=="string"||typeof cp2.sha!=="string"||typeof cp2.timestamp!=="string")invalidCount++;if(invalidCount>0)return{name:"Checkpoint Manifest",status:"❌",detail:`${invalidCount} checkpoint(s) have invalid structure (missing label/sha/timestamp)`};return{name:"Checkpoint Manifest",status:"✅",detail:`Checkpoint manifest valid — ${parsed.checkpoints.length} checkpoint(s)`}}catch(err){if(err instanceof SyntaxError)return{name:"Checkpoint Manifest",status:"❌",detail:"checkpoints.json is not valid JSON"};return{name:"Checkpoint Manifest",status:"❌",detail:"Could not read checkpoint manifest"}}}async function checkEventStreamIntegrity(directory){let eventsPath=path91.join(directory,".swarm/events.jsonl");if(!existsSync44(eventsPath))return{name:"Event Stream",status:"✅",detail:"No events.jsonl present"};try{let lines=readFileSync25(eventsPath,"utf-8").split(`
1550
1550
  `).filter((line)=>line.trim()!==""),malformedCount=0;for(let line of lines)try{JSON.parse(line)}catch{malformedCount++}if(malformedCount===0)return{name:"Event Stream",status:"✅",detail:`events.jsonl is valid — ${lines.length} event(s)`};return{name:"Event Stream",status:"❌",detail:`events.jsonl has ${malformedCount} malformed line(s) — possible data corruption`}}catch{return{name:"Event Stream",status:"❌",detail:"Could not read events.jsonl"}}}async function checkSteeringDirectives(directory){let eventsPath=path91.join(directory,".swarm/events.jsonl");if(!existsSync44(eventsPath))return{name:"Steering Directives",status:"✅",detail:"No events.jsonl — no steering directives to check"};try{let lines=readFileSync25(eventsPath,"utf-8").split(`
@@ -1666,10 +1666,10 @@ ${USAGE4}`;let flags=[];if(parsed.plan)flags.push("plan=true");if(parsed.trace)f
1666
1666
  `),entriesCount=0;for(let line of lines)if(line.trimStart().startsWith("- "))entriesCount++;return await _internals72.writeSentinel(externalSentinelPath,entriesCount,entriesCount),{migrated:!0,entriesMigrated:entriesCount,entriesDropped:0,entriesTotal:entriesCount}}async function migrateContextToKnowledge(directory,config3){let sentinelPath=path109.join(directory,".swarm",".knowledge-migrated"),contextPath=path109.join(directory,".swarm","context.md"),knowledgePath=resolveSwarmKnowledgePath(directory);if(existsSync56(sentinelPath))return{migrated:!1,entriesMigrated:0,entriesDropped:0,entriesTotal:0,skippedReason:"sentinel-exists"};if(!existsSync56(contextPath))return{migrated:!1,entriesMigrated:0,entriesDropped:0,entriesTotal:0,skippedReason:"no-context-file"};let contextContent=await readFile27(contextPath,"utf-8");if(contextContent.trim().length===0)return{migrated:!1,entriesMigrated:0,entriesDropped:0,entriesTotal:0,skippedReason:"empty-context"};let rawEntries=_internals72.parseContextMd(contextContent);if(rawEntries.length===0)return await _internals72.writeSentinel(sentinelPath,0,0),{migrated:!0,entriesMigrated:0,entriesDropped:0,entriesTotal:0};let existing=await readKnowledge(knowledgePath),migrated=0,dropped=0,projectName=_internals72.inferProjectName(directory);for(let raw of rawEntries){if(config3.validation_enabled!==!1){let category=raw.categoryHint??_internals72.inferCategoryFromText(raw.text);if(!validateLesson(raw.text,existing.map((e)=>e.lesson),{category,scope:"global",confidence:0.3}).valid){dropped++;continue}}if(findNearDuplicate(raw.text,existing,config3.dedup_threshold??0.6)){dropped++;continue}let inferredTags=inferTags2(raw.text),entry={id:randomUUID10(),tier:"swarm",lesson:_internals72.truncateLesson(raw.text),category:raw.categoryHint??_internals72.inferCategoryFromText(raw.text),tags:[...inferredTags,`migration:${raw.sourceSection}`],scope:"global",confidence:0.3,status:"candidate",confirmed_by:[],retrieval_outcomes:{applied_count:0,succeeded_after_count:0,failed_after_count:0},schema_version:config3.schema_version??KNOWLEDGE_SCHEMA_VERSION,created_at:new Date().toISOString(),updated_at:new Date().toISOString(),project_name:projectName,auto_generated:!0};existing.push(entry),migrated++}if(migrated>0)await rewriteKnowledge(knowledgePath,existing);return await _internals72.writeSentinel(sentinelPath,migrated,dropped),log(`[knowledge-migrator] Migrated ${migrated} entries, dropped ${dropped}`),{migrated:!0,entriesMigrated:migrated,entriesDropped:dropped,entriesTotal:rawEntries.length}}async function migrateHiveKnowledgeLegacy(config3){let legacyHivePath=_internals72.resolveLegacyHiveKnowledgePath(),canonicalHivePath=resolveHiveKnowledgePath2(),sentinelPath=path109.join(path109.dirname(canonicalHivePath),".hive-knowledge-migrated");if(existsSync56(sentinelPath))return{migrated:!1,entriesMigrated:0,entriesDropped:0,entriesTotal:0,skippedReason:"sentinel-exists"};if(!existsSync56(legacyHivePath))return{migrated:!1,entriesMigrated:0,entriesDropped:0,entriesTotal:0,skippedReason:"no-context-file"};let legacyEntries=await readKnowledge(legacyHivePath);if(legacyEntries.length===0)return await _internals72.writeSentinel(sentinelPath,0,0),{migrated:!0,entriesMigrated:0,entriesDropped:0,entriesTotal:0};let existingHiveEntries=await readKnowledge(canonicalHivePath),migrated=0,dropped=0,entryErrors=[];for(let legacyEntry of legacyEntries)try{let lesson=legacyEntry.lesson;if(!lesson||typeof lesson!=="string"||lesson.length<15){dropped++;continue}if(findNearDuplicate(lesson,existingHiveEntries,config3.dedup_threshold??0.6)){dropped++;continue}let category=legacyEntry.category||"process",validationResult=validateLesson(lesson,existingHiveEntries.map((e)=>e.lesson),{category,scope:"global",confidence:0.3});if(!validationResult.valid){let errorMsg=`Validation failed for legacy entry: ${validationResult.reason}`;entryErrors.push(errorMsg),warn(`[knowledge-migrator] ${errorMsg}`),dropped++;continue}let confidence=legacyEntry.confidence??0.8,scopeTag=legacyEntry.scope_tag||"global",legacyId=legacyEntry.id,existingIds=new Set(existingHiveEntries.map((e)=>e.id)),resolvedId=legacyId&&existingIds.has(legacyId)?randomUUID10():legacyId||randomUUID10();if(legacyId&&existingIds.has(legacyId))warn(`[knowledge-migrator] Legacy entry ID collision for "${legacyId}", generating new UUID`);let newHiveEntry={id:resolvedId,tier:"hive",lesson:_internals72.truncateLesson(lesson),category,tags:["migration:legacy-hive"],scope:scopeTag,confidence:Math.min(Math.max(confidence,0),1),status:"established",confirmed_by:[],retrieval_outcomes:{applied_count:0,succeeded_after_count:0,failed_after_count:0},schema_version:KNOWLEDGE_SCHEMA_VERSION,created_at:legacyEntry.created_at||new Date().toISOString(),updated_at:legacyEntry.updated_at||new Date().toISOString(),source_project:"legacy-promotion",encounter_score:1};try{await _internals72.appendKnowledge(canonicalHivePath,newHiveEntry),existingHiveEntries.push(newHiveEntry),migrated++}catch(appendError){let errorMsg=`Failed to append entry: ${appendError instanceof Error?appendError.message:String(appendError)}`;entryErrors.push(errorMsg),warn(`[knowledge-migrator] ${errorMsg}`),dropped++}}catch(entryError){let errorMsg=`Unexpected error processing legacy entry: ${entryError instanceof Error?entryError.message:String(entryError)}`;entryErrors.push(errorMsg),warn(`[knowledge-migrator] ${errorMsg}`),dropped++}return await _internals72.writeSentinel(sentinelPath,migrated,dropped),log(`[knowledge-migrator] Migrated ${migrated} legacy hive entries, dropped ${dropped}`),{migrated:!0,entriesMigrated:migrated,entriesDropped:dropped,entriesTotal:legacyEntries.length,...entryErrors.length>0&&{entryErrors}}}function parseContextMd(content){let sections=_internals72.splitIntoSections(content),entries=[],seen=new Set,sectionPatterns=[{pattern:/^#{1,3}\s+lessons?\s+learned/i,sourceSection:"lessons-learned"},{pattern:/^#{1,3}\s+patterns?/i,sourceSection:"patterns"},{pattern:/^#{1,3}\s+sme\s+cache/i,sourceSection:"sme-cache"},{pattern:/^#{1,3}\s+decisions?/i,sourceSection:"decisions"}];for(let section of sections){let match=sectionPatterns.find((sp)=>sp.pattern.test(section.heading));if(!match)continue;let bullets=_internals72.extractBullets(section.body);for(let bullet of bullets){if(bullet.length<15)continue;let normalized=normalize5(bullet);if(seen.has(normalized))continue;seen.add(normalized),entries.push({text:_internals72.truncateLesson(bullet),sourceSection:match.sourceSection,categoryHint:_internals72.inferCategoryFromText(bullet)})}}return entries}function splitIntoSections(content){let sections=[],headingRegex=/^(#{1,3})\s+(.+)/gm,matches=[],match=headingRegex.exec(content);while(match!==null)matches.push({index:match.index,heading:match[0]}),match=headingRegex.exec(content);for(let i=0;i<matches.length;i++){let current=matches[i],next=matches[i+1],bodyStart=current.index+current.heading.length,bodyEnd=next?next.index:content.length,body=content.slice(bodyStart,bodyEnd).trim();sections.push({heading:current.heading,body})}return sections}function extractBullets(body){let bullets=[],bulletRegex=/^\s*[-*]\s+(.+)/;for(let line of body.split(`
1667
1667
  `)){let match=line.match(bulletRegex);if(match)bullets.push(match[1].trim())}return bullets}function inferCategoryFromText(text){let lower=text.toLowerCase();if(/\b(?:test|spec|vitest|jest)\b/.test(lower))return"testing";if(/\b(?:security|auth|token|password|encrypt)\b/.test(lower))return"security";if(/\b(?:performance|latency|cache|throughput)\b/.test(lower))return"performance";if(/\b(?:architecture|design|pattern|structure)\b/.test(lower))return"architecture";if(/\b(?:debug|error|fix|bug|issue)\b/.test(lower))return"debugging";if(/\b(?:tool|config|setup|install|build)\b/.test(lower))return"tooling";if(/\b(?:integrate|api|hook|connect)\b/.test(lower))return"integration";if(/\b(?:process|workflow|step|approach)\b/.test(lower))return"process";return"other"}function truncateLesson2(text){if(text.length<=280)return text;return`${text.slice(0,277)}...`}function inferProjectName(directory){let packageJsonPath=path109.join(directory,"package.json");if(existsSync56(packageJsonPath))try{let pkg=JSON.parse(readFileSync37(packageJsonPath,"utf-8"));if(pkg.name&&typeof pkg.name==="string")return pkg.name}catch{}return path109.basename(directory)}async function writeSentinel(sentinelPath,migrated,dropped){let sentinel={migrated_at:new Date().toISOString(),source_version:"6.16",target_version:"6.17",entries_migrated:migrated,entries_dropped:dropped,schema_version:1,migration_tool:"knowledge-migrator.ts"};await _internals72.mkdir(path109.dirname(sentinelPath),{recursive:!0}),await _internals72.writeFile(sentinelPath,JSON.stringify(sentinel,null,2),"utf-8")}function resolveLegacyHiveKnowledgePath(){let platform=process.platform,home=process.env.HOME||os22.homedir(),dataDir;if(platform==="win32")dataDir=path109.join(process.env.LOCALAPPDATA||path109.join(home,"AppData","Local"),"opencode-swarm","Data");else if(platform==="darwin")dataDir=path109.join(home,"Library","Application Support","opencode-swarm");else dataDir=path109.join(process.env.XDG_DATA_HOME||path109.join(home,".local","share"),"opencode-swarm");return path109.join(dataDir,"hive-knowledge.jsonl")}var _internals72;var init_knowledge_migrator=__esm(()=>{init_logger();init_knowledge_store();init_knowledge_types();init_knowledge_validator();_internals72={appendKnowledge,migrateContextToKnowledge,migrateKnowledgeToExternal,migrateHiveKnowledgeLegacy,parseContextMd,splitIntoSections,extractBullets,inferCategoryFromText,truncateLesson:truncateLesson2,inferProjectName,writeSentinel,resolveLegacyHiveKnowledgePath,existsSync:existsSync56,readFileSync:readFileSync37,readFile:readFile27,mkdir:mkdir23,writeFile:writeFile18}});import{join as join86}from"node:path";function resolveEntryByPrefix(entries,inputId){let exact=entries.find((e)=>e.id===inputId);if(exact)return{entry:exact};let matches=entries.filter((e)=>e.id.startsWith(inputId));if(matches.length===0)return{error:`No entry found matching '${inputId}'.`};if(matches.length===1)return{entry:matches[0]};let candidates=matches.map((e)=>e.id).join(`
1668
1668
  `);return{error:`Ambiguous prefix '${inputId}' matches ${matches.length} entries:
1669
- ${candidates}`}}async function handleKnowledgeQuarantineCommand(directory,args2){let inputId=args2[0];if(!inputId)return"Usage: /swarm knowledge quarantine <id> [reason]";if(!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId))return"Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";let reason=args2.slice(1).join(" ")||"Quarantined via /swarm knowledge quarantine command";try{let entries=await readKnowledge(resolveSwarmKnowledgePath(directory)),resolved=resolveEntryByPrefix(entries,inputId);if("error"in resolved)return`❌ ${resolved.error}`;let fullId=resolved.entry.id;return await quarantineEntry(directory,fullId,reason,"user"),`✅ Entry ${fullId} quarantined successfully.`}catch(error93){return console.warn("[knowledge-command] quarantineEntry error:",error93 instanceof Error?error93.message:String(error93)),"❌ Failed to quarantine entry. Check the entry ID and try again."}}async function handleKnowledgeRestoreCommand(directory,args2){let inputId=args2[0];if(!inputId)return"Usage: /swarm knowledge restore <id>";if(!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId))return"Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";try{let swarmEntries=await readKnowledge(resolveSwarmKnowledgePath(directory)),swarmResolved=resolveEntryByPrefix(swarmEntries,inputId);if("entry"in swarmResolved&&swarmResolved.entry.status==="archived"){let fullId2=swarmResolved.entry.id,result=await unarchiveEntry(directory,fullId2);if(result.restored)return`✅ Archived entry ${fullId2} restored to '${result.restored_to}'.`;return`❌ Entry ${fullId2} could not be unarchived${result.reason?` (${result.reason})`:""}.`}let quarantinePath=join86(resolveKnowledgeStoreDir(directory),"knowledge-quarantined.jsonl"),entries=await readKnowledge(quarantinePath),resolved=resolveEntryByPrefix(entries,inputId);if("error"in resolved){if("entry"in swarmResolved)return`❌ Entry ${swarmResolved.entry.id} is neither archived nor quarantined (status: '${swarmResolved.entry.status}'). Only archived or quarantined entries can be restored.`;return`❌ ${resolved.error}`}let fullId=resolved.entry.id;return await restoreEntry(directory,fullId),`✅ Entry ${fullId} restored successfully.`}catch(error93){return console.warn("[knowledge-command] restoreEntry error:",error93 instanceof Error?error93.message:String(error93)),"❌ Failed to restore entry. Check the entry ID and try again."}}async function handleKnowledgeMigrateCommand(directory,args2){let targetDir=args2[0]||directory,config3=KnowledgeConfigSchema.parse({});try{let contextResult=await migrateContextToKnowledge(targetDir,config3),hiveResult=await migrateHiveKnowledgeLegacy(config3),messages=[];if(contextResult.skippedReason)switch(contextResult.skippedReason){case"sentinel-exists":messages.push("⏭ Context migration already completed. Delete .swarm/.knowledge-migrated to re-run.");break;case"no-context-file":messages.push("ℹ️ No .swarm/context.md found — nothing to migrate.");break;case"empty-context":messages.push("ℹ️ .swarm/context.md is empty — nothing to migrate.");break}else messages.push(`✅ Context migration: ${contextResult.entriesMigrated} entries added, ${contextResult.entriesDropped} dropped`);if(hiveResult.skippedReason)switch(hiveResult.skippedReason){case"sentinel-exists":messages.push("⏭ Hive legacy migration already completed. Delete the sentinel in the hive data dir to re-run.");break;case"no-context-file":messages.push("ℹ️ No legacy hive-knowledge.jsonl found — nothing to migrate.");break}else if(hiveResult.migrated)messages.push(`✅ Hive legacy migration: ${hiveResult.entriesMigrated} entries added, ${hiveResult.entriesDropped} dropped`);return messages.join(`
1670
- `)}catch(error93){return console.warn("[knowledge-command] migration error:",error93 instanceof Error?error93.message:String(error93)),"❌ Migration failed. Check that knowledge source files are readable."}}async function handleKnowledgeListCommand(directory,_args){try{let knowledgePath=resolveSwarmKnowledgePath(directory),entries=await readKnowledge(knowledgePath);if(entries.length===0)return"ℹ️ No knowledge entries found in .swarm/knowledge.jsonl";let lines=[`## Knowledge Entries (${entries.length} total)`,"","| ID (prefix) | Category | Confidence | Lesson (truncated) |","|--------------|----------|------------|---------------------|"];for(let entry of entries){let truncatedLesson=entry.lesson.length>60?`${entry.lesson.slice(0,57)}...`:entry.lesson,confidencePct=Math.round(entry.confidence*100);lines.push(`| ${entry.id.slice(0,12)}… | ${entry.category} | ${confidencePct}% | ${truncatedLesson} |`)}return lines.push(""),lines.push("Use `/swarm knowledge quarantine <id-prefix>` to hide an entry. Prefix matching is supported — the 12-character prefix shown is unique in most stores."),lines.join(`
1671
- `)}catch(error93){return console.warn("[knowledge-command] list error:",error93 instanceof Error?error93.message:String(error93)),"❌ Failed to list knowledge entries. Ensure .swarm/knowledge.jsonl exists."}}async function handleKnowledgeUnactionableCommand(directory,_args){try{let queuePath=resolveUnactionablePath(directory),entries=await readKnowledge(queuePath);if(entries.length===0)return"No unactionable entries in the queue.";let active=entries.filter((e)=>!e.retire_candidate),retired=entries.filter((e)=>e.retire_candidate),lines=[`## Unactionable Queue (${entries.length} total: ${active.length} pending, ${retired.length} retire candidates)`,""];if(active.length>0){lines.push("### Pending hardening","","| ID (prefix) | Lesson | Reason | Quarantined |","|-------------|--------|--------|-------------|");for(let entry of active){let lesson=entry.lesson.length>50?`${entry.lesson.slice(0,47)}...`:entry.lesson;lines.push(`| ${entry.id.slice(0,12)}… | ${lesson} | ${entry.unactionable_reason} | ${entry.quarantined_at?.slice(0,10)??"unknown"} |`)}lines.push("")}if(retired.length>0){lines.push("### Retire candidates (hardening failed)","","| ID (prefix) | Reason | Quarantined |","|-------------|--------|-------------|");for(let entry of retired)lines.push(`| ${entry.id.slice(0,12)}… | ${entry.unactionable_reason} | ${entry.quarantined_at?.slice(0,10)??"unknown"} |`);lines.push("")}return lines.push("Use `/swarm knowledge retry-hardening [id-prefix]` to reset retire candidates for re-processing on the next scheduled hardening pass."),lines.join(`
1672
- `)}catch(error93){return console.warn("[knowledge-command] unactionable list error:",error93 instanceof Error?error93.message:String(error93)),"Failed to list unactionable entries."}}async function handleKnowledgeRetryHardeningCommand(directory,args2){let inputId=args2[0];if(inputId&&!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId))return"Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";try{let queuePath=resolveUnactionablePath(directory),resetCount=0;if(await transactKnowledge(queuePath,(current)=>{let changed=!1,next=[];for(let rec of current){if(!rec.retire_candidate){next.push(rec);continue}if(inputId)if(rec.id===inputId||rec.id.startsWith(inputId))next.push({...rec,retire_candidate:void 0}),resetCount++,changed=!0;else next.push(rec);else next.push({...rec,retire_candidate:void 0}),resetCount++,changed=!0}return changed?next:null}),resetCount===0)return inputId?`No retire candidates found matching '${inputId}'.`:"No retire candidates to reset.";return`Reset ${resetCount} retire candidate(s). They will be re-processed on the next scheduled hardening pass.`}catch(error93){return console.warn("[knowledge-command] retry-hardening error:",error93 instanceof Error?error93.message:String(error93)),"Failed to reset retire candidates."}}var init_knowledge=__esm(()=>{init_schema();init_knowledge_link();init_knowledge_migrator();init_knowledge_store();init_knowledge_validator()});function buildRecoveryHint(failure,worktreePath){if(!failure)return"";if(failure.stage==="conflict")return`Merge conflict at ${worktreePath}. Resolve manually, then re-run merge.`;if(failure.outcome==="partial")return`Partial merge preserved at ${worktreePath}. Stage and commit, then re-run merge.`;return`Merge-back failed at stage "${failure.stage}" (${failure.message}). Manual review required.`}function handleLanesCommand(directory,args2){try{initDurableStatusPath(directory)}catch{}let useJson=args2.includes("--json"),lanes=[];for(let[callID,dispatch]of standardWorktreeByCallID)lanes.push({state:"active",laneId:callID,branch:dispatch.handle.branchName,worktreePath:dispatch.handle.worktreePath,taskId:dispatch.taskId,planTaskId:dispatch.planTaskId,parentSessionID:dispatch.parentSessionID,mergeStrategy:dispatch.mergeStrategy,mergeOutcome:void 0,recoveryHint:""});for(let[callID,record3]of awaitingMergeByCallID)lanes.push({state:"awaiting-merge",laneId:callID,branch:record3.branch,worktreePath:record3.worktreePath,taskId:record3.taskId,planTaskId:record3.planTaskId,parentSessionID:record3.parentSessionID,mergeStrategy:record3.mergeStrategy,mergeOutcome:void 0,recoveryHint:"Merge-back in progress; check `/swarm status` for the latest."});for(let[taskId,failure]of getAllWorktreeMergeFailures()){let isStale=!1;for(let record3 of awaitingMergeByCallID.values())if((record3.planTaskId??record3.taskId)===taskId){isStale=!0;break}if(isStale)continue;let worktreePath=failure.worktreePath??"",branch=failure.branch??"";lanes.push({state:"conflicted",laneId:taskId,branch,worktreePath,taskId,planTaskId:void 0,parentSessionID:"",mergeStrategy:"merge",mergeOutcome:failure,recoveryHint:buildRecoveryHint(failure,worktreePath)})}if(lanes.sort((a,b)=>STATE_ORDER2[a.state]-STATE_ORDER2[b.state]||a.laneId.localeCompare(b.laneId)),useJson)return JSON.stringify({lanes,totalCount:lanes.length},null,2);let lines=[],byState={};for(let l of lanes){let group=byState[l.state];if(group)group.push(l);else byState[l.state]=[l]}for(let state of["active","awaiting-merge","conflicted"]){let group=byState[state]??[];if(lines.push(`## ${state} (${group.length})`),group.length===0)lines.push(" (none)");else for(let lane of group){let outcome=lane.mergeOutcome?` [${lane.mergeOutcome.outcome} @ ${lane.mergeOutcome.stage}]`:"";if(lines.push(` - ${lane.laneId} task=${lane.taskId} branch=${lane.branch}${outcome}`),lines.push(` worktree=${lane.worktreePath}`),lane.recoveryHint)lines.push(` hint: ${lane.recoveryHint}`)}lines.push("")}return lines.push(`Total: ${lanes.length} lanes`),lines.join(`
1669
+ ${candidates}`}}async function handleKnowledgeQuarantineCommand(directory,args2){let inputId=args2[0];if(!inputId)return"Usage: /swarm knowledge quarantine <id> [reason]";if(!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId))return"Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";let reason=args2.slice(1).join(" ")||"Quarantined via /swarm knowledge quarantine command";try{let entries=await readKnowledge(resolveSwarmKnowledgePath(directory)),resolved=resolveEntryByPrefix(entries,inputId);if("error"in resolved)return`❌ ${resolved.error}`;let fullId=resolved.entry.id;return await quarantineEntry(directory,fullId,reason,"user"),`✅ Entry ${fullId} quarantined successfully.`}catch(error93){return log("[knowledge-command] quarantineEntry error:",error93 instanceof Error?error93.message:String(error93)),"❌ Failed to quarantine entry. Check the entry ID and try again."}}async function handleKnowledgeRestoreCommand(directory,args2){let inputId=args2[0];if(!inputId)return"Usage: /swarm knowledge restore <id>";if(!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId))return"Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";try{let swarmEntries=await readKnowledge(resolveSwarmKnowledgePath(directory)),swarmResolved=resolveEntryByPrefix(swarmEntries,inputId);if("entry"in swarmResolved&&swarmResolved.entry.status==="archived"){let fullId2=swarmResolved.entry.id,result=await unarchiveEntry(directory,fullId2);if(result.restored)return`✅ Archived entry ${fullId2} restored to '${result.restored_to}'.`;return`❌ Entry ${fullId2} could not be unarchived${result.reason?` (${result.reason})`:""}.`}let quarantinePath=join86(resolveKnowledgeStoreDir(directory),"knowledge-quarantined.jsonl"),entries=await readKnowledge(quarantinePath),resolved=resolveEntryByPrefix(entries,inputId);if("error"in resolved){if("entry"in swarmResolved)return`❌ Entry ${swarmResolved.entry.id} is neither archived nor quarantined (status: '${swarmResolved.entry.status}'). Only archived or quarantined entries can be restored.`;return`❌ ${resolved.error}`}let fullId=resolved.entry.id;return await restoreEntry(directory,fullId),`✅ Entry ${fullId} restored successfully.`}catch(error93){return log("[knowledge-command] restoreEntry error:",error93 instanceof Error?error93.message:String(error93)),"❌ Failed to restore entry. Check the entry ID and try again."}}async function handleKnowledgeMigrateCommand(directory,args2){let targetDir=args2[0]||directory,config3=KnowledgeConfigSchema.parse({});try{let contextResult=await migrateContextToKnowledge(targetDir,config3),hiveResult=await migrateHiveKnowledgeLegacy(config3),messages=[];if(contextResult.skippedReason)switch(contextResult.skippedReason){case"sentinel-exists":messages.push("⏭ Context migration already completed. Delete .swarm/.knowledge-migrated to re-run.");break;case"no-context-file":messages.push("ℹ️ No .swarm/context.md found — nothing to migrate.");break;case"empty-context":messages.push("ℹ️ .swarm/context.md is empty — nothing to migrate.");break}else messages.push(`✅ Context migration: ${contextResult.entriesMigrated} entries added, ${contextResult.entriesDropped} dropped`);if(hiveResult.skippedReason)switch(hiveResult.skippedReason){case"sentinel-exists":messages.push("⏭ Hive legacy migration already completed. Delete the sentinel in the hive data dir to re-run.");break;case"no-context-file":messages.push("ℹ️ No legacy hive-knowledge.jsonl found — nothing to migrate.");break}else if(hiveResult.migrated)messages.push(`✅ Hive legacy migration: ${hiveResult.entriesMigrated} entries added, ${hiveResult.entriesDropped} dropped`);return messages.join(`
1670
+ `)}catch(error93){return log("[knowledge-command] migration error:",error93 instanceof Error?error93.message:String(error93)),"❌ Migration failed. Check that knowledge source files are readable."}}async function handleKnowledgeListCommand(directory,_args){try{let knowledgePath=resolveSwarmKnowledgePath(directory),entries=await readKnowledge(knowledgePath);if(entries.length===0)return"ℹ️ No knowledge entries found in .swarm/knowledge.jsonl";let lines=[`## Knowledge Entries (${entries.length} total)`,"","| ID (prefix) | Category | Confidence | Lesson (truncated) |","|--------------|----------|------------|---------------------|"];for(let entry of entries){let truncatedLesson=entry.lesson.length>60?`${entry.lesson.slice(0,57)}...`:entry.lesson,confidencePct=Math.round(entry.confidence*100);lines.push(`| ${entry.id.slice(0,12)}… | ${entry.category} | ${confidencePct}% | ${truncatedLesson} |`)}return lines.push(""),lines.push("Use `/swarm knowledge quarantine <id-prefix>` to hide an entry. Prefix matching is supported — the 12-character prefix shown is unique in most stores."),lines.join(`
1671
+ `)}catch(error93){return log("[knowledge-command] list error:",error93 instanceof Error?error93.message:String(error93)),"❌ Failed to list knowledge entries. Ensure .swarm/knowledge.jsonl exists."}}async function handleKnowledgeUnactionableCommand(directory,_args){try{let queuePath=resolveUnactionablePath(directory),entries=await readKnowledge(queuePath);if(entries.length===0)return"No unactionable entries in the queue.";let active=entries.filter((e)=>!e.retire_candidate),retired=entries.filter((e)=>e.retire_candidate),lines=[`## Unactionable Queue (${entries.length} total: ${active.length} pending, ${retired.length} retire candidates)`,""];if(active.length>0){lines.push("### Pending hardening","","| ID (prefix) | Lesson | Reason | Quarantined |","|-------------|--------|--------|-------------|");for(let entry of active){let lesson=entry.lesson.length>50?`${entry.lesson.slice(0,47)}...`:entry.lesson;lines.push(`| ${entry.id.slice(0,12)}… | ${lesson} | ${entry.unactionable_reason} | ${entry.quarantined_at?.slice(0,10)??"unknown"} |`)}lines.push("")}if(retired.length>0){lines.push("### Retire candidates (hardening failed)","","| ID (prefix) | Reason | Quarantined |","|-------------|--------|-------------|");for(let entry of retired)lines.push(`| ${entry.id.slice(0,12)}… | ${entry.unactionable_reason} | ${entry.quarantined_at?.slice(0,10)??"unknown"} |`);lines.push("")}return lines.push("Use `/swarm knowledge retry-hardening [id-prefix]` to reset retire candidates for re-processing on the next scheduled hardening pass."),lines.join(`
1672
+ `)}catch(error93){return log("[knowledge-command] unactionable list error:",error93 instanceof Error?error93.message:String(error93)),"Failed to list unactionable entries."}}async function handleKnowledgeRetryHardeningCommand(directory,args2){let inputId=args2[0];if(inputId&&!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId))return"Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";try{let queuePath=resolveUnactionablePath(directory),resetCount=0;if(await transactKnowledge(queuePath,(current)=>{let changed=!1,next=[];for(let rec of current){if(!rec.retire_candidate){next.push(rec);continue}if(inputId)if(rec.id===inputId||rec.id.startsWith(inputId))next.push({...rec,retire_candidate:void 0}),resetCount++,changed=!0;else next.push(rec);else next.push({...rec,retire_candidate:void 0}),resetCount++,changed=!0}return changed?next:null}),resetCount===0)return inputId?`No retire candidates found matching '${inputId}'.`:"No retire candidates to reset.";return`Reset ${resetCount} retire candidate(s). They will be re-processed on the next scheduled hardening pass.`}catch(error93){return log("[knowledge-command] retry-hardening error:",error93 instanceof Error?error93.message:String(error93)),"Failed to reset retire candidates."}}var init_knowledge=__esm(()=>{init_schema();init_knowledge_link();init_knowledge_migrator();init_knowledge_store();init_knowledge_validator();init_logger()});function buildRecoveryHint(failure,worktreePath){if(!failure)return"";if(failure.stage==="conflict")return`Merge conflict at ${worktreePath}. Resolve manually, then re-run merge.`;if(failure.outcome==="partial")return`Partial merge preserved at ${worktreePath}. Stage and commit, then re-run merge.`;return`Merge-back failed at stage "${failure.stage}" (${failure.message}). Manual review required.`}function handleLanesCommand(directory,args2){try{initDurableStatusPath(directory)}catch{}let useJson=args2.includes("--json"),lanes=[];for(let[callID,dispatch]of standardWorktreeByCallID)lanes.push({state:"active",laneId:callID,branch:dispatch.handle.branchName,worktreePath:dispatch.handle.worktreePath,taskId:dispatch.taskId,planTaskId:dispatch.planTaskId,parentSessionID:dispatch.parentSessionID,mergeStrategy:dispatch.mergeStrategy,mergeOutcome:void 0,recoveryHint:""});for(let[callID,record3]of awaitingMergeByCallID)lanes.push({state:"awaiting-merge",laneId:callID,branch:record3.branch,worktreePath:record3.worktreePath,taskId:record3.taskId,planTaskId:record3.planTaskId,parentSessionID:record3.parentSessionID,mergeStrategy:record3.mergeStrategy,mergeOutcome:void 0,recoveryHint:"Merge-back in progress; check `/swarm status` for the latest."});for(let[taskId,failure]of getAllWorktreeMergeFailures()){let isStale=!1;for(let record3 of awaitingMergeByCallID.values())if((record3.planTaskId??record3.taskId)===taskId){isStale=!0;break}if(isStale)continue;let worktreePath=failure.worktreePath??"",branch=failure.branch??"";lanes.push({state:"conflicted",laneId:taskId,branch,worktreePath,taskId,planTaskId:void 0,parentSessionID:"",mergeStrategy:"merge",mergeOutcome:failure,recoveryHint:buildRecoveryHint(failure,worktreePath)})}if(lanes.sort((a,b)=>STATE_ORDER2[a.state]-STATE_ORDER2[b.state]||a.laneId.localeCompare(b.laneId)),useJson)return JSON.stringify({lanes,totalCount:lanes.length},null,2);let lines=[],byState={};for(let l of lanes){let group=byState[l.state];if(group)group.push(l);else byState[l.state]=[l]}for(let state of["active","awaiting-merge","conflicted"]){let group=byState[state]??[];if(lines.push(`## ${state} (${group.length})`),group.length===0)lines.push(" (none)");else for(let lane of group){let outcome=lane.mergeOutcome?` [${lane.mergeOutcome.outcome} @ ${lane.mergeOutcome.stage}]`:"";if(lines.push(` - ${lane.laneId} task=${lane.taskId} branch=${lane.branch}${outcome}`),lines.push(` worktree=${lane.worktreePath}`),lane.recoveryHint)lines.push(` hint: ${lane.recoveryHint}`)}lines.push("")}return lines.push(`Total: ${lanes.length} lanes`),lines.join(`
1673
1673
  `)}var STATE_ORDER2;var init_lanes=__esm(()=>{init_worktree_isolation();init_worktree_merge_status();STATE_ORDER2={active:0,"awaiting-merge":1,conflicted:2}});function parseTimeoutMs(args2){let timeoutIdx=args2.indexOf("--timeout-ms");if(timeoutIdx===-1||timeoutIdx+1>=args2.length)return DEFAULT_LEARNING_TIMEOUT_MS;let parsed=Number(args2[timeoutIdx+1]);if(!Number.isInteger(parsed)||parsed<1||parsed>MAX_LEARNING_TIMEOUT_MS)return DEFAULT_LEARNING_TIMEOUT_MS;return parsed}function timeoutMessage(timeoutMs){return`LEARNING_METRICS_TIMEOUT: exceeded ${timeoutMs}ms while computing learning metrics. Run /swarm diagnose to check .swarm/ health.`}async function computeWithTimeout(directory,currentPhase,timeoutMs){let controller=new AbortController,timeout,metricsPromise=_internals73.computeLearningMetrics(directory,{currentPhase,signal:controller.signal});metricsPromise.catch(()=>{});let timeoutPromise=new Promise((_,reject)=>{timeout=setTimeout(()=>{reject(new LearningMetricsTimeoutError(timeoutMs)),controller.abort()},timeoutMs)});try{return await Promise.race([metricsPromise,timeoutPromise])}finally{if(timeout)clearTimeout(timeout)}}async function handleLearningCommand(directory,args2){try{let jsonMode=args2.includes("--json"),timeoutMs=parseTimeoutMs(args2),currentPhase,phaseIdx=args2.indexOf("--phase");if(phaseIdx!==-1&&phaseIdx+1<args2.length){let parsed=Number(args2[phaseIdx+1]);if(Number.isFinite(parsed))currentPhase=parsed}let metrics=await computeWithTimeout(directory,currentPhase,timeoutMs);if(jsonMode)return`[LEARNING_JSON]
1674
1674
  ${JSON.stringify(formatLearningJSON(metrics),null,2)}
1675
1675
  [/LEARNING_JSON]`;return formatLearningMarkdown(metrics)}catch(err){if(err instanceof LearningMetricsTimeoutError){if(args2.includes("--json"))return`[LEARNING_JSON]
@@ -1797,12 +1797,12 @@ Use a valid summary ID (e.g., S1, S2, S3).`;return fullOutput}catch(error93){ret
1797
1797
 
1798
1798
  ${error93 instanceof Error?error93.message:String(error93)}`}}var init_retrieve=__esm(()=>{init_manager4()});import*as fs72 from"node:fs";import*as path138 from"node:path";function safeParseToolJson(result){try{let jsonStr=typeof result==="string"?result:result.output;return JSON.parse(jsonStr)}catch{return null}}async function listGitCheckpoints(directory){try{let result=await checkpoint.execute({action:"list"},{directory}),parsed=safeParseToolJson(result);if(!parsed)return null;if(parsed.success!==!0||!Array.isArray(parsed.checkpoints))return null;return parsed.checkpoints}catch{return null}}function formatGitCheckpointList(checkpoints){if(checkpoints.length===0)return"No checkpoints found. Create one with `/swarm checkpoint save <label>`";return["## Available Checkpoints","",...checkpoints.map((c,index)=>`- ${index+1}. "${c.label}" - ${new Date(c.timestamp).toLocaleString()} (${c.sha.slice(0,12)})`),"","Run `/swarm rollback <label-or-number>` to restore to a checkpoint."].join(`
1799
1799
  `)}function resolveGitCheckpoint(checkpoints,selector){let index=Number.parseInt(selector,10);if(/^\d+$/.test(selector)&&index>=1&&index<=checkpoints.length)return checkpoints[index-1]??null;return checkpoints.find((c)=>c.label===selector)??null}async function restoreGitCheckpoint(directory,selected){let result=await checkpoint.execute({action:"restore",label:selected.label},{directory}),parsed=safeParseToolJson(result);if(!parsed)return`Error: Failed to parse checkpoint response for "${selected.label}"`;if(parsed.success!==!0)return`Error: ${parsed.error||`Failed to restore checkpoint "${selected.label}"`}`;let eventsPath=validateSwarmPath(directory,"events.jsonl"),rollbackEvent={type:"rollback",label:selected.label,sha:selected.sha,timestamp:new Date().toISOString(),source:"checkpoints.json"};try{fs72.appendFileSync(eventsPath,`${JSON.stringify(rollbackEvent)}
1800
- `)}catch(error93){console.error("Failed to write rollback event:",error93 instanceof Error?error93.message:String(error93))}return`Rolled back to checkpoint "${selected.label}" (${selected.sha.slice(0,12)})`}async function handleRollbackCommand(directory,args2){let phaseArg=args2[0];if(!phaseArg){let manifestPath2=validateSwarmPath(directory,"checkpoints/manifest.json");if(!fs72.existsSync(manifestPath2)){let gitCheckpoints=await listGitCheckpoints(directory);if(gitCheckpoints)return formatGitCheckpointList(gitCheckpoints);return"No checkpoints found. Use `/swarm checkpoint save <label>` to create checkpoints."}let manifest2;try{manifest2=JSON.parse(fs72.readFileSync(manifestPath2,"utf-8"))}catch{return"Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint."}let checkpoints=manifest2.checkpoints||[];if(checkpoints.length===0)return"No checkpoints found in manifest.";return["## Available Checkpoints","",...checkpoints.map((c)=>`- Phase ${c.phase}: ${c.label||"no label"} (${new Date(c.timestamp).toLocaleString()})`),"","Run `/swarm rollback <phase>` to restore to a checkpoint."].join(`
1800
+ `)}catch(error93){log("Failed to write rollback event:",error93 instanceof Error?error93.message:String(error93))}return`Rolled back to checkpoint "${selected.label}" (${selected.sha.slice(0,12)})`}async function handleRollbackCommand(directory,args2){let phaseArg=args2[0];if(!phaseArg){let manifestPath2=validateSwarmPath(directory,"checkpoints/manifest.json");if(!fs72.existsSync(manifestPath2)){let gitCheckpoints=await listGitCheckpoints(directory);if(gitCheckpoints)return formatGitCheckpointList(gitCheckpoints);return"No checkpoints found. Use `/swarm checkpoint save <label>` to create checkpoints."}let manifest2;try{manifest2=JSON.parse(fs72.readFileSync(manifestPath2,"utf-8"))}catch{return"Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint."}let checkpoints=manifest2.checkpoints||[];if(checkpoints.length===0)return"No checkpoints found in manifest.";return["## Available Checkpoints","",...checkpoints.map((c)=>`- Phase ${c.phase}: ${c.label||"no label"} (${new Date(c.timestamp).toLocaleString()})`),"","Run `/swarm rollback <phase>` to restore to a checkpoint."].join(`
1801
1801
  `)}let targetPhase=parseInt(phaseArg,10);if(Number.isNaN(targetPhase)||targetPhase<1){let gitCheckpoints=await listGitCheckpoints(directory);if(!gitCheckpoints)return"Error: Phase number must be a positive integer.";let selected=resolveGitCheckpoint(gitCheckpoints,phaseArg);if(!selected)return`Error: Checkpoint "${phaseArg}" not found. Available checkpoints: ${gitCheckpoints.map((c)=>`"${c.label}"`).join(", ")||"none"}`;return restoreGitCheckpoint(directory,selected)}let manifestPath=validateSwarmPath(directory,"checkpoints/manifest.json");if(!fs72.existsSync(manifestPath)){let gitCheckpoints=await listGitCheckpoints(directory);if(!gitCheckpoints)return`Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;let selected=resolveGitCheckpoint(gitCheckpoints,phaseArg);if(!selected)return`Error: Checkpoint ${phaseArg} not found. Available checkpoints: ${gitCheckpoints.map((c,index)=>`${index+1}="${c.label}"`).join(", ")||"none"}`;return restoreGitCheckpoint(directory,selected)}let manifest;try{manifest=JSON.parse(fs72.readFileSync(manifestPath,"utf-8"))}catch{return"Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint."}let checkpoint2=manifest.checkpoints?.find((c)=>c.phase===targetPhase);if(!checkpoint2){let available=manifest.checkpoints?.map((c)=>c.phase).join(", ")||"none";return`Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`}let checkpointDir=validateSwarmPath(directory,`checkpoints/phase-${targetPhase}`);if(!fs72.existsSync(checkpointDir))return`Error: Checkpoint directory for phase ${targetPhase} does not exist.`;let checkpointFiles=fs72.readdirSync(checkpointDir);if(checkpointFiles.length===0)return`Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;let swarmDir=validateSwarmPath(directory,""),EXCLUDE_FILES=new Set(["plan-ledger.jsonl","plan-ledger.quarantine"]),successes=[],failures=[],warnings=[];for(let file3 of checkpointFiles){if(EXCLUDE_FILES.has(file3)||file3.startsWith("plan-ledger.archived-"))continue;let src=path138.join(checkpointDir,file3),dest=path138.join(swarmDir,file3);try{fs72.cpSync(src,dest,{recursive:!0,force:!0}),successes.push(file3)}catch(error93){failures.push({file:file3,error:error93.message})}}if(failures.length>0)return[`Rollback partially completed. Successfully restored ${successes.length} files.`,`Failed on ${failures.length} files:`,...failures.map((f)=>` - ${f.file}: ${f.error}`),"","Some files could not be restored. The .swarm/ directory may be in an inconsistent state.","Check permissions and disk space, then retry the rollback."].join(`
1802
1802
  `);let existingLedgerPath=path138.join(swarmDir,"plan-ledger.jsonl"),ledgerDeletionFailed=!1;if(fs72.existsSync(existingLedgerPath))try{fs72.unlinkSync(existingLedgerPath)}catch(err){ledgerDeletionFailed=!0;let errMsg=err instanceof Error?err.message:String(err);warnings.push(`⚠️ Warning: Could not delete stale ledger (${errMsg}). The ledger may be inconsistent with the restored plan. Run /swarm reset-session to clean up session state.`)}if(!ledgerDeletionFailed)try{let planJsonPath=path138.join(swarmDir,"plan.json");if(fs72.existsSync(planJsonPath)){let planRaw=fs72.readFileSync(planJsonPath,"utf-8"),plan=PlanSchema.parse(JSON.parse(planRaw)),planId=derivePlanId(plan),planHash=computePlanHash(plan);await initLedger(directory,planId,planHash,plan),await appendLedgerEvent(directory,{event_type:"plan_rebuilt",source:"rollback",plan_id:planId})}}catch(initError){return[`Rollback restored files but failed to initialize ledger: ${initError instanceof Error?initError.message:String(initError)}`,"The .swarm/plan.json has been restored but the ledger may be out of sync.","Run /swarm reset-session to reinitialize the ledger."].join(`
1803
1803
  `)}let eventsPath=validateSwarmPath(directory,"events.jsonl"),rollbackEvent={type:"rollback",phase:targetPhase,label:checkpoint2.label||"",timestamp:new Date().toISOString()};try{fs72.appendFileSync(eventsPath,`${JSON.stringify(rollbackEvent)}
1804
- `)}catch(error93){console.error("Failed to write rollback event:",error93 instanceof Error?error93.message:String(error93))}if(warnings.length>0)return[...warnings,"",`Rolled back to phase ${targetPhase}: ${checkpoint2.label||"no label"}`].join(`
1805
- `);return`Rolled back to phase ${targetPhase}: ${checkpoint2.label||"no label"}`}var init_rollback=__esm(()=>{init_plan_schema();init_utils2();init_ledger();init_utils3();init_checkpoint()});import*as fs73 from"node:fs";import*as path139 from"node:path";function isUnsafeId(value){return value.includes("/")||value.includes("\\")||value.includes("..")||value.includes("[")||value.includes("]")||containsControlChars(value)}function parseArgs11(args2){let parsed={json:!1,dryRun:!1,overwrite:!1};for(let i=0;i<args2.length;i++){let token=args2[i];if(token==="--json")parsed.json=!0;else if(token==="--dry-run")parsed.dryRun=!0;else if(token==="--overwrite")parsed.overwrite=!0;else if(token==="--change"){if(i+1>=args2.length||args2[i+1].startsWith("--"))return{...parsed,error:"--change requires a value"};let value=args2[++i];if(isUnsafeId(value))return{...parsed,error:"--change must be a single OpenSpec change id with no path separators, traversal, brackets, or control characters"};parsed.changeId=value}else if(token==="--source"){if(i+1>=args2.length||args2[i+1].startsWith("--"))return{...parsed,error:"--source requires a value"};let value=args2[++i];if(value!=="swarm"&&value!=="openspec"&&value!=="speckit")return{...parsed,error:`--source must be one of: swarm | openspec | speckit; got "${value}"`};parsed.source=value}else if(token==="--feature"){if(i+1>=args2.length||args2[i+1].startsWith("--"))return{...parsed,error:"--feature requires a value"};let value=args2[++i];if(isUnsafeId(value))return{...parsed,error:"--feature must be a single Spec-Kit feature directory name with no path separators, traversal, brackets, or control characters"};parsed.feature=value}else return{...parsed,error:`Unknown flag "${token}"`}}return parsed}function formatList(items){return items.length>0?items.map((item)=>`- ${item}`).join(`
1804
+ `)}catch(error93){log("Failed to write rollback event:",error93 instanceof Error?error93.message:String(error93))}if(warnings.length>0)return[...warnings,"",`Rolled back to phase ${targetPhase}: ${checkpoint2.label||"no label"}`].join(`
1805
+ `);return`Rolled back to phase ${targetPhase}: ${checkpoint2.label||"no label"}`}var init_rollback=__esm(()=>{init_plan_schema();init_utils2();init_ledger();init_utils3();init_checkpoint();init_logger()});import*as fs73 from"node:fs";import*as path139 from"node:path";function isUnsafeId(value){return value.includes("/")||value.includes("\\")||value.includes("..")||value.includes("[")||value.includes("]")||containsControlChars(value)}function parseArgs11(args2){let parsed={json:!1,dryRun:!1,overwrite:!1};for(let i=0;i<args2.length;i++){let token=args2[i];if(token==="--json")parsed.json=!0;else if(token==="--dry-run")parsed.dryRun=!0;else if(token==="--overwrite")parsed.overwrite=!0;else if(token==="--change"){if(i+1>=args2.length||args2[i+1].startsWith("--"))return{...parsed,error:"--change requires a value"};let value=args2[++i];if(isUnsafeId(value))return{...parsed,error:"--change must be a single OpenSpec change id with no path separators, traversal, brackets, or control characters"};parsed.changeId=value}else if(token==="--source"){if(i+1>=args2.length||args2[i+1].startsWith("--"))return{...parsed,error:"--source requires a value"};let value=args2[++i];if(value!=="swarm"&&value!=="openspec"&&value!=="speckit")return{...parsed,error:`--source must be one of: swarm | openspec | speckit; got "${value}"`};parsed.source=value}else if(token==="--feature"){if(i+1>=args2.length||args2[i+1].startsWith("--"))return{...parsed,error:"--feature requires a value"};let value=args2[++i];if(isUnsafeId(value))return{...parsed,error:"--feature must be a single Spec-Kit feature directory name with no path separators, traversal, brackets, or control characters"};parsed.feature=value}else return{...parsed,error:`Unknown flag "${token}"`}}return parsed}function formatList(items){return items.length>0?items.map((item)=>`- ${item}`).join(`
1806
1806
  `):"- none"}function formatSpeckitError(resolution){switch(resolution.kind){case"empty":return"Spec-Kit layout detected (.specify/ marker present) but no feature directories found under specs/.";case"ambiguous":return[`Multiple Spec-Kit features detected: ${resolution.features.join(", ")}.`,"Use --feature <id> to select one."].join(`
1807
1807
  `);case"unknown_feature":return[`Unknown Spec-Kit feature '${resolution.feature}'.`,`Available features: ${resolution.available.join(", ")}.`].join(`
1808
1808
  `);case"zero_requirements":return`Spec-Kit feature '${resolution.feature}' contains no parsable functional requirements.`;case"too_large":return`Spec-Kit feature '${resolution.feature}' projected output exceeds the size limit (${resolution.bytes} bytes).`;case"not_speckit":return"No Spec-Kit layout detected (.specify/ marker not present).";case"ok":return""}}async function handleSddStatusCommand(directory,args2){let parsed=parseArgs11(args2);if(parsed.error)return`Error: ${parsed.error}
@@ -5256,7 +5256,7 @@ Example:
5256
5256
  [TESTED] | task-2.2 | FAIL | 8/10 tests passed — bar.test.ts missing coverage for error path
5257
5257
 
5258
5258
  If covering a single task only, you do not need to emit the structured verdict line.
5259
- `;var init_test_engineer=()=>{};import{mkdir as mkdir29,writeFile as writeFile20}from"node:fs/promises";import*as path146 from"node:path";function stripSwarmPrefix(agentName,swarmPrefix){if(!swarmPrefix||!agentName)return agentName;let prefixWithUnderscore=`${swarmPrefix}_`;if(agentName.startsWith(prefixWithUnderscore))return agentName.substring(prefixWithUnderscore.length);return agentName}function extractSwarmIdFromAgentName(agentName){if(!agentName)return;let match=agentName.match(/^([^_]+)_/);return match?match[1]:void 0}function getModelForAgent(agentName,swarmAgents,swarmPrefix,quiet){let baseAgentName=stripSwarmPrefix(agentName,swarmPrefix),explicit=swarmAgents?.[baseAgentName]?.model;if(explicit)return explicit;let resolvedModel=DEFAULT_MODELS[baseAgentName]??DEFAULT_MODELS.default;if(!warnedAgents.has(baseAgentName))if(warnedAgents.add(baseAgentName),!quiet)console.warn("[swarm] Agent '%s' not found in config — using default model '%s'. Add it to opencode-swarm.json to customize.",baseAgentName,resolvedModel);else addDeferredWarning(`[swarm] Agent '${baseAgentName}' not found in config — using default model '${resolvedModel}'. Add it to opencode-swarm.json to customize.`);return resolvedModel}function resolveFallbackModel(agentBaseName,fallbackIndex,swarmAgents){let fallbackModels=swarmAgents?.[agentBaseName]?.fallback_models;if(fallbackModels===void 0&&(agentBaseName==="curator_init"||agentBaseName==="curator_phase"||agentBaseName==="curator_postmortem"))fallbackModels=swarmAgents?.explorer?.fallback_models;if(!fallbackModels||fallbackModels.length===0)return null;if(fallbackIndex<1||fallbackIndex>fallbackModels.length)return null;return fallbackModels[fallbackIndex-1]}function getSwarmAgents(swarmId){let id=swarmId??"default";return _swarmAgentsMap.get(id)}function isAgentDisabled(agentName,swarmAgents,swarmPrefix){let baseAgentName=stripSwarmPrefix(agentName,swarmPrefix);return swarmAgents?.[baseAgentName]?.disabled===!0}function getTemperatureOverride(agentName,swarmAgents,swarmPrefix){let baseAgentName=stripSwarmPrefix(agentName,swarmPrefix);return swarmAgents?.[baseAgentName]?.temperature}function getVariantOverride(agentName,swarmAgents,swarmPrefix){let baseAgentName=stripSwarmPrefix(agentName,swarmPrefix);return swarmAgents?.[baseAgentName]?.variant}function applyOverrides(agent,swarmAgents,swarmPrefix,quiet){let tempOverride=getTemperatureOverride(agent.name,swarmAgents,swarmPrefix);if(tempOverride!==void 0)agent.config.temperature=tempOverride;let variantOverride=getVariantOverride(agent.name,swarmAgents,swarmPrefix),modelSegments=agent.config.model?.split("/")??[],lastSegment=modelSegments[modelSegments.length-1]??"";if(modelSegments.length>=3&&KNOWN_VARIANT_VALUES.has(lastSegment)){let autoVariant=lastSegment,cleanedModel=modelSegments.slice(0,-1).join("/"),effectiveVariant=variantOverride??autoVariant;if(!quiet)console.warn(`[swarm] Deprecation: model "${agent.config.model}" embeds variant. Use "model": "${cleanedModel}", "variant": "${effectiveVariant}" instead.`);else addDeferredWarning(`[swarm] Deprecation: model "${agent.config.model}" embeds variant. Use "model": "${cleanedModel}", "variant": "${effectiveVariant}" instead.`);agent.config.model=cleanedModel,agent.config.variant=effectiveVariant}else if(variantOverride!==void 0)agent.config.variant=variantOverride;let baseAgentName=stripSwarmPrefix(agent.name,swarmPrefix),reasoningOverride=swarmAgents?.[baseAgentName]?.reasoning;if(reasoningOverride!==void 0)agent.config.reasoning=reasoningOverride;let thinkingOverride=swarmAgents?.[baseAgentName]?.thinking;if(thinkingOverride!==void 0)agent.config.thinking=thinkingOverride;return agent}function createSwarmAgents(swarmId,swarmConfig,isDefault,pluginConfig,projectContext=emptyProjectContext()){let agents=[],swarmAgents=swarmConfig.agents;_swarmAgentsMap.set(swarmId,swarmAgents??{});let prefix=isDefault?"":`${swarmId}_`,swarmPrefix=isDefault?void 0:swarmId,qaRetryLimit=pluginConfig?.qa_retry_limit??3,quiet=pluginConfig?.quiet??!0,getModel=(baseName)=>getModelForAgent(baseName,swarmAgents,swarmPrefix,quiet),getPrompts=(name)=>loadAgentPrompt(name),prefixName=(name)=>`${prefix}${name}`;if(!isAgentDisabled("architect",swarmAgents,swarmPrefix)){let architectPrompts=getPrompts("architect"),architect=createArchitectAgent(getModel("architect"),architectPrompts.prompt,architectPrompts.appendPrompt,pluginConfig?.adversarial_testing,pluginConfig?.council,pluginConfig?.ui_review,pluginConfig?.memory?.enabled===!0,pluginConfig?.architectural_supervision,pluginConfig?.design_docs?.enabled===!0,pluginConfig?.external_skills?.curation_enabled===!0,pluginConfig?.turbo!==void 0,pluginConfig?.skills?.enabled===!0);architect.name=prefixName("architect");let swarmName=swarmConfig.name||swarmId,swarmIdentity=isDefault?"default":swarmId,agentPrefix=prefix;if(architect.config.prompt=architect.config.prompt?.replace(/\{\{SWARM_ID\}\}/g,swarmIdentity).replace(/\{\{AGENT_PREFIX\}\}/g,agentPrefix).replace(/\{\{QA_RETRY_LIMIT\}\}/g,String(qaRetryLimit)).replace(/\{\{PROJECT_LANGUAGE\}\}/g,projectContext.PROJECT_LANGUAGE).replace(/\{\{PROJECT_FRAMEWORK\}\}/g,projectContext.PROJECT_FRAMEWORK).replace(/\{\{BUILD_CMD\}\}/g,projectContext.BUILD_CMD).replace(/\{\{TEST_CMD\}\}/g,projectContext.TEST_CMD).replace(/\{\{LINT_CMD\}\}/g,projectContext.LINT_CMD).replace(/\{\{ENTRY_POINTS\}\}/g,projectContext.ENTRY_POINTS).replace(/\{\{CODER_CONSTRAINTS\}\}/g,projectContext.CODER_CONSTRAINTS).replace(/\{\{TEST_CONSTRAINTS\}\}/g,projectContext.TEST_CONSTRAINTS).replace(/\{\{REVIEWER_CHECKLIST\}\}/g,projectContext.REVIEWER_CHECKLIST).replace(/\{\{PROJECT_CONTEXT_SECONDARY_LANGUAGES\}\}/g,projectContext.PROJECT_CONTEXT_SECONDARY_LANGUAGES),!isDefault){architect.description=`[${swarmName}] ${architect.description}`;let swarmHeader=`## ⚠️ YOU ARE THE ${swarmName.toUpperCase()} SWARM ARCHITECT
5259
+ `;var init_test_engineer=()=>{};import{mkdir as mkdir29,writeFile as writeFile20}from"node:fs/promises";import*as path146 from"node:path";function stripSwarmPrefix(agentName,swarmPrefix){if(!swarmPrefix||!agentName)return agentName;let prefixWithUnderscore=`${swarmPrefix}_`;if(agentName.startsWith(prefixWithUnderscore))return agentName.substring(prefixWithUnderscore.length);return agentName}function extractSwarmIdFromAgentName(agentName){if(!agentName)return;let match=agentName.match(/^([^_]+)_/);return match?match[1]:void 0}function getModelForAgent(agentName,swarmAgents,swarmPrefix,quiet){let baseAgentName=stripSwarmPrefix(agentName,swarmPrefix),explicit=swarmAgents?.[baseAgentName]?.model;if(explicit)return explicit;let resolvedModel=DEFAULT_MODELS[baseAgentName]??DEFAULT_MODELS.default;if(!warnedAgents.has(baseAgentName))if(warnedAgents.add(baseAgentName),!quiet)advisoryWarn(`[swarm] Agent '${baseAgentName}' not found in config — using default model '${resolvedModel}'. Add it to opencode-swarm.json to customize.`);else addDeferredWarning(`[swarm] Agent '${baseAgentName}' not found in config — using default model '${resolvedModel}'. Add it to opencode-swarm.json to customize.`);return resolvedModel}function resolveFallbackModel(agentBaseName,fallbackIndex,swarmAgents){let fallbackModels=swarmAgents?.[agentBaseName]?.fallback_models;if(fallbackModels===void 0&&(agentBaseName==="curator_init"||agentBaseName==="curator_phase"||agentBaseName==="curator_postmortem"))fallbackModels=swarmAgents?.explorer?.fallback_models;if(!fallbackModels||fallbackModels.length===0)return null;if(fallbackIndex<1||fallbackIndex>fallbackModels.length)return null;return fallbackModels[fallbackIndex-1]}function getSwarmAgents(swarmId){let id=swarmId??"default";return _swarmAgentsMap.get(id)}function isAgentDisabled(agentName,swarmAgents,swarmPrefix){let baseAgentName=stripSwarmPrefix(agentName,swarmPrefix);return swarmAgents?.[baseAgentName]?.disabled===!0}function getTemperatureOverride(agentName,swarmAgents,swarmPrefix){let baseAgentName=stripSwarmPrefix(agentName,swarmPrefix);return swarmAgents?.[baseAgentName]?.temperature}function getVariantOverride(agentName,swarmAgents,swarmPrefix){let baseAgentName=stripSwarmPrefix(agentName,swarmPrefix);return swarmAgents?.[baseAgentName]?.variant}function applyOverrides(agent,swarmAgents,swarmPrefix,quiet){let tempOverride=getTemperatureOverride(agent.name,swarmAgents,swarmPrefix);if(tempOverride!==void 0)agent.config.temperature=tempOverride;let variantOverride=getVariantOverride(agent.name,swarmAgents,swarmPrefix),modelSegments=agent.config.model?.split("/")??[],lastSegment=modelSegments[modelSegments.length-1]??"";if(modelSegments.length>=3&&KNOWN_VARIANT_VALUES.has(lastSegment)){let autoVariant=lastSegment,cleanedModel=modelSegments.slice(0,-1).join("/"),effectiveVariant=variantOverride??autoVariant;if(!quiet)advisoryWarn(`[swarm] Deprecation: model "${agent.config.model}" embeds variant. Use "model": "${cleanedModel}", "variant": "${effectiveVariant}" instead.`);else addDeferredWarning(`[swarm] Deprecation: model "${agent.config.model}" embeds variant. Use "model": "${cleanedModel}", "variant": "${effectiveVariant}" instead.`);agent.config.model=cleanedModel,agent.config.variant=effectiveVariant}else if(variantOverride!==void 0)agent.config.variant=variantOverride;let baseAgentName=stripSwarmPrefix(agent.name,swarmPrefix),reasoningOverride=swarmAgents?.[baseAgentName]?.reasoning;if(reasoningOverride!==void 0)agent.config.reasoning=reasoningOverride;let thinkingOverride=swarmAgents?.[baseAgentName]?.thinking;if(thinkingOverride!==void 0)agent.config.thinking=thinkingOverride;return agent}function createSwarmAgents(swarmId,swarmConfig,isDefault,pluginConfig,projectContext=emptyProjectContext()){let agents=[],swarmAgents=swarmConfig.agents;_swarmAgentsMap.set(swarmId,swarmAgents??{});let prefix=isDefault?"":`${swarmId}_`,swarmPrefix=isDefault?void 0:swarmId,qaRetryLimit=pluginConfig?.qa_retry_limit??3,quiet=pluginConfig?.quiet??!0,getModel=(baseName)=>getModelForAgent(baseName,swarmAgents,swarmPrefix,quiet),getPrompts=(name)=>loadAgentPrompt(name),prefixName=(name)=>`${prefix}${name}`;if(!isAgentDisabled("architect",swarmAgents,swarmPrefix)){let architectPrompts=getPrompts("architect"),architect=createArchitectAgent(getModel("architect"),architectPrompts.prompt,architectPrompts.appendPrompt,pluginConfig?.adversarial_testing,pluginConfig?.council,pluginConfig?.ui_review,pluginConfig?.memory?.enabled===!0,pluginConfig?.architectural_supervision,pluginConfig?.design_docs?.enabled===!0,pluginConfig?.external_skills?.curation_enabled===!0,pluginConfig?.turbo!==void 0,pluginConfig?.skills?.enabled===!0);architect.name=prefixName("architect");let swarmName=swarmConfig.name||swarmId,swarmIdentity=isDefault?"default":swarmId,agentPrefix=prefix;if(architect.config.prompt=architect.config.prompt?.replace(/\{\{SWARM_ID\}\}/g,swarmIdentity).replace(/\{\{AGENT_PREFIX\}\}/g,agentPrefix).replace(/\{\{QA_RETRY_LIMIT\}\}/g,String(qaRetryLimit)).replace(/\{\{PROJECT_LANGUAGE\}\}/g,projectContext.PROJECT_LANGUAGE).replace(/\{\{PROJECT_FRAMEWORK\}\}/g,projectContext.PROJECT_FRAMEWORK).replace(/\{\{BUILD_CMD\}\}/g,projectContext.BUILD_CMD).replace(/\{\{TEST_CMD\}\}/g,projectContext.TEST_CMD).replace(/\{\{LINT_CMD\}\}/g,projectContext.LINT_CMD).replace(/\{\{ENTRY_POINTS\}\}/g,projectContext.ENTRY_POINTS).replace(/\{\{CODER_CONSTRAINTS\}\}/g,projectContext.CODER_CONSTRAINTS).replace(/\{\{TEST_CONSTRAINTS\}\}/g,projectContext.TEST_CONSTRAINTS).replace(/\{\{REVIEWER_CHECKLIST\}\}/g,projectContext.REVIEWER_CHECKLIST).replace(/\{\{PROJECT_CONTEXT_SECONDARY_LANGUAGES\}\}/g,projectContext.PROJECT_CONTEXT_SECONDARY_LANGUAGES),!isDefault){architect.description=`[${swarmName}] ${architect.description}`;let swarmHeader=`## ⚠️ YOU ARE THE ${swarmName.toUpperCase()} SWARM ARCHITECT
5260
5260
 
5261
5261
  Your swarm ID is "${swarmId}". ALL your agents have the "${swarmId}_" prefix:
5262
5262
  - @${swarmId}_explorer (not @explorer)
@@ -5269,7 +5269,7 @@ Your swarm ID is "${swarmId}". ALL your agents have the "${swarmId}_" prefix:
5269
5269
  CRITICAL: Agents without the "${swarmId}_" prefix DO NOT EXIST or belong to a DIFFERENT swarm.
5270
5270
  If you call @coder instead of @${swarmId}_coder, the call will FAIL or go to the wrong swarm.
5271
5271
 
5272
- `;architect.config.prompt=swarmHeader+architect.config.prompt}agents.push(applyOverrides(architect,swarmAgents,swarmPrefix,quiet))}for(let{name,factory}of TYPE_A_AGENTS)if(!isAgentDisabled(name,swarmAgents,swarmPrefix)){let prompts=getPrompts(name),agent=factory(getModel(name),prompts.prompt,prompts.appendPrompt);agent.name=prefixName(name),agents.push(applyOverrides(agent,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic",swarmAgents,swarmPrefix)){let criticPrompts=getPrompts("critic"),critic=createCriticAgent(getModel("critic"),criticPrompts.prompt,criticPrompts.appendPrompt,"plan_critic");critic.name=prefixName("critic"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic_sounding_board",swarmAgents,swarmPrefix)){let critic=createCriticAgent(swarmAgents?.critic_sounding_board?.model??getModel("critic"),void 0,void 0,"sounding_board");critic.name=prefixName("critic_sounding_board"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic_drift_verifier",swarmAgents,swarmPrefix)){let critic=createCriticAgent(swarmAgents?.critic_drift_verifier?.model??getModel("critic"),void 0,void 0,"phase_drift_verifier");critic.name=prefixName("critic_drift_verifier"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic_hallucination_verifier",swarmAgents,swarmPrefix)){let critic=createCriticAgent(swarmAgents?.critic_hallucination_verifier?.model??getModel("critic"),void 0,void 0,"hallucination_verifier");critic.name=prefixName("critic_hallucination_verifier"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic_architecture_supervisor",swarmAgents,swarmPrefix)){let critic=createCriticAgent(swarmAgents?.critic_architecture_supervisor?.model??getModel("critic"),void 0,void 0,"architecture_supervisor");critic.name=prefixName("critic_architecture_supervisor"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic_oversight",swarmAgents,swarmPrefix)){let critic=createCriticAutonomousOversightAgent(swarmAgents?.critic_oversight?.model??getModel("critic"));critic.name=prefixName("critic_oversight"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("curator_init",swarmAgents,swarmPrefix)){let curatorInitPrompts=getPrompts("curator_init"),curatorInit=createCuratorAgent(swarmAgents?.curator_init?.model??getModel("explorer"),curatorInitPrompts.prompt,curatorInitPrompts.appendPrompt,"curator_init");curatorInit.name=prefixName("curator_init"),agents.push(applyOverrides(curatorInit,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("curator_phase",swarmAgents,swarmPrefix)){let curatorPhasePrompts=getPrompts("curator_phase"),curatorPhase=createCuratorAgent(swarmAgents?.curator_phase?.model??getModel("explorer"),curatorPhasePrompts.prompt,curatorPhasePrompts.appendPrompt,"curator_phase");curatorPhase.name=prefixName("curator_phase"),agents.push(applyOverrides(curatorPhase,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("curator_postmortem",swarmAgents,swarmPrefix)){let curatorPostmortemPrompts=getPrompts("curator_postmortem"),curatorPostmortem=createCuratorAgent(swarmAgents?.curator_postmortem?.model??getModel("explorer"),curatorPostmortemPrompts.prompt,curatorPostmortemPrompts.appendPrompt,"curator_postmortem");curatorPostmortem.name=prefixName("curator_postmortem"),agents.push(applyOverrides(curatorPostmortem,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("curator_consolidation",swarmAgents,swarmPrefix)){let curatorConsolidationPrompts=getPrompts("curator_consolidation"),curatorConsolidation=createCuratorAgent(swarmAgents?.curator_consolidation?.model??getModel("explorer"),curatorConsolidationPrompts.prompt,curatorConsolidationPrompts.appendPrompt,"curator_consolidation");curatorConsolidation.name=prefixName("curator_consolidation"),agents.push(applyOverrides(curatorConsolidation,swarmAgents,swarmPrefix,quiet))}if(pluginConfig?.council?.general?.enabled===!0){let councilAgentsCreated=0;if(!isAgentDisabled("reviewer",swarmAgents,swarmPrefix)){let councilGeneralist=createReviewerAgent(getModel("reviewer"),GENERALIST_COUNCIL_PROMPT);councilGeneralist.name=prefixName("council_generalist"),agents.push(applyOverrides(councilGeneralist,swarmAgents,swarmPrefix,quiet)),councilAgentsCreated++}if(!isAgentDisabled("critic",swarmAgents,swarmPrefix)){let councilSkeptic=createCriticAgent(getModel("critic"),SKEPTIC_COUNCIL_PROMPT);councilSkeptic.name=prefixName("council_skeptic"),agents.push(applyOverrides(councilSkeptic,swarmAgents,swarmPrefix,quiet)),councilAgentsCreated++}if(!isAgentDisabled("sme",swarmAgents,swarmPrefix)){let councilDomainExpert=createSMEAgent(getModel("sme"),DOMAIN_EXPERT_COUNCIL_PROMPT);councilDomainExpert.name=prefixName("council_domain_expert"),agents.push(applyOverrides(councilDomainExpert,swarmAgents,swarmPrefix,quiet)),councilAgentsCreated++}if(councilAgentsCreated<3){let missing=[];if(isAgentDisabled("reviewer",swarmAgents,swarmPrefix))missing.push("council_generalist (requires reviewer)");if(isAgentDisabled("critic",swarmAgents,swarmPrefix))missing.push("council_skeptic (requires critic)");if(isAgentDisabled("sme",swarmAgents,swarmPrefix))missing.push("council_domain_expert (requires sme)");addDeferredWarning(`[opencode-swarm] council.general.enabled is true but only ${councilAgentsCreated}/3 council agents could be registered because the following base agents are disabled: ${missing.join(", ")}. Re-enable those agents or accept a reduced council.`)}if(pluginConfig?.council?.general?.moderatorModel!==void 0)addDeferredWarning("[opencode-swarm] council.general.moderatorModel is deprecated and ignored. The architect now synthesizes the final answer directly using inline output rules. Remove this field (and council.general.moderator if set) from opencode-swarm.json to silence this warning.")}if(pluginConfig?.design_docs?.enabled===!0&&!isAgentDisabled("docs_design",swarmAgents,swarmPrefix)){let docsDesignPrompts=getPrompts("docs_design"),docsDesign=createDocsAgent(getModel("docs_design"),docsDesignPrompts.prompt,docsDesignPrompts.appendPrompt,"design_docs");docsDesign.name=prefixName("docs_design"),agents.push(applyOverrides(docsDesign,swarmAgents,swarmPrefix,quiet))}if(pluginConfig?.ui_review?.enabled===!0&&!isAgentDisabled("designer",swarmAgents,swarmPrefix)){let designerPrompts=getPrompts("designer"),designer=createDesignerAgent(getModel("designer"),designerPrompts.prompt,designerPrompts.appendPrompt);designer.name=prefixName("designer"),agents.push(applyOverrides(designer,swarmAgents,swarmPrefix,quiet))}for(let agent of agents)if(typeof agent.config.prompt==="string")try{assertNoUnresolvedPlaceholders(agent.config.prompt,agent.name)}catch(err){addDeferredWarning(`[opencode-swarm] ${err instanceof Error?err.message:String(err)} (agent "${agent.name}" was registered anyway; plugin init not aborted).`)}return agents}function createAgents(config3,projectContext=emptyProjectContext()){let allAgents=[],swarms=config3?.swarms;if(swarms&&Object.keys(swarms).length>0){_swarmAgentsMap.set("default",{});for(let swarmId of Object.keys(swarms)){let swarmConfig=swarms[swarmId],isDefault=swarmId==="default";if(config3?.agents)swarmConfig={...swarmConfig,agents:{...config3.agents,...swarmConfig.agents??{}}};let swarmAgents=createSwarmAgents(swarmId,swarmConfig,isDefault,config3,projectContext);allAgents.push(...swarmAgents)}}else{let legacySwarmConfig={name:"Default",agents:config3?.agents},swarmAgents=createSwarmAgents("default",legacySwarmConfig,!0,config3,projectContext);allAgents.push(...swarmAgents)}return allAgents}function resolvePrimaryAgentNames(agentNames,defaultAgent){let collectArchitectRole=()=>agentNames.filter((n)=>stripKnownSwarmPrefix(n)==="architect"),trimmed=typeof defaultAgent==="string"?defaultAgent.trim():void 0,value=trimmed===""?void 0:trimmed;if(agentNames.length===0)return{primaryNames:new Set,reason:"implicit-architects"};if(value===void 0){let architects2=collectArchitectRole();if(architects2.length>0)return{primaryNames:new Set(architects2),reason:"implicit-architects"};let first2=agentNames[0];return{primaryNames:new Set([first2]),reason:"fallback-first",warning:`[swarm] No architect-role agents are registered and default_agent is unset; falling back to '${first2}' as primary. Re-enable an architect agent or set default_agent to silence this warning.`}}if(ALL_AGENT_NAMES.includes(value)){let matching=agentNames.filter((n)=>stripKnownSwarmPrefix(n)===value);if(matching.length>0)return{primaryNames:new Set(matching),reason:"base-role"}}if(agentNames.includes(value))return{primaryNames:new Set([value]),reason:"exact"};let architects=collectArchitectRole();if(architects.length>0)return{primaryNames:new Set(architects),reason:"fallback-architects",warning:`[swarm] default_agent '${value}' did not match any registered agent; falling back to architect-role primaries: ${architects.join(", ")}.`};let first=agentNames[0];return{primaryNames:new Set([first]),reason:"fallback-first",warning:`[swarm] default_agent '${value}' did not match any registered agent and no architect-role agents are registered; falling back to '${first}' as primary.`}}function getAgentConfigs(config3,directory,sessionId,projectContext){let agents=createAgents(config3,projectContext??emptyProjectContext()),toolFilterEnabled=config3?.tool_filter?.enabled??!0,toolFilterOverrides=config3?.tool_filter?.overrides??{},quiet=config3?.quiet??!0,warnedMissingWhitelist=new Set,agentToolSnapshot={},resolution=resolvePrimaryAgentNames(agents.map((a)=>a.name),config3?.default_agent);if(resolution.warning)if(!quiet)console.warn(resolution.warning);else addDeferredWarning(resolution.warning);if(agents.length>0&&resolution.primaryNames.size===0){let generated=agents.map((a)=>a.name).join(", "),diagnostic=`[swarm] DIAGNOSTIC: ${agents.length} generated agents but zero primaries. Likely cause: a regression in resolvePrimaryAgentNames. Generated: ${generated}.`;if(!quiet)console.warn(diagnostic);else addDeferredWarning(diagnostic)}let result=Object.fromEntries(agents.map((agent)=>{let sdkConfig={...agent.config,description:agent.description};if(resolution.primaryNames.has(agent.name))sdkConfig.mode="primary",sdkConfig.permission={task:"allow"};else sdkConfig.mode="subagent";if(sdkConfig.mode==="primary")delete sdkConfig.model;let baseAgentName=stripKnownSwarmPrefix(agent.name);if(!toolFilterEnabled)return sdkConfig.tools=agent.config.tools??{},agentToolSnapshot[agent.name]=Object.keys(sdkConfig.tools??{}).filter((k)=>sdkConfig.tools[k]!==!1),[agent.name,sdkConfig];let allowedTools,override=toolFilterOverrides[baseAgentName];if(override!==void 0)allowedTools=override;else allowedTools=AGENT_TOOL_MAP[baseAgentName];if(config3?.memory?.enabled===!0){let memoryTools=MEMORY_AGENT_TOOL_MAP[baseAgentName]??[];if(memoryTools.length>0)allowedTools=Array.from(new Set([...allowedTools??[],...memoryTools]))}if(config3?.external_skills?.curation_enabled===!0){let externalSkillTools=EXTERNAL_SKILL_AGENT_TOOL_MAP[baseAgentName]??[];if(externalSkillTools.length>0)allowedTools=Array.from(new Set([...allowedTools??[],...externalSkillTools]))}if(config3?.council?.enabled===!0){let councilTools=COUNCIL_AGENT_TOOL_MAP[baseAgentName]??[];if(councilTools.length>0)allowedTools=Array.from(new Set([...allowedTools??[],...councilTools]))}if(config3?.council?.general?.enabled===!0){let generalCouncilTools=GENERAL_COUNCIL_AGENT_TOOL_MAP[baseAgentName]??[];if(generalCouncilTools.length>0)allowedTools=Array.from(new Set([...allowedTools??[],...generalCouncilTools]))}if(config3?.turbo!==void 0){let turboTools=TURBO_AGENT_TOOL_MAP[baseAgentName]??[];if(turboTools.length>0)allowedTools=Array.from(new Set([...allowedTools??[],...turboTools]))}{let skillTools=SKILL_AGENT_TOOL_MAP[baseAgentName]??[];if(skillTools.length>0&&allowedTools)if(config3?.skills?.enabled===!0)allowedTools=Array.from(new Set([...allowedTools,...skillTools]));else{let skillToolsSet=new Set(skillTools);allowedTools=allowedTools.filter((t)=>!skillToolsSet.has(t))}}if(baseAgentName==="architect"&&config3?.council?.enabled!==!0&&override!==void 0){let present=["declare_council_criteria","submit_council_verdicts","submit_phase_council_verdicts","write_final_council_evidence"].filter((t)=>override.includes(t));if(present.length>0&&!quiet)console.warn(`[opencode-swarm] tool_filter.overrides.architect includes ${present.join(", ")} but council.enabled is not true. The runtime gate will reject these calls. Either set council.enabled=true, or remove ${present.join(", ")} from the architect override.`)}if(!allowedTools&&!Object.hasOwn(toolFilterOverrides,baseAgentName)){if(!warnedMissingWhitelist.has(baseAgentName)&&!quiet)console.warn(`[getAgentConfigs] Unknown agent '${baseAgentName}', defaulting to minimal toolset.`),warnedMissingWhitelist.add(baseAgentName)}let originalTools=agent.config.tools?{...agent.config.tools}:void 0;if(allowedTools){let filteredTools={...Object.fromEntries(Object.entries(originalTools??{}).filter(([,value])=>value===!1))};for(let tool3 of allowedTools){if(filteredTools[tool3]===!1)continue;filteredTools[tool3]=!0}sdkConfig.tools=filteredTools}else sdkConfig.tools={write:!1,edit:!1};return agentToolSnapshot[agent.name]=Object.keys(sdkConfig.tools??{}).filter((k)=>sdkConfig.tools[k]!==!1),[agent.name,sdkConfig]}));if(directory){let sid=sessionId??`init-${Date.now()}`,evidenceDir=path146.join(directory,".swarm","evidence"),filename=`agent-tools-${sid}.json`,snapshotData=JSON.stringify({sessionId:sid,generatedAt:new Date().toISOString(),agents:agentToolSnapshot},null,2);mkdir29(evidenceDir,{recursive:!0}).then(()=>writeFile20(path146.join(evidenceDir,filename),snapshotData)).catch(()=>{})}return result}var warnedAgents,_swarmAgentsMap,KNOWN_VARIANT_VALUES,TYPE_A_AGENTS;var init_agents2=__esm(()=>{init_config();init_constants();init_schema();init_warning_buffer();init_architect();init_coder();init_council_prompts();init_critic();init_curator_agent();init_designer();init_docs();init_explorer();init_researcher();init_reviewer();init_skill_improver2();init_sme();init_spec_writer();init_test_engineer();init_architect();init_coder();init_council_prompts();init_critic();init_curator_agent();init_designer();init_docs();init_explorer();init_researcher();init_reviewer();init_sme();init_test_engineer();warnedAgents=new Set,_swarmAgentsMap=new Map;KNOWN_VARIANT_VALUES=new Set(["low","medium","high","max","xhigh","thinking"]);TYPE_A_AGENTS=[{name:"explorer",factory:createExplorerAgent},{name:"sme",factory:createSMEAgent},{name:"researcher",factory:createResearcherAgent},{name:"coder",factory:createCoderAgent},{name:"reviewer",factory:createReviewerAgent},{name:"test_engineer",factory:createTestEngineerAgent},{name:"docs",factory:createDocsAgent},{name:"skill_improver",factory:createSkillImproverAgent},{name:"spec_writer",factory:createSpecWriterAgent}]});var exports_evidence_summary_integration={};__export(exports_evidence_summary_integration,{createEvidenceSummaryIntegration:()=>createEvidenceSummaryIntegration,EvidenceSummaryIntegration:()=>EvidenceSummaryIntegration});import{existsSync as existsSync73,mkdirSync as mkdirSync38,writeFileSync as writeFileSync22}from"node:fs";import*as path147 from"node:path";function persistSummary(projectDir,artifact,filename){let swarmPath2=path147.join(projectDir,".swarm");if(!existsSync73(swarmPath2))mkdirSync38(swarmPath2,{recursive:!0});let artifactPath=path147.join(swarmPath2,filename),content=JSON.stringify(artifact,null,2);return writeFileSync22(artifactPath,content,"utf-8"),log("[EvidenceSummaryIntegration] Summary persisted",{path:artifactPath,size:content.length}),artifactPath}class EvidenceSummaryIntegration{config;eventBus;unsubscribes=[];constructor(config3){this.config=config3,this.eventBus=getGlobalEventBus()}isEnabled(){return isAutoSummaryEnabled(this.config.automationConfig)}initialize(){if(!this.isEnabled()){log("[EvidenceSummaryIntegration] Disabled via feature flags (evidence_auto_summaries=false or mode=manual)");return}log("[EvidenceSummaryIntegration] Initializing..."),this.subscribeToEvent("preflight.completed",async(event)=>{let phase=event.payload?.phase??1;await this.generateSummary(phase,"preflight.completed")}),this.subscribeToEvent("phase.boundary.detected",async(event)=>{let phase=event.payload?.currentPhase??1;await this.generateSummary(phase,"phase.boundary.detected")}),log("[EvidenceSummaryIntegration] Initialized and subscribed to events")}subscribeToEvent(type,handler){let unsubscribe2=this.eventBus.subscribe(type,handler);this.unsubscribes.push(unsubscribe2)}async generateSummary(phase,trigger){log("[EvidenceSummaryIntegration] Generating summary",{phase,trigger,directory:this.config.directory});try{let artifact=await buildEvidenceSummary(this.config.directory,phase);if(!artifact)return log("[EvidenceSummaryIntegration] No plan found, skipping"),null;let filename=this.config.summaryFilename??"evidence-summary.json",artifactPath=persistSummary(this.config.projectDir,artifact,filename);return log("[EvidenceSummaryIntegration] Summary generated and persisted",{path:artifactPath,completionRatio:artifact.overallCompletionRatio,blockers:artifact.overallBlockers.length}),await this.eventBus.publish("evidence.summary.generated",{trigger,phase,artifactPath,completionRatio:artifact.overallCompletionRatio,blockerCount:artifact.overallBlockers.length,timestamp:Date.now()}),artifact}catch(error93){return log("[EvidenceSummaryIntegration] Error generating summary",{error:error93 instanceof Error?error93.message:String(error93)}),await this.eventBus.publish("evidence.summary.error",{trigger,phase,error:error93 instanceof Error?error93.message:String(error93),timestamp:Date.now()}),null}}async triggerManual(phase){let isDisabled=!this.isEnabled();if(isDisabled)log("[EvidenceSummaryIntegration] Manual trigger with feature disabled - generating anyway for CLI use");return log("[EvidenceSummaryIntegration] Manual trigger",{phase,isDisabled}),this.generateSummary(phase??1,"preflight.completed")}cleanup(){for(let unsubscribe2 of this.unsubscribes)unsubscribe2();this.unsubscribes=[],log("[EvidenceSummaryIntegration] Cleanup complete")}}function createEvidenceSummaryIntegration(config3,autoInitialize=!0){let integration=new EvidenceSummaryIntegration(config3);if(autoInitialize)integration.initialize();return integration}var init_evidence_summary_integration=__esm(()=>{init_event_bus();init_evidence_summary_service();init_utils()});var exports_pr_event_delivery={};__export(exports_pr_event_delivery,{unregisterPrEventDelivery:()=>unregisterPrEventDelivery,registerPrEventDelivery:()=>registerPrEventDelivery,noteSessionIdle:()=>noteSessionIdle,isPrEventDeliveryRegistered:()=>isPrEventDeliveryRegistered,deliverPrActivity:()=>deliverPrActivity,buildWakeMessage:()=>buildWakeMessage,_internals:()=>_internals95,_getTrackedSessionCount:()=>_getTrackedSessionCount,_getSessionQueueStats:()=>_getSessionQueueStats,WAKE_PROMPT_TIMEOUT_MS:()=>WAKE_PROMPT_TIMEOUT_MS,MAX_TRACKED_SESSIONS:()=>MAX_TRACKED_SESSIONS,MAX_QUEUED_EVENTS_PER_SESSION:()=>MAX_QUEUED_EVENTS_PER_SESSION});function registerPrEventDelivery(options){registration=options,_internals95.log("[pr-monitor] Wake delivery registered",{directory:options.directory})}function unregisterPrEventDelivery(){registration=null,sessionStates2.clear()}function isPrEventDeliveryRegistered(){return registration!==null}function getSessionState2(sessionID){let state=sessionStates2.get(sessionID);if(!state){state={busy:!1,queue:[],droppedCount:0},sessionStates2.set(sessionID,state);while(sessionStates2.size>MAX_TRACKED_SESSIONS){let oldest=sessionStates2.keys().next().value;if(oldest===void 0)break;sessionStates2.delete(oldest)}}return state}function enqueueBounded(state,events){for(let event of events){state.queue.push(event);while(state.queue.length>MAX_QUEUED_EVENTS_PER_SESSION)state.queue.shift(),state.droppedCount+=1}}async function deliverPrActivity(sessionID,events){try{if(!registration||!sessionID||events.length===0)return!1;let state=getSessionState2(sessionID),fresh=events.filter((event)=>!state.queue.some((queued)=>queued.dedupToken===event.dedupToken));if(fresh.length===0)return!0;if(state.busy)return enqueueBounded(state,fresh),_internals95.log("[pr-monitor] Session busy — queued PR events",{sessionID,queued:state.queue.length,dropped:state.droppedCount}),!0;let previouslyQueued=state.queue.splice(0,state.queue.length),toSend=[...previouslyQueued,...fresh];if(state.busy=!0,!await _internals95.sendWakePrompt(sessionID,toSend)){let current=sessionStates2.get(sessionID);if(current){if(current.busy=!1,previouslyQueued.length>0)enqueueBounded(current,previouslyQueued)}return!1}return!0}catch(err){return _internals95.log("[pr-monitor] deliverPrActivity failed",{error:err instanceof Error?err.message:String(err)}),!1}}function noteSessionIdle(sessionID){try{if(!registration||!sessionID)return;let state=sessionStates2.get(sessionID);if(!state)return;if(state.busy=!1,state.queue.length===0)return;let toSend=state.queue.splice(0,state.queue.length);state.busy=!0,_internals95.sendWakePrompt(sessionID,toSend).then((ok)=>{if(ok)return;let current=sessionStates2.get(sessionID);if(current)current.busy=!1,enqueueBounded(current,toSend)}).catch(()=>{let current=sessionStates2.get(sessionID);if(current)current.busy=!1,enqueueBounded(current,toSend)})}catch(err){_internals95.log("[pr-monitor] noteSessionIdle failed",{error:err instanceof Error?err.message:String(err)})}}function sanitizeAttribute(value){return value.replace(/["<>\r\n]/g,"")}function sanitizeWakeBody(value){return value.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\[(MODE|SYSTEM|DEVELOPER|USER|ASSISTANT)\s*:/gi,"($1:")}function buildWakeMessage(events){let groups=new Map;for(let event of events){let key=`${event.repoFullName}#${event.prNumber}`,group=groups.get(key);if(group)group.push(event);else groups.set(key,[event])}let blocks=[];for(let[prKey,groupEvents]of groups){let types2=[...new Set(groupEvents.map((e)=>e.type))].join(","),url3=sanitizeAttribute(groupEvents[0]?.prUrl??""),lines=groupEvents.map((e)=>sanitizeWakeBody(e.message)).join(`
5272
+ `;architect.config.prompt=swarmHeader+architect.config.prompt}agents.push(applyOverrides(architect,swarmAgents,swarmPrefix,quiet))}for(let{name,factory}of TYPE_A_AGENTS)if(!isAgentDisabled(name,swarmAgents,swarmPrefix)){let prompts=getPrompts(name),agent=factory(getModel(name),prompts.prompt,prompts.appendPrompt);agent.name=prefixName(name),agents.push(applyOverrides(agent,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic",swarmAgents,swarmPrefix)){let criticPrompts=getPrompts("critic"),critic=createCriticAgent(getModel("critic"),criticPrompts.prompt,criticPrompts.appendPrompt,"plan_critic");critic.name=prefixName("critic"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic_sounding_board",swarmAgents,swarmPrefix)){let critic=createCriticAgent(swarmAgents?.critic_sounding_board?.model??getModel("critic"),void 0,void 0,"sounding_board");critic.name=prefixName("critic_sounding_board"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic_drift_verifier",swarmAgents,swarmPrefix)){let critic=createCriticAgent(swarmAgents?.critic_drift_verifier?.model??getModel("critic"),void 0,void 0,"phase_drift_verifier");critic.name=prefixName("critic_drift_verifier"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic_hallucination_verifier",swarmAgents,swarmPrefix)){let critic=createCriticAgent(swarmAgents?.critic_hallucination_verifier?.model??getModel("critic"),void 0,void 0,"hallucination_verifier");critic.name=prefixName("critic_hallucination_verifier"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic_architecture_supervisor",swarmAgents,swarmPrefix)){let critic=createCriticAgent(swarmAgents?.critic_architecture_supervisor?.model??getModel("critic"),void 0,void 0,"architecture_supervisor");critic.name=prefixName("critic_architecture_supervisor"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("critic_oversight",swarmAgents,swarmPrefix)){let critic=createCriticAutonomousOversightAgent(swarmAgents?.critic_oversight?.model??getModel("critic"));critic.name=prefixName("critic_oversight"),agents.push(applyOverrides(critic,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("curator_init",swarmAgents,swarmPrefix)){let curatorInitPrompts=getPrompts("curator_init"),curatorInit=createCuratorAgent(swarmAgents?.curator_init?.model??getModel("explorer"),curatorInitPrompts.prompt,curatorInitPrompts.appendPrompt,"curator_init");curatorInit.name=prefixName("curator_init"),agents.push(applyOverrides(curatorInit,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("curator_phase",swarmAgents,swarmPrefix)){let curatorPhasePrompts=getPrompts("curator_phase"),curatorPhase=createCuratorAgent(swarmAgents?.curator_phase?.model??getModel("explorer"),curatorPhasePrompts.prompt,curatorPhasePrompts.appendPrompt,"curator_phase");curatorPhase.name=prefixName("curator_phase"),agents.push(applyOverrides(curatorPhase,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("curator_postmortem",swarmAgents,swarmPrefix)){let curatorPostmortemPrompts=getPrompts("curator_postmortem"),curatorPostmortem=createCuratorAgent(swarmAgents?.curator_postmortem?.model??getModel("explorer"),curatorPostmortemPrompts.prompt,curatorPostmortemPrompts.appendPrompt,"curator_postmortem");curatorPostmortem.name=prefixName("curator_postmortem"),agents.push(applyOverrides(curatorPostmortem,swarmAgents,swarmPrefix,quiet))}if(!isAgentDisabled("curator_consolidation",swarmAgents,swarmPrefix)){let curatorConsolidationPrompts=getPrompts("curator_consolidation"),curatorConsolidation=createCuratorAgent(swarmAgents?.curator_consolidation?.model??getModel("explorer"),curatorConsolidationPrompts.prompt,curatorConsolidationPrompts.appendPrompt,"curator_consolidation");curatorConsolidation.name=prefixName("curator_consolidation"),agents.push(applyOverrides(curatorConsolidation,swarmAgents,swarmPrefix,quiet))}if(pluginConfig?.council?.general?.enabled===!0){let councilAgentsCreated=0;if(!isAgentDisabled("reviewer",swarmAgents,swarmPrefix)){let councilGeneralist=createReviewerAgent(getModel("reviewer"),GENERALIST_COUNCIL_PROMPT);councilGeneralist.name=prefixName("council_generalist"),agents.push(applyOverrides(councilGeneralist,swarmAgents,swarmPrefix,quiet)),councilAgentsCreated++}if(!isAgentDisabled("critic",swarmAgents,swarmPrefix)){let councilSkeptic=createCriticAgent(getModel("critic"),SKEPTIC_COUNCIL_PROMPT);councilSkeptic.name=prefixName("council_skeptic"),agents.push(applyOverrides(councilSkeptic,swarmAgents,swarmPrefix,quiet)),councilAgentsCreated++}if(!isAgentDisabled("sme",swarmAgents,swarmPrefix)){let councilDomainExpert=createSMEAgent(getModel("sme"),DOMAIN_EXPERT_COUNCIL_PROMPT);councilDomainExpert.name=prefixName("council_domain_expert"),agents.push(applyOverrides(councilDomainExpert,swarmAgents,swarmPrefix,quiet)),councilAgentsCreated++}if(councilAgentsCreated<3){let missing=[];if(isAgentDisabled("reviewer",swarmAgents,swarmPrefix))missing.push("council_generalist (requires reviewer)");if(isAgentDisabled("critic",swarmAgents,swarmPrefix))missing.push("council_skeptic (requires critic)");if(isAgentDisabled("sme",swarmAgents,swarmPrefix))missing.push("council_domain_expert (requires sme)");addDeferredWarning(`[opencode-swarm] council.general.enabled is true but only ${councilAgentsCreated}/3 council agents could be registered because the following base agents are disabled: ${missing.join(", ")}. Re-enable those agents or accept a reduced council.`)}if(pluginConfig?.council?.general?.moderatorModel!==void 0)addDeferredWarning("[opencode-swarm] council.general.moderatorModel is deprecated and ignored. The architect now synthesizes the final answer directly using inline output rules. Remove this field (and council.general.moderator if set) from opencode-swarm.json to silence this warning.")}if(pluginConfig?.design_docs?.enabled===!0&&!isAgentDisabled("docs_design",swarmAgents,swarmPrefix)){let docsDesignPrompts=getPrompts("docs_design"),docsDesign=createDocsAgent(getModel("docs_design"),docsDesignPrompts.prompt,docsDesignPrompts.appendPrompt,"design_docs");docsDesign.name=prefixName("docs_design"),agents.push(applyOverrides(docsDesign,swarmAgents,swarmPrefix,quiet))}if(pluginConfig?.ui_review?.enabled===!0&&!isAgentDisabled("designer",swarmAgents,swarmPrefix)){let designerPrompts=getPrompts("designer"),designer=createDesignerAgent(getModel("designer"),designerPrompts.prompt,designerPrompts.appendPrompt);designer.name=prefixName("designer"),agents.push(applyOverrides(designer,swarmAgents,swarmPrefix,quiet))}for(let agent of agents)if(typeof agent.config.prompt==="string")try{assertNoUnresolvedPlaceholders(agent.config.prompt,agent.name)}catch(err){addDeferredWarning(`[opencode-swarm] ${err instanceof Error?err.message:String(err)} (agent "${agent.name}" was registered anyway; plugin init not aborted).`)}return agents}function createAgents(config3,projectContext=emptyProjectContext()){let allAgents=[],swarms=config3?.swarms;if(swarms&&Object.keys(swarms).length>0){_swarmAgentsMap.set("default",{});for(let swarmId of Object.keys(swarms)){let swarmConfig=swarms[swarmId],isDefault=swarmId==="default";if(config3?.agents)swarmConfig={...swarmConfig,agents:{...config3.agents,...swarmConfig.agents??{}}};let swarmAgents=createSwarmAgents(swarmId,swarmConfig,isDefault,config3,projectContext);allAgents.push(...swarmAgents)}}else{let legacySwarmConfig={name:"Default",agents:config3?.agents},swarmAgents=createSwarmAgents("default",legacySwarmConfig,!0,config3,projectContext);allAgents.push(...swarmAgents)}return allAgents}function resolvePrimaryAgentNames(agentNames,defaultAgent){let collectArchitectRole=()=>agentNames.filter((n)=>stripKnownSwarmPrefix(n)==="architect"),trimmed=typeof defaultAgent==="string"?defaultAgent.trim():void 0,value=trimmed===""?void 0:trimmed;if(agentNames.length===0)return{primaryNames:new Set,reason:"implicit-architects"};if(value===void 0){let architects2=collectArchitectRole();if(architects2.length>0)return{primaryNames:new Set(architects2),reason:"implicit-architects"};let first2=agentNames[0];return{primaryNames:new Set([first2]),reason:"fallback-first",warning:`[swarm] No architect-role agents are registered and default_agent is unset; falling back to '${first2}' as primary. Re-enable an architect agent or set default_agent to silence this warning.`}}if(ALL_AGENT_NAMES.includes(value)){let matching=agentNames.filter((n)=>stripKnownSwarmPrefix(n)===value);if(matching.length>0)return{primaryNames:new Set(matching),reason:"base-role"}}if(agentNames.includes(value))return{primaryNames:new Set([value]),reason:"exact"};let architects=collectArchitectRole();if(architects.length>0)return{primaryNames:new Set(architects),reason:"fallback-architects",warning:`[swarm] default_agent '${value}' did not match any registered agent; falling back to architect-role primaries: ${architects.join(", ")}.`};let first=agentNames[0];return{primaryNames:new Set([first]),reason:"fallback-first",warning:`[swarm] default_agent '${value}' did not match any registered agent and no architect-role agents are registered; falling back to '${first}' as primary.`}}function getAgentConfigs(config3,directory,sessionId,projectContext){let agents=createAgents(config3,projectContext??emptyProjectContext()),toolFilterEnabled=config3?.tool_filter?.enabled??!0,toolFilterOverrides=config3?.tool_filter?.overrides??{},quiet=config3?.quiet??!0,warnedMissingWhitelist=new Set,agentToolSnapshot={},resolution=resolvePrimaryAgentNames(agents.map((a)=>a.name),config3?.default_agent);if(resolution.warning)if(!quiet)log(resolution.warning);else addDeferredWarning(resolution.warning);if(agents.length>0&&resolution.primaryNames.size===0){let generated=agents.map((a)=>a.name).join(", "),diagnostic=`[swarm] DIAGNOSTIC: ${agents.length} generated agents but zero primaries. Likely cause: a regression in resolvePrimaryAgentNames. Generated: ${generated}.`;if(!quiet)log(diagnostic);else addDeferredWarning(diagnostic)}let result=Object.fromEntries(agents.map((agent)=>{let sdkConfig={...agent.config,description:agent.description};if(resolution.primaryNames.has(agent.name))sdkConfig.mode="primary",sdkConfig.permission={task:"allow"};else sdkConfig.mode="subagent";if(sdkConfig.mode==="primary")delete sdkConfig.model;let baseAgentName=stripKnownSwarmPrefix(agent.name);if(!toolFilterEnabled)return sdkConfig.tools=agent.config.tools??{},agentToolSnapshot[agent.name]=Object.keys(sdkConfig.tools??{}).filter((k)=>sdkConfig.tools[k]!==!1),[agent.name,sdkConfig];let allowedTools,override=toolFilterOverrides[baseAgentName];if(override!==void 0)allowedTools=override;else allowedTools=AGENT_TOOL_MAP[baseAgentName];if(config3?.memory?.enabled===!0){let memoryTools=MEMORY_AGENT_TOOL_MAP[baseAgentName]??[];if(memoryTools.length>0)allowedTools=Array.from(new Set([...allowedTools??[],...memoryTools]))}if(config3?.external_skills?.curation_enabled===!0){let externalSkillTools=EXTERNAL_SKILL_AGENT_TOOL_MAP[baseAgentName]??[];if(externalSkillTools.length>0)allowedTools=Array.from(new Set([...allowedTools??[],...externalSkillTools]))}if(config3?.council?.enabled===!0){let councilTools=COUNCIL_AGENT_TOOL_MAP[baseAgentName]??[];if(councilTools.length>0)allowedTools=Array.from(new Set([...allowedTools??[],...councilTools]))}if(config3?.council?.general?.enabled===!0){let generalCouncilTools=GENERAL_COUNCIL_AGENT_TOOL_MAP[baseAgentName]??[];if(generalCouncilTools.length>0)allowedTools=Array.from(new Set([...allowedTools??[],...generalCouncilTools]))}if(config3?.turbo!==void 0){let turboTools=TURBO_AGENT_TOOL_MAP[baseAgentName]??[];if(turboTools.length>0)allowedTools=Array.from(new Set([...allowedTools??[],...turboTools]))}{let skillTools=SKILL_AGENT_TOOL_MAP[baseAgentName]??[];if(skillTools.length>0&&allowedTools)if(config3?.skills?.enabled===!0)allowedTools=Array.from(new Set([...allowedTools,...skillTools]));else{let skillToolsSet=new Set(skillTools);allowedTools=allowedTools.filter((t)=>!skillToolsSet.has(t))}}if(baseAgentName==="architect"&&config3?.council?.enabled!==!0&&override!==void 0){let present=["declare_council_criteria","submit_council_verdicts","submit_phase_council_verdicts","write_final_council_evidence"].filter((t)=>override.includes(t));if(present.length>0&&!quiet)advisoryWarn(`[opencode-swarm] tool_filter.overrides.architect includes ${present.join(", ")} but council.enabled is not true. The runtime gate will reject these calls. Either set council.enabled=true, or remove ${present.join(", ")} from the architect override.`)}if(!allowedTools&&!Object.hasOwn(toolFilterOverrides,baseAgentName)){if(!warnedMissingWhitelist.has(baseAgentName)&&!quiet)log(`[getAgentConfigs] Unknown agent '${baseAgentName}', defaulting to minimal toolset.`),warnedMissingWhitelist.add(baseAgentName)}let originalTools=agent.config.tools?{...agent.config.tools}:void 0;if(allowedTools){let filteredTools={...Object.fromEntries(Object.entries(originalTools??{}).filter(([,value])=>value===!1))};for(let tool3 of allowedTools){if(filteredTools[tool3]===!1)continue;filteredTools[tool3]=!0}sdkConfig.tools=filteredTools}else sdkConfig.tools={write:!1,edit:!1};return agentToolSnapshot[agent.name]=Object.keys(sdkConfig.tools??{}).filter((k)=>sdkConfig.tools[k]!==!1),[agent.name,sdkConfig]}));if(directory){let sid=sessionId??`init-${Date.now()}`,evidenceDir=path146.join(directory,".swarm","evidence"),filename=`agent-tools-${sid}.json`,snapshotData=JSON.stringify({sessionId:sid,generatedAt:new Date().toISOString(),agents:agentToolSnapshot},null,2);mkdir29(evidenceDir,{recursive:!0}).then(()=>writeFile20(path146.join(evidenceDir,filename),snapshotData)).catch(()=>{})}return result}var warnedAgents,_swarmAgentsMap,KNOWN_VARIANT_VALUES,TYPE_A_AGENTS;var init_agents2=__esm(()=>{init_config();init_constants();init_schema();init_warning_buffer();init_logger();init_architect();init_coder();init_council_prompts();init_critic();init_curator_agent();init_designer();init_docs();init_explorer();init_researcher();init_reviewer();init_skill_improver2();init_sme();init_spec_writer();init_test_engineer();init_architect();init_coder();init_council_prompts();init_critic();init_curator_agent();init_designer();init_docs();init_explorer();init_researcher();init_reviewer();init_sme();init_test_engineer();warnedAgents=new Set,_swarmAgentsMap=new Map;KNOWN_VARIANT_VALUES=new Set(["low","medium","high","max","xhigh","thinking"]);TYPE_A_AGENTS=[{name:"explorer",factory:createExplorerAgent},{name:"sme",factory:createSMEAgent},{name:"researcher",factory:createResearcherAgent},{name:"coder",factory:createCoderAgent},{name:"reviewer",factory:createReviewerAgent},{name:"test_engineer",factory:createTestEngineerAgent},{name:"docs",factory:createDocsAgent},{name:"skill_improver",factory:createSkillImproverAgent},{name:"spec_writer",factory:createSpecWriterAgent}]});var exports_evidence_summary_integration={};__export(exports_evidence_summary_integration,{createEvidenceSummaryIntegration:()=>createEvidenceSummaryIntegration,EvidenceSummaryIntegration:()=>EvidenceSummaryIntegration});import{existsSync as existsSync73,mkdirSync as mkdirSync38,writeFileSync as writeFileSync22}from"node:fs";import*as path147 from"node:path";function persistSummary(projectDir,artifact,filename){let swarmPath2=path147.join(projectDir,".swarm");if(!existsSync73(swarmPath2))mkdirSync38(swarmPath2,{recursive:!0});let artifactPath=path147.join(swarmPath2,filename),content=JSON.stringify(artifact,null,2);return writeFileSync22(artifactPath,content,"utf-8"),log("[EvidenceSummaryIntegration] Summary persisted",{path:artifactPath,size:content.length}),artifactPath}class EvidenceSummaryIntegration{config;eventBus;unsubscribes=[];constructor(config3){this.config=config3,this.eventBus=getGlobalEventBus()}isEnabled(){return isAutoSummaryEnabled(this.config.automationConfig)}initialize(){if(!this.isEnabled()){log("[EvidenceSummaryIntegration] Disabled via feature flags (evidence_auto_summaries=false or mode=manual)");return}log("[EvidenceSummaryIntegration] Initializing..."),this.subscribeToEvent("preflight.completed",async(event)=>{let phase=event.payload?.phase??1;await this.generateSummary(phase,"preflight.completed")}),this.subscribeToEvent("phase.boundary.detected",async(event)=>{let phase=event.payload?.currentPhase??1;await this.generateSummary(phase,"phase.boundary.detected")}),log("[EvidenceSummaryIntegration] Initialized and subscribed to events")}subscribeToEvent(type,handler){let unsubscribe2=this.eventBus.subscribe(type,handler);this.unsubscribes.push(unsubscribe2)}async generateSummary(phase,trigger){log("[EvidenceSummaryIntegration] Generating summary",{phase,trigger,directory:this.config.directory});try{let artifact=await buildEvidenceSummary(this.config.directory,phase);if(!artifact)return log("[EvidenceSummaryIntegration] No plan found, skipping"),null;let filename=this.config.summaryFilename??"evidence-summary.json",artifactPath=persistSummary(this.config.projectDir,artifact,filename);return log("[EvidenceSummaryIntegration] Summary generated and persisted",{path:artifactPath,completionRatio:artifact.overallCompletionRatio,blockers:artifact.overallBlockers.length}),await this.eventBus.publish("evidence.summary.generated",{trigger,phase,artifactPath,completionRatio:artifact.overallCompletionRatio,blockerCount:artifact.overallBlockers.length,timestamp:Date.now()}),artifact}catch(error93){return log("[EvidenceSummaryIntegration] Error generating summary",{error:error93 instanceof Error?error93.message:String(error93)}),await this.eventBus.publish("evidence.summary.error",{trigger,phase,error:error93 instanceof Error?error93.message:String(error93),timestamp:Date.now()}),null}}async triggerManual(phase){let isDisabled=!this.isEnabled();if(isDisabled)log("[EvidenceSummaryIntegration] Manual trigger with feature disabled - generating anyway for CLI use");return log("[EvidenceSummaryIntegration] Manual trigger",{phase,isDisabled}),this.generateSummary(phase??1,"preflight.completed")}cleanup(){for(let unsubscribe2 of this.unsubscribes)unsubscribe2();this.unsubscribes=[],log("[EvidenceSummaryIntegration] Cleanup complete")}}function createEvidenceSummaryIntegration(config3,autoInitialize=!0){let integration=new EvidenceSummaryIntegration(config3);if(autoInitialize)integration.initialize();return integration}var init_evidence_summary_integration=__esm(()=>{init_event_bus();init_evidence_summary_service();init_utils()});var exports_pr_event_delivery={};__export(exports_pr_event_delivery,{unregisterPrEventDelivery:()=>unregisterPrEventDelivery,registerPrEventDelivery:()=>registerPrEventDelivery,noteSessionIdle:()=>noteSessionIdle,isPrEventDeliveryRegistered:()=>isPrEventDeliveryRegistered,deliverPrActivity:()=>deliverPrActivity,buildWakeMessage:()=>buildWakeMessage,_internals:()=>_internals95,_getTrackedSessionCount:()=>_getTrackedSessionCount,_getSessionQueueStats:()=>_getSessionQueueStats,WAKE_PROMPT_TIMEOUT_MS:()=>WAKE_PROMPT_TIMEOUT_MS,MAX_TRACKED_SESSIONS:()=>MAX_TRACKED_SESSIONS,MAX_QUEUED_EVENTS_PER_SESSION:()=>MAX_QUEUED_EVENTS_PER_SESSION});function registerPrEventDelivery(options){registration=options,_internals95.log("[pr-monitor] Wake delivery registered",{directory:options.directory})}function unregisterPrEventDelivery(){registration=null,sessionStates2.clear()}function isPrEventDeliveryRegistered(){return registration!==null}function getSessionState2(sessionID){let state=sessionStates2.get(sessionID);if(!state){state={busy:!1,queue:[],droppedCount:0},sessionStates2.set(sessionID,state);while(sessionStates2.size>MAX_TRACKED_SESSIONS){let oldest=sessionStates2.keys().next().value;if(oldest===void 0)break;sessionStates2.delete(oldest)}}return state}function enqueueBounded(state,events){for(let event of events){state.queue.push(event);while(state.queue.length>MAX_QUEUED_EVENTS_PER_SESSION)state.queue.shift(),state.droppedCount+=1}}async function deliverPrActivity(sessionID,events){try{if(!registration||!sessionID||events.length===0)return!1;let state=getSessionState2(sessionID),fresh=events.filter((event)=>!state.queue.some((queued)=>queued.dedupToken===event.dedupToken));if(fresh.length===0)return!0;if(state.busy)return enqueueBounded(state,fresh),_internals95.log("[pr-monitor] Session busy — queued PR events",{sessionID,queued:state.queue.length,dropped:state.droppedCount}),!0;let previouslyQueued=state.queue.splice(0,state.queue.length),toSend=[...previouslyQueued,...fresh];if(state.busy=!0,!await _internals95.sendWakePrompt(sessionID,toSend)){let current=sessionStates2.get(sessionID);if(current){if(current.busy=!1,previouslyQueued.length>0)enqueueBounded(current,previouslyQueued)}return!1}return!0}catch(err){return _internals95.log("[pr-monitor] deliverPrActivity failed",{error:err instanceof Error?err.message:String(err)}),!1}}function noteSessionIdle(sessionID){try{if(!registration||!sessionID)return;let state=sessionStates2.get(sessionID);if(!state)return;if(state.busy=!1,state.queue.length===0)return;let toSend=state.queue.splice(0,state.queue.length);state.busy=!0,_internals95.sendWakePrompt(sessionID,toSend).then((ok)=>{if(ok)return;let current=sessionStates2.get(sessionID);if(current)current.busy=!1,enqueueBounded(current,toSend)}).catch(()=>{let current=sessionStates2.get(sessionID);if(current)current.busy=!1,enqueueBounded(current,toSend)})}catch(err){_internals95.log("[pr-monitor] noteSessionIdle failed",{error:err instanceof Error?err.message:String(err)})}}function sanitizeAttribute(value){return value.replace(/["<>\r\n]/g,"")}function sanitizeWakeBody(value){return value.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\[(MODE|SYSTEM|DEVELOPER|USER|ASSISTANT)\s*:/gi,"($1:")}function buildWakeMessage(events){let groups=new Map;for(let event of events){let key=`${event.repoFullName}#${event.prNumber}`,group=groups.get(key);if(group)group.push(event);else groups.set(key,[event])}let blocks=[];for(let[prKey,groupEvents]of groups){let types2=[...new Set(groupEvents.map((e)=>e.type))].join(","),url3=sanitizeAttribute(groupEvents[0]?.prUrl??""),lines=groupEvents.map((e)=>sanitizeWakeBody(e.message)).join(`
5273
5273
  `);blocks.push([`<pr-activity pr="${sanitizeAttribute(prKey)}" url="${url3}" events="${sanitizeAttribute(types2)}">`,lines,"</pr-activity>"].join(`
5274
5274
  `))}return`${blocks.join(`
5275
5275
 
@@ -6007,8 +6007,8 @@ Use these as DOMAIN values when delegating to @sme.`}});init_zod();init_config()
6007
6007
 
6008
6008
  Missing scopes: ${list}
6009
6009
 
6010
- Resolution: call \`declare_scope\` once for EACH of those task ids with the exact file paths the task will touch. Then re-invoke \`epic_plan_waves(phase=${phase})\`.`]}}let isUpstreamCommitted;if(_internals126.isGitRepo(directory)){let evidence=_internals126.buildIsUpstreamCommittedWithStatus(directory);if(evidence.gitFailed)return criticalWarn(`[epic_plan_waves] wave-planning blocked for directory=${directory} phase=${phase}: git log scan failed. Any prior promote verdict in .swarm/evidence/epic-promotions.jsonl for this phase is not backed by actual parallel execution.`),{success:!1,reason:"git-failed",errors:["epic_plan_waves: cannot verify cross-batch upstream-commit evidence — `git log` read failed. "+"Likely transient: retry once git is healthy (e.g. another process released its lock). If git is persistently broken (corrupt repo, permission issue, missing `.git`), repair the repository. "+"Until repaired, complete the phase serially — one task at a time, waiting for each commit to land before dispatching the next — so file-scope conflict detection is not required."]};isUpstreamCommitted=evidence.predicate}let leanConfig={...DEFAULT_LEAN_TURBO_CONFIG};try{let userLean=(await _internals126.loadPluginConfigWithMeta(directory))?.config?.turbo?.lean;if(userLean)leanConfig={...leanConfig,...userLean}}catch{}let wavePlan=planEpicWaves(directory,phase,plan,leanConfig,scopes,isUpstreamCommitted);return{success:!0,plan:wavePlan,waves:wavePlan.waves,serializedTasks:wavePlan.serializedTasks,degradedTasks:wavePlan.degradedTasks}}catch(error93){let errMsg=error93 instanceof Error?error93.message:String(error93);return criticalWarn(`[epic_plan_waves] wave-planning failed for directory=${directory} phase=${phase}: ${errMsg}. Any prior promote verdict in .swarm/evidence/epic-promotions.jsonl for this phase is not backed by actual parallel execution.`),{success:!1,reason:"planner-error",errors:[errMsg]}}}var _internals126={readPlanJson,readTaskScopes,isGitRepo:(cwd)=>isGitRepo(cwd),buildIsUpstreamCommittedWithStatus,loadPluginConfigWithMeta},epic_plan_waves=createSwarmTool({description:"Partition a phase's pending tasks into ordered concurrent waves for Epic Mode dispatch. A wave is a set of tasks with mutually disjoint declared scopes and all dependencies satisfied by prior waves. Returns `{ waves: [{ waveId, taskIds, files }, ...], serializedTasks, degradedTasks }`. "+'For each wave in order, the architect dispatches one `Task(subagent_type="coder", ...)` per `taskId` — all in one assistant message — so the wave runs concurrently and each coder appears as a visible subagent. '+"Wait for the wave to finish before dispatching the next. Pair with `epic_decide_phase` (called first; this tool is only relevant on a `promote` verdict). "+"Preflight reject reasons: `no-plan`, `no-phase`, `phase-empty`, `phase-already-complete`, `scopes-missing` (call `declare_scope` for `missingScopes`), `git-failed` (transient — retry), `planner-error`.",args:{directory:exports_external.string().describe("Project root directory where `.swarm/plan.json` is located"),phase:exports_external.number().int().positive().describe("Phase number to plan"),scopes:exports_external.record(exports_external.string(),exports_external.array(exports_external.string())).optional().describe("Optional pre-loaded scopes map (taskId -> file paths). When omitted, scopes are read from `.swarm/scopes/scope-<taskId>.json` and `files_touched` in plan.json.")},execute:async(args2,_directory)=>{let result=await executeEpicPlanWaves({...args2,directory:_directory});return JSON.stringify(result,null,2)}});init_zod();init_manager();init_scope_persistence();init_state2();init_divergence_recorder();init_logger();init_create_tool();var _internals127={hasActiveEpicMode,getAgentSession,readScopeFromDisk,loadPlanJsonOnly,recordTaskDivergence};async function findPhaseForTask(directory,taskId){try{let plan=await _internals127.loadPlanJsonOnly(directory);if(!plan)return;for(let phase of plan.phases)if(phase.tasks.some((t)=>t.id===taskId))return phase.id}catch{}return}async function executeEpicRecordDivergence(args2){let{directory,taskId,sessionID}=args2;if(!_internals127.hasActiveEpicMode(sessionID))return{success:!0,reason:"epic-mode-not-active"};let session=_internals127.getAgentSession(sessionID);if(!session)return{success:!0,reason:"no-session"};let declaredScope=_internals127.readScopeFromDisk(directory,taskId);if(declaredScope===null)return{success:!0,reason:"no-scope"};let actualFiles=session.modifiedFilesThisCoderTask??[],phaseNumber=await findPhaseForTask(directory,taskId),result=_internals127.recordTaskDivergence({directory,sessionID,taskId,phaseNumber,declaredScope,actualFiles});if(!result)return warn(`[epic_record_divergence] persist failed for ${taskId}; calibration will miss one observation`),{success:!0,reason:"persist-failed"};let{record:record3}=result;return{success:!0,reason:"recorded",summary:{declaredCount:record3.declaredScope.length,actualCount:record3.actualFiles.length,undeclaredCount:record3.undeclared.length,unusedCount:record3.unused.length,divergenceRatio:record3.divergenceRatio,isClean:record3.isClean}}}var epic_record_divergence=createSwarmTool({description:`Record divergence between a completed task's declared scope and the files actually modified, for Epic Mode calibration (Capability D). Call this immediately after update_task_status sets status="completed". Appends one line to .swarm/epic/divergence.jsonl. Best-effort — never fails the calling agent. Use only when /swarm epic is on for the session.`,args:{directory:exports_external.string().describe("Project root directory"),taskId:exports_external.string().describe("Task id whose divergence should be recorded"),sessionID:exports_external.string().describe("Active session ID")},execute:async(args2,_directory,ctx)=>{let{taskId,sessionID:argSessionID}=args2,sessionID=ctx?.sessionID&&ctx.sessionID.length>0?ctx.sessionID:argSessionID;return JSON.stringify(await executeEpicRecordDivergence({directory:_directory,taskId,sessionID}),null,2)}});init_zod();init_config();init_branch();init_manager();init_state2();init_activation();init_calibration();init_conflicts();var DEFAULT_FLOOR=0.05,DEFAULT_TIGHTEN_STEP=0.02,DEFAULT_LOOSEN_STEP=0.01,DEFAULT_LOOSEN_WINDOW=10;function applyCalibration(state,newRecords,options){let floor=options.floorThreshold??DEFAULT_FLOOR,tightenStep=options.tightenStep??DEFAULT_TIGHTEN_STEP,loosenStep=options.loosenStep??DEFAULT_LOOSEN_STEP,loosenWindow=options.loosenWindow??DEFAULT_LOOSEN_WINDOW,effectiveThreshold=state.activationThresholdOverride??options.staticThreshold,consecutiveCleanCount=state.consecutiveCleanCount,hotSet=new Set(state.hotModuleAdditions);for(let record3 of newRecords)if(record3.isClean){if(consecutiveCleanCount+=1,consecutiveCleanCount>=loosenWindow)effectiveThreshold=Math.min(options.staticThreshold,effectiveThreshold+loosenStep),consecutiveCleanCount=0}else{consecutiveCleanCount=0,effectiveThreshold=Math.max(floor,effectiveThreshold-tightenStep);for(let undeclaredFile of record3.undeclared)hotSet.add(normalizePath(undeclaredFile))}let newOverride=effectiveThreshold===options.staticThreshold?void 0:effectiveThreshold;return{version:1,updatedAt:state.updatedAt,activationThresholdOverride:newOverride,hotModuleAdditions:Array.from(hotSet).sort(),consecutiveCleanCount,lastCalibrationAt:newRecords.length>0?new Date().toISOString():state.lastCalibrationAt,processedRecords:state.processedRecords+newRecords.length}}function effectiveActivationThreshold(staticThreshold,state){if(!state||state.activationThresholdOverride===void 0)return staticThreshold;return Math.max(0,Math.min(staticThreshold,state.activationThresholdOverride))}function effectiveHotModules(staticHotModules,state){if(!state||state.hotModuleAdditions.length===0)return Array.from(staticHotModules);return Array.from(new Set([...staticHotModules,...state.hotModuleAdditions]))}init_cochange_source();init_divergence_recorder();init_promotion_evidence();init_state();init_conflicts();init_constants();init_state3();init_file_locks();init_manager();init_utils3();init_state2();init_merge();function getMergeStrategy2(config3){return getMergeStrategy({merge_strategy:config3.merge_strategy})}init_conflicts();init_conflicts();function planLeanTurboLanes(directory,phaseNumber,plan,config3,scopes,isUpstreamCommitted){let phase=plan.phases.find((p)=>p.id===phaseNumber);if(!phase)return createEmptyPlan2(phaseNumber,"");let pendingTasks=phase.tasks.filter((t)=>t.status!=="completed");if(pendingTasks.length===0)return createEmptyPlan2(phaseNumber,"");let{sortedTasks,taskMap,tasksInCycle}=runPartitionPreflight(directory,pendingTasks,config3,scopes),lanes=[],serializedTasks=[],degradedTasks=[],maxLanes=config3.max_parallel_coders,claimedFiles=new Set,assignedTasks=new Set,taskToLane=new Map,crossLaneDependencies={};for(let taskId of tasksInCycle)serializedTasks.push(taskId),assignedTasks.add(taskId),taskToLane.set(taskId,-1);let isSatisfied=makeDependencySatisfactionChecker(taskMap,assignedTasks,isUpstreamCommitted);while(!0){let readyTasks=getReadyTasks(sortedTasks,assignedTasks,isSatisfied);if(readyTasks.length===0)break;for(let classified of readyTasks){if(assignedTasks.has(classified.task.id))continue;if(classified.category==="global"){degradedTasks.push({taskId:classified.task.id,reason:"global file conflict",files:classified.files,requiredMode:"balanced"}),assignedTasks.add(classified.task.id);continue}if(classified.category==="protected"){if(config3.degrade_on_risk)degradedTasks.push({taskId:classified.task.id,reason:"protected path",files:classified.files,requiredMode:"balanced"});else serializedTasks.push(classified.task.id),taskToLane.set(classified.task.id,-1);assignedTasks.add(classified.task.id);continue}if(classified.category==="no-scope"||classified.category==="invalid-scope"){serializedTasks.push(classified.task.id),taskToLane.set(classified.task.id,-1),assignedTasks.add(classified.task.id);continue}if(classified.files.some((file3)=>claimedFiles.has(file3))){if(config3.conflict_policy==="degrade")degradedTasks.push({taskId:classified.task.id,reason:"file conflict with parallel task",files:classified.files,requiredMode:"balanced"});else serializedTasks.push(classified.task.id),taskToLane.set(classified.task.id,-1);assignedTasks.add(classified.task.id);continue}let hasParentChildConflict=!1;for(let file3 of classified.files){for(let claimed of Array.from(claimedFiles))if(pathsConflict(file3,claimed)){hasParentChildConflict=!0;break}if(hasParentChildConflict)break}if(hasParentChildConflict){if(config3.conflict_policy==="degrade")degradedTasks.push({taskId:classified.task.id,reason:"file conflict with parallel task",files:classified.files,requiredMode:"balanced"});else serializedTasks.push(classified.task.id),taskToLane.set(classified.task.id,-1);assignedTasks.add(classified.task.id);continue}let candidateLaneIndex=-1;for(let i=0;i<lanes.length;i++)if(!lanes[i].files.some((laneFile)=>classified.files.some((taskFile)=>pathsConflict(laneFile,taskFile)))){candidateLaneIndex=i;break}if(candidateLaneIndex===-1&&lanes.length<maxLanes)candidateLaneIndex=lanes.length;if(candidateLaneIndex!==-1){let depsInOtherLanes=[],deps=classified.task.depends??[];for(let dep of deps){if(!taskMap.has(dep))continue;let depLane=taskToLane.get(dep);if(depLane!==void 0&&depLane!==-1&&depLane!==candidateLaneIndex)depsInOtherLanes.push(dep)}if(depsInOtherLanes.length>0){serializedTasks.push(classified.task.id),assignedTasks.add(classified.task.id),taskToLane.set(classified.task.id,-1),crossLaneDependencies[classified.task.id]=depsInOtherLanes;continue}if(candidateLaneIndex<lanes.length){let lane=lanes[candidateLaneIndex];lane.taskIds.push(classified.task.id),lane.files.push(...classified.files),assignedTasks.add(classified.task.id),taskToLane.set(classified.task.id,candidateLaneIndex)}else lanes.push({laneId:`lane-${lanes.length+1}`,taskIds:[classified.task.id],files:[...classified.files],status:"pending"}),assignedTasks.add(classified.task.id),taskToLane.set(classified.task.id,lanes.length-1);for(let file3 of classified.files)claimedFiles.add(file3)}else serializedTasks.push(classified.task.id),assignedTasks.add(classified.task.id),taskToLane.set(classified.task.id,-1)}}if(isUpstreamCommitted)for(let classified of sortedTasks){if(assignedTasks.has(classified.task.id))continue;let deps=classified.task.depends??[],uncommittedCrossBatch=[],unassignedInBatch=[];for(let dep of deps)if(taskMap.has(dep)){if(!assignedTasks.has(dep))unassignedInBatch.push(dep)}else if(!isUpstreamCommitted(dep))uncommittedCrossBatch.push(dep);let reason;if(uncommittedCrossBatch.length>0){let sample=uncommittedCrossBatch.slice(0,3).join(", "),more=uncommittedCrossBatch.length>3?`, +${uncommittedCrossBatch.length-3} more`:"";reason=`cross-batch upstream not committed (greenfield-smart Rule 3): ${sample}${more}`}else if(unassignedInBatch.length>0){let sample=unassignedInBatch.slice(0,3).join(", "),more=unassignedInBatch.length>3?`, +${unassignedInBatch.length-3} more`:"";reason=`unresolved in-batch dependency: ${sample}${more}`}else reason="planning leftover (no identifiable blocker)";degradedTasks.push({taskId:classified.task.id,reason,files:classified.files,requiredMode:"balanced"}),assignedTasks.add(classified.task.id),taskToLane.set(classified.task.id,-1)}let degradationSummary;if(degradedTasks.length>0&&degradedTasks.length+serializedTasks.length===pendingTasks.length){let reasons=Array.from(new Set(degradedTasks.map((t)=>t.reason))),rule3Count=degradedTasks.filter((t)=>t.reason.includes("greenfield-smart Rule 3")).length;if(rule3Count>0&&rule3Count>=degradedTasks.length/2)degradationSummary=`All ${pendingTasks.length} tasks degraded. ${rule3Count} blocked by greenfield-smart Rule 3 — cross-batch upstream(s) not in git history. Remediation: verify Epic Mode commit-on-completion is succeeding for upstream phases, or commit those tasks manually before re-running.`;else degradationSummary=`All ${pendingTasks.length} tasks degraded. Reasons: ${reasons.join(", ")}. Consider running in standard (serial) mode.`}let counters={lanesPlanned:lanes.length,lanesStarted:0,lanesCompleted:0,lanesFailed:0,tasksSerialized:serializedTasks.length,tasksDegraded:degradedTasks.length},planId=`plan-${phaseNumber}-${Date.now()}`;return{phase:phaseNumber,planId,lanes,degradedTasks,serializedTasks,degradationSummary,counters,crossLaneDependencies}}function createEmptyPlan2(phaseNumber,planId){return{phase:phaseNumber,planId,lanes:[],degradedTasks:[],serializedTasks:[],counters:{lanesPlanned:0,lanesStarted:0,lanesCompleted:0,lanesFailed:0,tasksSerialized:0,tasksDegraded:0},crossLaneDependencies:{}}}init_state4();init_file_locks();var _internals128={tryAcquireLock};class TurboStateLockTimeoutError extends Error{directory;sessionID;constructor(directory,sessionID,timeoutMs){super(`Turbo state lock timeout after ${timeoutMs}ms for session ${sessionID}`);this.name="TurboStateLockTimeoutError",this.directory=directory,this.sessionID=sessionID}}var BACKOFF_START_MS2=50,BACKOFF_MAX_MS2=2000,BACKOFF_JITTER_RATIO2=0.25;function backoffMs2(attempt){let base=Math.min(BACKOFF_START_MS2*2**attempt,BACKOFF_MAX_MS2),jitter=base*BACKOFF_JITTER_RATIO2*(Math.random()*2-1);return Math.max(1,Math.round(base+jitter))}async function withTurboStateLock(directory,sessionID,fn2,timeoutMs=30000){let deadline=Date.now()+timeoutMs,attempt=0;while(!0){let result;try{result=await _internals128.tryAcquireLock(directory,".swarm/turbo-state.json","lean-turbo-runner",sessionID)}catch(acquireErr){console.warn(`[lean-turbo] state lock acquisition error for ${sessionID} (.swarm/turbo-state.json), will retry: ${acquireErr instanceof Error?acquireErr.message:String(acquireErr)}`)}if(result?.acquired){let lock=result.lock;try{return await fn2()}finally{if(lock._release)try{await lock._release()}catch(releaseErr){console.warn(`[lean-turbo] state lock release failed for ${sessionID} (.swarm/turbo-state.json): ${releaseErr instanceof Error?releaseErr.message:String(releaseErr)}`)}}}if(Date.now()>=deadline)throw new TurboStateLockTimeoutError(directory,sessionID,timeoutMs);let delay=Math.min(backoffMs2(attempt),deadline-Date.now());if(delay>0)await new Promise((resolve75)=>setTimeout(resolve75,delay));attempt++}}init_worktree_isolation();init_core3();import*as path203 from"node:path";function computeLaneRuntimeProfile2(runtime,laneIndex,worktreePath){if(!runtime?.enabled)return;let portStride=runtime.port_stride??1,envOverrides={};if(runtime.port_base!==void 0){let portBase=runtime.port_base,port=Math.min(portBase+laneIndex*portStride,65535);envOverrides.PORT=String(port)}if(runtime.env_overrides)Object.assign(envOverrides,runtime.env_overrides);if(runtime.cache_redirects)for(let[envName,basePath]of Object.entries(runtime.cache_redirects))envOverrides[envName]=path203.join(basePath,`lane-${laneIndex}`);return{laneIndex,worktreePath,envOverrides}}async function provisionWorktree2(directory,laneId,sessionId,config3,scope){let laneIndex=parseLeanLaneIndex(laneId),result=await provisionWorktree(directory,laneId,sessionId,{purpose:"lane",branchStyle:"legacy-lane",worktreeDir:config3.worktree_dir,mergeStrategy:config3.merge_strategy,depsStrategy:config3.deps_strategy,scope});if("error"in result)return result;let laneProfile=computeLaneRuntimeProfile2(config3.runtime_isolation,laneIndex,result.worktreePath);if(laneProfile)try{let{writeLaneProfileToDiskReal:writeLaneProfileToDiskReal2}=await Promise.resolve().then(() => (init_core3(),exports_core3));await writeLaneProfileToDiskReal2(result.worktreePath,laneProfile.laneIndex,laneProfile.envOverrides)}catch{}return{worktreePath:result.worktreePath,branchName:result.branchName}}function isTransientProvisionError(errorMsg){let lower=errorMsg.toLowerCase();if(lower.includes("already exists")||lower.includes("not a git repository"))return!1;let transientCodes=["enoent","econnrefused","etimedout","ebusy","eperm","enomem"];for(let code of transientCodes)if(lower.includes(code))return!0;let transientMessages=["disk full","no space left","resource temporarily unavailable"];for(let msg of transientMessages)if(lower.includes(msg))return!0;if(lower.includes("fatal:"))return!0;return!1}function pushDirtyTreeDowngradeAdvisory(sessionID,reason,lanesAffected=[]){let session=ensureAgentSession(sessionID);session.pendingAdvisoryMessages??=[];let affected=lanesAffected.length>0?`; affected lanes: ${lanesAffected.join(", ")}`:"";session.pendingAdvisoryMessages.push(`LEAN_TURBO_DIRTY_TREE_DOWNGRADE: ${reason}${affected}. Worktree isolation is OFF for this phase; lanes run in the shared working tree.`)}class LeanTurboRunner{static _internals={loadPlanJsonOnly,planLeanTurboLanes,acquireLaneLocks,releaseLaneLocks,loadLeanTurboRunState,saveLeanTurboRunState,hasActiveFullAuto,loadFullAutoRunState,writeLaneEvidence,writePhaseEvidence,laneDispatchTimeoutMs:void 0,provisionWorktree:provisionWorktree2,removeWorktree,removeLaneProfileFromDisk:removeLaneProfileFromDiskReal,mergeLaneBranch,postMergeCleanup,attemptMergeBackFromDirty,startupOrphanRecovery,getMergeStrategy:getMergeStrategy2,assertCleanWorkingTree,ensureAgentSession};_sessionOps=null;_directory;_sessionID;_client;_availableAgents;_laneLockMap={};_laneStatuses=new Map;_agentIndex=0;_timedOutLanes=new Map;_stateLock=Promise.resolve();_leanConfig;_pendingDowngrade=null;constructor(options){if(this._directory=options.directory,this._sessionID=options.sessionID,this._leanConfig=options.leanConfig,"opencodeClient"in options){if(this._client=options.opencodeClient??null,this._client)this._sessionOps=this._client.session}let names=options.generatedAgentNames??swarmState.generatedAgentNames;this._availableAgents=this._resolveCoderAgents(names)}async runPhase(phaseNumber){if(this._client===null)return{ok:!1,reason:"NO_CLIENT",lanes:[],degradedTasks:[],serializedTasks:[]};let plan=await LeanTurboRunner._internals.loadPlanJsonOnly(this._directory);if(!plan)return{ok:!1,reason:"NO_PLAN",lanes:[],degradedTasks:[],serializedTasks:[]};if(LeanTurboRunner._internals.hasActiveFullAuto(this._sessionID)){let fullAutoState=LeanTurboRunner._internals.loadFullAutoRunState(this._directory,this._sessionID);if(fullAutoState&&(fullAutoState.status==="paused"||fullAutoState.status==="terminated"))return{ok:!1,reason:"FULL_AUTO_BLOCKED",lanes:[],degradedTasks:[],serializedTasks:[]}}let leanConfig=this._getLeanConfig(this._leanConfig),phaseStartedAt=new Date().toISOString();if(leanConfig.worktree_isolation){await LeanTurboRunner._internals.startupOrphanRecovery(this._directory,[this._sessionID]);try{let cleanResult=await LeanTurboRunner._internals.assertCleanWorkingTree(this._directory);if(!cleanResult.clean)this._pendingDowngrade={reason:cleanResult.error??"uncommitted changes"},console.warn(`[lean-turbo] worktree isolation requires clean working tree: ${cleanResult.error}`),leanConfig.worktree_isolation=!1}catch(assertErr){let assertMsg=assertErr instanceof Error?assertErr.message:String(assertErr);this._pendingDowngrade={reason:`cleanliness check failed: ${assertMsg}`},console.warn(`[lean-turbo] unable to verify working tree cleanliness: ${assertMsg} — degrading to shared directory`),leanConfig.worktree_isolation=!1}}let lanePlan=LeanTurboRunner._internals.planLeanTurboLanes(this._directory,phaseNumber,{phases:plan.phases},leanConfig);if(this._pendingDowngrade){let lanesAffected=lanePlan.lanes.map((l)=>l.laneId);pushDirtyTreeDowngradeAdvisory(this._sessionID,this._pendingDowngrade.reason,lanesAffected),this._pendingDowngrade=null}let degradedTasks=lanePlan.degradedTasks.map((d)=>d.taskId);if(lanePlan.lanes.length===0&&degradedTasks.length===0&&lanePlan.serializedTasks.length===0)return{ok:!1,reason:"NO_LANES",lanes:[],degradedTasks,serializedTasks:lanePlan.serializedTasks};if(lanePlan.lanes.length===0)return await this._withStateLock(()=>this._updateDurableState(lanePlan)),await this._writePhaseEvidenceSafely({phaseNumber,plan,lanePlan,laneResults:[],leanConfig,status:"completed",startedAt:phaseStartedAt}),{ok:!0,lanes:[],degradedTasks,serializedTasks:lanePlan.serializedTasks};await this._withStateLock(()=>this._updateDurableState(lanePlan)),this._laneStatuses=new Map(lanePlan.lanes.map((lane)=>[lane.laneId,{...lane}]));let laneResults=[],results=await Promise.all(lanePlan.lanes.map((lane)=>this._processLane(lane,leanConfig)));laneResults.push(...results);let mergeBackFailures=await this._sequentialWorktreeCleanup(laneResults,leanConfig),phaseResult={ok:mergeBackFailures.length===0,reason:mergeBackFailures.length>0?`Lean Turbo merge-back failed for ${mergeBackFailures.length} lane(s); preserved affected worktrees for manual recovery.`:void 0,lanes:laneResults,degradedTasks,serializedTasks:lanePlan.serializedTasks,mergeBackFailures:mergeBackFailures.length>0?mergeBackFailures:void 0};return await this._writePhaseEvidenceSafely({phaseNumber,plan,lanePlan,laneResults,leanConfig,status:phaseResult.ok?"completed":"failed",startedAt:phaseStartedAt,mergeBackFailures}),phaseResult}async dispatchLane(lane,agentName,worktreeDirectory){let session=this._sessionOps??this._client?.session;if(!session)return{ok:!1,error:"NO_CLIENT"};let promptController=new AbortController,dispatchPromise=this._doDispatch(session,lane,agentName,worktreeDirectory,promptController),timeoutMs=LeanTurboRunner._internals.laneDispatchTimeoutMs;if(timeoutMs!==void 0&&timeoutMs>0){let timeoutHandle,timeoutPromise=new Promise((_,reject)=>{timeoutHandle=setTimeout(()=>{promptController.abort(),reject(Error(`Lane dispatch timed out after ${timeoutMs}ms`))},timeoutMs)});try{return await Promise.race([dispatchPromise,timeoutPromise])}catch(err){if(err instanceof Error&&err.message.includes("timed out"))return this._timedOutLanes.set(lane.laneId,"__pending__"),dispatchPromise.then((result)=>{if(result.ok&&result.sessionId)if(this._timedOutLanes.get(lane.laneId)!==void 0)this._timedOutLanes.delete(lane.laneId),session.delete({path:{id:result.sessionId}}).catch(()=>{});else this._timedOutLanes.delete(lane.laneId);else this._timedOutLanes.delete(lane.laneId)}).catch(()=>{this._timedOutLanes.delete(lane.laneId)}),{ok:!1,error:err.message};throw err}finally{if(timeoutHandle!==void 0)clearTimeout(timeoutHandle)}}return dispatchPromise}async _doDispatch(session,lane,agentName,worktreeDirectory,abortController){let sessionId;try{let effectiveDirectory=worktreeDirectory??this._directory,createResult=await session.create({...this._sessionID?{body:{parentID:this._sessionID,title:`lean_turbo_lane_${lane.laneId} background`}}:{},query:{directory:effectiveDirectory}});if(!createResult.data)return{ok:!1,error:`session.create failed: ${typeof createResult.error==="string"?createResult.error:JSON.stringify(createResult.error)}`};sessionId=createResult.data.id;let promptText=this._buildLanePrompt(lane),promptResult=await session.prompt({path:{id:sessionId},body:{agent:agentName,tools:{write:!0,edit:!0,patch:!0},parts:[{type:"text",text:promptText}]},signal:abortController?.signal});if(!promptResult.data)return abortController?.abort(),session.delete({path:{id:sessionId}}).catch(()=>{}),{ok:!1,error:`session.prompt failed: ${typeof promptResult.error==="string"?promptResult.error:JSON.stringify(promptResult.error)}`};return{ok:!0,sessionId}}catch(err){if(sessionId)abortController?.abort(),session.delete({path:{id:sessionId}}).catch(()=>{});return{ok:!1,error:err instanceof Error?err.message:String(err)}}}async waitForLanes(){let statuses=[];for(let[laneId,lane]of this._laneStatuses)statuses.push({laneId,status:lane.status,taskIds:lane.taskIds,agent:lane.agent,sessionId:lane.sessionId,error:lane.error});return statuses}async cleanup(){for(let[laneId]of Object.entries(this._laneLockMap))try{await LeanTurboRunner._internals.releaseLaneLocks(this._directory,laneId)}catch{}this._laneLockMap={};for(let[_laneId,lane]of this._laneStatuses)if(lane.worktreePath)try{await LeanTurboRunner._internals.removeWorktree(lane.worktreePath,this._directory,{force:!0,worktreeDir:this._leanConfig?.worktree_dir})}catch{}await this._withStateLock(async()=>{let runState=LeanTurboRunner._internals.loadLeanTurboRunState(this._directory,this._sessionID);if(runState)runState.lanes=runState.lanes.map((lane)=>lane.status==="running"||lane.status==="pending"?{...lane,status:"blocked"}:lane),LeanTurboRunner._internals.saveLeanTurboRunState(this._directory,runState)})}async cleanupAfterSuccess(){for(let[laneId]of Object.entries(this._laneLockMap)){let laneStatus=this._laneStatuses.get(laneId);if(laneStatus&&(laneStatus.status==="completed"||laneStatus.status==="failed"||laneStatus.status==="blocked")){try{await LeanTurboRunner._internals.releaseLaneLocks(this._directory,laneId)}catch{}delete this._laneLockMap[laneId]}}}async cleanupAfterFailure(){return this.cleanup()}_resolveCoderAgents(names){let coders=names.filter((n)=>n.toLowerCase().includes("coder"));if(coders.length===0)return["coder"];let prefixed=coders.filter((n)=>/[_-]coder$/i.test(n)||/^[a-z]+_[a-z]+_coder$/i.test(n)),bare=coders.filter((n)=>!n.includes("_")&&!n.includes("-")&&n==="coder"),sorted=[...prefixed.sort((a,b)=>b.length-a.length),...bare],seen=new Set,deduped=[];for(let name of sorted)if(!seen.has(name.toLowerCase()))seen.add(name.toLowerCase()),deduped.push(name);return deduped.length>0?deduped:["coder"]}_getLeanConfig(config3){if(config3)return structuredClone({...DEFAULT_LEAN_TURBO_CONFIG,...config3});return{...DEFAULT_LEAN_TURBO_CONFIG}}async _processLane(lane,leanConfig){let laneInState=this._laneStatuses.get(lane.laneId);if(laneInState)laneInState.status="running",laneInState.startedAt=new Date().toISOString();let taskId=lane.taskIds[0]??lane.laneId,agent=this._selectNextAgent();if(!(await LeanTurboRunner._internals.acquireLaneLocks(this._directory,lane.laneId,lane.files,agent,taskId,this._sessionID)).acquired){if(await this._withStateLock(async()=>{try{let runState=LeanTurboRunner._internals.loadLeanTurboRunState(this._directory,this._sessionID);if(runState){let existingSerialized=new Set(runState.serializedTasks??[]);for(let tid of lane.taskIds)existingSerialized.add(tid);runState.serializedTasks=Array.from(existingSerialized),runState.counters.tasksSerialized+=lane.taskIds.length,LeanTurboRunner._internals.saveLeanTurboRunState(this._directory,runState)}}catch{}}),laneInState)laneInState.status="failed",laneInState.error="lock conflict - tasks routed to serial fallback";return await this._updateDurableStateLaneStatus(lane.laneId,"failed"),{laneId:lane.laneId,status:"failed",taskIds:lane.taskIds,error:"lock conflict - tasks routed to serial fallback"}}this._laneLockMap[lane.laneId]=[...lane.files];let worktreeDirectory;if(leanConfig.worktree_isolation){let provisionError;try{let provisionResult=await LeanTurboRunner._internals.provisionWorktree(this._directory,lane.laneId,this._sessionID,leanConfig);if("worktreePath"in provisionResult){if(worktreeDirectory=provisionResult.worktreePath,laneInState)laneInState.worktreePath=provisionResult.worktreePath,laneInState.branchName=provisionResult.branchName;await this._persistLaneWorktreeFields(lane.laneId,provisionResult.worktreePath,provisionResult.branchName)}else provisionError=provisionResult.error}catch(provisionErr){provisionError=provisionErr instanceof Error?provisionErr.message:String(provisionErr)}if(provisionError)if(isTransientProvisionError(provisionError)){console.warn(`[lean-turbo] worktree provision failed for lane ${lane.laneId}: ${provisionError} — retrying once...`),await new Promise((r)=>setTimeout(r,100));try{let retryResult=await LeanTurboRunner._internals.provisionWorktree(this._directory,lane.laneId,this._sessionID,leanConfig);if("worktreePath"in retryResult){if(worktreeDirectory=retryResult.worktreePath,laneInState)laneInState.worktreePath=retryResult.worktreePath,laneInState.branchName=retryResult.branchName;await this._persistLaneWorktreeFields(lane.laneId,retryResult.worktreePath,retryResult.branchName),console.warn(`[lean-turbo] worktree provision retry succeeded for lane ${lane.laneId}`),provisionError=void 0}else provisionError=retryResult.error,console.warn(`[lean-turbo] worktree provision retry failed for lane ${lane.laneId}: ${retryResult.error}`)}catch(retryErr){let retryMsg=retryErr instanceof Error?retryErr.message:String(retryErr);console.warn(`[lean-turbo] worktree provision retry threw for lane ${lane.laneId}: ${retryMsg}`)}}else console.warn(`[lean-turbo] worktree provision failed for lane ${lane.laneId}: ${provisionError}`);if(!worktreeDirectory){let failMsg=`worktree provision failed: ${provisionError??"unknown error"}`;try{await LeanTurboRunner._internals.releaseLaneLocks(this._directory,lane.laneId)}catch{}if(delete this._laneLockMap[lane.laneId],laneInState)laneInState.status="failed",laneInState.error=failMsg;return await this._updateDurableStateLaneStatus(lane.laneId,"failed"),await this._writeLaneEvidenceSafely(lane,"failed",{status:"failed",error:failMsg,agent}),{laneId:lane.laneId,status:"failed",taskIds:lane.taskIds,agent,error:failMsg}}}let dispatchResult=await this.dispatchLane(lane,agent,worktreeDirectory);if(!dispatchResult.ok){try{await LeanTurboRunner._internals.releaseLaneLocks(this._directory,lane.laneId)}catch{}if(delete this._laneLockMap[lane.laneId],worktreeDirectory&&laneInState)laneInState._failureCleanupPending=!0;if(laneInState)laneInState.status="failed",laneInState.error=dispatchResult.error;return await this._updateDurableStateLaneStatus(lane.laneId,"failed"),await this._writeLaneEvidenceSafely(lane,"failed",{status:"failed",error:dispatchResult.error,agent}),{laneId:lane.laneId,status:"failed",taskIds:lane.taskIds,agent,error:dispatchResult.error}}let completedAt=new Date().toISOString();if(laneInState)laneInState.status="completed",laneInState.agent=agent,laneInState.sessionId=dispatchResult.sessionId,laneInState.completedAt=completedAt;await this._updateDurableStateLaneStatus(lane.laneId,"completed");try{await LeanTurboRunner._internals.releaseLaneLocks(this._directory,lane.laneId)}catch{}return delete this._laneLockMap[lane.laneId],await this._writeLaneEvidenceSafely(lane,"completed",{status:"completed",agent,sessionId:dispatchResult.sessionId,completedAt}),{laneId:lane.laneId,status:"completed",taskIds:lane.taskIds,agent,sessionId:dispatchResult.sessionId}}async _sequentialWorktreeCleanup(laneResults,leanConfig){let mergeBackFailures=[];for(let lr of laneResults){let laneInState=this._laneStatuses.get(lr.laneId);if(!laneInState?.worktreePath)continue;let needsPostMergeCleanup=!1;if(lr.status==="completed"){if(!laneInState.branchName)continue;try{let strategy=LeanTurboRunner._internals.getMergeStrategy(leanConfig),mergeResult=await LeanTurboRunner._internals.attemptMergeBackFromDirty(laneInState.worktreePath,laneInState.branchName,this._directory,strategy);if("merged"in mergeResult&&mergeResult.merged){needsPostMergeCleanup=!0;let leanLaneIndex=parseLeanLaneIndex(lr.laneId);try{await LeanTurboRunner._internals.removeLaneProfileFromDisk(laneInState.worktreePath,leanLaneIndex)}catch{}}else if("conflict"in mergeResult&&mergeResult.conflict||"partial"in mergeResult&&mergeResult.partial){let conflictFiles="conflictFiles"in mergeResult&&Array.isArray(mergeResult.conflictFiles)?mergeResult.conflictFiles:[],isConflict="conflict"in mergeResult&&mergeResult.conflict===!0||conflictFiles.length>0,reason="message"in mergeResult&&typeof mergeResult.message==="string"&&(mergeResult.message||"")||"merge-back partially failed",failureInfo={laneId:lr.laneId,branchName:laneInState.branchName,worktreePath:laneInState.worktreePath,status:isConflict?"conflict":"partial",reason,conflictFiles};mergeBackFailures.push(failureInfo),lr.status="failed",lr.error=failureInfo.reason,lr.mergeBackFailure=failureInfo,laneInState.status="failed",laneInState.error=failureInfo.reason,await this._updateDurableStateLaneStatus(lr.laneId,"failed"),await this._writeLaneEvidenceSafely({laneId:lr.laneId,taskIds:lr.taskIds,files:[],status:"failed"},"failed",{status:"failed",error:failureInfo.reason,mergeBackFailure:failureInfo}),console.warn(`[lean-turbo] merge-back PARTIAL for lane ${lr.laneId}: ${failureInfo.reason} — worktree preserved at ${laneInState.worktreePath} for manual recovery`);continue}else if("failed"in mergeResult&&mergeResult.failed){let failureInfo={laneId:lr.laneId,branchName:laneInState.branchName,worktreePath:laneInState.worktreePath,status:"failed",reason:mergeResult.message};mergeBackFailures.push(failureInfo),lr.status="failed",lr.error=failureInfo.reason,lr.mergeBackFailure=failureInfo,laneInState.status="failed",laneInState.error=failureInfo.reason,await this._updateDurableStateLaneStatus(lr.laneId,"failed"),await this._writeLaneEvidenceSafely({laneId:lr.laneId,taskIds:lr.taskIds,files:[],status:"failed"},"failed",{status:"failed",error:failureInfo.reason,mergeBackFailure:failureInfo}),console.warn(`[lean-turbo] merge-back ERROR for lane ${lr.laneId}: ${failureInfo.reason} — worktree preserved at ${laneInState.worktreePath} for manual recovery`);continue}}catch(err){let errMsg=err instanceof Error?err.message:String(err),failureInfo={laneId:lr.laneId,branchName:laneInState.branchName,worktreePath:laneInState.worktreePath,status:"failed",reason:errMsg};mergeBackFailures.push(failureInfo),lr.status="failed",lr.error=failureInfo.reason,lr.mergeBackFailure=failureInfo,laneInState.status="failed",laneInState.error=failureInfo.reason,await this._updateDurableStateLaneStatus(lr.laneId,"failed"),await this._writeLaneEvidenceSafely({laneId:lr.laneId,taskIds:lr.taskIds,files:[],status:"failed"},"failed",{status:"failed",error:failureInfo.reason,mergeBackFailure:failureInfo}),console.warn(`[lean-turbo] merge-back EXCEPTION for lane ${lr.laneId}: ${errMsg} — worktree preserved at ${laneInState.worktreePath} for manual recovery`);continue}}else if(lr.status==="failed"&&laneInState._failureCleanupPending){let failureInfo={laneId:lr.laneId,branchName:laneInState.branchName,worktreePath:laneInState.worktreePath,status:"failed",reason:lr.error||"Lane failed before completion; worktree preserved without merge-back"};mergeBackFailures.push(failureInfo),lr.mergeBackFailure=failureInfo,console.warn(`[lean-turbo] failed lane ${lr.laneId}: ${failureInfo.reason} — worktree preserved at ${laneInState.worktreePath}; not merging partial work`);continue}try{await LeanTurboRunner._internals.removeWorktree(laneInState.worktreePath,this._directory,{force:!0,worktreeDir:leanConfig.worktree_dir})}catch{}if(needsPostMergeCleanup&&laneInState.branchName)try{await LeanTurboRunner._internals.postMergeCleanup(this._directory,laneInState.branchName)}catch{}}return mergeBackFailures}_buildIntegratedDiffSummary(lanePlan,laneResults,mergeBackFailures=[]){let resultByLane=new Map(laneResults.map((lane)=>[lane.laneId,lane])),files=new Set;for(let lane of lanePlan.lanes)for(let file3 of lane.files)files.add(file3);let completed=laneResults.filter((lane)=>lane.status==="completed").length,failed=laneResults.filter((lane)=>lane.status==="failed").length,blocked=laneResults.filter((lane)=>lane.status==="blocked").length,fileList=[...files].sort(),displayedFiles=fileList.slice(0,50),hiddenFileCount=Math.max(0,fileList.length-displayedFiles.length),lines=[`Lean Turbo phase ${lanePlan.phase}: ${completed}/${lanePlan.lanes.length} lanes completed, ${failed} failed, ${blocked} blocked.`,`Files declared changed (${fileList.length}): ${displayedFiles.length>0?displayedFiles.join(", "):"none"}${hiddenFileCount>0?`, ... +${hiddenFileCount} more`:""}.`];if(lanePlan.serializedTasks.length>0)lines.push(`Serialized tasks pending standard execution: ${lanePlan.serializedTasks.join(", ")}.`);if(lanePlan.degradedTasks.length>0)lines.push(`Degraded tasks: ${lanePlan.degradedTasks.map((task)=>`${task.taskId} (${task.reason})`).join(", ")}.`);if(mergeBackFailures.length>0)lines.push(`Merge-back failures: ${mergeBackFailures.map((failure)=>`${failure.laneId}: ${failure.reason}`).join("; ")}.`);for(let lane of lanePlan.lanes){let result=resultByLane.get(lane.laneId);if(result?.error)lines.push(`${lane.laneId} error: ${result.error}.`)}return lines.join(`
6011
- `)}async _writePhaseEvidenceSafely(args2){let completedAt=new Date().toISOString(),resultByLane=new Map(args2.laneResults.map((lane)=>[lane.laneId,lane])),lanes=args2.lanePlan.lanes.map((lane)=>{let result=resultByLane.get(lane.laneId),evidenceLane={laneId:lane.laneId,taskIds:lane.taskIds,files:lane.files,status:result?.status??lane.status,startedAt:lane.startedAt,completedAt:result?.status==="completed"||result?.status==="failed"?lane.completedAt??completedAt:lane.completedAt,error:result?.error??lane.error,agent:result?.agent??lane.agent,sessionId:result?.sessionId??lane.sessionId};if(result?.mergeBackFailure)evidenceLane.mergeBackFailure=result.mergeBackFailure;return evidenceLane}),planId=args2.lanePlan.planId||derivePlanId({swarm:args2.plan.swarm??"default",title:args2.plan.title??"Untitled Plan"}),evidence={phase:args2.phaseNumber,planId,lanes,degradedTasks:args2.lanePlan.degradedTasks.map((task)=>({taskId:task.taskId,reason:task.reason})),startedAt:args2.startedAt,completedAt,status:args2.status,evidencePaths:lanes.map((lane)=>`.swarm/evidence/${args2.phaseNumber}/lean-turbo/${lane.laneId}.json`),integratedDiffSummary:this._buildIntegratedDiffSummary(args2.lanePlan,args2.laneResults,args2.mergeBackFailures??[]),configSnapshot:args2.leanConfig,timestamp:completedAt};try{await LeanTurboRunner._internals.writePhaseEvidence(this._directory,evidence)}catch(error93){let msg=error93 instanceof Error?error93.message:String(error93);console.warn(`[lean-turbo] phase evidence write failed: ${msg}`)}}_selectNextAgent(){if(this._availableAgents.length===0)return"coder";let agent=this._availableAgents[this._agentIndex%this._availableAgents.length];return this._agentIndex++,agent}async _writeLaneEvidenceSafely(lane,status,extras){for(let attempt=0;attempt<3;attempt++)try{let evidence={laneId:lane.laneId,taskIds:lane.taskIds,files:lane.files,status,startedAt:lane.startedAt,...extras},phase=LeanTurboRunner._internals.loadLeanTurboRunState(this._directory,this._sessionID)?.phase;if(phase===void 0){console.warn(`[lean-turbo] evidence write skipped for lane ${lane.laneId}: phase not set in run state`);return}await LeanTurboRunner._internals.writeLaneEvidence(this._directory,phase,evidence);return}catch(error93){let errCode=error93 instanceof Error?error93.code??"":"",isTransient=errCode.length>0&&["ENOENT","EBUSY","EPERM","EIO","EAGAIN","ETIMEDOUT","ENOSPC"].includes(errCode);if(attempt<2&&isTransient){let delayMs=100*2**attempt;await new Promise((resolve75)=>setTimeout(resolve75,delayMs));continue}let msg=error93 instanceof Error?error93.message:String(error93);console.warn(`[lean-turbo] evidence write failed for lane ${lane.laneId}: ${msg}`);return}}_buildLanePrompt(lane){let taskList=lane.taskIds.map((id)=>` - ${id}`).join(`
6010
+ Resolution: call \`declare_scope\` once for EACH of those task ids with the exact file paths the task will touch. Then re-invoke \`epic_plan_waves(phase=${phase})\`.`]}}let isUpstreamCommitted;if(_internals126.isGitRepo(directory)){let evidence=_internals126.buildIsUpstreamCommittedWithStatus(directory);if(evidence.gitFailed)return criticalWarn(`[epic_plan_waves] wave-planning blocked for directory=${directory} phase=${phase}: git log scan failed. Any prior promote verdict in .swarm/evidence/epic-promotions.jsonl for this phase is not backed by actual parallel execution.`),{success:!1,reason:"git-failed",errors:["epic_plan_waves: cannot verify cross-batch upstream-commit evidence — `git log` read failed. "+"Likely transient: retry once git is healthy (e.g. another process released its lock). If git is persistently broken (corrupt repo, permission issue, missing `.git`), repair the repository. "+"Until repaired, complete the phase serially — one task at a time, waiting for each commit to land before dispatching the next — so file-scope conflict detection is not required."]};isUpstreamCommitted=evidence.predicate}let leanConfig={...DEFAULT_LEAN_TURBO_CONFIG};try{let userLean=(await _internals126.loadPluginConfigWithMeta(directory))?.config?.turbo?.lean;if(userLean)leanConfig={...leanConfig,...userLean}}catch{}let wavePlan=planEpicWaves(directory,phase,plan,leanConfig,scopes,isUpstreamCommitted);return{success:!0,plan:wavePlan,waves:wavePlan.waves,serializedTasks:wavePlan.serializedTasks,degradedTasks:wavePlan.degradedTasks}}catch(error93){let errMsg=error93 instanceof Error?error93.message:String(error93);return criticalWarn(`[epic_plan_waves] wave-planning failed for directory=${directory} phase=${phase}: ${errMsg}. Any prior promote verdict in .swarm/evidence/epic-promotions.jsonl for this phase is not backed by actual parallel execution.`),{success:!1,reason:"planner-error",errors:[errMsg]}}}var _internals126={readPlanJson,readTaskScopes,isGitRepo:(cwd)=>isGitRepo(cwd),buildIsUpstreamCommittedWithStatus,loadPluginConfigWithMeta},epic_plan_waves=createSwarmTool({description:"Partition a phase's pending tasks into ordered concurrent waves for Epic Mode dispatch. A wave is a set of tasks with mutually disjoint declared scopes and all dependencies satisfied by prior waves. Returns `{ waves: [{ waveId, taskIds, files }, ...], serializedTasks, degradedTasks }`. "+'For each wave in order, the architect dispatches one `Task(subagent_type="coder", ...)` per `taskId` — all in one assistant message — so the wave runs concurrently and each coder appears as a visible subagent. '+"Wait for the wave to finish before dispatching the next. Pair with `epic_decide_phase` (called first; this tool is only relevant on a `promote` verdict). "+"Preflight reject reasons: `no-plan`, `no-phase`, `phase-empty`, `phase-already-complete`, `scopes-missing` (call `declare_scope` for `missingScopes`), `git-failed` (transient — retry), `planner-error`.",args:{directory:exports_external.string().describe("Project root directory where `.swarm/plan.json` is located"),phase:exports_external.number().int().positive().describe("Phase number to plan"),scopes:exports_external.record(exports_external.string(),exports_external.array(exports_external.string())).optional().describe("Optional pre-loaded scopes map (taskId -> file paths). When omitted, scopes are read from `.swarm/scopes/scope-<taskId>.json` and `files_touched` in plan.json.")},execute:async(args2,_directory)=>{let result=await executeEpicPlanWaves({...args2,directory:_directory});return JSON.stringify(result,null,2)}});init_zod();init_manager();init_scope_persistence();init_state2();init_divergence_recorder();init_logger();init_create_tool();var _internals127={hasActiveEpicMode,getAgentSession,readScopeFromDisk,loadPlanJsonOnly,recordTaskDivergence};async function findPhaseForTask(directory,taskId){try{let plan=await _internals127.loadPlanJsonOnly(directory);if(!plan)return;for(let phase of plan.phases)if(phase.tasks.some((t)=>t.id===taskId))return phase.id}catch{}return}async function executeEpicRecordDivergence(args2){let{directory,taskId,sessionID}=args2;if(!_internals127.hasActiveEpicMode(sessionID))return{success:!0,reason:"epic-mode-not-active"};let session=_internals127.getAgentSession(sessionID);if(!session)return{success:!0,reason:"no-session"};let declaredScope=_internals127.readScopeFromDisk(directory,taskId);if(declaredScope===null)return{success:!0,reason:"no-scope"};let actualFiles=session.modifiedFilesThisCoderTask??[],phaseNumber=await findPhaseForTask(directory,taskId),result=_internals127.recordTaskDivergence({directory,sessionID,taskId,phaseNumber,declaredScope,actualFiles});if(!result)return warn(`[epic_record_divergence] persist failed for ${taskId}; calibration will miss one observation`),{success:!0,reason:"persist-failed"};let{record:record3}=result;return{success:!0,reason:"recorded",summary:{declaredCount:record3.declaredScope.length,actualCount:record3.actualFiles.length,undeclaredCount:record3.undeclared.length,unusedCount:record3.unused.length,divergenceRatio:record3.divergenceRatio,isClean:record3.isClean}}}var epic_record_divergence=createSwarmTool({description:`Record divergence between a completed task's declared scope and the files actually modified, for Epic Mode calibration (Capability D). Call this immediately after update_task_status sets status="completed". Appends one line to .swarm/epic/divergence.jsonl. Best-effort — never fails the calling agent. Use only when /swarm epic is on for the session.`,args:{directory:exports_external.string().describe("Project root directory"),taskId:exports_external.string().describe("Task id whose divergence should be recorded"),sessionID:exports_external.string().describe("Active session ID")},execute:async(args2,_directory,ctx)=>{let{taskId,sessionID:argSessionID}=args2,sessionID=ctx?.sessionID&&ctx.sessionID.length>0?ctx.sessionID:argSessionID;return JSON.stringify(await executeEpicRecordDivergence({directory:_directory,taskId,sessionID}),null,2)}});init_zod();init_config();init_branch();init_manager();init_state2();init_activation();init_calibration();init_conflicts();var DEFAULT_FLOOR=0.05,DEFAULT_TIGHTEN_STEP=0.02,DEFAULT_LOOSEN_STEP=0.01,DEFAULT_LOOSEN_WINDOW=10;function applyCalibration(state,newRecords,options){let floor=options.floorThreshold??DEFAULT_FLOOR,tightenStep=options.tightenStep??DEFAULT_TIGHTEN_STEP,loosenStep=options.loosenStep??DEFAULT_LOOSEN_STEP,loosenWindow=options.loosenWindow??DEFAULT_LOOSEN_WINDOW,effectiveThreshold=state.activationThresholdOverride??options.staticThreshold,consecutiveCleanCount=state.consecutiveCleanCount,hotSet=new Set(state.hotModuleAdditions);for(let record3 of newRecords)if(record3.isClean){if(consecutiveCleanCount+=1,consecutiveCleanCount>=loosenWindow)effectiveThreshold=Math.min(options.staticThreshold,effectiveThreshold+loosenStep),consecutiveCleanCount=0}else{consecutiveCleanCount=0,effectiveThreshold=Math.max(floor,effectiveThreshold-tightenStep);for(let undeclaredFile of record3.undeclared)hotSet.add(normalizePath(undeclaredFile))}let newOverride=effectiveThreshold===options.staticThreshold?void 0:effectiveThreshold;return{version:1,updatedAt:state.updatedAt,activationThresholdOverride:newOverride,hotModuleAdditions:Array.from(hotSet).sort(),consecutiveCleanCount,lastCalibrationAt:newRecords.length>0?new Date().toISOString():state.lastCalibrationAt,processedRecords:state.processedRecords+newRecords.length}}function effectiveActivationThreshold(staticThreshold,state){if(!state||state.activationThresholdOverride===void 0)return staticThreshold;return Math.max(0,Math.min(staticThreshold,state.activationThresholdOverride))}function effectiveHotModules(staticHotModules,state){if(!state||state.hotModuleAdditions.length===0)return Array.from(staticHotModules);return Array.from(new Set([...staticHotModules,...state.hotModuleAdditions]))}init_cochange_source();init_divergence_recorder();init_promotion_evidence();init_state();init_conflicts();init_constants();init_state3();init_file_locks();init_manager();init_utils3();init_state2();init_logger();init_merge();function getMergeStrategy2(config3){return getMergeStrategy({merge_strategy:config3.merge_strategy})}init_conflicts();init_conflicts();function planLeanTurboLanes(directory,phaseNumber,plan,config3,scopes,isUpstreamCommitted){let phase=plan.phases.find((p)=>p.id===phaseNumber);if(!phase)return createEmptyPlan2(phaseNumber,"");let pendingTasks=phase.tasks.filter((t)=>t.status!=="completed");if(pendingTasks.length===0)return createEmptyPlan2(phaseNumber,"");let{sortedTasks,taskMap,tasksInCycle}=runPartitionPreflight(directory,pendingTasks,config3,scopes),lanes=[],serializedTasks=[],degradedTasks=[],maxLanes=config3.max_parallel_coders,claimedFiles=new Set,assignedTasks=new Set,taskToLane=new Map,crossLaneDependencies={};for(let taskId of tasksInCycle)serializedTasks.push(taskId),assignedTasks.add(taskId),taskToLane.set(taskId,-1);let isSatisfied=makeDependencySatisfactionChecker(taskMap,assignedTasks,isUpstreamCommitted);while(!0){let readyTasks=getReadyTasks(sortedTasks,assignedTasks,isSatisfied);if(readyTasks.length===0)break;for(let classified of readyTasks){if(assignedTasks.has(classified.task.id))continue;if(classified.category==="global"){degradedTasks.push({taskId:classified.task.id,reason:"global file conflict",files:classified.files,requiredMode:"balanced"}),assignedTasks.add(classified.task.id);continue}if(classified.category==="protected"){if(config3.degrade_on_risk)degradedTasks.push({taskId:classified.task.id,reason:"protected path",files:classified.files,requiredMode:"balanced"});else serializedTasks.push(classified.task.id),taskToLane.set(classified.task.id,-1);assignedTasks.add(classified.task.id);continue}if(classified.category==="no-scope"||classified.category==="invalid-scope"){serializedTasks.push(classified.task.id),taskToLane.set(classified.task.id,-1),assignedTasks.add(classified.task.id);continue}if(classified.files.some((file3)=>claimedFiles.has(file3))){if(config3.conflict_policy==="degrade")degradedTasks.push({taskId:classified.task.id,reason:"file conflict with parallel task",files:classified.files,requiredMode:"balanced"});else serializedTasks.push(classified.task.id),taskToLane.set(classified.task.id,-1);assignedTasks.add(classified.task.id);continue}let hasParentChildConflict=!1;for(let file3 of classified.files){for(let claimed of Array.from(claimedFiles))if(pathsConflict(file3,claimed)){hasParentChildConflict=!0;break}if(hasParentChildConflict)break}if(hasParentChildConflict){if(config3.conflict_policy==="degrade")degradedTasks.push({taskId:classified.task.id,reason:"file conflict with parallel task",files:classified.files,requiredMode:"balanced"});else serializedTasks.push(classified.task.id),taskToLane.set(classified.task.id,-1);assignedTasks.add(classified.task.id);continue}let candidateLaneIndex=-1;for(let i=0;i<lanes.length;i++)if(!lanes[i].files.some((laneFile)=>classified.files.some((taskFile)=>pathsConflict(laneFile,taskFile)))){candidateLaneIndex=i;break}if(candidateLaneIndex===-1&&lanes.length<maxLanes)candidateLaneIndex=lanes.length;if(candidateLaneIndex!==-1){let depsInOtherLanes=[],deps=classified.task.depends??[];for(let dep of deps){if(!taskMap.has(dep))continue;let depLane=taskToLane.get(dep);if(depLane!==void 0&&depLane!==-1&&depLane!==candidateLaneIndex)depsInOtherLanes.push(dep)}if(depsInOtherLanes.length>0){serializedTasks.push(classified.task.id),assignedTasks.add(classified.task.id),taskToLane.set(classified.task.id,-1),crossLaneDependencies[classified.task.id]=depsInOtherLanes;continue}if(candidateLaneIndex<lanes.length){let lane=lanes[candidateLaneIndex];lane.taskIds.push(classified.task.id),lane.files.push(...classified.files),assignedTasks.add(classified.task.id),taskToLane.set(classified.task.id,candidateLaneIndex)}else lanes.push({laneId:`lane-${lanes.length+1}`,taskIds:[classified.task.id],files:[...classified.files],status:"pending"}),assignedTasks.add(classified.task.id),taskToLane.set(classified.task.id,lanes.length-1);for(let file3 of classified.files)claimedFiles.add(file3)}else serializedTasks.push(classified.task.id),assignedTasks.add(classified.task.id),taskToLane.set(classified.task.id,-1)}}if(isUpstreamCommitted)for(let classified of sortedTasks){if(assignedTasks.has(classified.task.id))continue;let deps=classified.task.depends??[],uncommittedCrossBatch=[],unassignedInBatch=[];for(let dep of deps)if(taskMap.has(dep)){if(!assignedTasks.has(dep))unassignedInBatch.push(dep)}else if(!isUpstreamCommitted(dep))uncommittedCrossBatch.push(dep);let reason;if(uncommittedCrossBatch.length>0){let sample=uncommittedCrossBatch.slice(0,3).join(", "),more=uncommittedCrossBatch.length>3?`, +${uncommittedCrossBatch.length-3} more`:"";reason=`cross-batch upstream not committed (greenfield-smart Rule 3): ${sample}${more}`}else if(unassignedInBatch.length>0){let sample=unassignedInBatch.slice(0,3).join(", "),more=unassignedInBatch.length>3?`, +${unassignedInBatch.length-3} more`:"";reason=`unresolved in-batch dependency: ${sample}${more}`}else reason="planning leftover (no identifiable blocker)";degradedTasks.push({taskId:classified.task.id,reason,files:classified.files,requiredMode:"balanced"}),assignedTasks.add(classified.task.id),taskToLane.set(classified.task.id,-1)}let degradationSummary;if(degradedTasks.length>0&&degradedTasks.length+serializedTasks.length===pendingTasks.length){let reasons=Array.from(new Set(degradedTasks.map((t)=>t.reason))),rule3Count=degradedTasks.filter((t)=>t.reason.includes("greenfield-smart Rule 3")).length;if(rule3Count>0&&rule3Count>=degradedTasks.length/2)degradationSummary=`All ${pendingTasks.length} tasks degraded. ${rule3Count} blocked by greenfield-smart Rule 3 — cross-batch upstream(s) not in git history. Remediation: verify Epic Mode commit-on-completion is succeeding for upstream phases, or commit those tasks manually before re-running.`;else degradationSummary=`All ${pendingTasks.length} tasks degraded. Reasons: ${reasons.join(", ")}. Consider running in standard (serial) mode.`}let counters={lanesPlanned:lanes.length,lanesStarted:0,lanesCompleted:0,lanesFailed:0,tasksSerialized:serializedTasks.length,tasksDegraded:degradedTasks.length},planId=`plan-${phaseNumber}-${Date.now()}`;return{phase:phaseNumber,planId,lanes,degradedTasks,serializedTasks,degradationSummary,counters,crossLaneDependencies}}function createEmptyPlan2(phaseNumber,planId){return{phase:phaseNumber,planId,lanes:[],degradedTasks:[],serializedTasks:[],counters:{lanesPlanned:0,lanesStarted:0,lanesCompleted:0,lanesFailed:0,tasksSerialized:0,tasksDegraded:0},crossLaneDependencies:{}}}init_state4();init_file_locks();init_logger();var _internals128={tryAcquireLock};class TurboStateLockTimeoutError extends Error{directory;sessionID;constructor(directory,sessionID,timeoutMs){super(`Turbo state lock timeout after ${timeoutMs}ms for session ${sessionID}`);this.name="TurboStateLockTimeoutError",this.directory=directory,this.sessionID=sessionID}}var BACKOFF_START_MS2=50,BACKOFF_MAX_MS2=2000,BACKOFF_JITTER_RATIO2=0.25;function backoffMs2(attempt){let base=Math.min(BACKOFF_START_MS2*2**attempt,BACKOFF_MAX_MS2),jitter=base*BACKOFF_JITTER_RATIO2*(Math.random()*2-1);return Math.max(1,Math.round(base+jitter))}async function withTurboStateLock(directory,sessionID,fn2,timeoutMs=30000){let deadline=Date.now()+timeoutMs,attempt=0;while(!0){let result;try{result=await _internals128.tryAcquireLock(directory,".swarm/turbo-state.json","lean-turbo-runner",sessionID)}catch(acquireErr){log(`[lean-turbo] state lock acquisition error for ${sessionID} (.swarm/turbo-state.json), will retry: ${acquireErr instanceof Error?acquireErr.message:String(acquireErr)}`)}if(result?.acquired){let lock=result.lock;try{return await fn2()}finally{if(lock._release)try{await lock._release()}catch(releaseErr){log(`[lean-turbo] state lock release failed for ${sessionID} (.swarm/turbo-state.json): ${releaseErr instanceof Error?releaseErr.message:String(releaseErr)}`)}}}if(Date.now()>=deadline)throw new TurboStateLockTimeoutError(directory,sessionID,timeoutMs);let delay=Math.min(backoffMs2(attempt),deadline-Date.now());if(delay>0)await new Promise((resolve75)=>setTimeout(resolve75,delay));attempt++}}init_worktree_isolation();init_core3();import*as path203 from"node:path";function computeLaneRuntimeProfile2(runtime,laneIndex,worktreePath){if(!runtime?.enabled)return;let portStride=runtime.port_stride??1,envOverrides={};if(runtime.port_base!==void 0){let portBase=runtime.port_base,port=Math.min(portBase+laneIndex*portStride,65535);envOverrides.PORT=String(port)}if(runtime.env_overrides)Object.assign(envOverrides,runtime.env_overrides);if(runtime.cache_redirects)for(let[envName,basePath]of Object.entries(runtime.cache_redirects))envOverrides[envName]=path203.join(basePath,`lane-${laneIndex}`);return{laneIndex,worktreePath,envOverrides}}async function provisionWorktree2(directory,laneId,sessionId,config3,scope){let laneIndex=parseLeanLaneIndex(laneId),result=await provisionWorktree(directory,laneId,sessionId,{purpose:"lane",branchStyle:"legacy-lane",worktreeDir:config3.worktree_dir,mergeStrategy:config3.merge_strategy,depsStrategy:config3.deps_strategy,scope});if("error"in result)return result;let laneProfile=computeLaneRuntimeProfile2(config3.runtime_isolation,laneIndex,result.worktreePath);if(laneProfile)try{let{writeLaneProfileToDiskReal:writeLaneProfileToDiskReal2}=await Promise.resolve().then(() => (init_core3(),exports_core3));await writeLaneProfileToDiskReal2(result.worktreePath,laneProfile.laneIndex,laneProfile.envOverrides)}catch{}return{worktreePath:result.worktreePath,branchName:result.branchName}}function isTransientProvisionError(errorMsg){let lower=errorMsg.toLowerCase();if(lower.includes("already exists")||lower.includes("not a git repository"))return!1;let transientCodes=["enoent","econnrefused","etimedout","ebusy","eperm","enomem"];for(let code of transientCodes)if(lower.includes(code))return!0;let transientMessages=["disk full","no space left","resource temporarily unavailable"];for(let msg of transientMessages)if(lower.includes(msg))return!0;if(lower.includes("fatal:"))return!0;return!1}function pushDirtyTreeDowngradeAdvisory(sessionID,reason,lanesAffected=[]){let session=ensureAgentSession(sessionID);session.pendingAdvisoryMessages??=[];let affected=lanesAffected.length>0?`; affected lanes: ${lanesAffected.join(", ")}`:"";session.pendingAdvisoryMessages.push(`LEAN_TURBO_DIRTY_TREE_DOWNGRADE: ${reason}${affected}. Worktree isolation is OFF for this phase; lanes run in the shared working tree.`)}class LeanTurboRunner{static _internals={loadPlanJsonOnly,planLeanTurboLanes,acquireLaneLocks,releaseLaneLocks,loadLeanTurboRunState,saveLeanTurboRunState,hasActiveFullAuto,loadFullAutoRunState,writeLaneEvidence,writePhaseEvidence,laneDispatchTimeoutMs:void 0,provisionWorktree:provisionWorktree2,removeWorktree,removeLaneProfileFromDisk:removeLaneProfileFromDiskReal,mergeLaneBranch,postMergeCleanup,attemptMergeBackFromDirty,startupOrphanRecovery,getMergeStrategy:getMergeStrategy2,assertCleanWorkingTree,ensureAgentSession};_sessionOps=null;_directory;_sessionID;_client;_availableAgents;_laneLockMap={};_laneStatuses=new Map;_agentIndex=0;_timedOutLanes=new Map;_stateLock=Promise.resolve();_leanConfig;_pendingDowngrade=null;constructor(options){if(this._directory=options.directory,this._sessionID=options.sessionID,this._leanConfig=options.leanConfig,"opencodeClient"in options){if(this._client=options.opencodeClient??null,this._client)this._sessionOps=this._client.session}let names=options.generatedAgentNames??swarmState.generatedAgentNames;this._availableAgents=this._resolveCoderAgents(names)}async runPhase(phaseNumber){if(this._client===null)return{ok:!1,reason:"NO_CLIENT",lanes:[],degradedTasks:[],serializedTasks:[]};let plan=await LeanTurboRunner._internals.loadPlanJsonOnly(this._directory);if(!plan)return{ok:!1,reason:"NO_PLAN",lanes:[],degradedTasks:[],serializedTasks:[]};if(LeanTurboRunner._internals.hasActiveFullAuto(this._sessionID)){let fullAutoState=LeanTurboRunner._internals.loadFullAutoRunState(this._directory,this._sessionID);if(fullAutoState&&(fullAutoState.status==="paused"||fullAutoState.status==="terminated"))return{ok:!1,reason:"FULL_AUTO_BLOCKED",lanes:[],degradedTasks:[],serializedTasks:[]}}let leanConfig=this._getLeanConfig(this._leanConfig),phaseStartedAt=new Date().toISOString();if(leanConfig.worktree_isolation){await LeanTurboRunner._internals.startupOrphanRecovery(this._directory,[this._sessionID]);try{let cleanResult=await LeanTurboRunner._internals.assertCleanWorkingTree(this._directory);if(!cleanResult.clean)this._pendingDowngrade={reason:cleanResult.error??"uncommitted changes"},log(`[lean-turbo] worktree isolation requires clean working tree: ${cleanResult.error}`),leanConfig.worktree_isolation=!1}catch(assertErr){let assertMsg=assertErr instanceof Error?assertErr.message:String(assertErr);this._pendingDowngrade={reason:`cleanliness check failed: ${assertMsg}`},log(`[lean-turbo] unable to verify working tree cleanliness: ${assertMsg} — degrading to shared directory`),leanConfig.worktree_isolation=!1}}let lanePlan=LeanTurboRunner._internals.planLeanTurboLanes(this._directory,phaseNumber,{phases:plan.phases},leanConfig);if(this._pendingDowngrade){let lanesAffected=lanePlan.lanes.map((l)=>l.laneId);pushDirtyTreeDowngradeAdvisory(this._sessionID,this._pendingDowngrade.reason,lanesAffected),this._pendingDowngrade=null}let degradedTasks=lanePlan.degradedTasks.map((d)=>d.taskId);if(lanePlan.lanes.length===0&&degradedTasks.length===0&&lanePlan.serializedTasks.length===0)return{ok:!1,reason:"NO_LANES",lanes:[],degradedTasks,serializedTasks:lanePlan.serializedTasks};if(lanePlan.lanes.length===0)return await this._withStateLock(()=>this._updateDurableState(lanePlan)),await this._writePhaseEvidenceSafely({phaseNumber,plan,lanePlan,laneResults:[],leanConfig,status:"completed",startedAt:phaseStartedAt}),{ok:!0,lanes:[],degradedTasks,serializedTasks:lanePlan.serializedTasks};await this._withStateLock(()=>this._updateDurableState(lanePlan)),this._laneStatuses=new Map(lanePlan.lanes.map((lane)=>[lane.laneId,{...lane}]));let laneResults=[],results=await Promise.all(lanePlan.lanes.map((lane)=>this._processLane(lane,leanConfig)));laneResults.push(...results);let mergeBackFailures=await this._sequentialWorktreeCleanup(laneResults,leanConfig),phaseResult={ok:mergeBackFailures.length===0,reason:mergeBackFailures.length>0?`Lean Turbo merge-back failed for ${mergeBackFailures.length} lane(s); preserved affected worktrees for manual recovery.`:void 0,lanes:laneResults,degradedTasks,serializedTasks:lanePlan.serializedTasks,mergeBackFailures:mergeBackFailures.length>0?mergeBackFailures:void 0};return await this._writePhaseEvidenceSafely({phaseNumber,plan,lanePlan,laneResults,leanConfig,status:phaseResult.ok?"completed":"failed",startedAt:phaseStartedAt,mergeBackFailures}),phaseResult}async dispatchLane(lane,agentName,worktreeDirectory){let session=this._sessionOps??this._client?.session;if(!session)return{ok:!1,error:"NO_CLIENT"};let promptController=new AbortController,dispatchPromise=this._doDispatch(session,lane,agentName,worktreeDirectory,promptController),timeoutMs=LeanTurboRunner._internals.laneDispatchTimeoutMs;if(timeoutMs!==void 0&&timeoutMs>0){let timeoutHandle,timeoutPromise=new Promise((_,reject)=>{timeoutHandle=setTimeout(()=>{promptController.abort(),reject(Error(`Lane dispatch timed out after ${timeoutMs}ms`))},timeoutMs)});try{return await Promise.race([dispatchPromise,timeoutPromise])}catch(err){if(err instanceof Error&&err.message.includes("timed out"))return this._timedOutLanes.set(lane.laneId,"__pending__"),dispatchPromise.then((result)=>{if(result.ok&&result.sessionId)if(this._timedOutLanes.get(lane.laneId)!==void 0)this._timedOutLanes.delete(lane.laneId),session.delete({path:{id:result.sessionId}}).catch(()=>{});else this._timedOutLanes.delete(lane.laneId);else this._timedOutLanes.delete(lane.laneId)}).catch(()=>{this._timedOutLanes.delete(lane.laneId)}),{ok:!1,error:err.message};throw err}finally{if(timeoutHandle!==void 0)clearTimeout(timeoutHandle)}}return dispatchPromise}async _doDispatch(session,lane,agentName,worktreeDirectory,abortController){let sessionId;try{let effectiveDirectory=worktreeDirectory??this._directory,createResult=await session.create({...this._sessionID?{body:{parentID:this._sessionID,title:`lean_turbo_lane_${lane.laneId} background`}}:{},query:{directory:effectiveDirectory}});if(!createResult.data)return{ok:!1,error:`session.create failed: ${typeof createResult.error==="string"?createResult.error:JSON.stringify(createResult.error)}`};sessionId=createResult.data.id;let promptText=this._buildLanePrompt(lane),promptResult=await session.prompt({path:{id:sessionId},body:{agent:agentName,tools:{write:!0,edit:!0,patch:!0},parts:[{type:"text",text:promptText}]},signal:abortController?.signal});if(!promptResult.data)return abortController?.abort(),session.delete({path:{id:sessionId}}).catch(()=>{}),{ok:!1,error:`session.prompt failed: ${typeof promptResult.error==="string"?promptResult.error:JSON.stringify(promptResult.error)}`};return{ok:!0,sessionId}}catch(err){if(sessionId)abortController?.abort(),session.delete({path:{id:sessionId}}).catch(()=>{});return{ok:!1,error:err instanceof Error?err.message:String(err)}}}async waitForLanes(){let statuses=[];for(let[laneId,lane]of this._laneStatuses)statuses.push({laneId,status:lane.status,taskIds:lane.taskIds,agent:lane.agent,sessionId:lane.sessionId,error:lane.error});return statuses}async cleanup(){for(let[laneId]of Object.entries(this._laneLockMap))try{await LeanTurboRunner._internals.releaseLaneLocks(this._directory,laneId)}catch{}this._laneLockMap={};for(let[_laneId,lane]of this._laneStatuses)if(lane.worktreePath)try{await LeanTurboRunner._internals.removeWorktree(lane.worktreePath,this._directory,{force:!0,worktreeDir:this._leanConfig?.worktree_dir})}catch{}await this._withStateLock(async()=>{let runState=LeanTurboRunner._internals.loadLeanTurboRunState(this._directory,this._sessionID);if(runState)runState.lanes=runState.lanes.map((lane)=>lane.status==="running"||lane.status==="pending"?{...lane,status:"blocked"}:lane),LeanTurboRunner._internals.saveLeanTurboRunState(this._directory,runState)})}async cleanupAfterSuccess(){for(let[laneId]of Object.entries(this._laneLockMap)){let laneStatus=this._laneStatuses.get(laneId);if(laneStatus&&(laneStatus.status==="completed"||laneStatus.status==="failed"||laneStatus.status==="blocked")){try{await LeanTurboRunner._internals.releaseLaneLocks(this._directory,laneId)}catch{}delete this._laneLockMap[laneId]}}}async cleanupAfterFailure(){return this.cleanup()}_resolveCoderAgents(names){let coders=names.filter((n)=>n.toLowerCase().includes("coder"));if(coders.length===0)return["coder"];let prefixed=coders.filter((n)=>/[_-]coder$/i.test(n)||/^[a-z]+_[a-z]+_coder$/i.test(n)),bare=coders.filter((n)=>!n.includes("_")&&!n.includes("-")&&n==="coder"),sorted=[...prefixed.sort((a,b)=>b.length-a.length),...bare],seen=new Set,deduped=[];for(let name of sorted)if(!seen.has(name.toLowerCase()))seen.add(name.toLowerCase()),deduped.push(name);return deduped.length>0?deduped:["coder"]}_getLeanConfig(config3){if(config3)return structuredClone({...DEFAULT_LEAN_TURBO_CONFIG,...config3});return{...DEFAULT_LEAN_TURBO_CONFIG}}async _processLane(lane,leanConfig){let laneInState=this._laneStatuses.get(lane.laneId);if(laneInState)laneInState.status="running",laneInState.startedAt=new Date().toISOString();let taskId=lane.taskIds[0]??lane.laneId,agent=this._selectNextAgent();if(!(await LeanTurboRunner._internals.acquireLaneLocks(this._directory,lane.laneId,lane.files,agent,taskId,this._sessionID)).acquired){if(await this._withStateLock(async()=>{try{let runState=LeanTurboRunner._internals.loadLeanTurboRunState(this._directory,this._sessionID);if(runState){let existingSerialized=new Set(runState.serializedTasks??[]);for(let tid of lane.taskIds)existingSerialized.add(tid);runState.serializedTasks=Array.from(existingSerialized),runState.counters.tasksSerialized+=lane.taskIds.length,LeanTurboRunner._internals.saveLeanTurboRunState(this._directory,runState)}}catch{}}),laneInState)laneInState.status="failed",laneInState.error="lock conflict - tasks routed to serial fallback";return await this._updateDurableStateLaneStatus(lane.laneId,"failed"),{laneId:lane.laneId,status:"failed",taskIds:lane.taskIds,error:"lock conflict - tasks routed to serial fallback"}}this._laneLockMap[lane.laneId]=[...lane.files];let worktreeDirectory;if(leanConfig.worktree_isolation){let provisionError;try{let provisionResult=await LeanTurboRunner._internals.provisionWorktree(this._directory,lane.laneId,this._sessionID,leanConfig);if("worktreePath"in provisionResult){if(worktreeDirectory=provisionResult.worktreePath,laneInState)laneInState.worktreePath=provisionResult.worktreePath,laneInState.branchName=provisionResult.branchName;await this._persistLaneWorktreeFields(lane.laneId,provisionResult.worktreePath,provisionResult.branchName)}else provisionError=provisionResult.error}catch(provisionErr){provisionError=provisionErr instanceof Error?provisionErr.message:String(provisionErr)}if(provisionError)if(isTransientProvisionError(provisionError)){log(`[lean-turbo] worktree provision failed for lane ${lane.laneId}: ${provisionError} — retrying once...`),await new Promise((r)=>setTimeout(r,100));try{let retryResult=await LeanTurboRunner._internals.provisionWorktree(this._directory,lane.laneId,this._sessionID,leanConfig);if("worktreePath"in retryResult){if(worktreeDirectory=retryResult.worktreePath,laneInState)laneInState.worktreePath=retryResult.worktreePath,laneInState.branchName=retryResult.branchName;await this._persistLaneWorktreeFields(lane.laneId,retryResult.worktreePath,retryResult.branchName),log(`[lean-turbo] worktree provision retry succeeded for lane ${lane.laneId}`),provisionError=void 0}else provisionError=retryResult.error,log(`[lean-turbo] worktree provision retry failed for lane ${lane.laneId}: ${retryResult.error}`)}catch(retryErr){let retryMsg=retryErr instanceof Error?retryErr.message:String(retryErr);log(`[lean-turbo] worktree provision retry threw for lane ${lane.laneId}: ${retryMsg}`)}}else log(`[lean-turbo] worktree provision failed for lane ${lane.laneId}: ${provisionError}`);if(!worktreeDirectory){let failMsg=`worktree provision failed: ${provisionError??"unknown error"}`;try{await LeanTurboRunner._internals.releaseLaneLocks(this._directory,lane.laneId)}catch{}if(delete this._laneLockMap[lane.laneId],laneInState)laneInState.status="failed",laneInState.error=failMsg;return await this._updateDurableStateLaneStatus(lane.laneId,"failed"),await this._writeLaneEvidenceSafely(lane,"failed",{status:"failed",error:failMsg,agent}),{laneId:lane.laneId,status:"failed",taskIds:lane.taskIds,agent,error:failMsg}}}let dispatchResult=await this.dispatchLane(lane,agent,worktreeDirectory);if(!dispatchResult.ok){try{await LeanTurboRunner._internals.releaseLaneLocks(this._directory,lane.laneId)}catch{}if(delete this._laneLockMap[lane.laneId],worktreeDirectory&&laneInState)laneInState._failureCleanupPending=!0;if(laneInState)laneInState.status="failed",laneInState.error=dispatchResult.error;return await this._updateDurableStateLaneStatus(lane.laneId,"failed"),await this._writeLaneEvidenceSafely(lane,"failed",{status:"failed",error:dispatchResult.error,agent}),{laneId:lane.laneId,status:"failed",taskIds:lane.taskIds,agent,error:dispatchResult.error}}let completedAt=new Date().toISOString();if(laneInState)laneInState.status="completed",laneInState.agent=agent,laneInState.sessionId=dispatchResult.sessionId,laneInState.completedAt=completedAt;await this._updateDurableStateLaneStatus(lane.laneId,"completed");try{await LeanTurboRunner._internals.releaseLaneLocks(this._directory,lane.laneId)}catch{}return delete this._laneLockMap[lane.laneId],await this._writeLaneEvidenceSafely(lane,"completed",{status:"completed",agent,sessionId:dispatchResult.sessionId,completedAt}),{laneId:lane.laneId,status:"completed",taskIds:lane.taskIds,agent,sessionId:dispatchResult.sessionId}}async _sequentialWorktreeCleanup(laneResults,leanConfig){let mergeBackFailures=[];for(let lr of laneResults){let laneInState=this._laneStatuses.get(lr.laneId);if(!laneInState?.worktreePath)continue;let needsPostMergeCleanup=!1;if(lr.status==="completed"){if(!laneInState.branchName)continue;try{let strategy=LeanTurboRunner._internals.getMergeStrategy(leanConfig),mergeResult=await LeanTurboRunner._internals.attemptMergeBackFromDirty(laneInState.worktreePath,laneInState.branchName,this._directory,strategy);if("merged"in mergeResult&&mergeResult.merged){needsPostMergeCleanup=!0;let leanLaneIndex=parseLeanLaneIndex(lr.laneId);try{await LeanTurboRunner._internals.removeLaneProfileFromDisk(laneInState.worktreePath,leanLaneIndex)}catch{}}else if("conflict"in mergeResult&&mergeResult.conflict||"partial"in mergeResult&&mergeResult.partial){let conflictFiles="conflictFiles"in mergeResult&&Array.isArray(mergeResult.conflictFiles)?mergeResult.conflictFiles:[],isConflict="conflict"in mergeResult&&mergeResult.conflict===!0||conflictFiles.length>0,reason="message"in mergeResult&&typeof mergeResult.message==="string"&&(mergeResult.message||"")||"merge-back partially failed",failureInfo={laneId:lr.laneId,branchName:laneInState.branchName,worktreePath:laneInState.worktreePath,status:isConflict?"conflict":"partial",reason,conflictFiles};mergeBackFailures.push(failureInfo),lr.status="failed",lr.error=failureInfo.reason,lr.mergeBackFailure=failureInfo,laneInState.status="failed",laneInState.error=failureInfo.reason,await this._updateDurableStateLaneStatus(lr.laneId,"failed"),await this._writeLaneEvidenceSafely({laneId:lr.laneId,taskIds:lr.taskIds,files:[],status:"failed"},"failed",{status:"failed",error:failureInfo.reason,mergeBackFailure:failureInfo}),log(`[lean-turbo] merge-back PARTIAL for lane ${lr.laneId}: ${failureInfo.reason} — worktree preserved at ${laneInState.worktreePath} for manual recovery`);continue}else if("failed"in mergeResult&&mergeResult.failed){let failureInfo={laneId:lr.laneId,branchName:laneInState.branchName,worktreePath:laneInState.worktreePath,status:"failed",reason:mergeResult.message};mergeBackFailures.push(failureInfo),lr.status="failed",lr.error=failureInfo.reason,lr.mergeBackFailure=failureInfo,laneInState.status="failed",laneInState.error=failureInfo.reason,await this._updateDurableStateLaneStatus(lr.laneId,"failed"),await this._writeLaneEvidenceSafely({laneId:lr.laneId,taskIds:lr.taskIds,files:[],status:"failed"},"failed",{status:"failed",error:failureInfo.reason,mergeBackFailure:failureInfo}),log(`[lean-turbo] merge-back ERROR for lane ${lr.laneId}: ${failureInfo.reason} — worktree preserved at ${laneInState.worktreePath} for manual recovery`);continue}}catch(err){let errMsg=err instanceof Error?err.message:String(err),failureInfo={laneId:lr.laneId,branchName:laneInState.branchName,worktreePath:laneInState.worktreePath,status:"failed",reason:errMsg};mergeBackFailures.push(failureInfo),lr.status="failed",lr.error=failureInfo.reason,lr.mergeBackFailure=failureInfo,laneInState.status="failed",laneInState.error=failureInfo.reason,await this._updateDurableStateLaneStatus(lr.laneId,"failed"),await this._writeLaneEvidenceSafely({laneId:lr.laneId,taskIds:lr.taskIds,files:[],status:"failed"},"failed",{status:"failed",error:failureInfo.reason,mergeBackFailure:failureInfo}),log(`[lean-turbo] merge-back EXCEPTION for lane ${lr.laneId}: ${errMsg} — worktree preserved at ${laneInState.worktreePath} for manual recovery`);continue}}else if(lr.status==="failed"&&laneInState._failureCleanupPending){let failureInfo={laneId:lr.laneId,branchName:laneInState.branchName,worktreePath:laneInState.worktreePath,status:"failed",reason:lr.error||"Lane failed before completion; worktree preserved without merge-back"};mergeBackFailures.push(failureInfo),lr.mergeBackFailure=failureInfo,log(`[lean-turbo] failed lane ${lr.laneId}: ${failureInfo.reason} — worktree preserved at ${laneInState.worktreePath}; not merging partial work`);continue}try{await LeanTurboRunner._internals.removeWorktree(laneInState.worktreePath,this._directory,{force:!0,worktreeDir:leanConfig.worktree_dir})}catch{}if(needsPostMergeCleanup&&laneInState.branchName)try{await LeanTurboRunner._internals.postMergeCleanup(this._directory,laneInState.branchName)}catch{}}return mergeBackFailures}_buildIntegratedDiffSummary(lanePlan,laneResults,mergeBackFailures=[]){let resultByLane=new Map(laneResults.map((lane)=>[lane.laneId,lane])),files=new Set;for(let lane of lanePlan.lanes)for(let file3 of lane.files)files.add(file3);let completed=laneResults.filter((lane)=>lane.status==="completed").length,failed=laneResults.filter((lane)=>lane.status==="failed").length,blocked=laneResults.filter((lane)=>lane.status==="blocked").length,fileList=[...files].sort(),displayedFiles=fileList.slice(0,50),hiddenFileCount=Math.max(0,fileList.length-displayedFiles.length),lines=[`Lean Turbo phase ${lanePlan.phase}: ${completed}/${lanePlan.lanes.length} lanes completed, ${failed} failed, ${blocked} blocked.`,`Files declared changed (${fileList.length}): ${displayedFiles.length>0?displayedFiles.join(", "):"none"}${hiddenFileCount>0?`, ... +${hiddenFileCount} more`:""}.`];if(lanePlan.serializedTasks.length>0)lines.push(`Serialized tasks pending standard execution: ${lanePlan.serializedTasks.join(", ")}.`);if(lanePlan.degradedTasks.length>0)lines.push(`Degraded tasks: ${lanePlan.degradedTasks.map((task)=>`${task.taskId} (${task.reason})`).join(", ")}.`);if(mergeBackFailures.length>0)lines.push(`Merge-back failures: ${mergeBackFailures.map((failure)=>`${failure.laneId}: ${failure.reason}`).join("; ")}.`);for(let lane of lanePlan.lanes){let result=resultByLane.get(lane.laneId);if(result?.error)lines.push(`${lane.laneId} error: ${result.error}.`)}return lines.join(`
6011
+ `)}async _writePhaseEvidenceSafely(args2){let completedAt=new Date().toISOString(),resultByLane=new Map(args2.laneResults.map((lane)=>[lane.laneId,lane])),lanes=args2.lanePlan.lanes.map((lane)=>{let result=resultByLane.get(lane.laneId),evidenceLane={laneId:lane.laneId,taskIds:lane.taskIds,files:lane.files,status:result?.status??lane.status,startedAt:lane.startedAt,completedAt:result?.status==="completed"||result?.status==="failed"?lane.completedAt??completedAt:lane.completedAt,error:result?.error??lane.error,agent:result?.agent??lane.agent,sessionId:result?.sessionId??lane.sessionId};if(result?.mergeBackFailure)evidenceLane.mergeBackFailure=result.mergeBackFailure;return evidenceLane}),planId=args2.lanePlan.planId||derivePlanId({swarm:args2.plan.swarm??"default",title:args2.plan.title??"Untitled Plan"}),evidence={phase:args2.phaseNumber,planId,lanes,degradedTasks:args2.lanePlan.degradedTasks.map((task)=>({taskId:task.taskId,reason:task.reason})),startedAt:args2.startedAt,completedAt,status:args2.status,evidencePaths:lanes.map((lane)=>`.swarm/evidence/${args2.phaseNumber}/lean-turbo/${lane.laneId}.json`),integratedDiffSummary:this._buildIntegratedDiffSummary(args2.lanePlan,args2.laneResults,args2.mergeBackFailures??[]),configSnapshot:args2.leanConfig,timestamp:completedAt};try{await LeanTurboRunner._internals.writePhaseEvidence(this._directory,evidence)}catch(error93){let msg=error93 instanceof Error?error93.message:String(error93);log(`[lean-turbo] phase evidence write failed: ${msg}`)}}_selectNextAgent(){if(this._availableAgents.length===0)return"coder";let agent=this._availableAgents[this._agentIndex%this._availableAgents.length];return this._agentIndex++,agent}async _writeLaneEvidenceSafely(lane,status,extras){for(let attempt=0;attempt<3;attempt++)try{let evidence={laneId:lane.laneId,taskIds:lane.taskIds,files:lane.files,status,startedAt:lane.startedAt,...extras},phase=LeanTurboRunner._internals.loadLeanTurboRunState(this._directory,this._sessionID)?.phase;if(phase===void 0){log(`[lean-turbo] evidence write skipped for lane ${lane.laneId}: phase not set in run state`);return}await LeanTurboRunner._internals.writeLaneEvidence(this._directory,phase,evidence);return}catch(error93){let errCode=error93 instanceof Error?error93.code??"":"",isTransient=errCode.length>0&&["ENOENT","EBUSY","EPERM","EIO","EAGAIN","ETIMEDOUT","ENOSPC"].includes(errCode);if(attempt<2&&isTransient){let delayMs=100*2**attempt;await new Promise((resolve75)=>setTimeout(resolve75,delayMs));continue}let msg=error93 instanceof Error?error93.message:String(error93);log(`[lean-turbo] evidence write failed for lane ${lane.laneId}: ${msg}`);return}}_buildLanePrompt(lane){let taskList=lane.taskIds.map((id)=>` - ${id}`).join(`
6012
6012
  `),fileList=lane.files.map((f)=>` - ${f}`).join(`
6013
6013
  `);return`You are assigned to implement the following task(s) in lane "${lane.laneId}".
6014
6014
 
@@ -6067,14 +6067,14 @@ ${scanResult.neutralized}`;return result}catch(error93){if(error93 instanceof DO
6067
6067
  `)}class UnknownFormatFamilyError extends Error{constructor(){super("Unknown format family: neither impact_context nor invariant_violated present");this.name="UnknownFormatFamilyError"}}function detectFormatFamily(headerFields){let trimmed=headerFields.map((f)=>f.trim()),hasImpactContext=trimmed.includes(BASE_EXPLORER_DISCRIMINATOR),hasInvariantViolated=trimmed.includes(MICRO_LANE_DISCRIMINATOR);if(hasImpactContext)return"base_explorer";if(hasInvariantViolated)return"micro_lane";throw new UnknownFormatFamilyError}function detectRowFormatFamily(rowFields){let trimmed=rowFields.map((f)=>f.trim()),hasImpactContext=trimmed.length>7&&trimmed[7]!=="",hasInvariantViolated=trimmed.length>6&&trimmed[6]!=="";if(hasImpactContext&&!hasInvariantViolated)return"base_explorer";if(hasInvariantViolated&&!hasImpactContext)return"micro_lane";if(hasImpactContext&&hasInvariantViolated)return"base_explorer";throw new UnknownFormatFamilyError}function mapFields(fields,family){let trimmed=fields.map((f)=>f.trim()),names=family==="base_explorer"?BASE_EXPLORER_FIELDS:MICRO_LANE_FIELDS,result={};for(let i=0;i<names.length;i++)result[names[i]]=i<trimmed.length&&trimmed[i]!==""?trimmed[i]:null;if(family==="base_explorer")result.micro_lane=null,result.invariant_violated=null;else result.lane=null,result.impact_context=null;return result}function getRequiredFields(family){return family==="base_explorer"?BASE_EXPLORER_FIELDS:MICRO_LANE_FIELDS}function assertNonNullCandidateId(value){if(value===null||value==="")throw Error("Invariant violation: null/empty candidate_id reached candidate builder")}function buildInvocationEnvelope(input,flags,formatFamiliesDetected,candidateCount,parseErrors,malformedRows,cleanAttestationCount=0){return{record_type:"invocation",source_output_ref:input.output_ref,source_batch_id:input.batchId,source_lane_id:input.laneId,source_agent:input.agent,source_digest:input.digest,row_format_version:flags.row_format_version,sessionId:input.sessionId,parentSessionId:input.parentSessionId,...flags.producer?{producer:flags.producer}:{},produced_at:input.produced_at,record_version:RECORD_VERSION,format_families_detected:formatFamiliesDetected,candidate_count:candidateCount,parse_errors:parseErrors,malformed_rows:malformedRows,clean_attestation_count:cleanAttestationCount}}function buildEmptyDiagnostics(input,flags){return{candidate_count:0,parse_errors:0,parse_error_details:[],malformed_rows:0,duplicate_id_count:0,duplicate_id_warnings:[],degraded_source_count:flags.degraded?1:0,incomplete_source_count:input.transcriptIncomplete?1:0,format_families_detected:[],clean_attestation_count:0}}function refusalResult(errorCode,errorMessage3,input,flags){let envelope=buildInvocationEnvelope(input,flags,[],0,0,0);return{error:errorMessage3,error_code:errorCode,candidates:[],invocation_envelope:envelope,diagnostics:buildEmptyDiagnostics(input,flags)}}function detectFormatMismatchHint(text){if(text.trim()==="")return;let severityPattern=/\b(CRITICAL|HIGH|MEDIUM|LOW|INFO)\b/,fileLinePattern=/\b\S+\.[a-z]{1,4}:\d+\b/,hasSeverity=severityPattern.test(text),textForFileLine=text.replace(/\b\w+:\/\/\S*/g,""),hasFileLine=fileLinePattern.test(textForFileLine);if(hasSeverity&&hasFileLine)return"Lane output contains severity keywords and file:line references but no parseable [CANDIDATE] rows. The explorer may have emitted findings in prose format instead of pipe-delimited candidate rows.";if(hasSeverity)return"Lane output contains severity keywords but no parseable [CANDIDATE] rows. The explorer may have emitted findings in an unstructured format.";return}function emptyTextResult(input,flags){let envelope=buildInvocationEnvelope(input,flags,[],0,0,0),diagnostics=buildEmptyDiagnostics(input,flags),hint=detectFormatMismatchHint(input.text);if(hint)diagnostics.format_mismatch_hint=hint;return{candidates:[],invocation_envelope:envelope,diagnostics}}function parseCandidates(input,flags){let inputParse=ArtifactInputSchema.safeParse(input);if(!inputParse.success)throw Error(`Invalid ArtifactInput: ${inputParse.error.issues.map((issue3)=>issue3.message).join(", ")}`);let flagsParse=ParseFlagsSchema.safeParse(flags);if(!flagsParse.success)throw Error(`Invalid ParseFlags: ${flagsParse.error.issues.map((issue3)=>issue3.message).join(", ")}`);let validatedInput=inputParse.data,validatedFlags=flagsParse.data;if(validatedInput.artifact_status==="ref-not-found")return refusalResult("ref-not-found","Artifact reference not found in store",validatedInput,validatedFlags);if(validatedInput.artifact_status==="artifact-corrupted")return refusalResult("artifact-corrupted","Artifact data is corrupted",validatedInput,validatedFlags);if(validatedFlags.degraded&&!validatedFlags.accept_degraded)return refusalResult("degraded-source-refused","Degraded source refused by caller",validatedInput,validatedFlags);if(validatedInput.transcriptIncomplete===!0&&!validatedFlags.accept_partial)return refusalResult("partial-source-refused","Partial transcript refused by caller",validatedInput,validatedFlags);if(validatedInput.text.trim()==="")return emptyTextResult(validatedInput,validatedFlags);return parseText(validatedInput,validatedFlags)}function parseText(input,flags){let lines=removeCodeFences(input.text).split(`
6068
6068
  `),headerIndex=-1,headerFields=[];for(let i=0;i<lines.length;i++){let trimmed=lines[i].trim();if(trimmed==="")continue;let fields=splitRow(trimmed);if(fields.length>=2&&fields.some((f)=>f.trim()!=="")){headerIndex=i,headerFields=fields.map((f)=>f.trim());break}}if(headerIndex===-1)return emptyTextResult(input,flags);let headerFamily;try{headerFamily=detectFormatFamily(headerFields)}catch(e){if(e instanceof UnknownFormatFamilyError);else throw e}if(flags.expected_family!==void 0&&headerFamily!==void 0&&flags.expected_family!==headerFamily)return refusalResult("expected-family-mismatch",`Expected ${flags.expected_family} rows but header declares ${headerFamily}`,input,flags);let bothDiscriminators=headerFields.includes(BASE_EXPLORER_DISCRIMINATOR)&&headerFields.includes(MICRO_LANE_DISCRIMINATOR),parseErrorDetails=[];if(bothDiscriminators&&headerFamily==="base_explorer")parseErrorDetails.push({row_index:headerIndex,field:"header",message:"Both format-family discriminators present; defaulting to base_explorer"});let candidates=[],idCounts=new Map,idFirstRows=new Map,formatFamiliesDetected=new Set,malformedRows=0,currentCandidate=null,pendingClean,cleanErrorCode,cleanErrorMessage;for(let i=headerIndex+1;i<lines.length;i++){let trimmed=lines[i].trim();if(trimmed==="")continue;let fields=splitRow(trimmed);if(fields[0]?.trim()==="[CLEAN]"){let cleanFamily=flags.expected_family??headerFamily,cleanFields=fields.map((field)=>field.trim());if(cleanFamily!=="micro_lane")cleanErrorCode="invalid-clean-attestation",cleanErrorMessage="CLEAN attestation is valid only for micro_lane output";else if(cleanFields.length!==4||cleanFields.slice(1).some((field)=>field.length===0))cleanErrorCode="invalid-clean-attestation",cleanErrorMessage="CLEAN attestation requires micro_lane, coverage_scope, and evidence";else if(pendingClean!==void 0)cleanErrorCode="invalid-clean-attestation",cleanErrorMessage="Only one CLEAN attestation is allowed per artifact";else if(flags.degraded||input.transcriptIncomplete===!0)cleanErrorCode="untrusted-clean-attestation",cleanErrorMessage="CLEAN attestation cannot come from a degraded or partial artifact";else if(flags.expected_micro_lane!==void 0&&cleanFields[1]!==flags.expected_micro_lane)cleanErrorCode="expected-micro-lane-mismatch",cleanErrorMessage=`Expected CLEAN attestation for ${flags.expected_micro_lane}, received ${cleanFields[1]}`;else pendingClean={micro_lane:cleanFields[1],coverage_scope:cleanFields[2],evidence:cleanFields[3]};if(cleanErrorCode)parseErrorDetails.push({row_index:i,field:"clean_attestation",message:cleanErrorMessage??"Invalid CLEAN attestation"}),malformedRows++;continue}if(fields[0]?.trim()==="[CANDIDATE]")fields=fields.slice(1);if(fields.length<EXPECTED_FIELD_COUNT){if(currentCandidate){let prev=currentCandidate.evidence_summary??"";currentCandidate.evidence_summary=`${prev}
6069
6069
  ${trimmed}`}else malformedRows++;continue}let rowFields=fields.slice(0,EXPECTED_FIELD_COUNT),rowFamily;if(flags.expected_family??headerFamily)rowFamily=flags.expected_family??headerFamily;else try{rowFamily=detectRowFormatFamily(rowFields)}catch(e){if(e instanceof UnknownFormatFamilyError){malformedRows++;continue}throw e}let rowHasImpact=rowFields[7].trim()!=="",rowHasInvariant=rowFields[6].trim()!=="";if(rowHasImpact&&rowHasInvariant&&rowFamily==="base_explorer"&&flags.expected_family===void 0&&headerFamily===void 0)parseErrorDetails.push({row_index:i,field:"row",message:"Both format-family discriminators present; defaulting to base_explorer"});let mapped=mapFields(rowFields,rowFamily);if(rowFamily==="micro_lane"&&flags.expected_micro_lane!==void 0&&mapped.micro_lane!==flags.expected_micro_lane){parseErrorDetails.push({row_index:i,field:"micro_lane",message:`Expected micro_lane ${flags.expected_micro_lane}, received ${mapped.micro_lane??"<missing>"}`}),malformedRows++;continue}let requiredFields=rowFamily==="base_explorer"?getRequiredFields("base_explorer"):getRequiredFields("micro_lane"),rowMalformed=!1;for(let field of requiredFields){let value=mapped[field];if(field==="candidate_id"){if(value===null||value===""){rowMalformed=!0;break}}else if(value===null)parseErrorDetails.push({row_index:i,field,message:`Missing required field: ${field}`})}if(rowMalformed){malformedRows++;continue}assertNonNullCandidateId(mapped.candidate_id);let candidateId2=mapped.candidate_id,candidate={record_type:"candidate",row_format_family:rowFamily,row_format_version:flags.row_format_version,record_version:RECORD_VERSION,source_output_ref:input.output_ref,source_batch_id:input.batchId,source_lane_id:input.laneId,source_agent:input.agent,source_digest:input.digest,sessionId:input.sessionId,parentSessionId:input.parentSessionId,producer:flags.producer,extracted_from_partial_source:!!(input.transcriptIncomplete||flags.degraded),candidate_id:candidateId2,lane:mapped.lane,micro_lane:mapped.micro_lane,severity:mapped.severity,category:mapped.category,file_line:mapped.file_line,claim:mapped.claim,evidence_summary:mapped.evidence_summary,impact_context:mapped.impact_context,invariant_violated:mapped.invariant_violated,confidence:mapped.confidence},cid=candidate.candidate_id;if(idCounts.set(cid,(idCounts.get(cid)??0)+1),!idFirstRows.has(cid))idFirstRows.set(cid,i);formatFamiliesDetected.add(rowFamily),candidates.push(candidate),currentCandidate=candidate}let duplicateIdWarnings=[],duplicateIdCount=0;for(let[id,count]of idCounts)if(count>1)duplicateIdCount++,duplicateIdWarnings.push({candidate_id:id,occurrences:count}),parseErrorDetails.push({row_index:idFirstRows.get(id)??-1,field:"candidate_id",message:`Duplicate candidate_id: "${id}" appears ${count} times`});if(pendingClean&&candidates.length>0)cleanErrorCode="conflicting-clean-attestation",cleanErrorMessage="CLEAN attestation cannot appear with candidate rows",parseErrorDetails.push({row_index:headerIndex,field:"clean_attestation",message:cleanErrorMessage});if(pendingClean&&!cleanErrorCode&&(malformedRows>0||parseErrorDetails.length>0))cleanErrorCode="untrusted-clean-attestation",cleanErrorMessage="CLEAN attestation requires zero malformed rows and zero parse errors",parseErrorDetails.push({row_index:headerIndex,field:"clean_attestation",message:cleanErrorMessage});let cleanAttestation=pendingClean&&!cleanErrorCode&&candidates.length===0?{record_type:"clean_attestation",row_format_family:"micro_lane",row_format_version:flags.row_format_version,record_version:RECORD_VERSION,source_output_ref:input.output_ref,source_batch_id:input.batchId,source_lane_id:input.laneId,source_agent:input.agent,source_digest:input.digest,extracted_from_partial_source:!1,sessionId:input.sessionId,parentSessionId:input.parentSessionId,producer:flags.producer,micro_lane:pendingClean.micro_lane,coverage_scope:pendingClean.coverage_scope,evidence:pendingClean.evidence}:void 0;if(cleanAttestation)formatFamiliesDetected.add("micro_lane");let acceptedCandidates=cleanErrorCode?[]:candidates,parseErrors=parseErrorDetails.length,envelope=buildInvocationEnvelope(input,flags,Array.from(formatFamiliesDetected),acceptedCandidates.length,parseErrors,malformedRows,cleanAttestation?1:0),diagnostics={candidate_count:acceptedCandidates.length,parse_errors:parseErrors,parse_error_details:parseErrorDetails,malformed_rows:malformedRows,duplicate_id_count:duplicateIdCount,duplicate_id_warnings:duplicateIdWarnings,degraded_source_count:flags.degraded?1:0,incomplete_source_count:input.transcriptIncomplete?1:0,format_families_detected:Array.from(formatFamiliesDetected),clean_attestation_count:cleanAttestation?1:0};if(acceptedCandidates.length===0&&!cleanAttestation){let hint=detectFormatMismatchHint(input.text);if(hint)diagnostics.format_mismatch_hint=hint}return{...cleanErrorCode?{error:cleanErrorMessage??"Invalid CLEAN attestation",error_code:cleanErrorCode}:{},candidates:acceptedCandidates,...cleanAttestation?{clean_attestation:cleanAttestation}:{},invocation_envelope:envelope,diagnostics}}function parseAndPersist(input,flags,options){let result=parseCandidates(input,flags);try{appendToSidecar(options,input.batchId,result.invocation_envelope,result.candidates,result.clean_attestation)}catch(error93){let message=error93 instanceof Error?error93.message:String(error93);return{...result,sidecar_write_error:message}}return result}init_utils2();init_create_tool();var ParseLaneCandidatesArgsSchema=exports_external.object({output_ref:exports_external.string().min(1).describe("Opaque lane output ref returned as output_ref by dispatch_lanes or collect_lane_results."),accept_partial:exports_external.boolean().default(!1).describe("Accept sources where transcriptIncomplete is true (partial transcripts)."),accept_degraded:exports_external.boolean().default(!1).describe("Accept sources where the artifact storage was degraded (output_degraded)."),degraded:exports_external.boolean().default(!1).describe("Passed through from DispatchLaneResult.output_degraded by the orchestrator."),row_format_version:exports_external.number().int().nonnegative().default(1).describe("Row format version; currently only version 1 is supported."),producer:exports_external.string().optional().default("swarm-pr-review").describe("Producer label for cross-skill filtering in the sidecar."),expected_family:exports_external.enum(["base_explorer","micro_lane"]).optional().describe("Assert the row family for this dispatch batch. A recognizable conflicting header is refused."),expected_micro_lane:exports_external.string().trim().min(1).optional().describe("Assert the micro-lane label linked to this dispatch provenance. Mismatched candidates and CLEAN attestations are refused."),use_lockfile:exports_external.boolean().default(!1).describe("When true, use proper-lockfile for concurrency-safe sidecar writes."),project_root:exports_external.string().optional().describe("Project root directory where .swarm/ lives. Defaults to the injected working directory.")}).strict(),REF_RE2=/^L1:[a-f0-9]{64}:[a-f0-9]{64}:[a-f0-9]{64}$/;function laneOutputRelativePath2(ref){let parts=ref.split(":");if(parts.length!==4)return"";let[,batchDigest,laneDigest,outputDigest]=parts;return path215.join("lane-results",batchDigest,laneDigest,`${outputDigest}.json`)}var parse_lane_candidates=createSwarmTool({description:"Parse [CANDIDATE] rows from a dispatch_lanes or collect_lane_results artifact (by output_ref), produce structured records with provenance, optionally persist to a per-batch sidecar JSONL. Pure-parser variant exists as internal module.",args:{output_ref:ParseLaneCandidatesArgsSchema.shape.output_ref,accept_partial:ParseLaneCandidatesArgsSchema.shape.accept_partial,accept_degraded:ParseLaneCandidatesArgsSchema.shape.accept_degraded,degraded:ParseLaneCandidatesArgsSchema.shape.degraded,row_format_version:ParseLaneCandidatesArgsSchema.shape.row_format_version,producer:ParseLaneCandidatesArgsSchema.shape.producer,expected_family:ParseLaneCandidatesArgsSchema.shape.expected_family,expected_micro_lane:ParseLaneCandidatesArgsSchema.shape.expected_micro_lane,use_lockfile:ParseLaneCandidatesArgsSchema.shape.use_lockfile,project_root:ParseLaneCandidatesArgsSchema.shape.project_root},async execute(args2,directory){let parsed=ParseLaneCandidatesArgsSchema.safeParse(args2);if(!parsed.success)return JSON.stringify({success:!1,failure_class:"invalid_args",message:"Invalid parse_lane_candidates arguments",errors:parsed.error.issues.map((issue3)=>`${issue3.path.join(".")}: ${issue3.message}`)},null,2);let{output_ref,accept_partial,accept_degraded,degraded,row_format_version,producer,expected_family,expected_micro_lane,use_lockfile,project_root}=parsed.data;if(project_root!==void 0){let absRoot=path215.resolve(project_root),absDir=path215.resolve(directory),rel=path215.relative(absDir,absRoot);if(rel===".."||rel.startsWith(`..${path215.sep}`)||path215.isAbsolute(rel))return JSON.stringify({success:!1,failure_class:"invalid_args",message:"project_root must resolve within the injected working directory",errors:[`project_root: ${project_root} is outside the project root ${directory}`]},null,2)}let loaded;try{loaded=readLaneOutput(directory,output_ref)}catch{loaded=null}if(!loaded){let relPath=REF_RE2.test(output_ref)?laneOutputRelativePath2(output_ref):"",absPath=relPath?validateSwarmPath(directory,relPath):"",artifactStatus=(absPath?existsSync115(absPath):!1)?"artifact-corrupted":"ref-not-found",refParts=output_ref.split(":"),hasValidRef=REF_RE2.test(output_ref)&&refParts.length===4,syntheticBatchId=hasValidRef?refParts[1]:"unknown",syntheticLaneId=hasValidRef?refParts[2]:"unknown",syntheticDigest="0".repeat(64),artifactInput2={output_ref,batchId:syntheticBatchId,laneId:syntheticLaneId,agent:"unknown",role:"unknown",digest:syntheticDigest,text:"",artifact_status:artifactStatus,source:"dispatch_lanes",produced_at:new Date().toISOString()},flags2={accept_partial,accept_degraded,degraded,row_format_version,...producer?{producer}:{}},result2=parseAndPersist(artifactInput2,flags2,{projectRoot:project_root??directory,useLockfile:use_lockfile,batchDigest:syntheticBatchId});return JSON.stringify(result2,null,2)}let artifact=loaded.artifact,artifactInput={output_ref:artifact.ref,batchId:artifact.batchId,laneId:artifact.laneId,agent:artifact.agent,role:artifact.role,...artifact.sessionId!==void 0?{sessionId:artifact.sessionId}:{},...artifact.parentSessionId!==void 0?{parentSessionId:artifact.parentSessionId}:{},digest:artifact.digest,text:artifact.text,transcriptIncomplete:artifact.transcriptIncomplete,artifact_status:"ok",source:artifact.source,produced_at:artifact.createdAt??artifact.updatedAt},flags={accept_partial,accept_degraded,degraded,row_format_version,...producer?{producer}:{},...expected_family?{expected_family}:{},...expected_micro_lane?{expected_micro_lane}:{}},result=parseAndPersist(artifactInput,flags,{projectRoot:project_root??directory,useLockfile:use_lockfile});return JSON.stringify(result,null,2)}});init_zod();init_config();init_plan_schema();init_schema();init_manager2();init_task_file();import*as fs140 from"node:fs";import*as path225 from"node:path";init_utils2();init_logger();init_state3();import*as fs131 from"node:fs";import*as path216 from"node:path";var APPROVAL_TTL_MS=86400000;function readEvidenceDir(directory,phase){try{let dirPath=validateSwarmPath(directory,path216.posix.join("evidence",String(phase)));if(!fs131.existsSync(dirPath))return[];return fs131.readdirSync(dirPath).filter((e)=>e.startsWith("full-auto-")&&e.endsWith(".json")).map((e)=>path216.join(dirPath,e))}catch{return[]}}function parseEvidence(filePath){try{let raw=fs131.readFileSync(filePath,"utf-8");return JSON.parse(raw)}catch(error93){warn(`[full-auto/phase-approval] failed to parse ${filePath}: ${error93 instanceof Error?error93.message:String(error93)}`);return}}function verifyFullAutoPhaseApproval(directory,sessionID,phase,config3){let fullAutoConfig=config3.full_auto;if(!sessionID)return{ok:!0,reason:"no sessionID — gate skipped"};if(!isFullAutoRunActive(directory,sessionID))return{ok:!0,reason:"no active Full-Auto run"};let failClosed=fullAutoConfig?.fail_closed!==!1,files=readEvidenceDir(directory,phase);if(files.length===0)return failClosed?{ok:!1,reason:`Full-Auto v2 active but no full-auto oversight evidence found at .swarm/evidence/${phase}/`}:{ok:!0,reason:"no evidence and fail_closed=false"};let phaseBoundary=files.map((f)=>parseEvidence(f)).filter((e)=>Boolean(e)).filter((e)=>e.phase===phase&&e.trigger_source==="phase_boundary"&&(e.verdict??"").toUpperCase()==="APPROVED");if(phaseBoundary.length===0)return failClosed?{ok:!1,reason:`Full-Auto v2 active but no phase-boundary oversight record found for phase ${phase}`}:{ok:!0,reason:"no phase-boundary record and fail_closed=false"};phaseBoundary.sort((a,b)=>{let ta=a.timestamp?Date.parse(a.timestamp):0;return(b.timestamp?Date.parse(b.timestamp):0)-ta});let latest=phaseBoundary[0],verdict=latest.verdict?.toUpperCase()??"";if(verdict!=="APPROVED")return{ok:!1,reason:`Full-Auto oversight verdict for phase ${phase} is ${verdict||"MISSING"} (required: APPROVED)`,evidence:latest};let FORWARD_SKEW_MS=300000,ts=latest.timestamp?Date.parse(latest.timestamp):0,age=Date.now()-ts;if(!ts||age<-FORWARD_SKEW_MS||age>APPROVAL_TTL_MS)return{ok:!1,reason:age<-FORWARD_SKEW_MS?`Full-Auto oversight evidence for phase ${phase} has a future timestamp (${latest.timestamp}); rejected as forged or clock-skewed`:`Full-Auto oversight evidence for phase ${phase} is stale (>24h)`,evidence:latest};if((Array.isArray(latest.evidence_checked)?latest.evidence_checked:[]).length===0){let exception=phaseIsExplicitlyNonCode(directory,phase),runState=loadFullAutoRunState(directory,sessionID),codeWorkObserved=(runState?.counters.coderDelegations??0)>0||(runState?.counters.toolCalls??0)>0;if(!exception||codeWorkObserved)return{ok:!1,reason:!exception?`Full-Auto oversight evidence for phase ${phase} has empty evidence_checked and the phase is not declared non-code in plan.json (required: at least one verification source)`:`Full-Auto oversight evidence for phase ${phase} has empty evidence_checked while run counters indicate code work was performed`,evidence:latest};return{ok:!0,reason:`Full-Auto oversight APPROVED at ${latest.timestamp} (non-code phase exception)`,evidence:latest}}return{ok:!0,reason:`Full-Auto oversight APPROVED at ${latest.timestamp}`,evidence:latest}}function phaseIsExplicitlyNonCode(directory,phase){try{let planPath=validateSwarmPath(directory,"plan.json");if(!fs131.existsSync(planPath))return!1;let raw=fs131.readFileSync(planPath,"utf-8"),plan=JSON.parse(raw),entry=(Array.isArray(plan.phases)?plan.phases:[]).find((p)=>p.id===phase||p.phase===phase);if(!entry)return!1;if(entry.non_code===!0)return!0;let kindOrType=(entry.kind??entry.type??"").toString().toLowerCase();return["docs","documentation","spec","specification","research","planning","plan","non_code","non-code","noncode"].includes(kindOrType)}catch(error93){return warn(`[full-auto/phase-approval] plan.json inspection failed: ${error93 instanceof Error?error93.message:String(error93)}`),!1}}init_gate_evidence();init_curator();init_curator_llm_factory();init_extractors();init_knowledge_curator();init_knowledge_reader();init_knowledge_store();init_knowledge_events();init_knowledge_types();function isReceipt(e){return(e.type==="applied"||e.type==="ignored"||e.type==="n_a"||e.type==="violated")&&typeof e.knowledge_id==="string"}function evaluateCritical(id,receipts){let mine=receipts.filter((r)=>r.knowledge_id===id);if(mine.length===0)return"no_verdict";let latestViolation=mine.filter((r)=>r.type==="violated").reduce((acc,r)=>acc===null||r.timestamp>acc?r.timestamp:acc,null),latestApplied=mine.filter((r)=>r.type==="applied").reduce((acc,r)=>acc===null||r.timestamp>acc?r.timestamp:acc,null),hasResolvedDecision=mine.some((r)=>(r.type==="ignored"||r.type==="n_a")&&typeof r.reason==="string"&&r.reason.trim().length>0);if(latestViolation!==null){if(latestApplied!==null&&latestApplied>=latestViolation)return null;return"unremediated_violation"}if(latestApplied!==null)return null;if(hasResolvedDecision)return null;return"no_verdict"}async function evaluatePhaseCriticalDirectives(params){let accept=new Set(params.acceptViolations??[]);try{let events=await readKnowledgeEvents(params.directory),retrievedThisPhase=events.filter((e)=>e.type==="retrieved"&&(!params.phaseLabel||e.phase===params.phaseLabel)),phaseStart=retrievedThisPhase.length>0?retrievedThisPhase.map((e)=>e.timestamp).reduce((a,b)=>{if(b===void 0)return a;if(a===void 0)return b;return a<b?a:b},void 0):null,criticalIds=await readCriticalIdsForPhase(params.directory,params.phaseLabel);if(criticalIds.length===0)return{blocked:!1,unresolved:[],overridden:[],failedClosed:!1};let receipts=events.filter(isReceipt).filter((r)=>{if(phaseStart===null||phaseStart===void 0)return!0;if(r.timestamp===void 0)return!1;return r.timestamp>=phaseStart}).map((r)=>({type:r.type,knowledge_id:r.knowledge_id,timestamp:r.timestamp,reason:r.reason})),unresolved=[],overridden=[];for(let id of criticalIds){let reason=evaluateCritical(id,receipts);if(reason===null)continue;if(accept.has(id)){overridden.push(id);continue}unresolved.push({id,reason})}return{blocked:unresolved.length>0,unresolved,overridden,failedClosed:!1}}catch{return{blocked:!0,unresolved:[],overridden:[],failedClosed:!0}}}async function readCriticalIdsForPhase(directory,phaseLabel){let ids=await collectPhaseDirectiveIds(directory,phaseLabel);if(ids.length===0)return[];let entries=await readEntriesById(directory);return ids.filter((id)=>{let e=entries.get(id);if(!e)return!1;if(!isActiveStatus(e.status))return!1;return e.directive_priority==="critical"})}async function recordDirectiveOverrides(directory,ids,justification,sessionId){for(let id of ids)await recordKnowledgeEvent(directory,{type:"override",trace_id:"",knowledge_id:id,session_id:sessionId??"unknown",agent:"architect",source:"reviewer",reason:`override: ${justification}`.slice(0,280)})}function formatDirectiveBlockMessage(unresolved){return["PHASE_COMPLETE_BLOCKED: unresolved critical knowledge directive(s):",...unresolved.map((u)=>{let why=u.reason==="no_verdict"?"no terminal verdict (applied/verified/ignored+reason/n_a+reason)":"violated with no subsequent applied/verified remediation";return` - ${u.id}: ${why}`}),"Resolve each by applying/verifying the directive, recording an explicit","ignored/n_a with a reason, or (architect only) accept_violations with a","written justification."].join(`
6070
- `)}init_review_receipt();init_skill_usage_log();init_utils2();init_file_locks();init_plan_schema();init_ledger();init_utils3();init_manager();import*as fs132 from"node:fs";import*as path217 from"node:path";var _fsInternals={mkdirSync:(...args2)=>fs132.mkdirSync(...args2),writeFileSync:(path218,data,encoding)=>fs132.writeFileSync(path218,data,encoding??"utf8"),readFileSync:(path218,encoding)=>fs132.readFileSync(path218,encoding??"utf8"),existsSync:(path218)=>fs132.existsSync(path218)};async function writeCheckpoint(directory){try{let plan=await loadPlan(directory);if(!plan)return;let exportDir=path217.join(directory,".swarm","plan-export");_fsInternals.mkdirSync(exportDir,{recursive:!0});let jsonPath=path217.join(exportDir,"SWARM_PLAN.json"),mdPath=path217.join(exportDir,"SWARM_PLAN.md");_fsInternals.writeFileSync(jsonPath,JSON.stringify(plan,null,2));let md=derivePlanMarkdown(plan),header=`<!--
6070
+ `)}init_review_receipt();init_skill_usage_log();init_utils2();init_file_locks();init_plan_schema();init_ledger();init_utils3();init_warning_buffer();init_logger();init_manager();import*as fs132 from"node:fs";import*as path217 from"node:path";var _fsInternals={mkdirSync:(...args2)=>fs132.mkdirSync(...args2),writeFileSync:(path218,data,encoding)=>fs132.writeFileSync(path218,data,encoding??"utf8"),readFileSync:(path218,encoding)=>fs132.readFileSync(path218,encoding??"utf8"),existsSync:(path218)=>fs132.existsSync(path218)};async function writeCheckpoint(directory){try{let plan=await loadPlan(directory);if(!plan)return;let exportDir=path217.join(directory,".swarm","plan-export");_fsInternals.mkdirSync(exportDir,{recursive:!0});let jsonPath=path217.join(exportDir,"SWARM_PLAN.json"),mdPath=path217.join(exportDir,"SWARM_PLAN.md");_fsInternals.writeFileSync(jsonPath,JSON.stringify(plan,null,2));let md=derivePlanMarkdown(plan),header=`<!--
6071
6071
  AUTO-GENERATED EXPORT/CHECKPOINT SNAPSHOT — DO NOT EDIT
6072
6072
  This file is NOT the live plan. It is a derived export artifact.
6073
6073
  - .swarm/plan-ledger.jsonl is the authoritative source of plan state.
6074
6074
  - .swarm/plan.json and .swarm/plan.md are derived projections.
6075
6075
  Regenerated on: save_plan and phase_complete.
6076
6076
  -->
6077
- `;_fsInternals.writeFileSync(mdPath,header+md)}catch(error93){console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error?error93.message:String(error93)}`)}}init_ledger();init_manager();init_curator_llm_factory();init_zod();init_config2();init_curator_decision_helpers();function computeDecayExpiry(memory,halfLifeDays,_now=new Date){if(memory.kind==="scratch")return;let halfLife=halfLifeDays[memory.kind]??0;if(halfLife<=0)return;let created=Date.parse(memory.createdAt);if(!Number.isFinite(created))return;let candidateMs=created+halfLife*86400000,existing=memory.expiresAt?Date.parse(memory.expiresAt):void 0;if(existing!==void 0&&Number.isFinite(existing)&&existing<=candidateMs)return;let candidate=new Date(candidateMs).toISOString();if(memory.expiresAt===candidate)return;return candidate}function isPastDecayHorizon(memory,halfLifeDays,now=new Date){if(memory.kind==="scratch")return!1;let halfLife=halfLifeDays[memory.kind]??0;if(halfLife<=0)return!1;let created=Date.parse(memory.createdAt);if(!Number.isFinite(created))return!1;return created+halfLife*86400000<=now.getTime()}init_scoring();var CONSOLIDATION_AGENT_ROLE="curator_consolidation",DistilledFactSchema=exports_external.object({text:exports_external.string().min(1).max(2000),kind:exports_external.enum(["user_preference","project_fact","architecture_decision","repo_convention","api_finding","code_pattern","test_pattern","failure_pattern","security_note","evidence","todo","scratch"]),confidence:exports_external.number().min(0).max(1),contradictsMemoryId:exports_external.string().regex(/^mem_[a-f0-9]{16}$/).optional()}),DistillationOutputSchema=exports_external.object({facts:exports_external.array(DistilledFactSchema).max(50)});function parseDistillationOutput(raw){let candidates=[],fenceMatch=raw.match(/```(?:json)?\s*([\s\S]*?)```/i);if(fenceMatch?.[1])candidates.push(fenceMatch[1].trim());let firstBrace=raw.indexOf("{"),lastBrace=raw.lastIndexOf("}");if(firstBrace!==-1&&lastBrace>firstBrace)candidates.push(raw.slice(firstBrace,lastBrace+1));candidates.push(raw.trim());for(let candidate of candidates)try{return DistillationOutputSchema.parse(JSON.parse(candidate)).facts}catch{}return[]}function deriveDecision(fact,existing,options){if(fact.text.includes(MEMORY_RECALL_SENTINEL))return{type:"skip",fact,reason:"contains recall sentinel"};if(fact.kind==="scratch")return{type:"skip",fact,reason:"scratch is not promoted to semantic memory"};let eligible=DURABLE_MEMORY_KINDS.has(fact.kind)&&fact.text.length<=CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH&&fact.confidence>=options.autoApplyMinConfidence,factTokens=tokenize(fact.text);for(let memory of existing)if(jaccard(factTokens,tokenize(memory.text))>=options.jaccardThreshold)return{type:"dedup",fact,duplicateOf:memory.id};if(fact.contradictsMemoryId){let target=existing.find((m)=>m.id===fact.contradictsMemoryId);if(target&&eligible)return{type:"supersede",fact,oldMemoryId:target.id};return{type:"proposal",fact,reason:target?"contradiction not auto-appliable (kind/length/confidence)":"contradiction target not found"}}if(!eligible){let reason=!DURABLE_MEMORY_KINDS.has(fact.kind)?`kind ${fact.kind} is not auto-promotable`:fact.text.length>CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH?"text exceeds promotable length":"confidence below auto-apply threshold";return{type:"proposal",fact,reason}}return{type:"add",fact}}function hasRealEvidence(evidenceRefs){return evidenceRefs.some((r)=>/^https?:\/\//i.test(r)||/^[a-f0-9]{40}$/i.test(r)||r.includes("/")||r.includes("\\"))}function sourceForDistilled(evidenceRefs,phaseNumber){let url3=evidenceRefs.find((r)=>/^https?:\/\//i.test(r));if(url3)return{type:"web",url:url3,createdBy:"curator_consolidation"};let file3=evidenceRefs.find((r)=>r.includes("/")||r.includes("\\"));if(file3)return{type:"file",filePath:file3,createdBy:"curator_consolidation"};return{type:"agent",ref:`consolidation:phase-${phaseNumber}`,createdBy:"curator_consolidation"}}function buildDistillationPrompt(cluster,relatedExisting){let episodic=cluster.map((p,i)=>{let text=p.proposedRecord?.text??p.rationale;return`[E${i+1}] kind=${p.proposedRecord?.kind??"n/a"} | ${text}`}).join(`
6077
+ `;_fsInternals.writeFileSync(mdPath,header+md)}catch(error93){log(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error?error93.message:String(error93)}`)}}init_ledger();init_manager();init_curator_llm_factory();init_zod();init_config2();init_curator_decision_helpers();function computeDecayExpiry(memory,halfLifeDays,_now=new Date){if(memory.kind==="scratch")return;let halfLife=halfLifeDays[memory.kind]??0;if(halfLife<=0)return;let created=Date.parse(memory.createdAt);if(!Number.isFinite(created))return;let candidateMs=created+halfLife*86400000,existing=memory.expiresAt?Date.parse(memory.expiresAt):void 0;if(existing!==void 0&&Number.isFinite(existing)&&existing<=candidateMs)return;let candidate=new Date(candidateMs).toISOString();if(memory.expiresAt===candidate)return;return candidate}function isPastDecayHorizon(memory,halfLifeDays,now=new Date){if(memory.kind==="scratch")return!1;let halfLife=halfLifeDays[memory.kind]??0;if(halfLife<=0)return!1;let created=Date.parse(memory.createdAt);if(!Number.isFinite(created))return!1;return created+halfLife*86400000<=now.getTime()}init_scoring();var CONSOLIDATION_AGENT_ROLE="curator_consolidation",DistilledFactSchema=exports_external.object({text:exports_external.string().min(1).max(2000),kind:exports_external.enum(["user_preference","project_fact","architecture_decision","repo_convention","api_finding","code_pattern","test_pattern","failure_pattern","security_note","evidence","todo","scratch"]),confidence:exports_external.number().min(0).max(1),contradictsMemoryId:exports_external.string().regex(/^mem_[a-f0-9]{16}$/).optional()}),DistillationOutputSchema=exports_external.object({facts:exports_external.array(DistilledFactSchema).max(50)});function parseDistillationOutput(raw){let candidates=[],fenceMatch=raw.match(/```(?:json)?\s*([\s\S]*?)```/i);if(fenceMatch?.[1])candidates.push(fenceMatch[1].trim());let firstBrace=raw.indexOf("{"),lastBrace=raw.lastIndexOf("}");if(firstBrace!==-1&&lastBrace>firstBrace)candidates.push(raw.slice(firstBrace,lastBrace+1));candidates.push(raw.trim());for(let candidate of candidates)try{return DistillationOutputSchema.parse(JSON.parse(candidate)).facts}catch{}return[]}function deriveDecision(fact,existing,options){if(fact.text.includes(MEMORY_RECALL_SENTINEL))return{type:"skip",fact,reason:"contains recall sentinel"};if(fact.kind==="scratch")return{type:"skip",fact,reason:"scratch is not promoted to semantic memory"};let eligible=DURABLE_MEMORY_KINDS.has(fact.kind)&&fact.text.length<=CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH&&fact.confidence>=options.autoApplyMinConfidence,factTokens=tokenize(fact.text);for(let memory of existing)if(jaccard(factTokens,tokenize(memory.text))>=options.jaccardThreshold)return{type:"dedup",fact,duplicateOf:memory.id};if(fact.contradictsMemoryId){let target=existing.find((m)=>m.id===fact.contradictsMemoryId);if(target&&eligible)return{type:"supersede",fact,oldMemoryId:target.id};return{type:"proposal",fact,reason:target?"contradiction not auto-appliable (kind/length/confidence)":"contradiction target not found"}}if(!eligible){let reason=!DURABLE_MEMORY_KINDS.has(fact.kind)?`kind ${fact.kind} is not auto-promotable`:fact.text.length>CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH?"text exceeds promotable length":"confidence below auto-apply threshold";return{type:"proposal",fact,reason}}return{type:"add",fact}}function hasRealEvidence(evidenceRefs){return evidenceRefs.some((r)=>/^https?:\/\//i.test(r)||/^[a-f0-9]{40}$/i.test(r)||r.includes("/")||r.includes("\\"))}function sourceForDistilled(evidenceRefs,phaseNumber){let url3=evidenceRefs.find((r)=>/^https?:\/\//i.test(r));if(url3)return{type:"web",url:url3,createdBy:"curator_consolidation"};let file3=evidenceRefs.find((r)=>r.includes("/")||r.includes("\\"));if(file3)return{type:"file",filePath:file3,createdBy:"curator_consolidation"};return{type:"agent",ref:`consolidation:phase-${phaseNumber}`,createdBy:"curator_consolidation"}}function buildDistillationPrompt(cluster,relatedExisting){let episodic=cluster.map((p,i)=>{let text=p.proposedRecord?.text??p.rationale;return`[E${i+1}] kind=${p.proposedRecord?.kind??"n/a"} | ${text}`}).join(`
6078
6078
  `),existing=relatedExisting.slice(0,20).map((m)=>`[${m.id}] kind=${m.kind} | ${m.text}`).join(`
6079
6079
  `);return["You are consolidating raw episodic memory into durable semantic facts.","","Episodic events (verbatim):",episodic,"","Existing durable memories (for dedup/contradiction):",existing||"(none)","",'Emit STRICT JSON only: {"facts":[{"text":..,"kind":..,"confidence":0-1,"contradictsMemoryId"?:"mem_..."}]}',"Rules: only emit facts directly supported by the cited episodic evidence.","If uncertain, omit the fact (emit fewer facts or an empty array).",`Use durable kinds (${Array.from(DURABLE_MEMORY_KINDS).join(", ")}); keep each fact under ${CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH} characters.`,"Set contradictsMemoryId only when a fact directly conflicts with an existing memory above.",'Never include the literal text "## Retrieved Swarm Memory".'].join(`
6080
6080
  `)}function aggregateEvidence(cluster,phaseNumber){let refs=new Set;for(let p of cluster)for(let ref of p.evidenceRefs)refs.add(ref);let list=Array.from(refs).slice(0,19);return list.push(`consolidation:phase-${phaseNumber}`),list}async function runConsolidationPass(input,deps){let{phaseNumber,runId,config:config3}=input,consolidation=config3.consolidation,base={skipped:!0,phaseNumber,clusterCount:0,clustersDeferred:0,decisionsEmitted:0,added:0,superseded:0,contradictionsDetected:0,deduped:0,proposed:0,memoriesDecayed:0,errored:0};if(!config3.enabled||!consolidation.enabled||!deps.gateway.isEnabled())return{...base,skipReason:"disabled"};let priorLog=await deps.readLog();if(priorLog.some((r)=>r.phaseNumber===phaseNumber))return{...base,skipReason:"already_consolidated"};let processedBefore=new Set(priorLog.flatMap((r)=>r.processedProposalIds)),startedAt=deps.now().toISOString(),logKey=runId??"unknown";await deps.logEvent({event:"consolidation_started",runId:logKey,phaseNumber,timestamp:startedAt});let pendingProposals=(await deps.gateway.listProposals({status:"pending"})).filter((p)=>p.proposedBy?.agentRole!==CONSOLIDATION_AGENT_ROLE&&!processedBefore.has(p.id)).sort((a,b)=>a.id.localeCompare(b.id)),existingMemories=await deps.gateway.listMemories({}),clusters=clusterByJaccard(pendingProposals,(p)=>p.proposedRecord?.text??p.rationale,consolidation.jaccardThreshold),processable=clusters.slice(0,consolidation.maxClustersPerPass),clustersDeferred=Math.max(0,clusters.length-processable.length);await deps.logEvent({event:"cluster_count",runId:logKey,phaseNumber,clusterCount:clusters.length});let result={...base,skipped:!1,clusterCount:clusters.length,clustersDeferred},processedProposalIds=new Set;if(!deps.llmDelegate){if(result.memoriesDecayed=await applyDecay(existingMemories,input,deps),deps.signal?.aborted)return{...result,skipped:!0,skipReason:"aborted"};return await finalize2(input,deps,result,startedAt,processedProposalIds),{...result,skipReason:"no_llm_delegate_decay_only"}}let seenFactTexts=new Set;for(let cluster of processable){if(deps.signal?.aborted)return{...result,skipped:!0,skipReason:"aborted"};for(let p of cluster)processedProposalIds.add(p.id);let raw;try{let prompt=buildDistillationPrompt(cluster,existingMemories);raw=await deps.llmDelegate("",prompt,deps.signal)}catch{result.errored++;continue}let facts=parseDistillationOutput(raw),evidenceRefs=aggregateEvidence(cluster,phaseNumber);for(let fact of facts){let normalized=fact.text.replace(/\s+/g," ").trim().toLowerCase();if(seenFactTexts.has(normalized))continue;seenFactTexts.add(normalized);let plan=deriveDecision(fact,existingMemories,{autoApplyMinConfidence:consolidation.autoApplyMinConfidence,jaccardThreshold:consolidation.jaccardThreshold});try{await executePlan(plan,evidenceRefs,input,deps,result)}catch{result.errored++}}}if(deps.signal?.aborted)return{...result,skipped:!0,skipReason:"aborted"};if(result.memoriesDecayed=await applyDecay(existingMemories,input,deps),deps.signal?.aborted)return{...result,skipped:!0,skipReason:"aborted"};return await finalize2(input,deps,result,startedAt,processedProposalIds),result}async function executePlan(plan,evidenceRefs,input,deps,result){let{phaseNumber}=input;if(plan.type==="skip")return;if(plan.type==="dedup"){result.deduped++;return}let newRecord={kind:plan.fact.kind,text:plan.fact.text,confidence:plan.fact.confidence,stability:"durable",source:sourceForDistilled(evidenceRefs,phaseNumber),metadata:{consolidatedFromPhase:phaseNumber}},rationale=`consolidation phase ${phaseNumber}`;if(((plan.type==="add"||plan.type==="supersede")&&EVIDENCE_REQUIRED_KINDS.has(plan.fact.kind)&&!hasRealEvidence(evidenceRefs)?"proposal":plan.type)==="proposal"){await deps.gateway.propose({operation:plan.type==="supersede"?"supersede":"add",kind:plan.fact.kind,text:plan.fact.text,rationale:plan.type==="proposal"?`${rationale}: ${plan.reason}`:`${rationale}: evidence-required kind lacks real evidence source`,evidenceRefs,...plan.type==="supersede"?{targetMemoryId:plan.oldMemoryId}:{}}),result.proposed++;return}if(plan.type==="supersede"){let proposal2=await deps.gateway.propose({operation:"supersede",kind:plan.fact.kind,text:plan.fact.text,targetMemoryId:plan.oldMemoryId,rationale,evidenceRefs});if(proposal2.status!=="pending"){result.proposed++;return}await deps.gateway.applyCuratorDecision({action:"supersede",proposalId:proposal2.id,oldMemoryId:plan.oldMemoryId,replacement:newRecord,reason:`contradiction superseded during phase ${phaseNumber} consolidation`}),result.superseded++,result.contradictionsDetected++,result.decisionsEmitted++;return}let proposal=await deps.gateway.propose({operation:"add",kind:plan.fact.kind,text:plan.fact.text,rationale,evidenceRefs});if(proposal.status!=="pending"){result.proposed++;return}await deps.gateway.applyCuratorDecision({action:"add",proposalId:proposal.id,memory:newRecord}),result.added++,result.decisionsEmitted++}async function applyDecay(memories,input,deps){let decayed=0,halfLives=input.config.consolidation.decayHalfLifeDays,now=deps.now();for(let memory of memories){if(deps.signal?.aborted)break;if(memory.metadata.deleted===!0||memory.supersededBy)continue;if(isPastDecayHorizon(memory,halfLives,now))continue;let nextExpiry=computeDecayExpiry(memory,halfLives,now);if(!nextExpiry)continue;try{await deps.gateway.upsertCurated({...memory,expiresAt:nextExpiry}),decayed++}catch{}}return decayed}async function finalize2(input,deps,result,startedAt,processedProposalIds){let{phaseNumber,runId}=input,logKey=runId??"unknown",completedAt=deps.now().toISOString();await deps.logEvent({event:"decisions_emitted",runId:logKey,phaseNumber,decisionsEmitted:result.decisionsEmitted}),await deps.logEvent({event:"contradictions_detected",runId:logKey,phaseNumber,contradictionsDetected:result.contradictionsDetected}),await deps.logEvent({event:"memories_decayed",runId:logKey,phaseNumber,memoriesDecayed:result.memoriesDecayed}),await deps.logEvent({event:"consolidation_completed",runId:logKey,phaseNumber,clusterCount:result.clusterCount,decisionsEmitted:result.decisionsEmitted,contradictionsDetected:result.contradictionsDetected,memoriesDecayed:result.memoriesDecayed,timestamp:completedAt}),await deps.appendLog({phaseNumber,runId,startedAt,completedAt,clusterCount:result.clusterCount,clustersDeferred:result.clustersDeferred,decisionsEmitted:result.decisionsEmitted,added:result.added,superseded:result.superseded,contradictionsDetected:result.contradictionsDetected,deduped:result.deduped,proposed:result.proposed,memoriesDecayed:result.memoriesDecayed,errored:result.errored,processedProposalIds:Array.from(processedProposalIds)})}init_consolidation_log();init_gateway();init_run_log();var CONSOLIDATION_TIMEOUT_MS=300000,runningByDirectory2=new Map;async function runMemoryConsolidation(req){let existing=runningByDirectory2.get(req.directory);if(existing)return existing;let run=(async()=>{if(!req.config.enabled||!req.config.consolidation.enabled)return{started:!1,reason:"disabled"};let gateway=createMemoryGateway({directory:req.directory,sessionID:req.sessionId,runId:req.sessionId,agentRole:"curator_consolidation"},{config:req.config}),controller=new AbortController,timer=setTimeout(()=>controller.abort(),CONSOLIDATION_TIMEOUT_MS);timer.unref?.();try{if(!gateway.isEnabled())return{started:!1,reason:"disabled"};let llmDelegate=createCuratorLLMDelegate(req.directory,"consolidation",req.sessionId),result=await runConsolidationPass({directory:req.directory,phaseNumber:req.phase,runId:req.sessionId,config:req.config},{gateway,llmDelegate,now:()=>new Date,logEvent:(event)=>appendMemoryRunLog(req.directory,req.sessionId,event),readLog:()=>readConsolidationLog(req.directory),appendLog:(record3)=>appendConsolidationLog(req.directory,record3),signal:controller.signal});return{started:!result.skipped,reason:result.skipReason,result}}finally{clearTimeout(timer),await gateway.dispose()}})();runningByDirectory2.set(req.directory,run);try{return await run}finally{runningByDirectory2.delete(req.directory)}}function runMemoryConsolidationFireAndForget(req,onComplete,onError){queueMicrotask(()=>{runMemoryConsolidation(req).then(onComplete).catch(onError)})}init_skill_consolidation();init_snapshot_writer();init_state2();init_telemetry();init_state();init_file_locks();import*as fs133 from"node:fs";import*as path218 from"node:path";init_state4();var DEFAULT_CONFIG3={phase_reviewer:!0,phase_critic:!0,integrated_diff_required:!1};function defaultReadPlanJson(dir){try{let planPath=path218.join(dir,".swarm","plan.json");if(!fs133.existsSync(planPath))return null;let raw=fs133.readFileSync(planPath,"utf-8"),plan=JSON.parse(raw);if(typeof plan!=="object"||plan===null||!Array.isArray(plan.phases))return null;return plan}catch{return null}}function readReviewerEvidenceFromFile(directory,phase){try{let evidencePath=path218.join(directory,".swarm","evidence",String(phase),"lean-turbo-reviewer.json");if(!fs133.existsSync(evidencePath))return null;let raw=fs133.readFileSync(evidencePath,"utf-8"),parsed=JSON.parse(raw);if(typeof parsed!=="object"||parsed===null||typeof parsed.verdict!=="string")return null;let verdict=parsed.verdict;if(verdict!=="APPROVED"&&verdict!=="NEEDS_REVISION"&&verdict!=="REJECTED")return null;return parsed}catch{return null}}function readCriticEvidenceFromFile(directory,phase){try{let evidencePath=path218.join(directory,".swarm","evidence",String(phase),"lean-turbo-critic.json");if(!fs133.existsSync(evidencePath))return null;let raw=fs133.readFileSync(evidencePath,"utf-8"),parsed=JSON.parse(raw);if(typeof parsed!=="object"||parsed===null||typeof parsed.verdict!=="string")return null;let verdict=parsed.verdict;if(verdict!=="APPROVED"&&verdict!=="NEEDS_REVISION"&&verdict!=="REJECTED"&&verdict!=="ESCALATE_TO_HUMAN")return null;return parsed}catch{return null}}function listLaneEvidenceSync(directory,phase){let evidenceDir=path218.join(directory,".swarm","evidence",String(phase),"lean-turbo"),entries;try{entries=fs133.readdirSync(evidenceDir)}catch{return[]}entries.sort();let laneIds=[];for(let entry of entries){if(!entry.endsWith(".json")||entry==="lean-turbo-phase.json")continue;laneIds.push(entry.slice(0,-5))}return laneIds}var _internals144={listActiveLocks,readPersisted:readPersisted3,readPlanJson:defaultReadPlanJson,readReviewerEvidence:readReviewerEvidenceFromFile,readCriticEvidence:readCriticEvidenceFromFile,listLaneEvidence,listLaneEvidenceSync,verifyLeanTurboPhaseReady};function validatePersistedShape(persisted){if(typeof persisted!=="object"||persisted===null)return!1;if(Array.isArray(persisted))return!1;if(typeof persisted.sessions!=="object")return!1;if(persisted.sessions===null)return!1;if(Array.isArray(persisted.sessions))return!1;return!0}function validateLanesArray(lanes){if(!Array.isArray(lanes))return!1;for(let lane of lanes){if(typeof lane!=="object"||lane===null)return!1;if(typeof lane.laneId!=="string")return!1;if(typeof lane.status!=="string")return!1}return!0}function validateDegradedTasksArray(degradedTasks){if(!Array.isArray(degradedTasks))return!1;for(let dt of degradedTasks){if(typeof dt!=="object"||dt===null)return!1;if(typeof dt.taskId!=="string")return!1}return!0}function verifyLeanTurboPhaseReady(directory,phase,sessionIDOrConfig,config3){let sessionID=typeof sessionIDOrConfig==="string"?sessionIDOrConfig:void 0,mergedConfig={...DEFAULT_CONFIG3,...typeof sessionIDOrConfig==="object"&&sessionIDOrConfig!==null?sessionIDOrConfig:config3??DEFAULT_CONFIG3},statePath=path218.join(directory,".swarm","turbo-state.json");if(!fs133.existsSync(statePath))return{ok:!1,reason:"Lean Turbo state unreadable or missing"};let persisted=_internals144.readPersisted(directory);if(!persisted)return{ok:!1,reason:"Lean Turbo state unreadable or missing"};if(!validatePersistedShape(persisted))return{ok:!1,reason:"Lean Turbo state unreadable or missing"};let runState=null;for(let sessionState of Object.values(persisted.sessions))if(typeof sessionState==="object"&&sessionState!==null&&sessionState.status==="running"&&sessionState.phase===phase&&sessionState.strategy==="lean"&&sessionState.sessionID===sessionID){runState=sessionState;break}if(!runState&&sessionID===void 0){for(let sessionState of Object.values(persisted.sessions))if(typeof sessionState==="object"&&sessionState!==null&&sessionState.status==="running"&&sessionState.phase===phase&&sessionState.strategy==="lean"){runState=sessionState;break}}if(!runState)return{ok:!1,reason:sessionID?`No active Lean Turbo session for phase ${phase} and session ${sessionID}`:`No active Lean Turbo session for phase ${phase}`};if(!validateLanesArray(runState.lanes))return{ok:!1,reason:`No active Lean Turbo session for phase ${phase}`};if(!validateDegradedTasksArray(runState.degradedTasks))return{ok:!1,reason:`No active Lean Turbo session for phase ${phase}`};if(runState.lanes.length===0&&(!Array.isArray(runState.serializedTasks)||runState.serializedTasks.length===0)&&(!Array.isArray(runState.degradedTasks)||runState.degradedTasks.length===0))return{ok:!1,reason:`No lane plan or fallback tasks found for phase ${phase}`};let laneIds=runState.lanes.map((l)=>l.laneId);if(runState.lanes.length>0){for(let lane of runState.lanes)if(lane.status!=="completed"&&lane.status!=="failed")return{ok:!1,reason:`Lane ${lane.laneId} is not completed (status: ${lane.status})`}}if(runState.lanes.length>0){let evidenceLaneIds=new Set(_internals144.listLaneEvidenceSync(directory,phase));for(let lane of runState.lanes)if((lane.status==="completed"||lane.status==="failed")&&!evidenceLaneIds.has(lane.laneId))return{ok:!1,reason:`Lane ${lane.laneId} is ${lane.status} but lane evidence file is missing`}}let activeLocks=_internals144.listActiveLocks(directory),phaseLaneIds=new Set(laneIds);for(let lock of activeLocks)if(lock.laneId&&phaseLaneIds.has(lock.laneId))return{ok:!1,reason:`Active locks remain for lane ${lock.laneId}`};let laneTaskIds=new Set;for(let lane of runState.lanes)if(Array.isArray(lane.taskIds))for(let taskId of lane.taskIds)laneTaskIds.add(taskId);let serialDegradedTasks=runState.degradedTasks.filter((dt)=>!laneTaskIds.has(dt.taskId));if(serialDegradedTasks.length>0){let plan=_internals144.readPlanJson(directory);if(!plan)return{ok:!1,reason:"Cannot verify degraded task status: plan.json unreadable or malformed"};for(let dt of serialDegradedTasks){if(!Array.isArray(plan.phases))return{ok:!1,reason:`Cannot verify degraded task ${dt.taskId}: plan.json malformed (phases is not an array)`};let planPhase=plan.phases.find((p)=>p&&typeof p==="object"&&p!==null&&p.id===phase);if(!planPhase)return{ok:!1,reason:`Cannot verify degraded task ${dt.taskId}: phase ${phase} not found in plan.json`};if(!Array.isArray(planPhase.tasks))return{ok:!1,reason:`Cannot verify degraded task ${dt.taskId}: plan.json malformed (phase ${phase} tasks is not an array)`};let task=planPhase.tasks.find((t)=>t&&typeof t==="object"&&t!==null&&t.id===dt.taskId);if(!task)return{ok:!1,reason:`Degraded task ${dt.taskId} not found in plan`};if(task.status!=="completed")return{ok:!1,reason:`Degraded task ${dt.taskId} not yet completed via standard flow`}}}let serializedTasks=runState.serializedTasks;if(Array.isArray(serializedTasks)&&serializedTasks.length>0){let plan=_internals144.readPlanJson(directory);if(!plan)return{ok:!1,reason:"Cannot verify serialized task status: plan.json unreadable or malformed"};if(!Array.isArray(plan.phases))return{ok:!1,reason:"Cannot verify serialized tasks: plan.json malformed (phases is not an array)"};let planPhase=plan.phases.find((p)=>p&&typeof p==="object"&&p!==null&&p.id===phase);if(!planPhase)return{ok:!1,reason:`Cannot verify serialized tasks: phase ${phase} not found in plan.json`};if(!Array.isArray(planPhase.tasks))return{ok:!1,reason:`Cannot verify serialized tasks: plan.json malformed (phase ${phase} tasks is not an array)`};for(let serTaskId of serializedTasks){let task=planPhase.tasks.find((t)=>t&&typeof t==="object"&&t!==null&&t.id===serTaskId);if(!task)return{ok:!1,reason:`Serialized task ${serTaskId} not found in plan`};if(task.status!=="completed")return{ok:!1,reason:`Serialized task ${serTaskId} not yet completed (status: ${task.status})`}}}if(mergedConfig.integrated_diff_required){let evidencePath=path218.join(directory,".swarm","evidence",String(phase),"lean-turbo-phase.json"),hasDiff=!1;try{let content=fs133.readFileSync(evidencePath,"utf-8");hasDiff=!!JSON.parse(content).integratedDiffSummary}catch{}if(!hasDiff)return{ok:!1,reason:`Integrated diff summary is required but missing for phase ${phase}`}}let reviewerVerdict=runState.lastReviewerVerdict;if(!reviewerVerdict)reviewerVerdict=_internals144.readReviewerEvidence(directory,phase)?.verdict??void 0;if(mergedConfig.phase_reviewer){if(reviewerVerdict!=="APPROVED")return{ok:!1,reason:"Integrated reviewer approval missing or rejected"}}let criticVerdict=runState.lastCriticVerdict;if(!criticVerdict)criticVerdict=_internals144.readCriticEvidence(directory,phase)?.verdict??void 0;if(mergedConfig.phase_critic){if(criticVerdict!=="APPROVED")return{ok:!1,reason:"Integrated critic approval missing or rejected"}}return{ok:!0,reason:`Phase ${phase} is ready to advance`,evidence:{lanes:laneIds,degradedTasks:runState.degradedTasks.map((dt)=>dt.taskId),reviewerVerdict:reviewerVerdict??runState.lastReviewerVerdict,criticVerdict:criticVerdict??runState.lastCriticVerdict}}}init_logger();init_create_tool();init_store2();async function runArchitectureSupervisorGate(ctx){let{phase,dir,pluginConfig,agentsDispatched,safeWarn}=ctx,asConfig=pluginConfig.architectural_supervision,summarizeFindings=(findings)=>{if(!Array.isArray(findings)||findings.length===0)return"";let details=findings.map((f)=>f&&typeof f==="object"&&typeof f.description==="string"?f.description:void 0).filter((d)=>Boolean(d));return details.length>0?`
@@ -6117,7 +6117,7 @@ ${page.content}`;if(page.endLine<page.totalLines){let remaining=page.totalLines-
6117
6117
  ${paginatedContent}`;if(endLine<totalLines){let remaining=totalLines-endLine;response+=`
6118
6118
 
6119
6119
  ... ${remaining} more line${remaining===1?"":"s"}. Use offset=${endLine} to retrieve more.`}return response}});init_sast_scan();init_zod();init_plan_schema();init_qa_gate_profile();init_file_locks();import*as fs144 from"node:fs";import*as path231 from"node:path";init_ledger();init_manager();init_utils3();init_effective_spec();init_state2();init_create_tool();function executionProfilesEqual(a,b){return a.parallelization_enabled===b.parallelization_enabled&&a.max_concurrent_tasks===b.max_concurrent_tasks&&a.council_parallel===b.council_parallel&&a.locked===b.locked&&a.auto_proceed===b.auto_proceed}function evaluateRequirementCoverage(specContent,args2){if(!specContent)return null;let requirements=extractRequirements(specContent);if(requirements.length===0)return null;let covered=[],missing=[];for(let requirement of requirements){let mappedTaskIds=[],idPattern=new RegExp(`\\b${requirement.id}\\b`,"i");for(let phase of args2.phases)for(let task of phase.tasks){let taskText=`${task.description}
6120
- ${task.acceptance??""}`;if(idPattern.test(taskText))mappedTaskIds.push(task.id)}let entry={id:requirement.id,obligation:requirement.obligation,text:requirement.text,mapped_task_ids:mappedTaskIds};if(mappedTaskIds.length>0)covered.push(entry);else missing.push(entry)}let blockingMissing=missing.filter((entry)=>entry.obligation==="MUST"||entry.obligation==="SHALL");return{status:blockingMissing.length>0?args2.confirm_requirement_coverage_gaps===!0?"override":"failed":"passed",total_requirements:requirements.length,covered_count:covered.length,missing_count:missing.length,blocking_missing_count:blockingMissing.length,covered,missing,blocking_missing:blockingMissing}}function detectPlaceholderContent(args2){let issues=[],placeholderPattern=/^\[\w[\w\s]*\]$/;if(placeholderPattern.test(args2.title.trim()))issues.push(`Plan title appears to be a template placeholder: "${args2.title}"`);for(let phase of args2.phases){if(placeholderPattern.test(phase.name.trim()))issues.push(`Phase ${phase.id} name appears to be a template placeholder: "${phase.name}"`);for(let task of phase.tasks)if(placeholderPattern.test(task.description.trim()))issues.push(`Task ${task.id} description appears to be a template placeholder: "${task.description}"`)}return issues}function validateTargetWorkspace(target,source){if(target===void 0||target===null)return`Target workspace is required: ${source} not provided`;let trimmed=target.trim();if(trimmed.length===0)return`Target workspace cannot be empty or whitespace: ${source}`;if(trimmed.replace(/\\/g,"/").includes(".."))return`Target workspace cannot contain path traversal: ${source} contains ".."`;return}async function executeSavePlan(args2,fallbackDir){let validationErrors=[];for(let phase of args2.phases){if(!Number.isInteger(phase.id)||phase.id<=0)validationErrors.push(`Phase ${phase.id} has invalid id: must be a positive integer`);let taskIdPattern=/^\d+\.\d+(\.\d+)*$/;for(let task of phase.tasks)if(!taskIdPattern.test(task.id))validationErrors.push(`Task '${task.id}' in phase ${phase.id} has invalid id format: must match N.M pattern (e.g. '1.1', '2.3')`)}if(validationErrors.length>0)return{success:!1,message:"Plan rejected: invalid phase or task IDs",errors:validationErrors,recovery_guidance:'Phase IDs must be positive integers: 1, 2, 3 (not 0, -1, or decimals). Task IDs must use N.M format: "1.1", "2.3", "3.1". Call save_plan again with corrected ids. Never write .swarm/plan.json or .swarm/plan.md directly.'};let placeholderIssues=detectPlaceholderContent(args2);if(placeholderIssues.length>0)return{success:!1,message:"Plan rejected: contains template placeholder content",errors:placeholderIssues,recovery_guidance:"Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."};let targetWorkspace=args2.working_directory??fallbackDir,workspaceError=validateTargetWorkspace(targetWorkspace,args2.working_directory?"working_directory":"fallbackDir");if(workspaceError)return{success:!1,message:"Target workspace validation failed: provide working_directory parameter to save_plan",errors:[workspaceError],recovery_guidance:"Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."};if(args2.working_directory&&fallbackDir){let resolvedTarget=path231.resolve(args2.working_directory),resolvedRoot=path231.resolve(fallbackDir),fallbackExists=!1;try{fs144.accessSync(resolvedRoot,fs144.constants.F_OK),fallbackExists=!0}catch{fallbackExists=!1}if(fallbackExists){if(resolvedTarget.startsWith(resolvedRoot+path231.sep))return{success:!1,message:`working_directory must be the project root. Got "${args2.working_directory}" (resolves to "${resolvedTarget}"), which is a subdirectory of fallback "${resolvedRoot}". Omit working_directory or pass the project root explicitly.`,errors:[`working_directory "${resolvedTarget}" is a subdirectory of fallback "${resolvedRoot}"`],recovery_guidance:`Pass working_directory: "${resolvedRoot}" or omit the field entirely.`}}}let specMtime,specHash,specContent;if(process.env.SWARM_SKIP_SPEC_GATE!=="1"){let spec=readEffectiveSpecSync(targetWorkspace);if(!spec)return{success:!1,message:"SPEC_REQUIRED: an effective spec (native .swarm/spec.md, OpenSpec openspec/specs or openspec/changes, or Spec-Kit .specify/) must exist before saving a plan.",errors:["No effective spec found — .swarm/spec.md is absent and no OpenSpec/Spec-Kit projection succeeded."],recovery_guidance:"Obtain explicit user consent, then run /swarm sdd project (agent-invocable) to materialize an effective spec from SDD sources. If .swarm/spec.md already exists, pass --overwrite after consent. Alternatively, run /swarm specify to author a native spec. Never write .swarm/plan.json or .swarm/plan.md directly."};specMtime=spec.mtime??void 0,specHash=spec.hash,specContent=spec.content;try{let snapshotPath=path231.join(targetWorkspace,".swarm","spec-snapshot.md");await fs144.promises.writeFile(snapshotPath,spec.content,"utf-8")}catch{}}if(process.env.SWARM_SKIP_GATE_SELECTION!=="1"){let contextPath=path231.join(targetWorkspace,".swarm","context.md"),contextContent="";try{contextContent=await fs144.promises.readFile(contextPath,"utf8")}catch{}if(!contextContent.includes("## Pending QA Gate Selection")){let candidatePlanId=derivePlanId({swarm:args2.swarm_id,title:args2.title}),existingProfile=null;try{existingProfile=getProfile(targetWorkspace,candidatePlanId)}catch{}if(!existingProfile)return{success:!1,message:'QA_GATE_SELECTION_REQUIRED: QA gate selection has not been completed. Present the gate selection question to the user (step 5b of MODE: SPECIFY or Phase 6 of MODE: BRAINSTORM), write their response to .swarm/context.md under "## Pending QA Gate Selection", then retry save_plan.',errors:["Missing ## Pending QA Gate Selection in .swarm/context.md","No existing QaGateProfile found for this plan"],recovery_guidance:"Do not call set_qa_gates with assumed values. Present the gate dialogue, wait for the user's answer, write it to context.md, then retry save_plan."}}}let requirementCoverage=evaluateRequirementCoverage(specContent,args2);if(requirementCoverage?.status==="failed"&&args2.confirm_requirement_coverage_gaps!==!0)return{success:!1,message:"REQUIREMENT_COVERAGE_GAPS: save_plan rejected because required FR-### MUST/SHALL requirements are not mapped to any task.",errors:requirementCoverage.blocking_missing.map((requirement)=>`${requirement.id} (${requirement.obligation}): ${requirement.text}`),recovery_guidance:"Add each required FR-### id to a task description or acceptance criterion, or retry with confirm_requirement_coverage_gaps: true only after surfacing the gaps to the user.",requirement_coverage:requirementCoverage};let dir=targetWorkspace,existingStatusMap=new Map,priorTaskIds=new Set,preservedExecutionProfile;{let existing=null;try{existing=await loadPlanJsonOnly(dir)}catch{}if(existing){for(let phase of existing.phases)for(let task of phase.tasks)priorTaskIds.add(task.id);if(!args2.reset_statuses)for(let phase of existing.phases)for(let task of phase.tasks)existingStatusMap.set(task.id,task.status);if(args2.confirm_identity_change!==!0){let existingId=derivePlanId(existing),incomingId=derivePlanId({swarm:args2.swarm_id,title:args2.title});if(existingId!==incomingId)return{success:!1,message:"PLAN_IDENTITY_MISMATCH: The incoming plan identity does not match the existing plan. To overwrite with a new identity, set confirm_identity_change: true.",errors:[`Existing plan identity: ${existingId} (swarm: "${existing.swarm}", title: "${existing.title}")`,`Incoming plan identity: ${incomingId} (swarm: "${args2.swarm_id}", title: "${args2.title}")`],recovery_guidance:"Verify the title and swarm_id match the intended plan. If the identity change is intentional, retry with confirm_identity_change: true. Never write .swarm/plan.json or .swarm/plan.md directly."}}if(existing.execution_profile?.locked){if(args2.execution_profile!==void 0&&!args2.reset_statuses){let requestedProfile=ExecutionProfileSchema.safeParse({...existing.execution_profile,...args2.execution_profile});if(!requestedProfile.success)return{success:!1,message:"Invalid execution_profile: schema validation failed",errors:requestedProfile.error.issues.map((i)=>`${i.path.join(".")}: ${i.message}`),recovery_guidance:"Check execution_profile fields: parallelization_enabled (boolean), max_concurrent_tasks (integer 1-64), council_parallel (boolean), locked (boolean), auto_proceed (boolean)."};if(executionProfilesEqual(existing.execution_profile,requestedProfile.data))preservedExecutionProfile=existing.execution_profile;else return{success:!1,message:"EXECUTION_PROFILE_LOCKED: The execution_profile for this plan is locked and cannot be changed.",errors:["execution_profile.locked is true — to change the profile you must first unlock it via a separate plan revision that explicitly sets locked: false, or reset the plan with reset_statuses."],recovery_guidance:"Remove the execution_profile field from this save_plan call to preserve the locked profile, or use reset_statuses: true to start fresh (this clears the lock). Never modify execution_profile directly in plan.json."}}else if(!args2.reset_statuses)preservedExecutionProfile=existing.execution_profile}else preservedExecutionProfile=existing.execution_profile}}let resolvedProfile=preservedExecutionProfile;if(args2.execution_profile!==void 0){let merged={...preservedExecutionProfile??{},...args2.execution_profile},parsed=ExecutionProfileSchema.safeParse(merged);if(!parsed.success)return{success:!1,message:"Invalid execution_profile: schema validation failed",errors:parsed.error.issues.map((i)=>`${i.path.join(".")}: ${i.message}`),recovery_guidance:"Check execution_profile fields: parallelization_enabled (boolean), max_concurrent_tasks (integer 1-64), council_parallel (boolean), locked (boolean)."};resolvedProfile=parsed.data}let incomingTaskIds=new Set;for(let phase of args2.phases)for(let task of phase.tasks)incomingTaskIds.add(task.id);let missingTaskIds=[];for(let id of priorTaskIds)if(!incomingTaskIds.has(id))missingTaskIds.push(id);let rawRemovedIds=args2.removed_task_ids??[];if(rawRemovedIds.length>0){let seen=new Set;for(let id of rawRemovedIds){if(seen.has(id))return{success:!1,message:"PLAN_TASK_REMOVAL_INVALID: removed_task_ids contains duplicate entries",errors:[`Duplicate id in removed_task_ids: "${id}"`],recovery_guidance:"Deduplicate removed_task_ids and retry save_plan."};seen.add(id)}for(let id of rawRemovedIds)if(incomingTaskIds.has(id))return{success:!1,message:"PLAN_TASK_REMOVAL_INVALID: removed_task_ids contains a task that also appears in args.phases",errors:[`Task "${id}" appears in both removed_task_ids and args.phases — these are contradictory`],recovery_guidance:"A task cannot be both kept and removed in the same save_plan call. Either drop it from args.phases or remove it from removed_task_ids."};for(let id of rawRemovedIds)if(!priorTaskIds.has(id))return{success:!1,message:"PLAN_TASK_REMOVAL_INVALID: removed_task_ids contains an id that was not in the prior plan",errors:[`Task "${id}" is in removed_task_ids but not present in the prior plan`],recovery_guidance:"Re-read the prior plan and update removed_task_ids to only list tasks that actually existed."}}let resolvedRemovedIds=[...rawRemovedIds],resolvedRemovalReason=args2.removal_reason;if(args2.reset_statuses===!0&&missingTaskIds.length>0){if(args2.confirm_destructive_reset!==!0)return{success:!1,message:"PLAN_DESTRUCTIVE_RESET_NOT_CONFIRMED: reset_statuses with missing tasks requires confirm_destructive_reset: true",errors:[`reset_statuses: true would drop ${missingTaskIds.length} task(s) from the prior plan: ${missingTaskIds.join(", ")}`],recovery_guidance:"Surface the list of dropped tasks to the user and confirm intent before retrying. Pass confirm_destructive_reset: true (with reset_statuses: true) to acknowledge the destructive reset, or list removed_task_ids explicitly with a removal_reason."};if(rawRemovedIds.length===0)resolvedRemovedIds=[...missingTaskIds],resolvedRemovalReason="destructive reset acknowledged"}if(resolvedRemovedIds.length>0){if((resolvedRemovalReason??"").trim().length===0)return{success:!1,message:"PLAN_TASK_REMOVAL_INVALID: removal_reason is required when removed_task_ids is non-empty",errors:["removal_reason must be a non-empty, non-whitespace string"],recovery_guidance:"Provide a removal_reason describing why these tasks are being dropped."}}if(missingTaskIds.length>0){let ackSet=new Set(resolvedRemovedIds),unacked=missingTaskIds.filter((id)=>!ackSet.has(id));if(unacked.length>0)return{success:!1,message:"PLAN_TASK_REMOVAL_NOT_ACKNOWLEDGED: this save would silently drop tasks from the prior plan",errors:[`The following prior tasks are missing from the new save and were not listed in removed_task_ids: ${unacked.join(", ")}`],recovery_guidance:`Re-read the current plan, then retry save_plan with removed_task_ids: ${JSON.stringify(unacked)} and a non-empty removal_reason. Tasks not yet finished (status pending/in_progress/blocked) MUST NOT be removed without explicit user confirmation.`}}let plan={schema_version:"1.0.0",title:args2.title,swarm:args2.swarm_id,migration_status:"native",current_phase:args2.phases[0]?.id,specMtime,specHash,...resolvedProfile!==void 0?{execution_profile:resolvedProfile}:{},phases:args2.phases.map((phase)=>{return{id:phase.id,name:phase.name,status:"pending",tasks:phase.tasks.map((task)=>{return{id:task.id,phase:phase.id,status:existingStatusMap.get(task.id)??"pending",size:task.size??"small",description:task.description,depends:task.depends??[],acceptance:task.acceptance,files_touched:[]}})}})},tasksCount=plan.phases.reduce((acc,phase)=>acc+phase.tasks.length,0),lockTaskId=`save-plan-${Date.now()}`,planFilePath="plan.json";try{let lockResult=await tryAcquireLock(dir,planFilePath,"architect",lockTaskId);if(!lockResult.acquired)return{success:!1,message:`Plan write blocked: file is locked by ${lockResult.existing?.agent??"another agent"} (task: ${lockResult.existing?.taskId??"unknown"})`,errors:["Concurrent plan write detected — retry after the current write completes"],recovery_guidance:"Wait a moment and retry save_plan. The lock will expire automatically if the holding agent fails."};try{await savePlan(dir,plan,{preserveCompletedStatuses:!args2.reset_statuses,...resolvedRemovedIds.length>0?{acknowledged_removals:{ids:resolvedRemovedIds,reason:(resolvedRemovalReason??"").trim(),source:"save_plan_tool"}}:{}});let savedPlan=await loadPlanJsonOnly(dir);if(savedPlan)await takeSnapshotWithRetry(dir,savedPlan);if(resolvedProfile!==void 0&&savedPlan){let planId=derivePlanId(plan),planHashAfter=computePlanHash(savedPlan);if(JSON.stringify(resolvedProfile)!==JSON.stringify(preservedExecutionProfile))await appendLedgerEvent(dir,{event_type:"execution_profile_set",source:"save_plan",plan_id:planId,payload:{execution_profile:resolvedProfile}},{planHashAfter}).catch(()=>{});let wasAlreadyLocked=preservedExecutionProfile?.locked===!0;if(resolvedProfile.locked&&!wasAlreadyLocked)await appendLedgerEvent(dir,{event_type:"execution_profile_locked",source:"save_plan",plan_id:planId},{planHashAfter}).catch(()=>{})}await writeCheckpoint(dir).catch(()=>{});try{let markerPath=path231.join(dir,".swarm",".plan-write-marker"),marker=JSON.stringify({source:"save_plan",timestamp:new Date().toISOString(),phases_count:plan.phases.length,tasks_count:tasksCount});await fs144.promises.writeFile(markerPath,marker,"utf8")}catch{}let warnings=[],criticReviewFound=!1;for(let[,session]of swarmState.agentSessions)if(session.phaseAgentsDispatched?.has("critic")||session.lastCompletedPhaseAgentsDispatched?.has("critic")){criticReviewFound=!0;break}if(!criticReviewFound)warnings.push("No critic review detected before plan save. Consider delegating to critic for plan validation.");if(requirementCoverage?.status==="override"){let missingIds=requirementCoverage.blocking_missing.map((requirement)=>requirement.id).join(", ");warnings.push(`Requirement coverage override used. Missing required FR mappings: ${missingIds}`)}return{success:!0,message:"Plan saved successfully",plan_path:path231.join(dir,".swarm","plan.json"),phases_count:plan.phases.length,tasks_count:tasksCount,...requirementCoverage?{requirement_coverage:requirementCoverage}:{},...resolvedProfile!==void 0?{execution_profile:resolvedProfile}:{},...warnings.length>0?{warnings}:{}}}finally{if(lockResult.acquired&&lockResult.lock._release)await lockResult.lock._release().catch(()=>{})}}catch(error93){if(error93 instanceof PlanTaskRemovalNotAcknowledgedError){let ids=error93.missingTasks.map((t)=>t.id);return{success:!1,message:"PLAN_TASK_REMOVAL_NOT_ACKNOWLEDGED: this save would silently drop tasks from the prior plan",errors:[error93.message],recovery_guidance:`Re-read the current plan, then retry save_plan with removed_task_ids: ${JSON.stringify(ids)} and a non-empty removal_reason.`}}return{success:!1,message:"Failed to save plan: retry with save_plan after resolving the error above",errors:[error93 instanceof Error?error93.message:String(error93)],recovery_guidance:"Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."}}}var save_plan=createSwarmTool({description:"Save or revise a structured implementation plan to .swarm/plan.json and .swarm/plan.md. "+"Use this tool for all structural plan changes on an existing plan (adding/removing tasks, updating descriptions, dependencies, or phase names) — existing task statuses are preserved by default (set reset_statuses: true to start fresh). "+"Task descriptions and phase names MUST contain real content from the spec — "+"bracket placeholders like [task] or [Project] will be rejected.",args:{title:exports_external.string().min(1).describe("Plan title — the REAL project name from the spec. NOT a placeholder like [Project]."),swarm_id:exports_external.string().min(1).describe('Swarm identifier (e.g. "mega")'),phases:exports_external.array(exports_external.object({id:exports_external.number().int().min(1).describe("Phase number — a positive integer starting at 1. Use 1, 2, 3, etc."),name:exports_external.string().min(1).describe("Descriptive phase name derived from the spec"),tasks:exports_external.array(exports_external.object({id:exports_external.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/,'Task ID must be in N.M format, e.g. "1.1"').describe('Task ID in N.M format, e.g. "1.1", "2.3"'),description:exports_external.string().min(1).describe("Specific task description from the spec. NOT a placeholder like [task]."),size:exports_external.enum(["small","medium","large"]).optional().describe("Task size estimate (default: small)"),depends:exports_external.array(exports_external.string()).optional().describe('Task IDs this task depends on, e.g. ["1.1", "1.2"]'),acceptance:exports_external.string().optional().describe("Acceptance criteria for this task")})).min(1).describe("Tasks in this phase")})).min(1).describe("Implementation phases"),working_directory:exports_external.string().optional().describe("Working directory (explicit path, required - no fallback)"),reset_statuses:exports_external.boolean().optional().describe("When true, reset ALL task statuses to pending regardless of prior completion state. Use only when deliberately re-planning a phase from scratch. Default false (preserves existing task statuses across plan revisions)."),removed_task_ids:exports_external.array(exports_external.string()).optional().describe("Task IDs that are present in the prior plan but intentionally being removed by this save. Every task missing from `phases` MUST be enumerated here, otherwise save_plan rejects with PLAN_TASK_REMOVAL_NOT_ACKNOWLEDGED. Tasks not yet finished (status pending/in_progress/blocked) MUST NOT be removed without explicit user confirmation."),removal_reason:exports_external.string().optional().describe("Required when removed_task_ids is non-empty. Human-readable reason recorded on each task_removed ledger event."),confirm_destructive_reset:exports_external.boolean().optional().describe("Required when reset_statuses is true AND at least one task is missing from the new plan. Set true to acknowledge that the destructive reset drops unfinished work. When set together with reset_statuses, save_plan auto-populates removed_task_ids from the missing set."),confirm_identity_change:exports_external.boolean().optional().describe("When true, allows overwriting an existing plan that has a different identity (swarm_id + title). Without this flag, save_plan rejects with PLAN_IDENTITY_MISMATCH if the identity differs."),confirm_requirement_coverage_gaps:exports_external.boolean().optional().describe("When true, allows saving a plan even when required FR-### MUST/SHALL requirements from the effective spec are not explicitly mapped in task descriptions or acceptance criteria. Use only after surfacing the structured requirement_coverage gaps to the user."),execution_profile:exports_external.object({parallelization_enabled:exports_external.boolean().optional().describe("When true, enables parallel task dispatch for this plan. Default false (serial)."),max_concurrent_tasks:exports_external.number().int().min(1).max(64).optional().describe("Maximum tasks that may run concurrently when parallelization is enabled. Default 10."),council_parallel:exports_external.boolean().optional().describe("When true, council review phases may run in parallel. Default true."),locked:exports_external.boolean().optional().describe("When true, locks the profile — future save_plan calls that include "+"execution_profile will be rejected (fail-closed). Unlock by resetting the plan (reset_statuses: true)."),auto_proceed:exports_external.boolean().optional().describe("When true, the architect advances to the next phase automatically without asking for confirmation. Default false.")}).optional().describe("Architect-facing concurrency controls. Once locked, cannot be changed without resetting. Omit to preserve the existing profile.")},execute:async(args2,_directory)=>{return JSON.stringify(await executeSavePlan(args2,_directory),null,2)}});init_zod();init_manager2();import*as fs145 from"node:fs";import*as path232 from"node:path";init_utils();function parsePubspecLock(content){let components=[];if(!content.match(/^packages:\s*$/m))return components;let lines=content.split(`
6120
+ ${task.acceptance??""}`;if(idPattern.test(taskText))mappedTaskIds.push(task.id)}let entry={id:requirement.id,obligation:requirement.obligation,text:requirement.text,mapped_task_ids:mappedTaskIds};if(mappedTaskIds.length>0)covered.push(entry);else missing.push(entry)}let blockingMissing=missing.filter((entry)=>entry.obligation==="MUST"||entry.obligation==="SHALL");return{status:blockingMissing.length>0?args2.confirm_requirement_coverage_gaps===!0?"override":"failed":"passed",total_requirements:requirements.length,covered_count:covered.length,missing_count:missing.length,blocking_missing_count:blockingMissing.length,covered,missing,blocking_missing:blockingMissing}}function detectPlaceholderContent(args2){let issues=[],placeholderPattern=/^\[\w[\w\s]*\]$/;if(placeholderPattern.test(args2.title.trim()))issues.push(`Plan title appears to be a template placeholder: "${args2.title}"`);for(let phase of args2.phases){if(placeholderPattern.test(phase.name.trim()))issues.push(`Phase ${phase.id} name appears to be a template placeholder: "${phase.name}"`);for(let task of phase.tasks)if(placeholderPattern.test(task.description.trim()))issues.push(`Task ${task.id} description appears to be a template placeholder: "${task.description}"`)}return issues}function validateTargetWorkspace(target,source){if(target===void 0||target===null)return`Target workspace is required: ${source} not provided`;let trimmed=target.trim();if(trimmed.length===0)return`Target workspace cannot be empty or whitespace: ${source}`;if(trimmed.replace(/\\/g,"/").includes(".."))return`Target workspace cannot contain path traversal: ${source} contains ".."`;return}async function executeSavePlan(args2,fallbackDir){let validationErrors=[];for(let phase of args2.phases){if(!Number.isInteger(phase.id)||phase.id<=0)validationErrors.push(`Phase ${phase.id} has invalid id: must be a positive integer`);let taskIdPattern=/^\d+\.\d+(\.\d+)*$/;for(let task of phase.tasks)if(!taskIdPattern.test(task.id))validationErrors.push(`Task '${task.id}' in phase ${phase.id} has invalid id format: must match N.M pattern (e.g. '1.1', '2.3')`)}if(validationErrors.length>0)return{success:!1,message:"Plan rejected: invalid phase or task IDs",errors:validationErrors,recovery_guidance:'Phase IDs must be positive integers: 1, 2, 3 (not 0, -1, or decimals). Task IDs must use N.M format: "1.1", "2.3", "3.1". Call save_plan again with corrected ids. Never write .swarm/plan.json or .swarm/plan.md directly.'};let placeholderIssues=detectPlaceholderContent(args2);if(placeholderIssues.length>0)return{success:!1,message:"Plan rejected: contains template placeholder content",errors:placeholderIssues,recovery_guidance:"Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."};let targetWorkspace=args2.working_directory??fallbackDir,workspaceError=validateTargetWorkspace(targetWorkspace,args2.working_directory?"working_directory":"fallbackDir");if(workspaceError)return{success:!1,message:"Target workspace validation failed: provide working_directory parameter to save_plan",errors:[workspaceError],recovery_guidance:"Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."};if(args2.working_directory&&fallbackDir){let resolvedTarget=path231.resolve(args2.working_directory),resolvedRoot=path231.resolve(fallbackDir),fallbackExists=!1;try{fs144.accessSync(resolvedRoot,fs144.constants.F_OK),fallbackExists=!0}catch{fallbackExists=!1}if(fallbackExists){if(resolvedTarget.startsWith(resolvedRoot+path231.sep))return{success:!1,message:`working_directory must be the project root. Got "${args2.working_directory}" (resolves to "${resolvedTarget}"), which is a subdirectory of fallback "${resolvedRoot}". Omit working_directory or pass the project root explicitly.`,errors:[`working_directory "${resolvedTarget}" is a subdirectory of fallback "${resolvedRoot}"`],recovery_guidance:`Pass working_directory: "${resolvedRoot}" or omit the field entirely.`}}}let specMtime,specHash,specContent;if(process.env.SWARM_SKIP_SPEC_GATE!=="1"){let spec=readEffectiveSpecSync(targetWorkspace);if(!spec)return{success:!1,message:"SPEC_REQUIRED: an effective spec (native .swarm/spec.md, OpenSpec openspec/specs or openspec/changes, or Spec-Kit .specify/) must exist before saving a plan.",errors:["No effective spec found — .swarm/spec.md is absent and no OpenSpec/Spec-Kit projection succeeded."],recovery_guidance:"Obtain explicit user consent, then run /swarm sdd project (agent-invocable) to materialize an effective spec from SDD sources. If .swarm/spec.md already exists, pass --overwrite after consent. Alternatively, run /swarm specify to author a native spec. Never write .swarm/plan.json or .swarm/plan.md directly."};specMtime=spec.mtime??void 0,specHash=spec.hash,specContent=spec.content;try{let snapshotPath=path231.join(targetWorkspace,".swarm","spec-snapshot.md");await fs144.promises.writeFile(snapshotPath,spec.content,"utf-8")}catch{}}if(process.env.SWARM_SKIP_GATE_SELECTION!=="1"){let contextPath=path231.join(targetWorkspace,".swarm","context.md"),contextContent="";try{contextContent=await fs144.promises.readFile(contextPath,"utf8")}catch{}if(!contextContent.includes("## Pending QA Gate Selection")){let candidatePlanId=derivePlanId({swarm:args2.swarm_id,title:args2.title}),existingProfile=null;try{existingProfile=getProfile(targetWorkspace,candidatePlanId)}catch{}if(!existingProfile)return{success:!1,message:'QA_GATE_SELECTION_REQUIRED: QA gate selection has not been completed. Present the gate selection question to the user (step 5b of MODE: SPECIFY or Phase 6 of MODE: BRAINSTORM), write their response to .swarm/context.md under "## Pending QA Gate Selection", then retry save_plan.',errors:["Missing ## Pending QA Gate Selection in .swarm/context.md","No existing QaGateProfile found for this plan"],recovery_guidance:"Do not call set_qa_gates with assumed values. Present the gate dialogue, wait for the user's answer, write it to context.md, then retry save_plan."}}}let requirementCoverage=evaluateRequirementCoverage(specContent,args2);if(requirementCoverage?.status==="failed"&&args2.confirm_requirement_coverage_gaps!==!0)return{success:!1,message:"REQUIREMENT_COVERAGE_GAPS: save_plan rejected because required FR-### MUST/SHALL requirements are not mapped to any task.",errors:requirementCoverage.blocking_missing.map((requirement)=>`${requirement.id} (${requirement.obligation}): ${requirement.text}`),recovery_guidance:"Add each required FR-### id to a task description or acceptance criterion, or retry with confirm_requirement_coverage_gaps: true only after surfacing the gaps to the user.",requirement_coverage:requirementCoverage};let dir=targetWorkspace,existingStatusMap=new Map,priorTaskIds=new Set,preservedExecutionProfile;{let existing=null;try{existing=await loadPlanJsonOnly(dir)}catch{}if(existing){for(let phase of existing.phases)for(let task of phase.tasks)priorTaskIds.add(task.id);if(!args2.reset_statuses)for(let phase of existing.phases)for(let task of phase.tasks)existingStatusMap.set(task.id,task.status);if(args2.confirm_identity_change!==!0){let existingId=derivePlanId(existing),incomingId=derivePlanId({swarm:args2.swarm_id,title:args2.title});if(existingId!==incomingId)return{success:!1,message:"PLAN_IDENTITY_MISMATCH: The incoming plan identity does not match the existing plan. To overwrite with a new identity, set confirm_identity_change: true.",errors:[`Existing plan identity: ${existingId} (swarm: "${existing.swarm}", title: "${existing.title}")`,`Incoming plan identity: ${incomingId} (swarm: "${args2.swarm_id}", title: "${args2.title}")`],recovery_guidance:"Verify the title and swarm_id match the intended plan. If the identity change is intentional, retry with confirm_identity_change: true. Never write .swarm/plan.json or .swarm/plan.md directly."}}if(existing.execution_profile?.locked){if(args2.execution_profile!==void 0&&!args2.reset_statuses){let requestedProfile=ExecutionProfileSchema.safeParse({...existing.execution_profile,...args2.execution_profile});if(!requestedProfile.success)return{success:!1,message:"Invalid execution_profile: schema validation failed",errors:requestedProfile.error.issues.map((i)=>`${i.path.join(".")}: ${i.message}`),recovery_guidance:"Check execution_profile fields: parallelization_enabled (boolean), max_concurrent_tasks (integer 1-64), council_parallel (boolean), locked (boolean), auto_proceed (boolean)."};if(executionProfilesEqual(existing.execution_profile,requestedProfile.data))preservedExecutionProfile=existing.execution_profile;else return{success:!1,message:"EXECUTION_PROFILE_LOCKED: The execution_profile for this plan is locked and cannot be changed.",errors:["execution_profile.locked is true — to change the profile you must first unlock it via a separate plan revision that explicitly sets locked: false, or reset the plan with reset_statuses."],recovery_guidance:"Remove the execution_profile field from this save_plan call to preserve the locked profile, or use reset_statuses: true to start fresh (this clears the lock). Never modify execution_profile directly in plan.json."}}else if(!args2.reset_statuses)preservedExecutionProfile=existing.execution_profile}else preservedExecutionProfile=existing.execution_profile}}let resolvedProfile=preservedExecutionProfile;if(args2.execution_profile!==void 0){let merged={...preservedExecutionProfile??{},...args2.execution_profile},parsed=ExecutionProfileSchema.safeParse(merged);if(!parsed.success)return{success:!1,message:"Invalid execution_profile: schema validation failed",errors:parsed.error.issues.map((i)=>`${i.path.join(".")}: ${i.message}`),recovery_guidance:"Check execution_profile fields: parallelization_enabled (boolean), max_concurrent_tasks (integer 1-64), council_parallel (boolean), locked (boolean)."};resolvedProfile=parsed.data}let incomingTaskIds=new Set;for(let phase of args2.phases)for(let task of phase.tasks)incomingTaskIds.add(task.id);let missingTaskIds=[];for(let id of priorTaskIds)if(!incomingTaskIds.has(id))missingTaskIds.push(id);let rawRemovedIds=args2.removed_task_ids??[];if(rawRemovedIds.length>0){let seen=new Set;for(let id of rawRemovedIds){if(seen.has(id))return{success:!1,message:"PLAN_TASK_REMOVAL_INVALID: removed_task_ids contains duplicate entries",errors:[`Duplicate id in removed_task_ids: "${id}"`],recovery_guidance:"Deduplicate removed_task_ids and retry save_plan."};seen.add(id)}for(let id of rawRemovedIds)if(incomingTaskIds.has(id))return{success:!1,message:"PLAN_TASK_REMOVAL_INVALID: removed_task_ids contains a task that also appears in args.phases",errors:[`Task "${id}" appears in both removed_task_ids and args.phases — these are contradictory`],recovery_guidance:"A task cannot be both kept and removed in the same save_plan call. Either drop it from args.phases or remove it from removed_task_ids."};for(let id of rawRemovedIds)if(!priorTaskIds.has(id))return{success:!1,message:"PLAN_TASK_REMOVAL_INVALID: removed_task_ids contains an id that was not in the prior plan",errors:[`Task "${id}" is in removed_task_ids but not present in the prior plan`],recovery_guidance:"Re-read the prior plan and update removed_task_ids to only list tasks that actually existed."}}let resolvedRemovedIds=[...rawRemovedIds],resolvedRemovalReason=args2.removal_reason;if(args2.reset_statuses===!0&&missingTaskIds.length>0){if(args2.confirm_destructive_reset!==!0)return{success:!1,message:"PLAN_DESTRUCTIVE_RESET_NOT_CONFIRMED: reset_statuses with missing tasks requires confirm_destructive_reset: true",errors:[`reset_statuses: true would drop ${missingTaskIds.length} task(s) from the prior plan: ${missingTaskIds.join(", ")}`],recovery_guidance:"Surface the list of dropped tasks to the user and confirm intent before retrying. Pass confirm_destructive_reset: true (with reset_statuses: true) to acknowledge the destructive reset, or list removed_task_ids explicitly with a removal_reason."};if(rawRemovedIds.length===0)resolvedRemovedIds=[...missingTaskIds],resolvedRemovalReason="destructive reset acknowledged"}if(resolvedRemovedIds.length>0){if((resolvedRemovalReason??"").trim().length===0)return{success:!1,message:"PLAN_TASK_REMOVAL_INVALID: removal_reason is required when removed_task_ids is non-empty",errors:["removal_reason must be a non-empty, non-whitespace string"],recovery_guidance:"Provide a removal_reason describing why these tasks are being dropped."}}if(missingTaskIds.length>0){let ackSet=new Set(resolvedRemovedIds),unacked=missingTaskIds.filter((id)=>!ackSet.has(id));if(unacked.length>0)return{success:!1,message:"PLAN_TASK_REMOVAL_NOT_ACKNOWLEDGED: this save would silently drop tasks from the prior plan",errors:[`The following prior tasks are missing from the new save and were not listed in removed_task_ids: ${unacked.join(", ")}`],recovery_guidance:`Re-read the current plan, then retry save_plan with removed_task_ids: ${JSON.stringify(unacked)} and a non-empty removal_reason. Tasks not yet finished (status pending/in_progress/blocked) MUST NOT be removed without explicit user confirmation.`}}let plan={schema_version:"1.0.0",title:args2.title,swarm:args2.swarm_id,migration_status:"native",current_phase:args2.phases[0]?.id,specMtime,specHash,...resolvedProfile!==void 0?{execution_profile:resolvedProfile}:{},phases:args2.phases.map((phase)=>{return{id:phase.id,name:phase.name,status:"pending",tasks:phase.tasks.map((task)=>{return{id:task.id,phase:phase.id,status:existingStatusMap.get(task.id)??"pending",size:task.size??"small",description:task.description,depends:task.depends??[],acceptance:task.acceptance,files_touched:[]}})}})},tasksCount=plan.phases.reduce((acc,phase)=>acc+phase.tasks.length,0),lockTaskId=`save-plan-${Date.now()}`,planFilePath="plan.json";try{let lockResult=await tryAcquireLock(dir,planFilePath,"architect",lockTaskId);if(!lockResult.acquired)return{success:!1,message:`Plan write blocked: file is locked by ${lockResult.existing?.agent??"another agent"} (task: ${lockResult.existing?.taskId??"unknown"})`,errors:["Concurrent plan write detected — retry after the current write completes"],recovery_guidance:"Wait a moment and retry save_plan. The lock will expire automatically if the holding agent fails."};try{await savePlan(dir,plan,{preserveCompletedStatuses:!args2.reset_statuses,...resolvedRemovedIds.length>0?{acknowledged_removals:{ids:resolvedRemovedIds,reason:(resolvedRemovalReason??"").trim(),source:"save_plan_tool"}}:{}});let savedPlan=await loadPlanJsonOnly(dir);if(savedPlan)await takeSnapshotWithRetry(dir,savedPlan);if(resolvedProfile!==void 0&&savedPlan){let planId=derivePlanId(plan),planHashAfter=computePlanHash(savedPlan);if(JSON.stringify(resolvedProfile)!==JSON.stringify(preservedExecutionProfile))await appendLedgerEvent(dir,{event_type:"execution_profile_set",source:"save_plan",plan_id:planId,payload:{execution_profile:resolvedProfile}},{planHashAfter}).catch(()=>{});let wasAlreadyLocked=preservedExecutionProfile?.locked===!0;if(resolvedProfile.locked&&!wasAlreadyLocked)await appendLedgerEvent(dir,{event_type:"execution_profile_locked",source:"save_plan",plan_id:planId},{planHashAfter}).catch(()=>{})}await writeCheckpoint(dir).catch(()=>{});try{let markerPath=path231.join(dir,".swarm",".plan-write-marker"),marker=JSON.stringify({source:"save_plan",timestamp:new Date().toISOString(),phases_count:plan.phases.length,tasks_count:tasksCount});await fs144.promises.writeFile(markerPath,marker,"utf8")}catch{}let warnings=[],criticReviewFound=!1;for(let[,session]of swarmState.agentSessions)if(session.phaseAgentsDispatched?.has("critic")||session.lastCompletedPhaseAgentsDispatched?.has("critic")){criticReviewFound=!0;break}if(!criticReviewFound)warnings.push("No critic review detected before plan save. Consider delegating to critic for plan validation.");if(requirementCoverage?.status==="override"){let missingIds=requirementCoverage.blocking_missing.map((requirement)=>requirement.id).join(", ");warnings.push(`Requirement coverage override used. Missing required FR mappings: ${missingIds}`)}return{success:!0,message:"Plan saved successfully",plan_path:path231.join(dir,".swarm","plan.json"),phases_count:plan.phases.length,tasks_count:tasksCount,...requirementCoverage?{requirement_coverage:requirementCoverage}:{},...resolvedProfile!==void 0?{execution_profile:resolvedProfile}:{},...warnings.length>0?{warnings}:{}}}finally{if(lockResult.acquired&&lockResult.lock._release)await lockResult.lock._release().catch(()=>{})}}catch(error93){if(error93 instanceof PlanTaskRemovalNotAcknowledgedError){let ids=error93.missingTasks.map((t)=>t.id);return{success:!1,message:"PLAN_TASK_REMOVAL_NOT_ACKNOWLEDGED: this save would silently drop tasks from the prior plan",errors:[error93.message],recovery_guidance:`Re-read the current plan, then retry save_plan with removed_task_ids: ${JSON.stringify(ids)} and a non-empty removal_reason.`}}return{success:!1,message:"Failed to save plan: retry with save_plan after resolving the error above",errors:[error93 instanceof Error?error93.message:String(error93)],recovery_guidance:"Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."}}}var save_plan=createSwarmTool({description:"Save or revise a structured implementation plan to .swarm/plan.json and .swarm/plan.md. "+"Use this tool for all structural plan changes on an existing plan (adding/removing tasks, updating descriptions, dependencies, or phase names) — existing task statuses are preserved by default (set reset_statuses: true to start fresh). "+"Task descriptions and phase names MUST contain real content from the spec — "+"bracket placeholders like [task] or [Project] will be rejected.",args:{title:exports_external.string().min(1).describe("Plan title — the REAL project name from the spec. NOT a placeholder like [Project]."),swarm_id:exports_external.string().min(1).describe('Swarm identifier (e.g. "mega")'),phases:exports_external.array(exports_external.object({id:exports_external.number().int().min(1).describe("Phase number — a positive integer starting at 1. Use 1, 2, 3, etc."),name:exports_external.string().min(1).describe("Descriptive phase name derived from the spec"),tasks:exports_external.array(exports_external.object({id:exports_external.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/,'Task ID must be in N.M format, e.g. "1.1"').describe('Task ID in N.M format, e.g. "1.1", "2.3"'),description:exports_external.string().min(1).describe("Specific task description from the spec. NOT a placeholder like [task]."),size:exports_external.enum(["small","medium","large"]).optional().describe("Task size estimate (default: small)"),depends:exports_external.array(exports_external.string()).optional().describe('Task IDs this task depends on, e.g. ["1.1", "1.2"]'),acceptance:exports_external.string().optional().describe("Acceptance criteria for this task")})).min(1).describe("Tasks in this phase")})).min(1).describe("Implementation phases"),working_directory:exports_external.string().optional().describe("Working directory (explicit path, required - no fallback)"),reset_statuses:exports_external.boolean().optional().describe("When true, reset ALL task statuses to pending regardless of prior completion state. Use only when deliberately re-planning a phase from scratch. Default false (preserves existing task statuses across plan revisions)."),removed_task_ids:exports_external.array(exports_external.string()).optional().describe("Task IDs that are present in the prior plan but intentionally being removed by this save. Every task missing from `phases` MUST be enumerated here, otherwise save_plan rejects with PLAN_TASK_REMOVAL_NOT_ACKNOWLEDGED. Tasks not yet finished (status pending/in_progress/blocked) MUST NOT be removed without explicit user confirmation."),removal_reason:exports_external.string().optional().describe("Required when removed_task_ids is non-empty. Human-readable reason recorded on each task_removed ledger event."),confirm_destructive_reset:exports_external.boolean().optional().describe("Required when reset_statuses is true AND at least one task is missing from the new plan. Set true to acknowledge that the destructive reset drops unfinished work. When set together with reset_statuses, save_plan auto-populates removed_task_ids from the missing set."),confirm_identity_change:exports_external.boolean().optional().describe("When true, allows overwriting an existing plan that has a different identity (swarm_id + title). Without this flag, save_plan rejects with PLAN_IDENTITY_MISMATCH if the identity differs."),confirm_requirement_coverage_gaps:exports_external.boolean().optional().describe("When true, allows saving a plan even when required FR-### MUST/SHALL requirements from the effective spec are not explicitly mapped in task descriptions or acceptance criteria. Use only after surfacing the structured requirement_coverage gaps to the user."),execution_profile:exports_external.object({parallelization_enabled:exports_external.boolean().optional().describe("When true, enables parallel task dispatch for this plan. Default false (serial)."),max_concurrent_tasks:exports_external.number().int().min(1).max(64).optional().describe("Maximum tasks that may run concurrently when parallelization is enabled. Default 10."),council_parallel:exports_external.boolean().optional().describe("When true, council review phases may run in parallel. Default true."),locked:exports_external.boolean().optional().describe("When true, locks the profile — future save_plan calls that include "+"execution_profile will be rejected (fail-closed). Unlock by resetting the plan (reset_statuses: true)."),auto_proceed:exports_external.boolean().optional().describe("When true, the architect advances to the next phase automatically without asking for confirmation. Default false.")}).optional().describe("Architect-facing concurrency controls. Once locked, cannot be changed without resetting. Omit to preserve the existing profile.")},execute:async(args2,_directory)=>{return JSON.stringify(await executeSavePlan(args2,_directory),null,2)}});init_zod();init_manager2();import*as fs145 from"node:fs";import*as path232 from"node:path";init_utils();init_logger();function parsePubspecLock(content){let components=[];if(!content.match(/^packages:\s*$/m))return components;let lines=content.split(`
6121
6121
  `),inPackages=!1,currentPackage="",currentVersion="";for(let i=0;i<lines.length;i++){let line=lines[i],trimmed=line.replace(/^ {2}/,"");if(trimmed==="packages:"||trimmed.startsWith("packages:")){inPackages=!0;continue}if(!inPackages)continue;let packageMatch=line.match(/^ {2}([a-zA-Z0-9_-]+):\s*$/);if(packageMatch){if(currentPackage&&currentVersion)components.push({name:currentPackage,version:currentVersion,type:"library",purl:generatePurl("pub",currentPackage,currentVersion)});currentPackage=packageMatch[1],currentVersion="";continue}if(currentPackage&&line.includes("version:")){let versionMatch=line.match(/version:\s*"([^"]+)"/);if(versionMatch)currentVersion=versionMatch[1]}}if(currentPackage&&currentVersion)components.push({name:currentPackage,version:currentVersion,type:"library",purl:generatePurl("pub",currentPackage,currentVersion)});return components}function parsePubspecYaml(content){let components=[],lines=content.split(`
6122
6122
  `),inDependencies=!1,inDevDependencies=!1;for(let line of lines){let trimmed=line.trim();if(trimmed==="dependencies:"){inDependencies=!0,inDevDependencies=!1;continue}if(trimmed==="dev_dependencies:"){inDependencies=!1,inDevDependencies=!0;continue}if(trimmed==="dependencies_overrides:"||trimmed==="dev_dependencies_overrides:"||trimmed.startsWith("environment:")){inDependencies=!1,inDevDependencies=!1;continue}if(!inDependencies&&!inDevDependencies)continue;if(!trimmed||trimmed.startsWith("#")||trimmed.includes("sdk:"))continue;let match=trimmed.match(/^([a-zA-Z0-9_-]+):\s*(.+)?$/);if(match){let name=match[1],value=match[2]||"";if(name==="flutter"||name==="environment")continue;let version5="unknown",caretMatch=value.match(/\^?([\d.]+)/);if(caretMatch)version5=caretMatch[1];let hostedMatch=value.match(/version:\s*"?\^?([\d.]+)/);if(hostedMatch)version5=hostedMatch[1];if(name&&version5!=="unknown")components.push({name,version:version5,type:"library",purl:generatePurl("pub",name,version5)})}}return components}var dartDetectors=[{name:"Dart pubspec.lock",patterns:["pubspec.lock"],detect:(_filePath,content)=>{return parsePubspecLock(content)}},{name:"Dart pubspec.yaml",patterns:["pubspec.yaml"],detect:(_filePath,content)=>{return parsePubspecYaml(content)}}];function parsePackagesLockJson(content){let components=[];try{let lock=JSON.parse(content),targets=lock.targets||lock.dependencies||{};for(let[_target,targetDeps]of Object.entries(targets)){if(!targetDeps||typeof targetDeps!=="object")continue;for(let[pkgSpec,pkgData]of Object.entries(targetDeps)){if(!pkgSpec.includes("/"))continue;let[name,version5]=pkgSpec.split("/"),pkg=pkgData;if(name&&version5)components.push({name,version:version5,type:"library",purl:generatePurl("nuget",name,version5),license:pkg.license})}}}catch{}return components}function parsePaketLock(content){let components=[],lines=content.split(`
6123
6123
  `),inNuGetSection=!1;for(let line of lines){let trimmed=line.trim();if(trimmed==="NUGET"||trimmed.startsWith("NUGET")){inNuGetSection=!0;continue}if(trimmed==="GITHUB"||trimmed.startsWith("GITHUB")){inNuGetSection=!1;continue}if(!inNuGetSection)continue;if(!trimmed||trimmed.startsWith("remote:")||trimmed.startsWith("->"))continue;let match=trimmed.match(/^([a-zA-Z0-9_.-]+)\s+\(([^)]+)\)/);if(match){let name=match[1],version5=match[2];if(name&&version5)components.push({name,version:version5,type:"library",purl:generatePurl("nuget",name,version5)})}}return components}var dotnetDetectors=[{name:".NET packages.lock.json",patterns:["packages.lock.json"],detect:(_filePath,content)=>{return parsePackagesLockJson(content)}},{name:".NET paket.lock",patterns:["paket.lock"],detect:(_filePath,content)=>{return parsePaketLock(content)}}];function parseGoMod(content){let components=[],lines=content.split(`
@@ -6126,7 +6126,7 @@ ${task.acceptance??""}`;if(idPattern.test(taskText))mappedTaskIds.push(task.id)}
6126
6126
  `);for(let line of lines){let trimmed=line.trim();if(!trimmed||trimmed.startsWith("#")||trimmed.startsWith("metadata:"))continue;let match=trimmed.match(depRegex);if(match){let groupId=match[1],artifactId=match[2],version5=match[3];if(version5&&version5!=="unspecified")components.push({name:artifactId,version:version5,type:"library",purl:generatePurl("maven",artifactId,version5,groupId)})}}return components}var javaDetectors=[{name:"Java pom.xml",patterns:["pom.xml"],detect:(_filePath,content)=>{return parsePomXml(content)}},{name:"Java gradle.lockfile",patterns:["gradle.lockfile"],detect:(_filePath,content)=>{return parseGradleLockfile(content)}}];function parsePackageJson(content){let components=[];try{let pkg=JSON.parse(content),deps={...pkg.dependencies,...pkg.devDependencies};for(let[name,version5]of Object.entries(deps)){let cleanVersion=String(version5).replace(/^[\^~>=<]+/,"");components.push({name,version:cleanVersion||"unknown",type:"library",purl:generatePurl("npm",name,cleanVersion||"unknown")})}}catch{}return components}function parsePackageLock(content){let components=[];try{let lock=JSON.parse(content),packages=lock.packages||lock.dependencies||{};for(let[pkgPath,pkgData]of Object.entries(packages)){if(pkgPath==="")continue;let pkg=pkgData,version5=pkg.version||"",name=pkg.name||pkgPath.replace(/^node_modules\//,"").replace(/@.*$/,"");if(name&&version5)components.push({name,version:version5,type:"library",purl:generatePurl("npm",name,version5),license:pkg.license})}}catch{}return components}function parseYarnLock(content){let components=[],blocks=content.split(/^(?=@?[\w-]+@)/m);for(let block of blocks){let pkgMatch=block.match(/^(@?[\w-]+)@(\d+\.\d+\.\d+(?:-[\w.]+)?)/m);if(!pkgMatch)continue;let name=pkgMatch[1],version5=pkgMatch[2];if(name&&version5)components.push({name,version:version5,type:"library",purl:generatePurl("npm",name,version5)})}return components}function parsePnpmLockYaml(content){let components=[];try{let lines=content.split(`
6127
6127
  `);for(let line of lines){let packageMatch=line.match(/^\s*\/(@?[\w-]+)@([\d.]+):?/);if(packageMatch)components.push({name:packageMatch[1],version:packageMatch[2],type:"library",purl:generatePurl("npm",packageMatch[1],packageMatch[2])})}}catch{}return components}var nodejsDetectors=[{name:"Node.js package-lock.json",patterns:["package-lock.json"],detect:(_filePath,content)=>{return parsePackageLock(content)}},{name:"Node.js yarn.lock",patterns:["yarn.lock"],detect:(_filePath,content)=>{return parseYarnLock(content)}},{name:"Node.js pnpm-lock.yaml",patterns:["pnpm-lock.yaml"],detect:(_filePath,content)=>{return parsePnpmLockYaml(content)}},{name:"Node.js package.json",patterns:["package.json"],detect:(_filePath,content)=>{return parsePackageJson(content)}}];function parseRequirementsTxt(content){let components=[],lines=content.split(`
6128
6128
  `);for(let line of lines){let trimmed=line.trim();if(!trimmed||trimmed.startsWith("#"))continue;if(trimmed.startsWith("-"))continue;let match=trimmed.match(/^([a-zA-Z0-9_-]+)(?:[=<>~!]+)?([\d.]+)?/);if(match){let name=match[1],version5=match[2]||"unknown";if(name)components.push({name,version:version5,type:"library",purl:generatePurl("pypi",name,version5)})}}return components}function parsePoetryLock(content){let components=[],packageBlocks=content.split(/\[\[package\]\]/);for(let block of packageBlocks){if(block.trim()==="")continue;let nameMatch=block.match(/name\s*=\s*"([^"]+)"/),versionMatch=block.match(/version\s*=\s*"([^"]+)"/);if(nameMatch&&versionMatch){let name=nameMatch[1],version5=versionMatch[1],licenseMatch=block.match(/license\s*=\s*"([^"]+)"/);components.push({name,version:version5,type:"library",purl:generatePurl("pypi",name,version5),license:licenseMatch?.[1]})}}return components}function parsePipfileLock(content){let components=[];try{let lock=JSON.parse(content),sections=[lock.default,lock.dev].filter(Boolean);for(let section of sections){if(!section)continue;for(let[name,pkgData]of Object.entries(section)){let version5=pkgData.version||"unknown";if(version5=version5.replace(/^[=<>~!]+/,""),version5&&version5!=="*")components.push({name,version:version5,type:"library",purl:generatePurl("pypi",name,version5)})}}}catch{}return components}var pythonDetectors=[{name:"Python poetry.lock",patterns:["poetry.lock"],detect:(_filePath,content)=>{return parsePoetryLock(content)}},{name:"Python Pipfile.lock",patterns:["Pipfile.lock"],detect:(_filePath,content)=>{return parsePipfileLock(content)}},{name:"Python requirements.txt",patterns:["requirements.txt"],detect:(_filePath,content)=>{return parseRequirementsTxt(content)}}];function parseCargoToml(content){let components=[],lines=content.split(`
6129
- `),inDependencies=!1,inDevDependencies=!1;for(let line of lines){let trimmed=line.trim();if(trimmed==="[dependencies]"||trimmed.startsWith("[dependencies]")){inDependencies=!0,inDevDependencies=!1;continue}if(trimmed==="[dev-dependencies]"||trimmed.startsWith("[dev-dependencies]")){inDependencies=!1,inDevDependencies=!0;continue}if(trimmed.startsWith("[")&&trimmed.endsWith("]")){inDependencies=!1,inDevDependencies=!1;continue}if(!inDependencies&&!inDevDependencies)continue;if(!trimmed||trimmed.startsWith("#"))continue;let match=trimmed.match(/^([a-zA-Z0-9_-]+)\s*=/);if(match){let name=match[1],version5="unknown",simpleMatch=trimmed.match(/"([\d.]+)"/);if(simpleMatch)version5=simpleMatch[1];else{let versionFieldMatch=trimmed.match(/version\s*=\s*"([\d.]+)"/);if(versionFieldMatch)version5=versionFieldMatch[1]}if(name&&version5!=="unknown")components.push({name,version:version5,type:"library",purl:generatePurl("cargo",name,version5)})}}return components}function parseCargoLock(content){let components=[],packageBlocks=content.split(/\[\[package\]\]/);for(let block of packageBlocks){if(block.trim()==="")continue;let nameMatch=block.match(/name\s*=\s*"([^"]+)"/),versionMatch=block.match(/version\s*=\s*"([^"]+)"/);if(nameMatch&&versionMatch){let name=nameMatch[1],version5=versionMatch[1];components.push({name,version:version5,type:"library",purl:generatePurl("cargo",name,version5)})}}return components}var rustDetectors=[{name:"Rust Cargo.lock",patterns:["Cargo.lock"],detect:(_filePath,content)=>{return parseCargoLock(content)}},{name:"Rust Cargo.toml",patterns:["Cargo.toml"],detect:(_filePath,content)=>{return parseCargoToml(content)}}];function parsePackageResolved(content){let components=[];try{let pins=JSON.parse(content).pins||[];for(let pin of pins){let identity=pin.identity||pin.package||"",state=pin.state||{},version5=state.version||state.revision||"",org="",orgMatch=(pin.location||"").match(/github\.com\/([^/]+)\//);if(orgMatch)org=orgMatch[1];if(identity&&version5)components.push({name:identity,version:version5,type:"library",purl:generatePurl("swift",identity,version5,org||void 0)})}}catch{}return components}var swiftDetectors=[{name:"Swift Package.resolved",patterns:["Package.resolved"],detect:(_filePath,content)=>{return parsePackageResolved(content)}}];function generatePurl(ecosystem,name,version5,namespace){let encodedName=encodeURIComponent(name),encodedVersion=encodeURIComponent(version5);switch(ecosystem){case"npm":return`pkg:npm/${encodedName}@${encodedVersion}`;case"pypi":return`pkg:pypi/${encodedName}@${encodedVersion}`;case"cargo":return`pkg:cargo/${encodedName}@${encodedVersion}`;case"golang":if(namespace)return`pkg:golang/${namespace}/${encodedName}@${encodedVersion}`;return`pkg:golang/${encodedName}@${encodedVersion}`;case"maven":return`pkg:maven/${encodeURIComponent(namespace||"unknown")}/${encodedName}@${encodedVersion}`;case"nuget":return`pkg:nuget/${encodedName}@${encodedVersion}`;case"swift":if(namespace)return`pkg:swift/${encodeURIComponent(namespace)}/${encodedName}@${encodedVersion}`;return`pkg:swift/${encodedName}@${encodedVersion}`;case"pub":return`pkg:pub/${encodedName}@${encodedVersion}`;default:return`pkg:unknown/${encodedName}@${encodedVersion}`}}var allDetectors=[...nodejsDetectors,...pythonDetectors,...rustDetectors,...goDetectors,...javaDetectors,...dotnetDetectors,...swiftDetectors,...dartDetectors];function findDetectorsForFile(filePath){let fileName=filePath.split(/[/\\]/).pop()||"";return allDetectors.filter((detector)=>detector.patterns.some((pattern)=>simpleGlobToRegex(pattern).test(fileName)))}function detectComponents(filePath,content){let detectors=findDetectorsForFile(filePath);for(let detector of detectors)try{let components=detector.detect(filePath,content);if(components.length>0)return components}catch(error93){console.warn(`[sbom] Detector failed for ${filePath}:`,error93 instanceof Error?error93.message:String(error93))}return[]}var DEFAULT_TOOL_VENDOR="opencode-swarm",DEFAULT_TOOL_NAME="sbom_generate",DEFAULT_TOOL_VERSION="6.9.0";function toCycloneDXComponent(component){let cyclonedxComponent={type:component.type,name:component.name,version:component.version};if(component.purl)cyclonedxComponent.purl=component.purl;if(component.license){let isSpdxId=/^[A-Za-z][A-Za-z0-9.*+-]*$/.test(component.license);cyclonedxComponent.licenses=[{license:isSpdxId?{id:component.license}:{name:component.license}}]}return cyclonedxComponent}function generateCycloneDX(components,options){let toolName=options?.toolName??DEFAULT_TOOL_NAME,toolVersion=options?.toolVersion??DEFAULT_TOOL_VERSION,bomVersion=options?.bomVersion??1,timestamp=new Date().toISOString(),cyclonedxComponents=components.map(toCycloneDXComponent);return{bomFormat:"CycloneDX",specVersion:"1.5",version:bomVersion,metadata:{timestamp,tools:[{vendor:DEFAULT_TOOL_VENDOR,name:toolName,version:toolVersion}]},components:cyclonedxComponents}}function serializeCycloneDX(bom){return JSON.stringify(bom,null,2)}init_utils();init_logger();init_create_tool();var DEFAULT_OUTPUT_DIR=".swarm/evidence/sbom";function findManifestFiles(rootDir){let manifestFiles=[],patterns=[...new Set(allDetectors.flatMap((d)=>d.patterns))];function searchDir(dir){try{let entries=fs145.readdirSync(dir,{withFileTypes:!0});for(let entry of entries){let fullPath=path232.join(dir,entry.name);if(entry.name.startsWith(".")||entry.name==="node_modules"||entry.name==="dist"||entry.name==="build"||entry.name==="target")continue;if(entry.isDirectory())searchDir(fullPath);else if(entry.isFile()){for(let pattern of patterns)if(simpleGlobToRegex(pattern).test(entry.name)){manifestFiles.push(path232.relative(rootDir,fullPath));break}}}}catch{}}return searchDir(rootDir),manifestFiles}function findManifestFilesInDirs(directories,workingDir){let found=[],patterns=[...new Set(allDetectors.flatMap((d)=>d.patterns))];for(let dir of directories)try{let entries=fs145.readdirSync(dir,{withFileTypes:!0});for(let entry of entries){let fullPath=path232.join(dir,entry.name);if(entry.isFile()){for(let pattern of patterns)if(simpleGlobToRegex(pattern).test(entry.name)){found.push(path232.relative(workingDir,fullPath));break}}}}catch{}return found}function getDirectoriesFromChangedFiles(changedFiles,workingDir){let dirs=new Set;for(let file3 of changedFiles){let currentDir=path232.dirname(file3);while(!0)if(currentDir&&currentDir!=="."&&currentDir!==path232.sep){dirs.add(path232.join(workingDir,currentDir));let parent=path232.dirname(currentDir);if(parent===currentDir)break;currentDir=parent}else{dirs.add(workingDir);break}}return[...dirs]}function ensureOutputDir(outputDir){try{fs145.mkdirSync(outputDir,{recursive:!0})}catch(error93){if(!error93||error93.code!=="EEXIST")throw error93}}function generateSbomFilename(){let now=new Date,year=now.getFullYear(),month=String(now.getMonth()+1).padStart(2,"0"),day=String(now.getDate()).padStart(2,"0"),hours=String(now.getHours()).padStart(2,"0"),minutes=String(now.getMinutes()).padStart(2,"0"),seconds=String(now.getSeconds()).padStart(2,"0");return`sbom-${year}${month}${day}-${hours}${minutes}${seconds}.json`}function validateArgs4(args2){if(typeof args2!=="object"||args2===null)return!1;let obj=args2;if(typeof obj.scope!=="string"||!["changed","all"].includes(obj.scope))return!1;if(obj.scope==="changed"){if(!Array.isArray(obj.changed_files)||obj.changed_files.length===0)return!1}if(obj.output_dir!==void 0&&typeof obj.output_dir!=="string")return!1;if(obj.changed_files!==void 0){if(!Array.isArray(obj.changed_files))return!1;for(let f of obj.changed_files)if(typeof f!=="string")return!1}return!0}var sbom_generate=createSwarmTool({description:"Generate Software Bill of Materials (SBOM) by scanning project for dependency manifests. Uses CycloneDX format. Supports scanning entire project or only changed files.",args:{scope:exports_external.enum(["changed","all"]).describe('Scan scope: "changed" for modified files only, "all" for entire project'),changed_files:exports_external.array(exports_external.string()).optional().describe('List of changed files (required if scope="changed")'),output_dir:exports_external.string().optional().describe("Output directory for SBOM (default: .swarm/evidence/sbom/)")},async execute(args2,directory){if(!validateArgs4(args2))return JSON.stringify({...{verdict:"skip",files:[],components_count:0,output_path:""},error:'Invalid arguments: scope is required ("changed" or "all"), and changed_files is required when scope="changed"'},null,2);let obj=args2,scope=obj.scope,changedFiles=obj.changed_files,relativeOutputDir=obj.output_dir||DEFAULT_OUTPUT_DIR,workingDir=directory,outputDir=path232.isAbsolute(relativeOutputDir)?relativeOutputDir:path232.join(workingDir,relativeOutputDir),manifestFiles=[];if(scope==="all")manifestFiles=findManifestFiles(workingDir);else if(scope==="changed"&&changedFiles&&changedFiles.length>0){let changedDirs=getDirectoriesFromChangedFiles(changedFiles,workingDir);if(changedDirs.length>0)manifestFiles=findManifestFilesInDirs(changedDirs,workingDir)}if(manifestFiles.length===0)return JSON.stringify({verdict:"skip",files:[],components_count:0,output_path:""},null,2);let allComponents=[],processedFiles=[];for(let manifestFile of manifestFiles)try{let fullPath=path232.isAbsolute(manifestFile)?manifestFile:path232.join(workingDir,manifestFile);if(!fs145.existsSync(fullPath))continue;let content=fs145.readFileSync(fullPath,"utf-8"),components=detectComponents(manifestFile,content);if(processedFiles.push(manifestFile),components.length>0)allComponents.push(...components)}catch{}if(processedFiles.length===0&&manifestFiles.length>0);ensureOutputDir(outputDir);let bom=generateCycloneDX(allComponents),bomJson=serializeCycloneDX(bom),filename=generateSbomFilename(),outputPath=path232.join(outputDir,filename);fs145.writeFileSync(outputPath,bomJson,"utf-8");let verdict=processedFiles.length>0?"pass":"pass";try{let timestamp=new Date().toISOString();await saveEvidence(workingDir,"sbom_generate",{task_id:"sbom_generate",type:"sbom",timestamp,agent:"sbom_generate",verdict,summary:`Generated SBOM with ${allComponents.length} component(s) from ${processedFiles.length} manifest file(s)`,components:allComponents.map((c)=>({name:c.name,version:c.version,type:c.type,purl:c.purl,license:c.license})),metadata:{timestamp,tool:"sbom_generate",tool_version:"6.9.0"},files:processedFiles,components_count:allComponents.length,output_path:outputPath})}catch(error93){log(`Warning: Failed to save SBOM evidence: ${error93 instanceof Error?error93.message:String(error93)}`)}let result={verdict,files:processedFiles,components_count:allComponents.length,output_path:outputPath};return JSON.stringify(result,null,2)}});init_zod();init_create_tool();import*as fs146 from"node:fs";import*as path233 from"node:path";var SPEC_CANDIDATES=["openapi.json","openapi.yaml","openapi.yml","swagger.json","swagger.yaml","swagger.yml","api/openapi.json","api/openapi.yaml","docs/openapi.json","docs/openapi.yaml","spec/openapi.json","spec/openapi.yaml"],SKIP_DIRS=["node_modules","dist","build",".git",".swarm","coverage","__tests__"],SKIP_EXTENSIONS=[".test.",".spec."],MAX_SPEC_SIZE=10485760,ALLOWED_EXTENSIONS=[".json",".yaml",".yml"];function normalizeApiPath(p){return p.replace(/\/$/,"").replace(/\{[^}]+\}/g,":param").replace(/:[a-zA-Z_][a-zA-Z0-9_]*/g,":param")}function discoverSpecFile(cwd,specFileArg){if(specFileArg){let resolvedPath=path233.resolve(cwd,specFileArg),normalizedCwd=cwd.endsWith(path233.sep)?cwd:cwd+path233.sep;if(!resolvedPath.startsWith(normalizedCwd)&&resolvedPath!==cwd)throw Error("Invalid spec_file: path traversal detected");let ext=path233.extname(resolvedPath).toLowerCase();if(!ALLOWED_EXTENSIONS.includes(ext))throw Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);if(fs146.statSync(resolvedPath).size>MAX_SPEC_SIZE)throw Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE/1024/1024}MB limit`);if(!fs146.existsSync(resolvedPath))throw Error(`Spec file not found: ${resolvedPath}`);return resolvedPath}for(let candidate of SPEC_CANDIDATES){let candidatePath=path233.resolve(cwd,candidate);if(fs146.existsSync(candidatePath)){if(fs146.statSync(candidatePath).size<=MAX_SPEC_SIZE)return candidatePath}}return null}function parseSpec(specFile){let content=fs146.readFileSync(specFile,"utf-8");if(path233.extname(specFile).toLowerCase()===".json")return parseJsonSpec(content);return parseYamlSpec(content)}function parseJsonSpec(content){let spec;try{spec=JSON.parse(content)}catch{return[]}let paths=[];if(!spec.paths)return paths;for(let[pathKey,pathValue]of Object.entries(spec.paths)){let methods=[];if(typeof pathValue==="object"&&pathValue!==null){for(let method of["get","post","put","patch","delete","options","head"])if(method in pathValue)methods.push(method)}if(methods.length>0)paths.push({path:pathKey,methods})}return paths}function parseYamlSpec(content){let paths=[];if(!content.match(/^paths:\s*$/m))return paths;let pathRegex=/^\s{2}(\/[^\s:]+):/gm;for(let match=pathRegex.exec(content);match!==null;match=pathRegex.exec(content)){let pathKey=match[1],methodRegex=/^\s{4}(get|post|put|patch|delete|options|head):/gm,methods=[],pathStart=match.index,nextPathMatch=content.substring(pathStart+1).match(/^\s{2}\//m),pathEnd=nextPathMatch&&nextPathMatch.index!==void 0?pathStart+1+nextPathMatch.index:content.length,pathSection=content.substring(pathStart,pathEnd),methodMatch=methodRegex.exec(pathSection);while(methodMatch!==null)methods.push(methodMatch[1]),methodMatch=methodRegex.exec(pathSection);if(methods.length>0)paths.push({path:pathKey,methods})}return paths}function extractRoutes2(cwd){let routes=[];function walkDir2(dir){let entries;try{entries=fs146.readdirSync(dir,{withFileTypes:!0})}catch{return}for(let entry of entries){let fullPath=path233.join(dir,entry.name);if(entry.isSymbolicLink())continue;if(entry.isDirectory()){if(SKIP_DIRS.includes(entry.name))continue;walkDir2(fullPath)}else if(entry.isFile()){let ext=path233.extname(entry.name).toLowerCase(),baseName=entry.name.toLowerCase();if(![".ts",".js",".mjs"].includes(ext))continue;if(SKIP_EXTENSIONS.some((skip)=>baseName.includes(skip)))continue;let fileRoutes=extractRoutesFromFile(fullPath);routes.push(...fileRoutes)}}}return walkDir2(cwd),routes}function extractRoutesFromFile(filePath){let routes=[],lines=fs146.readFileSync(filePath,"utf-8").split(/\r?\n/),expressRegex=/(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g,flaskRegex=/@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;for(let lineNum=0;lineNum<lines.length;lineNum++){let line=lines[lineNum],match=expressRegex.exec(line);expressRegex.lastIndex=0,flaskRegex.lastIndex=0;while(match!==null){let method=match[1].toLowerCase(),routePath=match[2];routes.push({path:routePath,method,file:filePath,line:lineNum+1}),match=expressRegex.exec(line)}match=flaskRegex.exec(line);while(match!==null){let routePath=match[1];routes.push({path:routePath,method:"get",file:filePath,line:lineNum+1}),match=flaskRegex.exec(line)}}return routes}function findDrift(specPaths,codeRoutes){let specPathMap=new Map;for(let sp of specPaths){let normalized=normalizeApiPath(sp.path);if(!specPathMap.has(normalized))specPathMap.set(normalized,[]);specPathMap.get(normalized).push(...sp.methods)}let codeRouteMap=new Map;for(let cr of codeRoutes){let normalized=normalizeApiPath(cr.path);if(!codeRouteMap.has(normalized))codeRouteMap.set(normalized,[]);codeRouteMap.get(normalized).push(cr)}let undocumented=[];for(let[normalized,routes]of codeRouteMap)if(!specPathMap.has(normalized))for(let route of routes)undocumented.push({path:route.path,method:route.method,file:route.file,line:route.line});let phantom=[];for(let[normalized,methods]of specPathMap)if(!codeRouteMap.has(normalized))phantom.push({path:specPaths.find((sp)=>normalizeApiPath(sp.path)===normalized).path,methods});return{undocumented,phantom}}var schema_drift=createSwarmTool({description:"Compare OpenAPI spec against actual route implementations to find drift. Detects undocumented routes in code and phantom routes in spec.",args:{spec_file:exports_external.string().optional().describe("Path to OpenAPI spec file. Auto-detected if omitted. Checks: openapi.json/yaml/yml, swagger.json/yaml/yml, api/openapi.json/yaml, docs/openapi.json/yaml, spec/openapi.json/yaml")},async execute(args2,directory){let cwd=directory;if(args2!==null&&typeof args2!=="object")return JSON.stringify({...{specFile:"",specPathCount:0,codeRouteCount:0,undocumented:[],phantom:[],undocumentedCount:0,phantomCount:0,consistent:!1},error:"Invalid arguments"},null,2);let argsObj=args2;try{let specFile=discoverSpecFile(cwd,argsObj.spec_file);if(!specFile)return JSON.stringify({...{specFile:"",specPathCount:0,codeRouteCount:0,undocumented:[],phantom:[],undocumentedCount:0,phantomCount:0,consistent:!1},error:"No OpenAPI spec file found. Provide spec_file or place spec in one of: openapi.json/yaml/yml, swagger.json/yaml/yml, api/openapi.json/yaml, docs/openapi.json/yaml, spec/openapi.json/yaml"},null,2);let specPaths=parseSpec(specFile),codeRoutes=extractRoutes2(cwd),{undocumented,phantom}=findDrift(specPaths,codeRoutes),result={specFile,specPathCount:specPaths.length,codeRouteCount:codeRoutes.length,undocumented,phantom,undocumentedCount:undocumented.length,phantomCount:phantom.length,consistent:undocumented.length===0&&phantom.length===0};return JSON.stringify(result,null,2)}catch(error93){let errorMessage3=error93 instanceof Error?error93.message:"Unknown error";return JSON.stringify({...{specFile:"",specPathCount:0,codeRouteCount:0,undocumented:[],phantom:[],undocumentedCount:0,phantomCount:0,consistent:!1},error:errorMessage3},null,2)}}});init_zod();init_external_tool_runner();init_path_security();init_create_tool();import*as fs147 from"node:fs";import{createRequire as createRequire6}from"node:module";import*as path234 from"node:path";var require2=createRequire6(import.meta.url),DEFAULT_MAX_RESULTS4=100,DEFAULT_MAX_LINES=200,REGEX_TIMEOUT_MS=5000,MAX_FILE_SIZE_BYTES9=1048576,HARD_CAP_RESULTS4=1e4,HARD_CAP_LINES=1e4,MAX_QUERY_LENGTH=20000,MAX_RG_STDOUT_BYTES=8388608,MAX_RG_STDERR_BYTES=65536,FALLBACK_MAX_FILES=20000,FALLBACK_MAX_DIRS=5000,FALLBACK_MAX_DEPTH=40,FALLBACK_MAX_TOTAL_BYTES=67108864,DEFAULT_SKIP_DIRS=new Set([".git",".swarm","node_modules","dist","build","out","coverage",".next",".turbo",".cache"]);function globMatch(pattern,filePath){let normalizedPattern=pattern.replace(/\\/g,"/"),normalizedPath=filePath.replace(/\\/g,"/"),regexPattern=normalizedPattern.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*\*/g,"{{DOUBLESTAR}}").replace(/\*/g,"[^/]*").replace(/\?/g,".").replace(/\{\{DOUBLESTAR\}\}/g,".*");try{return new RegExp(`^${regexPattern}$`).test(normalizedPath)}catch{return!1}}function matchesGlobs(filePath,globs){if(globs.length===0)return!0;return globs.some((glob)=>globMatch(glob,filePath))}var WINDOWS_RESERVED_NAMES5=/^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;function containsWindowsAttacks4(str){if(/:[^\\/]/.test(str))return!0;let parts=str.split(/[/\\]/);for(let part of parts)if(WINDOWS_RESERVED_NAMES5.test(part))return!0;return!1}function isPathInWorkspace3(filePath,workspace){try{let resolvedPath=path234.resolve(workspace,filePath),realWorkspace=fs147.realpathSync(workspace),realResolvedPath=fs147.realpathSync(resolvedPath),relativePath2=path234.relative(realWorkspace,realResolvedPath);if(relativePath2.startsWith("..")||path234.isAbsolute(relativePath2))return!1;return!0}catch{return!1}}function validatePathForRead2(filePath,workspace){return isPathInWorkspace3(filePath,workspace)}function splitGlobPatterns2(value){return value?value.split(",").map((p)=>p.trim()).filter(Boolean):[]}function toWorkspaceRelativePath2(filePath,workspace){try{let resolved=path234.resolve(workspace,filePath),realWorkspace=fs147.realpathSync(workspace),realResolved=fs147.realpathSync(resolved),relative54=path234.relative(realWorkspace,realResolved);if(!relative54||relative54.startsWith("..")||path234.isAbsolute(relative54))return null;return relative54.split(path234.sep).join("/")}catch{return null}}function truncateLine(line,maxLines){let trimmed=line.trimEnd();if(trimmed.length>maxLines)return`${trimmed.substring(0,maxLines)}...`;return trimmed}function resolvePackagedRipgrep(){try{let mod=require2("@vscode/ripgrep");return typeof mod.rgPath==="string"&&mod.rgPath?mod.rgPath:null}catch{return null}}function resolveRipgrepBinary(){return _internals147.resolvePackagedRipgrep()??_internals147.resolveExecutableFromPath(["rg"])}async function ripgrepSearch(opts){let rgPath=_internals147.resolveRipgrepBinary();if(!rgPath)return{error:!0,type:"rg-not-found",message:"ripgrep (rg) not found; using fallback search was not possible"};let args2=["--json","--no-config","-n"];for(let pattern of splitGlobPatterns2(opts.include))args2.push("--glob",pattern);for(let pattern of splitGlobPatterns2(opts.exclude))args2.push("--glob",`!${pattern}`);if(opts.mode!=="regex")args2.push("--fixed-strings");args2.push("--",opts.query,".");let run=await _internals147.runExternalTool({executable:rgPath,args:args2,cwd:opts.workspace,timeoutMs:REGEX_TIMEOUT_MS,maxStdoutBytes:MAX_RG_STDOUT_BYTES,maxStderrBytes:MAX_RG_STDERR_BYTES});try{if(run.status==="timeout")return{error:!0,type:"regex-timeout",message:`Search timed out after ${REGEX_TIMEOUT_MS}ms`};if(run.status==="spawn-error")return{error:!0,type:"unknown",message:run.message??"ripgrep failed to start"};if(run.exitCode!==0&&run.stderr){if(run.stderr.includes("Invalid regex")||run.stderr.includes("regex parse error")||run.stderr.includes("SyntaxError"))return{error:!0,type:"invalid-query",message:`Invalid query: ${run.stderr.split(`
6129
+ `),inDependencies=!1,inDevDependencies=!1;for(let line of lines){let trimmed=line.trim();if(trimmed==="[dependencies]"||trimmed.startsWith("[dependencies]")){inDependencies=!0,inDevDependencies=!1;continue}if(trimmed==="[dev-dependencies]"||trimmed.startsWith("[dev-dependencies]")){inDependencies=!1,inDevDependencies=!0;continue}if(trimmed.startsWith("[")&&trimmed.endsWith("]")){inDependencies=!1,inDevDependencies=!1;continue}if(!inDependencies&&!inDevDependencies)continue;if(!trimmed||trimmed.startsWith("#"))continue;let match=trimmed.match(/^([a-zA-Z0-9_-]+)\s*=/);if(match){let name=match[1],version5="unknown",simpleMatch=trimmed.match(/"([\d.]+)"/);if(simpleMatch)version5=simpleMatch[1];else{let versionFieldMatch=trimmed.match(/version\s*=\s*"([\d.]+)"/);if(versionFieldMatch)version5=versionFieldMatch[1]}if(name&&version5!=="unknown")components.push({name,version:version5,type:"library",purl:generatePurl("cargo",name,version5)})}}return components}function parseCargoLock(content){let components=[],packageBlocks=content.split(/\[\[package\]\]/);for(let block of packageBlocks){if(block.trim()==="")continue;let nameMatch=block.match(/name\s*=\s*"([^"]+)"/),versionMatch=block.match(/version\s*=\s*"([^"]+)"/);if(nameMatch&&versionMatch){let name=nameMatch[1],version5=versionMatch[1];components.push({name,version:version5,type:"library",purl:generatePurl("cargo",name,version5)})}}return components}var rustDetectors=[{name:"Rust Cargo.lock",patterns:["Cargo.lock"],detect:(_filePath,content)=>{return parseCargoLock(content)}},{name:"Rust Cargo.toml",patterns:["Cargo.toml"],detect:(_filePath,content)=>{return parseCargoToml(content)}}];function parsePackageResolved(content){let components=[];try{let pins=JSON.parse(content).pins||[];for(let pin of pins){let identity=pin.identity||pin.package||"",state=pin.state||{},version5=state.version||state.revision||"",org="",orgMatch=(pin.location||"").match(/github\.com\/([^/]+)\//);if(orgMatch)org=orgMatch[1];if(identity&&version5)components.push({name:identity,version:version5,type:"library",purl:generatePurl("swift",identity,version5,org||void 0)})}}catch{}return components}var swiftDetectors=[{name:"Swift Package.resolved",patterns:["Package.resolved"],detect:(_filePath,content)=>{return parsePackageResolved(content)}}];function generatePurl(ecosystem,name,version5,namespace){let encodedName=encodeURIComponent(name),encodedVersion=encodeURIComponent(version5);switch(ecosystem){case"npm":return`pkg:npm/${encodedName}@${encodedVersion}`;case"pypi":return`pkg:pypi/${encodedName}@${encodedVersion}`;case"cargo":return`pkg:cargo/${encodedName}@${encodedVersion}`;case"golang":if(namespace)return`pkg:golang/${namespace}/${encodedName}@${encodedVersion}`;return`pkg:golang/${encodedName}@${encodedVersion}`;case"maven":return`pkg:maven/${encodeURIComponent(namespace||"unknown")}/${encodedName}@${encodedVersion}`;case"nuget":return`pkg:nuget/${encodedName}@${encodedVersion}`;case"swift":if(namespace)return`pkg:swift/${encodeURIComponent(namespace)}/${encodedName}@${encodedVersion}`;return`pkg:swift/${encodedName}@${encodedVersion}`;case"pub":return`pkg:pub/${encodedName}@${encodedVersion}`;default:return`pkg:unknown/${encodedName}@${encodedVersion}`}}var allDetectors=[...nodejsDetectors,...pythonDetectors,...rustDetectors,...goDetectors,...javaDetectors,...dotnetDetectors,...swiftDetectors,...dartDetectors];function findDetectorsForFile(filePath){let fileName=filePath.split(/[/\\]/).pop()||"";return allDetectors.filter((detector)=>detector.patterns.some((pattern)=>simpleGlobToRegex(pattern).test(fileName)))}function detectComponents(filePath,content){let detectors=findDetectorsForFile(filePath);for(let detector of detectors)try{let components=detector.detect(filePath,content);if(components.length>0)return components}catch(error93){log(`[sbom] Detector failed for ${filePath}:`,error93 instanceof Error?error93.message:String(error93))}return[]}var DEFAULT_TOOL_VENDOR="opencode-swarm",DEFAULT_TOOL_NAME="sbom_generate",DEFAULT_TOOL_VERSION="6.9.0";function toCycloneDXComponent(component){let cyclonedxComponent={type:component.type,name:component.name,version:component.version};if(component.purl)cyclonedxComponent.purl=component.purl;if(component.license){let isSpdxId=/^[A-Za-z][A-Za-z0-9.*+-]*$/.test(component.license);cyclonedxComponent.licenses=[{license:isSpdxId?{id:component.license}:{name:component.license}}]}return cyclonedxComponent}function generateCycloneDX(components,options){let toolName=options?.toolName??DEFAULT_TOOL_NAME,toolVersion=options?.toolVersion??DEFAULT_TOOL_VERSION,bomVersion=options?.bomVersion??1,timestamp=new Date().toISOString(),cyclonedxComponents=components.map(toCycloneDXComponent);return{bomFormat:"CycloneDX",specVersion:"1.5",version:bomVersion,metadata:{timestamp,tools:[{vendor:DEFAULT_TOOL_VENDOR,name:toolName,version:toolVersion}]},components:cyclonedxComponents}}function serializeCycloneDX(bom){return JSON.stringify(bom,null,2)}init_utils();init_logger();init_create_tool();var DEFAULT_OUTPUT_DIR=".swarm/evidence/sbom";function findManifestFiles(rootDir){let manifestFiles=[],patterns=[...new Set(allDetectors.flatMap((d)=>d.patterns))];function searchDir(dir){try{let entries=fs145.readdirSync(dir,{withFileTypes:!0});for(let entry of entries){let fullPath=path232.join(dir,entry.name);if(entry.name.startsWith(".")||entry.name==="node_modules"||entry.name==="dist"||entry.name==="build"||entry.name==="target")continue;if(entry.isDirectory())searchDir(fullPath);else if(entry.isFile()){for(let pattern of patterns)if(simpleGlobToRegex(pattern).test(entry.name)){manifestFiles.push(path232.relative(rootDir,fullPath));break}}}}catch{}}return searchDir(rootDir),manifestFiles}function findManifestFilesInDirs(directories,workingDir){let found=[],patterns=[...new Set(allDetectors.flatMap((d)=>d.patterns))];for(let dir of directories)try{let entries=fs145.readdirSync(dir,{withFileTypes:!0});for(let entry of entries){let fullPath=path232.join(dir,entry.name);if(entry.isFile()){for(let pattern of patterns)if(simpleGlobToRegex(pattern).test(entry.name)){found.push(path232.relative(workingDir,fullPath));break}}}}catch{}return found}function getDirectoriesFromChangedFiles(changedFiles,workingDir){let dirs=new Set;for(let file3 of changedFiles){let currentDir=path232.dirname(file3);while(!0)if(currentDir&&currentDir!=="."&&currentDir!==path232.sep){dirs.add(path232.join(workingDir,currentDir));let parent=path232.dirname(currentDir);if(parent===currentDir)break;currentDir=parent}else{dirs.add(workingDir);break}}return[...dirs]}function ensureOutputDir(outputDir){try{fs145.mkdirSync(outputDir,{recursive:!0})}catch(error93){if(!error93||error93.code!=="EEXIST")throw error93}}function generateSbomFilename(){let now=new Date,year=now.getFullYear(),month=String(now.getMonth()+1).padStart(2,"0"),day=String(now.getDate()).padStart(2,"0"),hours=String(now.getHours()).padStart(2,"0"),minutes=String(now.getMinutes()).padStart(2,"0"),seconds=String(now.getSeconds()).padStart(2,"0");return`sbom-${year}${month}${day}-${hours}${minutes}${seconds}.json`}function validateArgs4(args2){if(typeof args2!=="object"||args2===null)return!1;let obj=args2;if(typeof obj.scope!=="string"||!["changed","all"].includes(obj.scope))return!1;if(obj.scope==="changed"){if(!Array.isArray(obj.changed_files)||obj.changed_files.length===0)return!1}if(obj.output_dir!==void 0&&typeof obj.output_dir!=="string")return!1;if(obj.changed_files!==void 0){if(!Array.isArray(obj.changed_files))return!1;for(let f of obj.changed_files)if(typeof f!=="string")return!1}return!0}var sbom_generate=createSwarmTool({description:"Generate Software Bill of Materials (SBOM) by scanning project for dependency manifests. Uses CycloneDX format. Supports scanning entire project or only changed files.",args:{scope:exports_external.enum(["changed","all"]).describe('Scan scope: "changed" for modified files only, "all" for entire project'),changed_files:exports_external.array(exports_external.string()).optional().describe('List of changed files (required if scope="changed")'),output_dir:exports_external.string().optional().describe("Output directory for SBOM (default: .swarm/evidence/sbom/)")},async execute(args2,directory){if(!validateArgs4(args2))return JSON.stringify({...{verdict:"skip",files:[],components_count:0,output_path:""},error:'Invalid arguments: scope is required ("changed" or "all"), and changed_files is required when scope="changed"'},null,2);let obj=args2,scope=obj.scope,changedFiles=obj.changed_files,relativeOutputDir=obj.output_dir||DEFAULT_OUTPUT_DIR,workingDir=directory,outputDir=path232.isAbsolute(relativeOutputDir)?relativeOutputDir:path232.join(workingDir,relativeOutputDir),manifestFiles=[];if(scope==="all")manifestFiles=findManifestFiles(workingDir);else if(scope==="changed"&&changedFiles&&changedFiles.length>0){let changedDirs=getDirectoriesFromChangedFiles(changedFiles,workingDir);if(changedDirs.length>0)manifestFiles=findManifestFilesInDirs(changedDirs,workingDir)}if(manifestFiles.length===0)return JSON.stringify({verdict:"skip",files:[],components_count:0,output_path:""},null,2);let allComponents=[],processedFiles=[];for(let manifestFile of manifestFiles)try{let fullPath=path232.isAbsolute(manifestFile)?manifestFile:path232.join(workingDir,manifestFile);if(!fs145.existsSync(fullPath))continue;let content=fs145.readFileSync(fullPath,"utf-8"),components=detectComponents(manifestFile,content);if(processedFiles.push(manifestFile),components.length>0)allComponents.push(...components)}catch{}if(processedFiles.length===0&&manifestFiles.length>0);ensureOutputDir(outputDir);let bom=generateCycloneDX(allComponents),bomJson=serializeCycloneDX(bom),filename=generateSbomFilename(),outputPath=path232.join(outputDir,filename);fs145.writeFileSync(outputPath,bomJson,"utf-8");let verdict=processedFiles.length>0?"pass":"pass";try{let timestamp=new Date().toISOString();await saveEvidence(workingDir,"sbom_generate",{task_id:"sbom_generate",type:"sbom",timestamp,agent:"sbom_generate",verdict,summary:`Generated SBOM with ${allComponents.length} component(s) from ${processedFiles.length} manifest file(s)`,components:allComponents.map((c)=>({name:c.name,version:c.version,type:c.type,purl:c.purl,license:c.license})),metadata:{timestamp,tool:"sbom_generate",tool_version:"6.9.0"},files:processedFiles,components_count:allComponents.length,output_path:outputPath})}catch(error93){log(`Warning: Failed to save SBOM evidence: ${error93 instanceof Error?error93.message:String(error93)}`)}let result={verdict,files:processedFiles,components_count:allComponents.length,output_path:outputPath};return JSON.stringify(result,null,2)}});init_zod();init_create_tool();import*as fs146 from"node:fs";import*as path233 from"node:path";var SPEC_CANDIDATES=["openapi.json","openapi.yaml","openapi.yml","swagger.json","swagger.yaml","swagger.yml","api/openapi.json","api/openapi.yaml","docs/openapi.json","docs/openapi.yaml","spec/openapi.json","spec/openapi.yaml"],SKIP_DIRS=["node_modules","dist","build",".git",".swarm","coverage","__tests__"],SKIP_EXTENSIONS=[".test.",".spec."],MAX_SPEC_SIZE=10485760,ALLOWED_EXTENSIONS=[".json",".yaml",".yml"];function normalizeApiPath(p){return p.replace(/\/$/,"").replace(/\{[^}]+\}/g,":param").replace(/:[a-zA-Z_][a-zA-Z0-9_]*/g,":param")}function discoverSpecFile(cwd,specFileArg){if(specFileArg){let resolvedPath=path233.resolve(cwd,specFileArg),normalizedCwd=cwd.endsWith(path233.sep)?cwd:cwd+path233.sep;if(!resolvedPath.startsWith(normalizedCwd)&&resolvedPath!==cwd)throw Error("Invalid spec_file: path traversal detected");let ext=path233.extname(resolvedPath).toLowerCase();if(!ALLOWED_EXTENSIONS.includes(ext))throw Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);if(fs146.statSync(resolvedPath).size>MAX_SPEC_SIZE)throw Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE/1024/1024}MB limit`);if(!fs146.existsSync(resolvedPath))throw Error(`Spec file not found: ${resolvedPath}`);return resolvedPath}for(let candidate of SPEC_CANDIDATES){let candidatePath=path233.resolve(cwd,candidate);if(fs146.existsSync(candidatePath)){if(fs146.statSync(candidatePath).size<=MAX_SPEC_SIZE)return candidatePath}}return null}function parseSpec(specFile){let content=fs146.readFileSync(specFile,"utf-8");if(path233.extname(specFile).toLowerCase()===".json")return parseJsonSpec(content);return parseYamlSpec(content)}function parseJsonSpec(content){let spec;try{spec=JSON.parse(content)}catch{return[]}let paths=[];if(!spec.paths)return paths;for(let[pathKey,pathValue]of Object.entries(spec.paths)){let methods=[];if(typeof pathValue==="object"&&pathValue!==null){for(let method of["get","post","put","patch","delete","options","head"])if(method in pathValue)methods.push(method)}if(methods.length>0)paths.push({path:pathKey,methods})}return paths}function parseYamlSpec(content){let paths=[];if(!content.match(/^paths:\s*$/m))return paths;let pathRegex=/^\s{2}(\/[^\s:]+):/gm;for(let match=pathRegex.exec(content);match!==null;match=pathRegex.exec(content)){let pathKey=match[1],methodRegex=/^\s{4}(get|post|put|patch|delete|options|head):/gm,methods=[],pathStart=match.index,nextPathMatch=content.substring(pathStart+1).match(/^\s{2}\//m),pathEnd=nextPathMatch&&nextPathMatch.index!==void 0?pathStart+1+nextPathMatch.index:content.length,pathSection=content.substring(pathStart,pathEnd),methodMatch=methodRegex.exec(pathSection);while(methodMatch!==null)methods.push(methodMatch[1]),methodMatch=methodRegex.exec(pathSection);if(methods.length>0)paths.push({path:pathKey,methods})}return paths}function extractRoutes2(cwd){let routes=[];function walkDir2(dir){let entries;try{entries=fs146.readdirSync(dir,{withFileTypes:!0})}catch{return}for(let entry of entries){let fullPath=path233.join(dir,entry.name);if(entry.isSymbolicLink())continue;if(entry.isDirectory()){if(SKIP_DIRS.includes(entry.name))continue;walkDir2(fullPath)}else if(entry.isFile()){let ext=path233.extname(entry.name).toLowerCase(),baseName=entry.name.toLowerCase();if(![".ts",".js",".mjs"].includes(ext))continue;if(SKIP_EXTENSIONS.some((skip)=>baseName.includes(skip)))continue;let fileRoutes=extractRoutesFromFile(fullPath);routes.push(...fileRoutes)}}}return walkDir2(cwd),routes}function extractRoutesFromFile(filePath){let routes=[],lines=fs146.readFileSync(filePath,"utf-8").split(/\r?\n/),expressRegex=/(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g,flaskRegex=/@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;for(let lineNum=0;lineNum<lines.length;lineNum++){let line=lines[lineNum],match=expressRegex.exec(line);expressRegex.lastIndex=0,flaskRegex.lastIndex=0;while(match!==null){let method=match[1].toLowerCase(),routePath=match[2];routes.push({path:routePath,method,file:filePath,line:lineNum+1}),match=expressRegex.exec(line)}match=flaskRegex.exec(line);while(match!==null){let routePath=match[1];routes.push({path:routePath,method:"get",file:filePath,line:lineNum+1}),match=flaskRegex.exec(line)}}return routes}function findDrift(specPaths,codeRoutes){let specPathMap=new Map;for(let sp of specPaths){let normalized=normalizeApiPath(sp.path);if(!specPathMap.has(normalized))specPathMap.set(normalized,[]);specPathMap.get(normalized).push(...sp.methods)}let codeRouteMap=new Map;for(let cr of codeRoutes){let normalized=normalizeApiPath(cr.path);if(!codeRouteMap.has(normalized))codeRouteMap.set(normalized,[]);codeRouteMap.get(normalized).push(cr)}let undocumented=[];for(let[normalized,routes]of codeRouteMap)if(!specPathMap.has(normalized))for(let route of routes)undocumented.push({path:route.path,method:route.method,file:route.file,line:route.line});let phantom=[];for(let[normalized,methods]of specPathMap)if(!codeRouteMap.has(normalized))phantom.push({path:specPaths.find((sp)=>normalizeApiPath(sp.path)===normalized).path,methods});return{undocumented,phantom}}var schema_drift=createSwarmTool({description:"Compare OpenAPI spec against actual route implementations to find drift. Detects undocumented routes in code and phantom routes in spec.",args:{spec_file:exports_external.string().optional().describe("Path to OpenAPI spec file. Auto-detected if omitted. Checks: openapi.json/yaml/yml, swagger.json/yaml/yml, api/openapi.json/yaml, docs/openapi.json/yaml, spec/openapi.json/yaml")},async execute(args2,directory){let cwd=directory;if(args2!==null&&typeof args2!=="object")return JSON.stringify({...{specFile:"",specPathCount:0,codeRouteCount:0,undocumented:[],phantom:[],undocumentedCount:0,phantomCount:0,consistent:!1},error:"Invalid arguments"},null,2);let argsObj=args2;try{let specFile=discoverSpecFile(cwd,argsObj.spec_file);if(!specFile)return JSON.stringify({...{specFile:"",specPathCount:0,codeRouteCount:0,undocumented:[],phantom:[],undocumentedCount:0,phantomCount:0,consistent:!1},error:"No OpenAPI spec file found. Provide spec_file or place spec in one of: openapi.json/yaml/yml, swagger.json/yaml/yml, api/openapi.json/yaml, docs/openapi.json/yaml, spec/openapi.json/yaml"},null,2);let specPaths=parseSpec(specFile),codeRoutes=extractRoutes2(cwd),{undocumented,phantom}=findDrift(specPaths,codeRoutes),result={specFile,specPathCount:specPaths.length,codeRouteCount:codeRoutes.length,undocumented,phantom,undocumentedCount:undocumented.length,phantomCount:phantom.length,consistent:undocumented.length===0&&phantom.length===0};return JSON.stringify(result,null,2)}catch(error93){let errorMessage3=error93 instanceof Error?error93.message:"Unknown error";return JSON.stringify({...{specFile:"",specPathCount:0,codeRouteCount:0,undocumented:[],phantom:[],undocumentedCount:0,phantomCount:0,consistent:!1},error:errorMessage3},null,2)}}});init_zod();init_external_tool_runner();init_path_security();init_create_tool();import*as fs147 from"node:fs";import{createRequire as createRequire6}from"node:module";import*as path234 from"node:path";var require2=createRequire6(import.meta.url),DEFAULT_MAX_RESULTS4=100,DEFAULT_MAX_LINES=200,REGEX_TIMEOUT_MS=5000,MAX_FILE_SIZE_BYTES9=1048576,HARD_CAP_RESULTS4=1e4,HARD_CAP_LINES=1e4,MAX_QUERY_LENGTH=20000,MAX_RG_STDOUT_BYTES=8388608,MAX_RG_STDERR_BYTES=65536,FALLBACK_MAX_FILES=20000,FALLBACK_MAX_DIRS=5000,FALLBACK_MAX_DEPTH=40,FALLBACK_MAX_TOTAL_BYTES=67108864,DEFAULT_SKIP_DIRS=new Set([".git",".swarm","node_modules","dist","build","out","coverage",".next",".turbo",".cache"]);function globMatch(pattern,filePath){let normalizedPattern=pattern.replace(/\\/g,"/"),normalizedPath=filePath.replace(/\\/g,"/"),regexPattern=normalizedPattern.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*\*/g,"{{DOUBLESTAR}}").replace(/\*/g,"[^/]*").replace(/\?/g,".").replace(/\{\{DOUBLESTAR\}\}/g,".*");try{return new RegExp(`^${regexPattern}$`).test(normalizedPath)}catch{return!1}}function matchesGlobs(filePath,globs){if(globs.length===0)return!0;return globs.some((glob)=>globMatch(glob,filePath))}var WINDOWS_RESERVED_NAMES5=/^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;function containsWindowsAttacks4(str){if(/:[^\\/]/.test(str))return!0;let parts=str.split(/[/\\]/);for(let part of parts)if(WINDOWS_RESERVED_NAMES5.test(part))return!0;return!1}function isPathInWorkspace3(filePath,workspace){try{let resolvedPath=path234.resolve(workspace,filePath),realWorkspace=fs147.realpathSync(workspace),realResolvedPath=fs147.realpathSync(resolvedPath),relativePath2=path234.relative(realWorkspace,realResolvedPath);if(relativePath2.startsWith("..")||path234.isAbsolute(relativePath2))return!1;return!0}catch{return!1}}function validatePathForRead2(filePath,workspace){return isPathInWorkspace3(filePath,workspace)}function splitGlobPatterns2(value){return value?value.split(",").map((p)=>p.trim()).filter(Boolean):[]}function toWorkspaceRelativePath2(filePath,workspace){try{let resolved=path234.resolve(workspace,filePath),realWorkspace=fs147.realpathSync(workspace),realResolved=fs147.realpathSync(resolved),relative54=path234.relative(realWorkspace,realResolved);if(!relative54||relative54.startsWith("..")||path234.isAbsolute(relative54))return null;return relative54.split(path234.sep).join("/")}catch{return null}}function truncateLine(line,maxLines){let trimmed=line.trimEnd();if(trimmed.length>maxLines)return`${trimmed.substring(0,maxLines)}...`;return trimmed}function resolvePackagedRipgrep(){try{let mod=require2("@vscode/ripgrep");return typeof mod.rgPath==="string"&&mod.rgPath?mod.rgPath:null}catch{return null}}function resolveRipgrepBinary(){return _internals147.resolvePackagedRipgrep()??_internals147.resolveExecutableFromPath(["rg"])}async function ripgrepSearch(opts){let rgPath=_internals147.resolveRipgrepBinary();if(!rgPath)return{error:!0,type:"rg-not-found",message:"ripgrep (rg) not found; using fallback search was not possible"};let args2=["--json","--no-config","-n"];for(let pattern of splitGlobPatterns2(opts.include))args2.push("--glob",pattern);for(let pattern of splitGlobPatterns2(opts.exclude))args2.push("--glob",`!${pattern}`);if(opts.mode!=="regex")args2.push("--fixed-strings");args2.push("--",opts.query,".");let run=await _internals147.runExternalTool({executable:rgPath,args:args2,cwd:opts.workspace,timeoutMs:REGEX_TIMEOUT_MS,maxStdoutBytes:MAX_RG_STDOUT_BYTES,maxStderrBytes:MAX_RG_STDERR_BYTES});try{if(run.status==="timeout")return{error:!0,type:"regex-timeout",message:`Search timed out after ${REGEX_TIMEOUT_MS}ms`};if(run.status==="spawn-error")return{error:!0,type:"unknown",message:run.message??"ripgrep failed to start"};if(run.exitCode!==0&&run.stderr){if(run.stderr.includes("Invalid regex")||run.stderr.includes("regex parse error")||run.stderr.includes("SyntaxError"))return{error:!0,type:"invalid-query",message:`Invalid query: ${run.stderr.split(`
6130
6130
  `)[0]}`}}let matches=[],total=0;for(let line of run.stdout.split(`
6131
6131
  `)){if(!line.trim())continue;try{let entry=JSON.parse(line);if(entry.type==="match"){let rawPath=entry.data?.path?.text??entry.data?.path,relativePath2=typeof rawPath==="string"?toWorkspaceRelativePath2(rawPath,opts.workspace):null;if(!relativePath2)continue;if(total++,matches.length<opts.maxResults){let match={file:relativePath2,lineNumber:entry.data.line_number,lineText:truncateLine(entry.data.lines.text,opts.maxLines)};matches.push(match)}}}catch{}}return{matches,truncated:total>opts.maxResults||run.stdoutTruncated||run.stderrTruncated,total,query:opts.query,mode:opts.mode,maxResults:opts.maxResults,engine:"ripgrep",outputTruncated:run.stdoutTruncated||run.stderrTruncated}}catch(err2){return{error:!0,type:"unknown",message:err2 instanceof Error?err2.message:String(err2)}}}function escapeRegex4(str){return str.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function collectFiles(dir,workspace,includeGlobs,excludeGlobs,state,depth=0){if(depth>FALLBACK_MAX_DEPTH||state.files.length>=FALLBACK_MAX_FILES||state.dirCount>=FALLBACK_MAX_DIRS)return state.truncated=!0,state.files;try{let realDir=fs147.realpathSync(dir);if(state.seenRealPaths.has(realDir))return state.files;state.seenRealPaths.add(realDir),state.dirCount++}catch{return state.files}if(!validatePathForRead2(dir,workspace))return state.files;try{let entries=fs147.readdirSync(dir,{withFileTypes:!0});for(let entry of entries){if(state.files.length>=FALLBACK_MAX_FILES||state.dirCount>=FALLBACK_MAX_DIRS){state.truncated=!0;break}let fullPath=path234.join(dir,entry.name),relativePath2=path234.relative(workspace,fullPath);if(!validatePathForRead2(fullPath,workspace))continue;if(entry.isDirectory()){if(DEFAULT_SKIP_DIRS.has(entry.name))continue;collectFiles(fullPath,workspace,includeGlobs,excludeGlobs,state,depth+1)}else if(entry.isFile()){if(includeGlobs.length>0&&!matchesGlobs(relativePath2,includeGlobs))continue;if(excludeGlobs.length>0&&matchesGlobs(relativePath2,excludeGlobs))continue;let normalized=toWorkspaceRelativePath2(fullPath,workspace);if(!normalized)continue;state.files.push(normalized)}}}catch{}return state.files}async function fallbackSearch(opts){let includeGlobs=opts.include?opts.include.split(",").map((p)=>p.trim()).filter(Boolean):[],excludeGlobs=opts.exclude?opts.exclude.split(",").map((p)=>p.trim()).filter(Boolean):[],collectState={files:[],seenRealPaths:new Set,dirCount:0,truncated:!1},files=collectFiles(opts.workspace,opts.workspace,includeGlobs,excludeGlobs,collectState),regex;try{if(opts.mode==="regex")regex=new RegExp(opts.query);else regex=new RegExp(escapeRegex4(opts.query))}catch(err2){return{error:!0,type:"invalid-query",message:err2 instanceof Error?err2.message:"Invalid regex pattern"}}let matches=[],total=0,totalBytesRead=0,truncated=collectState.truncated;for(let file3 of files){let fullPath=path234.join(opts.workspace,file3);if(!validatePathForRead2(fullPath,opts.workspace))continue;let stats2;try{if(stats2=fs147.statSync(fullPath),stats2.size>MAX_FILE_SIZE_BYTES9)continue;if(totalBytesRead+stats2.size>FALLBACK_MAX_TOTAL_BYTES){truncated=!0;break}totalBytesRead+=stats2.size}catch{continue}let content;try{content=fs147.readFileSync(fullPath,"utf-8")}catch{continue}let lines=content.split(`
6132
6132
  `);for(let i=0;i<lines.length;i++){let line=lines[i];if(regex.test(line)){if(total++,matches.length<opts.maxResults)matches.push({file:file3,lineNumber:i+1,lineText:truncateLine(line,opts.maxLines)});regex.lastIndex=0}}}return{matches,truncated:truncated||total>opts.maxResults,total,query:opts.query,mode:opts.mode,maxResults:opts.maxResults,engine:"fallback",warning:"Fallback search uses bounded filesystem traversal and does not fully emulate ripgrep gitignore behavior."}}var search=createSwarmTool({description:"Search for text within workspace files using ripgrep-style interface. Supports literal and regex search modes with glob include/exclude filtering. Returns structured JSON output with file paths, line numbers, and line content.",args:{query:exports_external.string().describe("Search query string (literal or regex depending on mode)"),mode:exports_external.enum(["literal","regex"]).default("literal").describe("Search mode: literal for exact string match, regex for regular expression"),include:exports_external.string().optional().describe('Glob pattern for files to include (e.g., "*.ts", "src/**/*.js")'),exclude:exports_external.string().optional().describe('Glob pattern for files to exclude (e.g., "node_modules/**", "*.test.ts")'),max_results:exports_external.number().default(DEFAULT_MAX_RESULTS4).describe("Maximum number of matches to return"),max_lines:exports_external.number().default(DEFAULT_MAX_LINES).describe("Maximum characters per line in results")},execute:async(args2,directory)=>{let query,mode="literal",include,exclude,maxResults=DEFAULT_MAX_RESULTS4,maxLines=DEFAULT_MAX_LINES;try{let obj=args2;query=String(obj.query??""),mode=obj.mode==="regex"?"regex":"literal",include=typeof obj.include==="string"?obj.include:void 0,exclude=typeof obj.exclude==="string"?obj.exclude:void 0;let rawMaxResults=typeof obj.max_results==="number"?obj.max_results:DEFAULT_MAX_RESULTS4,sanitizedMaxResults=Number.isNaN(rawMaxResults)?DEFAULT_MAX_RESULTS4:rawMaxResults;maxResults=Math.min(Math.max(0,sanitizedMaxResults),HARD_CAP_RESULTS4);let rawMaxLines=typeof obj.max_lines==="number"?obj.max_lines:DEFAULT_MAX_LINES,sanitizedMaxLines=Number.isNaN(rawMaxLines)?DEFAULT_MAX_LINES:rawMaxLines;maxLines=Math.min(Math.max(0,sanitizedMaxLines),HARD_CAP_LINES)}catch{return JSON.stringify({error:!0,type:"invalid-query",message:"Could not parse search arguments"},null,2)}if(!query||query.trim()==="")return JSON.stringify({error:!0,type:"invalid-query",message:"Query cannot be empty"},null,2);if(query.length>MAX_QUERY_LENGTH)return JSON.stringify({error:!0,type:"invalid-query",message:`Query exceeds maximum length of ${MAX_QUERY_LENGTH} characters`},null,2);if(containsControlChars(query))return JSON.stringify({error:!0,type:"invalid-query",message:"Query contains invalid control characters"},null,2);if(include&&containsPathTraversal(include))return JSON.stringify({error:!0,type:"path-escape",message:"Include pattern contains path traversal sequence"},null,2);if(exclude&&containsPathTraversal(exclude))return JSON.stringify({error:!0,type:"path-escape",message:"Exclude pattern contains path traversal sequence"},null,2);if(include&&containsWindowsAttacks4(include))return JSON.stringify({error:!0,type:"path-escape",message:"Include pattern contains invalid Windows-specific sequence"},null,2);if(exclude&&containsWindowsAttacks4(exclude))return JSON.stringify({error:!0,type:"path-escape",message:"Exclude pattern contains invalid Windows-specific sequence"},null,2);if(!fs147.existsSync(directory))return JSON.stringify({error:!0,type:"unknown",message:"Workspace directory does not exist"},null,2);let result;if(_internals147.resolveRipgrepBinary())result=await ripgrepSearch({query,mode,include,exclude,maxResults,maxLines,workspace:directory});else result=await fallbackSearch({query,mode,include,exclude,maxResults,maxLines,workspace:directory});if("error"in result&&result.error)return JSON.stringify(result,null,2);return JSON.stringify(result,null,2)}}),_internals147={resolvePackagedRipgrep,resolveExecutableFromPath,resolveRipgrepBinary,runExternalTool,fallbackSearch};init_secretscan();init_zod();init_qa_gate_profile();init_manager();init_utils3();init_create_tool();async function executeSetQaGates(args2,directory){let plan=await loadPlanJsonOnly(directory);if(!plan)return{success:!1,reason:"plan_json_unavailable",message:"Cannot configure QA gates: plan.json is missing or invalid. Create a plan first (e.g. via /swarm specify or save_plan)."};let planId=derivePlanId(plan);getOrCreateProfile(directory,planId,args2.project_type);let partial3={};for(let key of["reviewer","test_engineer","council_mode","sme_enabled","critic_pre_plan","hallucination_guard","sast_enabled","mutation_test","phase_council","drift_check","final_council"])if(args2[key]!==void 0)partial3[key]=args2[key];try{let updated=setGates(directory,planId,partial3);return{success:!0,plan_id:planId,message:`QA gates updated for plan_id=${planId}`,profile:{plan_id:updated.plan_id,gates:{...updated.gates},locked_at:updated.locked_at,locked_by_snapshot_seq:updated.locked_by_snapshot_seq,profile_hash:computeProfileHash(updated)}}}catch(err2){let msg=err2 instanceof Error?err2.message:String(err2),lower=msg.toLowerCase(),reason="set_gates_failed";if(lower.includes("locked"))reason="profile_locked";else if(lower.includes("ratchet"))reason="ratchet_violation";return{success:!1,reason,message:msg,plan_id:planId}}}var set_qa_gates=createSwarmTool({description:"Configure the QA gate profile for the current plan. Architect-only. Ratchet-tighter: can enable additional gates but cannot disable gates that are already enabled. Rejects all writes once the profile is locked (after critic approval). Creates the profile with defaults if none exists. plan_id is derived automatically from plan.json.",args:{reviewer:exports_external.boolean().optional().describe("Enable the reviewer gate (true) — cannot be disabled."),test_engineer:exports_external.boolean().optional().describe("Enable the test_engineer gate (true) — cannot be disabled once on."),council_mode:exports_external.boolean().optional().describe("Enable council mode — replaces per-task Stage B (reviewer + test_engineer) with the full 5-member council (critic, reviewer, sme, test_engineer, explorer) per task."),sme_enabled:exports_external.boolean().optional().describe("Enable SME consultation."),critic_pre_plan:exports_external.boolean().optional().describe("Enable critic_pre_plan review before plan approval."),hallucination_guard:exports_external.boolean().optional().describe("Enable hallucination_guard checks on plan and implementation claims."),sast_enabled:exports_external.boolean().optional().describe("Enable SAST scanning as a required QA gate."),mutation_test:exports_external.boolean().optional().describe("Enable the mutation-testing gate (default: off). Requires mutation tests to achieve a passing kill rate before phase completion; WARN verdict allows advancement, FAIL blocks."),phase_council:exports_external.boolean().optional().describe("Enable the phase_council gate (default: off). When on, a full 5-member council (critic, reviewer, sme, test_engineer, explorer) reviews all work completed in a phase holistically at phase_complete time. Requires council.enabled: true in config."),drift_check:exports_external.boolean().optional().describe("Enable drift verification gate (default: on). Blocks phase_complete until drift-verifier.json has an approved verdict. When disabled, drift verification is skipped entirely."),final_council:exports_external.boolean().optional().describe("Enable the final_council gate (default: off). When on, after all phases complete the architect dispatches critic, reviewer, sme, test_engineer, and explorer with project-scoped context, collects their CouncilMemberVerdict objects, and calls write_final_council_evidence. This is not General Council mode and does not require council.general.enabled."),project_type:exports_external.string().optional().describe('Project type label (e.g. "ts", "python"). Only applied when the profile is being created for the first time.')},execute:async(args2,directory)=>{return JSON.stringify(await executeSetQaGates(args2??{},directory),null,2)}});init_zod();init_skill_generator();init_create_tool();var skill_apply=createSwarmTool({description:"Activate a draft skill proposal (.swarm/skills/proposals/<slug>.md) into .opencode/skills/generated/<slug>/SKILL.md.",args:{slug:exports_external.string().min(1).describe("Slug of the proposal to activate."),force:exports_external.boolean().optional().default(!1).describe("Overwrite an existing active SKILL.md even if it lacks the generator stamp. Default false."),evaluate:exports_external.boolean().optional().default(!1).describe("Validate the proposal against .swarm/skills/evals/<slug> before activation. Default false."),confirm_unevaluated:exports_external.boolean().optional().default(!1).describe('Allow activation when evaluateSkillChange returns status "unevaluated" (no eval set exists). Default false — the activation is blocked with a surfaced reason so the caller can confirm. Generated skills auto-derive an eval stub from their source directives, so this only applies to non-directive skills with no stub.')},execute:async(args2,directory)=>{let a=args2??{};if(!a.slug||typeof a.slug!=="string")return JSON.stringify({activated:!1,reason:"slug required"});let result=await activateProposal(directory,a.slug,a.force??!1,{evaluate:a.evaluate??!1,confirmUnevaluated:a.confirm_unevaluated??!1});return JSON.stringify(result,null,2)}});init_zod();init_skill_generator();init_create_tool();var skill_generate=createSwarmTool({description:'Compile mature knowledge entries into a SKILL.md. mode="draft" writes a proposal under .swarm/skills/proposals; mode="active" writes the live skill under .opencode/skills/generated and stamps source entries.',args:{source_knowledge_ids:exports_external.array(exports_external.string()).optional().describe("Optional explicit knowledge ids to compile. If omitted, all mature candidates are clustered and emitted."),slug:exports_external.string().optional().describe("Optional slug for the FIRST cluster. Sanitized; rejected if invalid."),mode:exports_external.enum(["draft","active"]).default("draft"),force:exports_external.boolean().optional().default(!1),evaluate:exports_external.boolean().optional().default(!1).describe("Validate generated skill content against .swarm/skills/evals/<slug> before writing. Default false."),min_confidence:exports_external.number().min(0).max(1).optional(),min_confirmations:exports_external.number().int().min(1).max(50).optional()},execute:async(args2,directory)=>{let a=args2??{},result=await generateSkills({directory,mode:a.mode??"draft",slug:a.slug,sourceKnowledgeIds:a.source_knowledge_ids,force:a.force??!1,evaluate:a.evaluate??!1,minConfidence:a.min_confidence,minConfirmations:a.min_confirmations});return JSON.stringify(result,null,2)}});init_zod();init_config();init_schema();init_skill_improver();init_create_tool();var skill_improve=createSwarmTool({description:'Run the skill_improver capability under daily quota. Writes a proposal under .swarm/skill-improver/proposals/<timestamp>.md. With mode="draft_skills" it also drafts SKILL.md proposals for mature clusters. Quota is enforced via .swarm/skill-improver-quota.json.',args:{targets:exports_external.array(exports_external.enum(["skills","spec","architect_prompt","knowledge"])).optional(),mode:exports_external.enum(["proposal","draft_skills"]).optional(),max_calls:exports_external.number().int().min(1).max(100).optional().describe("Override the per-run reservation count (capped by daily max)."),evaluate:exports_external.boolean().optional().default(!1).describe('When mode="draft_skills", validate generated draft skills before writing proposals. Default false.')},execute:async(args2,directory,ctx)=>{let a=args2??{},{config:config3}=loadPluginConfigWithMeta(directory),parsed=SkillImproverConfigSchema.parse(config3.skill_improver??{}),enrichmentConfig=KnowledgeConfigSchema.parse(config3.knowledge??{}).enrichment??{max_calls_per_day:30,quota_window:"utc"};if(!parsed.enabled)return JSON.stringify({ran:!1,reason:'skill_improver is disabled. Set "skill_improver.enabled": true in opencode-swarm config to use this tool.'},null,2);let result=await runSkillImprover({directory,config:parsed,targets:a.targets,mode:a.mode,maxCalls:a.max_calls,sessionId:ctx?.sessionID,enrichmentQuota:{maxCalls:enrichmentConfig.max_calls_per_day,window:enrichmentConfig.quota_window},evaluateDrafts:a.evaluate??!1});return JSON.stringify(result,null,2)}});init_zod();init_skill_generator();init_create_tool();var skill_inspect=createSwarmTool({description:"Read a generated skill (active or draft) and return its full markdown body and metadata.",args:{slug:exports_external.string().min(1).describe("Slug of the skill to inspect."),prefer:exports_external.enum(["auto","proposal","active"]).optional().default("auto")},execute:async(args2,directory)=>{let a=args2??{};if(!a.slug||typeof a.slug!=="string")return JSON.stringify({found:!1,reason:"slug required"});let result=await inspectSkill(directory,a.slug,a.prefer??"auto");return JSON.stringify(result,null,2)}});init_skill_generator();init_create_tool();var skill_list=createSwarmTool({description:"List generated skill drafts (under .swarm/skills/proposals) and active generated skills (under .opencode/skills/generated).",args:{},execute:async(_args,directory)=>{let result=await listSkills(directory);return JSON.stringify(result,null,2)}});init_zod();init_skill_generator();init_create_tool();var skill_regenerate=createSwarmTool({description:"Regenerate an active skill by re-clustering its source knowledge entries and updating the SKILL.md in place.",args:{slug:exports_external.string().min(1).describe("Slug of the active skill to regenerate."),evaluate:exports_external.boolean().optional().default(!1).describe("Validate regenerated content against .swarm/skills/evals/<slug> before writing. Default false.")},execute:async(args2,directory)=>{let a=args2??{};if(!a.slug||typeof a.slug!=="string")return JSON.stringify({regenerated:!1,reason:"slug required"});let result=await regenerateSkill(directory,a.slug,{evaluate:a.evaluate??!1});return JSON.stringify(result,null,2)}});init_zod();init_skill_generator();init_create_tool();var skill_retire=createSwarmTool({description:"Retire a generated skill by adding a retired.marker file. Retired skills are excluded from scoring and injection.",args:{slug:exports_external.string().min(1).describe("Slug of the active skill to retire."),reason:exports_external.string().optional().describe("Optional reason for retirement.")},execute:async(args2,directory)=>{let a=args2??{};if(!a.slug||typeof a.slug!=="string")return JSON.stringify({retired:!1,reason:"slug required"});let result=await retireSkill(directory,a.slug,a.reason);return JSON.stringify(result,null,2)}});init_zod();init_config();init_schema();init_create_tool();import{mkdir as mkdir41,rename as rename15,writeFile as writeFile25}from"node:fs/promises";import*as path235 from"node:path";var MAX_SPEC_BYTES2=262144,spec_write=createSwarmTool({description:"Write the canonical project spec to .swarm/spec.md. Atomic write, size-bounded (256 KiB), heading-required. Honors spec_writer.allow_spec_write.",args:{content:exports_external.string().min(20).max(MAX_SPEC_BYTES2),mode:exports_external.enum(["replace","append"]).optional().default("replace")},execute:async(args2,directory)=>{let a=args2??{},content=a.content,mode=a.mode??"replace";if(typeof content!=="string"||content.length<20)return JSON.stringify({written:!1,reason:"content must be a string >=20 chars"});if(content.length>MAX_SPEC_BYTES2)return JSON.stringify({written:!1,reason:`content exceeds ${MAX_SPEC_BYTES2} bytes`});let{config:config3}=loadPluginConfigWithMeta(directory);if(!SpecWriterConfigSchema.parse(config3.spec_writer??{}).allow_spec_write)return JSON.stringify({written:!1,reason:"spec_writer.allow_spec_write is false"},null,2);if(content.indexOf("\x00")!==-1)return JSON.stringify({written:!1,reason:"content contains null byte"},null,2);if(!/^#\s+/m.test(content))return JSON.stringify({written:!1,reason:'spec must contain at least one top-level "# Heading"'},null,2);let target=path235.join(directory,".swarm","spec.md");await mkdir41(path235.dirname(target),{recursive:!0});let tmp=`${target}.tmp-${process.pid}-${Date.now()}`,finalContent=content;if(mode==="append")try{if(finalContent=`${(await(await import("node:fs/promises")).readFile(target,"utf-8")).replace(/\s+$/,"")}