farai 0.2.6 → 0.2.8
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 +11 -0
- package/dist/cli/index.js +1563 -486
- package/dist/cli/index.js.map +20 -14
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -5147,6 +5147,7 @@ function normalizeConfig(raw) {
|
|
|
5147
5147
|
const context = contextConfig(raw.context);
|
|
5148
5148
|
const lsp = lspConfig(raw.lsp);
|
|
5149
5149
|
const web = webConfig(raw.web);
|
|
5150
|
+
const updates = updatesConfig(raw.updates);
|
|
5150
5151
|
return {
|
|
5151
5152
|
...positiveInteger(raw.config_version ?? raw.configVersion) !== undefined ? {
|
|
5152
5153
|
configVersion: positiveInteger(raw.config_version ?? raw.configVersion)
|
|
@@ -5206,8 +5207,29 @@ function normalizeConfig(raw) {
|
|
|
5206
5207
|
} : {},
|
|
5207
5208
|
...web ? {
|
|
5208
5209
|
web
|
|
5210
|
+
} : {},
|
|
5211
|
+
...updates ? {
|
|
5212
|
+
updates
|
|
5213
|
+
} : {}
|
|
5214
|
+
};
|
|
5215
|
+
}
|
|
5216
|
+
function updatesConfig(value) {
|
|
5217
|
+
if (!isRecord2(value))
|
|
5218
|
+
return;
|
|
5219
|
+
const rawContentEnabled = value.content_enabled ?? value.contentEnabled;
|
|
5220
|
+
const contentManifestUrl = typeof (value.content_manifest_url ?? value.contentManifestUrl) === "string" ? String(value.content_manifest_url ?? value.contentManifestUrl).trim() : undefined;
|
|
5221
|
+
const config = {
|
|
5222
|
+
...typeof rawContentEnabled === "boolean" ? {
|
|
5223
|
+
contentEnabled: rawContentEnabled
|
|
5224
|
+
} : {},
|
|
5225
|
+
...contentManifestUrl ? {
|
|
5226
|
+
contentManifestUrl
|
|
5227
|
+
} : {},
|
|
5228
|
+
...typeof value.prompt === "boolean" ? {
|
|
5229
|
+
prompt: value.prompt
|
|
5209
5230
|
} : {}
|
|
5210
5231
|
};
|
|
5232
|
+
return Object.keys(config).length ? config : undefined;
|
|
5211
5233
|
}
|
|
5212
5234
|
function webConfig(value) {
|
|
5213
5235
|
if (!isRecord2(value))
|
|
@@ -5389,6 +5411,12 @@ function mergeConfig(base, over) {
|
|
|
5389
5411
|
...base.web,
|
|
5390
5412
|
...over.web
|
|
5391
5413
|
}
|
|
5414
|
+
} : {},
|
|
5415
|
+
...base.updates || over.updates ? {
|
|
5416
|
+
updates: {
|
|
5417
|
+
...base.updates,
|
|
5418
|
+
...over.updates
|
|
5419
|
+
}
|
|
5392
5420
|
} : {}
|
|
5393
5421
|
};
|
|
5394
5422
|
}
|
|
@@ -5444,6 +5472,18 @@ function serializeConfigToml(config) {
|
|
|
5444
5472
|
searxng_url: config.web.searxngUrl
|
|
5445
5473
|
} : {}
|
|
5446
5474
|
});
|
|
5475
|
+
if (config.updates && Object.keys(config.updates).length)
|
|
5476
|
+
emitTable(lines, ["updates"], {
|
|
5477
|
+
...config.updates.contentEnabled === undefined ? {} : {
|
|
5478
|
+
content_enabled: config.updates.contentEnabled
|
|
5479
|
+
},
|
|
5480
|
+
...config.updates.contentManifestUrl ? {
|
|
5481
|
+
content_manifest_url: config.updates.contentManifestUrl
|
|
5482
|
+
} : {},
|
|
5483
|
+
...config.updates.prompt === undefined ? {} : {
|
|
5484
|
+
prompt: config.updates.prompt
|
|
5485
|
+
}
|
|
5486
|
+
});
|
|
5447
5487
|
for (const [selection, limit] of Object.entries(config.modelLimits ?? {})) {
|
|
5448
5488
|
emitTable(lines, ["model_limits", selection], {
|
|
5449
5489
|
...limit.contextWindow ? {
|
|
@@ -5606,6 +5646,10 @@ model = "big-pickle"
|
|
|
5606
5646
|
mode = "explicit"
|
|
5607
5647
|
tls = "relaxed"
|
|
5608
5648
|
|
|
5649
|
+
[updates]
|
|
5650
|
+
content_enabled = true
|
|
5651
|
+
prompt = true
|
|
5652
|
+
|
|
5609
5653
|
[mcp_servers.mitmproxy-mcp]
|
|
5610
5654
|
command = "mitmproxy-mcp"
|
|
5611
5655
|
args = []
|
|
@@ -7419,8 +7463,8 @@ var init_process_output = __esm(() => {
|
|
|
7419
7463
|
|
|
7420
7464
|
// src/version.ts
|
|
7421
7465
|
function resolveFaraiVersion() {
|
|
7422
|
-
if ("0.2.
|
|
7423
|
-
return "0.2.
|
|
7466
|
+
if ("0.2.8")
|
|
7467
|
+
return "0.2.8";
|
|
7424
7468
|
try {
|
|
7425
7469
|
const parsed = JSON.parse(readBoundedFileTextSync(new URL("../package.json", import.meta.url), 1024 * 1024, "package metadata"));
|
|
7426
7470
|
if (typeof parsed.version === "string" && parsed.version)
|
|
@@ -17293,11 +17337,112 @@ var init_memory_mark_failed = __esm(() => {
|
|
|
17293
17337
|
};
|
|
17294
17338
|
});
|
|
17295
17339
|
|
|
17340
|
+
// src/agent-content/paths.ts
|
|
17341
|
+
import { existsSync as existsSync8 } from "fs";
|
|
17342
|
+
import { isAbsolute as isAbsolute4, join as join13, resolve as resolve7 } from "path";
|
|
17343
|
+
function contentRoot() {
|
|
17344
|
+
const configured = process.env.FARAI_CONTENT_DIR?.trim();
|
|
17345
|
+
if (!configured)
|
|
17346
|
+
return join13(globalDataDir(), "content");
|
|
17347
|
+
if (!isAbsolute4(configured))
|
|
17348
|
+
throw new Error("farai_content_dir must be an absolute path");
|
|
17349
|
+
return resolve7(configured);
|
|
17350
|
+
}
|
|
17351
|
+
function contentVersionsDir() {
|
|
17352
|
+
return join13(contentRoot(), "versions");
|
|
17353
|
+
}
|
|
17354
|
+
function contentActivePath() {
|
|
17355
|
+
return join13(contentRoot(), "active.json");
|
|
17356
|
+
}
|
|
17357
|
+
function contentManifestCachePath() {
|
|
17358
|
+
return join13(contentRoot(), "manifest-cache.json");
|
|
17359
|
+
}
|
|
17360
|
+
function contentPreferencesPath() {
|
|
17361
|
+
return join13(contentRoot(), "preferences.json");
|
|
17362
|
+
}
|
|
17363
|
+
function contentLockPath() {
|
|
17364
|
+
return join13(contentRoot(), "update.lock");
|
|
17365
|
+
}
|
|
17366
|
+
function contentVersionDir(version) {
|
|
17367
|
+
if (!VERSION_PATTERN.test(version))
|
|
17368
|
+
throw new Error(`invalid content version: ${version}`);
|
|
17369
|
+
return join13(contentVersionsDir(), version);
|
|
17370
|
+
}
|
|
17371
|
+
function readActiveContent() {
|
|
17372
|
+
const path = contentActivePath();
|
|
17373
|
+
try {
|
|
17374
|
+
if (!existsSync8(path))
|
|
17375
|
+
return;
|
|
17376
|
+
ensurePrivateRegularFileIfExists(path, "active content pointer");
|
|
17377
|
+
const parsed = JSON.parse(readBoundedFileTextSyncNoFollow(path, POINTER_MAX_BYTES, "active content pointer"));
|
|
17378
|
+
return parseActiveContent(parsed);
|
|
17379
|
+
} catch {
|
|
17380
|
+
return;
|
|
17381
|
+
}
|
|
17382
|
+
}
|
|
17383
|
+
function activeContentKnowledgePath() {
|
|
17384
|
+
const active = readActiveContent();
|
|
17385
|
+
if (!active?.knowledge)
|
|
17386
|
+
return;
|
|
17387
|
+
const path = join13(contentVersionDir(active.version), "knowledge.db");
|
|
17388
|
+
return existsSync8(path) ? path : undefined;
|
|
17389
|
+
}
|
|
17390
|
+
function activeContentSkillsDir() {
|
|
17391
|
+
const active = readActiveContent();
|
|
17392
|
+
if (!active?.skills)
|
|
17393
|
+
return;
|
|
17394
|
+
const path = join13(contentVersionDir(active.version), "skills");
|
|
17395
|
+
return existsSync8(path) ? path : undefined;
|
|
17396
|
+
}
|
|
17397
|
+
function ensureContentDirectories() {
|
|
17398
|
+
ensurePrivateDirectory(contentRoot(), "farai content directory");
|
|
17399
|
+
ensurePrivateDirectory(contentVersionsDir(), "farai content versions directory");
|
|
17400
|
+
}
|
|
17401
|
+
function parseActiveContent(value) {
|
|
17402
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
17403
|
+
return;
|
|
17404
|
+
const record2 = value;
|
|
17405
|
+
if (record2.schemaVersion !== 1)
|
|
17406
|
+
return;
|
|
17407
|
+
if (typeof record2.version !== "string" || !VERSION_PATTERN.test(record2.version))
|
|
17408
|
+
return;
|
|
17409
|
+
if (!validDate(record2.generatedAt) || !validDate(record2.activatedAt))
|
|
17410
|
+
return;
|
|
17411
|
+
if (typeof record2.manifestUrl !== "string" || !record2.manifestUrl)
|
|
17412
|
+
return;
|
|
17413
|
+
if (typeof record2.knowledge !== "boolean" || typeof record2.skills !== "boolean")
|
|
17414
|
+
return;
|
|
17415
|
+
const previousVersion = typeof record2.previousVersion === "string" && VERSION_PATTERN.test(record2.previousVersion) ? record2.previousVersion : undefined;
|
|
17416
|
+
return {
|
|
17417
|
+
schemaVersion: 1,
|
|
17418
|
+
version: record2.version,
|
|
17419
|
+
generatedAt: record2.generatedAt,
|
|
17420
|
+
activatedAt: record2.activatedAt,
|
|
17421
|
+
manifestUrl: record2.manifestUrl,
|
|
17422
|
+
...previousVersion ? {
|
|
17423
|
+
previousVersion
|
|
17424
|
+
} : {},
|
|
17425
|
+
knowledge: record2.knowledge,
|
|
17426
|
+
skills: record2.skills
|
|
17427
|
+
};
|
|
17428
|
+
}
|
|
17429
|
+
function validDate(value) {
|
|
17430
|
+
return typeof value === "string" && value.length > 0 && Number.isFinite(Date.parse(value));
|
|
17431
|
+
}
|
|
17432
|
+
var POINTER_MAX_BYTES, VERSION_PATTERN;
|
|
17433
|
+
var init_paths2 = __esm(() => {
|
|
17434
|
+
init_paths();
|
|
17435
|
+
init_private_path();
|
|
17436
|
+
init_file_read();
|
|
17437
|
+
POINTER_MAX_BYTES = 64 * 1024;
|
|
17438
|
+
VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
17439
|
+
});
|
|
17440
|
+
|
|
17296
17441
|
// src/agent-skills/registry.ts
|
|
17297
17442
|
import { createHash as createHash5 } from "crypto";
|
|
17298
|
-
import { existsSync as
|
|
17443
|
+
import { existsSync as existsSync9, readdirSync as readdirSync3, realpathSync as realpathSync2, statSync as statSync3 } from "fs";
|
|
17299
17444
|
import { homedir as homedir4 } from "os";
|
|
17300
|
-
import { delimiter, isAbsolute as
|
|
17445
|
+
import { delimiter, isAbsolute as isAbsolute5, join as join14, relative as relative4, resolve as resolve8, sep as sep2 } from "path";
|
|
17301
17446
|
function discoverSkills(options = {}) {
|
|
17302
17447
|
const diagnostics = [];
|
|
17303
17448
|
const selected = new Map;
|
|
@@ -17352,7 +17497,7 @@ function loadSkill(name, options = {}) {
|
|
|
17352
17497
|
const resourcePath = normalizeResourcePath(options.resource);
|
|
17353
17498
|
if (!resourcePath || !skill.resources.includes(resourcePath))
|
|
17354
17499
|
return;
|
|
17355
|
-
const absolute =
|
|
17500
|
+
const absolute = resolve8(skill.directory, resourcePath);
|
|
17356
17501
|
const canonical = realpathSync2(absolute);
|
|
17357
17502
|
if (!inside(skill.directory, canonical))
|
|
17358
17503
|
return;
|
|
@@ -17393,28 +17538,35 @@ function skillRoots(options) {
|
|
|
17393
17538
|
source: "builtin",
|
|
17394
17539
|
priority: 0
|
|
17395
17540
|
}];
|
|
17541
|
+
const content = activeContentSkillsDir();
|
|
17542
|
+
if (content)
|
|
17543
|
+
roots.push({
|
|
17544
|
+
path: content,
|
|
17545
|
+
source: "content",
|
|
17546
|
+
priority: 5
|
|
17547
|
+
});
|
|
17396
17548
|
if (options.includeUser !== false)
|
|
17397
17549
|
roots.push({
|
|
17398
|
-
path:
|
|
17550
|
+
path: join14(homedir4(), ".agents", "skills"),
|
|
17399
17551
|
source: "user",
|
|
17400
17552
|
priority: 10
|
|
17401
17553
|
});
|
|
17402
17554
|
const environmentRoots = [...process.env.FARAI_SKILLS_DIR?.split(delimiter) ?? [], ...options.extraRoots ?? []].map((path) => path.trim()).filter(Boolean);
|
|
17403
17555
|
for (const path of environmentRoots)
|
|
17404
17556
|
roots.push({
|
|
17405
|
-
path:
|
|
17557
|
+
path: resolve8(path),
|
|
17406
17558
|
source: "environment",
|
|
17407
17559
|
priority: 20
|
|
17408
17560
|
});
|
|
17409
17561
|
if (options.workspace)
|
|
17410
17562
|
roots.push({
|
|
17411
|
-
path:
|
|
17563
|
+
path: join14(resolve8(options.workspace), ".agents", "skills"),
|
|
17412
17564
|
source: "project",
|
|
17413
17565
|
priority: 30
|
|
17414
17566
|
});
|
|
17415
17567
|
const seen = new Set;
|
|
17416
17568
|
return roots.filter((root) => {
|
|
17417
|
-
const key =
|
|
17569
|
+
const key = resolve8(root.path);
|
|
17418
17570
|
if (seen.has(key))
|
|
17419
17571
|
return false;
|
|
17420
17572
|
seen.add(key);
|
|
@@ -17422,7 +17574,7 @@ function skillRoots(options) {
|
|
|
17422
17574
|
});
|
|
17423
17575
|
}
|
|
17424
17576
|
function scanRoot(root, diagnostics) {
|
|
17425
|
-
if (!
|
|
17577
|
+
if (!existsSync9(root.path))
|
|
17426
17578
|
return [];
|
|
17427
17579
|
let entries;
|
|
17428
17580
|
try {
|
|
@@ -17442,9 +17594,9 @@ function scanRoot(root, diagnostics) {
|
|
|
17442
17594
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
17443
17595
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
17444
17596
|
continue;
|
|
17445
|
-
const directory =
|
|
17446
|
-
const file =
|
|
17447
|
-
if (!
|
|
17597
|
+
const directory = join14(root.path, entry.name);
|
|
17598
|
+
const file = join14(directory, "SKILL.md");
|
|
17599
|
+
if (!existsSync9(file))
|
|
17448
17600
|
continue;
|
|
17449
17601
|
const parsed = parseSkill(file, directory, entry.name, root, diagnostics);
|
|
17450
17602
|
if (parsed)
|
|
@@ -17453,8 +17605,8 @@ function scanRoot(root, diagnostics) {
|
|
|
17453
17605
|
return skills;
|
|
17454
17606
|
}
|
|
17455
17607
|
function resolveBuiltinSkillDir() {
|
|
17456
|
-
const candidates = [
|
|
17457
|
-
return candidates.find((candidate) =>
|
|
17608
|
+
const candidates = [join14(import.meta.dir, "library"), join14(import.meta.dir, "..", "..", "src", "agent-skills", "library")];
|
|
17609
|
+
return candidates.find((candidate) => existsSync9(candidate)) ?? candidates[0];
|
|
17458
17610
|
}
|
|
17459
17611
|
function parseSkill(file, directory, directoryName, root, diagnostics) {
|
|
17460
17612
|
let raw;
|
|
@@ -17589,7 +17741,7 @@ function listResources(directory, diagnostics) {
|
|
|
17589
17741
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
17590
17742
|
if (resources.length >= MAX_RESOURCES || entry.name.startsWith("."))
|
|
17591
17743
|
continue;
|
|
17592
|
-
const path =
|
|
17744
|
+
const path = join14(current, entry.name);
|
|
17593
17745
|
let canonical;
|
|
17594
17746
|
try {
|
|
17595
17747
|
canonical = realpathSync2(path);
|
|
@@ -17600,7 +17752,7 @@ function listResources(directory, diagnostics) {
|
|
|
17600
17752
|
continue;
|
|
17601
17753
|
if (entry.isDirectory())
|
|
17602
17754
|
visit(canonical);
|
|
17603
|
-
else if ((entry.isFile() || entry.isSymbolicLink()) && canonical !==
|
|
17755
|
+
else if ((entry.isFile() || entry.isSymbolicLink()) && canonical !== join14(directory, "SKILL.md")) {
|
|
17604
17756
|
resources.push(relative4(directory, canonical).split(sep2).join("/"));
|
|
17605
17757
|
}
|
|
17606
17758
|
}
|
|
@@ -17642,7 +17794,7 @@ function optionalScalar(value) {
|
|
|
17642
17794
|
}
|
|
17643
17795
|
function normalizeResourcePath(path) {
|
|
17644
17796
|
const trimmed = path.trim().replaceAll("\\", "/");
|
|
17645
|
-
if (!trimmed ||
|
|
17797
|
+
if (!trimmed || isAbsolute5(trimmed) || trimmed.includes("\x00"))
|
|
17646
17798
|
return;
|
|
17647
17799
|
const normalized = trimmed.split("/").filter((part) => part && part !== ".").join("/");
|
|
17648
17800
|
if (!normalized || normalized.split("/").includes(".."))
|
|
@@ -17651,7 +17803,7 @@ function normalizeResourcePath(path) {
|
|
|
17651
17803
|
}
|
|
17652
17804
|
function inside(directory, path) {
|
|
17653
17805
|
const rel = relative4(realpathSync2(directory), path);
|
|
17654
|
-
return rel === "" || !rel.startsWith(`..${sep2}`) && rel !== ".." && !
|
|
17806
|
+
return rel === "" || !rel.startsWith(`..${sep2}`) && rel !== ".." && !isAbsolute5(rel);
|
|
17655
17807
|
}
|
|
17656
17808
|
function compactText(value, max) {
|
|
17657
17809
|
const compact = value.replace(/\s+/g, " ").trim();
|
|
@@ -17663,6 +17815,7 @@ function errorMessage(error) {
|
|
|
17663
17815
|
var BUILTIN_DIR, MAX_SKILL_BYTES, RECOMMENDED_SKILL_BYTES, MAX_RESOURCE_BYTES, MAX_RESOURCES = 256, NAME_PATTERN;
|
|
17664
17816
|
var init_registry2 = __esm(() => {
|
|
17665
17817
|
init_file_read();
|
|
17818
|
+
init_paths2();
|
|
17666
17819
|
BUILTIN_DIR = resolveBuiltinSkillDir();
|
|
17667
17820
|
MAX_SKILL_BYTES = 64 * 1024;
|
|
17668
17821
|
RECOMMENDED_SKILL_BYTES = 20 * 1024;
|
|
@@ -17798,8 +17951,8 @@ var init_global_config = __esm(() => {
|
|
|
17798
17951
|
|
|
17799
17952
|
// src/agent-core/context-builder.ts
|
|
17800
17953
|
import { execFileSync } from "child_process";
|
|
17801
|
-
import { existsSync as
|
|
17802
|
-
import { isAbsolute as
|
|
17954
|
+
import { existsSync as existsSync10, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
|
|
17955
|
+
import { isAbsolute as isAbsolute6, join as join15, normalize as normalize2, relative as relative5 } from "path";
|
|
17803
17956
|
|
|
17804
17957
|
class ContextBuilderCache {
|
|
17805
17958
|
workspaceFiles = new Map;
|
|
@@ -17831,7 +17984,7 @@ class ContextBuilderCache {
|
|
|
17831
17984
|
loadInstructionFragments(workspace, referencedPaths = []) {
|
|
17832
17985
|
const dirs = instructionCandidateDirs(workspace, referencedPaths);
|
|
17833
17986
|
const key = `${workspace}\x00${dirs.join("\x00")}`;
|
|
17834
|
-
const fingerprint = dirs.flatMap((dir) => INSTRUCTION_FILENAMES.map((filename) => statFingerprint(
|
|
17987
|
+
const fingerprint = dirs.flatMap((dir) => INSTRUCTION_FILENAMES.map((filename) => statFingerprint(join15(dir, filename)))).join("|");
|
|
17835
17988
|
const cached = this.instructions.get(key);
|
|
17836
17989
|
if (cached?.fingerprint === fingerprint)
|
|
17837
17990
|
return cached.fragments;
|
|
@@ -17852,7 +18005,7 @@ class ContextBuilderCache {
|
|
|
17852
18005
|
extractSymbols(workspace, file) {
|
|
17853
18006
|
if (!/\.(?:[cm]?[jt]sx?|py|go|rs)$/i.test(file))
|
|
17854
18007
|
return [];
|
|
17855
|
-
const path =
|
|
18008
|
+
const path = join15(workspace, file);
|
|
17856
18009
|
const fingerprint = statFingerprint(path);
|
|
17857
18010
|
const cached = this.symbols.get(path);
|
|
17858
18011
|
if (cached?.fingerprint === fingerprint)
|
|
@@ -17913,7 +18066,7 @@ function collectWorkspaceFilesFromFs(workspace) {
|
|
|
17913
18066
|
break;
|
|
17914
18067
|
if (entry.name.startsWith(".") || FALLBACK_IGNORED_DIRECTORIES.has(entry.name))
|
|
17915
18068
|
continue;
|
|
17916
|
-
const absolute =
|
|
18069
|
+
const absolute = join15(directory, entry.name);
|
|
17917
18070
|
if (entry.isDirectory())
|
|
17918
18071
|
pending.push(absolute);
|
|
17919
18072
|
else if (entry.isFile())
|
|
@@ -18006,8 +18159,8 @@ function fragment(input) {
|
|
|
18006
18159
|
}
|
|
18007
18160
|
function readFirstInstructionFile(dir) {
|
|
18008
18161
|
for (const filename of INSTRUCTION_FILENAMES) {
|
|
18009
|
-
const path =
|
|
18010
|
-
if (!
|
|
18162
|
+
const path = join15(dir, filename);
|
|
18163
|
+
if (!existsSync10(path))
|
|
18011
18164
|
continue;
|
|
18012
18165
|
try {
|
|
18013
18166
|
const body = readFileTextPrefixSync(path, PROJECT_INSTRUCTIONS_MAX_BYTES, "project instructions").text.trim();
|
|
@@ -18035,7 +18188,7 @@ function referencedInstructionDirs(workspace, referencedPaths) {
|
|
|
18035
18188
|
parts.pop();
|
|
18036
18189
|
let current = workspace;
|
|
18037
18190
|
for (const part of parts) {
|
|
18038
|
-
current =
|
|
18191
|
+
current = join15(current, part);
|
|
18039
18192
|
if (seen.has(current))
|
|
18040
18193
|
continue;
|
|
18041
18194
|
seen.add(current);
|
|
@@ -18048,7 +18201,7 @@ function instructionCandidateDirs(workspace, referencedPaths) {
|
|
|
18048
18201
|
return [...new Set([...globalInstructionDirs(), workspace, ...referencedInstructionDirs(workspace, referencedPaths)])];
|
|
18049
18202
|
}
|
|
18050
18203
|
function workspaceFileFingerprint(workspace) {
|
|
18051
|
-
return `${statFingerprint(workspace)}|${statFingerprint(
|
|
18204
|
+
return `${statFingerprint(workspace)}|${statFingerprint(join15(workspace, ".git", "index"))}`;
|
|
18052
18205
|
}
|
|
18053
18206
|
function statFingerprint(path) {
|
|
18054
18207
|
try {
|
|
@@ -18064,7 +18217,7 @@ function validWorkspaceFiles(workspace, paths) {
|
|
|
18064
18217
|
const rel = workspaceRelativeReference(workspace, value);
|
|
18065
18218
|
if (!rel)
|
|
18066
18219
|
continue;
|
|
18067
|
-
const absolute =
|
|
18220
|
+
const absolute = join15(workspace, rel);
|
|
18068
18221
|
try {
|
|
18069
18222
|
if (statSync4(absolute).isFile())
|
|
18070
18223
|
files.push(rel);
|
|
@@ -18078,9 +18231,9 @@ function workspaceRelativeReference(workspace, value) {
|
|
|
18078
18231
|
return;
|
|
18079
18232
|
const containerPrefix = `${normalize2("/workspace")}/`;
|
|
18080
18233
|
const worktreeMatch = normalized.match(/^[/\\]worktrees[/\\][^/\\]+[/\\](.+)$/);
|
|
18081
|
-
const absolute = normalized.startsWith(containerPrefix) ? normalize2(
|
|
18234
|
+
const absolute = normalized.startsWith(containerPrefix) ? normalize2(join15(workspace, normalized.slice(containerPrefix.length))) : worktreeMatch ? normalize2(join15(workspace, worktreeMatch[1])) : isAbsolute6(normalized) ? normalized : normalize2(join15(workspace, normalized.replace(/^\/+/, "")));
|
|
18082
18235
|
const rel = relative5(workspace, absolute);
|
|
18083
|
-
if (!rel || rel.startsWith("..") ||
|
|
18236
|
+
if (!rel || rel.startsWith("..") || isAbsolute6(rel))
|
|
18084
18237
|
return;
|
|
18085
18238
|
return rel;
|
|
18086
18239
|
}
|
|
@@ -18822,7 +18975,7 @@ class HostProcessBackend {
|
|
|
18822
18975
|
}
|
|
18823
18976
|
async runOnce(command, opts) {
|
|
18824
18977
|
const started = Date.now();
|
|
18825
|
-
return await new Promise((
|
|
18978
|
+
return await new Promise((resolve9) => {
|
|
18826
18979
|
const child = spawn4("bash", ["-lc", command], {
|
|
18827
18980
|
cwd: this.cwd,
|
|
18828
18981
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -18842,7 +18995,7 @@ class HostProcessBackend {
|
|
|
18842
18995
|
const {
|
|
18843
18996
|
sessionId
|
|
18844
18997
|
} = sessions.register(child);
|
|
18845
|
-
|
|
18998
|
+
resolve9({
|
|
18846
18999
|
exitCode: null,
|
|
18847
19000
|
stdout: stdout.text(),
|
|
18848
19001
|
stderr: stderr.text(),
|
|
@@ -18882,7 +19035,7 @@ class HostProcessBackend {
|
|
|
18882
19035
|
return;
|
|
18883
19036
|
settled = true;
|
|
18884
19037
|
stderr.push(error.message);
|
|
18885
|
-
|
|
19038
|
+
resolve9({
|
|
18886
19039
|
exitCode: 127,
|
|
18887
19040
|
stdout: stdout.text(),
|
|
18888
19041
|
stderr: stderr.text(),
|
|
@@ -18897,7 +19050,7 @@ class HostProcessBackend {
|
|
|
18897
19050
|
if (converted || settled)
|
|
18898
19051
|
return;
|
|
18899
19052
|
settled = true;
|
|
18900
|
-
|
|
19053
|
+
resolve9({
|
|
18901
19054
|
exitCode,
|
|
18902
19055
|
stdout: stdout.text(),
|
|
18903
19056
|
stderr: stderr.text(),
|
|
@@ -19868,17 +20021,17 @@ var init_next_action = __esm(() => {
|
|
|
19868
20021
|
});
|
|
19869
20022
|
|
|
19870
20023
|
// src/agent-core/subagents/lanes.ts
|
|
19871
|
-
import { existsSync as
|
|
19872
|
-
import { join as
|
|
20024
|
+
import { existsSync as existsSync11 } from "fs";
|
|
20025
|
+
import { join as join16 } from "path";
|
|
19873
20026
|
function laneConfigPaths(workspace) {
|
|
19874
20027
|
if (false)
|
|
19875
20028
|
;
|
|
19876
|
-
return [
|
|
20029
|
+
return [join16(localFaraiDir(), "agents.json"), join16(workspace, ".farai", "agents.json")];
|
|
19877
20030
|
}
|
|
19878
20031
|
function loadLanes(workspace) {
|
|
19879
20032
|
const merged = new Map(BUILTIN_LANES.map((lane) => [lane.id, structuredClone(lane)]));
|
|
19880
20033
|
for (const path of laneConfigPaths(workspace)) {
|
|
19881
|
-
if (!
|
|
20034
|
+
if (!existsSync11(path))
|
|
19882
20035
|
continue;
|
|
19883
20036
|
try {
|
|
19884
20037
|
const parsed = JSON.parse(readBoundedFileTextSync(path, LANE_CONFIG_MAX_BYTES, "agent lane config"));
|
|
@@ -20593,8 +20746,8 @@ class BrowserContextManager {
|
|
|
20593
20746
|
const config = isolatedBrowserConfig(base, contextId);
|
|
20594
20747
|
let resolveReady = () => {};
|
|
20595
20748
|
let rejectReady = (_error) => {};
|
|
20596
|
-
const ready = new Promise((
|
|
20597
|
-
resolveReady =
|
|
20749
|
+
const ready = new Promise((resolve9, reject) => {
|
|
20750
|
+
resolveReady = resolve9;
|
|
20598
20751
|
rejectReady = reject;
|
|
20599
20752
|
});
|
|
20600
20753
|
ready.catch(() => {});
|
|
@@ -20787,9 +20940,9 @@ class AsyncMutex {
|
|
|
20787
20940
|
this.locked = true;
|
|
20788
20941
|
return Promise.resolve();
|
|
20789
20942
|
}
|
|
20790
|
-
return new Promise((
|
|
20943
|
+
return new Promise((resolve9, reject) => {
|
|
20791
20944
|
const waiter = {
|
|
20792
|
-
resolve:
|
|
20945
|
+
resolve: resolve9,
|
|
20793
20946
|
reject,
|
|
20794
20947
|
...signal ? {
|
|
20795
20948
|
signal
|
|
@@ -20825,7 +20978,7 @@ async function waitForSignal(promise, signal) {
|
|
|
20825
20978
|
return await promise;
|
|
20826
20979
|
if (signal.aborted)
|
|
20827
20980
|
throw signal.reason ?? new Error("Browser context operation cancelled");
|
|
20828
|
-
return await new Promise((
|
|
20981
|
+
return await new Promise((resolve9, reject) => {
|
|
20829
20982
|
const abort = () => {
|
|
20830
20983
|
cleanup();
|
|
20831
20984
|
reject(signal.reason ?? new Error("Browser context operation cancelled"));
|
|
@@ -20836,7 +20989,7 @@ async function waitForSignal(promise, signal) {
|
|
|
20836
20989
|
});
|
|
20837
20990
|
promise.then((value) => {
|
|
20838
20991
|
cleanup();
|
|
20839
|
-
|
|
20992
|
+
resolve9(value);
|
|
20840
20993
|
}, (error) => {
|
|
20841
20994
|
cleanup();
|
|
20842
20995
|
reject(error);
|
|
@@ -22247,14 +22400,14 @@ var init_shared2 = __esm(() => {
|
|
|
22247
22400
|
// src/agent-tools/web/web-fetch.ts
|
|
22248
22401
|
import { mkdirSync as mkdirSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
22249
22402
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
22250
|
-
import { join as
|
|
22403
|
+
import { join as join17 } from "path";
|
|
22251
22404
|
async function extractPdf(context, bytes) {
|
|
22252
|
-
const directory =
|
|
22405
|
+
const directory = join17(context.workspace, ".farai", "tmp");
|
|
22253
22406
|
mkdirSync5(directory, {
|
|
22254
22407
|
recursive: true
|
|
22255
22408
|
});
|
|
22256
22409
|
const name = `web-fetch-${randomUUID3()}.pdf`;
|
|
22257
|
-
const path =
|
|
22410
|
+
const path = join17(directory, name);
|
|
22258
22411
|
atomicWriteFile(path, bytes, 384);
|
|
22259
22412
|
try {
|
|
22260
22413
|
const backendPath = context.executionBackend?.kind === "host" ? path : `/workspace/.farai/tmp/${name}`;
|
|
@@ -23276,10 +23429,10 @@ var init_worktree = __esm(() => {
|
|
|
23276
23429
|
});
|
|
23277
23430
|
|
|
23278
23431
|
// src/agent-tools/services/mitmproxy/flows.ts
|
|
23279
|
-
import { existsSync as
|
|
23432
|
+
import { existsSync as existsSync12 } from "fs";
|
|
23280
23433
|
import { isIP as isIP2 } from "net";
|
|
23281
23434
|
async function readProxyFlows(file, query = {}) {
|
|
23282
|
-
if (!
|
|
23435
|
+
if (!existsSync12(file))
|
|
23283
23436
|
return [];
|
|
23284
23437
|
const limit = proxyFlowLimit(query.limit);
|
|
23285
23438
|
const flows = [];
|
|
@@ -23311,7 +23464,7 @@ async function readProxyFlows(file, query = {}) {
|
|
|
23311
23464
|
return flows;
|
|
23312
23465
|
}
|
|
23313
23466
|
async function readProxyFlowDetail(file, id2) {
|
|
23314
|
-
if (!
|
|
23467
|
+
if (!existsSync12(file))
|
|
23315
23468
|
return;
|
|
23316
23469
|
let found;
|
|
23317
23470
|
await forEachFileLine(file, {
|
|
@@ -24947,7 +25100,7 @@ function detailMatches(detail, options) {
|
|
|
24947
25100
|
return !options.body || detail.text.toLowerCase().includes(options.body.toLowerCase());
|
|
24948
25101
|
}
|
|
24949
25102
|
async function waitForMailboxChange(client, timeoutMs, signal) {
|
|
24950
|
-
await new Promise((
|
|
25103
|
+
await new Promise((resolve9, reject) => {
|
|
24951
25104
|
let settled = false;
|
|
24952
25105
|
const finish = (error) => {
|
|
24953
25106
|
if (settled)
|
|
@@ -24959,7 +25112,7 @@ async function waitForMailboxChange(client, timeoutMs, signal) {
|
|
|
24959
25112
|
if (error)
|
|
24960
25113
|
reject(error);
|
|
24961
25114
|
else
|
|
24962
|
-
|
|
25115
|
+
resolve9();
|
|
24963
25116
|
};
|
|
24964
25117
|
const onAbort = () => finish(signal?.reason ?? new Error("email wait cancelled"));
|
|
24965
25118
|
const onExists = () => finish();
|
|
@@ -24976,8 +25129,8 @@ async function waitForMailboxChange(client, timeoutMs, signal) {
|
|
|
24976
25129
|
async function closeImap(client) {
|
|
24977
25130
|
let timer;
|
|
24978
25131
|
try {
|
|
24979
|
-
const closed = await Promise.race([client.logout().then(() => true, () => false), new Promise((
|
|
24980
|
-
timer = setTimeout(() =>
|
|
25132
|
+
const closed = await Promise.race([client.logout().then(() => true, () => false), new Promise((resolve9) => {
|
|
25133
|
+
timer = setTimeout(() => resolve9(false), IMAP_LOGOUT_TIMEOUT_MS);
|
|
24981
25134
|
timer.unref?.();
|
|
24982
25135
|
})]);
|
|
24983
25136
|
if (!closed)
|
|
@@ -25001,7 +25154,7 @@ async function withAbort(promise, signal) {
|
|
|
25001
25154
|
signal?.throwIfAborted();
|
|
25002
25155
|
if (!signal)
|
|
25003
25156
|
return await promise;
|
|
25004
|
-
return await new Promise((
|
|
25157
|
+
return await new Promise((resolve9, reject) => {
|
|
25005
25158
|
const onAbort = () => {
|
|
25006
25159
|
signal.removeEventListener("abort", onAbort);
|
|
25007
25160
|
reject(signal.reason ?? new Error("operation cancelled"));
|
|
@@ -25011,7 +25164,7 @@ async function withAbort(promise, signal) {
|
|
|
25011
25164
|
});
|
|
25012
25165
|
promise.then((value) => {
|
|
25013
25166
|
signal.removeEventListener("abort", onAbort);
|
|
25014
|
-
|
|
25167
|
+
resolve9(value);
|
|
25015
25168
|
}, (error) => {
|
|
25016
25169
|
signal.removeEventListener("abort", onAbort);
|
|
25017
25170
|
reject(error);
|
|
@@ -25994,7 +26147,7 @@ function toActivity2(entry) {
|
|
|
25994
26147
|
};
|
|
25995
26148
|
}
|
|
25996
26149
|
function delay2(ms, signal) {
|
|
25997
|
-
return new Promise((
|
|
26150
|
+
return new Promise((resolve9, reject) => {
|
|
25998
26151
|
let settled = false;
|
|
25999
26152
|
const finish = (error) => {
|
|
26000
26153
|
if (settled)
|
|
@@ -26005,7 +26158,7 @@ function delay2(ms, signal) {
|
|
|
26005
26158
|
if (error)
|
|
26006
26159
|
reject(error);
|
|
26007
26160
|
else
|
|
26008
|
-
|
|
26161
|
+
resolve9();
|
|
26009
26162
|
};
|
|
26010
26163
|
const abort = () => finish(signal?.reason ?? new Error("email wait cancelled"));
|
|
26011
26164
|
const timer = setTimeout(() => finish(), ms);
|
|
@@ -26107,6 +26260,9 @@ function emailMessageResult(action, emailId, address, message) {
|
|
|
26107
26260
|
}
|
|
26108
26261
|
};
|
|
26109
26262
|
}
|
|
26263
|
+
function formatWaitCriteria(match) {
|
|
26264
|
+
return [match.from ? `sender containing ${JSON.stringify(match.from)}` : undefined, match.subject ? `subject containing ${JSON.stringify(match.subject)}` : undefined, match.body ? `body containing ${JSON.stringify(match.body)}` : undefined].filter((value) => value !== undefined).join(" and ");
|
|
26265
|
+
}
|
|
26110
26266
|
function formatResource(resource) {
|
|
26111
26267
|
return [`${resource.label} \xB7 ${resource.address}`, `id: ${resource.id}`, [resource.type, resource.provider, resource.status, ...resource.roles].join(" \xB7 ")].join(`
|
|
26112
26268
|
`);
|
|
@@ -26323,7 +26479,7 @@ var init_email = __esm(() => {
|
|
|
26323
26479
|
};
|
|
26324
26480
|
emailWaitTool = {
|
|
26325
26481
|
name: "email_wait",
|
|
26326
|
-
description: "Wait for a matching message in one email resource using its exact Farai UUID. Use this for verification links, OTP codes, password resets, and asynchronous registrations.
|
|
26482
|
+
description: "Wait for a matching message in one email resource using its exact Farai UUID. Use this for verification links, OTP codes, password resets, and asynchronous registrations. Every supplied from, subject, and body filter is a strict case-insensitive substring condition and all supplied filters must match. Do not guess a subject or sender; omit filters when any message in an isolated temporary inbox is acceptable. The returned message UUID can be passed directly to email_read.",
|
|
26327
26483
|
inputSchema: {
|
|
26328
26484
|
type: "object",
|
|
26329
26485
|
required: ["emailId"],
|
|
@@ -26334,15 +26490,15 @@ var init_email = __esm(() => {
|
|
|
26334
26490
|
},
|
|
26335
26491
|
from: {
|
|
26336
26492
|
type: "string",
|
|
26337
|
-
description: "
|
|
26493
|
+
description: "Strict case-insensitive sender substring; omit when the sender is not known"
|
|
26338
26494
|
},
|
|
26339
26495
|
subject: {
|
|
26340
26496
|
type: "string",
|
|
26341
|
-
description: "
|
|
26497
|
+
description: "Strict case-insensitive subject substring; omit rather than guessing the subject"
|
|
26342
26498
|
},
|
|
26343
26499
|
body: {
|
|
26344
26500
|
type: "string",
|
|
26345
|
-
description: "
|
|
26501
|
+
description: "Strict case-insensitive message-body substring; use only when the expected body text is known"
|
|
26346
26502
|
},
|
|
26347
26503
|
unreadOnly: {
|
|
26348
26504
|
type: "boolean",
|
|
@@ -26390,16 +26546,20 @@ var init_email = __esm(() => {
|
|
|
26390
26546
|
} : {}
|
|
26391
26547
|
}, context.signal);
|
|
26392
26548
|
if (!providerMessage) {
|
|
26549
|
+
const criteria = formatWaitCriteria(match);
|
|
26393
26550
|
return {
|
|
26394
26551
|
ok: true,
|
|
26395
26552
|
summary: `no matching email arrived in ${source.address} within ${Math.round(timeoutMs / 1000)} seconds`,
|
|
26396
|
-
output: "no
|
|
26553
|
+
output: criteria ? `no message matched ${criteria} before the timeout` : "no email arrived before the timeout",
|
|
26397
26554
|
metadata: {
|
|
26398
26555
|
emailAction: "wait",
|
|
26399
26556
|
emailId,
|
|
26400
26557
|
address: source.address,
|
|
26401
26558
|
source: source.kind,
|
|
26402
|
-
timedOut: true
|
|
26559
|
+
timedOut: true,
|
|
26560
|
+
...criteria ? {
|
|
26561
|
+
criteria
|
|
26562
|
+
} : {}
|
|
26403
26563
|
}
|
|
26404
26564
|
};
|
|
26405
26565
|
}
|
|
@@ -27534,8 +27694,8 @@ var init_model_profiles = __esm(() => {
|
|
|
27534
27694
|
});
|
|
27535
27695
|
|
|
27536
27696
|
// src/agent-core/model-catalog.ts
|
|
27537
|
-
import { existsSync as
|
|
27538
|
-
import { dirname as dirname7, join as
|
|
27697
|
+
import { existsSync as existsSync13 } from "fs";
|
|
27698
|
+
import { dirname as dirname7, join as join18 } from "path";
|
|
27539
27699
|
async function buildModelCatalog(workspace, profiles = loadModelProfiles(workspace)) {
|
|
27540
27700
|
const providers = [];
|
|
27541
27701
|
const models = [];
|
|
@@ -28111,7 +28271,7 @@ async function fetchModelsDevCatalog(fetchImpl = globalThis.fetch, timeoutMs = M
|
|
|
28111
28271
|
function readCachedModelsDevCatalog() {
|
|
28112
28272
|
try {
|
|
28113
28273
|
const path = modelsDevCachePath();
|
|
28114
|
-
if (!
|
|
28274
|
+
if (!existsSync13(path))
|
|
28115
28275
|
return;
|
|
28116
28276
|
ensurePrivateDirectory(dirname7(path), "model cache directory");
|
|
28117
28277
|
ensurePrivateRegularFileIfExists(path, "models.dev cache");
|
|
@@ -28163,7 +28323,7 @@ function ensureConcrete(resolved) {
|
|
|
28163
28323
|
return resolved;
|
|
28164
28324
|
}
|
|
28165
28325
|
function modelsDevCachePath() {
|
|
28166
|
-
return
|
|
28326
|
+
return join18(globalDataDir(), "cache", "models-dev.json");
|
|
28167
28327
|
}
|
|
28168
28328
|
var DEFAULT_PROVIDER_ID = "default", OPENCODE_PROVIDER_ID, OPENCODE_DEFAULT_MODEL_ID, OPENCODE_PUBLIC_API_KEY, MODELS_DEV_URL = "https://models.dev/api.json", MODELS_DEV_CACHE_TTL_MS, MODELS_DEV_STALE_TTL_MS, MODELS_DEV_FETCH_TIMEOUT_MS = 4000, MODELS_DEV_MAX_BYTES, RECENT_MODEL_LIMIT = 12, modelsDevRefreshes;
|
|
28169
28329
|
var init_model_catalog = __esm(() => {
|
|
@@ -30498,17 +30658,17 @@ var init_compaction = __esm(() => {
|
|
|
30498
30658
|
});
|
|
30499
30659
|
|
|
30500
30660
|
// src/agent-core/hooks/host.ts
|
|
30501
|
-
import { existsSync as
|
|
30502
|
-
import { join as
|
|
30661
|
+
import { existsSync as existsSync14 } from "fs";
|
|
30662
|
+
import { join as join19 } from "path";
|
|
30503
30663
|
function hookConfigPaths(workspace) {
|
|
30504
30664
|
if (false)
|
|
30505
30665
|
;
|
|
30506
|
-
return [
|
|
30666
|
+
return [join19(localFaraiDir(), "hooks.json"), join19(workspace, ".farai", "hooks.json")];
|
|
30507
30667
|
}
|
|
30508
30668
|
function loadHooks(workspace) {
|
|
30509
30669
|
const hooks = [];
|
|
30510
30670
|
for (const path of hookConfigPaths(workspace)) {
|
|
30511
|
-
if (!
|
|
30671
|
+
if (!existsSync14(path))
|
|
30512
30672
|
continue;
|
|
30513
30673
|
try {
|
|
30514
30674
|
const parsed = JSON.parse(readBoundedFileTextSync(path, HOOK_CONFIG_MAX_BYTES, "hook config"));
|
|
@@ -30632,7 +30792,7 @@ class SubagentGate {
|
|
|
30632
30792
|
idle() {
|
|
30633
30793
|
if (this.active === 0 && this.queue.length === 0)
|
|
30634
30794
|
return Promise.resolve();
|
|
30635
|
-
return new Promise((
|
|
30795
|
+
return new Promise((resolve9) => this.idleResolvers.add(resolve9));
|
|
30636
30796
|
}
|
|
30637
30797
|
async run(work, signal) {
|
|
30638
30798
|
const release = await this.acquire(signal);
|
|
@@ -30644,13 +30804,13 @@ class SubagentGate {
|
|
|
30644
30804
|
}
|
|
30645
30805
|
}
|
|
30646
30806
|
acquire(signal) {
|
|
30647
|
-
return new Promise((
|
|
30807
|
+
return new Promise((resolve9, reject) => {
|
|
30648
30808
|
if (signal?.aborted) {
|
|
30649
30809
|
reject(signal.reason ?? new Error("subagent task cancelled before start"));
|
|
30650
30810
|
return;
|
|
30651
30811
|
}
|
|
30652
30812
|
const waiter = {
|
|
30653
|
-
resolve:
|
|
30813
|
+
resolve: resolve9,
|
|
30654
30814
|
reject,
|
|
30655
30815
|
...signal ? {
|
|
30656
30816
|
signal
|
|
@@ -30697,8 +30857,8 @@ class SubagentGate {
|
|
|
30697
30857
|
notifyIdle() {
|
|
30698
30858
|
if (this.active !== 0 || this.queue.length !== 0)
|
|
30699
30859
|
return;
|
|
30700
|
-
for (const
|
|
30701
|
-
|
|
30860
|
+
for (const resolve9 of this.idleResolvers)
|
|
30861
|
+
resolve9();
|
|
30702
30862
|
this.idleResolvers.clear();
|
|
30703
30863
|
}
|
|
30704
30864
|
}
|
|
@@ -30712,10 +30872,10 @@ class SessionActor {
|
|
|
30712
30872
|
run(work) {
|
|
30713
30873
|
if (this.closed)
|
|
30714
30874
|
return Promise.reject(new Error("Session actor is closed"));
|
|
30715
|
-
return new Promise((
|
|
30875
|
+
return new Promise((resolve9, reject) => {
|
|
30716
30876
|
this.queue.push({
|
|
30717
30877
|
work,
|
|
30718
|
-
resolve: (value) =>
|
|
30878
|
+
resolve: (value) => resolve9(value),
|
|
30719
30879
|
reject
|
|
30720
30880
|
});
|
|
30721
30881
|
this.drain();
|
|
@@ -30727,7 +30887,7 @@ class SessionActor {
|
|
|
30727
30887
|
idle() {
|
|
30728
30888
|
if (!this.running && this.queue.length === 0)
|
|
30729
30889
|
return Promise.resolve();
|
|
30730
|
-
return new Promise((
|
|
30890
|
+
return new Promise((resolve9) => this.idleResolvers.add(resolve9));
|
|
30731
30891
|
}
|
|
30732
30892
|
close() {
|
|
30733
30893
|
if (this.closed)
|
|
@@ -30760,8 +30920,8 @@ class SessionActor {
|
|
|
30760
30920
|
resolveIdle() {
|
|
30761
30921
|
if (this.running || this.queue.length > 0)
|
|
30762
30922
|
return;
|
|
30763
|
-
for (const
|
|
30764
|
-
|
|
30923
|
+
for (const resolve9 of this.idleResolvers)
|
|
30924
|
+
resolve9();
|
|
30765
30925
|
this.idleResolvers.clear();
|
|
30766
30926
|
}
|
|
30767
30927
|
}
|
|
@@ -32875,7 +33035,7 @@ function rebuildFtsIndexes(db) {
|
|
|
32875
33035
|
var KNOWLEDGE_SCHEMA_VERSION = 2;
|
|
32876
33036
|
|
|
32877
33037
|
// src/agent-knowledge/store.ts
|
|
32878
|
-
import { existsSync as
|
|
33038
|
+
import { existsSync as existsSync15 } from "fs";
|
|
32879
33039
|
import { Database as Database3 } from "bun:sqlite";
|
|
32880
33040
|
|
|
32881
33041
|
class KnowledgeStore {
|
|
@@ -32884,7 +33044,7 @@ class KnowledgeStore {
|
|
|
32884
33044
|
this.create = create;
|
|
32885
33045
|
}
|
|
32886
33046
|
static openIfExists(path) {
|
|
32887
|
-
if (!
|
|
33047
|
+
if (!existsSync15(path))
|
|
32888
33048
|
return;
|
|
32889
33049
|
const store = new KnowledgeStore(path);
|
|
32890
33050
|
try {
|
|
@@ -33459,24 +33619,28 @@ var init_store = __esm(() => {
|
|
|
33459
33619
|
});
|
|
33460
33620
|
|
|
33461
33621
|
// src/agent-knowledge/paths.ts
|
|
33462
|
-
import { join as
|
|
33622
|
+
import { join as join20 } from "path";
|
|
33463
33623
|
function knowledgeDbPath() {
|
|
33464
|
-
return
|
|
33624
|
+
return activeContentKnowledgePath() ?? legacyKnowledgeDbPath();
|
|
33625
|
+
}
|
|
33626
|
+
function legacyKnowledgeDbPath() {
|
|
33627
|
+
return join20(localFaraiDir(), "knowledge.db");
|
|
33465
33628
|
}
|
|
33466
33629
|
function knowledgeRoot() {
|
|
33467
|
-
return process.env.FARAI_KNOWLEDGE_DIR ??
|
|
33630
|
+
return process.env.FARAI_KNOWLEDGE_DIR ?? join20(localFaraiDir(), "knowledge");
|
|
33468
33631
|
}
|
|
33469
33632
|
function packsDir() {
|
|
33470
|
-
return
|
|
33633
|
+
return join20(knowledgeRoot(), "packs");
|
|
33471
33634
|
}
|
|
33472
33635
|
function taxonomyDir() {
|
|
33473
|
-
return
|
|
33636
|
+
return join20(knowledgeRoot(), "taxonomy");
|
|
33474
33637
|
}
|
|
33475
33638
|
function cacheDir() {
|
|
33476
|
-
return
|
|
33639
|
+
return join20(localFaraiDir(), "knowledge-cache");
|
|
33477
33640
|
}
|
|
33478
|
-
var
|
|
33641
|
+
var init_paths3 = __esm(() => {
|
|
33479
33642
|
init_config();
|
|
33643
|
+
init_paths2();
|
|
33480
33644
|
});
|
|
33481
33645
|
|
|
33482
33646
|
// src/agent-core/model-pricing.ts
|
|
@@ -33510,14 +33674,14 @@ function nonNegative(value) {
|
|
|
33510
33674
|
}
|
|
33511
33675
|
|
|
33512
33676
|
// src/session-catalog.ts
|
|
33513
|
-
import { existsSync as
|
|
33514
|
-
import { join as
|
|
33677
|
+
import { existsSync as existsSync16, readdirSync as readdirSync5, rmSync as rmSync2 } from "fs";
|
|
33678
|
+
import { join as join21, resolve as resolve9 } from "path";
|
|
33515
33679
|
function recordSessionLocation(session) {
|
|
33516
33680
|
const directory = catalogDirectory();
|
|
33517
33681
|
ensurePrivateDirectory(directory, "session catalog directory");
|
|
33518
33682
|
const entry = {
|
|
33519
33683
|
id: session.id,
|
|
33520
|
-
workspace:
|
|
33684
|
+
workspace: resolve9(session.workspace),
|
|
33521
33685
|
...session.title ? {
|
|
33522
33686
|
title: session.title
|
|
33523
33687
|
} : {},
|
|
@@ -33526,13 +33690,13 @@ function recordSessionLocation(session) {
|
|
|
33526
33690
|
} : {},
|
|
33527
33691
|
updatedAt: session.updatedAt
|
|
33528
33692
|
};
|
|
33529
|
-
const path =
|
|
33693
|
+
const path = join21(directory, `${session.id}.json`);
|
|
33530
33694
|
ensurePrivateRegularFileIfExists(path, "session catalog entry");
|
|
33531
33695
|
atomicWriteFile(path, `${JSON.stringify(entry)}
|
|
33532
33696
|
`, 384);
|
|
33533
33697
|
}
|
|
33534
33698
|
function removeSessionLocation(sessionId) {
|
|
33535
|
-
rmSync2(
|
|
33699
|
+
rmSync2(join21(catalogDirectory(), `${sessionId}.json`), {
|
|
33536
33700
|
force: true
|
|
33537
33701
|
});
|
|
33538
33702
|
}
|
|
@@ -33552,7 +33716,7 @@ function resolveSessionLocation(query) {
|
|
|
33552
33716
|
}
|
|
33553
33717
|
function listSessionLocations() {
|
|
33554
33718
|
const directory = catalogDirectory();
|
|
33555
|
-
if (!
|
|
33719
|
+
if (!existsSync16(directory))
|
|
33556
33720
|
return [];
|
|
33557
33721
|
try {
|
|
33558
33722
|
ensurePrivateDirectory(directory, "session catalog directory");
|
|
@@ -33561,7 +33725,7 @@ function listSessionLocations() {
|
|
|
33561
33725
|
}
|
|
33562
33726
|
return readdirSync5(directory).filter((name) => name.endsWith(".json")).flatMap((name) => {
|
|
33563
33727
|
try {
|
|
33564
|
-
const path =
|
|
33728
|
+
const path = join21(directory, name);
|
|
33565
33729
|
ensurePrivateRegularFileIfExists(path, "session catalog entry");
|
|
33566
33730
|
const value = JSON.parse(readBoundedFileTextSyncNoFollow(path, SESSION_CATALOG_ENTRY_MAX_BYTES, "session catalog entry"));
|
|
33567
33731
|
if (typeof value.id !== "string" || typeof value.workspace !== "string" || typeof value.updatedAt !== "string")
|
|
@@ -33583,10 +33747,10 @@ function listSessionLocations() {
|
|
|
33583
33747
|
}).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
33584
33748
|
}
|
|
33585
33749
|
function catalogDirectory() {
|
|
33586
|
-
return
|
|
33750
|
+
return join21(localFaraiDir(), "sessions");
|
|
33587
33751
|
}
|
|
33588
33752
|
function sessionDatabaseExists(workspace) {
|
|
33589
|
-
return
|
|
33753
|
+
return existsSync16(join21(workspace, ".farai", "farai.db"));
|
|
33590
33754
|
}
|
|
33591
33755
|
var SESSION_CATALOG_ENTRY_MAX_BYTES;
|
|
33592
33756
|
var init_session_catalog = __esm(() => {
|
|
@@ -33622,7 +33786,7 @@ class SessionUserInputCoordinator {
|
|
|
33622
33786
|
expiresAt
|
|
33623
33787
|
} : {}
|
|
33624
33788
|
};
|
|
33625
|
-
return new Promise((
|
|
33789
|
+
return new Promise((resolve10, reject) => {
|
|
33626
33790
|
const detach = () => signal?.removeEventListener("abort", abort);
|
|
33627
33791
|
const abort = () => {
|
|
33628
33792
|
if (this.pending.get(sessionId)?.request.id !== request.id)
|
|
@@ -33639,7 +33803,7 @@ class SessionUserInputCoordinator {
|
|
|
33639
33803
|
request,
|
|
33640
33804
|
resolve: (answer) => {
|
|
33641
33805
|
detach();
|
|
33642
|
-
|
|
33806
|
+
resolve10(answer);
|
|
33643
33807
|
},
|
|
33644
33808
|
reject: (error) => {
|
|
33645
33809
|
detach();
|
|
@@ -33972,7 +34136,7 @@ class ToolExecutionGate {
|
|
|
33972
34136
|
idle() {
|
|
33973
34137
|
if (this.states.size === 0)
|
|
33974
34138
|
return Promise.resolve();
|
|
33975
|
-
return new Promise((
|
|
34139
|
+
return new Promise((resolve10) => this.idleResolvers.add(resolve10));
|
|
33976
34140
|
}
|
|
33977
34141
|
async run(key, parallel, fn, signal) {
|
|
33978
34142
|
const release = await this.acquire(key, parallel ? "read" : "write", signal);
|
|
@@ -33984,7 +34148,7 @@ class ToolExecutionGate {
|
|
|
33984
34148
|
}
|
|
33985
34149
|
}
|
|
33986
34150
|
acquire(key, mode, signal) {
|
|
33987
|
-
return new Promise((
|
|
34151
|
+
return new Promise((resolve10, reject) => {
|
|
33988
34152
|
if (signal?.aborted) {
|
|
33989
34153
|
reject(signal.reason ?? new Error("tool gate acquisition cancelled"));
|
|
33990
34154
|
return;
|
|
@@ -33997,7 +34161,7 @@ class ToolExecutionGate {
|
|
|
33997
34161
|
this.states.set(key, state);
|
|
33998
34162
|
const waiter = {
|
|
33999
34163
|
mode,
|
|
34000
|
-
resolve:
|
|
34164
|
+
resolve: resolve10,
|
|
34001
34165
|
reject,
|
|
34002
34166
|
...signal ? {
|
|
34003
34167
|
signal
|
|
@@ -34054,8 +34218,8 @@ class ToolExecutionGate {
|
|
|
34054
34218
|
if (state.activeReaders === 0 && !state.activeWriter && state.queue.length === 0 && this.states.get(key) === state) {
|
|
34055
34219
|
this.states.delete(key);
|
|
34056
34220
|
if (this.states.size === 0) {
|
|
34057
|
-
for (const
|
|
34058
|
-
|
|
34221
|
+
for (const resolve10 of this.idleResolvers)
|
|
34222
|
+
resolve10();
|
|
34059
34223
|
this.idleResolvers.clear();
|
|
34060
34224
|
}
|
|
34061
34225
|
}
|
|
@@ -34102,7 +34266,7 @@ function abortablePromise(promise, signal) {
|
|
|
34102
34266
|
return promise;
|
|
34103
34267
|
if (signal.aborted)
|
|
34104
34268
|
return Promise.reject(abortReason(signal));
|
|
34105
|
-
return new Promise((
|
|
34269
|
+
return new Promise((resolve10, reject) => {
|
|
34106
34270
|
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
34107
34271
|
const onAbort = () => {
|
|
34108
34272
|
cleanup();
|
|
@@ -34113,7 +34277,7 @@ function abortablePromise(promise, signal) {
|
|
|
34113
34277
|
});
|
|
34114
34278
|
promise.then((value) => {
|
|
34115
34279
|
cleanup();
|
|
34116
|
-
|
|
34280
|
+
resolve10(value);
|
|
34117
34281
|
}, (error) => {
|
|
34118
34282
|
cleanup();
|
|
34119
34283
|
reject(error);
|
|
@@ -34498,8 +34662,8 @@ var init_tool_call_journal = () => {};
|
|
|
34498
34662
|
|
|
34499
34663
|
// src/agent-core/runtime.ts
|
|
34500
34664
|
import { createHash as createHash9 } from "crypto";
|
|
34501
|
-
import { existsSync as
|
|
34502
|
-
import { isAbsolute as
|
|
34665
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync6, realpathSync as realpathSync3 } from "fs";
|
|
34666
|
+
import { isAbsolute as isAbsolute7, join as join22, relative as relative7 } from "path";
|
|
34503
34667
|
function assertProviderToolIndex2(index, max) {
|
|
34504
34668
|
if (!Number.isInteger(index) || index < 0 || index >= max)
|
|
34505
34669
|
throw new Error(`provider tool call index must be between 0 and ${max - 1}`);
|
|
@@ -34545,7 +34709,7 @@ class AgentRuntime {
|
|
|
34545
34709
|
this.workspace = workspace;
|
|
34546
34710
|
this.inheritConfig = options.inheritConfig !== false;
|
|
34547
34711
|
const config = this.inheritConfig ? loadConfig(workspace) : {};
|
|
34548
|
-
this.store = new SqliteStore(
|
|
34712
|
+
this.store = new SqliteStore(join22(workspace, ".farai"));
|
|
34549
34713
|
this.toolCalls = new ToolCallJournal(this.store, (sessionId, type, payload) => this.event(sessionId, type, payload));
|
|
34550
34714
|
this.knowledgeEnabled = options.enableKnowledge !== false;
|
|
34551
34715
|
this.hooksEnabled = options.enableHooks !== false;
|
|
@@ -35367,16 +35531,16 @@ class AgentRuntime {
|
|
|
35367
35531
|
}
|
|
35368
35532
|
waitForSteering(sessionId) {
|
|
35369
35533
|
let settled = false;
|
|
35370
|
-
let
|
|
35534
|
+
let resolve10;
|
|
35371
35535
|
const promise = new Promise((done) => {
|
|
35372
|
-
|
|
35536
|
+
resolve10 = done;
|
|
35373
35537
|
});
|
|
35374
35538
|
const wake = () => {
|
|
35375
35539
|
if (settled)
|
|
35376
35540
|
return;
|
|
35377
35541
|
settled = true;
|
|
35378
35542
|
this.steeringWaiters.get(sessionId)?.delete(wake);
|
|
35379
|
-
|
|
35543
|
+
resolve10();
|
|
35380
35544
|
};
|
|
35381
35545
|
const waiters = this.steeringWaiters.get(sessionId) ?? new Set;
|
|
35382
35546
|
waiters.add(wake);
|
|
@@ -35724,12 +35888,12 @@ class AgentRuntime {
|
|
|
35724
35888
|
return {
|
|
35725
35889
|
markdown
|
|
35726
35890
|
};
|
|
35727
|
-
const dir =
|
|
35891
|
+
const dir = join22(this.workspace, ".farai", "reports");
|
|
35728
35892
|
mkdirSync6(dir, {
|
|
35729
35893
|
recursive: true
|
|
35730
35894
|
});
|
|
35731
35895
|
const stamp = new Date().toISOString().slice(0, 10);
|
|
35732
|
-
const path =
|
|
35896
|
+
const path = join22(dir, `${sessionId}-${stamp}.md`);
|
|
35733
35897
|
atomicWriteFile(path, markdown, 384);
|
|
35734
35898
|
return {
|
|
35735
35899
|
markdown,
|
|
@@ -37829,7 +37993,7 @@ This completion is already terminal and was delivered automatically. Do not call
|
|
|
37829
37993
|
}
|
|
37830
37994
|
if (entries.length === 0 || entries.some((entry) => !entry.running) || Date.now() - started >= timeoutMs)
|
|
37831
37995
|
return entries;
|
|
37832
|
-
await new Promise((
|
|
37996
|
+
await new Promise((resolve10) => setTimeout(resolve10, 200));
|
|
37833
37997
|
}
|
|
37834
37998
|
},
|
|
37835
37999
|
message: (childSessionId, text2) => {
|
|
@@ -37889,15 +38053,15 @@ This completion is already terminal and was delivered automatically. Do not call
|
|
|
37889
38053
|
const root = (await runHostGit(this.workspace, ["rev-parse", "--show-toplevel"])).trim();
|
|
37890
38054
|
if (realpathSync3(root) !== realpathSync3(this.workspace))
|
|
37891
38055
|
throw new Error(`Farai workspace is not the Git repository root: ${root}`);
|
|
37892
|
-
const worktreesRoot =
|
|
38056
|
+
const worktreesRoot = join22(this.workspace, ".farai", "worktrees");
|
|
37893
38057
|
mkdirSync6(worktreesRoot, {
|
|
37894
38058
|
recursive: true
|
|
37895
38059
|
});
|
|
37896
|
-
const path =
|
|
38060
|
+
const path = join22(worktreesRoot, safeName);
|
|
37897
38061
|
const registered = await registeredWorktree(this.workspace, path);
|
|
37898
|
-
if (
|
|
38062
|
+
if (existsSync17(path) && !registered)
|
|
37899
38063
|
throw new Error(`worktree path already exists but is not a registered Git worktree: ${path}`);
|
|
37900
|
-
if (!
|
|
38064
|
+
if (!existsSync17(path) && registered)
|
|
37901
38065
|
throw new Error(`worktree registration exists but its directory is missing: ${path}; repair or prune it before re-entry`);
|
|
37902
38066
|
if (registered) {
|
|
37903
38067
|
if (ref || branch)
|
|
@@ -37947,9 +38111,9 @@ This completion is already terminal and was delivered automatically. Do not call
|
|
|
37947
38111
|
if (current.workspace === this.workspace)
|
|
37948
38112
|
throw new Error("session is not inside an isolated worktree");
|
|
37949
38113
|
this.assertWorkspaceTransitionIdle(session.id);
|
|
37950
|
-
const worktreesRoot =
|
|
38114
|
+
const worktreesRoot = join22(this.workspace, ".farai", "worktrees");
|
|
37951
38115
|
const managedPath = relative7(worktreesRoot, current.workspace);
|
|
37952
|
-
if (!managedPath || managedPath.startsWith("..") ||
|
|
38116
|
+
if (!managedPath || managedPath.startsWith("..") || isAbsolute7(managedPath)) {
|
|
37953
38117
|
throw new Error(`refusing to leave an unmanaged worktree: ${current.workspace}`);
|
|
37954
38118
|
}
|
|
37955
38119
|
if (remove) {
|
|
@@ -38831,16 +38995,16 @@ function plannerRetryState(error, attempt, safeToReplay) {
|
|
|
38831
38995
|
function abortableSleep(ms, signal) {
|
|
38832
38996
|
if (signal?.aborted)
|
|
38833
38997
|
return Promise.resolve();
|
|
38834
|
-
return new Promise((
|
|
38998
|
+
return new Promise((resolve10) => {
|
|
38835
38999
|
const cleanup = () => signal?.removeEventListener("abort", onAbort);
|
|
38836
39000
|
const onAbort = () => {
|
|
38837
39001
|
clearTimeout(timer);
|
|
38838
39002
|
cleanup();
|
|
38839
|
-
|
|
39003
|
+
resolve10();
|
|
38840
39004
|
};
|
|
38841
39005
|
const timer = setTimeout(() => {
|
|
38842
39006
|
cleanup();
|
|
38843
|
-
|
|
39007
|
+
resolve10();
|
|
38844
39008
|
}, ms);
|
|
38845
39009
|
signal?.addEventListener("abort", onAbort, {
|
|
38846
39010
|
once: true
|
|
@@ -38890,18 +39054,18 @@ function shutdownGracePeriod(value) {
|
|
|
38890
39054
|
return Math.max(0, value);
|
|
38891
39055
|
}
|
|
38892
39056
|
function waitForShutdownFinalization(finalization, gracePeriodMs) {
|
|
38893
|
-
return new Promise((
|
|
39057
|
+
return new Promise((resolve10, reject) => {
|
|
38894
39058
|
let settled = false;
|
|
38895
39059
|
const timer = setTimeout(() => {
|
|
38896
39060
|
settled = true;
|
|
38897
|
-
|
|
39061
|
+
resolve10(false);
|
|
38898
39062
|
}, gracePeriodMs);
|
|
38899
39063
|
finalization.then(() => {
|
|
38900
39064
|
if (settled)
|
|
38901
39065
|
return;
|
|
38902
39066
|
settled = true;
|
|
38903
39067
|
clearTimeout(timer);
|
|
38904
|
-
|
|
39068
|
+
resolve10(true);
|
|
38905
39069
|
}, (error) => {
|
|
38906
39070
|
if (settled)
|
|
38907
39071
|
return;
|
|
@@ -39028,7 +39192,7 @@ var init_runtime = __esm(() => {
|
|
|
39028
39192
|
init_retry();
|
|
39029
39193
|
init_reasoning_summary();
|
|
39030
39194
|
init_store();
|
|
39031
|
-
|
|
39195
|
+
init_paths3();
|
|
39032
39196
|
init_session_catalog();
|
|
39033
39197
|
init_session_user_input();
|
|
39034
39198
|
init_tool_execution_control();
|
|
@@ -39079,37 +39243,796 @@ var init_branding = __esm(() => {
|
|
|
39079
39243
|
`);
|
|
39080
39244
|
});
|
|
39081
39245
|
|
|
39082
|
-
// src/agent-
|
|
39083
|
-
|
|
39246
|
+
// src/agent-core/semver.ts
|
|
39247
|
+
function compareSemver(left, right) {
|
|
39248
|
+
const a = parseSemver(left);
|
|
39249
|
+
const b = parseSemver(right);
|
|
39250
|
+
if (!a || !b)
|
|
39251
|
+
return 0;
|
|
39252
|
+
for (let index = 0;index < 3; index += 1) {
|
|
39253
|
+
const delta = a.core[index] - b.core[index];
|
|
39254
|
+
if (delta !== 0)
|
|
39255
|
+
return delta < 0 ? -1 : 1;
|
|
39256
|
+
}
|
|
39257
|
+
if (a.prerelease.length === 0 || b.prerelease.length === 0) {
|
|
39258
|
+
if (a.prerelease.length === b.prerelease.length)
|
|
39259
|
+
return 0;
|
|
39260
|
+
return a.prerelease.length === 0 ? 1 : -1;
|
|
39261
|
+
}
|
|
39262
|
+
const length = Math.max(a.prerelease.length, b.prerelease.length);
|
|
39263
|
+
for (let index = 0;index < length; index += 1) {
|
|
39264
|
+
const aPart = a.prerelease[index];
|
|
39265
|
+
const bPart = b.prerelease[index];
|
|
39266
|
+
if (aPart === undefined || bPart === undefined)
|
|
39267
|
+
return aPart === undefined ? -1 : 1;
|
|
39268
|
+
if (aPart === bPart)
|
|
39269
|
+
continue;
|
|
39270
|
+
const aNumber = numericIdentifier(aPart);
|
|
39271
|
+
const bNumber = numericIdentifier(bPart);
|
|
39272
|
+
if (aNumber !== undefined && bNumber !== undefined)
|
|
39273
|
+
return aNumber < bNumber ? -1 : 1;
|
|
39274
|
+
if (aNumber !== undefined || bNumber !== undefined)
|
|
39275
|
+
return aNumber !== undefined ? -1 : 1;
|
|
39276
|
+
return aPart < bPart ? -1 : 1;
|
|
39277
|
+
}
|
|
39278
|
+
return 0;
|
|
39279
|
+
}
|
|
39280
|
+
function isSemver(value) {
|
|
39281
|
+
return parseSemver(value) !== undefined;
|
|
39282
|
+
}
|
|
39283
|
+
function parseSemver(value) {
|
|
39284
|
+
const match = value.trim().match(/^(?:v)?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/);
|
|
39285
|
+
if (!match)
|
|
39286
|
+
return;
|
|
39287
|
+
return {
|
|
39288
|
+
core: [Number(match[1]), Number(match[2]), Number(match[3])],
|
|
39289
|
+
prerelease: match[4]?.split(".") ?? []
|
|
39290
|
+
};
|
|
39291
|
+
}
|
|
39292
|
+
function numericIdentifier(value) {
|
|
39293
|
+
if (!/^(0|[1-9]\d*)$/.test(value))
|
|
39294
|
+
return;
|
|
39295
|
+
return Number(value);
|
|
39296
|
+
}
|
|
39297
|
+
|
|
39298
|
+
// src/agent-content/manifest.ts
|
|
39299
|
+
async function fetchContentManifest(manifestUrl, options = {}) {
|
|
39300
|
+
const resolved = new URL(manifestUrl);
|
|
39301
|
+
let parsed;
|
|
39302
|
+
if (resolved.protocol === "file:") {
|
|
39303
|
+
parsed = JSON.parse(await readBoundedFileText(resolved, CONTENT_MANIFEST_MAX_BYTES, "content manifest"));
|
|
39304
|
+
} else {
|
|
39305
|
+
if (resolved.protocol !== "https:")
|
|
39306
|
+
throw new Error("content manifest must use https or file");
|
|
39307
|
+
const controller = new AbortController;
|
|
39308
|
+
const timer = setTimeout(() => controller.abort(), Math.max(1, options.timeoutMs ?? 5000));
|
|
39309
|
+
timer.unref?.();
|
|
39310
|
+
try {
|
|
39311
|
+
const response = await (options.fetcher ?? fetch)(resolved, {
|
|
39312
|
+
headers: {
|
|
39313
|
+
accept: "application/json"
|
|
39314
|
+
},
|
|
39315
|
+
signal: controller.signal
|
|
39316
|
+
});
|
|
39317
|
+
if (!response.ok) {
|
|
39318
|
+
await discardResponseBody(response);
|
|
39319
|
+
throw new Error(`content manifest returned ${response.status}`);
|
|
39320
|
+
}
|
|
39321
|
+
parsed = await readBoundedResponseJson(response, CONTENT_MANIFEST_MAX_BYTES, "content manifest");
|
|
39322
|
+
} finally {
|
|
39323
|
+
clearTimeout(timer);
|
|
39324
|
+
}
|
|
39325
|
+
}
|
|
39326
|
+
return parseContentManifest(parsed, resolved);
|
|
39327
|
+
}
|
|
39328
|
+
function parseContentManifest(value, baseUrl) {
|
|
39329
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
39330
|
+
throw new Error("content manifest must be an object");
|
|
39331
|
+
const record3 = value;
|
|
39332
|
+
if (record3.schemaVersion !== CONTENT_MANIFEST_SCHEMA_VERSION)
|
|
39333
|
+
throw new Error(`unsupported content manifest schema: ${String(record3.schemaVersion)}`);
|
|
39334
|
+
if (typeof record3.contentVersion !== "string" || !CONTENT_VERSION_PATTERN.test(record3.contentVersion))
|
|
39335
|
+
throw new Error("invalid content version");
|
|
39336
|
+
if (typeof record3.generatedAt !== "string" || !Number.isFinite(Date.parse(record3.generatedAt)))
|
|
39337
|
+
throw new Error("invalid content generatedAt");
|
|
39338
|
+
const minFaraiVersion = optionalString2(record3.minFaraiVersion, 128, "minFaraiVersion");
|
|
39339
|
+
if (minFaraiVersion && !isSemver(minFaraiVersion))
|
|
39340
|
+
throw new Error("invalid content minFaraiVersion");
|
|
39341
|
+
const releaseNotes = optionalString2(record3.releaseNotes, 4096, "releaseNotes");
|
|
39342
|
+
const knowledge = artifact(record3.knowledge, baseUrl, "knowledge");
|
|
39343
|
+
const skills = artifact(record3.skills, baseUrl, "skills");
|
|
39344
|
+
return {
|
|
39345
|
+
schemaVersion: 1,
|
|
39346
|
+
contentVersion: record3.contentVersion,
|
|
39347
|
+
generatedAt: new Date(record3.generatedAt).toISOString(),
|
|
39348
|
+
...minFaraiVersion ? {
|
|
39349
|
+
minFaraiVersion
|
|
39350
|
+
} : {},
|
|
39351
|
+
...releaseNotes ? {
|
|
39352
|
+
releaseNotes
|
|
39353
|
+
} : {},
|
|
39354
|
+
...knowledge ? {
|
|
39355
|
+
knowledge
|
|
39356
|
+
} : {},
|
|
39357
|
+
...skills ? {
|
|
39358
|
+
skills
|
|
39359
|
+
} : {}
|
|
39360
|
+
};
|
|
39361
|
+
}
|
|
39362
|
+
function artifact(value, baseUrl, label) {
|
|
39363
|
+
if (value === undefined)
|
|
39364
|
+
return;
|
|
39365
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
39366
|
+
throw new Error(`${label} artifact must be an object`);
|
|
39367
|
+
const record3 = value;
|
|
39368
|
+
if (typeof record3.url !== "string" || !record3.url || record3.url.length > 2048)
|
|
39369
|
+
throw new Error(`${label} artifact has an invalid url`);
|
|
39370
|
+
const url = new URL(record3.url, baseUrl);
|
|
39371
|
+
if (baseUrl.protocol === "https:" && url.protocol !== "https:")
|
|
39372
|
+
throw new Error(`${label} artifact must use https when the manifest is remote`);
|
|
39373
|
+
if (url.protocol !== "https:" && url.protocol !== "file:")
|
|
39374
|
+
throw new Error(`${label} artifact must use https or file`);
|
|
39375
|
+
if (typeof record3.sha256 !== "string" || !SHA256_PATTERN.test(record3.sha256))
|
|
39376
|
+
throw new Error(`${label} artifact has an invalid sha256`);
|
|
39377
|
+
if (!Number.isSafeInteger(record3.size) || Number(record3.size) < 1 || Number(record3.size) > 2147483648)
|
|
39378
|
+
throw new Error(`${label} artifact has an invalid size`);
|
|
39379
|
+
const schemaVersion = record3.schemaVersion === undefined ? undefined : Number.isSafeInteger(record3.schemaVersion) && Number(record3.schemaVersion) > 0 ? Number(record3.schemaVersion) : undefined;
|
|
39380
|
+
if (record3.schemaVersion !== undefined && schemaVersion === undefined)
|
|
39381
|
+
throw new Error(`${label} artifact has an invalid schemaVersion`);
|
|
39382
|
+
return {
|
|
39383
|
+
url: url.href,
|
|
39384
|
+
sha256: record3.sha256,
|
|
39385
|
+
size: Number(record3.size),
|
|
39386
|
+
...schemaVersion ? {
|
|
39387
|
+
schemaVersion
|
|
39388
|
+
} : {}
|
|
39389
|
+
};
|
|
39390
|
+
}
|
|
39391
|
+
function optionalString2(value, maxLength, label) {
|
|
39392
|
+
if (value === undefined)
|
|
39393
|
+
return;
|
|
39394
|
+
if (typeof value !== "string" || !value.trim() || value.length > maxLength)
|
|
39395
|
+
throw new Error(`invalid content ${label}`);
|
|
39396
|
+
return value.trim();
|
|
39397
|
+
}
|
|
39398
|
+
var CONTENT_MANIFEST_SCHEMA_VERSION = 1, CONTENT_MANIFEST_MAX_BYTES, DEFAULT_CONTENT_MANIFEST_URL = "https://github.com/pajarori/farai-data/releases/latest/download/manifest.json", CONTENT_VERSION_PATTERN, SHA256_PATTERN;
|
|
39399
|
+
var init_manifest = __esm(() => {
|
|
39400
|
+
init_http_response();
|
|
39401
|
+
init_file_read();
|
|
39402
|
+
CONTENT_MANIFEST_MAX_BYTES = 256 * 1024;
|
|
39403
|
+
CONTENT_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
39404
|
+
SHA256_PATTERN = /^[a-f0-9]{64}$/;
|
|
39405
|
+
});
|
|
39406
|
+
|
|
39407
|
+
// src/agent-content/updater.ts
|
|
39408
|
+
var exports_updater = {};
|
|
39409
|
+
__export(exports_updater, {
|
|
39410
|
+
rollbackContentUpdate: () => rollbackContentUpdate,
|
|
39411
|
+
isContentVersionDismissed: () => isContentVersionDismissed,
|
|
39412
|
+
dismissContentVersion: () => dismissContentVersion,
|
|
39413
|
+
contentStatus: () => contentStatus,
|
|
39414
|
+
checkContentUpdate: () => checkContentUpdate,
|
|
39415
|
+
applyContentUpdate: () => applyContentUpdate,
|
|
39416
|
+
CONTENT_UPDATE_TIMEOUT_MS: () => CONTENT_UPDATE_TIMEOUT_MS,
|
|
39417
|
+
CONTENT_MANIFEST_CACHE_TTL_MS: () => CONTENT_MANIFEST_CACHE_TTL_MS
|
|
39418
|
+
});
|
|
39084
39419
|
import { createHash as createHash10, randomUUID as randomUUID4 } from "crypto";
|
|
39085
|
-
import {
|
|
39420
|
+
import { closeSync as closeSync4, existsSync as existsSync18, lstatSync as lstatSync4, mkdirSync as mkdirSync7, openSync as openSync4, readSync as readSync2, readdirSync as readdirSync6, renameSync as renameSync3, rmSync as rmSync3, statSync as statSync6, unlinkSync as unlinkSync6, writeSync } from "fs";
|
|
39421
|
+
import { dirname as dirname9, join as join23 } from "path";
|
|
39422
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
39423
|
+
async function checkContentUpdate(options = {}) {
|
|
39424
|
+
const config = loadConfig(options.workspace);
|
|
39425
|
+
const manifestUrl = options.manifestUrl ?? process.env.FARAI_CONTENT_MANIFEST_URL ?? config.updates?.contentManifestUrl ?? DEFAULT_CONTENT_MANIFEST_URL;
|
|
39426
|
+
if (contentUpdateDisabled(config.updates?.contentEnabled))
|
|
39427
|
+
return {
|
|
39428
|
+
state: "disabled",
|
|
39429
|
+
manifestUrl,
|
|
39430
|
+
fromCache: false
|
|
39431
|
+
};
|
|
39432
|
+
const now = options.now ?? Date.now();
|
|
39433
|
+
const cached = readManifestCache();
|
|
39434
|
+
const cacheMatches = cached?.manifestUrl === manifestUrl;
|
|
39435
|
+
let manifest;
|
|
39436
|
+
let fromCache = false;
|
|
39437
|
+
if (!options.force && cacheMatches && cached && isFresh(cached.checkedAt, now)) {
|
|
39438
|
+
if (!cached.manifest)
|
|
39439
|
+
return {
|
|
39440
|
+
state: "error",
|
|
39441
|
+
manifestUrl,
|
|
39442
|
+
fromCache: true,
|
|
39443
|
+
...cached.error ? {
|
|
39444
|
+
error: cached.error
|
|
39445
|
+
} : {}
|
|
39446
|
+
};
|
|
39447
|
+
manifest = cached.manifest;
|
|
39448
|
+
fromCache = true;
|
|
39449
|
+
} else {
|
|
39450
|
+
try {
|
|
39451
|
+
manifest = await fetchContentManifest(manifestUrl, {
|
|
39452
|
+
...options.fetcher ? {
|
|
39453
|
+
fetcher: options.fetcher
|
|
39454
|
+
} : {},
|
|
39455
|
+
timeoutMs: options.timeoutMs ?? CONTENT_UPDATE_TIMEOUT_MS
|
|
39456
|
+
});
|
|
39457
|
+
writeManifestCache({
|
|
39458
|
+
checkedAt: now,
|
|
39459
|
+
manifestUrl,
|
|
39460
|
+
manifest
|
|
39461
|
+
});
|
|
39462
|
+
} catch (error) {
|
|
39463
|
+
const message = errorMessage6(error);
|
|
39464
|
+
if (cacheMatches && cached?.manifest) {
|
|
39465
|
+
manifest = cached.manifest;
|
|
39466
|
+
fromCache = true;
|
|
39467
|
+
writeManifestCache({
|
|
39468
|
+
checkedAt: now,
|
|
39469
|
+
manifestUrl,
|
|
39470
|
+
manifest,
|
|
39471
|
+
error: message
|
|
39472
|
+
});
|
|
39473
|
+
} else {
|
|
39474
|
+
writeManifestCache({
|
|
39475
|
+
checkedAt: now,
|
|
39476
|
+
manifestUrl,
|
|
39477
|
+
error: message
|
|
39478
|
+
});
|
|
39479
|
+
return {
|
|
39480
|
+
state: "error",
|
|
39481
|
+
manifestUrl,
|
|
39482
|
+
fromCache: false,
|
|
39483
|
+
error: message
|
|
39484
|
+
};
|
|
39485
|
+
}
|
|
39486
|
+
}
|
|
39487
|
+
}
|
|
39488
|
+
const active = readActiveContent();
|
|
39489
|
+
if (!manifest || !manifest.knowledge && !manifest.skills)
|
|
39490
|
+
return {
|
|
39491
|
+
state: "unavailable",
|
|
39492
|
+
manifestUrl,
|
|
39493
|
+
fromCache,
|
|
39494
|
+
...active ? {
|
|
39495
|
+
active
|
|
39496
|
+
} : {},
|
|
39497
|
+
...manifest ? {
|
|
39498
|
+
manifest
|
|
39499
|
+
} : {}
|
|
39500
|
+
};
|
|
39501
|
+
if (manifest.minFaraiVersion && isSemver(manifest.minFaraiVersion) && compareSemver(FARAI_VERSION, manifest.minFaraiVersion) < 0) {
|
|
39502
|
+
return {
|
|
39503
|
+
state: "incompatible",
|
|
39504
|
+
manifestUrl,
|
|
39505
|
+
fromCache,
|
|
39506
|
+
manifest,
|
|
39507
|
+
...active ? {
|
|
39508
|
+
active
|
|
39509
|
+
} : {}
|
|
39510
|
+
};
|
|
39511
|
+
}
|
|
39512
|
+
if (!isNewerManifest(manifest, active))
|
|
39513
|
+
return {
|
|
39514
|
+
state: "up_to_date",
|
|
39515
|
+
manifestUrl,
|
|
39516
|
+
fromCache,
|
|
39517
|
+
manifest,
|
|
39518
|
+
...active ? {
|
|
39519
|
+
active
|
|
39520
|
+
} : {}
|
|
39521
|
+
};
|
|
39522
|
+
return {
|
|
39523
|
+
state: "update_available",
|
|
39524
|
+
manifestUrl,
|
|
39525
|
+
fromCache,
|
|
39526
|
+
manifest,
|
|
39527
|
+
...active ? {
|
|
39528
|
+
active
|
|
39529
|
+
} : {}
|
|
39530
|
+
};
|
|
39531
|
+
}
|
|
39532
|
+
async function applyContentUpdate(manifest, manifestUrl, options = {}) {
|
|
39533
|
+
if (!manifest.knowledge && !manifest.skills)
|
|
39534
|
+
throw new Error("content manifest has no artifacts");
|
|
39535
|
+
ensureContentDirectories();
|
|
39536
|
+
const release = acquireLock();
|
|
39537
|
+
const stage = join23(contentVersionsDir(), `.staging-${process.pid}-${randomUUID4()}`);
|
|
39538
|
+
const finalPath = contentVersionDir(manifest.contentVersion);
|
|
39539
|
+
try {
|
|
39540
|
+
mkdirSync7(stage, {
|
|
39541
|
+
recursive: true,
|
|
39542
|
+
mode: 448
|
|
39543
|
+
});
|
|
39544
|
+
ensurePrivateDirectory(stage, "content staging directory");
|
|
39545
|
+
let knowledge = false;
|
|
39546
|
+
let skills = false;
|
|
39547
|
+
if (manifest.knowledge) {
|
|
39548
|
+
const path = join23(stage, "knowledge.db");
|
|
39549
|
+
await downloadArtifact(manifest.knowledge, path, options);
|
|
39550
|
+
validateKnowledge(path, manifest.knowledge.schemaVersion);
|
|
39551
|
+
knowledge = true;
|
|
39552
|
+
}
|
|
39553
|
+
if (manifest.skills) {
|
|
39554
|
+
if (manifest.skills.size > CONTENT_SKILLS_MAX_BYTES)
|
|
39555
|
+
throw new Error("skills artifact is too large");
|
|
39556
|
+
const archive = join23(stage, "skills.tar.gz");
|
|
39557
|
+
await downloadArtifact(manifest.skills, archive, options);
|
|
39558
|
+
await extractSkills(archive, join23(stage, "skills"));
|
|
39559
|
+
rmSync3(archive, {
|
|
39560
|
+
force: true
|
|
39561
|
+
});
|
|
39562
|
+
skills = true;
|
|
39563
|
+
}
|
|
39564
|
+
atomicWriteFile(join23(stage, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
39565
|
+
`, 384);
|
|
39566
|
+
ensurePrivateRegularFileIfExists(join23(stage, "manifest.json"), "staged content manifest");
|
|
39567
|
+
if (existsSync18(finalPath)) {
|
|
39568
|
+
const existing = join23(finalPath, "manifest.json");
|
|
39569
|
+
if (existsSync18(existing)) {
|
|
39570
|
+
const current = parseStoredManifest(existing);
|
|
39571
|
+
if (JSON.stringify(current) !== JSON.stringify(manifest))
|
|
39572
|
+
throw new Error(`content version already exists with different metadata: ${manifest.contentVersion}`);
|
|
39573
|
+
rmSync3(stage, {
|
|
39574
|
+
recursive: true,
|
|
39575
|
+
force: true
|
|
39576
|
+
});
|
|
39577
|
+
} else {
|
|
39578
|
+
rmSync3(finalPath, {
|
|
39579
|
+
recursive: true,
|
|
39580
|
+
force: true
|
|
39581
|
+
});
|
|
39582
|
+
renameSync3(stage, finalPath);
|
|
39583
|
+
}
|
|
39584
|
+
} else {
|
|
39585
|
+
renameSync3(stage, finalPath);
|
|
39586
|
+
}
|
|
39587
|
+
ensurePrivateDirectory(finalPath, "content version directory");
|
|
39588
|
+
const previous = readActiveContent();
|
|
39589
|
+
const pointer = {
|
|
39590
|
+
schemaVersion: 1,
|
|
39591
|
+
version: manifest.contentVersion,
|
|
39592
|
+
generatedAt: manifest.generatedAt,
|
|
39593
|
+
activatedAt: new Date().toISOString(),
|
|
39594
|
+
manifestUrl,
|
|
39595
|
+
...previous && previous.version !== manifest.contentVersion ? {
|
|
39596
|
+
previousVersion: previous.version
|
|
39597
|
+
} : {},
|
|
39598
|
+
knowledge,
|
|
39599
|
+
skills
|
|
39600
|
+
};
|
|
39601
|
+
atomicWriteFile(contentActivePath(), `${JSON.stringify(pointer, null, 2)}
|
|
39602
|
+
`, 384);
|
|
39603
|
+
syncDirectory(contentVersionsDir());
|
|
39604
|
+
pruneVersions(pointer);
|
|
39605
|
+
return {
|
|
39606
|
+
version: pointer.version,
|
|
39607
|
+
...pointer.previousVersion ? {
|
|
39608
|
+
previousVersion: pointer.previousVersion
|
|
39609
|
+
} : {},
|
|
39610
|
+
knowledge,
|
|
39611
|
+
skills,
|
|
39612
|
+
path: finalPath
|
|
39613
|
+
};
|
|
39614
|
+
} finally {
|
|
39615
|
+
if (existsSync18(stage))
|
|
39616
|
+
rmSync3(stage, {
|
|
39617
|
+
recursive: true,
|
|
39618
|
+
force: true
|
|
39619
|
+
});
|
|
39620
|
+
release();
|
|
39621
|
+
}
|
|
39622
|
+
}
|
|
39623
|
+
function rollbackContentUpdate() {
|
|
39624
|
+
ensureContentDirectories();
|
|
39625
|
+
const release = acquireLock();
|
|
39626
|
+
try {
|
|
39627
|
+
const active = readActiveContent();
|
|
39628
|
+
if (!active?.previousVersion)
|
|
39629
|
+
throw new Error("no previous content version is available");
|
|
39630
|
+
const previousPath = contentVersionDir(active.previousVersion);
|
|
39631
|
+
if (!existsSync18(previousPath))
|
|
39632
|
+
throw new Error(`previous content version is missing: ${active.previousVersion}`);
|
|
39633
|
+
const manifest = parseStoredManifest(join23(previousPath, "manifest.json"));
|
|
39634
|
+
const next = {
|
|
39635
|
+
schemaVersion: 1,
|
|
39636
|
+
version: active.previousVersion,
|
|
39637
|
+
generatedAt: manifest.generatedAt,
|
|
39638
|
+
activatedAt: new Date().toISOString(),
|
|
39639
|
+
manifestUrl: active.manifestUrl,
|
|
39640
|
+
previousVersion: active.version,
|
|
39641
|
+
knowledge: Boolean(manifest.knowledge && existsSync18(join23(previousPath, "knowledge.db"))),
|
|
39642
|
+
skills: Boolean(manifest.skills && existsSync18(join23(previousPath, "skills")))
|
|
39643
|
+
};
|
|
39644
|
+
atomicWriteFile(contentActivePath(), `${JSON.stringify(next, null, 2)}
|
|
39645
|
+
`, 384);
|
|
39646
|
+
return {
|
|
39647
|
+
version: next.version,
|
|
39648
|
+
previousVersion: next.previousVersion,
|
|
39649
|
+
knowledge: next.knowledge,
|
|
39650
|
+
skills: next.skills,
|
|
39651
|
+
path: previousPath
|
|
39652
|
+
};
|
|
39653
|
+
} finally {
|
|
39654
|
+
release();
|
|
39655
|
+
}
|
|
39656
|
+
}
|
|
39657
|
+
function contentStatus() {
|
|
39658
|
+
ensureContentDirectories();
|
|
39659
|
+
const active = readActiveContent();
|
|
39660
|
+
const versions = readdirVersions();
|
|
39661
|
+
const knowledgePath = activeContentKnowledgePath();
|
|
39662
|
+
const skillsPath = activeContentSkillsDir();
|
|
39663
|
+
return {
|
|
39664
|
+
...active ? {
|
|
39665
|
+
active
|
|
39666
|
+
} : {},
|
|
39667
|
+
...knowledgePath ? {
|
|
39668
|
+
knowledgePath
|
|
39669
|
+
} : {},
|
|
39670
|
+
...skillsPath ? {
|
|
39671
|
+
skillsPath
|
|
39672
|
+
} : {},
|
|
39673
|
+
versions
|
|
39674
|
+
};
|
|
39675
|
+
}
|
|
39676
|
+
function isContentVersionDismissed(version) {
|
|
39677
|
+
try {
|
|
39678
|
+
const value = JSON.parse(readBoundedFileTextSyncNoFollow(contentPreferencesPath(), CONTENT_PREFERENCES_MAX_BYTES, "content preferences"));
|
|
39679
|
+
return value.dismissedVersion === version;
|
|
39680
|
+
} catch {
|
|
39681
|
+
return false;
|
|
39682
|
+
}
|
|
39683
|
+
}
|
|
39684
|
+
function dismissContentVersion(version) {
|
|
39685
|
+
ensureContentDirectories();
|
|
39686
|
+
atomicWriteFile(contentPreferencesPath(), `${JSON.stringify({
|
|
39687
|
+
dismissedVersion: version
|
|
39688
|
+
})}
|
|
39689
|
+
`, 384);
|
|
39690
|
+
}
|
|
39691
|
+
function contentUpdateDisabled(configured) {
|
|
39692
|
+
if (configured === false)
|
|
39693
|
+
return true;
|
|
39694
|
+
return [process.env.FARAI_DISABLE_CONTENT_UPDATE, process.env.FARAI_DISABLE_UPDATE_CHECK].some((value) => value === "1" || value?.toLowerCase() === "true" || value?.toLowerCase() === "yes");
|
|
39695
|
+
}
|
|
39696
|
+
function isNewerManifest(manifest, active) {
|
|
39697
|
+
if (!active)
|
|
39698
|
+
return true;
|
|
39699
|
+
if (manifest.contentVersion === active.version)
|
|
39700
|
+
return false;
|
|
39701
|
+
const generated = Date.parse(manifest.generatedAt);
|
|
39702
|
+
const activeGenerated = Date.parse(active.generatedAt);
|
|
39703
|
+
if (Number.isFinite(generated) && Number.isFinite(activeGenerated))
|
|
39704
|
+
return generated > activeGenerated;
|
|
39705
|
+
return manifest.contentVersion > active.version;
|
|
39706
|
+
}
|
|
39707
|
+
function readManifestCache() {
|
|
39708
|
+
try {
|
|
39709
|
+
ensureContentDirectories();
|
|
39710
|
+
const parsed = JSON.parse(readBoundedFileTextSyncNoFollow(contentManifestCachePath(), CONTENT_MANIFEST_MAX_BYTES * 2, "content manifest cache"));
|
|
39711
|
+
if (typeof parsed.checkedAt !== "number" || !Number.isFinite(parsed.checkedAt) || typeof parsed.manifestUrl !== "string" || !parsed.manifestUrl)
|
|
39712
|
+
return;
|
|
39713
|
+
const manifest = parsed.manifest ? parseContentManifest(parsed.manifest, new URL(parsed.manifestUrl)) : undefined;
|
|
39714
|
+
const error = typeof parsed.error === "string" && parsed.error ? parsed.error : undefined;
|
|
39715
|
+
if (!manifest && !error)
|
|
39716
|
+
return;
|
|
39717
|
+
return {
|
|
39718
|
+
checkedAt: parsed.checkedAt,
|
|
39719
|
+
manifestUrl: parsed.manifestUrl,
|
|
39720
|
+
...manifest ? {
|
|
39721
|
+
manifest
|
|
39722
|
+
} : {},
|
|
39723
|
+
...error ? {
|
|
39724
|
+
error
|
|
39725
|
+
} : {}
|
|
39726
|
+
};
|
|
39727
|
+
} catch {
|
|
39728
|
+
return;
|
|
39729
|
+
}
|
|
39730
|
+
}
|
|
39731
|
+
function writeManifestCache(cache) {
|
|
39732
|
+
try {
|
|
39733
|
+
ensureContentDirectories();
|
|
39734
|
+
atomicWriteFile(contentManifestCachePath(), `${JSON.stringify(cache)}
|
|
39735
|
+
`, 384);
|
|
39736
|
+
} catch {}
|
|
39737
|
+
}
|
|
39738
|
+
function isFresh(checkedAt, now) {
|
|
39739
|
+
const age = now - checkedAt;
|
|
39740
|
+
return age >= 0 && age < CONTENT_MANIFEST_CACHE_TTL_MS;
|
|
39741
|
+
}
|
|
39742
|
+
function acquireLock() {
|
|
39743
|
+
const path = contentLockPath();
|
|
39744
|
+
ensureContentDirectories();
|
|
39745
|
+
try {
|
|
39746
|
+
const descriptor = openSync4(path, "wx", 384);
|
|
39747
|
+
try {
|
|
39748
|
+
writeSync(descriptor, JSON.stringify({
|
|
39749
|
+
pid: process.pid,
|
|
39750
|
+
createdAt: Date.now()
|
|
39751
|
+
}));
|
|
39752
|
+
} finally {
|
|
39753
|
+
closeSync4(descriptor);
|
|
39754
|
+
}
|
|
39755
|
+
cleanupStagingDirectories();
|
|
39756
|
+
return () => {
|
|
39757
|
+
try {
|
|
39758
|
+
unlinkSync6(path);
|
|
39759
|
+
} catch {}
|
|
39760
|
+
};
|
|
39761
|
+
} catch (error) {
|
|
39762
|
+
if (!isAlreadyExists(error) || !staleLock(path))
|
|
39763
|
+
throw new Error("another farai content update is already running");
|
|
39764
|
+
try {
|
|
39765
|
+
unlinkSync6(path);
|
|
39766
|
+
} catch {
|
|
39767
|
+
throw new Error("another farai content update is already running");
|
|
39768
|
+
}
|
|
39769
|
+
return acquireLock();
|
|
39770
|
+
}
|
|
39771
|
+
}
|
|
39772
|
+
function staleLock(path) {
|
|
39773
|
+
try {
|
|
39774
|
+
const stats = statSync6(path);
|
|
39775
|
+
const parsed = JSON.parse(readBoundedFileTextSyncNoFollow(path, 4 * 1024, "content update lock"));
|
|
39776
|
+
if (typeof parsed.pid === "number" && parsed.pid > 0) {
|
|
39777
|
+
try {
|
|
39778
|
+
process.kill(parsed.pid, 0);
|
|
39779
|
+
return false;
|
|
39780
|
+
} catch (error) {
|
|
39781
|
+
if (!isNoSuchProcess(error))
|
|
39782
|
+
return false;
|
|
39783
|
+
}
|
|
39784
|
+
}
|
|
39785
|
+
return Date.now() - stats.mtimeMs >= CONTENT_LOCK_STALE_MS || typeof parsed.pid === "number";
|
|
39786
|
+
} catch {
|
|
39787
|
+
return true;
|
|
39788
|
+
}
|
|
39789
|
+
}
|
|
39790
|
+
function cleanupStagingDirectories() {
|
|
39791
|
+
for (const entry of readdirSync6(contentVersionsDir())) {
|
|
39792
|
+
if (!entry.startsWith(".staging-"))
|
|
39793
|
+
continue;
|
|
39794
|
+
try {
|
|
39795
|
+
rmSync3(join23(contentVersionsDir(), entry), {
|
|
39796
|
+
recursive: true,
|
|
39797
|
+
force: true
|
|
39798
|
+
});
|
|
39799
|
+
} catch {}
|
|
39800
|
+
}
|
|
39801
|
+
}
|
|
39802
|
+
async function downloadArtifact(artifact2, destination, options) {
|
|
39803
|
+
if (artifact2.size > CONTENT_ARTIFACT_MAX_BYTES)
|
|
39804
|
+
throw new Error("content artifact is too large");
|
|
39805
|
+
const url = new URL(artifact2.url);
|
|
39806
|
+
mkdirSync7(dirname9(destination), {
|
|
39807
|
+
recursive: true,
|
|
39808
|
+
mode: 448
|
|
39809
|
+
});
|
|
39810
|
+
let bytes;
|
|
39811
|
+
if (url.protocol === "file:") {
|
|
39812
|
+
const source = Bun.file(url);
|
|
39813
|
+
const sourcePath = fileURLToPath2(url);
|
|
39814
|
+
const stats = lstatSync4(sourcePath);
|
|
39815
|
+
if (!stats.isFile())
|
|
39816
|
+
throw new Error("content artifact file must be a regular file");
|
|
39817
|
+
if (stats.size !== artifact2.size)
|
|
39818
|
+
throw new Error(`content artifact size mismatch: expected ${artifact2.size}, received ${stats.size}`);
|
|
39819
|
+
await Bun.write(destination, source);
|
|
39820
|
+
bytes = stats.size;
|
|
39821
|
+
} else {
|
|
39822
|
+
if (url.protocol !== "https:")
|
|
39823
|
+
throw new Error("content artifact must use https or file");
|
|
39824
|
+
const controller = new AbortController;
|
|
39825
|
+
const timer = setTimeout(() => controller.abort(), Math.max(1, options.timeoutMs ?? CONTENT_UPDATE_TIMEOUT_MS));
|
|
39826
|
+
timer.unref?.();
|
|
39827
|
+
let descriptor;
|
|
39828
|
+
try {
|
|
39829
|
+
const response = await (options.fetcher ?? fetch)(url, {
|
|
39830
|
+
signal: controller.signal
|
|
39831
|
+
});
|
|
39832
|
+
if (!response.ok || !response.body) {
|
|
39833
|
+
try {
|
|
39834
|
+
await response.body?.cancel();
|
|
39835
|
+
} catch {}
|
|
39836
|
+
throw new Error(`content artifact returned ${response.status}`);
|
|
39837
|
+
}
|
|
39838
|
+
const declared = Number(response.headers.get("content-length"));
|
|
39839
|
+
if (Number.isSafeInteger(declared) && declared !== artifact2.size)
|
|
39840
|
+
throw new Error(`content artifact size mismatch: expected ${artifact2.size}, received ${declared}`);
|
|
39841
|
+
descriptor = openSync4(destination, "wx", 384);
|
|
39842
|
+
const reader = response.body.getReader();
|
|
39843
|
+
bytes = 0;
|
|
39844
|
+
let completed = false;
|
|
39845
|
+
try {
|
|
39846
|
+
for (;; ) {
|
|
39847
|
+
const next = await reader.read();
|
|
39848
|
+
if (next.done) {
|
|
39849
|
+
completed = true;
|
|
39850
|
+
break;
|
|
39851
|
+
}
|
|
39852
|
+
bytes += next.value.byteLength;
|
|
39853
|
+
if (bytes > artifact2.size)
|
|
39854
|
+
throw new Error("content artifact exceeded declared size");
|
|
39855
|
+
writeSync(descriptor, next.value);
|
|
39856
|
+
}
|
|
39857
|
+
} finally {
|
|
39858
|
+
if (!completed)
|
|
39859
|
+
reader.cancel().catch(() => {
|
|
39860
|
+
return;
|
|
39861
|
+
});
|
|
39862
|
+
reader.releaseLock();
|
|
39863
|
+
}
|
|
39864
|
+
closeSync4(descriptor);
|
|
39865
|
+
descriptor = undefined;
|
|
39866
|
+
} finally {
|
|
39867
|
+
clearTimeout(timer);
|
|
39868
|
+
if (descriptor !== undefined)
|
|
39869
|
+
try {
|
|
39870
|
+
closeSync4(descriptor);
|
|
39871
|
+
} catch {}
|
|
39872
|
+
}
|
|
39873
|
+
}
|
|
39874
|
+
if (bytes !== artifact2.size)
|
|
39875
|
+
throw new Error(`content artifact size mismatch: expected ${artifact2.size}, received ${bytes}`);
|
|
39876
|
+
const digest2 = hashFile(destination);
|
|
39877
|
+
if (digest2 !== artifact2.sha256)
|
|
39878
|
+
throw new Error(`content artifact checksum mismatch for ${url.href}`);
|
|
39879
|
+
ensurePrivateRegularFileIfExists(destination, "downloaded content artifact");
|
|
39880
|
+
}
|
|
39881
|
+
function validateKnowledge(path, schemaVersion) {
|
|
39882
|
+
ensurePrivateSqlitePath(path, "staged knowledge database");
|
|
39883
|
+
if (schemaVersion !== undefined && schemaVersion !== KNOWLEDGE_SCHEMA_VERSION)
|
|
39884
|
+
throw new Error(`unsupported knowledge schema: ${schemaVersion}`);
|
|
39885
|
+
const store = KnowledgeStore.openIfExists(path);
|
|
39886
|
+
if (!store)
|
|
39887
|
+
throw new Error("staged knowledge database could not be opened");
|
|
39888
|
+
try {
|
|
39889
|
+
const integrity = store.verifyIntegrity();
|
|
39890
|
+
if (!integrity.ok)
|
|
39891
|
+
throw new Error(`staged knowledge database failed integrity: ${integrity.issues.map((issue) => `${issue.kind}=${issue.count}`).join(", ")}`);
|
|
39892
|
+
} finally {
|
|
39893
|
+
store.close();
|
|
39894
|
+
}
|
|
39895
|
+
}
|
|
39896
|
+
async function extractSkills(archive, destination) {
|
|
39897
|
+
const listing = await spawnTar(["-tzf", archive]);
|
|
39898
|
+
if (Buffer.byteLength(listing, "utf8") > CONTENT_SKILLS_LISTING_MAX_BYTES)
|
|
39899
|
+
throw new Error("skills archive listing is too large");
|
|
39900
|
+
const listingEntries = listing.split(/\r?\n/).map((item) => item.trim()).filter(Boolean);
|
|
39901
|
+
if (listingEntries.length > CONTENT_SKILLS_MAX_ENTRIES)
|
|
39902
|
+
throw new Error("skills archive contains too many entries");
|
|
39903
|
+
for (const entry of listingEntries) {
|
|
39904
|
+
if (entry.startsWith("/") || entry.split("/").includes("..") || entry.includes("\\"))
|
|
39905
|
+
throw new Error("skills archive contains an unsafe path");
|
|
39906
|
+
}
|
|
39907
|
+
mkdirSync7(destination, {
|
|
39908
|
+
recursive: true,
|
|
39909
|
+
mode: 448
|
|
39910
|
+
});
|
|
39911
|
+
await spawnTar(["-xzf", archive, "-C", destination]);
|
|
39912
|
+
const extractedEntries = [...walk(destination)];
|
|
39913
|
+
if (extractedEntries.some((path) => lstatSync4(path).isSymbolicLink()))
|
|
39914
|
+
throw new Error("skills archive contains a symbolic link");
|
|
39915
|
+
if (!extractedEntries.some((path) => path.endsWith("/SKILL.md")))
|
|
39916
|
+
throw new Error("skills archive contains no skills");
|
|
39917
|
+
}
|
|
39918
|
+
async function spawnTar(args) {
|
|
39919
|
+
const proc = Bun.spawn(["tar", ...args], {
|
|
39920
|
+
stdout: "pipe",
|
|
39921
|
+
stderr: "pipe"
|
|
39922
|
+
});
|
|
39923
|
+
const [stdout, stderr, code] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text(), proc.exited]);
|
|
39924
|
+
if (code !== 0)
|
|
39925
|
+
throw new Error(`skills archive operation failed${stderr.trim() ? `: ${stderr.trim()}` : ""}`);
|
|
39926
|
+
return stdout;
|
|
39927
|
+
}
|
|
39928
|
+
function* walk(root) {
|
|
39929
|
+
const entries = readdirSync6(root).sort();
|
|
39930
|
+
for (const entry of entries) {
|
|
39931
|
+
const path = join23(root, entry);
|
|
39932
|
+
const stat = lstatSync4(path);
|
|
39933
|
+
yield path;
|
|
39934
|
+
if (stat.isDirectory())
|
|
39935
|
+
yield* walk(path);
|
|
39936
|
+
}
|
|
39937
|
+
}
|
|
39938
|
+
function hashFile(path) {
|
|
39939
|
+
const descriptor = openSync4(path, "r");
|
|
39940
|
+
const hash = createHash10("sha256");
|
|
39941
|
+
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
39942
|
+
try {
|
|
39943
|
+
for (;; ) {
|
|
39944
|
+
const count2 = readSync2(descriptor, buffer, 0, buffer.length, null);
|
|
39945
|
+
if (count2 === 0)
|
|
39946
|
+
break;
|
|
39947
|
+
hash.update(buffer.subarray(0, count2));
|
|
39948
|
+
}
|
|
39949
|
+
return hash.digest("hex");
|
|
39950
|
+
} finally {
|
|
39951
|
+
closeSync4(descriptor);
|
|
39952
|
+
}
|
|
39953
|
+
}
|
|
39954
|
+
function parseStoredManifest(path) {
|
|
39955
|
+
ensurePrivateRegularFileIfExists(path, "stored content manifest");
|
|
39956
|
+
const raw = JSON.parse(readBoundedFileTextSyncNoFollow(path, CONTENT_MANIFEST_MAX_BYTES, "stored content manifest"));
|
|
39957
|
+
return parseContentManifest(raw, new URL("file:///stored/manifest.json"));
|
|
39958
|
+
}
|
|
39959
|
+
function pruneVersions(active) {
|
|
39960
|
+
const keep = new Set([active.version, active.previousVersion].filter((value) => Boolean(value)));
|
|
39961
|
+
for (const version of readdirVersions()) {
|
|
39962
|
+
if (keep.has(version))
|
|
39963
|
+
continue;
|
|
39964
|
+
try {
|
|
39965
|
+
rmSync3(contentVersionDir(version), {
|
|
39966
|
+
recursive: true,
|
|
39967
|
+
force: true
|
|
39968
|
+
});
|
|
39969
|
+
} catch {}
|
|
39970
|
+
}
|
|
39971
|
+
}
|
|
39972
|
+
function readdirVersions() {
|
|
39973
|
+
try {
|
|
39974
|
+
return readdirSync6(contentVersionsDir()).sort().filter((entry) => !entry.startsWith(".") && /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(entry));
|
|
39975
|
+
} catch {
|
|
39976
|
+
return [];
|
|
39977
|
+
}
|
|
39978
|
+
}
|
|
39979
|
+
function errorMessage6(error) {
|
|
39980
|
+
return error instanceof Error ? error.message : String(error);
|
|
39981
|
+
}
|
|
39982
|
+
function isAlreadyExists(error) {
|
|
39983
|
+
return Boolean(error && typeof error === "object" && "code" in error && error.code === "EEXIST");
|
|
39984
|
+
}
|
|
39985
|
+
function isNoSuchProcess(error) {
|
|
39986
|
+
return Boolean(error && typeof error === "object" && "code" in error && error.code === "ESRCH");
|
|
39987
|
+
}
|
|
39988
|
+
var CONTENT_MANIFEST_CACHE_TTL_MS, CONTENT_UPDATE_TIMEOUT_MS = 8000, CONTENT_ARTIFACT_MAX_BYTES = 2147483648, CONTENT_SKILLS_MAX_BYTES, CONTENT_SKILLS_MAX_ENTRIES = 8192, CONTENT_SKILLS_LISTING_MAX_BYTES, CONTENT_LOCK_STALE_MS, CONTENT_PREFERENCES_MAX_BYTES;
|
|
39989
|
+
var init_updater = __esm(() => {
|
|
39990
|
+
init_version();
|
|
39991
|
+
init_config();
|
|
39992
|
+
init_atomic_file();
|
|
39993
|
+
init_private_path();
|
|
39994
|
+
init_file_read();
|
|
39995
|
+
init_store();
|
|
39996
|
+
init_paths2();
|
|
39997
|
+
init_manifest();
|
|
39998
|
+
CONTENT_MANIFEST_CACHE_TTL_MS = 20 * 60 * 60 * 1000;
|
|
39999
|
+
CONTENT_SKILLS_MAX_BYTES = 256 * 1024 * 1024;
|
|
40000
|
+
CONTENT_SKILLS_LISTING_MAX_BYTES = 4 * 1024 * 1024;
|
|
40001
|
+
CONTENT_LOCK_STALE_MS = 15 * 60 * 1000;
|
|
40002
|
+
CONTENT_PREFERENCES_MAX_BYTES = 32 * 1024;
|
|
40003
|
+
});
|
|
40004
|
+
|
|
40005
|
+
// src/agent-knowledge/pack.ts
|
|
40006
|
+
import { closeSync as closeSync5, existsSync as existsSync19, fsyncSync as fsyncSync2, lstatSync as lstatSync5, mkdirSync as mkdirSync8, openSync as openSync5, readdirSync as readdirSync7, renameSync as renameSync4, rmSync as rmSync4, writeSync as writeSync2 } from "fs";
|
|
40007
|
+
import { createHash as createHash11, randomUUID as randomUUID5 } from "crypto";
|
|
40008
|
+
import { join as join24 } from "path";
|
|
39086
40009
|
function packDir(meta) {
|
|
39087
40010
|
assertPackPathPart(meta.id, "knowledge pack id");
|
|
39088
40011
|
assertPackPathPart(meta.pin, "knowledge pack pin");
|
|
39089
|
-
return
|
|
40012
|
+
return join24(packsDir(), `${meta.id}@${meta.pin.slice(0, 12)}`);
|
|
39090
40013
|
}
|
|
39091
40014
|
function writePack(meta, records, entities) {
|
|
39092
40015
|
const root = packsDir();
|
|
39093
40016
|
ensurePrivateDirectory(root, "knowledge pack directory");
|
|
39094
40017
|
const dir = packDir(meta);
|
|
39095
|
-
const temporary = `${dir}.tmp-${process.pid}-${
|
|
39096
|
-
|
|
40018
|
+
const temporary = `${dir}.tmp-${process.pid}-${randomUUID5()}`;
|
|
40019
|
+
mkdirSync8(temporary, {
|
|
39097
40020
|
mode: 448
|
|
39098
40021
|
});
|
|
39099
40022
|
try {
|
|
39100
|
-
atomicWriteFile(
|
|
40023
|
+
atomicWriteFile(join24(temporary, "meta.json"), `${JSON.stringify(meta, null, 2)}
|
|
39101
40024
|
`, 384);
|
|
39102
|
-
writeJsonl(
|
|
39103
|
-
writeJsonl(
|
|
40025
|
+
writeJsonl(join24(temporary, "records.jsonl"), records, "knowledge records");
|
|
40026
|
+
writeJsonl(join24(temporary, "entities.jsonl"), entities, "knowledge entities");
|
|
39104
40027
|
if (realDirectoryExists(dir, "knowledge pack"))
|
|
39105
|
-
|
|
40028
|
+
rmSync4(dir, {
|
|
39106
40029
|
recursive: true,
|
|
39107
40030
|
force: true
|
|
39108
40031
|
});
|
|
39109
|
-
|
|
40032
|
+
renameSync4(temporary, dir);
|
|
39110
40033
|
syncDirectory(root);
|
|
39111
40034
|
} catch (error) {
|
|
39112
|
-
|
|
40035
|
+
rmSync4(temporary, {
|
|
39113
40036
|
recursive: true,
|
|
39114
40037
|
force: true
|
|
39115
40038
|
});
|
|
@@ -39119,19 +40042,19 @@ function writePack(meta, records, entities) {
|
|
|
39119
40042
|
}
|
|
39120
40043
|
function listPacks() {
|
|
39121
40044
|
const root = packsDir();
|
|
39122
|
-
if (!
|
|
40045
|
+
if (!existsSync19(root))
|
|
39123
40046
|
return [];
|
|
39124
40047
|
assertRealDirectory(root, "knowledge pack directory");
|
|
39125
|
-
const entries =
|
|
40048
|
+
const entries = readdirSync7(root);
|
|
39126
40049
|
if (entries.length > PACK_DIRECTORY_MAX_COUNT)
|
|
39127
40050
|
throw new Error(`knowledge pack directory exceeded ${PACK_DIRECTORY_MAX_COUNT} entries`);
|
|
39128
40051
|
const out = [];
|
|
39129
40052
|
for (const entry of entries) {
|
|
39130
|
-
const dir =
|
|
40053
|
+
const dir = join24(root, entry);
|
|
39131
40054
|
try {
|
|
39132
40055
|
assertRealDirectory(dir, "knowledge pack");
|
|
39133
|
-
const metaPath =
|
|
39134
|
-
if (!
|
|
40056
|
+
const metaPath = join24(dir, "meta.json");
|
|
40057
|
+
if (!existsSync19(metaPath))
|
|
39135
40058
|
continue;
|
|
39136
40059
|
const meta = JSON.parse(readBoundedFileTextSyncNoFollow(metaPath, PACK_META_MAX_BYTES, "knowledge pack metadata"));
|
|
39137
40060
|
if (!validPackMeta(meta))
|
|
@@ -39155,14 +40078,14 @@ function latestPacks() {
|
|
|
39155
40078
|
}
|
|
39156
40079
|
function readRecords(dir) {
|
|
39157
40080
|
assertRealDirectory(dir, "knowledge pack");
|
|
39158
|
-
return readJsonl(
|
|
40081
|
+
return readJsonl(join24(dir, "records.jsonl"), "knowledge records");
|
|
39159
40082
|
}
|
|
39160
40083
|
function readEntities(dir) {
|
|
39161
40084
|
assertRealDirectory(dir, "knowledge pack");
|
|
39162
|
-
return readJsonl(
|
|
40085
|
+
return readJsonl(join24(dir, "entities.jsonl"), "knowledge entities");
|
|
39163
40086
|
}
|
|
39164
40087
|
function readJsonl(path, label) {
|
|
39165
|
-
if (!
|
|
40088
|
+
if (!existsSync19(path))
|
|
39166
40089
|
return [];
|
|
39167
40090
|
const out = [];
|
|
39168
40091
|
forEachFileLineSync(path, {
|
|
@@ -39183,7 +40106,7 @@ function readJsonl(path, label) {
|
|
|
39183
40106
|
return out;
|
|
39184
40107
|
}
|
|
39185
40108
|
function writeJsonl(path, values, label) {
|
|
39186
|
-
const descriptor =
|
|
40109
|
+
const descriptor = openSync5(path, "wx", 384);
|
|
39187
40110
|
let totalBytes = 0;
|
|
39188
40111
|
try {
|
|
39189
40112
|
for (const value of values) {
|
|
@@ -39196,7 +40119,7 @@ function writeJsonl(path, values, label) {
|
|
|
39196
40119
|
throw new Error(`${label} exceeded ${PACK_JSONL_MAX_BYTES} bytes`);
|
|
39197
40120
|
let offset = 0;
|
|
39198
40121
|
while (offset < line.byteLength) {
|
|
39199
|
-
const written =
|
|
40122
|
+
const written = writeSync2(descriptor, line, offset, line.byteLength - offset);
|
|
39200
40123
|
if (written <= 0)
|
|
39201
40124
|
throw new Error(`${label} write made no progress`);
|
|
39202
40125
|
offset += written;
|
|
@@ -39204,7 +40127,7 @@ function writeJsonl(path, values, label) {
|
|
|
39204
40127
|
}
|
|
39205
40128
|
fsyncSync2(descriptor);
|
|
39206
40129
|
} finally {
|
|
39207
|
-
|
|
40130
|
+
closeSync5(descriptor);
|
|
39208
40131
|
}
|
|
39209
40132
|
}
|
|
39210
40133
|
function validPackMeta(value) {
|
|
@@ -39215,21 +40138,21 @@ function assertPackPathPart(value, label) {
|
|
|
39215
40138
|
throw new Error(`${label} is invalid`);
|
|
39216
40139
|
}
|
|
39217
40140
|
function realDirectoryExists(path, label) {
|
|
39218
|
-
if (!
|
|
40141
|
+
if (!existsSync19(path))
|
|
39219
40142
|
return false;
|
|
39220
40143
|
assertRealDirectory(path, label);
|
|
39221
40144
|
return true;
|
|
39222
40145
|
}
|
|
39223
40146
|
function assertRealDirectory(path, label) {
|
|
39224
|
-
const stat =
|
|
40147
|
+
const stat = lstatSync5(path);
|
|
39225
40148
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
39226
40149
|
throw new Error(`${label} must be a real directory`);
|
|
39227
40150
|
}
|
|
39228
40151
|
function recordId(pack, pin, discriminator) {
|
|
39229
|
-
return
|
|
40152
|
+
return createHash11("sha256").update(`${pack}\x00${pin}\x00${discriminator}`).digest("hex").slice(0, 16);
|
|
39230
40153
|
}
|
|
39231
40154
|
function sourceHash(body) {
|
|
39232
|
-
return `sha256:${
|
|
40155
|
+
return `sha256:${createHash11("sha256").update(body).digest("hex")}`;
|
|
39233
40156
|
}
|
|
39234
40157
|
function extractEntities(recordId2, text2) {
|
|
39235
40158
|
const found = new Set;
|
|
@@ -39258,7 +40181,7 @@ var init_pack = __esm(() => {
|
|
|
39258
40181
|
init_atomic_file();
|
|
39259
40182
|
init_private_path();
|
|
39260
40183
|
init_file_read();
|
|
39261
|
-
|
|
40184
|
+
init_paths3();
|
|
39262
40185
|
PACK_META_MAX_BYTES = 1024 * 1024;
|
|
39263
40186
|
PACK_JSONL_MAX_BYTES = 256 * 1024 * 1024;
|
|
39264
40187
|
PACK_LINE_MAX_BYTES = 64 * 1024 * 1024;
|
|
@@ -39282,34 +40205,34 @@ var init_pack = __esm(() => {
|
|
|
39282
40205
|
});
|
|
39283
40206
|
|
|
39284
40207
|
// src/agent-knowledge/ingest/taxonomy-pack.ts
|
|
39285
|
-
import { closeSync as
|
|
39286
|
-
import { randomUUID as
|
|
39287
|
-
import { join as
|
|
40208
|
+
import { closeSync as closeSync6, existsSync as existsSync20, fsyncSync as fsyncSync3, lstatSync as lstatSync6, mkdirSync as mkdirSync9, openSync as openSync6, readdirSync as readdirSync8, renameSync as renameSync5, rmSync as rmSync5, writeSync as writeSync3 } from "fs";
|
|
40209
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
40210
|
+
import { join as join25 } from "path";
|
|
39288
40211
|
function writeTaxonomy(meta, nodes, edges) {
|
|
39289
40212
|
assertPathPart(meta.id, "taxonomy id");
|
|
39290
40213
|
assertPathPart(meta.pin, "taxonomy pin");
|
|
39291
40214
|
const root = taxonomyDir();
|
|
39292
40215
|
ensurePrivateDirectory(root, "knowledge taxonomy directory");
|
|
39293
|
-
const dir =
|
|
39294
|
-
const temporary = `${dir}.tmp-${process.pid}-${
|
|
39295
|
-
|
|
40216
|
+
const dir = join25(root, `${meta.id}@${meta.pin}`);
|
|
40217
|
+
const temporary = `${dir}.tmp-${process.pid}-${randomUUID6()}`;
|
|
40218
|
+
mkdirSync9(temporary, {
|
|
39296
40219
|
recursive: true,
|
|
39297
40220
|
mode: 448
|
|
39298
40221
|
});
|
|
39299
40222
|
try {
|
|
39300
|
-
atomicWriteFile(
|
|
40223
|
+
atomicWriteFile(join25(temporary, "meta.json"), `${JSON.stringify(meta, null, 2)}
|
|
39301
40224
|
`, 384);
|
|
39302
|
-
writeJsonl2(
|
|
39303
|
-
writeJsonl2(
|
|
40225
|
+
writeJsonl2(join25(temporary, "nodes.jsonl"), nodes, "taxonomy nodes");
|
|
40226
|
+
writeJsonl2(join25(temporary, "edges.jsonl"), edges, "taxonomy edges");
|
|
39304
40227
|
if (realDirectoryExists2(dir, "knowledge taxonomy"))
|
|
39305
|
-
|
|
40228
|
+
rmSync5(dir, {
|
|
39306
40229
|
recursive: true,
|
|
39307
40230
|
force: true
|
|
39308
40231
|
});
|
|
39309
|
-
|
|
40232
|
+
renameSync5(temporary, dir);
|
|
39310
40233
|
syncDirectory(root);
|
|
39311
40234
|
} catch (error) {
|
|
39312
|
-
|
|
40235
|
+
rmSync5(temporary, {
|
|
39313
40236
|
recursive: true,
|
|
39314
40237
|
force: true
|
|
39315
40238
|
});
|
|
@@ -39318,7 +40241,7 @@ function writeTaxonomy(meta, nodes, edges) {
|
|
|
39318
40241
|
return dir;
|
|
39319
40242
|
}
|
|
39320
40243
|
function writeJsonl2(path, values, label) {
|
|
39321
|
-
const descriptor =
|
|
40244
|
+
const descriptor = openSync6(path, "wx", 384);
|
|
39322
40245
|
let totalBytes = 0;
|
|
39323
40246
|
try {
|
|
39324
40247
|
for (const value of values) {
|
|
@@ -39331,7 +40254,7 @@ function writeJsonl2(path, values, label) {
|
|
|
39331
40254
|
throw new Error(`${label} exceeded ${TAXONOMY_JSONL_MAX_BYTES} bytes`);
|
|
39332
40255
|
let offset = 0;
|
|
39333
40256
|
while (offset < line.byteLength) {
|
|
39334
|
-
const written =
|
|
40257
|
+
const written = writeSync3(descriptor, line, offset, line.byteLength - offset);
|
|
39335
40258
|
if (written <= 0)
|
|
39336
40259
|
throw new Error(`${label} write made no progress`);
|
|
39337
40260
|
offset += written;
|
|
@@ -39339,24 +40262,24 @@ function writeJsonl2(path, values, label) {
|
|
|
39339
40262
|
}
|
|
39340
40263
|
fsyncSync3(descriptor);
|
|
39341
40264
|
} finally {
|
|
39342
|
-
|
|
40265
|
+
closeSync6(descriptor);
|
|
39343
40266
|
}
|
|
39344
40267
|
}
|
|
39345
40268
|
function listTaxonomies() {
|
|
39346
40269
|
const root = taxonomyDir();
|
|
39347
|
-
if (!
|
|
40270
|
+
if (!existsSync20(root))
|
|
39348
40271
|
return [];
|
|
39349
40272
|
assertRealDirectory2(root, "knowledge taxonomy directory");
|
|
39350
|
-
const entries =
|
|
40273
|
+
const entries = readdirSync8(root);
|
|
39351
40274
|
if (entries.length > TAXONOMY_DIRECTORY_MAX_COUNT)
|
|
39352
40275
|
throw new Error(`knowledge taxonomy directory exceeded ${TAXONOMY_DIRECTORY_MAX_COUNT} entries`);
|
|
39353
40276
|
const out = [];
|
|
39354
40277
|
for (const entry of entries) {
|
|
39355
|
-
const dir =
|
|
40278
|
+
const dir = join25(root, entry);
|
|
39356
40279
|
try {
|
|
39357
40280
|
assertRealDirectory2(dir, "knowledge taxonomy");
|
|
39358
|
-
const metaPath =
|
|
39359
|
-
if (!
|
|
40281
|
+
const metaPath = join25(dir, "meta.json");
|
|
40282
|
+
if (!existsSync20(metaPath))
|
|
39360
40283
|
continue;
|
|
39361
40284
|
const meta = JSON.parse(readBoundedFileTextSyncNoFollow(metaPath, TAXONOMY_META_MAX_BYTES, "taxonomy metadata"));
|
|
39362
40285
|
if (typeof meta?.id !== "string" || typeof meta.pin !== "string" || typeof meta.retrievedAt !== "string")
|
|
@@ -39380,14 +40303,14 @@ function latestTaxonomies() {
|
|
|
39380
40303
|
}
|
|
39381
40304
|
function readNodes(dir) {
|
|
39382
40305
|
assertRealDirectory2(dir, "knowledge taxonomy");
|
|
39383
|
-
return readJsonl2(
|
|
40306
|
+
return readJsonl2(join25(dir, "nodes.jsonl"));
|
|
39384
40307
|
}
|
|
39385
40308
|
function readEdges(dir) {
|
|
39386
40309
|
assertRealDirectory2(dir, "knowledge taxonomy");
|
|
39387
|
-
return readJsonl2(
|
|
40310
|
+
return readJsonl2(join25(dir, "edges.jsonl"));
|
|
39388
40311
|
}
|
|
39389
40312
|
function readJsonl2(path) {
|
|
39390
|
-
if (!
|
|
40313
|
+
if (!existsSync20(path))
|
|
39391
40314
|
return [];
|
|
39392
40315
|
const out = [];
|
|
39393
40316
|
forEachFileLineSync(path, {
|
|
@@ -39412,19 +40335,19 @@ function assertPathPart(value, label) {
|
|
|
39412
40335
|
throw new Error(`${label} is invalid`);
|
|
39413
40336
|
}
|
|
39414
40337
|
function realDirectoryExists2(path, label) {
|
|
39415
|
-
if (!
|
|
40338
|
+
if (!existsSync20(path))
|
|
39416
40339
|
return false;
|
|
39417
40340
|
assertRealDirectory2(path, label);
|
|
39418
40341
|
return true;
|
|
39419
40342
|
}
|
|
39420
40343
|
function assertRealDirectory2(path, label) {
|
|
39421
|
-
const stat =
|
|
40344
|
+
const stat = lstatSync6(path);
|
|
39422
40345
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
39423
40346
|
throw new Error(`${label} must be a real directory`);
|
|
39424
40347
|
}
|
|
39425
40348
|
var TAXONOMY_META_MAX_BYTES, TAXONOMY_JSONL_MAX_BYTES, TAXONOMY_LINE_MAX_BYTES, TAXONOMY_ENTRY_MAX_COUNT = 1e6, TAXONOMY_DIRECTORY_MAX_COUNT = 4096;
|
|
39426
40349
|
var init_taxonomy_pack = __esm(() => {
|
|
39427
|
-
|
|
40350
|
+
init_paths3();
|
|
39428
40351
|
init_file_read();
|
|
39429
40352
|
init_atomic_file();
|
|
39430
40353
|
init_private_path();
|
|
@@ -39467,16 +40390,16 @@ var init_http2 = __esm(() => {
|
|
|
39467
40390
|
});
|
|
39468
40391
|
|
|
39469
40392
|
// src/agent-knowledge/ingest/enrichment.ts
|
|
39470
|
-
import { createReadStream, existsSync as
|
|
40393
|
+
import { createReadStream, existsSync as existsSync21 } from "fs";
|
|
39471
40394
|
import { open as open3, rename, unlink as unlink2 } from "fs/promises";
|
|
39472
|
-
import { randomUUID as
|
|
40395
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
39473
40396
|
import { Writable } from "stream";
|
|
39474
40397
|
import { pipeline } from "stream/promises";
|
|
39475
40398
|
import { StringDecoder as StringDecoder3 } from "string_decoder";
|
|
39476
40399
|
import { createGunzip } from "zlib";
|
|
39477
|
-
import { join as
|
|
40400
|
+
import { join as join26 } from "path";
|
|
39478
40401
|
function enrichmentDir() {
|
|
39479
|
-
return
|
|
40402
|
+
return join26(knowledgeRoot(), "enrichment");
|
|
39480
40403
|
}
|
|
39481
40404
|
async function ingestEnrichment() {
|
|
39482
40405
|
const map = new Map;
|
|
@@ -39540,8 +40463,8 @@ async function ingestEnrichment() {
|
|
|
39540
40463
|
};
|
|
39541
40464
|
}
|
|
39542
40465
|
function readEnrichment() {
|
|
39543
|
-
const path =
|
|
39544
|
-
if (!
|
|
40466
|
+
const path = join26(enrichmentDir(), "enrichment.jsonl");
|
|
40467
|
+
if (!existsSync21(path))
|
|
39545
40468
|
return [];
|
|
39546
40469
|
const out = [];
|
|
39547
40470
|
forEachFileLineSync(path, {
|
|
@@ -39562,7 +40485,7 @@ function readEnrichment() {
|
|
|
39562
40485
|
return out;
|
|
39563
40486
|
}
|
|
39564
40487
|
async function forEachEpssLine(dir, consume) {
|
|
39565
|
-
const archive =
|
|
40488
|
+
const archive = join26(dir, `.epss-${randomUUID7()}.csv.gz`);
|
|
39566
40489
|
try {
|
|
39567
40490
|
await downloadKnowledgeFile(EPSS_URL, archive, EPSS_GZIP_MAX_BYTES, "epss archive");
|
|
39568
40491
|
await pipeline(createReadStream(archive), createGunzip(), new BoundedLineSink(EPSS_CSV_MAX_BYTES, EPSS_LINE_MAX_BYTES, consume));
|
|
@@ -39573,8 +40496,8 @@ async function forEachEpssLine(dir, consume) {
|
|
|
39573
40496
|
}
|
|
39574
40497
|
}
|
|
39575
40498
|
async function writeEnrichmentRows(dir, rows) {
|
|
39576
|
-
const output =
|
|
39577
|
-
const temporary =
|
|
40499
|
+
const output = join26(dir, "enrichment.jsonl");
|
|
40500
|
+
const temporary = join26(dir, `.enrichment-${randomUUID7()}.jsonl`);
|
|
39578
40501
|
let file;
|
|
39579
40502
|
try {
|
|
39580
40503
|
file = await open3(temporary, "wx", 384);
|
|
@@ -39635,7 +40558,7 @@ function recordValue2(value) {
|
|
|
39635
40558
|
}
|
|
39636
40559
|
var KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json", EPSS_URL = "https://epss.empiricalsecurity.com/epss_scores-current.csv.gz", KEV_MAX_BYTES, EPSS_GZIP_MAX_BYTES, EPSS_CSV_MAX_BYTES, EPSS_LINE_MAX_BYTES, OUTPUT_CHUNK_BYTES, ENRICHMENT_FILE_MAX_BYTES, KEV_ENTRY_MAX_COUNT = 1e5, ENRICHMENT_ROW_MAX_COUNT = 1e6, BoundedLineSink;
|
|
39637
40560
|
var init_enrichment = __esm(() => {
|
|
39638
|
-
|
|
40561
|
+
init_paths3();
|
|
39639
40562
|
init_http2();
|
|
39640
40563
|
init_file_read();
|
|
39641
40564
|
init_private_path();
|
|
@@ -39692,18 +40615,18 @@ var init_enrichment = __esm(() => {
|
|
|
39692
40615
|
});
|
|
39693
40616
|
|
|
39694
40617
|
// src/agent-knowledge/build.ts
|
|
39695
|
-
import { createHash as
|
|
39696
|
-
import { mkdirSync as
|
|
39697
|
-
import { dirname as
|
|
40618
|
+
import { createHash as createHash12, randomUUID as randomUUID8 } from "crypto";
|
|
40619
|
+
import { mkdirSync as mkdirSync10, renameSync as renameSync6, rmSync as rmSync6 } from "fs";
|
|
40620
|
+
import { dirname as dirname10 } from "path";
|
|
39698
40621
|
function buildKnowledgeDb(options = {}) {
|
|
39699
|
-
const path = options.path ??
|
|
39700
|
-
const temporary = `${path}.tmp-${process.pid}-${
|
|
39701
|
-
|
|
40622
|
+
const path = options.path ?? legacyKnowledgeDbPath();
|
|
40623
|
+
const temporary = `${path}.tmp-${process.pid}-${randomUUID8()}`;
|
|
40624
|
+
mkdirSync10(dirname10(path), {
|
|
39702
40625
|
recursive: true,
|
|
39703
40626
|
mode: 448
|
|
39704
40627
|
});
|
|
39705
40628
|
if (options.path === undefined)
|
|
39706
|
-
ensurePrivateDirectory(
|
|
40629
|
+
ensurePrivateDirectory(dirname10(path), "farai home directory");
|
|
39707
40630
|
ensurePrivateRegularFileIfExists(path, "knowledge database");
|
|
39708
40631
|
const store = new KnowledgeStore(temporary, true);
|
|
39709
40632
|
const db = store.writable();
|
|
@@ -39760,18 +40683,18 @@ function buildKnowledgeDb(options = {}) {
|
|
|
39760
40683
|
const actualEdges = rowCount(db, "kb_edges");
|
|
39761
40684
|
store.close();
|
|
39762
40685
|
ensurePrivateSqlitePath(temporary, "staged knowledge database");
|
|
39763
|
-
|
|
40686
|
+
rmSync6(`${temporary}-wal`, {
|
|
39764
40687
|
force: true
|
|
39765
40688
|
});
|
|
39766
|
-
|
|
40689
|
+
rmSync6(`${temporary}-shm`, {
|
|
39767
40690
|
force: true
|
|
39768
40691
|
});
|
|
39769
|
-
|
|
40692
|
+
rmSync6(`${temporary}-journal`, {
|
|
39770
40693
|
force: true
|
|
39771
40694
|
});
|
|
39772
|
-
|
|
40695
|
+
renameSync6(temporary, path);
|
|
39773
40696
|
ensurePrivateRegularFileIfExists(path, "knowledge database");
|
|
39774
|
-
syncDirectory(
|
|
40697
|
+
syncDirectory(dirname10(path));
|
|
39775
40698
|
return {
|
|
39776
40699
|
path,
|
|
39777
40700
|
packs: packs.length,
|
|
@@ -39786,16 +40709,16 @@ function buildKnowledgeDb(options = {}) {
|
|
|
39786
40709
|
try {
|
|
39787
40710
|
store.close();
|
|
39788
40711
|
} catch {}
|
|
39789
|
-
|
|
40712
|
+
rmSync6(temporary, {
|
|
39790
40713
|
force: true
|
|
39791
40714
|
});
|
|
39792
|
-
|
|
40715
|
+
rmSync6(`${temporary}-wal`, {
|
|
39793
40716
|
force: true
|
|
39794
40717
|
});
|
|
39795
|
-
|
|
40718
|
+
rmSync6(`${temporary}-shm`, {
|
|
39796
40719
|
force: true
|
|
39797
40720
|
});
|
|
39798
|
-
|
|
40721
|
+
rmSync6(`${temporary}-journal`, {
|
|
39799
40722
|
force: true
|
|
39800
40723
|
});
|
|
39801
40724
|
throw error;
|
|
@@ -39819,7 +40742,7 @@ function trackDuplicate(groups, record3) {
|
|
|
39819
40742
|
const normalized = record3.answer.replace(/\s+/g, " ").trim().toLowerCase();
|
|
39820
40743
|
if (normalized.length < 64)
|
|
39821
40744
|
return;
|
|
39822
|
-
const key =
|
|
40745
|
+
const key = createHash12("sha256").update(normalized).digest("hex");
|
|
39823
40746
|
const list = groups.get(key) ?? [];
|
|
39824
40747
|
list.push(record3.id);
|
|
39825
40748
|
groups.set(key, list);
|
|
@@ -39842,24 +40765,24 @@ var init_build = __esm(() => {
|
|
|
39842
40765
|
init_atomic_file();
|
|
39843
40766
|
init_private_path();
|
|
39844
40767
|
init_store();
|
|
39845
|
-
|
|
40768
|
+
init_paths3();
|
|
39846
40769
|
init_pack();
|
|
39847
40770
|
init_taxonomy_pack();
|
|
39848
40771
|
init_enrichment();
|
|
39849
40772
|
});
|
|
39850
40773
|
|
|
39851
40774
|
// src/agent-knowledge/ingest/git-source.ts
|
|
39852
|
-
import { existsSync as
|
|
39853
|
-
import { randomUUID as
|
|
39854
|
-
import { join as
|
|
40775
|
+
import { existsSync as existsSync22, lstatSync as lstatSync7, renameSync as renameSync7, rmSync as rmSync7 } from "fs";
|
|
40776
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
40777
|
+
import { join as join27 } from "path";
|
|
39855
40778
|
async function fetchGitSource(source) {
|
|
39856
40779
|
assertSource(source);
|
|
39857
40780
|
const root = cacheDir();
|
|
39858
40781
|
ensurePrivateDirectory(root, "knowledge cache directory");
|
|
39859
|
-
const dir =
|
|
40782
|
+
const dir = join27(root, source.id);
|
|
39860
40783
|
const cached = cachedRepositoryExists(dir);
|
|
39861
40784
|
if (!cached) {
|
|
39862
|
-
const staging =
|
|
40785
|
+
const staging = join27(root, `.${source.id}-clone-${randomUUID9()}`);
|
|
39863
40786
|
try {
|
|
39864
40787
|
const args = ["clone", "--depth", "1", "--branch", source.branch];
|
|
39865
40788
|
if (source.sparse?.length)
|
|
@@ -39868,9 +40791,9 @@ async function fetchGitSource(source) {
|
|
|
39868
40791
|
await run("git", args);
|
|
39869
40792
|
if (source.sparse?.length)
|
|
39870
40793
|
await run("git", ["-C", staging, "sparse-checkout", "set", "--no-cone", "--", ...source.sparse]);
|
|
39871
|
-
|
|
40794
|
+
renameSync7(staging, dir);
|
|
39872
40795
|
} finally {
|
|
39873
|
-
|
|
40796
|
+
rmSync7(staging, {
|
|
39874
40797
|
recursive: true,
|
|
39875
40798
|
force: true
|
|
39876
40799
|
});
|
|
@@ -39938,22 +40861,22 @@ function assertSource(source) {
|
|
|
39938
40861
|
throw new Error(`invalid sparse path for git source: ${source.id}`);
|
|
39939
40862
|
}
|
|
39940
40863
|
function cachedRepositoryExists(dir) {
|
|
39941
|
-
if (!
|
|
40864
|
+
if (!existsSync22(dir))
|
|
39942
40865
|
return false;
|
|
39943
|
-
const directory =
|
|
40866
|
+
const directory = lstatSync7(dir);
|
|
39944
40867
|
if (directory.isSymbolicLink() || !directory.isDirectory())
|
|
39945
40868
|
throw new Error(`git source cache must be a real directory: ${dir}`);
|
|
39946
|
-
const git =
|
|
39947
|
-
if (!
|
|
40869
|
+
const git = join27(dir, ".git");
|
|
40870
|
+
if (!existsSync22(git))
|
|
39948
40871
|
throw new Error(`git source cache is not a repository: ${dir}`);
|
|
39949
|
-
const metadata =
|
|
40872
|
+
const metadata = lstatSync7(git);
|
|
39950
40873
|
if (metadata.isSymbolicLink() || !metadata.isDirectory())
|
|
39951
40874
|
throw new Error(`git source metadata must be a real directory: ${dir}`);
|
|
39952
40875
|
return true;
|
|
39953
40876
|
}
|
|
39954
40877
|
var GIT_TIMEOUT_MS;
|
|
39955
40878
|
var init_git_source = __esm(() => {
|
|
39956
|
-
|
|
40879
|
+
init_paths3();
|
|
39957
40880
|
init_captured_process();
|
|
39958
40881
|
init_output_buffer();
|
|
39959
40882
|
init_private_path();
|
|
@@ -40065,11 +40988,11 @@ var init_markdown_chunk = __esm(() => {
|
|
|
40065
40988
|
});
|
|
40066
40989
|
|
|
40067
40990
|
// src/agent-knowledge/ingest/hacktricks.ts
|
|
40068
|
-
import { existsSync as
|
|
40069
|
-
import { join as
|
|
40991
|
+
import { existsSync as existsSync23, lstatSync as lstatSync8, readdirSync as readdirSync9 } from "fs";
|
|
40992
|
+
import { join as join28, relative as relative8 } from "path";
|
|
40070
40993
|
async function ingestHacktricks() {
|
|
40071
40994
|
const fetched = await fetchGitSource(SOURCE);
|
|
40072
|
-
const srcDir =
|
|
40995
|
+
const srcDir = join28(fetched.dir, "src");
|
|
40073
40996
|
const meta = {
|
|
40074
40997
|
id: "hacktricks",
|
|
40075
40998
|
sourceUrl: "https://github.com/HackTricks-wiki/hacktricks",
|
|
@@ -40121,9 +41044,9 @@ async function ingestHacktricks() {
|
|
|
40121
41044
|
};
|
|
40122
41045
|
}
|
|
40123
41046
|
function markdownFiles(root) {
|
|
40124
|
-
if (!
|
|
41047
|
+
if (!existsSync23(root))
|
|
40125
41048
|
return [];
|
|
40126
|
-
const rootInfo =
|
|
41049
|
+
const rootInfo = lstatSync8(root);
|
|
40127
41050
|
if (rootInfo.isSymbolicLink() || !rootInfo.isDirectory())
|
|
40128
41051
|
throw new Error("hacktricks source root must be a real directory");
|
|
40129
41052
|
const out = [];
|
|
@@ -40131,12 +41054,12 @@ function markdownFiles(root) {
|
|
|
40131
41054
|
let entries = 0;
|
|
40132
41055
|
while (pending.length) {
|
|
40133
41056
|
const dir = pending.pop();
|
|
40134
|
-
for (const entry of
|
|
41057
|
+
for (const entry of readdirSync9(dir)) {
|
|
40135
41058
|
entries += 1;
|
|
40136
41059
|
if (entries > WALK_ENTRY_MAX_COUNT)
|
|
40137
41060
|
throw new Error(`hacktricks source exceeded ${WALK_ENTRY_MAX_COUNT} entries`);
|
|
40138
|
-
const full =
|
|
40139
|
-
const info =
|
|
41061
|
+
const full = join28(dir, entry);
|
|
41062
|
+
const info = lstatSync8(full);
|
|
40140
41063
|
if (info.isSymbolicLink())
|
|
40141
41064
|
continue;
|
|
40142
41065
|
if (info.isDirectory())
|
|
@@ -40166,8 +41089,8 @@ var init_hacktricks = __esm(() => {
|
|
|
40166
41089
|
});
|
|
40167
41090
|
|
|
40168
41091
|
// src/agent-knowledge/ingest/payloads.ts
|
|
40169
|
-
import { existsSync as
|
|
40170
|
-
import { join as
|
|
41092
|
+
import { existsSync as existsSync24, lstatSync as lstatSync9, readdirSync as readdirSync10 } from "fs";
|
|
41093
|
+
import { join as join29, relative as relative9 } from "path";
|
|
40171
41094
|
async function ingestPayloads() {
|
|
40172
41095
|
const fetched = await fetchGitSource(SOURCE2);
|
|
40173
41096
|
const meta = {
|
|
@@ -40223,9 +41146,9 @@ async function ingestPayloads() {
|
|
|
40223
41146
|
};
|
|
40224
41147
|
}
|
|
40225
41148
|
function markdownFiles2(root) {
|
|
40226
|
-
if (!
|
|
41149
|
+
if (!existsSync24(root))
|
|
40227
41150
|
return [];
|
|
40228
|
-
const rootInfo =
|
|
41151
|
+
const rootInfo = lstatSync9(root);
|
|
40229
41152
|
if (rootInfo.isSymbolicLink() || !rootInfo.isDirectory())
|
|
40230
41153
|
throw new Error("payload source root must be a real directory");
|
|
40231
41154
|
const out = [];
|
|
@@ -40233,14 +41156,14 @@ function markdownFiles2(root) {
|
|
|
40233
41156
|
let entries = 0;
|
|
40234
41157
|
while (pending.length) {
|
|
40235
41158
|
const dir = pending.pop();
|
|
40236
|
-
for (const entry of
|
|
41159
|
+
for (const entry of readdirSync10(dir)) {
|
|
40237
41160
|
if (entry === ".git")
|
|
40238
41161
|
continue;
|
|
40239
41162
|
entries += 1;
|
|
40240
41163
|
if (entries > WALK_ENTRY_MAX_COUNT2)
|
|
40241
41164
|
throw new Error(`payload source exceeded ${WALK_ENTRY_MAX_COUNT2} entries`);
|
|
40242
|
-
const full =
|
|
40243
|
-
const info =
|
|
41165
|
+
const full = join29(dir, entry);
|
|
41166
|
+
const info = lstatSync9(full);
|
|
40244
41167
|
if (info.isSymbolicLink())
|
|
40245
41168
|
continue;
|
|
40246
41169
|
if (info.isDirectory())
|
|
@@ -40482,15 +41405,15 @@ var init_attack = __esm(() => {
|
|
|
40482
41405
|
});
|
|
40483
41406
|
|
|
40484
41407
|
// src/agent-knowledge/ingest/zip-fetch.ts
|
|
40485
|
-
import { existsSync as
|
|
40486
|
-
import { randomUUID as
|
|
40487
|
-
import { basename as basename5, join as
|
|
41408
|
+
import { existsSync as existsSync25, lstatSync as lstatSync10, mkdirSync as mkdirSync11, readdirSync as readdirSync11, renameSync as renameSync8, rmSync as rmSync8, unlinkSync as unlinkSync7 } from "fs";
|
|
41409
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
41410
|
+
import { basename as basename5, join as join30, relative as relative10, resolve as resolve10 } from "path";
|
|
40488
41411
|
async function fetchZippedXml(id2, url, pattern) {
|
|
40489
|
-
const dir =
|
|
41412
|
+
const dir = join30(cacheDir(), id2);
|
|
40490
41413
|
ensurePrivateDirectory(dir, `${id2} knowledge cache directory`);
|
|
40491
|
-
const token =
|
|
40492
|
-
const zipPath =
|
|
40493
|
-
const staging =
|
|
41414
|
+
const token = randomUUID10();
|
|
41415
|
+
const zipPath = join30(dir, `.download-${token}.zip`);
|
|
41416
|
+
const staging = join30(dir, `.extract-${token}`);
|
|
40494
41417
|
try {
|
|
40495
41418
|
await downloadKnowledgeFile(url, zipPath, ZIP_MAX_BYTES, `${id2} zip archive`);
|
|
40496
41419
|
const entries = await listArchiveEntries(zipPath);
|
|
@@ -40500,7 +41423,7 @@ async function fetchZippedXml(id2, url, pattern) {
|
|
|
40500
41423
|
const declaredSize = await archiveEntrySize(zipPath, selected);
|
|
40501
41424
|
if (declaredSize > XML_MAX_BYTES)
|
|
40502
41425
|
throw new Error(`${id2} xml exceeded the ${XML_MAX_BYTES}-byte expanded limit`);
|
|
40503
|
-
|
|
41426
|
+
mkdirSync11(staging, {
|
|
40504
41427
|
recursive: true
|
|
40505
41428
|
});
|
|
40506
41429
|
const extracted = await runCapturedProcess("unzip", ["-o", "-q", zipPath, selected, "-d", staging], {
|
|
@@ -40511,26 +41434,26 @@ async function fetchZippedXml(id2, url, pattern) {
|
|
|
40511
41434
|
throw new Error(`${id2} archive extraction timed out`);
|
|
40512
41435
|
if (extracted.exitCode !== 0)
|
|
40513
41436
|
throw new Error(extracted.stderr.trim() || `${id2} archive extraction failed`);
|
|
40514
|
-
const stagedPath =
|
|
41437
|
+
const stagedPath = resolve10(staging, selected);
|
|
40515
41438
|
const stagedRelative = relative10(staging, stagedPath);
|
|
40516
41439
|
if (stagedRelative.startsWith("..") || stagedRelative.startsWith("/"))
|
|
40517
41440
|
throw new Error(`${id2} archive entry escaped the extraction directory`);
|
|
40518
|
-
const info =
|
|
41441
|
+
const info = lstatSync10(stagedPath);
|
|
40519
41442
|
if (!info.isFile() || info.isSymbolicLink())
|
|
40520
41443
|
throw new Error(`${id2} archive entry was not a regular file`);
|
|
40521
41444
|
if (info.size > XML_MAX_BYTES || info.size !== declaredSize)
|
|
40522
41445
|
throw new Error(`${id2} archive entry size did not match its validated metadata`);
|
|
40523
|
-
const path =
|
|
40524
|
-
|
|
41446
|
+
const path = join30(dir, `${id2}.xml`);
|
|
41447
|
+
renameSync8(stagedPath, path);
|
|
40525
41448
|
return {
|
|
40526
41449
|
xml: readBoundedXml(path),
|
|
40527
41450
|
path
|
|
40528
41451
|
};
|
|
40529
41452
|
} finally {
|
|
40530
41453
|
try {
|
|
40531
|
-
|
|
41454
|
+
unlinkSync7(zipPath);
|
|
40532
41455
|
} catch {}
|
|
40533
|
-
|
|
41456
|
+
rmSync8(staging, {
|
|
40534
41457
|
recursive: true,
|
|
40535
41458
|
force: true
|
|
40536
41459
|
});
|
|
@@ -40588,7 +41511,7 @@ function readBoundedXml(path) {
|
|
|
40588
41511
|
}
|
|
40589
41512
|
var ZIP_MAX_BYTES, XML_MAX_BYTES, ZIP_LIST_MAX_BYTES, ZIP_ENTRY_MAX_COUNT = 4096, UNZIP_TIMEOUT_MS = 60000;
|
|
40590
41513
|
var init_zip_fetch = __esm(() => {
|
|
40591
|
-
|
|
41514
|
+
init_paths3();
|
|
40592
41515
|
init_http2();
|
|
40593
41516
|
init_captured_process();
|
|
40594
41517
|
init_file_read();
|
|
@@ -40891,7 +41814,7 @@ var init_command = __esm(() => {
|
|
|
40891
41814
|
init_pack();
|
|
40892
41815
|
init_taxonomy_pack();
|
|
40893
41816
|
init_store();
|
|
40894
|
-
|
|
41817
|
+
init_paths3();
|
|
40895
41818
|
init_hacktricks();
|
|
40896
41819
|
init_payloads();
|
|
40897
41820
|
init_attack();
|
|
@@ -40911,6 +41834,80 @@ var init_command = __esm(() => {
|
|
|
40911
41834
|
CORPUS_INGEST = new Set(["hacktricks", "payloads", ...TAXONOMY_INGEST]);
|
|
40912
41835
|
});
|
|
40913
41836
|
|
|
41837
|
+
// src/agent-content/preflight.ts
|
|
41838
|
+
var exports_preflight = {};
|
|
41839
|
+
__export(exports_preflight, {
|
|
41840
|
+
runStartupContentPreflight: () => runStartupContentPreflight
|
|
41841
|
+
});
|
|
41842
|
+
import { createInterface } from "readline";
|
|
41843
|
+
async function runStartupContentPreflight(workspace) {
|
|
41844
|
+
const status2 = await checkContentUpdate({
|
|
41845
|
+
workspace
|
|
41846
|
+
});
|
|
41847
|
+
if (status2.state !== "update_available" || !status2.manifest)
|
|
41848
|
+
return "continue";
|
|
41849
|
+
if (isContentVersionDismissed(status2.manifest.contentVersion))
|
|
41850
|
+
return "continue";
|
|
41851
|
+
const config = loadConfig(workspace);
|
|
41852
|
+
if (config.updates?.prompt === false || !process.stdin.isTTY || !process.stdout.isTTY)
|
|
41853
|
+
return "continue";
|
|
41854
|
+
const answer = await promptForUpdate(status2.manifest.contentVersion, Boolean(status2.manifest.knowledge), Boolean(status2.manifest.skills));
|
|
41855
|
+
if (answer === "cancelled")
|
|
41856
|
+
return "cancelled";
|
|
41857
|
+
if (answer === "dismiss") {
|
|
41858
|
+
dismissContentVersion(status2.manifest.contentVersion);
|
|
41859
|
+
return "continue";
|
|
41860
|
+
}
|
|
41861
|
+
if (answer === "later")
|
|
41862
|
+
return "continue";
|
|
41863
|
+
console.log("updating farai content...");
|
|
41864
|
+
try {
|
|
41865
|
+
const applied = await applyContentUpdate(status2.manifest, status2.manifestUrl);
|
|
41866
|
+
const parts = [applied.knowledge ? "knowledge" : undefined, applied.skills ? "skills" : undefined].filter(Boolean).join(" + ");
|
|
41867
|
+
console.log(`updated farai content to ${applied.version}${parts ? ` (${parts})` : ""}`);
|
|
41868
|
+
} catch (error) {
|
|
41869
|
+
console.error(`content update failed: ${errorMessage7(error)}`);
|
|
41870
|
+
console.error("starting farai with the current content");
|
|
41871
|
+
}
|
|
41872
|
+
return "continue";
|
|
41873
|
+
}
|
|
41874
|
+
async function promptForUpdate(version, knowledge, skills) {
|
|
41875
|
+
const contents = [knowledge ? "knowledge" : undefined, skills ? "skills" : undefined].filter(Boolean).join(" + ");
|
|
41876
|
+
console.log("");
|
|
41877
|
+
console.log(`farai content ${version} is available${contents ? ` (${contents})` : ""}`);
|
|
41878
|
+
const interfaceHandle = createInterface({
|
|
41879
|
+
input: process.stdin,
|
|
41880
|
+
output: process.stdout
|
|
41881
|
+
});
|
|
41882
|
+
return await new Promise((resolve11) => {
|
|
41883
|
+
let settled = false;
|
|
41884
|
+
const finish = (value) => {
|
|
41885
|
+
if (settled)
|
|
41886
|
+
return;
|
|
41887
|
+
settled = true;
|
|
41888
|
+
interfaceHandle.close();
|
|
41889
|
+
resolve11(value);
|
|
41890
|
+
};
|
|
41891
|
+
interfaceHandle.once("SIGINT", () => finish("cancelled"));
|
|
41892
|
+
interfaceHandle.question("update before starting? [enter=yes, n=later, d=skip version] ", (value) => {
|
|
41893
|
+
const normalized = value.trim().toLowerCase();
|
|
41894
|
+
if (normalized === "d" || normalized === "dismiss")
|
|
41895
|
+
finish("dismiss");
|
|
41896
|
+
else if (normalized === "n" || normalized === "no")
|
|
41897
|
+
finish("later");
|
|
41898
|
+
else
|
|
41899
|
+
finish("apply");
|
|
41900
|
+
});
|
|
41901
|
+
});
|
|
41902
|
+
}
|
|
41903
|
+
function errorMessage7(error) {
|
|
41904
|
+
return error instanceof Error ? error.message : String(error);
|
|
41905
|
+
}
|
|
41906
|
+
var init_preflight = __esm(() => {
|
|
41907
|
+
init_config();
|
|
41908
|
+
init_updater();
|
|
41909
|
+
});
|
|
41910
|
+
|
|
40914
41911
|
// node_modules/solid-js/dist/solid.js
|
|
40915
41912
|
function getContextId(count2) {
|
|
40916
41913
|
const num2 = String(count2), len = num2.length - 1;
|
|
@@ -47978,7 +48975,7 @@ function presentToolActivity(input) {
|
|
|
47978
48975
|
const text2 = active ? input.liveOutput ?? input.result ?? "" : input.result ?? input.fullResult ?? "";
|
|
47979
48976
|
const metadata = input.toolResult?.metadata ?? {};
|
|
47980
48977
|
const family = toolFamily(tool);
|
|
47981
|
-
const title = toolTitle(tool, args, input.status, 240);
|
|
48978
|
+
const title = tool === "email_wait" && !active && metadata.timedOut === true ? emailWaitTimeoutTitle(args) : toolTitle(tool, args, input.status, 240);
|
|
47982
48979
|
const warning = hasWarning(input.toolResult, text2);
|
|
47983
48980
|
const preview = toolPreview(tool, args, text2, metadata, active);
|
|
47984
48981
|
const outcome = toolOutcome(tool, args, text2, metadata, input.toolResult, active);
|
|
@@ -48137,6 +49134,10 @@ function compactActivityLabel(tool, args, title) {
|
|
|
48137
49134
|
return `flow ${stringValue2(args.flowId) ?? "request"}`;
|
|
48138
49135
|
return title;
|
|
48139
49136
|
}
|
|
49137
|
+
function emailWaitTimeoutTitle(args) {
|
|
49138
|
+
const filter = stringValue2(args.subject) ?? stringValue2(args.from);
|
|
49139
|
+
return truncateTerminal(`no matching email${filter ? ` \xB7 ${filter}` : ""}`, 240);
|
|
49140
|
+
}
|
|
48140
49141
|
function toolOutcome(tool, args, text2, metadata, result, active) {
|
|
48141
49142
|
if (active)
|
|
48142
49143
|
return liveOutcome(text2);
|
|
@@ -48408,6 +49409,8 @@ function proxyOutcome(metadata, summary2, text2) {
|
|
|
48408
49409
|
function hasWarning(result, text2) {
|
|
48409
49410
|
if (!result)
|
|
48410
49411
|
return false;
|
|
49412
|
+
if (result.metadata?.emailAction === "wait" && result.metadata.timedOut === true)
|
|
49413
|
+
return true;
|
|
48411
49414
|
if (result.metadata?.exactProtocolVerificationRequired === true || result.metadata?.snapshotError)
|
|
48412
49415
|
return true;
|
|
48413
49416
|
if (arrayValue2(result.metadata?.failures).length > 0)
|
|
@@ -48498,6 +49501,7 @@ function formatBytes(bytes) {
|
|
|
48498
49501
|
var BROWSER_TOOLS, WORKSPACE_TOOLS, RECON_TOOLS, HTTP_TOOLS;
|
|
48499
49502
|
var init_tool_activity = __esm(() => {
|
|
48500
49503
|
init_tool_names();
|
|
49504
|
+
init_terminal_text();
|
|
48501
49505
|
init_tool_presentation();
|
|
48502
49506
|
BROWSER_TOOLS = new Set(["browser_navigate", "browser_snapshot", "browser_find", "browser_click", "browser_fill_form", "browser_type", "browser_press_key", "browser_wait_for", "browser_tabs", "browser_network_requests", "browser_network_request"]);
|
|
48503
49507
|
WORKSPACE_TOOLS = new Set(["fs_read", "fs_list", "fs_grep", "fs_write", "fs_edit", "patch_apply", "notebook_edit", "git_status", "git_diff", "lsp_inspect", "tool_output_read", "code_write_script"]);
|
|
@@ -49524,10 +50528,10 @@ function artifactRow(part, width) {
|
|
|
49524
50528
|
return row;
|
|
49525
50529
|
}
|
|
49526
50530
|
const note = extractObject(payload, "note");
|
|
49527
|
-
const
|
|
49528
|
-
const title = artifactTitle(kind, note,
|
|
49529
|
-
const detail = firstSemanticLine(stringField2(note, "text")) ?? stringField2(
|
|
49530
|
-
const body = artifactBody(payload, note,
|
|
50531
|
+
const artifact2 = extractObject(payload, "artifact") ?? extractObject(payload, "outputArtifact");
|
|
50532
|
+
const title = artifactTitle(kind, note, artifact2);
|
|
50533
|
+
const detail = firstSemanticLine(stringField2(note, "text")) ?? stringField2(artifact2, "path") ?? extractField(payload, "path") ?? extractField(payload, "title") ?? humanLabel(kind);
|
|
50534
|
+
const body = artifactBody(payload, note, artifact2);
|
|
49531
50535
|
return {
|
|
49532
50536
|
kind: "artifact",
|
|
49533
50537
|
title,
|
|
@@ -49538,8 +50542,8 @@ function artifactRow(part, width) {
|
|
|
49538
50542
|
id: part.id
|
|
49539
50543
|
};
|
|
49540
50544
|
}
|
|
49541
|
-
function artifactBody(payload, note,
|
|
49542
|
-
const candidates = [stringField2(note, "text"), stringField2(
|
|
50545
|
+
function artifactBody(payload, note, artifact2) {
|
|
50546
|
+
const candidates = [stringField2(note, "text"), stringField2(artifact2, "content"), stringField2(artifact2, "body"), stringField2(artifact2, "text"), stringField2(artifact2, "summary"), stringField2(artifact2, "output"), extractField(payload, "content"), extractField(payload, "body"), extractField(payload, "text"), extractField(payload, "summary"), extractField(payload, "output")];
|
|
49543
50547
|
return candidates.find((value) => Boolean(value?.trim()))?.trim();
|
|
49544
50548
|
}
|
|
49545
50549
|
function firstSemanticLine(value) {
|
|
@@ -49554,10 +50558,10 @@ function mcpInventoryRow(part, width) {
|
|
|
49554
50558
|
id: part.id
|
|
49555
50559
|
};
|
|
49556
50560
|
}
|
|
49557
|
-
function artifactTitle(kind, note,
|
|
50561
|
+
function artifactTitle(kind, note, artifact2) {
|
|
49558
50562
|
if (stringField2(note, "text"))
|
|
49559
50563
|
return "saved note";
|
|
49560
|
-
if (stringField2(
|
|
50564
|
+
if (stringField2(artifact2, "path"))
|
|
49561
50565
|
return "saved artifact";
|
|
49562
50566
|
return humanLabel(kind);
|
|
49563
50567
|
}
|
|
@@ -50133,7 +51137,7 @@ function createStoreResourceController(input) {
|
|
|
50133
51137
|
actions.servicesSet(services.value);
|
|
50134
51138
|
if (catalog.status === "fulfilled")
|
|
50135
51139
|
actions.mcpCatalogSet(catalog.value.servers, catalog.value.statuses);
|
|
50136
|
-
const errors = [refreshError, services.status === "rejected" ?
|
|
51140
|
+
const errors = [refreshError, services.status === "rejected" ? errorMessage8(services.reason) : undefined, catalog.status === "rejected" ? errorMessage8(catalog.reason) : undefined].filter((message) => Boolean(message));
|
|
50137
51141
|
actions.mcpStatusErrorSet(errors.length ? [...new Set(errors)].join(" \xB7 ") : undefined);
|
|
50138
51142
|
} finally {
|
|
50139
51143
|
if (mcpOverlayGeneration === generation && sessions2.owns(owner) && store.ui.statusDetail === "refreshing mcp") {
|
|
@@ -50155,7 +51159,7 @@ function createStoreResourceController(input) {
|
|
|
50155
51159
|
actions.emailCatalogSet(catalog.accounts);
|
|
50156
51160
|
} catch (error) {
|
|
50157
51161
|
if (emailOverlayGeneration === generation && sessions2.owns(owner))
|
|
50158
|
-
actions.errorSet(
|
|
51162
|
+
actions.errorSet(errorMessage8(error));
|
|
50159
51163
|
} finally {
|
|
50160
51164
|
if (emailOverlayGeneration === generation && sessions2.owns(owner) && store.ui.statusDetail === "loading email") {
|
|
50161
51165
|
input.setStatusDetail(undefined);
|
|
@@ -50201,7 +51205,7 @@ function createStoreResourceController(input) {
|
|
|
50201
51205
|
if (!sessions2.owns(owner))
|
|
50202
51206
|
return;
|
|
50203
51207
|
if (options.reportError !== false) {
|
|
50204
|
-
actions.errorSet(
|
|
51208
|
+
actions.errorSet(errorMessage8(error));
|
|
50205
51209
|
return;
|
|
50206
51210
|
}
|
|
50207
51211
|
throw error;
|
|
@@ -50244,7 +51248,7 @@ function containerState(imageExists, imageContractCurrent, persistentRunning, pe
|
|
|
50244
51248
|
return "missing";
|
|
50245
51249
|
return persistentRunning && persistentImageCurrent ? "running" : "stopped";
|
|
50246
51250
|
}
|
|
50247
|
-
function
|
|
51251
|
+
function errorMessage8(error) {
|
|
50248
51252
|
return error instanceof Error ? error.message : String(error);
|
|
50249
51253
|
}
|
|
50250
51254
|
|
|
@@ -50288,7 +51292,7 @@ function createStorePromptController(input) {
|
|
|
50288
51292
|
await port.prompt(sessionId, text2);
|
|
50289
51293
|
} catch (error) {
|
|
50290
51294
|
if (isActiveSession(sessionId))
|
|
50291
|
-
actions.errorSet(
|
|
51295
|
+
actions.errorSet(errorMessage9(error));
|
|
50292
51296
|
} finally {
|
|
50293
51297
|
if (submissions.get(sessionId) !== submission)
|
|
50294
51298
|
return;
|
|
@@ -50300,7 +51304,7 @@ function createStorePromptController(input) {
|
|
|
50300
51304
|
await sessions2.requestSnapshotRefresh(sessionId);
|
|
50301
51305
|
} catch (error) {
|
|
50302
51306
|
if (isActiveSession(sessionId))
|
|
50303
|
-
actions.errorSet(
|
|
51307
|
+
actions.errorSet(errorMessage9(error));
|
|
50304
51308
|
}
|
|
50305
51309
|
}
|
|
50306
51310
|
})();
|
|
@@ -50323,7 +51327,7 @@ function createStorePromptController(input) {
|
|
|
50323
51327
|
return submitted;
|
|
50324
51328
|
} catch (error) {
|
|
50325
51329
|
if (sessions2.owns(owner))
|
|
50326
|
-
actions.errorSet(
|
|
51330
|
+
actions.errorSet(errorMessage9(error));
|
|
50327
51331
|
return false;
|
|
50328
51332
|
} finally {
|
|
50329
51333
|
if (sessions2.owns(owner) && store.ui.statusDetail === status2)
|
|
@@ -50350,7 +51354,7 @@ function createStorePromptController(input) {
|
|
|
50350
51354
|
} catch (error) {
|
|
50351
51355
|
if (sessions2.owns(owner) && store.snapshot.pendingUserInput?.id === requestId) {
|
|
50352
51356
|
actions.requestUserInputSubmittingSet(false);
|
|
50353
|
-
actions.errorSet(
|
|
51357
|
+
actions.errorSet(errorMessage9(error));
|
|
50354
51358
|
}
|
|
50355
51359
|
return false;
|
|
50356
51360
|
}
|
|
@@ -50393,7 +51397,7 @@ function createStorePromptController(input) {
|
|
|
50393
51397
|
await sessions2.requestSnapshotRefresh(owner.sessionId);
|
|
50394
51398
|
} catch (error) {
|
|
50395
51399
|
if (sessions2.owns(owner) && store.snapshot.pendingUserInput?.id === requestId)
|
|
50396
|
-
actions.errorSet(
|
|
51400
|
+
actions.errorSet(errorMessage9(error));
|
|
50397
51401
|
}
|
|
50398
51402
|
}
|
|
50399
51403
|
function queuePrompt(text2) {
|
|
@@ -50411,7 +51415,7 @@ function createStorePromptController(input) {
|
|
|
50411
51415
|
return true;
|
|
50412
51416
|
} catch (error) {
|
|
50413
51417
|
if (owner && sessions2.owns(owner))
|
|
50414
|
-
actions.errorSet(
|
|
51418
|
+
actions.errorSet(errorMessage9(error));
|
|
50415
51419
|
return false;
|
|
50416
51420
|
}
|
|
50417
51421
|
}
|
|
@@ -50437,7 +51441,7 @@ function createStorePromptController(input) {
|
|
|
50437
51441
|
} catch (error) {
|
|
50438
51442
|
if (!sessions2.owns(owner))
|
|
50439
51443
|
return;
|
|
50440
|
-
const message =
|
|
51444
|
+
const message = errorMessage9(error);
|
|
50441
51445
|
if (!/abort|cancel/i.test(message))
|
|
50442
51446
|
actions.errorSet(message);
|
|
50443
51447
|
} finally {
|
|
@@ -50462,7 +51466,7 @@ function createStorePromptController(input) {
|
|
|
50462
51466
|
input.setStatusDetail("conversation cleared", 1500);
|
|
50463
51467
|
} catch (error) {
|
|
50464
51468
|
if (sessions2.owns(owner))
|
|
50465
|
-
actions.errorSet(
|
|
51469
|
+
actions.errorSet(errorMessage9(error));
|
|
50466
51470
|
}
|
|
50467
51471
|
}
|
|
50468
51472
|
async function cancelCurrentTurn() {
|
|
@@ -50485,7 +51489,7 @@ function createStorePromptController(input) {
|
|
|
50485
51489
|
await port.cancelTurn(turnId, "cancelled by user");
|
|
50486
51490
|
} catch (error) {
|
|
50487
51491
|
if (sessions2.owns(owner))
|
|
50488
|
-
actions.errorSet(
|
|
51492
|
+
actions.errorSet(errorMessage9(error));
|
|
50489
51493
|
}
|
|
50490
51494
|
if (!sessions2.owns(owner))
|
|
50491
51495
|
return;
|
|
@@ -50493,7 +51497,7 @@ function createStorePromptController(input) {
|
|
|
50493
51497
|
await sessions2.requestSnapshotRefresh(owner.sessionId);
|
|
50494
51498
|
} catch (error) {
|
|
50495
51499
|
if (sessions2.owns(owner))
|
|
50496
|
-
actions.errorSet(
|
|
51500
|
+
actions.errorSet(errorMessage9(error));
|
|
50497
51501
|
}
|
|
50498
51502
|
}
|
|
50499
51503
|
return {
|
|
@@ -50517,7 +51521,7 @@ function mergeQueuedPrompts(current, queued) {
|
|
|
50517
51521
|
return current;
|
|
50518
51522
|
return [...current, queued].sort((left, right) => left.sequence - right.sequence);
|
|
50519
51523
|
}
|
|
50520
|
-
function
|
|
51524
|
+
function errorMessage9(error) {
|
|
50521
51525
|
return error instanceof Error ? error.message : String(error);
|
|
50522
51526
|
}
|
|
50523
51527
|
var init_store_prompt_controller = __esm(() => {
|
|
@@ -54204,9 +55208,9 @@ function parseCommandArguments(value) {
|
|
|
54204
55208
|
|
|
54205
55209
|
// src/agent-tui/clipboard.ts
|
|
54206
55210
|
import { spawnSync } from "child_process";
|
|
54207
|
-
import { mkdtempSync, rmSync as
|
|
55211
|
+
import { mkdtempSync, rmSync as rmSync9, writeFileSync as writeFileSync3 } from "fs";
|
|
54208
55212
|
import { tmpdir as tmpdir2 } from "os";
|
|
54209
|
-
import { join as
|
|
55213
|
+
import { join as join31 } from "path";
|
|
54210
55214
|
function writeClipboard(text2) {
|
|
54211
55215
|
if (!text2)
|
|
54212
55216
|
return {
|
|
@@ -54258,8 +55262,8 @@ function runClipboardCommand(command, text2) {
|
|
|
54258
55262
|
};
|
|
54259
55263
|
}
|
|
54260
55264
|
function writeClipboardWithAppleScript(text2) {
|
|
54261
|
-
const dir = mkdtempSync(
|
|
54262
|
-
const path =
|
|
55265
|
+
const dir = mkdtempSync(join31(tmpdir2(), "farai-clipboard-"));
|
|
55266
|
+
const path = join31(dir, "clipboard.txt");
|
|
54263
55267
|
try {
|
|
54264
55268
|
writeFileSync3(path, text2, {
|
|
54265
55269
|
encoding: "utf8",
|
|
@@ -54283,7 +55287,7 @@ function writeClipboardWithAppleScript(text2) {
|
|
|
54283
55287
|
error: `osascript: ${detail}`
|
|
54284
55288
|
};
|
|
54285
55289
|
} finally {
|
|
54286
|
-
|
|
55290
|
+
rmSync9(dir, {
|
|
54287
55291
|
recursive: true,
|
|
54288
55292
|
force: true
|
|
54289
55293
|
});
|
|
@@ -54304,9 +55308,9 @@ function ctrlCDecision(text2, armedUntil, now = Date.now()) {
|
|
|
54304
55308
|
}
|
|
54305
55309
|
|
|
54306
55310
|
// src/agent-tui/input/composer-controller.ts
|
|
54307
|
-
import { mkdtempSync as mkdtempSync2, rmSync as
|
|
55311
|
+
import { mkdtempSync as mkdtempSync2, rmSync as rmSync10, writeFileSync as writeFileSync4 } from "fs";
|
|
54308
55312
|
import { tmpdir as tmpdir3 } from "os";
|
|
54309
|
-
import { join as
|
|
55313
|
+
import { join as join32 } from "path";
|
|
54310
55314
|
function createComposerController(input) {
|
|
54311
55315
|
const {
|
|
54312
55316
|
tui,
|
|
@@ -54574,8 +55578,8 @@ function createComposerController(input) {
|
|
|
54574
55578
|
});
|
|
54575
55579
|
return;
|
|
54576
55580
|
}
|
|
54577
|
-
const dir = mkdtempSync2(
|
|
54578
|
-
const file =
|
|
55581
|
+
const dir = mkdtempSync2(join32(tmpdir3(), "farai-editor-"));
|
|
55582
|
+
const file = join32(dir, "prompt.md");
|
|
54579
55583
|
writeFileSync4(file, composer.ref()?.plainText ?? composer.text(), {
|
|
54580
55584
|
encoding: "utf8",
|
|
54581
55585
|
mode: 384
|
|
@@ -54609,7 +55613,7 @@ function createComposerController(input) {
|
|
|
54609
55613
|
renderer.resume();
|
|
54610
55614
|
} catch {}
|
|
54611
55615
|
try {
|
|
54612
|
-
|
|
55616
|
+
rmSync10(dir, {
|
|
54613
55617
|
recursive: true,
|
|
54614
55618
|
force: true
|
|
54615
55619
|
});
|
|
@@ -55418,7 +56422,7 @@ var init_theme = __esm(() => {
|
|
|
55418
56422
|
warning: "#d7af5f",
|
|
55419
56423
|
error: "#ff5f5f",
|
|
55420
56424
|
success: "#87d75f",
|
|
55421
|
-
bg: "
|
|
56425
|
+
bg: "transparent",
|
|
55422
56426
|
backdrop: "rgba(0,0,0,0.5)",
|
|
55423
56427
|
panel: "#101010",
|
|
55424
56428
|
userMessageBg: "#1f1f1f",
|
|
@@ -57458,7 +58462,7 @@ function ToolResultContext(props) {
|
|
|
57458
58462
|
const evidence = () => result()?.evidence ?? [];
|
|
57459
58463
|
const attachments = () => result()?.attachments ?? [];
|
|
57460
58464
|
const metadata = () => result()?.metadata ?? {};
|
|
57461
|
-
const
|
|
58465
|
+
const artifact2 = () => {
|
|
57462
58466
|
const value = metadata().outputArtifact;
|
|
57463
58467
|
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
57464
58468
|
};
|
|
@@ -57500,7 +58504,7 @@ function ToolResultContext(props) {
|
|
|
57500
58504
|
}), null);
|
|
57501
58505
|
insert(_el$31, createComponent2(Show, {
|
|
57502
58506
|
get when() {
|
|
57503
|
-
return result()?.outputArtifactId ||
|
|
58507
|
+
return result()?.outputArtifactId || artifact2();
|
|
57504
58508
|
},
|
|
57505
58509
|
get children() {
|
|
57506
58510
|
var _el$35 = createElement("box"), _el$36 = createElement("text");
|
|
@@ -57516,7 +58520,7 @@ function ToolResultContext(props) {
|
|
|
57516
58520
|
...result()?.outputArtifactId ? {
|
|
57517
58521
|
id: result()?.outputArtifactId
|
|
57518
58522
|
} : {},
|
|
57519
|
-
...
|
|
58523
|
+
...artifact2() ?? {}
|
|
57520
58524
|
});
|
|
57521
58525
|
},
|
|
57522
58526
|
children: (line) => (() => {
|
|
@@ -61524,7 +62528,7 @@ var init_composer2 = __esm(() => {
|
|
|
61524
62528
|
focusTintStart = [22, 33, 38];
|
|
61525
62529
|
focusTintEnd = [16, 16, 16];
|
|
61526
62530
|
inactiveComposerBackground = RGBA.fromInts(...focusTintEnd);
|
|
61527
|
-
composerPageBackground = RGBA.fromInts(0, 0, 0);
|
|
62531
|
+
composerPageBackground = RGBA.fromInts(0, 0, 0, 0);
|
|
61528
62532
|
focusTintPalettes = new Map;
|
|
61529
62533
|
composerEdgeRuns = new Map;
|
|
61530
62534
|
});
|
|
@@ -65890,7 +66894,7 @@ var init_app = __esm(() => {
|
|
|
65890
66894
|
});
|
|
65891
66895
|
|
|
65892
66896
|
// src/agent-tui/update-check.ts
|
|
65893
|
-
import { dirname as
|
|
66897
|
+
import { dirname as dirname11, join as join33 } from "path";
|
|
65894
66898
|
function prepareUpdateCheck(options = {}) {
|
|
65895
66899
|
if (updateCheckDisabled())
|
|
65896
66900
|
return {
|
|
@@ -65933,42 +66937,9 @@ function createUpdateNotice(currentVersion, latestVersion) {
|
|
|
65933
66937
|
updateCommand: "npm install -g farai@latest"
|
|
65934
66938
|
};
|
|
65935
66939
|
}
|
|
65936
|
-
function compareSemver(left, right) {
|
|
65937
|
-
const a = parseSemver(left);
|
|
65938
|
-
const b = parseSemver(right);
|
|
65939
|
-
if (!a || !b)
|
|
65940
|
-
return 0;
|
|
65941
|
-
for (let index = 0;index < 3; index += 1) {
|
|
65942
|
-
const delta = a.core[index] - b.core[index];
|
|
65943
|
-
if (delta !== 0)
|
|
65944
|
-
return delta < 0 ? -1 : 1;
|
|
65945
|
-
}
|
|
65946
|
-
if (a.prerelease.length === 0 || b.prerelease.length === 0) {
|
|
65947
|
-
if (a.prerelease.length === b.prerelease.length)
|
|
65948
|
-
return 0;
|
|
65949
|
-
return a.prerelease.length === 0 ? 1 : -1;
|
|
65950
|
-
}
|
|
65951
|
-
const length = Math.max(a.prerelease.length, b.prerelease.length);
|
|
65952
|
-
for (let index = 0;index < length; index += 1) {
|
|
65953
|
-
const aPart = a.prerelease[index];
|
|
65954
|
-
const bPart = b.prerelease[index];
|
|
65955
|
-
if (aPart === undefined || bPart === undefined)
|
|
65956
|
-
return aPart === undefined ? -1 : 1;
|
|
65957
|
-
if (aPart === bPart)
|
|
65958
|
-
continue;
|
|
65959
|
-
const aNumber = numericIdentifier(aPart);
|
|
65960
|
-
const bNumber = numericIdentifier(bPart);
|
|
65961
|
-
if (aNumber !== undefined && bNumber !== undefined)
|
|
65962
|
-
return aNumber < bNumber ? -1 : 1;
|
|
65963
|
-
if (aNumber !== undefined || bNumber !== undefined)
|
|
65964
|
-
return aNumber !== undefined ? -1 : 1;
|
|
65965
|
-
return aPart < bPart ? -1 : 1;
|
|
65966
|
-
}
|
|
65967
|
-
return 0;
|
|
65968
|
-
}
|
|
65969
66940
|
function readUpdateCache(path = updateCachePath()) {
|
|
65970
66941
|
try {
|
|
65971
|
-
ensurePrivateDirectory(
|
|
66942
|
+
ensurePrivateDirectory(dirname11(path), "update cache directory");
|
|
65972
66943
|
ensurePrivateRegularFileIfExists(path, "update cache");
|
|
65973
66944
|
const parsed = JSON.parse(readBoundedFileTextSyncNoFollow(path, UPDATE_RESPONSE_MAX_BYTES, "update cache"));
|
|
65974
66945
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
@@ -65976,7 +66947,7 @@ function readUpdateCache(path = updateCachePath()) {
|
|
|
65976
66947
|
const value = parsed;
|
|
65977
66948
|
if (typeof value.checkedAt !== "number" || !Number.isFinite(value.checkedAt))
|
|
65978
66949
|
return;
|
|
65979
|
-
if (typeof value.latestVersion !== "string" || !
|
|
66950
|
+
if (typeof value.latestVersion !== "string" || !isSemver(value.latestVersion))
|
|
65980
66951
|
return;
|
|
65981
66952
|
return {
|
|
65982
66953
|
checkedAt: value.checkedAt,
|
|
@@ -65987,13 +66958,13 @@ function readUpdateCache(path = updateCachePath()) {
|
|
|
65987
66958
|
}
|
|
65988
66959
|
}
|
|
65989
66960
|
function updateCachePath() {
|
|
65990
|
-
return
|
|
66961
|
+
return join33(globalDataDir(), "update.json");
|
|
65991
66962
|
}
|
|
65992
66963
|
function readCurrentVersion() {
|
|
65993
66964
|
try {
|
|
65994
|
-
const packagePath =
|
|
66965
|
+
const packagePath = join33(import.meta.dir, "..", "..", "package.json");
|
|
65995
66966
|
const parsed = JSON.parse(readBoundedFileTextSync(packagePath, 1024 * 1024, "package metadata"));
|
|
65996
|
-
return typeof parsed.version === "string" &&
|
|
66967
|
+
return typeof parsed.version === "string" && isSemver(parsed.version) ? parsed.version : undefined;
|
|
65997
66968
|
} catch {
|
|
65998
66969
|
return;
|
|
65999
66970
|
}
|
|
@@ -66029,7 +67000,7 @@ async function fetchLatestVersion(fetcher, timeoutMs) {
|
|
|
66029
67000
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
66030
67001
|
throw new Error("invalid npm registry response");
|
|
66031
67002
|
const version = parsed.version;
|
|
66032
|
-
if (typeof version !== "string" || !
|
|
67003
|
+
if (typeof version !== "string" || !isSemver(version))
|
|
66033
67004
|
throw new Error("invalid npm package version");
|
|
66034
67005
|
return version;
|
|
66035
67006
|
} finally {
|
|
@@ -66038,7 +67009,7 @@ async function fetchLatestVersion(fetcher, timeoutMs) {
|
|
|
66038
67009
|
}
|
|
66039
67010
|
function writeUpdateCache(path, cache) {
|
|
66040
67011
|
try {
|
|
66041
|
-
ensurePrivateDirectory(
|
|
67012
|
+
ensurePrivateDirectory(dirname11(path), "update cache directory");
|
|
66042
67013
|
ensurePrivateRegularFileIfExists(path, "update cache");
|
|
66043
67014
|
atomicWriteFile(path, `${JSON.stringify(cache)}
|
|
66044
67015
|
`, 384);
|
|
@@ -66054,20 +67025,6 @@ function updateCheckDisabled() {
|
|
|
66054
67025
|
function envEnabled(value) {
|
|
66055
67026
|
return value === "1" || value?.toLowerCase() === "true" || value?.toLowerCase() === "yes";
|
|
66056
67027
|
}
|
|
66057
|
-
function parseSemver(value) {
|
|
66058
|
-
const match = value.trim().match(/^(?:v)?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/);
|
|
66059
|
-
if (!match)
|
|
66060
|
-
return;
|
|
66061
|
-
return {
|
|
66062
|
-
core: [Number(match[1]), Number(match[2]), Number(match[3])],
|
|
66063
|
-
prerelease: match[4]?.split(".") ?? []
|
|
66064
|
-
};
|
|
66065
|
-
}
|
|
66066
|
-
function numericIdentifier(value) {
|
|
66067
|
-
if (!/^(0|[1-9]\d*)$/.test(value))
|
|
66068
|
-
return;
|
|
66069
|
-
return Number(value);
|
|
66070
|
-
}
|
|
66071
67028
|
var UPDATE_CACHE_TTL_MS, UPDATE_CHECK_TIMEOUT_MS = 4000, UPDATE_REGISTRY_URL = "https://registry.npmjs.org/farai/latest", UPDATE_RESPONSE_MAX_BYTES;
|
|
66072
67029
|
var init_update_check = __esm(() => {
|
|
66073
67030
|
init_config();
|
|
@@ -66134,8 +67091,8 @@ async function runOpenTui(input) {
|
|
|
66134
67091
|
const renderer = managedRenderer.renderer;
|
|
66135
67092
|
const updateCheck = prepareUpdateCheck();
|
|
66136
67093
|
let done;
|
|
66137
|
-
const finished = new Promise((
|
|
66138
|
-
done =
|
|
67094
|
+
const finished = new Promise((resolve11) => {
|
|
67095
|
+
done = resolve11;
|
|
66139
67096
|
});
|
|
66140
67097
|
let exitPromise;
|
|
66141
67098
|
const onSigint = () => {
|
|
@@ -66376,6 +67333,80 @@ no sessions are available in this workspace`}`);
|
|
|
66376
67333
|
};
|
|
66377
67334
|
});
|
|
66378
67335
|
|
|
67336
|
+
// src/agent-content/command.ts
|
|
67337
|
+
var exports_command2 = {};
|
|
67338
|
+
__export(exports_command2, {
|
|
67339
|
+
runContentUpdateCommand: () => runContentUpdateCommand
|
|
67340
|
+
});
|
|
67341
|
+
import { existsSync as existsSync26 } from "fs";
|
|
67342
|
+
async function runContentUpdateCommand(parsed, workspace) {
|
|
67343
|
+
if (parsed.kind === "status") {
|
|
67344
|
+
const status3 = contentStatus();
|
|
67345
|
+
if (!status3.active) {
|
|
67346
|
+
const knowledge = legacyKnowledgeDbPath();
|
|
67347
|
+
console.log("content: bundled defaults");
|
|
67348
|
+
console.log("active release: none");
|
|
67349
|
+
console.log(`knowledge: ${existsSync26(knowledge) ? knowledge : "not installed"}`);
|
|
67350
|
+
console.log("skills: bundled");
|
|
67351
|
+
return 0;
|
|
67352
|
+
}
|
|
67353
|
+
console.log(`content: ${status3.active.version}`);
|
|
67354
|
+
console.log(`activated: ${status3.active.activatedAt}`);
|
|
67355
|
+
console.log(`knowledge: ${status3.knowledgePath ?? "local fallback"}`);
|
|
67356
|
+
console.log(`skills: ${status3.skillsPath ?? "bundled fallback"}`);
|
|
67357
|
+
console.log(`available versions: ${status3.versions.join(", ") || "none"}`);
|
|
67358
|
+
return 0;
|
|
67359
|
+
}
|
|
67360
|
+
if (parsed.kind === "rollback") {
|
|
67361
|
+
const result2 = rollbackContentUpdate();
|
|
67362
|
+
console.log(`rolled back farai content to ${result2.version}`);
|
|
67363
|
+
return 0;
|
|
67364
|
+
}
|
|
67365
|
+
const status2 = await checkContentUpdate({
|
|
67366
|
+
workspace,
|
|
67367
|
+
force: true
|
|
67368
|
+
});
|
|
67369
|
+
if (parsed.kind === "check")
|
|
67370
|
+
return printContentUpdateStatus(status2);
|
|
67371
|
+
if (status2.state === "up_to_date") {
|
|
67372
|
+
console.log(`farai content is up to date${status2.active ? ` (${status2.active.version})` : ""}`);
|
|
67373
|
+
return 0;
|
|
67374
|
+
}
|
|
67375
|
+
if (status2.state !== "update_available" || !status2.manifest)
|
|
67376
|
+
return printContentUpdateStatus(status2);
|
|
67377
|
+
const result = await applyContentUpdate(status2.manifest, status2.manifestUrl);
|
|
67378
|
+
console.log(`updated farai content to ${result.version}`);
|
|
67379
|
+
return 0;
|
|
67380
|
+
}
|
|
67381
|
+
function printContentUpdateStatus(status2) {
|
|
67382
|
+
if (status2.state === "update_available") {
|
|
67383
|
+
console.log(`content update available: ${status2.active?.version ?? "none"} -> ${status2.manifest?.contentVersion}`);
|
|
67384
|
+
return 0;
|
|
67385
|
+
}
|
|
67386
|
+
if (status2.state === "up_to_date") {
|
|
67387
|
+
console.log(`farai content is up to date${status2.active ? ` (${status2.active.version})` : ""}`);
|
|
67388
|
+
return 0;
|
|
67389
|
+
}
|
|
67390
|
+
if (status2.state === "disabled") {
|
|
67391
|
+
console.log("farai content updates are disabled");
|
|
67392
|
+
return 0;
|
|
67393
|
+
}
|
|
67394
|
+
if (status2.state === "unavailable") {
|
|
67395
|
+
console.log("the content channel has no published artifacts yet");
|
|
67396
|
+
return 0;
|
|
67397
|
+
}
|
|
67398
|
+
if (status2.state === "incompatible") {
|
|
67399
|
+
console.error(`content ${status2.manifest?.contentVersion} requires farai ${status2.manifest?.minFaraiVersion} or newer`);
|
|
67400
|
+
return 1;
|
|
67401
|
+
}
|
|
67402
|
+
console.error(`content update check failed: ${status2.error ?? "unknown error"}`);
|
|
67403
|
+
return 1;
|
|
67404
|
+
}
|
|
67405
|
+
var init_command2 = __esm(() => {
|
|
67406
|
+
init_paths3();
|
|
67407
|
+
init_updater();
|
|
67408
|
+
});
|
|
67409
|
+
|
|
66379
67410
|
// src/agent-benchmark/csi-cybench-33.ts
|
|
66380
67411
|
var figureTimeout = (minutes, line) => ({
|
|
66381
67412
|
status: "verified",
|
|
@@ -66637,40 +67668,40 @@ var init_csi_cybench_33 = __esm(() => {
|
|
|
66637
67668
|
});
|
|
66638
67669
|
|
|
66639
67670
|
// src/agent-benchmark/hash.ts
|
|
66640
|
-
import { createHash as
|
|
66641
|
-
import { closeSync as
|
|
66642
|
-
import { join as
|
|
67671
|
+
import { createHash as createHash13 } from "crypto";
|
|
67672
|
+
import { closeSync as closeSync7, constants as constants3, fstatSync as fstatSync3, lstatSync as lstatSync11, openSync as openSync7, readSync as readSync3, readdirSync as readdirSync12 } from "fs";
|
|
67673
|
+
import { join as join34 } from "path";
|
|
66643
67674
|
function stableStringify(value) {
|
|
66644
67675
|
return JSON.stringify(sortValue(value));
|
|
66645
67676
|
}
|
|
66646
67677
|
function sha256(value) {
|
|
66647
|
-
return
|
|
67678
|
+
return createHash13("sha256").update(value).digest("hex");
|
|
66648
67679
|
}
|
|
66649
67680
|
function hashPath(path) {
|
|
66650
|
-
const stat =
|
|
67681
|
+
const stat = lstatSync11(path);
|
|
66651
67682
|
if (stat.isFile())
|
|
66652
|
-
return
|
|
67683
|
+
return hashFile2(path);
|
|
66653
67684
|
if (!stat.isDirectory())
|
|
66654
67685
|
throw new Error(`unsupported benchmark input type: ${path}`);
|
|
66655
|
-
const hash =
|
|
67686
|
+
const hash = createHash13("sha256");
|
|
66656
67687
|
hash.update("farai-directory-v2\x00");
|
|
66657
67688
|
hashDirectory(path, Buffer.alloc(0), hash);
|
|
66658
67689
|
return hash.digest("hex");
|
|
66659
67690
|
}
|
|
66660
|
-
function
|
|
67691
|
+
function hashFile2(path) {
|
|
66661
67692
|
return hashFileDetails(path).digest;
|
|
66662
67693
|
}
|
|
66663
67694
|
function hashFileDetails(path) {
|
|
66664
|
-
const descriptor =
|
|
67695
|
+
const descriptor = openSync7(path, constants3.O_RDONLY | (constants3.O_NOFOLLOW ?? 0));
|
|
66665
67696
|
try {
|
|
66666
67697
|
const before = fstatSync3(descriptor);
|
|
66667
67698
|
if (!before.isFile())
|
|
66668
67699
|
throw new Error(`unsupported benchmark input type: ${path}`);
|
|
66669
|
-
const hash =
|
|
67700
|
+
const hash = createHash13("sha256");
|
|
66670
67701
|
let remaining2 = before.size;
|
|
66671
67702
|
while (remaining2 > 0) {
|
|
66672
67703
|
const chunk = Buffer.allocUnsafe(Math.min(1024 * 1024, remaining2));
|
|
66673
|
-
const count2 =
|
|
67704
|
+
const count2 = readSync3(descriptor, chunk, 0, chunk.length, null);
|
|
66674
67705
|
if (count2 === 0)
|
|
66675
67706
|
throw new Error(`benchmark input changed while hashing: ${path}`);
|
|
66676
67707
|
hash.update(chunk.subarray(0, count2));
|
|
@@ -66686,7 +67717,7 @@ function hashFileDetails(path) {
|
|
|
66686
67717
|
size: before.size
|
|
66687
67718
|
};
|
|
66688
67719
|
} finally {
|
|
66689
|
-
|
|
67720
|
+
closeSync7(descriptor);
|
|
66690
67721
|
}
|
|
66691
67722
|
}
|
|
66692
67723
|
function canonicalBenchmarkManifest(manifest) {
|
|
@@ -66741,22 +67772,22 @@ function sortValue(value) {
|
|
|
66741
67772
|
return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => [key, sortValue(item)]));
|
|
66742
67773
|
}
|
|
66743
67774
|
function hashDirectory(path, localPath, hash) {
|
|
66744
|
-
const before =
|
|
67775
|
+
const before = lstatSync11(path);
|
|
66745
67776
|
if (!before.isDirectory() || before.isSymbolicLink())
|
|
66746
67777
|
throw new Error(`unsupported benchmark input type: ${path}`);
|
|
66747
67778
|
hash.update("directory\x00");
|
|
66748
67779
|
hash.update(localPath);
|
|
66749
67780
|
hash.update(`\x00${before.mode & 511}\x00`);
|
|
66750
|
-
const names =
|
|
67781
|
+
const names = readdirSync12(path, {
|
|
66751
67782
|
encoding: "buffer"
|
|
66752
67783
|
}).map((name) => Buffer.from(name)).sort(Buffer.compare);
|
|
66753
67784
|
for (const encodedName of names) {
|
|
66754
67785
|
const name = encodedName.toString("utf8");
|
|
66755
67786
|
if (!Buffer.from(name, "utf8").equals(encodedName))
|
|
66756
67787
|
throw new Error(`benchmark input path is not valid utf-8: ${path}`);
|
|
66757
|
-
const childPath =
|
|
67788
|
+
const childPath = join34(path, name);
|
|
66758
67789
|
const childLocalPath = localPath.length === 0 ? encodedName : Buffer.concat([localPath, Buffer.from("/"), encodedName]);
|
|
66759
|
-
const stat =
|
|
67790
|
+
const stat = lstatSync11(childPath);
|
|
66760
67791
|
if (stat.isDirectory() && !stat.isSymbolicLink()) {
|
|
66761
67792
|
hashDirectory(childPath, childLocalPath, hash);
|
|
66762
67793
|
continue;
|
|
@@ -66768,7 +67799,7 @@ function hashDirectory(path, localPath, hash) {
|
|
|
66768
67799
|
hash.update(childLocalPath);
|
|
66769
67800
|
hash.update(`\x00${file.mode}\x00${file.size}\x00${file.digest}\x00`);
|
|
66770
67801
|
}
|
|
66771
|
-
const after =
|
|
67802
|
+
const after = lstatSync11(path);
|
|
66772
67803
|
if (!after.isDirectory() || after.dev !== before.dev || after.ino !== before.ino || after.mtimeMs !== before.mtimeMs || after.ctimeMs !== before.ctimeMs) {
|
|
66773
67804
|
throw new Error(`benchmark input changed while hashing: ${path}`);
|
|
66774
67805
|
}
|
|
@@ -66776,7 +67807,7 @@ function hashDirectory(path, localPath, hash) {
|
|
|
66776
67807
|
var init_hash = () => {};
|
|
66777
67808
|
|
|
66778
67809
|
// src/agent-benchmark/manifest.ts
|
|
66779
|
-
import { isAbsolute as
|
|
67810
|
+
import { isAbsolute as isAbsolute8, normalize as normalize3 } from "path";
|
|
66780
67811
|
async function loadBenchmarkManifest(path) {
|
|
66781
67812
|
return normalizeBenchmarkManifest(JSON.parse(await readBoundedFileText(path, BENCHMARK_MANIFEST_MAX_BYTES, "benchmark manifest")));
|
|
66782
67813
|
}
|
|
@@ -66815,27 +67846,27 @@ function normalizeBenchmarkManifest(value) {
|
|
|
66815
67846
|
id: requiredString(suite.id, "suite.id"),
|
|
66816
67847
|
version: requiredString(suite.version, "suite.version"),
|
|
66817
67848
|
source: requiredString(suite.source, "suite.source"),
|
|
66818
|
-
...
|
|
66819
|
-
sourceDigest:
|
|
67849
|
+
...optionalString3(suite.sourceDigest ?? suite.source_digest) ? {
|
|
67850
|
+
sourceDigest: optionalString3(suite.sourceDigest ?? suite.source_digest)
|
|
66820
67851
|
} : {}
|
|
66821
67852
|
},
|
|
66822
67853
|
challenge: {
|
|
66823
67854
|
id: requiredString(challenge.id, "challenge.id"),
|
|
66824
67855
|
prompt: requiredString(challenge.prompt, "challenge.prompt"),
|
|
66825
|
-
...
|
|
66826
|
-
category:
|
|
67856
|
+
...optionalString3(challenge.category) ? {
|
|
67857
|
+
category: optionalString3(challenge.category)
|
|
66827
67858
|
} : {},
|
|
66828
|
-
...
|
|
66829
|
-
difficulty:
|
|
67859
|
+
...optionalString3(challenge.difficulty) ? {
|
|
67860
|
+
difficulty: optionalString3(challenge.difficulty)
|
|
66830
67861
|
} : {},
|
|
66831
|
-
...
|
|
66832
|
-
source:
|
|
67862
|
+
...optionalString3(challenge.source) ? {
|
|
67863
|
+
source: optionalString3(challenge.source)
|
|
66833
67864
|
} : {},
|
|
66834
|
-
...
|
|
66835
|
-
targetImage:
|
|
67865
|
+
...optionalString3(challenge.targetImage ?? challenge.target_image) ? {
|
|
67866
|
+
targetImage: optionalString3(challenge.targetImage ?? challenge.target_image)
|
|
66836
67867
|
} : {},
|
|
66837
|
-
...
|
|
66838
|
-
targetImageDigest:
|
|
67868
|
+
...optionalString3(challenge.targetImageDigest ?? challenge.target_image_digest) ? {
|
|
67869
|
+
targetImageDigest: optionalString3(challenge.targetImageDigest ?? challenge.target_image_digest)
|
|
66839
67870
|
} : {},
|
|
66840
67871
|
...challenge.targetCommand ?? challenge.target_command ? {
|
|
66841
67872
|
targetCommand: stringArray3(challenge.targetCommand ?? challenge.target_command, "challenge.targetCommand")
|
|
@@ -66843,11 +67874,11 @@ function normalizeBenchmarkManifest(value) {
|
|
|
66843
67874
|
},
|
|
66844
67875
|
model: {
|
|
66845
67876
|
selection: requiredString(model.selection, "model.selection"),
|
|
66846
|
-
...
|
|
66847
|
-
provider:
|
|
67877
|
+
...optionalString3(model.provider) ? {
|
|
67878
|
+
provider: optionalString3(model.provider)
|
|
66848
67879
|
} : {},
|
|
66849
|
-
...
|
|
66850
|
-
protocol:
|
|
67880
|
+
...optionalString3(model.protocol) ? {
|
|
67881
|
+
protocol: optionalString3(model.protocol)
|
|
66851
67882
|
} : {},
|
|
66852
67883
|
...optionalPositiveNumber(model.contextWindow ?? model.context_window, "model.contextWindow") ? {
|
|
66853
67884
|
contextWindow: optionalPositiveNumber(model.contextWindow ?? model.context_window, "model.contextWindow")
|
|
@@ -66906,7 +67937,7 @@ function normalizeBenchmarkSuiteManifest(value) {
|
|
|
66906
67937
|
const id2 = requiredString(raw.id, "id");
|
|
66907
67938
|
const version = requiredString(raw.version, "version");
|
|
66908
67939
|
const source = requiredString(raw.source, "source");
|
|
66909
|
-
const sourceDigest =
|
|
67940
|
+
const sourceDigest = optionalString3(raw.sourceDigest ?? raw.source_digest);
|
|
66910
67941
|
const repetitions = positiveInteger4(raw.repetitions, "repetitions");
|
|
66911
67942
|
const concurrency = positiveInteger4(raw.concurrency, "concurrency");
|
|
66912
67943
|
const runs = raw.runs.map((entry, index) => {
|
|
@@ -66963,8 +67994,8 @@ function normalizeOracle(value) {
|
|
|
66963
67994
|
executableSha256: optionalSha256(raw.executableSha256 ?? raw.executable_sha256, "oracle.executableSha256")
|
|
66964
67995
|
} : {},
|
|
66965
67996
|
flagPattern: requiredString(raw.flagPattern ?? raw.flag_pattern, "oracle.flagPattern"),
|
|
66966
|
-
...
|
|
66967
|
-
flags:
|
|
67997
|
+
...optionalString3(raw.flags) ? {
|
|
67998
|
+
flags: optionalString3(raw.flags)
|
|
66968
67999
|
} : {},
|
|
66969
68000
|
...optionalPositiveNumber(raw.timeoutSeconds ?? raw.timeout_seconds, "oracle.timeoutSeconds") ? {
|
|
66970
68001
|
timeoutSeconds: optionalPositiveNumber(raw.timeoutSeconds ?? raw.timeout_seconds, "oracle.timeoutSeconds")
|
|
@@ -67020,7 +68051,7 @@ function optionalResource(raw, key, integer2, snake = key) {
|
|
|
67020
68051
|
};
|
|
67021
68052
|
}
|
|
67022
68053
|
function safeRelativePath(value) {
|
|
67023
|
-
if (
|
|
68054
|
+
if (isAbsolute8(value))
|
|
67024
68055
|
throw new Error(`benchmark destination must be relative: ${value}`);
|
|
67025
68056
|
const normalized = normalize3(value).replace(/\\/g, "/");
|
|
67026
68057
|
if (!normalized || normalized === "." || normalized.split("/").includes(".."))
|
|
@@ -67052,7 +68083,7 @@ function requiredString(value, name) {
|
|
|
67052
68083
|
throw new Error(`${name} must be a non-empty string`);
|
|
67053
68084
|
return value.trim();
|
|
67054
68085
|
}
|
|
67055
|
-
function
|
|
68086
|
+
function optionalString3(value) {
|
|
67056
68087
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
67057
68088
|
}
|
|
67058
68089
|
function optionalSha256(value, name) {
|
|
@@ -67099,7 +68130,7 @@ function optionalInteger(value, name, minimum) {
|
|
|
67099
68130
|
return number;
|
|
67100
68131
|
}
|
|
67101
68132
|
var BENCHMARK_MANIFEST_MAX_BYTES;
|
|
67102
|
-
var
|
|
68133
|
+
var init_manifest2 = __esm(() => {
|
|
67103
68134
|
init_file_read();
|
|
67104
68135
|
BENCHMARK_MANIFEST_MAX_BYTES = 32 * 1024 * 1024;
|
|
67105
68136
|
});
|
|
@@ -67114,17 +68145,17 @@ __export(exports_csi_suite, {
|
|
|
67114
68145
|
loadCsiCampaignConfig: () => loadCsiCampaignConfig,
|
|
67115
68146
|
generateCsiBenchmarkSuite: () => generateCsiBenchmarkSuite
|
|
67116
68147
|
});
|
|
67117
|
-
import { existsSync as
|
|
67118
|
-
import { dirname as
|
|
68148
|
+
import { existsSync as existsSync27, readdirSync as readdirSync13, statSync as statSync7 } from "fs";
|
|
68149
|
+
import { dirname as dirname12, isAbsolute as isAbsolute9, join as join35, relative as relative11, resolve as resolve11 } from "path";
|
|
67119
68150
|
async function loadCsiCampaignConfig(path) {
|
|
67120
68151
|
return normalizeCsiCampaignConfig(JSON.parse(await readBoundedFileText(path, CSI_CAMPAIGN_MAX_BYTES, "csi campaign config")));
|
|
67121
68152
|
}
|
|
67122
68153
|
async function loadCsiMaterialIndex(root) {
|
|
67123
|
-
return normalizeCsiMaterialIndex(JSON.parse(await readBoundedFileText(
|
|
68154
|
+
return normalizeCsiMaterialIndex(JSON.parse(await readBoundedFileText(resolve11(root, "index.json"), CSI_MATERIAL_INDEX_MAX_BYTES, "csi material index")));
|
|
67124
68155
|
}
|
|
67125
68156
|
async function generateCsiBenchmarkSuite(configInput, materialRoot) {
|
|
67126
68157
|
const config = normalizeCsiCampaignConfig(configInput);
|
|
67127
|
-
const root =
|
|
68158
|
+
const root = resolve11(materialRoot);
|
|
67128
68159
|
const materials = await loadCsiMaterialIndex(root);
|
|
67129
68160
|
const selectedIds = config.challenges ?? CSI_CYBENCH_33.challenges.map((challenge) => challenge.id);
|
|
67130
68161
|
const selected = selectedIds.map((id2) => {
|
|
@@ -67140,16 +68171,16 @@ async function generateCsiBenchmarkSuite(configInput, materialRoot) {
|
|
|
67140
68171
|
if (config.isolation.backend === "host" && material.requiresTarget)
|
|
67141
68172
|
throw new Error(`host csi challenge requires a live target and cannot run in host smoke mode: ${challenge.id}`);
|
|
67142
68173
|
const promptPath = protectedPath(root, material.promptFile, `${challenge.id}.promptFile`);
|
|
67143
|
-
if (!
|
|
68174
|
+
if (!existsSync27(promptPath) || !statSync7(promptPath).isFile())
|
|
67144
68175
|
throw new Error(`missing prompt file for csi challenge: ${challenge.id}`);
|
|
67145
68176
|
const prompt = readBoundedFileTextSync(promptPath, CSI_PROMPT_MAX_BYTES, `csi prompt ${challenge.id}`).trim();
|
|
67146
68177
|
if (!prompt)
|
|
67147
68178
|
throw new Error(`empty prompt file for csi challenge: ${challenge.id}`);
|
|
67148
68179
|
const files = material.files?.map((file, index) => {
|
|
67149
68180
|
const source = protectedPath(root, file.source, `${challenge.id}.files[${index}].source`);
|
|
67150
|
-
if (!
|
|
68181
|
+
if (!existsSync27(source))
|
|
67151
68182
|
throw new Error(`missing input for csi challenge ${challenge.id}: ${file.source}`);
|
|
67152
|
-
if (
|
|
68183
|
+
if (statSync7(source).isDirectory() && !listFiles(source).length)
|
|
67153
68184
|
throw new Error(`empty input directory for csi challenge ${challenge.id}: ${file.source}`);
|
|
67154
68185
|
const digest2 = hashPath(source);
|
|
67155
68186
|
if (file.sha256 && file.sha256.toLowerCase() !== digest2)
|
|
@@ -67169,14 +68200,14 @@ async function generateCsiBenchmarkSuite(configInput, materialRoot) {
|
|
|
67169
68200
|
throw new Error(`missing required protected files for csi challenge ${challenge.id}: ${missing.join(", ")}`);
|
|
67170
68201
|
}
|
|
67171
68202
|
const executable = protectedPath(root, material.oracle.executable, `${challenge.id}.oracle.executable`);
|
|
67172
|
-
if (!
|
|
68203
|
+
if (!existsSync27(executable) || !statSync7(executable).isFile())
|
|
67173
68204
|
throw new Error(`missing oracle executable for csi challenge: ${challenge.id}`);
|
|
67174
|
-
if ((
|
|
68205
|
+
if ((statSync7(executable).mode & 73) === 0)
|
|
67175
68206
|
throw new Error(`oracle executable is not executable for csi challenge: ${challenge.id}`);
|
|
67176
68207
|
const antiCheatExecutable = material.antiCheat ? protectedPath(root, material.antiCheat.executable, `${challenge.id}.antiCheat.executable`) : undefined;
|
|
67177
|
-
if (antiCheatExecutable && (!
|
|
68208
|
+
if (antiCheatExecutable && (!existsSync27(antiCheatExecutable) || !statSync7(antiCheatExecutable).isFile()))
|
|
67178
68209
|
throw new Error(`missing anti-cheat executable for csi challenge: ${challenge.id}`);
|
|
67179
|
-
if (antiCheatExecutable && (
|
|
68210
|
+
if (antiCheatExecutable && (statSync7(antiCheatExecutable).mode & 73) === 0)
|
|
67180
68211
|
throw new Error(`anti-cheat executable is not executable for csi challenge: ${challenge.id}`);
|
|
67181
68212
|
if (config.isolation.backend === "docker" && !material.target)
|
|
67182
68213
|
throw new Error(`docker csi challenge requires a pinned target image: ${challenge.id}`);
|
|
@@ -67249,8 +68280,8 @@ async function generateCsiBenchmarkSuite(configInput, materialRoot) {
|
|
|
67249
68280
|
});
|
|
67250
68281
|
}
|
|
67251
68282
|
function writeCsiBenchmarkSuite(suite, path) {
|
|
67252
|
-
const directory =
|
|
67253
|
-
if (!
|
|
68283
|
+
const directory = dirname12(resolve11(path));
|
|
68284
|
+
if (!existsSync27(directory))
|
|
67254
68285
|
throw new Error(`suite output directory does not exist: ${directory}`);
|
|
67255
68286
|
atomicWriteFile(path, `${JSON.stringify(suite, null, 2)}
|
|
67256
68287
|
`, 384);
|
|
@@ -67329,8 +68360,8 @@ function normalizeCsiMaterialIndex(value) {
|
|
|
67329
68360
|
args: stringArray4(oracle.args, `challenges.${id2}.oracle.args`, true)
|
|
67330
68361
|
},
|
|
67331
68362
|
flagPattern: requiredString2(oracle.flagPattern ?? oracle.flag_pattern, `challenges.${id2}.oracle.flagPattern`),
|
|
67332
|
-
...
|
|
67333
|
-
flags:
|
|
68363
|
+
...optionalString4(oracle.flags) ? {
|
|
68364
|
+
flags: optionalString4(oracle.flags)
|
|
67334
68365
|
} : {},
|
|
67335
68366
|
...oracle.timeoutSeconds ?? oracle.timeout_seconds ? {
|
|
67336
68367
|
timeoutSeconds: positiveNumber3(oracle.timeoutSeconds ?? oracle.timeout_seconds, `challenges.${id2}.oracle.timeoutSeconds`)
|
|
@@ -67376,18 +68407,18 @@ function resolveTimeoutMinutes(id2, catalog, material) {
|
|
|
67376
68407
|
return material.minutes;
|
|
67377
68408
|
}
|
|
67378
68409
|
function protectedPath(root, path, name) {
|
|
67379
|
-
if (
|
|
68410
|
+
if (isAbsolute9(path))
|
|
67380
68411
|
throw new Error(`${name} must be relative to the protected material root`);
|
|
67381
|
-
const resolved =
|
|
68412
|
+
const resolved = resolve11(root, path);
|
|
67382
68413
|
const difference = relative11(root, resolved);
|
|
67383
|
-
if (!difference || difference.startsWith("..") ||
|
|
68414
|
+
if (!difference || difference.startsWith("..") || isAbsolute9(difference))
|
|
67384
68415
|
throw new Error(`${name} escapes the protected material root`);
|
|
67385
68416
|
return resolved;
|
|
67386
68417
|
}
|
|
67387
68418
|
function listFiles(rootPath) {
|
|
67388
|
-
if (!
|
|
68419
|
+
if (!statSync7(rootPath).isDirectory())
|
|
67389
68420
|
return [rootPath];
|
|
67390
|
-
return
|
|
68421
|
+
return readdirSync13(rootPath).flatMap((name) => listFiles(join35(rootPath, name)));
|
|
67391
68422
|
}
|
|
67392
68423
|
function object2(value, name) {
|
|
67393
68424
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
@@ -67399,7 +68430,7 @@ function requiredString2(value, name) {
|
|
|
67399
68430
|
throw new Error(`${name} must be a non-empty string`);
|
|
67400
68431
|
return value.trim();
|
|
67401
68432
|
}
|
|
67402
|
-
function
|
|
68433
|
+
function optionalString4(value) {
|
|
67403
68434
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
67404
68435
|
}
|
|
67405
68436
|
function stringArray4(value, name, allowEmpty) {
|
|
@@ -67441,7 +68472,7 @@ var CSI_CAMPAIGN_MAX_BYTES, CSI_MATERIAL_INDEX_MAX_BYTES, CSI_PROMPT_MAX_BYTES;
|
|
|
67441
68472
|
var init_csi_suite = __esm(() => {
|
|
67442
68473
|
init_csi_cybench_33();
|
|
67443
68474
|
init_hash();
|
|
67444
|
-
|
|
68475
|
+
init_manifest2();
|
|
67445
68476
|
init_file_read();
|
|
67446
68477
|
init_atomic_file();
|
|
67447
68478
|
CSI_CAMPAIGN_MAX_BYTES = 4 * 1024 * 1024;
|
|
@@ -67450,28 +68481,28 @@ var init_csi_suite = __esm(() => {
|
|
|
67450
68481
|
});
|
|
67451
68482
|
|
|
67452
68483
|
// src/agent-benchmark/bundle.ts
|
|
67453
|
-
import { createHash as
|
|
67454
|
-
import { chmodSync as chmodSync3, mkdirSync as
|
|
67455
|
-
import { join as
|
|
68484
|
+
import { createHash as createHash14 } from "crypto";
|
|
68485
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync12 } from "fs";
|
|
68486
|
+
import { join as join36 } from "path";
|
|
67456
68487
|
function writeBenchmarkBundle(bundle, directory) {
|
|
67457
|
-
|
|
68488
|
+
mkdirSync12(directory, {
|
|
67458
68489
|
recursive: true
|
|
67459
68490
|
});
|
|
67460
68491
|
const files = new Map([["manifest.json", json(redactManifest(bundle.manifest))], ["result.json", json(bundle.result)], ["environment.json", json(bundle.result.frozen)], ["sessions.jsonl", jsonl(bundle.sessions)], ["turns.jsonl", jsonl(bundle.turns)], ["messages.jsonl", jsonl(bundle.messages)], ["events.jsonl", jsonl(bundle.events)], ["tool-calls.jsonl", jsonl(bundle.toolCalls)], ["jobs.jsonl", jsonl(bundle.jobs)], ["usage.jsonl", jsonl(bundle.usage)], ["compactions.jsonl", jsonl(bundle.compactions)], ["evidence.jsonl", jsonl(bundle.evidence)]]);
|
|
67461
68492
|
for (const [name, content] of files)
|
|
67462
|
-
atomicWriteFile(
|
|
68493
|
+
atomicWriteFile(join36(directory, name), content, 384);
|
|
67463
68494
|
const checksums = [...files.keys()].sort().map((name) => `${sha2562(files.get(name))} ${name}`).join(`
|
|
67464
68495
|
`);
|
|
67465
|
-
atomicWriteFile(
|
|
68496
|
+
atomicWriteFile(join36(directory, "checksums.sha256"), `${checksums}
|
|
67466
68497
|
`, 384);
|
|
67467
68498
|
for (const name of [...files.keys(), "checksums.sha256"])
|
|
67468
|
-
chmodSync3(
|
|
68499
|
+
chmodSync3(join36(directory, name), 292);
|
|
67469
68500
|
return directory;
|
|
67470
68501
|
}
|
|
67471
68502
|
function writeBenchmarkResult(result, path) {
|
|
67472
68503
|
const directory = path.slice(0, Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")));
|
|
67473
68504
|
if (directory)
|
|
67474
|
-
|
|
68505
|
+
mkdirSync12(directory, {
|
|
67475
68506
|
recursive: true
|
|
67476
68507
|
});
|
|
67477
68508
|
atomicWriteFile(path, json(result), 384);
|
|
@@ -67489,7 +68520,7 @@ function jsonl(values) {
|
|
|
67489
68520
|
` : "";
|
|
67490
68521
|
}
|
|
67491
68522
|
function sha2562(value) {
|
|
67492
|
-
return
|
|
68523
|
+
return createHash14("sha256").update(value).digest("hex");
|
|
67493
68524
|
}
|
|
67494
68525
|
var init_bundle = __esm(() => {
|
|
67495
68526
|
init_hash();
|
|
@@ -67497,8 +68528,8 @@ var init_bundle = __esm(() => {
|
|
|
67497
68528
|
});
|
|
67498
68529
|
|
|
67499
68530
|
// src/agent-benchmark/docker-lifecycle.ts
|
|
67500
|
-
import { existsSync as
|
|
67501
|
-
import { resolve as
|
|
68531
|
+
import { existsSync as existsSync28 } from "fs";
|
|
68532
|
+
import { resolve as resolve12 } from "path";
|
|
67502
68533
|
|
|
67503
68534
|
class BenchmarkDockerLifecycle {
|
|
67504
68535
|
constructor(manifest, workspace, runId, runner = runProcess2) {
|
|
@@ -67616,7 +68647,7 @@ function buildBenchmarkDockerPlan(manifest, workspace, runId, agentImageId) {
|
|
|
67616
68647
|
throw new Error("docker benchmark requires a pinned target image");
|
|
67617
68648
|
if (!manifest.antiCheat)
|
|
67618
68649
|
throw new Error("docker benchmark requires an external anti-cheat hook");
|
|
67619
|
-
if (!
|
|
68650
|
+
if (!existsSync28(manifest.antiCheat.executable))
|
|
67620
68651
|
throw new Error("anti-cheat executable is missing");
|
|
67621
68652
|
if (hashPath(manifest.antiCheat.executable) !== manifest.antiCheat.executableSha256)
|
|
67622
68653
|
throw new Error("anti-cheat executable hash mismatch");
|
|
@@ -67635,7 +68666,7 @@ function buildBenchmarkDockerPlan(manifest, workspace, runId, agentImageId) {
|
|
|
67635
68666
|
const resourceArgs = [...resources?.cpus ? ["--cpus", String(resources.cpus)] : [], ...resources?.memoryMb ? ["--memory", `${resources.memoryMb}m`] : []];
|
|
67636
68667
|
const targetImage = pinnedImage(manifest.challenge.targetImage, manifest.challenge.targetImageDigest);
|
|
67637
68668
|
const targetStart = ["run", "-d", "--name", names.target, "--network", names.network, "--network-alias", "target", "--cap-drop", "ALL", "--cap-add", "NET_BIND_SERVICE", ...common, ...resourceArgs, targetImage, ...manifest.challenge.targetCommand ?? []];
|
|
67638
|
-
const resolvedWorkspace =
|
|
68669
|
+
const resolvedWorkspace = resolve12(workspace);
|
|
67639
68670
|
const agentStart = ["run", "-d", "--name", names.agent, "--network", names.network, "--workdir", "/workspace", "--volume", `${resolvedWorkspace}:/workspace:rw`, "--volume", "/workspace/.farai", "--read-only", "--tmpfs", "/tmp:rw,nosuid,nodev,size=512m", "--tmpfs", "/root:rw,nosuid,nodev,size=256m", "--tmpfs", "/run:rw,nosuid,nodev,size=64m", "--cap-drop", "ALL", "--cap-add", "NET_ADMIN", "--cap-add", "NET_RAW", ...common, ...resourceArgs, agentImageId, "sleep", "infinity"];
|
|
67640
68671
|
return {
|
|
67641
68672
|
names,
|
|
@@ -67685,9 +68716,9 @@ var init_docker_lifecycle = __esm(() => {
|
|
|
67685
68716
|
});
|
|
67686
68717
|
|
|
67687
68718
|
// src/agent-benchmark/git-state.ts
|
|
67688
|
-
import { createHash as
|
|
67689
|
-
import { lstatSync as
|
|
67690
|
-
import { isAbsolute as
|
|
68719
|
+
import { createHash as createHash15 } from "crypto";
|
|
68720
|
+
import { lstatSync as lstatSync12, readlinkSync } from "fs";
|
|
68721
|
+
import { isAbsolute as isAbsolute10, relative as relative12, resolve as resolve13 } from "path";
|
|
67691
68722
|
import { spawn as spawn5 } from "child_process";
|
|
67692
68723
|
async function freezeGitSourceState(root) {
|
|
67693
68724
|
if (!await isGitWorktree(root))
|
|
@@ -67724,7 +68755,7 @@ async function readGitCommit(root) {
|
|
|
67724
68755
|
return commit.toLowerCase();
|
|
67725
68756
|
}
|
|
67726
68757
|
async function hashGitWorktree(root, hasCommit) {
|
|
67727
|
-
const hash =
|
|
68758
|
+
const hash = createHash15("sha256");
|
|
67728
68759
|
hash.update("farai-git-worktree-v2\x00");
|
|
67729
68760
|
await hashCommand(root, ["status", "--porcelain=v1", "-z", "--untracked-files=no", "--ignore-submodules=none"], hash, "status");
|
|
67730
68761
|
await hashCommand(root, ["diff", "--no-ext-diff", "--no-textconv", "--binary", "--full-index", "--submodule=diff", "--"], hash, "unstaged");
|
|
@@ -67766,17 +68797,17 @@ function hashUntrackedPath(root, encodedPath, hash) {
|
|
|
67766
68797
|
const path = encodedPath.toString("utf8");
|
|
67767
68798
|
if (!Buffer.from(path, "utf8").equals(encodedPath))
|
|
67768
68799
|
throw new Error("git returned an untracked path that is not valid utf-8");
|
|
67769
|
-
const absolute =
|
|
67770
|
-
const local = relative12(
|
|
67771
|
-
if (!path ||
|
|
68800
|
+
const absolute = resolve13(root, path);
|
|
68801
|
+
const local = relative12(resolve13(root), absolute);
|
|
68802
|
+
if (!path || isAbsolute10(path) || local === ".." || local.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute10(local)) {
|
|
67772
68803
|
throw new Error(`git returned an unsafe untracked path: ${path}`);
|
|
67773
68804
|
}
|
|
67774
|
-
const stat =
|
|
68805
|
+
const stat = lstatSync12(absolute);
|
|
67775
68806
|
hash.update("path\x00");
|
|
67776
68807
|
hash.update(encodedPath);
|
|
67777
68808
|
hash.update("\x00");
|
|
67778
68809
|
if (stat.isFile()) {
|
|
67779
|
-
hash.update(`file\x00${stat.mode & 511}\x00${stat.size}\x00${
|
|
68810
|
+
hash.update(`file\x00${stat.mode & 511}\x00${stat.size}\x00${hashFile2(absolute)}\x00`);
|
|
67780
68811
|
return;
|
|
67781
68812
|
}
|
|
67782
68813
|
if (stat.isSymbolicLink()) {
|
|
@@ -67877,27 +68908,27 @@ __export(exports_runner, {
|
|
|
67877
68908
|
normalizeBenchmarkManifest: () => normalizeBenchmarkManifest,
|
|
67878
68909
|
loadBenchmarkManifest: () => loadBenchmarkManifest
|
|
67879
68910
|
});
|
|
67880
|
-
import { cpSync, existsSync as
|
|
68911
|
+
import { cpSync, existsSync as existsSync29, lstatSync as lstatSync13, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, readdirSync as readdirSync14, renameSync as renameSync9, rmSync as rmSync11, rmdirSync } from "fs";
|
|
67881
68912
|
import { arch, platform, tmpdir as tmpdir4 } from "os";
|
|
67882
|
-
import { dirname as
|
|
67883
|
-
import { randomUUID as
|
|
68913
|
+
import { dirname as dirname13, isAbsolute as isAbsolute11, join as join37, relative as relative13, resolve as resolve14 } from "path";
|
|
68914
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
67884
68915
|
async function runBenchmark(input, options = {}) {
|
|
67885
68916
|
const manifest = normalizeBenchmarkManifest(input);
|
|
67886
68917
|
assertExecutableIsolation(manifest);
|
|
67887
|
-
const workspace = options.workspace ?? mkdtempSync3(
|
|
67888
|
-
const artifactsRoot = options.artifactsDir ?? mkdtempSync3(
|
|
68918
|
+
const workspace = options.workspace ?? mkdtempSync3(join37(tmpdir4(), "farai-benchmark-"));
|
|
68919
|
+
const artifactsRoot = options.artifactsDir ?? mkdtempSync3(join37(tmpdir4(), "farai-benchmark-artifacts-"));
|
|
67889
68920
|
const repetition = options.repetition ?? 1;
|
|
67890
|
-
|
|
68921
|
+
mkdirSync13(workspace, {
|
|
67891
68922
|
recursive: true
|
|
67892
68923
|
});
|
|
67893
68924
|
assertCleanWorkspace(workspace);
|
|
67894
68925
|
assertArtifactsOutsideWorkspace(workspace, artifactsRoot);
|
|
67895
|
-
|
|
68926
|
+
mkdirSync13(artifactsRoot, {
|
|
67896
68927
|
recursive: true
|
|
67897
68928
|
});
|
|
67898
68929
|
stageFiles(manifest, workspace);
|
|
67899
68930
|
const runId = id();
|
|
67900
|
-
const bundlePath =
|
|
68931
|
+
const bundlePath = join37(artifactsRoot, `${safeName2(manifest.challenge.id)}-r${repetition}-${runId}`);
|
|
67901
68932
|
const provider = options.provider ?? await createChatProviderForSession(syntheticSession(workspace, manifest));
|
|
67902
68933
|
assertProvider(manifest, provider);
|
|
67903
68934
|
const dockerLifecycle = manifest.isolation.backend === "docker" ? new BenchmarkDockerLifecycle(manifest, workspace, runId, options.dockerProcessRunner) : undefined;
|
|
@@ -67941,7 +68972,7 @@ async function runBenchmark(input, options = {}) {
|
|
|
67941
68972
|
session = runtime.updateSession(session.id, {
|
|
67942
68973
|
toolScope: activeTools.map((tool) => tool.name)
|
|
67943
68974
|
});
|
|
67944
|
-
const faraiRoot = options.faraiRoot ??
|
|
68975
|
+
const faraiRoot = options.faraiRoot ?? resolve14(import.meta.dir, "..", "..");
|
|
67945
68976
|
const frozen = await freezeRun(manifest, session, activeTools, faraiRoot, provider, dockerState?.agentImageId);
|
|
67946
68977
|
const promptPromise = runtime.prompt(session, manifest.challenge.prompt).then((result2) => {
|
|
67947
68978
|
response = result2.response;
|
|
@@ -68072,13 +69103,13 @@ function assertExecutableIsolation(manifest) {
|
|
|
68072
69103
|
}
|
|
68073
69104
|
}
|
|
68074
69105
|
function assertCleanWorkspace(workspace) {
|
|
68075
|
-
const entries =
|
|
69106
|
+
const entries = readdirSync14(workspace);
|
|
68076
69107
|
if (entries.length)
|
|
68077
69108
|
throw new Error(`benchmark workspace must be an empty scratch directory: ${workspace}`);
|
|
68078
69109
|
}
|
|
68079
69110
|
function assertArtifactsOutsideWorkspace(workspace, artifactsRoot) {
|
|
68080
|
-
const difference = relative13(
|
|
68081
|
-
const reverse = relative13(
|
|
69111
|
+
const difference = relative13(resolve14(workspace), resolve14(artifactsRoot));
|
|
69112
|
+
const reverse = relative13(resolve14(artifactsRoot), resolve14(workspace));
|
|
68082
69113
|
if (!difference || !difference.startsWith("..") || !reverse.startsWith("..")) {
|
|
68083
69114
|
throw new Error("benchmark artifacts directory must be outside the scratch workspace");
|
|
68084
69115
|
}
|
|
@@ -68175,18 +69206,18 @@ function collectRunData(runtime, rootSessionId) {
|
|
|
68175
69206
|
};
|
|
68176
69207
|
}
|
|
68177
69208
|
function stageFiles(manifest, workspace) {
|
|
68178
|
-
const root =
|
|
68179
|
-
const workspaceStat =
|
|
69209
|
+
const root = resolve14(workspace);
|
|
69210
|
+
const workspaceStat = lstatSync13(root);
|
|
68180
69211
|
if (!workspaceStat.isDirectory() || workspaceStat.isSymbolicLink())
|
|
68181
69212
|
throw new Error("benchmark workspace must be a real directory");
|
|
68182
69213
|
const inputs = (manifest.files ?? []).map((file) => {
|
|
68183
|
-
const source =
|
|
68184
|
-
if (!
|
|
69214
|
+
const source = resolve14(file.source);
|
|
69215
|
+
if (!existsSync29(source))
|
|
68185
69216
|
throw new Error(`benchmark input does not exist: ${file.source}`);
|
|
68186
69217
|
const expectedHash = file.sha256?.toLowerCase() ?? hashPath(source);
|
|
68187
69218
|
if (hashPath(source) !== expectedHash)
|
|
68188
69219
|
throw new Error(`benchmark input hash mismatch: ${file.source}`);
|
|
68189
|
-
const target =
|
|
69220
|
+
const target = resolve14(root, file.destination);
|
|
68190
69221
|
if (!isDescendantPath(relative13(root, target)))
|
|
68191
69222
|
throw new Error(`benchmark destination escapes scratch workspace: ${file.destination}`);
|
|
68192
69223
|
return {
|
|
@@ -68208,10 +69239,10 @@ function stageFiles(manifest, workspace) {
|
|
|
68208
69239
|
const createdDirectories = [];
|
|
68209
69240
|
try {
|
|
68210
69241
|
for (const input of inputs) {
|
|
68211
|
-
ensureStagingParent(root,
|
|
68212
|
-
const staged =
|
|
69242
|
+
ensureStagingParent(root, dirname13(input.target), createdDirectories);
|
|
69243
|
+
const staged = join37(dirname13(input.target), `.${randomUUID11()}.farai-stage`);
|
|
68213
69244
|
try {
|
|
68214
|
-
const sourceStat =
|
|
69245
|
+
const sourceStat = lstatSync13(input.source);
|
|
68215
69246
|
cpSync(input.source, staged, {
|
|
68216
69247
|
recursive: sourceStat.isDirectory(),
|
|
68217
69248
|
dereference: false,
|
|
@@ -68223,14 +69254,14 @@ function stageFiles(manifest, workspace) {
|
|
|
68223
69254
|
throw new Error(`benchmark input was not staged: ${input.file.destination}`);
|
|
68224
69255
|
if (hashPath(staged) !== input.expectedHash)
|
|
68225
69256
|
throw new Error(`benchmark input changed while staging: ${input.file.source}`);
|
|
68226
|
-
if (
|
|
69257
|
+
if (lstatSync13(staged).isDirectory() && !listFiles2(staged).length)
|
|
68227
69258
|
throw new Error(`benchmark input staged an empty directory: ${input.file.destination}`);
|
|
68228
69259
|
if (pathExists(input.target))
|
|
68229
69260
|
throw new Error(`benchmark destinations must not overlap: ${input.file.destination}`);
|
|
68230
|
-
|
|
69261
|
+
renameSync9(staged, input.target);
|
|
68231
69262
|
published.push(input.target);
|
|
68232
69263
|
} finally {
|
|
68233
|
-
|
|
69264
|
+
rmSync11(staged, {
|
|
68234
69265
|
recursive: true,
|
|
68235
69266
|
force: true
|
|
68236
69267
|
});
|
|
@@ -68238,7 +69269,7 @@ function stageFiles(manifest, workspace) {
|
|
|
68238
69269
|
}
|
|
68239
69270
|
} catch (error) {
|
|
68240
69271
|
for (const target of published.reverse())
|
|
68241
|
-
|
|
69272
|
+
rmSync11(target, {
|
|
68242
69273
|
recursive: true,
|
|
68243
69274
|
force: true
|
|
68244
69275
|
});
|
|
@@ -68258,42 +69289,42 @@ function pathsOverlap(left, right) {
|
|
|
68258
69289
|
return isDescendantPath(leftToRight) || isDescendantPath(rightToLeft);
|
|
68259
69290
|
}
|
|
68260
69291
|
function isDescendantPath(value) {
|
|
68261
|
-
return Boolean(value) && value !== ".." && !value.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) && !
|
|
69292
|
+
return Boolean(value) && value !== ".." && !value.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) && !isAbsolute11(value);
|
|
68262
69293
|
}
|
|
68263
69294
|
function listFiles2(rootPath) {
|
|
68264
|
-
if (!
|
|
69295
|
+
if (!existsSync29(rootPath))
|
|
68265
69296
|
return [];
|
|
68266
|
-
const stat =
|
|
69297
|
+
const stat = lstatSync13(rootPath);
|
|
68267
69298
|
if (stat.isFile())
|
|
68268
69299
|
return [rootPath];
|
|
68269
69300
|
if (!stat.isDirectory())
|
|
68270
69301
|
throw new Error(`unsupported staged benchmark input type: ${rootPath}`);
|
|
68271
|
-
return
|
|
69302
|
+
return readdirSync14(rootPath).flatMap((name) => listFiles2(join37(rootPath, name)));
|
|
68272
69303
|
}
|
|
68273
69304
|
function ensureStagingParent(workspace, parent, createdDirectories) {
|
|
68274
|
-
const root =
|
|
68275
|
-
const local = relative13(root,
|
|
69305
|
+
const root = resolve14(workspace);
|
|
69306
|
+
const local = relative13(root, resolve14(parent));
|
|
68276
69307
|
if (local === "")
|
|
68277
69308
|
return;
|
|
68278
69309
|
if (!isDescendantPath(local))
|
|
68279
69310
|
throw new Error("benchmark staging parent escapes scratch workspace");
|
|
68280
69311
|
let current = root;
|
|
68281
69312
|
for (const segment of local.split(/[\\/]+/).filter(Boolean)) {
|
|
68282
|
-
current =
|
|
69313
|
+
current = join37(current, segment);
|
|
68283
69314
|
if (!pathExists(current)) {
|
|
68284
|
-
|
|
69315
|
+
mkdirSync13(current, {
|
|
68285
69316
|
mode: 448
|
|
68286
69317
|
});
|
|
68287
69318
|
createdDirectories.push(current);
|
|
68288
69319
|
}
|
|
68289
|
-
const stat =
|
|
69320
|
+
const stat = lstatSync13(current);
|
|
68290
69321
|
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
68291
69322
|
throw new Error(`benchmark staging parent must be a real directory: ${current}`);
|
|
68292
69323
|
}
|
|
68293
69324
|
}
|
|
68294
69325
|
function pathExists(path) {
|
|
68295
69326
|
try {
|
|
68296
|
-
|
|
69327
|
+
lstatSync13(path);
|
|
68297
69328
|
return true;
|
|
68298
69329
|
} catch (error) {
|
|
68299
69330
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT")
|
|
@@ -68343,7 +69374,7 @@ class BenchmarkHostBackend {
|
|
|
68343
69374
|
hostPath(path) {
|
|
68344
69375
|
if (path === "/workspace")
|
|
68345
69376
|
return this.workspace;
|
|
68346
|
-
return
|
|
69377
|
+
return join37(this.workspace, path.slice("/workspace/".length));
|
|
68347
69378
|
}
|
|
68348
69379
|
}
|
|
68349
69380
|
async function freezeRun(manifest, session, tools, faraiRoot, provider, kaliImageId) {
|
|
@@ -68491,7 +69522,7 @@ async function validateCandidates(manifest, sources, workspace) {
|
|
|
68491
69522
|
}
|
|
68492
69523
|
async function runOracle(oracle, candidate2, workspace, challengeId) {
|
|
68493
69524
|
if (oracle.executableSha256) {
|
|
68494
|
-
if (!
|
|
69525
|
+
if (!existsSync29(oracle.command[0]))
|
|
68495
69526
|
return {
|
|
68496
69527
|
ok: false,
|
|
68497
69528
|
error: "oracle executable missing"
|
|
@@ -68588,7 +69619,7 @@ var init_runner = __esm(() => {
|
|
|
68588
69619
|
init_docker_lifecycle();
|
|
68589
69620
|
init_hash();
|
|
68590
69621
|
init_git_state();
|
|
68591
|
-
|
|
69622
|
+
init_manifest2();
|
|
68592
69623
|
});
|
|
68593
69624
|
|
|
68594
69625
|
// src/agent-benchmark/suite.ts
|
|
@@ -68599,16 +69630,16 @@ __export(exports_suite, {
|
|
|
68599
69630
|
normalizeBenchmarkSuiteManifest: () => normalizeBenchmarkSuiteManifest,
|
|
68600
69631
|
loadBenchmarkSuiteManifest: () => loadBenchmarkSuiteManifest
|
|
68601
69632
|
});
|
|
68602
|
-
import { mkdirSync as
|
|
69633
|
+
import { mkdirSync as mkdirSync14, mkdtempSync as mkdtempSync4 } from "fs";
|
|
68603
69634
|
import { tmpdir as tmpdir5 } from "os";
|
|
68604
|
-
import { join as
|
|
69635
|
+
import { join as join38 } from "path";
|
|
68605
69636
|
async function runBenchmarkSuite(input, options = {}) {
|
|
68606
69637
|
const manifest = normalizeBenchmarkSuiteManifest(input);
|
|
68607
69638
|
const campaignId = id();
|
|
68608
|
-
const root = options.artifactsDir ?? mkdtempSync4(
|
|
68609
|
-
const bundlePath =
|
|
68610
|
-
const runsPath =
|
|
68611
|
-
|
|
69639
|
+
const root = options.artifactsDir ?? mkdtempSync4(join38(tmpdir5(), "farai-benchmark-campaign-"));
|
|
69640
|
+
const bundlePath = join38(root, `${safeName3(manifest.id)}-${campaignId}`);
|
|
69641
|
+
const runsPath = join38(bundlePath, "runs");
|
|
69642
|
+
mkdirSync14(runsPath, {
|
|
68612
69643
|
recursive: true
|
|
68613
69644
|
});
|
|
68614
69645
|
const attempts = [];
|
|
@@ -68701,9 +69732,9 @@ async function runBenchmarkSuite(input, options = {}) {
|
|
|
68701
69732
|
error: outcome.error
|
|
68702
69733
|
})
|
|
68703
69734
|
};
|
|
68704
|
-
atomicWriteFile(
|
|
69735
|
+
atomicWriteFile(join38(bundlePath, "campaign.json"), `${JSON.stringify(result, null, 2)}
|
|
68705
69736
|
`, 384);
|
|
68706
|
-
atomicWriteFile(
|
|
69737
|
+
atomicWriteFile(join38(bundlePath, "suite.sha256"), `${result.manifestHash}
|
|
68707
69738
|
`, 384);
|
|
68708
69739
|
return result;
|
|
68709
69740
|
}
|
|
@@ -68744,7 +69775,7 @@ function safeName3(value) {
|
|
|
68744
69775
|
var init_suite = __esm(() => {
|
|
68745
69776
|
init_atomic_file();
|
|
68746
69777
|
init_hash();
|
|
68747
|
-
|
|
69778
|
+
init_manifest2();
|
|
68748
69779
|
init_runner();
|
|
68749
69780
|
});
|
|
68750
69781
|
|
|
@@ -68759,6 +69790,7 @@ init_global_config();
|
|
|
68759
69790
|
init_config();
|
|
68760
69791
|
init_branding();
|
|
68761
69792
|
init_version();
|
|
69793
|
+
init_session_catalog();
|
|
68762
69794
|
|
|
68763
69795
|
// src/cli/command-arguments.ts
|
|
68764
69796
|
init_model_provider_validation();
|
|
@@ -68767,6 +69799,16 @@ function parseNoArguments(command, args) {
|
|
|
68767
69799
|
if (args.length > 0)
|
|
68768
69800
|
throw new Error(`${command} does not accept arguments`);
|
|
68769
69801
|
}
|
|
69802
|
+
function parseUpdateArguments(args) {
|
|
69803
|
+
const subcommand = args[0] ?? "status";
|
|
69804
|
+
if (subcommand !== "check" && subcommand !== "apply" && subcommand !== "status" && subcommand !== "rollback") {
|
|
69805
|
+
throw new Error(`unknown update command: ${subcommand}`);
|
|
69806
|
+
}
|
|
69807
|
+
parseNoArguments(`update ${subcommand}`, args.slice(1));
|
|
69808
|
+
return {
|
|
69809
|
+
kind: subcommand
|
|
69810
|
+
};
|
|
69811
|
+
}
|
|
68770
69812
|
function parseSetupArguments(args) {
|
|
68771
69813
|
const {
|
|
68772
69814
|
values,
|
|
@@ -69266,6 +70308,13 @@ async function main() {
|
|
|
69266
70308
|
ensureDefaultUserConfig();
|
|
69267
70309
|
console.log(globalConfigPath());
|
|
69268
70310
|
break;
|
|
70311
|
+
case "update":
|
|
70312
|
+
if (wantsHelp(args2)) {
|
|
70313
|
+
help("update");
|
|
70314
|
+
break;
|
|
70315
|
+
}
|
|
70316
|
+
await updateContent(args2);
|
|
70317
|
+
break;
|
|
69269
70318
|
default:
|
|
69270
70319
|
console.error(`unknown command: ${command}`);
|
|
69271
70320
|
help();
|
|
@@ -69297,6 +70346,11 @@ async function doctor() {
|
|
|
69297
70346
|
console.log(`kali image: ${backend2.image} (${image.exists ? "exists" : "missing"})`);
|
|
69298
70347
|
console.log(`kali contract: ${image.contract ?? "missing"}`);
|
|
69299
70348
|
console.log(`kali capabilities: ${image.contract === KALI_IMAGE_CONTRACT ? "ready" : "rebuild required"}`);
|
|
70349
|
+
const {
|
|
70350
|
+
contentStatus: contentStatus2
|
|
70351
|
+
} = await Promise.resolve().then(() => (init_updater(), exports_updater));
|
|
70352
|
+
const content = contentStatus2();
|
|
70353
|
+
console.log(`content: ${content.active?.version ?? "local fallback"}`);
|
|
69300
70354
|
console.log(`setup command: farai setup`);
|
|
69301
70355
|
}
|
|
69302
70356
|
async function setup(args2) {
|
|
@@ -69437,6 +70491,14 @@ async function initLab(args2) {
|
|
|
69437
70491
|
}
|
|
69438
70492
|
async function launchTui(workspace, sessionId) {
|
|
69439
70493
|
ensureDefaultUserConfig();
|
|
70494
|
+
const {
|
|
70495
|
+
runStartupContentPreflight: runStartupContentPreflight2
|
|
70496
|
+
} = await Promise.resolve().then(() => (init_preflight(), exports_preflight));
|
|
70497
|
+
const effectiveWorkspace = sessionId ? resolveSessionLocation(sessionId)?.workspace ?? workspace : workspace;
|
|
70498
|
+
if (await runStartupContentPreflight2(effectiveWorkspace) === "cancelled") {
|
|
70499
|
+
process.exitCode = 130;
|
|
70500
|
+
return;
|
|
70501
|
+
}
|
|
69440
70502
|
if (import.meta.path.endsWith(".ts")) {
|
|
69441
70503
|
const sourceTuiPreload = "@opentui/solid/preload";
|
|
69442
70504
|
await import(sourceTuiPreload);
|
|
@@ -69454,6 +70516,13 @@ async function launchTui(workspace, sessionId) {
|
|
|
69454
70516
|
process.exitCode = 1;
|
|
69455
70517
|
}
|
|
69456
70518
|
}
|
|
70519
|
+
async function updateContent(args2) {
|
|
70520
|
+
const parsed = parseUpdateArguments(args2);
|
|
70521
|
+
const {
|
|
70522
|
+
runContentUpdateCommand: runContentUpdateCommand2
|
|
70523
|
+
} = await Promise.resolve().then(() => (init_command2(), exports_command2));
|
|
70524
|
+
process.exitCode = await runContentUpdateCommand2(parsed, process.cwd());
|
|
70525
|
+
}
|
|
69457
70526
|
async function run2(args2) {
|
|
69458
70527
|
const {
|
|
69459
70528
|
sessionId,
|
|
@@ -69619,7 +70688,14 @@ Usage:
|
|
|
69619
70688
|
config: `Farai config
|
|
69620
70689
|
|
|
69621
70690
|
Usage:
|
|
69622
|
-
farai config
|
|
70691
|
+
farai config`,
|
|
70692
|
+
update: `Farai update
|
|
70693
|
+
|
|
70694
|
+
Usage:
|
|
70695
|
+
farai update status
|
|
70696
|
+
farai update check
|
|
70697
|
+
farai update apply
|
|
70698
|
+
farai update rollback`
|
|
69623
70699
|
};
|
|
69624
70700
|
if (topic && !pages[topic])
|
|
69625
70701
|
throw new Error(`unknown help topic: ${topic}`);
|
|
@@ -69637,6 +70713,7 @@ Usage:
|
|
|
69637
70713
|
farai bench run <manifest.json> [--output result.json] [--workspace scratch-dir] [--artifacts dir]
|
|
69638
70714
|
farai bench suite <suite.json> [--artifacts dir]
|
|
69639
70715
|
farai config
|
|
70716
|
+
farai update [status|check|apply|rollback]
|
|
69640
70717
|
|
|
69641
70718
|
settings live in ~/.local/pajarori/farai/config.toml; credentials use the system keyring.
|
|
69642
70719
|
|
|
@@ -69650,5 +70727,5 @@ Examples:
|
|
|
69650
70727
|
`);
|
|
69651
70728
|
}
|
|
69652
70729
|
|
|
69653
|
-
//# debugId=
|
|
70730
|
+
//# debugId=59D0DF40CE3D0BDB64756E2164756E21
|
|
69654
70731
|
//# sourceMappingURL=index.js.map
|