@yuaone/core 0.3.3 → 0.4.0

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.
Files changed (126) hide show
  1. package/dist/agent-loop.d.ts +62 -0
  2. package/dist/agent-loop.d.ts.map +1 -1
  3. package/dist/agent-loop.js +705 -18
  4. package/dist/agent-loop.js.map +1 -1
  5. package/dist/background-agent.d.ts +110 -0
  6. package/dist/background-agent.d.ts.map +1 -0
  7. package/dist/background-agent.js +255 -0
  8. package/dist/background-agent.js.map +1 -0
  9. package/dist/coding-standards.d.ts +45 -0
  10. package/dist/coding-standards.d.ts.map +1 -0
  11. package/dist/coding-standards.js +1152 -0
  12. package/dist/coding-standards.js.map +1 -0
  13. package/dist/constants.d.ts.map +1 -1
  14. package/dist/constants.js +2 -6
  15. package/dist/constants.js.map +1 -1
  16. package/dist/context-manager.d.ts +6 -0
  17. package/dist/context-manager.d.ts.map +1 -1
  18. package/dist/context-manager.js +23 -4
  19. package/dist/context-manager.js.map +1 -1
  20. package/dist/index.d.ts +28 -4
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +26 -2
  23. package/dist/index.js.map +1 -1
  24. package/dist/llm-client.d.ts +8 -3
  25. package/dist/llm-client.d.ts.map +1 -1
  26. package/dist/llm-client.js +64 -13
  27. package/dist/llm-client.js.map +1 -1
  28. package/dist/plugin-auto-loader.d.ts +108 -0
  29. package/dist/plugin-auto-loader.d.ts.map +1 -0
  30. package/dist/plugin-auto-loader.js +743 -0
  31. package/dist/plugin-auto-loader.js.map +1 -0
  32. package/dist/plugin-registry.d.ts +112 -0
  33. package/dist/plugin-registry.d.ts.map +1 -0
  34. package/dist/plugin-registry.js +319 -0
  35. package/dist/plugin-registry.js.map +1 -0
  36. package/dist/plugin-types.d.ts +388 -0
  37. package/dist/plugin-types.d.ts.map +1 -0
  38. package/dist/plugin-types.js +8 -0
  39. package/dist/plugin-types.js.map +1 -0
  40. package/dist/plugin-validator.d.ts +54 -0
  41. package/dist/plugin-validator.d.ts.map +1 -0
  42. package/dist/plugin-validator.js +129 -0
  43. package/dist/plugin-validator.js.map +1 -0
  44. package/dist/repo-knowledge-graph.d.ts +112 -0
  45. package/dist/repo-knowledge-graph.d.ts.map +1 -0
  46. package/dist/repo-knowledge-graph.js +561 -0
  47. package/dist/repo-knowledge-graph.js.map +1 -0
  48. package/dist/role-registry.js +1 -1
  49. package/dist/role-registry.js.map +1 -1
  50. package/dist/self-debug-loop.d.ts +257 -0
  51. package/dist/self-debug-loop.d.ts.map +1 -0
  52. package/dist/self-debug-loop.js +870 -0
  53. package/dist/self-debug-loop.js.map +1 -0
  54. package/dist/skill-learner.d.ts +136 -0
  55. package/dist/skill-learner.d.ts.map +1 -0
  56. package/dist/skill-learner.js +382 -0
  57. package/dist/skill-learner.js.map +1 -0
  58. package/dist/skill-loader.d.ts +90 -0
  59. package/dist/skill-loader.d.ts.map +1 -0
  60. package/dist/skill-loader.js +309 -0
  61. package/dist/skill-loader.js.map +1 -0
  62. package/dist/specialist-registry.d.ts +132 -0
  63. package/dist/specialist-registry.d.ts.map +1 -0
  64. package/dist/specialist-registry.js +413 -0
  65. package/dist/specialist-registry.js.map +1 -0
  66. package/dist/sub-agent-prompts.d.ts +45 -0
  67. package/dist/sub-agent-prompts.d.ts.map +1 -0
  68. package/dist/sub-agent-prompts.js +177 -0
  69. package/dist/sub-agent-prompts.js.map +1 -0
  70. package/dist/sub-agent-router.d.ts +75 -0
  71. package/dist/sub-agent-router.d.ts.map +1 -0
  72. package/dist/sub-agent-router.js +174 -0
  73. package/dist/sub-agent-router.js.map +1 -0
  74. package/dist/sub-agent.d.ts +48 -0
  75. package/dist/sub-agent.d.ts.map +1 -1
  76. package/dist/sub-agent.js +108 -5
  77. package/dist/sub-agent.js.map +1 -1
  78. package/dist/system-prompt.d.ts +26 -0
  79. package/dist/system-prompt.d.ts.map +1 -1
  80. package/dist/system-prompt.js +177 -7
  81. package/dist/system-prompt.js.map +1 -1
  82. package/dist/task-classifier.d.ts +25 -1
  83. package/dist/task-classifier.d.ts.map +1 -1
  84. package/dist/task-classifier.js +171 -1
  85. package/dist/task-classifier.js.map +1 -1
  86. package/dist/tool-planner.d.ts +160 -0
  87. package/dist/tool-planner.d.ts.map +1 -0
  88. package/dist/tool-planner.js +501 -0
  89. package/dist/tool-planner.js.map +1 -0
  90. package/dist/types.d.ts +1 -1
  91. package/dist/types.d.ts.map +1 -1
  92. package/package.json +2 -1
  93. package/plugins/git/patterns/branch-patterns.json +101 -0
  94. package/plugins/git/patterns/commit-patterns.json +186 -0
  95. package/plugins/git/plugin.yaml +128 -0
  96. package/plugins/git/skills/branch-strategy.md +172 -0
  97. package/plugins/git/skills/commit-conv.md +178 -0
  98. package/plugins/git/skills/conflict-resolve.md +159 -0
  99. package/plugins/git/skills/history-clean.md +199 -0
  100. package/plugins/git/skills/pr-review.md +196 -0
  101. package/plugins/git/strategies/conflict-resolve.json +244 -0
  102. package/plugins/git/strategies/release-flow.json +292 -0
  103. package/plugins/git/validators/rules.json +348 -0
  104. package/plugins/react/patterns/anti-patterns.json +88 -0
  105. package/plugins/react/patterns/components.json +80 -0
  106. package/plugins/react/patterns/hooks.json +72 -0
  107. package/plugins/react/plugin.yaml +229 -0
  108. package/plugins/react/skills/bugfix.md +208 -0
  109. package/plugins/react/skills/component-gen.md +206 -0
  110. package/plugins/react/skills/hook-extract.md +208 -0
  111. package/plugins/react/skills/ssr.md +256 -0
  112. package/plugins/react/skills/test.md +273 -0
  113. package/plugins/react/strategies/build-fix.json +43 -0
  114. package/plugins/react/strategies/hook-loop-fix.json +36 -0
  115. package/plugins/react/strategies/hydration-fix.json +42 -0
  116. package/plugins/react/validators/rules.json +92 -0
  117. package/plugins/typescript/patterns/best-practices.json +25 -0
  118. package/plugins/typescript/patterns/common-errors.json +32 -0
  119. package/plugins/typescript/plugin.yaml +74 -0
  120. package/plugins/typescript/skills/debug.md +23 -0
  121. package/plugins/typescript/skills/migration.md +24 -0
  122. package/plugins/typescript/skills/refactor.md +22 -0
  123. package/plugins/typescript/skills/strict-mode.md +23 -0
  124. package/plugins/typescript/strategies/strict-migration.json +37 -0
  125. package/plugins/typescript/strategies/type-error-fix.json +37 -0
  126. package/plugins/typescript/validators/rules.json +28 -0
