agent-valley 2.2.1 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/plugin.json +1 -1
- package/dist/index.js +759 -317
- package/dist/supervisor.js +75 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6439,6 +6439,72 @@ var init_zod = __esm(() => {
|
|
|
6439
6439
|
init_external();
|
|
6440
6440
|
});
|
|
6441
6441
|
|
|
6442
|
+
// ../../packages/core/src/oma/skill-matrix-schema.ts
|
|
6443
|
+
var hash, name, bounded, path, skillCompatibilityConfigSchema, skillCompatibilityPolicySchema, omaConfigSchema, matrixSkillSchema, matrixReportSchema;
|
|
6444
|
+
var init_skill_matrix_schema = __esm(() => {
|
|
6445
|
+
init_zod();
|
|
6446
|
+
hash = string2().regex(/^[a-f0-9]{64}$/);
|
|
6447
|
+
name = string2().regex(/^[a-z0-9][a-z0-9-]{0,127}$/);
|
|
6448
|
+
bounded = string2().trim().min(1).max(2000);
|
|
6449
|
+
path = string2().min(1).max(4096).refine((value) => !value.includes("\x00"));
|
|
6450
|
+
skillCompatibilityConfigSchema = strictObject({
|
|
6451
|
+
report_path: path,
|
|
6452
|
+
max_age_hours: number2().finite().positive().max(8760).default(168),
|
|
6453
|
+
mode: _enum(["warn", "require"])
|
|
6454
|
+
});
|
|
6455
|
+
skillCompatibilityPolicySchema = strictObject({
|
|
6456
|
+
reportPath: path,
|
|
6457
|
+
maxAgeHours: number2().finite().positive().max(8760),
|
|
6458
|
+
mode: _enum(["warn", "require"])
|
|
6459
|
+
});
|
|
6460
|
+
omaConfigSchema = strictObject({
|
|
6461
|
+
mode: _enum(["off", "strict"]).default("off"),
|
|
6462
|
+
skill_compatibility: skillCompatibilityConfigSchema.optional()
|
|
6463
|
+
});
|
|
6464
|
+
matrixSkillSchema = object({
|
|
6465
|
+
name,
|
|
6466
|
+
hash,
|
|
6467
|
+
caseId: bounded,
|
|
6468
|
+
requiredFiles: array(path).min(1).max(500),
|
|
6469
|
+
missingFiles: array(path).max(500),
|
|
6470
|
+
excludedReferences: array(object({ path, reason: bounded })).max(500)
|
|
6471
|
+
});
|
|
6472
|
+
matrixReportSchema = object({
|
|
6473
|
+
schemaVersion: literal(1),
|
|
6474
|
+
kind: literal("skill-compatibility-matrix"),
|
|
6475
|
+
mode: _enum(["plan", "live"]),
|
|
6476
|
+
status: _enum(["planned", "completed", "cancelled", "interrupted"]),
|
|
6477
|
+
createdAt: exports_iso.datetime(),
|
|
6478
|
+
omaVersion: bounded,
|
|
6479
|
+
host: object({ platform: bounded, arch: bounded, node: bounded }),
|
|
6480
|
+
suiteHash: hash,
|
|
6481
|
+
sourceKind: _enum(["synthetic", "installed"]),
|
|
6482
|
+
delivery: _enum(["native", "injected"]),
|
|
6483
|
+
auditScope: _enum(["fixture-contract", "read-reference"]),
|
|
6484
|
+
protocolVersion: literal("oma-skill-matrix-v2"),
|
|
6485
|
+
bundle: object({ hash, skills: array(matrixSkillSchema).min(1).max(100) }).optional(),
|
|
6486
|
+
cases: array(object({ id: bounded, skill: name })).max(100),
|
|
6487
|
+
models: object({ claude: bounded.nullable(), codex: bounded.nullable() }),
|
|
6488
|
+
cells: array(object({
|
|
6489
|
+
caseId: bounded,
|
|
6490
|
+
skill: name,
|
|
6491
|
+
vendor: _enum(["claude", "codex"]),
|
|
6492
|
+
status: _enum(["pass", "fail", "unverifiable", "error"]),
|
|
6493
|
+
contentHash: hash,
|
|
6494
|
+
checks: array(object({
|
|
6495
|
+
id: bounded,
|
|
6496
|
+
status: _enum(["pass", "fail", "unverifiable"]),
|
|
6497
|
+
detail: bounded,
|
|
6498
|
+
proof: _enum(["read", "canary"]).optional()
|
|
6499
|
+
})).max(1000),
|
|
6500
|
+
nativeActivation: _enum(["observed", "unobserved"]),
|
|
6501
|
+
cliVersion: string2().regex(/^[\w .()+/-]{1,160}$/).nullable(),
|
|
6502
|
+
model: bounded.nullable(),
|
|
6503
|
+
durationMs: number2().finite().nonnegative()
|
|
6504
|
+
})).max(200)
|
|
6505
|
+
});
|
|
6506
|
+
});
|
|
6507
|
+
|
|
6442
6508
|
// ../../packages/core/src/config/task-schema.ts
|
|
6443
6509
|
var reportPath, taskSchema, resolvedTaskSchema;
|
|
6444
6510
|
var init_task_schema = __esm(() => {
|
|
@@ -6896,6 +6962,7 @@ var init_execution = __esm(() => {
|
|
|
6896
6962
|
var actorType, text, amount, routingCandidateSchema, chiefOperatingPolicySchema, operatingRunSchema, routeEvidenceSchema, reviewDecisionSchema, chiefOperationsSchema;
|
|
6897
6963
|
var init_operations = __esm(() => {
|
|
6898
6964
|
init_zod();
|
|
6965
|
+
init_skill_matrix_schema();
|
|
6899
6966
|
actorType = string2().regex(/^[a-z0-9][a-z0-9-]{0,127}$/);
|
|
6900
6967
|
text = string2().trim().min(1).max(2000);
|
|
6901
6968
|
amount = number2().finite().nonnegative();
|
|
@@ -6914,6 +6981,7 @@ var init_operations = __esm(() => {
|
|
|
6914
6981
|
reviewVendor: _enum(["prefer", "require", "off"]),
|
|
6915
6982
|
readyActors: array(actorType).max(20).optional(),
|
|
6916
6983
|
memory: boolean2(),
|
|
6984
|
+
skillCompatibility: skillCompatibilityPolicySchema.optional(),
|
|
6917
6985
|
metricTargets: array(strictObject({
|
|
6918
6986
|
name: text,
|
|
6919
6987
|
unit: text.optional(),
|
|
@@ -7232,7 +7300,7 @@ function chiefExecutionPolicy(config) {
|
|
|
7232
7300
|
autoResume: execution.auto_resume
|
|
7233
7301
|
} : {});
|
|
7234
7302
|
}
|
|
7235
|
-
function chiefOperatingPolicy(config, readyActors, automatic = true) {
|
|
7303
|
+
function chiefOperatingPolicy(config, readyActors, automatic = true, skillCompatibility) {
|
|
7236
7304
|
return chiefOperatingPolicySchema.parse({
|
|
7237
7305
|
routing: config.routing ? {
|
|
7238
7306
|
candidates: config.routing.candidates.map((item) => ({
|
|
@@ -7247,7 +7315,8 @@ function chiefOperatingPolicy(config, readyActors, automatic = true) {
|
|
|
7247
7315
|
reviewVendor: config.review_vendor ?? "prefer",
|
|
7248
7316
|
memory: config.memory ?? true,
|
|
7249
7317
|
metricTargets: config.metric_targets,
|
|
7250
|
-
readyActors
|
|
7318
|
+
readyActors,
|
|
7319
|
+
skillCompatibility
|
|
7251
7320
|
});
|
|
7252
7321
|
}
|
|
7253
7322
|
function chiefCapturePolicy(config) {
|
|
@@ -14575,7 +14644,7 @@ function mergeConfigs(global2, project, env) {
|
|
|
14575
14644
|
tunnel: buildTunnelConfig(project),
|
|
14576
14645
|
verify: buildVerifyConfig(project),
|
|
14577
14646
|
task: project?.task?.kind === "analysis" ? { kind: "analysis", reportPath: project.task.report_path } : { kind: "code" },
|
|
14578
|
-
oma:
|
|
14647
|
+
oma: project?.oma ?? { mode: "off" },
|
|
14579
14648
|
chief: global2?.chief || project?.chief ? mergeChiefConfig(global2?.chief, project?.chief) : undefined
|
|
14580
14649
|
};
|
|
14581
14650
|
}
|
|
@@ -14613,6 +14682,7 @@ Symphony cannot start until all config errors are resolved.`);
|
|
|
14613
14682
|
var globalConfigSchema, projectConfigSchema, githubConfigSchema, mergedConfigSchema;
|
|
14614
14683
|
var init_yaml_loader = __esm(() => {
|
|
14615
14684
|
init_zod();
|
|
14685
|
+
init_skill_matrix_schema();
|
|
14616
14686
|
init_actor_schema();
|
|
14617
14687
|
init_budget_schema();
|
|
14618
14688
|
init_chief_schema();
|
|
@@ -14706,7 +14776,7 @@ var init_yaml_loader = __esm(() => {
|
|
|
14706
14776
|
tunnel: tunnelProjectSchema,
|
|
14707
14777
|
verify: verifyProjectSchema,
|
|
14708
14778
|
task: taskSchema.optional(),
|
|
14709
|
-
oma:
|
|
14779
|
+
oma: omaConfigSchema.optional(),
|
|
14710
14780
|
chief: chiefConfigSchema.optional()
|
|
14711
14781
|
}).strict().overwrite(normalizeActorDefaults);
|
|
14712
14782
|
githubConfigSchema = object({
|
|
@@ -14775,7 +14845,7 @@ var init_yaml_loader = __esm(() => {
|
|
|
14775
14845
|
tunnel: tunnelMergedSchema,
|
|
14776
14846
|
verify: verifyMergedSchema,
|
|
14777
14847
|
task: resolvedTaskSchema.optional(),
|
|
14778
|
-
oma:
|
|
14848
|
+
oma: omaConfigSchema.optional(),
|
|
14779
14849
|
chief: chiefConfigSchema.optional()
|
|
14780
14850
|
}).superRefine((cfg, ctx) => {
|
|
14781
14851
|
if (cfg.trackerKind === "linear") {
|
|
@@ -20724,7 +20794,7 @@ var init_readdirp = __esm(() => {
|
|
|
20724
20794
|
|
|
20725
20795
|
// ../../node_modules/.bun/chokidar@5.0.0/node_modules/chokidar/handler.js
|
|
20726
20796
|
import { watch as fs_watch, unwatchFile, watchFile } from "node:fs";
|
|
20727
|
-
import { realpath as fsrealpath, lstat as lstat18, open as
|
|
20797
|
+
import { realpath as fsrealpath, lstat as lstat18, open as open12, stat as stat4 } from "node:fs/promises";
|
|
20728
20798
|
import { type as osType } from "node:os";
|
|
20729
20799
|
import * as sp from "node:path";
|
|
20730
20800
|
function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
|
|
@@ -20755,9 +20825,9 @@ class NodeFsHandler {
|
|
|
20755
20825
|
_watchWithNodeFs(path, listener) {
|
|
20756
20826
|
const opts = this.fsw.options;
|
|
20757
20827
|
const directory = sp.dirname(path);
|
|
20758
|
-
const
|
|
20828
|
+
const basename = sp.basename(path);
|
|
20759
20829
|
const parent = this.fsw._getWatchedDir(directory);
|
|
20760
|
-
parent.add(
|
|
20830
|
+
parent.add(basename);
|
|
20761
20831
|
const absolutePath = sp.resolve(path);
|
|
20762
20832
|
const options = {
|
|
20763
20833
|
persistent: opts.persistent
|
|
@@ -20767,7 +20837,7 @@ class NodeFsHandler {
|
|
|
20767
20837
|
let closer;
|
|
20768
20838
|
if (opts.usePolling) {
|
|
20769
20839
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
20770
|
-
options.interval = enableBin && isBinaryPath(
|
|
20840
|
+
options.interval = enableBin && isBinaryPath(basename) ? opts.binaryInterval : opts.interval;
|
|
20771
20841
|
closer = setFsWatchFileListener(path, absolutePath, options, {
|
|
20772
20842
|
listener,
|
|
20773
20843
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -20786,10 +20856,10 @@ class NodeFsHandler {
|
|
|
20786
20856
|
return;
|
|
20787
20857
|
}
|
|
20788
20858
|
const dirname = sp.dirname(file);
|
|
20789
|
-
const
|
|
20859
|
+
const basename = sp.basename(file);
|
|
20790
20860
|
const parent = this.fsw._getWatchedDir(dirname);
|
|
20791
20861
|
let prevStats = stats;
|
|
20792
|
-
if (parent.has(
|
|
20862
|
+
if (parent.has(basename))
|
|
20793
20863
|
return;
|
|
20794
20864
|
const listener = async (path, newStats) => {
|
|
20795
20865
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
@@ -20814,9 +20884,9 @@ class NodeFsHandler {
|
|
|
20814
20884
|
prevStats = newStats;
|
|
20815
20885
|
}
|
|
20816
20886
|
} catch (error) {
|
|
20817
|
-
this.fsw._remove(dirname,
|
|
20887
|
+
this.fsw._remove(dirname, basename);
|
|
20818
20888
|
}
|
|
20819
|
-
} else if (parent.has(
|
|
20889
|
+
} else if (parent.has(basename)) {
|
|
20820
20890
|
const at = newStats.atimeMs;
|
|
20821
20891
|
const mt = newStats.mtimeMs;
|
|
20822
20892
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -21066,7 +21136,7 @@ var STR_DATA = "data", STR_END = "end", STR_CLOSE = "close", EMPTY_FN = () => {}
|
|
|
21066
21136
|
cont.watcherUnusable = true;
|
|
21067
21137
|
if (isWindows && error.code === "EPERM") {
|
|
21068
21138
|
try {
|
|
21069
|
-
const fd = await
|
|
21139
|
+
const fd = await open12(path, "r");
|
|
21070
21140
|
await fd.close();
|
|
21071
21141
|
broadcastErr(error);
|
|
21072
21142
|
} catch (err) {}
|
|
@@ -22448,8 +22518,8 @@ function canonicalConfig(config) {
|
|
|
22448
22518
|
// src/agent-provisioning.ts
|
|
22449
22519
|
import { spawn as spawn17 } from "node:child_process";
|
|
22450
22520
|
import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
|
|
22451
|
-
import { homedir as
|
|
22452
|
-
import { delimiter as delimiter3, join as
|
|
22521
|
+
import { homedir as homedir8, tmpdir as tmpdir4 } from "node:os";
|
|
22522
|
+
import { delimiter as delimiter3, join as join47 } from "node:path";
|
|
22453
22523
|
function runTerminalCommand(request, spawnCommand = spawn17) {
|
|
22454
22524
|
return new Promise((resolve) => {
|
|
22455
22525
|
let child;
|
|
@@ -22492,13 +22562,13 @@ function runTerminalCommand(request, spawnCommand = spawn17) {
|
|
|
22492
22562
|
function defaults() {
|
|
22493
22563
|
return {
|
|
22494
22564
|
platform: process.platform,
|
|
22495
|
-
home:
|
|
22565
|
+
home: homedir8(),
|
|
22496
22566
|
env: process.env,
|
|
22497
22567
|
resolveBinary: resolveBinaryPath,
|
|
22498
22568
|
discover: discoverAgents,
|
|
22499
22569
|
runCommand: runTerminalCommand,
|
|
22500
22570
|
supportsLoginCommand: (agent, path, env) => supportsNativeLoginCommand(agent, path, { env }),
|
|
22501
|
-
makeTempDir: () => mkdtempSync(
|
|
22571
|
+
makeTempDir: () => mkdtempSync(join47(tmpdir4(), "av-agent-install-")),
|
|
22502
22572
|
removeTempDir: (path) => rmSync2(path, { recursive: true, force: true })
|
|
22503
22573
|
};
|
|
22504
22574
|
}
|
|
@@ -22525,7 +22595,7 @@ async function runOfficialInstaller(installerUrl, deps, options = {}) {
|
|
|
22525
22595
|
let directory;
|
|
22526
22596
|
try {
|
|
22527
22597
|
directory = deps.makeTempDir();
|
|
22528
|
-
const scriptPath =
|
|
22598
|
+
const scriptPath = join47(directory, "install.sh");
|
|
22529
22599
|
const request = { env: options.env ?? deps.env, ...options.cwd ? { cwd: options.cwd } : {} };
|
|
22530
22600
|
const download = await deps.runCommand({
|
|
22531
22601
|
command: curl,
|
|
@@ -22596,7 +22666,7 @@ async function installChiefAgent(agent, overrides = {}) {
|
|
|
22596
22666
|
const install = await runOfficialInstaller(plan.installerUrl, deps);
|
|
22597
22667
|
if (!install.success)
|
|
22598
22668
|
return commandFailure(install.stage === "download" ? "Installer download" : "Installation", install, plan.documentation);
|
|
22599
|
-
const localBin =
|
|
22669
|
+
const localBin = join47(deps.home, ".local", "bin");
|
|
22600
22670
|
const pathParts = (deps.env.PATH ?? "").split(delimiter3);
|
|
22601
22671
|
if (!pathParts.includes(localBin))
|
|
22602
22672
|
deps.env.PATH = [localBin, ...pathParts.filter(Boolean)].join(delimiter3);
|
|
@@ -22698,17 +22768,17 @@ var init_agent_provisioning = __esm(() => {
|
|
|
22698
22768
|
// src/oma-provisioning.ts
|
|
22699
22769
|
import { mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "node:fs";
|
|
22700
22770
|
import { chmod as chmod4, lstat as lstat19, readdir as readdir12, readFile as readFile16, realpath as realpath25, unlink as unlink8, writeFile as writeFile14 } from "node:fs/promises";
|
|
22701
|
-
import { homedir as
|
|
22702
|
-
import { delimiter as delimiter4, isAbsolute as
|
|
22771
|
+
import { homedir as homedir9, tmpdir as tmpdir5 } from "node:os";
|
|
22772
|
+
import { delimiter as delimiter4, isAbsolute as isAbsolute16, join as join48, relative as relative15, resolve as resolve29 } from "node:path";
|
|
22703
22773
|
function defaults2() {
|
|
22704
|
-
const home =
|
|
22774
|
+
const home = homedir9();
|
|
22705
22775
|
return {
|
|
22706
22776
|
platform: process.platform,
|
|
22707
22777
|
home,
|
|
22708
22778
|
env: process.env,
|
|
22709
|
-
resolveBinary: (name) => resolveBinaryPath(name, name === "bun" ? [
|
|
22779
|
+
resolveBinary: (name) => resolveBinaryPath(name, name === "bun" ? [join48(process.env.BUN_INSTALL ?? join48(home, ".bun"), "bin", "bun")] : []),
|
|
22710
22780
|
runCommand: runTerminalCommand,
|
|
22711
|
-
makeTempDir: () => mkdtempSync2(
|
|
22781
|
+
makeTempDir: () => mkdtempSync2(join48(tmpdir5(), "av-oma-install-")),
|
|
22712
22782
|
removeTempDir: (path) => rmSync3(path, { recursive: true, force: true })
|
|
22713
22783
|
};
|
|
22714
22784
|
}
|
|
@@ -22729,7 +22799,7 @@ async function present(path) {
|
|
|
22729
22799
|
}
|
|
22730
22800
|
async function installedVersion2(skills) {
|
|
22731
22801
|
try {
|
|
22732
|
-
const marker = JSON.parse(await readFile16(
|
|
22802
|
+
const marker = JSON.parse(await readFile16(join48(skills, "_version.json"), "utf8"));
|
|
22733
22803
|
return marker.schemaVersion === 2 && marker.mode === "project" && typeof marker.version === "string" && /^\d+\.\d+\.\d+(?:-[a-zA-Z0-9.-]+)?$/.test(marker.version) ? marker.version : null;
|
|
22734
22804
|
} catch {
|
|
22735
22805
|
return null;
|
|
@@ -22738,7 +22808,7 @@ async function installedVersion2(skills) {
|
|
|
22738
22808
|
async function snapshotConfig(agents) {
|
|
22739
22809
|
const snapshots = [];
|
|
22740
22810
|
for (const name of CUSTOM_CONFIG_NAMES) {
|
|
22741
|
-
const path =
|
|
22811
|
+
const path = join48(agents, name);
|
|
22742
22812
|
if (!await present(path))
|
|
22743
22813
|
continue;
|
|
22744
22814
|
const file = await lstat19(path);
|
|
@@ -22758,10 +22828,10 @@ async function restoreConfig(agents, snapshots) {
|
|
|
22758
22828
|
["oma-config.yaml", "oma-config.cue"],
|
|
22759
22829
|
["oma-config.local.yaml", "oma-config.local.cue"]
|
|
22760
22830
|
]) {
|
|
22761
|
-
if (!pair.some((name) => original.has(
|
|
22831
|
+
if (!pair.some((name) => original.has(join48(agents, name))))
|
|
22762
22832
|
continue;
|
|
22763
22833
|
for (const name of pair) {
|
|
22764
|
-
const path =
|
|
22834
|
+
const path = join48(agents, name);
|
|
22765
22835
|
if (!original.has(path))
|
|
22766
22836
|
await unlink8(path).catch((error) => {
|
|
22767
22837
|
if (error.code !== "ENOENT")
|
|
@@ -22771,17 +22841,17 @@ async function restoreConfig(agents, snapshots) {
|
|
|
22771
22841
|
}
|
|
22772
22842
|
}
|
|
22773
22843
|
async function workspacePath(input) {
|
|
22774
|
-
if (!input.trim() || !
|
|
22844
|
+
if (!input.trim() || !isAbsolute16(input))
|
|
22775
22845
|
return null;
|
|
22776
|
-
const root =
|
|
22846
|
+
const root = resolve29(input);
|
|
22777
22847
|
if (!await directory2(root))
|
|
22778
22848
|
return null;
|
|
22779
|
-
for (const path of [
|
|
22849
|
+
for (const path of [join48(root, ".agents"), join48(root, ".agents", "skills")]) {
|
|
22780
22850
|
if (!await present(path))
|
|
22781
22851
|
continue;
|
|
22782
22852
|
const actual = await realpath25(path);
|
|
22783
|
-
const location =
|
|
22784
|
-
if (location === ".." || location.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ||
|
|
22853
|
+
const location = relative15(await realpath25(root), actual);
|
|
22854
|
+
if (location === ".." || location.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute16(location))
|
|
22785
22855
|
return null;
|
|
22786
22856
|
}
|
|
22787
22857
|
return root;
|
|
@@ -22791,7 +22861,7 @@ async function inspectOma(workspaceRoot, _overrides = {}) {
|
|
|
22791
22861
|
const root = await workspacePath(workspaceRoot);
|
|
22792
22862
|
if (!root)
|
|
22793
22863
|
return { success: false, message: "Choose an existing absolute workspace with project-local OMA files." };
|
|
22794
|
-
const skills =
|
|
22864
|
+
const skills = join48(root, ".agents", "skills");
|
|
22795
22865
|
const version = await installedVersion2(skills);
|
|
22796
22866
|
if (!version)
|
|
22797
22867
|
throw new Error("Invalid installed metadata");
|
|
@@ -22799,7 +22869,7 @@ async function inspectOma(workspaceRoot, _overrides = {}) {
|
|
|
22799
22869
|
if (!entries.length)
|
|
22800
22870
|
throw new Error("No installed skills");
|
|
22801
22871
|
for (const entry of entries) {
|
|
22802
|
-
if (!entry.isDirectory() || !(await lstat19(
|
|
22872
|
+
if (!entry.isDirectory() || !(await lstat19(join48(skills, entry.name, "SKILL.md"))).isFile())
|
|
22803
22873
|
throw new Error("Incomplete installed skill");
|
|
22804
22874
|
}
|
|
22805
22875
|
return {
|
|
@@ -22847,16 +22917,16 @@ async function prepareOma(workspaceRoot, overrides = {}) {
|
|
|
22847
22917
|
delete environment.OMA_YES;
|
|
22848
22918
|
environment.CI = "true";
|
|
22849
22919
|
const paths = [
|
|
22850
|
-
deps.env.BUN_INSTALL_BIN ??
|
|
22851
|
-
|
|
22920
|
+
deps.env.BUN_INSTALL_BIN ?? join48(deps.env.BUN_INSTALL ?? join48(deps.home, ".bun"), "bin"),
|
|
22921
|
+
join48(deps.home, ".local", "bin")
|
|
22852
22922
|
];
|
|
22853
22923
|
environment.PATH = [...new Set([...paths, ...(environment.PATH ?? "").split(delimiter4).filter(Boolean)])].join(delimiter4);
|
|
22854
22924
|
const request = { command: bun, env: environment, cwd: root, timeoutMs: 300000 };
|
|
22855
22925
|
const latest = await deps.runCommand({ ...request, args: ["install", "--global", LATEST_PACKAGE] });
|
|
22856
22926
|
if (!latest.success)
|
|
22857
22927
|
return failure3("OMA CLI update", latest);
|
|
22858
|
-
const agents =
|
|
22859
|
-
const existing = await installedVersion2(
|
|
22928
|
+
const agents = join48(root, ".agents");
|
|
22929
|
+
const existing = await installedVersion2(join48(agents, "skills")) !== null || await directory2(join48(agents, "skills")) && (await present(join48(agents, "oma-config.yaml")) || await present(join48(agents, "mcp.json")) || await directory2(join48(agents, "workflows")));
|
|
22860
22930
|
const custom = await snapshotConfig(agents);
|
|
22861
22931
|
const args = existing ? ["update", "--yes", "--with-new-skills", "--all"] : ["install"];
|
|
22862
22932
|
let installed;
|
|
@@ -24343,9 +24413,9 @@ var init_ui = __esm(() => {
|
|
|
24343
24413
|
|
|
24344
24414
|
// src/setup/workspace-step.ts
|
|
24345
24415
|
import { statSync as statSync3 } from "node:fs";
|
|
24346
|
-
import { isAbsolute as
|
|
24416
|
+
import { isAbsolute as isAbsolute17 } from "node:path";
|
|
24347
24417
|
async function validateOrderWorkspace(path) {
|
|
24348
|
-
if (!
|
|
24418
|
+
if (!isAbsolute17(path))
|
|
24349
24419
|
return "Set workspace.root in av.yaml to an absolute Git repository path.";
|
|
24350
24420
|
try {
|
|
24351
24421
|
if (!statSync3(path).isDirectory())
|
|
@@ -24372,7 +24442,7 @@ async function stepWorkspace(ctx, step, total) {
|
|
|
24372
24442
|
validate: (v) => {
|
|
24373
24443
|
if (!v?.trim())
|
|
24374
24444
|
return "Required";
|
|
24375
|
-
if (!
|
|
24445
|
+
if (!isAbsolute17(v.trim()))
|
|
24376
24446
|
return "Must be an absolute path";
|
|
24377
24447
|
}
|
|
24378
24448
|
});
|
|
@@ -24399,7 +24469,7 @@ var init_workspace_step = __esm(() => {
|
|
|
24399
24469
|
|
|
24400
24470
|
// src/setup/noninteractive-config.ts
|
|
24401
24471
|
import { lstat as lstat20, realpath as realpath26 } from "node:fs/promises";
|
|
24402
|
-
import { isAbsolute as
|
|
24472
|
+
import { isAbsolute as isAbsolute18, join as join49, parse as parsePath, resolve as resolve30 } from "node:path";
|
|
24403
24473
|
function validateNoninteractiveOptions(options) {
|
|
24404
24474
|
if (!options.yes || options.edit || options.mode !== undefined && options.mode !== "order")
|
|
24405
24475
|
throw new Error("Use av setup --yes only for local order setup; --edit and --mode tracker require interactive setup.");
|
|
@@ -24442,7 +24512,7 @@ function selectChief(options, deps, project, global2) {
|
|
|
24442
24512
|
const globalActor = actor(global2);
|
|
24443
24513
|
const selected = options.actor ?? runtime?.actorType ?? projectActor.type ?? globalActor.type;
|
|
24444
24514
|
if (!selected)
|
|
24445
|
-
throw new Error(`actor.type is missing in ${
|
|
24515
|
+
throw new Error(`actor.type is missing in ${join49(deps.projectRoot, "av.yaml")} and ${deps.globalConfigPath}, and the current agent runtime is unknown. Rerun av setup --yes --actor <current-vendor> --model <current-model-or-empty>.`);
|
|
24446
24516
|
const actorType = selected;
|
|
24447
24517
|
const actorSource = options.actor !== undefined ? "explicit" : runtime ? "runtime" : projectActor.type ? "project" : "global";
|
|
24448
24518
|
const previousType = projectActor.type ?? globalActor.type;
|
|
@@ -24480,14 +24550,14 @@ async function prepareNoninteractiveConfig(options, deps) {
|
|
|
24480
24550
|
validateNoninteractiveOptions(options);
|
|
24481
24551
|
let projectRoot;
|
|
24482
24552
|
try {
|
|
24483
|
-
projectRoot = await realpath26(
|
|
24553
|
+
projectRoot = await realpath26(resolve30(deps.projectRoot));
|
|
24484
24554
|
if (!(await lstat20(projectRoot)).isDirectory())
|
|
24485
24555
|
throw new Error("not a directory");
|
|
24486
24556
|
} catch {
|
|
24487
24557
|
throw new Error(`AV configuration directory ${deps.projectRoot} does not exist. Run av setup from an existing directory.`);
|
|
24488
24558
|
}
|
|
24489
|
-
const globalPath =
|
|
24490
|
-
const projectPath =
|
|
24559
|
+
const globalPath = resolve30(deps.globalConfigPath);
|
|
24560
|
+
const projectPath = join49(projectRoot, "av.yaml");
|
|
24491
24561
|
const project = await configFile(projectPath, projectConfigSchema);
|
|
24492
24562
|
const global2 = await configFile(globalPath, globalConfigSchema);
|
|
24493
24563
|
const chief = selectChief(options, { ...deps, projectRoot, globalConfigPath: globalPath }, project.raw, global2.raw);
|
|
@@ -24504,7 +24574,7 @@ async function prepareNoninteractiveConfig(options, deps) {
|
|
|
24504
24574
|
}
|
|
24505
24575
|
const savedWorkspace = project.raw.workspace?.root;
|
|
24506
24576
|
const selectedWorkspace = options.workspace ?? savedWorkspace ?? projectRoot;
|
|
24507
|
-
const workspacePath =
|
|
24577
|
+
const workspacePath = isAbsolute18(selectedWorkspace) ? selectedWorkspace : resolve30(projectRoot, selectedWorkspace);
|
|
24508
24578
|
const workspaceError = await validateOrderWorkspace(workspacePath);
|
|
24509
24579
|
if (workspaceError)
|
|
24510
24580
|
throw new Error(workspaceError);
|
|
@@ -24539,7 +24609,7 @@ var init_noninteractive_config = __esm(() => {
|
|
|
24539
24609
|
});
|
|
24540
24610
|
|
|
24541
24611
|
// src/setup/noninteractive.ts
|
|
24542
|
-
import { join as
|
|
24612
|
+
import { join as join50, parse as parsePath2, resolve as resolve31 } from "node:path";
|
|
24543
24613
|
function rerunCommand(result, options) {
|
|
24544
24614
|
const quote = (value) => `'${value.replace(/'/g, "'\\''")}'`;
|
|
24545
24615
|
return `cd ${quote(result.projectRoot)} && av setup --yes --actor ${result.chief.actorType} --model ${quote(result.chief.model ?? "")} --workspace ${quote(result.workspace ?? result.projectRoot)} --oma ${options.oma ?? "prepare"} --json`;
|
|
@@ -24550,11 +24620,11 @@ async function setupNoninteractive(options, overrides = {}) {
|
|
|
24550
24620
|
version: 1,
|
|
24551
24621
|
status: "failed",
|
|
24552
24622
|
exitCode: 1,
|
|
24553
|
-
projectRoot:
|
|
24623
|
+
projectRoot: resolve31(deps.projectRoot),
|
|
24554
24624
|
workspace: null,
|
|
24555
24625
|
config: {
|
|
24556
|
-
project:
|
|
24557
|
-
global:
|
|
24626
|
+
project: join50(resolve31(deps.projectRoot), "av.yaml"),
|
|
24627
|
+
global: resolve31(deps.globalConfigPath),
|
|
24558
24628
|
saved: false
|
|
24559
24629
|
},
|
|
24560
24630
|
chief: {
|
|
@@ -25035,7 +25105,7 @@ var init_container_step = __esm(() => {
|
|
|
25035
25105
|
});
|
|
25036
25106
|
|
|
25037
25107
|
// src/setup/metric-step.ts
|
|
25038
|
-
import { isAbsolute as
|
|
25108
|
+
import { isAbsolute as isAbsolute19 } from "node:path";
|
|
25039
25109
|
async function text12(message, initialValue, validate) {
|
|
25040
25110
|
const value = await text10({
|
|
25041
25111
|
message: `${message} (:back goes back)`,
|
|
@@ -25119,7 +25189,7 @@ async function stepMetrics(ctx) {
|
|
|
25119
25189
|
draft.token_env = token;
|
|
25120
25190
|
} else {
|
|
25121
25191
|
const file = await text12("Repository-relative JSON file", old?.file ?? "metrics/revenue.json", (value) => {
|
|
25122
|
-
if (!value || value.length > 2000 ||
|
|
25192
|
+
if (!value || value.length > 2000 || isAbsolute19(value) || /^[A-Za-z]:/.test(value) || value.startsWith("\\") || value.split(/[\\/]/).includes(".."))
|
|
25123
25193
|
return "Use a relative file inside the repository, without ..";
|
|
25124
25194
|
});
|
|
25125
25195
|
if (navigated2(file))
|
|
@@ -25127,18 +25197,18 @@ async function stepMetrics(ctx) {
|
|
|
25127
25197
|
draft.file = file;
|
|
25128
25198
|
}
|
|
25129
25199
|
for (const field of ["value_path", "timestamp_path", "unit_path"]) {
|
|
25130
|
-
const value = await text12(`JSON ${field}`, old?.[field] ?? field.replace("_path", ""),
|
|
25200
|
+
const value = await text12(`JSON ${field}`, old?.[field] ?? field.replace("_path", ""), path4);
|
|
25131
25201
|
if (navigated2(value))
|
|
25132
25202
|
return value;
|
|
25133
25203
|
draft[field] = value;
|
|
25134
25204
|
}
|
|
25135
|
-
const start = await text12("JSON measurement window start path (optional; blank omits window)", old?.window_start_path ?? "", (value) => value ?
|
|
25205
|
+
const start = await text12("JSON measurement window start path (optional; blank omits window)", old?.window_start_path ?? "", (value) => value ? path4(value) : undefined);
|
|
25136
25206
|
if (navigated2(start))
|
|
25137
25207
|
return start;
|
|
25138
25208
|
delete draft.window_start_path;
|
|
25139
25209
|
delete draft.window_end_path;
|
|
25140
25210
|
if (start) {
|
|
25141
|
-
const end = await text12("JSON measurement window end path", old?.window_end_path ?? "window.end",
|
|
25211
|
+
const end = await text12("JSON measurement window end path", old?.window_end_path ?? "window.end", path4);
|
|
25142
25212
|
if (navigated2(end))
|
|
25143
25213
|
return end;
|
|
25144
25214
|
draft.window_start_path = start;
|
|
@@ -25184,7 +25254,7 @@ async function stepMetrics(ctx) {
|
|
|
25184
25254
|
ctx.chiefChanged = true;
|
|
25185
25255
|
log2.info("Metric settings are saved after confirmation. Measurements are collected at mission runtime; setup does not contact the source. Set --duration or chief.execution.max_duration_sec long enough for work and the full measurement/observation windows. The default mission limit is 86400 seconds including waits; Stripe's default measurement window is also 86400 seconds.");
|
|
25186
25256
|
}
|
|
25187
|
-
var envName3 = (value) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(value), navigated2 = (value) => typeof value !== "string", required2 = (limit) => (value) => value && value.length <= limit ? undefined : `Enter 1 to ${limit} characters.`, environment = (optional = false) => (value) => optional && !value || envName3(value) ? undefined : "Enter an environment variable name, never a token or URL.", number4 = (minimum, maximum) => (value) => value && Number.isInteger(Number(value)) && Number(value) >= minimum && Number(value) <= maximum ? undefined : `Enter a whole number from ${minimum} to ${maximum}.`,
|
|
25257
|
+
var envName3 = (value) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(value), navigated2 = (value) => typeof value !== "string", required2 = (limit) => (value) => value && value.length <= limit ? undefined : `Enter 1 to ${limit} characters.`, environment = (optional = false) => (value) => optional && !value || envName3(value) ? undefined : "Enter an environment variable name, never a token or URL.", number4 = (minimum, maximum) => (value) => value && Number.isInteger(Number(value)) && Number(value) >= minimum && Number(value) <= maximum ? undefined : `Enter a whole number from ${minimum} to ${maximum}.`, path4 = (value) => {
|
|
25188
25258
|
const result = metricSourceSchema.shape.value_path.safeParse(value);
|
|
25189
25259
|
return result.success ? undefined : "Use dot-separated JSON keys or array indexes, without prototype keys.";
|
|
25190
25260
|
};
|
|
@@ -27577,8 +27647,8 @@ var init_issue = __esm(() => {
|
|
|
27577
27647
|
|
|
27578
27648
|
// src/login.ts
|
|
27579
27649
|
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "node:fs";
|
|
27580
|
-
import { homedir as
|
|
27581
|
-
import { join as
|
|
27650
|
+
import { homedir as homedir10 } from "node:os";
|
|
27651
|
+
import { join as join51 } from "node:path";
|
|
27582
27652
|
function ensureConfigDir() {
|
|
27583
27653
|
if (!existsSync9(CONFIG_DIR)) {
|
|
27584
27654
|
mkdirSync4(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
@@ -27753,8 +27823,8 @@ var import_picocolors14, CONFIG_DIR, CREDENTIALS_FILE;
|
|
|
27753
27823
|
var init_login = __esm(() => {
|
|
27754
27824
|
init_dist6();
|
|
27755
27825
|
import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
27756
|
-
CONFIG_DIR =
|
|
27757
|
-
CREDENTIALS_FILE =
|
|
27826
|
+
CONFIG_DIR = join51(homedir10(), ".agent-valley");
|
|
27827
|
+
CREDENTIALS_FILE = join51(CONFIG_DIR, "credentials.json");
|
|
27758
27828
|
});
|
|
27759
27829
|
|
|
27760
27830
|
// src/index.ts
|
|
@@ -27762,7 +27832,7 @@ init_project_config_path();
|
|
|
27762
27832
|
init_yaml_loader();
|
|
27763
27833
|
import { spawn as spawn24, spawnSync as spawnSync5 } from "node:child_process";
|
|
27764
27834
|
import { existsSync as existsSync10, unlinkSync as unlinkSync2 } from "node:fs";
|
|
27765
|
-
import { resolve as
|
|
27835
|
+
import { resolve as resolve32 } from "node:path";
|
|
27766
27836
|
|
|
27767
27837
|
// ../../packages/core/src/version.ts
|
|
27768
27838
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
@@ -27872,7 +27942,7 @@ function humanReadableArgName(arg) {
|
|
|
27872
27942
|
// ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/command.js
|
|
27873
27943
|
import { EventEmitter } from "node:events";
|
|
27874
27944
|
import childProcess from "node:child_process";
|
|
27875
|
-
import
|
|
27945
|
+
import path2 from "node:path";
|
|
27876
27946
|
import fs from "node:fs";
|
|
27877
27947
|
import process2 from "node:process";
|
|
27878
27948
|
import { stripVTControlCharacters as stripVTControlCharacters2 } from "node:util";
|
|
@@ -29016,10 +29086,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
29016
29086
|
args = args.slice();
|
|
29017
29087
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
29018
29088
|
function findFile(baseDir, baseName) {
|
|
29019
|
-
const localBin =
|
|
29089
|
+
const localBin = path2.resolve(baseDir, baseName);
|
|
29020
29090
|
if (fs.existsSync(localBin))
|
|
29021
29091
|
return localBin;
|
|
29022
|
-
if (sourceExt.includes(
|
|
29092
|
+
if (sourceExt.includes(path2.extname(baseName)))
|
|
29023
29093
|
return;
|
|
29024
29094
|
const foundExt = sourceExt.find((ext) => fs.existsSync(`${localBin}${ext}`));
|
|
29025
29095
|
if (foundExt)
|
|
@@ -29037,19 +29107,19 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
29037
29107
|
} catch {
|
|
29038
29108
|
resolvedScriptPath = this._scriptPath;
|
|
29039
29109
|
}
|
|
29040
|
-
executableDir =
|
|
29110
|
+
executableDir = path2.resolve(path2.dirname(resolvedScriptPath), executableDir);
|
|
29041
29111
|
}
|
|
29042
29112
|
if (executableDir) {
|
|
29043
29113
|
let localFile = findFile(executableDir, executableFile);
|
|
29044
29114
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
29045
|
-
const legacyName =
|
|
29115
|
+
const legacyName = path2.basename(this._scriptPath, path2.extname(this._scriptPath));
|
|
29046
29116
|
if (legacyName !== this._name) {
|
|
29047
29117
|
localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`);
|
|
29048
29118
|
}
|
|
29049
29119
|
}
|
|
29050
29120
|
executableFile = localFile || executableFile;
|
|
29051
29121
|
}
|
|
29052
|
-
const launchWithNode = sourceExt.includes(
|
|
29122
|
+
const launchWithNode = sourceExt.includes(path2.extname(executableFile));
|
|
29053
29123
|
let proc;
|
|
29054
29124
|
if (process2.platform !== "win32") {
|
|
29055
29125
|
if (launchWithNode) {
|
|
@@ -29640,13 +29710,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
29640
29710
|
cmd.helpGroup(this._defaultCommandGroup);
|
|
29641
29711
|
}
|
|
29642
29712
|
nameFromFilename(filename) {
|
|
29643
|
-
this._name =
|
|
29713
|
+
this._name = path2.basename(filename, path2.extname(filename));
|
|
29644
29714
|
return this;
|
|
29645
29715
|
}
|
|
29646
|
-
executableDir(
|
|
29647
|
-
if (
|
|
29716
|
+
executableDir(path) {
|
|
29717
|
+
if (path === undefined)
|
|
29648
29718
|
return this._executableDir;
|
|
29649
|
-
this._executableDir =
|
|
29719
|
+
this._executableDir = path;
|
|
29650
29720
|
return this;
|
|
29651
29721
|
}
|
|
29652
29722
|
helpInformation(contextOptions) {
|
|
@@ -29824,7 +29894,7 @@ var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
|
29824
29894
|
|
|
29825
29895
|
// src/agent-client-commands.ts
|
|
29826
29896
|
init_client_integrations();
|
|
29827
|
-
import { resolve as
|
|
29897
|
+
import { resolve as resolve22 } from "node:path";
|
|
29828
29898
|
|
|
29829
29899
|
// src/mcp-oauth.ts
|
|
29830
29900
|
init_webapi();
|
|
@@ -48175,7 +48245,7 @@ async function startAvMcpHttp(api, options) {
|
|
|
48175
48245
|
// src/mission-api.ts
|
|
48176
48246
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
48177
48247
|
import { lstat as lstat15, readdir as readdir8, realpath as realpath21 } from "node:fs/promises";
|
|
48178
|
-
import { isAbsolute as
|
|
48248
|
+
import { isAbsolute as isAbsolute13, join as join38 } from "node:path";
|
|
48179
48249
|
|
|
48180
48250
|
// ../../packages/core/src/chief/reports.ts
|
|
48181
48251
|
init_zod();
|
|
@@ -48938,7 +49008,7 @@ var sha256 = string2().regex(/^[a-f0-9]{64}$/);
|
|
|
48938
49008
|
function safeVerificationPath(path) {
|
|
48939
49009
|
return path.length > 0 && path.length <= 1024 && !isAbsolute2(path) && !/^[a-z]:/i.test(path) && !/[\\\0\r\n]/.test(path) && path.split("/").every((part) => part !== "" && part !== "." && part !== "..") && !/^(?:\.git(?:\/|$)|\.agent-valley(?:\/|$)|\.agents\/(?:state|results)(?:\/|$))/.test(path);
|
|
48940
49010
|
}
|
|
48941
|
-
var
|
|
49011
|
+
var path3 = string2().refine(safeVerificationPath, "Use a literal relative product path inside the worktree.");
|
|
48942
49012
|
var testPath = (name, nodeOnly = false) => safeVerificationPath(name) && !name.startsWith("-") && !/[*?{}]/.test(name) && !name.startsWith("node_modules/") && (nodeOnly ? /(?:\.test|\.spec)\.(?:js|mjs|cjs)$/ : /(?:\.test|\.spec)\.(?:[cm]?[jt]sx?)$/).test(name);
|
|
48943
49013
|
function verificationCommandTestPaths(program, args) {
|
|
48944
49014
|
if (program === "bun" && args[0] === "test")
|
|
@@ -48975,14 +49045,14 @@ function safeVerificationCommand(program, args) {
|
|
|
48975
49045
|
var goalVerificationCheckSchema = discriminatedUnion("kind", [
|
|
48976
49046
|
strictObject({
|
|
48977
49047
|
kind: literal("file"),
|
|
48978
|
-
path:
|
|
49048
|
+
path: path3,
|
|
48979
49049
|
minBytes: number2().int().min(1).max(4194304).default(1),
|
|
48980
49050
|
contains: array(text4).min(1).max(10).optional(),
|
|
48981
49051
|
sha256: sha256.optional()
|
|
48982
49052
|
}),
|
|
48983
49053
|
strictObject({
|
|
48984
49054
|
kind: literal("json"),
|
|
48985
|
-
path:
|
|
49055
|
+
path: path3,
|
|
48986
49056
|
pointer: string2().max(1024).refine((value) => value === "" || /^(?:\/(?:[^~]|~[01])*)+$/.test(value), {
|
|
48987
49057
|
message: "Use an RFC 6901 JSON pointer such as /engines/node."
|
|
48988
49058
|
}),
|
|
@@ -49444,16 +49514,29 @@ function routeEvidence(mission) {
|
|
|
49444
49514
|
function price2(candidate) {
|
|
49445
49515
|
return candidate.inputPerMillionUsd !== undefined && candidate.outputPerMillionUsd !== undefined ? candidate.inputPerMillionUsd + candidate.outputPerMillionUsd : Number.POSITIVE_INFINITY;
|
|
49446
49516
|
}
|
|
49447
|
-
function
|
|
49517
|
+
function workActorCandidates(mission, actor, preserveExplicit = false) {
|
|
49448
49518
|
const routing = mission.operatingPolicy?.routing;
|
|
49449
|
-
if (!routing || actor.id === mission.chiefId || !mission.availableAgents && actor.model)
|
|
49519
|
+
if (!routing || actor.id === mission.chiefId || !mission.availableAgents && (actor.model || preserveExplicit))
|
|
49520
|
+
return [{ actorType: actor.agentType, model: actor.model }];
|
|
49521
|
+
const ready = mission.operatingPolicy?.readyActors ?? mission.availableAgents ?? [];
|
|
49522
|
+
return routing.candidates.filter((candidate) => ready.includes(candidate.actorType));
|
|
49523
|
+
}
|
|
49524
|
+
function selectWorkActor(mission, actor, taskId, compatibleRoutes) {
|
|
49525
|
+
const routing = mission.operatingPolicy?.routing;
|
|
49526
|
+
if (!routing || actor.id === mission.chiefId || !mission.availableAgents && (actor.model || compatibleRoutes)) {
|
|
49527
|
+
if (compatibleRoutes && !compatibleRoutes.has(routeKey({ actorType: actor.agentType, model: actor.model })))
|
|
49528
|
+
throw new Error("Skill compatibility required: the configured Actor/model has no current passing evidence. Refresh oma.skill_compatibility.report_path in av.yaml; explicit Actors are not rerouted.");
|
|
49450
49529
|
return { actor, reason: "Preserved the configured Actor and explicit model." };
|
|
49530
|
+
}
|
|
49451
49531
|
const ready = mission.operatingPolicy?.readyActors ?? mission.availableAgents ?? [];
|
|
49452
49532
|
const candidates = routing.candidates.filter((candidate) => ready.includes(candidate.actorType));
|
|
49453
49533
|
if (!candidates.length)
|
|
49454
49534
|
throw new Error("No configured work routing candidate is ready. Install/login a candidate CLI or update chief.routing.candidates in av.yaml.");
|
|
49535
|
+
const compatible = compatibleRoutes ? candidates.filter((candidate) => compatibleRoutes.has(routeKey(candidate))) : candidates;
|
|
49536
|
+
if (!compatible.length)
|
|
49537
|
+
throw new Error("Skill compatibility required: no ready work candidate has current passing installed evidence. Refresh oma.skill_compatibility.report_path in av.yaml with explicit models before retrying.");
|
|
49455
49538
|
const evidence = routeEvidence(mission);
|
|
49456
|
-
const eligible =
|
|
49539
|
+
const eligible = compatible.filter((candidate) => {
|
|
49457
49540
|
const observed = evidence.find((item) => routeKey(item) === routeKey(candidate));
|
|
49458
49541
|
return !observed || observed.samples < routing.minSamples || observed.successes / observed.samples >= routing.minSuccessRate;
|
|
49459
49542
|
});
|
|
@@ -49515,6 +49598,10 @@ function operationsEvidence(mission) {
|
|
|
49515
49598
|
pricingBasis: "Estimates from configured input/output prices and actual adapter-reported tokens; excludes unreported cache/reasoning/subagent usage and subscription billing.",
|
|
49516
49599
|
routeQuality: routeEvidence(mission).slice(0, 20),
|
|
49517
49600
|
reviewPolicy: mission.operatingPolicy?.reviewVendor ?? "legacy independent Actor",
|
|
49601
|
+
skillCompatibility: mission.operatingPolicy?.skillCompatibility ? {
|
|
49602
|
+
mode: mission.operatingPolicy.skillCompatibility.mode,
|
|
49603
|
+
recentChecks: mission.history.filter((entry) => entry.stage === "skill-compatibility").slice(-10)
|
|
49604
|
+
} : undefined,
|
|
49518
49605
|
recentRuns: runs.slice(-20),
|
|
49519
49606
|
crossVendorReviews: mission.operations?.reviewDecisions.slice(-20) ?? [],
|
|
49520
49607
|
organizationContext: mission.organizationContext,
|
|
@@ -49530,6 +49617,10 @@ function operationsReportLines(mission) {
|
|
|
49530
49617
|
`기록된 token·설정 단가 기반 부분 비용 추정 USD ${evidence.knownEstimatedCostUsd.toFixed(6)} / 비용 미확인 ${evidence.unknownCostRuns}회 / 전체 추정 ${evidence.totalEstimatedCostUsd === null ? "미확인" : `USD ${evidence.totalEstimatedCostUsd.toFixed(6)}`}`,
|
|
49531
49618
|
`최근 독립 리뷰 배정: 다른 vendor ${evidence.crossVendorReviews.filter((review) => review.crossVendor).length}회 / 동일 vendor fallback ${evidence.crossVendorReviews.filter((review) => !review.crossVendor).length}회 / 실제 리뷰 통과 ${evidence.crossVendorReviews.filter((review) => review.outcome === "passed").length}회`,
|
|
49532
49619
|
`vendor 리뷰 정책: ${evidence.reviewPolicy}`,
|
|
49620
|
+
...evidence.skillCompatibility ? [
|
|
49621
|
+
`OMA 스킬 읽기·참조 정책: ${evidence.skillCompatibility.mode}; AV 실행 환경 또는 작업 품질 인증이 아닙니다.`,
|
|
49622
|
+
...evidence.skillCompatibility.recentChecks.map((entry) => `${entry.at}: ${entry.message}`)
|
|
49623
|
+
] : [],
|
|
49533
49624
|
...mission.organizationContext ? [
|
|
49534
49625
|
`계획·리뷰에 제공한 조직 근거: 승인 memory ${mission.organizationContext.memories.length}개 / 과거 outcome ${mission.organizationContext.outcomes.length}개 / 기록된 metric sample ${mission.organizationContext.metrics.length}개`
|
|
49535
49626
|
] : [],
|
|
@@ -49557,15 +49648,15 @@ var chiefReportSchema = strictObject({
|
|
|
49557
49648
|
checks: entries,
|
|
49558
49649
|
remaining: entries
|
|
49559
49650
|
});
|
|
49560
|
-
function
|
|
49651
|
+
function bounded2(value, limit = 500) {
|
|
49561
49652
|
const content = value.trim();
|
|
49562
49653
|
return content.length <= limit ? content : `${content.slice(0, limit - 8)}… [생략]`;
|
|
49563
49654
|
}
|
|
49564
49655
|
function compact(values, limit = 20) {
|
|
49565
49656
|
if (values.length <= limit)
|
|
49566
|
-
return values.map((value) =>
|
|
49657
|
+
return values.map((value) => bounded2(value)).filter(Boolean);
|
|
49567
49658
|
return [
|
|
49568
|
-
...values.slice(0, limit - 1).map((value) =>
|
|
49659
|
+
...values.slice(0, limit - 1).map((value) => bounded2(value)).filter(Boolean),
|
|
49569
49660
|
`${values.length - limit + 1}개 항목 생략`
|
|
49570
49661
|
];
|
|
49571
49662
|
}
|
|
@@ -49580,7 +49671,7 @@ function criteria(mission) {
|
|
|
49580
49671
|
function incompleteReasons(mission) {
|
|
49581
49672
|
const reasons = [];
|
|
49582
49673
|
if (mission.error)
|
|
49583
|
-
reasons.push(`${["waiting", "paused"].includes(mission.status) ? "대기·중단 이유" : "실패 원인"}: ${
|
|
49674
|
+
reasons.push(`${["waiting", "paused"].includes(mission.status) ? "대기·중단 이유" : "실패 원인"}: ${bounded2(mission.error, 450)}`);
|
|
49584
49675
|
if (mission.status !== "completed")
|
|
49585
49676
|
reasons.push(`미션 상태: ${mission.status}. 완료 판정이 없습니다.`);
|
|
49586
49677
|
if (!mission.verification)
|
|
@@ -49633,33 +49724,33 @@ function incompleteReasons(mission) {
|
|
|
49633
49724
|
}
|
|
49634
49725
|
function decisionEvidence(mission) {
|
|
49635
49726
|
const actions = { repair: "수정", reassign: "담당 교체", replan: "재계획", wait: "대기", stop: "중단" };
|
|
49636
|
-
return (mission.supervision?.decisions ?? []).slice(-20).map((decision) =>
|
|
49727
|
+
return (mission.supervision?.decisions ?? []).slice(-20).map((decision) => bounded2(`${decision.round}차 ${actions[decision.action]}${decision.taskId ? ` / 작업 ${decision.taskId}` : ""}${decision.personaId ? ` / 담당 ${decision.personaId}` : ""}: ${decision.reason}`));
|
|
49637
49728
|
}
|
|
49638
49729
|
function reviewEvidence(review) {
|
|
49639
49730
|
return review ? {
|
|
49640
49731
|
passed: review.passed,
|
|
49641
|
-
summary:
|
|
49732
|
+
summary: bounded2(review.summary),
|
|
49642
49733
|
findings: compact(review.findings),
|
|
49643
49734
|
criteria: review.criteria?.slice(0, 20).map((item) => ({
|
|
49644
|
-
criterion:
|
|
49735
|
+
criterion: bounded2(item.criterion),
|
|
49645
49736
|
passed: item.passed,
|
|
49646
|
-
evidence:
|
|
49737
|
+
evidence: bounded2(item.evidence)
|
|
49647
49738
|
}))
|
|
49648
49739
|
} : undefined;
|
|
49649
49740
|
}
|
|
49650
49741
|
function verificationEvidence(verification) {
|
|
49651
49742
|
return verification ? {
|
|
49652
49743
|
ok: verification.ok,
|
|
49653
|
-
output: verification.output ?
|
|
49654
|
-
fingerprint:
|
|
49744
|
+
output: verification.output ? bounded2(verification.output, 3000) : undefined,
|
|
49745
|
+
fingerprint: bounded2(verification.fingerprint, 128)
|
|
49655
49746
|
} : undefined;
|
|
49656
49747
|
}
|
|
49657
49748
|
function advisoryEvidence(kind, advisory) {
|
|
49658
49749
|
return advisory ? {
|
|
49659
49750
|
kind: `upfront ${kind} advice; historical snapshot; not current approval`,
|
|
49660
|
-
planKey:
|
|
49751
|
+
planKey: bounded2(advisory.planKey, 128),
|
|
49661
49752
|
reviewerId: advisory.reviewerId,
|
|
49662
|
-
fingerprint:
|
|
49753
|
+
fingerprint: bounded2(advisory.fingerprint, 128),
|
|
49663
49754
|
review: reviewEvidence(advisory.review)
|
|
49664
49755
|
} : undefined;
|
|
49665
49756
|
}
|
|
@@ -49669,24 +49760,24 @@ function historicalEvidence(mission) {
|
|
|
49669
49760
|
const verification = decision.evidence?.verification;
|
|
49670
49761
|
const review = decision.evidence?.finalReview;
|
|
49671
49762
|
if (verification)
|
|
49672
|
-
lines.push(
|
|
49763
|
+
lines.push(bounded2(`${decision.round}차 판단 당시 검증: ${verification.ok ? "통과" : "실패"} / 파일 상태 ${bounded2(verification.fingerprint, 128)}${verification.output ? ` / ${bounded2(verification.output, 250)}` : ""}`));
|
|
49673
49764
|
if (review) {
|
|
49674
|
-
lines.push(
|
|
49675
|
-
lines.push(...compact(review.findings, 3).map((finding) =>
|
|
49765
|
+
lines.push(bounded2(`${decision.round}차 판단 당시 최종 리뷰: ${review.passed ? "통과" : "실패"} / ${bounded2(review.summary, 350)}`));
|
|
49766
|
+
lines.push(...compact(review.findings, 3).map((finding) => bounded2(`${decision.round}차 판단 당시 지적: ${finding}`)));
|
|
49676
49767
|
}
|
|
49677
49768
|
return lines;
|
|
49678
49769
|
});
|
|
49679
49770
|
}
|
|
49680
49771
|
function checkEvidence(mission) {
|
|
49681
49772
|
return compact([
|
|
49682
|
-
`운영자 검증: ${mission.verification ? mission.verification.ok ? "통과" : "실패" : "미실행"} / 명령: ${
|
|
49773
|
+
`운영자 검증: ${mission.verification ? mission.verification.ok ? "통과" : "실패" : "미실행"} / 명령: ${bounded2(mission.supervision?.operatorVerifyCommand ?? mission.verifyCommand, 350)}`,
|
|
49683
49774
|
...mission.verification?.output ? [`검증 출력: ${mission.verification.output}`] : [],
|
|
49684
49775
|
`Chief Director 최종 리뷰: ${mission.finalReview ? mission.finalReview.passed && mission.finalReview.findings.length === 0 ? "통과" : "실패" : "미실행"}${mission.finalReview ? ` / ${mission.finalReview.summary}` : ""}`,
|
|
49685
49776
|
...mission.tasks.map((task) => `${task.id}: 상태 ${task.status}, 시도 ${task.attempts}회, 독립 리뷰 ${task.review ? task.review.passed && task.review.findings.length === 0 ? "통과" : "실패" : "미실행"} / 리뷰어 ${task.reviewerId}`)
|
|
49686
49777
|
]);
|
|
49687
49778
|
}
|
|
49688
49779
|
function criterionEvidence(mission) {
|
|
49689
|
-
return (mission.finalReview?.criteria ?? []).map((item) =>
|
|
49780
|
+
return (mission.finalReview?.criteria ?? []).map((item) => bounded2(`${bounded2(item.criterion, 200)}: ${item.passed ? "통과" : "실패"} / 근거: ${bounded2(item.evidence, 250)}`));
|
|
49690
49781
|
}
|
|
49691
49782
|
function reportPrompt(mission) {
|
|
49692
49783
|
const goal = mission.supervision?.operatorGoal ?? mission.goal;
|
|
@@ -49714,8 +49805,8 @@ function reportPrompt(mission) {
|
|
|
49714
49805
|
'{"summary":"result","eli5":"plain-language result and user impact","goalAssessment":"criteria and actual verdict","assumptions":[],"decisions":[],"deliverables":[],"checks":[],"remaining":[]}',
|
|
49715
49806
|
`Report evidence (JSON data):
|
|
49716
49807
|
${JSON.stringify({
|
|
49717
|
-
operatorGoal:
|
|
49718
|
-
interpretation: mission.goalBrief ?
|
|
49808
|
+
operatorGoal: bounded2(goal, 4000),
|
|
49809
|
+
interpretation: mission.goalBrief ? bounded2(mission.goalBrief.interpretation, 2000) : undefined,
|
|
49719
49810
|
assumptions: compact(mission.goalBrief?.assumptions ?? []),
|
|
49720
49811
|
successCriteria: compact(criteria(mission)),
|
|
49721
49812
|
status: mission.status,
|
|
@@ -49724,9 +49815,9 @@ ${JSON.stringify({
|
|
|
49724
49815
|
containerObservation: mission.containerObservation,
|
|
49725
49816
|
verdict: incompleteReasons(mission).length === 0 ? "completed" : "incomplete",
|
|
49726
49817
|
incompleteReasons: incompleteReasons(mission),
|
|
49727
|
-
error: mission.error ?
|
|
49728
|
-
workspace:
|
|
49729
|
-
branch:
|
|
49818
|
+
error: mission.error ? bounded2(mission.error, 2000) : undefined,
|
|
49819
|
+
workspace: bounded2(mission.workspace.path, 2000),
|
|
49820
|
+
branch: bounded2(mission.workspace.branch),
|
|
49730
49821
|
chiefId: mission.chiefId,
|
|
49731
49822
|
technicalLeadId: mission.technicalLeadId,
|
|
49732
49823
|
technicalAdvice: advisoryEvidence("technical", mission.technicalReview),
|
|
@@ -49736,10 +49827,10 @@ ${JSON.stringify({
|
|
|
49736
49827
|
marketingAdvice: advisoryEvidence("marketing", mission.marketingReview),
|
|
49737
49828
|
actors: mission.personas.slice(0, 20).map((persona) => ({
|
|
49738
49829
|
id: persona.id,
|
|
49739
|
-
name:
|
|
49740
|
-
role:
|
|
49741
|
-
cli:
|
|
49742
|
-
model: persona.model ?
|
|
49830
|
+
name: bounded2(persona.name),
|
|
49831
|
+
role: bounded2(persona.role),
|
|
49832
|
+
cli: bounded2(persona.agentType),
|
|
49833
|
+
model: persona.model ? bounded2(persona.model) : "native default (actual model not recorded)",
|
|
49743
49834
|
selectedSkills: persona.skills.slice(0, 30)
|
|
49744
49835
|
})),
|
|
49745
49836
|
decisions: decisions.map((decision) => ({
|
|
@@ -49747,8 +49838,8 @@ ${JSON.stringify({
|
|
|
49747
49838
|
action: decision.action,
|
|
49748
49839
|
taskId: decision.taskId,
|
|
49749
49840
|
actorId: decision.personaId,
|
|
49750
|
-
reason:
|
|
49751
|
-
instructions: decision.instructions ?
|
|
49841
|
+
reason: bounded2(decision.reason),
|
|
49842
|
+
instructions: decision.instructions ? bounded2(decision.instructions) : undefined,
|
|
49752
49843
|
historicalEvidence: decision.evidence && snapshotDecisions.has(decision) ? {
|
|
49753
49844
|
kind: "evidence at the recovery decision; not current approval",
|
|
49754
49845
|
finalReview: reviewEvidence(decision.evidence.finalReview),
|
|
@@ -49757,25 +49848,25 @@ ${JSON.stringify({
|
|
|
49757
49848
|
})),
|
|
49758
49849
|
tasks: mission.tasks.slice(0, 12).map((state) => ({
|
|
49759
49850
|
id: state.id,
|
|
49760
|
-
title:
|
|
49851
|
+
title: bounded2(mission.plan?.tasks.find((task) => task.id === state.id)?.title ?? state.id),
|
|
49761
49852
|
actorId: mission.plan?.tasks.find((task) => task.id === state.id)?.personaId,
|
|
49762
49853
|
reviewerId: state.reviewerId,
|
|
49763
49854
|
status: state.status,
|
|
49764
49855
|
attempts: state.attempts,
|
|
49765
|
-
actorClaim: state.output ?
|
|
49856
|
+
actorClaim: state.output ? bounded2(state.output, 3000) : undefined,
|
|
49766
49857
|
review: reviewEvidence(state.review)
|
|
49767
49858
|
})),
|
|
49768
|
-
verifyCommand:
|
|
49859
|
+
verifyCommand: bounded2(mission.supervision?.operatorVerifyCommand ?? mission.verifyCommand, 1200),
|
|
49769
49860
|
verification: verificationEvidence(mission.verification),
|
|
49770
49861
|
goalVerification: mission.goalVerification,
|
|
49771
49862
|
execution: mission.execution,
|
|
49772
49863
|
executionPolicy: mission.executionPolicy,
|
|
49773
49864
|
finalReview: reviewEvidence(mission.finalReview),
|
|
49774
49865
|
history: mission.history.slice(-30).map((event) => ({
|
|
49775
|
-
at:
|
|
49776
|
-
stage:
|
|
49866
|
+
at: bounded2(event.at),
|
|
49867
|
+
stage: bounded2(event.stage),
|
|
49777
49868
|
taskId: event.taskId,
|
|
49778
|
-
message:
|
|
49869
|
+
message: bounded2(event.message)
|
|
49779
49870
|
}))
|
|
49780
49871
|
})}`
|
|
49781
49872
|
].join(`
|
|
@@ -49797,10 +49888,10 @@ function parseReport(source) {
|
|
|
49797
49888
|
function fallbackReport(mission) {
|
|
49798
49889
|
const reasons = incompleteReasons(mission);
|
|
49799
49890
|
const complete = reasons.length === 0;
|
|
49800
|
-
const goal =
|
|
49891
|
+
const goal = bounded2(mission.supervision?.operatorGoal ?? mission.goal, 350);
|
|
49801
49892
|
return {
|
|
49802
49893
|
summary: complete ? "작업, 독립 리뷰, 운영자 검증과 Chief Director 최종 리뷰를 통과했습니다." : "목표는 미완료입니다. 확인된 미해결 조건과 보관된 실행 기록을 보고합니다.",
|
|
49803
|
-
eli5: complete ? `“${goal}”을 위한 결과물을 만들고, 다른 담당자의 점검과 지정한 확인 절차를 마쳤습니다. 결과물은 아래 작업 경로에 보관되어 있어 직접 확인할 수 있습니다.` : `“${goal}”을 위해 작업했지만, 아직 모든 확인 절차를 통과한 결과는 아닙니다. ${
|
|
49894
|
+
eli5: complete ? `“${goal}”을 위한 결과물을 만들고, 다른 담당자의 점검과 지정한 확인 절차를 마쳤습니다. 결과물은 아래 작업 경로에 보관되어 있어 직접 확인할 수 있습니다.` : `“${goal}”을 위해 작업했지만, 아직 모든 확인 절차를 통과한 결과는 아닙니다. ${bounded2(reasons[0] ?? "완료 증거가 없습니다.", 350)} 이미 만든 작업은 보관되어 있습니다. Chief Director가 기록한 판단과 다음 관측·재개 시각, 아직 충족되지 않은 조건을 아래에서 보고합니다.`,
|
|
49804
49895
|
goalAssessment: complete ? "기록된 성공 기준에 대해 작업별 독립 리뷰와 운영자 검증이 통과했고, Chief Director가 최종 승인했습니다." : "성공 기준 전체의 충족을 확인하지 못했습니다. 일부 작업이나 검증이 통과했더라도 목표 달성으로 표시하지 않습니다.",
|
|
49805
49896
|
assumptions: compact(mission.goalBrief?.assumptions ?? []),
|
|
49806
49897
|
decisions: decisionEvidence(mission),
|
|
@@ -49818,7 +49909,7 @@ function fallbackReport(mission) {
|
|
|
49818
49909
|
};
|
|
49819
49910
|
}
|
|
49820
49911
|
function markdown(value, limit = 1200) {
|
|
49821
|
-
return
|
|
49912
|
+
return bounded2(value, limit).replace(/[\p{Cc}\p{Cf}]/gu, " ").replace(/\s+/g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/[\\`*_{}[\]()#+.!|~-]/g, "\\$&");
|
|
49822
49913
|
}
|
|
49823
49914
|
function list(values) {
|
|
49824
49915
|
return values.length ? compact(values).map((value) => `- ${markdown(value)}`).join(`
|
|
@@ -50333,12 +50424,12 @@ async function assertMissionWorkspace(mission) {
|
|
|
50333
50424
|
}
|
|
50334
50425
|
|
|
50335
50426
|
// ../../packages/core/src/chief/parallel-workspace.ts
|
|
50336
|
-
var
|
|
50427
|
+
var hash2 = (value) => createHash10("sha256").update(value).digest("hex");
|
|
50337
50428
|
var same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
50338
50429
|
function identity3(missionId, taskId, attempt) {
|
|
50339
50430
|
if (!taskId || taskId.length > 200 || !Number.isSafeInteger(attempt) || attempt < 1)
|
|
50340
50431
|
throw new Error("Use a valid task ID and positive attempt number for each parallel Actor.");
|
|
50341
|
-
return `${
|
|
50432
|
+
return `${hash2(missionId).slice(0, 16)}-${hash2(taskId).slice(0, 16)}-${attempt}`;
|
|
50342
50433
|
}
|
|
50343
50434
|
async function paths(source, missionId, taskId, attempt) {
|
|
50344
50435
|
const root = await parallelRoot(source);
|
|
@@ -50482,7 +50573,7 @@ async function collectTaskDelivery(mission, workspace) {
|
|
|
50482
50573
|
version: 1,
|
|
50483
50574
|
workspace,
|
|
50484
50575
|
patchPath: location.patch,
|
|
50485
|
-
patchSha256:
|
|
50576
|
+
patchSha256: hash2(patch),
|
|
50486
50577
|
deliveryTree: final.tree,
|
|
50487
50578
|
changes,
|
|
50488
50579
|
status: "prepared"
|
|
@@ -50498,7 +50589,7 @@ async function integrateTaskDelivery(mission, input) {
|
|
|
50498
50589
|
if (delivery.workspace.missionId !== mission.id || !same(delivery.workspace, input.workspace) || delivery.patchSha256 !== input.patchSha256 || delivery.patchPath !== location.patch)
|
|
50499
50590
|
throw new Error("Parallel delivery does not match its persisted task identity and patch. Inspect the saved artifacts before recovery.");
|
|
50500
50591
|
const patch = await readFile4(location.patch);
|
|
50501
|
-
if (
|
|
50592
|
+
if (hash2(patch) !== delivery.patchSha256)
|
|
50502
50593
|
throw new Error("Parallel delivery patch changed. Restore its saved SHA256 before integration.");
|
|
50503
50594
|
const current = await captureParallelBaseline(mission.workspace.path);
|
|
50504
50595
|
const images = await parallelTreeImages(mission.workspace.path, current.tree);
|
|
@@ -66141,7 +66232,11 @@ ${details}` : ""}`);
|
|
|
66141
66232
|
timeoutSec,
|
|
66142
66233
|
maxRepairs,
|
|
66143
66234
|
maxRounds,
|
|
66144
|
-
operatingPolicy: chiefOperatingPolicy(chiefConfig, readyActors, !profile
|
|
66235
|
+
operatingPolicy: chiefOperatingPolicy(chiefConfig, readyActors, !profile, project?.oma?.skill_compatibility ? {
|
|
66236
|
+
reportPath: resolve11(root, project.oma.skill_compatibility.report_path),
|
|
66237
|
+
maxAgeHours: project.oma.skill_compatibility.max_age_hours,
|
|
66238
|
+
mode: project.oma.skill_compatibility.mode
|
|
66239
|
+
} : undefined),
|
|
66145
66240
|
capturePolicy: chiefCapturePolicy(chiefConfig),
|
|
66146
66241
|
executionPolicy,
|
|
66147
66242
|
metricSourcePolicy: chiefConfig.metric_sources,
|
|
@@ -66472,7 +66567,7 @@ async function launchMission(input) {
|
|
|
66472
66567
|
// src/operation-api.ts
|
|
66473
66568
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
66474
66569
|
import { realpath as realpath20 } from "node:fs/promises";
|
|
66475
|
-
import { join as
|
|
66570
|
+
import { join as join37 } from "node:path";
|
|
66476
66571
|
|
|
66477
66572
|
// ../../packages/core/src/chief/continuous-store.ts
|
|
66478
66573
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
@@ -66676,10 +66771,10 @@ class ContinuousOperationStore {
|
|
|
66676
66771
|
}
|
|
66677
66772
|
|
|
66678
66773
|
// src/chief-continuous.ts
|
|
66679
|
-
import { execFile as
|
|
66774
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
66680
66775
|
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
66681
66776
|
import { mkdir as mkdir17, realpath as realpath19, rename as rename7, unlink as unlink7, writeFile as writeFile13 } from "node:fs/promises";
|
|
66682
|
-
import { join as
|
|
66777
|
+
import { join as join36, resolve as resolve20 } from "node:path";
|
|
66683
66778
|
import { promisify as promisify2 } from "node:util";
|
|
66684
66779
|
|
|
66685
66780
|
// ../../packages/core/src/chief/container-observation-command.ts
|
|
@@ -67676,7 +67771,7 @@ async function createContinuousMissionWorkspace(repositoryRoot, operationId, bas
|
|
|
67676
67771
|
init_execution();
|
|
67677
67772
|
|
|
67678
67773
|
// src/chief-continuous-decision.ts
|
|
67679
|
-
import { join as
|
|
67774
|
+
import { join as join35 } from "node:path";
|
|
67680
67775
|
|
|
67681
67776
|
// ../../packages/core/src/chief/coordinator-run.ts
|
|
67682
67777
|
init_execution();
|
|
@@ -67771,13 +67866,13 @@ init_execution();
|
|
|
67771
67866
|
|
|
67772
67867
|
// ../../packages/core/src/chief/runtime.ts
|
|
67773
67868
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
67774
|
-
import { join as
|
|
67869
|
+
import { join as join28, resolve as resolve16 } from "node:path";
|
|
67775
67870
|
|
|
67776
67871
|
// ../../packages/core/src/oma/receipt-adapter.ts
|
|
67777
67872
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
67778
|
-
import { existsSync as existsSync4, lstatSync as
|
|
67873
|
+
import { existsSync as existsSync4, lstatSync as lstatSync3, readFileSync as readFileSync9 } from "node:fs";
|
|
67779
67874
|
import { mkdir as mkdir12, writeFile as writeFile9 } from "node:fs/promises";
|
|
67780
|
-
import { isAbsolute as
|
|
67875
|
+
import { basename as basename2, dirname as dirname7, isAbsolute as isAbsolute8, join as join26, relative as relative8, resolve as resolve15, sep as sep10 } from "node:path";
|
|
67781
67876
|
|
|
67782
67877
|
// ../../packages/core/src/config/workflow-router.ts
|
|
67783
67878
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
@@ -68093,27 +68188,107 @@ function ensureLatestOmaCli(options = {}) {
|
|
|
68093
68188
|
return pending;
|
|
68094
68189
|
}
|
|
68095
68190
|
|
|
68191
|
+
// ../../packages/core/src/oma/receipt-storage.ts
|
|
68192
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
68193
|
+
import { lstatSync as lstatSync2, readdirSync, realpathSync as realpathSync5 } from "node:fs";
|
|
68194
|
+
import { homedir as homedir6 } from "node:os";
|
|
68195
|
+
import { basename, dirname as dirname6, isAbsolute as isAbsolute7, join as join25, relative as relative7, resolve as resolve14, sep as sep9 } from "node:path";
|
|
68196
|
+
var OMA_RUN_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
68197
|
+
function absolutePath(value, key) {
|
|
68198
|
+
if (!isAbsolute7(value) || Array.from(value).some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127))
|
|
68199
|
+
throw new Error(`${key} must be an absolute path without control characters`);
|
|
68200
|
+
return resolve14(value);
|
|
68201
|
+
}
|
|
68202
|
+
function omaReceiptDirectories(workspace, options = {}) {
|
|
68203
|
+
const env = options.env ?? process.env;
|
|
68204
|
+
const profile = env.OMA_PROFILE ?? "0";
|
|
68205
|
+
if (!/^(0|[1-9][0-9]{0,9})$/.test(profile))
|
|
68206
|
+
throw new Error("OMA_PROFILE must be a non-negative profile number");
|
|
68207
|
+
const stateHome = env.OMA_STATE_HOME === undefined ? absolutePath(env.OMA_HOME || join25(options.home ?? homedir6(), ".oma"), "OMA_HOME") : absolutePath(env.OMA_STATE_HOME, "OMA_STATE_HOME");
|
|
68208
|
+
const project = createHash16("sha256").update(realpathSync5(resolve14(workspace))).digest("hex");
|
|
68209
|
+
return [
|
|
68210
|
+
join25(stateHome, "u", profile, "projects", project, "agent-runs"),
|
|
68211
|
+
...profile === "0" ? [join25(resolve14(workspace), ".agents", "state", "agent-runs")] : []
|
|
68212
|
+
];
|
|
68213
|
+
}
|
|
68214
|
+
function regularDirectory(path) {
|
|
68215
|
+
try {
|
|
68216
|
+
const stat = lstatSync2(path);
|
|
68217
|
+
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
68218
|
+
throw new Error("OMA receipt directory is not a regular directory");
|
|
68219
|
+
return true;
|
|
68220
|
+
} catch (error) {
|
|
68221
|
+
if (error.code === "ENOENT")
|
|
68222
|
+
return false;
|
|
68223
|
+
throw error;
|
|
68224
|
+
}
|
|
68225
|
+
}
|
|
68226
|
+
function validateDirectory(directory, workspace) {
|
|
68227
|
+
if (!regularDirectory(directory))
|
|
68228
|
+
return false;
|
|
68229
|
+
const legacy = join25(resolve14(workspace), ".agents", "state", "agent-runs");
|
|
68230
|
+
const boundary = directory === legacy ? resolve14(workspace) : dirname6(dirname6(dirname6(dirname6(dirname6(directory)))));
|
|
68231
|
+
const components = relative7(boundary, directory).split(sep9).filter(Boolean);
|
|
68232
|
+
let path = boundary;
|
|
68233
|
+
for (const component of components) {
|
|
68234
|
+
path = join25(path, component);
|
|
68235
|
+
if (!regularDirectory(path))
|
|
68236
|
+
throw new Error("OMA receipt directory changed during inspection");
|
|
68237
|
+
}
|
|
68238
|
+
return true;
|
|
68239
|
+
}
|
|
68240
|
+
function listOmaRunFiles(workspace, options = {}) {
|
|
68241
|
+
return omaReceiptDirectories(workspace, options).flatMap((directory) => {
|
|
68242
|
+
if (!validateDirectory(directory, workspace))
|
|
68243
|
+
return [];
|
|
68244
|
+
return readdirSync(directory).filter((name) => name.endsWith(".json") && OMA_RUN_ID.test(name.slice(0, -5))).map((name) => join25(directory, name));
|
|
68245
|
+
});
|
|
68246
|
+
}
|
|
68247
|
+
function resolveOmaReceiptPath(workspace, entry, options = {}) {
|
|
68248
|
+
const name = basename(entry);
|
|
68249
|
+
if (!name.endsWith(".json") || !OMA_RUN_ID.test(name.slice(0, -5)))
|
|
68250
|
+
throw new Error("Invalid receipt filename");
|
|
68251
|
+
if (entry === name)
|
|
68252
|
+
return join25(resolve14(workspace), ".agents", "state", "agent-runs", name);
|
|
68253
|
+
if (!isAbsolute7(entry) || resolve14(entry) !== entry)
|
|
68254
|
+
throw new Error("Invalid receipt path");
|
|
68255
|
+
if (!omaReceiptDirectories(workspace, options).includes(dirname6(entry)))
|
|
68256
|
+
throw new Error("OMA receipt is outside the selected project/profile");
|
|
68257
|
+
if (!validateDirectory(dirname6(entry), workspace))
|
|
68258
|
+
throw new Error("OMA receipt directory is missing");
|
|
68259
|
+
return entry;
|
|
68260
|
+
}
|
|
68261
|
+
|
|
68096
68262
|
// ../../packages/core/src/oma/receipt-adapter.ts
|
|
68097
68263
|
var OMA_RECEIPT_SCHEMA_VERSION = 1;
|
|
68098
|
-
var RUN_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
68099
68264
|
var HASH = /^[a-f0-9]{64}$/;
|
|
68100
|
-
|
|
68101
|
-
|
|
68102
|
-
|
|
68103
|
-
|
|
68104
|
-
}
|
|
68105
|
-
|
|
68106
|
-
|
|
68107
|
-
|
|
68108
|
-
|
|
68109
|
-
|
|
68110
|
-
|
|
68111
|
-
|
|
68112
|
-
|
|
68113
|
-
|
|
68114
|
-
|
|
68115
|
-
|
|
68116
|
-
|
|
68265
|
+
function createOmaEvidenceIO(options = {}) {
|
|
68266
|
+
const env = { ...options.env ?? process.env, OMA_SKIP_VERSION_CHECK: "1" };
|
|
68267
|
+
if (options.home !== undefined && !env.OMA_HOME)
|
|
68268
|
+
env.OMA_HOME = join26(options.home, ".oma");
|
|
68269
|
+
const storage = { ...options, env };
|
|
68270
|
+
return {
|
|
68271
|
+
listRunFiles: (workspacePath) => listOmaRunFiles(workspacePath, storage),
|
|
68272
|
+
resolveRunFile: (workspacePath, entry) => resolveOmaReceiptPath(workspacePath, entry, storage),
|
|
68273
|
+
readReceipt: (path) => {
|
|
68274
|
+
if (!lstatSync3(path).isFile())
|
|
68275
|
+
throw new Error("Receipt is not a regular file");
|
|
68276
|
+
return readFileSync9(path, "utf-8");
|
|
68277
|
+
},
|
|
68278
|
+
runCli: (args, cwd) => {
|
|
68279
|
+
const result = spawnSync2("oma", args, {
|
|
68280
|
+
cwd,
|
|
68281
|
+
env,
|
|
68282
|
+
encoding: "utf-8",
|
|
68283
|
+
timeout: 15000,
|
|
68284
|
+
maxBuffer: 1024 * 1024
|
|
68285
|
+
});
|
|
68286
|
+
if (result.error)
|
|
68287
|
+
throw result.error;
|
|
68288
|
+
return { exitCode: result.status, stdout: result.stdout };
|
|
68289
|
+
}
|
|
68290
|
+
};
|
|
68291
|
+
}
|
|
68117
68292
|
function fail(reason) {
|
|
68118
68293
|
return { ok: false, reason };
|
|
68119
68294
|
}
|
|
@@ -68137,17 +68312,17 @@ async function prepareOmaAttempt(request, dependencies = {}) {
|
|
|
68137
68312
|
const routed = routeIssue(`${request.issue.title}
|
|
68138
68313
|
${request.issue.description ?? ""}`, table);
|
|
68139
68314
|
for (const workflow of routed.workflows) {
|
|
68140
|
-
const file =
|
|
68315
|
+
const file = join26(request.workspace.path, ".agents", "workflows", `${workflow}.md`);
|
|
68141
68316
|
if (!existsSync4(file))
|
|
68142
68317
|
throw new Error(`OMA workflow file missing in target worktree: ${file}`);
|
|
68143
68318
|
}
|
|
68144
68319
|
await ensureLatestOmaCli({ io: dependencies.latestCliIO });
|
|
68145
|
-
const path =
|
|
68320
|
+
const path = join26(request.workspace.path, ".agents", "results", `plan-${request.attempt.id}.json`);
|
|
68146
68321
|
const plan = {
|
|
68147
68322
|
session_id: request.attempt.id,
|
|
68148
68323
|
lineage_id: request.attempt.id,
|
|
68149
68324
|
valley_issue_id: request.issue.id,
|
|
68150
|
-
valley_workspace:
|
|
68325
|
+
valley_workspace: resolve15(request.workspace.path),
|
|
68151
68326
|
tasks: [
|
|
68152
68327
|
{
|
|
68153
68328
|
id: request.attempt.id,
|
|
@@ -68167,7 +68342,7 @@ ${request.issue.description ?? ""}`, table);
|
|
|
68167
68342
|
}
|
|
68168
68343
|
]
|
|
68169
68344
|
};
|
|
68170
|
-
await mkdir12(
|
|
68345
|
+
await mkdir12(join26(request.workspace.path, ".agents", "results"), { recursive: true });
|
|
68171
68346
|
await writeFile9(path, JSON.stringify(plan, null, 2), { encoding: "utf-8", flag: "wx" });
|
|
68172
68347
|
return path;
|
|
68173
68348
|
}
|
|
@@ -68195,8 +68370,8 @@ function buildOmaGuidance(request) {
|
|
|
68195
68370
|
].join(`
|
|
68196
68371
|
`);
|
|
68197
68372
|
}
|
|
68198
|
-
function validateOmaEvidence(request, io =
|
|
68199
|
-
const root =
|
|
68373
|
+
function validateOmaEvidence(request, io = createOmaEvidenceIO()) {
|
|
68374
|
+
const root = resolve15(request.workspace.path);
|
|
68200
68375
|
if (!request.verifyCommand.trim())
|
|
68201
68376
|
return fail("Strict OMA mode has no configured verify command");
|
|
68202
68377
|
let cliVersion;
|
|
@@ -68210,26 +68385,37 @@ function validateOmaEvidence(request, io = defaultIO2) {
|
|
|
68210
68385
|
return fail(`OMA CLI unavailable: ${String(err)}`);
|
|
68211
68386
|
}
|
|
68212
68387
|
let receipts;
|
|
68388
|
+
const locations = new Map;
|
|
68213
68389
|
try {
|
|
68214
|
-
receipts = io.listRunFiles(root).map((
|
|
68215
|
-
|
|
68390
|
+
receipts = io.listRunFiles(root).map((entry) => {
|
|
68391
|
+
const name = basename2(entry);
|
|
68392
|
+
const path = (io.resolveRunFile ?? resolveOmaReceiptPath)(root, entry);
|
|
68393
|
+
if (!OMA_RUN_ID.test(name.slice(0, -5)) || !name.endsWith(".json"))
|
|
68216
68394
|
throw new Error("Invalid receipt filename");
|
|
68217
|
-
const parsed = JSON.parse(io.readReceipt(
|
|
68395
|
+
const parsed = JSON.parse(io.readReceipt(path));
|
|
68218
68396
|
if (!isRecord(parsed) || parsed.runId !== name.slice(0, -5))
|
|
68219
68397
|
throw new Error("Malformed run receipt");
|
|
68398
|
+
locations.set(parsed, dirname7(path));
|
|
68220
68399
|
return parsed;
|
|
68221
68400
|
});
|
|
68222
68401
|
} catch (err) {
|
|
68223
68402
|
return fail(`Missing or malformed OMA receipt: ${String(err)}`);
|
|
68224
68403
|
}
|
|
68225
|
-
const forAttempt = receipts.filter((run) => run.sessionId === request.attempt.id && run.agentId === request.agentId)
|
|
68404
|
+
const forAttempt = receipts.filter((run) => run.sessionId === request.attempt.id && run.agentId === request.agentId);
|
|
68405
|
+
if (forAttempt.some((run) => !Number.isSafeInteger(run.sequence) || Number(run.sequence) < 1))
|
|
68406
|
+
return fail("OMA receipt sequence is malformed");
|
|
68407
|
+
if (new Set(forAttempt.map((run) => run.sequence)).size !== forAttempt.length)
|
|
68408
|
+
return fail("OMA receipt sequence is ambiguous across matching runs");
|
|
68409
|
+
if (new Set(forAttempt.map((run) => locations.get(run))).size > 1)
|
|
68410
|
+
return fail("Matching OMA receipts span multiple stores; generate current evidence in the active CLI's selected project/profile");
|
|
68411
|
+
forAttempt.sort((a, b) => Number(a.sequence) - Number(b.sequence));
|
|
68226
68412
|
const run = forAttempt.at(-1);
|
|
68227
68413
|
if (!run)
|
|
68228
68414
|
return fail("No OMA receipt is bound to this Valley attempt");
|
|
68229
68415
|
if (run.schemaVersion !== OMA_RECEIPT_SCHEMA_VERSION) {
|
|
68230
68416
|
return fail(`OMA CLI ${cliVersion} returned an unsupported receipt schema. AV requires agent-run schema v${OMA_RECEIPT_SCHEMA_VERSION}; update AV and OMA (npm install -g oh-my-agent@latest), then generate and verify a compatible receipt.`);
|
|
68231
68417
|
}
|
|
68232
|
-
if (run.taskId !== request.attempt.id || !
|
|
68418
|
+
if (run.taskId !== request.attempt.id || !OMA_RUN_ID.test(String(run.runId))) {
|
|
68233
68419
|
return fail("OMA receipt task identity is incompatible");
|
|
68234
68420
|
}
|
|
68235
68421
|
if (run.workspace !== root || run.artifactRoot !== root || run.status !== "completed" || run.exitCode !== 0) {
|
|
@@ -68263,12 +68449,12 @@ function validateOmaEvidence(request, io = defaultIO2) {
|
|
|
68263
68449
|
if (!template?.includes("{{attempt.id}}"))
|
|
68264
68450
|
return fail("Analysis requires a configured current-attempt report path");
|
|
68265
68451
|
const expanded = template.replaceAll("{{attempt.id}}", request.attempt.id);
|
|
68266
|
-
const target =
|
|
68267
|
-
const subpath =
|
|
68268
|
-
if (
|
|
68452
|
+
const target = resolve15(root, expanded);
|
|
68453
|
+
const subpath = relative8(root, target);
|
|
68454
|
+
if (isAbsolute8(expanded) || expanded.split(/[\\/]/).includes("..") || subpath === "" || subpath === ".." || subpath.startsWith(`..${sep10}`) || isAbsolute8(subpath)) {
|
|
68269
68455
|
return fail("Configured analysis report escapes the workspace");
|
|
68270
68456
|
}
|
|
68271
|
-
if (!isRecord(run.artifacts) || !Object.entries(run.artifacts).some(([path, hash]) => !
|
|
68457
|
+
if (!isRecord(run.artifacts) || !Object.entries(run.artifacts).some(([path, hash]) => !isAbsolute8(path) && !path.split(/[\\/]/).includes("..") && resolve15(root, path) === target && HASH.test(String(hash)))) {
|
|
68272
68458
|
return fail("OMA receipt does not bind the configured current-attempt report");
|
|
68273
68459
|
}
|
|
68274
68460
|
}
|
|
@@ -68285,7 +68471,7 @@ function validateOmaEvidence(request, io = defaultIO2) {
|
|
|
68285
68471
|
for (const check of run.checks) {
|
|
68286
68472
|
if (!isRecord(check) || !stringArray(check.command) || !check.command.length || typeof check.cwd !== "string")
|
|
68287
68473
|
return fail("OMA verification receipt is malformed");
|
|
68288
|
-
latestChecks.set(JSON.stringify([check.command,
|
|
68474
|
+
latestChecks.set(JSON.stringify([check.command, resolve15(check.cwd)]), check);
|
|
68289
68475
|
}
|
|
68290
68476
|
if ([...latestChecks.values()].some((check) => check.exitCode !== 0 || check.before !== run.after || check.after !== run.after)) {
|
|
68291
68477
|
return fail("An OMA verification check failed or is stale");
|
|
@@ -68307,6 +68493,214 @@ function validateOmaEvidence(request, io = defaultIO2) {
|
|
|
68307
68493
|
return { ok: true, runId: String(run.runId) };
|
|
68308
68494
|
}
|
|
68309
68495
|
|
|
68496
|
+
// ../../packages/core/src/oma/skill-matrix-adapter.ts
|
|
68497
|
+
import { posix } from "node:path";
|
|
68498
|
+
|
|
68499
|
+
// ../../packages/core/src/oma/skill-matrix-io.ts
|
|
68500
|
+
init_skill_matrix_schema();
|
|
68501
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
68502
|
+
import { constants as constants5 } from "node:fs";
|
|
68503
|
+
import { open as open7 } from "node:fs/promises";
|
|
68504
|
+
var MAX_BYTES = 4 * 1024 * 1024;
|
|
68505
|
+
async function command(binary, args, signal) {
|
|
68506
|
+
return new Promise((resolve, reject) => {
|
|
68507
|
+
execFile4(binary, args, {
|
|
68508
|
+
encoding: "utf8",
|
|
68509
|
+
timeout: 1e4,
|
|
68510
|
+
maxBuffer: MAX_BYTES,
|
|
68511
|
+
signal,
|
|
68512
|
+
...binary === "oma" ? { env: { ...process.env, OMA_SKIP_VERSION_CHECK: "1" } } : {}
|
|
68513
|
+
}, (error, stdout) => {
|
|
68514
|
+
if (error)
|
|
68515
|
+
reject(new Error(`${binary} local diagnostic command failed. Check its installation/version and retry.`));
|
|
68516
|
+
else
|
|
68517
|
+
resolve(stdout);
|
|
68518
|
+
});
|
|
68519
|
+
});
|
|
68520
|
+
}
|
|
68521
|
+
async function readReport(path) {
|
|
68522
|
+
const file = await open7(path, constants5.O_RDONLY | constants5.O_NOFOLLOW | constants5.O_NONBLOCK);
|
|
68523
|
+
try {
|
|
68524
|
+
const info = await file.stat();
|
|
68525
|
+
if (!info.isFile() || info.size > MAX_BYTES)
|
|
68526
|
+
throw new Error("Matrix report must be a regular file at most 4 MiB.");
|
|
68527
|
+
const bytes = Buffer.alloc(info.size + 1);
|
|
68528
|
+
let length = 0;
|
|
68529
|
+
while (length < bytes.length) {
|
|
68530
|
+
const result = await file.read(bytes, length, bytes.length - length, length);
|
|
68531
|
+
if (!result.bytesRead)
|
|
68532
|
+
break;
|
|
68533
|
+
length += result.bytesRead;
|
|
68534
|
+
}
|
|
68535
|
+
if (length !== info.size)
|
|
68536
|
+
throw new Error("Matrix report changed during the read. Retry after its writer finishes.");
|
|
68537
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
|
|
68538
|
+
} finally {
|
|
68539
|
+
await file.close();
|
|
68540
|
+
}
|
|
68541
|
+
}
|
|
68542
|
+
var defaultSkillMatrixDeps = {
|
|
68543
|
+
now: Date.now,
|
|
68544
|
+
platform: process.platform,
|
|
68545
|
+
arch: process.arch,
|
|
68546
|
+
readReport,
|
|
68547
|
+
plan: async (workspace, skills, signal) => JSON.parse(await command("oma", [
|
|
68548
|
+
"skills",
|
|
68549
|
+
"matrix",
|
|
68550
|
+
"--project-root",
|
|
68551
|
+
workspace,
|
|
68552
|
+
"--skills",
|
|
68553
|
+
skills.join(","),
|
|
68554
|
+
"--delivery",
|
|
68555
|
+
"injected",
|
|
68556
|
+
"--vendors",
|
|
68557
|
+
"claude,codex",
|
|
68558
|
+
"--json"
|
|
68559
|
+
], signal)),
|
|
68560
|
+
cliVersion: async (vendor, signal) => {
|
|
68561
|
+
const version = (await command(vendor, ["--version"], signal)).trim();
|
|
68562
|
+
return /^[\w .()+/-]{1,160}$/.test(version) ? version : null;
|
|
68563
|
+
}
|
|
68564
|
+
};
|
|
68565
|
+
function parseSkillMatrix(value) {
|
|
68566
|
+
const parsed = matrixReportSchema.safeParse(value);
|
|
68567
|
+
if (!parsed.success)
|
|
68568
|
+
throw new Error("Matrix report uses an unsupported or malformed evidence contract. Regenerate it with the current OMA CLI.");
|
|
68569
|
+
const report = parsed.data;
|
|
68570
|
+
const unique = (values) => new Set(values).size === values.length;
|
|
68571
|
+
if (!unique(report.cases.map((entry) => entry.id)) || !unique(report.cells.map((entry) => `${entry.vendor}\x00${entry.caseId}`)) || report.bundle && (!unique(report.bundle.skills.map((entry) => entry.name)) || !unique(report.bundle.skills.map((entry) => entry.caseId))) || report.cells.some((cell) => !unique(cell.checks.map((check) => check.id))))
|
|
68572
|
+
throw new Error("Matrix report repeats a skill, case or vendor cell. Regenerate an unambiguous report.");
|
|
68573
|
+
return report;
|
|
68574
|
+
}
|
|
68575
|
+
|
|
68576
|
+
// ../../packages/core/src/oma/skill-matrix-adapter.ts
|
|
68577
|
+
var scope = "installed injected read-reference audit; not AV runtime or task-quality certification";
|
|
68578
|
+
var safeNames = /^[a-z0-9][a-z0-9-]{0,127}$/;
|
|
68579
|
+
var remediation = "Regenerate the installed injected matrix with explicit models, then set oma.skill_compatibility.report_path in av.yaml.";
|
|
68580
|
+
var matrixRouteKey = (route) => `${route.actorType}\x00${route.model ?? ""}`;
|
|
68581
|
+
function sourceProblem(report) {
|
|
68582
|
+
if (report.sourceKind !== "installed" || report.delivery !== "injected" || report.auditScope !== "read-reference" || !report.bundle)
|
|
68583
|
+
return "Evidence is not an installed, injected, read-reference audit. Synthetic probes cannot authorize installed skills.";
|
|
68584
|
+
return;
|
|
68585
|
+
}
|
|
68586
|
+
function sameCoverage(a, b) {
|
|
68587
|
+
const sorted = (items) => JSON.stringify([...items].sort());
|
|
68588
|
+
return a.hash === b.hash && a.caseId === b.caseId && sorted(a.requiredFiles) === sorted(b.requiredFiles) && sorted(a.missingFiles) === sorted(b.missingFiles) && JSON.stringify(a.excludedReferences) === JSON.stringify(b.excludedReferences);
|
|
68589
|
+
}
|
|
68590
|
+
function assessRoute(report, plan, skills, route, version) {
|
|
68591
|
+
const result = (status, reason) => ({
|
|
68592
|
+
...route,
|
|
68593
|
+
status,
|
|
68594
|
+
reason
|
|
68595
|
+
});
|
|
68596
|
+
if (route.actorType !== "claude" && route.actorType !== "codex")
|
|
68597
|
+
return result("unknown", "This matrix protocol measures only Claude and Codex.");
|
|
68598
|
+
if (!route.model)
|
|
68599
|
+
return result("unknown", "The candidate uses an unpinned native model default; it cannot match a measured model.");
|
|
68600
|
+
if (!version)
|
|
68601
|
+
return result("unknown", "The current native CLI version could not be verified.");
|
|
68602
|
+
for (const name of skills) {
|
|
68603
|
+
const current = plan.bundle?.skills.find((entry) => entry.name === name);
|
|
68604
|
+
const saved = report.bundle?.skills.find((entry) => entry.name === name);
|
|
68605
|
+
if (!current || !saved)
|
|
68606
|
+
return result("unknown", `Skill ${name} has no complete installed audit coverage.`);
|
|
68607
|
+
if (!sameCoverage(current, saved))
|
|
68608
|
+
return result("unknown", `Skill ${name} content or reference coverage changed after the audit.`);
|
|
68609
|
+
if (current.missingFiles.length || current.excludedReferences.length || saved.missingFiles.length || saved.excludedReferences.length)
|
|
68610
|
+
return result("unknown", `Skill ${name} has missing or excluded references; complete its audit coverage first.`);
|
|
68611
|
+
if (!report.cases.some((entry) => entry.id === saved.caseId && entry.skill === name))
|
|
68612
|
+
return result("unknown", `Skill ${name} required case is absent from the measured selection.`);
|
|
68613
|
+
const cell = report.cells.find((entry) => entry.caseId === saved.caseId && entry.vendor === route.actorType);
|
|
68614
|
+
if (!cell || cell.skill !== name || cell.contentHash !== current.hash)
|
|
68615
|
+
return result("unknown", `Skill ${name} lacks a matching measured vendor cell.`);
|
|
68616
|
+
if (cell.cliVersion !== version)
|
|
68617
|
+
return result("unknown", `Skill ${name} was measured with a different or unknown native CLI version.`);
|
|
68618
|
+
if (cell.model !== route.model)
|
|
68619
|
+
return result("unknown", `Skill ${name} was measured with a different or unknown reported model.`);
|
|
68620
|
+
if (cell.status !== "pass" || !cell.checks.length || cell.checks.some((check) => check.status !== "pass"))
|
|
68621
|
+
return result(cell.status === "fail" ? "fail" : "unknown", `Skill ${name} audit is ${cell.status}; passing read-reference evidence is required.`);
|
|
68622
|
+
const entry = `${name}/SKILL.md`;
|
|
68623
|
+
if (!current.requiredFiles.includes(entry))
|
|
68624
|
+
return result("unknown", `Skill ${name} audit omits its installed SKILL.md.`);
|
|
68625
|
+
const required = [
|
|
68626
|
+
"process",
|
|
68627
|
+
"output",
|
|
68628
|
+
"content",
|
|
68629
|
+
"integrity",
|
|
68630
|
+
"reference-coverage",
|
|
68631
|
+
...current.requiredFiles.filter((file) => file !== entry).map((file) => `reference:${posix.relative(name, file)}`)
|
|
68632
|
+
];
|
|
68633
|
+
if (required.some((id) => !cell.checks.some((check) => check.id === id && check.status === "pass" && (id === "content" || id.startsWith("reference:") ? check.proof === "read" : true))))
|
|
68634
|
+
return result("unknown", `Skill ${name} audit lacks a mandatory successful read-reference check.`);
|
|
68635
|
+
}
|
|
68636
|
+
return result("pass", "All selected skills have current passing installed injected read-reference evidence.");
|
|
68637
|
+
}
|
|
68638
|
+
async function inspectSkillCompatibility(policy, workspace, selectedSkills, routes, deps = defaultSkillMatrixDeps, signal) {
|
|
68639
|
+
const unknown = (reason) => ({
|
|
68640
|
+
scope,
|
|
68641
|
+
routes: routes.map((route) => ({ ...route, status: "unknown", reason }))
|
|
68642
|
+
});
|
|
68643
|
+
if (selectedSkills?.length === 0)
|
|
68644
|
+
return {
|
|
68645
|
+
scope,
|
|
68646
|
+
routes: routes.map((route) => ({
|
|
68647
|
+
...route,
|
|
68648
|
+
status: "pass",
|
|
68649
|
+
reason: "No skills selected; no compatibility claim is required."
|
|
68650
|
+
}))
|
|
68651
|
+
};
|
|
68652
|
+
try {
|
|
68653
|
+
if (signal?.aborted)
|
|
68654
|
+
throw new Error("Interrupted");
|
|
68655
|
+
const report = parseSkillMatrix(await deps.readReport(policy.reportPath));
|
|
68656
|
+
const source = sourceProblem(report);
|
|
68657
|
+
if (source)
|
|
68658
|
+
return unknown(source);
|
|
68659
|
+
if (report.mode !== "live" || report.status !== "completed")
|
|
68660
|
+
return unknown("The report is not a completed live measurement; a plan is unmeasured.");
|
|
68661
|
+
const age = deps.now() - Date.parse(report.createdAt);
|
|
68662
|
+
if (age < -60000 || age > policy.maxAgeHours * 3600000)
|
|
68663
|
+
return unknown("The cached matrix is stale or has a future timestamp.");
|
|
68664
|
+
if (report.host.platform !== deps.platform || report.host.arch !== deps.arch)
|
|
68665
|
+
return unknown("The matrix host platform or architecture differs from this runtime.");
|
|
68666
|
+
const skills = [...new Set(selectedSkills ?? report.bundle?.skills.map((entry) => entry.name) ?? [])];
|
|
68667
|
+
if (!skills.length || skills.length > 100 || skills.some((name) => !safeNames.test(name)))
|
|
68668
|
+
return unknown("Select a bounded list of valid installed skill names.");
|
|
68669
|
+
const plan = parseSkillMatrix(await deps.plan(workspace, skills, signal));
|
|
68670
|
+
if (sourceProblem(plan) || plan.mode !== "plan" || plan.status !== "planned")
|
|
68671
|
+
return unknown("OMA did not return a supported installed injected plan.");
|
|
68672
|
+
if (plan.omaVersion !== report.omaVersion)
|
|
68673
|
+
return unknown("The OMA version changed after measurement; refresh the cached matrix.");
|
|
68674
|
+
if (plan.host.platform !== deps.platform || plan.host.arch !== deps.arch)
|
|
68675
|
+
return unknown("The current OMA plan host does not match this runtime.");
|
|
68676
|
+
const versions = new Map;
|
|
68677
|
+
for (const route of routes) {
|
|
68678
|
+
if (versions.has(route.actorType) || route.actorType !== "claude" && route.actorType !== "codex")
|
|
68679
|
+
continue;
|
|
68680
|
+
try {
|
|
68681
|
+
versions.set(route.actorType, await deps.cliVersion(route.actorType, signal));
|
|
68682
|
+
} catch {
|
|
68683
|
+
versions.set(route.actorType, null);
|
|
68684
|
+
}
|
|
68685
|
+
}
|
|
68686
|
+
if (signal?.aborted)
|
|
68687
|
+
throw new Error("Interrupted");
|
|
68688
|
+
return {
|
|
68689
|
+
scope,
|
|
68690
|
+
routes: routes.map((route) => assessRoute(report, plan, skills, route, versions.get(route.actorType) ?? null))
|
|
68691
|
+
};
|
|
68692
|
+
} catch {
|
|
68693
|
+
if (signal?.aborted)
|
|
68694
|
+
throw new Error("Skill compatibility inspection interrupted before Actor launch.");
|
|
68695
|
+
return unknown(`The cached report or local OMA plan could not be validated. ${remediation}`);
|
|
68696
|
+
}
|
|
68697
|
+
}
|
|
68698
|
+
function assertCompatibleRoute(route, inspection) {
|
|
68699
|
+
const result = inspection.routes.find((entry) => matrixRouteKey(entry) === matrixRouteKey(route));
|
|
68700
|
+
if (result?.status !== "pass")
|
|
68701
|
+
throw new Error(`Skill compatibility required for ${route.actorType}/${route.model ?? "native default"}: ${result?.reason ?? "no matching evidence"} ${remediation}`);
|
|
68702
|
+
}
|
|
68703
|
+
|
|
68310
68704
|
// ../../packages/core/src/orchestrator/agent-runner.ts
|
|
68311
68705
|
init_logger();
|
|
68312
68706
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -68798,9 +69192,9 @@ async function withMissionDeadline(mission, parent, run) {
|
|
|
68798
69192
|
|
|
68799
69193
|
// ../../packages/core/src/chief/skills.ts
|
|
68800
69194
|
init_dist();
|
|
68801
|
-
import { constants as
|
|
68802
|
-
import { lstat as lstat11, mkdir as mkdir13, open as
|
|
68803
|
-
import { isAbsolute as
|
|
69195
|
+
import { constants as constants6 } from "node:fs";
|
|
69196
|
+
import { lstat as lstat11, mkdir as mkdir13, open as open8, readdir as readdir6, realpath as realpath14, stat, writeFile as writeFile10 } from "node:fs/promises";
|
|
69197
|
+
import { isAbsolute as isAbsolute9, join as join27, relative as relative9, sep as sep11 } from "node:path";
|
|
68804
69198
|
var MAX_SKILL_BYTES = 256000;
|
|
68805
69199
|
var MAX_METADATA_BYTES = 16384;
|
|
68806
69200
|
var MAX_CATALOG_SIZE = 100;
|
|
@@ -68809,8 +69203,8 @@ var MAX_HARNESS_ENTRIES = 5000;
|
|
|
68809
69203
|
var SKILL_NAME = /^[a-z0-9][a-z0-9-]{0,127}$/;
|
|
68810
69204
|
var OMA_SKILL_NAME = /^oma-[a-z0-9][a-z0-9-]{0,123}$/;
|
|
68811
69205
|
function inside(root, path) {
|
|
68812
|
-
const child =
|
|
68813
|
-
return child !== "" && child !== ".." && !child.startsWith(`..${
|
|
69206
|
+
const child = relative9(root, path);
|
|
69207
|
+
return child !== "" && child !== ".." && !child.startsWith(`..${sep11}`) && !isAbsolute9(child);
|
|
68814
69208
|
}
|
|
68815
69209
|
function excludedResource(name) {
|
|
68816
69210
|
return [
|
|
@@ -68833,11 +69227,11 @@ async function prepareMissionSkills(sourceRepositoryPath, workspacePath) {
|
|
|
68833
69227
|
if (!source)
|
|
68834
69228
|
return;
|
|
68835
69229
|
const workspace = await realpath14(workspacePath);
|
|
68836
|
-
const agents =
|
|
69230
|
+
const agents = join27(workspace, ".agents");
|
|
68837
69231
|
await mkdir13(agents, { recursive: true });
|
|
68838
69232
|
if (!inside(workspace, await realpath14(agents)))
|
|
68839
69233
|
throw new Error("The target .agents directory escapes the mission worktree. Fix its symlink before creating this order.");
|
|
68840
|
-
const target =
|
|
69234
|
+
const target = join27(agents, "skills");
|
|
68841
69235
|
await mkdir13(target, { recursive: true });
|
|
68842
69236
|
const targetRoot = await skillRoot(workspace);
|
|
68843
69237
|
if (!targetRoot)
|
|
@@ -68858,13 +69252,13 @@ async function prepareMissionSkills(sourceRepositoryPath, workspacePath) {
|
|
|
68858
69252
|
continue;
|
|
68859
69253
|
if (++entries > MAX_HARNESS_ENTRIES)
|
|
68860
69254
|
throw new Error("The installed skill resources exceed 5,000 entries. Remove unused resources before creating this order.");
|
|
68861
|
-
const from = await realpath14(
|
|
69255
|
+
const from = await realpath14(join27(sourceDirectory, name)).catch(() => {
|
|
68862
69256
|
return;
|
|
68863
69257
|
});
|
|
68864
69258
|
if (!from || !inside(sourceRoot, from))
|
|
68865
69259
|
continue;
|
|
68866
69260
|
const info = await stat(from);
|
|
68867
|
-
const to =
|
|
69261
|
+
const to = join27(targetDirectory, name);
|
|
68868
69262
|
const existing = await lstat11(to).catch(() => {
|
|
68869
69263
|
return;
|
|
68870
69264
|
});
|
|
@@ -68880,7 +69274,7 @@ async function prepareMissionSkills(sourceRepositoryPath, workspacePath) {
|
|
|
68880
69274
|
const parent = await realpath14(targetDirectory);
|
|
68881
69275
|
if (parent !== destinationRoot && !inside(destinationRoot, parent))
|
|
68882
69276
|
throw new Error("A target skill resource escapes the mission worktree. Fix its symlink before creating this order.");
|
|
68883
|
-
const file = await
|
|
69277
|
+
const file = await open8(from, constants6.O_RDONLY | constants6.O_NOFOLLOW | constants6.O_NONBLOCK);
|
|
68884
69278
|
try {
|
|
68885
69279
|
const current = await file.stat();
|
|
68886
69280
|
if (!current.isFile())
|
|
@@ -68919,7 +69313,7 @@ async function skillRoot(workspacePath) {
|
|
|
68919
69313
|
});
|
|
68920
69314
|
if (!workspace)
|
|
68921
69315
|
return;
|
|
68922
|
-
const root = await realpath14(
|
|
69316
|
+
const root = await realpath14(join27(workspace, ".agents", "skills")).catch(() => {
|
|
68923
69317
|
return;
|
|
68924
69318
|
});
|
|
68925
69319
|
if (!root)
|
|
@@ -68933,7 +69327,7 @@ async function skillRoot(workspacePath) {
|
|
|
68933
69327
|
async function skillPath(root, name) {
|
|
68934
69328
|
if (!SKILL_NAME.test(name))
|
|
68935
69329
|
throw new Error(`Invalid skill name: ${name}. Select an installed skill directory name.`);
|
|
68936
|
-
const path = await realpath14(
|
|
69330
|
+
const path = await realpath14(join27(root, name, "SKILL.md")).catch(() => {
|
|
68937
69331
|
throw new Error(`Skill ${name}/SKILL.md is missing. Restore that installed skill in ${root} before resuming.`);
|
|
68938
69332
|
});
|
|
68939
69333
|
if (!inside(root, path))
|
|
@@ -68941,7 +69335,7 @@ async function skillPath(root, name) {
|
|
|
68941
69335
|
return path;
|
|
68942
69336
|
}
|
|
68943
69337
|
async function readSkill(path, metadataOnly) {
|
|
68944
|
-
const file = await
|
|
69338
|
+
const file = await open8(path, constants6.O_RDONLY | constants6.O_NOFOLLOW | constants6.O_NONBLOCK);
|
|
68945
69339
|
try {
|
|
68946
69340
|
const info = await file.stat();
|
|
68947
69341
|
if (!info.isFile())
|
|
@@ -68989,7 +69383,7 @@ function metadata(source, name, path) {
|
|
|
68989
69383
|
async function descriptor(root, name) {
|
|
68990
69384
|
if (!OMA_SKILL_NAME.test(name))
|
|
68991
69385
|
return;
|
|
68992
|
-
const directory = await realpath14(
|
|
69386
|
+
const directory = await realpath14(join27(root, name));
|
|
68993
69387
|
if (!inside(root, directory) || !(await stat(directory)).isDirectory())
|
|
68994
69388
|
return;
|
|
68995
69389
|
const path = await skillPath(root, name);
|
|
@@ -69169,11 +69563,13 @@ class ChiefRuntime {
|
|
|
69169
69563
|
store;
|
|
69170
69564
|
signal;
|
|
69171
69565
|
onStage;
|
|
69566
|
+
skillMatrixDeps;
|
|
69172
69567
|
runners = new Set;
|
|
69173
|
-
constructor(store, signal, onStage = () => {}) {
|
|
69568
|
+
constructor(store, signal, onStage = () => {}, skillMatrixDeps) {
|
|
69174
69569
|
this.store = store;
|
|
69175
69570
|
this.signal = signal;
|
|
69176
69571
|
this.onStage = onStage;
|
|
69572
|
+
this.skillMatrixDeps = skillMatrixDeps;
|
|
69177
69573
|
}
|
|
69178
69574
|
ports() {
|
|
69179
69575
|
return {
|
|
@@ -69244,18 +69640,32 @@ class ChiefRuntime {
|
|
|
69244
69640
|
workspace,
|
|
69245
69641
|
availableSkills: mission.availableSkills?.map((skill) => ({
|
|
69246
69642
|
...skill,
|
|
69247
|
-
path:
|
|
69643
|
+
path: join28(workspace.path, ".agents", "skills", skill.name, "SKILL.md")
|
|
69248
69644
|
}))
|
|
69249
69645
|
};
|
|
69250
69646
|
if (signal?.aborted)
|
|
69251
69647
|
throw new Error("Order interrupted. Resume it with av order --resume followed by its mission ID.");
|
|
69252
|
-
const
|
|
69648
|
+
const compatibilityPolicy = mission.operatingPolicy?.skillCompatibility;
|
|
69649
|
+
const compatibility = stage === "work" && compatibilityPolicy ? await inspectSkillCompatibility(compatibilityPolicy, workspace.path, persona.skills, workActorCandidates(mission, persona, compatibilityPolicy.mode === "require"), this.skillMatrixDeps, signal) : undefined;
|
|
69650
|
+
const compatibleRoutes = compatibilityPolicy?.mode === "require" && compatibility ? new Set(compatibility.routes.filter((entry) => entry.status === "pass").map(matrixRouteKey)) : undefined;
|
|
69651
|
+
if (compatibility && compatibilityPolicy)
|
|
69652
|
+
mission.history.push({
|
|
69653
|
+
at: new Date().toISOString(),
|
|
69654
|
+
stage: "skill-compatibility",
|
|
69655
|
+
message: `${compatibilityPolicy.mode}: ${compatibility.routes.map((entry) => `${entry.actorType}/${entry.model ?? "native default"} ${entry.status}: ${entry.reason}`).join("; ")} Scope: ${compatibility.scope}.`,
|
|
69656
|
+
...context?.taskId ? { taskId: context.taskId } : {}
|
|
69657
|
+
});
|
|
69658
|
+
const route = stage === "work" ? selectWorkActor(mission, persona, context?.taskId, compatibleRoutes) : undefined;
|
|
69253
69659
|
persona = route?.actor ?? persona;
|
|
69660
|
+
if (compatibility && compatibilityPolicy) {
|
|
69661
|
+
if (compatibilityPolicy.mode === "require")
|
|
69662
|
+
assertCompatibleRoute({ actorType: persona.agentType, model: persona.model }, compatibility);
|
|
69663
|
+
}
|
|
69254
69664
|
this.onStage(stage, persona);
|
|
69255
69665
|
const attempt = {
|
|
69256
69666
|
id: randomUUID11(),
|
|
69257
69667
|
issueId: mission.id,
|
|
69258
|
-
workspacePath:
|
|
69668
|
+
workspacePath: resolve16(workspace.path),
|
|
69259
69669
|
startedAt: new Date().toISOString(),
|
|
69260
69670
|
finishedAt: null,
|
|
69261
69671
|
exitCode: null,
|
|
@@ -69461,16 +69871,16 @@ init_execution();
|
|
|
69461
69871
|
// src/chief-supervisor.ts
|
|
69462
69872
|
import { spawn as spawn16 } from "node:child_process";
|
|
69463
69873
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
69464
|
-
import { join as
|
|
69874
|
+
import { join as join32 } from "node:path";
|
|
69465
69875
|
init_execution();
|
|
69466
69876
|
|
|
69467
69877
|
// src/chief-delivery.ts
|
|
69468
|
-
import { createHash as
|
|
69878
|
+
import { createHash as createHash18 } from "node:crypto";
|
|
69469
69879
|
import { mkdir as mkdir15, writeFile as writeFile12 } from "node:fs/promises";
|
|
69470
|
-
import { join as
|
|
69880
|
+
import { join as join31 } from "node:path";
|
|
69471
69881
|
|
|
69472
69882
|
// ../../packages/core/src/chief/report-delivery.ts
|
|
69473
|
-
import { join as
|
|
69883
|
+
import { join as join30 } from "node:path";
|
|
69474
69884
|
|
|
69475
69885
|
// ../../packages/core/src/chief/report-delivery-adapters.ts
|
|
69476
69886
|
init_report_delivery_contract();
|
|
@@ -69851,20 +70261,20 @@ init_report_delivery_contract();
|
|
|
69851
70261
|
// ../../packages/core/src/chief/report-delivery-outbox.ts
|
|
69852
70262
|
init_zod();
|
|
69853
70263
|
init_report_delivery_contract();
|
|
69854
|
-
import { createHash as
|
|
69855
|
-
import { constants as
|
|
69856
|
-
import { mkdir as mkdir14, open as
|
|
69857
|
-
import { isAbsolute as
|
|
69858
|
-
var
|
|
70264
|
+
import { createHash as createHash17, randomUUID as randomUUID12 } from "node:crypto";
|
|
70265
|
+
import { constants as constants7 } from "node:fs";
|
|
70266
|
+
import { mkdir as mkdir14, open as open9, readdir as readdir7, readFile as readFile11, realpath as realpath15, rename as rename6, unlink as unlink5, writeFile as writeFile11 } from "node:fs/promises";
|
|
70267
|
+
import { isAbsolute as isAbsolute10, join as join29, relative as relative10, resolve as resolve17 } from "node:path";
|
|
70268
|
+
var hash3 = string2().regex(/^[a-f0-9]{64}$/);
|
|
69859
70269
|
var outboxRecordSchema = strictObject({
|
|
69860
70270
|
version: literal(1),
|
|
69861
|
-
id:
|
|
70271
|
+
id: hash3,
|
|
69862
70272
|
missionId: string2().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/),
|
|
69863
70273
|
missionStatus: _enum(["completed", "failed"]),
|
|
69864
70274
|
destinationId: string2().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/),
|
|
69865
70275
|
channel: string2().regex(/^[a-z][a-z0-9-]{0,63}$/),
|
|
69866
|
-
reportHash:
|
|
69867
|
-
destinationHash:
|
|
70276
|
+
reportHash: hash3,
|
|
70277
|
+
destinationHash: hash3.optional(),
|
|
69868
70278
|
goal: string2().max(32000),
|
|
69869
70279
|
markdown: string2().max(256000),
|
|
69870
70280
|
reportPath: string2().max(4096),
|
|
@@ -69878,7 +70288,7 @@ var outboxRecordSchema = strictObject({
|
|
|
69878
70288
|
message: string2().max(1000)
|
|
69879
70289
|
}).refine((record) => record.nextPart <= record.parts && (record.status !== "delivered" || record.nextPart === record.parts));
|
|
69880
70290
|
function sha2562(content) {
|
|
69881
|
-
return
|
|
70291
|
+
return createHash17("sha256").update(content).digest("hex");
|
|
69882
70292
|
}
|
|
69883
70293
|
function receipt(record) {
|
|
69884
70294
|
const {
|
|
@@ -69896,12 +70306,12 @@ function receipt(record) {
|
|
|
69896
70306
|
class ReportOutbox {
|
|
69897
70307
|
directory;
|
|
69898
70308
|
constructor(stateDir) {
|
|
69899
|
-
this.directory =
|
|
70309
|
+
this.directory = join29(stateDir, "report-outbox");
|
|
69900
70310
|
}
|
|
69901
70311
|
path(id) {
|
|
69902
|
-
if (!
|
|
70312
|
+
if (!hash3.safeParse(id).success)
|
|
69903
70313
|
throw new Error("Invalid report receipt ID. Use av reports to find a receipt.");
|
|
69904
|
-
return
|
|
70314
|
+
return join29(this.directory, `${id}.json`);
|
|
69905
70315
|
}
|
|
69906
70316
|
lock(id) {
|
|
69907
70317
|
return new MissionStore(this.directory).lock(id);
|
|
@@ -69957,18 +70367,18 @@ async function verifiedAttachment(attachment, artifactRoot, readBytes) {
|
|
|
69957
70367
|
try {
|
|
69958
70368
|
const root = await realpath15(artifactRoot);
|
|
69959
70369
|
const path = await realpath15(attachment.path);
|
|
69960
|
-
const local =
|
|
69961
|
-
if (!local || local.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || local === ".." ||
|
|
70370
|
+
const local = relative10(root, path);
|
|
70371
|
+
if (!local || local.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || local === ".." || isAbsolute10(local))
|
|
69962
70372
|
throw failure;
|
|
69963
|
-
if (
|
|
70373
|
+
if (resolve17(attachment.path) !== attachment.path)
|
|
69964
70374
|
throw failure;
|
|
69965
|
-
const file = await
|
|
70375
|
+
const file = await open9(attachment.path, constants7.O_RDONLY | constants7.O_NOFOLLOW);
|
|
69966
70376
|
try {
|
|
69967
70377
|
const stat = await file.stat();
|
|
69968
70378
|
if (!stat.isFile() || stat.size !== attachment.sizeBytes)
|
|
69969
70379
|
throw failure;
|
|
69970
70380
|
if (!readBytes) {
|
|
69971
|
-
const digest =
|
|
70381
|
+
const digest = createHash17("sha256");
|
|
69972
70382
|
for await (const chunk of file.createReadStream({ autoClose: false }))
|
|
69973
70383
|
digest.update(chunk);
|
|
69974
70384
|
if (digest.digest("hex") !== attachment.sha256)
|
|
@@ -70015,7 +70425,7 @@ function dependencies(stateDir, overrides) {
|
|
|
70015
70425
|
env: overrides.env ?? process.env,
|
|
70016
70426
|
registry: { ...createReportChannelRegistry(fetch2), ...overrides.registry },
|
|
70017
70427
|
attachments: overrides.attachments ?? [],
|
|
70018
|
-
artifactRoot: overrides.artifactRoot ??
|
|
70428
|
+
artifactRoot: overrides.artifactRoot ?? join30(stateDir, "captures"),
|
|
70019
70429
|
now: overrides.now ?? (() => new Date)
|
|
70020
70430
|
};
|
|
70021
70431
|
}
|
|
@@ -70196,8 +70606,8 @@ init_chief_schema();
|
|
|
70196
70606
|
init_yaml_loader();
|
|
70197
70607
|
async function saveAndDeliverMissionReport(mission, root) {
|
|
70198
70608
|
const repository = mission.repositoryRoot ?? root;
|
|
70199
|
-
const directory =
|
|
70200
|
-
const reportPath =
|
|
70609
|
+
const directory = join31(root, ".agent-valley/reports");
|
|
70610
|
+
const reportPath = join31(directory, `${mission.id}.md`);
|
|
70201
70611
|
const report = renderReport(mission);
|
|
70202
70612
|
await mkdir15(directory, { recursive: true, mode: 448 });
|
|
70203
70613
|
await writeFile12(reportPath, report, { mode: 384 });
|
|
@@ -70212,12 +70622,12 @@ ${explanation.eli5}`);
|
|
|
70212
70622
|
try {
|
|
70213
70623
|
const config = mergeChiefConfig(loadGlobalConfig()?.chief, loadProjectConfig(root)?.chief);
|
|
70214
70624
|
const attachments = [...mission.capture?.attachments ?? []];
|
|
70215
|
-
const artifactRoot =
|
|
70625
|
+
const artifactRoot = join31(repository, ".agent-valley/captures");
|
|
70216
70626
|
if (config.reporting?.destinations.length) {
|
|
70217
70627
|
const bytes = Buffer.from(report);
|
|
70218
|
-
const sha256 =
|
|
70219
|
-
const reportDirectory =
|
|
70220
|
-
const attachmentPath =
|
|
70628
|
+
const sha256 = createHash18("sha256").update(bytes).digest("hex");
|
|
70629
|
+
const reportDirectory = join31(artifactRoot, mission.id);
|
|
70630
|
+
const attachmentPath = join31(reportDirectory, `report-${sha256}.md`);
|
|
70221
70631
|
await mkdir15(reportDirectory, { recursive: true, mode: 448 });
|
|
70222
70632
|
await writeFile12(attachmentPath, bytes, { mode: 384 });
|
|
70223
70633
|
attachments.push({
|
|
@@ -70228,7 +70638,7 @@ ${explanation.eli5}`);
|
|
|
70228
70638
|
sha256
|
|
70229
70639
|
});
|
|
70230
70640
|
}
|
|
70231
|
-
const receipts = await dispatchMissionReport(mission, report, reportPath, config.reporting,
|
|
70641
|
+
const receipts = await dispatchMissionReport(mission, report, reportPath, config.reporting, join31(repository, ".agent-valley"), {
|
|
70232
70642
|
attachments,
|
|
70233
70643
|
artifactRoot
|
|
70234
70644
|
});
|
|
@@ -70318,7 +70728,7 @@ function runWorker(args, root, signal) {
|
|
|
70318
70728
|
async function superviseOrder(goal, options, root, dependencies = {}) {
|
|
70319
70729
|
assertNotManagedRun();
|
|
70320
70730
|
const id = options.resume ?? options.missionId ?? randomUUID13();
|
|
70321
|
-
const store = new MissionStore(
|
|
70731
|
+
const store = new MissionStore(join32(root, ".agent-valley/missions"));
|
|
70322
70732
|
const controller = new AbortController;
|
|
70323
70733
|
const interrupt = () => controller.abort();
|
|
70324
70734
|
dependencies.signal?.addEventListener("abort", interrupt, { once: true });
|
|
@@ -70497,9 +70907,9 @@ Return one valid JSON object under the original charter and pinned evidence.` :
|
|
|
70497
70907
|
|
|
70498
70908
|
// ../../packages/core/src/chief/metric-source-adapters.ts
|
|
70499
70909
|
init_metric_source_policy();
|
|
70500
|
-
import { constants as
|
|
70501
|
-
import { lstat as lstat12, open as
|
|
70502
|
-
import { isAbsolute as
|
|
70910
|
+
import { constants as constants8 } from "node:fs";
|
|
70911
|
+
import { lstat as lstat12, open as open10, realpath as realpath16 } from "node:fs/promises";
|
|
70912
|
+
import { isAbsolute as isAbsolute11, relative as relative11, resolve as resolve18, sep as sep12 } from "node:path";
|
|
70503
70913
|
var MAX_METRIC_RESPONSE_BYTES = 2000000;
|
|
70504
70914
|
function metricSourceEnvironment(request, name) {
|
|
70505
70915
|
if (!name || !request.env[name]?.trim())
|
|
@@ -70584,19 +70994,19 @@ var jsonFileMetricAdapter = {
|
|
|
70584
70994
|
async collect(request) {
|
|
70585
70995
|
const root = await realpath16(request.repositoryRoot);
|
|
70586
70996
|
const name = request.source.file;
|
|
70587
|
-
if (!name ||
|
|
70997
|
+
if (!name || isAbsolute11(name))
|
|
70588
70998
|
throw new MetricSourceError("Metric file must be relative to the source repository. Set chief.metric_sources.sources[].file in av.yaml.");
|
|
70589
|
-
const path =
|
|
70590
|
-
const within =
|
|
70591
|
-
if (!within || within.startsWith(`..${
|
|
70999
|
+
const path = resolve18(root, name);
|
|
71000
|
+
const within = relative11(root, path);
|
|
71001
|
+
if (!within || within.startsWith(`..${sep12}`) || within === ".." || isAbsolute11(within))
|
|
70592
71002
|
throw new MetricSourceError("Metric file escapes the source repository. Choose a repository-relative JSON file.");
|
|
70593
71003
|
let current = root;
|
|
70594
|
-
for (const part of within.split(
|
|
70595
|
-
current =
|
|
71004
|
+
for (const part of within.split(sep12)) {
|
|
71005
|
+
current = resolve18(current, part);
|
|
70596
71006
|
if ((await lstat12(current)).isSymbolicLink())
|
|
70597
71007
|
throw new MetricSourceError("Metric file and parent directories must not be symlinks. Choose a regular JSON file inside the source repository.");
|
|
70598
71008
|
}
|
|
70599
|
-
const file = await
|
|
71009
|
+
const file = await open10(path, constants8.O_RDONLY | constants8.O_NOFOLLOW);
|
|
70600
71010
|
try {
|
|
70601
71011
|
const stat = await file.stat();
|
|
70602
71012
|
if (!stat.isFile() || stat.size > MAX_METRIC_RESPONSE_BYTES || await realpath16(path) !== path)
|
|
@@ -70997,9 +71407,9 @@ function createMissionMetricPorts(repository, mission, dependencies = {}) {
|
|
|
70997
71407
|
|
|
70998
71408
|
// src/chief-tool-config.ts
|
|
70999
71409
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
71000
|
-
import { constants as
|
|
71001
|
-
import { link as link2, lstat as lstat13, mkdir as mkdir16, open as
|
|
71002
|
-
import { join as
|
|
71410
|
+
import { constants as constants9 } from "node:fs";
|
|
71411
|
+
import { link as link2, lstat as lstat13, mkdir as mkdir16, open as open11, realpath as realpath17, unlink as unlink6 } from "node:fs/promises";
|
|
71412
|
+
import { join as join33 } from "node:path";
|
|
71003
71413
|
init_dist2();
|
|
71004
71414
|
init_client_toml();
|
|
71005
71415
|
var maximumBytes = 1024 * 1024;
|
|
@@ -71018,7 +71428,7 @@ async function assertLocalPath(root, local) {
|
|
|
71018
71428
|
const parts = local.split("/");
|
|
71019
71429
|
let current = root;
|
|
71020
71430
|
for (const [index, part] of parts.entries()) {
|
|
71021
|
-
current =
|
|
71431
|
+
current = join33(current, part);
|
|
71022
71432
|
const stats = await lstat13(current).catch((error) => {
|
|
71023
71433
|
if (error.code === "ENOENT")
|
|
71024
71434
|
return;
|
|
@@ -71032,7 +71442,7 @@ async function assertLocalPath(root, local) {
|
|
|
71032
71442
|
return true;
|
|
71033
71443
|
}
|
|
71034
71444
|
async function readPrivateFile(path) {
|
|
71035
|
-
const file = await
|
|
71445
|
+
const file = await open11(path, constants9.O_RDONLY | constants9.O_NOFOLLOW);
|
|
71036
71446
|
try {
|
|
71037
71447
|
const stats = await file.stat();
|
|
71038
71448
|
if (!stats.isFile() || stats.size > maximumBytes)
|
|
@@ -71075,9 +71485,9 @@ async function privateExclude(original, target, paths) {
|
|
|
71075
71485
|
]);
|
|
71076
71486
|
const common = targetCommon.trim();
|
|
71077
71487
|
const path = exclude.trim();
|
|
71078
|
-
if (common !==
|
|
71488
|
+
if (common !== join33(target, ".git") && common !== originalCommon.trim() || path !== join33(common, "info", "exclude") || await realpath17(common) !== common)
|
|
71079
71489
|
throw new ChiefToolConfigError("Chief MCP configuration requires the workspace's own Git metadata or its original repository's shared worktree metadata.");
|
|
71080
|
-
const info =
|
|
71490
|
+
const info = join33(common, "info");
|
|
71081
71491
|
const infoStats = await lstat13(info).catch((error) => {
|
|
71082
71492
|
if (error.code === "ENOENT")
|
|
71083
71493
|
return;
|
|
@@ -71095,7 +71505,7 @@ async function privateExclude(original, target, paths) {
|
|
|
71095
71505
|
const patterns = paths.flatMap((local) => [`/${local}`, `/${local}.av-mcp-*.tmp`]).filter((pattern) => !lines.has(pattern));
|
|
71096
71506
|
if (!patterns.length)
|
|
71097
71507
|
return;
|
|
71098
|
-
const file = await
|
|
71508
|
+
const file = await open11(path, constants9.O_WRONLY | constants9.O_APPEND | constants9.O_CREAT | constants9.O_NOFOLLOW, 384);
|
|
71099
71509
|
try {
|
|
71100
71510
|
await file.writeFile(`${content && !content.endsWith(`
|
|
71101
71511
|
`) ? `
|
|
@@ -71116,14 +71526,14 @@ async function prepareToolConfig(originalRepository, targetWorkspace) {
|
|
|
71116
71526
|
continue;
|
|
71117
71527
|
if (!await assertLocalPath(original, config.path))
|
|
71118
71528
|
continue;
|
|
71119
|
-
const content = selectedNamespace(await readPrivateFile(
|
|
71529
|
+
const content = selectedNamespace(await readPrivateFile(join33(original, config.path)), config.namespace, config.toml);
|
|
71120
71530
|
if (content)
|
|
71121
71531
|
selected.push({ path: config.path, content });
|
|
71122
71532
|
}
|
|
71123
71533
|
if (!selected.length)
|
|
71124
71534
|
return;
|
|
71125
71535
|
for (const root of [original, target]) {
|
|
71126
|
-
const stats = await lstat13(
|
|
71536
|
+
const stats = await lstat13(join33(root, ".git"));
|
|
71127
71537
|
if (stats.isSymbolicLink() || !stats.isFile() && !stats.isDirectory() || await realpath17((await parallelGit(root, ["rev-parse", "--show-toplevel"])).trim()) !== root)
|
|
71128
71538
|
throw new ChiefToolConfigError("Chief MCP tools require original local Git repository metadata. Restore the workspace before starting Chief.");
|
|
71129
71539
|
}
|
|
@@ -71131,16 +71541,16 @@ async function prepareToolConfig(originalRepository, targetWorkspace) {
|
|
|
71131
71541
|
for (const config of selected) {
|
|
71132
71542
|
const parts = config.path.split("/");
|
|
71133
71543
|
if (parts.length > 1) {
|
|
71134
|
-
const parent =
|
|
71544
|
+
const parent = join33(target, ...parts.slice(0, -1));
|
|
71135
71545
|
await mkdir16(parent, { recursive: true, mode: 448 });
|
|
71136
71546
|
if (await realpath17(parent) !== parent)
|
|
71137
71547
|
throw new ChiefToolConfigError("Chief MCP configuration parent redirects through a symlink. Restore its local directory.");
|
|
71138
71548
|
}
|
|
71139
71549
|
if (await assertLocalPath(target, config.path))
|
|
71140
71550
|
continue;
|
|
71141
|
-
const path =
|
|
71551
|
+
const path = join33(target, config.path);
|
|
71142
71552
|
const temporary = `${path}.av-mcp-${randomUUID14()}.tmp`;
|
|
71143
|
-
const file = await
|
|
71553
|
+
const file = await open11(temporary, "wx", 384);
|
|
71144
71554
|
try {
|
|
71145
71555
|
await file.writeFile(config.content);
|
|
71146
71556
|
} finally {
|
|
@@ -71169,10 +71579,10 @@ async function prepareChiefToolConfig(originalRepository, targetWorkspace) {
|
|
|
71169
71579
|
|
|
71170
71580
|
// src/tool-discovery.ts
|
|
71171
71581
|
init_client_toml();
|
|
71172
|
-
import { constants as
|
|
71582
|
+
import { constants as constants10 } from "node:fs";
|
|
71173
71583
|
import { access, lstat as lstat14, readFile as readFile12, realpath as realpath18 } from "node:fs/promises";
|
|
71174
|
-
import { homedir as
|
|
71175
|
-
import { delimiter as delimiter2, isAbsolute as
|
|
71584
|
+
import { homedir as homedir7 } from "node:os";
|
|
71585
|
+
import { delimiter as delimiter2, isAbsolute as isAbsolute12, join as join34, resolve as resolve19 } from "node:path";
|
|
71176
71586
|
var binaries = [
|
|
71177
71587
|
"docker",
|
|
71178
71588
|
"orb",
|
|
@@ -71188,10 +71598,10 @@ var binaries = [
|
|
|
71188
71598
|
var MAX_CONFIG_BYTES = 1048576;
|
|
71189
71599
|
var record4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
71190
71600
|
async function executable(name, env) {
|
|
71191
|
-
for (const directory of (env.PATH ?? "").split(delimiter2).filter(
|
|
71601
|
+
for (const directory of (env.PATH ?? "").split(delimiter2).filter(isAbsolute12)) {
|
|
71192
71602
|
try {
|
|
71193
|
-
const path =
|
|
71194
|
-
await access(path,
|
|
71603
|
+
const path = join34(directory, name);
|
|
71604
|
+
await access(path, constants10.X_OK);
|
|
71195
71605
|
if ((await lstat14(await realpath18(path))).isFile())
|
|
71196
71606
|
return true;
|
|
71197
71607
|
} catch {}
|
|
@@ -71244,7 +71654,7 @@ async function mcpNames(path, scope, project, requestedRoot) {
|
|
|
71244
71654
|
}
|
|
71245
71655
|
async function discoverTools(root, dependencies = {}) {
|
|
71246
71656
|
const env = dependencies.env ?? process.env;
|
|
71247
|
-
const home = dependencies.home ??
|
|
71657
|
+
const home = dependencies.home ?? homedir7();
|
|
71248
71658
|
const project = await realpath18(root);
|
|
71249
71659
|
const projectFiles = [
|
|
71250
71660
|
".mcp.json",
|
|
@@ -71255,11 +71665,11 @@ async function discoverTools(root, dependencies = {}) {
|
|
|
71255
71665
|
".codex/config.toml"
|
|
71256
71666
|
];
|
|
71257
71667
|
const userFiles = [".claude.json", ".cursor/mcp.json", ".qwen/settings.json", ".gemini/settings.json"];
|
|
71258
|
-
const codexHome = env.CODEX_HOME &&
|
|
71668
|
+
const codexHome = env.CODEX_HOME && isAbsolute12(env.CODEX_HOME) ? env.CODEX_HOME : join34(home, ".codex");
|
|
71259
71669
|
const configs = [
|
|
71260
|
-
...projectFiles.map((path) => ({ path:
|
|
71261
|
-
...userFiles.map((path) => ({ path:
|
|
71262
|
-
{ path:
|
|
71670
|
+
...projectFiles.map((path) => ({ path: join34(project, path), scope: "project" })),
|
|
71671
|
+
...userFiles.map((path) => ({ path: resolve19(home, path), scope: "user" })),
|
|
71672
|
+
{ path: join34(codexHome, "config.toml"), scope: "user" }
|
|
71263
71673
|
];
|
|
71264
71674
|
const [cli, mcp] = await Promise.all([
|
|
71265
71675
|
Promise.all(binaries.map(async (name) => ({
|
|
@@ -71271,7 +71681,7 @@ async function discoverTools(root, dependencies = {}) {
|
|
|
71271
71681
|
availability: await executable(name, env) ? "available" : "unavailable",
|
|
71272
71682
|
reason: "Executable presence only; service access, daemon state and login are unverified."
|
|
71273
71683
|
}))),
|
|
71274
|
-
Promise.all(configs.map(({ path, scope }) => mcpNames(path, scope, project,
|
|
71684
|
+
Promise.all(configs.map(({ path, scope }) => mcpNames(path, scope, project, resolve19(root))))
|
|
71275
71685
|
]);
|
|
71276
71686
|
return [...cli, ...mcp.flat()];
|
|
71277
71687
|
}
|
|
@@ -71306,7 +71716,7 @@ function continuousDecisionPrompt(operation, mission, tools, previousReport) {
|
|
|
71306
71716
|
async function decideContinuousGoal(operation, decisionId, root, dependencies = {}) {
|
|
71307
71717
|
if (!operation.baseline)
|
|
71308
71718
|
throw new Error("An accepted operation baseline is required before selecting a goal.");
|
|
71309
|
-
const store = new MissionStore(
|
|
71719
|
+
const store = new MissionStore(join35(root, ".agent-valley", "operation-decisions", operation.id));
|
|
71310
71720
|
const unlock = await store.lock(decisionId);
|
|
71311
71721
|
const runtime = (dependencies.runtime ?? ((storage, signal) => new ChiefRuntime(storage, signal)))(store, dependencies.signal);
|
|
71312
71722
|
let mission;
|
|
@@ -71415,7 +71825,7 @@ async function decideContinuousGoal(operation, decisionId, root, dependencies =
|
|
|
71415
71825
|
const previousId = operation.history.at(-1)?.missionId;
|
|
71416
71826
|
let previousReport;
|
|
71417
71827
|
if (previousId) {
|
|
71418
|
-
const previous = await new MissionStore(
|
|
71828
|
+
const previous = await new MissionStore(join35(root, ".agent-valley", "missions")).load(previousId);
|
|
71419
71829
|
if (previous.repositoryRoot !== operation.repositoryRoot || previous.status !== "completed")
|
|
71420
71830
|
throw new Error("The previous accepted child's evidence no longer matches this operation. Restore its saved checkpoint before selecting another goal.");
|
|
71421
71831
|
previousReport = renderReport(previous).slice(0, 16000);
|
|
@@ -71446,7 +71856,7 @@ async function decideContinuousGoal(operation, decisionId, root, dependencies =
|
|
|
71446
71856
|
}
|
|
71447
71857
|
|
|
71448
71858
|
// src/chief-continuous.ts
|
|
71449
|
-
var execute = promisify2(
|
|
71859
|
+
var execute = promisify2(execFile5);
|
|
71450
71860
|
var orderKeys = [
|
|
71451
71861
|
"workspace",
|
|
71452
71862
|
"verify",
|
|
@@ -71474,7 +71884,7 @@ function integerOption(value, name, maximum) {
|
|
|
71474
71884
|
return number;
|
|
71475
71885
|
}
|
|
71476
71886
|
function operationStore(root) {
|
|
71477
|
-
return new ContinuousOperationStore(
|
|
71887
|
+
return new ContinuousOperationStore(join36(resolve20(root), ".agent-valley", "operations"));
|
|
71478
71888
|
}
|
|
71479
71889
|
async function restoreOperationOrigin(repository, workspace) {
|
|
71480
71890
|
const env = { ...process.env, ...clearedGitEnvironment };
|
|
@@ -71530,7 +71940,7 @@ async function newOperation(charter, options, root, id) {
|
|
|
71530
71940
|
...config.executionPolicy.maxEstimatedCostUsd !== undefined ? { cost: String(config.executionPolicy.maxEstimatedCostUsd) } : {}
|
|
71531
71941
|
});
|
|
71532
71942
|
if (typeof settings.actors === "string")
|
|
71533
|
-
settings.actors =
|
|
71943
|
+
settings.actors = resolve20(root, settings.actors);
|
|
71534
71944
|
const now = new Date().toISOString();
|
|
71535
71945
|
return operationSchema.parse({
|
|
71536
71946
|
id,
|
|
@@ -71592,9 +72002,9 @@ function renderOperationReport(operation) {
|
|
|
71592
72002
|
`);
|
|
71593
72003
|
}
|
|
71594
72004
|
async function saveOperationReport(root, operation) {
|
|
71595
|
-
const directory =
|
|
72005
|
+
const directory = join36(root, ".agent-valley", "operation-reports");
|
|
71596
72006
|
await mkdir17(directory, { recursive: true, mode: 448 });
|
|
71597
|
-
const path =
|
|
72007
|
+
const path = join36(directory, `${operation.id}.md`);
|
|
71598
72008
|
const temporary = `${path}.${randomUUID15()}.tmp`;
|
|
71599
72009
|
try {
|
|
71600
72010
|
await writeFile13(temporary, renderOperationReport(operation), { mode: 384, flag: "wx" });
|
|
@@ -71629,7 +72039,7 @@ async function runOperation(charter, options, root = process.cwd(), dependencies
|
|
|
71629
72039
|
if (decisionBudgetKeys.some((key) => options[key] !== undefined)) {
|
|
71630
72040
|
if (operation.currentMissionId || !operation.decisionId)
|
|
71631
72041
|
throw new Error("Operation resume budget reconciliation applies only to an active decision checkpoint. Adjust the current child's budget with av order --resume <child-id>.");
|
|
71632
|
-
const decisions = new MissionStore(
|
|
72042
|
+
const decisions = new MissionStore(join36(root, ".agent-valley", "operation-decisions", operation.id));
|
|
71633
72043
|
const unlockDecision = await decisions.lock(operation.decisionId);
|
|
71634
72044
|
try {
|
|
71635
72045
|
const decision = await decisions.load(operation.decisionId);
|
|
@@ -71675,7 +72085,7 @@ async function runOperation(charter, options, root = process.cwd(), dependencies
|
|
|
71675
72085
|
console.log(`Operation ${id}
|
|
71676
72086
|
Charter: ${operation.charter}
|
|
71677
72087
|
Resume: av order --resume ${id}`);
|
|
71678
|
-
const missions = new MissionStore(
|
|
72088
|
+
const missions = new MissionStore(join36(root, ".agent-valley", "missions"));
|
|
71679
72089
|
return await runContinuousOperation(operation, {
|
|
71680
72090
|
signal: controller.signal,
|
|
71681
72091
|
...dependencies.now ? { now: dependencies.now } : {},
|
|
@@ -71783,7 +72193,7 @@ class OperationApi {
|
|
|
71783
72193
|
this.root = root;
|
|
71784
72194
|
this.workspace = workspace;
|
|
71785
72195
|
this.dependencies = dependencies;
|
|
71786
|
-
this.store = new ContinuousOperationStore(
|
|
72196
|
+
this.store = new ContinuousOperationStore(join37(root, ".agent-valley/operations"));
|
|
71787
72197
|
this.jobs = new MissionJobs(root, "operation-jobs");
|
|
71788
72198
|
}
|
|
71789
72199
|
order(raw) {
|
|
@@ -72021,17 +72431,17 @@ class MissionApi {
|
|
|
72021
72431
|
this.projectRoot = projectRoot;
|
|
72022
72432
|
this.workspace = workspace;
|
|
72023
72433
|
this.dependencies = dependencies;
|
|
72024
|
-
this.store = new MissionStore(
|
|
72434
|
+
this.store = new MissionStore(join38(projectRoot, ".agent-valley/missions"));
|
|
72025
72435
|
this.jobs = new MissionJobs(projectRoot);
|
|
72026
72436
|
this.operationApi = new OperationApi(projectRoot, workspace, dependencies);
|
|
72027
72437
|
this.operationJobs = new MissionJobs(projectRoot, "operation-jobs");
|
|
72028
72438
|
}
|
|
72029
72439
|
static async create(workspace, dependencies = {}) {
|
|
72030
|
-
if (!
|
|
72440
|
+
if (!isAbsolute13(workspace))
|
|
72031
72441
|
throw new Error("Set an absolute Git repository path in av mcp --workspace <path>.");
|
|
72032
72442
|
const projectRoot = await realpath21(workspace);
|
|
72033
72443
|
const target = loadProjectConfig(projectRoot)?.workspace?.root ?? projectRoot;
|
|
72034
|
-
if (!
|
|
72444
|
+
if (!isAbsolute13(target))
|
|
72035
72445
|
throw new Error("Set workspace.root in av.yaml to an absolute Git repository path.");
|
|
72036
72446
|
return new MissionApi(projectRoot, await realpath21(target), dependencies);
|
|
72037
72447
|
}
|
|
@@ -72060,7 +72470,7 @@ class MissionApi {
|
|
|
72060
72470
|
async order(raw) {
|
|
72061
72471
|
assertNotManagedRun(this.dependencies.env);
|
|
72062
72472
|
const input = mcpOrderSchema.parse(raw);
|
|
72063
|
-
if (input.workspace && (!
|
|
72473
|
+
if (input.workspace && (!isAbsolute13(input.workspace) || await realpath21(input.workspace) !== this.workspace))
|
|
72064
72474
|
throw new Error("This AV server is bound to another workspace. Start av mcp --workspace for the target repository.");
|
|
72065
72475
|
return this.serializeOrder(async () => {
|
|
72066
72476
|
if (input.requestId) {
|
|
@@ -72083,7 +72493,7 @@ class MissionApi {
|
|
|
72083
72493
|
async list() {
|
|
72084
72494
|
this.assertOpen();
|
|
72085
72495
|
await ensureAvDirectory(this.projectRoot, ["missions"]);
|
|
72086
|
-
const ids = new Set((await readdir8(
|
|
72496
|
+
const ids = new Set((await readdir8(join38(this.projectRoot, ".agent-valley/missions"))).filter((name) => name.endsWith(".json")).map((name) => missionIdSchema.parse(name.slice(0, -5))));
|
|
72087
72497
|
for (const job of await this.jobs.list())
|
|
72088
72498
|
ids.add(job.missionId);
|
|
72089
72499
|
return {
|
|
@@ -72237,7 +72647,7 @@ class MissionApi {
|
|
|
72237
72647
|
async load(id) {
|
|
72238
72648
|
await ensureAvDirectory(this.projectRoot, ["missions"]);
|
|
72239
72649
|
try {
|
|
72240
|
-
const path =
|
|
72650
|
+
const path = join38(this.projectRoot, ".agent-valley/missions", `${missionIdSchema.parse(id)}.json`);
|
|
72241
72651
|
const stat = await lstat15(path);
|
|
72242
72652
|
if (!stat.isFile() || stat.isSymbolicLink())
|
|
72243
72653
|
throw new Error(`Mission record must be a regular file: ${path}. Remove the symlink before retrying.`);
|
|
@@ -72263,7 +72673,7 @@ class MissionApi {
|
|
|
72263
72673
|
init_client_integrations_assets();
|
|
72264
72674
|
init_client_integrations_files();
|
|
72265
72675
|
import { lstat as lstat16, readdir as readdir9, realpath as realpath22 } from "node:fs/promises";
|
|
72266
|
-
import { dirname as
|
|
72676
|
+
import { dirname as dirname8, join as join39, relative as relative12, resolve as resolve21 } from "node:path";
|
|
72267
72677
|
|
|
72268
72678
|
// src/plugin-assets.ts
|
|
72269
72679
|
import { copyFile as copyFile2, mkdir as mkdir18, readFile as readFile13 } from "node:fs/promises";
|
|
@@ -72430,7 +72840,7 @@ async function projectDirectory(workspace) {
|
|
|
72430
72840
|
if (typeof workspace !== "string" || !workspace.trim())
|
|
72431
72841
|
throw new Error("Pass --workspace /absolute/AV-project to bind every exported MCP server to its AV configuration.");
|
|
72432
72842
|
try {
|
|
72433
|
-
const project = await realpath22(
|
|
72843
|
+
const project = await realpath22(resolve21(workspace));
|
|
72434
72844
|
if (!(await lstat16(project)).isDirectory())
|
|
72435
72845
|
throw new Error("not a directory");
|
|
72436
72846
|
return project;
|
|
@@ -72453,7 +72863,7 @@ function remoteEndpoint(value) {
|
|
|
72453
72863
|
async function outputDirectory(output) {
|
|
72454
72864
|
if (typeof output !== "string" || !output.trim())
|
|
72455
72865
|
throw new Error("Pass --output /absolute/export-directory to write the generated AV plugin packages.");
|
|
72456
|
-
const target =
|
|
72866
|
+
const target = resolve21(output);
|
|
72457
72867
|
let ancestor = target;
|
|
72458
72868
|
for (;; ) {
|
|
72459
72869
|
try {
|
|
@@ -72462,11 +72872,11 @@ async function outputDirectory(output) {
|
|
|
72462
72872
|
throw exportConflict(ancestor, "symbolic link exports are not modified");
|
|
72463
72873
|
if (!info.isDirectory())
|
|
72464
72874
|
throw exportConflict(ancestor, "expected an output directory");
|
|
72465
|
-
return
|
|
72875
|
+
return join39(await realpath22(ancestor), relative12(ancestor, target));
|
|
72466
72876
|
} catch (error) {
|
|
72467
72877
|
if (error.code !== "ENOENT")
|
|
72468
72878
|
throw error;
|
|
72469
|
-
ancestor =
|
|
72879
|
+
ancestor = dirname8(ancestor);
|
|
72470
72880
|
}
|
|
72471
72881
|
}
|
|
72472
72882
|
}
|
|
@@ -72481,13 +72891,13 @@ async function outputFiles(root, directory = root) {
|
|
|
72481
72891
|
}
|
|
72482
72892
|
const files = [];
|
|
72483
72893
|
for (const entry of entries) {
|
|
72484
|
-
const path =
|
|
72894
|
+
const path = join39(directory, entry.name);
|
|
72485
72895
|
if (entry.isSymbolicLink())
|
|
72486
72896
|
throw exportConflict(path, "symbolic links are not modified");
|
|
72487
72897
|
if (entry.isDirectory())
|
|
72488
72898
|
files.push(...await outputFiles(root, path));
|
|
72489
72899
|
else if (entry.isFile())
|
|
72490
|
-
files.push(
|
|
72900
|
+
files.push(relative12(root, path).split("\\").join("/"));
|
|
72491
72901
|
else
|
|
72492
72902
|
throw exportConflict(path, "expected regular export files");
|
|
72493
72903
|
}
|
|
@@ -72518,21 +72928,21 @@ async function exportPluginPackages(options) {
|
|
|
72518
72928
|
if (output === workspace)
|
|
72519
72929
|
throw exportConflict(output, "the output directory must be separate from the AV project root");
|
|
72520
72930
|
const { manifest } = await loadPluginManifestAsset(options.sourceManifest ? [options.sourceManifest] : undefined);
|
|
72521
|
-
const { content: skill } = await loadClientSkillAsset(options.sourceSkillRoot ? [
|
|
72931
|
+
const { content: skill } = await loadClientSkillAsset(options.sourceSkillRoot ? [join39(options.sourceSkillRoot, "SKILL.md")] : clientSkillAssetCandidates());
|
|
72522
72932
|
const { content: license } = await loadPluginLicenseAsset(options.sourceLicense ? [options.sourceLicense] : undefined);
|
|
72523
72933
|
const packageFiles = pluginPackageFiles(manifest, skill, license, { workspace, remoteUrl });
|
|
72524
|
-
const receipt = await integrationFile(output,
|
|
72934
|
+
const receipt = await integrationFile(output, join39(output, receiptName2), "", 384);
|
|
72525
72935
|
const hashes = ownedFileHashes(receipt.before, receipt.path);
|
|
72526
72936
|
const existing = await outputFiles(output);
|
|
72527
72937
|
for (const path of existing) {
|
|
72528
72938
|
if (path === receiptName2)
|
|
72529
72939
|
continue;
|
|
72530
72940
|
if (!packageFiles.has(path) || hashes[path] === undefined)
|
|
72531
|
-
throw exportConflict(
|
|
72941
|
+
throw exportConflict(join39(output, path), "unowned files are retained");
|
|
72532
72942
|
}
|
|
72533
72943
|
const files = [];
|
|
72534
72944
|
for (const [path, content] of packageFiles) {
|
|
72535
|
-
const file = await integrationFile(output,
|
|
72945
|
+
const file = await integrationFile(output, join39(output, path), content, 420);
|
|
72536
72946
|
if (hashes[path] !== undefined && (file.before === null || contentHash(file.before) !== hashes[path]))
|
|
72537
72947
|
throw exportConflict(file.path, "the exported file was changed or removed locally");
|
|
72538
72948
|
if (hashes[path] === undefined && file.before !== null)
|
|
@@ -72551,11 +72961,11 @@ async function exportPluginPackages(options) {
|
|
|
72551
72961
|
transport: remoteUrl ? "streamable-http" : "stdio",
|
|
72552
72962
|
files: await applyIntegrationFiles(output, [...files, receipt]),
|
|
72553
72963
|
packages: {
|
|
72554
|
-
portable:
|
|
72555
|
-
claude:
|
|
72556
|
-
cursor:
|
|
72557
|
-
qwen:
|
|
72558
|
-
antigravity:
|
|
72964
|
+
portable: join39(output, "portable/av"),
|
|
72965
|
+
claude: join39(output, "claude/plugins/av"),
|
|
72966
|
+
cursor: join39(output, "cursor/plugins/av"),
|
|
72967
|
+
qwen: join39(output, "qwen/av"),
|
|
72968
|
+
antigravity: join39(output, "antigravity/av")
|
|
72559
72969
|
}
|
|
72560
72970
|
};
|
|
72561
72971
|
}
|
|
@@ -72588,7 +72998,7 @@ function registerAgentClientCommands(program) {
|
|
|
72588
72998
|
].some((value) => value !== undefined))
|
|
72589
72999
|
throw new Error("OAuth gateway options require av mcp --http. Omit them to use local stdio.");
|
|
72590
73000
|
const oauth = options.http ? resolveMcpOAuthOptions(options) : undefined;
|
|
72591
|
-
const project =
|
|
73001
|
+
const project = resolve22(options.workspace);
|
|
72592
73002
|
const api = await MissionApi.create(project);
|
|
72593
73003
|
const workspace = api.targetWorkspace;
|
|
72594
73004
|
try {
|
|
@@ -72618,7 +73028,7 @@ function registerAgentClientCommands(program) {
|
|
|
72618
73028
|
// src/chief.ts
|
|
72619
73029
|
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
72620
73030
|
import { realpath as realpath23 } from "node:fs/promises";
|
|
72621
|
-
import { join as
|
|
73031
|
+
import { join as join41 } from "node:path";
|
|
72622
73032
|
|
|
72623
73033
|
// ../../packages/core/src/chief/coordinator-container.ts
|
|
72624
73034
|
init_execution();
|
|
@@ -73135,7 +73545,7 @@ function selectTaskReviewer(mission, task, state) {
|
|
|
73135
73545
|
}
|
|
73136
73546
|
|
|
73137
73547
|
// ../../packages/core/src/chief/coordinator.ts
|
|
73138
|
-
var
|
|
73548
|
+
var bounded3 = (value) => value.slice(-32000);
|
|
73139
73549
|
async function coordinate(mission, ports) {
|
|
73140
73550
|
Object.assign(mission, validateMission(mission));
|
|
73141
73551
|
const operatorGoal = mission.goal;
|
|
@@ -73199,7 +73609,7 @@ async function coordinate(mission, ports) {
|
|
|
73199
73609
|
if (task.effectScope === "external" && state.effectState === "unknown")
|
|
73200
73610
|
throw new MissionPause(`External effect ${task.id} has no established destination outcome and will not be repeated.`, "unknown-effect");
|
|
73201
73611
|
if (task.effectScope !== "external" || state.effectState !== "completed") {
|
|
73202
|
-
state.output =
|
|
73612
|
+
state.output = bounded3(await run(persona(task.personaId), workPrompt(mission, task, state, persona(task.personaId)), "work", task.id));
|
|
73203
73613
|
if (task.effectScope === "external")
|
|
73204
73614
|
state.effectState = "completed";
|
|
73205
73615
|
}
|
|
@@ -73373,7 +73783,7 @@ async function coordinate(mission, ports) {
|
|
|
73373
73783
|
mission.fingerprint = await ports.fingerprint(mission);
|
|
73374
73784
|
mission.verification = {
|
|
73375
73785
|
ok: result.ok,
|
|
73376
|
-
output: result.output ?
|
|
73786
|
+
output: result.output ? bounded3(result.output) : undefined,
|
|
73377
73787
|
fingerprint: mission.fingerprint
|
|
73378
73788
|
};
|
|
73379
73789
|
if (mission.verificationMode === "chief" && !mission.goalVerification?.ok) {
|
|
@@ -73472,7 +73882,7 @@ async function coordinate(mission, ports) {
|
|
|
73472
73882
|
return mission;
|
|
73473
73883
|
}
|
|
73474
73884
|
mission.status = "failed";
|
|
73475
|
-
mission.error =
|
|
73885
|
+
mission.error = bounded3(error instanceof Error ? error.message : String(error));
|
|
73476
73886
|
if (error instanceof ReadOnlyViolation || error instanceof ContractViolation || error instanceof CheckpointError)
|
|
73477
73887
|
executionState(mission).failureKind = "integrity";
|
|
73478
73888
|
if (error instanceof ReadOnlyViolation)
|
|
@@ -73489,7 +73899,7 @@ async function coordinate(mission, ports) {
|
|
|
73489
73899
|
if (reportError instanceof ReadOnlyViolation) {
|
|
73490
73900
|
executionState(mission).failureKind = "integrity";
|
|
73491
73901
|
invalidate();
|
|
73492
|
-
mission.error =
|
|
73902
|
+
mission.error = bounded3(`${mission.error}
|
|
73493
73903
|
${reportError.message}`);
|
|
73494
73904
|
mission.report = fallbackReport(mission);
|
|
73495
73905
|
}
|
|
@@ -73506,14 +73916,14 @@ init_execution();
|
|
|
73506
73916
|
|
|
73507
73917
|
// ../../packages/core/src/workspace/delivery-strategy.ts
|
|
73508
73918
|
init_logger();
|
|
73509
|
-
import { lstatSync as
|
|
73919
|
+
import { lstatSync as lstatSync4 } from "node:fs";
|
|
73510
73920
|
|
|
73511
73921
|
// ../../packages/core/src/workspace/isolated-branch-import.ts
|
|
73512
73922
|
init_worktree_lifecycle();
|
|
73513
73923
|
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
73514
73924
|
import { mkdtemp, rm as rm5 } from "node:fs/promises";
|
|
73515
73925
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
73516
|
-
import { join as
|
|
73926
|
+
import { join as join40 } from "node:path";
|
|
73517
73927
|
async function importIsolatedBranch(workspace, root) {
|
|
73518
73928
|
if (!isIsolatedGitWorkspace(workspace))
|
|
73519
73929
|
return null;
|
|
@@ -73560,7 +73970,7 @@ async function importIsolatedBranch(workspace, root) {
|
|
|
73560
73970
|
`).filter(Boolean);
|
|
73561
73971
|
if (commits.length === 0)
|
|
73562
73972
|
return null;
|
|
73563
|
-
temporaryWorktree = await mkdtemp(
|
|
73973
|
+
temporaryWorktree = await mkdtemp(join40(tmpdir3(), "av-branch-import-"));
|
|
73564
73974
|
const added = await runCommand("git", ["worktree", "add", "--detach", temporaryWorktree, currentHead], {
|
|
73565
73975
|
cwd: root
|
|
73566
73976
|
});
|
|
@@ -73833,7 +74243,7 @@ function gitFailure(action, result, fix) {
|
|
|
73833
74243
|
}
|
|
73834
74244
|
function linkedWorktreePath(workspace) {
|
|
73835
74245
|
try {
|
|
73836
|
-
return
|
|
74246
|
+
return lstatSync4(`${workspace.path}/.git`).isFile() ? workspace.path : null;
|
|
73837
74247
|
} catch {
|
|
73838
74248
|
return null;
|
|
73839
74249
|
}
|
|
@@ -74140,7 +74550,7 @@ async function runOrder(goal, options, root = process.cwd()) {
|
|
|
74140
74550
|
assertNotManagedRun();
|
|
74141
74551
|
if (!options.resume && [options.retry, options.resolveEffect, options.effectResult, options.accountRun, options.accountCost].some((value) => value !== undefined && value !== false))
|
|
74142
74552
|
throw new Error("Use --resume <id> for retry, external-effect resolution or cost reconciliation.");
|
|
74143
|
-
const store = new MissionStore(
|
|
74553
|
+
const store = new MissionStore(join41(root, ".agent-valley/missions"));
|
|
74144
74554
|
const id = options.resume ?? options.missionId ?? randomUUID19();
|
|
74145
74555
|
const unlock = await store.lock(id);
|
|
74146
74556
|
const abortController = new AbortController;
|
|
@@ -74318,7 +74728,7 @@ async function dispatchOrder(goal, options, root = process.cwd(), dependencies =
|
|
|
74318
74728
|
};
|
|
74319
74729
|
const [operation, mission] = await Promise.all([
|
|
74320
74730
|
operationStore(root).load(options.resume).catch(missing),
|
|
74321
|
-
new MissionStore(
|
|
74731
|
+
new MissionStore(join41(root, ".agent-valley", "missions")).load(options.resume).catch(missing)
|
|
74322
74732
|
]);
|
|
74323
74733
|
if (operation && mission)
|
|
74324
74734
|
throw new Error(`Saved ID ${options.resume} names both an operation and a mission. Use --once to resume the mission; inspect av operations before resuming the operation.`);
|
|
@@ -74376,7 +74786,7 @@ function registerChiefCommands(program) {
|
|
|
74376
74786
|
process.once("SIGTERM", stop);
|
|
74377
74787
|
try {
|
|
74378
74788
|
while (!controller.signal.aborted) {
|
|
74379
|
-
const store = new MissionStore(
|
|
74789
|
+
const store = new MissionStore(join41(process.cwd(), ".agent-valley/missions"));
|
|
74380
74790
|
for (const mission of await store.list()) {
|
|
74381
74791
|
if (controller.signal.aborted)
|
|
74382
74792
|
break;
|
|
@@ -74399,7 +74809,7 @@ function registerChiefCommands(program) {
|
|
|
74399
74809
|
}
|
|
74400
74810
|
return;
|
|
74401
74811
|
}
|
|
74402
|
-
const missions = await new MissionStore(
|
|
74812
|
+
const missions = await new MissionStore(join41(process.cwd(), ".agent-valley/missions")).list();
|
|
74403
74813
|
if (!missions.length)
|
|
74404
74814
|
console.log("No orders yet. Run bun av order --help.");
|
|
74405
74815
|
for (const mission of missions) {
|
|
@@ -74412,17 +74822,17 @@ function registerChiefCommands(program) {
|
|
|
74412
74822
|
|
|
74413
74823
|
// src/chief-organization.ts
|
|
74414
74824
|
import { readFile as readFile15, stat as stat2 } from "node:fs/promises";
|
|
74415
|
-
import { isAbsolute as
|
|
74825
|
+
import { isAbsolute as isAbsolute14, join as join42, resolve as resolve23 } from "node:path";
|
|
74416
74826
|
init_chief_schema();
|
|
74417
74827
|
init_yaml_loader();
|
|
74418
74828
|
function organizationRepository(root, workspace) {
|
|
74419
74829
|
const repository = workspace ?? loadProjectConfig(root)?.workspace?.root ?? root;
|
|
74420
|
-
if (!
|
|
74830
|
+
if (!isAbsolute14(repository))
|
|
74421
74831
|
throw new Error("Set workspace.root in av.yaml or --workspace to an absolute source repository path.");
|
|
74422
74832
|
return repository;
|
|
74423
74833
|
}
|
|
74424
74834
|
async function inputFile(file) {
|
|
74425
|
-
const path =
|
|
74835
|
+
const path = resolve23(file);
|
|
74426
74836
|
const info = await stat2(path);
|
|
74427
74837
|
if (!info.isFile() || info.size > 2000000)
|
|
74428
74838
|
throw new Error("Use a regular JSON input file no larger than 2 MB.");
|
|
@@ -74466,22 +74876,22 @@ function registerOrganizationCommands(program) {
|
|
|
74466
74876
|
});
|
|
74467
74877
|
const reports = program.command("reports").description("Inspect and retry third-party report attachments");
|
|
74468
74878
|
reports.command("list").option("--workspace <path>", "Source repository").action(async (opts) => {
|
|
74469
|
-
console.log(JSON.stringify(await listReportDeliveries(
|
|
74879
|
+
console.log(JSON.stringify(await listReportDeliveries(join42(organizationRepository(process.cwd(), opts.workspace), ".agent-valley")), null, 2));
|
|
74470
74880
|
});
|
|
74471
74881
|
reports.command("retry").option("--workspace <path>", "Source repository").action(async (opts) => {
|
|
74472
74882
|
const config = mergeChiefConfig(loadGlobalConfig()?.chief, loadProjectConfig()?.chief);
|
|
74473
74883
|
if (!config.reporting)
|
|
74474
74884
|
throw new Error("Set chief.reporting.destinations in av.yaml before retrying reports.");
|
|
74475
|
-
console.log(JSON.stringify(await retryPendingReports(config.reporting,
|
|
74885
|
+
console.log(JSON.stringify(await retryPendingReports(config.reporting, join42(organizationRepository(process.cwd(), opts.workspace), ".agent-valley")), null, 2));
|
|
74476
74886
|
});
|
|
74477
74887
|
}
|
|
74478
74888
|
|
|
74479
74889
|
// src/config-watch.ts
|
|
74480
74890
|
init_project_config_path();
|
|
74481
|
-
import { resolve as
|
|
74891
|
+
import { resolve as resolve26 } from "node:path";
|
|
74482
74892
|
async function watchConfig(root, globalPath, onChange) {
|
|
74483
74893
|
await Promise.resolve().then(() => init_chokidar());
|
|
74484
|
-
const watcher = watch([
|
|
74894
|
+
const watcher = watch([resolve26(root, PROJECT_CONFIG_FILENAME), globalPath], { ignoreInitial: true });
|
|
74485
74895
|
watcher.on("all", (event, path) => {
|
|
74486
74896
|
if (["add", "change", "unlink"].includes(event))
|
|
74487
74897
|
onChange(path);
|
|
@@ -74497,10 +74907,10 @@ var import_picocolors = __toESM(require_picocolors(), 1);
|
|
|
74497
74907
|
init_project_config_path();
|
|
74498
74908
|
init_yaml_loader();
|
|
74499
74909
|
init_doctor_checks();
|
|
74500
|
-
import { join as
|
|
74910
|
+
import { join as join46 } from "node:path";
|
|
74501
74911
|
|
|
74502
74912
|
// src/doctor-oma-checks.ts
|
|
74503
|
-
import { join as
|
|
74913
|
+
import { join as join45 } from "node:path";
|
|
74504
74914
|
function checkOma(project, deps) {
|
|
74505
74915
|
const strict = project?.oma?.mode === "strict";
|
|
74506
74916
|
const order = !!project && !project.tracker && !project.linear && !project.github;
|
|
@@ -74588,7 +74998,7 @@ function checkOma(project, deps) {
|
|
|
74588
74998
|
fix: "Set verify.command to a deterministic non-build check in av.yaml before using oma.mode: strict.",
|
|
74589
74999
|
critical: true
|
|
74590
75000
|
});
|
|
74591
|
-
const triggerPath =
|
|
75001
|
+
const triggerPath = join45(deps.cwd, ".agents", "hooks", "core", "triggers.json");
|
|
74592
75002
|
let table = null;
|
|
74593
75003
|
try {
|
|
74594
75004
|
table = parseTriggerTable(deps.readFileSync(triggerPath));
|
|
@@ -74605,7 +75015,7 @@ function checkOma(project, deps) {
|
|
|
74605
75015
|
return results;
|
|
74606
75016
|
}
|
|
74607
75017
|
results.push({ id: "oma.triggers", name: "OMA trigger table", status: "pass", message: triggerPath, critical: false });
|
|
74608
|
-
const missing = Object.entries(table.workflows).filter(([name, workflow]) => !workflow.persistent && !table.excludedWorkflows.includes(name)).map(([name]) =>
|
|
75018
|
+
const missing = Object.entries(table.workflows).filter(([name, workflow]) => !workflow.persistent && !table.excludedWorkflows.includes(name)).map(([name]) => join45(deps.cwd, ".agents", "workflows", `${name}.md`)).filter((path) => !deps.existsSync(path));
|
|
74609
75019
|
results.push(missing.length === 0 ? {
|
|
74610
75020
|
id: "oma.workflows",
|
|
74611
75021
|
name: "OMA workflow files",
|
|
@@ -74623,6 +75033,37 @@ function checkOma(project, deps) {
|
|
|
74623
75033
|
return results;
|
|
74624
75034
|
}
|
|
74625
75035
|
|
|
75036
|
+
// src/doctor-skill-matrix-checks.ts
|
|
75037
|
+
import { resolve as resolve27 } from "node:path";
|
|
75038
|
+
async function checkSkillMatrix(project, global2, deps) {
|
|
75039
|
+
const config = project?.oma?.skill_compatibility;
|
|
75040
|
+
if (!config)
|
|
75041
|
+
return [];
|
|
75042
|
+
const projectActor = project?.actor ?? project?.agent;
|
|
75043
|
+
const globalActor = global2?.actor ?? global2?.agent;
|
|
75044
|
+
const actorType = projectActor?.type ?? globalActor?.type ?? "claude";
|
|
75045
|
+
const model = projectActor?.model ?? (globalActor?.type === actorType ? globalActor.model : undefined);
|
|
75046
|
+
const inspection = await inspectSkillCompatibility({
|
|
75047
|
+
reportPath: resolve27(deps.cwd, config.report_path),
|
|
75048
|
+
maxAgeHours: config.max_age_hours,
|
|
75049
|
+
mode: config.mode
|
|
75050
|
+
}, resolve27(deps.cwd, project?.workspace?.root ?? "."), undefined, [{ actorType, model }], deps.skillMatrix);
|
|
75051
|
+
const route = inspection.routes[0];
|
|
75052
|
+
const status = route?.status ?? "unknown";
|
|
75053
|
+
return [
|
|
75054
|
+
{
|
|
75055
|
+
id: "oma.skill-compatibility",
|
|
75056
|
+
name: "OMA skill read-reference compatibility",
|
|
75057
|
+
status,
|
|
75058
|
+
message: `${config.mode}: ${actorType}/${model ?? "native default"}: ${route?.reason ?? "Evidence unavailable."} Scope: ${inspection.scope}. Work dispatch rechecks its own selected skills and candidates.`,
|
|
75059
|
+
...status !== "pass" ? {
|
|
75060
|
+
fix: "Generate a completed installed injected matrix with explicit models and set oma.skill_compatibility.report_path in av.yaml. av doctor never runs a live matrix."
|
|
75061
|
+
} : {},
|
|
75062
|
+
critical: config.mode === "require"
|
|
75063
|
+
}
|
|
75064
|
+
];
|
|
75065
|
+
}
|
|
75066
|
+
|
|
74626
75067
|
// src/doctor-config-checks.ts
|
|
74627
75068
|
function checkTunnel(project, deps) {
|
|
74628
75069
|
const provider = project?.tunnel?.provider ?? "ngrok";
|
|
@@ -74649,7 +75090,7 @@ function checkTunnel(project, deps) {
|
|
|
74649
75090
|
}
|
|
74650
75091
|
const mode = project?.tunnel?.cloudflare?.mode ?? "quick";
|
|
74651
75092
|
if (mode === "named") {
|
|
74652
|
-
const certPath =
|
|
75093
|
+
const certPath = join46(deps.home, ".cloudflared", "cert.pem");
|
|
74653
75094
|
if (!deps.existsSync(certPath)) {
|
|
74654
75095
|
return {
|
|
74655
75096
|
id: "tunnel",
|
|
@@ -74689,7 +75130,7 @@ function checkTunnel(project, deps) {
|
|
|
74689
75130
|
critical: false
|
|
74690
75131
|
};
|
|
74691
75132
|
}
|
|
74692
|
-
const ngrokConfigPath = deps.platform === "darwin" ?
|
|
75133
|
+
const ngrokConfigPath = deps.platform === "darwin" ? join46(deps.home, "Library", "Application Support", "ngrok", "ngrok.yml") : join46(deps.home, ".config", "ngrok", "ngrok.yml");
|
|
74693
75134
|
if (!deps.existsSync(ngrokConfigPath)) {
|
|
74694
75135
|
return {
|
|
74695
75136
|
id: "tunnel",
|
|
@@ -74760,7 +75201,7 @@ function checkConfig(deps) {
|
|
|
74760
75201
|
critical: true
|
|
74761
75202
|
});
|
|
74762
75203
|
}
|
|
74763
|
-
const projectPath =
|
|
75204
|
+
const projectPath = join46(deps.cwd, PROJECT_CONFIG_FILENAME);
|
|
74764
75205
|
try {
|
|
74765
75206
|
project = deps.loadProjectConfig(deps.cwd);
|
|
74766
75207
|
results.push(project ? {
|
|
@@ -74877,10 +75318,11 @@ async function runDoctorChecks(deps, options = {}) {
|
|
|
74877
75318
|
results.push(checkTunnel(project, deps));
|
|
74878
75319
|
results.push(checkWebhookSecret(project));
|
|
74879
75320
|
results.push(...checkOma(project, deps));
|
|
75321
|
+
results.push(...await checkSkillMatrix(project, global2, deps));
|
|
74880
75322
|
return results;
|
|
74881
75323
|
}
|
|
74882
75324
|
function computeExitCode(results) {
|
|
74883
|
-
return results.some((r) => r.critical && r.status === "fail") ? 1 : 0;
|
|
75325
|
+
return results.some((r) => r.critical && (r.status === "fail" || r.status === "unknown")) ? 1 : 0;
|
|
74884
75326
|
}
|
|
74885
75327
|
function summarize(results) {
|
|
74886
75328
|
return { passed: results.filter((r) => r.status === "pass").length, total: results.length };
|
|
@@ -74955,7 +75397,7 @@ async function registerLinearWebhook(root, tunnelUrl) {
|
|
|
74955
75397
|
init_yaml_loader();
|
|
74956
75398
|
import { existsSync as existsSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync2 } from "node:fs";
|
|
74957
75399
|
import { createServer as createServer3 } from "node:net";
|
|
74958
|
-
import { resolve as
|
|
75400
|
+
import { resolve as resolve28 } from "node:path";
|
|
74959
75401
|
import { setTimeout as delay } from "node:timers/promises";
|
|
74960
75402
|
|
|
74961
75403
|
// src/webhook-proxy.ts
|
|
@@ -75070,12 +75512,12 @@ function resolveServerPort(root, runningPort) {
|
|
|
75070
75512
|
return String(port);
|
|
75071
75513
|
}
|
|
75072
75514
|
function resolveRuntimePaths(root, cliDir) {
|
|
75073
|
-
const dashboardCwd =
|
|
75074
|
-
if (!existsSync5(
|
|
75515
|
+
const dashboardCwd = resolve28(root, "apps/dashboard");
|
|
75516
|
+
if (!existsSync5(resolve28(dashboardCwd, "package.json"))) {
|
|
75075
75517
|
throw new Error(`Dashboard source is missing at ${dashboardCwd}. Clone https://github.com/first-fluke/agent-valley, run bun install, then run bun av setup and bun av dev from that checkout. The standalone CLI does not include the dashboard.`);
|
|
75076
75518
|
}
|
|
75077
|
-
const bundled =
|
|
75078
|
-
const supervisorScript = existsSync5(bundled) ? bundled :
|
|
75519
|
+
const bundled = resolve28(cliDir, "supervisor.js");
|
|
75520
|
+
const supervisorScript = existsSync5(bundled) ? bundled : resolve28(cliDir, "supervisor.ts");
|
|
75079
75521
|
if (!existsSync5(supervisorScript)) {
|
|
75080
75522
|
throw new Error(`Supervisor is missing at ${supervisorScript}. Run bun av up from an intact Agent Valley checkout.`);
|
|
75081
75523
|
}
|
|
@@ -75354,8 +75796,8 @@ function spawnTunnel(config, input) {
|
|
|
75354
75796
|
|
|
75355
75797
|
// src/index.ts
|
|
75356
75798
|
var ROOT = process.cwd();
|
|
75357
|
-
var PID_FILE =
|
|
75358
|
-
var LOG_FILE =
|
|
75799
|
+
var PID_FILE = resolve32(ROOT, ".av.pid");
|
|
75800
|
+
var LOG_FILE = resolve32(ROOT, ".av.log");
|
|
75359
75801
|
function ensureConfig() {
|
|
75360
75802
|
if (!existsSync10(resolveProjectConfigPath(ROOT))) {
|
|
75361
75803
|
console.log(import_picocolors15.default.red("No av.yaml found. Run `av setup` first."));
|