muonroi-cli 1.8.5 → 1.9.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 (206) hide show
  1. package/dist/packages/agent-harness-core/src/event-filter.js +11 -0
  2. package/dist/packages/agent-harness-core/src/event-redact.js +7 -0
  3. package/dist/packages/agent-harness-core/src/event-tee.d.ts +20 -4
  4. package/dist/packages/agent-harness-core/src/event-tee.js +32 -5
  5. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +14 -0
  6. package/dist/packages/agent-harness-core/src/mcp-server.js +86 -10
  7. package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
  8. package/dist/packages/agent-harness-core/src/protocol.d.ts +24 -2
  9. package/dist/src/agent-harness/mock-model.d.ts +10 -0
  10. package/dist/src/agent-harness/mock-model.js +6 -2
  11. package/dist/src/chat/chat-keychain.d.ts +7 -12
  12. package/dist/src/chat/chat-keychain.js +19 -86
  13. package/dist/src/cli/keys.d.ts +8 -45
  14. package/dist/src/cli/keys.js +18 -324
  15. package/dist/src/council/clarifier.d.ts +4 -2
  16. package/dist/src/council/clarifier.js +158 -36
  17. package/dist/src/council/debate-planner.js +3 -2
  18. package/dist/src/council/debate.js +59 -5
  19. package/dist/src/council/index.d.ts +23 -0
  20. package/dist/src/council/index.js +37 -2
  21. package/dist/src/council/llm.d.ts +62 -0
  22. package/dist/src/council/llm.js +123 -23
  23. package/dist/src/council/panel-select.js +13 -3
  24. package/dist/src/council/planner.js +17 -0
  25. package/dist/src/council/preflight.d.ts +10 -0
  26. package/dist/src/council/preflight.js +36 -0
  27. package/dist/src/council/prompts.d.ts +9 -1
  28. package/dist/src/council/prompts.js +23 -6
  29. package/dist/src/council/types.d.ts +10 -0
  30. package/dist/src/ee/auth.d.ts +19 -0
  31. package/dist/src/ee/auth.js +39 -0
  32. package/dist/src/ee/client.js +28 -3
  33. package/dist/src/ee/ee-onboarding.js +6 -26
  34. package/dist/src/flow/compaction/compress.d.ts +2 -2
  35. package/dist/src/flow/compaction/compress.js +21 -8
  36. package/dist/src/flow/compaction/extract.d.ts +3 -3
  37. package/dist/src/flow/compaction/extract.js +6 -6
  38. package/dist/src/flow/compaction/index.d.ts +2 -1
  39. package/dist/src/flow/compaction/index.js +29 -3
  40. package/dist/src/flow/compaction/progress.d.ts +35 -0
  41. package/dist/src/flow/compaction/progress.js +35 -0
  42. package/dist/src/generated/version.d.ts +1 -1
  43. package/dist/src/generated/version.js +1 -1
  44. package/dist/src/gsd/flags.d.ts +11 -0
  45. package/dist/src/gsd/flags.js +19 -0
  46. package/dist/src/gsd/plan-council.js +104 -72
  47. package/dist/src/gsd/verdict-schema.d.ts +1 -1
  48. package/dist/src/headless/council-answers.js +4 -0
  49. package/dist/src/index.js +129 -260
  50. package/dist/src/lsp/builtins.js +3 -1
  51. package/dist/src/lsp/manager.d.ts +5 -1
  52. package/dist/src/lsp/manager.js +249 -3
  53. package/dist/src/lsp/npm-cache.d.ts +11 -1
  54. package/dist/src/lsp/npm-cache.js +17 -1
  55. package/dist/src/lsp/runtime.d.ts +6 -1
  56. package/dist/src/lsp/runtime.js +17 -1
  57. package/dist/src/lsp/types.d.ts +83 -1
  58. package/dist/src/lsp/types.js +10 -0
  59. package/dist/src/mcp/client-pool.js +43 -15
  60. package/dist/src/mcp/lsp-tools.d.ts +5 -1
  61. package/dist/src/mcp/lsp-tools.js +93 -2
  62. package/dist/src/mcp/mcp-keychain.d.ts +3 -5
  63. package/dist/src/mcp/mcp-keychain.js +9 -49
  64. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  65. package/dist/src/mcp/setup-guide-text.js +22 -2
  66. package/dist/src/mcp/tools-server.d.ts +10 -0
  67. package/dist/src/mcp/tools-server.js +10 -2
  68. package/dist/src/models/catalog.json +19 -19
  69. package/dist/src/orchestrator/ask-user.d.ts +61 -0
  70. package/dist/src/orchestrator/ask-user.js +65 -0
  71. package/dist/src/orchestrator/compaction.d.ts +2 -3
  72. package/dist/src/orchestrator/compaction.js +8 -8
  73. package/dist/src/orchestrator/council-manager.js +9 -8
  74. package/dist/src/orchestrator/council-request.d.ts +49 -0
  75. package/dist/src/orchestrator/council-request.js +62 -0
  76. package/dist/src/orchestrator/interactive-pause.d.ts +26 -0
  77. package/dist/src/orchestrator/interactive-pause.js +36 -0
  78. package/dist/src/orchestrator/message-processor.d.ts +4 -0
  79. package/dist/src/orchestrator/message-processor.js +26 -8
  80. package/dist/src/orchestrator/orchestrator.d.ts +25 -0
  81. package/dist/src/orchestrator/orchestrator.js +204 -50
  82. package/dist/src/orchestrator/preprocessor.js +2 -2
  83. package/dist/src/orchestrator/safety-askcard.d.ts +1 -1
  84. package/dist/src/orchestrator/safety-askcard.js +5 -2
  85. package/dist/src/orchestrator/safety-intercept.d.ts +5 -0
  86. package/dist/src/orchestrator/safety-intercept.js +7 -0
  87. package/dist/src/orchestrator/stall-watchdog.d.ts +8 -1
  88. package/dist/src/orchestrator/stall-watchdog.js +24 -3
  89. package/dist/src/orchestrator/stream-runner.d.ts +13 -3
  90. package/dist/src/orchestrator/stream-runner.js +54 -21
  91. package/dist/src/orchestrator/tool-engine.d.ts +19 -0
  92. package/dist/src/orchestrator/tool-engine.js +241 -25
  93. package/dist/src/orchestrator/turn-watchdog.d.ts +7 -0
  94. package/dist/src/orchestrator/turn-watchdog.js +38 -9
  95. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  96. package/dist/src/pil/agent-operating-contract.js +6 -4
  97. package/dist/src/pil/discovery.d.ts +1 -1
  98. package/dist/src/pil/discovery.js +2 -2
  99. package/dist/src/pil/layer1_5-complexity-size.d.ts +7 -0
  100. package/dist/src/pil/layer1_5-complexity-size.js +31 -5
  101. package/dist/src/pil/llm-classify.d.ts +78 -3
  102. package/dist/src/pil/llm-classify.js +351 -111
  103. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  104. package/dist/src/pil/native-capabilities-workbook.js +7 -0
  105. package/dist/src/pil/pipeline.js +2 -0
  106. package/dist/src/pil/repo-grounding-probe.d.ts +15 -0
  107. package/dist/src/pil/repo-grounding-probe.js +136 -0
  108. package/dist/src/pil/repo-structure-hints.d.ts +7 -0
  109. package/dist/src/pil/repo-structure-hints.js +45 -0
  110. package/dist/src/product-loop/artifact-io.js +4 -0
  111. package/dist/src/product-loop/criteria-seed.d.ts +51 -0
  112. package/dist/src/product-loop/criteria-seed.js +200 -0
  113. package/dist/src/product-loop/discovery-interview.d.ts +9 -0
  114. package/dist/src/product-loop/discovery-interview.js +37 -18
  115. package/dist/src/product-loop/discovery-recommender.js +2 -1
  116. package/dist/src/product-loop/discovery-schema.js +14 -1
  117. package/dist/src/product-loop/discovery-triage.d.ts +23 -0
  118. package/dist/src/product-loop/discovery-triage.js +109 -0
  119. package/dist/src/product-loop/gather.js +150 -2
  120. package/dist/src/product-loop/index.js +7 -0
  121. package/dist/src/product-loop/loop-driver.js +21 -8
  122. package/dist/src/product-loop/phase-plan.d.ts +16 -0
  123. package/dist/src/product-loop/phase-plan.js +42 -4
  124. package/dist/src/product-loop/phase-rituals.d.ts +3 -0
  125. package/dist/src/product-loop/phase-rituals.js +8 -3
  126. package/dist/src/product-loop/phase-runner.js +30 -11
  127. package/dist/src/product-loop/plan-adherence-review.d.ts +26 -0
  128. package/dist/src/product-loop/plan-adherence-review.js +144 -0
  129. package/dist/src/product-loop/sprint-runner.d.ts +62 -0
  130. package/dist/src/product-loop/sprint-runner.js +309 -8
  131. package/dist/src/product-loop/types.d.ts +25 -0
  132. package/dist/src/providers/anthropic.d.ts +9 -8
  133. package/dist/src/providers/anthropic.js +13 -47
  134. package/dist/src/providers/auth/grok-oauth.d.ts +1 -0
  135. package/dist/src/providers/auth/grok-oauth.js +30 -5
  136. package/dist/src/providers/auth/openai-oauth.d.ts +1 -0
  137. package/dist/src/providers/auth/openai-oauth.js +14 -0
  138. package/dist/src/providers/auth/token-store.d.ts +9 -9
  139. package/dist/src/providers/auth/token-store.js +8 -70
  140. package/dist/src/providers/auth/types.d.ts +8 -0
  141. package/dist/src/providers/env-store.d.ts +17 -0
  142. package/dist/src/providers/env-store.js +228 -0
  143. package/dist/src/providers/keychain.d.ts +21 -17
  144. package/dist/src/providers/keychain.js +124 -135
  145. package/dist/src/providers/runtime.d.ts +24 -9
  146. package/dist/src/providers/runtime.js +48 -37
  147. package/dist/src/providers/strategies/thinking-mode.js +9 -1
  148. package/dist/src/providers/strategies/xai.strategy.js +27 -0
  149. package/dist/src/providers/warm.d.ts +65 -0
  150. package/dist/src/providers/warm.js +145 -0
  151. package/dist/src/self-qa/agentic-loop.js +3 -2
  152. package/dist/src/storage/transcript.js +56 -2
  153. package/dist/src/tools/git-safety.d.ts +19 -0
  154. package/dist/src/tools/git-safety.js +168 -0
  155. package/dist/src/tools/native-tools.d.ts +1 -1
  156. package/dist/src/tools/native-tools.js +76 -1
  157. package/dist/src/tools/registry.d.ts +17 -0
  158. package/dist/src/tools/registry.js +116 -1
  159. package/dist/src/types/index.d.ts +29 -1
  160. package/dist/src/ui/app.js +67 -4
  161. package/dist/src/ui/components/agent-rail-activities.d.ts +26 -0
  162. package/dist/src/ui/components/agent-rail-activities.js +47 -0
  163. package/dist/src/ui/components/compact-progress-card.d.ts +24 -0
  164. package/dist/src/ui/components/compact-progress-card.js +42 -0
  165. package/dist/src/ui/components/council-phase-timeline.js +17 -2
  166. package/dist/src/ui/components/council-question-card.js +1 -0
  167. package/dist/src/ui/components/message-view.d.ts +15 -0
  168. package/dist/src/ui/components/message-view.js +50 -1
  169. package/dist/src/ui/components/tool-group.d.ts +15 -3
  170. package/dist/src/ui/components/tool-group.js +69 -11
  171. package/dist/src/ui/containers/modals-layer.d.ts +2 -1
  172. package/dist/src/ui/containers/modals-layer.js +2 -2
  173. package/dist/src/ui/council-harness-event.d.ts +57 -0
  174. package/dist/src/ui/council-harness-event.js +46 -0
  175. package/dist/src/ui/heartbeat-debug.d.ts +29 -0
  176. package/dist/src/ui/heartbeat-debug.js +45 -0
  177. package/dist/src/ui/modals/api-key-modal.js +1 -1
  178. package/dist/src/ui/modals/model-picker-modal.d.ts +8 -18
  179. package/dist/src/ui/modals/model-picker-modal.js +8 -10
  180. package/dist/src/ui/slash/ee.js +81 -0
  181. package/dist/src/ui/slash/menu-items.js +11 -2
  182. package/dist/src/ui/use-app-logic.js +354 -224
  183. package/dist/src/ui/utils/agent-activities.d.ts +39 -0
  184. package/dist/src/ui/utils/agent-activities.js +96 -0
  185. package/dist/src/ui/utils/group-tool-entries.d.ts +26 -0
  186. package/dist/src/ui/utils/group-tool-entries.js +111 -0
  187. package/dist/src/ui/utils/tool-summary.d.ts +21 -0
  188. package/dist/src/ui/utils/tool-summary.js +91 -0
  189. package/dist/src/utils/event-loop-monitor.d.ts +85 -0
  190. package/dist/src/utils/event-loop-monitor.js +107 -0
  191. package/dist/src/utils/llm-deadline.d.ts +14 -0
  192. package/dist/src/utils/llm-deadline.js +19 -0
  193. package/dist/src/utils/loop-profiler.d.ts +102 -0
  194. package/dist/src/utils/loop-profiler.js +202 -0
  195. package/dist/src/utils/settings.d.ts +27 -0
  196. package/dist/src/utils/settings.js +38 -2
  197. package/dist/src/utils/side-question.d.ts +1 -2
  198. package/dist/src/utils/side-question.js +2 -2
  199. package/dist/src/verify/entrypoint.js +51 -16
  200. package/dist/src/verify/orchestrator.d.ts +1 -1
  201. package/dist/src/verify/orchestrator.js +20 -3
  202. package/package.json +1 -2
  203. package/dist/src/cli/bw-vault.d.ts +0 -55
  204. package/dist/src/cli/bw-vault.js +0 -133
  205. package/dist/src/mcp/ee-tools.d.ts +0 -46
  206. package/dist/src/mcp/ee-tools.js +0 -194
