@cleocode/core 2026.8.2 → 2026.8.4

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 (186) hide show
  1. package/dist/check/pr-gate.d.ts.map +1 -1
  2. package/dist/check/pr-gate.js +9 -0
  3. package/dist/check/pr-gate.js.map +1 -1
  4. package/dist/docs/export-document.js +66 -16
  5. package/dist/docs/export-document.js.map +3 -3
  6. package/dist/doctor/index.d.ts +2 -0
  7. package/dist/doctor/index.d.ts.map +1 -1
  8. package/dist/doctor/index.js +1 -0
  9. package/dist/doctor/index.js.map +1 -1
  10. package/dist/doctor/superseded-store.d.ts +101 -0
  11. package/dist/doctor/superseded-store.d.ts.map +1 -0
  12. package/dist/doctor/superseded-store.js +156 -0
  13. package/dist/doctor/superseded-store.js.map +1 -0
  14. package/dist/hooks/registry.d.ts +2 -2
  15. package/dist/hooks/registry.d.ts.map +1 -1
  16. package/dist/hooks/registry.js +5 -0
  17. package/dist/hooks/registry.js.map +1 -1
  18. package/dist/hooks/types.d.ts +59 -0
  19. package/dist/hooks/types.d.ts.map +1 -1
  20. package/dist/init/scaffold-workflows.d.ts +12 -0
  21. package/dist/init/scaffold-workflows.d.ts.map +1 -1
  22. package/dist/init/scaffold-workflows.js +16 -0
  23. package/dist/init/scaffold-workflows.js.map +1 -1
  24. package/dist/init/upgrade-workflows.d.ts.map +1 -1
  25. package/dist/init/upgrade-workflows.js +16 -0
  26. package/dist/init/upgrade-workflows.js.map +1 -1
  27. package/dist/init.d.ts.map +1 -1
  28. package/dist/init.js +16 -1
  29. package/dist/init.js.map +1 -1
  30. package/dist/internal.d.ts +1 -0
  31. package/dist/internal.d.ts.map +1 -1
  32. package/dist/internal.js +2 -0
  33. package/dist/internal.js.map +1 -1
  34. package/dist/llm/credentials.d.ts +16 -1
  35. package/dist/llm/credentials.d.ts.map +1 -1
  36. package/dist/llm/credentials.js.map +1 -1
  37. package/dist/llm/cross-provider-selector.d.ts +25 -0
  38. package/dist/llm/cross-provider-selector.d.ts.map +1 -1
  39. package/dist/llm/cross-provider-selector.js +76 -3
  40. package/dist/llm/cross-provider-selector.js.map +1 -1
  41. package/dist/llm/local-inference-probe.d.ts +101 -0
  42. package/dist/llm/local-inference-probe.d.ts.map +1 -0
  43. package/dist/llm/local-inference-probe.js +174 -0
  44. package/dist/llm/local-inference-probe.js.map +1 -0
  45. package/dist/llm/plugin-facade.js +199 -21
  46. package/dist/llm/plugin-facade.js.map +3 -3
  47. package/dist/llm/role-executor.d.ts.map +1 -1
  48. package/dist/llm/role-executor.js +95 -9
  49. package/dist/llm/role-executor.js.map +1 -1
  50. package/dist/llm/role-resolver.d.ts +10 -0
  51. package/dist/llm/role-resolver.d.ts.map +1 -1
  52. package/dist/llm/role-resolver.js +92 -1
  53. package/dist/llm/role-resolver.js.map +1 -1
  54. package/dist/llm/system-resolver.d.ts.map +1 -1
  55. package/dist/llm/system-resolver.js +2 -0
  56. package/dist/llm/system-resolver.js.map +1 -1
  57. package/dist/memory/brain-search.d.ts +109 -0
  58. package/dist/memory/brain-search.d.ts.map +1 -1
  59. package/dist/memory/brain-search.js +149 -37
  60. package/dist/memory/brain-search.js.map +1 -1
  61. package/dist/memory/brain-stub-prune.d.ts +109 -0
  62. package/dist/memory/brain-stub-prune.d.ts.map +1 -0
  63. package/dist/memory/brain-stub-prune.js +155 -0
  64. package/dist/memory/brain-stub-prune.js.map +1 -0
  65. package/dist/memory/engine-compat.d.ts.map +1 -1
  66. package/dist/memory/engine-compat.js +61 -3
  67. package/dist/memory/engine-compat.js.map +1 -1
  68. package/dist/nexus/analyze-orchestrator.d.ts.map +1 -1
  69. package/dist/nexus/analyze-orchestrator.js +28 -0
  70. package/dist/nexus/analyze-orchestrator.js.map +1 -1
  71. package/dist/nexus/context.d.ts.map +1 -1
  72. package/dist/nexus/context.js +3 -3
  73. package/dist/nexus/context.js.map +1 -1
  74. package/dist/nexus/impact.d.ts.map +1 -1
  75. package/dist/nexus/impact.js +3 -3
  76. package/dist/nexus/impact.js.map +1 -1
  77. package/dist/nexus/symbol-miss.d.ts +132 -0
  78. package/dist/nexus/symbol-miss.d.ts.map +1 -0
  79. package/dist/nexus/symbol-miss.js +168 -0
  80. package/dist/nexus/symbol-miss.js.map +1 -0
  81. package/dist/orchestrate/spawn-ops.d.ts +21 -1
  82. package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
  83. package/dist/orchestrate/spawn-ops.js +39 -2
  84. package/dist/orchestrate/spawn-ops.js.map +1 -1
  85. package/dist/orchestrate/worker-verify.d.ts.map +1 -1
  86. package/dist/orchestrate/worker-verify.js +22 -0
  87. package/dist/orchestrate/worker-verify.js.map +1 -1
  88. package/dist/release/changesets-aggregator.d.ts.map +1 -1
  89. package/dist/release/changesets-aggregator.js +15 -1
  90. package/dist/release/changesets-aggregator.js.map +1 -1
  91. package/dist/release/open.d.ts +29 -2
  92. package/dist/release/open.d.ts.map +1 -1
  93. package/dist/release/open.js +48 -11
  94. package/dist/release/open.js.map +1 -1
  95. package/dist/resources/governor.d.ts +12 -2
  96. package/dist/resources/governor.d.ts.map +1 -1
  97. package/dist/resources/governor.js +12 -3
  98. package/dist/resources/governor.js.map +1 -1
  99. package/dist/scaffold/ensure-dirs.d.ts.map +1 -1
  100. package/dist/scaffold/ensure-dirs.js +14 -2
  101. package/dist/scaffold/ensure-dirs.js.map +1 -1
  102. package/dist/scaffold/project-detection.d.ts.map +1 -1
  103. package/dist/scaffold/project-detection.js +2 -1
  104. package/dist/scaffold/project-detection.js.map +1 -1
  105. package/dist/selfimprove/draft-pr.d.ts +14 -1
  106. package/dist/selfimprove/draft-pr.d.ts.map +1 -1
  107. package/dist/selfimprove/draft-pr.js.map +1 -1
  108. package/dist/selfimprove/fix-gen.d.ts +0 -21
  109. package/dist/selfimprove/fix-gen.d.ts.map +1 -1
  110. package/dist/selfimprove/fix-gen.js +276 -76
  111. package/dist/selfimprove/fix-gen.js.map +3 -3
  112. package/dist/selfimprove/run-loop.d.ts.map +1 -1
  113. package/dist/selfimprove/run-loop.js +50 -19
  114. package/dist/selfimprove/run-loop.js.map +1 -1
  115. package/dist/selfimprove/scenarios/dhq-replay-find/golden.json +114 -4
  116. package/dist/selfimprove/scenarios/dhq-replay-find/scenario.json +3 -3
  117. package/dist/sentient/dream-cycle.d.ts +20 -19
  118. package/dist/sentient/dream-cycle.d.ts.map +1 -1
  119. package/dist/sentient/dream-cycle.js +322 -11
  120. package/dist/sentient/dream-cycle.js.map +1 -1
  121. package/dist/sentient/dream-watermark.d.ts +134 -0
  122. package/dist/sentient/dream-watermark.d.ts.map +1 -0
  123. package/dist/sentient/dream-watermark.js +156 -0
  124. package/dist/sentient/dream-watermark.js.map +1 -0
  125. package/dist/sentient/state.d.ts +17 -0
  126. package/dist/sentient/state.d.ts.map +1 -1
  127. package/dist/sentient/state.js +22 -3
  128. package/dist/sentient/state.js.map +1 -1
  129. package/dist/sentient/tick.d.ts.map +1 -1
  130. package/dist/sentient/tick.js +79 -2
  131. package/dist/sentient/tick.js.map +1 -1
  132. package/dist/sessions/index.d.ts.map +1 -1
  133. package/dist/sessions/index.js +5 -1
  134. package/dist/sessions/index.js.map +1 -1
  135. package/dist/sessions/snapshot.d.ts.map +1 -1
  136. package/dist/sessions/snapshot.js +6 -3
  137. package/dist/sessions/snapshot.js.map +1 -1
  138. package/dist/store/checkpoint-git-dir.d.ts +95 -0
  139. package/dist/store/checkpoint-git-dir.d.ts.map +1 -0
  140. package/dist/store/checkpoint-git-dir.js +111 -0
  141. package/dist/store/checkpoint-git-dir.js.map +1 -0
  142. package/dist/store/git-checkpoint.d.ts.map +1 -1
  143. package/dist/store/git-checkpoint.js +6 -5
  144. package/dist/store/git-checkpoint.js.map +1 -1
  145. package/dist/system/health.d.ts.map +1 -1
  146. package/dist/system/health.js +2 -1
  147. package/dist/system/health.js.map +1 -1
  148. package/dist/tasks/add.d.ts.map +1 -1
  149. package/dist/tasks/add.js +40 -4
  150. package/dist/tasks/add.js.map +1 -1
  151. package/dist/tasks/collection.d.ts +51 -0
  152. package/dist/tasks/collection.d.ts.map +1 -0
  153. package/dist/tasks/collection.js +81 -0
  154. package/dist/tasks/collection.js.map +1 -0
  155. package/dist/tasks/complete.d.ts.map +1 -1
  156. package/dist/tasks/complete.js +8 -3
  157. package/dist/tasks/complete.js.map +1 -1
  158. package/dist/tasks/evidence.d.ts.map +1 -1
  159. package/dist/tasks/evidence.js +17 -0
  160. package/dist/tasks/evidence.js.map +1 -1
  161. package/dist/tasks/find.d.ts +50 -0
  162. package/dist/tasks/find.d.ts.map +1 -1
  163. package/dist/tasks/find.js +63 -2
  164. package/dist/tasks/find.js.map +1 -1
  165. package/dist/tasks/heavy-tool-env.d.ts +112 -0
  166. package/dist/tasks/heavy-tool-env.d.ts.map +1 -0
  167. package/dist/tasks/heavy-tool-env.js +133 -0
  168. package/dist/tasks/heavy-tool-env.js.map +1 -0
  169. package/dist/tasks/index.d.ts +2 -0
  170. package/dist/tasks/index.d.ts.map +1 -1
  171. package/dist/tasks/index.js +1 -0
  172. package/dist/tasks/index.js.map +1 -1
  173. package/dist/tasks/tool-cache.d.ts.map +1 -1
  174. package/dist/tasks/tool-cache.js +9 -3
  175. package/dist/tasks/tool-cache.js.map +1 -1
  176. package/dist/tasks/tool-resolver.d.ts +1 -1
  177. package/dist/tasks/tool-resolver.d.ts.map +1 -1
  178. package/dist/tasks/tool-resolver.js +83 -0
  179. package/dist/tasks/tool-resolver.js.map +1 -1
  180. package/dist/tasks/tool-semaphore.d.ts +82 -12
  181. package/dist/tasks/tool-semaphore.d.ts.map +1 -1
  182. package/dist/tasks/tool-semaphore.js +79 -17
  183. package/dist/tasks/tool-semaphore.js.map +1 -1
  184. package/package.json +13 -13
  185. package/templates/CLEO-INJECTION.md +55 -22
  186. package/templates/workflows/release-prepare.yml.tmpl +73 -16
