akm-cli 0.9.17-alpha.3 → 0.9.17-alpha.4
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 +731 -0
- package/dist/akm +94 -196
- package/dist/cli/shared.js +6 -2
- package/dist/cli.js +22 -9
- package/dist/commands/agent/agent-dispatch.js +1 -1
- package/dist/commands/command/command-execution.js +24 -62
- package/dist/commands/feedback-cli.js +0 -1
- package/dist/commands/health/accept-rate.js +2 -2
- package/dist/commands/health/checks.js +30 -75
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +0 -38
- package/dist/commands/health/improve-metrics.js +123 -562
- package/dist/commands/health/plugin-staleness.js +53 -3
- package/dist/commands/health/renderers.js +12 -4
- package/dist/commands/health/report-view-model.js +11 -106
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -73
- package/dist/commands/health.js +122 -143
- package/dist/commands/improve/consolidate/chunking.js +25 -100
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +538 -1075
- package/dist/commands/improve/content-hash.js +16 -24
- package/dist/commands/improve/distill/content-repair.js +18 -100
- package/dist/commands/improve/distill-guards.js +20 -81
- package/dist/commands/improve/distill-promotion-policy.js +23 -243
- package/dist/commands/improve/distill.js +608 -1075
- package/dist/commands/improve/eligibility.js +126 -400
- package/dist/commands/improve/execution.js +3 -5
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +29 -166
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +12 -7
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +443 -1063
- package/dist/commands/improve/ledger.js +114 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +459 -1172
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +14 -118
- package/dist/commands/improve/memory/memory-improve.js +4 -3
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -10
- package/dist/commands/improve/preparation.js +851 -2339
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +621 -1367
- package/dist/commands/improve/salience.js +46 -232
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +323 -0
- package/dist/commands/proposal/drain.js +251 -644
- package/dist/commands/proposal/proposal-cli.js +3 -18
- package/dist/commands/proposal/proposal-types.js +20 -41
- package/dist/commands/proposal/proposal.js +1 -2
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +502 -1487
- package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
- package/dist/commands/proposal/validators/proposal-validators.js +1 -1
- package/dist/commands/proposal/validators/proposals.js +13 -89
- package/dist/commands/read/curate.js +63 -413
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +2 -13
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +7 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +2 -11
- package/dist/commands/sources/installed-stashes.js +197 -746
- package/dist/commands/sources/schema-repair.js +98 -129
- package/dist/commands/sources/source-add.js +62 -12
- package/dist/commands/sources/stash-cli.js +1 -1
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +9 -8
- package/dist/commands/tasks/tasks.js +326 -930
- package/dist/commands/tasks/validate.js +42 -21
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +0 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +11 -12
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +291 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +1 -33
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +163 -68
- package/dist/core/config/legacy-source-shape-shim.js +38 -9
- package/dist/core/config/schema/embedding.js +20 -5
- package/dist/core/config/schema/engines.js +5 -0
- package/dist/core/config/schema/execution.js +1 -1
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/improve-processes.js +21 -95
- package/dist/core/config/schema/improve.js +4 -42
- package/dist/core/config/schema/scheduler.js +12 -12
- package/dist/core/config/schema/search.js +6 -22
- package/dist/core/env-secret-ref.js +0 -1
- package/dist/core/errors.js +8 -9
- package/dist/core/file-lock.js +76 -173
- package/dist/core/logs-db.js +2 -2
- package/dist/core/paths.js +0 -27
- package/dist/core/redaction.js +109 -2
- package/dist/core/run-lock.js +2 -5
- package/dist/core/spawn-env.js +1 -1
- package/dist/core/state/migrations.js +108 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +293 -1012
- package/dist/execution/input-contract.js +1 -1
- package/dist/execution/resolved-request.js +135 -689
- package/dist/execution/source.js +63 -257
- package/dist/execution/target-ref.js +1 -1
- package/dist/indexer/bundle-identity-guard.js +2 -2
- package/dist/indexer/db/graph-db.js +106 -46
- package/dist/indexer/ensure-index.js +44 -85
- package/dist/indexer/graph/graph-extraction.js +340 -562
- package/dist/indexer/graph/graph-related.js +130 -0
- package/dist/indexer/index-rebuild-lock.js +3 -11
- package/dist/indexer/index-writer-lock.js +8 -17
- package/dist/indexer/index-written-assets.js +139 -151
- package/dist/indexer/indexer.js +524 -846
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +81 -90
- package/dist/indexer/passes/metadata.js +132 -200
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +1 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +181 -590
- package/dist/indexer/search/fts-query.js +30 -41
- package/dist/indexer/search/ranking.js +28 -154
- package/dist/indexer/search/search-attribution.js +12 -32
- package/dist/indexer/search/search-fields.js +11 -15
- package/dist/indexer/search/search-hit-enrichers.js +54 -85
- package/dist/indexer/search/search-source.js +1 -4
- package/dist/indexer/usage/usage-events.js +2 -7
- package/dist/integrations/agent/engine-fallback.js +23 -40
- package/dist/integrations/agent/engine-resolution.js +93 -183
- package/dist/integrations/agent/execution.js +507 -0
- package/dist/integrations/agent/model-map.js +28 -156
- package/dist/integrations/agent/request-lowering.js +66 -141
- package/dist/integrations/agent/runner-dispatch.js +143 -321
- package/dist/integrations/agent/runner.js +54 -14
- package/dist/integrations/lockfile.js +53 -101
- package/dist/llm/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +10 -15
- package/dist/llm/graph-extract.js +3 -12
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/metadata-enhance.js +1 -2
- package/dist/llm/structured-call.js +5 -24
- package/dist/output/generic-render.js +23 -11
- package/dist/output/html-render.js +13 -10
- package/dist/output/render-registry.js +3 -32
- package/dist/output/shapes/helpers.js +2 -34
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +60 -23
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +1 -2
- package/dist/output/text/workflow-format.js +0 -32
- package/dist/output/text.js +2 -0
- package/dist/registry/factory.js +4 -19
- package/dist/registry/network.js +66 -220
- package/dist/registry/providers/index.js +0 -2
- package/dist/registry/providers/skills-sh.js +3 -14
- package/dist/registry/providers/static-index.js +24 -26
- package/dist/registry/resolve.js +55 -131
- package/dist/scripts/akm-migrate-node.js +43937 -93313
- package/dist/scripts/akm-migrate.js +43697 -93071
- package/dist/setup/registry-stash-loader.js +4 -13
- package/dist/setup/semantic-assets.js +3 -44
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +25 -15
- package/dist/sources/provider-factory.js +17 -18
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +7 -1
- package/dist/sources/providers/git-provider.js +0 -3
- package/dist/sources/providers/git-stash.js +0 -17
- package/dist/sources/providers/npm.js +2 -4
- package/dist/sources/providers/provider-utils.js +5 -10
- package/dist/sources/providers/website.js +0 -2
- package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
- package/dist/sources/website-url.js +2 -2
- package/dist/storage/database.js +9 -35
- package/dist/storage/repositories/improve-ledger-repository.js +168 -0
- package/dist/storage/repositories/index-connection.js +34 -70
- package/dist/storage/repositories/index-entries-repository.js +69 -111
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +83 -269
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +192 -220
- package/dist/storage/repositories/index-utility-repository.js +8 -29
- package/dist/storage/repositories/index-vec-repository.js +133 -414
- package/dist/storage/repositories/outcome-repository.js +2 -1
- package/dist/storage/repositories/proposals-repository.js +35 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- package/dist/storage/repositories/task-history-repository.js +26 -4
- package/dist/storage/repositories/workflow-runs-repository.js +53 -244
- package/dist/storage/sqlite-migrations.js +136 -0
- package/dist/storage/sqlite-pragmas.js +11 -9
- package/dist/storage/sqlite-transaction.js +170 -0
- package/dist/storage/state-db-integrity.js +34 -27
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +129 -277
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +125 -745
- package/dist/tasks/backends/schtasks.js +101 -620
- package/dist/tasks/prepare/prepare-support.js +5 -15
- package/dist/tasks/prepare/prepare.js +0 -2
- package/dist/tasks/resolve-akm-bin.js +20 -79
- package/dist/tasks/run/attempt-lifecycle.js +0 -1
- package/dist/tasks/scheduler-binding.js +18 -238
- package/dist/tasks/scheduler-invocation.js +52 -52
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +361 -751
- package/dist/tasks/source/parse-task-source.js +160 -10
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +2 -2
- package/dist/workflows/authoring/authoring.js +3 -12
- package/dist/workflows/compile.js +211 -0
- package/dist/workflows/concurrency-policy.js +13 -74
- package/dist/workflows/exec/child-invocation.js +3 -17
- package/dist/workflows/exec/child-workflow.js +32 -141
- package/dist/workflows/exec/dispatch-redaction.js +13 -53
- package/dist/workflows/exec/environment.js +98 -0
- package/dist/workflows/exec/exec-unit.js +33 -140
- package/dist/workflows/exec/frozen-judge.js +7 -59
- package/dist/workflows/exec/native-executor.js +82 -341
- package/dist/workflows/exec/param-secrets.js +29 -47
- package/dist/workflows/exec/run-workflow.js +154 -387
- package/dist/workflows/exec/scheduler.js +9 -36
- package/dist/workflows/exec/step-work.js +127 -430
- package/dist/workflows/exec/unit-dispatch.js +11 -63
- package/dist/workflows/exec/unit-writer.js +8 -52
- package/dist/workflows/exec/worktree.js +39 -273
- package/dist/workflows/freeze/child-output-references.js +4 -15
- package/dist/workflows/freeze/environment.js +99 -92
- package/dist/workflows/freeze/freeze.js +172 -0
- package/dist/workflows/freeze/step-values.js +19 -21
- package/dist/workflows/freeze/targets/child-workflow.js +23 -92
- package/dist/workflows/freeze/targets/command.js +10 -33
- package/dist/workflows/freeze/targets/script.js +5 -12
- package/dist/workflows/freeze/targets/shell.js +3 -6
- package/dist/workflows/freeze/targets/task.js +25 -80
- package/dist/workflows/freeze/task-bindings.js +20 -67
- package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
- package/dist/workflows/ir/params.js +6 -51
- package/dist/workflows/ir/plan-hash.js +2 -34
- package/dist/workflows/parser.js +140 -43
- package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
- package/dist/workflows/renderer.js +36 -69
- package/dist/workflows/resource-limits.js +12 -120
- package/dist/workflows/runtime/agent-identity.js +8 -40
- package/dist/workflows/runtime/run-outputs.js +3 -6
- package/dist/workflows/runtime/run-plan.js +316 -0
- package/dist/workflows/runtime/runs.js +48 -200
- package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
- package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/integration/bundling-akm.md +49 -42
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.17.md +41 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
- package/docs/reference/cli.md +182 -125
- package/docs/reference/configuration.md +49 -56
- package/docs/reference/data-and-telemetry.md +19 -20
- package/docs/reference/tasks.md +86 -38
- package/docs/reference/workflow-schema.md +14 -18
- package/docs/reference/workflows.md +6 -9
- package/package.json +1 -1
- package/schemas/akm-config.json +87 -406
- package/dist/commands/health/advisories.js +0 -150
- package/dist/commands/health/metrics.js +0 -329
- package/dist/commands/health/surfaces.js +0 -102
- package/dist/commands/improve/anti-collapse.js +0 -83
- package/dist/commands/improve/collapse-detector.js +0 -432
- package/dist/commands/improve/consolidate/eligibility.js +0 -48
- package/dist/commands/improve/consolidate/merge.js +0 -146
- package/dist/commands/improve/distill/promote-memory.js +0 -329
- package/dist/commands/improve/distill/quality-gate.js +0 -500
- package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
- package/dist/commands/improve/proposal-envelope.js +0 -31
- package/dist/commands/improve/run-context.js +0 -123
- package/dist/commands/improve/shared.js +0 -21
- package/dist/commands/improve/source-identity.js +0 -28
- package/dist/commands/improve/triage.js +0 -96
- package/dist/commands/proposal/drain-policies.js +0 -151
- package/dist/commands/sources/update-transaction.js +0 -220
- package/dist/core/action-contributors.js +0 -28
- package/dist/core/config/config-version-shim.js +0 -101
- package/dist/core/config/retired-experimental-keys-shim.js +0 -62
- package/dist/core/fs-txn.js +0 -405
- package/dist/core/lexical-score.js +0 -25
- package/dist/core/maintenance-barrier.js +0 -167
- package/dist/execution/executable-identity.js +0 -105
- package/dist/execution/guarded-source.js +0 -441
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- package/dist/indexer/walk/project-context.js +0 -192
- package/dist/integrations/agent/execution-cascade.js +0 -566
- package/dist/integrations/agent/execution-definitions.js +0 -202
- package/dist/integrations/agent/execution-lowering.js +0 -841
- package/dist/integrations/agent/execution-preparation.js +0 -98
- package/dist/integrations/agent/inline-execution.js +0 -74
- package/dist/registry/create-provider-registry.js +0 -29
- package/dist/registry/pinned-request-helper.js +0 -247
- package/dist/registry/pinned-transport.js +0 -717
- package/dist/sources/providers/index.js +0 -14
- package/dist/storage/engines/sqlite-migrations.js +0 -271
- package/dist/storage/repositories/canaries-repository.js +0 -107
- package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
- package/dist/storage/repositories/registry-cache.js +0 -113
- package/dist/tasks/scheduler-sync-preview.js +0 -52
- package/dist/workflows/freeze/resolve-steps.js +0 -86
- package/dist/workflows/freeze/source-freeze.js +0 -64
- package/dist/workflows/ir/compile.js +0 -321
- package/dist/workflows/ir/environment-v4.js +0 -330
- package/dist/workflows/ir/freeze-v4.js +0 -153
- package/dist/workflows/ir/schema-v4.js +0 -745
- package/dist/workflows/ir/schema.js +0 -354
- package/dist/workflows/program/schema.js +0 -78
- package/dist/workflows/runtime/checkin.js +0 -57
- package/dist/workflows/runtime/plan-classifier.js +0 -196
- package/dist/workflows/runtime/unit-checkin.js +0 -45
- package/dist/workflows/runtime/unit-phases.js +0 -20
- package/dist/workflows/schema.js +0 -4
- package/dist/workflows/source-ir/compile.js +0 -200
- package/dist/workflows/source-ir/program.js +0 -50
- package/dist/workflows/source-ir/result.js +0 -26
- package/dist/workflows/source-ir/schema.js +0 -786
- package/dist/workflows/source-ir/triggers.js +0 -79
- package/dist/workflows/source-ir/uses.js +0 -40
- package/dist/workflows/validator.js +0 -60
|
@@ -2,18 +2,10 @@
|
|
|
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
|
-
* Plan hashing
|
|
6
|
-
*
|
|
7
|
-
* `workflow run` persists `plan_json` + `plan_hash` on the run row
|
|
8
|
-
* (migration 006); every later invocation executes that snapshot. The hash is
|
|
9
|
-
* the sha256 (hex) of the plan's CANONICAL JSON — object keys recursively
|
|
10
|
-
* sorted — so two structurally-equal plans hash identically regardless of key
|
|
11
|
-
* insertion order, and the same program always freezes to the same hash.
|
|
12
|
-
*
|
|
13
|
-
* Pure module: no IO beyond node:crypto, no engine imports.
|
|
5
|
+
* Plan hashing: sha256 of the plan's canonical JSON (keys recursively sorted),
|
|
6
|
+
* stored beside `plan_json` as information — a stored plan is never gated on it.
|
|
14
7
|
*/
|
|
15
8
|
import { createHash } from "node:crypto";
|
|
16
|
-
import { decodeWorkflowPlanV4, WORKFLOW_IR_V5_VERSION } from "./schema-v4.js";
|
|
17
9
|
/** sha256 hex of the canonical (recursively sorted-keys) JSON of the plan. */
|
|
18
10
|
export function computePlanHash(plan) {
|
|
19
11
|
return createHash("sha256").update(canonicalPlanJson(plan)).digest("hex");
|
|
@@ -26,30 +18,6 @@ export function canonicalPlanJson(plan) {
|
|
|
26
18
|
export function canonicalJson(value) {
|
|
27
19
|
return JSON.stringify(sortKeys(value));
|
|
28
20
|
}
|
|
29
|
-
/** Decode, require stored canonical bytes, then verify the stored SHA-256. */
|
|
30
|
-
export function decodeCanonicalPlan(runId, planJson, planHash, expectedVersion) {
|
|
31
|
-
let parsed;
|
|
32
|
-
try {
|
|
33
|
-
parsed = JSON.parse(planJson);
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
throw new Error(`Workflow run ${runId} has corrupt frozen plan JSON.`);
|
|
37
|
-
}
|
|
38
|
-
const canonicalWire = canonicalJson(parsed);
|
|
39
|
-
if (planJson !== canonicalWire)
|
|
40
|
-
throw new Error(`Workflow run ${runId} has noncanonical frozen plan JSON.`);
|
|
41
|
-
const actual = createHash("sha256").update(planJson).digest("hex");
|
|
42
|
-
if (!planHash || !/^[0-9a-f]{64}$/.test(planHash) || actual !== planHash)
|
|
43
|
-
throw new Error(`Workflow run ${runId} frozen plan integrity check failed.`);
|
|
44
|
-
if (expectedVersion !== undefined && expectedVersion !== null && expectedVersion !== WORKFLOW_IR_V5_VERSION) {
|
|
45
|
-
throw new Error(`Workflow run ${runId} uses unsupported workflow IR version ${expectedVersion}; this runtime supports only workflow IR version 5.`);
|
|
46
|
-
}
|
|
47
|
-
const plan = decodeWorkflowPlanV4(parsed);
|
|
48
|
-
const canonical = canonicalPlanJson(plan);
|
|
49
|
-
if (planJson !== canonical)
|
|
50
|
-
throw new Error(`Workflow run ${runId} has noncanonical frozen plan JSON.`);
|
|
51
|
-
return plan;
|
|
52
|
-
}
|
|
53
21
|
function sortKeys(value) {
|
|
54
22
|
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
55
23
|
return value;
|
package/dist/workflows/parser.js
CHANGED
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
* parsed with the `yaml` package's `parseDocument` + `LineCounter` (best-effort
|
|
11
11
|
* per-key line anchoring), the body's heading list with `parseMarkdownToc`
|
|
12
12
|
* (already fence-aware) — both already in the codebase. The parser
|
|
13
|
-
* accumulates `WorkflowError`s rather than throwing
|
|
13
|
+
* accumulates `WorkflowError`s rather than throwing, and emits a compiled
|
|
14
|
+
* {@link WorkflowPlan} directly (`plan.ts`).
|
|
14
15
|
*
|
|
15
16
|
* Frontmatter carries the orchestration graph (params/defaults/budget/steps);
|
|
16
17
|
* the body carries per-step prose, joined to the graph by step id. Body rules
|
|
17
|
-
|
|
18
|
+
*, exactly three:
|
|
18
19
|
*
|
|
19
20
|
* 1. Every level-2 heading must be `## <step-id>` for a DECLARED step,
|
|
20
21
|
* exactly (fenced code blocks are skipped when scanning for headings).
|
|
@@ -31,16 +32,45 @@
|
|
|
31
32
|
* (`program/expressions.ts`): `map.over`, `route.input`, `inputs[]`.
|
|
32
33
|
*/
|
|
33
34
|
import { LineCounter, parseDocument } from "yaml";
|
|
35
|
+
import { bundleRefToString, parseBundleRef } from "../core/asset/asset-ref.js";
|
|
34
36
|
import { parseFrontmatterBlock } from "../core/asset/frontmatter.js";
|
|
35
37
|
import { parseMarkdownToc } from "../core/asset/markdown.js";
|
|
36
|
-
import { isContainedRelativePath, isRecord } from "../core/common.js";
|
|
38
|
+
import { compareCodePoints, isContainedRelativePath, isRecord } from "../core/common.js";
|
|
37
39
|
import { formatExtraParamsIssue, validateExtraParams } from "../core/extra-params.js";
|
|
38
40
|
import { checkJsonSchemaDefinition, JSON_SCHEMA_SUBSET_SUPPORTED_KEYWORDS } from "../core/json-schema.js";
|
|
41
|
+
import { INPUT_NAME_PATTERN } from "../execution/input-contract.js";
|
|
42
|
+
import { WORKFLOW_PLAN_VERSION, } from "./plan.js";
|
|
39
43
|
import { parseReference } from "./program/expressions.js";
|
|
40
|
-
import {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
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_INSTRUCTION_BYTES, WORKFLOW_MAX_SCHEMA_BYTES, WORKFLOW_MAX_SOURCE_BYTES, WORKFLOW_MAX_TIMEOUT_MS, } from "./resource-limits.js";
|
|
45
|
+
// ── The Markdown grammar's vocabulary (pinned against schemas/akm-workflow.json) ──
|
|
46
|
+
export const PROGRAM_REDUCERS = ["collect", "vote"];
|
|
47
|
+
export const PROGRAM_ON_ERROR = ["fail", "continue"];
|
|
48
|
+
export const PROGRAM_ISOLATION_KINDS = ["none", "worktree"];
|
|
49
|
+
/** `retry.on`: exactly the persisted `AgentFailureReason` taxonomy (the `satisfies` fails typecheck on drift). */
|
|
50
|
+
const RETRY_REASON_SET = {
|
|
51
|
+
timeout: true,
|
|
52
|
+
spawn_failed: true,
|
|
53
|
+
non_zero_exit: true,
|
|
54
|
+
parse_error: true,
|
|
55
|
+
cooldown: true,
|
|
56
|
+
llm_rate_limit: true,
|
|
57
|
+
llm_content_filter: true,
|
|
58
|
+
llm_invalid_json: true,
|
|
59
|
+
content_policy_reject: true,
|
|
60
|
+
unsupported_type: true,
|
|
61
|
+
no_change: true,
|
|
62
|
+
quality_rejected: true,
|
|
63
|
+
aborted: true,
|
|
64
|
+
};
|
|
65
|
+
export const PROGRAM_RETRY_REASONS = Object.keys(RETRY_REASON_SET);
|
|
66
|
+
/**
|
|
67
|
+
* Step ids are exactly the `<ident>` grammar `steps.<id>.output` references
|
|
68
|
+
* accept: no dots, so every step is addressable and `<stepId>.gate` can never
|
|
69
|
+
* collide with a real step id.
|
|
70
|
+
*/
|
|
71
|
+
export const PROGRAM_STEP_ID_PATTERN = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
72
|
+
/** Param (and output) names: plain `params.<ident>`-addressable identifiers, shared with task inputs. */
|
|
73
|
+
export const PROGRAM_PARAM_NAME_PATTERN = INPUT_NAME_PATTERN;
|
|
44
74
|
/** Envelope keys every AKM markdown asset carries ($ref'd from schemas/akm-asset-envelope.json). */
|
|
45
75
|
const ENVELOPE_KEYS = [
|
|
46
76
|
"type",
|
|
@@ -174,7 +204,7 @@ export function parseWorkflow(markdown, source) {
|
|
|
174
204
|
checkUnknownKeys(ctx, root, [], TOP_LEVEL_KEYS, "workflow frontmatter");
|
|
175
205
|
checkEnvelopeFields(ctx, root, frontmatterEndLine);
|
|
176
206
|
const description = typeof root.description === "string" ? root.description : undefined;
|
|
177
|
-
|
|
207
|
+
readTags(ctx, root.tags, frontmatterEndLine);
|
|
178
208
|
const params = parseParams(ctx, root.params);
|
|
179
209
|
const outputs = parseOutputs(ctx, root.outputs);
|
|
180
210
|
const defaults = parseDefaults(ctx, root.defaults);
|
|
@@ -194,46 +224,113 @@ export function parseWorkflow(markdown, source) {
|
|
|
194
224
|
});
|
|
195
225
|
}
|
|
196
226
|
}
|
|
197
|
-
else {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
227
|
+
else if (step.route === undefined && !section.instructions) {
|
|
228
|
+
errors.push({
|
|
229
|
+
line: section.headingLine,
|
|
230
|
+
message: `Step "${step.id}" section ("## ${step.id}") is empty. Add the step's instructions below the heading.`,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
for (const [block, what] of [
|
|
234
|
+
[section?.instructions, "instructions exceed"],
|
|
235
|
+
[section?.gateRubric, "gate rubric exceeds"],
|
|
236
|
+
]) {
|
|
237
|
+
if (block && utf8Bytes(block.text) > WORKFLOW_MAX_INSTRUCTION_BYTES) {
|
|
238
|
+
errors.push({ line: block.source.start, message: `Step "${step.id}" ${what} the 256 KiB resource limit.` });
|
|
203
239
|
}
|
|
204
240
|
}
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
241
|
+
const rubric = section?.gateRubric?.text;
|
|
242
|
+
return {
|
|
243
|
+
stepId: step.id,
|
|
244
|
+
title: step.id,
|
|
208
245
|
sequenceIndex: index,
|
|
209
|
-
|
|
210
|
-
...(step.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
246
|
+
spec: stepSpec(step, section),
|
|
247
|
+
...(step.route
|
|
248
|
+
? {
|
|
249
|
+
route: {
|
|
250
|
+
input: step.route.input,
|
|
251
|
+
when: Object.fromEntries(step.route.branches.map((branch) => [branch.match, branch.stepId])),
|
|
252
|
+
...(step.route.defaultStepId !== undefined ? { defaultStepId: step.route.defaultStepId } : {}),
|
|
253
|
+
},
|
|
254
|
+
}
|
|
255
|
+
: {}),
|
|
256
|
+
...(step.output !== undefined ? { outputSchema: step.output } : {}),
|
|
257
|
+
gate: {
|
|
258
|
+
kind: "gate",
|
|
259
|
+
id: `${step.id}.gate`,
|
|
260
|
+
stepId: step.id,
|
|
261
|
+
criteria: rubric?.trim() ? [rubric] : [],
|
|
262
|
+
maxLoops: step.gate?.maxLoops ?? 1,
|
|
263
|
+
frozenJudge: null,
|
|
264
|
+
},
|
|
218
265
|
};
|
|
219
|
-
return out;
|
|
220
266
|
});
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
267
|
+
checkCanonicalXrefs(root.xrefs, frontmatterEndLine, errors);
|
|
268
|
+
if (errors.length > 0)
|
|
269
|
+
return { ok: false, errors: sortErrors(errors) };
|
|
270
|
+
const paramNames = params ? Object.keys(params) : [];
|
|
271
|
+
const plan = {
|
|
272
|
+
irVersion: WORKFLOW_PLAN_VERSION,
|
|
273
|
+
title: source.title ?? path.replace(/^.*[\\/]/, "").replace(/\.[^.]*$/, ""),
|
|
274
|
+
...(params && paramNames.length > 0 ? { params: paramNames, paramSchemas: params } : {}),
|
|
275
|
+
...(outputs ? { outputs: sortedByName(outputs) } : {}),
|
|
228
276
|
...(budget ? { budget } : {}),
|
|
229
|
-
|
|
277
|
+
...(defaults ? { defaults } : {}),
|
|
278
|
+
...(description ? { description } : {}),
|
|
230
279
|
...(preamble ? { preamble } : {}),
|
|
231
|
-
|
|
280
|
+
steps,
|
|
232
281
|
};
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
282
|
+
return { ok: true, plan };
|
|
283
|
+
}
|
|
284
|
+
/** The authored step as the plan carries it. A prose step is inline `akm/command` literal content. */
|
|
285
|
+
function stepSpec(step, section) {
|
|
286
|
+
const prose = section?.instructions?.text;
|
|
287
|
+
if (step.route)
|
|
288
|
+
return { ...(prose?.trim() ? { instructions: prose } : {}), source: step.source };
|
|
289
|
+
const dispatchUnit = step.map?.unit ?? step.unit;
|
|
290
|
+
const { exec, source: _unitSource, ...unit } = dispatchUnit ?? { source: step.source };
|
|
291
|
+
return {
|
|
292
|
+
...(exec
|
|
293
|
+
? { exec: { ...exec }, ...(prose?.trim() ? { instructions: prose } : {}) }
|
|
294
|
+
: { uses: "akm/command", commandMode: "literal", with: { content: prose ?? "" } }),
|
|
295
|
+
...(Object.keys(unit).length > 0 ? { unit } : {}),
|
|
296
|
+
...(step.map
|
|
297
|
+
? {
|
|
298
|
+
map: {
|
|
299
|
+
over: step.map.over,
|
|
300
|
+
...(step.map.concurrency !== undefined ? { concurrency: step.map.concurrency } : {}),
|
|
301
|
+
...(step.map.reducer !== undefined ? { reducer: step.map.reducer } : {}),
|
|
302
|
+
},
|
|
303
|
+
}
|
|
304
|
+
: {}),
|
|
305
|
+
...(step.inputs ? { inputs: [...step.inputs] } : {}),
|
|
306
|
+
source: step.source,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/** `outputs:` in canonical wire order (code-point ascending by name). */
|
|
310
|
+
function sortedByName(entries) {
|
|
311
|
+
return Object.fromEntries(Object.keys(entries)
|
|
312
|
+
.sort(compareCodePoints)
|
|
313
|
+
.map((name) => [name, entries[name]]));
|
|
314
|
+
}
|
|
315
|
+
/** `xrefs` entries must be canonical asset refs. */
|
|
316
|
+
function checkCanonicalXrefs(value, line, errors) {
|
|
317
|
+
if (!Array.isArray(value))
|
|
318
|
+
return; // shape already flagged by checkXrefs
|
|
319
|
+
for (const ref of value) {
|
|
320
|
+
try {
|
|
321
|
+
if (typeof ref !== "string")
|
|
322
|
+
throw new Error("non-canonical ref");
|
|
323
|
+
const parsed = parseBundleRef(ref);
|
|
324
|
+
if (parsed.conceptId.includes(":") || ref !== bundleRefToString(parsed))
|
|
325
|
+
throw new Error("non-canonical ref");
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
errors.push({
|
|
329
|
+
line,
|
|
330
|
+
message: `Workflow frontmatter "xrefs" contains an invalid or non-canonical ref: ${String(ref)}.`,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
237
334
|
}
|
|
238
335
|
function bindStepSections(headings, lines, bodyStartLine, totalLines, path, declaredIds, errors) {
|
|
239
336
|
const sections = new Map();
|
|
@@ -425,9 +522,9 @@ function parseParams(ctx, raw) {
|
|
|
425
522
|
return Object.keys(params).length > 0 ? params : undefined;
|
|
426
523
|
}
|
|
427
524
|
/**
|
|
428
|
-
* `outputs
|
|
525
|
+
* `outputs:`: named, optionally schema-validated projections
|
|
429
526
|
* of step artifacts, exported when the run completes. Symmetrical with
|
|
430
|
-
* `parseParams` above
|
|
527
|
+
* `parseParams` above — same authoring surface, same name grammar,
|
|
431
528
|
* same schema-subset validator, same per-schema byte bound — but each entry
|
|
432
529
|
* is a STRUCTURED `{from, schema?}` mapping rather than a bare JSON Schema.
|
|
433
530
|
*
|
|
@@ -435,7 +532,7 @@ function parseParams(ctx, raw) {
|
|
|
435
532
|
* `steps.<id>.output(.<seg>)*` reference (never `params.<name>` — an output
|
|
436
533
|
* projects a step artifact, never a param, B-07). Whether the named step is
|
|
437
534
|
* actually DECLARED in this document is a semantic, cross-step check left to
|
|
438
|
-
* `
|
|
535
|
+
* `compile.ts`'s `checkWorkflowPlan`, mirroring how `inputs[]` /
|
|
439
536
|
* `map.over` / `route.input` already split "syntax here, semantics there".
|
|
440
537
|
*/
|
|
441
538
|
function parseOutputs(ctx, raw) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
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
|
+
/** Stored plans record this; earlier releases wrote 4 and 5, which still decode. */
|
|
5
|
+
export const WORKFLOW_PLAN_VERSION = 6;
|
|
@@ -2,17 +2,15 @@
|
|
|
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
|
-
* Show
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* Show renderer for peer workflow sources. `.md` and `.yml` both compile
|
|
6
|
+
* through `compileWorkflowSource` into a plan, which is projected down to the
|
|
7
|
+
* public `ShowResponse` shape, including a compact per-step orchestration
|
|
8
|
+
* summary (engine/model or an exec unit's argv, `map.over` reference, route
|
|
9
|
+
* table) when the step declares one.
|
|
10
10
|
*/
|
|
11
11
|
import { displayRef } from "../core/asset/resolve-ref.js";
|
|
12
12
|
import { UsageError } from "../core/errors.js";
|
|
13
|
-
import {
|
|
14
|
-
import { compileWorkflowSource } from "./source-ir/compile.js";
|
|
15
|
-
import { sourceStepInstructions, workflowShellCommand } from "./source-ir/program.js";
|
|
13
|
+
import { compileWorkflowSource, routeDescription, workflowStepInstructions } from "./compile.js";
|
|
16
14
|
function shellQuote(value) {
|
|
17
15
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
18
16
|
}
|
|
@@ -26,36 +24,18 @@ function deriveName(ctx) {
|
|
|
26
24
|
const ext = ctx.relPath.lastIndexOf(".");
|
|
27
25
|
return ext > 0 ? ctx.relPath.slice(0, ext) : ctx.relPath;
|
|
28
26
|
}
|
|
29
|
-
function
|
|
27
|
+
function loadPlan(ctx) {
|
|
30
28
|
const result = compileWorkflowSource(ctx.content(), { path: ctx.relPath, workspaceRoot: ctx.stashRoot });
|
|
31
29
|
if (result.ok)
|
|
32
|
-
return result.
|
|
30
|
+
return result.plan;
|
|
33
31
|
const summary = result.errors.map((e) => `${e.path}:${e.line} — ${e.message}`).join("\n");
|
|
34
32
|
throw new UsageError(`Workflow has errors:\n${summary}`);
|
|
35
33
|
}
|
|
36
|
-
/**
|
|
37
|
-
* The instruction text a step contributes to the flat step projection. A
|
|
38
|
-
* route step has no body requirement, so a deterministic description of the
|
|
39
|
-
* routing table stands in when it declares no section (the spine still needs
|
|
40
|
-
* a non-empty instructions string).
|
|
41
|
-
*/
|
|
42
|
-
function stepInstructions(step) {
|
|
43
|
-
const instructions = sourceStepInstructions(step);
|
|
44
|
-
if (instructions)
|
|
45
|
-
return instructions;
|
|
46
|
-
if (step.route) {
|
|
47
|
-
const branches = step.route.branches.map((b) => `"${b.match}" -> ${b.stepId}`);
|
|
48
|
-
if (step.route.defaultStepId !== undefined)
|
|
49
|
-
branches.push(`default -> ${step.route.defaultStepId}`);
|
|
50
|
-
return `Route on ${step.route.input}: ${branches.join(", ")}.`;
|
|
51
|
-
}
|
|
52
|
-
return "";
|
|
53
|
-
}
|
|
54
34
|
/** Project the `params` block into the flat `WorkflowParameter` list. */
|
|
55
|
-
function projectParameters(
|
|
56
|
-
if (!
|
|
35
|
+
function projectParameters(plan) {
|
|
36
|
+
if (!plan.paramSchemas)
|
|
57
37
|
return undefined;
|
|
58
|
-
const parameters = Object.entries(
|
|
38
|
+
const parameters = Object.entries(plan.paramSchemas).map(([name, schema]) => {
|
|
59
39
|
const description = schema.description;
|
|
60
40
|
return { name, ...(typeof description === "string" && description !== "" ? { description } : {}) };
|
|
61
41
|
});
|
|
@@ -91,15 +71,9 @@ function projectParameters(sourceIr) {
|
|
|
91
71
|
* already carries whole.
|
|
92
72
|
*/
|
|
93
73
|
function summarizeStepOrchestration(step, defaults) {
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
: step.run !== undefined
|
|
98
|
-
? {
|
|
99
|
-
command: workflowShellCommand(step.shell ?? "sh", step.run),
|
|
100
|
-
...(step.workingDirectory ? { cwd: step.workingDirectory } : {}),
|
|
101
|
-
}
|
|
102
|
-
: undefined;
|
|
74
|
+
const spec = step.spec;
|
|
75
|
+
const unit = spec?.unit;
|
|
76
|
+
const exec = spec?.exec;
|
|
103
77
|
const engine = exec ? undefined : (unit?.engine ?? defaults?.engine);
|
|
104
78
|
const model = exec ? undefined : (unit?.model ?? defaults?.model);
|
|
105
79
|
const timeoutMs = unit?.timeoutMs !== undefined ? unit.timeoutMs : defaults?.timeoutMs;
|
|
@@ -107,25 +81,24 @@ function summarizeStepOrchestration(step, defaults) {
|
|
|
107
81
|
...(engine !== undefined ? { engine } : {}),
|
|
108
82
|
...(model !== undefined ? { model } : {}),
|
|
109
83
|
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
110
|
-
// Same projection the
|
|
111
|
-
|
|
112
|
-
...(
|
|
113
|
-
...(step.map
|
|
84
|
+
// Same projection the frozen plan uses, so what `show` prints cannot drift from what runs.
|
|
85
|
+
...(exec ? { exec: { ...exec } } : {}),
|
|
86
|
+
...(spec?.map
|
|
114
87
|
? {
|
|
115
88
|
fanOut: {
|
|
116
|
-
over:
|
|
117
|
-
...(
|
|
118
|
-
reducer:
|
|
89
|
+
over: spec.map.over,
|
|
90
|
+
...(spec.map.concurrency !== undefined ? { concurrency: spec.map.concurrency } : {}),
|
|
91
|
+
reducer: spec.map.reducer ?? "collect",
|
|
119
92
|
},
|
|
120
93
|
}
|
|
121
94
|
: {}),
|
|
122
|
-
...(unit?.output !== undefined || step.
|
|
95
|
+
...(unit?.output !== undefined || step.outputSchema !== undefined ? { hasSchema: true } : {}),
|
|
123
96
|
...(unit?.env !== undefined ? { env: [...unit.env] } : {}),
|
|
124
97
|
...(step.route
|
|
125
98
|
? {
|
|
126
99
|
route: {
|
|
127
100
|
input: step.route.input,
|
|
128
|
-
branches: step.route.
|
|
101
|
+
branches: Object.entries(step.route.when).map(([match, stepId]) => ({ match, stepId })),
|
|
129
102
|
...(step.route.defaultStepId !== undefined ? { defaultStepId: step.route.defaultStepId } : {}),
|
|
130
103
|
},
|
|
131
104
|
}
|
|
@@ -133,20 +106,15 @@ function summarizeStepOrchestration(step, defaults) {
|
|
|
133
106
|
};
|
|
134
107
|
return Object.keys(summary).length > 0 ? summary : undefined;
|
|
135
108
|
}
|
|
136
|
-
function projectStepDefinitions(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
counts.set(step.id, (counts.get(step.id) ?? 0) + 1);
|
|
141
|
-
return flattened.map(({ jobId, step }, sequenceIndex) => {
|
|
142
|
-
const id = (counts.get(step.id) ?? 0) > 1 ? `${jobId}-${step.id}` : step.id;
|
|
143
|
-
const orchestration = summarizeStepOrchestration(step, sourceIr.defaults);
|
|
109
|
+
function projectStepDefinitions(plan) {
|
|
110
|
+
return plan.steps.map((step, sequenceIndex) => {
|
|
111
|
+
const orchestration = summarizeStepOrchestration(step, plan.defaults);
|
|
112
|
+
const instructions = workflowStepInstructions(step);
|
|
144
113
|
return {
|
|
145
|
-
id,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
...(step.gate?.rubric?.trim() ? { completionCriteria: [step.gate.rubric] } : {}),
|
|
114
|
+
id: step.stepId,
|
|
115
|
+
title: step.stepId,
|
|
116
|
+
instructions: instructions || (step.route ? routeDescription(step.route) : ""),
|
|
117
|
+
...(step.gate.criteria.length > 0 ? { completionCriteria: [...step.gate.criteria] } : {}),
|
|
150
118
|
sequenceIndex,
|
|
151
119
|
...(orchestration ? { orchestration } : {}),
|
|
152
120
|
};
|
|
@@ -156,26 +124,25 @@ export const workflowMdRenderer = {
|
|
|
156
124
|
name: "workflow-md",
|
|
157
125
|
buildShowResponse(ctx) {
|
|
158
126
|
const name = deriveName(ctx);
|
|
159
|
-
const
|
|
127
|
+
const plan = loadPlan(ctx);
|
|
160
128
|
// WI-8.5b (display flip): the `akm workflow run <ref>` action is DISPLAY
|
|
161
129
|
// output — its spelling follows the D-R5 display rule (`displayRef`). A
|
|
162
130
|
// primary/default-bundle workflow renders the SHORT conceptId
|
|
163
131
|
// (`workflows/<name>`); a named source qualifies it as
|
|
164
132
|
// (`<bundle>//workflows/<name>`).
|
|
165
133
|
const ref = displayRef({ type: "workflow", name, bundleId: ctx.origin }, ctx.defaultBundle);
|
|
166
|
-
const parameters = projectParameters(
|
|
134
|
+
const parameters = projectParameters(plan);
|
|
167
135
|
return {
|
|
168
136
|
type: "workflow",
|
|
169
137
|
name,
|
|
170
138
|
path: ctx.absPath,
|
|
171
139
|
action: buildWorkflowAction(ref),
|
|
172
|
-
...(
|
|
173
|
-
description:
|
|
174
|
-
// No authored title
|
|
175
|
-
// its `description`/H1 like any other asset; this is its canonical name.
|
|
140
|
+
...(plan.preamble ? { content: plan.preamble } : {}),
|
|
141
|
+
description: plan.description,
|
|
142
|
+
// No authored title — the asset's human name is its `description`/H1; this is its canonical name.
|
|
176
143
|
workflowTitle: name,
|
|
177
144
|
...(parameters ? { parameters: parameters.map((p) => p.name), workflowParameters: parameters } : {}),
|
|
178
|
-
steps: projectStepDefinitions(
|
|
145
|
+
steps: projectStepDefinitions(plan),
|
|
179
146
|
};
|
|
180
147
|
},
|
|
181
148
|
};
|
|
@@ -6,18 +6,8 @@ export const WORKFLOW_MAX_SOURCE_BYTES = 1024 * 1024;
|
|
|
6
6
|
export const WORKFLOW_MAX_INSTRUCTION_BYTES = 256 * 1024;
|
|
7
7
|
export const WORKFLOW_MAX_SCHEMA_BYTES = 256 * 1024;
|
|
8
8
|
export const WORKFLOW_MAX_EXTRA_PARAMS_BYTES = 64 * 1024;
|
|
9
|
-
// ──
|
|
10
|
-
//
|
|
11
|
-
// Defined ONCE here so the enforcement layers cannot drift:
|
|
12
|
-
// 1. the parser (`../parser.ts`) — line-anchored authoring-time errors,
|
|
13
|
-
// 2. the published JSON Schema (`schemas/akm-workflow.json`) — mirrored
|
|
14
|
-
// `maximum`/`pattern`/`maxLength` values, pinned against these constants
|
|
15
|
-
// by `tests/integration/workflows/schema-drift.test.ts`,
|
|
16
|
-
// 3. the strict frozen-plan decoder (`./ir/schema.ts`) — the corruption
|
|
17
|
-
// gate for persisted plans.
|
|
18
|
-
// A bound enforced only by the decoder surfaces as a terse, unlocated
|
|
19
|
-
// "Invalid frozen workflow plan" at `workflow run` — after lint and
|
|
20
|
-
// `workflow create` already said the document was fine.
|
|
9
|
+
// ── Bounds the parser enforces, mirrored by schemas/akm-workflow.json ────────
|
|
10
|
+
// (pinned by tests/workflows/schema-drift.test.ts)
|
|
21
11
|
/** Max per-step map fan-out concurrency (also the run-level concurrency ceiling). */
|
|
22
12
|
export const WORKFLOW_MAX_CONCURRENCY = 64;
|
|
23
13
|
/** Max timeout in milliseconds (setTimeout's 32-bit signed ceiling: 2^31-1, ~24.8 days). */
|
|
@@ -26,69 +16,21 @@ export const WORKFLOW_MAX_TIMEOUT_MS = EXECUTION_MAX_TIMEOUT_MS;
|
|
|
26
16
|
export const WORKFLOW_ENGINE_NAME_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
27
17
|
export const WORKFLOW_MAX_ENGINE_NAME_LENGTH = 63;
|
|
28
18
|
// ── exec (shell) unit bounds ─────────────────────────────────────────────────
|
|
29
|
-
/**
|
|
30
|
-
* Grammar for an env var NAME in `pass_env:`. Matches the frozen-plan
|
|
31
|
-
* `envPassthrough` grammar in `ir/schema.ts` so both allowlist surfaces accept
|
|
32
|
-
* exactly the same identifiers.
|
|
33
|
-
*/
|
|
19
|
+
/** Grammar for an env var NAME (`pass_env:`, step `env:` keys, task env). */
|
|
34
20
|
export const WORKFLOW_ENV_VAR_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
35
21
|
/**
|
|
36
|
-
* Default
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* 10 minutes matches `DEFAULT_LLM_TIMEOUT_MS`. Unlike an agent harness (which
|
|
40
|
-
* owns its own lifetime, hence `DEFAULT_AGENT_TIMEOUT_MS === null`), a shell
|
|
41
|
-
* command has NO lifetime discipline of its own: an unbounded default would let
|
|
42
|
-
* a hung `npm install` or an interactive prompt wedge a workflow run forever.
|
|
43
|
-
* Authors who genuinely need an unbounded command write `timeout: none`.
|
|
22
|
+
* Default timeout for an exec unit with no `timeout:` of its own or in
|
|
23
|
+
* `defaults` (a command has no lifetime discipline; `timeout: none` opts out).
|
|
44
24
|
*/
|
|
45
25
|
export const DEFAULT_EXEC_TIMEOUT_MS = 600_000;
|
|
46
26
|
/**
|
|
47
|
-
* Max
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* bounded only by the command's exit or the wall timeout, so a command that
|
|
52
|
-
* writes continuously (`yes`, a verbose test loop) grows a string in the akm
|
|
53
|
-
* process until the host runs out of memory — and the default budget gives it
|
|
54
|
-
* ten minutes to do so. What the cap buys is a BOUND where there was none: the
|
|
55
|
-
* retained prefix is promoted into the unit's outcome text and every outcome is
|
|
56
|
-
* held until the step reduces, so the worst case is (units in the STEP × this
|
|
57
|
-
* cap) — the step's width, not the in-flight width, is what sizes it.
|
|
58
|
-
*
|
|
59
|
-
* On reaching the cap the reader switches to DRAIN-AND-DISCARD: it keeps
|
|
60
|
-
* pulling from the pipe (so the child never blocks on backpressure) and stops
|
|
61
|
-
* RETAINING. The command therefore runs to completion and its real exit code
|
|
62
|
-
* stands — a passing-but-chatty test suite is no longer failed over log volume.
|
|
63
|
-
* What overflow costs is honesty about the artifact, and that is paid two ways
|
|
64
|
-
* in `exec/exec-unit.ts`:
|
|
65
|
-
*
|
|
66
|
-
* - no declared `output:` schema → the unit succeeds and its artifact carries
|
|
67
|
-
* an unmistakable {@link WORKFLOW_EXEC_OUTPUT_TRUNCATED_MARKER} block naming
|
|
68
|
-
* the total and retained byte counts, so truncated text can never be
|
|
69
|
-
* mistaken for the whole output;
|
|
70
|
-
* - a declared `output:` schema → the unit fails `exec_output_limit`, because
|
|
71
|
-
* validating a truncated JSON prefix is meaningless and promoting it would
|
|
72
|
-
* corrupt every downstream reference. That is the residual failure the cap
|
|
73
|
-
* genuinely justifies.
|
|
74
|
-
*
|
|
75
|
-
* 8 MiB is deliberately generous, so any output a step is likely to produce
|
|
76
|
-
* fits many times over and an ordinary full test/build log is nowhere near
|
|
77
|
-
* it.
|
|
27
|
+
* Max bytes of one captured pipe an exec unit retains in memory. Past it the
|
|
28
|
+
* reader drains and discards, so the command still runs to its real exit
|
|
29
|
+
* code; the artifact gets a {@link WORKFLOW_EXEC_OUTPUT_TRUNCATED_MARKER}
|
|
30
|
+
* block, or the unit fails `exec_output_limit` if it declared an `output:` schema.
|
|
78
31
|
*/
|
|
79
32
|
export const WORKFLOW_MAX_EXEC_OUTPUT_BYTES = 8 * 1024 * 1024;
|
|
80
|
-
/**
|
|
81
|
-
* Marker stamped on an exec artifact that was RETAINED ONLY IN PART because the
|
|
82
|
-
* command wrote past {@link WORKFLOW_MAX_EXEC_OUTPUT_BYTES}.
|
|
83
|
-
*
|
|
84
|
-
* Deliberately ugly and unique: a truncated value must NEVER be mistakable
|
|
85
|
-
* for a complete one by a downstream `steps.<id>.output` reference, by a gate
|
|
86
|
-
* judge, by `akm workflow status`, or by a human reading the row. The
|
|
87
|
-
* artifact is TEXT here rather than a JSON value, so the marker is appended
|
|
88
|
-
* as a trailing block instead of replacing the value with an envelope: the
|
|
89
|
-
* retained prefix is still genuinely useful (it is the head of a real log),
|
|
90
|
-
* and the block says exactly how much is missing.
|
|
91
|
-
*/
|
|
33
|
+
/** Appended to an exec artifact retained only in part, so it is never mistaken for complete output. */
|
|
92
34
|
export const WORKFLOW_EXEC_OUTPUT_TRUNCATED_MARKER = "__akm_exec_output_truncated__";
|
|
93
35
|
// Per-var: Win32 `SetEnvironmentVariable` caps one variable at 32 767 UTF-16
|
|
94
36
|
// code units; measuring UTF-8 bytes is conservative in the right direction.
|
|
@@ -116,65 +58,15 @@ const EXEC_CONTEXT_LIMITS_POSIX = {
|
|
|
116
58
|
export function execContextLimits(platform = process.platform) {
|
|
117
59
|
return platform === "win32" ? EXEC_CONTEXT_LIMITS_WIN32 : EXEC_CONTEXT_LIMITS_POSIX;
|
|
118
60
|
}
|
|
119
|
-
/**
|
|
120
|
-
* Max characters of the per-unit human diagnostic — the `error`/stderr text
|
|
121
|
-
* journaled on a failed unit row and rendered by `akm workflow status --units`.
|
|
122
|
-
*
|
|
123
|
-
* ONE constant for the write side (`exec/native-executor.ts`, which clips before
|
|
124
|
-
* journaling) and the read side (`runtime/runs.ts`, which clips whatever a row
|
|
125
|
-
* already holds), so a diagnostic can never be stored larger than the surface
|
|
126
|
-
* that displays it. Long enough for a real stack trace or a compiler's error
|
|
127
|
-
* block; short enough that a runaway command cannot turn the journal into its
|
|
128
|
-
* log file.
|
|
129
|
-
*/
|
|
61
|
+
/** Max characters of a unit's journaled diagnostic, on both the write and the display side. */
|
|
130
62
|
export const WORKFLOW_UNIT_DIAGNOSTIC_CLIP = 2_000;
|
|
131
|
-
/**
|
|
132
|
-
* Truncate to `max` chars with an ellipsis marker.
|
|
133
|
-
*
|
|
134
|
-
* Lives with the bounds rather than with either caller: the write side
|
|
135
|
-
* (`exec/step-work.ts`) and the read side (`runtime/runs.ts`) clip against the
|
|
136
|
-
* same constants, and `runtime/runs.ts` cannot take the helper from
|
|
137
|
-
* `exec/step-work.ts` — that module imports `runtime/runs.ts`.
|
|
138
|
-
*/
|
|
63
|
+
/** Truncate to `max` chars with an ellipsis marker. */
|
|
139
64
|
export function clip(text, max) {
|
|
140
65
|
return text.length > max ? `${text.slice(0, max)}…` : text;
|
|
141
66
|
}
|
|
142
|
-
// ── Persistence bounds ───────────────────────────────────────────────────────
|
|
143
|
-
//
|
|
144
|
-
// `workflow_run_steps.evidence_json` is persisted WHOLE and unclipped. It used
|
|
145
|
-
// to be capped at 1 MiB, past which the row was replaced by a marked
|
|
146
|
-
// truncation envelope — but the run still looked successful, and the NEXT
|
|
147
|
-
// invocation (a resume, or any later step referencing the artifact) failed
|
|
148
|
-
// permanently: the value was gone from the only place a resumed run can read
|
|
149
|
-
// it from, so every prior paid step had to be re-run from scratch. SQLite has
|
|
150
|
-
// no practical row-size problem here (its own ceiling is ~1 GB), so there is
|
|
151
|
-
// nothing this cap protected that a full write does not already handle
|
|
152
|
-
// correctly. `JSON.stringify` throwing on genuinely unserializable evidence
|
|
153
|
-
// is unchanged.
|
|
154
67
|
export function utf8Bytes(value) {
|
|
155
68
|
return Buffer.byteLength(value, "utf8");
|
|
156
69
|
}
|
|
157
70
|
export function jsonBytes(value) {
|
|
158
71
|
return utf8Bytes(JSON.stringify(value));
|
|
159
72
|
}
|
|
160
|
-
// ── Recursive child-workflow composition bounds (spec docs/plans/specs/
|
|
161
|
-
// ── p3a-plan-v5-child-freeze.md §4.5, A-N6) ──────────────────────────────────
|
|
162
|
-
//
|
|
163
|
-
// Composition DEPTH is unbounded — `assertNoCompositionCycle` (freeze/targets/
|
|
164
|
-
// child-workflow.ts) already makes infinite composition mathematically
|
|
165
|
-
// impossible, so a depth ceiling on top of it only bounded how many
|
|
166
|
-
// legitimately distinct workflows an author could nest.
|
|
167
|
-
//
|
|
168
|
-
// This section used to also cap the AGGREGATE canonical-JSON bytes of every
|
|
169
|
-
// embedded child plan in one root freeze (`WORKFLOW_MAX_EMBEDDED_CHILD_PLAN_BYTES`,
|
|
170
|
-
// enforced in `freeze/targets/child-workflow.ts` and re-checked on every
|
|
171
|
-
// decode in `ir/schema-v4.ts`'s `decodeChildWorkflowTarget`), alongside a
|
|
172
|
-
// standalone cap on any one frozen plan's own bytes
|
|
173
|
-
// (`WORKFLOW_MAX_PLAN_BYTES`, enforced in `ir/plan-hash.ts` and
|
|
174
|
-
// `ir/schema.ts`). A large plan is not a wrong plan: composing several
|
|
175
|
-
// substantial workflows together is a legitimate, deliberate authoring
|
|
176
|
-
// choice, and SQLite has no practical row-size problem here (its own
|
|
177
|
-
// ceiling is ~1 GB) — there was nothing left for either cap to protect that
|
|
178
|
-
// `planHash`/`contentHash` verification does not already cover. Both caps
|
|
179
|
-
// are removed; the hash/canonical-JSON integrity checks they sat next to
|
|
180
|
-
// are unchanged.
|