akm-cli 0.9.17-alpha.3 → 0.9.17-alpha.5

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.
Files changed (346) hide show
  1. package/CHANGELOG.md +760 -0
  2. package/dist/akm +94 -196
  3. package/dist/cli/shared.js +6 -2
  4. package/dist/cli.js +22 -9
  5. package/dist/commands/agent/agent-dispatch.js +1 -1
  6. package/dist/commands/command/command-execution.js +24 -62
  7. package/dist/commands/feedback-cli.js +0 -1
  8. package/dist/commands/health/accept-rate.js +2 -2
  9. package/dist/commands/health/checks.js +30 -75
  10. package/dist/commands/health/config-skew.js +38 -0
  11. package/dist/commands/health/egress.js +54 -0
  12. package/dist/commands/health/html-report.js +0 -38
  13. package/dist/commands/health/improve-metrics.js +123 -562
  14. package/dist/commands/health/plugin-staleness.js +53 -3
  15. package/dist/commands/health/renderers.js +12 -4
  16. package/dist/commands/health/report-view-model.js +11 -106
  17. package/dist/commands/health/types-improve.js +4 -19
  18. package/dist/commands/health/windows.js +64 -73
  19. package/dist/commands/health.js +122 -143
  20. package/dist/commands/improve/consolidate/chunking.js +25 -100
  21. package/dist/commands/improve/consolidate/sanitize.js +54 -149
  22. package/dist/commands/improve/consolidate.js +538 -1075
  23. package/dist/commands/improve/content-hash.js +16 -24
  24. package/dist/commands/improve/distill/content-repair.js +18 -100
  25. package/dist/commands/improve/distill-guards.js +20 -81
  26. package/dist/commands/improve/distill-promotion-policy.js +23 -243
  27. package/dist/commands/improve/distill.js +608 -1075
  28. package/dist/commands/improve/eligibility.js +126 -400
  29. package/dist/commands/improve/execution.js +3 -5
  30. package/dist/commands/improve/extract.js +487 -1046
  31. package/dist/commands/improve/feedback-valence.js +0 -25
  32. package/dist/commands/improve/improve-cli.js +29 -166
  33. package/dist/commands/improve/improve-result-file.js +10 -66
  34. package/dist/commands/improve/improve-strategies.js +12 -7
  35. package/dist/commands/improve/improve-usage-report.js +18 -64
  36. package/dist/commands/improve/improve.js +443 -1063
  37. package/dist/commands/improve/ledger.js +114 -0
  38. package/dist/commands/improve/locks.js +2 -8
  39. package/dist/commands/improve/loop-stages.js +459 -1172
  40. package/dist/commands/improve/memory/derived-ref.js +12 -77
  41. package/dist/commands/improve/memory/memory-belief.js +14 -118
  42. package/dist/commands/improve/memory/memory-improve.js +4 -3
  43. package/dist/commands/improve/outcome-loop.js +28 -156
  44. package/dist/commands/improve/planner.js +5 -10
  45. package/dist/commands/improve/preparation.js +851 -2339
  46. package/dist/commands/improve/proactive-maintenance.js +34 -101
  47. package/dist/commands/improve/reflect-noise.js +104 -280
  48. package/dist/commands/improve/reflect.js +621 -1367
  49. package/dist/commands/improve/salience.js +46 -232
  50. package/dist/commands/improve/session-asset.js +19 -100
  51. package/dist/commands/improve/stage.js +323 -0
  52. package/dist/commands/lint/base-linter.js +19 -5
  53. package/dist/commands/proposal/drain.js +251 -644
  54. package/dist/commands/proposal/proposal-cli.js +3 -18
  55. package/dist/commands/proposal/proposal-types.js +20 -41
  56. package/dist/commands/proposal/proposal.js +1 -2
  57. package/dist/commands/proposal/propose.js +134 -160
  58. package/dist/commands/proposal/repository.js +502 -1487
  59. package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
  60. package/dist/commands/proposal/validators/proposal-validators.js +1 -1
  61. package/dist/commands/proposal/validators/proposals.js +13 -89
  62. package/dist/commands/read/curate.js +63 -413
  63. package/dist/commands/read/search-cli.js +16 -33
  64. package/dist/commands/read/search.js +17 -23
  65. package/dist/commands/read/show.js +2 -13
  66. package/dist/commands/sources/bundle-cli.js +25 -2
  67. package/dist/commands/sources/bundle-config-ops.js +4 -0
  68. package/dist/commands/sources/dangerous-env-audit.js +1 -2
  69. package/dist/commands/sources/info.js +2 -11
  70. package/dist/commands/sources/installed-stashes.js +197 -746
  71. package/dist/commands/sources/schema-repair.js +98 -129
  72. package/dist/commands/sources/source-add.js +62 -12
  73. package/dist/commands/sources/source-manage.js +9 -2
  74. package/dist/commands/sources/stash-cli.js +1 -1
  75. package/dist/commands/tasks/explain.js +10 -13
  76. package/dist/commands/tasks/tasks-cli.js +9 -8
  77. package/dist/commands/tasks/tasks.js +326 -930
  78. package/dist/commands/tasks/validate.js +42 -21
  79. package/dist/commands/workflow/plan.js +22 -29
  80. package/dist/commands/workflow-cli.js +4 -4
  81. package/dist/core/adapter/adapters/akm-adapter.js +0 -1
  82. package/dist/core/adapter/adapters/akm-lint.js +2 -3
  83. package/dist/core/adapter/adapters/akm-metadata.js +11 -12
  84. package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
  85. package/dist/core/adapter/execution-source.js +17 -29
  86. package/dist/core/asset/asset-placement.js +4 -13
  87. package/dist/core/asset/resolve-ref.js +1 -1
  88. package/dist/core/bundle-id.js +42 -5
  89. package/dist/core/bundle-rename.js +291 -0
  90. package/dist/core/config/config-io.js +1 -2
  91. package/dist/core/config/config-schema.js +1 -33
  92. package/dist/core/config/config-walker.js +1 -1
  93. package/dist/core/config/config.js +163 -68
  94. package/dist/core/config/legacy-source-shape-shim.js +38 -9
  95. package/dist/core/config/schema/embedding.js +20 -5
  96. package/dist/core/config/schema/engines.js +5 -0
  97. package/dist/core/config/schema/execution.js +1 -1
  98. package/dist/core/config/schema/experimental.js +1 -1
  99. package/dist/core/config/schema/improve-processes.js +21 -95
  100. package/dist/core/config/schema/improve.js +4 -42
  101. package/dist/core/config/schema/scheduler.js +12 -12
  102. package/dist/core/config/schema/search.js +6 -22
  103. package/dist/core/env-secret-ref.js +0 -1
  104. package/dist/core/errors.js +8 -9
  105. package/dist/core/file-lock.js +76 -173
  106. package/dist/core/logs-db.js +2 -2
  107. package/dist/core/paths.js +0 -27
  108. package/dist/core/redaction.js +109 -2
  109. package/dist/core/run-lock.js +2 -5
  110. package/dist/core/spawn-env.js +1 -1
  111. package/dist/core/state/migrations.js +108 -61
  112. package/dist/core/state-db-scope.js +2 -4
  113. package/dist/core/state-db.js +126 -692
  114. package/dist/core/type-presentation.js +1 -9
  115. package/dist/core/write-source.js +293 -1012
  116. package/dist/execution/input-contract.js +1 -1
  117. package/dist/execution/resolved-request.js +135 -689
  118. package/dist/execution/source.js +63 -257
  119. package/dist/execution/target-ref.js +1 -1
  120. package/dist/indexer/bundle-identity-guard.js +2 -2
  121. package/dist/indexer/db/graph-db.js +106 -46
  122. package/dist/indexer/ensure-index.js +44 -85
  123. package/dist/indexer/graph/graph-extraction.js +340 -562
  124. package/dist/indexer/graph/graph-related.js +130 -0
  125. package/dist/indexer/index-rebuild-lock.js +3 -11
  126. package/dist/indexer/index-writer-lock.js +8 -17
  127. package/dist/indexer/index-written-assets.js +139 -151
  128. package/dist/indexer/indexer.js +524 -846
  129. package/dist/indexer/materialize-embeddings.js +60 -397
  130. package/dist/indexer/passes/memory-inference.js +81 -90
  131. package/dist/indexer/passes/metadata.js +132 -200
  132. package/dist/indexer/read-preflight.js +0 -7
  133. package/dist/indexer/scan/doc-to-entry.js +1 -3
  134. package/dist/indexer/scan/drain-dir.js +1 -1
  135. package/dist/indexer/search/db-search.js +181 -590
  136. package/dist/indexer/search/fts-query.js +30 -41
  137. package/dist/indexer/search/ranking.js +28 -154
  138. package/dist/indexer/search/search-attribution.js +12 -32
  139. package/dist/indexer/search/search-fields.js +11 -15
  140. package/dist/indexer/search/search-hit-enrichers.js +54 -85
  141. package/dist/indexer/search/search-source.js +1 -4
  142. package/dist/indexer/usage/usage-events.js +2 -7
  143. package/dist/integrations/agent/engine-fallback.js +23 -40
  144. package/dist/integrations/agent/engine-resolution.js +93 -183
  145. package/dist/integrations/agent/execution.js +507 -0
  146. package/dist/integrations/agent/model-map.js +28 -156
  147. package/dist/integrations/agent/request-lowering.js +66 -141
  148. package/dist/integrations/agent/runner-dispatch.js +143 -321
  149. package/dist/integrations/agent/runner.js +54 -14
  150. package/dist/integrations/lockfile.js +53 -101
  151. package/dist/llm/embedders/deterministic.js +2 -3
  152. package/dist/llm/embedders/profile.js +71 -0
  153. package/dist/llm/embedders/remote.js +10 -15
  154. package/dist/llm/graph-extract.js +3 -12
  155. package/dist/llm/index-passes.js +3 -5
  156. package/dist/llm/memory-infer.js +1 -2
  157. package/dist/llm/metadata-enhance.js +1 -2
  158. package/dist/llm/structured-call.js +5 -24
  159. package/dist/output/generic-render.js +23 -11
  160. package/dist/output/html-render.js +13 -10
  161. package/dist/output/render-registry.js +3 -32
  162. package/dist/output/shapes/helpers.js +2 -34
  163. package/dist/output/shapes/passthrough.js +1 -9
  164. package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
  165. package/dist/output/text/command-format.js +60 -23
  166. package/dist/output/text/helpers.js +1 -1
  167. package/dist/output/text/migrate.js +5 -14
  168. package/dist/output/text/proposal-format.js +1 -2
  169. package/dist/output/text/workflow-format.js +0 -32
  170. package/dist/output/text.js +2 -0
  171. package/dist/registry/factory.js +4 -19
  172. package/dist/registry/network.js +66 -220
  173. package/dist/registry/providers/index.js +0 -2
  174. package/dist/registry/providers/skills-sh.js +3 -14
  175. package/dist/registry/providers/static-index.js +24 -26
  176. package/dist/registry/resolve.js +55 -131
  177. package/dist/scripts/akm-migrate-node.js +43940 -93320
  178. package/dist/scripts/akm-migrate.js +43700 -93078
  179. package/dist/setup/registry-stash-loader.js +4 -13
  180. package/dist/setup/semantic-assets.js +3 -44
  181. package/dist/setup/setup.js +1 -1
  182. package/dist/setup/steps/tasks.js +25 -15
  183. package/dist/sources/provider-factory.js +17 -18
  184. package/dist/sources/providers/filesystem.js +2 -3
  185. package/dist/sources/providers/git-install.js +7 -1
  186. package/dist/sources/providers/git-provider.js +0 -3
  187. package/dist/sources/providers/git-stash.js +0 -17
  188. package/dist/sources/providers/npm.js +2 -4
  189. package/dist/sources/providers/provider-utils.js +5 -10
  190. package/dist/sources/providers/website.js +0 -2
  191. package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
  192. package/dist/sources/website-url.js +2 -2
  193. package/dist/storage/database.js +9 -35
  194. package/dist/storage/repositories/improve-ledger-repository.js +168 -0
  195. package/dist/storage/repositories/index-connection.js +34 -70
  196. package/dist/storage/repositories/index-entries-repository.js +69 -111
  197. package/dist/storage/repositories/index-entry-mapper.js +1 -2
  198. package/dist/storage/repositories/index-entry-schema.js +83 -269
  199. package/dist/storage/repositories/index-fts-repository.js +86 -256
  200. package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
  201. package/dist/storage/repositories/index-meta-repository.js +6 -4
  202. package/dist/storage/repositories/index-schema.js +192 -220
  203. package/dist/storage/repositories/index-utility-repository.js +8 -29
  204. package/dist/storage/repositories/index-vec-repository.js +133 -414
  205. package/dist/storage/repositories/outcome-repository.js +2 -1
  206. package/dist/storage/repositories/proposals-repository.js +35 -0
  207. package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
  208. package/dist/storage/repositories/task-history-repository.js +26 -4
  209. package/dist/storage/repositories/workflow-runs-repository.js +53 -244
  210. package/dist/storage/sqlite-migrations.js +136 -0
  211. package/dist/storage/sqlite-pragmas.js +11 -9
  212. package/dist/storage/sqlite-transaction.js +170 -0
  213. package/dist/storage/state-db-integrity.js +34 -27
  214. package/dist/tasks/activation-config.js +134 -62
  215. package/dist/tasks/backends/cron.js +129 -277
  216. package/dist/tasks/backends/exec-utils.js +2 -5
  217. package/dist/tasks/backends/launchd.js +125 -745
  218. package/dist/tasks/backends/schtasks.js +101 -620
  219. package/dist/tasks/prepare/prepare-support.js +5 -15
  220. package/dist/tasks/prepare/prepare.js +0 -2
  221. package/dist/tasks/resolve-akm-bin.js +20 -79
  222. package/dist/tasks/run/attempt-lifecycle.js +0 -1
  223. package/dist/tasks/scheduler-binding.js +18 -238
  224. package/dist/tasks/scheduler-invocation.js +52 -52
  225. package/dist/tasks/scheduler-lock.js +53 -0
  226. package/dist/tasks/scheduler-sync.js +361 -751
  227. package/dist/tasks/source/parse-task-source.js +160 -10
  228. package/dist/tasks/source/task-source-v3-frozen.js +3 -4
  229. package/dist/tasks/source/task-to-v4.js +2 -2
  230. package/dist/workflows/authoring/authoring.js +3 -12
  231. package/dist/workflows/compile.js +211 -0
  232. package/dist/workflows/concurrency-policy.js +13 -74
  233. package/dist/workflows/exec/child-invocation.js +3 -17
  234. package/dist/workflows/exec/child-workflow.js +32 -141
  235. package/dist/workflows/exec/dispatch-redaction.js +13 -53
  236. package/dist/workflows/exec/environment.js +98 -0
  237. package/dist/workflows/exec/exec-unit.js +33 -140
  238. package/dist/workflows/exec/frozen-judge.js +7 -59
  239. package/dist/workflows/exec/native-executor.js +82 -341
  240. package/dist/workflows/exec/param-secrets.js +29 -47
  241. package/dist/workflows/exec/run-workflow.js +154 -387
  242. package/dist/workflows/exec/scheduler.js +9 -36
  243. package/dist/workflows/exec/step-work.js +127 -430
  244. package/dist/workflows/exec/unit-dispatch.js +11 -63
  245. package/dist/workflows/exec/unit-writer.js +8 -52
  246. package/dist/workflows/exec/worktree.js +39 -273
  247. package/dist/workflows/freeze/child-output-references.js +4 -15
  248. package/dist/workflows/freeze/environment.js +99 -92
  249. package/dist/workflows/freeze/freeze.js +172 -0
  250. package/dist/workflows/freeze/step-values.js +19 -21
  251. package/dist/workflows/freeze/targets/child-workflow.js +23 -92
  252. package/dist/workflows/freeze/targets/command.js +10 -33
  253. package/dist/workflows/freeze/targets/script.js +5 -12
  254. package/dist/workflows/freeze/targets/shell.js +3 -6
  255. package/dist/workflows/freeze/targets/task.js +25 -80
  256. package/dist/workflows/freeze/task-bindings.js +20 -67
  257. package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
  258. package/dist/workflows/ir/params.js +6 -51
  259. package/dist/workflows/ir/plan-hash.js +2 -34
  260. package/dist/workflows/parser.js +140 -43
  261. package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
  262. package/dist/workflows/renderer.js +36 -69
  263. package/dist/workflows/resource-limits.js +12 -120
  264. package/dist/workflows/runtime/agent-identity.js +8 -40
  265. package/dist/workflows/runtime/run-outputs.js +3 -6
  266. package/dist/workflows/runtime/run-plan.js +316 -0
  267. package/dist/workflows/runtime/runs.js +48 -200
  268. package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
  269. package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
  270. package/dist/workflows/validate-summary.js +2 -7
  271. package/docs/integration/bundling-akm.md +49 -42
  272. package/docs/migration/README.md +1 -0
  273. package/docs/migration/release-notes/0.9.17.md +41 -0
  274. package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
  275. package/docs/reference/cli.md +182 -125
  276. package/docs/reference/configuration.md +49 -56
  277. package/docs/reference/data-and-telemetry.md +19 -20
  278. package/docs/reference/tasks.md +86 -38
  279. package/docs/reference/workflow-schema.md +14 -18
  280. package/docs/reference/workflows.md +6 -9
  281. package/package.json +1 -1
  282. package/schemas/akm-config.json +87 -406
  283. package/dist/commands/health/advisories.js +0 -150
  284. package/dist/commands/health/metrics.js +0 -329
  285. package/dist/commands/health/surfaces.js +0 -102
  286. package/dist/commands/improve/anti-collapse.js +0 -83
  287. package/dist/commands/improve/collapse-detector.js +0 -432
  288. package/dist/commands/improve/consolidate/eligibility.js +0 -48
  289. package/dist/commands/improve/consolidate/merge.js +0 -146
  290. package/dist/commands/improve/distill/promote-memory.js +0 -329
  291. package/dist/commands/improve/distill/quality-gate.js +0 -500
  292. package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
  293. package/dist/commands/improve/proposal-envelope.js +0 -31
  294. package/dist/commands/improve/run-context.js +0 -123
  295. package/dist/commands/improve/shared.js +0 -21
  296. package/dist/commands/improve/source-identity.js +0 -28
  297. package/dist/commands/improve/triage.js +0 -96
  298. package/dist/commands/proposal/drain-policies.js +0 -151
  299. package/dist/commands/sources/update-transaction.js +0 -220
  300. package/dist/core/action-contributors.js +0 -28
  301. package/dist/core/config/config-version-shim.js +0 -101
  302. package/dist/core/config/retired-experimental-keys-shim.js +0 -62
  303. package/dist/core/fs-txn.js +0 -405
  304. package/dist/core/lexical-score.js +0 -25
  305. package/dist/core/maintenance-barrier.js +0 -167
  306. package/dist/execution/executable-identity.js +0 -105
  307. package/dist/execution/guarded-source.js +0 -441
  308. package/dist/indexer/graph/graph-boost.js +0 -427
  309. package/dist/indexer/graph/graph-dedup.js +0 -95
  310. package/dist/indexer/search/name-match.js +0 -35
  311. package/dist/indexer/search/ranking-contributors.js +0 -515
  312. package/dist/indexer/walk/project-context.js +0 -192
  313. package/dist/integrations/agent/execution-cascade.js +0 -566
  314. package/dist/integrations/agent/execution-definitions.js +0 -202
  315. package/dist/integrations/agent/execution-lowering.js +0 -841
  316. package/dist/integrations/agent/execution-preparation.js +0 -98
  317. package/dist/integrations/agent/inline-execution.js +0 -74
  318. package/dist/registry/create-provider-registry.js +0 -29
  319. package/dist/registry/pinned-request-helper.js +0 -247
  320. package/dist/registry/pinned-transport.js +0 -717
  321. package/dist/sources/providers/index.js +0 -14
  322. package/dist/storage/engines/sqlite-migrations.js +0 -271
  323. package/dist/storage/repositories/canaries-repository.js +0 -107
  324. package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
  325. package/dist/storage/repositories/registry-cache.js +0 -113
  326. package/dist/tasks/scheduler-sync-preview.js +0 -52
  327. package/dist/workflows/freeze/resolve-steps.js +0 -86
  328. package/dist/workflows/freeze/source-freeze.js +0 -64
  329. package/dist/workflows/ir/compile.js +0 -321
  330. package/dist/workflows/ir/environment-v4.js +0 -330
  331. package/dist/workflows/ir/freeze-v4.js +0 -153
  332. package/dist/workflows/ir/schema-v4.js +0 -745
  333. package/dist/workflows/ir/schema.js +0 -354
  334. package/dist/workflows/program/schema.js +0 -78
  335. package/dist/workflows/runtime/checkin.js +0 -57
  336. package/dist/workflows/runtime/plan-classifier.js +0 -196
  337. package/dist/workflows/runtime/unit-checkin.js +0 -45
  338. package/dist/workflows/runtime/unit-phases.js +0 -20
  339. package/dist/workflows/schema.js +0 -4
  340. package/dist/workflows/source-ir/compile.js +0 -200
  341. package/dist/workflows/source-ir/program.js +0 -50
  342. package/dist/workflows/source-ir/result.js +0 -26
  343. package/dist/workflows/source-ir/schema.js +0 -786
  344. package/dist/workflows/source-ir/triggers.js +0 -79
  345. package/dist/workflows/source-ir/uses.js +0 -40
  346. package/dist/workflows/validator.js +0 -60