@@ -10178,6 +10178,27 @@ var init_operations_registry = __esm({
10178
10178
  type: "boolean",
10179
10179
  required: false,
10180
10180
  description: "Commit plan file before dispatching"
10181
+ },
10182
+ // T12089: the plan SCOPE. The workflow regenerates the plan when no
10183
+ // committed plan is supplied, and `cleo release plan` requires
10184
+ // `--saga | --epic | --tasks` — so without one of these the dispatched
10185
+ // run dies at "Prepare bump-PR" after a fully green preflight.
10186
+ //
10187
+ // A param absent from this registry is STRIPPED before the domain handler
10188
+ // sees it, silently. `--tasks` was accepted by the CLI, forwarded by the
10189
+ // handler and by `releaseOpen`, and still arrived empty at the workflow
10190
+ // because this declaration was the fourth hop in the chain.
10191
+ {
10192
+ name: "epic",
10193
+ type: "string",
10194
+ required: false,
10195
+ description: "Epic task ID forwarded as the plan scope (e.g. T9999)"
10196
+ },
10197
+ {
10198
+ name: "tasks",
10199
+ type: "string",
10200
+ required: false,
10201
+ description: "Comma-separated task IDs forwarded as the plan scope for a task-scoped release"
10181
10202
  }
10182
10203
  ]
