@wundam/orchex 1.0.0-rc.21 → 1.0.0-rc.23
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 +25 -2
- package/dist/intelligence/index.d.ts +1 -1
- package/dist/intelligence/index.js +51 -40
- package/dist/mcp-instructions.d.ts +1 -1
- package/dist/mcp-instructions.js +1 -1
- package/dist/orchestrator.js +98 -17
- package/dist/ownership.js +14 -8
- package/dist/tools.js +39 -4
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { exec as execChildProcess } from 'child_process';
|
|
|
4
4
|
import { registerTools, setProjectDir } from './tools.js';
|
|
5
5
|
import { ORCHEX_INSTRUCTIONS } from './mcp-instructions.js';
|
|
6
6
|
import { registerResources } from './mcp-resources.js';
|
|
7
|
+
import { broadcaster } from './execution-broadcaster.js';
|
|
7
8
|
import { loadConfig, saveConfig, maskConfigForDisplay, resolveApiUrl, PRODUCTION_URL, LLMProviderSchema } from './config.js';
|
|
8
9
|
import { buildVerificationMessage, buildStatusMessage, parseLoginApiResponse, } from './login-helpers.js';
|
|
9
10
|
/** Opens browser cross-platform. Errors are silently ignored — URL already printed to terminal. */
|
|
@@ -606,12 +607,34 @@ async function handleRunCommand(args) {
|
|
|
606
607
|
let done = false;
|
|
607
608
|
let waveNum = 1;
|
|
608
609
|
while (!done) {
|
|
609
|
-
|
|
610
|
+
// Subscribe to broadcaster for per-stream progress during this wave
|
|
611
|
+
const orchestrationId = plan.title;
|
|
612
|
+
const cliProgressListener = (event) => {
|
|
613
|
+
switch (event.type) {
|
|
614
|
+
case 'stream_started':
|
|
615
|
+
process.stdout.write(` ⟳ ${event.data.streamId} — running...\n`);
|
|
616
|
+
break;
|
|
617
|
+
case 'stream_completed': {
|
|
618
|
+
const dur = event.data.duration ? ` (${Math.round(event.data.duration / 1000)}s)` : '';
|
|
619
|
+
process.stdout.write(` ✓ ${event.data.streamId} — complete${dur}\n`);
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
case 'stream_failed':
|
|
623
|
+
process.stdout.write(` ✗ ${event.data.streamId} — failed: ${String(event.data.error).slice(0, 100)}\n`);
|
|
624
|
+
break;
|
|
625
|
+
case 'stream_rate_limited':
|
|
626
|
+
process.stdout.write(` ⏳ ${event.data.streamId} — rate limited (retry in ${Math.round((event.data.retryAfterMs ?? 0) / 1000)}s)\n`);
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
broadcaster.subscribe(orchestrationId, cliProgressListener);
|
|
631
|
+
console.log(`\nExecuting wave ${waveNum}...`);
|
|
610
632
|
const response = await executeWave(projectDir, exec, { model: modelFlag });
|
|
611
633
|
allResponses.push(response);
|
|
634
|
+
broadcaster.unsubscribe(orchestrationId, cliProgressListener);
|
|
612
635
|
const completed = response.streams.filter(s => s.status === 'complete').length;
|
|
613
636
|
const failed = response.streams.filter(s => s.status === 'failed').length;
|
|
614
|
-
console.log(` Wave ${waveNum}: ${completed} complete, ${failed} failed`);
|
|
637
|
+
console.log(` Wave ${waveNum} summary: ${completed} complete, ${failed} failed`);
|
|
615
638
|
done = response.done;
|
|
616
639
|
waveNum++;
|
|
617
640
|
}
|
|
@@ -27,7 +27,7 @@ export type { InteractiveSuggestion } from './split-suggester.js';
|
|
|
27
27
|
export { autoMergeOwnershipConflicts } from './ownership-resolver.js';
|
|
28
28
|
export { suggestProvider, classifyTask } from './model-routing.js';
|
|
29
29
|
export { applyPartialApproval, rollbackStream } from './interactive-approval.js';
|
|
30
|
-
export { generateFixStream } from './self-healer.js';
|
|
30
|
+
export { generateFixStream, generateRootCauseFixStream, analyzeFailureCorrelation, type FailureCorrelation } from './self-healer.js';
|
|
31
31
|
export { cleanupOrphanFixStreams, getFixChainInfo, isFixStream, getOriginalStreamId, onStreamComplete } from './fix-stream-manager.js';
|
|
32
32
|
export { routeStream, loadRoutingRules } from './smart-router.js';
|
|
33
33
|
export type { RouteDecision, RouteOptions } from './smart-router.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import*as
|
|
2
|
-
`),s={};try{let r=await
|
|
1
|
+
import*as _ from"fs/promises";import{existsSync as et}from"fs";import*as P from"path";import{DEFAULT_MODELS as tt}from"../config.js";var nt=new Set(["node_modules",".git","dist","build",".next",".orchex","coverage",".turbo",".cache","__pycache__",".venv","venv"]),ge=500;async function we(n,t,e){if(e.length>=ge)return;let s;try{s=await _.readdir(n,{withFileTypes:!0})}catch{return}for(let o of s){if(e.length>=ge)break;if(nt.has(o.name)||o.name.startsWith(".")&&o.name!==".env.example")continue;let r=P.join(n,o.name);o.isDirectory()?await we(r,t,e):e.push(P.relative(t,r))}}async function ye(n){let t=[];await we(n,n,t);let e=t.sort().join(`
|
|
2
|
+
`),s={};try{let r=await _.readFile(P.join(n,"package.json"),"utf-8");s=JSON.parse(r)}catch{}let o;try{let r=await _.readFile(P.join(n,"tsconfig.json"),"utf-8");o=JSON.parse(r)}catch{}return{fileTree:e,packageJson:s,tsconfig:o,existingFiles:t}}function st(n,t){let e=[],s=/(?:spec|plan|design|doc):\s*(\S+\.(?:md|txt|yaml|yml))/gi,o;for(;(o=s.exec(n))!==null;)e.push(o[1]);if(t&&e.length===0){let r=/(\S+\.(?:md|txt|yaml|yml))/gi;for(;(o=r.exec(n))!==null;){let i=o[1],a=P.join(t,i);et(a)&&e.push(i)}}return e}function ot(n,t,e){let s=[];if(s.push(`You are an expert software architect using orchex, a parallel AI orchestration tool.
|
|
3
3
|
Your task: generate a plan document in orchex format from the user's intent.
|
|
4
4
|
|
|
5
5
|
## Output Format Rules
|
|
@@ -34,7 +34,8 @@ streams:
|
|
|
34
34
|
- The \`plan:\` field is the LLM's ENTIRE instruction set. Be specific and complete.
|
|
35
35
|
- Do NOT create circular dependencies.
|
|
36
36
|
- Keep streams small and focused \u2014 better to have more small streams than fewer large ones.
|
|
37
|
-
- CRITICAL: No two streams can own the same file. Each file must have exactly one owner. If multiple tasks need to modify the same file (e.g., adding imports to index.ts), combine those tasks into a single stream. Prefer fewer, larger streams over ownership conflicts
|
|
37
|
+
- CRITICAL: No two streams can own the same file. Each file must have exactly one owner. If multiple tasks need to modify the same file (e.g., adding imports to index.ts), combine those tasks into a single stream. Prefer fewer, larger streams over ownership conflicts.
|
|
38
|
+
- For \`verify:\` commands: use \`npm run build\` for non-test streams that create/modify source code. Only use vitest/jest when the stream creates or modifies test files. Do NOT use vitest as a verify command for streams that only create config files (package.json, tsconfig.json, etc.).`),s.push(`
|
|
38
39
|
## User Intent
|
|
39
40
|
|
|
40
41
|
${n}`),s.push(`
|
|
@@ -52,12 +53,21 @@ ${JSON.stringify(i,null,2)}
|
|
|
52
53
|
|
|
53
54
|
\`\`\`json
|
|
54
55
|
${JSON.stringify(t.tsconfig,null,2)}
|
|
55
|
-
\`\`\``),e?.specContents&&Object.keys(e.specContents).length>0)for(let[i,a]of Object.entries(e.specContents)){let l=a.length>8e3?a.substring(0,8e3)+`
|
|
56
|
+
\`\`\``),e?.specContents&&Object.keys(e.specContents).length>0){for(let[i,a]of Object.entries(e.specContents)){let l=a.length>8e3?a.substring(0,8e3)+`
|
|
56
57
|
|
|
57
58
|
[... truncated]`:a;s.push(`
|
|
58
59
|
## Referenced Document: ${i}
|
|
59
60
|
|
|
60
|
-
${l}`)}
|
|
61
|
+
${l}`)}s.push(`
|
|
62
|
+
## IMPORTANT: Referenced Document Fidelity
|
|
63
|
+
|
|
64
|
+
When a Referenced Document above contains:
|
|
65
|
+
- Exact code (function bodies, type definitions, imports) \u2014 use it **verbatim** in stream plans. Do NOT rewrite, rename, or reinterpret the code.
|
|
66
|
+
- Specific file paths \u2014 use those exact paths in \`owns:\` and \`reads:\`.
|
|
67
|
+
- Step-by-step tasks \u2014 map each task to a stream, preserving the document's structure.
|
|
68
|
+
- Type definitions (interfaces, enums, const arrays) \u2014 copy them exactly. Do NOT invent different field names, roles, or values.
|
|
69
|
+
|
|
70
|
+
The user has already designed the implementation. Your job is to decompose it into parallel streams, not to redesign it.`)}let o=[],r=t.packageJson?.files;if(Array.isArray(r)&&r.length>0&&o.push("- This is an npm package with an explicit `files` list in package.json. When creating new source files that compile to dist/, add their dist/ paths (e.g., `dist/new-module.js`, `dist/new-module.d.ts`) to the `files` array."),t.fileTree.split(`
|
|
61
71
|
`).some(i=>i.startsWith("public/"))&&o.push("- The `public/` directory contains static assets served by Express. If the feature involves web-discoverable content (e.g., llms.txt, robots.txt), update files in public/."),t.fileTree.split(`
|
|
62
72
|
`).some(i=>i==="src/index.ts")&&o.push("- If adding a new CLI subcommand, add its dispatch in src/index.ts and update the help text in the printHelp() function."),o.length>0&&s.push(`
|
|
63
73
|
## Project Conventions
|
|
@@ -74,33 +84,33 @@ NEVER exceed ${e.maxStreams} streams \u2014 the plan will be rejected if you do.
|
|
|
74
84
|
|
|
75
85
|
Generate the plan document now. Output ONLY the markdown plan document \u2014 no preamble, no explanation.
|
|
76
86
|
Start with \`# <Feature Title>\` and include all H2 stream sections with YAML blocks.`),s.join(`
|
|
77
|
-
`)}async function
|
|
87
|
+
`)}async function rt(n,t,e,s){let o=await ye(t),r=st(n,t),i={};for(let u of r)try{let d=P.join(t,u),f=await _.readFile(d,"utf-8");i[u]=f}catch{}let a=ot(n,o,{specContents:Object.keys(i).length>0?i:void 0,maxStreams:s?.maxStreams});s?.extraContext&&(a+=`
|
|
78
88
|
|
|
79
|
-
`+s.extraContext);let l=await e.execute({prompt:a,model:s?.model??
|
|
80
|
-
`),s=/^```(\w+)?[ \t]*\n(?:\/\/\s*(\S+)\n)?([\s\S]*?)^```[ \t]*$/gm,o;for(;(o=s.exec(e))!==null;)t.push({language:o[1]||"text",filename:o[2],code:o[3].trim()});return t}function
|
|
89
|
+
`+s.extraContext);let l=await e.execute({prompt:a,model:s?.model??tt[s?.provider??e.provider??"anthropic"]??"claude-sonnet-4-5-20250929",maxTokens:s?.maxTokens??16384,streamId:"_auto-plan"});if(!l.rawResponse?.trim())throw new Error(`Auto-plan generation failed: ${l.error??"Empty response from LLM"}`);let c=l.rawResponse.trim();return c.startsWith("```markdown")?(c=c.slice(11),c.endsWith("```")&&(c=c.slice(0,-3)),c=c.trim()):c.startsWith("```")&&(c=c.slice(3),c.endsWith("```")&&(c=c.slice(0,-3)),c=c.trim()),{planMarkdown:c,tokensUsed:l.tokensUsed}}import{createLogger as it}from"../logging.js";var at=it("plan-parser");function ct(n){return n.replace(/^```[\s\S]*?^```/gm,"")}function lt(n){let t=ct(n),e=[/`([^`]+\.(ts|js|tsx|jsx|md|sql|json|yaml|yml))`/g,/"([^"]+\.(ts|js|tsx|jsx|md|sql|json|yaml|yml))"/g,/\[([^\]]+\.(ts|js|tsx|jsx|md|sql|json|yaml|yml))\]/g,/\b(src\/[^\s,)]+\.(ts|js|tsx|jsx))/g,/\b(tests?\/[^\s,)]+\.(ts|js|tsx|jsx))/g,/\b(docs\/[^\s,)]+\.md)/g],s=new Set;for(let r of e){r.lastIndex=0;let i;for(;(i=r.exec(t))!==null;){let a=i[1].trim();a&&!a.includes(" ")&&s.add(a)}}return[...s].filter(r=>{if(r.endsWith(".js")){let i=r.replace(/\.js$/,".ts");if(s.has(i))return!1}if(r.endsWith(".jsx")){let i=r.replace(/\.jsx$/,".tsx");if(s.has(i))return!1}return!0})}function ut(n){let t=[/depends?\s+on\s+[`"]?([^`",.]+)[`"]?/gi,/requires?\s+[`"]?([^`",.]+)[`"]?/gi,/after\s+[`"]?([^`",.]+)[`"]?\s+(?:is\s+)?(?:complete|done|finished)/gi,/\bdeps?:\s*\[([^\]]+)\]/gi],e=new Set;for(let s of t){s.lastIndex=0;let o;for(;(o=s.exec(n))!==null;)if(s.source.includes("deps")){let r=o[1].split(",").map(i=>i.trim().replace(/[`"']/g,""));for(let i of r)i&&i.length>2&&i.length<50&&e.add(i)}else{let r=o[1].trim().replace(/\s+is$/i,"").replace(/[`"]/g,"");r&&r.length>2&&r.length<50&&e.add(r)}}return[...e]}function dt(n){let t=[],e=n.replace(/\r\n/g,`
|
|
90
|
+
`),s=/^```(\w+)?[ \t]*\n(?:\/\/\s*(\S+)\n)?([\s\S]*?)^```[ \t]*$/gm,o;for(;(o=s.exec(e))!==null;)t.push({language:o[1]||"text",filename:o[2],code:o[3].trim()});return t}function ft(n){let t=n.split(`
|
|
81
91
|
`),e=[],s=[],o=[],r=!1;for(let a of t){if(a.startsWith("```")){r=!r,o.push(a);continue}if(r){o.push(a);continue}let l=a.match(/^(#{1,6})\s+(.+)$/);if(l){s.length>0&&(s[s.length-1].content=o.join(`
|
|
82
92
|
`).trim()),o=[];let c=l[1].length,u=l[2].trim(),d={level:c,title:u,content:"",codeBlocks:[],fileReferences:[],explicitDeps:[],children:[]};for(;s.length>0&&s[s.length-1].level>=c;)s.pop();s.length>0?s[s.length-1].children.push(d):e.push(d),s.push(d)}else o.push(a)}s.length>0&&(s[s.length-1].content=o.join(`
|
|
83
|
-
`).trim());function i(a){a.codeBlocks=
|
|
93
|
+
`).trim());function i(a){a.codeBlocks=dt(a.content),a.fileReferences=lt(a.content),a.explicitDeps=ut(a.content);for(let l of a.children)i(l)}for(let a of e)i(a);return e}function pt(n){let t=ft(n),e=t.find(l=>l.level===1)?.title??"Untitled Plan",o=t.find(l=>l.level===1)?.content.split(`
|
|
84
94
|
`).slice(0,3).join(`
|
|
85
|
-
`)??"",r=new Set,i=[];function a(l){for(let c of l.fileReferences)r.add(c);i.push(...l.codeBlocks);for(let c of l.children)a(c)}for(let l of t)a(l);return{title:e,description:o,sections:t,allFileReferences:[...r],allCodeBlocks:i}}function U(n,t){let e=[];function s(o){o.level===t&&e.push(o);for(let r of o.children)s(r)}for(let o of n)s(o);return e}function
|
|
95
|
+
`)??"",r=new Set,i=[];function a(l){for(let c of l.fileReferences)r.add(c);i.push(...l.codeBlocks);for(let c of l.children)a(c)}for(let l of t)a(l);return{title:e,description:o,sections:t,allFileReferences:[...r],allCodeBlocks:i}}function U(n,t){let e=[];function s(o){o.level===t&&e.push(o);for(let r of o.children)s(r)}for(let o of n)s(o);return e}function z(n){let t=[];function e(s){t.push(s);for(let o of s.children)e(o)}for(let s of n)e(s);return t}function ee(n){let t=n.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t:t.replace(/\s+#(?=\s|$).*/,"").trim()}function mt(n){let t={},e=n.split(`
|
|
86
96
|
`),s=null,o=[],r=!1,i=!1,a=[];for(let l of e){if(r&&(l.startsWith(" ")||l.startsWith(" ")||l.trim()==="")){o.push(l.replace(/^ /,"").replace(/^\t/,""));continue}else r&&(s&&(t[s]=o.join(`
|
|
87
97
|
`).trim()),r=!1,s=null,o=[]);if(i&&l.match(/^\s+-\s+/)){let u=l.replace(/^\s+-\s+/,"").trim();a.push(ee(u));continue}else i&&!l.match(/^\s+-\s+/)&&l.trim()!==""&&(s&&(t[s]=a),i=!1,s=null,a=[]);let c=l.match(/^([\w-]+):\s*(.*)$/);if(c){let[,u,d]=c;if(d.startsWith("[")&&d.endsWith("]")){let f=d.slice(1,-1).split(",").map(p=>ee(p).replace(/['"]/g,""));t[u]=f.filter(p=>p.length>0);continue}if(d==="|"||d==="|-"){s=u,o=[],r=!0;continue}if(d===""){s=u,a=[],i=!0;continue}t[u]=ee(d).replace(/^["']|["']$/g,"")}}return r&&s&&(t[s]=o.join(`
|
|
88
|
-
`).trim()),i&&s&&(t[s]=a),t}function
|
|
98
|
+
`).trim()),i&&s&&(t[s]=a),t}function ht(n){let t=n.split(`
|
|
89
99
|
`),e=[],s=t.findIndex(i=>/^streams:\s*$/.test(i));if(s===-1)return[];let o=null,r=[];for(let i=s+1;i<t.length;i++){let a=t[i],l=a.match(/^ ([\w-]+):\s*$/);if(l){o&&r.some(c=>c.trim())&&e.push({id:o,block:r.join(`
|
|
90
100
|
`)}),o=l[1],r=[];continue}if(o&&(/^ /.test(a)||a.trim()==="")){r.push(a.replace(/^ /,""));continue}if(a.trim()!==""&&!/^\s/.test(a))break}return o&&r.some(i=>i.trim())&&e.push({id:o,block:r.join(`
|
|
91
|
-
`)}),e}function
|
|
101
|
+
`)}),e}function xe(n,t){let e=mt(n),s=t??e.id??"",o=e.name??"";if(!s&&!o){at.warn({block:n.slice(0,100)},"Malformed YAML block skipped \u2014 no id or name found");return}let r={id:s,name:o};return e.deps&&(r.deps=Array.isArray(e.deps)?e.deps:[e.deps]),e.owns&&(r.owns=Array.isArray(e.owns)?e.owns:[e.owns]),e.reads&&(r.reads=Array.isArray(e.reads)?e.reads:[e.reads]),e.plan&&(r.plan=e.plan),e.verify&&(r.verify=Array.isArray(e.verify)?e.verify:[e.verify]),e.setup&&(r.setup=Array.isArray(e.setup)?e.setup:[e.setup]),r}function te(n){let t=[];for(let e of n.codeBlocks){if(e.language!=="yaml"&&e.language!=="yml")continue;let s=ht(e.code);if(s.length>0){for(let{id:r,block:i}of s){let a=xe(i,r);a&&t.push(a)}continue}if(!e.code.includes("id:")&&!e.code.includes("name:"))continue;let o=xe(e.code);o&&t.push(o)}return t}function gt(n){return n.includes("ORCHEX PLAN TEMPLATE")}import*as T from"fs/promises";import*as F from"path";import{createLogger as wt}from"../logging.js";var H=wt("learning-engine"),B={maxOwnsCount:{code:4,docs:6,tutorial:3,"integration-guide":3,test:4,migration:3,"api-reference":4,other:4},maxReadsCount:{code:4,docs:3,tutorial:4,"integration-guide":4,test:5,migration:4,"api-reference":3,other:4},maxContextTokens:{code:14e4,docs:8e4,tutorial:1e5,"integration-guide":1e5,test:14e4,migration:16e4,"api-reference":8e4,other:1e5},globalSoftLimit:14e4,globalHardLimit:18e4,sampleCount:0,confidence:"low",lastUpdated:new Date().toISOString(),version:1},ne=20,yt=100,xt=50;function St(n){return n>=yt?"high":n>=xt?"medium":"low"}function q(n,t){let e=`${n} ${t??""}`.toLowerCase();return e.includes("test")||e.includes("spec")?"test":e.includes("migration")||e.includes("migrate")||e.includes("refactor")||e.includes("restructure")?"migration":e.includes("integration")&&(e.includes("guide")||e.includes("doc"))?"integration-guide":e.includes("tutorial")||e.includes("getting-started")||e.includes("getting started")?"tutorial":e.includes("api")&&(e.includes("ref")||e.includes("doc"))?"api-reference":e.includes("doc")||e.includes("readme")||e.includes("md")||e.includes("guide")?"docs":"code"}function $t(n,t=ne){let e=[],s=[],o=n.filter(u=>(u.eventType==="stream_complete"||u.eventType==="stream_failed")&&u.contextTokensEstimated!==void 0);if(o.length<t)return{correlations:[],suggestedThresholds:{},insights:[`Not enough data for learning. Have ${o.length}, need ${t} samples.`],hasEnoughData:!1};let r=o.filter(u=>u.eventType==="stream_complete").length,i=r/o.length;s.push(`Overall success rate: ${(i*100).toFixed(1)}% (${r}/${o.length})`);let a=vt(o);a.optimalRange&&(e.push({factor:"contextTokens",successRate:a.optimalSuccessRate,sampleSize:a.optimalSampleSize,threshold:a.optimalRange.max,recommendation:`Optimal context size: ${a.optimalRange.min.toLocaleString()}-${a.optimalRange.max.toLocaleString()} tokens (${(a.optimalSuccessRate*100).toFixed(1)}% success)`}),s.push(e[e.length-1].recommendation));let l=Ct(o);l.softViolationSuccessRate!==void 0&&e.push({factor:"softViolation",successRate:l.softViolationSuccessRate,sampleSize:l.softViolationCount,threshold:0,recommendation:l.softViolationSuccessRate<.7?"Soft limit violations have low success rate - consider lowering soft limit":"Soft limit violations acceptable - current threshold is appropriate"});let c=bt(e,a,o.length);return{correlations:e,suggestedThresholds:c,insights:s,hasEnoughData:!0}}function vt(n){let t=[{min:0,max:5e4},{min:5e4,max:1e5},{min:1e5,max:15e4},{min:15e4,max:2e5}],e=t[0],s=0,o=0;for(let r of t){let i=n.filter(a=>a.contextTokensEstimated!==void 0&&a.contextTokensEstimated>=r.min&&a.contextTokensEstimated<r.max);if(i.length>=5){let l=i.filter(c=>c.eventType==="stream_complete").length/i.length;l>s&&(s=l,e=r,o=i.length)}}return{optimalRange:o>=5?e:void 0,optimalSuccessRate:s,optimalSampleSize:o}}function Ct(n){let t=n.filter(s=>s.budgetViolationType==="soft"),e=n.filter(s=>s.budgetViolationType==="hard");return{softViolationCount:t.length,softViolationSuccessRate:t.length>=5?t.filter(s=>s.eventType==="stream_complete").length/t.length:void 0,hardViolationCount:e.length,hardViolationSuccessRate:e.length>=5?e.filter(s=>s.eventType==="stream_complete").length/e.length:void 0}}function bt(n,t,e){let s={sampleCount:e,confidence:St(e),lastUpdated:new Date().toISOString(),version:1};return t.optimalRange&&(s.globalSoftLimit=t.optimalRange.max,s.globalHardLimit=Math.round(t.optimalRange.max*1.3)),s}function kt(n,t,e=.3){if(!t.hasEnoughData)return n;let s={...n},o=t.suggestedThresholds;return o.globalSoftLimit!==void 0&&(s.globalSoftLimit=Math.round(n.globalSoftLimit*(1-e)+o.globalSoftLimit*e)),o.globalHardLimit!==void 0&&(s.globalHardLimit=Math.round(n.globalHardLimit*(1-e)+o.globalHardLimit*e)),o.sampleCount!==void 0&&(s.sampleCount=o.sampleCount),o.confidence!==void 0&&(s.confidence=o.confidence),s.lastUpdated=new Date().toISOString(),s}function Se(n){return F.join(n,".orchex","learn","thresholds.json")}async function Tt(n,t){let e=Se(n),s=F.dirname(e);await T.mkdir(s,{recursive:!0}),await T.writeFile(e,JSON.stringify(t,null,2),"utf-8")}async function Et(n){let t=Se(n);try{let e=await T.readFile(t,"utf-8"),s=JSON.parse(e);return s.version!==1?(H.warn({version:s.version},"unknown_thresholds_version"),null):s}catch{return null}}async function $e(n){return await Et(n)??{...B}}function Ot(n,t,e){switch(e){case"owns":return n.maxOwnsCount[t]??B.maxOwnsCount.other;case"reads":return n.maxReadsCount[t]??B.maxReadsCount.other;case"tokens":return n.maxContextTokens[t]??n.globalSoftLimit}}function ve(n){return F.join(n,".orchex","learn","events.jsonl")}function Pt(n,t,e){return{id:`learn-${Date.now()}-${n.id}`,sessionHash:"local",eventType:n.status==="complete"?"stream_complete":"stream_failed",timestamp:new Date().toISOString(),durationMs:n.executionTimeMs,success:n.status==="complete",tokensInput:n.tokensUsed?.input,tokensOutput:n.tokensUsed?.output,provider:t,model:e,contextTokensEstimated:n.contextMetrics?.estimatedTokens,contextTokensActual:n.contextMetrics?.actualTokens,contextBudgetUtilization:n.contextMetrics?.budgetUtilization,budgetViolationType:n.contextMetrics?.violationType}}async function Mt(n,t){if(t.length===0)return;let e=ve(n),s=F.dirname(e);await T.mkdir(s,{recursive:!0});let o=t.map(r=>JSON.stringify(r)).join(`
|
|
92
102
|
`)+`
|
|
93
|
-
`;await
|
|
94
|
-
`))if(o.trim())try{s.push(JSON.parse(o))}catch{}return s}catch{return[]}}async function
|
|
95
|
-
`),o=
|
|
103
|
+
`;await T.appendFile(e,o,"utf-8")}async function It(n){let t=ve(n);try{let e=await T.readFile(t,"utf-8"),s=[];for(let o of e.split(`
|
|
104
|
+
`))if(o.trim())try{s.push(JSON.parse(o))}catch{}return s}catch{return[]}}async function Rt(n){let t=await It(n);if(t.length<ne)return H.debug({eventCount:t.length,minRequired:ne},"learning_skipped_insufficient_data"),null;let e=$t(t);if(!e.hasEnoughData)return H.debug({insights:e.insights},"learning_insufficient_context_data"),e;let s=await $e(n),o=kt(s,e);return await Tt(n,o),H.info({sampleCount:o.sampleCount,confidence:o.confidence,globalSoftLimit:o.globalSoftLimit,globalHardLimit:o.globalHardLimit},"learning_cycle_completed"),e}var _t=["tests","migrations","docs","types","styles","core"],Ft=["types","migrations","styles","core","tests","docs"];function jt(n){let t=n.toLowerCase(),e=t.split("/").pop()??t;for(let s of _t)switch(s){case"tests":if(t.includes("/test")||t.includes("/__tests__/")||e.includes(".test.")||e.includes(".spec.")||e.startsWith("test_")||e.endsWith("_test.ts")||e.endsWith("_test.js"))return"tests";break;case"migrations":if(t.includes("/migration")||e.includes("migration")||e.endsWith(".sql"))return"migrations";break;case"docs":if(t.endsWith(".md")||t.includes("/docs/")||t.includes("/documentation/"))return"docs";break;case"types":if(e.includes("types")||e.includes("schema")||e.includes("interface")||e==="index.d.ts")return"types";break;case"styles":if(t.endsWith(".css")||t.endsWith(".scss")||t.endsWith(".less")||t.endsWith(".sass")||t.includes("/styles/"))return"styles";break}return"core"}var At={types:["type","interface","schema","define","definition","typescript","zod"],migrations:["migrate","migration","schema","table","column","database","sql","alter"],core:["implement","create","add","configure","setup","install","build"],tests:["test","verify","check","assert","coverage","spec","expect"],docs:["document","readme","guide","example","usage","api reference"],styles:["style","css","scss","theme","design","token","color","layout"]};function Dt(n,t,e){let s=n.split(`
|
|
105
|
+
`),o=At[t],r=e.map(a=>(a.split("/").pop()??a).toLowerCase().replace(/\.[^.]+$/,"")),i=s.filter(a=>{let l=a.toLowerCase();return!!(o.some(c=>l.includes(c))||r.some(c=>l.includes(c)))});return i.length>0?i.join(`
|
|
96
106
|
`):`${n}
|
|
97
107
|
|
|
98
|
-
Files: ${e.join(", ")}`}function
|
|
108
|
+
Files: ${e.join(", ")}`}function Lt(n,t){let e=n.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40);return t?`${t}-${e}`:e}function be(n){let t=[],e=[],s=/^\s*[-*]?\s*(?:Create|Modify|Test):\s*`([^`]+)`/gim,o;for(;(o=s.exec(n))!==null;){let a=o[1].replace(/:\d+(-\d+)?$/,"").trim();a&&a.includes(".")&&t.push(a)}let r=/\*\*(?:New\s+)?[Ff]ile:\*\*\s*`([^`]+)`/gi;for(;(o=r.exec(n))!==null;){let a=o[1].replace(/:\d+(-\d+)?$/,"").trim();a&&a.includes(".")&&t.push(a)}let i=/^\s*[-*]?\s*(?:Reads?|Imports?):\s*`([^`]+)`/gim;for(;(o=i.exec(n))!==null;){let a=o[1].replace(/:\d+(-\d+)?$/,"").trim();a&&a.includes(".")&&e.push(a)}return{owned:t,reads:e}}function ke(n,t){let e=new Set,s=new Set(t),o=/(?:import\s+(?:[\s\S]*?\s+from\s+)?|import\s*\()['"]([^'"]+)['"]/g,r=/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;for(let i of n){let a=[],l;for(o.lastIndex=0;(l=o.exec(i.code))!==null;)a.push(l[1]);for(r.lastIndex=0;(l=r.exec(i.code))!==null;)a.push(l[1]);for(let c of a){let u=Nt(c,i.filename);u&&(s.has(u)||t.some(d=>d.endsWith("/"+u))||e.add(u))}}return[...e]}function Nt(n,t){if(!n.startsWith(".")&&!n.startsWith("src/")&&!n.startsWith("tests/")&&!n.startsWith("lib/")||n.startsWith("node:"))return null;let e;if(n.startsWith(".")){if(!t)return null;let s=t.split("/");s.pop();let o=s.join("/"),r=[...o?o.split("/"):[]];for(let i of n.split("/"))i!=="."&&(i===".."?r.pop():r.push(i));e=r.join("/")}else e=n;return e.endsWith(".js")&&(e=e.replace(/\.js$/,".ts")),e.includes(".")||(e=e+".ts"),e}function Wt(n,t){let e=new Set,s=new Set,o=n.content.match(/reads:\s*\[([^\]]+)\]/i);if(o){let d=o[1].split(",").map(f=>f.trim().replace(/[`"']/g,""));for(let f of d)f&&f.includes(".")&&s.add(f)}let r=L(n),i=Te(r),a=be(i);for(let d of a.owned)s.has(d)||e.add(d);let l=V(n,t);for(let d of l)d.filename&&d.filename.includes(".")&&!s.has(d.filename)&&e.add(d.filename);let c=/owns:\s*\[([^\]]+)\]/gi,u;for(;(u=c.exec(i))!==null;){let d=u[1].split(",").map(f=>f.trim().replace(/[`"']/g,""));for(let f of d)f&&f.includes(".")&&!s.has(f)&&e.add(f)}return[...e]}function Te(n){return n.replace(/^```[^\n]*\n[\s\S]*?^```\s*$/gm,"")}function L(n){let t=n.content;for(let e of n.children)t+=`
|
|
99
109
|
`+e.title+`
|
|
100
|
-
`+L(e);return t}function V(n,t){let e=[...t];for(let s of n.children){e.push(...s.codeBlocks);for(let o of s.children)e.push(...V(o,[]))}return e}function
|
|
101
|
-
`);for(let e of t){let s=e.trim();if(!s||/^-{3,}$/.test(s)||/^\*\*[^*]+\*\*$/.test(s)&&s.split(/\s+/).length<=3)continue;if(s.split(/\s+/).filter(r=>r.length>0).length>3)return s.length>150?s.slice(0,147)+"...":s}return""}function
|
|
102
|
-
`)}function
|
|
103
|
-
`)}function
|
|
110
|
+
`+L(e);return t}function V(n,t){let e=[...t];for(let s of n.children){e.push(...s.codeBlocks);for(let o of s.children)e.push(...V(o,[]))}return e}function Ut(n){let t=n.split(`
|
|
111
|
+
`);for(let e of t){let s=e.trim();if(!s||/^-{3,}$/.test(s)||/^\*\*[^*]+\*\*$/.test(s)&&s.split(/\s+/).length<=3)continue;if(s.split(/\s+/).filter(r=>r.length>0).length>3)return s.length>150?s.slice(0,147)+"...":s}return""}function zt(n,t,e=3e3){let s=L(n);if(s.length<=e||n.children.length<3)return s.slice(0,e);let o=[],r=n.content.trim();r&&o.push(r.slice(0,300));for(let l=0;l<n.children.length;l++){let c=n.children[l],u=c.title,d=Ut(c.content),p=(c.fileReferences||[]).filter(g=>t.includes(g)),m=`${l+1}. ${u}`;p.length>0&&(m+=` (${p.join(", ")})`),d&&(m+=` \u2014 ${d}`),o.push(m)}let i=0,a=[];for(let l of o){if(i+l.length+1>e&&a.length>0)break;a.push(l),i+=l.length+1}return a.join(`
|
|
112
|
+
`)}function Ht(n,t){let e=new Set,s=L(n),o=Te(s),r=o.match(/reads:\s*\[([^\]]+)\]/i);if(r){let c=r[1].split(",").map(u=>u.trim().replace(/[`"']/g,""));for(let u of c)u&&u.includes(".")&&!t.includes(u)&&e.add(u)}let i=be(o);for(let c of i.reads)t.includes(c)||e.add(c);let a=V(n,n.codeBlocks),l=ke(a,t);for(let c of l)t.includes(c)||e.add(c);return[...e]}function Ee(n){let t=new Map;for(let e of n){let s=jt(e);t.has(s)||t.set(s,[]),t.get(s).push(e)}return t}function Oe(n){if(n._fromYaml)return{split:!1,reasons:[]};let e=[];n.ownedFiles.length>4&&e.push(`Owns ${n.ownedFiles.length} files (max recommended: 4)`);let s=(n.description.match(/\band\b/gi)??[]).length;if(s>2&&e.push(`Description has ${s} "and" conjunctions (suggests multiple tasks)`),n.ownedFiles.length>1){let o=Ee(n.ownedFiles);if(o.size>1){let r=[...o.keys()].join(", ");e.push(`Files belong to ${o.size} different concerns (${r})`)}}return{split:e.length>0,reasons:e}}function Bt(n){let t=q(n.name,n.plan||"");return{id:n.id,name:n.name,description:n.plan||"",category:t,ownedFiles:n.owns||[],readFiles:n.reads||[],explicitDeps:n.deps||[],codeExamples:[],isAtomic:!0,_fromYaml:!0,_verify:n.verify,_setup:n.setup}}function qt(n,t,e){let s=[],o=z(n.sections);for(let r of o){let i=te(r);if(e){let a=r.codeBlocks.filter(l=>l.language==="yaml"||l.language==="yml");e.yamlBlocksFound+=a.length,e.yamlBlocksParsed+=i.length}for(let a of i){t&&!a.id.startsWith(t)&&(a.id=`${t}-${a.id}`);let l=Bt(a),c=Oe(l);c.split&&(l.isAtomic=!1,l.suggestedSplit=c.reasons),s.push(l)}}return s}function Vt(n){let t=z(n.sections);for(let e of t)if(te(e).length>0)return!0;return!1}function Yt(n){if(["test plan","implementation order","security checklist","gap inventory","task order","dependency order","execution order","deployment order","wave order"].some(r=>n.includes(r)))return!0;let e=["checklist","inventory","roadmap","timeline","schedule"],s=n.split(/[\s:]+/).filter(r=>r.length>0),o=s[s.length-1]??"";return!!e.includes(o)}function Gt(n,t={}){let{deliverableLevel:e=2,prefix:s,preferYaml:o=!0,diagnostics:r}=t;if(o&&Vt(n)){r&&(r.extractionPath="yaml");let c=qt(n,s,r);return r&&(r.deliverableCount=c.length),c}if(r){let c=z(n.sections);for(let u of c)r.yamlBlocksFound+=u.codeBlocks.filter(d=>d.language==="yaml"||d.language==="yml").length;r.extractionPath="markdown"}let i=[],a=U(n.sections,e);if(r)for(let c of[2,3,4])r.sectionsFound[c]=U(n.sections,c).length;for(let c of a){let S=function(I){for(let R of I.fileReferences)m.includes(R)||g.includes(R)||k&&!v.has(R)||g.push(R);for(let R of I.children)S(R)};var l=S;let u=c.title.toLowerCase(),f=u.split(/[\s:]+/).filter(I=>I.length>0)[0]??"";if(u.includes("overview")&&a.indexOf(c)===0||f==="summary"||u==="summary: task order"||f==="conclusion"||f==="introduction"||f==="context"||f==="background"||f==="appendix"||f==="references"||f==="changelog"||f==="prerequisites"||Yt(u)){r&&r.sectionsFilteredAsMeta.push(c.title);continue}let p=Lt(c.title,s),m=Wt(c,c.codeBlocks),g=Ht(c,m),y=V(c,c.codeBlocks),v=new Set(ke(y,m)),k=v.size>0;for(let I of c.children)S(I);let x=L(c),h=q(c.title,x),w={id:p,name:c.title,description:zt(c,m),category:h,ownedFiles:m,readFiles:g,explicitDeps:c.explicitDeps,codeExamples:y,isAtomic:!0,childCount:c.children.length},he=Oe(w);he.split&&(w.isAtomic=!1,w.suggestedSplit=he.reasons),i.push(w)}return r&&(r.deliverableCount=i.length),i}function Kt(n,t){let e=(n.language||"").toLowerCase(),s=n.code.toLowerCase();switch(t){case"migrations":return e==="sql"||s.includes("create table")||s.includes("alter table");case"types":return(e==="typescript"||e==="ts")&&(s.includes("export type ")||s.includes("export interface ")||s.includes("z.object"));case"tests":return s.includes("describe(")||s.includes("it(")||s.includes("expect(");case"docs":return e==="markdown"||e==="md";case"styles":return e==="css"||e==="scss"||e==="less"||e==="sass";case"core":return(e==="typescript"||e==="ts"||e==="javascript"||e==="js")&&!s.includes("export type ")&&!s.includes("export interface ")&&!s.includes("describe(")&&!s.includes("it(");default:return!1}}function Jt(n){if(n._fromYaml)return[{...n,isAtomic:!0}];let e=Ee(n.ownedFiles);if(e.size<=1)return[{...n,isAtomic:!0}];let s=[],o=null,r=0;for(let i of Ft){let a=e.get(i);if(!a||a.length===0)continue;r++;let l=`${n.id}-${i}`,c=`${n.name} (${i})`,u=Dt(n.description,i,a),d=[];r===1&&n.explicitDeps.length>0&&d.push(...n.explicitDeps),o&&d.push(o);let f=[];switch(i){case"types":break;case"core":case"migrations":f=[...n.readFiles];break;case"tests":f=[...e.get("core")||[]];break;case"docs":f=[...e.get("core")||e.get("types")||[]];break}let p=n.codeExamples.filter(m=>m.filename&&a.some(g=>m.filename===g)?!0:m.filename?!1:Kt(m,i));s.push({id:l,name:c,description:u,category:n.category,ownedFiles:a,readFiles:f,explicitDeps:d,codeExamples:p,isAtomic:!0}),o=l}return s}function Qt(n){let t=[];for(let e of n)e.isAtomic?t.push(e):t.push(...Jt(e));return t}function Ce(n){let t=[];return t.push(`${n.id}:`),t.push(` Name: ${n.name}`),t.push(` Category: ${n.category}`),t.push(` Owns: ${n.ownedFiles.join(", ")||"(none)"}`),n.readFiles.length>0&&t.push(` Reads: ${n.readFiles.join(", ")}`),n.explicitDeps.length>0&&t.push(` Deps: ${n.explicitDeps.join(", ")}`),n.isAtomic||t.push(` \u26A0\uFE0F Should split: ${n.suggestedSplit?.join("; ")}`),t.join(`
|
|
113
|
+
`)}function Xt(n){let t=n.filter(o=>o.isAtomic),e=n.filter(o=>!o.isAtomic),s=`=== Deliverables Report ===
|
|
104
114
|
|
|
105
115
|
`;if(s+=`Total: ${n.length} deliverables
|
|
106
116
|
`,s+=` ${t.length} atomic (ready for streams)
|
|
@@ -108,26 +118,28 @@ Files: ${e.join(", ")}`}function Ft(n,t){let e=n.toLowerCase().replace(/[^a-z0-9
|
|
|
108
118
|
|
|
109
119
|
`,e.length>0){s+=`--- Needs Splitting ---
|
|
110
120
|
|
|
111
|
-
`;for(let o of e)s
|
|
121
|
+
`;for(let o of e)s+=Ce(o)+`
|
|
112
122
|
|
|
113
123
|
`}s+=`--- Atomic Deliverables ---
|
|
114
124
|
|
|
115
|
-
`;for(let o of t)s
|
|
125
|
+
`;for(let o of t)s+=Ce(o)+`
|
|
116
126
|
|
|
117
|
-
`;return s}var
|
|
118
|
-
`)}import*as
|
|
127
|
+
`;return s}var Pe=["-types","-migrations","-core","-tests","-docs"];function se(n,t){let e=Pe.find(a=>n.id.endsWith(a));if(!e)return n;let s=n.id.slice(0,-e.length),o=t.filter(a=>Pe.some(l=>a.id===`${s}${l}`));if(o.length<=1)return n;let r=o.find(a=>a.id===`${s}-core`);if(r)return r;let i=["-migrations","-types"];for(let a of i){let l=o.find(c=>c.id===`${s}${a}`);if(l)return l}return n}function Zt(n,t){let e=n.toLowerCase().trim(),s=t.find(l=>l.id===n);if(s)return s;let o=t.find(l=>l.name.toLowerCase()===e);if(o)return se(o,t);let r=t.find(l=>l.id.includes(e)||e.includes(l.id));if(r)return se(r,t);let i=e.split(/[\s-_]+/).filter(l=>l.length>2),a=t.find(l=>{let c=l.name.toLowerCase().split(/[\s-_]+/);return i.filter(d=>c.some(f=>f.includes(d)||d.includes(f))).length>=i.length*.5});if(a)return se(a,t)}function en(n){let t=`${n.name} ${n.description}`.toLowerCase();return/\b(cleanup|clean\s*up|remove|delete|drop)\b/.test(t)}function tn(n){let t=[],e=new Map;for(let r of n)if(!en(r))for(let i of r.ownedFiles)e.set(i,r);for(let r of n)for(let i of r.readFiles){let a=e.get(i);a&&a.id!==r.id&&t.push({from:r.id,to:a.id,reason:"file-ownership",explanation:`${r.id} reads ${i} which is owned by ${a.id}`})}let s=new Set(t.map(r=>`${r.from}\u2192${r.to}`)),o=new Set;for(let r of t){let i=`${r.to}\u2192${r.from}`;s.has(i)&&(o.add(`${r.from}\u2192${r.to}`),o.add(i))}return t.filter(r=>!o.has(`${r.from}\u2192${r.to}`))}function nn(n){let t=[];for(let e of n){if(e.category==="test"){let s=e.id.replace(/-tests?$/,"").replace(/^tests?-/,""),o=n.find(r=>r.id!==e.id&&r.category==="code"&&(r.id===s||r.id===`${s}-core`||r.id===`${s}-service`||r.id===`${s}-implementation`));o&&t.push({from:e.id,to:o.id,reason:"content-pattern",explanation:`${e.id} (test) depends on ${o.id} (implementation)`})}if(e.category==="docs"||e.category==="tutorial"){let s=e.id.replace(/^docs?-/,"").replace(/-docs?$/,"").replace(/^tutorials?-/,"").replace(/-tutorials?$/,""),o=n.filter(i=>i.id!==e.id&&i.category==="code"),r=o.find(i=>i.id===s)||o.find(i=>i.id===`${s}-service`||i.id===`${s}-core`||i.id===`${s}-implementation`)||o.find(i=>i.id.startsWith(`${s}-`)&&!i.id.includes("types"));r&&t.push({from:e.id,to:r.id,reason:"content-pattern",explanation:`${e.id} (${e.category}) documents ${r.id}`})}}return t}function sn(n,t){let e=[];for(let s of n)for(let o of s.explicitDeps){let r=Zt(o,n);if(r&&r.id!==s.id)e.push({from:s.id,to:r.id,reason:"explicit",explanation:`${s.id} explicitly depends on "${o}" (matched ${r.id})`});else if(!r){let i=`Stream '${s.id}': unmatched explicit dep '${o}'`;t?.diagnostics?.unmatchedDeps.push(i),t?.diagnostics?.warnings.push(i)}}return e}function Me(n){let t=[],e=new Set,s=new Set,o=[];function r(i){e.add(i),s.add(i),o.push(i);let a=n.get(i)||[];for(let l of a)if(!e.has(l))r(l);else if(s.has(l)){let c=o.indexOf(l);if(c!==-1){let u=[...o.slice(c),l];t.push(u)}}o.pop(),s.delete(i)}for(let i of n.keys())e.has(i)||r(i);return t}function on(n,t,e){let s=0,o=new Set;for(let r of n){let i=[];for(let f=0;f<r.length-1;f++)i.push({from:r[f],to:r[f+1]});let a=[];for(let f of i){let p=t.find(m=>m.from===f.from&&m.to===f.to&&!o.has(`${m.from}\u2192${m.to}`));p&&a.push(p)}if(a.length===0||!a.every(f=>f.reason==="file-ownership"))continue;let c=a.reduce((f,p)=>{let m=e.get(f.from)?.length??0,g=e.get(p.from)?.length??0;return g<m||g===m&&p.from<f.from?p:f}),u=t.indexOf(c);u!==-1&&t.splice(u,1);let d=e.get(c.from);if(d){let f=d.indexOf(c.to);f!==-1&&d.splice(f,1)}o.add(`${c.from}\u2192${c.to}`),s++}return{broken:s}}function rn(n,t){let e=[...sn(n,t),...tn(n),...nn(n)],s=new Set,o=[];for(let a of e){let l=`${a.from}\u2192${a.to}`;s.has(l)||(s.add(l),o.push(a))}let r=new Map;for(let a of n)r.set(a.id,[]);for(let a of o){let l=r.get(a.from)||[];l.includes(a.to)||l.push(a.to),r.set(a.from,l)}let i=Me(r);if(i.length>0){let{broken:a}=on(i,o,r);a>0&&(i=Me(r))}return{dependencies:r,edges:o,cycles:i,isAcyclic:i.length===0}}function an(n){let t=["=== Dependency Analysis ===",""];if(t.push(`Total edges: ${n.edges.length}`),t.push(`Acyclic: ${n.isAcyclic?"Yes \u2713":"No \u26A0\uFE0F"}`),n.cycles.length>0){t.push(""),t.push("--- Cycles Detected ---");for(let e of n.cycles)t.push(` ${e.join(" \u2192 ")}`)}t.push(""),t.push("--- Dependencies by Deliverable ---");for(let[e,s]of n.dependencies)s.length>0&&t.push(`${e}: ${s.join(", ")}`);t.push(""),t.push("--- Edge Details ---");for(let e of n.edges)t.push(`${e.from} \u2192 ${e.to} (${e.reason})`),t.push(` ${e.explanation}`);return t.join(`
|
|
128
|
+
`)}import*as C from"node:fs";import*as $ from"node:path";var Ie={maxOwnsCount:4,maxReadsCount:4,maxDirectories:2,maxPlanConjunctions:4,warnOnMixedActions:!0,warnOnMixedFileTypes:!0,requireVerifyCommands:!0},oe=class{config;constructor(t=Ie){this.config=t}analyzeStream(t,e){let s=[],o=e.owns||[],r=e.reads||[],i=e.plan||"",a=e.verify||[],l=o.length,c=r.length,u=this.countDirectories(o),d=this.countConjunctions(i),f=a.length,p=this.detectActionTypes(i),m=this.detectFileTypes([...o,...r]),g={ownsCount:l,readsCount:c,directoriesAffected:u,planConjunctions:d,verifyCommands:f,actionTypes:p,fileTypes:m};l>this.config.maxOwnsCount&&u>this.config.maxDirectories?s.push({type:"high_owns_complexity",severity:"error",message:`Stream owns ${l} files across ${u} directories`,details:`Consider splitting into smaller streams. Threshold: ${this.config.maxOwnsCount} files across ${this.config.maxDirectories} directories`,streamName:t}):l>this.config.maxOwnsCount&&s.push({type:"high_owns_count",severity:"warning",message:`Stream owns ${l} files (threshold: ${this.config.maxOwnsCount})`,details:"Consider splitting into smaller, more focused streams",streamName:t}),c>this.config.maxReadsCount&&s.push({type:"high_reads_count",severity:"warning",message:`Stream reads ${c} files (threshold: ${this.config.maxReadsCount})`,details:"Too many dependencies may indicate unclear scope or context bloat",streamName:t}),d>this.config.maxPlanConjunctions&&s.push({type:"compound_plan",severity:"warning",message:`Plan contains ${d} 'and' conjunctions (threshold: ${this.config.maxPlanConjunctions})`,details:"Complex plans with multiple actions should be split into separate streams",streamName:t}),this.config.warnOnMixedActions&&this.hasMixedActions(p)&&s.push({type:"mixed_actions",severity:"warning",message:"Stream mixes structural changes with content changes",details:`Detected actions: ${p.join(", ")}. Consider separating setup/structure from implementation`,streamName:t}),this.hasUnboundedTutorial(i,o)&&s.push({type:"unbounded_tutorial",severity:"error",message:"Stream appears to create tutorial/documentation without specific file ownership",details:"Tutorial or documentation streams must specify exact files in owns[]",streamName:t}),this.config.warnOnMixedFileTypes&&m.size>3&&s.push({type:"mixed_file_types",severity:"info",message:`Stream touches ${m.size} different file types`,details:`File types: ${Array.from(m).join(", ")}. Consider organizing by concern`,streamName:t}),this.config.requireVerifyCommands&&f===0&&l>0&&s.push({type:"no_verify",severity:"warning",message:"Stream has no verify commands",details:"Add verify commands to ensure implementation correctness",streamName:t}),(!i||i.trim().length===0)&&s.push({type:"empty_plan",severity:"error",message:"Stream has no plan description",details:"Every stream must have a clear plan describing what it does",streamName:t}),this.hasVaguePlan(i)&&s.push({type:"vague_plan",severity:"info",message:"Plan may be too vague or generic",details:"Use specific, actionable language describing exact changes",streamName:t});let y=this.calculateQualityScore(s,g);return{streamName:t,qualityScore:y,issues:s,metrics:g}}analyzeStreams(t){let e=[];for(let[r,i]of Object.entries(t))e.push(this.analyzeStream(r,i));let s=this.countIssuesBySeverity(e),o=this.calculateOverallScore(e);return{streams:e,overallScore:o,totalIssues:s}}countDirectories(t){let e=new Set;for(let s of t){let o=s.substring(0,s.lastIndexOf("/"));o?e.add(o):e.add(".")}return e.size}countConjunctions(t){let s=t.toLowerCase().match(/\band\b/g);return s?s.length:0}detectActionTypes(t){let e=t.toLowerCase(),s=[],o=[{type:"create",pattern:/\b(create|add|implement|build)\b/},{type:"update",pattern:/\b(update|modify|change|edit|refactor)\b/},{type:"delete",pattern:/\b(delete|remove)\b/},{type:"configure",pattern:/\b(configure|setup|install)\b/},{type:"test",pattern:/\b(test|verify)\b/},{type:"document",pattern:/\b(document|write|tutorial)\b/}];for(let{type:r,pattern:i}of o)i.test(e)&&s.push(r);return s}detectFileTypes(t){let e=new Set;for(let s of t){let o=s.substring(s.lastIndexOf(".")+1).toLowerCase();o&&o!==s&&e.add(o)}return e}hasMixedActions(t){let e=["create","delete","configure"],s=["update","document"],o=t.some(i=>e.includes(i)),r=t.some(i=>s.includes(i));return o&&r}hasUnboundedTutorial(t,e){let s=t.toLowerCase();return/\b(tutorial|guide|documentation|example)\b/.test(s)&&e.length===0}hasVaguePlan(t){let e=t.toLowerCase(),s=["various","some","multiple","general","misc","other","stuff","things"];for(let o of s)if(e.includes(o))return!0;return t.trim().split(/\s+/).length<5}calculateQualityScore(t,e){let s=100;for(let o of t)switch(o.severity){case"error":s-=20;break;case"warning":s-=10;break;case"info":s-=5;break}return e.verifyCommands>0&&(s+=5),e.ownsCount>0&&e.ownsCount<=3&&(s+=5),e.planConjunctions===0&&(s+=5),Math.max(0,Math.min(100,s))}calculateOverallScore(t){if(t.length===0)return 0;let e=t.reduce((s,o)=>s+o.qualityScore,0);return Math.round(e/t.length)}countIssuesBySeverity(t){let e={errors:0,warnings:0,info:0};for(let s of t)for(let o of s.issues)switch(o.severity){case"error":e.errors++;break;case"warning":e.warnings++;break;case"info":e.info++;break}return e}};function N(n){return new oe({...Ie,...n})}import{createLogger as cn}from"../logging.js";var ln=cn("topology-optimizer");function un(n){let t=new Map,e=[...n.keys()];function s(o,r){let i=new Set,a=[o];for(;a.length>0;){let l=a.shift();if(!i.has(l)){i.add(l);for(let c of n.get(l)??[])c!==r&&!i.has(c)&&a.push(c)}}return i}for(let o of e){let r=n.get(o)??[],i=[];for(let a of r){let l=r.filter(u=>u!==a),c=!1;for(let u of l)if(s(u,o).has(a)){c=!0;break}c||i.push(a)}t.set(o,i)}return t}function dn(n){let t=new Map,e=new Map;for(let r of n){t.set(r.id,r.deps.length);for(let i of r.deps)e.has(i)||e.set(i,[]),e.get(i).push(r.id);e.has(r.id)||e.set(r.id,[])}let s=n.filter(r=>r.deps.length===0).map(r=>r.id),o=0;for(;s.length>0;){let r=s.shift();o++;for(let i of e.get(r)??[])t.set(i,(t.get(i)??1)-1),t.get(i)===0&&s.push(i)}return o===n.length}function fn(n){let t=[],e=new Set,s=new Map(n.map(o=>[o.id,[...o.deps]]));for(;s.size>0;){let o=[];for(let[r,i]of s)i.every(a=>e.has(a))&&o.push(r);if(o.length===0)break;for(let r of o)s.delete(r),e.add(r);t.push(o)}return t}function re(n){let t=[],e=n.reduce((f,p)=>f+p.deps.length,0),s=new Map(n.map(f=>[f.id,[...f.deps]])),o=un(s);t.push("transitive-reduction");let r=n.map(f=>({...f,deps:o.get(f.id)??f.deps})),i=r.reduce((f,p)=>f+p.deps.length,0),a=e-i;a>0&&ln.info({edgesRemoved:a,original:e},"transitive_reduction_applied");let l=fn(r),c=dn(r),u=Math.max(0,...l.map(f=>f.length)),d=l.length===1?"parallel":u===1?"sequential":"mixed";return{streams:r,waves:l,report:{originalEdgeCount:e,edgesRemoved:a,waveCount:l.length,classification:d,passesApplied:t},isValid:c}}var pn={code:12e4,test:9e4,docs:6e4,tutorial:9e4,"integration-guide":9e4,"api-reference":6e4,migration:18e4,other:12e4};function mn(n,t=5,e=4e3){let s=n.description.trim();if(s.split(/\s+/).filter(r=>r.length>0).length<t){let r=hn(n.category),i=n.ownedFiles.join(", ")||"the target files";s=`${r} ${n.name}. ${s}. Target: ${i}`}if(n.codeExamples.length>0){let r=[],i=0;for(let a of n.codeExamples){let l=`\`\`\`${a.language||""}
|
|
119
129
|
${a.code}
|
|
120
130
|
\`\`\``;if(i+l.length>e)break;r.push(l),i+=l.length}r.length>0&&(s+=`
|
|
121
131
|
|
|
122
132
|
Reference code:
|
|
123
133
|
`+r.join(`
|
|
124
134
|
|
|
125
|
-
`))}return s}function
|
|
126
|
-
`).length;if(
|
|
127
|
-
`)}function
|
|
128
|
-
`);for(let i of r){let a=
|
|
129
|
-
`)}function
|
|
130
|
-
`)}import*as W from"fs/promises";import*as k from"path";async function jn(n,t){if(!t.confirm)throw new Error("Reset learning requires --confirm flag. This permanently deletes learning data.");let e=[],s=k.join(n,".orchex","learn"),o=k.join(n,".orchex","reports");t.patternsOnly?await Y(k.join(s,"patterns.json"),e):t.reportsOnly?await De(o,e,".json"):(await Y(k.join(s,"thresholds.json"),e),await Y(k.join(s,"events.jsonl"),e),await Y(k.join(s,"patterns.json"),e),await De(o,e,".json"));let r=t.patternsOnly?"patterns":t.reportsOnly?"reports":"all learning data";return{deleted:e,totalDeleted:e.length,message:e.length>0?`Reset ${r}: ${e.length} file(s) deleted.`:`No ${r} found to delete.`}}async function Y(n,t){try{await W.unlink(n),t.push(k.basename(n))}catch(e){if(e.code!=="ENOENT")throw e}}async function De(n,t,e){try{let s=await W.readdir(n);for(let o of s)e&&!o.endsWith(e)||(await W.unlink(k.join(n,o)),t.push(o))}catch(s){if(s.code!=="ENOENT")throw s}}var An=[{pattern:/model.*not.found|not_found_error.*model|Model ".*" not found/i,category:"model_not_found",retryable:!1,selfHealable:!1,suggestion:"Model not found. Check the model name in your configuration and ensure it is available for your API key."},{pattern:/invalid api key|api key.*expired|authentication failed|(?<!\d)401(?!\d)|unauthorized/i,category:"auth_error",retryable:!1,selfHealable:!1,suggestion:"Authentication error. Check your API key configuration and ensure it is valid and not expired."},{pattern:/cloud api error: 5\d{2}|502 bad gateway|503 service unavailable|504 gateway timeout|internal server error|overloaded_error/i,category:"server_error",retryable:!0,selfHealable:!1,suggestion:"Cloud server error. Transport retries exhausted \u2014 try again later or switch to local mode."},{pattern:/timed?\s*out|ETIMEDOUT|deadline|timeout/i,category:"timeout",retryable:!1,selfHealable:!1,suggestion:"Timeout is an infrastructure issue. Consider increasing stream timeout or reducing scope."},{pattern:/network error|ECONNREFUSED|ECONNRESET|EHOSTUNREACH|socket hang up/i,category:"network",retryable:!1,selfHealable:!1,suggestion:"Network connectivity issue. Check API endpoint availability and network configuration."},{pattern:/rate limit|too many requests|429|quota exceeded/i,category:"rate_limit",retryable:!1,selfHealable:!1,suggestion:"Rate limited by API. Wait before retrying or reduce parallel stream count."},{pattern:/old_?content.*not found|edit.*mismatch|does not match|oldContent/i,category:"edit_mismatch",retryable:!0,selfHealable:!0,suggestion:"The file content changed since context was built. Re-read the file and retry with updated content."},{pattern:/invalid.*artifact|parse.*error|orchex-artifact.*not found|JSON\.parse/i,category:"invalid_artifact",retryable:!0,selfHealable:!0,suggestion:"The agent produced malformed output. Retry with clearer instructions about the artifact format."},{pattern:/ENOENT|EACCES|EPERM|ENOSPC|no such file|permission denied/i,category:"environment",retryable:!1,selfHealable:!1,suggestion:"File system error. Check file paths and permissions."},{pattern:/ownership violation|outside owned files|SECURITY.*path traversal|SECURITY.*absolute path/i,category:"ownership_violation",retryable:!0,selfHealable:!0,suggestion:"File operation attempted outside owned files. The fix stream should only modify files in the owns list, or the owns list should be updated to include the new file."},{pattern:/test.*fail|expect.*received|assertion.*error|FAIL\s+tests\//i,category:"test_failure",retryable:!0,selfHealable:!0,suggestion:"Tests are failing. Include the test error output in the retry prompt so the agent can fix the issue."},{pattern:/lint|eslint|prettier|formatting/i,category:"lint_error",retryable:!0,selfHealable:!0,suggestion:"Lint or formatting error. Include the lint output in the retry prompt."},{pattern:/TypeError|ReferenceError|SyntaxError|Cannot find module|cannot find name|TS\d{4}/i,category:"runtime_error",retryable:!0,selfHealable:!0,suggestion:"Code has type or runtime errors. Include the error output and relevant type definitions in the retry prompt."}];function ie(n,t){for(let{pattern:s,category:o,retryable:r,selfHealable:i,suggestion:a}of An)if(s.test(n))return{category:o,retryable:r,selfHealable:i,suggestion:a};let e=t==="artifact"||t==="verify";return{category:"unknown",retryable:e,selfHealable:e,suggestion:e?"Unknown code error. Retry with the full error message included in the prompt.":`Unknown infrastructure error (origin: ${t??"unspecified"}). Check API key, model availability, and network connectivity.`}}import{createLogger as Dn}from"../logging.js";var Ln=Dn("iteration-evaluator");function Nn(n){let{streamResults:t,iterationNumber:e,maxIterations:s,intent:o}=n;if(e>=s){let d=t.filter(f=>f.status==="failed"||!f.verifyPassed).length;return{complete:!0,reason:`Reached max iterations (${s})${d>0?` with ${d} unresolved failure(s)`:""}`,failureSummary:d>0?t.filter(f=>f.status==="failed").map(f=>`${f.id}: ${f.error}`).join("; "):void 0}}let r=t.filter(d=>d.status==="failed"),i=t.filter(d=>d.status==="complete"&&!d.verifyPassed);if(r.length===0&&i.length===0)return{complete:!0,reason:`All ${t.length} stream(s) completed and verified successfully`};let l=[];for(let d of r)l.push(`Stream "${d.id}" failed: ${d.error??"unknown error"}`);for(let d of i)l.push(`Stream "${d.id}" verify failed: ${d.verifyError??"verification error"}`);let c=l.join("; "),u=`Fix the following issues from the previous attempt to "${o}": ${c}`;return Ln.info({iteration:e,failed:r.length,verifyFailed:i.length},"iteration_incomplete"),{complete:!1,reason:`${r.length} stream(s) failed, ${i.length} verification(s) failed`,nextIntent:u,failureSummary:c}}var Wn={id:"documentation-set",name:"Documentation Set",description:"Multiple documentation files (guides, tutorials, API references) that should be created independently",keywords:["docs","documentation","guide","tutorial","readme","api reference","multiple pages"],patterns:["Multiple .md files in docs/","Creating 3+ documentation files","Tutorial series","API documentation pages"],streamStructure:[{namePattern:"docs-{topic}",purpose:"Create documentation for a specific topic",dependsOn:[],ownsPatterns:["docs/{topic}/**/*.md"],readsPatterns:["src/**/*.ts","README.md"],planOutline:"Research implementation \u2192 Write documentation \u2192 Add examples \u2192 Review completeness"}],guidelines:["Split by logical topic, not file count","Each stream should own 1-3 related doc files","Order dependencies: concepts \u2192 API reference \u2192 tutorials \u2192 advanced guides","Streams can run in parallel if topics are independent","Keep related examples with their topic"]},Un={id:"code-feature",name:"Code Feature Implementation",description:"Multi-component feature with types, implementation, tests, and documentation",keywords:["feature","implement","add","create","types","tests","integration"],patterns:["Types \u2192 Implementation \u2192 Tests \u2192 Docs","Multiple source files with dependencies","Test files alongside implementation","Integration with existing code"],streamStructure:[{namePattern:"{feature}-types",purpose:"Define interfaces, types, and schemas",dependsOn:[],ownsPatterns:["src/types/{feature}.ts","src/schemas/{feature}.ts"],readsPatterns:["src/types.ts"],planOutline:"Analyze requirements \u2192 Define types \u2192 Add validation schemas \u2192 Export types"},{namePattern:"{feature}-core",purpose:"Core feature implementation",dependsOn:["{feature}-types"],ownsPatterns:["src/{feature}/*.ts"],readsPatterns:["src/types/{feature}.ts","src/utils/*.ts"],planOutline:"Implement core logic \u2192 Add error handling \u2192 Integrate with existing systems"},{namePattern:"{feature}-tests",purpose:"Unit and integration tests",dependsOn:["{feature}-core"],ownsPatterns:["tests/{feature}.test.ts"],readsPatterns:["src/{feature}/*.ts"],planOutline:"Write unit tests \u2192 Add integration tests \u2192 Test edge cases \u2192 Verify coverage"},{namePattern:"{feature}-docs",purpose:"Documentation and examples",dependsOn:["{feature}-core"],ownsPatterns:["docs/{feature}/*.md"],readsPatterns:["src/{feature}/*.ts"],planOutline:"Document API \u2192 Add usage examples \u2192 Write integration guide"}],guidelines:["Always start with types to establish contracts","Core implementation depends on types being defined","Tests and docs can run in parallel after core is complete","Keep streams focused: one stream = one responsibility","If a file has 200+ lines, consider splitting implementation into multiple streams"]},Hn={id:"migration",name:"Migration",description:"Migrating code, data, or structure with backward compatibility",keywords:["migration","migrate","refactor","rename","move","deprecate","backward compatible"],patterns:["From old to new","Rename/move files or functions","Change data structure","Update multiple call sites","Maintain backward compatibility"],streamStructure:[{namePattern:"{migration}-new-implementation",purpose:"Create new implementation alongside old one",dependsOn:[],ownsPatterns:["src/{new}/*.ts"],readsPatterns:["src/{old}/*.ts"],planOutline:"Implement new version \u2192 Match old API \u2192 Add compatibility layer"},{namePattern:"{migration}-migrate-{component}",purpose:"Migrate specific component to new implementation",dependsOn:["{migration}-new-implementation"],ownsPatterns:["src/{component}/**/*.ts"],readsPatterns:["src/{new}/*.ts","src/{old}/*.ts"],planOutline:"Update imports \u2192 Replace function calls \u2192 Update tests \u2192 Verify behavior"},{namePattern:"{migration}-deprecate-old",purpose:"Mark old implementation as deprecated",dependsOn:["{migration}-migrate-*"],ownsPatterns:["src/{old}/*.ts"],readsPatterns:[],planOutline:"Add deprecation notices \u2192 Update docs \u2192 Plan removal timeline"}],guidelines:["Create new before removing old","Migrate in small, independent chunks (by component/module)","Each migration stream should be independently testable","Keep deprecation as the final step","Ensure each stream leaves the codebase in a working state"]},zn={id:"tutorial",name:"Tutorial Series",description:"Progressive tutorial series from basics to advanced",keywords:["tutorial","guide","example","walkthrough","getting started","beginner","advanced"],patterns:["Multiple tutorial steps","Progressive complexity","Beginner \u2192 Intermediate \u2192 Advanced","Examples with documentation"],streamStructure:[{namePattern:"tutorial-{level}-{topic}",purpose:"Create tutorial for specific level and topic",dependsOn:["tutorial-{previous-level}-*"],ownsPatterns:["docs/tutorials/{level}-{topic}.md","examples/{topic}/**/*"],readsPatterns:["src/**/*.ts","docs/tutorials/{previous}*.md"],planOutline:"Define learning objectives \u2192 Write tutorial \u2192 Create working example \u2192 Add exercises"}],guidelines:["Order by prerequisite knowledge: basics \u2192 intermediate \u2192 advanced","Each tutorial should be self-contained but build on previous concepts","Include working code examples","Beginner tutorials can run in parallel if they cover different topics","Advanced tutorials depend on relevant beginner/intermediate tutorials"]},Bn={id:"api-reference",name:"API Reference",description:"Comprehensive API documentation for modules, classes, and functions",keywords:["api","reference","documentation","modules","classes","functions","methods"],patterns:["Documenting multiple modules","Class/function reference","Method documentation","Parameter and return type docs"],streamStructure:[{namePattern:"api-{module}-reference",purpose:"Create API reference for a specific module",dependsOn:[],ownsPatterns:["docs/api/{module}.md"],readsPatterns:["src/{module}/**/*.ts"],planOutline:"Extract types/interfaces \u2192 Document functions \u2192 Add examples \u2192 Cross-link related APIs"}],guidelines:["Split by module or logical grouping","All API reference streams can run in parallel","Include type signatures and examples","Cross-reference related APIs","Keep each stream to 1-2 related modules"]},qn=[Wn,Un,Hn,zn,Bn];function G(n){let t=n.toLowerCase(),e=null;for(let s of qn){let o=0;for(let r of s.keywords)t.includes(r.toLowerCase())&&(o+=2);for(let r of s.patterns){let i=r.toLowerCase().split(/[\s/,]+/).filter(l=>l.length>2);i.filter(l=>t.includes(l)).length>=i.length/2&&(o+=1)}o>0&&(!e||o>e.score)&&(e={template:s,score:o})}return e&&e.score>=3?e.template:null}function ae(n,t){let e=[];if(n.id==="documentation-set"){let s=t.topics||[];for(let o of s)e.push({name:`docs-${o}`,deps:[],owns:[`docs/${o}/**/*.md`],reads:["src/**/*.ts","README.md"],plan:`Research ${o} implementation \u2192 Write documentation \u2192 Add examples \u2192 Review completeness`})}else if(n.id==="code-feature"){let s=t.featureName;e.push({name:`${s}-types`,deps:[],owns:[`src/types/${s}.ts`],reads:["src/types.ts"],plan:"Analyze requirements \u2192 Define types \u2192 Add validation schemas \u2192 Export types"},{name:`${s}-core`,deps:[`${s}-types`],owns:[`src/${s}/*.ts`],reads:[`src/types/${s}.ts`,"src/utils/*.ts"],plan:"Implement core logic \u2192 Add error handling \u2192 Integrate with existing systems"},{name:`${s}-tests`,deps:[`${s}-core`],owns:[`tests/${s}.test.ts`],reads:[`src/${s}/*.ts`],plan:"Write unit tests \u2192 Add integration tests \u2192 Test edge cases \u2192 Verify coverage"},{name:`${s}-docs`,deps:[`${s}-core`],owns:[`docs/${s}/*.md`],reads:[`src/${s}/*.ts`],plan:"Document API \u2192 Add usage examples \u2192 Write integration guide"})}else if(n.id==="migration"){let s=t.featureName,o=t.components||[];e.push({name:`${s}-new-implementation`,deps:[],owns:[`src/${s}-new/*.ts`],reads:[`src/${s}-old/*.ts`],plan:"Implement new version \u2192 Match old API \u2192 Add compatibility layer"});for(let r of o)e.push({name:`${s}-migrate-${r}`,deps:[`${s}-new-implementation`],owns:[`src/${r}/**/*.ts`],reads:[`src/${s}-new/*.ts`,`src/${s}-old/*.ts`],plan:"Update imports \u2192 Replace function calls \u2192 Update tests \u2192 Verify behavior"});e.push({name:`${s}-deprecate-old`,deps:o.map(r=>`${s}-migrate-${r}`),owns:[`src/${s}-old/*.ts`],reads:[],plan:"Add deprecation notices \u2192 Update docs \u2192 Plan removal timeline"})}else if(n.id==="tutorial"){let s=t.topics||[];for(let o of s)e.push({name:`tutorial-${o}`,deps:[],owns:[`docs/tutorials/${o}.md`,`examples/${o}/**/*`],reads:["src/**/*.ts"],plan:"Define learning objectives \u2192 Write tutorial \u2192 Create working example \u2192 Add exercises"})}else if(n.id==="api-reference"){let s=t.modules||[];for(let o of s)e.push({name:`api-${o}-reference`,deps:[],owns:[`docs/api/${o}.md`],reads:[`src/${o}/**/*.ts`],plan:"Extract types/interfaces \u2192 Document functions \u2192 Add examples \u2192 Cross-link related APIs"})}return e}function Vn(n){let t=n.owns||[],e=n.reads||[];if(t.length>5)return{originalStream:n.name,reason:`Stream owns ${t.length} files, which may be too many for a single stream`,guidance:["Consider grouping related files together","Split by logical component or responsibility","Create dependencies between resulting streams if needed"],suggestedStreams:[]};if(e.length>10)return{originalStream:n.name,reason:`Stream reads ${e.length} files, which may indicate broad scope`,guidance:["Reading many files often means the stream is doing too much","Consider splitting into smaller, focused streams","Each stream should ideally read 3-5 context files"],suggestedStreams:[]};let s=`${n.name} ${n.plan||""}`,o=G(s);return o&&["multiple","all","complete","full","entire"].some(a=>n.name.toLowerCase().includes(a))?{originalStream:n.name,reason:"Stream name suggests broad scope that could be split",template:o,guidance:o.guidelines,suggestedStreams:[]}:null}function Yn(n,t,e){if(e.issues.length===0)return null;let s=e.issues.some(c=>c.severity==="error"),o=e.issues.some(c=>c.severity==="warning"),r=`${t.name??n} ${t.plan??""}`,i=G(r),a=null;if(i){let c=n.replace(/-/g,"_");a=ae(i,{featureName:c})}let l="";s?l=`Stream "${n}" has critical issues:
|
|
135
|
+
`))}return s}function hn(n){switch(n){case"code":return"Implement";case"test":return"Write tests for";case"docs":return"Document";case"tutorial":return"Create tutorial for";case"integration-guide":return"Write integration guide for";case"api-reference":return"Generate API reference for";case"migration":return"Migrate";default:return"Complete"}}function gn(n){let t=[];if(n.ownedFiles.some(s=>s.endsWith(".ts")||s.endsWith(".tsx")||s.endsWith(".js")||s.endsWith(".jsx"))&&t.push("npm run build"),n.category==="test"){let s=n.ownedFiles.find(o=>o.includes(".test."));s?t.push(`npm test -- ${s}`):t.push("npm test")}return t}function wn(n,t,e){let s=[];for(let o of n){t!=="test"&&/vitest|jest/.test(o)&&!/build|tsc/.test(o)&&s.push(`Verify command '${o}' uses a test runner but stream category is '${t}'. Consider using 'npm run build' or 'npx tsc --noEmit' instead.`);let r=o.match(/(?:vitest|jest)\s+(?:run\s+)?(\S+\.(?:ts|tsx|js|jsx))/);if(r){let i=r[1];e.some(l=>i.includes(l)||l.includes(i))||s.push(`Verify command references '${i}' which is not in this stream's owned files.`)}}return s}function yn(n,t,e={}){let{minPlanLength:s=5,estimateTimeout:o=!0,defaultVerify:r}=e,i=n,a=i._verify||r||gn(n),l=i._setup,c=wn(a,n.category,n.ownedFiles);if(c.length>0&&e.diagnostics)for(let p of c)e.diagnostics.warnings.push(`${n.id}: verify_warning - ${p}`);let d=(i._verify!==void 0||i._setup!==void 0)&&n.description.length>=s?n.description:mn(n,s),f={name:n.name,deps:t.length>0?t:void 0,owns:n.ownedFiles.length>0?n.ownedFiles:void 0,reads:n.readFiles.length>0?n.readFiles:void 0,plan:d,verify:a.length>0?a:void 0,setup:l&&l.length>0?l:void 0};if(o){let p=pn[n.category],m=Math.max(1,Math.ceil(n.ownedFiles.length/2));f.timeoutMs=p*m}return f}function xn(n,t,e={}){let{validateAntiPatterns:s=!0}=e,o={},r=[],i=[];t.isAcyclic||r.push(`Dependency graph has cycles: ${t.cycles.map(c=>c.join(" \u2192 ")).join("; ")}`);let a=s?N():null;for(let c of n){let u=t.dependencies.get(c.id)||[],d=yn(c,u,e);if(a){let g=a.analyzeStream(c.id,{name:d.name,deps:d.deps||[],owns:d.owns||[],reads:d.reads||[],plan:d.plan,verify:d.verify||[]});if(g.issues.length>0){i.push(g);for(let y of g.issues)r.push(`${c.id}: ${y.type} - ${y.message}`)}}let f=c.childCount,p=d.plan?.length??0,m=(d.owns||[]).length;if(f!==void 0&&f>=5&&p>2500?r.push(`${c.id}: too_complex - ${f} sub-sections, ${m} owned files, ~${p} char plan. Consider: use YAML stream definitions for manual decomposition, or set deliverable_level: 3`):f!==void 0&&f>=3&&p>3500&&r.push(`${c.id}: too_complex - ${f} sub-sections, ~${p} char plan. Consider: use YAML stream definitions for finer control`),e.projectDir){let g=d.owns||[];for(let y of g)try{let v=$.join(e.projectDir,y),S=C.readFileSync(v,"utf-8").split(`
|
|
136
|
+
`).length;if(S>800){let x=`${c.id}: large_file_critical - ${y} is ${S} lines (>800). Consider splitting this stream to reduce file scope`;r.push(x),e.diagnostics&&e.diagnostics.warnings.push(x)}else if(S>500&&g.length>=3){let x=`${c.id}: large_file_risk - ${y} is ${S} lines, stream owns ${g.length} files. Consider splitting to reduce complexity`;r.push(x),e.diagnostics&&e.diagnostics.warnings.push(x)}}catch{}}if(c.ownedFiles.length===0){let g=`Stream '${c.id}' has no owned files. It can read but not write. If this is unintentional, check your Create:/Modify: syntax (must use backtick-quoted paths).`;r.push(g),e.diagnostics&&e.diagnostics.warnings.push(g)}o[c.id]=d}if(e.projectDir){let c=Cn(o,e.projectDir);r.push(...c.warnings);for(let[u,d]of Object.entries(c.streams))o[u]=d}let l=Object.entries(o).map(([c,u])=>({id:c,owns:u.owns??[],reads:u.reads??[],deps:u.deps??[]}));if(l.length>0){let c=re(l);e.diagnostics&&(e.diagnostics.topologyReport=c.report);for(let u of c.streams)o[u.id]&&(o[u.id]={...o[u.id],deps:u.deps.length>0?u.deps:void 0});c.report.edgesRemoved>0&&r.push(`Topology optimization: removed ${c.report.edgesRemoved} redundant edge(s)`)}return{streams:o,warnings:r,antiPatterns:s?i:void 0,count:n.length}}function Sn(n){let t=["=== Generated Streams ===",""];if(t.push(`Total: ${n.count} streams`),n.warnings.length>0){t.push(""),t.push("--- Warnings ---");for(let e of n.warnings)t.push(`\u26A0\uFE0F ${e}`)}t.push(""),t.push("--- Stream Definitions ---");for(let[e,s]of Object.entries(n.streams))t.push(""),t.push(`${e}:`),t.push(` name: ${s.name}`),s.deps&&s.deps.length>0&&t.push(` deps: [${s.deps.join(", ")}]`),s.owns&&s.owns.length>0&&t.push(` owns: [${s.owns.join(", ")}]`),s.reads&&s.reads.length>0&&t.push(` reads: [${s.reads.join(", ")}]`),s.plan&&t.push(` plan: ${s.plan.slice(0,80)}${s.plan.length>80?"...":""}`),s.verify&&s.verify.length>0&&t.push(` verify: [${s.verify.join(", ")}]`),s.timeoutMs&&t.push(` timeoutMs: ${s.timeoutMs}`);return t.join(`
|
|
137
|
+
`)}function $n(n){return n.streams}var Re=/(?:npm\s+install|pnpm\s+add|yarn\s+add|pip\s+install|bun\s+add)\s+(.+)/gi,_e=/install\s+(?:dependencies|packages)\s*:\s*\n((?:\s+[-*]\s+.+\n?)+)/gi;function Fe(n){let t=n.replace(/^\s*[-*]\s*/,"").trim();return t=t.replace(/\s*\(.*?\)\s*$/,"").trim(),t=t.replace(/[`"']/g,"").trim(),/^@?[a-z0-9][\w./-]*$/i.test(t)?t:null}function vn(n){let t=new Set;for(let e of Object.values(n)){let s=e.plan??"",o;for(Re.lastIndex=0;(o=Re.exec(s))!==null;){let r=o[1].split(/\s+/).filter(i=>i&&!i.startsWith("-"));for(let i of r){let a=Fe(i);a&&t.add(a)}}for(_e.lastIndex=0;(o=_e.exec(s))!==null;){let r=o[1].split(`
|
|
138
|
+
`);for(let i of r){let a=Fe(i);a&&t.add(a)}}}return t.size===0?[]:[`npm install ${[...t].join(" ")}`]}function Cn(n,t){let e=[];if(!t)return{streams:n,warnings:e};let s={},o=new Set;for(let r of Object.values(n))for(let i of r.owns||[])o.add(i);for(let[r,i]of Object.entries(n)){let a=[...i.owns||[]],l=[...i.reads||[]];for(let u of a){let d=$.join(t,u);if(!C.existsSync(d)){let f=$.dirname(d);C.existsSync(f)||e.push(`${r}: path_not_found - owns path "${u}" not found and parent directory does not exist`)}}let c=[];for(let u=0;u<l.length;u++){let d=l[u];if(o.has(d))continue;let f=$.join(t,d);if(!C.existsSync(f)){let p=$.basename(d),m=bn(t,p);m.matches===1&&m.path?(e.push(`${r}: path_corrected - reads path "${d}" corrected to "${m.path}" (only match found)`),l[u]=m.path):m.matches>1?e.push(`${r}: path_ambiguous - reads path "${d}" not found, ${m.matches} candidates exist`):(e.push(`${r}: path_removed - reads path "${d}" not found on disk, removed from reads`),c.push(u))}}for(let u=c.length-1;u>=0;u--)l.splice(c[u],1);s[r]={...i,owns:a,reads:l}}return{streams:s,warnings:e}}function bn(n,t){let e=[],s=["src","tests","lib","scripts"];for(let r of s){let i=$.join(n,r);C.existsSync(i)&&je(i,t,e)}let o=$.join(n,t);return C.existsSync(o)&&C.statSync(o).isFile()&&e.push(t),e.length===1?{matches:1,path:e[0]}:{matches:e.length}}function je(n,t,e,s){let o=s||$.dirname(n);try{let r=C.readdirSync(n,{withFileTypes:!0});for(let i of r){if(i.name==="node_modules"||i.name===".git"||i.name==="dist")continue;let a=$.join(n,i.name);i.isDirectory()?je(a,t,e,o):i.name===t&&e.push($.relative(o,a))}}catch{}}function kn(n,t,e,s,o){let r=new Set;for(let d of Object.values(n))for(let f of d.owns??[])r.add(f);let i=0;if(o)for(let d of Object.values(o))d.estimatedCostUsd&&(i+=d.estimatedCostUsd);let a=t.map(d=>({number:d.number,streams:d.streams.map(f=>{let p=n[f],m=o?.[f];return{id:f,name:p?.name??f,owns:p?.owns??[],reads:p?.reads??[],deps:p?.deps??[],provider:m?.provider,model:m?.model,estimatedCostUsd:m?.estimatedCostUsd,modelFallback:m?.fallback}})})),l=[...e];if(s)for(let d of s)l.push(`Sequential edit conflict: ${d.suggestion}`);if(o)for(let[d,f]of Object.entries(o))f.fallback&&l.push(`${d}: ${f.fallback}`);let c=100;l.length>0&&(c-=l.length*5);let u=Object.values(n).filter(d=>!d.owns||d.owns.length===0).length;return c-=u*10,c=Math.max(0,Math.min(100,c)),{summary:{streamCount:Object.keys(n).length,waveCount:t.length,fileCount:r.size,estimatedCostUsd:i>0?i:void 0},waves:a,warnings:l,qualityScore:c}}function Tn(n){return!n||n===0?"":n<.01?" ~< $0.01":` ~$${n.toFixed(2)}`}function En(n){let t=[],e=n.summary.estimatedCostUsd?`, est. ~$${n.summary.estimatedCostUsd.toFixed(2)}`:"";t.push(`Plan Preview: ${n.summary.streamCount} streams, ${n.summary.waveCount} waves, ${n.summary.fileCount} files${e}`),t.push(`Quality Score: ${n.qualityScore}/100`),t.push("");for(let s of n.waves){t.push(`Wave ${s.number}:`);for(let o of s.streams){let r=o.deps.length>0?` (deps: ${o.deps.join(", ")})`:"",i=o.model?` (${o.model})`:"",a=Tn(o.estimatedCostUsd);t.push(` ${o.id}: ${o.name}${i}${a}${r}`),o.owns.length>0&&t.push(` owns: ${o.owns.join(", ")}`),o.reads.length>0&&t.push(` reads: ${o.reads.join(", ")}`)}t.push("")}if(n.warnings.length>0){t.push("Warnings:");for(let s of n.warnings)t.push(` - ${s}`);t.push("")}return t.join(`
|
|
139
|
+
`)}function Ae(n){let t=new Map;for(let[r,i]of Object.entries(n))for(let a of i.owns??[]){let l=t.get(a)??[];l.push(r),t.set(a,l)}let e=new Map;function s(r,i=new Set){if(e.has(r))return e.get(r);if(i.has(r))return new Set;i.add(r);let a=n[r]?.deps??[],l=new Set(a);for(let c of a)for(let u of s(c,i))l.add(u);return e.set(r,l),l}for(let r of Object.keys(n))s(r);let o=[];for(let[r,i]of t){if(i.length<2)continue;let a=[];for(let l=0;l<i.length;l++){let c=!1;for(let u=0;u<i.length;u++){if(l===u)continue;let d=e.get(i[l])??new Set,f=e.get(i[u])??new Set;if(d.has(i[u])||f.has(i[l])){c=!0;break}}c||a.push(i[l])}a.length>=2&&o.push({file:r,streams:a,suggestion:`${r} is modified by ${a.join(" and ")} in the same wave. Split into separate waves by adding a dependency edge, or merge into one stream.`})}return o}function On(n){let t=Ae(n),e=0,s=[];for(let o of t)for(let r=1;r<o.streams.length;r++){let i=n[o.streams[r]],a=o.streams[r-1],l=i.deps??[];l.includes(a)||(l.push(a),i.deps=l,e++,s.push(`Added dep: ${o.streams[r]} \u2192 ${a} (shared file: ${o.file})`))}return{edgesAdded:e,fixes:s}}function Pn(){return{yamlBlocksFound:0,yamlBlocksParsed:0,yamlParseErrors:[],extractionPath:null,sectionsFound:{},sectionsFilteredAsMeta:[],deliverableCount:0,splitCount:0,unmatchedDeps:[],ownershipConflicts:[],warnings:[]}}function Mn(n){let t=new Map;for(let[s,o]of Object.entries(n))for(let r of o.owns||[]){let i=t.get(r)||[];i.push(s),t.set(r,i)}let e=[];for(let[s,o]of t)o.length>1&&e.push(`${s} owned by: ${o.join(", ")}`);return e}import{randomUUID as zn}from"crypto";var In=[{pattern:/model.*not.found|not_found_error.*model|Model ".*" not found/i,category:"model_not_found",retryable:!1,selfHealable:!1,suggestion:"Model not found. Check the model name in your configuration and ensure it is available for your API key."},{pattern:/invalid api key|api key.*expired|authentication failed|(?<!\d)401(?!\d)|unauthorized/i,category:"auth_error",retryable:!1,selfHealable:!1,suggestion:"Authentication error. Check your API key configuration and ensure it is valid and not expired."},{pattern:/cloud api error: 5\d{2}|502 bad gateway|503 service unavailable|504 gateway timeout|internal server error|overloaded_error/i,category:"server_error",retryable:!0,selfHealable:!1,suggestion:"Cloud server error. Transport retries exhausted \u2014 try again later or switch to local mode."},{pattern:/timed?\s*out|ETIMEDOUT|deadline|timeout/i,category:"timeout",retryable:!1,selfHealable:!1,suggestion:"Timeout is an infrastructure issue. Consider increasing stream timeout or reducing scope."},{pattern:/network error|ECONNREFUSED|ECONNRESET|EHOSTUNREACH|socket hang up/i,category:"network",retryable:!1,selfHealable:!1,suggestion:"Network connectivity issue. Check API endpoint availability and network configuration."},{pattern:/rate limit|too many requests|429|quota exceeded/i,category:"rate_limit",retryable:!1,selfHealable:!1,suggestion:"Rate limited by API. Wait before retrying or reduce parallel stream count."},{pattern:/old_?content.*not found|edit.*mismatch|does not match|oldContent/i,category:"edit_mismatch",retryable:!0,selfHealable:!0,suggestion:"The file content changed since context was built. Re-read the file and retry with updated content."},{pattern:/invalid.*artifact|parse.*error|orchex-artifact.*not found|JSON\.parse/i,category:"invalid_artifact",retryable:!0,selfHealable:!0,suggestion:"The agent produced malformed output. Retry with clearer instructions about the artifact format."},{pattern:/ENOENT|EACCES|EPERM|ENOSPC|no such file|permission denied/i,category:"environment",retryable:!1,selfHealable:!1,suggestion:"File system error. Check file paths and permissions."},{pattern:/ownership violation|outside owned files|SECURITY.*path traversal|SECURITY.*absolute path/i,category:"ownership_violation",retryable:!0,selfHealable:!0,suggestion:"File operation attempted outside owned files. The fix stream should only modify files in the owns list, or the owns list should be updated to include the new file."},{pattern:/test.*fail|expect.*received|assertion.*error|FAIL\s+tests\//i,category:"test_failure",retryable:!0,selfHealable:!0,suggestion:"Tests are failing. Include the test error output in the retry prompt so the agent can fix the issue."},{pattern:/lint|eslint|prettier|formatting/i,category:"lint_error",retryable:!0,selfHealable:!0,suggestion:"Lint or formatting error. Include the lint output in the retry prompt."},{pattern:/TypeError|ReferenceError|SyntaxError|Cannot find module|cannot find name|TS\d{4}/i,category:"runtime_error",retryable:!0,selfHealable:!0,suggestion:"Code has type or runtime errors. Include the error output and relevant type definitions in the retry prompt."}];function ie(n,t){for(let{pattern:s,category:o,retryable:r,selfHealable:i,suggestion:a}of In)if(s.test(n))return{category:o,retryable:r,selfHealable:i,suggestion:a};let e=t==="artifact"||t==="verify";return{category:"unknown",retryable:e,selfHealable:e,suggestion:e?"Unknown code error. Retry with the full error message included in the prompt.":`Unknown infrastructure error (origin: ${t??"unspecified"}). Check API key, model availability, and network connectivity.`}}import{loadManifest as De,saveManifest as Le}from"../manifest.js";import{createLogger as Rn}from"../logging.js";var ae=Rn("fix-stream-manager");async function _n(n){let t=await De(n),e={skipped:[],warnings:[]},s=Object.entries(t.streams).filter(([o,r])=>r.parentStreamId!==void 0);for(let[o,r]of s)r.status==="pending"&&Dn(t,r.parentStreamId)&&(t.streams[o].status="skipped",t.streams[o].error="Parent stream completed; fix no longer needed",e.skipped.push(o));return e.skipped.length>0&&await Le(n,t),e}async function Fn(n,t){let e=await De(n),s={skipped:[],warnings:[]},o=Ln(e,t);for(let a of o){let l=e.streams[a];l.status==="pending"?(e.streams[a].status="skipped",e.streams[a].error=`Ancestor '${t}' completed; fix no longer needed`,s.skipped.push(a)):l.status==="in_progress"&&(e.streams[a].status="skipped",e.streams[a].error=`Sibling fix already resolved this stream (completed: '${t}')`,s.skipped.push(a))}let r=!1,i=e.streams[t];if(i?.parentStreamId){let a=i.parentStreamId;for(;e.streams[a]?.parentStreamId;)a=e.streams[a].parentStreamId;let l=e.streams[a];l&&l.status==="failed"&&(e.streams[a].status="complete",delete e.streams[a].error,r=!0,ae.info({fixStreamId:t,rootStreamId:a},"fix_stream_propagated_completion_to_root"))}return(s.skipped.length>0||r)&&await Le(n,e),s}function Y(n,t){let e=n.streams[t];if(!e||!e.parentStreamId)return null;let s=[t],o=e.parentStreamId,r=new Set;for(;o&&!r.has(o);){r.add(o);let i=n.streams[o];if(!i)break;if(s.unshift(o),!i.parentStreamId)return{rootStreamId:o,fixChain:s.slice(1),rootStatus:i.status??"pending"};o=i.parentStreamId}return null}function jn(n,t){return n.streams[t]?.parentStreamId!==void 0}function An(n,t){return Y(n,t)?.rootStreamId??t}function Dn(n,t){let e=t,s=new Set;for(;e;){if(s.has(e)){ae.warn({streamId:e},"circular_reference_in_fix_chain");break}s.add(e);let o=n.streams[e];if(!o){ae.warn({parentId:e},"fix_stream_orphaned_parent");break}if(o.status==="complete")return!0;e=o.parentStreamId}return!1}function Ln(n,t){let e=[];for(let[s,o]of Object.entries(n.streams))o.parentStreamId&&Nn(n,s,t)&&e.push(s);return e}function Nn(n,t,e){let s=n.streams[t]?.parentStreamId,o=new Set;for(;s&&!o.has(s);){if(o.add(s),s===e)return!0;s=n.streams[s]?.parentStreamId}return!1}var We=3;function Ue(n,t){let e=0,s=t;for(;s;){let o=n.streams[s];if(!o)break;e+=o.attempts??0,s=o.parentStreamId}return e}function Ne(n,t){return Y(n,t)?.rootStreamId??t}function ze(n,t){let e=Ne(n,t);for(let[s,o]of Object.entries(n.streams)){if(s===t||!o.parentStreamId||o.status!=="pending"&&o.status!=="in_progress")continue;if(Ne(n,s)===e)return!0}return!1}function Wn(n,t,e){let s=n.streams[t];if(!s||s.status==="failed"&&s.error?.startsWith("Setup failed:"))return null;let o=s.error??"",r=e??ie(o);if(!r.selfHealable||ze(n,t)||Ue(n,t)>=We)return null;let l=(s.attempts??0)+1,c=`${t}-fix-${l}`,u=t,d=[`## Fix Attempt #${l} for "${s.name}"`,"","### Original Plan",s.plan??"(no plan)","","### Error That Occurred","```",o,"```","",`### Error Category: ${r.category}`,"",`### Suggestion: ${r.suggestion}`,"","### Instructions",`This is a retry of the failed stream "${t}".`,"Fix the issue described above. The original files are in your owns list.","Make sure to address the specific error before implementing the rest of the plan."].join(`
|
|
140
|
+
`),f={name:`${s.name} (Fix #${l})`,deps:s.deps??[],owns:s.owns??[],reads:s.reads??[],plan:d,setup:s.setup??[],verify:s.verify??[],status:"pending",attempts:0,parentStreamId:u};return{fixStreamId:c,fixStream:f,analysis:{category:r.category,suggestion:r.suggestion}}}function ce(n,t){if(t.length<2)return null;let e=new Map;for(let d of t){let f=n.streams[d];f?.error&&e.set(d,f.error)}if(e.size<2)return null;let s=/(?:Cannot find (?:name|module)|Type '(\w+)'|has no (?:exported )?member '(\w+)'|is not assignable|does not exist on type '(\w+)')/.source,o=new Map;for(let[d,f]of e){let p=new RegExp(s,"gi"),m,g=new Set;for(;(m=p.exec(f))!==null;){let y=m[1]||m[2]||m[3]||m[0];g.add(y)}for(let y of g){let v=o.get(y)??[];v.push(d),o.set(y,v)}}let r="",i=0;for(let[d,f]of o)f.length>i&&(r=d,i=f.length);if(i<2)return null;let a=o.get(r),l=new Map;for(let d of a){let f=n.streams[d];for(let p of f?.deps??[])l.set(p,(l.get(p)??0)+1)}let c="",u=0;for(let[d,f]of l)n.streams[d]?.status==="complete"&&f>u&&(c=d,u=f);return c?{rootCauseStreamId:c,reason:`Stream '${c}' completed but ${a.length} downstream streams failed with errors referencing '${r}'`,affectedStreamIds:a,commonErrorPattern:r}:null}function Un(n,t){let e=t.rootCauseStreamId,s=n.streams[e];if(!s||s.status!=="failed"||Ue(n,e)>=We||ze(n,e))return null;let i=(s.attempts??0)+1,a=`${e}-fix-${i}`,l=[];for(let d of t.affectedStreamIds.slice(0,3)){let f=n.streams[d];f?.error&&l.push(`- ${f.name}: ${f.error.slice(0,200)}`)}let c=[`## Root Cause Fix #${i} for "${s.name}"`,"","### Original Plan",s.plan??"(no plan)","","### Problem Identified",`This stream completed but its output caused ${t.affectedStreamIds.length} downstream streams to fail.`,`All downstream errors reference: **${t.commonErrorPattern}**`,"","### Downstream Error Samples",...l,"","### Instructions",`This stream's output is incorrect. The code you produce must define '${t.commonErrorPattern}' correctly`,"so that downstream streams importing from this file can compile successfully.","Re-read the original plan carefully and ensure your output matches the specified types, exports, and signatures exactly.","Pay special attention to type definitions, enum values, and const arrays \u2014 they must match what downstream code expects."].join(`
|
|
141
|
+
`),u={name:`${s.name} (Root Cause Fix #${i})`,deps:s.deps??[],owns:s.owns??[],reads:s.reads??[],plan:c,setup:s.setup??[],verify:s.verify??[],status:"pending",attempts:0,parentStreamId:e};return{fixStreamId:a,fixStream:u,analysis:{category:"runtime_error",suggestion:t.reason}}}function Hn(n,t,e){let s=100,o=n.filter(r=>r.status==="failed").length;return s-=o*20,s-=e*10,s+=t*5,Math.max(0,Math.min(100,s))}function Bn(n,t,e){let s=n.runId??zn(),o=new Date().toISOString(),r=[];for(let h of t)r.push(...h.streams);let i=new Set;for(let h of t)if(h.fixStreamsGenerated)for(let w of h.fixStreamsGenerated)i.add(w);for(let[h,w]of Object.entries(n.streams))w.parentStreamId&&i.add(h);let a=new Map;for(let h of r)a.set(h.id,h);let l=[...a.values()].map(h=>({id:h.id,name:h.name,status:h.status,tokensUsed:h.tokensUsed,executionTimeMs:h.executionTimeMs,selfHealCount:i.has(h.id)?1:0,errorCategory:h.errorDetail?.category,errorMessage:h.error,errorSuggestion:h.errorDetail?.suggestion,provider:h.provider,model:h.model,filesChanged:h.filesChanged})),c=0,u=0,d={};for(let h of r)if(h.tokensUsed){c+=h.tokensUsed.input,u+=h.tokensUsed.output;let w=h.provider??"unknown";d[w]||(d[w]={input:0,output:0}),d[w].input+=h.tokensUsed.input,d[w].output+=h.tokensUsed.output}let f=0,p=0;for(let h of t)h.timing&&(f+=h.timing.parallelMs,p+=h.timing.sequentialMs);let m=new Set;for(let h of r)if(h.filesChanged)for(let w of h.filesChanged)m.add(w);let g=0;for(let h of t)h.streams.length>0&&h.streams.every(w=>w.status==="complete")&&g++;let y={};for(let h of r)if(h.status==="failed"&&h.errorDetail?.category){let w=h.errorDetail.category;y[w]=(y[w]??0)+1}let v,k=r.filter(h=>h.status==="failed").map(h=>h.id);if(k.length>=2){let h=ce(n,k);h&&(v=h)}let S=i.size,x=Hn(r,g,S);return{runId:s,timestamp:o,feature:n.feature,planQualityScore:x,streamResults:l,waveEfficiency:{parallelMs:f,sequentialMs:p,timeSavedMs:Math.max(0,p-f)},autoPlanAccuracy:e?.autoPlanEdits!==void 0?{editsBeforeApproval:e.autoPlanEdits}:void 0,tokenUsage:{totalInput:c,totalOutput:u,byProvider:d},fileChangeImpact:{filesCreated:0,filesModified:m.size,totalFilesChanged:m.size},failurePatterns:y,failureCorrelation:v,totalWaves:t.length,totalStreams:a.size}}async function qn(n,t){let{mkdir:e,writeFile:s}=await import("fs/promises"),{join:o}=await import("path"),r=o(n,".orchex","reports");await e(r,{recursive:!0});let i=o(r,`${t.runId}.json`);return await s(i,JSON.stringify(t,null,2),"utf-8"),i}import{formatDuration as Vn}from"../types.js";function Yn(n,t){let e=[];if(n.waveEfficiency.timeSavedMs>0&&n.totalStreams>1){let r=Vn(n.waveEfficiency.timeSavedMs),i=n.waveEfficiency.sequentialMs>0?Math.round(n.waveEfficiency.timeSavedMs/n.waveEfficiency.sequentialMs*100):0;e.push(`${n.totalStreams} streams ran in parallel across ${n.totalWaves} wave(s), saving ${r} (${i}%).`)}else n.totalStreams>1&&e.push(`${n.totalStreams} streams executed across ${n.totalWaves} wave(s).`);let s=Object.entries(n.failurePatterns);if(s.length>0){s.sort((l,c)=>c[1]-l[1]);let[r,i]=s[0],a=s.reduce((l,[,c])=>l+c,0);r==="type_error"?e.push(`${r} was the most common failure (${i}/${a}). Consider adding a types-only stream first.`):e.push(`${r} was the most common failure (${i}/${a}).`)}if(t&&t.length>0){let r=t.reduce((a,l)=>a+l.planQualityScore,0)/t.length,i=n.planQualityScore-r;i>10?e.push(`Plan quality improved from ${Math.round(r)} to ${n.planQualityScore} \u2014 orchex is learning your patterns.`):i<-10?e.push(`Plan quality dropped from ${Math.round(r)} to ${n.planQualityScore}. Review the failure patterns above.`):e.push(`Plan quality score: ${n.planQualityScore}/100 (consistent with previous runs at ~${Math.round(r)}).`)}else e.push(`Plan quality score: ${n.planQualityScore}/100.`);let o=n.tokenUsage.totalInput+n.tokenUsage.totalOutput;if(o>0&&e.length<3){let r=Object.keys(n.tokenUsage.byProvider);r.length>1&&e.push(`Used ${r.length} providers: ${r.join(", ")} \u2014 total ${o.toLocaleString()} tokens.`)}return e.slice(0,3)}import*as b from"fs/promises";import*as M from"path";var He=".first-run-complete";async function Gn(n){let t=M.join(n,".orchex");try{await b.access(t)}catch{return!0}try{return await b.access(M.join(t,He)),!1}catch{}try{let e=M.join(t,"archive");if((await b.readdir(e)).length>0)return!1}catch{}try{let e=M.join(t,"reports");if((await b.readdir(e)).some(o=>o.endsWith(".json")))return!1}catch{}try{let e=M.join(t,"learn","events.jsonl");if((await b.stat(e)).size>0)return!1}catch{}return!0}async function Kn(n){let t=M.join(n,".orchex");await b.mkdir(t,{recursive:!0}),await b.writeFile(M.join(t,He),new Date().toISOString(),"utf-8")}function Jn(){return["Welcome to orchex! This looks like your first time using orchex in this project.","","Try a quick demo to see orchestration in action:",' orchex run "Add a hello world API endpoint to this project"',"","Or use the MCP auto tool in your AI assistant:",' auto({ prompt: "Add a health check endpoint" })',"","Orchex will generate a plan, show you a preview, and execute in parallel.","Learn more: https://orchex.dev/docs/user-guide/quickstart"].join(`
|
|
142
|
+
`)}import*as W from"fs/promises";import*as E from"path";async function Qn(n,t){if(!t.confirm)throw new Error("Reset learning requires --confirm flag. This permanently deletes learning data.");let e=[],s=E.join(n,".orchex","learn"),o=E.join(n,".orchex","reports");t.patternsOnly?await G(E.join(s,"patterns.json"),e):t.reportsOnly?await Be(o,e,".json"):(await G(E.join(s,"thresholds.json"),e),await G(E.join(s,"events.jsonl"),e),await G(E.join(s,"patterns.json"),e),await Be(o,e,".json"));let r=t.patternsOnly?"patterns":t.reportsOnly?"reports":"all learning data";return{deleted:e,totalDeleted:e.length,message:e.length>0?`Reset ${r}: ${e.length} file(s) deleted.`:`No ${r} found to delete.`}}async function G(n,t){try{await W.unlink(n),t.push(E.basename(n))}catch(e){if(e.code!=="ENOENT")throw e}}async function Be(n,t,e){try{let s=await W.readdir(n);for(let o of s)e&&!o.endsWith(e)||(await W.unlink(E.join(n,o)),t.push(o))}catch(s){if(s.code!=="ENOENT")throw s}}import{createLogger as Xn}from"../logging.js";var Zn=Xn("iteration-evaluator");function es(n){let{streamResults:t,iterationNumber:e,maxIterations:s,intent:o}=n;if(e>=s){let d=t.filter(f=>f.status==="failed"||!f.verifyPassed).length;return{complete:!0,reason:`Reached max iterations (${s})${d>0?` with ${d} unresolved failure(s)`:""}`,failureSummary:d>0?t.filter(f=>f.status==="failed").map(f=>`${f.id}: ${f.error}`).join("; "):void 0}}let r=t.filter(d=>d.status==="failed"),i=t.filter(d=>d.status==="complete"&&!d.verifyPassed);if(r.length===0&&i.length===0)return{complete:!0,reason:`All ${t.length} stream(s) completed and verified successfully`};let l=[];for(let d of r)l.push(`Stream "${d.id}" failed: ${d.error??"unknown error"}`);for(let d of i)l.push(`Stream "${d.id}" verify failed: ${d.verifyError??"verification error"}`);let c=l.join("; "),u=`Fix the following issues from the previous attempt to "${o}": ${c}`;return Zn.info({iteration:e,failed:r.length,verifyFailed:i.length},"iteration_incomplete"),{complete:!1,reason:`${r.length} stream(s) failed, ${i.length} verification(s) failed`,nextIntent:u,failureSummary:c}}var ts={id:"documentation-set",name:"Documentation Set",description:"Multiple documentation files (guides, tutorials, API references) that should be created independently",keywords:["docs","documentation","guide","tutorial","readme","api reference","multiple pages"],patterns:["Multiple .md files in docs/","Creating 3+ documentation files","Tutorial series","API documentation pages"],streamStructure:[{namePattern:"docs-{topic}",purpose:"Create documentation for a specific topic",dependsOn:[],ownsPatterns:["docs/{topic}/**/*.md"],readsPatterns:["src/**/*.ts","README.md"],planOutline:"Research implementation \u2192 Write documentation \u2192 Add examples \u2192 Review completeness"}],guidelines:["Split by logical topic, not file count","Each stream should own 1-3 related doc files","Order dependencies: concepts \u2192 API reference \u2192 tutorials \u2192 advanced guides","Streams can run in parallel if topics are independent","Keep related examples with their topic"]},ns={id:"code-feature",name:"Code Feature Implementation",description:"Multi-component feature with types, implementation, tests, and documentation",keywords:["feature","implement","add","create","types","tests","integration"],patterns:["Types \u2192 Implementation \u2192 Tests \u2192 Docs","Multiple source files with dependencies","Test files alongside implementation","Integration with existing code"],streamStructure:[{namePattern:"{feature}-types",purpose:"Define interfaces, types, and schemas",dependsOn:[],ownsPatterns:["src/types/{feature}.ts","src/schemas/{feature}.ts"],readsPatterns:["src/types.ts"],planOutline:"Analyze requirements \u2192 Define types \u2192 Add validation schemas \u2192 Export types"},{namePattern:"{feature}-core",purpose:"Core feature implementation",dependsOn:["{feature}-types"],ownsPatterns:["src/{feature}/*.ts"],readsPatterns:["src/types/{feature}.ts","src/utils/*.ts"],planOutline:"Implement core logic \u2192 Add error handling \u2192 Integrate with existing systems"},{namePattern:"{feature}-tests",purpose:"Unit and integration tests",dependsOn:["{feature}-core"],ownsPatterns:["tests/{feature}.test.ts"],readsPatterns:["src/{feature}/*.ts"],planOutline:"Write unit tests \u2192 Add integration tests \u2192 Test edge cases \u2192 Verify coverage"},{namePattern:"{feature}-docs",purpose:"Documentation and examples",dependsOn:["{feature}-core"],ownsPatterns:["docs/{feature}/*.md"],readsPatterns:["src/{feature}/*.ts"],planOutline:"Document API \u2192 Add usage examples \u2192 Write integration guide"}],guidelines:["Always start with types to establish contracts","Core implementation depends on types being defined","Tests and docs can run in parallel after core is complete","Keep streams focused: one stream = one responsibility","If a file has 200+ lines, consider splitting implementation into multiple streams"]},ss={id:"migration",name:"Migration",description:"Migrating code, data, or structure with backward compatibility",keywords:["migration","migrate","refactor","rename","move","deprecate","backward compatible"],patterns:["From old to new","Rename/move files or functions","Change data structure","Update multiple call sites","Maintain backward compatibility"],streamStructure:[{namePattern:"{migration}-new-implementation",purpose:"Create new implementation alongside old one",dependsOn:[],ownsPatterns:["src/{new}/*.ts"],readsPatterns:["src/{old}/*.ts"],planOutline:"Implement new version \u2192 Match old API \u2192 Add compatibility layer"},{namePattern:"{migration}-migrate-{component}",purpose:"Migrate specific component to new implementation",dependsOn:["{migration}-new-implementation"],ownsPatterns:["src/{component}/**/*.ts"],readsPatterns:["src/{new}/*.ts","src/{old}/*.ts"],planOutline:"Update imports \u2192 Replace function calls \u2192 Update tests \u2192 Verify behavior"},{namePattern:"{migration}-deprecate-old",purpose:"Mark old implementation as deprecated",dependsOn:["{migration}-migrate-*"],ownsPatterns:["src/{old}/*.ts"],readsPatterns:[],planOutline:"Add deprecation notices \u2192 Update docs \u2192 Plan removal timeline"}],guidelines:["Create new before removing old","Migrate in small, independent chunks (by component/module)","Each migration stream should be independently testable","Keep deprecation as the final step","Ensure each stream leaves the codebase in a working state"]},os={id:"tutorial",name:"Tutorial Series",description:"Progressive tutorial series from basics to advanced",keywords:["tutorial","guide","example","walkthrough","getting started","beginner","advanced"],patterns:["Multiple tutorial steps","Progressive complexity","Beginner \u2192 Intermediate \u2192 Advanced","Examples with documentation"],streamStructure:[{namePattern:"tutorial-{level}-{topic}",purpose:"Create tutorial for specific level and topic",dependsOn:["tutorial-{previous-level}-*"],ownsPatterns:["docs/tutorials/{level}-{topic}.md","examples/{topic}/**/*"],readsPatterns:["src/**/*.ts","docs/tutorials/{previous}*.md"],planOutline:"Define learning objectives \u2192 Write tutorial \u2192 Create working example \u2192 Add exercises"}],guidelines:["Order by prerequisite knowledge: basics \u2192 intermediate \u2192 advanced","Each tutorial should be self-contained but build on previous concepts","Include working code examples","Beginner tutorials can run in parallel if they cover different topics","Advanced tutorials depend on relevant beginner/intermediate tutorials"]},rs={id:"api-reference",name:"API Reference",description:"Comprehensive API documentation for modules, classes, and functions",keywords:["api","reference","documentation","modules","classes","functions","methods"],patterns:["Documenting multiple modules","Class/function reference","Method documentation","Parameter and return type docs"],streamStructure:[{namePattern:"api-{module}-reference",purpose:"Create API reference for a specific module",dependsOn:[],ownsPatterns:["docs/api/{module}.md"],readsPatterns:["src/{module}/**/*.ts"],planOutline:"Extract types/interfaces \u2192 Document functions \u2192 Add examples \u2192 Cross-link related APIs"}],guidelines:["Split by module or logical grouping","All API reference streams can run in parallel","Include type signatures and examples","Cross-reference related APIs","Keep each stream to 1-2 related modules"]},is=[ts,ns,ss,os,rs];function K(n){let t=n.toLowerCase(),e=null;for(let s of is){let o=0;for(let r of s.keywords)t.includes(r.toLowerCase())&&(o+=2);for(let r of s.patterns){let i=r.toLowerCase().split(/[\s/,]+/).filter(l=>l.length>2);i.filter(l=>t.includes(l)).length>=i.length/2&&(o+=1)}o>0&&(!e||o>e.score)&&(e={template:s,score:o})}return e&&e.score>=3?e.template:null}function le(n,t){let e=[];if(n.id==="documentation-set"){let s=t.topics||[];for(let o of s)e.push({name:`docs-${o}`,deps:[],owns:[`docs/${o}/**/*.md`],reads:["src/**/*.ts","README.md"],plan:`Research ${o} implementation \u2192 Write documentation \u2192 Add examples \u2192 Review completeness`})}else if(n.id==="code-feature"){let s=t.featureName;e.push({name:`${s}-types`,deps:[],owns:[`src/types/${s}.ts`],reads:["src/types.ts"],plan:"Analyze requirements \u2192 Define types \u2192 Add validation schemas \u2192 Export types"},{name:`${s}-core`,deps:[`${s}-types`],owns:[`src/${s}/*.ts`],reads:[`src/types/${s}.ts`,"src/utils/*.ts"],plan:"Implement core logic \u2192 Add error handling \u2192 Integrate with existing systems"},{name:`${s}-tests`,deps:[`${s}-core`],owns:[`tests/${s}.test.ts`],reads:[`src/${s}/*.ts`],plan:"Write unit tests \u2192 Add integration tests \u2192 Test edge cases \u2192 Verify coverage"},{name:`${s}-docs`,deps:[`${s}-core`],owns:[`docs/${s}/*.md`],reads:[`src/${s}/*.ts`],plan:"Document API \u2192 Add usage examples \u2192 Write integration guide"})}else if(n.id==="migration"){let s=t.featureName,o=t.components||[];e.push({name:`${s}-new-implementation`,deps:[],owns:[`src/${s}-new/*.ts`],reads:[`src/${s}-old/*.ts`],plan:"Implement new version \u2192 Match old API \u2192 Add compatibility layer"});for(let r of o)e.push({name:`${s}-migrate-${r}`,deps:[`${s}-new-implementation`],owns:[`src/${r}/**/*.ts`],reads:[`src/${s}-new/*.ts`,`src/${s}-old/*.ts`],plan:"Update imports \u2192 Replace function calls \u2192 Update tests \u2192 Verify behavior"});e.push({name:`${s}-deprecate-old`,deps:o.map(r=>`${s}-migrate-${r}`),owns:[`src/${s}-old/*.ts`],reads:[],plan:"Add deprecation notices \u2192 Update docs \u2192 Plan removal timeline"})}else if(n.id==="tutorial"){let s=t.topics||[];for(let o of s)e.push({name:`tutorial-${o}`,deps:[],owns:[`docs/tutorials/${o}.md`,`examples/${o}/**/*`],reads:["src/**/*.ts"],plan:"Define learning objectives \u2192 Write tutorial \u2192 Create working example \u2192 Add exercises"})}else if(n.id==="api-reference"){let s=t.modules||[];for(let o of s)e.push({name:`api-${o}-reference`,deps:[],owns:[`docs/api/${o}.md`],reads:[`src/${o}/**/*.ts`],plan:"Extract types/interfaces \u2192 Document functions \u2192 Add examples \u2192 Cross-link related APIs"})}return e}function as(n){let t=n.owns||[],e=n.reads||[];if(t.length>5)return{originalStream:n.name,reason:`Stream owns ${t.length} files, which may be too many for a single stream`,guidance:["Consider grouping related files together","Split by logical component or responsibility","Create dependencies between resulting streams if needed"],suggestedStreams:[]};if(e.length>10)return{originalStream:n.name,reason:`Stream reads ${e.length} files, which may indicate broad scope`,guidance:["Reading many files often means the stream is doing too much","Consider splitting into smaller, focused streams","Each stream should ideally read 3-5 context files"],suggestedStreams:[]};let s=`${n.name} ${n.plan||""}`,o=K(s);return o&&["multiple","all","complete","full","entire"].some(a=>n.name.toLowerCase().includes(a))?{originalStream:n.name,reason:"Stream name suggests broad scope that could be split",template:o,guidance:o.guidelines,suggestedStreams:[]}:null}function cs(n,t,e){if(e.issues.length===0)return null;let s=e.issues.some(c=>c.severity==="error"),o=e.issues.some(c=>c.severity==="warning"),r=`${t.name??n} ${t.plan??""}`,i=K(r),a=null;if(i){let c=n.replace(/-/g,"_");a=le(i,{featureName:c})}let l="";s?l=`Stream "${n}" has critical issues:
|
|
131
143
|
`:o?l=`Stream "${n}" has potential issues:
|
|
132
144
|
`:l=`Stream "${n}" has suggestions:
|
|
133
145
|
`;for(let c of e.issues){let u=c.severity==="error"?"\u274C":c.severity==="warning"?"\u26A0\uFE0F":"\u2139\uFE0F";l+=` ${u} ${c.message}
|
|
@@ -137,24 +149,23 @@ Reference code:
|
|
|
137
149
|
`;for(let c of a){let u=c.owns?.join(", ")??"TBD";l+=` \u2022 ${c.name}: ${u}
|
|
138
150
|
`}l+=`
|
|
139
151
|
Accept suggested split? [Y/n/edit]`}else l+=`
|
|
140
|
-
No template match. Consider manual split or ignore.`;return{streamId:n,violations:e.issues,qualityScore:e.qualityScore,templateMatch:i,suggestedSplit:a,message:l,action:s?"accept_split":o?"modify":"ignore"}}function
|
|
152
|
+
No template match. Consider manual split or ignore.`;return{streamId:n,violations:e.issues,qualityScore:e.qualityScore,templateMatch:i,suggestedSplit:a,message:l,action:s?"accept_split":o?"modify":"ignore"}}function ls(n,t){let e=t??N(),s=[];for(let[o,r]of Object.entries(n)){let i=e.analyzeStream(o,r),a=cs(o,r,i);a&&s.push(a)}return s.sort((o,r)=>{let i=o.violations.some(u=>u.severity==="error"),a=r.violations.some(u=>u.severity==="error");if(i&&!a)return-1;if(!i&&a)return 1;let l=o.violations.some(u=>u.severity==="warning"),c=r.violations.some(u=>u.severity==="warning");return l&&!c?-1:!l&&c?1:0}),s}function us(n){let t=n.filter(r=>r.violations.some(i=>i.severity==="error")).length,e=n.filter(r=>r.violations.some(i=>i.severity==="warning")&&!r.violations.some(i=>i.severity==="error")).length,s=n.filter(r=>r.templateMatch!==null).length,o="";if(n.length===0)o="\u2705 All streams passed validation. No issues detected.";else if(o=`Stream Validation Summary:
|
|
141
153
|
`,o+=` ${t} stream${t!==1?"s":""} with errors
|
|
142
154
|
`,o+=` ${e} stream${e!==1?"s":""} with warnings
|
|
143
155
|
`,o+=` ${s} template match${s!==1?"es":""} found
|
|
144
156
|
`,t>0){o+=`
|
|
145
157
|
\u274C Critical issues (must fix):
|
|
146
158
|
`;for(let r of n.filter(i=>i.violations.some(a=>a.severity==="error"))){let i=r.violations.filter(a=>a.severity==="error").map(a=>a.type);o+=` \u2022 ${r.streamId}: ${i.join(", ")}
|
|
147
|
-
`}}return{totalStreams:n.length,errorCount:t,warningCount:e,templateMatches:s,summary:o}}function
|
|
159
|
+
`}}return{totalStreams:n.length,errorCount:t,warningCount:e,templateMatches:s,summary:o}}function ds(n){let t=new Map;for(let[c,u]of Object.entries(n))for(let d of u.owns??[]){let f=t.get(d)??[];f.push(c),t.set(d,f)}let e=new Map;function s(c){return e.has(c)||e.set(c,c),e.get(c)!==c&&e.set(c,s(e.get(c))),e.get(c)}function o(c,u){let d=s(c),f=s(u);d!==f&&(d<f?e.set(f,d):e.set(d,f))}for(let[,c]of t)if(!(c.length<2))for(let u=1;u<c.length;u++)o(c[0],c[u]);let r=new Map;for(let c of Object.keys(n)){let u=s(c),d=r.get(u)??[];d.push(c),r.set(u,d)}let i={},a=[],l=new Map;for(let[,c]of r){if(c.length===1){let x=c[0];i[x]=n[x],l.set(x,x);continue}c.sort();let u=c[0],d=[],f=new Set,p=new Set,m=new Set,g=[],y=[];for(let x of c){let h=n[x];d.push(h.name);for(let w of h.owns??[])f.add(w);for(let w of h.reads??[])p.add(w);for(let w of h.deps??[])m.add(w);for(let w of h.verify??[])g.includes(w)||g.push(w);h.plan&&y.push(`## ${h.name}
|
|
148
160
|
|
|
149
|
-
${
|
|
161
|
+
${h.plan}`),l.set(x,u)}for(let x of f)p.delete(x);let v=new Set(c);for(let x of v)m.delete(x);let k,S=[];for(let x of c){let h=n[x];h.timeoutMs&&(!k||h.timeoutMs>k)&&(k=h.timeoutMs);for(let w of h.setup??[])S.includes(w)||S.push(w)}i[u]={name:d.join(" + "),owns:[...f],reads:[...p],deps:[...m],plan:y.join(`
|
|
150
162
|
|
|
151
163
|
---
|
|
152
164
|
|
|
153
|
-
`),verify:h,setup:g.length>0?g:void 0,timeoutMs:T},a.push(`Merged [${c.join(", ")}] \u2192 ${u} (shared files: ${[...f].filter(w=>(t.get(w)??[]).length>1).join(", ")})`)}for(let[c,u]of Object.entries(i)){let d=u.deps??[],f=[...new Set(d.map(p=>l.get(p)??p))].filter(p=>p!==c);u.deps=f}return{streams:i,merges:a}}function Qn(n){return n.isTestGeneration?{provider:void 0,confidence:.3,reason:"Test generation works well with any provider \u2014 use your default."}:n.isStructuralChange&&(n.totalOwnedLines>500||n.fileCount>4)?{provider:"anthropic",confidence:.7,reason:`Structural edits across ${n.fileCount} files (${n.totalOwnedLines} lines) \u2014 Claude handles complex multi-file reasoning best.`}:!n.isStructuralChange&&n.totalOwnedLines<200&&n.fileCount<=2?{provider:"openai",model:"gpt-4.1-mini",confidence:.6,reason:`Simple transform (${n.totalOwnedLines} lines, ${n.fileCount} files) \u2014 GPT-4.1-mini is cost-effective for small tasks.`}:n.isStructuralChange?{provider:"anthropic",confidence:.5,reason:`Structural changes across ${n.fileCount} files \u2014 Claude recommended for refactoring tasks.`}:{provider:void 0,confidence:.2,reason:"No strong provider preference for this task type \u2014 use your configured default."}}function Xn(n,t,e){let s=n.toLowerCase(),o=s.includes("test")||s.includes("spec")||t.some(a=>a.includes(".test.")||a.includes(".spec.")||a.startsWith("tests/")),i=["refactor","restructure","reorganize","migrate","rewrite","split","merge","move","rename","extract","inline","new module","new class","new service","new component"].some(a=>s.includes(a));return{totalOwnedLines:e,isStructuralChange:i,isTestGeneration:o,fileCount:t.length}}import*as j from"fs/promises";import*as ce from"path";import*as K from"yaml";import{exec as Zn}from"child_process";import{promisify as es}from"util";var Le=es(Zn);async function ts(n,t){let e=ce.join(n,".orchex","active","manifest.yaml"),s=await j.readFile(e,"utf-8"),o=K.parse(s),r=new Set(t);for(let[i,a]of Object.entries(o.streams))a.status==="pending"&&(r.has(i)||(o.streams[i].status="skipped"));await j.writeFile(e,K.stringify(o,{indent:2,lineWidth:0}),"utf-8")}async function ns(n,t,e){let s=[],o=[];for(let r of e){let i=ce.join(n,r);try{let{stdout:a}=await Le(`git ls-files "${r}"`,{cwd:n});if(a.trim())await Le(`git checkout HEAD -- "${r}"`,{cwd:n}),s.push(r);else try{await j.unlink(i),s.push(r)}catch(l){l.code!=="ENOENT"&&o.push(`Failed to delete ${r}: ${l.message}`)}}catch(a){if(a.message?.includes("did not match any"))continue;o.push(`Failed to rollback ${r}: ${a.message}`)}}return{streamId:t,reverted:s,errors:o}}import{loadManifest as Ne,saveManifest as We}from"../manifest.js";import{createLogger as ss}from"../logging.js";var le=ss("fix-stream-manager");async function os(n){let t=await Ne(n),e={skipped:[],warnings:[]},s=Object.entries(t.streams).filter(([o,r])=>r.parentStreamId!==void 0);for(let[o,r]of s)r.status==="pending"&&cs(t,r.parentStreamId)&&(t.streams[o].status="skipped",t.streams[o].error="Parent stream completed; fix no longer needed",e.skipped.push(o));return e.skipped.length>0&&await We(n,t),e}async function rs(n,t){let e=await Ne(n),s={skipped:[],warnings:[]},o=ls(e,t);for(let a of o){let l=e.streams[a];l.status==="pending"?(e.streams[a].status="skipped",e.streams[a].error=`Ancestor '${t}' completed; fix no longer needed`,s.skipped.push(a)):l.status==="in_progress"&&(e.streams[a].status="skipped",e.streams[a].error=`Sibling fix already resolved this stream (completed: '${t}')`,s.skipped.push(a))}let r=!1,i=e.streams[t];if(i?.parentStreamId){let a=i.parentStreamId;for(;e.streams[a]?.parentStreamId;)a=e.streams[a].parentStreamId;let l=e.streams[a];l&&l.status==="failed"&&(e.streams[a].status="complete",delete e.streams[a].error,r=!0,le.info({fixStreamId:t,rootStreamId:a},"fix_stream_propagated_completion_to_root"))}return(s.skipped.length>0||r)&&await We(n,e),s}function J(n,t){let e=n.streams[t];if(!e||!e.parentStreamId)return null;let s=[t],o=e.parentStreamId,r=new Set;for(;o&&!r.has(o);){r.add(o);let i=n.streams[o];if(!i)break;if(s.unshift(o),!i.parentStreamId)return{rootStreamId:o,fixChain:s.slice(1),rootStatus:i.status??"pending"};o=i.parentStreamId}return null}function is(n,t){return n.streams[t]?.parentStreamId!==void 0}function as(n,t){return J(n,t)?.rootStreamId??t}function cs(n,t){let e=t,s=new Set;for(;e;){if(s.has(e)){le.warn({streamId:e},"circular_reference_in_fix_chain");break}s.add(e);let o=n.streams[e];if(!o){le.warn({parentId:e},"fix_stream_orphaned_parent");break}if(o.status==="complete")return!0;e=o.parentStreamId}return!1}function ls(n,t){let e=[];for(let[s,o]of Object.entries(n.streams))o.parentStreamId&&us(n,s,t)&&e.push(s);return e}function us(n,t,e){let s=n.streams[t]?.parentStreamId,o=new Set;for(;s&&!o.has(s);){if(o.add(s),s===e)return!0;s=n.streams[s]?.parentStreamId}return!1}var ds=3;function fs(n,t){let e=0,s=t;for(;s;){let o=n.streams[s];if(!o)break;e+=o.attempts??0,s=o.parentStreamId}return e}function Ue(n,t){return J(n,t)?.rootStreamId??t}function ps(n,t){let e=Ue(n,t);for(let[s,o]of Object.entries(n.streams)){if(s===t||!o.parentStreamId||o.status!=="pending"&&o.status!=="in_progress")continue;if(Ue(n,s)===e)return!0}return!1}function ms(n,t,e){let s=n.streams[t];if(!s||s.status==="failed"&&s.error?.startsWith("Setup failed:"))return null;let o=s.error??"",r=e??ie(o);if(!r.selfHealable||ps(n,t)||fs(n,t)>=ds)return null;let l=(s.attempts??0)+1,c=`${t}-fix-${l}`,u=t,d=[`## Fix Attempt #${l} for "${s.name}"`,"","### Original Plan",s.plan??"(no plan)","","### Error That Occurred","```",o,"```","",`### Error Category: ${r.category}`,"",`### Suggestion: ${r.suggestion}`,"","### Instructions",`This is a retry of the failed stream "${t}".`,"Fix the issue described above. The original files are in your owns list.","Make sure to address the specific error before implementing the rest of the plan."].join(`
|
|
154
|
-
`),f={name:`${s.name} (Fix #${l})`,deps:s.deps??[],owns:s.owns??[],reads:s.reads??[],plan:d,setup:s.setup??[],verify:s.verify??[],status:"pending",attempts:0,parentStreamId:u};return{fixStreamId:c,fixStream:f,analysis:{category:r.category,suggestion:r.suggestion}}}import*as qe from"fs";import*as ue from"path";import{createLogger as ws}from"../logging.js";var Q={"claude-opus-4-5-20251101":{input:.015,output:.075},"claude-sonnet-4-5-20250929":{input:.003,output:.015},"claude-sonnet-4-20250514":{input:.003,output:.015},"claude-3-5-sonnet-20241022":{input:.003,output:.015},"claude-3-opus-20240229":{input:.015,output:.075},"claude-3-haiku-20240307":{input:25e-5,output:.00125},"gpt-4.5-turbo":{input:.005,output:.015},"gpt-4-turbo":{input:.01,output:.03},"gpt-4-turbo-preview":{input:.01,output:.03},"gpt-4o":{input:.005,output:.015},"gpt-4o-mini":{input:15e-5,output:6e-4},"o1-preview":{input:.015,output:.06},"o1-mini":{input:.003,output:.012},"o3-mini":{input:.0011,output:.0044},"gpt-3.5-turbo":{input:5e-4,output:.0015},"gemini-2.5-pro":{input:.00125,output:.01},"gemini-2.0-flash":{input:1e-4,output:4e-4},"gemini-1.5-pro":{input:.00125,output:.005},"gemini-1.5-flash":{input:75e-6,output:3e-4},"gemini-pro":{input:125e-6,output:375e-6},"deepseek-chat":{input:28e-5,output:42e-5},"deepseek-coder":{input:28e-5,output:42e-5},"deepseek-reasoner":{input:55e-5,output:.00219},"llama3.3:70b":{input:0,output:0},"llama3.2:latest":{input:0,output:0},"mistral:latest":{input:0,output:0},default:{input:.003,output:.015}},hs=.9;function He(n){if(Q[n])return Q[n];let t=n.toLowerCase();for(let[e,s]of Object.entries(Q))if(e!=="default"&&t.includes(e.split("-").slice(0,2).join("-")))return s;return Q.default}function ze(n,t,e,s){let o=He(e),r=n/1e3*o.input,i=t/1e3*o.output,a=r+i,l;s&&s>0&&(l=s/1e3*o.input*hs);let c=a-(l??0);return{inputTokens:n,outputTokens:t,inputCost:r,outputCost:i,totalCost:a,cacheHitTokens:s,cacheDiscount:l,finalCost:c,model:e}}function gs(n,t,e=.3){let s=Math.ceil(n*e);return ze(n,s,t)}var Uo=ws("smart-router"),Be={anthropic:"claude-sonnet-4-5-20250929",openai:"gpt-4.1",google:"gemini-2.5-pro",deepseek:"deepseek-chat",ollama:"llama3.3:70b"};function ys(n){let t=[...n.owns,...n.reads??[]],e=n.name.toLowerCase(),s=(n.plan??"").toLowerCase();return t.some(o=>o.match(/\.(md|mdx|txt|rst)$/))||e.includes("doc")||e.includes("readme")?"docs":t.some(o=>o.includes(".test.")||o.includes(".spec.")||o.includes("__tests__"))||e.includes("test")?"test":t.some(o=>o.includes("migration"))||e.includes("migrat")?"migration":n.owns.length>=3||(n.estimatedLines??0)>500||s.includes("refactor")||s.includes("restructur")?"complex-code":"simple-code"}function xs(n,t){switch(n){case"docs":return{provider:"deepseek",model:"deepseek-chat",reasoning:`Routed documentation stream "${t.name}" to cheapest provider (DeepSeek)`};case"test":return{provider:"openai",model:"gpt-4o",reasoning:`Routed test stream "${t.name}" to mid-tier provider (GPT-4o)`};case"migration":return{provider:"google",model:"gemini-2.5-pro",reasoning:`Routed migration stream "${t.name}" to cost-effective provider (Gemini)`};case"complex-code":return{provider:"anthropic",model:"claude-sonnet-4-5-20250929",reasoning:`Routed complex code stream "${t.name}" (${t.owns.length} files${(t.estimatedLines??0)>500?", large file edits":""}) to premium provider (Claude)`};default:return{provider:"openai",model:"gpt-4o",reasoning:`Routed simple code stream "${t.name}" to balanced provider (GPT-4o)`}}}function Ss(n){switch(n){case"docs":return["gemini","openai","anthropic"];case"test":return["anthropic","gemini","deepseek"];case"migration":return["openai","anthropic","deepseek"];case"complex-code":return["openai","gemini","deepseek"];default:return["anthropic","gemini","deepseek"]}}function vs(n,t,e){let s=e?.availableProviders,o=e?.registryModels,r=(l,c)=>o?.[l]?.length?o[l].includes(c)?c:o[l][0]:c;if(t.overrides?.[n.id]){let l=t.overrides[n.id];return{provider:l.provider,model:l.model,reasoning:"User override"}}if(t.defaultProvider){let l=t.defaultModel??Be[t.defaultProvider]??t.defaultProvider,c=r(t.defaultProvider,l);return{provider:t.defaultProvider,model:c,reasoning:"User default provider preference"}}let i=ys(n),a=xs(i,n);if(s&&!s.has(a.provider)){let l=Ss(i);for(let c of l)if(s.has(c)){let u=r(c,Be[c]??c);return{provider:c,model:u,reasoning:`${a.reasoning} \u2014 ${a.provider} not available, fell back to ${c}`}}}return a.model=r(a.provider,a.model),a}function $s(n){let t=n??ue.join(process.env.HOME??"",".orchex"),e=ue.join(t,"config.json");try{let s=qe.readFileSync(e,"utf-8"),o=JSON.parse(s);return{defaultProvider:o.routing?.defaultProvider,defaultModel:o.routing?.defaultModel,overrides:o.routing?.overrides}}catch{return{}}}import*as A from"fs/promises";import*as X from"path";var E;(function(n){n.STREAM_COUNT_SWEET_SPOT="stream-count-sweet-spot",n.DEPENDENCY_ORDERING="dependency-ordering",n.FILE_PER_STREAM="file-per-stream",n.WAVE_EFFICIENCY="wave-efficiency",n.PROVIDER_PERFORMANCE="provider-performance",n.SELF_HEAL_PATTERN="self-heal-pattern",n.TIME_OF_DAY="time-of-day"})(E||(E={}));function Cs(n){let t=n.streamResults.filter(r=>r.status==="complete").length,e=n.streamResults.filter(r=>r.status==="failed").length,s=n.streamResults.filter(r=>r.status==="skipped").length,o=n.streamResults.reduce((r,i)=>r+(i.executionTimeMs??0),0);return{id:n.runId,feature:n.feature,timestamp:n.timestamp,success:n.planQualityScore>=80,totalStreams:n.totalStreams,completedStreams:t,failedStreams:e,skippedStreams:s,totalWaves:n.totalWaves,executionTimeMs:o,streams:n.streamResults.map(r=>({id:r.id,name:r.name,status:r.status,wave:0,filesOwned:0,executionTimeMs:r.executionTimeMs??0,tokensUsed:r.tokensUsed??{input:0,output:0},errorCategory:r.errorCategory}))}}var bs=5;function ks(n){if(n.length<bs)return[];let t=[],e=[Ts,Es,Os,Ps,Ms,_s,Is];for(let s of e){let o=s(n);o&&t.push(o)}return t}function Ts(n){let t={low:{total:0,success:0,ids:[]},mid:{total:0,success:0,ids:[]},high:{total:0,success:0,ids:[]}};for(let u of n){let d=u.totalStreams<=5?"low":u.totalStreams<=8?"mid":"high";t[d].total++,u.success&&t[d].success++,t[d].ids.push(u.id)}if(t.low.total<3&&t.mid.total<3||t.high.total<2&&t.mid.total<2)return null;let e=t.low.total>0?t.low.success/t.low.total:0,s=t.high.total>0?t.high.success/t.high.total:0,o=t.mid.total>0?t.mid.success/t.mid.total:0,r=Math.max(e,o),i=Math.min(e,o,s);if(r-i<.2)return null;let a=e>=o?"low (1-5 streams)":"mid (6-8 streams)",l=Math.max(e,o),c=[...t.low.ids,...t.mid.ids,...t.high.ids];return{type:E.STREAM_COUNT_SWEET_SPOT,description:`Plans with ${a} succeed ${(l*100).toFixed(0)}% of the time`,confidence:Math.min(n.length/20,1),recommendation:`Prefer ${a.includes("low")?"3-5":"6-8"} streams per plan. Larger plans (${t.high.total>0?`>8 streams: ${(s*100).toFixed(0)}% success`:"not enough data"}) tend to fail more.`,evidence:{reportIds:c,metric:"streamCount",values:{"low_1-5_rate":`${(e*100).toFixed(0)}%`,"mid_6-8_rate":`${(o*100).toFixed(0)}%`,"high_9+_rate":`${(s*100).toFixed(0)}%`,low_count:t.low.total,high_count:t.high.total}}}}function Es(n){let t=0,e=0,s=0,o=0,r=[];for(let l of n){for(let c of l.streams)c.filesOwned<=4?(e++,c.status==="complete"&&t++):(o++,c.status==="complete"&&s++);r.push(l.id)}if(e<5||o<3)return null;let i=t/e,a=s/o;return i-a<.15?null:{type:E.FILE_PER_STREAM,description:`Streams with <=4 files succeed ${(i*100).toFixed(0)}%, streams with >4 files succeed ${(a*100).toFixed(0)}%`,confidence:Math.min((e+o)/30,1),recommendation:"Keep streams to 4 or fewer owned files. Split larger streams into focused units.",evidence:{reportIds:r,metric:"filesPerStream",values:{low_files_success_rate:`${(i*100).toFixed(0)}%`,high_files_success_rate:`${(a*100).toFixed(0)}%`,low_files_count:e,high_files_count:o}}}}function Os(n){let t={},e=0,s=[];for(let l of n){for(let c of l.streams)c.status==="failed"&&c.errorCategory&&(t[c.errorCategory]=(t[c.errorCategory]||0)+1,e++);l.failedStreams>0&&s.push(l.id)}if(e<3)return null;let o=Object.entries(t).sort((l,c)=>c[1]-l[1]),[r,i]=o[0],a=i/e*100;return{type:E.SELF_HEAL_PATTERN,description:`${r} errors are the most common failure (${a.toFixed(0)}% of all errors)`,confidence:Math.min(e/15,1),recommendation:`Focus on preventing ${r} errors. Consider adding targeted verify commands or adjusting prompts to avoid this error type.`,evidence:{reportIds:s,metric:"errorCategories",values:Object.fromEntries(o.map(([l,c])=>[l,`${c} (${(c/e*100).toFixed(0)}%)`]))}}}function Ps(n){let t=0,e=0,s=0,o=0,r=[];for(let l of n){let c=new Set(l.streams.filter(u=>!u.name.toLowerCase().includes("test")).map(u=>u.id));for(let u of l.streams){if(!u.name.toLowerCase().includes("test"))continue;u.deps&&u.deps.some(p=>c.has(p))?(t++,u.status==="complete"&&e++):(s++,u.status==="complete"&&o++)}r.push(l.id)}if(t<3||s<3)return null;let i=e/t,a=o/s;return i-a<.15?null:{type:E.DEPENDENCY_ORDERING,description:`Test streams with impl dependencies succeed ${(i*100).toFixed(0)}%, without: ${(a*100).toFixed(0)}%`,confidence:Math.min((t+s)/15,1),recommendation:"Always add implementation streams as dependencies of test streams. Place tests in later waves.",evidence:{reportIds:r,metric:"dependencyOrdering",values:{with_deps_rate:`${(i*100).toFixed(0)}%`,without_deps_rate:`${(a*100).toFixed(0)}%`,with_deps_count:t,without_deps_count:s}}}}function Ms(n){let t={low:{total:0,success:0},high:{total:0,success:0}},e=[];for(let l of n){let c=l.totalWaves<=3?"low":"high";t[c].total++,l.success&&t[c].success++,e.push(l.id)}if(t.low.total<3||t.high.total<3)return null;let s=t.low.success/t.low.total,o=t.high.success/t.high.total;if(Math.abs(s-o)<.15)return null;let r=s>=o?"low":"high",i=r==="low"?s:o,a=r==="low"?"1-3":"4+";return{type:E.WAVE_EFFICIENCY,description:`Orchestrations with ${a} waves succeed ${(i*100).toFixed(0)}%`,confidence:Math.min(n.length/15,1),recommendation:`Prefer ${a} waves for best results. ${r==="low"?"Keep dependency depth shallow.":"More waves indicates better dependency structure."}`,evidence:{reportIds:e,metric:"waveCount",values:{"low_1-3_rate":`${(s*100).toFixed(0)}%`,"high_4+_rate":`${(o*100).toFixed(0)}%`,low_count:t.low.total,high_count:t.high.total}}}}function _s(n){let t={},e=[];for(let l of n){for(let c of l.streams){let u=c.provider??l.provider??"unknown";u!=="unknown"&&(t[u]||(t[u]={total:0,success:0}),t[u].total++,c.status==="complete"&&t[u].success++)}e.push(l.id)}let s=Object.entries(t).filter(([l,c])=>c.total>=3);if(s.length<2)return null;let o=s.map(([l,c])=>({name:l,rate:c.success/c.total,total:c.total})),r=o.sort((l,c)=>c.rate-l.rate),i=r[0],a=r[r.length-1];return i.rate-a.rate<.1?null:{type:E.PROVIDER_PERFORMANCE,description:`${i.name} succeeds ${(i.rate*100).toFixed(0)}%, ${a.name}: ${(a.rate*100).toFixed(0)}%`,confidence:Math.min(s.reduce((l,[c,u])=>l+u.total,0)/30,1),recommendation:`${i.name} performs best in your project. Consider using it as the default provider.`,evidence:{reportIds:e,metric:"providerPerformance",values:Object.fromEntries(o.map(l=>[l.name,`${(l.rate*100).toFixed(0)}% (n=${l.total})`]))}}}function Is(n){let t={morning:{total:0,success:0},afternoon:{total:0,success:0},evening:{total:0,success:0},night:{total:0,success:0}},e=[];for(let l of n){let c=new Date(l.timestamp).getHours(),u=c<6?"night":c<12?"morning":c<18?"afternoon":"evening";t[u].total++,l.success&&t[u].success++,e.push(l.id)}let s=Object.entries(t).filter(([l,c])=>c.total>=3);if(s.length<2)return null;let o=s.map(([l,c])=>({name:l,rate:c.success/c.total,total:c.total})),r=o.sort((l,c)=>c.rate-l.rate),i=r[0],a=r[r.length-1];return i.rate-a.rate<.2?null:{type:E.TIME_OF_DAY,description:`${i.name} runs succeed ${(i.rate*100).toFixed(0)}%, ${a.name}: ${(a.rate*100).toFixed(0)}%`,confidence:Math.min(n.length/20,1),recommendation:`Orchestrations during ${i.name} hours have the highest success rate. This may correlate with API rate limit availability.`,evidence:{reportIds:e,metric:"timeOfDay",values:Object.fromEntries(o.map(l=>[l.name,`${(l.rate*100).toFixed(0)}% (n=${l.total})`]))}}}function Rs(n){if(n.length===0)return"No significant patterns detected yet. Need more execution history.";let t=["=== Detected Patterns ===",""];for(let e of n){let s=e.confidence>=.7?"HIGH":e.confidence>=.4?"MEDIUM":"LOW";t.push(`[${s}] ${e.description}`),t.push(` Recommendation: ${e.recommendation}`),t.push("")}return t.join(`
|
|
155
|
-
`)}function Fs(n){if(n.length===0)return"";let t=n.filter(e=>e.confidence>=.4).map(e=>`- ${e.recommendation}`).join(`
|
|
165
|
+
`),verify:g,setup:S.length>0?S:void 0,timeoutMs:k},a.push(`Merged [${c.join(", ")}] \u2192 ${u} (shared files: ${[...f].filter(x=>(t.get(x)??[]).length>1).join(", ")})`)}for(let[c,u]of Object.entries(i)){let d=u.deps??[],f=[...new Set(d.map(p=>l.get(p)??p))].filter(p=>p!==c);u.deps=f}return{streams:i,merges:a}}function fs(n){return n.isTestGeneration?{provider:void 0,confidence:.3,reason:"Test generation works well with any provider \u2014 use your default."}:n.isStructuralChange&&(n.totalOwnedLines>500||n.fileCount>4)?{provider:"anthropic",confidence:.7,reason:`Structural edits across ${n.fileCount} files (${n.totalOwnedLines} lines) \u2014 Claude handles complex multi-file reasoning best.`}:!n.isStructuralChange&&n.totalOwnedLines<200&&n.fileCount<=2?{provider:"openai",model:"gpt-4.1-mini",confidence:.6,reason:`Simple transform (${n.totalOwnedLines} lines, ${n.fileCount} files) \u2014 GPT-4.1-mini is cost-effective for small tasks.`}:n.isStructuralChange?{provider:"anthropic",confidence:.5,reason:`Structural changes across ${n.fileCount} files \u2014 Claude recommended for refactoring tasks.`}:{provider:void 0,confidence:.2,reason:"No strong provider preference for this task type \u2014 use your configured default."}}function ps(n,t,e){let s=n.toLowerCase(),o=s.includes("test")||s.includes("spec")||t.some(a=>a.includes(".test.")||a.includes(".spec.")||a.startsWith("tests/")),i=["refactor","restructure","reorganize","migrate","rewrite","split","merge","move","rename","extract","inline","new module","new class","new service","new component"].some(a=>s.includes(a));return{totalOwnedLines:e,isStructuralChange:i,isTestGeneration:o,fileCount:t.length}}import*as j from"fs/promises";import*as ue from"path";import*as J from"yaml";import{exec as ms}from"child_process";import{promisify as hs}from"util";var qe=hs(ms);async function gs(n,t){let e=ue.join(n,".orchex","active","manifest.yaml"),s=await j.readFile(e,"utf-8"),o=J.parse(s),r=new Set(t);for(let[i,a]of Object.entries(o.streams))a.status==="pending"&&(r.has(i)||(o.streams[i].status="skipped"));await j.writeFile(e,J.stringify(o,{indent:2,lineWidth:0}),"utf-8")}async function ws(n,t,e){let s=[],o=[];for(let r of e){let i=ue.join(n,r);try{let{stdout:a}=await qe(`git ls-files "${r}"`,{cwd:n});if(a.trim())await qe(`git checkout HEAD -- "${r}"`,{cwd:n}),s.push(r);else try{await j.unlink(i),s.push(r)}catch(l){l.code!=="ENOENT"&&o.push(`Failed to delete ${r}: ${l.message}`)}}catch(a){if(a.message?.includes("did not match any"))continue;o.push(`Failed to rollback ${r}: ${a.message}`)}}return{streamId:t,reverted:s,errors:o}}import*as Ke from"fs";import*as de from"path";import{createLogger as Ss}from"../logging.js";var Q={"claude-opus-4-5-20251101":{input:.015,output:.075},"claude-sonnet-4-5-20250929":{input:.003,output:.015},"claude-sonnet-4-20250514":{input:.003,output:.015},"claude-3-5-sonnet-20241022":{input:.003,output:.015},"claude-3-opus-20240229":{input:.015,output:.075},"claude-3-haiku-20240307":{input:25e-5,output:.00125},"gpt-4.5-turbo":{input:.005,output:.015},"gpt-4-turbo":{input:.01,output:.03},"gpt-4-turbo-preview":{input:.01,output:.03},"gpt-4o":{input:.005,output:.015},"gpt-4o-mini":{input:15e-5,output:6e-4},"o1-preview":{input:.015,output:.06},"o1-mini":{input:.003,output:.012},"o3-mini":{input:.0011,output:.0044},"gpt-3.5-turbo":{input:5e-4,output:.0015},"gemini-2.5-pro":{input:.00125,output:.01},"gemini-2.0-flash":{input:1e-4,output:4e-4},"gemini-1.5-pro":{input:.00125,output:.005},"gemini-1.5-flash":{input:75e-6,output:3e-4},"gemini-pro":{input:125e-6,output:375e-6},"deepseek-chat":{input:28e-5,output:42e-5},"deepseek-coder":{input:28e-5,output:42e-5},"deepseek-reasoner":{input:55e-5,output:.00219},"llama3.3:70b":{input:0,output:0},"llama3.2:latest":{input:0,output:0},"mistral:latest":{input:0,output:0},default:{input:.003,output:.015}},ys=.9;function Ve(n){if(Q[n])return Q[n];let t=n.toLowerCase();for(let[e,s]of Object.entries(Q))if(e!=="default"&&t.includes(e.split("-").slice(0,2).join("-")))return s;return Q.default}function Ye(n,t,e,s){let o=Ve(e),r=n/1e3*o.input,i=t/1e3*o.output,a=r+i,l;s&&s>0&&(l=s/1e3*o.input*ys);let c=a-(l??0);return{inputTokens:n,outputTokens:t,inputCost:r,outputCost:i,totalCost:a,cacheHitTokens:s,cacheDiscount:l,finalCost:c,model:e}}function xs(n,t,e=.3){let s=Math.ceil(n*e);return Ye(n,s,t)}var qo=Ss("smart-router"),Ge={anthropic:"claude-sonnet-4-5-20250929",openai:"gpt-4.1",google:"gemini-2.5-pro",deepseek:"deepseek-chat",ollama:"llama3.3:70b"};function $s(n){let t=[...n.owns,...n.reads??[]],e=n.name.toLowerCase(),s=(n.plan??"").toLowerCase();return t.some(o=>o.match(/\.(md|mdx|txt|rst)$/))||e.includes("doc")||e.includes("readme")?"docs":t.some(o=>o.includes(".test.")||o.includes(".spec.")||o.includes("__tests__"))||e.includes("test")?"test":t.some(o=>o.includes("migration"))||e.includes("migrat")?"migration":n.owns.length>=3||(n.estimatedLines??0)>500||s.includes("refactor")||s.includes("restructur")?"complex-code":"simple-code"}function vs(n,t){switch(n){case"docs":return{provider:"deepseek",model:"deepseek-chat",reasoning:`Routed documentation stream "${t.name}" to cheapest provider (DeepSeek)`};case"test":return{provider:"openai",model:"gpt-4o",reasoning:`Routed test stream "${t.name}" to mid-tier provider (GPT-4o)`};case"migration":return{provider:"google",model:"gemini-2.5-pro",reasoning:`Routed migration stream "${t.name}" to cost-effective provider (Gemini)`};case"complex-code":return{provider:"anthropic",model:"claude-sonnet-4-5-20250929",reasoning:`Routed complex code stream "${t.name}" (${t.owns.length} files${(t.estimatedLines??0)>500?", large file edits":""}) to premium provider (Claude)`};default:return{provider:"openai",model:"gpt-4o",reasoning:`Routed simple code stream "${t.name}" to balanced provider (GPT-4o)`}}}function Cs(n){switch(n){case"docs":return["gemini","openai","anthropic"];case"test":return["anthropic","gemini","deepseek"];case"migration":return["openai","anthropic","deepseek"];case"complex-code":return["openai","gemini","deepseek"];default:return["anthropic","gemini","deepseek"]}}function bs(n,t,e){let s=e?.availableProviders,o=e?.registryModels,r=(l,c)=>o?.[l]?.length?o[l].includes(c)?c:o[l][0]:c;if(t.overrides?.[n.id]){let l=t.overrides[n.id];return{provider:l.provider,model:l.model,reasoning:"User override"}}if(t.defaultProvider){let l=t.defaultModel??Ge[t.defaultProvider]??t.defaultProvider,c=r(t.defaultProvider,l);return{provider:t.defaultProvider,model:c,reasoning:"User default provider preference"}}let i=$s(n),a=vs(i,n);if(s&&!s.has(a.provider)){let l=Cs(i);for(let c of l)if(s.has(c)){let u=r(c,Ge[c]??c);return{provider:c,model:u,reasoning:`${a.reasoning} \u2014 ${a.provider} not available, fell back to ${c}`}}}return a.model=r(a.provider,a.model),a}function ks(n){let t=n??de.join(process.env.HOME??"",".orchex"),e=de.join(t,"config.json");try{let s=Ke.readFileSync(e,"utf-8"),o=JSON.parse(s);return{defaultProvider:o.routing?.defaultProvider,defaultModel:o.routing?.defaultModel,overrides:o.routing?.overrides}}catch{return{}}}import*as A from"fs/promises";import*as X from"path";var O;(function(n){n.STREAM_COUNT_SWEET_SPOT="stream-count-sweet-spot",n.DEPENDENCY_ORDERING="dependency-ordering",n.FILE_PER_STREAM="file-per-stream",n.WAVE_EFFICIENCY="wave-efficiency",n.PROVIDER_PERFORMANCE="provider-performance",n.SELF_HEAL_PATTERN="self-heal-pattern",n.TIME_OF_DAY="time-of-day"})(O||(O={}));function Ts(n){let t=n.streamResults.filter(r=>r.status==="complete").length,e=n.streamResults.filter(r=>r.status==="failed").length,s=n.streamResults.filter(r=>r.status==="skipped").length,o=n.streamResults.reduce((r,i)=>r+(i.executionTimeMs??0),0);return{id:n.runId,feature:n.feature,timestamp:n.timestamp,success:n.planQualityScore>=80,totalStreams:n.totalStreams,completedStreams:t,failedStreams:e,skippedStreams:s,totalWaves:n.totalWaves,executionTimeMs:o,streams:n.streamResults.map(r=>({id:r.id,name:r.name,status:r.status,wave:0,filesOwned:0,executionTimeMs:r.executionTimeMs??0,tokensUsed:r.tokensUsed??{input:0,output:0},errorCategory:r.errorCategory}))}}var Es=5;function Os(n){if(n.length<Es)return[];let t=[],e=[Ps,Ms,Is,Rs,_s,Fs,js];for(let s of e){let o=s(n);o&&t.push(o)}return t}function Ps(n){let t={low:{total:0,success:0,ids:[]},mid:{total:0,success:0,ids:[]},high:{total:0,success:0,ids:[]}};for(let u of n){let d=u.totalStreams<=5?"low":u.totalStreams<=8?"mid":"high";t[d].total++,u.success&&t[d].success++,t[d].ids.push(u.id)}if(t.low.total<3&&t.mid.total<3||t.high.total<2&&t.mid.total<2)return null;let e=t.low.total>0?t.low.success/t.low.total:0,s=t.high.total>0?t.high.success/t.high.total:0,o=t.mid.total>0?t.mid.success/t.mid.total:0,r=Math.max(e,o),i=Math.min(e,o,s);if(r-i<.2)return null;let a=e>=o?"low (1-5 streams)":"mid (6-8 streams)",l=Math.max(e,o),c=[...t.low.ids,...t.mid.ids,...t.high.ids];return{type:O.STREAM_COUNT_SWEET_SPOT,description:`Plans with ${a} succeed ${(l*100).toFixed(0)}% of the time`,confidence:Math.min(n.length/20,1),recommendation:`Prefer ${a.includes("low")?"3-5":"6-8"} streams per plan. Larger plans (${t.high.total>0?`>8 streams: ${(s*100).toFixed(0)}% success`:"not enough data"}) tend to fail more.`,evidence:{reportIds:c,metric:"streamCount",values:{"low_1-5_rate":`${(e*100).toFixed(0)}%`,"mid_6-8_rate":`${(o*100).toFixed(0)}%`,"high_9+_rate":`${(s*100).toFixed(0)}%`,low_count:t.low.total,high_count:t.high.total}}}}function Ms(n){let t=0,e=0,s=0,o=0,r=[];for(let l of n){for(let c of l.streams)c.filesOwned<=4?(e++,c.status==="complete"&&t++):(o++,c.status==="complete"&&s++);r.push(l.id)}if(e<5||o<3)return null;let i=t/e,a=s/o;return i-a<.15?null:{type:O.FILE_PER_STREAM,description:`Streams with <=4 files succeed ${(i*100).toFixed(0)}%, streams with >4 files succeed ${(a*100).toFixed(0)}%`,confidence:Math.min((e+o)/30,1),recommendation:"Keep streams to 4 or fewer owned files. Split larger streams into focused units.",evidence:{reportIds:r,metric:"filesPerStream",values:{low_files_success_rate:`${(i*100).toFixed(0)}%`,high_files_success_rate:`${(a*100).toFixed(0)}%`,low_files_count:e,high_files_count:o}}}}function Is(n){let t={},e=0,s=[];for(let l of n){for(let c of l.streams)c.status==="failed"&&c.errorCategory&&(t[c.errorCategory]=(t[c.errorCategory]||0)+1,e++);l.failedStreams>0&&s.push(l.id)}if(e<3)return null;let o=Object.entries(t).sort((l,c)=>c[1]-l[1]),[r,i]=o[0],a=i/e*100;return{type:O.SELF_HEAL_PATTERN,description:`${r} errors are the most common failure (${a.toFixed(0)}% of all errors)`,confidence:Math.min(e/15,1),recommendation:`Focus on preventing ${r} errors. Consider adding targeted verify commands or adjusting prompts to avoid this error type.`,evidence:{reportIds:s,metric:"errorCategories",values:Object.fromEntries(o.map(([l,c])=>[l,`${c} (${(c/e*100).toFixed(0)}%)`]))}}}function Rs(n){let t=0,e=0,s=0,o=0,r=[];for(let l of n){let c=new Set(l.streams.filter(u=>!u.name.toLowerCase().includes("test")).map(u=>u.id));for(let u of l.streams){if(!u.name.toLowerCase().includes("test"))continue;u.deps&&u.deps.some(p=>c.has(p))?(t++,u.status==="complete"&&e++):(s++,u.status==="complete"&&o++)}r.push(l.id)}if(t<3||s<3)return null;let i=e/t,a=o/s;return i-a<.15?null:{type:O.DEPENDENCY_ORDERING,description:`Test streams with impl dependencies succeed ${(i*100).toFixed(0)}%, without: ${(a*100).toFixed(0)}%`,confidence:Math.min((t+s)/15,1),recommendation:"Always add implementation streams as dependencies of test streams. Place tests in later waves.",evidence:{reportIds:r,metric:"dependencyOrdering",values:{with_deps_rate:`${(i*100).toFixed(0)}%`,without_deps_rate:`${(a*100).toFixed(0)}%`,with_deps_count:t,without_deps_count:s}}}}function _s(n){let t={low:{total:0,success:0},high:{total:0,success:0}},e=[];for(let l of n){let c=l.totalWaves<=3?"low":"high";t[c].total++,l.success&&t[c].success++,e.push(l.id)}if(t.low.total<3||t.high.total<3)return null;let s=t.low.success/t.low.total,o=t.high.success/t.high.total;if(Math.abs(s-o)<.15)return null;let r=s>=o?"low":"high",i=r==="low"?s:o,a=r==="low"?"1-3":"4+";return{type:O.WAVE_EFFICIENCY,description:`Orchestrations with ${a} waves succeed ${(i*100).toFixed(0)}%`,confidence:Math.min(n.length/15,1),recommendation:`Prefer ${a} waves for best results. ${r==="low"?"Keep dependency depth shallow.":"More waves indicates better dependency structure."}`,evidence:{reportIds:e,metric:"waveCount",values:{"low_1-3_rate":`${(s*100).toFixed(0)}%`,"high_4+_rate":`${(o*100).toFixed(0)}%`,low_count:t.low.total,high_count:t.high.total}}}}function Fs(n){let t={},e=[];for(let l of n){for(let c of l.streams){let u=c.provider??l.provider??"unknown";u!=="unknown"&&(t[u]||(t[u]={total:0,success:0}),t[u].total++,c.status==="complete"&&t[u].success++)}e.push(l.id)}let s=Object.entries(t).filter(([l,c])=>c.total>=3);if(s.length<2)return null;let o=s.map(([l,c])=>({name:l,rate:c.success/c.total,total:c.total})),r=o.sort((l,c)=>c.rate-l.rate),i=r[0],a=r[r.length-1];return i.rate-a.rate<.1?null:{type:O.PROVIDER_PERFORMANCE,description:`${i.name} succeeds ${(i.rate*100).toFixed(0)}%, ${a.name}: ${(a.rate*100).toFixed(0)}%`,confidence:Math.min(s.reduce((l,[c,u])=>l+u.total,0)/30,1),recommendation:`${i.name} performs best in your project. Consider using it as the default provider.`,evidence:{reportIds:e,metric:"providerPerformance",values:Object.fromEntries(o.map(l=>[l.name,`${(l.rate*100).toFixed(0)}% (n=${l.total})`]))}}}function js(n){let t={morning:{total:0,success:0},afternoon:{total:0,success:0},evening:{total:0,success:0},night:{total:0,success:0}},e=[];for(let l of n){let c=new Date(l.timestamp).getHours(),u=c<6?"night":c<12?"morning":c<18?"afternoon":"evening";t[u].total++,l.success&&t[u].success++,e.push(l.id)}let s=Object.entries(t).filter(([l,c])=>c.total>=3);if(s.length<2)return null;let o=s.map(([l,c])=>({name:l,rate:c.success/c.total,total:c.total})),r=o.sort((l,c)=>c.rate-l.rate),i=r[0],a=r[r.length-1];return i.rate-a.rate<.2?null:{type:O.TIME_OF_DAY,description:`${i.name} runs succeed ${(i.rate*100).toFixed(0)}%, ${a.name}: ${(a.rate*100).toFixed(0)}%`,confidence:Math.min(n.length/20,1),recommendation:`Orchestrations during ${i.name} hours have the highest success rate. This may correlate with API rate limit availability.`,evidence:{reportIds:e,metric:"timeOfDay",values:Object.fromEntries(o.map(l=>[l.name,`${(l.rate*100).toFixed(0)}% (n=${l.total})`]))}}}function As(n){if(n.length===0)return"No significant patterns detected yet. Need more execution history.";let t=["=== Detected Patterns ===",""];for(let e of n){let s=e.confidence>=.7?"HIGH":e.confidence>=.4?"MEDIUM":"LOW";t.push(`[${s}] ${e.description}`),t.push(` Recommendation: ${e.recommendation}`),t.push("")}return t.join(`
|
|
166
|
+
`)}function Ds(n){if(n.length===0)return"";let t=n.filter(e=>e.confidence>=.4).map(e=>`- ${e.recommendation}`).join(`
|
|
156
167
|
`);return t?["## Project-Specific Guidance (from execution history)","","Based on this project's past orchestration runs:",t,"","Apply these recommendations when generating the plan."].join(`
|
|
157
|
-
`):""}function
|
|
158
|
-
`),o=0,r=0,i=0,a=0;for(let f of s){let p=f.trim();if(o+=f.length,p.length===0){a+=f.length;continue}if(p.startsWith("//")||p.startsWith("/*")||p.startsWith("*")||p.startsWith("#"))i+=f.length;else{r+=f.length;let m=f.length-p.length;a+=m,r-=m}}let l=Math.ceil(r/D.CODE),c=Math.ceil(i/D.COMMENTS),u=Math.ceil(a/D.WHITESPACE),d=Math.ceil((o-r-i-a)/D.COMMENTS);return l+c+u+d}var
|
|
159
|
-
`)}function
|
|
160
|
-
`)}function
|
|
168
|
+
`):""}function Je(n){return X.join(n,".orchex","learn","patterns.json")}async function Ls(n,t){let e=Je(n),s=X.dirname(e);await A.mkdir(s,{recursive:!0}),await A.writeFile(e,JSON.stringify(t,null,2),"utf-8")}async function Ns(n){let t=Je(n);try{let e=await A.readFile(t,"utf-8");return JSON.parse(e)}catch{return[]}}function fe(n){let t=[],e=/(?:import|export)\s+.*?from\s+['"](.+?)['"]/g,s;for(;(s=e.exec(n))!==null;)t.push(s[1]);let o=/require\s*\(\s*['"](.+?)['"]\s*\)/g;for(;(s=o.exec(n))!==null;)t.push(s[1]);return t}function pe(n,t){if(!t.startsWith("."))return null;let e=n.substring(0,n.lastIndexOf("/")),s=t.replace(/\.js$/,""),o=[...e.split("/"),...s.split("/")],r=[];for(let a of o)a===".."?r.pop():a!=="."&&r.push(a);let i=r.join("/");return i.endsWith(".ts")?i:i+".ts"}var D={CODE:3.5,COMMENTS:4.5,WHITESPACE:6,JSON:3.8,MARKDOWN:4.2};function Ws(n,t,e){let s=new Set([...n]),o=new Set,r=[...n],i=[],a=new Map;for(let c of n)a.set(c,[]);for(;r.length>0;){let c=r.shift();if(o.has(c))continue;o.add(c);let u=e[c];if(!u)continue;let d=fe(u);for(let f of d){let p=pe(c,f);if(p&&e[p]){if(o.has(p)){let m=a.get(c)||[];i.push(`Circular dependency detected: ${[...m,c,p].join(" \u2192 ")}`)}else if(!s.has(p)){s.add(p),r.push(p);let m=a.get(c)||[];a.set(p,[...m,c])}}}}for(let c of t)s.add(c);let l=Object.keys(e).filter(c=>!s.has(c));return{needed:[...s],pruned:l,warnings:i.length>0?i:void 0}}function Us(n,t,e){let s=[];return e.length>100&&s.push({content:e,type:"system_prompt",reusable:!0,estimatedTokens:Z(e)}),n.length>500&&s.push({content:n,type:"project_context",reusable:!0,estimatedTokens:Z(n)}),t.length>500&&s.push({content:t,type:"stream_context",reusable:!0,estimatedTokens:Z(t)}),s}function Z(n){if(!n||n.length===0)return 0;let t=n.trim().startsWith("{")||n.trim().startsWith("["),e=/^#+\s|^-\s|^\*\s|^\d+\.\s/m.test(n);if(t)return Math.ceil(n.length/D.JSON);if(e)return Math.ceil(n.length/D.MARKDOWN);let s=n.split(`
|
|
169
|
+
`),o=0,r=0,i=0,a=0;for(let f of s){let p=f.trim();if(o+=f.length,p.length===0){a+=f.length;continue}if(p.startsWith("//")||p.startsWith("/*")||p.startsWith("*")||p.startsWith("#"))i+=f.length;else{r+=f.length;let m=f.length-p.length;a+=m,r-=m}}let l=Math.ceil(r/D.CODE),c=Math.ceil(i/D.COMMENTS),u=Math.ceil(a/D.WHITESPACE),d=Math.ceil((o-r-i-a)/D.COMMENTS);return l+c+u+d}var Qe={anthropic:2e5,openai:128e3,gemini:1e6,deepseek:128e3,ollama:128e3,default:1e5},Xe={"claude-opus-4-5-20251101":2e5,"claude-sonnet-4-5-20250929":2e5,"claude-sonnet-4-20250514":2e5,"claude-3-5-sonnet-20241022":2e5,"claude-3-opus-20240229":2e5,"claude-3-haiku-20240307":2e5,"gpt-4.5-turbo":128e3,"gpt-4-turbo":128e3,"gpt-4-turbo-preview":128e3,"gpt-4o":128e3,"gpt-4o-mini":128e3,"o1-preview":128e3,"o1-mini":128e3,"o3-mini":2e5,"gpt-3.5-turbo":16385,"gemini-2.5-pro":1e6,"gemini-2.0-flash":1e6,"gemini-1.5-pro":1e6,"gemini-1.5-flash":1e6,"gemini-pro":32768,"deepseek-chat":128e3,"deepseek-coder":128e3,"deepseek-reasoner":128e3,"llama3.3:70b":128e3,"llama3.2:latest":128e3,"mistral:latest":32e3},zs=.7,Hs=.9,Bs=.8;function Ze(n,t){return t&&Xe[t]?Xe[t]:Qe[n]??Qe.default}function qs(n,t,e){let s=Ze(t,e),o=n?.softLimitTokens??Math.floor(s*zs),r=n?.hardLimitTokens??Math.floor(s*Hs),i=n?.enforcementLevel??"warn",a=n?.warningThreshold??Bs;return{enforcementLevel:i,softLimitTokens:o,hardLimitTokens:r,warningThreshold:a,provider:t,model:e}}function Vs(n,t,e){let s=t-e,o=Math.round(s/e*100);if(n==="none")return"";let r=[`Context is ${o}% over the ${n} limit.`,"Consider:",' - Reducing the number of files in "reads"'," - Splitting the stream into smaller tasks"," - Using file patterns instead of directories"," - Extracting only function signatures instead of full files"];return n==="hard"&&r.push(" - Or increase the hard limit in contextBudget settings"),r.join(`
|
|
170
|
+
`)}function Ys(n,t){let e=Ze(t.provider,t.model),{softLimitTokens:s,hardLimitTokens:o,warningThreshold:r,enforcementLevel:i}=t,a="none",l=s;n>=o?(a="hard",l=o):n>=s&&(a="soft",l=s);let c=n/s,u=!0;a==="hard"&&i==="hard"?u=!1:a==="soft"&&i==="soft"&&(u=!0);let d;if(a!=="none"){let p=a==="hard"?"hard limit":"soft limit";d=`Context size (${n.toLocaleString()} tokens) exceeds ${p} (${l.toLocaleString()} tokens)`,u||(d+=". Execution blocked.")}else c>=r&&(d=`Context size at ${Math.round(c*100)}% of soft limit (${n.toLocaleString()} / ${s.toLocaleString()} tokens)`);let f=a!=="none"?Vs(a,n,l):void 0;return{allowed:u,violationType:a,estimatedTokens:n,budgetLimit:l,utilizationRatio:c,warning:d,suggestion:f,providerLimit:e}}var me=class extends Error{checkResult;streamId;constructor(t,e){let s=e?` for stream "${e}"`:"";super(`Context budget exceeded${s}: ${t.warning}`),this.checkResult=t,this.streamId=e,this.name="ContextBudgetExceededError"}};function Gs(n,t,e=300,s=10,o=120,r=!1){let i=n.split(/\r?\n/);if(i.length<e||t.length===0)return n;let a=t.map(g=>new RegExp(Ks(g),"i")),l=[];for(let g=0;g<i.length;++g)a.some(y=>y.test(i[g]))&&l.push(g);let c=new Set;for(let g of l)for(let y=Math.max(0,g-s);y<=Math.min(i.length-1,g+s);++y)c.add(y);if(c.size<Math.min(20,s*2)){for(let g=0;g<Math.min(s*2,i.length);++g)c.add(g);for(let g=Math.max(0,i.length-s*2);g<i.length;++g)c.add(g)}let d=Array.from(c).sort((g,y)=>g-y).slice(0,o),f=-2,p=[],m=r?String(i.length).length:0;for(let g of d)g>f+1&&p.length>0&&p.push("..."),r?p.push(`${String(g+1).padStart(m)}: ${i[g]}`):p.push(i[g]),f=g;return p.join(`
|
|
171
|
+
`)}function Ks(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}export{me as ContextBudgetExceededError,B as DEFAULT_THRESHOLDS,Ts as adaptReport,ie as analyzeError,ce as analyzeFailureCorrelation,Mt as appendLocalEvents,gs as applyPartialApproval,le as applyTemplate,On as autoFixSequentialEdits,ds as autoMergeOwnershipConflicts,rn as buildDependencyGraph,q as categorizeStream,Ys as checkBudget,ps as classifyTask,_n as cleanupOrphanFixStreams,qs as createBudgetConfig,N as createDetector,Pn as createDiagnostics,Mn as detectOwnershipConflicts,Os as detectPatterns,Ae as detectSequentialEdits,xs as estimatePlannedCost,Z as estimateTokens,es as evaluateCompletion,Gt as extractDeliverables,fe as extractImports,vn as extractPrerequisites,Gs as extractRelevantChunks,K as findMatchingTemplate,Xt as formatDeliverablesReport,an as formatDependencyReport,As as formatPatterns,kn as formatPlanPreview,En as formatPlanPreviewText,Sn as formatStreamsForReview,ye as gatherProjectContext,ls as generateAllSuggestions,Us as generateCachingHints,Wn as generateFixStream,Yn as generateLearningSummary,rt as generatePlan,Bn as generateReport,Un as generateRootCauseFixStream,xn as generateStreams,Jn as getFirstRunSuggestion,Y as getFixChainInfo,Ve as getModelCosts,An as getOriginalStreamId,Ot as getRecommendedLimit,U as getSectionsAtLevel,us as getSuggestionsSummary,$e as getThresholds,Gn as isFirstRun,jn as isFixStream,gt as isUnpopulatedTemplate,Ns as loadPatterns,ks as loadRoutingRules,Kn as markFirstRunComplete,Fn as onStreamComplete,re as optimizeTopology,pt as parsePlanDocument,Ds as patternsToPromptHints,Qt as processDeliverables,Ws as pruneUnusedFiles,Qn as resetLearning,pe as resolveImportPath,ws as rollbackStream,bs as routeStream,Rt as runLearningCycle,Ls as savePatterns,qn as saveReportLocally,Pt as streamResultToTelemetryEvent,fs as suggestProvider,as as suggestSplit,$n as toInitFormat};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ORCHEX_INSTRUCTIONS = "Orchex is a multi-LLM orchestration tool that coordinates parallel AI agents to implement features across multiple files with zero merge conflicts.\n\n## Core Concepts\n\n\u2022 **Streams**: File ownership units \u2014 each stream owns 1-3 files exclusively\n\u2022 **Waves**: Parallel execution groups \u2014 streams in same wave run simultaneously \n\u2022 **Ownership**: Strict isolation \u2014 no two streams can modify the same file\n\u2022 **Self-Healing**: Auto-recovery from failures (max 3 attempts per stream)\n\u2022 **Learning**: System improves with every run, adapting to your codebase\n\u2022 **Model Registry**: Dynamic model discovery \u2014 available models auto-updated from providers daily\n\n## How to Start\n\nAlways use `auto`. It handles everything:\n- Short intent: \"Add user auth with JWT\"\n- Full PRD or spec document: paste the content as the intent\n- Bug report: \"Fix the login timeout on mobile\"\n- Refactoring request: \"Extract payment logic into service layer\"\n\nDo NOT use `learn` directly \u2014 it expects a structured implementation plan with code deliverables, not a PRD or spec.\nDo NOT parse user documents into sections yourself \u2014 `auto` does this automatically.\n\n## Available Tools\n\n### Getting Started:\n\u2022 `auto` \u2014 **Start here.** Takes any input (intent, PRD, spec, bug report) \u2192 generates implementation plan \u2192 previews \u2192 executes.\n\u2022 `init-plan` \u2014 Generate plan template for manual editing (advanced \u2014 use `auto` for most cases)\n\u2022 `init` + `add_stream` \u2014 Manual stream-by-stream control (advanced)\n\n### During Execution:\n\u2022 `status` \u2014 Check current state and progress\n\u2022 `execute` \u2014 Run all pending streams\n\u2022 `recover` \u2014 Auto-heal failed streams\n\u2022 `rollback-stream` \u2014 Undo changes from a specific stream\n\u2022 `reload` \u2014 Refresh state from disk\n\n### After Execution:\n\u2022 `complete` \u2014 Mark orchestration as done and cleanup\n\u2022 `reset-learning` \u2014 Clear learned patterns\n\n### Internal (rarely called directly):\n\u2022 `learn` \u2014 Parse a structured implementation plan into stream definitions. Prefer `auto`.\n\n## Error Recovery\n\nIf execute fails, call status to check stream states, then recover to self-heal failed streams automatically.\n\n## Available Resources\n\n\u2022 orchex://quickstart \u2014 Getting started guide and setup\n\u2022 orchex://concepts/streams \u2014 Stream ownership model\n\u2022 orchex://concepts/waves \u2014 Parallel execution system\n\u2022 orchex://concepts/ownership \u2014 File isolation rules\n\u2022 orchex://concepts/self-healing \u2014 Auto-recovery mechanics\n\u2022 orchex://concepts/providers \u2014 LLM provider configuration\n\u2022 orchex://examples \u2014 Real-world orchestration examples\n\u2022 orchex://api-reference \u2014 Stream definition schema\n\n## API Keys\n\nANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, DEEPSEEK_API_KEY, AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY (for Bedrock)\n\n## Supported Providers\n\nClaude (Anthropic), OpenAI, Gemini, DeepSeek, Ollama (local), AWS Bedrock \u2014 models auto-discovered via registry\n\n**Note:** Cloud mode (`mode: \"cloud\"`) currently uses Anthropic as the execution provider. All 6 providers are available in local mode.\n\n## Cloud Trial\n\nGet 10 free cloud runs (no expiry, no credit card required) \u2014 run `npx @wundam/orchex login`\n\n## Tiers\n\n\u2022 **Free**: 5 streams, 2 waves, all 6 providers (BYOK)\n\u2022 **Pro** ($19/mo): 15 streams, 10 waves\n\u2022 **Team** ($49/user/mo): 25 streams, 25 waves";
|
|
1
|
+
export declare const ORCHEX_INSTRUCTIONS = "Orchex is a multi-LLM orchestration tool that coordinates parallel AI agents to implement features across multiple files with zero merge conflicts.\n\n## Core Concepts\n\n\u2022 **Streams**: File ownership units \u2014 each stream owns 1-3 files exclusively\n\u2022 **Waves**: Parallel execution groups \u2014 streams in same wave run simultaneously \n\u2022 **Ownership**: Strict isolation \u2014 no two streams can modify the same file\n\u2022 **Self-Healing**: Auto-recovery from failures (max 3 attempts per stream)\n\u2022 **Learning**: System improves with every run, adapting to your codebase\n\u2022 **Model Registry**: Dynamic model discovery \u2014 available models auto-updated from providers daily\n\n## How to Start\n\nAlways use `auto`. It handles everything:\n- Short intent: \"Add user auth with JWT\"\n- Full PRD or spec document: paste the content as the intent\n- Bug report: \"Fix the login timeout on mobile\"\n- Refactoring request: \"Extract payment logic into service layer\"\n\nDo NOT use `learn` directly \u2014 it expects a structured implementation plan with code deliverables, not a PRD or spec.\nDo NOT parse user documents into sections yourself \u2014 `auto` does this automatically.\n\n## Available Tools\n\n### Getting Started:\n\u2022 `auto` \u2014 **Start here.** Takes any input (intent, PRD, spec, bug report) \u2192 generates implementation plan \u2192 previews \u2192 executes.\n\u2022 `init-plan` \u2014 Generate plan template for manual editing (advanced \u2014 use `auto` for most cases)\n\u2022 `init` + `add_stream` \u2014 Manual stream-by-stream control (advanced)\n\n### During Execution:\n\u2022 `status` \u2014 Check current state and progress. **Call every 15-30 seconds during execution and relay the executionProgress to the user** \u2014 they cannot see progress otherwise.\n\u2022 `execute` \u2014 Run all pending streams\n\u2022 `recover` \u2014 Auto-heal failed streams\n\u2022 `rollback-stream` \u2014 Undo changes from a specific stream\n\u2022 `reload` \u2014 Refresh state from disk\n\n### After Execution:\n\u2022 `complete` \u2014 Mark orchestration as done and cleanup\n\u2022 `reset-learning` \u2014 Clear learned patterns\n\n### Internal (rarely called directly):\n\u2022 `learn` \u2014 Parse a structured implementation plan into stream definitions. Prefer `auto`.\n\n## Error Recovery\n\nIf execute fails, call status to check stream states, then recover to self-heal failed streams automatically.\n\n## Available Resources\n\n\u2022 orchex://quickstart \u2014 Getting started guide and setup\n\u2022 orchex://concepts/streams \u2014 Stream ownership model\n\u2022 orchex://concepts/waves \u2014 Parallel execution system\n\u2022 orchex://concepts/ownership \u2014 File isolation rules\n\u2022 orchex://concepts/self-healing \u2014 Auto-recovery mechanics\n\u2022 orchex://concepts/providers \u2014 LLM provider configuration\n\u2022 orchex://examples \u2014 Real-world orchestration examples\n\u2022 orchex://api-reference \u2014 Stream definition schema\n\n## API Keys\n\nANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, DEEPSEEK_API_KEY, AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY (for Bedrock)\n\n## Supported Providers\n\nClaude (Anthropic), OpenAI, Gemini, DeepSeek, Ollama (local), AWS Bedrock \u2014 models auto-discovered via registry\n\n**Note:** Cloud mode (`mode: \"cloud\"`) currently uses Anthropic as the execution provider. All 6 providers are available in local mode.\n\n## Cloud Trial\n\nGet 10 free cloud runs (no expiry, no credit card required) \u2014 run `npx @wundam/orchex login`\n\n## Tiers\n\n\u2022 **Free**: 5 streams, 2 waves, all 6 providers (BYOK)\n\u2022 **Pro** ($19/mo): 15 streams, 10 waves\n\u2022 **Team** ($49/user/mo): 25 streams, 25 waves";
|
package/dist/mcp-instructions.js
CHANGED
|
@@ -30,7 +30,7 @@ Do NOT parse user documents into sections yourself — \`auto\` does this automa
|
|
|
30
30
|
• \`init\` + \`add_stream\` — Manual stream-by-stream control (advanced)
|
|
31
31
|
|
|
32
32
|
### During Execution:
|
|
33
|
-
• \`status\` — Check current state and progress
|
|
33
|
+
• \`status\` — Check current state and progress. **Call every 15-30 seconds during execution and relay the executionProgress to the user** — they cannot see progress otherwise.
|
|
34
34
|
• \`execute\` — Run all pending streams
|
|
35
35
|
• \`recover\` — Auto-heal failed streams
|
|
36
36
|
• \`rollback-stream\` — Undo changes from a specific stream
|
package/dist/orchestrator.js
CHANGED
|
@@ -2,7 +2,7 @@ import { loadManifest, saveManifest, updateStreamStatus, addStream, recoverStuck
|
|
|
2
2
|
import { createLogger, clearExecutionLog } from './logger.js';
|
|
3
3
|
import { createLogger as createPinoLogger } from './logging.js';
|
|
4
4
|
const log = createPinoLogger('orchestrator');
|
|
5
|
-
import { generateFixStream, analyzeError, cleanupOrphanFixStreams, streamResultToTelemetryEvent, appendLocalEvents, runLearningCycle, routeStream, loadRoutingRules, } from './intelligence/index.js';
|
|
5
|
+
import { generateFixStream, generateRootCauseFixStream, analyzeFailureCorrelation, analyzeError, cleanupOrphanFixStreams, streamResultToTelemetryEvent, appendLocalEvents, runLearningCycle, routeStream, loadRoutingRules, } from './intelligence/index.js';
|
|
6
6
|
import { calculateWaves } from './waves.js';
|
|
7
7
|
import { buildFullPrompt, buildFullPromptOptimized } from './context-builder.js';
|
|
8
8
|
import { applyArtifact, writeArtifact, validateArtifactSanity, createStreamBackup, revertStreamBackup, withStreamIsolation, writeBackup, readAllBackups, deleteBackup, recoverFromIsolationCrash } from './artifacts.js';
|
|
@@ -540,8 +540,9 @@ async function executeWaveInternal(projectDir, executor, options, logger) {
|
|
|
540
540
|
};
|
|
541
541
|
}
|
|
542
542
|
catch (error) {
|
|
543
|
-
const
|
|
544
|
-
const
|
|
543
|
+
const err = error;
|
|
544
|
+
const catchError = err.name && err.name !== 'Error' ? `${err.name}: ${err.message}` : err.message;
|
|
545
|
+
const catchAnalysis = analyzeError(err.stack ?? catchError, 'transport');
|
|
545
546
|
await logger.error('stream_failed', {
|
|
546
547
|
id: stream.id,
|
|
547
548
|
phase: 'execution',
|
|
@@ -568,21 +569,28 @@ async function executeWaveInternal(projectDir, executor, options, logger) {
|
|
|
568
569
|
}
|
|
569
570
|
});
|
|
570
571
|
// Wrap each promise with stream ID so rejections are identifiable
|
|
571
|
-
const taggedPromises = executePromises.map((p, i) => p.catch(err =>
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
572
|
+
const taggedPromises = executePromises.map((p, i) => p.catch(err => {
|
|
573
|
+
const errorMsg = err.message ?? String(err);
|
|
574
|
+
const errorStack = err.stack;
|
|
575
|
+
const fullError = errorStack ? `${errorMsg}\n${errorStack}` : errorMsg;
|
|
576
|
+
const analysis = analyzeError(fullError, 'transport');
|
|
577
|
+
return {
|
|
578
|
+
id: activeStreams[i]?.id ?? `wave-${targetWave.number}-idx-${i}`,
|
|
579
|
+
name: activeStreams[i]?.name ?? 'unknown',
|
|
580
|
+
status: 'failed',
|
|
581
|
+
error: errorMsg,
|
|
582
|
+
errorDetail: { category: analysis.category, retryable: analysis.retryable, selfHealable: analysis.selfHealable, suggestion: analysis.suggestion },
|
|
583
|
+
tokensUsed: { input: 0, output: 0 },
|
|
584
|
+
};
|
|
585
|
+
}));
|
|
579
586
|
// Promise.allSettled — one failure doesn't kill the wave
|
|
580
587
|
const settled = await Promise.allSettled(taggedPromises);
|
|
581
588
|
// Calculate parallel execution time (wall clock)
|
|
582
589
|
const waveEndTime = Date.now();
|
|
583
590
|
const waveCompletedAt = new Date().toISOString();
|
|
584
591
|
const parallelMs = waveEndTime - waveStartTime;
|
|
585
|
-
for (
|
|
592
|
+
for (let idx = 0; idx < settled.length; idx++) {
|
|
593
|
+
const result = settled[idx];
|
|
586
594
|
if (result.status === 'fulfilled') {
|
|
587
595
|
streamResults.push(result.value);
|
|
588
596
|
}
|
|
@@ -590,8 +598,8 @@ async function executeWaveInternal(projectDir, executor, options, logger) {
|
|
|
590
598
|
const rejectedError = result.reason?.message ?? 'Unknown error';
|
|
591
599
|
const rejectedAnalysis = analyzeError(rejectedError, 'transport');
|
|
592
600
|
streamResults.push({
|
|
593
|
-
id:
|
|
594
|
-
name: 'unknown',
|
|
601
|
+
id: activeStreams[idx]?.id ?? `wave-${targetWave.number}-idx-${idx}`,
|
|
602
|
+
name: activeStreams[idx]?.name ?? 'unknown',
|
|
595
603
|
status: 'failed',
|
|
596
604
|
error: rejectedError,
|
|
597
605
|
errorDetail: { category: rejectedAnalysis.category, retryable: rejectedAnalysis.retryable, selfHealable: rejectedAnalysis.selfHealable, suggestion: rejectedAnalysis.suggestion },
|
|
@@ -669,7 +677,7 @@ async function executeWaveInternal(projectDir, executor, options, logger) {
|
|
|
669
677
|
.filter(s => s && s.trim())
|
|
670
678
|
.join('\n')
|
|
671
679
|
|| 'unknown error';
|
|
672
|
-
|
|
680
|
+
let errorSummary = `Verify failed: ${failed.command}: ${verifyError.slice(0, 500)}`;
|
|
673
681
|
const verifyAnalysis = analyzeError(verifyError, 'verify');
|
|
674
682
|
verifyDetails.push(`${sr.id}: ${errorSummary}`);
|
|
675
683
|
await updateStreamStatus(projectDir, sr.id, 'failed', errorSummary);
|
|
@@ -681,6 +689,7 @@ async function executeWaveInternal(projectDir, executor, options, logger) {
|
|
|
681
689
|
isolated: otherBackups.length > 0,
|
|
682
690
|
});
|
|
683
691
|
// Rollback file changes for failed verify — prevents leaving orphan files on disk
|
|
692
|
+
let rollbackFailed = false;
|
|
684
693
|
const streamBackup = successBackups.find(b => b.streamId === sr.id);
|
|
685
694
|
if (streamBackup) {
|
|
686
695
|
try {
|
|
@@ -688,12 +697,18 @@ async function executeWaveInternal(projectDir, executor, options, logger) {
|
|
|
688
697
|
await logger.info('verify_rollback', { stream: sr.id, files: streamBackup.entries.length + streamBackup.createdFiles.length });
|
|
689
698
|
}
|
|
690
699
|
catch (rollbackErr) {
|
|
691
|
-
|
|
700
|
+
rollbackFailed = true;
|
|
701
|
+
const rollbackMsg = rollbackErr.message;
|
|
702
|
+
await logger.warn('verify_rollback_failed', { stream: sr.id, error: rollbackMsg });
|
|
703
|
+
errorSummary += ` [ROLLBACK FAILED: ${rollbackMsg} — files may remain on disk]`;
|
|
692
704
|
}
|
|
693
705
|
}
|
|
694
706
|
sr.status = 'failed';
|
|
695
707
|
sr.error = errorSummary;
|
|
696
|
-
|
|
708
|
+
const suggestion = rollbackFailed
|
|
709
|
+
? `${verifyAnalysis.suggestion}. WARNING: Rollback failed — manually check files owned by this stream.`
|
|
710
|
+
: verifyAnalysis.suggestion;
|
|
711
|
+
sr.errorDetail = { category: verifyAnalysis.category, retryable: verifyAnalysis.retryable, selfHealable: verifyAnalysis.selfHealable && !rollbackFailed, suggestion };
|
|
697
712
|
}
|
|
698
713
|
else {
|
|
699
714
|
verifyPassed++;
|
|
@@ -753,9 +768,75 @@ async function executeWaveInternal(projectDir, executor, options, logger) {
|
|
|
753
768
|
// When all streams fail with a selfHealable category (code errors), fix streams are still useful.
|
|
754
769
|
const cbBlocksHealing = circuitBreaker.tripped && !(circuitBreaker.selfHealable ?? false);
|
|
755
770
|
if (tier.selfHealing === 'full' && !cbBlocksHealing) {
|
|
771
|
+
// Root-cause correlation: when multiple downstream streams fail with the same error,
|
|
772
|
+
// fix the root-cause stream instead of retrying each downstream independently.
|
|
773
|
+
const failedIds = streamResults.filter(sr => sr.status === 'failed' && sr.id !== 'unknown').map(sr => sr.id);
|
|
774
|
+
const correlation = failedIds.length >= 2 ? analyzeFailureCorrelation(currentManifest, failedIds) : null;
|
|
775
|
+
const correlatedSkipSet = new Set();
|
|
776
|
+
if (correlation) {
|
|
777
|
+
const rootId = correlation.rootCauseStreamId;
|
|
778
|
+
await logger.info('root_cause_correlation_detected', {
|
|
779
|
+
rootCauseStream: rootId,
|
|
780
|
+
affectedStreams: correlation.affectedStreamIds,
|
|
781
|
+
commonPattern: correlation.commonErrorPattern,
|
|
782
|
+
});
|
|
783
|
+
// Mark root-cause stream as failed so it gets a fix stream
|
|
784
|
+
const rootError = `Root cause: ${correlation.affectedStreamIds.length} downstream streams failed with errors referencing '${correlation.commonErrorPattern}'`;
|
|
785
|
+
currentManifest.streams[rootId].status = 'failed';
|
|
786
|
+
currentManifest.streams[rootId].error = rootError;
|
|
787
|
+
// Reset attempts so the original successful run doesn't count against MAX_ATTEMPTS
|
|
788
|
+
currentManifest.streams[rootId].attempts = 0;
|
|
789
|
+
// Revert root-cause stream's files — its output is wrong
|
|
790
|
+
// Try in-memory backups first, fall back to disk (root may have completed in a previous wave)
|
|
791
|
+
let rootBackup = successBackups.find(b => b.streamId === rootId);
|
|
792
|
+
if (!rootBackup) {
|
|
793
|
+
const diskBackups = await readAllBackups(projectDir);
|
|
794
|
+
rootBackup = diskBackups.find(b => b.streamId === rootId);
|
|
795
|
+
}
|
|
796
|
+
if (rootBackup) {
|
|
797
|
+
try {
|
|
798
|
+
await revertStreamBackup(projectDir, rootBackup);
|
|
799
|
+
await logger.info('root_cause_reverted', { stream: rootId, files: rootBackup.entries.length + rootBackup.createdFiles.length });
|
|
800
|
+
}
|
|
801
|
+
catch (revertErr) {
|
|
802
|
+
await logger.warn('root_cause_revert_failed', { stream: rootId, error: revertErr.message });
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
// Skip orphaned fix streams for affected downstream streams before resetting them.
|
|
806
|
+
// Without this, previous fix streams (e.g., B-fix-1) remain pending and conflict
|
|
807
|
+
// with the root-cause fix approach.
|
|
808
|
+
for (const affectedId of correlation.affectedStreamIds) {
|
|
809
|
+
for (const [id, stream] of Object.entries(currentManifest.streams)) {
|
|
810
|
+
if (stream.parentStreamId === affectedId && stream.status === 'pending') {
|
|
811
|
+
currentManifest.streams[id].status = 'skipped';
|
|
812
|
+
currentManifest.streams[id].error = `Root cause identified: '${rootId}' — fix stream no longer needed`;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
// Reset correlated downstream streams to pending — they'll re-run after root is fixed
|
|
817
|
+
for (const affectedId of correlation.affectedStreamIds) {
|
|
818
|
+
currentManifest.streams[affectedId].status = 'pending';
|
|
819
|
+
delete currentManifest.streams[affectedId].error;
|
|
820
|
+
correlatedSkipSet.add(affectedId);
|
|
821
|
+
}
|
|
822
|
+
// Save all status mutations BEFORE addStream() — addStream internally reloads
|
|
823
|
+
// the manifest, so it must see the latest state to compute waves correctly.
|
|
824
|
+
await saveManifest(projectDir, currentManifest);
|
|
825
|
+
// Generate fix stream for root cause (after save so addStream sees current state)
|
|
826
|
+
const rootFix = generateRootCauseFixStream(currentManifest, correlation);
|
|
827
|
+
if (rootFix) {
|
|
828
|
+
await addStream(projectDir, rootFix.fixStreamId, rootFix.fixStream);
|
|
829
|
+
fixStreamsGenerated.push(rootFix.fixStreamId);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
// Generate fix streams for remaining (non-correlated) failures
|
|
756
833
|
for (const sr of streamResults) {
|
|
757
834
|
if (sr.status !== 'failed' || sr.id === 'unknown')
|
|
758
835
|
continue;
|
|
836
|
+
if (correlatedSkipSet.has(sr.id))
|
|
837
|
+
continue; // Already handled by root-cause fix
|
|
838
|
+
if (sr.id === correlation?.rootCauseStreamId)
|
|
839
|
+
continue; // Root cause gets its own fix above
|
|
759
840
|
// Pass the in-memory errorDetail (computed with origin hint) so generateFixStream
|
|
760
841
|
// can use the correct selfHealable flag rather than re-analyzing without origin.
|
|
761
842
|
const fixResult = generateFixStream(currentManifest, sr.id, sr.errorDetail);
|
package/dist/ownership.js
CHANGED
|
@@ -107,8 +107,12 @@ export function checkOwnership(operations, owns, options = {}) {
|
|
|
107
107
|
}
|
|
108
108
|
return { violations, warnings, allowed };
|
|
109
109
|
}
|
|
110
|
+
function normalizePath(p) {
|
|
111
|
+
// Strip leading "./" — LLM artifacts may include it inconsistently
|
|
112
|
+
return p.startsWith('./') ? p.slice(2) : p;
|
|
113
|
+
}
|
|
110
114
|
function checkSingleOperation(op, owns, options) {
|
|
111
|
-
const filePath = op.path;
|
|
115
|
+
const filePath = normalizePath(op.path);
|
|
112
116
|
// SECURITY: Block path traversal (non-negotiable, checked first)
|
|
113
117
|
if (filePath.includes('..')) {
|
|
114
118
|
return {
|
|
@@ -141,26 +145,28 @@ function checkSingleOperation(op, owns, options) {
|
|
|
141
145
|
warning: `Common file '${filePath}' created (not in owns list)`,
|
|
142
146
|
};
|
|
143
147
|
}
|
|
144
|
-
// Not allowed
|
|
148
|
+
// Not allowed — include owns list for debuggability
|
|
145
149
|
return {
|
|
146
|
-
violation: `${op.type} on '${filePath}' is outside owned files`,
|
|
150
|
+
violation: `${op.type} on '${filePath}' is outside owned files [${owns.join(', ')}]`,
|
|
147
151
|
};
|
|
148
152
|
}
|
|
149
153
|
/**
|
|
150
154
|
* Check if a path is explicitly covered by an ownership pattern.
|
|
151
155
|
*/
|
|
152
156
|
function isExplicitlyOwned(filePath, owns) {
|
|
157
|
+
const normalizedFile = normalizePath(filePath);
|
|
153
158
|
return owns.some((pattern) => {
|
|
159
|
+
const normalizedPattern = normalizePath(pattern);
|
|
154
160
|
// Directory pattern: "src/" matches "src/foo.ts"
|
|
155
|
-
if (
|
|
156
|
-
return
|
|
161
|
+
if (normalizedPattern.endsWith('/')) {
|
|
162
|
+
return normalizedFile.startsWith(normalizedPattern);
|
|
157
163
|
}
|
|
158
164
|
// Glob pattern: "src/*.ts" matches "src/foo.ts"
|
|
159
|
-
if (
|
|
160
|
-
return matchGlobPattern(
|
|
165
|
+
if (normalizedPattern.includes('*')) {
|
|
166
|
+
return matchGlobPattern(normalizedPattern, normalizedFile);
|
|
161
167
|
}
|
|
162
168
|
// Exact match
|
|
163
|
-
return
|
|
169
|
+
return normalizedFile === normalizedPattern;
|
|
164
170
|
});
|
|
165
171
|
}
|
|
166
172
|
/**
|
package/dist/tools.js
CHANGED
|
@@ -497,7 +497,7 @@ export function registerTools(server, executor, context) {
|
|
|
497
497
|
// --------------------------------------------------------------------------
|
|
498
498
|
server.registerTool('status', {
|
|
499
499
|
title: 'Orchestration Status',
|
|
500
|
-
description: 'Get the current orchestration status and progress.',
|
|
500
|
+
description: 'Get the current orchestration status and progress. Call every 15-30 seconds during execution to show the user real-time progress.',
|
|
501
501
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
502
502
|
inputSchema: {
|
|
503
503
|
project_dir: z.string().optional().describe('Project directory'),
|
|
@@ -659,7 +659,40 @@ export function registerTools(server, executor, context) {
|
|
|
659
659
|
hint: 'Fix the root cause, then run recover with include_failed: true to resume.',
|
|
660
660
|
};
|
|
661
661
|
}
|
|
662
|
-
|
|
662
|
+
// Build execution progress block when streams are actively running
|
|
663
|
+
const inProgressStreams = streams.filter(s => s.status === 'in_progress');
|
|
664
|
+
const isExecuting = inProgressStreams.length > 0;
|
|
665
|
+
if (isExecuting) {
|
|
666
|
+
// Build per-stream status lines for LLM to relay to user
|
|
667
|
+
const streamLines = streams.map(s => {
|
|
668
|
+
const icon = s.status === 'complete' ? '✓'
|
|
669
|
+
: s.status === 'failed' ? '✗'
|
|
670
|
+
: s.status === 'in_progress' ? '⟳'
|
|
671
|
+
: s.status === 'skipped' ? '⊘'
|
|
672
|
+
: '·';
|
|
673
|
+
const detail = s.status === 'failed' && s.error ? ` — ${s.error.slice(0, 80)}` : '';
|
|
674
|
+
return ` ${icon} ${s.name ?? s.id} — ${s.status}${detail}`;
|
|
675
|
+
});
|
|
676
|
+
responseData.executionProgress = {
|
|
677
|
+
executing: true,
|
|
678
|
+
summary: `Wave ${currentWave?.number ?? '?'}/${waves.length} in progress — ${completed}/${total} complete, ${failed} failed, ${inProgressStreams.length} running`,
|
|
679
|
+
streamStatus: streamLines,
|
|
680
|
+
hint: 'Relay the above progress to the user. Call status again in 15-30 seconds for updates.',
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
else if (completed + failed === total && total > 0) {
|
|
684
|
+
responseData.executionProgress = {
|
|
685
|
+
executing: false,
|
|
686
|
+
summary: `Execution complete — ${completed}/${total} succeeded, ${failed} failed`,
|
|
687
|
+
hint: failed > 0
|
|
688
|
+
? 'Some streams failed. Use recover to retry, or complete to finish.'
|
|
689
|
+
: 'All streams succeeded. Use complete to finalize.',
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
const statusMessage = isExecuting
|
|
693
|
+
? `Orchestration "${manifest.feature}" — executing (${completed}/${total} complete, ${inProgressStreams.length} running)`
|
|
694
|
+
: `Orchestration: "${manifest.feature}"`;
|
|
695
|
+
return ok(statusMessage, responseData);
|
|
663
696
|
});
|
|
664
697
|
});
|
|
665
698
|
// --------------------------------------------------------------------------
|
|
@@ -1011,7 +1044,8 @@ export function registerTools(server, executor, context) {
|
|
|
1011
1044
|
eventsEnabled: true,
|
|
1012
1045
|
totalWaves: waves.length,
|
|
1013
1046
|
totalStreams: Object.keys(manifest.streams).length,
|
|
1014
|
-
|
|
1047
|
+
pollIntervalSeconds: 20,
|
|
1048
|
+
hint: 'IMPORTANT: The user cannot see execution progress unless you poll and relay it. Call orchex.status every 15-30 seconds and show the user the executionProgress block until execution completes.',
|
|
1015
1049
|
});
|
|
1016
1050
|
}
|
|
1017
1051
|
// Wave mode: execute one wave in background
|
|
@@ -1140,7 +1174,8 @@ export function registerTools(server, executor, context) {
|
|
|
1140
1174
|
wave: currentWave.number,
|
|
1141
1175
|
totalWaves: waves.length,
|
|
1142
1176
|
streams: currentWave.streams.map((s) => s.id),
|
|
1143
|
-
|
|
1177
|
+
pollIntervalSeconds: 20,
|
|
1178
|
+
hint: 'IMPORTANT: The user cannot see execution progress unless you poll and relay it. Call orchex.status every 15-30 seconds and show the user the executionProgress block until execution completes.',
|
|
1144
1179
|
});
|
|
1145
1180
|
});
|
|
1146
1181
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wundam/orchex",
|
|
3
3
|
"mcpName": "io.github.wundam/orchex",
|
|
4
|
-
"version": "1.0.0-rc.
|
|
4
|
+
"version": "1.0.0-rc.23",
|
|
5
5
|
"description": "Autopilot AI orchestration — auto-plan, parallelize, and execute with ownership enforcement",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"author": "Wundam LLC",
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
|
-
"url": "https://orchex
|
|
23
|
+
"url": "https://github.com/wundam/orchex-community"
|
|
24
24
|
},
|
|
25
25
|
"homepage": "https://orchex.dev",
|
|
26
26
|
"bugs": {
|
|
27
|
-
"url": "https://
|
|
27
|
+
"url": "https://github.com/wundam/orchex-community/discussions"
|
|
28
28
|
},
|
|
29
29
|
"keywords": [
|
|
30
30
|
"mcp",
|