@@ -6,10 +6,9 @@ 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 { jsonWithByteCap } from "../core/common.js";
10
- import { NotFoundError, UsageError } from "../core/errors.js";
9
+ import { ConfigError, NotFoundError, UsageError } from "../core/errors.js";
11
10
  import { asRecord, asString, GITHUB_API_BASE, githubHeaders } from "../integrations/github.js";
12
- import { cancelRegistryResponse, fetchRegistryResponse } from "./network.js";
11
+ import { fetchRegistryJson } from "./network.js";
13
12
  import { isExactSemver, isSemverRange, maxSatisfying } from "./semver.js";
14
13
  /**
15
14
  * Pass an HTTPS bearer credential to Git without placing it in the remote URL
@@ -64,12 +63,12 @@ export function validateGitRef(ref) {
64
63
  export function parseRegistryRef(rawRef) {
65
64
  const ref = rawRef.trim();
66
65
  if (!ref)
67
- throw new Error("Registry ref is required.");
66
+ throw new UsageError("Registry ref is required.", "MISSING_REQUIRED_ARGUMENT");
68
67
  // Detect registry search result IDs (e.g. "skills-sh:org/skills/name")
69
68
  // that are not installable refs. Known installable prefixes are handled below.
70
69
  const registryIdHint = detectRegistrySearchId(ref);
71
70
  if (registryIdHint) {
72
- throw new Error(registryIdHint);
71
+ throw new UsageError(registryIdHint);
73
72
  }
74
73
  if (ref.startsWith("npm:")) {
75
74
  return parseNpmRef(ref.slice(4), ref);
@@ -160,7 +159,7 @@ export async function resolveRegistryArtifact(parsed, options) {
160
159
  function parseNpmRef(input, originalRef) {
161
160
  const trimmed = input.trim();
162
161
  if (!trimmed)
163
- throw new Error("Invalid npm ref.");
162
+ throw new UsageError("Invalid npm ref.");
164
163
  const parsed = splitNpmNameAndVersion(trimmed);
165
164
  validateNpmPackageName(parsed.packageName);
166
165
  return {
@@ -175,12 +174,12 @@ function parseGithubShorthand(input, originalRef) {
175
174
  const [repoPart, requestedRef] = splitRefSuffix(input.trim());
176
175
  const segments = repoPart.split("/").filter(Boolean);
177
176
  if (segments.length !== 2) {
178
- throw new Error("Invalid GitHub ref. Expected owner/repo or owner/repo#ref.");
177
+ throw new UsageError("Invalid GitHub ref. Expected owner/repo or owner/repo#ref.");
179
178
  }
180
179
  const owner = segments[0];
181
180
  const repo = segments[1].replace(/\.git$/i, "");
182
181
  if (!owner || !repo) {
183
- throw new Error("Invalid GitHub ref. Expected owner/repo.");
182
+ throw new UsageError("Invalid GitHub ref. Expected owner/repo.");
184
183
  }
185
184
  return {
186
185
  source: "github",
@@ -197,7 +196,7 @@ function parseRemoteUrl(rawUrl) {
197
196
  url = new URL(rawUrl);
198
197
  }
199
198
  catch {
200
- throw new Error("Invalid registry URL.");
199
+ throw new UsageError("Invalid registry URL.");
201
200
  }
202
201
  if (url.hostname === "github.com") {
203
202
  return parseGithubUrl(url, rawUrl);
@@ -207,7 +206,7 @@ function parseRemoteUrl(rawUrl) {
207
206
  function parseGithubUrl(url, rawUrl) {
208
207
  const segments = url.pathname.split("/").filter(Boolean);
209
208
  if (segments.length < 2) {
210
- throw new Error("Invalid GitHub URL. Expected https://github.com/owner/repo.");
209
+ throw new UsageError("Invalid GitHub URL. Expected https://github.com/owner/repo.");
211
210
  }
212
211
  const owner = segments[0];
213
212
  const repo = segments[1].replace(/\.git$/i, "");
@@ -224,7 +223,7 @@ function parseGithubUrl(url, rawUrl) {
224
223
  function parseGitUrl(input, originalRef) {
225
224
  const [urlPart, requestedRef] = splitRefSuffix(input.trim());
226
225
  if (!urlPart)
227
- throw new Error("Invalid git ref. A URL is required.");
226
+ throw new UsageError("Invalid git ref. A URL is required.");
228
227
  // Normalize the URL for the id (strip .git suffix, fragment)
229
228
  const normalized = urlPart.replace(/\.git$/i, "");
230
229
  return {
@@ -251,7 +250,7 @@ function tryParseLocalRef(rawRef, explicitPath) {
251
250
  }
252
251
  if (!stat.isDirectory()) {
253
252
  if (explicitPath) {
254
- throw new Error("Local add path must be a directory, but the provided path is not one.");
253
+ throw new UsageError("Local add path must be a directory, but the provided path is not one.");
255
254
  }
256
255
  // Bare name exists but isn't a directory — not a local ref
257
256
  return undefined;
@@ -292,55 +291,11 @@ function isPathLikeRef(ref) {
292
291
  }
293
292
  /** Default public npm registry host. */