10183
10204
  },
@@ -15808,6 +15829,13 @@ var init_caamp_markers = __esm({
15808
15829
  }
15809
15830
  });
15810
15831
 
15832
+ // packages/contracts/src/collection-keys.ts
15833
+ var init_collection_keys = __esm({
15834
+ "packages/contracts/src/collection-keys.ts"() {
15835
+ "use strict";
15836
+ }
15837
+ });
15838
+
15811
15839
  // packages/contracts/src/index.ts
15812
15840
  var init_src = __esm({
15813
15841
  "packages/contracts/src/index.ts"() {
@@ -15876,6 +15904,7 @@ var init_src = __esm({
15876
15904
  init_service_provider();
15877
15905
  init_workgraph();
15878
15906
  init_caamp_markers();
15907
+ init_collection_keys();
15879
15908
  }
15880
15909
  });
15881
15910
 
@@ -17885,7 +17914,7 @@ var init_sql = __esm({
17885
17914
  return new SQL([new StringChunk(str)]);
17886
17915
  }
17887
17916
  _sql.raw = raw;
17888
- function join34(chunks, separator) {
17917
+ function join35(chunks, separator) {
17889
17918
  const result = [];
17890
17919
  for (const [i, chunk] of chunks.entries()) {
17891
17920
  if (i > 0 && separator !== void 0) result.push(separator);
@@ -17893,7 +17922,7 @@ var init_sql = __esm({
17893
17922
  }
17894
17923
  return new SQL(result);
17895
17924
  }
17896
- _sql.join = join34;
17925
+ _sql.join = join35;
17897
17926
  function identifier(value) {
17898
17927
  return new Name(value);
17899
17928
  }
@@ -19862,7 +19891,7 @@ var init_select = __esm({
19862
19891
  const baseTableName = this.tableName;
19863
19892
  const tableName = getTableLikeName(table);
19864
19893
  for (const item of extractUsedTable(table)) this.usedTables.add(item);
19865
- if (typeof tableName === "string" && this.config.joins?.some((join34) => join34.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
19894
+ if (typeof tableName === "string" && this.config.joins?.some((join35) => join35.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
19866
19895
  if (!this.isPartialSelect) {
19867
19896
  if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === "string") this.config.fields = { [baseTableName]: this.config.fields };
19868
19897
  if (typeof tableName === "string" && !is(table, SQL)) {
@@ -21459,7 +21488,7 @@ var init_dialect = __esm({
21459
21488
  if (!joins2) return;
21460
21489
  const withEntries = Object.entries(joins2).filter(([_, v]) => v);
21461
21490
  if (!withEntries.length) return;
21462
- return sql.join(withEntries.map(([k, join34]) => {
21491
+ return sql.join(withEntries.map(([k, join35]) => {
21463
21492
  const relation = tableConfig.relations[k];
21464
21493
  const isSingle2 = is(relation, One);
21465
21494
  const targetTable = aliasedTable(relation.targetTable, `d${currentDepth + 1}`);
@@ -21470,7 +21499,7 @@ var init_dialect = __esm({
21470
21499
  table: targetTable,
21471
21500
  mode: isSingle2 ? "first" : "many",
21472
21501
  schema,
21473
- queryConfig: join34,
21502
+ queryConfig: join35,
21474
21503
  tableConfig: schema[relation.targetTableName],
21475
21504
  relationWhere: filter2,
21476
21505
  isNested: true,
@@ -21484,7 +21513,7 @@ var init_dialect = __esm({
21484
21513
  key: k,
21485
21514
  selection: innerQuery.selection,
21486
21515
  isArray: !isSingle2,
21487
- isOptional: (relation.optional ?? false) || join34 !== true && !!join34.where
21516
+ isOptional: (relation.optional ?? false) || join35 !== true && !!join35.where
21488
21517
  });
21489
21518
  const jsonColumns = sql.join(innerQuery.selection.map((s) => {
21490
21519
  return sql`${sql.raw(this.escapeString(s.key))}, ${s.selection ? sql`${jsonb}(${sql.identifier(s.key)})` : sql.identifier(s.key)}`;
@@ -21906,7 +21935,7 @@ var init_update = __esm({
21906
21935
  createJoin(joinType) {
21907
21936
  return ((table, on) => {
21908
21937
  const tableName = getTableLikeName(table);
21909
- if (typeof tableName === "string" && this.config.joins.some((join34) => join34.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
21938
+ if (typeof tableName === "string" && this.config.joins.some((join35) => join35.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
21910
21939
  if (typeof on === "function") {
21911
21940
  const from = this.config.from ? is(table, SQLiteTable) ? table[Table.Symbol.Columns] : is(table, Subquery) ? table._.selectedFields : is(table, SQLiteViewBase) ? table[ViewBaseConfig].selectedFields : void 0 : void 0;
21912
21941
  on = on(new Proxy(this.config.table[Table.Symbol.Columns], new SelectionProxyHandler({
@@ -24684,7 +24713,9 @@ function computeClassBudget(cls, sample, opts = {}) {
24684
24713
  return Math.max(1, cpus - 2);
24685
24714
  case "test-run":
24686
24715
  case "scoped-build": {
24687
- const base = Math.max(1, Math.floor(cpus / 4));
24716
+ const estRamBytes = (opts.testRunEstRamMb ?? 24576) * MB;
24717
+ const byMem = Math.floor((availBytes - headroomBytes) / estRamBytes);
24718
+ const base = clamp2(1, byMem, Math.max(1, Math.floor(cpus / 4)));
24688
24719
  if (some > floor) return 1;
24689
24720
  if (some > hold) return Math.max(1, Math.floor(base / 2));
24690
24721
  return base;
@@ -25177,6 +25208,11 @@ var init_registry = __esm({
25177
25208
  * });
25178
25209
  * ```
25179
25210
  */
25211
+ // T12071: keyed on the EVENT so the payload shape is checked against
25212
+ // `HookEventPayloadMap`. The previous `<T extends HookPayload>` form inferred
25213
+ // T from the argument, relating the event and the payload not at all — which
25214
+ // is how `PostToolUse` came to be dispatched with `newStatus` instead of
25215
+ // `status` and filled 29% of BRAIN with "status: undefined".
25180
25216
  async dispatch(event, projectRoot, payload) {
25181
25217
  if (!this.config.enabled) return;
25182
25218
  const resolvedEvent = this.resolveEvent(event);
@@ -28458,8 +28494,8 @@ function reuseValid(key, store) {
28458
28494
  return row;
28459
28495
  }
28460
28496
  async function bindAgainst(key, store, establish) {
28461
- const cached2 = reuseValid(key, store);
28462
- if (cached2) return cached2;
28497
+ const cached3 = reuseValid(key, store);
28498
+ if (cached3) return cached3;
28463
28499
  const pending = _inflight.get(key);
28464
28500
  if (pending) {
28465
28501
  const row = await pending;
@@ -33071,6 +33107,76 @@ var init_credential_pool = __esm({
33071
33107
  }
33072
33108
  });
33073
33109
 
33110
+ // packages/core/src/llm/local-inference-probe.ts
33111
+ function extractModels(body) {
33112
+ if (body === null || typeof body !== "object") return [];
33113
+ const rec = body;
33114
+ if (Array.isArray(rec.models)) {
33115
+ return rec.models.map(
33116
+ (m) => m !== null && typeof m === "object" ? m.name ?? m.model : void 0
33117
+ ).filter((n) => typeof n === "string");
33118
+ }
33119
+ if (Array.isArray(rec.data)) {
33120
+ return rec.data.map((m) => m !== null && typeof m === "object" ? m.id : void 0).filter((n) => typeof n === "string");
33121
+ }
33122
+ return [];
33123
+ }
33124
+ async function detectLocalInference(opts = {}) {
33125
+ if (process.env["CLEO_DISABLE_LOCAL_INFERENCE"]?.trim()) return null;
33126
+ if (!opts.force && cached !== void 0) return cached;
33127
+ for (const endpoint of LOCAL_ENDPOINTS) {
33128
+ try {
33129
+ const response = await fetch(endpoint.tagsUrl, {
33130
+ signal: AbortSignal.timeout(PROBE_TIMEOUT_MS)
33131
+ });
33132
+ if (!response.ok) continue;
33133
+ const models = extractModels(await response.json());
33134
+ if (models.length === 0) continue;
33135
+ cached = {
33136
+ name: endpoint.name,
33137
+ baseUrl: endpoint.baseUrl,
33138
+ openAiBaseUrl: endpoint.openAiBaseUrl,
33139
+ models
33140
+ };
33141
+ return cached;
33142
+ } catch {
33143
+ }
33144
+ }
33145
+ cached = null;
33146
+ return cached;
33147
+ }
33148
+ async function listOllamaModels(baseUrl) {
33149
+ try {
33150
+ const url2 = `${baseUrl.replace(/\/+$/, "")}/api/tags`;
33151
+ const response = await fetch(url2, { signal: AbortSignal.timeout(PROBE_TIMEOUT_MS) });
33152
+ if (!response.ok) return [];
33153
+ return extractModels(await response.json());
33154
+ } catch {
33155
+ return [];
33156
+ }
33157
+ }
33158
+ var LOCAL_ENDPOINTS, PROBE_TIMEOUT_MS, cached;
33159
+ var init_local_inference_probe = __esm({
33160
+ "packages/core/src/llm/local-inference-probe.ts"() {
33161
+ "use strict";
33162
+ LOCAL_ENDPOINTS = [
33163
+ {
33164
+ name: "ollama",
33165
+ tagsUrl: "http://127.0.0.1:11434/api/tags",
33166
+ baseUrl: "http://127.0.0.1:11434",
33167
+ openAiBaseUrl: "http://127.0.0.1:11434/v1"
33168
+ },
33169
+ {
33170
+ name: "lm-studio",
33171
+ tagsUrl: "http://127.0.0.1:1234/v1/models",
33172
+ baseUrl: "http://127.0.0.1:1234",
33173
+ openAiBaseUrl: "http://127.0.0.1:1234/v1"
33174
+ }
33175
+ ];
33176
+ PROBE_TIMEOUT_MS = 300;
33177
+ }
33178
+ });
33179
+
33074
33180
  // packages/core/src/llm/catalog-cache.ts
33075
33181
  import {
33076
33182
  existsSync as existsSync27,
@@ -33194,9 +33300,9 @@ var init_catalog_model_resolver = __esm({
33194
33300
  // packages/core/src/llm/cross-provider-selector.ts
33195
33301
  import { totalmem as totalmem2 } from "node:os";
33196
33302
  async function probeOllamaAlive(baseUrl) {
33197
- const cached2 = _ollamaProbeCache.get(baseUrl);
33198
- if (cached2 && Date.now() - cached2.checkedAt < OLLAMA_PROBE_TTL_MS) {
33199
- return cached2.alive;
33303
+ const cached3 = _ollamaProbeCache.get(baseUrl);
33304
+ if (cached3 && Date.now() - cached3.checkedAt < OLLAMA_PROBE_TTL_MS) {
33305
+ return cached3.alive;
33200
33306
  }
33201
33307
  let alive = false;
33202
33308
  try {
@@ -33238,6 +33344,16 @@ function isProvisioned(provider) {
33238
33344
  const cred = resolveCredentials(provider);
33239
33345
  return (cred.apiKey?.trim().length ?? 0) > 0;
33240
33346
  }
33347
+ function reconcileOllamaModel(preferred, installed) {
33348
+ if (installed.length === 0) return preferred;
33349
+ if (installed.includes(preferred)) return preferred;
33350
+ const family = preferred.split(":")[0];
33351
+ if (family !== void 0 && family !== "") {
33352
+ const sameFamily = installed.find((m) => m.split(":")[0] === family);
33353
+ if (sameFamily !== void 0) return sameFamily;
33354
+ }
33355
+ return installed[0] ?? preferred;
33356
+ }
33241
33357
  function scoreProvider(provider, providerTier, taskTier, ollamaAlive, costInputPerMillion) {
33242
33358
  let score = TIER_BASE[providerTier];
33243
33359
  if (taskTier === "frontier" && providerTier === "frontier") {
@@ -33270,6 +33386,7 @@ function roleTierFor(role) {
33270
33386
  }
33271
33387
  async function selectBestProvisioned(role, opts) {
33272
33388
  const taskTier = roleTierFor(role);
33389
+ const excluded = new Set(opts.exclude ?? []);
33273
33390
  for (const id of BUILTIN_PROVIDER_IDS) {
33274
33391
  const creds = await listCredentials(id);
33275
33392
  const hasExpiredOAuth = creds.some(
@@ -33294,10 +33411,23 @@ async function selectBestProvisioned(role, opts) {
33294
33411
  }
33295
33412
  const provisionedIds = [];
33296
33413
  for (const id of BUILTIN_PROVIDER_IDS) {
33414
+ if (excluded.has(id)) continue;
33297
33415
  if (isProvisioned(id)) {
33298
33416
  provisionedIds.push(id);
33299
33417
  }
33300
33418
  }
33419
+ let localModels = [];
33420
+ if (!excluded.has("ollama") && !provisionedIds.includes("ollama")) {
33421
+ const local = await detectLocalInference();
33422
+ if (local !== null && local.name === "ollama") {
33423
+ provisionedIds.push("ollama");
33424
+ localModels = local.models;
33425
+ logger3.debug(
33426
+ { baseUrl: local.baseUrl, models: local.models },
33427
+ "cross-provider-selector: unlisted ollama daemon is live \u2014 admitting as provisioned"
33428
+ );
33429
+ }
33430
+ }
33301
33431
  if (provisionedIds.length === 0) {
33302
33432
  logger3.warn(
33303
33433
  {
@@ -33314,11 +33444,12 @@ async function selectBestProvisioned(role, opts) {
33314
33444
  const { resolveProviderDefaultModel: resolveProviderDefaultModel2, catalogKeyForProvider: catalogKeyForProvider2 } = await Promise.resolve().then(() => (init_catalog_model_resolver(), catalog_model_resolver_exports));
33315
33445
  const { pickCredentialForProvider: pickCredentialForProvider2 } = await Promise.resolve().then(() => (init_credentials_store(), credentials_store_exports));
33316
33446
  const ollamaProvisioned = provisionedIds.includes("ollama");
33317
- let ollamaAlive = false;
33318
- if (ollamaProvisioned) {
33447
+ let ollamaAlive = localModels.length > 0;
33448
+ if (ollamaProvisioned && !ollamaAlive) {
33319
33449
  const profile = await getProviderProfile2("ollama");
33320
33450
  const ollamaBase = profile?.baseUrl ?? "http://localhost:11434";
33321
33451
  ollamaAlive = await probeOllamaAlive(ollamaBase);
33452
+ if (ollamaAlive) localModels = await listOllamaModels(ollamaBase);
33322
33453
  }
33323
33454
  const scored = [];
33324
33455
  for (const id of provisionedIds) {
@@ -33348,6 +33479,7 @@ async function selectBestProvisioned(role, opts) {
33348
33479
  } else {
33349
33480
  model = ollamaDefaultModelForTier(winner.tier, ramBytes);
33350
33481
  }
33482
+ model = reconcileOllamaModel(model, localModels);
33351
33483
  const catalogKey = catalogKeyForProvider2(winner.id);
33352
33484
  const catalogModel = resolveProviderDefaultModel2(catalogKey);
33353
33485
  if (!catalogModel?.startsWith("gemma4")) {
@@ -33391,6 +33523,7 @@ var init_cross_provider_selector = __esm({
33391
33523
  init_credential_pool();
33392
33524
  init_credentials2();
33393
33525
  init_credentials_store();
33526
+ init_local_inference_probe();
33394
33527
  logger3 = getLogger("llm-cross-provider-selector");
33395
33528
  BUILTIN_PROVIDER_IDS = [
33396
33529
  "anthropic",
@@ -33602,6 +33735,16 @@ async function selectProviderModel(llm, role, systemKey, profileOverride, projec
33602
33735
  source: "implicit-fallback"
33603
33736
  };
33604
33737
  }
33738
+ async function applyProviderExclusions(selected, role, projectRoot, exclude) {
33739
+ if (exclude === void 0 || exclude.length === 0) return selected;
33740
+ if (!exclude.includes(selected.provider)) return selected;
33741
+ try {
33742
+ const substitute = await selectBestProvisioned(role, { projectRoot, exclude });
33743
+ if (substitute !== null) return substitute;
33744
+ } catch {
33745
+ }
33746
+ return selected;
33747
+ }
33605
33748
  async function resolveCredentialForRole(provider, credentialLabel, projectRoot) {
33606
33749
  try {
33607
33750
  await new CredentialPool(provider).refreshExpiredOAuth();
@@ -33616,7 +33759,9 @@ async function resolveCredentialForRole(provider, credentialLabel, projectRoot)
33616
33759
  provider,
33617
33760
  apiKey: stored.accessToken,
33618
33761
  source: "cred-file",
33619
- authType: wireAuthType
33762
+ authType: wireAuthType,
33763
+ // T12081: preserve the stored endpoint (Ollama/LM Studio/vLLM/…).
33764
+ baseUrl: stored.baseUrl ?? null
33620
33765
  },
33621
33766
  usedLabel: stored.label
33622
33767
  };
@@ -33632,7 +33777,9 @@ async function resolveCredentialForRole(provider, credentialLabel, projectRoot)
33632
33777
  provider,
33633
33778
  apiKey: picked.accessToken,
33634
33779
  source: "cred-file",
33635
- authType: wireAuthType
33780
+ authType: wireAuthType,
33781
+ // T12081: preserve the stored endpoint (Ollama/LM Studio/vLLM/…).
33782
+ baseUrl: picked.baseUrl ?? null
33636
33783
  },
33637
33784
  usedLabel: picked.label
33638
33785
  };
@@ -33642,6 +33789,23 @@ async function resolveCredentialForRole(provider, credentialLabel, projectRoot)
33642
33789
  if (cred.apiKey) {
33643
33790
  return { credential: cred, usedLabel: void 0 };
33644
33791
  }
33792
+ if (provider === "ollama") {
33793
+ const local = await detectLocalInference();
33794
+ if (local !== null && local.name === "ollama") {
33795
+ return {
33796
+ credential: {
33797
+ provider,
33798
+ apiKey: LOCAL_PLACEHOLDER_TOKEN,
33799
+ source: "local-daemon",
33800
+ authType: "api_key",
33801
+ // ROOT url, not the `/v1` form: `deriveApiWire('ollama')` selects the
33802
+ // NATIVE transport, which appends `/api/chat` itself.
33803
+ baseUrl: local.baseUrl
33804
+ },
33805
+ usedLabel: void 0
33806
+ };
33807
+ }
33808
+ }
33645
33809
  return { credential: null, usedLabel: void 0 };
33646
33810
  }
33647
33811
  async function resolveLLMForRole(role, opts) {
@@ -33654,13 +33818,19 @@ async function resolveLLMForRole(role, opts) {
33654
33818
  config2 = void 0;
33655
33819
  }
33656
33820
  const llmBlock = readLlmBlock(config2);
33657
- const { provider, model, credentialLabel, source } = await selectProviderModel(
33821
+ const selected = await selectProviderModel(
33658
33822
  llmBlock,
33659
33823
  role,
33660
33824
  opts?.systemKey,
33661
33825
  opts?.profileOverride,
33662
33826
  projectRoot
33663
33827
  );
33828
+ const { provider, model, credentialLabel, source } = await applyProviderExclusions(
33829
+ selected,
33830
+ role,
33831
+ projectRoot,
33832
+ opts?.excludeProviders
33833
+ );
33664
33834
  const { credential, usedLabel } = await resolveCredentialForRole(
33665
33835
  provider,
33666
33836
  credentialLabel,
@@ -33686,7 +33856,12 @@ async function resolveLLMForRole(role, opts) {
33686
33856
  credentialMetadata = {
33687
33857
  provider: credential.provider,
33688
33858
  source: credential.source,
33689
- authType: wireAuthType
33859
+ authType: wireAuthType,
33860
+ // T12081: carry the credential's OWN endpoint. Without it a consumer
33861
+ // building a transport cannot tell that this credential targets a local
33862
+ // or proxied host, and falls back to the provider's public API — which
33863
+ // rejected every Ollama / LM Studio / vLLM / OpenRouter credential 401.
33864
+ baseUrl: credential.baseUrl ?? null
33690
33865
  };
33691
33866
  sealedCredential = makeSealedCredential({
33692
33867
  provider: credential.provider,
@@ -33714,7 +33889,7 @@ async function resolveLLMForRole(role, opts) {
33714
33889
  authType
33715
33890
  };
33716
33891
  }
33717
- var IMPLICIT_FALLBACK_PROVIDER;
33892
+ var IMPLICIT_FALLBACK_PROVIDER, LOCAL_PLACEHOLDER_TOKEN;
33718
33893
  var init_role_resolver = __esm({
33719
33894
  "packages/core/src/llm/role-resolver.ts"() {
33720
33895
  "use strict";
@@ -33725,10 +33900,12 @@ var init_role_resolver = __esm({
33725
33900
  init_credentials_store();
33726
33901
  init_cross_provider_selector();
33727
33902
  init_fallback_model();
33903
+ init_local_inference_probe();
33728
33904
  init_sealed_credential();
33729
33905
  init_system_of_use_registry();
33730
33906
  init_anthropic_client_factory();
33731
33907
  IMPLICIT_FALLBACK_PROVIDER = "anthropic";
33908
+ LOCAL_PLACEHOLDER_TOKEN = "local";
33732
33909
  }
33733
33910
  });
33734
33911
 
@@ -33983,7 +34160,9 @@ async function resolveLLMForSystem(system, opts) {
33983
34160
  systemKey,
33984
34161
  // T11759: pin a named profile (e.g. a `.cantbook` stage's `profile:`) as
33985
34162
  // the highest-priority resolution tier. Absent/incomplete → falls through.
33986
- ...opts?.profile !== void 0 ? { profileOverride: opts.profile } : {}
34163
+ ...opts?.profile !== void 0 ? { profileOverride: opts.profile } : {},
34164
+ // T12084: carry exclusions through to the provisioning-aware tier.
34165
+ ...opts?.excludeProviders !== void 0 ? { excludeProviders: opts.excludeProviders } : {}
33987
34166
  });
33988
34167
  } catch (err) {
33989
34168
  logger6.warn(
@@ -36836,9 +37015,9 @@ var init_chat_completions = __esm({
36836
37015
  outputTokens: response.usage?.completion_tokens ?? 0
36837
37016
  };
36838
37017
  const promptDetails = response.usage?.["prompt_tokens_details"];
36839
- const cached2 = promptDetails?.["cached_tokens"];
36840
- if (typeof cached2 === "number" && cached2 > 0) {
36841
- usage.cachedTokens = cached2;
37018
+ const cached3 = promptDetails?.["cached_tokens"];
37019
+ if (typeof cached3 === "number" && cached3 > 0) {
37020
+ usage.cachedTokens = cached3;
36842
37021
  }
36843
37022
  return {
36844
37023
  id: response.id ?? `chat-${Date.now().toString(36)}`,
@@ -37080,9 +37259,9 @@ function normalizeUsage(usage) {
37080
37259
  const outputTokens = usage["output_tokens"] ?? 0;
37081
37260
  const normalized = { inputTokens, outputTokens };
37082
37261
  const details = usage["input_tokens_details"];
37083
- const cached2 = details?.["cached_tokens"];
37084
- if (typeof cached2 === "number" && cached2 > 0) {
37085
- normalized.cachedTokens = cached2;
37262
+ const cached3 = details?.["cached_tokens"];
37263
+ if (typeof cached3 === "number" && cached3 > 0) {
37264
+ normalized.cachedTokens = cached3;
37086
37265
  }
37087
37266
  return normalized;
37088
37267
  }
@@ -38804,7 +38983,7 @@ __export(util_exports, {
38804
38983
  assignProp: () => assignProp,
38805
38984
  base64ToUint8Array: () => base64ToUint8Array,
38806
38985
  base64urlToUint8Array: () => base64urlToUint8Array,
38807
- cached: () => cached,
38986
+ cached: () => cached2,
38808
38987
  captureStackTrace: () => captureStackTrace,
38809
38988
  cleanEnum: () => cleanEnum,
38810
38989
  cleanRegex: () => cleanRegex,
@@ -38880,7 +39059,7 @@ function jsonStringifyReplacer(_, value) {
38880
39059
  return value.toString();
38881
39060
  return value;
38882
39061
  }
38883
- function cached(getter) {
39062
+ function cached2(getter) {
38884
39063
  const set2 = false;
38885
39064
  return {
38886
39065
  get value() {
@@ -39396,7 +39575,7 @@ var init_util = __esm({
39396
39575
  EVALUATING = /* @__PURE__ */ Symbol("evaluating");
39397
39576
  captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {
39398
39577
  };
39399
- allowsEval = cached(() => {
39578
+ allowsEval = cached2(() => {
39400
39579
  if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) {
39401
39580
  return false;
39402
39581
  }
@@ -41463,7 +41642,7 @@ var init_schemas = __esm({
41463
41642
  }
41464
41643
  });
41465
41644
  }
41466
- const _normalized = cached(() => normalizeDef(def2));
41645
+ const _normalized = cached2(() => normalizeDef(def2));
41467
41646
  defineLazy(inst._zod, "propValues", () => {
41468
41647
  const shape = def2.shape;
41469
41648
  const propValues = {};
@@ -41514,7 +41693,7 @@ var init_schemas = __esm({
41514
41693
  $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def2) => {
41515
41694
  $ZodObject.init(inst, def2);
41516
41695
  const superParse = inst._zod.parse;
41517
- const _normalized = cached(() => normalizeDef(def2));
41696
+ const _normalized = cached2(() => normalizeDef(def2));
41518
41697
  const generateFastpass = (shape) => {
41519
41698
  const doc = new Doc(["shape", "payload", "ctx"]);
41520
41699
  const normalized = _normalized.value;
@@ -41706,7 +41885,7 @@ var init_schemas = __esm({
41706
41885
  }
41707
41886
  return propValues;
41708
41887
  });
41709
- const disc = cached(() => {
41888
+ const disc = cached2(() => {
41710
41889
  const opts = def2.options;
41711
41890
  const map2 = /* @__PURE__ */ new Map();
41712
41891
  for (const o of opts) {
@@ -66256,8 +66435,8 @@ var init_model_runner = __esm({
66256
66435
  });
66257
66436
 
66258
66437
  // packages/core/src/selfimprove/fix-gen.ts
66259
- import { writeFileSync as writeFileSync11 } from "node:fs";
66260
- import { resolve as resolvePath2 } from "node:path";
66438
+ import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
66439
+ import { dirname as dirname13, join as join34, resolve as resolvePath2 } from "node:path";
66261
66440
  import { cwd as processCwd } from "node:process";
66262
66441
 
66263
66442
  // packages/utils/src/redact.ts
@@ -66519,7 +66698,7 @@ var FIXGEN_SYSTEM = "task-executor";
66519
66698
  var UNIFIED_DIFF_MARKERS = ["diff --git ", "--- ", "+++ ", "@@ "];
66520
66699
  function fixPatchPath(scenario, cwd) {
66521
66700
  const safeScenario = scenario.replace(/[^a-z0-9-]/gi, "-");
66522
- return resolvePath2(cwd ?? processCwd(), `selfimprove-${safeScenario}.patch`);
66701
+ return resolvePath2(cwd ?? processCwd(), join34(".cleo", "selfimprove", `${safeScenario}.patch`));
66523
66702
  }
66524
66703
  function looksLikeUnifiedDiff(text2) {
66525
66704
  if (text2.trim().length === 0) return false;
@@ -66604,6 +66783,7 @@ async function generateFixPatch(opts) {
66604
66783
  }
66605
66784
  const diff = output.diff.endsWith("\n") ? output.diff : `${output.diff}
66606
66785
  `;
66786
+ mkdirSync12(dirname13(patchPath), { recursive: true });
66607
66787
  writeFileSync11(patchPath, diff, "utf8");
66608
66788
  const bytes = Buffer.byteLength(diff, "utf8");
66609
66789
  logger8.info(
@@ -66612,6 +66792,7 @@ async function generateFixPatch(opts) {
66612
66792
  );
66613
66793
  return { kind: "written", patchPath, bytes, model: output.model };
66614
66794
  }
66795
+ var MAX_FIXGEN_FAILOVERS = 2;
66615
66796
  function createLlmFixGenerator(opts = {}) {
66616
66797
  return {
66617
66798
  async propose(request) {
@@ -66619,49 +66800,68 @@ function createLlmFixGenerator(opts = {}) {
66619
66800
  const { resolveLLMForSystem: resolveLLMForSystem2 } = await Promise.resolve().then(() => (init_system_resolver2(), system_resolver_exports));
66620
66801
  const { ModelRunner: ModelRunner2 } = await Promise.resolve().then(() => (init_model_runner(), model_runner_exports));
66621
66802
  const projectRoot = opts.projectRoot ?? request.repoContext.projectRoot;
66622
- const resolved = await resolveLLMForSystem2(FIXGEN_SYSTEM, { projectRoot });
66623
- if (!resolved.sealedCredential && resolved.authType !== "aws_sdk") {
66624
- return { kind: "none", reason: "no-credential-resolved" };
66625
- }
66626
- const apiKey = resolved.sealedCredential ? (await resolved.sealedCredential.fetch()).value : null;
66627
- const built = await ModelRunner2.build({
66628
- provider: resolved.provider,
66629
- model: resolved.model,
66630
- credential: resolved.credential ? {
66631
- provider: resolved.credential.provider,
66632
- apiKey,
66633
- source: resolved.credential.source,
66634
- authType: resolved.credential.authType
66635
- } : null,
66636
- source: resolved.source,
66637
- ...resolved.credentialLabel !== void 0 ? { credentialLabel: resolved.credentialLabel } : {},
66638
- apiMode: resolved.apiMode,
66639
- baseUrl: resolved.baseUrl,
66640
- authType: resolved.authType,
66641
- ...resolved.capabilities !== void 0 ? { capabilities: resolved.capabilities } : {}
66642
- });
66643
- const { system, user } = buildFixGenPrompt(request);
66644
- try {
66645
- const response = await built.session.send([{ role: "user", content: user }], {
66646
- systemSuffix: system
66803
+ const excludeProviders = [];
66804
+ for (let attempt = 0; attempt <= MAX_FIXGEN_FAILOVERS; attempt++) {
66805
+ const resolved = await resolveLLMForSystem2(FIXGEN_SYSTEM, {
66806
+ projectRoot,
66807
+ excludeProviders: [...excludeProviders]
66647
66808
  });
66648
- const text2 = (response.content ?? "").trim();
66649
- if (text2.length === 0 || text2 === "NO_PATCH") {
66650
- const rawReply = text2.length > 0 ? truncateReply(text2) : void 0;
66651
- return {
66652
- kind: "none",
66653
- reason: "model-declined",
66654
- ...rawReply !== void 0 ? { rawReply } : {}
66655
- };
66809
+ if (!resolved.sealedCredential && resolved.authType !== "aws_sdk") {
66810
+ return { kind: "none", reason: "no-credential-resolved" };
66811
+ }
66812
+ if (excludeProviders.includes(resolved.provider)) {
66813
+ return { kind: "none", reason: "llm-call-failed" };
66814
+ }
66815
+ const apiKey = resolved.sealedCredential ? (await resolved.sealedCredential.fetch()).value : null;
66816
+ const built = await ModelRunner2.build({
66817
+ provider: resolved.provider,
66818
+ model: resolved.model,
66819
+ credential: resolved.credential ? {
66820
+ provider: resolved.credential.provider,
66821
+ apiKey,
66822
+ source: resolved.credential.source,
66823
+ authType: resolved.credential.authType
66824
+ } : null,
66825
+ source: resolved.source,
66826
+ ...resolved.credentialLabel !== void 0 ? { credentialLabel: resolved.credentialLabel } : {},
66827
+ apiMode: resolved.apiMode,
66828
+ baseUrl: resolved.baseUrl,
66829
+ authType: resolved.authType,
66830
+ ...resolved.capabilities !== void 0 ? { capabilities: resolved.capabilities } : {}
66831
+ });
66832
+ const { system, user } = buildFixGenPrompt(request);
66833
+ try {
66834
+ const response = await built.session.send([{ role: "user", content: user }], {
66835
+ systemSuffix: system
66836
+ });
66837
+ const text2 = (response.content ?? "").trim();
66838
+ if (text2.length === 0 || text2 === "NO_PATCH") {
66839
+ const rawReply = text2.length > 0 ? truncateReply(text2) : void 0;
66840
+ return {
66841
+ kind: "none",
66842
+ reason: "model-declined",
66843
+ ...rawReply !== void 0 ? { rawReply } : {}
66844
+ };
66845
+ }
66846
+ return { kind: "patch", diff: stripCodeFences(text2), model: response.model };
66847
+ } catch (err) {
66848
+ logger8.warn(
66849
+ {
66850
+ system: FIXGEN_SYSTEM,
66851
+ provider: resolved.provider,
66852
+ model: resolved.model,
66853
+ attempt: attempt + 1,
66854
+ err: err instanceof Error ? err.message : String(err)
66855
+ },
66856
+ attempt < MAX_FIXGEN_FAILOVERS ? "fix-gen LLM call failed \u2014 failing over to another provider" : "fix-gen LLM call failed \u2014 degrading to no-patch"
66857
+ );
66858
+ if (attempt >= MAX_FIXGEN_FAILOVERS) {
66859
+ return { kind: "none", reason: "llm-call-failed" };
66860
+ }
66861
+ excludeProviders.push(resolved.provider);
66656
66862
  }
66657
- return { kind: "patch", diff: stripCodeFences(text2), model: response.model };
66658
- } catch (err) {
66659
- logger8.warn(
66660
- { system: FIXGEN_SYSTEM, err: err instanceof Error ? err.message : String(err) },
66661
- "fix-gen LLM call failed \u2014 degrading to no-patch"
66662
- );
66663
- return { kind: "none", reason: "llm-call-failed" };
66664
66863
  }
66864
+ return { kind: "none", reason: "llm-call-failed" };
66665
66865
  }
66666
66866
  };
66667
66867
  }