@@ -37,7 +37,7 @@
37
37
  * one imperative line targeting that phase's most damaging failure mode. Kept
38
38
  * tight (primacy matters more than detail; tokens are the cost).
39
39
  */
40
- export declare const AGENT_OPERATING_CONTRACT = "[AGENT OPERATING CONTRACT \u2014 read first; applies to every step]\n\n1. BEFORE ACTING: do only what was asked. Never assume scope or facts \u2014 if ambiguous, ask or use defaults; never invent requirements. RESEARCH FIRST: explore code (read/grep) and recall EE brain before editing. RECALL FIRST: ee.query in unfamiliar areas to surface past lessons.\n2. READING: base statements on what you read/ran THIS turn. Do not infer contents of files you did not open.\n3. EXECUTING: smallest correct change; never widen scope or mask failures (no `|| true`, skipped tests, or swallowed catch).\n4. WHEN UNSURE: verify and cross-check BEFORE concluding. Reading code is not proof \u2014 reproduce the bug.\n5. REPORTING: answer ONLY what was asked. Every fact or file:line MUST come from this turn; else label \"unverified\"; do not guess. Synthesize evidence gracefully \u2014 do NOT dump massive verbatim tool outputs into the final answer. Cite concise file:line references. Never claim a build/test ran, or describe edits, you did not actually do this turn; if a check can't run, fix it or say so \u2014 don't imply success.\n\n6. LANGUAGE: Reply in user's detected language for final output. Internal reasoning, tools, and code remain in English.\n\n7. ANTI-M\u00D9 / COMPACTION: On compaction, emit PRESERVE_FULL_CONTEXT (veto) or KEEP_TOOL_IDS (from stub id=) to protect results. Use ee_query with \"tool-artifact id=XXX\" to re-hydrate. Self-check via EE checkpoints. Use 'compact' tool near limits.\n\n8. GIT SAFETY: never push on red \u2014 run the check, await its result in a SEPARATE step, confirm 0 failures, then push. Never `git add -A`/`commit -a`; stage explicitly so secrets (.env, .muonroi-cli/, keys) aren't committed. Never `--no-verify`.\n\n9. VERIFICATION: when finishing a task, ALWAYS self-verify your work. Use the `selfverify_*` native tools (start/status/result) to run the QA harness which drives the live TUI like a real user to catch regressions that unit tests can't.\n\n[END CONTRACT \u2014 instructions follow]";
40
+ export declare const AGENT_OPERATING_CONTRACT = "[AGENT OPERATING CONTRACT \u2014 read first; applies to every step]\n\n1. BEFORE ACTING: do only what was asked. Never assume scope or facts \u2014 if ambiguous, ask or use defaults; never invent requirements. RESEARCH FIRST: explore code (read/grep) and recall the EE brain (ee.query in unfamiliar areas) before editing.\n2. READING: base statements on what you read/ran THIS turn. Do not infer contents of files you did not open.\n3. EXECUTING: smallest correct change; never widen scope or mask failures (no `|| true`, skipped tests, or swallowed catch).\n4. WHEN UNSURE: verify and cross-check BEFORE concluding. Reading code is not proof \u2014 reproduce the bug.\n5. REPORTING: answer ONLY what was asked. Every fact or file:line MUST come from this turn; else label \"unverified\"; do not guess. Don't dump verbatim tool outputs \u2014 cite concise file:line. Never claim a build/test ran, or edits you did not actually do this turn; if a check can't run, fix it or say so.\n\n6. LANGUAGE: reply in the user's detected language; internal reasoning, tools, and code stay English.\n\n7. ANTI-M\u00D9/COMPACTION: on compaction emit PRESERVE_FULL_CONTEXT (veto) or KEEP_TOOL_IDS (from stub id=) to protect results; re-hydrate via ee_query \"tool-artifact id=XXX\". Use 'compact' near limits.\n\n8. GIT SAFETY: never push on red \u2014 run the check, await its result in a SEPARATE step, confirm 0 failures, then push. Never `git add -A`/`commit -a`; stage explicitly so secrets (.env, .muonroi-cli/, keys) aren't committed. Never `--no-verify`.\n\n9. VERIFICATION: when finishing a task, ALWAYS self-verify your work. Use the `selfverify_*` native tools (start/status/result) to run the QA harness which drives the live TUI like a real user to catch regressions that unit tests can't.\n\n10. COUNCIL/ASK: call `convene_council` for high-stakes/conflicting calls \u2014 its conclusion returns as the tool result; then YOU decide. In impl discussion you MAY confirm via `ask_user` before building, else keep going.\n\n[END CONTRACT \u2014 instructions follow]";
41
41
  export interface ContractSectionOptions {
42
42
  /** Chitchat turns carry no tools and make no factual claims — skip the contract. */
43
43
  chitchat?: boolean;
@@ -39,20 +39,22 @@
39
39
  */
40
40
  export const AGENT_OPERATING_CONTRACT = `[AGENT OPERATING CONTRACT — read first; applies to every step]
41
41
 
42
- 1. BEFORE ACTING: do only what was asked. Never assume scope or facts — if ambiguous, ask or use defaults; never invent requirements. RESEARCH FIRST: explore code (read/grep) and recall EE brain before editing. RECALL FIRST: ee.query in unfamiliar areas to surface past lessons.
42
+ 1. BEFORE ACTING: do only what was asked. Never assume scope or facts — if ambiguous, ask or use defaults; never invent requirements. RESEARCH FIRST: explore code (read/grep) and recall the EE brain (ee.query in unfamiliar areas) before editing.
43
43
  2. READING: base statements on what you read/ran THIS turn. Do not infer contents of files you did not open.
44
44
  3. EXECUTING: smallest correct change; never widen scope or mask failures (no \`|| true\`, skipped tests, or swallowed catch).
45
45
  4. WHEN UNSURE: verify and cross-check BEFORE concluding. Reading code is not proof — reproduce the bug.
46
- 5. REPORTING: answer ONLY what was asked. Every fact or file:line MUST come from this turn; else label "unverified"; do not guess. Synthesize evidence gracefully — do NOT dump massive verbatim tool outputs into the final answer. Cite concise file:line references. Never claim a build/test ran, or describe edits, you did not actually do this turn; if a check can't run, fix it or say so — don't imply success.
46
+ 5. REPORTING: answer ONLY what was asked. Every fact or file:line MUST come from this turn; else label "unverified"; do not guess. Don't dump verbatim tool outputs cite concise file:line. Never claim a build/test ran, or edits you did not actually do this turn; if a check can't run, fix it or say so.
47
47
 
48
- 6. LANGUAGE: Reply in user's detected language for final output. Internal reasoning, tools, and code remain in English.
48
+ 6. LANGUAGE: reply in the user's detected language; internal reasoning, tools, and code stay English.
49
49
 
50
- 7. ANTI-MÙ / COMPACTION: On compaction, emit PRESERVE_FULL_CONTEXT (veto) or KEEP_TOOL_IDS (from stub id=) to protect results. Use ee_query with "tool-artifact id=XXX" to re-hydrate. Self-check via EE checkpoints. Use 'compact' tool near limits.
50
+ 7. ANTI-MÙ/COMPACTION: on compaction emit PRESERVE_FULL_CONTEXT (veto) or KEEP_TOOL_IDS (from stub id=) to protect results; re-hydrate via ee_query "tool-artifact id=XXX". Use 'compact' near limits.
51
51
 
52
52
  8. GIT SAFETY: never push on red — run the check, await its result in a SEPARATE step, confirm 0 failures, then push. Never \`git add -A\`/\`commit -a\`; stage explicitly so secrets (.env, .muonroi-cli/, keys) aren't committed. Never \`--no-verify\`.
53
53
 
54
54
  9. VERIFICATION: when finishing a task, ALWAYS self-verify your work. Use the \`selfverify_*\` native tools (start/status/result) to run the QA harness which drives the live TUI like a real user to catch regressions that unit tests can't.
55
55
 
56
+ 10. COUNCIL/ASK: call \`convene_council\` for high-stakes/conflicting calls — its conclusion returns as the tool result; then YOU decide. In impl discussion you MAY confirm via \`ask_user\` before building, else keep going.
57
+
56
58
  [END CONTRACT — instructions follow]`;
57
59
  /**
58
60
  * Build the contract block for insertion at the front of the system prompt.
@@ -15,4 +15,4 @@ export declare function runDiscovery(raw: string, l1: L1Result, cwd: string, han
15
15
  * exact ModelCard[] it wants shown — full control over questions, options,
16
16
  * option kinds, and cancel/adjust markers.
17
17
  */
18
- export declare function createModelClarificationProposer(providerFactory: any, modelId: string): ModelClarificationProposer;
18
+ export declare function createModelClarificationProposer(modelId: string): ModelClarificationProposer;
@@ -234,13 +234,13 @@ async function proposeModelCards(proposer, raw, l1, projectContext, recentTurnsS
234
234
  * exact ModelCard[] it wants shown — full control over questions, options,
235
235
  * option kinds, and cancel/adjust markers.
236
236
  */
237
- export function createModelClarificationProposer(providerFactory, modelId) {
237
+ export function createModelClarificationProposer(modelId) {
238
238
  return async (input) => {
239
239
  // process.stderr.write(`[discovery] createModelClarificationProposer CALLED!\n`);
240
240
  try {
241
241
  const { resolveModelRuntime } = await import("../providers/runtime.js");
242
242
  const { generateText } = await import("ai");
243
- const runtime = resolveModelRuntime(providerFactory, modelId);
243
+ const runtime = resolveModelRuntime(modelId);
244
244
  const contextStr = input.additionalContext
245
245
  ? `\nCurrent CLI enrichment / context (use this to decide what is already known):\n${input.additionalContext}`
246
246
  : "";
@@ -11,13 +11,20 @@
11
11
  * "Layer 1.5 complexity-size (4C)"). Do NOT alter weights without re-running the
12
12
  * baseline harness regression.
13
13
  */
14
+ import type { RepoStructureHint } from "./repo-structure-hints.js";
14
15
  export interface ComplexitySizeInput {
15
16
  rawText: string;
16
17
  taskType: string;
18
+ repoHints?: RepoStructureHint[];
17
19
  }
18
20
  export interface ComplexitySizeResult {
19
21
  size: "small" | "medium" | "large";
20
22
  score: number;
21
23
  features: Record<string, number | boolean>;
22
24
  }
25
+ export declare function extractPathTokens(rawText: string): string[];
26
+ export declare function scoreRepoGrounding(paths: string[], hints: RepoStructureHint[]): {
27
+ score: number;
28
+ hits: number;
29
+ };
23
30
  export declare function scoreComplexitySize(input: ComplexitySizeInput): ComplexitySizeResult;
@@ -62,14 +62,32 @@ function effectiveLen(rawText, taskType) {
62
62
  // ---------------------------------------------------------------------------
63
63
  // Path token counter — counts DISTINCT path-like tokens.
64
64
  // ---------------------------------------------------------------------------
65
- function countDistinctPaths(rawText) {
65
+ export function extractPathTokens(rawText) {
66
66
  const matches = rawText.match(PATH_TOKEN_RE);
67
67
  if (!matches)
68
- return 0;
68
+ return [];
69
69
  const set = new Set();
70
70
  for (const m of matches)
71
71
  set.add(m.toLowerCase());
72
- return set.size;
72
+ return [...set];
73
+ }
74
+ export function scoreRepoGrounding(paths, hints) {
75
+ if (paths.length === 0 || hints.length === 0)
76
+ return { score: 0, hits: 0 };
77
+ const hinted = new Map(hints.map((hint) => [hint.path.toLowerCase(), hint]));
78
+ let score = 0;
79
+ let hits = 0;
80
+ for (const path of paths) {
81
+ const hint = hinted.get(path);
82
+ if (!hint)
83
+ continue;
84
+ hits += 1;
85
+ if (hint.lineCount >= 5000)
86
+ score = Math.max(score, 4);
87
+ else if (hint.lineCount >= 2000)
88
+ score = Math.max(score, 2);
89
+ }
90
+ return { score, hits };
73
91
  }
74
92
  // ---------------------------------------------------------------------------
75
93
  // Main: scoreComplexitySize
@@ -77,6 +95,7 @@ function countDistinctPaths(rawText) {
77
95
  export function scoreComplexitySize(input) {
78
96
  const rawText = input.rawText ?? "";
79
97
  const taskType = input.taskType ?? "general";
98
+ const repoHints = input.repoHints ?? [];
80
99
  // 1. Length score (debug + stack-trace gets mitigation).
81
100
  // CONTEXT-locked thresholds are <60 / >240. We use <80 for the "small" knee
82
101
  // because the baseline-2 prompt "đổi default --max-tool-rounds từ 100 →
@@ -102,13 +121,18 @@ export function scoreComplexitySize(input) {
102
121
  // baseline-2 "đổi default ... trong src/orchestrator/cli-args.ts")
103
122
  // - zero paths is neutral (vagueness is handled by `vaguenessAmplifier`)
104
123
  // - ≥3 paths is multi-file work, push toward large
105
- const pathCount = countDistinctPaths(rawText);
124
+ const distinctPaths = extractPathTokens(rawText);
125
+ const pathCount = distinctPaths.length;
106
126
  let pathScore = 0;
107
127
  if (pathCount === 1)
108
128
  pathScore = -1;
109
129
  else if (pathCount >= 3)
110
130
  pathScore = 2;
111
131
  // 0 or 2 → 0 (neutral)
132
+ // 4.5 Repo-structure grounding probe. Cheap deterministic lookup against the
133
+ // checked-in REPO_DEEP_MAP index: monolith roots like src/ui/app.tsx should
134
+ // not size the same as a narrow leaf module when both appear as one-path asks.
135
+ const repoGrounding = scoreRepoGrounding(distinctPaths, repoHints);
112
136
  // 5. Question form score.
113
137
  const trimmed = rawText.trim();
114
138
  const isQuestion = QUESTION_START_RE.test(trimmed) || trimmed.endsWith("?");
@@ -123,7 +147,7 @@ export function scoreComplexitySize(input) {
123
147
  // "improve X" / "clean up Y" without targets is the canonical wandering shape.
124
148
  const vaguenessAmplifier = sweepCount > 0 && pathCount === 0 ? 4 : 0;
125
149
  // Total score → bucket.
126
- const score = lenScore + sweepScore + heavyScore + pathScore + questionScore + vaguenessAmplifier;
150
+ const score = lenScore + sweepScore + heavyScore + pathScore + repoGrounding.score + questionScore + vaguenessAmplifier;
127
151
  let size;
128
152
  if (score <= -1)
129
153
  size = "small";
@@ -142,6 +166,8 @@ export function scoreComplexitySize(input) {
142
166
  heavyScore,
143
167
  pathCount,
144
168
  pathScore,
169
+ repoGroundingHits: repoGrounding.hits,
170
+ repoGroundingScore: repoGrounding.score,
145
171
  isQuestion,
146
172
  questionScore,
147
173
  isImperative,
@@ -1,4 +1,4 @@
1
- import type { ProviderFactory } from "../providers/runtime.js";
1
+ import type { ProviderId } from "../providers/types.js";
2
2
  import type { OutputStyle, TaskType } from "./types.js";
3
3
  /**
4
4
  * What the user wants the turn to PRODUCE — decided by the model (Phase 2b) so
@@ -92,6 +92,56 @@ export interface LlmClassifyOptions {
92
92
  signal?: AbortSignal;
93
93
  }
94
94
  export type LlmClassifyFn = (prompt: string, opts?: LlmClassifyOptions) => Promise<LlmClassifyResult | null>;
95
+ /**
96
+ * Factory-level options for `createLlmClassifier` (distinct from the per-call
97
+ * `LlmClassifyOptions`). Chosen once when the closure is built.
98
+ */
99
+ export interface CreateClassifierOptions {
100
+ /**
101
+ * Route the throwaway classify to the provider's fast tier when one exists
102
+ * (mirrors `classifySubSessionAction`). Same-provider only, so the already-
103
+ * bound factory/key still works. A no-op when the provider exposes no
104
+ * routable fast model (e.g. xai). Zero-hardcode: the fast id comes from
105
+ * `getRoutedModelByTier`, not a literal. Cheap — safe on every turn.
106
+ */
107
+ routeFastTier?: boolean;
108
+ /**
109
+ * When the session provider has NO same-provider fast tier (e.g. xai, whose
110
+ * session model may be an agentic model that ignores the terse classify
111
+ * contract — measured 2026-07-15 for grok-composer), also try keyed fast
112
+ * models from OTHER configured providers, in catalog switch order, until one
113
+ * parses. Bounded by CLASSIFY_TOTAL_BUDGET_MS so a chain of dead/slow keys
114
+ * can't stall the turn. This adds latency ONLY on that fallback path, so it is
115
+ * opt-in per call-site: enable it for the high-value /ideal routing classify,
116
+ * NOT for the per-turn PIL classify (there a fast fail-open "standard" is fine
117
+ * and cheaper than chaining providers on every message).
118
+ */
119
+ crossProviderFallback?: boolean;
120
+ }
121
+ /**
122
+ * Compute the classify call budget from the resolved model's catalog metadata.
123
+ *
124
+ * TIMEOUT is a flat safety-net ceiling for all models — see CLASSIFY_TIMEOUT_MS.
125
+ * Measurement showed classify latency is provider-independent and well under
126
+ * the ceiling, so keying the timeout off `tier`/`reasoning` added no value and
127
+ * amounted to an identity-proxy soft-hardcode.
128
+ *
129
+ * MAX-OUTPUT scales with REASONING only: a reasoning model burns its output
130
+ * budget on reasoning tokens before any visible text, so it needs the room in
131
+ * tokens; a non-reasoning model emits the 8 words directly. This knob is real —
132
+ * it is the fix for reasoning models routing the verdict into the reasoning
133
+ * channel — and stays decoupled from the (now flat) timeout.
134
+ */
135
+ export declare function classifierBudget(modelInfo: {
136
+ reasoning?: boolean;
137
+ tier?: string;
138
+ } | undefined): {
139
+ isReasoning: boolean;
140
+ timeoutMs: number;
141
+ maxOutputTokens: number;
142
+ };
143
+ /** Test seam — clear the cross-provider factory cache between specs. */
144
+ export declare function __resetClassifyFactoryCache(): void;
95
145
  /**
96
146
  * Build a closure the PIL pipeline can call. Reuses the orchestrator's already-
97
147
  * constructed providerFactory + modelId so we don't pay key-loading cost twice.
@@ -99,14 +149,39 @@ export type LlmClassifyFn = (prompt: string, opts?: LlmClassifyOptions) => Promi
99
149
  * Returns null if the call fails / times out / parses to garbage. Callers must
100
150
  * fail-open (keep prior taskType, do not block the turn).
101
151
  */
102
- export declare function createLlmClassifier(factory: ProviderFactory, modelId: string): LlmClassifyFn;
152
+ /**
153
+ * Order the classify candidate list.
154
+ *
155
+ * - `hasSameFast` (e.g. openai → gpt-5.4-mini): the same-provider fast tier is a
156
+ * real fast model, so try it FIRST, then keyed cross-provider models as a
157
+ * FALLBACK. This is the fix for the failure-not-just-absence case: an
158
+ * openai-OAuth session's fast tier can 401 on the api-key path — previously
159
+ * the chain stopped there and fail-opened to "standard" (so /ideal
160
+ * over-councilled trivial tasks). Appending the cross-provider models lets a
161
+ * working alternative (a keyed deepseek/opencode fast model) rescue it.
162
+ * - No same-provider fast tier (e.g. xai, whose session model is agentic and
163
+ * ignores the terse contract): try keyed cross-provider fast models FIRST and
164
+ * keep the session model as the last-resort candidate.
165
+ */
166
+ export declare function orderClassifyCandidates(args: {
167
+ primaryModelId: string;
168
+ hasSameFast: boolean;
169
+ crossModels: ReadonlyArray<{
170
+ modelId: string;
171
+ providerId: ProviderId;
172
+ }>;
173
+ }): Array<{
174
+ modelId: string;
175
+ providerId: ProviderId | null;
176
+ }>;
177
+ export declare function createLlmClassifier(modelId: string, classifyOpts?: CreateClassifierOptions): LlmClassifyFn;
103
178
  export type SubSessionAction = "DIRECT_ANSWER" | "ROTATE_SESSION" | "SPAWN_SUB_SESSION";
104
179
  export interface SubSessionRouteResult {
105
180
  action: SubSessionAction;
106
181
  confidence: number;
107
182
  reason: string;
108
183
  }
109
- export declare function classifySubSessionAction(factory: ProviderFactory, modelId: string, prompt: string, contextInfo?: {
184
+ export declare function classifySubSessionAction(modelId: string, prompt: string, contextInfo?: {
110
185
  currentChars: number;
111
186
  threshold: number;
112
187
  /**