294
293
  const DEFAULT_NPM_REGISTRY_HOST = "registry.npmjs.org";
295
- /**
296
- * Typed error raised when the npm registry returns a tarball URL on a host
297
- * that is not the public registry or the operator-configured mirror. Carries
298
- * a stable `.code` so callers (and JSON envelope output) can branch on it
299
- * without parsing the message string.
300
- */
301
- export class UntrustedNpmTarballError extends Error {
302
- code = "UNTRUSTED_NPM_TARBALL";
303
- _hint;
304
- constructor(msg, hint) {
305
- super(msg);
306
- this.name = "UntrustedNpmTarballError";
307
- this._hint = hint;
308
- Object.setPrototypeOf(this, new.target.prototype);
309
- }
310
- hint() {
311
- return (this._hint ??
312
- "Set AKM_NPM_REGISTRY to your private npm mirror's base URL if you install from a non-default registry.");
313
- }
314
- }
315
- /**
316
- * Resolve the set of npm registry hosts whose tarballs are considered trusted.
317
- * Always includes the public npm registry, plus the host of an operator-set
318
- * `AKM_NPM_REGISTRY` environment variable (if it parses to a valid URL).
319
- */
320
- export function trustedNpmTarballHosts() {
321
- const hosts = new Set([DEFAULT_NPM_REGISTRY_HOST]);
322
- const override = process.env.AKM_NPM_REGISTRY?.trim();
323
- if (override) {
324
- // A malformed override must not be silently ignored (falling back to the
325
- // public registry as though nothing was configured) — that would install
326
- // from the wrong registry without telling the operator (R-035).
327
- let overrideHost;
328
- try {
329
- overrideHost = new URL(override).hostname.toLowerCase();
330
- }
331
- catch {
332
- throw new UsageError(`AKM_NPM_REGISTRY is set to an invalid URL: ${override}`);
333
- }
334
- if (overrideHost)
335
- hosts.add(overrideHost);
336
- }
337
- return hosts;
338
- }
294
+ const UNTRUSTED_TARBALL_HINT = "Set AKM_NPM_REGISTRY to your private npm mirror's base URL if you install from a non-default registry.";
339
295
  /**
340
296
  * Validate that an npm tarball URL starts at the exact metadata registry
341
- * origin. A compromised mirror must not change scheme or port (or nominate a
342
- * different host) in `dist.tarball`; later public redirects remain subject to
343
- * the outbound boundary's hop-by-hop policy.
297
+ * origin: a mirror must not change scheme or port, or nominate a different
298
+ * host, in `dist.tarball`.
344
299
  */
