akm-cli 0.7.0 → 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/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 -996
- package/dist/tests/bench/cleanup-sigint.test.js +0 -83
- package/dist/tests/bench/cleanup.js +0 -234
- package/dist/tests/bench/cleanup.test.js +0 -166
- package/dist/tests/bench/cli.js +0 -1018
- package/dist/tests/bench/cli.test.js +0 -445
- package/dist/tests/bench/compare.test.js +0 -556
- package/dist/tests/bench/corpus.js +0 -317
- package/dist/tests/bench/corpus.test.js +0 -258
- package/dist/tests/bench/doctor.js +0 -525
- package/dist/tests/bench/driver.js +0 -401
- package/dist/tests/bench/driver.test.js +0 -584
- package/dist/tests/bench/environment.js +0 -233
- package/dist/tests/bench/environment.test.js +0 -199
- 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 -647
- package/dist/tests/bench/evolve.test.js +0 -624
- package/dist/tests/bench/failure-modes.test.js +0 -349
- package/dist/tests/bench/feedback-integrity.test.js +0 -457
- package/dist/tests/bench/leakage.test.js +0 -228
- package/dist/tests/bench/learning-curve.test.js +0 -134
- package/dist/tests/bench/metrics.js +0 -2395
- package/dist/tests/bench/metrics.test.js +0 -1150
- package/dist/tests/bench/no-os-tmpdir-invariant.test.js +0 -43
- package/dist/tests/bench/opencode-config.js +0 -194
- package/dist/tests/bench/opencode-config.test.js +0 -370
- package/dist/tests/bench/report.js +0 -1885
- package/dist/tests/bench/report.test.js +0 -1038
- package/dist/tests/bench/run-config.js +0 -355
- package/dist/tests/bench/run-config.test.js +0 -298
- package/dist/tests/bench/run-curate-test.js +0 -32
- package/dist/tests/bench/run-failing-tasks.js +0 -56
- package/dist/tests/bench/run-full-bench.js +0 -51
- package/dist/tests/bench/run-items36-targeted.js +0 -69
- package/dist/tests/bench/run-nano-quick.js +0 -42
- package/dist/tests/bench/run-waveg-targeted.js +0 -62
- package/dist/tests/bench/runner.js +0 -699
- 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 -131
- package/dist/tests/bench/trajectory.js +0 -116
- package/dist/tests/bench/trajectory.test.js +0 -127
- package/dist/tests/bench/verifier.js +0 -114
- 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 -345
- package/dist/tests/bench/workflow-spec.test.js +0 -363
- package/dist/tests/bench/workflow-trace.js +0 -472
- 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 -204
- package/dist/tests/commands/events.test.js +0 -370
- package/dist/tests/commands/history.test.js +0 -418
- 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 -569
- 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 -1419
- 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 -97
- 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 -570
- 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 -218
- package/dist/tests/output-shapes-unit.test.js +0 -478
- 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 -394
- 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 -238
- package/dist/tests/registry-resolve.test.js +0 -126
- package/dist/tests/registry-search.test.js +0 -923
- package/dist/tests/remember-frontmatter.test.js +0 -378
- 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 -286
- 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 -281
- 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 -395
- package/dist/tests/workflows/indexer-rejection.test.js +0 -213
- /package/dist/{src/cli.js → cli.js} +0 -0
- /package/dist/{src/commands → commands}/completions.js +0 -0
- /package/dist/{src/commands → commands}/config-cli.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}/history.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}/registry-search.js +0 -0
- /package/dist/{src/commands → commands}/remember.js +0 -0
- /package/dist/{src/commands → commands}/search.js +0 -0
- /package/dist/{src/commands → commands}/self-update.js +0 -0
- /package/dist/{src/commands → commands}/show.js +0 -0
- /package/dist/{src/commands → commands}/source-add.js +0 -0
- /package/dist/{src/commands → commands}/source-clone.js +0 -0
- /package/dist/{src/commands → commands}/source-manage.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}/config.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-search.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}/indexer.js +0 -0
- /package/dist/{src/indexer → indexer}/manifest.js +0 -0
- /package/dist/{src/indexer → indexer}/matchers.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}/search-source.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/profiles.js +0 -0
- /package/dist/{src/integrations → integrations}/agent/prompts.js +0 -0
- /package/dist/{src/integrations → integrations}/agent/spawn.js +0 -0
- /package/dist/{src/integrations → integrations}/github.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/remote.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}/cli-hints.js +0 -0
- /package/dist/{src/output → output}/context.js +0 -0
- /package/dist/{src/output → output}/renderers.js +0 -0
- /package/dist/{src/output → output}/shapes.js +0 -0
- /package/dist/{src/output → output}/text.js +0 -0
- /package/dist/{src/registry → registry}/build-index.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/static-index.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}/setup.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/wiki → wiki}/wiki.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}/runs.js +0 -0
- /package/dist/{src/workflows → workflows}/schema.js +0 -0
- /package/dist/{src/workflows → workflows}/validator.js +0 -0
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
|
-
});
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration test: the AkmConfig loader propagates the `agent` block
|
|
3
|
-
* through `loadConfig()` (and through the on-disk JSONC parser, exercising
|
|
4
|
-
* the `pickKnownKeys` path).
|
|
5
|
-
*
|
|
6
|
-
* The acceptance criterion "config schema accepts an optional agent block"
|
|
7
|
-
* lives at the loader boundary, not just the parser; this test pins the
|
|
8
|
-
* end-to-end shape.
|
|
9
|
-
*/
|
|
10
|
-
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
11
|
-
import fs from "node:fs";
|
|
12
|
-
import os from "node:os";
|
|
13
|
-
import path from "node:path";
|
|
14
|
-
let tmpHome;
|
|
15
|
-
let originalHome;
|
|
16
|
-
let originalXdg;
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "akm-agent-cfg-"));
|
|
19
|
-
originalHome = process.env.HOME;
|
|
20
|
-
originalXdg = process.env.XDG_CONFIG_HOME;
|
|
21
|
-
process.env.HOME = tmpHome;
|
|
22
|
-
process.env.XDG_CONFIG_HOME = path.join(tmpHome, ".config");
|
|
23
|
-
});
|
|
24
|
-
afterEach(() => {
|
|
25
|
-
if (originalHome === undefined)
|
|
26
|
-
delete process.env.HOME;
|
|
27
|
-
else
|
|
28
|
-
process.env.HOME = originalHome;
|
|
29
|
-
if (originalXdg === undefined)
|
|
30
|
-
delete process.env.XDG_CONFIG_HOME;
|
|
31
|
-
else
|
|
32
|
-
process.env.XDG_CONFIG_HOME = originalXdg;
|
|
33
|
-
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
34
|
-
});
|
|
35
|
-
describe("AkmConfig loader — agent block", () => {
|
|
36
|
-
test("loads agent.default + agent.profiles from disk", async () => {
|
|
37
|
-
const { getConfigPath, loadUserConfig, resetConfigCache } = await import("../../src/core/config");
|
|
38
|
-
const cfgPath = getConfigPath();
|
|
39
|
-
fs.mkdirSync(path.dirname(cfgPath), { recursive: true });
|
|
40
|
-
fs.writeFileSync(cfgPath, JSON.stringify({
|
|
41
|
-
semanticSearchMode: "auto",
|
|
42
|
-
agent: {
|
|
43
|
-
default: "claude",
|
|
44
|
-
timeoutMs: 45000,
|
|
45
|
-
profiles: {
|
|
46
|
-
claude: { args: ["--print"] },
|
|
47
|
-
rover: { bin: "rover-cli", parseOutput: "json" },
|
|
48
|
-
},
|
|
49
|
-
// Unknown key — must not throw at load.
|
|
50
|
-
mystery: 1,
|
|
51
|
-
},
|
|
52
|
-
}, null, 2));
|
|
53
|
-
resetConfigCache();
|
|
54
|
-
const cfg = loadUserConfig();
|
|
55
|
-
expect(cfg.agent?.default).toBe("claude");
|
|
56
|
-
expect(cfg.agent?.timeoutMs).toBe(45000);
|
|
57
|
-
expect(cfg.agent?.profiles?.claude?.args).toEqual(["--print"]);
|
|
58
|
-
expect(cfg.agent?.profiles?.rover?.bin).toBe("rover-cli");
|
|
59
|
-
expect(cfg.agent?.profiles?.rover?.parseOutput).toBe("json");
|
|
60
|
-
});
|
|
61
|
-
test("agent block absent → cfg.agent is undefined → requireAgentProfile throws", async () => {
|
|
62
|
-
const { loadUserConfig, resetConfigCache } = await import("../../src/core/config");
|
|
63
|
-
const { requireAgentProfile } = await import("../../src/integrations/agent/config");
|
|
64
|
-
const { ConfigError } = await import("../../src/core/errors");
|
|
65
|
-
resetConfigCache();
|
|
66
|
-
const cfg = loadUserConfig();
|
|
67
|
-
expect(cfg.agent).toBeUndefined();
|
|
68
|
-
expect(() => requireAgentProfile(cfg.agent)).toThrow(ConfigError);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for the `agent.*` config block parser and profile resolver.
|
|
3
|
-
*
|
|
4
|
-
* Acceptance coverage:
|
|
5
|
-
* • Parser accepts the documented shape.
|
|
6
|
-
* • Unknown keys are warn-and-ignored (no throw).
|
|
7
|
-
* • Built-in profiles resolve for opencode, claude, codex, gemini, aider.
|
|
8
|
-
* • Missing block surfaces a stable ConfigError via requireAgentProfile.
|
|
9
|
-
*/
|
|
10
|
-
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
11
|
-
const warnings = [];
|
|
12
|
-
// NOTE: `mock.module` in Bun is process-global — once installed it persists
|
|
13
|
-
// across test files run in the same `bun test` invocation. So this mock has
|
|
14
|
-
// to remain a faithful drop-in for the real `src/core/warn` module:
|
|
15
|
-
//
|
|
16
|
-
// 1. Every export that the real module ships must be represented here,
|
|
17
|
-
// otherwise tests in other files that import a missing export get
|
|
18
|
-
// `undefined` and silently break (issue #273).
|
|
19
|
-
// 2. `warn()` must also forward to `console.warn` so other test files that
|
|
20
|
-
// capture stderr (e.g. the noise-gate tests in
|
|
21
|
-
// tests/workflows/indexer-rejection.test.ts) continue to see the calls.
|
|
22
|
-
// We push to the local `warnings[]` so this file's own assertions still
|
|
23
|
-
// work, AND forward to `console.warn` so callers that intercept it
|
|
24
|
-
// still observe what was emitted.
|
|
25
|
-
let mockedQuiet = false;
|
|
26
|
-
let mockedVerbose = false;
|
|
27
|
-
mock.module("../../src/core/warn", () => ({
|
|
28
|
-
warn: (...args) => {
|
|
29
|
-
warnings.push(args.join(" "));
|
|
30
|
-
if (!mockedQuiet)
|
|
31
|
-
console.warn(...args);
|
|
32
|
-
},
|
|
33
|
-
warnVerbose: (...args) => {
|
|
34
|
-
if (!mockedVerbose)
|
|
35
|
-
return;
|
|
36
|
-
warnings.push(args.join(" "));
|
|
37
|
-
if (!mockedQuiet)
|
|
38
|
-
console.warn(...args);
|
|
39
|
-
},
|
|
40
|
-
setQuiet: (value) => {
|
|
41
|
-
mockedQuiet = value;
|
|
42
|
-
},
|
|
43
|
-
resetQuiet: () => {
|
|
44
|
-
mockedQuiet = false;
|
|
45
|
-
},
|
|
46
|
-
isQuiet: () => mockedQuiet,
|
|
47
|
-
setVerbose: (value) => {
|
|
48
|
-
mockedVerbose = value;
|
|
49
|
-
},
|
|
50
|
-
resetVerbose: () => {
|
|
51
|
-
mockedVerbose = false;
|
|
52
|
-
},
|
|
53
|
-
isVerbose: () => {
|
|
54
|
-
const env = process.env.AKM_VERBOSE?.trim().toLowerCase();
|
|
55
|
-
if (env === "1" || env === "true" || env === "yes" || env === "on")
|
|
56
|
-
return true;
|
|
57
|
-
if (env === "0" || env === "false" || env === "no" || env === "off")
|
|
58
|
-
return false;
|
|
59
|
-
return mockedVerbose;
|
|
60
|
-
},
|
|
61
|
-
}));
|
|
62
|
-
beforeEach(() => {
|
|
63
|
-
warnings.length = 0;
|
|
64
|
-
});
|
|
65
|
-
afterEach(() => {
|
|
66
|
-
warnings.length = 0;
|
|
67
|
-
});
|
|
68
|
-
describe("parseAgentConfig", () => {
|
|
69
|
-
test("returns undefined when block is absent", async () => {
|
|
70
|
-
const { parseAgentConfig } = await import("../../src/integrations/agent/config");
|
|
71
|
-
expect(parseAgentConfig(undefined)).toBeUndefined();
|
|
72
|
-
expect(warnings).toHaveLength(0);
|
|
73
|
-
});
|
|
74
|
-
test("warns and returns undefined for non-object root", async () => {
|
|
75
|
-
const { parseAgentConfig } = await import("../../src/integrations/agent/config");
|
|
76
|
-
expect(parseAgentConfig("oops")).toBeUndefined();
|
|
77
|
-
expect(warnings.some((w) => w.includes('"agent"'))).toBe(true);
|
|
78
|
-
});
|
|
79
|
-
test("accepts the documented shape", async () => {
|
|
80
|
-
const { parseAgentConfig } = await import("../../src/integrations/agent/config");
|
|
81
|
-
const parsed = parseAgentConfig({
|
|
82
|
-
default: "opencode",
|
|
83
|
-
timeoutMs: 30000,
|
|
84
|
-
profiles: {
|
|
85
|
-
opencode: { bin: "opencode", args: ["--non-interactive"], stdio: "captured" },
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
expect(parsed?.default).toBe("opencode");
|
|
89
|
-
expect(parsed?.timeoutMs).toBe(30000);
|
|
90
|
-
expect(parsed?.profiles?.opencode).toEqual({
|
|
91
|
-
bin: "opencode",
|
|
92
|
-
args: ["--non-interactive"],
|
|
93
|
-
stdio: "captured",
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
test("warn-and-ignore unknown top-level keys (no throw)", async () => {
|
|
97
|
-
const { parseAgentConfig } = await import("../../src/integrations/agent/config");
|
|
98
|
-
const parsed = parseAgentConfig({
|
|
99
|
-
default: "claude",
|
|
100
|
-
moonRoutingTable: { foo: "bar" }, // unknown
|
|
101
|
-
});
|
|
102
|
-
expect(parsed?.default).toBe("claude");
|
|
103
|
-
expect(warnings.some((w) => w.includes("moonRoutingTable"))).toBe(true);
|
|
104
|
-
});
|
|
105
|
-
test("warn-and-ignore unknown per-profile keys", async () => {
|
|
106
|
-
const { parseAgentConfig } = await import("../../src/integrations/agent/config");
|
|
107
|
-
const parsed = parseAgentConfig({
|
|
108
|
-
profiles: {
|
|
109
|
-
custom: { bin: "ok", quirks: "nope" },
|
|
110
|
-
},
|
|
111
|
-
});
|
|
112
|
-
expect(parsed?.profiles?.custom?.bin).toBe("ok");
|
|
113
|
-
expect(warnings.some((w) => w.includes("quirks"))).toBe(true);
|
|
114
|
-
});
|
|
115
|
-
test("warn-and-ignore malformed timeoutMs", async () => {
|
|
116
|
-
const { parseAgentConfig } = await import("../../src/integrations/agent/config");
|
|
117
|
-
const parsed = parseAgentConfig({ timeoutMs: "60s" });
|
|
118
|
-
expect(parsed?.timeoutMs).toBeUndefined();
|
|
119
|
-
expect(warnings.some((w) => w.includes("timeoutMs"))).toBe(true);
|
|
120
|
-
});
|
|
121
|
-
test("rejects non-string args entries", async () => {
|
|
122
|
-
const { parseAgentConfig } = await import("../../src/integrations/agent/config");
|
|
123
|
-
const parsed = parseAgentConfig({
|
|
124
|
-
profiles: { opencode: { args: ["--ok", 5, "--also-ok"] } },
|
|
125
|
-
});
|
|
126
|
-
expect(parsed?.profiles?.opencode?.args).toEqual(["--ok", "--also-ok"]);
|
|
127
|
-
expect(warnings.some((w) => w.includes("args"))).toBe(true);
|
|
128
|
-
});
|
|
129
|
-
test("rejects bad stdio mode", async () => {
|
|
130
|
-
const { parseAgentConfig } = await import("../../src/integrations/agent/config");
|
|
131
|
-
const parsed = parseAgentConfig({
|
|
132
|
-
profiles: { opencode: { stdio: "weird" } },
|
|
133
|
-
});
|
|
134
|
-
expect(parsed?.profiles?.opencode?.stdio).toBeUndefined();
|
|
135
|
-
expect(warnings.some((w) => w.includes("stdio"))).toBe(true);
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
describe("built-in profile resolution", () => {
|
|
139
|
-
test("resolves opencode, claude, codex, gemini, aider out of the box", async () => {
|
|
140
|
-
const { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile } = await import("../../src/integrations/agent/profiles");
|
|
141
|
-
expect(BUILTIN_AGENT_PROFILE_NAMES).toEqual(["aider", "claude", "codex", "gemini", "opencode"]);
|
|
142
|
-
for (const name of ["opencode", "claude", "codex", "gemini", "aider"]) {
|
|
143
|
-
const profile = getBuiltinAgentProfile(name);
|
|
144
|
-
expect(profile).toBeDefined();
|
|
145
|
-
expect(profile?.bin).toBeTruthy();
|
|
146
|
-
expect(profile?.envPassthrough).toContain("PATH");
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
test("user override merges on top of built-in", async () => {
|
|
150
|
-
const { resolveAgentProfile } = await import("../../src/integrations/agent/config");
|
|
151
|
-
const merged = resolveAgentProfile("opencode", { args: ["--scripted"], stdio: "captured" });
|
|
152
|
-
expect(merged?.bin).toBe("opencode"); // built-in default
|
|
153
|
-
expect(merged?.args).toEqual(["--scripted"]); // override
|
|
154
|
-
expect(merged?.stdio).toBe("captured"); // override
|
|
155
|
-
expect(merged?.envPassthrough).toContain("PATH"); // built-in retained
|
|
156
|
-
});
|
|
157
|
-
test("user-defined profile (no built-in) requires bin", async () => {
|
|
158
|
-
const { resolveAgentProfile } = await import("../../src/integrations/agent/config");
|
|
159
|
-
expect(resolveAgentProfile("rover", undefined)).toBeUndefined();
|
|
160
|
-
expect(resolveAgentProfile("rover", {})).toBeUndefined();
|
|
161
|
-
const ok = resolveAgentProfile("rover", { bin: "rover-cli", args: ["--silent"] });
|
|
162
|
-
expect(ok?.bin).toBe("rover-cli");
|
|
163
|
-
expect(ok?.args).toEqual(["--silent"]);
|
|
164
|
-
expect(ok?.stdio).toBe("captured");
|
|
165
|
-
});
|
|
166
|
-
test("envPassthrough merges base + override", async () => {
|
|
167
|
-
const { resolveAgentProfile } = await import("../../src/integrations/agent/config");
|
|
168
|
-
const merged = resolveAgentProfile("opencode", { envPassthrough: ["MY_TOKEN"] });
|
|
169
|
-
expect(merged?.envPassthrough).toContain("PATH"); // from built-in
|
|
170
|
-
expect(merged?.envPassthrough).toContain("MY_TOKEN"); // from override
|
|
171
|
-
});
|
|
172
|
-
test("listAgentProfileNames includes built-ins plus user-defined", async () => {
|
|
173
|
-
const { listAgentProfileNames } = await import("../../src/integrations/agent/config");
|
|
174
|
-
const names = listAgentProfileNames({ profiles: { rover: { bin: "rover" } } });
|
|
175
|
-
expect(names).toContain("rover");
|
|
176
|
-
expect(names).toContain("opencode");
|
|
177
|
-
expect(names).toContain("claude");
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
describe("requireAgentProfile", () => {
|
|
181
|
-
test("throws ConfigError when the agent block is missing", async () => {
|
|
182
|
-
const { requireAgentProfile } = await import("../../src/integrations/agent/config");
|
|
183
|
-
const { ConfigError } = await import("../../src/core/errors");
|
|
184
|
-
let caught;
|
|
185
|
-
try {
|
|
186
|
-
requireAgentProfile(undefined);
|
|
187
|
-
}
|
|
188
|
-
catch (err) {
|
|
189
|
-
caught = err;
|
|
190
|
-
}
|
|
191
|
-
expect(caught).toBeInstanceOf(ConfigError);
|
|
192
|
-
expect(caught.message).toContain("agent commands are disabled");
|
|
193
|
-
const hint = caught.hint();
|
|
194
|
-
expect(hint).toBeTruthy();
|
|
195
|
-
expect(hint).toContain("akm setup");
|
|
196
|
-
});
|
|
197
|
-
test("throws when no default and no requested name", async () => {
|
|
198
|
-
const { requireAgentProfile } = await import("../../src/integrations/agent/config");
|
|
199
|
-
const { ConfigError } = await import("../../src/core/errors");
|
|
200
|
-
let caught;
|
|
201
|
-
try {
|
|
202
|
-
requireAgentProfile({});
|
|
203
|
-
}
|
|
204
|
-
catch (err) {
|
|
205
|
-
caught = err;
|
|
206
|
-
}
|
|
207
|
-
expect(caught).toBeInstanceOf(ConfigError);
|
|
208
|
-
expect(caught.message).toContain("require a profile");
|
|
209
|
-
});
|
|
210
|
-
test("resolves the requested profile when valid", async () => {
|
|
211
|
-
const { requireAgentProfile } = await import("../../src/integrations/agent/config");
|
|
212
|
-
const profile = requireAgentProfile({ default: "claude" });
|
|
213
|
-
expect(profile.name).toBe("claude");
|
|
214
|
-
expect(profile.bin).toBe("claude");
|
|
215
|
-
});
|
|
216
|
-
test("explicit requested name beats config default", async () => {
|
|
217
|
-
const { requireAgentProfile } = await import("../../src/integrations/agent/config");
|
|
218
|
-
const profile = requireAgentProfile({ default: "claude" }, "codex");
|
|
219
|
-
expect(profile.name).toBe("codex");
|
|
220
|
-
});
|
|
221
|
-
});
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for setup-time agent CLI detection.
|
|
3
|
-
*
|
|
4
|
-
* Acceptance coverage:
|
|
5
|
-
* • Detects every built-in profile bin via the injected `which` probe.
|
|
6
|
-
* • Picks the first available profile as the default.
|
|
7
|
-
* • Honours an existing `agent.default` when that profile is still
|
|
8
|
-
* available (round-trip stability).
|
|
9
|
-
* • Returns `undefined` when nothing is installed.
|
|
10
|
-
* • `stepAgentCliDetection` produces a config-shaped result the wizard
|
|
11
|
-
* can `apply()`.
|
|
12
|
-
*/
|
|
13
|
-
import { describe, expect, test } from "bun:test";
|
|
14
|
-
import { detectAgentCliProfiles, pickDefaultAgentProfile } from "../../src/integrations/agent/detect";
|
|
15
|
-
function whichOnly(installed) {
|
|
16
|
-
const set = new Set(installed);
|
|
17
|
-
return (bin) => (set.has(bin) ? `/usr/local/bin/${bin}` : undefined);
|
|
18
|
-
}
|
|
19
|
-
describe("detectAgentCliProfiles", () => {
|
|
20
|
-
test("reports every built-in profile, available iff bin found", () => {
|
|
21
|
-
const results = detectAgentCliProfiles(undefined, whichOnly(["claude", "codex"]));
|
|
22
|
-
const names = results.map((r) => r.name).sort();
|
|
23
|
-
expect(names).toEqual(["aider", "claude", "codex", "gemini", "opencode"]);
|
|
24
|
-
expect(results.find((r) => r.name === "claude")?.available).toBe(true);
|
|
25
|
-
expect(results.find((r) => r.name === "codex")?.available).toBe(true);
|
|
26
|
-
expect(results.find((r) => r.name === "gemini")?.available).toBe(false);
|
|
27
|
-
});
|
|
28
|
-
test("includes user-defined profiles via the resolver", () => {
|
|
29
|
-
const results = detectAgentCliProfiles({ profiles: { rover: { bin: "rover-cli" } } }, whichOnly(["rover-cli"]));
|
|
30
|
-
const rover = results.find((r) => r.name === "rover");
|
|
31
|
-
expect(rover?.available).toBe(true);
|
|
32
|
-
expect(rover?.resolvedPath).toContain("rover-cli");
|
|
33
|
-
});
|
|
34
|
-
test("returns nothing-installed when the probe always says no", () => {
|
|
35
|
-
const results = detectAgentCliProfiles(undefined, whichOnly([]));
|
|
36
|
-
expect(results.every((r) => !r.available)).toBe(true);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
describe("pickDefaultAgentProfile", () => {
|
|
40
|
-
test("picks the first available result when no existing default", () => {
|
|
41
|
-
const picked = pickDefaultAgentProfile([
|
|
42
|
-
{ name: "aider", bin: "aider", available: false },
|
|
43
|
-
{ name: "claude", bin: "claude", available: true },
|
|
44
|
-
{ name: "codex", bin: "codex", available: true },
|
|
45
|
-
]);
|
|
46
|
-
expect(picked).toBe("claude");
|
|
47
|
-
});
|
|
48
|
-
test("keeps an existing available default", () => {
|
|
49
|
-
const picked = pickDefaultAgentProfile([
|
|
50
|
-
{ name: "claude", bin: "claude", available: true },
|
|
51
|
-
{ name: "codex", bin: "codex", available: true },
|
|
52
|
-
], "codex");
|
|
53
|
-
expect(picked).toBe("codex");
|
|
54
|
-
});
|
|
55
|
-
test("falls back when the existing default is no longer available", () => {
|
|
56
|
-
const picked = pickDefaultAgentProfile([
|
|
57
|
-
{ name: "claude", bin: "claude", available: true },
|
|
58
|
-
{ name: "codex", bin: "codex", available: false },
|
|
59
|
-
], "codex");
|
|
60
|
-
expect(picked).toBe("claude");
|
|
61
|
-
});
|
|
62
|
-
test("returns undefined when nothing is available", () => {
|
|
63
|
-
const picked = pickDefaultAgentProfile([
|
|
64
|
-
{ name: "claude", bin: "claude", available: false },
|
|
65
|
-
{ name: "codex", bin: "codex", available: false },
|
|
66
|
-
]);
|
|
67
|
-
expect(picked).toBeUndefined();
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
describe("stepAgentCliDetection (setup wizard)", () => {
|
|
71
|
-
test("persists default + leaves block absent when nothing detected & no prior config", async () => {
|
|
72
|
-
const { stepAgentCliDetection } = await import("../../src/setup/setup");
|
|
73
|
-
const result = stepAgentCliDetection({ semanticSearchMode: "auto" }, () => [
|
|
74
|
-
{ name: "claude", bin: "claude", available: false },
|
|
75
|
-
{ name: "codex", bin: "codex", available: false },
|
|
76
|
-
]);
|
|
77
|
-
expect(result.agent).toBeUndefined();
|
|
78
|
-
expect(result.detections).toHaveLength(2);
|
|
79
|
-
});
|
|
80
|
-
test("writes agent.default to the first detected profile", async () => {
|
|
81
|
-
const { stepAgentCliDetection } = await import("../../src/setup/setup");
|
|
82
|
-
const result = stepAgentCliDetection({ semanticSearchMode: "auto" }, () => [
|
|
83
|
-
{ name: "claude", bin: "claude", available: false },
|
|
84
|
-
{ name: "codex", bin: "codex", available: true },
|
|
85
|
-
]);
|
|
86
|
-
expect(result.agent?.default).toBe("codex");
|
|
87
|
-
});
|
|
88
|
-
test("preserves user-overridden default when still available", async () => {
|
|
89
|
-
const { stepAgentCliDetection } = await import("../../src/setup/setup");
|
|
90
|
-
const result = stepAgentCliDetection({
|
|
91
|
-
semanticSearchMode: "auto",
|
|
92
|
-
agent: { default: "aider", profiles: { aider: { args: ["--no-auto-commits"] } } },
|
|
93
|
-
}, () => [
|
|
94
|
-
{ name: "claude", bin: "claude", available: true },
|
|
95
|
-
{ name: "aider", bin: "aider", available: true },
|
|
96
|
-
]);
|
|
97
|
-
expect(result.agent?.default).toBe("aider");
|
|
98
|
-
expect(result.agent?.profiles?.aider?.args).toEqual(["--no-auto-commits"]);
|
|
99
|
-
});
|
|
100
|
-
});
|