akm-cli 0.8.6 → 0.8.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +442 -0
- package/dist/assets/help/help-proposals.md +1 -2
- package/dist/assets/hints/cli-hints-full.md +34 -19
- package/dist/assets/hints/cli-hints-short.md +1 -1
- package/dist/assets/profiles/catchup.json +13 -0
- package/dist/assets/profiles/consolidate.json +13 -0
- package/dist/assets/profiles/frequent.json +13 -0
- package/dist/assets/tasks/core/backup.yml +4 -0
- package/dist/assets/tasks/core/extract.yml +4 -0
- package/dist/assets/tasks/core/improve.yml +4 -0
- package/dist/assets/tasks/core/index-refresh.yml +4 -0
- package/dist/assets/tasks/core/sync.yml +4 -0
- package/dist/assets/tasks/core/update-stashes.yml +4 -0
- package/dist/assets/tasks/core/version-check.yml +4 -0
- package/dist/assets/templates/html/default.html +78 -0
- package/dist/assets/templates/html/health.html +560 -0
- package/dist/assets/templates/html/vendor/echarts.min.js +45 -0
- package/dist/cli/config-migrate.js +6 -6
- package/dist/cli/config-validate.js +4 -4
- package/dist/cli/confirm.js +3 -3
- package/dist/cli/parse-args.js +1 -1
- package/dist/cli/shared.js +72 -19
- package/dist/cli-node.mjs +26 -0
- package/dist/cli.js +206 -3866
- package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
- package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
- package/dist/commands/agent/contribute-cli.js +200 -0
- package/dist/commands/completions.js +1 -1
- package/dist/commands/config-cli.js +230 -3
- package/dist/commands/db-cli.js +2 -2
- package/dist/commands/env/env-cli.js +529 -0
- package/dist/commands/env/env.js +410 -0
- package/dist/commands/env/secret-cli.js +259 -0
- package/dist/commands/{secret.js → env/secret.js} +6 -47
- package/dist/commands/events.js +4 -4
- package/dist/commands/feedback-cli.js +18 -34
- package/dist/commands/graph/graph-cli.js +132 -0
- package/dist/commands/{graph.js → graph/graph.js} +22 -16
- package/dist/commands/health/checks.js +279 -0
- package/dist/commands/health/html-report.js +448 -0
- package/dist/commands/health.js +189 -266
- package/dist/commands/{consolidate.js → improve/consolidate.js} +63 -38
- package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
- package/dist/commands/{distill.js → improve/distill.js} +39 -18
- package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
- package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
- package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
- package/dist/commands/{extract.js → improve/extract.js} +221 -26
- package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +30 -4
- package/dist/commands/{improve-cli.js → improve/improve-cli.js} +44 -22
- package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
- package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +1 -1
- package/dist/commands/{improve.js → improve/improve.js} +672 -292
- package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
- package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
- package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/{reflect.js → improve/reflect.js} +58 -28
- package/dist/commands/improve/session-asset.js +248 -0
- package/dist/commands/lint/agent-linter.js +1 -1
- package/dist/commands/lint/base-linter.js +55 -37
- package/dist/commands/lint/command-linter.js +1 -1
- package/dist/commands/lint/default-linter.js +1 -1
- package/dist/commands/lint/env-key-rules.js +1 -1
- package/dist/commands/lint/index.js +19 -25
- package/dist/commands/lint/knowledge-linter.js +1 -1
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +8 -8
- package/dist/commands/lint/skill-linter.js +1 -1
- package/dist/commands/lint/task-linter.js +1 -1
- package/dist/commands/lint/workflow-linter.js +1 -1
- package/dist/commands/lint.js +1 -1
- package/dist/commands/observability-cli.js +244 -0
- package/dist/commands/proposal/drain-policies.js +3 -3
- package/dist/commands/proposal/drain.js +87 -15
- package/dist/commands/proposal/proposal-cli.js +490 -0
- package/dist/commands/{proposal.js → proposal/proposal.js} +17 -6
- package/dist/commands/{propose.js → proposal/propose.js} +11 -11
- package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
- package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
- package/dist/{core → commands/proposal/validators}/proposals.js +374 -345
- package/dist/commands/{curate.js → read/curate.js} +7 -7
- package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
- package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
- package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
- package/dist/commands/read/search-cli.js +207 -0
- package/dist/commands/{search.js → read/search.js} +22 -27
- package/dist/commands/{show.js → read/show.js} +31 -45
- package/dist/commands/registry-cli.js +8 -8
- package/dist/commands/remember.js +14 -10
- package/dist/commands/sources/add-cli.js +293 -0
- package/dist/commands/{history.js → sources/history.js} +27 -25
- package/dist/commands/{info.js → sources/info.js} +6 -6
- package/dist/commands/{init.js → sources/init.js} +6 -6
- package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
- package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
- package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
- package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
- package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
- package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
- package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
- package/dist/commands/sources/sources-cli.js +305 -0
- package/dist/commands/sources/stash-cli.js +219 -0
- package/dist/commands/{stash-skeleton.js → sources/stash-skeleton.js} +2 -1
- package/dist/commands/tasks/default-tasks.js +173 -0
- package/dist/commands/tasks/tasks-cli.js +210 -0
- package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
- package/dist/commands/wiki-cli.js +307 -0
- package/dist/commands/workflow-cli.js +329 -0
- package/dist/core/action-contributors.js +1 -1
- package/dist/core/assert.js +40 -0
- package/dist/core/asset/asset-create.js +54 -0
- package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
- package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
- package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
- package/dist/core/{markdown.js → asset/markdown.js} +1 -1
- package/dist/core/{stash-meta.js → asset/stash-meta.js} +1 -1
- package/dist/core/best-effort.js +64 -0
- package/dist/core/common.js +32 -18
- package/dist/core/{config-io.js → config/config-io.js} +29 -19
- package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
- package/dist/core/{config-schema.js → config/config-schema.js} +50 -7
- package/dist/core/config/config-types.js +16 -0
- package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
- package/dist/core/{config.js → config/config.js} +10 -8
- package/dist/core/env-secret-ref.js +90 -0
- package/dist/core/errors.js +13 -3
- package/dist/core/events.js +27 -4
- package/dist/core/file-lock.js +1 -1
- package/dist/core/improve-types.js +48 -0
- package/dist/core/lesson-lint.js +2 -2
- package/dist/core/logs-db.js +304 -0
- package/dist/core/paths.js +2 -2
- package/dist/core/ripgrep/install.js +2 -2
- package/dist/core/ripgrep/resolve.js +2 -2
- package/dist/core/state-db.js +195 -60
- package/dist/core/text-truncation.js +148 -0
- package/dist/core/time.js +1 -1
- package/dist/core/write-source.js +98 -85
- package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
- package/dist/indexer/{db.js → db/db.js} +128 -118
- package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
- package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
- package/dist/indexer/ensure-index.js +4 -4
- package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
- package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
- package/dist/indexer/indexer.js +37 -30
- package/dist/indexer/init.js +54 -0
- package/dist/indexer/manifest.js +10 -10
- package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +141 -33
- package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
- package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
- package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
- package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
- package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
- package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
- package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
- package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
- package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
- package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
- package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
- package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
- package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
- package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
- package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
- package/dist/indexer/{walker.js → walk/walker.js} +4 -3
- package/dist/integrations/agent/builder-shared.js +39 -0
- package/dist/integrations/agent/builders.js +14 -81
- package/dist/integrations/agent/config.js +6 -4
- package/dist/integrations/agent/detect.js +1 -1
- package/dist/integrations/agent/index.js +23 -8
- package/dist/integrations/agent/prompts.js +2 -3
- package/dist/integrations/agent/runner.js +22 -3
- package/dist/integrations/agent/spawn.js +9 -10
- package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
- package/dist/integrations/harnesses/claude/config-import.js +70 -0
- package/dist/integrations/harnesses/claude/index.js +64 -0
- package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +32 -5
- package/dist/integrations/harnesses/index.js +144 -0
- package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
- package/dist/integrations/harnesses/opencode/config-import.js +82 -0
- package/dist/integrations/harnesses/opencode/index.js +59 -0
- package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
- package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
- package/dist/integrations/harnesses/types.js +43 -0
- package/dist/integrations/lockfile.js +7 -16
- package/dist/integrations/session-logs/index.js +82 -9
- package/dist/llm/call-ai.js +4 -4
- package/dist/llm/client.js +146 -6
- package/dist/llm/embedder.js +6 -6
- package/dist/llm/embedders/local.js +9 -22
- package/dist/llm/embedders/remote.js +2 -2
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +31 -12
- package/dist/llm/index-passes.js +1 -1
- package/dist/llm/memory-infer.js +12 -5
- package/dist/llm/metadata-enhance.js +2 -2
- package/dist/llm/usage-persist.js +77 -0
- package/dist/llm/usage-telemetry.js +103 -0
- package/dist/output/context.js +9 -46
- package/dist/output/html-render.js +73 -0
- package/dist/output/renderers.js +88 -58
- package/dist/output/shapes/curate.js +7 -3
- package/dist/output/shapes/distill.js +7 -3
- package/dist/output/shapes/env-list.js +18 -16
- package/dist/output/shapes/events.js +5 -4
- package/dist/output/shapes/helpers.js +19 -5
- package/dist/output/shapes/history.js +7 -3
- package/dist/output/shapes/passthrough.js +8 -11
- package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
- package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
- package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
- package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
- package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
- package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
- package/dist/output/shapes/registry-search.js +7 -3
- package/dist/output/shapes/registry.js +12 -0
- package/dist/output/shapes/search.js +7 -3
- package/dist/output/shapes/secret-list.js +18 -16
- package/dist/output/shapes/show.js +7 -3
- package/dist/output/shapes.js +55 -30
- package/dist/output/text/add.js +2 -3
- package/dist/output/text/clone.js +2 -3
- package/dist/output/text/config.js +2 -3
- package/dist/output/text/curate.js +4 -3
- package/dist/output/text/distill.js +2 -3
- package/dist/output/text/enable-disable.js +5 -4
- package/dist/output/text/env.js +13 -0
- package/dist/output/text/events.js +5 -4
- package/dist/output/text/feedback.js +4 -3
- package/dist/output/text/helpers.js +123 -40
- package/dist/output/text/history.js +2 -3
- package/dist/output/text/import.js +2 -3
- package/dist/output/text/index.js +2 -3
- package/dist/output/text/info.js +2 -3
- package/dist/output/text/init.js +2 -3
- package/dist/output/text/list.js +2 -3
- package/dist/output/text/proposal/producer.js +9 -0
- package/dist/output/text/proposal/proposal.js +13 -0
- package/dist/output/text/registry-commands.js +8 -7
- package/dist/output/text/registry.js +12 -0
- package/dist/output/text/remember.js +4 -3
- package/dist/output/text/remove.js +2 -3
- package/dist/output/text/save.js +2 -3
- package/dist/output/text/search.js +4 -3
- package/dist/output/text/show.js +4 -3
- package/dist/output/text/update.js +2 -3
- package/dist/output/text/upgrade.js +2 -3
- package/dist/output/text/wiki.js +12 -11
- package/dist/output/text/workflow.js +12 -10
- package/dist/output/text.js +66 -32
- package/dist/registry/build-index.js +11 -10
- package/dist/registry/factory.js +1 -1
- package/dist/registry/origin-resolve.js +1 -1
- package/dist/registry/providers/index.js +2 -2
- package/dist/registry/providers/skills-sh.js +91 -72
- package/dist/registry/providers/static-index.js +75 -52
- package/dist/registry/resolve.js +3 -3
- package/dist/runtime.js +242 -0
- package/dist/scripts/migrate-storage.js +1654 -683
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +254 -168
- package/dist/setup/detect.js +311 -9
- package/dist/setup/harness-config-import.js +6 -120
- package/dist/setup/setup.js +454 -43
- package/dist/sources/include.js +1 -1
- package/dist/sources/provider-factory.js +2 -2
- package/dist/sources/providers/filesystem.js +3 -3
- package/dist/sources/providers/git.js +9 -9
- package/dist/sources/providers/index.js +4 -4
- package/dist/sources/providers/npm.js +6 -6
- package/dist/sources/providers/provider-utils.js +13 -20
- package/dist/sources/providers/sync-from-ref.js +5 -5
- package/dist/sources/providers/tar-utils.js +2 -2
- package/dist/sources/providers/website.js +2 -2
- package/dist/sources/resolve.js +5 -5
- package/dist/sources/website-ingest.js +5 -5
- package/dist/storage/database.js +102 -0
- package/dist/storage/engines/sqlite-migrations.js +42 -0
- package/dist/storage/locations.js +25 -0
- package/dist/storage/repositories/index-db.js +43 -0
- package/dist/storage/repositories/workflow-runs-repository.js +141 -0
- package/dist/tasks/backends/cron.js +4 -4
- package/dist/tasks/backends/exec-utils.js +32 -0
- package/dist/tasks/backends/index.js +3 -3
- package/dist/tasks/backends/launchd.js +7 -14
- package/dist/tasks/backends/schtasks.js +7 -16
- package/dist/tasks/embedded.js +71 -0
- package/dist/tasks/parser.js +2 -2
- package/dist/tasks/resolveAkmBin.js +1 -1
- package/dist/tasks/runner.js +127 -31
- package/dist/tasks/schedule.js +1 -1
- package/dist/tasks/validator.js +7 -7
- package/dist/text-import-hook.mjs +51 -0
- package/dist/version.js +2 -1
- package/dist/wiki/wiki.js +7 -7
- package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
- package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
- package/dist/workflows/cli.js +1 -1
- package/dist/workflows/db.js +54 -32
- package/dist/workflows/parser.js +4 -4
- package/dist/workflows/renderer.js +5 -5
- package/dist/workflows/runtime/agent-identity.js +56 -0
- package/dist/workflows/runtime/checkin.js +57 -0
- package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
- package/dist/workflows/validate-summary.js +82 -0
- package/docs/README.md +1 -1
- package/docs/data-and-telemetry.md +6 -6
- package/package.json +17 -8
- package/dist/commands/add-cli.js +0 -279
- package/dist/commands/env.js +0 -213
- package/dist/integrations/agent/sdk-runner.js +0 -126
- package/dist/output/shapes/vault-list.js +0 -19
- package/dist/output/text/proposal-producer.js +0 -8
- package/dist/output/text/proposal.js +0 -12
- package/dist/output/text/vault.js +0 -16
- /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
- /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
- /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
- /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
- /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
- /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
- /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
- /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
package/dist/setup/setup.js
CHANGED
|
@@ -13,23 +13,31 @@ import fs from "node:fs";
|
|
|
13
13
|
import os from "node:os";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import * as p from "@clack/prompts";
|
|
16
|
-
import { akmInit } from "../commands/init";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
16
|
+
import { akmInit } from "../commands/sources/init.js";
|
|
17
|
+
import { detectServerDefault, isCiEnvironment, registerDefaultTasks } from "../commands/tasks/default-tasks.js";
|
|
18
|
+
import { akmTasksAdd, akmTasksList, akmTasksSetEnabled, akmTasksSync } from "../commands/tasks/tasks.js";
|
|
19
|
+
import { isHttpUrl } from "../core/common.js";
|
|
20
|
+
import { DEFAULT_CONFIG, getDefaultLlmConfig, getEffectiveRegistries, loadUserConfig, saveConfig, } from "../core/config/config.js";
|
|
21
|
+
import { backupExistingConfig } from "../core/config/config-io.js";
|
|
22
|
+
import { ConfigError, UsageError } from "../core/errors.js";
|
|
23
|
+
import { assertSafeStashDir, getConfigPath, getDefaultStashDir, isTransientStashPath } from "../core/paths.js";
|
|
24
|
+
import { warn } from "../core/warn.js";
|
|
25
|
+
import { closeDatabase, isVecAvailable, openDatabase } from "../indexer/db/db.js";
|
|
26
|
+
import { akmIndex } from "../indexer/indexer.js";
|
|
27
|
+
import { clearSemanticStatus, deriveSemanticProviderFingerprint, writeSemanticStatus, } from "../indexer/search/semantic-status.js";
|
|
28
|
+
import { detectAgentCliProfiles, pickDefaultAgentProfile } from "../integrations/agent/index.js";
|
|
29
|
+
import { defaultProfileName, v1ProfilePlatform } from "../integrations/harnesses/index.js";
|
|
30
|
+
import { probeLlmCapabilities } from "../llm/client.js";
|
|
31
|
+
import { checkEmbeddingAvailability, DEFAULT_LOCAL_MODEL, isTransformersAvailable } from "../llm/embedder.js";
|
|
32
|
+
import { getDirname, spawn } from "../runtime.js";
|
|
33
|
+
import { saveGitStash } from "../sources/providers/git.js";
|
|
34
|
+
import { backendNameForPlatform } from "../tasks/backends/index.js";
|
|
35
|
+
import { listEmbeddedTasks } from "../tasks/embedded.js";
|
|
36
|
+
import { parseSchedule } from "../tasks/schedule.js";
|
|
37
|
+
import { detectAgentPlatforms, detectEnvironment, detectLMStudio, detectOllama, renderDetectionSummary, } from "./detect.js";
|
|
38
|
+
import { detectHarnessConfigs } from "./harness-config-import.js";
|
|
39
|
+
import { loadSetupStashes } from "./registry-stash-loader.js";
|
|
40
|
+
import { createSetupContext, runSetupSteps } from "./steps.js";
|
|
33
41
|
// ── Setup sandbox guard ─────────────────────────────────────────────────────
|
|
34
42
|
/**
|
|
35
43
|
* Refuse to persist an explicit `--dir /tmp/...` stashDir to the user's
|
|
@@ -135,11 +143,28 @@ function applyLegacyAgent(config, agent) {
|
|
|
135
143
|
}
|
|
136
144
|
const v2Profiles = { ...(config.profiles?.agent ?? {}) };
|
|
137
145
|
for (const [name, profile] of Object.entries(agent.profiles ?? {})) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
146
|
+
// #566: resolve the platform via the harness registry instead of the old
|
|
147
|
+
// `name.includes("claude") ? "claude" : "opencode"` heuristic, which
|
|
148
|
+
// silently mapped Cursor/Copilot/any new harness to "opencode". An explicit
|
|
149
|
+
// sdkMode flag still wins; otherwise we ask the registry. A name the
|
|
150
|
+
// registry does not recognize is surfaced (warn) rather than silently
|
|
151
|
+
// misclassified, then kept as a best-effort "opencode" profile so the user
|
|
152
|
+
// does not lose a profile they explicitly configured.
|
|
153
|
+
let platform;
|
|
154
|
+
if (profile.sdkMode) {
|
|
155
|
+
platform = "opencode-sdk";
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
const resolved = v1ProfilePlatform(name);
|
|
159
|
+
if (resolved) {
|
|
160
|
+
platform = resolved;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
warn(`[akm setup] Agent profile "${name}" did not match any known harness; ` +
|
|
164
|
+
`defaulting its platform to "opencode". Set its platform explicitly in config if this is wrong.`);
|
|
165
|
+
platform = "opencode";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
143
168
|
v2Profiles[name] = {
|
|
144
169
|
platform,
|
|
145
170
|
...(profile.bin ? { bin: profile.bin } : {}),
|
|
@@ -386,8 +411,8 @@ async function prepareSemanticSearchAssets(config) {
|
|
|
386
411
|
const spin = p.spinner();
|
|
387
412
|
spin.start("Installing @huggingface/transformers...");
|
|
388
413
|
try {
|
|
389
|
-
const pkgRoot = path.resolve(import.meta.
|
|
390
|
-
const proc =
|
|
414
|
+
const pkgRoot = path.resolve(getDirname(import.meta.url), "../..");
|
|
415
|
+
const proc = spawn(["bun", "add", "@huggingface/transformers"], {
|
|
391
416
|
cwd: pkgRoot,
|
|
392
417
|
stdout: "pipe",
|
|
393
418
|
stderr: "pipe",
|
|
@@ -1464,6 +1489,165 @@ export function stepAgentCliDetection(current, detectFn = detectAgentCliProfiles
|
|
|
1464
1489
|
return { agent, detections };
|
|
1465
1490
|
}
|
|
1466
1491
|
// ── Main Wizard ─────────────────────────────────────────────────────────────
|
|
1492
|
+
/**
|
|
1493
|
+
* Normalise a task id the same way `akm tasks` does (strip a trailing `.yml`
|
|
1494
|
+
* / `.md` suffix, trim) so the wizard can match embedded template ids against
|
|
1495
|
+
* the ids reported by `akmTasksList()`.
|
|
1496
|
+
*/
|
|
1497
|
+
function normaliseTaskIdForMatch(raw) {
|
|
1498
|
+
return raw.trim().replace(/\.(yml|md)$/, "");
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* Interactive-only setup step: enable/disable embedded core tasks.
|
|
1502
|
+
*
|
|
1503
|
+
* Presents a multi-select of the bundled core task templates pre-checked
|
|
1504
|
+
* against the user's currently-enabled tasks. On confirm:
|
|
1505
|
+
* - newly-checked & absent → copy template (with edited schedule) into the
|
|
1506
|
+
* primary stash via `akmTasksAdd`, then `akmTasksSync`, then `akm sync`
|
|
1507
|
+
* (a no-op for non-git stashes).
|
|
1508
|
+
* - newly-checked & present-but-disabled → `akmTasksSetEnabled(id, true)`.
|
|
1509
|
+
* - previously-enabled & now unchecked → `akmTasksSetEnabled(id, false)`
|
|
1510
|
+
* (keeps the stash file, removes the scheduler entry).
|
|
1511
|
+
* - unchanged → no action.
|
|
1512
|
+
*
|
|
1513
|
+
* Exported for testing. Not registered as `nonInteractive`, so `akm init` /
|
|
1514
|
+
* `--yes` never reach it.
|
|
1515
|
+
*
|
|
1516
|
+
* The task primitives + git-sync helper are injected via `deps` (defaulting
|
|
1517
|
+
* to the real implementations) so tests can supply fakes without
|
|
1518
|
+
* `mock.module`-ing the shared `commands/tasks` / `sources/providers/git`
|
|
1519
|
+
* modules — which would leak into unrelated test files (Bun's `mock.module`
|
|
1520
|
+
* is process-global and not reverted by `mock.restore()`).
|
|
1521
|
+
*/
|
|
1522
|
+
/**
|
|
1523
|
+
* Setup sub-step (issue #552): idempotently register the default improve task
|
|
1524
|
+
* set. Asks a single "Is this a server install?" question (defaulting per
|
|
1525
|
+
* platform) to decide whether the nightly sweep is enabled, then delegates to
|
|
1526
|
+
* {@link registerDefaultTasks}, which is CI-aware and never duplicates an
|
|
1527
|
+
* existing task. Skipped entirely under CI (the registration helper short-
|
|
1528
|
+
* circuits, and we never even prompt).
|
|
1529
|
+
*
|
|
1530
|
+
* Exported for testing.
|
|
1531
|
+
*/
|
|
1532
|
+
export async function stepDefaultImproveTasks(register = registerDefaultTasks) {
|
|
1533
|
+
// CI: register nothing and don't prompt.
|
|
1534
|
+
if (isCiEnvironment()) {
|
|
1535
|
+
p.log.info("CI detected — skipping default improve task registration.");
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
const platformDefault = detectServerDefault();
|
|
1539
|
+
const serverInstall = await prompt(() => p.confirm({
|
|
1540
|
+
message: "Is this a server install? (enables the nightly quality sweep at 2am)",
|
|
1541
|
+
initialValue: platformDefault,
|
|
1542
|
+
}));
|
|
1543
|
+
const result = await register({ serverInstall: serverInstall === true });
|
|
1544
|
+
if (result.skipped)
|
|
1545
|
+
return;
|
|
1546
|
+
const total = result.created.length + result.existing.length;
|
|
1547
|
+
p.log.success(`Default improve tasks registered (${result.created.length} new, ${result.existing.length} already present, ${total} total).`);
|
|
1548
|
+
}
|
|
1549
|
+
const DEFAULT_SCHEDULED_TASKS_DEPS = {
|
|
1550
|
+
list: akmTasksList,
|
|
1551
|
+
add: akmTasksAdd,
|
|
1552
|
+
setEnabled: akmTasksSetEnabled,
|
|
1553
|
+
sync: akmTasksSync,
|
|
1554
|
+
gitSync: saveGitStash,
|
|
1555
|
+
};
|
|
1556
|
+
export async function stepScheduledTasks(deps = DEFAULT_SCHEDULED_TASKS_DEPS) {
|
|
1557
|
+
const embedded = listEmbeddedTasks();
|
|
1558
|
+
if (embedded.length === 0)
|
|
1559
|
+
return;
|
|
1560
|
+
// Snapshot current state so we can diff against the user's selection.
|
|
1561
|
+
let installed = [];
|
|
1562
|
+
try {
|
|
1563
|
+
installed = (await deps.list()).tasks;
|
|
1564
|
+
}
|
|
1565
|
+
catch {
|
|
1566
|
+
// A missing/empty tasks dir is fine — treat as nothing installed.
|
|
1567
|
+
installed = [];
|
|
1568
|
+
}
|
|
1569
|
+
const byId = new Map();
|
|
1570
|
+
for (const t of installed)
|
|
1571
|
+
byId.set(normaliseTaskIdForMatch(t.id), t);
|
|
1572
|
+
// Pre-check tasks that are installed AND enabled.
|
|
1573
|
+
const preChecked = embedded.filter((e) => byId.get(e.id)?.enabled === true).map((e) => e.id);
|
|
1574
|
+
const stateLabel = (e) => {
|
|
1575
|
+
const cur = byId.get(e.id);
|
|
1576
|
+
if (!cur)
|
|
1577
|
+
return "not installed";
|
|
1578
|
+
return cur.enabled ? "enabled" : "disabled";
|
|
1579
|
+
};
|
|
1580
|
+
const selected = await prompt(() => p.multiselect({
|
|
1581
|
+
message: "Enable scheduled core tasks? (space to toggle, enter to confirm)",
|
|
1582
|
+
required: false,
|
|
1583
|
+
initialValues: preChecked,
|
|
1584
|
+
options: embedded.map((e) => ({
|
|
1585
|
+
value: e.id,
|
|
1586
|
+
label: e.label,
|
|
1587
|
+
hint: `${e.description} — ${e.schedule} [${stateLabel(e)}]`,
|
|
1588
|
+
})),
|
|
1589
|
+
}));
|
|
1590
|
+
const selectedSet = new Set(selected);
|
|
1591
|
+
// Resolve per-task schedule edits for newly-checked, not-yet-installed tasks.
|
|
1592
|
+
const scheduleFor = new Map();
|
|
1593
|
+
for (const e of embedded) {
|
|
1594
|
+
const cur = byId.get(e.id);
|
|
1595
|
+
if (selectedSet.has(e.id) && !cur) {
|
|
1596
|
+
const edited = await prompt(() => p.text({
|
|
1597
|
+
message: `Schedule for ${e.label}?`,
|
|
1598
|
+
initialValue: e.schedule,
|
|
1599
|
+
validate(value) {
|
|
1600
|
+
const candidate = (value ?? "").trim() || e.schedule;
|
|
1601
|
+
try {
|
|
1602
|
+
parseSchedule(candidate, backendNameForPlatform());
|
|
1603
|
+
}
|
|
1604
|
+
catch (err) {
|
|
1605
|
+
return err instanceof Error ? err.message : "Invalid schedule.";
|
|
1606
|
+
}
|
|
1607
|
+
return undefined;
|
|
1608
|
+
},
|
|
1609
|
+
}));
|
|
1610
|
+
const sched = (edited ?? "").trim() || e.schedule;
|
|
1611
|
+
scheduleFor.set(e.id, sched);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
let syncNeeded = false;
|
|
1615
|
+
for (const e of embedded) {
|
|
1616
|
+
const cur = byId.get(e.id);
|
|
1617
|
+
const checked = selectedSet.has(e.id);
|
|
1618
|
+
if (checked && !cur) {
|
|
1619
|
+
// New task: copy template into the primary stash + install scheduler entry.
|
|
1620
|
+
const schedule = scheduleFor.get(e.id) ?? e.schedule;
|
|
1621
|
+
await deps.add({
|
|
1622
|
+
id: e.id,
|
|
1623
|
+
schedule,
|
|
1624
|
+
command: e.command,
|
|
1625
|
+
description: e.description,
|
|
1626
|
+
});
|
|
1627
|
+
syncNeeded = true;
|
|
1628
|
+
}
|
|
1629
|
+
else if (checked && cur && !cur.enabled) {
|
|
1630
|
+
// Present but disabled → re-enable.
|
|
1631
|
+
await deps.setEnabled(e.id, true);
|
|
1632
|
+
}
|
|
1633
|
+
else if (!checked && cur?.enabled) {
|
|
1634
|
+
// Previously enabled, now unchecked → disable (keep the stash file).
|
|
1635
|
+
await deps.setEnabled(e.id, false);
|
|
1636
|
+
}
|
|
1637
|
+
// No state change → no action.
|
|
1638
|
+
}
|
|
1639
|
+
if (syncNeeded) {
|
|
1640
|
+
// Reconcile scheduler entries with on-disk YAML, then commit the new file
|
|
1641
|
+
// to git (a no-op for non-git stashes).
|
|
1642
|
+
await deps.sync();
|
|
1643
|
+
try {
|
|
1644
|
+
deps.gitSync(undefined, "akm setup: enable scheduled tasks");
|
|
1645
|
+
}
|
|
1646
|
+
catch {
|
|
1647
|
+
// Non-fatal — the task is installed regardless of git sync outcome.
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1467
1651
|
/**
|
|
1468
1652
|
* Build the canonical list of `SetupStep`s for the interactive wizard.
|
|
1469
1653
|
* Exposed (and exported) so tests and `akm init` can compose subsets.
|
|
@@ -1479,8 +1663,9 @@ export function buildSetupSteps(options) {
|
|
|
1479
1663
|
let ollamaEndpoint;
|
|
1480
1664
|
let ollamaChatModels;
|
|
1481
1665
|
let lmStudioResult;
|
|
1482
|
-
// Harness configs detected once and shared with the LLM step.
|
|
1483
|
-
|
|
1666
|
+
// Harness configs detected once and shared with the LLM step. Reuse the
|
|
1667
|
+
// aggregate detection's harness configs when available so we detect once.
|
|
1668
|
+
const harnessConfigs = options.detection?.harnessConfigs ?? detectHarnessConfigs();
|
|
1484
1669
|
const steps = [
|
|
1485
1670
|
{
|
|
1486
1671
|
id: "stash-dir",
|
|
@@ -1580,6 +1765,16 @@ export function buildSetupSteps(options) {
|
|
|
1580
1765
|
ctx.apply({ output });
|
|
1581
1766
|
},
|
|
1582
1767
|
},
|
|
1768
|
+
{
|
|
1769
|
+
id: "scheduled-tasks",
|
|
1770
|
+
label: "Scheduled Tasks",
|
|
1771
|
+
// Interactive-only: `akm init` / `--yes` skip this step so headless
|
|
1772
|
+
// runs never enable a scheduled task (see issue #512).
|
|
1773
|
+
async run() {
|
|
1774
|
+
await stepDefaultImproveTasks();
|
|
1775
|
+
await stepScheduledTasks();
|
|
1776
|
+
},
|
|
1777
|
+
},
|
|
1583
1778
|
];
|
|
1584
1779
|
return { steps, outcome };
|
|
1585
1780
|
}
|
|
@@ -1604,11 +1799,28 @@ export async function runSetupWizard(opts) {
|
|
|
1604
1799
|
p.log.warn("No network connectivity detected. Skipping Ollama detection and remote embedding checks.\n" +
|
|
1605
1800
|
"Local-only setup will continue. Re-run `akm setup` when online for full configuration.");
|
|
1606
1801
|
}
|
|
1802
|
+
// Aggregate environment detection — run once before any prompt and surface
|
|
1803
|
+
// a summary so the user sees what was auto-detected. NAMES only, never
|
|
1804
|
+
// API key values.
|
|
1805
|
+
const detection = await detectEnvironment({ existingStashDir: current.stashDir });
|
|
1806
|
+
p.note(renderDetectionSummary(detection), "Detected environment");
|
|
1807
|
+
// Interactive entry point for `--reset-recommended`: offer to apply the
|
|
1808
|
+
// opinionated, detection-derived defaults and skip the step-by-step wizard.
|
|
1809
|
+
const useRecommended = await prompt(() => p.confirm({
|
|
1810
|
+
message: "Apply recommended defaults from the detected environment (merged into your existing config)?",
|
|
1811
|
+
initialValue: false,
|
|
1812
|
+
}));
|
|
1813
|
+
if (useRecommended) {
|
|
1814
|
+
const result = await runResetRecommended({ dir: opts?.dir, noInit: opts?.noInit });
|
|
1815
|
+
p.outro(`Recommended configuration saved to ${result.configPath}`);
|
|
1816
|
+
return;
|
|
1817
|
+
}
|
|
1607
1818
|
const ctx = createSetupContext(current, { nonInteractive: false });
|
|
1608
1819
|
const { steps, outcome } = buildSetupSteps({
|
|
1609
1820
|
online,
|
|
1610
1821
|
semanticSearchOutcome: { mode: current.semanticSearchMode, prepareAssets: false },
|
|
1611
1822
|
preferredStashDir: resolvedStashDir,
|
|
1823
|
+
detection,
|
|
1612
1824
|
});
|
|
1613
1825
|
// Wrap each step with a `p.log.step()` header so the wizard UI is
|
|
1614
1826
|
// unchanged. The canonical `runSetupSteps()` runner is used directly by
|
|
@@ -1664,10 +1876,7 @@ export async function runSetupWizard(opts) {
|
|
|
1664
1876
|
bail();
|
|
1665
1877
|
// Save config
|
|
1666
1878
|
const cfgPath1 = getConfigPath();
|
|
1667
|
-
|
|
1668
|
-
backupExistingConfig(cfgPath1);
|
|
1669
|
-
p.log.info(`Config backed up to ~/.cache/akm/config-backups/`);
|
|
1670
|
-
}
|
|
1879
|
+
backupAndAnnounce(cfgPath1);
|
|
1671
1880
|
saveConfig(newConfig);
|
|
1672
1881
|
if (semanticSearchMode.mode === "off") {
|
|
1673
1882
|
clearSemanticStatus();
|
|
@@ -1751,6 +1960,20 @@ export async function runSetupWizard(opts) {
|
|
|
1751
1960
|
p.outro(`Configuration saved to ${configPath}`);
|
|
1752
1961
|
}
|
|
1753
1962
|
// ── Non-interactive / scripting entry points ─────────────────────────────────
|
|
1963
|
+
/**
|
|
1964
|
+
* Back up an existing config file and print the real, timestamped backup
|
|
1965
|
+
* location (not a generic display string). On a fresh install where there is
|
|
1966
|
+
* nothing to back up, print a "nothing to back up" notice instead.
|
|
1967
|
+
*/
|
|
1968
|
+
function backupAndAnnounce(configPath) {
|
|
1969
|
+
const result = backupExistingConfig(configPath);
|
|
1970
|
+
if (result) {
|
|
1971
|
+
p.log.info(`Config backed up to ${result.timestamped}`);
|
|
1972
|
+
}
|
|
1973
|
+
else {
|
|
1974
|
+
p.log.info("No existing config to back up.");
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1754
1977
|
/**
|
|
1755
1978
|
* Run setup in non-interactive mode, applying all defaults.
|
|
1756
1979
|
* Safe to call from CI or scripts. Idempotent — re-running produces the same result.
|
|
@@ -1776,19 +1999,41 @@ export async function runSetupWithDefaults(opts) {
|
|
|
1776
1999
|
// Ensure stashDir is set
|
|
1777
2000
|
if (!ctx.config.stashDir)
|
|
1778
2001
|
ctx.apply({ stashDir });
|
|
2002
|
+
// Aggregate environment detection — apply detected values directly.
|
|
2003
|
+
const env = await detectEnvironment({ existingStashDir: ctx.config.stashDir });
|
|
2004
|
+
// Apply a detected LLM (live local server) when the config has none yet.
|
|
2005
|
+
if (!getDefaultLlmConfig(ctx.config)) {
|
|
2006
|
+
const liveLocal = env.localServers.find((s) => s.available && s.defaultModel);
|
|
2007
|
+
if (liveLocal?.defaultModel) {
|
|
2008
|
+
const llm = {
|
|
2009
|
+
provider: "local",
|
|
2010
|
+
endpoint: `${liveLocal.baseUrl.replace(/\/$/, "")}/v1`,
|
|
2011
|
+
model: liveLocal.defaultModel,
|
|
2012
|
+
};
|
|
2013
|
+
// A required field being unresolvable must fail loudly rather than write
|
|
2014
|
+
// a broken config (--yes acceptance criterion).
|
|
2015
|
+
if (!llm.endpoint?.trim() || !llm.model?.trim()) {
|
|
2016
|
+
throw new UsageError("Detected a local LLM server but could not resolve a required field (endpoint/model). Re-run `akm setup` interactively.", "MISSING_REQUIRED_ARGUMENT");
|
|
2017
|
+
}
|
|
2018
|
+
ctx.apply(applyLegacyLlm(ctx.config, llm));
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
1779
2021
|
// Auto-detect agent CLI if not already configured
|
|
1780
2022
|
if (!ctx.config.defaults?.agent) {
|
|
1781
|
-
|
|
1782
|
-
|
|
2023
|
+
let defaultProfile;
|
|
2024
|
+
if (env.harness !== "none") {
|
|
2025
|
+
defaultProfile = env.harness;
|
|
2026
|
+
}
|
|
2027
|
+
else {
|
|
2028
|
+
const detected = detectAgentCliProfiles(undefined);
|
|
2029
|
+
defaultProfile = pickDefaultAgentProfile(detected, undefined);
|
|
2030
|
+
}
|
|
1783
2031
|
if (defaultProfile) {
|
|
1784
2032
|
ctx.apply(applyLegacyAgent(ctx.config, { default: defaultProfile }));
|
|
1785
2033
|
}
|
|
1786
2034
|
}
|
|
1787
2035
|
const cfgPath2 = getConfigPath();
|
|
1788
|
-
|
|
1789
|
-
backupExistingConfig(cfgPath2);
|
|
1790
|
-
p.log.info(`Config backed up to ~/.cache/akm/config-backups/`);
|
|
1791
|
-
}
|
|
2036
|
+
backupAndAnnounce(cfgPath2);
|
|
1792
2037
|
saveConfig(ctx.config);
|
|
1793
2038
|
return {
|
|
1794
2039
|
configPath: getConfigPath(),
|
|
@@ -1799,6 +2044,147 @@ export async function runSetupWithDefaults(opts) {
|
|
|
1799
2044
|
ripgrep: initResult?.ripgrep,
|
|
1800
2045
|
};
|
|
1801
2046
|
}
|
|
2047
|
+
/**
|
|
2048
|
+
* Recursively merge `incoming` into `base`: plain objects merge key-by-key,
|
|
2049
|
+
* while arrays and scalars replace wholesale. A partial input therefore only
|
|
2050
|
+
* updates the keys it carries and never drops sibling subkeys (e.g. a file
|
|
2051
|
+
* containing `{ output: { format: "text" } }` leaves `output.detail` intact).
|
|
2052
|
+
*
|
|
2053
|
+
* `base` is treated as immutable — a fresh object graph is returned.
|
|
2054
|
+
*/
|
|
2055
|
+
function deepMergeConfig(base, incoming) {
|
|
2056
|
+
if (!isPlainObject(incoming))
|
|
2057
|
+
return incoming;
|
|
2058
|
+
const baseObj = isPlainObject(base) ? base : {};
|
|
2059
|
+
const out = { ...baseObj };
|
|
2060
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
2061
|
+
if (value === undefined)
|
|
2062
|
+
continue;
|
|
2063
|
+
if (isPlainObject(value) && isPlainObject(baseObj[key])) {
|
|
2064
|
+
out[key] = deepMergeConfig(baseObj[key], value);
|
|
2065
|
+
}
|
|
2066
|
+
else {
|
|
2067
|
+
out[key] = value;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
return out;
|
|
2071
|
+
}
|
|
2072
|
+
/** True for non-null, non-array plain objects. */
|
|
2073
|
+
function isPlainObject(value) {
|
|
2074
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2075
|
+
}
|
|
2076
|
+
/**
|
|
2077
|
+
* Run ONLY environment detection and return the typed result. Performs no
|
|
2078
|
+
* config writes and shows no prompts. Backs `akm setup --detect-only`.
|
|
2079
|
+
*
|
|
2080
|
+
* SAFETY: The returned object carries env var NAMES only — never any API key
|
|
2081
|
+
* value.
|
|
2082
|
+
*/
|
|
2083
|
+
export async function runDetectOnly() {
|
|
2084
|
+
const current = loadUserConfig();
|
|
2085
|
+
return detectEnvironment({ existingStashDir: current.stashDir });
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Derive opinionated defaults from a detection result.
|
|
2089
|
+
*
|
|
2090
|
+
* - Best harness → agent default (when a profile maps to it).
|
|
2091
|
+
* - Fastest live local model, else the first detected cloud key's provider.
|
|
2092
|
+
* - `nomic-embed-text` embeddings when a local LLM is live.
|
|
2093
|
+
* - improve task `0 2 * * *`, index task `0 4 * * *`.
|
|
2094
|
+
*
|
|
2095
|
+
* Returns a partial `AkmConfig`-shaped object plus a legacy `llm` block, ready
|
|
2096
|
+
* to merge. Never includes an API key value.
|
|
2097
|
+
*/
|
|
2098
|
+
export function deriveRecommendedConfig(env) {
|
|
2099
|
+
const result = {};
|
|
2100
|
+
// Best harness → agent default. #566: derive the default profile name from
|
|
2101
|
+
// the harness registry instead of a hardcoded if-chain, so a newly added
|
|
2102
|
+
// dispatch-capable harness gets a usable headless default (its canonical id)
|
|
2103
|
+
// automatically. "none" / unknown ids resolve to undefined (no default).
|
|
2104
|
+
const agentDefault = defaultProfileName(env.harness);
|
|
2105
|
+
if (agentDefault)
|
|
2106
|
+
result.agentDefault = agentDefault;
|
|
2107
|
+
// LLM: prefer a live local server, else a detected cloud provider key.
|
|
2108
|
+
const liveLocal = env.localServers.find((s) => s.available && s.defaultModel);
|
|
2109
|
+
if (liveLocal?.defaultModel) {
|
|
2110
|
+
result.llm = {
|
|
2111
|
+
provider: "local",
|
|
2112
|
+
endpoint: `${liveLocal.baseUrl.replace(/\/$/, "")}/v1`,
|
|
2113
|
+
model: liveLocal.defaultModel,
|
|
2114
|
+
};
|
|
2115
|
+
// Local LLM live → use a local embedding model.
|
|
2116
|
+
result.embedding = { provider: "ollama", model: "nomic-embed-text", endpoint: `${liveLocal.baseUrl}/v1` };
|
|
2117
|
+
}
|
|
2118
|
+
else {
|
|
2119
|
+
// Map a detected cloud API-key provider to an llm endpoint. NAMES only —
|
|
2120
|
+
// the value lives in the env var the user already set; we never read it.
|
|
2121
|
+
const cloud = env.providers.find((pr) => pr.kind === "apiKey");
|
|
2122
|
+
if (cloud) {
|
|
2123
|
+
const endpoint = cloudEndpointForProvider(cloud.provider);
|
|
2124
|
+
const model = cloudDefaultModelForProvider(cloud.provider);
|
|
2125
|
+
if (endpoint && model) {
|
|
2126
|
+
result.llm = { provider: cloud.provider, endpoint, model };
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
result.taskSchedules = { improve: "0 2 * * *", index: "0 4 * * *" };
|
|
2131
|
+
return result;
|
|
2132
|
+
}
|
|
2133
|
+
function cloudEndpointForProvider(provider) {
|
|
2134
|
+
switch (provider) {
|
|
2135
|
+
case "anthropic":
|
|
2136
|
+
return "https://api.anthropic.com/v1";
|
|
2137
|
+
case "openai":
|
|
2138
|
+
return "https://api.openai.com/v1";
|
|
2139
|
+
case "gemini":
|
|
2140
|
+
return "https://generativelanguage.googleapis.com/v1beta/openai";
|
|
2141
|
+
case "groq":
|
|
2142
|
+
return "https://api.groq.com/openai/v1";
|
|
2143
|
+
default:
|
|
2144
|
+
return undefined;
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
function cloudDefaultModelForProvider(provider) {
|
|
2148
|
+
switch (provider) {
|
|
2149
|
+
case "anthropic":
|
|
2150
|
+
return "claude-sonnet-4-5";
|
|
2151
|
+
case "openai":
|
|
2152
|
+
return "gpt-4o-mini";
|
|
2153
|
+
case "gemini":
|
|
2154
|
+
return "gemini-1.5-flash";
|
|
2155
|
+
case "groq":
|
|
2156
|
+
return "llama-3.3-70b-versatile";
|
|
2157
|
+
default:
|
|
2158
|
+
return undefined;
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
/**
|
|
2162
|
+
* `akm setup --reset-recommended`: merge opinionated, detection-derived
|
|
2163
|
+
* defaults into the existing config WITHOUT removing pre-existing custom keys.
|
|
2164
|
+
* Uses the same merge path as {@link runSetupFromConfig} so custom keys survive
|
|
2165
|
+
* (follows #511 semantics).
|
|
2166
|
+
*/
|
|
2167
|
+
export async function runResetRecommended(opts) {
|
|
2168
|
+
const current = loadUserConfig();
|
|
2169
|
+
const env = await detectEnvironment({ existingStashDir: current.stashDir });
|
|
2170
|
+
const recommended = deriveRecommendedConfig(env);
|
|
2171
|
+
const incoming = {};
|
|
2172
|
+
if (recommended.llm)
|
|
2173
|
+
incoming.llm = recommended.llm;
|
|
2174
|
+
if (recommended.embedding)
|
|
2175
|
+
incoming.embedding = recommended.embedding;
|
|
2176
|
+
if (recommended.agentDefault)
|
|
2177
|
+
incoming.agent = { default: recommended.agentDefault };
|
|
2178
|
+
if (recommended.taskSchedules) {
|
|
2179
|
+
incoming.setup = { taskSchedules: recommended.taskSchedules };
|
|
2180
|
+
}
|
|
2181
|
+
return runSetupFromConfig({
|
|
2182
|
+
configJson: JSON.stringify(incoming),
|
|
2183
|
+
dir: opts.dir,
|
|
2184
|
+
noInit: opts.noInit,
|
|
2185
|
+
probe: opts.probe,
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
1802
2188
|
/**
|
|
1803
2189
|
* Apply a JSON config blob non-interactively, merging it with the current config.
|
|
1804
2190
|
* Validates required sub-fields and strips unknown/restricted keys.
|
|
@@ -1821,6 +2207,7 @@ export async function runSetupFromConfig(opts) {
|
|
|
1821
2207
|
"output",
|
|
1822
2208
|
"profiles",
|
|
1823
2209
|
"defaults",
|
|
2210
|
+
"setup",
|
|
1824
2211
|
]);
|
|
1825
2212
|
for (const key of Object.keys(incoming)) {
|
|
1826
2213
|
if (!ALLOWED_KEYS.has(key)) {
|
|
@@ -1852,12 +2239,16 @@ export async function runSetupFromConfig(opts) {
|
|
|
1852
2239
|
assertSetupSandbox(stashDir, stashDirExplicit);
|
|
1853
2240
|
applyStashIsolationToEnv(stashDir, stashDirExplicit);
|
|
1854
2241
|
let merged = { ...current, stashDir };
|
|
1855
|
-
//
|
|
1856
|
-
|
|
2242
|
+
// Deep-merge non-llm/agent keys: nested objects merge key-by-key so a
|
|
2243
|
+
// partial `--file` only updates the keys it carries and never drops sibling
|
|
2244
|
+
// subkeys (e.g. output.detail survives an output.format-only file). Arrays
|
|
2245
|
+
// and scalars replace wholesale.
|
|
1857
2246
|
for (const key of Object.keys(incoming)) {
|
|
1858
2247
|
if (key === "llm" || key === "agent")
|
|
1859
2248
|
continue;
|
|
1860
|
-
|
|
2249
|
+
const incomingVal = incoming[key];
|
|
2250
|
+
const mergedRec = merged;
|
|
2251
|
+
mergedRec[key] = deepMergeConfig(mergedRec[key], incomingVal);
|
|
1861
2252
|
}
|
|
1862
2253
|
// Translate legacy llm/agent inputs into the new shape.
|
|
1863
2254
|
if (incoming.llm) {
|
|
@@ -1866,6 +2257,29 @@ export async function runSetupFromConfig(opts) {
|
|
|
1866
2257
|
if (incoming.agent) {
|
|
1867
2258
|
merged = { ...merged, ...applyLegacyAgent(merged, incoming.agent) };
|
|
1868
2259
|
}
|
|
2260
|
+
// With `--yes`, fill keys still missing after the merge with non-interactive
|
|
2261
|
+
// defaults. Steps start from `merged` and their nonInteractive path only
|
|
2262
|
+
// populates absent values, so nothing the file or existing config supplied
|
|
2263
|
+
// is overwritten.
|
|
2264
|
+
if (opts.applyDefaults) {
|
|
2265
|
+
const ctx = createSetupContext(merged, { nonInteractive: true });
|
|
2266
|
+
const { steps } = buildSetupSteps({
|
|
2267
|
+
online: false,
|
|
2268
|
+
semanticSearchOutcome: { mode: merged.semanticSearchMode, prepareAssets: false },
|
|
2269
|
+
preferredStashDir: stashDir,
|
|
2270
|
+
});
|
|
2271
|
+
await runSetupSteps(steps, ctx);
|
|
2272
|
+
if (!ctx.config.stashDir)
|
|
2273
|
+
ctx.apply({ stashDir });
|
|
2274
|
+
if (!ctx.config.defaults?.agent) {
|
|
2275
|
+
const detected = detectAgentCliProfiles(undefined);
|
|
2276
|
+
const defaultProfile = pickDefaultAgentProfile(detected, undefined);
|
|
2277
|
+
if (defaultProfile) {
|
|
2278
|
+
ctx.apply(applyLegacyAgent(ctx.config, { default: defaultProfile }));
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
merged = ctx.config;
|
|
2282
|
+
}
|
|
1869
2283
|
// Bootstrap directory structure
|
|
1870
2284
|
let initResult;
|
|
1871
2285
|
if (!opts.noInit) {
|
|
@@ -1891,10 +2305,7 @@ export async function runSetupFromConfig(opts) {
|
|
|
1891
2305
|
}
|
|
1892
2306
|
}
|
|
1893
2307
|
const cfgPath3 = getConfigPath();
|
|
1894
|
-
|
|
1895
|
-
backupExistingConfig(cfgPath3);
|
|
1896
|
-
p.log.info(`Config backed up to ~/.cache/akm/config-backups/`);
|
|
1897
|
-
}
|
|
2308
|
+
backupAndAnnounce(cfgPath3);
|
|
1898
2309
|
saveConfig(merged);
|
|
1899
2310
|
return {
|
|
1900
2311
|
configPath: getConfigPath(),
|
package/dist/sources/include.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import { isWithin } from "../core/common";
|
|
6
|
+
import { isWithin } from "../core/common.js";
|
|
7
7
|
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
8
8
|
/** Key to check in package.json for akm include configuration. */
|
|
9
9
|
const INCLUDE_CONFIG_KEYS = ["akm"];
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { getSources } from "../core/config";
|
|
5
|
-
import { createProviderRegistry } from "../registry/create-provider-registry";
|
|
4
|
+
import { getSources } from "../core/config/config.js";
|
|
5
|
+
import { createProviderRegistry } from "../registry/create-provider-registry.js";
|
|
6
6
|
// ── Factory map ─────────────────────────────────────────────────────────────
|
|
7
7
|
const registry = createProviderRegistry();
|
|
8
8
|
export function registerSourceProvider(type, factory) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { resolveStashDir } from "../../core/common";
|
|
5
|
-
import { ConfigError } from "../../core/errors";
|
|
6
|
-
import { registerSourceProvider } from "../provider-factory";
|
|
4
|
+
import { resolveStashDir } from "../../core/common.js";
|
|
5
|
+
import { ConfigError } from "../../core/errors.js";
|
|
6
|
+
import { registerSourceProvider } from "../provider-factory.js";
|
|
7
7
|
/**
|
|
8
8
|
* Filesystem source — points at a directory the user already manages.
|
|
9
9
|
*
|