345
300
  export function validateNpmTarballUrl(tarballUrl, packageRef, registryOrigin) {
346
301
  let url;
@@ -348,39 +303,20 @@ export function validateNpmTarballUrl(tarballUrl, packageRef, registryOrigin) {
348
303
  url = new URL(tarballUrl);
349
304
  }
350
305
  catch {
351
- throw new UntrustedNpmTarballError(`npm package ${packageRef} returned an invalid tarball URL: ${tarballUrl}`);
306
+ throw new NotFoundError(`npm package ${packageRef} returned an invalid tarball URL: ${tarballUrl}`, "REGISTRY_RESPONSE_INVALID", UNTRUSTED_TARBALL_HINT);
352
307
  }
353
308
  if (url.protocol !== "https:" && url.protocol !== "http:") {
354
- throw new UntrustedNpmTarballError(`npm package ${packageRef} returned a tarball with disallowed scheme "${url.protocol}".`);
309
+ throw new NotFoundError(`npm package ${packageRef} returned a tarball with disallowed scheme "${url.protocol}".`, "REGISTRY_RESPONSE_INVALID", UNTRUSTED_TARBALL_HINT);
355
310
  }
356
- const expectedOrigin = registryOrigin ?? new URL(npmMetadataRegistry().baseUrl).origin;
311
+ const expectedOrigin = registryOrigin ?? new URL(npmMetadataRegistry()).origin;
357
312
  if (url.origin !== expectedOrigin) {
358
- throw new UntrustedNpmTarballError(`npm package ${packageRef} returned a tarball URL on untrusted origin "${url.origin}" (expected: ${expectedOrigin}).`);
313
+ throw new NotFoundError(`npm package ${packageRef} returned a tarball URL on untrusted origin "${url.origin}" (expected: ${expectedOrigin}).`, "REGISTRY_RESPONSE_INVALID", UNTRUSTED_TARBALL_HINT);
359
314
  }
360
315
  }
