@wrongstack/core 0.109.1 → 0.141.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 (67) hide show
  1. package/dist/{agent-bridge-mOxbpFcg.d.ts → agent-bridge-r9y6gdn4.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-DukQLUcS.d.ts → agent-subagent-runner-1GeQE_L0.d.ts} +7 -8
  3. package/dist/{brain-Dfv4Y82E.d.ts → brain-Cp_3GIS2.d.ts} +14 -3
  4. package/dist/{compactor-DXLxLcmU.d.ts → compactor-BueGt7LG.d.ts} +9 -1
  5. package/dist/{config-BSU-6vah.d.ts → config-BaVThgnT.d.ts} +104 -3
  6. package/dist/{context-CNRYfhUv.d.ts → context-C7G_MtLV.d.ts} +38 -1
  7. package/dist/coordination/index.d.ts +12 -13
  8. package/dist/coordination/index.js +229 -17
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +26 -27
  11. package/dist/defaults/index.js +886 -721
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/execution/index.d.ts +15 -16
  14. package/dist/execution/index.js +535 -322
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +6 -7
  17. package/dist/{goal-preamble-CI8lxeY1.d.ts → goal-preamble-iuIUTQwk.d.ts} +48 -18
  18. package/dist/{index-BWRN6wOb.d.ts → index-BZdezm3g.d.ts} +9 -10
  19. package/dist/{index-DIKEcfgC.d.ts → index-CPweVoFM.d.ts} +7 -6
  20. package/dist/index.d.ts +51 -52
  21. package/dist/index.js +752 -545
  22. package/dist/index.js.map +1 -1
  23. package/dist/infrastructure/index.d.ts +6 -7
  24. package/dist/infrastructure/index.js +64 -19
  25. package/dist/infrastructure/index.js.map +1 -1
  26. package/dist/kernel/index.d.ts +10 -11
  27. package/dist/kernel/index.js.map +1 -1
  28. package/dist/llm-selector-CP72f1lC.d.ts +58 -0
  29. package/dist/{mcp-servers-CXCsANdY.d.ts → mcp-servers-Bl5LTvQg.d.ts} +3 -3
  30. package/dist/{mode-ARA3HrkY.d.ts → mode-CZlO9iU1.d.ts} +1 -1
  31. package/dist/models/index.d.ts +157 -53
  32. package/dist/models/index.js +475 -20
  33. package/dist/models/index.js.map +1 -1
  34. package/dist/{models-registry-DU64QxQa.d.ts → models-registry-D90K9UnM.d.ts} +1 -1
  35. package/dist/{multi-agent-coordinator-51LvnXkD.d.ts → multi-agent-coordinator-QWEzJDlm.d.ts} +1 -1
  36. package/dist/{null-fleet-bus-D09hMzFQ.d.ts → null-fleet-bus-BUyfqh23.d.ts} +13 -10
  37. package/dist/observability/index.d.ts +2 -2
  38. package/dist/{parallel-eternal-engine-B2CbsKpc.d.ts → parallel-eternal-engine-Dj2SYzha.d.ts} +24 -11
  39. package/dist/{path-resolver-DDJiMAtX.d.ts → path-resolver-DRjQBkoO.d.ts} +3 -3
  40. package/dist/{permission-BDv7z0mk.d.ts → permission-B7nKnEvQ.d.ts} +1 -1
  41. package/dist/{permission-policy-dF74EpDp.d.ts → permission-policy-8-6zBmfA.d.ts} +2 -13
  42. package/dist/{pipeline-BqiA_UMr.d.ts → pipeline-BG7UgbDc.d.ts} +2 -2
  43. package/dist/{plan-templates-BdDxl9cI.d.ts → plan-templates-CkKNPU3I.d.ts} +6 -6
  44. package/dist/{provider-runner-BUunikwY.d.ts → provider-runner-BNpuIyOL.d.ts} +3 -3
  45. package/dist/{retry-policy-BcmuT_V0.d.ts → retry-policy-rutAfVeR.d.ts} +1 -1
  46. package/dist/sdd/index.d.ts +8 -9
  47. package/dist/sdd/index.js +208 -1
  48. package/dist/sdd/index.js.map +1 -1
  49. package/dist/{secret-vault-DrOhc2i5.d.ts → secret-vault-BTcC_T5v.d.ts} +3 -2
  50. package/dist/security/index.d.ts +5 -7
  51. package/dist/security/index.js +4 -35
  52. package/dist/security/index.js.map +1 -1
  53. package/dist/{selector-C7wcdqMA.d.ts → selector-4vDFZKt3.d.ts} +1 -1
  54. package/dist/{session-event-bridge-BpJ5trO9.d.ts → session-event-bridge-DWlvglC2.d.ts} +2 -2
  55. package/dist/{session-reader-DDz1Ek4V.d.ts → session-reader-BAtCxdaw.d.ts} +1 -1
  56. package/dist/storage/index.d.ts +14 -15
  57. package/dist/storage/index.js +140 -134
  58. package/dist/storage/index.js.map +1 -1
  59. package/dist/types/index.d.ts +19 -20
  60. package/dist/types/index.js +186 -102
  61. package/dist/types/index.js.map +1 -1
  62. package/dist/utils/index.d.ts +38 -15
  63. package/dist/utils/index.js +62 -33
  64. package/dist/utils/index.js.map +1 -1
  65. package/dist/{wstack-paths-_lqjzErq.d.ts → wstack-paths-DD50Omgn.d.ts} +3 -0
  66. package/package.json +2 -2
  67. package/dist/models-registry-B6_KfS65.d.ts +0 -95
