akm-cli 0.7.0-rc1 → 0.7.1
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/dist/{src/cli.js → cli.js} +100 -16
- package/dist/{src/commands → commands}/config-cli.js +42 -0
- package/dist/{src/commands → commands}/history.js +78 -7
- package/dist/{src/commands → commands}/registry-search.js +69 -6
- package/dist/{src/commands → commands}/search.js +30 -3
- package/dist/{src/commands → commands}/show.js +29 -0
- package/dist/{src/commands → commands}/source-add.js +5 -1
- package/dist/{src/commands → commands}/source-manage.js +7 -1
- package/dist/{src/core → core}/config.js +28 -0
- package/dist/{src/indexer → indexer}/db-search.js +1 -0
- package/dist/{src/indexer → indexer}/indexer.js +16 -2
- package/dist/{src/indexer → indexer}/matchers.js +1 -1
- package/dist/{src/indexer → indexer}/search-source.js +4 -2
- package/dist/{src/integrations → integrations}/agent/profiles.js +1 -1
- package/dist/{src/integrations → integrations}/agent/spawn.js +67 -16
- package/dist/{src/integrations → integrations}/github.js +9 -3
- package/dist/{src/llm → llm}/embedders/remote.js +37 -3
- package/dist/{src/output → output}/cli-hints.js +15 -2
- package/dist/{src/output → output}/renderers.js +3 -1
- package/dist/{src/output → output}/shapes.js +8 -1
- package/dist/{src/output → output}/text.js +156 -3
- package/dist/{src/registry → registry}/build-index.js +5 -4
- package/dist/{src/registry → registry}/providers/static-index.js +3 -1
- package/dist/{src/setup → setup}/setup.js +9 -0
- package/dist/{src/wiki → wiki}/wiki.js +54 -6
- package/dist/{src/workflows → workflows}/runs.js +37 -3
- package/package.json +8 -8
- package/dist/tests/add-website-source.test.js +0 -119
- package/dist/tests/agent/agent-config-loader.test.js +0 -70
- package/dist/tests/agent/agent-config.test.js +0 -221
- package/dist/tests/agent/agent-detect.test.js +0 -100
- package/dist/tests/agent/agent-spawn.test.js +0 -234
- package/dist/tests/agent-output.test.js +0 -186
- package/dist/tests/architecture/agent-no-llm-sdk-guard.test.js +0 -103
- package/dist/tests/architecture/agent-spawn-seam.test.js +0 -193
- package/dist/tests/architecture/llm-stateless-seam.test.js +0 -112
- package/dist/tests/asset-ref.test.js +0 -192
- package/dist/tests/asset-registry.test.js +0 -103
- package/dist/tests/asset-spec.test.js +0 -241
- package/dist/tests/bench/attribution.test.js +0 -995
- package/dist/tests/bench/cleanup-sigint.test.js +0 -83
- package/dist/tests/bench/cleanup.js +0 -203
- package/dist/tests/bench/cleanup.test.js +0 -166
- package/dist/tests/bench/cli.js +0 -683
- package/dist/tests/bench/cli.test.js +0 -177
- package/dist/tests/bench/compare.test.js +0 -556
- package/dist/tests/bench/corpus.js +0 -314
- package/dist/tests/bench/corpus.test.js +0 -258
- package/dist/tests/bench/driver.js +0 -346
- package/dist/tests/bench/driver.test.js +0 -443
- package/dist/tests/bench/evolve-metrics.js +0 -179
- package/dist/tests/bench/evolve-metrics.test.js +0 -187
- package/dist/tests/bench/evolve.js +0 -580
- package/dist/tests/bench/evolve.test.js +0 -616
- package/dist/tests/bench/failure-modes.test.js +0 -300
- package/dist/tests/bench/feedback-integrity.test.js +0 -456
- package/dist/tests/bench/leakage.test.js +0 -125
- package/dist/tests/bench/learning-curve.test.js +0 -133
- package/dist/tests/bench/metrics.js +0 -2319
- package/dist/tests/bench/metrics.test.js +0 -1144
- package/dist/tests/bench/no-os-tmpdir-invariant.test.js +0 -43
- package/dist/tests/bench/report.js +0 -1821
- package/dist/tests/bench/report.test.js +0 -989
- package/dist/tests/bench/runner.js +0 -536
- package/dist/tests/bench/runner.test.js +0 -958
- package/dist/tests/bench/search-bridge.test.js +0 -331
- package/dist/tests/bench/tmp.js +0 -41
- package/dist/tests/bench/trajectory.js +0 -116
- package/dist/tests/bench/trajectory.test.js +0 -127
- package/dist/tests/bench/verifier.js +0 -109
- package/dist/tests/bench/verifier.test.js +0 -118
- package/dist/tests/bench/workflow-evaluator.js +0 -557
- package/dist/tests/bench/workflow-evaluator.test.js +0 -421
- package/dist/tests/bench/workflow-spec.js +0 -358
- package/dist/tests/bench/workflow-spec.test.js +0 -363
- package/dist/tests/bench/workflow-trace.js +0 -438
- package/dist/tests/bench/workflow-trace.test.js +0 -254
- package/dist/tests/benchmark-search-quality.js +0 -536
- package/dist/tests/benchmark-suite.js +0 -1441
- package/dist/tests/capture-cli.test.js +0 -112
- package/dist/tests/cli-errors.test.js +0 -203
- package/dist/tests/commands/events.test.js +0 -370
- package/dist/tests/commands/history.test.js +0 -223
- package/dist/tests/commands/import.test.js +0 -103
- package/dist/tests/commands/proposal-cli.test.js +0 -209
- package/dist/tests/commands/reflect-propose-cli.test.js +0 -333
- package/dist/tests/commands/remember.test.js +0 -97
- package/dist/tests/commands/scope-flags.test.js +0 -300
- package/dist/tests/commands/search.test.js +0 -537
- package/dist/tests/commands/show-indexer-parity.test.js +0 -117
- package/dist/tests/commands/show.test.js +0 -294
- package/dist/tests/common.test.js +0 -266
- package/dist/tests/completions.test.js +0 -142
- package/dist/tests/config-cli.test.js +0 -193
- package/dist/tests/config-llm-features.test.js +0 -139
- package/dist/tests/config.test.js +0 -544
- package/dist/tests/contracts/migration-baseline.test.js +0 -43
- package/dist/tests/contracts/reflect-propose-envelope.test.js +0 -139
- package/dist/tests/contracts/spec-helpers.js +0 -46
- package/dist/tests/contracts/v1-spec-section-11-proposal-queue.test.js +0 -228
- package/dist/tests/contracts/v1-spec-section-12-agent-config.test.js +0 -56
- package/dist/tests/contracts/v1-spec-section-13-lesson-type.test.js +0 -34
- package/dist/tests/contracts/v1-spec-section-14-llm-features.test.js +0 -94
- package/dist/tests/contracts/v1-spec-section-4-1-asset-types.test.js +0 -39
- package/dist/tests/contracts/v1-spec-section-4-2-quality-rules.test.js +0 -44
- package/dist/tests/contracts/v1-spec-section-5-configuration.test.js +0 -47
- package/dist/tests/contracts/v1-spec-section-6-orchestration.test.js +0 -40
- package/dist/tests/contracts/v1-spec-section-7-module-layout.test.js +0 -58
- package/dist/tests/contracts/v1-spec-section-8-extension-points.test.js +0 -34
- package/dist/tests/contracts/v1-spec-section-9-4-cli-surface.test.js +0 -75
- package/dist/tests/contracts/v1-spec-section-9-7-llm-agent-boundary.test.js +0 -36
- package/dist/tests/core/write-source.test.js +0 -366
- package/dist/tests/curate-command.test.js +0 -87
- package/dist/tests/db-scoring.test.js +0 -201
- package/dist/tests/db.test.js +0 -654
- package/dist/tests/distill-cli-flag.test.js +0 -208
- package/dist/tests/distill.test.js +0 -515
- package/dist/tests/docker-install.test.js +0 -120
- package/dist/tests/e2e.test.js +0 -1398
- package/dist/tests/embedder.test.js +0 -340
- package/dist/tests/embedding-model-config.test.js +0 -379
- package/dist/tests/feedback-command.test.js +0 -172
- package/dist/tests/file-context.test.js +0 -552
- package/dist/tests/fixtures/scripts/git/summarize-diff.js +0 -9
- package/dist/tests/fixtures/scripts/lint/eslint-check.js +0 -7
- package/dist/tests/fixtures/stashes/load.js +0 -166
- package/dist/tests/fixtures/stashes/load.test.js +0 -88
- package/dist/tests/fixtures/stashes/ranking-baseline/scripts/mem0-search.js +0 -12
- package/dist/tests/frontmatter.test.js +0 -190
- package/dist/tests/fts-field-weighting.test.js +0 -254
- package/dist/tests/fuzzy-search.test.js +0 -230
- package/dist/tests/git-provider-clone.test.js +0 -45
- package/dist/tests/github.test.js +0 -161
- package/dist/tests/graph-boost-ranking.test.js +0 -305
- package/dist/tests/graph-extraction.test.js +0 -282
- package/dist/tests/helpers/usage-events.js +0 -8
- package/dist/tests/index-pass-llm.test.js +0 -161
- package/dist/tests/indexer.test.js +0 -559
- package/dist/tests/info-command.test.js +0 -166
- package/dist/tests/init.test.js +0 -69
- package/dist/tests/install-script.test.js +0 -246
- package/dist/tests/integration/agent-real-profile.test.js +0 -94
- package/dist/tests/issue-36-repro.test.js +0 -304
- package/dist/tests/issues-191-194.test.js +0 -160
- package/dist/tests/lesson-lint.test.js +0 -111
- package/dist/tests/llm-client.test.js +0 -115
- package/dist/tests/llm-feature-gate.test.js +0 -151
- package/dist/tests/llm.test.js +0 -139
- package/dist/tests/lockfile.test.js +0 -216
- package/dist/tests/manifest.test.js +0 -205
- package/dist/tests/markdown.test.js +0 -126
- package/dist/tests/matchers-unit.test.js +0 -189
- package/dist/tests/memory-inference.test.js +0 -299
- package/dist/tests/merge-scoring.test.js +0 -136
- package/dist/tests/metadata.test.js +0 -313
- package/dist/tests/migration-help.test.js +0 -89
- package/dist/tests/origin-resolve.test.js +0 -124
- package/dist/tests/output-baseline.test.js +0 -217
- package/dist/tests/output-shapes-unit.test.js +0 -476
- package/dist/tests/parallel-search.test.js +0 -272
- package/dist/tests/parameter-metadata.test.js +0 -365
- package/dist/tests/paths.test.js +0 -177
- package/dist/tests/progressive-disclosure.test.js +0 -280
- package/dist/tests/proposals.test.js +0 -279
- package/dist/tests/proposed-quality.test.js +0 -271
- package/dist/tests/provider-registry.test.js +0 -32
- package/dist/tests/ranking-regression.test.js +0 -548
- package/dist/tests/reflect-propose.test.js +0 -455
- package/dist/tests/registry-build-index.test.js +0 -378
- package/dist/tests/registry-cli.test.js +0 -290
- package/dist/tests/registry-index-v2.test.js +0 -430
- package/dist/tests/registry-install.test.js +0 -728
- package/dist/tests/registry-providers/parity.test.js +0 -189
- package/dist/tests/registry-providers/skills-sh.test.js +0 -309
- package/dist/tests/registry-providers/static-index.test.js +0 -204
- package/dist/tests/registry-resolve.test.js +0 -126
- package/dist/tests/registry-search.test.js +0 -723
- package/dist/tests/remember-frontmatter.test.js +0 -380
- package/dist/tests/remember-unit.test.js +0 -123
- package/dist/tests/ripgrep-install.test.js +0 -251
- package/dist/tests/ripgrep-resolve.test.js +0 -108
- package/dist/tests/ripgrep.test.js +0 -163
- package/dist/tests/save-command.test.js +0 -94
- package/dist/tests/save-trust-qa-fixes.test.js +0 -270
- package/dist/tests/scoring-pipeline.test.js +0 -648
- package/dist/tests/search-include-proposed-cli.test.js +0 -118
- package/dist/tests/self-update.test.js +0 -442
- package/dist/tests/semantic-search-e2e.test.js +0 -512
- package/dist/tests/semantic-status.test.js +0 -471
- package/dist/tests/setup-run.integration.js +0 -877
- package/dist/tests/setup-wizard.test.js +0 -198
- package/dist/tests/setup.test.js +0 -131
- package/dist/tests/source-add.test.js +0 -11
- package/dist/tests/source-clone.test.js +0 -254
- package/dist/tests/source-manage.test.js +0 -366
- package/dist/tests/source-providers/filesystem.test.js +0 -82
- package/dist/tests/source-providers/git.test.js +0 -252
- package/dist/tests/source-providers/website.test.js +0 -128
- package/dist/tests/source-qa-fixes.test.js +0 -268
- package/dist/tests/source-registry.test.js +0 -350
- package/dist/tests/source-resolve.test.js +0 -100
- package/dist/tests/source-source.test.js +0 -221
- package/dist/tests/source.test.js +0 -533
- package/dist/tests/tar-utils-scan.test.js +0 -73
- package/dist/tests/toggle-components.test.js +0 -73
- package/dist/tests/usage-telemetry.test.js +0 -265
- package/dist/tests/utility-scoring.test.js +0 -558
- package/dist/tests/vault-load-error.test.js +0 -78
- package/dist/tests/vault-qa-fixes.test.js +0 -194
- package/dist/tests/vault.test.js +0 -429
- package/dist/tests/vector-search.test.js +0 -608
- package/dist/tests/walker.test.js +0 -252
- package/dist/tests/wave2-cluster-bc.test.js +0 -228
- package/dist/tests/wave2-cluster-d.test.js +0 -180
- package/dist/tests/wave2-cluster-e.test.js +0 -179
- package/dist/tests/wiki-qa-fixes.test.js +0 -270
- package/dist/tests/wiki.test.js +0 -529
- package/dist/tests/workflow-cli.test.js +0 -271
- package/dist/tests/workflow-markdown.test.js +0 -171
- package/dist/tests/workflow-path-escape.test.js +0 -132
- package/dist/tests/workflow-qa-fixes.test.js +0 -377
- package/dist/tests/workflows/indexer-rejection.test.js +0 -213
- /package/dist/{src/commands → commands}/completions.js +0 -0
- /package/dist/{src/commands → commands}/curate.js +0 -0
- /package/dist/{src/commands → commands}/distill.js +0 -0
- /package/dist/{src/commands → commands}/events.js +0 -0
- /package/dist/{src/commands → commands}/info.js +0 -0
- /package/dist/{src/commands → commands}/init.js +0 -0
- /package/dist/{src/commands → commands}/install-audit.js +0 -0
- /package/dist/{src/commands → commands}/installed-stashes.js +0 -0
- /package/dist/{src/commands → commands}/migration-help.js +0 -0
- /package/dist/{src/commands → commands}/proposal.js +0 -0
- /package/dist/{src/commands → commands}/propose.js +0 -0
- /package/dist/{src/commands → commands}/reflect.js +0 -0
- /package/dist/{src/commands → commands}/remember.js +0 -0
- /package/dist/{src/commands → commands}/self-update.js +0 -0
- /package/dist/{src/commands → commands}/source-clone.js +0 -0
- /package/dist/{src/commands → commands}/vault.js +0 -0
- /package/dist/{src/core → core}/asset-ref.js +0 -0
- /package/dist/{src/core → core}/asset-registry.js +0 -0
- /package/dist/{src/core → core}/asset-spec.js +0 -0
- /package/dist/{src/core → core}/common.js +0 -0
- /package/dist/{src/core → core}/errors.js +0 -0
- /package/dist/{src/core → core}/events.js +0 -0
- /package/dist/{src/core → core}/frontmatter.js +0 -0
- /package/dist/{src/core → core}/lesson-lint.js +0 -0
- /package/dist/{src/core → core}/markdown.js +0 -0
- /package/dist/{src/core → core}/paths.js +0 -0
- /package/dist/{src/core → core}/proposals.js +0 -0
- /package/dist/{src/core → core}/warn.js +0 -0
- /package/dist/{src/core → core}/write-source.js +0 -0
- /package/dist/{src/indexer → indexer}/db.js +0 -0
- /package/dist/{src/indexer → indexer}/file-context.js +0 -0
- /package/dist/{src/indexer → indexer}/graph-boost.js +0 -0
- /package/dist/{src/indexer → indexer}/graph-extraction.js +0 -0
- /package/dist/{src/indexer → indexer}/manifest.js +0 -0
- /package/dist/{src/indexer → indexer}/memory-inference.js +0 -0
- /package/dist/{src/indexer → indexer}/metadata.js +0 -0
- /package/dist/{src/indexer → indexer}/search-fields.js +0 -0
- /package/dist/{src/indexer → indexer}/semantic-status.js +0 -0
- /package/dist/{src/indexer → indexer}/usage-events.js +0 -0
- /package/dist/{src/indexer → indexer}/walker.js +0 -0
- /package/dist/{src/integrations → integrations}/agent/config.js +0 -0
- /package/dist/{src/integrations → integrations}/agent/detect.js +0 -0
- /package/dist/{src/integrations → integrations}/agent/index.js +0 -0
- /package/dist/{src/integrations → integrations}/agent/prompts.js +0 -0
- /package/dist/{src/integrations → integrations}/lockfile.js +0 -0
- /package/dist/{src/llm → llm}/client.js +0 -0
- /package/dist/{src/llm → llm}/embedder.js +0 -0
- /package/dist/{src/llm → llm}/embedders/cache.js +0 -0
- /package/dist/{src/llm → llm}/embedders/local.js +0 -0
- /package/dist/{src/llm → llm}/embedders/types.js +0 -0
- /package/dist/{src/llm → llm}/feature-gate.js +0 -0
- /package/dist/{src/llm → llm}/graph-extract.js +0 -0
- /package/dist/{src/llm → llm}/index-passes.js +0 -0
- /package/dist/{src/llm → llm}/memory-infer.js +0 -0
- /package/dist/{src/llm → llm}/metadata-enhance.js +0 -0
- /package/dist/{src/output → output}/context.js +0 -0
- /package/dist/{src/registry → registry}/create-provider-registry.js +0 -0
- /package/dist/{src/registry → registry}/factory.js +0 -0
- /package/dist/{src/registry → registry}/origin-resolve.js +0 -0
- /package/dist/{src/registry → registry}/providers/index.js +0 -0
- /package/dist/{src/registry → registry}/providers/skills-sh.js +0 -0
- /package/dist/{src/registry → registry}/providers/types.js +0 -0
- /package/dist/{src/registry → registry}/resolve.js +0 -0
- /package/dist/{src/registry → registry}/types.js +0 -0
- /package/dist/{src/setup → setup}/detect.js +0 -0
- /package/dist/{src/setup → setup}/ripgrep-install.js +0 -0
- /package/dist/{src/setup → setup}/ripgrep-resolve.js +0 -0
- /package/dist/{src/setup → setup}/steps.js +0 -0
- /package/dist/{src/sources → sources}/include.js +0 -0
- /package/dist/{src/sources → sources}/provider-factory.js +0 -0
- /package/dist/{src/sources → sources}/provider.js +0 -0
- /package/dist/{src/sources → sources}/providers/filesystem.js +0 -0
- /package/dist/{src/sources → sources}/providers/git.js +0 -0
- /package/dist/{src/sources → sources}/providers/index.js +0 -0
- /package/dist/{src/sources → sources}/providers/install-types.js +0 -0
- /package/dist/{src/sources → sources}/providers/npm.js +0 -0
- /package/dist/{src/sources → sources}/providers/provider-utils.js +0 -0
- /package/dist/{src/sources → sources}/providers/sync-from-ref.js +0 -0
- /package/dist/{src/sources → sources}/providers/tar-utils.js +0 -0
- /package/dist/{src/sources → sources}/providers/website.js +0 -0
- /package/dist/{src/sources → sources}/resolve.js +0 -0
- /package/dist/{src/sources → sources}/types.js +0 -0
- /package/dist/{src/templates → templates}/wiki-templates.js +0 -0
- /package/dist/{src/version.js → version.js} +0 -0
- /package/dist/{src/workflows → workflows}/authoring.js +0 -0
- /package/dist/{src/workflows → workflows}/cli.js +0 -0
- /package/dist/{src/workflows → workflows}/db.js +0 -0
- /package/dist/{src/workflows → workflows}/document-cache.js +0 -0
- /package/dist/{src/workflows → workflows}/parser.js +0 -0
- /package/dist/{src/workflows → workflows}/renderer.js +0 -0
- /package/dist/{src/workflows → workflows}/schema.js +0 -0
- /package/dist/{src/workflows → workflows}/validator.js +0 -0
|
@@ -120,6 +120,8 @@ export function formatPlain(command, result, detail) {
|
|
|
120
120
|
const flagText = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
|
|
121
121
|
lines.push(`[${kind}] ${name}${ver}${prov}${flagText}`);
|
|
122
122
|
}
|
|
123
|
+
lines.push("");
|
|
124
|
+
lines.push("To search: akm search '<query>' | To view an asset: akm show <ref>");
|
|
123
125
|
return lines.join("\n");
|
|
124
126
|
}
|
|
125
127
|
case "add": {
|
|
@@ -597,6 +599,10 @@ export function formatHistoryPlain(r) {
|
|
|
597
599
|
headerParts.push(`since: ${r.since}`);
|
|
598
600
|
const totalCount = typeof r.totalCount === "number" ? r.totalCount : entries.length;
|
|
599
601
|
headerParts.push(`${totalCount} event(s)`);
|
|
602
|
+
// Show active event sources so operators know which streams were consulted.
|
|
603
|
+
if (Array.isArray(r.sources) && r.sources.length > 0) {
|
|
604
|
+
headerParts.push(`sources: ${r.sources.join(", ")}`);
|
|
605
|
+
}
|
|
600
606
|
const header = headerParts.join(" ");
|
|
601
607
|
if (entries.length === 0) {
|
|
602
608
|
const scope = typeof r.ref === "string" && r.ref ? ` for ${r.ref}` : "";
|
|
@@ -627,6 +633,9 @@ function formatShowPlain(r, detail) {
|
|
|
627
633
|
if (r.type || r.name) {
|
|
628
634
|
lines.push(`# ${String(r.type ?? "asset")}: ${String(r.name ?? "unknown")}`);
|
|
629
635
|
}
|
|
636
|
+
if (r.path && r.editable !== false) {
|
|
637
|
+
lines.push(`file: ${String(r.path)}`);
|
|
638
|
+
}
|
|
630
639
|
if (r.origin !== undefined)
|
|
631
640
|
lines.push(`# origin: ${String(r.origin)}`);
|
|
632
641
|
if (r.action)
|
|
@@ -677,7 +686,10 @@ function formatShowPlain(r, detail) {
|
|
|
677
686
|
const id = typeof step.id === "string" ? step.id : "unknown";
|
|
678
687
|
lines.push(` ${index + 1}. ${title} [${id}]`);
|
|
679
688
|
if (typeof step.instructions === "string" && step.instructions.trim()) {
|
|
680
|
-
|
|
689
|
+
const instrLines = step.instructions.trim().split("\n");
|
|
690
|
+
lines.push(` instructions: ${instrLines[0]}`);
|
|
691
|
+
for (const instrLine of instrLines.slice(1))
|
|
692
|
+
lines.push(` ${instrLine}`);
|
|
681
693
|
}
|
|
682
694
|
if (Array.isArray(step.completionCriteria) && step.completionCriteria.length > 0) {
|
|
683
695
|
lines.push(" completion:");
|
|
@@ -692,8 +704,94 @@ function formatShowPlain(r, detail) {
|
|
|
692
704
|
lines.push("");
|
|
693
705
|
lines.push(...payloads);
|
|
694
706
|
}
|
|
707
|
+
// REC-01 / REC-09: Append a type-specific directive so agents apply the
|
|
708
|
+
// content rather than substituting training-data approximations.
|
|
709
|
+
const assetType = typeof r.type === "string" ? r.type : null;
|
|
710
|
+
const assetRef = typeof r.name === "string" && assetType ? `${assetType}:${r.name}` : null;
|
|
711
|
+
// Show-loop detection: if the agent has shown this asset 3+ times without
|
|
712
|
+
// writing anything, surface a warning so it stops cycling and acts.
|
|
713
|
+
const showLoopCount = typeof r.showLoopWarning === "number" ? r.showLoopWarning : 0;
|
|
714
|
+
if (showLoopCount >= 3) {
|
|
715
|
+
lines.push("");
|
|
716
|
+
lines.push(`WARNING: You have shown this asset ${showLoopCount} times without completing the task.`);
|
|
717
|
+
lines.push("Stop re-reading — you have the information you need. Act on it now:");
|
|
718
|
+
lines.push(" - Write your output file using the content above.");
|
|
719
|
+
lines.push(` - If this asset does not contain what you need, run \`akm feedback '${assetRef ?? "<ref>"}' --negative\` and search for a different asset.`);
|
|
720
|
+
}
|
|
721
|
+
if (assetType === "skill" || assetType === "knowledge") {
|
|
722
|
+
const activeRun = r.activeRun;
|
|
723
|
+
if (activeRun) {
|
|
724
|
+
// Active workflow: redirect agent to workflow commands instead of direct apply
|
|
725
|
+
lines.unshift(` akm workflow complete '${activeRun.runId}'${activeRun.stepId ? ` --step '${activeRun.stepId}'` : ""}`);
|
|
726
|
+
lines.unshift("Read this schema, then follow your workflow step's instructions to edit the workspace file. When done, mark the step complete:");
|
|
727
|
+
lines.unshift(`WORKFLOW ACTIVE — schema shown as reference (run: ${activeRun.runId})`);
|
|
728
|
+
lines.unshift("---");
|
|
729
|
+
lines.unshift("");
|
|
730
|
+
// Still show feedback line at the end but skip the APPLY directive
|
|
731
|
+
lines.push("");
|
|
732
|
+
lines.push(`Run \`akm feedback ${assetRef ? `'${assetRef}'` : "<ref>"} --positive\` if the step succeeds, or \`--negative\` if this schema did not help.`);
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
// No active workflow: show the APPLY directive. Branch on whether this
|
|
736
|
+
// skill primarily teaches CLI commands (shell output) vs YAML schema.
|
|
737
|
+
const preApplyLines = [...lines];
|
|
738
|
+
lines.push("");
|
|
739
|
+
lines.push("---");
|
|
740
|
+
if (isCommandOutputSkill(preApplyLines)) {
|
|
741
|
+
lines.push("APPLY (only if no workflow step is required for this task):");
|
|
742
|
+
lines.push(" 1. Identify the output file from README.md (typically commands.txt).");
|
|
743
|
+
lines.push(" 2. Write the exact command syntax from the code blocks above — replace every placeholder (`<name>`, `<value>`) with a real, concrete value from your task context. Do not write placeholder text.");
|
|
744
|
+
lines.push(" 3. Each command should be on a single line (no backslash line continuation unless the verifier expects it).");
|
|
745
|
+
lines.push(`Run \`akm feedback ${assetRef ? `'${assetRef}'` : "<ref>"} --positive\` after the task succeeds, or \`--negative\` if this reference did not contain the needed command syntax.`);
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
lines.push("APPLY (only if no workflow step is required for this task):");
|
|
749
|
+
lines.push(" 1. Identify the target file from README.md — write or edit it. If the file does not yet exist, CREATE it with the full structure from this schema.");
|
|
750
|
+
lines.push(" 2. Add/edit the fields shown above using the exact field names from this schema.");
|
|
751
|
+
lines.push(" 3. COPY the exact YAML structure and field names from the code blocks above — do not substitute synonyms or invent nesting. Replace every placeholder value with a real, concrete value from your task context. Do not leave any field as null, empty, or a placeholder.");
|
|
752
|
+
lines.push(`Run \`akm feedback ${assetRef ? `'${assetRef}'` : "<ref>"} --positive\` after the task succeeds, or \`--negative\` if the task fails after following this guidance.`);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
else if (assetType === "workflow") {
|
|
757
|
+
const workflowName = typeof r.name === "string" ? r.name : null;
|
|
758
|
+
const workflowRef = workflowName ? `workflow:${workflowName}` : "<ref>";
|
|
759
|
+
// Insert action directive BEFORE the workflow content by prepending to lines at the
|
|
760
|
+
// separator position. We find where the header ends and insert after the first `---`.
|
|
761
|
+
// Since lines already contain the full content at this point, we locate the insertion
|
|
762
|
+
// index: right after the first `---` separator if present, otherwise after the header.
|
|
763
|
+
const separatorIdx = lines.indexOf("---");
|
|
764
|
+
const insertIdx = separatorIdx >= 0 ? separatorIdx + 1 : r.type || r.name ? 1 : 0;
|
|
765
|
+
const actionDirective = [
|
|
766
|
+
`ACTION REQUIRED: Do not execute steps manually from this output.`,
|
|
767
|
+
`Run \`akm workflow next '${workflowRef}'\` to get your current step with exact instructions.`,
|
|
768
|
+
"---",
|
|
769
|
+
];
|
|
770
|
+
lines.splice(insertIdx, 0, "", ...actionDirective);
|
|
771
|
+
lines.push("");
|
|
772
|
+
lines.push("---");
|
|
773
|
+
lines.push(`NEXT STEP: Run \`akm workflow next '${workflowRef}'\` to see the current workflow step.`);
|
|
774
|
+
lines.push("Do not edit workspace files before completing each step with `akm workflow complete`.");
|
|
775
|
+
}
|
|
695
776
|
return lines.length > 0 ? lines.join("\n") : null;
|
|
696
777
|
}
|
|
778
|
+
/**
|
|
779
|
+
* Detect whether a skill's rendered content primarily teaches CLI commands
|
|
780
|
+
* rather than YAML schema. Used to select the right APPLY directive variant.
|
|
781
|
+
*
|
|
782
|
+
* Heuristic: count code-block lines that start with known shell command
|
|
783
|
+
* prefixes vs lines that look like YAML key-value pairs. If CLI lines
|
|
784
|
+
* outnumber YAML lines (and there is at least one CLI line), treat the
|
|
785
|
+
* skill as command-output.
|
|
786
|
+
*/
|
|
787
|
+
function isCommandOutputSkill(lines) {
|
|
788
|
+
const codeLines = lines.filter((l) => l.startsWith(" ") || l.startsWith("\t") || /^`/.test(l));
|
|
789
|
+
const cliPattern = /^(az |kubectl |docker |git |helm |terraform |aws |gcloud )/;
|
|
790
|
+
const yamlPattern = /^\s+\w+:/;
|
|
791
|
+
const cliCount = codeLines.filter((l) => cliPattern.test(l.trim())).length;
|
|
792
|
+
const yamlCount = codeLines.filter((l) => yamlPattern.test(l)).length;
|
|
793
|
+
return cliCount > yamlCount && cliCount > 0;
|
|
794
|
+
}
|
|
697
795
|
export function formatWorkflowListPlain(result) {
|
|
698
796
|
const runs = Array.isArray(result.runs) ? result.runs : [];
|
|
699
797
|
if (runs.length === 0) {
|
|
@@ -747,7 +845,10 @@ export function formatWorkflowNextPlain(result) {
|
|
|
747
845
|
const lines = base ? [base, "", "next:"] : ["next:"];
|
|
748
846
|
lines.push(` ${String(step.title ?? "Untitled step")} [${String(step.id ?? "unknown")}]`);
|
|
749
847
|
if (typeof step.instructions === "string" && step.instructions.trim()) {
|
|
750
|
-
|
|
848
|
+
const instrLines = step.instructions.trim().split("\n");
|
|
849
|
+
lines.push(` instructions: ${instrLines[0]}`);
|
|
850
|
+
for (const instrLine of instrLines.slice(1))
|
|
851
|
+
lines.push(` ${instrLine}`);
|
|
751
852
|
}
|
|
752
853
|
const completion = Array.isArray(step.completionCriteria) ? step.completionCriteria : [];
|
|
753
854
|
if (completion.length > 0) {
|
|
@@ -756,6 +857,25 @@ export function formatWorkflowNextPlain(result) {
|
|
|
756
857
|
lines.push(` - ${String(criterion)}`);
|
|
757
858
|
}
|
|
758
859
|
}
|
|
860
|
+
// T2-3: surface run-id as labeled field
|
|
861
|
+
const run = typeof result.run === "object" && result.run !== null ? result.run : undefined;
|
|
862
|
+
const runId = typeof run?.id === "string" ? run.id : null;
|
|
863
|
+
const stepId = typeof step?.id === "string" ? step.id : null;
|
|
864
|
+
if (runId) {
|
|
865
|
+
lines.push("");
|
|
866
|
+
lines.push(`runId: ${runId}`);
|
|
867
|
+
}
|
|
868
|
+
// T1-6: complete command
|
|
869
|
+
if (runId && stepId) {
|
|
870
|
+
lines.push("");
|
|
871
|
+
lines.push("COMPLETE THIS STEP:");
|
|
872
|
+
lines.push(` akm workflow complete '${runId}' --step '${stepId}'`);
|
|
873
|
+
}
|
|
874
|
+
else if (runId) {
|
|
875
|
+
lines.push("");
|
|
876
|
+
lines.push("COMPLETE THIS STEP:");
|
|
877
|
+
lines.push(` akm workflow complete '${runId}' --step '<step-id>'`);
|
|
878
|
+
}
|
|
759
879
|
return lines.join("\n");
|
|
760
880
|
}
|
|
761
881
|
export function formatSearchPlain(r, detail) {
|
|
@@ -763,7 +883,13 @@ export function formatSearchPlain(r, detail) {
|
|
|
763
883
|
const registryHits = r.registryHits ?? [];
|
|
764
884
|
const allHits = [...hits, ...registryHits];
|
|
765
885
|
if (allHits.length === 0) {
|
|
766
|
-
|
|
886
|
+
const warnings = Array.isArray(r.warnings) ? r.warnings : [];
|
|
887
|
+
const hasSetupWarning = warnings.some((w) => String(w).toLowerCase().includes("no stash") || String(w).toLowerCase().includes("not configured"));
|
|
888
|
+
if (hasSetupWarning) {
|
|
889
|
+
return "No stash configured. Run `akm init` to create your working stash, then `akm index` to build the search index.";
|
|
890
|
+
}
|
|
891
|
+
const base = r.tip ? String(r.tip) : "No matches found.";
|
|
892
|
+
return `${base}\nTry:\n akm search '<broader-term>' # fewer keywords\n akm list # see all configured sources\n akm curate '<query>' # let akm select the best match`;
|
|
767
893
|
}
|
|
768
894
|
const lines = [];
|
|
769
895
|
for (const hit of allHits) {
|
|
@@ -822,6 +948,27 @@ export function formatSearchPlain(r, detail) {
|
|
|
822
948
|
if (parts.length > 0)
|
|
823
949
|
lines.push(`timing: ${parts.join(", ")}`);
|
|
824
950
|
}
|
|
951
|
+
// REC-02: When stash hits exist, tell the agent the next required step so it
|
|
952
|
+
// doesn't skip `akm show` and write from training memory instead.
|
|
953
|
+
if (hits.length >= 1) {
|
|
954
|
+
// Prefer skill/command/agent type hits for the "Next:" ref — knowledge docs are
|
|
955
|
+
// supplementary context, not the authoritative schema agents should load first.
|
|
956
|
+
const preferredHit = hits.find((h) => h.type === "skill" || h.type === "command" || h.type === "agent") ?? hits[0];
|
|
957
|
+
const topRef = typeof preferredHit.ref === "string" ? preferredHit.ref : null;
|
|
958
|
+
const hasWorkflowHit = hits.some((h) => h.type === "workflow");
|
|
959
|
+
if (topRef) {
|
|
960
|
+
if (hasWorkflowHit) {
|
|
961
|
+
const workflowRef = hits.find((h) => h.type === "workflow");
|
|
962
|
+
const wfRef = workflowRef && typeof workflowRef.ref === "string" ? workflowRef.ref : topRef;
|
|
963
|
+
lines.push(`Next: akm show '${topRef}' | To start a workflow: akm workflow next '${wfRef}'`);
|
|
964
|
+
lines.push("After running workflow next: follow each step and run `akm workflow complete <run-id> --step <step-id>` when done.");
|
|
965
|
+
}
|
|
966
|
+
else {
|
|
967
|
+
lines.push(`Next: akm show '${topRef}'`);
|
|
968
|
+
lines.push("After reading the asset: check whether a workflow applies before editing — if so, use `akm workflow next` instead.");
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
825
972
|
return lines.join("\n").trimEnd();
|
|
826
973
|
}
|
|
827
974
|
export function formatWikiListPlain(r) {
|
|
@@ -959,5 +1106,11 @@ export function formatCuratePlain(r, detail) {
|
|
|
959
1106
|
lines.push(`- ${String(warning)}`);
|
|
960
1107
|
}
|
|
961
1108
|
}
|
|
1109
|
+
lines.push("");
|
|
1110
|
+
lines.push("Next steps:");
|
|
1111
|
+
lines.push(" 1. Run `akm show <ref>` for the best result above to read the full schema.");
|
|
1112
|
+
lines.push(" 2. Edit the workspace file using the schema field names and your task-specific values.");
|
|
1113
|
+
lines.push(" 3. Run `akm feedback <ref> --positive` when the task succeeds.");
|
|
1114
|
+
lines.push("To search further: akm search '<query>'");
|
|
962
1115
|
return lines.join("\n");
|
|
963
1116
|
}
|
|
@@ -19,15 +19,16 @@ import { detectStashRoot } from "../sources/providers/provider-utils";
|
|
|
19
19
|
import { extractTarGzSecure } from "../sources/providers/tar-utils";
|
|
20
20
|
import { parseRegistryIndex } from "./providers/static-index";
|
|
21
21
|
const DEFAULT_NPM_REGISTRY_BASE = "https://registry.npmjs.org";
|
|
22
|
-
const DEFAULT_MANUAL_ENTRIES_PATH = path.resolve("manual-entries.json");
|
|
23
|
-
const DEFAULT_OUTPUT_PATH = path.resolve("index.json");
|
|
24
22
|
const REQUIRED_KEYWORDS = ["akm-stash"];
|
|
25
23
|
const GITHUB_TOPICS = ["akm-stash"];
|
|
26
24
|
const EXCLUDED_REPOS = new Set(["itlackey/akm"]);
|
|
27
25
|
const EXCLUDED_NPM_PACKAGES = new Set(["akm-cli"]);
|
|
28
26
|
const EMPTY_INSPECTION = {};
|
|
27
|
+
function getDefaultRegistryBuildDir() {
|
|
28
|
+
return path.join(getCacheDir(), "registry-build");
|
|
29
|
+
}
|
|
29
30
|
export async function buildRegistryIndex(options) {
|
|
30
|
-
const manualEntriesPath = path.resolve(options?.manualEntriesPath ??
|
|
31
|
+
const manualEntriesPath = path.resolve(options?.manualEntriesPath ?? path.join(getDefaultRegistryBuildDir(), "manual-entries.json"));
|
|
31
32
|
const npmRegistryBase = trimTrailingSlash(options?.npmRegistryBase ?? DEFAULT_NPM_REGISTRY_BASE);
|
|
32
33
|
const githubApiBase = trimTrailingSlash(options?.githubApiBase ?? GITHUB_API_BASE);
|
|
33
34
|
const [manualKits, npmKits, githubKits] = await Promise.all([
|
|
@@ -55,7 +56,7 @@ export async function buildRegistryIndex(options) {
|
|
|
55
56
|
};
|
|
56
57
|
}
|
|
57
58
|
export function writeRegistryIndex(index, outPath) {
|
|
58
|
-
const resolved = path.resolve(outPath ??
|
|
59
|
+
const resolved = path.resolve(outPath ?? path.join(getDefaultRegistryBuildDir(), "index.json"));
|
|
59
60
|
fs.mkdirSync(path.dirname(resolved), { recursive: true });
|
|
60
61
|
fs.writeFileSync(resolved, `${JSON.stringify(index, null, 2)}\n`, "utf8");
|
|
61
62
|
return resolved;
|
|
@@ -190,7 +190,9 @@ export function parseRegistryIndex(data) {
|
|
|
190
190
|
if (typeof data !== "object" || data === null || Array.isArray(data))
|
|
191
191
|
return null;
|
|
192
192
|
const obj = data;
|
|
193
|
-
|
|
193
|
+
// Accept version 2 and 3 — both use the same stashes[] wire format.
|
|
194
|
+
// The live official registry currently publishes version 2.
|
|
195
|
+
if (typeof obj.version !== "number" || (obj.version !== 2 && obj.version !== 3))
|
|
194
196
|
return null;
|
|
195
197
|
if (typeof obj.updatedAt !== "string")
|
|
196
198
|
return null;
|
|
@@ -283,6 +283,7 @@ async function stepOllama(current) {
|
|
|
283
283
|
mxbai: 1024,
|
|
284
284
|
minilm: 384,
|
|
285
285
|
bge: 384,
|
|
286
|
+
qwen3: 1024,
|
|
286
287
|
};
|
|
287
288
|
const guessedDim = Object.entries(knownDims).find(([k]) => embChoice.includes(k))?.[1] ?? 384;
|
|
288
289
|
p.note("Embedding dimension must match the model. Common values: 384 (BGE small), 768 (BGE base), 1024 (BGE large). Press Enter to accept the detected default.", "Embedding dimension");
|
|
@@ -302,6 +303,14 @@ async function stepOllama(current) {
|
|
|
302
303
|
model: embChoice,
|
|
303
304
|
dimension: Number(dimChoice),
|
|
304
305
|
};
|
|
306
|
+
p.note([
|
|
307
|
+
"Recommended Qwen embedding models (modern, high context support):",
|
|
308
|
+
" • qwen3-embedding-0.6b — fast and lightweight (ollama pull qwen3-embedding-0.6b)",
|
|
309
|
+
" • qwen3-embedding-4b — higher quality (ollama pull qwen3-embedding-4b)",
|
|
310
|
+
"",
|
|
311
|
+
"For long documents (wiki pages, large files), set context length to avoid 400 errors:",
|
|
312
|
+
" akm config set embedding.contextLength 8192",
|
|
313
|
+
].join("\n"), "Embedding tips");
|
|
305
314
|
}
|
|
306
315
|
// else: undefined → use built-in local
|
|
307
316
|
// Surface Ollama details to the LLM step so it can offer Ollama as a preset.
|
|
@@ -11,6 +11,32 @@
|
|
|
11
11
|
* Principle: "akm surfaces. The agent writes." akm owns lifecycle, raw-slug
|
|
12
12
|
* generation, structural lint, and `index.md` regeneration. The agent uses
|
|
13
13
|
* its native file tools for every other page operation.
|
|
14
|
+
*
|
|
15
|
+
* ## Canonical wiki content contract
|
|
16
|
+
*
|
|
17
|
+
* The three "infrastructure" files at the wiki root — `schema.md`, `index.md`,
|
|
18
|
+
* and `log.md` — are excluded from all user-facing content surfaces:
|
|
19
|
+
*
|
|
20
|
+
* | Surface | schema/index/log | raw/<slug>.md | <page>.md |
|
|
21
|
+
* | -------------------- | ---------------- | ------------- | --------- |
|
|
22
|
+
* | `wiki pages` | excluded | included | included |
|
|
23
|
+
* | scoped wiki search | excluded | included | included |
|
|
24
|
+
* | stash-wide FTS index | excluded | included | included |
|
|
25
|
+
* | `wiki lint` | excluded | tracked | tracked |
|
|
26
|
+
*
|
|
27
|
+
* `raw/` files are first-class addressable content (`wiki:<n>/raw/<slug>`),
|
|
28
|
+
* searchable, and listed. They are NOT authored pages — they are source
|
|
29
|
+
* material the agent turns into pages. `lint` tracks whether each raw file
|
|
30
|
+
* has been cited by a page's `sources:` frontmatter field.
|
|
31
|
+
*
|
|
32
|
+
* ## Regeneration contract
|
|
33
|
+
*
|
|
34
|
+
* `regenerateWikiIndex` / `regenerateAllWikiIndexes` apply ONLY to
|
|
35
|
+
* stash-owned wikis (directories under `<stashDir>/wikis/`). External wikis
|
|
36
|
+
* registered via `akm wiki register` are read-only caches; mutating their
|
|
37
|
+
* `index.md` would corrupt source-of-truth content that akm does not own.
|
|
38
|
+
* The indexer therefore calls `regenerateAllWikiIndexes(stashDir)` — which
|
|
39
|
+
* only iterates `<stashDir>/wikis/` — and never touches registered sources.
|
|
14
40
|
*/
|
|
15
41
|
import fs from "node:fs";
|
|
16
42
|
import path from "node:path";
|
|
@@ -496,10 +522,15 @@ function readPageFrontmatter(absPath) {
|
|
|
496
522
|
return out;
|
|
497
523
|
}
|
|
498
524
|
/**
|
|
499
|
-
* List
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
525
|
+
* List all addressable wiki content entries.
|
|
526
|
+
*
|
|
527
|
+
* Per the canonical wiki contract: `schema.md`, `index.md`, and `log.md` at
|
|
528
|
+
* the wiki root are infrastructure files and are excluded. Everything else —
|
|
529
|
+
* authored pages AND `raw/<slug>.md` sources — is included and addressable as
|
|
530
|
+
* `wiki:<name>/<rel-path-without-.md>`.
|
|
531
|
+
*
|
|
532
|
+
* Callers that need to distinguish authored pages from raw sources should
|
|
533
|
+
* check whether the returned `name` starts with `"raw/"`.
|
|
503
534
|
*/
|
|
504
535
|
export function listPages(stashDir, name) {
|
|
505
536
|
const wikiDir = resolveWikiSource(stashDir, name).path;
|
|
@@ -521,6 +552,10 @@ export function listPages(stashDir, name) {
|
|
|
521
552
|
* Uses `akmSearch({ type: "wiki" })` to reuse the full FTS5+boost pipeline,
|
|
522
553
|
* then drops hits that aren't inside `wikis/<name>/`. No parallel scorer.
|
|
523
554
|
*
|
|
555
|
+
* Per the canonical wiki contract: infrastructure files (`schema.md`,
|
|
556
|
+
* `index.md`, `log.md`) at the wiki root are excluded. `raw/<slug>.md`
|
|
557
|
+
* sources are included — they are first-class addressable content.
|
|
558
|
+
*
|
|
524
559
|
* When the index is absent (e.g. fresh stash), `akmSearch` falls back to its
|
|
525
560
|
* substring walker; hits still come through path-filtered here.
|
|
526
561
|
*/
|
|
@@ -795,7 +830,13 @@ export function lintWiki(stashDir, name) {
|
|
|
795
830
|
}
|
|
796
831
|
// ── Index regeneration ─────────────────────────────────────────────────────
|
|
797
832
|
/**
|
|
798
|
-
* Rebuild a wiki's `index.md` from its pages' frontmatter.
|
|
833
|
+
* Rebuild a stash-owned wiki's `index.md` from its pages' frontmatter.
|
|
834
|
+
*
|
|
835
|
+
* This function uses `resolveWikiDir` (not `resolveWikiSource`) so it only
|
|
836
|
+
* ever operates on the stash-owned path `<stashDir>/wikis/<name>/`. External
|
|
837
|
+
* wikis registered via `akm wiki register` are never regenerated here — they
|
|
838
|
+
* are read-only caches. See the canonical wiki contract at the top of this
|
|
839
|
+
* file for the full regeneration rule.
|
|
799
840
|
*
|
|
800
841
|
* Pages are grouped by `pageKind` (falling back to `uncategorised`) and
|
|
801
842
|
* listed alphabetically inside each group. If the wiki directory doesn't
|
|
@@ -861,7 +902,14 @@ export function regenerateWikiIndex(stashDir, name) {
|
|
|
861
902
|
}
|
|
862
903
|
}
|
|
863
904
|
/**
|
|
864
|
-
* Regenerate `index.md` for every wiki
|
|
905
|
+
* Regenerate `index.md` for every stash-owned wiki under `<stashDir>/wikis/`.
|
|
906
|
+
*
|
|
907
|
+
* Per the canonical wiki contract: regeneration applies ONLY to stash-owned
|
|
908
|
+
* wikis. External wikis registered via `akm wiki register` are read-only
|
|
909
|
+
* caches whose source-of-truth lives outside this stash; mutating their
|
|
910
|
+
* `index.md` would corrupt content that akm does not own. Those wikis
|
|
911
|
+
* therefore appear only in the FTS index (read), never in regeneration
|
|
912
|
+
* (write).
|
|
865
913
|
*
|
|
866
914
|
* Called from `akmIndex()` as a side effect after the FTS rebuild. Never
|
|
867
915
|
* throws; returns the list of wiki names that were regenerated.
|
|
@@ -3,6 +3,7 @@ import fs from "node:fs";
|
|
|
3
3
|
import { parseAssetRef } from "../core/asset-ref";
|
|
4
4
|
import { loadConfig } from "../core/config";
|
|
5
5
|
import { NotFoundError, UsageError } from "../core/errors";
|
|
6
|
+
import { appendEvent } from "../core/events";
|
|
6
7
|
import { getDbPath } from "../core/paths";
|
|
7
8
|
import { closeDatabase, openDatabase } from "../indexer/db";
|
|
8
9
|
import { resolveSourceEntries } from "../indexer/search-source";
|
|
@@ -32,7 +33,13 @@ export async function startWorkflowRun(ref, params = {}) {
|
|
|
32
33
|
insertStep.run(runId, step.id, step.title, step.instructions, step.completionCriteria ? JSON.stringify(step.completionCriteria) : null, step.sequenceIndex ?? 0);
|
|
33
34
|
}
|
|
34
35
|
})();
|
|
35
|
-
|
|
36
|
+
const result = getWorkflowStatus(runId);
|
|
37
|
+
appendEvent({
|
|
38
|
+
eventType: "workflow_started",
|
|
39
|
+
ref: ref,
|
|
40
|
+
metadata: { runId: result.run.id, title: result.run.workflowTitle },
|
|
41
|
+
});
|
|
42
|
+
return result;
|
|
36
43
|
}
|
|
37
44
|
finally {
|
|
38
45
|
closeWorkflowDatabase(workflowDb);
|
|
@@ -173,7 +180,16 @@ export function completeWorkflowStep(input) {
|
|
|
173
180
|
completed_at: state.completedAt,
|
|
174
181
|
};
|
|
175
182
|
})();
|
|
176
|
-
|
|
183
|
+
const detail = buildWorkflowRunDetail(updatedRun, refreshedSteps);
|
|
184
|
+
appendEvent({
|
|
185
|
+
eventType: "workflow_step_completed",
|
|
186
|
+
ref: detail.run.workflowRef,
|
|
187
|
+
metadata: { runId: input.runId, stepId: input.stepId, notes: input.notes },
|
|
188
|
+
});
|
|
189
|
+
if (detail.run.status === "completed") {
|
|
190
|
+
appendEvent({ eventType: "workflow_finished", ref: detail.run.workflowRef, metadata: { runId: input.runId } });
|
|
191
|
+
}
|
|
192
|
+
return detail;
|
|
177
193
|
}
|
|
178
194
|
finally {
|
|
179
195
|
closeWorkflowDatabase(workflowDb);
|
|
@@ -187,6 +203,9 @@ async function resolveRunSpecifier(db, specifier, params) {
|
|
|
187
203
|
}
|
|
188
204
|
return { run: explicitRun, autoStarted: false };
|
|
189
205
|
}
|
|
206
|
+
if (!specifier.includes(":")) {
|
|
207
|
+
throw new NotFoundError(`Workflow run "${specifier}" not found.`, "WORKFLOW_NOT_FOUND");
|
|
208
|
+
}
|
|
190
209
|
const parsed = parseAssetRef(specifier);
|
|
191
210
|
if (parsed.type !== "workflow") {
|
|
192
211
|
throw new UsageError(`Expected a workflow ref or workflow run id, got "${specifier}".`);
|
|
@@ -316,7 +335,7 @@ function resolveWorkflowEntryId(sourcePath, ref) {
|
|
|
316
335
|
function readWorkflowRun(db, runId) {
|
|
317
336
|
const run = db.prepare("SELECT * FROM workflow_runs WHERE id = ?").get(runId);
|
|
318
337
|
if (!run) {
|
|
319
|
-
throw new NotFoundError(`Workflow run not found
|
|
338
|
+
throw new NotFoundError(`Workflow run "${runId}" not found.`, "WORKFLOW_NOT_FOUND");
|
|
320
339
|
}
|
|
321
340
|
return run;
|
|
322
341
|
}
|
|
@@ -416,3 +435,18 @@ function parseJsonArray(value) {
|
|
|
416
435
|
}
|
|
417
436
|
return undefined;
|
|
418
437
|
}
|
|
438
|
+
export function getActiveWorkflowRun() {
|
|
439
|
+
try {
|
|
440
|
+
const workflowDb = openWorkflowDatabase();
|
|
441
|
+
const row = workflowDb
|
|
442
|
+
.query("SELECT id, current_step_id, workflow_ref FROM workflow_runs WHERE status IN ('active', 'blocked') ORDER BY updated_at DESC LIMIT 1")
|
|
443
|
+
.get();
|
|
444
|
+
closeWorkflowDatabase(workflowDb);
|
|
445
|
+
if (!row)
|
|
446
|
+
return null;
|
|
447
|
+
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
|
+
}
|
|
452
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "akm (Agent Kit Manager) — A package manager for AI agent skills, commands, tools, and knowledge. Works with Claude Code, OpenCode, Cursor, and any AI coding assistant.",
|
|
6
6
|
"keywords": [
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"akm": "dist/cli.js"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
|
-
"build": "rm -rf dist && bun run tsc --project ./tsconfig.json
|
|
45
|
+
"build": "rm -rf dist && bun run tsc --project ./tsconfig.build.json",
|
|
46
46
|
"check": "bun run lint && bunx tsc --noEmit && bun test ./tests",
|
|
47
47
|
"check:changed": "bun test tests/output-baseline.test.ts tests/e2e.test.ts tests/stash-search.test.ts && bun run lint && bunx tsc --noEmit",
|
|
48
48
|
"test": "bun test ./tests",
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"access": "public"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@biomejs/biome": "^2.4.
|
|
61
|
-
"@types/node": "^22.
|
|
62
|
-
"bun-types": "^1.3.
|
|
60
|
+
"@biomejs/biome": "^2.4.14",
|
|
61
|
+
"@types/node": "^22.19.17",
|
|
62
|
+
"bun-types": "^1.3.13",
|
|
63
63
|
"typescript": "^5.9.3"
|
|
64
64
|
},
|
|
65
65
|
"optionalDependencies": {
|
|
@@ -70,9 +70,9 @@
|
|
|
70
70
|
"bun": ">=1.0.0"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@clack/prompts": "^1.
|
|
74
|
-
"citty": "^0.2.
|
|
73
|
+
"@clack/prompts": "^1.3.0",
|
|
74
|
+
"citty": "^0.2.2",
|
|
75
75
|
"dotenv": "^17.4.2",
|
|
76
|
-
"yaml": "^2.8.
|
|
76
|
+
"yaml": "^2.8.4"
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { afterAll, afterEach, describe, expect, test } from "bun:test";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
|
-
import fs from "node:fs";
|
|
4
|
-
import os from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
const CLI = path.join(__dirname, "..", "src", "cli.ts");
|
|
7
|
-
const tempDirs = [];
|
|
8
|
-
const servers = [];
|
|
9
|
-
const CLI_TIMEOUT_MS = 30_000;
|
|
10
|
-
const TEST_TIMEOUT_MS = 60_000;
|
|
11
|
-
function makeTempDir(prefix) {
|
|
12
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
13
|
-
tempDirs.push(dir);
|
|
14
|
-
return dir;
|
|
15
|
-
}
|
|
16
|
-
function createWorkingStash() {
|
|
17
|
-
const dir = makeTempDir("akm-add-website-stash-");
|
|
18
|
-
for (const sub of ["skills", "commands", "agents", "knowledge", "scripts"]) {
|
|
19
|
-
fs.mkdirSync(path.join(dir, sub), { recursive: true });
|
|
20
|
-
}
|
|
21
|
-
return dir;
|
|
22
|
-
}
|
|
23
|
-
function serveWebsite() {
|
|
24
|
-
const server = Bun.serve({
|
|
25
|
-
port: 0,
|
|
26
|
-
fetch(request) {
|
|
27
|
-
const url = new URL(request.url);
|
|
28
|
-
if (url.pathname === "/") {
|
|
29
|
-
return new Response("<html><head><title>Example Docs</title></head><body><h1>Example Docs</h1><p>Welcome to the docs.</p><a href='/getting-started'>Getting started</a></body></html>", {
|
|
30
|
-
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
if (url.pathname === "/getting-started") {
|
|
34
|
-
return new Response("<html><body><h1>Getting started</h1><p>Run setup first.</p></body></html>", {
|
|
35
|
-
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
return new Response("not found", { status: 404 });
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
servers.push(server);
|
|
42
|
-
return `http://127.0.0.1:${server.port}`;
|
|
43
|
-
}
|
|
44
|
-
afterEach(() => {
|
|
45
|
-
for (const server of servers.splice(0)) {
|
|
46
|
-
server.stop(true);
|
|
47
|
-
}
|
|
48
|
-
for (const dir of tempDirs.splice(0)) {
|
|
49
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
afterAll(() => {
|
|
53
|
-
for (const server of servers.splice(0)) {
|
|
54
|
-
server.stop(true);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
describe("akm add website", () => {
|
|
58
|
-
test("adds a website stash source, caches markdown, and indexes it", async () => {
|
|
59
|
-
const stashDir = createWorkingStash();
|
|
60
|
-
const xdgCache = makeTempDir("akm-add-website-cache-");
|
|
61
|
-
const xdgConfig = makeTempDir("akm-add-website-config-");
|
|
62
|
-
const websiteUrl = serveWebsite();
|
|
63
|
-
const configDir = path.join(xdgConfig, "akm");
|
|
64
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
65
|
-
fs.writeFileSync(path.join(configDir, "config.json"), `${JSON.stringify({ semanticSearchMode: "off" }, null, 2)}\n`);
|
|
66
|
-
const child = spawn("bun", [CLI, "add", websiteUrl, "--name", "docs-site", "--format=json"], {
|
|
67
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
68
|
-
env: {
|
|
69
|
-
...process.env,
|
|
70
|
-
AKM_STASH_DIR: stashDir,
|
|
71
|
-
XDG_CACHE_HOME: xdgCache,
|
|
72
|
-
XDG_CONFIG_HOME: xdgConfig,
|
|
73
|
-
},
|
|
74
|
-
});
|
|
75
|
-
let stdout = "";
|
|
76
|
-
let stderr = "";
|
|
77
|
-
child.stdout.on("data", (chunk) => {
|
|
78
|
-
stdout += String(chunk);
|
|
79
|
-
});
|
|
80
|
-
child.stderr.on("data", (chunk) => {
|
|
81
|
-
stderr += String(chunk);
|
|
82
|
-
});
|
|
83
|
-
const exitCode = await new Promise((resolve, reject) => {
|
|
84
|
-
const timer = setTimeout(() => {
|
|
85
|
-
child.kill("SIGKILL");
|
|
86
|
-
reject(new Error("CLI website add timed out"));
|
|
87
|
-
}, CLI_TIMEOUT_MS);
|
|
88
|
-
child.on("error", (err) => {
|
|
89
|
-
clearTimeout(timer);
|
|
90
|
-
reject(err);
|
|
91
|
-
});
|
|
92
|
-
child.on("close", (code) => {
|
|
93
|
-
clearTimeout(timer);
|
|
94
|
-
resolve(code ?? 1);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
expect(exitCode).toBe(0);
|
|
98
|
-
expect(stderr.trim()).toBe("");
|
|
99
|
-
const parsed = JSON.parse(stdout.trim());
|
|
100
|
-
const normalizedWebsiteUrl = `${websiteUrl}/`;
|
|
101
|
-
expect(parsed.sourceAdded).toBeDefined();
|
|
102
|
-
expect(parsed.sourceAdded?.type).toBe("website");
|
|
103
|
-
expect(parsed.sourceAdded?.url).toBe(normalizedWebsiteUrl);
|
|
104
|
-
expect(parsed.sourceAdded?.name).toBe("docs-site");
|
|
105
|
-
expect(parsed.index?.totalEntries).toBeGreaterThanOrEqual(2);
|
|
106
|
-
const configPath = path.join(xdgConfig, "akm", "config.json");
|
|
107
|
-
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
108
|
-
expect(config.sources).toContainEqual({
|
|
109
|
-
type: "website",
|
|
110
|
-
url: normalizedWebsiteUrl,
|
|
111
|
-
name: "docs-site",
|
|
112
|
-
});
|
|
113
|
-
expect(parsed.sourceAdded?.stashRoot).toBeDefined();
|
|
114
|
-
const knowledgeFiles = fs.readdirSync(path.join(parsed.sourceAdded?.stashRoot, "knowledge")).sort();
|
|
115
|
-
expect(knowledgeFiles).toEqual(["getting-started.md", "index.md"]);
|
|
116
|
-
const homeDoc = fs.readFileSync(path.join(parsed.sourceAdded?.stashRoot, "knowledge", "index.md"), "utf8");
|
|
117
|
-
expect(homeDoc).toContain("Example Docs");
|
|
118
|
-
}, { timeout: TEST_TIMEOUT_MS });
|
|
119
|
-
});
|