361
- /** Network policy for a tarball URL that already passed {@link validateNpmTarballUrl}. */
362
- export function npmArtifactNetworkPolicy(artifact) {
363
- if (!artifact.registryOrigin) {
364
- throw new UsageError("npm artifact network policy requires the registry origin that authorized its metadata.");
365
- }
366
- return {
367
- kind: "npm-api",
368
- registryOrigin: new URL(artifact.registryOrigin).origin,
369
- allowPrivateRegistryOrigin: artifact.allowPrivateRegistryOrigin === true,
370
- };
371
- }
372
316
  /**
373
- * Resolve the npm registry base URL used to fetch package METADATA.
374
- *
375
- * R-035: `AKM_NPM_REGISTRY` previously only widened the trusted-tarball-host
376
- * allowlist (see {@link trustedNpmTarballHosts}) while the metadata endpoint
377
- * stayed hardcoded to the public registry — so an operator-configured mirror
378
- * was never actually consulted, making the `UntrustedNpmTarballError.hint()`
379
- * text below false. Honoring the override here for metadata too makes the
380
- * hint true: installs really do resolve entirely against the configured
381
- * mirror when it is set, mirroring how a private npm registry replaces the
382
- * default wholesale (like npm's own `--registry` flag) rather than being
383
- * merged with it.
317
+ * The npm registry base URL for package METADATA: `AKM_NPM_REGISTRY` when set
318
+ * (a private mirror replaces the default wholesale, like npm's own
319
+ * `--registry`), else the public registry.
384
320
  */
