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
|
@@ -2,31 +2,34 @@
|
|
|
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
4
|
/**
|
|
5
|
-
* write-source — the
|
|
5
|
+
* write-source — the command-layer helper that performs asset writes.
|
|
6
6
|
*
|
|
7
|
-
* v1 architecture spec §2.6 / §2.7 / §10 step 5: writing to
|
|
8
|
-
* a SourceProvider interface concern. It's a small
|
|
9
|
-
* does a plain filesystem write
|
|
10
|
-
* push) when the source is backed by a git working tree.
|
|
7
|
+
* v1 architecture spec §2.6 / §2.7 / §10 step 5 (amended for 0.9.0): writing to
|
|
8
|
+
* a source is *not* a SourceProvider interface concern. It's a small
|
|
9
|
+
* command-layer helper that does a plain filesystem write for **every** kind.
|
|
11
10
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* 0.9.0 amendment (issue #507): the per-asset git commit/push path is retired.
|
|
12
|
+
* `writeAssetToSource` / `deleteAssetFromSource` no longer branch on `kind` for
|
|
13
|
+
* commit behaviour — they only ever touch the filesystem. Git-backed targets
|
|
14
|
+
* are committed in a SINGLE batch at the operation boundary via
|
|
15
|
+
* {@link commitWriteTargetBoundary} (which delegates to `saveGitStash`). This
|
|
16
|
+
* stages `.akm/` + sibling assets together as one complete commit instead of
|
|
17
|
+
* one noisy, incomplete commit per asset.
|
|
15
18
|
*
|
|
16
|
-
* This module is the **single dispatch point** for
|
|
17
|
-
*
|
|
18
|
-
* `
|
|
19
|
-
*
|
|
19
|
+
* This module is still the **single dispatch point** for write/delete: callers
|
|
20
|
+
* (remember, import, source-add, etc.) MUST go through `writeAssetToSource` /
|
|
21
|
+
* `deleteAssetFromSource` rather than re-inlining a filesystem write, and they
|
|
22
|
+
* fire {@link commitWriteTargetBoundary} once after a batch of mutations to a
|
|
23
|
+
* writable git target.
|
|
20
24
|
*/
|
|
21
|
-
import { spawnSync } from "node:child_process";
|
|
22
25
|
import fs from "node:fs";
|
|
23
26
|
import path from "node:path";
|
|
24
|
-
import { getCachePaths, parseGitRepoUrl } from "../sources/providers/git";
|
|
25
|
-
import { makeAssetRef } from "./asset-ref";
|
|
26
|
-
import { resolveAssetPathFromName, TYPE_DIRS } from "./asset-spec";
|
|
27
|
-
import { isWithin, resolveStashDir } from "./common";
|
|
28
|
-
import { resolveConfiguredSources } from "./config";
|
|
29
|
-
import { ConfigError, UsageError } from "./errors";
|
|
27
|
+
import { getCachePaths, parseGitRepoUrl, saveGitStash } from "../sources/providers/git.js";
|
|
28
|
+
import { makeAssetRef } from "./asset/asset-ref.js";
|
|
29
|
+
import { resolveAssetPathFromName, TYPE_DIRS } from "./asset/asset-spec.js";
|
|
30
|
+
import { isWithin, resolveStashDir } from "./common.js";
|
|
31
|
+
import { resolveConfiguredSources } from "./config/config.js";
|
|
32
|
+
import { ConfigError, UsageError } from "./errors.js";
|
|
30
33
|
/**
|
|
31
34
|
* Source kinds that the loader is allowed to mark `writable: true`. Anything
|
|
32
35
|
* else is rejected at config load (per locked decision 4) — see
|
|
@@ -114,41 +117,91 @@ export function assertWritableAllowedForKind(entry) {
|
|
|
114
117
|
* `ref`. Always:
|
|
115
118
|
*
|
|
116
119
|
* 1. Refuses if `config.writable` is not truthy (per §5.4).
|
|
117
|
-
* 2.
|
|
120
|
+
* 2. Rejects unsupported kinds (anything but `filesystem` / `git`).
|
|
121
|
+
* 3. Performs a plain filesystem write to `path.join(source.path, …)`.
|
|
118
122
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* 5. `git -C <path> push` when `config.options.pushOnCommit` is truthy.
|
|
124
|
-
*
|
|
125
|
-
* Any other `kind` reaching this helper is a configuration bug — the loader
|
|
126
|
-
* rejects unsupported writable kinds — so we throw {@link ConfigError}.
|
|
123
|
+
* No commit runs here — for **every** kind. Git-backed targets are committed in
|
|
124
|
+
* one batch at the operation boundary via {@link commitWriteTargetBoundary}
|
|
125
|
+
* (0.9.0 amendment, issue #507). The caller fires that boundary commit once
|
|
126
|
+
* after a batch of mutations to a writable git target.
|
|
127
127
|
*/
|
|
128
128
|
export async function writeAssetToSource(source, config, ref, content) {
|
|
129
129
|
ensureWritable(source, config);
|
|
130
|
+
assertSupportedKind(source);
|
|
130
131
|
const filePath = resolveAssetFilePath(source, ref);
|
|
131
132
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
132
133
|
const normalized = content.endsWith("\n") ? content : `${content}\n`;
|
|
133
134
|
fs.writeFileSync(filePath, normalized, "utf8");
|
|
134
|
-
await runKindSpecificCommit(source, config, filePath, `Update ${formatRefForMessage(ref)}`);
|
|
135
135
|
return { path: filePath, ref: makeAssetRef(ref.type, ref.name, ref.origin) };
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
138
138
|
* Delete the asset at `ref` from `source`. Symmetric to
|
|
139
|
-
* {@link writeAssetToSource}: same writable check, same
|
|
140
|
-
*
|
|
139
|
+
* {@link writeAssetToSource}: same writable check, same unsupported-kind guard,
|
|
140
|
+
* a plain `unlink` with no commit. Git-backed targets are committed once at the
|
|
141
|
+
* operation boundary via {@link commitWriteTargetBoundary}.
|
|
141
142
|
*/
|
|
142
143
|
export async function deleteAssetFromSource(source, config, ref) {
|
|
143
144
|
ensureWritable(source, config);
|
|
145
|
+
assertSupportedKind(source);
|
|
144
146
|
const filePath = resolveAssetFilePath(source, ref);
|
|
145
147
|
if (!fs.existsSync(filePath)) {
|
|
146
148
|
throw new UsageError(`Asset "${formatRefForMessage(ref)}" not found in source "${source.name}" (expected at ${filePath}).`, "MISSING_REQUIRED_ARGUMENT");
|
|
147
149
|
}
|
|
148
150
|
fs.unlinkSync(filePath);
|
|
149
|
-
await runKindSpecificCommit(source, config, filePath, `Remove ${formatRefForMessage(ref)}`);
|
|
150
151
|
return { path: filePath, ref: makeAssetRef(ref.type, ref.name, ref.origin) };
|
|
151
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Fire the one-shot batch-at-boundary commit for a resolved write target.
|
|
155
|
+
*
|
|
156
|
+
* 0.9.0 (issue #507): replaces the retired per-asset git commit. Callers invoke
|
|
157
|
+
* this EXACTLY ONCE after a batch of writes/deletes to a resolved write target.
|
|
158
|
+
* It is a no-op for any non-git target (plain filesystem sources and the
|
|
159
|
+
* primary stash stay non-committing here — the primary stash is committed by
|
|
160
|
+
* the existing improve auto-sync boundary).
|
|
161
|
+
*
|
|
162
|
+
* For a git target it delegates to `saveGitStash(name, message, writable, …)`,
|
|
163
|
+
* which stages `.akm/` + sibling assets together (`git add -A`), commits once,
|
|
164
|
+
* and pushes when the target is writable, has a remote, and `push !== false`.
|
|
165
|
+
*
|
|
166
|
+
* The push intent honours a deprecated `options.pushOnCommit` on the source
|
|
167
|
+
* config (mapped onto the batch push gate) when `push` is not explicitly set.
|
|
168
|
+
*/
|
|
169
|
+
export function commitWriteTargetBoundary(target, message, options) {
|
|
170
|
+
if (target.source.kind !== "git")
|
|
171
|
+
return;
|
|
172
|
+
warnIfPushOnCommit(target.config);
|
|
173
|
+
// Map the deprecated per-asset `pushOnCommit` intent onto the batch push gate
|
|
174
|
+
// when the caller did not pass an explicit push toggle. `saveGitStash` still
|
|
175
|
+
// gates the actual push on writable + remote, so this only ever opts *in*.
|
|
176
|
+
const push = options?.push ?? (target.config.options?.pushOnCommit === true ? true : undefined);
|
|
177
|
+
const writable = resolveWritable(target.config);
|
|
178
|
+
// Commit against the already-resolved repo directory (target.source.path)
|
|
179
|
+
// rather than re-resolving the stash by name through config. The write helper
|
|
180
|
+
// resolved this exact path; the boundary commit must operate on the SAME
|
|
181
|
+
// directory so the staged batch matches what was just written.
|
|
182
|
+
saveGitStash(undefined, message, writable, {
|
|
183
|
+
repoDir: target.source.path,
|
|
184
|
+
...(push === undefined ? {} : { push }),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Emit a one-time deprecation warning the first time a source config carrying
|
|
189
|
+
* `options.pushOnCommit` is encountered. The field still parses (for old
|
|
190
|
+
* configs) but its per-asset push-on-commit behaviour is retired; its intent is
|
|
191
|
+
* now honoured via the batch push gate (writable + remote + push toggle).
|
|
192
|
+
*/
|
|
193
|
+
let pushOnCommitWarned = false;
|
|
194
|
+
function warnIfPushOnCommit(config) {
|
|
195
|
+
if (config.options?.pushOnCommit === undefined)
|
|
196
|
+
return;
|
|
197
|
+
if (pushOnCommitWarned)
|
|
198
|
+
return;
|
|
199
|
+
pushOnCommitWarned = true;
|
|
200
|
+
const label = config.name ? ` on source "${config.name}"` : "";
|
|
201
|
+
process.stderr.write(`warning: \`options.pushOnCommit\`${label} is deprecated (0.9.0) and no longer commits per asset. ` +
|
|
202
|
+
"akm now commits writes in a single batch at the operation boundary and pushes when the target is " +
|
|
203
|
+
"writable with a remote. Remove the option or rely on sync push instead.\n");
|
|
204
|
+
}
|
|
152
205
|
/**
|
|
153
206
|
* Resolve the destination for a write per locked decision 3:
|
|
154
207
|
*
|
|
@@ -201,12 +254,10 @@ export function resolveWriteTarget(akmConfig, explicitTarget) {
|
|
|
201
254
|
//
|
|
202
255
|
// The primary stash stays `kind: "filesystem"` on purpose, even when it is a
|
|
203
256
|
// git repo on disk (recognized elsewhere via isGitBackedStash). Returning
|
|
204
|
-
// `kind: "git"` here would
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
// non-committing, and the primary stash is committed in a single batch at
|
|
209
|
-
// operation boundaries (e.g. the end-of-run improve auto-sync via saveGitStash).
|
|
257
|
+
// `kind: "git"` here would fire the boundary commit on every write through
|
|
258
|
+
// this resolver, double-committing the primary stash which is already
|
|
259
|
+
// committed in a single batch at operation boundaries (e.g. the end-of-run
|
|
260
|
+
// improve auto-sync via saveGitStash). Per-write stays non-committing.
|
|
210
261
|
try {
|
|
211
262
|
const stashDir = resolveStashDir({ readOnly: true });
|
|
212
263
|
return {
|
|
@@ -241,57 +292,19 @@ function resolveAssetFilePath(source, ref) {
|
|
|
241
292
|
}
|
|
242
293
|
return assetPath;
|
|
243
294
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
295
|
+
/**
|
|
296
|
+
* Reject any kind reaching the write/delete helpers other than the two
|
|
297
|
+
* supported writable kinds. The config loader is the first line of defence
|
|
298
|
+
* (assertWritableAllowedForKind), but we throw here so external callers that
|
|
299
|
+
* bypass the loader still get a clear error.
|
|
300
|
+
*/
|
|
301
|
+
function assertSupportedKind(source) {
|
|
302
|
+
if (source.kind === "filesystem" || source.kind === "git")
|
|
253
303
|
return;
|
|
254
|
-
}
|
|
255
|
-
// Reject any other kind reaching the helper. The config loader is the
|
|
256
|
-
// first line of defence (assertWritableAllowedForKind), but we throw here
|
|
257
|
-
// so external callers that bypass the loader still get a clear error.
|
|
258
304
|
throw new ConfigError(`write-source: unsupported kind "${source.kind}" for source "${source.name}". ` +
|
|
259
305
|
"Writes are only defined for `filesystem` and `git` sources.", "INVALID_CONFIG_FILE", 'Set `kind: "filesystem"` (or `kind: "git"`) on the source, or add a parallel filesystem entry.');
|
|
260
306
|
}
|
|
261
|
-
function
|
|
262
|
-
// Stage the specific file rather than `add -A` so unrelated working-tree
|
|
263
|
-
// changes don't get folded into the asset commit.
|
|
264
|
-
const relPath = path.relative(repoDir, filePath) || filePath;
|
|
265
|
-
const addResult = spawnSync("git", ["-C", repoDir, "add", "--", relPath], { encoding: "utf8" });
|
|
266
|
-
if (addResult.status !== 0) {
|
|
267
|
-
throw new Error(`git add failed: ${addResult.stderr?.trim() || "unknown error"}`);
|
|
268
|
-
}
|
|
269
|
-
// Defense in depth: sanitize the commit subject one more time at the spawn
|
|
270
|
-
// boundary. Callers should already pass sanitized strings (via
|
|
271
|
-
// formatRefForMessage / saveGitStash), but this guards against future
|
|
272
|
-
// refactors that forget. Empty after sanitize falls back to a safe stub.
|
|
273
|
-
const safeMessage = sanitizeCommitMessage(message) || "akm update";
|
|
274
|
-
// Provide a fallback identity so fresh CI/test environments without
|
|
275
|
-
// user.name/user.email configured can always commit.
|
|
276
|
-
const commitResult = spawnSync("git", ["-C", repoDir, "-c", "user.name=akm", "-c", "user.email=akm@local", "commit", "-m", safeMessage], { encoding: "utf8" });
|
|
277
|
-
if (commitResult.status !== 0) {
|
|
278
|
-
// `nothing to commit` is a no-op success — the file may have matched the
|
|
279
|
-
// existing tree exactly. Surface other errors verbatim.
|
|
280
|
-
const stderr = commitResult.stderr ?? "";
|
|
281
|
-
if (/nothing to commit|no changes added/i.test(stderr) ||
|
|
282
|
-
/nothing to commit|no changes added/i.test(commitResult.stdout ?? "")) {
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
throw new Error(`git commit failed: ${stderr.trim() || "unknown error"}`);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
function runGitPush(repoDir) {
|
|
289
|
-
const pushResult = spawnSync("git", ["-C", repoDir, "push"], { encoding: "utf8", timeout: 120_000 });
|
|
290
|
-
if (pushResult.status !== 0) {
|
|
291
|
-
throw new Error(`git push failed: ${pushResult.stderr?.trim() || "unknown error"}`);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
function formatRefForMessage(ref) {
|
|
307
|
+
export function formatRefForMessage(ref) {
|
|
295
308
|
// Sanitize each component independently. `ref.origin` originates from user
|
|
296
309
|
// config and could contain CR/LF that would otherwise be smuggled into the
|
|
297
310
|
// commit subject and forge trailers downstream. `ref.type` and `ref.name`
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* MVP data-directory backup for AKM.
|
|
6
6
|
*
|
|
7
|
-
* The DB upgrade path in `src/indexer/db.ts` `handleVersionUpgrade()` is
|
|
7
|
+
* The DB upgrade path in `src/indexer/db/db.ts` `handleVersionUpgrade()` is
|
|
8
8
|
* intentionally destructive: when `DB_VERSION` bumps and a stored DB is at an
|
|
9
9
|
* older version, ~17 tables are dropped and recreated. Until 0.9.0 ships a
|
|
10
10
|
* full migration framework, this MVP captures a recursive copy of the entire
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
*/
|
|
28
28
|
import fs from "node:fs";
|
|
29
29
|
import path from "node:path";
|
|
30
|
-
import {
|
|
30
|
+
import { bestEffort } from "../../core/best-effort.js";
|
|
31
|
+
import { warn } from "../../core/warn.js";
|
|
31
32
|
/** Default reason recorded for backups that don't override it. */
|
|
32
33
|
export const DEFAULT_BACKUP_REASON = "version-upgrade";
|
|
33
34
|
/** Reason recorded for backups taken before the embedding-dim drop path. */
|
|
@@ -95,12 +96,9 @@ export function measureDataDirSize(dirPath) {
|
|
|
95
96
|
stack.push(full);
|
|
96
97
|
}
|
|
97
98
|
else if (entry.isFile()) {
|
|
98
|
-
|
|
99
|
+
bestEffort(() => {
|
|
99
100
|
total += fs.statSync(full).size;
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
// File vanished between readdir and stat — ignore.
|
|
103
|
-
}
|
|
101
|
+
}, "file vanished between readdir and stat");
|
|
104
102
|
}
|
|
105
103
|
}
|
|
106
104
|
}
|
|
@@ -154,7 +152,7 @@ export function listBackups(dataDir) {
|
|
|
154
152
|
let sizeBytes;
|
|
155
153
|
let reason = DEFAULT_BACKUP_REASON;
|
|
156
154
|
if (fs.existsSync(metaPath)) {
|
|
157
|
-
|
|
155
|
+
bestEffort(() => {
|
|
158
156
|
const raw = fs.readFileSync(metaPath, "utf8");
|
|
159
157
|
const parsed = JSON.parse(raw);
|
|
160
158
|
if (typeof parsed.createdAt === "string")
|
|
@@ -167,10 +165,7 @@ export function listBackups(dataDir) {
|
|
|
167
165
|
sizeBytes = parsed.sizeBytes;
|
|
168
166
|
if (typeof parsed.reason === "string" && parsed.reason.length > 0)
|
|
169
167
|
reason = parsed.reason;
|
|
170
|
-
}
|
|
171
|
-
catch {
|
|
172
|
-
// Malformed metadata — fall back to filesystem-derived values.
|
|
173
|
-
}
|
|
168
|
+
}, "malformed backup metadata — fall back to filesystem-derived values");
|
|
174
169
|
}
|
|
175
170
|
if (!createdAt) {
|
|
176
171
|
try {
|
|
@@ -286,12 +281,7 @@ export function backupDataDir(opts) {
|
|
|
286
281
|
catch (err) {
|
|
287
282
|
warn("[akm] data dir backup failed — %s; upgrade will proceed without a snapshot", err instanceof Error ? err.message : String(err));
|
|
288
283
|
// Best-effort cleanup of the partial copy so we don't litter the data dir.
|
|
289
|
-
|
|
290
|
-
fs.rmSync(finalDest, { recursive: true, force: true });
|
|
291
|
-
}
|
|
292
|
-
catch {
|
|
293
|
-
/* ignore */
|
|
294
|
-
}
|
|
284
|
+
bestEffort(() => fs.rmSync(finalDest, { recursive: true, force: true }), "cleanup partial backup copy");
|
|
295
285
|
return null;
|
|
296
286
|
}
|
|
297
287
|
const createdAt = now.toISOString();
|
|
@@ -369,12 +359,7 @@ function copyDataDirExcludingBackups(srcRoot, destRoot) {
|
|
|
369
359
|
// dir occasionally carries symlinked source roots; following them
|
|
370
360
|
// could explode the backup size unexpectedly.
|
|
371
361
|
const target = fs.readlinkSync(srcPath);
|
|
372
|
-
|
|
373
|
-
fs.symlinkSync(target, destPath);
|
|
374
|
-
}
|
|
375
|
-
catch {
|
|
376
|
-
/* ignore — symlink creation can fail on Windows without admin */
|
|
377
|
-
}
|
|
362
|
+
bestEffort(() => fs.symlinkSync(target, destPath), "symlink creation can fail on Windows without admin");
|
|
378
363
|
}
|
|
379
364
|
// Other entry types (block/character/fifo/socket) are silently skipped.
|
|
380
365
|
}
|