@event4u/agent-config 8.4.0 → 8.5.0

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 (682) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +73 -0
  3. package/README.md +17 -5
  4. package/dist/agent-src/README.md +1 -1
  5. package/dist/agent-src/commands/{analyze-reference-repo.md → analyze/reference-repo.md} +3 -1
  6. package/dist/agent-src/commands/analyze.md +9 -6
  7. package/dist/agent-src/commands/{bug-fix.md → bug/fix.md} +3 -1
  8. package/dist/agent-src/commands/{bug-investigate.md → bug/investigate.md} +4 -2
  9. package/dist/agent-src/commands/bug.md +59 -0
  10. package/dist/agent-src/commands/{set-cost-profile.md → cost/profile.md} +9 -6
  11. package/dist/agent-src/commands/{cost-report.md → cost/report.md} +18 -17
  12. package/dist/agent-src/commands/cost.md +57 -0
  13. package/dist/agent-src/commands/evals/{review-changes.json → review.json} +12 -8
  14. package/dist/agent-src/commands/{quality-fix.md → fix/quality.md} +5 -2
  15. package/dist/agent-src/commands/fix.md +7 -4
  16. package/dist/agent-src/commands/optimize/project.md +250 -0
  17. package/dist/agent-src/commands/{optimize-prompt.md → optimize/prompt.md} +3 -2
  18. package/dist/agent-src/commands/optimize.md +17 -12
  19. package/dist/agent-src/commands/{package-reset.md → package/reset.md} +2 -0
  20. package/dist/agent-src/commands/{package-test.md → package/test.md} +3 -1
  21. package/dist/agent-src/commands/package.md +56 -0
  22. package/dist/agent-src/commands/{project-analyze.md → project/analyze.md} +10 -8
  23. package/dist/agent-src/commands/{project-health.md → project/health.md} +2 -0
  24. package/dist/agent-src/commands/project.md +60 -0
  25. package/dist/agent-src/commands/{review-changes.md → review/changes.md} +26 -24
  26. package/dist/agent-src/commands/{review-routing.md → review/routing.md} +21 -17
  27. package/dist/agent-src/commands/review.md +61 -0
  28. package/dist/agent-src/commands/security-audit-config.md +24 -23
  29. package/dist/agent-src/commands/{sync-agent-settings.md → sync/agent-settings.md} +11 -7
  30. package/dist/agent-src/commands/{sync-gitignore → sync/gitignore}/fix.md +36 -27
  31. package/dist/agent-src/commands/{sync-gitignore.md → sync/gitignore.md} +22 -21
  32. package/dist/agent-src/commands/sync.md +58 -0
  33. package/dist/agent-src/commands/{e2e-heal.md → tests/e2e-heal.md} +5 -2
  34. package/dist/agent-src/commands/{e2e-plan.md → tests/e2e-plan.md} +5 -2
  35. package/dist/agent-src/commands/tests.md +11 -5
  36. package/dist/agent-src/contexts/augment-infrastructure.md +3 -3
  37. package/dist/agent-src/contexts/execution/toolchain-resolver.md +1 -1
  38. package/dist/agent-src/contexts/skills-and-commands.md +2 -2
  39. package/dist/agent-src/rules/external-reference-deep-dive.md +1 -1
  40. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
  41. package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +1 -1
  42. package/dist/agent-src/skills/judge-bug-hunter/SKILL.md +1 -1
  43. package/dist/agent-src/skills/judge-code-quality/SKILL.md +1 -1
  44. package/dist/agent-src/skills/judge-security-auditor/SKILL.md +1 -1
  45. package/dist/agent-src/skills/judge-synthesis/SKILL.md +1 -1
  46. package/dist/agent-src/skills/judge-test-coverage/SKILL.md +1 -1
  47. package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
  48. package/dist/agent-src/skills/mobile-e2e-strategy/SKILL.md +5 -5
  49. package/dist/agent-src/skills/prompt-optimizer/SKILL.md +2 -2
  50. package/dist/agent-src/skills/quality-tools/SKILL.md +1 -1
  51. package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
  52. package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
  53. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
  54. package/dist/agent-src/templates/agent-settings.md +1 -1
  55. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +2 -2
  56. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +1 -1
  57. package/dist/cli/commands/config.js +44 -0
  58. package/dist/cli/commands/config.js.map +1 -0
  59. package/dist/cli/commands/uiServe.js +1 -0
  60. package/dist/cli/commands/uiServe.js.map +1 -1
  61. package/dist/cli/help.js +38 -0
  62. package/dist/cli/help.js.map +1 -0
  63. package/dist/cli/initRouting.js +16 -1
  64. package/dist/cli/initRouting.js.map +1 -1
  65. package/dist/cli/main.js +43 -37
  66. package/dist/cli/main.js.map +1 -1
  67. package/dist/cli/registry.js +45 -44
  68. package/dist/cli/registry.js.map +1 -1
  69. package/dist/discovery/deprecation-report.md +1 -1
  70. package/dist/discovery/discovery-manifest.json +419 -210
  71. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  72. package/dist/discovery/discovery-manifest.summary.md +4 -4
  73. package/dist/discovery/orphan-report.md +1 -1
  74. package/dist/discovery/packs.json +31 -25
  75. package/dist/discovery/trust-report.md +2 -2
  76. package/dist/discovery/workspaces.json +30 -24
  77. package/dist/install/install.mjs +6064 -159
  78. package/dist/install/selectedTools.js +39 -10
  79. package/dist/install/selectedTools.js.map +1 -1
  80. package/dist/mcp/registry-manifest.json +3 -3
  81. package/dist/server/app.js +15 -3
  82. package/dist/server/app.js.map +1 -1
  83. package/dist/server/routes/ping.js +16 -0
  84. package/dist/server/routes/ping.js.map +1 -1
  85. package/dist/server/routes/settings.js +42 -6
  86. package/dist/server/routes/settings.js.map +1 -1
  87. package/dist/server/routes/settingsChanges.js +55 -0
  88. package/dist/server/routes/settingsChanges.js.map +1 -0
  89. package/dist/server/routes/userMd.js +7 -2
  90. package/dist/server/routes/userMd.js.map +1 -1
  91. package/dist/server/routes/wizard.js +76 -14
  92. package/dist/server/routes/wizard.js.map +1 -1
  93. package/dist/server/writeRoot.js +17 -0
  94. package/dist/server/writeRoot.js.map +1 -1
  95. package/dist/shared/settingsSurface.js +120 -0
  96. package/dist/shared/settingsSurface.js.map +1 -0
  97. package/dist/ui/assets/index-BPFMZWUs.css +1 -0
  98. package/dist/ui/assets/index-BiEZiZ31.js +40 -0
  99. package/dist/ui/assets/index-BiEZiZ31.js.map +1 -0
  100. package/dist/ui/index.html +15 -2
  101. package/docs/CLAIMS.md +20 -15
  102. package/docs/architecture.md +1 -1
  103. package/docs/catalog.md +37 -31
  104. package/docs/command-flows.md +22 -16
  105. package/docs/contracts/command-clusters.md +39 -9
  106. package/docs/contracts/file-ownership-matrix.json +21 -0
  107. package/docs/contracts/frontmatter-contract.md +1 -1
  108. package/docs/contracts/gui-wizard.md +16 -4
  109. package/docs/contracts/iron-law-overrides.txt +1 -0
  110. package/docs/contracts/rule-classification.md +2 -2
  111. package/docs/contracts/settings-api.md +58 -2
  112. package/docs/contracts/surface-matrix.md +5 -0
  113. package/docs/cookbook.md +7 -7
  114. package/docs/decisions/ADR-114-commit-policy-iron-law-override.md +74 -0
  115. package/docs/decisions/ADR-115-command-cluster-consolidation-phase-4.md +91 -0
  116. package/docs/decisions/INDEX.md +2 -0
  117. package/docs/featured-commands.md +1 -1
  118. package/docs/featured-skills.md +4 -4
  119. package/docs/flows.md +2 -2
  120. package/docs/getting-started-by-role.md +1 -1
  121. package/docs/getting-started-laravel.md +1 -1
  122. package/docs/getting-started.md +6 -3
  123. package/docs/governance-advantage.md +1 -1
  124. package/docs/guidelines/agent-infra/5w2h-analysis.md +1 -1
  125. package/docs/guidelines/agent-infra/ios-simulator-guide.md +1 -1
  126. package/docs/proof.md +11 -2
  127. package/package.json +6 -1
  128. package/src/agent-src/README.md +64 -0
  129. package/src/agent-src/scripts/archive_completed_roadmaps.ts +497 -0
  130. package/src/agent-src/scripts/scan-seeder-violations.php +145 -0
  131. package/src/agent-src/scripts/update_roadmap_progress.ts +1087 -0
  132. package/src/agent-src/templates/AGENTS.md +34 -0
  133. package/src/agent-src/templates/scripts/README.md +195 -0
  134. package/src/agent-src/templates/scripts/check_memory.ts +662 -0
  135. package/src/agent-src/templates/scripts/check_memory_proposal.ts +370 -0
  136. package/src/agent-src/templates/scripts/historical-bug-patterns.example.yml +84 -0
  137. package/src/agent-src/templates/scripts/implement_ticket/__main__.ts +27 -0
  138. package/src/agent-src/templates/scripts/memory_hash.ts +355 -0
  139. package/src/agent-src/templates/scripts/memory_lookup.ts +1089 -0
  140. package/src/agent-src/templates/scripts/memory_report.ts +868 -0
  141. package/src/agent-src/templates/scripts/memory_signal.ts +444 -0
  142. package/src/agent-src/templates/scripts/memory_status.ts +215 -0
  143. package/src/agent-src/templates/scripts/ownership-map.example.yml +87 -0
  144. package/src/agent-src/templates/scripts/pr-risk-config.example.yml +76 -0
  145. package/src/agent-src/templates/scripts/pr_review_routing.ts +544 -0
  146. package/src/agent-src/templates/scripts/pr_risk_review.ts +0 -0
  147. package/src/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
  148. package/src/agent-src/templates/scripts/telemetry/boundary.ts +164 -0
  149. package/src/agent-src/templates/scripts/telemetry/engagement.ts +479 -0
  150. package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +394 -0
  151. package/src/agent-src/templates/scripts/telemetry/settings.ts +210 -0
  152. package/src/agent-src/templates/scripts/telemetry_record.ts +276 -0
  153. package/src/agent-src/templates/scripts/telemetry_report.ts +211 -0
  154. package/src/agent-src/templates/scripts/telemetry_status.ts +333 -0
  155. package/src/agent-src/templates/scripts/tier_usage_report.ts +619 -0
  156. package/src/agent-src/templates/scripts/work_engine/__main__.ts +14 -0
  157. package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +1261 -0
  158. package/src/agent-src/templates/scripts/work_engine/_lib/user_global_paths.ts +329 -0
  159. package/src/agent-src/templates/scripts/work_engine/cli.ts +206 -0
  160. package/src/agent-src/templates/scripts/work_engine/cli_args.ts +249 -0
  161. package/src/agent-src/templates/scripts/work_engine/delivery_state.ts +225 -0
  162. package/src/agent-src/templates/scripts/work_engine/directives/backend/analyze.ts +125 -0
  163. package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +189 -0
  164. package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +94 -0
  165. package/src/agent-src/templates/scripts/work_engine/directives/backend/memory.ts +193 -0
  166. package/src/agent-src/templates/scripts/work_engine/directives/backend/plan.ts +267 -0
  167. package/src/agent-src/templates/scripts/work_engine/directives/backend/refine.ts +518 -0
  168. package/src/agent-src/templates/scripts/work_engine/directives/backend/report.ts +379 -0
  169. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +268 -0
  170. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +258 -0
  171. package/src/agent-src/templates/scripts/work_engine/directives/index.ts +32 -0
  172. package/src/agent-src/templates/scripts/work_engine/directives/mixed/contract.ts +243 -0
  173. package/src/agent-src/templates/scripts/work_engine/directives/mixed/index.ts +108 -0
  174. package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +259 -0
  175. package/src/agent-src/templates/scripts/work_engine/directives/mixed/ui.ts +216 -0
  176. package/src/agent-src/templates/scripts/work_engine/directives/ui/_passthrough.ts +40 -0
  177. package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +241 -0
  178. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +216 -0
  179. package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +506 -0
  180. package/src/agent-src/templates/scripts/work_engine/directives/ui/design.ts +325 -0
  181. package/src/agent-src/templates/scripts/work_engine/directives/ui/index.ts +102 -0
  182. package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +462 -0
  183. package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +474 -0
  184. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +352 -0
  185. package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/_skipped.ts +33 -0
  186. package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/apply.ts +213 -0
  187. package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/index.ts +111 -0
  188. package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/refine.ts +126 -0
  189. package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/report.ts +112 -0
  190. package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/test.ts +164 -0
  191. package/src/agent-src/templates/scripts/work_engine/dispatcher.ts +515 -0
  192. package/src/agent-src/templates/scripts/work_engine/emitters.ts +119 -0
  193. package/src/agent-src/templates/scripts/work_engine/errors.ts +24 -0
  194. package/src/agent-src/templates/scripts/work_engine/hook_bootstrap.ts +104 -0
  195. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.ts +189 -0
  196. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.ts +41 -0
  197. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.ts +89 -0
  198. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_gate.ts +193 -0
  199. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +304 -0
  200. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/directive_set_guard.ts +110 -0
  201. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/halt_surface_audit.ts +118 -0
  202. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/index.ts +17 -0
  203. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +161 -0
  204. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/state_shape_validation.ts +45 -0
  205. package/src/agent-src/templates/scripts/work_engine/hooks/builtin/trace.ts +134 -0
  206. package/src/agent-src/templates/scripts/work_engine/hooks/context.ts +94 -0
  207. package/src/agent-src/templates/scripts/work_engine/hooks/events.ts +58 -0
  208. package/src/agent-src/templates/scripts/work_engine/hooks/exceptions.ts +85 -0
  209. package/src/agent-src/templates/scripts/work_engine/hooks/index.ts +27 -0
  210. package/src/agent-src/templates/scripts/work_engine/hooks/registry.ts +66 -0
  211. package/src/agent-src/templates/scripts/work_engine/hooks/runner.ts +90 -0
  212. package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +260 -0
  213. package/src/agent-src/templates/scripts/work_engine/input_builders.ts +260 -0
  214. package/src/agent-src/templates/scripts/work_engine/intent/classify.ts +466 -0
  215. package/src/agent-src/templates/scripts/work_engine/migration/v0_to_v1.ts +531 -0
  216. package/src/agent-src/templates/scripts/work_engine/orchestration.ts +366 -0
  217. package/src/agent-src/templates/scripts/work_engine/persona_policy.ts +97 -0
  218. package/src/agent-src/templates/scripts/work_engine/resolvers/diff.ts +135 -0
  219. package/src/agent-src/templates/scripts/work_engine/resolvers/file.ts +175 -0
  220. package/src/agent-src/templates/scripts/work_engine/resolvers/prompt.ts +115 -0
  221. package/src/agent-src/templates/scripts/work_engine/scoring/confidence.ts +415 -0
  222. package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +466 -0
  223. package/src/agent-src/templates/scripts/work_engine/scoring/decision_trace.ts +298 -0
  224. package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +444 -0
  225. package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +252 -0
  226. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +745 -0
  227. package/src/agent-src/templates/scripts/work_engine/state.ts +1151 -0
  228. package/src/agent-src/templates/scripts/work_engine/state_io.ts +413 -0
  229. package/src/config/agent-settings.template.yml +1 -1
  230. package/src/install/atomic.ts +111 -0
  231. package/src/install/conflict.ts +226 -0
  232. package/src/install/detect.ts +280 -0
  233. package/src/install/paths.ts +90 -0
  234. package/src/install/plan.ts +205 -0
  235. package/src/install/preflight.ts +210 -0
  236. package/src/install/selectedTools.ts +80 -0
  237. package/src/install/toolDetection.ts +120 -0
  238. package/src/install/txlog.ts +161 -0
  239. package/src/install/types.ts +175 -0
  240. package/src/install/wizard-plan.ts +216 -0
  241. package/src/scripts/_cli/cmd_converge.ts +38 -0
  242. package/src/scripts/_cli/cmd_doctor.ts +113 -2
  243. package/src/scripts/_cli/cmd_explain.ts +2 -2
  244. package/src/scripts/_cli/cmd_export.ts +3 -3
  245. package/src/scripts/_cli/cmd_fleet.ts +13 -1
  246. package/src/scripts/_cli/cmd_migrate.ts +3 -3
  247. package/src/scripts/_cli/cmd_prune.ts +2 -2
  248. package/src/scripts/_cli/cmd_refresh.ts +4 -4
  249. package/src/scripts/_cli/cmd_settings_check.ts +2 -2
  250. package/src/scripts/_cli/cmd_settings_migrate.ts +2 -2
  251. package/src/scripts/_cli/cmd_sync.ts +2 -2
  252. package/src/scripts/_cli/cmd_uninstall.ts +2 -2
  253. package/src/scripts/_cli/cmd_update.ts +8 -8
  254. package/src/scripts/_cli/cmd_upgrade.ts +4 -3
  255. package/src/scripts/_cli/cmd_validate.ts +3 -3
  256. package/src/scripts/_cli/cmd_versions.ts +2 -2
  257. package/src/scripts/_cli/explain_last/assumptions.ts +2 -2
  258. package/src/scripts/_cli/explain_last/council.ts +2 -2
  259. package/src/scripts/_cli/explain_last/halt.ts +2 -2
  260. package/src/scripts/_cli/explain_last/index.ts +2 -2
  261. package/src/scripts/_cli/explain_last/inputs.ts +4 -4
  262. package/src/scripts/_cli/explain_last/memory.ts +2 -2
  263. package/src/scripts/_cli/explain_last/provider.ts +2 -2
  264. package/src/scripts/_cli/explain_last/render.ts +2 -2
  265. package/src/scripts/_cli/explain_last/route.ts +2 -2
  266. package/src/scripts/_cli/explain_last/scrubber.ts +2 -2
  267. package/src/scripts/_cli/explain_last/sections/assumptions.ts +2 -2
  268. package/src/scripts/_cli/explain_last/sections/council.ts +2 -2
  269. package/src/scripts/_cli/explain_last/sections/halt.ts +2 -2
  270. package/src/scripts/_cli/explain_last/sections/header.ts +2 -2
  271. package/src/scripts/_cli/explain_last/sections/index.ts +1 -1
  272. package/src/scripts/_cli/explain_last/sections/inputs.ts +2 -2
  273. package/src/scripts/_cli/explain_last/sections/memory.ts +2 -2
  274. package/src/scripts/_cli/explain_last/sections/pack.ts +2 -2
  275. package/src/scripts/_cli/explain_last/sections/provider.ts +2 -2
  276. package/src/scripts/_cli/explain_last/sections/route.ts +2 -2
  277. package/src/scripts/_cli/explain_last/state_loader.ts +2 -2
  278. package/src/scripts/_dispatch.bash +20 -1
  279. package/src/scripts/_lib/agent_settings.ts +1 -1
  280. package/src/scripts/_lib/agent_src.ts +7 -7
  281. package/src/scripts/_lib/agents_overlay.ts +1 -1
  282. package/src/scripts/_lib/bench_ab_cache.ts +1 -1
  283. package/src/scripts/_lib/bench_ab_scoring.ts +1 -1
  284. package/src/scripts/_lib/bench_ab_scoring_v2.ts +3 -3
  285. package/src/scripts/_lib/bench_cost.ts +1 -1
  286. package/src/scripts/_lib/bench_quality.ts +3 -3
  287. package/src/scripts/_lib/bench_report.ts +4 -4
  288. package/src/scripts/_lib/bench_telegraph.ts +1 -1
  289. package/src/scripts/_lib/bench_telegraph_report.ts +4 -4
  290. package/src/scripts/_lib/changelog_eras.ts +1 -1
  291. package/src/scripts/_lib/claude_desktop_bundler.ts +1 -1
  292. package/src/scripts/_lib/cli_wrapper.ts +1 -1
  293. package/src/scripts/_lib/fs_atomic.ts +1 -1
  294. package/src/scripts/_lib/global_deploy_inventory.ts +1 -1
  295. package/src/scripts/_lib/install_layout.ts +1 -1
  296. package/src/scripts/_lib/install_regenerator.ts +1 -1
  297. package/src/scripts/_lib/installed_lock.ts +1 -1
  298. package/src/scripts/_lib/installed_tools.ts +1 -1
  299. package/src/scripts/_lib/json_pointers.ts +1 -1
  300. package/src/scripts/_lib/knowledge_global.ts +1 -1
  301. package/src/scripts/_lib/knowledge_global_promote.ts +2 -2
  302. package/src/scripts/_lib/knowledge_global_redaction.ts +2 -2
  303. package/src/scripts/_lib/link_crypto.ts +4 -4
  304. package/src/scripts/_lib/linked_projects.ts +4 -4
  305. package/src/scripts/_lib/model_tier.ts +1 -1
  306. package/src/scripts/_lib/module_detection.ts +2 -2
  307. package/src/scripts/_lib/pin_resolver.ts +1 -1
  308. package/src/scripts/_lib/script_output.ts +1 -1
  309. package/src/scripts/_lib/security_lint.ts +1 -1
  310. package/src/scripts/_lib/surface_tiers.ts +1 -1
  311. package/src/scripts/_lib/text_similarity.ts +1 -1
  312. package/src/scripts/_lib/update_check.ts +2 -2
  313. package/src/scripts/_lib/user_global_paths.ts +1 -1
  314. package/src/scripts/_lib/value_ladder.ts +1 -1
  315. package/src/scripts/_lib/value_report.ts +1 -1
  316. package/src/scripts/_lib/zip_min.ts +2 -2
  317. package/src/scripts/adoption_report.ts +3 -3
  318. package/src/scripts/adoption_snapshot.ts +3 -3
  319. package/src/scripts/adoption_status.ts +2 -2
  320. package/src/scripts/adr/regenerate_index.ts +3 -3
  321. package/src/scripts/ai_council/_default_prices.ts +2 -3
  322. package/src/scripts/ai_council/advisors.ts +1 -1
  323. package/src/scripts/ai_council/airgap.ts +1 -1
  324. package/src/scripts/ai_council/budget_guard.ts +1 -1
  325. package/src/scripts/ai_council/bundler.ts +1 -1
  326. package/src/scripts/ai_council/cli_hints.ts +1 -1
  327. package/src/scripts/ai_council/clients.ts +5 -5
  328. package/src/scripts/ai_council/compile_corpus.ts +1 -1
  329. package/src/scripts/ai_council/confidence_gate.ts +1 -1
  330. package/src/scripts/ai_council/config.ts +1 -1
  331. package/src/scripts/ai_council/consensus.ts +1 -1
  332. package/src/scripts/ai_council/events_log.ts +1 -1
  333. package/src/scripts/ai_council/learn_low_impact_preview.ts +1 -1
  334. package/src/scripts/ai_council/low_impact_corpus.ts +1 -1
  335. package/src/scripts/ai_council/low_impact_intake.ts +1 -1
  336. package/src/scripts/ai_council/modes.ts +1 -1
  337. package/src/scripts/ai_council/orchestrator.ts +3 -3
  338. package/src/scripts/ai_council/pricing.ts +2 -2
  339. package/src/scripts/ai_council/probation_gate.ts +2 -2
  340. package/src/scripts/ai_council/project_context.ts +1 -1
  341. package/src/scripts/ai_council/prompts.ts +1 -1
  342. package/src/scripts/ai_council/redact_low_impact_entry.ts +2 -2
  343. package/src/scripts/ai_council/session.ts +1 -1
  344. package/src/scripts/ai_council/shadow_dispatch.ts +1 -1
  345. package/src/scripts/ai_council/solo_dispatch.ts +1 -1
  346. package/src/scripts/analysis_freshness.ts +2 -2
  347. package/src/scripts/annotate_discovery.ts +2 -2
  348. package/src/scripts/apply_modules_config.ts +2 -2
  349. package/src/scripts/audit_adr_coverage.ts +3 -3
  350. package/src/scripts/audit_auto_rules.ts +2 -2
  351. package/src/scripts/audit_cloud_compatibility.ts +3 -3
  352. package/src/scripts/audit_command_surface.ts +2 -2
  353. package/src/scripts/audit_initial_context.ts +7 -6
  354. package/src/scripts/audit_likelihood.ts +5 -5
  355. package/src/scripts/audit_mcp_tools.ts +3 -3
  356. package/src/scripts/audit_overlap.ts +2 -2
  357. package/src/scripts/audit_skill_descriptions.ts +2 -2
  358. package/src/scripts/audit_skill_overlap.ts +5 -5
  359. package/src/scripts/audit_user_type_axis.ts +4 -4
  360. package/src/scripts/backfill_model_tier.ts +1 -1
  361. package/src/scripts/bench_ab_cache_dispatch.ts +2 -2
  362. package/src/scripts/bench_ab_clone.ts +2 -2
  363. package/src/scripts/bench_ab_diff.ts +3 -3
  364. package/src/scripts/bench_ab_integrity.ts +2 -2
  365. package/src/scripts/bench_ab_run.ts +4 -4
  366. package/src/scripts/bench_ab_task_runner.ts +1 -1
  367. package/src/scripts/bench_ab_tracka_run.ts +2 -2
  368. package/src/scripts/bench_ab_v2_run.ts +1 -1
  369. package/src/scripts/bench_ab_v2_stats.ts +2 -2
  370. package/src/scripts/bench_baseline_ready.ts +1 -1
  371. package/src/scripts/bench_condense_memory.ts +4 -4
  372. package/src/scripts/bench_drift_check.ts +3 -3
  373. package/src/scripts/bench_per_tool.ts +1 -1
  374. package/src/scripts/bench_rtk_savings.ts +4 -4
  375. package/src/scripts/bench_run.ts +4 -4
  376. package/src/scripts/bench_runner.ts +1 -1
  377. package/src/scripts/build_cloud_bundle.ts +3 -3
  378. package/src/scripts/build_discovery_manifest.ts +13 -15
  379. package/src/scripts/build_linear_digest.ts +2 -2
  380. package/src/scripts/build_mcp_registry_manifest.ts +3 -3
  381. package/src/scripts/build_proof.ts +6 -0
  382. package/src/scripts/build_rule_trigger_matrix.ts +2 -2
  383. package/src/scripts/capture_showcase_session.ts +3 -3
  384. package/src/scripts/chat_history.ts +1 -1
  385. package/src/scripts/check_always_budget.ts +1 -1
  386. package/src/scripts/check_artefact_checksums.ts +4 -4
  387. package/src/scripts/check_artefact_count_messaging.ts +197 -0
  388. package/src/scripts/check_augment_description_cap.ts +3 -3
  389. package/src/scripts/check_augmentignore.ts +1 -1
  390. package/src/scripts/check_beta_review_markers.ts +3 -3
  391. package/src/scripts/check_bite_sized_granularity.ts +1 -1
  392. package/src/scripts/check_cluster_patterns.ts +47 -3
  393. package/src/scripts/check_command_count_messaging.ts +2 -2
  394. package/src/scripts/check_condensation.ts +2 -2
  395. package/src/scripts/check_condensed_paths.ts +6 -6
  396. package/src/scripts/check_context_paths.ts +1 -1
  397. package/src/scripts/check_council_config_location.ts +3 -3
  398. package/src/scripts/check_council_layout.ts +2 -2
  399. package/src/scripts/check_council_references.ts +2 -2
  400. package/src/scripts/check_discovery_determinism.ts +3 -3
  401. package/src/scripts/check_gate_paths.ts +4 -4
  402. package/src/scripts/check_iron_law_prominence.ts +2 -2
  403. package/src/scripts/check_kernel_rule_bundle.ts +3 -3
  404. package/src/scripts/check_knowledge_cards.ts +4 -4
  405. package/src/scripts/check_knowledge_pages.ts +1 -1
  406. package/src/scripts/check_md_language.ts +3 -3
  407. package/src/scripts/check_memory.ts +3 -3
  408. package/src/scripts/check_memory_proposal.ts +2 -2
  409. package/src/scripts/check_module_management_neutral.ts +1 -1
  410. package/src/scripts/check_no_conflict_markers.ts +1 -1
  411. package/src/scripts/check_no_external_sources.ts +1 -1
  412. package/src/scripts/check_no_local_settings_committed.ts +2 -2
  413. package/src/scripts/check_no_new_legacy_path.ts +3 -3
  414. package/src/scripts/check_no_roadmap_refs.ts +3 -3
  415. package/src/scripts/check_one_off_location.ts +3 -3
  416. package/src/scripts/check_overlay_cascade_subdirs.ts +3 -3
  417. package/src/scripts/check_portability.ts +3 -3
  418. package/src/scripts/check_proposal.ts +0 -0
  419. package/src/scripts/check_public_catalog_links.ts +1 -1
  420. package/src/scripts/check_public_links.ts +2 -2
  421. package/src/scripts/check_references.ts +3 -3
  422. package/src/scripts/check_release_includes_discovery.ts +2 -2
  423. package/src/scripts/check_release_pr_shape.ts +2 -2
  424. package/src/scripts/check_release_published.ts +1 -1
  425. package/src/scripts/check_release_trunk_sync.ts +3 -3
  426. package/src/scripts/check_reply_consistency.ts +1 -1
  427. package/src/scripts/check_roadmap_trackable.ts +2 -2
  428. package/src/scripts/check_role_doc_links.ts +2 -2
  429. package/src/scripts/check_safety_floor_untouched.ts +3 -3
  430. package/src/scripts/check_skill_requires.ts +2 -2
  431. package/src/scripts/check_structural_breaking.ts +2 -2
  432. package/src/scripts/check_surface_tiers.ts +2 -2
  433. package/src/scripts/check_template_pin_drift.ts +1 -1
  434. package/src/scripts/check_test_coverage_diff.ts +2 -2
  435. package/src/scripts/check_token_optimizer_freshness.ts +3 -3
  436. package/src/scripts/check_trigger_evals.ts +2 -2
  437. package/src/scripts/check_update_banner.ts +1 -1
  438. package/src/scripts/ci_status.ts +0 -0
  439. package/src/scripts/ci_summary.ts +3 -3
  440. package/src/scripts/ci_time_ratio.ts +1 -1
  441. package/src/scripts/command_suggester/cooldown.ts +1 -1
  442. package/src/scripts/command_suggester/index.ts +1 -1
  443. package/src/scripts/command_suggester/loader.ts +1 -1
  444. package/src/scripts/command_suggester/match.ts +1 -1
  445. package/src/scripts/command_suggester/rank.ts +1 -1
  446. package/src/scripts/command_suggester/render.ts +1 -1
  447. package/src/scripts/command_suggester/sanitize.ts +1 -1
  448. package/src/scripts/command_suggester/settings.ts +1 -1
  449. package/src/scripts/command_suggester/types.ts +0 -0
  450. package/src/scripts/compile_router.ts +4 -4
  451. package/src/scripts/condense.ts +3 -3
  452. package/src/scripts/condense_memory.ts +1 -1
  453. package/src/scripts/config/index.ts +1 -1
  454. package/src/scripts/config/packs.ts +1 -1
  455. package/src/scripts/config/presets.ts +1 -1
  456. package/src/scripts/config/profile_explain.ts +1 -1
  457. package/src/scripts/config/profiles.ts +1 -1
  458. package/src/scripts/config/session_profiles.ts +1 -1
  459. package/src/scripts/context_hygiene_hook.ts +2 -2
  460. package/src/scripts/cost_by_conversation.ts +1 -1
  461. package/src/scripts/cost_summary.ts +2 -2
  462. package/src/scripts/council_cli.ts +1 -1
  463. package/src/scripts/council_prune.ts +1 -1
  464. package/src/scripts/cross_repo_retrieve.ts +2 -2
  465. package/src/scripts/discovery_stats.ts +3 -3
  466. package/src/scripts/evidence_report.ts +4 -4
  467. package/src/scripts/extract_audit_patterns.ts +2 -2
  468. package/src/scripts/first_run_gate_hook.ts +1 -1
  469. package/src/scripts/gen_discovery_baseline.ts +2 -2
  470. package/src/scripts/generate_capabilities_index.ts +2 -2
  471. package/src/scripts/generate_capability_matrix.ts +2 -2
  472. package/src/scripts/generate_catalog.ts +2 -2
  473. package/src/scripts/generate_command_flows.ts +2 -2
  474. package/src/scripts/generate_cookbook.ts +1 -1
  475. package/src/scripts/generate_index.ts +3 -3
  476. package/src/scripts/generate_ownership_matrix.ts +2 -2
  477. package/src/scripts/generate_pack_manifests.ts +2 -2
  478. package/src/scripts/generate_role_experiences_catalog.ts +3 -3
  479. package/src/scripts/hooks/block_no_verify.ts +2 -2
  480. package/src/scripts/hooks/dispatch_hook.ts +2 -2
  481. package/src/scripts/hooks/dispatch_issues.ts +1 -1
  482. package/src/scripts/hooks/envelope.ts +1 -1
  483. package/src/scripts/hooks/replay_hook.ts +1 -1
  484. package/src/scripts/hooks/state_io.ts +1 -1
  485. package/src/scripts/hooks_doctor.ts +1 -1
  486. package/src/scripts/hooks_status.ts +1 -1
  487. package/src/scripts/injection_scan_hook.ts +1 -1
  488. package/src/scripts/install.ts +145 -3
  489. package/src/scripts/inventory_abstraction_budget.ts +5 -5
  490. package/src/scripts/inventory_frontmatter.ts +1 -1
  491. package/src/scripts/inventory_meta_layers.ts +1 -1
  492. package/src/scripts/iron_law_sha.ts +1 -1
  493. package/src/scripts/knowledge_global_cli.ts +3 -3
  494. package/src/scripts/linked_projects_list.ts +1 -1
  495. package/src/scripts/lint_agent_security.ts +4 -4
  496. package/src/scripts/lint_agent_skill_names.ts +1 -1
  497. package/src/scripts/lint_agents_layout.ts +2 -2
  498. package/src/scripts/lint_agents_md.ts +3 -3
  499. package/src/scripts/lint_archived_skills.ts +2 -2
  500. package/src/scripts/lint_artefact_frontmatter.ts +2 -2
  501. package/src/scripts/lint_bench_ab.ts +2 -2
  502. package/src/scripts/lint_bench_corpus.ts +1 -1
  503. package/src/scripts/lint_command_flow_coverage.ts +1 -1
  504. package/src/scripts/lint_command_routing.ts +2 -2
  505. package/src/scripts/lint_command_tiers.ts +1 -1
  506. package/src/scripts/lint_command_verbs.ts +4 -4
  507. package/src/scripts/lint_commit_subjects.ts +2 -2
  508. package/src/scripts/lint_context_spine_usage.ts +3 -3
  509. package/src/scripts/lint_discovery_manifest.ts +4 -4
  510. package/src/scripts/lint_discovery_vocabulary.ts +2 -2
  511. package/src/scripts/lint_empty_roadmaps.ts +3 -3
  512. package/src/scripts/lint_eval_freshness.ts +2 -2
  513. package/src/scripts/lint_examples.ts +2 -2
  514. package/src/scripts/lint_explain_trace.ts +2 -2
  515. package/src/scripts/lint_featured_skills.ts +0 -0
  516. package/src/scripts/lint_flows.ts +5 -5
  517. package/src/scripts/lint_framework_leakage.ts +1 -1
  518. package/src/scripts/lint_framework_leakage_allowlist.json +10 -2
  519. package/src/scripts/lint_frontmatter_boilerplate.ts +2 -2
  520. package/src/scripts/lint_ghostwriter_source.ts +3 -3
  521. package/src/scripts/lint_global_paths.ts +1 -1
  522. package/src/scripts/lint_handoffs.ts +1 -1
  523. package/src/scripts/lint_hidden_unicode.ts +1 -1
  524. package/src/scripts/lint_hook_concern_budget.ts +2 -2
  525. package/src/scripts/lint_hook_manifest.ts +2 -2
  526. package/src/scripts/lint_instruction_smuggling.ts +1 -1
  527. package/src/scripts/lint_load_context.ts +2 -2
  528. package/src/scripts/lint_marketplace.ts +1 -1
  529. package/src/scripts/lint_marketplace_install_completeness.ts +2 -2
  530. package/src/scripts/lint_mcp_config_security.ts +1 -1
  531. package/src/scripts/lint_mcp_registry_manifest.ts +1 -1
  532. package/src/scripts/lint_media_policy_linkage.ts +3 -3
  533. package/src/scripts/lint_missions.ts +3 -3
  534. package/src/scripts/lint_model_tier_coverage.ts +3 -3
  535. package/src/scripts/lint_namespace.ts +2 -2
  536. package/src/scripts/lint_namespace_collisions.ts +2 -2
  537. package/src/scripts/lint_new_skill_gate.ts +3 -3
  538. package/src/scripts/lint_no_new_atomic_commands.ts +9 -6
  539. package/src/scripts/lint_no_python_twin_rationale.ts +102 -0
  540. package/src/scripts/lint_one_off_age.ts +2 -2
  541. package/src/scripts/lint_orchestration_dsl.ts +3 -3
  542. package/src/scripts/lint_orchestrator_auto_detect.ts +1 -1
  543. package/src/scripts/lint_pack_boundaries.ts +2 -2
  544. package/src/scripts/lint_pack_dependencies.ts +2 -2
  545. package/src/scripts/lint_pack_first_win.ts +2 -2
  546. package/src/scripts/lint_persona_governance.ts +3 -3
  547. package/src/scripts/lint_positioning.ts +1 -1
  548. package/src/scripts/lint_profile_overlay_set_only.ts +2 -2
  549. package/src/scripts/lint_readme_jargon.ts +2 -2
  550. package/src/scripts/lint_readme_size.ts +2 -2
  551. package/src/scripts/lint_regression.ts +3 -3
  552. package/src/scripts/lint_roadmap_ci_steps.ts +3 -3
  553. package/src/scripts/lint_roadmap_complexity.ts +1 -1
  554. package/src/scripts/lint_roadmap_later_disposition.ts +2 -2
  555. package/src/scripts/lint_role_experiences.ts +2 -2
  556. package/src/scripts/lint_rule_interactions.ts +1 -1
  557. package/src/scripts/lint_rule_tiers.ts +1 -1
  558. package/src/scripts/lint_showcase_sessions.ts +2 -2
  559. package/src/scripts/lint_skill_frontmatter_safety.ts +1 -1
  560. package/src/scripts/lint_skill_originality.ts +1 -1
  561. package/src/scripts/lint_skill_tools.ts +3 -3
  562. package/src/scripts/lint_ticket_buildable.ts +2 -2
  563. package/src/scripts/lint_topics_yaml.ts +3 -3
  564. package/src/scripts/lint_trust_coherence.ts +3 -3
  565. package/src/scripts/lint_value_dashboard.ts +3 -3
  566. package/src/scripts/lint_workflow_security.ts +3 -3
  567. package/src/scripts/lint_workspace_boundary.ts +2 -2
  568. package/src/scripts/mcp_parity_smoke.ts +1 -1
  569. package/src/scripts/mcp_render.ts +1 -1
  570. package/src/scripts/mcp_server/catalog.ts +1 -1
  571. package/src/scripts/mcp_server/index.ts +1 -1
  572. package/src/scripts/mcp_server/metadata.ts +1 -1
  573. package/src/scripts/mcp_server/prompts.ts +1 -1
  574. package/src/scripts/mcp_server/resources.ts +1 -1
  575. package/src/scripts/mcp_server/server.ts +1 -1
  576. package/src/scripts/mcp_server/telemetry.ts +1 -1
  577. package/src/scripts/mcp_server/tools.ts +1 -1
  578. package/src/scripts/mcp_telemetry_health.ts +1 -1
  579. package/src/scripts/mcp_telemetry_query.ts +3 -3
  580. package/src/scripts/mcp_telemetry_store.ts +3 -3
  581. package/src/scripts/measure_augment_budget.ts +2 -2
  582. package/src/scripts/measure_density.ts +2 -2
  583. package/src/scripts/measure_frugality_savings.ts +3 -3
  584. package/src/scripts/measure_markitdown_lift.ts +1 -1
  585. package/src/scripts/measure_patterns.ts +1 -1
  586. package/src/scripts/measure_projection_bytes.ts +1 -1
  587. package/src/scripts/measure_rule_budget.ts +1 -1
  588. package/src/scripts/measure_skill_reduction.ts +1 -1
  589. package/src/scripts/memory_hash.ts +1 -1
  590. package/src/scripts/memory_lookup.ts +6 -6
  591. package/src/scripts/memory_report.ts +1 -1
  592. package/src/scripts/memory_signal.ts +1 -1
  593. package/src/scripts/memory_status.ts +2 -2
  594. package/src/scripts/migrate_command_suggestions.ts +1 -1
  595. package/src/scripts/migrate_frontmatter_defaults.ts +1 -1
  596. package/src/scripts/mine_session.ts +3 -3
  597. package/src/scripts/minimal_safe_diff_hook.ts +2 -2
  598. package/src/scripts/move_artefact.ts +3 -3
  599. package/src/scripts/new_skill.ts +3 -3
  600. package/src/scripts/onboarding_gate_hook.ts +2 -2
  601. package/src/scripts/pack_mcp_content.ts +1 -1
  602. package/src/scripts/parity/replay.ts +3 -2
  603. package/src/scripts/pattern_share.ts +2 -2
  604. package/src/scripts/plan_physical_move.ts +3 -3
  605. package/src/scripts/prediction-pool/poisson_sim.ts +2 -2
  606. package/src/scripts/prediction-pool/pool_winsim.ts +2 -2
  607. package/src/scripts/prediction-pool/score_ev.ts +2 -2
  608. package/src/scripts/prepack-check.mjs +108 -5
  609. package/src/scripts/print_required_checks.ts +2 -2
  610. package/src/scripts/probe_projection_fidelity.ts +2 -2
  611. package/src/scripts/probe_skill_registration.ts +2 -2
  612. package/src/scripts/profile_staleness_hook.ts +2 -2
  613. package/src/scripts/profile_use.ts +2 -2
  614. package/src/scripts/project_thin_rules.ts +3 -3
  615. package/src/scripts/propose_modules_config.ts +2 -2
  616. package/src/scripts/prototype_lint_contradictions.ts +2 -2
  617. package/src/scripts/prove_pack_extractable.ts +1 -1
  618. package/src/scripts/readme_linter.ts +4 -4
  619. package/src/scripts/redact_hook_capture.ts +2 -2
  620. package/src/scripts/refine_ticket_detect.ts +1 -1
  621. package/src/scripts/release.ts +30 -19
  622. package/src/scripts/render_benchmark_md.ts +2 -2
  623. package/src/scripts/render_value_md.ts +2 -2
  624. package/src/scripts/roadmap_progress_hook.ts +1 -1
  625. package/src/scripts/router_telemetry.ts +1 -1
  626. package/src/scripts/run_skill_evals.ts +2 -2
  627. package/src/scripts/runtime_dispatcher.ts +1 -1
  628. package/src/scripts/runtime_handler.ts +1 -1
  629. package/src/scripts/runtime_registry.ts +3 -3
  630. package/src/scripts/score_skill_selection.ts +1 -1
  631. package/src/scripts/security_audit_config.ts +2 -2
  632. package/src/scripts/skill_collision_clusters.ts +1 -1
  633. package/src/scripts/skill_discovery.ts +1 -1
  634. package/src/scripts/skill_linter.ts +8 -7
  635. package/src/scripts/skill_overlap.ts +2 -2
  636. package/src/scripts/skill_preview.ts +1 -1
  637. package/src/scripts/skill_tools/audit_persona_coverage.ts +3 -3
  638. package/src/scripts/skill_tools/audit_user_type_coverage.ts +3 -3
  639. package/src/scripts/skill_tools/index.ts +1 -1
  640. package/src/scripts/skill_tools/run_block_d_eval.ts +3 -3
  641. package/src/scripts/skill_tools/score_skill_relevance.ts +3 -3
  642. package/src/scripts/skill_tools/suggest_skill_for_task.ts +3 -3
  643. package/src/scripts/skill_trigger_eval.ts +2 -2
  644. package/src/scripts/skill_usage_collect.ts +2 -2
  645. package/src/scripts/skill_usage_report.ts +2 -2
  646. package/src/scripts/smoke_path_resolution.ts +2 -2
  647. package/src/scripts/smoke_quickstart.ts +4 -4
  648. package/src/scripts/snapshot_agent_outputs.ts +2 -2
  649. package/src/scripts/spotcheck_thin_root.ts +2 -2
  650. package/src/scripts/surface-tiers.yml +1 -0
  651. package/src/scripts/sync_agent_settings.ts +2 -2
  652. package/src/scripts/sync_github_metadata.ts +4 -4
  653. package/src/scripts/sync_gitignore.ts +3 -3
  654. package/src/scripts/sync_yaml_rt.ts +2 -2
  655. package/src/scripts/telegraph_stats.ts +1 -1
  656. package/src/scripts/tool_registry.ts +2 -2
  657. package/src/scripts/tools/adapter_errors.ts +1 -1
  658. package/src/scripts/tools/base_adapter.ts +1 -1
  659. package/src/scripts/tools/github_adapter.ts +1 -1
  660. package/src/scripts/tools/jira_adapter.ts +1 -1
  661. package/src/scripts/trigger_coverage.ts +2 -2
  662. package/src/scripts/update_counts.ts +68 -6
  663. package/src/scripts/update_prices.ts +3 -3
  664. package/src/scripts/validate_agent_settings.ts +3 -3
  665. package/src/scripts/validate_decision_engine.ts +2 -2
  666. package/src/scripts/validate_discovery_manifest.ts +3 -3
  667. package/src/scripts/validate_frontmatter.ts +5 -5
  668. package/src/scripts/validate_pack_yaml.ts +0 -0
  669. package/src/scripts/validate_safe_paths.ts +2 -2
  670. package/src/scripts/validate_telegraph_carveouts.ts +3 -3
  671. package/src/scripts/verify_before_complete_hook.ts +2 -2
  672. package/src/scripts/verify_physical_move.ts +2 -2
  673. package/src/scripts/wrapper_freshness_hook.ts +3 -3
  674. package/src/server/schemas/settings.ts +426 -0
  675. package/src/shared/settingsSurface.ts +184 -0
  676. package/src/shared/userMd/formAdapter.ts +86 -0
  677. package/src/shared/userMd/schema.ts +59 -0
  678. package/src/shared/userMd/utils.ts +91 -0
  679. package/dist/agent-src/commands/optimize-project.md +0 -243
  680. package/dist/ui/assets/index-BbWWuFrF.css +0 -1
  681. package/dist/ui/assets/index-UjcTG_9O.js +0 -40
  682. package/dist/ui/assets/index-UjcTG_9O.js.map +0 -1