385
321
  function npmMetadataRegistry() {
386
322
  const override = process.env.AKM_NPM_REGISTRY?.trim();
@@ -393,22 +329,16 @@ function npmMetadataRegistry() {
393
329
  url = new URL(override);
394
330
  }
395
331
  catch {
396
- throw new UsageError(`AKM_NPM_REGISTRY is set to an invalid URL: ${override}`);
332
+ throw new ConfigError(`AKM_NPM_REGISTRY is set to an invalid URL: ${override}`, "REGISTRY_URL_INVALID");
397
333
  }
398
- const base = `${url.origin}${url.pathname === "/" ? "" : url.pathname}`;
399
- return { baseUrl: base.replace(/\/+$/, ""), allowPrivateRegistryOrigin: true };
334
+ return `${url.origin}${url.pathname === "/" ? "" : url.pathname}`.replace(/\/+$/, "");
400
335
  }
401
- return { baseUrl: `https://${DEFAULT_NPM_REGISTRY_HOST}`, allowPrivateRegistryOrigin: false };
336
+ return `https://${DEFAULT_NPM_REGISTRY_HOST}`;
402
337
  }
403
338
  async function resolveNpmArtifact(parsed) {
404
339
  const encodedName = encodeURIComponent(parsed.packageName);
405
- const npmRegistry = npmMetadataRegistry();
406
- const npmPolicy = {
407
- kind: "npm-api",
408
- registryOrigin: new URL(npmRegistry.baseUrl).origin,
409
- allowPrivateRegistryOrigin: npmRegistry.allowPrivateRegistryOrigin,
410
- };
411
- const metadata = await fetchJson(`${npmRegistry.baseUrl}/${encodedName}`, undefined, npmPolicy);
340
+ const registryBase = npmMetadataRegistry();
341
+ const metadata = await fetchJson(`${registryBase}/${encodedName}`, undefined);
412
342
  const versions = asRecord(metadata.versions);
413
343
  const distTags = asRecord(metadata["dist-tags"]);
414
344
  const requested = parsed.requestedVersionOrTag;
@@ -429,15 +359,15 @@ async function resolveNpmArtifact(parsed) {
429
359
  }
430
360
  }