@@ -756,6 +756,55 @@ function expectDefined(value, label) {
756
756
  return value;
757
757
  }
758
758
 
759
+ // src/utils/token-estimate.ts
760
+ var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
761
+ var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
762
+ var ESTIMATE_CACHE_MAX_SIZE = 1e4;
763
+ function getCachedEstimate(key, compute) {
764
+ const existing = ESTIMATE_CACHE.get(key);
765
+ if (existing !== void 0) return existing;
766
+ if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
767
+ const keys = [...ESTIMATE_CACHE.keys()];
768
+ for (let i = 0; i < Math.floor(ESTIMATE_CACHE_MAX_SIZE / 4); i++) {
769
+ ESTIMATE_CACHE.delete(expectDefined(keys[i]));
770
+ }
771
+ }
772
+ const estimate = compute();
773
+ ESTIMATE_CACHE.set(key, estimate);
774
+ return estimate;
775
+ }
776
+ function estimateToolInputTokens(input) {
777
+ if (typeof input === "string") return RoughTokenEstimate(input);
778
+ if (input === null || typeof input !== "object") {
779
+ return RoughTokenEstimate(String(input));
780
+ }
781
+ const key = JSON.stringify(input);
782
+ return getCachedEstimate(key, () => RoughTokenEstimate(key));
783
+ }
784
+ function estimateToolResultTokens(content) {
785
+ if (typeof content === "string") return RoughTokenEstimate(content);
786
+ const key = JSON.stringify(content);
787
+ return getCachedEstimate(key, () => RoughTokenEstimate(key));
788
+ }
789
+ function estimateTextTokens(text) {
790
+ return RoughTokenEstimate(text);
791
+ }
792
+ function estimateMessageTokens(messages) {
793
+ let total = 0;
794
+ for (const m of messages) {
795
+ if (typeof m.content === "string") {
796
+ total += estimateTextTokens(m.content);
797
+ } else {
798
+ for (const b of m.content) {
799
+ if (b.type === "text") total += estimateTextTokens(b.text);
800
+ else if (b.type === "tool_use") total += estimateToolInputTokens(b.input);
801
+ else if (b.type === "tool_result") total += estimateToolResultTokens(b.content);
802
+ }
803
+ }
804
+ }
805
+ return total;
806
+ }
807
+
759
808
  // src/types/blocks.ts
