akm-cli 0.9.31 → 0.10.261001-beta
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 +409 -0
- package/STABILITY.md +99 -57
- package/dist/api-node.mjs +20 -0
- package/dist/api.d.ts +23 -0
- package/dist/api.js +45 -0
- package/dist/assets/hints/cli-hints-full.md +15 -29
- package/dist/assets/hints/cli-hints-short.md +2 -2
- package/dist/assets/improve-strategies/default.json +3 -3
- package/dist/assets/prompts/consolidate-pair.md +9 -7
- package/dist/assets/stash-skeleton/README.md +1 -1
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
- package/dist/cli/shared.js +31 -48
- package/dist/cli/unknown-flags.js +6 -43
- package/dist/cli.js +8 -34
- package/dist/commands/agent/contribute-cli.js +1 -1
- package/dist/commands/completions.js +1 -2
- package/dist/commands/config-cli.js +5 -28
- package/dist/commands/env/env-cli.js +5 -5
- package/dist/commands/env/secret-cli.js +2 -2
- package/dist/commands/feedback-cli.js +75 -49
- package/dist/commands/health/checks.js +41 -16
- package/dist/commands/health/plugin-staleness.js +52 -22
- package/dist/commands/improve/autonomy-gate.js +5 -3
- package/dist/commands/improve/consolidate/chunking.js +3 -10
- package/dist/commands/improve/consolidate/continuity-check.js +4 -4
- package/dist/commands/improve/consolidate/pair-pass.js +29 -10
- package/dist/commands/improve/consolidate.js +10 -65
- package/dist/commands/improve/distill/lesson-update.js +91 -0
- package/dist/commands/improve/distill-guards.js +1 -43
- package/dist/commands/improve/distill.js +148 -21
- package/dist/commands/improve/eligibility.js +14 -1
- package/dist/commands/improve/extract-cli.js +1 -1
- package/dist/commands/improve/extract-prompt.js +17 -7
- package/dist/commands/improve/extract.js +5 -7
- package/dist/commands/improve/improve-cli.js +92 -106
- package/dist/commands/improve/improve-strategies.js +8 -12
- package/dist/commands/improve/improve.js +134 -52
- package/dist/commands/improve/loop-stages.js +18 -5
- package/dist/commands/improve/planner.js +0 -1
- package/dist/commands/improve/preparation.js +40 -99
- package/dist/commands/improve/proactive-maintenance.js +2 -2
- package/dist/commands/improve/reflect-noise.js +3 -55
- package/dist/commands/improve/reflect.js +29 -34
- package/dist/commands/improve/retrieval-queries.js +37 -0
- package/dist/commands/improve/retrieval-scope.js +2 -2
- package/dist/commands/improve/salience.js +2 -9
- package/dist/commands/improve/session-asset.js +4 -1
- package/dist/commands/improve/stage.js +23 -12
- package/dist/commands/lint/index.js +5 -20
- package/dist/commands/observability-cli.js +3 -9
- package/dist/commands/proposal/drain.js +43 -6
- package/dist/commands/proposal/proposal-cli.js +11 -31
- package/dist/commands/proposal/repository.js +20 -14
- package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -3
- package/dist/commands/read/knowledge.js +3 -3
- package/dist/commands/read/remember-cli.js +0 -13
- package/dist/commands/read/search-cli.js +29 -97
- package/dist/commands/read/search.js +0 -11
- package/dist/commands/read/show.js +0 -19
- package/dist/commands/sources/plugin-upgrade.js +164 -101
- package/dist/commands/sources/sources-cli.js +1 -15
- package/dist/commands/sources/stash-cli.js +6 -14
- package/dist/commands/tasks/tasks-cli.js +4 -115
- package/dist/commands/workflow/plan.js +11 -33
- package/dist/commands/workflow-cli.js +2 -7
- package/dist/core/adapter/adapter-ids.js +1 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
- package/dist/core/adapter/adapters/akm-adapter.js +9 -48
- package/dist/core/adapter/adapters/akm-lint.js +10 -26
- package/dist/core/adapter/adapters/akm-metadata.js +2 -72
- package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
- package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
- package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
- package/dist/core/adapter/recognize-match.js +3 -4
- package/dist/core/common.js +18 -2
- package/dist/core/config/config-schema.js +12 -15
- package/dist/core/config/config-types.js +6 -15
- package/dist/core/config/config-walker.js +6 -23
- package/dist/core/config/config.js +17 -80
- package/dist/core/config/engine-semantics.js +7 -3
- package/dist/core/config/schema/engines.js +7 -7
- package/dist/core/config/schema/improve-processes.js +10 -63
- package/dist/core/config/schema/improve.js +2 -21
- package/dist/core/config/schema/index-config.js +6 -39
- package/dist/core/env-secret-ref.js +2 -45
- package/dist/core/errors.js +1 -2
- package/dist/core/extra-params.js +2 -86
- package/dist/core/file-lock.js +2 -6
- package/dist/core/improve-result.js +13 -1
- package/dist/core/mutation-target.js +2 -2
- package/dist/core/paths.js +4 -0
- package/dist/core/recognition-util.js +4 -5
- package/dist/core/run-lock.js +1 -1
- package/dist/core/subprocess.js +49 -0
- package/dist/core/warn.js +21 -4
- package/dist/core/write-source.js +3 -3
- package/dist/execution/target-ref.js +1 -2
- package/dist/indexer/indexer.js +15 -6
- package/dist/indexer/passes/memory-inference.js +15 -6
- package/dist/indexer/search/db-search.js +49 -36
- package/dist/indexer/search/fts-query.js +0 -19
- package/dist/indexer/search/ranking.js +29 -1
- package/dist/indexer/usage/usage-events.js +21 -16
- package/dist/integrations/agent/engine-resolution.js +5 -2
- package/dist/integrations/agent/index.js +1 -1
- package/dist/integrations/agent/profiles.js +41 -98
- package/dist/integrations/agent/request-lowering.js +3 -3
- package/dist/integrations/harnesses/aider/index.js +5 -0
- package/dist/integrations/harnesses/amazonq/index.js +1 -0
- package/dist/integrations/harnesses/claude/config-import.js +2 -3
- package/dist/integrations/harnesses/claude/index.js +5 -0
- package/dist/integrations/harnesses/codex/index.js +1 -0
- package/dist/integrations/harnesses/copilot/index.js +1 -0
- package/dist/integrations/harnesses/gemini/index.js +1 -0
- package/dist/integrations/harnesses/index.js +18 -39
- package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
- package/dist/integrations/harnesses/opencode/config-import.js +121 -52
- package/dist/integrations/harnesses/opencode/index.js +22 -0
- package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
- package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
- package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
- package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
- package/dist/integrations/harnesses/opencode/session-log.js +104 -115
- package/dist/integrations/harnesses/opencode/version.js +98 -0
- package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
- package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
- package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +254 -0
- package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
- package/dist/integrations/harnesses/openhands/index.js +1 -0
- package/dist/integrations/harnesses/pi/index.js +1 -0
- package/dist/integrations/harnesses/shared.js +2 -0
- package/dist/integrations/harnesses/types.js +2 -0
- package/dist/llm/client.js +41 -11
- package/dist/output/cli-hints.js +1 -1
- package/dist/output/context.js +10 -19
- package/dist/output/format-exempt.js +5 -8
- package/dist/output/shapes/helpers.js +1 -22
- package/dist/output/shapes/passthrough.js +0 -1
- package/dist/output/shapes.js +3 -31
- package/dist/output/stdout.js +5 -1
- package/dist/output/text/command-format.js +6 -1
- package/dist/output/text/workflow-format.js +4 -22
- package/dist/scripts/akm-migrate-node.js +15745 -16711
- package/dist/scripts/akm-migrate.js +16318 -17280
- package/dist/setup/detect.js +10 -4
- package/dist/setup/harness-config-import.js +5 -14
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +12 -13
- package/dist/sources/providers/git-stash.js +94 -13
- package/dist/storage/repositories/index-utility-repository.js +2 -32
- package/dist/storage/repositories/index-vec-repository.js +4 -0
- package/dist/storage/repositories/task-history-repository.js +0 -5
- package/dist/storage/repositories/workflow-runs-repository.js +5 -15
- package/dist/tasks/embedded.js +2 -1
- package/dist/tasks/run/run-command-task.js +9 -1
- package/dist/tasks/run/run-workflow-task.js +4 -3
- package/dist/tasks/run/task-history.js +0 -2
- package/dist/tasks/run/task-log.js +38 -1
- package/dist/tasks/schedule-gates.js +39 -0
- package/dist/tasks/scheduler-binding.js +0 -16
- package/dist/tasks/scheduler-sync.js +3 -97
- package/dist/tasks/source/bounded-document.js +1 -1
- package/dist/tasks/source/task-source-v4.js +2 -12
- package/dist/tasks/task-run-reserved-flags.js +2 -31
- package/dist/workflows/authoring/authoring.js +6 -6
- package/dist/workflows/compile.js +8 -65
- package/dist/workflows/exec/child-workflow.js +22 -3
- package/dist/workflows/exec/native-executor.js +12 -147
- package/dist/workflows/exec/run-workflow.js +31 -103
- package/dist/workflows/exec/step-work.js +9 -178
- package/dist/workflows/exec/unit-dispatch.js +0 -10
- package/dist/workflows/freeze/environment.js +3 -44
- package/dist/workflows/freeze/freeze.js +8 -41
- package/dist/workflows/freeze/targets/child-workflow.js +27 -63
- package/dist/workflows/freeze/targets/command.js +2 -16
- package/dist/workflows/freeze/targets/shell.js +0 -2
- package/dist/workflows/freeze/task-bindings.js +2 -28
- package/dist/workflows/ir/params.js +12 -2
- package/dist/workflows/parser.js +82 -232
- package/dist/workflows/plan.js +1 -1
- package/dist/workflows/renderer.js +10 -19
- package/dist/workflows/runtime/run-plan.js +11 -53
- package/dist/workflows/runtime/runs.js +4 -27
- package/dist/workflows/source-files.js +12 -16
- package/dist/workflows/source-semantics.js +1 -93
- package/docs/README.md +1 -1
- package/docs/agents/README.md +3 -3
- package/docs/agents/agent-install.md +1 -1
- package/docs/architecture/0.10-process-rules.md +827 -0
- package/docs/architecture/adapters.md +17 -31
- package/docs/architecture/architecture.md +4 -5
- package/docs/architecture/improvement.md +115 -76
- package/docs/architecture/internals/improve-workflow.md +22 -16
- package/docs/architecture/internals/indexing.md +1 -1
- package/docs/architecture/internals/search.md +1 -2
- package/docs/architecture/internals/storage-locations.md +6 -6
- package/docs/architecture/persisted-data-compat.md +13 -4
- package/docs/architecture/specs/0.9.0-decisions.md +6 -2
- package/docs/architecture/specs/improve-collapse-churn-detector-design.md +2 -2
- package/docs/architecture/specs/workflow-format-unification.md +1 -6
- package/docs/architecture/testing/manual-testing-checklist.md +21 -30
- package/docs/architecture/testing/task-workflow-manual-tests.md +106 -203
- package/docs/architecture/testing/testing-workflow.md +1 -1
- package/docs/architecture/workflow-engine.md +5 -56
- package/docs/guides/author-workflows.md +39 -69
- package/docs/guides/bundles.md +3 -1
- package/docs/guides/capture-knowledge.md +1 -1
- package/docs/guides/claude-code-vs-akm-workflows.md +1 -2
- package/docs/guides/discover-and-load.md +4 -4
- package/docs/guides/getting-started.md +1 -1
- package/docs/guides/improve-the-library.md +10 -9
- package/docs/guides/recipes/headless-install.md +2 -2
- package/docs/guides/run-workflows.md +1 -1
- package/docs/guides/scheduling.md +9 -1
- package/docs/guides/use-with-any-agent.md +49 -4
- package/docs/integration/bundling-akm.md +7 -6
- package/docs/maintainers/curate-workmap.md +1 -2
- package/docs/maintainers/release-checklist.md +33 -1
- package/docs/migration/README.md +2 -0
- package/docs/migration/release-notes/0.10.0.md +201 -0
- package/docs/migration/release-notes/README.md +1 -0
- package/docs/migration/v0.9-to-v0.10.md +507 -0
- package/docs/posts/akm-command-tour.md +3 -3
- package/docs/product-surface.md +1 -1
- package/docs/reference/README.md +1 -0
- package/docs/reference/api.md +65 -0
- package/docs/reference/asset-types.md +3 -5
- package/docs/reference/bundle-types.md +2 -4
- package/docs/reference/cli.md +160 -188
- package/docs/reference/configuration.md +101 -20
- package/docs/reference/data-and-telemetry.md +2 -2
- package/docs/reference/env-and-secrets.md +2 -2
- package/docs/reference/supported-formats.md +3 -4
- package/docs/reference/tasks.md +12 -19
- package/docs/reference/website-sources.md +1 -1
- package/docs/reference/workflow-schema.md +89 -317
- package/docs/reference/workflows.md +20 -48
- package/package.json +12 -2
- package/schemas/akm-config.json +2 -243
- package/schemas/akm-task.json +2 -3
- package/schemas/akm-workflow.json +47 -84
- package/dist/assets/improve-strategies/catchup.json +0 -41
- package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
- package/dist/assets/improve-strategies/quick.json +0 -17
- package/dist/assets/improve-strategies/reflect-distill.json +0 -29
- package/dist/assets/improve-strategies/thorough.json +0 -49
- package/dist/assets/prompts/retrieval-relevance-judge.md +0 -6
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
- package/dist/cli/retired-commands.js +0 -118
- package/dist/commands/improve/retrieval-gate.js +0 -132
- package/dist/commands/tasks/validate.js +0 -176
- package/dist/core/config/legacy-source-shape-shim.js +0 -117
- package/dist/indexer/feedback/utility-policy.js +0 -75
- package/dist/integrations/harnesses/ids.js +0 -28
- package/dist/tasks/source/task-source-v3-frozen.js +0 -424
- package/dist/tasks/source/task-to-v4.js +0 -863
- package/dist/workflows/exec/worktree.js +0 -372
- package/dist/workflows/freeze/child-output-references.js +0 -83
- package/dist/workflows/freeze/identity.js +0 -22
- package/dist/workflows/freeze/targets/script.js +0 -50
- package/dist/workflows/freeze/targets/task.js +0 -124
- package/dist/workflows/github-yaml.js +0 -506
- package/dist/workflows/runtime/run-outputs.js +0 -80
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
5
|
* Scheduler reconciliation: compile the desired bindings from a bundle's
|
|
6
|
-
* task
|
|
6
|
+
* task sources, then diff them against the rows the native
|
|
7
7
|
* scheduler holds.
|
|
8
8
|
*
|
|
9
9
|
* `compileSchedulerSources` reads each source once. One source that fails
|
|
@@ -17,14 +17,9 @@ import fs from "node:fs";
|
|
|
17
17
|
import path from "node:path";
|
|
18
18
|
import { makeBundleRef, parseBundleRef } from "../core/asset/asset-ref.js";
|
|
19
19
|
import { compareCodePoints, toPosix } from "../core/common.js";
|
|
20
|
-
import { UsageError } from "../core/errors.js";
|
|
21
|
-
import { canonicalizeWorkflowName, WORKFLOW_EXTENSIONS } from "../core/recognition-util.js";
|
|
22
|
-
import { applyInputDefaults, validateInputs } from "../execution/input-contract.js";
|
|
23
|
-
import { checkWorkflowPlan, compileWorkflowSource } from "../workflows/compile.js";
|
|
24
|
-
import { WorkflowSourceCollisionError, WorkflowSourceNameError, workflowNameForSourcePath, } from "../workflows/source-files.js";
|
|
25
20
|
import { prepareTaskV3Execution } from "./prepare/prepare.js";
|
|
26
|
-
import {
|
|
27
|
-
import { compileTaskSchedulerBindings,
|
|
21
|
+
import { assertTaskScheduleCronValid, assertTaskScheduleInputsSatisfyContract } from "./schedule-gates.js";
|
|
22
|
+
import { compileTaskSchedulerBindings, schedulerBindingNativeId, schedulerNativeBindingId, } from "./scheduler-binding.js";
|
|
28
23
|
import { parseTaskSource } from "./source/parse-task-source.js";
|
|
29
24
|
import { projectTaskSourceV4 } from "./source/project-v4.js";
|
|
30
25
|
import { taskSourceErrorDetail } from "./source-v3.js";
|
|
@@ -37,7 +32,6 @@ export async function compileSchedulerSources(input) {
|
|
|
37
32
|
const desired = [];
|
|
38
33
|
const failures = [];
|
|
39
34
|
await compileTaskSources({ ...input, sourceRoot }, desired, failures);
|
|
40
|
-
compileWorkflowSources({ ...input, sourceRoot }, desired, failures);
|
|
41
35
|
return Object.freeze({
|
|
42
36
|
desired: Object.freeze(desired),
|
|
43
37
|
failures: Object.freeze(failures.sort((left, right) => compareCodePoints(left.path, right.path))),
|
|
@@ -107,67 +101,6 @@ function taskSourceFiles(sourceRoot, adapterId) {
|
|
|
107
101
|
return walkFiles(sourceRoot).filter((file) => file.endsWith(".yml"));
|
|
108
102
|
return [];
|
|
109
103
|
}
|
|
110
|
-
function compileWorkflowSources(input, desired, failures) {
|
|
111
|
-
if (input.adapterId !== "akm" && input.adapterId !== "akm-workflow")
|
|
112
|
-
return;
|
|
113
|
-
const root = input.adapterId === "akm" ? path.join(input.sourceRoot, "workflows") : input.sourceRoot;
|
|
114
|
-
const byName = new Map();
|
|
115
|
-
for (const file of walkFiles(root)) {
|
|
116
|
-
if (path.basename(file).toLowerCase() === "readme.md")
|
|
117
|
-
continue;
|
|
118
|
-
const authoredName = workflowNameForSourcePath(input.sourceRoot, input.adapterId, file);
|
|
119
|
-
if (authoredName === undefined)
|
|
120
|
-
continue;
|
|
121
|
-
const extension = path.posix.extname(authoredName).toLowerCase();
|
|
122
|
-
const stem = authoredName.slice(0, -extension.length).toLowerCase();
|
|
123
|
-
const nestedSuffix = WORKFLOW_EXTENSIONS.find((suffix) => stem.endsWith(suffix));
|
|
124
|
-
if (nestedSuffix) {
|
|
125
|
-
const relative = toPosix(path.relative(input.sourceRoot, file));
|
|
126
|
-
failures.push({ path: file, reason: new WorkflowSourceNameError(relative, nestedSuffix).message });
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
const canonicalName = canonicalizeWorkflowName(authoredName);
|
|
130
|
-
byName.set(canonicalName, [...(byName.get(canonicalName) ?? []), file]);
|
|
131
|
-
}
|
|
132
|
-
for (const [canonicalName, sources] of [...byName].sort(([left], [right]) => compareCodePoints(left, right))) {
|
|
133
|
-
const conceptId = input.adapterId === "akm" ? `workflows/${canonicalName}` : canonicalName;
|
|
134
|
-
const ref = sourceRef(input.bundleName, conceptId);
|
|
135
|
-
if (ref === undefined || (input.enabledRefs && !input.enabledRefs.has(ref)))
|
|
136
|
-
continue;
|
|
137
|
-
const file = sources[0];
|
|
138
|
-
try {
|
|
139
|
-
if (sources.length > 1) {
|
|
140
|
-
throw new WorkflowSourceCollisionError(conceptId, sources.map((source) => toPosix(path.relative(input.sourceRoot, source))));
|
|
141
|
-
}
|
|
142
|
-
const relative = toPosix(path.relative(input.sourceRoot, file));
|
|
143
|
-
const compiled = compileWorkflowSource(fs.readFileSync(file, "utf8"), {
|
|
144
|
-
path: relative,
|
|
145
|
-
workspaceRoot: input.sourceRoot,
|
|
146
|
-
});
|
|
147
|
-
if (!compiled.ok) {
|
|
148
|
-
throw new UsageError(compiled.errors
|
|
149
|
-
.map((error) => `${error.path}:${error.line ?? 1} [${error.code}] ${error.message}`)
|
|
150
|
-
.join("; "), "WORKFLOW_SOURCE_INVALID");
|
|
151
|
-
}
|
|
152
|
-
const planDraft = checkWorkflowPlan(compiled.plan);
|
|
153
|
-
if (!planDraft.ok) {
|
|
154
|
-
throw new UsageError(planDraft.errors.map((error) => `${relative}:${error.line} ${error.message}`).join("; "), "WORKFLOW_SOURCE_INVALID");
|
|
155
|
-
}
|
|
156
|
-
const schedules = (compiled.plan.schedules ?? []).map((schedule) => ({
|
|
157
|
-
cron: schedule.cron,
|
|
158
|
-
source: `${relative}:${schedule.line}`,
|
|
159
|
-
ordinal: schedule.ordinal,
|
|
160
|
-
}));
|
|
161
|
-
for (const binding of compileWorkflowSchedulerBindings({ qualifiedRef: ref, schedules })) {
|
|
162
|
-
parseSchedule(binding.cron, input.backend);
|
|
163
|
-
desired.push(binding);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
catch (cause) {
|
|
167
|
-
failures.push({ path: file, ref, reason: errorMessage(cause) });
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
104
|
/** A file whose name cannot form a ref (a `#` in it) cannot be enabled, so it is not this sync's. */
|
|
172
105
|
function sourceRef(bundleName, conceptId) {
|
|
173
106
|
try {
|
|
@@ -213,33 +146,6 @@ function statOrUndefined(file) {
|
|
|
213
146
|
return undefined;
|
|
214
147
|
}
|
|
215
148
|
}
|
|
216
|
-
/**
|
|
217
|
-
* Validate every v4 `schedule:` entry's `inputs` against the task's own
|
|
218
|
-
* declared contract with defaults applied — the exact set of values a
|
|
219
|
-
* compiled invocation delivers — so a violation is reported at sync rather
|
|
220
|
-
* than when the scheduler fires. Shared with `akm task validate`.
|
|
221
|
-
*/
|
|
222
|
-
export function assertTaskScheduleInputsSatisfyContract(v4, refLabel) {
|
|
223
|
-
const contract = v4.inputs ?? {};
|
|
224
|
-
for (const scheduleEntry of v4.schedule) {
|
|
225
|
-
const defaultedInputs = applyInputDefaults(contract, { ...scheduleEntry.inputs });
|
|
226
|
-
const errors = validateInputs(contract, defaultedInputs);
|
|
227
|
-
if (errors.length > 0) {
|
|
228
|
-
throw new UsageError(`Task ${JSON.stringify(refLabel)} schedule[${scheduleEntry.ordinal}].inputs does not satisfy ` +
|
|
229
|
-
`its declared inputs once defaults are applied: ${errors.join("; ")}`, "TASK_SOURCE_INVALID");
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Validate every v4 `schedule:` entry's `cron` against the active backend's
|
|
235
|
-
* dialect: cron is the most permissive of the three, so a task authored on
|
|
236
|
-
* Linux can carry an expression launchd/schtasks cannot translate. Shared
|
|
237
|
-
* with `akm task validate`.
|
|
238
|
-
*/
|
|
239
|
-
export function assertTaskScheduleCronValid(v4, backend) {
|
|
240
|
-
for (const scheduleEntry of v4.schedule)
|
|
241
|
-
parseSchedule(scheduleEntry.cron, backend);
|
|
242
|
-
}
|
|
243
149
|
export function installedRowNativeId(row) {
|
|
244
150
|
return row.nativeId ?? schedulerNativeBindingId(row.id);
|
|
245
151
|
}
|
|
@@ -380,7 +380,7 @@ export function assertBoundedTaskYamlDocument(document, options) {
|
|
|
380
380
|
* P4 (docs/plans/specs/p4-deletions-closeout.md §3.2) deleted task v3
|
|
381
381
|
* acceptance from `src` entirely — `parseTaskV3Yaml` and its `"task v3
|
|
382
382
|
* source"` label no longer exist here (the grammar survives only in the
|
|
383
|
-
* vendored, frozen `
|
|
383
|
+
* vendored, frozen `scripts/akm-migrate/migrate/task-source-v3-frozen.ts`
|
|
384
384
|
* copy, which does not call this function). The two live `src` callers
|
|
385
385
|
* today: `parseTaskSourceV4`'s standalone YAML-string entry
|
|
386
386
|
* (`task-source-v4.ts:790`) passes `sourceLabel: "task source v4"`; the
|
|
@@ -44,7 +44,7 @@ import { classifyTargetRef } from "../../execution/target-ref.js";
|
|
|
44
44
|
import { detectSecretShapedParams } from "../../workflows/exec/param-secrets.js";
|
|
45
45
|
import { WORKFLOW_ENV_VAR_NAME_PATTERN, WORKFLOW_MAX_SCHEMA_BYTES } from "../../workflows/resource-limits.js";
|
|
46
46
|
import { TASK_V3_HOST_SHELLS, TASK_V3_MAX_SCHEDULES } from "../source-v3.js";
|
|
47
|
-
import { TASK_RUN_RESERVED_FLAG_NAMES
|
|
47
|
+
import { TASK_RUN_RESERVED_FLAG_NAMES } from "../task-run-reserved-flags.js";
|
|
48
48
|
import { asRecord, checkKeys, cloneBoundedJson, noGithubExpression, own, parseEnvironment, parseStringArray, presentJsonValue, readBoundedTaskSourceYaml, sourceError, stringField, TASK_V3_MAX_REDACT_NAMES, utf8Bytes, validateWorkingDirectory, } from "./bounded-document.js";
|
|
49
49
|
// ── Closed constants (D1, D2-N3, D2-N7) ─────────────────────────────────────
|
|
50
50
|
export const TASK_SOURCE_V4_VERSION = 4;
|
|
@@ -391,18 +391,8 @@ function parseInputDeclarations(value, ctx) {
|
|
|
391
391
|
// checked against this same contract below, so a banned name can never
|
|
392
392
|
// reach compileTaskSchedulerBindings's invocation tail either) — see
|
|
393
393
|
// ../task-run-reserved-flags.ts's own header.
|
|
394
|
-
//
|
|
395
|
-
// 0.9.2 review round 2: `target` joins that set from the CLI's DIAGNOSTIC
|
|
396
|
-
// side rather than its declared-arg side. `rejectRetiredTaskTargetFlag`
|
|
397
|
-
// (../../commands/tasks/tasks-cli.ts) throws the 0.9 `--target` ->
|
|
398
|
-
// `--bundle` rename hint for every spelling of the name, before
|
|
399
|
-
// parseTaskInputFlags scans argv at all, so an input declared under that
|
|
400
|
-
// name could never be supplied either — it is the same unusable
|
|
401
|
-
// declaration, reached by a different route (TASK_RUN_SELF_DIAGNOSED_FLAGS).
|
|
402
394
|
if (TASK_RUN_RESERVED_FLAG_NAMES.has(name)) {
|
|
403
|
-
sourceError(ctx, ["inputs", name],
|
|
404
|
-
? `collides with the retired \`akm task --${name}\` spelling, which every task subcommand still rejects with a rename hint, so no --${name} flag can ever reach this input; declare the input under a different name.`
|
|
405
|
-
: `collides with akm task run's own --${name} flag; declare the input under a different name.`);
|
|
395
|
+
sourceError(ctx, ["inputs", name], `collides with akm task run's own --${name} flag; declare the input under a different name.`);
|
|
406
396
|
}
|
|
407
397
|
result[name] = parseInputDeclaration(name, input[name], ctx);
|
|
408
398
|
}
|
|
@@ -26,9 +26,7 @@
|
|
|
26
26
|
* `src/commands/tasks/tasks-cli.ts` re-exports `TASK_RUN_VALUE_FLAGS` /
|
|
27
27
|
* `TASK_RUN_BOOLEAN_FLAGS` from here unchanged, so this module is the single
|
|
28
28
|
* source of truth both the CLI's own argv scanner and the source parser read
|
|
29
|
-
* — the two can never drift apart.
|
|
30
|
-
* covers the third category the scanner sets cannot express: a name the CLI
|
|
31
|
-
* claims by REJECTING it rather than by declaring it. This file imports
|
|
29
|
+
* — the two can never drift apart. This file imports
|
|
32
30
|
* nothing, and nothing it
|
|
33
31
|
* exports depends on IO, config, or any other `src/tasks/**` module, so it
|
|
34
32
|
* can be imported from either side of that boundary without participating in
|
|
@@ -45,35 +43,8 @@ export const TASK_RUN_BOOLEAN_FLAGS = [
|
|
|
45
43
|
"no-quiet",
|
|
46
44
|
"no-verbose",
|
|
47
45
|
];
|
|
48
|
-
/**
|
|
49
|
-
* Flag names `akm task` claims WITHOUT declaring them as citty args, so they
|
|
50
|
-
* appear in neither list above and must be reserved separately.
|
|
51
|
-
*
|
|
52
|
-
* `target` is the only member: the 0.9 rename of `akm task --target` to
|
|
53
|
-
* `--bundle` (S8.4) is self-diagnosed rather than merely dropped —
|
|
54
|
-
* `rejectRetiredTaskTargetFlag` (`../commands/tasks/tasks-cli.ts`) throws the
|
|
55
|
-
* rename hint for a `--target` in ANY spelling, bare or `--target=<value>`,
|
|
56
|
-
* and the generic pre-dispatch gate exempts the name on every `task`
|
|
57
|
-
* subcommand precisely so that handler can answer (`../cli/unknown-flags.ts`'s
|
|
58
|
-
* `SELF_DIAGNOSED_FLAGS`). That rejection runs before `parseTaskInputFlags`
|
|
59
|
-
* ever scans argv, so a declared input named `target` is unreachable through
|
|
60
|
-
* every spelling of its own flag — the exact value-misrouting hole the union
|
|
61
|
-
* below exists to close, just reached from the CLI's diagnostic side instead
|
|
62
|
-
* of from its declared-arg side (0.9.2 review round 2). Rejecting the
|
|
63
|
-
* DECLARATION keeps the rename hint intact for everyone typing the retired
|
|
64
|
-
* spelling while making the unusable declaration impossible to author, rather
|
|
65
|
-
* than trading one silent failure for another.
|
|
66
|
-
*
|
|
67
|
-
* It deliberately stays OUT of `TASK_RUN_VALUE_FLAGS` /
|
|
68
|
-
* `TASK_RUN_BOOLEAN_FLAGS`: those two are `parseTaskInputFlags`' own scanner
|
|
69
|
-
* sets (a value flag makes the scanner swallow the following token), and
|
|
70
|
-
* `--target` must keep reaching the rename diagnostic rather than being
|
|
71
|
-
* silently consumed as one of `akm task run`'s own flags.
|
|
72
|
-
*/
|
|
73
|
-
export const TASK_RUN_SELF_DIAGNOSED_FLAGS = ["target"];
|
|
74
|
-
/** The union of all three lists above, for a single membership check against a candidate input name. */
|
|
46
|
+
/** The union of the two lists above, for a single membership check against a candidate input name. */
|
|
75
47
|
export const TASK_RUN_RESERVED_FLAG_NAMES = new Set([
|
|
76
48
|
...TASK_RUN_VALUE_FLAGS,
|
|
77
49
|
...TASK_RUN_BOOLEAN_FLAGS,
|
|
78
|
-
...TASK_RUN_SELF_DIAGNOSED_FLAGS,
|
|
79
50
|
]);
|
|
@@ -41,13 +41,13 @@ function validateWorkflowContent(content, sourcePath) {
|
|
|
41
41
|
throw new UsageError(formatWorkflowErrors(sourcePath, compiled.errors));
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
44
|
+
/** Workflows are Markdown; `akm workflow create` rejects a YAML suffix. */
|
|
45
45
|
const YAML_SUFFIX_RE = /\.ya?ml$/i;
|
|
46
46
|
export function assertWorkflowMarkdownName(name) {
|
|
47
47
|
if (!YAML_SUFFIX_RE.test(name.trim()))
|
|
48
48
|
return;
|
|
49
49
|
throw new UsageError(`akm workflow create is markdown-only: it emits Markdown and cannot create "${name}". ` +
|
|
50
|
-
`Use a plain name (no ".yaml"/".yml" suffix)
|
|
50
|
+
`Use a plain name (no ".yaml"/".yml" suffix).`);
|
|
51
51
|
}
|
|
52
52
|
// 0.9.2 review round 2 (P4 sweep criterion-21 caveat, spec
|
|
53
53
|
// docs/plans/specs/p4-deletions-closeout.md §4.1 row B-49): this return's
|
|
@@ -75,7 +75,7 @@ export function createWorkflowAsset(input) {
|
|
|
75
75
|
path.isAbsolute(relativeAssetPath)) {
|
|
76
76
|
throw new UsageError(`Resolved workflow path escapes the bundle: "${normalizedName}"`, "PATH_ESCAPE_VIOLATION");
|
|
77
77
|
}
|
|
78
|
-
// A
|
|
78
|
+
// A `.md` file whose canonical name matches already owns this
|
|
79
79
|
// ref. Case variants (`upper.MD` vs `upper.md`) may also name one physical
|
|
80
80
|
// file on a case-insensitive filesystem, so writing the Markdown create
|
|
81
81
|
// target would silently clobber or shadow the existing asset.
|
|
@@ -160,9 +160,9 @@ export function formatWorkflowErrors(path, errors) {
|
|
|
160
160
|
}
|
|
161
161
|
/**
|
|
162
162
|
* Every file under `typeRoot` whose canonical workflow name equals
|
|
163
|
-
* `normalizedName`.
|
|
164
|
-
*
|
|
165
|
-
*
|
|
163
|
+
* `normalizedName`. `.md` extension matching is case-INSENSITIVE, so case
|
|
164
|
+
* variants are returned for the create path to refuse rather than silently
|
|
165
|
+
* clobber or shadow them.
|
|
166
166
|
*/
|
|
167
167
|
function findExistingWorkflowPaths(typeRoot, normalizedName) {
|
|
168
168
|
const parent = path.join(typeRoot, path.dirname(normalizedName));
|
|
@@ -3,43 +3,26 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
5
|
* The workflow compiler's front door. `.md` goes through the Markdown grammar
|
|
6
|
-
* (`parser.ts`),
|
|
7
|
-
* (`github-yaml.ts`); both produce a {@link WorkflowPlan} directly.
|
|
6
|
+
* (`parser.ts`), which produces a {@link WorkflowPlan} directly.
|
|
8
7
|
*
|
|
9
8
|
* {@link checkWorkflowPlan} is the one cross-step pass the grammars do not
|
|
10
|
-
* run: every `steps.<id>` reference must name an earlier step
|
|
11
|
-
* name any step), `inputs:` never name a param, and two non-fatal advisories.
|
|
9
|
+
* run: every `steps.<id>` reference must name an earlier step, `inputs:` never name a param, and two non-fatal advisories.
|
|
12
10
|
*/
|
|
13
11
|
import path from "node:path";
|
|
14
|
-
import { parseBuiltinCommandAction } from "../commands/command/builtin-action.js";
|
|
15
|
-
import { PORTABLE_ARGUMENTS_PLACEHOLDER } from "../commands/command/portable-template.js";
|
|
16
|
-
import { parseGithubWorkflowSource, WorkflowSourceFailure } from "./github-yaml.js";
|
|
17
12
|
import { parseWorkflow } from "./parser.js";
|
|
18
13
|
import { formatReference, parseReference } from "./program/expressions.js";
|
|
19
14
|
import { canonicalizeWorkflowWorkingDirectory, WorkflowSourceSemanticError } from "./source-semantics.js";
|
|
20
|
-
export { looksLikeGithubWorkflowSource } from "./github-yaml.js";
|
|
21
15
|
/** Compile by authoritative source extension. */
|
|
22
16
|
export function compileWorkflowSource(source, options) {
|
|
23
17
|
const extension = path.extname(options.path).toLowerCase();
|
|
24
18
|
const title = options.title ?? path.basename(options.path, path.extname(options.path));
|
|
25
|
-
if (extension === ".yml") {
|
|
26
|
-
try {
|
|
27
|
-
return { ok: true, plan: parseGithubWorkflowSource(source, { ...options, title }) };
|
|
28
|
-
}
|
|
29
|
-
catch (cause) {
|
|
30
|
-
if (cause instanceof WorkflowSourceFailure)
|
|
31
|
-
return { ok: false, errors: [cause.error] };
|
|
32
|
-
const message = cause instanceof Error ? cause.message : String(cause);
|
|
33
|
-
return { ok: false, errors: [{ code: "invalid-workflow-source", message, path: options.path, line: 1 }] };
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
19
|
if (extension !== ".md") {
|
|
37
20
|
return {
|
|
38
21
|
ok: false,
|
|
39
22
|
errors: [
|
|
40
23
|
{
|
|
41
24
|
code: "unsupported-workflow-extension",
|
|
42
|
-
message: `Workflow source ${options.path} must use .md
|
|
25
|
+
message: `Workflow source ${options.path} must use .md.`,
|
|
43
26
|
path: options.path,
|
|
44
27
|
line: 1,
|
|
45
28
|
},
|
|
@@ -74,8 +57,7 @@ export function compileWorkflowSource(source, options) {
|
|
|
74
57
|
}
|
|
75
58
|
/**
|
|
76
59
|
* The display text a step contributes to `show`, search hints, and the run
|
|
77
|
-
* spine: its authored prose, else what its target does.
|
|
78
|
-
* step with no section.
|
|
60
|
+
* spine: its authored prose, else what its target does.
|
|
79
61
|
*/
|
|
80
62
|
export function workflowStepInstructions(step) {
|
|
81
63
|
const spec = step.spec;
|
|
@@ -83,25 +65,9 @@ export function workflowStepInstructions(step) {
|
|
|
83
65
|
return "";
|
|
84
66
|
if (spec.instructions !== undefined)
|
|
85
67
|
return spec.instructions;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return `Invoke stored command ${action.ref}${action.arguments === undefined ? "" : " with arguments"}.`;
|
|
90
|
-
}
|
|
91
|
-
if (spec.commandMode === "literal")
|
|
92
|
-
return action.content;
|
|
93
|
-
return action.content.split(PORTABLE_ARGUMENTS_PLACEHOLDER).join(action.arguments ?? "");
|
|
94
|
-
}
|
|
95
|
-
if (spec.uses !== undefined)
|
|
96
|
-
return `Invoke local target ${spec.uses}.`;
|
|
97
|
-
return "";
|
|
98
|
-
}
|
|
99
|
-
/** A route step's deterministic one-line description of its branch table. */
|
|
100
|
-
export function routeDescription(route) {
|
|
101
|
-
const branches = Object.entries(route.when).map(([match, stepId]) => `"${match}" -> ${stepId}`);
|
|
102
|
-
if (route.defaultStepId !== undefined)
|
|
103
|
-
branches.push(`default -> ${route.defaultStepId}`);
|
|
104
|
-
return `Route on ${route.input}: ${branches.join(", ")}.`;
|
|
68
|
+
// A prose step is `akm/command` with its body as literal content.
|
|
69
|
+
const content = spec.with?.content;
|
|
70
|
+
return spec.uses === "akm/command" && typeof content === "string" ? content : "";
|
|
105
71
|
}
|
|
106
72
|
/** Cross-step reference validation plus the non-fatal advisories. Pure. */
|
|
107
73
|
export function checkWorkflowPlan(plan) {
|
|
@@ -136,40 +102,18 @@ export function checkWorkflowPlan(plan) {
|
|
|
136
102
|
const line = step.spec?.source.start ?? 1;
|
|
137
103
|
if (step.spec?.map)
|
|
138
104
|
check(step.spec.map.over, line, `Step "${step.stepId}" map.over`, true);
|
|
139
|
-
if (step.route)
|
|
140
|
-
check(step.route.input, line, `Step "${step.stepId}" route.input`, true);
|
|
141
105
|
for (const [index, reference] of (step.spec?.inputs ?? []).entries()) {
|
|
142
106
|
check(reference, line, `Step "${step.stepId}" inputs[${index}]`, false);
|
|
143
107
|
}
|
|
144
108
|
earlierStepIds.add(step.stepId);
|
|
145
109
|
}
|
|
146
|
-
// Outputs resolve at run completion, so they may name any declared step.
|
|
147
|
-
for (const [name, declaration] of Object.entries(plan.outputs ?? {})) {
|
|
148
|
-
const parsed = parseReference(declaration.from);
|
|
149
|
-
const label = `Output "${name}" from`;
|
|
150
|
-
if (!parsed.ok)
|
|
151
|
-
errors.push({ line: 1, message: `${label}: ${parsed.message}` });
|
|
152
|
-
else if (parsed.expr.kind === "param") {
|
|
153
|
-
errors.push({
|
|
154
|
-
line: 1,
|
|
155
|
-
message: `${label}: "${formatReference(parsed.expr)}" names a param, not a step output — an output projects a ` +
|
|
156
|
-
`STEP artifact, never a param. "outputs:" only names step outputs (steps.<id>.output...).`,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
else if (!allStepIds.has(parsed.expr.stepId)) {
|
|
160
|
-
errors.push({
|
|
161
|
-
line: 1,
|
|
162
|
-
message: `${label}: "${formatReference(parsed.expr)}" cannot be resolved — "${parsed.expr.stepId}" is not a step in this workflow.`,
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
110
|
if (errors.length > 0)
|
|
167
111
|
return { ok: false, errors };
|
|
168
112
|
return { ok: true, warnings: workflowWarnings(plan) };
|
|
169
113
|
}
|
|
170
114
|
/**
|
|
171
115
|
* Advisories that never fail compilation or change the plan:
|
|
172
|
-
* A. a `params.<name>` reference (in `map.over
|
|
116
|
+
* A. a `params.<name>` reference (in `map.over`) to a param the
|
|
173
117
|
* document's `params:` block does not declare — a likely typo;
|
|
174
118
|
* B. `gate.max_loops` above 1 on an exec step, which is judged but never
|
|
175
119
|
* looped (a frozen argv cannot read the judge's feedback).
|
|
@@ -205,7 +149,6 @@ function workflowWarnings(plan) {
|
|
|
205
149
|
});
|
|
206
150
|
};
|
|
207
151
|
scan(step.spec?.map?.over, `Step "${step.stepId}" map.over`);
|
|
208
|
-
scan(step.route?.input, `Step "${step.stepId}" route.input`);
|
|
209
152
|
}
|
|
210
153
|
return warnings;
|
|
211
154
|
}
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* `with:` bindings against the child's `params:`; (2) derive the deterministic
|
|
9
9
|
* invocation key; (3) publish the child run idempotently; (4) drive it with
|
|
10
10
|
* the same engine as a top-level run unless it is already `blocked`/`failed`;
|
|
11
|
-
* (5) map the child's final status onto this unit's outcome
|
|
11
|
+
* (5) map the child's final status onto this unit's outcome; a completed
|
|
12
|
+
* child returns the output of its last step.
|
|
12
13
|
*
|
|
13
14
|
* `runWorkflowSteps` is reached through a lazy dynamic import: a static one
|
|
14
15
|
* would close the cycle native-executor -> child-workflow -> run-workflow ->
|
|
@@ -19,7 +20,6 @@ import { TransientError } from "../../core/errors.js";
|
|
|
19
20
|
import { withWorkflowRunsRepo } from "../../storage/repositories/workflow-runs-repository.js";
|
|
20
21
|
import { validateWorkflowParams } from "../ir/params.js";
|
|
21
22
|
import { canonicalPlanJson } from "../ir/plan-hash.js";
|
|
22
|
-
import { workflowRunExportedResult } from "../runtime/run-outputs.js";
|
|
23
23
|
import { frozenStepRows } from "../runtime/run-plan.js";
|
|
24
24
|
import { computeChildInvocationKey } from "./child-invocation.js";
|
|
25
25
|
/** The real engine, via a dynamic import (see the module doc). The caller re-reads the child row afterward. */
|
|
@@ -27,6 +27,25 @@ async function driveWithRealEngine(options) {
|
|
|
27
27
|
const { runWorkflowSteps } = await import("./run-workflow.js");
|
|
28
28
|
await runWorkflowSteps(options);
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* A completed child's result: the artifact of its last step (a step with no
|
|
32
|
+
* recorded evidence yields `null`). Read from the persisted step rows, so a
|
|
33
|
+
* resumed parent sees the same value as the live one.
|
|
34
|
+
*/
|
|
35
|
+
async function childFinalOutput(childRunId) {
|
|
36
|
+
const steps = await withWorkflowRunsRepo((repo) => repo.getStepsForRun(childRunId));
|
|
37
|
+
const evidenceJson = steps[steps.length - 1]?.evidence_json;
|
|
38
|
+
if (!evidenceJson)
|
|
39
|
+
return null;
|
|
40
|
+
try {
|
|
41
|
+
const evidence = JSON.parse(evidenceJson);
|
|
42
|
+
// Same projection as `steps.<id>.output` (step-work.ts `projectStepOutput`).
|
|
43
|
+
return Object.hasOwn(evidence, "output") ? evidence.output : evidence;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
30
49
|
function errorMessage(err) {
|
|
31
50
|
return err instanceof Error ? err.message : String(err);
|
|
32
51
|
}
|
|
@@ -218,7 +237,7 @@ export async function driveChildWorkflowUnit(input) {
|
|
|
218
237
|
return {
|
|
219
238
|
unitId: request.unitId,
|
|
220
239
|
ok: true,
|
|
221
|
-
result:
|
|
240
|
+
result: await childFinalOutput(finalRow.id),
|
|
222
241
|
childRun: childRunSummary,
|
|
223
242
|
};
|
|
224
243
|
case "failed": {
|