akm-cli 0.9.10 → 0.9.11
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/CHANGELOG.md +60 -0
- package/STABILITY.md +22 -14
- package/dist/commands/health/checks.js +23 -7
- package/dist/commands/health/improve-metrics.js +12 -0
- package/dist/commands/improve/distill/quality-gate.js +13 -5
- package/dist/commands/improve/eval-cases.js +9 -2
- package/dist/commands/improve/improve.js +19 -4
- package/dist/commands/improve/loop-stages.js +13 -3
- package/dist/commands/tasks/tasks-cli.js +32 -0
- package/dist/commands/tasks/validate.js +186 -0
- package/dist/commands/url-checker.js +75 -16
- package/dist/core/bundle-id.js +7 -1
- package/dist/core/config/schema/engines.js +17 -0
- package/dist/core/improve-result.js +8 -0
- package/dist/core/paths.js +112 -0
- package/dist/indexer/search/search-source.js +3 -2
- package/dist/integrations/agent/engine-resolution.js +92 -3
- package/dist/integrations/agent/execution-lowering.js +15 -2
- package/dist/integrations/agent/runner-dispatch.js +16 -3
- package/dist/integrations/agent/runner.js +2 -0
- package/dist/output/shapes/passthrough.js +1 -0
- package/dist/scripts/akm-migrate-node.js +1043 -822
- package/dist/scripts/akm-migrate.js +1043 -822
- package/dist/tasks/scheduler-sync.js +51 -25
- package/dist/workflows/exec/dispatch-redaction.js +21 -7
- package/docs/integration/bundling-akm.md +1 -1
- package/docs/migration/v0.8-to-v0.9.md +32 -0
- package/docs/reference/cli.md +31 -5
- package/docs/reference/configuration.md +12 -2
- package/docs/reference/data-and-telemetry.md +1 -1
- package/docs/reference/tasks.md +8 -0
- package/package.json +1 -1
- package/schemas/akm-config.json +8 -0
|
@@ -7124,6 +7124,136 @@ var init_errors = __esm(() => {
|
|
|
7124
7124
|
};
|
|
7125
7125
|
});
|
|
7126
7126
|
|
|
7127
|
+
// src/core/asset/asset-ref.ts
|
|
7128
|
+
import path from "node:path";
|
|
7129
|
+
function validateName(name) {
|
|
7130
|
+
if (!name)
|
|
7131
|
+
throw new UsageError("Empty asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
7132
|
+
if (name.includes("\x00"))
|
|
7133
|
+
throw new UsageError("Null byte in asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
7134
|
+
if (/^[A-Za-z]:/.test(name))
|
|
7135
|
+
throw new UsageError("Windows drive path in asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
7136
|
+
const slashName = name.replace(/\\/g, "/");
|
|
7137
|
+
if (slashName === ".." || slashName.startsWith("../")) {
|
|
7138
|
+
throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
7139
|
+
}
|
|
7140
|
+
if (slashName.split("/").some((seg) => seg === "." || seg === "..")) {
|
|
7141
|
+
throw new UsageError("Asset name cannot contain relative path segments.", "MISSING_REQUIRED_ARGUMENT");
|
|
7142
|
+
}
|
|
7143
|
+
const normalized = path.posix.normalize(slashName);
|
|
7144
|
+
if (path.posix.isAbsolute(normalized))
|
|
7145
|
+
throw new UsageError("Absolute path in asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
7146
|
+
if (normalized === ".." || normalized.startsWith("../")) {
|
|
7147
|
+
throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
7148
|
+
}
|
|
7149
|
+
}
|
|
7150
|
+
function normalizeName(name) {
|
|
7151
|
+
return path.posix.normalize(name.replace(/\\/g, "/"));
|
|
7152
|
+
}
|
|
7153
|
+
function isBundleSlug(s) {
|
|
7154
|
+
return BUNDLE_SLUG_RE.test(s);
|
|
7155
|
+
}
|
|
7156
|
+
function normalizeConceptId(raw) {
|
|
7157
|
+
const nfc = raw.normalize("NFC");
|
|
7158
|
+
if (nfc.includes("#")) {
|
|
7159
|
+
throw new UsageError("`#` is reserved for the export fragment in a concept id.", "MISSING_REQUIRED_ARGUMENT");
|
|
7160
|
+
}
|
|
7161
|
+
validateName(nfc);
|
|
7162
|
+
return normalizeName(nfc);
|
|
7163
|
+
}
|
|
7164
|
+
function makeBundleRef(bundle, conceptId, fragment) {
|
|
7165
|
+
const normalized = normalizeConceptId(conceptId);
|
|
7166
|
+
let out = normalized;
|
|
7167
|
+
if (bundle) {
|
|
7168
|
+
if (!BUNDLE_SLUG_RE.test(bundle)) {
|
|
7169
|
+
throw new UsageError(`Invalid bundle slug "${bundle}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
|
|
7170
|
+
}
|
|
7171
|
+
out = `${bundle}//${normalized}`;
|
|
7172
|
+
}
|
|
7173
|
+
if (fragment)
|
|
7174
|
+
out = `${out}#${fragment}`;
|
|
7175
|
+
return out;
|
|
7176
|
+
}
|
|
7177
|
+
function bundleRefToString(ref) {
|
|
7178
|
+
return makeBundleRef(ref.bundle, ref.conceptId, ref.fragment);
|
|
7179
|
+
}
|
|
7180
|
+
function parseBundleRef(ref) {
|
|
7181
|
+
const trimmed = ref.trim();
|
|
7182
|
+
if (!trimmed)
|
|
7183
|
+
throw new UsageError("Empty ref.", "MISSING_REQUIRED_ARGUMENT");
|
|
7184
|
+
let bundle;
|
|
7185
|
+
let body = trimmed;
|
|
7186
|
+
const boundary = trimmed.indexOf("//");
|
|
7187
|
+
if (boundary >= 0) {
|
|
7188
|
+
bundle = trimmed.slice(0, boundary);
|
|
7189
|
+
body = trimmed.slice(boundary + 2);
|
|
7190
|
+
if (!bundle)
|
|
7191
|
+
throw new UsageError("Empty bundle in ref.", "MISSING_REQUIRED_ARGUMENT");
|
|
7192
|
+
if (!BUNDLE_SLUG_RE.test(bundle)) {
|
|
7193
|
+
throw new UsageError(`Invalid bundle slug "${bundle}" in ref "${trimmed}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
|
|
7194
|
+
}
|
|
7195
|
+
}
|
|
7196
|
+
let fragment;
|
|
7197
|
+
const hash = body.indexOf("#");
|
|
7198
|
+
if (hash >= 0) {
|
|
7199
|
+
fragment = body.slice(hash + 1) || undefined;
|
|
7200
|
+
body = body.slice(0, hash);
|
|
7201
|
+
}
|
|
7202
|
+
if (!body) {
|
|
7203
|
+
throw new UsageError(`Invalid ref "${trimmed}". Expected [bundle//]conceptId, e.g. knowledge/guide or core//skills/review`, "MISSING_REQUIRED_ARGUMENT");
|
|
7204
|
+
}
|
|
7205
|
+
const conceptId = normalizeConceptId(body);
|
|
7206
|
+
return { bundle: bundle || undefined, conceptId, fragment };
|
|
7207
|
+
}
|
|
7208
|
+
var BUNDLE_SLUG_RE;
|
|
7209
|
+
var init_asset_ref = __esm(() => {
|
|
7210
|
+
init_errors();
|
|
7211
|
+
BUNDLE_SLUG_RE = /^[^\s:.#/]+$/;
|
|
7212
|
+
});
|
|
7213
|
+
|
|
7214
|
+
// src/core/bundle-id.ts
|
|
7215
|
+
import crypto2 from "node:crypto";
|
|
7216
|
+
import path2 from "node:path";
|
|
7217
|
+
function slugForPath(sourcePath) {
|
|
7218
|
+
const resolved = path2.resolve(sourcePath);
|
|
7219
|
+
const base = path2.basename(resolved).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
7220
|
+
if (base.length > 0)
|
|
7221
|
+
return base;
|
|
7222
|
+
return `bundle-${shortHash(resolved)}`;
|
|
7223
|
+
}
|
|
7224
|
+
function deriveBundleId(registryId, sourcePath, usedIds) {
|
|
7225
|
+
const preferred = registryId && registryId.length > 0 && isBundleSlug(registryId) ? registryId : slugForPath(sourcePath);
|
|
7226
|
+
const id = ensureUniqueId(preferred, sourcePath, usedIds);
|
|
7227
|
+
usedIds.add(id);
|
|
7228
|
+
return id;
|
|
7229
|
+
}
|
|
7230
|
+
function deriveBundleIds(sources) {
|
|
7231
|
+
const usedIds = new Set;
|
|
7232
|
+
const reservedIds = new Set(sources.flatMap((source) => source.registryId && isBundleSlug(source.registryId) ? [source.registryId] : []));
|
|
7233
|
+
return sources.map((source) => {
|
|
7234
|
+
const id = source.registryId && isBundleSlug(source.registryId) ? deriveBundleId(source.registryId, source.path, usedIds) : deriveBundleId(undefined, source.path, new Set([...usedIds, ...reservedIds]));
|
|
7235
|
+
usedIds.add(id);
|
|
7236
|
+
return id;
|
|
7237
|
+
});
|
|
7238
|
+
}
|
|
7239
|
+
function ensureUniqueId(preferred, sourcePath, used) {
|
|
7240
|
+
if (!used.has(preferred))
|
|
7241
|
+
return preferred;
|
|
7242
|
+
const suffixed = `${preferred}-${shortHash(path2.resolve(sourcePath))}`;
|
|
7243
|
+
if (!used.has(suffixed))
|
|
7244
|
+
return suffixed;
|
|
7245
|
+
let n = 2;
|
|
7246
|
+
while (used.has(`${suffixed}-${n}`))
|
|
7247
|
+
n++;
|
|
7248
|
+
return `${suffixed}-${n}`;
|
|
7249
|
+
}
|
|
7250
|
+
function shortHash(input) {
|
|
7251
|
+
return crypto2.createHash("sha256").update(input).digest("hex").slice(0, 8);
|
|
7252
|
+
}
|
|
7253
|
+
var init_bundle_id = __esm(() => {
|
|
7254
|
+
init_asset_ref();
|
|
7255
|
+
});
|
|
7256
|
+
|
|
7127
7257
|
// src/core/platform.ts
|
|
7128
7258
|
var IS_WINDOWS;
|
|
7129
7259
|
var init_platform = __esm(() => {
|
|
@@ -7132,7 +7262,7 @@ var init_platform = __esm(() => {
|
|
|
7132
7262
|
|
|
7133
7263
|
// src/core/paths.ts
|
|
7134
7264
|
import os from "node:os";
|
|
7135
|
-
import
|
|
7265
|
+
import path3 from "node:path";
|
|
7136
7266
|
function isUnderBunTest(env) {
|
|
7137
7267
|
return env.BUN_TEST === "1" || env.NODE_ENV === "test";
|
|
7138
7268
|
}
|
|
@@ -7149,37 +7279,37 @@ function getConfigDir(env = process.env, platform = process.platform) {
|
|
|
7149
7279
|
if (platform === "win32") {
|
|
7150
7280
|
const appData = env.APPDATA?.trim();
|
|
7151
7281
|
if (appData)
|
|
7152
|
-
return
|
|
7282
|
+
return path3.join(appData, "akm");
|
|
7153
7283
|
} else {
|
|
7154
7284
|
const xdgConfigHome2 = env.XDG_CONFIG_HOME?.trim();
|
|
7155
7285
|
if (xdgConfigHome2)
|
|
7156
|
-
return
|
|
7286
|
+
return path3.join(xdgConfigHome2, "akm");
|
|
7157
7287
|
}
|
|
7158
7288
|
const stashOverride = env.AKM_BUNDLE_DIR?.trim();
|
|
7159
7289
|
if (stashOverride && isTransientStashPath(stashOverride)) {
|
|
7160
|
-
return
|
|
7290
|
+
return path3.join(stashOverride, ".akm");
|
|
7161
7291
|
}
|
|
7162
7292
|
if (platform === "win32") {
|
|
7163
7293
|
const appData = env.APPDATA?.trim();
|
|
7164
7294
|
if (appData)
|
|
7165
|
-
return
|
|
7295
|
+
return path3.join(appData, "akm");
|
|
7166
7296
|
const userProfile = env.USERPROFILE?.trim();
|
|
7167
7297
|
if (!userProfile) {
|
|
7168
7298
|
throw new ConfigError("Unable to determine config directory. Set APPDATA or USERPROFILE.", "CONFIG_DIR_UNRESOLVABLE");
|
|
7169
7299
|
}
|
|
7170
|
-
return
|
|
7300
|
+
return path3.join(userProfile, "AppData", "Roaming", "akm");
|
|
7171
7301
|
}
|
|
7172
7302
|
const xdgConfigHome = env.XDG_CONFIG_HOME?.trim();
|
|
7173
7303
|
if (xdgConfigHome)
|
|
7174
|
-
return
|
|
7304
|
+
return path3.join(xdgConfigHome, "akm");
|
|
7175
7305
|
const home = env.HOME?.trim();
|
|
7176
7306
|
if (!home) {
|
|
7177
7307
|
throw new ConfigError("Unable to determine config directory. Set XDG_CONFIG_HOME or HOME.", "CONFIG_DIR_UNRESOLVABLE");
|
|
7178
7308
|
}
|
|
7179
|
-
return
|
|
7309
|
+
return path3.join(home, ".config", "akm");
|
|
7180
7310
|
}
|
|
7181
7311
|
function getConfigPath(env = process.env) {
|
|
7182
|
-
return
|
|
7312
|
+
return path3.join(getConfigDir(env), "config.json");
|
|
7183
7313
|
}
|
|
7184
7314
|
function getCacheDir(env = process.env) {
|
|
7185
7315
|
const override = env.AKM_CACHE_DIR?.trim();
|
|
@@ -7188,22 +7318,22 @@ function getCacheDir(env = process.env) {
|
|
|
7188
7318
|
if (IS_WINDOWS) {
|
|
7189
7319
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
7190
7320
|
if (localAppData)
|
|
7191
|
-
return
|
|
7321
|
+
return path3.join(localAppData, "akm");
|
|
7192
7322
|
const userProfile = env.USERPROFILE?.trim();
|
|
7193
7323
|
if (userProfile)
|
|
7194
|
-
return
|
|
7324
|
+
return path3.join(userProfile, "AppData", "Local", "akm");
|
|
7195
7325
|
const appData = env.APPDATA?.trim();
|
|
7196
7326
|
if (appData) {
|
|
7197
|
-
return
|
|
7327
|
+
return path3.join(appData, "..", "Local", "akm");
|
|
7198
7328
|
}
|
|
7199
7329
|
} else {
|
|
7200
7330
|
const xdgCacheHome = env.XDG_CACHE_HOME?.trim();
|
|
7201
7331
|
if (xdgCacheHome)
|
|
7202
|
-
return
|
|
7332
|
+
return path3.join(xdgCacheHome, "akm");
|
|
7203
7333
|
}
|
|
7204
7334
|
const stashOverride = env.AKM_BUNDLE_DIR?.trim();
|
|
7205
7335
|
if (stashOverride && isTransientStashPath(stashOverride)) {
|
|
7206
|
-
return
|
|
7336
|
+
return path3.join(stashOverride, ".akm", "cache");
|
|
7207
7337
|
}
|
|
7208
7338
|
if (IS_WINDOWS) {
|
|
7209
7339
|
throw new ConfigError("Unable to determine cache directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
|
|
@@ -7211,11 +7341,11 @@ function getCacheDir(env = process.env) {
|
|
|
7211
7341
|
const home = env.HOME?.trim();
|
|
7212
7342
|
if (!home)
|
|
7213
7343
|
return homelessFallbackDir("akm-cache");
|
|
7214
|
-
return
|
|
7344
|
+
return path3.join(home, ".cache", "akm");
|
|
7215
7345
|
}
|
|
7216
7346
|
function homelessFallbackDir(kind) {
|
|
7217
7347
|
const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
|
|
7218
|
-
return
|
|
7348
|
+
return path3.join(os.tmpdir(), uid === undefined ? kind : `${kind}-${uid}`);
|
|
7219
7349
|
}
|
|
7220
7350
|
function getDataDir(env = process.env, platform = process.platform) {
|
|
7221
7351
|
const override = env.AKM_DATA_DIR?.trim();
|
|
@@ -7227,38 +7357,83 @@ function getDataDir(env = process.env, platform = process.platform) {
|
|
|
7227
7357
|
if (platform === "win32") {
|
|
7228
7358
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
7229
7359
|
if (localAppData)
|
|
7230
|
-
return
|
|
7360
|
+
return path3.join(localAppData, "akm", "data");
|
|
7231
7361
|
const userProfile = env.USERPROFILE?.trim();
|
|
7232
7362
|
if (userProfile)
|
|
7233
|
-
return
|
|
7363
|
+
return path3.join(userProfile, "AppData", "Local", "akm", "data");
|
|
7234
7364
|
const appData = env.APPDATA?.trim();
|
|
7235
7365
|
if (!appData) {
|
|
7236
7366
|
throw new ConfigError("Unable to determine data directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
|
|
7237
7367
|
}
|
|
7238
|
-
return
|
|
7368
|
+
return path3.join(appData, "..", "Local", "akm", "data");
|
|
7239
7369
|
}
|
|
7240
7370
|
const xdgDataHome = env.XDG_DATA_HOME?.trim();
|
|
7241
7371
|
if (xdgDataHome)
|
|
7242
|
-
return
|
|
7372
|
+
return path3.join(xdgDataHome, "akm");
|
|
7243
7373
|
const home = env.HOME?.trim();
|
|
7244
7374
|
if (!home)
|
|
7245
7375
|
return homelessFallbackDir("akm-data");
|
|
7246
|
-
return
|
|
7376
|
+
return path3.join(home, ".local", "share", "akm");
|
|
7247
7377
|
}
|
|
7248
7378
|
function getDbPath(env = process.env) {
|
|
7249
|
-
return
|
|
7379
|
+
return path3.join(getDataDir(env), "index.db");
|
|
7250
7380
|
}
|
|
7251
7381
|
function getMaintenanceBarrierPath() {
|
|
7252
|
-
return
|
|
7382
|
+
return path3.join(getDataDir(), "maintenance.barrier.lock");
|
|
7253
7383
|
}
|
|
7254
7384
|
function getLockfilePath() {
|
|
7255
|
-
return
|
|
7385
|
+
return path3.join(getDataDir(), "akm.lock");
|
|
7256
7386
|
}
|
|
7257
7387
|
function getRegistryCacheDir() {
|
|
7258
|
-
return
|
|
7388
|
+
return path3.join(getCacheDir(), "registry");
|
|
7259
7389
|
}
|
|
7260
7390
|
function getRegistryIndexCacheDir() {
|
|
7261
|
-
return
|
|
7391
|
+
return path3.join(getCacheDir(), "registry-index");
|
|
7392
|
+
}
|
|
7393
|
+
function getStateDir(env = process.env, platform = process.platform) {
|
|
7394
|
+
const override = env.AKM_STATE_DIR?.trim();
|
|
7395
|
+
if (override)
|
|
7396
|
+
return override;
|
|
7397
|
+
if (platform === "win32") {
|
|
7398
|
+
const localAppData = env.LOCALAPPDATA?.trim();
|
|
7399
|
+
if (localAppData)
|
|
7400
|
+
return path3.join(localAppData, "akm", "state");
|
|
7401
|
+
const userProfile = env.USERPROFILE?.trim();
|
|
7402
|
+
if (userProfile)
|
|
7403
|
+
return path3.join(userProfile, "AppData", "Local", "akm", "state");
|
|
7404
|
+
const appData = env.APPDATA?.trim();
|
|
7405
|
+
if (!appData) {
|
|
7406
|
+
throw new ConfigError("Unable to determine state directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
|
|
7407
|
+
}
|
|
7408
|
+
return path3.join(appData, "..", "Local", "akm", "state");
|
|
7409
|
+
}
|
|
7410
|
+
const xdgStateHome = env.XDG_STATE_HOME?.trim();
|
|
7411
|
+
if (xdgStateHome)
|
|
7412
|
+
return path3.join(xdgStateHome, "akm");
|
|
7413
|
+
const home = env.HOME?.trim();
|
|
7414
|
+
if (!home)
|
|
7415
|
+
return homelessFallbackDir("akm-state");
|
|
7416
|
+
return path3.join(home, ".local", "state", "akm");
|
|
7417
|
+
}
|
|
7418
|
+
function getStashStateKey(stashDir) {
|
|
7419
|
+
const resolved = path3.resolve(stashDir).replace(/\\/g, "/");
|
|
7420
|
+
const normalized = IS_WINDOWS ? resolved.toLowerCase() : resolved;
|
|
7421
|
+
return shortHash(normalized);
|
|
7422
|
+
}
|
|
7423
|
+
function stashScopedDir(base, stashDir) {
|
|
7424
|
+
return path3.join(base, getStashStateKey(stashDir));
|
|
7425
|
+
}
|
|
7426
|
+
function getDistillRejectedDir(stashDir) {
|
|
7427
|
+
return stashScopedDir(path3.join(getStateDir(), "improve", "distill-rejected"), stashDir);
|
|
7428
|
+
}
|
|
7429
|
+
function getEvalCasesDir(stashDir) {
|
|
7430
|
+
return stashScopedDir(path3.join(getStateDir(), "improve", "eval-cases"), stashDir);
|
|
7431
|
+
}
|
|
7432
|
+
function getMeasurementVerdictsDir(stashDir) {
|
|
7433
|
+
return stashScopedDir(path3.join(getStateDir(), "improve", "measurement", "verdicts"), stashDir);
|
|
7434
|
+
}
|
|
7435
|
+
function getUnresolvedSourcesDir(stashDir) {
|
|
7436
|
+
return stashScopedDir(path3.join(getCacheDir(), "index", "unresolved-sources"), stashDir);
|
|
7262
7437
|
}
|
|
7263
7438
|
function getDefaultStashDir(env = process.env) {
|
|
7264
7439
|
const override = env.AKM_BUNDLE_DIR?.trim();
|
|
@@ -7267,24 +7442,25 @@ function getDefaultStashDir(env = process.env) {
|
|
|
7267
7442
|
if (IS_WINDOWS) {
|
|
7268
7443
|
const userProfile = env.USERPROFILE?.trim();
|
|
7269
7444
|
if (userProfile)
|
|
7270
|
-
return
|
|
7271
|
-
return
|
|
7445
|
+
return path3.join(userProfile, "Documents", "akm");
|
|
7446
|
+
return path3.join("C:\\", "akm");
|
|
7272
7447
|
}
|
|
7273
7448
|
const home = env.HOME?.trim();
|
|
7274
7449
|
if (!home) {
|
|
7275
7450
|
throw new ConfigError("Unable to determine default bundle directory. Set HOME.", "STASH_DIR_NOT_FOUND");
|
|
7276
7451
|
}
|
|
7277
|
-
return
|
|
7452
|
+
return path3.join(home, "akm");
|
|
7278
7453
|
}
|
|
7279
7454
|
var init_paths = __esm(() => {
|
|
7455
|
+
init_bundle_id();
|
|
7280
7456
|
init_errors();
|
|
7281
7457
|
init_platform();
|
|
7282
7458
|
});
|
|
7283
7459
|
|
|
7284
7460
|
// src/core/common.ts
|
|
7285
|
-
import
|
|
7461
|
+
import crypto3 from "node:crypto";
|
|
7286
7462
|
import fs from "node:fs";
|
|
7287
|
-
import
|
|
7463
|
+
import path4 from "node:path";
|
|
7288
7464
|
function isHttpUrl(value) {
|
|
7289
7465
|
return !!value && /^https?:\/\//.test(value);
|
|
7290
7466
|
}
|
|
@@ -7362,7 +7538,7 @@ function stripJsonComments(text) {
|
|
|
7362
7538
|
return result;
|
|
7363
7539
|
}
|
|
7364
7540
|
function writeFileAtomic(target, content, mode) {
|
|
7365
|
-
const tmp = `${target}.tmp.${process.pid}.${
|
|
7541
|
+
const tmp = `${target}.tmp.${process.pid}.${crypto3.randomBytes(8).toString("hex")}`;
|
|
7366
7542
|
const data = typeof content === "string" ? Buffer.from(content) : content;
|
|
7367
7543
|
const fileMode = mode ?? 384;
|
|
7368
7544
|
let fd;
|
|
@@ -7417,7 +7593,7 @@ function writeFileAtomic(target, content, mode) {
|
|
|
7417
7593
|
if (process.platform !== "win32") {
|
|
7418
7594
|
let dirFd;
|
|
7419
7595
|
try {
|
|
7420
|
-
dirFd = fs.openSync(
|
|
7596
|
+
dirFd = fs.openSync(path4.dirname(target), "r");
|
|
7421
7597
|
} catch (error) {
|
|
7422
7598
|
if (hasErrnoCode(error, "EINVAL") || hasErrnoCode(error, "ENOTSUP"))
|
|
7423
7599
|
return;
|
|
@@ -7450,7 +7626,7 @@ function resolveStashDir(env = process.env) {
|
|
|
7450
7626
|
throw new ConfigError(`No bundle directory found. Run "akm bundle create" to create one at ${defaultDir}.`, "STASH_DIR_NOT_FOUND");
|
|
7451
7627
|
}
|
|
7452
7628
|
function validateStashDir(raw) {
|
|
7453
|
-
const stashDir =
|
|
7629
|
+
const stashDir = path4.resolve(raw);
|
|
7454
7630
|
let stat;
|
|
7455
7631
|
try {
|
|
7456
7632
|
stat = fs.statSync(stashDir);
|
|
@@ -7496,8 +7672,8 @@ function readStashDirFromConfig() {
|
|
|
7496
7672
|
const componentConfig = component;
|
|
7497
7673
|
if (typeof componentConfig.root !== "string")
|
|
7498
7674
|
return bundlePath;
|
|
7499
|
-
const bundleRoot =
|
|
7500
|
-
const componentRoot =
|
|
7675
|
+
const bundleRoot = path4.resolve(bundlePath);
|
|
7676
|
+
const componentRoot = path4.resolve(bundleRoot, componentConfig.root);
|
|
7501
7677
|
if (!isWithin(componentRoot, bundleRoot)) {
|
|
7502
7678
|
throw new ConfigError(`Component root "${componentConfig.root}" escapes bundle "${defaultBundle}".`, "INVALID_CONFIG_FILE");
|
|
7503
7679
|
}
|
|
@@ -7542,30 +7718,30 @@ function isAkmRegistryCachePath(filePath) {
|
|
|
7542
7718
|
return isWithin(filePath, getRegistryCacheDir()) || isWithin(filePath, getRegistryIndexCacheDir());
|
|
7543
7719
|
}
|
|
7544
7720
|
function isContainedResolvedPath(resolvedCandidate, resolvedRoot) {
|
|
7545
|
-
const rel =
|
|
7721
|
+
const rel = path4.relative(normalizeFsPathForComparison(resolvedRoot), normalizeFsPathForComparison(resolvedCandidate));
|
|
7546
7722
|
if (rel === "")
|
|
7547
7723
|
return true;
|
|
7548
|
-
if (
|
|
7724
|
+
if (path4.isAbsolute(rel))
|
|
7549
7725
|
return false;
|
|
7550
7726
|
return rel.split(/[/\\]+/)[0] !== "..";
|
|
7551
7727
|
}
|
|
7552
7728
|
function safeRealpath(p) {
|
|
7553
|
-
const resolved =
|
|
7729
|
+
const resolved = path4.resolve(p);
|
|
7554
7730
|
try {
|
|
7555
7731
|
return fs.realpathSync(resolved);
|
|
7556
7732
|
} catch {
|
|
7557
7733
|
const suffix = [];
|
|
7558
7734
|
let current = resolved;
|
|
7559
7735
|
for (;; ) {
|
|
7560
|
-
const parent =
|
|
7736
|
+
const parent = path4.dirname(current);
|
|
7561
7737
|
if (parent === current) {
|
|
7562
7738
|
return resolved;
|
|
7563
7739
|
}
|
|
7564
|
-
suffix.unshift(
|
|
7740
|
+
suffix.unshift(path4.basename(current));
|
|
7565
7741
|
current = parent;
|
|
7566
7742
|
try {
|
|
7567
7743
|
const realParent = fs.realpathSync(current);
|
|
7568
|
-
return
|
|
7744
|
+
return path4.join(realParent, ...suffix);
|
|
7569
7745
|
} catch {}
|
|
7570
7746
|
}
|
|
7571
7747
|
}
|
|
@@ -7879,7 +8055,7 @@ var init_recognition_util = __esm(() => {
|
|
|
7879
8055
|
|
|
7880
8056
|
// src/core/asset/asset-placement.ts
|
|
7881
8057
|
import fs2 from "node:fs";
|
|
7882
|
-
import
|
|
8058
|
+
import path7 from "node:path";
|
|
7883
8059
|
function placementSpecFor(type) {
|
|
7884
8060
|
return PLACEMENT_SPECS[type];
|
|
7885
8061
|
}
|
|
@@ -7903,10 +8079,10 @@ function deriveCanonicalAssetName(assetType, typeRoot, filePath) {
|
|
|
7903
8079
|
return PLACEMENT_SPECS[assetType]?.toCanonicalName(typeRoot, filePath);
|
|
7904
8080
|
}
|
|
7905
8081
|
function deriveCanonicalAssetNameFromStashRoot(assetType, stashRoot, filePath) {
|
|
7906
|
-
const relPath = toPosix(
|
|
8082
|
+
const relPath = toPosix(path7.relative(stashRoot, filePath));
|
|
7907
8083
|
const segments = relPath.split("/").filter(Boolean);
|
|
7908
8084
|
const firstSegment = segments[0];
|
|
7909
|
-
const typeRoot = firstSegment !== undefined && firstSegment === stashDirFor(assetType) ?
|
|
8085
|
+
const typeRoot = firstSegment !== undefined && firstSegment === stashDirFor(assetType) ? path7.join(stashRoot, firstSegment) : stashRoot;
|
|
7910
8086
|
return deriveCanonicalAssetName(assetType, typeRoot, filePath);
|
|
7911
8087
|
}
|
|
7912
8088
|
function assetPathForName(assetType, typeRoot, name) {
|
|
@@ -7925,8 +8101,8 @@ function assetPathCandidatesForName(assetType, typeRoot, name) {
|
|
|
7925
8101
|
const base = name === "default" ? "" : name.endsWith("/default") ? name.slice(0, -"default".length) : undefined;
|
|
7926
8102
|
if (base === undefined)
|
|
7927
8103
|
return [primary];
|
|
7928
|
-
const dotForm =
|
|
7929
|
-
const namedForm =
|
|
8104
|
+
const dotForm = path7.join(typeRoot, base, ".env");
|
|
8105
|
+
const namedForm = path7.join(typeRoot, base, "default.env");
|
|
7930
8106
|
return [...new Set([primary, dotForm, namedForm])];
|
|
7931
8107
|
}
|
|
7932
8108
|
var workflowSpec, markdownSpec, scriptSpec, BUILTIN_PLACEMENT_SPECS, PLACEMENT_SPECS;
|
|
@@ -7934,9 +8110,9 @@ var init_asset_placement = __esm(() => {
|
|
|
7934
8110
|
init_common();
|
|
7935
8111
|
init_recognition_util();
|
|
7936
8112
|
workflowSpec = {
|
|
7937
|
-
isRelevantFile: (fileName) => WORKFLOW_EXTENSIONS.includes(
|
|
8113
|
+
isRelevantFile: (fileName) => WORKFLOW_EXTENSIONS.includes(path7.extname(fileName).toLowerCase()),
|
|
7938
8114
|
toCanonicalName: (typeRoot, filePath) => {
|
|
7939
|
-
const rel = toPosix(
|
|
8115
|
+
const rel = toPosix(path7.relative(typeRoot, filePath));
|
|
7940
8116
|
for (const ext of WORKFLOW_EXTENSIONS) {
|
|
7941
8117
|
if (rel.toLowerCase().endsWith(ext))
|
|
7942
8118
|
return rel.slice(0, -ext.length);
|
|
@@ -7947,43 +8123,43 @@ var init_asset_placement = __esm(() => {
|
|
|
7947
8123
|
const lower = name.toLowerCase();
|
|
7948
8124
|
for (const ext of WORKFLOW_EXTENSIONS) {
|
|
7949
8125
|
if (lower.endsWith(ext))
|
|
7950
|
-
return
|
|
8126
|
+
return path7.join(typeRoot, name);
|
|
7951
8127
|
}
|
|
7952
8128
|
for (const ext of WORKFLOW_EXTENSIONS) {
|
|
7953
|
-
const candidate =
|
|
8129
|
+
const candidate = path7.join(typeRoot, `${name}${ext}`);
|
|
7954
8130
|
if (fs2.existsSync(candidate))
|
|
7955
8131
|
return candidate;
|
|
7956
8132
|
}
|
|
7957
|
-
return
|
|
8133
|
+
return path7.join(typeRoot, `${name}.md`);
|
|
7958
8134
|
}
|
|
7959
8135
|
};
|
|
7960
8136
|
markdownSpec = {
|
|
7961
|
-
isRelevantFile: (fileName) =>
|
|
8137
|
+
isRelevantFile: (fileName) => path7.extname(fileName).toLowerCase() === ".md",
|
|
7962
8138
|
toCanonicalName: (typeRoot, filePath) => {
|
|
7963
|
-
const rel = toPosix(
|
|
8139
|
+
const rel = toPosix(path7.relative(typeRoot, filePath));
|
|
7964
8140
|
return rel.endsWith(".md") ? rel.slice(0, -3) : rel;
|
|
7965
8141
|
},
|
|
7966
8142
|
toAssetPath: (typeRoot, name) => {
|
|
7967
8143
|
const withExt = name.endsWith(".md") ? name : `${name}.md`;
|
|
7968
|
-
return
|
|
8144
|
+
return path7.join(typeRoot, withExt);
|
|
7969
8145
|
}
|
|
7970
8146
|
};
|
|
7971
8147
|
scriptSpec = {
|
|
7972
|
-
isRelevantFile: (fileName) => SCRIPT_EXTENSIONS.has(
|
|
7973
|
-
toCanonicalName: (typeRoot, filePath) => toPosix(
|
|
7974
|
-
toAssetPath: (typeRoot, name) =>
|
|
8148
|
+
isRelevantFile: (fileName) => SCRIPT_EXTENSIONS.has(path7.extname(fileName).toLowerCase()),
|
|
8149
|
+
toCanonicalName: (typeRoot, filePath) => toPosix(path7.relative(typeRoot, filePath)),
|
|
8150
|
+
toAssetPath: (typeRoot, name) => path7.join(typeRoot, name)
|
|
7975
8151
|
};
|
|
7976
8152
|
BUILTIN_PLACEMENT_SPECS = {
|
|
7977
8153
|
skill: {
|
|
7978
8154
|
stashDir: "skills",
|
|
7979
8155
|
isRelevantFile: (fileName) => fileName === "SKILL.md",
|
|
7980
8156
|
toCanonicalName: (typeRoot, filePath) => {
|
|
7981
|
-
const relDir = toPosix(
|
|
8157
|
+
const relDir = toPosix(path7.dirname(path7.relative(typeRoot, filePath)));
|
|
7982
8158
|
if (!relDir || relDir === ".")
|
|
7983
8159
|
return;
|
|
7984
8160
|
return relDir;
|
|
7985
8161
|
},
|
|
7986
|
-
toAssetPath: (typeRoot, name) =>
|
|
8162
|
+
toAssetPath: (typeRoot, name) => path7.join(typeRoot, name, "SKILL.md")
|
|
7987
8163
|
},
|
|
7988
8164
|
command: { stashDir: "commands", ...markdownSpec },
|
|
7989
8165
|
agent: { stashDir: "agents", ...markdownSpec },
|
|
@@ -7996,10 +8172,10 @@ var init_asset_placement = __esm(() => {
|
|
|
7996
8172
|
stashDir: "env",
|
|
7997
8173
|
isRelevantFile: (fileName) => fileName === ".env" || fileName.endsWith(".env"),
|
|
7998
8174
|
toCanonicalName: (typeRoot, filePath) => {
|
|
7999
|
-
const rel = toPosix(
|
|
8000
|
-
const fileName =
|
|
8175
|
+
const rel = toPosix(path7.relative(typeRoot, filePath));
|
|
8176
|
+
const fileName = path7.basename(rel);
|
|
8001
8177
|
if (fileName === ".env") {
|
|
8002
|
-
const dir =
|
|
8178
|
+
const dir = path7.dirname(rel);
|
|
8003
8179
|
return dir === "." || dir === "" ? "default" : `${dir}/default`;
|
|
8004
8180
|
}
|
|
8005
8181
|
const stripped = rel.endsWith(".env") ? rel.slice(0, -4) : rel;
|
|
@@ -8007,27 +8183,27 @@ var init_asset_placement = __esm(() => {
|
|
|
8007
8183
|
},
|
|
8008
8184
|
toAssetPath: (typeRoot, name) => {
|
|
8009
8185
|
if (name === "default")
|
|
8010
|
-
return
|
|
8011
|
-
return
|
|
8186
|
+
return path7.join(typeRoot, ".env");
|
|
8187
|
+
return path7.join(typeRoot, name.endsWith(".env") ? name : `${name}.env`);
|
|
8012
8188
|
}
|
|
8013
8189
|
},
|
|
8014
8190
|
secret: {
|
|
8015
8191
|
stashDir: "secrets",
|
|
8016
8192
|
isRelevantFile: (fileName) => !fileName.endsWith(".lock") && !fileName.endsWith(".sensitive"),
|
|
8017
|
-
toCanonicalName: (typeRoot, filePath) => toPosix(
|
|
8018
|
-
toAssetPath: (typeRoot, name) =>
|
|
8193
|
+
toCanonicalName: (typeRoot, filePath) => toPosix(path7.relative(typeRoot, filePath)),
|
|
8194
|
+
toAssetPath: (typeRoot, name) => path7.join(typeRoot, name)
|
|
8019
8195
|
},
|
|
8020
8196
|
lesson: { stashDir: "lessons", ...markdownSpec },
|
|
8021
8197
|
task: {
|
|
8022
8198
|
stashDir: "tasks",
|
|
8023
|
-
isRelevantFile: (fileName) =>
|
|
8199
|
+
isRelevantFile: (fileName) => path7.extname(fileName).toLowerCase() === ".yml",
|
|
8024
8200
|
toCanonicalName: (typeRoot, filePath) => {
|
|
8025
|
-
const rel = toPosix(
|
|
8201
|
+
const rel = toPosix(path7.relative(typeRoot, filePath));
|
|
8026
8202
|
return rel.toLowerCase().endsWith(".yml") ? rel.slice(0, -4) : rel;
|
|
8027
8203
|
},
|
|
8028
8204
|
toAssetPath: (typeRoot, name) => {
|
|
8029
8205
|
const withExt = name.toLowerCase().endsWith(".yml") ? name : `${name}.yml`;
|
|
8030
|
-
return
|
|
8206
|
+
return path7.join(typeRoot, withExt);
|
|
8031
8207
|
}
|
|
8032
8208
|
},
|
|
8033
8209
|
session: { stashDir: "sessions", ...markdownSpec },
|
|
@@ -8036,93 +8212,6 @@ var init_asset_placement = __esm(() => {
|
|
|
8036
8212
|
PLACEMENT_SPECS = { ...BUILTIN_PLACEMENT_SPECS };
|
|
8037
8213
|
});
|
|
8038
8214
|
|
|
8039
|
-
// src/core/asset/asset-ref.ts
|
|
8040
|
-
import path6 from "node:path";
|
|
8041
|
-
function validateName(name) {
|
|
8042
|
-
if (!name)
|
|
8043
|
-
throw new UsageError("Empty asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
8044
|
-
if (name.includes("\x00"))
|
|
8045
|
-
throw new UsageError("Null byte in asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
8046
|
-
if (/^[A-Za-z]:/.test(name))
|
|
8047
|
-
throw new UsageError("Windows drive path in asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
8048
|
-
const slashName = name.replace(/\\/g, "/");
|
|
8049
|
-
if (slashName === ".." || slashName.startsWith("../")) {
|
|
8050
|
-
throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
8051
|
-
}
|
|
8052
|
-
if (slashName.split("/").some((seg) => seg === "." || seg === "..")) {
|
|
8053
|
-
throw new UsageError("Asset name cannot contain relative path segments.", "MISSING_REQUIRED_ARGUMENT");
|
|
8054
|
-
}
|
|
8055
|
-
const normalized = path6.posix.normalize(slashName);
|
|
8056
|
-
if (path6.posix.isAbsolute(normalized))
|
|
8057
|
-
throw new UsageError("Absolute path in asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
8058
|
-
if (normalized === ".." || normalized.startsWith("../")) {
|
|
8059
|
-
throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
|
|
8060
|
-
}
|
|
8061
|
-
}
|
|
8062
|
-
function normalizeName(name) {
|
|
8063
|
-
return path6.posix.normalize(name.replace(/\\/g, "/"));
|
|
8064
|
-
}
|
|
8065
|
-
function isBundleSlug(s) {
|
|
8066
|
-
return BUNDLE_SLUG_RE.test(s);
|
|
8067
|
-
}
|
|
8068
|
-
function normalizeConceptId(raw) {
|
|
8069
|
-
const nfc = raw.normalize("NFC");
|
|
8070
|
-
if (nfc.includes("#")) {
|
|
8071
|
-
throw new UsageError("`#` is reserved for the export fragment in a concept id.", "MISSING_REQUIRED_ARGUMENT");
|
|
8072
|
-
}
|
|
8073
|
-
validateName(nfc);
|
|
8074
|
-
return normalizeName(nfc);
|
|
8075
|
-
}
|
|
8076
|
-
function makeBundleRef(bundle, conceptId, fragment) {
|
|
8077
|
-
const normalized = normalizeConceptId(conceptId);
|
|
8078
|
-
let out = normalized;
|
|
8079
|
-
if (bundle) {
|
|
8080
|
-
if (!BUNDLE_SLUG_RE.test(bundle)) {
|
|
8081
|
-
throw new UsageError(`Invalid bundle slug "${bundle}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
|
|
8082
|
-
}
|
|
8083
|
-
out = `${bundle}//${normalized}`;
|
|
8084
|
-
}
|
|
8085
|
-
if (fragment)
|
|
8086
|
-
out = `${out}#${fragment}`;
|
|
8087
|
-
return out;
|
|
8088
|
-
}
|
|
8089
|
-
function bundleRefToString(ref) {
|
|
8090
|
-
return makeBundleRef(ref.bundle, ref.conceptId, ref.fragment);
|
|
8091
|
-
}
|
|
8092
|
-
function parseBundleRef(ref) {
|
|
8093
|
-
const trimmed = ref.trim();
|
|
8094
|
-
if (!trimmed)
|
|
8095
|
-
throw new UsageError("Empty ref.", "MISSING_REQUIRED_ARGUMENT");
|
|
8096
|
-
let bundle;
|
|
8097
|
-
let body = trimmed;
|
|
8098
|
-
const boundary = trimmed.indexOf("//");
|
|
8099
|
-
if (boundary >= 0) {
|
|
8100
|
-
bundle = trimmed.slice(0, boundary);
|
|
8101
|
-
body = trimmed.slice(boundary + 2);
|
|
8102
|
-
if (!bundle)
|
|
8103
|
-
throw new UsageError("Empty bundle in ref.", "MISSING_REQUIRED_ARGUMENT");
|
|
8104
|
-
if (!BUNDLE_SLUG_RE.test(bundle)) {
|
|
8105
|
-
throw new UsageError(`Invalid bundle slug "${bundle}" in ref "${trimmed}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
|
|
8106
|
-
}
|
|
8107
|
-
}
|
|
8108
|
-
let fragment;
|
|
8109
|
-
const hash = body.indexOf("#");
|
|
8110
|
-
if (hash >= 0) {
|
|
8111
|
-
fragment = body.slice(hash + 1) || undefined;
|
|
8112
|
-
body = body.slice(0, hash);
|
|
8113
|
-
}
|
|
8114
|
-
if (!body) {
|
|
8115
|
-
throw new UsageError(`Invalid ref "${trimmed}". Expected [bundle//]conceptId, e.g. knowledge/guide or core//skills/review`, "MISSING_REQUIRED_ARGUMENT");
|
|
8116
|
-
}
|
|
8117
|
-
const conceptId = normalizeConceptId(body);
|
|
8118
|
-
return { bundle: bundle || undefined, conceptId, fragment };
|
|
8119
|
-
}
|
|
8120
|
-
var BUNDLE_SLUG_RE;
|
|
8121
|
-
var init_asset_ref = __esm(() => {
|
|
8122
|
-
init_errors();
|
|
8123
|
-
BUNDLE_SLUG_RE = /^[^\s:.#/]+$/;
|
|
8124
|
-
});
|
|
8125
|
-
|
|
8126
8215
|
// src/core/asset/resolve-ref.ts
|
|
8127
8216
|
function conceptIdFromTypeName(type, name) {
|
|
8128
8217
|
const stashDir = stashDirFor(type);
|
|
@@ -8186,13 +8275,13 @@ function validateExtraParams(value) {
|
|
|
8186
8275
|
}
|
|
8187
8276
|
const issues = [];
|
|
8188
8277
|
const seen = new WeakSet;
|
|
8189
|
-
const visit2 = (entry,
|
|
8278
|
+
const visit2 = (entry, path8) => {
|
|
8190
8279
|
if (Array.isArray(entry)) {
|
|
8191
8280
|
if (seen.has(entry))
|
|
8192
8281
|
return;
|
|
8193
8282
|
seen.add(entry);
|
|
8194
8283
|
entry.forEach((child, index) => {
|
|
8195
|
-
visit2(child, [...
|
|
8284
|
+
visit2(child, [...path8, index]);
|
|
8196
8285
|
});
|
|
8197
8286
|
return;
|
|
8198
8287
|
}
|
|
@@ -8203,7 +8292,7 @@ function validateExtraParams(value) {
|
|
|
8203
8292
|
seen.add(entry);
|
|
8204
8293
|
for (const [key, child] of Object.entries(entry)) {
|
|
8205
8294
|
const normalized = normalizeExtraParamKey(key);
|
|
8206
|
-
if (
|
|
8295
|
+
if (path8.length === 0 && PROTECTED_TOP_LEVEL_KEYS.has(normalized)) {
|
|
8207
8296
|
const remedy = protectedKeyRemedy(normalized);
|
|
8208
8297
|
issues.push({
|
|
8209
8298
|
path: [key],
|
|
@@ -8211,9 +8300,9 @@ function validateExtraParams(value) {
|
|
|
8211
8300
|
});
|
|
8212
8301
|
}
|
|
8213
8302
|
if (CREDENTIAL_KEYS.has(normalized)) {
|
|
8214
|
-
issues.push({ path: [...
|
|
8303
|
+
issues.push({ path: [...path8, key], message: `${key} cannot carry credentials` });
|
|
8215
8304
|
}
|
|
8216
|
-
visit2(child, [...
|
|
8305
|
+
visit2(child, [...path8, key]);
|
|
8217
8306
|
}
|
|
8218
8307
|
};
|
|
8219
8308
|
visit2(value, []);
|
|
@@ -8406,13 +8495,13 @@ var init_warn = __esm(() => {
|
|
|
8406
8495
|
});
|
|
8407
8496
|
|
|
8408
8497
|
// src/core/write-provenance.ts
|
|
8409
|
-
import
|
|
8498
|
+
import path16 from "node:path";
|
|
8410
8499
|
function recordWrittenPath(filePath) {
|
|
8411
8500
|
if (activeJournals.size === 0 || !filePath)
|
|
8412
8501
|
return;
|
|
8413
8502
|
let absolute;
|
|
8414
8503
|
try {
|
|
8415
|
-
absolute =
|
|
8504
|
+
absolute = path16.resolve(filePath);
|
|
8416
8505
|
} catch {
|
|
8417
8506
|
return;
|
|
8418
8507
|
}
|
|
@@ -8520,7 +8609,7 @@ var init_frontmatter = __esm(() => {
|
|
|
8520
8609
|
|
|
8521
8610
|
// src/indexer/passes/metadata.ts
|
|
8522
8611
|
import fs13 from "node:fs";
|
|
8523
|
-
import
|
|
8612
|
+
import path18 from "node:path";
|
|
8524
8613
|
function normalizeQuality(raw) {
|
|
8525
8614
|
if (KNOWN_QUALITY_VALUES.has(raw))
|
|
8526
8615
|
return raw;
|
|
@@ -9280,7 +9369,7 @@ function projectMarkdownContent(body, truncationInfo) {
|
|
|
9280
9369
|
return truncateUnicodeSafe(text, MARKDOWN_CONTENT_MAX_CHARS);
|
|
9281
9370
|
}
|
|
9282
9371
|
function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
9283
|
-
const ext =
|
|
9372
|
+
const ext = path18.extname(file).toLowerCase();
|
|
9284
9373
|
if (pkgMeta) {
|
|
9285
9374
|
if (pkgMeta.description && !entry.description) {
|
|
9286
9375
|
entry.description = pkgMeta.description;
|
|
@@ -9326,8 +9415,8 @@ function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
|
9326
9415
|
}
|
|
9327
9416
|
}
|
|
9328
9417
|
function applyPostContributorFields(entry, file, canonicalName, dirPath) {
|
|
9329
|
-
const ext =
|
|
9330
|
-
const baseName =
|
|
9418
|
+
const ext = path18.extname(file).toLowerCase();
|
|
9419
|
+
const baseName = path18.basename(file, ext);
|
|
9331
9420
|
if (!entry.description) {
|
|
9332
9421
|
entry.description = fileNameToDescription(baseName);
|
|
9333
9422
|
entry.source = "filename";
|
|
@@ -9339,7 +9428,7 @@ function applyPostContributorFields(entry, file, canonicalName, dirPath) {
|
|
|
9339
9428
|
entry.tags = [...entry.tags ?? [], ...extractDirTagsFromName(canonicalName)];
|
|
9340
9429
|
entry.tags = normalizeTerms(entry.tags ?? []);
|
|
9341
9430
|
entry.aliases = mergeAliases(entry.aliases, buildAliases(canonicalName, entry.tags));
|
|
9342
|
-
entry.filename =
|
|
9431
|
+
entry.filename = path18.basename(file);
|
|
9343
9432
|
}
|
|
9344
9433
|
function buildMetadataSkipWarning(filePath, assetType, error) {
|
|
9345
9434
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -9371,7 +9460,7 @@ function buildAliases(name, tags) {
|
|
|
9371
9460
|
return Array.from(aliases);
|
|
9372
9461
|
}
|
|
9373
9462
|
function extractPackageMetadata(dirPath) {
|
|
9374
|
-
const pkgPath =
|
|
9463
|
+
const pkgPath = path18.join(dirPath, "package.json");
|
|
9375
9464
|
if (!fs13.existsSync(pkgPath))
|
|
9376
9465
|
return null;
|
|
9377
9466
|
try {
|
|
@@ -9393,11 +9482,11 @@ function fileNameToDescription(fileName) {
|
|
|
9393
9482
|
return fileName.replace(/[-_]+/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().trim();
|
|
9394
9483
|
}
|
|
9395
9484
|
function extractTagsFromPath(filePath, rootDir) {
|
|
9396
|
-
const rel =
|
|
9397
|
-
const parts = rel.split(
|
|
9485
|
+
const rel = path18.relative(rootDir, filePath);
|
|
9486
|
+
const parts = rel.split(path18.sep);
|
|
9398
9487
|
const tags = new Set;
|
|
9399
9488
|
for (const part of parts) {
|
|
9400
|
-
const name = part.replace(
|
|
9489
|
+
const name = part.replace(path18.extname(part), "");
|
|
9401
9490
|
for (const token of name.split(/[-_./\\]+/)) {
|
|
9402
9491
|
const clean = token.toLowerCase().trim();
|
|
9403
9492
|
if (clean && clean.length > 1)
|
|
@@ -9429,27 +9518,27 @@ var init_metadata = __esm(() => {
|
|
|
9429
9518
|
});
|
|
9430
9519
|
|
|
9431
9520
|
// src/execution/record.ts
|
|
9432
|
-
function snapshotStrictRecord(value,
|
|
9521
|
+
function snapshotStrictRecord(value, path19, options = {}) {
|
|
9433
9522
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
9434
|
-
throw new TypeError(`${
|
|
9523
|
+
throw new TypeError(`${path19} must be an object`);
|
|
9435
9524
|
}
|
|
9436
9525
|
const prototype = Object.getPrototypeOf(value);
|
|
9437
9526
|
if (prototype !== Object.prototype && prototype !== null) {
|
|
9438
|
-
throw new TypeError(`${
|
|
9527
|
+
throw new TypeError(`${path19} must use a plain or null prototype`);
|
|
9439
9528
|
}
|
|
9440
9529
|
const out = Object.create(null);
|
|
9441
9530
|
for (const key of Reflect.ownKeys(value)) {
|
|
9442
9531
|
const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
|
|
9443
9532
|
if (!descriptor)
|
|
9444
|
-
throw new TypeError(`${
|
|
9533
|
+
throw new TypeError(`${path19}.${String(key)} must have a stable own descriptor`);
|
|
9445
9534
|
if (typeof key === "symbol" && !options.allowedSymbols?.has(key)) {
|
|
9446
|
-
throw new TypeError(`${
|
|
9535
|
+
throw new TypeError(`${path19} contains unsupported symbol field: ${String(key)}`);
|
|
9447
9536
|
}
|
|
9448
9537
|
if (!("value" in descriptor)) {
|
|
9449
|
-
throw new TypeError(`${
|
|
9538
|
+
throw new TypeError(`${path19}.${String(key)} must be an enumerable data property, not an accessor`);
|
|
9450
9539
|
}
|
|
9451
9540
|
if (typeof key === "string" && !descriptor.enumerable) {
|
|
9452
|
-
throw new TypeError(`${
|
|
9541
|
+
throw new TypeError(`${path19}.${key} must be an enumerable data property, not a non-enumerable field`);
|
|
9453
9542
|
}
|
|
9454
9543
|
Object.defineProperty(out, key, {
|
|
9455
9544
|
value: descriptor.value,
|
|
@@ -9460,14 +9549,14 @@ function snapshotStrictRecord(value, path18, options = {}) {
|
|
|
9460
9549
|
}
|
|
9461
9550
|
return Object.freeze(out);
|
|
9462
9551
|
}
|
|
9463
|
-
function assertSnapshotKeys(value, allowed,
|
|
9552
|
+
function assertSnapshotKeys(value, allowed, path19, allowedSymbols = new Set) {
|
|
9464
9553
|
const allowedKeys = new Set(allowed);
|
|
9465
9554
|
for (const key of Reflect.ownKeys(value)) {
|
|
9466
9555
|
if (typeof key === "symbol") {
|
|
9467
9556
|
if (!allowedSymbols.has(key))
|
|
9468
|
-
throw new TypeError(`${
|
|
9557
|
+
throw new TypeError(`${path19} contains unsupported field: ${String(key)}`);
|
|
9469
9558
|
} else if (!allowedKeys.has(key)) {
|
|
9470
|
-
throw new TypeError(`${
|
|
9559
|
+
throw new TypeError(`${path19} contains unsupported field: ${key}`);
|
|
9471
9560
|
}
|
|
9472
9561
|
}
|
|
9473
9562
|
}
|
|
@@ -9475,9 +9564,9 @@ function assertSnapshotKeys(value, allowed, path18, allowedSymbols = new Set) {
|
|
|
9475
9564
|
// node_modules/dotenv/lib/main.js
|
|
9476
9565
|
var require_main = __commonJS((exports, module) => {
|
|
9477
9566
|
var fs14 = __require("fs");
|
|
9478
|
-
var
|
|
9567
|
+
var path19 = __require("path");
|
|
9479
9568
|
var os2 = __require("os");
|
|
9480
|
-
var
|
|
9569
|
+
var crypto4 = __require("crypto");
|
|
9481
9570
|
var TIPS = [
|
|
9482
9571
|
"◈ encrypted .env [www.dotenvx.com]",
|
|
9483
9572
|
"◈ secrets for agents [www.dotenvx.com]",
|
|
@@ -9616,7 +9705,7 @@ var require_main = __commonJS((exports, module) => {
|
|
|
9616
9705
|
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
|
|
9617
9706
|
}
|
|
9618
9707
|
} else {
|
|
9619
|
-
possibleVaultPath =
|
|
9708
|
+
possibleVaultPath = path19.resolve(process.cwd(), ".env.vault");
|
|
9620
9709
|
}
|
|
9621
9710
|
if (fs14.existsSync(possibleVaultPath)) {
|
|
9622
9711
|
return possibleVaultPath;
|
|
@@ -9624,7 +9713,7 @@ var require_main = __commonJS((exports, module) => {
|
|
|
9624
9713
|
return null;
|
|
9625
9714
|
}
|
|
9626
9715
|
function _resolveHome(envPath) {
|
|
9627
|
-
return envPath[0] === "~" ?
|
|
9716
|
+
return envPath[0] === "~" ? path19.join(os2.homedir(), envPath.slice(1)) : envPath;
|
|
9628
9717
|
}
|
|
9629
9718
|
function _configVault(options) {
|
|
9630
9719
|
const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
@@ -9641,7 +9730,7 @@ var require_main = __commonJS((exports, module) => {
|
|
|
9641
9730
|
return { parsed };
|
|
9642
9731
|
}
|
|
9643
9732
|
function configDotenv(options) {
|
|
9644
|
-
const dotenvPath =
|
|
9733
|
+
const dotenvPath = path19.resolve(process.cwd(), ".env");
|
|
9645
9734
|
let encoding = "utf8";
|
|
9646
9735
|
let processEnv = process.env;
|
|
9647
9736
|
if (options && options.processEnv != null) {
|
|
@@ -9669,13 +9758,13 @@ var require_main = __commonJS((exports, module) => {
|
|
|
9669
9758
|
}
|
|
9670
9759
|
let lastError;
|
|
9671
9760
|
const parsedAll = {};
|
|
9672
|
-
for (const
|
|
9761
|
+
for (const path20 of optionPaths) {
|
|
9673
9762
|
try {
|
|
9674
|
-
const parsed = DotenvModule.parse(fs14.readFileSync(
|
|
9763
|
+
const parsed = DotenvModule.parse(fs14.readFileSync(path20, { encoding }));
|
|
9675
9764
|
DotenvModule.populate(parsedAll, parsed, options);
|
|
9676
9765
|
} catch (e) {
|
|
9677
9766
|
if (debug) {
|
|
9678
|
-
_debug(`failed to load ${
|
|
9767
|
+
_debug(`failed to load ${path20} ${e.message}`);
|
|
9679
9768
|
}
|
|
9680
9769
|
lastError = e;
|
|
9681
9770
|
}
|
|
@@ -9688,7 +9777,7 @@ var require_main = __commonJS((exports, module) => {
|
|
|
9688
9777
|
const shortPaths = [];
|
|
9689
9778
|
for (const filePath of optionPaths) {
|
|
9690
9779
|
try {
|
|
9691
|
-
const relative =
|
|
9780
|
+
const relative = path19.relative(process.cwd(), filePath);
|
|
9692
9781
|
shortPaths.push(relative);
|
|
9693
9782
|
} catch (e) {
|
|
9694
9783
|
if (debug) {
|
|
@@ -9723,7 +9812,7 @@ var require_main = __commonJS((exports, module) => {
|
|
|
9723
9812
|
const authTag = ciphertext.subarray(-16);
|
|
9724
9813
|
ciphertext = ciphertext.subarray(12, -16);
|
|
9725
9814
|
try {
|
|
9726
|
-
const aesgcm =
|
|
9815
|
+
const aesgcm = crypto4.createDecipheriv("aes-256-gcm", key, nonce);
|
|
9727
9816
|
aesgcm.setAuthTag(authTag);
|
|
9728
9817
|
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
|
|
9729
9818
|
} catch (error) {
|
|
@@ -9827,7 +9916,7 @@ var init_time = __esm(() => {
|
|
|
9827
9916
|
|
|
9828
9917
|
// src/tasks/source/bounded-document.ts
|
|
9829
9918
|
import fs14 from "node:fs";
|
|
9830
|
-
import
|
|
9919
|
+
import path19 from "node:path";
|
|
9831
9920
|
import { types as utilTypes } from "node:util";
|
|
9832
9921
|
function own2(value, key) {
|
|
9833
9922
|
return Object.hasOwn(value, key);
|
|
@@ -9998,7 +10087,7 @@ function parseTools(value, ctx) {
|
|
|
9998
10087
|
sourceError(ctx, ["akm", "tools"], "must be a string, string array, mapping, or null.");
|
|
9999
10088
|
}
|
|
10000
10089
|
function validateWorkingDirectory(value, ctx) {
|
|
10001
|
-
if (value.trim().length === 0 || value.includes("\x00") ||
|
|
10090
|
+
if (value.trim().length === 0 || value.includes("\x00") || path19.posix.isAbsolute(value.replaceAll("\\", "/")) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\")) {
|
|
10002
10091
|
sourceError(ctx, ["working-directory"], "must be a non-empty relative path contained by the workspace root.");
|
|
10003
10092
|
}
|
|
10004
10093
|
const segments = value.replaceAll("\\", "/").split("/");
|
|
@@ -10012,7 +10101,7 @@ function validateWorkingDirectory(value, ctx) {
|
|
|
10012
10101
|
let realCandidate;
|
|
10013
10102
|
try {
|
|
10014
10103
|
realRoot = fs14.realpathSync(ctx.workspaceRoot);
|
|
10015
|
-
const candidate =
|
|
10104
|
+
const candidate = path19.resolve(realRoot, value);
|
|
10016
10105
|
const stat = fs14.statSync(candidate);
|
|
10017
10106
|
if (!stat.isDirectory())
|
|
10018
10107
|
sourceError(ctx, ["working-directory"], "must resolve to a directory.");
|
|
@@ -10022,8 +10111,8 @@ function validateWorkingDirectory(value, ctx) {
|
|
|
10022
10111
|
throw cause;
|
|
10023
10112
|
sourceError(ctx, ["working-directory"], `cannot be physically verified: ${cause instanceof Error ? cause.message : String(cause)}.`);
|
|
10024
10113
|
}
|
|
10025
|
-
const relative =
|
|
10026
|
-
if (relative.startsWith("..") ||
|
|
10114
|
+
const relative = path19.relative(realRoot, realCandidate);
|
|
10115
|
+
if (relative.startsWith("..") || path19.isAbsolute(relative)) {
|
|
10027
10116
|
sourceError(ctx, ["working-directory"], "resolves outside the workspace root and is not physically contained.");
|
|
10028
10117
|
}
|
|
10029
10118
|
}
|
|
@@ -10192,34 +10281,34 @@ function checkJsonSchemaDefinition(schema) {
|
|
|
10192
10281
|
checkDefinitionNode(schema, [], issues, 0);
|
|
10193
10282
|
return issues;
|
|
10194
10283
|
}
|
|
10195
|
-
function pointerFor(
|
|
10196
|
-
return
|
|
10284
|
+
function pointerFor(path20) {
|
|
10285
|
+
return path20.length === 0 ? "$" : `$.${path20.map(String).join(".")}`;
|
|
10197
10286
|
}
|
|
10198
|
-
function pushIssue(issues,
|
|
10199
|
-
issues.push({ path: [...
|
|
10287
|
+
function pushIssue(issues, path20, keyword, kind, message) {
|
|
10288
|
+
issues.push({ path: [...path20], pointer: pointerFor(path20), keyword, kind, message });
|
|
10200
10289
|
}
|
|
10201
10290
|
function isSupportedEnumValue(value) {
|
|
10202
10291
|
return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
|
|
10203
10292
|
}
|
|
10204
|
-
function checkDefinitionNode(schema,
|
|
10293
|
+
function checkDefinitionNode(schema, path20, issues, depth) {
|
|
10205
10294
|
if (depth > MAX_DEFINITION_DEPTH) {
|
|
10206
|
-
pushIssue(issues,
|
|
10295
|
+
pushIssue(issues, path20, "(depth)", "malformed", `schema nesting exceeds the depth limit of ${MAX_DEFINITION_DEPTH}`);
|
|
10207
10296
|
return;
|
|
10208
10297
|
}
|
|
10209
10298
|
for (const keyword of Object.keys(schema)) {
|
|
10210
10299
|
if (UNSUPPORTED_KEYWORDS.has(keyword)) {
|
|
10211
10300
|
const hint = UNSUPPORTED_KEYWORD_HINTS.get(keyword);
|
|
10212
|
-
pushIssue(issues, [...
|
|
10301
|
+
pushIssue(issues, [...path20, keyword], keyword, "unsupported", `keyword "${keyword}" is not enforced by the workflow schema subset — the schema would silently not ` + `constrain what it looks like it constrains${hint ? `; ${hint}` : ""}`);
|
|
10213
10302
|
}
|
|
10214
10303
|
}
|
|
10215
10304
|
const declared = schema.type;
|
|
10216
10305
|
if (declared !== undefined) {
|
|
10217
10306
|
const names = Array.isArray(declared) ? declared : [declared];
|
|
10218
10307
|
if (names.length === 0) {
|
|
10219
|
-
pushIssue(issues, [...
|
|
10308
|
+
pushIssue(issues, [...path20, "type"], "type", "malformed", `"type" must name at least one type`);
|
|
10220
10309
|
}
|
|
10221
10310
|
for (const [index, name] of names.entries()) {
|
|
10222
|
-
const namePath = Array.isArray(declared) ? [...
|
|
10311
|
+
const namePath = Array.isArray(declared) ? [...path20, "type", index] : [...path20, "type"];
|
|
10223
10312
|
if (typeof name !== "string") {
|
|
10224
10313
|
pushIssue(issues, namePath, "type", "malformed", `"type" must be a string or an array of strings`);
|
|
10225
10314
|
} else if (!KNOWN_TYPE_NAMES.has(name)) {
|
|
@@ -10229,12 +10318,12 @@ function checkDefinitionNode(schema, path19, issues, depth) {
|
|
|
10229
10318
|
}
|
|
10230
10319
|
if (schema.enum !== undefined) {
|
|
10231
10320
|
if (!Array.isArray(schema.enum) || schema.enum.length === 0) {
|
|
10232
|
-
pushIssue(issues, [...
|
|
10321
|
+
pushIssue(issues, [...path20, "enum"], "enum", "malformed", `"enum" must be a non-empty array of allowed values`);
|
|
10233
10322
|
} else {
|
|
10234
10323
|
schema.enum.forEach((value, index) => {
|
|
10235
10324
|
if (isSupportedEnumValue(value))
|
|
10236
10325
|
return;
|
|
10237
|
-
pushIssue(issues, [...
|
|
10326
|
+
pushIssue(issues, [...path20, "enum", index], "enum", "unsupported", `"enum" values must be JSON primitives (string, finite number, boolean, or null) in the workflow ` + `schema subset — object and array enum members cannot be matched by the runtime subset`);
|
|
10238
10327
|
});
|
|
10239
10328
|
}
|
|
10240
10329
|
}
|
|
@@ -10243,68 +10332,68 @@ function checkDefinitionNode(schema, path19, issues, depth) {
|
|
|
10243
10332
|
if (branches === undefined)
|
|
10244
10333
|
continue;
|
|
10245
10334
|
if (!Array.isArray(branches) || branches.length === 0) {
|
|
10246
|
-
pushIssue(issues, [...
|
|
10335
|
+
pushIssue(issues, [...path20, keyword], keyword, "malformed", `"${keyword}" must be a non-empty array of schema objects`);
|
|
10247
10336
|
continue;
|
|
10248
10337
|
}
|
|
10249
10338
|
branches.forEach((branch, index) => {
|
|
10250
10339
|
if (isRecord(branch)) {
|
|
10251
|
-
checkDefinitionNode(branch, [...
|
|
10340
|
+
checkDefinitionNode(branch, [...path20, keyword, index], issues, depth + 1);
|
|
10252
10341
|
} else {
|
|
10253
|
-
pushIssue(issues, [...
|
|
10342
|
+
pushIssue(issues, [...path20, keyword, index], keyword, "malformed", `"${keyword}[${index}]" must be a schema object`);
|
|
10254
10343
|
}
|
|
10255
10344
|
});
|
|
10256
10345
|
}
|
|
10257
10346
|
if (schema.not !== undefined) {
|
|
10258
10347
|
if (isRecord(schema.not)) {
|
|
10259
|
-
checkDefinitionNode(schema.not, [...
|
|
10348
|
+
checkDefinitionNode(schema.not, [...path20, "not"], issues, depth + 1);
|
|
10260
10349
|
} else {
|
|
10261
|
-
pushIssue(issues, [...
|
|
10350
|
+
pushIssue(issues, [...path20, "not"], "not", "malformed", `"not" must be a schema object`);
|
|
10262
10351
|
}
|
|
10263
10352
|
}
|
|
10264
10353
|
if (schema.required !== undefined) {
|
|
10265
10354
|
if (!Array.isArray(schema.required) || !schema.required.every((key) => typeof key === "string")) {
|
|
10266
|
-
pushIssue(issues, [...
|
|
10355
|
+
pushIssue(issues, [...path20, "required"], "required", "malformed", `"required" must be an array of property-name strings`);
|
|
10267
10356
|
}
|
|
10268
10357
|
}
|
|
10269
10358
|
if (schema.properties !== undefined) {
|
|
10270
10359
|
if (!isRecord(schema.properties)) {
|
|
10271
|
-
pushIssue(issues, [...
|
|
10360
|
+
pushIssue(issues, [...path20, "properties"], "properties", "malformed", `"properties" must be an object mapping property names to schemas`);
|
|
10272
10361
|
} else {
|
|
10273
10362
|
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
10274
10363
|
if (isRecord(propSchema)) {
|
|
10275
|
-
checkDefinitionNode(propSchema, [...
|
|
10364
|
+
checkDefinitionNode(propSchema, [...path20, "properties", key], issues, depth + 1);
|
|
10276
10365
|
} else {
|
|
10277
|
-
pushIssue(issues, [...
|
|
10366
|
+
pushIssue(issues, [...path20, "properties", key], "properties", "malformed", `property ${JSON.stringify(key)} must be a schema object`);
|
|
10278
10367
|
}
|
|
10279
10368
|
}
|
|
10280
10369
|
}
|
|
10281
10370
|
}
|
|
10282
10371
|
if (schema.items !== undefined) {
|
|
10283
10372
|
if (isRecord(schema.items)) {
|
|
10284
|
-
checkDefinitionNode(schema.items, [...
|
|
10373
|
+
checkDefinitionNode(schema.items, [...path20, "items"], issues, depth + 1);
|
|
10285
10374
|
} else if (Array.isArray(schema.items)) {
|
|
10286
|
-
pushIssue(issues, [...
|
|
10375
|
+
pushIssue(issues, [...path20, "items"], "items", "unsupported", `tuple-form "items" (an array of schemas) is not enforced by the workflow schema subset — use a single schema object`);
|
|
10287
10376
|
} else {
|
|
10288
|
-
pushIssue(issues, [...
|
|
10377
|
+
pushIssue(issues, [...path20, "items"], "items", "malformed", `"items" must be a schema object`);
|
|
10289
10378
|
}
|
|
10290
10379
|
}
|
|
10291
10380
|
if (schema.additionalProperties !== undefined && typeof schema.additionalProperties !== "boolean") {
|
|
10292
10381
|
if (isRecord(schema.additionalProperties)) {
|
|
10293
|
-
pushIssue(issues, [...
|
|
10382
|
+
pushIssue(issues, [...path20, "additionalProperties"], "additionalProperties", "unsupported", `schema-form "additionalProperties" is not enforced by the workflow schema subset — only "additionalProperties: false" is`);
|
|
10294
10383
|
} else {
|
|
10295
|
-
pushIssue(issues, [...
|
|
10384
|
+
pushIssue(issues, [...path20, "additionalProperties"], "additionalProperties", "malformed", `"additionalProperties" must be a boolean (only "false" is enforced)`);
|
|
10296
10385
|
}
|
|
10297
10386
|
}
|
|
10298
10387
|
for (const keyword of ["minItems", "maxItems", "minLength", "maxLength"]) {
|
|
10299
10388
|
const value = schema[keyword];
|
|
10300
10389
|
if (value !== undefined && (typeof value !== "number" || !Number.isInteger(value) || value < 0)) {
|
|
10301
|
-
pushIssue(issues, [...
|
|
10390
|
+
pushIssue(issues, [...path20, keyword], keyword, "malformed", `"${keyword}" must be a non-negative integer`);
|
|
10302
10391
|
}
|
|
10303
10392
|
}
|
|
10304
10393
|
for (const keyword of ["minimum", "maximum"]) {
|
|
10305
10394
|
const value = schema[keyword];
|
|
10306
10395
|
if (value !== undefined && (typeof value !== "number" || !Number.isFinite(value))) {
|
|
10307
|
-
pushIssue(issues, [...
|
|
10396
|
+
pushIssue(issues, [...path20, keyword], keyword, "malformed", `"${keyword}" must be a finite number`);
|
|
10308
10397
|
}
|
|
10309
10398
|
}
|
|
10310
10399
|
}
|
|
@@ -10329,9 +10418,9 @@ function matchesType(actual, expected) {
|
|
|
10329
10418
|
return true;
|
|
10330
10419
|
return expected === "number" && actual === "integer";
|
|
10331
10420
|
}
|
|
10332
|
-
function branchErrors(value, schema,
|
|
10421
|
+
function branchErrors(value, schema, path20, ctx) {
|
|
10333
10422
|
const errors3 = [];
|
|
10334
|
-
validateNode(value, schema,
|
|
10423
|
+
validateNode(value, schema, path20, { ...ctx, errors: errors3, depth: ctx.depth + 1 });
|
|
10335
10424
|
return errors3;
|
|
10336
10425
|
}
|
|
10337
10426
|
function combinatorBranches(schema, keyword) {
|
|
@@ -10346,9 +10435,9 @@ function summarizeBranchFailures(failures) {
|
|
|
10346
10435
|
shown.push(`…${failures.length - shown.length} more`);
|
|
10347
10436
|
return shown.join("; ");
|
|
10348
10437
|
}
|
|
10349
|
-
function validateCombinators(value, schema,
|
|
10438
|
+
function validateCombinators(value, schema, path20, ctx) {
|
|
10350
10439
|
for (const branch of combinatorBranches(schema, "allOf")) {
|
|
10351
|
-
ctx.errors.push(...branchErrors(value, branch,
|
|
10440
|
+
ctx.errors.push(...branchErrors(value, branch, path20, ctx));
|
|
10352
10441
|
}
|
|
10353
10442
|
for (const keyword of ["anyOf", "oneOf"]) {
|
|
10354
10443
|
const branches = combinatorBranches(schema, keyword);
|
|
@@ -10357,27 +10446,27 @@ function validateCombinators(value, schema, path19, ctx) {
|
|
|
10357
10446
|
const failures = [];
|
|
10358
10447
|
const matched = [];
|
|
10359
10448
|
branches.forEach((branch, index) => {
|
|
10360
|
-
const errors3 = branchErrors(value, branch,
|
|
10449
|
+
const errors3 = branchErrors(value, branch, path20, ctx);
|
|
10361
10450
|
if (errors3.length === 0)
|
|
10362
10451
|
matched.push(index + 1);
|
|
10363
10452
|
else
|
|
10364
10453
|
failures.push({ index, errors: errors3 });
|
|
10365
10454
|
});
|
|
10366
10455
|
if (matched.length === 0) {
|
|
10367
|
-
ctx.errors.push(`${
|
|
10456
|
+
ctx.errors.push(`${path20}: value matches none of the ${branches.length} "${keyword}" schemas (${summarizeBranchFailures(failures)})`);
|
|
10368
10457
|
} else if (keyword === "oneOf" && matched.length > 1) {
|
|
10369
|
-
ctx.errors.push(`${
|
|
10458
|
+
ctx.errors.push(`${path20}: value matches ${matched.length} "oneOf" schemas (branches ${matched.join(", ")}); exactly one must match`);
|
|
10370
10459
|
}
|
|
10371
10460
|
}
|
|
10372
10461
|
const not = schema.not;
|
|
10373
|
-
if (isRecord(not) && branchErrors(value, not,
|
|
10374
|
-
ctx.errors.push(`${
|
|
10462
|
+
if (isRecord(not) && branchErrors(value, not, path20, ctx).length === 0) {
|
|
10463
|
+
ctx.errors.push(`${path20}: value must not match the "not" schema`);
|
|
10375
10464
|
}
|
|
10376
10465
|
}
|
|
10377
|
-
function validateNode(value, schema,
|
|
10466
|
+
function validateNode(value, schema, path20, ctx) {
|
|
10378
10467
|
const errors3 = ctx.errors;
|
|
10379
10468
|
if (ctx.depth > MAX_DEFINITION_DEPTH) {
|
|
10380
|
-
errors3.push(`${
|
|
10469
|
+
errors3.push(`${path20}: schema nesting exceeds the depth limit of ${MAX_DEFINITION_DEPTH}`);
|
|
10381
10470
|
return;
|
|
10382
10471
|
}
|
|
10383
10472
|
if (--ctx.budget.nodes < 0)
|
|
@@ -10387,47 +10476,47 @@ function validateNode(value, schema, path19, ctx) {
|
|
|
10387
10476
|
if (typeof declared === "string" || Array.isArray(declared)) {
|
|
10388
10477
|
const expected = (Array.isArray(declared) ? declared : [declared]).filter((t) => typeof t === "string");
|
|
10389
10478
|
if (expected.length > 0 && !expected.some((t) => matchesType(actual, t))) {
|
|
10390
|
-
errors3.push(`${
|
|
10479
|
+
errors3.push(`${path20}: expected type ${expected.join(" | ")}, got ${actual}`);
|
|
10391
10480
|
return;
|
|
10392
10481
|
}
|
|
10393
10482
|
}
|
|
10394
10483
|
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
|
|
10395
10484
|
const allowed = schema.enum;
|
|
10396
10485
|
if (!allowed.some((candidate) => candidate === value)) {
|
|
10397
|
-
errors3.push(ctx.redactValues ? `${
|
|
10486
|
+
errors3.push(ctx.redactValues ? `${path20}: value is not one of ${JSON.stringify(allowed)}` : `${path20}: value ${JSON.stringify(value)} is not one of ${JSON.stringify(allowed)}`);
|
|
10398
10487
|
return;
|
|
10399
10488
|
}
|
|
10400
10489
|
}
|
|
10401
|
-
validateCombinators(value, schema,
|
|
10490
|
+
validateCombinators(value, schema, path20, ctx);
|
|
10402
10491
|
if (actual === "string" && typeof value === "string") {
|
|
10403
10492
|
if (typeof schema.minLength === "number" && value.length < schema.minLength) {
|
|
10404
|
-
errors3.push(`${
|
|
10493
|
+
errors3.push(`${path20}: string shorter than minLength ${schema.minLength}`);
|
|
10405
10494
|
}
|
|
10406
10495
|
if (typeof schema.maxLength === "number" && value.length > schema.maxLength) {
|
|
10407
|
-
errors3.push(`${
|
|
10496
|
+
errors3.push(`${path20}: string longer than maxLength ${schema.maxLength}`);
|
|
10408
10497
|
}
|
|
10409
10498
|
return;
|
|
10410
10499
|
}
|
|
10411
10500
|
if ((actual === "number" || actual === "integer") && typeof value === "number") {
|
|
10412
10501
|
if (typeof schema.minimum === "number" && value < schema.minimum) {
|
|
10413
|
-
errors3.push(ctx.redactValues ? `${
|
|
10502
|
+
errors3.push(ctx.redactValues ? `${path20}: value is below minimum ${schema.minimum}` : `${path20}: ${value} is below minimum ${schema.minimum}`);
|
|
10414
10503
|
}
|
|
10415
10504
|
if (typeof schema.maximum === "number" && value > schema.maximum) {
|
|
10416
|
-
errors3.push(ctx.redactValues ? `${
|
|
10505
|
+
errors3.push(ctx.redactValues ? `${path20}: value is above maximum ${schema.maximum}` : `${path20}: ${value} is above maximum ${schema.maximum}`);
|
|
10417
10506
|
}
|
|
10418
10507
|
return;
|
|
10419
10508
|
}
|
|
10420
10509
|
if (actual === "array" && Array.isArray(value)) {
|
|
10421
10510
|
if (typeof schema.minItems === "number" && value.length < schema.minItems) {
|
|
10422
|
-
errors3.push(`${
|
|
10511
|
+
errors3.push(`${path20}: array has fewer than minItems ${schema.minItems}`);
|
|
10423
10512
|
}
|
|
10424
10513
|
if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
|
|
10425
|
-
errors3.push(`${
|
|
10514
|
+
errors3.push(`${path20}: array has more than maxItems ${schema.maxItems}`);
|
|
10426
10515
|
}
|
|
10427
10516
|
const items = schema.items;
|
|
10428
10517
|
if (items && typeof items === "object" && !Array.isArray(items)) {
|
|
10429
10518
|
value.forEach((element, index) => {
|
|
10430
|
-
validateNode(element, items, `${
|
|
10519
|
+
validateNode(element, items, `${path20}[${index}]`, {
|
|
10431
10520
|
...ctx,
|
|
10432
10521
|
depth: ctx.depth + 1
|
|
10433
10522
|
});
|
|
@@ -10441,7 +10530,7 @@ function validateNode(value, schema, path19, ctx) {
|
|
|
10441
10530
|
if (Array.isArray(schema.required)) {
|
|
10442
10531
|
for (const key of schema.required) {
|
|
10443
10532
|
if (typeof key === "string" && !Object.hasOwn(record, key)) {
|
|
10444
|
-
errors3.push(`${
|
|
10533
|
+
errors3.push(`${path20}: missing required property "${key}"`);
|
|
10445
10534
|
}
|
|
10446
10535
|
}
|
|
10447
10536
|
}
|
|
@@ -10450,7 +10539,7 @@ function validateNode(value, schema, path19, ctx) {
|
|
|
10450
10539
|
if (!Object.hasOwn(record, key))
|
|
10451
10540
|
continue;
|
|
10452
10541
|
if (propSchema && typeof propSchema === "object" && !Array.isArray(propSchema)) {
|
|
10453
|
-
validateNode(record[key], propSchema, `${
|
|
10542
|
+
validateNode(record[key], propSchema, `${path20}.${key}`, {
|
|
10454
10543
|
...ctx,
|
|
10455
10544
|
depth: ctx.depth + 1
|
|
10456
10545
|
});
|
|
@@ -10460,7 +10549,7 @@ function validateNode(value, schema, path19, ctx) {
|
|
|
10460
10549
|
if (schema.additionalProperties === false) {
|
|
10461
10550
|
for (const key of Object.keys(record)) {
|
|
10462
10551
|
if (!properties || !Object.hasOwn(properties, key)) {
|
|
10463
|
-
errors3.push(`${
|
|
10552
|
+
errors3.push(`${path20}: unexpected property "${key}" (additionalProperties: false)`);
|
|
10464
10553
|
}
|
|
10465
10554
|
}
|
|
10466
10555
|
}
|
|
@@ -10641,10 +10730,10 @@ function parseReference(source) {
|
|
|
10641
10730
|
if (!output || output.name !== "output") {
|
|
10642
10731
|
return { ok: false, message: `Expected ".output" after "steps.${stepId.name}" in "${text}".` };
|
|
10643
10732
|
}
|
|
10644
|
-
const
|
|
10645
|
-
if (!
|
|
10646
|
-
return { ok: false, message:
|
|
10647
|
-
return { ok: true, expr: { kind: "stepOutput", stepId: stepId.name, path:
|
|
10733
|
+
const path22 = parsePath(text, output.end);
|
|
10734
|
+
if (!path22.ok)
|
|
10735
|
+
return { ok: false, message: path22.message };
|
|
10736
|
+
return { ok: true, expr: { kind: "stepOutput", stepId: stepId.name, path: path22.path } };
|
|
10648
10737
|
}
|
|
10649
10738
|
default:
|
|
10650
10739
|
return { ok: false, message: `Unknown root "${root.name}" in "${text}"; ${GRAMMAR_HINT}.` };
|
|
@@ -10659,7 +10748,7 @@ function readIdent(text, start) {
|
|
|
10659
10748
|
return { name: text.slice(start, end), end };
|
|
10660
10749
|
}
|
|
10661
10750
|
function parsePath(text, start) {
|
|
10662
|
-
const
|
|
10751
|
+
const path22 = [];
|
|
10663
10752
|
let i = start;
|
|
10664
10753
|
while (i < text.length) {
|
|
10665
10754
|
const char = text[i];
|
|
@@ -10668,7 +10757,7 @@ function parsePath(text, start) {
|
|
|
10668
10757
|
if (!ident) {
|
|
10669
10758
|
return { ok: false, message: `Invalid path segment after "." at position ${i} in "${text}".` };
|
|
10670
10759
|
}
|
|
10671
|
-
|
|
10760
|
+
path22.push(ident.name);
|
|
10672
10761
|
i = ident.end;
|
|
10673
10762
|
} else if (char === "[") {
|
|
10674
10763
|
let j = i + 1;
|
|
@@ -10680,13 +10769,13 @@ function parsePath(text, start) {
|
|
|
10680
10769
|
message: `Invalid indexer at position ${i} in "${text}" — expected [<non-negative integer>].`
|
|
10681
10770
|
};
|
|
10682
10771
|
}
|
|
10683
|
-
|
|
10772
|
+
path22.push(Number.parseInt(text.slice(i + 1, j), 10));
|
|
10684
10773
|
i = j + 1;
|
|
10685
10774
|
} else {
|
|
10686
10775
|
return { ok: false, message: `Unexpected character "${char}" at position ${i} in "${text}".` };
|
|
10687
10776
|
}
|
|
10688
10777
|
}
|
|
10689
|
-
return { ok: true, path:
|
|
10778
|
+
return { ok: true, path: path22 };
|
|
10690
10779
|
}
|
|
10691
10780
|
function formatReference(expr) {
|
|
10692
10781
|
switch (expr.kind) {
|
|
@@ -11059,7 +11148,7 @@ var init_uses = __esm(() => {
|
|
|
11059
11148
|
|
|
11060
11149
|
// src/workflows/source-ir/semantics.ts
|
|
11061
11150
|
import fs15 from "node:fs";
|
|
11062
|
-
import
|
|
11151
|
+
import path22 from "node:path";
|
|
11063
11152
|
function canonicalizeWorkflowCron(value) {
|
|
11064
11153
|
const canonical = value.trim().split(/\s+/).join(" ");
|
|
11065
11154
|
if (canonical.startsWith("@") || canonical.split(" ").length !== 5) {
|
|
@@ -11095,7 +11184,7 @@ function canonicalizeWorkflowWorkingDirectory(value, workspaceRoot) {
|
|
|
11095
11184
|
}
|
|
11096
11185
|
const portable = value.replaceAll("\\", "/");
|
|
11097
11186
|
const segments = portable.split("/");
|
|
11098
|
-
if (
|
|
11187
|
+
if (path22.posix.isAbsolute(portable) || path22.win32.isAbsolute(value) || portable.startsWith("~") || segments.some((segment) => segment === "" || segment === "..")) {
|
|
11099
11188
|
throw new WorkflowSourceSemanticError("working-directory-escape", "working-directory must be relative and contained.");
|
|
11100
11189
|
}
|
|
11101
11190
|
const withoutDots = segments.filter((segment) => segment !== ".");
|
|
@@ -11175,13 +11264,13 @@ function verifyPhysicalContainment(workspaceRoot, relative) {
|
|
|
11175
11264
|
} catch {
|
|
11176
11265
|
throw new WorkflowSourceSemanticError("working-directory-unverifiable", "Workspace root cannot be physically verified.");
|
|
11177
11266
|
}
|
|
11178
|
-
const candidate =
|
|
11267
|
+
const candidate = path22.resolve(root, ...relative.split("/"));
|
|
11179
11268
|
if (!contained(root, candidate)) {
|
|
11180
11269
|
throw new WorkflowSourceSemanticError("working-directory-escape", "working-directory escapes the workspace.");
|
|
11181
11270
|
}
|
|
11182
11271
|
let current = root;
|
|
11183
11272
|
for (const segment of relative === "." ? [] : relative.split("/")) {
|
|
11184
|
-
current =
|
|
11273
|
+
current = path22.join(current, segment);
|
|
11185
11274
|
try {
|
|
11186
11275
|
const entry = fs15.lstatSync(current);
|
|
11187
11276
|
if (entry.isSymbolicLink()) {
|
|
@@ -11224,8 +11313,8 @@ function verifyPhysicalContainment(workspaceRoot, relative) {
|
|
|
11224
11313
|
}
|
|
11225
11314
|
}
|
|
11226
11315
|
function contained(root, candidate) {
|
|
11227
|
-
const relative =
|
|
11228
|
-
return relative === "" || !relative.startsWith(`..${
|
|
11316
|
+
const relative = path22.relative(root, candidate);
|
|
11317
|
+
return relative === "" || !relative.startsWith(`..${path22.sep}`) && relative !== ".." && !path22.isAbsolute(relative);
|
|
11229
11318
|
}
|
|
11230
11319
|
var TOKEN_SAFE_RUN, WorkflowSourceSemanticError;
|
|
11231
11320
|
var init_semantics = __esm(() => {
|
|
@@ -12059,7 +12148,7 @@ function parseWorkflow(markdown, source) {
|
|
|
12059
12148
|
};
|
|
12060
12149
|
}
|
|
12061
12150
|
const errors3 = [];
|
|
12062
|
-
const
|
|
12151
|
+
const path23 = source.path;
|
|
12063
12152
|
const lines = markdown.split(/\r?\n/);
|
|
12064
12153
|
const totalLines = lines.length;
|
|
12065
12154
|
const fmBlock = parseFrontmatterBlock(markdown);
|
|
@@ -12111,7 +12200,7 @@ function parseWorkflow(markdown, source) {
|
|
|
12111
12200
|
return 2;
|
|
12112
12201
|
};
|
|
12113
12202
|
const ctx = {
|
|
12114
|
-
filePath:
|
|
12203
|
+
filePath: path23,
|
|
12115
12204
|
errors: errors3,
|
|
12116
12205
|
...source.validateExecCwd ? { validateExecCwd: source.validateExecCwd } : {},
|
|
12117
12206
|
lineAt,
|
|
@@ -12124,10 +12213,10 @@ function parseWorkflow(markdown, source) {
|
|
|
12124
12213
|
if (range) {
|
|
12125
12214
|
const start = Math.max(1, lineCounter2.linePos(range[0]).line + lineOffset);
|
|
12126
12215
|
const end = Math.max(start, lineCounter2.linePos(Math.max(range[0], range[1] - 1)).line + lineOffset);
|
|
12127
|
-
return { path:
|
|
12216
|
+
return { path: path23, start, end };
|
|
12128
12217
|
}
|
|
12129
12218
|
}
|
|
12130
|
-
return { path:
|
|
12219
|
+
return { path: path23, start: frontmatterEndLine, end: frontmatterEndLine };
|
|
12131
12220
|
},
|
|
12132
12221
|
err: (p, message) => errors3.push({ line: lineAt(p), message }),
|
|
12133
12222
|
errAtLine: (line, message) => errors3.push({ line, message })
|
|
@@ -12151,7 +12240,7 @@ function parseWorkflow(markdown, source) {
|
|
|
12151
12240
|
const parsedSteps = parseSteps(ctx, root.steps);
|
|
12152
12241
|
const toc = parseMarkdownToc(markdown);
|
|
12153
12242
|
const declaredIds = new Set(parsedSteps.map((s) => s.id));
|
|
12154
|
-
const { sections, preamble } = bindStepSections(toc.headings, lines, fmBlock.bodyStartLine, totalLines,
|
|
12243
|
+
const { sections, preamble } = bindStepSections(toc.headings, lines, fmBlock.bodyStartLine, totalLines, path23, declaredIds, errors3);
|
|
12155
12244
|
const steps = parsedSteps.map((step, index) => {
|
|
12156
12245
|
const section = sections.get(step.id);
|
|
12157
12246
|
if (!section) {
|
|
@@ -12195,14 +12284,14 @@ function parseWorkflow(markdown, source) {
|
|
|
12195
12284
|
...budget ? { budget } : {},
|
|
12196
12285
|
steps,
|
|
12197
12286
|
...preamble ? { preamble } : {},
|
|
12198
|
-
source: { path:
|
|
12287
|
+
source: { path: path23, lineCount: totalLines }
|
|
12199
12288
|
};
|
|
12200
12289
|
runSemanticChecks(draft, root, frontmatterEndLine, errors3);
|
|
12201
12290
|
if (errors3.length > 0)
|
|
12202
12291
|
return { ok: false, errors: sortErrors(errors3) };
|
|
12203
12292
|
return { ok: true, document: draft };
|
|
12204
12293
|
}
|
|
12205
|
-
function bindStepSections(headings, lines, bodyStartLine, totalLines,
|
|
12294
|
+
function bindStepSections(headings, lines, bodyStartLine, totalLines, path23, declaredIds, errors3) {
|
|
12206
12295
|
const sections = new Map;
|
|
12207
12296
|
const h2s = headings.filter((h) => h.level === 2);
|
|
12208
12297
|
const firstH2Line = h2s[0]?.line;
|
|
@@ -12226,24 +12315,24 @@ function bindStepSections(headings, lines, bodyStartLine, totalLines, path22, de
|
|
|
12226
12315
|
continue;
|
|
12227
12316
|
}
|
|
12228
12317
|
const sectionEnd = findNextHeadingAtOrAboveLevel(headings, i, 2, totalLines);
|
|
12229
|
-
const gate = findGateSubsection(headings, i, sectionEnd,
|
|
12318
|
+
const gate = findGateSubsection(headings, i, sectionEnd, path23, h.text, errors3);
|
|
12230
12319
|
const instructionsEnd = gate ? gate.headingLine - 1 : sectionEnd;
|
|
12231
12320
|
const instructionsText = sliceProseLines(lines, h.line + 1, instructionsEnd);
|
|
12232
12321
|
const section = { headingLine: h.line };
|
|
12233
12322
|
if (instructionsText) {
|
|
12234
|
-
section.instructions = { text: instructionsText, source: { path:
|
|
12323
|
+
section.instructions = { text: instructionsText, source: { path: path23, start: h.line + 1, end: instructionsEnd } };
|
|
12235
12324
|
}
|
|
12236
12325
|
if (gate) {
|
|
12237
12326
|
const gateText = sliceProseLines(lines, gate.bodyStart, gate.bodyEnd);
|
|
12238
12327
|
if (gateText) {
|
|
12239
|
-
section.gateRubric = { text: gateText, source: { path:
|
|
12328
|
+
section.gateRubric = { text: gateText, source: { path: path23, start: gate.bodyStart, end: gate.bodyEnd } };
|
|
12240
12329
|
}
|
|
12241
12330
|
}
|
|
12242
12331
|
sections.set(h.text, section);
|
|
12243
12332
|
}
|
|
12244
12333
|
return { sections, preamble: preambleRaw || undefined };
|
|
12245
12334
|
}
|
|
12246
|
-
function findGateSubsection(headings, stepHeadingIndex, sectionEnd,
|
|
12335
|
+
function findGateSubsection(headings, stepHeadingIndex, sectionEnd, path23, stepId, errors3) {
|
|
12247
12336
|
let found;
|
|
12248
12337
|
for (let j = stepHeadingIndex + 1;j < headings.length; j++) {
|
|
12249
12338
|
const h = headings[j];
|
|
@@ -12325,19 +12414,19 @@ function checkEnvelopeFields(ctx, root, fmEndLine) {
|
|
|
12325
12414
|
ctx.err(["stale_after"], `Workflow frontmatter "stale_after" must be a string.`);
|
|
12326
12415
|
}
|
|
12327
12416
|
}
|
|
12328
|
-
function checkActorStamp(ctx, value,
|
|
12417
|
+
function checkActorStamp(ctx, value, path23, label) {
|
|
12329
12418
|
if (value === undefined)
|
|
12330
12419
|
return;
|
|
12331
12420
|
if (!isRecord(value)) {
|
|
12332
|
-
ctx.err(
|
|
12421
|
+
ctx.err(path23, `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
|
|
12333
12422
|
return;
|
|
12334
12423
|
}
|
|
12335
|
-
checkUnknownKeys(ctx, value,
|
|
12424
|
+
checkUnknownKeys(ctx, value, path23, ACTOR_STAMP_KEYS, `${label} actor stamp`);
|
|
12336
12425
|
if (typeof value.by !== "string" || value.by.length === 0) {
|
|
12337
|
-
ctx.err([...
|
|
12426
|
+
ctx.err([...path23, "by"], `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
|
|
12338
12427
|
}
|
|
12339
12428
|
if (value.at !== undefined && typeof value.at !== "string") {
|
|
12340
|
-
ctx.err([...
|
|
12429
|
+
ctx.err([...path23, "at"], `Workflow frontmatter ${label} actor stamp "at" must be a string.`);
|
|
12341
12430
|
}
|
|
12342
12431
|
}
|
|
12343
12432
|
function readTags2(ctx, value, fmEndLine) {
|
|
@@ -12390,38 +12479,38 @@ function parseOutputs(ctx, raw) {
|
|
|
12390
12479
|
}
|
|
12391
12480
|
const outputs = {};
|
|
12392
12481
|
for (const [outputName, value] of Object.entries(raw)) {
|
|
12393
|
-
const
|
|
12482
|
+
const path23 = ["outputs", outputName];
|
|
12394
12483
|
if (!INPUT_NAME_PATTERN.test(outputName)) {
|
|
12395
|
-
ctx.err(
|
|
12484
|
+
ctx.err(path23, `Output name "${outputName}" is invalid. Use letters, digits, and underscores, starting with a letter or ` + `underscore, so "steps.<child>.output.${outputName}" can address it.`);
|
|
12396
12485
|
continue;
|
|
12397
12486
|
}
|
|
12398
12487
|
if (!isRecord(value)) {
|
|
12399
|
-
ctx.err(
|
|
12488
|
+
ctx.err(path23, `Output "${outputName}" must be a mapping with "from" (and optional "schema").`);
|
|
12400
12489
|
continue;
|
|
12401
12490
|
}
|
|
12402
|
-
checkUnknownKeys(ctx, value,
|
|
12491
|
+
checkUnknownKeys(ctx, value, path23, OUTPUT_ENTRY_KEYS, `output "${outputName}"`);
|
|
12403
12492
|
if (typeof value.from !== "string" || value.from.trim() === "") {
|
|
12404
|
-
ctx.err([...
|
|
12493
|
+
ctx.err([...path23, "from"], `Output "${outputName}" must declare "from": a steps.<id>.output(.<seg>)* reference.`);
|
|
12405
12494
|
continue;
|
|
12406
12495
|
}
|
|
12407
12496
|
const parsedFrom = parseReference(value.from);
|
|
12408
12497
|
if (!parsedFrom.ok) {
|
|
12409
|
-
ctx.err([...
|
|
12498
|
+
ctx.err([...path23, "from"], `Output "${outputName}" "from": ${parsedFrom.message}`);
|
|
12410
12499
|
continue;
|
|
12411
12500
|
}
|
|
12412
12501
|
if (parsedFrom.expr.kind !== "stepOutput") {
|
|
12413
|
-
ctx.err([...
|
|
12502
|
+
ctx.err([...path23, "from"], `Output "${outputName}" "from" must reference a step output (steps.<id>.output...), not a param — an ` + `output projects a step artifact, never a param (got "${value.from}").`);
|
|
12414
12503
|
continue;
|
|
12415
12504
|
}
|
|
12416
12505
|
const entry = { from: value.from };
|
|
12417
12506
|
if (value.schema !== undefined) {
|
|
12418
12507
|
if (!isRecord(value.schema)) {
|
|
12419
|
-
ctx.err([...
|
|
12508
|
+
ctx.err([...path23, "schema"], `Output "${outputName}" "schema" must be a JSON Schema object.`);
|
|
12420
12509
|
} else {
|
|
12421
12510
|
if (jsonBytes(value.schema) > WORKFLOW_MAX_SCHEMA_BYTES) {
|
|
12422
|
-
ctx.err([...
|
|
12511
|
+
ctx.err([...path23, "schema"], `Output "${outputName}" schema exceeds the 256 KiB resource limit.`);
|
|
12423
12512
|
}
|
|
12424
|
-
checkSchemaDefinition(ctx, value.schema, [...
|
|
12513
|
+
checkSchemaDefinition(ctx, value.schema, [...path23, "schema"], `Output "${outputName}" schema`);
|
|
12425
12514
|
entry.schema = value.schema;
|
|
12426
12515
|
}
|
|
12427
12516
|
}
|
|
@@ -12432,15 +12521,15 @@ function parseOutputs(ctx, raw) {
|
|
|
12432
12521
|
function parseDefaults(ctx, raw) {
|
|
12433
12522
|
if (raw === undefined)
|
|
12434
12523
|
return;
|
|
12435
|
-
const
|
|
12524
|
+
const path23 = ["defaults"];
|
|
12436
12525
|
if (!isRecord(raw)) {
|
|
12437
|
-
ctx.err(
|
|
12526
|
+
ctx.err(path23, `"defaults" must be a mapping with any of: ${DEFAULTS_KEYS.join(", ")}.`);
|
|
12438
12527
|
return;
|
|
12439
12528
|
}
|
|
12440
|
-
checkUnknownKeys(ctx, raw,
|
|
12529
|
+
checkUnknownKeys(ctx, raw, path23, DEFAULTS_KEYS, `"defaults"`);
|
|
12441
12530
|
const defaults = {};
|
|
12442
12531
|
if (raw.engine !== undefined) {
|
|
12443
|
-
const engine = parseEngineName(ctx, raw.engine, [...
|
|
12532
|
+
const engine = parseEngineName(ctx, raw.engine, [...path23, "engine"], `"defaults.engine"`);
|
|
12444
12533
|
if (engine !== undefined)
|
|
12445
12534
|
defaults.engine = engine;
|
|
12446
12535
|
}
|
|
@@ -12448,15 +12537,15 @@ function parseDefaults(ctx, raw) {
|
|
|
12448
12537
|
if (typeof raw.model === "string" && raw.model.trim() !== "")
|
|
12449
12538
|
defaults.model = raw.model.trim();
|
|
12450
12539
|
else
|
|
12451
|
-
ctx.err([...
|
|
12540
|
+
ctx.err([...path23, "model"], `"defaults.model" must be a non-empty string (a model alias or exact id).`);
|
|
12452
12541
|
}
|
|
12453
|
-
const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...
|
|
12542
|
+
const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...path23, "timeout"], `"defaults.timeout"`);
|
|
12454
12543
|
if (timeoutMs !== undefined)
|
|
12455
12544
|
defaults.timeoutMs = timeoutMs;
|
|
12456
|
-
const onError = parseEnumField(ctx, raw.on_error, [...
|
|
12545
|
+
const onError = parseEnumField(ctx, raw.on_error, [...path23, "on_error"], `"defaults.on_error"`, PROGRAM_ON_ERROR);
|
|
12457
12546
|
if (onError !== undefined)
|
|
12458
12547
|
defaults.onError = onError;
|
|
12459
|
-
const llm = parseLlmOverrides(ctx, raw.llm, [...
|
|
12548
|
+
const llm = parseLlmOverrides(ctx, raw.llm, [...path23, "llm"], `"defaults.llm"`);
|
|
12460
12549
|
if (llm !== undefined)
|
|
12461
12550
|
defaults.llm = llm;
|
|
12462
12551
|
return Object.keys(defaults).length > 0 ? defaults : undefined;
|
|
@@ -12464,25 +12553,25 @@ function parseDefaults(ctx, raw) {
|
|
|
12464
12553
|
function parseBudget(ctx, raw) {
|
|
12465
12554
|
if (raw === undefined)
|
|
12466
12555
|
return;
|
|
12467
|
-
const
|
|
12556
|
+
const path23 = ["budget"];
|
|
12468
12557
|
if (!isRecord(raw)) {
|
|
12469
|
-
ctx.err(
|
|
12558
|
+
ctx.err(path23, `"budget" must be a mapping with any of: ${BUDGET_KEYS.join(", ")}.`);
|
|
12470
12559
|
return;
|
|
12471
12560
|
}
|
|
12472
|
-
checkUnknownKeys(ctx, raw,
|
|
12561
|
+
checkUnknownKeys(ctx, raw, path23, BUDGET_KEYS, `"budget"`);
|
|
12473
12562
|
const budget = {};
|
|
12474
12563
|
if (raw.max_tokens !== undefined) {
|
|
12475
12564
|
if (typeof raw.max_tokens === "number" && Number.isInteger(raw.max_tokens) && raw.max_tokens >= 1) {
|
|
12476
12565
|
budget.maxTokens = raw.max_tokens;
|
|
12477
12566
|
} else {
|
|
12478
|
-
ctx.err([...
|
|
12567
|
+
ctx.err([...path23, "max_tokens"], `"budget.max_tokens" must be an integer >= 1.`);
|
|
12479
12568
|
}
|
|
12480
12569
|
}
|
|
12481
12570
|
if (raw.max_units !== undefined) {
|
|
12482
12571
|
if (typeof raw.max_units === "number" && Number.isInteger(raw.max_units) && raw.max_units >= 1) {
|
|
12483
12572
|
budget.maxUnits = raw.max_units;
|
|
12484
12573
|
} else {
|
|
12485
|
-
ctx.err([...
|
|
12574
|
+
ctx.err([...path23, "max_units"], `"budget.max_units" must be an integer >= 1.`);
|
|
12486
12575
|
}
|
|
12487
12576
|
}
|
|
12488
12577
|
return Object.keys(budget).length > 0 ? budget : undefined;
|
|
@@ -12502,49 +12591,49 @@ function parseSteps(ctx, raw) {
|
|
|
12502
12591
|
const seenIds = new Map;
|
|
12503
12592
|
const routeChecks = [];
|
|
12504
12593
|
raw.forEach((rawStep, index) => {
|
|
12505
|
-
const
|
|
12594
|
+
const path23 = ["steps", index];
|
|
12506
12595
|
if (!isRecord(rawStep)) {
|
|
12507
|
-
ctx.err(
|
|
12596
|
+
ctx.err(path23, `Step ${index + 1} must be a mapping with an "id".`);
|
|
12508
12597
|
return;
|
|
12509
12598
|
}
|
|
12510
12599
|
const label = typeof rawStep.id === "string" && rawStep.id !== "" ? `Step "${rawStep.id}"` : `Step ${index + 1}`;
|
|
12511
|
-
checkUnknownKeys(ctx, rawStep,
|
|
12600
|
+
checkUnknownKeys(ctx, rawStep, path23, STEP_KEYS, label);
|
|
12512
12601
|
let id = "";
|
|
12513
12602
|
if (typeof rawStep.id !== "string" || rawStep.id === "") {
|
|
12514
|
-
ctx.err([...
|
|
12603
|
+
ctx.err([...path23, "id"], `${label} requires a non-empty string "id".`);
|
|
12515
12604
|
} else if (!PROGRAM_STEP_ID_PATTERN.test(rawStep.id)) {
|
|
12516
|
-
ctx.err([...
|
|
12605
|
+
ctx.err([...path23, "id"], `${label} has an invalid id "${rawStep.id}". A step id cannot be referenced from steps.${rawStep.id}.output ` + `unless it matches [A-Za-z_][A-Za-z0-9_-]* (a letter or underscore first, then letters, digits, ` + `underscores, or dashes; no dots, no leading digit).`);
|
|
12517
12606
|
} else {
|
|
12518
12607
|
id = rawStep.id;
|
|
12519
12608
|
const firstIndex = seenIds.get(id);
|
|
12520
12609
|
if (firstIndex !== undefined) {
|
|
12521
|
-
ctx.err([...
|
|
12610
|
+
ctx.err([...path23, "id"], `Duplicate step id "${id}" (first used by step ${firstIndex + 1}). Step ids must be unique.`);
|
|
12522
12611
|
} else {
|
|
12523
12612
|
seenIds.set(id, index);
|
|
12524
12613
|
}
|
|
12525
12614
|
}
|
|
12526
12615
|
const declaredKinds = ["map", "route"].filter((kind) => rawStep[kind] !== undefined);
|
|
12527
12616
|
if (declaredKinds.length > 1) {
|
|
12528
|
-
ctx.err(
|
|
12617
|
+
ctx.err(path23, `${label} must declare at most one of "map" or "route" (found ${declaredKinds.join(" + ")}).`);
|
|
12529
12618
|
}
|
|
12530
12619
|
const isRoute = rawStep.route !== undefined;
|
|
12531
12620
|
const isMapStep = rawStep.map !== undefined;
|
|
12532
12621
|
if (isRoute && rawStep.unit !== undefined) {
|
|
12533
|
-
ctx.err(
|
|
12622
|
+
ctx.err(path23, `${label} is a route step and cannot also declare "unit" (route steps dispatch no unit).`);
|
|
12534
12623
|
}
|
|
12535
12624
|
if (isMapStep && rawStep.unit !== undefined) {
|
|
12536
|
-
ctx.err(
|
|
12625
|
+
ctx.err(path23, `${label} is a map step; the per-item dispatch-override bag belongs at "map.unit", not top-level "unit".`);
|
|
12537
12626
|
}
|
|
12538
12627
|
if (isRoute && rawStep.inputs !== undefined) {
|
|
12539
|
-
ctx.err(
|
|
12540
|
-
}
|
|
12541
|
-
const unit = rawStep.unit !== undefined && !isRoute && !isMapStep ? parseUnit(ctx, rawStep.unit, [...
|
|
12542
|
-
const map = isMapStep ? parseMap(ctx, rawStep.map, [...
|
|
12543
|
-
const route = isRoute ? parseRoute(ctx, rawStep.route, [...
|
|
12544
|
-
const inputs = !isRoute ? parseInputs(ctx, rawStep.inputs, [...
|
|
12545
|
-
const output = parseSchemaObject(ctx, rawStep.output, [...
|
|
12546
|
-
const gate = rawStep.gate !== undefined ? parseGate(ctx, rawStep.gate, [...
|
|
12547
|
-
const step = { id, source: ctx.refAt(
|
|
12628
|
+
ctx.err(path23, `${label} is a route step and cannot declare "inputs" (route steps dispatch no unit).`);
|
|
12629
|
+
}
|
|
12630
|
+
const unit = rawStep.unit !== undefined && !isRoute && !isMapStep ? parseUnit(ctx, rawStep.unit, [...path23, "unit"], label) : undefined;
|
|
12631
|
+
const map = isMapStep ? parseMap(ctx, rawStep.map, [...path23, "map"], label) : undefined;
|
|
12632
|
+
const route = isRoute ? parseRoute(ctx, rawStep.route, [...path23, "route"], label, index, routeChecks) : undefined;
|
|
12633
|
+
const inputs = !isRoute ? parseInputs(ctx, rawStep.inputs, [...path23, "inputs"], label) : undefined;
|
|
12634
|
+
const output = parseSchemaObject(ctx, rawStep.output, [...path23, "output"], `${label} "output"`);
|
|
12635
|
+
const gate = rawStep.gate !== undefined ? parseGate(ctx, rawStep.gate, [...path23, "gate"], label) : undefined;
|
|
12636
|
+
const step = { id, source: ctx.refAt(path23) };
|
|
12548
12637
|
if (unit)
|
|
12549
12638
|
step.unit = unit;
|
|
12550
12639
|
if (map)
|
|
@@ -12576,25 +12665,25 @@ function parseSteps(ctx, raw) {
|
|
|
12576
12665
|
}
|
|
12577
12666
|
return steps;
|
|
12578
12667
|
}
|
|
12579
|
-
function parseUnit(ctx, raw,
|
|
12668
|
+
function parseUnit(ctx, raw, path23, stepLabel) {
|
|
12580
12669
|
if (!isRecord(raw)) {
|
|
12581
|
-
ctx.err(
|
|
12670
|
+
ctx.err(path23, `${stepLabel} "unit" must be a mapping (a dispatch-override bag).`);
|
|
12582
12671
|
return;
|
|
12583
12672
|
}
|
|
12584
|
-
checkUnknownKeys(ctx, raw,
|
|
12585
|
-
const unit = { source: ctx.refAt(
|
|
12673
|
+
checkUnknownKeys(ctx, raw, path23, UNIT_KEYS, `${stepLabel} "unit"`);
|
|
12674
|
+
const unit = { source: ctx.refAt(path23) };
|
|
12586
12675
|
if (raw.exec !== undefined) {
|
|
12587
|
-
const exec = parseExec(ctx, raw.exec, [...
|
|
12676
|
+
const exec = parseExec(ctx, raw.exec, [...path23, "exec"], stepLabel);
|
|
12588
12677
|
if (exec !== undefined)
|
|
12589
12678
|
unit.exec = exec;
|
|
12590
12679
|
for (const key of UNIT_ENGINE_KEYS) {
|
|
12591
12680
|
if (raw[key] === undefined)
|
|
12592
12681
|
continue;
|
|
12593
|
-
ctx.err([...
|
|
12682
|
+
ctx.err([...path23, key], `${stepLabel} "unit" declares both "exec" and "${key}". An exec unit runs a shell command and never ` + `reaches an engine, so "${key}" would have no effect — remove one of the two.`);
|
|
12594
12683
|
}
|
|
12595
12684
|
}
|
|
12596
12685
|
if (raw.engine !== undefined) {
|
|
12597
|
-
const engine = parseEngineName(ctx, raw.engine, [...
|
|
12686
|
+
const engine = parseEngineName(ctx, raw.engine, [...path23, "engine"], `${stepLabel} "engine"`);
|
|
12598
12687
|
if (engine !== undefined)
|
|
12599
12688
|
unit.engine = engine;
|
|
12600
12689
|
}
|
|
@@ -12602,21 +12691,21 @@ function parseUnit(ctx, raw, path22, stepLabel) {
|
|
|
12602
12691
|
if (typeof raw.model === "string" && raw.model.trim() !== "")
|
|
12603
12692
|
unit.model = raw.model.trim();
|
|
12604
12693
|
else
|
|
12605
|
-
ctx.err([...
|
|
12694
|
+
ctx.err([...path23, "model"], `${stepLabel} "model" must be a non-empty string (a model alias or exact id).`);
|
|
12606
12695
|
}
|
|
12607
|
-
const llm = parseLlmOverrides(ctx, raw.llm, [...
|
|
12696
|
+
const llm = parseLlmOverrides(ctx, raw.llm, [...path23, "llm"], `${stepLabel} "llm"`);
|
|
12608
12697
|
if (llm !== undefined)
|
|
12609
12698
|
unit.llm = llm;
|
|
12610
|
-
const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...
|
|
12699
|
+
const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...path23, "timeout"], `${stepLabel} "timeout"`);
|
|
12611
12700
|
if (timeoutMs !== undefined)
|
|
12612
12701
|
unit.timeoutMs = timeoutMs;
|
|
12613
|
-
const retry = parseRetry(ctx, raw.retry, [...
|
|
12702
|
+
const retry = parseRetry(ctx, raw.retry, [...path23, "retry"], stepLabel);
|
|
12614
12703
|
if (retry !== undefined)
|
|
12615
12704
|
unit.retry = retry;
|
|
12616
|
-
const onError = parseEnumField(ctx, raw.on_error, [...
|
|
12705
|
+
const onError = parseEnumField(ctx, raw.on_error, [...path23, "on_error"], `${stepLabel} "on_error"`, PROGRAM_ON_ERROR);
|
|
12617
12706
|
if (onError !== undefined)
|
|
12618
12707
|
unit.onError = onError;
|
|
12619
|
-
const output = parseSchemaObject(ctx, raw.output, [...
|
|
12708
|
+
const output = parseSchemaObject(ctx, raw.output, [...path23, "output"], `${stepLabel} unit "output"`);
|
|
12620
12709
|
if (output !== undefined)
|
|
12621
12710
|
unit.output = output;
|
|
12622
12711
|
if (raw.env !== undefined) {
|
|
@@ -12624,87 +12713,87 @@ function parseUnit(ctx, raw, path22, stepLabel) {
|
|
|
12624
12713
|
const envRefs = raw.env.map((entry) => entry.trim());
|
|
12625
12714
|
const duplicate = envRefs.find((ref, i) => envRefs.indexOf(ref) !== i);
|
|
12626
12715
|
if (duplicate !== undefined) {
|
|
12627
|
-
ctx.err([...
|
|
12716
|
+
ctx.err([...path23, "env"], `${stepLabel} "env" contains a duplicate entry: "${duplicate}".`);
|
|
12628
12717
|
} else {
|
|
12629
12718
|
unit.env = envRefs;
|
|
12630
12719
|
}
|
|
12631
12720
|
} else {
|
|
12632
|
-
ctx.err([...
|
|
12721
|
+
ctx.err([...path23, "env"], `${stepLabel} "env" must be a list of non-empty env asset refs.`);
|
|
12633
12722
|
}
|
|
12634
12723
|
}
|
|
12635
|
-
const isolation = parseEnumField(ctx, raw.isolation, [...
|
|
12724
|
+
const isolation = parseEnumField(ctx, raw.isolation, [...path23, "isolation"], `${stepLabel} "isolation"`, PROGRAM_ISOLATION_KINDS);
|
|
12636
12725
|
if (isolation !== undefined)
|
|
12637
12726
|
unit.isolation = isolation;
|
|
12638
12727
|
return unit;
|
|
12639
12728
|
}
|
|
12640
|
-
function parseExec(ctx, raw,
|
|
12729
|
+
function parseExec(ctx, raw, path23, stepLabel) {
|
|
12641
12730
|
if (!isRecord(raw)) {
|
|
12642
|
-
ctx.err(
|
|
12731
|
+
ctx.err(path23, `${stepLabel} "exec" must be a mapping with a "command" argv list.`);
|
|
12643
12732
|
return;
|
|
12644
12733
|
}
|
|
12645
|
-
checkUnknownKeys(ctx, raw,
|
|
12646
|
-
const command = parseExecCommand(ctx, raw.command, [...
|
|
12734
|
+
checkUnknownKeys(ctx, raw, path23, EXEC_KEYS, `${stepLabel} "exec"`);
|
|
12735
|
+
const command = parseExecCommand(ctx, raw.command, [...path23, "command"], stepLabel);
|
|
12647
12736
|
if (command === undefined)
|
|
12648
12737
|
return;
|
|
12649
12738
|
const exec = { command };
|
|
12650
|
-
const cwd = parseExecCwd(ctx, raw.cwd, [...
|
|
12739
|
+
const cwd = parseExecCwd(ctx, raw.cwd, [...path23, "cwd"], stepLabel);
|
|
12651
12740
|
if (cwd !== undefined)
|
|
12652
12741
|
exec.cwd = cwd;
|
|
12653
|
-
const passEnv = parseExecPassEnv(ctx, raw.pass_env, [...
|
|
12742
|
+
const passEnv = parseExecPassEnv(ctx, raw.pass_env, [...path23, "pass_env"], stepLabel);
|
|
12654
12743
|
if (passEnv !== undefined)
|
|
12655
12744
|
exec.passEnv = passEnv;
|
|
12656
12745
|
return exec;
|
|
12657
12746
|
}
|
|
12658
|
-
function parseExecPassEnv(ctx, raw,
|
|
12747
|
+
function parseExecPassEnv(ctx, raw, path23, stepLabel) {
|
|
12659
12748
|
if (raw === undefined)
|
|
12660
12749
|
return;
|
|
12661
12750
|
if (!Array.isArray(raw) || raw.length === 0) {
|
|
12662
|
-
ctx.err(
|
|
12751
|
+
ctx.err(path23, `${stepLabel} "exec.pass_env" must be a non-empty list of environment variable NAMES to copy through from ` + `akm's own environment, e.g. pass_env: [CARGO_HOME]. Values never appear here — use "env:" bindings for those.`);
|
|
12663
12752
|
return;
|
|
12664
12753
|
}
|
|
12665
12754
|
const names = [];
|
|
12666
12755
|
for (const [index, entry] of raw.entries()) {
|
|
12667
12756
|
if (typeof entry !== "string" || !WORKFLOW_ENV_VAR_NAME_PATTERN.test(entry)) {
|
|
12668
|
-
ctx.err(
|
|
12757
|
+
ctx.err(path23, `${stepLabel} "exec.pass_env[${index}]" must be an environment variable name matching ` + `${WORKFLOW_ENV_VAR_NAME_PATTERN.source}.`);
|
|
12669
12758
|
return;
|
|
12670
12759
|
}
|
|
12671
12760
|
if (names.includes(entry)) {
|
|
12672
|
-
ctx.err(
|
|
12761
|
+
ctx.err(path23, `${stepLabel} "exec.pass_env" lists "${entry}" more than once.`);
|
|
12673
12762
|
return;
|
|
12674
12763
|
}
|
|
12675
12764
|
names.push(entry);
|
|
12676
12765
|
}
|
|
12677
12766
|
return names;
|
|
12678
12767
|
}
|
|
12679
|
-
function parseExecCommand(ctx, raw,
|
|
12768
|
+
function parseExecCommand(ctx, raw, path23, stepLabel) {
|
|
12680
12769
|
if (!Array.isArray(raw) || raw.length === 0) {
|
|
12681
|
-
ctx.err(
|
|
12770
|
+
ctx.err(path23, `${stepLabel} "exec" requires "command": a non-empty argv list, e.g. command: ["bun", "run", "test:unit"]. ` + `A single shell string is not accepted — the command is spawned directly, never through a shell.`);
|
|
12682
12771
|
return;
|
|
12683
12772
|
}
|
|
12684
12773
|
const argv = [];
|
|
12685
12774
|
for (const [index, entry] of raw.entries()) {
|
|
12686
12775
|
if (typeof entry !== "string" || entry === "") {
|
|
12687
|
-
ctx.err(
|
|
12776
|
+
ctx.err(path23, `${stepLabel} "exec.command[${index}]" must be a non-empty string.`);
|
|
12688
12777
|
return;
|
|
12689
12778
|
}
|
|
12690
12779
|
if (entry.includes("\x00")) {
|
|
12691
|
-
ctx.err([...
|
|
12780
|
+
ctx.err([...path23, index], `${stepLabel} "exec.command[${index}]" may not contain NUL bytes.`);
|
|
12692
12781
|
return;
|
|
12693
12782
|
}
|
|
12694
12783
|
argv.push(entry);
|
|
12695
12784
|
}
|
|
12696
12785
|
return argv;
|
|
12697
12786
|
}
|
|
12698
|
-
function parseExecCwd(ctx, raw,
|
|
12787
|
+
function parseExecCwd(ctx, raw, path23, stepLabel) {
|
|
12699
12788
|
if (raw === undefined)
|
|
12700
12789
|
return;
|
|
12701
12790
|
if (typeof raw !== "string" || raw.trim() === "") {
|
|
12702
|
-
ctx.err(
|
|
12791
|
+
ctx.err(path23, `${stepLabel} "exec.cwd" must be a non-empty relative path inside the unit's working directory.`);
|
|
12703
12792
|
return;
|
|
12704
12793
|
}
|
|
12705
12794
|
const value = raw.trim();
|
|
12706
12795
|
if (!isContainedRelativePath(value)) {
|
|
12707
|
-
ctx.err(
|
|
12796
|
+
ctx.err(path23, `${stepLabel} "exec.cwd" (${JSON.stringify(value)}) must be a RELATIVE path inside the unit's working ` + `directory — absolute paths, Windows drive letters, "~", and ".." segments are rejected.`);
|
|
12708
12797
|
return;
|
|
12709
12798
|
}
|
|
12710
12799
|
if (ctx.validateExecCwd) {
|
|
@@ -12712,7 +12801,7 @@ function parseExecCwd(ctx, raw, path22, stepLabel) {
|
|
|
12712
12801
|
if (!semantic.ok) {
|
|
12713
12802
|
ctx.errors.push({
|
|
12714
12803
|
code: semantic.code,
|
|
12715
|
-
line: ctx.lineAt(
|
|
12804
|
+
line: ctx.lineAt(path23),
|
|
12716
12805
|
message: semantic.message
|
|
12717
12806
|
});
|
|
12718
12807
|
return;
|
|
@@ -12721,29 +12810,29 @@ function parseExecCwd(ctx, raw, path22, stepLabel) {
|
|
|
12721
12810
|
}
|
|
12722
12811
|
return value;
|
|
12723
12812
|
}
|
|
12724
|
-
function parseMap(ctx, raw,
|
|
12813
|
+
function parseMap(ctx, raw, path23, stepLabel) {
|
|
12725
12814
|
if (!isRecord(raw)) {
|
|
12726
|
-
ctx.err(
|
|
12815
|
+
ctx.err(path23, `${stepLabel} "map" must be a mapping with an "over" key.`);
|
|
12727
12816
|
return;
|
|
12728
12817
|
}
|
|
12729
|
-
checkUnknownKeys(ctx, raw,
|
|
12818
|
+
checkUnknownKeys(ctx, raw, path23, MAP_KEYS, `${stepLabel} "map"`);
|
|
12730
12819
|
let over = "";
|
|
12731
12820
|
if (typeof raw.over === "string" && raw.over.trim() !== "") {
|
|
12732
12821
|
over = raw.over.trim();
|
|
12733
|
-
checkReferenceSyntax(ctx, over, [...
|
|
12822
|
+
checkReferenceSyntax(ctx, over, [...path23, "over"], `${stepLabel} "over"`);
|
|
12734
12823
|
} else {
|
|
12735
|
-
ctx.err([...
|
|
12824
|
+
ctx.err([...path23, "over"], `${stepLabel} "map" requires "over": a reference naming the item list (e.g. steps.discover.output.files).`);
|
|
12736
12825
|
}
|
|
12737
12826
|
let concurrency;
|
|
12738
12827
|
if (raw.concurrency !== undefined) {
|
|
12739
12828
|
if (typeof raw.concurrency === "number" && Number.isInteger(raw.concurrency) && raw.concurrency > 0) {
|
|
12740
12829
|
concurrency = Math.min(raw.concurrency, WORKFLOW_MAX_CONCURRENCY);
|
|
12741
12830
|
} else {
|
|
12742
|
-
ctx.err([...
|
|
12831
|
+
ctx.err([...path23, "concurrency"], `${stepLabel} "concurrency" must be a positive integer.`);
|
|
12743
12832
|
}
|
|
12744
12833
|
}
|
|
12745
|
-
const reducer = parseEnumField(ctx, raw.reducer, [...
|
|
12746
|
-
const unit = raw.unit !== undefined ? parseUnit(ctx, raw.unit, [...
|
|
12834
|
+
const reducer = parseEnumField(ctx, raw.reducer, [...path23, "reducer"], `${stepLabel} "reducer"`, PROGRAM_REDUCERS);
|
|
12835
|
+
const unit = raw.unit !== undefined ? parseUnit(ctx, raw.unit, [...path23, "unit"], stepLabel) : undefined;
|
|
12747
12836
|
const map = { over };
|
|
12748
12837
|
if (concurrency !== undefined)
|
|
12749
12838
|
map.concurrency = concurrency;
|
|
@@ -12753,21 +12842,21 @@ function parseMap(ctx, raw, path22, stepLabel) {
|
|
|
12753
12842
|
map.unit = unit;
|
|
12754
12843
|
return map;
|
|
12755
12844
|
}
|
|
12756
|
-
function parseRoute(ctx, raw,
|
|
12845
|
+
function parseRoute(ctx, raw, path23, stepLabel, stepIndex, routeChecks) {
|
|
12757
12846
|
if (!isRecord(raw)) {
|
|
12758
|
-
ctx.err(
|
|
12847
|
+
ctx.err(path23, `${stepLabel} "route" must be a mapping with "input" and "when" keys.`);
|
|
12759
12848
|
return;
|
|
12760
12849
|
}
|
|
12761
|
-
checkUnknownKeys(ctx, raw,
|
|
12850
|
+
checkUnknownKeys(ctx, raw, path23, ROUTE_KEYS, `${stepLabel} "route"`);
|
|
12762
12851
|
let input = "";
|
|
12763
12852
|
if (typeof raw.input === "string" && raw.input.trim() !== "") {
|
|
12764
12853
|
input = raw.input.trim();
|
|
12765
|
-
checkReferenceSyntax(ctx, input, [...
|
|
12854
|
+
checkReferenceSyntax(ctx, input, [...path23, "input"], `${stepLabel} "route.input"`);
|
|
12766
12855
|
} else {
|
|
12767
|
-
ctx.err([...
|
|
12856
|
+
ctx.err([...path23, "input"], `${stepLabel} "route" requires "input": a reference naming the value to route on.`);
|
|
12768
12857
|
}
|
|
12769
12858
|
const check = { stepIndex, stepLabel, branches: [] };
|
|
12770
|
-
const whenPath = [...
|
|
12859
|
+
const whenPath = [...path23, "when"];
|
|
12771
12860
|
if (!Array.isArray(raw.when) || raw.when.length === 0) {
|
|
12772
12861
|
ctx.err(whenPath, `${stepLabel} "route" requires "when": a non-empty list of { match, step } branches (e.g. when: [{ match: pass, step: ship }]).`);
|
|
12773
12862
|
} else {
|
|
@@ -12808,9 +12897,9 @@ function parseRoute(ctx, raw, path22, stepLabel, stepIndex, routeChecks) {
|
|
|
12808
12897
|
if (raw.default !== undefined) {
|
|
12809
12898
|
if (typeof raw.default === "string" && raw.default.trim() !== "") {
|
|
12810
12899
|
defaultStepId = raw.default.trim();
|
|
12811
|
-
check.defaultTarget = { stepId: defaultStepId, line: ctx.lineAt([...
|
|
12900
|
+
check.defaultTarget = { stepId: defaultStepId, line: ctx.lineAt([...path23, "default"]) };
|
|
12812
12901
|
} else {
|
|
12813
|
-
ctx.err([...
|
|
12902
|
+
ctx.err([...path23, "default"], `${stepLabel} "route.default" must be a step id string.`);
|
|
12814
12903
|
}
|
|
12815
12904
|
}
|
|
12816
12905
|
routeChecks.push(check);
|
|
@@ -12819,70 +12908,70 @@ function parseRoute(ctx, raw, path22, stepLabel, stepIndex, routeChecks) {
|
|
|
12819
12908
|
route.defaultStepId = defaultStepId;
|
|
12820
12909
|
return route;
|
|
12821
12910
|
}
|
|
12822
|
-
function parseInputs(ctx, raw,
|
|
12911
|
+
function parseInputs(ctx, raw, path23, stepLabel) {
|
|
12823
12912
|
if (raw === undefined)
|
|
12824
12913
|
return;
|
|
12825
12914
|
if (!Array.isArray(raw) || raw.length === 0) {
|
|
12826
|
-
ctx.err(
|
|
12915
|
+
ctx.err(path23, `${stepLabel} "inputs" must be a non-empty list of reference strings.`);
|
|
12827
12916
|
return;
|
|
12828
12917
|
}
|
|
12829
12918
|
const out = [];
|
|
12830
12919
|
const seen = new Set;
|
|
12831
12920
|
raw.forEach((entry, i) => {
|
|
12832
12921
|
if (typeof entry !== "string" || entry.trim() === "") {
|
|
12833
|
-
ctx.err([...
|
|
12922
|
+
ctx.err([...path23, i], `${stepLabel} "inputs[${i}]" must be a non-empty reference string.`);
|
|
12834
12923
|
return;
|
|
12835
12924
|
}
|
|
12836
12925
|
const value = entry.trim();
|
|
12837
12926
|
if (seen.has(value)) {
|
|
12838
|
-
ctx.err([...
|
|
12927
|
+
ctx.err([...path23, i], `${stepLabel} "inputs[${i}]" duplicates an earlier entry: "${value}".`);
|
|
12839
12928
|
return;
|
|
12840
12929
|
}
|
|
12841
12930
|
seen.add(value);
|
|
12842
|
-
checkReferenceSyntax(ctx, value, [...
|
|
12931
|
+
checkReferenceSyntax(ctx, value, [...path23, i], `${stepLabel} "inputs[${i}]"`);
|
|
12843
12932
|
out.push(value);
|
|
12844
12933
|
});
|
|
12845
12934
|
return out.length > 0 ? out : undefined;
|
|
12846
12935
|
}
|
|
12847
|
-
function parseGate(ctx, raw,
|
|
12936
|
+
function parseGate(ctx, raw, path23, stepLabel) {
|
|
12848
12937
|
if (!isRecord(raw)) {
|
|
12849
|
-
ctx.err(
|
|
12938
|
+
ctx.err(path23, `${stepLabel} "gate" must be a mapping with any of: ${GATE_KEYS.join(", ")}.`);
|
|
12850
12939
|
return;
|
|
12851
12940
|
}
|
|
12852
|
-
checkUnknownKeys(ctx, raw,
|
|
12941
|
+
checkUnknownKeys(ctx, raw, path23, GATE_KEYS, `${stepLabel} "gate"`);
|
|
12853
12942
|
const gate = {};
|
|
12854
12943
|
if (raw.max_loops !== undefined) {
|
|
12855
12944
|
if (typeof raw.max_loops === "number" && Number.isInteger(raw.max_loops) && raw.max_loops >= 1) {
|
|
12856
12945
|
gate.maxLoops = raw.max_loops;
|
|
12857
12946
|
} else {
|
|
12858
|
-
ctx.err([...
|
|
12947
|
+
ctx.err([...path23, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer of at least 1.`);
|
|
12859
12948
|
}
|
|
12860
12949
|
}
|
|
12861
12950
|
return gate;
|
|
12862
12951
|
}
|
|
12863
|
-
function parseEngineName(ctx, raw,
|
|
12952
|
+
function parseEngineName(ctx, raw, path23, label) {
|
|
12864
12953
|
if (typeof raw !== "string" || raw.trim() === "") {
|
|
12865
|
-
ctx.err(
|
|
12954
|
+
ctx.err(path23, `${label} must be a non-empty engine name.`);
|
|
12866
12955
|
return;
|
|
12867
12956
|
}
|
|
12868
12957
|
const name = raw.trim();
|
|
12869
12958
|
if (!WORKFLOW_ENGINE_NAME_PATTERN.test(name) || name.length > WORKFLOW_MAX_ENGINE_NAME_LENGTH) {
|
|
12870
|
-
ctx.err(
|
|
12959
|
+
ctx.err(path23, `${label} has an invalid engine name ${JSON.stringify(name)}. Engine names are lowercase words of letters ` + `and digits separated by single dashes, starting with a letter (e.g. "code-review-llm"), at most ` + `${WORKFLOW_MAX_ENGINE_NAME_LENGTH} characters.`);
|
|
12871
12960
|
return;
|
|
12872
12961
|
}
|
|
12873
12962
|
return name;
|
|
12874
12963
|
}
|
|
12875
|
-
function parseRetry(ctx, raw,
|
|
12964
|
+
function parseRetry(ctx, raw, path23, stepLabel) {
|
|
12876
12965
|
if (raw === undefined)
|
|
12877
12966
|
return;
|
|
12878
12967
|
if (!isRecord(raw)) {
|
|
12879
|
-
ctx.err(
|
|
12968
|
+
ctx.err(path23, `${stepLabel} "retry" must be a mapping: { max: <n>, on: [<failure_reason>, …] }.`);
|
|
12880
12969
|
return;
|
|
12881
12970
|
}
|
|
12882
|
-
checkUnknownKeys(ctx, raw,
|
|
12971
|
+
checkUnknownKeys(ctx, raw, path23, RETRY_KEYS, `${stepLabel} "retry"`);
|
|
12883
12972
|
let ok = true;
|
|
12884
12973
|
if (!(typeof raw.max === "number" && Number.isInteger(raw.max) && raw.max >= 0)) {
|
|
12885
|
-
ctx.err([...
|
|
12974
|
+
ctx.err([...path23, "max"], `${stepLabel} "retry.max" is required and must be a non-negative integer.`);
|
|
12886
12975
|
ok = false;
|
|
12887
12976
|
}
|
|
12888
12977
|
const on = [];
|
|
@@ -12891,27 +12980,27 @@ function parseRetry(ctx, raw, path22, stepLabel) {
|
|
|
12891
12980
|
if (typeof reason === "string" && PROGRAM_RETRY_REASONS.includes(reason)) {
|
|
12892
12981
|
on.push(reason);
|
|
12893
12982
|
} else {
|
|
12894
|
-
ctx.err([...
|
|
12983
|
+
ctx.err([...path23, "on", i], `${stepLabel} "retry.on" has unknown failure reason ${JSON.stringify(reason)}. Valid reasons: ${PROGRAM_RETRY_REASONS.join(", ")}.`);
|
|
12895
12984
|
ok = false;
|
|
12896
12985
|
}
|
|
12897
12986
|
});
|
|
12898
12987
|
} else {
|
|
12899
|
-
ctx.err([...
|
|
12988
|
+
ctx.err([...path23, "on"], `${stepLabel} "retry.on" is required and must be a non-empty list of failure reasons (${PROGRAM_RETRY_REASONS.join(", ")}).`);
|
|
12900
12989
|
ok = false;
|
|
12901
12990
|
}
|
|
12902
12991
|
return ok ? { max: raw.max, on } : undefined;
|
|
12903
12992
|
}
|
|
12904
|
-
function parseTimeoutField(ctx, raw,
|
|
12993
|
+
function parseTimeoutField(ctx, raw, path23, label) {
|
|
12905
12994
|
if (raw === undefined)
|
|
12906
12995
|
return;
|
|
12907
12996
|
if (typeof raw === "number") {
|
|
12908
12997
|
if (Number.isInteger(raw) && raw > 0)
|
|
12909
|
-
return checkTimeoutCeiling(ctx, raw,
|
|
12910
|
-
ctx.err(
|
|
12998
|
+
return checkTimeoutCeiling(ctx, raw, path23, label, String(raw));
|
|
12999
|
+
ctx.err(path23, `${label} has a non-positive timeout ${JSON.stringify(raw)}. ${TIMEOUT_HINT}.`);
|
|
12911
13000
|
return;
|
|
12912
13001
|
}
|
|
12913
13002
|
if (typeof raw !== "string") {
|
|
12914
|
-
ctx.err(
|
|
13003
|
+
ctx.err(path23, `${label} must be a duration string. ${TIMEOUT_HINT}.`);
|
|
12915
13004
|
return;
|
|
12916
13005
|
}
|
|
12917
13006
|
const value = raw.trim().toLowerCase();
|
|
@@ -12919,37 +13008,37 @@ function parseTimeoutField(ctx, raw, path22, label) {
|
|
|
12919
13008
|
return null;
|
|
12920
13009
|
const match = value.match(TIMEOUT_VALUE);
|
|
12921
13010
|
if (!match) {
|
|
12922
|
-
ctx.err(
|
|
13011
|
+
ctx.err(path23, `${label} has an invalid timeout "${raw}". ${TIMEOUT_HINT}.`);
|
|
12923
13012
|
return;
|
|
12924
13013
|
}
|
|
12925
13014
|
const n = Number.parseInt(match[1], 10);
|
|
12926
13015
|
const unit = match[2] ?? "ms";
|
|
12927
13016
|
const timeoutMs = unit === "m" ? n * 60000 : unit === "s" ? n * 1000 : n;
|
|
12928
13017
|
if (timeoutMs <= 0) {
|
|
12929
|
-
ctx.err(
|
|
13018
|
+
ctx.err(path23, `${label} has a non-positive timeout "${raw}". Use a positive duration or "none".`);
|
|
12930
13019
|
return;
|
|
12931
13020
|
}
|
|
12932
|
-
return checkTimeoutCeiling(ctx, timeoutMs,
|
|
13021
|
+
return checkTimeoutCeiling(ctx, timeoutMs, path23, label, raw);
|
|
12933
13022
|
}
|
|
12934
|
-
function checkTimeoutCeiling(ctx, timeoutMs,
|
|
13023
|
+
function checkTimeoutCeiling(ctx, timeoutMs, path23, label, raw) {
|
|
12935
13024
|
if (timeoutMs <= WORKFLOW_MAX_TIMEOUT_MS)
|
|
12936
13025
|
return timeoutMs;
|
|
12937
|
-
ctx.err(
|
|
13026
|
+
ctx.err(path23, `${label} has a timeout "${raw}" above the maximum of ${WORKFLOW_MAX_TIMEOUT_MS} ms (about 24.8 days). ` + `Use a shorter duration or "none" for no timeout.`);
|
|
12938
13027
|
return;
|
|
12939
13028
|
}
|
|
12940
|
-
function parseEnumField(ctx, raw,
|
|
13029
|
+
function parseEnumField(ctx, raw, path23, label, allowed) {
|
|
12941
13030
|
if (raw === undefined)
|
|
12942
13031
|
return;
|
|
12943
13032
|
if (typeof raw === "string" && allowed.includes(raw))
|
|
12944
13033
|
return raw;
|
|
12945
|
-
ctx.err(
|
|
13034
|
+
ctx.err(path23, `${label} must be one of: ${allowed.join(" | ")} (got ${JSON.stringify(raw)}).`);
|
|
12946
13035
|
return;
|
|
12947
13036
|
}
|
|
12948
|
-
function parseLlmOverrides(ctx, raw,
|
|
13037
|
+
function parseLlmOverrides(ctx, raw, path23, label) {
|
|
12949
13038
|
if (raw === undefined)
|
|
12950
13039
|
return;
|
|
12951
13040
|
if (!isRecord(raw)) {
|
|
12952
|
-
ctx.err(
|
|
13041
|
+
ctx.err(path23, `${label} must be a mapping of LLM invocation overrides.`);
|
|
12953
13042
|
return;
|
|
12954
13043
|
}
|
|
12955
13044
|
const keys2 = [
|
|
@@ -12961,36 +13050,36 @@ function parseLlmOverrides(ctx, raw, path22, label) {
|
|
|
12961
13050
|
"enable_thinking",
|
|
12962
13051
|
"reasoning_effort"
|
|
12963
13052
|
];
|
|
12964
|
-
checkUnknownKeys(ctx, raw,
|
|
13053
|
+
checkUnknownKeys(ctx, raw, path23, keys2, label);
|
|
12965
13054
|
const result = {};
|
|
12966
13055
|
if (raw.temperature !== undefined) {
|
|
12967
13056
|
if (typeof raw.temperature === "number" && Number.isFinite(raw.temperature))
|
|
12968
13057
|
result.temperature = raw.temperature;
|
|
12969
13058
|
else
|
|
12970
|
-
ctx.err([...
|
|
13059
|
+
ctx.err([...path23, "temperature"], `${label}.temperature must be a finite number.`);
|
|
12971
13060
|
}
|
|
12972
13061
|
if (raw.max_tokens !== undefined) {
|
|
12973
13062
|
if (typeof raw.max_tokens === "number" && Number.isInteger(raw.max_tokens) && raw.max_tokens > 0) {
|
|
12974
13063
|
result.maxTokens = raw.max_tokens;
|
|
12975
13064
|
} else
|
|
12976
|
-
ctx.err([...
|
|
13065
|
+
ctx.err([...path23, "max_tokens"], `${label}.max_tokens must be a positive integer.`);
|
|
12977
13066
|
}
|
|
12978
13067
|
if (raw.supports_json_schema !== undefined) {
|
|
12979
13068
|
if (typeof raw.supports_json_schema === "boolean")
|
|
12980
13069
|
result.supportsJsonSchema = raw.supports_json_schema;
|
|
12981
13070
|
else
|
|
12982
|
-
ctx.err([...
|
|
13071
|
+
ctx.err([...path23, "supports_json_schema"], `${label}.supports_json_schema must be a boolean.`);
|
|
12983
13072
|
}
|
|
12984
13073
|
if (raw.extra_params !== undefined) {
|
|
12985
13074
|
if (!isRecord(raw.extra_params)) {
|
|
12986
|
-
ctx.err([...
|
|
13075
|
+
ctx.err([...path23, "extra_params"], `${label}.extra_params must be a JSON object.`);
|
|
12987
13076
|
} else {
|
|
12988
13077
|
const issues = validateExtraParams(raw.extra_params);
|
|
12989
13078
|
for (const issue of issues) {
|
|
12990
|
-
ctx.err([...
|
|
13079
|
+
ctx.err([...path23, "extra_params", ...issue.path], `${formatExtraParamsIssue(`${label}.extra_params`, issue)}.`);
|
|
12991
13080
|
}
|
|
12992
13081
|
if (jsonBytes(raw.extra_params) > WORKFLOW_MAX_EXTRA_PARAMS_BYTES) {
|
|
12993
|
-
ctx.err([...
|
|
13082
|
+
ctx.err([...path23, "extra_params"], `${label}.extra_params exceeds the 64 KiB resource limit.`);
|
|
12994
13083
|
}
|
|
12995
13084
|
if (issues.length === 0 && jsonBytes(raw.extra_params) <= WORKFLOW_MAX_EXTRA_PARAMS_BYTES) {
|
|
12996
13085
|
result.extraParams = raw.extra_params;
|
|
@@ -13001,38 +13090,38 @@ function parseLlmOverrides(ctx, raw, path22, label) {
|
|
|
13001
13090
|
if (typeof raw.context_length === "number" && Number.isInteger(raw.context_length) && raw.context_length > 0) {
|
|
13002
13091
|
result.contextLength = raw.context_length;
|
|
13003
13092
|
} else
|
|
13004
|
-
ctx.err([...
|
|
13093
|
+
ctx.err([...path23, "context_length"], `${label}.context_length must be a positive integer.`);
|
|
13005
13094
|
}
|
|
13006
13095
|
if (raw.enable_thinking !== undefined) {
|
|
13007
13096
|
if (typeof raw.enable_thinking === "boolean")
|
|
13008
13097
|
result.enableThinking = raw.enable_thinking;
|
|
13009
13098
|
else
|
|
13010
|
-
ctx.err([...
|
|
13099
|
+
ctx.err([...path23, "enable_thinking"], `${label}.enable_thinking must be a boolean.`);
|
|
13011
13100
|
}
|
|
13012
13101
|
if (raw.reasoning_effort !== undefined) {
|
|
13013
13102
|
if (typeof raw.reasoning_effort === "string" && raw.reasoning_effort.trim().length > 0) {
|
|
13014
13103
|
result.reasoningEffort = raw.reasoning_effort;
|
|
13015
13104
|
} else
|
|
13016
|
-
ctx.err([...
|
|
13105
|
+
ctx.err([...path23, "reasoning_effort"], `${label}.reasoning_effort must be a non-empty string.`);
|
|
13017
13106
|
}
|
|
13018
13107
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
13019
13108
|
}
|
|
13020
|
-
function parseSchemaObject(ctx, raw,
|
|
13109
|
+
function parseSchemaObject(ctx, raw, path23, label) {
|
|
13021
13110
|
if (raw === undefined)
|
|
13022
13111
|
return;
|
|
13023
13112
|
if (!isRecord(raw)) {
|
|
13024
|
-
ctx.err(
|
|
13113
|
+
ctx.err(path23, `${label} must be a JSON Schema object (e.g. { type: object, properties: { … } }).`);
|
|
13025
13114
|
return;
|
|
13026
13115
|
}
|
|
13027
13116
|
if (jsonBytes(raw) > WORKFLOW_MAX_SCHEMA_BYTES) {
|
|
13028
|
-
ctx.err(
|
|
13117
|
+
ctx.err(path23, `${label} exceeds the 256 KiB resource limit.`);
|
|
13029
13118
|
}
|
|
13030
|
-
checkSchemaDefinition(ctx, raw,
|
|
13119
|
+
checkSchemaDefinition(ctx, raw, path23, label);
|
|
13031
13120
|
return raw;
|
|
13032
13121
|
}
|
|
13033
|
-
function checkSchemaDefinition(ctx, schema,
|
|
13122
|
+
function checkSchemaDefinition(ctx, schema, path23, label) {
|
|
13034
13123
|
for (const issue of checkJsonSchemaDefinition(schema)) {
|
|
13035
|
-
const issuePath = [...
|
|
13124
|
+
const issuePath = [...path23, ...issue.path];
|
|
13036
13125
|
if (issue.kind === "unsupported") {
|
|
13037
13126
|
ctx.err(issuePath, `${label} (at ${issue.pointer}): ${issue.message}. Supported JSON Schema keywords: ` + `${JSON_SCHEMA_SUBSET_SUPPORTED_KEYWORDS}.`);
|
|
13038
13127
|
} else {
|
|
@@ -13040,15 +13129,15 @@ function checkSchemaDefinition(ctx, schema, path22, label) {
|
|
|
13040
13129
|
}
|
|
13041
13130
|
}
|
|
13042
13131
|
}
|
|
13043
|
-
function checkReferenceSyntax(ctx, text,
|
|
13132
|
+
function checkReferenceSyntax(ctx, text, path23, label) {
|
|
13044
13133
|
const result = parseReference(text);
|
|
13045
13134
|
if (!result.ok)
|
|
13046
|
-
ctx.err(
|
|
13135
|
+
ctx.err(path23, `${label}: ${result.message}`);
|
|
13047
13136
|
}
|
|
13048
|
-
function checkUnknownKeys(ctx, obj,
|
|
13137
|
+
function checkUnknownKeys(ctx, obj, path23, allowed, label) {
|
|
13049
13138
|
for (const key of Object.keys(obj)) {
|
|
13050
13139
|
if (!allowed.includes(key)) {
|
|
13051
|
-
ctx.err([...
|
|
13140
|
+
ctx.err([...path23, key], `Unknown ${label} key "${key}". Allowed keys: ${allowed.join(", ")}.`);
|
|
13052
13141
|
}
|
|
13053
13142
|
}
|
|
13054
13143
|
}
|
|
@@ -13108,7 +13197,7 @@ var init_parser = __esm(() => {
|
|
|
13108
13197
|
});
|
|
13109
13198
|
|
|
13110
13199
|
// src/workflows/source-ir/result.ts
|
|
13111
|
-
function sourceFailureResult(cause,
|
|
13200
|
+
function sourceFailureResult(cause, path23) {
|
|
13112
13201
|
if (cause instanceof WorkflowSourceFailure)
|
|
13113
13202
|
return { ok: false, errors: [cause.error] };
|
|
13114
13203
|
return {
|
|
@@ -13117,7 +13206,7 @@ function sourceFailureResult(cause, path22) {
|
|
|
13117
13206
|
{
|
|
13118
13207
|
code: "invalid-workflow-source",
|
|
13119
13208
|
message: cause instanceof Error ? cause.message : String(cause),
|
|
13120
|
-
path:
|
|
13209
|
+
path: path23,
|
|
13121
13210
|
line: 1
|
|
13122
13211
|
}
|
|
13123
13212
|
]
|
|
@@ -13768,7 +13857,7 @@ var init_triggers = __esm(() => {
|
|
|
13768
13857
|
});
|
|
13769
13858
|
|
|
13770
13859
|
// src/workflows/source-ir/compile.ts
|
|
13771
|
-
import
|
|
13860
|
+
import path23 from "node:path";
|
|
13772
13861
|
function compileGithubWorkflowSource(source, options) {
|
|
13773
13862
|
try {
|
|
13774
13863
|
return {
|
|
@@ -13852,7 +13941,7 @@ function compileMarkdownWorkflowSource(source, options) {
|
|
|
13852
13941
|
}
|
|
13853
13942
|
}
|
|
13854
13943
|
function compileWorkflowSource(source, options) {
|
|
13855
|
-
const extension =
|
|
13944
|
+
const extension = path23.extname(options.path).toLowerCase();
|
|
13856
13945
|
if (extension === ".md")
|
|
13857
13946
|
return compileMarkdownWorkflowSource(source, options);
|
|
13858
13947
|
if (extension === ".yml")
|
|
@@ -13930,7 +14019,7 @@ function markdownName(source, filePath) {
|
|
|
13930
14019
|
const title = body.match(/^#\s+(.+?)\s*$/m)?.[1]?.trim();
|
|
13931
14020
|
if (title)
|
|
13932
14021
|
return title;
|
|
13933
|
-
return
|
|
14022
|
+
return path23.basename(filePath, path23.extname(filePath));
|
|
13934
14023
|
}
|
|
13935
14024
|
function wholeSourceSpan2(source, filePath) {
|
|
13936
14025
|
return { path: filePath, start: 1, end: Math.max(1, source.split(/\r?\n/).length) };
|
|
@@ -68660,13 +68749,13 @@ function flattenForText(value, path, lines) {
|
|
|
68660
68749
|
}
|
|
68661
68750
|
|
|
68662
68751
|
// src/output/html-render.ts
|
|
68663
|
-
import
|
|
68752
|
+
import path6 from "node:path";
|
|
68664
68753
|
// src/runtime.ts
|
|
68665
68754
|
import { spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "node:child_process";
|
|
68666
68755
|
init_common();
|
|
68667
68756
|
import { createWriteStream, statfsSync } from "node:fs";
|
|
68668
68757
|
import { createRequire as createRequire2 } from "node:module";
|
|
68669
|
-
import
|
|
68758
|
+
import path5 from "node:path";
|
|
68670
68759
|
import { Readable } from "node:stream";
|
|
68671
68760
|
import { pipeline } from "node:stream/promises";
|
|
68672
68761
|
import { fileURLToPath } from "node:url";
|
|
@@ -68752,11 +68841,11 @@ async function writeResponseToFileCapped(filePath, res, options) {
|
|
|
68752
68841
|
}
|
|
68753
68842
|
}
|
|
68754
68843
|
function getDirname(importMetaUrl) {
|
|
68755
|
-
return
|
|
68844
|
+
return path5.dirname(fileURLToPath(importMetaUrl));
|
|
68756
68845
|
}
|
|
68757
|
-
function statfsType(
|
|
68846
|
+
function statfsType(path6) {
|
|
68758
68847
|
try {
|
|
68759
|
-
return statfsSync(
|
|
68848
|
+
return statfsSync(path6).type;
|
|
68760
68849
|
} catch {
|
|
68761
68850
|
return;
|
|
68762
68851
|
}
|
|
@@ -68783,7 +68872,7 @@ function toBuffer(data) {
|
|
|
68783
68872
|
}
|
|
68784
68873
|
|
|
68785
68874
|
// src/output/html-render.ts
|
|
68786
|
-
var TEMPLATES_DIR =
|
|
68875
|
+
var TEMPLATES_DIR = path6.join(getDirname(import.meta.url), "../assets/templates/html");
|
|
68787
68876
|
|
|
68788
68877
|
// src/output/command-registry.ts
|
|
68789
68878
|
function createCommandRegistry() {
|
|
@@ -69368,6 +69457,7 @@ var PASSTHROUGH_COMMANDS = [
|
|
|
69368
69457
|
"task-run",
|
|
69369
69458
|
"task-sync",
|
|
69370
69459
|
"task-sync-dry-run",
|
|
69460
|
+
"task-validate",
|
|
69371
69461
|
"update",
|
|
69372
69462
|
"upgrade",
|
|
69373
69463
|
"workflow-abandon",
|
|
@@ -69953,16 +70043,16 @@ function formatConfigPlain(r) {
|
|
|
69953
70043
|
const lines = [];
|
|
69954
70044
|
const walk = (obj, prefix) => {
|
|
69955
70045
|
for (const [k, v] of Object.entries(obj)) {
|
|
69956
|
-
const
|
|
70046
|
+
const path7 = prefix ? `${prefix}.${k}` : k;
|
|
69957
70047
|
if (v === null || v === undefined) {
|
|
69958
|
-
lines.push(`${
|
|
70048
|
+
lines.push(`${path7}=`);
|
|
69959
70049
|
} else if (Array.isArray(v)) {
|
|
69960
|
-
lines.push(`${
|
|
70050
|
+
lines.push(`${path7}=${JSON.stringify(v)}`);
|
|
69961
70051
|
} else if (typeof v === "object") {
|
|
69962
|
-
walk(v,
|
|
70052
|
+
walk(v, path7);
|
|
69963
70053
|
} else {
|
|
69964
|
-
const rendered = typeof v === "string" && /^registries\.\d+\.url$/u.test(
|
|
69965
|
-
lines.push(`${
|
|
70054
|
+
const rendered = typeof v === "string" && /^registries\.\d+\.url$/u.test(path7) ? formatRegistryUrl(v) : String(v);
|
|
70055
|
+
lines.push(`${path7}=${rendered}`);
|
|
69966
70056
|
}
|
|
69967
70057
|
}
|
|
69968
70058
|
};
|
|
@@ -71508,27 +71598,7 @@ var GLOBAL_OUTPUT_ARGS2 = {
|
|
|
71508
71598
|
init_errors();
|
|
71509
71599
|
|
|
71510
71600
|
// scripts/akm-migrate/help.txt
|
|
71511
|
-
var help_default =
|
|
71512
|
-
|
|
71513
|
-
The one migration tool for an akm installation. Every historical shape akm
|
|
71514
|
-
has ever written lives here; the CLI proper reads only current schemas.
|
|
71515
|
-
\`status\` and \`apply\` run every step, in order, and print one combined JSON
|
|
71516
|
-
plan (exit 1 when any step is blocked):
|
|
71517
|
-
|
|
71518
|
-
1. legacy config \`extraParams\` keys lifted onto first-class engine fields
|
|
71519
|
-
2. pending state.db migrations, historical-destructive ones included,
|
|
71520
|
-
with a verified sibling safety copy (the only path that admits them)
|
|
71521
|
-
3. task-v2 files to task v3, then task-v3 files to task source v4
|
|
71522
|
-
4. superseded pre-0.9.0 \`.akm\` residue and stale filesystem transactions
|
|
71523
|
-
|
|
71524
|
-
\`akm migrate status|apply\` wraps this executable; \`akm upgrade\` runs
|
|
71525
|
-
\`apply\` after its install step, so an image that ships akm can put either
|
|
71526
|
-
in its entrypoint (a current installation is a no-op).
|
|
71527
|
-
|
|
71528
|
-
Commands:
|
|
71529
|
-
status Inspect every pending migration without changing anything.
|
|
71530
|
-
apply [--dry-run] Back up and apply every pending migration.
|
|
71531
|
-
`;
|
|
71601
|
+
var help_default = "Usage: akm-migrate <command> [options]\n\nThe one migration tool for an akm installation. Every historical shape akm\nhas ever written lives here; the CLI proper reads only current schemas.\n`status` and `apply` run every step, in order, and print one combined JSON\nplan (exit 1 when any step is blocked):\n\n 1. legacy config `extraParams` keys lifted onto first-class engine fields\n 2. pending state.db migrations, historical-destructive ones included,\n with a verified sibling safety copy (the only path that admits them)\n 3. task-v2 files to task v3, then task-v3 files to task source v4\n 4. superseded pre-0.9.0 `.akm` residue and stale filesystem transactions\n 5. live `.akm` writers relocated to `$STATE`/`$CACHE`, for every local\n bundle (distill-rejected, eval-cases, measurement verdicts, and stale\n improve-pipeline locks — a lock a live run still holds is left alone)\n\n`akm migrate status|apply` wraps this executable; `akm upgrade` runs\n`apply` after its install step, so an image that ships akm can put either\nin its entrypoint (a current installation is a no-op).\n\nCommands:\n status Inspect every pending migration without changing anything.\n apply [--dry-run] Back up and apply every pending migration.\n";
|
|
71532
71602
|
|
|
71533
71603
|
// scripts/akm-migrate/run-migrate.ts
|
|
71534
71604
|
init_common();
|
|
@@ -71540,14 +71610,14 @@ init_extra_params();
|
|
|
71540
71610
|
|
|
71541
71611
|
// src/core/config/config-io.ts
|
|
71542
71612
|
import fs4 from "node:fs";
|
|
71543
|
-
import
|
|
71613
|
+
import path9 from "node:path";
|
|
71544
71614
|
init_common();
|
|
71545
71615
|
init_errors();
|
|
71546
71616
|
|
|
71547
71617
|
// src/core/file-lock.ts
|
|
71548
71618
|
import { randomUUID } from "node:crypto";
|
|
71549
71619
|
import fs3 from "node:fs";
|
|
71550
|
-
import
|
|
71620
|
+
import path8 from "node:path";
|
|
71551
71621
|
|
|
71552
71622
|
// src/storage/database.ts
|
|
71553
71623
|
import { createRequire as createRequire3 } from "node:module";
|
|
@@ -71571,12 +71641,12 @@ function selectProvider() {
|
|
|
71571
71641
|
}
|
|
71572
71642
|
return provider;
|
|
71573
71643
|
}
|
|
71574
|
-
function openDatabase(
|
|
71575
|
-
return selectProvider().open(
|
|
71644
|
+
function openDatabase(path8, opts) {
|
|
71645
|
+
return selectProvider().open(path8, opts);
|
|
71576
71646
|
}
|
|
71577
|
-
function openBunDatabase(
|
|
71647
|
+
function openBunDatabase(path8, opts) {
|
|
71578
71648
|
const { Database: BunDatabase } = loadBunSqlite();
|
|
71579
|
-
const db = opts ? new BunDatabase(
|
|
71649
|
+
const db = opts ? new BunDatabase(path8, bunOptions(opts)) : new BunDatabase(path8);
|
|
71580
71650
|
return db;
|
|
71581
71651
|
}
|
|
71582
71652
|
function bunOptions(opts) {
|
|
@@ -71632,7 +71702,7 @@ function loadBetterSqlite3() {
|
|
|
71632
71702
|
}
|
|
71633
71703
|
return betterSqlite3Ctor;
|
|
71634
71704
|
}
|
|
71635
|
-
function openNodeDatabase(
|
|
71705
|
+
function openNodeDatabase(path8, opts) {
|
|
71636
71706
|
const BetterSqlite3 = loadBetterSqlite3();
|
|
71637
71707
|
const options = {};
|
|
71638
71708
|
if (opts?.readonly !== undefined)
|
|
@@ -71641,7 +71711,7 @@ function openNodeDatabase(path7, opts) {
|
|
|
71641
71711
|
options.fileMustExist = true;
|
|
71642
71712
|
let db;
|
|
71643
71713
|
try {
|
|
71644
|
-
db = opts ? new BetterSqlite3(
|
|
71714
|
+
db = opts ? new BetterSqlite3(path8, options) : new BetterSqlite3(path8);
|
|
71645
71715
|
} catch (err) {
|
|
71646
71716
|
const raw = err instanceof Error ? err.message : String(err);
|
|
71647
71717
|
const remedy = abiMismatchRemedy(raw);
|
|
@@ -71689,7 +71759,7 @@ function sameIdentity(left, right) {
|
|
|
71689
71759
|
return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs;
|
|
71690
71760
|
}
|
|
71691
71761
|
function operationMutexPath(lockPath) {
|
|
71692
|
-
return
|
|
71762
|
+
return path8.join(path8.dirname(lockPath), `.${path8.basename(lockPath)}.operations.sensitive`);
|
|
71693
71763
|
}
|
|
71694
71764
|
function withLockOperationMutex(lockPath, run) {
|
|
71695
71765
|
const db = openDatabase(operationMutexPath(lockPath));
|
|
@@ -71908,14 +71978,14 @@ var MAX_CONFIG_BACKUPS = 5;
|
|
|
71908
71978
|
function backupExistingConfig(configPath, now = new Date) {
|
|
71909
71979
|
if (!fs4.existsSync(configPath))
|
|
71910
71980
|
return;
|
|
71911
|
-
const backupDir =
|
|
71981
|
+
const backupDir = path9.join(getCacheDir(), "config-backups");
|
|
71912
71982
|
fs4.mkdirSync(backupDir, { recursive: true, mode: 448 });
|
|
71913
71983
|
fs4.chmodSync(backupDir, 448);
|
|
71914
71984
|
const timestamp = now.toISOString().replace(/[.:]/g, "-");
|
|
71915
71985
|
let sequence = 0;
|
|
71916
71986
|
let timestamped;
|
|
71917
71987
|
while (true) {
|
|
71918
|
-
timestamped =
|
|
71988
|
+
timestamped = path9.join(backupDir, `config-${timestamp}${sequence === 0 ? "" : `-${sequence}`}.json`);
|
|
71919
71989
|
try {
|
|
71920
71990
|
fs4.copyFileSync(configPath, timestamped, fs4.constants.COPYFILE_EXCL);
|
|
71921
71991
|
break;
|
|
@@ -71925,7 +71995,7 @@ function backupExistingConfig(configPath, now = new Date) {
|
|
|
71925
71995
|
sequence++;
|
|
71926
71996
|
}
|
|
71927
71997
|
}
|
|
71928
|
-
const latest =
|
|
71998
|
+
const latest = path9.join(backupDir, "config.latest.json");
|
|
71929
71999
|
fs4.copyFileSync(configPath, latest);
|
|
71930
72000
|
fs4.chmodSync(timestamped, 384);
|
|
71931
72001
|
fs4.chmodSync(latest, 384);
|
|
@@ -71946,7 +72016,7 @@ function pruneToNewest(dir, keep, select) {
|
|
|
71946
72016
|
return;
|
|
71947
72017
|
}
|
|
71948
72018
|
const candidates = entries.filter(select).map((entry) => {
|
|
71949
|
-
const full =
|
|
72019
|
+
const full = path9.join(dir, entry.name);
|
|
71950
72020
|
let mtime = 0;
|
|
71951
72021
|
try {
|
|
71952
72022
|
mtime = fs4.statSync(full).mtimeMs;
|
|
@@ -71960,7 +72030,7 @@ function pruneToNewest(dir, keep, select) {
|
|
|
71960
72030
|
}
|
|
71961
72031
|
}
|
|
71962
72032
|
function getConfigLockPath() {
|
|
71963
|
-
return
|
|
72033
|
+
return path9.join(getConfigDir(), "config.json.lck");
|
|
71964
72034
|
}
|
|
71965
72035
|
var CONFIG_LOCK_MAX_RETRIES = 40;
|
|
71966
72036
|
var CONFIG_LOCK_RETRY_DELAY_MS = 50;
|
|
@@ -71970,7 +72040,7 @@ function sleepSyncMs(ms) {
|
|
|
71970
72040
|
function acquireConfigLock() {
|
|
71971
72041
|
const lockPath = getConfigLockPath();
|
|
71972
72042
|
try {
|
|
71973
|
-
fs4.mkdirSync(
|
|
72043
|
+
fs4.mkdirSync(path9.dirname(lockPath), { recursive: true });
|
|
71974
72044
|
} catch {}
|
|
71975
72045
|
for (let attempt = 0;attempt < CONFIG_LOCK_MAX_RETRIES; attempt++) {
|
|
71976
72046
|
try {
|
|
@@ -72475,8 +72545,8 @@ function getErrorMap() {
|
|
|
72475
72545
|
}
|
|
72476
72546
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
72477
72547
|
var makeIssue = (params) => {
|
|
72478
|
-
const { data, path:
|
|
72479
|
-
const fullPath = [...
|
|
72548
|
+
const { data, path: path10, errorMaps, issueData } = params;
|
|
72549
|
+
const fullPath = [...path10, ...issueData.path || []];
|
|
72480
72550
|
const fullIssue = {
|
|
72481
72551
|
...issueData,
|
|
72482
72552
|
path: fullPath
|
|
@@ -72588,11 +72658,11 @@ var errorUtil;
|
|
|
72588
72658
|
|
|
72589
72659
|
// node_modules/zod/v3/types.js
|
|
72590
72660
|
class ParseInputLazyPath {
|
|
72591
|
-
constructor(parent, value,
|
|
72661
|
+
constructor(parent, value, path10, key) {
|
|
72592
72662
|
this._cachedPath = [];
|
|
72593
72663
|
this.parent = parent;
|
|
72594
72664
|
this.data = value;
|
|
72595
|
-
this._path =
|
|
72665
|
+
this._path = path10;
|
|
72596
72666
|
this._key = key;
|
|
72597
72667
|
}
|
|
72598
72668
|
get path() {
|
|
@@ -76100,6 +76170,7 @@ var LlmEngineSchema = exports_external.object({
|
|
|
76100
76170
|
endpoint: chatCompletionsEndpoint,
|
|
76101
76171
|
model: nonEmptyString,
|
|
76102
76172
|
apiKey: exports_external.string().regex(ENV_REFERENCE_PATTERN, `apiKey must be $VAR or \${VAR}`).optional(),
|
|
76173
|
+
apiKeyFile: nonEmptyString.optional(),
|
|
76103
76174
|
temperature: exports_external.number().finite().optional(),
|
|
76104
76175
|
maxTokens: positiveInt.optional(),
|
|
76105
76176
|
timeoutMs: timeoutMsField,
|
|
@@ -76113,6 +76184,13 @@ var LlmEngineSchema = exports_external.object({
|
|
|
76113
76184
|
if (key in value)
|
|
76114
76185
|
ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path: [key], message: `${key} is not valid on an LLM engine` });
|
|
76115
76186
|
}
|
|
76187
|
+
if (value.apiKey !== undefined && value.apiKeyFile !== undefined) {
|
|
76188
|
+
ctx.addIssue({
|
|
76189
|
+
code: exports_external.ZodIssueCode.custom,
|
|
76190
|
+
path: ["apiKeyFile"],
|
|
76191
|
+
message: "apiKey and apiKeyFile cannot both be set"
|
|
76192
|
+
});
|
|
76193
|
+
}
|
|
76116
76194
|
});
|
|
76117
76195
|
var AgentEngineSchema = exports_external.object({
|
|
76118
76196
|
kind: exports_external.literal("agent"),
|
|
@@ -76130,6 +76208,7 @@ var AgentEngineSchema = exports_external.object({
|
|
|
76130
76208
|
"provider",
|
|
76131
76209
|
"endpoint",
|
|
76132
76210
|
"apiKey",
|
|
76211
|
+
"apiKeyFile",
|
|
76133
76212
|
"temperature",
|
|
76134
76213
|
"maxTokens",
|
|
76135
76214
|
"concurrency",
|
|
@@ -76867,7 +76946,7 @@ var AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
|
|
|
76867
76946
|
// src/core/config/config-sources.ts
|
|
76868
76947
|
init_errors();
|
|
76869
76948
|
import { createHash } from "node:crypto";
|
|
76870
|
-
import
|
|
76949
|
+
import path10 from "node:path";
|
|
76871
76950
|
function bundleComponentConfig(bundle) {
|
|
76872
76951
|
if (!bundle?.components)
|
|
76873
76952
|
return;
|
|
@@ -76878,7 +76957,20 @@ function bundleComponentConfig(bundle) {
|
|
|
76878
76957
|
return components[0];
|
|
76879
76958
|
}
|
|
76880
76959
|
function bundleContentRoot(entryPath, componentRoot) {
|
|
76881
|
-
return
|
|
76960
|
+
return path10.resolve(entryPath, componentRoot ?? ".");
|
|
76961
|
+
}
|
|
76962
|
+
function bundleContentRoots(config) {
|
|
76963
|
+
const bundles = config.bundles ?? {};
|
|
76964
|
+
const out = [];
|
|
76965
|
+
for (const [id, entry] of Object.entries(bundles)) {
|
|
76966
|
+
if (typeof entry.path !== "string" || entry.path.length === 0)
|
|
76967
|
+
continue;
|
|
76968
|
+
out.push({ id, contentRoot: bundleContentRoot(entry.path, bundleComponentConfig(entry)?.root) });
|
|
76969
|
+
}
|
|
76970
|
+
return out;
|
|
76971
|
+
}
|
|
76972
|
+
function bundleKeyForContentRoot(config, resolvedContentRoot) {
|
|
76973
|
+
return bundleContentRoots(config).find((entry) => entry.contentRoot === resolvedContentRoot)?.id;
|
|
76882
76974
|
}
|
|
76883
76975
|
function bundlesToSourceEntries(config) {
|
|
76884
76976
|
const bundles = config.bundles;
|
|
@@ -77191,7 +77283,7 @@ init_paths();
|
|
|
77191
77283
|
// src/core/state-db.ts
|
|
77192
77284
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
77193
77285
|
import fs9 from "node:fs";
|
|
77194
|
-
import
|
|
77286
|
+
import path13 from "node:path";
|
|
77195
77287
|
|
|
77196
77288
|
// src/storage/engines/sqlite-migrations.ts
|
|
77197
77289
|
function assertMigrationRegistry(migrations) {
|
|
@@ -77360,7 +77452,7 @@ function withImmediateWriteLock(db, fn) {
|
|
|
77360
77452
|
|
|
77361
77453
|
// src/storage/managed-db.ts
|
|
77362
77454
|
import fs7 from "node:fs";
|
|
77363
|
-
import
|
|
77455
|
+
import path11 from "node:path";
|
|
77364
77456
|
|
|
77365
77457
|
// src/storage/sqlite-pragmas.ts
|
|
77366
77458
|
init_warn();
|
|
@@ -77434,7 +77526,7 @@ function warnNetworkFallbackOnce(dataDir) {
|
|
|
77434
77526
|
|
|
77435
77527
|
// src/storage/managed-db.ts
|
|
77436
77528
|
function openManagedDatabase(spec) {
|
|
77437
|
-
const dir =
|
|
77529
|
+
const dir = path11.dirname(spec.path);
|
|
77438
77530
|
if (spec.create !== false && !fs7.existsSync(dir)) {
|
|
77439
77531
|
fs7.mkdirSync(dir, { recursive: true });
|
|
77440
77532
|
}
|
|
@@ -77472,13 +77564,13 @@ function withManagedDb(open, fn, opts) {
|
|
|
77472
77564
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
77473
77565
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
77474
77566
|
import fs8 from "node:fs";
|
|
77475
|
-
import
|
|
77567
|
+
import path12 from "node:path";
|
|
77476
77568
|
init_errors();
|
|
77477
77569
|
init_paths();
|
|
77478
77570
|
var heldBarrierContext = new AsyncLocalStorage;
|
|
77479
77571
|
function tryAcquireMaintenanceBarrier() {
|
|
77480
77572
|
const lockPath = getMaintenanceBarrierPath();
|
|
77481
|
-
fs8.mkdirSync(
|
|
77573
|
+
fs8.mkdirSync(path12.dirname(lockPath), { recursive: true });
|
|
77482
77574
|
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
77483
77575
|
const ownership = tryAcquireLockSync(lockPath, createLockPayload({ purpose: "maintenance-start" }));
|
|
77484
77576
|
if (ownership) {
|
|
@@ -77529,9 +77621,9 @@ function withMaintenanceStartBarrierSyncWait(run) {
|
|
|
77529
77621
|
}
|
|
77530
77622
|
function acquireMaintenanceActivitySync(name) {
|
|
77531
77623
|
return withMaintenanceStartBarrierSyncWait(() => {
|
|
77532
|
-
const directory =
|
|
77624
|
+
const directory = path12.join(path12.dirname(getMaintenanceBarrierPath()), "maintenance-activities");
|
|
77533
77625
|
fs8.mkdirSync(directory, { recursive: true, mode: 448 });
|
|
77534
|
-
const lockPath =
|
|
77626
|
+
const lockPath = path12.join(directory, `${name}-${process.pid}-${randomUUID2()}.lock`);
|
|
77535
77627
|
const ownership = tryAcquireLockSync(lockPath, createLockPayload({ purpose: name }));
|
|
77536
77628
|
if (!ownership) {
|
|
77537
77629
|
throw new ConfigError(`Could not register AKM maintenance activity at ${lockPath}.`, "INVALID_CONFIG_FILE");
|
|
@@ -78297,7 +78389,7 @@ function runMigrations2(db, options) {
|
|
|
78297
78389
|
|
|
78298
78390
|
// src/core/state-db.ts
|
|
78299
78391
|
function getStateDbPath() {
|
|
78300
|
-
return
|
|
78392
|
+
return path13.join(getDataDir(), "state.db");
|
|
78301
78393
|
}
|
|
78302
78394
|
function safetyCopyTimestamp() {
|
|
78303
78395
|
return new Date().toISOString().replaceAll(/[^0-9]/g, "");
|
|
@@ -78482,7 +78574,7 @@ function createHistoricalStateSafetyCopy(source, migrationId) {
|
|
|
78482
78574
|
fs9.fchmodSync(reservation.fd, finalMode);
|
|
78483
78575
|
fs9.fsyncSync(reservation.fd);
|
|
78484
78576
|
assertOwnedFileReservation(reservation, "Reserved state.db safety copy");
|
|
78485
|
-
fsyncDirectory(
|
|
78577
|
+
fsyncDirectory(path13.dirname(reservation.path));
|
|
78486
78578
|
closeFileIdentity(reservation);
|
|
78487
78579
|
return reservation.path;
|
|
78488
78580
|
} catch (error) {
|
|
@@ -78500,11 +78592,11 @@ function openStateDatabase(dbPath, options) {
|
|
|
78500
78592
|
if (resolvedPath === ":memory:") {
|
|
78501
78593
|
return openManagedDatabase({
|
|
78502
78594
|
path: resolvedPath,
|
|
78503
|
-
pragmas: { dataDir:
|
|
78595
|
+
pragmas: { dataDir: path13.dirname(resolvedPath) },
|
|
78504
78596
|
init: (db) => runMigrations2(db, { freshDatabase: true })
|
|
78505
78597
|
});
|
|
78506
78598
|
}
|
|
78507
|
-
const isCanonical =
|
|
78599
|
+
const isCanonical = path13.resolve(resolvedPath) === path13.resolve(canonicalPath);
|
|
78508
78600
|
const releaseActivity = isCanonical ? acquireMaintenanceActivitySync("state-db") : undefined;
|
|
78509
78601
|
let freshReservation;
|
|
78510
78602
|
let existingSource;
|
|
@@ -78512,7 +78604,7 @@ function openStateDatabase(dbPath, options) {
|
|
|
78512
78604
|
let existingUnversionedDatabase = false;
|
|
78513
78605
|
let stateSafetyCopyCreated = false;
|
|
78514
78606
|
try {
|
|
78515
|
-
fs9.mkdirSync(
|
|
78607
|
+
fs9.mkdirSync(path13.dirname(resolvedPath), { recursive: true });
|
|
78516
78608
|
freshReservation = reserveFreshStateDatabase(resolvedPath);
|
|
78517
78609
|
if (!freshReservation) {
|
|
78518
78610
|
existingSource = openExistingStateDatabaseSource(resolvedPath);
|
|
@@ -78533,7 +78625,7 @@ function openStateDatabase(dbPath, options) {
|
|
|
78533
78625
|
const boundSource = existingSource;
|
|
78534
78626
|
openedDb = openManagedDatabase({
|
|
78535
78627
|
path: boundSource ? sqliteBoundFilePath(boundSource) : resolvedPath,
|
|
78536
|
-
pragmas: { dataDir:
|
|
78628
|
+
pragmas: { dataDir: path13.dirname(resolvedPath) },
|
|
78537
78629
|
init: (db2) => {
|
|
78538
78630
|
runMigrations2(db2, {
|
|
78539
78631
|
freshDatabase: !!freshReservation,
|
|
@@ -78734,7 +78826,7 @@ function applyConfigExtraParamsLift(configPath) {
|
|
|
78734
78826
|
|
|
78735
78827
|
// scripts/akm-migrate/migrate/dead-residue.ts
|
|
78736
78828
|
import fs10 from "node:fs";
|
|
78737
|
-
import
|
|
78829
|
+
import path14 from "node:path";
|
|
78738
78830
|
var DEAD_RESIDUE_PATHS = [
|
|
78739
78831
|
{ name: "proposals", reason: "superseded by the `proposals` table in $DATA/state.db (0.9.0)" },
|
|
78740
78832
|
{ prefix: "runs.archived-", reason: "orphaned archive of a directory that no longer exists" },
|
|
@@ -78756,7 +78848,7 @@ function dirSizeBytes(target) {
|
|
|
78756
78848
|
return 0;
|
|
78757
78849
|
}
|
|
78758
78850
|
for (const entry of entries) {
|
|
78759
|
-
const entryPath =
|
|
78851
|
+
const entryPath = path14.join(target, entry.name);
|
|
78760
78852
|
if (entry.isDirectory()) {
|
|
78761
78853
|
total += dirSizeBytes(entryPath);
|
|
78762
78854
|
} else if (entry.isFile()) {
|
|
@@ -78772,7 +78864,7 @@ function sizeOf(target) {
|
|
|
78772
78864
|
return st.isDirectory() ? dirSizeBytes(target) : st.size;
|
|
78773
78865
|
}
|
|
78774
78866
|
function findDeadResidueEntries(stashDir) {
|
|
78775
|
-
const akmDir =
|
|
78867
|
+
const akmDir = path14.join(stashDir, ".akm");
|
|
78776
78868
|
let names;
|
|
78777
78869
|
try {
|
|
78778
78870
|
names = fs10.readdirSync(akmDir);
|
|
@@ -78785,14 +78877,14 @@ function findDeadResidueEntries(stashDir) {
|
|
|
78785
78877
|
for (const name of matches) {
|
|
78786
78878
|
if (!names.includes(name))
|
|
78787
78879
|
continue;
|
|
78788
|
-
const absolutePath =
|
|
78880
|
+
const absolutePath = path14.join(akmDir, name);
|
|
78789
78881
|
let sizeBytes;
|
|
78790
78882
|
try {
|
|
78791
78883
|
sizeBytes = sizeOf(absolutePath);
|
|
78792
78884
|
} catch {
|
|
78793
78885
|
continue;
|
|
78794
78886
|
}
|
|
78795
|
-
found.push({ relativePath:
|
|
78887
|
+
found.push({ relativePath: path14.join(".akm", name), absolutePath, sizeBytes, reason: spec.reason });
|
|
78796
78888
|
}
|
|
78797
78889
|
}
|
|
78798
78890
|
return found;
|
|
@@ -78819,7 +78911,7 @@ init_paths();
|
|
|
78819
78911
|
init_warn();
|
|
78820
78912
|
import { createHash as createHash2, randomUUID as randomUUID4 } from "node:crypto";
|
|
78821
78913
|
import fs11 from "node:fs";
|
|
78822
|
-
import
|
|
78914
|
+
import path15 from "node:path";
|
|
78823
78915
|
var kinds = new Map;
|
|
78824
78916
|
function registerTxnKind(kind, handler3) {
|
|
78825
78917
|
kinds.set(kind, handler3);
|
|
@@ -78863,18 +78955,18 @@ function writeTxnFileDurably(filePath, content, mode = 384) {
|
|
|
78863
78955
|
fs11.writeFileSync(tempPath, content, { mode });
|
|
78864
78956
|
fsyncTxnFile(tempPath);
|
|
78865
78957
|
fs11.renameSync(tempPath, filePath);
|
|
78866
|
-
fsyncTxnDir(
|
|
78958
|
+
fsyncTxnDir(path15.dirname(filePath));
|
|
78867
78959
|
}
|
|
78868
78960
|
function canonicalTxnRoot(root) {
|
|
78869
78961
|
try {
|
|
78870
|
-
return fs11.realpathSync(
|
|
78962
|
+
return fs11.realpathSync(path15.resolve(root));
|
|
78871
78963
|
} catch {
|
|
78872
|
-
return
|
|
78964
|
+
return path15.resolve(root);
|
|
78873
78965
|
}
|
|
78874
78966
|
}
|
|
78875
78967
|
function txnNamespaceDir(root) {
|
|
78876
78968
|
const ns = txnHash(canonicalTxnRoot(root)).slice(0, 24);
|
|
78877
|
-
return
|
|
78969
|
+
return path15.join(getDataDir(), "txn", ns);
|
|
78878
78970
|
}
|
|
78879
78971
|
function advanceTxn(txn, phase) {
|
|
78880
78972
|
const handler3 = requireKind(txn.journal.kind);
|
|
@@ -78890,7 +78982,7 @@ function cleanupTxn(dir) {
|
|
|
78890
78982
|
try {
|
|
78891
78983
|
fs11.rmSync(dir, { recursive: true, force: true });
|
|
78892
78984
|
try {
|
|
78893
|
-
fs11.rmdirSync(
|
|
78985
|
+
fs11.rmdirSync(path15.dirname(dir));
|
|
78894
78986
|
} catch {}
|
|
78895
78987
|
return null;
|
|
78896
78988
|
} catch (error) {
|
|
@@ -78912,8 +79004,8 @@ function sweepJournallessTxnDir(dir, graceMs = TXN_SWEEP_GRACE_MS) {
|
|
|
78912
79004
|
}
|
|
78913
79005
|
}
|
|
78914
79006
|
function isWithinTxnRoot(candidate, root) {
|
|
78915
|
-
const rel =
|
|
78916
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
79007
|
+
const rel = path15.relative(path15.resolve(root), path15.resolve(candidate));
|
|
79008
|
+
return rel !== "" && !rel.startsWith("..") && !path15.isAbsolute(rel);
|
|
78917
79009
|
}
|
|
78918
79010
|
function readJournal(journalPath) {
|
|
78919
79011
|
let journal;
|
|
@@ -78954,8 +79046,8 @@ async function recoverTxnsForRoot(root, filter) {
|
|
|
78954
79046
|
for (const entry of fs11.readdirSync(nsDir, { withFileTypes: true })) {
|
|
78955
79047
|
if (!entry.isDirectory())
|
|
78956
79048
|
continue;
|
|
78957
|
-
const dir =
|
|
78958
|
-
const journalPath =
|
|
79049
|
+
const dir = path15.join(nsDir, entry.name);
|
|
79050
|
+
const journalPath = path15.join(dir, "journal.json");
|
|
78959
79051
|
if (!fs11.existsSync(journalPath)) {
|
|
78960
79052
|
sweepJournallessTxnDir(dir);
|
|
78961
79053
|
continue;
|
|
@@ -78984,7 +79076,7 @@ async function recoverTxnsForRoot(root, filter) {
|
|
|
78984
79076
|
return recovered;
|
|
78985
79077
|
}
|
|
78986
79078
|
function listTxnJournalsTolerant(predicate) {
|
|
78987
|
-
const home =
|
|
79079
|
+
const home = path15.join(getDataDir(), "txn");
|
|
78988
79080
|
const matches = [];
|
|
78989
79081
|
const unreadableMtimes = [];
|
|
78990
79082
|
if (!fs11.existsSync(home))
|
|
@@ -78992,11 +79084,11 @@ function listTxnJournalsTolerant(predicate) {
|
|
|
78992
79084
|
for (const ns of fs11.readdirSync(home, { withFileTypes: true })) {
|
|
78993
79085
|
if (!ns.isDirectory())
|
|
78994
79086
|
continue;
|
|
78995
|
-
const nsDir =
|
|
79087
|
+
const nsDir = path15.join(home, ns.name);
|
|
78996
79088
|
for (const entry of fs11.readdirSync(nsDir, { withFileTypes: true })) {
|
|
78997
79089
|
if (!entry.isDirectory())
|
|
78998
79090
|
continue;
|
|
78999
|
-
const journalPath =
|
|
79091
|
+
const journalPath = path15.join(nsDir, entry.name, "journal.json");
|
|
79000
79092
|
let mtimeMs;
|
|
79001
79093
|
try {
|
|
79002
79094
|
mtimeMs = fs11.statSync(journalPath).mtimeMs;
|
|
@@ -79025,7 +79117,7 @@ import path60 from "node:path";
|
|
|
79025
79117
|
init_frontmatter();
|
|
79026
79118
|
init_common();
|
|
79027
79119
|
import fs12 from "node:fs";
|
|
79028
|
-
import
|
|
79120
|
+
import path17 from "node:path";
|
|
79029
79121
|
|
|
79030
79122
|
// src/core/adapter/adapters/shared.ts
|
|
79031
79123
|
init_frontmatter();
|
|
@@ -79334,10 +79426,10 @@ var agentSkillsAdapter = {
|
|
|
79334
79426
|
recognize,
|
|
79335
79427
|
validate,
|
|
79336
79428
|
readCandidates(c, conceptId) {
|
|
79337
|
-
return [{ path:
|
|
79429
|
+
return [{ path: path17.join(c.root, conceptId, SKILL_MANIFEST), conceptId }];
|
|
79338
79430
|
},
|
|
79339
79431
|
placeNew(c, conceptId) {
|
|
79340
|
-
return
|
|
79432
|
+
return path17.join(c.root, conceptId, SKILL_MANIFEST);
|
|
79341
79433
|
},
|
|
79342
79434
|
looksLikeRoot(root) {
|
|
79343
79435
|
let entries;
|
|
@@ -79350,7 +79442,7 @@ var agentSkillsAdapter = {
|
|
|
79350
79442
|
if (!entry.isDirectory())
|
|
79351
79443
|
return false;
|
|
79352
79444
|
try {
|
|
79353
|
-
return fs12.existsSync(
|
|
79445
|
+
return fs12.existsSync(path17.join(root, entry.name, SKILL_MANIFEST));
|
|
79354
79446
|
} catch {
|
|
79355
79447
|
return false;
|
|
79356
79448
|
}
|
|
@@ -79363,66 +79455,66 @@ init_metadata();
|
|
|
79363
79455
|
init_asset_placement();
|
|
79364
79456
|
init_frontmatter();
|
|
79365
79457
|
import fs16 from "node:fs";
|
|
79366
|
-
import
|
|
79458
|
+
import path25 from "node:path";
|
|
79367
79459
|
|
|
79368
79460
|
// src/core/adapter/execution-source.ts
|
|
79369
79461
|
init_dist();
|
|
79370
79462
|
import { createHash as createHash4 } from "node:crypto";
|
|
79371
79463
|
|
|
79372
79464
|
// src/execution/json.ts
|
|
79373
|
-
function fail(
|
|
79374
|
-
throw new TypeError(`${
|
|
79465
|
+
function fail(path19, detail) {
|
|
79466
|
+
throw new TypeError(`${path19} ${detail}`);
|
|
79375
79467
|
}
|
|
79376
|
-
function cloneExecutionJson(value,
|
|
79468
|
+
function cloneExecutionJson(value, path19 = "execution value", ancestors = new Set) {
|
|
79377
79469
|
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
79378
79470
|
return value;
|
|
79379
79471
|
if (typeof value === "number") {
|
|
79380
79472
|
if (!Number.isFinite(value))
|
|
79381
|
-
fail(
|
|
79473
|
+
fail(path19, "must contain only finite numbers");
|
|
79382
79474
|
return value;
|
|
79383
79475
|
}
|
|
79384
79476
|
if (value === undefined)
|
|
79385
|
-
fail(
|
|
79477
|
+
fail(path19, "must be omitted rather than set to undefined");
|
|
79386
79478
|
if (typeof value !== "object")
|
|
79387
|
-
fail(
|
|
79479
|
+
fail(path19, "must be JSON-safe");
|
|
79388
79480
|
if (ancestors.has(value))
|
|
79389
|
-
fail(
|
|
79481
|
+
fail(path19, "must not contain a cycle");
|
|
79390
79482
|
const nextAncestors = new Set(ancestors);
|
|
79391
79483
|
nextAncestors.add(value);
|
|
79392
79484
|
if (Array.isArray(value)) {
|
|
79393
79485
|
if (Object.getPrototypeOf(value) !== Array.prototype)
|
|
79394
|
-
fail(
|
|
79486
|
+
fail(path19, "array must use the standard Array prototype");
|
|
79395
79487
|
const ownKeys = Reflect.ownKeys(value);
|
|
79396
79488
|
const lengthDescriptor = Reflect.getOwnPropertyDescriptor(value, "length");
|
|
79397
79489
|
if (!lengthDescriptor || !("value" in lengthDescriptor) || typeof lengthDescriptor.value !== "number" || !Number.isInteger(lengthDescriptor.value) || lengthDescriptor.value < 0) {
|
|
79398
|
-
fail(
|
|
79490
|
+
fail(path19, "array length must be a stable nonnegative integer data property");
|
|
79399
79491
|
}
|
|
79400
79492
|
const length = lengthDescriptor.value;
|
|
79401
79493
|
if (ownKeys.length !== length + 1) {
|
|
79402
|
-
fail(
|
|
79494
|
+
fail(path19, "array must be dense and contain no non-index properties");
|
|
79403
79495
|
}
|
|
79404
79496
|
for (const key of ownKeys) {
|
|
79405
79497
|
if (key === "length")
|
|
79406
79498
|
continue;
|
|
79407
79499
|
if (typeof key !== "string" || !/^(?:0|[1-9]\d*)$/.test(key) || Number(key) >= length) {
|
|
79408
|
-
fail(
|
|
79500
|
+
fail(path19, "array must contain only canonical index properties");
|
|
79409
79501
|
}
|
|
79410
79502
|
}
|
|
79411
79503
|
const cloned2 = [];
|
|
79412
79504
|
for (let index = 0;index < length; index++) {
|
|
79413
79505
|
const descriptor = Reflect.getOwnPropertyDescriptor(value, String(index));
|
|
79414
79506
|
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
|
|
79415
|
-
fail(
|
|
79507
|
+
fail(path19, "array must be dense enumerable data properties");
|
|
79416
79508
|
}
|
|
79417
|
-
cloned2.push(cloneExecutionJson(descriptor.value, `${
|
|
79509
|
+
cloned2.push(cloneExecutionJson(descriptor.value, `${path19}[${index}]`, nextAncestors));
|
|
79418
79510
|
}
|
|
79419
79511
|
return Object.freeze(cloned2);
|
|
79420
79512
|
}
|
|
79421
|
-
const snapshot = snapshotStrictRecord(value,
|
|
79513
|
+
const snapshot = snapshotStrictRecord(value, path19);
|
|
79422
79514
|
const cloned = Object.create(null);
|
|
79423
79515
|
for (const [key, child] of Object.entries(snapshot)) {
|
|
79424
79516
|
Object.defineProperty(cloned, key, {
|
|
79425
|
-
value: cloneExecutionJson(child, `${
|
|
79517
|
+
value: cloneExecutionJson(child, `${path19}.${key}`, nextAncestors),
|
|
79426
79518
|
enumerable: true,
|
|
79427
79519
|
configurable: false,
|
|
79428
79520
|
writable: false
|
|
@@ -79430,10 +79522,10 @@ function cloneExecutionJson(value, path18 = "execution value", ancestors = new S
|
|
|
79430
79522
|
}
|
|
79431
79523
|
return Object.freeze(cloned);
|
|
79432
79524
|
}
|
|
79433
|
-
function cloneExecutionJsonObject(value,
|
|
79434
|
-
const cloned = cloneExecutionJson(value,
|
|
79525
|
+
function cloneExecutionJsonObject(value, path19) {
|
|
79526
|
+
const cloned = cloneExecutionJson(value, path19);
|
|
79435
79527
|
if (cloned === null || Array.isArray(cloned) || typeof cloned !== "object") {
|
|
79436
|
-
fail(
|
|
79528
|
+
fail(path19, "must be a JSON object");
|
|
79437
79529
|
}
|
|
79438
79530
|
return cloned;
|
|
79439
79531
|
}
|
|
@@ -79447,11 +79539,11 @@ var WINDOWS_DRIVE_PREFIX_PATTERN = /^[A-Za-z]:/;
|
|
|
79447
79539
|
var RESERVED_EXTENSION_OWNERS = new Set(["__proto__", "constructor", "prototype", "tostring"]);
|
|
79448
79540
|
var renderedSourceBrand = Symbol("akm.adapter-rendered-execution-source");
|
|
79449
79541
|
var renderedSourceInstances = new WeakSet;
|
|
79450
|
-
function requireRecord(value,
|
|
79451
|
-
return snapshotStrictRecord(value,
|
|
79542
|
+
function requireRecord(value, path19) {
|
|
79543
|
+
return snapshotStrictRecord(value, path19);
|
|
79452
79544
|
}
|
|
79453
|
-
function assertOnlyKeys(value, allowed,
|
|
79454
|
-
assertSnapshotKeys(value, allowed,
|
|
79545
|
+
function assertOnlyKeys(value, allowed, path19) {
|
|
79546
|
+
assertSnapshotKeys(value, allowed, path19);
|
|
79455
79547
|
}
|
|
79456
79548
|
function validateExtensionOwner(owner) {
|
|
79457
79549
|
const normalized = owner.toLowerCase();
|
|
@@ -79467,16 +79559,16 @@ function frozenNullPrototypeMap(entries) {
|
|
|
79467
79559
|
return Object.freeze(out);
|
|
79468
79560
|
}
|
|
79469
79561
|
function cloneExtensionEntry(value, index) {
|
|
79470
|
-
const
|
|
79471
|
-
const cloned = cloneExecutionJson(value,
|
|
79562
|
+
const path19 = `extension entry ${index}`;
|
|
79563
|
+
const cloned = cloneExecutionJson(value, path19);
|
|
79472
79564
|
if (!Array.isArray(cloned) || cloned.length !== 2) {
|
|
79473
|
-
throw new TypeError(`${
|
|
79565
|
+
throw new TypeError(`${path19} must be a two-element [owner, values] array`);
|
|
79474
79566
|
}
|
|
79475
79567
|
const [owner, values] = cloned;
|
|
79476
79568
|
if (typeof owner !== "string")
|
|
79477
|
-
throw new TypeError(`${
|
|
79569
|
+
throw new TypeError(`${path19} owner must be a string`);
|
|
79478
79570
|
if (values === null || Array.isArray(values) || typeof values !== "object") {
|
|
79479
|
-
throw new TypeError(`${
|
|
79571
|
+
throw new TypeError(`${path19} values must be a JSON object`);
|
|
79480
79572
|
}
|
|
79481
79573
|
return [owner, values];
|
|
79482
79574
|
}
|
|
@@ -79494,18 +79586,18 @@ function createAdapterExtensions(first, second, ...rest) {
|
|
|
79494
79586
|
}
|
|
79495
79587
|
return frozenNullPrototypeMap(cloned);
|
|
79496
79588
|
}
|
|
79497
|
-
function cloneAdapterExtensions(value,
|
|
79498
|
-
const record = requireRecord(value,
|
|
79499
|
-
const entries = Object.entries(record).map(([owner, fields]) => [owner, cloneExecutionJsonObject(fields, `${
|
|
79589
|
+
function cloneAdapterExtensions(value, path19) {
|
|
79590
|
+
const record = requireRecord(value, path19);
|
|
79591
|
+
const entries = Object.entries(record).map(([owner, fields]) => [owner, cloneExecutionJsonObject(fields, `${path19}.${owner}`)]);
|
|
79500
79592
|
const [first, ...rest] = entries;
|
|
79501
79593
|
return first ? createAdapterExtensions(first, ...rest) : frozenNullPrototypeMap([]);
|
|
79502
79594
|
}
|
|
79503
|
-
function requireCanonicalString(value,
|
|
79595
|
+
function requireCanonicalString(value, path19) {
|
|
79504
79596
|
if (typeof value !== "string" || value.length === 0 || !isWellFormedUnicode(value) || value.normalize("NFC") !== value) {
|
|
79505
|
-
throw new TypeError(`${
|
|
79597
|
+
throw new TypeError(`${path19} must be a non-empty NFC string`);
|
|
79506
79598
|
}
|
|
79507
79599
|
if (hasUnsafeIdentityCharacter(value)) {
|
|
79508
|
-
throw new TypeError(`${
|
|
79600
|
+
throw new TypeError(`${path19} must not contain Unicode control or dangerous format characters`);
|
|
79509
79601
|
}
|
|
79510
79602
|
return value;
|
|
79511
79603
|
}
|
|
@@ -79532,38 +79624,38 @@ function isWellFormedUnicode(value) {
|
|
|
79532
79624
|
}
|
|
79533
79625
|
return true;
|
|
79534
79626
|
}
|
|
79535
|
-
function validateCanonicalIdentity(input,
|
|
79536
|
-
assertOnlyKeys(input, ["ref", "bundle", "adapter", "file", "hash"],
|
|
79537
|
-
const ref = requireCanonicalString(input.ref, `${
|
|
79538
|
-
const bundle = requireCanonicalString(input.bundle, `${
|
|
79539
|
-
const adapter = requireCanonicalString(input.adapter, `${
|
|
79540
|
-
const file = requireCanonicalString(input.file, `${
|
|
79541
|
-
const hash = requireCanonicalString(input.hash, `${
|
|
79627
|
+
function validateCanonicalIdentity(input, path19) {
|
|
79628
|
+
assertOnlyKeys(input, ["ref", "bundle", "adapter", "file", "hash"], path19);
|
|
79629
|
+
const ref = requireCanonicalString(input.ref, `${path19}.ref`);
|
|
79630
|
+
const bundle = requireCanonicalString(input.bundle, `${path19}.bundle`);
|
|
79631
|
+
const adapter = requireCanonicalString(input.adapter, `${path19}.adapter`);
|
|
79632
|
+
const file = requireCanonicalString(input.file, `${path19}.file`);
|
|
79633
|
+
const hash = requireCanonicalString(input.hash, `${path19}.hash`);
|
|
79542
79634
|
let parsed;
|
|
79543
79635
|
try {
|
|
79544
79636
|
parsed = parseBundleRef(ref);
|
|
79545
79637
|
} catch (cause) {
|
|
79546
|
-
throw new TypeError(`${
|
|
79638
|
+
throw new TypeError(`${path19}.ref is not a canonical bundle ref`, { cause });
|
|
79547
79639
|
}
|
|
79548
79640
|
if (parsed.bundle === undefined || parsed.bundle !== bundle || parsed.fragment !== undefined || !isBundleSlug(bundle) || bundleRefToString(parsed) !== ref) {
|
|
79549
|
-
throw new TypeError(`${
|
|
79641
|
+
throw new TypeError(`${path19}.ref must round-trip as the same fully-qualified bundle ref without a fragment`);
|
|
79550
79642
|
}
|
|
79551
79643
|
if (!EXECUTION_ADAPTER_ID_PATTERN.test(adapter)) {
|
|
79552
|
-
throw new TypeError(`${
|
|
79644
|
+
throw new TypeError(`${path19}.adapter must use the current lowercase kebab-case adapter identifier grammar`);
|
|
79553
79645
|
}
|
|
79554
79646
|
const segments = file.split("/");
|
|
79555
79647
|
if (file.startsWith("/") || WINDOWS_DRIVE_PREFIX_PATTERN.test(file) || file.includes("\\") || segments.some((segment) => !segment || segment === "." || segment === "..")) {
|
|
79556
|
-
throw new TypeError(`${
|
|
79648
|
+
throw new TypeError(`${path19}.file must be a normalized relative POSIX path`);
|
|
79557
79649
|
}
|
|
79558
79650
|
if (!/^[a-f0-9]{64}$/.test(hash))
|
|
79559
|
-
throw new TypeError(`${
|
|
79651
|
+
throw new TypeError(`${path19}.hash must be a SHA-256 hex digest`);
|
|
79560
79652
|
return { ref, bundle, adapter, file, hash };
|
|
79561
79653
|
}
|
|
79562
79654
|
function createExecutionSourceIdentity(input) {
|
|
79563
79655
|
return Object.freeze(validateCanonicalIdentity(requireRecord(input, "execution source identity"), "execution source identity"));
|
|
79564
79656
|
}
|
|
79565
|
-
function cloneUnresolvedExecutionDefaults(input,
|
|
79566
|
-
const record = requireRecord(input,
|
|
79657
|
+
function cloneUnresolvedExecutionDefaults(input, path19 = "execution source defaults") {
|
|
79658
|
+
const record = requireRecord(input, path19);
|
|
79567
79659
|
assertOnlyKeys(record, [
|
|
79568
79660
|
"agent",
|
|
79569
79661
|
"engine",
|
|
@@ -79575,47 +79667,47 @@ function cloneUnresolvedExecutionDefaults(input, path18 = "execution source defa
|
|
|
79575
79667
|
"workspace",
|
|
79576
79668
|
"environment",
|
|
79577
79669
|
"runtime"
|
|
79578
|
-
],
|
|
79579
|
-
const json = { ...cloneExecutionJsonObject(record,
|
|
79670
|
+
], path19);
|
|
79671
|
+
const json = { ...cloneExecutionJsonObject(record, path19) };
|
|
79580
79672
|
for (const key of ["agent", "engine", "model", "workspace"]) {
|
|
79581
79673
|
const value = json[key];
|
|
79582
79674
|
if (value !== undefined && value !== null && typeof value !== "string") {
|
|
79583
|
-
throw new TypeError(`${
|
|
79675
|
+
throw new TypeError(`${path19}.${key} must be a string or null`);
|
|
79584
79676
|
}
|
|
79585
79677
|
}
|
|
79586
79678
|
const timeout = json.timeout;
|
|
79587
79679
|
if (timeout !== undefined && timeout !== null && typeof timeout !== "string" && typeof timeout !== "number") {
|
|
79588
|
-
throw new TypeError(`${
|
|
79680
|
+
throw new TypeError(`${path19}.timeout must be a string, number, or null`);
|
|
79589
79681
|
}
|
|
79590
79682
|
for (const key of ["inference", "outputSchema", "runtime"]) {
|
|
79591
79683
|
const value = json[key];
|
|
79592
79684
|
if (value !== undefined && value !== null && (Array.isArray(value) || typeof value !== "object")) {
|
|
79593
|
-
throw new TypeError(`${
|
|
79685
|
+
throw new TypeError(`${path19}.${key} must be an object or null`);
|
|
79594
79686
|
}
|
|
79595
79687
|
}
|
|
79596
79688
|
const environment = json.environment;
|
|
79597
79689
|
if (environment !== undefined && environment !== null) {
|
|
79598
79690
|
if (Array.isArray(environment) || typeof environment !== "object") {
|
|
79599
|
-
throw new TypeError(`${
|
|
79691
|
+
throw new TypeError(`${path19}.environment must be an object or null`);
|
|
79600
79692
|
}
|
|
79601
79693
|
if (Object.values(environment).some((value) => typeof value !== "string")) {
|
|
79602
|
-
throw new TypeError(`${
|
|
79694
|
+
throw new TypeError(`${path19}.environment values must be strings`);
|
|
79603
79695
|
}
|
|
79604
79696
|
}
|
|
79605
79697
|
if (Object.hasOwn(json, "tools"))
|
|
79606
|
-
json.tools = cloneToolSelection(json.tools, `${
|
|
79698
|
+
json.tools = cloneToolSelection(json.tools, `${path19}.tools`);
|
|
79607
79699
|
return Object.freeze(json);
|
|
79608
79700
|
}
|
|
79609
|
-
function cloneToolSelection(value,
|
|
79701
|
+
function cloneToolSelection(value, path19 = "tools") {
|
|
79610
79702
|
if (value === null || typeof value === "string")
|
|
79611
79703
|
return value;
|
|
79612
|
-
const cloned = cloneExecutionJson(value,
|
|
79704
|
+
const cloned = cloneExecutionJson(value, path19);
|
|
79613
79705
|
if (Array.isArray(cloned)) {
|
|
79614
79706
|
if (cloned.some((tool) => typeof tool !== "string"))
|
|
79615
|
-
throw new TypeError(`${
|
|
79707
|
+
throw new TypeError(`${path19} array values must be strings`);
|
|
79616
79708
|
return cloned;
|
|
79617
79709
|
}
|
|
79618
|
-
return cloneExecutionJsonObject(cloned,
|
|
79710
|
+
return cloneExecutionJsonObject(cloned, path19);
|
|
79619
79711
|
}
|
|
79620
79712
|
function createAdapterRenderedExecutionSource(input) {
|
|
79621
79713
|
const record = requireRecord(input, "adapter-rendered execution source");
|
|
@@ -79724,34 +79816,34 @@ function parseExecutionMarkdown(raw) {
|
|
|
79724
79816
|
function own(data, key) {
|
|
79725
79817
|
return Object.hasOwn(data, key);
|
|
79726
79818
|
}
|
|
79727
|
-
function requireMetadataMapping(value,
|
|
79819
|
+
function requireMetadataMapping(value, path19) {
|
|
79728
79820
|
try {
|
|
79729
|
-
return snapshotStrictRecord(value,
|
|
79821
|
+
return snapshotStrictRecord(value, path19);
|
|
79730
79822
|
} catch (cause) {
|
|
79731
|
-
throw new TypeError(`${
|
|
79823
|
+
throw new TypeError(`${path19} must be a mapping with enumerable data fields`, { cause });
|
|
79732
79824
|
}
|
|
79733
79825
|
}
|
|
79734
|
-
function nullableString(value,
|
|
79826
|
+
function nullableString(value, path19) {
|
|
79735
79827
|
if (value !== null && typeof value !== "string")
|
|
79736
|
-
throw new TypeError(`${
|
|
79828
|
+
throw new TypeError(`${path19} must be a string or null`);
|
|
79737
79829
|
return value;
|
|
79738
79830
|
}
|
|
79739
|
-
function nullableObject(value,
|
|
79740
|
-
return value === null ? null : cloneExecutionJsonObject(value,
|
|
79831
|
+
function nullableObject(value, path19) {
|
|
79832
|
+
return value === null ? null : cloneExecutionJsonObject(value, path19);
|
|
79741
79833
|
}
|
|
79742
|
-
function nullableEnvironment(value,
|
|
79834
|
+
function nullableEnvironment(value, path19) {
|
|
79743
79835
|
if (value === null)
|
|
79744
79836
|
return null;
|
|
79745
|
-
const environment = cloneExecutionJsonObject(value,
|
|
79837
|
+
const environment = cloneExecutionJsonObject(value, path19);
|
|
79746
79838
|
if (Object.values(environment).some((entry) => typeof entry !== "string")) {
|
|
79747
|
-
throw new TypeError(`${
|
|
79839
|
+
throw new TypeError(`${path19} values must be strings`);
|
|
79748
79840
|
}
|
|
79749
79841
|
return environment;
|
|
79750
79842
|
}
|
|
79751
|
-
function nullableTimeout(value,
|
|
79752
|
-
const timeout = cloneExecutionJson(value,
|
|
79843
|
+
function nullableTimeout(value, path19) {
|
|
79844
|
+
const timeout = cloneExecutionJson(value, path19);
|
|
79753
79845
|
if (timeout !== null && typeof timeout !== "string" && typeof timeout !== "number") {
|
|
79754
|
-
throw new TypeError(`${
|
|
79846
|
+
throw new TypeError(`${path19} must be a string, number, or null`);
|
|
79755
79847
|
}
|
|
79756
79848
|
return timeout;
|
|
79757
79849
|
}
|
|
@@ -80195,7 +80287,7 @@ function recognizeMatch(file) {
|
|
|
80195
80287
|
}
|
|
80196
80288
|
|
|
80197
80289
|
// src/core/adapter/adapters/akm-lint.ts
|
|
80198
|
-
import
|
|
80290
|
+
import path24 from "node:path";
|
|
80199
80291
|
|
|
80200
80292
|
// src/commands/lint/env-key-rules.ts
|
|
80201
80293
|
init_env();
|
|
@@ -80318,28 +80410,28 @@ var MOVE_TO_ENV = "Workflow params are copied verbatim into every native unit ex
|
|
|
80318
80410
|
function detectSecretShapedParams(params) {
|
|
80319
80411
|
const warnings = [];
|
|
80320
80412
|
const seen = new Set;
|
|
80321
|
-
const push = (
|
|
80322
|
-
if (seen.has(
|
|
80413
|
+
const push = (path20, why) => {
|
|
80414
|
+
if (seen.has(path20))
|
|
80323
80415
|
return;
|
|
80324
|
-
seen.add(
|
|
80325
|
-
warnings.push(`Run param "${
|
|
80416
|
+
seen.add(path20);
|
|
80417
|
+
warnings.push(`Run param "${path20}" ${why}. ${MOVE_TO_ENV} (Heuristic warning; params are declared non-secret.)`);
|
|
80326
80418
|
};
|
|
80327
|
-
const walk = (value,
|
|
80419
|
+
const walk = (value, path20, key) => {
|
|
80328
80420
|
if (key !== null && keyLooksSecret(key))
|
|
80329
|
-
push(
|
|
80421
|
+
push(path20, "has a secret-suggesting name");
|
|
80330
80422
|
if (typeof value === "string") {
|
|
80331
80423
|
if (valueLooksSecret(value))
|
|
80332
|
-
push(
|
|
80424
|
+
push(path20, "has a secret-shaped value (long, high-entropy string)");
|
|
80333
80425
|
return;
|
|
80334
80426
|
}
|
|
80335
80427
|
if (Array.isArray(value)) {
|
|
80336
80428
|
for (let i = 0;i < value.length; i++)
|
|
80337
|
-
walk(value[i], `${
|
|
80429
|
+
walk(value[i], `${path20}[${i}]`, null);
|
|
80338
80430
|
return;
|
|
80339
80431
|
}
|
|
80340
80432
|
if (value && typeof value === "object") {
|
|
80341
80433
|
for (const [k, v] of Object.entries(value)) {
|
|
80342
|
-
walk(v,
|
|
80434
|
+
walk(v, path20 ? `${path20}.${k}` : k, k);
|
|
80343
80435
|
}
|
|
80344
80436
|
}
|
|
80345
80437
|
};
|
|
@@ -80787,8 +80879,8 @@ init_dist();
|
|
|
80787
80879
|
init_asset_ref();
|
|
80788
80880
|
init_extra_params();
|
|
80789
80881
|
init_resource_limits();
|
|
80790
|
-
import
|
|
80791
|
-
import
|
|
80882
|
+
import crypto4 from "node:crypto";
|
|
80883
|
+
import path20 from "node:path";
|
|
80792
80884
|
|
|
80793
80885
|
// src/tasks/task-id.ts
|
|
80794
80886
|
init_errors();
|
|
@@ -81230,7 +81322,7 @@ var KNOWN_PROMPT_REF_FAMILIES = new Set([
|
|
|
81230
81322
|
"workflows"
|
|
81231
81323
|
]);
|
|
81232
81324
|
function hash(bytes) {
|
|
81233
|
-
return
|
|
81325
|
+
return crypto4.createHash("sha256").update(bytes).digest("hex");
|
|
81234
81326
|
}
|
|
81235
81327
|
function base(input) {
|
|
81236
81328
|
return {
|
|
@@ -81389,7 +81481,7 @@ function addSharedNonPromptOverrides(data, akm) {
|
|
|
81389
81481
|
}
|
|
81390
81482
|
function promptSourceKind(raw) {
|
|
81391
81483
|
const trimmed = raw.trim();
|
|
81392
|
-
if (trimmed.startsWith("./") || trimmed.startsWith("../") ||
|
|
81484
|
+
if (trimmed.startsWith("./") || trimmed.startsWith("../") || path20.isAbsolute(trimmed) || /^[A-Za-z]:[\\/]/.test(trimmed)) {
|
|
81393
81485
|
return "file";
|
|
81394
81486
|
}
|
|
81395
81487
|
try {
|
|
@@ -81496,7 +81588,7 @@ function planLegacyTaskDataToV3(input, data) {
|
|
|
81496
81588
|
return blocked(input, "read-only-source", !input.writable ? "the owning source is not writable" : "the source file or publication directory is read-only");
|
|
81497
81589
|
}
|
|
81498
81590
|
try {
|
|
81499
|
-
validateTaskId(
|
|
81591
|
+
validateTaskId(path20.basename(input.filePath, ".yml"));
|
|
81500
81592
|
} catch (cause) {
|
|
81501
81593
|
return blocked(input, "invalid-v2-task", cause instanceof Error ? cause.message : String(cause));
|
|
81502
81594
|
}
|
|
@@ -81566,7 +81658,7 @@ function planTaskToV3File(input) {
|
|
|
81566
81658
|
return planLegacyTaskDataToV3(input, data);
|
|
81567
81659
|
}
|
|
81568
81660
|
function generationFor(files) {
|
|
81569
|
-
const digest =
|
|
81661
|
+
const digest = crypto4.createHash("sha256");
|
|
81570
81662
|
digest.update("akm-task-to-v3-plan-v1\x00");
|
|
81571
81663
|
for (const file of files) {
|
|
81572
81664
|
digest.update(file.filePath);
|
|
@@ -81600,7 +81692,7 @@ function taskToV3PlanFromOutcomes(outcomes) {
|
|
|
81600
81692
|
for (let index = 1;index < files.length; index += 1) {
|
|
81601
81693
|
const previous = files[index - 1];
|
|
81602
81694
|
const current = files[index];
|
|
81603
|
-
if (previous && current &&
|
|
81695
|
+
if (previous && current && path20.resolve(previous.filePath) === path20.resolve(current.filePath)) {
|
|
81604
81696
|
throw new Error(`duplicate task migration file path: ${current.filePath}`);
|
|
81605
81697
|
}
|
|
81606
81698
|
}
|
|
@@ -81610,7 +81702,7 @@ function planTaskToV3Migration(inputs) {
|
|
|
81610
81702
|
const sorted = [...inputs].sort((left, right) => left.filePath < right.filePath ? -1 : left.filePath > right.filePath ? 1 : 0);
|
|
81611
81703
|
let previous;
|
|
81612
81704
|
for (const current of sorted) {
|
|
81613
|
-
if (previous &&
|
|
81705
|
+
if (previous && path20.resolve(previous.filePath) === path20.resolve(current.filePath)) {
|
|
81614
81706
|
throw new Error(`duplicate task migration file path: ${current.filePath}`);
|
|
81615
81707
|
}
|
|
81616
81708
|
previous = current;
|
|
@@ -81621,8 +81713,8 @@ function planTaskToV3Migration(inputs) {
|
|
|
81621
81713
|
// src/tasks/source/task-to-v4.ts
|
|
81622
81714
|
init_dist();
|
|
81623
81715
|
init_bounded_document();
|
|
81624
|
-
import
|
|
81625
|
-
import
|
|
81716
|
+
import crypto5 from "node:crypto";
|
|
81717
|
+
import path21 from "node:path";
|
|
81626
81718
|
var V3_TOP_LEVEL_KEYS = new Set([
|
|
81627
81719
|
"version",
|
|
81628
81720
|
"name",
|
|
@@ -81668,7 +81760,7 @@ var AKM_HOIST_KEYS = [
|
|
|
81668
81760
|
"maxRetries"
|
|
81669
81761
|
];
|
|
81670
81762
|
function hash2(bytes) {
|
|
81671
|
-
return
|
|
81763
|
+
return crypto5.createHash("sha256").update(bytes).digest("hex");
|
|
81672
81764
|
}
|
|
81673
81765
|
function causeMessage(cause) {
|
|
81674
81766
|
return cause instanceof Error ? cause.message : String(cause);
|
|
@@ -81937,7 +82029,7 @@ function planTaskToV4File(input) {
|
|
|
81937
82029
|
return planV3DataToV4(input, data);
|
|
81938
82030
|
}
|
|
81939
82031
|
function generationFor2(files) {
|
|
81940
|
-
const digest =
|
|
82032
|
+
const digest = crypto5.createHash("sha256");
|
|
81941
82033
|
digest.update("akm-task-to-v4-plan-v1\x00");
|
|
81942
82034
|
for (const file of files) {
|
|
81943
82035
|
digest.update(file.filePath);
|
|
@@ -81974,7 +82066,7 @@ function taskToV4PlanFromOutcomes(outcomes) {
|
|
|
81974
82066
|
for (let index = 1;index < files.length; index += 1) {
|
|
81975
82067
|
const previous = files[index - 1];
|
|
81976
82068
|
const current = files[index];
|
|
81977
|
-
if (previous && current &&
|
|
82069
|
+
if (previous && current && path21.resolve(previous.filePath) === path21.resolve(current.filePath)) {
|
|
81978
82070
|
throw new Error(`duplicate task migration file path: ${current.filePath}`);
|
|
81979
82071
|
}
|
|
81980
82072
|
}
|
|
@@ -81984,7 +82076,7 @@ function planTaskToV4Migration(inputs) {
|
|
|
81984
82076
|
const sorted = [...inputs].sort((left, right) => left.filePath < right.filePath ? -1 : left.filePath > right.filePath ? 1 : 0);
|
|
81985
82077
|
let previous;
|
|
81986
82078
|
for (const current of sorted) {
|
|
81987
|
-
if (previous &&
|
|
82079
|
+
if (previous && path21.resolve(previous.filePath) === path21.resolve(current.filePath)) {
|
|
81988
82080
|
throw new Error(`duplicate task migration file path: ${current.filePath}`);
|
|
81989
82081
|
}
|
|
81990
82082
|
previous = current;
|
|
@@ -82299,7 +82391,7 @@ function checkInvalidTypeValue(data, allowedTypes) {
|
|
|
82299
82391
|
return `type field has invalid value '${value}'; expected one of: ${allowedTypes.join(", ")}`;
|
|
82300
82392
|
}
|
|
82301
82393
|
function suggestSlug(filePath) {
|
|
82302
|
-
return
|
|
82394
|
+
return path24.basename(filePath, ".md").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
82303
82395
|
}
|
|
82304
82396
|
function nameOrTypeDiagnostics(relPath, data, frontmatter, allowedTypes) {
|
|
82305
82397
|
const missingFieldDetail = checkMissingNameOrType(data, frontmatter);
|
|
@@ -82339,7 +82431,7 @@ function collectSuppressedKeys(raw) {
|
|
|
82339
82431
|
function dangerousEnvKeyDiagnostics(type, relPath, raw) {
|
|
82340
82432
|
if (type !== "env" && type !== "secret")
|
|
82341
82433
|
return [];
|
|
82342
|
-
const baseNameWithExt =
|
|
82434
|
+
const baseNameWithExt = path24.basename(relPath);
|
|
82343
82435
|
if (!baseNameWithExt.endsWith(".env"))
|
|
82344
82436
|
return [];
|
|
82345
82437
|
const ref = conceptIdForStashFile(type, ".", relPath);
|
|
@@ -82485,7 +82577,7 @@ function workflowFrontendDiagnostics(relPath, raw, parsePath2) {
|
|
|
82485
82577
|
}
|
|
82486
82578
|
return { errors: errors3, warnings };
|
|
82487
82579
|
}
|
|
82488
|
-
const compiled = compileWorkflowPlan(result.ir,
|
|
82580
|
+
const compiled = compileWorkflowPlan(result.ir, path24.basename(parsePath2, path24.extname(parsePath2)));
|
|
82489
82581
|
if (!compiled.ok) {
|
|
82490
82582
|
for (const err of compiled.errors) {
|
|
82491
82583
|
errors3.push({
|
|
@@ -82803,13 +82895,13 @@ function isReservedFileName(name) {
|
|
|
82803
82895
|
}
|
|
82804
82896
|
var WIKI_INFRA_FILES = new Set(["schema.md", "index.md", "log.md"]);
|
|
82805
82897
|
function akmStashAbstains(root, absPath) {
|
|
82806
|
-
const relPath =
|
|
82807
|
-
if (!relPath || relPath.startsWith("..") ||
|
|
82898
|
+
const relPath = path25.relative(root, absPath);
|
|
82899
|
+
if (!relPath || relPath.startsWith("..") || path25.isAbsolute(relPath))
|
|
82808
82900
|
return false;
|
|
82809
82901
|
const segments = relPath.split(/[\\/]+/).filter(Boolean);
|
|
82810
82902
|
if (segments.length === 0)
|
|
82811
82903
|
return false;
|
|
82812
|
-
if (segments[0] === "env" && (absPath.endsWith(".env") ||
|
|
82904
|
+
if (segments[0] === "env" && (absPath.endsWith(".env") || path25.basename(absPath) === ".env")) {
|
|
82813
82905
|
if (fs16.existsSync(absPath.replace(/\.env$/, ".sensitive")))
|
|
82814
82906
|
return true;
|
|
82815
82907
|
}
|
|
@@ -82916,7 +83008,7 @@ function recognize2(c, file) {
|
|
|
82916
83008
|
return null;
|
|
82917
83009
|
const stashDir = stashDirFor(match.type);
|
|
82918
83010
|
const canonicalName = stashDir !== undefined ? conceptId.slice(stashDir.length + 1) : conceptId;
|
|
82919
|
-
const dirPath =
|
|
83011
|
+
const dirPath = path25.dirname(file.absPath);
|
|
82920
83012
|
const entry = {
|
|
82921
83013
|
name: canonicalName,
|
|
82922
83014
|
type: match.type,
|
|
@@ -82962,13 +83054,13 @@ function renderExecutionSource(c, file) {
|
|
|
82962
83054
|
});
|
|
82963
83055
|
}
|
|
82964
83056
|
function buildOverlayContext(root, relPathInput, raw) {
|
|
82965
|
-
const absPath =
|
|
82966
|
-
const relPath =
|
|
82967
|
-
const ext =
|
|
82968
|
-
const fileName =
|
|
82969
|
-
const parentDirAbs =
|
|
82970
|
-
const parentDir =
|
|
82971
|
-
const relDir =
|
|
83057
|
+
const absPath = path25.join(root, relPathInput);
|
|
83058
|
+
const relPath = path25.relative(root, absPath).replace(/\\/g, "/");
|
|
83059
|
+
const ext = path25.extname(absPath).toLowerCase();
|
|
83060
|
+
const fileName = path25.basename(absPath);
|
|
83061
|
+
const parentDirAbs = path25.dirname(absPath);
|
|
83062
|
+
const parentDir = path25.basename(parentDirAbs);
|
|
83063
|
+
const relDir = path25.dirname(relPath).replace(/\\/g, "/");
|
|
82972
83064
|
const ancestorDirs = relDir === "." ? [] : relDir.split("/").filter((seg) => seg.length > 0);
|
|
82973
83065
|
let cachedFrontmatter;
|
|
82974
83066
|
let frontmatterComputed = false;
|
|
@@ -83066,13 +83158,13 @@ var akmAdapter = {
|
|
|
83066
83158
|
const posix = conceptId.replace(/\\/g, "/");
|
|
83067
83159
|
const slash = posix.indexOf("/");
|
|
83068
83160
|
if (slash <= 0)
|
|
83069
|
-
return [{ path:
|
|
83161
|
+
return [{ path: path25.join(c.root, `${posix}.md`), conceptId: posix }];
|
|
83070
83162
|
const head = posix.slice(0, slash);
|
|
83071
83163
|
const rest = posix.slice(slash + 1);
|
|
83072
83164
|
const type = stashDirToType(head);
|
|
83073
83165
|
if (type === undefined || rest.length === 0)
|
|
83074
83166
|
return [];
|
|
83075
|
-
const canonical = assetPathCandidatesForName(type,
|
|
83167
|
+
const canonical = assetPathCandidatesForName(type, path25.join(c.root, head), rest);
|
|
83076
83168
|
const loose = assetPathCandidatesForName(type, c.root, rest);
|
|
83077
83169
|
return [...new Set([...canonical, ...loose])].map((candidatePath) => ({
|
|
83078
83170
|
path: candidatePath,
|
|
@@ -83087,18 +83179,18 @@ var akmAdapter = {
|
|
|
83087
83179
|
const rest = posix.slice(slash + 1);
|
|
83088
83180
|
const type = stashDirToType(head);
|
|
83089
83181
|
if (type !== undefined && rest.length > 0) {
|
|
83090
|
-
const typeDir =
|
|
83182
|
+
const typeDir = path25.join(c.root, head);
|
|
83091
83183
|
return assetPathForName(type, typeDir, rest);
|
|
83092
83184
|
}
|
|
83093
83185
|
}
|
|
83094
|
-
return
|
|
83186
|
+
return path25.join(c.root, `${posix}.md`);
|
|
83095
83187
|
},
|
|
83096
83188
|
directoryList(_c) {
|
|
83097
83189
|
return [...new Set(stashDirNames())];
|
|
83098
83190
|
},
|
|
83099
83191
|
looksLikeRoot(root) {
|
|
83100
83192
|
try {
|
|
83101
|
-
if (fs16.statSync(
|
|
83193
|
+
if (fs16.statSync(path25.join(root, ".stash")).isDirectory())
|
|
83102
83194
|
return true;
|
|
83103
83195
|
} catch {}
|
|
83104
83196
|
const ownedDirNames = new Set(stashDirNames());
|
|
@@ -83116,10 +83208,10 @@ var akmAdapter = {
|
|
|
83116
83208
|
return false;
|
|
83117
83209
|
const expectedType = stashDirToType(only.name);
|
|
83118
83210
|
try {
|
|
83119
|
-
const markdown = fs16.readdirSync(
|
|
83211
|
+
const markdown = fs16.readdirSync(path25.join(root, only.name), { withFileTypes: true }).find((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".md"));
|
|
83120
83212
|
if (!markdown)
|
|
83121
83213
|
return true;
|
|
83122
|
-
const data = parseFrontmatter(fs16.readFileSync(
|
|
83214
|
+
const data = parseFrontmatter(fs16.readFileSync(path25.join(root, only.name, markdown.name), "utf8")).data;
|
|
83123
83215
|
const declaredType = typeof data.type === "string" ? data.type.trim() : "";
|
|
83124
83216
|
return !declaredType || declaredType === expectedType;
|
|
83125
83217
|
} catch {
|
|
@@ -83130,7 +83222,7 @@ var akmAdapter = {
|
|
|
83130
83222
|
|
|
83131
83223
|
// src/core/adapter/adapters/akm-task-adapter.ts
|
|
83132
83224
|
import fs17 from "node:fs";
|
|
83133
|
-
import
|
|
83225
|
+
import path26 from "node:path";
|
|
83134
83226
|
init_common();
|
|
83135
83227
|
var COMPONENT_ID2 = "main";
|
|
83136
83228
|
var TASK_EXT = TASK_EXTENSION;
|
|
@@ -83161,7 +83253,7 @@ async function validate3(c, changes, ctx) {
|
|
|
83161
83253
|
const raw = change.after ?? await ctx.readFile(change.path);
|
|
83162
83254
|
if (typeof raw !== "string")
|
|
83163
83255
|
continue;
|
|
83164
|
-
const ext =
|
|
83256
|
+
const ext = path26.extname(change.path).toLowerCase();
|
|
83165
83257
|
if (ext !== TASK_EXT && ext !== TASK_NEAR_MISS_EXTENSION)
|
|
83166
83258
|
continue;
|
|
83167
83259
|
const relPath = toPosix(change.path);
|
|
@@ -83196,13 +83288,13 @@ var akmTaskAdapter = {
|
|
|
83196
83288
|
readCandidates(c, conceptId) {
|
|
83197
83289
|
const posix = toPosix(conceptId).replace(/\.ya?ml$/i, "");
|
|
83198
83290
|
return [
|
|
83199
|
-
{ path:
|
|
83200
|
-
{ path:
|
|
83291
|
+
{ path: path26.join(c.root, `${posix}.yml`), conceptId: posix },
|
|
83292
|
+
{ path: path26.join(c.root, `${posix}.yaml`), conceptId: posix }
|
|
83201
83293
|
];
|
|
83202
83294
|
},
|
|
83203
83295
|
placeNew(c, conceptId) {
|
|
83204
83296
|
const posix = toPosix(conceptId);
|
|
83205
|
-
return
|
|
83297
|
+
return path26.join(c.root, /\.yml$/i.test(posix) ? posix : `${posix}.yml`);
|
|
83206
83298
|
},
|
|
83207
83299
|
directoryList() {
|
|
83208
83300
|
return ["."];
|
|
@@ -83215,11 +83307,11 @@ var akmTaskAdapter = {
|
|
|
83215
83307
|
return false;
|
|
83216
83308
|
}
|
|
83217
83309
|
for (const entry of entries) {
|
|
83218
|
-
if (!entry.isFile() ||
|
|
83310
|
+
if (!entry.isFile() || path26.extname(entry.name).toLowerCase() !== TASK_EXT)
|
|
83219
83311
|
continue;
|
|
83220
83312
|
let raw;
|
|
83221
83313
|
try {
|
|
83222
|
-
raw = fs17.readFileSync(
|
|
83314
|
+
raw = fs17.readFileSync(path26.join(root, entry.name), "utf8");
|
|
83223
83315
|
} catch {
|
|
83224
83316
|
continue;
|
|
83225
83317
|
}
|
|
@@ -83237,7 +83329,7 @@ init_compile();
|
|
|
83237
83329
|
init_frontmatter();
|
|
83238
83330
|
init_common();
|
|
83239
83331
|
import fs18 from "node:fs";
|
|
83240
|
-
import
|
|
83332
|
+
import path27 from "node:path";
|
|
83241
83333
|
var COMPONENT_ID3 = "main";
|
|
83242
83334
|
var WORKFLOW_EXTS = new Set([".md", ".yml"]);
|
|
83243
83335
|
function conceptIdOf(relPath) {
|
|
@@ -83291,8 +83383,8 @@ async function validate4(c, changes, ctx) {
|
|
|
83291
83383
|
const raw = change.after ?? await ctx.readFile(change.path);
|
|
83292
83384
|
if (typeof raw !== "string")
|
|
83293
83385
|
continue;
|
|
83294
|
-
const ext =
|
|
83295
|
-
if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(
|
|
83386
|
+
const ext = path27.extname(change.path).toLowerCase();
|
|
83387
|
+
if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path27.basename(change.path)))
|
|
83296
83388
|
continue;
|
|
83297
83389
|
const relPath = toPosix(change.path);
|
|
83298
83390
|
if (ext === ".yml") {
|
|
@@ -83321,12 +83413,12 @@ function hasTopLevelWorkflowFile(root, entries) {
|
|
|
83321
83413
|
for (const entry of entries) {
|
|
83322
83414
|
if (!entry.isFile())
|
|
83323
83415
|
continue;
|
|
83324
|
-
const ext =
|
|
83416
|
+
const ext = path27.extname(entry.name).toLowerCase();
|
|
83325
83417
|
if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(entry.name))
|
|
83326
83418
|
continue;
|
|
83327
83419
|
let raw;
|
|
83328
83420
|
try {
|
|
83329
|
-
raw = fs18.readFileSync(
|
|
83421
|
+
raw = fs18.readFileSync(path27.join(root, entry.name), "utf8");
|
|
83330
83422
|
} catch {
|
|
83331
83423
|
continue;
|
|
83332
83424
|
}
|
|
@@ -83346,16 +83438,16 @@ var akmWorkflowAdapter = {
|
|
|
83346
83438
|
readCandidates(c, conceptId) {
|
|
83347
83439
|
const posix = toPosix(conceptId);
|
|
83348
83440
|
const canonical = posix.replace(/\.(?:md|yml)$/i, "");
|
|
83349
|
-
return /\.(?:md|yml)$/i.test(posix) ? [{ path:
|
|
83350
|
-
{ path:
|
|
83351
|
-
{ path:
|
|
83441
|
+
return /\.(?:md|yml)$/i.test(posix) ? [{ path: path27.join(c.root, posix), conceptId: canonical }] : [
|
|
83442
|
+
{ path: path27.join(c.root, `${posix}.md`), conceptId: canonical },
|
|
83443
|
+
{ path: path27.join(c.root, `${posix}.yml`), conceptId: canonical }
|
|
83352
83444
|
];
|
|
83353
83445
|
},
|
|
83354
83446
|
placeNew(c, conceptId) {
|
|
83355
83447
|
const posix = toPosix(conceptId);
|
|
83356
83448
|
if (/\.(?:md|yml)$/i.test(posix))
|
|
83357
|
-
return
|
|
83358
|
-
return
|
|
83449
|
+
return path27.join(c.root, posix);
|
|
83450
|
+
return path27.join(c.root, `${posix}.md`);
|
|
83359
83451
|
},
|
|
83360
83452
|
directoryList() {
|
|
83361
83453
|
return ["."];
|
|
@@ -83373,10 +83465,10 @@ var akmWorkflowAdapter = {
|
|
|
83373
83465
|
|
|
83374
83466
|
// src/core/adapter/adapters/claude-adapter.ts
|
|
83375
83467
|
import fs19 from "node:fs";
|
|
83376
|
-
import
|
|
83468
|
+
import path29 from "node:path";
|
|
83377
83469
|
|
|
83378
83470
|
// src/core/adapter/adapters/tool-dir-shared.ts
|
|
83379
|
-
import
|
|
83471
|
+
import path28 from "node:path";
|
|
83380
83472
|
init_frontmatter();
|
|
83381
83473
|
init_common();
|
|
83382
83474
|
var CANONICAL_COMMAND_DIR = "commands";
|
|
@@ -83398,7 +83490,7 @@ function classify(relPath, layout) {
|
|
|
83398
83490
|
return { type: "instruction", conceptId: layout.instructionConceptId, name: layout.instructionConceptId };
|
|
83399
83491
|
}
|
|
83400
83492
|
const head = segs[0];
|
|
83401
|
-
const ext =
|
|
83493
|
+
const ext = path28.extname(base3).toLowerCase();
|
|
83402
83494
|
if (layout.skillDirs.has(head)) {
|
|
83403
83495
|
if (segs.length === 3 && base3 === SKILL_MANIFEST2) {
|
|
83404
83496
|
return { type: "skill", conceptId: `${segs[0]}/${segs[1]}`, name: segs[1] };
|
|
@@ -83447,24 +83539,24 @@ function recognizeToolDir(layout, c, file) {
|
|
|
83447
83539
|
function placeNewToolDir(layout, c, conceptId) {
|
|
83448
83540
|
const posix = toPosix(conceptId);
|
|
83449
83541
|
if (posix === layout.instructionConceptId)
|
|
83450
|
-
return
|
|
83542
|
+
return path28.join(c.root, layout.instructionFile);
|
|
83451
83543
|
const segs = posix.split("/").filter((s) => s.length > 0);
|
|
83452
83544
|
const head = segs[0];
|
|
83453
83545
|
const rest = segs.slice(1).join("/");
|
|
83454
83546
|
if (rest.length > 0) {
|
|
83455
83547
|
if (layout.skillDirs.has(head))
|
|
83456
|
-
return
|
|
83548
|
+
return path28.join(c.root, CANONICAL_SKILL_DIR, rest, SKILL_MANIFEST2);
|
|
83457
83549
|
if (layout.commandDirs.has(head))
|
|
83458
|
-
return
|
|
83550
|
+
return path28.join(c.root, CANONICAL_COMMAND_DIR, `${rest}.md`);
|
|
83459
83551
|
if (layout.agentDirs.has(head))
|
|
83460
|
-
return
|
|
83552
|
+
return path28.join(c.root, CANONICAL_AGENT_DIR, `${rest}.md`);
|
|
83461
83553
|
}
|
|
83462
|
-
return
|
|
83554
|
+
return path28.join(c.root, `${posix}.md`);
|
|
83463
83555
|
}
|
|
83464
83556
|
function readCandidatesToolDir(layout, c, conceptId) {
|
|
83465
83557
|
const posix = toPosix(conceptId);
|
|
83466
83558
|
if (posix === layout.instructionConceptId) {
|
|
83467
|
-
return [{ path:
|
|
83559
|
+
return [{ path: path28.join(c.root, layout.instructionFile), conceptId: posix }];
|
|
83468
83560
|
}
|
|
83469
83561
|
const segs = posix.split("/").filter((segment) => segment.length > 0);
|
|
83470
83562
|
const head = segs[0];
|
|
@@ -83472,10 +83564,10 @@ function readCandidatesToolDir(layout, c, conceptId) {
|
|
|
83472
83564
|
if (!head || !rest)
|
|
83473
83565
|
return [];
|
|
83474
83566
|
if (layout.skillDirs.has(head)) {
|
|
83475
|
-
return segs.length === 2 ? [{ path:
|
|
83567
|
+
return segs.length === 2 ? [{ path: path28.join(c.root, head, rest, SKILL_MANIFEST2), conceptId: posix }] : [];
|
|
83476
83568
|
}
|
|
83477
83569
|
if (layout.commandDirs.has(head) || layout.agentDirs.has(head)) {
|
|
83478
|
-
return [{ path:
|
|
83570
|
+
return [{ path: path28.join(c.root, head, `${rest}.md`), conceptId: posix }];
|
|
83479
83571
|
}
|
|
83480
83572
|
return [];
|
|
83481
83573
|
}
|
|
@@ -83587,12 +83679,12 @@ function dirExists(p) {
|
|
|
83587
83679
|
}
|
|
83588
83680
|
function claudeLooksLikeRoot(root) {
|
|
83589
83681
|
try {
|
|
83590
|
-
if (!fs19.existsSync(
|
|
83682
|
+
if (!fs19.existsSync(path29.join(root, "CLAUDE.md")))
|
|
83591
83683
|
return false;
|
|
83592
83684
|
} catch {
|
|
83593
83685
|
return false;
|
|
83594
83686
|
}
|
|
83595
|
-
return ["commands", "agents", "skills"].some((d) => dirExists(
|
|
83687
|
+
return ["commands", "agents", "skills"].some((d) => dirExists(path29.join(root, d)));
|
|
83596
83688
|
}
|
|
83597
83689
|
var claudeAdapter = makeToolDirAdapter(LAYOUT, claudeLooksLikeRoot);
|
|
83598
83690
|
|
|
@@ -83600,7 +83692,7 @@ var claudeAdapter = makeToolDirAdapter(LAYOUT, claudeLooksLikeRoot);
|
|
|
83600
83692
|
init_asset_placement();
|
|
83601
83693
|
init_common();
|
|
83602
83694
|
import fs20 from "node:fs";
|
|
83603
|
-
import
|
|
83695
|
+
import path30 from "node:path";
|
|
83604
83696
|
var COMPONENT_ID4 = "main";
|
|
83605
83697
|
var ENV_DIR = "env";
|
|
83606
83698
|
var SECRETS_DIR = "secrets";
|
|
@@ -83702,7 +83794,7 @@ var dotenvAdapter = {
|
|
|
83702
83794
|
const type = typeForStashDir(head);
|
|
83703
83795
|
if (type !== "env" && type !== "secret" || rest.length === 0)
|
|
83704
83796
|
return [];
|
|
83705
|
-
const primaries = assetPathCandidatesForName(type,
|
|
83797
|
+
const primaries = assetPathCandidatesForName(type, path30.join(c.root, head), rest);
|
|
83706
83798
|
const expanded = primaries.flatMap((primary) => type === "env" ? [primary, primary.replace(/\.env$/i, ".sensitive")] : [primary, `${primary}.sensitive`, `${primary}.lock`]);
|
|
83707
83799
|
return expanded.map((candidatePath) => ({ path: candidatePath, conceptId: posix }));
|
|
83708
83800
|
},
|
|
@@ -83714,10 +83806,10 @@ var dotenvAdapter = {
|
|
|
83714
83806
|
const rest = posix.slice(slash + 1);
|
|
83715
83807
|
const type = typeForStashDir(head);
|
|
83716
83808
|
if ((type === "env" || type === "secret") && rest.length > 0) {
|
|
83717
|
-
return assetPathForName(type,
|
|
83809
|
+
return assetPathForName(type, path30.join(c.root, head), rest);
|
|
83718
83810
|
}
|
|
83719
83811
|
}
|
|
83720
|
-
return
|
|
83812
|
+
return path30.join(c.root, posix);
|
|
83721
83813
|
},
|
|
83722
83814
|
directoryList() {
|
|
83723
83815
|
return [ENV_DIR, SECRETS_DIR];
|
|
@@ -83742,7 +83834,7 @@ var dotenvAdapter = {
|
|
|
83742
83834
|
init_frontmatter();
|
|
83743
83835
|
init_common();
|
|
83744
83836
|
init_recognition_util();
|
|
83745
|
-
import
|
|
83837
|
+
import path31 from "node:path";
|
|
83746
83838
|
var COMPONENT_ID5 = "main";
|
|
83747
83839
|
var DOCUMENT_EXTENSIONS = new Set([".md", ".markdown", ".txt", ".text"]);
|
|
83748
83840
|
function isReserved2(base3) {
|
|
@@ -83808,17 +83900,17 @@ var genericFilesAdapter = {
|
|
|
83808
83900
|
validate: validate6,
|
|
83809
83901
|
readCandidates(c, conceptId) {
|
|
83810
83902
|
const posix = toPosix(conceptId);
|
|
83811
|
-
const extension =
|
|
83903
|
+
const extension = path31.extname(posix).toLowerCase();
|
|
83812
83904
|
const documentCandidates = [...DOCUMENT_EXTENSIONS].map((candidateExtension) => ({
|
|
83813
|
-
path:
|
|
83905
|
+
path: path31.join(c.root, `${posix}${candidateExtension}`),
|
|
83814
83906
|
conceptId: posix
|
|
83815
83907
|
}));
|
|
83816
|
-
return DOCUMENT_EXTENSIONS.has(extension) ? documentCandidates : [{ path:
|
|
83908
|
+
return DOCUMENT_EXTENSIONS.has(extension) ? documentCandidates : [{ path: path31.join(c.root, posix), conceptId: posix }, ...documentCandidates];
|
|
83817
83909
|
},
|
|
83818
83910
|
placeNew(c, conceptId) {
|
|
83819
83911
|
const posix = toPosix(conceptId);
|
|
83820
|
-
const hasExt =
|
|
83821
|
-
return
|
|
83912
|
+
const hasExt = path31.extname(posix) !== "";
|
|
83913
|
+
return path31.join(c.root, hasExt ? posix : `${posix}.md`);
|
|
83822
83914
|
},
|
|
83823
83915
|
looksLikeRoot() {
|
|
83824
83916
|
return false;
|
|
@@ -83830,7 +83922,7 @@ init_dist();
|
|
|
83830
83922
|
init_frontmatter();
|
|
83831
83923
|
init_common();
|
|
83832
83924
|
import fs21 from "node:fs";
|
|
83833
|
-
import
|
|
83925
|
+
import path32 from "node:path";
|
|
83834
83926
|
var WIKI_COMPONENT_ID = "main";
|
|
83835
83927
|
var WIKI_SOURCE_TYPE = "wiki-source";
|
|
83836
83928
|
var DEFAULT_PAGE_KIND = "note";
|
|
@@ -83888,7 +83980,7 @@ function resolveXref(xref, bundleId) {
|
|
|
83888
83980
|
return target.length > 0 ? target : null;
|
|
83889
83981
|
}
|
|
83890
83982
|
function resolveBodyLinks(body, fileRelPath) {
|
|
83891
|
-
const dir =
|
|
83983
|
+
const dir = path32.posix.dirname(toPosix(fileRelPath));
|
|
83892
83984
|
const linkRe = /\[[^\]]*\]\(([^)]+)\)/g;
|
|
83893
83985
|
const out = [];
|
|
83894
83986
|
const seen = new Set;
|
|
@@ -83914,10 +84006,10 @@ function resolveBodyLinks(body, fileRelPath) {
|
|
|
83914
84006
|
continue;
|
|
83915
84007
|
let resolved;
|
|
83916
84008
|
if (target.startsWith("/")) {
|
|
83917
|
-
resolved =
|
|
84009
|
+
resolved = path32.posix.normalize(target.slice(1));
|
|
83918
84010
|
} else {
|
|
83919
84011
|
const base3 = dir === "." ? "" : dir;
|
|
83920
|
-
resolved =
|
|
84012
|
+
resolved = path32.posix.normalize(path32.posix.join(base3, target));
|
|
83921
84013
|
}
|
|
83922
84014
|
if (resolved.startsWith("../") || resolved === ".." || resolved.startsWith("/"))
|
|
83923
84015
|
continue;
|
|
@@ -84099,19 +84191,19 @@ var llmWikiAdapter = {
|
|
|
84099
84191
|
validate: validate7,
|
|
84100
84192
|
readCandidates(c, conceptId) {
|
|
84101
84193
|
const canonical = toPosix(conceptId).replace(/\.md$/i, "");
|
|
84102
|
-
return [{ path:
|
|
84194
|
+
return [{ path: path32.join(c.root, `${canonical}.md`), conceptId: canonical }];
|
|
84103
84195
|
},
|
|
84104
84196
|
placeNew(c, conceptId) {
|
|
84105
|
-
return
|
|
84197
|
+
return path32.join(c.root, `${conceptId}.md`);
|
|
84106
84198
|
},
|
|
84107
84199
|
directoryList(_c) {
|
|
84108
84200
|
return ["."];
|
|
84109
84201
|
},
|
|
84110
84202
|
looksLikeRoot(root) {
|
|
84111
84203
|
try {
|
|
84112
|
-
if (!fs21.existsSync(
|
|
84204
|
+
if (!fs21.existsSync(path32.join(root, "schema.md")))
|
|
84113
84205
|
return false;
|
|
84114
|
-
return fs21.statSync(
|
|
84206
|
+
return fs21.statSync(path32.join(root, PAGES_SUBDIR)).isDirectory();
|
|
84115
84207
|
} catch {
|
|
84116
84208
|
return false;
|
|
84117
84209
|
}
|
|
@@ -84122,7 +84214,7 @@ var llmWikiAdapter = {
|
|
|
84122
84214
|
init_frontmatter();
|
|
84123
84215
|
init_common();
|
|
84124
84216
|
import fs22 from "node:fs";
|
|
84125
|
-
import
|
|
84217
|
+
import path33 from "node:path";
|
|
84126
84218
|
var CONSUMED_FRONTMATTER_KEYS = [
|
|
84127
84219
|
"type",
|
|
84128
84220
|
"title",
|
|
@@ -84194,7 +84286,7 @@ function isReservedFileName2(name) {
|
|
|
84194
84286
|
return RESERVED_FILES.has(name.toLowerCase());
|
|
84195
84287
|
}
|
|
84196
84288
|
function resolveOkfLinks(body, fileRelPath) {
|
|
84197
|
-
const dir =
|
|
84289
|
+
const dir = path33.posix.dirname(toPosix(fileRelPath));
|
|
84198
84290
|
const definitions = new Map;
|
|
84199
84291
|
for (const match of body.matchAll(/^\s*\[([^\]]+)\]:\s*(\S+)/gm)) {
|
|
84200
84292
|
definitions.set(match[1].trim().toLowerCase(), match[2]);
|
|
@@ -84232,10 +84324,10 @@ function resolveOkfLinks(body, fileRelPath) {
|
|
|
84232
84324
|
continue;
|
|
84233
84325
|
let resolved;
|
|
84234
84326
|
if (target.startsWith("/")) {
|
|
84235
|
-
resolved =
|
|
84327
|
+
resolved = path33.posix.normalize(target.slice(1));
|
|
84236
84328
|
} else {
|
|
84237
84329
|
const base3 = dir === "." ? "" : dir;
|
|
84238
|
-
resolved =
|
|
84330
|
+
resolved = path33.posix.normalize(path33.posix.join(base3, target));
|
|
84239
84331
|
}
|
|
84240
84332
|
if (resolved.startsWith("../") || resolved === ".." || resolved.startsWith("/"))
|
|
84241
84333
|
continue;
|
|
@@ -84363,13 +84455,13 @@ var okfAdapter = {
|
|
|
84363
84455
|
validate: validate8,
|
|
84364
84456
|
readCandidates(c, conceptId) {
|
|
84365
84457
|
const canonical = conceptId.replace(/\\/g, "/").replace(/\.md$/i, "");
|
|
84366
|
-
return [{ path:
|
|
84458
|
+
return [{ path: path33.join(c.root, `${canonical}.md`), conceptId: canonical }];
|
|
84367
84459
|
},
|
|
84368
84460
|
directoryList(_c) {
|
|
84369
84461
|
return ["."];
|
|
84370
84462
|
},
|
|
84371
84463
|
looksLikeRoot(root) {
|
|
84372
|
-
if (fs22.existsSync(
|
|
84464
|
+
if (fs22.existsSync(path33.join(root, "index.md")))
|
|
84373
84465
|
return true;
|
|
84374
84466
|
const stack = [root];
|
|
84375
84467
|
while (stack.length > 0) {
|
|
@@ -84385,7 +84477,7 @@ var okfAdapter = {
|
|
|
84385
84477
|
for (const entry of entries) {
|
|
84386
84478
|
if (entry.isSymbolicLink() || entry.name === ".git")
|
|
84387
84479
|
continue;
|
|
84388
|
-
const absolute =
|
|
84480
|
+
const absolute = path33.join(current, entry.name);
|
|
84389
84481
|
if (entry.isDirectory()) {
|
|
84390
84482
|
stack.push(absolute);
|
|
84391
84483
|
continue;
|
|
@@ -84403,7 +84495,7 @@ var okfAdapter = {
|
|
|
84403
84495
|
|
|
84404
84496
|
// src/core/adapter/adapters/opencode-adapter.ts
|
|
84405
84497
|
import fs23 from "node:fs";
|
|
84406
|
-
import
|
|
84498
|
+
import path34 from "node:path";
|
|
84407
84499
|
var LAYOUT2 = {
|
|
84408
84500
|
adapterId: "opencode",
|
|
84409
84501
|
componentId: ".opencode",
|
|
@@ -84430,11 +84522,11 @@ function dirExists2(p) {
|
|
|
84430
84522
|
}
|
|
84431
84523
|
}
|
|
84432
84524
|
function opencodeLooksLikeRoot(root) {
|
|
84433
|
-
if (CONFIG_FILES.some((f) => fileExists(
|
|
84525
|
+
if (CONFIG_FILES.some((f) => fileExists(path34.join(root, f))))
|
|
84434
84526
|
return true;
|
|
84435
|
-
if (!fileExists(
|
|
84527
|
+
if (!fileExists(path34.join(root, "AGENTS.md")))
|
|
84436
84528
|
return false;
|
|
84437
|
-
return TOOL_DIRS.some((d) => dirExists2(
|
|
84529
|
+
return TOOL_DIRS.some((d) => dirExists2(path34.join(root, d)));
|
|
84438
84530
|
}
|
|
84439
84531
|
var opencodeAdapter = makeToolDirAdapter(LAYOUT2, opencodeLooksLikeRoot);
|
|
84440
84532
|
|
|
@@ -84443,7 +84535,7 @@ init_dist();
|
|
|
84443
84535
|
init_frontmatter();
|
|
84444
84536
|
init_common();
|
|
84445
84537
|
import fs24 from "node:fs";
|
|
84446
|
-
import
|
|
84538
|
+
import path35 from "node:path";
|
|
84447
84539
|
var COMPONENT_ID6 = "main";
|
|
84448
84540
|
var PAGES_PREFIX = "stash/knowledge/";
|
|
84449
84541
|
var MANIFEST_FILE = "manifest.json";
|
|
@@ -84531,12 +84623,12 @@ var websiteSnapshotAdapter = {
|
|
|
84531
84623
|
validate: validate9,
|
|
84532
84624
|
readCandidates(c, conceptId) {
|
|
84533
84625
|
const canonical = toPosix(conceptId).replace(/\.md$/i, "");
|
|
84534
|
-
return [{ path:
|
|
84626
|
+
return [{ path: path35.join(c.root, PAGES_PREFIX, `${canonical}.md`), conceptId: canonical }];
|
|
84535
84627
|
},
|
|
84536
84628
|
looksLikeRoot(root) {
|
|
84537
84629
|
let raw;
|
|
84538
84630
|
try {
|
|
84539
|
-
raw = fs24.readFileSync(
|
|
84631
|
+
raw = fs24.readFileSync(path35.join(root, MANIFEST_FILE), "utf8");
|
|
84540
84632
|
} catch {
|
|
84541
84633
|
return false;
|
|
84542
84634
|
}
|
|
@@ -84649,7 +84741,7 @@ function isSourceWriteActivated(source) {
|
|
|
84649
84741
|
|
|
84650
84742
|
// src/core/adapter/detect-adapter.ts
|
|
84651
84743
|
import fs25 from "node:fs";
|
|
84652
|
-
import
|
|
84744
|
+
import path36 from "node:path";
|
|
84653
84745
|
var SHADOWABLE_ADAPTER_IDS = new Set(["agent-skills", "claude", "opencode"]);
|
|
84654
84746
|
function hasExtraAkmContent(root, winnerId) {
|
|
84655
84747
|
const akm = adapterForId("akm");
|
|
@@ -84671,13 +84763,13 @@ function hasExtraAkmContent(root, winnerId) {
|
|
|
84671
84763
|
continue;
|
|
84672
84764
|
if (winnerId === "agent-skills") {
|
|
84673
84765
|
try {
|
|
84674
|
-
if (fs25.statSync(
|
|
84766
|
+
if (fs25.statSync(path36.join(root, entry.name, "SKILL.md")).isFile())
|
|
84675
84767
|
continue;
|
|
84676
84768
|
} catch {}
|
|
84677
84769
|
}
|
|
84678
84770
|
let children;
|
|
84679
84771
|
try {
|
|
84680
|
-
children = fs25.readdirSync(
|
|
84772
|
+
children = fs25.readdirSync(path36.join(root, entry.name), { withFileTypes: true });
|
|
84681
84773
|
} catch {
|
|
84682
84774
|
continue;
|
|
84683
84775
|
}
|
|
@@ -84702,48 +84794,7 @@ function detectAdapterId(root, fallback = "akm") {
|
|
|
84702
84794
|
|
|
84703
84795
|
// src/indexer/installations.ts
|
|
84704
84796
|
init_asset_placement();
|
|
84705
|
-
|
|
84706
|
-
// src/core/bundle-id.ts
|
|
84707
|
-
init_asset_ref();
|
|
84708
|
-
import crypto5 from "node:crypto";
|
|
84709
|
-
import path36 from "node:path";
|
|
84710
|
-
function slugForPath(sourcePath) {
|
|
84711
|
-
const resolved = path36.resolve(sourcePath);
|
|
84712
|
-
const base3 = path36.basename(resolved).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
84713
|
-
if (base3.length > 0)
|
|
84714
|
-
return base3;
|
|
84715
|
-
return `bundle-${shortHash(resolved)}`;
|
|
84716
|
-
}
|
|
84717
|
-
function deriveBundleId(registryId, sourcePath, usedIds) {
|
|
84718
|
-
const preferred = registryId && registryId.length > 0 && isBundleSlug(registryId) ? registryId : slugForPath(sourcePath);
|
|
84719
|
-
const id = ensureUniqueId(preferred, sourcePath, usedIds);
|
|
84720
|
-
usedIds.add(id);
|
|
84721
|
-
return id;
|
|
84722
|
-
}
|
|
84723
|
-
function deriveBundleIds(sources) {
|
|
84724
|
-
const usedIds = new Set;
|
|
84725
|
-
const reservedIds = new Set(sources.flatMap((source) => source.registryId && isBundleSlug(source.registryId) ? [source.registryId] : []));
|
|
84726
|
-
return sources.map((source) => {
|
|
84727
|
-
const id = source.registryId && isBundleSlug(source.registryId) ? deriveBundleId(source.registryId, source.path, usedIds) : deriveBundleId(undefined, source.path, new Set([...usedIds, ...reservedIds]));
|
|
84728
|
-
usedIds.add(id);
|
|
84729
|
-
return id;
|
|
84730
|
-
});
|
|
84731
|
-
}
|
|
84732
|
-
function ensureUniqueId(preferred, sourcePath, used) {
|
|
84733
|
-
if (!used.has(preferred))
|
|
84734
|
-
return preferred;
|
|
84735
|
-
const suffixed = `${preferred}-${shortHash(path36.resolve(sourcePath))}`;
|
|
84736
|
-
if (!used.has(suffixed))
|
|
84737
|
-
return suffixed;
|
|
84738
|
-
let n = 2;
|
|
84739
|
-
while (used.has(`${suffixed}-${n}`))
|
|
84740
|
-
n++;
|
|
84741
|
-
return `${suffixed}-${n}`;
|
|
84742
|
-
}
|
|
84743
|
-
function shortHash(input) {
|
|
84744
|
-
return crypto5.createHash("sha256").update(input).digest("hex").slice(0, 8);
|
|
84745
|
-
}
|
|
84746
|
-
// src/indexer/installations.ts
|
|
84797
|
+
init_bundle_id();
|
|
84747
84798
|
var FALLBACK_ADAPTER_ID = "akm";
|
|
84748
84799
|
function deriveInstallations(sources) {
|
|
84749
84800
|
const ids = deriveBundleIds(sources);
|
|
@@ -84782,6 +84833,7 @@ function deriveEntryProvenance(bundle, type, name, adapterConceptId) {
|
|
|
84782
84833
|
// src/indexer/search/search-source.ts
|
|
84783
84834
|
init_common();
|
|
84784
84835
|
import path49 from "node:path";
|
|
84836
|
+
init_paths();
|
|
84785
84837
|
|
|
84786
84838
|
// src/core/write-source.ts
|
|
84787
84839
|
import fs36 from "node:fs";
|
|
@@ -87752,6 +87804,7 @@ function buildGithubTargetAliases(canonicalUrl) {
|
|
|
87752
87804
|
// src/core/write-source.ts
|
|
87753
87805
|
init_asset_placement();
|
|
87754
87806
|
init_resolve_ref();
|
|
87807
|
+
init_bundle_id();
|
|
87755
87808
|
init_common();
|
|
87756
87809
|
init_errors();
|
|
87757
87810
|
init_warn();
|
|
@@ -92295,14 +92348,14 @@ function resolveSourceEntries(overrideStashDir, existingConfig) {
|
|
|
92295
92348
|
const component = bundleComponentConfig(config.bundles?.[entry.name ?? ""]);
|
|
92296
92349
|
const contentRoot = resolveEntryContentDir(entry);
|
|
92297
92350
|
if (contentRoot == null) {
|
|
92298
|
-
const unresolvedPath = path49.join(implicitStashDir ?? process.cwd(),
|
|
92351
|
+
const unresolvedPath = path49.join(getUnresolvedSourcesDir(implicitStashDir ?? process.cwd()), entry.name ?? entry.type);
|
|
92299
92352
|
addSource(unresolvedPath, entry.name, component?.writable ?? resolveWritable(entry), entry.type, component?.adapter, true);
|
|
92300
92353
|
continue;
|
|
92301
92354
|
}
|
|
92302
92355
|
const dir = path49.resolve(contentRoot, component?.root ?? ".");
|
|
92303
92356
|
if (!isWithin(dir, contentRoot)) {
|
|
92304
92357
|
warn(`Warning: component root "${component?.root}" escapes bundle "${entry.name}"; skipping source.`);
|
|
92305
|
-
const unresolvedPath = path49.join(contentRoot,
|
|
92358
|
+
const unresolvedPath = path49.join(getUnresolvedSourcesDir(contentRoot), entry.name ?? entry.type);
|
|
92306
92359
|
addSource(unresolvedPath, entry.name, component?.writable ?? resolveWritable(entry), entry.type, component?.adapter, true);
|
|
92307
92360
|
continue;
|
|
92308
92361
|
}
|
|
@@ -95472,31 +95525,178 @@ async function recoverStaleTxns(stashDir) {
|
|
|
95472
95525
|
return recovered.map(journalToEntry);
|
|
95473
95526
|
}
|
|
95474
95527
|
|
|
95528
|
+
// scripts/akm-migrate/migrate/writer-relocation.ts
|
|
95529
|
+
import fs48 from "node:fs";
|
|
95530
|
+
import path61 from "node:path";
|
|
95531
|
+
init_paths();
|
|
95532
|
+
function relocationSpecs(stashDir) {
|
|
95533
|
+
return [
|
|
95534
|
+
{ key: "distillRejected", oldRelative: "distill-rejected", newDir: getDistillRejectedDir(stashDir) },
|
|
95535
|
+
{ key: "evalCases", oldRelative: "eval-cases", newDir: getEvalCasesDir(stashDir) },
|
|
95536
|
+
{
|
|
95537
|
+
key: "measurementVerdicts",
|
|
95538
|
+
oldRelative: ["measurement", "verdicts"],
|
|
95539
|
+
newDir: getMeasurementVerdictsDir(stashDir)
|
|
95540
|
+
}
|
|
95541
|
+
];
|
|
95542
|
+
}
|
|
95543
|
+
var LOCK_NAMES = ["improve.lock", "consolidate.lock", "reflect-distill.lock", "triage.lock"];
|
|
95544
|
+
function mutexSiblingName(lockName) {
|
|
95545
|
+
return `.${lockName}.operations.sensitive`;
|
|
95546
|
+
}
|
|
95547
|
+
function fileCountIfExists(dir) {
|
|
95548
|
+
let entries;
|
|
95549
|
+
try {
|
|
95550
|
+
entries = fs48.readdirSync(dir, { withFileTypes: true });
|
|
95551
|
+
} catch {
|
|
95552
|
+
return;
|
|
95553
|
+
}
|
|
95554
|
+
return entries.filter((entry) => entry.isFile()).length;
|
|
95555
|
+
}
|
|
95556
|
+
function statFileIfExists(filePath) {
|
|
95557
|
+
try {
|
|
95558
|
+
const stat = fs48.statSync(filePath);
|
|
95559
|
+
return stat.isFile() ? stat : undefined;
|
|
95560
|
+
} catch {
|
|
95561
|
+
return;
|
|
95562
|
+
}
|
|
95563
|
+
}
|
|
95564
|
+
function classifyLockArtifacts(akmDir) {
|
|
95565
|
+
const removable = [];
|
|
95566
|
+
const skipped = [];
|
|
95567
|
+
for (const lockName of LOCK_NAMES) {
|
|
95568
|
+
const lockPath = path61.join(akmDir, lockName);
|
|
95569
|
+
const mutexPath = path61.join(akmDir, mutexSiblingName(lockName));
|
|
95570
|
+
const lockStat = statFileIfExists(lockPath);
|
|
95571
|
+
const mutexStat = statFileIfExists(mutexPath);
|
|
95572
|
+
if (!lockStat) {
|
|
95573
|
+
if (mutexStat)
|
|
95574
|
+
removable.push({ path: mutexPath, sizeBytes: mutexStat.size });
|
|
95575
|
+
continue;
|
|
95576
|
+
}
|
|
95577
|
+
const probe = probeLock(lockPath);
|
|
95578
|
+
if (probe.state === "held") {
|
|
95579
|
+
skipped.push({ path: lockPath, reason: "held", holderPid: probe.holderPid });
|
|
95580
|
+
continue;
|
|
95581
|
+
}
|
|
95582
|
+
if (probe.state === "inaccessible") {
|
|
95583
|
+
skipped.push({ path: lockPath, reason: "inaccessible" });
|
|
95584
|
+
continue;
|
|
95585
|
+
}
|
|
95586
|
+
if (probe.state === "absent")
|
|
95587
|
+
continue;
|
|
95588
|
+
removable.push({ path: lockPath, sizeBytes: lockStat.size });
|
|
95589
|
+
if (mutexStat)
|
|
95590
|
+
removable.push({ path: mutexPath, sizeBytes: mutexStat.size });
|
|
95591
|
+
}
|
|
95592
|
+
return { removable, skipped };
|
|
95593
|
+
}
|
|
95594
|
+
function findWriterRelocationEntries(stashDir) {
|
|
95595
|
+
const akmDir = path61.join(stashDir, ".akm");
|
|
95596
|
+
const directories = [];
|
|
95597
|
+
for (const spec of relocationSpecs(stashDir)) {
|
|
95598
|
+
const relativeParts = Array.isArray(spec.oldRelative) ? spec.oldRelative : [spec.oldRelative];
|
|
95599
|
+
const oldPath = path61.join(akmDir, ...relativeParts);
|
|
95600
|
+
const fileCount = fileCountIfExists(oldPath);
|
|
95601
|
+
if (fileCount === undefined || fileCount === 0)
|
|
95602
|
+
continue;
|
|
95603
|
+
directories.push({ key: spec.key, oldPath, newPath: spec.newDir, fileCount });
|
|
95604
|
+
}
|
|
95605
|
+
const { removable, skipped } = classifyLockArtifacts(akmDir);
|
|
95606
|
+
return { directories, lockArtifacts: removable, skippedLocks: skipped };
|
|
95607
|
+
}
|
|
95608
|
+
function moveFile(oldFilePath, newFilePath) {
|
|
95609
|
+
try {
|
|
95610
|
+
fs48.renameSync(oldFilePath, newFilePath);
|
|
95611
|
+
} catch (error2) {
|
|
95612
|
+
if (error2.code !== "EXDEV")
|
|
95613
|
+
throw error2;
|
|
95614
|
+
fs48.copyFileSync(oldFilePath, newFilePath);
|
|
95615
|
+
fs48.rmSync(oldFilePath, { force: true });
|
|
95616
|
+
}
|
|
95617
|
+
}
|
|
95618
|
+
function moveDirectoryContents(entry) {
|
|
95619
|
+
const errors3 = [];
|
|
95620
|
+
let moved = 0;
|
|
95621
|
+
fs48.mkdirSync(entry.newPath, { recursive: true });
|
|
95622
|
+
let names;
|
|
95623
|
+
try {
|
|
95624
|
+
names = fs48.readdirSync(entry.oldPath).sort();
|
|
95625
|
+
} catch {
|
|
95626
|
+
return { key: entry.key, oldPath: entry.oldPath, newPath: entry.newPath, moved: 0, errors: [] };
|
|
95627
|
+
}
|
|
95628
|
+
for (const name of names) {
|
|
95629
|
+
const oldFilePath = path61.join(entry.oldPath, name);
|
|
95630
|
+
const newFilePath = path61.join(entry.newPath, name);
|
|
95631
|
+
let oldStat;
|
|
95632
|
+
try {
|
|
95633
|
+
oldStat = fs48.lstatSync(oldFilePath);
|
|
95634
|
+
} catch {
|
|
95635
|
+
continue;
|
|
95636
|
+
}
|
|
95637
|
+
if (!oldStat.isFile())
|
|
95638
|
+
continue;
|
|
95639
|
+
if (fs48.existsSync(newFilePath))
|
|
95640
|
+
continue;
|
|
95641
|
+
try {
|
|
95642
|
+
moveFile(oldFilePath, newFilePath);
|
|
95643
|
+
moved += 1;
|
|
95644
|
+
} catch (error2) {
|
|
95645
|
+
errors3.push(`${name}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
95646
|
+
}
|
|
95647
|
+
}
|
|
95648
|
+
return { key: entry.key, oldPath: entry.oldPath, newPath: entry.newPath, moved, errors: errors3 };
|
|
95649
|
+
}
|
|
95650
|
+
function removeIfEmptyDir(dir) {
|
|
95651
|
+
try {
|
|
95652
|
+
if (fs48.readdirSync(dir).length === 0)
|
|
95653
|
+
fs48.rmdirSync(dir);
|
|
95654
|
+
} catch {}
|
|
95655
|
+
}
|
|
95656
|
+
function removeLockArtifact(entry) {
|
|
95657
|
+
try {
|
|
95658
|
+
fs48.rmSync(entry.path, { force: true });
|
|
95659
|
+
return { path: entry.path, removed: true };
|
|
95660
|
+
} catch (error2) {
|
|
95661
|
+
return { path: entry.path, removed: false, error: error2 instanceof Error ? error2.message : String(error2) };
|
|
95662
|
+
}
|
|
95663
|
+
}
|
|
95664
|
+
function applyWriterRelocation(stashDir) {
|
|
95665
|
+
const { directories, lockArtifacts, skippedLocks } = findWriterRelocationEntries(stashDir);
|
|
95666
|
+
const directoryResults = directories.map(moveDirectoryContents);
|
|
95667
|
+
const lockResults = lockArtifacts.map(removeLockArtifact);
|
|
95668
|
+
for (const spec of relocationSpecs(stashDir)) {
|
|
95669
|
+
const relativeParts = Array.isArray(spec.oldRelative) ? spec.oldRelative : [spec.oldRelative];
|
|
95670
|
+
removeIfEmptyDir(path61.join(stashDir, ".akm", ...relativeParts));
|
|
95671
|
+
}
|
|
95672
|
+
return { directories: directoryResults, lockArtifacts: lockResults, skippedLocks };
|
|
95673
|
+
}
|
|
95674
|
+
|
|
95475
95675
|
// scripts/akm-migrate/task-migrate.ts
|
|
95476
95676
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
95477
|
-
import
|
|
95677
|
+
import fs53 from "node:fs";
|
|
95478
95678
|
import os5 from "node:os";
|
|
95479
|
-
import
|
|
95679
|
+
import path64 from "node:path";
|
|
95480
95680
|
init_errors();
|
|
95481
95681
|
init_paths();
|
|
95482
95682
|
|
|
95483
95683
|
// scripts/akm-migrate/migrate/task-files-to-v3.ts
|
|
95484
95684
|
init_errors();
|
|
95485
95685
|
import crypto6 from "node:crypto";
|
|
95486
|
-
import
|
|
95487
|
-
import
|
|
95686
|
+
import fs50 from "node:fs";
|
|
95687
|
+
import path62 from "node:path";
|
|
95488
95688
|
|
|
95489
95689
|
// scripts/akm-migrate/migrate/durable-fs.ts
|
|
95490
|
-
import
|
|
95690
|
+
import fs49 from "node:fs";
|
|
95491
95691
|
function fsyncDirectoryPortable(directory) {
|
|
95492
95692
|
if (process.platform === "win32")
|
|
95493
95693
|
return;
|
|
95494
95694
|
try {
|
|
95495
|
-
const fd =
|
|
95695
|
+
const fd = fs49.openSync(directory, "r");
|
|
95496
95696
|
try {
|
|
95497
|
-
|
|
95697
|
+
fs49.fsyncSync(fd);
|
|
95498
95698
|
} finally {
|
|
95499
|
-
|
|
95699
|
+
fs49.closeSync(fd);
|
|
95500
95700
|
}
|
|
95501
95701
|
} catch (cause) {
|
|
95502
95702
|
const code = cause.code;
|
|
@@ -95510,25 +95710,25 @@ function migrationError(detail) {
|
|
|
95510
95710
|
return new ConfigError(`Task migration to v3 failed: ${detail}`, "INVALID_CONFIG_FILE");
|
|
95511
95711
|
}
|
|
95512
95712
|
function contained2(root, candidate) {
|
|
95513
|
-
const relative =
|
|
95514
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
95713
|
+
const relative = path62.relative(root, candidate);
|
|
95714
|
+
return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
|
|
95515
95715
|
}
|
|
95516
95716
|
function realDirectory(filePath) {
|
|
95517
|
-
const stat =
|
|
95717
|
+
const stat = fs50.lstatSync(filePath);
|
|
95518
95718
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
95519
95719
|
throw migrationError(`${filePath} must be a real directory.`);
|
|
95520
|
-
return
|
|
95720
|
+
return fs50.realpathSync(filePath);
|
|
95521
95721
|
}
|
|
95522
95722
|
function snapshot(filePath) {
|
|
95523
|
-
const stat =
|
|
95723
|
+
const stat = fs50.lstatSync(filePath);
|
|
95524
95724
|
if (stat.isSymbolicLink() || !stat.isFile())
|
|
95525
95725
|
throw migrationError(`${filePath} must be a real file.`);
|
|
95526
|
-
const bytes =
|
|
95726
|
+
const bytes = fs50.readFileSync(filePath);
|
|
95527
95727
|
return Object.freeze({ bytes, mode: stat.mode & 511 });
|
|
95528
95728
|
}
|
|
95529
95729
|
function writable(filePath) {
|
|
95530
95730
|
try {
|
|
95531
|
-
|
|
95731
|
+
fs50.accessSync(filePath, fs50.constants.W_OK);
|
|
95532
95732
|
return true;
|
|
95533
95733
|
} catch {
|
|
95534
95734
|
return false;
|
|
@@ -95541,12 +95741,12 @@ function walkTasks(root, tasksDir, out) {
|
|
|
95541
95741
|
throw migrationError(`${root.root} resolves outside bundle ${root.bundleId}.`);
|
|
95542
95742
|
}
|
|
95543
95743
|
const visit2 = (directory) => {
|
|
95544
|
-
const physicalDirectory =
|
|
95744
|
+
const physicalDirectory = fs50.realpathSync(directory);
|
|
95545
95745
|
if (!contained2(physicalRoot, physicalDirectory)) {
|
|
95546
95746
|
throw migrationError(`${directory} resolves outside bundle ${root.bundleId}.`);
|
|
95547
95747
|
}
|
|
95548
|
-
for (const entry of
|
|
95549
|
-
const candidate =
|
|
95748
|
+
for (const entry of fs50.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
95749
|
+
const candidate = path62.join(directory, entry.name);
|
|
95550
95750
|
if (entry.isSymbolicLink())
|
|
95551
95751
|
throw migrationError(`task migration does not follow symbolic link ${candidate}.`);
|
|
95552
95752
|
if (entry.isDirectory()) {
|
|
@@ -95556,7 +95756,7 @@ function walkTasks(root, tasksDir, out) {
|
|
|
95556
95756
|
if (!entry.isFile() || !entry.name.endsWith(".yml"))
|
|
95557
95757
|
continue;
|
|
95558
95758
|
const current = snapshot(candidate);
|
|
95559
|
-
const parent =
|
|
95759
|
+
const parent = path62.dirname(candidate);
|
|
95560
95760
|
out.push({
|
|
95561
95761
|
filePath: candidate,
|
|
95562
95762
|
bytes: current.bytes,
|
|
@@ -95572,9 +95772,9 @@ function walkTasks(root, tasksDir, out) {
|
|
|
95572
95772
|
function inspectTaskToV3Files(roots) {
|
|
95573
95773
|
const files = [];
|
|
95574
95774
|
for (const root of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
|
|
95575
|
-
const tasksDir = root.layout === "akm-task" ? root.root :
|
|
95775
|
+
const tasksDir = root.layout === "akm-task" ? root.root : path62.join(root.root, "tasks");
|
|
95576
95776
|
try {
|
|
95577
|
-
const stat =
|
|
95777
|
+
const stat = fs50.lstatSync(tasksDir);
|
|
95578
95778
|
if (stat.isSymbolicLink())
|
|
95579
95779
|
throw migrationError(`task migration does not follow symbolic link ${tasksDir}.`);
|
|
95580
95780
|
if (!stat.isDirectory())
|
|
@@ -95589,33 +95789,33 @@ function inspectTaskToV3Files(roots) {
|
|
|
95589
95789
|
return files.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
95590
95790
|
}
|
|
95591
95791
|
function hashPath(filePath) {
|
|
95592
|
-
return crypto6.createHash("sha256").update(
|
|
95792
|
+
return crypto6.createHash("sha256").update(path62.resolve(filePath)).digest("hex").slice(0, 16);
|
|
95593
95793
|
}
|
|
95594
95794
|
function taskMigrationBackupPath(backupRoot, filePath) {
|
|
95595
|
-
return
|
|
95795
|
+
return path62.join(backupRoot, "files", `${hashPath(filePath)}-${path62.basename(filePath)}`);
|
|
95596
95796
|
}
|
|
95597
95797
|
function writeDurable(filePath, bytes, mode, exclusive = false) {
|
|
95598
|
-
|
|
95798
|
+
fs50.mkdirSync(path62.dirname(filePath), { recursive: true });
|
|
95599
95799
|
const flags = exclusive ? "wx" : "w";
|
|
95600
|
-
const fd =
|
|
95800
|
+
const fd = fs50.openSync(filePath, flags, mode);
|
|
95601
95801
|
try {
|
|
95602
|
-
|
|
95603
|
-
|
|
95802
|
+
fs50.writeFileSync(fd, bytes);
|
|
95803
|
+
fs50.fsyncSync(fd);
|
|
95604
95804
|
} finally {
|
|
95605
|
-
|
|
95805
|
+
fs50.closeSync(fd);
|
|
95606
95806
|
}
|
|
95607
|
-
|
|
95608
|
-
fsyncDirectoryPortable(
|
|
95807
|
+
fs50.chmodSync(filePath, mode);
|
|
95808
|
+
fsyncDirectoryPortable(path62.dirname(filePath));
|
|
95609
95809
|
}
|
|
95610
95810
|
function replaceAtomically(filePath, bytes, mode) {
|
|
95611
|
-
const temporary =
|
|
95811
|
+
const temporary = path62.join(path62.dirname(filePath), `.${path62.basename(filePath)}.migrate-${crypto6.randomUUID()}`);
|
|
95612
95812
|
try {
|
|
95613
95813
|
writeDurable(temporary, bytes, mode, true);
|
|
95614
|
-
|
|
95615
|
-
fsyncDirectoryPortable(
|
|
95814
|
+
fs50.renameSync(temporary, filePath);
|
|
95815
|
+
fsyncDirectoryPortable(path62.dirname(filePath));
|
|
95616
95816
|
} finally {
|
|
95617
95817
|
try {
|
|
95618
|
-
|
|
95818
|
+
fs50.unlinkSync(temporary);
|
|
95619
95819
|
} catch (cause) {
|
|
95620
95820
|
if (cause.code !== "ENOENT")
|
|
95621
95821
|
throw cause;
|
|
@@ -95654,7 +95854,7 @@ function applyTaskToV3MigrationPlan(plan, options) {
|
|
|
95654
95854
|
const current = snapshot(change.filePath);
|
|
95655
95855
|
if (!current.bytes.equals(change.after))
|
|
95656
95856
|
continue;
|
|
95657
|
-
replaceAtomically(change.filePath,
|
|
95857
|
+
replaceAtomically(change.filePath, fs50.readFileSync(taskMigrationBackupPath(options.backupRoot, change.filePath)), change.mode);
|
|
95658
95858
|
}
|
|
95659
95859
|
throw cause;
|
|
95660
95860
|
}
|
|
@@ -95664,31 +95864,31 @@ function applyTaskToV3MigrationPlan(plan, options) {
|
|
|
95664
95864
|
// scripts/akm-migrate/migrate/task-files-to-v4.ts
|
|
95665
95865
|
init_errors();
|
|
95666
95866
|
import crypto7 from "node:crypto";
|
|
95667
|
-
import
|
|
95668
|
-
import
|
|
95867
|
+
import fs51 from "node:fs";
|
|
95868
|
+
import path63 from "node:path";
|
|
95669
95869
|
function migrationError2(detail) {
|
|
95670
95870
|
return new ConfigError(`Task migration to v4 failed: ${detail}`, "INVALID_CONFIG_FILE");
|
|
95671
95871
|
}
|
|
95672
95872
|
function contained3(root, candidate) {
|
|
95673
|
-
const relative =
|
|
95674
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
95873
|
+
const relative = path63.relative(root, candidate);
|
|
95874
|
+
return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
|
|
95675
95875
|
}
|
|
95676
95876
|
function realDirectory2(filePath) {
|
|
95677
|
-
const stat =
|
|
95877
|
+
const stat = fs51.lstatSync(filePath);
|
|
95678
95878
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
95679
95879
|
throw migrationError2(`${filePath} must be a real directory.`);
|
|
95680
|
-
return
|
|
95880
|
+
return fs51.realpathSync(filePath);
|
|
95681
95881
|
}
|
|
95682
95882
|
function snapshot2(filePath) {
|
|
95683
|
-
const stat =
|
|
95883
|
+
const stat = fs51.lstatSync(filePath);
|
|
95684
95884
|
if (stat.isSymbolicLink() || !stat.isFile())
|
|
95685
95885
|
throw migrationError2(`${filePath} must be a real file.`);
|
|
95686
|
-
const bytes =
|
|
95886
|
+
const bytes = fs51.readFileSync(filePath);
|
|
95687
95887
|
return Object.freeze({ bytes, mode: stat.mode & 511 });
|
|
95688
95888
|
}
|
|
95689
95889
|
function writable2(filePath) {
|
|
95690
95890
|
try {
|
|
95691
|
-
|
|
95891
|
+
fs51.accessSync(filePath, fs51.constants.W_OK);
|
|
95692
95892
|
return true;
|
|
95693
95893
|
} catch {
|
|
95694
95894
|
return false;
|
|
@@ -95701,12 +95901,12 @@ function walkTasks2(root, tasksDir, out) {
|
|
|
95701
95901
|
throw migrationError2(`${root.root} resolves outside bundle ${root.bundleId}.`);
|
|
95702
95902
|
}
|
|
95703
95903
|
const visit2 = (directory) => {
|
|
95704
|
-
const physicalDirectory =
|
|
95904
|
+
const physicalDirectory = fs51.realpathSync(directory);
|
|
95705
95905
|
if (!contained3(physicalRoot, physicalDirectory)) {
|
|
95706
95906
|
throw migrationError2(`${directory} resolves outside bundle ${root.bundleId}.`);
|
|
95707
95907
|
}
|
|
95708
|
-
for (const entry of
|
|
95709
|
-
const candidate =
|
|
95908
|
+
for (const entry of fs51.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
95909
|
+
const candidate = path63.join(directory, entry.name);
|
|
95710
95910
|
if (entry.isSymbolicLink())
|
|
95711
95911
|
throw migrationError2(`task migration does not follow symbolic link ${candidate}.`);
|
|
95712
95912
|
if (entry.isDirectory()) {
|
|
@@ -95716,7 +95916,7 @@ function walkTasks2(root, tasksDir, out) {
|
|
|
95716
95916
|
if (!entry.isFile() || !entry.name.endsWith(".yml"))
|
|
95717
95917
|
continue;
|
|
95718
95918
|
const current = snapshot2(candidate);
|
|
95719
|
-
const parent =
|
|
95919
|
+
const parent = path63.dirname(candidate);
|
|
95720
95920
|
out.push({
|
|
95721
95921
|
filePath: candidate,
|
|
95722
95922
|
bytes: current.bytes,
|
|
@@ -95732,9 +95932,9 @@ function walkTasks2(root, tasksDir, out) {
|
|
|
95732
95932
|
function inspectTaskToV4Files(roots) {
|
|
95733
95933
|
const files = [];
|
|
95734
95934
|
for (const root of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
|
|
95735
|
-
const tasksDir = root.layout === "akm-task" ? root.root :
|
|
95935
|
+
const tasksDir = root.layout === "akm-task" ? root.root : path63.join(root.root, "tasks");
|
|
95736
95936
|
try {
|
|
95737
|
-
const stat =
|
|
95937
|
+
const stat = fs51.lstatSync(tasksDir);
|
|
95738
95938
|
if (stat.isSymbolicLink())
|
|
95739
95939
|
throw migrationError2(`task migration does not follow symbolic link ${tasksDir}.`);
|
|
95740
95940
|
if (!stat.isDirectory())
|
|
@@ -95749,33 +95949,33 @@ function inspectTaskToV4Files(roots) {
|
|
|
95749
95949
|
return files.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
95750
95950
|
}
|
|
95751
95951
|
function hashPath2(filePath) {
|
|
95752
|
-
return crypto7.createHash("sha256").update(
|
|
95952
|
+
return crypto7.createHash("sha256").update(path63.resolve(filePath)).digest("hex").slice(0, 16);
|
|
95753
95953
|
}
|
|
95754
95954
|
function taskMigrationBackupPathV4(backupRoot, filePath) {
|
|
95755
|
-
return
|
|
95955
|
+
return path63.join(backupRoot, "files", `${hashPath2(filePath)}-${path63.basename(filePath)}`);
|
|
95756
95956
|
}
|
|
95757
95957
|
function writeDurable2(filePath, bytes, mode, exclusive = false) {
|
|
95758
|
-
|
|
95958
|
+
fs51.mkdirSync(path63.dirname(filePath), { recursive: true });
|
|
95759
95959
|
const flags = exclusive ? "wx" : "w";
|
|
95760
|
-
const fd =
|
|
95960
|
+
const fd = fs51.openSync(filePath, flags, mode);
|
|
95761
95961
|
try {
|
|
95762
|
-
|
|
95763
|
-
|
|
95962
|
+
fs51.writeFileSync(fd, bytes);
|
|
95963
|
+
fs51.fsyncSync(fd);
|
|
95764
95964
|
} finally {
|
|
95765
|
-
|
|
95965
|
+
fs51.closeSync(fd);
|
|
95766
95966
|
}
|
|
95767
|
-
|
|
95768
|
-
fsyncDirectoryPortable(
|
|
95967
|
+
fs51.chmodSync(filePath, mode);
|
|
95968
|
+
fsyncDirectoryPortable(path63.dirname(filePath));
|
|
95769
95969
|
}
|
|
95770
95970
|
function replaceAtomically2(filePath, bytes, mode) {
|
|
95771
|
-
const temporary =
|
|
95971
|
+
const temporary = path63.join(path63.dirname(filePath), `.${path63.basename(filePath)}.migrate-${crypto7.randomUUID()}`);
|
|
95772
95972
|
try {
|
|
95773
95973
|
writeDurable2(temporary, bytes, mode, true);
|
|
95774
|
-
|
|
95775
|
-
fsyncDirectoryPortable(
|
|
95974
|
+
fs51.renameSync(temporary, filePath);
|
|
95975
|
+
fsyncDirectoryPortable(path63.dirname(filePath));
|
|
95776
95976
|
} finally {
|
|
95777
95977
|
try {
|
|
95778
|
-
|
|
95978
|
+
fs51.unlinkSync(temporary);
|
|
95779
95979
|
} catch (cause) {
|
|
95780
95980
|
if (cause.code !== "ENOENT")
|
|
95781
95981
|
throw cause;
|
|
@@ -95814,7 +96014,7 @@ function applyTaskToV4MigrationPlan(plan, options) {
|
|
|
95814
96014
|
const current = snapshot2(change.filePath);
|
|
95815
96015
|
if (!current.bytes.equals(change.after))
|
|
95816
96016
|
continue;
|
|
95817
|
-
replaceAtomically2(change.filePath,
|
|
96017
|
+
replaceAtomically2(change.filePath, fs51.readFileSync(taskMigrationBackupPathV4(options.backupRoot, change.filePath)), change.mode);
|
|
95818
96018
|
}
|
|
95819
96019
|
throw cause;
|
|
95820
96020
|
}
|
|
@@ -95826,12 +96026,12 @@ function expandTilde(value) {
|
|
|
95826
96026
|
if (value === "~")
|
|
95827
96027
|
return os5.homedir();
|
|
95828
96028
|
if (value.startsWith("~/") || value.startsWith("~\\"))
|
|
95829
|
-
return
|
|
96029
|
+
return path64.join(os5.homedir(), value.slice(2));
|
|
95830
96030
|
return value;
|
|
95831
96031
|
}
|
|
95832
96032
|
function existingDirectory(target) {
|
|
95833
96033
|
try {
|
|
95834
|
-
return
|
|
96034
|
+
return fs53.statSync(target).isDirectory();
|
|
95835
96035
|
} catch (cause) {
|
|
95836
96036
|
if (cause.code === "ENOENT")
|
|
95837
96037
|
return false;
|
|
@@ -95852,21 +96052,21 @@ function taskRoots(config, resolutionBase = process.cwd()) {
|
|
|
95852
96052
|
const source = sources.get(bundleId);
|
|
95853
96053
|
if (!source)
|
|
95854
96054
|
continue;
|
|
95855
|
-
const configuredRoot = source.type === "filesystem" && source.path ?
|
|
96055
|
+
const configuredRoot = source.type === "filesystem" && source.path ? path64.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
|
|
95856
96056
|
if (!configuredRoot || !existingDirectory(configuredRoot))
|
|
95857
96057
|
continue;
|
|
95858
|
-
const bundleRoot =
|
|
96058
|
+
const bundleRoot = path64.resolve(configuredRoot);
|
|
95859
96059
|
const component = bundleComponentConfig(bundle);
|
|
95860
|
-
const componentRoot =
|
|
95861
|
-
const relative =
|
|
95862
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
96060
|
+
const componentRoot = path64.resolve(bundleRoot, component?.root ?? ".");
|
|
96061
|
+
const relative = path64.relative(bundleRoot, componentRoot);
|
|
96062
|
+
if (relative === ".." || relative.startsWith(`..${path64.sep}`) || path64.isAbsolute(relative)) {
|
|
95863
96063
|
throw new ConfigError(`Task migration component root ${componentRoot} escapes bundle ${bundleId} at ${bundleRoot}.`, "INVALID_CONFIG_FILE");
|
|
95864
96064
|
}
|
|
95865
96065
|
if (!existingDirectory(componentRoot))
|
|
95866
96066
|
continue;
|
|
95867
96067
|
const adapter = component?.adapter ?? detectAdapterId(componentRoot, "");
|
|
95868
96068
|
if (!component?.adapter && adapter === "") {
|
|
95869
|
-
const flatTasks =
|
|
96069
|
+
const flatTasks = fs53.readdirSync(componentRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".yml")).map((entry) => entry.name).sort();
|
|
95870
96070
|
if (flatTasks.length > 0) {
|
|
95871
96071
|
throw new ConfigError(`Task migration cannot classify top-level task file(s) ${flatTasks.join(", ")} in bundle ${bundleId}; configure adapter "akm-task" or move them under tasks/.`, "INVALID_CONFIG_FILE");
|
|
95872
96072
|
}
|
|
@@ -95938,8 +96138,8 @@ function applyTaskV3Migration() {
|
|
|
95938
96138
|
const before = inspectCurrentTaskPlan();
|
|
95939
96139
|
if (before.result.taskV3Migration.changed === 0)
|
|
95940
96140
|
return before.result;
|
|
95941
|
-
const backupRoot =
|
|
95942
|
-
const backupPath =
|
|
96141
|
+
const backupRoot = path64.join(getDataDir(), "backups", "task-v3");
|
|
96142
|
+
const backupPath = path64.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
|
|
95943
96143
|
const applied = applyTaskToV3MigrationPlan(before.plan, { backupRoot: backupPath });
|
|
95944
96144
|
const after = inspectCurrentTaskPlan().result;
|
|
95945
96145
|
if (after.taskV3Migration.changed > 0) {
|
|
@@ -95995,8 +96195,8 @@ function applyTaskV4Migration() {
|
|
|
95995
96195
|
const before = inspectCurrentTaskV4Plan();
|
|
95996
96196
|
if (before.result.taskV4Migration.changed === 0)
|
|
95997
96197
|
return before.result;
|
|
95998
|
-
const backupRoot =
|
|
95999
|
-
const backupPath =
|
|
96198
|
+
const backupRoot = path64.join(getDataDir(), "backups", "task-v4");
|
|
96199
|
+
const backupPath = path64.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
|
|
96000
96200
|
const applied = applyTaskToV4MigrationPlan(before.plan, { backupRoot: backupPath });
|
|
96001
96201
|
const after = inspectCurrentTaskV4Plan().result;
|
|
96002
96202
|
if (after.taskV4Migration.changed > 0) {
|
|
@@ -96024,6 +96224,22 @@ function stashDirIfConfigured() {
|
|
|
96024
96224
|
throw error2;
|
|
96025
96225
|
}
|
|
96026
96226
|
}
|
|
96227
|
+
function writerRelocationTargets(defaultStashDir) {
|
|
96228
|
+
const config = loadConfig();
|
|
96229
|
+
const seen = new Set;
|
|
96230
|
+
const targets = [];
|
|
96231
|
+
if (defaultStashDir !== undefined) {
|
|
96232
|
+
targets.push({ id: bundleKeyForContentRoot(config, defaultStashDir) ?? "default", dir: defaultStashDir });
|
|
96233
|
+
seen.add(defaultStashDir);
|
|
96234
|
+
}
|
|
96235
|
+
for (const { id, contentRoot } of bundleContentRoots(config)) {
|
|
96236
|
+
if (seen.has(contentRoot))
|
|
96237
|
+
continue;
|
|
96238
|
+
seen.add(contentRoot);
|
|
96239
|
+
targets.push({ id, dir: contentRoot });
|
|
96240
|
+
}
|
|
96241
|
+
return targets;
|
|
96242
|
+
}
|
|
96027
96243
|
async function runMigration(options) {
|
|
96028
96244
|
const { apply } = options;
|
|
96029
96245
|
const configPath = getConfigPath();
|
|
@@ -96044,10 +96260,15 @@ async function runMigration(options) {
|
|
|
96044
96260
|
const stashDir = stashDirIfConfigured();
|
|
96045
96261
|
const taskV3 = apply ? applyTaskV3Migration() : inspectMigrationPlan();
|
|
96046
96262
|
const taskV4 = apply ? applyTaskV4Migration() : inspectTaskV4MigrationStatus();
|
|
96047
|
-
const stashSections =
|
|
96048
|
-
|
|
96049
|
-
|
|
96050
|
-
|
|
96263
|
+
const stashSections = {};
|
|
96264
|
+
if (stashDir !== undefined) {
|
|
96265
|
+
stashSections.deadResidue = apply ? { removed: removeDeadResidue(stashDir) } : { pending: findDeadResidueEntries(stashDir) };
|
|
96266
|
+
stashSections.staleTxns = apply ? { recovered: await recoverStaleTxns(stashDir) } : { pending: findStaleTxnEntries(stashDir) };
|
|
96267
|
+
}
|
|
96268
|
+
const relocationTargets = writerRelocationTargets(stashDir);
|
|
96269
|
+
if (relocationTargets.length > 0) {
|
|
96270
|
+
stashSections.writerRelocation = apply ? { relocated: Object.fromEntries(relocationTargets.map(({ id, dir }) => [id, applyWriterRelocation(dir)])) } : { pending: Object.fromEntries(relocationTargets.map(({ id, dir }) => [id, findWriterRelocationEntries(dir)])) };
|
|
96271
|
+
}
|
|
96051
96272
|
const stateStatus = "pending" in stateMigrations && stateMigrations.pending.length > 0 ? "ready" : "current";
|
|
96052
96273
|
return {
|
|
96053
96274
|
schemaVersion: 1,
|