@@ -0,0 +1,1089 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * File-first memory retrieval.
4
+ *
5
+ * TypeScript twin of `src/agent-src/templates/scripts/memory_lookup.py`
6
+ * (ADR-200, consumer-shipped template; byte-identical to the dev-side
7
+ * `src/scripts/memory_lookup.py`). The public API and CLI contract mirror
8
+ * the Python original EXACTLY — same exported names (snake_case kept
9
+ * deliberately, especially `retrieve(...)` whose
10
+ * signature/return shape is cited by rules), same exit codes, stdout/stderr
11
+ * split, byte-identical messages, same memory-file scan + ranking + JSON
12
+ * output. No behaviour changes — latent Python bugs are replicated and
13
+ * flagged as divergence candidates.
14
+ *
15
+ * Implements the shared `retrieve(types, keys, limit)` abstraction used
16
+ * by skills. Reads YAML under `agents/memory/<type>/` (curated, hand-
17
+ * reviewed) and JSONL under `agents/memory/intake/*.jsonl` (agent-written,
18
+ * append-only, supersede-chain aware), plus user-ingested `knowledge`
19
+ * chunks and opted-in `cross-repo` matches.
20
+ *
21
+ * Retrieval is entirely repo-side and file-backed — there is no external
22
+ * backend. (The former optional `@event4u/agent-memory` package routing
23
+ * was removed; see `docs/decisions/` for the agent-memory removal ADR.)
24
+ *
25
+ * Usage:
26
+ * memory_lookup --types domain-invariants,ownership --key "app/Http/Controllers/Foo" --limit 5
27
+ * memory_lookup --types incident-learnings --format json
28
+ *
29
+ * import { retrieve } from './memory_lookup.js';
30
+ * const hits = retrieve(['ownership'], ['app/Http'], 3);
31
+ */
32
+
33
+ import * as fs from 'node:fs';
34
+ import * as path from 'node:path';
35
+ import process from 'node:process';
36
+ import { fileURLToPath, pathToFileURL } from 'node:url';
37
+ import YAML, { parseDocument } from 'yaml';
38
+
39
+
40
+ // PyYAML implicit timestamp resolver. PyYAML's `safe_load` turns a plain
41
+ // `YYYY-MM-DD` scalar into a `datetime.date` (str → `YYYY-MM-DD`) and a full
42
+ // timestamp into a `datetime.datetime`. The `yaml` npm parses both to JS Date
43
+ // objects whose String()/JSON form differs, so `json.dumps(..., default=str)`
44
+ // in the CLI would not match. This marker preserves PyYAML's str() form so
45
+ // JSON output and as_dict() are byte-identical to the Python original.
46
+ const PYYAML_DATE_ONLY_RE = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/;
47
+ const PYYAML_TIMESTAMP_RE =
48
+ /^(?:[0-9]{4}-[0-9]{2}-[0-9]{2}|[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}(?:[Tt]|[ \t]+)[0-9]{1,2}:[0-9]{2}:[0-9]{2}(?:\.[0-9]*)?(?:[ \t]*(?:Z|[-+][0-9]{1,2}(?::[0-9]{2})?))?)$/;
49
+
50
+ /** Marker carrying PyYAML's `str(datetime.*)` form (for JSON/default=str). */
51
+ class PyTimestamp {
52
+ constructor(readonly pyStr: string) {}
53
+ toString(): string {
54
+ return this.pyStr;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Marker for a Python `float` so json.dumps renders integer-valued floats as
60
+ * `0.0`/`1.0`, not `0`/`1`. The Hit `score` and the v1 `confidence` are always
61
+ * Python floats; JS has no int/float distinction, so this preserves byte-for-byte
62
+ * parity for whole-number scores.
63
+ */
64
+ class PyFloat {
65
+ constructor(readonly value: number) {}
66
+ }
67
+
68
+ // Mutable so tests can repoint them at a tmp tree (monkeypatch parity).
69
+ export let MEMORY_ROOT = path.join('agents', 'memory');
70
+ export let INTAKE_ROOT = path.join(MEMORY_ROOT, 'intake');
71
+ export let KNOWLEDGE_ROOT = path.join(MEMORY_ROOT, 'knowledge');
72
+
73
+ /** Test-only setters mirroring pytest monkeypatch on the module constants. */
74
+ export function _setMemoryRoot(p: string): void {
75
+ MEMORY_ROOT = p;
76
+ }
77
+ export function _setIntakeRoot(p: string): void {
78
+ INTAKE_ROOT = p;
79
+ }
80
+ export function _setKnowledgeRoot(p: string): void {
81
+ KNOWLEDGE_ROOT = p;
82
+ }
83
+
84
+ export const CURATED_TYPES: ReadonlySet<string> = new Set([
85
+ 'ownership',
86
+ 'historical-patterns',
87
+ 'domain-invariants',
88
+ 'incident-learnings',
89
+ 'product-rules',
90
+ ]);
91
+
92
+ // `knowledge` is its own type: user-ingested local documents that live
93
+ // under `agents/memory/knowledge/<ingest-id>/chunks/*.md`. They are
94
+ // repo-side (file-backed) but not "curated" and not intake.
95
+ export const KNOWLEDGE_TYPE = 'knowledge';
96
+
97
+ // Cross-repo retrieval. When this type is requested AND opted-in
98
+ // linked-project siblings exist, matches from `cross_repo_retrieve` are
99
+ // projected as `source="cross-repo"` Hits, scored below curated/knowledge.
100
+ // Opt-in by caller + lazy import → existing call sites unaffected.
101
+ export const CROSS_REPO_TYPE = 'cross-repo';
102
+
103
+ export type HitSource = 'curated' | 'intake' | 'knowledge' | 'cross-repo';
104
+
105
+ export class Hit {
106
+ id: string;
107
+ type: string;
108
+ source: string; // HitSource, kept as string to mirror the Python dataclass
109
+ path: string; // file (or logical locator) that produced the hit
110
+ score: number; // naive, content-match based [0..1]
111
+ entry: Record<string, unknown>;
112
+
113
+ constructor(
114
+ id: string,
115
+ type: string,
116
+ source: string,
117
+ p: string,
118
+ score: number,
119
+ entry: Record<string, unknown> = {},
120
+ ) {
121
+ this.id = id;
122
+ this.type = type;
123
+ this.source = source;
124
+ this.path = p;
125
+ this.score = score;
126
+ this.entry = entry;
127
+ }
128
+
129
+ as_dict(): Record<string, unknown> {
130
+ return {
131
+ id: this.id,
132
+ type: this.type,
133
+ source: this.source,
134
+ path: this.path,
135
+ // score is a Python float — render `0.0` not `0` for whole numbers.
136
+ score: new PyFloat(this.score),
137
+ entry: this.entry,
138
+ };
139
+ }
140
+ }
141
+
142
+ function _isPlainObject(v: unknown): v is Record<string, unknown> {
143
+ return (
144
+ typeof v === 'object' &&
145
+ v !== null &&
146
+ !Array.isArray(v) &&
147
+ !(v instanceof PyTimestamp) &&
148
+ !(v instanceof PyFloat)
149
+ );
150
+ }
151
+
152
+ function _isFile(p: string): boolean {
153
+ try {
154
+ return fs.statSync(p).isFile();
155
+ } catch {
156
+ return false;
157
+ }
158
+ }
159
+
160
+ function _isDir(p: string): boolean {
161
+ try {
162
+ return fs.statSync(p).isDirectory();
163
+ } catch {
164
+ return false;
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Load a YAML file the way the Python `_load_yaml` does:
170
+ * `yaml.safe_load(fh) or {}`. version: '1.1' matches PyYAML's default so
171
+ * implicit scalar typing (dates, yes/no booleans) lands identically.
172
+ */
173
+ function _load_yaml(p: string): unknown {
174
+ const text = fs.readFileSync(p, 'utf-8');
175
+ const doc = parseDocument(text, { version: '1.1', prettyErrors: false });
176
+ if (doc.errors.length > 0) {
177
+ const err = doc.errors[0];
178
+ throw new Error(err ? err.message : 'YAML parse error');
179
+ }
180
+ YAML.visit(doc, {
181
+ Scalar(_key, node) {
182
+ if (!node.range) {
183
+ return;
184
+ }
185
+ const raw = text.slice(node.range[0], node.range[1]);
186
+ // Under YAML 1.1 the `yaml` lib resolves plain timestamp scalars to
187
+ // JS Date objects. Recover PyYAML's str() form from the original
188
+ // source so JSON output / as_dict() match the Python original.
189
+ if (node.value instanceof Date) {
190
+ if (PYYAML_DATE_ONLY_RE.test(raw)) {
191
+ (node as { value: unknown }).value = new PyTimestamp(raw);
192
+ } else if (PYYAML_TIMESTAMP_RE.test(raw)) {
193
+ (node as { value: unknown }).value = new PyTimestamp(_pyYamlDatetimeStr(raw));
194
+ }
195
+ return;
196
+ }
197
+ // PyYAML's bool resolver does NOT treat bare `y/Y/n/N` as boolean
198
+ // (only yes/no/on/off/true/false) — restore those to strings.
199
+ if (typeof node.value === 'boolean' && node.type === 'PLAIN' && /^[ynYN]$/.test(raw)) {
200
+ (node as { value: unknown }).value = raw;
201
+ }
202
+ },
203
+ });
204
+ const data = doc.toJS({ mapAsMap: false });
205
+ return data == null ? {} : data;
206
+ }
207
+
208
+ /** Compute PyYAML `str(datetime.datetime(...))` for a matched timestamp scalar. */
209
+ function _pyYamlDatetimeStr(raw: string): string {
210
+ const m =
211
+ /^(\d{4})-(\d{1,2})-(\d{1,2})(?:[Tt]|[ \t]+)(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d*))?(?:[ \t]*(Z|[-+]\d{1,2}(?::\d{2})?))?$/.exec(
212
+ raw,
213
+ );
214
+ if (!m) {
215
+ return raw;
216
+ }
217
+ const [, y, mo, d, h, mi, s, frac, tz] = m;
218
+ const date = `${y}-${_pad2(mo as string)}-${_pad2(d as string)}`;
219
+ let time = `${_pad2(h as string)}:${mi}:${s}`;
220
+ if (frac && /[1-9]/.test(frac)) {
221
+ time += `.${(frac + '000000').slice(0, 6)}`;
222
+ }
223
+ let off = '';
224
+ if (tz) {
225
+ if (tz === 'Z') {
226
+ off = '+00:00';
227
+ } else {
228
+ const tm = /^([-+])(\d{1,2})(?::(\d{2}))?$/.exec(tz);
229
+ if (tm) {
230
+ off = `${tm[1]}${_pad2(tm[2] as string)}:${tm[3] ?? '00'}`;
231
+ }
232
+ }
233
+ }
234
+ return `${date} ${time}${off}`;
235
+ }
236
+
237
+ function _pad2(v: string): string {
238
+ return v.length === 1 ? `0${v}` : v;
239
+ }
240
+
241
+ /**
242
+ * Yield [file, entry] pairs for curated files of `mtype`.
243
+ *
244
+ * Supports both the content-addressed layout (`agents/memory/<type>/
245
+ * <hash>.yml` — one entry per file) and the single-file layout
246
+ * (`agents/memory/<type>.yml` or `<type>/entries.yml` with an `entries:`
247
+ * list), so consumers can adopt either.
248
+ */
249
+ function* _iter_curated_entries(mtype: string): Generator<[string, Record<string, unknown>]> {
250
+ const type_dir = path.join(MEMORY_ROOT, mtype);
251
+ const single_file = path.join(MEMORY_ROOT, `${mtype}.yml`);
252
+ if (_isFile(single_file)) {
253
+ const data = _load_yaml(single_file);
254
+ const entries = _isPlainObject(data) ? data['entries'] : null;
255
+ for (const e of Array.isArray(entries) ? entries : []) {
256
+ if (_isPlainObject(e)) {
257
+ yield [single_file, e];
258
+ }
259
+ }
260
+ }
261
+ if (_isDir(type_dir)) {
262
+ for (const yml of _rglobYmlSorted(type_dir)) {
263
+ const dataRaw = _load_yaml(yml);
264
+ const data = dataRaw == null ? {} : dataRaw;
265
+ const entries = _isPlainObject(data) ? data['entries'] : undefined;
266
+ if (Array.isArray(entries)) {
267
+ for (const e of entries) {
268
+ if (_isPlainObject(e)) {
269
+ yield [yml, e];
270
+ }
271
+ }
272
+ } else if (_isPlainObject(data) && data['id']) {
273
+ // Flat, one-entry-per-file layout (content-addressed).
274
+ yield [yml, data];
275
+ }
276
+ }
277
+ }
278
+ }
279
+
280
+ /** Yield [file, entry] from intake JSONL, applying supersede chains. */
281
+ function* _iter_intake_entries(mtype: string): Generator<[string, Record<string, unknown>]> {
282
+ if (!_isDir(INTAKE_ROOT)) {
283
+ return;
284
+ }
285
+ // Resolve supersede chains globally per file: later lines win.
286
+ for (const jsonl of _globJsonlSorted(INTAKE_ROOT)) {
287
+ const by_id = new Map<string, Record<string, unknown>>();
288
+ const superseded = new Set<string>();
289
+ const content = fs.readFileSync(jsonl, 'utf-8');
290
+ for (let line of content.split(/\n/)) {
291
+ line = line.trim();
292
+ if (!line) {
293
+ continue;
294
+ }
295
+ let obj: unknown;
296
+ try {
297
+ obj = JSON.parse(line);
298
+ } catch {
299
+ continue;
300
+ }
301
+ if (!_isPlainObject(obj)) {
302
+ continue;
303
+ }
304
+ if (obj['type'] === 'supersede') {
305
+ const target = obj['supersedes'];
306
+ if (typeof target === 'string') {
307
+ superseded.add(target);
308
+ }
309
+ continue;
310
+ }
311
+ const eid = obj['id'];
312
+ if (typeof eid === 'string') {
313
+ by_id.set(eid, obj);
314
+ }
315
+ }
316
+ for (const [eid, obj] of by_id.entries()) {
317
+ if (superseded.has(eid)) {
318
+ continue;
319
+ }
320
+ if (mtype && obj['entry_type'] && obj['entry_type'] !== mtype) {
321
+ continue;
322
+ }
323
+ yield [jsonl, obj];
324
+ }
325
+ }
326
+ }
327
+
328
+ /**
329
+ * Yield [chunk-file, entry] pairs from `agents/memory/knowledge/`.
330
+ *
331
+ * Layout (frozen in `docs/contracts/local-knowledge-ingestion.md`):
332
+ *
333
+ * agents/memory/knowledge/<ingest-id>/
334
+ * manifest.json
335
+ * chunks/<n>.md
336
+ *
337
+ * Each chunk becomes one retrieval entry. The chunk body, the manifest
338
+ * source path, and pinned flag are surfaced into the entry so `_score()`
339
+ * can match on either the source path or the chunk text. The entry id is
340
+ * `<ingest-id>:<chunk-stem>` so callers can locate the exact file on disk.
341
+ */
342
+ function* _iter_knowledge_entries(): Generator<[string, Record<string, unknown>]> {
343
+ if (!_isDir(KNOWLEDGE_ROOT)) {
344
+ return;
345
+ }
346
+ for (const ingest_dir of _iterdirSorted(KNOWLEDGE_ROOT)) {
347
+ if (!_isDir(ingest_dir)) {
348
+ continue;
349
+ }
350
+ const manifest_path = path.join(ingest_dir, 'manifest.json');
351
+ let manifest: Record<string, unknown> = {};
352
+ if (_isFile(manifest_path)) {
353
+ try {
354
+ const parsed = JSON.parse(fs.readFileSync(manifest_path, 'utf-8'));
355
+ manifest = _isPlainObject(parsed) ? parsed : {};
356
+ } catch {
357
+ manifest = {};
358
+ }
359
+ }
360
+ const ingest_id = String(manifest['ingest_id'] || path.basename(ingest_dir));
361
+ const source = String(manifest['source'] || '');
362
+ const pinned = Boolean(manifest['pinned'] ?? false);
363
+ const chunks_dir = path.join(ingest_dir, 'chunks');
364
+ if (!_isDir(chunks_dir)) {
365
+ continue;
366
+ }
367
+ for (const chunk of _globMdSorted(chunks_dir)) {
368
+ let body: string;
369
+ try {
370
+ body = fs.readFileSync(chunk, 'utf-8');
371
+ } catch {
372
+ continue;
373
+ }
374
+ const entry: Record<string, unknown> = {
375
+ id: `${ingest_id}:${_stem(chunk)}`,
376
+ ingest_id,
377
+ source,
378
+ path: source,
379
+ body,
380
+ pinned,
381
+ source_kind: 'knowledge',
382
+ };
383
+ yield [chunk, entry];
384
+ }
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Naive relevance score: max over keys of (glob-match | substring).
390
+ *
391
+ * Good enough for the `absent` path where retrieval is best-effort.
392
+ * The `present` path returns a real score from agent-memory.
393
+ */
394
+ export function _score(entry: Record<string, unknown>, keys: string[]): number {
395
+ if (keys.length === 0) {
396
+ return 0.1; // any hit beats no hit when there is no key
397
+ }
398
+ const hay_parts: string[] = [];
399
+ for (const field_name of ['path', 'key', 'symptom', 'feature', 'rule', 'body']) {
400
+ const v = entry[field_name];
401
+ if (typeof v === 'string') {
402
+ hay_parts.push(v);
403
+ } else if (Array.isArray(v)) {
404
+ for (const x of v) {
405
+ hay_parts.push(_pyStr(x));
406
+ }
407
+ }
408
+ }
409
+ const hay = hay_parts.join(' | ').toLowerCase();
410
+ let best = 0.0;
411
+ for (const k of keys) {
412
+ const kl = k.toLowerCase();
413
+ if (_fnmatch(hay, `*${kl}*`)) {
414
+ best = Math.max(best, 0.8);
415
+ } else if (hay.includes(kl)) {
416
+ best = Math.max(best, 0.6);
417
+ }
418
+ }
419
+ return best;
420
+ }
421
+
422
+ /**
423
+ * Project cross-repo matches into discounted, tagged Hits.
424
+ *
425
+ * Lazy + guarded: the Python original imports `cross_repo_retrieve` on
426
+ * demand and swallows any failure (script absent, no opted-in siblings) so
427
+ * the cross-repo type degrades to zero hits rather than breaking retrieval.
428
+ * The TypeScript twin of `cross_repo_retrieve` is unported in this phase, so
429
+ * this always degrades to zero hits — flagged as a divergence candidate.
430
+ * Scores sit below curated/knowledge (0.85× floor, then a small per-rank
431
+ * decrement) so cross-repo context never outranks the project's own truth.
432
+ */
433
+ function _cross_repo_hits(keys: string[], limit: number): Hit[] {
434
+ const query = keys
435
+ .filter((k) => k)
436
+ .join(' ')
437
+ .trim();
438
+ if (!query) {
439
+ return [];
440
+ }
441
+ // cross_repo_retrieve has no TS twin yet, so the optional surface degrades
442
+ // to zero hits exactly as the Python `except` branch would when the script
443
+ // is absent in a consumer install.
444
+ void limit;
445
+ return [];
446
+ }
447
+
448
+ /**
449
+ * Return up to `limit` hits across the requested types, highest score first.
450
+ *
451
+ * Repo entries (curated + intake) are preferred on ties — they are
452
+ * hand-reviewed or session-captured against the repo itself. Knowledge
453
+ * and cross-repo hits are discounted so the project's own truth wins on
454
+ * equal relevance.
455
+ */
456
+ export function retrieve(types: string[], keys: string[], limit = 5): Hit[] {
457
+ const repo_hits: Hit[] = [];
458
+ for (const mtype of types) {
459
+ if (mtype === KNOWLEDGE_TYPE) {
460
+ for (const [p, entry] of _iter_knowledge_entries()) {
461
+ let base = _score(entry, keys);
462
+ // Pinned entries get a slight ranking boost so the
463
+ // `/knowledge:list --pin` flag has retrieval effect.
464
+ if (entry['pinned']) {
465
+ base = Math.min(1.0, base + 0.05);
466
+ }
467
+ repo_hits.push(
468
+ new Hit(
469
+ String(entry['id'] ?? ''),
470
+ KNOWLEDGE_TYPE,
471
+ 'knowledge',
472
+ String(p),
473
+ // Discount vs curated/intake so hand-reviewed repo
474
+ // entries still win on equal relevance.
475
+ base * 0.85,
476
+ entry,
477
+ ),
478
+ );
479
+ }
480
+ continue;
481
+ }
482
+ if (mtype === CROSS_REPO_TYPE) {
483
+ for (const h of _cross_repo_hits(keys, limit)) {
484
+ repo_hits.push(h);
485
+ }
486
+ continue;
487
+ }
488
+ if (!CURATED_TYPES.has(mtype)) {
489
+ continue;
490
+ }
491
+ for (const [p, entry] of _iter_curated_entries(mtype)) {
492
+ repo_hits.push(new Hit(String(entry['id'] ?? ''), mtype, 'curated', String(p), _score(entry, keys), entry));
493
+ }
494
+ for (const [p, entry] of _iter_intake_entries(mtype)) {
495
+ repo_hits.push(
496
+ new Hit(
497
+ String(entry['id'] ?? ''),
498
+ mtype,
499
+ 'intake',
500
+ String(p),
501
+ _score(entry, keys) * 0.9, // slight discount vs curated
502
+ entry,
503
+ ),
504
+ );
505
+ }
506
+ }
507
+
508
+ _sortMerged(repo_hits);
509
+ const positives = repo_hits.filter((h) => h.score > 0);
510
+ return (positives.length > 0 ? positives : repo_hits).slice(0, limit);
511
+ }
512
+
513
+ /**
514
+ * Mirror `repo_hits.sort(key=lambda h: (h.score, h.source == "curated"),
515
+ * reverse=True)` — stable descending by (score, isCurated).
516
+ */
517
+ function _sortMerged(merged: Hit[]): void {
518
+ // Python's list.sort is stable. To reproduce a stable descending sort by
519
+ // a composite key, sort the (index, hit) pairs and compare keys; equal
520
+ // keys keep original order (lower index first).
521
+ const indexed = merged.map((h, i) => ({ h, i }));
522
+ indexed.sort((a, b) => {
523
+ if (a.h.score !== b.h.score) {
524
+ return b.h.score - a.h.score; // descending score
525
+ }
526
+ const ac = a.h.source === 'curated' ? 1 : 0;
527
+ const bc = b.h.source === 'curated' ? 1 : 0;
528
+ if (ac !== bc) {
529
+ return bc - ac; // descending: curated (True) before non-curated
530
+ }
531
+ return a.i - b.i; // stable: preserve original order
532
+ });
533
+ for (let i = 0; i < indexed.length; i += 1) {
534
+ merged[i] = (indexed[i] as { h: Hit }).h;
535
+ }
536
+ }
537
+
538
+ export const _CONTRACT_VERSION = 1;
539
+ // Exported under the Python name too.
540
+ export { _CONTRACT_VERSION as CONTRACT_VERSION };
541
+
542
+ // Memory types this file-backed backend can answer. Types outside this set
543
+ // map to `unknown_type` per the retrieval contract.
544
+ const _KNOWN_TYPES: ReadonlySet<string> = new Set([...CURATED_TYPES, KNOWLEDGE_TYPE, CROSS_REPO_TYPE]);
545
+
546
+ /**
547
+ * Return a v1 retrieval-contract envelope.
548
+ *
549
+ * Wraps {@link retrieve} and projects the internal `Hit` shape into the
550
+ * shape defined by `internal/schemas/retrieval-v1.schema.json`. Unknown
551
+ * types are reported as `status: unknown_type` for that slice only, rather
552
+ * than failing the whole call. All entries are file-backed (`source: "repo"`).
553
+ */
554
+ export function retrieve_v1(types: string[], keys: string[], limit = 20): Record<string, unknown> {
555
+ const known = types.filter((t) => _KNOWN_TYPES.has(t));
556
+ const unknown = types.filter((t) => !_KNOWN_TYPES.has(t));
557
+
558
+ const hits = retrieve(known, keys, limit);
559
+
560
+ const slice_counts: Record<string, number> = {};
561
+ for (const t of known) {
562
+ slice_counts[t] = 0;
563
+ }
564
+ const entries: Record<string, unknown>[] = [];
565
+ for (const h of hits) {
566
+ const envelope_entry: Record<string, unknown> = {
567
+ id: h.id,
568
+ type: h.type,
569
+ source: 'repo',
570
+ // confidence = round(float(score), 4) — always a Python float.
571
+ confidence: new PyFloat(_round4(h.score)),
572
+ body: _isPlainObject(h.entry) ? { ...h.entry } : {},
573
+ };
574
+ if (h.type in slice_counts) {
575
+ slice_counts[h.type] = (slice_counts[h.type] as number) + 1;
576
+ }
577
+ entries.push(envelope_entry);
578
+ }
579
+
580
+ const slices: Record<string, Record<string, unknown>> = {};
581
+ for (const t of known) {
582
+ slices[t] = { status: 'ok', count: slice_counts[t] ?? 0 };
583
+ }
584
+ const errors: Record<string, unknown>[] = [];
585
+ for (const t of unknown) {
586
+ slices[t] = { status: 'unknown_type', count: 0 };
587
+ errors.push({
588
+ type: t,
589
+ code: 'unknown_type',
590
+ message: `file-backed backend does not know type ${_pyRepr(t)}`,
591
+ });
592
+ }
593
+
594
+ const sliceVals = Object.values(slices);
595
+ const oks = sliceVals.filter((s) => s['status'] === 'ok');
596
+ const fails = sliceVals.filter((s) => s['status'] !== 'ok');
597
+ const envelope_status = fails.length === 0 ? 'ok' : oks.length === 0 ? 'error' : 'partial';
598
+
599
+ const envelope: Record<string, unknown> = {
600
+ contract_version: _CONTRACT_VERSION,
601
+ status: envelope_status,
602
+ entries,
603
+ slices,
604
+ };
605
+ if (errors.length > 0) {
606
+ envelope['errors'] = errors;
607
+ }
608
+ return envelope;
609
+ }
610
+
611
+ // ---------------------------------------------------------------------------
612
+ // CLI
613
+ // ---------------------------------------------------------------------------
614
+
615
+ interface ParsedArgs {
616
+ types: string;
617
+ key: string[];
618
+ limit: number;
619
+ format: 'text' | 'json';
620
+ envelope: 'legacy' | 'v1';
621
+ }
622
+
623
+ function _parseArgs(argv: string[]): ParsedArgs {
624
+ const args: ParsedArgs = {
625
+ types: '',
626
+ key: [],
627
+ limit: 5,
628
+ format: 'text',
629
+ envelope: 'legacy',
630
+ };
631
+ for (let i = 0; i < argv.length; i += 1) {
632
+ const a = argv[i] as string;
633
+ if (a === '--types') {
634
+ args.types = argv[++i] as string;
635
+ } else if (a.startsWith('--types=')) {
636
+ args.types = a.slice('--types='.length);
637
+ } else if (a === '--key') {
638
+ args.key.push(argv[++i] as string);
639
+ } else if (a.startsWith('--key=')) {
640
+ args.key.push(a.slice('--key='.length));
641
+ } else if (a === '--limit') {
642
+ args.limit = _parseInt(argv[++i], '--limit');
643
+ } else if (a.startsWith('--limit=')) {
644
+ args.limit = _parseInt(a.slice('--limit='.length), '--limit');
645
+ } else if (a === '--format') {
646
+ args.format = _checkChoice(argv[++i], ['text', 'json'], '--format') as 'text' | 'json';
647
+ } else if (a.startsWith('--format=')) {
648
+ args.format = _checkChoice(a.slice('--format='.length), ['text', 'json'], '--format') as 'text' | 'json';
649
+ } else if (a === '--envelope') {
650
+ args.envelope = _checkChoice(argv[++i], ['legacy', 'v1'], '--envelope') as 'legacy' | 'v1';
651
+ } else if (a.startsWith('--envelope=')) {
652
+ args.envelope = _checkChoice(a.slice('--envelope='.length), ['legacy', 'v1'], '--envelope') as
653
+ | 'legacy'
654
+ | 'v1';
655
+ } else if (a === '-h' || a === '--help') {
656
+ _printUsage();
657
+ process.exit(0);
658
+ } else {
659
+ process.stderr.write(`memory_lookup: error: unrecognized arguments: ${a}\n`);
660
+ process.exit(2);
661
+ }
662
+ }
663
+ return args;
664
+ }
665
+
666
+ function _parseInt(value: string | undefined, flag: string): number {
667
+ const n = Number(value);
668
+ if (value === undefined || !Number.isInteger(n)) {
669
+ process.stderr.write(
670
+ `memory_lookup: error: argument ${flag}: invalid int value: '${value ?? ''}'\n`,
671
+ );
672
+ process.exit(2);
673
+ }
674
+ return n;
675
+ }
676
+
677
+ function _checkChoice(value: string | undefined, choices: string[], flag: string): string {
678
+ if (value === undefined || !choices.includes(value)) {
679
+ process.stderr.write(
680
+ `memory_lookup: error: argument ${flag}: invalid choice: '${value ?? ''}' (choose from ${choices
681
+ .map((c) => `'${c}'`)
682
+ .join(', ')})\n`,
683
+ );
684
+ process.exit(2);
685
+ }
686
+ return value;
687
+ }
688
+
689
+ function _printUsage(): void {
690
+ process.stdout.write(
691
+ 'usage: memory_lookup [-h] [--types TYPES] [--key KEY] [--limit LIMIT] ' +
692
+ '[--format {text,json}] [--envelope {legacy,v1}]\n',
693
+ );
694
+ }
695
+
696
+ export function main(): number {
697
+ const args = _parseArgs(process.argv.slice(2));
698
+ const types = args.types
699
+ .split(',')
700
+ .map((t) => t.trim())
701
+ .filter((t) => t);
702
+ if (types.length === 0) {
703
+ process.stderr.write('error: --types is required\n');
704
+ return 2;
705
+ }
706
+ if (args.envelope === 'v1') {
707
+ const envelope = retrieve_v1(types, args.key, args.limit);
708
+ process.stdout.write(`${pyJsonDumps(envelope, 2)}\n`);
709
+ return 0;
710
+ }
711
+ const hits = retrieve(types, args.key, args.limit);
712
+ if (args.format === 'json') {
713
+ const payload = {
714
+ hits: hits.map((h) => h.as_dict()),
715
+ };
716
+ process.stdout.write(`${pyJsonDumps(payload, 2)}\n`);
717
+ } else {
718
+ if (hits.length === 0) {
719
+ process.stdout.write(' (no hits)\n');
720
+ }
721
+ for (const h of hits) {
722
+ process.stdout.write(
723
+ ` [${h.source}] ${h.type} score=${_fixed2(h.score)} ` +
724
+ `id=${h.id || '-'} path=${h.path}\n`,
725
+ );
726
+ }
727
+ }
728
+ return 0;
729
+ }
730
+
731
+ // ---------------------------------------------------------------------------
732
+ // helpers — Python compatibility
733
+ // ---------------------------------------------------------------------------
734
+
735
+ /** Mirror Python `f"{score:.2f}"`. */
736
+ function _fixed2(n: number): string {
737
+ return n.toFixed(2);
738
+ }
739
+
740
+ /** Mirror Python `round(x, 4)` (banker's rounding). */
741
+ function _round4(n: number): number {
742
+ return _pyRound(n, 4);
743
+ }
744
+
745
+ /** Python 3 round(): round-half-to-even at the given decimal places. */
746
+ function _pyRound(value: number, ndigits: number): number {
747
+ const factor = 10 ** ndigits;
748
+ const scaled = value * factor;
749
+ const floor = Math.floor(scaled);
750
+ const diff = scaled - floor;
751
+ let rounded: number;
752
+ if (diff > 0.5) {
753
+ rounded = floor + 1;
754
+ } else if (diff < 0.5) {
755
+ rounded = floor;
756
+ } else {
757
+ // exactly .5 → round to even
758
+ rounded = floor % 2 === 0 ? floor : floor + 1;
759
+ }
760
+ return rounded / factor;
761
+ }
762
+
763
+ /** fnmatch.fnmatch — translate a shell glob to a regex (POSIX-normcase). */
764
+ function _fnmatch(name: string, pattern: string): boolean {
765
+ const re = _fnmatchTranslate(pattern);
766
+ return re.test(name);
767
+ }
768
+
769
+ /**
770
+ * Mirror fnmatch.translate: `*` → `.*`, `?` → `.`, `[...]` char class,
771
+ * everything else escaped. Anchored full-match.
772
+ */
773
+ function _fnmatchTranslate(pat: string): RegExp {
774
+ let res = '';
775
+ let i = 0;
776
+ const n = pat.length;
777
+ while (i < n) {
778
+ const c = pat[i] as string;
779
+ i += 1;
780
+ if (c === '*') {
781
+ res += '.*';
782
+ } else if (c === '?') {
783
+ res += '.';
784
+ } else if (c === '[') {
785
+ let j = i;
786
+ if (j < n && pat[j] === '!') {
787
+ j += 1;
788
+ }
789
+ if (j < n && pat[j] === ']') {
790
+ j += 1;
791
+ }
792
+ while (j < n && pat[j] !== ']') {
793
+ j += 1;
794
+ }
795
+ if (j >= n) {
796
+ res += '\\[';
797
+ } else {
798
+ let stuff = pat.slice(i, j);
799
+ if (!stuff.includes('-')) {
800
+ stuff = stuff.replace(/\\/g, '\\\\');
801
+ } else {
802
+ // Match CPython's bracket-range handling minimally.
803
+ stuff = stuff.replace(/\\/g, '\\\\');
804
+ }
805
+ i = j + 1;
806
+ if (stuff.startsWith('!')) {
807
+ stuff = `^${stuff.slice(1)}`;
808
+ } else if (stuff.startsWith('^') || stuff.startsWith('[')) {
809
+ stuff = `\\${stuff}`;
810
+ }
811
+ res += `[${stuff}]`;
812
+ }
813
+ } else {
814
+ res += _reEscape(c);
815
+ }
816
+ }
817
+ // CPython uses (?s:...)\Z — dotall, anchored to end. Anchor both ends.
818
+ return new RegExp(`^(?:${res})$`, 's');
819
+ }
820
+
821
+ function _reEscape(ch: string): string {
822
+ return ch.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
823
+ }
824
+
825
+ /** Mirror Python str(x) for list-element haystack building / repr. */
826
+ function _pyStr(value: unknown): string {
827
+ if (value === null || value === undefined) {
828
+ return 'None';
829
+ }
830
+ if (value === true) {
831
+ return 'True';
832
+ }
833
+ if (value === false) {
834
+ return 'False';
835
+ }
836
+ return String(value);
837
+ }
838
+
839
+ /** Mirror Python repr() for a string in the unknown_type message: {t!r}. */
840
+ function _pyRepr(s: string): string {
841
+ // Python repr prefers single quotes unless the string contains a single
842
+ // quote and no double quote.
843
+ const hasSingle = s.includes("'");
844
+ const hasDouble = s.includes('"');
845
+ const quote = hasSingle && !hasDouble ? '"' : "'";
846
+ let out = quote;
847
+ for (const ch of s) {
848
+ if (ch === quote || ch === '\\') {
849
+ out += `\\${ch}`;
850
+ } else if (ch === '\n') {
851
+ out += '\\n';
852
+ } else if (ch === '\r') {
853
+ out += '\\r';
854
+ } else if (ch === '\t') {
855
+ out += '\\t';
856
+ } else {
857
+ out += ch;
858
+ }
859
+ }
860
+ return out + quote;
861
+ }
862
+
863
+ // ---------------------------------------------------------------------------
864
+ // filesystem helpers — mirror pathlib glob/rglob/iterdir ordering
865
+ // ---------------------------------------------------------------------------
866
+
867
+ /** Mirror sorted(dir.rglob("*.yml")) — recursive, sorted by POSIX path string. */
868
+ function _rglobYmlSorted(root: string): string[] {
869
+ const out: string[] = [];
870
+ const walk = (dir: string): void => {
871
+ let entries: fs.Dirent[];
872
+ try {
873
+ entries = fs.readdirSync(dir, { withFileTypes: true });
874
+ } catch {
875
+ return;
876
+ }
877
+ for (const ent of entries) {
878
+ const full = path.join(dir, ent.name);
879
+ if (ent.name.endsWith('.yml')) {
880
+ out.push(full);
881
+ }
882
+ if (ent.isDirectory() || (ent.isSymbolicLink() && _isDir(full))) {
883
+ walk(full);
884
+ }
885
+ }
886
+ };
887
+ walk(root);
888
+ out.sort();
889
+ return out;
890
+ }
891
+
892
+ /** Mirror sorted(dir.glob("*.jsonl")) — non-recursive, sorted. */
893
+ function _globJsonlSorted(dir: string): string[] {
894
+ return _globSorted(dir, '.jsonl');
895
+ }
896
+
897
+ /** Mirror sorted(dir.glob("*.md")). */
898
+ function _globMdSorted(dir: string): string[] {
899
+ return _globSorted(dir, '.md');
900
+ }
901
+
902
+ function _globSorted(dir: string, suffix: string): string[] {
903
+ let entries: fs.Dirent[];
904
+ try {
905
+ entries = fs.readdirSync(dir, { withFileTypes: true });
906
+ } catch {
907
+ return [];
908
+ }
909
+ const out = entries
910
+ .filter((e) => e.name.endsWith(suffix) && (e.isFile() || (e.isSymbolicLink() && _isFile(path.join(dir, e.name)))))
911
+ .map((e) => path.join(dir, e.name));
912
+ out.sort();
913
+ return out;
914
+ }
915
+
916
+ /** Mirror sorted(dir.iterdir()). */
917
+ function _iterdirSorted(dir: string): string[] {
918
+ let names: string[];
919
+ try {
920
+ names = fs.readdirSync(dir);
921
+ } catch {
922
+ return [];
923
+ }
924
+ const out = names.map((name) => path.join(dir, name));
925
+ out.sort();
926
+ return out;
927
+ }
928
+
929
+ function _stem(p: string): string {
930
+ const base = path.basename(p);
931
+ const dot = base.lastIndexOf('.');
932
+ return dot <= 0 ? base : base.slice(0, dot);
933
+ }
934
+
935
+ // ---------------------------------------------------------------------------
936
+ // Python-compatible json.dumps(obj, indent=N, default=str)
937
+ // ---------------------------------------------------------------------------
938
+
939
+ /**
940
+ * `json.dumps(obj, indent=2, default=str)`. Uses item separator `,\n` +
941
+ * indent and key separator `": "`. Non-serialisable values fall back to
942
+ * str(). `ensure_ascii=True` by default → non-ASCII escaped.
943
+ */
944
+ function pyJsonDumps(value: unknown, indent: number): string {
945
+ return _escapeNonAscii(_dumpsIndent(value, indent, 0));
946
+ }
947
+
948
+ function _dumpsIndent(value: unknown, indent: number, depth: number): string {
949
+ const pad = ' '.repeat(indent * (depth + 1));
950
+ const closePad = ' '.repeat(indent * depth);
951
+ if (value === null || value === undefined) {
952
+ return 'null';
953
+ }
954
+ if (typeof value === 'boolean') {
955
+ return value ? 'true' : 'false';
956
+ }
957
+ if (typeof value === 'number') {
958
+ return _jsonNum(value);
959
+ }
960
+ if (typeof value === 'string') {
961
+ return _jsonStrAscii(value);
962
+ }
963
+ if (value instanceof PyTimestamp) {
964
+ // default=str on a datetime → PyYAML str() form (already computed).
965
+ return _jsonStrAscii(value.pyStr);
966
+ }
967
+ if (value instanceof PyFloat) {
968
+ return _jsonFloat(value.value);
969
+ }
970
+ if (Array.isArray(value)) {
971
+ if (value.length === 0) {
972
+ return '[]';
973
+ }
974
+ const items = value.map((v) => pad + _dumpsIndent(v, indent, depth + 1));
975
+ return `[\n${items.join(',\n')}\n${closePad}]`;
976
+ }
977
+ if (_isPlainObject(value)) {
978
+ const keys = Object.keys(value);
979
+ if (keys.length === 0) {
980
+ return '{}';
981
+ }
982
+ const items = keys.map((k) => `${pad}${_jsonStrAscii(k)}: ${_dumpsIndent(value[k], indent, depth + 1)}`);
983
+ return `{\n${items.join(',\n')}\n${closePad}}`;
984
+ }
985
+ // default=str
986
+ return _jsonStrAscii(String(value));
987
+ }
988
+
989
+ function _jsonNum(n: number): string {
990
+ if (!Number.isFinite(n)) {
991
+ if (Number.isNaN(n)) {
992
+ return 'NaN';
993
+ }
994
+ return n > 0 ? 'Infinity' : '-Infinity';
995
+ }
996
+ return String(n);
997
+ }
998
+
999
+ /** Render a Python float — integer-valued floats keep a `.0` suffix (repr(float)). */
1000
+ function _jsonFloat(n: number): string {
1001
+ if (!Number.isFinite(n)) {
1002
+ if (Number.isNaN(n)) {
1003
+ return 'NaN';
1004
+ }
1005
+ return n > 0 ? 'Infinity' : '-Infinity';
1006
+ }
1007
+ return Number.isInteger(n) ? `${n}.0` : String(n);
1008
+ }
1009
+
1010
+ /** JSON string with standard escapes (ensure_ascii handled by caller pass). */
1011
+ function _jsonStrAscii(s: string): string {
1012
+ let out = '"';
1013
+ for (const ch of s) {
1014
+ const code = ch.codePointAt(0) ?? 0;
1015
+ switch (ch) {
1016
+ case '"':
1017
+ out += '\\"';
1018
+ break;
1019
+ case '\\':
1020
+ out += '\\\\';
1021
+ break;
1022
+ case '\n':
1023
+ out += '\\n';
1024
+ break;
1025
+ case '\r':
1026
+ out += '\\r';
1027
+ break;
1028
+ case '\t':
1029
+ out += '\\t';
1030
+ break;
1031
+ case '\b':
1032
+ out += '\\b';
1033
+ break;
1034
+ case '\f':
1035
+ out += '\\f';
1036
+ break;
1037
+ default:
1038
+ if (code < 0x20) {
1039
+ out += `\\u${code.toString(16).padStart(4, '0')}`;
1040
+ } else {
1041
+ out += ch;
1042
+ }
1043
+ }
1044
+ }
1045
+ return `${out}"`;
1046
+ }
1047
+
1048
+ function _escapeNonAscii(s: string): string {
1049
+ let out = '';
1050
+ for (const ch of s) {
1051
+ const code = ch.codePointAt(0) ?? 0;
1052
+ if (code > 0x7f) {
1053
+ for (let i = 0; i < ch.length; i += 1) {
1054
+ out += `\\u${ch.charCodeAt(i).toString(16).padStart(4, '0')}`;
1055
+ }
1056
+ } else {
1057
+ out += ch;
1058
+ }
1059
+ }
1060
+ return out;
1061
+ }
1062
+
1063
+ function _isCliEntry(): boolean {
1064
+ if (process.argv[1] === undefined) {
1065
+ return false;
1066
+ }
1067
+ const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
1068
+ if (import.meta.url === argvUrl) {
1069
+ return true;
1070
+ }
1071
+ // A symlinked invocation (e.g. via an installed `.augment/` projection,
1072
+ // or macOS /var → /private/var temp dirs) makes the raw URLs differ:
1073
+ // import.meta.url is the resolved real path while argv[1] keeps the
1074
+ // symlink path. Compare realpaths so the entry guard still fires
1075
+ // (without this the CLI silently no-ops when run through a symlink).
1076
+ try {
1077
+ const here = fs.realpathSync(fileURLToPath(import.meta.url));
1078
+ const argv = fs.realpathSync(path.resolve(process.argv[1]));
1079
+ return here === argv;
1080
+ } catch {
1081
+ return false;
1082
+ }
1083
+ }
1084
+
1085
+ const _isMain =
1086
+ _isCliEntry();
1087
+ if (_isMain) {
1088
+ process.exit(main());
1089
+ }