akm-cli 0.9.2-alpha.4 → 0.9.2
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 +493 -0
- package/STABILITY.md +23 -5
- package/dist/assets/hints/cli-hints-full.md +12 -7
- package/dist/assets/tasks/core/extract.yml +3 -5
- package/dist/assets/tasks/core/improve.yml +3 -5
- package/dist/assets/tasks/core/index-refresh.yml +3 -5
- package/dist/assets/tasks/core/sync.yml +3 -5
- package/dist/assets/tasks/core/version-check.yml +3 -5
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +3 -5
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -6
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +3 -5
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +3 -5
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +3 -5
- package/dist/cli/unknown-flags.js +12 -1
- package/dist/cli.js +8 -1
- package/dist/commands/command/command-execution.js +23 -2
- package/dist/commands/health/improve-metrics.js +38 -0
- package/dist/commands/health/windows.js +8 -4
- package/dist/commands/health.js +8 -4
- package/dist/commands/lint/index.js +1 -1
- package/dist/commands/migrate-cli.js +130 -24
- package/dist/commands/proposal/validators/proposal-validators.js +7 -2
- package/dist/commands/tasks/explain.js +304 -0
- package/dist/commands/tasks/tasks-cli.js +185 -3
- package/dist/commands/tasks/tasks.js +265 -52
- package/dist/commands/workflow/plan.js +159 -0
- package/dist/commands/workflow-cli.js +94 -2
- package/dist/core/activation-policy.js +2 -12
- package/dist/core/adapter/adapters/akm-lint.js +7 -4
- package/dist/core/adapter/adapters/akm-metadata.js +26 -14
- package/dist/core/adapter/adapters/akm-task-adapter.js +13 -10
- package/dist/core/errors.js +45 -0
- package/dist/core/json-schema.js +15 -5
- package/dist/core/state/migrations.js +57 -0
- package/dist/core/state-db.js +16 -14
- package/dist/core/subprocess.js +47 -13
- package/dist/execution/guarded-source.js +44 -0
- package/dist/execution/input-contract.js +250 -0
- package/dist/execution/target-ref.js +63 -0
- package/dist/indexer/usage/usage-events.js +14 -3
- package/dist/integrations/agent/execution-lowering.js +12 -1
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +12 -3
- package/dist/output/text/workflow-format.js +192 -10
- package/dist/output/text/workflow.js +2 -1
- package/dist/runtime.js +1 -0
- package/dist/scripts/akm-migrate-node.js +11838 -10118
- package/dist/scripts/akm-migrate.js +11828 -10117
- package/dist/setup/steps/tasks.js +34 -17
- package/dist/storage/repositories/task-history-repository.js +5 -1
- package/dist/storage/repositories/workflow-runs-repository.js +144 -6
- package/dist/tasks/backends/launchd.js +31 -84
- package/dist/tasks/embedded.js +13 -7
- package/dist/tasks/model/invocation.js +4 -0
- package/dist/tasks/prepare/prepare-script-target.js +9 -0
- package/dist/tasks/prepare/prepare-support.js +154 -0
- package/dist/tasks/prepare/prepare.js +117 -0
- package/dist/tasks/prepare/prepared-execution.js +4 -0
- package/dist/tasks/prepare/script-capture.js +80 -0
- package/dist/tasks/run/attempt-lifecycle.js +165 -0
- package/dist/tasks/run/load-task.js +117 -0
- package/dist/tasks/run/provenance.js +20 -0
- package/dist/tasks/run/run-command-task.js +92 -0
- package/dist/tasks/run/run-native-task.js +222 -0
- package/dist/tasks/run/run-task.js +99 -0
- package/dist/tasks/run/run-workflow-task.js +222 -0
- package/dist/tasks/run/task-history.js +134 -0
- package/dist/tasks/run/task-log.js +179 -0
- package/dist/tasks/run/task-result.js +19 -0
- package/dist/tasks/scheduler-binding.js +66 -2
- package/dist/tasks/scheduler-invocation.js +63 -3
- package/dist/tasks/scheduler-sync.js +77 -14
- package/dist/tasks/source/bounded-document.js +455 -0
- package/dist/tasks/source/parse-task-source.js +59 -0
- package/dist/tasks/source/project-v4.js +62 -0
- package/dist/tasks/source/task-input-diagnostics.js +36 -0
- package/dist/tasks/source/task-source-v4.js +626 -0
- package/dist/tasks/source-v3.js +10 -733
- package/dist/tasks/task-run-reserved-flags.js +79 -0
- package/dist/workflows/authoring/authoring.js +17 -8
- package/dist/workflows/exec/child-invocation.js +34 -0
- package/dist/workflows/exec/child-workflow.js +370 -0
- package/dist/workflows/exec/exec-unit.js +50 -170
- package/dist/workflows/exec/frozen-judge.js +19 -2
- package/dist/workflows/exec/native-executor.js +49 -27
- package/dist/workflows/exec/param-secrets.js +12 -0
- package/dist/workflows/exec/run-workflow.js +48 -59
- package/dist/workflows/exec/step-work.js +222 -80
- package/dist/workflows/exec/unit-dispatch.js +72 -0
- package/dist/workflows/freeze/child-output-references.js +94 -0
- package/dist/workflows/freeze/environment.js +174 -0
- package/dist/workflows/freeze/identity.js +22 -0
- package/dist/workflows/freeze/resolve-steps.js +78 -0
- package/dist/workflows/freeze/source-freeze.js +57 -0
- package/dist/workflows/freeze/step-values.js +68 -0
- package/dist/workflows/freeze/targets/child-workflow.js +206 -0
- package/dist/workflows/freeze/targets/command.js +81 -0
- package/dist/workflows/freeze/targets/script.js +57 -0
- package/dist/workflows/freeze/targets/shell.js +31 -0
- package/dist/workflows/freeze/targets/task.js +179 -0
- package/dist/workflows/freeze/task-bindings.js +180 -0
- package/dist/workflows/ir/compile.js +59 -11
- package/dist/workflows/ir/environment-v4.js +3 -3
- package/dist/workflows/ir/freeze-v4.js +41 -7
- package/dist/workflows/ir/params.js +58 -131
- package/dist/workflows/ir/plan-hash.js +3 -3
- package/dist/workflows/ir/schema-v4.js +246 -17
- package/dist/workflows/parser.js +74 -2
- package/dist/workflows/program/schema.js +5 -2
- package/dist/workflows/resource-limits.js +20 -0
- package/dist/workflows/runtime/plan-classifier.js +24 -7
- package/dist/workflows/runtime/run-outputs.js +103 -0
- package/dist/workflows/runtime/runs.js +114 -9
- package/dist/workflows/runtime/workflow-asset-loader.js +14 -6
- package/dist/workflows/source-files.js +5 -5
- package/dist/workflows/source-ir/compare.js +17 -0
- package/dist/workflows/source-ir/compile.js +7 -3
- package/dist/workflows/source-ir/github-yaml.js +64 -17
- package/dist/workflows/source-ir/schema.js +69 -21
- package/dist/workflows/source-ir/semantics.js +7 -25
- package/dist/workflows/source-ir/triggers.js +79 -0
- package/dist/workflows/source-ir/uses.js +33 -7
- package/docs/migration/README.md +1 -1
- package/docs/migration/release-notes/0.9.2.md +87 -11
- package/docs/migration/release-notes/README.md +3 -2
- package/docs/migration/v0.8-to-v0.9.md +13 -11
- package/docs/migration/v0.9.0-troubleshooting.md +20 -13
- package/docs/migration/v0.9.1-to-v0.9.2.md +598 -49
- package/docs/reference/README.md +1 -1
- package/docs/reference/cli.md +140 -46
- package/docs/reference/configuration.md +6 -5
- package/docs/reference/supported-formats.md +9 -5
- package/docs/reference/tasks.md +338 -75
- package/docs/reference/workflow-schema.md +290 -16
- package/docs/reference/workflows.md +57 -7
- package/package.json +1 -1
- package/schemas/akm-task.json +173 -118
- package/schemas/akm-workflow.json +28 -0
- package/dist/tasks/runner.js +0 -941
- package/dist/tasks/runtime-v3.js +0 -281
- package/dist/workflows/ir/source-freeze-v4.js +0 -506
- package/dist/workflows/source-ir/ordering.js +0 -38
|
@@ -14,8 +14,8 @@ 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, utf8Bytes, WORKFLOW_ENGINE_NAME_PATTERN, WORKFLOW_ENV_VAR_NAME_PATTERN, WORKFLOW_MAX_CONCURRENCY, WORKFLOW_MAX_ENGINE_NAME_LENGTH, WORKFLOW_MAX_EXEC_ARG_BYTES, WORKFLOW_MAX_EXEC_ARGV, WORKFLOW_MAX_EXEC_CWD_LENGTH, WORKFLOW_MAX_EXEC_PASS_ENV, WORKFLOW_MAX_EXTRA_PARAMS_BYTES, WORKFLOW_MAX_GATE_LOOPS, WORKFLOW_MAX_INPUTS, WORKFLOW_MAX_MAP_EXPANSION, WORKFLOW_MAX_PARAMS, WORKFLOW_MAX_RETRIES, WORKFLOW_MAX_ROUTE_BRANCHES, WORKFLOW_MAX_SCHEMA_BYTES, WORKFLOW_MAX_TIMEOUT_MS, } from "../resource-limits.js";
|
|
18
|
-
import {
|
|
17
|
+
import { jsonBytes, utf8Bytes, WORKFLOW_ENGINE_NAME_PATTERN, WORKFLOW_ENV_VAR_NAME_PATTERN, WORKFLOW_MAX_CONCURRENCY, WORKFLOW_MAX_ENGINE_NAME_LENGTH, WORKFLOW_MAX_EXEC_ARG_BYTES, WORKFLOW_MAX_EXEC_ARGV, WORKFLOW_MAX_EXEC_CWD_LENGTH, WORKFLOW_MAX_EXEC_PASS_ENV, WORKFLOW_MAX_EXTRA_PARAMS_BYTES, WORKFLOW_MAX_GATE_LOOPS, WORKFLOW_MAX_INPUTS, WORKFLOW_MAX_MAP_EXPANSION, WORKFLOW_MAX_OUTPUTS, WORKFLOW_MAX_PARAMS, WORKFLOW_MAX_RETRIES, WORKFLOW_MAX_ROUTE_BRANCHES, WORKFLOW_MAX_SCHEMA_BYTES, WORKFLOW_MAX_TIMEOUT_MS, } from "../resource-limits.js";
|
|
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;
|
|
21
21
|
export const WORKFLOW_SOURCE_IR_MAX_BYTES = 2 * 1024 * 1024;
|
|
@@ -35,6 +35,7 @@ export function decodeWorkflowSourceIrV1(input, options = {}) {
|
|
|
35
35
|
"description",
|
|
36
36
|
"tags",
|
|
37
37
|
"params",
|
|
38
|
+
"outputs",
|
|
38
39
|
"defaults",
|
|
39
40
|
"budget",
|
|
40
41
|
"preamble",
|
|
@@ -50,6 +51,7 @@ export function decodeWorkflowSourceIrV1(input, options = {}) {
|
|
|
50
51
|
optionalString(root.preamble, "preamble");
|
|
51
52
|
optionalStringList(root.tags, "tags", 256);
|
|
52
53
|
validateParams(root.params);
|
|
54
|
+
validateOutputs(root.outputs);
|
|
53
55
|
validateUnit(root.defaults, "defaults", true);
|
|
54
56
|
validateBudget(root.budget);
|
|
55
57
|
span(root.source, "source");
|
|
@@ -58,8 +60,8 @@ export function decodeWorkflowSourceIrV1(input, options = {}) {
|
|
|
58
60
|
fail("triggers must contain 1 through 64 entries");
|
|
59
61
|
}
|
|
60
62
|
validateTriggers(root.triggers);
|
|
61
|
-
if (!Array.isArray(root.jobs) || root.jobs.length
|
|
62
|
-
fail("jobs must contain 1
|
|
63
|
+
if (!Array.isArray(root.jobs) || root.jobs.length !== 1) {
|
|
64
|
+
fail("jobs must contain exactly 1 entry");
|
|
63
65
|
}
|
|
64
66
|
const jobIds = new Set();
|
|
65
67
|
for (const [index, job] of root.jobs.entries())
|
|
@@ -69,7 +71,6 @@ export function decodeWorkflowSourceIrV1(input, options = {}) {
|
|
|
69
71
|
if (!jobIds.has(need))
|
|
70
72
|
fail(`job ${job.id} needs missing job ${need}`);
|
|
71
73
|
}
|
|
72
|
-
validateTopologicalJobs(root.jobs);
|
|
73
74
|
return decoded;
|
|
74
75
|
}
|
|
75
76
|
function validateTrigger(value, index) {
|
|
@@ -177,6 +178,9 @@ function validateStep(value, jobId, index, stepIds, options) {
|
|
|
177
178
|
fail(`step ${id} uses must be a non-empty string`);
|
|
178
179
|
if (step.run !== undefined && !hasRun)
|
|
179
180
|
fail(`step ${id} run must be a non-empty string`);
|
|
181
|
+
// A-N3: captured at the outer scope so scalarRecord's task-scoped widening
|
|
182
|
+
// (below) can consult it without re-classifying `step.uses`.
|
|
183
|
+
let usesTarget;
|
|
180
184
|
if (hasUses) {
|
|
181
185
|
let target;
|
|
182
186
|
try {
|
|
@@ -185,6 +189,7 @@ function validateStep(value, jobId, index, stepIds, options) {
|
|
|
185
189
|
catch (cause) {
|
|
186
190
|
semanticFail(cause, `step ${id} uses`);
|
|
187
191
|
}
|
|
192
|
+
usesTarget = target;
|
|
188
193
|
if (target.kind === "builtin-command") {
|
|
189
194
|
if (step.commandMode !== "literal" &&
|
|
190
195
|
step.commandMode !== "portable-template" &&
|
|
@@ -214,7 +219,13 @@ function validateStep(value, jobId, index, stepIds, options) {
|
|
|
214
219
|
}
|
|
215
220
|
}
|
|
216
221
|
validateExec(step.exec, `step ${id} exec`, options);
|
|
217
|
-
|
|
222
|
+
// A-N3, widened in P3a (spec docs/plans/specs/p3a-plan-v5-child-freeze.md
|
|
223
|
+
// §4.2 step 7, row B-10, A-N8): the "must be a scalar" restriction narrows
|
|
224
|
+
// to non-task, non-workflow targets only. A tasks/<ref> or workflows/<ref>
|
|
225
|
+
// step's with: may carry any JSON value the bounded document front end
|
|
226
|
+
// already accepts; freeze (src/workflows/freeze/**) decides what a
|
|
227
|
+
// declared input/param actually accepts.
|
|
228
|
+
scalarRecord(step.with, `step ${id} with`, true, usesTarget?.kind === "task" || usesTarget?.kind === "workflow");
|
|
218
229
|
environment(step.env, `step ${id} env`);
|
|
219
230
|
rejectStepWithExpressions(step, id);
|
|
220
231
|
rejectExpressionsInRecord(step.env, `step ${id} env`);
|
|
@@ -258,17 +269,6 @@ function validateStep(value, jobId, index, stepIds, options) {
|
|
|
258
269
|
extensions(step.extensions, `step ${id} extensions`);
|
|
259
270
|
span(step.source, `step ${id} source`);
|
|
260
271
|
}
|
|
261
|
-
function validateTopologicalJobs(jobs) {
|
|
262
|
-
const result = canonicalTopologicalJobs(jobs);
|
|
263
|
-
if (!result.ok) {
|
|
264
|
-
if (result.kind === "missing")
|
|
265
|
-
fail(`job ${result.job.id} needs missing job ${result.dependency}`);
|
|
266
|
-
fail("jobs contain a dependency cycle");
|
|
267
|
-
}
|
|
268
|
-
if (result.jobs.some((job, index) => job.id !== jobs[index]?.id)) {
|
|
269
|
-
fail("jobs are not in canonical dependency-topological order");
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
272
|
function compareCodePoints(left, right) {
|
|
273
273
|
return compareWorkflowSourceCodePoints(left, right);
|
|
274
274
|
}
|
|
@@ -441,10 +441,13 @@ function validateRouteTargets(steps, jobId) {
|
|
|
441
441
|
}
|
|
442
442
|
}
|
|
443
443
|
}
|
|
444
|
-
function validateReference(value, location) {
|
|
444
|
+
function validateReference(value, location, expectedKind) {
|
|
445
445
|
const parsed = parseReference(value);
|
|
446
446
|
if (!parsed.ok)
|
|
447
447
|
fail(`${location} is invalid: ${parsed.message}`);
|
|
448
|
+
if (expectedKind && parsed.expr.kind !== expectedKind) {
|
|
449
|
+
fail(`${location} must reference a step output (steps.<id>.output...), not a param`);
|
|
450
|
+
}
|
|
448
451
|
}
|
|
449
452
|
function validateParams(value) {
|
|
450
453
|
if (value === undefined)
|
|
@@ -459,6 +462,30 @@ function validateParams(value) {
|
|
|
459
462
|
validateSchema(schema, `params.${name}`, false);
|
|
460
463
|
}
|
|
461
464
|
}
|
|
465
|
+
/**
|
|
466
|
+
* Structural re-validation of `outputs:` (P3b, spec §4.2) — the parser
|
|
467
|
+
* (`../parser.ts`) already enforces the same rules at authoring time; this is
|
|
468
|
+
* the corruption-gate re-check every source-IR field gets, mirroring
|
|
469
|
+
* `validateParams` immediately above.
|
|
470
|
+
*/
|
|
471
|
+
function validateOutputs(value) {
|
|
472
|
+
if (value === undefined)
|
|
473
|
+
return;
|
|
474
|
+
const outputs = record(value, "outputs");
|
|
475
|
+
if (Object.keys(outputs).length === 0 || Object.keys(outputs).length > WORKFLOW_MAX_OUTPUTS) {
|
|
476
|
+
fail(`outputs must contain 1 through ${WORKFLOW_MAX_OUTPUTS} entries`);
|
|
477
|
+
}
|
|
478
|
+
for (const [name, declaration] of Object.entries(outputs)) {
|
|
479
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
480
|
+
fail(`outputs has invalid name ${name}`);
|
|
481
|
+
const decl = record(declaration, `outputs.${name}`);
|
|
482
|
+
keys(decl, ["from", "schema"], `outputs.${name}`);
|
|
483
|
+
nonEmptyString(decl.from, `outputs.${name}.from`);
|
|
484
|
+
validateReference(decl.from, `outputs.${name}.from`, "stepOutput");
|
|
485
|
+
if (decl.schema !== undefined)
|
|
486
|
+
validateSchema(decl.schema, `outputs.${name}.schema`, false);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
462
489
|
function validateBudget(value) {
|
|
463
490
|
if (value === undefined)
|
|
464
491
|
return;
|
|
@@ -545,14 +572,25 @@ function rejectExpressionsInRecord(value, location) {
|
|
|
545
572
|
fail(`${location}.${key} contains an unsupported expression`);
|
|
546
573
|
}
|
|
547
574
|
}
|
|
575
|
+
/** A-N3: recurses into nested values, since a task step's with: may now carry an object/array. */
|
|
576
|
+
function containsUnsupportedExpression(value) {
|
|
577
|
+
if (typeof value === "string")
|
|
578
|
+
return value.includes("${{");
|
|
579
|
+
if (Array.isArray(value))
|
|
580
|
+
return value.some((item) => containsUnsupportedExpression(item));
|
|
581
|
+
if (value !== null && typeof value === "object") {
|
|
582
|
+
return Object.values(value).some((item) => containsUnsupportedExpression(item));
|
|
583
|
+
}
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
548
586
|
function rejectStepWithExpressions(step, id) {
|
|
549
587
|
if (step.with === undefined)
|
|
550
588
|
return;
|
|
551
589
|
for (const [key, item] of Object.entries(record(step.with, `step ${id} with`))) {
|
|
552
|
-
if (typeof item !== "string" || !item.includes("${{"))
|
|
553
|
-
continue;
|
|
554
590
|
if (step.uses === "akm/command" && step.commandMode === "literal" && key === "content")
|
|
555
591
|
continue;
|
|
592
|
+
if (!containsUnsupportedExpression(item))
|
|
593
|
+
continue;
|
|
556
594
|
fail(`step ${id} with.${key} contains an unsupported expression`);
|
|
557
595
|
}
|
|
558
596
|
}
|
|
@@ -722,13 +760,23 @@ function stringList(value, location, max, allowEmpty) {
|
|
|
722
760
|
seen.add(item);
|
|
723
761
|
}
|
|
724
762
|
}
|
|
725
|
-
|
|
763
|
+
/**
|
|
764
|
+
* `allowNonScalar` (A-N3, P2b; widened in P3a, A-N8): when true (a
|
|
765
|
+
* `tasks/<ref>` or `workflows/<ref>` step's `with:`), the key-grammar check
|
|
766
|
+
* still runs but the scalar/null value restriction is skipped entirely — a
|
|
767
|
+
* declared object/array-typed input or param, or a `{from: "..."}`
|
|
768
|
+
* reference, may decode. Every other target keeps the byte-identical
|
|
769
|
+
* scalar-or-null restriction.
|
|
770
|
+
*/
|
|
771
|
+
function scalarRecord(value, location, allowNull, allowNonScalar = false) {
|
|
726
772
|
if (value === undefined)
|
|
727
773
|
return;
|
|
728
774
|
const map = record(value, location);
|
|
729
775
|
for (const [key, item] of Object.entries(map)) {
|
|
730
776
|
if (!/^[A-Za-z_][A-Za-z0-9_.-]{0,127}$/.test(key))
|
|
731
777
|
fail(`${location} has invalid key ${key}`);
|
|
778
|
+
if (allowNonScalar)
|
|
779
|
+
continue;
|
|
732
780
|
if (item === null && allowNull)
|
|
733
781
|
continue;
|
|
734
782
|
if (typeof item !== "string" && typeof item !== "number" && typeof item !== "boolean") {
|
|
@@ -6,7 +6,6 @@ import fs from "node:fs";
|
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { parseBuiltinCommandAction } from "../../commands/command/builtin-action.js";
|
|
8
8
|
import { validatePortableCommandTemplate } from "../../commands/command/portable-template.js";
|
|
9
|
-
import { bundleRefToString, parseBundleRef } from "../../core/asset/asset-ref.js";
|
|
10
9
|
import { parseSchedule } from "../../tasks/schedule.js";
|
|
11
10
|
import { classifyWorkflowSourceUses } from "./uses.js";
|
|
12
11
|
const TOKEN_SAFE_RUN = /^[A-Za-z0-9_./:@+=,-]+(?: [A-Za-z0-9_./:@+=,-]+)*$/;
|
|
@@ -83,9 +82,6 @@ export function classifyWorkflowStepUses(value, classifier = classifyWorkflowSou
|
|
|
83
82
|
if (value.length === 0 || value.trim() !== value || /\s/.test(value)) {
|
|
84
83
|
throw new WorkflowSourceSemanticError("unsupported-uses-target", "uses must be one exact, non-empty executable ref");
|
|
85
84
|
}
|
|
86
|
-
const task = canonicalTaskTarget(value);
|
|
87
|
-
if (task)
|
|
88
|
-
return task;
|
|
89
85
|
let target;
|
|
90
86
|
try {
|
|
91
87
|
target = classifier(value);
|
|
@@ -93,29 +89,15 @@ export function classifyWorkflowStepUses(value, classifier = classifyWorkflowSou
|
|
|
93
89
|
catch (cause) {
|
|
94
90
|
throw usesFailure(value, cause);
|
|
95
91
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
92
|
+
// P3a (docs/plans/specs/p3a-plan-v5-child-freeze.md §1.3(2)/§4, A-N4): a
|
|
93
|
+
// `kind: "workflow"` target used to throw `nested-workflow-unsupported`
|
|
94
|
+
// here. That rejection is REMOVED — classification returns the workflow
|
|
95
|
+
// target like any other target-ref-shaped `uses:`, and freeze decides
|
|
96
|
+
// (`src/workflows/freeze/targets/child-workflow.ts`, the ONE recursive
|
|
97
|
+
// child-workflow resolver both the direct and task-wrapped composition
|
|
98
|
+
// forms route through).
|
|
102
99
|
return target;
|
|
103
100
|
}
|
|
104
|
-
function canonicalTaskTarget(value) {
|
|
105
|
-
try {
|
|
106
|
-
const parsed = parseBundleRef(value);
|
|
107
|
-
if (parsed.fragment !== undefined || bundleRefToString(parsed) !== value)
|
|
108
|
-
return undefined;
|
|
109
|
-
const slash = parsed.conceptId.indexOf("/");
|
|
110
|
-
if (slash < 0 || parsed.conceptId.slice(0, slash) !== "tasks" || parsed.conceptId.length === slash + 1) {
|
|
111
|
-
return undefined;
|
|
112
|
-
}
|
|
113
|
-
return { kind: "task", ref: value };
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
return undefined;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
101
|
/**
|
|
120
102
|
* Validate AKM's built-in command action at the shared source/decoder boundary.
|
|
121
103
|
*
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import { asRecord, checkKeys, cloneBoundedJson, noGithubExpression, own, presentJsonValue, sourceError, stringField, TASK_V3_MAX_SCHEDULES, } from "../../tasks/source/bounded-document.js";
|
|
5
|
+
const SOURCE_LABEL = "task v3 source";
|
|
6
|
+
function ctxFrom(options) {
|
|
7
|
+
return {
|
|
8
|
+
filePath: options.filePath,
|
|
9
|
+
sourceLabel: SOURCE_LABEL,
|
|
10
|
+
...(options.lineAt ? { lineAt: options.lineAt } : {}),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const ON_KEYS = ["schedule", "workflow_dispatch"];
|
|
14
|
+
function parseOn(value, ctx) {
|
|
15
|
+
const input = asRecord(value, ctx, ["on"]);
|
|
16
|
+
const keys = Object.keys(input);
|
|
17
|
+
if (keys.length === 0)
|
|
18
|
+
sourceError(ctx, ["on"], "must declare schedule and/or workflow_dispatch.");
|
|
19
|
+
const unsupported = keys.find((key) => !ON_KEYS.includes(key));
|
|
20
|
+
if (unsupported)
|
|
21
|
+
sourceError(ctx, ["on", unsupported], "is an unsupported local service event; no scheduler binding was created.");
|
|
22
|
+
const schedules = [];
|
|
23
|
+
if (own(input, "schedule")) {
|
|
24
|
+
if (!Array.isArray(input.schedule) || input.schedule.length === 0) {
|
|
25
|
+
sourceError(ctx, ["on", "schedule"], "must be a non-empty list of {cron: string} records.");
|
|
26
|
+
}
|
|
27
|
+
if (input.schedule.length > TASK_V3_MAX_SCHEDULES) {
|
|
28
|
+
sourceError(ctx, ["on", "schedule"], `accepts at most ${TASK_V3_MAX_SCHEDULES} entries.`);
|
|
29
|
+
}
|
|
30
|
+
for (const [index, raw] of input.schedule.entries()) {
|
|
31
|
+
const entry = asRecord(raw, ctx, ["on", "schedule", index]);
|
|
32
|
+
checkKeys(entry, ["cron"], ctx, ["on", "schedule", index]);
|
|
33
|
+
if (!own(entry, "cron"))
|
|
34
|
+
sourceError(ctx, ["on", "schedule", index, "cron"], "is required.");
|
|
35
|
+
const cron = stringField(entry.cron, ctx, ["on", "schedule", index, "cron"], { nonempty: true });
|
|
36
|
+
noGithubExpression(cron, ctx, ["on", "schedule", index, "cron"]);
|
|
37
|
+
schedules.push(Object.freeze({ cron, source: `on.schedule[${index}].cron`, ordinal: index }));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
let manual = false;
|
|
41
|
+
if (own(input, "workflow_dispatch")) {
|
|
42
|
+
const dispatch = input.workflow_dispatch;
|
|
43
|
+
if (dispatch !== null) {
|
|
44
|
+
const mapping = asRecord(presentJsonValue(dispatch, ctx, ["on", "workflow_dispatch"]), ctx, [
|
|
45
|
+
"on",
|
|
46
|
+
"workflow_dispatch",
|
|
47
|
+
]);
|
|
48
|
+
if (Object.keys(mapping).length > 0) {
|
|
49
|
+
sourceError(ctx, ["on", "workflow_dispatch"], "must be null or an empty mapping; inputs are unsupported.");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
manual = true;
|
|
53
|
+
}
|
|
54
|
+
return Object.freeze({ manual, schedules: Object.freeze(schedules) });
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* `on:` is the one canonical scheduling source a workflow YAML trigger
|
|
58
|
+
* fragment has a live caller for (see file header — the task-v3 `akm:`
|
|
59
|
+
* options bag this used to also accept is deleted, along with the
|
|
60
|
+
* "exactly one scheduling source" choice between the two).
|
|
61
|
+
*/
|
|
62
|
+
function compileTriggers(input, ctx) {
|
|
63
|
+
if (!own(input, "on"))
|
|
64
|
+
sourceError(ctx, ["on"], "is required.");
|
|
65
|
+
return parseOn(presentJsonValue(input.on, ctx, ["on"]), ctx);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Classify the strict trigger fragment `{on}` into deterministic local
|
|
69
|
+
* scheduler bindings. Full workflow adapters pass only that one field; this
|
|
70
|
+
* rejects `jobs` and every other workflow field (and, since the review fix
|
|
71
|
+
* above, `akm` too) rather than owning the document grammar.
|
|
72
|
+
*/
|
|
73
|
+
export function classifyWorkflowYamlTriggers(value, options) {
|
|
74
|
+
const ctx = ctxFrom(options);
|
|
75
|
+
const cloned = cloneBoundedJson(value, ctx, [], { nodes: 0 });
|
|
76
|
+
const input = asRecord(cloned, ctx, []);
|
|
77
|
+
checkKeys(input, ["on"], ctx, []);
|
|
78
|
+
return compileTriggers(input, ctx);
|
|
79
|
+
}
|
|
@@ -2,13 +2,39 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* canonical task
|
|
5
|
+
* The workflow `uses:` classification seam (P1a Lane B,
|
|
6
|
+
* docs/plans/specs/p1a-with-rejection-classifier.md §4.2).
|
|
7
|
+
*
|
|
8
|
+
* `classifyWorkflowSourceUses` is the canonical non-task `uses:` classifier
|
|
9
|
+
* used by direct source-IR decoding (and, via `compile.ts`, by the GitHub-YAML
|
|
10
|
+
* entrypoint): it recognizes the `akm/command` builtin special case and
|
|
11
|
+
* otherwise delegates to `classifyTargetRef` (src/execution/target-ref.ts),
|
|
12
|
+
* the canonical classifier for `commands/`, `scripts/`, `tasks/`, and
|
|
13
|
+
* `workflows/` asset refs — including `tasks/...` targets, for which
|
|
14
|
+
* `classifyTargetRef`'s own `tasks/` arm is the one authority (brief §8.1;
|
|
15
|
+
* P4 deleted `classifyWorkflowStepUses`'s `canonicalTaskTarget` pre-check in
|
|
16
|
+
* semantics.ts, which used to match them first).
|
|
17
|
+
*
|
|
18
|
+
* This module imports NOTHING from `src/tasks/source-v3.ts`: workflow `uses:`
|
|
19
|
+
* classification no longer delegates to the task-v3 grammar, and (P4) native
|
|
20
|
+
* target classification recognizes no GitHub Action variant at all —
|
|
21
|
+
* `WorkflowSourceUsesTarget` below has no `github-action` member, typed or
|
|
22
|
+
* otherwise.
|
|
23
|
+
*/
|
|
24
|
+
import { classifyTargetRef } from "../../execution/target-ref.js";
|
|
25
|
+
/**
|
|
26
|
+
* Canonical non-task classifier used by direct source-IR decoding (and the
|
|
27
|
+
* GitHub-YAML entrypoint's default, wired via compile.ts). Layers the
|
|
28
|
+
* `akm/command` builtin special case over `classifyTargetRef`, which throws
|
|
29
|
+
* `UsageError` `TARGET_REF_INVALID` for anything else.
|
|
9
30
|
*/
|
|
10
|
-
import { classifyTaskV3Uses } from "../../tasks/source-v3.js";
|
|
11
|
-
/** Canonical non-task classifier used by direct source-IR decoding. */
|
|
12
31
|
export function classifyWorkflowSourceUses(value) {
|
|
13
|
-
|
|
32
|
+
if (value === "akm/command") {
|
|
33
|
+
return Object.freeze({ kind: "builtin-command", ref: "akm/command" });
|
|
34
|
+
}
|
|
35
|
+
// classifyTargetRef's return type is structurally identical to this
|
|
36
|
+
// module's `{ kind: "command" | "script" | "task" | "workflow"; ref:
|
|
37
|
+
// string }` union arm, so it is assignable to WorkflowSourceUsesTarget
|
|
38
|
+
// without a cast.
|
|
39
|
+
return classifyTargetRef(value);
|
|
14
40
|
}
|
package/docs/migration/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Upgrade guides and per-release migration notes.
|
|
4
4
|
|
|
5
|
-
- [v0.9.1 -> v0.9.2 migration guide](v0.9.1-to-v0.9.2.md) -- Task-v2 to task
|
|
5
|
+
- [v0.9.1 -> v0.9.2 migration guide](v0.9.1-to-v0.9.2.md) -- Task-v2/task-v3 to task source v4 conversion, the durable-v4-family workflow boundary at executable `irVersion: 5`, and release behavior changes
|
|
6
6
|
- [v0.9.2 release note](release-notes/0.9.2.md) -- Self-contained terminal upgrade summary shipped for `akm help migrate 0.9.2`
|
|
7
7
|
- [v0.8 -> current v0.9 migration guide](v0.8-to-v0.9.md) -- Package upgrade with fresh current config/state and explicit task conversion
|
|
8
8
|
- [v0.7 -> v0.8 migration guide](v0.7-to-v0.8.md) -- Task schema and 0.8-era changes
|
|
@@ -21,19 +21,95 @@ the recovery snapshot and migration 002's rebuild. Snapshot readers and targets
|
|
|
21
21
|
are bound to their held inodes, not swappable pathnames. A failed snapshot path
|
|
22
22
|
is reported and never removed by cleanup code.
|
|
23
23
|
|
|
24
|
-
Task sources now use
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
Task sources now use task source v4. Normal execution rejects task-v3 and
|
|
25
|
+
task-v2 files with `TASK_SCHEMA_VERSION_UNSUPPORTED`; preview the
|
|
26
|
+
repository-wide conversion with `akm migrate apply --dry-run`, review every
|
|
27
|
+
`changed`, `skipped`, or `blocked` result, then run `akm migrate apply` — it
|
|
28
|
+
now runs both the v2→v3 and v3→v4 generations in one pass. The migrator
|
|
29
|
+
validates each replacement before it backs up and replaces a source, and
|
|
30
|
+
ambiguous cases (an argv array with no safe shell equivalent, a `with:`
|
|
31
|
+
block with no v4 equivalent, an ambiguous scheduling source, and similar)
|
|
32
|
+
remain blocked for manual review. Task source v4 adds typed `inputs:` with
|
|
33
|
+
defaults, a single bounded `output:` schema, optional `schedule:`, and
|
|
34
|
+
per-schedule-binding enablement. See
|
|
35
|
+
[Task sources](../v0.9.1-to-v0.9.2.md#task-sources) and
|
|
36
|
+
[The migration procedure](../v0.9.1-to-v0.9.2.md#the-migration-procedure).
|
|
37
|
+
|
|
38
|
+
Task run history's `target.kind` result field also changed vocabulary:
|
|
39
|
+
`"prompt"` is now `"command"` (an agent/LLM dispatch), and the old shared
|
|
40
|
+
`"command"` split into `"shell"` and `"script"`. `akm task history` reads
|
|
41
|
+
both generations of existing rows correctly, forever, keyed on a per-row
|
|
42
|
+
`targetVocab` marker — but a pre-0.9.2 akm's decoder does not recognize
|
|
43
|
+
that marker and **throws** reading a row this release (or later) wrote, so
|
|
44
|
+
upgrade once and don't downgrade below 0.9.2 for a given `state.db`. See
|
|
45
|
+
[Task history result vocabulary](../v0.9.1-to-v0.9.2.md#task-history-result-vocabulary-targetkind).
|
|
29
46
|
|
|
30
47
|
Workflows now accept peer Markdown (`.md`) and GitHub-shaped YAML (`.yml`)
|
|
31
|
-
sources through source IR v1. Runs freeze durable plan
|
|
32
|
-
plan format. Pre
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
48
|
+
sources through source IR v1. Runs freeze durable plan `irVersion` 5, the
|
|
49
|
+
only executable plan format. Pre-`irVersion`-5 stored plans cannot resume,
|
|
50
|
+
next, complete, or run — `status`, `list`, and `abandon` keep working, and
|
|
51
|
+
`akm workflow abandon <id>` followed by a fresh `akm workflow run <ref>`
|
|
52
|
+
recovers a blocked run; no data is lost. A resume does not re-read the
|
|
53
|
+
authored workflow, configuration, or asset index. Scheduled fires are new
|
|
54
|
+
starts, so they read the current source and create a fresh freeze. `.yml`
|
|
55
|
+
also rejects `inherit_env`; use exact named environment bindings and
|
|
56
|
+
`pass_env` names instead. See
|
|
57
|
+
[Workflow cutover](../v0.9.1-to-v0.9.2.md#workflow-cutover).
|
|
58
|
+
|
|
59
|
+
A workflow step can now compose another workflow as a child — directly
|
|
60
|
+
(`uses: workflows/<ref>`) or through a task whose own target is a workflow
|
|
61
|
+
— bounded by composition depth, cycle detection, and aggregate embedded-plan
|
|
62
|
+
size, all checked at freeze before the parent run is published. Running the
|
|
63
|
+
step drives the child to completion inline, in the parent's own process:
|
|
64
|
+
cancellation propagates because it is the same process, the child is
|
|
65
|
+
independently resumable, and `akm workflow status` on the parent renders a
|
|
66
|
+
`children:` tree. A workflow may also declare `outputs:` — a run-level
|
|
67
|
+
export resolved once from persisted step evidence at completion, which a
|
|
68
|
+
composing parent step promotes as its own output. See
|
|
69
|
+
[Child workflows](../v0.9.1-to-v0.9.2.md#child-workflows) and
|
|
70
|
+
[Workflow outputs](../v0.9.1-to-v0.9.2.md#workflow-outputs).
|
|
71
|
+
|
|
72
|
+
A workflow step's `with:` on a `uses: tasks/<ref>` target now **binds** the
|
|
73
|
+
task's declared `inputs:` — literal values or `{from: "steps.<id>.output…"}`
|
|
74
|
+
references resolved just before dispatch (the reference grammar also
|
|
75
|
+
accepts `{from: "params.<name>"}`, but a composing step's own document can
|
|
76
|
+
never declare `params:`, so that form is not reachable in this release) —
|
|
77
|
+
instead of being silently dropped. A `with:` on a task with no `inputs:`,
|
|
78
|
+
or on a `commands/`/`scripts/` target (never binding surfaces), is now
|
|
79
|
+
rejected at freeze rather than discarded. See
|
|
80
|
+
[`with:` on a task-composed step now binds — or rejects](../v0.9.1-to-v0.9.2.md#with-on-a-task-composed-step-now-binds--or-rejects).
|
|
81
|
+
|
|
82
|
+
Three recognized-but-limited constructs are removed outright in 0.9.2: the
|
|
83
|
+
GitHub Action `uses:` locator (`owner/repo[/path]@ref`) is no longer
|
|
84
|
+
recognized anywhere — it was always rejected before dispatch in every prior
|
|
85
|
+
release, so this deletes the recognition, not a working capability;
|
|
86
|
+
multi-job GitHub-shaped YAML is rejected at the source adapter instead of
|
|
87
|
+
parsing clean and being refused later in two different places — split a
|
|
88
|
+
multi-job document into single-job workflows composed with a child-workflow
|
|
89
|
+
step; and the second task scheduling syntax (`akm.schedule` / a task's
|
|
90
|
+
top-level `on:`) is gone along with task v3, leaving task source v4's
|
|
91
|
+
optional top-level `schedule:` as the one canonical form. See
|
|
92
|
+
[GitHub Action locators are no longer recognized anywhere](../v0.9.1-to-v0.9.2.md#github-action-locators-are-no-longer-recognized-anywhere)
|
|
93
|
+
and
|
|
94
|
+
[Multi-job YAML is rejected at the adapter boundary](../v0.9.1-to-v0.9.2.md#multi-job-yaml-is-rejected-at-the-adapter-boundary).
|
|
95
|
+
|
|
96
|
+
Two new read-only introspection verbs: `akm workflow plan <ref>`
|
|
97
|
+
(secret-free by construction) compiles, resolves, and freezes a workflow
|
|
98
|
+
without publishing a run, printing the canonical step graph, target/child
|
|
99
|
+
expansion, and input bindings; `akm task explain <ref>` prints a task's
|
|
100
|
+
resolved target, declared and supplied `inputs:` (secret-shaped values
|
|
101
|
+
redacted on a best-effort heuristic basis), and schedule bindings — its
|
|
102
|
+
default and `--format json` output are the same raw JSON. See
|
|
103
|
+
[New commands](../v0.9.1-to-v0.9.2.md#new-commands).
|
|
104
|
+
|
|
105
|
+
Task-source, workflow-source, and composition failures now report
|
|
106
|
+
phase-specific `UsageError` codes (`TASK_SOURCE_INVALID`,
|
|
107
|
+
`TASK_SCHEMA_VERSION_UNSUPPORTED`, `TARGET_REF_INVALID`,
|
|
108
|
+
`WORKFLOW_SOURCE_INVALID`, `COMPOSITION_INVALID`, `INPUT_BINDING_INVALID`,
|
|
109
|
+
`TASK_TARGET_UNSUPPORTED`, `WORKFLOW_OUTPUT_INVALID`,
|
|
110
|
+
`WORKFLOW_IR_VERSION_UNSUPPORTED`) instead of the generic
|
|
111
|
+
`INVALID_FLAG_VALUE`; exit codes are unchanged. See
|
|
112
|
+
[Diagnostics](../v0.9.1-to-v0.9.2.md#diagnostics).
|
|
37
113
|
|
|
38
114
|
`akm command run --dry-run` performs authorization and adapter lowering but
|
|
39
115
|
does not dispatch or materialize credentials. It writes no authored source or
|
|
@@ -7,8 +7,9 @@ live one level up in `docs/migration/`.
|
|
|
7
7
|
|
|
8
8
|
## Available notes
|
|
9
9
|
|
|
10
|
-
- [0.9.2](0.9.2.md) — task
|
|
11
|
-
command diagnostics, and strategy judgment
|
|
10
|
+
- [0.9.2](0.9.2.md) — task source v4 migration, workflow source IR v1 and
|
|
11
|
+
durable-v4-family `irVersion: 5`, command diagnostics, and strategy judgment
|
|
12
|
+
migration
|
|
12
13
|
|
|
13
14
|
## Adding notes for a new release
|
|
14
15
|
|
|
@@ -7,8 +7,8 @@ in place is not.
|
|
|
7
7
|
## What the upgrade preserves
|
|
8
8
|
|
|
9
9
|
- authored assets that you copy into a current bundle;
|
|
10
|
-
- task-v2 source files that the explicit task migrator can translate
|
|
11
|
-
guessing;
|
|
10
|
+
- task-v2 source files that the explicit task migrator can translate — through
|
|
11
|
+
task-v3 and on to task source v4 — without guessing;
|
|
12
12
|
- package-manager or standalone-binary updates through `akm upgrade`.
|
|
13
13
|
|
|
14
14
|
## What it does not preserve
|
|
@@ -17,7 +17,7 @@ in place is not.
|
|
|
17
17
|
- old `index.db`, `workflow.db`, task-history JSONL, or legacy lock/cache
|
|
18
18
|
layouts;
|
|
19
19
|
- old ref grammar or old workflow/task execution paths;
|
|
20
|
-
- in-flight
|
|
20
|
+
- in-flight workflow plans older than `irVersion: 5`.
|
|
21
21
|
|
|
22
22
|
Those formats are not compatibility inputs to the current runtime. Keep an
|
|
23
23
|
archive if you need historical inspection; do not place it in the live 0.9
|
|
@@ -70,16 +70,18 @@ for 0.8 databases.
|
|
|
70
70
|
|
|
71
71
|
### 4. Convert task-v2 sources explicitly
|
|
72
72
|
|
|
73
|
-
Normal task execution accepts task
|
|
73
|
+
Normal task execution accepts task source v4 only. Preview every translation:
|
|
74
74
|
|
|
75
75
|
```sh
|
|
76
76
|
akm migrate status
|
|
77
77
|
akm migrate apply --dry-run
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
Review each `changed`, `skipped`, and `blocked` entry. The migrator
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
Review each `changed`, `skipped`, and `blocked` entry. The migrator runs both
|
|
81
|
+
generations in one pass — task-v2 to task-v3, then task-v3 to task source
|
|
82
|
+
v4 — against the resulting files. It blocks ambiguous argv arrays or any
|
|
83
|
+
conversion whose execution meaning is not provable. Rewrite blocked files
|
|
84
|
+
manually as task source v4.
|
|
83
85
|
|
|
84
86
|
Apply only after the preview is correct:
|
|
85
87
|
|
|
@@ -106,9 +108,9 @@ existing scheduler entry.
|
|
|
106
108
|
## Workflow boundary
|
|
107
109
|
|
|
108
110
|
Current Markdown and GitHub-shaped YAML workflows compile to the same source
|
|
109
|
-
IR and freeze durable plan
|
|
110
|
-
plan. Do not copy an old workflow database
|
|
111
|
-
new runs from current authored sources.
|
|
111
|
+
IR and freeze the durable plan v4 family's executable `irVersion: 5` format.
|
|
112
|
+
That is the only executable stored plan. Do not copy an old workflow database
|
|
113
|
+
expecting old runs to resume; start new runs from current authored sources.
|
|
112
114
|
|
|
113
115
|
## Recovery
|
|
114
116
|
|
|
@@ -117,6 +119,6 @@ and restore the archived 0.8 installation with its matching 0.8 executable.
|
|
|
117
119
|
Do not mix old executable code with current state or current executable code
|
|
118
120
|
with old state.
|
|
119
121
|
|
|
120
|
-
For the task
|
|
122
|
+
For the task source v4 format and the narrower 0.9.1-to-0.9.2 transition, see
|
|
121
123
|
[Tasks](../reference/tasks.md) and
|
|
122
124
|
[Migrating from 0.9.1 to 0.9.2](v0.9.1-to-v0.9.2.md).
|
|
@@ -83,32 +83,39 @@ akm migrate status
|
|
|
83
83
|
akm migrate apply --dry-run
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
The migrator runs two generations in one pass — task-v2 to task-v3, then
|
|
87
|
+
task-v3 to task source v4 against the resulting files — and either
|
|
88
|
+
generation can block a file. A blocked file is intentionally unchanged.
|
|
89
|
+
Common causes at the v2-to-v3 stage are argv arrays, shell-sensitive command
|
|
90
|
+
forms, invalid YAML, unsupported fields, or a source that cannot be proven
|
|
91
|
+
writable; rewrite that file manually as task v3 and preview again. Common
|
|
92
|
+
causes at the v3-to-v4 stage are a GitHub Action `uses:` locator (no v4
|
|
93
|
+
equivalent) or a `with:` block on a non-command target (v4 wants declared
|
|
94
|
+
`inputs:` instead); rewrite that file manually as task source v4 and preview
|
|
95
|
+
again.
|
|
90
96
|
|
|
91
97
|
The task migrator does not repair config or databases.
|
|
92
98
|
|
|
93
99
|
## Task migration was interrupted
|
|
94
100
|
|
|
95
101
|
The migrator validates and backs up each changed task immediately before its
|
|
96
|
-
atomic replacement. Re-run the preview. Already-current
|
|
97
|
-
remaining v2 files are planned again from their current
|
|
98
|
-
generation fails closed instead of applying a stale
|
|
102
|
+
atomic replacement. Re-run the preview. Already-current task source v4 files
|
|
103
|
+
are skipped; remaining v2 and v3 files are planned again from their current
|
|
104
|
+
bytes. A changed input generation fails closed instead of applying a stale
|
|
105
|
+
plan.
|
|
99
106
|
|
|
100
107
|
Use the per-file backup only to reverse that file deliberately. Do not copy a
|
|
101
108
|
backup over a file while a task sync or scheduler process is running.
|
|
102
109
|
|
|
103
110
|
## A workflow will not resume
|
|
104
111
|
|
|
105
|
-
Only durable plan
|
|
106
|
-
decoded by a compatibility runtime.
|
|
107
|
-
or YAML workflow source.
|
|
112
|
+
Only the durable plan v4 family's `irVersion: 5` executes. Pre-`irVersion`-5
|
|
113
|
+
stored plans are rejected rather than decoded by a compatibility runtime.
|
|
114
|
+
Start a new run from the current Markdown or YAML workflow source.
|
|
108
115
|
|
|
109
|
-
For
|
|
110
|
-
run uses its frozen plan. A plan-hash or schema failure is
|
|
111
|
-
corruption and must fail closed.
|
|
116
|
+
For an `irVersion: 5` run, a missing or changed authored source is not a resume
|
|
117
|
+
blocker: the run uses its frozen plan. A plan-hash or schema failure is
|
|
118
|
+
durable-state corruption and must fail closed.
|
|
112
119
|
|
|
113
120
|
## A stale transaction journal is reported
|
|
114
121
|
|