akm-cli 0.9.5 → 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 +105 -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/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/sources/bundle-config-ops.js +9 -4
- package/dist/commands/sources/info.js +14 -10
- package/dist/commands/tasks/tasks.js +12 -16
- package/dist/commands/workflow-cli.js +2 -2
- 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.js +1 -1
- 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/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/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/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/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/registry/network.js +5 -37
- package/dist/runtime.js +2 -10
- package/dist/scripts/akm-migrate-node.js +60 -126
- package/dist/scripts/akm-migrate.js +60 -126
- 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/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/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 +5 -10
- package/dist/tasks/source/task-to-v4.js +1 -4
- 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/configuration.md +1 -1
- 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
package/dist/workflows/parser.js
CHANGED
|
@@ -38,7 +38,7 @@ import { formatExtraParamsIssue, validateExtraParams } from "../core/extra-param
|
|
|
38
38
|
import { checkJsonSchemaDefinition, JSON_SCHEMA_SUBSET_SUPPORTED_KEYWORDS } from "../core/json-schema.js";
|
|
39
39
|
import { parseReference } from "./program/expressions.js";
|
|
40
40
|
import { PROGRAM_ISOLATION_KINDS, PROGRAM_ON_ERROR, PROGRAM_PARAM_NAME_PATTERN, PROGRAM_REDUCERS, PROGRAM_RETRY_REASONS, PROGRAM_STEP_ID_PATTERN, } from "./program/schema.js";
|
|
41
|
-
import { jsonBytes, utf8Bytes, WORKFLOW_ENGINE_NAME_PATTERN, WORKFLOW_ENV_VAR_NAME_PATTERN, WORKFLOW_MAX_CONCURRENCY, WORKFLOW_MAX_ENGINE_NAME_LENGTH,
|
|
41
|
+
import { jsonBytes, utf8Bytes, WORKFLOW_ENGINE_NAME_PATTERN, WORKFLOW_ENV_VAR_NAME_PATTERN, WORKFLOW_MAX_CONCURRENCY, WORKFLOW_MAX_ENGINE_NAME_LENGTH, WORKFLOW_MAX_EXTRA_PARAMS_BYTES, WORKFLOW_MAX_SCHEMA_BYTES, WORKFLOW_MAX_SOURCE_BYTES, WORKFLOW_MAX_TIMEOUT_MS, } from "./resource-limits.js";
|
|
42
42
|
import { WORKFLOW_SCHEMA_VERSION, } from "./schema.js";
|
|
43
43
|
import { runSemanticChecks } from "./validator.js";
|
|
44
44
|
/** Envelope keys every AKM markdown asset carries ($ref'd from schemas/akm-asset-envelope.json). */
|
|
@@ -406,9 +406,6 @@ function parseParams(ctx, raw) {
|
|
|
406
406
|
ctx.err(["params"], `"params" must be a mapping of param name to a JSON Schema object (e.g. changed_files: { type: array }).`);
|
|
407
407
|
return undefined;
|
|
408
408
|
}
|
|
409
|
-
if (Object.keys(raw).length > WORKFLOW_MAX_PARAMS) {
|
|
410
|
-
ctx.err(["params"], `"params" must contain at most ${WORKFLOW_MAX_PARAMS} entries.`);
|
|
411
|
-
}
|
|
412
409
|
const params = {};
|
|
413
410
|
for (const [paramName, value] of Object.entries(raw)) {
|
|
414
411
|
if (!PROGRAM_PARAM_NAME_PATTERN.test(paramName)) {
|
|
@@ -448,9 +445,6 @@ function parseOutputs(ctx, raw) {
|
|
|
448
445
|
ctx.err(["outputs"], `"outputs" must be a mapping of output name to { from, schema? } (e.g. report: { from: steps.summarize.output }).`);
|
|
449
446
|
return undefined;
|
|
450
447
|
}
|
|
451
|
-
if (Object.keys(raw).length > WORKFLOW_MAX_OUTPUTS) {
|
|
452
|
-
ctx.err(["outputs"], `"outputs" must contain at most ${WORKFLOW_MAX_OUTPUTS} entries.`);
|
|
453
|
-
}
|
|
454
448
|
const outputs = {};
|
|
455
449
|
for (const [outputName, value] of Object.entries(raw)) {
|
|
456
450
|
const path = ["outputs", outputName];
|
|
@@ -546,14 +540,11 @@ function parseBudget(ctx, raw) {
|
|
|
546
540
|
}
|
|
547
541
|
}
|
|
548
542
|
if (raw.max_units !== undefined) {
|
|
549
|
-
if (typeof raw.max_units === "number" &&
|
|
550
|
-
Number.isInteger(raw.max_units) &&
|
|
551
|
-
raw.max_units >= 1 &&
|
|
552
|
-
raw.max_units <= WORKFLOW_MAX_MAP_EXPANSION) {
|
|
543
|
+
if (typeof raw.max_units === "number" && Number.isInteger(raw.max_units) && raw.max_units >= 1) {
|
|
553
544
|
budget.maxUnits = raw.max_units;
|
|
554
545
|
}
|
|
555
546
|
else {
|
|
556
|
-
ctx.err([...path, "max_units"], `"budget.max_units" must be an integer
|
|
547
|
+
ctx.err([...path, "max_units"], `"budget.max_units" must be an integer >= 1.`);
|
|
557
548
|
}
|
|
558
549
|
}
|
|
559
550
|
return Object.keys(budget).length > 0 ? budget : undefined;
|
|
@@ -563,9 +554,6 @@ function parseSteps(ctx, raw) {
|
|
|
563
554
|
ctx.err(["steps"], `"steps" is required and must be a list with at least one step.`);
|
|
564
555
|
return [];
|
|
565
556
|
}
|
|
566
|
-
if (raw.length > WORKFLOW_MAX_STEPS) {
|
|
567
|
-
ctx.err(["steps"], `"steps" must contain at most ${WORKFLOW_MAX_STEPS} entries.`);
|
|
568
|
-
}
|
|
569
557
|
// First pass: collect ids so route targets can be checked against ALL steps
|
|
570
558
|
// (including ones that fail their own validation).
|
|
571
559
|
const idIndex = new Map();
|
|
@@ -775,11 +763,6 @@ function parseExecPassEnv(ctx, raw, path, stepLabel) {
|
|
|
775
763
|
`akm's own environment, e.g. pass_env: [CARGO_HOME]. Values never appear here — use "env:" bindings for those.`);
|
|
776
764
|
return undefined;
|
|
777
765
|
}
|
|
778
|
-
if (raw.length > WORKFLOW_MAX_EXEC_PASS_ENV) {
|
|
779
|
-
ctx.err(path, `${stepLabel} "exec.pass_env" must have at most ${WORKFLOW_MAX_EXEC_PASS_ENV} entries. A command needing ` +
|
|
780
|
-
`more than that should use explicit named "env:" bindings instead.`);
|
|
781
|
-
return undefined;
|
|
782
|
-
}
|
|
783
766
|
const names = [];
|
|
784
767
|
for (const [index, entry] of raw.entries()) {
|
|
785
768
|
if (typeof entry !== "string" || !WORKFLOW_ENV_VAR_NAME_PATTERN.test(entry)) {
|
|
@@ -795,17 +778,13 @@ function parseExecPassEnv(ctx, raw, path, stepLabel) {
|
|
|
795
778
|
}
|
|
796
779
|
return names;
|
|
797
780
|
}
|
|
798
|
-
/** The argv array itself:
|
|
781
|
+
/** The argv array itself: a non-empty list of non-empty strings. */
|
|
799
782
|
function parseExecCommand(ctx, raw, path, stepLabel) {
|
|
800
783
|
if (!Array.isArray(raw) || raw.length === 0) {
|
|
801
784
|
ctx.err(path, `${stepLabel} "exec" requires "command": a non-empty argv list, e.g. command: ["bun", "run", "test:unit"]. ` +
|
|
802
785
|
`A single shell string is not accepted — the command is spawned directly, never through a shell.`);
|
|
803
786
|
return undefined;
|
|
804
787
|
}
|
|
805
|
-
if (raw.length > WORKFLOW_MAX_EXEC_ARGV) {
|
|
806
|
-
ctx.err(path, `${stepLabel} "exec.command" must have at most ${WORKFLOW_MAX_EXEC_ARGV} entries.`);
|
|
807
|
-
return undefined;
|
|
808
|
-
}
|
|
809
788
|
const argv = [];
|
|
810
789
|
for (const [index, entry] of raw.entries()) {
|
|
811
790
|
if (typeof entry !== "string" || entry === "") {
|
|
@@ -816,10 +795,6 @@ function parseExecCommand(ctx, raw, path, stepLabel) {
|
|
|
816
795
|
ctx.err([...path, index], `${stepLabel} "exec.command[${index}]" may not contain NUL bytes.`);
|
|
817
796
|
return undefined;
|
|
818
797
|
}
|
|
819
|
-
if (utf8Bytes(entry) > WORKFLOW_MAX_EXEC_ARG_BYTES) {
|
|
820
|
-
ctx.err(path, `${stepLabel} "exec.command[${index}]" exceeds ${WORKFLOW_MAX_EXEC_ARG_BYTES} bytes.`);
|
|
821
|
-
return undefined;
|
|
822
|
-
}
|
|
823
798
|
argv.push(entry);
|
|
824
799
|
}
|
|
825
800
|
return argv;
|
|
@@ -837,10 +812,6 @@ function parseExecCwd(ctx, raw, path, stepLabel) {
|
|
|
837
812
|
return undefined;
|
|
838
813
|
}
|
|
839
814
|
const value = raw.trim();
|
|
840
|
-
if (value.length > WORKFLOW_MAX_EXEC_CWD_LENGTH) {
|
|
841
|
-
ctx.err(path, `${stepLabel} "exec.cwd" exceeds ${WORKFLOW_MAX_EXEC_CWD_LENGTH} characters.`);
|
|
842
|
-
return undefined;
|
|
843
|
-
}
|
|
844
815
|
if (!isContainedRelativePath(value)) {
|
|
845
816
|
ctx.err(path, `${stepLabel} "exec.cwd" (${JSON.stringify(value)}) must be a RELATIVE path inside the unit's working ` +
|
|
846
817
|
`directory — absolute paths, Windows drive letters, "~", and ".." segments are rejected.`);
|
|
@@ -876,14 +847,11 @@ function parseMap(ctx, raw, path, stepLabel) {
|
|
|
876
847
|
}
|
|
877
848
|
let concurrency;
|
|
878
849
|
if (raw.concurrency !== undefined) {
|
|
879
|
-
if (typeof raw.concurrency === "number" &&
|
|
880
|
-
|
|
881
|
-
raw.concurrency > 0 &&
|
|
882
|
-
raw.concurrency <= WORKFLOW_MAX_CONCURRENCY) {
|
|
883
|
-
concurrency = raw.concurrency;
|
|
850
|
+
if (typeof raw.concurrency === "number" && Number.isInteger(raw.concurrency) && raw.concurrency > 0) {
|
|
851
|
+
concurrency = Math.min(raw.concurrency, WORKFLOW_MAX_CONCURRENCY);
|
|
884
852
|
}
|
|
885
853
|
else {
|
|
886
|
-
ctx.err([...path, "concurrency"], `${stepLabel} "concurrency" must be
|
|
854
|
+
ctx.err([...path, "concurrency"], `${stepLabel} "concurrency" must be a positive integer.`);
|
|
887
855
|
}
|
|
888
856
|
}
|
|
889
857
|
const reducer = parseEnumField(ctx, raw.reducer, [...path, "reducer"], `${stepLabel} "reducer"`, PROGRAM_REDUCERS);
|
|
@@ -917,9 +885,6 @@ function parseRoute(ctx, raw, path, stepLabel, stepIndex, routeChecks) {
|
|
|
917
885
|
ctx.err(whenPath, `${stepLabel} "route" requires "when": a non-empty list of { match, step } branches (e.g. when: [{ match: pass, step: ship }]).`);
|
|
918
886
|
}
|
|
919
887
|
else {
|
|
920
|
-
if (raw.when.length > WORKFLOW_MAX_ROUTE_BRANCHES) {
|
|
921
|
-
ctx.err(whenPath, `${stepLabel} "when" must contain at most ${WORKFLOW_MAX_ROUTE_BRANCHES} branches.`);
|
|
922
|
-
}
|
|
923
888
|
const seenMatches = new Map();
|
|
924
889
|
raw.when.forEach((branch, i) => {
|
|
925
890
|
const branchPath = [...whenPath, i];
|
|
@@ -980,9 +945,6 @@ function parseInputs(ctx, raw, path, stepLabel) {
|
|
|
980
945
|
ctx.err(path, `${stepLabel} "inputs" must be a non-empty list of reference strings.`);
|
|
981
946
|
return undefined;
|
|
982
947
|
}
|
|
983
|
-
if (raw.length > WORKFLOW_MAX_INPUTS) {
|
|
984
|
-
ctx.err(path, `${stepLabel} "inputs" must contain at most ${WORKFLOW_MAX_INPUTS} entries.`);
|
|
985
|
-
}
|
|
986
948
|
const out = [];
|
|
987
949
|
// The frozen-plan decoder requires uniqueness (validateStringArray(..., true)),
|
|
988
950
|
// so duplicates parsed and linted clean and then failed the run with an
|
|
@@ -1012,14 +974,11 @@ function parseGate(ctx, raw, path, stepLabel) {
|
|
|
1012
974
|
checkUnknownKeys(ctx, raw, path, GATE_KEYS, `${stepLabel} "gate"`);
|
|
1013
975
|
const gate = {};
|
|
1014
976
|
if (raw.max_loops !== undefined) {
|
|
1015
|
-
if (typeof raw.max_loops === "number" &&
|
|
1016
|
-
Number.isInteger(raw.max_loops) &&
|
|
1017
|
-
raw.max_loops >= 1 &&
|
|
1018
|
-
raw.max_loops <= WORKFLOW_MAX_GATE_LOOPS) {
|
|
977
|
+
if (typeof raw.max_loops === "number" && Number.isInteger(raw.max_loops) && raw.max_loops >= 1) {
|
|
1019
978
|
gate.maxLoops = raw.max_loops;
|
|
1020
979
|
}
|
|
1021
980
|
else {
|
|
1022
|
-
ctx.err([...path, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer
|
|
981
|
+
ctx.err([...path, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer of at least 1.`);
|
|
1023
982
|
}
|
|
1024
983
|
}
|
|
1025
984
|
return gate;
|
|
@@ -1056,8 +1015,8 @@ function parseRetry(ctx, raw, path, stepLabel) {
|
|
|
1056
1015
|
}
|
|
1057
1016
|
checkUnknownKeys(ctx, raw, path, RETRY_KEYS, `${stepLabel} "retry"`);
|
|
1058
1017
|
let ok = true;
|
|
1059
|
-
if (!(typeof raw.max === "number" && Number.isInteger(raw.max) && raw.max >= 0
|
|
1060
|
-
ctx.err([...path, "max"], `${stepLabel} "retry.max" is required and must be
|
|
1018
|
+
if (!(typeof raw.max === "number" && Number.isInteger(raw.max) && raw.max >= 0)) {
|
|
1019
|
+
ctx.err([...path, "max"], `${stepLabel} "retry.max" is required and must be a non-negative integer.`);
|
|
1061
1020
|
ok = false;
|
|
1062
1021
|
}
|
|
1063
1022
|
const on = [];
|
|
@@ -87,9 +87,8 @@ function projectParameters(sourceIr) {
|
|
|
87
87
|
* visible in the workflow file `show` is rendering, and (b) pointless to clip:
|
|
88
88
|
* the whole finding this projection answers is `show` describing something
|
|
89
89
|
* other than what runs, and a truncated argv is that same bug in miniature.
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* `instructions` this same projection already carries whole.
|
|
90
|
+
* It is far smaller than the step `instructions` this same projection
|
|
91
|
+
* already carries whole.
|
|
93
92
|
*/
|
|
94
93
|
function summarizeStepOrchestration(step, defaults) {
|
|
95
94
|
const unit = step.unit;
|
|
@@ -4,22 +4,12 @@
|
|
|
4
4
|
import { EXECUTION_MAX_TIMEOUT_MS } from "../execution/limits.js";
|
|
5
5
|
export const WORKFLOW_MAX_PLAN_BYTES = 2 * 1024 * 1024;
|
|
6
6
|
export const WORKFLOW_MAX_SOURCE_BYTES = 1024 * 1024;
|
|
7
|
-
export const WORKFLOW_MAX_STEPS = 256;
|
|
8
|
-
export const WORKFLOW_MAX_ENGINES = 64;
|
|
9
|
-
export const WORKFLOW_MAX_PARAMS = 128;
|
|
10
|
-
export const WORKFLOW_MAX_ROUTE_BRANCHES = 256;
|
|
11
7
|
export const WORKFLOW_MAX_INSTRUCTION_BYTES = 256 * 1024;
|
|
12
8
|
export const WORKFLOW_MAX_SCHEMA_BYTES = 256 * 1024;
|
|
13
9
|
export const WORKFLOW_MAX_EXTRA_PARAMS_BYTES = 64 * 1024;
|
|
14
|
-
export const WORKFLOW_MAX_JSON_DEPTH = 64;
|
|
15
|
-
export const WORKFLOW_MAX_MAP_EXPANSION = 10_000;
|
|
16
|
-
/** Max declared `inputs:` reference strings on one unit/map step. */
|
|
17
|
-
export const WORKFLOW_MAX_INPUTS = 64;
|
|
18
|
-
/** Max declared `outputs:` entries on one workflow document (P3b, spec §4.1). */
|
|
19
|
-
export const WORKFLOW_MAX_OUTPUTS = 64;
|
|
20
10
|
// ── Dispatch-significant bounds shared across validation layers ──────────────
|
|
21
11
|
//
|
|
22
|
-
// Defined ONCE here so the
|
|
12
|
+
// Defined ONCE here so the enforcement layers cannot drift:
|
|
23
13
|
// 1. the parser (`../parser.ts`) — line-anchored authoring-time errors,
|
|
24
14
|
// 2. the published JSON Schema (`schemas/akm-workflow.json`) — mirrored
|
|
25
15
|
// `maximum`/`pattern`/`maxLength` values, pinned against these constants
|
|
@@ -31,33 +21,12 @@ export const WORKFLOW_MAX_OUTPUTS = 64;
|
|
|
31
21
|
// `workflow create` already said the document was fine.
|
|
32
22
|
/** Max per-step map fan-out concurrency (also the run-level concurrency ceiling). */
|
|
33
23
|
export const WORKFLOW_MAX_CONCURRENCY = 64;
|
|
34
|
-
/** Max evaluator-optimizer gate loops per step. */
|
|
35
|
-
export const WORKFLOW_MAX_GATE_LOOPS = 100;
|
|
36
|
-
/** Max retry attempts per unit. */
|
|
37
|
-
export const WORKFLOW_MAX_RETRIES = 100;
|
|
38
24
|
/** Max timeout in milliseconds (setTimeout's 32-bit signed ceiling: 2^31-1, ~24.8 days). */
|
|
39
25
|
export const WORKFLOW_MAX_TIMEOUT_MS = EXECUTION_MAX_TIMEOUT_MS;
|
|
40
26
|
/** Engine names: lowercase dash-separated runs of letters/digits, starting with a letter. */
|
|
41
27
|
export const WORKFLOW_ENGINE_NAME_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
42
28
|
export const WORKFLOW_MAX_ENGINE_NAME_LENGTH = 63;
|
|
43
29
|
// ── exec (shell) unit bounds ─────────────────────────────────────────────────
|
|
44
|
-
/**
|
|
45
|
-
* Max entries in an exec unit's `command:` argv array. Generous for a real
|
|
46
|
-
* command line, small enough that a corrupted plan cannot ask the OS to spawn
|
|
47
|
-
* a megabyte of arguments.
|
|
48
|
-
*/
|
|
49
|
-
export const WORKFLOW_MAX_EXEC_ARGV = 64;
|
|
50
|
-
/** Max UTF-8 bytes of ONE argv entry (well under every platform's ARG_MAX per-arg limit). */
|
|
51
|
-
export const WORKFLOW_MAX_EXEC_ARG_BYTES = 4096;
|
|
52
|
-
/** Max characters of an exec unit's relative `cwd:`. */
|
|
53
|
-
export const WORKFLOW_MAX_EXEC_CWD_LENGTH = 1024;
|
|
54
|
-
/**
|
|
55
|
-
* Max entries in an exec unit's `pass_env:` list.
|
|
56
|
-
*
|
|
57
|
-
* `pass_env` is bounded; use explicit named `env:` bindings for a larger set.
|
|
58
|
-
* New v4 starts do not offer whole-process inheritance.
|
|
59
|
-
*/
|
|
60
|
-
export const WORKFLOW_MAX_EXEC_PASS_ENV = 32;
|
|
61
30
|
/**
|
|
62
31
|
* Grammar for an env var NAME in `pass_env:`. Matches the frozen-plan
|
|
63
32
|
* `envPassthrough` grammar in `ir/schema.ts` so both allowlist surfaces accept
|
|
@@ -86,8 +55,7 @@ export const DEFAULT_EXEC_TIMEOUT_MS = 600_000;
|
|
|
86
55
|
* ten minutes to do so. What the cap buys is a BOUND where there was none: the
|
|
87
56
|
* retained prefix is promoted into the unit's outcome text and every outcome is
|
|
88
57
|
* held until the step reduces, so the worst case is (units in the STEP × this
|
|
89
|
-
* cap)
|
|
90
|
-
* what sizes it, up to {@link WORKFLOW_MAX_MAP_EXPANSION}.
|
|
58
|
+
* cap) — the step's width, not the in-flight width, is what sizes it.
|
|
91
59
|
*
|
|
92
60
|
* On reaching the cap the reader switches to DRAIN-AND-DISCARD: it keeps
|
|
93
61
|
* pulling from the pipe (so the child never blocks on backpressure) and stops
|
|
@@ -180,11 +148,10 @@ export function clip(text, max) {
|
|
|
180
148
|
*
|
|
181
149
|
* The promoted step artifact (`evidence.output`) is deliberately NOT clipped
|
|
182
150
|
* when it is built — gates judge the full artifact and downstream
|
|
183
|
-
* `steps.<id>.output` references need it intact — but a `collect`
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* bounded here, at the write boundary, by
|
|
151
|
+
* `steps.<id>.output` references need it intact — but a `collect` reducer
|
|
152
|
+
* over an unbounded fan-out (each unit contributing up to a full unit
|
|
153
|
+
* result) would otherwise write an unbounded blob into a single SQLite row.
|
|
154
|
+
* Persistence is therefore bounded here, at the write boundary, by
|
|
188
155
|
* `clipStepEvidenceForPersistence` (`runtime/runs.ts`), which replaces
|
|
189
156
|
* oversized values with an explicitly-marked truncation envelope rather than
|
|
190
157
|
* silently shortening them.
|
|
@@ -213,8 +180,11 @@ export function jsonBytes(value) {
|
|
|
213
180
|
// (`src/workflows/ir/schema-v4.ts`'s recursive `decodeChildWorkflowTarget`).
|
|
214
181
|
// Full design history, including the rejected alternative for the byte cap:
|
|
215
182
|
// docs/architecture/decisions/0007-workflow-composition-bounds.md.
|
|
216
|
-
|
|
217
|
-
|
|
183
|
+
//
|
|
184
|
+
// Composition DEPTH is unbounded — `assertNoCompositionCycle` (freeze/targets/
|
|
185
|
+
// child-workflow.ts) already makes infinite composition mathematically
|
|
186
|
+
// impossible, so a depth ceiling on top of it only bounded how many
|
|
187
|
+
// legitimately distinct workflows an author could nest.
|
|
218
188
|
/**
|
|
219
189
|
* Max AGGREGATE canonical-JSON bytes of every embedded child plan in ONE root
|
|
220
190
|
* freeze (the sum across the whole composition tree, not per child).
|
|
@@ -396,10 +396,9 @@ export function isTruncatedEvidence(value) {
|
|
|
396
396
|
* `buildEvidence` (exec/step-work.ts) promotes `evidence.output` UNCLIPPED by
|
|
397
397
|
* design: gates judge the full promoted artifact and the in-memory
|
|
398
398
|
* {@link StepExecutionResult} carries it to the caller intact. Nothing bounded
|
|
399
|
-
* the PERSISTED form, though — a `collect` reducer over
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
* the shared step-semantics module.
|
|
399
|
+
* the PERSISTED form, though — a `collect` reducer over an unbounded fan-out
|
|
400
|
+
* can serialize to hundreds of megabytes. This is the write boundary, so the
|
|
401
|
+
* bound lives here rather than in the shared step-semantics module.
|
|
403
402
|
*
|
|
404
403
|
* Over-cap values are REPLACED (largest top-level entry BY UTF-8 BYTES first —
|
|
405
404
|
* the unit the cap is measured in — until the row fits) with a
|
|
@@ -14,7 +14,7 @@ import { validateExtraParams } from "../../core/extra-params.js";
|
|
|
14
14
|
import { checkJsonSchemaDefinition } from "../../core/json-schema.js";
|
|
15
15
|
import { parseReference } from "../program/expressions.js";
|
|
16
16
|
import { PROGRAM_RETRY_REASONS } from "../program/schema.js";
|
|
17
|
-
import { jsonBytes,
|
|
17
|
+
import { jsonBytes, WORKFLOW_ENGINE_NAME_PATTERN, WORKFLOW_ENV_VAR_NAME_PATTERN, WORKFLOW_MAX_CONCURRENCY, WORKFLOW_MAX_ENGINE_NAME_LENGTH, WORKFLOW_MAX_EXTRA_PARAMS_BYTES, WORKFLOW_MAX_SCHEMA_BYTES, WORKFLOW_MAX_TIMEOUT_MS, } from "../resource-limits.js";
|
|
18
18
|
import { compareWorkflowSourceCodePoints } from "./compare.js";
|
|
19
19
|
import { canonicalizeWorkflowCron, canonicalizeWorkflowRun, canonicalizeWorkflowWorkingDirectory, classifyWorkflowStepUses, rejectNulInArgv, validateWorkflowBuiltinCommand, WorkflowSourceSemanticError, } from "./semantics.js";
|
|
20
20
|
export const WORKFLOW_SOURCE_IR_VERSION = 1;
|
|
@@ -255,7 +255,7 @@ function validateStep(value, jobId, index, stepIds, options) {
|
|
|
255
255
|
}
|
|
256
256
|
validateMap(step.map, `step ${id} map`);
|
|
257
257
|
validateRoute(step.route, `step ${id} route`);
|
|
258
|
-
optionalStringList(step.inputs, `step ${id} inputs`,
|
|
258
|
+
optionalStringList(step.inputs, `step ${id} inputs`, Infinity);
|
|
259
259
|
if (Array.isArray(step.inputs)) {
|
|
260
260
|
for (const [inputIndex, input] of step.inputs.entries())
|
|
261
261
|
validateReference(input, `step ${id} inputs[${inputIndex}]`);
|
|
@@ -277,12 +277,7 @@ function validateExec(value, location, options) {
|
|
|
277
277
|
return;
|
|
278
278
|
const exec = record(value, location);
|
|
279
279
|
keys(exec, ["command", "cwd", "passEnv"], location);
|
|
280
|
-
stringList(exec.command, `${location}.command`,
|
|
281
|
-
for (const [index, argument] of exec.command.entries()) {
|
|
282
|
-
if (utf8Bytes(argument) > WORKFLOW_MAX_EXEC_ARG_BYTES) {
|
|
283
|
-
fail(`${location}.command[${index}] exceeds ${WORKFLOW_MAX_EXEC_ARG_BYTES} bytes`);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
280
|
+
stringList(exec.command, `${location}.command`, Infinity, false);
|
|
286
281
|
try {
|
|
287
282
|
rejectNulInArgv(exec.command);
|
|
288
283
|
}
|
|
@@ -291,9 +286,6 @@ function validateExec(value, location, options) {
|
|
|
291
286
|
}
|
|
292
287
|
optionalString(exec.cwd, `${location}.cwd`);
|
|
293
288
|
if (exec.cwd !== undefined) {
|
|
294
|
-
if (exec.cwd.length > WORKFLOW_MAX_EXEC_CWD_LENGTH) {
|
|
295
|
-
fail(`${location}.cwd exceeds ${WORKFLOW_MAX_EXEC_CWD_LENGTH} characters`);
|
|
296
|
-
}
|
|
297
289
|
try {
|
|
298
290
|
exec.cwd = canonicalizeWorkflowWorkingDirectory(exec.cwd, options.workspaceRoot);
|
|
299
291
|
}
|
|
@@ -302,7 +294,7 @@ function validateExec(value, location, options) {
|
|
|
302
294
|
}
|
|
303
295
|
}
|
|
304
296
|
if (exec.passEnv !== undefined) {
|
|
305
|
-
stringList(exec.passEnv, `${location}.passEnv`,
|
|
297
|
+
stringList(exec.passEnv, `${location}.passEnv`, Infinity, false);
|
|
306
298
|
}
|
|
307
299
|
if (Array.isArray(exec.passEnv)) {
|
|
308
300
|
for (const name of exec.passEnv) {
|
|
@@ -359,8 +351,8 @@ function validateRetry(value, location) {
|
|
|
359
351
|
return;
|
|
360
352
|
const retry = record(value, location);
|
|
361
353
|
keys(retry, ["max", "on"], location);
|
|
362
|
-
if (!Number.isSafeInteger(retry.max) || retry.max < 0
|
|
363
|
-
fail(`${location}.max must be
|
|
354
|
+
if (!Number.isSafeInteger(retry.max) || retry.max < 0) {
|
|
355
|
+
fail(`${location}.max must be a non-negative integer`);
|
|
364
356
|
}
|
|
365
357
|
stringList(retry.on, `${location}.on`, PROGRAM_RETRY_REASONS.length, false);
|
|
366
358
|
for (const reason of retry.on) {
|
|
@@ -393,10 +385,8 @@ function validateRoute(value, location) {
|
|
|
393
385
|
keys(route, ["input", "branches", "defaultStepId"], location);
|
|
394
386
|
nonEmptyString(route.input, `${location}.input`);
|
|
395
387
|
validateReference(route.input, `${location}.input`);
|
|
396
|
-
if (!Array.isArray(route.branches) ||
|
|
397
|
-
|
|
398
|
-
route.branches.length > WORKFLOW_MAX_ROUTE_BRANCHES) {
|
|
399
|
-
fail(`${location}.branches must contain 1 through ${WORKFLOW_MAX_ROUTE_BRANCHES} entries`);
|
|
388
|
+
if (!Array.isArray(route.branches) || route.branches.length === 0) {
|
|
389
|
+
fail(`${location}.branches must be a non-empty array`);
|
|
400
390
|
}
|
|
401
391
|
const matches = new Set();
|
|
402
392
|
for (const [index, value] of route.branches.entries()) {
|
|
@@ -416,11 +406,8 @@ function validateGate(value, location) {
|
|
|
416
406
|
return;
|
|
417
407
|
const gate = record(value, location);
|
|
418
408
|
keys(gate, ["maxLoops", "rubric"], location);
|
|
419
|
-
if (gate.maxLoops !== undefined &&
|
|
420
|
-
(
|
|
421
|
-
gate.maxLoops < 1 ||
|
|
422
|
-
gate.maxLoops > WORKFLOW_MAX_GATE_LOOPS)) {
|
|
423
|
-
fail(`${location}.maxLoops must be an integer from 1 through ${WORKFLOW_MAX_GATE_LOOPS}`);
|
|
409
|
+
if (gate.maxLoops !== undefined && (!Number.isSafeInteger(gate.maxLoops) || gate.maxLoops < 1)) {
|
|
410
|
+
fail(`${location}.maxLoops must be an integer of at least 1`);
|
|
424
411
|
}
|
|
425
412
|
optionalString(gate.rubric, `${location}.rubric`);
|
|
426
413
|
}
|
|
@@ -453,8 +440,8 @@ function validateParams(value) {
|
|
|
453
440
|
if (value === undefined)
|
|
454
441
|
return;
|
|
455
442
|
const params = record(value, "params");
|
|
456
|
-
if (Object.keys(params).length === 0
|
|
457
|
-
fail(`params must contain
|
|
443
|
+
if (Object.keys(params).length === 0) {
|
|
444
|
+
fail(`params must contain at least one entry`);
|
|
458
445
|
}
|
|
459
446
|
for (const [name, schema] of Object.entries(params)) {
|
|
460
447
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
@@ -472,8 +459,8 @@ function validateOutputs(value) {
|
|
|
472
459
|
if (value === undefined)
|
|
473
460
|
return;
|
|
474
461
|
const outputs = record(value, "outputs");
|
|
475
|
-
if (Object.keys(outputs).length === 0
|
|
476
|
-
fail(`outputs must contain
|
|
462
|
+
if (Object.keys(outputs).length === 0) {
|
|
463
|
+
fail(`outputs must contain at least one entry`);
|
|
477
464
|
}
|
|
478
465
|
for (const [name, declaration] of Object.entries(outputs)) {
|
|
479
466
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
@@ -496,9 +483,6 @@ function validateBudget(value) {
|
|
|
496
483
|
fail(`budget.${key} must be a positive integer`);
|
|
497
484
|
}
|
|
498
485
|
}
|
|
499
|
-
if (typeof budget.maxUnits === "number" && budget.maxUnits > WORKFLOW_MAX_MAP_EXPANSION) {
|
|
500
|
-
fail(`budget.maxUnits must be at most ${WORKFLOW_MAX_MAP_EXPANSION}`);
|
|
501
|
-
}
|
|
502
486
|
}
|
|
503
487
|
function validateLlm(value, location) {
|
|
504
488
|
if (value === undefined)
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* resource limits).
|
|
17
17
|
*/
|
|
18
18
|
import { bundleRefToString, parseBundleRef } from "../core/asset/asset-ref.js";
|
|
19
|
-
import { utf8Bytes, WORKFLOW_MAX_INSTRUCTION_BYTES
|
|
19
|
+
import { utf8Bytes, WORKFLOW_MAX_INSTRUCTION_BYTES } from "./resource-limits.js";
|
|
20
20
|
export function runSemanticChecks(draft, frontmatterData, frontmatterEndLine, errors) {
|
|
21
21
|
checkXrefs(frontmatterData.xrefs, frontmatterEndLine, errors);
|
|
22
22
|
checkResourceLimits(draft, errors);
|
|
@@ -43,12 +43,6 @@ function checkXrefs(value, line, errors) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
function checkResourceLimits(draft, errors) {
|
|
46
|
-
if (draft.steps.length > WORKFLOW_MAX_STEPS) {
|
|
47
|
-
errors.push({ line: 1, message: `Workflow must contain at most ${WORKFLOW_MAX_STEPS} steps.` });
|
|
48
|
-
}
|
|
49
|
-
if (Object.keys(draft.params ?? {}).length > WORKFLOW_MAX_PARAMS) {
|
|
50
|
-
errors.push({ line: 1, message: `Workflow must contain at most ${WORKFLOW_MAX_PARAMS} parameters.` });
|
|
51
|
-
}
|
|
52
46
|
for (const step of draft.steps) {
|
|
53
47
|
if (step.instructions && utf8Bytes(step.instructions.text) > WORKFLOW_MAX_INSTRUCTION_BYTES) {
|
|
54
48
|
errors.push({
|
|
@@ -366,7 +366,7 @@ reference, same rules as engine `apiKey`), `dimension`, `localModel`,
|
|
|
366
366
|
|
|
367
367
|
| Key | Purpose |
|
|
368
368
|
| --- | --- |
|
|
369
|
-
| `search.graphBoost.*` | Entity-graph relevance boost: `directBoostPerEntity`/`directBoostCap` (directly related entities), `hopBoostPerEntity`/`hopBoostCap` (multi-hop, capped at `maxHops` ≤ 3), `confidenceMode` (`
|
|
369
|
+
| `search.graphBoost.*` | Entity-graph relevance boost: `directBoostPerEntity`/`directBoostCap` (directly related entities), `hopBoostPerEntity`/`hopBoostCap` (multi-hop, capped at `maxHops` ≤ 3), `confidenceMode` (`blend`, the only supported value), `confidenceWeight` (0–1, default `0.2`) |
|
|
370
370
|
|
|
371
371
|
## Feedback
|
|
372
372
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cursor.",
|
|
6
6
|
"keywords": [
|
package/schemas/akm-config.json
CHANGED
|
@@ -57,9 +57,6 @@
|
|
|
57
57
|
"type": "integer",
|
|
58
58
|
"exclusiveMinimum": 0
|
|
59
59
|
},
|
|
60
|
-
"supportsJsonSchema": {
|
|
61
|
-
"type": "boolean"
|
|
62
|
-
},
|
|
63
60
|
"extraParams": {
|
|
64
61
|
"type": "object",
|
|
65
62
|
"additionalProperties": {}
|
|
@@ -572,9 +569,7 @@
|
|
|
572
569
|
"confidenceMode": {
|
|
573
570
|
"type": "string",
|
|
574
571
|
"enum": [
|
|
575
|
-
"
|
|
576
|
-
"blend",
|
|
577
|
-
"multiply"
|
|
572
|
+
"blend"
|
|
578
573
|
],
|
|
579
574
|
"default": "blend"
|
|
580
575
|
},
|
|
@@ -1747,9 +1742,6 @@
|
|
|
1747
1742
|
"type": "integer",
|
|
1748
1743
|
"exclusiveMinimum": 0
|
|
1749
1744
|
},
|
|
1750
|
-
"supportsJsonSchema": {
|
|
1751
|
-
"type": "boolean"
|
|
1752
|
-
},
|
|
1753
1745
|
"extraParams": {
|
|
1754
1746
|
"type": "object",
|
|
1755
1747
|
"additionalProperties": {}
|
|
@@ -2262,9 +2254,7 @@
|
|
|
2262
2254
|
"confidenceMode": {
|
|
2263
2255
|
"type": "string",
|
|
2264
2256
|
"enum": [
|
|
2265
|
-
"
|
|
2266
|
-
"blend",
|
|
2267
|
-
"multiply"
|
|
2257
|
+
"blend"
|
|
2268
2258
|
],
|
|
2269
2259
|
"default": "blend"
|
|
2270
2260
|
},
|
|
@@ -3420,14 +3410,8 @@
|
|
|
3420
3410
|
"type": "integer",
|
|
3421
3411
|
"exclusiveMinimum": 0
|
|
3422
3412
|
},
|
|
3423
|
-
"
|
|
3424
|
-
"type": "
|
|
3425
|
-
"properties": {
|
|
3426
|
-
"structuredOutput": {
|
|
3427
|
-
"type": "boolean"
|
|
3428
|
-
}
|
|
3429
|
-
},
|
|
3430
|
-
"additionalProperties": true
|
|
3413
|
+
"supportsJsonSchema": {
|
|
3414
|
+
"type": "boolean"
|
|
3431
3415
|
},
|
|
3432
3416
|
"extraParams": {
|
|
3433
3417
|
"type": "object",
|
|
@@ -3443,9 +3427,6 @@
|
|
|
3443
3427
|
"reasoningEffort": {
|
|
3444
3428
|
"type": "string",
|
|
3445
3429
|
"minLength": 1
|
|
3446
|
-
},
|
|
3447
|
-
"supportsJsonSchema": {
|
|
3448
|
-
"type": "boolean"
|
|
3449
3430
|
}
|
|
3450
3431
|
},
|
|
3451
3432
|
"required": [
|
package/schemas/akm-task.json
CHANGED
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
},
|
|
28
28
|
"inputs": {
|
|
29
29
|
"type": "object",
|
|
30
|
-
"maxProperties": 128,
|
|
31
30
|
"propertyNames": { "$ref": "#/definitions/taskInputName" },
|
|
32
31
|
"additionalProperties": { "$ref": "#/definitions/inputDeclaration" }
|
|
33
32
|
},
|
|
@@ -105,7 +104,7 @@
|
|
|
105
104
|
"items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }
|
|
106
105
|
},
|
|
107
106
|
"maxSteps": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 },
|
|
108
|
-
"maxRetries": { "type": "integer", "minimum": 0
|
|
107
|
+
"maxRetries": { "type": "integer", "minimum": 0 }
|
|
109
108
|
},
|
|
110
109
|
"oneOf": [
|
|
111
110
|
{
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
"params": {
|
|
23
23
|
"type": "object",
|
|
24
24
|
"minProperties": 1,
|
|
25
|
-
"maxProperties": 128,
|
|
26
25
|
"description": "Run parameters: param name -> JSON Schema declaration. Names must be params.<name>-addressable identifiers.",
|
|
27
26
|
"propertyNames": {
|
|
28
27
|
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
|
|
@@ -34,7 +33,6 @@
|
|
|
34
33
|
"outputs": {
|
|
35
34
|
"type": "object",
|
|
36
35
|
"minProperties": 1,
|
|
37
|
-
"maxProperties": 64,
|
|
38
36
|
"description": "Named, optionally schema-validated projections of step artifacts, exported when the run completes. Names must be steps.<child>.output.<name>-addressable identifiers. Each entry: { from: steps.<id>.output(.<seg>)*, schema?: <bounded JSON Schema> }. Markdown-frontmatter only.",
|
|
39
37
|
"propertyNames": {
|
|
40
38
|
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
|
|
@@ -52,7 +50,6 @@
|
|
|
52
50
|
"steps": {
|
|
53
51
|
"type": "array",
|
|
54
52
|
"minItems": 1,
|
|
55
|
-
"maxItems": 256,
|
|
56
53
|
"items": {
|
|
57
54
|
"$ref": "#/definitions/step"
|
|
58
55
|
}
|
|
@@ -188,7 +185,6 @@
|
|
|
188
185
|
"max": {
|
|
189
186
|
"type": "integer",
|
|
190
187
|
"minimum": 0,
|
|
191
|
-
"maximum": 100,
|
|
192
188
|
"description": "Maximum retry attempts per unit."
|
|
193
189
|
},
|
|
194
190
|
"on": {
|
|
@@ -213,7 +209,6 @@
|
|
|
213
209
|
"max_units": {
|
|
214
210
|
"type": "integer",
|
|
215
211
|
"minimum": 1,
|
|
216
|
-
"maximum": 10000,
|
|
217
212
|
"description": "Ceiling on total dispatched units across the run (seeded from journaled unit rows)."
|
|
218
213
|
}
|
|
219
214
|
}
|
|
@@ -252,25 +247,21 @@
|
|
|
252
247
|
"type": "array",
|
|
253
248
|
"description": "argv; command[0] is the program, resolved through PATH. Never shell-parsed.",
|
|
254
249
|
"minItems": 1,
|
|
255
|
-
"maxItems": 64,
|
|
256
250
|
"items": {
|
|
257
251
|
"type": "string",
|
|
258
|
-
"minLength": 1
|
|
259
|
-
"maxLength": 4096
|
|
252
|
+
"minLength": 1
|
|
260
253
|
}
|
|
261
254
|
},
|
|
262
255
|
"cwd": {
|
|
263
256
|
"type": "string",
|
|
264
257
|
"description": "Optional RELATIVE working directory inside the unit's working directory (its fresh worktree under `isolation: worktree`). Absolute paths, Windows drive letters, \"~\", and \"..\" segments are rejected here, and containment is re-checked against the resolved base — symlinks included — before the command is spawned.",
|
|
265
258
|
"minLength": 1,
|
|
266
|
-
"maxLength": 1024,
|
|
267
259
|
"pattern": "^(?!/|\\\\|~|[A-Za-z]:)(?!.*(?:^|[/\\\\])\\.\\.(?:[/\\\\]|$)).+$"
|
|
268
260
|
},
|
|
269
261
|
"pass_env": {
|
|
270
262
|
"type": "array",
|
|
271
263
|
"description": "Extra environment variable NAMES copied through from akm's own environment on top of the default allowlist — for a per-machine toolchain variable (e.g. CARGO_HOME) that no committed `env:` asset could carry. NAMES ONLY: values never appear in a workflow, and unlike `env:` bindings these values are NOT redacted from the command's output, so never list a credential here.",
|
|
272
264
|
"minItems": 1,
|
|
273
|
-
"maxItems": 32,
|
|
274
265
|
"uniqueItems": true,
|
|
275
266
|
"items": {
|
|
276
267
|
"type": "string",
|
|
@@ -398,7 +389,6 @@
|
|
|
398
389
|
"when": {
|
|
399
390
|
"type": "array",
|
|
400
391
|
"minItems": 1,
|
|
401
|
-
"maxItems": 256,
|
|
402
392
|
"items": {
|
|
403
393
|
"$ref": "#/definitions/routeBranch"
|
|
404
394
|
}
|
|
@@ -416,7 +406,6 @@
|
|
|
416
406
|
"max_loops": {
|
|
417
407
|
"type": "integer",
|
|
418
408
|
"minimum": 1,
|
|
419
|
-
"maximum": 100,
|
|
420
409
|
"description": "Evaluator-optimizer loop bound."
|
|
421
410
|
}
|
|
422
411
|
}
|
|
@@ -424,7 +413,6 @@
|
|
|
424
413
|
"inputs": {
|
|
425
414
|
"type": "array",
|
|
426
415
|
"minItems": 1,
|
|
427
|
-
"maxItems": 64,
|
|
428
416
|
"uniqueItems": true,
|
|
429
417
|
"items": {
|
|
430
418
|
"$ref": "#/definitions/reference"
|