akm-cli 0.9.4 → 0.9.6
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 +265 -0
- package/dist/commands/env/env-cli.js +1 -2
- package/dist/commands/env/secret-cli.js +1 -5
- package/dist/commands/feedback-cli.js +0 -4
- package/dist/commands/health/checks.js +0 -32
- package/dist/commands/health/surfaces.js +2 -2
- package/dist/commands/health.js +6 -15
- package/dist/commands/improve/anti-collapse.js +4 -91
- package/dist/commands/improve/autonomy-gate.js +1 -1
- package/dist/commands/improve/consolidate.js +25 -26
- package/dist/commands/improve/distill.js +2 -2
- package/dist/commands/improve/extract.js +8 -1
- package/dist/commands/improve/improve.js +3 -5
- package/dist/commands/improve/locks.js +13 -5
- package/dist/commands/improve/loop-stages.js +8 -9
- package/dist/commands/improve/memory/memory-contradiction-detect.js +1 -19
- package/dist/commands/improve/outcome-loop.js +0 -6
- package/dist/commands/improve/reflect.js +20 -9
- package/dist/commands/lint/index.js +4 -6
- package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -7
- package/dist/commands/proposal/validators/proposal-validators.js +12 -0
- package/dist/commands/read/search.js +14 -24
- package/dist/commands/sources/bundle-config-ops.js +9 -4
- package/dist/commands/sources/info.js +14 -10
- package/dist/commands/tasks/tasks-cli.js +56 -3
- package/dist/commands/tasks/tasks.js +101 -18
- package/dist/commands/workflow-cli.js +2 -2
- package/dist/core/adapter/adapters/akm-adapter.js +2 -0
- package/dist/core/common.js +61 -24
- package/dist/core/config/config-io.js +2 -2
- package/dist/core/config/config-sources.js +32 -2
- package/dist/core/config/config-version-shim.js +101 -0
- package/dist/core/config/config.js +7 -7
- package/dist/core/config/schema/engines.js +9 -7
- package/dist/core/config/schema/primitives.js +0 -5
- package/dist/core/config/schema/search.js +2 -1
- package/dist/core/file-lock.js +2 -1
- package/dist/core/improve-result.js +35 -14
- package/dist/core/maintenance-barrier.js +2 -14
- package/dist/core/paths.js +0 -3
- package/dist/core/redaction.js +2 -2
- package/dist/core/spawn-env.js +8 -12
- package/dist/core/state/migrations.js +1 -12
- package/dist/core/state-db.js +9 -27
- package/dist/core/write-source.js +12 -19
- package/dist/execution/directory-identity.js +36 -10
- package/dist/execution/guarded-source.js +0 -10
- package/dist/indexer/graph/graph-boost.js +0 -4
- package/dist/indexer/index-writer-lock.js +43 -24
- package/dist/indexer/index-written-assets.js +5 -6
- package/dist/indexer/indexer.js +2 -39
- package/dist/indexer/materialize-embeddings.js +85 -41
- package/dist/indexer/passes/metadata.js +12 -4
- package/dist/indexer/scan/doc-to-entry.js +2 -0
- package/dist/indexer/search/db-search.js +15 -48
- package/dist/indexer/search/ranking-contributors.js +0 -25
- package/dist/indexer/search/ranking.js +3 -13
- package/dist/indexer/search/search-fields.js +16 -1
- package/dist/integrations/agent/builder-shared.js +0 -25
- package/dist/integrations/agent/model-map.js +2 -60
- package/dist/integrations/harnesses/aider/agent-builder.js +1 -3
- package/dist/integrations/harnesses/amazonq/agent-builder.js +2 -7
- package/dist/integrations/harnesses/claude/agent-builder.js +1 -4
- package/dist/integrations/harnesses/codex/agent-builder.js +1 -4
- package/dist/integrations/harnesses/copilot/agent-builder.js +2 -6
- package/dist/integrations/harnesses/gemini/agent-builder.js +2 -7
- package/dist/integrations/harnesses/opencode/agent-builder.js +1 -4
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +2 -16
- package/dist/integrations/harnesses/openhands/agent-builder.js +1 -3
- package/dist/integrations/harnesses/pi/agent-builder.js +2 -4
- package/dist/integrations/session-logs/index.js +0 -9
- package/dist/llm/client.js +75 -42
- package/dist/llm/embedder.js +7 -3
- package/dist/llm/embedders/remote.js +141 -42
- package/dist/output/shapes/passthrough.js +17 -5
- package/dist/registry/network.js +5 -37
- package/dist/runtime.js +2 -10
- package/dist/scripts/akm-migrate-node.js +180 -238
- package/dist/scripts/akm-migrate.js +180 -238
- package/dist/setup/engine-config.js +2 -5
- package/dist/setup/registry-stash-loader.js +0 -8
- package/dist/setup/setup.js +9 -46
- package/dist/setup/steps/connection-shared.js +10 -13
- package/dist/sources/providers/git-install.js +1 -1
- package/dist/storage/engines/sqlite-migrations.js +20 -1
- package/dist/storage/repositories/index-entries-repository.js +0 -15
- package/dist/storage/repositories/proposals-repository.js +32 -6
- package/dist/tasks/backends/launchd.js +15 -20
- package/dist/tasks/backends/schtasks.js +18 -8
- package/dist/tasks/run/run-native-task.js +8 -6
- package/dist/tasks/scheduler-binding.js +15 -5
- package/dist/tasks/scheduler-sync-preview.js +4 -2
- package/dist/tasks/scheduler-sync.js +77 -42
- package/dist/tasks/source/bounded-document.js +2 -4
- package/dist/tasks/source/task-source-v3-frozen.js +5 -7
- package/dist/tasks/source/task-source-v4.js +5 -10
- package/dist/tasks/source/task-to-v3.js +29 -22
- package/dist/tasks/source/task-to-v4.js +1 -14
- package/dist/tasks/source-v3.js +6 -6
- package/dist/workflows/exec/native-executor.js +21 -31
- package/dist/workflows/exec/run-workflow.js +5 -6
- package/dist/workflows/exec/scheduler.js +3 -19
- package/dist/workflows/exec/step-work.js +1 -4
- package/dist/workflows/exec/unit-dispatch.js +2 -2
- package/dist/workflows/exec/worktree.js +1 -13
- package/dist/workflows/freeze/targets/child-workflow.js +2 -10
- package/dist/workflows/ir/plan-hash.js +4 -6
- package/dist/workflows/ir/schema-v4.js +0 -12
- package/dist/workflows/ir/schema.js +20 -31
- package/dist/workflows/parser.js +11 -52
- package/dist/workflows/renderer.js +2 -3
- package/dist/workflows/resource-limits.js +11 -41
- package/dist/workflows/runtime/runs.js +3 -4
- package/dist/workflows/source-ir/schema.js +14 -30
- package/dist/workflows/validator.js +1 -7
- package/docs/reference/cli.md +25 -3
- package/docs/reference/configuration.md +28 -7
- package/docs/reference/tasks.md +10 -0
- package/package.json +1 -1
- package/schemas/akm-config.json +4 -23
- package/schemas/akm-task.json +1 -2
- package/schemas/akm-workflow.json +1 -13
- package/dist/indexer/search/semantic-status.js +0 -142
|
@@ -9380,8 +9380,6 @@ function getRegistryIndexCacheDir() {
|
|
|
9380
9380
|
}
|
|
9381
9381
|
|
|
9382
9382
|
// src/core/common.ts
|
|
9383
|
-
var MAX_CONFIG_FILE_BYTES = 1024 * 1024;
|
|
9384
|
-
var MAX_LOCAL_METADATA_BYTES = 1024 * 1024;
|
|
9385
9383
|
var MAX_LOCK_METADATA_BYTES = 64 * 1024;
|
|
9386
9384
|
function readTextFileDescriptorWithLimit(fd, maxBytes, label = "File", displayPath = "(open file)") {
|
|
9387
9385
|
const stat = fs.fstatSync(fd);
|
|
@@ -9403,10 +9401,13 @@ function readTextFileDescriptorWithLimit(fd, maxBytes, label = "File", displayPa
|
|
|
9403
9401
|
}
|
|
9404
9402
|
return buffer.subarray(0, total).toString("utf8");
|
|
9405
9403
|
}
|
|
9406
|
-
function
|
|
9404
|
+
function readTextFile(filePath, label = "File") {
|
|
9407
9405
|
const fd = fs.openSync(filePath, "r");
|
|
9408
9406
|
try {
|
|
9409
|
-
|
|
9407
|
+
const stat = fs.fstatSync(fd);
|
|
9408
|
+
if (!stat.isFile())
|
|
9409
|
+
throw new ConfigError(`${label} is not a regular file: ${filePath}.`, "INVALID_CONFIG_FILE");
|
|
9410
|
+
return fs.readFileSync(fd, "utf8");
|
|
9410
9411
|
} finally {
|
|
9411
9412
|
fs.closeSync(fd);
|
|
9412
9413
|
}
|
|
@@ -9506,6 +9507,8 @@ function asNonEmptyString(value) {
|
|
|
9506
9507
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
9507
9508
|
}
|
|
9508
9509
|
function isProcessAlive(pid) {
|
|
9510
|
+
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0)
|
|
9511
|
+
return false;
|
|
9509
9512
|
try {
|
|
9510
9513
|
process.kill(pid, 0);
|
|
9511
9514
|
return true;
|
|
@@ -10067,11 +10070,13 @@ function makeStampHandler(command) {
|
|
|
10067
10070
|
if (typeof result !== "object" || Array.isArray(result))
|
|
10068
10071
|
return result;
|
|
10069
10072
|
const obj = result;
|
|
10070
|
-
if (obj.shape
|
|
10071
|
-
obj
|
|
10072
|
-
|
|
10073
|
-
obj
|
|
10074
|
-
|
|
10073
|
+
if (obj.shape !== undefined && obj.schemaVersion !== undefined)
|
|
10074
|
+
return obj;
|
|
10075
|
+
return {
|
|
10076
|
+
...obj,
|
|
10077
|
+
shape: obj.shape ?? command,
|
|
10078
|
+
schemaVersion: obj.schemaVersion ?? 1
|
|
10079
|
+
};
|
|
10075
10080
|
};
|
|
10076
10081
|
}
|
|
10077
10082
|
var PASSTHROUGH_COMMANDS = [
|
|
@@ -10111,6 +10116,7 @@ var PASSTHROUGH_COMMANDS = [
|
|
|
10111
10116
|
"task-doctor",
|
|
10112
10117
|
"task-explain",
|
|
10113
10118
|
"task-history",
|
|
10119
|
+
"task-prune",
|
|
10114
10120
|
"task-run",
|
|
10115
10121
|
"task-sync",
|
|
10116
10122
|
"task-sync-dry-run",
|
|
@@ -13024,8 +13030,17 @@ import path8 from "node:path";
|
|
|
13024
13030
|
// src/core/warn.ts
|
|
13025
13031
|
import fs4 from "node:fs";
|
|
13026
13032
|
var quiet = false;
|
|
13033
|
+
var verbose = false;
|
|
13027
13034
|
var logFilePath;
|
|
13028
13035
|
var sinkOverride;
|
|
13036
|
+
function isVerbose() {
|
|
13037
|
+
const env = process.env.AKM_VERBOSE?.trim().toLowerCase();
|
|
13038
|
+
if (env === "1" || env === "true" || env === "yes" || env === "on")
|
|
13039
|
+
return true;
|
|
13040
|
+
if (env === "0" || env === "false" || env === "no" || env === "off")
|
|
13041
|
+
return false;
|
|
13042
|
+
return verbose;
|
|
13043
|
+
}
|
|
13029
13044
|
function appendToLogFile(level, args) {
|
|
13030
13045
|
if (!logFilePath)
|
|
13031
13046
|
return;
|
|
@@ -13051,6 +13066,15 @@ function warn(...args) {
|
|
|
13051
13066
|
console.warn(...args);
|
|
13052
13067
|
}
|
|
13053
13068
|
}
|
|
13069
|
+
function warnVerbose(...args) {
|
|
13070
|
+
if (sinkOverride) {
|
|
13071
|
+
sinkOverride("warnVerbose", args);
|
|
13072
|
+
return;
|
|
13073
|
+
}
|
|
13074
|
+
if (isVerbose()) {
|
|
13075
|
+
warn(...args);
|
|
13076
|
+
}
|
|
13077
|
+
}
|
|
13054
13078
|
|
|
13055
13079
|
// src/indexer/passes/metadata.ts
|
|
13056
13080
|
var SCOPE_KEYS = ["user", "agent", "run", "channel"];
|
|
@@ -13766,7 +13790,7 @@ function stripMarkdownLinkDestinations(text, nesting = 0) {
|
|
|
13766
13790
|
}
|
|
13767
13791
|
return visible;
|
|
13768
13792
|
}
|
|
13769
|
-
function projectMarkdownContent(body) {
|
|
13793
|
+
function projectMarkdownContent(body, truncationInfo) {
|
|
13770
13794
|
const lines = body.split(/\r?\n/);
|
|
13771
13795
|
const innerBlock = findInnerFrontmatterBlock(lines);
|
|
13772
13796
|
const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
|
|
@@ -13812,6 +13836,8 @@ function projectMarkdownContent(body) {
|
|
|
13812
13836
|
const text = projected.join(" ").replace(/\s+/g, " ").trim();
|
|
13813
13837
|
if (!text)
|
|
13814
13838
|
return;
|
|
13839
|
+
if (truncationInfo)
|
|
13840
|
+
truncationInfo.truncated = text.length > MARKDOWN_CONTENT_MAX_CHARS;
|
|
13815
13841
|
return truncateUnicodeSafe(text, MARKDOWN_CONTENT_MAX_CHARS);
|
|
13816
13842
|
}
|
|
13817
13843
|
function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
@@ -13835,9 +13861,15 @@ function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
|
13835
13861
|
applyWikiFrontmatter(entry, parsed.data);
|
|
13836
13862
|
applyProvenanceFrontmatter(entry, parsed.data);
|
|
13837
13863
|
if (entry.type !== "env" && entry.type !== "session" && !hasSessionMemoryMarker(parsed.data, parsed.content)) {
|
|
13838
|
-
const
|
|
13839
|
-
|
|
13864
|
+
const truncationInfo = { truncated: false };
|
|
13865
|
+
const contentProjection = projectMarkdownContent(parsed.content, truncationInfo);
|
|
13866
|
+
if (contentProjection) {
|
|
13840
13867
|
entry.content = contentProjection;
|
|
13868
|
+
if (truncationInfo.truncated) {
|
|
13869
|
+
entry.contentTruncated = true;
|
|
13870
|
+
warnVerbose(`${file}: indexed content truncated to ${MARKDOWN_CONTENT_MAX_CHARS} chars`);
|
|
13871
|
+
}
|
|
13872
|
+
}
|
|
13841
13873
|
}
|
|
13842
13874
|
if (entry.type === "command") {
|
|
13843
13875
|
const cmdParams = extractCommandParameters(parsed.content);
|
|
@@ -14928,25 +14960,13 @@ var EXECUTION_MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
|
14928
14960
|
// src/workflows/resource-limits.ts
|
|
14929
14961
|
var WORKFLOW_MAX_PLAN_BYTES = 2 * 1024 * 1024;
|
|
14930
14962
|
var WORKFLOW_MAX_SOURCE_BYTES = 1024 * 1024;
|
|
14931
|
-
var WORKFLOW_MAX_STEPS = 256;
|
|
14932
|
-
var WORKFLOW_MAX_PARAMS = 128;
|
|
14933
|
-
var WORKFLOW_MAX_ROUTE_BRANCHES = 256;
|
|
14934
14963
|
var WORKFLOW_MAX_INSTRUCTION_BYTES = 256 * 1024;
|
|
14935
14964
|
var WORKFLOW_MAX_SCHEMA_BYTES = 256 * 1024;
|
|
14936
14965
|
var WORKFLOW_MAX_EXTRA_PARAMS_BYTES = 64 * 1024;
|
|
14937
|
-
var WORKFLOW_MAX_MAP_EXPANSION = 1e4;
|
|
14938
|
-
var WORKFLOW_MAX_INPUTS = 64;
|
|
14939
|
-
var WORKFLOW_MAX_OUTPUTS = 64;
|
|
14940
14966
|
var WORKFLOW_MAX_CONCURRENCY = 64;
|
|
14941
|
-
var WORKFLOW_MAX_GATE_LOOPS = 100;
|
|
14942
|
-
var WORKFLOW_MAX_RETRIES = 100;
|
|
14943
14967
|
var WORKFLOW_MAX_TIMEOUT_MS = EXECUTION_MAX_TIMEOUT_MS;
|
|
14944
14968
|
var WORKFLOW_ENGINE_NAME_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
14945
14969
|
var WORKFLOW_MAX_ENGINE_NAME_LENGTH = 63;
|
|
14946
|
-
var WORKFLOW_MAX_EXEC_ARGV = 64;
|
|
14947
|
-
var WORKFLOW_MAX_EXEC_ARG_BYTES = 4096;
|
|
14948
|
-
var WORKFLOW_MAX_EXEC_CWD_LENGTH = 1024;
|
|
14949
|
-
var WORKFLOW_MAX_EXEC_PASS_ENV = 32;
|
|
14950
14970
|
var WORKFLOW_ENV_VAR_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
14951
14971
|
var WORKFLOW_MAX_EXEC_OUTPUT_BYTES = 8 * 1024 * 1024;
|
|
14952
14972
|
var EXEC_CONTEXT_LIMITS_POSIX = {
|
|
@@ -14964,13 +14984,13 @@ function jsonBytes(value) {
|
|
|
14964
14984
|
var WORKFLOW_MAX_EMBEDDED_CHILD_PLAN_BYTES = 1024 * 1024;
|
|
14965
14985
|
|
|
14966
14986
|
// src/tasks/source/bounded-document.ts
|
|
14967
|
-
var TASK_V3_MAX_SOURCE_BYTES = 1024 * 1024;
|
|
14968
14987
|
var TASK_V3_MAX_JSON_DEPTH = 64;
|
|
14969
14988
|
var TASK_V3_MAX_JSON_NODES = 1e4;
|
|
14970
14989
|
var TASK_V3_MAX_COLLECTION_ITEMS = 1024;
|
|
14971
14990
|
var TASK_V3_MAX_OBJECT_KEYS = 256;
|
|
14972
14991
|
var TASK_V3_MAX_STRING_BYTES = 256 * 1024;
|
|
14973
14992
|
var TASK_V3_MAX_SCHEDULES = 64;
|
|
14993
|
+
var TASK_V3_MAX_REDACT_NAMES = 32;
|
|
14974
14994
|
function own2(value, key) {
|
|
14975
14995
|
return Object.hasOwn(value, key);
|
|
14976
14996
|
}
|
|
@@ -15259,9 +15279,6 @@ function readBoundedTaskSourceYaml(input, options) {
|
|
|
15259
15279
|
if (typeof input.yaml !== "string") {
|
|
15260
15280
|
throw new UsageError(`Invalid ${sourceLabel} at ${input.filePath}: source must be a string.`, "TASK_SOURCE_INVALID");
|
|
15261
15281
|
}
|
|
15262
|
-
if (utf8Bytes2(input.yaml) > TASK_V3_MAX_SOURCE_BYTES) {
|
|
15263
|
-
throw new UsageError(`Invalid ${sourceLabel} at ${input.filePath}: source exceeds the 1 MiB (${TASK_V3_MAX_SOURCE_BYTES}-byte) resource limit.`, "TASK_SOURCE_INVALID");
|
|
15264
|
-
}
|
|
15265
15282
|
const lineCounter2 = new $LineCounter;
|
|
15266
15283
|
let document;
|
|
15267
15284
|
try {
|
|
@@ -16021,7 +16038,7 @@ function parseExecutionControls(input, ctx) {
|
|
|
16021
16038
|
out.timeout = parseTimeoutTopLevel(input.timeout, ctx);
|
|
16022
16039
|
if (own2(input, "redact")) {
|
|
16023
16040
|
const names = parseStringArray(input.redact, ctx, ["redact"], {
|
|
16024
|
-
max:
|
|
16041
|
+
max: TASK_V3_MAX_REDACT_NAMES,
|
|
16025
16042
|
pattern: WORKFLOW_ENV_VAR_NAME_PATTERN
|
|
16026
16043
|
});
|
|
16027
16044
|
if (new Set(names).size !== names.length)
|
|
@@ -16035,8 +16052,8 @@ function parseExecutionControls(input, ctx) {
|
|
|
16035
16052
|
out.maxSteps = input.maxSteps;
|
|
16036
16053
|
}
|
|
16037
16054
|
if (own2(input, "maxRetries")) {
|
|
16038
|
-
if (!Number.isSafeInteger(input.maxRetries) || input.maxRetries < 0
|
|
16039
|
-
sourceError(ctx, ["maxRetries"],
|
|
16055
|
+
if (!Number.isSafeInteger(input.maxRetries) || input.maxRetries < 0) {
|
|
16056
|
+
sourceError(ctx, ["maxRetries"], "must be a non-negative safe integer.");
|
|
16040
16057
|
}
|
|
16041
16058
|
out.maxRetries = input.maxRetries;
|
|
16042
16059
|
}
|
|
@@ -16096,9 +16113,6 @@ function parseInputDeclaration(name, raw, ctx) {
|
|
|
16096
16113
|
function parseInputDeclarations(value, ctx) {
|
|
16097
16114
|
const input = asRecord(value, ctx, ["inputs"]);
|
|
16098
16115
|
const names = Object.keys(input);
|
|
16099
|
-
if (names.length > WORKFLOW_MAX_PARAMS) {
|
|
16100
|
-
sourceError(ctx, ["inputs"], `accepts at most ${WORKFLOW_MAX_PARAMS} declared inputs.`);
|
|
16101
|
-
}
|
|
16102
16116
|
const result = {};
|
|
16103
16117
|
for (const name of names) {
|
|
16104
16118
|
if (!INPUT_NAME_PATTERN.test(name)) {
|
|
@@ -16531,7 +16545,7 @@ function parseAkm(value, ctx) {
|
|
|
16531
16545
|
out.timeout = parseTimeout(input.timeout, ctx);
|
|
16532
16546
|
if (own2(input, "redact")) {
|
|
16533
16547
|
const names = parseStringArray(input.redact, ctx, ["akm", "redact"], {
|
|
16534
|
-
max:
|
|
16548
|
+
max: TASK_V3_MAX_REDACT_NAMES,
|
|
16535
16549
|
pattern: WORKFLOW_ENV_VAR_NAME_PATTERN
|
|
16536
16550
|
});
|
|
16537
16551
|
if (new Set(names).size !== names.length)
|
|
@@ -16545,8 +16559,8 @@ function parseAkm(value, ctx) {
|
|
|
16545
16559
|
out.maxSteps = input.maxSteps;
|
|
16546
16560
|
}
|
|
16547
16561
|
if (own2(input, "maxRetries")) {
|
|
16548
|
-
if (!Number.isSafeInteger(input.maxRetries) || input.maxRetries < 0
|
|
16549
|
-
sourceError(ctx, ["akm", "maxRetries"],
|
|
16562
|
+
if (!Number.isSafeInteger(input.maxRetries) || input.maxRetries < 0) {
|
|
16563
|
+
sourceError(ctx, ["akm", "maxRetries"], "must be a non-negative safe integer.");
|
|
16550
16564
|
}
|
|
16551
16565
|
out.maxRetries = input.maxRetries;
|
|
16552
16566
|
}
|
|
@@ -16800,6 +16814,16 @@ var SHELL_ASSIGNMENT_WORD = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
|
16800
16814
|
function shellStableV2Executable(executable) {
|
|
16801
16815
|
return executable === "akm" || executable.includes("/");
|
|
16802
16816
|
}
|
|
16817
|
+
function skipEnvAssignmentPrefix(tokens) {
|
|
16818
|
+
if (tokens[0] !== "env")
|
|
16819
|
+
return { tokens, envWrapped: false };
|
|
16820
|
+
let index = 1;
|
|
16821
|
+
while (index < tokens.length && SHELL_ASSIGNMENT_WORD.test(tokens[index]))
|
|
16822
|
+
index += 1;
|
|
16823
|
+
if (index >= tokens.length)
|
|
16824
|
+
return { tokens, envWrapped: false };
|
|
16825
|
+
return { tokens: tokens.slice(index), envWrapped: true };
|
|
16826
|
+
}
|
|
16803
16827
|
var KNOWN_PROMPT_REF_FAMILIES = new Set([
|
|
16804
16828
|
"agents",
|
|
16805
16829
|
"commands",
|
|
@@ -16820,11 +16844,6 @@ function hash(bytes) {
|
|
|
16820
16844
|
return crypto.createHash("sha256").update(bytes).digest("hex");
|
|
16821
16845
|
}
|
|
16822
16846
|
function base(input) {
|
|
16823
|
-
const inspectionIdentity = input.inspectionIdentity ? Object.freeze({
|
|
16824
|
-
file: Object.freeze({ ...input.inspectionIdentity.file }),
|
|
16825
|
-
root: Object.freeze({ ...input.inspectionIdentity.root }),
|
|
16826
|
-
...input.inspectionIdentity.bundleRoot ? { bundleRoot: Object.freeze({ ...input.inspectionIdentity.bundleRoot }) } : {}
|
|
16827
|
-
}) : undefined;
|
|
16828
16847
|
return {
|
|
16829
16848
|
filePath: input.filePath,
|
|
16830
16849
|
before: Buffer.from(input.bytes),
|
|
@@ -16832,8 +16851,7 @@ function base(input) {
|
|
|
16832
16851
|
mode: input.mode,
|
|
16833
16852
|
writable: input.writable,
|
|
16834
16853
|
...input.onDiskWritable !== undefined ? { onDiskWritable: input.onDiskWritable } : {},
|
|
16835
|
-
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
16836
|
-
...inspectionIdentity ? { inspectionIdentity } : {}
|
|
16854
|
+
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
16837
16855
|
};
|
|
16838
16856
|
}
|
|
16839
16857
|
function blocked(input, reason, detail) {
|
|
@@ -16859,9 +16877,6 @@ function optionalString(value, label) {
|
|
|
16859
16877
|
return exactString(value, label);
|
|
16860
16878
|
}
|
|
16861
16879
|
function parseLegacyTaskYaml(input) {
|
|
16862
|
-
if (input.bytes.byteLength > TASK_V3_MAX_SOURCE_BYTES) {
|
|
16863
|
-
throw new Error(`task YAML exceeds the 1 MiB (${TASK_V3_MAX_SOURCE_BYTES}-byte) source resource limit`);
|
|
16864
|
-
}
|
|
16865
16880
|
let source;
|
|
16866
16881
|
try {
|
|
16867
16882
|
source = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(input.bytes);
|
|
@@ -16909,7 +16924,7 @@ function validateCommonV2(data) {
|
|
|
16909
16924
|
}
|
|
16910
16925
|
}
|
|
16911
16926
|
if (data.redact !== undefined && data.redact !== null) {
|
|
16912
|
-
if (!Array.isArray(data.redact) || data.redact.length >
|
|
16927
|
+
if (!Array.isArray(data.redact) || data.redact.length > TASK_V3_MAX_REDACT_NAMES || data.redact.some((entry) => typeof entry !== "string" || !WORKFLOW_ENV_VAR_NAME_PATTERN.test(entry))) {
|
|
16913
16928
|
throw new Error("redact must contain only bounded environment variable names");
|
|
16914
16929
|
}
|
|
16915
16930
|
}
|
|
@@ -17035,8 +17050,8 @@ function migratedObject(data) {
|
|
|
17035
17050
|
akm.maxSteps = data.maxSteps;
|
|
17036
17051
|
}
|
|
17037
17052
|
if (data.maxRetries !== undefined && data.maxRetries !== null) {
|
|
17038
|
-
if (!Number.isSafeInteger(data.maxRetries) || data.maxRetries < 0
|
|
17039
|
-
throw new Error(
|
|
17053
|
+
if (!Number.isSafeInteger(data.maxRetries) || data.maxRetries < 0) {
|
|
17054
|
+
throw new Error("maxRetries must be a non-negative integer");
|
|
17040
17055
|
}
|
|
17041
17056
|
akm.maxRetries = data.maxRetries;
|
|
17042
17057
|
}
|
|
@@ -17069,8 +17084,9 @@ function migratedObject(data) {
|
|
|
17069
17084
|
if (tokens.length === 0 || tokens.some((token) => !SAFE_V2_COMMAND_TOKEN.test(token))) {
|
|
17070
17085
|
return "shell-operators-change-v2-literal-argv-semantics";
|
|
17071
17086
|
}
|
|
17072
|
-
const
|
|
17073
|
-
|
|
17087
|
+
const { tokens: targetTokens, envWrapped } = skipEnvAssignmentPrefix(tokens);
|
|
17088
|
+
const executable = targetTokens[0];
|
|
17089
|
+
if (SHELL_ASSIGNMENT_WORD.test(executable) || !envWrapped && !shellStableV2Executable(executable)) {
|
|
17074
17090
|
return "shell-command-resolution-changes-v2-literal-argv-semantics";
|
|
17075
17091
|
}
|
|
17076
17092
|
output.run = tokens.join(" ");
|
|
@@ -17264,11 +17280,6 @@ function causeMessage(cause) {
|
|
|
17264
17280
|
return cause instanceof Error ? cause.message : String(cause);
|
|
17265
17281
|
}
|
|
17266
17282
|
function base2(input) {
|
|
17267
|
-
const inspectionIdentity = input.inspectionIdentity ? Object.freeze({
|
|
17268
|
-
file: Object.freeze({ ...input.inspectionIdentity.file }),
|
|
17269
|
-
root: Object.freeze({ ...input.inspectionIdentity.root }),
|
|
17270
|
-
...input.inspectionIdentity.bundleRoot ? { bundleRoot: Object.freeze({ ...input.inspectionIdentity.bundleRoot }) } : {}
|
|
17271
|
-
}) : undefined;
|
|
17272
17283
|
return {
|
|
17273
17284
|
filePath: input.filePath,
|
|
17274
17285
|
before: Buffer.from(input.bytes),
|
|
@@ -17276,8 +17287,7 @@ function base2(input) {
|
|
|
17276
17287
|
mode: input.mode,
|
|
17277
17288
|
writable: input.writable,
|
|
17278
17289
|
...input.onDiskWritable !== undefined ? { onDiskWritable: input.onDiskWritable } : {},
|
|
17279
|
-
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
17280
|
-
...inspectionIdentity ? { inspectionIdentity } : {}
|
|
17290
|
+
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
17281
17291
|
};
|
|
17282
17292
|
}
|
|
17283
17293
|
function blocked2(input, reason, detail) {
|
|
@@ -17300,9 +17310,6 @@ function exactString2(value, label, nonempty = false) {
|
|
|
17300
17310
|
return value;
|
|
17301
17311
|
}
|
|
17302
17312
|
function parseV3RawYaml(input) {
|
|
17303
|
-
if (input.bytes.byteLength > TASK_V3_MAX_SOURCE_BYTES) {
|
|
17304
|
-
throw new Error(`task YAML exceeds the 1 MiB (${TASK_V3_MAX_SOURCE_BYTES}-byte) source resource limit`);
|
|
17305
|
-
}
|
|
17306
17313
|
let source;
|
|
17307
17314
|
try {
|
|
17308
17315
|
source = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(input.bytes);
|
|
@@ -18503,7 +18510,7 @@ function validateStep(value, jobId, index, stepIds, options) {
|
|
|
18503
18510
|
}
|
|
18504
18511
|
validateMap(step.map, `step ${id} map`);
|
|
18505
18512
|
validateRoute(step.route, `step ${id} route`);
|
|
18506
|
-
optionalStringList(step.inputs, `step ${id} inputs`,
|
|
18513
|
+
optionalStringList(step.inputs, `step ${id} inputs`, Infinity);
|
|
18507
18514
|
if (Array.isArray(step.inputs)) {
|
|
18508
18515
|
for (const [inputIndex, input] of step.inputs.entries())
|
|
18509
18516
|
validateReference(input, `step ${id} inputs[${inputIndex}]`);
|
|
@@ -18525,12 +18532,7 @@ function validateExec(value, location, options) {
|
|
|
18525
18532
|
return;
|
|
18526
18533
|
const exec = record(value, location);
|
|
18527
18534
|
keys(exec, ["command", "cwd", "passEnv"], location);
|
|
18528
|
-
stringList(exec.command, `${location}.command`,
|
|
18529
|
-
for (const [index, argument] of exec.command.entries()) {
|
|
18530
|
-
if (utf8Bytes(argument) > WORKFLOW_MAX_EXEC_ARG_BYTES) {
|
|
18531
|
-
fail2(`${location}.command[${index}] exceeds ${WORKFLOW_MAX_EXEC_ARG_BYTES} bytes`);
|
|
18532
|
-
}
|
|
18533
|
-
}
|
|
18535
|
+
stringList(exec.command, `${location}.command`, Infinity, false);
|
|
18534
18536
|
try {
|
|
18535
18537
|
rejectNulInArgv(exec.command);
|
|
18536
18538
|
} catch (cause) {
|
|
@@ -18538,9 +18540,6 @@ function validateExec(value, location, options) {
|
|
|
18538
18540
|
}
|
|
18539
18541
|
optionalString2(exec.cwd, `${location}.cwd`);
|
|
18540
18542
|
if (exec.cwd !== undefined) {
|
|
18541
|
-
if (exec.cwd.length > WORKFLOW_MAX_EXEC_CWD_LENGTH) {
|
|
18542
|
-
fail2(`${location}.cwd exceeds ${WORKFLOW_MAX_EXEC_CWD_LENGTH} characters`);
|
|
18543
|
-
}
|
|
18544
18543
|
try {
|
|
18545
18544
|
exec.cwd = canonicalizeWorkflowWorkingDirectory(exec.cwd, options.workspaceRoot);
|
|
18546
18545
|
} catch (cause) {
|
|
@@ -18548,7 +18547,7 @@ function validateExec(value, location, options) {
|
|
|
18548
18547
|
}
|
|
18549
18548
|
}
|
|
18550
18549
|
if (exec.passEnv !== undefined) {
|
|
18551
|
-
stringList(exec.passEnv, `${location}.passEnv`,
|
|
18550
|
+
stringList(exec.passEnv, `${location}.passEnv`, Infinity, false);
|
|
18552
18551
|
}
|
|
18553
18552
|
if (Array.isArray(exec.passEnv)) {
|
|
18554
18553
|
for (const name of exec.passEnv) {
|
|
@@ -18599,8 +18598,8 @@ function validateRetry(value, location) {
|
|
|
18599
18598
|
return;
|
|
18600
18599
|
const retry = record(value, location);
|
|
18601
18600
|
keys(retry, ["max", "on"], location);
|
|
18602
|
-
if (!Number.isSafeInteger(retry.max) || retry.max < 0
|
|
18603
|
-
fail2(`${location}.max must be
|
|
18601
|
+
if (!Number.isSafeInteger(retry.max) || retry.max < 0) {
|
|
18602
|
+
fail2(`${location}.max must be a non-negative integer`);
|
|
18604
18603
|
}
|
|
18605
18604
|
stringList(retry.on, `${location}.on`, PROGRAM_RETRY_REASONS.length, false);
|
|
18606
18605
|
for (const reason of retry.on) {
|
|
@@ -18630,8 +18629,8 @@ function validateRoute(value, location) {
|
|
|
18630
18629
|
keys(route, ["input", "branches", "defaultStepId"], location);
|
|
18631
18630
|
nonEmptyString2(route.input, `${location}.input`);
|
|
18632
18631
|
validateReference(route.input, `${location}.input`);
|
|
18633
|
-
if (!Array.isArray(route.branches) || route.branches.length === 0
|
|
18634
|
-
fail2(`${location}.branches must
|
|
18632
|
+
if (!Array.isArray(route.branches) || route.branches.length === 0) {
|
|
18633
|
+
fail2(`${location}.branches must be a non-empty array`);
|
|
18635
18634
|
}
|
|
18636
18635
|
const matches = new Set;
|
|
18637
18636
|
for (const [index, value2] of route.branches.entries()) {
|
|
@@ -18651,8 +18650,8 @@ function validateGate(value, location) {
|
|
|
18651
18650
|
return;
|
|
18652
18651
|
const gate = record(value, location);
|
|
18653
18652
|
keys(gate, ["maxLoops", "rubric"], location);
|
|
18654
|
-
if (gate.maxLoops !== undefined && (!Number.isSafeInteger(gate.maxLoops) || gate.maxLoops < 1
|
|
18655
|
-
fail2(`${location}.maxLoops must be an integer
|
|
18653
|
+
if (gate.maxLoops !== undefined && (!Number.isSafeInteger(gate.maxLoops) || gate.maxLoops < 1)) {
|
|
18654
|
+
fail2(`${location}.maxLoops must be an integer of at least 1`);
|
|
18656
18655
|
}
|
|
18657
18656
|
optionalString2(gate.rubric, `${location}.rubric`);
|
|
18658
18657
|
}
|
|
@@ -18685,8 +18684,8 @@ function validateParams(value) {
|
|
|
18685
18684
|
if (value === undefined)
|
|
18686
18685
|
return;
|
|
18687
18686
|
const params = record(value, "params");
|
|
18688
|
-
if (Object.keys(params).length === 0
|
|
18689
|
-
fail2(`params must contain
|
|
18687
|
+
if (Object.keys(params).length === 0) {
|
|
18688
|
+
fail2(`params must contain at least one entry`);
|
|
18690
18689
|
}
|
|
18691
18690
|
for (const [name, schema] of Object.entries(params)) {
|
|
18692
18691
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
@@ -18698,8 +18697,8 @@ function validateOutputs(value) {
|
|
|
18698
18697
|
if (value === undefined)
|
|
18699
18698
|
return;
|
|
18700
18699
|
const outputs = record(value, "outputs");
|
|
18701
|
-
if (Object.keys(outputs).length === 0
|
|
18702
|
-
fail2(`outputs must contain
|
|
18700
|
+
if (Object.keys(outputs).length === 0) {
|
|
18701
|
+
fail2(`outputs must contain at least one entry`);
|
|
18703
18702
|
}
|
|
18704
18703
|
for (const [name, declaration] of Object.entries(outputs)) {
|
|
18705
18704
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
@@ -18722,9 +18721,6 @@ function validateBudget(value) {
|
|
|
18722
18721
|
fail2(`budget.${key} must be a positive integer`);
|
|
18723
18722
|
}
|
|
18724
18723
|
}
|
|
18725
|
-
if (typeof budget.maxUnits === "number" && budget.maxUnits > WORKFLOW_MAX_MAP_EXPANSION) {
|
|
18726
|
-
fail2(`budget.maxUnits must be at most ${WORKFLOW_MAX_MAP_EXPANSION}`);
|
|
18727
|
-
}
|
|
18728
18724
|
}
|
|
18729
18725
|
function validateLlm(value, location) {
|
|
18730
18726
|
if (value === undefined)
|
|
@@ -19308,12 +19304,6 @@ function checkXrefs(value, line, errors2) {
|
|
|
19308
19304
|
}
|
|
19309
19305
|
}
|
|
19310
19306
|
function checkResourceLimits(draft, errors2) {
|
|
19311
|
-
if (draft.steps.length > WORKFLOW_MAX_STEPS) {
|
|
19312
|
-
errors2.push({ line: 1, message: `Workflow must contain at most ${WORKFLOW_MAX_STEPS} steps.` });
|
|
19313
|
-
}
|
|
19314
|
-
if (Object.keys(draft.params ?? {}).length > WORKFLOW_MAX_PARAMS) {
|
|
19315
|
-
errors2.push({ line: 1, message: `Workflow must contain at most ${WORKFLOW_MAX_PARAMS} parameters.` });
|
|
19316
|
-
}
|
|
19317
19307
|
for (const step of draft.steps) {
|
|
19318
19308
|
if (step.instructions && utf8Bytes(step.instructions.text) > WORKFLOW_MAX_INSTRUCTION_BYTES) {
|
|
19319
19309
|
errors2.push({
|
|
@@ -19675,9 +19665,6 @@ function parseParams(ctx, raw) {
|
|
|
19675
19665
|
ctx.err(["params"], `"params" must be a mapping of param name to a JSON Schema object (e.g. changed_files: { type: array }).`);
|
|
19676
19666
|
return;
|
|
19677
19667
|
}
|
|
19678
|
-
if (Object.keys(raw).length > WORKFLOW_MAX_PARAMS) {
|
|
19679
|
-
ctx.err(["params"], `"params" must contain at most ${WORKFLOW_MAX_PARAMS} entries.`);
|
|
19680
|
-
}
|
|
19681
19668
|
const params = {};
|
|
19682
19669
|
for (const [paramName, value] of Object.entries(raw)) {
|
|
19683
19670
|
if (!INPUT_NAME_PATTERN.test(paramName)) {
|
|
@@ -19703,9 +19690,6 @@ function parseOutputs(ctx, raw) {
|
|
|
19703
19690
|
ctx.err(["outputs"], `"outputs" must be a mapping of output name to { from, schema? } (e.g. report: { from: steps.summarize.output }).`);
|
|
19704
19691
|
return;
|
|
19705
19692
|
}
|
|
19706
|
-
if (Object.keys(raw).length > WORKFLOW_MAX_OUTPUTS) {
|
|
19707
|
-
ctx.err(["outputs"], `"outputs" must contain at most ${WORKFLOW_MAX_OUTPUTS} entries.`);
|
|
19708
|
-
}
|
|
19709
19693
|
const outputs = {};
|
|
19710
19694
|
for (const [outputName, value] of Object.entries(raw)) {
|
|
19711
19695
|
const path13 = ["outputs", outputName];
|
|
@@ -19797,10 +19781,10 @@ function parseBudget(ctx, raw) {
|
|
|
19797
19781
|
}
|
|
19798
19782
|
}
|
|
19799
19783
|
if (raw.max_units !== undefined) {
|
|
19800
|
-
if (typeof raw.max_units === "number" && Number.isInteger(raw.max_units) && raw.max_units >= 1
|
|
19784
|
+
if (typeof raw.max_units === "number" && Number.isInteger(raw.max_units) && raw.max_units >= 1) {
|
|
19801
19785
|
budget.maxUnits = raw.max_units;
|
|
19802
19786
|
} else {
|
|
19803
|
-
ctx.err([...path13, "max_units"], `"budget.max_units" must be an integer
|
|
19787
|
+
ctx.err([...path13, "max_units"], `"budget.max_units" must be an integer >= 1.`);
|
|
19804
19788
|
}
|
|
19805
19789
|
}
|
|
19806
19790
|
return Object.keys(budget).length > 0 ? budget : undefined;
|
|
@@ -19810,9 +19794,6 @@ function parseSteps(ctx, raw) {
|
|
|
19810
19794
|
ctx.err(["steps"], `"steps" is required and must be a list with at least one step.`);
|
|
19811
19795
|
return [];
|
|
19812
19796
|
}
|
|
19813
|
-
if (raw.length > WORKFLOW_MAX_STEPS) {
|
|
19814
|
-
ctx.err(["steps"], `"steps" must contain at most ${WORKFLOW_MAX_STEPS} entries.`);
|
|
19815
|
-
}
|
|
19816
19797
|
const idIndex = new Map;
|
|
19817
19798
|
raw.forEach((rawStep, index) => {
|
|
19818
19799
|
if (isPlainRecord(rawStep) && typeof rawStep.id === "string" && !idIndex.has(rawStep.id)) {
|
|
@@ -19983,10 +19964,6 @@ function parseExecPassEnv(ctx, raw, path13, stepLabel) {
|
|
|
19983
19964
|
ctx.err(path13, `${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.`);
|
|
19984
19965
|
return;
|
|
19985
19966
|
}
|
|
19986
|
-
if (raw.length > WORKFLOW_MAX_EXEC_PASS_ENV) {
|
|
19987
|
-
ctx.err(path13, `${stepLabel} "exec.pass_env" must have at most ${WORKFLOW_MAX_EXEC_PASS_ENV} entries. A command needing ` + `more than that should use explicit named "env:" bindings instead.`);
|
|
19988
|
-
return;
|
|
19989
|
-
}
|
|
19990
19967
|
const names = [];
|
|
19991
19968
|
for (const [index, entry] of raw.entries()) {
|
|
19992
19969
|
if (typeof entry !== "string" || !WORKFLOW_ENV_VAR_NAME_PATTERN.test(entry)) {
|
|
@@ -20006,10 +19983,6 @@ function parseExecCommand(ctx, raw, path13, stepLabel) {
|
|
|
20006
19983
|
ctx.err(path13, `${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.`);
|
|
20007
19984
|
return;
|
|
20008
19985
|
}
|
|
20009
|
-
if (raw.length > WORKFLOW_MAX_EXEC_ARGV) {
|
|
20010
|
-
ctx.err(path13, `${stepLabel} "exec.command" must have at most ${WORKFLOW_MAX_EXEC_ARGV} entries.`);
|
|
20011
|
-
return;
|
|
20012
|
-
}
|
|
20013
19986
|
const argv = [];
|
|
20014
19987
|
for (const [index, entry] of raw.entries()) {
|
|
20015
19988
|
if (typeof entry !== "string" || entry === "") {
|
|
@@ -20020,10 +19993,6 @@ function parseExecCommand(ctx, raw, path13, stepLabel) {
|
|
|
20020
19993
|
ctx.err([...path13, index], `${stepLabel} "exec.command[${index}]" may not contain NUL bytes.`);
|
|
20021
19994
|
return;
|
|
20022
19995
|
}
|
|
20023
|
-
if (utf8Bytes(entry) > WORKFLOW_MAX_EXEC_ARG_BYTES) {
|
|
20024
|
-
ctx.err(path13, `${stepLabel} "exec.command[${index}]" exceeds ${WORKFLOW_MAX_EXEC_ARG_BYTES} bytes.`);
|
|
20025
|
-
return;
|
|
20026
|
-
}
|
|
20027
19996
|
argv.push(entry);
|
|
20028
19997
|
}
|
|
20029
19998
|
return argv;
|
|
@@ -20036,10 +20005,6 @@ function parseExecCwd(ctx, raw, path13, stepLabel) {
|
|
|
20036
20005
|
return;
|
|
20037
20006
|
}
|
|
20038
20007
|
const value = raw.trim();
|
|
20039
|
-
if (value.length > WORKFLOW_MAX_EXEC_CWD_LENGTH) {
|
|
20040
|
-
ctx.err(path13, `${stepLabel} "exec.cwd" exceeds ${WORKFLOW_MAX_EXEC_CWD_LENGTH} characters.`);
|
|
20041
|
-
return;
|
|
20042
|
-
}
|
|
20043
20008
|
if (!isContainedRelativePath(value)) {
|
|
20044
20009
|
ctx.err(path13, `${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.`);
|
|
20045
20010
|
return;
|
|
@@ -20073,10 +20038,10 @@ function parseMap(ctx, raw, path13, stepLabel) {
|
|
|
20073
20038
|
}
|
|
20074
20039
|
let concurrency;
|
|
20075
20040
|
if (raw.concurrency !== undefined) {
|
|
20076
|
-
if (typeof raw.concurrency === "number" && Number.isInteger(raw.concurrency) && raw.concurrency > 0
|
|
20077
|
-
concurrency = raw.concurrency;
|
|
20041
|
+
if (typeof raw.concurrency === "number" && Number.isInteger(raw.concurrency) && raw.concurrency > 0) {
|
|
20042
|
+
concurrency = Math.min(raw.concurrency, WORKFLOW_MAX_CONCURRENCY);
|
|
20078
20043
|
} else {
|
|
20079
|
-
ctx.err([...path13, "concurrency"], `${stepLabel} "concurrency" must be
|
|
20044
|
+
ctx.err([...path13, "concurrency"], `${stepLabel} "concurrency" must be a positive integer.`);
|
|
20080
20045
|
}
|
|
20081
20046
|
}
|
|
20082
20047
|
const reducer = parseEnumField(ctx, raw.reducer, [...path13, "reducer"], `${stepLabel} "reducer"`, PROGRAM_REDUCERS);
|
|
@@ -20108,9 +20073,6 @@ function parseRoute(ctx, raw, path13, stepLabel, stepIndex, routeChecks) {
|
|
|
20108
20073
|
if (!Array.isArray(raw.when) || raw.when.length === 0) {
|
|
20109
20074
|
ctx.err(whenPath, `${stepLabel} "route" requires "when": a non-empty list of { match, step } branches (e.g. when: [{ match: pass, step: ship }]).`);
|
|
20110
20075
|
} else {
|
|
20111
|
-
if (raw.when.length > WORKFLOW_MAX_ROUTE_BRANCHES) {
|
|
20112
|
-
ctx.err(whenPath, `${stepLabel} "when" must contain at most ${WORKFLOW_MAX_ROUTE_BRANCHES} branches.`);
|
|
20113
|
-
}
|
|
20114
20076
|
const seenMatches = new Map;
|
|
20115
20077
|
raw.when.forEach((branch, i) => {
|
|
20116
20078
|
const branchPath = [...whenPath, i];
|
|
@@ -20166,9 +20128,6 @@ function parseInputs(ctx, raw, path13, stepLabel) {
|
|
|
20166
20128
|
ctx.err(path13, `${stepLabel} "inputs" must be a non-empty list of reference strings.`);
|
|
20167
20129
|
return;
|
|
20168
20130
|
}
|
|
20169
|
-
if (raw.length > WORKFLOW_MAX_INPUTS) {
|
|
20170
|
-
ctx.err(path13, `${stepLabel} "inputs" must contain at most ${WORKFLOW_MAX_INPUTS} entries.`);
|
|
20171
|
-
}
|
|
20172
20131
|
const out = [];
|
|
20173
20132
|
const seen = new Set;
|
|
20174
20133
|
raw.forEach((entry, i) => {
|
|
@@ -20195,10 +20154,10 @@ function parseGate(ctx, raw, path13, stepLabel) {
|
|
|
20195
20154
|
checkUnknownKeys(ctx, raw, path13, GATE_KEYS, `${stepLabel} "gate"`);
|
|
20196
20155
|
const gate = {};
|
|
20197
20156
|
if (raw.max_loops !== undefined) {
|
|
20198
|
-
if (typeof raw.max_loops === "number" && Number.isInteger(raw.max_loops) && raw.max_loops >= 1
|
|
20157
|
+
if (typeof raw.max_loops === "number" && Number.isInteger(raw.max_loops) && raw.max_loops >= 1) {
|
|
20199
20158
|
gate.maxLoops = raw.max_loops;
|
|
20200
20159
|
} else {
|
|
20201
|
-
ctx.err([...path13, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer
|
|
20160
|
+
ctx.err([...path13, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer of at least 1.`);
|
|
20202
20161
|
}
|
|
20203
20162
|
}
|
|
20204
20163
|
return gate;
|
|
@@ -20224,8 +20183,8 @@ function parseRetry(ctx, raw, path13, stepLabel) {
|
|
|
20224
20183
|
}
|
|
20225
20184
|
checkUnknownKeys(ctx, raw, path13, RETRY_KEYS, `${stepLabel} "retry"`);
|
|
20226
20185
|
let ok = true;
|
|
20227
|
-
if (!(typeof raw.max === "number" && Number.isInteger(raw.max) && raw.max >= 0
|
|
20228
|
-
ctx.err([...path13, "max"], `${stepLabel} "retry.max" is required and must be
|
|
20186
|
+
if (!(typeof raw.max === "number" && Number.isInteger(raw.max) && raw.max >= 0)) {
|
|
20187
|
+
ctx.err([...path13, "max"], `${stepLabel} "retry.max" is required and must be a non-negative integer.`);
|
|
20229
20188
|
ok = false;
|
|
20230
20189
|
}
|
|
20231
20190
|
const on = [];
|
|
@@ -21842,6 +21801,8 @@ function indexDocumentFromEntry(entry, base3, rendererName) {
|
|
|
21842
21801
|
doc.tags = entry.tags;
|
|
21843
21802
|
if (entry.content !== undefined)
|
|
21844
21803
|
doc.content = entry.content;
|
|
21804
|
+
if (entry.contentTruncated !== undefined)
|
|
21805
|
+
doc.contentTruncated = entry.contentTruncated;
|
|
21845
21806
|
if (entry.aliases !== undefined)
|
|
21846
21807
|
doc.aliases = entry.aliases;
|
|
21847
21808
|
if (entry.searchHints !== undefined)
|
|
@@ -23811,7 +23772,7 @@ function withLockOperationMutex(lockPath, run) {
|
|
|
23811
23772
|
db.exec("BEGIN IMMEDIATE");
|
|
23812
23773
|
began = db.inTransaction;
|
|
23813
23774
|
if (!began)
|
|
23814
|
-
|
|
23775
|
+
sleepSync(2 ** attempt);
|
|
23815
23776
|
}
|
|
23816
23777
|
if (!began)
|
|
23817
23778
|
throw new Error(`Could not acquire lock operation mutex for ${lockPath}.`);
|
|
@@ -23974,7 +23935,7 @@ function extractHolderPid(content) {
|
|
|
23974
23935
|
// src/core/config/config-io.ts
|
|
23975
23936
|
function readConfigText(configPath) {
|
|
23976
23937
|
try {
|
|
23977
|
-
return
|
|
23938
|
+
return readTextFile(configPath, "Config file");
|
|
23978
23939
|
} catch (err) {
|
|
23979
23940
|
if (err.code === "ENOENT")
|
|
23980
23941
|
return;
|
|
@@ -28081,9 +28042,6 @@ var ExtraParamsSchema = exports_external.record(exports_external.unknown()).supe
|
|
|
28081
28042
|
ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path: issue.path, message: issue.message });
|
|
28082
28043
|
}
|
|
28083
28044
|
});
|
|
28084
|
-
var LlmCapabilitiesSchema = exports_external.object({
|
|
28085
|
-
structuredOutput: exports_external.boolean().optional()
|
|
28086
|
-
}).passthrough();
|
|
28087
28045
|
var LlmInvocationOverridesSchema = exports_external.object({
|
|
28088
28046
|
temperature: exports_external.number().finite().optional(),
|
|
28089
28047
|
maxTokens: positiveInt.optional(),
|
|
@@ -28139,15 +28097,13 @@ var LlmConnectionConfigSchema = exports_external.object({
|
|
|
28139
28097
|
maxTokens: positiveInt.optional(),
|
|
28140
28098
|
timeoutMs: timeoutMsField,
|
|
28141
28099
|
concurrency: positiveInt.optional(),
|
|
28142
|
-
|
|
28100
|
+
supportsJsonSchema: exports_external.boolean().optional(),
|
|
28143
28101
|
extraParams: ExtraParamsSchema.optional(),
|
|
28144
28102
|
contextLength: positiveInt.optional(),
|
|
28145
28103
|
enableThinking: exports_external.boolean().optional(),
|
|
28146
28104
|
reasoningEffort: nonEmptyString3.optional()
|
|
28147
28105
|
}).passthrough();
|
|
28148
|
-
var LlmProfileConfigSchema = LlmConnectionConfigSchema.
|
|
28149
|
-
supportsJsonSchema: exports_external.boolean().optional()
|
|
28150
|
-
}).passthrough();
|
|
28106
|
+
var LlmProfileConfigSchema = LlmConnectionConfigSchema.passthrough();
|
|
28151
28107
|
var AgentPlatformSchema = exports_external.enum(VALID_HARNESS_IDS);
|
|
28152
28108
|
var LlmEngineSchema = exports_external.object({
|
|
28153
28109
|
kind: exports_external.literal("llm"),
|
|
@@ -28159,7 +28115,6 @@ var LlmEngineSchema = exports_external.object({
|
|
|
28159
28115
|
maxTokens: positiveInt.optional(),
|
|
28160
28116
|
timeoutMs: timeoutMsField,
|
|
28161
28117
|
concurrency: positiveInt.optional(),
|
|
28162
|
-
supportsJsonSchema: exports_external.boolean().optional(),
|
|
28163
28118
|
extraParams: ExtraParamsSchema.optional(),
|
|
28164
28119
|
contextLength: positiveInt.optional(),
|
|
28165
28120
|
enableThinking: exports_external.boolean().optional(),
|
|
@@ -28189,7 +28144,6 @@ var AgentEngineSchema = exports_external.object({
|
|
|
28189
28144
|
"temperature",
|
|
28190
28145
|
"maxTokens",
|
|
28191
28146
|
"concurrency",
|
|
28192
|
-
"supportsJsonSchema",
|
|
28193
28147
|
"extraParams",
|
|
28194
28148
|
"contextLength",
|
|
28195
28149
|
"enableThinking",
|
|
@@ -28555,7 +28509,7 @@ var SearchGraphBoostSchema = exports_external.object({
|
|
|
28555
28509
|
hopBoostPerEntity: nonNegativeNumber.optional(),
|
|
28556
28510
|
hopBoostCap: nonNegativeNumber.optional(),
|
|
28557
28511
|
maxHops: positiveInt.max(3).optional(),
|
|
28558
|
-
confidenceMode: exports_external.enum(["
|
|
28512
|
+
confidenceMode: exports_external.enum(["blend"]).default("blend").optional(),
|
|
28559
28513
|
confidenceWeight: exports_external.number().finite().min(0).max(1).default(0.2).optional()
|
|
28560
28514
|
}).passthrough();
|
|
28561
28515
|
var SearchConfigSchema = exports_external.object({
|
|
@@ -28892,6 +28846,43 @@ var AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
|
|
|
28892
28846
|
}
|
|
28893
28847
|
});
|
|
28894
28848
|
|
|
28849
|
+
// src/core/config/config-version-shim.ts
|
|
28850
|
+
var KNOWN_OLD_CONFIG_VERSIONS = ["0.0.1"];
|
|
28851
|
+
function isKnownOldConfigVersion(value) {
|
|
28852
|
+
return typeof value === "string" && KNOWN_OLD_CONFIG_VERSIONS.includes(value);
|
|
28853
|
+
}
|
|
28854
|
+
function upgradeFrom080(raw) {
|
|
28855
|
+
const { defaultEngine, defaults, ...rest } = raw;
|
|
28856
|
+
if (typeof defaultEngine !== "string" || defaultEngine.length === 0) {
|
|
28857
|
+
return { ...rest, ...defaults !== undefined ? { defaults } : {}, configVersion: CURRENT_CONFIG_VERSION };
|
|
28858
|
+
}
|
|
28859
|
+
const existingDefaults = defaults !== null && typeof defaults === "object" ? defaults : {};
|
|
28860
|
+
return {
|
|
28861
|
+
...rest,
|
|
28862
|
+
configVersion: CURRENT_CONFIG_VERSION,
|
|
28863
|
+
defaults: { llmEngine: defaultEngine, ...existingDefaults }
|
|
28864
|
+
};
|
|
28865
|
+
}
|
|
28866
|
+
var CONFIG_VERSION_UPGRADES = {
|
|
28867
|
+
"0.0.1": upgradeFrom080
|
|
28868
|
+
};
|
|
28869
|
+
function unsupportedConfigVersionError(rawVersion, sourcePath) {
|
|
28870
|
+
const where = sourcePath ? ` at ${sourcePath}` : "";
|
|
28871
|
+
const supported = [CURRENT_CONFIG_VERSION, ...KNOWN_OLD_CONFIG_VERSIONS].map((v) => `"${v}"`).join(", ");
|
|
28872
|
+
return new ConfigError(`Unsupported configVersion${where}: got ${JSON.stringify(rawVersion)}, expected one of ${supported}.`, "UNSUPPORTED_CONFIG_VERSION", "Recreate engines and improve.strategies manually for AKM 0.9.0; profile-based configuration is not translated automatically.");
|
|
28873
|
+
}
|
|
28874
|
+
function upgradeConfigVersion(raw, sourcePath) {
|
|
28875
|
+
const version = raw.configVersion;
|
|
28876
|
+
if (version === CURRENT_CONFIG_VERSION)
|
|
28877
|
+
return raw;
|
|
28878
|
+
if (isKnownOldConfigVersion(version)) {
|
|
28879
|
+
const upgraded = CONFIG_VERSION_UPGRADES[version](raw);
|
|
28880
|
+
warn(`Config${sourcePath ? ` at ${sourcePath}` : ""} uses configVersion "${version}" — auto-upgraded to ${CURRENT_CONFIG_VERSION} in memory; the next config write (e.g. \`akm config set\`) persists this and silences the warning.`);
|
|
28881
|
+
return upgraded;
|
|
28882
|
+
}
|
|
28883
|
+
throw unsupportedConfigVersionError(version, sourcePath);
|
|
28884
|
+
}
|
|
28885
|
+
|
|
28895
28886
|
// src/core/config/deep-merge.ts
|
|
28896
28887
|
var UNSAFE_KEYS3 = new Set(["__proto__", "constructor", "prototype"]);
|
|
28897
28888
|
function isPlainObject4(value) {
|
|
@@ -28982,10 +28973,7 @@ function loadUserConfig() {
|
|
|
28982
28973
|
return finalConfig;
|
|
28983
28974
|
}
|
|
28984
28975
|
function parseAndValidateConfigText(text, sourcePath) {
|
|
28985
|
-
const parsedRaw = parseConfigText(text, sourcePath);
|
|
28986
|
-
if (parsedRaw.configVersion !== CURRENT_CONFIG_VERSION) {
|
|
28987
|
-
throw new ConfigError(`Unsupported configVersion${sourcePath ? ` at ${sourcePath}` : ""}: expected "${CURRENT_CONFIG_VERSION}".`, "UNSUPPORTED_CONFIG_VERSION", "Recreate engines and improve.strategies manually for AKM 0.9.0; profile-based configuration is not translated automatically.");
|
|
28988
|
-
}
|
|
28976
|
+
const parsedRaw = upgradeConfigVersion(parseConfigText(text, sourcePath), sourcePath);
|
|
28989
28977
|
const { config: raw, lifted, conflicts } = liftLegacyEngineExtraParams(parsedRaw);
|
|
28990
28978
|
const where = sourcePath ? ` at ${sourcePath}` : "";
|
|
28991
28979
|
if (conflicts.length > 0) {
|
|
@@ -29063,8 +29051,7 @@ function withMaintenanceStartBarrier(run) {
|
|
|
29063
29051
|
|
|
29064
29052
|
// src/indexer/index-writer-lock.ts
|
|
29065
29053
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
29066
|
-
var
|
|
29067
|
-
var DEFAULT_INDEX_WRITER_MAX_WAIT_MS = 10 * 60 * 1000;
|
|
29054
|
+
var DEFAULT_ASSET_MUTATION_MAX_WAIT_MS = 10 * 60 * 1000;
|
|
29068
29055
|
var leaseContext = new AsyncLocalStorage2;
|
|
29069
29056
|
|
|
29070
29057
|
// src/integrations/lockfile.ts
|
|
@@ -29538,32 +29525,18 @@ function contained2(root, candidate) {
|
|
|
29538
29525
|
const relative = path31.relative(root, candidate);
|
|
29539
29526
|
return relative === "" || !relative.startsWith("..") && !path31.isAbsolute(relative);
|
|
29540
29527
|
}
|
|
29541
|
-
function
|
|
29542
|
-
const stat = fs26.lstatSync(filePath
|
|
29543
|
-
|
|
29544
|
-
|
|
29545
|
-
|
|
29546
|
-
if (kind === "file" && stat.nlink !== 1n)
|
|
29547
|
-
throw migrationError(`${filePath} must not be hard-linked.`);
|
|
29548
|
-
return Object.freeze({
|
|
29549
|
-
realPath: fs26.realpathSync(filePath),
|
|
29550
|
-
device: stat.dev.toString(),
|
|
29551
|
-
inode: stat.ino.toString(),
|
|
29552
|
-
linkCount: stat.nlink.toString(),
|
|
29553
|
-
changeTimeNs: stat.ctimeNs.toString()
|
|
29554
|
-
});
|
|
29555
|
-
}
|
|
29556
|
-
function sameIdentity2(left, right) {
|
|
29557
|
-
return left.realPath === right.realPath && left.device === right.device && left.inode === right.inode && left.linkCount === right.linkCount && left.changeTimeNs === right.changeTimeNs;
|
|
29528
|
+
function realDirectory(filePath) {
|
|
29529
|
+
const stat = fs26.lstatSync(filePath);
|
|
29530
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
29531
|
+
throw migrationError(`${filePath} must be a real directory.`);
|
|
29532
|
+
return fs26.realpathSync(filePath);
|
|
29558
29533
|
}
|
|
29559
29534
|
function snapshot(filePath) {
|
|
29560
|
-
const before = identity3(filePath, "file");
|
|
29561
29535
|
const stat = fs26.lstatSync(filePath);
|
|
29536
|
+
if (stat.isSymbolicLink() || !stat.isFile())
|
|
29537
|
+
throw migrationError(`${filePath} must be a real file.`);
|
|
29562
29538
|
const bytes = fs26.readFileSync(filePath);
|
|
29563
|
-
|
|
29564
|
-
if (!sameIdentity2(before, after))
|
|
29565
|
-
throw migrationError(`${filePath} changed while it was read.`);
|
|
29566
|
-
return Object.freeze({ bytes, mode: stat.mode & 511, identity: after });
|
|
29539
|
+
return Object.freeze({ bytes, mode: stat.mode & 511 });
|
|
29567
29540
|
}
|
|
29568
29541
|
function writable(filePath) {
|
|
29569
29542
|
try {
|
|
@@ -29574,10 +29547,9 @@ function writable(filePath) {
|
|
|
29574
29547
|
}
|
|
29575
29548
|
}
|
|
29576
29549
|
function walkTasks(root, tasksDir, out) {
|
|
29577
|
-
const
|
|
29578
|
-
const
|
|
29579
|
-
|
|
29580
|
-
if (!contained2(bundleIdentity.realPath, physicalRoot)) {
|
|
29550
|
+
const physicalRoot = realDirectory(root.root);
|
|
29551
|
+
const physicalBundleRoot = realDirectory(root.bundleRoot ?? root.root);
|
|
29552
|
+
if (!contained2(physicalBundleRoot, physicalRoot)) {
|
|
29581
29553
|
throw migrationError(`${root.root} resolves outside bundle ${root.bundleId}.`);
|
|
29582
29554
|
}
|
|
29583
29555
|
const visit2 = (directory) => {
|
|
@@ -29603,12 +29575,7 @@ function walkTasks(root, tasksDir, out) {
|
|
|
29603
29575
|
mode: current.mode,
|
|
29604
29576
|
writable: root.writable,
|
|
29605
29577
|
onDiskWritable: writable(candidate) && writable(parent) && (current.mode & 146) !== 0,
|
|
29606
|
-
containmentRoot: physicalRoot
|
|
29607
|
-
inspectionIdentity: Object.freeze({
|
|
29608
|
-
file: current.identity,
|
|
29609
|
-
root: rootIdentity,
|
|
29610
|
-
bundleRoot: bundleIdentity
|
|
29611
|
-
})
|
|
29578
|
+
containmentRoot: physicalRoot
|
|
29612
29579
|
});
|
|
29613
29580
|
}
|
|
29614
29581
|
};
|
|
@@ -29672,17 +29639,9 @@ function assertUnchanged(change) {
|
|
|
29672
29639
|
if (!current.bytes.equals(change.before) || current.mode !== change.mode) {
|
|
29673
29640
|
throw migrationError(`${change.filePath} changed after preview; no task files were replaced.`);
|
|
29674
29641
|
}
|
|
29675
|
-
const planned = change.inspectionIdentity?.file;
|
|
29676
|
-
if (planned && !sameIdentity2(planned, current.identity)) {
|
|
29677
|
-
throw migrationError(`${change.filePath} identity changed after preview; no task files were replaced.`);
|
|
29678
|
-
}
|
|
29679
29642
|
return current;
|
|
29680
29643
|
}
|
|
29681
29644
|
function applyTaskToV3MigrationPlan(plan, options) {
|
|
29682
|
-
const blocked3 = plan.files.filter((file) => file.status === "blocked");
|
|
29683
|
-
if (blocked3.length > 0) {
|
|
29684
|
-
throw migrationError(`plan is blocked: ${blocked3.map((file) => `${file.filePath} (${file.reason})`).join(", ")}. No files were written.`);
|
|
29685
|
-
}
|
|
29686
29645
|
const changes = plan.files.filter((file) => file.status === "changed");
|
|
29687
29646
|
for (const change of changes) {
|
|
29688
29647
|
assertUnchanged(change);
|
|
@@ -29725,32 +29684,18 @@ function contained3(root, candidate) {
|
|
|
29725
29684
|
const relative = path32.relative(root, candidate);
|
|
29726
29685
|
return relative === "" || !relative.startsWith("..") && !path32.isAbsolute(relative);
|
|
29727
29686
|
}
|
|
29728
|
-
function
|
|
29729
|
-
const stat = fs27.lstatSync(filePath
|
|
29730
|
-
|
|
29731
|
-
|
|
29732
|
-
|
|
29733
|
-
if (kind === "file" && stat.nlink !== 1n)
|
|
29734
|
-
throw migrationError2(`${filePath} must not be hard-linked.`);
|
|
29735
|
-
return Object.freeze({
|
|
29736
|
-
realPath: fs27.realpathSync(filePath),
|
|
29737
|
-
device: stat.dev.toString(),
|
|
29738
|
-
inode: stat.ino.toString(),
|
|
29739
|
-
linkCount: stat.nlink.toString(),
|
|
29740
|
-
changeTimeNs: stat.ctimeNs.toString()
|
|
29741
|
-
});
|
|
29742
|
-
}
|
|
29743
|
-
function sameIdentity3(left, right) {
|
|
29744
|
-
return left.realPath === right.realPath && left.device === right.device && left.inode === right.inode && left.linkCount === right.linkCount && left.changeTimeNs === right.changeTimeNs;
|
|
29687
|
+
function realDirectory2(filePath) {
|
|
29688
|
+
const stat = fs27.lstatSync(filePath);
|
|
29689
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
29690
|
+
throw migrationError2(`${filePath} must be a real directory.`);
|
|
29691
|
+
return fs27.realpathSync(filePath);
|
|
29745
29692
|
}
|
|
29746
29693
|
function snapshot2(filePath) {
|
|
29747
|
-
const before = identity4(filePath, "file");
|
|
29748
29694
|
const stat = fs27.lstatSync(filePath);
|
|
29695
|
+
if (stat.isSymbolicLink() || !stat.isFile())
|
|
29696
|
+
throw migrationError2(`${filePath} must be a real file.`);
|
|
29749
29697
|
const bytes = fs27.readFileSync(filePath);
|
|
29750
|
-
|
|
29751
|
-
if (!sameIdentity3(before, after))
|
|
29752
|
-
throw migrationError2(`${filePath} changed while it was read.`);
|
|
29753
|
-
return Object.freeze({ bytes, mode: stat.mode & 511, identity: after });
|
|
29698
|
+
return Object.freeze({ bytes, mode: stat.mode & 511 });
|
|
29754
29699
|
}
|
|
29755
29700
|
function writable2(filePath) {
|
|
29756
29701
|
try {
|
|
@@ -29761,10 +29706,9 @@ function writable2(filePath) {
|
|
|
29761
29706
|
}
|
|
29762
29707
|
}
|
|
29763
29708
|
function walkTasks2(root, tasksDir, out) {
|
|
29764
|
-
const
|
|
29765
|
-
const
|
|
29766
|
-
|
|
29767
|
-
if (!contained3(bundleIdentity.realPath, physicalRoot)) {
|
|
29709
|
+
const physicalRoot = realDirectory2(root.root);
|
|
29710
|
+
const physicalBundleRoot = realDirectory2(root.bundleRoot ?? root.root);
|
|
29711
|
+
if (!contained3(physicalBundleRoot, physicalRoot)) {
|
|
29768
29712
|
throw migrationError2(`${root.root} resolves outside bundle ${root.bundleId}.`);
|
|
29769
29713
|
}
|
|
29770
29714
|
const visit2 = (directory) => {
|
|
@@ -29790,12 +29734,7 @@ function walkTasks2(root, tasksDir, out) {
|
|
|
29790
29734
|
mode: current.mode,
|
|
29791
29735
|
writable: root.writable,
|
|
29792
29736
|
onDiskWritable: writable2(candidate) && writable2(parent) && (current.mode & 146) !== 0,
|
|
29793
|
-
containmentRoot: physicalRoot
|
|
29794
|
-
inspectionIdentity: Object.freeze({
|
|
29795
|
-
file: current.identity,
|
|
29796
|
-
root: rootIdentity,
|
|
29797
|
-
bundleRoot: bundleIdentity
|
|
29798
|
-
})
|
|
29737
|
+
containmentRoot: physicalRoot
|
|
29799
29738
|
});
|
|
29800
29739
|
}
|
|
29801
29740
|
};
|
|
@@ -29859,17 +29798,9 @@ function assertUnchanged2(change) {
|
|
|
29859
29798
|
if (!current.bytes.equals(change.before) || current.mode !== change.mode) {
|
|
29860
29799
|
throw migrationError2(`${change.filePath} changed after preview; no task files were replaced.`);
|
|
29861
29800
|
}
|
|
29862
|
-
const planned = change.inspectionIdentity?.file;
|
|
29863
|
-
if (planned && !sameIdentity3(planned, current.identity)) {
|
|
29864
|
-
throw migrationError2(`${change.filePath} identity changed after preview; no task files were replaced.`);
|
|
29865
|
-
}
|
|
29866
29801
|
return current;
|
|
29867
29802
|
}
|
|
29868
29803
|
function applyTaskToV4MigrationPlan(plan, options) {
|
|
29869
|
-
const blocked3 = plan.files.filter((file) => file.status === "blocked");
|
|
29870
|
-
if (blocked3.length > 0) {
|
|
29871
|
-
throw migrationError2(`plan is blocked: ${blocked3.map((file) => `${file.filePath} (${file.reason})`).join(", ")}. No files were written.`);
|
|
29872
|
-
}
|
|
29873
29804
|
const changes = plan.files.filter((file) => file.status === "changed");
|
|
29874
29805
|
for (const change of changes) {
|
|
29875
29806
|
assertUnchanged2(change);
|
|
@@ -29918,9 +29849,14 @@ function existingDirectory(target) {
|
|
|
29918
29849
|
throw cause;
|
|
29919
29850
|
}
|
|
29920
29851
|
}
|
|
29852
|
+
function reconcileDuplicateRoot(existing, candidate, sharedPath) {
|
|
29853
|
+
if (existing.writable === candidate.writable && existing.layout === candidate.layout)
|
|
29854
|
+
return;
|
|
29855
|
+
throw new ConfigError(`Bundles "${existing.bundleId}" and "${candidate.bundleId}" both resolve to the same directory ` + `(${sharedPath}) but disagree on writable/adapter settings. Two bundle ids configured for one ` + "directory must have matching settings, or one of them removed — run `akm bundle list` to see both.", "INVALID_CONFIG_FILE");
|
|
29856
|
+
}
|
|
29921
29857
|
function taskRoots(config, resolutionBase = process.cwd()) {
|
|
29922
29858
|
const sources = new Map((bundlesToSourceEntries(config) ?? []).map((source) => [source.name, source]));
|
|
29923
|
-
const
|
|
29859
|
+
const rootsByPath = new Map;
|
|
29924
29860
|
for (const [bundleId, bundle] of Object.entries(config.bundles ?? {})) {
|
|
29925
29861
|
if (bundle.enabled === false)
|
|
29926
29862
|
continue;
|
|
@@ -29948,15 +29884,21 @@ function taskRoots(config, resolutionBase = process.cwd()) {
|
|
|
29948
29884
|
}
|
|
29949
29885
|
if (adapter !== "akm" && adapter !== "akm-task")
|
|
29950
29886
|
continue;
|
|
29951
|
-
|
|
29887
|
+
const candidate = {
|
|
29952
29888
|
bundleId,
|
|
29953
29889
|
root: componentRoot,
|
|
29954
29890
|
bundleRoot,
|
|
29955
29891
|
writable: component?.writable ?? resolveWritable(source),
|
|
29956
29892
|
layout: adapter === "akm-task" ? "akm-task" : "akm-stash"
|
|
29957
|
-
}
|
|
29893
|
+
};
|
|
29894
|
+
const existing = rootsByPath.get(componentRoot);
|
|
29895
|
+
if (existing) {
|
|
29896
|
+
reconcileDuplicateRoot(existing, candidate, componentRoot);
|
|
29897
|
+
continue;
|
|
29898
|
+
}
|
|
29899
|
+
rootsByPath.set(componentRoot, candidate);
|
|
29958
29900
|
}
|
|
29959
|
-
return
|
|
29901
|
+
return [...rootsByPath.values()];
|
|
29960
29902
|
}
|
|
29961
29903
|
function summarize(plan) {
|
|
29962
29904
|
const files = plan.files.map((file) => ({
|
|
@@ -30013,12 +29955,12 @@ async function runMigrationApply(options = {}) {
|
|
|
30013
29955
|
}
|
|
30014
29956
|
const result = withConfigLock(() => withMaintenanceStartBarrier(() => {
|
|
30015
29957
|
const before = inspectCurrentTaskPlan();
|
|
30016
|
-
if (before.result.
|
|
29958
|
+
if (before.result.taskV3Migration.changed === 0)
|
|
30017
29959
|
return before.result;
|
|
30018
29960
|
const backupPath = path33.join(getDataDir(), "backups", "task-v3", `${Date.now()}-${randomUUID2()}`);
|
|
30019
29961
|
const applied = applyTaskToV3MigrationPlan(before.plan, { backupRoot: backupPath });
|
|
30020
29962
|
const after = inspectCurrentTaskPlan().result;
|
|
30021
|
-
if (after.
|
|
29963
|
+
if (after.taskV3Migration.changed > 0) {
|
|
30022
29964
|
throw new ConfigError("Task migration did not converge to task v3.", "INVALID_CONFIG_FILE");
|
|
30023
29965
|
}
|
|
30024
29966
|
return { ...after, backupPath, applied: applied.changed.length };
|
|
@@ -30076,12 +30018,12 @@ async function runTaskV4MigrationApply(options = {}) {
|
|
|
30076
30018
|
}
|
|
30077
30019
|
const result = withConfigLock(() => withMaintenanceStartBarrier(() => {
|
|
30078
30020
|
const before = inspectCurrentTaskV4Plan();
|
|
30079
|
-
if (before.result.
|
|
30021
|
+
if (before.result.taskV4Migration.changed === 0)
|
|
30080
30022
|
return before.result;
|
|
30081
30023
|
const backupPath = path33.join(getDataDir(), "backups", "task-v4", `${Date.now()}-${randomUUID2()}`);
|
|
30082
30024
|
const applied = applyTaskToV4MigrationPlan(before.plan, { backupRoot: backupPath });
|
|
30083
30025
|
const after = inspectCurrentTaskV4Plan().result;
|
|
30084
|
-
if (after.
|
|
30026
|
+
if (after.taskV4Migration.changed > 0) {
|
|
30085
30027
|
throw new ConfigError("Task migration did not converge to task source v4.", "INVALID_CONFIG_FILE");
|
|
30086
30028
|
}
|
|
30087
30029
|
return { ...after, backupPath, applied: applied.changed.length };
|