431
361
  if (!resolvedVersion || !(resolvedVersion in versions)) {
432
- throw new Error(`Unable to resolve npm ref "${parsed.ref}".`);
362
+ throw new NotFoundError(`Unable to resolve npm ref "${parsed.ref}".`, "REGISTRY_NOT_FOUND");
433
363
  }
434
364
  const versionMeta = asRecord(versions[resolvedVersion]);
435
365
  const dist = asRecord(versionMeta.dist);
436
366
  const tarballUrl = asString(dist.tarball);
437
367
  if (!tarballUrl) {
438
- throw new Error(`npm package ${parsed.packageName}@${resolvedVersion} does not expose a tarball URL.`);
368
+ throw new NotFoundError(`npm package ${parsed.packageName}@${resolvedVersion} does not expose a tarball URL.`, "REGISTRY_RESPONSE_INVALID");
439
369
  }
440
- validateNpmTarballUrl(tarballUrl, `${parsed.packageName}@${resolvedVersion}`, npmPolicy.registryOrigin);
370
+ validateNpmTarballUrl(tarballUrl, `${parsed.packageName}@${resolvedVersion}`, new URL(registryBase).origin);
441
371
  const resolvedRevision = asString(dist.shasum) ?? asString(dist.integrity);
442
372
  return {
443
373
  id: parsed.id,
@@ -446,8 +376,6 @@ async function resolveNpmArtifact(parsed) {
446
376
  artifactUrl: tarballUrl,
447
377
  resolvedVersion,
448
378
  resolvedRevision,
449
- registryOrigin: npmPolicy.registryOrigin,
450
- allowPrivateRegistryOrigin: npmPolicy.allowPrivateRegistryOrigin,
451
379
  };
452
380
  }
