akm-cli 0.9.17-alpha.2 → 0.9.17-alpha.4

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 (343) hide show
  1. package/CHANGELOG.md +756 -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/proposal/drain.js +251 -644
  53. package/dist/commands/proposal/proposal-cli.js +3 -18
  54. package/dist/commands/proposal/proposal-types.js +20 -41
  55. package/dist/commands/proposal/proposal.js +1 -2
  56. package/dist/commands/proposal/propose.js +134 -160
  57. package/dist/commands/proposal/repository.js +502 -1487
  58. package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
  59. package/dist/commands/proposal/validators/proposal-validators.js +1 -1
  60. package/dist/commands/proposal/validators/proposals.js +13 -89
  61. package/dist/commands/read/curate.js +63 -413
  62. package/dist/commands/read/search-cli.js +16 -33
  63. package/dist/commands/read/search.js +17 -23
  64. package/dist/commands/read/show.js +2 -13
  65. package/dist/commands/sources/bundle-cli.js +25 -2
  66. package/dist/commands/sources/bundle-config-ops.js +7 -0
  67. package/dist/commands/sources/dangerous-env-audit.js +1 -2
  68. package/dist/commands/sources/info.js +2 -11
  69. package/dist/commands/sources/installed-stashes.js +197 -746
  70. package/dist/commands/sources/schema-repair.js +98 -129
  71. package/dist/commands/sources/source-add.js +62 -12
  72. package/dist/commands/sources/stash-cli.js +1 -1
  73. package/dist/commands/tasks/explain.js +10 -13
  74. package/dist/commands/tasks/tasks-cli.js +9 -8
  75. package/dist/commands/tasks/tasks.js +326 -930
  76. package/dist/commands/tasks/validate.js +42 -21
  77. package/dist/commands/workflow/plan.js +22 -29
  78. package/dist/commands/workflow-cli.js +4 -4
  79. package/dist/core/adapter/adapters/akm-adapter.js +0 -1
  80. package/dist/core/adapter/adapters/akm-lint.js +2 -3
  81. package/dist/core/adapter/adapters/akm-metadata.js +11 -12
  82. package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
  83. package/dist/core/adapter/execution-source.js +17 -29
  84. package/dist/core/asset/resolve-ref.js +1 -1
  85. package/dist/core/bundle-id.js +42 -5
  86. package/dist/core/bundle-rename.js +291 -0
  87. package/dist/core/config/config-io.js +1 -2
  88. package/dist/core/config/config-schema.js +1 -33
  89. package/dist/core/config/config-walker.js +1 -1
  90. package/dist/core/config/config.js +163 -68
  91. package/dist/core/config/legacy-source-shape-shim.js +38 -9
  92. package/dist/core/config/schema/embedding.js +20 -5
  93. package/dist/core/config/schema/engines.js +5 -0
  94. package/dist/core/config/schema/execution.js +1 -1
  95. package/dist/core/config/schema/experimental.js +1 -1
  96. package/dist/core/config/schema/improve-processes.js +21 -95
  97. package/dist/core/config/schema/improve.js +4 -42
  98. package/dist/core/config/schema/scheduler.js +12 -12
  99. package/dist/core/config/schema/search.js +6 -22
  100. package/dist/core/env-secret-ref.js +0 -1
  101. package/dist/core/errors.js +8 -9
  102. package/dist/core/file-lock.js +76 -173
  103. package/dist/core/logs-db.js +2 -2
  104. package/dist/core/paths.js +0 -27
  105. package/dist/core/redaction.js +109 -2
  106. package/dist/core/run-lock.js +2 -5
  107. package/dist/core/spawn-env.js +1 -1
  108. package/dist/core/state/migrations.js +108 -61
  109. package/dist/core/state-db-scope.js +2 -4
  110. package/dist/core/state-db.js +126 -692
  111. package/dist/core/type-presentation.js +1 -9
  112. package/dist/core/write-source.js +293 -1012
  113. package/dist/execution/input-contract.js +1 -1
  114. package/dist/execution/resolved-request.js +135 -689
  115. package/dist/execution/source.js +63 -257
  116. package/dist/execution/target-ref.js +1 -1
  117. package/dist/indexer/bundle-identity-guard.js +2 -2
  118. package/dist/indexer/db/graph-db.js +106 -46
  119. package/dist/indexer/ensure-index.js +44 -85
  120. package/dist/indexer/graph/graph-extraction.js +340 -562
  121. package/dist/indexer/graph/graph-related.js +130 -0
  122. package/dist/indexer/index-rebuild-lock.js +3 -11
  123. package/dist/indexer/index-writer-lock.js +8 -17
  124. package/dist/indexer/index-written-assets.js +139 -151
  125. package/dist/indexer/indexer.js +524 -846
  126. package/dist/indexer/materialize-embeddings.js +60 -397
  127. package/dist/indexer/passes/memory-inference.js +81 -90
  128. package/dist/indexer/passes/metadata.js +132 -200
  129. package/dist/indexer/read-preflight.js +0 -7
  130. package/dist/indexer/scan/doc-to-entry.js +1 -3
  131. package/dist/indexer/scan/drain-dir.js +1 -1
  132. package/dist/indexer/search/db-search.js +181 -590
  133. package/dist/indexer/search/fts-query.js +30 -41
  134. package/dist/indexer/search/ranking.js +28 -154
  135. package/dist/indexer/search/search-attribution.js +12 -32
  136. package/dist/indexer/search/search-fields.js +11 -15
  137. package/dist/indexer/search/search-hit-enrichers.js +54 -85
  138. package/dist/indexer/search/search-source.js +1 -4
  139. package/dist/indexer/usage/usage-events.js +2 -7
  140. package/dist/integrations/agent/engine-fallback.js +23 -40
  141. package/dist/integrations/agent/engine-resolution.js +93 -183
  142. package/dist/integrations/agent/execution.js +507 -0
  143. package/dist/integrations/agent/model-map.js +28 -156
  144. package/dist/integrations/agent/request-lowering.js +66 -141
  145. package/dist/integrations/agent/runner-dispatch.js +143 -321
  146. package/dist/integrations/agent/runner.js +54 -14
  147. package/dist/integrations/lockfile.js +53 -101
  148. package/dist/llm/embedders/deterministic.js +2 -3
  149. package/dist/llm/embedders/profile.js +71 -0
  150. package/dist/llm/embedders/remote.js +10 -15
  151. package/dist/llm/graph-extract.js +3 -12
  152. package/dist/llm/index-passes.js +3 -5
  153. package/dist/llm/memory-infer.js +1 -2
  154. package/dist/llm/metadata-enhance.js +1 -2
  155. package/dist/llm/structured-call.js +5 -24
  156. package/dist/output/generic-render.js +23 -11
  157. package/dist/output/html-render.js +13 -10
  158. package/dist/output/render-registry.js +3 -32
  159. package/dist/output/shapes/helpers.js +2 -34
  160. package/dist/output/shapes/passthrough.js +1 -9
  161. package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
  162. package/dist/output/text/command-format.js +60 -23
  163. package/dist/output/text/helpers.js +1 -1
  164. package/dist/output/text/migrate.js +5 -14
  165. package/dist/output/text/proposal-format.js +1 -2
  166. package/dist/output/text/workflow-format.js +0 -32
  167. package/dist/output/text.js +2 -0
  168. package/dist/registry/factory.js +4 -19
  169. package/dist/registry/network.js +66 -220
  170. package/dist/registry/providers/index.js +0 -2
  171. package/dist/registry/providers/skills-sh.js +3 -14
  172. package/dist/registry/providers/static-index.js +24 -26
  173. package/dist/registry/resolve.js +55 -131
  174. package/dist/scripts/akm-migrate-node.js +43937 -93313
  175. package/dist/scripts/akm-migrate.js +43697 -93071
  176. package/dist/setup/registry-stash-loader.js +4 -13
  177. package/dist/setup/semantic-assets.js +3 -44
  178. package/dist/setup/setup.js +1 -1
  179. package/dist/setup/steps/tasks.js +25 -15
  180. package/dist/sources/provider-factory.js +17 -18
  181. package/dist/sources/providers/filesystem.js +2 -3
  182. package/dist/sources/providers/git-install.js +7 -1
  183. package/dist/sources/providers/git-provider.js +0 -3
  184. package/dist/sources/providers/git-stash.js +0 -17
  185. package/dist/sources/providers/npm.js +2 -4
  186. package/dist/sources/providers/provider-utils.js +5 -10
  187. package/dist/sources/providers/website.js +0 -2
  188. package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
  189. package/dist/sources/website-url.js +2 -2
  190. package/dist/storage/database.js +9 -35
  191. package/dist/storage/repositories/improve-ledger-repository.js +168 -0
  192. package/dist/storage/repositories/index-connection.js +34 -70
  193. package/dist/storage/repositories/index-entries-repository.js +69 -111
  194. package/dist/storage/repositories/index-entry-mapper.js +1 -2
  195. package/dist/storage/repositories/index-entry-schema.js +83 -269
  196. package/dist/storage/repositories/index-fts-repository.js +86 -256
  197. package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
  198. package/dist/storage/repositories/index-meta-repository.js +6 -4
  199. package/dist/storage/repositories/index-schema.js +192 -220
  200. package/dist/storage/repositories/index-utility-repository.js +8 -29
  201. package/dist/storage/repositories/index-vec-repository.js +133 -414
  202. package/dist/storage/repositories/outcome-repository.js +2 -1
  203. package/dist/storage/repositories/proposals-repository.js +35 -0
  204. package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
  205. package/dist/storage/repositories/task-history-repository.js +26 -4
  206. package/dist/storage/repositories/workflow-runs-repository.js +53 -244
  207. package/dist/storage/sqlite-migrations.js +136 -0
  208. package/dist/storage/sqlite-pragmas.js +11 -9
  209. package/dist/storage/sqlite-transaction.js +170 -0
  210. package/dist/storage/state-db-integrity.js +34 -27
  211. package/dist/tasks/activation-config.js +134 -62
  212. package/dist/tasks/backends/cron.js +129 -277
  213. package/dist/tasks/backends/exec-utils.js +2 -5
  214. package/dist/tasks/backends/launchd.js +125 -745
  215. package/dist/tasks/backends/schtasks.js +101 -620
  216. package/dist/tasks/prepare/prepare-support.js +5 -15
  217. package/dist/tasks/prepare/prepare.js +0 -2
  218. package/dist/tasks/resolve-akm-bin.js +20 -79
  219. package/dist/tasks/run/attempt-lifecycle.js +0 -1
  220. package/dist/tasks/scheduler-binding.js +18 -238
  221. package/dist/tasks/scheduler-invocation.js +52 -52
  222. package/dist/tasks/scheduler-lock.js +53 -0
  223. package/dist/tasks/scheduler-sync.js +363 -679
  224. package/dist/tasks/source/parse-task-source.js +160 -10
  225. package/dist/tasks/source/task-source-v3-frozen.js +3 -4
  226. package/dist/tasks/source/task-to-v4.js +2 -2
  227. package/dist/workflows/authoring/authoring.js +3 -12
  228. package/dist/workflows/compile.js +211 -0
  229. package/dist/workflows/concurrency-policy.js +13 -74
  230. package/dist/workflows/exec/child-invocation.js +3 -17
  231. package/dist/workflows/exec/child-workflow.js +32 -141
  232. package/dist/workflows/exec/dispatch-redaction.js +13 -53
  233. package/dist/workflows/exec/environment.js +98 -0
  234. package/dist/workflows/exec/exec-unit.js +33 -140
  235. package/dist/workflows/exec/frozen-judge.js +7 -59
  236. package/dist/workflows/exec/native-executor.js +82 -341
  237. package/dist/workflows/exec/param-secrets.js +29 -47
  238. package/dist/workflows/exec/run-workflow.js +154 -387
  239. package/dist/workflows/exec/scheduler.js +9 -36
  240. package/dist/workflows/exec/step-work.js +127 -430
  241. package/dist/workflows/exec/unit-dispatch.js +11 -63
  242. package/dist/workflows/exec/unit-writer.js +8 -52
  243. package/dist/workflows/exec/worktree.js +39 -273
  244. package/dist/workflows/freeze/child-output-references.js +4 -15
  245. package/dist/workflows/freeze/environment.js +99 -92
  246. package/dist/workflows/freeze/freeze.js +172 -0
  247. package/dist/workflows/freeze/step-values.js +19 -21
  248. package/dist/workflows/freeze/targets/child-workflow.js +23 -92
  249. package/dist/workflows/freeze/targets/command.js +10 -33
  250. package/dist/workflows/freeze/targets/script.js +5 -12
  251. package/dist/workflows/freeze/targets/shell.js +3 -6
  252. package/dist/workflows/freeze/targets/task.js +25 -80
  253. package/dist/workflows/freeze/task-bindings.js +20 -67
  254. package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
  255. package/dist/workflows/ir/params.js +6 -51
  256. package/dist/workflows/ir/plan-hash.js +2 -34
  257. package/dist/workflows/parser.js +140 -43
  258. package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
  259. package/dist/workflows/renderer.js +36 -69
  260. package/dist/workflows/resource-limits.js +12 -120
  261. package/dist/workflows/runtime/agent-identity.js +8 -40
  262. package/dist/workflows/runtime/run-outputs.js +3 -6
  263. package/dist/workflows/runtime/run-plan.js +316 -0
  264. package/dist/workflows/runtime/runs.js +48 -200
  265. package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
  266. package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
  267. package/dist/workflows/validate-summary.js +2 -7
  268. package/docs/integration/bundling-akm.md +49 -42
  269. package/docs/migration/README.md +1 -0
  270. package/docs/migration/release-notes/0.9.17.md +41 -0
  271. package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
  272. package/docs/reference/cli.md +182 -125
  273. package/docs/reference/configuration.md +49 -56
  274. package/docs/reference/data-and-telemetry.md +19 -20
  275. package/docs/reference/tasks.md +86 -38
  276. package/docs/reference/workflow-schema.md +14 -18
  277. package/docs/reference/workflows.md +6 -9
  278. package/package.json +1 -1
  279. package/schemas/akm-config.json +87 -406
  280. package/dist/commands/health/advisories.js +0 -150
  281. package/dist/commands/health/metrics.js +0 -329
  282. package/dist/commands/health/surfaces.js +0 -102
  283. package/dist/commands/improve/anti-collapse.js +0 -83
  284. package/dist/commands/improve/collapse-detector.js +0 -432
  285. package/dist/commands/improve/consolidate/eligibility.js +0 -48
  286. package/dist/commands/improve/consolidate/merge.js +0 -146
  287. package/dist/commands/improve/distill/promote-memory.js +0 -329
  288. package/dist/commands/improve/distill/quality-gate.js +0 -500
  289. package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
  290. package/dist/commands/improve/proposal-envelope.js +0 -31
  291. package/dist/commands/improve/run-context.js +0 -123
  292. package/dist/commands/improve/shared.js +0 -21
  293. package/dist/commands/improve/source-identity.js +0 -28
  294. package/dist/commands/improve/triage.js +0 -96
  295. package/dist/commands/proposal/drain-policies.js +0 -151
  296. package/dist/commands/sources/update-transaction.js +0 -220
  297. package/dist/core/action-contributors.js +0 -28
  298. package/dist/core/config/config-version-shim.js +0 -101
  299. package/dist/core/config/retired-experimental-keys-shim.js +0 -62
  300. package/dist/core/fs-txn.js +0 -405
  301. package/dist/core/lexical-score.js +0 -25
  302. package/dist/core/maintenance-barrier.js +0 -167
  303. package/dist/execution/executable-identity.js +0 -105
  304. package/dist/execution/guarded-source.js +0 -427
  305. package/dist/indexer/graph/graph-boost.js +0 -427
  306. package/dist/indexer/graph/graph-dedup.js +0 -95
  307. package/dist/indexer/search/name-match.js +0 -35
  308. package/dist/indexer/search/ranking-contributors.js +0 -515
  309. package/dist/indexer/walk/project-context.js +0 -192
  310. package/dist/integrations/agent/execution-cascade.js +0 -566
  311. package/dist/integrations/agent/execution-definitions.js +0 -202
  312. package/dist/integrations/agent/execution-lowering.js +0 -841
  313. package/dist/integrations/agent/execution-preparation.js +0 -98
  314. package/dist/integrations/agent/inline-execution.js +0 -74
  315. package/dist/registry/create-provider-registry.js +0 -29
  316. package/dist/registry/pinned-request-helper.js +0 -247
  317. package/dist/registry/pinned-transport.js +0 -717
  318. package/dist/sources/providers/index.js +0 -14
  319. package/dist/storage/engines/sqlite-migrations.js +0 -271
  320. package/dist/storage/repositories/canaries-repository.js +0 -107
  321. package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
  322. package/dist/storage/repositories/registry-cache.js +0 -113
  323. package/dist/tasks/scheduler-sync-preview.js +0 -52
  324. package/dist/workflows/freeze/resolve-steps.js +0 -86
  325. package/dist/workflows/freeze/source-freeze.js +0 -64
  326. package/dist/workflows/ir/compile.js +0 -321
  327. package/dist/workflows/ir/environment-v4.js +0 -330
  328. package/dist/workflows/ir/freeze-v4.js +0 -153
  329. package/dist/workflows/ir/schema-v4.js +0 -745
  330. package/dist/workflows/ir/schema.js +0 -354
  331. package/dist/workflows/program/schema.js +0 -78
  332. package/dist/workflows/runtime/checkin.js +0 -57
  333. package/dist/workflows/runtime/plan-classifier.js +0 -196
  334. package/dist/workflows/runtime/unit-checkin.js +0 -45
  335. package/dist/workflows/runtime/unit-phases.js +0 -20
  336. package/dist/workflows/schema.js +0 -4
  337. package/dist/workflows/source-ir/compile.js +0 -200
  338. package/dist/workflows/source-ir/program.js +0 -50
  339. package/dist/workflows/source-ir/result.js +0 -26
  340. package/dist/workflows/source-ir/schema.js +0 -786
  341. package/dist/workflows/source-ir/triggers.js +0 -79
  342. package/dist/workflows/source-ir/uses.js +0 -40
  343. 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
  }