akm-cli 0.8.0-rc2 → 0.8.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/{.github/CHANGELOG.md → CHANGELOG.md} +238 -3
- package/README.md +22 -6
- package/SECURITY.md +93 -0
- package/dist/assets/help/help-accept.md +12 -0
- package/dist/assets/help/help-improve.md +81 -0
- package/dist/{commands → assets}/help/help-proposals.md +7 -4
- package/dist/assets/help/help-reject.md +11 -0
- package/dist/{output → assets/hints}/cli-hints-full.md +60 -32
- package/dist/{output → assets/hints}/cli-hints-short.md +10 -7
- package/dist/assets/profiles/default.json +15 -0
- package/dist/assets/profiles/graph-refresh.json +13 -0
- package/dist/assets/profiles/memory-focus.json +12 -0
- package/dist/assets/profiles/quick.json +15 -0
- package/dist/assets/profiles/thorough.json +15 -0
- package/dist/assets/prompts/extract-session.md +80 -0
- package/dist/assets/prompts/graph-extract-user-prompt.md +35 -0
- package/dist/assets/tasks/graph-refresh-weekly.yml +10 -0
- package/dist/cli/config-migrate.js +144 -0
- package/dist/cli/config-validate.js +39 -0
- package/dist/cli/confirm.js +73 -0
- package/dist/cli/parse-args.js +93 -3
- package/dist/cli/shared.js +129 -0
- package/dist/cli.js +2141 -1268
- package/dist/commands/add-cli.js +279 -0
- package/dist/commands/agent-dispatch.js +20 -12
- package/dist/commands/agent-support.js +11 -5
- package/dist/commands/completions.js +3 -0
- package/dist/commands/config-cli.js +129 -517
- package/dist/commands/consolidate.js +1557 -147
- package/dist/commands/curate.js +44 -3
- package/dist/commands/db-cli.js +23 -0
- package/dist/commands/distill-promotion-policy.js +5 -3
- package/dist/commands/distill.js +906 -100
- package/dist/commands/env.js +213 -0
- package/dist/commands/eval-cases.js +3 -0
- package/dist/commands/events.js +3 -0
- package/dist/commands/extract-cli.js +127 -0
- package/dist/commands/extract-prompt.js +217 -0
- package/dist/commands/extract.js +477 -0
- package/dist/commands/feedback-cli.js +331 -0
- package/dist/commands/graph.js +260 -5
- package/dist/commands/health.js +1042 -55
- package/dist/commands/history.js +51 -16
- package/dist/commands/improve-auto-accept.js +97 -0
- package/dist/commands/improve-cli.js +236 -0
- package/dist/commands/improve-profiles.js +138 -0
- package/dist/commands/improve-result-file.js +167 -0
- package/dist/commands/improve.js +1736 -346
- package/dist/commands/info.js +26 -28
- package/dist/commands/init.js +49 -1
- package/dist/commands/installed-stashes.js +6 -23
- package/dist/commands/knowledge.js +3 -0
- package/dist/commands/lint/agent-linter.js +3 -0
- package/dist/commands/lint/base-linter.js +199 -5
- package/dist/commands/lint/command-linter.js +3 -0
- package/dist/commands/lint/default-linter.js +3 -0
- package/dist/commands/lint/env-key-rules.js +154 -0
- package/dist/commands/lint/index.js +92 -3
- package/dist/commands/lint/knowledge-linter.js +3 -0
- package/dist/commands/lint/markdown-insertion.js +343 -0
- package/dist/commands/lint/memory-linter.js +3 -0
- package/dist/commands/lint/registry.js +3 -0
- package/dist/commands/lint/skill-linter.js +3 -0
- package/dist/commands/lint/task-linter.js +15 -12
- package/dist/commands/lint/types.js +3 -0
- package/dist/commands/lint/workflow-linter.js +3 -0
- package/dist/commands/lint.js +3 -0
- package/dist/commands/migration-help.js +5 -2
- package/dist/commands/proposal-drain-policies.js +128 -0
- package/dist/commands/proposal-drain.js +477 -0
- package/dist/commands/proposal.js +60 -6
- package/dist/commands/propose.js +24 -19
- package/dist/commands/reflect.js +1004 -94
- package/dist/commands/registry-cli.js +150 -0
- package/dist/commands/registry-search.js +3 -0
- package/dist/commands/remember-cli.js +257 -0
- package/dist/commands/remember.js +15 -6
- package/dist/commands/schema-repair.js +88 -15
- package/dist/commands/search.js +99 -14
- package/dist/commands/secret.js +173 -0
- package/dist/commands/self-update.js +3 -0
- package/dist/commands/show.js +32 -13
- package/dist/commands/source-add.js +7 -35
- package/dist/commands/source-clone.js +3 -0
- package/dist/commands/source-manage.js +3 -0
- package/dist/commands/tasks.js +161 -95
- package/dist/commands/url-checker.js +3 -0
- package/dist/core/action-contributors.js +3 -0
- package/dist/core/asset-ref.js +13 -2
- package/dist/core/asset-registry.js +9 -2
- package/dist/core/asset-serialize.js +88 -0
- package/dist/core/asset-spec.js +61 -5
- package/dist/core/common.js +93 -5
- package/dist/core/concurrent.js +3 -0
- package/dist/core/config-io.js +347 -0
- package/dist/core/config-migration.js +622 -0
- package/dist/core/config-schema.js +558 -0
- package/dist/core/config-sources.js +108 -0
- package/dist/core/config-types.js +4 -0
- package/dist/core/config-walker.js +337 -0
- package/dist/core/config.js +366 -1077
- package/dist/core/errors.js +42 -20
- package/dist/core/events.js +31 -25
- package/dist/core/file-lock.js +104 -0
- package/dist/core/frontmatter.js +75 -10
- package/dist/core/lesson-lint.js +3 -0
- package/dist/core/markdown.js +3 -0
- package/dist/core/memory-belief.js +62 -0
- package/dist/core/memory-contradiction-detect.js +274 -0
- package/dist/core/memory-improve.js +142 -14
- package/dist/core/parse.js +3 -0
- package/dist/core/paths.js +218 -50
- package/dist/core/proposal-quality-validators.js +380 -0
- package/dist/core/proposal-validators.js +11 -3
- package/dist/core/proposals.js +464 -5
- package/dist/core/state-db.js +349 -56
- package/dist/core/text-truncation.js +107 -0
- package/dist/core/time.js +3 -0
- package/dist/core/tty.js +59 -0
- package/dist/core/warn.js +7 -2
- package/dist/core/write-source.js +12 -0
- package/dist/indexer/db-backup.js +391 -0
- package/dist/indexer/db-search.js +136 -28
- package/dist/indexer/db.js +661 -166
- package/dist/indexer/ensure-index.js +3 -0
- package/dist/indexer/file-context.js +3 -0
- package/dist/indexer/graph-boost.js +162 -40
- package/dist/indexer/graph-db.js +241 -51
- package/dist/indexer/graph-dedup.js +3 -7
- package/dist/indexer/graph-extraction.js +242 -149
- package/dist/indexer/index-context.js +3 -9
- package/dist/indexer/indexer.js +86 -16
- package/dist/indexer/llm-cache.js +24 -19
- package/dist/indexer/manifest.js +3 -0
- package/dist/indexer/matchers.js +184 -11
- package/dist/indexer/memory-inference.js +94 -50
- package/dist/indexer/metadata-contributors.js +3 -0
- package/dist/indexer/metadata.js +110 -50
- package/dist/indexer/path-resolver.js +3 -0
- package/dist/indexer/project-context.js +192 -0
- package/dist/indexer/ranking-contributors.js +134 -7
- package/dist/indexer/ranking.js +8 -1
- package/dist/indexer/search-fields.js +5 -9
- package/dist/indexer/search-hit-enrichers.js +91 -2
- package/dist/indexer/search-source.js +20 -1
- package/dist/indexer/semantic-status.js +4 -1
- package/dist/indexer/staleness-detect.js +447 -0
- package/dist/indexer/usage-events.js +12 -9
- package/dist/indexer/walker.js +3 -0
- package/dist/integrations/agent/builders.js +135 -0
- package/dist/integrations/agent/config.js +121 -401
- package/dist/integrations/agent/detect.js +3 -0
- package/dist/integrations/agent/index.js +6 -14
- package/dist/integrations/agent/model-aliases.js +55 -0
- package/dist/integrations/agent/profiles.js +3 -0
- package/dist/integrations/agent/prompts.js +137 -8
- package/dist/integrations/agent/runner.js +208 -0
- package/dist/integrations/agent/sdk-runner.js +8 -2
- package/dist/integrations/agent/spawn.js +54 -14
- package/dist/integrations/github.js +3 -0
- package/dist/integrations/lockfile.js +22 -51
- package/dist/integrations/session-logs/index.js +4 -0
- package/dist/integrations/session-logs/inline-refs.js +35 -0
- package/dist/integrations/session-logs/pre-filter.js +152 -0
- package/dist/integrations/session-logs/providers/claude-code.js +226 -0
- package/dist/integrations/session-logs/providers/opencode.js +231 -25
- package/dist/integrations/session-logs/types.js +3 -0
- package/dist/llm/call-ai.js +14 -26
- package/dist/llm/client.js +16 -2
- package/dist/llm/embedder.js +20 -29
- package/dist/llm/embedders/cache.js +3 -7
- package/dist/llm/embedders/local.js +42 -1
- package/dist/llm/embedders/remote.js +20 -8
- package/dist/llm/embedders/types.js +3 -7
- package/dist/llm/feature-gate.js +92 -56
- package/dist/llm/graph-extract.js +402 -31
- package/dist/llm/index-passes.js +44 -29
- package/dist/llm/memory-infer.js +30 -2
- package/dist/llm/metadata-enhance.js +3 -7
- package/dist/output/cli-hints.js +7 -4
- package/dist/output/context.js +60 -8
- package/dist/output/renderers.js +170 -194
- package/dist/output/shapes/curate.js +56 -0
- package/dist/output/shapes/distill.js +10 -0
- package/dist/output/shapes/env-list.js +19 -0
- package/dist/output/shapes/events.js +11 -0
- package/dist/output/shapes/helpers.js +424 -0
- package/dist/output/shapes/history.js +7 -0
- package/dist/output/shapes/passthrough.js +105 -0
- package/dist/output/shapes/proposal-accept.js +7 -0
- package/dist/output/shapes/proposal-diff.js +7 -0
- package/dist/output/shapes/proposal-list.js +7 -0
- package/dist/output/shapes/proposal-producer.js +11 -0
- package/dist/output/shapes/proposal-reject.js +7 -0
- package/dist/output/shapes/proposal-show.js +7 -0
- package/dist/output/shapes/registry-search.js +6 -0
- package/dist/output/shapes/registry.js +30 -0
- package/dist/output/shapes/search.js +6 -0
- package/dist/output/shapes/secret-list.js +19 -0
- package/dist/output/shapes/show.js +6 -0
- package/dist/output/shapes/vault-list.js +19 -0
- package/dist/output/shapes.js +51 -549
- package/dist/output/text/add.js +6 -0
- package/dist/output/text/clone.js +6 -0
- package/dist/output/text/config.js +6 -0
- package/dist/output/text/curate.js +6 -0
- package/dist/output/text/distill.js +7 -0
- package/dist/output/text/enable-disable.js +7 -0
- package/dist/output/text/events.js +10 -0
- package/dist/output/text/feedback.js +6 -0
- package/dist/output/text/helpers.js +1059 -0
- package/dist/output/text/history.js +7 -0
- package/dist/output/text/import.js +6 -0
- package/dist/output/text/index.js +6 -0
- package/dist/output/text/info.js +6 -0
- package/dist/output/text/init.js +6 -0
- package/dist/output/text/list.js +6 -0
- package/dist/output/text/proposal-producer.js +8 -0
- package/dist/output/text/proposal.js +12 -0
- package/dist/output/text/registry-commands.js +11 -0
- package/dist/output/text/registry.js +30 -0
- package/dist/output/text/remember.js +6 -0
- package/dist/output/text/remove.js +6 -0
- package/dist/output/text/save.js +6 -0
- package/dist/output/text/search.js +6 -0
- package/dist/output/text/show.js +6 -0
- package/dist/output/text/update.js +6 -0
- package/dist/output/text/upgrade.js +6 -0
- package/dist/output/text/vault.js +16 -0
- package/dist/output/text/wiki.js +15 -0
- package/dist/output/text/workflow.js +14 -0
- package/dist/output/text.js +44 -1329
- package/dist/registry/build-index.js +3 -0
- package/dist/registry/create-provider-registry.js +3 -0
- package/dist/registry/factory.js +4 -1
- package/dist/registry/origin-resolve.js +3 -0
- package/dist/registry/providers/index.js +3 -0
- package/dist/registry/providers/skills-sh.js +11 -2
- package/dist/registry/providers/static-index.js +10 -1
- package/dist/registry/providers/types.js +3 -24
- package/dist/registry/resolve.js +11 -16
- package/dist/registry/types.js +3 -0
- package/dist/scripts/migrate-storage.js +17767 -0
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +9031 -0
- package/dist/scripts/migrations/v16-to-v17.js +141 -0
- package/dist/setup/detect.js +3 -0
- package/dist/setup/ripgrep-install.js +3 -0
- package/dist/setup/ripgrep-resolve.js +3 -0
- package/dist/setup/setup.js +306 -67
- package/dist/setup/steps.js +3 -15
- package/dist/sources/include.js +3 -0
- package/dist/sources/provider-factory.js +3 -11
- package/dist/sources/provider.js +3 -20
- package/dist/sources/providers/filesystem.js +19 -23
- package/dist/sources/providers/git.js +171 -21
- package/dist/sources/providers/index.js +3 -0
- package/dist/sources/providers/install-types.js +3 -13
- package/dist/sources/providers/npm.js +3 -4
- package/dist/sources/providers/provider-utils.js +3 -0
- package/dist/sources/providers/sync-from-ref.js +3 -11
- package/dist/sources/providers/tar-utils.js +3 -0
- package/dist/sources/providers/website.js +18 -22
- package/dist/sources/resolve.js +3 -0
- package/dist/sources/types.js +3 -0
- package/dist/sources/website-ingest.js +3 -0
- package/dist/tasks/backends/cron.js +3 -0
- package/dist/tasks/backends/exec-utils.js +3 -0
- package/dist/tasks/backends/index.js +3 -11
- package/dist/tasks/backends/launchd.js +4 -1
- package/dist/tasks/backends/schtasks.js +4 -1
- package/dist/tasks/parser.js +51 -38
- package/dist/tasks/resolveAkmBin.js +3 -0
- package/dist/tasks/runner.js +35 -9
- package/dist/tasks/schedule.js +20 -1
- package/dist/tasks/schema.js +5 -3
- package/dist/tasks/validator.js +6 -3
- package/dist/version.js +3 -0
- package/dist/wiki/wiki-templates.js +6 -3
- package/dist/wiki/wiki.js +4 -1
- package/dist/workflows/authoring.js +4 -1
- package/dist/workflows/cli.js +3 -0
- package/dist/workflows/db.js +140 -10
- package/dist/workflows/document-cache.js +3 -10
- package/dist/workflows/parser.js +3 -0
- package/dist/workflows/renderer.js +3 -0
- package/dist/workflows/runs.js +18 -1
- package/dist/workflows/schema.js +3 -0
- package/dist/workflows/scope-key.js +3 -0
- package/dist/workflows/validator.js +5 -9
- package/docs/README.md +7 -2
- package/docs/data-and-telemetry.md +225 -0
- package/docs/migration/release-notes/0.7.5.md +2 -2
- package/docs/migration/release-notes/0.8.0.md +57 -5
- package/docs/migration/v0.7-to-v0.8.md +1378 -0
- package/package.json +28 -11
- package/.github/LICENSE +0 -374
- package/dist/commands/help/help-accept.md +0 -9
- package/dist/commands/help/help-improve.md +0 -53
- package/dist/commands/help/help-reject.md +0 -8
- package/dist/commands/install-audit.js +0 -385
- package/dist/commands/vault.js +0 -310
- package/dist/indexer/match-contributors.js +0 -141
- package/dist/integrations/agent/pipeline.js +0 -39
- package/dist/integrations/agent/runners.js +0 -31
- package/dist/llm/prompts/graph-extract-user-prompt.md +0 -12
- /package/dist/{tasks → assets}/backends/launchd-template.xml +0 -0
- /package/dist/{tasks → assets}/backends/schtasks-template.xml +0 -0
- /package/dist/{commands → assets}/help/help-propose.md +0 -0
- /package/dist/{wiki → assets/wiki}/index-template.md +0 -0
- /package/dist/{wiki → assets/wiki}/ingest-workflow-template.md +0 -0
- /package/dist/{wiki → assets/wiki}/log-template.md +0 -0
- /package/dist/{wiki → assets/wiki}/schema-template.md +0 -0
- /package/dist/{workflows → assets/workflows}/workflow-template.md +0 -0
package/dist/setup/steps.js
CHANGED
|
@@ -1,18 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* The interactive wizard in `setup.ts` historically ran a fixed series of
|
|
5
|
-
* step functions (`stepStashDir`, `stepOllama`, `stepLlm`, ...) inline.
|
|
6
|
-
* This module formalizes that pattern so steps can be:
|
|
7
|
-
* - reused by `akm init` (non-interactive preset, see Finding 31),
|
|
8
|
-
* - tested in isolation by passing a stub `SetupContext`, and
|
|
9
|
-
* - extended by plugins without touching the wizard call site.
|
|
10
|
-
*
|
|
11
|
-
* Steps mutate state through `SetupContext.apply()`, which accumulates a
|
|
12
|
-
* delta on top of the original config. `stepLlm` reading the embedding
|
|
13
|
-
* endpoint that `stepSemanticSearch` produced is the canonical example of
|
|
14
|
-
* why mutable accumulation is preferred over immutable returns.
|
|
15
|
-
*/
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
16
4
|
/**
|
|
17
5
|
* Build a fresh `SetupContext` over a starting config. The returned context
|
|
18
6
|
* applies deltas in-place onto an internal accumulator and exposes the
|
package/dist/sources/include.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
import fs from "node:fs";
|
|
2
5
|
import path from "node:path";
|
|
3
6
|
import { isWithin } from "../core/common";
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Maps source kind identifiers (e.g. "filesystem", "git", "website", "npm")
|
|
5
|
-
* to factory functions that build {@link SourceProvider} instances from a
|
|
6
|
-
* {@link SourceConfigEntry}.
|
|
7
|
-
*
|
|
8
|
-
* Distinct from the registry-discovery factory (`registry/factory.ts`).
|
|
9
|
-
* Both share `create-provider-registry.ts` for the underlying string→factory
|
|
10
|
-
* map.
|
|
11
|
-
*/
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
12
4
|
import { getSources } from "../core/config";
|
|
13
5
|
import { createProviderRegistry } from "../registry/create-provider-registry";
|
|
14
6
|
// ── Factory map ─────────────────────────────────────────────────────────────
|
package/dist/sources/provider.js
CHANGED
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* A SourceProvider gets files into a directory. The indexer walks `path()`
|
|
5
|
-
* and reads files from disk. Search and show go through the indexer, not
|
|
6
|
-
* through provider methods.
|
|
7
|
-
*
|
|
8
|
-
* Three required members + one optional:
|
|
9
|
-
* - name configured source name
|
|
10
|
-
* - kind "filesystem" | "git" | "website" | "npm"
|
|
11
|
-
* - init(ctx) called once after construction
|
|
12
|
-
* - path() the directory the indexer walks (stable for instance lifetime)
|
|
13
|
-
* - sync?() refresh the directory from upstream (no-op for filesystem)
|
|
14
|
-
*
|
|
15
|
-
* All other writing/reading concerns live outside this interface:
|
|
16
|
-
* - Writes: src/core/write-source.ts (Phase 5)
|
|
17
|
-
* - Reads: src/indexer.ts (Phase 4)
|
|
18
|
-
* - Install: src/sources/providers/sync-from-ref.ts (install-time helpers,
|
|
19
|
-
* separate from configured-source plumbing)
|
|
20
|
-
*/
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
21
4
|
export {};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
import { resolveStashDir } from "../../core/common";
|
|
2
5
|
import { ConfigError } from "../../core/errors";
|
|
3
6
|
import { registerSourceProvider } from "../provider-factory";
|
|
@@ -8,28 +11,21 @@ import { registerSourceProvider } from "../provider-factory";
|
|
|
8
11
|
* just `{ name, kind, init, path }`. No `sync()` — content is the user's
|
|
9
12
|
* own directory, never refreshed by akm.
|
|
10
13
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
#stashDir;
|
|
15
|
-
constructor(entry) {
|
|
16
|
-
if (entry.type !== "filesystem") {
|
|
17
|
-
throw new ConfigError(`FilesystemSourceProvider invoked with type="${entry.type}"`);
|
|
18
|
-
}
|
|
19
|
-
this.#stashDir = entry.path ?? resolveStashDir();
|
|
20
|
-
if (!this.#stashDir) {
|
|
21
|
-
throw new ConfigError("filesystem source requires a `path`");
|
|
22
|
-
}
|
|
23
|
-
this.name = entry.name ?? this.#stashDir;
|
|
14
|
+
registerSourceProvider("filesystem", (entry) => {
|
|
15
|
+
if (entry.type !== "filesystem") {
|
|
16
|
+
throw new ConfigError(`filesystem source invoked with type="${entry.type}"`);
|
|
24
17
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
const stashDir = entry.path ?? resolveStashDir();
|
|
19
|
+
if (!stashDir) {
|
|
20
|
+
throw new ConfigError("filesystem source requires a `path`");
|
|
28
21
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
22
|
+
const name = entry.name ?? stashDir;
|
|
23
|
+
return {
|
|
24
|
+
kind: "filesystem",
|
|
25
|
+
name,
|
|
26
|
+
async init(_ctx) { },
|
|
27
|
+
path() {
|
|
28
|
+
return stashDir;
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
});
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
import { spawnSync } from "node:child_process";
|
|
2
5
|
import { createHash, randomBytes } from "node:crypto";
|
|
3
6
|
import fs from "node:fs";
|
|
@@ -15,7 +18,13 @@ import { applyAkmIncludeConfig, buildInstallCacheDir, copyDirectoryContents, det
|
|
|
15
18
|
const CACHE_TTL_MS = 12 * 60 * 60 * 1000;
|
|
16
19
|
/** Maximum stale age allowed when refresh fails (7 days). */
|
|
17
20
|
const CACHE_STALE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
18
|
-
|
|
21
|
+
function runGit(args, options) {
|
|
22
|
+
return spawnSync("git", args, {
|
|
23
|
+
encoding: "utf8",
|
|
24
|
+
...options,
|
|
25
|
+
env: { ...process.env, ...options?.env, GIT_TERMINAL_PROMPT: "0" },
|
|
26
|
+
});
|
|
27
|
+
}
|
|
19
28
|
/**
|
|
20
29
|
* Git source provider — clones (and re-pulls) a remote repo into a local
|
|
21
30
|
* cache directory. Implements the v1 {@link SourceProvider} interface (spec
|
|
@@ -219,10 +228,9 @@ async function doSyncGit(parsed, options) {
|
|
|
219
228
|
cloneArgs.push("--branch", parsed.requestedRef);
|
|
220
229
|
}
|
|
221
230
|
cloneArgs.push(parsed.url, cloneDir);
|
|
222
|
-
const cloneResult =
|
|
231
|
+
const cloneResult = runGit(cloneArgs, { timeout: 120_000 });
|
|
223
232
|
if (cloneResult.status !== 0) {
|
|
224
|
-
|
|
225
|
-
throw new Error(`Failed to clone ${parsed.url}: ${err}`);
|
|
233
|
+
throw new Error(classifyCloneFailure(parsed.url, cloneResult.stderr, cloneResult.error));
|
|
226
234
|
}
|
|
227
235
|
// Copy contents to extracted dir without .git
|
|
228
236
|
fs.mkdirSync(extractedDir, { recursive: true });
|
|
@@ -267,12 +275,11 @@ export function cloneRepo(cloneUrl, ref, destDir, writable = false) {
|
|
|
267
275
|
if (ref)
|
|
268
276
|
args.push("--branch", ref);
|
|
269
277
|
args.push(cloneUrl, tmpDir);
|
|
270
|
-
const result =
|
|
278
|
+
const result = runGit(args, { timeout: 120_000 });
|
|
271
279
|
if (result.status !== 0) {
|
|
272
280
|
// Clean up the (possibly partial) temp dir but leave destDir untouched.
|
|
273
281
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
274
|
-
|
|
275
|
-
throw new Error(`Failed to clone ${cloneUrl}: ${err}`);
|
|
282
|
+
throw new Error(classifyCloneFailure(cloneUrl, result.stderr, result.error));
|
|
276
283
|
}
|
|
277
284
|
try {
|
|
278
285
|
if (!writable) {
|
|
@@ -293,8 +300,7 @@ export function cloneRepo(cloneUrl, ref, destDir, writable = false) {
|
|
|
293
300
|
}
|
|
294
301
|
}
|
|
295
302
|
function pullRepo(repoDir) {
|
|
296
|
-
const result =
|
|
297
|
-
encoding: "utf8",
|
|
303
|
+
const result = runGit(["-C", repoDir, "pull", "--ff-only"], {
|
|
298
304
|
timeout: 120_000,
|
|
299
305
|
});
|
|
300
306
|
if (result.status !== 0) {
|
|
@@ -383,6 +389,29 @@ function parseGitRepoUrl(rawUrl) {
|
|
|
383
389
|
}
|
|
384
390
|
return { cloneUrl: rawUrl, ref: null, canonicalUrl };
|
|
385
391
|
}
|
|
392
|
+
// ── Save support ─────────────────────────────────────────────────────────────
|
|
393
|
+
/**
|
|
394
|
+
* Recognize a stash directory as git-backed by the presence of a `.git` entry.
|
|
395
|
+
*
|
|
396
|
+
* Recognition is deliberately by `.git` presence — NOT by a configured remote.
|
|
397
|
+
* `akm init` git-inits the primary stash (see init.ts `ensureGitRepo`), so a
|
|
398
|
+
* freshly-initialized local stash with no remote is still git-backed. This is
|
|
399
|
+
* the single source of truth used both by `saveGitStash` (below) and by the
|
|
400
|
+
* end-of-run improve auto-sync gate.
|
|
401
|
+
*/
|
|
402
|
+
export function isGitBackedStash(stashDir) {
|
|
403
|
+
return fs.existsSync(path.join(stashDir, ".git"));
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Resolve the writable-override flag for an end-of-run / `akm sync` commit on
|
|
407
|
+
* the primary stash. Returns `true` when the root config explicitly marks the
|
|
408
|
+
* primary stash writable, otherwise `undefined` (leave the per-stash default
|
|
409
|
+
* untouched). Extracted so `akm sync`, `akm improve`'s end-of-run sync, and the
|
|
410
|
+
* CLI body all derive this identically instead of re-copying the expression.
|
|
411
|
+
*/
|
|
412
|
+
export function resolveWritableOverride(config) {
|
|
413
|
+
return config.writable === true ? true : undefined;
|
|
414
|
+
}
|
|
386
415
|
/**
|
|
387
416
|
* Commit (and optionally push) local changes in a git-backed stash.
|
|
388
417
|
*
|
|
@@ -394,8 +423,18 @@ function parseGitRepoUrl(rawUrl) {
|
|
|
394
423
|
*
|
|
395
424
|
* When `name` is omitted the primary stash directory is used.
|
|
396
425
|
* When `message` is omitted a timestamp is used.
|
|
426
|
+
*
|
|
427
|
+
* `options.repoDir` overrides the primary-stash directory the commit targets
|
|
428
|
+
* (only honoured when `name` is omitted). Callers that already resolved the
|
|
429
|
+
* primary stash dir (e.g. `akm improve`'s end-of-run sync, whose pre-commit
|
|
430
|
+
* gate validates that exact directory) pass it here so the gate and the commit
|
|
431
|
+
* operate on the SAME directory instead of independently calling
|
|
432
|
+
* `resolveStashDir({ readOnly: true })`. When absent, behaviour is unchanged.
|
|
397
433
|
*/
|
|
398
|
-
export function saveGitStash(name, message, writableOverride) {
|
|
434
|
+
export function saveGitStash(name, message, writableOverride, options) {
|
|
435
|
+
// `push: false` (from `akm sync --no-push`) commits but never pushes, even
|
|
436
|
+
// when the stash is writable with a remote configured.
|
|
437
|
+
const allowPush = options?.push !== false;
|
|
399
438
|
const timestamp = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
400
439
|
// Sanitize the user-supplied message: strip CR/LF/NUL, collapse whitespace,
|
|
401
440
|
// clamp length. An attacker can otherwise pass `--message "subject\n\n\
|
|
@@ -410,7 +449,7 @@ export function saveGitStash(name, message, writableOverride) {
|
|
|
410
449
|
const stash = findGitStashByTarget(getSources(config), name);
|
|
411
450
|
if (!stash)
|
|
412
451
|
throw new UsageError(`No git stash found with name "${name}"`);
|
|
413
|
-
if (
|
|
452
|
+
if (stash.type !== "git") {
|
|
414
453
|
throw new UsageError(`Stash "${name}" is not a git stash (type: ${stash.type})`);
|
|
415
454
|
}
|
|
416
455
|
if (!stash.url)
|
|
@@ -420,44 +459,72 @@ export function saveGitStash(name, message, writableOverride) {
|
|
|
420
459
|
writable = stash.writable === true;
|
|
421
460
|
}
|
|
422
461
|
else {
|
|
423
|
-
|
|
462
|
+
// Honour an explicit primary-stash dir override (keeps the improve gate and
|
|
463
|
+
// the commit on the same directory); otherwise resolve the default.
|
|
464
|
+
repoDir = options?.repoDir ?? resolveStashDir({ readOnly: true });
|
|
424
465
|
// Allow caller to override writable for the primary stash (e.g. from root config.writable)
|
|
425
466
|
if (writableOverride !== undefined) {
|
|
426
467
|
writable = writableOverride;
|
|
427
468
|
}
|
|
428
469
|
}
|
|
429
470
|
// No-op: not a git repo
|
|
430
|
-
if (!
|
|
471
|
+
if (!isGitBackedStash(repoDir)) {
|
|
431
472
|
return { committed: false, pushed: false, skipped: true, reason: "not a git repository", output: "" };
|
|
432
473
|
}
|
|
433
474
|
// Nothing to commit?
|
|
434
|
-
const statusResult =
|
|
475
|
+
const statusResult = runGit(["-C", repoDir, "status", "--porcelain"]);
|
|
435
476
|
if (statusResult.error || statusResult.status !== 0) {
|
|
436
477
|
throw new Error(`git status failed: ${statusResult.error?.message || statusResult.stderr?.trim() || "unknown error"}`);
|
|
437
478
|
}
|
|
438
479
|
if (!statusResult.stdout.trim()) {
|
|
439
480
|
return { committed: false, pushed: false, skipped: false, output: "nothing to commit, working tree clean" };
|
|
440
481
|
}
|
|
482
|
+
// Safety check (#476): when the stash dir is shared with a non-akm project
|
|
483
|
+
// (stash root == project repo root), `git add -A` would stage every dirty
|
|
484
|
+
// file in the user's working tree and push their unrelated WIP to the
|
|
485
|
+
// stash's remote. Refuse if any dirty path is outside the known akm-
|
|
486
|
+
// managed subtrees (TYPE_DIRS + `.akm/` state).
|
|
487
|
+
const nonAkmDirty = collectNonAkmDirtyPaths(statusResult.stdout);
|
|
488
|
+
if (nonAkmDirty.length > 0) {
|
|
489
|
+
const sample = nonAkmDirty.slice(0, 10);
|
|
490
|
+
const more = nonAkmDirty.length > sample.length ? `\n ...and ${nonAkmDirty.length - sample.length} more` : "";
|
|
491
|
+
throw new Error(`refusing to push: stash repo at ${repoDir} has uncommitted non-akm changes:\n` +
|
|
492
|
+
sample.map((p) => ` ${p}`).join("\n") +
|
|
493
|
+
more +
|
|
494
|
+
`\nCommit or stash these manually before running an akm push. ` +
|
|
495
|
+
`Akm-managed paths are: ${Object.values(TYPE_DIRS).join(", ")}, .akm/`);
|
|
496
|
+
}
|
|
441
497
|
// Stage and commit — supply fallback identity so fresh environments without
|
|
442
498
|
// user.name/user.email configured can always commit to the default stash.
|
|
443
|
-
|
|
499
|
+
// `add -A` is safe here because nonAkmDirty was just verified empty.
|
|
500
|
+
const addResult = runGit(["-C", repoDir, "add", "-A"]);
|
|
444
501
|
if (addResult.status !== 0) {
|
|
445
502
|
throw new Error(`git add failed: ${addResult.stderr?.trim() || "unknown error"}`);
|
|
446
503
|
}
|
|
447
|
-
const commitResult =
|
|
504
|
+
const commitResult = runGit([
|
|
505
|
+
"-C",
|
|
506
|
+
repoDir,
|
|
507
|
+
"-c",
|
|
508
|
+
"user.name=akm",
|
|
509
|
+
"-c",
|
|
510
|
+
"user.email=akm@local",
|
|
511
|
+
"commit",
|
|
512
|
+
"-m",
|
|
513
|
+
commitMessage,
|
|
514
|
+
]);
|
|
448
515
|
if (commitResult.status !== 0) {
|
|
449
516
|
throw new Error(`git commit failed: ${commitResult.stderr?.trim() || "unknown error"}`);
|
|
450
517
|
}
|
|
451
518
|
// Push only when there is a remote AND the stash is marked writable
|
|
452
|
-
const remoteResult =
|
|
519
|
+
const remoteResult = runGit(["-C", repoDir, "remote"]);
|
|
453
520
|
if (remoteResult.status !== 0) {
|
|
454
521
|
throw new Error(`git remote failed: ${remoteResult.stderr?.trim() || "unknown error"}`);
|
|
455
522
|
}
|
|
456
523
|
const hasRemote = remoteResult.stdout.trim().length > 0;
|
|
457
|
-
if (!hasRemote || !writable) {
|
|
524
|
+
if (!hasRemote || !writable || !allowPush) {
|
|
458
525
|
return { committed: true, pushed: false, skipped: false, output: commitResult.stdout.trim() };
|
|
459
526
|
}
|
|
460
|
-
const pushResult =
|
|
527
|
+
const pushResult = runGit(["-C", repoDir, "push"], { timeout: 120_000 });
|
|
461
528
|
if (pushResult.status !== 0) {
|
|
462
529
|
throw new Error(`git push failed: ${pushResult.stderr?.trim() || "unknown error"}`);
|
|
463
530
|
}
|
|
@@ -472,7 +539,7 @@ function findGitStashByTarget(stashes, target) {
|
|
|
472
539
|
return stashes.find((stash) => matchesGitStashTarget(stash, target));
|
|
473
540
|
}
|
|
474
541
|
function matchesGitStashTarget(stash, target) {
|
|
475
|
-
if (
|
|
542
|
+
if (stash.type !== "git")
|
|
476
543
|
return false;
|
|
477
544
|
if (stash.name === target || stash.url === target)
|
|
478
545
|
return true;
|
|
@@ -510,5 +577,88 @@ function buildGithubTargetAliases(canonicalUrl) {
|
|
|
510
577
|
return new Set();
|
|
511
578
|
}
|
|
512
579
|
}
|
|
580
|
+
// ── Clone-failure classification (#487) ─────────────────────────────────────
|
|
581
|
+
/**
|
|
582
|
+
* Translate git's stderr into an actionable message. Without this, a user
|
|
583
|
+
* who passes a nonexistent or private repo to `akm add` sees:
|
|
584
|
+
*
|
|
585
|
+
* "could not read Username for 'https://github.com': No such device or
|
|
586
|
+
* address"
|
|
587
|
+
*
|
|
588
|
+
* That is git falling through to its auth-prompt path — the actual cause
|
|
589
|
+
* is "repo doesn't exist (or is private)". We classify the common patterns
|
|
590
|
+
* and emit a message that names the cause and the fix.
|
|
591
|
+
*/
|
|
592
|
+
export function classifyCloneFailure(url, stderr, spawnError) {
|
|
593
|
+
const raw = (stderr ?? "").trim();
|
|
594
|
+
const spawnMsg = spawnError?.message ?? "";
|
|
595
|
+
// `git` binary not on PATH.
|
|
596
|
+
if (spawnError?.code === "ENOENT") {
|
|
597
|
+
return `Failed to clone ${url}: 'git' is not installed or not on PATH. Install git, then re-run.`;
|
|
598
|
+
}
|
|
599
|
+
// Auth-prompt fall-through (the headline #487 case).
|
|
600
|
+
if (/could not read Username|terminal prompts disabled|Authentication failed|fatal: Authentication/i.test(raw)) {
|
|
601
|
+
return (`Failed to clone ${url}: repository not found or private. ` +
|
|
602
|
+
`If the repository is public, double-check the URL and try again. ` +
|
|
603
|
+
`If it is private, set GH_TOKEN (or configure a git credential helper) before re-running.`);
|
|
604
|
+
}
|
|
605
|
+
// 404-style messages from git http.
|
|
606
|
+
if (/repository '.*' not found|HTTP 404|fatal: remote error|not found:|Not Found/i.test(raw)) {
|
|
607
|
+
return (`Failed to clone ${url}: repository not found. ` +
|
|
608
|
+
`Check the URL — for GitHub, the form is 'owner/repo' or 'github:owner/repo'.`);
|
|
609
|
+
}
|
|
610
|
+
// SSH connection issues.
|
|
611
|
+
if (/Permission denied \(publickey\)|kex_exchange_identification|Connection refused|Connection timed out/i.test(raw)) {
|
|
612
|
+
return (`Failed to clone ${url}: network or SSH failure. ` +
|
|
613
|
+
`Check connectivity, your SSH agent, and the remote host's availability.`);
|
|
614
|
+
}
|
|
615
|
+
// Branch / ref-specific failures.
|
|
616
|
+
if (/Remote branch .* not found in upstream origin|couldn't find remote ref/i.test(raw)) {
|
|
617
|
+
return (`Failed to clone ${url}: the requested branch/tag does not exist on the remote. ` +
|
|
618
|
+
`Verify the ref name and re-run.`);
|
|
619
|
+
}
|
|
620
|
+
const detail = raw || spawnMsg || "unknown error";
|
|
621
|
+
return `Failed to clone ${url}: ${detail}`;
|
|
622
|
+
}
|
|
623
|
+
// ── Stash-safety helpers (#476) ──────────────────────────────────────────────
|
|
624
|
+
/**
|
|
625
|
+
* Inspect `git status --porcelain` output and return every dirty path that is
|
|
626
|
+
* NOT inside an akm-managed subtree. Used by `runUpstreamPush` to refuse
|
|
627
|
+
* pushing unrelated WIP when a writable stash shares its root with a project
|
|
628
|
+
* repo.
|
|
629
|
+
*
|
|
630
|
+
* Porcelain v1 format: `XY <path>` or `XY <orig> -> <new>` for renames. We
|
|
631
|
+
* key off the post-rename path (or the only path) — that is the working-tree
|
|
632
|
+
* file at risk of being staged by `git add -A`.
|
|
633
|
+
*/
|
|
634
|
+
function collectNonAkmDirtyPaths(porcelainOutput) {
|
|
635
|
+
const akmDirs = new Set(Object.values(TYPE_DIRS));
|
|
636
|
+
const result = [];
|
|
637
|
+
for (const rawLine of porcelainOutput.split("\n")) {
|
|
638
|
+
const line = rawLine.replace(/\r$/, "");
|
|
639
|
+
if (line.length === 0)
|
|
640
|
+
continue;
|
|
641
|
+
// Skip the 2-char status code + 1 space.
|
|
642
|
+
let p = line.length > 3 ? line.slice(3) : "";
|
|
643
|
+
// Renames / copies: `from -> to`. Stage decision applies to `to`.
|
|
644
|
+
const arrow = p.lastIndexOf(" -> ");
|
|
645
|
+
if (arrow !== -1) {
|
|
646
|
+
p = p.slice(arrow + 4);
|
|
647
|
+
}
|
|
648
|
+
// Strip surrounding quotes for paths with special chars.
|
|
649
|
+
if (p.startsWith('"') && p.endsWith('"') && p.length >= 2) {
|
|
650
|
+
p = p.slice(1, -1);
|
|
651
|
+
}
|
|
652
|
+
if (!p)
|
|
653
|
+
continue;
|
|
654
|
+
const segments = p.split("/");
|
|
655
|
+
const top = segments[0];
|
|
656
|
+
if (top === ".akm" || akmDirs.has(top))
|
|
657
|
+
continue;
|
|
658
|
+
result.push(p);
|
|
659
|
+
}
|
|
660
|
+
return result;
|
|
661
|
+
}
|
|
513
662
|
// ── Exports ─────────────────────────────────────────────────────────────────
|
|
514
|
-
export { ensureGitMirror, GitSourceProvider, getCachePaths, parseGitRepoUrl };
|
|
663
|
+
export { collectNonAkmDirtyPaths, ensureGitMirror, GitSourceProvider, getCachePaths, parseGitRepoUrl };
|
|
664
|
+
// resolveWritableOverride is exported at its declaration above.
|
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Distinct from the v1 {@link SourceProvider} interface (which only deals
|
|
5
|
-
* with "configured sources" — entries already resolved into a directory).
|
|
6
|
-
* These types describe the resolution+lockfile step that runs when
|
|
7
|
-
* `akm add <install-ref>` materialises an upstream artifact into a local
|
|
8
|
-
* cache directory.
|
|
9
|
-
*
|
|
10
|
-
* They live here, outside `provider.ts`, so the v1 SourceProvider
|
|
11
|
-
* interface stays minimal (`{ name, kind, init, path, sync? }`) per the
|
|
12
|
-
* architecture spec §2.1.
|
|
13
|
-
*/
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
14
4
|
export {};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
/**
|
|
2
5
|
* Npm-source stash provider.
|
|
3
6
|
*
|
|
@@ -5,10 +8,6 @@
|
|
|
5
8
|
* integrity, extracts it securely (via `extractTarGzSecure`), detects the
|
|
6
9
|
* stash root inside the package, and applies any nested `.akm-include`
|
|
7
10
|
* configuration. Cache hits short-circuit the fetch.
|
|
8
|
-
*
|
|
9
|
-
* Audit is intentionally NOT performed here — `akmAdd` calls
|
|
10
|
-
* `auditInstallCandidate` after `sync()` so the policy decision lives at
|
|
11
|
-
* the orchestrator layer where the `--trust` flag is known.
|
|
12
11
|
*/
|
|
13
12
|
import fs from "node:fs";
|
|
14
13
|
import path from "node:path";
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
import { createHash } from "node:crypto";
|
|
2
5
|
import fs from "node:fs";
|
|
3
6
|
import path from "node:path";
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Replaces the historical `installRegistryRef()` entry point. Given an
|
|
5
|
-
* unparsed install ref, this resolves the right syncable provider and
|
|
6
|
-
* invokes its `sync()` method.
|
|
7
|
-
*
|
|
8
|
-
* Audit is intentionally NOT performed here; callers (`akmAdd`,
|
|
9
|
-
* `akmUpdate`) decide whether to run `auditInstallCandidate` on the
|
|
10
|
-
* synced `contentDir` because they own the `--trust` flag.
|
|
11
|
-
*/
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
12
4
|
import { UsageError } from "../../core/errors";
|
|
13
5
|
import { parseRegistryRef } from "../../registry/resolve";
|
|
14
6
|
import { detectStashRoot } from "./provider-utils";
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
/**
|
|
2
5
|
* Tar archive extraction and integrity verification utilities.
|
|
3
6
|
*
|
|
@@ -1,27 +1,23 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
import { registerSourceProvider } from "../provider-factory";
|
|
2
5
|
import { ensureWebsiteMirror, getWebsiteCachePaths, validateWebsiteUrl } from "../website-ingest";
|
|
3
6
|
/**
|
|
4
7
|
* Website source provider — thin adapter over the shared website ingest module.
|
|
5
8
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
name;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
async sync() {
|
|
23
|
-
await ensureWebsiteMirror(this.#config, { requireStashDir: true });
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
registerSourceProvider("website", (config) => new WebsiteSourceProvider(config));
|
|
27
|
-
export { WebsiteSourceProvider };
|
|
9
|
+
registerSourceProvider("website", (config) => {
|
|
10
|
+
const url = validateWebsiteUrl(config.url ?? "");
|
|
11
|
+
const name = config.name ?? "website";
|
|
12
|
+
return {
|
|
13
|
+
kind: "website",
|
|
14
|
+
name,
|
|
15
|
+
async init(_ctx) { },
|
|
16
|
+
path() {
|
|
17
|
+
return getWebsiteCachePaths(url).stashDir;
|
|
18
|
+
},
|
|
19
|
+
async sync() {
|
|
20
|
+
await ensureWebsiteMirror(config, { requireStashDir: true });
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
});
|
package/dist/sources/resolve.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
import fs from "node:fs";
|
|
2
5
|
import path from "node:path";
|
|
3
6
|
import { deriveCanonicalAssetNameFromStashRoot, isRelevantAssetFile, resolveAssetPathFromName, TYPE_DIRS, } from "../core/asset-spec";
|
package/dist/sources/types.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
import { createHash } from "node:crypto";
|
|
2
5
|
import fs from "node:fs";
|
|
3
6
|
import path from "node:path";
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
// crontab backend for `akm tasks` (Linux default).
|
|
2
5
|
//
|
|
3
6
|
// Each akm-owned entry is wrapped in markers so a hand-edited crontab keeps
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
import { spawnSync } from "node:child_process";
|
|
2
5
|
/**
|
|
3
6
|
* Run a command synchronously, normalizing null results to safe defaults.
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* • Linux → crontab
|
|
5
|
-
* • macOS → launchd (per-user LaunchAgent)
|
|
6
|
-
* • Windows → schtasks.exe / Task Scheduler
|
|
7
|
-
*
|
|
8
|
-
* Each backend implements {@link TaskBackend}; selection is a one-line
|
|
9
|
-
* platform check. Tests inject a fake `platform` to exercise non-host
|
|
10
|
-
* code paths.
|
|
11
|
-
*/
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
12
4
|
import { CRON_BACKEND } from "./cron";
|
|
13
5
|
import { LAUNCHD_BACKEND } from "./launchd";
|
|
14
6
|
import { SCHTASKS_BACKEND } from "./schtasks";
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
1
4
|
/**
|
|
2
5
|
* launchd backend for `akm tasks` (macOS default).
|
|
3
6
|
*
|
|
@@ -21,12 +24,12 @@
|
|
|
21
24
|
import fs from "node:fs";
|
|
22
25
|
import os from "node:os";
|
|
23
26
|
import path from "node:path";
|
|
27
|
+
import launchdTemplate from "../../assets/backends/launchd-template.xml" with { type: "text" };
|
|
24
28
|
import { ConfigError } from "../../core/errors";
|
|
25
29
|
import { getTaskLogDir } from "../../core/paths";
|
|
26
30
|
import { resolveAkmInvocation } from "../resolveAkmBin";
|
|
27
31
|
import { parseSchedule, translateToLaunchd } from "../schedule";
|
|
28
32
|
import { escapeXml, spawnCommand } from "./exec-utils";
|
|
29
|
-
import launchdTemplate from "./launchd-template.xml" with { type: "text" };
|
|
30
33
|
export const LAUNCHD_LABEL_PREFIX = "com.akm.task.";
|
|
31
34
|
export function LAUNCHD_BACKEND(options = {}) {
|
|
32
35
|
const exec = options.exec ?? defaultLaunchdExec();
|