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
|
@@ -9379,8 +9379,6 @@ function getRegistryIndexCacheDir() {
|
|
|
9379
9379
|
}
|
|
9380
9380
|
|
|
9381
9381
|
// src/core/common.ts
|
|
9382
|
-
var MAX_CONFIG_FILE_BYTES = 1024 * 1024;
|
|
9383
|
-
var MAX_LOCAL_METADATA_BYTES = 1024 * 1024;
|
|
9384
9382
|
var MAX_LOCK_METADATA_BYTES = 64 * 1024;
|
|
9385
9383
|
function readTextFileDescriptorWithLimit(fd, maxBytes, label = "File", displayPath = "(open file)") {
|
|
9386
9384
|
const stat = fs.fstatSync(fd);
|
|
@@ -9402,10 +9400,13 @@ function readTextFileDescriptorWithLimit(fd, maxBytes, label = "File", displayPa
|
|
|
9402
9400
|
}
|
|
9403
9401
|
return buffer.subarray(0, total).toString("utf8");
|
|
9404
9402
|
}
|
|
9405
|
-
function
|
|
9403
|
+
function readTextFile(filePath, label = "File") {
|
|
9406
9404
|
const fd = fs.openSync(filePath, "r");
|
|
9407
9405
|
try {
|
|
9408
|
-
|
|
9406
|
+
const stat = fs.fstatSync(fd);
|
|
9407
|
+
if (!stat.isFile())
|
|
9408
|
+
throw new ConfigError(`${label} is not a regular file: ${filePath}.`, "INVALID_CONFIG_FILE");
|
|
9409
|
+
return fs.readFileSync(fd, "utf8");
|
|
9409
9410
|
} finally {
|
|
9410
9411
|
fs.closeSync(fd);
|
|
9411
9412
|
}
|
|
@@ -9505,6 +9506,8 @@ function asNonEmptyString(value) {
|
|
|
9505
9506
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
9506
9507
|
}
|
|
9507
9508
|
function isProcessAlive(pid) {
|
|
9509
|
+
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0)
|
|
9510
|
+
return false;
|
|
9508
9511
|
try {
|
|
9509
9512
|
process.kill(pid, 0);
|
|
9510
9513
|
return true;
|
|
@@ -10066,11 +10069,13 @@ function makeStampHandler(command) {
|
|
|
10066
10069
|
if (typeof result !== "object" || Array.isArray(result))
|
|
10067
10070
|
return result;
|
|
10068
10071
|
const obj = result;
|
|
10069
|
-
if (obj.shape
|
|
10070
|
-
obj
|
|
10071
|
-
|
|
10072
|
-
obj
|
|
10073
|
-
|
|
10072
|
+
if (obj.shape !== undefined && obj.schemaVersion !== undefined)
|
|
10073
|
+
return obj;
|
|
10074
|
+
return {
|
|
10075
|
+
...obj,
|
|
10076
|
+
shape: obj.shape ?? command,
|
|
10077
|
+
schemaVersion: obj.schemaVersion ?? 1
|
|
10078
|
+
};
|
|
10074
10079
|
};
|
|
10075
10080
|
}
|
|
10076
10081
|
var PASSTHROUGH_COMMANDS = [
|
|
@@ -10110,6 +10115,7 @@ var PASSTHROUGH_COMMANDS = [
|
|
|
10110
10115
|
"task-doctor",
|
|
10111
10116
|
"task-explain",
|
|
10112
10117
|
"task-history",
|
|
10118
|
+
"task-prune",
|
|
10113
10119
|
"task-run",
|
|
10114
10120
|
"task-sync",
|
|
10115
10121
|
"task-sync-dry-run",
|
|
@@ -12946,8 +12952,17 @@ import path8 from "path";
|
|
|
12946
12952
|
// src/core/warn.ts
|
|
12947
12953
|
import fs4 from "fs";
|
|
12948
12954
|
var quiet = false;
|
|
12955
|
+
var verbose = false;
|
|
12949
12956
|
var logFilePath;
|
|
12950
12957
|
var sinkOverride;
|
|
12958
|
+
function isVerbose() {
|
|
12959
|
+
const env = process.env.AKM_VERBOSE?.trim().toLowerCase();
|
|
12960
|
+
if (env === "1" || env === "true" || env === "yes" || env === "on")
|
|
12961
|
+
return true;
|
|
12962
|
+
if (env === "0" || env === "false" || env === "no" || env === "off")
|
|
12963
|
+
return false;
|
|
12964
|
+
return verbose;
|
|
12965
|
+
}
|
|
12951
12966
|
function appendToLogFile(level, args) {
|
|
12952
12967
|
if (!logFilePath)
|
|
12953
12968
|
return;
|
|
@@ -12973,6 +12988,15 @@ function warn(...args) {
|
|
|
12973
12988
|
console.warn(...args);
|
|
12974
12989
|
}
|
|
12975
12990
|
}
|
|
12991
|
+
function warnVerbose(...args) {
|
|
12992
|
+
if (sinkOverride) {
|
|
12993
|
+
sinkOverride("warnVerbose", args);
|
|
12994
|
+
return;
|
|
12995
|
+
}
|
|
12996
|
+
if (isVerbose()) {
|
|
12997
|
+
warn(...args);
|
|
12998
|
+
}
|
|
12999
|
+
}
|
|
12976
13000
|
|
|
12977
13001
|
// src/indexer/passes/metadata.ts
|
|
12978
13002
|
var SCOPE_KEYS = ["user", "agent", "run", "channel"];
|
|
@@ -13688,7 +13712,7 @@ function stripMarkdownLinkDestinations(text, nesting = 0) {
|
|
|
13688
13712
|
}
|
|
13689
13713
|
return visible;
|
|
13690
13714
|
}
|
|
13691
|
-
function projectMarkdownContent(body) {
|
|
13715
|
+
function projectMarkdownContent(body, truncationInfo) {
|
|
13692
13716
|
const lines = body.split(/\r?\n/);
|
|
13693
13717
|
const innerBlock = findInnerFrontmatterBlock(lines);
|
|
13694
13718
|
const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
|
|
@@ -13734,6 +13758,8 @@ function projectMarkdownContent(body) {
|
|
|
13734
13758
|
const text = projected.join(" ").replace(/\s+/g, " ").trim();
|
|
13735
13759
|
if (!text)
|
|
13736
13760
|
return;
|
|
13761
|
+
if (truncationInfo)
|
|
13762
|
+
truncationInfo.truncated = text.length > MARKDOWN_CONTENT_MAX_CHARS;
|
|
13737
13763
|
return truncateUnicodeSafe(text, MARKDOWN_CONTENT_MAX_CHARS);
|
|
13738
13764
|
}
|
|
13739
13765
|
function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
@@ -13757,9 +13783,15 @@ function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
|
13757
13783
|
applyWikiFrontmatter(entry, parsed.data);
|
|
13758
13784
|
applyProvenanceFrontmatter(entry, parsed.data);
|
|
13759
13785
|
if (entry.type !== "env" && entry.type !== "session" && !hasSessionMemoryMarker(parsed.data, parsed.content)) {
|
|
13760
|
-
const
|
|
13761
|
-
|
|
13786
|
+
const truncationInfo = { truncated: false };
|
|
13787
|
+
const contentProjection = projectMarkdownContent(parsed.content, truncationInfo);
|
|
13788
|
+
if (contentProjection) {
|
|
13762
13789
|
entry.content = contentProjection;
|
|
13790
|
+
if (truncationInfo.truncated) {
|
|
13791
|
+
entry.contentTruncated = true;
|
|
13792
|
+
warnVerbose(`${file}: indexed content truncated to ${MARKDOWN_CONTENT_MAX_CHARS} chars`);
|
|
13793
|
+
}
|
|
13794
|
+
}
|
|
13763
13795
|
}
|
|
13764
13796
|
if (entry.type === "command") {
|
|
13765
13797
|
const cmdParams = extractCommandParameters(parsed.content);
|
|
@@ -14850,25 +14882,13 @@ var EXECUTION_MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
|
14850
14882
|
// src/workflows/resource-limits.ts
|
|
14851
14883
|
var WORKFLOW_MAX_PLAN_BYTES = 2 * 1024 * 1024;
|
|
14852
14884
|
var WORKFLOW_MAX_SOURCE_BYTES = 1024 * 1024;
|
|
14853
|
-
var WORKFLOW_MAX_STEPS = 256;
|
|
14854
|
-
var WORKFLOW_MAX_PARAMS = 128;
|
|
14855
|
-
var WORKFLOW_MAX_ROUTE_BRANCHES = 256;
|
|
14856
14885
|
var WORKFLOW_MAX_INSTRUCTION_BYTES = 256 * 1024;
|
|
14857
14886
|
var WORKFLOW_MAX_SCHEMA_BYTES = 256 * 1024;
|
|
14858
14887
|
var WORKFLOW_MAX_EXTRA_PARAMS_BYTES = 64 * 1024;
|
|
14859
|
-
var WORKFLOW_MAX_MAP_EXPANSION = 1e4;
|
|
14860
|
-
var WORKFLOW_MAX_INPUTS = 64;
|
|
14861
|
-
var WORKFLOW_MAX_OUTPUTS = 64;
|
|
14862
14888
|
var WORKFLOW_MAX_CONCURRENCY = 64;
|
|
14863
|
-
var WORKFLOW_MAX_GATE_LOOPS = 100;
|
|
14864
|
-
var WORKFLOW_MAX_RETRIES = 100;
|
|
14865
14889
|
var WORKFLOW_MAX_TIMEOUT_MS = EXECUTION_MAX_TIMEOUT_MS;
|
|
14866
14890
|
var WORKFLOW_ENGINE_NAME_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
14867
14891
|
var WORKFLOW_MAX_ENGINE_NAME_LENGTH = 63;
|
|
14868
|
-
var WORKFLOW_MAX_EXEC_ARGV = 64;
|
|
14869
|
-
var WORKFLOW_MAX_EXEC_ARG_BYTES = 4096;
|
|
14870
|
-
var WORKFLOW_MAX_EXEC_CWD_LENGTH = 1024;
|
|
14871
|
-
var WORKFLOW_MAX_EXEC_PASS_ENV = 32;
|
|
14872
14892
|
var WORKFLOW_ENV_VAR_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
14873
14893
|
var WORKFLOW_MAX_EXEC_OUTPUT_BYTES = 8 * 1024 * 1024;
|
|
14874
14894
|
var EXEC_CONTEXT_LIMITS_POSIX = {
|
|
@@ -14886,13 +14906,13 @@ function jsonBytes(value) {
|
|
|
14886
14906
|
var WORKFLOW_MAX_EMBEDDED_CHILD_PLAN_BYTES = 1024 * 1024;
|
|
14887
14907
|
|
|
14888
14908
|
// src/tasks/source/bounded-document.ts
|
|
14889
|
-
var TASK_V3_MAX_SOURCE_BYTES = 1024 * 1024;
|
|
14890
14909
|
var TASK_V3_MAX_JSON_DEPTH = 64;
|
|
14891
14910
|
var TASK_V3_MAX_JSON_NODES = 1e4;
|
|
14892
14911
|
var TASK_V3_MAX_COLLECTION_ITEMS = 1024;
|
|
14893
14912
|
var TASK_V3_MAX_OBJECT_KEYS = 256;
|
|
14894
14913
|
var TASK_V3_MAX_STRING_BYTES = 256 * 1024;
|
|
14895
14914
|
var TASK_V3_MAX_SCHEDULES = 64;
|
|
14915
|
+
var TASK_V3_MAX_REDACT_NAMES = 32;
|
|
14896
14916
|
function own2(value, key) {
|
|
14897
14917
|
return Object.hasOwn(value, key);
|
|
14898
14918
|
}
|
|
@@ -15181,9 +15201,6 @@ function readBoundedTaskSourceYaml(input, options) {
|
|
|
15181
15201
|
if (typeof input.yaml !== "string") {
|
|
15182
15202
|
throw new UsageError(`Invalid ${sourceLabel} at ${input.filePath}: source must be a string.`, "TASK_SOURCE_INVALID");
|
|
15183
15203
|
}
|
|
15184
|
-
if (utf8Bytes2(input.yaml) > TASK_V3_MAX_SOURCE_BYTES) {
|
|
15185
|
-
throw new UsageError(`Invalid ${sourceLabel} at ${input.filePath}: source exceeds the 1 MiB (${TASK_V3_MAX_SOURCE_BYTES}-byte) resource limit.`, "TASK_SOURCE_INVALID");
|
|
15186
|
-
}
|
|
15187
15204
|
const lineCounter2 = new $LineCounter;
|
|
15188
15205
|
let document;
|
|
15189
15206
|
try {
|
|
@@ -15943,7 +15960,7 @@ function parseExecutionControls(input, ctx) {
|
|
|
15943
15960
|
out.timeout = parseTimeoutTopLevel(input.timeout, ctx);
|
|
15944
15961
|
if (own2(input, "redact")) {
|
|
15945
15962
|
const names = parseStringArray(input.redact, ctx, ["redact"], {
|
|
15946
|
-
max:
|
|
15963
|
+
max: TASK_V3_MAX_REDACT_NAMES,
|
|
15947
15964
|
pattern: WORKFLOW_ENV_VAR_NAME_PATTERN
|
|
15948
15965
|
});
|
|
15949
15966
|
if (new Set(names).size !== names.length)
|
|
@@ -15957,8 +15974,8 @@ function parseExecutionControls(input, ctx) {
|
|
|
15957
15974
|
out.maxSteps = input.maxSteps;
|
|
15958
15975
|
}
|
|
15959
15976
|
if (own2(input, "maxRetries")) {
|
|
15960
|
-
if (!Number.isSafeInteger(input.maxRetries) || input.maxRetries < 0
|
|
15961
|
-
sourceError(ctx, ["maxRetries"],
|
|
15977
|
+
if (!Number.isSafeInteger(input.maxRetries) || input.maxRetries < 0) {
|
|
15978
|
+
sourceError(ctx, ["maxRetries"], "must be a non-negative safe integer.");
|
|
15962
15979
|
}
|
|
15963
15980
|
out.maxRetries = input.maxRetries;
|
|
15964
15981
|
}
|
|
@@ -16018,9 +16035,6 @@ function parseInputDeclaration(name, raw, ctx) {
|
|
|
16018
16035
|
function parseInputDeclarations(value, ctx) {
|
|
16019
16036
|
const input = asRecord(value, ctx, ["inputs"]);
|
|
16020
16037
|
const names = Object.keys(input);
|
|
16021
|
-
if (names.length > WORKFLOW_MAX_PARAMS) {
|
|
16022
|
-
sourceError(ctx, ["inputs"], `accepts at most ${WORKFLOW_MAX_PARAMS} declared inputs.`);
|
|
16023
|
-
}
|
|
16024
16038
|
const result = {};
|
|
16025
16039
|
for (const name of names) {
|
|
16026
16040
|
if (!INPUT_NAME_PATTERN.test(name)) {
|
|
@@ -16453,7 +16467,7 @@ function parseAkm(value, ctx) {
|
|
|
16453
16467
|
out.timeout = parseTimeout(input.timeout, ctx);
|
|
16454
16468
|
if (own2(input, "redact")) {
|
|
16455
16469
|
const names = parseStringArray(input.redact, ctx, ["akm", "redact"], {
|
|
16456
|
-
max:
|
|
16470
|
+
max: TASK_V3_MAX_REDACT_NAMES,
|
|
16457
16471
|
pattern: WORKFLOW_ENV_VAR_NAME_PATTERN
|
|
16458
16472
|
});
|
|
16459
16473
|
if (new Set(names).size !== names.length)
|
|
@@ -16467,8 +16481,8 @@ function parseAkm(value, ctx) {
|
|
|
16467
16481
|
out.maxSteps = input.maxSteps;
|
|
16468
16482
|
}
|
|
16469
16483
|
if (own2(input, "maxRetries")) {
|
|
16470
|
-
if (!Number.isSafeInteger(input.maxRetries) || input.maxRetries < 0
|
|
16471
|
-
sourceError(ctx, ["akm", "maxRetries"],
|
|
16484
|
+
if (!Number.isSafeInteger(input.maxRetries) || input.maxRetries < 0) {
|
|
16485
|
+
sourceError(ctx, ["akm", "maxRetries"], "must be a non-negative safe integer.");
|
|
16472
16486
|
}
|
|
16473
16487
|
out.maxRetries = input.maxRetries;
|
|
16474
16488
|
}
|
|
@@ -16722,6 +16736,16 @@ var SHELL_ASSIGNMENT_WORD = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
|
16722
16736
|
function shellStableV2Executable(executable) {
|
|
16723
16737
|
return executable === "akm" || executable.includes("/");
|
|
16724
16738
|
}
|
|
16739
|
+
function skipEnvAssignmentPrefix(tokens) {
|
|
16740
|
+
if (tokens[0] !== "env")
|
|
16741
|
+
return { tokens, envWrapped: false };
|
|
16742
|
+
let index = 1;
|
|
16743
|
+
while (index < tokens.length && SHELL_ASSIGNMENT_WORD.test(tokens[index]))
|
|
16744
|
+
index += 1;
|
|
16745
|
+
if (index >= tokens.length)
|
|
16746
|
+
return { tokens, envWrapped: false };
|
|
16747
|
+
return { tokens: tokens.slice(index), envWrapped: true };
|
|
16748
|
+
}
|
|
16725
16749
|
var KNOWN_PROMPT_REF_FAMILIES = new Set([
|
|
16726
16750
|
"agents",
|
|
16727
16751
|
"commands",
|
|
@@ -16742,11 +16766,6 @@ function hash(bytes) {
|
|
|
16742
16766
|
return crypto.createHash("sha256").update(bytes).digest("hex");
|
|
16743
16767
|
}
|
|
16744
16768
|
function base(input) {
|
|
16745
|
-
const inspectionIdentity = input.inspectionIdentity ? Object.freeze({
|
|
16746
|
-
file: Object.freeze({ ...input.inspectionIdentity.file }),
|
|
16747
|
-
root: Object.freeze({ ...input.inspectionIdentity.root }),
|
|
16748
|
-
...input.inspectionIdentity.bundleRoot ? { bundleRoot: Object.freeze({ ...input.inspectionIdentity.bundleRoot }) } : {}
|
|
16749
|
-
}) : undefined;
|
|
16750
16769
|
return {
|
|
16751
16770
|
filePath: input.filePath,
|
|
16752
16771
|
before: Buffer.from(input.bytes),
|
|
@@ -16754,8 +16773,7 @@ function base(input) {
|
|
|
16754
16773
|
mode: input.mode,
|
|
16755
16774
|
writable: input.writable,
|
|
16756
16775
|
...input.onDiskWritable !== undefined ? { onDiskWritable: input.onDiskWritable } : {},
|
|
16757
|
-
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
16758
|
-
...inspectionIdentity ? { inspectionIdentity } : {}
|
|
16776
|
+
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
16759
16777
|
};
|
|
16760
16778
|
}
|
|
16761
16779
|
function blocked(input, reason, detail) {
|
|
@@ -16781,9 +16799,6 @@ function optionalString(value, label) {
|
|
|
16781
16799
|
return exactString(value, label);
|
|
16782
16800
|
}
|
|
16783
16801
|
function parseLegacyTaskYaml(input) {
|
|
16784
|
-
if (input.bytes.byteLength > TASK_V3_MAX_SOURCE_BYTES) {
|
|
16785
|
-
throw new Error(`task YAML exceeds the 1 MiB (${TASK_V3_MAX_SOURCE_BYTES}-byte) source resource limit`);
|
|
16786
|
-
}
|
|
16787
16802
|
let source;
|
|
16788
16803
|
try {
|
|
16789
16804
|
source = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(input.bytes);
|
|
@@ -16831,7 +16846,7 @@ function validateCommonV2(data) {
|
|
|
16831
16846
|
}
|
|
16832
16847
|
}
|
|
16833
16848
|
if (data.redact !== undefined && data.redact !== null) {
|
|
16834
|
-
if (!Array.isArray(data.redact) || data.redact.length >
|
|
16849
|
+
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))) {
|
|
16835
16850
|
throw new Error("redact must contain only bounded environment variable names");
|
|
16836
16851
|
}
|
|
16837
16852
|
}
|
|
@@ -16957,8 +16972,8 @@ function migratedObject(data) {
|
|
|
16957
16972
|
akm.maxSteps = data.maxSteps;
|
|
16958
16973
|
}
|
|
16959
16974
|
if (data.maxRetries !== undefined && data.maxRetries !== null) {
|
|
16960
|
-
if (!Number.isSafeInteger(data.maxRetries) || data.maxRetries < 0
|
|
16961
|
-
throw new Error(
|
|
16975
|
+
if (!Number.isSafeInteger(data.maxRetries) || data.maxRetries < 0) {
|
|
16976
|
+
throw new Error("maxRetries must be a non-negative integer");
|
|
16962
16977
|
}
|
|
16963
16978
|
akm.maxRetries = data.maxRetries;
|
|
16964
16979
|
}
|
|
@@ -16991,8 +17006,9 @@ function migratedObject(data) {
|
|
|
16991
17006
|
if (tokens.length === 0 || tokens.some((token) => !SAFE_V2_COMMAND_TOKEN.test(token))) {
|
|
16992
17007
|
return "shell-operators-change-v2-literal-argv-semantics";
|
|
16993
17008
|
}
|
|
16994
|
-
const
|
|
16995
|
-
|
|
17009
|
+
const { tokens: targetTokens, envWrapped } = skipEnvAssignmentPrefix(tokens);
|
|
17010
|
+
const executable = targetTokens[0];
|
|
17011
|
+
if (SHELL_ASSIGNMENT_WORD.test(executable) || !envWrapped && !shellStableV2Executable(executable)) {
|
|
16996
17012
|
return "shell-command-resolution-changes-v2-literal-argv-semantics";
|
|
16997
17013
|
}
|
|
16998
17014
|
output.run = tokens.join(" ");
|
|
@@ -17186,11 +17202,6 @@ function causeMessage(cause) {
|
|
|
17186
17202
|
return cause instanceof Error ? cause.message : String(cause);
|
|
17187
17203
|
}
|
|
17188
17204
|
function base2(input) {
|
|
17189
|
-
const inspectionIdentity = input.inspectionIdentity ? Object.freeze({
|
|
17190
|
-
file: Object.freeze({ ...input.inspectionIdentity.file }),
|
|
17191
|
-
root: Object.freeze({ ...input.inspectionIdentity.root }),
|
|
17192
|
-
...input.inspectionIdentity.bundleRoot ? { bundleRoot: Object.freeze({ ...input.inspectionIdentity.bundleRoot }) } : {}
|
|
17193
|
-
}) : undefined;
|
|
17194
17205
|
return {
|
|
17195
17206
|
filePath: input.filePath,
|
|
17196
17207
|
before: Buffer.from(input.bytes),
|
|
@@ -17198,8 +17209,7 @@ function base2(input) {
|
|
|
17198
17209
|
mode: input.mode,
|
|
17199
17210
|
writable: input.writable,
|
|
17200
17211
|
...input.onDiskWritable !== undefined ? { onDiskWritable: input.onDiskWritable } : {},
|
|
17201
|
-
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
17202
|
-
...inspectionIdentity ? { inspectionIdentity } : {}
|
|
17212
|
+
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
17203
17213
|
};
|
|
17204
17214
|
}
|
|
17205
17215
|
function blocked2(input, reason, detail) {
|
|
@@ -17222,9 +17232,6 @@ function exactString2(value, label, nonempty = false) {
|
|
|
17222
17232
|
return value;
|
|
17223
17233
|
}
|
|
17224
17234
|
function parseV3RawYaml(input) {
|
|
17225
|
-
if (input.bytes.byteLength > TASK_V3_MAX_SOURCE_BYTES) {
|
|
17226
|
-
throw new Error(`task YAML exceeds the 1 MiB (${TASK_V3_MAX_SOURCE_BYTES}-byte) source resource limit`);
|
|
17227
|
-
}
|
|
17228
17235
|
let source;
|
|
17229
17236
|
try {
|
|
17230
17237
|
source = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(input.bytes);
|
|
@@ -18425,7 +18432,7 @@ function validateStep(value, jobId, index, stepIds, options) {
|
|
|
18425
18432
|
}
|
|
18426
18433
|
validateMap(step.map, `step ${id} map`);
|
|
18427
18434
|
validateRoute(step.route, `step ${id} route`);
|
|
18428
|
-
optionalStringList(step.inputs, `step ${id} inputs`,
|
|
18435
|
+
optionalStringList(step.inputs, `step ${id} inputs`, Infinity);
|
|
18429
18436
|
if (Array.isArray(step.inputs)) {
|
|
18430
18437
|
for (const [inputIndex, input] of step.inputs.entries())
|
|
18431
18438
|
validateReference(input, `step ${id} inputs[${inputIndex}]`);
|
|
@@ -18447,12 +18454,7 @@ function validateExec(value, location, options) {
|
|
|
18447
18454
|
return;
|
|
18448
18455
|
const exec = record(value, location);
|
|
18449
18456
|
keys(exec, ["command", "cwd", "passEnv"], location);
|
|
18450
|
-
stringList(exec.command, `${location}.command`,
|
|
18451
|
-
for (const [index, argument] of exec.command.entries()) {
|
|
18452
|
-
if (utf8Bytes(argument) > WORKFLOW_MAX_EXEC_ARG_BYTES) {
|
|
18453
|
-
fail2(`${location}.command[${index}] exceeds ${WORKFLOW_MAX_EXEC_ARG_BYTES} bytes`);
|
|
18454
|
-
}
|
|
18455
|
-
}
|
|
18457
|
+
stringList(exec.command, `${location}.command`, Infinity, false);
|
|
18456
18458
|
try {
|
|
18457
18459
|
rejectNulInArgv(exec.command);
|
|
18458
18460
|
} catch (cause) {
|
|
@@ -18460,9 +18462,6 @@ function validateExec(value, location, options) {
|
|
|
18460
18462
|
}
|
|
18461
18463
|
optionalString2(exec.cwd, `${location}.cwd`);
|
|
18462
18464
|
if (exec.cwd !== undefined) {
|
|
18463
|
-
if (exec.cwd.length > WORKFLOW_MAX_EXEC_CWD_LENGTH) {
|
|
18464
|
-
fail2(`${location}.cwd exceeds ${WORKFLOW_MAX_EXEC_CWD_LENGTH} characters`);
|
|
18465
|
-
}
|
|
18466
18465
|
try {
|
|
18467
18466
|
exec.cwd = canonicalizeWorkflowWorkingDirectory(exec.cwd, options.workspaceRoot);
|
|
18468
18467
|
} catch (cause) {
|
|
@@ -18470,7 +18469,7 @@ function validateExec(value, location, options) {
|
|
|
18470
18469
|
}
|
|
18471
18470
|
}
|
|
18472
18471
|
if (exec.passEnv !== undefined) {
|
|
18473
|
-
stringList(exec.passEnv, `${location}.passEnv`,
|
|
18472
|
+
stringList(exec.passEnv, `${location}.passEnv`, Infinity, false);
|
|
18474
18473
|
}
|
|
18475
18474
|
if (Array.isArray(exec.passEnv)) {
|
|
18476
18475
|
for (const name of exec.passEnv) {
|
|
@@ -18521,8 +18520,8 @@ function validateRetry(value, location) {
|
|
|
18521
18520
|
return;
|
|
18522
18521
|
const retry = record(value, location);
|
|
18523
18522
|
keys(retry, ["max", "on"], location);
|
|
18524
|
-
if (!Number.isSafeInteger(retry.max) || retry.max < 0
|
|
18525
|
-
fail2(`${location}.max must be
|
|
18523
|
+
if (!Number.isSafeInteger(retry.max) || retry.max < 0) {
|
|
18524
|
+
fail2(`${location}.max must be a non-negative integer`);
|
|
18526
18525
|
}
|
|
18527
18526
|
stringList(retry.on, `${location}.on`, PROGRAM_RETRY_REASONS.length, false);
|
|
18528
18527
|
for (const reason of retry.on) {
|
|
@@ -18552,8 +18551,8 @@ function validateRoute(value, location) {
|
|
|
18552
18551
|
keys(route, ["input", "branches", "defaultStepId"], location);
|
|
18553
18552
|
nonEmptyString2(route.input, `${location}.input`);
|
|
18554
18553
|
validateReference(route.input, `${location}.input`);
|
|
18555
|
-
if (!Array.isArray(route.branches) || route.branches.length === 0
|
|
18556
|
-
fail2(`${location}.branches must
|
|
18554
|
+
if (!Array.isArray(route.branches) || route.branches.length === 0) {
|
|
18555
|
+
fail2(`${location}.branches must be a non-empty array`);
|
|
18557
18556
|
}
|
|
18558
18557
|
const matches = new Set;
|
|
18559
18558
|
for (const [index, value2] of route.branches.entries()) {
|
|
@@ -18573,8 +18572,8 @@ function validateGate(value, location) {
|
|
|
18573
18572
|
return;
|
|
18574
18573
|
const gate = record(value, location);
|
|
18575
18574
|
keys(gate, ["maxLoops", "rubric"], location);
|
|
18576
|
-
if (gate.maxLoops !== undefined && (!Number.isSafeInteger(gate.maxLoops) || gate.maxLoops < 1
|
|
18577
|
-
fail2(`${location}.maxLoops must be an integer
|
|
18575
|
+
if (gate.maxLoops !== undefined && (!Number.isSafeInteger(gate.maxLoops) || gate.maxLoops < 1)) {
|
|
18576
|
+
fail2(`${location}.maxLoops must be an integer of at least 1`);
|
|
18578
18577
|
}
|
|
18579
18578
|
optionalString2(gate.rubric, `${location}.rubric`);
|
|
18580
18579
|
}
|
|
@@ -18607,8 +18606,8 @@ function validateParams(value) {
|
|
|
18607
18606
|
if (value === undefined)
|
|
18608
18607
|
return;
|
|
18609
18608
|
const params = record(value, "params");
|
|
18610
|
-
if (Object.keys(params).length === 0
|
|
18611
|
-
fail2(`params must contain
|
|
18609
|
+
if (Object.keys(params).length === 0) {
|
|
18610
|
+
fail2(`params must contain at least one entry`);
|
|
18612
18611
|
}
|
|
18613
18612
|
for (const [name, schema] of Object.entries(params)) {
|
|
18614
18613
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
@@ -18620,8 +18619,8 @@ function validateOutputs(value) {
|
|
|
18620
18619
|
if (value === undefined)
|
|
18621
18620
|
return;
|
|
18622
18621
|
const outputs = record(value, "outputs");
|
|
18623
|
-
if (Object.keys(outputs).length === 0
|
|
18624
|
-
fail2(`outputs must contain
|
|
18622
|
+
if (Object.keys(outputs).length === 0) {
|
|
18623
|
+
fail2(`outputs must contain at least one entry`);
|
|
18625
18624
|
}
|
|
18626
18625
|
for (const [name, declaration] of Object.entries(outputs)) {
|
|
18627
18626
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
@@ -18644,9 +18643,6 @@ function validateBudget(value) {
|
|
|
18644
18643
|
fail2(`budget.${key} must be a positive integer`);
|
|
18645
18644
|
}
|
|
18646
18645
|
}
|
|
18647
|
-
if (typeof budget.maxUnits === "number" && budget.maxUnits > WORKFLOW_MAX_MAP_EXPANSION) {
|
|
18648
|
-
fail2(`budget.maxUnits must be at most ${WORKFLOW_MAX_MAP_EXPANSION}`);
|
|
18649
|
-
}
|
|
18650
18646
|
}
|
|
18651
18647
|
function validateLlm(value, location) {
|
|
18652
18648
|
if (value === undefined)
|
|
@@ -19230,12 +19226,6 @@ function checkXrefs(value, line, errors2) {
|
|
|
19230
19226
|
}
|
|
19231
19227
|
}
|
|
19232
19228
|
function checkResourceLimits(draft, errors2) {
|
|
19233
|
-
if (draft.steps.length > WORKFLOW_MAX_STEPS) {
|
|
19234
|
-
errors2.push({ line: 1, message: `Workflow must contain at most ${WORKFLOW_MAX_STEPS} steps.` });
|
|
19235
|
-
}
|
|
19236
|
-
if (Object.keys(draft.params ?? {}).length > WORKFLOW_MAX_PARAMS) {
|
|
19237
|
-
errors2.push({ line: 1, message: `Workflow must contain at most ${WORKFLOW_MAX_PARAMS} parameters.` });
|
|
19238
|
-
}
|
|
19239
19229
|
for (const step of draft.steps) {
|
|
19240
19230
|
if (step.instructions && utf8Bytes(step.instructions.text) > WORKFLOW_MAX_INSTRUCTION_BYTES) {
|
|
19241
19231
|
errors2.push({
|
|
@@ -19597,9 +19587,6 @@ function parseParams(ctx, raw) {
|
|
|
19597
19587
|
ctx.err(["params"], `"params" must be a mapping of param name to a JSON Schema object (e.g. changed_files: { type: array }).`);
|
|
19598
19588
|
return;
|
|
19599
19589
|
}
|
|
19600
|
-
if (Object.keys(raw).length > WORKFLOW_MAX_PARAMS) {
|
|
19601
|
-
ctx.err(["params"], `"params" must contain at most ${WORKFLOW_MAX_PARAMS} entries.`);
|
|
19602
|
-
}
|
|
19603
19590
|
const params = {};
|
|
19604
19591
|
for (const [paramName, value] of Object.entries(raw)) {
|
|
19605
19592
|
if (!INPUT_NAME_PATTERN.test(paramName)) {
|
|
@@ -19625,9 +19612,6 @@ function parseOutputs(ctx, raw) {
|
|
|
19625
19612
|
ctx.err(["outputs"], `"outputs" must be a mapping of output name to { from, schema? } (e.g. report: { from: steps.summarize.output }).`);
|
|
19626
19613
|
return;
|
|
19627
19614
|
}
|
|
19628
|
-
if (Object.keys(raw).length > WORKFLOW_MAX_OUTPUTS) {
|
|
19629
|
-
ctx.err(["outputs"], `"outputs" must contain at most ${WORKFLOW_MAX_OUTPUTS} entries.`);
|
|
19630
|
-
}
|
|
19631
19615
|
const outputs = {};
|
|
19632
19616
|
for (const [outputName, value] of Object.entries(raw)) {
|
|
19633
19617
|
const path13 = ["outputs", outputName];
|
|
@@ -19719,10 +19703,10 @@ function parseBudget(ctx, raw) {
|
|
|
19719
19703
|
}
|
|
19720
19704
|
}
|
|
19721
19705
|
if (raw.max_units !== undefined) {
|
|
19722
|
-
if (typeof raw.max_units === "number" && Number.isInteger(raw.max_units) && raw.max_units >= 1
|
|
19706
|
+
if (typeof raw.max_units === "number" && Number.isInteger(raw.max_units) && raw.max_units >= 1) {
|
|
19723
19707
|
budget.maxUnits = raw.max_units;
|
|
19724
19708
|
} else {
|
|
19725
|
-
ctx.err([...path13, "max_units"], `"budget.max_units" must be an integer
|
|
19709
|
+
ctx.err([...path13, "max_units"], `"budget.max_units" must be an integer >= 1.`);
|
|
19726
19710
|
}
|
|
19727
19711
|
}
|
|
19728
19712
|
return Object.keys(budget).length > 0 ? budget : undefined;
|
|
@@ -19732,9 +19716,6 @@ function parseSteps(ctx, raw) {
|
|
|
19732
19716
|
ctx.err(["steps"], `"steps" is required and must be a list with at least one step.`);
|
|
19733
19717
|
return [];
|
|
19734
19718
|
}
|
|
19735
|
-
if (raw.length > WORKFLOW_MAX_STEPS) {
|
|
19736
|
-
ctx.err(["steps"], `"steps" must contain at most ${WORKFLOW_MAX_STEPS} entries.`);
|
|
19737
|
-
}
|
|
19738
19719
|
const idIndex = new Map;
|
|
19739
19720
|
raw.forEach((rawStep, index) => {
|
|
19740
19721
|
if (isPlainRecord(rawStep) && typeof rawStep.id === "string" && !idIndex.has(rawStep.id)) {
|
|
@@ -19905,10 +19886,6 @@ function parseExecPassEnv(ctx, raw, path13, stepLabel) {
|
|
|
19905
19886
|
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 \u2014 use "env:" bindings for those.`);
|
|
19906
19887
|
return;
|
|
19907
19888
|
}
|
|
19908
|
-
if (raw.length > WORKFLOW_MAX_EXEC_PASS_ENV) {
|
|
19909
|
-
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.`);
|
|
19910
|
-
return;
|
|
19911
|
-
}
|
|
19912
19889
|
const names = [];
|
|
19913
19890
|
for (const [index, entry] of raw.entries()) {
|
|
19914
19891
|
if (typeof entry !== "string" || !WORKFLOW_ENV_VAR_NAME_PATTERN.test(entry)) {
|
|
@@ -19928,10 +19905,6 @@ function parseExecCommand(ctx, raw, path13, stepLabel) {
|
|
|
19928
19905
|
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 \u2014 the command is spawned directly, never through a shell.`);
|
|
19929
19906
|
return;
|
|
19930
19907
|
}
|
|
19931
|
-
if (raw.length > WORKFLOW_MAX_EXEC_ARGV) {
|
|
19932
|
-
ctx.err(path13, `${stepLabel} "exec.command" must have at most ${WORKFLOW_MAX_EXEC_ARGV} entries.`);
|
|
19933
|
-
return;
|
|
19934
|
-
}
|
|
19935
19908
|
const argv = [];
|
|
19936
19909
|
for (const [index, entry] of raw.entries()) {
|
|
19937
19910
|
if (typeof entry !== "string" || entry === "") {
|
|
@@ -19942,10 +19915,6 @@ function parseExecCommand(ctx, raw, path13, stepLabel) {
|
|
|
19942
19915
|
ctx.err([...path13, index], `${stepLabel} "exec.command[${index}]" may not contain NUL bytes.`);
|
|
19943
19916
|
return;
|
|
19944
19917
|
}
|
|
19945
|
-
if (utf8Bytes(entry) > WORKFLOW_MAX_EXEC_ARG_BYTES) {
|
|
19946
|
-
ctx.err(path13, `${stepLabel} "exec.command[${index}]" exceeds ${WORKFLOW_MAX_EXEC_ARG_BYTES} bytes.`);
|
|
19947
|
-
return;
|
|
19948
|
-
}
|
|
19949
19918
|
argv.push(entry);
|
|
19950
19919
|
}
|
|
19951
19920
|
return argv;
|
|
@@ -19958,10 +19927,6 @@ function parseExecCwd(ctx, raw, path13, stepLabel) {
|
|
|
19958
19927
|
return;
|
|
19959
19928
|
}
|
|
19960
19929
|
const value = raw.trim();
|
|
19961
|
-
if (value.length > WORKFLOW_MAX_EXEC_CWD_LENGTH) {
|
|
19962
|
-
ctx.err(path13, `${stepLabel} "exec.cwd" exceeds ${WORKFLOW_MAX_EXEC_CWD_LENGTH} characters.`);
|
|
19963
|
-
return;
|
|
19964
|
-
}
|
|
19965
19930
|
if (!isContainedRelativePath(value)) {
|
|
19966
19931
|
ctx.err(path13, `${stepLabel} "exec.cwd" (${JSON.stringify(value)}) must be a RELATIVE path inside the unit's working ` + `directory \u2014 absolute paths, Windows drive letters, "~", and ".." segments are rejected.`);
|
|
19967
19932
|
return;
|
|
@@ -19995,10 +19960,10 @@ function parseMap(ctx, raw, path13, stepLabel) {
|
|
|
19995
19960
|
}
|
|
19996
19961
|
let concurrency;
|
|
19997
19962
|
if (raw.concurrency !== undefined) {
|
|
19998
|
-
if (typeof raw.concurrency === "number" && Number.isInteger(raw.concurrency) && raw.concurrency > 0
|
|
19999
|
-
concurrency = raw.concurrency;
|
|
19963
|
+
if (typeof raw.concurrency === "number" && Number.isInteger(raw.concurrency) && raw.concurrency > 0) {
|
|
19964
|
+
concurrency = Math.min(raw.concurrency, WORKFLOW_MAX_CONCURRENCY);
|
|
20000
19965
|
} else {
|
|
20001
|
-
ctx.err([...path13, "concurrency"], `${stepLabel} "concurrency" must be
|
|
19966
|
+
ctx.err([...path13, "concurrency"], `${stepLabel} "concurrency" must be a positive integer.`);
|
|
20002
19967
|
}
|
|
20003
19968
|
}
|
|
20004
19969
|
const reducer = parseEnumField(ctx, raw.reducer, [...path13, "reducer"], `${stepLabel} "reducer"`, PROGRAM_REDUCERS);
|
|
@@ -20030,9 +19995,6 @@ function parseRoute(ctx, raw, path13, stepLabel, stepIndex, routeChecks) {
|
|
|
20030
19995
|
if (!Array.isArray(raw.when) || raw.when.length === 0) {
|
|
20031
19996
|
ctx.err(whenPath, `${stepLabel} "route" requires "when": a non-empty list of { match, step } branches (e.g. when: [{ match: pass, step: ship }]).`);
|
|
20032
19997
|
} else {
|
|
20033
|
-
if (raw.when.length > WORKFLOW_MAX_ROUTE_BRANCHES) {
|
|
20034
|
-
ctx.err(whenPath, `${stepLabel} "when" must contain at most ${WORKFLOW_MAX_ROUTE_BRANCHES} branches.`);
|
|
20035
|
-
}
|
|
20036
19998
|
const seenMatches = new Map;
|
|
20037
19999
|
raw.when.forEach((branch, i) => {
|
|
20038
20000
|
const branchPath = [...whenPath, i];
|
|
@@ -20088,9 +20050,6 @@ function parseInputs(ctx, raw, path13, stepLabel) {
|
|
|
20088
20050
|
ctx.err(path13, `${stepLabel} "inputs" must be a non-empty list of reference strings.`);
|
|
20089
20051
|
return;
|
|
20090
20052
|
}
|
|
20091
|
-
if (raw.length > WORKFLOW_MAX_INPUTS) {
|
|
20092
|
-
ctx.err(path13, `${stepLabel} "inputs" must contain at most ${WORKFLOW_MAX_INPUTS} entries.`);
|
|
20093
|
-
}
|
|
20094
20053
|
const out = [];
|
|
20095
20054
|
const seen = new Set;
|
|
20096
20055
|
raw.forEach((entry, i) => {
|
|
@@ -20117,10 +20076,10 @@ function parseGate(ctx, raw, path13, stepLabel) {
|
|
|
20117
20076
|
checkUnknownKeys(ctx, raw, path13, GATE_KEYS, `${stepLabel} "gate"`);
|
|
20118
20077
|
const gate = {};
|
|
20119
20078
|
if (raw.max_loops !== undefined) {
|
|
20120
|
-
if (typeof raw.max_loops === "number" && Number.isInteger(raw.max_loops) && raw.max_loops >= 1
|
|
20079
|
+
if (typeof raw.max_loops === "number" && Number.isInteger(raw.max_loops) && raw.max_loops >= 1) {
|
|
20121
20080
|
gate.maxLoops = raw.max_loops;
|
|
20122
20081
|
} else {
|
|
20123
|
-
ctx.err([...path13, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer
|
|
20082
|
+
ctx.err([...path13, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer of at least 1.`);
|
|
20124
20083
|
}
|
|
20125
20084
|
}
|
|
20126
20085
|
return gate;
|
|
@@ -20146,8 +20105,8 @@ function parseRetry(ctx, raw, path13, stepLabel) {
|
|
|
20146
20105
|
}
|
|
20147
20106
|
checkUnknownKeys(ctx, raw, path13, RETRY_KEYS, `${stepLabel} "retry"`);
|
|
20148
20107
|
let ok = true;
|
|
20149
|
-
if (!(typeof raw.max === "number" && Number.isInteger(raw.max) && raw.max >= 0
|
|
20150
|
-
ctx.err([...path13, "max"], `${stepLabel} "retry.max" is required and must be
|
|
20108
|
+
if (!(typeof raw.max === "number" && Number.isInteger(raw.max) && raw.max >= 0)) {
|
|
20109
|
+
ctx.err([...path13, "max"], `${stepLabel} "retry.max" is required and must be a non-negative integer.`);
|
|
20151
20110
|
ok = false;
|
|
20152
20111
|
}
|
|
20153
20112
|
const on = [];
|
|
@@ -21764,6 +21723,8 @@ function indexDocumentFromEntry(entry, base3, rendererName) {
|
|
|
21764
21723
|
doc.tags = entry.tags;
|
|
21765
21724
|
if (entry.content !== undefined)
|
|
21766
21725
|
doc.content = entry.content;
|
|
21726
|
+
if (entry.contentTruncated !== undefined)
|
|
21727
|
+
doc.contentTruncated = entry.contentTruncated;
|
|
21767
21728
|
if (entry.aliases !== undefined)
|
|
21768
21729
|
doc.aliases = entry.aliases;
|
|
21769
21730
|
if (entry.searchHints !== undefined)
|
|
@@ -23733,7 +23694,7 @@ function withLockOperationMutex(lockPath, run) {
|
|
|
23733
23694
|
db.exec("BEGIN IMMEDIATE");
|
|
23734
23695
|
began = db.inTransaction;
|
|
23735
23696
|
if (!began)
|
|
23736
|
-
|
|
23697
|
+
sleepSync(2 ** attempt);
|
|
23737
23698
|
}
|
|
23738
23699
|
if (!began)
|
|
23739
23700
|
throw new Error(`Could not acquire lock operation mutex for ${lockPath}.`);
|
|
@@ -23896,7 +23857,7 @@ function extractHolderPid(content) {
|
|
|
23896
23857
|
// src/core/config/config-io.ts
|
|
23897
23858
|
function readConfigText(configPath) {
|
|
23898
23859
|
try {
|
|
23899
|
-
return
|
|
23860
|
+
return readTextFile(configPath, "Config file");
|
|
23900
23861
|
} catch (err) {
|
|
23901
23862
|
if (err.code === "ENOENT")
|
|
23902
23863
|
return;
|
|
@@ -28003,9 +27964,6 @@ var ExtraParamsSchema = exports_external.record(exports_external.unknown()).supe
|
|
|
28003
27964
|
ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path: issue.path, message: issue.message });
|
|
28004
27965
|
}
|
|
28005
27966
|
});
|
|
28006
|
-
var LlmCapabilitiesSchema = exports_external.object({
|
|
28007
|
-
structuredOutput: exports_external.boolean().optional()
|
|
28008
|
-
}).passthrough();
|
|
28009
27967
|
var LlmInvocationOverridesSchema = exports_external.object({
|
|
28010
27968
|
temperature: exports_external.number().finite().optional(),
|
|
28011
27969
|
maxTokens: positiveInt.optional(),
|
|
@@ -28061,15 +28019,13 @@ var LlmConnectionConfigSchema = exports_external.object({
|
|
|
28061
28019
|
maxTokens: positiveInt.optional(),
|
|
28062
28020
|
timeoutMs: timeoutMsField,
|
|
28063
28021
|
concurrency: positiveInt.optional(),
|
|
28064
|
-
|
|
28022
|
+
supportsJsonSchema: exports_external.boolean().optional(),
|
|
28065
28023
|
extraParams: ExtraParamsSchema.optional(),
|
|
28066
28024
|
contextLength: positiveInt.optional(),
|
|
28067
28025
|
enableThinking: exports_external.boolean().optional(),
|
|
28068
28026
|
reasoningEffort: nonEmptyString3.optional()
|
|
28069
28027
|
}).passthrough();
|
|
28070
|
-
var LlmProfileConfigSchema = LlmConnectionConfigSchema.
|
|
28071
|
-
supportsJsonSchema: exports_external.boolean().optional()
|
|
28072
|
-
}).passthrough();
|
|
28028
|
+
var LlmProfileConfigSchema = LlmConnectionConfigSchema.passthrough();
|
|
28073
28029
|
var AgentPlatformSchema = exports_external.enum(VALID_HARNESS_IDS);
|
|
28074
28030
|
var LlmEngineSchema = exports_external.object({
|
|
28075
28031
|
kind: exports_external.literal("llm"),
|
|
@@ -28081,7 +28037,6 @@ var LlmEngineSchema = exports_external.object({
|
|
|
28081
28037
|
maxTokens: positiveInt.optional(),
|
|
28082
28038
|
timeoutMs: timeoutMsField,
|
|
28083
28039
|
concurrency: positiveInt.optional(),
|
|
28084
|
-
supportsJsonSchema: exports_external.boolean().optional(),
|
|
28085
28040
|
extraParams: ExtraParamsSchema.optional(),
|
|
28086
28041
|
contextLength: positiveInt.optional(),
|
|
28087
28042
|
enableThinking: exports_external.boolean().optional(),
|
|
@@ -28111,7 +28066,6 @@ var AgentEngineSchema = exports_external.object({
|
|
|
28111
28066
|
"temperature",
|
|
28112
28067
|
"maxTokens",
|
|
28113
28068
|
"concurrency",
|
|
28114
|
-
"supportsJsonSchema",
|
|
28115
28069
|
"extraParams",
|
|
28116
28070
|
"contextLength",
|
|
28117
28071
|
"enableThinking",
|
|
@@ -28477,7 +28431,7 @@ var SearchGraphBoostSchema = exports_external.object({
|
|
|
28477
28431
|
hopBoostPerEntity: nonNegativeNumber.optional(),
|
|
28478
28432
|
hopBoostCap: nonNegativeNumber.optional(),
|
|
28479
28433
|
maxHops: positiveInt.max(3).optional(),
|
|
28480
|
-
confidenceMode: exports_external.enum(["
|
|
28434
|
+
confidenceMode: exports_external.enum(["blend"]).default("blend").optional(),
|
|
28481
28435
|
confidenceWeight: exports_external.number().finite().min(0).max(1).default(0.2).optional()
|
|
28482
28436
|
}).passthrough();
|
|
28483
28437
|
var SearchConfigSchema = exports_external.object({
|
|
@@ -28814,6 +28768,43 @@ var AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
|
|
|
28814
28768
|
}
|
|
28815
28769
|
});
|
|
28816
28770
|
|
|
28771
|
+
// src/core/config/config-version-shim.ts
|
|
28772
|
+
var KNOWN_OLD_CONFIG_VERSIONS = ["0.0.1"];
|
|
28773
|
+
function isKnownOldConfigVersion(value) {
|
|
28774
|
+
return typeof value === "string" && KNOWN_OLD_CONFIG_VERSIONS.includes(value);
|
|
28775
|
+
}
|
|
28776
|
+
function upgradeFrom080(raw) {
|
|
28777
|
+
const { defaultEngine, defaults, ...rest } = raw;
|
|
28778
|
+
if (typeof defaultEngine !== "string" || defaultEngine.length === 0) {
|
|
28779
|
+
return { ...rest, ...defaults !== undefined ? { defaults } : {}, configVersion: CURRENT_CONFIG_VERSION };
|
|
28780
|
+
}
|
|
28781
|
+
const existingDefaults = defaults !== null && typeof defaults === "object" ? defaults : {};
|
|
28782
|
+
return {
|
|
28783
|
+
...rest,
|
|
28784
|
+
configVersion: CURRENT_CONFIG_VERSION,
|
|
28785
|
+
defaults: { llmEngine: defaultEngine, ...existingDefaults }
|
|
28786
|
+
};
|
|
28787
|
+
}
|
|
28788
|
+
var CONFIG_VERSION_UPGRADES = {
|
|
28789
|
+
"0.0.1": upgradeFrom080
|
|
28790
|
+
};
|
|
28791
|
+
function unsupportedConfigVersionError(rawVersion, sourcePath) {
|
|
28792
|
+
const where = sourcePath ? ` at ${sourcePath}` : "";
|
|
28793
|
+
const supported = [CURRENT_CONFIG_VERSION, ...KNOWN_OLD_CONFIG_VERSIONS].map((v) => `"${v}"`).join(", ");
|
|
28794
|
+
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.");
|
|
28795
|
+
}
|
|
28796
|
+
function upgradeConfigVersion(raw, sourcePath) {
|
|
28797
|
+
const version = raw.configVersion;
|
|
28798
|
+
if (version === CURRENT_CONFIG_VERSION)
|
|
28799
|
+
return raw;
|
|
28800
|
+
if (isKnownOldConfigVersion(version)) {
|
|
28801
|
+
const upgraded = CONFIG_VERSION_UPGRADES[version](raw);
|
|
28802
|
+
warn(`Config${sourcePath ? ` at ${sourcePath}` : ""} uses configVersion "${version}" \u2014 auto-upgraded to ${CURRENT_CONFIG_VERSION} in memory; the next config write (e.g. \`akm config set\`) persists this and silences the warning.`);
|
|
28803
|
+
return upgraded;
|
|
28804
|
+
}
|
|
28805
|
+
throw unsupportedConfigVersionError(version, sourcePath);
|
|
28806
|
+
}
|
|
28807
|
+
|
|
28817
28808
|
// src/core/config/deep-merge.ts
|
|
28818
28809
|
var UNSAFE_KEYS3 = new Set(["__proto__", "constructor", "prototype"]);
|
|
28819
28810
|
function isPlainObject4(value) {
|
|
@@ -28904,10 +28895,7 @@ function loadUserConfig() {
|
|
|
28904
28895
|
return finalConfig;
|
|
28905
28896
|
}
|
|
28906
28897
|
function parseAndValidateConfigText(text, sourcePath) {
|
|
28907
|
-
const parsedRaw = parseConfigText(text, sourcePath);
|
|
28908
|
-
if (parsedRaw.configVersion !== CURRENT_CONFIG_VERSION) {
|
|
28909
|
-
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.");
|
|
28910
|
-
}
|
|
28898
|
+
const parsedRaw = upgradeConfigVersion(parseConfigText(text, sourcePath), sourcePath);
|
|
28911
28899
|
const { config: raw, lifted, conflicts } = liftLegacyEngineExtraParams(parsedRaw);
|
|
28912
28900
|
const where = sourcePath ? ` at ${sourcePath}` : "";
|
|
28913
28901
|
if (conflicts.length > 0) {
|
|
@@ -28985,8 +28973,7 @@ function withMaintenanceStartBarrier(run) {
|
|
|
28985
28973
|
|
|
28986
28974
|
// src/indexer/index-writer-lock.ts
|
|
28987
28975
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
28988
|
-
var
|
|
28989
|
-
var DEFAULT_INDEX_WRITER_MAX_WAIT_MS = 10 * 60 * 1000;
|
|
28976
|
+
var DEFAULT_ASSET_MUTATION_MAX_WAIT_MS = 10 * 60 * 1000;
|
|
28990
28977
|
var leaseContext = new AsyncLocalStorage2;
|
|
28991
28978
|
|
|
28992
28979
|
// src/integrations/lockfile.ts
|
|
@@ -29460,32 +29447,18 @@ function contained2(root, candidate) {
|
|
|
29460
29447
|
const relative = path31.relative(root, candidate);
|
|
29461
29448
|
return relative === "" || !relative.startsWith("..") && !path31.isAbsolute(relative);
|
|
29462
29449
|
}
|
|
29463
|
-
function
|
|
29464
|
-
const stat = fs26.lstatSync(filePath
|
|
29465
|
-
|
|
29466
|
-
|
|
29467
|
-
|
|
29468
|
-
if (kind === "file" && stat.nlink !== 1n)
|
|
29469
|
-
throw migrationError(`${filePath} must not be hard-linked.`);
|
|
29470
|
-
return Object.freeze({
|
|
29471
|
-
realPath: fs26.realpathSync(filePath),
|
|
29472
|
-
device: stat.dev.toString(),
|
|
29473
|
-
inode: stat.ino.toString(),
|
|
29474
|
-
linkCount: stat.nlink.toString(),
|
|
29475
|
-
changeTimeNs: stat.ctimeNs.toString()
|
|
29476
|
-
});
|
|
29477
|
-
}
|
|
29478
|
-
function sameIdentity2(left, right) {
|
|
29479
|
-
return left.realPath === right.realPath && left.device === right.device && left.inode === right.inode && left.linkCount === right.linkCount && left.changeTimeNs === right.changeTimeNs;
|
|
29450
|
+
function realDirectory(filePath) {
|
|
29451
|
+
const stat = fs26.lstatSync(filePath);
|
|
29452
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
29453
|
+
throw migrationError(`${filePath} must be a real directory.`);
|
|
29454
|
+
return fs26.realpathSync(filePath);
|
|
29480
29455
|
}
|
|
29481
29456
|
function snapshot(filePath) {
|
|
29482
|
-
const before = identity3(filePath, "file");
|
|
29483
29457
|
const stat = fs26.lstatSync(filePath);
|
|
29458
|
+
if (stat.isSymbolicLink() || !stat.isFile())
|
|
29459
|
+
throw migrationError(`${filePath} must be a real file.`);
|
|
29484
29460
|
const bytes = fs26.readFileSync(filePath);
|
|
29485
|
-
|
|
29486
|
-
if (!sameIdentity2(before, after))
|
|
29487
|
-
throw migrationError(`${filePath} changed while it was read.`);
|
|
29488
|
-
return Object.freeze({ bytes, mode: stat.mode & 511, identity: after });
|
|
29461
|
+
return Object.freeze({ bytes, mode: stat.mode & 511 });
|
|
29489
29462
|
}
|
|
29490
29463
|
function writable(filePath) {
|
|
29491
29464
|
try {
|
|
@@ -29496,10 +29469,9 @@ function writable(filePath) {
|
|
|
29496
29469
|
}
|
|
29497
29470
|
}
|
|
29498
29471
|
function walkTasks(root, tasksDir, out) {
|
|
29499
|
-
const
|
|
29500
|
-
const
|
|
29501
|
-
|
|
29502
|
-
if (!contained2(bundleIdentity.realPath, physicalRoot)) {
|
|
29472
|
+
const physicalRoot = realDirectory(root.root);
|
|
29473
|
+
const physicalBundleRoot = realDirectory(root.bundleRoot ?? root.root);
|
|
29474
|
+
if (!contained2(physicalBundleRoot, physicalRoot)) {
|
|
29503
29475
|
throw migrationError(`${root.root} resolves outside bundle ${root.bundleId}.`);
|
|
29504
29476
|
}
|
|
29505
29477
|
const visit2 = (directory) => {
|
|
@@ -29525,12 +29497,7 @@ function walkTasks(root, tasksDir, out) {
|
|
|
29525
29497
|
mode: current.mode,
|
|
29526
29498
|
writable: root.writable,
|
|
29527
29499
|
onDiskWritable: writable(candidate) && writable(parent) && (current.mode & 146) !== 0,
|
|
29528
|
-
containmentRoot: physicalRoot
|
|
29529
|
-
inspectionIdentity: Object.freeze({
|
|
29530
|
-
file: current.identity,
|
|
29531
|
-
root: rootIdentity,
|
|
29532
|
-
bundleRoot: bundleIdentity
|
|
29533
|
-
})
|
|
29500
|
+
containmentRoot: physicalRoot
|
|
29534
29501
|
});
|
|
29535
29502
|
}
|
|
29536
29503
|
};
|
|
@@ -29594,17 +29561,9 @@ function assertUnchanged(change) {
|
|
|
29594
29561
|
if (!current.bytes.equals(change.before) || current.mode !== change.mode) {
|
|
29595
29562
|
throw migrationError(`${change.filePath} changed after preview; no task files were replaced.`);
|
|
29596
29563
|
}
|
|
29597
|
-
const planned = change.inspectionIdentity?.file;
|
|
29598
|
-
if (planned && !sameIdentity2(planned, current.identity)) {
|
|
29599
|
-
throw migrationError(`${change.filePath} identity changed after preview; no task files were replaced.`);
|
|
29600
|
-
}
|
|
29601
29564
|
return current;
|
|
29602
29565
|
}
|
|
29603
29566
|
function applyTaskToV3MigrationPlan(plan, options) {
|
|
29604
|
-
const blocked3 = plan.files.filter((file) => file.status === "blocked");
|
|
29605
|
-
if (blocked3.length > 0) {
|
|
29606
|
-
throw migrationError(`plan is blocked: ${blocked3.map((file) => `${file.filePath} (${file.reason})`).join(", ")}. No files were written.`);
|
|
29607
|
-
}
|
|
29608
29567
|
const changes = plan.files.filter((file) => file.status === "changed");
|
|
29609
29568
|
for (const change of changes) {
|
|
29610
29569
|
assertUnchanged(change);
|
|
@@ -29647,32 +29606,18 @@ function contained3(root, candidate) {
|
|
|
29647
29606
|
const relative = path32.relative(root, candidate);
|
|
29648
29607
|
return relative === "" || !relative.startsWith("..") && !path32.isAbsolute(relative);
|
|
29649
29608
|
}
|
|
29650
|
-
function
|
|
29651
|
-
const stat = fs27.lstatSync(filePath
|
|
29652
|
-
|
|
29653
|
-
|
|
29654
|
-
|
|
29655
|
-
if (kind === "file" && stat.nlink !== 1n)
|
|
29656
|
-
throw migrationError2(`${filePath} must not be hard-linked.`);
|
|
29657
|
-
return Object.freeze({
|
|
29658
|
-
realPath: fs27.realpathSync(filePath),
|
|
29659
|
-
device: stat.dev.toString(),
|
|
29660
|
-
inode: stat.ino.toString(),
|
|
29661
|
-
linkCount: stat.nlink.toString(),
|
|
29662
|
-
changeTimeNs: stat.ctimeNs.toString()
|
|
29663
|
-
});
|
|
29664
|
-
}
|
|
29665
|
-
function sameIdentity3(left, right) {
|
|
29666
|
-
return left.realPath === right.realPath && left.device === right.device && left.inode === right.inode && left.linkCount === right.linkCount && left.changeTimeNs === right.changeTimeNs;
|
|
29609
|
+
function realDirectory2(filePath) {
|
|
29610
|
+
const stat = fs27.lstatSync(filePath);
|
|
29611
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
29612
|
+
throw migrationError2(`${filePath} must be a real directory.`);
|
|
29613
|
+
return fs27.realpathSync(filePath);
|
|
29667
29614
|
}
|
|
29668
29615
|
function snapshot2(filePath) {
|
|
29669
|
-
const before = identity4(filePath, "file");
|
|
29670
29616
|
const stat = fs27.lstatSync(filePath);
|
|
29617
|
+
if (stat.isSymbolicLink() || !stat.isFile())
|
|
29618
|
+
throw migrationError2(`${filePath} must be a real file.`);
|
|
29671
29619
|
const bytes = fs27.readFileSync(filePath);
|
|
29672
|
-
|
|
29673
|
-
if (!sameIdentity3(before, after))
|
|
29674
|
-
throw migrationError2(`${filePath} changed while it was read.`);
|
|
29675
|
-
return Object.freeze({ bytes, mode: stat.mode & 511, identity: after });
|
|
29620
|
+
return Object.freeze({ bytes, mode: stat.mode & 511 });
|
|
29676
29621
|
}
|
|
29677
29622
|
function writable2(filePath) {
|
|
29678
29623
|
try {
|
|
@@ -29683,10 +29628,9 @@ function writable2(filePath) {
|
|
|
29683
29628
|
}
|
|
29684
29629
|
}
|
|
29685
29630
|
function walkTasks2(root, tasksDir, out) {
|
|
29686
|
-
const
|
|
29687
|
-
const
|
|
29688
|
-
|
|
29689
|
-
if (!contained3(bundleIdentity.realPath, physicalRoot)) {
|
|
29631
|
+
const physicalRoot = realDirectory2(root.root);
|
|
29632
|
+
const physicalBundleRoot = realDirectory2(root.bundleRoot ?? root.root);
|
|
29633
|
+
if (!contained3(physicalBundleRoot, physicalRoot)) {
|
|
29690
29634
|
throw migrationError2(`${root.root} resolves outside bundle ${root.bundleId}.`);
|
|
29691
29635
|
}
|
|
29692
29636
|
const visit2 = (directory) => {
|
|
@@ -29712,12 +29656,7 @@ function walkTasks2(root, tasksDir, out) {
|
|
|
29712
29656
|
mode: current.mode,
|
|
29713
29657
|
writable: root.writable,
|
|
29714
29658
|
onDiskWritable: writable2(candidate) && writable2(parent) && (current.mode & 146) !== 0,
|
|
29715
|
-
containmentRoot: physicalRoot
|
|
29716
|
-
inspectionIdentity: Object.freeze({
|
|
29717
|
-
file: current.identity,
|
|
29718
|
-
root: rootIdentity,
|
|
29719
|
-
bundleRoot: bundleIdentity
|
|
29720
|
-
})
|
|
29659
|
+
containmentRoot: physicalRoot
|
|
29721
29660
|
});
|
|
29722
29661
|
}
|
|
29723
29662
|
};
|
|
@@ -29781,17 +29720,9 @@ function assertUnchanged2(change) {
|
|
|
29781
29720
|
if (!current.bytes.equals(change.before) || current.mode !== change.mode) {
|
|
29782
29721
|
throw migrationError2(`${change.filePath} changed after preview; no task files were replaced.`);
|
|
29783
29722
|
}
|
|
29784
|
-
const planned = change.inspectionIdentity?.file;
|
|
29785
|
-
if (planned && !sameIdentity3(planned, current.identity)) {
|
|
29786
|
-
throw migrationError2(`${change.filePath} identity changed after preview; no task files were replaced.`);
|
|
29787
|
-
}
|
|
29788
29723
|
return current;
|
|
29789
29724
|
}
|
|
29790
29725
|
function applyTaskToV4MigrationPlan(plan, options) {
|
|
29791
|
-
const blocked3 = plan.files.filter((file) => file.status === "blocked");
|
|
29792
|
-
if (blocked3.length > 0) {
|
|
29793
|
-
throw migrationError2(`plan is blocked: ${blocked3.map((file) => `${file.filePath} (${file.reason})`).join(", ")}. No files were written.`);
|
|
29794
|
-
}
|
|
29795
29726
|
const changes = plan.files.filter((file) => file.status === "changed");
|
|
29796
29727
|
for (const change of changes) {
|
|
29797
29728
|
assertUnchanged2(change);
|
|
@@ -29840,9 +29771,14 @@ function existingDirectory(target) {
|
|
|
29840
29771
|
throw cause;
|
|
29841
29772
|
}
|
|
29842
29773
|
}
|
|
29774
|
+
function reconcileDuplicateRoot(existing, candidate, sharedPath) {
|
|
29775
|
+
if (existing.writable === candidate.writable && existing.layout === candidate.layout)
|
|
29776
|
+
return;
|
|
29777
|
+
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 \u2014 run `akm bundle list` to see both.", "INVALID_CONFIG_FILE");
|
|
29778
|
+
}
|
|
29843
29779
|
function taskRoots(config, resolutionBase = process.cwd()) {
|
|
29844
29780
|
const sources = new Map((bundlesToSourceEntries(config) ?? []).map((source) => [source.name, source]));
|
|
29845
|
-
const
|
|
29781
|
+
const rootsByPath = new Map;
|
|
29846
29782
|
for (const [bundleId, bundle] of Object.entries(config.bundles ?? {})) {
|
|
29847
29783
|
if (bundle.enabled === false)
|
|
29848
29784
|
continue;
|
|
@@ -29870,15 +29806,21 @@ function taskRoots(config, resolutionBase = process.cwd()) {
|
|
|
29870
29806
|
}
|
|
29871
29807
|
if (adapter !== "akm" && adapter !== "akm-task")
|
|
29872
29808
|
continue;
|
|
29873
|
-
|
|
29809
|
+
const candidate = {
|
|
29874
29810
|
bundleId,
|
|
29875
29811
|
root: componentRoot,
|
|
29876
29812
|
bundleRoot,
|
|
29877
29813
|
writable: component?.writable ?? resolveWritable(source),
|
|
29878
29814
|
layout: adapter === "akm-task" ? "akm-task" : "akm-stash"
|
|
29879
|
-
}
|
|
29815
|
+
};
|
|
29816
|
+
const existing = rootsByPath.get(componentRoot);
|
|
29817
|
+
if (existing) {
|
|
29818
|
+
reconcileDuplicateRoot(existing, candidate, componentRoot);
|
|
29819
|
+
continue;
|
|
29820
|
+
}
|
|
29821
|
+
rootsByPath.set(componentRoot, candidate);
|
|
29880
29822
|
}
|
|
29881
|
-
return
|
|
29823
|
+
return [...rootsByPath.values()];
|
|
29882
29824
|
}
|
|
29883
29825
|
function summarize(plan) {
|
|
29884
29826
|
const files = plan.files.map((file) => ({
|
|
@@ -29935,12 +29877,12 @@ async function runMigrationApply(options = {}) {
|
|
|
29935
29877
|
}
|
|
29936
29878
|
const result = withConfigLock(() => withMaintenanceStartBarrier(() => {
|
|
29937
29879
|
const before = inspectCurrentTaskPlan();
|
|
29938
|
-
if (before.result.
|
|
29880
|
+
if (before.result.taskV3Migration.changed === 0)
|
|
29939
29881
|
return before.result;
|
|
29940
29882
|
const backupPath = path33.join(getDataDir(), "backups", "task-v3", `${Date.now()}-${randomUUID2()}`);
|
|
29941
29883
|
const applied = applyTaskToV3MigrationPlan(before.plan, { backupRoot: backupPath });
|
|
29942
29884
|
const after = inspectCurrentTaskPlan().result;
|
|
29943
|
-
if (after.
|
|
29885
|
+
if (after.taskV3Migration.changed > 0) {
|
|
29944
29886
|
throw new ConfigError("Task migration did not converge to task v3.", "INVALID_CONFIG_FILE");
|
|
29945
29887
|
}
|
|
29946
29888
|
return { ...after, backupPath, applied: applied.changed.length };
|
|
@@ -29998,12 +29940,12 @@ async function runTaskV4MigrationApply(options = {}) {
|
|
|
29998
29940
|
}
|
|
29999
29941
|
const result = withConfigLock(() => withMaintenanceStartBarrier(() => {
|
|
30000
29942
|
const before = inspectCurrentTaskV4Plan();
|
|
30001
|
-
if (before.result.
|
|
29943
|
+
if (before.result.taskV4Migration.changed === 0)
|
|
30002
29944
|
return before.result;
|
|
30003
29945
|
const backupPath = path33.join(getDataDir(), "backups", "task-v4", `${Date.now()}-${randomUUID2()}`);
|
|
30004
29946
|
const applied = applyTaskToV4MigrationPlan(before.plan, { backupRoot: backupPath });
|
|
30005
29947
|
const after = inspectCurrentTaskV4Plan().result;
|
|
30006
|
-
if (after.
|
|
29948
|
+
if (after.taskV4Migration.changed > 0) {
|
|
30007
29949
|
throw new ConfigError("Task migration did not converge to task source v4.", "INVALID_CONFIG_FILE");
|
|
30008
29950
|
}
|
|
30009
29951
|
return { ...after, backupPath, applied: applied.changed.length };
|