760
809
  function isTextBlock(b) {
761
810
  return b.type === "text";
@@ -784,20 +833,6 @@ Rules:
784
833
  - If unsure, keep rather than collapse (errors are more costly than waste)
785
834
 
786
835
  Return ONLY the JSON object, no markdown, no explanation outside the JSON.`;
787
- function estimateTokens(messages) {
788
- let total = 0;
789
- for (const m of messages) {
790
- if (typeof m.content === "string") {
791
- total += Math.ceil(m.content.length / 4);
792
- } else if (Array.isArray(m.content)) {
793
- for (const b of m.content) {
794
- if (b.type === "text") total += Math.ceil(b.text.length / 4);
795
- else total += Math.ceil(JSON.stringify(b).length / 4);
796
- }
797
- }
798
- }
799
- return total;
800
- }
801
836
  function formatMessages(messages, maxChars = 8e3) {
802
837
  const lines = [];
803
838
  let used = 0;
@@ -836,7 +871,7 @@ var LLMSelector = class {
836
871
  async select(messages, maxToKeep) {
837
872
  const effectiveBudget = Math.min(maxToKeep, this.maxContextTokens);
838
873
  const historyText = formatMessages(messages);
839
- const totalTokens = estimateTokens(messages);
874
+ const totalTokens = estimateMessageTokens(messages);
840
875
  const systemText = `${this.systemPrompt}
841
876
 
842
877
  Conversation (${messages.length} messages, ~${totalTokens} tokens, budget: ${effectiveBudget}):
@@ -868,10 +903,7 @@ IMPORTANT: Total conversation (${totalTokens} tokens) exceeds budget (${effectiv
868
903
  let startIdx = 0;
869
904
  for (let i = messages.length - 1; i >= 0; i--) {
870
905
  const m = expectDefined(messages[i]);
871
- const cost = typeof m.content === "string" ? Math.ceil(m.content.length / 4) : m.content.reduce(
872
- (acc, b) => acc + (b.type === "text" ? Math.ceil(b.text.length / 4) : Math.ceil(JSON.stringify(b).length / 4)),
873
- 0
874
- );
906
+ const cost = estimateMessageTokens([m]);
875
907
  if (tokenCount + cost <= budget) {
876
908
  tokenCount += cost;
877
909
  } else {
@@ -922,6 +954,429 @@ IMPORTANT: Total conversation (${totalTokens} tokens) exceeds budget (${effectiv
922
954
  }
923
955
  };
924
956
 
925
- export { DefaultModeStore, DefaultModelsRegistry, LLMSelector, classifyFamily, loadProjectModes, loadUserModes };
957
+ // src/models/model-intelligence.ts
958
+ var MODEL_PROFILES = [
959
+ // ── Anthropic ──
960
+ {
961
+ provider: "anthropic",
962
+ pattern: /claude-opus/i,
963
+ family: "Claude Opus",
964
+ strengths: ["complex reasoning", "multi-step planning", "nuanced judgment", "long-form analysis"],
965
+ weaknesses: ["latency", "cost"],
966
+ bestFor: ["planning", "security", "debugging", "review"],
967
+ costTier: "premium",
968
+ speedTier: "slow"
969
+ },
970
+ {
971
+ provider: "anthropic",
972
+ pattern: /claude-sonnet/i,
973
+ family: "Claude Sonnet",
974
+ strengths: ["coding", "balanced reasoning", "tool use", "fast iteration"],
975
+ bestFor: ["coding", "refactoring", "backend", "general"],
976
+ costTier: "standard",
977
+ speedTier: "fast"
978
+ },
979
+ {
980
+ provider: "anthropic",
981
+ pattern: /claude-haiku/i,
982
+ family: "Claude Haiku",
983
+ strengths: ["speed", "low cost", "simple tasks"],
984
+ weaknesses: ["complex reasoning", "long context"],
985
+ bestFor: ["lightweight", "docs", "frontend"],
986
+ avoidFor: ["planning", "security"],
987
+ costTier: "budget",
988
+ speedTier: "fast"
989
+ },
990
+ // ── OpenAI ──
991
+ {
992
+ provider: "openai",
993
+ pattern: /gpt-5|o3|o4/i,
994
+ family: "GPT-5 / o3 / o4",
995
+ strengths: ["complex reasoning", "coding", "multi-modal"],
996
+ bestFor: ["planning", "coding", "debugging", "general"],
997
+ costTier: "premium",
998
+ speedTier: "normal"
999
+ },
1000
+ {
1001
+ provider: "openai",
1002
+ pattern: /gpt-4\.1|gpt-4o/i,
1003
+ family: "GPT-4.1 / 4o",
1004
+ strengths: ["coding", "balanced reasoning", "fast"],
1005
+ bestFor: ["coding", "refactoring", "backend", "docs"],
1006
+ costTier: "standard",
1007
+ speedTier: "fast"
1008
+ },
1009
+ {
1010
+ provider: "openai",
1011
+ pattern: /gpt-4o-mini/i,
1012
+ family: "GPT-4o Mini",
1013
+ strengths: ["speed", "low cost", "simple tasks"],
1014
+ weaknesses: ["complex reasoning"],
1015
+ bestFor: ["lightweight", "frontend", "docs"],
1016
+ avoidFor: ["planning", "security"],
1017
+ costTier: "budget",
1018
+ speedTier: "fast"
1019
+ },
1020
+ // ── Google ──
1021
+ {
1022
+ provider: "google",
1023
+ pattern: /gemini-(?:2\.5|3)/i,
1024
+ family: "Gemini 2.5 / 3",
1025
+ strengths: ["long context", "multi-modal", "coding", "reasoning"],
1026
+ bestFor: ["coding", "planning", "data", "general"],
1027
+ costTier: "standard",
1028
+ speedTier: "normal"
1029
+ },
1030
+ {
1031
+ provider: "google",
1032
+ pattern: /gemini-2\.0-flash|gemini-flash/i,
1033
+ family: "Gemini Flash",
1034
+ strengths: ["speed", "low cost", "long context"],
1035
+ weaknesses: ["deep reasoning"],
1036
+ bestFor: ["lightweight", "docs", "frontend", "data"],
1037
+ avoidFor: ["planning", "security"],
1038
+ costTier: "budget",
1039
+ speedTier: "fast"
1040
+ },
1041
+ // ── DeepSeek ──
1042
+ {
1043
+ provider: "deepseek",
1044
+ pattern: /deepseek-v3|deepseek-r1/i,
1045
+ family: "DeepSeek V3 / R1",
1046
+ strengths: ["coding", "math", "reasoning", "cost-effective"],
1047
+ bestFor: ["coding", "refactoring", "debugging", "general"],
1048
+ costTier: "standard",
1049
+ speedTier: "normal"
1050
+ },
1051
+ // ── OpenRouter / catch-all ──
1052
+ {
1053
+ provider: "openrouter",
1054
+ pattern: /.*/,
1055
+ family: "OpenRouter (routed)",
1056
+ strengths: ["model variety", "fallback"],
1057
+ bestFor: ["general"],
1058
+ costTier: "standard",
1059
+ speedTier: "normal"
1060
+ }
1061
+ ];
1062
+ var TASK_TO_ROLE = {
1063
+ coding: ["executor", "architect", "bug-hunter"],
1064
+ planning: ["planner", "architect", "refactor-planner"],
1065
+ security: ["security-scanner", "security-reviewer"],
1066
+ docs: ["document", "simplifier"],
1067
+ testing: ["test", "e2e"],
1068
+ refactoring: ["refactor-planner", "refactor", "simplifier"],
1069
+ debugging: ["debugger", "bug-hunter", "tracer"],
1070
+ data: ["analyst", "data", "database"],
1071
+ frontend: ["frontend", "designer"],
1072
+ backend: ["backend", "api", "auth"],
1073
+ review: ["code-reviewer", "critic"],
1074
+ lightweight: ["executor", "simplifier"],
1075
+ general: ["executor", "analyst"]
1076
+ };
1077
+ function inferTaskType(description, role) {
1078
+ const d = description.toLowerCase();
1079
+ const keywords = [
1080
+ [/plan|architect|design|strategy|blueprint|system\s*design/i, "planning"],
1081
+ [/security|vuln|exploit|injection|auth/i, "security"],
1082
+ [/doc|readme|explain|write\s*(a|the)\s*doc|tutorial/i, "docs"],
1083
+ [/test|spec|assert|mock|coverage/i, "testing"],
1084
+ [/refactor|clean\s*up|restructure|simplify/i, "refactoring"],
1085
+ [/bug|fix|debug|trace|crash|error/i, "debugging"],
1086
+ [/data|json|sql|query|analyze|parse/i, "data"],
1087
+ [/frontend|react|ui|css|component|jsx/i, "frontend"],
1088
+ [/backend|api|server|endpoint|route|middleware/i, "backend"],
1089
+ [/review|audit|inspect|check/i, "review"],
1090
+ [/simple|quick|one-liner|trivial/i, "lightweight"]
1091
+ ];
1092
+ for (const [re, taskType] of keywords) {
1093
+ if (re.test(d)) return taskType;
1094
+ }
1095
+ if (role) {
1096
+ for (const [taskType, roles] of Object.entries(TASK_TO_ROLE)) {
1097
+ if (roles.includes(role)) return taskType;
1098
+ }
1099
+ }
1100
+ return "general";
1101
+ }
1102
+ function findModelProfile(provider, modelId) {
1103
+ const candidates = MODEL_PROFILES.filter((p) => p.provider === provider);
1104
+ for (const p of candidates) {
1105
+ if (p.pattern.test(modelId)) return p;
1106
+ }
1107
+ return void 0;
1108
+ }
1109
+ function scoreModelForTask(profile, taskType) {
1110
+ if (!profile) return 50;
1111
+ if (profile.avoidFor?.includes(taskType)) return 10;
1112
+ const bestIdx = profile.bestFor.indexOf(taskType);
1113
+ if (bestIdx >= 0) {
1114
+ return 90 - bestIdx * 10;
1115
+ }
1116
+ let score = 50;
1117
+ if (taskType === "lightweight") {
1118
+ score += profile.costTier === "budget" ? 30 : profile.costTier === "standard" ? 15 : 0;
1119
+ score += profile.speedTier === "fast" ? 20 : 0;
1120
+ }
1121
+ if (taskType === "planning" || taskType === "security") {
1122
+ score += profile.costTier === "premium" ? 20 : 0;
1123
+ score += profile.speedTier === "slow" ? 10 : 0;
1124
+ }
1125
+ return score;
1126
+ }
1127
+
1128
+ // src/models/model-router.ts
1129
+ var DEFAULT_PROFILES = [
1130
+ { provider: "anthropic", pattern: /claude-opus/i, family: "Claude Opus", strengths: ["reasoning", "planning"], bestFor: ["planning", "security", "debugging"], costTier: "premium", speedTier: "slow" },
1131
+ { provider: "anthropic", pattern: /claude-sonnet/i, family: "Claude Sonnet", strengths: ["coding", "balanced"], bestFor: ["coding", "general"], costTier: "standard", speedTier: "fast" },
1132
+ { provider: "anthropic", pattern: /claude-haiku/i, family: "Claude Haiku", strengths: ["speed"], bestFor: ["lightweight", "docs"], avoidFor: ["planning"], costTier: "budget", speedTier: "fast" },
1133
+ { provider: "openai", pattern: /gpt-5|o3|o4/i, family: "GPT-5/o3/o4", strengths: ["reasoning", "coding"], bestFor: ["planning", "coding", "debugging"], costTier: "premium", speedTier: "normal" },
1134
+ { provider: "openai", pattern: /gpt-4/i, family: "GPT-4", strengths: ["coding"], bestFor: ["coding", "docs"], costTier: "standard", speedTier: "fast" },
1135
+ { provider: "openai", pattern: /gpt-4o-mini/i, family: "GPT-4o Mini", strengths: ["speed"], bestFor: ["lightweight", "docs"], avoidFor: ["planning"], costTier: "budget", speedTier: "fast" },
1136
+ { provider: "google", pattern: /gemini-(?:2\.5|3)/i, family: "Gemini 2.5/3", strengths: ["context", "coding"], bestFor: ["coding", "data"], costTier: "standard", speedTier: "normal" },
1137
+ { provider: "google", pattern: /gemini.*flash/i, family: "Gemini Flash", strengths: ["speed"], bestFor: ["lightweight", "docs"], avoidFor: ["planning"], costTier: "budget", speedTier: "fast" },
1138
+ { provider: "deepseek", pattern: /deepseek/i, family: "DeepSeek", strengths: ["coding", "cost-effective"], bestFor: ["coding", "general"], costTier: "standard", speedTier: "normal" }
1139
+ ];
1140
+ var TASK_CATEGORIES = {
1141
+ plan: "planning",
1142
+ architect: "planning",
1143
+ design: "planning",
1144
+ strategy: "planning",
1145
+ security: "security",
1146
+ vuln: "security",
1147
+ exploit: "security",
1148
+ auth: "security",
1149
+ doc: "docs",
1150
+ readme: "docs",
1151
+ explain: "docs",
1152
+ write: "docs",
1153
+ test: "testing",
1154
+ spec: "testing",
1155
+ assert: "testing",
1156
+ coverage: "testing",
1157
+ refactor: "refactoring",
1158
+ cleanup: "refactoring",
1159
+ restructure: "refactoring",
1160
+ bug: "debugging",
1161
+ fix: "debugging",
1162
+ debug: "debugging",
1163
+ trace: "debugging",
1164
+ crash: "debugging",
1165
+ data: "data",
1166
+ json: "data",
1167
+ sql: "data",
1168
+ query: "data",
1169
+ analyze: "data",
1170
+ parse: "data",
1171
+ frontend: "frontend",
1172
+ react: "frontend",
1173
+ ui: "frontend",
1174
+ css: "frontend",
1175
+ component: "frontend",
1176
+ backend: "backend",
1177
+ api: "backend",
1178
+ server: "backend",
1179
+ endpoint: "backend",
1180
+ review: "review",
1181
+ audit: "review",
1182
+ inspect: "review",
1183
+ simple: "lightweight",
1184
+ quick: "lightweight",
1185
+ trivial: "lightweight"
1186
+ };
1187
+ var ModelRouter = class {
1188
+ profiles;
1189
+ matrix;
1190
+ config;
1191
+ costs = { byModel: {}, totalCost: 0 };
1192
+ constructor(opts) {
1193
+ this.profiles = opts.profiles ?? DEFAULT_PROFILES;
1194
+ this.matrix = opts.matrix ?? {};
1195
+ this.config = opts.config;
1196
+ }
1197
+ /** Look up the model matrix resolution for a role (role → phase → * → leader). */
1198
+ resolveMatrix(role) {
1199
+ if (this.matrix[role]) return this.matrix[role];
1200
+ const phase = this.roleToPhase(role);
1201
+ if (phase && this.matrix[phase]) return this.matrix[phase];
1202
+ if (this.matrix["*"]) return this.matrix["*"];
1203
+ return void 0;
1204
+ }
1205
+ /** Simplified phase lookup for common roles. */
1206
+ roleToPhase(role) {
1207
+ const phaseMap = {
1208
+ planner: "plan",
1209
+ architect: "plan",
1210
+ "refactor-planner": "plan",
1211
+ executor: "code",
1212
+ refactor: "code",
1213
+ simplifier: "code",
1214
+ migration: "code",
1215
+ "bug-hunter": "code",
1216
+ debugger: "code",
1217
+ tracer: "code",
1218
+ test: "code",
1219
+ e2e: "code",
1220
+ performance: "code",
1221
+ chaos: "code",
1222
+ "security-scanner": "review",
1223
+ "security-reviewer": "review",
1224
+ "code-reviewer": "review",
1225
+ critic: "review",
1226
+ accessibility: "review",
1227
+ compliance: "review",
1228
+ analyst: "code",
1229
+ data: "code",
1230
+ database: "code",
1231
+ frontend: "code",
1232
+ backend: "code",
1233
+ api: "code",
1234
+ auth: "code",
1235
+ designer: "code",
1236
+ document: "code",
1237
+ researcher: "plan",
1238
+ explore: "plan",
1239
+ search: "plan"
1240
+ };
1241
+ return phaseMap[role];
1242
+ }
1243
+ /**
1244
+ * Pick the best model for a task.
1245
+ *
1246
+ * Priority:
1247
+ * 1. User's /setmodel matrix entry for this role (explicit override)
1248
+ * 2. Best-matching model from intelligence profiles
1249
+ * 3. Leader model (fallback)
1250
+ */
1251
+ pickForTask(role, description) {
1252
+ const matrixEntry = this.resolveMatrix(role);
1253
+ if (matrixEntry) {
1254
+ const provider = matrixEntry.provider ?? this.config.provider;
1255
+ return {
1256
+ provider,
1257
+ model: matrixEntry.model,
1258
+ reason: `matrix override for role ${role}`,
1259
+ fromMatrix: true
1260
+ };
1261
+ }
1262
+ const category = this.inferCategory(description, role);
1263
+ const best = this.findBestModel(category);
1264
+ if (best) {
1265
+ return { ...best, reason: `best-for ${category} (auto-detected)`, fromMatrix: false };
1266
+ }
1267
+ return {
1268
+ provider: this.config.provider,
1269
+ model: this.config.model,
1270
+ reason: "leader fallback",
1271
+ fromMatrix: false
1272
+ };
1273
+ }
1274
+ /** Infer task category from description keywords + role. */
1275
+ inferCategory(description, role) {
1276
+ const d = description.toLowerCase();
1277
+ for (const [keyword, category] of Object.entries(TASK_CATEGORIES)) {
1278
+ if (d.includes(keyword)) return category;
1279
+ }
1280
+ const roleMap = {
1281
+ "security-scanner": "security",
1282
+ "security-reviewer": "security",
1283
+ "bug-hunter": "debugging",
1284
+ debugger: "debugging",
1285
+ planner: "planning",
1286
+ architect: "planning",
1287
+ "refactor-planner": "refactoring",
1288
+ refactor: "refactoring",
1289
+ test: "testing",
1290
+ e2e: "testing",
1291
+ document: "docs",
1292
+ simplifier: "docs",
1293
+ "code-reviewer": "review",
1294
+ critic: "review",
1295
+ "frontend": "frontend",
1296
+ "backend": "backend"
1297
+ };
1298
+ return roleMap[role] ?? "general";
1299
+ }
1300
+ /** Find the best available model for a task category. */
1301
+ findBestModel(category) {
1302
+ const scored = this.profiles.filter((p) => this.hasKey(p.provider)).map((p) => {
1303
+ let score = 50;
1304
+ if (p.bestFor.includes(category)) score += 40;
1305
+ if (p.avoidFor?.includes(category)) score -= 50;
1306
+ if (category === "lightweight" && p.costTier === "budget") score += 20;
1307
+ if (category === "planning" && p.costTier === "premium") score += 15;
1308
+ if (category === "planning" && p.speedTier === "slow") score += 10;
1309
+ return { profile: p, score };
1310
+ }).filter((s) => s.score > 0).sort((a, b) => b.score - a.score);
1311
+ if (scored.length === 0) return void 0;
1312
+ const best = scored[0]?.profile;
1313
+ if (!best) return void 0;
1314
+ const models = this.getProviderModels(best.provider);
1315
+ const match = models.find((m) => best.pattern.test(m)) ?? models[0];
1316
+ if (!match) return void 0;
1317
+ return { provider: best.provider, model: match };
1318
+ }
1319
+ /** Check if a provider has an API key configured. */
1320
+ hasKey(providerId) {
1321
+ const pc = this.config.providers?.[providerId];
1322
+ if (!pc) return providerId === this.config.provider;
1323
+ if (typeof pc.apiKey === "string" && pc.apiKey.length > 0) return true;
1324
+ if (Array.isArray(pc.apiKeys) && pc.apiKeys.some((k) => k?.apiKey)) return true;
1325
+ return false;
1326
+ }
1327
+ /** Get the configured model list for a provider. */
1328
+ getProviderModels(providerId) {
1329
+ const pc = this.config.providers?.[providerId];
1330
+ return pc?.models ?? [];
1331
+ }
1332
+ /** Record cost for a model. */
1333
+ recordCost(provider, model, cost, tokens) {
1334
+ const key = `${provider}/${model}`;
1335
+ const entry = this.costs.byModel[key] ?? { cost: 0, tokens: { input: 0, output: 0 }, calls: 0 };
1336
+ entry.cost += cost;
1337
+ if (tokens) {
1338
+ entry.tokens.input += tokens.input;
1339
+ entry.tokens.output += tokens.output;
1340
+ }
1341
+ entry.calls += 1;
1342
+ this.costs.byModel[key] = entry;
1343
+ this.costs.totalCost += cost;
1344
+ }
1345
+ /** Get cumulative costs. */
1346
+ getCosts() {
1347
+ return { ...this.costs, byModel: { ...this.costs.byModel } };
1348
+ }
1349
+ /** Reset cost tracking. */
1350
+ resetCosts() {
1351
+ this.costs = { byModel: {}, totalCost: 0 };
1352
+ }
1353
+ /** List all available providers with their best model for each task category. */
1354
+ suggestMatrix() {
1355
+ const matrix = {};
1356
+ const roles = [
1357
+ "security-scanner",
1358
+ "bug-hunter",
1359
+ "planner",
1360
+ "architect",
1361
+ "refactor-planner",
1362
+ "test",
1363
+ "document",
1364
+ "code-reviewer",
1365
+ "executor",
1366
+ "debugger",
1367
+ "analyst"
1368
+ ];
1369
+ for (const role of roles) {
1370
+ if (this.matrix[role]) continue;
1371
+ const pick = this.pickForTask(role, role);
1372
+ if (!pick.fromMatrix) {
1373
+ matrix[role] = pick;
1374
+ }
1375
+ }
1376
+ return matrix;
1377
+ }
1378
+ };
1379
+
1380
+ export { DefaultModeStore, DefaultModelsRegistry, LLMSelector, MODEL_PROFILES, ModelRouter, TASK_TO_ROLE, classifyFamily, findModelProfile, inferTaskType, loadProjectModes, loadUserModes, scoreModelForTask };
926
1381
  //# sourceMappingURL=index.js.map
927
1382
  //# sourceMappingURL=index.js.map