453
381
  async function resolveGithubArtifact(parsed, credential) {
@@ -468,7 +396,7 @@ async function resolveGithubArtifact(parsed, credential) {
468
396
  }
469
397
  const headers = { ...githubHeaders(), ...(credential ? { Authorization: `Bearer ${credential}` } : {}) };
470
398
  if (parsed.requestedRef) {
471
- const commit = await tryFetchJson(`${repoBase}/commits/${encodeURIComponent(parsed.requestedRef)}`, headers, GITHUB_API_POLICY);
399
+ const commit = await tryFetchJson(`${repoBase}/commits/${encodeURIComponent(parsed.requestedRef)}`, headers);
472
400
  const resolvedRevision = asString(commit?.sha) ?? parsed.requestedRef;
473
401
  return {
474
402
  id: parsed.id,
@@ -479,7 +407,7 @@ async function resolveGithubArtifact(parsed, credential) {
479
407
  resolvedVersion: parsed.requestedRef,
480
408
  };
481
409
  }
482
- const latestRelease = await tryFetchJson(`${repoBase}/releases/latest`, headers, GITHUB_API_POLICY);
410
+ const latestRelease = await tryFetchJson(`${repoBase}/releases/latest`, headers);
483
411
  if (latestRelease) {
484
412
  const tarballUrl = asString(latestRelease.tarball_url);
485
413
  if (tarballUrl) {
@@ -493,12 +421,12 @@ async function resolveGithubArtifact(parsed, credential) {
493
421
  };
494
422
  }
495
423
  }
496
- const repoMeta = await fetchJson(repoBase, headers, GITHUB_API_POLICY);
424
+ const repoMeta = await fetchJson(repoBase, headers);
497
425
  const defaultBranch = asString(repoMeta.default_branch);
498
426
  if (!defaultBranch) {
499
- throw new Error(`Unable to resolve default branch for ${parsed.owner}/${parsed.repo}.`);
427
+ throw new NotFoundError(`Unable to resolve default branch for ${parsed.owner}/${parsed.repo}.`, "REGISTRY_RESPONSE_INVALID");
500
428
  }
501
- const commit = await tryFetchJson(`${repoBase}/commits/${encodeURIComponent(defaultBranch)}`, headers, GITHUB_API_POLICY);
429
+ const commit = await tryFetchJson(`${repoBase}/commits/${encodeURIComponent(defaultBranch)}`, headers);
502
430
  return {
503
431
  id: parsed.id,
504
432
  source: parsed.source,
@@ -530,7 +458,7 @@ async function resolveGitArtifact(parsed, credential) {
530
458
  // `git ls-remote`), a plain git source has no fallback resolver — an
531
459
  // unresolved revision here would silently disable the post-clone
532
460
  // revision-integrity check in `verifyClonedRevision` (R-011).
533
- throw new Error(`Unable to resolve ${parsed.requestedRef ?? "HEAD"} for ${parsed.url} via 'git ls-remote'; refusing to install without a verifiable revision.`);
461
+ throw new NotFoundError(`Unable to resolve ${parsed.requestedRef ?? "HEAD"} for ${parsed.url} via 'git ls-remote'; refusing to install without a verifiable revision.`, "REGISTRY_NOT_FOUND");
534
462
  }
535
463
  return {
536
464
  id: parsed.id,
@@ -573,21 +501,21 @@ function splitNpmNameAndVersion(input) {
573
501
  }
574
502
  function validateNpmPackageName(name) {
575
503
  if (!name)
576
- throw new Error("Invalid npm package name: name is required.");
504
+ throw new UsageError("Invalid npm package name: name is required.");
577
505
  if (name.length > 214)
578
- throw new Error(`Invalid npm package name: "${name}" exceeds 214 characters.`);
506
+ throw new UsageError(`Invalid npm package name: "${name}" exceeds 214 characters.`);
579
507
  if (name !== name.toLowerCase() && !name.startsWith("@")) {
580
- throw new Error(`Invalid npm package name: "${name}" must be lowercase.`);
508
+ throw new UsageError(`Invalid npm package name: "${name}" must be lowercase.`);
581
509
  }
582
510
  if (name.startsWith(".") || name.startsWith("_")) {
583
- throw new Error(`Invalid npm package name: "${name}" cannot start with . or _.`);
511
+ throw new UsageError(`Invalid npm package name: "${name}" cannot start with . or _.`);
584
512
  }
585
513
  if (/[~'!()*]/.test(name) ||
586
514
  name.includes(" ") ||
587
515
  encodeURIComponent(name)
588
516
  .replace(/%40/g, "@")
589
517
  .replace(/%2[Ff]/g, "/") !== name) {
590
- throw new Error(`Invalid npm package name: "${name}" contains invalid characters.`);
518
+ throw new UsageError(`Invalid npm package name: "${name}" contains invalid characters.`);
591
519
  }
592
520
  }
593
521
  function looksLikeGithubOwnerRepo(ref) {
@@ -662,24 +590,20 @@ function readGitValue(repoRoot, ...args) {
662
590
  const value = result.stdout.trim();
663
591
  return value || undefined;
664
592
  }
665
- // Cap JSON responses at 10 MB — npm package manifests and GitHub API
666
- // responses are typically a few KB; a compromised registry streaming
667
- // tens of MB of JSON is a DoS surface, not a feature.
593
+ // npm package manifests and GitHub API responses are typically a few KB; 10 MB
594
+ // is the cap on what one is allowed to send.
668
595
  const REGISTRY_JSON_BYTE_CAP = 10 * 1024 * 1024;
669
- const GITHUB_API_POLICY = { kind: "github-api" };
670
- async function fetchJson(url, headers, policy) {
671
- const response = await fetchRegistryResponse(url, { headers }, { policy, timeoutMs: 30_000 });
672
- if (!response.ok) {
673
- await cancelRegistryResponse(response);
674
- throw new Error(`Request failed (${response.status}) for ${url}`);
675
- }
676
- return jsonWithByteCap(response, REGISTRY_JSON_BYTE_CAP, { bodyTimeoutMs: 30_000 });
677
- }
678
- async function tryFetchJson(url, headers, policy) {
679
- const response = await fetchRegistryResponse(url, { headers }, { policy, timeoutMs: 30_000 });
680
- if (!response.ok) {
681
- await cancelRegistryResponse(response);
682
- return null;
683
- }
684
- return jsonWithByteCap(response, REGISTRY_JSON_BYTE_CAP, { bodyTimeoutMs: 30_000 });
596
+ async function fetchJson(url, headers) {
597
+ return fetchRegistryJson(url, { headers, timeoutMs: 30_000, maxBytes: REGISTRY_JSON_BYTE_CAP });
598
+ }
599
+ /** `fetchJson` for optional GitHub lookups: a not-found / unusable answer is `null`, a transient failure still throws. */
600
+ async function tryFetchJson(url, headers) {
601
+ try {
602
+ return await fetchJson(url, headers);
603
+ }
604
+ catch (error) {
605
+ if (error instanceof NotFoundError)
606
+ return null;
607
+ throw error;
608
+ }
685
609
  }