zelari-code 1.1.1 → 1.3.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.
- package/dist/cli/app.js +5 -3
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/ast/engine.js +126 -0
- package/dist/cli/ast/engine.js.map +1 -0
- package/dist/cli/ast/tools.js +71 -0
- package/dist/cli/ast/tools.js.map +1 -0
- package/dist/cli/browser/driver.js +125 -0
- package/dist/cli/browser/driver.js.map +1 -0
- package/dist/cli/browser/tools.js +71 -0
- package/dist/cli/browser/tools.js.map +1 -0
- package/dist/cli/checkpoint/checkpointManager.js +198 -0
- package/dist/cli/checkpoint/checkpointManager.js.map +1 -0
- package/dist/cli/components/StatusBar.js +9 -1
- package/dist/cli/components/StatusBar.js.map +1 -1
- package/dist/cli/diagnostics/engine.js +256 -0
- package/dist/cli/diagnostics/engine.js.map +1 -0
- package/dist/cli/hooks/chatStats.js +5 -1
- package/dist/cli/hooks/chatStats.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/hooks/useSlashDispatch.js +50 -2
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/lsp/client.js +89 -0
- package/dist/cli/lsp/client.js.map +1 -0
- package/dist/cli/lsp/manager.js +287 -0
- package/dist/cli/lsp/manager.js.map +1 -0
- package/dist/cli/lsp/protocol.js +83 -0
- package/dist/cli/lsp/protocol.js.map +1 -0
- package/dist/cli/lsp/servers.js +80 -0
- package/dist/cli/lsp/servers.js.map +1 -0
- package/dist/cli/lsp/tools.js +125 -0
- package/dist/cli/lsp/tools.js.map +1 -0
- package/dist/cli/main.bundled.js +2442 -424
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/mode.js +32 -0
- package/dist/cli/mode.js.map +1 -0
- package/dist/cli/modelPricing.js +29 -5
- package/dist/cli/modelPricing.js.map +1 -1
- package/dist/cli/provider/openai-compatible.js +37 -1
- package/dist/cli/provider/openai-compatible.js.map +1 -1
- package/dist/cli/semantic/embeddings.js +71 -0
- package/dist/cli/semantic/embeddings.js.map +1 -0
- package/dist/cli/semantic/index.js +147 -0
- package/dist/cli/semantic/index.js.map +1 -0
- package/dist/cli/semantic/provider.js +29 -0
- package/dist/cli/semantic/provider.js.map +1 -0
- package/dist/cli/semantic/store.js +71 -0
- package/dist/cli/semantic/store.js.map +1 -0
- package/dist/cli/semantic/tools.js +54 -0
- package/dist/cli/semantic/tools.js.map +1 -0
- package/dist/cli/slashCommands.js +45 -1
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/slashHandlers/checkpoint.js +42 -0
- package/dist/cli/slashHandlers/checkpoint.js.map +1 -0
- package/dist/cli/slashHandlers/semantic.js +37 -0
- package/dist/cli/slashHandlers/semantic.js.map +1 -0
- package/dist/cli/toolRegistry.js +176 -19
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/taskTool.js +145 -0
- package/dist/cli/tools/taskTool.js.map +1 -0
- package/dist/cli/zelariMission.js +10 -0
- package/dist/cli/zelariMission.js.map +1 -1
- package/package.json +3 -3
package/dist/cli/mode.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mode — the free-form dispatch mode (agent / council / zelari) shared by the
|
|
3
|
+
* shift+tab toggle and the `/mode` command.
|
|
4
|
+
*
|
|
5
|
+
* Kept as a tiny pure module so the cycle order is unit-testable and both the
|
|
6
|
+
* keyboard handler (app.tsx) and the slash command (useSlashDispatch) agree on
|
|
7
|
+
* exactly one source of truth.
|
|
8
|
+
*/
|
|
9
|
+
/** Cycle order for shift+tab. */
|
|
10
|
+
export const MODES = ['agent', 'council', 'zelari'];
|
|
11
|
+
/** Next mode in the cycle (wraps agent → council → zelari → agent). */
|
|
12
|
+
export function nextMode(current) {
|
|
13
|
+
const i = MODES.indexOf(current);
|
|
14
|
+
return MODES[(i + 1) % MODES.length] ?? 'agent';
|
|
15
|
+
}
|
|
16
|
+
/** Parse a mode name (case-insensitive), or null if unrecognized. */
|
|
17
|
+
export function parseMode(input) {
|
|
18
|
+
const v = input.trim().toLowerCase();
|
|
19
|
+
return MODES.includes(v) ? v : null;
|
|
20
|
+
}
|
|
21
|
+
/** Short human description of what each mode does (for `/mode` feedback). */
|
|
22
|
+
export function describeMode(mode) {
|
|
23
|
+
switch (mode) {
|
|
24
|
+
case 'council':
|
|
25
|
+
return 'council — 6-member pipeline (Caronte…Lucifero)';
|
|
26
|
+
case 'zelari':
|
|
27
|
+
return 'zelari — autonomous multi-run mission';
|
|
28
|
+
default:
|
|
29
|
+
return 'agent — single LLM turn';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode.js","sourceRoot":"","sources":["../../src/cli/mode.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,iCAAiC;AACjC,MAAM,CAAC,MAAM,KAAK,GAAwB,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAU,CAAC;AAElF,uEAAuE;AACvE,MAAM,UAAU,QAAQ,CAAC,OAAiB;IACxC,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC;AAClD,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,OAAQ,KAA2B,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3E,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,gDAAgD,CAAC;QAC1D,KAAK,QAAQ;YACX,OAAO,uCAAuC,CAAC;QACjD;YACE,OAAO,yBAAyB,CAAC;IACrC,CAAC;AACH,CAAC"}
|
package/dist/cli/modelPricing.js
CHANGED
|
@@ -14,7 +14,13 @@
|
|
|
14
14
|
*
|
|
15
15
|
* Costs returned are precise to 6 decimals. Round to cents at the UI layer.
|
|
16
16
|
*/
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Pricing table (USD per 1M tokens) — conservative public list prices.
|
|
19
|
+
*
|
|
20
|
+
* `cachedInput` (optional) is the discounted rate for prompt tokens served
|
|
21
|
+
* from the provider's automatic prompt cache. When omitted, cached tokens
|
|
22
|
+
* are billed at `input * DEFAULT_CACHE_DISCOUNT` (see below).
|
|
23
|
+
*/
|
|
18
24
|
const PRICES_PER_MILLION = {
|
|
19
25
|
// xAI Grok
|
|
20
26
|
'grok-4': { input: 3, output: 15 },
|
|
@@ -33,8 +39,9 @@ const PRICES_PER_MILLION = {
|
|
|
33
39
|
'MiniMax-M2-her': { input: 0.30, output: 1.20 },
|
|
34
40
|
// DeepSeek (global platform) — estimated list prices; override via
|
|
35
41
|
// ANATHEMA_PRICE_DEEPSEEK_V4_FLASH / ANATHEMA_PRICE_DEEPSEEK_V4_PRO.
|
|
36
|
-
|
|
37
|
-
'deepseek-v4-
|
|
42
|
+
// DeepSeek prompt-cache hits are ~10× cheaper than a cache miss.
|
|
43
|
+
'deepseek-v4-flash': { input: 0.14, output: 0.28, cachedInput: 0.014 },
|
|
44
|
+
'deepseek-v4-pro': { input: 0.55, output: 2.19, cachedInput: 0.055 },
|
|
38
45
|
// OpenAI (for openai-compatible fallback)
|
|
39
46
|
'gpt-4o': { input: 2.50, output: 10 },
|
|
40
47
|
'gpt-4o-mini': { input: 0.15, output: 0.60 },
|
|
@@ -44,6 +51,12 @@ const PRICES_PER_MILLION = {
|
|
|
44
51
|
};
|
|
45
52
|
/** Default rate for unknown models — assume a mid-tier provider. */
|
|
46
53
|
const DEFAULT_RATE = { input: 1.0, output: 3.0 };
|
|
54
|
+
/**
|
|
55
|
+
* When a model has no explicit `cachedInput` rate, bill cache-hit prompt
|
|
56
|
+
* tokens at this fraction of the input rate. 0.25 is a conservative middle
|
|
57
|
+
* across providers (OpenAI ~0.5×, xAI ~0.25×, DeepSeek ~0.1×).
|
|
58
|
+
*/
|
|
59
|
+
const DEFAULT_CACHE_DISCOUNT = 0.25;
|
|
47
60
|
/** Read an env-var override for a given model, if present. */
|
|
48
61
|
function envOverride(model) {
|
|
49
62
|
const key = `ANATHEMA_PRICE_${model.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`;
|
|
@@ -79,15 +92,26 @@ export function getModelRate(model) {
|
|
|
79
92
|
* Compute the USD cost for a given number of prompt + completion tokens.
|
|
80
93
|
* Rates are per 1M tokens, so we divide the token count by 1_000_000.
|
|
81
94
|
*
|
|
95
|
+
* `cachedPromptTokens` (optional, a subset of `promptTokens`) are prompt
|
|
96
|
+
* tokens served from the provider's automatic prompt cache; they are billed
|
|
97
|
+
* at the model's `cachedInput` rate (or `input * DEFAULT_CACHE_DISCOUNT` when
|
|
98
|
+
* the model has no explicit cached rate). Values are clamped so cached never
|
|
99
|
+
* exceeds prompt.
|
|
100
|
+
*
|
|
82
101
|
* @returns cost in USD (0 if either token count is negative or NaN).
|
|
83
102
|
*/
|
|
84
|
-
export function calculateCost(model, promptTokens, completionTokens) {
|
|
103
|
+
export function calculateCost(model, promptTokens, completionTokens, cachedPromptTokens = 0) {
|
|
85
104
|
if (!Number.isFinite(promptTokens) || promptTokens < 0)
|
|
86
105
|
return 0;
|
|
87
106
|
if (!Number.isFinite(completionTokens) || completionTokens < 0)
|
|
88
107
|
return 0;
|
|
89
108
|
const rate = getModelRate(model);
|
|
90
|
-
const
|
|
109
|
+
const cached = Number.isFinite(cachedPromptTokens) && cachedPromptTokens > 0
|
|
110
|
+
? Math.min(cachedPromptTokens, promptTokens)
|
|
111
|
+
: 0;
|
|
112
|
+
const uncachedPrompt = promptTokens - cached;
|
|
113
|
+
const cachedRate = rate.cachedInput ?? rate.input * DEFAULT_CACHE_DISCOUNT;
|
|
114
|
+
const inputCost = (uncachedPrompt / 1_000_000) * rate.input + (cached / 1_000_000) * cachedRate;
|
|
91
115
|
const outputCost = (completionTokens / 1_000_000) * rate.output;
|
|
92
116
|
return Number((inputCost + outputCost).toFixed(6));
|
|
93
117
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modelPricing.js","sourceRoot":"","sources":["../../src/cli/modelPricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH
|
|
1
|
+
{"version":3,"file":"modelPricing.js","sourceRoot":"","sources":["../../src/cli/modelPricing.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,6 +35,36 @@ export const PROVIDER_ENDPOINTS = {
|
|
|
35
35
|
export function resolveActiveProvider() {
|
|
36
36
|
return getProviderConfig().activeProviderId;
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Extract the number of prompt tokens served from the provider's prompt
|
|
40
|
+
* cache, normalizing across the two OpenAI-compatible reporting shapes:
|
|
41
|
+
* - OpenAI / xAI / GLM: `usage.prompt_tokens_details.cached_tokens`
|
|
42
|
+
* - DeepSeek: `usage.prompt_cache_hit_tokens`
|
|
43
|
+
*
|
|
44
|
+
* Prompt caching is automatic server-side for these providers — there is no
|
|
45
|
+
* request-side `cache_control` to send (that is an Anthropic-only mechanism).
|
|
46
|
+
* The stable prompt prefix (system prompt + tool schema + early transcript)
|
|
47
|
+
* gets cached and billed at a discount; this function surfaces the hit count
|
|
48
|
+
* so cost accounting and the cache-hit-rate stat are accurate.
|
|
49
|
+
*
|
|
50
|
+
* Returns 0 when no cache field is present or the value is not a finite
|
|
51
|
+
* non-negative number.
|
|
52
|
+
*
|
|
53
|
+
* @internal exported for unit testing
|
|
54
|
+
*/
|
|
55
|
+
export function parseCachedPromptTokens(usage) {
|
|
56
|
+
if (!usage || typeof usage !== 'object')
|
|
57
|
+
return 0;
|
|
58
|
+
const candidates = [
|
|
59
|
+
usage.prompt_tokens_details?.cached_tokens,
|
|
60
|
+
usage.prompt_cache_hit_tokens,
|
|
61
|
+
];
|
|
62
|
+
for (const c of candidates) {
|
|
63
|
+
if (typeof c === 'number' && Number.isFinite(c) && c >= 0)
|
|
64
|
+
return c;
|
|
65
|
+
}
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
38
68
|
/**
|
|
39
69
|
* Resolve baseUrl for a given provider. Priority:
|
|
40
70
|
* 1. Custom endpoint persisted via `/provider custom <url>` (wins always)
|
|
@@ -180,9 +210,15 @@ export function openaiCompatibleProvider(config) {
|
|
|
180
210
|
const totalTokens = typeof parsed.usage.total_tokens === 'number'
|
|
181
211
|
? parsed.usage.total_tokens
|
|
182
212
|
: promptTokens + completionTokens;
|
|
213
|
+
const cachedPromptTokens = parseCachedPromptTokens(parsed.usage);
|
|
183
214
|
yield {
|
|
184
215
|
kind: 'usage',
|
|
185
|
-
usage: {
|
|
216
|
+
usage: {
|
|
217
|
+
promptTokens,
|
|
218
|
+
completionTokens,
|
|
219
|
+
totalTokens,
|
|
220
|
+
...(cachedPromptTokens > 0 ? { cachedPromptTokens } : {}),
|
|
221
|
+
},
|
|
186
222
|
};
|
|
187
223
|
}
|
|
188
224
|
if (typeof delta?.content === 'string' && delta.content.length > 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-compatible.js","sourceRoot":"","sources":["../../../src/cli/provider/openai-compatible.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"openai-compatible.js","sourceRoot":"","sources":["../../../src/cli/provider/openai-compatible.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantic/embeddings — call an OpenAI-compatible `/embeddings` endpoint.
|
|
3
|
+
*
|
|
4
|
+
* Reuses the active provider's base URL + API key (the same ones chat uses).
|
|
5
|
+
* Not every provider exposes embeddings, so this is best-effort: any failure
|
|
6
|
+
* (missing endpoint, HTTP error, bad shape) resolves to `{ error }` and the
|
|
7
|
+
* caller degrades gracefully. The fetch is injectable for tests.
|
|
8
|
+
*/
|
|
9
|
+
/** Parse an OpenAI-compatible embeddings response into ordered vectors. */
|
|
10
|
+
export function parseEmbeddingsResponse(json, expected) {
|
|
11
|
+
if (!json || typeof json !== 'object')
|
|
12
|
+
return null;
|
|
13
|
+
const data = json.data;
|
|
14
|
+
if (!Array.isArray(data))
|
|
15
|
+
return null;
|
|
16
|
+
const rows = [];
|
|
17
|
+
for (const item of data) {
|
|
18
|
+
if (!item || typeof item !== 'object')
|
|
19
|
+
continue;
|
|
20
|
+
const it = item;
|
|
21
|
+
if (!Array.isArray(it.embedding))
|
|
22
|
+
continue;
|
|
23
|
+
const embedding = it.embedding.filter((n) => typeof n === 'number');
|
|
24
|
+
if (embedding.length === 0)
|
|
25
|
+
continue;
|
|
26
|
+
rows.push({ index: typeof it.index === 'number' ? it.index : rows.length, embedding });
|
|
27
|
+
}
|
|
28
|
+
if (rows.length === 0)
|
|
29
|
+
return null;
|
|
30
|
+
// Respect the provider-reported order.
|
|
31
|
+
rows.sort((a, b) => a.index - b.index);
|
|
32
|
+
const out = rows.map((r) => r.embedding);
|
|
33
|
+
// Only accept a full result — a partial batch would misalign chunks.
|
|
34
|
+
return out.length === expected ? out : null;
|
|
35
|
+
}
|
|
36
|
+
/** Embed a batch of texts. Never throws. */
|
|
37
|
+
export async function embedTexts(texts, config, fetchImpl = fetch) {
|
|
38
|
+
if (texts.length === 0)
|
|
39
|
+
return { embeddings: [] };
|
|
40
|
+
const url = `${config.baseUrl.replace(/\/$/, '')}/embeddings`;
|
|
41
|
+
let response;
|
|
42
|
+
try {
|
|
43
|
+
response = await fetchImpl(url, {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: {
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({ model: config.model, input: texts }),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return { error: `network error contacting ${url}: ${err instanceof Error ? err.message : String(err)}` };
|
|
54
|
+
}
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
const body = await response.text().catch(() => '');
|
|
57
|
+
return { error: `HTTP ${response.status} from ${url}: ${body.slice(0, 160)}` };
|
|
58
|
+
}
|
|
59
|
+
let json;
|
|
60
|
+
try {
|
|
61
|
+
json = await response.json();
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
return { error: `invalid JSON from ${url}: ${err instanceof Error ? err.message : String(err)}` };
|
|
65
|
+
}
|
|
66
|
+
const embeddings = parseEmbeddingsResponse(json, texts.length);
|
|
67
|
+
if (!embeddings)
|
|
68
|
+
return { error: `unexpected embeddings response shape from ${url}` };
|
|
69
|
+
return { embeddings };
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=embeddings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../../src/cli/semantic/embeddings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantic/index — build, persist, and query a repo's semantic code index.
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates the pure store (chunk/cosine/rank) with an injectable embed
|
|
5
|
+
* function. Persistence is a JSON file under the user's state dir, keyed by
|
|
6
|
+
* repo root — no native vector DB, brute-force cosine, which is plenty for
|
|
7
|
+
* repo-scale indexes.
|
|
8
|
+
*/
|
|
9
|
+
import { promises as fs, existsSync, readFileSync } from 'node:fs';
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { createHash } from 'node:crypto';
|
|
13
|
+
import { chunkFile, searchIndex, } from './store.js';
|
|
14
|
+
const SOURCE_EXTENSIONS = new Set([
|
|
15
|
+
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.py', '.go', '.rs', '.java',
|
|
16
|
+
'.rb', '.php', '.c', '.h', '.cc', '.cpp', '.hpp', '.cs', '.swift', '.kt',
|
|
17
|
+
'.scala', '.sh', '.md',
|
|
18
|
+
]);
|
|
19
|
+
const IGNORE_DIRS = new Set([
|
|
20
|
+
'node_modules', '.git', 'dist', 'build', 'out', 'coverage', '.next',
|
|
21
|
+
'.turbo', '.cache', 'vendor', '__pycache__', '.venv', 'venv', '.tmp',
|
|
22
|
+
]);
|
|
23
|
+
export function getIndexPath(root) {
|
|
24
|
+
const hash = createHash('sha1').update(path.resolve(root)).digest('hex').slice(0, 16);
|
|
25
|
+
return (process.env.ZELARI_SEMANTIC_FILE ??
|
|
26
|
+
path.join(homedir(), '.tmp', 'zelari-code', 'semantic', `${hash}.json`));
|
|
27
|
+
}
|
|
28
|
+
/** Walk `root` collecting indexable source files (bounded by `maxFiles`). */
|
|
29
|
+
export async function collectSourceFiles(root, maxFiles = 1500) {
|
|
30
|
+
const out = [];
|
|
31
|
+
const walk = async (dir) => {
|
|
32
|
+
if (out.length >= maxFiles)
|
|
33
|
+
return;
|
|
34
|
+
let entries;
|
|
35
|
+
try {
|
|
36
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
if (out.length >= maxFiles)
|
|
43
|
+
return;
|
|
44
|
+
if (entry.name.startsWith('.') && entry.name !== '.') {
|
|
45
|
+
// Skip dotfiles/dotdirs except allow walking the root itself.
|
|
46
|
+
if (entry.isDirectory() && IGNORE_DIRS.has(entry.name))
|
|
47
|
+
continue;
|
|
48
|
+
if (entry.isDirectory())
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const full = path.join(dir, entry.name);
|
|
52
|
+
if (entry.isDirectory()) {
|
|
53
|
+
if (IGNORE_DIRS.has(entry.name))
|
|
54
|
+
continue;
|
|
55
|
+
await walk(full);
|
|
56
|
+
}
|
|
57
|
+
else if (SOURCE_EXTENSIONS.has(path.extname(entry.name).toLowerCase())) {
|
|
58
|
+
out.push(full);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
await walk(root);
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build an index over `files` using `embed`. Chunks are embedded in batches;
|
|
67
|
+
* if any batch fails, the whole build fails (a partial index would give
|
|
68
|
+
* misleading results).
|
|
69
|
+
*/
|
|
70
|
+
export async function buildIndex(files, embed, options) {
|
|
71
|
+
const batchSize = options.batchSize ?? 64;
|
|
72
|
+
const maxChunkChars = options.maxChunkChars ?? 8000;
|
|
73
|
+
const chunks = [];
|
|
74
|
+
let filesIndexed = 0;
|
|
75
|
+
for (const file of files) {
|
|
76
|
+
let text;
|
|
77
|
+
try {
|
|
78
|
+
text = await fs.readFile(file, 'utf8');
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const fileChunks = chunkFile(file, text, options).filter((c) => c.text.length <= maxChunkChars);
|
|
84
|
+
if (fileChunks.length > 0)
|
|
85
|
+
filesIndexed += 1;
|
|
86
|
+
chunks.push(...fileChunks);
|
|
87
|
+
}
|
|
88
|
+
if (chunks.length === 0) {
|
|
89
|
+
return { error: 'no indexable source found', filesIndexed: 0, chunksIndexed: 0 };
|
|
90
|
+
}
|
|
91
|
+
const indexed = [];
|
|
92
|
+
for (let i = 0; i < chunks.length; i += batchSize) {
|
|
93
|
+
const batch = chunks.slice(i, i + batchSize);
|
|
94
|
+
const res = await embed(batch.map((c) => c.text));
|
|
95
|
+
if ('error' in res) {
|
|
96
|
+
return { error: res.error, filesIndexed, chunksIndexed: 0 };
|
|
97
|
+
}
|
|
98
|
+
if (res.length !== batch.length) {
|
|
99
|
+
return { error: 'embedding count mismatch', filesIndexed, chunksIndexed: 0 };
|
|
100
|
+
}
|
|
101
|
+
batch.forEach((c, j) => indexed.push({ ...c, embedding: res[j] }));
|
|
102
|
+
}
|
|
103
|
+
const data = {
|
|
104
|
+
model: options.model,
|
|
105
|
+
dim: indexed[0]?.embedding.length ?? 0,
|
|
106
|
+
chunks: indexed,
|
|
107
|
+
builtAt: Date.now(),
|
|
108
|
+
};
|
|
109
|
+
return { data, filesIndexed, chunksIndexed: indexed.length };
|
|
110
|
+
}
|
|
111
|
+
/** Persist an index atomically. */
|
|
112
|
+
export async function saveIndex(root, data) {
|
|
113
|
+
const file = getIndexPath(root);
|
|
114
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
115
|
+
const tmp = `${file}.tmp-${process.pid}`;
|
|
116
|
+
await fs.writeFile(tmp, JSON.stringify(data), 'utf8');
|
|
117
|
+
await fs.rename(tmp, file);
|
|
118
|
+
}
|
|
119
|
+
/** Load a persisted index (sync — used at query time). Null if missing/corrupt. */
|
|
120
|
+
export function loadIndex(root) {
|
|
121
|
+
const file = getIndexPath(root);
|
|
122
|
+
if (!existsSync(file))
|
|
123
|
+
return null;
|
|
124
|
+
try {
|
|
125
|
+
const parsed = JSON.parse(readFileSync(file, 'utf8'));
|
|
126
|
+
if (parsed && Array.isArray(parsed.chunks))
|
|
127
|
+
return parsed;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
/* corrupt */
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
/** Embed a query and rank the persisted index against it. */
|
|
135
|
+
export async function semanticSearch(root, query, embed, k = 8) {
|
|
136
|
+
const data = loadIndex(root);
|
|
137
|
+
if (!data)
|
|
138
|
+
return { error: 'no semantic index — run /index first' };
|
|
139
|
+
const res = await embed([query]);
|
|
140
|
+
if ('error' in res)
|
|
141
|
+
return { error: res.error };
|
|
142
|
+
const vector = res[0];
|
|
143
|
+
if (!vector)
|
|
144
|
+
return { error: 'query embedding failed' };
|
|
145
|
+
return { hits: searchIndex(data, vector, k) };
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/semantic/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantic/provider — build an EmbedFn from the active chat provider.
|
|
3
|
+
*
|
|
4
|
+
* Reuses the same base URL + API key resolution as chat (providerFromEnv), so
|
|
5
|
+
* `/index` and `semantic_search` hit the provider the user is already logged
|
|
6
|
+
* into. The embedding model is configurable via ZELARI_EMBED_MODEL.
|
|
7
|
+
*/
|
|
8
|
+
import { providerFromEnv } from '../provider/openai-compatible.js';
|
|
9
|
+
import { embedTexts } from './embeddings.js';
|
|
10
|
+
export const DEFAULT_EMBED_MODEL = 'text-embedding-3-small';
|
|
11
|
+
export function embedModel() {
|
|
12
|
+
return process.env.ZELARI_EMBED_MODEL ?? DEFAULT_EMBED_MODEL;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Build an EmbedFn bound to the active provider, or null if no provider/API
|
|
16
|
+
* key is configured. The returned fn normalizes embedTexts' result shape into
|
|
17
|
+
* the `number[][] | { error }` the index expects.
|
|
18
|
+
*/
|
|
19
|
+
export async function buildProviderEmbedFn() {
|
|
20
|
+
const cfg = await providerFromEnv();
|
|
21
|
+
if (!cfg)
|
|
22
|
+
return null;
|
|
23
|
+
const embedCfg = { apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, model: embedModel() };
|
|
24
|
+
return async (texts) => {
|
|
25
|
+
const res = await embedTexts(texts, embedCfg);
|
|
26
|
+
return 'error' in res ? { error: res.error } : res.embeddings;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/cli/semantic/provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,MAAM,CAAC,MAAM,mBAAmB,GAAG,wBAAwB,CAAC;AAE5D,MAAM,UAAU,UAAU;IACxB,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,mBAAmB,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,MAAM,GAAG,GAAG,MAAM,eAAe,EAAE,CAAC;IACpC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,QAAQ,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC;IACnF,OAAO,KAAK,EAAE,KAAe,EAAE,EAAE;QAC/B,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC9C,OAAO,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC;IAChE,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantic/store — the pure core of the semantic code index.
|
|
3
|
+
*
|
|
4
|
+
* Chunk source files into overlapping line windows, hold each chunk's
|
|
5
|
+
* embedding vector, and rank chunks against a query vector by cosine
|
|
6
|
+
* similarity. No I/O, no embeddings API — those live in embeddings.ts /
|
|
7
|
+
* index.ts — so all of this is deterministic and unit-testable.
|
|
8
|
+
*
|
|
9
|
+
* Persistence is a plain JSON file (no native vector DB): fine for
|
|
10
|
+
* repo-scale indexes (thousands of chunks) with a brute-force cosine scan.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Split a file's text into overlapping line-window chunks. Blank-only chunks
|
|
14
|
+
* are dropped. Overlap keeps a symbol that straddles a boundary retrievable
|
|
15
|
+
* from either side.
|
|
16
|
+
*/
|
|
17
|
+
export function chunkFile(file, text, opts = {}) {
|
|
18
|
+
const maxLines = Math.max(1, opts.maxLines ?? 40);
|
|
19
|
+
const overlap = Math.max(0, Math.min(opts.overlap ?? 8, maxLines - 1));
|
|
20
|
+
const lines = text.split('\n');
|
|
21
|
+
const step = maxLines - overlap;
|
|
22
|
+
const chunks = [];
|
|
23
|
+
for (let start = 0; start < lines.length; start += step) {
|
|
24
|
+
const end = Math.min(start + maxLines, lines.length);
|
|
25
|
+
const slice = lines.slice(start, end);
|
|
26
|
+
if (slice.join('').trim().length > 0) {
|
|
27
|
+
chunks.push({
|
|
28
|
+
file,
|
|
29
|
+
startLine: start + 1,
|
|
30
|
+
endLine: end,
|
|
31
|
+
text: slice.join('\n'),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (end >= lines.length)
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
return chunks;
|
|
38
|
+
}
|
|
39
|
+
/** Cosine similarity of two equal-length vectors. Returns 0 on mismatch/zero. */
|
|
40
|
+
export function cosineSimilarity(a, b) {
|
|
41
|
+
if (a.length === 0 || a.length !== b.length)
|
|
42
|
+
return 0;
|
|
43
|
+
let dot = 0;
|
|
44
|
+
let na = 0;
|
|
45
|
+
let nb = 0;
|
|
46
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
47
|
+
dot += a[i] * b[i];
|
|
48
|
+
na += a[i] * a[i];
|
|
49
|
+
nb += b[i] * b[i];
|
|
50
|
+
}
|
|
51
|
+
if (na === 0 || nb === 0)
|
|
52
|
+
return 0;
|
|
53
|
+
return dot / (Math.sqrt(na) * Math.sqrt(nb));
|
|
54
|
+
}
|
|
55
|
+
/** Rank indexed chunks against a query embedding, returning the top-k hits. */
|
|
56
|
+
export function searchIndex(data, queryEmbedding, k = 8) {
|
|
57
|
+
const scored = [];
|
|
58
|
+
for (const chunk of data.chunks) {
|
|
59
|
+
const score = cosineSimilarity(queryEmbedding, chunk.embedding);
|
|
60
|
+
scored.push({
|
|
61
|
+
file: chunk.file,
|
|
62
|
+
startLine: chunk.startLine,
|
|
63
|
+
endLine: chunk.endLine,
|
|
64
|
+
text: chunk.text,
|
|
65
|
+
score,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
scored.sort((a, b) => b.score - a.score);
|
|
69
|
+
return scored.slice(0, Math.max(0, k));
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/cli/semantic/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantic/tools — the `semantic_search` agent tool.
|
|
3
|
+
*
|
|
4
|
+
* Concept-level code search: "where is retry/backoff handled?" finds the
|
|
5
|
+
* relevant chunks even when they share no literal keyword with the query —
|
|
6
|
+
* where grep can't. Requires a prior index (`/index`). Read-only.
|
|
7
|
+
*
|
|
8
|
+
* The EmbedFn is injectable so the tool is testable without hitting a real
|
|
9
|
+
* embeddings endpoint; in production it's bound to the active provider.
|
|
10
|
+
*/
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { typedOk } from '@zelari/core/harness/tools/toolTypes';
|
|
14
|
+
import { semanticSearch, loadIndex } from './index.js';
|
|
15
|
+
import { buildProviderEmbedFn } from './provider.js';
|
|
16
|
+
export function createSemanticTool(deps) {
|
|
17
|
+
const buildEmbedFn = deps.buildEmbedFn ?? buildProviderEmbedFn;
|
|
18
|
+
return {
|
|
19
|
+
name: 'semantic_search',
|
|
20
|
+
description: 'Concept-level search over the indexed codebase: describe what you are ' +
|
|
21
|
+
'looking for in plain language ("where is rate-limit backoff handled?") and ' +
|
|
22
|
+
'get the most relevant code chunks (file:line + snippet), even when they ' +
|
|
23
|
+
'share no exact keyword with your query. Requires an index — if none exists, ' +
|
|
24
|
+
'ask the user to run /index. Complements grep_content (exact matches).',
|
|
25
|
+
permissions: ['read'],
|
|
26
|
+
inputSchema: z.object({
|
|
27
|
+
query: z.string().min(1).describe('Natural-language description of the code you want.'),
|
|
28
|
+
k: z.number().int().positive().max(25).optional().describe('Max results (default 8).'),
|
|
29
|
+
}),
|
|
30
|
+
execute: async (args) => {
|
|
31
|
+
const { query, k } = args;
|
|
32
|
+
if (!loadIndex(deps.root)) {
|
|
33
|
+
return typedOk({ results: [], note: 'no semantic index yet — run /index to build one, then retry' });
|
|
34
|
+
}
|
|
35
|
+
const embed = await buildEmbedFn();
|
|
36
|
+
if (!embed) {
|
|
37
|
+
return typedOk({ results: [], note: 'no provider/API key configured for embeddings' });
|
|
38
|
+
}
|
|
39
|
+
const res = await semanticSearch(deps.root, query, embed, k ?? 8);
|
|
40
|
+
if ('error' in res) {
|
|
41
|
+
return typedOk({ results: [], note: `semantic search unavailable: ${res.error}` });
|
|
42
|
+
}
|
|
43
|
+
return typedOk({
|
|
44
|
+
count: res.hits.length,
|
|
45
|
+
results: res.hits.map((h) => ({
|
|
46
|
+
location: `${path.relative(deps.root, h.file) || h.file}:${h.startLine}-${h.endLine}`,
|
|
47
|
+
score: Number(h.score.toFixed(3)),
|
|
48
|
+
preview: h.text.length > 400 ? `${h.text.slice(0, 400)}…` : h.text,
|
|
49
|
+
})),
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/cli/semantic/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAuB,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,SAAS,EAAgB,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AASrD,MAAM,UAAU,kBAAkB,CAAC,IAAsB;IACvD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,oBAAoB,CAAC;IAC/D,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,WAAW,EACT,wEAAwE;YACxE,6EAA6E;YAC7E,0EAA0E;YAC1E,8EAA8E;YAC9E,uEAAuE;QACzE,WAAW,EAAE,CAAC,MAAM,CAAC;QACrB,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,oDAAoD,CAAC;YACvF,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;SACvF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACtB,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAqC,CAAC;YAC3D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,OAAO,OAAO,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,6DAA6D,EAAE,CAAC,CAAC;YACvG,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,YAAY,EAAE,CAAC;YACnC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,OAAO,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,+CAA+C,EAAE,CAAC,CAAC;YACzF,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YAClE,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC;gBACnB,OAAO,OAAO,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,gCAAgC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACrF,CAAC;YACD,OAAO,OAAO,CAAC;gBACb,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM;gBACtB,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC5B,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,OAAO,EAAE;oBACrF,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;oBACjC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;iBACnE,CAAC,CAAC;aACJ,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
|