agentwheel 0.21.6 → 0.21.7
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/index.js +764 -605
- package/openpack.json +1 -1
- package/package.json +1 -1
- package/skills/agentwheel/SKILL.md +1 -1
- package/skills/agentwheel-discovery/SKILL.md +1 -1
package/dist/index.js
CHANGED
|
@@ -583,7 +583,7 @@ async function withFilesystemLock(lockPath, timeoutMs, fn, description = "cache"
|
|
|
583
583
|
if (Date.now() - started > timeoutMs) {
|
|
584
584
|
throw new Error(`Timed out waiting for ${description} lock at ${lockPath}`);
|
|
585
585
|
}
|
|
586
|
-
await new Promise((
|
|
586
|
+
await new Promise((resolve46) => setTimeout(resolve46, 50));
|
|
587
587
|
}
|
|
588
588
|
}
|
|
589
589
|
try {
|
|
@@ -853,7 +853,7 @@ var init_protocol = __esm({
|
|
|
853
853
|
// src/mutation/process.ts
|
|
854
854
|
import { spawn } from "child_process";
|
|
855
855
|
async function runProcess(command, args, options = {}) {
|
|
856
|
-
return new Promise((
|
|
856
|
+
return new Promise((resolve46, reject) => {
|
|
857
857
|
const useProcessGroup = options.killProcessGroup === true && process.platform !== "win32";
|
|
858
858
|
const child = spawn(command, args, {
|
|
859
859
|
cwd: options.cwd,
|
|
@@ -913,7 +913,7 @@ async function runProcess(command, args, options = {}) {
|
|
|
913
913
|
reject(new Error(`${command} exited ${exitCode}${detail ? `: ${detail}` : ""}`));
|
|
914
914
|
return;
|
|
915
915
|
}
|
|
916
|
-
|
|
916
|
+
resolve46(result);
|
|
917
917
|
});
|
|
918
918
|
if (options.input !== void 0) child.stdin.end(options.input);
|
|
919
919
|
else child.stdin.end();
|
|
@@ -1961,13 +1961,13 @@ async function spawnWithInput(command, args, input) {
|
|
|
1961
1961
|
if (result.stderr) throw new Error(result.stderr);
|
|
1962
1962
|
}
|
|
1963
1963
|
function waitForProcess(child, label) {
|
|
1964
|
-
return new Promise((
|
|
1964
|
+
return new Promise((resolve46, reject) => {
|
|
1965
1965
|
const stderr = [];
|
|
1966
1966
|
child.stderr?.on("data", (chunk) => stderr.push(chunk));
|
|
1967
1967
|
child.on("error", reject);
|
|
1968
1968
|
child.on("close", (code) => {
|
|
1969
1969
|
const message = Buffer.concat(stderr).toString("utf8");
|
|
1970
|
-
if (code === 0)
|
|
1970
|
+
if (code === 0) resolve46({ stderr: "" });
|
|
1971
1971
|
else reject(new Error(`${label} exited ${code}${message ? `: ${message}` : ""}`));
|
|
1972
1972
|
});
|
|
1973
1973
|
});
|
|
@@ -3267,10 +3267,197 @@ var init_workspace = __esm({
|
|
|
3267
3267
|
}
|
|
3268
3268
|
});
|
|
3269
3269
|
|
|
3270
|
+
// src/model/fleet.ts
|
|
3271
|
+
import { lstat, readFile as readFile11, realpath } from "fs/promises";
|
|
3272
|
+
import { homedir as homedir5 } from "os";
|
|
3273
|
+
import { isAbsolute as isAbsolute7, relative as relative5, resolve as resolve12 } from "path";
|
|
3274
|
+
async function resolveWorkspaceScope(request = {}) {
|
|
3275
|
+
const selected = [request.user === true, request.local === true, request.fleet !== void 0].filter(Boolean).length;
|
|
3276
|
+
if (selected > 1) {
|
|
3277
|
+
throw new Error("Choose exactly one workspace selector: --user, --local, or --fleet <id>.");
|
|
3278
|
+
}
|
|
3279
|
+
const globalRoot = resolve12(request.globalRoot ?? homedir5());
|
|
3280
|
+
if (request.user) {
|
|
3281
|
+
const config2 = await readWorkspaceConfig(globalRoot);
|
|
3282
|
+
assertNonFleetScope("user", config2);
|
|
3283
|
+
return { kind: "user", root: globalRoot, config: config2 };
|
|
3284
|
+
}
|
|
3285
|
+
if (request.fleet !== void 0) {
|
|
3286
|
+
const id = fleetIdSchema.parse(request.fleet);
|
|
3287
|
+
const registration = await showRegisteredFleet(id, { globalRoot });
|
|
3288
|
+
const root = await assertCanonicalDirectory(registration.root, `Registered fleet '${id}' root`);
|
|
3289
|
+
const config2 = await readRequiredConfig(root, `fleet '${id}'`);
|
|
3290
|
+
assertFleetContract(id, registration, config2);
|
|
3291
|
+
return { kind: "fleet", root, fleetId: id, config: config2 };
|
|
3292
|
+
}
|
|
3293
|
+
const cwd = resolve12(request.cwd ?? process.cwd());
|
|
3294
|
+
const discoveredRoot = await findExistingWorkspaceRoot(cwd);
|
|
3295
|
+
if (!discoveredRoot || discoveredRoot === globalRoot) {
|
|
3296
|
+
if (request.local === true && cwd !== globalRoot) {
|
|
3297
|
+
return { kind: "local", root: cwd, config: await readWorkspaceConfig(cwd) };
|
|
3298
|
+
}
|
|
3299
|
+
throw missingScopeError(request.local === true ? "local" : "implicit local");
|
|
3300
|
+
}
|
|
3301
|
+
const config = await readRequiredConfig(discoveredRoot, "local");
|
|
3302
|
+
assertNonFleetScope("local", config);
|
|
3303
|
+
return { kind: "local", root: discoveredRoot, config };
|
|
3304
|
+
}
|
|
3305
|
+
async function registerFleet(request) {
|
|
3306
|
+
const id = fleetIdSchema.parse(request.id);
|
|
3307
|
+
const requiredPackages = sortedUnique3(request.requiredPackages);
|
|
3308
|
+
if (requiredPackages.length === 0) throw new Error("Fleet registration requires at least one --required-package <name>.");
|
|
3309
|
+
const globalRoot = resolve12(request.globalRoot ?? homedir5());
|
|
3310
|
+
const home = await readWorkspaceConfig(globalRoot);
|
|
3311
|
+
if (supportsFleetConfig(home) && home.fleetId) {
|
|
3312
|
+
throw new Error(`The home config is fleet '${home.fleetId}', so it cannot own the global fleet registry.`);
|
|
3313
|
+
}
|
|
3314
|
+
const existing = supportsFleetConfig(home) ? await canonicalizeExistingFleetRoots(home.fleets, globalRoot) : {};
|
|
3315
|
+
if (existing[id]) throw new Error(`Fleet '${id}' is already registered.`);
|
|
3316
|
+
const root = await assertCanonicalDirectory(request.root, `Fleet '${id}' root`);
|
|
3317
|
+
const duplicateRoot = Object.entries(existing).find(([, value]) => value.root === root);
|
|
3318
|
+
if (duplicateRoot) throw new Error(`Fleet root ${root} is already registered as '${duplicateRoot[0]}'.`);
|
|
3319
|
+
if (root === globalRoot) throw new Error("A fleet root must be outside the user config root contract.");
|
|
3320
|
+
const target = await readRequiredConfig(root, `fleet '${id}'`);
|
|
3321
|
+
const registration = registeredFleetSchema.parse({ root, requiredPackages });
|
|
3322
|
+
assertFleetContract(id, registration, target);
|
|
3323
|
+
const upgraded = workspaceConfigSchema.parse({
|
|
3324
|
+
...home,
|
|
3325
|
+
schemaVersion: CURRENT_WORKSPACE_SCHEMA_VERSION,
|
|
3326
|
+
exports: home.schemaVersion >= 2 ? home.exports : { selections: {} },
|
|
3327
|
+
fleets: { ...existing, [id]: registration }
|
|
3328
|
+
});
|
|
3329
|
+
const configPath = globalWorkspaceConfigPath(globalRoot);
|
|
3330
|
+
declareMutationPath(configPath);
|
|
3331
|
+
await writeJsonAtomic(configPath, upgraded);
|
|
3332
|
+
return { id, ...registration };
|
|
3333
|
+
}
|
|
3334
|
+
async function canonicalizeExistingFleetRoots(fleets, globalRoot) {
|
|
3335
|
+
const canonical = /* @__PURE__ */ new Map();
|
|
3336
|
+
const normalized = {};
|
|
3337
|
+
for (const [id, registration] of Object.entries(fleets).sort(([a], [b]) => a.localeCompare(b))) {
|
|
3338
|
+
const root = await canonicalizeDirectory(registration.root, `Registered fleet '${id}' root`);
|
|
3339
|
+
if (root === globalRoot) throw new Error(`Registered fleet '${id}' root must be outside the user config root contract.`);
|
|
3340
|
+
const incumbent = canonical.get(root);
|
|
3341
|
+
if (incumbent) {
|
|
3342
|
+
throw new Error(`Fleet root ${root} is registered more than once as '${incumbent}' and '${id}'.`);
|
|
3343
|
+
}
|
|
3344
|
+
canonical.set(root, id);
|
|
3345
|
+
normalized[id] = registeredFleetSchema.parse({ ...registration, root });
|
|
3346
|
+
}
|
|
3347
|
+
return normalized;
|
|
3348
|
+
}
|
|
3349
|
+
async function listRegisteredFleets(options = {}) {
|
|
3350
|
+
const globalRoot = resolve12(options.globalRoot ?? homedir5());
|
|
3351
|
+
const home = await readWorkspaceConfig(globalRoot);
|
|
3352
|
+
if (!supportsFleetConfig(home)) return [];
|
|
3353
|
+
return Object.entries(home.fleets).sort(([a], [b]) => a.localeCompare(b)).map(([id, registration]) => ({ id, ...registration }));
|
|
3354
|
+
}
|
|
3355
|
+
async function showRegisteredFleet(idInput, options = {}) {
|
|
3356
|
+
const id = fleetIdSchema.parse(idInput);
|
|
3357
|
+
const fleets = await listRegisteredFleets(options);
|
|
3358
|
+
const registration = fleets.find((candidate) => candidate.id === id);
|
|
3359
|
+
if (!registration) {
|
|
3360
|
+
throw new Error(`Unknown fleet '${id}'. Use 'agentwheel fleet list' or register it with 'agentwheel fleet register'.`);
|
|
3361
|
+
}
|
|
3362
|
+
return registration;
|
|
3363
|
+
}
|
|
3364
|
+
async function resolveWorkspaceOwnershipScope(workspaceRootInput, options = {}) {
|
|
3365
|
+
const workspaceRoot = await canonicalizeDirectory(resolve12(workspaceRootInput), "Workspace ownership root");
|
|
3366
|
+
if (options.fleetId) {
|
|
3367
|
+
return { root: workspaceRoot, fleetId: fleetIdSchema.parse(options.fleetId) };
|
|
3368
|
+
}
|
|
3369
|
+
const syntacticallyContaining = (await listRegisteredFleets({ globalRoot: options.globalRoot })).filter((fleet2) => containsPath(resolve12(fleet2.root), workspaceRoot));
|
|
3370
|
+
const registered = await Promise.all(syntacticallyContaining.map(async (fleet2) => ({
|
|
3371
|
+
...fleet2,
|
|
3372
|
+
root: await canonicalizeDirectory(fleet2.root, `Registered fleet '${fleet2.id}' root`)
|
|
3373
|
+
})));
|
|
3374
|
+
const containing = registered.filter((fleet2) => containsPath(fleet2.root, workspaceRoot));
|
|
3375
|
+
if (containing.length > 1) {
|
|
3376
|
+
throw new Error(
|
|
3377
|
+
`Workspace ${workspaceRoot} is contained by multiple registered fleets: ` + containing.map((fleet2) => `'${fleet2.id}' at ${fleet2.root}`).join(", ") + ". Resolve the overlapping registrations before planning ownership."
|
|
3378
|
+
);
|
|
3379
|
+
}
|
|
3380
|
+
const fleet = containing[0];
|
|
3381
|
+
if (fleet) assertFleetContract(fleet.id, fleet, await readRequiredConfig(fleet.root, `fleet '${fleet.id}'`));
|
|
3382
|
+
return fleet ? { root: fleet.root, fleetId: fleet.id } : { root: workspaceRoot };
|
|
3383
|
+
}
|
|
3384
|
+
async function readRequiredConfig(root, label) {
|
|
3385
|
+
const path = workspaceConfigPath(root);
|
|
3386
|
+
if (!await pathExists(path)) throw missingScopeError(label);
|
|
3387
|
+
try {
|
|
3388
|
+
return workspaceConfigSchema.parse(JSON.parse(await readFile11(path, "utf8")));
|
|
3389
|
+
} catch (error) {
|
|
3390
|
+
throw new Error(`Invalid ${label} Agentwheel config at ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
function assertFleetContract(id, registration, config) {
|
|
3394
|
+
if (!supportsFleetConfig(config)) {
|
|
3395
|
+
throw new Error(`Fleet '${id}' config must use schemaVersion 3 or newer before registration or selection.`);
|
|
3396
|
+
}
|
|
3397
|
+
if (config.fleetId !== id) {
|
|
3398
|
+
throw new Error(`Fleet fleetId mismatch: expected '${id}', found '${config.fleetId ?? "missing"}'.`);
|
|
3399
|
+
}
|
|
3400
|
+
if (Object.keys(config.fleets).length > 0) {
|
|
3401
|
+
throw new Error(`Fleet '${id}' config may not contain the home fleets registry.`);
|
|
3402
|
+
}
|
|
3403
|
+
const names = new Set(config.packages.map((pkg) => pkg.name));
|
|
3404
|
+
for (const packageName of registration.requiredPackages) {
|
|
3405
|
+
if (!names.has(packageName)) throw new Error(`Fleet '${id}' is missing required package '${packageName}'.`);
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
async function assertCanonicalDirectory(input, label) {
|
|
3409
|
+
const canonical = await canonicalizeDirectory(input, label);
|
|
3410
|
+
const normalized = resolve12(input);
|
|
3411
|
+
const stats = await lstat(input);
|
|
3412
|
+
if (stats.isSymbolicLink() || canonical !== normalized || input !== normalized) {
|
|
3413
|
+
throw new Error(`${label} must be canonical and symlink-unambiguous: ${input} resolves to ${canonical}.`);
|
|
3414
|
+
}
|
|
3415
|
+
return canonical;
|
|
3416
|
+
}
|
|
3417
|
+
async function canonicalizeDirectory(input, label) {
|
|
3418
|
+
if (!isAbsolute7(input)) throw new Error(`${label} must be an absolute canonical path.`);
|
|
3419
|
+
let canonical;
|
|
3420
|
+
try {
|
|
3421
|
+
canonical = await realpath(input);
|
|
3422
|
+
} catch {
|
|
3423
|
+
throw new Error(`${label} does not exist: ${input}`);
|
|
3424
|
+
}
|
|
3425
|
+
const stats = await lstat(canonical);
|
|
3426
|
+
if (!stats.isDirectory()) throw new Error(`${label} is not a directory: ${input}`);
|
|
3427
|
+
return canonical;
|
|
3428
|
+
}
|
|
3429
|
+
function missingScopeError(label) {
|
|
3430
|
+
return new Error(
|
|
3431
|
+
`Missing ${label} Agentwheel workspace config. Select --user, --local, or --fleet <id>, or run 'agentwheel init workspace' in the intended local root. Agentwheel never falls back to home desired state.`
|
|
3432
|
+
);
|
|
3433
|
+
}
|
|
3434
|
+
function assertNonFleetScope(kind, config) {
|
|
3435
|
+
if (supportsFleetConfig(config) && config.fleetId) {
|
|
3436
|
+
throw new Error(
|
|
3437
|
+
`The ${kind} config declares fleetId '${config.fleetId}'. Select it through the registered --fleet <id> scope.`
|
|
3438
|
+
);
|
|
3439
|
+
}
|
|
3440
|
+
}
|
|
3441
|
+
function sortedUnique3(values) {
|
|
3442
|
+
return [...new Set(values.map((value) => value.trim()).filter(Boolean))].sort((a, b) => a.localeCompare(b));
|
|
3443
|
+
}
|
|
3444
|
+
function containsPath(parent, candidate) {
|
|
3445
|
+
const path = relative5(parent, candidate);
|
|
3446
|
+
return path === "" || !path.startsWith("..") && !isAbsolute7(path);
|
|
3447
|
+
}
|
|
3448
|
+
var init_fleet = __esm({
|
|
3449
|
+
"src/model/fleet.ts"() {
|
|
3450
|
+
"use strict";
|
|
3451
|
+
init_fs();
|
|
3452
|
+
init_declarations();
|
|
3453
|
+
init_workspace();
|
|
3454
|
+
}
|
|
3455
|
+
});
|
|
3456
|
+
|
|
3270
3457
|
// src/mutation/repository.ts
|
|
3271
3458
|
import { createHash as createHash7 } from "crypto";
|
|
3272
|
-
import { lstat, readFile as
|
|
3273
|
-
import { posix as posix3, relative as
|
|
3459
|
+
import { lstat as lstat2, readFile as readFile12, readlink, readdir as readdir4 } from "fs/promises";
|
|
3460
|
+
import { posix as posix3, relative as relative6, resolve as resolve13, sep as sep3 } from "path";
|
|
3274
3461
|
async function discoverGitRepository(start) {
|
|
3275
3462
|
const probe = await runProcess("git", ["-C", start, "rev-parse", "--show-toplevel"], { allowExitCodes: [0, 128] });
|
|
3276
3463
|
if (probe.exitCode !== 0) return void 0;
|
|
@@ -3293,7 +3480,7 @@ async function assertGitPreflight(repository) {
|
|
|
3293
3480
|
if (result.exitCode === 0) throw new Error(`Revisioning refuses an in-progress Git operation (${marker}) in ${gitDir}.`);
|
|
3294
3481
|
}
|
|
3295
3482
|
for (const marker of ["rebase-merge", "rebase-apply"]) {
|
|
3296
|
-
if (await exists(
|
|
3483
|
+
if (await exists(resolve13(gitDir, marker))) throw new Error(`Revisioning refuses an in-progress Git operation (${marker}) in ${gitDir}.`);
|
|
3297
3484
|
}
|
|
3298
3485
|
}
|
|
3299
3486
|
async function assertHeadLease(repositoryRoot, expectedHead, head, paths, provider) {
|
|
@@ -3409,16 +3596,16 @@ async function hashHeadPath(repositoryRoot, head, path) {
|
|
|
3409
3596
|
return sha256(result.stdout);
|
|
3410
3597
|
}
|
|
3411
3598
|
async function hashWorkingPath(repositoryRoot, path) {
|
|
3412
|
-
const absolute =
|
|
3599
|
+
const absolute = resolve13(repositoryRoot, ...path.split("/"));
|
|
3413
3600
|
let stats;
|
|
3414
3601
|
try {
|
|
3415
|
-
stats = await
|
|
3602
|
+
stats = await lstat2(absolute);
|
|
3416
3603
|
} catch (error) {
|
|
3417
3604
|
if (isMissing3(error)) return null;
|
|
3418
3605
|
throw error;
|
|
3419
3606
|
}
|
|
3420
3607
|
if (stats.isSymbolicLink()) return sha256(Buffer.from(await readlink(absolute), "utf8"));
|
|
3421
|
-
if (stats.isFile()) return sha256(await
|
|
3608
|
+
if (stats.isFile()) return sha256(await readFile12(absolute));
|
|
3422
3609
|
if (stats.isDirectory()) return hashDirectory(absolute);
|
|
3423
3610
|
throw new Error(`Unsupported repository path kind: ${path}`);
|
|
3424
3611
|
}
|
|
@@ -3427,11 +3614,11 @@ async function hashDirectory(root) {
|
|
|
3427
3614
|
async function walk2(dir) {
|
|
3428
3615
|
for (const entry of (await readdir4(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
3429
3616
|
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
|
3430
|
-
const absolute =
|
|
3431
|
-
const relativePath = normalizeRepoPath(
|
|
3617
|
+
const absolute = resolve13(dir, entry.name);
|
|
3618
|
+
const relativePath = normalizeRepoPath(relative6(root, absolute));
|
|
3432
3619
|
if (entry.isDirectory()) await walk2(absolute);
|
|
3433
3620
|
else if (entry.isSymbolicLink()) hash2.update(relativePath).update("\0").update(await readlink(absolute)).update("\0");
|
|
3434
|
-
else if (entry.isFile()) hash2.update(relativePath).update("\0").update(await
|
|
3621
|
+
else if (entry.isFile()) hash2.update(relativePath).update("\0").update(await readFile12(absolute)).update("\0");
|
|
3435
3622
|
}
|
|
3436
3623
|
}
|
|
3437
3624
|
await walk2(root);
|
|
@@ -3451,7 +3638,7 @@ function isMissing3(error) {
|
|
|
3451
3638
|
}
|
|
3452
3639
|
async function exists(path) {
|
|
3453
3640
|
try {
|
|
3454
|
-
await
|
|
3641
|
+
await lstat2(path);
|
|
3455
3642
|
return true;
|
|
3456
3643
|
} catch (error) {
|
|
3457
3644
|
if (isMissing3(error)) return false;
|
|
@@ -3467,9 +3654,9 @@ var init_repository = __esm({
|
|
|
3467
3654
|
|
|
3468
3655
|
// src/mutation/providers.ts
|
|
3469
3656
|
import { createHash as createHash8 } from "crypto";
|
|
3470
|
-
import { chmod as chmod2, mkdtemp, open as open2, readFile as
|
|
3657
|
+
import { chmod as chmod2, mkdtemp, open as open2, readFile as readFile13, rename as rename5, rm as rm4, rmdir, stat as stat3, writeFile as writeFile7 } from "fs/promises";
|
|
3471
3658
|
import { tmpdir as tmpdir2 } from "os";
|
|
3472
|
-
import { isAbsolute as
|
|
3659
|
+
import { isAbsolute as isAbsolute8, join as join10, resolve as resolve14 } from "path";
|
|
3473
3660
|
function revisionProviderRejection(error) {
|
|
3474
3661
|
return error instanceof RevisionProviderRejectedError ? error.response : void 0;
|
|
3475
3662
|
}
|
|
@@ -3675,7 +3862,7 @@ async function assertProviderSemantics(request, response, config) {
|
|
|
3675
3862
|
}
|
|
3676
3863
|
async function invokeGitProvider(providerId, request, config) {
|
|
3677
3864
|
const repository = await discoverGitRepository(request.repositoryRoot);
|
|
3678
|
-
if (!repository || repository.root !==
|
|
3865
|
+
if (!repository || repository.root !== resolve14(request.repositoryRoot)) {
|
|
3679
3866
|
throw new Error(`Git revision provider requires the repository root itself: ${request.repositoryRoot}.`);
|
|
3680
3867
|
}
|
|
3681
3868
|
if (request.action === "check" || request.action === "preflight") {
|
|
@@ -3752,7 +3939,7 @@ async function finalizeGit(providerId, request, config) {
|
|
|
3752
3939
|
const stagedAfterHooks = splitNull2((await runProcess("git", ["-C", request.repositoryRoot, "diff", "--cached", "--name-only", "-z"], { env: env2 })).stdout);
|
|
3753
3940
|
assertExactSet(stagedAfterHooks, request.paths.map((entry) => entry.path), "temporary Git index after hooks");
|
|
3754
3941
|
await verifyTemporaryIndexPaths(request, env2);
|
|
3755
|
-
const message = await
|
|
3942
|
+
const message = await readFile13(messagePath, "utf8");
|
|
3756
3943
|
assertCommitMessageContract(message, request, planDigest);
|
|
3757
3944
|
commitSha = (await runProcess("git", ["-C", request.repositoryRoot, "commit-tree", tree, "-p", repository.head], {
|
|
3758
3945
|
env: env2,
|
|
@@ -3783,7 +3970,7 @@ async function runCommitHooks(request, env2, messagePath) {
|
|
|
3783
3970
|
["commit-msg", [messagePath]]
|
|
3784
3971
|
]) {
|
|
3785
3972
|
const rawPath = (await runProcess("git", ["-C", request.repositoryRoot, "rev-parse", "--git-path", `hooks/${name}`])).stdout.toString("utf8").trim();
|
|
3786
|
-
const hookPath =
|
|
3973
|
+
const hookPath = isAbsolute8(rawPath) ? rawPath : resolve14(request.repositoryRoot, rawPath);
|
|
3787
3974
|
let executable = false;
|
|
3788
3975
|
try {
|
|
3789
3976
|
executable = ((await stat3(hookPath)).mode & 73) !== 0;
|
|
@@ -3869,9 +4056,9 @@ async function realignIndexAfterRecoveredCommit(repositoryRoot, expectedHead, co
|
|
|
3869
4056
|
}
|
|
3870
4057
|
async function captureIndexLease(repositoryRoot) {
|
|
3871
4058
|
const rawPath = (await runProcess("git", ["-C", repositoryRoot, "rev-parse", "--git-path", "index"])).stdout.toString("utf8").trim();
|
|
3872
|
-
const path =
|
|
4059
|
+
const path = isAbsolute8(rawPath) ? rawPath : resolve14(repositoryRoot, rawPath);
|
|
3873
4060
|
try {
|
|
3874
|
-
const [content, info] = await Promise.all([
|
|
4061
|
+
const [content, info] = await Promise.all([readFile13(path), stat3(path)]);
|
|
3875
4062
|
return { path, sha256: sha2562(content), mode: info.mode & 511 };
|
|
3876
4063
|
} catch (error) {
|
|
3877
4064
|
if (isMissing4(error)) return { path, sha256: null, mode: 384 };
|
|
@@ -3887,7 +4074,7 @@ async function replaceIndexCas(repositoryRoot, lease, commitSha) {
|
|
|
3887
4074
|
await runProcess("git", ["-C", repositoryRoot, "read-tree", commitSha], {
|
|
3888
4075
|
env: { ...process.env, GIT_INDEX_FILE: replacementPath }
|
|
3889
4076
|
});
|
|
3890
|
-
const replacement = await
|
|
4077
|
+
const replacement = await readFile13(replacementPath);
|
|
3891
4078
|
handle = await open2(lockPath, "wx", lease.mode);
|
|
3892
4079
|
const current = await readOptionalFile(lease.path);
|
|
3893
4080
|
const currentSha256 = current ? sha2562(current) : null;
|
|
@@ -3929,7 +4116,7 @@ async function hashGitObject(repositoryRoot, spec) {
|
|
|
3929
4116
|
}
|
|
3930
4117
|
async function readOptionalFile(path) {
|
|
3931
4118
|
try {
|
|
3932
|
-
return await
|
|
4119
|
+
return await readFile13(path);
|
|
3933
4120
|
} catch (error) {
|
|
3934
4121
|
if (isMissing4(error)) return null;
|
|
3935
4122
|
throw error;
|
|
@@ -4035,14 +4222,14 @@ var init_providers = __esm({
|
|
|
4035
4222
|
|
|
4036
4223
|
// src/mutation/coordinator.ts
|
|
4037
4224
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4038
|
-
import { homedir as
|
|
4039
|
-
import { isAbsolute as
|
|
4225
|
+
import { homedir as homedir6 } from "os";
|
|
4226
|
+
import { dirname as dirname9, isAbsolute as isAbsolute9, relative as relative7, resolve as resolve15, sep as sep4 } from "path";
|
|
4040
4227
|
function dirtyRepositoryPaths(repositoryRoot, baseline, paths) {
|
|
4041
4228
|
const conflicts = /* @__PURE__ */ new Set();
|
|
4042
4229
|
for (const path of paths) {
|
|
4043
|
-
const absolute =
|
|
4044
|
-
const relativePath =
|
|
4045
|
-
if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${sep4}`) ||
|
|
4230
|
+
const absolute = isAbsolute9(path) ? resolve15(path) : resolve15(process.cwd(), path);
|
|
4231
|
+
const relativePath = relative7(repositoryRoot, absolute);
|
|
4232
|
+
if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${sep4}`) || isAbsolute9(relativePath)) continue;
|
|
4046
4233
|
const normalized = relativePath.split(sep4).join("/");
|
|
4047
4234
|
if (baseline.changed.has(normalized)) conflicts.add(normalized);
|
|
4048
4235
|
}
|
|
@@ -4259,13 +4446,18 @@ async function checkMutationProvider(workspaceRoot, globalRoot) {
|
|
|
4259
4446
|
});
|
|
4260
4447
|
return invokeRevisionProvider(policy.revisioning.provider, request, { workspaceRoot });
|
|
4261
4448
|
}
|
|
4262
|
-
async function mutationPolicyForWorkspace(workspaceRoot, globalRoot =
|
|
4449
|
+
async function mutationPolicyForWorkspace(workspaceRoot, globalRoot = homedir6()) {
|
|
4263
4450
|
const scopedConfig = await readWorkspaceConfig(workspaceRoot);
|
|
4264
4451
|
const scoped = scopedConfig.schemaVersion === 4 ? scopedConfig.mutationPolicy : void 0;
|
|
4265
|
-
if (
|
|
4452
|
+
if (resolve15(workspaceRoot) === resolve15(globalRoot)) return scoped;
|
|
4266
4453
|
const globalConfig = await readWorkspaceConfig(globalRoot);
|
|
4267
4454
|
const global = globalConfig.schemaVersion === 4 ? globalConfig.mutationPolicy : void 0;
|
|
4268
|
-
|
|
4455
|
+
let existingRoot = resolve15(workspaceRoot);
|
|
4456
|
+
while (!await pathExists(existingRoot) && dirname9(existingRoot) !== existingRoot) existingRoot = dirname9(existingRoot);
|
|
4457
|
+
const owner = await resolveWorkspaceOwnershipScope(existingRoot, { globalRoot });
|
|
4458
|
+
const fleetConfig = owner.fleetId ? await readWorkspaceConfig(owner.root) : void 0;
|
|
4459
|
+
const fleet = fleetConfig?.schemaVersion === 4 ? fleetConfig.mutationPolicy : void 0;
|
|
4460
|
+
return mergeMutationPolicies(mergeMutationPolicies(global, fleet), scoped);
|
|
4269
4461
|
}
|
|
4270
4462
|
function mergeMutationPolicies(global, scoped) {
|
|
4271
4463
|
if (!global) return scoped;
|
|
@@ -4337,6 +4529,8 @@ var init_coordinator = __esm({
|
|
|
4337
4529
|
"use strict";
|
|
4338
4530
|
init_mutation();
|
|
4339
4531
|
init_workspace();
|
|
4532
|
+
init_fleet();
|
|
4533
|
+
init_fs();
|
|
4340
4534
|
init_declarations();
|
|
4341
4535
|
init_providers();
|
|
4342
4536
|
init_protocol();
|
|
@@ -4619,18 +4813,18 @@ __export(transaction_exports, {
|
|
|
4619
4813
|
writeApplyJournal: () => writeApplyJournal
|
|
4620
4814
|
});
|
|
4621
4815
|
import { createHash as createHash9 } from "crypto";
|
|
4622
|
-
import { cp as cp2, lstat as
|
|
4623
|
-
import { dirname as
|
|
4816
|
+
import { cp as cp2, lstat as lstat3, mkdir as mkdir7, open as open3, readFile as readFile14, readdir as readdir5, rm as rm5, stat as stat4 } from "fs/promises";
|
|
4817
|
+
import { dirname as dirname10, join as join11, relative as relative8, resolve as resolve16, sep as sep5 } from "path";
|
|
4624
4818
|
async function assertNoSymlinkPath(path) {
|
|
4625
|
-
const absolute =
|
|
4819
|
+
const absolute = resolve16(path);
|
|
4626
4820
|
let current = absolute;
|
|
4627
4821
|
while (true) {
|
|
4628
4822
|
try {
|
|
4629
|
-
if ((await
|
|
4823
|
+
if ((await lstat3(current)).isSymbolicLink()) throw new Error(`Symlink path is unsupported: ${current}`);
|
|
4630
4824
|
} catch (error) {
|
|
4631
4825
|
if (error.code !== "ENOENT") throw error;
|
|
4632
4826
|
}
|
|
4633
|
-
const parent =
|
|
4827
|
+
const parent = dirname10(current);
|
|
4634
4828
|
if (parent === current) break;
|
|
4635
4829
|
current = parent;
|
|
4636
4830
|
}
|
|
@@ -4639,15 +4833,15 @@ async function ownershipRuntimeSnapshot(path) {
|
|
|
4639
4833
|
await assertNoSymlinkPath(path);
|
|
4640
4834
|
const hash2 = createHash9("sha256");
|
|
4641
4835
|
async function visit(candidate) {
|
|
4642
|
-
const info = await
|
|
4836
|
+
const info = await lstat3(candidate);
|
|
4643
4837
|
if (info.isSymbolicLink() || !info.isDirectory() && !info.isFile()) {
|
|
4644
4838
|
throw new Error(`Unsupported ownership runtime path: ${candidate}`);
|
|
4645
4839
|
}
|
|
4646
|
-
hash2.update(JSON.stringify([
|
|
4840
|
+
hash2.update(JSON.stringify([relative8(path, candidate), info.isDirectory() ? "dir" : "file", info.mode & 4095]));
|
|
4647
4841
|
if (info.isDirectory()) {
|
|
4648
4842
|
for (const name of (await readdir5(candidate)).sort()) await visit(join11(candidate, name));
|
|
4649
4843
|
} else {
|
|
4650
|
-
const content = await
|
|
4844
|
+
const content = await readFile14(candidate);
|
|
4651
4845
|
hash2.update(String(content.length)).update("\0").update(content);
|
|
4652
4846
|
}
|
|
4653
4847
|
}
|
|
@@ -4656,14 +4850,14 @@ async function ownershipRuntimeSnapshot(path) {
|
|
|
4656
4850
|
}
|
|
4657
4851
|
function metadataAuditPath(audit, path) {
|
|
4658
4852
|
mutationOperationIdSchema.parse(audit.operationId);
|
|
4659
|
-
if (
|
|
4853
|
+
if (resolve16(audit.workspaceRoot) !== audit.workspaceRoot || path !== `.agentwheel/${audit.kind === "ownership-handoff" ? "ownership-handoffs" : "ownership-releases"}/${audit.operationId}.json`) {
|
|
4660
4854
|
throw new Error("Invalid ownership release audit path.");
|
|
4661
4855
|
}
|
|
4662
4856
|
return join11(audit.workspaceRoot, ...path.split("/"));
|
|
4663
4857
|
}
|
|
4664
4858
|
function metadataRuntimePath(root, path) {
|
|
4665
|
-
const result =
|
|
4666
|
-
if (!path ||
|
|
4859
|
+
const result = resolve16(root, path);
|
|
4860
|
+
if (!path || relative8(resolve16(root), result).split(sep5).join("/") !== path || path === ".agentwheel" || path.startsWith(".agentwheel/") || result === resolve16(root) || !result.startsWith(`${resolve16(root)}${sep5}`)) {
|
|
4667
4861
|
throw new Error(`Unsafe ownership release path: ${path}`);
|
|
4668
4862
|
}
|
|
4669
4863
|
return result;
|
|
@@ -4677,7 +4871,7 @@ async function syncMetadataPath(path, directoryOnly = false) {
|
|
|
4677
4871
|
await file.close();
|
|
4678
4872
|
}
|
|
4679
4873
|
}
|
|
4680
|
-
const directory = await open3(directoryOnly ? path :
|
|
4874
|
+
const directory = await open3(directoryOnly ? path : dirname10(path), "r");
|
|
4681
4875
|
try {
|
|
4682
4876
|
await directory.sync();
|
|
4683
4877
|
} finally {
|
|
@@ -4781,8 +4975,8 @@ async function listAllApplyJournals(targetRoot, adapter, transport = localTransp
|
|
|
4781
4975
|
return found.sort((a, b) => a.path.localeCompare(b.path));
|
|
4782
4976
|
}
|
|
4783
4977
|
async function readLinkedLocalApplyJournal(path, operationId, expectedDigest, expectedTransportDescription) {
|
|
4784
|
-
const absolutePath =
|
|
4785
|
-
const journal = parseApplyJournal(JSON.parse(await
|
|
4978
|
+
const absolutePath = resolve16(path);
|
|
4979
|
+
const journal = parseApplyJournal(JSON.parse(await readFile14(absolutePath, "utf8")));
|
|
4786
4980
|
if (journal.version !== 2 || !journal.mutation) {
|
|
4787
4981
|
throw new Error(`Runtime apply journal ${absolutePath} is not linked to a governed mutation.`);
|
|
4788
4982
|
}
|
|
@@ -4800,7 +4994,7 @@ async function readLinkedLocalApplyJournal(path, operationId, expectedDigest, ex
|
|
|
4800
4994
|
}) !== expectedDigest) {
|
|
4801
4995
|
throw new Error(`Runtime apply journal ${absolutePath} digest does not match its durable receipt.`);
|
|
4802
4996
|
}
|
|
4803
|
-
const expectedPath =
|
|
4997
|
+
const expectedPath = resolve16(applyJournalPath(journal.targetRoot, journal.adapter, {
|
|
4804
4998
|
installationType: journal.installationType,
|
|
4805
4999
|
stateKey: journal.stateKey
|
|
4806
5000
|
}));
|
|
@@ -4815,7 +5009,7 @@ async function removeApplyJournal(targetRoot, adapter, transport = localTranspor
|
|
|
4815
5009
|
if (existing?.mutation) await beginResolveMutationRuntimeJournal(existing.mutation.operationId, path);
|
|
4816
5010
|
await transport.rm(applyJournalPath(targetRoot, adapter, scope));
|
|
4817
5011
|
await transport.rm(applyBackupDir(targetRoot, adapter, scope));
|
|
4818
|
-
if ((existing?.metadataAudit || existing?.metadataGuards) && transport.kind === "local") await syncMetadataPath(
|
|
5012
|
+
if ((existing?.metadataAudit || existing?.metadataGuards) && transport.kind === "local") await syncMetadataPath(dirname10(path), true);
|
|
4819
5013
|
if (existing?.mutation) await resolveMutationRuntimeJournal(existing.mutation.operationId, path);
|
|
4820
5014
|
}
|
|
4821
5015
|
async function abortApplyJournal(targetRoot, adapter, transport = localTransport, scope = {}) {
|
|
@@ -4875,7 +5069,7 @@ function applyJournalLinkDigest(journal, transport) {
|
|
|
4875
5069
|
adapter: journal.adapter,
|
|
4876
5070
|
installationType: journal.installationType ?? null,
|
|
4877
5071
|
stateKey: journal.stateKey ?? null,
|
|
4878
|
-
targetRoot:
|
|
5072
|
+
targetRoot: resolve16(journal.targetRoot),
|
|
4879
5073
|
baseRevision: journal.baseRevision,
|
|
4880
5074
|
graphLockDigest: journal.graphLockDigest ?? null,
|
|
4881
5075
|
graphLockPath: journal.graphLockPath ?? null,
|
|
@@ -4951,7 +5145,7 @@ async function recordBackup(operation, index, targetRoot, adapter, transport = l
|
|
|
4951
5145
|
}
|
|
4952
5146
|
const backupPath = join11(applyBackupDir(targetRoot, adapter, scope), String(index));
|
|
4953
5147
|
await rm5(backupPath, { recursive: true, force: true });
|
|
4954
|
-
await mkdir7(
|
|
5148
|
+
await mkdir7(dirname10(backupPath), { recursive: true });
|
|
4955
5149
|
await cp2(operation.destPath, backupPath, { recursive: operation.kind === "dir", dereference: true });
|
|
4956
5150
|
return {
|
|
4957
5151
|
index,
|
|
@@ -5017,15 +5211,15 @@ var init_transaction = __esm({
|
|
|
5017
5211
|
});
|
|
5018
5212
|
|
|
5019
5213
|
// src/install/toml-merge.ts
|
|
5020
|
-
import { mkdir as mkdir8, readFile as
|
|
5021
|
-
import { dirname as
|
|
5214
|
+
import { mkdir as mkdir8, readFile as readFile15, writeFile as writeFile8 } from "fs/promises";
|
|
5215
|
+
import { dirname as dirname11 } from "path";
|
|
5022
5216
|
async function mergeCodexTomlMcp(sourcePath, destPath) {
|
|
5023
|
-
const source = JSON.parse(await
|
|
5217
|
+
const source = JSON.parse(await readFile15(sourcePath, "utf8"));
|
|
5024
5218
|
const servers = extractMcpServers(source);
|
|
5025
|
-
const current = await pathExists(destPath) ? await
|
|
5219
|
+
const current = await pathExists(destPath) ? await readFile15(destPath, "utf8") : "";
|
|
5026
5220
|
const withoutManaged = removeManagedMcpSections(current, Object.keys(servers));
|
|
5027
5221
|
const merged = appendMcpServers(withoutManaged, servers);
|
|
5028
|
-
await mkdir8(
|
|
5222
|
+
await mkdir8(dirname11(destPath), { recursive: true });
|
|
5029
5223
|
await writeFile8(destPath, merged, "utf8");
|
|
5030
5224
|
}
|
|
5031
5225
|
function mismatchedCodexTomlMcpServers(source, currentContent) {
|
|
@@ -5141,14 +5335,14 @@ var init_toml_merge = __esm({
|
|
|
5141
5335
|
});
|
|
5142
5336
|
|
|
5143
5337
|
// src/install/yaml-merge.ts
|
|
5144
|
-
import { mkdir as mkdir9, readFile as
|
|
5145
|
-
import { dirname as
|
|
5338
|
+
import { mkdir as mkdir9, readFile as readFile16, writeFile as writeFile9 } from "fs/promises";
|
|
5339
|
+
import { dirname as dirname12 } from "path";
|
|
5146
5340
|
import { parse as parse2, stringify } from "yaml";
|
|
5147
5341
|
async function mergeYamlFile(sourcePath, destPath) {
|
|
5148
|
-
const source = parseYamlValue(await
|
|
5149
|
-
const current = await pathExists(destPath) ? parseYamlValue(await
|
|
5342
|
+
const source = parseYamlValue(await readFile16(sourcePath, "utf8"));
|
|
5343
|
+
const current = await pathExists(destPath) ? parseYamlValue(await readFile16(destPath, "utf8")) : {};
|
|
5150
5344
|
const merged = deepMerge2(current, source);
|
|
5151
|
-
await mkdir9(
|
|
5345
|
+
await mkdir9(dirname12(destPath), { recursive: true });
|
|
5152
5346
|
await writeFile9(destPath, stringify(merged), "utf8");
|
|
5153
5347
|
}
|
|
5154
5348
|
function parseYamlValue(content) {
|
|
@@ -5206,8 +5400,8 @@ var init_yaml_merge = __esm({
|
|
|
5206
5400
|
});
|
|
5207
5401
|
|
|
5208
5402
|
// src/install/merge-removal.ts
|
|
5209
|
-
import { mkdir as mkdir10, readFile as
|
|
5210
|
-
import { dirname as
|
|
5403
|
+
import { mkdir as mkdir10, readFile as readFile17, writeFile as writeFile10 } from "fs/promises";
|
|
5404
|
+
import { dirname as dirname13 } from "path";
|
|
5211
5405
|
import { parse as parse3, stringify as stringify2 } from "yaml";
|
|
5212
5406
|
function assertExactMergeContribution(contribution, strategy, currentContent) {
|
|
5213
5407
|
if (strategy === "codex-toml-mcp") {
|
|
@@ -5274,7 +5468,7 @@ async function mergeRemovalForInstall(sourcePath, strategy, currentContent, opti
|
|
|
5274
5468
|
return introducedMergeContent(parseMergeDestination(currentContent, strategy), source);
|
|
5275
5469
|
}
|
|
5276
5470
|
async function removeMergeContribution(destPath, strategy, removal) {
|
|
5277
|
-
const content = await
|
|
5471
|
+
const content = await readFile17(destPath, "utf8");
|
|
5278
5472
|
if (strategy === "codex-toml-mcp") {
|
|
5279
5473
|
const servers = isRecord4(removal.mcpServers) ? removal.mcpServers : removal;
|
|
5280
5474
|
await writeFile10(destPath, removeCodexTomlMcpSections(content, Object.keys(servers)), "utf8");
|
|
@@ -5282,7 +5476,7 @@ async function removeMergeContribution(destPath, strategy, removal) {
|
|
|
5282
5476
|
}
|
|
5283
5477
|
const current = parseMergeDestination(content, strategy);
|
|
5284
5478
|
removeIntroducedContent(current, removal);
|
|
5285
|
-
await mkdir10(
|
|
5479
|
+
await mkdir10(dirname13(destPath), { recursive: true });
|
|
5286
5480
|
await writeFile10(destPath, strategy === "yaml-deep" ? stringify2(current) : `${JSON.stringify(current, null, 2)}
|
|
5287
5481
|
`, "utf8");
|
|
5288
5482
|
}
|
|
@@ -5298,7 +5492,7 @@ async function readMergeSource(sourcePath, strategy) {
|
|
|
5298
5492
|
if (strategy === "openclaw-json-deep") {
|
|
5299
5493
|
return requireRecord(await renderOpenClawJsonMergeSource(sourcePath), "OpenClaw JSON merge source");
|
|
5300
5494
|
}
|
|
5301
|
-
const content = await
|
|
5495
|
+
const content = await readFile17(sourcePath, "utf8");
|
|
5302
5496
|
if (strategy === "yaml-deep") return requireRecord(normalizeYamlValue2(parse3(content)), "YAML merge source");
|
|
5303
5497
|
return requireRecord(JSON.parse(content), "JSON merge source");
|
|
5304
5498
|
}
|
|
@@ -5550,9 +5744,9 @@ var init_desired = __esm({
|
|
|
5550
5744
|
|
|
5551
5745
|
// src/install/instructions-block.ts
|
|
5552
5746
|
import { createHash as createHash10 } from "crypto";
|
|
5553
|
-
import { mkdtemp as mkdtemp2, readFile as
|
|
5747
|
+
import { mkdtemp as mkdtemp2, readFile as readFile18, realpath as realpath2, rm as rm6, writeFile as writeFile11 } from "fs/promises";
|
|
5554
5748
|
import { tmpdir as tmpdir3 } from "os";
|
|
5555
|
-
import { basename as basename2, dirname as
|
|
5749
|
+
import { basename as basename2, dirname as dirname14, join as join12, relative as relative9 } from "path";
|
|
5556
5750
|
function exactManagedInstructionBlockSnapshot(content, selector) {
|
|
5557
5751
|
const beginCount = [...content.matchAll(new RegExp(`<!-- BEGIN openpack:include ${escapeRegex(selector)}(?=\\s|-->)`, "gu"))].length;
|
|
5558
5752
|
const endCount = [...content.matchAll(new RegExp(`<!-- END openpack:include ${escapeRegex(selector)}(?=\\s|-->)`, "gu"))].length;
|
|
@@ -5603,7 +5797,7 @@ function exactManagedInstructionBlockSnapshot(content, selector) {
|
|
|
5603
5797
|
};
|
|
5604
5798
|
}
|
|
5605
5799
|
async function desiredManagedInstructionBlockHash(sourcePath) {
|
|
5606
|
-
const source = await
|
|
5800
|
+
const source = await readFile18(sourcePath, "utf8");
|
|
5607
5801
|
return hashText(managedBlockBody(source));
|
|
5608
5802
|
}
|
|
5609
5803
|
async function readManagedInstructionBlockState(destPath, selector, transport) {
|
|
@@ -5623,7 +5817,7 @@ async function readManagedInstructionBlockState(destPath, selector, transport) {
|
|
|
5623
5817
|
};
|
|
5624
5818
|
}
|
|
5625
5819
|
async function writeManagedInstructionBlock(sourcePath, destPath, selector, transport, options = {}) {
|
|
5626
|
-
const source = await
|
|
5820
|
+
const source = await readFile18(sourcePath, "utf8");
|
|
5627
5821
|
const desired = renderManagedInstructionBlock(selector, source);
|
|
5628
5822
|
const existing = await readOptionalText(destPath, transport);
|
|
5629
5823
|
const merged = upsertManagedInstructionBlock(existing ?? "", selector, desired.block, options);
|
|
@@ -5643,7 +5837,7 @@ async function managedInstructionBlockLanded(destPath, selector, expectedHash, t
|
|
|
5643
5837
|
}
|
|
5644
5838
|
async function managedInstructionPhysicalKey(destPath, transport) {
|
|
5645
5839
|
if (transport.kind !== "local" || !await transport.pathExists(destPath)) return destPath;
|
|
5646
|
-
return
|
|
5840
|
+
return realpath2(destPath);
|
|
5647
5841
|
}
|
|
5648
5842
|
async function claudeInstructionBridgesAgents(claudePath, agentsPath, transport) {
|
|
5649
5843
|
if (!await transport.pathExists(claudePath)) return false;
|
|
@@ -5735,7 +5929,7 @@ function assertCleanBlock(block, selector) {
|
|
|
5735
5929
|
}
|
|
5736
5930
|
}
|
|
5737
5931
|
function referencesAgentsMd(content, claudePath, agentsPath) {
|
|
5738
|
-
const claudeDir =
|
|
5932
|
+
const claudeDir = dirname14(claudePath);
|
|
5739
5933
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
5740
5934
|
const line = rawLine.trim();
|
|
5741
5935
|
const atImport = /^@import\s+(.+)$/i.exec(line);
|
|
@@ -5745,7 +5939,7 @@ function referencesAgentsMd(content, claudePath, agentsPath) {
|
|
|
5745
5939
|
const cleaned = referenced.trim().replace(/^["']|["']$/g, "");
|
|
5746
5940
|
if (!/AGENTS\.md$/i.test(cleaned)) continue;
|
|
5747
5941
|
const candidate = cleaned.startsWith("/") ? cleaned : join12(claudeDir, cleaned);
|
|
5748
|
-
if (
|
|
5942
|
+
if (relative9(dirname14(agentsPath), candidate).replaceAll("\\", "/") === "AGENTS.md") return true;
|
|
5749
5943
|
if (candidate === agentsPath) return true;
|
|
5750
5944
|
}
|
|
5751
5945
|
return false;
|
|
@@ -5753,7 +5947,7 @@ function referencesAgentsMd(content, claudePath, agentsPath) {
|
|
|
5753
5947
|
async function samePhysicalPath(left, right, transport) {
|
|
5754
5948
|
if (transport.kind !== "local") return false;
|
|
5755
5949
|
if (!await transport.pathExists(left) || !await transport.pathExists(right)) return false;
|
|
5756
|
-
return await
|
|
5950
|
+
return await realpath2(left) === await realpath2(right);
|
|
5757
5951
|
}
|
|
5758
5952
|
async function readOptionalText(path, transport) {
|
|
5759
5953
|
if (!await transport.pathExists(path)) return void 0;
|
|
@@ -5803,9 +5997,9 @@ __export(apply_exports, {
|
|
|
5803
5997
|
});
|
|
5804
5998
|
import { execFile as execFile4 } from "child_process";
|
|
5805
5999
|
import { createHash as createHash11, randomUUID as randomUUID3 } from "crypto";
|
|
5806
|
-
import { link as link2, mkdir as mkdir11, mkdtemp as mkdtemp3, open as open4, readFile as
|
|
6000
|
+
import { link as link2, mkdir as mkdir11, mkdtemp as mkdtemp3, open as open4, readFile as readFile19, rm as rm7, writeFile as writeFile12 } from "fs/promises";
|
|
5807
6001
|
import { tmpdir as tmpdir4 } from "os";
|
|
5808
|
-
import { basename as basename3, dirname as
|
|
6002
|
+
import { basename as basename3, dirname as dirname15, join as join13, resolve as resolve17 } from "path";
|
|
5809
6003
|
import { promisify as promisify4 } from "util";
|
|
5810
6004
|
async function applyInstallPlan(plan, sourceLock, options = {}) {
|
|
5811
6005
|
return applyPlanTransactionally(plan, { ...options, sourceLock });
|
|
@@ -6172,7 +6366,7 @@ async function assertCommittedJournalState(journal, expectedManifest, transport)
|
|
|
6172
6366
|
}
|
|
6173
6367
|
}
|
|
6174
6368
|
if (journal.workspaceConfigPath && journal.workspaceConfig) {
|
|
6175
|
-
const actual = JSON.parse(await
|
|
6369
|
+
const actual = JSON.parse(await readFile19(journal.workspaceConfigPath, "utf8"));
|
|
6176
6370
|
if (canonicalJson5(actual) !== canonicalJson5(journal.workspaceConfig)) {
|
|
6177
6371
|
throw new Error(`Workspace config postcheck failed for ${journal.workspaceConfigPath}.`);
|
|
6178
6372
|
}
|
|
@@ -6182,7 +6376,7 @@ async function assertCommittedJournalState(journal, expectedManifest, transport)
|
|
|
6182
6376
|
async function assertMetadataAuditGuards(journal, after, transport, requireAfter = false) {
|
|
6183
6377
|
const audit = journal.metadataAudit;
|
|
6184
6378
|
const sha = /^[a-f0-9]{64}$/;
|
|
6185
|
-
if (transport.kind !== "local" || audit.kind !== "ownership-release" || after.adapter !== journal.adapter || after.targetRoot !== journal.targetRoot || after.installationType !== journal.installationType || after.stateKey !== journal.stateKey || journal.mode !== "uninstall" || journal.operations.length || journal.completed.length || journal.sourceLock || journal.graphLock || journal.graphLockPath || journal.graphLockRemovePath || journal.stateRemoveKey || journal.workspaceConfigPath || journal.workspaceConfig || !sha.test(audit.planDigest) || !sha.test(journal.baseRevision ?? "") || audit.auditFiles.length !== 1 || audit.runtime.length !== 1 || !audit.inventory.length) {
|
|
6379
|
+
if (transport.kind !== "local" || audit.kind !== "ownership-release" && audit.kind !== "ownership-handoff" || after.adapter !== journal.adapter || after.targetRoot !== journal.targetRoot || after.installationType !== journal.installationType || after.stateKey !== journal.stateKey || journal.mode !== "uninstall" || journal.operations.length || journal.completed.length || journal.sourceLock || journal.graphLock || journal.graphLockPath || journal.graphLockRemovePath || journal.stateRemoveKey || journal.workspaceConfigPath || journal.workspaceConfig || !sha.test(audit.planDigest) || !sha.test(journal.baseRevision ?? "") || audit.auditFiles.length !== 1 || audit.runtime.length !== 1 || !audit.inventory.length) {
|
|
6186
6380
|
throw new Error("Invalid metadata-audit transaction; no state was committed.");
|
|
6187
6381
|
}
|
|
6188
6382
|
await assertMetadataStateGuards(journal, after, audit, transport, requireAfter);
|
|
@@ -6193,7 +6387,7 @@ async function assertMetadataAuditGuards(journal, after, transport, requireAfter
|
|
|
6193
6387
|
throw new Error("Metadata-audit content digest is invalid.");
|
|
6194
6388
|
}
|
|
6195
6389
|
try {
|
|
6196
|
-
if (await
|
|
6390
|
+
if (await readFile19(path, "utf8") !== file.content) throw new Error(`Metadata-audit file changed: ${path}`);
|
|
6197
6391
|
} catch (error) {
|
|
6198
6392
|
if (error.code !== "ENOENT" || requireAfter) throw error;
|
|
6199
6393
|
}
|
|
@@ -6235,8 +6429,8 @@ async function assertMetadataStateGuards(journal, after, guards, transport, requ
|
|
|
6235
6429
|
}
|
|
6236
6430
|
async function writeAuditFileExclusive(path, content) {
|
|
6237
6431
|
await assertNoSymlinkPath(path);
|
|
6238
|
-
await mkdir11(
|
|
6239
|
-
await syncMetadataPath(
|
|
6432
|
+
await mkdir11(dirname15(path), { recursive: true });
|
|
6433
|
+
await syncMetadataPath(dirname15(dirname15(path)), true);
|
|
6240
6434
|
const temporary = `${path}.pending-${randomUUID3()}`;
|
|
6241
6435
|
try {
|
|
6242
6436
|
const handle = await open4(temporary, "wx", 384);
|
|
@@ -6249,9 +6443,9 @@ async function writeAuditFileExclusive(path, content) {
|
|
|
6249
6443
|
try {
|
|
6250
6444
|
await link2(temporary, path);
|
|
6251
6445
|
} catch (error) {
|
|
6252
|
-
if (error.code !== "EEXIST" || await
|
|
6446
|
+
if (error.code !== "EEXIST" || await readFile19(path, "utf8") !== content) throw error;
|
|
6253
6447
|
}
|
|
6254
|
-
const directory = await open4(
|
|
6448
|
+
const directory = await open4(dirname15(path), "r");
|
|
6255
6449
|
try {
|
|
6256
6450
|
await directory.sync();
|
|
6257
6451
|
} finally {
|
|
@@ -6710,7 +6904,7 @@ async function assertBaseRevision(plan, transport) {
|
|
|
6710
6904
|
async function assertTargetStateFilePreconditions(plan, transport, graphLockWritePath) {
|
|
6711
6905
|
const expected = plan.targetStateFilePreconditions;
|
|
6712
6906
|
if (!expected) return;
|
|
6713
|
-
if (graphLockWritePath &&
|
|
6907
|
+
if (graphLockWritePath && resolve17(graphLockWritePath) !== resolve17(expected.graphLockPath)) {
|
|
6714
6908
|
throw new Error(
|
|
6715
6909
|
`Graph-lock destination changed after planning: expected ${expected.graphLockPath}, found ${graphLockWritePath}; replan needed.`
|
|
6716
6910
|
);
|
|
@@ -6903,7 +7097,7 @@ async function validateOpenClawConfig(configPath, destPath, transport) {
|
|
|
6903
7097
|
if (!transport.execFile) {
|
|
6904
7098
|
throw new Error(`Cannot validate OpenClaw config over ${transport.description}: transport does not support command execution.`);
|
|
6905
7099
|
}
|
|
6906
|
-
const openClawHome =
|
|
7100
|
+
const openClawHome = dirname15(destPath);
|
|
6907
7101
|
const bundledBin = join13(openClawHome, "npm", "node_modules", ".bin", "openclaw");
|
|
6908
7102
|
const script = String.raw`
|
|
6909
7103
|
set -euo pipefail
|
|
@@ -6954,8 +7148,8 @@ __export(identify_exports, {
|
|
|
6954
7148
|
inferSourceDriverName: () => inferSourceDriverName,
|
|
6955
7149
|
isExplicitSource: () => isExplicitSource
|
|
6956
7150
|
});
|
|
6957
|
-
import { homedir as
|
|
6958
|
-
import { resolve as
|
|
7151
|
+
import { homedir as homedir10 } from "os";
|
|
7152
|
+
import { resolve as resolve24 } from "path";
|
|
6959
7153
|
function inferSourceDriverName(source) {
|
|
6960
7154
|
if (source.startsWith("clawhub:")) return "clawhub";
|
|
6961
7155
|
if (source.startsWith("mcp-registry:")) return "mcp-registry";
|
|
@@ -6973,9 +7167,9 @@ async function isExplicitSource(source) {
|
|
|
6973
7167
|
return pathExists(resolveLocalPath(source));
|
|
6974
7168
|
}
|
|
6975
7169
|
function resolveLocalPath(source) {
|
|
6976
|
-
if (source === "~") return
|
|
6977
|
-
if (source.startsWith("~/")) return
|
|
6978
|
-
return
|
|
7170
|
+
if (source === "~") return homedir10();
|
|
7171
|
+
if (source.startsWith("~/")) return resolve24(homedir10(), source.slice(2));
|
|
7172
|
+
return resolve24(source);
|
|
6979
7173
|
}
|
|
6980
7174
|
var init_identify = __esm({
|
|
6981
7175
|
"src/source/identify.ts"() {
|
|
@@ -6985,11 +7179,11 @@ var init_identify = __esm({
|
|
|
6985
7179
|
});
|
|
6986
7180
|
|
|
6987
7181
|
// src/cli/index.ts
|
|
6988
|
-
import { createHash as
|
|
7182
|
+
import { createHash as createHash29 } from "crypto";
|
|
6989
7183
|
import { existsSync } from "fs";
|
|
6990
7184
|
import { mkdir as mkdir27, mkdtemp as mkdtemp6, readFile as readFile45, realpath as realpath4, rm as rm17, writeFile as writeFile24 } from "fs/promises";
|
|
6991
7185
|
import { homedir as homedir18, tmpdir as tmpdir7 } from "os";
|
|
6992
|
-
import { basename as basename24, dirname as
|
|
7186
|
+
import { basename as basename24, dirname as dirname38, isAbsolute as isAbsolute14, join as join62, relative as relative19, resolve as resolve45 } from "path";
|
|
6993
7187
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
6994
7188
|
import { Command } from "commander";
|
|
6995
7189
|
|
|
@@ -7077,12 +7271,12 @@ init_manifest2();
|
|
|
7077
7271
|
// src/install/plan.ts
|
|
7078
7272
|
init_adapter();
|
|
7079
7273
|
init_manifest();
|
|
7080
|
-
import { basename as basename8, join as join24, relative as
|
|
7274
|
+
import { basename as basename8, join as join24, relative as relative10 } from "path";
|
|
7081
7275
|
|
|
7082
7276
|
// src/staging/codex-subagents.ts
|
|
7083
7277
|
init_fs();
|
|
7084
|
-
import { mkdir as mkdir12, readFile as
|
|
7085
|
-
import { basename as basename4, dirname as
|
|
7278
|
+
import { mkdir as mkdir12, readFile as readFile20, writeFile as writeFile13 } from "fs/promises";
|
|
7279
|
+
import { basename as basename4, dirname as dirname16, join as join14 } from "path";
|
|
7086
7280
|
import { parse as parseYaml } from "yaml";
|
|
7087
7281
|
var requiredCodexAgentFields = ["name", "description", "developer_instructions"];
|
|
7088
7282
|
async function renderCodexSubagents(artifacts, stageRoot, adapter) {
|
|
@@ -7109,7 +7303,7 @@ async function renderCodexSubagent(artifact, stageRoot) {
|
|
|
7109
7303
|
const renderedPath = join14(stageRoot, ".agentwheel-rendered", "codex-subagents", `${agentName}.toml`);
|
|
7110
7304
|
const lowerSourcePath = sourcePath.toLowerCase();
|
|
7111
7305
|
if (artifact.kind === "file" && (artifact.name.toLowerCase().endsWith(".toml") || lowerSourcePath.endsWith(".toml"))) {
|
|
7112
|
-
const content = await
|
|
7306
|
+
const content = await readFile20(sourcePath, "utf8");
|
|
7113
7307
|
validateCodexAgentToml(content, sourcePath);
|
|
7114
7308
|
return {
|
|
7115
7309
|
...artifact,
|
|
@@ -7126,9 +7320,9 @@ async function renderCodexSubagent(artifact, stageRoot) {
|
|
|
7126
7320
|
if (artifact.kind === "file" && !artifact.name.toLowerCase().endsWith(".md") && !lowerSourcePath.endsWith(".md")) {
|
|
7127
7321
|
throw new Error(`Codex subagent ${artifact.relativePath} must be a .toml file, .md file, or directory containing AGENTS.md.`);
|
|
7128
7322
|
}
|
|
7129
|
-
const markdown = await
|
|
7323
|
+
const markdown = await readFile20(markdownPath, "utf8");
|
|
7130
7324
|
const toml = markdownToCodexAgentToml(agentName, markdown);
|
|
7131
|
-
await mkdir12(
|
|
7325
|
+
await mkdir12(dirname16(renderedPath), { recursive: true });
|
|
7132
7326
|
await writeFile13(renderedPath, toml, "utf8");
|
|
7133
7327
|
return {
|
|
7134
7328
|
...artifact,
|
|
@@ -7210,8 +7404,8 @@ function escapeRegExp2(value) {
|
|
|
7210
7404
|
|
|
7211
7405
|
// src/staging/copilot-artifacts.ts
|
|
7212
7406
|
init_fs();
|
|
7213
|
-
import { mkdir as mkdir13, readFile as
|
|
7214
|
-
import { basename as basename5, dirname as
|
|
7407
|
+
import { mkdir as mkdir13, readFile as readFile21, writeFile as writeFile14 } from "fs/promises";
|
|
7408
|
+
import { basename as basename5, dirname as dirname17, join as join15 } from "path";
|
|
7215
7409
|
async function renderCopilotArtifacts(artifacts, stageRoot, adapter) {
|
|
7216
7410
|
if (adapter?.name !== "copilot") return artifacts;
|
|
7217
7411
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -7241,8 +7435,8 @@ async function renderCopilotSubagent(artifact, stageRoot) {
|
|
|
7241
7435
|
if (artifact.kind === "file" && !artifact.name.toLowerCase().endsWith(".md")) {
|
|
7242
7436
|
throw new Error(`Copilot subagent ${artifact.relativePath} must be a .md file or directory containing AGENTS.md.`);
|
|
7243
7437
|
}
|
|
7244
|
-
const markdown = await
|
|
7245
|
-
await mkdir13(
|
|
7438
|
+
const markdown = await readFile21(markdownPath, "utf8");
|
|
7439
|
+
await mkdir13(dirname17(renderedPath), { recursive: true });
|
|
7246
7440
|
await writeFile14(renderedPath, ensureCopilotAgentDescription(agentName, markdown), "utf8");
|
|
7247
7441
|
return {
|
|
7248
7442
|
...artifact,
|
|
@@ -7297,8 +7491,8 @@ function yamlString(value) {
|
|
|
7297
7491
|
|
|
7298
7492
|
// src/staging/openclaw-subagents.ts
|
|
7299
7493
|
init_fs();
|
|
7300
|
-
import { mkdir as mkdir14, readFile as
|
|
7301
|
-
import { basename as basename6, dirname as
|
|
7494
|
+
import { mkdir as mkdir14, readFile as readFile22, writeFile as writeFile15 } from "fs/promises";
|
|
7495
|
+
import { basename as basename6, dirname as dirname18, join as join16 } from "path";
|
|
7302
7496
|
async function renderOpenClawSubagents(artifacts, stageRoot, adapter) {
|
|
7303
7497
|
if (adapter?.name !== "openclaw") return artifacts;
|
|
7304
7498
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -7327,15 +7521,15 @@ async function renderOpenClawSubagent(artifact, stageRoot) {
|
|
|
7327
7521
|
if (artifact.kind === "file" && !artifact.name.toLowerCase().endsWith(".md") && !sourcePath.toLowerCase().endsWith(".md")) {
|
|
7328
7522
|
throw new Error(`OpenClaw subagent ${artifact.relativePath} must be a .md file or directory containing AGENTS.md.`);
|
|
7329
7523
|
}
|
|
7330
|
-
const parsed = splitFrontmatter3(await
|
|
7524
|
+
const parsed = splitFrontmatter3(await readFile22(markdownPath, "utf8"));
|
|
7331
7525
|
const body = parsed.body.trim().length > 0 ? parsed.body.trim() : `# ${titleFromAgentId(agentId)}
|
|
7332
7526
|
|
|
7333
7527
|
${parsed.description ?? `OpenClaw subagent ${agentId}.`}`;
|
|
7334
7528
|
const renderedPath = join16(stageRoot, ".agentwheel-rendered", "openclaw-subagents", agentId, "AGENTS.md");
|
|
7335
|
-
await mkdir14(
|
|
7529
|
+
await mkdir14(dirname18(renderedPath), { recursive: true });
|
|
7336
7530
|
await writeFile15(renderedPath, `${body}
|
|
7337
7531
|
`, "utf8");
|
|
7338
|
-
const renderedDir =
|
|
7532
|
+
const renderedDir = dirname18(renderedPath);
|
|
7339
7533
|
return {
|
|
7340
7534
|
...artifact,
|
|
7341
7535
|
name: agentId,
|
|
@@ -7370,7 +7564,7 @@ import { join as join18 } from "path";
|
|
|
7370
7564
|
|
|
7371
7565
|
// src/targets/plugins/common.ts
|
|
7372
7566
|
init_fs();
|
|
7373
|
-
import { readFile as
|
|
7567
|
+
import { readFile as readFile23 } from "fs/promises";
|
|
7374
7568
|
import { join as join17 } from "path";
|
|
7375
7569
|
import { parseDocument } from "yaml";
|
|
7376
7570
|
function pluginStateRoot(request) {
|
|
@@ -7394,14 +7588,14 @@ function safeNameSegment(value) {
|
|
|
7394
7588
|
async function jsonPluginName(root, relativeManifestPath, fallback) {
|
|
7395
7589
|
const manifestPath = join17(root, relativeManifestPath);
|
|
7396
7590
|
if (!await pathExists(manifestPath)) return fallback;
|
|
7397
|
-
const parsed = JSON.parse(await
|
|
7591
|
+
const parsed = JSON.parse(await readFile23(manifestPath, "utf8"));
|
|
7398
7592
|
return typeof parsed.name === "string" && parsed.name.trim().length > 0 ? parsed.name.trim() : fallback;
|
|
7399
7593
|
}
|
|
7400
7594
|
async function yamlPluginName(root, relativeManifestPaths, fallback) {
|
|
7401
7595
|
for (const relativeManifestPath of relativeManifestPaths) {
|
|
7402
7596
|
const manifestPath = join17(root, relativeManifestPath);
|
|
7403
7597
|
if (!await pathExists(manifestPath)) continue;
|
|
7404
|
-
const document = parseDocument(await
|
|
7598
|
+
const document = parseDocument(await readFile23(manifestPath, "utf8"));
|
|
7405
7599
|
const parsed = document.toJSON();
|
|
7406
7600
|
if (!isRecord5(parsed)) continue;
|
|
7407
7601
|
for (const key of ["name", "module", "package"]) {
|
|
@@ -7534,7 +7728,7 @@ async function hermesPluginSpec(request) {
|
|
|
7534
7728
|
|
|
7535
7729
|
// src/targets/plugins/openclaw.ts
|
|
7536
7730
|
init_fs();
|
|
7537
|
-
import { readFile as
|
|
7731
|
+
import { readFile as readFile24 } from "fs/promises";
|
|
7538
7732
|
import { join as join22 } from "path";
|
|
7539
7733
|
function openClawPluginInstallCommand(request) {
|
|
7540
7734
|
return ["openclaw", "plugins", "install", "--force", request.path];
|
|
@@ -7564,7 +7758,7 @@ async function openClawPluginName(root, fallback) {
|
|
|
7564
7758
|
for (const manifestName of ["plugin.json", "openclaw.plugin.json"]) {
|
|
7565
7759
|
const manifestPath = join22(root, manifestName);
|
|
7566
7760
|
if (!await pathExists(manifestPath)) continue;
|
|
7567
|
-
const parsed = JSON.parse(await
|
|
7761
|
+
const parsed = JSON.parse(await readFile24(manifestPath, "utf8"));
|
|
7568
7762
|
if (typeof parsed.name === "string" && parsed.name.trim().length > 0) return parsed.name.trim();
|
|
7569
7763
|
}
|
|
7570
7764
|
return fallback;
|
|
@@ -7574,7 +7768,7 @@ async function openClawClawHubPluginMetadata(root, fallback) {
|
|
|
7574
7768
|
if (!await pathExists(metadataPath)) {
|
|
7575
7769
|
throw new Error("OpenClaw ClawHub plugins must contain clawhub.json");
|
|
7576
7770
|
}
|
|
7577
|
-
const parsed = JSON.parse(await
|
|
7771
|
+
const parsed = JSON.parse(await readFile24(metadataPath, "utf8"));
|
|
7578
7772
|
const installSpec = stringField(parsed.installSpec);
|
|
7579
7773
|
if (!installSpec?.startsWith("clawhub:")) {
|
|
7580
7774
|
throw new Error("OpenClaw ClawHub plugin metadata must declare installSpec starting with clawhub:");
|
|
@@ -7663,7 +7857,7 @@ function skipWarning(selector, adapter, installationType, artifactType, support)
|
|
|
7663
7857
|
init_adapter();
|
|
7664
7858
|
init_selection();
|
|
7665
7859
|
init_fs();
|
|
7666
|
-
import { readFile as
|
|
7860
|
+
import { readFile as readFile25 } from "fs/promises";
|
|
7667
7861
|
import { basename as basename7, join as join23 } from "path";
|
|
7668
7862
|
import { parseDocument as parseDocument2 } from "yaml";
|
|
7669
7863
|
var behavioralRuleFormats = ["markdown-rule", "claude-markdown-rule", "copilot-instruction-rule"];
|
|
@@ -7868,7 +8062,7 @@ async function validateGenericStructure(artifact, target) {
|
|
|
7868
8062
|
async function validateSkillFrontmatter(artifact, skillMdPath) {
|
|
7869
8063
|
let content;
|
|
7870
8064
|
try {
|
|
7871
|
-
content = await
|
|
8065
|
+
content = await readFile25(skillMdPath, "utf8");
|
|
7872
8066
|
} catch (error) {
|
|
7873
8067
|
return [{ artifact, message: `could not read SKILL.md: ${errorMessage(error)}` }];
|
|
7874
8068
|
}
|
|
@@ -7938,7 +8132,7 @@ async function validateHermesPlugin(artifact) {
|
|
|
7938
8132
|
return [{ artifact, message: "Hermes plugins must contain plugin.yaml or plugin.yml" }];
|
|
7939
8133
|
}
|
|
7940
8134
|
try {
|
|
7941
|
-
const document = parseDocument2(await
|
|
8135
|
+
const document = parseDocument2(await readFile25(manifestPath, "utf8"));
|
|
7942
8136
|
if (document.errors.length > 0) {
|
|
7943
8137
|
return [{ artifact, message: `Hermes ${basename7(manifestPath)} must be valid YAML: ${document.errors[0]?.message ?? "parse error"}` }];
|
|
7944
8138
|
}
|
|
@@ -7962,7 +8156,7 @@ async function firstExistingPath(paths) {
|
|
|
7962
8156
|
}
|
|
7963
8157
|
async function parseJsonPluginManifest(manifestPath, label) {
|
|
7964
8158
|
try {
|
|
7965
|
-
const parsed = JSON.parse(await
|
|
8159
|
+
const parsed = JSON.parse(await readFile25(manifestPath, "utf8"));
|
|
7966
8160
|
if (!isRecord6(parsed)) {
|
|
7967
8161
|
return { ok: false, message: `${label} ${basename7(manifestPath)} must be a JSON object` };
|
|
7968
8162
|
}
|
|
@@ -8009,7 +8203,7 @@ async function validateOpenClawClawHubPlugin(artifact) {
|
|
|
8009
8203
|
return [{ artifact, message: "OpenClaw ClawHub plugins must contain clawhub.json" }];
|
|
8010
8204
|
}
|
|
8011
8205
|
try {
|
|
8012
|
-
const parsed = JSON.parse(await
|
|
8206
|
+
const parsed = JSON.parse(await readFile25(metadataPath, "utf8"));
|
|
8013
8207
|
if (!isRecord6(parsed)) {
|
|
8014
8208
|
return [{ artifact, message: "OpenClaw ClawHub clawhub.json must be a JSON object" }];
|
|
8015
8209
|
}
|
|
@@ -8033,7 +8227,7 @@ async function openClawPluginManifestPaths(artifact) {
|
|
|
8033
8227
|
async function parseOpenClawPluginManifest(manifestPath) {
|
|
8034
8228
|
const manifestName = basename7(manifestPath);
|
|
8035
8229
|
try {
|
|
8036
|
-
const parsed = JSON.parse(await
|
|
8230
|
+
const parsed = JSON.parse(await readFile25(manifestPath, "utf8"));
|
|
8037
8231
|
if (!isRecord6(parsed)) {
|
|
8038
8232
|
return { ok: false, path: manifestPath, message: `OpenClaw ${manifestName} must be a JSON object` };
|
|
8039
8233
|
}
|
|
@@ -8050,7 +8244,7 @@ async function parseJsonObjectArtifact(artifact) {
|
|
|
8050
8244
|
return { ok: false, message: "merge artifacts must be JSON files" };
|
|
8051
8245
|
}
|
|
8052
8246
|
try {
|
|
8053
|
-
const parsed = JSON.parse(await
|
|
8247
|
+
const parsed = JSON.parse(await readFile25(artifactPath(artifact), "utf8"));
|
|
8054
8248
|
if (!isRecord6(parsed)) return { ok: false, message: "merge artifacts must contain a JSON object" };
|
|
8055
8249
|
return { ok: true, value: parsed };
|
|
8056
8250
|
} catch (error) {
|
|
@@ -8062,7 +8256,7 @@ async function parseYamlObjectArtifact(artifact) {
|
|
|
8062
8256
|
return { ok: false, message: "merge artifacts must be YAML files" };
|
|
8063
8257
|
}
|
|
8064
8258
|
try {
|
|
8065
|
-
const document = parseDocument2(await
|
|
8259
|
+
const document = parseDocument2(await readFile25(artifactPath(artifact), "utf8"));
|
|
8066
8260
|
if (document.errors.length > 0) {
|
|
8067
8261
|
return { ok: false, message: `merge artifact must be valid YAML: ${document.errors[0]?.message ?? "parse error"}` };
|
|
8068
8262
|
}
|
|
@@ -8784,7 +8978,7 @@ async function operationForArtifact(artifact, adapter, targetRoot, installationT
|
|
|
8784
8978
|
kind: "file",
|
|
8785
8979
|
sourcePath: artifact.stagedPath ?? artifact.sourcePath,
|
|
8786
8980
|
destPath: destPath2,
|
|
8787
|
-
relativeDestPath:
|
|
8981
|
+
relativeDestPath: relative10(targetRoot, destPath2).replaceAll("\\", "/"),
|
|
8788
8982
|
desiredHash: artifact.hash,
|
|
8789
8983
|
reason: "destination missing",
|
|
8790
8984
|
channel: artifact.channel ?? "managed",
|
|
@@ -8802,7 +8996,7 @@ async function operationForArtifact(artifact, adapter, targetRoot, installationT
|
|
|
8802
8996
|
kind: artifact.kind,
|
|
8803
8997
|
sourcePath: artifact.stagedPath ?? artifact.sourcePath,
|
|
8804
8998
|
destPath,
|
|
8805
|
-
relativeDestPath:
|
|
8999
|
+
relativeDestPath: relative10(targetRoot, destPath).replaceAll("\\", "/"),
|
|
8806
9000
|
desiredHash: artifact.hash,
|
|
8807
9001
|
reason: "destination missing",
|
|
8808
9002
|
channel: artifact.channel ?? "managed",
|
|
@@ -9799,14 +9993,14 @@ async function writeMermaidAsset(response) {
|
|
|
9799
9993
|
"content-type": "application/javascript; charset=utf-8",
|
|
9800
9994
|
"cache-control": "public, max-age=3600"
|
|
9801
9995
|
});
|
|
9802
|
-
await new Promise((
|
|
9996
|
+
await new Promise((resolve46) => {
|
|
9803
9997
|
const stream = createReadStream(assetPath);
|
|
9804
9998
|
stream.on("error", () => {
|
|
9805
9999
|
if (!response.headersSent) writeText(response, 404, "Mermaid asset unavailable.\n");
|
|
9806
10000
|
else response.destroy();
|
|
9807
|
-
|
|
10001
|
+
resolve46();
|
|
9808
10002
|
});
|
|
9809
|
-
stream.on("end",
|
|
10003
|
+
stream.on("end", resolve46);
|
|
9810
10004
|
stream.pipe(response);
|
|
9811
10005
|
});
|
|
9812
10006
|
}
|
|
@@ -9833,14 +10027,14 @@ function escapeHtml2(value) {
|
|
|
9833
10027
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
9834
10028
|
}
|
|
9835
10029
|
function listen(server, port, bind) {
|
|
9836
|
-
return new Promise((
|
|
10030
|
+
return new Promise((resolve46, reject) => {
|
|
9837
10031
|
const onError = (error) => {
|
|
9838
10032
|
server.off("listening", onListening);
|
|
9839
10033
|
reject(error);
|
|
9840
10034
|
};
|
|
9841
10035
|
const onListening = () => {
|
|
9842
10036
|
server.off("error", onError);
|
|
9843
|
-
|
|
10037
|
+
resolve46();
|
|
9844
10038
|
};
|
|
9845
10039
|
server.once("error", onError);
|
|
9846
10040
|
server.once("listening", onListening);
|
|
@@ -9848,7 +10042,7 @@ function listen(server, port, bind) {
|
|
|
9848
10042
|
});
|
|
9849
10043
|
}
|
|
9850
10044
|
function waitForShutdown(server, beforeClose) {
|
|
9851
|
-
return new Promise((
|
|
10045
|
+
return new Promise((resolve46) => {
|
|
9852
10046
|
let closing = false;
|
|
9853
10047
|
const shutdown = () => {
|
|
9854
10048
|
if (closing) return;
|
|
@@ -9856,7 +10050,7 @@ function waitForShutdown(server, beforeClose) {
|
|
|
9856
10050
|
process.off("SIGINT", shutdown);
|
|
9857
10051
|
process.off("SIGTERM", shutdown);
|
|
9858
10052
|
beforeClose();
|
|
9859
|
-
server.close(() =>
|
|
10053
|
+
server.close(() => resolve46());
|
|
9860
10054
|
};
|
|
9861
10055
|
process.once("SIGINT", shutdown);
|
|
9862
10056
|
process.once("SIGTERM", shutdown);
|
|
@@ -9866,7 +10060,7 @@ function waitForShutdown(server, beforeClose) {
|
|
|
9866
10060
|
process.off("SIGINT", shutdown);
|
|
9867
10061
|
process.off("SIGTERM", shutdown);
|
|
9868
10062
|
beforeClose();
|
|
9869
|
-
|
|
10063
|
+
resolve46();
|
|
9870
10064
|
});
|
|
9871
10065
|
});
|
|
9872
10066
|
}
|
|
@@ -9885,13 +10079,13 @@ function errorMessage2(error) {
|
|
|
9885
10079
|
|
|
9886
10080
|
// src/source/clawhub.ts
|
|
9887
10081
|
import { mkdir as mkdir15, rm as rm8, writeFile as writeFile16 } from "fs/promises";
|
|
9888
|
-
import { basename as basename10, dirname as
|
|
10082
|
+
import { basename as basename10, dirname as dirname19, join as join28, resolve as resolve19 } from "path";
|
|
9889
10083
|
|
|
9890
10084
|
// src/model/package.ts
|
|
9891
10085
|
init_artifact();
|
|
9892
10086
|
init_fs();
|
|
9893
10087
|
init_artifact();
|
|
9894
|
-
import { readFile as
|
|
10088
|
+
import { readFile as readFile26 } from "fs/promises";
|
|
9895
10089
|
import { join as join26 } from "path";
|
|
9896
10090
|
import { parse as parse4, printParseErrorCode as printParseErrorCode2 } from "jsonc-parser";
|
|
9897
10091
|
import { z as z11 } from "zod";
|
|
@@ -9999,7 +10193,7 @@ async function findPackageManifestPath(root, options = {}) {
|
|
|
9999
10193
|
async function readPackageManifest(root) {
|
|
10000
10194
|
const path = await findPackageManifestPath(root);
|
|
10001
10195
|
if (!path) return void 0;
|
|
10002
|
-
const content = await
|
|
10196
|
+
const content = await readFile26(path, "utf8");
|
|
10003
10197
|
const errors = [];
|
|
10004
10198
|
const parsed = parse4(content, errors, { allowTrailingComma: true, disallowComments: false });
|
|
10005
10199
|
if (errors.length > 0) {
|
|
@@ -10079,12 +10273,12 @@ init_fs();
|
|
|
10079
10273
|
// src/source/local.ts
|
|
10080
10274
|
import { createHash as createHash13 } from "crypto";
|
|
10081
10275
|
import { readdir as readdir6, stat as stat5 } from "fs/promises";
|
|
10082
|
-
import { basename as basename9, join as join27, relative as
|
|
10276
|
+
import { basename as basename9, join as join27, relative as relative11, resolve as resolve18 } from "path";
|
|
10083
10277
|
init_fs();
|
|
10084
10278
|
var LocalSourceDriver = class {
|
|
10085
10279
|
name = "local";
|
|
10086
10280
|
async resolve(source) {
|
|
10087
|
-
const resolvedPath =
|
|
10281
|
+
const resolvedPath = resolve18(source);
|
|
10088
10282
|
if (!await pathExists(resolvedPath)) {
|
|
10089
10283
|
throw new Error(`Local source not found: ${resolvedPath}`);
|
|
10090
10284
|
}
|
|
@@ -10224,7 +10418,7 @@ async function hashLocalSource(root, manifest) {
|
|
|
10224
10418
|
const manifestPath = await findPackageManifestPath(root, { warnLegacy: false });
|
|
10225
10419
|
if (manifestPath) {
|
|
10226
10420
|
hash2.update("manifest\0");
|
|
10227
|
-
hash2.update(
|
|
10421
|
+
hash2.update(relative11(root, manifestPath).replaceAll("\\", "/")).update("\0");
|
|
10228
10422
|
hash2.update(await hashPath(manifestPath)).update("\0");
|
|
10229
10423
|
}
|
|
10230
10424
|
const provides = [...manifest.provides].sort((a, b) => `${a.type}\0${a.path}`.localeCompare(`${b.type}\0${b.path}`));
|
|
@@ -10426,7 +10620,7 @@ async function fetchClawHubPackage(fetchImpl, packageName) {
|
|
|
10426
10620
|
throw new Error(`ClawHub lookup failed for ${packageName}`);
|
|
10427
10621
|
}
|
|
10428
10622
|
async function delay(ms) {
|
|
10429
|
-
await new Promise((
|
|
10623
|
+
await new Promise((resolve46) => setTimeout(resolve46, ms));
|
|
10430
10624
|
}
|
|
10431
10625
|
function parseClawHubSource(source) {
|
|
10432
10626
|
if (!source.startsWith(sourcePrefix)) {
|
|
@@ -10458,7 +10652,7 @@ async function writeGeneratedPackage(root, packageInfo) {
|
|
|
10458
10652
|
};
|
|
10459
10653
|
const pluginPath = join28(root, "plugins", pluginId, "clawhub.json");
|
|
10460
10654
|
await rm8(root, { recursive: true, force: true });
|
|
10461
|
-
await mkdir15(
|
|
10655
|
+
await mkdir15(dirname19(pluginPath), { recursive: true });
|
|
10462
10656
|
await writeFile16(join28(root, "openpack.json"), `${JSON.stringify({
|
|
10463
10657
|
schemaVersion: CURRENT_OPENPACK_SCHEMA_VERSION,
|
|
10464
10658
|
name: `clawhub/${name}`,
|
|
@@ -10482,7 +10676,7 @@ function installNameFor2(value) {
|
|
|
10482
10676
|
return basename10(value).replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "clawhub-plugin";
|
|
10483
10677
|
}
|
|
10484
10678
|
function cachePathFor(packageName, cacheRoot) {
|
|
10485
|
-
const root = cacheRoot ?
|
|
10679
|
+
const root = cacheRoot ? resolve19(cacheRoot) : join28(process.env.HOME ?? ".", ".agentwheel", "cache");
|
|
10486
10680
|
const slug2 = `clawhub-${packageName}`.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "");
|
|
10487
10681
|
return join28(root, slug2 || "clawhub-package");
|
|
10488
10682
|
}
|
|
@@ -10490,14 +10684,14 @@ function cachePathFor(packageName, cacheRoot) {
|
|
|
10490
10684
|
// src/source/git.ts
|
|
10491
10685
|
import { execFile as execFile5 } from "child_process";
|
|
10492
10686
|
import { mkdir as mkdir17, rename as rename6, rm as rm10, stat as stat7 } from "fs/promises";
|
|
10493
|
-
import { homedir as
|
|
10494
|
-
import { basename as basename11, dirname as
|
|
10687
|
+
import { homedir as homedir8 } from "os";
|
|
10688
|
+
import { basename as basename11, dirname as dirname21, join as join31, resolve as resolve20, sep as sep6 } from "path";
|
|
10495
10689
|
import { promisify as promisify5 } from "util";
|
|
10496
10690
|
init_fs();
|
|
10497
10691
|
|
|
10498
10692
|
// src/source/auth.ts
|
|
10499
|
-
import { readFile as
|
|
10500
|
-
import { homedir as
|
|
10693
|
+
import { readFile as readFile27 } from "fs/promises";
|
|
10694
|
+
import { homedir as homedir7 } from "os";
|
|
10501
10695
|
import { join as join29 } from "path";
|
|
10502
10696
|
var AUTH_CONFIG_ENV = "AGENTWHEEL_AUTH_CONFIG";
|
|
10503
10697
|
async function gitAuthArguments(url) {
|
|
@@ -10520,9 +10714,9 @@ async function matchingGitAuthProfile(url) {
|
|
|
10520
10714
|
);
|
|
10521
10715
|
}
|
|
10522
10716
|
async function readGitAuthConfig() {
|
|
10523
|
-
const path = process.env[AUTH_CONFIG_ENV] ?? join29(
|
|
10717
|
+
const path = process.env[AUTH_CONFIG_ENV] ?? join29(homedir7(), ".agentwheel", "auth.json");
|
|
10524
10718
|
try {
|
|
10525
|
-
const parsed = JSON.parse(await
|
|
10719
|
+
const parsed = JSON.parse(await readFile27(path, "utf8"));
|
|
10526
10720
|
return parseGitAuthConfig(parsed, path);
|
|
10527
10721
|
} catch (error) {
|
|
10528
10722
|
if (isMissingFile(error)) return void 0;
|
|
@@ -10573,8 +10767,8 @@ function isMissingFile(error) {
|
|
|
10573
10767
|
// src/source/cache.ts
|
|
10574
10768
|
init_fs();
|
|
10575
10769
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
10576
|
-
import { mkdir as mkdir16, readdir as readdir7, readFile as
|
|
10577
|
-
import { dirname as
|
|
10770
|
+
import { mkdir as mkdir16, readdir as readdir7, readFile as readFile28, rm as rm9, stat as stat6, writeFile as writeFile17 } from "fs/promises";
|
|
10771
|
+
import { dirname as dirname20, join as join30 } from "path";
|
|
10578
10772
|
var snapshotNamePattern = /^(.*)-([0-9a-f]{12})$/i;
|
|
10579
10773
|
var leaseMarker = ".agentwheel-lease-";
|
|
10580
10774
|
async function pruneGitCache(cacheRoot, options = {}) {
|
|
@@ -10605,7 +10799,7 @@ async function withGitCacheMaintenanceLock(cacheRoot, timeoutMs, fn) {
|
|
|
10605
10799
|
if (Date.now() - started > timeoutMs) {
|
|
10606
10800
|
throw new Error(`Timed out waiting for git cache maintenance lock at ${lockPath}`);
|
|
10607
10801
|
}
|
|
10608
|
-
await new Promise((
|
|
10802
|
+
await new Promise((resolve46) => setTimeout(resolve46, 50));
|
|
10609
10803
|
}
|
|
10610
10804
|
}
|
|
10611
10805
|
try {
|
|
@@ -10642,7 +10836,7 @@ async function removeGeneratedEntries(root, preserveGit) {
|
|
|
10642
10836
|
}
|
|
10643
10837
|
}
|
|
10644
10838
|
async function pruneGitCacheUnlocked(cacheRoot, options) {
|
|
10645
|
-
const referencedCommits = await referencedGraphLockCommits(join30(
|
|
10839
|
+
const referencedCommits = await referencedGraphLockCommits(join30(dirname20(cacheRoot), "locks"));
|
|
10646
10840
|
const entries = await readdir7(cacheRoot, { withFileTypes: true });
|
|
10647
10841
|
const groups = /* @__PURE__ */ new Map();
|
|
10648
10842
|
for (const entry of entries) {
|
|
@@ -10701,7 +10895,7 @@ async function walkGraphLocks(root, visit) {
|
|
|
10701
10895
|
await walkGraphLocks(path, visit);
|
|
10702
10896
|
} else if (entry.isFile() && entry.name.endsWith(".graph-lock.json")) {
|
|
10703
10897
|
try {
|
|
10704
|
-
visit(JSON.parse(await
|
|
10898
|
+
visit(JSON.parse(await readFile28(path, "utf8")));
|
|
10705
10899
|
} catch (error) {
|
|
10706
10900
|
throw new Error(`Cannot read graph lock ${path}; cache prune aborted: ${errorMessage3(error)}`);
|
|
10707
10901
|
}
|
|
@@ -10709,7 +10903,7 @@ async function walkGraphLocks(root, visit) {
|
|
|
10709
10903
|
}
|
|
10710
10904
|
}
|
|
10711
10905
|
async function hasLiveSnapshotLease(snapshotPath, dryRun) {
|
|
10712
|
-
const directory =
|
|
10906
|
+
const directory = dirname20(snapshotPath);
|
|
10713
10907
|
const prefix = `${snapshotPath.slice(directory.length + 1)}${leaseMarker}`;
|
|
10714
10908
|
const entries = await readdir7(directory, { withFileTypes: true });
|
|
10715
10909
|
let live = false;
|
|
@@ -10717,7 +10911,7 @@ async function hasLiveSnapshotLease(snapshotPath, dryRun) {
|
|
|
10717
10911
|
if (!entry.isFile() || !entry.name.startsWith(prefix)) continue;
|
|
10718
10912
|
const leasePath = join30(directory, entry.name);
|
|
10719
10913
|
try {
|
|
10720
|
-
const value = JSON.parse(await
|
|
10914
|
+
const value = JSON.parse(await readFile28(leasePath, "utf8"));
|
|
10721
10915
|
if (typeof value.pid !== "number" || !Number.isSafeInteger(value.pid) || value.pid <= 0) {
|
|
10722
10916
|
live = true;
|
|
10723
10917
|
} else if (isProcessAlive2(value.pid)) {
|
|
@@ -10733,7 +10927,7 @@ async function hasLiveSnapshotLease(snapshotPath, dryRun) {
|
|
|
10733
10927
|
}
|
|
10734
10928
|
async function removeStaleMaintenanceLock(lockPath) {
|
|
10735
10929
|
try {
|
|
10736
|
-
const value = JSON.parse(await
|
|
10930
|
+
const value = JSON.parse(await readFile28(join30(lockPath, "owner.json"), "utf8"));
|
|
10737
10931
|
if (typeof value.pid !== "number" || !Number.isSafeInteger(value.pid) || value.pid <= 0 || isProcessAlive2(value.pid)) {
|
|
10738
10932
|
return false;
|
|
10739
10933
|
}
|
|
@@ -10848,7 +11042,7 @@ var GitSourceDriver = class {
|
|
|
10848
11042
|
async fetch(resolved) {
|
|
10849
11043
|
return withFilesystemLock(`${resolved.resolvedPath}.lock`, resolved.cacheLockTimeoutMs ?? 3e4, async () => {
|
|
10850
11044
|
const parsed = parseGitSource(resolved.source);
|
|
10851
|
-
const cacheRoot =
|
|
11045
|
+
const cacheRoot = dirname21(resolved.resolvedPath);
|
|
10852
11046
|
await mkdir17(cacheRoot, { recursive: true });
|
|
10853
11047
|
await assertOwnedByCurrentUser(cacheRoot);
|
|
10854
11048
|
if (await pathExists(resolved.resolvedPath)) await assertOwnedByCurrentUser(resolved.resolvedPath);
|
|
@@ -10922,7 +11116,7 @@ async function isDirectory(path) {
|
|
|
10922
11116
|
}
|
|
10923
11117
|
}
|
|
10924
11118
|
function cachePathFor2(url, cacheRoot) {
|
|
10925
|
-
const root = cacheRoot ?
|
|
11119
|
+
const root = cacheRoot ? resolve20(cacheRoot) : join31(homedir8(), ".agentwheel", "cache");
|
|
10926
11120
|
const slug2 = url.replace(/^[a-z]+:\/\//i, "").replace(/\.git$/i, "").replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "");
|
|
10927
11121
|
return join31(root, slug2 || basename11(url));
|
|
10928
11122
|
}
|
|
@@ -10943,9 +11137,9 @@ async function resolveCommit(checkoutPath, ref) {
|
|
|
10943
11137
|
throw lastError;
|
|
10944
11138
|
}
|
|
10945
11139
|
async function snapshotCommit(checkoutPath, commit) {
|
|
10946
|
-
const snapshotPath = join31(
|
|
11140
|
+
const snapshotPath = join31(dirname21(checkoutPath), `${basename11(checkoutPath)}-${commit.slice(0, 12)}`);
|
|
10947
11141
|
if (await pathExists(snapshotPath)) return snapshotPath;
|
|
10948
|
-
const tempPath = join31(
|
|
11142
|
+
const tempPath = join31(dirname21(checkoutPath), `${basename11(snapshotPath)}.tmp-${process.pid}-${Date.now()}`);
|
|
10949
11143
|
const tempIndexPath = `${tempPath}.index`;
|
|
10950
11144
|
await rm10(tempPath, { recursive: true, force: true });
|
|
10951
11145
|
await rm10(tempIndexPath, { force: true });
|
|
@@ -10953,7 +11147,7 @@ async function snapshotCommit(checkoutPath, commit) {
|
|
|
10953
11147
|
const env2 = { ...process.env, GIT_INDEX_FILE: tempIndexPath };
|
|
10954
11148
|
try {
|
|
10955
11149
|
await git(["-C", checkoutPath, "read-tree", commit], env2);
|
|
10956
|
-
await git(["-C", checkoutPath, "checkout-index", "--all", `--prefix=${
|
|
11150
|
+
await git(["-C", checkoutPath, "checkout-index", "--all", `--prefix=${resolve20(tempPath)}${sep6}`], env2);
|
|
10957
11151
|
await removeGeneratedEntries(tempPath, false);
|
|
10958
11152
|
} catch (error) {
|
|
10959
11153
|
await rm10(tempPath, { recursive: true, force: true });
|
|
@@ -10983,7 +11177,7 @@ async function assertOwnedByCurrentUser(path) {
|
|
|
10983
11177
|
|
|
10984
11178
|
// src/source/mcp-registry.ts
|
|
10985
11179
|
import { mkdir as mkdir18, writeFile as writeFile18 } from "fs/promises";
|
|
10986
|
-
import { basename as basename12, dirname as
|
|
11180
|
+
import { basename as basename12, dirname as dirname22, join as join32, resolve as resolve21 } from "path";
|
|
10987
11181
|
init_fs();
|
|
10988
11182
|
var registryBaseUrl = "https://registry.modelcontextprotocol.io/v0.1";
|
|
10989
11183
|
var sourcePrefix2 = "mcp-registry:";
|
|
@@ -11091,7 +11285,7 @@ function isSafeHttpUrl(value) {
|
|
|
11091
11285
|
async function writeGeneratedPackage2(root, server) {
|
|
11092
11286
|
const serverId = installNameFor3(server.serverName);
|
|
11093
11287
|
const mcpPath = join32(root, "mcp", `${serverId}.json`);
|
|
11094
|
-
await mkdir18(
|
|
11288
|
+
await mkdir18(dirname22(mcpPath), { recursive: true });
|
|
11095
11289
|
await writeFile18(join32(root, "openpack.json"), `${JSON.stringify({
|
|
11096
11290
|
schemaVersion: CURRENT_OPENPACK_SCHEMA_VERSION,
|
|
11097
11291
|
name: `mcp-registry/${server.serverName}`,
|
|
@@ -11113,7 +11307,7 @@ function installNameFor3(serverName) {
|
|
|
11113
11307
|
return basename12(serverName).replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "mcp-server";
|
|
11114
11308
|
}
|
|
11115
11309
|
function cachePathFor3(serverName, cacheRoot) {
|
|
11116
|
-
const root = cacheRoot ?
|
|
11310
|
+
const root = cacheRoot ? resolve21(cacheRoot) : join32(process.env.HOME ?? ".", ".agentwheel", "cache");
|
|
11117
11311
|
const slug2 = `mcp-registry-${serverName}`.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "");
|
|
11118
11312
|
return join32(root, slug2 || "mcp-registry-server");
|
|
11119
11313
|
}
|
|
@@ -11123,16 +11317,16 @@ init_cache_identity();
|
|
|
11123
11317
|
init_fs();
|
|
11124
11318
|
import { createHash as createHash14, randomUUID as randomUUID5 } from "crypto";
|
|
11125
11319
|
import { execFile as execFile6 } from "child_process";
|
|
11126
|
-
import { cp as cp3, mkdir as mkdir19, readFile as
|
|
11127
|
-
import { homedir as
|
|
11128
|
-
import { basename as basename14, dirname as
|
|
11320
|
+
import { cp as cp3, mkdir as mkdir19, readFile as readFile29, rename as rename7, rm as rm11 } from "fs/promises";
|
|
11321
|
+
import { homedir as homedir9 } from "os";
|
|
11322
|
+
import { basename as basename14, dirname as dirname24, join as join34, resolve as resolve22 } from "path";
|
|
11129
11323
|
import { promisify as promisify6 } from "util";
|
|
11130
11324
|
import * as defaultSkillKit from "@skillkit/core";
|
|
11131
11325
|
|
|
11132
11326
|
// src/source/skill-artifacts.ts
|
|
11133
11327
|
init_fs();
|
|
11134
11328
|
import { readdir as readdir8, stat as stat8 } from "fs/promises";
|
|
11135
|
-
import { basename as basename13, dirname as
|
|
11329
|
+
import { basename as basename13, dirname as dirname23, extname as extname2, join as join33 } from "path";
|
|
11136
11330
|
async function artifactsFromSkillPaths(paths, packageName) {
|
|
11137
11331
|
const artifacts = [];
|
|
11138
11332
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -11169,7 +11363,7 @@ async function artifactFromSkillPath(item, packageName) {
|
|
|
11169
11363
|
};
|
|
11170
11364
|
}
|
|
11171
11365
|
if (stats.isFile() && basename13(item.path).toLowerCase() === "skill.md") {
|
|
11172
|
-
const dir =
|
|
11366
|
+
const dir = dirname23(item.path);
|
|
11173
11367
|
const name = sanitizeSkillName(item.name ?? basename13(dir));
|
|
11174
11368
|
return {
|
|
11175
11369
|
type: "skills",
|
|
@@ -11225,7 +11419,7 @@ var SkillKitSourceDriver = class {
|
|
|
11225
11419
|
async resolve(source, options = {}) {
|
|
11226
11420
|
const spec = parseSkillKitSource(source);
|
|
11227
11421
|
if (await pathExists(spec)) {
|
|
11228
|
-
const resolvedPath =
|
|
11422
|
+
const resolvedPath = resolve22(spec);
|
|
11229
11423
|
return {
|
|
11230
11424
|
driver: this.name,
|
|
11231
11425
|
source,
|
|
@@ -11277,7 +11471,7 @@ var SkillKitSourceDriver = class {
|
|
|
11277
11471
|
sourceHash: await hashPath(resolved.resolvedPath)
|
|
11278
11472
|
};
|
|
11279
11473
|
}
|
|
11280
|
-
const specCachePath = cachePathFor4(spec,
|
|
11474
|
+
const specCachePath = cachePathFor4(spec, dirname24(dirname24(resolved.resolvedPath)));
|
|
11281
11475
|
const refIdentity = resolved.requestedRef ?? "default";
|
|
11282
11476
|
const lockPath = `${specCachePath}.ref-${createHash14("sha256").update(refIdentity).digest("hex")}.lock`;
|
|
11283
11477
|
const inflightKey = `${lockPath}\0${requestedCommit ?? "movable"}`;
|
|
@@ -11298,11 +11492,11 @@ var SkillKitSourceDriver = class {
|
|
|
11298
11492
|
throw new Error("SkillKit provider API unavailable or cannot resolve source. Expected @skillkit/core detectProvider().clone().");
|
|
11299
11493
|
}
|
|
11300
11494
|
const materialized = await withFilesystemLock(lockPath, resolved.cacheLockTimeoutMs ?? 3e4, async () => {
|
|
11301
|
-
const immutablePath = requestedCommit ? cachePathFor4(spec,
|
|
11495
|
+
const immutablePath = requestedCommit ? cachePathFor4(spec, dirname24(dirname24(specCachePath)), requestedCommit) : void 0;
|
|
11302
11496
|
if (immutablePath && await pathExists(immutablePath)) {
|
|
11303
11497
|
return { path: immutablePath, commit: requestedCommit, cacheIdentity: requestedCommit };
|
|
11304
11498
|
}
|
|
11305
|
-
await mkdir19(
|
|
11499
|
+
await mkdir19(dirname24(specCachePath), { recursive: true });
|
|
11306
11500
|
const candidatePath = `${specCachePath}.agentwheel-tmp-${process.pid}-${randomUUID5()}`;
|
|
11307
11501
|
const publishPath = `${candidatePath}.publish`;
|
|
11308
11502
|
let result;
|
|
@@ -11324,11 +11518,11 @@ var SkillKitSourceDriver = class {
|
|
|
11324
11518
|
`SkillKit provider resolved ${resolvedIdentity.commit ?? "non-Git content"} instead of requested commit ${requestedCommit}`
|
|
11325
11519
|
);
|
|
11326
11520
|
}
|
|
11327
|
-
const cachePath = cachePathFor4(spec,
|
|
11521
|
+
const cachePath = cachePathFor4(spec, dirname24(dirname24(specCachePath)), resolvedIdentity.cacheKey);
|
|
11328
11522
|
if (await pathExists(cachePath)) {
|
|
11329
11523
|
return { path: cachePath, commit: resolvedIdentity.commit, cacheIdentity: resolvedIdentity.cacheKey };
|
|
11330
11524
|
}
|
|
11331
|
-
const publishCandidate =
|
|
11525
|
+
const publishCandidate = resolve22(result.path) === resolve22(candidatePath) ? candidatePath : publishPath;
|
|
11332
11526
|
if (publishCandidate === publishPath) await cp3(result.path, publishPath, { recursive: true, dereference: true });
|
|
11333
11527
|
try {
|
|
11334
11528
|
await rename7(publishCandidate, cachePath);
|
|
@@ -11382,7 +11576,7 @@ var SkillKitSourceDriver = class {
|
|
|
11382
11576
|
for (const skill of this.discover(resolved.resolvedPath)) {
|
|
11383
11577
|
const skillMd = join34(skill.path, "SKILL.md");
|
|
11384
11578
|
if (await pathExists(skillMd)) {
|
|
11385
|
-
this.core.translateSkill(await
|
|
11579
|
+
this.core.translateSkill(await readFile29(skillMd, "utf8"), "openclaw", { sourceFilename: "SKILL.md" });
|
|
11386
11580
|
}
|
|
11387
11581
|
}
|
|
11388
11582
|
return resolved;
|
|
@@ -11411,7 +11605,7 @@ function normalizeProviderSource(spec) {
|
|
|
11411
11605
|
return spec;
|
|
11412
11606
|
}
|
|
11413
11607
|
function cachePathFor4(spec, cacheRoot, immutableIdentity) {
|
|
11414
|
-
const root = cacheRoot ?
|
|
11608
|
+
const root = cacheRoot ? resolve22(cacheRoot) : join34(homedir9(), ".agentwheel", "cache");
|
|
11415
11609
|
const sourceIdentity = createHash14("sha256").update(spec).digest("hex");
|
|
11416
11610
|
const snapshotIdentity = immutableIdentity ? `-${immutableIdentity.toLowerCase()}` : "";
|
|
11417
11611
|
return join34(root, "skillkit", `${packageSlug(spec)}-${sourceIdentity}${snapshotIdentity}`);
|
|
@@ -11458,14 +11652,14 @@ async function checkoutCommit(root, commit) {
|
|
|
11458
11652
|
// src/source/vercel-skills.ts
|
|
11459
11653
|
init_fs();
|
|
11460
11654
|
import { stat as stat9 } from "fs/promises";
|
|
11461
|
-
import { basename as basename15, join as join35, relative as
|
|
11655
|
+
import { basename as basename15, join as join35, relative as relative12, resolve as resolve23 } from "path";
|
|
11462
11656
|
var VercelSkillsSourceDriver = class {
|
|
11463
11657
|
name = "vercel-skills";
|
|
11464
11658
|
git = new GitSourceDriver();
|
|
11465
11659
|
async resolve(source, options = {}) {
|
|
11466
11660
|
const parsed = parseVercelSource(source);
|
|
11467
11661
|
if (parsed.kind === "local") {
|
|
11468
|
-
const resolvedPath =
|
|
11662
|
+
const resolvedPath = resolve23(parsed.path);
|
|
11469
11663
|
if (!await pathExists(resolvedPath) || !(await stat9(resolvedPath)).isDirectory()) {
|
|
11470
11664
|
throw new Error(`Vercel skills local source not found: ${resolvedPath}`);
|
|
11471
11665
|
}
|
|
@@ -11525,7 +11719,7 @@ async function resolveVercelSkillSubpath(root, subpath) {
|
|
|
11525
11719
|
for (const candidate of candidates) {
|
|
11526
11720
|
if (await pathExists(candidate)) return candidate;
|
|
11527
11721
|
}
|
|
11528
|
-
const tried = candidates.map((candidate) =>
|
|
11722
|
+
const tried = candidates.map((candidate) => relative12(root, candidate)).join(", ");
|
|
11529
11723
|
throw new Error(`Vercel skills subpath not found: ${subpath} (tried ${tried})`);
|
|
11530
11724
|
}
|
|
11531
11725
|
function parseVercelSource(source) {
|
|
@@ -11595,7 +11789,7 @@ init_identify();
|
|
|
11595
11789
|
|
|
11596
11790
|
// src/staging/staging.ts
|
|
11597
11791
|
import { chmod as chmod3, cp as cp5, mkdir as mkdir22, mkdtemp as mkdtemp4, readdir as readdir11, stat as stat12 } from "fs/promises";
|
|
11598
|
-
import { basename as basename19, dirname as
|
|
11792
|
+
import { basename as basename19, dirname as dirname28, join as join39, relative as relative14, resolve as resolve26, sep as sep8 } from "path";
|
|
11599
11793
|
import { tmpdir as tmpdir5 } from "os";
|
|
11600
11794
|
init_fs();
|
|
11601
11795
|
|
|
@@ -11603,8 +11797,8 @@ init_fs();
|
|
|
11603
11797
|
init_artifact();
|
|
11604
11798
|
init_fs();
|
|
11605
11799
|
import { createHash as createHash15 } from "crypto";
|
|
11606
|
-
import { readdir as readdir9, readFile as
|
|
11607
|
-
import { basename as basename16, dirname as
|
|
11800
|
+
import { readdir as readdir9, readFile as readFile30, stat as stat10, writeFile as writeFile19 } from "fs/promises";
|
|
11801
|
+
import { basename as basename16, dirname as dirname25, extname as extname3, join as join36, relative as relative13, resolve as resolve25, sep as sep7 } from "path";
|
|
11608
11802
|
var includePattern = /<!--\s*openpack:include(\?)?\s+([^>]+?)\s*-->/g;
|
|
11609
11803
|
var escapedIncludePattern = /<!--\s*openpack\\:include(\?)?\s+([^>]+?)\s*-->/g;
|
|
11610
11804
|
var generatedPattern = /<!--\s*(?:BEGIN|END)\s+openpack:include\b/;
|
|
@@ -11650,7 +11844,7 @@ async function validateMarkdownIncludes(artifacts, packageRoot, options = {}) {
|
|
|
11650
11844
|
}
|
|
11651
11845
|
}
|
|
11652
11846
|
async function expandFile(file, packageRoot, appendEntries, artifactPaths, options) {
|
|
11653
|
-
const raw = await
|
|
11847
|
+
const raw = await readFile30(file, "utf8");
|
|
11654
11848
|
const owner = ownerSelector(packageRoot, file, options.nodeId);
|
|
11655
11849
|
const expanded = await expandContent(raw, packageRoot, [owner], artifactPaths, options);
|
|
11656
11850
|
let content = expanded.content;
|
|
@@ -11752,14 +11946,14 @@ async function expandInclude(selector, packageRoot, artifactPaths, options) {
|
|
|
11752
11946
|
if (!stats.isFile()) {
|
|
11753
11947
|
throw new Error(`OpenPack include is not a file: ${displaySelector}`);
|
|
11754
11948
|
}
|
|
11755
|
-
const raw = sourceContent ?? await
|
|
11949
|
+
const raw = sourceContent ?? await readFile30(sourcePath, "utf8");
|
|
11756
11950
|
const { optional: _optional, markers: _markers, chain: _chain, ...childOptions } = options;
|
|
11757
11951
|
const expanded = await expandContent(raw, includePackageRoot, [...options.chain, displaySelector], includeArtifactPaths, {
|
|
11758
11952
|
...childOptions,
|
|
11759
11953
|
nodeId: includeNodeId
|
|
11760
11954
|
});
|
|
11761
11955
|
const contentHash = sha2563(expanded.content);
|
|
11762
|
-
const identity = `${includeNodeId ??
|
|
11956
|
+
const identity = `${includeNodeId ?? resolve25(includePackageRoot)}\0${parsed.selector}\0${contentHash}`;
|
|
11763
11957
|
const ownEntry = { selector: displaySelector, hash: contentHash };
|
|
11764
11958
|
const composedFrom = uniqueComposedFrom([ownEntry, ...expanded.composedFrom]);
|
|
11765
11959
|
if (!options.markers) return { rendered: expanded.content, composedFrom, identity };
|
|
@@ -11812,8 +12006,8 @@ function extractOpenPackIncludeSelectors(content) {
|
|
|
11812
12006
|
return selectors;
|
|
11813
12007
|
}
|
|
11814
12008
|
function resolvePackageSelector(packageRoot, selector) {
|
|
11815
|
-
const root =
|
|
11816
|
-
const resolved =
|
|
12009
|
+
const root = resolve25(packageRoot);
|
|
12010
|
+
const resolved = resolve25(root, selector);
|
|
11817
12011
|
if (resolved !== root && !resolved.startsWith(`${root}${sep7}`)) {
|
|
11818
12012
|
throw new Error(`OpenPack include escapes package root: ${selector}`);
|
|
11819
12013
|
}
|
|
@@ -11843,12 +12037,12 @@ async function listMarkdownFiles(root) {
|
|
|
11843
12037
|
}
|
|
11844
12038
|
function composeEntriesForFile(artifact, file) {
|
|
11845
12039
|
if (!artifact.compose?.length) return [];
|
|
11846
|
-
if (artifact.kind === "file") return [
|
|
11847
|
-
return basename16(file) === "SKILL.md" &&
|
|
12040
|
+
if (artifact.kind === "file") return [resolve25(artifact.stagedPath ?? artifact.sourcePath), resolve25(file)].every(Boolean) && resolve25(artifact.stagedPath ?? artifact.sourcePath) === resolve25(file) ? artifact.compose : [];
|
|
12041
|
+
return basename16(file) === "SKILL.md" && dirname25(file) === resolve25(artifact.stagedPath ?? artifact.sourcePath) ? artifact.compose : [];
|
|
11848
12042
|
}
|
|
11849
12043
|
function isPrimaryMarkdownFile(artifact, file) {
|
|
11850
|
-
if (artifact.kind === "file") return
|
|
11851
|
-
return basename16(file) === "SKILL.md" &&
|
|
12044
|
+
if (artifact.kind === "file") return resolve25(artifact.stagedPath ?? artifact.sourcePath) === resolve25(file);
|
|
12045
|
+
return basename16(file) === "SKILL.md" && dirname25(file) === resolve25(artifact.stagedPath ?? artifact.sourcePath);
|
|
11852
12046
|
}
|
|
11853
12047
|
function orderedForExpansion(artifacts) {
|
|
11854
12048
|
return [...artifacts].sort((a, b) => Number(a.type === "fragments") - Number(b.type === "fragments"));
|
|
@@ -11865,7 +12059,7 @@ function applyReplacements(content, replacements) {
|
|
|
11865
12059
|
return out + content.slice(cursor);
|
|
11866
12060
|
}
|
|
11867
12061
|
function relativeSelector(root, file) {
|
|
11868
|
-
return
|
|
12062
|
+
return relative13(root, file).replaceAll("\\", "/");
|
|
11869
12063
|
}
|
|
11870
12064
|
function ownerSelector(root, file, nodeId) {
|
|
11871
12065
|
const selector = relativeSelector(root, file);
|
|
@@ -11895,8 +12089,8 @@ function artifactPathMap(artifacts) {
|
|
|
11895
12089
|
|
|
11896
12090
|
// src/staging/customize.ts
|
|
11897
12091
|
init_fs();
|
|
11898
|
-
import { cp as cp4, mkdir as mkdir20, readdir as readdir10, readFile as
|
|
11899
|
-
import { dirname as
|
|
12092
|
+
import { cp as cp4, mkdir as mkdir20, readdir as readdir10, readFile as readFile31, writeFile as writeFile20 } from "fs/promises";
|
|
12093
|
+
import { dirname as dirname26, join as join37 } from "path";
|
|
11900
12094
|
async function applyCustomizations(artifacts, options) {
|
|
11901
12095
|
let next = [...artifacts];
|
|
11902
12096
|
next = await applyReplacements2(next, options, "override", installableArtifactTypes());
|
|
@@ -11917,10 +12111,10 @@ async function applyInstructionOverlay(artifacts, options) {
|
|
|
11917
12111
|
const index = artifacts.findIndex((artifact2) => artifact2.type === "instructions");
|
|
11918
12112
|
if (index < 0) return artifacts;
|
|
11919
12113
|
const artifact = artifacts[index];
|
|
11920
|
-
const managed = await
|
|
11921
|
-
const local = await
|
|
12114
|
+
const managed = await readFile31(artifact.stagedPath ?? artifact.sourcePath, "utf8");
|
|
12115
|
+
const local = await readFile31(overlayPath, "utf8");
|
|
11922
12116
|
const composedPath = join37(options.stageRoot, ".agentwheel-composed", "instructions", "AGENTS.md");
|
|
11923
|
-
await mkdir20(
|
|
12117
|
+
await mkdir20(dirname26(composedPath), { recursive: true });
|
|
11924
12118
|
await writeFile20(
|
|
11925
12119
|
composedPath,
|
|
11926
12120
|
[
|
|
@@ -11993,7 +12187,7 @@ async function applyReplacements2(artifacts, options, channel, artifactTypes) {
|
|
|
11993
12187
|
const artifactKind = entry.isDirectory() ? "dir" : "file";
|
|
11994
12188
|
const existing = byKey.get(artifactMapKey);
|
|
11995
12189
|
const stagedPath = join37(options.stageRoot, ".agentwheel-composed", channel, type, entry.name);
|
|
11996
|
-
await mkdir20(
|
|
12190
|
+
await mkdir20(dirname26(stagedPath), { recursive: true });
|
|
11997
12191
|
await cp4(full, stagedPath, { recursive: artifactKind === "dir", dereference: true });
|
|
11998
12192
|
byKey.set(artifactMapKey, {
|
|
11999
12193
|
...existing,
|
|
@@ -12038,8 +12232,8 @@ async function sortedDirEntries2(path) {
|
|
|
12038
12232
|
|
|
12039
12233
|
// src/staging/claude-subagents.ts
|
|
12040
12234
|
init_fs();
|
|
12041
|
-
import { mkdir as mkdir21, readFile as
|
|
12042
|
-
import { basename as basename18, dirname as
|
|
12235
|
+
import { mkdir as mkdir21, readFile as readFile32, writeFile as writeFile21 } from "fs/promises";
|
|
12236
|
+
import { basename as basename18, dirname as dirname27, join as join38 } from "path";
|
|
12043
12237
|
async function renderClaudeSubagents(artifacts, stageRoot, adapter) {
|
|
12044
12238
|
if (adapter?.name !== "claude") return artifacts;
|
|
12045
12239
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -12068,9 +12262,9 @@ async function renderClaudeSubagent(artifact, stageRoot) {
|
|
|
12068
12262
|
if (artifact.kind === "file" && !artifact.name.toLowerCase().endsWith(".md") && !sourcePath.toLowerCase().endsWith(".md")) {
|
|
12069
12263
|
throw new Error(`Claude subagent ${artifact.relativePath} must be a .md file or directory containing AGENTS.md.`);
|
|
12070
12264
|
}
|
|
12071
|
-
const content = await
|
|
12265
|
+
const content = await readFile32(markdownPath, "utf8");
|
|
12072
12266
|
const renderedPath = join38(stageRoot, ".agentwheel-rendered", "claude-subagents", `${agentName}.md`);
|
|
12073
|
-
await mkdir21(
|
|
12267
|
+
await mkdir21(dirname27(renderedPath), { recursive: true });
|
|
12074
12268
|
await writeFile21(renderedPath, content.endsWith("\n") ? content : `${content}
|
|
12075
12269
|
`, "utf8");
|
|
12076
12270
|
return {
|
|
@@ -12113,7 +12307,7 @@ async function stageResolvedArtifactsRaw(resolved, artifacts, parentDir = tmpdir
|
|
|
12113
12307
|
await removeOnFailure(root, async () => {
|
|
12114
12308
|
for (const artifact of artifacts) {
|
|
12115
12309
|
const stagedPath = join39(root, artifact.relativePath);
|
|
12116
|
-
await mkdir22(
|
|
12310
|
+
await mkdir22(dirname28(stagedPath), { recursive: true });
|
|
12117
12311
|
await cp5(artifact.sourcePath, stagedPath, {
|
|
12118
12312
|
recursive: artifact.kind === "dir",
|
|
12119
12313
|
dereference: true,
|
|
@@ -12219,25 +12413,25 @@ async function copyAsset(asset, source, dest) {
|
|
|
12219
12413
|
throw new Error(`Asset include source is not a file or directory: ${source}`);
|
|
12220
12414
|
}
|
|
12221
12415
|
if (!asset.include?.length) {
|
|
12222
|
-
await mkdir22(
|
|
12416
|
+
await mkdir22(dirname28(dest), { recursive: true });
|
|
12223
12417
|
await cp5(source, dest, { recursive: true, dereference: true });
|
|
12224
12418
|
if (asset.mode === "copy") await normalizeCopiedModes(dest);
|
|
12225
12419
|
return;
|
|
12226
12420
|
}
|
|
12227
12421
|
for (const file of await listFiles2(source)) {
|
|
12228
|
-
const rel =
|
|
12422
|
+
const rel = relative14(source, file).replaceAll("\\", "/");
|
|
12229
12423
|
if (!matchesAny(rel, asset.include) && !matchesAny(basename19(file), asset.include)) continue;
|
|
12230
12424
|
await copyAssetFile(file, join39(dest, rel), asset);
|
|
12231
12425
|
}
|
|
12232
12426
|
}
|
|
12233
12427
|
async function copyAssetFile(source, dest, asset) {
|
|
12234
|
-
await mkdir22(
|
|
12428
|
+
await mkdir22(dirname28(dest), { recursive: true });
|
|
12235
12429
|
await cp5(source, dest, { dereference: true });
|
|
12236
12430
|
if (asset.mode === "copy") await chmod3(dest, 420);
|
|
12237
12431
|
}
|
|
12238
12432
|
function resolvePackagePath(packageRoot, path) {
|
|
12239
|
-
const resolved =
|
|
12240
|
-
const root =
|
|
12433
|
+
const resolved = resolve26(packageRoot, path);
|
|
12434
|
+
const root = resolve26(packageRoot);
|
|
12241
12435
|
if (resolved !== root && !resolved.startsWith(`${root}${sep8}`)) {
|
|
12242
12436
|
throw new Error(`Asset include escapes package root: ${path}`);
|
|
12243
12437
|
}
|
|
@@ -12286,12 +12480,12 @@ init_adapters();
|
|
|
12286
12480
|
init_adapter();
|
|
12287
12481
|
init_artifact();
|
|
12288
12482
|
init_workspace();
|
|
12289
|
-
import { appendFile, cp as cp6, lstat as
|
|
12290
|
-
import { dirname as
|
|
12483
|
+
import { appendFile, cp as cp6, lstat as lstat4, mkdir as mkdir23, readdir as readdir13, rm as rm13 } from "fs/promises";
|
|
12484
|
+
import { dirname as dirname30, join as join42, relative as relative15 } from "path";
|
|
12291
12485
|
|
|
12292
12486
|
// src/resolve/graph.ts
|
|
12293
12487
|
import { createHash as createHash17 } from "crypto";
|
|
12294
|
-
import { readdir as readdir12, readFile as
|
|
12488
|
+
import { readdir as readdir12, readFile as readFile35, stat as stat14 } from "fs/promises";
|
|
12295
12489
|
import { basename as basename20, extname as extname4, join as join41 } from "path";
|
|
12296
12490
|
init_artifact();
|
|
12297
12491
|
init_fs();
|
|
@@ -12302,7 +12496,7 @@ init_workspace();
|
|
|
12302
12496
|
init_selection();
|
|
12303
12497
|
init_fs();
|
|
12304
12498
|
import { createHash as createHash16 } from "crypto";
|
|
12305
|
-
import { readFile as
|
|
12499
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
12306
12500
|
import { z as z12 } from "zod";
|
|
12307
12501
|
var selectionSourceConfigSchema = z12.object({
|
|
12308
12502
|
schemaVersion: z12.literal(2),
|
|
@@ -12321,7 +12515,7 @@ async function resolveSelectionImport(sourceRoot, sourceDriver, selection) {
|
|
|
12321
12515
|
}
|
|
12322
12516
|
let raw;
|
|
12323
12517
|
try {
|
|
12324
|
-
raw = JSON.parse(await
|
|
12518
|
+
raw = JSON.parse(await readFile33(path, "utf8"));
|
|
12325
12519
|
} catch (error) {
|
|
12326
12520
|
const message = error instanceof Error ? error.message : String(error);
|
|
12327
12521
|
throw new Error(`Selection import '${parsedSelection.export}' cannot parse ${path}: ${message}`);
|
|
@@ -12385,17 +12579,17 @@ function resolveExport(name, selections, stack) {
|
|
|
12385
12579
|
}
|
|
12386
12580
|
function applySelection(inherited, additions, exclusions) {
|
|
12387
12581
|
const excluded = new Set(exclusions);
|
|
12388
|
-
return
|
|
12582
|
+
return sortedUnique4([...inherited, ...additions]).filter((selector) => !excluded.has(selector));
|
|
12389
12583
|
}
|
|
12390
12584
|
function normalizeSelectors(values, label) {
|
|
12391
12585
|
try {
|
|
12392
|
-
return
|
|
12586
|
+
return sortedUnique4(normalizeArtifactSelectors(values) ?? []);
|
|
12393
12587
|
} catch (error) {
|
|
12394
12588
|
const message = error instanceof Error ? error.message : String(error);
|
|
12395
12589
|
throw new Error(`Invalid ${label}: ${message}`);
|
|
12396
12590
|
}
|
|
12397
12591
|
}
|
|
12398
|
-
function
|
|
12592
|
+
function sortedUnique4(values) {
|
|
12399
12593
|
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
|
|
12400
12594
|
}
|
|
12401
12595
|
function sha2564(value) {
|
|
@@ -12419,13 +12613,13 @@ function isRecord9(value) {
|
|
|
12419
12613
|
}
|
|
12420
12614
|
|
|
12421
12615
|
// src/resolve/identity.ts
|
|
12422
|
-
import { homedir as
|
|
12423
|
-
import { resolve as
|
|
12616
|
+
import { homedir as homedir12 } from "os";
|
|
12617
|
+
import { resolve as resolve28 } from "path";
|
|
12424
12618
|
|
|
12425
12619
|
// src/registry/client.ts
|
|
12426
|
-
import { readFile as
|
|
12427
|
-
import { homedir as
|
|
12428
|
-
import { dirname as
|
|
12620
|
+
import { readFile as readFile34, rm as rm12, stat as stat13 } from "fs/promises";
|
|
12621
|
+
import { homedir as homedir11 } from "os";
|
|
12622
|
+
import { dirname as dirname29, join as join40, resolve as resolve27 } from "path";
|
|
12429
12623
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12430
12624
|
|
|
12431
12625
|
// src/model/registry.ts
|
|
@@ -12525,7 +12719,7 @@ var RegistryClient = class {
|
|
|
12525
12719
|
}
|
|
12526
12720
|
async readCache() {
|
|
12527
12721
|
if (!await pathExists(this.cachePath)) return void 0;
|
|
12528
|
-
return registryCacheSchema.parse(JSON.parse(await
|
|
12722
|
+
return registryCacheSchema.parse(JSON.parse(await readFile34(this.cachePath, "utf8")));
|
|
12529
12723
|
}
|
|
12530
12724
|
isExpired(cache, ttlMs) {
|
|
12531
12725
|
return this.now().getTime() - new Date(cache.fetchedAt).getTime() > ttlMs;
|
|
@@ -12542,12 +12736,12 @@ var RegistryClient = class {
|
|
|
12542
12736
|
}
|
|
12543
12737
|
const filePath = source.startsWith("file:") ? fileURLToPath2(source) : source;
|
|
12544
12738
|
if (await pathExists(filePath)) {
|
|
12545
|
-
const fullPath =
|
|
12739
|
+
const fullPath = resolve27(filePath);
|
|
12546
12740
|
const stats = await stat13(fullPath);
|
|
12547
|
-
return
|
|
12741
|
+
return readFile34(stats.isDirectory() ? join40(fullPath, "index.json") : fullPath, "utf8");
|
|
12548
12742
|
}
|
|
12549
|
-
const resolved = await this.git.fetch(await this.git.resolve(source, { cacheRoot: join40(
|
|
12550
|
-
return
|
|
12743
|
+
const resolved = await this.git.fetch(await this.git.resolve(source, { cacheRoot: join40(dirname29(this.cachePath), "registry-repos") }));
|
|
12744
|
+
return readFile34(join40(resolved.resolvedPath, "index.json"), "utf8");
|
|
12551
12745
|
}
|
|
12552
12746
|
warnCompatibility(entries) {
|
|
12553
12747
|
for (const entry of entries) {
|
|
@@ -12585,7 +12779,7 @@ function mergeIndexes(indexes) {
|
|
|
12585
12779
|
return [...merged.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
12586
12780
|
}
|
|
12587
12781
|
function defaultRegistryCachePath() {
|
|
12588
|
-
return join40(
|
|
12782
|
+
return join40(homedir11(), ".agentwheel", "registry-cache.json");
|
|
12589
12783
|
}
|
|
12590
12784
|
function sameSources(a, b) {
|
|
12591
12785
|
return a.length === b.length && a.every((source, index) => source === b[index]);
|
|
@@ -12682,10 +12876,10 @@ function localSourcePath(source) {
|
|
|
12682
12876
|
return source.startsWith("local:") ? source.slice("local:".length) : source;
|
|
12683
12877
|
}
|
|
12684
12878
|
function resolveLocalPath2(path, declaringPackageRoot) {
|
|
12685
|
-
if (path === "~") return
|
|
12686
|
-
if (path.startsWith("~/")) return
|
|
12687
|
-
if (path.startsWith("/")) return
|
|
12688
|
-
return
|
|
12879
|
+
if (path === "~") return homedir12();
|
|
12880
|
+
if (path.startsWith("~/")) return resolve28(homedir12(), path.slice(2));
|
|
12881
|
+
if (path.startsWith("/")) return resolve28(path);
|
|
12882
|
+
return resolve28(declaringPackageRoot, path);
|
|
12689
12883
|
}
|
|
12690
12884
|
async function normalizeRegistrySource(name, options) {
|
|
12691
12885
|
const client = options.registryClient ?? new RegistryClient({ workspaceRoot: options.workspaceRoot });
|
|
@@ -12784,7 +12978,7 @@ async function resolveDependencyGraph(roots, options) {
|
|
|
12784
12978
|
optional: false,
|
|
12785
12979
|
chain: [`workspace:${rootId}`],
|
|
12786
12980
|
includeSuggestions: root.includeSuggestions ?? options.includeSuggestions,
|
|
12787
|
-
suggestionAliases:
|
|
12981
|
+
suggestionAliases: sortedUnique5([...root.suggestionAliases ?? [], ...options.suggestionAliases ?? []])
|
|
12788
12982
|
};
|
|
12789
12983
|
});
|
|
12790
12984
|
const requiredQueue = rootRequirements();
|
|
@@ -13005,7 +13199,7 @@ Run without ${lockLabel === "Offline" ? "--offline" : "--frozen-lock"} first.`
|
|
|
13005
13199
|
version: requirement.version,
|
|
13006
13200
|
mode: requirement.mode,
|
|
13007
13201
|
optional: requirement.optional,
|
|
13008
|
-
selected:
|
|
13202
|
+
selected: sortedUnique5([...previous?.selected ?? [], ...selected])
|
|
13009
13203
|
});
|
|
13010
13204
|
}
|
|
13011
13205
|
return await collectDependencyNeeds(state, fetched, options, requirement.chain);
|
|
@@ -13075,7 +13269,7 @@ async function collectDependencyNeeds(state, fetched, options, chain) {
|
|
|
13075
13269
|
fetched,
|
|
13076
13270
|
parsed.alias,
|
|
13077
13271
|
dependency,
|
|
13078
|
-
|
|
13272
|
+
sortedUnique5([...dependency.select ?? [], parsed.selector]),
|
|
13079
13273
|
chain,
|
|
13080
13274
|
options,
|
|
13081
13275
|
parsed.optional || dependency.optional === true,
|
|
@@ -13127,7 +13321,7 @@ async function collectDependencyNeeds(state, fetched, options, chain) {
|
|
|
13127
13321
|
fetched,
|
|
13128
13322
|
include.alias,
|
|
13129
13323
|
dependency,
|
|
13130
|
-
|
|
13324
|
+
sortedUnique5([...dependency.select ?? [], include.selector]),
|
|
13131
13325
|
chain,
|
|
13132
13326
|
options,
|
|
13133
13327
|
include.optional || dependency.optional === true
|
|
@@ -13160,7 +13354,7 @@ function dependencyRequirement(state, fetched, alias, dependency, select, chain,
|
|
|
13160
13354
|
integrity: dependency.integrity,
|
|
13161
13355
|
selectionReason,
|
|
13162
13356
|
includeSuggestions: state.includeSuggestions,
|
|
13163
|
-
suggestionAliases:
|
|
13357
|
+
suggestionAliases: sortedUnique5([...state.suggestionAliases])
|
|
13164
13358
|
};
|
|
13165
13359
|
}
|
|
13166
13360
|
function suggestionRequirement(state, fetched, alias, suggestion, select, chain, options, optional = shouldTreatSuggestionAsOptional(alias, suggestion, options), selectionReason) {
|
|
@@ -13177,7 +13371,7 @@ function suggestionRequirement(state, fetched, alias, suggestion, select, chain,
|
|
|
13177
13371
|
);
|
|
13178
13372
|
}
|
|
13179
13373
|
function assertDependencyUpdateSelectors(lock, selectors) {
|
|
13180
|
-
for (const selector of
|
|
13374
|
+
for (const selector of sortedUnique5(selectors ?? [])) {
|
|
13181
13375
|
if (!lock) throw new Error(`Dependency update '${selector}' requires an existing graph lock.`);
|
|
13182
13376
|
const nodeIds = matchingDependencyUpdateNodeIds(lock, selector);
|
|
13183
13377
|
if (nodeIds.size === 0) throw new Error(`Tracking dependency not found in graph lock: ${selector}`);
|
|
@@ -13231,7 +13425,7 @@ function suggestionForAlias(suggestions, nodeId, alias) {
|
|
|
13231
13425
|
return suggestion;
|
|
13232
13426
|
}
|
|
13233
13427
|
function warnNoDepsOnce(state, aliases, warn) {
|
|
13234
|
-
const unique =
|
|
13428
|
+
const unique = sortedUnique5(aliases.filter(Boolean));
|
|
13235
13429
|
if (unique.length === 0 || state.processedPackageAliases.has("__noDepsWarned")) return;
|
|
13236
13430
|
state.processedPackageAliases.add("__noDepsWarned");
|
|
13237
13431
|
warn?.(`--no-deps ignored dependencies for ${state.node.id}: ${unique.join(", ")}`);
|
|
@@ -13272,7 +13466,7 @@ function suggestionOptionsForState(state, options) {
|
|
|
13272
13466
|
return {
|
|
13273
13467
|
...options,
|
|
13274
13468
|
includeSuggestions: state.includeSuggestions || options.includeSuggestions === true,
|
|
13275
|
-
suggestionAliases:
|
|
13469
|
+
suggestionAliases: sortedUnique5([...options.suggestionAliases ?? [], ...state.suggestionAliases])
|
|
13276
13470
|
};
|
|
13277
13471
|
}
|
|
13278
13472
|
function explicitSuggestionAlias(alias, options) {
|
|
@@ -13284,7 +13478,7 @@ function shouldTreatSuggestionAsOptional(alias, suggestion, options) {
|
|
|
13284
13478
|
}
|
|
13285
13479
|
function combinedSelectors(base, extra) {
|
|
13286
13480
|
const values = [...base ?? [], ...extra ?? []];
|
|
13287
|
-
return values.length > 0 ?
|
|
13481
|
+
return values.length > 0 ? sortedUnique5(values) : void 0;
|
|
13288
13482
|
}
|
|
13289
13483
|
function parseDependencySelector(value) {
|
|
13290
13484
|
const cleaned = value.trim();
|
|
@@ -13324,7 +13518,7 @@ async function collectIncludeNeeds(artifact, artifactsByRelativePath) {
|
|
|
13324
13518
|
const file = stack.shift();
|
|
13325
13519
|
if (scanned.has(file)) continue;
|
|
13326
13520
|
scanned.add(file);
|
|
13327
|
-
const content = await
|
|
13521
|
+
const content = await readFile35(file, "utf8");
|
|
13328
13522
|
for (const include of extractOpenPackIncludeSelectors(content)) {
|
|
13329
13523
|
await collectIncludeSelector(include.raw, include.optional, artifactsByRelativePath, scanned, stack, needs);
|
|
13330
13524
|
}
|
|
@@ -13473,7 +13667,7 @@ function lockedNodeCoversRequirementSelection(node, requirement, options) {
|
|
|
13473
13667
|
return false;
|
|
13474
13668
|
}
|
|
13475
13669
|
const requestedExclusionSet = new Set(requestedExclusions);
|
|
13476
|
-
const requestedEffective =
|
|
13670
|
+
const requestedEffective = sortedUnique5([...lockedSelection2.inherited, ...requestedAdditions]).filter((selector) => !requestedExclusionSet.has(selector));
|
|
13477
13671
|
const lockedSelectors = new Set(node.selected);
|
|
13478
13672
|
return requestedEffective.every((selector) => lockedSelectors.has(selector));
|
|
13479
13673
|
}
|
|
@@ -13548,8 +13742,8 @@ function verifyIntegrity(integrity, sourceHash, label) {
|
|
|
13548
13742
|
async function withCachePathLock(path, fn) {
|
|
13549
13743
|
const previous = cacheLocks.get(path) ?? Promise.resolve();
|
|
13550
13744
|
let release = () => void 0;
|
|
13551
|
-
const current = previous.then(() => new Promise((
|
|
13552
|
-
release =
|
|
13745
|
+
const current = previous.then(() => new Promise((resolve46) => {
|
|
13746
|
+
release = resolve46;
|
|
13553
13747
|
}));
|
|
13554
13748
|
cacheLocks.set(path, current);
|
|
13555
13749
|
await previous;
|
|
@@ -13562,7 +13756,7 @@ async function withCachePathLock(path, fn) {
|
|
|
13562
13756
|
}
|
|
13563
13757
|
function computeSelectedSelectors(artifacts, select, isRoot, chain) {
|
|
13564
13758
|
if (isRoot && select === void 0) {
|
|
13565
|
-
return
|
|
13759
|
+
return sortedUnique5(artifacts.map(artifactSelectorKey));
|
|
13566
13760
|
}
|
|
13567
13761
|
const explicit = normalizeArtifactSelectors(select) ?? [];
|
|
13568
13762
|
const available = new Set(artifacts.map(artifactSelectorKey));
|
|
@@ -13571,7 +13765,7 @@ function computeSelectedSelectors(artifacts, select, isRoot, chain) {
|
|
|
13571
13765
|
throw new Error(`Selected artifact not found in package: ${missing.join(", ")} (${chain.join(" -> ")})`);
|
|
13572
13766
|
}
|
|
13573
13767
|
const required = artifacts.filter((artifact) => artifact.required && artifact.type !== "fragments").map(artifactSelectorKey);
|
|
13574
|
-
return
|
|
13768
|
+
return sortedUnique5([...explicit, ...required]);
|
|
13575
13769
|
}
|
|
13576
13770
|
function materializeRawNode(state) {
|
|
13577
13771
|
refreshNode(state);
|
|
@@ -13584,11 +13778,11 @@ function materializeRawNode(state) {
|
|
|
13584
13778
|
};
|
|
13585
13779
|
}
|
|
13586
13780
|
function refreshNode(state) {
|
|
13587
|
-
state.node.requiredBy =
|
|
13588
|
-
state.node.selected =
|
|
13781
|
+
state.node.requiredBy = sortedUnique5([...state.requiredBy]);
|
|
13782
|
+
state.node.selected = sortedUnique5([...state.selected]);
|
|
13589
13783
|
const selectionReasons = {};
|
|
13590
13784
|
for (const [selector, reasons] of [...state.selectionReasons.entries()].sort(([a], [b]) => a.localeCompare(b))) {
|
|
13591
|
-
selectionReasons[selector] =
|
|
13785
|
+
selectionReasons[selector] = sortedUnique5([...reasons]);
|
|
13592
13786
|
}
|
|
13593
13787
|
state.node.selectionReasons = Object.keys(selectionReasons).length > 0 ? selectionReasons : void 0;
|
|
13594
13788
|
}
|
|
@@ -13633,7 +13827,7 @@ function graphNodeId(name, version, normalizedSource, resolvedCommit, sourceHash
|
|
|
13633
13827
|
const digest3 = createHash17("sha256").update(normalizedSource).update("\0").update(resolvedCommit ?? sourceHash).digest("hex").slice(0, 12);
|
|
13634
13828
|
return `${name}@${version}+${digest3}`;
|
|
13635
13829
|
}
|
|
13636
|
-
function
|
|
13830
|
+
function sortedUnique5(values) {
|
|
13637
13831
|
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
|
|
13638
13832
|
}
|
|
13639
13833
|
function closureProcessingKey(value, updateClosure) {
|
|
@@ -13673,7 +13867,7 @@ init_declarations();
|
|
|
13673
13867
|
async function remember(workspaceRoot, runtime, text) {
|
|
13674
13868
|
const overlayPath = join42(workspaceRoot, ".agentwheel", "overlays", runtime, "instructions.local.md");
|
|
13675
13869
|
declareMutationPath(overlayPath);
|
|
13676
|
-
await mkdir23(
|
|
13870
|
+
await mkdir23(dirname30(overlayPath), { recursive: true });
|
|
13677
13871
|
await appendFile(overlayPath, `${text.trim()}
|
|
13678
13872
|
`, "utf8");
|
|
13679
13873
|
return { overlayPath };
|
|
@@ -13701,12 +13895,12 @@ async function ejectArtifact(workspaceRoot, item) {
|
|
|
13701
13895
|
for (const path of await listFilesIfPresent(ejectedPath)) declareMutationPath(path);
|
|
13702
13896
|
if (artifact.kind === "dir") {
|
|
13703
13897
|
for (const sourceFile of await listFiles3(sourcePath)) {
|
|
13704
|
-
declareMutationPath(join42(ejectedPath,
|
|
13898
|
+
declareMutationPath(join42(ejectedPath, relative15(sourcePath, sourceFile)));
|
|
13705
13899
|
}
|
|
13706
13900
|
} else {
|
|
13707
13901
|
declareMutationPath(ejectedPath);
|
|
13708
13902
|
}
|
|
13709
|
-
await mkdir23(
|
|
13903
|
+
await mkdir23(dirname30(ejectedPath), { recursive: true });
|
|
13710
13904
|
await rm13(ejectedPath, { recursive: true, force: true });
|
|
13711
13905
|
await cp6(sourcePath, ejectedPath, { recursive: artifact.kind === "dir", dereference: true });
|
|
13712
13906
|
return {
|
|
@@ -13722,7 +13916,7 @@ async function ejectArtifact(workspaceRoot, item) {
|
|
|
13722
13916
|
}
|
|
13723
13917
|
}
|
|
13724
13918
|
async function listFiles3(root) {
|
|
13725
|
-
const stats = await
|
|
13919
|
+
const stats = await lstat4(root);
|
|
13726
13920
|
if (stats.isFile()) return [root];
|
|
13727
13921
|
const files = [];
|
|
13728
13922
|
async function walk2(dir) {
|
|
@@ -13825,7 +14019,7 @@ init_adapter();
|
|
|
13825
14019
|
init_graph_lock();
|
|
13826
14020
|
import { createHash as createHash19 } from "crypto";
|
|
13827
14021
|
import { mkdir as mkdir25, readdir as readdir14 } from "fs/promises";
|
|
13828
|
-
import { basename as basename21, dirname as
|
|
14022
|
+
import { basename as basename21, dirname as dirname32, join as join45, posix as posix6, resolve as resolve31 } from "path";
|
|
13829
14023
|
init_paths();
|
|
13830
14024
|
init_merge_removal();
|
|
13831
14025
|
init_transaction();
|
|
@@ -13992,7 +14186,7 @@ function formatSelectionImport(root) {
|
|
|
13992
14186
|
// src/resolve/render.ts
|
|
13993
14187
|
init_selection();
|
|
13994
14188
|
import { createHash as createHash18 } from "crypto";
|
|
13995
|
-
import { readFile as
|
|
14189
|
+
import { readFile as readFile36, mkdtemp as mkdtemp5 } from "fs/promises";
|
|
13996
14190
|
import { tmpdir as tmpdir6 } from "os";
|
|
13997
14191
|
import { join as join43 } from "path";
|
|
13998
14192
|
init_fs();
|
|
@@ -14185,7 +14379,7 @@ async function artifactContentMap(artifacts) {
|
|
|
14185
14379
|
const out = /* @__PURE__ */ new Map();
|
|
14186
14380
|
for (const artifact of artifacts) {
|
|
14187
14381
|
if (artifact.kind !== "file") continue;
|
|
14188
|
-
out.set(artifact.relativePath.replaceAll("\\", "/"), await
|
|
14382
|
+
out.set(artifact.relativePath.replaceAll("\\", "/"), await readFile36(artifact.stagedPath ?? artifact.sourcePath, "utf8"));
|
|
14189
14383
|
}
|
|
14190
14384
|
return out;
|
|
14191
14385
|
}
|
|
@@ -14507,9 +14701,9 @@ init_fs();
|
|
|
14507
14701
|
|
|
14508
14702
|
// src/lifecycle/trust.ts
|
|
14509
14703
|
init_fs();
|
|
14510
|
-
import { mkdir as mkdir24, readFile as
|
|
14511
|
-
import { homedir as
|
|
14512
|
-
import { dirname as
|
|
14704
|
+
import { mkdir as mkdir24, readFile as readFile37 } from "fs/promises";
|
|
14705
|
+
import { homedir as homedir13 } from "os";
|
|
14706
|
+
import { dirname as dirname31, join as join44 } from "path";
|
|
14513
14707
|
import { z as z14 } from "zod";
|
|
14514
14708
|
var trustStoreSchema = z14.object({
|
|
14515
14709
|
version: z14.literal(1),
|
|
@@ -14517,9 +14711,9 @@ var trustStoreSchema = z14.object({
|
|
|
14517
14711
|
});
|
|
14518
14712
|
function normalizeTrustPolicy(policy) {
|
|
14519
14713
|
return {
|
|
14520
|
-
allow:
|
|
14521
|
-
acceptedSources:
|
|
14522
|
-
denyArtifactTypes:
|
|
14714
|
+
allow: sortedUnique6(policy?.allow ?? []),
|
|
14715
|
+
acceptedSources: sortedUnique6(policy?.acceptedSources ?? []),
|
|
14716
|
+
denyArtifactTypes: sortedUnique6(policy?.denyArtifactTypes ?? []),
|
|
14523
14717
|
requireReviewForTransitive: policy?.requireReviewForTransitive ?? true
|
|
14524
14718
|
};
|
|
14525
14719
|
}
|
|
@@ -14556,10 +14750,10 @@ async function readTrustedSources(_workspaceRoot, storePath = defaultTrustStoreP
|
|
|
14556
14750
|
return (await readTrustStore(storePath)).acceptedSources;
|
|
14557
14751
|
}
|
|
14558
14752
|
async function rememberTrustedSources(_workspaceRoot, sources, storePath = defaultTrustStorePath()) {
|
|
14559
|
-
const unique =
|
|
14753
|
+
const unique = sortedUnique6(sources);
|
|
14560
14754
|
if (unique.length === 0) return [];
|
|
14561
14755
|
const store = await readTrustStore(storePath);
|
|
14562
|
-
const acceptedSources =
|
|
14756
|
+
const acceptedSources = sortedUnique6([...store.acceptedSources, ...unique]);
|
|
14563
14757
|
await writeTrustStore(storePath, { version: 1, acceptedSources });
|
|
14564
14758
|
return unique.filter((source) => !store.acceptedSources.includes(source));
|
|
14565
14759
|
}
|
|
@@ -14578,19 +14772,19 @@ function matchesGlob2(value, pattern) {
|
|
|
14578
14772
|
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
14579
14773
|
return new RegExp(`^${escaped}$`).test(value);
|
|
14580
14774
|
}
|
|
14581
|
-
function
|
|
14775
|
+
function sortedUnique6(values) {
|
|
14582
14776
|
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
|
|
14583
14777
|
}
|
|
14584
14778
|
async function readTrustStore(path) {
|
|
14585
14779
|
if (!await pathExists(path)) return { version: 1, acceptedSources: [] };
|
|
14586
|
-
return trustStoreSchema.parse(JSON.parse(await
|
|
14780
|
+
return trustStoreSchema.parse(JSON.parse(await readFile37(path, "utf8")));
|
|
14587
14781
|
}
|
|
14588
14782
|
async function writeTrustStore(path, store) {
|
|
14589
|
-
await mkdir24(
|
|
14783
|
+
await mkdir24(dirname31(path), { recursive: true });
|
|
14590
14784
|
await writeJsonAtomic(path, trustStoreSchema.parse(store));
|
|
14591
14785
|
}
|
|
14592
14786
|
function defaultTrustStorePath() {
|
|
14593
|
-
return process.env.AGENTWHEEL_TRUST_STORE ?? join44(
|
|
14787
|
+
return process.env.AGENTWHEEL_TRUST_STORE ?? join44(homedir13(), ".agentwheel", "trust.json");
|
|
14594
14788
|
}
|
|
14595
14789
|
|
|
14596
14790
|
// src/lifecycle/source-plan.ts
|
|
@@ -14599,14 +14793,14 @@ init_selection();
|
|
|
14599
14793
|
|
|
14600
14794
|
// src/model/workspace-owner.ts
|
|
14601
14795
|
import { Buffer as Buffer2 } from "buffer";
|
|
14602
|
-
import { isAbsolute as
|
|
14796
|
+
import { isAbsolute as isAbsolute10, resolve as resolve29 } from "path";
|
|
14603
14797
|
var workspaceOwnerPrefix = "workspace-root:";
|
|
14604
14798
|
var fleetOwnerSeparator = "|fleet-id:";
|
|
14605
14799
|
var encodedRootPrefix = "v2:";
|
|
14606
14800
|
var fleetIdPattern = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
14607
14801
|
var base64UrlPattern = /^[a-z0-9_-]+$/i;
|
|
14608
14802
|
function workspaceOwnerForRoot(workspaceRoot, fleetId) {
|
|
14609
|
-
const root =
|
|
14803
|
+
const root = resolve29(workspaceRoot);
|
|
14610
14804
|
const encodedRoot = root.includes(fleetOwnerSeparator) ? `${encodedRootPrefix}${Buffer2.from(root, "utf8").toString("base64url")}` : root;
|
|
14611
14805
|
const legacy = `${workspaceOwnerPrefix}${encodedRoot}`;
|
|
14612
14806
|
return fleetId ? `${legacy}${fleetOwnerSeparator}${fleetId}` : legacy;
|
|
@@ -14618,7 +14812,7 @@ function parseWorkspaceOwner(value) {
|
|
|
14618
14812
|
const encodedRoot = separator === -1 ? encoded : encoded.slice(0, separator);
|
|
14619
14813
|
const fleetId = separator === -1 ? void 0 : encoded.slice(separator + fleetOwnerSeparator.length);
|
|
14620
14814
|
const rootValue = decodeRoot(encodedRoot);
|
|
14621
|
-
if (!rootValue || !
|
|
14815
|
+
if (!rootValue || !isAbsolute10(rootValue) || resolve29(rootValue) !== rootValue) return void 0;
|
|
14622
14816
|
if (fleetId !== void 0 && !fleetIdPattern.test(fleetId)) return void 0;
|
|
14623
14817
|
return { root: rootValue, ...fleetId ? { fleetId } : {} };
|
|
14624
14818
|
}
|
|
@@ -14711,187 +14905,8 @@ async function createExactMcpRetirementPlan(desiredArtifacts, adapter, targetRoo
|
|
|
14711
14905
|
};
|
|
14712
14906
|
}
|
|
14713
14907
|
|
|
14714
|
-
// src/
|
|
14715
|
-
|
|
14716
|
-
init_declarations();
|
|
14717
|
-
init_workspace();
|
|
14718
|
-
import { lstat as lstat4, readFile as readFile37, realpath as realpath2 } from "fs/promises";
|
|
14719
|
-
import { homedir as homedir13 } from "os";
|
|
14720
|
-
import { isAbsolute as isAbsolute10, relative as relative15, resolve as resolve29 } from "path";
|
|
14721
|
-
async function resolveWorkspaceScope(request = {}) {
|
|
14722
|
-
const selected = [request.user === true, request.local === true, request.fleet !== void 0].filter(Boolean).length;
|
|
14723
|
-
if (selected > 1) {
|
|
14724
|
-
throw new Error("Choose exactly one workspace selector: --user, --local, or --fleet <id>.");
|
|
14725
|
-
}
|
|
14726
|
-
const globalRoot = resolve29(request.globalRoot ?? homedir13());
|
|
14727
|
-
if (request.user) {
|
|
14728
|
-
const config2 = await readWorkspaceConfig(globalRoot);
|
|
14729
|
-
assertNonFleetScope("user", config2);
|
|
14730
|
-
return { kind: "user", root: globalRoot, config: config2 };
|
|
14731
|
-
}
|
|
14732
|
-
if (request.fleet !== void 0) {
|
|
14733
|
-
const id = fleetIdSchema.parse(request.fleet);
|
|
14734
|
-
const registration = await showRegisteredFleet(id, { globalRoot });
|
|
14735
|
-
const root = await assertCanonicalDirectory(registration.root, `Registered fleet '${id}' root`);
|
|
14736
|
-
const config2 = await readRequiredConfig(root, `fleet '${id}'`);
|
|
14737
|
-
assertFleetContract(id, registration, config2);
|
|
14738
|
-
return { kind: "fleet", root, fleetId: id, config: config2 };
|
|
14739
|
-
}
|
|
14740
|
-
const cwd = resolve29(request.cwd ?? process.cwd());
|
|
14741
|
-
const discoveredRoot = await findExistingWorkspaceRoot(cwd);
|
|
14742
|
-
if (!discoveredRoot || discoveredRoot === globalRoot) {
|
|
14743
|
-
if (request.local === true && cwd !== globalRoot) {
|
|
14744
|
-
return { kind: "local", root: cwd, config: await readWorkspaceConfig(cwd) };
|
|
14745
|
-
}
|
|
14746
|
-
throw missingScopeError(request.local === true ? "local" : "implicit local");
|
|
14747
|
-
}
|
|
14748
|
-
const config = await readRequiredConfig(discoveredRoot, "local");
|
|
14749
|
-
assertNonFleetScope("local", config);
|
|
14750
|
-
return { kind: "local", root: discoveredRoot, config };
|
|
14751
|
-
}
|
|
14752
|
-
async function registerFleet(request) {
|
|
14753
|
-
const id = fleetIdSchema.parse(request.id);
|
|
14754
|
-
const requiredPackages = sortedUnique6(request.requiredPackages);
|
|
14755
|
-
if (requiredPackages.length === 0) throw new Error("Fleet registration requires at least one --required-package <name>.");
|
|
14756
|
-
const globalRoot = resolve29(request.globalRoot ?? homedir13());
|
|
14757
|
-
const home = await readWorkspaceConfig(globalRoot);
|
|
14758
|
-
if (supportsFleetConfig(home) && home.fleetId) {
|
|
14759
|
-
throw new Error(`The home config is fleet '${home.fleetId}', so it cannot own the global fleet registry.`);
|
|
14760
|
-
}
|
|
14761
|
-
const existing = supportsFleetConfig(home) ? await canonicalizeExistingFleetRoots(home.fleets, globalRoot) : {};
|
|
14762
|
-
if (existing[id]) throw new Error(`Fleet '${id}' is already registered.`);
|
|
14763
|
-
const root = await assertCanonicalDirectory(request.root, `Fleet '${id}' root`);
|
|
14764
|
-
const duplicateRoot = Object.entries(existing).find(([, value]) => value.root === root);
|
|
14765
|
-
if (duplicateRoot) throw new Error(`Fleet root ${root} is already registered as '${duplicateRoot[0]}'.`);
|
|
14766
|
-
if (root === globalRoot) throw new Error("A fleet root must be outside the user config root contract.");
|
|
14767
|
-
const target = await readRequiredConfig(root, `fleet '${id}'`);
|
|
14768
|
-
const registration = registeredFleetSchema.parse({ root, requiredPackages });
|
|
14769
|
-
assertFleetContract(id, registration, target);
|
|
14770
|
-
const upgraded = workspaceConfigSchema.parse({
|
|
14771
|
-
...home,
|
|
14772
|
-
schemaVersion: CURRENT_WORKSPACE_SCHEMA_VERSION,
|
|
14773
|
-
exports: home.schemaVersion >= 2 ? home.exports : { selections: {} },
|
|
14774
|
-
fleets: { ...existing, [id]: registration }
|
|
14775
|
-
});
|
|
14776
|
-
const configPath = globalWorkspaceConfigPath(globalRoot);
|
|
14777
|
-
declareMutationPath(configPath);
|
|
14778
|
-
await writeJsonAtomic(configPath, upgraded);
|
|
14779
|
-
return { id, ...registration };
|
|
14780
|
-
}
|
|
14781
|
-
async function canonicalizeExistingFleetRoots(fleets, globalRoot) {
|
|
14782
|
-
const canonical = /* @__PURE__ */ new Map();
|
|
14783
|
-
const normalized = {};
|
|
14784
|
-
for (const [id, registration] of Object.entries(fleets).sort(([a], [b]) => a.localeCompare(b))) {
|
|
14785
|
-
const root = await canonicalizeDirectory(registration.root, `Registered fleet '${id}' root`);
|
|
14786
|
-
if (root === globalRoot) throw new Error(`Registered fleet '${id}' root must be outside the user config root contract.`);
|
|
14787
|
-
const incumbent = canonical.get(root);
|
|
14788
|
-
if (incumbent) {
|
|
14789
|
-
throw new Error(`Fleet root ${root} is registered more than once as '${incumbent}' and '${id}'.`);
|
|
14790
|
-
}
|
|
14791
|
-
canonical.set(root, id);
|
|
14792
|
-
normalized[id] = registeredFleetSchema.parse({ ...registration, root });
|
|
14793
|
-
}
|
|
14794
|
-
return normalized;
|
|
14795
|
-
}
|
|
14796
|
-
async function listRegisteredFleets(options = {}) {
|
|
14797
|
-
const globalRoot = resolve29(options.globalRoot ?? homedir13());
|
|
14798
|
-
const home = await readWorkspaceConfig(globalRoot);
|
|
14799
|
-
if (!supportsFleetConfig(home)) return [];
|
|
14800
|
-
return Object.entries(home.fleets).sort(([a], [b]) => a.localeCompare(b)).map(([id, registration]) => ({ id, ...registration }));
|
|
14801
|
-
}
|
|
14802
|
-
async function showRegisteredFleet(idInput, options = {}) {
|
|
14803
|
-
const id = fleetIdSchema.parse(idInput);
|
|
14804
|
-
const fleets = await listRegisteredFleets(options);
|
|
14805
|
-
const registration = fleets.find((candidate) => candidate.id === id);
|
|
14806
|
-
if (!registration) {
|
|
14807
|
-
throw new Error(`Unknown fleet '${id}'. Use 'agentwheel fleet list' or register it with 'agentwheel fleet register'.`);
|
|
14808
|
-
}
|
|
14809
|
-
return registration;
|
|
14810
|
-
}
|
|
14811
|
-
async function resolveWorkspaceOwnershipScope(workspaceRootInput, options = {}) {
|
|
14812
|
-
const workspaceRoot = await canonicalizeDirectory(resolve29(workspaceRootInput), "Workspace ownership root");
|
|
14813
|
-
if (options.fleetId) {
|
|
14814
|
-
return { root: workspaceRoot, fleetId: fleetIdSchema.parse(options.fleetId) };
|
|
14815
|
-
}
|
|
14816
|
-
const syntacticallyContaining = (await listRegisteredFleets({ globalRoot: options.globalRoot })).filter((fleet2) => containsPath(resolve29(fleet2.root), workspaceRoot));
|
|
14817
|
-
const registered = await Promise.all(syntacticallyContaining.map(async (fleet2) => ({
|
|
14818
|
-
...fleet2,
|
|
14819
|
-
root: await canonicalizeDirectory(fleet2.root, `Registered fleet '${fleet2.id}' root`)
|
|
14820
|
-
})));
|
|
14821
|
-
const containing = registered.filter((fleet2) => containsPath(fleet2.root, workspaceRoot));
|
|
14822
|
-
if (containing.length > 1) {
|
|
14823
|
-
throw new Error(
|
|
14824
|
-
`Workspace ${workspaceRoot} is contained by multiple registered fleets: ` + containing.map((fleet2) => `'${fleet2.id}' at ${fleet2.root}`).join(", ") + ". Resolve the overlapping registrations before planning ownership."
|
|
14825
|
-
);
|
|
14826
|
-
}
|
|
14827
|
-
const fleet = containing[0];
|
|
14828
|
-
if (fleet) assertFleetContract(fleet.id, fleet, await readRequiredConfig(fleet.root, `fleet '${fleet.id}'`));
|
|
14829
|
-
return fleet ? { root: fleet.root, fleetId: fleet.id } : { root: workspaceRoot };
|
|
14830
|
-
}
|
|
14831
|
-
async function readRequiredConfig(root, label) {
|
|
14832
|
-
const path = workspaceConfigPath(root);
|
|
14833
|
-
if (!await pathExists(path)) throw missingScopeError(label);
|
|
14834
|
-
try {
|
|
14835
|
-
return workspaceConfigSchema.parse(JSON.parse(await readFile37(path, "utf8")));
|
|
14836
|
-
} catch (error) {
|
|
14837
|
-
throw new Error(`Invalid ${label} Agentwheel config at ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
14838
|
-
}
|
|
14839
|
-
}
|
|
14840
|
-
function assertFleetContract(id, registration, config) {
|
|
14841
|
-
if (!supportsFleetConfig(config)) {
|
|
14842
|
-
throw new Error(`Fleet '${id}' config must use schemaVersion 3 or newer before registration or selection.`);
|
|
14843
|
-
}
|
|
14844
|
-
if (config.fleetId !== id) {
|
|
14845
|
-
throw new Error(`Fleet fleetId mismatch: expected '${id}', found '${config.fleetId ?? "missing"}'.`);
|
|
14846
|
-
}
|
|
14847
|
-
if (Object.keys(config.fleets).length > 0) {
|
|
14848
|
-
throw new Error(`Fleet '${id}' config may not contain the home fleets registry.`);
|
|
14849
|
-
}
|
|
14850
|
-
const names = new Set(config.packages.map((pkg) => pkg.name));
|
|
14851
|
-
for (const packageName of registration.requiredPackages) {
|
|
14852
|
-
if (!names.has(packageName)) throw new Error(`Fleet '${id}' is missing required package '${packageName}'.`);
|
|
14853
|
-
}
|
|
14854
|
-
}
|
|
14855
|
-
async function assertCanonicalDirectory(input, label) {
|
|
14856
|
-
const canonical = await canonicalizeDirectory(input, label);
|
|
14857
|
-
const normalized = resolve29(input);
|
|
14858
|
-
const stats = await lstat4(input);
|
|
14859
|
-
if (stats.isSymbolicLink() || canonical !== normalized || input !== normalized) {
|
|
14860
|
-
throw new Error(`${label} must be canonical and symlink-unambiguous: ${input} resolves to ${canonical}.`);
|
|
14861
|
-
}
|
|
14862
|
-
return canonical;
|
|
14863
|
-
}
|
|
14864
|
-
async function canonicalizeDirectory(input, label) {
|
|
14865
|
-
if (!isAbsolute10(input)) throw new Error(`${label} must be an absolute canonical path.`);
|
|
14866
|
-
let canonical;
|
|
14867
|
-
try {
|
|
14868
|
-
canonical = await realpath2(input);
|
|
14869
|
-
} catch {
|
|
14870
|
-
throw new Error(`${label} does not exist: ${input}`);
|
|
14871
|
-
}
|
|
14872
|
-
const stats = await lstat4(canonical);
|
|
14873
|
-
if (!stats.isDirectory()) throw new Error(`${label} is not a directory: ${input}`);
|
|
14874
|
-
return canonical;
|
|
14875
|
-
}
|
|
14876
|
-
function missingScopeError(label) {
|
|
14877
|
-
return new Error(
|
|
14878
|
-
`Missing ${label} Agentwheel workspace config. Select --user, --local, or --fleet <id>, or run 'agentwheel init workspace' in the intended local root. Agentwheel never falls back to home desired state.`
|
|
14879
|
-
);
|
|
14880
|
-
}
|
|
14881
|
-
function assertNonFleetScope(kind, config) {
|
|
14882
|
-
if (supportsFleetConfig(config) && config.fleetId) {
|
|
14883
|
-
throw new Error(
|
|
14884
|
-
`The ${kind} config declares fleetId '${config.fleetId}'. Select it through the registered --fleet <id> scope.`
|
|
14885
|
-
);
|
|
14886
|
-
}
|
|
14887
|
-
}
|
|
14888
|
-
function sortedUnique6(values) {
|
|
14889
|
-
return [...new Set(values.map((value) => value.trim()).filter(Boolean))].sort((a, b) => a.localeCompare(b));
|
|
14890
|
-
}
|
|
14891
|
-
function containsPath(parent, candidate) {
|
|
14892
|
-
const path = relative15(parent, candidate);
|
|
14893
|
-
return path === "" || !path.startsWith("..") && !isAbsolute10(path);
|
|
14894
|
-
}
|
|
14908
|
+
// src/lifecycle/source-plan.ts
|
|
14909
|
+
init_fleet();
|
|
14895
14910
|
|
|
14896
14911
|
// src/model/target-state.ts
|
|
14897
14912
|
init_graph_lock();
|
|
@@ -15265,7 +15280,7 @@ async function discoverTargetApplyJournal(options) {
|
|
|
15265
15280
|
continue;
|
|
15266
15281
|
}
|
|
15267
15282
|
if (!journal.graphLockPath || !journal.graphLock || !journal.graphLockDigest) continue;
|
|
15268
|
-
if (resolve31(
|
|
15283
|
+
if (resolve31(dirname32(journal.graphLockPath)) !== resolve31(dirname32(options.graphLockPath))) continue;
|
|
15269
15284
|
if (options.transport.kind === "ssh") {
|
|
15270
15285
|
throw new Error(
|
|
15271
15286
|
`Legacy SSH apply journal at ${item.path} does not record its original endpoint; Agentwheel cannot prove endpoint identity, so the journal was preserved.`
|
|
@@ -15407,7 +15422,7 @@ async function resolvePriorTargetState(options) {
|
|
|
15407
15422
|
return {};
|
|
15408
15423
|
}
|
|
15409
15424
|
async function discoverLegacyStateCandidates(options) {
|
|
15410
|
-
const directory =
|
|
15425
|
+
const directory = dirname32(options.graphLockPath);
|
|
15411
15426
|
let names;
|
|
15412
15427
|
try {
|
|
15413
15428
|
names = await readdir14(directory);
|
|
@@ -15695,7 +15710,7 @@ function mcpServerNames(strategy, removal) {
|
|
|
15695
15710
|
return new Set(Object.keys(servers));
|
|
15696
15711
|
}
|
|
15697
15712
|
function globalConfigRoot(globalRoot) {
|
|
15698
|
-
return
|
|
15713
|
+
return dirname32(dirname32(globalWorkspaceConfigPath(globalRoot)));
|
|
15699
15714
|
}
|
|
15700
15715
|
function ownedByWorkspace(owner, desiredOwner, workspaceRoot, ownsSubWorkspaces) {
|
|
15701
15716
|
if (owner === desiredOwner) return true;
|
|
@@ -15841,7 +15856,7 @@ function targetLabel(target) {
|
|
|
15841
15856
|
|
|
15842
15857
|
// src/runtime/target.ts
|
|
15843
15858
|
init_workspace();
|
|
15844
|
-
import { basename as basename22, dirname as
|
|
15859
|
+
import { basename as basename22, dirname as dirname33, join as join47, resolve as resolve33 } from "path";
|
|
15845
15860
|
|
|
15846
15861
|
// src/transport/run-as-identity.ts
|
|
15847
15862
|
import { execFileSync } from "child_process";
|
|
@@ -16013,7 +16028,7 @@ async function detectRuntimeTargets(cwd = process.cwd(), adapterFilter) {
|
|
|
16013
16028
|
if (adapterFilter && marker.adapter !== adapterFilter) continue;
|
|
16014
16029
|
for (const dir of marker.dirs) {
|
|
16015
16030
|
if (basename22(root) === dir) {
|
|
16016
|
-
matches.push({ adapter: marker.adapter, targetRoot:
|
|
16031
|
+
matches.push({ adapter: marker.adapter, targetRoot: dirname33(root) });
|
|
16017
16032
|
} else if (await pathExists(join47(root, dir))) {
|
|
16018
16033
|
matches.push({ adapter: marker.adapter, targetRoot: root });
|
|
16019
16034
|
}
|
|
@@ -16060,7 +16075,7 @@ function dedupeTargets(matches) {
|
|
|
16060
16075
|
function runtimeScanRoot(request) {
|
|
16061
16076
|
const root = resolve33(request.targetRoot ?? request.cwd ?? process.cwd());
|
|
16062
16077
|
if (request.targetRoot) return root;
|
|
16063
|
-
return runtimeMarkers.some((marker) => marker.dirs.includes(basename22(root))) ?
|
|
16078
|
+
return runtimeMarkers.some((marker) => marker.dirs.includes(basename22(root))) ? dirname33(root) : root;
|
|
16064
16079
|
}
|
|
16065
16080
|
|
|
16066
16081
|
// src/lifecycle/profile.ts
|
|
@@ -16394,7 +16409,7 @@ init_selection();
|
|
|
16394
16409
|
// src/cli/update-check.ts
|
|
16395
16410
|
import { mkdir as mkdir26, readFile as readFile38, writeFile as writeFile22 } from "fs/promises";
|
|
16396
16411
|
import { homedir as homedir14 } from "os";
|
|
16397
|
-
import { dirname as
|
|
16412
|
+
import { dirname as dirname34, join as join48 } from "path";
|
|
16398
16413
|
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
16399
16414
|
var DEFAULT_TIMEOUT_MS = 300;
|
|
16400
16415
|
var REGISTRY_URL = "https://registry.npmjs.org/agentwheel";
|
|
@@ -16447,7 +16462,7 @@ async function readCache(path) {
|
|
|
16447
16462
|
}
|
|
16448
16463
|
}
|
|
16449
16464
|
async function writeCache(path, cache) {
|
|
16450
|
-
await mkdir26(
|
|
16465
|
+
await mkdir26(dirname34(path), { recursive: true });
|
|
16451
16466
|
await writeFile22(path, `${JSON.stringify(cache, null, 2)}
|
|
16452
16467
|
`, "utf8");
|
|
16453
16468
|
}
|
|
@@ -16683,11 +16698,11 @@ init_graph_lock();
|
|
|
16683
16698
|
|
|
16684
16699
|
// src/cli/version.ts
|
|
16685
16700
|
import { readFileSync as readFileSync2 } from "fs";
|
|
16686
|
-
import { dirname as
|
|
16701
|
+
import { dirname as dirname35, join as join51 } from "path";
|
|
16687
16702
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
16688
16703
|
var FALLBACK_VERSION = "0.0.0";
|
|
16689
16704
|
function resolveCliVersion() {
|
|
16690
|
-
let dir =
|
|
16705
|
+
let dir = dirname35(fileURLToPath3(import.meta.url));
|
|
16691
16706
|
while (true) {
|
|
16692
16707
|
try {
|
|
16693
16708
|
const pkg = JSON.parse(readFileSync2(join51(dir, "package.json"), "utf8"));
|
|
@@ -16696,13 +16711,146 @@ function resolveCliVersion() {
|
|
|
16696
16711
|
}
|
|
16697
16712
|
} catch {
|
|
16698
16713
|
}
|
|
16699
|
-
const parent =
|
|
16714
|
+
const parent = dirname35(dir);
|
|
16700
16715
|
if (parent === dir) return FALLBACK_VERSION;
|
|
16701
16716
|
dir = parent;
|
|
16702
16717
|
}
|
|
16703
16718
|
}
|
|
16704
16719
|
|
|
16720
|
+
// src/lifecycle/ownership-handoff-audit.ts
|
|
16721
|
+
init_apply();
|
|
16722
|
+
init_manifest2();
|
|
16723
|
+
init_paths();
|
|
16724
|
+
init_transaction();
|
|
16725
|
+
init_coordinator();
|
|
16726
|
+
init_declarations();
|
|
16727
|
+
init_protocol();
|
|
16728
|
+
init_process();
|
|
16729
|
+
init_repository();
|
|
16730
|
+
init_transport();
|
|
16731
|
+
import { createHash as createHash20, randomUUID as randomUUID6 } from "crypto";
|
|
16732
|
+
import { join as join52, resolve as resolve36 } from "path";
|
|
16733
|
+
async function applyAuditedOwnershipHandoff(request, observe4) {
|
|
16734
|
+
const existing = activeMutationMetadata();
|
|
16735
|
+
const workspaceRoot = resolve36(request.workspaceRoot ?? existing.workspaceRoot);
|
|
16736
|
+
if (existing && (resolve36(existing.workspaceRoot) !== workspaceRoot || request.reason !== void 0 && existing.reason !== request.reason.replace(/\r\n?/gu, "\n").trim() || request.operationId && request.operationId !== existing.operationId)) {
|
|
16737
|
+
throw new Error("Ownership handoff does not match the active governed workspace, reason or operation.");
|
|
16738
|
+
}
|
|
16739
|
+
const operationId = mutationOperationIdSchema.parse(existing?.operationId ?? request.operationId ?? randomUUID6());
|
|
16740
|
+
const auditPath = join52(workspaceRoot, ".agentwheel", "ownership-handoffs", `${operationId}.json`);
|
|
16741
|
+
const mutation = existing ? void 0 : await GovernedMutation.begin({
|
|
16742
|
+
workspaceRoot,
|
|
16743
|
+
commandName: "agentwheel ownership handoff",
|
|
16744
|
+
reason: request.reason,
|
|
16745
|
+
operationId,
|
|
16746
|
+
noCommit: request.noCommit,
|
|
16747
|
+
globalRoot: request.globalRoot,
|
|
16748
|
+
anticipatedPaths: [auditPath]
|
|
16749
|
+
});
|
|
16750
|
+
try {
|
|
16751
|
+
const transport = request.transport ?? localTransport;
|
|
16752
|
+
assertGovernedRuntimeTransportSupported(transport);
|
|
16753
|
+
if (transport.kind !== "local") throw new Error("Audited ownership handoff supports local targets only.");
|
|
16754
|
+
await assertNoSymlinkPath(workspaceRoot);
|
|
16755
|
+
await assertNoSymlinkPath(auditPath);
|
|
16756
|
+
if ((existing ?? mutation?.metadata())?.revisionMode === "commit-after-verify") {
|
|
16757
|
+
const repository = await discoverGitRepository(workspaceRoot);
|
|
16758
|
+
if (!repository) throw new Error("Ownership handoff requires a declarative Git audit path.");
|
|
16759
|
+
const ignored = await runProcess("git", ["-C", repository.root, "check-ignore", "--no-index", "--", auditPath], { allowExitCodes: [0, 1] });
|
|
16760
|
+
if (ignored.exitCode === 0) throw new Error("Ownership handoff audit path is Git-ignored; declare it before handing off ownership.");
|
|
16761
|
+
}
|
|
16762
|
+
const scope = { installationType: request.installationType, stateKey: request.stateKey };
|
|
16763
|
+
await assertNoSymlinkPath(join52(request.targetRoot, ".agentwheel"));
|
|
16764
|
+
const lock = await acquireApplyLock(request.targetRoot, request.adapter, transport, {}, scope);
|
|
16765
|
+
try {
|
|
16766
|
+
if ((await listAllApplyJournals(request.targetRoot, void 0, transport)).length) {
|
|
16767
|
+
throw new Error("Cannot hand off ownership while an apply journal is pending. Recover the same operation first.");
|
|
16768
|
+
}
|
|
16769
|
+
if (await transport.pathExists(auditPath)) throw new Error("Ownership handoff intent already exists; recover the same operation instead of applying again.");
|
|
16770
|
+
const plan = await observe4(request, transport);
|
|
16771
|
+
if (plan.drifted && !request.expectedRuntimeHash) {
|
|
16772
|
+
throw new Error("Applying a drifted ownership handoff requires expectedRuntimeHash from a reviewed dry-run.");
|
|
16773
|
+
}
|
|
16774
|
+
const manifest = await readInstallManifest(request.targetRoot, request.adapter, transport, scope);
|
|
16775
|
+
if (!manifest || manifest.version !== 2 || manifest.revision !== plan.manifestRevision) {
|
|
16776
|
+
throw new Error("Ownership handoff manifest changed while locked; replan required.");
|
|
16777
|
+
}
|
|
16778
|
+
const inventory = await listInstallManifests(request.targetRoot, void 0, transport);
|
|
16779
|
+
for (const item of inventory) await assertNoSymlinkPath(item.path);
|
|
16780
|
+
const runtimePath = metadataRuntimePath(request.targetRoot, plan.path);
|
|
16781
|
+
const runtime = [{ path: plan.path, hash: await transport.hashPath(runtimePath), snapshotDigest: await ownershipRuntimeSnapshot(runtimePath) }];
|
|
16782
|
+
const reason = existing?.reason ?? mutation?.metadata().reason ?? request.reason ?? "Ownership handoff";
|
|
16783
|
+
const intent = {
|
|
16784
|
+
schemaVersion: 1,
|
|
16785
|
+
event: "ownership-handoff-intent",
|
|
16786
|
+
operationId,
|
|
16787
|
+
reason,
|
|
16788
|
+
// Explicit whitelist: never serialize manifest entries, mergeRemoval or runtime/config values.
|
|
16789
|
+
plan: {
|
|
16790
|
+
adapter: plan.adapter,
|
|
16791
|
+
installationType: manifest.installationType,
|
|
16792
|
+
stateKey: manifest.stateKey,
|
|
16793
|
+
targetRoot: plan.targetRoot,
|
|
16794
|
+
selector: plan.selector,
|
|
16795
|
+
path: plan.path,
|
|
16796
|
+
artifactHash: plan.artifactHash,
|
|
16797
|
+
runtimeHash: plan.runtimeHash,
|
|
16798
|
+
drifted: plan.drifted,
|
|
16799
|
+
manifestRevision: plan.manifestRevision,
|
|
16800
|
+
fromOwner: plan.fromOwner,
|
|
16801
|
+
toOwner: plan.toOwner
|
|
16802
|
+
},
|
|
16803
|
+
completion: "Verify the linked runtime journal and mutation receipt; intent alone is not completion."
|
|
16804
|
+
};
|
|
16805
|
+
const content = `${JSON.stringify(intent, null, 2)}
|
|
16806
|
+
`;
|
|
16807
|
+
const sha2568 = createHash20("sha256").update(content).digest("hex");
|
|
16808
|
+
declareMutationPath(auditPath);
|
|
16809
|
+
declareMutationPath(installManifestPath(request.targetRoot, request.adapter, scope));
|
|
16810
|
+
const metadata = mutationMetadataForApplyJournal();
|
|
16811
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
16812
|
+
const journal = {
|
|
16813
|
+
version: metadata ? 2 : 1,
|
|
16814
|
+
...metadata ? { mutation: metadata } : {},
|
|
16815
|
+
mode: "uninstall",
|
|
16816
|
+
adapter: manifest.adapter,
|
|
16817
|
+
installationType: manifest.installationType,
|
|
16818
|
+
stateKey: manifest.stateKey,
|
|
16819
|
+
targetRoot: manifest.targetRoot,
|
|
16820
|
+
baseRevision: manifest.revision,
|
|
16821
|
+
createdAt: now,
|
|
16822
|
+
updatedAt: now,
|
|
16823
|
+
operations: [],
|
|
16824
|
+
completed: [],
|
|
16825
|
+
manifest: { ...manifest, entries: manifest.entries.map((entry) => entry.artifactType === request.artifactType && entry.artifactName === request.artifactName ? { ...entry, workspaceOwner: plan.toOwner } : entry) },
|
|
16826
|
+
metadataAudit: {
|
|
16827
|
+
kind: "ownership-handoff",
|
|
16828
|
+
workspaceRoot,
|
|
16829
|
+
operationId,
|
|
16830
|
+
planDigest: sha2568,
|
|
16831
|
+
inventory: inventory.map((item) => ({ stateKey: item.stateKey, revision: item.manifest.revision })),
|
|
16832
|
+
runtime,
|
|
16833
|
+
auditFiles: [{ path: `.agentwheel/ownership-handoffs/${operationId}.json`, content, sha256: sha2568 }]
|
|
16834
|
+
}
|
|
16835
|
+
};
|
|
16836
|
+
if (JSON.stringify(await observe4(request, transport)) !== JSON.stringify(plan)) {
|
|
16837
|
+
throw new Error("Ownership handoff preconditions changed before journaling; replan required.");
|
|
16838
|
+
}
|
|
16839
|
+
await writeApplyJournal(journal, transport);
|
|
16840
|
+
await commitManifestMetadataJournal(journal, transport);
|
|
16841
|
+
await mutation?.complete();
|
|
16842
|
+
return plan;
|
|
16843
|
+
} finally {
|
|
16844
|
+
await lock.release();
|
|
16845
|
+
}
|
|
16846
|
+
} catch (error) {
|
|
16847
|
+
await mutation?.fail(error);
|
|
16848
|
+
throw error;
|
|
16849
|
+
}
|
|
16850
|
+
}
|
|
16851
|
+
|
|
16705
16852
|
// src/lifecycle/ownership.ts
|
|
16853
|
+
init_coordinator();
|
|
16706
16854
|
init_manifest2();
|
|
16707
16855
|
init_paths();
|
|
16708
16856
|
init_merge_removal();
|
|
@@ -16710,7 +16858,7 @@ init_instructions_block();
|
|
|
16710
16858
|
init_adapter();
|
|
16711
16859
|
init_transaction();
|
|
16712
16860
|
init_transport();
|
|
16713
|
-
import { resolve as
|
|
16861
|
+
import { resolve as resolve37 } from "path";
|
|
16714
16862
|
var unknownWorkspaceOwner = "workspace:unknown";
|
|
16715
16863
|
async function planArtifactOwnershipHandoff(request) {
|
|
16716
16864
|
return validateOwnershipHandoff(request, request.transport ?? localTransport);
|
|
@@ -16719,6 +16867,9 @@ async function applyArtifactOwnershipHandoff(request) {
|
|
|
16719
16867
|
if (!request.expectedHash || !request.expectedRevision) {
|
|
16720
16868
|
throw new Error("Applying an ownership handoff requires expectedHash and expectedRevision from a reviewed dry-run.");
|
|
16721
16869
|
}
|
|
16870
|
+
if (request.workspaceRoot || activeMutationMetadata()) {
|
|
16871
|
+
return applyAuditedOwnershipHandoff(request, validateOwnershipHandoff);
|
|
16872
|
+
}
|
|
16722
16873
|
const transport = request.transport ?? localTransport;
|
|
16723
16874
|
assertGovernedRuntimeTransportSupported(transport);
|
|
16724
16875
|
const scope = { installationType: request.installationType, stateKey: request.stateKey };
|
|
@@ -16854,8 +17005,8 @@ function containedArtifactPath(targetRoot, relativePath) {
|
|
|
16854
17005
|
if (!relativePath || relativePath.startsWith("/") || relativePath.includes("\0")) {
|
|
16855
17006
|
throw new Error(`Unsafe managed artifact path: ${relativePath}`);
|
|
16856
17007
|
}
|
|
16857
|
-
const root =
|
|
16858
|
-
const candidate =
|
|
17008
|
+
const root = resolve37(targetRoot);
|
|
17009
|
+
const candidate = resolve37(root, relativePath);
|
|
16859
17010
|
if (candidate !== root && !candidate.startsWith(`${root}/`)) {
|
|
16860
17011
|
throw new Error(`Managed artifact path escapes target root: ${relativePath}`);
|
|
16861
17012
|
}
|
|
@@ -16892,8 +17043,8 @@ init_apply();
|
|
|
16892
17043
|
init_paths();
|
|
16893
17044
|
init_transaction();
|
|
16894
17045
|
init_selection();
|
|
16895
|
-
import { createHash as
|
|
16896
|
-
import { resolve as
|
|
17046
|
+
import { createHash as createHash21 } from "crypto";
|
|
17047
|
+
import { resolve as resolve38 } from "path";
|
|
16897
17048
|
init_declarations();
|
|
16898
17049
|
init_transport();
|
|
16899
17050
|
init_instructions_block();
|
|
@@ -17030,14 +17181,14 @@ async function observe(request, transport) {
|
|
|
17030
17181
|
return { ...withoutDigest, planDigest: digest(withoutDigest) };
|
|
17031
17182
|
}
|
|
17032
17183
|
function normalizeRequest(request) {
|
|
17033
|
-
const targetRoot =
|
|
17184
|
+
const targetRoot = resolve38(request.targetRoot);
|
|
17034
17185
|
const sourceStateKey = exactStateKey(request.adapter, request.sourceStateKey, request.installationType, "source");
|
|
17035
17186
|
const destinationStateKey = exactStateKey(request.adapter, request.destinationStateKey, request.installationType, "destination");
|
|
17036
17187
|
if (sourceStateKey === destinationStateKey) throw new Error("Source and destination state keys must differ.");
|
|
17037
17188
|
if (!request.toFleetId.trim()) throw new Error("Destination Fleet id is required.");
|
|
17038
17189
|
const fromFleetId = request.fromFleetId?.trim();
|
|
17039
17190
|
if (request.fromFleetId !== void 0 && !fromFleetId) throw new Error("Source Fleet id cannot be empty.");
|
|
17040
|
-
if (fromFleetId && (fromFleetId !== request.toFleetId.trim() ||
|
|
17191
|
+
if (fromFleetId && (fromFleetId !== request.toFleetId.trim() || resolve38(request.fromWorkspaceRoot) !== resolve38(request.toWorkspaceRoot))) {
|
|
17041
17192
|
throw new Error("Fleet-qualified stale ownership retirement requires the same source and destination Fleet and workspace root.");
|
|
17042
17193
|
}
|
|
17043
17194
|
return {
|
|
@@ -17046,9 +17197,9 @@ function normalizeRequest(request) {
|
|
|
17046
17197
|
installationType: request.installationType.trim(),
|
|
17047
17198
|
sourceStateKey,
|
|
17048
17199
|
destinationStateKey,
|
|
17049
|
-
fromWorkspaceRoot:
|
|
17200
|
+
fromWorkspaceRoot: resolve38(request.fromWorkspaceRoot),
|
|
17050
17201
|
...fromFleetId ? { fromFleetId } : {},
|
|
17051
|
-
toWorkspaceRoot:
|
|
17202
|
+
toWorkspaceRoot: resolve38(request.toWorkspaceRoot),
|
|
17052
17203
|
toFleetId: request.toFleetId.trim()
|
|
17053
17204
|
};
|
|
17054
17205
|
}
|
|
@@ -17069,7 +17220,7 @@ async function requireManifest(request, stateKey, transport, label) {
|
|
|
17069
17220
|
installationType: manifest.installationType,
|
|
17070
17221
|
stateKey: manifest.stateKey
|
|
17071
17222
|
});
|
|
17072
|
-
if (manifest.adapter !== request.adapter || manifest.installationType !== request.installationType ||
|
|
17223
|
+
if (manifest.adapter !== request.adapter || manifest.installationType !== request.installationType || resolve38(manifest.targetRoot) !== request.targetRoot || actualStateKey !== stateKey) {
|
|
17073
17224
|
throw new Error(`${label} install manifest identity does not match the requested adapter, target, installation type, and state key.`);
|
|
17074
17225
|
}
|
|
17075
17226
|
return manifest;
|
|
@@ -17162,7 +17313,7 @@ function entryDigest(entry) {
|
|
|
17162
17313
|
return digest(entry);
|
|
17163
17314
|
}
|
|
17164
17315
|
function digest(value) {
|
|
17165
|
-
return
|
|
17316
|
+
return createHash21("sha256").update(canonicalJson6(value)).digest("hex");
|
|
17166
17317
|
}
|
|
17167
17318
|
function canonicalJson6(value) {
|
|
17168
17319
|
if (Array.isArray(value)) return `[${value.map(canonicalJson6).join(",")}]`;
|
|
@@ -17176,9 +17327,9 @@ init_apply();
|
|
|
17176
17327
|
init_manifest2();
|
|
17177
17328
|
init_paths();
|
|
17178
17329
|
init_transaction();
|
|
17179
|
-
import { createHash as
|
|
17330
|
+
import { createHash as createHash22, randomUUID as randomUUID7 } from "crypto";
|
|
17180
17331
|
import { lstat as lstat5 } from "fs/promises";
|
|
17181
|
-
import { join as
|
|
17332
|
+
import { join as join53, resolve as resolve39 } from "path";
|
|
17182
17333
|
init_coordinator();
|
|
17183
17334
|
init_declarations();
|
|
17184
17335
|
init_protocol();
|
|
@@ -17196,13 +17347,13 @@ async function applyReleaseOwnership(request) {
|
|
|
17196
17347
|
})) {
|
|
17197
17348
|
if (!value || !/^[a-f0-9]{64}$/.test(value)) throw new Error(`Reviewed SHA-256 ${name} is required to release a claim.`);
|
|
17198
17349
|
}
|
|
17199
|
-
const workspaceRoot =
|
|
17350
|
+
const workspaceRoot = resolve39(request.workspaceRoot);
|
|
17200
17351
|
const existing = activeMutationMetadata();
|
|
17201
|
-
if (existing && (
|
|
17352
|
+
if (existing && (resolve39(existing.workspaceRoot) !== workspaceRoot || existing.reason !== request.reason.replace(/\r\n?/gu, "\n").trim() || request.operationId && request.operationId !== existing.operationId)) {
|
|
17202
17353
|
throw new Error("Ownership release does not match the active governed workspace, reason or operation.");
|
|
17203
17354
|
}
|
|
17204
|
-
const operationId = mutationOperationIdSchema.parse(existing?.operationId ?? request.operationId ??
|
|
17205
|
-
const auditPath =
|
|
17355
|
+
const operationId = mutationOperationIdSchema.parse(existing?.operationId ?? request.operationId ?? randomUUID7());
|
|
17356
|
+
const auditPath = join53(workspaceRoot, ".agentwheel", "ownership-releases", `${operationId}.json`);
|
|
17206
17357
|
const mutation = existing ? void 0 : await GovernedMutation.begin({
|
|
17207
17358
|
workspaceRoot,
|
|
17208
17359
|
commandName: "agentwheel ownership release-claim",
|
|
@@ -17232,9 +17383,9 @@ async function applyReleaseOwnership(request) {
|
|
|
17232
17383
|
async function applyLocked(request, operationId, auditPath) {
|
|
17233
17384
|
const transport = request.transport ?? localTransport;
|
|
17234
17385
|
if (transport.kind !== "local") throw new Error("Ownership release supports local targets only.");
|
|
17235
|
-
await assertNoSymlinkPath(
|
|
17386
|
+
await assertNoSymlinkPath(join53(resolve39(request.targetRoot), ".agentwheel"));
|
|
17236
17387
|
await assertNoSymlinkPath(auditPath);
|
|
17237
|
-
const lock = await acquireApplyLock(
|
|
17388
|
+
const lock = await acquireApplyLock(resolve39(request.targetRoot), request.adapter, transport, {}, {
|
|
17238
17389
|
installationType: request.installationType,
|
|
17239
17390
|
stateKey: request.stateKey
|
|
17240
17391
|
});
|
|
@@ -17303,15 +17454,15 @@ async function applyLocked(request, operationId, auditPath) {
|
|
|
17303
17454
|
async function observe2(request) {
|
|
17304
17455
|
const transport = request.transport ?? localTransport;
|
|
17305
17456
|
if (transport.kind !== "local") throw new Error("Ownership release supports local targets only.");
|
|
17306
|
-
const targetRoot =
|
|
17307
|
-
const workspaceRoot =
|
|
17457
|
+
const targetRoot = resolve39(request.targetRoot);
|
|
17458
|
+
const workspaceRoot = resolve39(request.workspaceRoot);
|
|
17308
17459
|
const reason = mutationReasonSchema.parse(request.reason.trim());
|
|
17309
17460
|
if (!request.stateKey || stateKeyFor(request.adapter, { stateKey: request.stateKey }) !== request.stateKey || !request.installationType.trim() || !request.selector.includes("/")) {
|
|
17310
17461
|
throw new Error("Ownership release requires an exact state key, installation type and type/name selector.");
|
|
17311
17462
|
}
|
|
17312
17463
|
const runtimePath = metadataRuntimePath(targetRoot, request.path);
|
|
17313
17464
|
await assertNoSymlinkPath(workspaceRoot);
|
|
17314
|
-
await assertNoSymlinkPath(
|
|
17465
|
+
await assertNoSymlinkPath(join53(targetRoot, ".agentwheel"));
|
|
17315
17466
|
const manifests = await listInstallManifests(targetRoot, void 0, transport);
|
|
17316
17467
|
for (const item of manifests) await assertNoSymlinkPath(item.path);
|
|
17317
17468
|
const source = manifests.find((item) => item.stateKey === request.stateKey);
|
|
@@ -17366,7 +17517,7 @@ async function observe2(request) {
|
|
|
17366
17517
|
return { ...plan, planDigest: digest2(plan) };
|
|
17367
17518
|
}
|
|
17368
17519
|
function hash(content) {
|
|
17369
|
-
return
|
|
17520
|
+
return createHash22("sha256").update(content).digest("hex");
|
|
17370
17521
|
}
|
|
17371
17522
|
function digest2(value) {
|
|
17372
17523
|
return hash(canonicalJson7(value));
|
|
@@ -17384,10 +17535,11 @@ init_manifest2();
|
|
|
17384
17535
|
init_paths();
|
|
17385
17536
|
init_transaction();
|
|
17386
17537
|
init_instructions_block();
|
|
17387
|
-
|
|
17388
|
-
import { realpath as realpath3 } from "fs/promises";
|
|
17389
|
-
import { isAbsolute as isAbsolute12, join as join54, relative as relative17, resolve as resolve40 } from "path";
|
|
17538
|
+
init_fleet();
|
|
17390
17539
|
init_manifest();
|
|
17540
|
+
import { createHash as createHash24 } from "crypto";
|
|
17541
|
+
import { realpath as realpath3 } from "fs/promises";
|
|
17542
|
+
import { isAbsolute as isAbsolute12, join as join55, relative as relative17, resolve as resolve41 } from "path";
|
|
17391
17543
|
init_declarations();
|
|
17392
17544
|
init_transport();
|
|
17393
17545
|
init_fs();
|
|
@@ -17399,18 +17551,18 @@ init_instructions_block();
|
|
|
17399
17551
|
init_merge_removal();
|
|
17400
17552
|
init_graph_lock();
|
|
17401
17553
|
init_manifest();
|
|
17402
|
-
import { createHash as
|
|
17554
|
+
import { createHash as createHash23 } from "crypto";
|
|
17403
17555
|
import { lstat as lstat6, readdir as readdir15 } from "fs/promises";
|
|
17404
|
-
import { basename as basename23, dirname as
|
|
17556
|
+
import { basename as basename23, dirname as dirname36, join as join54, posix as posix7, relative as relative16, resolve as resolve40 } from "path";
|
|
17405
17557
|
async function inventoryHistoricalLocks(fleetRoot) {
|
|
17406
|
-
const root =
|
|
17558
|
+
const root = join54(fleetRoot, ".agentwheel", "locks");
|
|
17407
17559
|
const found = [];
|
|
17408
17560
|
async function visit(dir) {
|
|
17409
17561
|
for (const entry of await readdir15(dir, { withFileTypes: true }).catch((error) => {
|
|
17410
17562
|
if (error.code === "ENOENT") return [];
|
|
17411
17563
|
throw error;
|
|
17412
17564
|
})) {
|
|
17413
|
-
const path =
|
|
17565
|
+
const path = join54(dir, entry.name);
|
|
17414
17566
|
if (entry.isDirectory()) await visit(path);
|
|
17415
17567
|
else if (entry.isFile() && entry.name.endsWith(".graph-lock.json")) found.push(await historicalLock(path));
|
|
17416
17568
|
}
|
|
@@ -17419,14 +17571,14 @@ async function inventoryHistoricalLocks(fleetRoot) {
|
|
|
17419
17571
|
return found.sort((a, b) => a.path.localeCompare(b.path));
|
|
17420
17572
|
}
|
|
17421
17573
|
async function findLegacyNamedLocks(workspaceRoot, adapter, fingerprint) {
|
|
17422
|
-
const root =
|
|
17574
|
+
const root = join54(workspaceRoot, ".agentwheel", "locks");
|
|
17423
17575
|
const found = [];
|
|
17424
17576
|
for (const target of await readdir15(root, { withFileTypes: true }).catch((error) => {
|
|
17425
17577
|
if (error.code === "ENOENT") return [];
|
|
17426
17578
|
throw error;
|
|
17427
17579
|
})) {
|
|
17428
17580
|
if (!target.isDirectory()) continue;
|
|
17429
|
-
const path =
|
|
17581
|
+
const path = join54(root, target.name, adapter, `${fingerprint}.graph-lock.json`);
|
|
17430
17582
|
const stats = await lstat6(path).catch((error) => {
|
|
17431
17583
|
if (error.code === "ENOENT") return void 0;
|
|
17432
17584
|
throw error;
|
|
@@ -17448,7 +17600,7 @@ async function planLegacyRecovery(input) {
|
|
|
17448
17600
|
const { graphPlan, installRoot, targetKey: targetKey2, adapter, installationType, historicalLocks, transport } = input;
|
|
17449
17601
|
assertCompleteGraphPlan(graphPlan);
|
|
17450
17602
|
const binding = {
|
|
17451
|
-
targetLockDir:
|
|
17603
|
+
targetLockDir: dirname36(graphPlan.graphLockPath),
|
|
17452
17604
|
stableLockPath: graphPlan.graphLockPath,
|
|
17453
17605
|
stableStateKey: graphPlan.plan.stateKey,
|
|
17454
17606
|
currentFingerprint: graphPlan.targetFingerprint,
|
|
@@ -17487,7 +17639,7 @@ async function planLegacyRecovery(input) {
|
|
|
17487
17639
|
const currentNodeIds = [...new Set(current.map((item) => item.graphNodeId).filter((value) => Boolean(value)))].sort();
|
|
17488
17640
|
const currentSelectors = [...new Set(current.map((item) => item.logicalSelector).filter((value) => Boolean(value)))].sort();
|
|
17489
17641
|
const currentOwners = [...new Set(current.flatMap((item) => item.owners ?? []))].sort();
|
|
17490
|
-
const livePath =
|
|
17642
|
+
const livePath = resolve40(installRoot, path);
|
|
17491
17643
|
if (relative16(installRoot, livePath).startsWith("..")) throw new Error(`Manifest path escapes target: ${path}`);
|
|
17492
17644
|
const liveHash = await transport.pathExists(livePath) ? await transport.hashPath(livePath) : null;
|
|
17493
17645
|
const reasons = [];
|
|
@@ -17559,8 +17711,8 @@ function claimFor(item, entry, locks, binding) {
|
|
|
17559
17711
|
const matches = locks.filter((candidate) => candidate.digest === digest3);
|
|
17560
17712
|
const evidence = [];
|
|
17561
17713
|
const owner = "workspaceOwner" in entry ? entry.workspaceOwner : legacyUnownedWorkspaceOwner;
|
|
17562
|
-
const sameRoot = binding.transportKind === "ssh" ? posix7.normalize(item.manifest.targetRoot) === posix7.normalize(binding.installRoot) :
|
|
17563
|
-
const inTargetDir = matches.filter((candidate) =>
|
|
17714
|
+
const sameRoot = binding.transportKind === "ssh" ? posix7.normalize(item.manifest.targetRoot) === posix7.normalize(binding.installRoot) : resolve40(item.manifest.targetRoot) === resolve40(binding.installRoot);
|
|
17715
|
+
const inTargetDir = matches.filter((candidate) => resolve40(dirname36(candidate.path)) === resolve40(binding.targetLockDir));
|
|
17564
17716
|
const boundLocks = inTargetDir.filter((candidate) => lockBindsState(candidate, item, binding));
|
|
17565
17717
|
if (owner !== binding.expectedOwner) evidence.push("workspace owner differs from selected Fleet target");
|
|
17566
17718
|
if (item.manifest.version !== 2 || item.manifest.installationType !== binding.installationType) evidence.push("installation type differs or manifest is legacy v1");
|
|
@@ -17602,7 +17754,7 @@ function lockBindsState(candidate, manifest, binding) {
|
|
|
17602
17754
|
if (!name.endsWith(".graph-lock.json")) return false;
|
|
17603
17755
|
const fingerprint = name.slice(0, -".graph-lock.json".length);
|
|
17604
17756
|
if (!/^[a-f0-9]{64}$/u.test(fingerprint)) return false;
|
|
17605
|
-
const stable =
|
|
17757
|
+
const stable = resolve40(candidate.path) === resolve40(binding.stableLockPath);
|
|
17606
17758
|
if (stable) {
|
|
17607
17759
|
return manifest.stateKey === binding.stableStateKey && candidate.lock.canonical.targetFingerprint === binding.currentFingerprint;
|
|
17608
17760
|
}
|
|
@@ -17670,7 +17822,7 @@ function assertCompleteGraphPlan(plan) {
|
|
|
17670
17822
|
}
|
|
17671
17823
|
}
|
|
17672
17824
|
function sha2566(value) {
|
|
17673
|
-
return
|
|
17825
|
+
return createHash23("sha256").update(value).digest("hex");
|
|
17674
17826
|
}
|
|
17675
17827
|
|
|
17676
17828
|
// src/lifecycle/ownership-adopt-legacy.ts
|
|
@@ -17692,12 +17844,12 @@ async function planAdoptLegacyOwnership(request) {
|
|
|
17692
17844
|
async function applyAdoptLegacyOwnership(request) {
|
|
17693
17845
|
assertApplyPreconditions2(request);
|
|
17694
17846
|
const transport = request.transport ?? localTransport;
|
|
17695
|
-
const targetRoot =
|
|
17847
|
+
const targetRoot = resolve41(request.targetRoot);
|
|
17696
17848
|
const installationType = request.installationType.trim();
|
|
17697
17849
|
if (transport.kind !== "local") throw new Error("Legacy ownership adoption requires a local filesystem transport.");
|
|
17698
17850
|
const beforeLock = await readInstallManifest(targetRoot, request.adapter, transport, { installationType, stateKey: request.sourceStateKey });
|
|
17699
17851
|
if (beforeLock?.entries.some((entry) => entry.mode === "managed-block")) {
|
|
17700
|
-
await assertNoSymlinkPath(
|
|
17852
|
+
await assertNoSymlinkPath(join55(targetRoot, ".agentwheel"));
|
|
17701
17853
|
}
|
|
17702
17854
|
const lock = await acquireApplyLock(targetRoot, request.adapter, transport, {}, {
|
|
17703
17855
|
installationType,
|
|
@@ -17936,13 +18088,13 @@ async function observe3(request, transport) {
|
|
|
17936
18088
|
}))
|
|
17937
18089
|
} } : {}
|
|
17938
18090
|
};
|
|
17939
|
-
return { ...withoutDigest, planDigest:
|
|
18091
|
+
return { ...withoutDigest, planDigest: createHash24("sha256").update(canonicalJson6(withoutDigest)).digest("hex") };
|
|
17940
18092
|
}
|
|
17941
18093
|
async function normalizeRequest2(request) {
|
|
17942
18094
|
if (request.destinationFleetId !== void 0) {
|
|
17943
18095
|
throw new Error("Legacy ownership adoption targets a nested workspace; a Fleet target uses fleet normalize or ownership retire-stale.");
|
|
17944
18096
|
}
|
|
17945
|
-
const targetRoot =
|
|
18097
|
+
const targetRoot = resolve41(request.targetRoot);
|
|
17946
18098
|
const installationType = request.installationType.trim();
|
|
17947
18099
|
const sourceStateKey = exactStateKey(request.adapter, request.sourceStateKey, installationType, "source");
|
|
17948
18100
|
const destinationStateKey = exactStateKey(request.adapter, request.destinationStateKey, installationType, "destination");
|
|
@@ -17954,22 +18106,22 @@ async function normalizeRequest2(request) {
|
|
|
17954
18106
|
const scope = await resolveWorkspaceOwnershipScope(request.workspaceRoot, { globalRoot: request.globalRoot });
|
|
17955
18107
|
const destinationOwner = workspaceOwnerForRoot(scope.root, scope.fleetId);
|
|
17956
18108
|
const workspaceRoot = await realpath3(request.workspaceRoot);
|
|
17957
|
-
const sourceRoot =
|
|
18109
|
+
const sourceRoot = resolve41(request.fromWorkspaceRoot);
|
|
17958
18110
|
const sourceOwner = workspaceOwnerForRoot(sourceRoot);
|
|
17959
18111
|
let sourceClass;
|
|
17960
|
-
if (sourceRoot === workspaceRoot || sourceRoot ===
|
|
18112
|
+
if (sourceRoot === workspaceRoot || sourceRoot === resolve41(request.workspaceRoot)) {
|
|
17961
18113
|
if (sourceOwner === destinationOwner) {
|
|
17962
18114
|
throw new Error(`${sourceOwner} is already the destination owner; ordinary install migration handles its legacy state.`);
|
|
17963
18115
|
}
|
|
17964
18116
|
sourceClass = "own-legacy-owner";
|
|
17965
18117
|
} else {
|
|
17966
18118
|
const sourceForms = [sourceRoot, ...await realpath3(sourceRoot).then((path) => [path], () => [])];
|
|
17967
|
-
const workspaceForms = [workspaceRoot,
|
|
18119
|
+
const workspaceForms = [workspaceRoot, resolve41(request.workspaceRoot), scope.root];
|
|
17968
18120
|
if (sourceForms.some((source) => workspaceForms.some((workspace) => containsPath2(source, workspace) || containsPath2(workspace, source)))) {
|
|
17969
18121
|
throw new Error(`Source root ${sourceRoot} contains or is contained by the destination workspace; it cannot be adopted as a foreign root.`);
|
|
17970
18122
|
}
|
|
17971
18123
|
for (const fleet of await listRegisteredFleets({ globalRoot: request.globalRoot })) {
|
|
17972
|
-
const fleetForms = [
|
|
18124
|
+
const fleetForms = [resolve41(fleet.root), ...await realpath3(fleet.root).then((path) => [path], () => [])];
|
|
17973
18125
|
if (sourceForms.some((source) => fleetForms.some((root) => containsPath2(root, source)))) {
|
|
17974
18126
|
throw new Error(`Source root ${sourceRoot} is inside registered Fleet '${fleet.id}'; use fleet normalize or ownership retire-stale.`);
|
|
17975
18127
|
}
|
|
@@ -18126,7 +18278,7 @@ function containsPath2(parent, candidate) {
|
|
|
18126
18278
|
// src/version/policy.ts
|
|
18127
18279
|
import { execFile as execFile7 } from "child_process";
|
|
18128
18280
|
import { readFile as readFile40 } from "fs/promises";
|
|
18129
|
-
import { join as
|
|
18281
|
+
import { join as join56, resolve as resolve42 } from "path";
|
|
18130
18282
|
import { promisify as promisify7 } from "util";
|
|
18131
18283
|
import { parse as parseJsonc } from "jsonc-parser";
|
|
18132
18284
|
import { z as z15 } from "zod";
|
|
@@ -18223,7 +18375,7 @@ async function discoverVersionsFromSource(pkg, workspaceRoot) {
|
|
|
18223
18375
|
if (tagged.length > 0) return tagged;
|
|
18224
18376
|
}
|
|
18225
18377
|
if (driverName === "local") {
|
|
18226
|
-
const root =
|
|
18378
|
+
const root = resolve42(workspaceRoot, pkg.source);
|
|
18227
18379
|
const manifest2 = await readPackageManifest(root);
|
|
18228
18380
|
const current = manifest2 ? [{ version: manifest2.version, ref: pkg.requestedRef ?? root }] : [];
|
|
18229
18381
|
try {
|
|
@@ -18238,7 +18390,7 @@ async function discoverVersionsFromSource(pkg, workspaceRoot) {
|
|
|
18238
18390
|
}
|
|
18239
18391
|
const driver = getSourceDriver(driverName);
|
|
18240
18392
|
const resolved = await driver.resolve(pkg.source, {
|
|
18241
|
-
cacheRoot:
|
|
18393
|
+
cacheRoot: join56(workspaceRoot, ".agentwheel", "cache"),
|
|
18242
18394
|
mode: "tracking",
|
|
18243
18395
|
ref: pkg.requestedRef
|
|
18244
18396
|
});
|
|
@@ -18332,7 +18484,7 @@ function gitUrlFromSource(source) {
|
|
|
18332
18484
|
throw new Error(`Version discovery does not support Git source: ${source}`);
|
|
18333
18485
|
}
|
|
18334
18486
|
function versionCachePath(workspaceRoot) {
|
|
18335
|
-
return
|
|
18487
|
+
return join56(workspaceRoot, ".agentwheel", "cache", "version-index.json");
|
|
18336
18488
|
}
|
|
18337
18489
|
async function readVersionCache(path) {
|
|
18338
18490
|
if (!await pathExists(path)) return { schemaVersion: 1, sources: {} };
|
|
@@ -18349,7 +18501,7 @@ init_semver();
|
|
|
18349
18501
|
// src/profile/members.ts
|
|
18350
18502
|
import { execFile as execFile8 } from "child_process";
|
|
18351
18503
|
import { readFile as readFile41 } from "fs/promises";
|
|
18352
|
-
import { join as
|
|
18504
|
+
import { join as join57, resolve as resolve43 } from "path";
|
|
18353
18505
|
import { promisify as promisify8 } from "util";
|
|
18354
18506
|
import { z as z17 } from "zod";
|
|
18355
18507
|
|
|
@@ -18525,7 +18677,7 @@ async function invokeMemberStatus(member, parentWorkspace, chain, options, cliEn
|
|
|
18525
18677
|
let stderr = "";
|
|
18526
18678
|
try {
|
|
18527
18679
|
if (member.transport === "local") {
|
|
18528
|
-
const workspace =
|
|
18680
|
+
const workspace = resolve43(parentWorkspace, member.workspace);
|
|
18529
18681
|
const result = await execFileAsync8(process.execPath, [cliEntry, ...args], {
|
|
18530
18682
|
cwd: workspace,
|
|
18531
18683
|
env: env2,
|
|
@@ -18571,7 +18723,7 @@ async function runMemberAgentwheel(member, parentWorkspace, args, chain) {
|
|
|
18571
18723
|
process.execPath,
|
|
18572
18724
|
[process.argv[1], ...memberCommandArgs(member, args)],
|
|
18573
18725
|
{
|
|
18574
|
-
cwd:
|
|
18726
|
+
cwd: resolve43(parentWorkspace, member.workspace),
|
|
18575
18727
|
env: env2,
|
|
18576
18728
|
maxBuffer: 20 * 1024 * 1024
|
|
18577
18729
|
}
|
|
@@ -18651,7 +18803,7 @@ function memberFailure(member, health, error) {
|
|
|
18651
18803
|
};
|
|
18652
18804
|
}
|
|
18653
18805
|
function memberCachePath(workspaceRoot, profileName, memberId) {
|
|
18654
|
-
return
|
|
18806
|
+
return join57(workspaceRoot, ".agentwheel", "cache", "member-status", profileName, `${memberId}.json`);
|
|
18655
18807
|
}
|
|
18656
18808
|
async function readMemberCache(path) {
|
|
18657
18809
|
if (!await pathExists(path)) return void 0;
|
|
@@ -18677,7 +18829,7 @@ function assertNoCompositeCycle(workspaceRoot, profileName, chain) {
|
|
|
18677
18829
|
}
|
|
18678
18830
|
}
|
|
18679
18831
|
function compositeKey(workspaceRoot, profileName) {
|
|
18680
|
-
return `${
|
|
18832
|
+
return `${resolve43(workspaceRoot)}#${profileName}`;
|
|
18681
18833
|
}
|
|
18682
18834
|
|
|
18683
18835
|
// src/status/repository.ts
|
|
@@ -18724,10 +18876,10 @@ function valueAfter(lines, prefix) {
|
|
|
18724
18876
|
}
|
|
18725
18877
|
|
|
18726
18878
|
// src/catalogue/client.ts
|
|
18727
|
-
import { createHash as
|
|
18879
|
+
import { createHash as createHash25 } from "crypto";
|
|
18728
18880
|
import { readFile as readFile42, rm as rm15 } from "fs/promises";
|
|
18729
18881
|
import { homedir as homedir15 } from "os";
|
|
18730
|
-
import { join as
|
|
18882
|
+
import { join as join58 } from "path";
|
|
18731
18883
|
|
|
18732
18884
|
// src/model/catalogue.ts
|
|
18733
18885
|
import { z as z18 } from "zod";
|
|
@@ -19000,18 +19152,18 @@ var CatalogueClient = class {
|
|
|
19000
19152
|
}
|
|
19001
19153
|
return {
|
|
19002
19154
|
value: schema.parse(value),
|
|
19003
|
-
digest:
|
|
19155
|
+
digest: createHash25("sha256").update(bytes).digest("hex")
|
|
19004
19156
|
};
|
|
19005
19157
|
}
|
|
19006
19158
|
};
|
|
19007
19159
|
function defaultCatalogueCachePath() {
|
|
19008
|
-
return
|
|
19160
|
+
return join58(homedir15(), ".agentwheel", "catalogue-cache.json");
|
|
19009
19161
|
}
|
|
19010
19162
|
function sameSources2(a, b) {
|
|
19011
19163
|
return a.length === b.length && a.every((source, index) => source === b[index]);
|
|
19012
19164
|
}
|
|
19013
19165
|
function catalogueContentHash(enriched, vercel) {
|
|
19014
|
-
return
|
|
19166
|
+
return createHash25("sha256").update(JSON.stringify({ enriched, vercel })).digest("hex");
|
|
19015
19167
|
}
|
|
19016
19168
|
|
|
19017
19169
|
// src/search/index.ts
|
|
@@ -19373,9 +19525,9 @@ function includesToken(normalizedText, token) {
|
|
|
19373
19525
|
}
|
|
19374
19526
|
|
|
19375
19527
|
// src/semantic/index.ts
|
|
19376
|
-
import { createHash as
|
|
19528
|
+
import { createHash as createHash26 } from "crypto";
|
|
19377
19529
|
import { homedir as homedir16 } from "os";
|
|
19378
|
-
import { join as
|
|
19530
|
+
import { join as join59 } from "path";
|
|
19379
19531
|
import { env, pipeline } from "@huggingface/transformers";
|
|
19380
19532
|
var DEFAULT_SEMANTIC_INDEX_URL = "https://raw.githubusercontent.com/NestDevLab/agentwheel-registry/main/catalogue-semantic-index/gte-v1/";
|
|
19381
19533
|
var CONTRACT = {
|
|
@@ -19463,13 +19615,13 @@ var SemanticSearchClient = class {
|
|
|
19463
19615
|
if (!response.ok) throw new Error(`Semantic index file failed (${response.status}): ${descriptor.path}`);
|
|
19464
19616
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
19465
19617
|
if (bytes.byteLength !== descriptor.bytes) throw new Error(`Semantic index file size does not match: ${descriptor.path}`);
|
|
19466
|
-
const digest3 =
|
|
19618
|
+
const digest3 = createHash26("sha256").update(bytes).digest("hex");
|
|
19467
19619
|
if (digest3 !== descriptor.sha256) throw new Error(`Semantic index checksum does not match: ${descriptor.path}`);
|
|
19468
19620
|
return bytes;
|
|
19469
19621
|
}
|
|
19470
19622
|
};
|
|
19471
19623
|
async function embedQuery(query) {
|
|
19472
|
-
env.cacheDir =
|
|
19624
|
+
env.cacheDir = join59(homedir16(), ".agentwheel", "semantic-models");
|
|
19473
19625
|
const extractor = await pipeline("feature-extraction", CONTRACT.model.id, {
|
|
19474
19626
|
revision: CONTRACT.model.revision,
|
|
19475
19627
|
dtype: CONTRACT.model.dtype,
|
|
@@ -19554,9 +19706,9 @@ function ensureTrailingSlash(value) {
|
|
|
19554
19706
|
|
|
19555
19707
|
// src/trial/skill.ts
|
|
19556
19708
|
init_selection();
|
|
19557
|
-
import { createHash as
|
|
19709
|
+
import { createHash as createHash27 } from "crypto";
|
|
19558
19710
|
import { readFile as readFile43, stat as stat16 } from "fs/promises";
|
|
19559
|
-
import { join as
|
|
19711
|
+
import { join as join60 } from "path";
|
|
19560
19712
|
import { parse as parseYaml2 } from "yaml";
|
|
19561
19713
|
var MAX_TRIAL_SKILL_BYTES = 512 * 1024;
|
|
19562
19714
|
async function createSkillTrial(driver, resolved, selectors) {
|
|
@@ -19568,7 +19720,7 @@ async function createSkillTrial(driver, resolved, selectors) {
|
|
|
19568
19720
|
throw new Error("Skill trial requires exactly one selected skill. Use --skill <name> or --select skills/<name>.");
|
|
19569
19721
|
}
|
|
19570
19722
|
const artifact = skills[0];
|
|
19571
|
-
const path = artifact.kind === "dir" ?
|
|
19723
|
+
const path = artifact.kind === "dir" ? join60(artifact.sourcePath, "SKILL.md") : artifact.sourcePath;
|
|
19572
19724
|
const info = await stat16(path);
|
|
19573
19725
|
if (info.size > MAX_TRIAL_SKILL_BYTES) {
|
|
19574
19726
|
throw new Error(`Skill trial exceeds the ${MAX_TRIAL_SKILL_BYTES / 1024} KiB content limit.`);
|
|
@@ -19584,7 +19736,7 @@ async function createSkillTrial(driver, resolved, selectors) {
|
|
|
19584
19736
|
skill: {
|
|
19585
19737
|
name: artifact.name,
|
|
19586
19738
|
relativePath: artifact.relativePath,
|
|
19587
|
-
sha256:
|
|
19739
|
+
sha256: createHash27("sha256").update(content).digest("hex"),
|
|
19588
19740
|
frontmatter,
|
|
19589
19741
|
content
|
|
19590
19742
|
}
|
|
@@ -19602,17 +19754,21 @@ function readSkillFrontmatter(content, artifact) {
|
|
|
19602
19754
|
return { name: value.name, description: value.description };
|
|
19603
19755
|
}
|
|
19604
19756
|
|
|
19757
|
+
// src/cli/index.ts
|
|
19758
|
+
init_fleet();
|
|
19759
|
+
|
|
19605
19760
|
// src/lifecycle/fleet-normalize.ts
|
|
19606
|
-
import { createHash as
|
|
19761
|
+
import { createHash as createHash28 } from "crypto";
|
|
19607
19762
|
import { readFile as readFile44, readdir as readdir16, rm as rm16 } from "fs/promises";
|
|
19608
19763
|
import { homedir as homedir17 } from "os";
|
|
19609
|
-
import { dirname as
|
|
19764
|
+
import { dirname as dirname37, isAbsolute as isAbsolute13, join as join61, relative as relative18, resolve as resolve44 } from "path";
|
|
19610
19765
|
init_manifest2();
|
|
19611
19766
|
init_paths();
|
|
19612
19767
|
init_merge_removal();
|
|
19613
19768
|
init_instructions_block();
|
|
19614
19769
|
init_transaction();
|
|
19615
19770
|
init_adapter();
|
|
19771
|
+
init_fleet();
|
|
19616
19772
|
init_graph_lock();
|
|
19617
19773
|
init_manifest();
|
|
19618
19774
|
init_workspace();
|
|
@@ -19896,17 +20052,17 @@ function normalizeRequest3(request) {
|
|
|
19896
20052
|
...profile ? { profile } : {},
|
|
19897
20053
|
...agent ? { agent } : {},
|
|
19898
20054
|
...orphanedOwnerRoots ? { orphanedOwnerRoots } : {},
|
|
19899
|
-
...request.globalRoot ? { globalRoot:
|
|
20055
|
+
...request.globalRoot ? { globalRoot: resolve44(request.globalRoot) } : {}
|
|
19900
20056
|
};
|
|
19901
20057
|
}
|
|
19902
20058
|
function normalizeOrphanedOwnerRoot(value) {
|
|
19903
20059
|
const root = value.trim();
|
|
19904
20060
|
if (!root || !isAbsolute13(root)) throw new Error(`Invalid orphaned owner root '${value}'; expected an absolute workspace path.`);
|
|
19905
|
-
return
|
|
20061
|
+
return resolve44(root);
|
|
19906
20062
|
}
|
|
19907
20063
|
async function normalizationRoots(request) {
|
|
19908
20064
|
const destination = await showRegisteredFleet(request.destinationFleet, { globalRoot: request.globalRoot });
|
|
19909
|
-
const source = request.from === "user" ?
|
|
20065
|
+
const source = request.from === "user" ? resolve44(request.globalRoot ?? homedir17()) : (await showRegisteredFleet(request.from.slice("fleet:".length), { globalRoot: request.globalRoot })).root;
|
|
19910
20066
|
return { source, destination: destination.root };
|
|
19911
20067
|
}
|
|
19912
20068
|
async function withOrderedLocks(roots, fn) {
|
|
@@ -19914,7 +20070,7 @@ async function withOrderedLocks(roots, fn) {
|
|
|
19914
20070
|
if (index === roots.length) return fn();
|
|
19915
20071
|
const root = roots[index];
|
|
19916
20072
|
return withFilesystemLock(
|
|
19917
|
-
|
|
20073
|
+
join61(root, ".agentwheel", "fleet-normalize.lock"),
|
|
19918
20074
|
5e3,
|
|
19919
20075
|
() => run(index + 1),
|
|
19920
20076
|
"fleet normalization"
|
|
@@ -20121,7 +20277,7 @@ async function inspectLegacySelfInstalledState(fleet, packageNames, profileName,
|
|
|
20121
20277
|
let normalizedGraphCount = 0;
|
|
20122
20278
|
for (const graph of graphCandidates) {
|
|
20123
20279
|
const destinationState = await targetStateForGraph(fleet, graph, fleet.fleetId, allowOrphanedRetiredPackages);
|
|
20124
|
-
if (
|
|
20280
|
+
if (resolve44(destinationState.graphLockPath) === resolve44(graph.path)) {
|
|
20125
20281
|
const destinationManifest = (await collectManifestPaths([destinationState.manifestPath]))[0];
|
|
20126
20282
|
if (destinationManifest?.manifest.entries.some((entry) => entry.workspaceOwner === fleetOwner && entryMatchesPackages(entry, selected))) {
|
|
20127
20283
|
assertCorrelatedGraphManifest(
|
|
@@ -20136,7 +20292,7 @@ async function inspectLegacySelfInstalledState(fleet, packageNames, profileName,
|
|
|
20136
20292
|
}
|
|
20137
20293
|
}
|
|
20138
20294
|
const legacyState = await legacyTargetStateForGraph(fleet, graph, allowOrphanedRetiredPackages);
|
|
20139
|
-
if (
|
|
20295
|
+
if (resolve44(legacyState.graphLockPath) !== resolve44(graph.path)) {
|
|
20140
20296
|
throw new Error(`Legacy graph lock target identity is stale or noncanonical: ${graph.path}`);
|
|
20141
20297
|
}
|
|
20142
20298
|
const legacyManifest = (await collectManifestPaths([legacyState.manifestPath]))[0];
|
|
@@ -20311,7 +20467,7 @@ function targetKeysForAgent(scope, name) {
|
|
|
20311
20467
|
async function runtimeRoots(scope) {
|
|
20312
20468
|
const roots = /* @__PURE__ */ new Set([scope.root]);
|
|
20313
20469
|
if (scope.config.packages.some((pkg) => pkg.installationType === "user") || Object.values(scope.config.agents).some((agent) => agent.installationType === "user")) {
|
|
20314
|
-
roots.add(
|
|
20470
|
+
roots.add(resolve44(process.env.AGENTWHEEL_TEST_HOME || process.env.HOME || homedir17()));
|
|
20315
20471
|
}
|
|
20316
20472
|
for (const [name, agent] of Object.entries(scope.config.agents)) {
|
|
20317
20473
|
if (agent.transport === "ssh" || agent.transport === "local-run-as") throw new Error(`Installed-state normalization cannot inspect ${agent.transport} agent '${name}' locally.`);
|
|
@@ -20329,7 +20485,7 @@ async function runtimeRoots(scope) {
|
|
|
20329
20485
|
async function collectManifests(roots) {
|
|
20330
20486
|
const found = /* @__PURE__ */ new Map();
|
|
20331
20487
|
for (const root of roots) {
|
|
20332
|
-
const dir =
|
|
20488
|
+
const dir = join61(root, ".agentwheel");
|
|
20333
20489
|
let names;
|
|
20334
20490
|
try {
|
|
20335
20491
|
names = await readdir16(dir);
|
|
@@ -20339,7 +20495,7 @@ async function collectManifests(roots) {
|
|
|
20339
20495
|
}
|
|
20340
20496
|
for (const name of names.sort((a, b) => a.localeCompare(b))) {
|
|
20341
20497
|
if (!name.endsWith(".install-manifest.json")) continue;
|
|
20342
|
-
const path =
|
|
20498
|
+
const path = join61(dir, name);
|
|
20343
20499
|
const raw = JSON.parse(await readFile44(path, "utf8"));
|
|
20344
20500
|
const parsed = installManifestSchema.parse(raw);
|
|
20345
20501
|
if (parsed.version !== 2) {
|
|
@@ -20348,14 +20504,14 @@ async function collectManifests(roots) {
|
|
|
20348
20504
|
}
|
|
20349
20505
|
continue;
|
|
20350
20506
|
}
|
|
20351
|
-
if (
|
|
20507
|
+
if (resolve44(parsed.targetRoot) !== resolve44(root)) {
|
|
20352
20508
|
throw new Error(`Install manifest target root does not match its enumerated runtime root: ${path}`);
|
|
20353
20509
|
}
|
|
20354
20510
|
const expectedPath = installManifestPath(parsed.targetRoot, parsed.adapter, {
|
|
20355
20511
|
installationType: parsed.installationType,
|
|
20356
20512
|
stateKey: parsed.stateKey
|
|
20357
20513
|
});
|
|
20358
|
-
if (
|
|
20514
|
+
if (resolve44(expectedPath) !== resolve44(path)) {
|
|
20359
20515
|
throw new Error(`Install manifest state identity does not match its canonical path: ${path}`);
|
|
20360
20516
|
}
|
|
20361
20517
|
found.set(path, { path, raw, manifest: { ...parsed, revision: computeManifestRevision(raw), legacy: false } });
|
|
@@ -20376,7 +20532,7 @@ async function collectManifestPaths(paths) {
|
|
|
20376
20532
|
installationType: parsed.installationType,
|
|
20377
20533
|
stateKey: parsed.stateKey
|
|
20378
20534
|
});
|
|
20379
|
-
if (
|
|
20535
|
+
if (resolve44(expectedPath) !== resolve44(path)) {
|
|
20380
20536
|
throw new Error(`Install manifest state identity does not match its canonical path: ${path}`);
|
|
20381
20537
|
}
|
|
20382
20538
|
found.push({ path, raw, manifest: { ...parsed, revision: computeManifestRevision(raw), legacy: false } });
|
|
@@ -20395,7 +20551,7 @@ function assertNoForeignSamePathOwnership(manifests, renderedPaths, allowedOwner
|
|
|
20395
20551
|
}
|
|
20396
20552
|
}
|
|
20397
20553
|
async function relevantGraphLocks(workspaceRoot, selected, targetKeys, include) {
|
|
20398
|
-
const root =
|
|
20554
|
+
const root = join61(workspaceRoot, ".agentwheel", "locks");
|
|
20399
20555
|
if (!await pathExists(root)) return [];
|
|
20400
20556
|
const results = [];
|
|
20401
20557
|
for (const path of await listFiles(root)) {
|
|
@@ -20444,7 +20600,7 @@ async function hasRelevantLegacyManifestCandidate(scope, graph, selected) {
|
|
|
20444
20600
|
const legacyManifest = (await collectManifestPaths([legacyState.manifestPath]))[0];
|
|
20445
20601
|
if (legacyManifest?.manifest.entries.some((entry) => entryMatchesGraphPackages(entry, graph.lock, selected))) return true;
|
|
20446
20602
|
const stableState = await targetStateForGraph(scope, graph, scope.fleetId ?? null);
|
|
20447
|
-
if (
|
|
20603
|
+
if (resolve44(stableState.graphLockPath) !== resolve44(graph.path)) return false;
|
|
20448
20604
|
const stableManifest = (await collectManifestPaths([stableState.manifestPath]))[0];
|
|
20449
20605
|
return stableManifest?.manifest.entries.some((entry) => entryMatchesGraphPackages(entry, graph.lock, selected)) ?? false;
|
|
20450
20606
|
}
|
|
@@ -20465,7 +20621,7 @@ async function legacyManifestPathForConfiguredTarget(scope, graph) {
|
|
|
20465
20621
|
baseDir: scope.root
|
|
20466
20622
|
});
|
|
20467
20623
|
const targetRoot = resolveConfigPath(agent.root, scope.root);
|
|
20468
|
-
const installRoot =
|
|
20624
|
+
const installRoot = resolve44(installRootForAdapterInstallationType(adapter, targetRoot, agent.installationType, { kind: "local" }));
|
|
20469
20625
|
const stateKey = stateKeyFor(adapter.name, {
|
|
20470
20626
|
installationType: agent.installationType,
|
|
20471
20627
|
stateKey: agent.stateKey,
|
|
@@ -20533,7 +20689,7 @@ async function targetStateForGraph(scope, graph, identityFleetId = scope.fleetId
|
|
|
20533
20689
|
ssh: void 0,
|
|
20534
20690
|
...agent?.stateKey ? { stateKey: agent.stateKey } : {}
|
|
20535
20691
|
};
|
|
20536
|
-
const installRoot =
|
|
20692
|
+
const installRoot = resolve44(installRootForAdapterInstallationType(adapter, targetRoot, installationType, { kind: "local" }));
|
|
20537
20693
|
const targetIdentity = resolveTargetStateIdentity({
|
|
20538
20694
|
targetFingerprintParts: fingerprintParts,
|
|
20539
20695
|
workspaceRoot: scope.root,
|
|
@@ -20565,16 +20721,16 @@ async function targetStateForGraph(scope, graph, identityFleetId = scope.fleetId
|
|
|
20565
20721
|
async function installedTargetStateForGraph(scope, graph, manifests, owners, selected, identityFleetId = scope.fleetId ?? null) {
|
|
20566
20722
|
const stable = await targetStateForGraph(scope, graph, identityFleetId);
|
|
20567
20723
|
let state;
|
|
20568
|
-
if (
|
|
20724
|
+
if (resolve44(graph.path) === resolve44(stable.graphLockPath)) {
|
|
20569
20725
|
state = stable;
|
|
20570
20726
|
} else {
|
|
20571
20727
|
const released = await releasedTargetStateForGraph(scope, graph, identityFleetId);
|
|
20572
|
-
if (
|
|
20728
|
+
if (resolve44(graph.path) !== resolve44(released.graphLockPath)) {
|
|
20573
20729
|
throw new Error(`Graph lock target identity is stale or noncanonical: ${graph.path}`);
|
|
20574
20730
|
}
|
|
20575
20731
|
state = released;
|
|
20576
20732
|
}
|
|
20577
|
-
const manifest = manifests.find((candidate) =>
|
|
20733
|
+
const manifest = manifests.find((candidate) => resolve44(candidate.path) === resolve44(state.manifestPath));
|
|
20578
20734
|
if (!manifest) {
|
|
20579
20735
|
throw new Error(`Graph lock is not covered by its canonical install manifest: ${state.manifestPath}`);
|
|
20580
20736
|
}
|
|
@@ -20598,7 +20754,7 @@ async function releasedTargetStateForGraph(scope, graph, identityFleetId = scope
|
|
|
20598
20754
|
...current,
|
|
20599
20755
|
stateKey,
|
|
20600
20756
|
targetFingerprint,
|
|
20601
|
-
graphLockPath:
|
|
20757
|
+
graphLockPath: join61(dirname37(graph.path), `${targetFingerprint}.graph-lock.json`),
|
|
20602
20758
|
manifestPath: installManifestPath(current.installRoot, current.adapter, {
|
|
20603
20759
|
installationType: current.installationType,
|
|
20604
20760
|
stateKey
|
|
@@ -20606,7 +20762,7 @@ async function releasedTargetStateForGraph(scope, graph, identityFleetId = scope
|
|
|
20606
20762
|
};
|
|
20607
20763
|
}
|
|
20608
20764
|
function assertCorrelatedGraphManifest(graph, state, manifest, owners, selected) {
|
|
20609
|
-
if (manifest.manifest.adapter !== state.adapter || manifest.manifest.installationType !== state.installationType || manifest.manifest.stateKey !== state.stateKey ||
|
|
20765
|
+
if (manifest.manifest.adapter !== state.adapter || manifest.manifest.installationType !== state.installationType || manifest.manifest.stateKey !== state.stateKey || resolve44(manifest.manifest.targetRoot) !== resolve44(state.installRoot)) {
|
|
20610
20766
|
throw new Error(`Install manifest identity does not match graph target state: ${manifest.path}`);
|
|
20611
20767
|
}
|
|
20612
20768
|
const entries = manifest.manifest.entries.filter((entry) => entryMatchesGraphPackages(entry, graph.lock, selected));
|
|
@@ -20663,7 +20819,7 @@ function destinationGraphFromSource(source, targetFingerprint) {
|
|
|
20663
20819
|
function mergeDestinationManifest(existing, state, generatedAt, desiredEntries, replaceOwners = /* @__PURE__ */ new Set()) {
|
|
20664
20820
|
if (existing) {
|
|
20665
20821
|
const manifest2 = existing.manifest;
|
|
20666
|
-
if (manifest2.adapter !== state.adapter || manifest2.installationType !== state.installationType || manifest2.stateKey !== state.stateKey ||
|
|
20822
|
+
if (manifest2.adapter !== state.adapter || manifest2.installationType !== state.installationType || manifest2.stateKey !== state.stateKey || resolve44(manifest2.targetRoot) !== state.installRoot) {
|
|
20667
20823
|
throw new Error(`Destination manifest identity diverges from the derived target: ${existing.path}`);
|
|
20668
20824
|
}
|
|
20669
20825
|
}
|
|
@@ -20723,7 +20879,7 @@ async function assertEquivalentRuntimeState(entry, sourcePath, destinationPath)
|
|
|
20723
20879
|
const content = await readFile44(path, "utf8");
|
|
20724
20880
|
if (hasMergeRemovalContent(entry.mergeRemoval)) {
|
|
20725
20881
|
assertExactMergeContribution(entry.mergeRemoval, entry.mergeStrategy, content);
|
|
20726
|
-
} else if (
|
|
20882
|
+
} else if (resolve44(sourcePath) === resolve44(destinationPath) && entry.mergeStrategy !== "codex-toml-mcp") {
|
|
20727
20883
|
assertExactMergeContribution({}, entry.mergeStrategy, content);
|
|
20728
20884
|
} else {
|
|
20729
20885
|
throw new Error(`Installed-state normalization cannot prove incomplete merge ownership at ${path}.`);
|
|
@@ -20734,8 +20890,8 @@ async function assertEquivalentRuntimeState(entry, sourcePath, destinationPath)
|
|
|
20734
20890
|
await assertEquivalentRuntimeBytes(sourcePath, destinationPath, entry.hash);
|
|
20735
20891
|
}
|
|
20736
20892
|
function renderedEntryPathForRoot(root, entryPath) {
|
|
20737
|
-
const normalizedRoot =
|
|
20738
|
-
const candidate =
|
|
20893
|
+
const normalizedRoot = resolve44(root);
|
|
20894
|
+
const candidate = resolve44(normalizedRoot, entryPath);
|
|
20739
20895
|
if (candidate !== normalizedRoot && !candidate.startsWith(`${normalizedRoot}/`)) {
|
|
20740
20896
|
throw new Error(`Install manifest entry escapes its target root: ${entryPath}`);
|
|
20741
20897
|
}
|
|
@@ -20826,8 +20982,8 @@ function ownerMatchesGraphPackage(lock, owner, selected) {
|
|
|
20826
20982
|
return ownerMatchesPackage(owner, selected) || lock.canonical.roots.some((root) => selected.has(root.rootId) && root.graphNodeId === owner);
|
|
20827
20983
|
}
|
|
20828
20984
|
function renderedEntryPath(manifest, entry) {
|
|
20829
|
-
const root =
|
|
20830
|
-
const candidate =
|
|
20985
|
+
const root = resolve44(manifest.targetRoot);
|
|
20986
|
+
const candidate = resolve44(root, entry.path);
|
|
20831
20987
|
if (candidate !== root && !candidate.startsWith(`${root}/`)) {
|
|
20832
20988
|
throw new Error(`Install manifest entry escapes its target root: ${entry.path}`);
|
|
20833
20989
|
}
|
|
@@ -21168,7 +21324,7 @@ function configRevision(config) {
|
|
|
21168
21324
|
return sha2567(canonicalJson8(config));
|
|
21169
21325
|
}
|
|
21170
21326
|
function normalizationJournalPath(sourceRoot, destinationFleet) {
|
|
21171
|
-
return
|
|
21327
|
+
return join61(sourceRoot, ".agentwheel", `fleet-normalize-${destinationFleet}.journal.json`);
|
|
21172
21328
|
}
|
|
21173
21329
|
function canonicalJson8(value) {
|
|
21174
21330
|
return JSON.stringify(sortValue(value));
|
|
@@ -21181,7 +21337,7 @@ function sortValue(value) {
|
|
|
21181
21337
|
return value;
|
|
21182
21338
|
}
|
|
21183
21339
|
function sha2567(value) {
|
|
21184
|
-
return
|
|
21340
|
+
return createHash28("sha256").update(value).digest("hex");
|
|
21185
21341
|
}
|
|
21186
21342
|
function assertDigest(value) {
|
|
21187
21343
|
if (!/^[a-f0-9]{64}$/.test(value)) throw new Error(`Invalid plan digest: ${value}`);
|
|
@@ -21335,7 +21491,7 @@ fleetCommand.command("normalize").description("plan or apply duplicate desired-s
|
|
|
21335
21491
|
});
|
|
21336
21492
|
cacheCommand.command("prune").description("remove old Git source snapshots while preserving locked commits").option("--user", "use the user workspace", false).option("--local", "use the nearest local workspace", false).option("--fleet <id>", "use one registered named fleet").option("-t, --target-root <path>", "explicit workspace root").option("--keep <count>", "newest snapshots to retain per source", parsePositiveInteger, 3).option("--apply", "delete the selected snapshots; without this flag only preview", false).action(async (options) => {
|
|
21337
21493
|
const targetRoot = await workspaceContextRootFromOptions(normalizeRuntimeScopeOptions(options));
|
|
21338
|
-
const cacheRoot =
|
|
21494
|
+
const cacheRoot = join62(targetRoot, ".agentwheel", "cache");
|
|
21339
21495
|
const result = await pruneGitCache(cacheRoot, { keepSnapshots: options.keep, dryRun: !options.apply });
|
|
21340
21496
|
const verb = options.apply ? "Removed" : "Would remove";
|
|
21341
21497
|
for (const path of result.removedPaths) console.log(`${verb} ${path}`);
|
|
@@ -21355,7 +21511,7 @@ program.command("pin").description("pin configured revisions or replace package
|
|
|
21355
21511
|
throw new Error("Choose pin <alias> <commit> [--select ...], --pins-file <path>, or --packages-file <path>, exclusively.");
|
|
21356
21512
|
}
|
|
21357
21513
|
const inputFile = options.packagesFile ?? options.pinsFile;
|
|
21358
|
-
const input = inputFile ? JSON.parse(await readFile45(
|
|
21514
|
+
const input = inputFile ? JSON.parse(await readFile45(resolve45(inputFile), "utf8")) : [{ alias, commit, ...options.select === void 0 ? {} : { select: options.select } }];
|
|
21359
21515
|
const config = await pinConfiguredPackages(workspaceRoot, input, {
|
|
21360
21516
|
dryRun: options.dryRun,
|
|
21361
21517
|
replacePackages: options.packagesFile !== void 0
|
|
@@ -21368,7 +21524,7 @@ program.command("list").description("list artifacts exposed by a package source"
|
|
|
21368
21524
|
const resolvedInput = await resolvePackageSource(source, targetRoot);
|
|
21369
21525
|
const selectedArtifacts = selectedArtifactsFromOptionsOrRegistry(options, resolvedInput.registryEntry);
|
|
21370
21526
|
const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
|
|
21371
|
-
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot:
|
|
21527
|
+
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot: join62(targetRoot, ".agentwheel", "cache") }))));
|
|
21372
21528
|
try {
|
|
21373
21529
|
const artifacts = filterArtifactsBySelection(await driver.list(resolved), selectedArtifacts);
|
|
21374
21530
|
for (const artifact of artifacts) {
|
|
@@ -21437,7 +21593,7 @@ program.command("try").description("read and validate one skill for the current
|
|
|
21437
21593
|
const resolvedInput = await resolvePackageSource(source, targetRoot);
|
|
21438
21594
|
const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
|
|
21439
21595
|
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, {
|
|
21440
|
-
cacheRoot:
|
|
21596
|
+
cacheRoot: join62(targetRoot, ".agentwheel", "cache")
|
|
21441
21597
|
}))));
|
|
21442
21598
|
try {
|
|
21443
21599
|
const trial = await createSkillTrial(driver, resolved, selectedArtifactsFromOptionsOrRegistry(options, resolvedInput.registryEntry));
|
|
@@ -21459,7 +21615,7 @@ program.command("scan").description("scan a package source for validation findin
|
|
|
21459
21615
|
const targetRoot = await workspaceContextRootFromOptions(normalizeRuntimeScopeOptions(options));
|
|
21460
21616
|
const resolvedInput = await resolvePackageSource(source, targetRoot);
|
|
21461
21617
|
const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
|
|
21462
|
-
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot:
|
|
21618
|
+
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot: join62(targetRoot, ".agentwheel", "cache") }))));
|
|
21463
21619
|
try {
|
|
21464
21620
|
const result = await driver.scan(resolved);
|
|
21465
21621
|
if (result.findings.length === 0) {
|
|
@@ -21715,11 +21871,15 @@ ownershipCommand.command("handoff").description("transfer one managed artifact b
|
|
|
21715
21871
|
const toWorkspaceRoot = normalizeCliPath(options.toWorkspaceRoot);
|
|
21716
21872
|
if (options.toFleet) {
|
|
21717
21873
|
const fleet = await showRegisteredFleet(options.toFleet);
|
|
21718
|
-
if (
|
|
21874
|
+
if (resolve45(fleet.root) !== resolve45(toWorkspaceRoot)) {
|
|
21719
21875
|
throw new Error(`Destination fleet '${options.toFleet}' is registered at ${fleet.root}, not ${toWorkspaceRoot}.`);
|
|
21720
21876
|
}
|
|
21721
21877
|
}
|
|
21722
21878
|
const request = {
|
|
21879
|
+
workspaceRoot: await workspaceRootFromOptions(normalizedOptions),
|
|
21880
|
+
reason: options.reason,
|
|
21881
|
+
operationId: options.operationId,
|
|
21882
|
+
noCommit: options.commit === false,
|
|
21723
21883
|
installationType,
|
|
21724
21884
|
stateKey: state.stableStateKey,
|
|
21725
21885
|
targetRoot: state.installRoot,
|
|
@@ -21756,8 +21916,8 @@ ownershipCommand.command("recovery-plan").description("write a read-only per-pat
|
|
|
21756
21916
|
const adapter = await resolveAdapterForTarget(target, {});
|
|
21757
21917
|
const transport = transportForTarget(target);
|
|
21758
21918
|
const requestedReport = normalizeCliPath(options.report);
|
|
21759
|
-
const reportPath =
|
|
21760
|
-
const reportInsideTarget = relative19(
|
|
21919
|
+
const reportPath = join62(await realpath4(dirname38(requestedReport)), basename24(requestedReport));
|
|
21920
|
+
const reportInsideTarget = relative19(resolve45(target.targetRoot), reportPath);
|
|
21761
21921
|
if (reportInsideTarget === "" || !reportInsideTarget.startsWith("..") && !isAbsolute14(reportInsideTarget)) {
|
|
21762
21922
|
throw new Error("Recovery report must be outside the runtime target root.");
|
|
21763
21923
|
}
|
|
@@ -21788,7 +21948,7 @@ ownershipCommand.command("retire-stale").description("retire stale source-manife
|
|
|
21788
21948
|
const normalizedOptions = normalizeRuntimeScopeOptions(options);
|
|
21789
21949
|
const fleet = await showRegisteredFleet(options.fleet);
|
|
21790
21950
|
const toWorkspaceRoot = normalizeCliPath(options.toWorkspaceRoot);
|
|
21791
|
-
if (
|
|
21951
|
+
if (resolve45(fleet.root) !== resolve45(toWorkspaceRoot)) {
|
|
21792
21952
|
throw new Error(`Destination Fleet '${options.fleet}' is registered at ${fleet.root}, not ${toWorkspaceRoot}.`);
|
|
21793
21953
|
}
|
|
21794
21954
|
const targets = await resolveCliTargets(normalizedOptions);
|
|
@@ -21796,7 +21956,7 @@ ownershipCommand.command("retire-stale").description("retire stale source-manife
|
|
|
21796
21956
|
throw new Error(`Stale ownership retirement requires exactly one destination Fleet target, found ${targets.length}.`);
|
|
21797
21957
|
}
|
|
21798
21958
|
const target = targets[0];
|
|
21799
|
-
if (target.fleetId !== options.fleet ||
|
|
21959
|
+
if (target.fleetId !== options.fleet || resolve45(target.workspaceRoot) !== resolve45(fleet.root)) {
|
|
21800
21960
|
throw new Error(`Resolved target does not belong to destination Fleet '${options.fleet}'.`);
|
|
21801
21961
|
}
|
|
21802
21962
|
const adapterOptions = adapterOptionsForTarget(target, normalizedOptions);
|
|
@@ -21918,7 +22078,7 @@ ownershipCommand.command("adopt-legacy").description("move proven legacy-keyed o
|
|
|
21918
22078
|
];
|
|
21919
22079
|
for (const { flag, requested, resolved, none } of requestedAdapterSettings) {
|
|
21920
22080
|
if (requested === void 0) continue;
|
|
21921
|
-
if (resolved !== void 0 &&
|
|
22081
|
+
if (resolved !== void 0 && resolve45(target.workspaceRoot, requested) === resolve45(target.workspaceRoot, resolved)) continue;
|
|
21922
22082
|
throw new Error(`${flag} ${requested} does not match what install resolves for the configured packages: ${resolved ?? none}.`);
|
|
21923
22083
|
}
|
|
21924
22084
|
const adapter = await resolveAdapterForTarget(group.target, adapterOptions);
|
|
@@ -22088,7 +22248,7 @@ journalCommand.command("list").description("show pending apply journals for reso
|
|
|
22088
22248
|
if (!journal) continue;
|
|
22089
22249
|
pending += 1;
|
|
22090
22250
|
console.log(`PENDING ${state.adapter.name}/${state.installationType} at ${state.installRoot}`);
|
|
22091
|
-
console.log(` journal: ${
|
|
22251
|
+
console.log(` journal: ${join62(state.installRoot, ".agentwheel", `${state.state.stateKey}.apply-journal.json`)}`);
|
|
22092
22252
|
console.log(` stateKey: ${state.state.stateKey}`);
|
|
22093
22253
|
console.log(` createdAt: ${journal.createdAt}`);
|
|
22094
22254
|
console.log(` updatedAt: ${journal.updatedAt}`);
|
|
@@ -22438,14 +22598,14 @@ async function packageEntryFromSource(source, targetRoot, options) {
|
|
|
22438
22598
|
);
|
|
22439
22599
|
}
|
|
22440
22600
|
const bundle = options.deferGraphRendering ? await stageSourceRaw(driver, resolvedSource, {
|
|
22441
|
-
cacheRoot:
|
|
22601
|
+
cacheRoot: join62(targetRoot, ".agentwheel", "cache"),
|
|
22442
22602
|
mode: options.mode,
|
|
22443
22603
|
ref: initialVersion?.ref,
|
|
22444
22604
|
frozenLock: lockMode
|
|
22445
22605
|
}) : await stageSource(driver, resolvedSource, {
|
|
22446
22606
|
workspaceRoot: targetRoot,
|
|
22447
22607
|
adapter,
|
|
22448
|
-
cacheRoot:
|
|
22608
|
+
cacheRoot: join62(targetRoot, ".agentwheel", "cache"),
|
|
22449
22609
|
mode: options.mode,
|
|
22450
22610
|
ref: initialVersion?.ref,
|
|
22451
22611
|
frozenLock: lockMode,
|
|
@@ -23054,7 +23214,7 @@ function scopeUpdatePlanToDependencies(result, selectors, previousLock, manifest
|
|
|
23054
23214
|
selectedPreviousNodeIds,
|
|
23055
23215
|
selectedRootIds
|
|
23056
23216
|
);
|
|
23057
|
-
const graphLockDigest =
|
|
23217
|
+
const graphLockDigest = createHash29("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
23058
23218
|
return {
|
|
23059
23219
|
...result,
|
|
23060
23220
|
bundle: { ...result.bundle, graphLock },
|
|
@@ -23180,7 +23340,7 @@ function operationBelongsToDependencyUpdate(operation, allowedNodeIds, allowedNa
|
|
|
23180
23340
|
function scopeInstallPlanToArtifact(result, rootId, focused, manifest) {
|
|
23181
23341
|
const scoped = scopePlanOperationsToArtifact(result, rootId, focused, manifest);
|
|
23182
23342
|
const graphLock = focusedGraphLockForInstall(scoped.bundle.graphLock, rootId, focused);
|
|
23183
|
-
const graphLockDigest =
|
|
23343
|
+
const graphLockDigest = createHash29("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
23184
23344
|
return {
|
|
23185
23345
|
...scoped,
|
|
23186
23346
|
bundle: { ...scoped.bundle, graphLock },
|
|
@@ -23191,7 +23351,7 @@ function scopeInstallPlanToArtifact(result, rootId, focused, manifest) {
|
|
|
23191
23351
|
function scopeUpdatePlanToArtifact(result, rootId, focused, previousLock, manifest) {
|
|
23192
23352
|
const scoped = scopePlanOperationsToArtifact(result, rootId, focused, manifest, previousLock);
|
|
23193
23353
|
const graphLock = mergeFocusedArtifactGraphLock(scoped.bundle.graphLock, previousLock, rootId, focused);
|
|
23194
|
-
const graphLockDigest =
|
|
23354
|
+
const graphLockDigest = createHash29("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
23195
23355
|
return {
|
|
23196
23356
|
...scoped,
|
|
23197
23357
|
bundle: { ...scoped.bundle, graphLock },
|
|
@@ -23486,7 +23646,7 @@ function scopeUpdatePlanToRoot(result, rootId, previousLock, manifest) {
|
|
|
23486
23646
|
selectedPreviousNodeIds,
|
|
23487
23647
|
/* @__PURE__ */ new Set([rootId])
|
|
23488
23648
|
);
|
|
23489
|
-
const graphLockDigest =
|
|
23649
|
+
const graphLockDigest = createHash29("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
23490
23650
|
return {
|
|
23491
23651
|
...scoped,
|
|
23492
23652
|
bundle: { ...scoped.bundle, graphLock },
|
|
@@ -23558,7 +23718,7 @@ function keepManifestEntryOperation(entry, targetRoot, scopeDescription, operati
|
|
|
23558
23718
|
artifactType: entry.artifactType,
|
|
23559
23719
|
artifactName: entry.artifactName,
|
|
23560
23720
|
kind: entry.kind,
|
|
23561
|
-
destPath: operation?.destPath ??
|
|
23721
|
+
destPath: operation?.destPath ?? join62(targetRoot, entry.path),
|
|
23562
23722
|
relativeDestPath: entry.path,
|
|
23563
23723
|
desiredHash: entry.sourceHash,
|
|
23564
23724
|
currentHash: operation?.currentHash ?? entry.hash,
|
|
@@ -23759,7 +23919,7 @@ function installRootContextForTarget(target) {
|
|
|
23759
23919
|
return { kind: target.transport, homeRoot: target.runAs?.home };
|
|
23760
23920
|
}
|
|
23761
23921
|
async function withFreshReadOnlyGraphPlan(target, adapter, adapterOptions, installationType, packages, use) {
|
|
23762
|
-
const stage = await mkdtemp6(
|
|
23922
|
+
const stage = await mkdtemp6(join62(tmpdir7(), "agentwheel-recovery-"));
|
|
23763
23923
|
const priorTmpdir = process.env.TMPDIR;
|
|
23764
23924
|
try {
|
|
23765
23925
|
process.env.TMPDIR = stage;
|
|
@@ -23791,8 +23951,8 @@ async function withFreshReadOnlyGraphPlan(target, adapter, adapterOptions, insta
|
|
|
23791
23951
|
yes: true,
|
|
23792
23952
|
freshGraphOnly: true,
|
|
23793
23953
|
deferForeignStateCheck: true,
|
|
23794
|
-
cacheRoot:
|
|
23795
|
-
registryCachePath:
|
|
23954
|
+
cacheRoot: join62(stage, "source-cache"),
|
|
23955
|
+
registryCachePath: join62(stage, "registry.json")
|
|
23796
23956
|
});
|
|
23797
23957
|
return await use(graphPlan);
|
|
23798
23958
|
} finally {
|
|
@@ -23879,7 +24039,7 @@ async function resolveCliTargetState(target, options) {
|
|
|
23879
24039
|
migration: prior.migration,
|
|
23880
24040
|
targetStateFilePreconditions: {
|
|
23881
24041
|
graphLockPath: stableGraphLockPath,
|
|
23882
|
-
graphLockRevision: stableLock ?
|
|
24042
|
+
graphLockRevision: stableLock ? createHash29("sha256").update(canonicalGraphLockJson(stableLock)).digest("hex") : null,
|
|
23883
24043
|
sourceLockRevision: computeSourceLockRevision(stableSourceLock)
|
|
23884
24044
|
}
|
|
23885
24045
|
};
|
|
@@ -23902,7 +24062,7 @@ async function collectTargetStatus(target, options) {
|
|
|
23902
24062
|
const pending = await collectPendingInstallWork(target, options);
|
|
23903
24063
|
const foreignObservations = pending.foreignStateObservations;
|
|
23904
24064
|
const effectiveGraphLock = graphLock ?? pending.observedGraphLock;
|
|
23905
|
-
const observedManifestRevision = foreignObservations.length > 0 ?
|
|
24065
|
+
const observedManifestRevision = foreignObservations.length > 0 ? createHash29("sha256").update(JSON.stringify(foreignObservations.map((observation) => [
|
|
23906
24066
|
observation.fileName,
|
|
23907
24067
|
observation.manifestRevision
|
|
23908
24068
|
]).sort())).digest("hex") : null;
|
|
@@ -24149,7 +24309,7 @@ async function assertCompositeMutationSupported(workspaceRoot, profile, readOnly
|
|
|
24149
24309
|
`Composite-profile mutation is refused before member execution because ${member.id} uses ${member.transport}; durable remote policy and recovery preflight is not implemented.`
|
|
24150
24310
|
);
|
|
24151
24311
|
}
|
|
24152
|
-
const memberRoot =
|
|
24312
|
+
const memberRoot = resolve45(workspaceRoot, member.workspace);
|
|
24153
24313
|
const memberPolicy = await mutationPolicyForWorkspace(memberRoot);
|
|
24154
24314
|
if (memberPolicy?.revisioning.mode === "commit-after-verify") {
|
|
24155
24315
|
throw new Error(
|
|
@@ -24386,12 +24546,12 @@ async function printDoctor(target, options) {
|
|
|
24386
24546
|
const requestedSkills = doctorSkillRequests(target, options);
|
|
24387
24547
|
const skills = [];
|
|
24388
24548
|
for (const request of requestedSkills) {
|
|
24389
|
-
const skillPath =
|
|
24549
|
+
const skillPath = join62(state.installRoot, targetMapping.dest, request.name);
|
|
24390
24550
|
const exists2 = await pathExists(skillPath);
|
|
24391
24551
|
const manifestEntry = manifest?.entries.find((entry) => {
|
|
24392
24552
|
if (entry.artifactType !== "skills") return false;
|
|
24393
24553
|
const legacyInstallName = "installName" in entry && typeof entry.installName === "string" ? entry.installName : void 0;
|
|
24394
|
-
return entry.artifactName === request.name || legacyInstallName === request.name || entry.path ===
|
|
24554
|
+
return entry.artifactName === request.name || legacyInstallName === request.name || entry.path === join62(targetMapping.dest, request.name);
|
|
24395
24555
|
});
|
|
24396
24556
|
const status = manifestEntry ? "managed" : exists2 ? "present-unmanaged" : "missing";
|
|
24397
24557
|
skills.push({
|
|
@@ -24471,7 +24631,7 @@ function doctorSkillLabel(name) {
|
|
|
24471
24631
|
return `${name} skill`;
|
|
24472
24632
|
}
|
|
24473
24633
|
function isSyncwheelWorkspace(targetRoot) {
|
|
24474
|
-
return existsSync(
|
|
24634
|
+
return existsSync(join62(targetRoot, ".syncwheel", "manifest.json"));
|
|
24475
24635
|
}
|
|
24476
24636
|
function skillInstallCommand(adapter, installationType, options, skill, behavior = {}) {
|
|
24477
24637
|
const args = [
|
|
@@ -24634,14 +24794,14 @@ function looksLikeSourceSpecifier(value) {
|
|
|
24634
24794
|
}
|
|
24635
24795
|
function normalizeCliPath(value) {
|
|
24636
24796
|
if (value === "~") return homedir18();
|
|
24637
|
-
if (value.startsWith("~/")) return
|
|
24638
|
-
return
|
|
24797
|
+
if (value.startsWith("~/")) return resolve45(homedir18(), value.slice(2));
|
|
24798
|
+
return resolve45(value);
|
|
24639
24799
|
}
|
|
24640
24800
|
function shellQuoteArgument(value) {
|
|
24641
24801
|
return /^[a-z0-9_./:@%+=,-]+$/i.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
24642
24802
|
}
|
|
24643
24803
|
function isHomePath(path) {
|
|
24644
|
-
return
|
|
24804
|
+
return resolve45(path) === resolve45(homedir18());
|
|
24645
24805
|
}
|
|
24646
24806
|
function adapterListFromOption(adapter) {
|
|
24647
24807
|
if (!adapter) return [];
|
|
@@ -24696,11 +24856,11 @@ function filterUninstallPlanBySelection(plan, selected) {
|
|
|
24696
24856
|
};
|
|
24697
24857
|
}
|
|
24698
24858
|
async function initPackage(root) {
|
|
24699
|
-
await mkdir27(
|
|
24700
|
-
await mkdir27(
|
|
24701
|
-
await mkdir27(
|
|
24702
|
-
const manifestPath =
|
|
24703
|
-
const instructionsPath =
|
|
24859
|
+
await mkdir27(join62(root, "instructions"), { recursive: true });
|
|
24860
|
+
await mkdir27(join62(root, "rules"), { recursive: true });
|
|
24861
|
+
await mkdir27(join62(root, "skills"), { recursive: true });
|
|
24862
|
+
const manifestPath = join62(root, "openpack.json");
|
|
24863
|
+
const instructionsPath = join62(root, "instructions", "AGENTS.md");
|
|
24704
24864
|
const manifest = {
|
|
24705
24865
|
schemaVersion: CURRENT_OPENPACK_SCHEMA_VERSION,
|
|
24706
24866
|
name: "example/agentwheel-package",
|
|
@@ -24718,7 +24878,7 @@ async function initPackage(root) {
|
|
|
24718
24878
|
await writeFile24(instructionsPath, "# Agent Instructions\n", "utf8");
|
|
24719
24879
|
}
|
|
24720
24880
|
async function defaultBootstrapPackage(_root) {
|
|
24721
|
-
const packageRoot = await findAgentwheelPackageRoot(
|
|
24881
|
+
const packageRoot = await findAgentwheelPackageRoot(dirname38(fileURLToPath4(import.meta.url)));
|
|
24722
24882
|
if (!packageRoot) return void 0;
|
|
24723
24883
|
return {
|
|
24724
24884
|
name: "agentwheel",
|
|
@@ -24762,10 +24922,10 @@ function withFleetExample(config) {
|
|
|
24762
24922
|
};
|
|
24763
24923
|
}
|
|
24764
24924
|
async function findAgentwheelPackageRoot(start) {
|
|
24765
|
-
let current =
|
|
24925
|
+
let current = resolve45(start);
|
|
24766
24926
|
while (true) {
|
|
24767
24927
|
if (await findPackageManifestPath(current, { warnLegacy: false })) return current;
|
|
24768
|
-
const parent =
|
|
24928
|
+
const parent = dirname38(current);
|
|
24769
24929
|
if (parent === current) return void 0;
|
|
24770
24930
|
current = parent;
|
|
24771
24931
|
}
|
|
@@ -24890,14 +25050,14 @@ async function governedCommandContext(command, options) {
|
|
|
24890
25050
|
const kind = String(command.args[0] ?? "workspace");
|
|
24891
25051
|
return {
|
|
24892
25052
|
workspaceRoot: workspaceRoot2,
|
|
24893
|
-
anticipatedPaths: kind === "package" ? [
|
|
25053
|
+
anticipatedPaths: kind === "package" ? [join62(targetRoot, "openpack.json"), join62(targetRoot, "instructions", "AGENTS.md")] : [workspaceConfigPath(targetRoot)]
|
|
24894
25054
|
};
|
|
24895
25055
|
}
|
|
24896
25056
|
if (path === "package migrate") {
|
|
24897
25057
|
const packageRoot = normalizeTargetRoot(String(command.args[0] ?? "."));
|
|
24898
25058
|
return {
|
|
24899
25059
|
workspaceRoot: await findExistingWorkspaceRoot(packageRoot) ?? packageRoot,
|
|
24900
|
-
anticipatedPaths: ["agentwheel.json", "agentwheel.jsonc", "openpack.json", "openpack.jsonc"].map((name) =>
|
|
25060
|
+
anticipatedPaths: ["agentwheel.json", "agentwheel.jsonc", "openpack.json", "openpack.jsonc"].map((name) => join62(packageRoot, name))
|
|
24901
25061
|
};
|
|
24902
25062
|
}
|
|
24903
25063
|
const source = typeof command.args[0] === "string" ? command.args[0] : void 0;
|
|
@@ -24909,14 +25069,13 @@ async function governedCommandContext(command, options) {
|
|
|
24909
25069
|
const anticipatedPaths = [];
|
|
24910
25070
|
if (path === "add" || path === "pin") anticipatedPaths.push(workspaceConfigPath(workspaceRoot));
|
|
24911
25071
|
if (path === "remember" && options.runtime) {
|
|
24912
|
-
anticipatedPaths.push(
|
|
25072
|
+
anticipatedPaths.push(join62(workspaceRoot, ".agentwheel", "overlays", options.runtime, "instructions.local.md"));
|
|
24913
25073
|
}
|
|
24914
25074
|
if (path === "uninstall" && source) anticipatedPaths.push(workspaceConfigPath(workspaceRoot));
|
|
24915
25075
|
return {
|
|
24916
25076
|
workspaceRoot,
|
|
24917
25077
|
anticipatedPaths,
|
|
24918
|
-
requireCleanWorkingTree: requiresCleanMutationPreflight(path)
|
|
24919
|
-
requiresDeclarativeRepositoryDelta: path === "ownership handoff"
|
|
25078
|
+
requireCleanWorkingTree: requiresCleanMutationPreflight(path)
|
|
24920
25079
|
};
|
|
24921
25080
|
}
|
|
24922
25081
|
function commandPath(command) {
|