@@ -0,0 +1,160 @@
1
+ /**
2
+ * @module tool-planner
3
+ * @description Tool Planning Layer — Plans optimal tool sequences before execution.
4
+ *
5
+ * Adds explicit planning between reasoning and execution:
6
+ * reasoning → plan → tool sequence → execute → verify
7
+ *
8
+ * Benefits:
9
+ * - Fewer unnecessary tool calls
10
+ * - Better first-attempt quality
11
+ * - Adapts based on task type and repo memory
12
+ */
13
+ /** Context provided when creating a plan */
14
+ export interface PlanContext {
15
+ /** User's original message / goal */
16
+ userMessage: string;
17
+ /** Known file paths relevant to the task */
18
+ knownFiles?: string[];
19
+ /** Project language / framework info */
20
+ language?: string;
21
+ /** Whether the project has tests */
22
+ hasTests?: boolean;
23
+ /** Whether the project has lint configured */
24
+ hasLint?: boolean;
25
+ /** Whether the project uses TypeScript */
26
+ usesTypeScript?: boolean;
27
+ /** Extra context hints from TaskClassifier */
28
+ contextHints?: string[];
29
+ }
30
+ /** Repo-specific profile used to adapt plans */
31
+ export interface RepoProfile {
32
+ /** Whether tsc --noEmit should always be run */
33
+ alwaysTypeCheck?: boolean;
34
+ /** Whether lint should always be run after edits */
35
+ alwaysLint?: boolean;
36
+ /** Whether tests should always be run after changes */
37
+ alwaysTest?: boolean;
38
+ /** Custom verification command (e.g., "pnpm build") */
39
+ verifyCommand?: string;
40
+ /** File patterns to always read first (e.g., CLAUDE.md) */
41
+ alwaysReadFiles?: string[];
42
+ /** Known flaky tools to avoid */
43
+ avoidTools?: string[];
44
+ }
45
+ /** A single step in a tool plan */
46
+ export interface ToolPlanStep {
47
+ /** Tool name */
48
+ tool: string;
49
+ /** Why this tool is needed */
50
+ purpose: string;
51
+ /** Expected input pattern */
52
+ expectedInput?: string;
53
+ /** What to do if this step fails */
54
+ fallback?: string;
55
+ /** Dependencies on previous steps (step indices) */
56
+ dependsOn?: number[];
57
+ /** Can be skipped if previous step covers it */
58
+ optional?: boolean;
59
+ }
60
+ /** A complete tool execution plan */
61
+ export interface ToolPlan {
62
+ /** Planned tool sequence */
63
+ steps: ToolPlanStep[];
64
+ /** Estimated total tool calls */
65
+ estimatedCalls: number;
66
+ /** Reasoning for this plan */
67
+ reasoning: string;
68
+ /** Confidence in this plan (0–1) */
69
+ confidence: number;
70
+ }
71
+ /** Report on how well execution followed the plan */
72
+ export interface PlanComplianceReport {
73
+ /** Did execution follow the plan? */
74
+ compliant: boolean;
75
+ /** Steps that were executed as planned */
76
+ executedSteps: number[];
77
+ /** Steps that were skipped */
78
+ skippedSteps: number[];
79
+ /** Tools used that were not in the plan */
80
+ unplannedTools: string[];
81
+ /** Overall compliance ratio (0–1) */
82
+ complianceRatio: number;
83
+ /** Human-readable summary */
84
+ summary: string;
85
+ }
86
+ /**
87
+ * ToolPlanner — Plans optimal tool sequences before execution.
88
+ *
89
+ * Uses pre-defined task sequences combined with repo-specific profiles
90
+ * to produce an efficient, dependency-ordered plan.
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * const planner = new ToolPlanner();
95
+ * const plan = planner.planForTask("debug", {
96
+ * userMessage: "Fix the type error in agent-loop.ts",
97
+ * usesTypeScript: true,
98
+ * });
99
+ * console.log(planner.formatPlanHint(plan));
100
+ * ```
101
+ */
102
+ export declare class ToolPlanner {
103
+ /**
104
+ * Create a tool plan based on task classification.
105
+ *
106
+ * @param taskType - Task type from TaskClassifier (e.g., "debug", "feature")
107
+ * @param context - Optional planning context (user message, known files, etc.)
108
+ * @returns A ToolPlan with ordered steps, estimated calls, and confidence
109
+ */
110
+ planForTask(taskType: string, context?: PlanContext): ToolPlan;
111
+ /**
112
+ * Adapt plan based on repo-specific memory.
113
+ * E.g., if repo always needs tsc check, add it.
114
+ *
115
+ * @param plan - The base plan to adapt
116
+ * @param repoProfile - Repo-specific profile
117
+ * @returns Adapted plan with extra steps as needed
118
+ */
119
+ adaptPlan(plan: ToolPlan, repoProfile?: RepoProfile): ToolPlan;
120
+ /**
121
+ * Format plan as system prompt hint for the LLM.
122
+ *
123
+ * @param plan - The tool plan to format
124
+ * @returns Formatted string suitable for system prompt injection
125
+ */
126
+ formatPlanHint(plan: ToolPlan): string;
127
+ /**
128
+ * Validate execution against plan (did we follow the plan?).
129
+ *
130
+ * @param plan - The original plan
131
+ * @param executedTools - List of tool names actually executed (in order)
132
+ * @returns Compliance report
133
+ */
134
+ validateExecution(plan: ToolPlan, executedTools: string[]): PlanComplianceReport;
135
+ /**
136
+ * Get all available task types that have predefined sequences.
137
+ */
138
+ getAvailableTaskTypes(): string[];
139
+ /**
140
+ * Get the raw step template for a task type (or undefined).
141
+ */
142
+ getStepsForType(taskType: string): readonly ToolPlanStep[] | undefined;
143
+ /**
144
+ * Customize steps based on context.
145
+ */
146
+ private customizeSteps;
147
+ /**
148
+ * Compute plan confidence based on task type and context completeness.
149
+ */
150
+ private computeConfidence;
151
+ /**
152
+ * Build reasoning string for the plan.
153
+ */
154
+ private buildReasoning;
155
+ /**
156
+ * Find the last index in an array matching a predicate.
157
+ */
158
+ private findLastIndex;
159
+ }
160
+ //# sourceMappingURL=tool-planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-planner.d.ts","sourceRoot":"","sources":["../src/tool-planner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,501 @@
1
+ /**
2
+ * @module tool-planner
3
+ * @description Tool Planning Layer — Plans optimal tool sequences before execution.
4
+ *
5
+ * Adds explicit planning between reasoning and execution:
6
+ * reasoning → plan → tool sequence → execute → verify
7
+ *
8
+ * Benefits:
9
+ * - Fewer unnecessary tool calls
10
+ * - Better first-attempt quality
11
+ * - Adapts based on task type and repo memory
12
+ */
13
+ // ─── Task Sequences ───
14
+ /** Pre-defined tool sequences by task type */
15
+ const TASK_SEQUENCES = {
16
+ debug: [
17
+ { tool: "grep", purpose: "Find error source/pattern in codebase" },
18
+ { tool: "file_read", purpose: "Read error source file + related files", dependsOn: [0] },
19
+ { tool: "file_edit", purpose: "Apply fix based on analysis", dependsOn: [1] },
20
+ { tool: "shell_exec", purpose: "Run tests to verify fix", dependsOn: [2] },
21
+ ],
22
+ feature: [
23
+ { tool: "file_read", purpose: "Understand existing code context" },
24
+ { tool: "glob", purpose: "Find related files and patterns", optional: true },
25
+ { tool: "file_write", purpose: "Create new files if needed" },
26
+ { tool: "file_edit", purpose: "Modify existing files", dependsOn: [0] },
27
+ { tool: "shell_exec", purpose: "Build + test", dependsOn: [3] },
28
+ ],
29
+ refactor: [
30
+ { tool: "grep", purpose: "Find all references to refactor target" },
31
+ { tool: "file_read", purpose: "Read all affected files", dependsOn: [0] },
32
+ { tool: "file_edit", purpose: "Apply refactoring changes", dependsOn: [1] },
33
+ { tool: "shell_exec", purpose: "Type check (tsc --noEmit)", dependsOn: [2] },
34
+ { tool: "shell_exec", purpose: "Run tests", dependsOn: [3] },
35
+ ],
36
+ test: [
37
+ { tool: "file_read", purpose: "Read source file to test" },
38
+ { tool: "glob", purpose: "Find existing test files/patterns" },
39
+ { tool: "file_write", purpose: "Create test file", dependsOn: [0, 1] },
40
+ { tool: "shell_exec", purpose: "Run new tests", dependsOn: [2] },
41
+ ],
42
+ security: [
43
+ { tool: "grep", purpose: "Find vulnerability patterns in codebase" },
44
+ { tool: "file_read", purpose: "Read potentially vulnerable code", dependsOn: [0] },
45
+ { tool: "file_edit", purpose: "Apply security fix", dependsOn: [1] },
46
+ { tool: "shell_exec", purpose: "Run security scan / tests", dependsOn: [2] },
47
+ { tool: "grep", purpose: "Verify fix removed vulnerability pattern", dependsOn: [3] },
48
+ ],
49
+ explain: [
50
+ { tool: "glob", purpose: "Discover project structure" },
51
+ { tool: "file_read", purpose: "Read target files", dependsOn: [0] },
52
+ { tool: "grep", purpose: "Trace dependencies and references", dependsOn: [1], optional: true },
53
+ ],
54
+ search: [
55
+ { tool: "glob", purpose: "Find files matching pattern" },
56
+ { tool: "grep", purpose: "Search file contents for pattern" },
57
+ { tool: "file_read", purpose: "Read matched files for detail", dependsOn: [0, 1], optional: true },
58
+ ],
59
+ config: [
60
+ { tool: "file_read", purpose: "Read current config file" },
61
+ { tool: "file_edit", purpose: "Modify configuration", dependsOn: [0] },
62
+ { tool: "shell_exec", purpose: "Validate config (build/lint)", dependsOn: [1] },
63
+ ],
64
+ deploy: [
65
+ { tool: "shell_exec", purpose: "Check git status for uncommitted changes" },
66
+ { tool: "shell_exec", purpose: "Run build to verify", dependsOn: [0] },
67
+ { tool: "shell_exec", purpose: "Run tests", dependsOn: [1] },
68
+ { tool: "shell_exec", purpose: "Execute deploy command", dependsOn: [2] },
69
+ ],
70
+ design: [
71
+ { tool: "file_read", purpose: "Read existing design tokens / component styles" },
72
+ { tool: "glob", purpose: "Find related UI components", optional: true },
73
+ { tool: "file_edit", purpose: "Update design tokens or styles", dependsOn: [0] },
74
+ { tool: "file_write", purpose: "Create new components if needed", dependsOn: [0] },
75
+ { tool: "shell_exec", purpose: "Build to verify no regressions", dependsOn: [2, 3] },
76
+ ],
77
+ infra: [
78
+ { tool: "file_read", purpose: "Read infrastructure config (docker, CI, etc.)" },
79
+ { tool: "grep", purpose: "Find related infrastructure references", optional: true },
80
+ { tool: "file_edit", purpose: "Modify infrastructure files", dependsOn: [0] },
81
+ { tool: "file_write", purpose: "Create new infra files if needed", dependsOn: [0] },
82
+ { tool: "shell_exec", purpose: "Validate config (dry-run, lint)", dependsOn: [2, 3] },
83
+ ],
84
+ performance: [
85
+ { tool: "grep", purpose: "Find performance bottleneck patterns" },
86
+ { tool: "file_read", purpose: "Read hot-path code", dependsOn: [0] },
87
+ { tool: "file_edit", purpose: "Apply optimization", dependsOn: [1] },
88
+ { tool: "shell_exec", purpose: "Run benchmarks / profile", dependsOn: [2] },
89
+ { tool: "shell_exec", purpose: "Run tests to ensure no regression", dependsOn: [3] },
90
+ ],
91
+ migration: [
92
+ { tool: "grep", purpose: "Find all references to old API/pattern" },
93
+ { tool: "file_read", purpose: "Read affected files", dependsOn: [0] },
94
+ { tool: "file_edit", purpose: "Apply migration changes", dependsOn: [1] },
95
+ { tool: "shell_exec", purpose: "Type check across codebase", dependsOn: [2] },
96
+ { tool: "shell_exec", purpose: "Run full test suite", dependsOn: [3] },
97
+ { tool: "grep", purpose: "Verify no old pattern remains", dependsOn: [4] },
98
+ ],
99
+ documentation: [
100
+ { tool: "file_read", purpose: "Read source code to document" },
101
+ { tool: "glob", purpose: "Find existing documentation files", optional: true },
102
+ { tool: "file_edit", purpose: "Update existing documentation", dependsOn: [0, 1] },
103
+ { tool: "file_write", purpose: "Create new documentation files", dependsOn: [0], optional: true },
104
+ ],
105
+ };
106
+ // ─── ToolPlanner ───
107
+ /**
108
+ * ToolPlanner — Plans optimal tool sequences before execution.
109
+ *
110
+ * Uses pre-defined task sequences combined with repo-specific profiles
111
+ * to produce an efficient, dependency-ordered plan.
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * const planner = new ToolPlanner();
116
+ * const plan = planner.planForTask("debug", {
117
+ * userMessage: "Fix the type error in agent-loop.ts",
118
+ * usesTypeScript: true,
119
+ * });
120
+ * console.log(planner.formatPlanHint(plan));
121
+ * ```
122
+ */
123
+ export class ToolPlanner {
124
+ /**
125
+ * Create a tool plan based on task classification.
126
+ *
127
+ * @param taskType - Task type from TaskClassifier (e.g., "debug", "feature")
128
+ * @param context - Optional planning context (user message, known files, etc.)
129
+ * @returns A ToolPlan with ordered steps, estimated calls, and confidence
130
+ */
131
+ planForTask(taskType, context) {
132
+ const baseSteps = TASK_SEQUENCES[taskType];
133
+ if (!baseSteps) {
134
+ // Unknown task type — return a generic exploration plan
135
+ return {
136
+ steps: [
137
+ { tool: "glob", purpose: "Discover project structure" },
138
+ { tool: "file_read", purpose: "Read relevant files" },
139
+ { tool: "grep", purpose: "Search for relevant patterns", optional: true },
140
+ ],
141
+ estimatedCalls: 3,
142
+ reasoning: `Unknown task type "${taskType}" — using generic exploration plan.`,
143
+ confidence: 0.3,
144
+ };
145
+ }
146
+ // Deep-copy base steps so we don't mutate the template
147
+ let steps = baseSteps.map((s) => ({ ...s }));
148
+ // Customize based on context
149
+ if (context) {
150
+ steps = this.customizeSteps(steps, taskType, context);
151
+ }
152
+ // Compute confidence based on context availability
153
+ const confidence = this.computeConfidence(taskType, context);
154
+ // Build reasoning
155
+ const reasoning = this.buildReasoning(taskType, steps, context);
156
+ return {
157
+ steps,
158
+ estimatedCalls: steps.filter((s) => !s.optional).length,
159
+ reasoning,
160
+ confidence,
161
+ };
162
+ }
163
+ /**
164
+ * Adapt plan based on repo-specific memory.
165
+ * E.g., if repo always needs tsc check, add it.
166
+ *
167
+ * @param plan - The base plan to adapt
168
+ * @param repoProfile - Repo-specific profile
169
+ * @returns Adapted plan with extra steps as needed
170
+ */
171
+ adaptPlan(plan, repoProfile) {
172
+ if (!repoProfile)
173
+ return plan;
174
+ const steps = [...plan.steps.map((s) => ({ ...s }))];
175
+ // Add always-read files as first step
176
+ if (repoProfile.alwaysReadFiles && repoProfile.alwaysReadFiles.length > 0) {
177
+ const hasInitialRead = steps.length > 0 && steps[0].tool === "file_read";
178
+ if (!hasInitialRead) {
179
+ steps.unshift({
180
+ tool: "file_read",
181
+ purpose: `Read required files: ${repoProfile.alwaysReadFiles.join(", ")}`,
182
+ expectedInput: repoProfile.alwaysReadFiles.join(", "),
183
+ });
184
+ // Shift all dependsOn indices by 1
185
+ for (let i = 1; i < steps.length; i++) {
186
+ if (steps[i].dependsOn) {
187
+ steps[i].dependsOn = steps[i].dependsOn.map((d) => d + 1);
188
+ }
189
+ }
190
+ }
191
+ }
192
+ // Add type check if always required and not present
193
+ if (repoProfile.alwaysTypeCheck) {
194
+ const hasTypeCheck = steps.some((s) => s.tool === "shell_exec" && s.purpose.toLowerCase().includes("type check"));
195
+ if (!hasTypeCheck) {
196
+ const lastEditIdx = this.findLastIndex(steps, (s) => s.tool === "file_edit" || s.tool === "file_write");
197
+ if (lastEditIdx >= 0) {
198
+ steps.splice(lastEditIdx + 1, 0, {
199
+ tool: "shell_exec",
200
+ purpose: "Type check (tsc --noEmit) — repo requires it",
201
+ dependsOn: [lastEditIdx],
202
+ });
203
+ }
204
+ }
205
+ }
206
+ // Add lint if always required and not present
207
+ if (repoProfile.alwaysLint) {
208
+ const hasLint = steps.some((s) => s.tool === "shell_exec" && s.purpose.toLowerCase().includes("lint"));
209
+ if (!hasLint) {
210
+ const lastStep = steps.length - 1;
211
+ steps.push({
212
+ tool: "shell_exec",
213
+ purpose: "Run lint — repo requires it",
214
+ dependsOn: [lastStep],
215
+ optional: true,
216
+ });
217
+ }
218
+ }
219
+ // Add test if always required and not present
220
+ if (repoProfile.alwaysTest) {
221
+ const hasTest = steps.some((s) => s.tool === "shell_exec" && s.purpose.toLowerCase().includes("test"));
222
+ if (!hasTest) {
223
+ const lastStep = steps.length - 1;
224
+ steps.push({
225
+ tool: "shell_exec",
226
+ purpose: "Run tests — repo requires it",
227
+ dependsOn: [lastStep],
228
+ });
229
+ }
230
+ }
231
+ // Add custom verify command
232
+ if (repoProfile.verifyCommand) {
233
+ const hasVerify = steps.some((s) => s.expectedInput === repoProfile.verifyCommand);
234
+ if (!hasVerify) {
235
+ const lastStep = steps.length - 1;
236
+ steps.push({
237
+ tool: "shell_exec",
238
+ purpose: `Run repo verify: ${repoProfile.verifyCommand}`,
239
+ expectedInput: repoProfile.verifyCommand,
240
+ dependsOn: [lastStep],
241
+ });
242
+ }
243
+ }
244
+ // Remove avoided tools
245
+ if (repoProfile.avoidTools && repoProfile.avoidTools.length > 0) {
246
+ const avoid = new Set(repoProfile.avoidTools);
247
+ const filtered = steps.filter((s) => !avoid.has(s.tool));
248
+ return {
249
+ ...plan,
250
+ steps: filtered,
251
+ estimatedCalls: filtered.filter((s) => !s.optional).length,
252
+ reasoning: plan.reasoning + ` (adapted for repo profile, avoided: ${repoProfile.avoidTools.join(", ")})`,
253
+ };
254
+ }
255
+ return {
256
+ ...plan,
257
+ steps,
258
+ estimatedCalls: steps.filter((s) => !s.optional).length,
259
+ reasoning: plan.reasoning + " (adapted for repo profile)",
260
+ };
261
+ }
262
+ /**
263
+ * Format plan as system prompt hint for the LLM.
264
+ *
265
+ * @param plan - The tool plan to format
266
+ * @returns Formatted string suitable for system prompt injection
267
+ */
268
+ formatPlanHint(plan) {
269
+ const lines = [
270
+ "<tool-plan>",
271
+ `Confidence: ${(plan.confidence * 100).toFixed(0)}%`,
272
+ `Estimated tool calls: ${plan.estimatedCalls}`,
273
+ "",
274
+ "Planned steps:",
275
+ ];
276
+ for (let i = 0; i < plan.steps.length; i++) {
277
+ const step = plan.steps[i];
278
+ const prefix = step.optional ? " (optional) " : " ";
279
+ const deps = step.dependsOn?.length
280
+ ? ` [after step ${step.dependsOn.map((d) => d + 1).join(", ")}]`
281
+ : "";
282
+ lines.push(`${prefix}${i + 1}. ${step.tool} — ${step.purpose}${deps}`);
283
+ if (step.fallback) {
284
+ lines.push(` Fallback: ${step.fallback}`);
285
+ }
286
+ }
287
+ lines.push("");
288
+ lines.push(`Reasoning: ${plan.reasoning}`);
289
+ lines.push("</tool-plan>");
290
+ return lines.join("\n");
291
+ }
292
+ /**
293
+ * Validate execution against plan (did we follow the plan?).
294
+ *
295
+ * @param plan - The original plan
296
+ * @param executedTools - List of tool names actually executed (in order)
297
+ * @returns Compliance report
298
+ */
299
+ validateExecution(plan, executedTools) {
300
+ const executedSteps = [];
301
+ const skippedSteps = [];
302
+ const unplannedTools = [];
303
+ // Track which plan steps were matched
304
+ const matched = new Set();
305
+ const plannedTools = plan.steps.map((s) => s.tool);
306
+ // For each executed tool, try to match it to a plan step
307
+ let planCursor = 0;
308
+ for (const tool of executedTools) {
309
+ let found = false;
310
+ // Search forward from cursor for a matching plan step
311
+ for (let i = planCursor; i < plan.steps.length; i++) {
312
+ if (!matched.has(i) && plan.steps[i].tool === tool) {
313
+ matched.add(i);
314
+ executedSteps.push(i);
315
+ planCursor = i + 1;
316
+ found = true;
317
+ break;
318
+ }
319
+ }
320
+ // If not found forward, search from beginning (out-of-order execution)
321
+ if (!found) {
322
+ for (let i = 0; i < planCursor; i++) {
323
+ if (!matched.has(i) && plan.steps[i].tool === tool) {
324
+ matched.add(i);
325
+ executedSteps.push(i);
326
+ found = true;
327
+ break;
328
+ }
329
+ }
330
+ }
331
+ if (!found) {
332
+ // Tool not in plan
333
+ if (!plannedTools.includes(tool)) {
334
+ unplannedTools.push(tool);
335
+ }
336
+ }
337
+ }
338
+ // Steps not matched are skipped
339
+ for (let i = 0; i < plan.steps.length; i++) {
340
+ if (!matched.has(i)) {
341
+ skippedSteps.push(i);
342
+ }
343
+ }
344
+ // Calculate compliance
345
+ const requiredSteps = plan.steps.filter((s) => !s.optional).length;
346
+ const requiredExecuted = executedSteps.filter((idx) => !plan.steps[idx].optional).length;
347
+ const complianceRatio = requiredSteps > 0 ? requiredExecuted / requiredSteps : 1;
348
+ const compliant = complianceRatio >= 0.7 && unplannedTools.length <= 2;
349
+ // Build summary
350
+ const summaryParts = [];
351
+ summaryParts.push(`${executedSteps.length}/${plan.steps.length} steps executed`);
352
+ if (skippedSteps.length > 0) {
353
+ const skippedNames = skippedSteps.map((i) => plan.steps[i].tool);
354
+ summaryParts.push(`skipped: ${skippedNames.join(", ")}`);
355
+ }
356
+ if (unplannedTools.length > 0) {
357
+ summaryParts.push(`unplanned: ${unplannedTools.join(", ")}`);
358
+ }
359
+ return {
360
+ compliant,
361
+ executedSteps,
362
+ skippedSteps,
363
+ unplannedTools,
364
+ complianceRatio,
365
+ summary: summaryParts.join("; "),
366
+ };
367
+ }
368
+ /**
369
+ * Get all available task types that have predefined sequences.
370
+ */
371
+ getAvailableTaskTypes() {
372
+ return Object.keys(TASK_SEQUENCES);
373
+ }
374
+ /**
375
+ * Get the raw step template for a task type (or undefined).
376
+ */
377
+ getStepsForType(taskType) {
378
+ const steps = TASK_SEQUENCES[taskType];
379
+ return steps ? steps.map((s) => ({ ...s })) : undefined;
380
+ }
381
+ // ─── Private ───
382
+ /**
383
+ * Customize steps based on context.
384
+ */
385
+ customizeSteps(steps, taskType, context) {
386
+ const result = [...steps];
387
+ // If specific files are known, add expected input hints
388
+ if (context.knownFiles && context.knownFiles.length > 0) {
389
+ for (const step of result) {
390
+ if (step.tool === "file_read" && !step.expectedInput) {
391
+ step.expectedInput = context.knownFiles.join(", ");
392
+ }
393
+ }
394
+ }
395
+ // If project has no tests, make test steps optional
396
+ if (context.hasTests === false) {
397
+ for (const step of result) {
398
+ if (step.tool === "shell_exec" &&
399
+ step.purpose.toLowerCase().includes("test")) {
400
+ step.optional = true;
401
+ step.fallback = "Skip tests — project has no test setup";
402
+ }
403
+ }
404
+ }
405
+ // If project uses TypeScript, add type check hint to shell_exec steps
406
+ if (context.usesTypeScript) {
407
+ const hasTypeCheck = result.some((s) => s.tool === "shell_exec" && s.purpose.toLowerCase().includes("type check"));
408
+ if (!hasTypeCheck && (taskType === "feature" || taskType === "refactor" || taskType === "migration")) {
409
+ const lastEditIdx = this.findLastIndex(result, (s) => s.tool === "file_edit" || s.tool === "file_write");
410
+ if (lastEditIdx >= 0) {
411
+ result.splice(lastEditIdx + 1, 0, {
412
+ tool: "shell_exec",
413
+ purpose: "Type check (tsc --noEmit)",
414
+ dependsOn: [lastEditIdx],
415
+ });
416
+ }
417
+ }
418
+ }
419
+ // Add fallback hints for key steps
420
+ for (const step of result) {
421
+ if (!step.fallback) {
422
+ if (step.tool === "grep") {
423
+ step.fallback = "Try glob or file_read with broader pattern";
424
+ }
425
+ else if (step.tool === "file_edit") {
426
+ step.fallback = "If edit fails, try file_write to replace entire file";
427
+ }
428
+ else if (step.tool === "shell_exec") {
429
+ step.fallback = "If command fails, check error output and retry with fix";
430
+ }
431
+ }
432
+ }
433
+ return result;
434
+ }
435
+ /**
436
+ * Compute plan confidence based on task type and context completeness.
437
+ */
438
+ computeConfidence(taskType, context) {
439
+ let confidence = 0.6; // Base confidence for having a known task type
440
+ if (!context)
441
+ return confidence;
442
+ // Boost for known files
443
+ if (context.knownFiles && context.knownFiles.length > 0) {
444
+ confidence += 0.1;
445
+ }
446
+ // Boost for known language/framework
447
+ if (context.language) {
448
+ confidence += 0.05;
449
+ }
450
+ // Boost for test/lint awareness
451
+ if (context.hasTests !== undefined) {
452
+ confidence += 0.05;
453
+ }
454
+ if (context.hasLint !== undefined) {
455
+ confidence += 0.05;
456
+ }
457
+ // Boost for TypeScript projects (better tooling support)
458
+ if (context.usesTypeScript) {
459
+ confidence += 0.05;
460
+ }
461
+ // Context hints boost
462
+ if (context.contextHints && context.contextHints.length > 0) {
463
+ confidence += Math.min(context.contextHints.length * 0.03, 0.1);
464
+ }
465
+ // Task-specific confidence adjustments
466
+ const highConfidenceTasks = ["debug", "test", "search", "config"];
467
+ if (highConfidenceTasks.includes(taskType)) {
468
+ confidence += 0.05;
469
+ }
470
+ return Math.min(confidence, 0.95);
471
+ }
472
+ /**
473
+ * Build reasoning string for the plan.
474
+ */
475
+ buildReasoning(taskType, steps, context) {
476
+ const parts = [];
477
+ parts.push(`Task type: ${taskType}`);
478
+ parts.push(`${steps.length} steps planned (${steps.filter((s) => s.optional).length} optional)`);
479
+ if (context?.knownFiles?.length) {
480
+ parts.push(`targeting ${context.knownFiles.length} known file(s)`);
481
+ }
482
+ if (context?.usesTypeScript) {
483
+ parts.push("TypeScript project — includes type checking");
484
+ }
485
+ if (context?.hasTests === false) {
486
+ parts.push("no test setup detected — test steps optional");
487
+ }
488
+ return parts.join("; ") + ".";
489
+ }
490
+ /**
491
+ * Find the last index in an array matching a predicate.
492
+ */
493
+ findLastIndex(arr, predicate) {
494
+ for (let i = arr.length - 1; i >= 0; i--) {
495
+ if (predicate(arr[i]))
496
+ return i;
497
+ }
498
+ return -1;
499
+ }
500
+ }
501
+ //# sourceMappingURL=tool-planner.js.map