akm-cli 0.8.7 → 0.8.14
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 +428 -0
- package/dist/assets/help/help-proposals.md +1 -2
- package/dist/assets/hints/cli-hints-full.md +34 -19
- package/dist/assets/hints/cli-hints-short.md +1 -1
- package/dist/assets/profiles/catchup.json +13 -0
- package/dist/assets/profiles/consolidate.json +13 -0
- package/dist/assets/profiles/frequent.json +13 -0
- package/dist/assets/tasks/core/backup.yml +4 -0
- package/dist/assets/tasks/core/extract.yml +4 -0
- package/dist/assets/tasks/core/improve.yml +4 -0
- package/dist/assets/tasks/core/index-refresh.yml +4 -0
- package/dist/assets/tasks/core/sync.yml +4 -0
- package/dist/assets/tasks/core/update-stashes.yml +4 -0
- package/dist/assets/tasks/core/version-check.yml +4 -0
- package/dist/assets/templates/html/default.html +78 -0
- package/dist/assets/templates/html/health.html +560 -0
- package/dist/assets/templates/html/vendor/echarts.min.js +45 -0
- package/dist/cli/config-migrate.js +6 -6
- package/dist/cli/config-validate.js +4 -4
- package/dist/cli/confirm.js +3 -3
- package/dist/cli/parse-args.js +1 -1
- package/dist/cli/shared.js +72 -19
- package/dist/cli-node.mjs +26 -0
- package/dist/cli.js +206 -3866
- package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
- package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
- package/dist/commands/agent/contribute-cli.js +200 -0
- package/dist/commands/completions.js +1 -1
- package/dist/commands/config-cli.js +230 -3
- package/dist/commands/db-cli.js +2 -2
- package/dist/commands/env/env-cli.js +529 -0
- package/dist/commands/env/env.js +410 -0
- package/dist/commands/env/secret-cli.js +259 -0
- package/dist/commands/{secret.js → env/secret.js} +6 -47
- package/dist/commands/events.js +4 -4
- package/dist/commands/feedback-cli.js +18 -34
- package/dist/commands/graph/graph-cli.js +132 -0
- package/dist/commands/{graph.js → graph/graph.js} +22 -16
- package/dist/commands/health/checks.js +279 -0
- package/dist/commands/health/html-report.js +448 -0
- package/dist/commands/health.js +189 -266
- package/dist/commands/{consolidate.js → improve/consolidate.js} +48 -36
- package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
- package/dist/commands/{distill.js → improve/distill.js} +39 -18
- package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
- package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
- package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
- package/dist/commands/{extract.js → improve/extract.js} +221 -26
- package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +30 -4
- package/dist/commands/{improve-cli.js → improve/improve-cli.js} +44 -22
- package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
- package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +1 -1
- package/dist/commands/{improve.js → improve/improve.js} +672 -292
- package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
- package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
- package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/{reflect.js → improve/reflect.js} +58 -28
- package/dist/commands/improve/session-asset.js +248 -0
- package/dist/commands/lint/agent-linter.js +1 -1
- package/dist/commands/lint/base-linter.js +55 -37
- package/dist/commands/lint/command-linter.js +1 -1
- package/dist/commands/lint/default-linter.js +1 -1
- package/dist/commands/lint/env-key-rules.js +1 -1
- package/dist/commands/lint/index.js +19 -25
- package/dist/commands/lint/knowledge-linter.js +1 -1
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +8 -8
- package/dist/commands/lint/skill-linter.js +1 -1
- package/dist/commands/lint/task-linter.js +1 -1
- package/dist/commands/lint/workflow-linter.js +1 -1
- package/dist/commands/lint.js +1 -1
- package/dist/commands/observability-cli.js +244 -0
- package/dist/commands/proposal/drain-policies.js +3 -3
- package/dist/commands/proposal/drain.js +87 -15
- package/dist/commands/proposal/proposal-cli.js +490 -0
- package/dist/commands/{proposal.js → proposal/proposal.js} +17 -6
- package/dist/commands/{propose.js → proposal/propose.js} +11 -11
- package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
- package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
- package/dist/{core → commands/proposal/validators}/proposals.js +374 -345
- package/dist/commands/{curate.js → read/curate.js} +7 -7
- package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
- package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
- package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
- package/dist/commands/read/search-cli.js +207 -0
- package/dist/commands/{search.js → read/search.js} +22 -27
- package/dist/commands/{show.js → read/show.js} +31 -45
- package/dist/commands/registry-cli.js +8 -8
- package/dist/commands/remember.js +14 -10
- package/dist/commands/sources/add-cli.js +293 -0
- package/dist/commands/{history.js → sources/history.js} +27 -25
- package/dist/commands/{info.js → sources/info.js} +6 -6
- package/dist/commands/{init.js → sources/init.js} +6 -6
- package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
- package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
- package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
- package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
- package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
- package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
- package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
- package/dist/commands/sources/sources-cli.js +305 -0
- package/dist/commands/sources/stash-cli.js +219 -0
- package/dist/commands/{stash-skeleton.js → sources/stash-skeleton.js} +2 -1
- package/dist/commands/tasks/default-tasks.js +173 -0
- package/dist/commands/tasks/tasks-cli.js +210 -0
- package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
- package/dist/commands/wiki-cli.js +307 -0
- package/dist/commands/workflow-cli.js +329 -0
- package/dist/core/action-contributors.js +1 -1
- package/dist/core/assert.js +40 -0
- package/dist/core/asset/asset-create.js +54 -0
- package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
- package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
- package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
- package/dist/core/{markdown.js → asset/markdown.js} +1 -1
- package/dist/core/{stash-meta.js → asset/stash-meta.js} +1 -1
- package/dist/core/best-effort.js +64 -0
- package/dist/core/common.js +32 -18
- package/dist/core/{config-io.js → config/config-io.js} +29 -19
- package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
- package/dist/core/{config-schema.js → config/config-schema.js} +50 -7
- package/dist/core/config/config-types.js +16 -0
- package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
- package/dist/core/{config.js → config/config.js} +10 -8
- package/dist/core/env-secret-ref.js +90 -0
- package/dist/core/errors.js +13 -3
- package/dist/core/events.js +27 -4
- package/dist/core/file-lock.js +1 -1
- package/dist/core/improve-types.js +48 -0
- package/dist/core/lesson-lint.js +2 -2
- package/dist/core/logs-db.js +304 -0
- package/dist/core/paths.js +2 -2
- package/dist/core/ripgrep/install.js +2 -2
- package/dist/core/ripgrep/resolve.js +2 -2
- package/dist/core/state-db.js +195 -60
- package/dist/core/text-truncation.js +148 -0
- package/dist/core/time.js +1 -1
- package/dist/core/write-source.js +98 -85
- package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
- package/dist/indexer/{db.js → db/db.js} +128 -118
- package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
- package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
- package/dist/indexer/ensure-index.js +4 -4
- package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
- package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
- package/dist/indexer/indexer.js +37 -30
- package/dist/indexer/init.js +54 -0
- package/dist/indexer/manifest.js +10 -10
- package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +141 -33
- package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
- package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
- package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
- package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
- package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
- package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
- package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
- package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
- package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
- package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
- package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
- package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
- package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
- package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
- package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
- package/dist/indexer/{walker.js → walk/walker.js} +4 -3
- package/dist/integrations/agent/builder-shared.js +39 -0
- package/dist/integrations/agent/builders.js +14 -81
- package/dist/integrations/agent/config.js +6 -4
- package/dist/integrations/agent/detect.js +1 -1
- package/dist/integrations/agent/index.js +23 -8
- package/dist/integrations/agent/prompts.js +2 -3
- package/dist/integrations/agent/runner.js +22 -3
- package/dist/integrations/agent/spawn.js +9 -10
- package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
- package/dist/integrations/harnesses/claude/config-import.js +70 -0
- package/dist/integrations/harnesses/claude/index.js +64 -0
- package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +32 -5
- package/dist/integrations/harnesses/index.js +144 -0
- package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
- package/dist/integrations/harnesses/opencode/config-import.js +82 -0
- package/dist/integrations/harnesses/opencode/index.js +59 -0
- package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
- package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
- package/dist/integrations/harnesses/types.js +43 -0
- package/dist/integrations/lockfile.js +7 -16
- package/dist/integrations/session-logs/index.js +82 -9
- package/dist/llm/call-ai.js +4 -4
- package/dist/llm/client.js +146 -6
- package/dist/llm/embedder.js +6 -6
- package/dist/llm/embedders/local.js +9 -22
- package/dist/llm/embedders/remote.js +2 -2
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +31 -12
- package/dist/llm/index-passes.js +1 -1
- package/dist/llm/memory-infer.js +12 -5
- package/dist/llm/metadata-enhance.js +2 -2
- package/dist/llm/usage-persist.js +77 -0
- package/dist/llm/usage-telemetry.js +103 -0
- package/dist/output/context.js +9 -46
- package/dist/output/html-render.js +73 -0
- package/dist/output/renderers.js +88 -58
- package/dist/output/shapes/curate.js +7 -3
- package/dist/output/shapes/distill.js +7 -3
- package/dist/output/shapes/env-list.js +18 -16
- package/dist/output/shapes/events.js +5 -4
- package/dist/output/shapes/helpers.js +19 -5
- package/dist/output/shapes/history.js +7 -3
- package/dist/output/shapes/passthrough.js +8 -11
- package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
- package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
- package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
- package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
- package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
- package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
- package/dist/output/shapes/registry-search.js +7 -3
- package/dist/output/shapes/registry.js +12 -0
- package/dist/output/shapes/search.js +7 -3
- package/dist/output/shapes/secret-list.js +18 -16
- package/dist/output/shapes/show.js +7 -3
- package/dist/output/shapes.js +55 -30
- package/dist/output/text/add.js +2 -3
- package/dist/output/text/clone.js +2 -3
- package/dist/output/text/config.js +2 -3
- package/dist/output/text/curate.js +4 -3
- package/dist/output/text/distill.js +2 -3
- package/dist/output/text/enable-disable.js +5 -4
- package/dist/output/text/env.js +13 -0
- package/dist/output/text/events.js +5 -4
- package/dist/output/text/feedback.js +4 -3
- package/dist/output/text/helpers.js +123 -40
- package/dist/output/text/history.js +2 -3
- package/dist/output/text/import.js +2 -3
- package/dist/output/text/index.js +2 -3
- package/dist/output/text/info.js +2 -3
- package/dist/output/text/init.js +2 -3
- package/dist/output/text/list.js +2 -3
- package/dist/output/text/proposal/producer.js +9 -0
- package/dist/output/text/proposal/proposal.js +13 -0
- package/dist/output/text/registry-commands.js +8 -7
- package/dist/output/text/registry.js +12 -0
- package/dist/output/text/remember.js +4 -3
- package/dist/output/text/remove.js +2 -3
- package/dist/output/text/save.js +2 -3
- package/dist/output/text/search.js +4 -3
- package/dist/output/text/show.js +4 -3
- package/dist/output/text/update.js +2 -3
- package/dist/output/text/upgrade.js +2 -3
- package/dist/output/text/wiki.js +12 -11
- package/dist/output/text/workflow.js +12 -10
- package/dist/output/text.js +66 -32
- package/dist/registry/build-index.js +11 -10
- package/dist/registry/factory.js +1 -1
- package/dist/registry/origin-resolve.js +1 -1
- package/dist/registry/providers/index.js +2 -2
- package/dist/registry/providers/skills-sh.js +91 -72
- package/dist/registry/providers/static-index.js +75 -52
- package/dist/registry/resolve.js +3 -3
- package/dist/runtime.js +242 -0
- package/dist/scripts/migrate-storage.js +1654 -683
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +254 -168
- package/dist/setup/detect.js +311 -9
- package/dist/setup/harness-config-import.js +6 -120
- package/dist/setup/setup.js +454 -43
- package/dist/sources/include.js +1 -1
- package/dist/sources/provider-factory.js +2 -2
- package/dist/sources/providers/filesystem.js +3 -3
- package/dist/sources/providers/git.js +9 -9
- package/dist/sources/providers/index.js +4 -4
- package/dist/sources/providers/npm.js +6 -6
- package/dist/sources/providers/provider-utils.js +13 -20
- package/dist/sources/providers/sync-from-ref.js +5 -5
- package/dist/sources/providers/tar-utils.js +2 -2
- package/dist/sources/providers/website.js +2 -2
- package/dist/sources/resolve.js +5 -5
- package/dist/sources/website-ingest.js +5 -5
- package/dist/storage/database.js +102 -0
- package/dist/storage/engines/sqlite-migrations.js +42 -0
- package/dist/storage/locations.js +25 -0
- package/dist/storage/repositories/index-db.js +43 -0
- package/dist/storage/repositories/workflow-runs-repository.js +141 -0
- package/dist/tasks/backends/cron.js +4 -4
- package/dist/tasks/backends/exec-utils.js +32 -0
- package/dist/tasks/backends/index.js +3 -3
- package/dist/tasks/backends/launchd.js +7 -14
- package/dist/tasks/backends/schtasks.js +7 -16
- package/dist/tasks/embedded.js +71 -0
- package/dist/tasks/parser.js +2 -2
- package/dist/tasks/resolveAkmBin.js +1 -1
- package/dist/tasks/runner.js +127 -31
- package/dist/tasks/schedule.js +1 -1
- package/dist/tasks/validator.js +7 -7
- package/dist/text-import-hook.mjs +51 -0
- package/dist/version.js +2 -1
- package/dist/wiki/wiki.js +7 -7
- package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
- package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
- package/dist/workflows/cli.js +1 -1
- package/dist/workflows/db.js +54 -32
- package/dist/workflows/parser.js +4 -4
- package/dist/workflows/renderer.js +5 -5
- package/dist/workflows/runtime/agent-identity.js +56 -0
- package/dist/workflows/runtime/checkin.js +57 -0
- package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
- package/dist/workflows/validate-summary.js +82 -0
- package/docs/README.md +1 -1
- package/docs/data-and-telemetry.md +6 -6
- package/package.json +17 -8
- package/dist/commands/add-cli.js +0 -279
- package/dist/commands/env.js +0 -213
- package/dist/integrations/agent/sdk-runner.js +0 -126
- package/dist/output/shapes/vault-list.js +0 -19
- package/dist/output/text/proposal-producer.js +0 -8
- package/dist/output/text/proposal.js +0 -12
- package/dist/output/text/vault.js +0 -16
- /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
- /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
- /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
- /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
- /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
- /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
- /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
- /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
|
@@ -3,61 +3,76 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import fs from "node:fs";
|
|
6
|
-
import { parseAssetRef } from "
|
|
7
|
-
import { loadConfig } from "
|
|
8
|
-
import { NotFoundError, UsageError } from "
|
|
9
|
-
import { appendEvent } from "
|
|
10
|
-
import { getDbPath } from "
|
|
11
|
-
import { closeDatabase, openExistingDatabase } from "
|
|
12
|
-
import { resolveSourceEntries } from "
|
|
13
|
-
import { resolveSourcesForOrigin } from "
|
|
14
|
-
import { resolveAssetPath } from "
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return await Promise.resolve(fn(db));
|
|
23
|
-
}
|
|
24
|
-
finally {
|
|
25
|
-
closeWorkflowDatabase(db);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
6
|
+
import { parseAssetRef } from "../../core/asset/asset-ref.js";
|
|
7
|
+
import { loadConfig } from "../../core/config/config.js";
|
|
8
|
+
import { NotFoundError, UsageError } from "../../core/errors.js";
|
|
9
|
+
import { appendEvent } from "../../core/events.js";
|
|
10
|
+
import { getDbPath } from "../../core/paths.js";
|
|
11
|
+
import { closeDatabase, openExistingDatabase } from "../../indexer/db/db.js";
|
|
12
|
+
import { resolveSourceEntries } from "../../indexer/search/search-source.js";
|
|
13
|
+
import { resolveSourcesForOrigin } from "../../registry/origin-resolve.js";
|
|
14
|
+
import { resolveAssetPath } from "../../sources/resolve.js";
|
|
15
|
+
import { withWorkflowRunsRepo, } from "../../storage/repositories/workflow-runs-repository.js";
|
|
16
|
+
import { formatWorkflowErrors } from "../authoring/authoring.js";
|
|
17
|
+
import { getCurrentWorkflowScopeKey } from "../authoring/scope-key.js";
|
|
18
|
+
import { parseWorkflow } from "../parser.js";
|
|
19
|
+
import { validateStepSummary } from "../validate-summary.js";
|
|
20
|
+
import { resolveAgentIdentity } from "./agent-identity.js";
|
|
21
|
+
import { evaluateCheckin } from "./checkin.js";
|
|
28
22
|
export async function startWorkflowRun(ref, params = {}, options) {
|
|
29
23
|
const asset = await loadWorkflowAsset(ref);
|
|
30
|
-
return
|
|
24
|
+
return withWorkflowRunsRepo(async (repo) => {
|
|
31
25
|
const now = new Date().toISOString();
|
|
32
26
|
const runId = randomUUID();
|
|
33
27
|
const scopeKey = getCurrentWorkflowScopeKey();
|
|
34
28
|
const currentStepId = asset.steps[0]?.id ?? null;
|
|
35
29
|
const workflowEntryId = resolveWorkflowEntryId(asset.sourcePath, asset.ref);
|
|
30
|
+
// Capture the agent harness + session driving this run. Explicit options
|
|
31
|
+
// win; otherwise fall back to best-effort environment detection. This is
|
|
32
|
+
// identity-only — no background thread or timer is started here.
|
|
33
|
+
const detected = resolveAgentIdentity();
|
|
34
|
+
const agentHarness = options?.agentHarness !== undefined ? options.agentHarness : detected.harness;
|
|
35
|
+
const agentSessionId = options?.agentSessionId !== undefined ? options.agentSessionId : detected.sessionId;
|
|
36
36
|
// Concurrency guard (#485): if an active run already exists in this
|
|
37
37
|
// (workflow_ref, scope_key) pair, refuse to create a parallel run unless
|
|
38
38
|
// `force: true` is set. Previously every call inserted unconditionally,
|
|
39
39
|
// so two terminals running `akm workflow start <ref>` left two runs
|
|
40
40
|
// racing; `akm workflow next` then non-deterministically picked one.
|
|
41
41
|
if (!options?.force) {
|
|
42
|
-
const existing =
|
|
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);
|
|
42
|
+
const existing = repo.findActiveRunForScope(asset.ref, scopeKey);
|
|
45
43
|
if (existing) {
|
|
46
44
|
throw new UsageError(`Workflow ${asset.ref} already has an active run in this scope (id=${existing.id}, step=${existing.current_step_id ?? "—"}). ` +
|
|
47
45
|
`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
46
|
}
|
|
49
47
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
48
|
+
// #506: arm a file-signal check-in (a timestamp, NOT a background thread —
|
|
49
|
+
// see docs/technical/workflow-agent-checkin-adr.md) so a stalled run can be
|
|
50
|
+
// re-targeted with a `continue` directive. The agent harness + session id
|
|
51
|
+
// are already resolved above (agentHarness/agentSessionId, from #501).
|
|
52
|
+
repo.transaction(() => {
|
|
53
|
+
repo.insertRun({
|
|
54
|
+
id: runId,
|
|
55
|
+
workflowRef: asset.ref,
|
|
56
|
+
scopeKey,
|
|
57
|
+
workflowEntryId,
|
|
58
|
+
workflowTitle: asset.title,
|
|
59
|
+
paramsJson: JSON.stringify(params),
|
|
60
|
+
currentStepId,
|
|
61
|
+
createdAt: now,
|
|
62
|
+
updatedAt: now,
|
|
63
|
+
agentHarness,
|
|
64
|
+
agentSessionId,
|
|
65
|
+
checkinArmedAt: now,
|
|
66
|
+
});
|
|
67
|
+
repo.insertSteps(asset.steps.map((step) => ({
|
|
68
|
+
runId,
|
|
69
|
+
stepId: step.id,
|
|
70
|
+
stepTitle: step.title,
|
|
71
|
+
instructions: step.instructions,
|
|
72
|
+
completionJson: step.completionCriteria ? JSON.stringify(step.completionCriteria) : null,
|
|
73
|
+
sequenceIndex: step.sequenceIndex ?? 0,
|
|
74
|
+
})));
|
|
75
|
+
});
|
|
61
76
|
const result = await getWorkflowStatus(runId);
|
|
62
77
|
appendEvent({
|
|
63
78
|
eventType: "workflow_started",
|
|
@@ -68,49 +83,49 @@ export async function startWorkflowRun(ref, params = {}, options) {
|
|
|
68
83
|
});
|
|
69
84
|
}
|
|
70
85
|
export async function getWorkflowStatus(runId) {
|
|
71
|
-
return
|
|
72
|
-
const run = readWorkflowRun(
|
|
73
|
-
const steps = readWorkflowRunSteps(
|
|
86
|
+
return withWorkflowRunsRepo((repo) => {
|
|
87
|
+
const run = readWorkflowRun(repo, runId);
|
|
88
|
+
const steps = readWorkflowRunSteps(repo, run.id);
|
|
74
89
|
return buildWorkflowRunDetail(run, steps);
|
|
75
90
|
});
|
|
76
91
|
}
|
|
77
92
|
export async function hasWorkflowRun(runId) {
|
|
78
|
-
return
|
|
79
|
-
const row = db.prepare("SELECT 1 FROM workflow_runs WHERE id = ? LIMIT 1").get(runId);
|
|
80
|
-
return !!row;
|
|
81
|
-
});
|
|
93
|
+
return withWorkflowRunsRepo((repo) => repo.hasRun(runId));
|
|
82
94
|
}
|
|
83
95
|
export async function listWorkflowRuns(input) {
|
|
84
|
-
return
|
|
85
|
-
const filters = [];
|
|
86
|
-
const params = [];
|
|
96
|
+
return withWorkflowRunsRepo((repo) => {
|
|
87
97
|
const scopeKey = getCurrentWorkflowScopeKey();
|
|
88
|
-
|
|
89
|
-
params.push(scopeKey);
|
|
98
|
+
let workflowRef;
|
|
90
99
|
if (input?.workflowRef) {
|
|
91
100
|
const parsed = parseAssetRef(input.workflowRef);
|
|
92
101
|
if (parsed.type !== "workflow") {
|
|
93
102
|
throw new UsageError(`Expected a workflow ref (workflow:<name>), got "${input.workflowRef}".`);
|
|
94
103
|
}
|
|
95
|
-
|
|
96
|
-
params.push(`${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`);
|
|
104
|
+
workflowRef = `${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`;
|
|
97
105
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
.prepare(`SELECT * FROM workflow_runs ${where} ORDER BY updated_at DESC, created_at DESC`)
|
|
104
|
-
.all(...params);
|
|
106
|
+
const rows = repo.listRuns({
|
|
107
|
+
scopeKey,
|
|
108
|
+
...(workflowRef ? { workflowRef } : {}),
|
|
109
|
+
...(input?.activeOnly ? { activeOnly: true } : {}),
|
|
110
|
+
});
|
|
105
111
|
return { runs: rows.map(toWorkflowRunSummary) };
|
|
106
112
|
});
|
|
107
113
|
}
|
|
108
114
|
export async function getNextWorkflowStep(specifier, params) {
|
|
109
|
-
return
|
|
110
|
-
const { run, autoStarted } = await resolveRunSpecifier(
|
|
111
|
-
const steps = readWorkflowRunSteps(
|
|
115
|
+
return withWorkflowRunsRepo(async (repo) => {
|
|
116
|
+
const { run, autoStarted } = await resolveRunSpecifier(repo, specifier, params);
|
|
117
|
+
const steps = readWorkflowRunSteps(repo, run.id);
|
|
112
118
|
const currentStep = resolveCurrentStep(run, steps);
|
|
113
119
|
const done = run.status === "completed" ? true : undefined;
|
|
120
|
+
// #506: surface a check-in directive through the normal command output when
|
|
121
|
+
// the run looks stalled. Pure timestamp evaluation — no background thread.
|
|
122
|
+
const checkin = evaluateCheckin({
|
|
123
|
+
status: run.status,
|
|
124
|
+
updatedAt: run.updated_at,
|
|
125
|
+
checkinArmedAt: run.checkin_armed_at,
|
|
126
|
+
agentHarness: run.agent_harness,
|
|
127
|
+
agentSessionId: run.agent_session_id,
|
|
128
|
+
}) ?? undefined;
|
|
114
129
|
return {
|
|
115
130
|
run: toWorkflowRunSummary(run),
|
|
116
131
|
workflow: {
|
|
@@ -121,47 +136,90 @@ export async function getNextWorkflowStep(specifier, params) {
|
|
|
121
136
|
step: currentStep ? toWorkflowRunStepState(currentStep) : null,
|
|
122
137
|
...(done ? { done } : {}),
|
|
123
138
|
...(autoStarted ? { autoStarted } : {}),
|
|
139
|
+
...(checkin ? { checkin } : {}),
|
|
124
140
|
};
|
|
125
141
|
});
|
|
126
142
|
}
|
|
127
143
|
export async function resumeWorkflowRun(runId) {
|
|
128
|
-
return
|
|
129
|
-
const run = readWorkflowRun(
|
|
144
|
+
return withWorkflowRunsRepo((repo) => {
|
|
145
|
+
const run = readWorkflowRun(repo, runId);
|
|
130
146
|
if (run.status === "completed") {
|
|
131
147
|
throw new UsageError(`Workflow run ${run.id} is already completed and cannot be resumed.`);
|
|
132
148
|
}
|
|
133
149
|
if (run.status === "active") {
|
|
134
|
-
const steps = readWorkflowRunSteps(
|
|
150
|
+
const steps = readWorkflowRunSteps(repo, run.id);
|
|
135
151
|
return buildWorkflowRunDetail(run, steps);
|
|
136
152
|
}
|
|
137
153
|
// blocked or failed → flip back to active and re-open the current step so
|
|
138
154
|
// it can be reclassified (completed, failed, skipped) after resuming.
|
|
139
155
|
const now = new Date().toISOString();
|
|
140
|
-
|
|
156
|
+
repo.transaction(() => {
|
|
141
157
|
if (run.current_step_id) {
|
|
142
|
-
|
|
143
|
-
SET status = 'pending', notes = NULL, evidence_json = NULL, completed_at = NULL
|
|
144
|
-
WHERE run_id = ? AND step_id = ? AND status IN ('blocked', 'failed')`).run(run.id, run.current_step_id);
|
|
158
|
+
repo.reopenStepsForResume(run.id, run.current_step_id);
|
|
145
159
|
}
|
|
146
|
-
|
|
147
|
-
})
|
|
160
|
+
repo.markRunActive(run.id, now);
|
|
161
|
+
});
|
|
148
162
|
const updated = { ...run, status: "active", updated_at: now };
|
|
149
|
-
const steps = readWorkflowRunSteps(
|
|
163
|
+
const steps = readWorkflowRunSteps(repo, run.id);
|
|
150
164
|
return buildWorkflowRunDetail(updated, steps);
|
|
151
165
|
});
|
|
152
166
|
}
|
|
153
167
|
export async function completeWorkflowStep(input) {
|
|
154
|
-
|
|
168
|
+
// Read the step (read-only) up front so the LLM validation gate runs OUTSIDE
|
|
169
|
+
// the write transaction — a slow/hung LLM must never hold a db write lock.
|
|
170
|
+
const preflight = await withWorkflowRunsRepo((repo) => {
|
|
171
|
+
const run = readWorkflowRun(repo, input.runId);
|
|
172
|
+
if (run.status !== "active") {
|
|
173
|
+
throw new UsageError(`Workflow run ${run.id} is ${run.status} and cannot be updated.`);
|
|
174
|
+
}
|
|
175
|
+
const existing = repo.getStep(run.id, input.stepId);
|
|
176
|
+
if (!existing) {
|
|
177
|
+
throw new NotFoundError(`Step "${input.stepId}" was not found in workflow run ${run.id}.`);
|
|
178
|
+
}
|
|
179
|
+
if (existing.status !== "pending") {
|
|
180
|
+
throw new UsageError(`Step "${input.stepId}" is already ${existing.status} in workflow run ${run.id}.`);
|
|
181
|
+
}
|
|
182
|
+
if (run.current_step_id !== existing.step_id) {
|
|
183
|
+
throw new UsageError(`Step "${input.stepId}" is not the current step for workflow run ${run.id}. Complete "${run.current_step_id}" first.`);
|
|
184
|
+
}
|
|
185
|
+
return { existing };
|
|
186
|
+
});
|
|
187
|
+
const summary = input.summary?.trim();
|
|
188
|
+
// #506: completing a step requires a summary of the work done.
|
|
189
|
+
if (input.status === "completed" && !summary) {
|
|
190
|
+
throw new UsageError(`Completing step "${input.stepId}" requires a --summary describing the work done.`, "MISSING_REQUIRED_ARGUMENT");
|
|
191
|
+
}
|
|
192
|
+
// #506: validation gate — judge the summary against the step's
|
|
193
|
+
// completionCriteria via the configured LLM. Fail-open when no criteria or no
|
|
194
|
+
// judge. Only a well-formed `complete: false` blocks completion.
|
|
195
|
+
if (input.status === "completed" && summary) {
|
|
196
|
+
const criteria = parseJsonArray(preflight.existing.completion_json) ?? [];
|
|
197
|
+
const judge = input.summaryJudge === undefined ? buildDefaultSummaryJudge() : input.summaryJudge;
|
|
198
|
+
const verdict = await validateStepSummary({ stepTitle: preflight.existing.step_title, completionCriteria: criteria, summary }, judge ?? undefined);
|
|
199
|
+
if (!verdict.complete) {
|
|
200
|
+
// Re-arm the check-in so a subsequent stall is still nudged, but leave the
|
|
201
|
+
// step pending and return corrective feedback instead of completing.
|
|
202
|
+
await withWorkflowRunsRepo((repo) => {
|
|
203
|
+
repo.rearmCheckin(input.runId, new Date().toISOString());
|
|
204
|
+
});
|
|
205
|
+
return {
|
|
206
|
+
ok: false,
|
|
207
|
+
runId: input.runId,
|
|
208
|
+
stepId: input.stepId,
|
|
209
|
+
missing: verdict.missing,
|
|
210
|
+
feedback: verdict.feedback ?? "The summary does not satisfy the step's completion criteria.",
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return withWorkflowRunsRepo((repo) => {
|
|
155
215
|
let updatedRun;
|
|
156
216
|
let refreshedSteps = [];
|
|
157
|
-
|
|
158
|
-
const run = readWorkflowRun(
|
|
217
|
+
repo.transaction(() => {
|
|
218
|
+
const run = readWorkflowRun(repo, input.runId);
|
|
159
219
|
if (run.status !== "active") {
|
|
160
220
|
throw new UsageError(`Workflow run ${run.id} is ${run.status} and cannot be updated.`);
|
|
161
221
|
}
|
|
162
|
-
const existing =
|
|
163
|
-
.prepare("SELECT * FROM workflow_run_steps WHERE run_id = ? AND step_id = ?")
|
|
164
|
-
.get(run.id, input.stepId);
|
|
222
|
+
const existing = repo.getStep(run.id, input.stepId);
|
|
165
223
|
if (!existing) {
|
|
166
224
|
throw new NotFoundError(`Step "${input.stepId}" was not found in workflow run ${run.id}.`);
|
|
167
225
|
}
|
|
@@ -172,22 +230,36 @@ export async function completeWorkflowStep(input) {
|
|
|
172
230
|
throw new UsageError(`Step "${input.stepId}" is not the current step for workflow run ${run.id}. Complete "${run.current_step_id}" first.`);
|
|
173
231
|
}
|
|
174
232
|
const completedAt = new Date().toISOString();
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
233
|
+
repo.updateStepCompletion({
|
|
234
|
+
status: input.status,
|
|
235
|
+
notes: input.notes?.trim() || null,
|
|
236
|
+
evidenceJson: input.evidence ? JSON.stringify(input.evidence) : null,
|
|
237
|
+
summary: summary || null,
|
|
238
|
+
completedAt,
|
|
239
|
+
runId: run.id,
|
|
240
|
+
stepId: input.stepId,
|
|
241
|
+
});
|
|
242
|
+
refreshedSteps = readWorkflowRunSteps(repo, run.id);
|
|
179
243
|
const state = deriveRunState(refreshedSteps);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
244
|
+
// Re-arm the check-in on every state change: a healthy, progressing run
|
|
245
|
+
// keeps pushing the stall window forward so the directive never fires.
|
|
246
|
+
repo.updateRunState({
|
|
247
|
+
status: state.status,
|
|
248
|
+
currentStepId: state.currentStepId,
|
|
249
|
+
updatedAt: completedAt,
|
|
250
|
+
completedAt: state.completedAt,
|
|
251
|
+
checkinArmedAt: completedAt,
|
|
252
|
+
runId: run.id,
|
|
253
|
+
});
|
|
183
254
|
updatedRun = {
|
|
184
255
|
...run,
|
|
185
256
|
status: state.status,
|
|
186
257
|
current_step_id: state.currentStepId,
|
|
187
258
|
updated_at: completedAt,
|
|
188
259
|
completed_at: state.completedAt,
|
|
260
|
+
checkin_armed_at: completedAt,
|
|
189
261
|
};
|
|
190
|
-
})
|
|
262
|
+
});
|
|
191
263
|
const detail = buildWorkflowRunDetail(updatedRun, refreshedSteps);
|
|
192
264
|
appendEvent({
|
|
193
265
|
eventType: "workflow_step_completed",
|
|
@@ -200,8 +272,8 @@ export async function completeWorkflowStep(input) {
|
|
|
200
272
|
return detail;
|
|
201
273
|
});
|
|
202
274
|
}
|
|
203
|
-
async function resolveRunSpecifier(
|
|
204
|
-
const explicitRun =
|
|
275
|
+
async function resolveRunSpecifier(repo, specifier, params) {
|
|
276
|
+
const explicitRun = repo.getRunById(specifier);
|
|
205
277
|
if (explicitRun) {
|
|
206
278
|
if (params && Object.keys(params).length > 0) {
|
|
207
279
|
throw new UsageError(`--params can only be used when starting a new run from a workflow ref, not with an existing run id ("${specifier}")`);
|
|
@@ -217,9 +289,7 @@ async function resolveRunSpecifier(db, specifier, params) {
|
|
|
217
289
|
}
|
|
218
290
|
const ref = `${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`;
|
|
219
291
|
const scopeKey = getCurrentWorkflowScopeKey();
|
|
220
|
-
const active =
|
|
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);
|
|
292
|
+
const active = repo.getActiveRunRowForScope(ref, scopeKey);
|
|
223
293
|
if (active) {
|
|
224
294
|
if (params && Object.keys(params).length > 0) {
|
|
225
295
|
throw new UsageError(`--params can only be set on a new run; ${ref} already has an active run`);
|
|
@@ -227,7 +297,7 @@ async function resolveRunSpecifier(db, specifier, params) {
|
|
|
227
297
|
return { run: active, autoStarted: false };
|
|
228
298
|
}
|
|
229
299
|
const started = await startWorkflowRun(ref, params ?? {});
|
|
230
|
-
return { run: readWorkflowRun(
|
|
300
|
+
return { run: readWorkflowRun(repo, started.run.id), autoStarted: true };
|
|
231
301
|
}
|
|
232
302
|
async function loadWorkflowAsset(ref) {
|
|
233
303
|
const parsed = parseAssetRef(ref);
|
|
@@ -338,17 +408,15 @@ function resolveWorkflowEntryId(sourcePath, ref) {
|
|
|
338
408
|
closeDatabase(db);
|
|
339
409
|
}
|
|
340
410
|
}
|
|
341
|
-
function readWorkflowRun(
|
|
342
|
-
const run =
|
|
411
|
+
function readWorkflowRun(repo, runId) {
|
|
412
|
+
const run = repo.getRunById(runId);
|
|
343
413
|
if (!run) {
|
|
344
414
|
throw new NotFoundError(`Workflow run "${runId}" not found.`, "WORKFLOW_NOT_FOUND");
|
|
345
415
|
}
|
|
346
416
|
return run;
|
|
347
417
|
}
|
|
348
|
-
function readWorkflowRunSteps(
|
|
349
|
-
return
|
|
350
|
-
.prepare("SELECT * FROM workflow_run_steps WHERE run_id = ? ORDER BY sequence_index ASC")
|
|
351
|
-
.all(runId);
|
|
418
|
+
function readWorkflowRunSteps(repo, runId) {
|
|
419
|
+
return repo.getStepsForRun(runId);
|
|
352
420
|
}
|
|
353
421
|
function buildWorkflowRunDetail(run, steps) {
|
|
354
422
|
return {
|
|
@@ -373,6 +441,8 @@ function toWorkflowRunSummary(run) {
|
|
|
373
441
|
updatedAt: run.updated_at,
|
|
374
442
|
completedAt: run.completed_at,
|
|
375
443
|
params: parseJsonObject(run.params_json),
|
|
444
|
+
agentHarness: run.agent_harness ?? null,
|
|
445
|
+
agentSessionId: run.agent_session_id ?? null,
|
|
376
446
|
};
|
|
377
447
|
}
|
|
378
448
|
function toWorkflowRunStepState(step) {
|
|
@@ -385,6 +455,7 @@ function toWorkflowRunStepState(step) {
|
|
|
385
455
|
status: step.status,
|
|
386
456
|
notes: step.notes ?? undefined,
|
|
387
457
|
evidence: parseJsonObject(step.evidence_json),
|
|
458
|
+
summary: step.summary ?? undefined,
|
|
388
459
|
completedAt: step.completed_at,
|
|
389
460
|
};
|
|
390
461
|
}
|
|
@@ -414,6 +485,33 @@ function deriveRunState(steps) {
|
|
|
414
485
|
.at(-1);
|
|
415
486
|
return { status: "completed", currentStepId: null, completedAt: completedAt ?? null };
|
|
416
487
|
}
|
|
488
|
+
/**
|
|
489
|
+
/**
|
|
490
|
+
* Build the default summary-validation judge from the configured LLM, or return
|
|
491
|
+
* `null` when no LLM is configured (gate is then skipped — fail-open). Lazily
|
|
492
|
+
* imports the client/config so the workflow engine has no hard LLM dependency.
|
|
493
|
+
*/
|
|
494
|
+
function buildDefaultSummaryJudge() {
|
|
495
|
+
let llm;
|
|
496
|
+
try {
|
|
497
|
+
const config = loadConfig();
|
|
498
|
+
const { getDefaultLlmConfig } = require("../../core/config/config");
|
|
499
|
+
llm = getDefaultLlmConfig(config);
|
|
500
|
+
}
|
|
501
|
+
catch {
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
if (!llm)
|
|
505
|
+
return null;
|
|
506
|
+
const resolved = llm;
|
|
507
|
+
return async ({ system, user }) => {
|
|
508
|
+
const { chatCompletion } = require("../../llm/client");
|
|
509
|
+
return chatCompletion(resolved, [
|
|
510
|
+
{ role: "system", content: system },
|
|
511
|
+
{ role: "user", content: user },
|
|
512
|
+
]);
|
|
513
|
+
};
|
|
514
|
+
}
|
|
417
515
|
function parseJsonObject(value) {
|
|
418
516
|
if (!value)
|
|
419
517
|
return undefined;
|
|
@@ -443,10 +541,8 @@ function parseJsonArray(value) {
|
|
|
443
541
|
return undefined;
|
|
444
542
|
}
|
|
445
543
|
export async function getActiveWorkflowRun(scopeKey = getCurrentWorkflowScopeKey()) {
|
|
446
|
-
return
|
|
447
|
-
const row =
|
|
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);
|
|
544
|
+
return withWorkflowRunsRepo((repo) => {
|
|
545
|
+
const row = repo.findActiveOrBlockedRunForScope(scopeKey);
|
|
450
546
|
if (!row)
|
|
451
547
|
return null;
|
|
452
548
|
return { runId: row.id, stepId: row.current_step_id, workflowRef: row.workflow_ref };
|
|
@@ -0,0 +1,82 @@
|
|
|
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
|
+
/**
|
|
5
|
+
* Summary-validation gate for workflow step/workflow completion (#506).
|
|
6
|
+
*
|
|
7
|
+
* Takes a step's `completionCriteria` and the summary of work the agent claims
|
|
8
|
+
* to have done, asks the configured LLM to judge whether the summary
|
|
9
|
+
* demonstrates each criterion is met, and returns either a pass or structured
|
|
10
|
+
* corrective feedback steering the agent on what to finish/fix.
|
|
11
|
+
*
|
|
12
|
+
* The LLM call is injected (`judge`) so the gate is unit-testable without a
|
|
13
|
+
* live endpoint, and the whole gate is fail-open: when no criteria exist or no
|
|
14
|
+
* judge is available the step completes as before. See
|
|
15
|
+
* docs/technical/workflow-agent-checkin-adr.md.
|
|
16
|
+
*
|
|
17
|
+
* @module workflows/validate-summary
|
|
18
|
+
*/
|
|
19
|
+
import { parseJsonResponse } from "../core/parse.js";
|
|
20
|
+
const JUDGE_SYSTEM = "You are a strict completion auditor for a software workflow engine. " +
|
|
21
|
+
"Given a step's completion criteria and a summary of the work an agent claims to have done, " +
|
|
22
|
+
"judge whether the summary provides concrete evidence that EVERY criterion is satisfied. " +
|
|
23
|
+
"Be skeptical: vague, hand-wavy, or unsubstantiated claims do NOT satisfy a criterion. " +
|
|
24
|
+
'Respond with ONLY a JSON object: {"complete": boolean, "missing": string[], "feedback": string}. ' +
|
|
25
|
+
'"missing" lists the exact criteria that are not yet satisfied; "feedback" is a short directive ' +
|
|
26
|
+
"telling the agent what to finish or fix. No prose, no markdown fences.";
|
|
27
|
+
function buildUserPrompt(input) {
|
|
28
|
+
const criteria = input.completionCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n");
|
|
29
|
+
return [
|
|
30
|
+
`Step: ${input.stepTitle}`,
|
|
31
|
+
"",
|
|
32
|
+
"Completion criteria:",
|
|
33
|
+
criteria,
|
|
34
|
+
"",
|
|
35
|
+
"Agent's summary of work done:",
|
|
36
|
+
input.summary.trim(),
|
|
37
|
+
"",
|
|
38
|
+
"Return the JSON verdict now.",
|
|
39
|
+
].join("\n");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Run the summary-validation gate.
|
|
43
|
+
*
|
|
44
|
+
* Fail-open contract:
|
|
45
|
+
* - no criteria → `{ complete: true, skipped: true }`
|
|
46
|
+
* - no judge → `{ complete: true, skipped: true }`
|
|
47
|
+
* - judge throws / returns unparseable → `{ complete: true, skipped: true }`
|
|
48
|
+
*
|
|
49
|
+
* Only a well-formed `complete: false` verdict blocks completion.
|
|
50
|
+
*/
|
|
51
|
+
export async function validateStepSummary(input, judge) {
|
|
52
|
+
const criteria = input.completionCriteria.filter((c) => c.trim().length > 0);
|
|
53
|
+
if (criteria.length === 0) {
|
|
54
|
+
return { complete: true, missing: [], skipped: true };
|
|
55
|
+
}
|
|
56
|
+
if (!judge) {
|
|
57
|
+
return { complete: true, missing: [], skipped: true };
|
|
58
|
+
}
|
|
59
|
+
let raw;
|
|
60
|
+
try {
|
|
61
|
+
raw = await judge({ system: JUDGE_SYSTEM, user: buildUserPrompt({ ...input, completionCriteria: criteria }) });
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// LLM unreachable / errored — fail open so offline use keeps working.
|
|
65
|
+
return { complete: true, missing: [], skipped: true };
|
|
66
|
+
}
|
|
67
|
+
const parsed = parseJsonResponse(raw);
|
|
68
|
+
if (!parsed || typeof parsed.complete !== "boolean") {
|
|
69
|
+
return { complete: true, missing: [], skipped: true };
|
|
70
|
+
}
|
|
71
|
+
if (parsed.complete) {
|
|
72
|
+
return { complete: true, missing: [] };
|
|
73
|
+
}
|
|
74
|
+
const missing = Array.isArray(parsed.missing)
|
|
75
|
+
? parsed.missing.filter((m) => typeof m === "string" && m.trim().length > 0)
|
|
76
|
+
: [];
|
|
77
|
+
const feedback = typeof parsed.feedback === "string" && parsed.feedback.trim().length > 0
|
|
78
|
+
? parsed.feedback.trim()
|
|
79
|
+
: "The summary does not yet demonstrate every completion criterion is met. " +
|
|
80
|
+
"Finish the outstanding work and resubmit with a summary that addresses each criterion.";
|
|
81
|
+
return { complete: false, missing, feedback };
|
|
82
|
+
}
|
package/docs/README.md
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
## Operations
|
|
33
33
|
|
|
34
|
-
- Analyzing `akm improve` runs -- use [`akm health`](../src/commands/health.ts) (0.8.0+): `--since`, `--
|
|
34
|
+
- Analyzing `akm improve` runs -- use [`akm health`](../src/commands/health.ts) (0.8.0+): `--since`, `--group-by run`, `--window-compare`, `--windows`. See [health-command-enhancements.md](technical/health-command-enhancements.md).
|
|
35
35
|
|
|
36
36
|
## Internals
|
|
37
37
|
|
|
@@ -76,7 +76,7 @@ Override: set `AKM_STASH_DIR` (or configure `stashDir` in `config.json`).
|
|
|
76
76
|
|
|
77
77
|
### 1. Events Table
|
|
78
78
|
|
|
79
|
-
An append-only log of every mutating action you perform with AKM. Events are stored locally for self-improvement (the improve loop uses them to surface usage patterns) and for inspection via `akm
|
|
79
|
+
An append-only log of every mutating action you perform with AKM. Events are stored locally for self-improvement (the improve loop uses them to surface usage patterns) and for inspection via `akm log`.
|
|
80
80
|
|
|
81
81
|
**What is recorded:**
|
|
82
82
|
- `event_type` — what action was taken (see full list below)
|
|
@@ -101,7 +101,7 @@ An append-only log of every mutating action you perform with AKM. Events are sto
|
|
|
101
101
|
| `update` | `akm update [source]` | `ref` |
|
|
102
102
|
| `remember` | `akm remember <text>` | `ref` |
|
|
103
103
|
| `import` | `akm import <file>` | `ref` |
|
|
104
|
-
| `save` | `akm
|
|
104
|
+
| `save` | `akm sync` | `ref` |
|
|
105
105
|
| `feedback` | `akm feedback <ref>` | `signal` (positive/negative) |
|
|
106
106
|
| `search` | `akm search <query>` | `query`, `source`, `signal` |
|
|
107
107
|
| `curate` | `akm curate <prompt>` | `query`, `source` |
|
|
@@ -154,16 +154,16 @@ A record of scheduled task runs (from `akm tasks`):
|
|
|
154
154
|
|
|
155
155
|
```sh
|
|
156
156
|
# List recent events
|
|
157
|
-
akm
|
|
157
|
+
akm log list
|
|
158
158
|
|
|
159
159
|
# Stream live events (tail)
|
|
160
|
-
akm
|
|
160
|
+
akm log tail
|
|
161
161
|
|
|
162
162
|
# Filter by type
|
|
163
|
-
akm
|
|
163
|
+
akm log list --type search --limit 20
|
|
164
164
|
|
|
165
165
|
# Filter by asset ref
|
|
166
|
-
akm
|
|
166
|
+
akm log list --ref skill:code-review
|
|
167
167
|
```
|
|
168
168
|
|
|
169
169
|
### Inspect proposals
|