@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.
- package/dist/check/pr-gate.d.ts.map +1 -1
- package/dist/check/pr-gate.js +9 -0
- package/dist/check/pr-gate.js.map +1 -1
- package/dist/docs/export-document.js +66 -16
- package/dist/docs/export-document.js.map +3 -3
- package/dist/doctor/index.d.ts +2 -0
- package/dist/doctor/index.d.ts.map +1 -1
- package/dist/doctor/index.js +1 -0
- package/dist/doctor/index.js.map +1 -1
- package/dist/doctor/superseded-store.d.ts +101 -0
- package/dist/doctor/superseded-store.d.ts.map +1 -0
- package/dist/doctor/superseded-store.js +156 -0
- package/dist/doctor/superseded-store.js.map +1 -0
- package/dist/hooks/registry.d.ts +2 -2
- package/dist/hooks/registry.d.ts.map +1 -1
- package/dist/hooks/registry.js +5 -0
- package/dist/hooks/registry.js.map +1 -1
- package/dist/hooks/types.d.ts +59 -0
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/init/scaffold-workflows.d.ts +12 -0
- package/dist/init/scaffold-workflows.d.ts.map +1 -1
- package/dist/init/scaffold-workflows.js +16 -0
- package/dist/init/scaffold-workflows.js.map +1 -1
- package/dist/init/upgrade-workflows.d.ts.map +1 -1
- package/dist/init/upgrade-workflows.js +16 -0
- package/dist/init/upgrade-workflows.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +16 -1
- package/dist/init.js.map +1 -1
- package/dist/internal.d.ts +1 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -0
- package/dist/internal.js.map +1 -1
- package/dist/llm/credentials.d.ts +16 -1
- package/dist/llm/credentials.d.ts.map +1 -1
- package/dist/llm/credentials.js.map +1 -1
- package/dist/llm/cross-provider-selector.d.ts +25 -0
- package/dist/llm/cross-provider-selector.d.ts.map +1 -1
- package/dist/llm/cross-provider-selector.js +76 -3
- package/dist/llm/cross-provider-selector.js.map +1 -1
- package/dist/llm/local-inference-probe.d.ts +101 -0
- package/dist/llm/local-inference-probe.d.ts.map +1 -0
- package/dist/llm/local-inference-probe.js +174 -0
- package/dist/llm/local-inference-probe.js.map +1 -0
- package/dist/llm/plugin-facade.js +199 -21
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/llm/role-executor.d.ts.map +1 -1
- package/dist/llm/role-executor.js +95 -9
- package/dist/llm/role-executor.js.map +1 -1
- package/dist/llm/role-resolver.d.ts +10 -0
- package/dist/llm/role-resolver.d.ts.map +1 -1
- package/dist/llm/role-resolver.js +92 -1
- package/dist/llm/role-resolver.js.map +1 -1
- package/dist/llm/system-resolver.d.ts.map +1 -1
- package/dist/llm/system-resolver.js +2 -0
- package/dist/llm/system-resolver.js.map +1 -1
- package/dist/memory/brain-search.d.ts +109 -0
- package/dist/memory/brain-search.d.ts.map +1 -1
- package/dist/memory/brain-search.js +149 -37
- package/dist/memory/brain-search.js.map +1 -1
- package/dist/memory/brain-stub-prune.d.ts +109 -0
- package/dist/memory/brain-stub-prune.d.ts.map +1 -0
- package/dist/memory/brain-stub-prune.js +155 -0
- package/dist/memory/brain-stub-prune.js.map +1 -0
- package/dist/memory/engine-compat.d.ts.map +1 -1
- package/dist/memory/engine-compat.js +61 -3
- package/dist/memory/engine-compat.js.map +1 -1
- package/dist/nexus/analyze-orchestrator.d.ts.map +1 -1
- package/dist/nexus/analyze-orchestrator.js +28 -0
- package/dist/nexus/analyze-orchestrator.js.map +1 -1
- package/dist/nexus/context.d.ts.map +1 -1
- package/dist/nexus/context.js +3 -3
- package/dist/nexus/context.js.map +1 -1
- package/dist/nexus/impact.d.ts.map +1 -1
- package/dist/nexus/impact.js +3 -3
- package/dist/nexus/impact.js.map +1 -1
- package/dist/nexus/symbol-miss.d.ts +132 -0
- package/dist/nexus/symbol-miss.d.ts.map +1 -0
- package/dist/nexus/symbol-miss.js +168 -0
- package/dist/nexus/symbol-miss.js.map +1 -0
- package/dist/orchestrate/spawn-ops.d.ts +21 -1
- package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
- package/dist/orchestrate/spawn-ops.js +39 -2
- package/dist/orchestrate/spawn-ops.js.map +1 -1
- package/dist/orchestrate/worker-verify.d.ts.map +1 -1
- package/dist/orchestrate/worker-verify.js +22 -0
- package/dist/orchestrate/worker-verify.js.map +1 -1
- package/dist/release/changesets-aggregator.d.ts.map +1 -1
- package/dist/release/changesets-aggregator.js +15 -1
- package/dist/release/changesets-aggregator.js.map +1 -1
- package/dist/release/open.d.ts +29 -2
- package/dist/release/open.d.ts.map +1 -1
- package/dist/release/open.js +48 -11
- package/dist/release/open.js.map +1 -1
- package/dist/resources/governor.d.ts +12 -2
- package/dist/resources/governor.d.ts.map +1 -1
- package/dist/resources/governor.js +12 -3
- package/dist/resources/governor.js.map +1 -1
- package/dist/scaffold/ensure-dirs.d.ts.map +1 -1
- package/dist/scaffold/ensure-dirs.js +14 -2
- package/dist/scaffold/ensure-dirs.js.map +1 -1
- package/dist/scaffold/project-detection.d.ts.map +1 -1
- package/dist/scaffold/project-detection.js +2 -1
- package/dist/scaffold/project-detection.js.map +1 -1
- package/dist/selfimprove/draft-pr.d.ts +14 -1
- package/dist/selfimprove/draft-pr.d.ts.map +1 -1
- package/dist/selfimprove/draft-pr.js.map +1 -1
- package/dist/selfimprove/fix-gen.d.ts +0 -21
- package/dist/selfimprove/fix-gen.d.ts.map +1 -1
- package/dist/selfimprove/fix-gen.js +276 -76
- package/dist/selfimprove/fix-gen.js.map +3 -3
- package/dist/selfimprove/run-loop.d.ts.map +1 -1
- package/dist/selfimprove/run-loop.js +50 -19
- package/dist/selfimprove/run-loop.js.map +1 -1
- package/dist/selfimprove/scenarios/dhq-replay-find/golden.json +114 -4
- package/dist/selfimprove/scenarios/dhq-replay-find/scenario.json +3 -3
- package/dist/sentient/dream-cycle.d.ts +20 -19
- package/dist/sentient/dream-cycle.d.ts.map +1 -1
- package/dist/sentient/dream-cycle.js +322 -11
- package/dist/sentient/dream-cycle.js.map +1 -1
- package/dist/sentient/dream-watermark.d.ts +134 -0
- package/dist/sentient/dream-watermark.d.ts.map +1 -0
- package/dist/sentient/dream-watermark.js +156 -0
- package/dist/sentient/dream-watermark.js.map +1 -0
- package/dist/sentient/state.d.ts +17 -0
- package/dist/sentient/state.d.ts.map +1 -1
- package/dist/sentient/state.js +22 -3
- package/dist/sentient/state.js.map +1 -1
- package/dist/sentient/tick.d.ts.map +1 -1
- package/dist/sentient/tick.js +79 -2
- package/dist/sentient/tick.js.map +1 -1
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +5 -1
- package/dist/sessions/index.js.map +1 -1
- package/dist/sessions/snapshot.d.ts.map +1 -1
- package/dist/sessions/snapshot.js +6 -3
- package/dist/sessions/snapshot.js.map +1 -1
- package/dist/store/checkpoint-git-dir.d.ts +95 -0
- package/dist/store/checkpoint-git-dir.d.ts.map +1 -0
- package/dist/store/checkpoint-git-dir.js +111 -0
- package/dist/store/checkpoint-git-dir.js.map +1 -0
- package/dist/store/git-checkpoint.d.ts.map +1 -1
- package/dist/store/git-checkpoint.js +6 -5
- package/dist/store/git-checkpoint.js.map +1 -1
- package/dist/system/health.d.ts.map +1 -1
- package/dist/system/health.js +2 -1
- package/dist/system/health.js.map +1 -1
- package/dist/tasks/add.d.ts.map +1 -1
- package/dist/tasks/add.js +40 -4
- package/dist/tasks/add.js.map +1 -1
- package/dist/tasks/collection.d.ts +51 -0
- package/dist/tasks/collection.d.ts.map +1 -0
- package/dist/tasks/collection.js +81 -0
- package/dist/tasks/collection.js.map +1 -0
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +8 -3
- package/dist/tasks/complete.js.map +1 -1
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js +17 -0
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/tasks/find.d.ts +50 -0
- package/dist/tasks/find.d.ts.map +1 -1
- package/dist/tasks/find.js +63 -2
- package/dist/tasks/find.js.map +1 -1
- package/dist/tasks/heavy-tool-env.d.ts +112 -0
- package/dist/tasks/heavy-tool-env.d.ts.map +1 -0
- package/dist/tasks/heavy-tool-env.js +133 -0
- package/dist/tasks/heavy-tool-env.js.map +1 -0
- package/dist/tasks/index.d.ts +2 -0
- package/dist/tasks/index.d.ts.map +1 -1
- package/dist/tasks/index.js +1 -0
- package/dist/tasks/index.js.map +1 -1
- package/dist/tasks/tool-cache.d.ts.map +1 -1
- package/dist/tasks/tool-cache.js +9 -3
- package/dist/tasks/tool-cache.js.map +1 -1
- package/dist/tasks/tool-resolver.d.ts +1 -1
- package/dist/tasks/tool-resolver.d.ts.map +1 -1
- package/dist/tasks/tool-resolver.js +83 -0
- package/dist/tasks/tool-resolver.js.map +1 -1
- package/dist/tasks/tool-semaphore.d.ts +82 -12
- package/dist/tasks/tool-semaphore.d.ts.map +1 -1
- package/dist/tasks/tool-semaphore.js +79 -17
- package/dist/tasks/tool-semaphore.js.map +1 -1
- package/package.json +13 -13
- package/templates/CLEO-INJECTION.md +55 -22
- package/templates/workflows/release-prepare.yml.tmpl +73 -16
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime detection of a reachable local inference server (T12082).
|
|
3
|
+
*
|
|
4
|
+
* ## Why CLEO should find this by itself
|
|
5
|
+
*
|
|
6
|
+
* The auxiliary fallback chain exists so that "context compression, brain dream
|
|
7
|
+
* cycles, hygiene scans" do not fail silently when the primary provider is
|
|
8
|
+
* unavailable. Its default chain is `anthropic → openrouter → groq` — all
|
|
9
|
+
* cloud. When every cloud credential is unusable, the chain is exhausted and
|
|
10
|
+
* the capability simply stops.
|
|
11
|
+
*
|
|
12
|
+
* That is exactly the state this machine was in on 2026-08-06: the anthropic
|
|
13
|
+
* credential was consent-gated, the openai one returned 401 — and an Ollama
|
|
14
|
+
* server was running the whole time with `qwen2.5-coder:3b` loaded. The dream
|
|
15
|
+
* cycle reported "no usable LLM client" while free local inference sat one
|
|
16
|
+
* HTTP request away. Nothing was broken except that nobody looked.
|
|
17
|
+
*
|
|
18
|
+
* A background consolidation pass is precisely the workload that should degrade
|
|
19
|
+
* to a small local model rather than stop: it is not latency-critical, it is
|
|
20
|
+
* not user-facing, and a shallow synthesis is worth more than none. So the
|
|
21
|
+
* chain now ends with a local tier that is included ONLY when a server actually
|
|
22
|
+
* answers.
|
|
23
|
+
*
|
|
24
|
+
* ## Why a probe rather than a config flag
|
|
25
|
+
*
|
|
26
|
+
* A config flag would need the operator to know their own machine's state and
|
|
27
|
+
* keep it current. A 300 ms probe against loopback is cheap, is cached for the
|
|
28
|
+
* process, and is correct by construction — it reports what is true now.
|
|
29
|
+
*
|
|
30
|
+
* @task T12082
|
|
31
|
+
*/
|
|
32
|
+
/** Loopback endpoints checked, in order. Ollama first — it is the common case. */
|
|
33
|
+
const LOCAL_ENDPOINTS = [
|
|
34
|
+
{
|
|
35
|
+
name: 'ollama',
|
|
36
|
+
tagsUrl: 'http://127.0.0.1:11434/api/tags',
|
|
37
|
+
baseUrl: 'http://127.0.0.1:11434',
|
|
38
|
+
openAiBaseUrl: 'http://127.0.0.1:11434/v1',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'lm-studio',
|
|
42
|
+
tagsUrl: 'http://127.0.0.1:1234/v1/models',
|
|
43
|
+
baseUrl: 'http://127.0.0.1:1234',
|
|
44
|
+
openAiBaseUrl: 'http://127.0.0.1:1234/v1',
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
/** Probe timeout. Loopback either answers immediately or is not there. */
|
|
48
|
+
const PROBE_TIMEOUT_MS = 300;
|
|
49
|
+
/** Process-lifetime cache — `undefined` = not yet probed, `null` = none found. */
|
|
50
|
+
let cached;
|
|
51
|
+
/**
|
|
52
|
+
* Extract model ids from either an Ollama `/api/tags` or an OpenAI `/v1/models`
|
|
53
|
+
* payload, whichever shape came back.
|
|
54
|
+
*
|
|
55
|
+
* @param body - parsed JSON response.
|
|
56
|
+
* @returns model ids, possibly empty.
|
|
57
|
+
*/
|
|
58
|
+
function extractModels(body) {
|
|
59
|
+
if (body === null || typeof body !== 'object')
|
|
60
|
+
return [];
|
|
61
|
+
const rec = body;
|
|
62
|
+
// Ollama: { models: [{ name, model, … }] }
|
|
63
|
+
if (Array.isArray(rec.models)) {
|
|
64
|
+
return rec.models
|
|
65
|
+
.map((m) => m !== null && typeof m === 'object'
|
|
66
|
+
? (m.name ?? m.model)
|
|
67
|
+
: undefined)
|
|
68
|
+
.filter((n) => typeof n === 'string');
|
|
69
|
+
}
|
|
70
|
+
// OpenAI-compatible: { data: [{ id }] }
|
|
71
|
+
if (Array.isArray(rec.data)) {
|
|
72
|
+
return rec.data
|
|
73
|
+
.map((m) => (m !== null && typeof m === 'object' ? m.id : undefined))
|
|
74
|
+
.filter((n) => typeof n === 'string');
|
|
75
|
+
}
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Detect a reachable local inference server with at least one model loaded.
|
|
80
|
+
*
|
|
81
|
+
* Cached for the process lifetime: a background tick may consult this many
|
|
82
|
+
* times and the answer does not change mid-run in practice.
|
|
83
|
+
*
|
|
84
|
+
* Never throws — a probe failure means "not available", which is a normal
|
|
85
|
+
* result rather than an error.
|
|
86
|
+
*
|
|
87
|
+
* @param opts - `force` re-probes, ignoring the cache (tests).
|
|
88
|
+
* @returns the detected server, or `null` when none answers.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* const local = await detectLocalInference();
|
|
93
|
+
* if (local) console.log(`${local.name} has ${local.models.length} model(s)`);
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @task T12082
|
|
97
|
+
*/
|
|
98
|
+
export async function detectLocalInference(opts = {}) {
|
|
99
|
+
// Operator opt-out. Two audiences: someone on a shared or metered box who
|
|
100
|
+
// does not want background work routed to a daemon they run for other
|
|
101
|
+
// purposes, and the test suite — which must produce the same result whether
|
|
102
|
+
// or not the developer happens to have Ollama running.
|
|
103
|
+
if (process.env['CLEO_DISABLE_LOCAL_INFERENCE']?.trim())
|
|
104
|
+
return null;
|
|
105
|
+
if (!opts.force && cached !== undefined)
|
|
106
|
+
return cached;
|
|
107
|
+
for (const endpoint of LOCAL_ENDPOINTS) {
|
|
108
|
+
try {
|
|
109
|
+
const response = await fetch(endpoint.tagsUrl, {
|
|
110
|
+
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
|
|
111
|
+
});
|
|
112
|
+
if (!response.ok)
|
|
113
|
+
continue;
|
|
114
|
+
const models = extractModels(await response.json());
|
|
115
|
+
// A server with no models loaded cannot serve a completion, so it is not
|
|
116
|
+
// a usable fallback — treat it as absent rather than advertising it.
|
|
117
|
+
if (models.length === 0)
|
|
118
|
+
continue;
|
|
119
|
+
cached = {
|
|
120
|
+
name: endpoint.name,
|
|
121
|
+
baseUrl: endpoint.baseUrl,
|
|
122
|
+
openAiBaseUrl: endpoint.openAiBaseUrl,
|
|
123
|
+
models,
|
|
124
|
+
};
|
|
125
|
+
return cached;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Unreachable / timed out / non-JSON — try the next endpoint.
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
cached = null;
|
|
132
|
+
return cached;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* List the models an Ollama daemon actually has pulled.
|
|
136
|
+
*
|
|
137
|
+
* The cross-provider selector picks an Ollama model from a RAM heuristic
|
|
138
|
+
* alone, which answers "what could this machine run", not "what is installed".
|
|
139
|
+
* Those differ constantly — this machine has 62 GB of RAM and therefore scored
|
|
140
|
+
* into the `gemma4:e4b` tier while holding only `qwen2.5-coder:3b` and
|
|
141
|
+
* `qwen2:0.5b`, so the resolved model would have 404'd at the daemon. The fit
|
|
142
|
+
* heuristic is still right; it just has to be intersected with reality.
|
|
143
|
+
*
|
|
144
|
+
* Not cached — the installed set changes whenever the operator pulls a model,
|
|
145
|
+
* and the call is one loopback request.
|
|
146
|
+
*
|
|
147
|
+
* Never throws.
|
|
148
|
+
*
|
|
149
|
+
* @param baseUrl - Ollama root URL, e.g. `http://localhost:11434` (no `/v1`).
|
|
150
|
+
* @returns installed model ids in daemon order, empty when unreachable.
|
|
151
|
+
*
|
|
152
|
+
* @task T12082
|
|
153
|
+
*/
|
|
154
|
+
export async function listOllamaModels(baseUrl) {
|
|
155
|
+
try {
|
|
156
|
+
const url = `${baseUrl.replace(/\/+$/, '')}/api/tags`;
|
|
157
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(PROBE_TIMEOUT_MS) });
|
|
158
|
+
if (!response.ok)
|
|
159
|
+
return [];
|
|
160
|
+
return extractModels(await response.json());
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Clear the probe cache. Tests only.
|
|
168
|
+
*
|
|
169
|
+
* @task T12082
|
|
170
|
+
*/
|
|
171
|
+
export function _resetLocalInferenceCacheForTests() {
|
|
172
|
+
cached = undefined;
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=local-inference-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-inference-probe.js","sourceRoot":"","sources":["../../src/llm/local-inference-probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -10043,6 +10043,27 @@ var init_operations_registry = __esm({
|
|
|
10043
10043
|
type: "boolean",
|
|
10044
10044
|
required: false,
|
|
10045
10045
|
description: "Commit plan file before dispatching"
|
|
10046
|
+
},
|
|
10047
|
+
// T12089: the plan SCOPE. The workflow regenerates the plan when no
|
|
10048
|
+
// committed plan is supplied, and `cleo release plan` requires
|
|
10049
|
+
// `--saga | --epic | --tasks` — so without one of these the dispatched
|
|
10050
|
+
// run dies at "Prepare bump-PR" after a fully green preflight.
|
|
10051
|
+
//
|
|
10052
|
+
// A param absent from this registry is STRIPPED before the domain handler
|
|
10053
|
+
// sees it, silently. `--tasks` was accepted by the CLI, forwarded by the
|
|
10054
|
+
// handler and by `releaseOpen`, and still arrived empty at the workflow
|
|
10055
|
+
// because this declaration was the fourth hop in the chain.
|
|
10056
|
+
{
|
|
10057
|
+
name: "epic",
|
|
10058
|
+
type: "string",
|
|
10059
|
+
required: false,
|
|
10060
|
+
description: "Epic task ID forwarded as the plan scope (e.g. T9999)"
|
|
10061
|
+
},
|
|
10062
|
+
{
|
|
10063
|
+
name: "tasks",
|
|
10064
|
+
type: "string",
|
|
10065
|
+
required: false,
|
|
10066
|
+
description: "Comma-separated task IDs forwarded as the plan scope for a task-scoped release"
|
|
10046
10067
|
}
|
|
10047
10068
|
]
|
|
10048
10069
|
},
|
|
@@ -15734,6 +15755,13 @@ var init_caamp_markers = __esm({
|
|
|
15734
15755
|
}
|
|
15735
15756
|
});
|
|
15736
15757
|
|
|
15758
|
+
// packages/contracts/src/collection-keys.ts
|
|
15759
|
+
var init_collection_keys = __esm({
|
|
15760
|
+
"packages/contracts/src/collection-keys.ts"() {
|
|
15761
|
+
"use strict";
|
|
15762
|
+
}
|
|
15763
|
+
});
|
|
15764
|
+
|
|
15737
15765
|
// packages/contracts/src/index.ts
|
|
15738
15766
|
var init_src = __esm({
|
|
15739
15767
|
"packages/contracts/src/index.ts"() {
|
|
@@ -15802,6 +15830,7 @@ var init_src = __esm({
|
|
|
15802
15830
|
init_service_provider();
|
|
15803
15831
|
init_workgraph();
|
|
15804
15832
|
init_caamp_markers();
|
|
15833
|
+
init_collection_keys();
|
|
15805
15834
|
}
|
|
15806
15835
|
});
|
|
15807
15836
|
|
|
@@ -24483,7 +24512,9 @@ function computeClassBudget(cls, sample, opts = {}) {
|
|
|
24483
24512
|
return Math.max(1, cpus - 2);
|
|
24484
24513
|
case "test-run":
|
|
24485
24514
|
case "scoped-build": {
|
|
24486
|
-
const
|
|
24515
|
+
const estRamBytes = (opts.testRunEstRamMb ?? 24576) * MB;
|
|
24516
|
+
const byMem = Math.floor((availBytes - headroomBytes) / estRamBytes);
|
|
24517
|
+
const base = clamp(1, byMem, Math.max(1, Math.floor(cpus / 4)));
|
|
24487
24518
|
if (some > floor) return 1;
|
|
24488
24519
|
if (some > hold) return Math.max(1, Math.floor(base / 2));
|
|
24489
24520
|
return base;
|
|
@@ -24976,6 +25007,11 @@ var init_registry = __esm({
|
|
|
24976
25007
|
* });
|
|
24977
25008
|
* ```
|
|
24978
25009
|
*/
|
|
25010
|
+
// T12071: keyed on the EVENT so the payload shape is checked against
|
|
25011
|
+
// `HookEventPayloadMap`. The previous `<T extends HookPayload>` form inferred
|
|
25012
|
+
// T from the argument, relating the event and the payload not at all — which
|
|
25013
|
+
// is how `PostToolUse` came to be dispatched with `newStatus` instead of
|
|
25014
|
+
// `status` and filled 29% of BRAIN with "status: undefined".
|
|
24979
25015
|
async dispatch(event, projectRoot, payload) {
|
|
24980
25016
|
if (!this.config.enabled) return;
|
|
24981
25017
|
const resolvedEvent = this.resolveEvent(event);
|
|
@@ -28257,8 +28293,8 @@ function reuseValid(key, store) {
|
|
|
28257
28293
|
return row;
|
|
28258
28294
|
}
|
|
28259
28295
|
async function bindAgainst(key, store, establish) {
|
|
28260
|
-
const
|
|
28261
|
-
if (
|
|
28296
|
+
const cached3 = reuseValid(key, store);
|
|
28297
|
+
if (cached3) return cached3;
|
|
28262
28298
|
const pending = _inflight.get(key);
|
|
28263
28299
|
if (pending) {
|
|
28264
28300
|
const row = await pending;
|
|
@@ -36067,9 +36103,9 @@ var init_chat_completions = __esm({
|
|
|
36067
36103
|
outputTokens: response.usage?.completion_tokens ?? 0
|
|
36068
36104
|
};
|
|
36069
36105
|
const promptDetails = response.usage?.["prompt_tokens_details"];
|
|
36070
|
-
const
|
|
36071
|
-
if (typeof
|
|
36072
|
-
usage.cachedTokens =
|
|
36106
|
+
const cached3 = promptDetails?.["cached_tokens"];
|
|
36107
|
+
if (typeof cached3 === "number" && cached3 > 0) {
|
|
36108
|
+
usage.cachedTokens = cached3;
|
|
36073
36109
|
}
|
|
36074
36110
|
return {
|
|
36075
36111
|
id: response.id ?? `chat-${Date.now().toString(36)}`,
|
|
@@ -36311,9 +36347,9 @@ function normalizeUsage(usage) {
|
|
|
36311
36347
|
const outputTokens = usage["output_tokens"] ?? 0;
|
|
36312
36348
|
const normalized = { inputTokens, outputTokens };
|
|
36313
36349
|
const details = usage["input_tokens_details"];
|
|
36314
|
-
const
|
|
36315
|
-
if (typeof
|
|
36316
|
-
normalized.cachedTokens =
|
|
36350
|
+
const cached3 = details?.["cached_tokens"];
|
|
36351
|
+
if (typeof cached3 === "number" && cached3 > 0) {
|
|
36352
|
+
normalized.cachedTokens = cached3;
|
|
36317
36353
|
}
|
|
36318
36354
|
return normalized;
|
|
36319
36355
|
}
|
|
@@ -65486,6 +65522,76 @@ var init_model_runner = __esm({
|
|
|
65486
65522
|
}
|
|
65487
65523
|
});
|
|
65488
65524
|
|
|
65525
|
+
// packages/core/src/llm/local-inference-probe.ts
|
|
65526
|
+
function extractModels(body) {
|
|
65527
|
+
if (body === null || typeof body !== "object") return [];
|
|
65528
|
+
const rec = body;
|
|
65529
|
+
if (Array.isArray(rec.models)) {
|
|
65530
|
+
return rec.models.map(
|
|
65531
|
+
(m) => m !== null && typeof m === "object" ? m.name ?? m.model : void 0
|
|
65532
|
+
).filter((n) => typeof n === "string");
|
|
65533
|
+
}
|
|
65534
|
+
if (Array.isArray(rec.data)) {
|
|
65535
|
+
return rec.data.map((m) => m !== null && typeof m === "object" ? m.id : void 0).filter((n) => typeof n === "string");
|
|
65536
|
+
}
|
|
65537
|
+
return [];
|
|
65538
|
+
}
|
|
65539
|
+
async function detectLocalInference(opts = {}) {
|
|
65540
|
+
if (process.env["CLEO_DISABLE_LOCAL_INFERENCE"]?.trim()) return null;
|
|
65541
|
+
if (!opts.force && cached2 !== void 0) return cached2;
|
|
65542
|
+
for (const endpoint of LOCAL_ENDPOINTS) {
|
|
65543
|
+
try {
|
|
65544
|
+
const response = await fetch(endpoint.tagsUrl, {
|
|
65545
|
+
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS)
|
|
65546
|
+
});
|
|
65547
|
+
if (!response.ok) continue;
|
|
65548
|
+
const models = extractModels(await response.json());
|
|
65549
|
+
if (models.length === 0) continue;
|
|
65550
|
+
cached2 = {
|
|
65551
|
+
name: endpoint.name,
|
|
65552
|
+
baseUrl: endpoint.baseUrl,
|
|
65553
|
+
openAiBaseUrl: endpoint.openAiBaseUrl,
|
|
65554
|
+
models
|
|
65555
|
+
};
|
|
65556
|
+
return cached2;
|
|
65557
|
+
} catch {
|
|
65558
|
+
}
|
|
65559
|
+
}
|
|
65560
|
+
cached2 = null;
|
|
65561
|
+
return cached2;
|
|
65562
|
+
}
|
|
65563
|
+
async function listOllamaModels(baseUrl) {
|
|
65564
|
+
try {
|
|
65565
|
+
const url2 = `${baseUrl.replace(/\/+$/, "")}/api/tags`;
|
|
65566
|
+
const response = await fetch(url2, { signal: AbortSignal.timeout(PROBE_TIMEOUT_MS) });
|
|
65567
|
+
if (!response.ok) return [];
|
|
65568
|
+
return extractModels(await response.json());
|
|
65569
|
+
} catch {
|
|
65570
|
+
return [];
|
|
65571
|
+
}
|
|
65572
|
+
}
|
|
65573
|
+
var LOCAL_ENDPOINTS, PROBE_TIMEOUT_MS, cached2;
|
|
65574
|
+
var init_local_inference_probe = __esm({
|
|
65575
|
+
"packages/core/src/llm/local-inference-probe.ts"() {
|
|
65576
|
+
"use strict";
|
|
65577
|
+
LOCAL_ENDPOINTS = [
|
|
65578
|
+
{
|
|
65579
|
+
name: "ollama",
|
|
65580
|
+
tagsUrl: "http://127.0.0.1:11434/api/tags",
|
|
65581
|
+
baseUrl: "http://127.0.0.1:11434",
|
|
65582
|
+
openAiBaseUrl: "http://127.0.0.1:11434/v1"
|
|
65583
|
+
},
|
|
65584
|
+
{
|
|
65585
|
+
name: "lm-studio",
|
|
65586
|
+
tagsUrl: "http://127.0.0.1:1234/v1/models",
|
|
65587
|
+
baseUrl: "http://127.0.0.1:1234",
|
|
65588
|
+
openAiBaseUrl: "http://127.0.0.1:1234/v1"
|
|
65589
|
+
}
|
|
65590
|
+
];
|
|
65591
|
+
PROBE_TIMEOUT_MS = 300;
|
|
65592
|
+
}
|
|
65593
|
+
});
|
|
65594
|
+
|
|
65489
65595
|
// packages/core/src/llm/catalog-model-resolver.ts
|
|
65490
65596
|
var catalog_model_resolver_exports = {};
|
|
65491
65597
|
__export(catalog_model_resolver_exports, {
|
|
@@ -65570,9 +65676,9 @@ var init_catalog_model_resolver = __esm({
|
|
|
65570
65676
|
// packages/core/src/llm/cross-provider-selector.ts
|
|
65571
65677
|
import { totalmem as totalmem2 } from "node:os";
|
|
65572
65678
|
async function probeOllamaAlive(baseUrl) {
|
|
65573
|
-
const
|
|
65574
|
-
if (
|
|
65575
|
-
return
|
|
65679
|
+
const cached3 = _ollamaProbeCache.get(baseUrl);
|
|
65680
|
+
if (cached3 && Date.now() - cached3.checkedAt < OLLAMA_PROBE_TTL_MS) {
|
|
65681
|
+
return cached3.alive;
|
|
65576
65682
|
}
|
|
65577
65683
|
let alive = false;
|
|
65578
65684
|
try {
|
|
@@ -65614,6 +65720,16 @@ function isProvisioned(provider) {
|
|
|
65614
65720
|
const cred = resolveCredentials(provider);
|
|
65615
65721
|
return (cred.apiKey?.trim().length ?? 0) > 0;
|
|
65616
65722
|
}
|
|
65723
|
+
function reconcileOllamaModel(preferred, installed) {
|
|
65724
|
+
if (installed.length === 0) return preferred;
|
|
65725
|
+
if (installed.includes(preferred)) return preferred;
|
|
65726
|
+
const family = preferred.split(":")[0];
|
|
65727
|
+
if (family !== void 0 && family !== "") {
|
|
65728
|
+
const sameFamily = installed.find((m) => m.split(":")[0] === family);
|
|
65729
|
+
if (sameFamily !== void 0) return sameFamily;
|
|
65730
|
+
}
|
|
65731
|
+
return installed[0] ?? preferred;
|
|
65732
|
+
}
|
|
65617
65733
|
function scoreProvider(provider, providerTier, taskTier, ollamaAlive, costInputPerMillion) {
|
|
65618
65734
|
let score = TIER_BASE[providerTier];
|
|
65619
65735
|
if (taskTier === "frontier" && providerTier === "frontier") {
|
|
@@ -65646,6 +65762,7 @@ function roleTierFor(role) {
|
|
|
65646
65762
|
}
|
|
65647
65763
|
async function selectBestProvisioned(role, opts) {
|
|
65648
65764
|
const taskTier = roleTierFor(role);
|
|
65765
|
+
const excluded = new Set(opts.exclude ?? []);
|
|
65649
65766
|
for (const id of BUILTIN_PROVIDER_IDS) {
|
|
65650
65767
|
const creds = await listCredentials(id);
|
|
65651
65768
|
const hasExpiredOAuth = creds.some(
|
|
@@ -65670,10 +65787,23 @@ async function selectBestProvisioned(role, opts) {
|
|
|
65670
65787
|
}
|
|
65671
65788
|
const provisionedIds = [];
|
|
65672
65789
|
for (const id of BUILTIN_PROVIDER_IDS) {
|
|
65790
|
+
if (excluded.has(id)) continue;
|
|
65673
65791
|
if (isProvisioned(id)) {
|
|
65674
65792
|
provisionedIds.push(id);
|
|
65675
65793
|
}
|
|
65676
65794
|
}
|
|
65795
|
+
let localModels = [];
|
|
65796
|
+
if (!excluded.has("ollama") && !provisionedIds.includes("ollama")) {
|
|
65797
|
+
const local = await detectLocalInference();
|
|
65798
|
+
if (local !== null && local.name === "ollama") {
|
|
65799
|
+
provisionedIds.push("ollama");
|
|
65800
|
+
localModels = local.models;
|
|
65801
|
+
logger4.debug(
|
|
65802
|
+
{ baseUrl: local.baseUrl, models: local.models },
|
|
65803
|
+
"cross-provider-selector: unlisted ollama daemon is live \u2014 admitting as provisioned"
|
|
65804
|
+
);
|
|
65805
|
+
}
|
|
65806
|
+
}
|
|
65677
65807
|
if (provisionedIds.length === 0) {
|
|
65678
65808
|
logger4.warn(
|
|
65679
65809
|
{
|
|
@@ -65690,11 +65820,12 @@ async function selectBestProvisioned(role, opts) {
|
|
|
65690
65820
|
const { resolveProviderDefaultModel: resolveProviderDefaultModel2, catalogKeyForProvider: catalogKeyForProvider2 } = await Promise.resolve().then(() => (init_catalog_model_resolver(), catalog_model_resolver_exports));
|
|
65691
65821
|
const { pickCredentialForProvider: pickCredentialForProvider2 } = await Promise.resolve().then(() => (init_credentials_store(), credentials_store_exports));
|
|
65692
65822
|
const ollamaProvisioned = provisionedIds.includes("ollama");
|
|
65693
|
-
let ollamaAlive =
|
|
65694
|
-
if (ollamaProvisioned) {
|
|
65823
|
+
let ollamaAlive = localModels.length > 0;
|
|
65824
|
+
if (ollamaProvisioned && !ollamaAlive) {
|
|
65695
65825
|
const profile = await getProviderProfile2("ollama");
|
|
65696
65826
|
const ollamaBase = profile?.baseUrl ?? "http://localhost:11434";
|
|
65697
65827
|
ollamaAlive = await probeOllamaAlive(ollamaBase);
|
|
65828
|
+
if (ollamaAlive) localModels = await listOllamaModels(ollamaBase);
|
|
65698
65829
|
}
|
|
65699
65830
|
const scored = [];
|
|
65700
65831
|
for (const id of provisionedIds) {
|
|
@@ -65724,6 +65855,7 @@ async function selectBestProvisioned(role, opts) {
|
|
|
65724
65855
|
} else {
|
|
65725
65856
|
model = ollamaDefaultModelForTier(winner.tier, ramBytes);
|
|
65726
65857
|
}
|
|
65858
|
+
model = reconcileOllamaModel(model, localModels);
|
|
65727
65859
|
const catalogKey = catalogKeyForProvider2(winner.id);
|
|
65728
65860
|
const catalogModel = resolveProviderDefaultModel2(catalogKey);
|
|
65729
65861
|
if (!catalogModel?.startsWith("gemma4")) {
|
|
@@ -65767,6 +65899,7 @@ var init_cross_provider_selector = __esm({
|
|
|
65767
65899
|
init_credential_pool();
|
|
65768
65900
|
init_credentials2();
|
|
65769
65901
|
init_credentials_store();
|
|
65902
|
+
init_local_inference_probe();
|
|
65770
65903
|
logger4 = getLogger("llm-cross-provider-selector");
|
|
65771
65904
|
BUILTIN_PROVIDER_IDS = [
|
|
65772
65905
|
"anthropic",
|
|
@@ -65883,6 +66016,7 @@ __export(role_resolver_exports, {
|
|
|
65883
66016
|
HYGIENE_FALLBACK_MODEL: () => HYGIENE_FALLBACK_MODEL,
|
|
65884
66017
|
IMPLICIT_FALLBACK_MODEL: () => IMPLICIT_FALLBACK_MODEL,
|
|
65885
66018
|
IMPLICIT_FALLBACK_PROVIDER: () => IMPLICIT_FALLBACK_PROVIDER,
|
|
66019
|
+
LOCAL_PLACEHOLDER_TOKEN: () => LOCAL_PLACEHOLDER_TOKEN,
|
|
65886
66020
|
resolveAnthropicForRole: () => resolveAnthropicForRole,
|
|
65887
66021
|
resolveLLMForRole: () => resolveLLMForRole
|
|
65888
66022
|
});
|
|
@@ -65986,6 +66120,16 @@ async function selectProviderModel(llm, role, systemKey, profileOverride, projec
|
|
|
65986
66120
|
source: "implicit-fallback"
|
|
65987
66121
|
};
|
|
65988
66122
|
}
|
|
66123
|
+
async function applyProviderExclusions(selected, role, projectRoot, exclude) {
|
|
66124
|
+
if (exclude === void 0 || exclude.length === 0) return selected;
|
|
66125
|
+
if (!exclude.includes(selected.provider)) return selected;
|
|
66126
|
+
try {
|
|
66127
|
+
const substitute = await selectBestProvisioned(role, { projectRoot, exclude });
|
|
66128
|
+
if (substitute !== null) return substitute;
|
|
66129
|
+
} catch {
|
|
66130
|
+
}
|
|
66131
|
+
return selected;
|
|
66132
|
+
}
|
|
65989
66133
|
async function resolveCredentialForRole(provider, credentialLabel, projectRoot) {
|
|
65990
66134
|
try {
|
|
65991
66135
|
await new CredentialPool(provider).refreshExpiredOAuth();
|
|
@@ -66000,7 +66144,9 @@ async function resolveCredentialForRole(provider, credentialLabel, projectRoot)
|
|
|
66000
66144
|
provider,
|
|
66001
66145
|
apiKey: stored.accessToken,
|
|
66002
66146
|
source: "cred-file",
|
|
66003
|
-
authType: wireAuthType
|
|
66147
|
+
authType: wireAuthType,
|
|
66148
|
+
// T12081: preserve the stored endpoint (Ollama/LM Studio/vLLM/…).
|
|
66149
|
+
baseUrl: stored.baseUrl ?? null
|
|
66004
66150
|
},
|
|
66005
66151
|
usedLabel: stored.label
|
|
66006
66152
|
};
|
|
@@ -66016,7 +66162,9 @@ async function resolveCredentialForRole(provider, credentialLabel, projectRoot)
|
|
|
66016
66162
|
provider,
|
|
66017
66163
|
apiKey: picked.accessToken,
|
|
66018
66164
|
source: "cred-file",
|
|
66019
|
-
authType: wireAuthType
|
|
66165
|
+
authType: wireAuthType,
|
|
66166
|
+
// T12081: preserve the stored endpoint (Ollama/LM Studio/vLLM/…).
|
|
66167
|
+
baseUrl: picked.baseUrl ?? null
|
|
66020
66168
|
},
|
|
66021
66169
|
usedLabel: picked.label
|
|
66022
66170
|
};
|
|
@@ -66026,6 +66174,23 @@ async function resolveCredentialForRole(provider, credentialLabel, projectRoot)
|
|
|
66026
66174
|
if (cred.apiKey) {
|
|
66027
66175
|
return { credential: cred, usedLabel: void 0 };
|
|
66028
66176
|
}
|
|
66177
|
+
if (provider === "ollama") {
|
|
66178
|
+
const local = await detectLocalInference();
|
|
66179
|
+
if (local !== null && local.name === "ollama") {
|
|
66180
|
+
return {
|
|
66181
|
+
credential: {
|
|
66182
|
+
provider,
|
|
66183
|
+
apiKey: LOCAL_PLACEHOLDER_TOKEN,
|
|
66184
|
+
source: "local-daemon",
|
|
66185
|
+
authType: "api_key",
|
|
66186
|
+
// ROOT url, not the `/v1` form: `deriveApiWire('ollama')` selects the
|
|
66187
|
+
// NATIVE transport, which appends `/api/chat` itself.
|
|
66188
|
+
baseUrl: local.baseUrl
|
|
66189
|
+
},
|
|
66190
|
+
usedLabel: void 0
|
|
66191
|
+
};
|
|
66192
|
+
}
|
|
66193
|
+
}
|
|
66029
66194
|
return { credential: null, usedLabel: void 0 };
|
|
66030
66195
|
}
|
|
66031
66196
|
async function resolveLLMForRole(role, opts) {
|
|
@@ -66038,13 +66203,19 @@ async function resolveLLMForRole(role, opts) {
|
|
|
66038
66203
|
config2 = void 0;
|
|
66039
66204
|
}
|
|
66040
66205
|
const llmBlock = readLlmBlock(config2);
|
|
66041
|
-
const
|
|
66206
|
+
const selected = await selectProviderModel(
|
|
66042
66207
|
llmBlock,
|
|
66043
66208
|
role,
|
|
66044
66209
|
opts?.systemKey,
|
|
66045
66210
|
opts?.profileOverride,
|
|
66046
66211
|
projectRoot
|
|
66047
66212
|
);
|
|
66213
|
+
const { provider, model, credentialLabel, source } = await applyProviderExclusions(
|
|
66214
|
+
selected,
|
|
66215
|
+
role,
|
|
66216
|
+
projectRoot,
|
|
66217
|
+
opts?.excludeProviders
|
|
66218
|
+
);
|
|
66048
66219
|
const { credential, usedLabel } = await resolveCredentialForRole(
|
|
66049
66220
|
provider,
|
|
66050
66221
|
credentialLabel,
|
|
@@ -66070,7 +66241,12 @@ async function resolveLLMForRole(role, opts) {
|
|
|
66070
66241
|
credentialMetadata = {
|
|
66071
66242
|
provider: credential.provider,
|
|
66072
66243
|
source: credential.source,
|
|
66073
|
-
authType: wireAuthType
|
|
66244
|
+
authType: wireAuthType,
|
|
66245
|
+
// T12081: carry the credential's OWN endpoint. Without it a consumer
|
|
66246
|
+
// building a transport cannot tell that this credential targets a local
|
|
66247
|
+
// or proxied host, and falls back to the provider's public API — which
|
|
66248
|
+
// rejected every Ollama / LM Studio / vLLM / OpenRouter credential 401.
|
|
66249
|
+
baseUrl: credential.baseUrl ?? null
|
|
66074
66250
|
};
|
|
66075
66251
|
sealedCredential = makeSealedCredential({
|
|
66076
66252
|
provider: credential.provider,
|
|
@@ -66112,7 +66288,7 @@ async function resolveAnthropicForRole(role, opts) {
|
|
|
66112
66288
|
model: llm.model
|
|
66113
66289
|
};
|
|
66114
66290
|
}
|
|
66115
|
-
var IMPLICIT_FALLBACK_PROVIDER, HYGIENE_FALLBACK_MODEL;
|
|
66291
|
+
var IMPLICIT_FALLBACK_PROVIDER, LOCAL_PLACEHOLDER_TOKEN, HYGIENE_FALLBACK_MODEL;
|
|
66116
66292
|
var init_role_resolver = __esm({
|
|
66117
66293
|
"packages/core/src/llm/role-resolver.ts"() {
|
|
66118
66294
|
"use strict";
|
|
@@ -66123,10 +66299,12 @@ var init_role_resolver = __esm({
|
|
|
66123
66299
|
init_credentials_store();
|
|
66124
66300
|
init_cross_provider_selector();
|
|
66125
66301
|
init_fallback_model();
|
|
66302
|
+
init_local_inference_probe();
|
|
66126
66303
|
init_sealed_credential();
|
|
66127
66304
|
init_system_of_use_registry();
|
|
66128
66305
|
init_anthropic_client_factory();
|
|
66129
66306
|
IMPLICIT_FALLBACK_PROVIDER = "anthropic";
|
|
66307
|
+
LOCAL_PLACEHOLDER_TOKEN = "local";
|
|
66130
66308
|
HYGIENE_FALLBACK_MODEL = "claude-sonnet-4-6";
|
|
66131
66309
|
}
|
|
66132
66310
|
});
|
|
@@ -66985,8 +67163,8 @@ var _engineRegistry = /* @__PURE__ */ new Map([
|
|
|
66985
67163
|
registerContextEngine("llm-summarization", _engineRegistry.get("compression"));
|
|
66986
67164
|
var _executorCache = /* @__PURE__ */ new Map();
|
|
66987
67165
|
async function getLlmExecutor(role) {
|
|
66988
|
-
const
|
|
66989
|
-
if (
|
|
67166
|
+
const cached3 = _executorCache.get(role);
|
|
67167
|
+
if (cached3 !== void 0) return cached3;
|
|
66990
67168
|
const contextEngine = _engineRegistry.get(role);
|
|
66991
67169
|
const factory11 = new DefaultLlmExecutorFactory({ contextEngine });
|
|
66992
67170
|
const executor = await factory11.createForRole(role);
|