akm-cli 0.9.1 → 0.9.2-alpha.2
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 +103 -28
- package/README.md +3 -1
- package/SECURITY.md +1 -1
- package/STABILITY.md +1 -1
- package/dist/akm +2 -2
- package/dist/akm-migrate +2 -2
- package/dist/assets/hints/cli-hints-full.md +14 -9
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/models.json +35 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +3 -4
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
- package/dist/assets/tasks/core/extract.yml +6 -5
- package/dist/assets/tasks/core/improve.yml +6 -5
- package/dist/assets/tasks/core/index-refresh.yml +6 -5
- package/dist/assets/tasks/core/sync.yml +6 -5
- package/dist/assets/tasks/core/version-check.yml +6 -5
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
- package/dist/cli/confirm.js +2 -2
- package/dist/cli/parse-args.js +3 -24
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +2 -2
- package/dist/cli.js +11 -9
- package/dist/commands/agent/agent-dispatch.js +55 -89
- package/dist/commands/agent/contribute-cli.js +12 -45
- package/dist/commands/command/builtin-action.js +32 -0
- package/dist/commands/command/command-cli.js +99 -0
- package/dist/commands/command/command-execution.js +308 -0
- package/dist/commands/command/execution-source-loader.js +176 -0
- package/dist/commands/command/portable-template.js +60 -0
- package/dist/commands/config-cli.js +10 -4
- package/dist/commands/env/env.js +4 -2
- package/dist/commands/feedback-cli.js +1 -1
- package/dist/commands/health/checks.js +241 -29
- package/dist/commands/health/html-report.js +0 -14
- package/dist/commands/health/report-view-model.js +0 -1
- package/dist/commands/health/surfaces.js +6 -7
- package/dist/commands/health/types.js +0 -2
- package/dist/commands/health.js +63 -18
- package/dist/commands/improve/collapse-detector.js +5 -6
- package/dist/commands/improve/consolidate.js +251 -214
- package/dist/commands/improve/distill/promote-memory.js +71 -34
- package/dist/commands/improve/distill/quality-gate.js +17 -5
- package/dist/commands/improve/distill.js +232 -155
- package/dist/commands/improve/eligibility.js +112 -79
- package/dist/commands/improve/execution.js +57 -0
- package/dist/commands/improve/extract-cli.js +5 -5
- package/dist/commands/improve/extract-prompt.js +64 -22
- package/dist/commands/improve/extract.js +608 -360
- package/dist/commands/improve/improve-strategies.js +43 -14
- package/dist/commands/improve/improve.js +249 -29
- package/dist/commands/improve/loop-stages.js +11 -17
- package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
- package/dist/commands/improve/outcome-loop.js +22 -38
- package/dist/commands/improve/planner.js +134 -0
- package/dist/commands/improve/preparation.js +730 -409
- package/dist/commands/improve/reflect.js +386 -223
- package/dist/commands/improve/run-context.js +3 -4
- package/dist/commands/improve/salience.js +6 -58
- package/dist/commands/improve/session-asset.js +12 -12
- package/dist/commands/lint/index.js +101 -29
- package/dist/commands/migrate-cli.js +11 -69
- package/dist/commands/migration-tool.js +6 -9
- package/dist/commands/models-cli.js +27 -0
- package/dist/commands/proposal/drain.js +258 -186
- package/dist/commands/proposal/proposal-cli.js +32 -10
- package/dist/commands/proposal/proposal.js +2 -5
- package/dist/commands/proposal/propose.js +192 -172
- package/dist/commands/proposal/repository.js +54 -91
- package/dist/commands/proposal/validators/proposal-validators.js +9 -7
- package/dist/commands/read/curate.js +53 -22
- package/dist/commands/read/registry-search.js +25 -9
- package/dist/commands/read/remember-cli.js +14 -2
- package/dist/commands/read/search.js +10 -4
- package/dist/commands/read/show.js +139 -153
- package/dist/commands/registry-cli.js +16 -7
- package/dist/commands/remember.js +33 -18
- package/dist/commands/sources/add-cli.js +19 -178
- package/dist/commands/sources/bundle-cli.js +15 -3
- package/dist/commands/sources/dangerous-env-audit.js +135 -0
- package/dist/commands/sources/info.js +2 -1
- package/dist/commands/sources/installed-stashes.js +901 -177
- package/dist/commands/sources/schema-repair.js +174 -95
- package/dist/commands/sources/self-update.js +30 -74
- package/dist/commands/sources/source-add.js +3 -5
- package/dist/commands/sources/sources-cli.js +2 -15
- package/dist/commands/sources/update-transaction.js +220 -0
- package/dist/commands/tasks/tasks-cli.js +3 -3
- package/dist/commands/tasks/tasks.js +736 -317
- package/dist/commands/workflow-cli.js +2 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
- package/dist/core/adapter/adapters/akm-adapter.js +85 -35
- package/dist/core/adapter/adapters/akm-lint.js +54 -39
- package/dist/core/adapter/adapters/akm-metadata.js +45 -45
- package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
- package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
- package/dist/core/adapter/adapters/index.js +0 -9
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
- package/dist/core/adapter/adapters/okf-adapter.js +4 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
- package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
- package/dist/core/adapter/execution-source.js +308 -0
- package/dist/core/adapter/recognize-match.js +36 -13
- package/dist/core/adapter/registry.js +0 -9
- package/dist/core/asset/stash-meta.js +94 -4
- package/dist/core/common.js +6 -11
- package/dist/core/config/config-io.js +3 -3
- package/dist/core/config/config-schema.js +18 -40
- package/dist/core/config/config-sources.js +11 -21
- package/dist/core/config/config-walker.js +31 -13
- package/dist/core/config/config.js +23 -26
- package/dist/core/config/schema/engines.js +8 -7
- package/dist/core/config/schema/improve-processes.js +29 -5
- package/dist/core/config/schema/index-config.js +0 -27
- package/dist/core/config/schema/primitives.js +1 -23
- package/dist/core/config/schema/sources-bundles.js +13 -16
- package/dist/core/errors.js +2 -0
- package/dist/core/events.js +68 -32
- package/dist/core/extra-params.js +1 -0
- package/dist/core/improve-result.js +315 -0
- package/dist/core/lesson-lint.js +0 -6
- package/dist/core/maintenance-barrier.js +4 -4
- package/dist/core/network-policy.js +152 -0
- package/dist/core/paths.js +1 -1
- package/dist/core/recognition-util.js +4 -4
- package/dist/core/registry-url.js +456 -0
- package/dist/core/state/migrations.js +161 -47
- package/dist/core/state-db.js +453 -80
- package/dist/core/system-error.js +32 -0
- package/dist/core/time.js +2 -12
- package/dist/core/write-source.js +0 -18
- package/dist/execution/directory-identity.js +52 -0
- package/dist/execution/executable-identity.js +107 -0
- package/dist/execution/guarded-source.js +398 -0
- package/dist/execution/json.js +95 -0
- package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
- package/dist/execution/record.js +55 -0
- package/dist/execution/resolved-request.js +730 -0
- package/dist/execution/source.js +320 -0
- package/dist/indexer/bundle-identity-guard.js +5 -4
- package/dist/indexer/db/graph-db.js +33 -0
- package/dist/indexer/graph/graph-boost.js +3 -4
- package/dist/indexer/graph/graph-extraction.js +562 -373
- package/dist/indexer/index-written-assets.js +78 -39
- package/dist/indexer/indexer.js +471 -432
- package/dist/indexer/installations.js +6 -0
- package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
- package/dist/indexer/materialize-embeddings.js +155 -0
- package/dist/indexer/passes/memory-inference.js +227 -174
- package/dist/indexer/passes/metadata.js +263 -118
- package/dist/indexer/scan/doc-to-entry.js +7 -10
- package/dist/indexer/scan/drain-dir.js +51 -23
- package/dist/indexer/search/db-search.js +156 -50
- package/dist/indexer/search/fts-query.js +40 -40
- package/dist/indexer/search/ranking.js +36 -1
- package/dist/indexer/search/search-attribution.js +3 -1
- package/dist/indexer/search/search-fields.js +23 -14
- package/dist/indexer/search/search-hit-enrichers.js +1 -1
- package/dist/indexer/search/search-source.js +7 -16
- package/dist/indexer/search/semantic-status.js +10 -1
- package/dist/indexer/usage/show-usage.js +105 -0
- package/dist/indexer/usage/usage-events.js +7 -2
- package/dist/indexer/walk/matchers.js +40 -10
- package/dist/indexer/walk/path-resolver.js +5 -2
- package/dist/indexer/walk/walker.js +20 -2
- package/dist/integrations/agent/builder-shared.js +3 -6
- package/dist/integrations/agent/conversation-fallback.js +16 -0
- package/dist/integrations/agent/engine-resolution.js +87 -87
- package/dist/integrations/agent/execution-cascade.js +566 -0
- package/dist/integrations/agent/execution-definitions.js +211 -0
- package/dist/integrations/agent/execution-lowering.js +811 -0
- package/dist/integrations/agent/execution-preparation.js +67 -0
- package/dist/integrations/agent/index.js +0 -2
- package/dist/integrations/agent/inline-execution.js +74 -0
- package/dist/integrations/agent/model-map.js +515 -0
- package/dist/integrations/agent/persona-fallback.js +30 -0
- package/dist/integrations/agent/request-lowering.js +186 -0
- package/dist/integrations/agent/runner-dispatch.js +230 -37
- package/dist/integrations/agent/runner.js +12 -83
- package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
- package/dist/integrations/harnesses/aider/index.js +0 -1
- package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
- package/dist/integrations/harnesses/amazonq/index.js +0 -1
- package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
- package/dist/integrations/harnesses/claude/index.js +1 -5
- package/dist/integrations/harnesses/claude/session-log.js +3 -33
- package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
- package/dist/integrations/harnesses/codex/index.js +0 -1
- package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
- package/dist/integrations/harnesses/copilot/index.js +0 -1
- package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
- package/dist/integrations/harnesses/gemini/index.js +0 -1
- package/dist/integrations/harnesses/index.js +4 -44
- package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
- package/dist/integrations/harnesses/opencode/index.js +0 -2
- package/dist/integrations/harnesses/opencode/session-log.js +14 -204
- package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
- package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
- package/dist/integrations/harnesses/openhands/index.js +0 -1
- package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
- package/dist/integrations/harnesses/pi/index.js +0 -1
- package/dist/integrations/harnesses/shared.js +0 -1
- package/dist/integrations/harnesses/types.js +1 -3
- package/dist/integrations/lockfile.js +82 -79
- package/dist/integrations/session-logs/index.js +6 -17
- package/dist/integrations/session-logs/provider-base.js +1 -29
- package/dist/llm/client.js +10 -5
- package/dist/llm/embedder.js +6 -7
- package/dist/llm/embedders/local.js +37 -88
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +75 -50
- package/dist/llm/index-passes.js +43 -5
- package/dist/llm/memory-infer.js +8 -6
- package/dist/llm/metadata-enhance.js +5 -3
- package/dist/llm/structured-call.js +122 -25
- package/dist/output/format-exempt.js +1 -1
- package/dist/output/render-registry.js +0 -16
- package/dist/output/renderers.js +12 -7
- package/dist/output/shapes/curate.js +1 -0
- package/dist/output/shapes/helpers.js +10 -2
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/output/text/command-format.js +31 -33
- package/dist/output/text/health-format.js +1 -29
- package/dist/output/text/migrate.js +6 -56
- package/dist/output/text/proposal-format.js +16 -1
- package/dist/output/text/workflow-format.js +16 -0
- package/dist/registry/network.js +279 -0
- package/dist/registry/pinned-request-helper.js +247 -0
- package/dist/registry/pinned-transport.js +717 -0
- package/dist/registry/providers/skills-sh.js +18 -6
- package/dist/registry/providers/static-index.js +20 -7
- package/dist/registry/resolve.js +53 -28
- package/dist/scripts/akm-migrate-node.js +19334 -52269
- package/dist/scripts/akm-migrate.js +19270 -51612
- package/dist/setup/registry-stash-loader.js +64 -20
- package/dist/setup/semantic-assets.js +9 -34
- package/dist/setup/setup.js +12 -30
- package/dist/setup/source-identity.js +17 -0
- package/dist/setup/steps/sources.js +36 -15
- package/dist/setup/steps/tasks.js +39 -11
- package/dist/sources/providers/git-provider.js +3 -3
- package/dist/sources/providers/npm.js +2 -2
- package/dist/sources/providers/provider-utils.js +4 -3
- package/dist/sources/providers/website.js +11 -7
- package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
- package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
- package/dist/sources/website-url.js +73 -0
- package/dist/storage/engines/sqlite-migrations.js +81 -26
- package/dist/storage/managed-db.js +27 -24
- package/dist/storage/repositories/events-repository.js +3 -0
- package/dist/storage/repositories/index-connection.js +42 -10
- package/dist/storage/repositories/index-entries-repository.js +203 -229
- package/dist/storage/repositories/index-entry-mapper.js +8 -12
- package/dist/storage/repositories/index-entry-schema.js +255 -0
- package/dist/storage/repositories/index-fts-repository.js +64 -71
- package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
- package/dist/storage/repositories/index-meta-repository.js +0 -11
- package/dist/storage/repositories/index-schema.js +74 -350
- package/dist/storage/repositories/index-utility-repository.js +12 -17
- package/dist/storage/repositories/index-vec-repository.js +56 -7
- package/dist/storage/repositories/proposals-repository.js +4 -127
- package/dist/storage/repositories/registry-cache.js +2 -1
- package/dist/storage/repositories/task-history-repository.js +20 -40
- package/dist/storage/repositories/workflow-runs-repository.js +228 -129
- package/dist/storage/sqlite-read-snapshot.js +148 -0
- package/dist/tasks/backends/cron.js +170 -42
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +787 -202
- package/dist/tasks/backends/schtasks.js +282 -83
- package/dist/tasks/embedded.js +7 -7
- package/dist/tasks/frozen-script.js +50 -0
- package/dist/tasks/resolve-akm-bin.js +5 -1
- package/dist/tasks/runner.js +239 -251
- package/dist/tasks/runtime-v3.js +281 -0
- package/dist/tasks/scheduler-binding.js +272 -0
- package/dist/tasks/scheduler-invocation.js +57 -43
- package/dist/tasks/scheduler-sync.js +654 -0
- package/dist/tasks/source-v3.js +752 -0
- package/dist/tasks/standalone-script-entry.js +5 -0
- package/dist/tasks/task-id.js +29 -0
- package/dist/workflows/authoring/authoring.js +15 -32
- package/dist/workflows/exec/dispatch-redaction.js +14 -8
- package/dist/workflows/exec/exec-unit.js +7 -28
- package/dist/workflows/exec/frozen-judge.js +57 -89
- package/dist/workflows/exec/lowering-notices.js +23 -0
- package/dist/workflows/exec/native-executor.js +301 -458
- package/dist/workflows/exec/param-secrets.js +4 -3
- package/dist/workflows/exec/run-workflow.js +26 -32
- package/dist/workflows/exec/step-work.js +105 -109
- package/dist/workflows/exec/unit-dispatch.js +103 -27
- package/dist/workflows/exec/unit-writer.js +3 -3
- package/dist/workflows/exec/worktree.js +2 -2
- package/dist/workflows/ir/compile.js +86 -72
- package/dist/workflows/ir/environment-v4.js +328 -0
- package/dist/workflows/ir/freeze-v4.js +122 -0
- package/dist/workflows/ir/plan-hash.js +13 -7
- package/dist/workflows/ir/schema-v4.js +525 -0
- package/dist/workflows/ir/schema.js +25 -284
- package/dist/workflows/ir/source-freeze-v4.js +506 -0
- package/dist/workflows/parser.js +27 -24
- package/dist/workflows/program/schema.js +1 -2
- package/dist/workflows/renderer.js +42 -29
- package/dist/workflows/resource-limits.js +4 -5
- package/dist/workflows/runtime/agent-identity.js +11 -13
- package/dist/workflows/runtime/plan-classifier.js +8 -8
- package/dist/workflows/runtime/runs.js +27 -43
- package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
- package/dist/workflows/source-files.js +373 -0
- package/dist/workflows/source-ir/compile.js +196 -0
- package/dist/workflows/source-ir/github-yaml.js +577 -0
- package/dist/workflows/source-ir/ordering.js +38 -0
- package/dist/workflows/source-ir/program.js +50 -0
- package/dist/workflows/source-ir/result.js +26 -0
- package/dist/workflows/source-ir/schema.js +772 -0
- package/dist/workflows/source-ir/semantics.js +242 -0
- package/dist/workflows/source-ir/uses.js +14 -0
- package/docs/README.md +2 -0
- package/docs/migration/README.md +3 -1
- package/docs/migration/release-notes/0.9.2.md +55 -0
- package/docs/migration/release-notes/README.md +5 -0
- package/docs/migration/v0.8-to-v0.9.md +76 -1077
- package/docs/migration/v0.9.0-troubleshooting.md +104 -516
- package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
- package/docs/reference/README.md +1 -0
- package/docs/reference/cli.md +230 -98
- package/docs/reference/configuration.md +159 -36
- package/docs/reference/data-and-telemetry.md +19 -1
- package/docs/reference/supported-formats.md +23 -3
- package/docs/reference/tasks.md +182 -0
- package/docs/reference/workflow-schema.md +91 -40
- package/docs/reference/workflows.md +33 -6
- package/package.json +10 -6
- package/schemas/akm-config.json +372 -224
- package/schemas/akm-task.json +324 -80
- package/schemas/akm-workflow.json +6 -9
- package/dist/core/migration-operation.js +0 -75
- package/dist/integrations/agent/model-aliases.js +0 -74
- package/dist/tasks/parser.js +0 -380
- package/dist/tasks/schema.js +0 -123
- package/dist/tasks/validator.js +0 -80
- package/dist/workflows/ir/freeze.js +0 -320
- package/dist/workflows/runtime/document-cache.js +0 -13
|
@@ -1,10 +1,12 @@
|
|
|
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 {
|
|
4
|
+
import { jsonWithByteCap } from "../../core/common.js";
|
|
5
|
+
import { formatRegistryCredentialWarning, formatRegistryError, formatRegistryLabel, hasRegistryUrlCredentials, } from "../../core/registry-url.js";
|
|
5
6
|
import { md5Hex } from "../../runtime.js";
|
|
6
7
|
import { fetchCachedJson } from "../../storage/repositories/registry-cache.js";
|
|
7
8
|
import { registerRegistryProvider } from "../factory.js";
|
|
9
|
+
import { allowPrivateRegistryFixtureForTests, cancelRegistryResponse, fetchRegistryResponse } from "../network.js";
|
|
8
10
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
9
11
|
/** Per-query cache TTL in milliseconds (15 minutes). */
|
|
10
12
|
const QUERY_CACHE_TTL_MS = 15 * 60 * 1000;
|
|
@@ -16,6 +18,9 @@ class SkillsShProvider {
|
|
|
16
18
|
this.config = config;
|
|
17
19
|
}
|
|
18
20
|
async search(options) {
|
|
21
|
+
if (hasRegistryUrlCredentials(this.config.url)) {
|
|
22
|
+
return { hits: [], warnings: [formatRegistryCredentialWarning(this.config)] };
|
|
23
|
+
}
|
|
19
24
|
try {
|
|
20
25
|
const entries = await this.fetchSkills(options.query, options.limit);
|
|
21
26
|
const limited = entries.slice(0, options.limit);
|
|
@@ -27,9 +32,10 @@ class SkillsShProvider {
|
|
|
27
32
|
return { hits, assetHits };
|
|
28
33
|
}
|
|
29
34
|
catch (err) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
return {
|
|
36
|
+
hits: [],
|
|
37
|
+
warnings: [`Registry ${formatRegistryLabel(this.config)}: ${formatRegistryError(err)}`],
|
|
38
|
+
};
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
async fetchSkills(query, limit) {
|
|
@@ -57,11 +63,17 @@ class SkillsShProvider {
|
|
|
57
63
|
}
|
|
58
64
|
},
|
|
59
65
|
fetchFresh: async () => {
|
|
60
|
-
const response = await
|
|
66
|
+
const response = await fetchRegistryResponse(url, undefined, {
|
|
67
|
+
policy: { kind: "public-registry" },
|
|
68
|
+
timeoutMs: 10_000,
|
|
69
|
+
retries: 1,
|
|
70
|
+
allowPrivateHostsForTesting: allowPrivateRegistryFixtureForTests(url),
|
|
71
|
+
});
|
|
61
72
|
if (!response.ok) {
|
|
73
|
+
await cancelRegistryResponse(response);
|
|
62
74
|
throw new Error(`HTTP ${response.status}`);
|
|
63
75
|
}
|
|
64
|
-
const data =
|
|
76
|
+
const data = await jsonWithByteCap(response, 10 * 1024 * 1024, { bodyTimeoutMs: 10_000 });
|
|
65
77
|
const entries = parseSkillsResponse(data);
|
|
66
78
|
return { value: entries, cacheJson: JSON.stringify(entries) };
|
|
67
79
|
},
|
|
@@ -1,10 +1,12 @@
|
|
|
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 {
|
|
4
|
+
import { jsonWithByteCap } from "../../core/common.js";
|
|
5
|
+
import { formatRegistryCredentialWarning, formatRegistryError, formatRegistryLabel, hasRegistryUrlCredentials, } from "../../core/registry-url.js";
|
|
5
6
|
import { asString } from "../../integrations/github.js";
|
|
6
7
|
import { fetchCachedJson } from "../../storage/repositories/registry-cache.js";
|
|
7
8
|
import { registerRegistryProvider } from "../factory.js";
|
|
9
|
+
import { allowPrivateRegistryFixtureForTests, cancelRegistryResponse, fetchRegistryResponse } from "../network.js";
|
|
8
10
|
import { buildInstallRef } from "../resolve.js";
|
|
9
11
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
10
12
|
/** Cache TTL in milliseconds (1 hour). */
|
|
@@ -17,6 +19,9 @@ class StaticIndexProvider {
|
|
|
17
19
|
this.config = config;
|
|
18
20
|
}
|
|
19
21
|
async search(options) {
|
|
22
|
+
if (hasRegistryUrlCredentials(this.config.url)) {
|
|
23
|
+
return { hits: [], warnings: [formatRegistryCredentialWarning(this.config)] };
|
|
24
|
+
}
|
|
20
25
|
const warnings = [];
|
|
21
26
|
const bundles = await this.loadBundles(warnings);
|
|
22
27
|
const hits = scoreBundles(bundles, options.query, options.limit);
|
|
@@ -36,13 +41,16 @@ class StaticIndexProvider {
|
|
|
36
41
|
if (index) {
|
|
37
42
|
const regName = this.config.name;
|
|
38
43
|
for (const stash of index.stashes) {
|
|
44
|
+
if (stash.source === "git") {
|
|
45
|
+
warnings.push(`Registry ${formatRegistryLabel(this.config)}: ignored ${stash.id} because registry-provided git transport refs are not installable`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
39
48
|
bundles.push({ stash, registryName: regName });
|
|
40
49
|
}
|
|
41
50
|
}
|
|
42
51
|
}
|
|
43
52
|
catch (err) {
|
|
44
|
-
|
|
45
|
-
warnings.push(`Registry ${label}: ${toErrorMessage(err)}`);
|
|
53
|
+
warnings.push(`Registry ${formatRegistryLabel(this.config)}: ${formatRegistryError(err)}`);
|
|
46
54
|
}
|
|
47
55
|
return bundles;
|
|
48
56
|
}
|
|
@@ -58,13 +66,18 @@ async function loadIndex(entry) {
|
|
|
58
66
|
// cache row lets JSON.parse throw out of the load.
|
|
59
67
|
parseCache: (json) => parseRegistryIndex(JSON.parse(json)) ?? undefined,
|
|
60
68
|
fetchFresh: async () => {
|
|
61
|
-
const response = await
|
|
69
|
+
const response = await fetchRegistryResponse(entry.url, undefined, {
|
|
70
|
+
policy: { kind: "public-registry" },
|
|
71
|
+
timeoutMs: 10_000,
|
|
72
|
+
allowPrivateHostsForTesting: allowPrivateRegistryFixtureForTests(entry.url),
|
|
73
|
+
});
|
|
62
74
|
if (!response.ok) {
|
|
75
|
+
await cancelRegistryResponse(response);
|
|
63
76
|
throw new Error(`HTTP ${response.status}`);
|
|
64
77
|
}
|
|
65
78
|
// Cap at 50 MB — registry indexes can grow large but unbounded
|
|
66
79
|
// responses from a compromised server would OOM us.
|
|
67
|
-
const data = await jsonWithByteCap(response, 50 * 1024 * 1024);
|
|
80
|
+
const data = await jsonWithByteCap(response, 50 * 1024 * 1024, { bodyTimeoutMs: 10_000 });
|
|
68
81
|
const index = parseRegistryIndex(data);
|
|
69
82
|
if (!index) {
|
|
70
83
|
throw new Error("Invalid registry index format");
|
|
@@ -182,7 +195,7 @@ function toSearchHit(stash, score, registryName) {
|
|
|
182
195
|
title: stash.name,
|
|
183
196
|
description: stash.description,
|
|
184
197
|
ref: stash.ref,
|
|
185
|
-
installRef: buildInstallRef(stash.source, stash.ref),
|
|
198
|
+
installRef: buildInstallRef(stash.source, stash.ref, "registry"),
|
|
186
199
|
homepage: stash.homepage,
|
|
187
200
|
score: Math.round(score * 1000) / 1000,
|
|
188
201
|
metadata,
|
|
@@ -224,7 +237,7 @@ function scoreAssets(stashes, query, limit) {
|
|
|
224
237
|
for (const { stash, registryName } of stashes) {
|
|
225
238
|
if (!stash.assets || stash.assets.length === 0)
|
|
226
239
|
continue;
|
|
227
|
-
const installRef = buildInstallRef(stash.source, stash.ref);
|
|
240
|
+
const installRef = buildInstallRef(stash.source, stash.ref, "registry");
|
|
228
241
|
for (const asset of stash.assets) {
|
|
229
242
|
const score = scoreAsset(asset, tokens);
|
|
230
243
|
if (score > 0) {
|
package/dist/registry/resolve.js
CHANGED
|
@@ -6,9 +6,10 @@ import fs from "node:fs";
|
|
|
6
6
|
import os from "node:os";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
9
|
-
import {
|
|
9
|
+
import { jsonWithByteCap } from "../core/common.js";
|
|
10
10
|
import { NotFoundError, UsageError } from "../core/errors.js";
|
|
11
11
|
import { asRecord, asString, GITHUB_API_BASE, githubHeaders } from "../integrations/github.js";
|
|
12
|
+
import { cancelRegistryResponse, fetchRegistryResponse } from "./network.js";
|
|
12
13
|
import { isExactSemver, isSemverRange, maxSatisfying } from "./semver.js";
|
|
13
14
|
/**
|
|
14
15
|
* Validate that a URL is safe to pass to git.
|
|
@@ -72,7 +73,10 @@ export function parseRegistryRef(rawRef) {
|
|
|
72
73
|
return parseGithubShorthand(ref, ref);
|
|
73
74
|
}
|
|
74
75
|
/** Inverse of {@link parseRegistryRef}: build the install ref for a source kind. */
|
|
75
|
-
export function buildInstallRef(source, ref) {
|
|
76
|
+
export function buildInstallRef(source, ref, provenance = "operator") {
|
|
77
|
+
if (source === "git" && provenance === "registry") {
|
|
78
|
+
throw new UsageError("Registry-provided git transport refs are not installable. Add a trusted git URL directly if you intend to use it.");
|
|
79
|
+
}
|
|
76
80
|
switch (source) {
|
|
77
81
|
case "npm":
|
|
78
82
|
return `npm:${ref}`;
|
|
@@ -306,11 +310,12 @@ export function trustedNpmTarballHosts() {
|
|
|
306
310
|
return hosts;
|
|
307
311
|
}
|
|
308
312
|
/**
|
|
309
|
-
* Validate that an npm tarball URL
|
|
310
|
-
* compromised mirror
|
|
311
|
-
* `dist.tarball
|
|
313
|
+
* Validate that an npm tarball URL starts at the exact metadata registry
|
|
314
|
+
* origin. A compromised mirror must not change scheme or port (or nominate a
|
|
315
|
+
* different host) in `dist.tarball`; later public redirects remain subject to
|
|
316
|
+
* the outbound boundary's hop-by-hop policy.
|
|
312
317
|
*/
|
|
313
|
-
export function validateNpmTarballUrl(tarballUrl, packageRef) {
|
|
318
|
+
export function validateNpmTarballUrl(tarballUrl, packageRef, registryOrigin) {
|
|
314
319
|
let url;
|
|
315
320
|
try {
|
|
316
321
|
url = new URL(tarballUrl);
|
|
@@ -321,12 +326,21 @@ export function validateNpmTarballUrl(tarballUrl, packageRef) {
|
|
|
321
326
|
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
322
327
|
throw new UntrustedNpmTarballError(`npm package ${packageRef} returned a tarball with disallowed scheme "${url.protocol}".`);
|
|
323
328
|
}
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
+
const expectedOrigin = registryOrigin ?? new URL(npmMetadataRegistry().baseUrl).origin;
|
|
330
|
+
if (url.origin !== expectedOrigin) {
|
|
331
|
+
throw new UntrustedNpmTarballError(`npm package ${packageRef} returned a tarball URL on untrusted origin "${url.origin}" (expected: ${expectedOrigin}).`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/** Network policy for a tarball URL that already passed {@link validateNpmTarballUrl}. */
|
|
335
|
+
export function npmArtifactNetworkPolicy(artifact) {
|
|
336
|
+
if (!artifact.registryOrigin) {
|
|
337
|
+
throw new UsageError("npm artifact network policy requires the registry origin that authorized its metadata.");
|
|
329
338
|
}
|
|
339
|
+
return {
|
|
340
|
+
kind: "npm-api",
|
|
341
|
+
registryOrigin: new URL(artifact.registryOrigin).origin,
|
|
342
|
+
allowPrivateRegistryOrigin: artifact.allowPrivateRegistryOrigin === true,
|
|
343
|
+
};
|
|
330
344
|
}
|
|
331
345
|
/**
|
|
332
346
|
* Resolve the npm registry base URL used to fetch package METADATA.
|
|
@@ -341,24 +355,29 @@ export function validateNpmTarballUrl(tarballUrl, packageRef) {
|
|
|
341
355
|
* default wholesale (like npm's own `--registry` flag) rather than being
|
|
342
356
|
* merged with it.
|
|
343
357
|
*/
|
|
344
|
-
function
|
|
358
|
+
function npmMetadataRegistry() {
|
|
345
359
|
const override = process.env.AKM_NPM_REGISTRY?.trim();
|
|
346
360
|
if (override) {
|
|
347
361
|
try {
|
|
348
362
|
const url = new URL(override);
|
|
349
363
|
const base = `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
|
|
350
|
-
return base.replace(/\/+$/, "");
|
|
364
|
+
return { baseUrl: base.replace(/\/+$/, ""), allowPrivateRegistryOrigin: true };
|
|
351
365
|
}
|
|
352
366
|
catch {
|
|
353
367
|
// Ignore unparseable overrides; fall back to the public registry.
|
|
354
368
|
}
|
|
355
369
|
}
|
|
356
|
-
return `https://${DEFAULT_NPM_REGISTRY_HOST}
|
|
370
|
+
return { baseUrl: `https://${DEFAULT_NPM_REGISTRY_HOST}`, allowPrivateRegistryOrigin: false };
|
|
357
371
|
}
|
|
358
372
|
async function resolveNpmArtifact(parsed) {
|
|
359
373
|
const encodedName = encodeURIComponent(parsed.packageName);
|
|
360
|
-
const
|
|
361
|
-
const
|
|
374
|
+
const npmRegistry = npmMetadataRegistry();
|
|
375
|
+
const npmPolicy = {
|
|
376
|
+
kind: "npm-api",
|
|
377
|
+
registryOrigin: new URL(npmRegistry.baseUrl).origin,
|
|
378
|
+
allowPrivateRegistryOrigin: npmRegistry.allowPrivateRegistryOrigin,
|
|
379
|
+
};
|
|
380
|
+
const metadata = await fetchJson(`${npmRegistry.baseUrl}/${encodedName}`, undefined, npmPolicy);
|
|
362
381
|
const versions = asRecord(metadata.versions);
|
|
363
382
|
const distTags = asRecord(metadata["dist-tags"]);
|
|
364
383
|
const requested = parsed.requestedVersionOrTag;
|
|
@@ -387,7 +406,7 @@ async function resolveNpmArtifact(parsed) {
|
|
|
387
406
|
if (!tarballUrl) {
|
|
388
407
|
throw new Error(`npm package ${parsed.packageName}@${resolvedVersion} does not expose a tarball URL.`);
|
|
389
408
|
}
|
|
390
|
-
validateNpmTarballUrl(tarballUrl, `${parsed.packageName}@${resolvedVersion}
|
|
409
|
+
validateNpmTarballUrl(tarballUrl, `${parsed.packageName}@${resolvedVersion}`, npmPolicy.registryOrigin);
|
|
391
410
|
const resolvedRevision = asString(dist.shasum) ?? asString(dist.integrity);
|
|
392
411
|
return {
|
|
393
412
|
id: parsed.id,
|
|
@@ -396,6 +415,8 @@ async function resolveNpmArtifact(parsed) {
|
|
|
396
415
|
artifactUrl: tarballUrl,
|
|
397
416
|
resolvedVersion,
|
|
398
417
|
resolvedRevision,
|
|
418
|
+
registryOrigin: npmPolicy.registryOrigin,
|
|
419
|
+
allowPrivateRegistryOrigin: npmPolicy.allowPrivateRegistryOrigin,
|
|
399
420
|
};
|
|
400
421
|
}
|
|
401
422
|
async function resolveGithubArtifact(parsed) {
|
|
@@ -416,7 +437,7 @@ async function resolveGithubArtifact(parsed) {
|
|
|
416
437
|
}
|
|
417
438
|
const headers = githubHeaders();
|
|
418
439
|
if (parsed.requestedRef) {
|
|
419
|
-
const commit = await tryFetchJson(`${repoBase}/commits/${encodeURIComponent(parsed.requestedRef)}`, headers);
|
|
440
|
+
const commit = await tryFetchJson(`${repoBase}/commits/${encodeURIComponent(parsed.requestedRef)}`, headers, GITHUB_API_POLICY);
|
|
420
441
|
const resolvedRevision = asString(commit?.sha) ?? parsed.requestedRef;
|
|
421
442
|
return {
|
|
422
443
|
id: parsed.id,
|
|
@@ -427,7 +448,7 @@ async function resolveGithubArtifact(parsed) {
|
|
|
427
448
|
resolvedVersion: parsed.requestedRef,
|
|
428
449
|
};
|
|
429
450
|
}
|
|
430
|
-
const latestRelease = await tryFetchJson(`${repoBase}/releases/latest`, headers);
|
|
451
|
+
const latestRelease = await tryFetchJson(`${repoBase}/releases/latest`, headers, GITHUB_API_POLICY);
|
|
431
452
|
if (latestRelease) {
|
|
432
453
|
const tarballUrl = asString(latestRelease.tarball_url);
|
|
433
454
|
if (tarballUrl) {
|
|
@@ -441,12 +462,12 @@ async function resolveGithubArtifact(parsed) {
|
|
|
441
462
|
};
|
|
442
463
|
}
|
|
443
464
|
}
|
|
444
|
-
const repoMeta = await fetchJson(repoBase, headers);
|
|
465
|
+
const repoMeta = await fetchJson(repoBase, headers, GITHUB_API_POLICY);
|
|
445
466
|
const defaultBranch = asString(repoMeta.default_branch);
|
|
446
467
|
if (!defaultBranch) {
|
|
447
468
|
throw new Error(`Unable to resolve default branch for ${parsed.owner}/${parsed.repo}.`);
|
|
448
469
|
}
|
|
449
|
-
const commit = await tryFetchJson(`${repoBase}/commits/${encodeURIComponent(defaultBranch)}`, headers);
|
|
470
|
+
const commit = await tryFetchJson(`${repoBase}/commits/${encodeURIComponent(defaultBranch)}`, headers, GITHUB_API_POLICY);
|
|
450
471
|
return {
|
|
451
472
|
id: parsed.id,
|
|
452
473
|
source: parsed.source,
|
|
@@ -603,16 +624,20 @@ function readGitValue(repoRoot, ...args) {
|
|
|
603
624
|
// responses are typically a few KB; a compromised registry streaming
|
|
604
625
|
// tens of MB of JSON is a DoS surface, not a feature.
|
|
605
626
|
const REGISTRY_JSON_BYTE_CAP = 10 * 1024 * 1024;
|
|
606
|
-
|
|
607
|
-
|
|
627
|
+
const GITHUB_API_POLICY = { kind: "github-api" };
|
|
628
|
+
async function fetchJson(url, headers, policy) {
|
|
629
|
+
const response = await fetchRegistryResponse(url, { headers }, { policy, timeoutMs: 30_000 });
|
|
608
630
|
if (!response.ok) {
|
|
631
|
+
await cancelRegistryResponse(response);
|
|
609
632
|
throw new Error(`Request failed (${response.status}) for ${url}`);
|
|
610
633
|
}
|
|
611
|
-
return jsonWithByteCap(response, REGISTRY_JSON_BYTE_CAP);
|
|
634
|
+
return jsonWithByteCap(response, REGISTRY_JSON_BYTE_CAP, { bodyTimeoutMs: 30_000 });
|
|
612
635
|
}
|
|
613
|
-
async function tryFetchJson(url, headers) {
|
|
614
|
-
const response = await
|
|
615
|
-
if (!response.ok)
|
|
636
|
+
async function tryFetchJson(url, headers, policy) {
|
|
637
|
+
const response = await fetchRegistryResponse(url, { headers }, { policy, timeoutMs: 30_000 });
|
|
638
|
+
if (!response.ok) {
|
|
639
|
+
await cancelRegistryResponse(response);
|
|
616
640
|
return null;
|
|
617
|
-
|
|
641
|
+
}
|
|
642
|
+
return jsonWithByteCap(response, REGISTRY_JSON_BYTE_CAP, { bodyTimeoutMs: 30_000 });
|
|
618
643
|
}
|