akm-cli 0.7.4 → 0.8.0-rc.10
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 +224 -1
- package/README.md +22 -6
- package/SECURITY.md +93 -0
- package/dist/cli/config-migrate.js +144 -0
- package/dist/cli/config-validate.js +39 -0
- package/dist/cli/confirm.js +73 -0
- package/dist/cli/parse-args.js +133 -0
- package/dist/cli/shared.js +129 -0
- package/dist/cli.js +2631 -1440
- package/dist/commands/add-cli.js +279 -0
- package/dist/commands/agent-dispatch.js +110 -0
- package/dist/commands/agent-support.js +68 -0
- package/dist/commands/completions.js +3 -0
- package/dist/commands/config-cli.js +130 -534
- package/dist/commands/consolidate.js +2122 -0
- package/dist/commands/curate.js +45 -3
- package/dist/commands/db-cli.js +23 -0
- package/dist/commands/distill-promotion-policy.js +660 -0
- package/dist/commands/distill.js +1081 -73
- package/dist/commands/env.js +213 -0
- package/dist/commands/eval-cases.js +43 -0
- package/dist/commands/events.js +15 -24
- package/dist/commands/extract-cli.js +127 -0
- package/dist/commands/extract-prompt.js +204 -0
- package/dist/commands/extract.js +477 -0
- package/dist/commands/feedback-cli.js +331 -0
- package/dist/commands/graph.js +477 -0
- package/dist/commands/health.js +1302 -0
- package/dist/commands/help/help-accept.md +12 -0
- package/dist/commands/help/help-improve.md +69 -0
- package/dist/commands/help/help-proposals.md +18 -0
- package/dist/commands/help/help-propose.md +17 -0
- package/dist/commands/help/help-reject.md +11 -0
- package/dist/commands/history.js +54 -46
- package/dist/commands/improve-auto-accept.js +97 -0
- package/dist/commands/improve-cli.js +217 -0
- package/dist/commands/improve-profiles.js +166 -0
- package/dist/commands/improve-result-file.js +167 -0
- package/dist/commands/improve.js +2373 -0
- package/dist/commands/info.js +5 -2
- package/dist/commands/init.js +50 -2
- package/dist/commands/installed-stashes.js +102 -139
- package/dist/commands/knowledge.js +136 -0
- package/dist/commands/lint/agent-linter.js +49 -0
- package/dist/commands/lint/base-linter.js +479 -0
- package/dist/commands/lint/command-linter.js +49 -0
- package/dist/commands/lint/default-linter.js +16 -0
- package/dist/commands/lint/env-key-rules.js +154 -0
- package/dist/commands/lint/index.js +196 -0
- package/dist/commands/lint/knowledge-linter.js +16 -0
- package/dist/commands/lint/markdown-insertion.js +343 -0
- package/dist/commands/lint/memory-linter.js +61 -0
- package/dist/commands/lint/registry.js +36 -0
- package/dist/commands/lint/skill-linter.js +45 -0
- package/dist/commands/lint/task-linter.js +50 -0
- package/dist/commands/lint/types.js +4 -0
- package/dist/commands/lint/workflow-linter.js +56 -0
- package/dist/commands/lint.js +4 -0
- package/dist/commands/migration-help.js +3 -0
- package/dist/commands/proposal.js +67 -12
- package/dist/commands/propose.js +120 -45
- package/dist/commands/reflect.js +1104 -60
- package/dist/commands/registry-cli.js +150 -0
- package/dist/commands/registry-search.js +5 -2
- package/dist/commands/remember-cli.js +257 -0
- package/dist/commands/remember.js +70 -7
- package/dist/commands/schema-repair.js +203 -0
- package/dist/commands/search.js +115 -14
- package/dist/commands/secret.js +173 -0
- package/dist/commands/self-update.js +3 -0
- package/dist/commands/show.js +158 -60
- package/dist/commands/source-add.js +17 -45
- package/dist/commands/source-clone.js +3 -0
- package/dist/commands/source-manage.js +14 -19
- package/dist/commands/tasks.js +437 -0
- package/dist/commands/url-checker.js +42 -0
- package/dist/core/action-contributors.js +28 -0
- package/dist/core/asset-ref.js +17 -2
- package/dist/core/asset-registry.js +12 -17
- package/dist/core/asset-serialize.js +88 -0
- package/dist/core/asset-spec.js +67 -1
- package/dist/core/common.js +182 -0
- package/dist/core/concurrent.js +25 -0
- package/dist/core/config-io.js +347 -0
- package/dist/core/config-migration.js +622 -0
- package/dist/core/config-schema.js +534 -0
- package/dist/core/config-sources.js +108 -0
- package/dist/core/config-types.js +4 -0
- package/dist/core/config-walker.js +337 -0
- package/dist/core/config.js +364 -968
- package/dist/core/errors.js +42 -20
- package/dist/core/events.js +105 -135
- package/dist/core/file-lock.js +104 -0
- package/dist/core/frontmatter.js +75 -8
- package/dist/core/lesson-lint.js +3 -0
- package/dist/core/markdown.js +20 -0
- package/dist/core/memory-belief.js +62 -0
- package/dist/core/memory-contradiction-detect.js +274 -0
- package/dist/core/memory-improve.js +806 -0
- package/dist/core/parse.js +158 -0
- package/dist/core/paths.js +280 -14
- package/dist/core/proposal-quality-validators.js +380 -0
- package/dist/core/proposal-validators.js +69 -0
- package/dist/core/proposals.js +512 -42
- package/dist/core/state-db.js +1068 -0
- package/dist/core/text-truncation.js +107 -0
- package/dist/core/time.js +54 -0
- package/dist/core/tty.js +59 -0
- package/dist/core/warn.js +64 -1
- package/dist/core/write-source.js +3 -0
- package/dist/indexer/db-backup.js +391 -0
- package/dist/indexer/db-search.js +198 -489
- package/dist/indexer/db.js +990 -108
- package/dist/indexer/ensure-index.js +136 -0
- package/dist/indexer/file-context.js +3 -0
- package/dist/indexer/graph-boost.js +376 -101
- package/dist/indexer/graph-db.js +391 -0
- package/dist/indexer/graph-dedup.js +95 -0
- package/dist/indexer/graph-extraction.js +550 -114
- package/dist/indexer/index-context.js +4 -0
- package/dist/indexer/indexer.js +547 -309
- package/dist/indexer/llm-cache.js +52 -0
- package/dist/indexer/manifest.js +3 -0
- package/dist/indexer/matchers.js +167 -160
- package/dist/indexer/memory-inference.js +152 -74
- package/dist/indexer/metadata-contributors.js +29 -0
- package/dist/indexer/metadata.js +275 -196
- package/dist/indexer/path-resolver.js +92 -0
- package/dist/indexer/project-context.js +192 -0
- package/dist/indexer/ranking-contributors.js +331 -0
- package/dist/indexer/ranking.js +81 -0
- package/dist/indexer/search-fields.js +5 -9
- package/dist/indexer/search-hit-enrichers.js +111 -0
- package/dist/indexer/search-source.js +44 -10
- package/dist/indexer/semantic-status.js +6 -17
- package/dist/indexer/staleness-detect.js +447 -0
- package/dist/indexer/usage-events.js +12 -9
- package/dist/indexer/walker.js +28 -0
- package/dist/integrations/agent/builders.js +135 -0
- package/dist/integrations/agent/config.js +122 -230
- package/dist/integrations/agent/detect.js +3 -0
- package/dist/integrations/agent/index.js +7 -13
- package/dist/integrations/agent/model-aliases.js +55 -0
- package/dist/integrations/agent/profiles.js +70 -5
- package/dist/integrations/agent/prompts.js +250 -36
- package/dist/integrations/agent/runner.js +151 -0
- package/dist/integrations/agent/sdk-runner.js +126 -0
- package/dist/integrations/agent/spawn.js +183 -35
- package/dist/integrations/github.js +3 -0
- package/dist/integrations/lockfile.js +32 -69
- package/dist/integrations/session-logs/index.js +69 -0
- package/dist/integrations/session-logs/inline-refs.js +35 -0
- package/dist/integrations/session-logs/pre-filter.js +152 -0
- package/dist/integrations/session-logs/providers/claude-code.js +282 -0
- package/dist/integrations/session-logs/providers/opencode.js +258 -0
- package/dist/integrations/session-logs/types.js +4 -0
- package/dist/llm/call-ai.js +62 -0
- package/dist/llm/client.js +79 -88
- package/dist/llm/embedder.js +20 -29
- package/dist/llm/embedders/cache.js +3 -7
- package/dist/llm/embedders/local.js +42 -1
- package/dist/llm/embedders/remote.js +20 -8
- package/dist/llm/embedders/types.js +3 -7
- package/dist/llm/feature-gate.js +95 -48
- package/dist/llm/graph-extract.js +676 -72
- package/dist/llm/index-passes.js +44 -29
- package/dist/llm/memory-infer.js +80 -71
- package/dist/llm/metadata-enhance.js +42 -29
- package/dist/llm/prompts/extract-session.md +80 -0
- package/dist/llm/prompts/graph-extract-user-prompt.md +35 -0
- package/dist/output/cli-hints-full.md +292 -0
- package/dist/output/cli-hints-short.md +66 -0
- package/dist/output/cli-hints.js +7 -311
- package/dist/output/context.js +60 -8
- package/dist/output/renderers.js +306 -258
- package/dist/output/shapes/curate.js +56 -0
- package/dist/output/shapes/distill.js +10 -0
- package/dist/output/shapes/env-list.js +19 -0
- package/dist/output/shapes/events.js +11 -0
- package/dist/output/shapes/helpers.js +424 -0
- package/dist/output/shapes/history.js +7 -0
- package/dist/output/shapes/passthrough.js +102 -0
- package/dist/output/shapes/proposal-accept.js +7 -0
- package/dist/output/shapes/proposal-diff.js +7 -0
- package/dist/output/shapes/proposal-list.js +7 -0
- package/dist/output/shapes/proposal-producer.js +11 -0
- package/dist/output/shapes/proposal-reject.js +7 -0
- package/dist/output/shapes/proposal-show.js +7 -0
- package/dist/output/shapes/registry-search.js +6 -0
- package/dist/output/shapes/registry.js +30 -0
- package/dist/output/shapes/search.js +6 -0
- package/dist/output/shapes/secret-list.js +19 -0
- package/dist/output/shapes/show.js +6 -0
- package/dist/output/shapes/vault-list.js +19 -0
- package/dist/output/shapes.js +51 -511
- package/dist/output/text/add.js +6 -0
- package/dist/output/text/clone.js +6 -0
- package/dist/output/text/config.js +6 -0
- package/dist/output/text/curate.js +6 -0
- package/dist/output/text/distill.js +7 -0
- package/dist/output/text/enable-disable.js +7 -0
- package/dist/output/text/events.js +10 -0
- package/dist/output/text/feedback.js +6 -0
- package/dist/output/text/helpers.js +1039 -0
- package/dist/output/text/history.js +7 -0
- package/dist/output/text/import.js +6 -0
- package/dist/output/text/index.js +6 -0
- package/dist/output/text/info.js +6 -0
- package/dist/output/text/init.js +6 -0
- package/dist/output/text/list.js +6 -0
- package/dist/output/text/proposal-producer.js +8 -0
- package/dist/output/text/proposal.js +11 -0
- package/dist/output/text/registry-commands.js +11 -0
- package/dist/output/text/registry.js +30 -0
- package/dist/output/text/remember.js +6 -0
- package/dist/output/text/remove.js +6 -0
- package/dist/output/text/save.js +6 -0
- package/dist/output/text/search.js +6 -0
- package/dist/output/text/show.js +6 -0
- package/dist/output/text/update.js +6 -0
- package/dist/output/text/upgrade.js +6 -0
- package/dist/output/text/vault.js +16 -0
- package/dist/output/text/wiki.js +15 -0
- package/dist/output/text/workflow.js +14 -0
- package/dist/output/text.js +44 -1093
- package/dist/registry/build-index.js +3 -0
- package/dist/registry/create-provider-registry.js +3 -0
- package/dist/registry/factory.js +4 -1
- package/dist/registry/origin-resolve.js +3 -0
- package/dist/registry/providers/index.js +3 -0
- package/dist/registry/providers/skills-sh.js +71 -50
- package/dist/registry/providers/static-index.js +53 -48
- package/dist/registry/providers/types.js +3 -24
- package/dist/registry/resolve.js +11 -16
- package/dist/registry/types.js +3 -0
- package/dist/scripts/migrate-storage.js +17750 -0
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +9031 -0
- package/dist/scripts/migrations/v16-to-v17.js +141 -0
- package/dist/setup/detect.js +3 -0
- package/dist/setup/ripgrep-install.js +3 -0
- package/dist/setup/ripgrep-resolve.js +3 -0
- package/dist/setup/setup.js +775 -37
- package/dist/setup/steps.js +3 -15
- package/dist/sources/include.js +3 -0
- package/dist/sources/provider-factory.js +5 -12
- package/dist/sources/provider.js +3 -20
- package/dist/sources/providers/filesystem.js +19 -23
- package/dist/sources/providers/git.js +179 -20
- package/dist/sources/providers/index.js +3 -0
- package/dist/sources/providers/install-types.js +3 -13
- package/dist/sources/providers/npm.js +3 -4
- package/dist/sources/providers/provider-utils.js +3 -0
- package/dist/sources/providers/sync-from-ref.js +3 -11
- package/dist/sources/providers/tar-utils.js +3 -0
- package/dist/sources/providers/website.js +18 -22
- package/dist/sources/resolve.js +3 -0
- package/dist/sources/types.js +3 -0
- package/dist/sources/website-ingest.js +7 -0
- package/dist/tasks/backends/cron.js +203 -0
- package/dist/tasks/backends/exec-utils.js +28 -0
- package/dist/tasks/backends/index.js +24 -0
- package/dist/tasks/backends/launchd-template.xml +19 -0
- package/dist/tasks/backends/launchd.js +187 -0
- package/dist/tasks/backends/schtasks-template.xml +29 -0
- package/dist/tasks/backends/schtasks.js +215 -0
- package/dist/tasks/parser.js +211 -0
- package/dist/tasks/resolveAkmBin.js +87 -0
- package/dist/tasks/runner.js +458 -0
- package/dist/tasks/schedule.js +227 -0
- package/dist/tasks/schema.js +15 -0
- package/dist/tasks/validator.js +62 -0
- package/dist/version.js +3 -0
- package/dist/wiki/index-template.md +12 -0
- package/dist/wiki/ingest-workflow-template.md +54 -0
- package/dist/wiki/log-template.md +8 -0
- package/dist/wiki/schema-template.md +61 -0
- package/dist/wiki/wiki-templates.js +15 -0
- package/dist/wiki/wiki.js +13 -61
- package/dist/workflows/authoring.js +8 -25
- package/dist/workflows/cli.js +3 -0
- package/dist/workflows/db.js +141 -2
- package/dist/workflows/document-cache.js +3 -10
- package/dist/workflows/parser.js +3 -0
- package/dist/workflows/renderer.js +11 -3
- package/dist/workflows/runs.js +91 -89
- package/dist/workflows/schema.js +3 -0
- package/dist/workflows/scope-key.js +79 -0
- package/dist/workflows/validator.js +4 -8
- package/dist/workflows/workflow-template.md +24 -0
- package/docs/README.md +10 -2
- package/docs/data-and-telemetry.md +225 -0
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.7.4.md +1 -1
- package/docs/migration/release-notes/0.7.5.md +20 -0
- package/docs/migration/release-notes/0.8.0.md +48 -0
- package/docs/migration/v0.7-to-v0.8.md +1307 -0
- package/package.json +29 -11
- package/dist/commands/install-audit.js +0 -381
- package/dist/commands/vault.js +0 -333
- package/dist/templates/wiki-templates.js +0 -100
package/dist/workflows/runs.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
import { randomUUID } from "node:crypto";
|
|
2
5
|
import fs from "node:fs";
|
|
3
6
|
import { parseAssetRef } from "../core/asset-ref";
|
|
@@ -12,55 +15,78 @@ import { resolveAssetPath } from "../sources/resolve";
|
|
|
12
15
|
import { formatWorkflowErrors } from "./authoring";
|
|
13
16
|
import { closeWorkflowDatabase, openWorkflowDatabase } from "./db";
|
|
14
17
|
import { parseWorkflow } from "./parser";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
+
import { getCurrentWorkflowScopeKey } from "./scope-key";
|
|
19
|
+
async function withWorkflowDb(fn) {
|
|
20
|
+
const db = openWorkflowDatabase();
|
|
18
21
|
try {
|
|
22
|
+
return await Promise.resolve(fn(db));
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
closeWorkflowDatabase(db);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function startWorkflowRun(ref, params = {}, options) {
|
|
29
|
+
const asset = await loadWorkflowAsset(ref);
|
|
30
|
+
return withWorkflowDb(async (db) => {
|
|
19
31
|
const now = new Date().toISOString();
|
|
20
32
|
const runId = randomUUID();
|
|
33
|
+
const scopeKey = getCurrentWorkflowScopeKey();
|
|
21
34
|
const currentStepId = asset.steps[0]?.id ?? null;
|
|
22
35
|
const workflowEntryId = resolveWorkflowEntryId(asset.sourcePath, asset.ref);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
36
|
+
// Concurrency guard (#485): if an active run already exists in this
|
|
37
|
+
// (workflow_ref, scope_key) pair, refuse to create a parallel run unless
|
|
38
|
+
// `force: true` is set. Previously every call inserted unconditionally,
|
|
39
|
+
// so two terminals running `akm workflow start <ref>` left two runs
|
|
40
|
+
// racing; `akm workflow next` then non-deterministically picked one.
|
|
41
|
+
if (!options?.force) {
|
|
42
|
+
const existing = db
|
|
43
|
+
.prepare("SELECT id, current_step_id FROM workflow_runs WHERE workflow_ref = ? AND scope_key = ? AND status = 'active' ORDER BY updated_at DESC LIMIT 1")
|
|
44
|
+
.get(asset.ref, scopeKey);
|
|
45
|
+
if (existing) {
|
|
46
|
+
throw new UsageError(`Workflow ${asset.ref} already has an active run in this scope (id=${existing.id}, step=${existing.current_step_id ?? "—"}). ` +
|
|
47
|
+
`Use 'akm workflow next ${asset.ref}' to resume it, 'akm workflow abandon ${existing.id}' to give up on it, or pass --force to start a parallel run.`, "RESOURCE_ALREADY_EXISTS");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
db.transaction(() => {
|
|
51
|
+
db.prepare(`INSERT INTO workflow_runs (
|
|
52
|
+
id, workflow_ref, scope_key, workflow_entry_id, workflow_title, status, params_json, current_step_id, created_at, updated_at
|
|
53
|
+
) VALUES (?, ?, ?, ?, ?, 'active', ?, ?, ?, ?)`).run(runId, asset.ref, scopeKey, workflowEntryId, asset.title, JSON.stringify(params), currentStepId, now, now);
|
|
54
|
+
const insertStep = db.prepare(`INSERT INTO workflow_run_steps (
|
|
30
55
|
run_id, step_id, step_title, instructions, completion_json, sequence_index, status
|
|
31
56
|
) VALUES (?, ?, ?, ?, ?, ?, 'pending')`);
|
|
32
57
|
for (const step of asset.steps) {
|
|
33
58
|
insertStep.run(runId, step.id, step.title, step.instructions, step.completionCriteria ? JSON.stringify(step.completionCriteria) : null, step.sequenceIndex ?? 0);
|
|
34
59
|
}
|
|
35
60
|
})();
|
|
36
|
-
const result = getWorkflowStatus(runId);
|
|
61
|
+
const result = await getWorkflowStatus(runId);
|
|
37
62
|
appendEvent({
|
|
38
63
|
eventType: "workflow_started",
|
|
39
64
|
ref: ref,
|
|
40
65
|
metadata: { runId: result.run.id, title: result.run.workflowTitle },
|
|
41
66
|
});
|
|
42
67
|
return result;
|
|
43
|
-
}
|
|
44
|
-
finally {
|
|
45
|
-
closeWorkflowDatabase(workflowDb);
|
|
46
|
-
}
|
|
68
|
+
});
|
|
47
69
|
}
|
|
48
|
-
export function getWorkflowStatus(runId) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
const steps = readWorkflowRunSteps(workflowDb, run.id);
|
|
70
|
+
export async function getWorkflowStatus(runId) {
|
|
71
|
+
return withWorkflowDb((db) => {
|
|
72
|
+
const run = readWorkflowRun(db, runId);
|
|
73
|
+
const steps = readWorkflowRunSteps(db, run.id);
|
|
53
74
|
return buildWorkflowRunDetail(run, steps);
|
|
54
|
-
}
|
|
55
|
-
finally {
|
|
56
|
-
closeWorkflowDatabase(workflowDb);
|
|
57
|
-
}
|
|
75
|
+
});
|
|
58
76
|
}
|
|
59
|
-
export function
|
|
60
|
-
|
|
61
|
-
|
|
77
|
+
export async function hasWorkflowRun(runId) {
|
|
78
|
+
return withWorkflowDb((db) => {
|
|
79
|
+
const row = db.prepare("SELECT 1 FROM workflow_runs WHERE id = ? LIMIT 1").get(runId);
|
|
80
|
+
return !!row;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
export async function listWorkflowRuns(input) {
|
|
84
|
+
return withWorkflowDb((db) => {
|
|
62
85
|
const filters = [];
|
|
63
86
|
const params = [];
|
|
87
|
+
const scopeKey = getCurrentWorkflowScopeKey();
|
|
88
|
+
filters.push("scope_key = ?");
|
|
89
|
+
params.push(scopeKey);
|
|
64
90
|
if (input?.workflowRef) {
|
|
65
91
|
const parsed = parseAssetRef(input.workflowRef);
|
|
66
92
|
if (parsed.type !== "workflow") {
|
|
@@ -73,20 +99,16 @@ export function listWorkflowRuns(input) {
|
|
|
73
99
|
filters.push("status IN ('active', 'blocked')");
|
|
74
100
|
}
|
|
75
101
|
const where = filters.length > 0 ? `WHERE ${filters.join(" AND ")}` : "";
|
|
76
|
-
const rows =
|
|
102
|
+
const rows = db
|
|
77
103
|
.prepare(`SELECT * FROM workflow_runs ${where} ORDER BY updated_at DESC, created_at DESC`)
|
|
78
104
|
.all(...params);
|
|
79
105
|
return { runs: rows.map(toWorkflowRunSummary) };
|
|
80
|
-
}
|
|
81
|
-
finally {
|
|
82
|
-
closeWorkflowDatabase(workflowDb);
|
|
83
|
-
}
|
|
106
|
+
});
|
|
84
107
|
}
|
|
85
108
|
export async function getNextWorkflowStep(specifier, params) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
const steps = readWorkflowRunSteps(workflowDb, run.id);
|
|
109
|
+
return withWorkflowDb(async (db) => {
|
|
110
|
+
const { run, autoStarted } = await resolveRunSpecifier(db, specifier, params);
|
|
111
|
+
const steps = readWorkflowRunSteps(db, run.id);
|
|
90
112
|
const currentStep = resolveCurrentStep(run, steps);
|
|
91
113
|
const done = run.status === "completed" ? true : undefined;
|
|
92
114
|
return {
|
|
@@ -100,54 +122,44 @@ export async function getNextWorkflowStep(specifier, params) {
|
|
|
100
122
|
...(done ? { done } : {}),
|
|
101
123
|
...(autoStarted ? { autoStarted } : {}),
|
|
102
124
|
};
|
|
103
|
-
}
|
|
104
|
-
finally {
|
|
105
|
-
closeWorkflowDatabase(workflowDb);
|
|
106
|
-
}
|
|
125
|
+
});
|
|
107
126
|
}
|
|
108
|
-
export function resumeWorkflowRun(runId) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const run = readWorkflowRun(workflowDb, runId);
|
|
127
|
+
export async function resumeWorkflowRun(runId) {
|
|
128
|
+
return withWorkflowDb((db) => {
|
|
129
|
+
const run = readWorkflowRun(db, runId);
|
|
112
130
|
if (run.status === "completed") {
|
|
113
131
|
throw new UsageError(`Workflow run ${run.id} is already completed and cannot be resumed.`);
|
|
114
132
|
}
|
|
115
133
|
if (run.status === "active") {
|
|
116
|
-
const steps = readWorkflowRunSteps(
|
|
134
|
+
const steps = readWorkflowRunSteps(db, run.id);
|
|
117
135
|
return buildWorkflowRunDetail(run, steps);
|
|
118
136
|
}
|
|
119
137
|
// blocked or failed → flip back to active and re-open the current step so
|
|
120
138
|
// it can be reclassified (completed, failed, skipped) after resuming.
|
|
121
139
|
const now = new Date().toISOString();
|
|
122
|
-
|
|
140
|
+
db.transaction(() => {
|
|
123
141
|
if (run.current_step_id) {
|
|
124
|
-
|
|
125
|
-
.prepare(`UPDATE workflow_run_steps
|
|
142
|
+
db.prepare(`UPDATE workflow_run_steps
|
|
126
143
|
SET status = 'pending', notes = NULL, evidence_json = NULL, completed_at = NULL
|
|
127
|
-
WHERE run_id = ? AND step_id = ? AND status IN ('blocked', 'failed')`)
|
|
128
|
-
.run(run.id, run.current_step_id);
|
|
144
|
+
WHERE run_id = ? AND step_id = ? AND status IN ('blocked', 'failed')`).run(run.id, run.current_step_id);
|
|
129
145
|
}
|
|
130
|
-
|
|
146
|
+
db.prepare("UPDATE workflow_runs SET status = 'active', updated_at = ? WHERE id = ?").run(now, run.id);
|
|
131
147
|
})();
|
|
132
148
|
const updated = { ...run, status: "active", updated_at: now };
|
|
133
|
-
const steps = readWorkflowRunSteps(
|
|
149
|
+
const steps = readWorkflowRunSteps(db, run.id);
|
|
134
150
|
return buildWorkflowRunDetail(updated, steps);
|
|
135
|
-
}
|
|
136
|
-
finally {
|
|
137
|
-
closeWorkflowDatabase(workflowDb);
|
|
138
|
-
}
|
|
151
|
+
});
|
|
139
152
|
}
|
|
140
|
-
export function completeWorkflowStep(input) {
|
|
141
|
-
|
|
142
|
-
try {
|
|
153
|
+
export async function completeWorkflowStep(input) {
|
|
154
|
+
return withWorkflowDb((db) => {
|
|
143
155
|
let updatedRun;
|
|
144
156
|
let refreshedSteps = [];
|
|
145
|
-
|
|
146
|
-
const run = readWorkflowRun(
|
|
157
|
+
db.transaction(() => {
|
|
158
|
+
const run = readWorkflowRun(db, input.runId);
|
|
147
159
|
if (run.status !== "active") {
|
|
148
160
|
throw new UsageError(`Workflow run ${run.id} is ${run.status} and cannot be updated.`);
|
|
149
161
|
}
|
|
150
|
-
const existing =
|
|
162
|
+
const existing = db
|
|
151
163
|
.prepare("SELECT * FROM workflow_run_steps WHERE run_id = ? AND step_id = ?")
|
|
152
164
|
.get(run.id, input.stepId);
|
|
153
165
|
if (!existing) {
|
|
@@ -160,18 +172,14 @@ export function completeWorkflowStep(input) {
|
|
|
160
172
|
throw new UsageError(`Step "${input.stepId}" is not the current step for workflow run ${run.id}. Complete "${run.current_step_id}" first.`);
|
|
161
173
|
}
|
|
162
174
|
const completedAt = new Date().toISOString();
|
|
163
|
-
|
|
164
|
-
.prepare(`UPDATE workflow_run_steps
|
|
175
|
+
db.prepare(`UPDATE workflow_run_steps
|
|
165
176
|
SET status = ?, notes = ?, evidence_json = ?, completed_at = ?
|
|
166
|
-
WHERE run_id = ? AND step_id = ?`)
|
|
167
|
-
|
|
168
|
-
refreshedSteps = readWorkflowRunSteps(workflowDb, run.id);
|
|
177
|
+
WHERE run_id = ? AND step_id = ?`).run(input.status, input.notes?.trim() || null, input.evidence ? JSON.stringify(input.evidence) : null, completedAt, run.id, input.stepId);
|
|
178
|
+
refreshedSteps = readWorkflowRunSteps(db, run.id);
|
|
169
179
|
const state = deriveRunState(refreshedSteps);
|
|
170
|
-
|
|
171
|
-
.prepare(`UPDATE workflow_runs
|
|
180
|
+
db.prepare(`UPDATE workflow_runs
|
|
172
181
|
SET status = ?, current_step_id = ?, updated_at = ?, completed_at = ?
|
|
173
|
-
WHERE id = ?`)
|
|
174
|
-
.run(state.status, state.currentStepId, completedAt, state.completedAt, run.id);
|
|
182
|
+
WHERE id = ?`).run(state.status, state.currentStepId, completedAt, state.completedAt, run.id);
|
|
175
183
|
updatedRun = {
|
|
176
184
|
...run,
|
|
177
185
|
status: state.status,
|
|
@@ -190,10 +198,7 @@ export function completeWorkflowStep(input) {
|
|
|
190
198
|
appendEvent({ eventType: "workflow_finished", ref: detail.run.workflowRef, metadata: { runId: input.runId } });
|
|
191
199
|
}
|
|
192
200
|
return detail;
|
|
193
|
-
}
|
|
194
|
-
finally {
|
|
195
|
-
closeWorkflowDatabase(workflowDb);
|
|
196
|
-
}
|
|
201
|
+
});
|
|
197
202
|
}
|
|
198
203
|
async function resolveRunSpecifier(db, specifier, params) {
|
|
199
204
|
const explicitRun = db.prepare("SELECT * FROM workflow_runs WHERE id = ?").get(specifier);
|
|
@@ -211,9 +216,10 @@ async function resolveRunSpecifier(db, specifier, params) {
|
|
|
211
216
|
throw new UsageError(`Expected a workflow ref or workflow run id, got "${specifier}".`);
|
|
212
217
|
}
|
|
213
218
|
const ref = `${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`;
|
|
219
|
+
const scopeKey = getCurrentWorkflowScopeKey();
|
|
214
220
|
const active = db
|
|
215
|
-
.prepare("SELECT * FROM workflow_runs WHERE workflow_ref = ? AND status = 'active' ORDER BY updated_at DESC LIMIT 1")
|
|
216
|
-
.get(ref);
|
|
221
|
+
.prepare("SELECT * FROM workflow_runs WHERE workflow_ref = ? AND scope_key = ? AND status = 'active' ORDER BY updated_at DESC LIMIT 1")
|
|
222
|
+
.get(ref, scopeKey);
|
|
217
223
|
if (active) {
|
|
218
224
|
if (params && Object.keys(params).length > 0) {
|
|
219
225
|
throw new UsageError(`--params can only be set on a new run; ${ref} already has an active run`);
|
|
@@ -246,7 +252,7 @@ async function loadWorkflowAsset(ref) {
|
|
|
246
252
|
if (!assetPath) {
|
|
247
253
|
throw new NotFoundError(`Workflow not found for ref: workflow:${parsed.name}`);
|
|
248
254
|
}
|
|
249
|
-
const resolvedSourcePath = sourcePath ??
|
|
255
|
+
const resolvedSourcePath = sourcePath ?? config.stashDir ?? assetPath;
|
|
250
256
|
const fullRef = `${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`;
|
|
251
257
|
const cached = readWorkflowDocumentFromIndex(resolvedSourcePath, fullRef);
|
|
252
258
|
const document = cached ?? loadWorkflowDocumentFromDisk(assetPath);
|
|
@@ -358,6 +364,7 @@ function toWorkflowRunSummary(run) {
|
|
|
358
364
|
return {
|
|
359
365
|
id: run.id,
|
|
360
366
|
workflowRef: run.workflow_ref,
|
|
367
|
+
scopeKey: run.scope_key,
|
|
361
368
|
workflowEntryId: run.workflow_entry_id,
|
|
362
369
|
workflowTitle: run.workflow_title,
|
|
363
370
|
status: run.status,
|
|
@@ -435,18 +442,13 @@ function parseJsonArray(value) {
|
|
|
435
442
|
}
|
|
436
443
|
return undefined;
|
|
437
444
|
}
|
|
438
|
-
export function getActiveWorkflowRun() {
|
|
439
|
-
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
.
|
|
443
|
-
.get();
|
|
444
|
-
closeWorkflowDatabase(workflowDb);
|
|
445
|
+
export async function getActiveWorkflowRun(scopeKey = getCurrentWorkflowScopeKey()) {
|
|
446
|
+
return withWorkflowDb((db) => {
|
|
447
|
+
const row = db
|
|
448
|
+
.query("SELECT id, current_step_id, workflow_ref FROM workflow_runs WHERE scope_key = ? AND status IN ('active', 'blocked') ORDER BY updated_at DESC LIMIT 1")
|
|
449
|
+
.get(scopeKey);
|
|
445
450
|
if (!row)
|
|
446
451
|
return null;
|
|
447
452
|
return { runId: row.id, stepId: row.current_step_id, workflowRef: row.workflow_ref };
|
|
448
|
-
}
|
|
449
|
-
catch {
|
|
450
|
-
return null; // fail-open: never crash show output due to DB error
|
|
451
|
-
}
|
|
453
|
+
}).catch(() => null); // fail-open: never crash show output due to DB error
|
|
452
454
|
}
|
package/dist/workflows/schema.js
CHANGED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { isWithin, resolveStashDir, safeRealpath, toPosix } from "../core/common";
|
|
8
|
+
const PROJECT_CONFIG_RELATIVE_PATH = path.join(".akm", "config.json");
|
|
9
|
+
export function getCurrentWorkflowScopeKey() {
|
|
10
|
+
const anchor = resolveWorkflowScopeAnchor(process.cwd());
|
|
11
|
+
const normalized = normalizeScopePath(anchor);
|
|
12
|
+
const digest = createHash("sha256").update(normalized).digest("hex");
|
|
13
|
+
return `dir:v1:${digest}`;
|
|
14
|
+
}
|
|
15
|
+
export function resolveWorkflowScopeAnchor(startDir) {
|
|
16
|
+
const cwd = safeRealpath(startDir);
|
|
17
|
+
const projectRoot = findNearestProjectConfigRoot(cwd);
|
|
18
|
+
if (projectRoot)
|
|
19
|
+
return projectRoot;
|
|
20
|
+
const gitRoot = findNearestGitRoot(cwd);
|
|
21
|
+
if (gitRoot)
|
|
22
|
+
return gitRoot;
|
|
23
|
+
try {
|
|
24
|
+
const stashDir = safeRealpath(resolveStashDir({ readOnly: true }));
|
|
25
|
+
if (isWithin(cwd, stashDir))
|
|
26
|
+
return stashDir;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Ignore stash resolution failures and fall back to cwd.
|
|
30
|
+
}
|
|
31
|
+
return cwd;
|
|
32
|
+
}
|
|
33
|
+
function findNearestProjectConfigRoot(startDir) {
|
|
34
|
+
let currentDir = startDir;
|
|
35
|
+
while (true) {
|
|
36
|
+
const configPath = path.join(currentDir, PROJECT_CONFIG_RELATIVE_PATH);
|
|
37
|
+
if (isFile(configPath)) {
|
|
38
|
+
return safeRealpath(currentDir);
|
|
39
|
+
}
|
|
40
|
+
const parentDir = path.dirname(currentDir);
|
|
41
|
+
if (parentDir === currentDir)
|
|
42
|
+
return null;
|
|
43
|
+
currentDir = parentDir;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function findNearestGitRoot(startDir) {
|
|
47
|
+
let currentDir = startDir;
|
|
48
|
+
while (true) {
|
|
49
|
+
const gitPath = path.join(currentDir, ".git");
|
|
50
|
+
if (exists(gitPath)) {
|
|
51
|
+
return safeRealpath(currentDir);
|
|
52
|
+
}
|
|
53
|
+
const parentDir = path.dirname(currentDir);
|
|
54
|
+
if (parentDir === currentDir)
|
|
55
|
+
return null;
|
|
56
|
+
currentDir = parentDir;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function exists(candidate) {
|
|
60
|
+
try {
|
|
61
|
+
fs.accessSync(candidate, fs.constants.F_OK);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function isFile(candidate) {
|
|
69
|
+
try {
|
|
70
|
+
return fs.statSync(candidate).isFile();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function normalizeScopePath(value) {
|
|
77
|
+
const posix = toPosix(value);
|
|
78
|
+
return process.platform === "win32" ? posix.toLowerCase() : posix;
|
|
79
|
+
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* The parser handles per-line shape checks; this module runs rules that need
|
|
5
|
-
* the whole document or the raw frontmatter at once: duplicate step IDs,
|
|
6
|
-
* step-id format, and the frontmatter key whitelist.
|
|
7
|
-
*/
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
8
4
|
const STEP_ID_REGEX = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
9
|
-
const ALLOWED_FRONTMATTER_KEYS = new Set(["description", "tags", "params"]);
|
|
5
|
+
const ALLOWED_FRONTMATTER_KEYS = new Set(["description", "tags", "params", "name", "updated"]);
|
|
10
6
|
export function runSemanticChecks(draft, frontmatterData, frontmatterEndLine, errors) {
|
|
11
7
|
checkFrontmatterKeys(frontmatterData, frontmatterEndLine, errors);
|
|
12
8
|
checkStepIdFormat(draft, errors);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Describe what this workflow accomplishes
|
|
3
|
+
tags:
|
|
4
|
+
- example
|
|
5
|
+
params:
|
|
6
|
+
example_param: Explain this parameter
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Workflow: {{TITLE}}
|
|
10
|
+
|
|
11
|
+
## Step: {{FIRST_STEP_TITLE}}
|
|
12
|
+
Step ID: {{FIRST_STEP_ID}}
|
|
13
|
+
|
|
14
|
+
### Instructions
|
|
15
|
+
Describe what to do in this step.
|
|
16
|
+
|
|
17
|
+
### Completion Criteria
|
|
18
|
+
- Confirm the first step is complete
|
|
19
|
+
|
|
20
|
+
## Step: Second Step
|
|
21
|
+
Step ID: second-step
|
|
22
|
+
|
|
23
|
+
### Instructions
|
|
24
|
+
Describe what happens next.
|
package/docs/README.md
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
|
|
11
11
|
## Upgrading
|
|
12
12
|
|
|
13
|
+
- [Roadmap](roadmap.md) -- High-level focus for the 0.9 and 1.0 releases
|
|
13
14
|
- [v1 migration guide](migration/v1.md) -- The path from 0.x to v1.0, including the `.stash.json` removal scheduled for v0.8.0
|
|
14
|
-
- [Release notes (latest: 0.
|
|
15
|
+
- [Release notes (latest: 0.8.0)](migration/release-notes/0.8.0.md) -- Per-release notes drop into `migration/release-notes/`, including current pre-release removals
|
|
15
16
|
- [v0.5 → v0.6 migration guide](migration/v0.5-to-v0.6.md) -- Every breaking change with before/after code, publisher checklist, and troubleshooting
|
|
16
17
|
|
|
17
18
|
## Reference
|
|
@@ -28,17 +29,24 @@
|
|
|
28
29
|
- [itlackey/akm-plugins](https://github.com/itlackey/akm-plugins) -- optional integrations for tools like OpenCode
|
|
29
30
|
- [itlackey/akm-bench](https://github.com/itlackey/akm-bench) -- the standalone benchmark and evaluation repo for akm
|
|
30
31
|
|
|
32
|
+
## Operations
|
|
33
|
+
|
|
34
|
+
- Analyzing `akm improve` runs -- use [`akm health`](../src/commands/health.ts) (0.8.0+): `--since`, `--detail per-run`, `--window-compare`, `--windows`. See [health-command-enhancements.md](technical/health-command-enhancements.md).
|
|
35
|
+
|
|
31
36
|
## Internals
|
|
32
37
|
|
|
33
38
|
- [Search](technical/search.md) -- Hybrid search architecture and scoring
|
|
34
39
|
- [Indexing](technical/indexing.md) -- How the search index is built
|
|
35
40
|
- [Classification](technical/classification.md) -- Matcher and renderer behavior
|
|
41
|
+
- [Functional Contract Patterns](technical/functional-contract-patterns.md) -- Quick reference for contributor pipelines and small process contracts
|
|
42
|
+
- [Implementation Plan: Functional Contract Refactor](technical/implementation-plan-functional-contract-refactor.md) -- Phased plan to move behavior from type-centric switchboards to process-local contributors
|
|
43
|
+
- [Architecture Cleanup Checklist](technical/architecture-cleanup-checklist.md) -- Living checklist for executing the cleanup plan with parity gates, reviews, and git hygiene
|
|
36
44
|
- [Show Response](technical/show-response.md) -- `akm show` output fields by asset type
|
|
37
45
|
- [Testing Workflow](technical/testing-workflow.md) -- End-to-end, Docker, deployment, and upgrade validation
|
|
38
46
|
- [Ref Format](technical/ref.md) -- Wire format for asset references
|
|
39
47
|
- [Test Coverage Guide](technical/test-coverage-guide.md) -- High-value testing areas
|
|
40
48
|
- [Core Principles](technical/akm-core-principles.md) -- Design principles and constraints
|
|
41
|
-
-
|
|
49
|
+
- `technical/benchmark.md` (planned) -- Search-quality benchmark suite
|
|
42
50
|
|
|
43
51
|
## Posts
|
|
44
52
|
|