@unerr-ai/unerr 0.1.7 → 0.1.9
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/README.md +9 -2
- package/dist/cli.js +1467 -296
- package/package.json +9 -2
package/dist/cli.js
CHANGED
|
@@ -245,16 +245,16 @@ async function getParser(language) {
|
|
|
245
245
|
const parser = new TreeSitter();
|
|
246
246
|
const langFile = `tree-sitter-${language}.wasm`;
|
|
247
247
|
try {
|
|
248
|
-
const { join:
|
|
248
|
+
const { join: join85 } = await import("path");
|
|
249
249
|
const { existsSync: existsSync82 } = await import("fs");
|
|
250
250
|
const possiblePaths = [
|
|
251
|
-
|
|
251
|
+
join85(
|
|
252
252
|
process.cwd(),
|
|
253
253
|
"node_modules",
|
|
254
254
|
`tree-sitter-${language}`,
|
|
255
255
|
langFile
|
|
256
256
|
),
|
|
257
|
-
|
|
257
|
+
join85(process.cwd(), "node_modules", "web-tree-sitter", langFile)
|
|
258
258
|
];
|
|
259
259
|
let wasmPath = null;
|
|
260
260
|
for (const p of possiblePaths) {
|
|
@@ -5770,6 +5770,7 @@ var init_startup_log = __esm({
|
|
|
5770
5770
|
// src/config/settings.ts
|
|
5771
5771
|
var settings_exports = {};
|
|
5772
5772
|
__export(settings_exports, {
|
|
5773
|
+
FetchUrlConfigSchema: () => FetchUrlConfigSchema,
|
|
5773
5774
|
LocalLlmConfigSchema: () => LocalLlmConfigSchema,
|
|
5774
5775
|
SettingsSchema: () => SettingsSchema,
|
|
5775
5776
|
loadSettings: () => loadSettings,
|
|
@@ -5852,7 +5853,7 @@ function loadSettings(cwd) {
|
|
|
5852
5853
|
};
|
|
5853
5854
|
return SettingsSchema.parse(merged);
|
|
5854
5855
|
}
|
|
5855
|
-
var LlmProviderEnum, EndpointConfigSchema, LocalLlmConfigSchema, LlmConfigSchema, SettingsSchema, DEFAULTS;
|
|
5856
|
+
var LlmProviderEnum, EndpointConfigSchema, LocalLlmConfigSchema, LlmConfigSchema, FetchUrlConfigSchema, SettingsSchema, DEFAULTS;
|
|
5856
5857
|
var init_settings = __esm({
|
|
5857
5858
|
"src/config/settings.ts"() {
|
|
5858
5859
|
"use strict";
|
|
@@ -5885,6 +5886,17 @@ var init_settings = __esm({
|
|
|
5885
5886
|
apiKey: z.string().optional(),
|
|
5886
5887
|
baseUrl: z.string().optional()
|
|
5887
5888
|
});
|
|
5889
|
+
FetchUrlConfigSchema = z.object({
|
|
5890
|
+
playwright: z.object({
|
|
5891
|
+
enabled: z.boolean().default(false),
|
|
5892
|
+
timeoutMs: z.number().int().min(1e3).max(6e4).default(15e3),
|
|
5893
|
+
waitUntil: z.enum(["load", "domcontentloaded", "networkidle"]).default("networkidle")
|
|
5894
|
+
}).default(() => ({
|
|
5895
|
+
enabled: false,
|
|
5896
|
+
timeoutMs: 15e3,
|
|
5897
|
+
waitUntil: "networkidle"
|
|
5898
|
+
}))
|
|
5899
|
+
});
|
|
5888
5900
|
SettingsSchema = z.object({
|
|
5889
5901
|
/** Default Claude model for interactive sessions */
|
|
5890
5902
|
model: z.string().default("claude-sonnet-4-20250514"),
|
|
@@ -5899,7 +5911,15 @@ var init_settings = __esm({
|
|
|
5899
5911
|
/** AI SDK LLM configuration (Sprint D — unified multi-provider) */
|
|
5900
5912
|
llm: LlmConfigSchema.optional(),
|
|
5901
5913
|
/** BYO-LLM configuration for local LLM providers */
|
|
5902
|
-
localLlm: LocalLlmConfigSchema.optional()
|
|
5914
|
+
localLlm: LocalLlmConfigSchema.optional(),
|
|
5915
|
+
/** fetch_url runtime config (Playwright SPA fallback, etc.) */
|
|
5916
|
+
fetchUrl: FetchUrlConfigSchema.default(() => ({
|
|
5917
|
+
playwright: {
|
|
5918
|
+
enabled: false,
|
|
5919
|
+
timeoutMs: 15e3,
|
|
5920
|
+
waitUntil: "networkidle"
|
|
5921
|
+
}
|
|
5922
|
+
}))
|
|
5903
5923
|
});
|
|
5904
5924
|
DEFAULTS = SettingsSchema.parse({});
|
|
5905
5925
|
}
|
|
@@ -6551,6 +6571,19 @@ CREATE TABLE IF NOT EXISTS meta (
|
|
|
6551
6571
|
key TEXT PRIMARY KEY,
|
|
6552
6572
|
value TEXT NOT NULL
|
|
6553
6573
|
);
|
|
6574
|
+
|
|
6575
|
+
CREATE TABLE IF NOT EXISTS fetch_cache (
|
|
6576
|
+
url TEXT PRIMARY KEY,
|
|
6577
|
+
content_hash TEXT NOT NULL,
|
|
6578
|
+
markdown TEXT NOT NULL,
|
|
6579
|
+
title TEXT NOT NULL,
|
|
6580
|
+
extractor TEXT NOT NULL,
|
|
6581
|
+
raw_bytes INTEGER NOT NULL,
|
|
6582
|
+
compressed_bytes INTEGER NOT NULL,
|
|
6583
|
+
fetched_at INTEGER NOT NULL,
|
|
6584
|
+
hit_count INTEGER NOT NULL DEFAULT 0
|
|
6585
|
+
);
|
|
6586
|
+
CREATE INDEX IF NOT EXISTS idx_fetch_cache_fetched ON fetch_cache(fetched_at);
|
|
6554
6587
|
`;
|
|
6555
6588
|
SCHEMA_VERSION = "1";
|
|
6556
6589
|
MetricsStore = class {
|
|
@@ -6660,9 +6693,39 @@ CREATE TABLE IF NOT EXISTS meta (
|
|
|
6660
6693
|
`),
|
|
6661
6694
|
allSessionSummaries: this.db.prepare(`
|
|
6662
6695
|
SELECT * FROM session_summaries ORDER BY ended_at DESC
|
|
6696
|
+
`),
|
|
6697
|
+
upsertFetchCache: this.db.prepare(`
|
|
6698
|
+
INSERT INTO fetch_cache
|
|
6699
|
+
(url, content_hash, markdown, title, extractor,
|
|
6700
|
+
raw_bytes, compressed_bytes, fetched_at, hit_count)
|
|
6701
|
+
VALUES (@url, @content_hash, @markdown, @title, @extractor,
|
|
6702
|
+
@raw_bytes, @compressed_bytes, @fetched_at, 0)
|
|
6703
|
+
ON CONFLICT(url) DO UPDATE SET
|
|
6704
|
+
content_hash = excluded.content_hash,
|
|
6705
|
+
markdown = excluded.markdown,
|
|
6706
|
+
title = excluded.title,
|
|
6707
|
+
extractor = excluded.extractor,
|
|
6708
|
+
raw_bytes = excluded.raw_bytes,
|
|
6709
|
+
compressed_bytes = excluded.compressed_bytes,
|
|
6710
|
+
fetched_at = excluded.fetched_at
|
|
6711
|
+
`),
|
|
6712
|
+
getFetchCache: this.db.prepare(`
|
|
6713
|
+
SELECT * FROM fetch_cache WHERE url = @url
|
|
6714
|
+
`),
|
|
6715
|
+
bumpFetchCacheHit: this.db.prepare(`
|
|
6716
|
+
UPDATE fetch_cache SET hit_count = hit_count + 1 WHERE url = @url
|
|
6663
6717
|
`)
|
|
6664
6718
|
};
|
|
6665
6719
|
}
|
|
6720
|
+
upsertFetchCacheRow(row) {
|
|
6721
|
+
this.stmt.upsertFetchCache.run(row);
|
|
6722
|
+
}
|
|
6723
|
+
getFetchCacheRow(url) {
|
|
6724
|
+
return this.stmt.getFetchCache.get({ url }) ?? null;
|
|
6725
|
+
}
|
|
6726
|
+
bumpFetchCacheHitFor(url) {
|
|
6727
|
+
this.stmt.bumpFetchCacheHit.run({ url });
|
|
6728
|
+
}
|
|
6666
6729
|
// ── Writes ──────────────────────────────────────────────────────────
|
|
6667
6730
|
insertCompression(row) {
|
|
6668
6731
|
return Number(this.stmt.insertCompression.run(row).lastInsertRowid);
|
|
@@ -10717,6 +10780,7 @@ var init_protocol = __esm({
|
|
|
10717
10780
|
var registry_exports = {};
|
|
10718
10781
|
__export(registry_exports, {
|
|
10719
10782
|
addRepo: () => addRepo,
|
|
10783
|
+
clearNeedsInputKey: () => clearNeedsInputKey,
|
|
10720
10784
|
deriveLabel: () => deriveLabel,
|
|
10721
10785
|
detectChildConflicts: () => detectChildConflicts,
|
|
10722
10786
|
detectParentConflict: () => detectParentConflict,
|
|
@@ -10887,6 +10951,13 @@ function writeNeedsInput(repoPath, signals) {
|
|
|
10887
10951
|
`
|
|
10888
10952
|
);
|
|
10889
10953
|
}
|
|
10954
|
+
function clearNeedsInputKey(repoPath, key) {
|
|
10955
|
+
const existing = readNeedsInput(repoPath);
|
|
10956
|
+
if (existing.length === 0) return;
|
|
10957
|
+
const remaining = existing.filter((s) => s.key !== key);
|
|
10958
|
+
if (remaining.length === existing.length) return;
|
|
10959
|
+
writeNeedsInput(repoPath, remaining);
|
|
10960
|
+
}
|
|
10890
10961
|
function buildSettings(partial) {
|
|
10891
10962
|
const s = {};
|
|
10892
10963
|
for (const [k, v] of Object.entries(partial)) {
|
|
@@ -10974,6 +11045,7 @@ async function enrichWithScip(files, projectRoot, existingEdges, entities, optio
|
|
|
10974
11045
|
const outputDir = join29(projectRoot, ".unerr", "scip");
|
|
10975
11046
|
const binaryPath = binaryInfo.path ?? binaryInfo.binaryName;
|
|
10976
11047
|
let extraArgs;
|
|
11048
|
+
let javaPlan = null;
|
|
10977
11049
|
if (language === "typescript") {
|
|
10978
11050
|
if (!existsSync25(join29(projectRoot, "tsconfig.json")) && !existsSync25(join29(projectRoot, "jsconfig.json"))) {
|
|
10979
11051
|
log6.info(
|
|
@@ -10983,9 +11055,12 @@ async function enrichWithScip(files, projectRoot, existingEdges, entities, optio
|
|
|
10983
11055
|
}
|
|
10984
11056
|
}
|
|
10985
11057
|
if (language === "java") {
|
|
10986
|
-
|
|
10987
|
-
if (
|
|
10988
|
-
|
|
11058
|
+
javaPlan = await resolveJavaBuildTool(projectRoot, options);
|
|
11059
|
+
if (!javaPlan) {
|
|
11060
|
+
log6.info(
|
|
11061
|
+
"SCIP skipping java: no recognized build tool (Maven/Gradle/Bazel/Sbt) detected"
|
|
11062
|
+
);
|
|
11063
|
+
continue;
|
|
10989
11064
|
}
|
|
10990
11065
|
}
|
|
10991
11066
|
if (language === "cpp") {
|
|
@@ -11002,7 +11077,13 @@ async function enrichWithScip(files, projectRoot, existingEdges, entities, optio
|
|
|
11002
11077
|
log6.info(
|
|
11003
11078
|
`SCIP enrichment: ${language} (${binaryInfo.bundled ? "bundled" : "external"}: ${binaryInfo.binaryName})`
|
|
11004
11079
|
);
|
|
11005
|
-
const runResult = await
|
|
11080
|
+
const runResult = language === "java" && javaPlan ? await runJavaScipWithCascade({
|
|
11081
|
+
binaryPath,
|
|
11082
|
+
projectRoot,
|
|
11083
|
+
outputDir,
|
|
11084
|
+
timeoutMs: 3e4,
|
|
11085
|
+
plan: javaPlan
|
|
11086
|
+
}) : await runScipIndexer({
|
|
11006
11087
|
language,
|
|
11007
11088
|
binaryPath,
|
|
11008
11089
|
projectRoot,
|
|
@@ -11163,29 +11244,106 @@ async function resolveJavaBuildTool(projectRoot, _options) {
|
|
|
11163
11244
|
const stored = getStoredBuildTool(projectRoot);
|
|
11164
11245
|
if (stored && detected.includes(stored)) {
|
|
11165
11246
|
log6.info(`Java build tool: ${stored} (from config)`);
|
|
11166
|
-
return {
|
|
11247
|
+
return {
|
|
11248
|
+
primary: stored,
|
|
11249
|
+
alternatives: [],
|
|
11250
|
+
reason: "from config",
|
|
11251
|
+
ambiguous: false,
|
|
11252
|
+
fromConfig: true
|
|
11253
|
+
};
|
|
11167
11254
|
}
|
|
11168
11255
|
const choice = chooseBuildTool(detected, projectRoot);
|
|
11169
11256
|
if (!choice) return null;
|
|
11170
|
-
storeBuildTool(projectRoot, choice.tool);
|
|
11171
11257
|
if (choice.ambiguous) {
|
|
11172
|
-
const signal = {
|
|
11173
|
-
type: "needs_input",
|
|
11174
|
-
key: "javaBuildTool",
|
|
11175
|
-
auto: choice.tool,
|
|
11176
|
-
alternatives: choice.alternatives,
|
|
11177
|
-
reason: choice.reason
|
|
11178
|
-
};
|
|
11179
|
-
writeNeedsInput(projectRoot, [signal]);
|
|
11180
11258
|
log6.info(
|
|
11181
|
-
`Java build tool: ${choice.tool} (auto: ${choice.reason}
|
|
11259
|
+
`Java build tool: ${choice.tool} (auto: ${choice.reason}; fallbacks: ${choice.alternatives.join(", ")})`
|
|
11182
11260
|
);
|
|
11183
11261
|
} else {
|
|
11184
11262
|
log6.info(`Java build tool: ${choice.tool} (${choice.reason})`);
|
|
11185
11263
|
}
|
|
11186
11264
|
return {
|
|
11187
|
-
|
|
11188
|
-
|
|
11265
|
+
primary: choice.tool,
|
|
11266
|
+
alternatives: choice.alternatives,
|
|
11267
|
+
reason: choice.reason,
|
|
11268
|
+
ambiguous: choice.ambiguous,
|
|
11269
|
+
fromConfig: false
|
|
11270
|
+
};
|
|
11271
|
+
}
|
|
11272
|
+
function parseScipJavaBuildToolMismatch(error) {
|
|
11273
|
+
if (!error) return [];
|
|
11274
|
+
const match = error.match(
|
|
11275
|
+
/Automatically detected the build tool\(s\) ([^.]+?) but none of them match/i
|
|
11276
|
+
);
|
|
11277
|
+
if (!match?.[1]) return [];
|
|
11278
|
+
const known = new Set(JAVA_BUILD_TOOLS);
|
|
11279
|
+
return match[1].split(/[,\s]+/).map((s) => s.trim()).filter((s) => known.has(s));
|
|
11280
|
+
}
|
|
11281
|
+
async function runJavaScipWithCascade(opts) {
|
|
11282
|
+
const candidates = [
|
|
11283
|
+
opts.plan.primary,
|
|
11284
|
+
...opts.plan.alternatives
|
|
11285
|
+
];
|
|
11286
|
+
const attempted = [];
|
|
11287
|
+
let lastResult = null;
|
|
11288
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
11289
|
+
const tool = candidates[i];
|
|
11290
|
+
attempted.push(tool);
|
|
11291
|
+
if (i === 0) {
|
|
11292
|
+
log6.info(`scip-java attempting --build-tool=${tool}`);
|
|
11293
|
+
} else {
|
|
11294
|
+
log6.info(
|
|
11295
|
+
`scip-java retrying --build-tool=${tool} (fallback #${i}, after ${attempted.slice(0, -1).join(" \u2192 ")})`
|
|
11296
|
+
);
|
|
11297
|
+
}
|
|
11298
|
+
const result = await runScipIndexer({
|
|
11299
|
+
language: "java",
|
|
11300
|
+
binaryPath: opts.binaryPath,
|
|
11301
|
+
projectRoot: opts.projectRoot,
|
|
11302
|
+
outputDir: opts.outputDir,
|
|
11303
|
+
timeoutMs: opts.timeoutMs,
|
|
11304
|
+
extraArgs: [`--build-tool=${tool}`]
|
|
11305
|
+
});
|
|
11306
|
+
lastResult = result;
|
|
11307
|
+
if (result.success) {
|
|
11308
|
+
storeBuildTool(opts.projectRoot, tool);
|
|
11309
|
+
clearNeedsInputKey(opts.projectRoot, "javaBuildTool");
|
|
11310
|
+
if (attempted.length > 1) {
|
|
11311
|
+
log6.info(
|
|
11312
|
+
`scip-java cascade resolved: ${tool} (${attempted.join(" \u2192 ")})`
|
|
11313
|
+
);
|
|
11314
|
+
}
|
|
11315
|
+
return result;
|
|
11316
|
+
}
|
|
11317
|
+
const detectedByScip = parseScipJavaBuildToolMismatch(result.error);
|
|
11318
|
+
if (detectedByScip.length === 0) {
|
|
11319
|
+
return result;
|
|
11320
|
+
}
|
|
11321
|
+
const detectedSet = new Set(detectedByScip);
|
|
11322
|
+
const remaining = candidates.slice(i + 1).filter((t) => detectedSet.has(t) && !attempted.includes(t));
|
|
11323
|
+
if (remaining.length === 0) {
|
|
11324
|
+
log6.warn(
|
|
11325
|
+
`scip-java cascade exhausted: tried ${attempted.join(" \u2192 ")}; scip-java detected ${detectedByScip.join(", ")} but no viable fallback remains`
|
|
11326
|
+
);
|
|
11327
|
+
const signal = {
|
|
11328
|
+
type: "needs_input",
|
|
11329
|
+
key: "javaBuildTool",
|
|
11330
|
+
auto: opts.plan.primary,
|
|
11331
|
+
alternatives: opts.plan.alternatives,
|
|
11332
|
+
reason: `cascade exhausted (tried ${attempted.join(" \u2192 ")}); override with unerr pm config <repo> --java-build-tool=<tool>`
|
|
11333
|
+
};
|
|
11334
|
+
writeNeedsInput(opts.projectRoot, [signal]);
|
|
11335
|
+
return result;
|
|
11336
|
+
}
|
|
11337
|
+
candidates.splice(i + 1, candidates.length - i - 1, ...remaining);
|
|
11338
|
+
log6.warn(
|
|
11339
|
+
`scip-java rejected --build-tool=${tool} (scip-java detected: ${detectedByScip.join(", ")}); cascading to ${candidates[i + 1]}`
|
|
11340
|
+
);
|
|
11341
|
+
}
|
|
11342
|
+
return lastResult ?? {
|
|
11343
|
+
success: false,
|
|
11344
|
+
outputPath: null,
|
|
11345
|
+
durationMs: 0,
|
|
11346
|
+
error: "no Java build tool candidates available"
|
|
11189
11347
|
};
|
|
11190
11348
|
}
|
|
11191
11349
|
function resolveCompileCommandsJson(projectRoot) {
|
|
@@ -11270,6 +11428,7 @@ var init_orchestrator = __esm({
|
|
|
11270
11428
|
init_downloader();
|
|
11271
11429
|
init_merger();
|
|
11272
11430
|
init_runner();
|
|
11431
|
+
init_protocol();
|
|
11273
11432
|
init_registry();
|
|
11274
11433
|
log6 = createModuleLogger("scip-orchestrator");
|
|
11275
11434
|
BUILD_TOOL_FILES = {
|
|
@@ -11813,6 +11972,7 @@ __export(local_indexer_exports, {
|
|
|
11813
11972
|
discoverSourceFiles: () => discoverSourceFiles,
|
|
11814
11973
|
indexLocalProject: () => indexLocalProject,
|
|
11815
11974
|
reindexFile: () => reindexFile,
|
|
11975
|
+
removeOrphanedEntities: () => removeOrphanedEntities,
|
|
11816
11976
|
resolveImportSourceToFile: () => resolveImportSourceToFile,
|
|
11817
11977
|
runCommunityDetection: () => runCommunityDetection,
|
|
11818
11978
|
runConventionDetection: () => runConventionDetection
|
|
@@ -12830,7 +12990,45 @@ async function removeOrphanedEntities(graphStore, liveKeys) {
|
|
|
12830
12990
|
const orphanKeys = existingKeys.filter((k) => !liveKeys.has(k));
|
|
12831
12991
|
if (orphanKeys.length === 0) return;
|
|
12832
12992
|
log7.info(`Removing ${orphanKeys.length} orphaned entities from graph`);
|
|
12833
|
-
for (
|
|
12993
|
+
for (let i = 0; i < orphanKeys.length; i += ORPHAN_BATCH_SIZE) {
|
|
12994
|
+
const chunk = orphanKeys.slice(i, i + ORPHAN_BATCH_SIZE);
|
|
12995
|
+
const keyRows = chunk.map((k) => [k]);
|
|
12996
|
+
try {
|
|
12997
|
+
await db.run(
|
|
12998
|
+
`orphan[k] <- $keys
|
|
12999
|
+
?[from_key, to_key, type] := orphan[from_key], *edges{from_key, to_key, type}
|
|
13000
|
+
:rm edges {from_key, to_key, type}`,
|
|
13001
|
+
{ keys: keyRows }
|
|
13002
|
+
);
|
|
13003
|
+
await db.run(
|
|
13004
|
+
`orphan[k] <- $keys
|
|
13005
|
+
?[from_key, to_key, type] := orphan[to_key], *edges{from_key, to_key, type}
|
|
13006
|
+
:rm edges {from_key, to_key, type}`,
|
|
13007
|
+
{ keys: keyRows }
|
|
13008
|
+
);
|
|
13009
|
+
await db.run(
|
|
13010
|
+
`orphan[k] <- $keys
|
|
13011
|
+
?[token, entity_key] := orphan[entity_key], *search_tokens[token, entity_key]
|
|
13012
|
+
:rm search_tokens {token, entity_key}`,
|
|
13013
|
+
{ keys: keyRows }
|
|
13014
|
+
);
|
|
13015
|
+
await db.run(
|
|
13016
|
+
`orphan[k] <- $keys
|
|
13017
|
+
?[file_path, entity_key] := orphan[entity_key], *file_index[file_path, entity_key]
|
|
13018
|
+
:rm file_index {file_path, entity_key}`,
|
|
13019
|
+
{ keys: keyRows }
|
|
13020
|
+
);
|
|
13021
|
+
await db.run("?[key] <- $keys :rm entities {key}", { keys: keyRows });
|
|
13022
|
+
} catch (err) {
|
|
13023
|
+
log7.info(
|
|
13024
|
+
`Batched orphan removal failed for chunk of ${chunk.length} (${formatUnknownError(err)}); falling back to per-key`
|
|
13025
|
+
);
|
|
13026
|
+
await removeOrphansPerKey(db, chunk);
|
|
13027
|
+
}
|
|
13028
|
+
}
|
|
13029
|
+
}
|
|
13030
|
+
async function removeOrphansPerKey(db, keys) {
|
|
13031
|
+
for (const key of keys) {
|
|
12834
13032
|
try {
|
|
12835
13033
|
await db.run(
|
|
12836
13034
|
"?[from_key, to_key, type] := *edges{from_key, to_key, type}, from_key = $key :rm edges {from_key, to_key, type}",
|
|
@@ -12987,7 +13185,7 @@ async function indexDocumentFiles(projectRoot, graphStore) {
|
|
|
12987
13185
|
}
|
|
12988
13186
|
return docKeys;
|
|
12989
13187
|
}
|
|
12990
|
-
var INDEXABLE_EXTENSIONS, EXCLUDED_DIRS2, EXCLUDED_PATH_PREFIXES, MAX_FILE_SIZE, DOCUMENT_EXTENSIONS, DOCUMENT_NAMES, CI_CD_DIRS, DOC_READ_LIMIT, log7, DOC_TOKEN_PATTERNS;
|
|
13188
|
+
var INDEXABLE_EXTENSIONS, EXCLUDED_DIRS2, EXCLUDED_PATH_PREFIXES, MAX_FILE_SIZE, DOCUMENT_EXTENSIONS, DOCUMENT_NAMES, CI_CD_DIRS, DOC_READ_LIMIT, log7, ORPHAN_BATCH_SIZE, DOC_TOKEN_PATTERNS;
|
|
12991
13189
|
var init_local_indexer = __esm({
|
|
12992
13190
|
"src/intelligence/local-indexer.ts"() {
|
|
12993
13191
|
"use strict";
|
|
@@ -13136,6 +13334,7 @@ var init_local_indexer = __esm({
|
|
|
13136
13334
|
`);
|
|
13137
13335
|
}
|
|
13138
13336
|
};
|
|
13337
|
+
ORPHAN_BATCH_SIZE = 1e3;
|
|
13139
13338
|
DOC_TOKEN_PATTERNS = {
|
|
13140
13339
|
".md": /^#{1,6}\s+(.+)$/gm,
|
|
13141
13340
|
".mdx": /^#{1,6}\s+(.+)$/gm,
|
|
@@ -14771,7 +14970,7 @@ function installFileLogger(opts) {
|
|
|
14771
14970
|
bytesWritten = statSync9(filePath).size;
|
|
14772
14971
|
} catch {
|
|
14773
14972
|
}
|
|
14774
|
-
const
|
|
14973
|
+
const idSuffix = usePrefix ? ` pid=${process.pid} sid=${getOrCreateSid()}] ` : "";
|
|
14775
14974
|
const original = process.stderr.write;
|
|
14776
14975
|
const bound = original.bind(process.stderr);
|
|
14777
14976
|
const wrapped = ((chunk, ...rest) => {
|
|
@@ -14779,6 +14978,7 @@ function installFileLogger(opts) {
|
|
|
14779
14978
|
try {
|
|
14780
14979
|
const text2 = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf-8");
|
|
14781
14980
|
const clean = stripAnsi2(text2);
|
|
14981
|
+
const linePrefix = usePrefix ? `[${(/* @__PURE__ */ new Date()).toISOString()}${idSuffix}` : "";
|
|
14782
14982
|
const out = usePrefix ? prefixLines(clean, linePrefix) : clean;
|
|
14783
14983
|
appendFileSync5(filePath, out);
|
|
14784
14984
|
bytesWritten += out.length;
|
|
@@ -16881,9 +17081,9 @@ function createEmptyAllTime() {
|
|
|
16881
17081
|
function loadStats() {
|
|
16882
17082
|
const currentWeek = getWeekStart();
|
|
16883
17083
|
try {
|
|
16884
|
-
const { readFileSync:
|
|
17084
|
+
const { readFileSync: readFileSync71 } = __require("fs");
|
|
16885
17085
|
const raw = JSON.parse(
|
|
16886
|
-
|
|
17086
|
+
readFileSync71(getStatsPath(), "utf-8")
|
|
16887
17087
|
);
|
|
16888
17088
|
if (raw.version !== 1) {
|
|
16889
17089
|
return {
|
|
@@ -17601,9 +17801,9 @@ function getCumulativePath() {
|
|
|
17601
17801
|
function loadCumulativeStats() {
|
|
17602
17802
|
const currentWeek = getWeekStart2();
|
|
17603
17803
|
try {
|
|
17604
|
-
const { readFileSync:
|
|
17804
|
+
const { readFileSync: readFileSync71 } = __require("fs");
|
|
17605
17805
|
const raw = JSON.parse(
|
|
17606
|
-
|
|
17806
|
+
readFileSync71(getCumulativePath(), "utf-8")
|
|
17607
17807
|
);
|
|
17608
17808
|
if (raw.weekStart !== currentWeek) {
|
|
17609
17809
|
return {
|
|
@@ -17664,9 +17864,9 @@ function createEmptyCumulativeLocal(weekStart) {
|
|
|
17664
17864
|
function loadCumulativeLocalStats() {
|
|
17665
17865
|
const currentWeek = getWeekStart2();
|
|
17666
17866
|
try {
|
|
17667
|
-
const { readFileSync:
|
|
17867
|
+
const { readFileSync: readFileSync71 } = __require("fs");
|
|
17668
17868
|
const raw = JSON.parse(
|
|
17669
|
-
|
|
17869
|
+
readFileSync71(getCumulativeLocalPath(), "utf-8")
|
|
17670
17870
|
);
|
|
17671
17871
|
if (raw.weekStartDate !== currentWeek) {
|
|
17672
17872
|
return createEmptyCumulativeLocal(currentWeek);
|
|
@@ -19119,6 +19319,24 @@ var init_tool_clusters = __esm({
|
|
|
19119
19319
|
"starting",
|
|
19120
19320
|
"planning"
|
|
19121
19321
|
]
|
|
19322
|
+
},
|
|
19323
|
+
{
|
|
19324
|
+
id: "web",
|
|
19325
|
+
name: "Web Fetch",
|
|
19326
|
+
tools: ["fetch_url"],
|
|
19327
|
+
triggerKeywords: [
|
|
19328
|
+
"fetch",
|
|
19329
|
+
"url",
|
|
19330
|
+
"webpage",
|
|
19331
|
+
"web page",
|
|
19332
|
+
"http",
|
|
19333
|
+
"https",
|
|
19334
|
+
"scrape",
|
|
19335
|
+
"docs at",
|
|
19336
|
+
"documentation at",
|
|
19337
|
+
"blog",
|
|
19338
|
+
"article"
|
|
19339
|
+
]
|
|
19122
19340
|
}
|
|
19123
19341
|
];
|
|
19124
19342
|
TOOL_TO_CLUSTER = /* @__PURE__ */ new Map();
|
|
@@ -19236,6 +19454,11 @@ var init_tool_descriptions = __esm({
|
|
|
19236
19454
|
active: "Find callers or callees of an entity across the codebase. Pass direction:'callers' (default) or 'callees'. Catches indirect refs grep misses.",
|
|
19237
19455
|
locked: "[tier 1 \u2014 always exposed]"
|
|
19238
19456
|
},
|
|
19457
|
+
fetch_url: {
|
|
19458
|
+
tier: 1,
|
|
19459
|
+
active: "Fetch a web page and return DOM-extracted markdown passages. Strips chrome, converts to ATX-markdown, splits by heading, ranks by BM25 when prompt is set, caches by content hash. Use instead of built-in WebFetch \u2014 5\u201310\xD7 fewer tokens.",
|
|
19460
|
+
locked: "[tier 1 \u2014 always exposed]"
|
|
19461
|
+
},
|
|
19239
19462
|
// ── Tier 2 — structural unlock ─────────────────────────────────────────
|
|
19240
19463
|
get_critical_nodes: {
|
|
19241
19464
|
tier: 2,
|
|
@@ -19407,6 +19630,36 @@ var init_tool_definitions = __esm({
|
|
|
19407
19630
|
openWorldHint: false
|
|
19408
19631
|
}
|
|
19409
19632
|
},
|
|
19633
|
+
fetch_url: {
|
|
19634
|
+
inputSchema: {
|
|
19635
|
+
type: "object",
|
|
19636
|
+
properties: {
|
|
19637
|
+
url: {
|
|
19638
|
+
type: "string",
|
|
19639
|
+
description: "Absolute URL to fetch (http or https). Localhost is allowed without TLS upgrade."
|
|
19640
|
+
},
|
|
19641
|
+
prompt: {
|
|
19642
|
+
type: "string",
|
|
19643
|
+
description: "Optional. When set AND extracted markdown > 8 KB, passages are re-ranked by BM25 relevance to this prompt (default top 20)."
|
|
19644
|
+
},
|
|
19645
|
+
offset: {
|
|
19646
|
+
type: "integer",
|
|
19647
|
+
description: "Passage index to start at for pagination (default 0). Pair with limit to walk long pages without re-fetching."
|
|
19648
|
+
},
|
|
19649
|
+
limit: {
|
|
19650
|
+
type: "integer",
|
|
19651
|
+
description: "Maximum passages to return (default 30, max 300). Also acts as BM25 topK when prompt is set."
|
|
19652
|
+
},
|
|
19653
|
+
token_budget: TOKEN_BUDGET_PROP
|
|
19654
|
+
},
|
|
19655
|
+
required: ["url"]
|
|
19656
|
+
},
|
|
19657
|
+
annotations: {
|
|
19658
|
+
title: "Fetch Web Page (Markdown + BM25)",
|
|
19659
|
+
readOnlyHint: true,
|
|
19660
|
+
openWorldHint: true
|
|
19661
|
+
}
|
|
19662
|
+
},
|
|
19410
19663
|
file_outline: {
|
|
19411
19664
|
inputSchema: {
|
|
19412
19665
|
type: "object",
|
|
@@ -23084,6 +23337,12 @@ var init_wire_cap = __esm({
|
|
|
23084
23337
|
// statically. The caller should pick from the returned `entities[].name`
|
|
23085
23338
|
// and re-call file_read with that exact value. A literal `entity:<name>`
|
|
23086
23339
|
// hint trains the agent to paste the placeholder verbatim.
|
|
23340
|
+
},
|
|
23341
|
+
fetch_url: {
|
|
23342
|
+
arrayKey: "passages",
|
|
23343
|
+
defaultLimit: 30,
|
|
23344
|
+
maxLimit: 300,
|
|
23345
|
+
cursorArg: "limit"
|
|
23087
23346
|
}
|
|
23088
23347
|
};
|
|
23089
23348
|
HARD_BYTE_CAP = 8192;
|
|
@@ -24309,6 +24568,785 @@ var init_file_read_protocol = __esm({
|
|
|
24309
24568
|
}
|
|
24310
24569
|
});
|
|
24311
24570
|
|
|
24571
|
+
// src/tools/web/bm25-rank.ts
|
|
24572
|
+
function tokenize2(text2) {
|
|
24573
|
+
return text2.toLowerCase().replace(/[^a-z0-9\s]+/g, " ").split(/\s+/).filter((t) => t.length > 1 && !STOPWORDS.has(t));
|
|
24574
|
+
}
|
|
24575
|
+
async function rankPassagesByPrompt(passages, opts) {
|
|
24576
|
+
const prompt = opts.prompt?.trim();
|
|
24577
|
+
if (!prompt || passages.length === 0) return passages;
|
|
24578
|
+
const promptTokens = tokenize2(prompt);
|
|
24579
|
+
if (promptTokens.length === 0) return passages;
|
|
24580
|
+
const mod = await import("wink-bm25-text-search");
|
|
24581
|
+
const engine = mod.default();
|
|
24582
|
+
engine.defineConfig({ fldWeights: { text: 1, heading: 2 } });
|
|
24583
|
+
engine.definePrepTasks([tokenize2]);
|
|
24584
|
+
for (const p of passages) {
|
|
24585
|
+
engine.addDoc(
|
|
24586
|
+
{ text: p.text, heading: p.heading ?? "" },
|
|
24587
|
+
String(p.index)
|
|
24588
|
+
);
|
|
24589
|
+
}
|
|
24590
|
+
engine.consolidate();
|
|
24591
|
+
const hits = engine.search(prompt);
|
|
24592
|
+
if (hits.length === 0) return passages;
|
|
24593
|
+
const topK = Math.max(1, opts.topK ?? Math.min(20, passages.length));
|
|
24594
|
+
const ranked = [];
|
|
24595
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24596
|
+
for (const [docId] of hits.slice(0, topK)) {
|
|
24597
|
+
const idx = Number(docId);
|
|
24598
|
+
const p = passages.find((x2) => x2.index === idx);
|
|
24599
|
+
if (p && !seen.has(idx)) {
|
|
24600
|
+
ranked.push(p);
|
|
24601
|
+
seen.add(idx);
|
|
24602
|
+
}
|
|
24603
|
+
}
|
|
24604
|
+
if (ranked.length === 0) return passages;
|
|
24605
|
+
return ranked;
|
|
24606
|
+
}
|
|
24607
|
+
var STOPWORDS;
|
|
24608
|
+
var init_bm25_rank = __esm({
|
|
24609
|
+
"src/tools/web/bm25-rank.ts"() {
|
|
24610
|
+
"use strict";
|
|
24611
|
+
STOPWORDS = /* @__PURE__ */ new Set([
|
|
24612
|
+
"a",
|
|
24613
|
+
"an",
|
|
24614
|
+
"the",
|
|
24615
|
+
"is",
|
|
24616
|
+
"are",
|
|
24617
|
+
"was",
|
|
24618
|
+
"were",
|
|
24619
|
+
"be",
|
|
24620
|
+
"been",
|
|
24621
|
+
"being",
|
|
24622
|
+
"of",
|
|
24623
|
+
"and",
|
|
24624
|
+
"or",
|
|
24625
|
+
"but",
|
|
24626
|
+
"in",
|
|
24627
|
+
"on",
|
|
24628
|
+
"at",
|
|
24629
|
+
"to",
|
|
24630
|
+
"for",
|
|
24631
|
+
"with",
|
|
24632
|
+
"by",
|
|
24633
|
+
"from",
|
|
24634
|
+
"up",
|
|
24635
|
+
"down",
|
|
24636
|
+
"out",
|
|
24637
|
+
"off",
|
|
24638
|
+
"over",
|
|
24639
|
+
"under",
|
|
24640
|
+
"as",
|
|
24641
|
+
"this",
|
|
24642
|
+
"that",
|
|
24643
|
+
"these",
|
|
24644
|
+
"those",
|
|
24645
|
+
"it",
|
|
24646
|
+
"its",
|
|
24647
|
+
"into",
|
|
24648
|
+
"if",
|
|
24649
|
+
"then",
|
|
24650
|
+
"do",
|
|
24651
|
+
"does",
|
|
24652
|
+
"did"
|
|
24653
|
+
]);
|
|
24654
|
+
}
|
|
24655
|
+
});
|
|
24656
|
+
|
|
24657
|
+
// src/tools/web/diff-cache.ts
|
|
24658
|
+
import { createHash as createHash3 } from "crypto";
|
|
24659
|
+
import { join as join60 } from "path";
|
|
24660
|
+
function hashHtml(html) {
|
|
24661
|
+
return createHash3("sha256").update(html).digest("hex").slice(0, 32);
|
|
24662
|
+
}
|
|
24663
|
+
function lookupFetchCache(cwd, url) {
|
|
24664
|
+
try {
|
|
24665
|
+
const store = openMetricsStore(join60(cwd, ".unerr"));
|
|
24666
|
+
const row = store.getFetchCacheRow(url);
|
|
24667
|
+
if (!row) return { hit: false, prior: null };
|
|
24668
|
+
return { hit: true, prior: row };
|
|
24669
|
+
} catch {
|
|
24670
|
+
return { hit: false, prior: null };
|
|
24671
|
+
}
|
|
24672
|
+
}
|
|
24673
|
+
function storeFetchCache(cwd, row) {
|
|
24674
|
+
try {
|
|
24675
|
+
const store = openMetricsStore(join60(cwd, ".unerr"));
|
|
24676
|
+
store.upsertFetchCacheRow({ ...row, hit_count: 0 });
|
|
24677
|
+
} catch {
|
|
24678
|
+
}
|
|
24679
|
+
}
|
|
24680
|
+
function bumpCacheHit(cwd, url) {
|
|
24681
|
+
try {
|
|
24682
|
+
const store = openMetricsStore(join60(cwd, ".unerr"));
|
|
24683
|
+
store.bumpFetchCacheHitFor(url);
|
|
24684
|
+
} catch {
|
|
24685
|
+
}
|
|
24686
|
+
}
|
|
24687
|
+
function summarizeMarkdownDiff(oldMd, newMd) {
|
|
24688
|
+
if (oldMd === newMd) {
|
|
24689
|
+
return { unchanged: true, changedRegions: 0, addedLines: 0, removedLines: 0 };
|
|
24690
|
+
}
|
|
24691
|
+
const oldLines = new Set(oldMd.split("\n"));
|
|
24692
|
+
const newLines = newMd.split("\n");
|
|
24693
|
+
let added = 0;
|
|
24694
|
+
let regions = 0;
|
|
24695
|
+
let inRegion = false;
|
|
24696
|
+
for (const line of newLines) {
|
|
24697
|
+
if (!oldLines.has(line)) {
|
|
24698
|
+
added++;
|
|
24699
|
+
if (!inRegion) {
|
|
24700
|
+
regions++;
|
|
24701
|
+
inRegion = true;
|
|
24702
|
+
}
|
|
24703
|
+
} else {
|
|
24704
|
+
inRegion = false;
|
|
24705
|
+
}
|
|
24706
|
+
}
|
|
24707
|
+
const newLineSet = new Set(newLines);
|
|
24708
|
+
let removed = 0;
|
|
24709
|
+
for (const line of oldMd.split("\n")) {
|
|
24710
|
+
if (!newLineSet.has(line)) removed++;
|
|
24711
|
+
}
|
|
24712
|
+
return {
|
|
24713
|
+
unchanged: false,
|
|
24714
|
+
changedRegions: regions,
|
|
24715
|
+
addedLines: added,
|
|
24716
|
+
removedLines: removed
|
|
24717
|
+
};
|
|
24718
|
+
}
|
|
24719
|
+
var init_diff_cache = __esm({
|
|
24720
|
+
"src/tools/web/diff-cache.ts"() {
|
|
24721
|
+
"use strict";
|
|
24722
|
+
init_metrics_store();
|
|
24723
|
+
}
|
|
24724
|
+
});
|
|
24725
|
+
|
|
24726
|
+
// src/tools/web/extract.ts
|
|
24727
|
+
async function extractMainContent(html, baseUrl) {
|
|
24728
|
+
const { JSDOM } = await import("jsdom");
|
|
24729
|
+
const dom = new JSDOM(html, { url: baseUrl });
|
|
24730
|
+
const defuddled = await tryDefuddle(dom);
|
|
24731
|
+
if (defuddled && stripTags(defuddled.contentHtml).length >= MIN_USEFUL_CHARS) {
|
|
24732
|
+
return defuddled;
|
|
24733
|
+
}
|
|
24734
|
+
const readabilityResult = await tryReadability(dom);
|
|
24735
|
+
if (readabilityResult && stripTags(readabilityResult.contentHtml).length >= MIN_USEFUL_CHARS) {
|
|
24736
|
+
return readabilityResult;
|
|
24737
|
+
}
|
|
24738
|
+
return rawBodyFallback(dom);
|
|
24739
|
+
}
|
|
24740
|
+
async function tryDefuddle(dom) {
|
|
24741
|
+
try {
|
|
24742
|
+
const mod = await import("defuddle");
|
|
24743
|
+
const DefuddleCtor = mod.default;
|
|
24744
|
+
const doc = dom.window.document;
|
|
24745
|
+
const result = new DefuddleCtor(doc, { markdown: false }).parse();
|
|
24746
|
+
if (!result?.content) return null;
|
|
24747
|
+
return {
|
|
24748
|
+
title: result.title ?? "",
|
|
24749
|
+
contentHtml: result.content,
|
|
24750
|
+
wordCount: result.wordCount ?? wordCountOf(result.content),
|
|
24751
|
+
byline: result.author ?? void 0,
|
|
24752
|
+
excerpt: result.description ?? void 0,
|
|
24753
|
+
extractor: "defuddle"
|
|
24754
|
+
};
|
|
24755
|
+
} catch {
|
|
24756
|
+
return null;
|
|
24757
|
+
}
|
|
24758
|
+
}
|
|
24759
|
+
async function tryReadability(dom) {
|
|
24760
|
+
try {
|
|
24761
|
+
const mod = await import("@mozilla/readability");
|
|
24762
|
+
const doc = dom.window.document;
|
|
24763
|
+
if (mod.isProbablyReaderable && !mod.isProbablyReaderable(doc)) {
|
|
24764
|
+
return null;
|
|
24765
|
+
}
|
|
24766
|
+
const article = new mod.Readability(
|
|
24767
|
+
doc
|
|
24768
|
+
).parse();
|
|
24769
|
+
if (!article?.content) return null;
|
|
24770
|
+
return {
|
|
24771
|
+
title: article.title ?? "",
|
|
24772
|
+
contentHtml: article.content,
|
|
24773
|
+
wordCount: wordCountOf(article.textContent ?? article.content),
|
|
24774
|
+
byline: article.byline ?? void 0,
|
|
24775
|
+
excerpt: article.excerpt ?? void 0,
|
|
24776
|
+
lang: article.lang ?? void 0,
|
|
24777
|
+
extractor: "readability"
|
|
24778
|
+
};
|
|
24779
|
+
} catch {
|
|
24780
|
+
return null;
|
|
24781
|
+
}
|
|
24782
|
+
}
|
|
24783
|
+
function rawBodyFallback(dom) {
|
|
24784
|
+
const doc = dom.window.document;
|
|
24785
|
+
for (const sel of ["script", "style", "noscript", "iframe", "svg"]) {
|
|
24786
|
+
for (const node of doc.querySelectorAll(sel)) node.remove();
|
|
24787
|
+
}
|
|
24788
|
+
const main = doc.querySelector("main") ?? doc.querySelector("article") ?? doc.body ?? doc.documentElement;
|
|
24789
|
+
const html = main?.innerHTML ?? "";
|
|
24790
|
+
return {
|
|
24791
|
+
title: doc.title ?? "",
|
|
24792
|
+
contentHtml: html,
|
|
24793
|
+
wordCount: wordCountOf(main?.textContent ?? ""),
|
|
24794
|
+
extractor: "raw-body"
|
|
24795
|
+
};
|
|
24796
|
+
}
|
|
24797
|
+
function stripTags(html) {
|
|
24798
|
+
return html.replace(/<[^>]+>/g, "").trim();
|
|
24799
|
+
}
|
|
24800
|
+
function wordCountOf(text2) {
|
|
24801
|
+
return text2.trim().split(/\s+/).filter(Boolean).length;
|
|
24802
|
+
}
|
|
24803
|
+
var MIN_USEFUL_CHARS;
|
|
24804
|
+
var init_extract = __esm({
|
|
24805
|
+
"src/tools/web/extract.ts"() {
|
|
24806
|
+
"use strict";
|
|
24807
|
+
MIN_USEFUL_CHARS = 200;
|
|
24808
|
+
}
|
|
24809
|
+
});
|
|
24810
|
+
|
|
24811
|
+
// src/tools/web/markdown.ts
|
|
24812
|
+
async function htmlToMarkdown(html) {
|
|
24813
|
+
if (!html.trim()) return "";
|
|
24814
|
+
const TurndownModule = await import("turndown");
|
|
24815
|
+
const Turndown = TurndownModule.default;
|
|
24816
|
+
const td = new Turndown({
|
|
24817
|
+
headingStyle: "atx",
|
|
24818
|
+
codeBlockStyle: "fenced",
|
|
24819
|
+
hr: "---",
|
|
24820
|
+
bulletListMarker: "-",
|
|
24821
|
+
emDelimiter: "_"
|
|
24822
|
+
});
|
|
24823
|
+
td.addRule("drop-anchor-only", {
|
|
24824
|
+
filter: (node) => {
|
|
24825
|
+
if (node.nodeName !== "A") return false;
|
|
24826
|
+
const href = node.getAttribute("href") ?? "";
|
|
24827
|
+
const text2 = (node.textContent ?? "").trim();
|
|
24828
|
+
return href.startsWith("#") || href === "" && text2 === "";
|
|
24829
|
+
},
|
|
24830
|
+
replacement: (content) => content
|
|
24831
|
+
});
|
|
24832
|
+
td.addRule("strip-tracking-params", {
|
|
24833
|
+
filter: (node) => node.nodeName === "A",
|
|
24834
|
+
replacement: (content, node) => {
|
|
24835
|
+
const rawHref = node.getAttribute("href") ?? "";
|
|
24836
|
+
const cleanHref = cleanUrl(rawHref);
|
|
24837
|
+
const title = node.getAttribute("title");
|
|
24838
|
+
if (!cleanHref) return content;
|
|
24839
|
+
const titleSuffix = title ? ` "${title}"` : "";
|
|
24840
|
+
return `[${content}](${cleanHref}${titleSuffix})`;
|
|
24841
|
+
}
|
|
24842
|
+
});
|
|
24843
|
+
return td.turndown(html);
|
|
24844
|
+
}
|
|
24845
|
+
function cleanUrl(href) {
|
|
24846
|
+
if (!href || href.startsWith("#") || href.startsWith("javascript:")) {
|
|
24847
|
+
return href;
|
|
24848
|
+
}
|
|
24849
|
+
try {
|
|
24850
|
+
const url = new URL(href, "https://example.invalid");
|
|
24851
|
+
const params = url.searchParams;
|
|
24852
|
+
const drop = [];
|
|
24853
|
+
for (const key of params.keys()) {
|
|
24854
|
+
if (TRACKING_PARAMS.test(key)) drop.push(key);
|
|
24855
|
+
}
|
|
24856
|
+
for (const key of drop) params.delete(key);
|
|
24857
|
+
return url.protocol === "https:" && url.hostname === "example.invalid" ? url.pathname + url.search + url.hash : url.toString();
|
|
24858
|
+
} catch {
|
|
24859
|
+
return href;
|
|
24860
|
+
}
|
|
24861
|
+
}
|
|
24862
|
+
var TRACKING_PARAMS;
|
|
24863
|
+
var init_markdown = __esm({
|
|
24864
|
+
"src/tools/web/markdown.ts"() {
|
|
24865
|
+
"use strict";
|
|
24866
|
+
TRACKING_PARAMS = /^(utm_|mc_|gclid$|fbclid$|yclid$|msclkid$|ref$|ref_)/i;
|
|
24867
|
+
}
|
|
24868
|
+
});
|
|
24869
|
+
|
|
24870
|
+
// src/tools/web/passage-split.ts
|
|
24871
|
+
function splitMarkdownIntoPassages(markdown) {
|
|
24872
|
+
const lines = markdown.split("\n");
|
|
24873
|
+
const passages = [];
|
|
24874
|
+
let currentHeading = null;
|
|
24875
|
+
let buffer = [];
|
|
24876
|
+
let bufferStart = 0;
|
|
24877
|
+
let inFence = false;
|
|
24878
|
+
let fenceMarker = "";
|
|
24879
|
+
const flush = () => {
|
|
24880
|
+
const text2 = buffer.join("\n").trim();
|
|
24881
|
+
if (text2) {
|
|
24882
|
+
passages.push({
|
|
24883
|
+
index: passages.length,
|
|
24884
|
+
heading: currentHeading,
|
|
24885
|
+
text: text2,
|
|
24886
|
+
startLine: bufferStart + 1
|
|
24887
|
+
});
|
|
24888
|
+
}
|
|
24889
|
+
buffer = [];
|
|
24890
|
+
};
|
|
24891
|
+
for (let i = 0; i < lines.length; i++) {
|
|
24892
|
+
const line = lines[i] ?? "";
|
|
24893
|
+
const fenceMatch = line.match(/^(```|~~~)/);
|
|
24894
|
+
if (fenceMatch) {
|
|
24895
|
+
if (!inFence) {
|
|
24896
|
+
inFence = true;
|
|
24897
|
+
fenceMarker = fenceMatch[1] ?? "```";
|
|
24898
|
+
if (buffer.length === 0) bufferStart = i;
|
|
24899
|
+
buffer.push(line);
|
|
24900
|
+
} else if (line.startsWith(fenceMarker)) {
|
|
24901
|
+
buffer.push(line);
|
|
24902
|
+
inFence = false;
|
|
24903
|
+
} else {
|
|
24904
|
+
buffer.push(line);
|
|
24905
|
+
}
|
|
24906
|
+
continue;
|
|
24907
|
+
}
|
|
24908
|
+
if (inFence) {
|
|
24909
|
+
buffer.push(line);
|
|
24910
|
+
continue;
|
|
24911
|
+
}
|
|
24912
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+?)\s*$/);
|
|
24913
|
+
if (headingMatch) {
|
|
24914
|
+
flush();
|
|
24915
|
+
currentHeading = headingMatch[2] ?? null;
|
|
24916
|
+
bufferStart = i;
|
|
24917
|
+
buffer.push(line);
|
|
24918
|
+
continue;
|
|
24919
|
+
}
|
|
24920
|
+
if (line.trim() === "") {
|
|
24921
|
+
if (buffer.length > 0) flush();
|
|
24922
|
+
continue;
|
|
24923
|
+
}
|
|
24924
|
+
if (buffer.length === 0) bufferStart = i;
|
|
24925
|
+
buffer.push(line);
|
|
24926
|
+
}
|
|
24927
|
+
flush();
|
|
24928
|
+
return passages;
|
|
24929
|
+
}
|
|
24930
|
+
var init_passage_split = __esm({
|
|
24931
|
+
"src/tools/web/passage-split.ts"() {
|
|
24932
|
+
"use strict";
|
|
24933
|
+
}
|
|
24934
|
+
});
|
|
24935
|
+
|
|
24936
|
+
// src/tools/web/post-process.ts
|
|
24937
|
+
import { readdirSync as readdirSync14, readFileSync as readFileSync51 } from "fs";
|
|
24938
|
+
import { join as join61 } from "path";
|
|
24939
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
24940
|
+
function loadRules() {
|
|
24941
|
+
if (rulesCache) return rulesCache;
|
|
24942
|
+
const map = /* @__PURE__ */ new Map();
|
|
24943
|
+
if (!RULES_DIR) {
|
|
24944
|
+
rulesCache = map;
|
|
24945
|
+
return map;
|
|
24946
|
+
}
|
|
24947
|
+
let entries;
|
|
24948
|
+
try {
|
|
24949
|
+
entries = readdirSync14(RULES_DIR);
|
|
24950
|
+
} catch {
|
|
24951
|
+
rulesCache = map;
|
|
24952
|
+
return map;
|
|
24953
|
+
}
|
|
24954
|
+
for (const name of entries) {
|
|
24955
|
+
if (!name.endsWith(".json")) continue;
|
|
24956
|
+
try {
|
|
24957
|
+
const raw = readFileSync51(join61(RULES_DIR, name), "utf-8");
|
|
24958
|
+
const parsed = JSON.parse(raw);
|
|
24959
|
+
if (parsed.host) map.set(parsed.host.toLowerCase(), parsed);
|
|
24960
|
+
} catch {
|
|
24961
|
+
}
|
|
24962
|
+
}
|
|
24963
|
+
rulesCache = map;
|
|
24964
|
+
return map;
|
|
24965
|
+
}
|
|
24966
|
+
function postProcessMarkdown(markdown, opts = {}) {
|
|
24967
|
+
let out = universalCleanup(markdown);
|
|
24968
|
+
const hostRule = pickHostRule(opts);
|
|
24969
|
+
if (hostRule) out = applyHostRule(out, hostRule);
|
|
24970
|
+
out = universalCleanup(out);
|
|
24971
|
+
return out;
|
|
24972
|
+
}
|
|
24973
|
+
function universalCleanup(md) {
|
|
24974
|
+
return md.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, "\n\n").replace(/^\[\s*\]\([^)]*\)\s*$/gm, "").trim();
|
|
24975
|
+
}
|
|
24976
|
+
function pickHostRule(opts) {
|
|
24977
|
+
if (opts.rules?.length) {
|
|
24978
|
+
return mergeRules(opts.rules);
|
|
24979
|
+
}
|
|
24980
|
+
if (!opts.url) return null;
|
|
24981
|
+
try {
|
|
24982
|
+
const host = new URL(opts.url).hostname.toLowerCase();
|
|
24983
|
+
const rules = loadRules();
|
|
24984
|
+
const exact = rules.get(host);
|
|
24985
|
+
if (exact) return exact;
|
|
24986
|
+
const parts = host.split(".");
|
|
24987
|
+
for (let i = 1; i < parts.length - 1; i++) {
|
|
24988
|
+
const suffix = parts.slice(i).join(".");
|
|
24989
|
+
const match = rules.get(suffix);
|
|
24990
|
+
if (match) return match;
|
|
24991
|
+
}
|
|
24992
|
+
return null;
|
|
24993
|
+
} catch {
|
|
24994
|
+
return null;
|
|
24995
|
+
}
|
|
24996
|
+
}
|
|
24997
|
+
function mergeRules(rules) {
|
|
24998
|
+
return {
|
|
24999
|
+
host: "merged",
|
|
25000
|
+
drop: rules.flatMap((r) => r.drop ?? []),
|
|
25001
|
+
replace: rules.flatMap((r) => r.replace ?? [])
|
|
25002
|
+
};
|
|
25003
|
+
}
|
|
25004
|
+
function applyHostRule(md, rule) {
|
|
25005
|
+
let out = md;
|
|
25006
|
+
if (rule.drop?.length) {
|
|
25007
|
+
for (const pat of rule.drop) {
|
|
25008
|
+
try {
|
|
25009
|
+
const re = new RegExp(pat, "gm");
|
|
25010
|
+
out = out.replace(re, "");
|
|
25011
|
+
} catch {
|
|
25012
|
+
}
|
|
25013
|
+
}
|
|
25014
|
+
}
|
|
25015
|
+
if (rule.replace?.length) {
|
|
25016
|
+
for (const { pattern, with: replacement } of rule.replace) {
|
|
25017
|
+
try {
|
|
25018
|
+
const re = new RegExp(pattern, "gm");
|
|
25019
|
+
out = out.replace(re, replacement);
|
|
25020
|
+
} catch {
|
|
25021
|
+
}
|
|
25022
|
+
}
|
|
25023
|
+
}
|
|
25024
|
+
return out;
|
|
25025
|
+
}
|
|
25026
|
+
var RULES_DIR, rulesCache;
|
|
25027
|
+
var init_post_process = __esm({
|
|
25028
|
+
"src/tools/web/post-process.ts"() {
|
|
25029
|
+
"use strict";
|
|
25030
|
+
RULES_DIR = (() => {
|
|
25031
|
+
try {
|
|
25032
|
+
return join61(fileURLToPath3(new URL(".", import.meta.url)), "rules");
|
|
25033
|
+
} catch {
|
|
25034
|
+
return "";
|
|
25035
|
+
}
|
|
25036
|
+
})();
|
|
25037
|
+
rulesCache = null;
|
|
25038
|
+
}
|
|
25039
|
+
});
|
|
25040
|
+
|
|
25041
|
+
// src/tools/web/spa-render.ts
|
|
25042
|
+
function shouldUsePlaywright(args) {
|
|
25043
|
+
if (!args.config?.playwright?.enabled) return false;
|
|
25044
|
+
if (args.extractor !== "raw-body") return false;
|
|
25045
|
+
return args.wordCount < SPA_EMPTY_WC;
|
|
25046
|
+
}
|
|
25047
|
+
async function renderWithPlaywright(url, config) {
|
|
25048
|
+
const pw = await loadPlaywright();
|
|
25049
|
+
if (!pw) return null;
|
|
25050
|
+
const browser = await pw.chromium.launch({ headless: true });
|
|
25051
|
+
try {
|
|
25052
|
+
const ctx = await browser.newContext({
|
|
25053
|
+
userAgent: "unerr-fetch-url/1.0 (+https://unerr.dev) Mozilla/5.0 compatible"
|
|
25054
|
+
});
|
|
25055
|
+
const page = await ctx.newPage();
|
|
25056
|
+
const response = await page.goto(url, {
|
|
25057
|
+
waitUntil: config.playwright.waitUntil,
|
|
25058
|
+
timeout: config.playwright.timeoutMs
|
|
25059
|
+
});
|
|
25060
|
+
const html = await page.content();
|
|
25061
|
+
return {
|
|
25062
|
+
html,
|
|
25063
|
+
finalUrl: page.url(),
|
|
25064
|
+
status: response?.status() ?? 200
|
|
25065
|
+
};
|
|
25066
|
+
} finally {
|
|
25067
|
+
await browser.close();
|
|
25068
|
+
}
|
|
25069
|
+
}
|
|
25070
|
+
async function loadPlaywright() {
|
|
25071
|
+
try {
|
|
25072
|
+
return await import("playwright");
|
|
25073
|
+
} catch {
|
|
25074
|
+
return null;
|
|
25075
|
+
}
|
|
25076
|
+
}
|
|
25077
|
+
var SPA_EMPTY_WC;
|
|
25078
|
+
var init_spa_render = __esm({
|
|
25079
|
+
"src/tools/web/spa-render.ts"() {
|
|
25080
|
+
"use strict";
|
|
25081
|
+
SPA_EMPTY_WC = 40;
|
|
25082
|
+
}
|
|
25083
|
+
});
|
|
25084
|
+
|
|
25085
|
+
// src/tools/web/telemetry.ts
|
|
25086
|
+
function recordFetchUrlTelemetry(cwd, ev) {
|
|
25087
|
+
const savedPct = ev.rawBytes > 0 ? Math.round((ev.rawBytes - ev.compressedBytes) / ev.rawBytes * 100) : 0;
|
|
25088
|
+
appendCompressionLog(cwd, {
|
|
25089
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25090
|
+
command: `fetch_url ${ev.url}`,
|
|
25091
|
+
category: "fetch_url",
|
|
25092
|
+
confidence: 1,
|
|
25093
|
+
rawBytes: ev.rawBytes,
|
|
25094
|
+
compressedBytes: ev.compressedBytes,
|
|
25095
|
+
savedPct,
|
|
25096
|
+
omniFallback: ev.extractor === "raw-body",
|
|
25097
|
+
teeFile: ev.cacheHit ? "cache-hit" : void 0
|
|
25098
|
+
});
|
|
25099
|
+
}
|
|
25100
|
+
var init_telemetry = __esm({
|
|
25101
|
+
"src/tools/web/telemetry.ts"() {
|
|
25102
|
+
"use strict";
|
|
25103
|
+
init_shell_compression_log();
|
|
25104
|
+
}
|
|
25105
|
+
});
|
|
25106
|
+
|
|
25107
|
+
// src/tools/web/fetch-url-protocol.ts
|
|
25108
|
+
var fetch_url_protocol_exports = {};
|
|
25109
|
+
__export(fetch_url_protocol_exports, {
|
|
25110
|
+
runFetchUrl: () => runFetchUrl
|
|
25111
|
+
});
|
|
25112
|
+
function shouldRank(args, markdown) {
|
|
25113
|
+
if (!args.prompt || args.prompt.trim().length === 0) return false;
|
|
25114
|
+
return Buffer.byteLength(markdown, "utf-8") > BM25_GATE_BYTES;
|
|
25115
|
+
}
|
|
25116
|
+
async function runFetchUrl(args, ctx) {
|
|
25117
|
+
if (!args.url || typeof args.url !== "string") {
|
|
25118
|
+
throw new Error("fetch_url requires a string `url` argument");
|
|
25119
|
+
}
|
|
25120
|
+
const url = upgradeToHttps(args.url);
|
|
25121
|
+
const started = Date.now();
|
|
25122
|
+
const fetched = await fetchHtml(url, ctx.abortSignal);
|
|
25123
|
+
const contentHash = hashHtml(fetched.html);
|
|
25124
|
+
const cache = lookupFetchCache(ctx.cwd, fetched.finalUrl);
|
|
25125
|
+
let markdown;
|
|
25126
|
+
let title;
|
|
25127
|
+
let extractor;
|
|
25128
|
+
let wordCount;
|
|
25129
|
+
let cacheHit = false;
|
|
25130
|
+
let diff;
|
|
25131
|
+
if (cache.hit && cache.prior && cache.prior.content_hash === contentHash) {
|
|
25132
|
+
markdown = cache.prior.markdown;
|
|
25133
|
+
title = cache.prior.title;
|
|
25134
|
+
extractor = "cache";
|
|
25135
|
+
wordCount = markdown.trim().split(/\s+/).filter(Boolean).length;
|
|
25136
|
+
cacheHit = true;
|
|
25137
|
+
diff = {
|
|
25138
|
+
unchanged: true,
|
|
25139
|
+
changed_regions: 0,
|
|
25140
|
+
added_lines: 0,
|
|
25141
|
+
removed_lines: 0
|
|
25142
|
+
};
|
|
25143
|
+
bumpCacheHit(ctx.cwd, fetched.finalUrl);
|
|
25144
|
+
} else {
|
|
25145
|
+
let extracted = await extractMainContent(fetched.html, fetched.finalUrl);
|
|
25146
|
+
const settings = safeLoadSettings(ctx.cwd);
|
|
25147
|
+
if (shouldUsePlaywright({
|
|
25148
|
+
config: settings?.fetchUrl,
|
|
25149
|
+
extractor: extracted.extractor,
|
|
25150
|
+
wordCount: extracted.wordCount
|
|
25151
|
+
}) && settings) {
|
|
25152
|
+
const rendered = await renderWithPlaywright(
|
|
25153
|
+
fetched.finalUrl,
|
|
25154
|
+
settings.fetchUrl
|
|
25155
|
+
);
|
|
25156
|
+
if (rendered) {
|
|
25157
|
+
fetched.html = rendered.html;
|
|
25158
|
+
fetched.finalUrl = rendered.finalUrl;
|
|
25159
|
+
fetched.status = rendered.status;
|
|
25160
|
+
extracted = await extractMainContent(rendered.html, rendered.finalUrl);
|
|
25161
|
+
}
|
|
25162
|
+
}
|
|
25163
|
+
const rawMarkdown = await htmlToMarkdown(extracted.contentHtml);
|
|
25164
|
+
markdown = postProcessMarkdown(rawMarkdown, { url: fetched.finalUrl });
|
|
25165
|
+
title = extracted.title;
|
|
25166
|
+
extractor = extracted.extractor;
|
|
25167
|
+
wordCount = extracted.wordCount;
|
|
25168
|
+
if (cache.prior) {
|
|
25169
|
+
const summary = summarizeMarkdownDiff(cache.prior.markdown, markdown);
|
|
25170
|
+
diff = {
|
|
25171
|
+
unchanged: summary.unchanged,
|
|
25172
|
+
changed_regions: summary.changedRegions,
|
|
25173
|
+
added_lines: summary.addedLines,
|
|
25174
|
+
removed_lines: summary.removedLines
|
|
25175
|
+
};
|
|
25176
|
+
}
|
|
25177
|
+
storeFetchCache(ctx.cwd, {
|
|
25178
|
+
url: fetched.finalUrl,
|
|
25179
|
+
content_hash: contentHash,
|
|
25180
|
+
markdown,
|
|
25181
|
+
title,
|
|
25182
|
+
extractor,
|
|
25183
|
+
raw_bytes: Buffer.byteLength(fetched.html, "utf-8"),
|
|
25184
|
+
compressed_bytes: Buffer.byteLength(markdown, "utf-8"),
|
|
25185
|
+
fetched_at: Date.now()
|
|
25186
|
+
});
|
|
25187
|
+
}
|
|
25188
|
+
const allPassages = splitMarkdownIntoPassages(markdown);
|
|
25189
|
+
const ranked = shouldRank(args, markdown) ? await rankPassagesByPrompt(allPassages, {
|
|
25190
|
+
prompt: args.prompt ?? "",
|
|
25191
|
+
topK: args.limit ?? BM25_DEFAULT_TOPK
|
|
25192
|
+
}) : allPassages;
|
|
25193
|
+
const offset = Math.max(0, args.offset ?? 0);
|
|
25194
|
+
const sliced = offset > 0 ? ranked.slice(offset) : ranked;
|
|
25195
|
+
const rawBytes = byteLength(fetched.html);
|
|
25196
|
+
const compressedBytes = byteLength(markdown);
|
|
25197
|
+
recordFetchUrlTelemetry(ctx.cwd, {
|
|
25198
|
+
url: fetched.finalUrl,
|
|
25199
|
+
rawBytes,
|
|
25200
|
+
compressedBytes,
|
|
25201
|
+
durationMs: Date.now() - started,
|
|
25202
|
+
extractor: extractor === "cache" ? "raw-body" : extractor,
|
|
25203
|
+
cacheHit
|
|
25204
|
+
});
|
|
25205
|
+
return {
|
|
25206
|
+
url: args.url,
|
|
25207
|
+
final_url: fetched.finalUrl,
|
|
25208
|
+
status: fetched.status,
|
|
25209
|
+
title,
|
|
25210
|
+
extractor,
|
|
25211
|
+
word_count: wordCount,
|
|
25212
|
+
cache_hit: cacheHit,
|
|
25213
|
+
diff,
|
|
25214
|
+
raw_bytes: rawBytes,
|
|
25215
|
+
extracted_bytes: compressedBytes,
|
|
25216
|
+
compression_ratio: rawBytes > 0 ? Math.round((1 - compressedBytes / rawBytes) * 100) / 100 : 0,
|
|
25217
|
+
passages: sliced.map((p) => ({
|
|
25218
|
+
index: p.index,
|
|
25219
|
+
heading: p.heading,
|
|
25220
|
+
text: p.text,
|
|
25221
|
+
start_line: p.startLine
|
|
25222
|
+
})),
|
|
25223
|
+
total: allPassages.length
|
|
25224
|
+
};
|
|
25225
|
+
}
|
|
25226
|
+
function upgradeToHttps(url) {
|
|
25227
|
+
if (!url.startsWith("http://")) return url;
|
|
25228
|
+
try {
|
|
25229
|
+
const host = new URL(url).hostname;
|
|
25230
|
+
if (host === "localhost" || host === "127.0.0.1" || host === "::1") {
|
|
25231
|
+
return url;
|
|
25232
|
+
}
|
|
25233
|
+
} catch {
|
|
25234
|
+
return url;
|
|
25235
|
+
}
|
|
25236
|
+
return "https://" + url.slice(7);
|
|
25237
|
+
}
|
|
25238
|
+
async function fetchHtml(url, abortSignal) {
|
|
25239
|
+
const controller = new AbortController();
|
|
25240
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
25241
|
+
const signal = abortSignal ? composeSignals(controller.signal, abortSignal) : controller.signal;
|
|
25242
|
+
try {
|
|
25243
|
+
const res = await fetch(url, {
|
|
25244
|
+
signal,
|
|
25245
|
+
redirect: "follow",
|
|
25246
|
+
headers: {
|
|
25247
|
+
"user-agent": "unerr-fetch-url/1.0 (+https://unerr.dev) Mozilla/5.0 compatible",
|
|
25248
|
+
accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
25249
|
+
}
|
|
25250
|
+
});
|
|
25251
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
25252
|
+
if (!contentType.includes("html") && !contentType.includes("xml")) {
|
|
25253
|
+
throw new Error(
|
|
25254
|
+
`fetch_url expected HTML response, got content-type: ${contentType || "unknown"}`
|
|
25255
|
+
);
|
|
25256
|
+
}
|
|
25257
|
+
const reader = res.body?.getReader();
|
|
25258
|
+
if (!reader) {
|
|
25259
|
+
const text2 = await res.text();
|
|
25260
|
+
return capHtml({
|
|
25261
|
+
html: text2,
|
|
25262
|
+
finalUrl: res.url,
|
|
25263
|
+
status: res.status,
|
|
25264
|
+
contentType
|
|
25265
|
+
});
|
|
25266
|
+
}
|
|
25267
|
+
const chunks = [];
|
|
25268
|
+
let total = 0;
|
|
25269
|
+
for (; ; ) {
|
|
25270
|
+
const { done, value } = await reader.read();
|
|
25271
|
+
if (done) break;
|
|
25272
|
+
if (value) {
|
|
25273
|
+
total += value.byteLength;
|
|
25274
|
+
if (total > MAX_HTML_BYTES) {
|
|
25275
|
+
await reader.cancel();
|
|
25276
|
+
break;
|
|
25277
|
+
}
|
|
25278
|
+
chunks.push(value);
|
|
25279
|
+
}
|
|
25280
|
+
}
|
|
25281
|
+
const merged = concatBytes(chunks);
|
|
25282
|
+
const html = new TextDecoder("utf-8", { fatal: false }).decode(merged);
|
|
25283
|
+
return capHtml({
|
|
25284
|
+
html,
|
|
25285
|
+
finalUrl: res.url,
|
|
25286
|
+
status: res.status,
|
|
25287
|
+
contentType
|
|
25288
|
+
});
|
|
25289
|
+
} finally {
|
|
25290
|
+
clearTimeout(timer);
|
|
25291
|
+
}
|
|
25292
|
+
}
|
|
25293
|
+
function capHtml(fetched) {
|
|
25294
|
+
if (fetched.html.length > MAX_HTML_BYTES) {
|
|
25295
|
+
return { ...fetched, html: fetched.html.slice(0, MAX_HTML_BYTES) };
|
|
25296
|
+
}
|
|
25297
|
+
return fetched;
|
|
25298
|
+
}
|
|
25299
|
+
function composeSignals(a, b) {
|
|
25300
|
+
const controller = new AbortController();
|
|
25301
|
+
const onAbort = () => controller.abort();
|
|
25302
|
+
if (a.aborted || b.aborted) controller.abort();
|
|
25303
|
+
else {
|
|
25304
|
+
a.addEventListener("abort", onAbort, { once: true });
|
|
25305
|
+
b.addEventListener("abort", onAbort, { once: true });
|
|
25306
|
+
}
|
|
25307
|
+
return controller.signal;
|
|
25308
|
+
}
|
|
25309
|
+
function byteLength(s) {
|
|
25310
|
+
return Buffer.byteLength(s, "utf-8");
|
|
25311
|
+
}
|
|
25312
|
+
function safeLoadSettings(cwd) {
|
|
25313
|
+
try {
|
|
25314
|
+
return loadSettings(cwd);
|
|
25315
|
+
} catch {
|
|
25316
|
+
return null;
|
|
25317
|
+
}
|
|
25318
|
+
}
|
|
25319
|
+
function concatBytes(chunks) {
|
|
25320
|
+
let total = 0;
|
|
25321
|
+
for (const c of chunks) total += c.byteLength;
|
|
25322
|
+
const out = new Uint8Array(total);
|
|
25323
|
+
let offset = 0;
|
|
25324
|
+
for (const c of chunks) {
|
|
25325
|
+
out.set(c, offset);
|
|
25326
|
+
offset += c.byteLength;
|
|
25327
|
+
}
|
|
25328
|
+
return out;
|
|
25329
|
+
}
|
|
25330
|
+
var FETCH_TIMEOUT_MS, MAX_HTML_BYTES, BM25_GATE_BYTES, BM25_DEFAULT_TOPK;
|
|
25331
|
+
var init_fetch_url_protocol = __esm({
|
|
25332
|
+
"src/tools/web/fetch-url-protocol.ts"() {
|
|
25333
|
+
"use strict";
|
|
25334
|
+
init_settings();
|
|
25335
|
+
init_bm25_rank();
|
|
25336
|
+
init_diff_cache();
|
|
25337
|
+
init_extract();
|
|
25338
|
+
init_markdown();
|
|
25339
|
+
init_passage_split();
|
|
25340
|
+
init_post_process();
|
|
25341
|
+
init_spa_render();
|
|
25342
|
+
init_telemetry();
|
|
25343
|
+
FETCH_TIMEOUT_MS = 15e3;
|
|
25344
|
+
MAX_HTML_BYTES = 5 * 1024 * 1024;
|
|
25345
|
+
BM25_GATE_BYTES = 8 * 1024;
|
|
25346
|
+
BM25_DEFAULT_TOPK = 20;
|
|
25347
|
+
}
|
|
25348
|
+
});
|
|
25349
|
+
|
|
24312
25350
|
// src/intelligence/query-router.ts
|
|
24313
25351
|
var query_router_exports = {};
|
|
24314
25352
|
__export(query_router_exports, {
|
|
@@ -24564,7 +25602,9 @@ var init_query_router = __esm({
|
|
|
24564
25602
|
"get_test_coverage",
|
|
24565
25603
|
// Sprint FE-B: file read protocol
|
|
24566
25604
|
"file_outline",
|
|
24567
|
-
"file_read"
|
|
25605
|
+
"file_read",
|
|
25606
|
+
// Sprint FU-1: web fetch
|
|
25607
|
+
"fetch_url"
|
|
24568
25608
|
]);
|
|
24569
25609
|
ENRICHABLE_TOOLS = /* @__PURE__ */ new Set([
|
|
24570
25610
|
// Agent-facing tools
|
|
@@ -25362,7 +26402,8 @@ var init_query_router = __esm({
|
|
|
25362
26402
|
const saved = estimate.tokensWithout - estimate.tokensUsed;
|
|
25363
26403
|
if (saved > 0) {
|
|
25364
26404
|
const isFileNav = toolName === "file_read" || toolName === "file_outline" || toolName === "get_file";
|
|
25365
|
-
const
|
|
26405
|
+
const isFetchUrl = toolName === "fetch_url";
|
|
26406
|
+
const mechanism = isFetchUrl ? "fetch_url" : isFileNav ? "file_read" : "graph_query";
|
|
25366
26407
|
enrichTokensSaved = saved;
|
|
25367
26408
|
enrichSavingsMechanism = mechanism;
|
|
25368
26409
|
const dollarSavings = calculateDollarSavings(saved);
|
|
@@ -26280,11 +27321,11 @@ var init_query_router = __esm({
|
|
|
26280
27321
|
const entity = await this.resolveEntityWithOverlay(key);
|
|
26281
27322
|
if (entity?.file_path && entity.start_line > 0) {
|
|
26282
27323
|
try {
|
|
26283
|
-
const { readFileSync:
|
|
27324
|
+
const { readFileSync: readFileSync71 } = await import("fs");
|
|
26284
27325
|
const { resolve: resolve6 } = await import("path");
|
|
26285
27326
|
const cwd = this.projectRoot ?? process.cwd();
|
|
26286
27327
|
const abs = resolve6(cwd, entity.file_path);
|
|
26287
|
-
const lines =
|
|
27328
|
+
const lines = readFileSync71(abs, "utf-8").split("\n");
|
|
26288
27329
|
const start = entity.start_line - 1;
|
|
26289
27330
|
const end = entity.end_line ?? lines.length;
|
|
26290
27331
|
const bodyLines = lines.slice(start, end);
|
|
@@ -26522,6 +27563,12 @@ var init_query_router = __esm({
|
|
|
26522
27563
|
graph: this.localGraph
|
|
26523
27564
|
});
|
|
26524
27565
|
}
|
|
27566
|
+
case "fetch_url": {
|
|
27567
|
+
const { runFetchUrl: runFetchUrl2 } = await Promise.resolve().then(() => (init_fetch_url_protocol(), fetch_url_protocol_exports));
|
|
27568
|
+
return runFetchUrl2(args, {
|
|
27569
|
+
cwd: this.projectRoot ?? process.cwd()
|
|
27570
|
+
});
|
|
27571
|
+
}
|
|
26525
27572
|
default:
|
|
26526
27573
|
throw new Error(`Unknown local tool: ${toolName}`);
|
|
26527
27574
|
}
|
|
@@ -27881,8 +28928,8 @@ __export(causal_bridge_exports, {
|
|
|
27881
28928
|
assembleCausalChain: () => assembleCausalChain,
|
|
27882
28929
|
computeDurability: () => computeDurability
|
|
27883
28930
|
});
|
|
27884
|
-
import { existsSync as existsSync59, readFileSync as
|
|
27885
|
-
import { join as
|
|
28931
|
+
import { existsSync as existsSync59, readFileSync as readFileSync52 } from "fs";
|
|
28932
|
+
import { join as join62 } from "path";
|
|
27886
28933
|
function computeAggregateDurability(interactions) {
|
|
27887
28934
|
if (interactions.length === 0) return 1;
|
|
27888
28935
|
const survivedCount = interactions.filter((i) => i.survived).length;
|
|
@@ -28039,9 +29086,9 @@ var init_causal_bridge = __esm({
|
|
|
28039
29086
|
return chains;
|
|
28040
29087
|
}
|
|
28041
29088
|
loadEntityLedgerEntries(entityKey2) {
|
|
28042
|
-
const ledgerPath =
|
|
29089
|
+
const ledgerPath = join62(this.unerrDir, "ledger", "shadow.jsonl");
|
|
28043
29090
|
if (!existsSync59(ledgerPath)) return [];
|
|
28044
|
-
const content =
|
|
29091
|
+
const content = readFileSync52(ledgerPath, "utf-8");
|
|
28045
29092
|
const lines = content.split("\n").filter((l) => l.trim().length > 0);
|
|
28046
29093
|
const entries = [];
|
|
28047
29094
|
for (const line of lines) {
|
|
@@ -28527,11 +29574,11 @@ var context_ledger_exports = {};
|
|
|
28527
29574
|
__export(context_ledger_exports, {
|
|
28528
29575
|
createContextLedger: () => createContextLedger
|
|
28529
29576
|
});
|
|
28530
|
-
import { existsSync as existsSync60, mkdirSync as mkdirSync32, readFileSync as
|
|
28531
|
-
import { join as
|
|
29577
|
+
import { existsSync as existsSync60, mkdirSync as mkdirSync32, readFileSync as readFileSync53, writeFileSync as writeFileSync27 } from "fs";
|
|
29578
|
+
import { join as join63 } from "path";
|
|
28532
29579
|
function createContextLedger(unerrDir2) {
|
|
28533
|
-
const stateDir =
|
|
28534
|
-
const filePath =
|
|
29580
|
+
const stateDir = join63(unerrDir2, "state");
|
|
29581
|
+
const filePath = join63(stateDir, "context-ledger.json");
|
|
28535
29582
|
let records = [];
|
|
28536
29583
|
let index = /* @__PURE__ */ new Map();
|
|
28537
29584
|
function ensureDir() {
|
|
@@ -28550,7 +29597,7 @@ function createContextLedger(unerrDir2) {
|
|
|
28550
29597
|
return /* @__PURE__ */ new Map();
|
|
28551
29598
|
}
|
|
28552
29599
|
try {
|
|
28553
|
-
const raw =
|
|
29600
|
+
const raw = readFileSync53(filePath, "utf-8");
|
|
28554
29601
|
const parsed = JSON.parse(raw);
|
|
28555
29602
|
records = Array.isArray(parsed) ? parsed : [];
|
|
28556
29603
|
} catch {
|
|
@@ -29477,11 +30524,11 @@ __export(intent_correlator_exports, {
|
|
|
29477
30524
|
import {
|
|
29478
30525
|
existsSync as existsSync61,
|
|
29479
30526
|
mkdirSync as mkdirSync33,
|
|
29480
|
-
readFileSync as
|
|
30527
|
+
readFileSync as readFileSync54,
|
|
29481
30528
|
renameSync as renameSync2,
|
|
29482
30529
|
writeFileSync as writeFileSync28
|
|
29483
30530
|
} from "fs";
|
|
29484
|
-
import { join as
|
|
30531
|
+
import { join as join64 } from "path";
|
|
29485
30532
|
function extractFiles4(args) {
|
|
29486
30533
|
const files = args.files;
|
|
29487
30534
|
if (files && Array.isArray(files)) {
|
|
@@ -29529,8 +30576,8 @@ var init_intent_correlator = __esm({
|
|
|
29529
30576
|
pendingPath;
|
|
29530
30577
|
pending = [];
|
|
29531
30578
|
constructor(unerrDir2) {
|
|
29532
|
-
this.ledgerDir =
|
|
29533
|
-
this.pendingPath =
|
|
30579
|
+
this.ledgerDir = join64(unerrDir2, "ledger");
|
|
30580
|
+
this.pendingPath = join64(this.ledgerDir, "pending_correlations.json");
|
|
29534
30581
|
if (!existsSync61(this.ledgerDir)) {
|
|
29535
30582
|
mkdirSync33(this.ledgerDir, { recursive: true });
|
|
29536
30583
|
}
|
|
@@ -29625,7 +30672,7 @@ var init_intent_correlator = __esm({
|
|
|
29625
30672
|
load() {
|
|
29626
30673
|
if (!existsSync61(this.pendingPath)) return;
|
|
29627
30674
|
try {
|
|
29628
|
-
const raw =
|
|
30675
|
+
const raw = readFileSync54(this.pendingPath, "utf-8");
|
|
29629
30676
|
const parsed = JSON.parse(raw);
|
|
29630
30677
|
if (Array.isArray(parsed)) {
|
|
29631
30678
|
this.pending = parsed;
|
|
@@ -30190,7 +31237,7 @@ var init_session_state = __esm({
|
|
|
30190
31237
|
|
|
30191
31238
|
// src/proxy/tool-exposure-store.ts
|
|
30192
31239
|
import { promises as fs6 } from "fs";
|
|
30193
|
-
import { dirname as dirname16, join as
|
|
31240
|
+
import { dirname as dirname16, join as join65 } from "path";
|
|
30194
31241
|
var ToolExposureStore;
|
|
30195
31242
|
var init_tool_exposure_store = __esm({
|
|
30196
31243
|
"src/proxy/tool-exposure-store.ts"() {
|
|
@@ -30200,7 +31247,7 @@ var init_tool_exposure_store = __esm({
|
|
|
30200
31247
|
sessionId;
|
|
30201
31248
|
ensuredDir = false;
|
|
30202
31249
|
constructor(unerrDir2, sessionId) {
|
|
30203
|
-
this.filePath =
|
|
31250
|
+
this.filePath = join65(unerrDir2, "router", "exposure-events.jsonl");
|
|
30204
31251
|
this.sessionId = sessionId;
|
|
30205
31252
|
}
|
|
30206
31253
|
/**
|
|
@@ -30462,11 +31509,11 @@ var init_router_gateway = __esm({
|
|
|
30462
31509
|
|
|
30463
31510
|
// src/timeline/timeline-store.ts
|
|
30464
31511
|
import { existsSync as existsSync62, mkdirSync as mkdirSync34 } from "fs";
|
|
30465
|
-
import { join as
|
|
31512
|
+
import { join as join66 } from "path";
|
|
30466
31513
|
async function openTimelineDb(projectRoot) {
|
|
30467
|
-
const unerrDir2 =
|
|
31514
|
+
const unerrDir2 = join66(projectRoot, ".unerr");
|
|
30468
31515
|
mkdirSync34(unerrDir2, { recursive: true });
|
|
30469
|
-
const dbPath =
|
|
31516
|
+
const dbPath = join66(unerrDir2, TIMELINE_DB_FILENAME);
|
|
30470
31517
|
const isNew = !existsSync62(dbPath);
|
|
30471
31518
|
const cozoModule = await import("cozo-node");
|
|
30472
31519
|
const CozoDbConstructor = cozoModule.default ? cozoModule.default.CozoDb : cozoModule.CozoDb;
|
|
@@ -31510,23 +32557,23 @@ import {
|
|
|
31510
32557
|
appendFileSync as appendFileSync8,
|
|
31511
32558
|
existsSync as existsSync63,
|
|
31512
32559
|
mkdirSync as mkdirSync35,
|
|
31513
|
-
readFileSync as
|
|
32560
|
+
readFileSync as readFileSync55,
|
|
31514
32561
|
renameSync as renameSync3,
|
|
31515
32562
|
writeFileSync as writeFileSync29
|
|
31516
32563
|
} from "fs";
|
|
31517
|
-
import { join as
|
|
32564
|
+
import { join as join67 } from "path";
|
|
31518
32565
|
import { gzipSync } from "zlib";
|
|
31519
32566
|
function archiveShadowLedger(unerrDir2, opts = {}) {
|
|
31520
|
-
const ledgerDir =
|
|
31521
|
-
const filePath =
|
|
31522
|
-
const archiveDir =
|
|
32567
|
+
const ledgerDir = join67(unerrDir2, "ledger");
|
|
32568
|
+
const filePath = join67(ledgerDir, "shadow.jsonl");
|
|
32569
|
+
const archiveDir = join67(ledgerDir, "archive");
|
|
31523
32570
|
if (!existsSync63(filePath)) {
|
|
31524
32571
|
return { archived: 0, kept: 0, archivePath: null };
|
|
31525
32572
|
}
|
|
31526
32573
|
const retainMs = opts.retainMs ?? DEFAULT_RETAIN_MS;
|
|
31527
32574
|
const now = opts.nowMs ?? Date.now();
|
|
31528
32575
|
const cutoff = now - retainMs;
|
|
31529
|
-
const raw =
|
|
32576
|
+
const raw = readFileSync55(filePath, "utf-8");
|
|
31530
32577
|
const initialBytes = Buffer.byteLength(raw);
|
|
31531
32578
|
const lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
31532
32579
|
const keep = [];
|
|
@@ -31551,7 +32598,7 @@ function archiveShadowLedger(unerrDir2, opts = {}) {
|
|
|
31551
32598
|
}
|
|
31552
32599
|
mkdirSync35(archiveDir, { recursive: true });
|
|
31553
32600
|
const dateStamp = new Date(now).toISOString().slice(0, 10);
|
|
31554
|
-
const archivePath =
|
|
32601
|
+
const archivePath = join67(archiveDir, `${dateStamp}.jsonl.gz`);
|
|
31555
32602
|
const payload = `${archive.join("\n")}
|
|
31556
32603
|
`;
|
|
31557
32604
|
const gz = gzipSync(Buffer.from(payload, "utf-8"));
|
|
@@ -31563,7 +32610,7 @@ function archiveShadowLedger(unerrDir2, opts = {}) {
|
|
|
31563
32610
|
const tmpPath = `${filePath}.tmp-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
31564
32611
|
const kept = `${keep.join("\n")}${keep.length > 0 ? "\n" : ""}`;
|
|
31565
32612
|
writeFileSync29(tmpPath, kept, "utf-8");
|
|
31566
|
-
const afterRaw =
|
|
32613
|
+
const afterRaw = readFileSync55(filePath, "utf-8");
|
|
31567
32614
|
const afterBytes = Buffer.byteLength(afterRaw);
|
|
31568
32615
|
if (afterBytes > initialBytes) {
|
|
31569
32616
|
const tail = afterRaw.slice(raw.length);
|
|
@@ -32072,12 +33119,12 @@ import { randomBytes as randomBytes5 } from "crypto";
|
|
|
32072
33119
|
import {
|
|
32073
33120
|
existsSync as existsSync64,
|
|
32074
33121
|
mkdirSync as mkdirSync36,
|
|
32075
|
-
readFileSync as
|
|
32076
|
-
readdirSync as
|
|
33122
|
+
readFileSync as readFileSync56,
|
|
33123
|
+
readdirSync as readdirSync15,
|
|
32077
33124
|
rmSync as rmSync2,
|
|
32078
33125
|
writeFileSync as writeFileSync30
|
|
32079
33126
|
} from "fs";
|
|
32080
|
-
import { join as
|
|
33127
|
+
import { join as join68 } from "path";
|
|
32081
33128
|
var _log2, MAX_SNAPSHOTS, AUTO_SNAPSHOT_COOLDOWN_MS, WorkingSnapshotStore;
|
|
32082
33129
|
var init_working_snapshots = __esm({
|
|
32083
33130
|
"src/tracking/working-snapshots.ts"() {
|
|
@@ -32095,7 +33142,7 @@ var init_working_snapshots = __esm({
|
|
|
32095
33142
|
unerrDir;
|
|
32096
33143
|
constructor(unerrDir2) {
|
|
32097
33144
|
this.unerrDir = unerrDir2;
|
|
32098
|
-
this.snapshotDir =
|
|
33145
|
+
this.snapshotDir = join68(unerrDir2, "snapshots");
|
|
32099
33146
|
if (!existsSync64(this.snapshotDir)) {
|
|
32100
33147
|
mkdirSync36(this.snapshotDir, { recursive: true });
|
|
32101
33148
|
}
|
|
@@ -32116,7 +33163,7 @@ var init_working_snapshots = __esm({
|
|
|
32116
33163
|
processed: false
|
|
32117
33164
|
};
|
|
32118
33165
|
writeFileSync30(
|
|
32119
|
-
|
|
33166
|
+
join68(this.snapshotDir, `${id}.json`),
|
|
32120
33167
|
JSON.stringify(snapshot, null, 2),
|
|
32121
33168
|
"utf-8"
|
|
32122
33169
|
);
|
|
@@ -32130,10 +33177,10 @@ var init_working_snapshots = __esm({
|
|
|
32130
33177
|
* Get a snapshot by ID.
|
|
32131
33178
|
*/
|
|
32132
33179
|
get(snapshotId) {
|
|
32133
|
-
const filePath =
|
|
33180
|
+
const filePath = join68(this.snapshotDir, `${snapshotId}.json`);
|
|
32134
33181
|
if (!existsSync64(filePath)) return null;
|
|
32135
33182
|
try {
|
|
32136
|
-
return JSON.parse(
|
|
33183
|
+
return JSON.parse(readFileSync56(filePath, "utf-8"));
|
|
32137
33184
|
} catch {
|
|
32138
33185
|
return null;
|
|
32139
33186
|
}
|
|
@@ -32143,13 +33190,13 @@ var init_working_snapshots = __esm({
|
|
|
32143
33190
|
*/
|
|
32144
33191
|
list() {
|
|
32145
33192
|
if (!existsSync64(this.snapshotDir)) return [];
|
|
32146
|
-
const files =
|
|
33193
|
+
const files = readdirSync15(this.snapshotDir).filter(
|
|
32147
33194
|
(f) => f.endsWith(".json")
|
|
32148
33195
|
);
|
|
32149
33196
|
const snapshots = [];
|
|
32150
33197
|
for (const file of files) {
|
|
32151
33198
|
try {
|
|
32152
|
-
const raw =
|
|
33199
|
+
const raw = readFileSync56(join68(this.snapshotDir, file), "utf-8");
|
|
32153
33200
|
snapshots.push(JSON.parse(raw));
|
|
32154
33201
|
} catch {
|
|
32155
33202
|
}
|
|
@@ -32190,7 +33237,7 @@ var init_working_snapshots = __esm({
|
|
|
32190
33237
|
if (!snapshot) return;
|
|
32191
33238
|
snapshot.processed = true;
|
|
32192
33239
|
writeFileSync30(
|
|
32193
|
-
|
|
33240
|
+
join68(this.snapshotDir, `${snapshotId}.json`),
|
|
32194
33241
|
JSON.stringify(snapshot, null, 2),
|
|
32195
33242
|
"utf-8"
|
|
32196
33243
|
);
|
|
@@ -32205,7 +33252,7 @@ var init_working_snapshots = __esm({
|
|
|
32205
33252
|
* Delete a snapshot.
|
|
32206
33253
|
*/
|
|
32207
33254
|
delete(snapshotId) {
|
|
32208
|
-
const filePath =
|
|
33255
|
+
const filePath = join68(this.snapshotDir, `${snapshotId}.json`);
|
|
32209
33256
|
if (!existsSync64(filePath)) return false;
|
|
32210
33257
|
rmSync2(filePath);
|
|
32211
33258
|
return true;
|
|
@@ -32214,10 +33261,10 @@ var init_working_snapshots = __esm({
|
|
|
32214
33261
|
* Get the timeline branch counter from branch_context.json.
|
|
32215
33262
|
*/
|
|
32216
33263
|
getTimelineBranch() {
|
|
32217
|
-
const contextPath =
|
|
33264
|
+
const contextPath = join68(this.unerrDir, "branch_context.json");
|
|
32218
33265
|
if (!existsSync64(contextPath)) return 0;
|
|
32219
33266
|
try {
|
|
32220
|
-
const ctx = JSON.parse(
|
|
33267
|
+
const ctx = JSON.parse(readFileSync56(contextPath, "utf-8"));
|
|
32221
33268
|
return ctx.timelineBranch ?? 0;
|
|
32222
33269
|
} catch {
|
|
32223
33270
|
return 0;
|
|
@@ -32227,11 +33274,11 @@ var init_working_snapshots = __esm({
|
|
|
32227
33274
|
* Increment the timeline branch counter. Returns the new value.
|
|
32228
33275
|
*/
|
|
32229
33276
|
incrementTimelineBranch() {
|
|
32230
|
-
const contextPath =
|
|
33277
|
+
const contextPath = join68(this.unerrDir, "branch_context.json");
|
|
32231
33278
|
let ctx = {};
|
|
32232
33279
|
if (existsSync64(contextPath)) {
|
|
32233
33280
|
try {
|
|
32234
|
-
ctx = JSON.parse(
|
|
33281
|
+
ctx = JSON.parse(readFileSync56(contextPath, "utf-8"));
|
|
32235
33282
|
} catch {
|
|
32236
33283
|
ctx = {};
|
|
32237
33284
|
}
|
|
@@ -32404,8 +33451,8 @@ var quality_signals_exports = {};
|
|
|
32404
33451
|
__export(quality_signals_exports, {
|
|
32405
33452
|
QualitySignalTracker: () => QualitySignalTracker
|
|
32406
33453
|
});
|
|
32407
|
-
import { existsSync as existsSync65, readFileSync as
|
|
32408
|
-
import { join as
|
|
33454
|
+
import { existsSync as existsSync65, readFileSync as readFileSync57, writeFileSync as writeFileSync31 } from "fs";
|
|
33455
|
+
import { join as join69 } from "path";
|
|
32409
33456
|
function computeDurabilityFromAge(survivalMs) {
|
|
32410
33457
|
if (survivalMs < FRAGILE_THRESHOLD_MS) {
|
|
32411
33458
|
return 0.1 + survivalMs / FRAGILE_THRESHOLD_MS * 0.2;
|
|
@@ -32432,7 +33479,7 @@ var init_quality_signals = __esm({
|
|
|
32432
33479
|
/** Maximum corrections to retain in memory/disk. */
|
|
32433
33480
|
static MAX_CORRECTIONS = 200;
|
|
32434
33481
|
constructor(unerrDir2) {
|
|
32435
|
-
this.signalsPath =
|
|
33482
|
+
this.signalsPath = join69(unerrDir2, "state", "quality_signals.json");
|
|
32436
33483
|
this.signals = this.load();
|
|
32437
33484
|
}
|
|
32438
33485
|
/**
|
|
@@ -32524,7 +33571,7 @@ var init_quality_signals = __esm({
|
|
|
32524
33571
|
*/
|
|
32525
33572
|
save() {
|
|
32526
33573
|
try {
|
|
32527
|
-
const dir =
|
|
33574
|
+
const dir = join69(this.signalsPath, "..");
|
|
32528
33575
|
if (!existsSync65(dir)) {
|
|
32529
33576
|
const { mkdirSync: mkdirSync48 } = __require("fs");
|
|
32530
33577
|
mkdirSync48(dir, { recursive: true });
|
|
@@ -32580,7 +33627,7 @@ var init_quality_signals = __esm({
|
|
|
32580
33627
|
}
|
|
32581
33628
|
try {
|
|
32582
33629
|
return JSON.parse(
|
|
32583
|
-
|
|
33630
|
+
readFileSync57(this.signalsPath, "utf-8")
|
|
32584
33631
|
);
|
|
32585
33632
|
} catch {
|
|
32586
33633
|
return {
|
|
@@ -33599,8 +34646,8 @@ var incomplete_work_exports = {};
|
|
|
33599
34646
|
__export(incomplete_work_exports, {
|
|
33600
34647
|
IncompleteWorkDetector: () => IncompleteWorkDetector
|
|
33601
34648
|
});
|
|
33602
|
-
import { existsSync as existsSync66, mkdirSync as mkdirSync37, readFileSync as
|
|
33603
|
-
import { join as
|
|
34649
|
+
import { existsSync as existsSync66, mkdirSync as mkdirSync37, readFileSync as readFileSync58, writeFileSync as writeFileSync32 } from "fs";
|
|
34650
|
+
import { join as join70 } from "path";
|
|
33604
34651
|
function severityRank(severity) {
|
|
33605
34652
|
switch (severity) {
|
|
33606
34653
|
case "high":
|
|
@@ -33793,9 +34840,9 @@ var init_incomplete_work = __esm({
|
|
|
33793
34840
|
persistItems(items) {
|
|
33794
34841
|
if (!this.unerrDir) return false;
|
|
33795
34842
|
try {
|
|
33796
|
-
const stateDir =
|
|
34843
|
+
const stateDir = join70(this.unerrDir, "state");
|
|
33797
34844
|
if (!existsSync66(stateDir)) mkdirSync37(stateDir, { recursive: true });
|
|
33798
|
-
const filePath =
|
|
34845
|
+
const filePath = join70(stateDir, PERSISTENCE_FILE);
|
|
33799
34846
|
writeFileSync32(
|
|
33800
34847
|
filePath,
|
|
33801
34848
|
JSON.stringify({
|
|
@@ -33815,9 +34862,9 @@ var init_incomplete_work = __esm({
|
|
|
33815
34862
|
*/
|
|
33816
34863
|
static readPersistedItems(unerrDir2) {
|
|
33817
34864
|
try {
|
|
33818
|
-
const filePath =
|
|
34865
|
+
const filePath = join70(unerrDir2, "state", PERSISTENCE_FILE);
|
|
33819
34866
|
if (!existsSync66(filePath)) return [];
|
|
33820
|
-
const data = JSON.parse(
|
|
34867
|
+
const data = JSON.parse(readFileSync58(filePath, "utf-8"));
|
|
33821
34868
|
return data.items ?? [];
|
|
33822
34869
|
} catch {
|
|
33823
34870
|
return [];
|
|
@@ -35597,8 +36644,8 @@ __export(git_trailers_exports, {
|
|
|
35597
36644
|
parseTrailersFromMessage: () => parseTrailersFromMessage,
|
|
35598
36645
|
uninstallPrepareCommitMsgHook: () => uninstallPrepareCommitMsgHook
|
|
35599
36646
|
});
|
|
35600
|
-
import { existsSync as existsSync68, readFileSync as
|
|
35601
|
-
import { join as
|
|
36647
|
+
import { existsSync as existsSync68, readFileSync as readFileSync59, writeFileSync as writeFileSync33 } from "fs";
|
|
36648
|
+
import { join as join71 } from "path";
|
|
35602
36649
|
function getCommitTrailers(ledger, timelineBranch, branch) {
|
|
35603
36650
|
const recent = ledger.getRecentEntries(1);
|
|
35604
36651
|
if (recent.length === 0) return null;
|
|
@@ -35618,15 +36665,15 @@ function formatTrailers(trailers) {
|
|
|
35618
36665
|
].join("\n");
|
|
35619
36666
|
}
|
|
35620
36667
|
function installPrepareCommitMsgHook(projectRoot) {
|
|
35621
|
-
const hooksDir =
|
|
36668
|
+
const hooksDir = join71(projectRoot, ".git", "hooks");
|
|
35622
36669
|
if (!existsSync68(hooksDir)) {
|
|
35623
36670
|
return false;
|
|
35624
36671
|
}
|
|
35625
|
-
const hookPath =
|
|
36672
|
+
const hookPath = join71(hooksDir, "prepare-commit-msg");
|
|
35626
36673
|
const marker = "# unerr-trailer-injection";
|
|
35627
36674
|
if (existsSync68(hookPath)) {
|
|
35628
36675
|
try {
|
|
35629
|
-
const existing =
|
|
36676
|
+
const existing = readFileSync59(hookPath, "utf-8");
|
|
35630
36677
|
if (existing.includes(marker)) {
|
|
35631
36678
|
return true;
|
|
35632
36679
|
}
|
|
@@ -35655,10 +36702,10 @@ ${generateHookScript()}`;
|
|
|
35655
36702
|
}
|
|
35656
36703
|
}
|
|
35657
36704
|
function uninstallPrepareCommitMsgHook(projectRoot) {
|
|
35658
|
-
const hookPath =
|
|
36705
|
+
const hookPath = join71(projectRoot, ".git", "hooks", "prepare-commit-msg");
|
|
35659
36706
|
if (!existsSync68(hookPath)) return true;
|
|
35660
36707
|
try {
|
|
35661
|
-
const content =
|
|
36708
|
+
const content = readFileSync59(hookPath, "utf-8");
|
|
35662
36709
|
const marker = "# unerr-trailer-injection";
|
|
35663
36710
|
if (!content.includes(marker)) return true;
|
|
35664
36711
|
const lines = content.split("\n");
|
|
@@ -35825,13 +36872,13 @@ var init_http_transport = __esm({
|
|
|
35825
36872
|
import {
|
|
35826
36873
|
existsSync as existsSync69,
|
|
35827
36874
|
mkdirSync as mkdirSync39,
|
|
35828
|
-
readFileSync as
|
|
35829
|
-
readdirSync as
|
|
36875
|
+
readFileSync as readFileSync60,
|
|
36876
|
+
readdirSync as readdirSync16,
|
|
35830
36877
|
rmSync as rmSync3,
|
|
35831
36878
|
statSync as statSync11,
|
|
35832
36879
|
writeFileSync as writeFileSync34
|
|
35833
36880
|
} from "fs";
|
|
35834
|
-
import { join as
|
|
36881
|
+
import { join as join72 } from "path";
|
|
35835
36882
|
function sanitizeBranchName(branch) {
|
|
35836
36883
|
return branch.replace(/\//g, "__").replace(/[^a-zA-Z0-9_.\-]/g, "_");
|
|
35837
36884
|
}
|
|
@@ -35849,7 +36896,7 @@ var init_branch_snapshot = __esm({
|
|
|
35849
36896
|
branchDir;
|
|
35850
36897
|
projectRoot;
|
|
35851
36898
|
constructor(unerrDir2, projectRoot) {
|
|
35852
|
-
this.branchDir =
|
|
36899
|
+
this.branchDir = join72(unerrDir2, "drift", "branches");
|
|
35853
36900
|
this.projectRoot = projectRoot;
|
|
35854
36901
|
}
|
|
35855
36902
|
/**
|
|
@@ -35863,7 +36910,7 @@ var init_branch_snapshot = __esm({
|
|
|
35863
36910
|
log17.info(`No drift entities/edges to snapshot for branch ${branch}`);
|
|
35864
36911
|
}
|
|
35865
36912
|
const dirName = sanitizeBranchName(branch);
|
|
35866
|
-
const snapshotDir =
|
|
36913
|
+
const snapshotDir = join72(this.branchDir, dirName);
|
|
35867
36914
|
if (!existsSync69(snapshotDir)) {
|
|
35868
36915
|
mkdirSync39(snapshotDir, { recursive: true });
|
|
35869
36916
|
}
|
|
@@ -35875,12 +36922,12 @@ var init_branch_snapshot = __esm({
|
|
|
35875
36922
|
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
35876
36923
|
};
|
|
35877
36924
|
writeFileSync34(
|
|
35878
|
-
|
|
36925
|
+
join72(snapshotDir, OVERLAY_FILE),
|
|
35879
36926
|
JSON.stringify(snapshot, null, 2),
|
|
35880
36927
|
"utf-8"
|
|
35881
36928
|
);
|
|
35882
36929
|
writeFileSync34(
|
|
35883
|
-
|
|
36930
|
+
join72(snapshotDir, HASHES_FILE),
|
|
35884
36931
|
JSON.stringify(fileHashState, null, 2),
|
|
35885
36932
|
"utf-8"
|
|
35886
36933
|
);
|
|
@@ -35896,14 +36943,14 @@ var init_branch_snapshot = __esm({
|
|
|
35896
36943
|
*/
|
|
35897
36944
|
async restoreSnapshot(branch, localGraph) {
|
|
35898
36945
|
const dirName = sanitizeBranchName(branch);
|
|
35899
|
-
const snapshotDir =
|
|
35900
|
-
const overlayPath =
|
|
36946
|
+
const snapshotDir = join72(this.branchDir, dirName);
|
|
36947
|
+
const overlayPath = join72(snapshotDir, OVERLAY_FILE);
|
|
35901
36948
|
if (!existsSync69(overlayPath)) {
|
|
35902
36949
|
log17.info(`No snapshot for branch ${branch} \u2014 first visit`);
|
|
35903
36950
|
return null;
|
|
35904
36951
|
}
|
|
35905
36952
|
try {
|
|
35906
|
-
const raw =
|
|
36953
|
+
const raw = readFileSync60(overlayPath, "utf-8");
|
|
35907
36954
|
const snapshot = JSON.parse(raw);
|
|
35908
36955
|
for (const entity of snapshot.entities) {
|
|
35909
36956
|
await localGraph.upsertDriftEntity(entity);
|
|
@@ -35915,7 +36962,7 @@ var init_branch_snapshot = __esm({
|
|
|
35915
36962
|
}
|
|
35916
36963
|
const now = /* @__PURE__ */ new Date();
|
|
35917
36964
|
writeFileSync34(
|
|
35918
|
-
|
|
36965
|
+
join72(snapshotDir, ".last_access"),
|
|
35919
36966
|
now.toISOString(),
|
|
35920
36967
|
"utf-8"
|
|
35921
36968
|
);
|
|
@@ -35935,17 +36982,17 @@ var init_branch_snapshot = __esm({
|
|
|
35935
36982
|
*/
|
|
35936
36983
|
hasSnapshot(branch) {
|
|
35937
36984
|
const dirName = sanitizeBranchName(branch);
|
|
35938
|
-
return existsSync69(
|
|
36985
|
+
return existsSync69(join72(this.branchDir, dirName, OVERLAY_FILE));
|
|
35939
36986
|
}
|
|
35940
36987
|
/**
|
|
35941
36988
|
* Get the file hash state from a branch snapshot.
|
|
35942
36989
|
*/
|
|
35943
36990
|
getSnapshotFileHashes(branch) {
|
|
35944
36991
|
const dirName = sanitizeBranchName(branch);
|
|
35945
|
-
const hashesPath =
|
|
36992
|
+
const hashesPath = join72(this.branchDir, dirName, HASHES_FILE);
|
|
35946
36993
|
if (!existsSync69(hashesPath)) return null;
|
|
35947
36994
|
try {
|
|
35948
|
-
const raw =
|
|
36995
|
+
const raw = readFileSync60(hashesPath, "utf-8");
|
|
35949
36996
|
return JSON.parse(raw);
|
|
35950
36997
|
} catch {
|
|
35951
36998
|
return null;
|
|
@@ -35956,7 +37003,7 @@ var init_branch_snapshot = __esm({
|
|
|
35956
37003
|
*/
|
|
35957
37004
|
deleteSnapshot(branch) {
|
|
35958
37005
|
const dirName = sanitizeBranchName(branch);
|
|
35959
|
-
const snapshotDir =
|
|
37006
|
+
const snapshotDir = join72(this.branchDir, dirName);
|
|
35960
37007
|
if (!existsSync69(snapshotDir)) return false;
|
|
35961
37008
|
rmSync3(snapshotDir, { recursive: true, force: true });
|
|
35962
37009
|
log17.info(`Deleted branch snapshot: ${branch}`);
|
|
@@ -35973,7 +37020,7 @@ var init_branch_snapshot = __esm({
|
|
|
35973
37020
|
let removed = 0;
|
|
35974
37021
|
for (const snapshot of snapshots) {
|
|
35975
37022
|
if (!gitBranches.has(snapshot.branch)) {
|
|
35976
|
-
const snapshotDir =
|
|
37023
|
+
const snapshotDir = join72(this.branchDir, snapshot.id);
|
|
35977
37024
|
rmSync3(snapshotDir, { recursive: true, force: true });
|
|
35978
37025
|
log17.info(`GC removed snapshot for deleted branch: ${snapshot.branch}`);
|
|
35979
37026
|
removed++;
|
|
@@ -35987,16 +37034,16 @@ var init_branch_snapshot = __esm({
|
|
|
35987
37034
|
listSnapshots() {
|
|
35988
37035
|
if (!existsSync69(this.branchDir)) return [];
|
|
35989
37036
|
try {
|
|
35990
|
-
const entries =
|
|
37037
|
+
const entries = readdirSync16(this.branchDir, { withFileTypes: true });
|
|
35991
37038
|
const snapshots = [];
|
|
35992
37039
|
for (const entry of entries) {
|
|
35993
37040
|
if (!entry.isDirectory()) continue;
|
|
35994
|
-
const overlayPath =
|
|
37041
|
+
const overlayPath = join72(this.branchDir, entry.name, OVERLAY_FILE);
|
|
35995
37042
|
if (!existsSync69(overlayPath)) continue;
|
|
35996
37043
|
try {
|
|
35997
|
-
const raw =
|
|
37044
|
+
const raw = readFileSync60(overlayPath, "utf-8");
|
|
35998
37045
|
const snapshot = JSON.parse(raw);
|
|
35999
|
-
const accessPath =
|
|
37046
|
+
const accessPath = join72(this.branchDir, entry.name, ".last_access");
|
|
36000
37047
|
let accessedAt;
|
|
36001
37048
|
if (existsSync69(accessPath)) {
|
|
36002
37049
|
accessedAt = statSync11(accessPath).mtime;
|
|
@@ -36025,7 +37072,7 @@ var init_branch_snapshot = __esm({
|
|
|
36025
37072
|
if (snapshots.length <= MAX_BRANCH_SNAPSHOTS) return;
|
|
36026
37073
|
const toRemove = snapshots.slice(MAX_BRANCH_SNAPSHOTS);
|
|
36027
37074
|
for (const snapshot of toRemove) {
|
|
36028
|
-
const dir =
|
|
37075
|
+
const dir = join72(this.branchDir, snapshot.id);
|
|
36029
37076
|
rmSync3(dir, { recursive: true, force: true });
|
|
36030
37077
|
log17.info(`LRU evicted branch snapshot: ${snapshot.branch}`);
|
|
36031
37078
|
}
|
|
@@ -36040,17 +37087,17 @@ __export(file_hash_state_exports, {
|
|
|
36040
37087
|
FileHashManager: () => FileHashManager,
|
|
36041
37088
|
contentSha256: () => contentSha256
|
|
36042
37089
|
});
|
|
36043
|
-
import { createHash as
|
|
37090
|
+
import { createHash as createHash4 } from "crypto";
|
|
36044
37091
|
import {
|
|
36045
37092
|
existsSync as existsSync70,
|
|
36046
37093
|
mkdirSync as mkdirSync40,
|
|
36047
|
-
readFileSync as
|
|
37094
|
+
readFileSync as readFileSync61,
|
|
36048
37095
|
renameSync as renameSync4,
|
|
36049
37096
|
writeFileSync as writeFileSync35
|
|
36050
37097
|
} from "fs";
|
|
36051
|
-
import { join as
|
|
37098
|
+
import { join as join73 } from "path";
|
|
36052
37099
|
function contentSha256(content) {
|
|
36053
|
-
return
|
|
37100
|
+
return createHash4("sha256").update(content).digest("hex");
|
|
36054
37101
|
}
|
|
36055
37102
|
var STATE_FILE2, FileHashManager;
|
|
36056
37103
|
var init_file_hash_state = __esm({
|
|
@@ -36062,8 +37109,8 @@ var init_file_hash_state = __esm({
|
|
|
36062
37109
|
statePath;
|
|
36063
37110
|
state;
|
|
36064
37111
|
constructor(unerrDir2) {
|
|
36065
|
-
this.stateDir =
|
|
36066
|
-
this.statePath =
|
|
37112
|
+
this.stateDir = join73(unerrDir2, "state");
|
|
37113
|
+
this.statePath = join73(this.stateDir, STATE_FILE2);
|
|
36067
37114
|
this.state = this.load();
|
|
36068
37115
|
}
|
|
36069
37116
|
/**
|
|
@@ -36139,7 +37186,7 @@ var init_file_hash_state = __esm({
|
|
|
36139
37186
|
return { files: {} };
|
|
36140
37187
|
}
|
|
36141
37188
|
try {
|
|
36142
|
-
const raw =
|
|
37189
|
+
const raw = readFileSync61(this.statePath, "utf-8");
|
|
36143
37190
|
return JSON.parse(raw);
|
|
36144
37191
|
} catch {
|
|
36145
37192
|
return { files: {} };
|
|
@@ -36153,13 +37200,13 @@ var init_file_hash_state = __esm({
|
|
|
36153
37200
|
import {
|
|
36154
37201
|
existsSync as existsSync71,
|
|
36155
37202
|
mkdirSync as mkdirSync41,
|
|
36156
|
-
readFileSync as
|
|
36157
|
-
readdirSync as
|
|
37203
|
+
readFileSync as readFileSync62,
|
|
37204
|
+
readdirSync as readdirSync17,
|
|
36158
37205
|
rmSync as rmSync4,
|
|
36159
37206
|
statSync as statSync12,
|
|
36160
37207
|
writeFileSync as writeFileSync36
|
|
36161
37208
|
} from "fs";
|
|
36162
|
-
import { join as
|
|
37209
|
+
import { join as join74 } from "path";
|
|
36163
37210
|
var MAX_STASH_SNAPSHOTS, OVERLAY_FILE2, HASHES_FILE2, _log6, StashManager;
|
|
36164
37211
|
var init_stash_manager = __esm({
|
|
36165
37212
|
"src/tracking/stash-manager.ts"() {
|
|
@@ -36177,8 +37224,8 @@ var init_stash_manager = __esm({
|
|
|
36177
37224
|
constructor(unerrDir2, projectRoot) {
|
|
36178
37225
|
this.unerrDir = unerrDir2;
|
|
36179
37226
|
this.projectRoot = projectRoot;
|
|
36180
|
-
this.stashDir =
|
|
36181
|
-
this.gitDir =
|
|
37227
|
+
this.stashDir = join74(unerrDir2, "drift", "stash");
|
|
37228
|
+
this.gitDir = join74(projectRoot, ".git");
|
|
36182
37229
|
this.previousStashRef = this.readStashRef();
|
|
36183
37230
|
this.previousStashCount = this.getStashCount();
|
|
36184
37231
|
}
|
|
@@ -36223,7 +37270,7 @@ var init_stash_manager = __esm({
|
|
|
36223
37270
|
return null;
|
|
36224
37271
|
}
|
|
36225
37272
|
const snapshotId = stashRef.slice(0, 12);
|
|
36226
|
-
const snapshotDir =
|
|
37273
|
+
const snapshotDir = join74(this.stashDir, snapshotId);
|
|
36227
37274
|
if (!existsSync71(snapshotDir)) {
|
|
36228
37275
|
mkdirSync41(snapshotDir, { recursive: true });
|
|
36229
37276
|
}
|
|
@@ -36235,12 +37282,12 @@ var init_stash_manager = __esm({
|
|
|
36235
37282
|
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
36236
37283
|
};
|
|
36237
37284
|
writeFileSync36(
|
|
36238
|
-
|
|
37285
|
+
join74(snapshotDir, OVERLAY_FILE2),
|
|
36239
37286
|
JSON.stringify(snapshot, null, 2),
|
|
36240
37287
|
"utf-8"
|
|
36241
37288
|
);
|
|
36242
37289
|
writeFileSync36(
|
|
36243
|
-
|
|
37290
|
+
join74(snapshotDir, HASHES_FILE2),
|
|
36244
37291
|
JSON.stringify(fileHashState, null, 2),
|
|
36245
37292
|
"utf-8"
|
|
36246
37293
|
);
|
|
@@ -36261,14 +37308,14 @@ var init_stash_manager = __esm({
|
|
|
36261
37308
|
return 0;
|
|
36262
37309
|
}
|
|
36263
37310
|
const latest = snapshots[0];
|
|
36264
|
-
const snapshotDir =
|
|
36265
|
-
const overlayPath =
|
|
37311
|
+
const snapshotDir = join74(this.stashDir, latest.id);
|
|
37312
|
+
const overlayPath = join74(snapshotDir, OVERLAY_FILE2);
|
|
36266
37313
|
if (!existsSync71(overlayPath)) {
|
|
36267
37314
|
_log6.warn(`Snapshot ${latest.id} missing overlay file`);
|
|
36268
37315
|
return 0;
|
|
36269
37316
|
}
|
|
36270
37317
|
try {
|
|
36271
|
-
const raw =
|
|
37318
|
+
const raw = readFileSync62(overlayPath, "utf-8");
|
|
36272
37319
|
const snapshot = JSON.parse(raw);
|
|
36273
37320
|
for (const entity of snapshot.entities) {
|
|
36274
37321
|
await localGraph.upsertDriftEntity(entity);
|
|
@@ -36298,10 +37345,10 @@ var init_stash_manager = __esm({
|
|
|
36298
37345
|
const snapshots = this.listSnapshots();
|
|
36299
37346
|
if (snapshots.length === 0) return null;
|
|
36300
37347
|
const latest = snapshots[0];
|
|
36301
|
-
const hashesPath =
|
|
37348
|
+
const hashesPath = join74(this.stashDir, latest.id, HASHES_FILE2);
|
|
36302
37349
|
if (!existsSync71(hashesPath)) return null;
|
|
36303
37350
|
try {
|
|
36304
|
-
const raw =
|
|
37351
|
+
const raw = readFileSync62(hashesPath, "utf-8");
|
|
36305
37352
|
return JSON.parse(raw);
|
|
36306
37353
|
} catch {
|
|
36307
37354
|
return null;
|
|
@@ -36312,7 +37359,7 @@ var init_stash_manager = __esm({
|
|
|
36312
37359
|
*/
|
|
36313
37360
|
dropSnapshot(stashRef) {
|
|
36314
37361
|
const snapshotId = stashRef.slice(0, 12);
|
|
36315
|
-
const snapshotDir =
|
|
37362
|
+
const snapshotDir = join74(this.stashDir, snapshotId);
|
|
36316
37363
|
if (!existsSync71(snapshotDir)) return false;
|
|
36317
37364
|
rmSync4(snapshotDir, { recursive: true, force: true });
|
|
36318
37365
|
_log6.info(`Dropped stash snapshot: ${snapshotId}`);
|
|
@@ -36324,11 +37371,11 @@ var init_stash_manager = __esm({
|
|
|
36324
37371
|
listSnapshots() {
|
|
36325
37372
|
if (!existsSync71(this.stashDir)) return [];
|
|
36326
37373
|
try {
|
|
36327
|
-
const entries =
|
|
37374
|
+
const entries = readdirSync17(this.stashDir, { withFileTypes: true });
|
|
36328
37375
|
const snapshots = [];
|
|
36329
37376
|
for (const entry of entries) {
|
|
36330
37377
|
if (!entry.isDirectory()) continue;
|
|
36331
|
-
const overlayPath =
|
|
37378
|
+
const overlayPath = join74(this.stashDir, entry.name, OVERLAY_FILE2);
|
|
36332
37379
|
if (!existsSync71(overlayPath)) continue;
|
|
36333
37380
|
try {
|
|
36334
37381
|
const stat2 = statSync12(overlayPath);
|
|
@@ -36346,10 +37393,10 @@ var init_stash_manager = __esm({
|
|
|
36346
37393
|
* Read the current stash ref SHA from `.git/refs/stash`.
|
|
36347
37394
|
*/
|
|
36348
37395
|
readStashRef() {
|
|
36349
|
-
const stashPath =
|
|
37396
|
+
const stashPath = join74(this.gitDir, "refs", "stash");
|
|
36350
37397
|
if (!existsSync71(stashPath)) return null;
|
|
36351
37398
|
try {
|
|
36352
|
-
return
|
|
37399
|
+
return readFileSync62(stashPath, "utf-8").trim() || null;
|
|
36353
37400
|
} catch {
|
|
36354
37401
|
return null;
|
|
36355
37402
|
}
|
|
@@ -36358,10 +37405,10 @@ var init_stash_manager = __esm({
|
|
|
36358
37405
|
* Count current stash entries via `.git/logs/refs/stash`.
|
|
36359
37406
|
*/
|
|
36360
37407
|
getStashCount() {
|
|
36361
|
-
const logPath =
|
|
37408
|
+
const logPath = join74(this.gitDir, "logs", "refs", "stash");
|
|
36362
37409
|
if (!existsSync71(logPath)) return 0;
|
|
36363
37410
|
try {
|
|
36364
|
-
const content =
|
|
37411
|
+
const content = readFileSync62(logPath, "utf-8");
|
|
36365
37412
|
return content.split("\n").filter((line) => line.trim().length > 0).length;
|
|
36366
37413
|
} catch {
|
|
36367
37414
|
return 0;
|
|
@@ -36375,7 +37422,7 @@ var init_stash_manager = __esm({
|
|
|
36375
37422
|
if (snapshots.length <= MAX_STASH_SNAPSHOTS) return;
|
|
36376
37423
|
const toRemove = snapshots.slice(MAX_STASH_SNAPSHOTS);
|
|
36377
37424
|
for (const snapshot of toRemove) {
|
|
36378
|
-
const dir =
|
|
37425
|
+
const dir = join74(this.stashDir, snapshot.id);
|
|
36379
37426
|
rmSync4(dir, { recursive: true, force: true });
|
|
36380
37427
|
_log6.info(`LRU evicted stash snapshot: ${snapshot.id}`);
|
|
36381
37428
|
}
|
|
@@ -36395,11 +37442,11 @@ __export(drift_tracker_exports, {
|
|
|
36395
37442
|
import {
|
|
36396
37443
|
existsSync as existsSync72,
|
|
36397
37444
|
mkdirSync as mkdirSync42,
|
|
36398
|
-
readFileSync as
|
|
37445
|
+
readFileSync as readFileSync63,
|
|
36399
37446
|
statSync as statSync13,
|
|
36400
37447
|
writeFileSync as writeFileSync37
|
|
36401
37448
|
} from "fs";
|
|
36402
|
-
import { join as
|
|
37449
|
+
import { join as join75 } from "path";
|
|
36403
37450
|
function determineOrigin(lastSyncTimestamp) {
|
|
36404
37451
|
if (lastSyncTimestamp === 0) return "human";
|
|
36405
37452
|
const elapsed = Date.now() - lastSyncTimestamp;
|
|
@@ -36610,7 +37657,7 @@ var init_drift_tracker = __esm({
|
|
|
36610
37657
|
crossFileInvalidated: 0,
|
|
36611
37658
|
edgesExtracted: 0
|
|
36612
37659
|
};
|
|
36613
|
-
const absPath = filePath.startsWith("/") ? filePath :
|
|
37660
|
+
const absPath = filePath.startsWith("/") ? filePath : join75(this.config.projectRoot, filePath);
|
|
36614
37661
|
const relPath = filePath.startsWith("/") ? filePath.slice(this.config.projectRoot.length + 1) : filePath;
|
|
36615
37662
|
const language = detectLanguage2(relPath);
|
|
36616
37663
|
if (!language) return result;
|
|
@@ -36656,7 +37703,7 @@ var init_drift_tracker = __esm({
|
|
|
36656
37703
|
this.maybeEmitDrift(relPath, result);
|
|
36657
37704
|
return result;
|
|
36658
37705
|
}
|
|
36659
|
-
const content =
|
|
37706
|
+
const content = readFileSync63(absPath, "utf-8");
|
|
36660
37707
|
const sha = contentSha256(content);
|
|
36661
37708
|
const decision = this.fileHashManager.shouldProcess(relPath, sha, headSha);
|
|
36662
37709
|
if (decision === "skip") {
|
|
@@ -36890,7 +37937,7 @@ var init_drift_tracker = __esm({
|
|
|
36890
37937
|
return await this.stashManager.restoreSnapshot(this.localGraph);
|
|
36891
37938
|
}
|
|
36892
37939
|
async markFileDeleted(filePath, intentId) {
|
|
36893
|
-
const absPath = filePath.startsWith("/") ? filePath :
|
|
37940
|
+
const absPath = filePath.startsWith("/") ? filePath : join75(this.config.projectRoot, filePath);
|
|
36894
37941
|
this.mtimeCache.evict(absPath);
|
|
36895
37942
|
const baseEntities = await this.localGraph.getEntitiesByFile(filePath);
|
|
36896
37943
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -36975,13 +38022,13 @@ var init_drift_tracker = __esm({
|
|
|
36975
38022
|
return invalidated;
|
|
36976
38023
|
}
|
|
36977
38024
|
async saveDriftSummary() {
|
|
36978
|
-
const driftDir =
|
|
38025
|
+
const driftDir = join75(this.config.unerrDir, "drift");
|
|
36979
38026
|
if (!existsSync72(driftDir)) {
|
|
36980
38027
|
mkdirSync42(driftDir, { recursive: true });
|
|
36981
38028
|
}
|
|
36982
38029
|
const summary = await this.getDriftSummary();
|
|
36983
38030
|
writeFileSync37(
|
|
36984
|
-
|
|
38031
|
+
join75(driftDir, "drift_summary.json"),
|
|
36985
38032
|
JSON.stringify(summary, null, 2),
|
|
36986
38033
|
"utf-8"
|
|
36987
38034
|
);
|
|
@@ -37392,8 +38439,8 @@ var incremental_indexer_exports = {};
|
|
|
37392
38439
|
__export(incremental_indexer_exports, {
|
|
37393
38440
|
indexFilesIncremental: () => indexFilesIncremental
|
|
37394
38441
|
});
|
|
37395
|
-
import { existsSync as existsSync73, readFileSync as
|
|
37396
|
-
import { join as
|
|
38442
|
+
import { existsSync as existsSync73, readFileSync as readFileSync64 } from "fs";
|
|
38443
|
+
import { join as join76, relative as relative5 } from "path";
|
|
37397
38444
|
async function indexFilesIncremental(projectRoot, changedFiles, graphStore, repoId) {
|
|
37398
38445
|
const startMs = Date.now();
|
|
37399
38446
|
const db = {
|
|
@@ -37411,7 +38458,7 @@ async function indexFilesIncremental(projectRoot, changedFiles, graphStore, repo
|
|
|
37411
38458
|
const changedEntityKeys = /* @__PURE__ */ new Set();
|
|
37412
38459
|
const deletedEntityKeys = /* @__PURE__ */ new Set();
|
|
37413
38460
|
for (const filePath of changedFiles) {
|
|
37414
|
-
const absPath = filePath.startsWith("/") ? filePath :
|
|
38461
|
+
const absPath = filePath.startsWith("/") ? filePath : join76(projectRoot, filePath);
|
|
37415
38462
|
const relPath = filePath.startsWith("/") ? relative5(projectRoot, filePath) : filePath;
|
|
37416
38463
|
if (!existsSync73(absPath)) {
|
|
37417
38464
|
const deleted2 = await deleteFileFromGraph(db, relPath);
|
|
@@ -37426,7 +38473,7 @@ async function indexFilesIncremental(projectRoot, changedFiles, graphStore, repo
|
|
|
37426
38473
|
}
|
|
37427
38474
|
let content;
|
|
37428
38475
|
try {
|
|
37429
|
-
content =
|
|
38476
|
+
content = readFileSync64(absPath, "utf-8");
|
|
37430
38477
|
} catch {
|
|
37431
38478
|
continue;
|
|
37432
38479
|
}
|
|
@@ -38604,8 +39651,8 @@ var workspace_manifest_exports = {};
|
|
|
38604
39651
|
__export(workspace_manifest_exports, {
|
|
38605
39652
|
WorkspaceManifest: () => WorkspaceManifest
|
|
38606
39653
|
});
|
|
38607
|
-
import { existsSync as existsSync74, mkdirSync as mkdirSync43, readFileSync as
|
|
38608
|
-
import { join as
|
|
39654
|
+
import { existsSync as existsSync74, mkdirSync as mkdirSync43, readFileSync as readFileSync65, writeFileSync as writeFileSync38 } from "fs";
|
|
39655
|
+
import { join as join77 } from "path";
|
|
38609
39656
|
var WorkspaceManifest;
|
|
38610
39657
|
var init_workspace_manifest = __esm({
|
|
38611
39658
|
"src/tracking/workspace-manifest.ts"() {
|
|
@@ -38615,7 +39662,7 @@ var init_workspace_manifest = __esm({
|
|
|
38615
39662
|
this.unerrDir = unerrDir2;
|
|
38616
39663
|
this.repoId = repoId;
|
|
38617
39664
|
this.sessionId = sessionId;
|
|
38618
|
-
this.manifestPath =
|
|
39665
|
+
this.manifestPath = join77(unerrDir2, "manifest.json");
|
|
38619
39666
|
this.data = this.load();
|
|
38620
39667
|
}
|
|
38621
39668
|
unerrDir;
|
|
@@ -38720,7 +39767,7 @@ var init_workspace_manifest = __esm({
|
|
|
38720
39767
|
};
|
|
38721
39768
|
}
|
|
38722
39769
|
try {
|
|
38723
|
-
const raw =
|
|
39770
|
+
const raw = readFileSync65(this.manifestPath, "utf-8");
|
|
38724
39771
|
const parsed = JSON.parse(raw);
|
|
38725
39772
|
if (parsed.repoId !== this.repoId) {
|
|
38726
39773
|
return {
|
|
@@ -38945,7 +39992,7 @@ import {
|
|
|
38945
39992
|
statSync as statSync14,
|
|
38946
39993
|
watch
|
|
38947
39994
|
} from "fs";
|
|
38948
|
-
import { join as
|
|
39995
|
+
import { join as join78 } from "path";
|
|
38949
39996
|
function formatSize(bytes) {
|
|
38950
39997
|
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
38951
39998
|
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
@@ -39092,9 +40139,9 @@ function tokenFlowRowToEntry(r) {
|
|
|
39092
40139
|
};
|
|
39093
40140
|
}
|
|
39094
40141
|
function startLogTailer(cwd, options) {
|
|
39095
|
-
const unerrDir2 =
|
|
39096
|
-
const logsDir =
|
|
39097
|
-
const generalPath =
|
|
40142
|
+
const unerrDir2 = join78(cwd, ".unerr");
|
|
40143
|
+
const logsDir = join78(unerrDir2, "logs");
|
|
40144
|
+
const generalPath = join78(logsDir, "events.jsonl");
|
|
39098
40145
|
const pollIntervalMs = options?.pollIntervalMs ?? 500;
|
|
39099
40146
|
const generalState = {
|
|
39100
40147
|
path: generalPath,
|
|
@@ -39240,13 +40287,13 @@ var init_middleware = __esm({
|
|
|
39240
40287
|
});
|
|
39241
40288
|
|
|
39242
40289
|
// src/server/routes/drift.ts
|
|
39243
|
-
import { existsSync as existsSync76, readFileSync as
|
|
39244
|
-
import { join as
|
|
40290
|
+
import { existsSync as existsSync76, readFileSync as readFileSync66, readdirSync as readdirSync18 } from "fs";
|
|
40291
|
+
import { join as join79 } from "path";
|
|
39245
40292
|
import { Hono as Hono2 } from "hono";
|
|
39246
40293
|
function readFlags(path7) {
|
|
39247
40294
|
try {
|
|
39248
40295
|
if (!existsSync76(path7)) return null;
|
|
39249
|
-
return JSON.parse(
|
|
40296
|
+
return JSON.parse(readFileSync66(path7, "utf8"));
|
|
39250
40297
|
} catch {
|
|
39251
40298
|
return null;
|
|
39252
40299
|
}
|
|
@@ -39254,7 +40301,7 @@ function readFlags(path7) {
|
|
|
39254
40301
|
function listSessionFiles(stateDir) {
|
|
39255
40302
|
try {
|
|
39256
40303
|
if (!existsSync76(stateDir)) return [];
|
|
39257
|
-
return
|
|
40304
|
+
return readdirSync18(stateDir).filter((f) => f.startsWith("nudge-") && f.endsWith(".flags")).map((f) => join79(stateDir, f));
|
|
39258
40305
|
} catch {
|
|
39259
40306
|
return [];
|
|
39260
40307
|
}
|
|
@@ -39274,7 +40321,7 @@ function rowFor(file) {
|
|
|
39274
40321
|
}
|
|
39275
40322
|
function createDriftRoutes(deps) {
|
|
39276
40323
|
const app = new Hono2();
|
|
39277
|
-
const stateDir =
|
|
40324
|
+
const stateDir = join79(deps.cwd, ".unerr", "state");
|
|
39278
40325
|
app.get("/sessions", (c) => {
|
|
39279
40326
|
const rows = [];
|
|
39280
40327
|
for (const file of listSessionFiles(stateDir)) {
|
|
@@ -39295,7 +40342,7 @@ function createDriftRoutes(deps) {
|
|
|
39295
40342
|
});
|
|
39296
40343
|
app.get("/current", (c) => {
|
|
39297
40344
|
const id = process.env.UNERR_SESSION_ID ?? `pid-${process.pid}`;
|
|
39298
|
-
const file =
|
|
40345
|
+
const file = join79(stateDir, `nudge-${id}.flags`);
|
|
39299
40346
|
const row = rowFor(file);
|
|
39300
40347
|
return c.json({
|
|
39301
40348
|
data: row ?? {
|
|
@@ -41458,13 +42505,13 @@ function createSystemRoutes(deps) {
|
|
|
41458
42505
|
});
|
|
41459
42506
|
app.get("/config", async (c) => {
|
|
41460
42507
|
const start = performance.now();
|
|
41461
|
-
const { existsSync: existsSync82, readFileSync:
|
|
41462
|
-
const { join:
|
|
42508
|
+
const { existsSync: existsSync82, readFileSync: readFileSync71 } = await import("fs");
|
|
42509
|
+
const { join: join85 } = await import("path");
|
|
41463
42510
|
let config = {};
|
|
41464
|
-
const configPath2 =
|
|
42511
|
+
const configPath2 = join85(deps.cwd, ".unerr", "config.json");
|
|
41465
42512
|
if (existsSync82(configPath2)) {
|
|
41466
42513
|
try {
|
|
41467
|
-
config = JSON.parse(
|
|
42514
|
+
config = JSON.parse(readFileSync71(configPath2, "utf-8"));
|
|
41468
42515
|
} catch {
|
|
41469
42516
|
config = { error: "unreadable" };
|
|
41470
42517
|
}
|
|
@@ -42757,10 +43804,10 @@ var http_exports = {};
|
|
|
42757
43804
|
__export(http_exports, {
|
|
42758
43805
|
startDashboardServer: () => startDashboardServer
|
|
42759
43806
|
});
|
|
42760
|
-
import { existsSync as existsSync77, readFileSync as
|
|
43807
|
+
import { existsSync as existsSync77, readFileSync as readFileSync67, unlinkSync as unlinkSync14, writeFileSync as writeFileSync39 } from "fs";
|
|
42761
43808
|
import { createServer as createServer5 } from "net";
|
|
42762
|
-
import { dirname as dirname17, join as
|
|
42763
|
-
import { fileURLToPath as
|
|
43809
|
+
import { dirname as dirname17, join as join80 } from "path";
|
|
43810
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
42764
43811
|
import { serve as serve2 } from "@hono/node-server";
|
|
42765
43812
|
import { serveStatic as serveStatic2 } from "@hono/node-server/serve-static";
|
|
42766
43813
|
import { Hono as Hono13 } from "hono";
|
|
@@ -42819,10 +43866,10 @@ async function startDashboardServer(opts) {
|
|
|
42819
43866
|
app.route("/api/router", createRouterApiV2(opts.routerV2));
|
|
42820
43867
|
}
|
|
42821
43868
|
if (!opts.apiOnly) {
|
|
42822
|
-
const distDir =
|
|
42823
|
-
const spaIndex =
|
|
43869
|
+
const distDir = join80(dirname17(fileURLToPath4(import.meta.url)), "ui");
|
|
43870
|
+
const spaIndex = join80(distDir, "index.html");
|
|
42824
43871
|
if (existsSync77(spaIndex)) {
|
|
42825
|
-
const spaHtml =
|
|
43872
|
+
const spaHtml = readFileSync67(spaIndex, "utf-8");
|
|
42826
43873
|
app.use("*", serveStatic2({ root: distDir }));
|
|
42827
43874
|
app.get("*", (c) => {
|
|
42828
43875
|
const path7 = c.req.path;
|
|
@@ -42854,7 +43901,7 @@ async function startDashboardServer(opts) {
|
|
|
42854
43901
|
port,
|
|
42855
43902
|
hostname: "127.0.0.1"
|
|
42856
43903
|
});
|
|
42857
|
-
const serverJsonPath =
|
|
43904
|
+
const serverJsonPath = join80(opts.stateDir, "server.json");
|
|
42858
43905
|
const serverInfo = {
|
|
42859
43906
|
port,
|
|
42860
43907
|
pid: process.pid,
|
|
@@ -43284,15 +44331,15 @@ import {
|
|
|
43284
44331
|
existsSync as existsSync78,
|
|
43285
44332
|
writeFileSync as fsWriteFileSync,
|
|
43286
44333
|
mkdirSync as mkdirSync44,
|
|
43287
|
-
readFileSync as
|
|
43288
|
-
readdirSync as
|
|
44334
|
+
readFileSync as readFileSync68,
|
|
44335
|
+
readdirSync as readdirSync19
|
|
43289
44336
|
} from "fs";
|
|
43290
|
-
import { join as
|
|
44337
|
+
import { join as join81 } from "path";
|
|
43291
44338
|
async function getProxyFactStore(unerrDir2) {
|
|
43292
44339
|
if (proxyFactStore !== void 0) return proxyFactStore;
|
|
43293
44340
|
try {
|
|
43294
44341
|
const { TemporalFactStore: TemporalFactStore2 } = await Promise.resolve().then(() => (init_temporal_facts(), temporal_facts_exports));
|
|
43295
|
-
const cwd =
|
|
44342
|
+
const cwd = join81(unerrDir2, "..");
|
|
43296
44343
|
proxyFactStore = await TemporalFactStore2.create(cwd);
|
|
43297
44344
|
return proxyFactStore;
|
|
43298
44345
|
} catch {
|
|
@@ -43436,9 +44483,9 @@ async function handleRecallFactsProxy(args, unerrDir2, effectiveness) {
|
|
|
43436
44483
|
}
|
|
43437
44484
|
function migrateAgentPermissions(cwd) {
|
|
43438
44485
|
try {
|
|
43439
|
-
const settingsPath =
|
|
44486
|
+
const settingsPath = join81(cwd, ".claude", "settings.json");
|
|
43440
44487
|
if (!existsSync78(settingsPath)) return;
|
|
43441
|
-
const raw =
|
|
44488
|
+
const raw = readFileSync68(settingsPath, "utf-8");
|
|
43442
44489
|
const settings = JSON.parse(raw);
|
|
43443
44490
|
const deny = settings?.permissions?.deny;
|
|
43444
44491
|
if (!Array.isArray(deny)) return;
|
|
@@ -43455,7 +44502,7 @@ function migrateAgentPermissions(cwd) {
|
|
|
43455
44502
|
}
|
|
43456
44503
|
async function startProxy(opts = {}) {
|
|
43457
44504
|
installFileLogger({
|
|
43458
|
-
filePath:
|
|
44505
|
+
filePath: join81(process.cwd(), ".unerr", "logs", "unerr.log"),
|
|
43459
44506
|
maxBytes: 5e6,
|
|
43460
44507
|
keep: 5
|
|
43461
44508
|
});
|
|
@@ -43468,7 +44515,7 @@ async function startProxy(opts = {}) {
|
|
|
43468
44515
|
const lifecycle = createLifecycleActor(process.cwd());
|
|
43469
44516
|
lifecycle.send({ type: "START_DETECT" });
|
|
43470
44517
|
startup.setLocalMode(true);
|
|
43471
|
-
const stateDir =
|
|
44518
|
+
const stateDir = join81(process.cwd(), ".unerr", "state");
|
|
43472
44519
|
if (!existsSync78(stateDir)) {
|
|
43473
44520
|
mkdirSync44(stateDir, { recursive: true });
|
|
43474
44521
|
}
|
|
@@ -43487,7 +44534,7 @@ async function startProxy(opts = {}) {
|
|
|
43487
44534
|
startupLog.step(
|
|
43488
44535
|
`PID ${process.pid} ${startupLog.fmt.muted(`\xB7 health localhost:${lockResult.healthPort}`)}`
|
|
43489
44536
|
);
|
|
43490
|
-
const ledgerDir =
|
|
44537
|
+
const ledgerDir = join81(process.cwd(), ".unerr", "ledger");
|
|
43491
44538
|
const previousSession = detectSessionResume(stateDir, ledgerDir);
|
|
43492
44539
|
if (previousSession) {
|
|
43493
44540
|
stats.isResumedSession = true;
|
|
@@ -43502,21 +44549,21 @@ async function startProxy(opts = {}) {
|
|
|
43502
44549
|
if (opts.repoId) {
|
|
43503
44550
|
repoIds = [opts.repoId];
|
|
43504
44551
|
} else {
|
|
43505
|
-
const configPath2 =
|
|
44552
|
+
const configPath2 = join81(process.cwd(), ".unerr", "config.json");
|
|
43506
44553
|
if (existsSync78(configPath2)) {
|
|
43507
44554
|
try {
|
|
43508
|
-
const config = JSON.parse(
|
|
44555
|
+
const config = JSON.parse(readFileSync68(configPath2, "utf-8"));
|
|
43509
44556
|
if (config.repoId) repoIds = [config.repoId];
|
|
43510
44557
|
} catch {
|
|
43511
44558
|
}
|
|
43512
44559
|
}
|
|
43513
|
-
const manifestsDir =
|
|
44560
|
+
const manifestsDir = join81(process.cwd(), ".unerr", "manifests");
|
|
43514
44561
|
if (repoIds.length === 0 && existsSync78(manifestsDir)) {
|
|
43515
|
-
repoIds =
|
|
44562
|
+
repoIds = readdirSync19(manifestsDir).filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
|
|
43516
44563
|
}
|
|
43517
44564
|
}
|
|
43518
44565
|
if (repoIds.length === 0) {
|
|
43519
|
-
const { createHash:
|
|
44566
|
+
const { createHash: createHash6 } = await import("crypto");
|
|
43520
44567
|
let repoIdentifier = process.cwd();
|
|
43521
44568
|
try {
|
|
43522
44569
|
const { getRemoteUrl: getRemoteUrl2 } = await Promise.resolve().then(() => (init_git(), git_exports));
|
|
@@ -43524,7 +44571,7 @@ async function startProxy(opts = {}) {
|
|
|
43524
44571
|
if (remote) repoIdentifier = remote;
|
|
43525
44572
|
} catch {
|
|
43526
44573
|
}
|
|
43527
|
-
const localRepoId =
|
|
44574
|
+
const localRepoId = createHash6("sha256").update(repoIdentifier).digest("hex").slice(0, 12);
|
|
43528
44575
|
repoIds = [localRepoId];
|
|
43529
44576
|
startupLog.done(
|
|
43530
44577
|
`Repository ${startupLog.fmt.cyan(localRepoId)} ${startupLog.fmt.muted(`(from ${repoIdentifier === process.cwd() ? "directory" : "git remote"})`)}`
|
|
@@ -43636,7 +44683,7 @@ async function startProxy(opts = {}) {
|
|
|
43636
44683
|
`Migrated snapshot to persistent graph ${startupLog.fmt.muted(`\u2192 ${dbPath}`)}`
|
|
43637
44684
|
);
|
|
43638
44685
|
try {
|
|
43639
|
-
const migrationUnerrDir =
|
|
44686
|
+
const migrationUnerrDir = join81(process.cwd(), ".unerr");
|
|
43640
44687
|
const factStoreForMigration = await getProxyFactStore(migrationUnerrDir);
|
|
43641
44688
|
if (factStoreForMigration) {
|
|
43642
44689
|
const { detectLocalConventions: detectLocalConventions2 } = await Promise.resolve().then(() => (init_local_convention_detector(), local_convention_detector_exports));
|
|
@@ -43735,7 +44782,7 @@ async function startProxy(opts = {}) {
|
|
|
43735
44782
|
let efficiencyTracker = createEfficiencyTracker2();
|
|
43736
44783
|
router.setTokenCounter(tokenCounter);
|
|
43737
44784
|
router.setEfficiencyTracker(efficiencyTracker);
|
|
43738
|
-
const proxyFactStore2 = await getProxyFactStore(
|
|
44785
|
+
const proxyFactStore2 = await getProxyFactStore(join81(process.cwd(), ".unerr"));
|
|
43739
44786
|
if (proxyFactStore2) {
|
|
43740
44787
|
router.setFactStore(proxyFactStore2);
|
|
43741
44788
|
}
|
|
@@ -43743,7 +44790,7 @@ async function startProxy(opts = {}) {
|
|
|
43743
44790
|
try {
|
|
43744
44791
|
const { generateSessionResume: generateSessionResume2 } = await Promise.resolve().then(() => (init_session_resume(), session_resume_exports));
|
|
43745
44792
|
const { ShadowLedger: ResumeLedger } = await Promise.resolve().then(() => (init_shadow_ledger(), shadow_ledger_exports));
|
|
43746
|
-
const resumeLedger = new ResumeLedger(
|
|
44793
|
+
const resumeLedger = new ResumeLedger(join81(process.cwd(), ".unerr"));
|
|
43747
44794
|
const ledgerEntries = resumeLedger.getRecentEntries(50);
|
|
43748
44795
|
const resumeCtx = generateSessionResume2(ledgerEntries);
|
|
43749
44796
|
if (resumeCtx) {
|
|
@@ -43764,7 +44811,7 @@ async function startProxy(opts = {}) {
|
|
|
43764
44811
|
const { createDurabilityScorer: createDurabilityScorer2 } = await Promise.resolve().then(() => (init_durability_scorer(), durability_scorer_exports));
|
|
43765
44812
|
const durabilityScorer = createDurabilityScorer2();
|
|
43766
44813
|
const { ShadowLedger: DurLedger } = await Promise.resolve().then(() => (init_shadow_ledger(), shadow_ledger_exports));
|
|
43767
|
-
const durLedger = new DurLedger(
|
|
44814
|
+
const durLedger = new DurLedger(join81(process.cwd(), ".unerr"));
|
|
43768
44815
|
const durEntries = durLedger.getRecentEntries(200);
|
|
43769
44816
|
if (durEntries.length > 0) {
|
|
43770
44817
|
durabilityScorer.computeScores(durEntries);
|
|
@@ -43784,7 +44831,7 @@ async function startProxy(opts = {}) {
|
|
|
43784
44831
|
try {
|
|
43785
44832
|
const { detectInstableEntities: detectInstableEntities2 } = await Promise.resolve().then(() => (init_negative_knowledge(), negative_knowledge_exports));
|
|
43786
44833
|
const { ShadowLedger: NkLedger } = await Promise.resolve().then(() => (init_shadow_ledger(), shadow_ledger_exports));
|
|
43787
|
-
const nkLedger = new NkLedger(
|
|
44834
|
+
const nkLedger = new NkLedger(join81(process.cwd(), ".unerr"));
|
|
43788
44835
|
const nkEntries = nkLedger.getRecentEntries(200);
|
|
43789
44836
|
if (nkEntries.length > 0) {
|
|
43790
44837
|
const antiPatterns = detectInstableEntities2(nkEntries);
|
|
@@ -43806,7 +44853,7 @@ async function startProxy(opts = {}) {
|
|
|
43806
44853
|
try {
|
|
43807
44854
|
const { CausalBridge: CausalBridge2 } = await Promise.resolve().then(() => (init_causal_bridge(), causal_bridge_exports));
|
|
43808
44855
|
const causalBridge = new CausalBridge2(
|
|
43809
|
-
|
|
44856
|
+
join81(process.cwd(), ".unerr"),
|
|
43810
44857
|
process.cwd()
|
|
43811
44858
|
);
|
|
43812
44859
|
router.setCausalBridge(causalBridge);
|
|
@@ -43816,7 +44863,7 @@ async function startProxy(opts = {}) {
|
|
|
43816
44863
|
try {
|
|
43817
44864
|
const { learnConventions: learnConventions2 } = await Promise.resolve().then(() => (init_convention_learner(), convention_learner_exports));
|
|
43818
44865
|
const { ShadowLedger: ConvLedger } = await Promise.resolve().then(() => (init_shadow_ledger(), shadow_ledger_exports));
|
|
43819
|
-
const convLedger = new ConvLedger(
|
|
44866
|
+
const convLedger = new ConvLedger(join81(process.cwd(), ".unerr"));
|
|
43820
44867
|
const convEntries = convLedger.getRecentEntries(100);
|
|
43821
44868
|
if (convEntries.length > 0) {
|
|
43822
44869
|
const learned = learnConventions2(convEntries);
|
|
@@ -43839,7 +44886,7 @@ async function startProxy(opts = {}) {
|
|
|
43839
44886
|
try {
|
|
43840
44887
|
const { computePromptDurabilityProfiles: computePromptDurabilityProfiles2 } = await Promise.resolve().then(() => (init_prompt_durability(), prompt_durability_exports));
|
|
43841
44888
|
const { ShadowLedger: DurProfLedger } = await Promise.resolve().then(() => (init_shadow_ledger(), shadow_ledger_exports));
|
|
43842
|
-
const durProfLedger = new DurProfLedger(
|
|
44889
|
+
const durProfLedger = new DurProfLedger(join81(process.cwd(), ".unerr"));
|
|
43843
44890
|
const durProfEntries = durProfLedger.getRecentEntries(200);
|
|
43844
44891
|
if (durProfEntries.length > 0) {
|
|
43845
44892
|
const profiles = computePromptDurabilityProfiles2(durProfEntries);
|
|
@@ -43859,7 +44906,7 @@ async function startProxy(opts = {}) {
|
|
|
43859
44906
|
}
|
|
43860
44907
|
try {
|
|
43861
44908
|
const { createContextLedger: createContextLedger2 } = await Promise.resolve().then(() => (init_context_ledger(), context_ledger_exports));
|
|
43862
|
-
const contextLedger = createContextLedger2(
|
|
44909
|
+
const contextLedger = createContextLedger2(join81(process.cwd(), ".unerr"));
|
|
43863
44910
|
contextLedger.load();
|
|
43864
44911
|
contextLedger.prune();
|
|
43865
44912
|
router.setContextLedger(contextLedger);
|
|
@@ -43984,7 +45031,7 @@ async function startProxy(opts = {}) {
|
|
|
43984
45031
|
});
|
|
43985
45032
|
const { ShadowLedger: ShadowLedger2 } = await Promise.resolve().then(() => (init_shadow_ledger(), shadow_ledger_exports));
|
|
43986
45033
|
const { IntentCorrelator: IntentCorrelator2 } = await Promise.resolve().then(() => (init_intent_correlator(), intent_correlator_exports));
|
|
43987
|
-
const unerrDirForLedger =
|
|
45034
|
+
const unerrDirForLedger = join81(process.cwd(), ".unerr");
|
|
43988
45035
|
const shadowLedger = new ShadowLedger2(unerrDirForLedger);
|
|
43989
45036
|
const intentCorrelator = new IntentCorrelator2(unerrDirForLedger);
|
|
43990
45037
|
log22.info(
|
|
@@ -44094,7 +45141,7 @@ async function startProxy(opts = {}) {
|
|
|
44094
45141
|
try {
|
|
44095
45142
|
const { writeFileSync: writeFileSync42 } = await import("fs");
|
|
44096
45143
|
writeFileSync42(
|
|
44097
|
-
|
|
45144
|
+
join81(unerrDirForLedger, "state", "session.id"),
|
|
44098
45145
|
shadowLedger.getSessionId(),
|
|
44099
45146
|
"utf-8"
|
|
44100
45147
|
);
|
|
@@ -44522,7 +45569,7 @@ ${signalFooter.trimEnd()}` : "";
|
|
|
44522
45569
|
lifecycle.send({ type: "INDEX_COMPLETE" });
|
|
44523
45570
|
lifecycle.send({ type: "MCP_READY" });
|
|
44524
45571
|
const { TransportMux: TransportMux2 } = await Promise.resolve().then(() => (init_transport_mux(), transport_mux_exports));
|
|
44525
|
-
const sockPath2 =
|
|
45572
|
+
const sockPath2 = join81(stateDir, "proxy.sock");
|
|
44526
45573
|
const transportMux = new TransportMux2(sockPath2);
|
|
44527
45574
|
const agentNameByClient = /* @__PURE__ */ new Map();
|
|
44528
45575
|
transportMux.setCustomHttpHandler("/commit-context", (_url) => {
|
|
@@ -44807,7 +45854,7 @@ ${signalFooter2.trimEnd()}` : "";
|
|
|
44807
45854
|
try {
|
|
44808
45855
|
const { DriftTracker: DriftTracker2 } = await Promise.resolve().then(() => (init_drift_tracker(), drift_tracker_exports));
|
|
44809
45856
|
const { FileHashManager: FileHashManager2 } = await Promise.resolve().then(() => (init_file_hash_state(), file_hash_state_exports));
|
|
44810
|
-
const unerrDir2 =
|
|
45857
|
+
const unerrDir2 = join81(process.cwd(), ".unerr");
|
|
44811
45858
|
const fileHashManager = new FileHashManager2(unerrDir2);
|
|
44812
45859
|
_driftTracker = new DriftTracker2(
|
|
44813
45860
|
{ projectRoot: process.cwd(), repoId: repoIds[0], unerrDir: unerrDir2 },
|
|
@@ -45031,7 +46078,7 @@ ${signalFooter2.trimEnd()}` : "";
|
|
|
45031
46078
|
}
|
|
45032
46079
|
const { WorkspaceManifest: WorkspaceManifest2 } = await Promise.resolve().then(() => (init_workspace_manifest(), workspace_manifest_exports));
|
|
45033
46080
|
const workspaceManifest = repoIds[0] ? new WorkspaceManifest2(
|
|
45034
|
-
|
|
46081
|
+
join81(process.cwd(), ".unerr"),
|
|
45035
46082
|
repoIds[0],
|
|
45036
46083
|
shadowLedger.getSessionId()
|
|
45037
46084
|
) : null;
|
|
@@ -45116,7 +46163,7 @@ ${signalFooter2.trimEnd()}` : "";
|
|
|
45116
46163
|
if (proxyMode === "parse" && parseIndex) {
|
|
45117
46164
|
try {
|
|
45118
46165
|
const { extractEntitiesFromSource: extractEntitiesFromSource2 } = await Promise.resolve().then(() => (init_auto_bootstrap(), auto_bootstrap_exports));
|
|
45119
|
-
const allFiles =
|
|
46166
|
+
const allFiles = readdirSync19(process.cwd(), {
|
|
45120
46167
|
recursive: true,
|
|
45121
46168
|
encoding: "utf-8"
|
|
45122
46169
|
});
|
|
@@ -45130,7 +46177,7 @@ ${signalFooter2.trimEnd()}` : "";
|
|
|
45130
46177
|
});
|
|
45131
46178
|
for (const file of sourceFiles.slice(0, 500)) {
|
|
45132
46179
|
try {
|
|
45133
|
-
const content =
|
|
46180
|
+
const content = readFileSync68(join81(process.cwd(), file), "utf-8");
|
|
45134
46181
|
const entities = extractEntitiesFromSource2(file, content);
|
|
45135
46182
|
parseIndex.addEntities(entities);
|
|
45136
46183
|
} catch {
|
|
@@ -45194,7 +46241,7 @@ ${signalFooter2.trimEnd()}` : "";
|
|
|
45194
46241
|
}
|
|
45195
46242
|
const { writeFileSync: writeStatsFile } = await import("fs");
|
|
45196
46243
|
const { computePercentiles: computePercentiles2 } = await Promise.resolve().then(() => (init_session_stats(), session_stats_exports));
|
|
45197
|
-
const statsSnapshotPath =
|
|
46244
|
+
const statsSnapshotPath = join81(stateDir, "session_stats.json");
|
|
45198
46245
|
const statsSnapshotInterval = setInterval(() => {
|
|
45199
46246
|
try {
|
|
45200
46247
|
const total = stats.toolCallsLocal;
|
|
@@ -45232,7 +46279,7 @@ ${signalFooter2.trimEnd()}` : "";
|
|
|
45232
46279
|
const { startDashboardServer: startDashboardServer2 } = await Promise.resolve().then(() => (init_http(), http_exports));
|
|
45233
46280
|
const { detectIde: detectIdeDashboard } = await Promise.resolve().then(() => (init_detect(), detect_exports));
|
|
45234
46281
|
const ideType = await detectIdeDashboard(process.cwd());
|
|
45235
|
-
const unerrDirForApi =
|
|
46282
|
+
const unerrDirForApi = join81(process.cwd(), ".unerr");
|
|
45236
46283
|
dashboardHandle = await startDashboardServer2({
|
|
45237
46284
|
system: {
|
|
45238
46285
|
stats,
|
|
@@ -45300,16 +46347,16 @@ ${signalFooter2.trimEnd()}` : "";
|
|
|
45300
46347
|
temporal: await (async () => {
|
|
45301
46348
|
try {
|
|
45302
46349
|
const { TemporalFactStore: TemporalFactStore2 } = await Promise.resolve().then(() => (init_temporal_facts(), temporal_facts_exports));
|
|
45303
|
-
const { readdirSync:
|
|
46350
|
+
const { readdirSync: readdirSync20, readFileSync: readFileSync71 } = await import("fs");
|
|
45304
46351
|
const factStore = await TemporalFactStore2.create(process.cwd());
|
|
45305
46352
|
return {
|
|
45306
46353
|
factStore,
|
|
45307
46354
|
loadRecentSessions: (limit) => {
|
|
45308
46355
|
try {
|
|
45309
|
-
const sessDir =
|
|
45310
|
-
const files =
|
|
46356
|
+
const sessDir = join81(unerrDirForApi, "sessions");
|
|
46357
|
+
const files = readdirSync20(sessDir).filter((f) => f.endsWith(".jsonl")).sort().slice(-limit);
|
|
45311
46358
|
return files.map((f) => {
|
|
45312
|
-
const content =
|
|
46359
|
+
const content = readFileSync71(join81(sessDir, f), "utf-8").trim().split("\n").pop();
|
|
45313
46360
|
return JSON.parse(content);
|
|
45314
46361
|
});
|
|
45315
46362
|
} catch {
|
|
@@ -45396,7 +46443,7 @@ ${signalFooter2.trimEnd()}` : "";
|
|
|
45396
46443
|
const topMech = Object.entries(tokenFlowSummary.by_mechanism).sort(
|
|
45397
46444
|
([, a], [, b]) => b.tokens_saved - a.tokens_saved
|
|
45398
46445
|
)[0];
|
|
45399
|
-
appendSessionHistory2(
|
|
46446
|
+
appendSessionHistory2(join81(process.cwd(), ".unerr"), {
|
|
45400
46447
|
sessionId: shadowLedger.getSessionId(),
|
|
45401
46448
|
startedAt: new Date(stats.sessionStartedAt).toISOString(),
|
|
45402
46449
|
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -45556,7 +46603,7 @@ ${signalFooter2.trimEnd()}` : "";
|
|
|
45556
46603
|
try {
|
|
45557
46604
|
const correctionModule = (init_correction_detector(), __toCommonJS(correction_detector_exports));
|
|
45558
46605
|
const detectCorrections2 = correctionModule.detectCorrections;
|
|
45559
|
-
const ledgerPath =
|
|
46606
|
+
const ledgerPath = join81(
|
|
45560
46607
|
process.cwd(),
|
|
45561
46608
|
".unerr",
|
|
45562
46609
|
"ledger",
|
|
@@ -45920,19 +46967,19 @@ __export(setup_wizard_exports, {
|
|
|
45920
46967
|
promptLocalOrExit: () => promptLocalOrExit,
|
|
45921
46968
|
runSetup: () => runSetup
|
|
45922
46969
|
});
|
|
45923
|
-
import { createHash as
|
|
46970
|
+
import { createHash as createHash5 } from "crypto";
|
|
45924
46971
|
import { existsSync as existsSync80, mkdirSync as mkdirSync46, writeFileSync as writeFileSync40 } from "fs";
|
|
45925
|
-
import { join as
|
|
46972
|
+
import { join as join82 } from "path";
|
|
45926
46973
|
import * as clack from "@clack/prompts";
|
|
45927
46974
|
async function runSetup(cwd) {
|
|
45928
46975
|
const projectDir = cwd ?? process.cwd();
|
|
45929
46976
|
clack.intro("unerr");
|
|
45930
46977
|
clack.log.step("Project Setup");
|
|
45931
46978
|
const repoId = await generateRepoId(projectDir);
|
|
45932
|
-
const configDir =
|
|
46979
|
+
const configDir = join82(projectDir, ".unerr");
|
|
45933
46980
|
mkdirSync46(configDir, { recursive: true });
|
|
45934
|
-
const configPath2 =
|
|
45935
|
-
const settingsPath =
|
|
46981
|
+
const configPath2 = join82(configDir, "config.json");
|
|
46982
|
+
const settingsPath = join82(configDir, "settings.json");
|
|
45936
46983
|
writeFileSync40(configPath2, `${JSON.stringify({ repoId }, null, 2)}
|
|
45937
46984
|
`);
|
|
45938
46985
|
let existingSettings = {};
|
|
@@ -46003,7 +47050,7 @@ async function generateRepoId(cwd) {
|
|
|
46003
47050
|
let repoIdentifier = cwd;
|
|
46004
47051
|
const remote = await getRemoteUrl(cwd);
|
|
46005
47052
|
if (remote) repoIdentifier = remote;
|
|
46006
|
-
return
|
|
47053
|
+
return createHash5("sha256").update(repoIdentifier).digest("hex").slice(0, 12);
|
|
46007
47054
|
}
|
|
46008
47055
|
function formatSize2(bytes) {
|
|
46009
47056
|
if (bytes >= 1e9) return `${(bytes / 1e9).toFixed(1)}GB`;
|
|
@@ -46316,6 +47363,112 @@ var init_setup_wizard = __esm({
|
|
|
46316
47363
|
}
|
|
46317
47364
|
});
|
|
46318
47365
|
|
|
47366
|
+
// src/proxy/bridge-catalog.ts
|
|
47367
|
+
var bridge_catalog_exports = {};
|
|
47368
|
+
__export(bridge_catalog_exports, {
|
|
47369
|
+
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
47370
|
+
SERVER_INFO: () => SERVER_INFO,
|
|
47371
|
+
StaticCatalogInterceptor: () => StaticCatalogInterceptor,
|
|
47372
|
+
buildInitializeResult: () => buildInitializeResult,
|
|
47373
|
+
buildToolsListResult: () => buildToolsListResult
|
|
47374
|
+
});
|
|
47375
|
+
function tryIntercept(line) {
|
|
47376
|
+
let msg;
|
|
47377
|
+
try {
|
|
47378
|
+
const parsed = JSON.parse(line);
|
|
47379
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
47380
|
+
msg = parsed;
|
|
47381
|
+
} catch {
|
|
47382
|
+
return null;
|
|
47383
|
+
}
|
|
47384
|
+
if (msg.method === "initialize") {
|
|
47385
|
+
return JSON.stringify({
|
|
47386
|
+
jsonrpc: "2.0",
|
|
47387
|
+
id: msg.id ?? null,
|
|
47388
|
+
result: {
|
|
47389
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
47390
|
+
capabilities: { tools: {} },
|
|
47391
|
+
serverInfo: SERVER_INFO
|
|
47392
|
+
}
|
|
47393
|
+
});
|
|
47394
|
+
}
|
|
47395
|
+
if (msg.method === "tools/list") {
|
|
47396
|
+
return JSON.stringify({
|
|
47397
|
+
jsonrpc: "2.0",
|
|
47398
|
+
id: msg.id ?? null,
|
|
47399
|
+
result: { tools: TOOL_DEFINITIONS }
|
|
47400
|
+
});
|
|
47401
|
+
}
|
|
47402
|
+
return null;
|
|
47403
|
+
}
|
|
47404
|
+
function buildInitializeResult(id) {
|
|
47405
|
+
return {
|
|
47406
|
+
jsonrpc: "2.0",
|
|
47407
|
+
id,
|
|
47408
|
+
result: {
|
|
47409
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
47410
|
+
capabilities: { tools: {} },
|
|
47411
|
+
serverInfo: SERVER_INFO
|
|
47412
|
+
}
|
|
47413
|
+
};
|
|
47414
|
+
}
|
|
47415
|
+
function buildToolsListResult(id) {
|
|
47416
|
+
return {
|
|
47417
|
+
jsonrpc: "2.0",
|
|
47418
|
+
id,
|
|
47419
|
+
result: { tools: TOOL_DEFINITIONS }
|
|
47420
|
+
};
|
|
47421
|
+
}
|
|
47422
|
+
var PROTOCOL_VERSION, SERVER_INFO, StaticCatalogInterceptor;
|
|
47423
|
+
var init_bridge_catalog = __esm({
|
|
47424
|
+
"src/proxy/bridge-catalog.ts"() {
|
|
47425
|
+
"use strict";
|
|
47426
|
+
init_tool_definitions();
|
|
47427
|
+
PROTOCOL_VERSION = "2024-11-05";
|
|
47428
|
+
SERVER_INFO = {
|
|
47429
|
+
name: "unerr-local",
|
|
47430
|
+
version: "0.1.7"
|
|
47431
|
+
};
|
|
47432
|
+
StaticCatalogInterceptor = class {
|
|
47433
|
+
partial = "";
|
|
47434
|
+
ingest(chunk) {
|
|
47435
|
+
const replies = [];
|
|
47436
|
+
const forward = [];
|
|
47437
|
+
this.partial += chunk.toString("utf8");
|
|
47438
|
+
const lastNewline = this.partial.lastIndexOf("\n");
|
|
47439
|
+
if (lastNewline < 0) {
|
|
47440
|
+
return { replies, forward };
|
|
47441
|
+
}
|
|
47442
|
+
const completeBlock = this.partial.slice(0, lastNewline + 1);
|
|
47443
|
+
this.partial = this.partial.slice(lastNewline + 1);
|
|
47444
|
+
for (const rawLine of completeBlock.split("\n")) {
|
|
47445
|
+
if (rawLine === "") continue;
|
|
47446
|
+
const reply = tryIntercept(rawLine);
|
|
47447
|
+
if (reply !== null) {
|
|
47448
|
+
replies.push(`${reply}
|
|
47449
|
+
`);
|
|
47450
|
+
} else {
|
|
47451
|
+
forward.push(Buffer.from(`${rawLine}
|
|
47452
|
+
`, "utf8"));
|
|
47453
|
+
}
|
|
47454
|
+
}
|
|
47455
|
+
return { replies, forward };
|
|
47456
|
+
}
|
|
47457
|
+
/**
|
|
47458
|
+
* Returns any unfinished line (no terminating newline yet). Call exactly
|
|
47459
|
+
* once when handing the pre-buffer off to the bridge so partial frames are
|
|
47460
|
+
* forwarded to the proxy without being dropped.
|
|
47461
|
+
*/
|
|
47462
|
+
drainPartial() {
|
|
47463
|
+
if (this.partial.length === 0) return null;
|
|
47464
|
+
const buf = Buffer.from(this.partial, "utf8");
|
|
47465
|
+
this.partial = "";
|
|
47466
|
+
return buf;
|
|
47467
|
+
}
|
|
47468
|
+
};
|
|
47469
|
+
}
|
|
47470
|
+
});
|
|
47471
|
+
|
|
46319
47472
|
// src/daemon/spawn-lock.ts
|
|
46320
47473
|
var spawn_lock_exports = {};
|
|
46321
47474
|
__export(spawn_lock_exports, {
|
|
@@ -46327,16 +47480,16 @@ import {
|
|
|
46327
47480
|
closeSync as closeSync2,
|
|
46328
47481
|
mkdirSync as mkdirSync47,
|
|
46329
47482
|
openSync as openSync2,
|
|
46330
|
-
readFileSync as
|
|
47483
|
+
readFileSync as readFileSync69,
|
|
46331
47484
|
unlinkSync as unlinkSync16,
|
|
46332
47485
|
writeFileSync as writeFileSync41
|
|
46333
47486
|
} from "fs";
|
|
46334
|
-
import { join as
|
|
47487
|
+
import { join as join83 } from "path";
|
|
46335
47488
|
function spawnLockPath() {
|
|
46336
|
-
return
|
|
47489
|
+
return join83(globalDir(), "state", "spawn.lock");
|
|
46337
47490
|
}
|
|
46338
47491
|
function tryAcquireSpawnLock() {
|
|
46339
|
-
mkdirSync47(
|
|
47492
|
+
mkdirSync47(join83(globalDir(), "state"), { recursive: true });
|
|
46340
47493
|
const path7 = spawnLockPath();
|
|
46341
47494
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
46342
47495
|
try {
|
|
@@ -46364,7 +47517,7 @@ function releaseSpawnLock() {
|
|
|
46364
47517
|
function reclaimIfStale(path7) {
|
|
46365
47518
|
let body = null;
|
|
46366
47519
|
try {
|
|
46367
|
-
body = JSON.parse(
|
|
47520
|
+
body = JSON.parse(readFileSync69(path7, "utf8"));
|
|
46368
47521
|
} catch {
|
|
46369
47522
|
try {
|
|
46370
47523
|
unlinkSync16(path7);
|
|
@@ -46536,8 +47689,8 @@ var init_bridge = __esm({
|
|
|
46536
47689
|
});
|
|
46537
47690
|
|
|
46538
47691
|
// src/entrypoints/cli.ts
|
|
46539
|
-
import { existsSync as existsSync81, readFileSync as
|
|
46540
|
-
import { join as
|
|
47692
|
+
import { existsSync as existsSync81, readFileSync as readFileSync70 } from "fs";
|
|
47693
|
+
import { join as join84 } from "path";
|
|
46541
47694
|
import { Command } from "commander";
|
|
46542
47695
|
|
|
46543
47696
|
// src/commands/branches.ts
|
|
@@ -49573,12 +50726,12 @@ async function tryLoadGraphForShellBoost(cwd) {
|
|
|
49573
50726
|
if (cached && Date.now() - cached.loadedAt < BOOST_TTL_MS) {
|
|
49574
50727
|
return cached.kind === "ok" ? cached.graph : null;
|
|
49575
50728
|
}
|
|
49576
|
-
const { existsSync: existsSync82, readFileSync:
|
|
49577
|
-
const { join:
|
|
49578
|
-
const snapshotsDir =
|
|
49579
|
-
let snapshotPath2 =
|
|
50729
|
+
const { existsSync: existsSync82, readFileSync: readFileSync71 } = await import("fs");
|
|
50730
|
+
const { join: join85 } = await import("path");
|
|
50731
|
+
const snapshotsDir = join85(cwd, ".unerr", "snapshots");
|
|
50732
|
+
let snapshotPath2 = join85(snapshotsDir, "graph.msgpack.gz");
|
|
49580
50733
|
if (!existsSync82(snapshotPath2)) {
|
|
49581
|
-
snapshotPath2 =
|
|
50734
|
+
snapshotPath2 = join85(snapshotsDir, "graph.msgpack");
|
|
49582
50735
|
}
|
|
49583
50736
|
if (!existsSync82(snapshotPath2)) {
|
|
49584
50737
|
const reason = `snapshot missing at ${snapshotsDir}`;
|
|
@@ -49605,7 +50758,7 @@ async function tryLoadGraphForShellBoost(cwd) {
|
|
|
49605
50758
|
let buffer;
|
|
49606
50759
|
try {
|
|
49607
50760
|
const { gunzipSync: gunzipSync3 } = await import("zlib");
|
|
49608
|
-
const raw =
|
|
50761
|
+
const raw = readFileSync71(snapshotPath2);
|
|
49609
50762
|
try {
|
|
49610
50763
|
buffer = gunzipSync3(raw);
|
|
49611
50764
|
} catch {
|
|
@@ -54765,9 +55918,9 @@ When your next action is Edit, use built-in Read with offset/limit on the target
|
|
|
54765
55918
|
|
|
54766
55919
|
**Common failure mode:** Using \`file_read\` to understand a file, then attempting Edit without calling built-in Read first. The Edit tool WILL reject with "File has not been read yet". Always call built-in Read (with offset/limit) immediately before Edit.` : "";
|
|
54767
55920
|
const summaryEditNote = isClaudeCode ? "\nNEVER use built-in Read/Grep/Glob for code navigation. EXCEPTION: built-in Read (with offset/limit) is REQUIRED immediately before Edit (file_read cannot substitute \u2014 Edit will fail without it)." : "\nNEVER use built-in Read/Grep/Glob for code navigation \u2014 use unerr MCP tools instead.";
|
|
54768
|
-
return `## REQUIRED: Use unerr Graph Intelligence Tools (
|
|
55921
|
+
return `## REQUIRED: Use unerr Graph Intelligence Tools (20 MCP tools)
|
|
54769
55922
|
|
|
54770
|
-
This project has unerr MCP tools installed. You MUST use these instead of built-in Read/Grep/Glob for code navigation. unerr tools are graph-backed, return results in <5ms, and include project context that built-in tools miss.
|
|
55923
|
+
This project has unerr MCP tools installed. You MUST use these instead of built-in Read/Grep/Glob for code navigation, and \`fetch_url\` instead of built-in WebFetch. unerr tools are graph-backed, return results in <5ms, and include project context that built-in tools miss.
|
|
54771
55924
|
|
|
54772
55925
|
### Tool Routing (MANDATORY \u2014 match your goal before calling any tool)
|
|
54773
55926
|
|
|
@@ -54781,6 +55934,7 @@ ${readForEditRow}
|
|
|
54781
55934
|
| Get a specific function or class | \`get_entity\` or \`file_read\` with \`entity\` param | Reading entire file |
|
|
54782
55935
|
| Trace imports/dependencies | \`get_imports\` or \`get_references\` (direction: callees) | Manual import scanning |
|
|
54783
55936
|
| Find hotspots / high fan-in / blast-radius candidates | \`get_critical_nodes\` | \`get_entity\` (won't show ranked list), guessing |
|
|
55937
|
+
| Fetch a web page by URL | \`fetch_url\` (Defuddle/Readability \u2192 markdown passages \u2192 BM25 ranking when \`prompt\` supplied \u2192 diff-cache) | Built-in WebFetch |
|
|
54784
55938
|
| Run a shell command | Automatic \u2014 routed through shell intelligence | N/A |
|
|
54785
55939
|
|
|
54786
55940
|
### FORBIDDEN Patterns (these waste tokens and miss context)
|
|
@@ -54791,7 +55945,8 @@ ${readForEditRow}
|
|
|
54791
55945
|
- Reading multiple files to understand conventions -> use \`get_conventions\`
|
|
54792
55946
|
- Guessing code style for new code -> use \`get_conventions\`
|
|
54793
55947
|
- Guessing which entity has the highest fan-in / is the biggest hotspot -> use \`get_critical_nodes\`
|
|
54794
|
-
- Reading a full file when you only need a section -> use \`file_read\` with \`entity\` param or offset/limit
|
|
55948
|
+
- Reading a full file when you only need a section -> use \`file_read\` with \`entity\` param or offset/limit
|
|
55949
|
+
- Using built-in WebFetch for a URL -> use \`fetch_url\` (DOM extraction + markdown + BM25 passage selection cuts 5\u201310\xD7 tokens; pass \`prompt\` to rank passages by relevance)${twoStepSection}
|
|
54795
55950
|
|
|
54796
55951
|
### Tool Reference
|
|
54797
55952
|
|
|
@@ -54829,6 +55984,14 @@ ${readForEditRow}
|
|
|
54829
55984
|
- \`purpose:'explore'\` (default) \u2014 budget-capped, returns outline for large files. Use for browsing and pre-edit understanding.
|
|
54830
55985
|
- \`purpose:'reference'\` \u2014 tight budget, entity/offset reads only. Use for quick lookups.
|
|
54831
55986
|
|
|
55987
|
+
#### Web Fetch (1 tool)
|
|
55988
|
+
|
|
55989
|
+
| Task | Tool | Replaces |
|
|
55990
|
+
|------|------|----------|
|
|
55991
|
+
| Fetch a web page by URL | \`fetch_url\` | Built-in WebFetch |
|
|
55992
|
+
|
|
55993
|
+
\`fetch_url\` strips chrome (nav, footer, ads), converts to markdown, splits into heading-bounded passages, optionally re-ranks passages with BM25 when you pass \`prompt\`, and caches by content hash so re-fetching an unchanged page costs near-zero tokens. Pass \`offset\`/\`limit\` to paginate large pages.
|
|
55994
|
+
|
|
54832
55995
|
#### Shell Compression (automatic)
|
|
54833
55996
|
|
|
54834
55997
|
All shell commands automatically route through unerr's compression layer. It strips ANSI codes, classifies output (diffs, test results, logs, errors), and returns compressed summaries \u2014 saving tokens without losing critical information.
|
|
@@ -55187,7 +56350,8 @@ function registerInstallCommand(program2) {
|
|
|
55187
56350
|
}
|
|
55188
56351
|
process.stderr.write("\n");
|
|
55189
56352
|
process.stderr.write(
|
|
55190
|
-
|
|
56353
|
+
` \x1B[38;2;161;161;170mRestart ${agentDef.name} to start using unerr.\x1B[0m
|
|
56354
|
+
`
|
|
55191
56355
|
);
|
|
55192
56356
|
process.stderr.write("\n");
|
|
55193
56357
|
}
|
|
@@ -55243,29 +56407,13 @@ async function runInstall(cwd, ide, opts) {
|
|
|
55243
56407
|
const { daemonSockPath: daemonSockPath2, probeDaemon: probeDaemon2, ensureRepo: ensureRepo2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
55244
56408
|
const { addRepo: addRepo2, findRepo: findRepo2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
55245
56409
|
const sock = daemonSockPath2();
|
|
55246
|
-
|
|
55247
|
-
if (daemonRunning) {
|
|
56410
|
+
if (await probeDaemon2(sock)) {
|
|
55248
56411
|
if (!findRepo2(cwd)) {
|
|
55249
56412
|
addRepo2(cwd, {});
|
|
55250
56413
|
repoRegistered = true;
|
|
55251
|
-
process.stderr.write(
|
|
55252
|
-
"\x1B[38;2;52;211;153m\u2713\x1B[0m Registered repo with unerrd.\n"
|
|
55253
|
-
);
|
|
55254
|
-
}
|
|
55255
|
-
try {
|
|
55256
|
-
await ensureRepo2(sock, cwd);
|
|
55257
|
-
process.stderr.write(
|
|
55258
|
-
"\x1B[38;2;52;211;153m\u2713\x1B[0m unerr process started via daemon.\n"
|
|
55259
|
-
);
|
|
55260
|
-
} catch {
|
|
55261
|
-
process.stderr.write(
|
|
55262
|
-
"\x1B[38;2;251;191;36m\u26A0\x1B[0m Repo registered but process did not start. It will start on next IDE connection.\n"
|
|
55263
|
-
);
|
|
55264
56414
|
}
|
|
55265
|
-
|
|
55266
|
-
|
|
55267
|
-
"\x1B[38;2;34;211;238m\u25B8\x1B[0m Daemon not running. To use daemon mode: \x1B[1munerr daemon initialize\x1B[0m\n For standalone mode: run \x1B[1munerr\x1B[0m in this directory.\n"
|
|
55268
|
-
);
|
|
56415
|
+
await ensureRepo2(sock, cwd).catch(() => {
|
|
56416
|
+
});
|
|
55269
56417
|
}
|
|
55270
56418
|
} catch {
|
|
55271
56419
|
}
|
|
@@ -55417,12 +56565,12 @@ function showSetupInstructions(agentName) {
|
|
|
55417
56565
|
w(" After restarting your agent, verify unerr tools are available.\n");
|
|
55418
56566
|
w(" You should see tools like: get_callers, search_code, file_read,\n");
|
|
55419
56567
|
w(" file_outline, get_imports, get_callees.\n\n");
|
|
55420
|
-
w(" \x1B[1mStep 4:
|
|
55421
|
-
w(" \x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m\n");
|
|
56568
|
+
w(" \x1B[1mStep 4: Restart your agent\x1B[0m\n");
|
|
56569
|
+
w(" \x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m\n");
|
|
55422
56570
|
w(
|
|
55423
|
-
"
|
|
56571
|
+
" unerr starts automatically when your agent first connects to its MCP server.\n"
|
|
55424
56572
|
);
|
|
55425
|
-
w("
|
|
56573
|
+
w(" No background service to install \u2014 no boot-time setup needed.\n");
|
|
55426
56574
|
}
|
|
55427
56575
|
w("\n");
|
|
55428
56576
|
}
|
|
@@ -55757,8 +56905,8 @@ async function persistPatterns(patterns, _unerrDir) {
|
|
|
55757
56905
|
);
|
|
55758
56906
|
return;
|
|
55759
56907
|
}
|
|
55760
|
-
const { readFileSync:
|
|
55761
|
-
const config = JSON.parse(
|
|
56908
|
+
const { readFileSync: readFileSync71 } = await import("fs");
|
|
56909
|
+
const config = JSON.parse(readFileSync71(configPath2, "utf-8"));
|
|
55762
56910
|
if (!config.repoId || !config.orgId) {
|
|
55763
56911
|
warn("Repo not configured \u2014 cannot persist to CozoDB.");
|
|
55764
56912
|
return;
|
|
@@ -55776,7 +56924,7 @@ async function persistPatterns(patterns, _unerrDir) {
|
|
|
55776
56924
|
const { CozoGraphStore: CozoGraphStore2 } = await Promise.resolve().then(() => (init_local_graph(), local_graph_exports));
|
|
55777
56925
|
const store = await CozoGraphStore2.create(db);
|
|
55778
56926
|
const { unpack } = await import("msgpackr");
|
|
55779
|
-
const raw =
|
|
56927
|
+
const raw = readFileSync71(snapshotPath2);
|
|
55780
56928
|
const buffer = gunzipSync2(raw);
|
|
55781
56929
|
const envelope = unpack(buffer);
|
|
55782
56930
|
await store.loadSnapshot(envelope);
|
|
@@ -56037,7 +57185,13 @@ function parseSettingsFlags(raw) {
|
|
|
56037
57185
|
var write3 = (msg) => process.stderr.write(msg);
|
|
56038
57186
|
function registerPmCommand(program2) {
|
|
56039
57187
|
const pm = program2.command("pm").description("Manage the unerr process manager");
|
|
56040
|
-
pm.command("start").description("Start the unerr process manager").option(
|
|
57188
|
+
pm.command("start").description("Start the unerr process manager").option(
|
|
57189
|
+
"--foreground",
|
|
57190
|
+
"Run in foreground (blocks terminal \u2014 useful for debugging)"
|
|
57191
|
+
).option(
|
|
57192
|
+
"--detached",
|
|
57193
|
+
"Run in-process as a detached supervisor (used by auto-spawn)"
|
|
57194
|
+
).action(async (opts) => {
|
|
56041
57195
|
if (opts.foreground || opts.detached) {
|
|
56042
57196
|
process.title = "unerrd";
|
|
56043
57197
|
const { startDaemon: startDaemon2 } = await Promise.resolve().then(() => (init_daemon(), daemon_exports));
|
|
@@ -56049,7 +57203,12 @@ function registerPmCommand(program2) {
|
|
|
56049
57203
|
const child = spawn(
|
|
56050
57204
|
process.execPath,
|
|
56051
57205
|
[unerrBin, "pm", "start", "--detached"],
|
|
56052
|
-
{
|
|
57206
|
+
{
|
|
57207
|
+
detached: true,
|
|
57208
|
+
stdio: "ignore",
|
|
57209
|
+
windowsHide: true,
|
|
57210
|
+
env: { ...process.env }
|
|
57211
|
+
}
|
|
56053
57212
|
);
|
|
56054
57213
|
child.unref();
|
|
56055
57214
|
const { daemonSockPath: daemonSockPath2, probeDaemon: probeDaemon2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
@@ -56066,12 +57225,12 @@ function registerPmCommand(program2) {
|
|
|
56066
57225
|
}
|
|
56067
57226
|
if (running) {
|
|
56068
57227
|
const { homedir: homedir12 } = await import("os");
|
|
56069
|
-
const { join:
|
|
56070
|
-
const pidPath2 =
|
|
57228
|
+
const { join: join85 } = await import("path");
|
|
57229
|
+
const pidPath2 = join85(homedir12(), ".unerr", "unerrd.pid");
|
|
56071
57230
|
let daemonPid = String(child.pid);
|
|
56072
57231
|
try {
|
|
56073
|
-
const { readFileSync:
|
|
56074
|
-
daemonPid =
|
|
57232
|
+
const { readFileSync: readFileSync71 } = await import("fs");
|
|
57233
|
+
daemonPid = readFileSync71(pidPath2, "utf-8").trim();
|
|
56075
57234
|
} catch {
|
|
56076
57235
|
}
|
|
56077
57236
|
write3(
|
|
@@ -56088,8 +57247,8 @@ function registerPmCommand(program2) {
|
|
|
56088
57247
|
pm.command("stop").description("Stop the unerrd supervisor").action(async () => {
|
|
56089
57248
|
const { createConnection: createConnection3 } = await import("net");
|
|
56090
57249
|
const { globalDir: globalDir2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
56091
|
-
const { join:
|
|
56092
|
-
const sock =
|
|
57250
|
+
const { join: join85 } = await import("path");
|
|
57251
|
+
const sock = join85(globalDir2(), "unerrd.sock");
|
|
56093
57252
|
const { existsSync: existsSync82 } = await import("fs");
|
|
56094
57253
|
if (!existsSync82(sock)) {
|
|
56095
57254
|
write3("unerrd is not running (no socket found).\n");
|
|
@@ -56214,7 +57373,7 @@ function registerPmCommand(program2) {
|
|
|
56214
57373
|
pm.command("status").description("List all registered repos and their state").action(async () => {
|
|
56215
57374
|
const repos = listRepos();
|
|
56216
57375
|
if (repos.length === 0) {
|
|
56217
|
-
write3("No repos registered. Use `unerr
|
|
57376
|
+
write3("No repos registered. Use `unerr pm add .` to register.\n");
|
|
56218
57377
|
return;
|
|
56219
57378
|
}
|
|
56220
57379
|
let liveStatus = null;
|
|
@@ -56263,7 +57422,7 @@ function registerPmCommand(program2) {
|
|
|
56263
57422
|
}
|
|
56264
57423
|
write3(
|
|
56265
57424
|
`
|
|
56266
|
-
\x1B[1munerr
|
|
57425
|
+
\x1B[1munerr pm\x1B[0m \u2014 ${repos.length} repo${repos.length === 1 ? "" : "s"} registered
|
|
56267
57426
|
|
|
56268
57427
|
`
|
|
56269
57428
|
);
|
|
@@ -56296,7 +57455,7 @@ function registerPmCommand(program2) {
|
|
|
56296
57455
|
write3(
|
|
56297
57456
|
` ${ni.key}: auto-selected \x1B[1m${ni.auto}\x1B[0m (${ni.reason})
|
|
56298
57457
|
Alternatives: ${ni.alternatives.join(", ")}
|
|
56299
|
-
Override: unerr
|
|
57458
|
+
Override: unerr pm config ${repo.path} --${toKebab(ni.key)}=${ni.alternatives[0]}
|
|
56300
57459
|
`
|
|
56301
57460
|
);
|
|
56302
57461
|
}
|
|
@@ -56327,7 +57486,7 @@ function registerPmCommand(program2) {
|
|
|
56327
57486
|
if (!entry) {
|
|
56328
57487
|
write3(
|
|
56329
57488
|
`\x1B[38;2;248;113;113m\u2717\x1B[0m Not registered: ${targetPath}
|
|
56330
|
-
Register first: unerr
|
|
57489
|
+
Register first: unerr pm add ${targetPath}
|
|
56331
57490
|
`
|
|
56332
57491
|
);
|
|
56333
57492
|
process.exitCode = 1;
|
|
@@ -56382,7 +57541,7 @@ function registerPmCommand(program2) {
|
|
|
56382
57541
|
if (!updated) {
|
|
56383
57542
|
write3(
|
|
56384
57543
|
`\x1B[38;2;248;113;113m\u2717\x1B[0m Not registered: ${targetPath}
|
|
56385
|
-
Register first: unerr
|
|
57544
|
+
Register first: unerr pm add ${targetPath}
|
|
56386
57545
|
`
|
|
56387
57546
|
);
|
|
56388
57547
|
process.exitCode = 1;
|
|
@@ -58025,8 +59184,8 @@ function registerStatusCommand(program2) {
|
|
|
58025
59184
|
try {
|
|
58026
59185
|
const logsDir = join53(unerrDir2, "logs");
|
|
58027
59186
|
if (existsSync50(logsDir)) {
|
|
58028
|
-
const { readdirSync:
|
|
58029
|
-
const logs =
|
|
59187
|
+
const { readdirSync: readdirSync20, statSync: statSync16 } = await import("fs");
|
|
59188
|
+
const logs = readdirSync20(logsDir).filter((f) => f.startsWith("session-") && f.endsWith(".log")).map((f) => ({
|
|
58030
59189
|
name: f,
|
|
58031
59190
|
mtime: statSync16(join53(logsDir, f)).mtimeMs
|
|
58032
59191
|
})).sort((a, b) => b.mtime - a.mtime);
|
|
@@ -59034,7 +60193,7 @@ var SOURCE_DIRS = /* @__PURE__ */ new Set([
|
|
|
59034
60193
|
]);
|
|
59035
60194
|
var DETECTION_THRESHOLD = 5;
|
|
59036
60195
|
async function detectProjectRoot(cwd) {
|
|
59037
|
-
const { readdirSync:
|
|
60196
|
+
const { readdirSync: readdirSync20 } = await import("fs");
|
|
59038
60197
|
let score = 0;
|
|
59039
60198
|
const signals = [];
|
|
59040
60199
|
let hasGit = false;
|
|
@@ -59052,7 +60211,7 @@ async function detectProjectRoot(cwd) {
|
|
|
59052
60211
|
}
|
|
59053
60212
|
let rootEntries = [];
|
|
59054
60213
|
try {
|
|
59055
|
-
rootEntries =
|
|
60214
|
+
rootEntries = readdirSync20(cwd, { withFileTypes: true }).map((e) => ({
|
|
59056
60215
|
name: e.name,
|
|
59057
60216
|
isFile: e.isFile(),
|
|
59058
60217
|
isDir: e.isDirectory()
|
|
@@ -59143,7 +60302,7 @@ async function detectProjectRoot(cwd) {
|
|
|
59143
60302
|
}
|
|
59144
60303
|
function dirHasCodeFile(dir) {
|
|
59145
60304
|
try {
|
|
59146
|
-
const entries =
|
|
60305
|
+
const entries = readdirSync20(dir, { withFileTypes: true });
|
|
59147
60306
|
for (const entry of entries) {
|
|
59148
60307
|
if (!entry.isFile()) continue;
|
|
59149
60308
|
const dot = entry.name.lastIndexOf(".");
|
|
@@ -59167,7 +60326,7 @@ async function detectProjectRoot(cwd) {
|
|
|
59167
60326
|
for (const dirEntry of rootEntries) {
|
|
59168
60327
|
if (!dirEntry.isDir || dirEntry.name.startsWith(".")) continue;
|
|
59169
60328
|
if (!SOURCE_DIRS.has(dirEntry.name.toLowerCase())) continue;
|
|
59170
|
-
const sourceDir =
|
|
60329
|
+
const sourceDir = join84(cwd, dirEntry.name);
|
|
59171
60330
|
const srcCodeFile = dirHasCodeFile(sourceDir);
|
|
59172
60331
|
if (srcCodeFile) {
|
|
59173
60332
|
score += 6;
|
|
@@ -59175,11 +60334,11 @@ async function detectProjectRoot(cwd) {
|
|
|
59175
60334
|
break;
|
|
59176
60335
|
}
|
|
59177
60336
|
try {
|
|
59178
|
-
const subEntries =
|
|
60337
|
+
const subEntries = readdirSync20(sourceDir, { withFileTypes: true });
|
|
59179
60338
|
let found = false;
|
|
59180
60339
|
for (const sub of subEntries) {
|
|
59181
60340
|
if (!sub.isDirectory() || sub.name.startsWith(".")) continue;
|
|
59182
|
-
const deepCode = dirHasCodeFile(
|
|
60341
|
+
const deepCode = dirHasCodeFile(join84(sourceDir, sub.name));
|
|
59183
60342
|
if (deepCode) {
|
|
59184
60343
|
score += 6;
|
|
59185
60344
|
signals.push(`code-src: ${dirEntry.name}/${sub.name}/${deepCode}`);
|
|
@@ -59202,10 +60361,10 @@ async function detectProjectRoot(cwd) {
|
|
|
59202
60361
|
};
|
|
59203
60362
|
}
|
|
59204
60363
|
function readLocalConfig(cwd) {
|
|
59205
|
-
const configPath2 =
|
|
60364
|
+
const configPath2 = join84(cwd, ".unerr", "config.json");
|
|
59206
60365
|
if (!existsSync81(configPath2)) return null;
|
|
59207
60366
|
try {
|
|
59208
|
-
return JSON.parse(
|
|
60367
|
+
return JSON.parse(readFileSync70(configPath2, "utf-8"));
|
|
59209
60368
|
} catch {
|
|
59210
60369
|
return null;
|
|
59211
60370
|
}
|
|
@@ -59328,8 +60487,8 @@ async function daemonChildBoot(cwd) {
|
|
|
59328
60487
|
repoId: config.repoId,
|
|
59329
60488
|
daemonChild: true
|
|
59330
60489
|
});
|
|
59331
|
-
const stateDir =
|
|
59332
|
-
const sockPath2 =
|
|
60490
|
+
const stateDir = join84(cwd, ".unerr", "state");
|
|
60491
|
+
const sockPath2 = join84(stateDir, "proxy.sock");
|
|
59333
60492
|
if (process.send) {
|
|
59334
60493
|
process.send({ type: "ready", sock: sockPath2 });
|
|
59335
60494
|
}
|
|
@@ -59383,8 +60542,18 @@ async function mcpBoot(cwd) {
|
|
|
59383
60542
|
keep: 5
|
|
59384
60543
|
});
|
|
59385
60544
|
initFileLog(cwd);
|
|
60545
|
+
const { StaticCatalogInterceptor: StaticCatalogInterceptor2 } = await Promise.resolve().then(() => (init_bridge_catalog(), bridge_catalog_exports));
|
|
60546
|
+
const interceptor = new StaticCatalogInterceptor2();
|
|
59386
60547
|
const stdinPreBuffer = [];
|
|
59387
|
-
const preBufferHandler = (chunk) =>
|
|
60548
|
+
const preBufferHandler = (chunk) => {
|
|
60549
|
+
const out = interceptor.ingest(chunk);
|
|
60550
|
+
for (const reply of out.replies) {
|
|
60551
|
+
process.stdout.write(reply);
|
|
60552
|
+
}
|
|
60553
|
+
for (const buf of out.forward) {
|
|
60554
|
+
stdinPreBuffer.push(buf);
|
|
60555
|
+
}
|
|
60556
|
+
};
|
|
59388
60557
|
process.stdin.on("data", preBufferHandler);
|
|
59389
60558
|
let stdinEndedEarly = false;
|
|
59390
60559
|
const earlyEndHandler = () => {
|
|
@@ -59446,6 +60615,8 @@ ${antiSignals.length > 0 ? ` Negative signals: ${antiSignals.map((s) => s.repla
|
|
|
59446
60615
|
if (process.stdin.listenerCount("data") > 0 && stdinPreBuffer.length >= 0) {
|
|
59447
60616
|
process.stdin.removeListener("data", preBufferHandler);
|
|
59448
60617
|
process.stdin.removeListener("end", earlyEndHandler);
|
|
60618
|
+
const partial = interceptor.drainPartial();
|
|
60619
|
+
if (partial) stdinPreBuffer.push(partial);
|
|
59449
60620
|
bufferForBridge = stdinPreBuffer.slice();
|
|
59450
60621
|
stdinPreBuffer.length = 0;
|
|
59451
60622
|
}
|
|
@@ -59500,10 +60671,10 @@ async function discoverWithRetry(cwd, daemonSockPath2, probeDaemon2, ensureRepo2
|
|
|
59500
60671
|
let attempt = 0;
|
|
59501
60672
|
let spawnAttempted = false;
|
|
59502
60673
|
for (; ; ) {
|
|
59503
|
-
const repoSock =
|
|
60674
|
+
const repoSock = join84(cwd, ".unerr", "state", "proxy.sock");
|
|
59504
60675
|
if (existsSync81(repoSock)) {
|
|
59505
60676
|
const { PidLock: PidLock2 } = await Promise.resolve().then(() => (init_pid_lock(), pid_lock_exports));
|
|
59506
|
-
const pidLock = new PidLock2(
|
|
60677
|
+
const pidLock = new PidLock2(join84(cwd, ".unerr", "state"));
|
|
59507
60678
|
const probeResult = await pidLock.probe();
|
|
59508
60679
|
if (probeResult.alive) {
|
|
59509
60680
|
return {
|