hecks 2.9.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (600) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +51 -6
  3. data/lib/hecks/adapters/driven/heki/journal.rb +1 -1
  4. data/lib/hecks/adapters/driven/lambda/client.rb +1 -1
  5. data/lib/hecks/adapters/driven/lambda.rb +1 -1
  6. data/lib/hecks/adapters/driven/memory.rb +16 -3
  7. data/lib/hecks/adapters/driven/postgres/reconnect.rb +6 -2
  8. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
  9. data/lib/hecks/adapters/driven/postgres.rb +13 -4
  10. data/lib/hecks/adapters/driven/prism.rb +41 -8
  11. data/lib/hecks/adapters/driven/tenant_provisioner.rb +73 -16
  12. data/lib/hecks/behaviors/expectations.rb +1 -1
  13. data/lib/hecks/behaviors.rb +1 -1
  14. data/lib/hecks/bench/cli.rb +62 -0
  15. data/lib/hecks/bench/environment.rb +71 -0
  16. data/lib/hecks/bench/postgres_probe.rb +30 -0
  17. data/lib/hecks/bench/report.rb +76 -0
  18. data/lib/hecks/bench/ruby_runner.rb +93 -0
  19. data/lib/hecks/bench/run.rb +55 -0
  20. data/lib/hecks/bench/rust_runner.rb +101 -0
  21. data/lib/hecks/bench/stats.rb +46 -0
  22. data/lib/hecks/bench/suite.rb +98 -0
  23. data/lib/hecks/bench/workload.rb +89 -0
  24. data/lib/hecks/bench.rb +17 -0
  25. data/lib/hecks/bluebook/assembly/contracts.rb +2 -0
  26. data/lib/hecks/bluebook/attribute.rb +1 -1
  27. data/lib/hecks/bluebook/behaviour/aggregate.rb +30 -1
  28. data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -0
  29. data/lib/hecks/bluebook/chapter.rb +6 -2
  30. data/lib/hecks/bluebook/domain_port.rb +36 -5
  31. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +10 -0
  32. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +8 -0
  33. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -1
  34. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +31 -3
  35. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +122 -3
  36. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +1 -1
  37. data/lib/hecks/bluebook/dsl/query_builder.rb +27 -1
  38. data/lib/hecks/bluebook/dsl/rule_reference.rb +1 -1
  39. data/lib/hecks/bluebook/dsl/world_builder.rb +29 -2
  40. data/lib/hecks/bluebook/expression/canonical_form.rb +1 -1
  41. data/lib/hecks/bluebook/expression/resolver.rb +3 -2
  42. data/lib/hecks/bluebook/hexagon.rb +13 -5
  43. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +1 -0
  44. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +4 -1
  45. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
  46. data/lib/hecks/bluebook/meta_validator.rb +9 -4
  47. data/lib/hecks/bluebook/model_check.rb +23 -0
  48. data/lib/hecks/bluebook/pattern_subset.rb +38 -0
  49. data/lib/hecks/bluebook/query.rb +20 -5
  50. data/lib/hecks/bluebook/smoke_test.rb +1 -1
  51. data/lib/hecks/canonical_json.rb +30 -0
  52. data/lib/hecks/chapters.rb +102 -0
  53. data/lib/hecks/cli/behaviors.rb +61 -0
  54. data/lib/hecks/cli/canonicalise.rb +25 -0
  55. data/lib/hecks/cli/check_engine_agreement.rb +32 -0
  56. data/lib/hecks/cli/check_era.rb +88 -0
  57. data/lib/hecks/cli/console.rb +66 -0
  58. data/lib/hecks/cli/deploy_template_diff.rb +40 -0
  59. data/lib/hecks/cli/doc_coverage.rb +32 -0
  60. data/lib/hecks/cli/document.rb +2 -2
  61. data/lib/hecks/cli/expression_projection.rb +41 -0
  62. data/lib/hecks/cli/follow.rb +88 -0
  63. data/lib/hecks/cli/history.rb +44 -0
  64. data/lib/hecks/cli/ir.rb +1 -1
  65. data/lib/hecks/cli/mcp.rb +3 -3
  66. data/lib/hecks/cli/model_check.rb +15 -8
  67. data/lib/hecks/cli/pattern_cases.rb +47 -0
  68. data/lib/hecks/cli/present.rb +39 -0
  69. data/lib/hecks/cli/project_cli.rb +224 -32
  70. data/lib/hecks/cli/project_diagrams.rb +4 -3
  71. data/lib/hecks/cli/project_glossary.rb +44 -0
  72. data/lib/hecks/cli/reference.rb +46 -0
  73. data/lib/hecks/cli/refresh_projections.rb +44 -0
  74. data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
  75. data/lib/hecks/cli/release.rb +70 -0
  76. data/lib/hecks/cli/release_gem.rb +59 -0
  77. data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
  78. data/lib/hecks/cli/rspec_shard_files.rb +66 -0
  79. data/lib/hecks/cli/run.rb +3 -3
  80. data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
  81. data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
  82. data/lib/hecks/cli/shape.rb +70 -0
  83. data/lib/hecks/cli/smoke_http.rb +230 -0
  84. data/lib/hecks/cli/smoke_test.rb +5 -3
  85. data/lib/hecks/cli/spec_example.rb +27 -0
  86. data/lib/hecks/cli/statements.rb +32 -0
  87. data/lib/hecks/cli/stores.rb +4 -5
  88. data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
  89. data/lib/hecks/cli.rb +201 -52
  90. data/lib/hecks/codemod.rb +324 -0
  91. data/lib/hecks/corpus.rb +423 -0
  92. data/lib/hecks/deploy/bluebook/deploy.bluebook +591 -23
  93. data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -4
  94. data/lib/hecks/deploy/oidc.json +82 -2
  95. data/lib/hecks/doc/reference.rb +351 -0
  96. data/lib/hecks/doors/cli_door.rb +196 -0
  97. data/lib/hecks/doors/cli_runner.rb +297 -0
  98. data/lib/hecks/{facade → doors}/command_request.rb +1 -1
  99. data/lib/hecks/{facade → doors}/handle.rb +2 -2
  100. data/lib/hecks/{facade → doors}/json_door.rb +4 -4
  101. data/lib/hecks/doors/launcher_options.rb +129 -0
  102. data/lib/hecks/{cli → doors}/mcp_door.rb +7 -7
  103. data/lib/hecks/doors/mcp_door_scope.rb +97 -0
  104. data/lib/hecks/{facade/surface → doors/ruby_door}/aggregate_door.rb +8 -3
  105. data/lib/hecks/{facade/surface → doors/ruby_door}/chapter.rb +3 -3
  106. data/lib/hecks/{facade/surface.rb → doors/ruby_door.rb} +36 -5
  107. data/lib/hecks/doors.rb +61 -0
  108. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +1 -1
  109. data/lib/hecks/embryonaut_bluebook.rb +1 -1
  110. data/lib/hecks/engine_agreement.rb +156 -0
  111. data/lib/hecks/facade.rb +24 -37
  112. data/lib/hecks/forms/app.rb +6 -6
  113. data/lib/hecks/forms/banking_presentation.rb +50 -0
  114. data/lib/hecks/forms/field_shape.rb +2 -1
  115. data/lib/hecks/forms/port_argument.rb +1 -1
  116. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
  117. data/lib/hecks/fuzzing/combination_miner.rb +86 -0
  118. data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
  119. data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
  120. data/lib/hecks/fuzzing/differential.rb +156 -0
  121. data/lib/hecks/fuzzing/domain_generator.rb +615 -0
  122. data/lib/hecks/fuzzing/era_boundary.rb +71 -0
  123. data/lib/hecks/fuzzing/form_census.rb +136 -0
  124. data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
  125. data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
  126. data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
  127. data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
  128. data/lib/hecks/fuzzing/outside_world.rb +45 -0
  129. data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
  130. data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
  131. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
  132. data/lib/hecks/fuzzing/properties/guards.rb +190 -0
  133. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
  134. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
  135. data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
  136. data/lib/hecks/fuzzing/properties/querying.rb +175 -0
  137. data/lib/hecks/fuzzing/properties.rb +162 -0
  138. data/lib/hecks/fuzzing/qa_settings.rb +123 -0
  139. data/lib/hecks/fuzzing/replay.rb +505 -0
  140. data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
  141. data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
  142. data/lib/hecks/fuzzing/self_consistency.rb +339 -0
  143. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
  144. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
  145. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
  146. data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
  147. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
  148. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
  149. data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
  150. data/lib/hecks/fuzzing/shrinker.rb +166 -0
  151. data/lib/hecks/fuzzing/structural_skips.rb +33 -0
  152. data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
  153. data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
  154. data/lib/hecks/fuzzing/value_generator.rb +216 -0
  155. data/lib/hecks/fuzzing.rb +23 -0
  156. data/lib/hecks/grammar/evolve.rb +336 -0
  157. data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
  158. data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
  159. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
  160. data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
  161. data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
  162. data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
  163. data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
  164. data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
  165. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
  166. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
  167. data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
  168. data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
  169. data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
  170. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
  171. data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
  172. data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
  173. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
  174. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
  175. data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
  176. data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
  177. data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
  178. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
  179. data/lib/hecks/hecks/adapters/git.adapter +7 -0
  180. data/lib/hecks/hecks/adapters/git.rb +102 -0
  181. data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
  182. data/lib/hecks/hecks/adapters/host_http.rb +65 -0
  183. data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
  184. data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
  185. data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
  186. data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
  187. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
  188. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
  189. data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
  190. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
  191. data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
  192. data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
  193. data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
  194. data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
  195. data/lib/hecks/hecks/adapters/local_files.rb +46 -0
  196. data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
  197. data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
  198. data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
  199. data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
  200. data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
  201. data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
  202. data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
  203. data/lib/hecks/hecks/adapters/shell.adapter +7 -0
  204. data/lib/hecks/hecks/adapters/shell.rb +49 -0
  205. data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
  206. data/lib/hecks/hecks/adapters/terminal.rb +74 -0
  207. data/lib/hecks/hecks/codebase.behaviors +172 -0
  208. data/lib/hecks/hecks/codebase.bluebook +2453 -0
  209. data/lib/hecks/hecks/context_map.hecksagon +13 -0
  210. data/lib/hecks/hecks/custodian.behaviors +179 -0
  211. data/lib/hecks/hecks/custodian.bluebook +1847 -0
  212. data/lib/hecks/hecks/deploy.behaviors +74 -0
  213. data/lib/hecks/hecks/deploy.world +12 -0
  214. data/lib/hecks/hecks/environments/memory.world +10 -0
  215. data/lib/hecks/hecks/governance.world +7 -0
  216. data/lib/hecks/hecks/hecks.behaviors +62 -0
  217. data/lib/hecks/hecks/hecks.bluebook +124 -0
  218. data/lib/hecks/hecks/hecks.hecksagon +390 -0
  219. data/lib/hecks/hecks/hecks.world +42 -0
  220. data/lib/hecks/kernel_capabilities.rb +194 -0
  221. data/lib/hecks/language/bluebook/bluebook.bluebook +11 -0
  222. data/lib/hecks/language/bluebook/query.bluebook +7 -0
  223. data/lib/hecks/language/bluebook/vocabulary.bluebook +4 -4
  224. data/lib/hecks/language/hecksagon/domain_port.bluebook +10 -0
  225. data/lib/hecks/language/hecksagon/hecksagon.bluebook +20 -0
  226. data/lib/hecks/mcp_stdio_guard.rb +2 -2
  227. data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
  228. data/lib/hecks/persistence_legacy_fixture.rb +113 -0
  229. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +8 -5
  230. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +4 -1
  231. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +15 -2
  232. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +1 -1
  233. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +1 -1
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +1 -1
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +32 -15
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +15 -5
  237. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
  238. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +1 -1
  239. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +43 -24
  240. data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
  241. data/lib/hecks/ports/persistence/state_codec.rb +24 -5
  242. data/lib/hecks/projection_files.rb +285 -0
  243. data/lib/hecks/projections/bootstrap_table.rb +1 -1
  244. data/lib/hecks/projections/deploy/fargate.rb +5 -5
  245. data/lib/hecks/projections/deploy/lambda.rb +43 -32
  246. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  247. data/lib/hecks/projections/deploy/preview/template.rb +1 -1
  248. data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
  249. data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
  250. data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
  251. data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
  252. data/lib/hecks/projections/deploy/shared.rb +1 -1
  253. data/lib/hecks/projections/diagrams.rb +3 -3
  254. data/lib/hecks/projections/model/deviations.rb +1 -1
  255. data/lib/hecks/projections/parser_table.rb +4 -4
  256. data/lib/hecks/projections/reference.rb +2 -3
  257. data/lib/hecks/projections/rust_vocabulary.rb +1 -1
  258. data/lib/hecks/projector/cli_projector.rb +106 -37
  259. data/lib/hecks/projector.rb +1 -1
  260. data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
  261. data/lib/hecks/quality_control/adapters/agent.rb +58 -0
  262. data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
  263. data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
  264. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
  265. data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
  266. data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
  267. data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
  268. data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
  269. data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
  270. data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
  271. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
  272. data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
  273. data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
  274. data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
  275. data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
  276. data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
  277. data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
  278. data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
  279. data/lib/hecks/quality_control/cli/child.rb +45 -0
  280. data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
  281. data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
  282. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
  283. data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
  284. data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
  285. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
  286. data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
  287. data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
  288. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
  289. data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
  290. data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
  291. data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
  292. data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
  293. data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
  294. data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
  295. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
  296. data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
  297. data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
  298. data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
  299. data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
  300. data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
  301. data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
  302. data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
  303. data/lib/hecks/query_ir.rb +346 -0
  304. data/lib/hecks/query_ir_mcp.rb +198 -0
  305. data/lib/hecks/release/runner/ci_publisher.rb +2 -2
  306. data/lib/hecks/release/runner/clean_tree.rb +42 -0
  307. data/lib/hecks/release/runner/console.rb +6 -0
  308. data/lib/hecks/release/runner/gem_publisher.rb +14 -7
  309. data/lib/hecks/release/runner/npm_publisher.rb +6 -36
  310. data/lib/hecks/release/runner/preflight.rb +26 -2
  311. data/lib/hecks/release/runner/published.rb +8 -26
  312. data/lib/hecks/release/runner/tagger.rb +30 -15
  313. data/lib/hecks/release/runner.rb +57 -6
  314. data/lib/hecks/router/namespace_installer.rb +3 -3
  315. data/lib/hecks/runtime/adapter_lookup.rb +124 -0
  316. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +4 -0
  317. data/lib/hecks/runtime/dependency_planning.rb +20 -2
  318. data/lib/hecks/runtime/dispatcher.rb +53 -3
  319. data/lib/hecks/runtime/interpreting.rb +3 -0
  320. data/lib/hecks/runtime/loader.rb +65 -12
  321. data/lib/hecks/runtime/outbox.rb +1 -1
  322. data/lib/hecks/runtime/policy_interpreter.rb +5 -2
  323. data/lib/hecks/runtime/port_operation_interpreter.rb +2 -10
  324. data/lib/hecks/runtime/query_interpreter.rb +77 -0
  325. data/lib/hecks/runtime/reaction_outcome.rb +89 -0
  326. data/lib/hecks/runtime/refusal_wording.rb +23 -1
  327. data/lib/hecks/runtime/registry/verification.rb +163 -4
  328. data/lib/hecks/runtime/registry.rb +57 -3
  329. data/lib/hecks/runtime/remote_dispatcher.rb +31 -2
  330. data/lib/hecks/runtime/value/coercion.rb +23 -135
  331. data/lib/hecks/runtime/value/field_checks.rb +172 -0
  332. data/lib/hecks/runtime/value.rb +4 -1
  333. data/lib/hecks/runtime.rb +20 -6
  334. data/lib/hecks/rust_build/conformance.rb +158 -0
  335. data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
  336. data/lib/hecks/rust_build/coverage.rb +218 -0
  337. data/lib/hecks/rust_build/native_build.rb +124 -0
  338. data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
  339. data/lib/hecks/rust_build/project_rust.rb +332 -0
  340. data/lib/hecks/rust_build/wasm.rb +105 -0
  341. data/lib/hecks/rust_build/wasm_browser.rb +113 -0
  342. data/lib/hecks/rust_build.rb +144 -0
  343. data/lib/hecks/storehouse.rb +16 -16
  344. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +2 -2
  345. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +1 -1
  346. data/lib/hecks/three_zero/forms.yml +127 -0
  347. data/lib/hecks/three_zero.rb +12 -0
  348. data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
  349. data/lib/hecks/tools/comment_style.rb +1070 -0
  350. data/lib/hecks/tools/corpus_report.rb +87 -0
  351. data/lib/hecks/tools/deploy_recipe.rb +255 -0
  352. data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
  353. data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
  354. data/lib/hecks/tools/era_projection_backfill.rb +94 -0
  355. data/lib/hecks/tools/era_reattest.rb +146 -0
  356. data/lib/hecks/tools/evolve_run.rb +189 -0
  357. data/lib/hecks/tools/fuzz_sweep.rb +373 -0
  358. data/lib/hecks/tools/heki_compaction.rb +100 -0
  359. data/lib/hecks/tools/hoist_local_givens.rb +246 -0
  360. data/lib/hecks/tools/journal_compaction.rb +89 -0
  361. data/lib/hecks/tools/oidc_manifests.rb +70 -0
  362. data/lib/hecks/tools/query_ir_run.rb +81 -0
  363. data/lib/hecks/tools/regeneration_run.rb +166 -0
  364. data/lib/hecks/tools/rust_comment_style.rb +642 -0
  365. data/lib/hecks/tools/sequence_script.rb +62 -0
  366. data/lib/hecks/tools/tail_merge.rb +117 -0
  367. data/lib/hecks/tools/tenant_provisioning.rb +142 -0
  368. data/lib/hecks/tools/translation_audit.rb +208 -0
  369. data/lib/hecks/tools/translation_scaffold.rb +131 -0
  370. data/lib/hecks/tools.rb +86 -0
  371. data/lib/hecks/version.rb +1 -1
  372. data/lib/hecks.rb +32 -15
  373. data/qa/settings.yml +66 -0
  374. data/rust/.cargo/config.toml +6 -0
  375. data/rust/.gitignore +2 -0
  376. data/rust/Cargo.lock +54 -0
  377. data/rust/Cargo.toml +61 -0
  378. data/rust/build/.cargo/config.toml +3 -0
  379. data/rust/build/.gitignore +1 -0
  380. data/rust/build/Cargo.lock +7 -0
  381. data/rust/build/Cargo.toml +19 -0
  382. data/rust/build/src/build_artifact.rs +47 -0
  383. data/rust/build/src/cargo_sync.rs +248 -0
  384. data/rust/build/src/json.rs +421 -0
  385. data/rust/build/src/lineage_pass.rs +285 -0
  386. data/rust/build/src/main.rs +51 -0
  387. data/rust/build/src/optional_pass.rs +150 -0
  388. data/rust/build/src/pipeline.rs +264 -0
  389. data/rust/build/src/reserved_names.rs +76 -0
  390. data/rust/build/src/resolve.rs +124 -0
  391. data/rust/build/src/root.rs +25 -0
  392. data/rust/build/src/sidecars.rs +73 -0
  393. data/rust/build/src/subprocess.rs +51 -0
  394. data/rust/build/src/tmp.rs +31 -0
  395. data/rust/codegen/.cargo/config.toml +3 -0
  396. data/rust/codegen/.gitignore +1 -0
  397. data/rust/codegen/Cargo.lock +7 -0
  398. data/rust/codegen/Cargo.toml +20 -0
  399. data/rust/codegen/src/attr.rs +32 -0
  400. data/rust/codegen/src/bridging.rs +481 -0
  401. data/rust/codegen/src/commands.rs +1226 -0
  402. data/rust/codegen/src/constraints.rs +109 -0
  403. data/rust/codegen/src/dependency_planning.rs +209 -0
  404. data/rust/codegen/src/domain_generator.rs +1288 -0
  405. data/rust/codegen/src/exemplar.rs +230 -0
  406. data/rust/codegen/src/expr_emitter.rs +87 -0
  407. data/rust/codegen/src/fielded.rs +192 -0
  408. data/rust/codegen/src/hecks_naming.rs +33 -0
  409. data/rust/codegen/src/json.rs +335 -0
  410. data/rust/codegen/src/json_codec.rs +697 -0
  411. data/rust/codegen/src/literal.rs +207 -0
  412. data/rust/codegen/src/main.rs +290 -0
  413. data/rust/codegen/src/manifest.rs +227 -0
  414. data/rust/codegen/src/mutations.rs +784 -0
  415. data/rust/codegen/src/naming.rs +286 -0
  416. data/rust/codegen/src/ports.rs +208 -0
  417. data/rust/codegen/src/prelude.rs +116 -0
  418. data/rust/codegen/src/queries.rs +786 -0
  419. data/rust/codegen/src/reactions.rs +532 -0
  420. data/rust/codegen/src/read_models.rs +697 -0
  421. data/rust/codegen/src/reference_specs.rs +40 -0
  422. data/rust/codegen/src/registry.rs +966 -0
  423. data/rust/codegen/src/reserved_names.rs +76 -0
  424. data/rust/codegen/src/shared.rs +93 -0
  425. data/rust/codegen/src/skip_reason.rs +25 -0
  426. data/rust/codegen/src/types.rs +362 -0
  427. data/rust/host/.cargo/config.toml +3 -0
  428. data/rust/host/.gitignore +1 -0
  429. data/rust/host/Cargo.lock +4297 -0
  430. data/rust/host/Cargo.toml +61 -0
  431. data/rust/host/HECKS_RELEASE +1 -0
  432. data/rust/host/rds-ca-bundle.pem +2736 -0
  433. data/rust/host/src/api.rs +1596 -0
  434. data/rust/host/src/approval.rs +652 -0
  435. data/rust/host/src/auth.rs +1287 -0
  436. data/rust/host/src/bin/expr_harness.rs +46 -0
  437. data/rust/host/src/bin/lineage_harness.rs +119 -0
  438. data/rust/host/src/bin/mint_harness.rs +135 -0
  439. data/rust/host/src/checkout.rs +265 -0
  440. data/rust/host/src/dispatch.rs +1443 -0
  441. data/rust/host/src/expr_json.rs +1117 -0
  442. data/rust/host/src/field_hints.rs +52 -0
  443. data/rust/host/src/ir.rs +733 -0
  444. data/rust/host/src/journal.rs +874 -0
  445. data/rust/host/src/lambda_client.rs +378 -0
  446. data/rust/host/src/log.rs +147 -0
  447. data/rust/host/src/main.rs +474 -0
  448. data/rust/host/src/mint.rs +1865 -0
  449. data/rust/host/src/payments/keystore.rs +330 -0
  450. data/rust/host/src/payments/tests.rs +1400 -0
  451. data/rust/host/src/payments.rs +767 -0
  452. data/rust/host/src/presentation.rs +698 -0
  453. data/rust/host/src/presentation_write.rs +1431 -0
  454. data/rust/host/src/query_step.rs +149 -0
  455. data/rust/host/src/rate_limit.rs +904 -0
  456. data/rust/host/src/reference_transform.rs +241 -0
  457. data/rust/host/src/reference_validate.rs +338 -0
  458. data/rust/host/src/resend.rs +296 -0
  459. data/rust/host/src/secrets.rs +106 -0
  460. data/rust/host/src/server.rs +663 -0
  461. data/rust/host/src/storage_shape.rs +175 -0
  462. data/rust/host/src/test_pg.rs +40 -0
  463. data/rust/host/src/ui_schema.rs +1351 -0
  464. data/rust/host/src/wasm_runner.rs +191 -0
  465. data/rust/host/src/web/newsletter/cooldown.rs +126 -0
  466. data/rust/host/src/web/newsletter/tests.rs +104 -0
  467. data/rust/host/src/web/newsletter.rs +310 -0
  468. data/rust/host/src/web/newsletter_send.rs +357 -0
  469. data/rust/host/src/web/registrations.rs +1505 -0
  470. data/rust/host/src/web.rs +2937 -0
  471. data/rust/lsp/.gitignore +1 -0
  472. data/rust/lsp/Cargo.lock +7 -0
  473. data/rust/lsp/Cargo.toml +16 -0
  474. data/rust/lsp/README.md +133 -0
  475. data/rust/lsp/src/diagnostics.rs +165 -0
  476. data/rust/lsp/src/json.rs +385 -0
  477. data/rust/lsp/src/main.rs +399 -0
  478. data/rust/lsp/src/outline.rs +177 -0
  479. data/rust/lsp/src/rpc.rs +67 -0
  480. data/rust/parser/.cargo/config.toml +5 -0
  481. data/rust/parser/.gitignore +1 -0
  482. data/rust/parser/Cargo.lock +7 -0
  483. data/rust/parser/Cargo.toml +21 -0
  484. data/rust/parser/src/build/closed_sets.rs +27 -0
  485. data/rust/parser/src/build/identity.rs +276 -0
  486. data/rust/parser/src/build/mod.rs +12 -0
  487. data/rust/parser/src/build/naming.rs +141 -0
  488. data/rust/parser/src/build/pattern_subset.rs +161 -0
  489. data/rust/parser/src/build/query_derive.rs +72 -0
  490. data/rust/parser/src/build/query_inference.rs +269 -0
  491. data/rust/parser/src/build/query_options.rs +100 -0
  492. data/rust/parser/src/build/read_model.rs +94 -0
  493. data/rust/parser/src/build/references.rs +32 -0
  494. data/rust/parser/src/canonical.rs +114 -0
  495. data/rust/parser/src/diag.rs +55 -0
  496. data/rust/parser/src/emit.rs +953 -0
  497. data/rust/parser/src/expr/ast_json.rs +147 -0
  498. data/rust/parser/src/expr/evaluator.rs +81 -0
  499. data/rust/parser/src/expr/mod.rs +84 -0
  500. data/rust/parser/src/expr/resolver.rs +497 -0
  501. data/rust/parser/src/ir.rs +387 -0
  502. data/rust/parser/src/keywords.rs +585 -0
  503. data/rust/parser/src/lex.rs +662 -0
  504. data/rust/parser/src/main.rs +252 -0
  505. data/rust/parser/src/parse/aggregate.rs +612 -0
  506. data/rust/parser/src/parse/chapter.rs +517 -0
  507. data/rust/parser/src/parse/command.rs +637 -0
  508. data/rust/parser/src/parse/domain_port.rs +127 -0
  509. data/rust/parser/src/parse/entity.rs +527 -0
  510. data/rust/parser/src/parse/file.rs +67 -0
  511. data/rust/parser/src/parse/hecksagon.rs +231 -0
  512. data/rust/parser/src/parse/lifecycle.rs +162 -0
  513. data/rust/parser/src/parse/mod.rs +1262 -0
  514. data/rust/parser/src/parse/policy.rs +87 -0
  515. data/rust/parser/src/parse/process_manager.rs +305 -0
  516. data/rust/parser/src/parse/query.rs +100 -0
  517. data/rust/parser/src/parse/read_model.rs +214 -0
  518. data/rust/parser/src/parse/value_object.rs +250 -0
  519. data/rust/parser/src/ruby_value.rs +422 -0
  520. data/rust/project/bridging.rb +257 -0
  521. data/rust/project/commands.rb +877 -0
  522. data/rust/project/constraints.rb +86 -0
  523. data/rust/project/dependency_planning.rb +178 -0
  524. data/rust/project/domain_generator.rb +980 -0
  525. data/rust/project/exemplar.rb +148 -0
  526. data/rust/project/expr_emitter.rb +72 -0
  527. data/rust/project/fielded.rb +141 -0
  528. data/rust/project/json_codec.rb +641 -0
  529. data/rust/project/mutations.rb +721 -0
  530. data/rust/project/naming.rb +205 -0
  531. data/rust/project/ports.rb +65 -0
  532. data/rust/project/queries.rb +493 -0
  533. data/rust/project/reactions.rb +317 -0
  534. data/rust/project/read_models.rb +690 -0
  535. data/rust/project/reference_specs.rb +27 -0
  536. data/rust/project/registry.rb +396 -0
  537. data/rust/project/skip_reason.rb +29 -0
  538. data/rust/project/types.rb +225 -0
  539. data/rust/project/write_if_changed.rb +83 -0
  540. data/rust/project.rb +30 -0
  541. data/rust/project_rust_pipeline.rb +383 -0
  542. data/rust/src/exemplar/commands.rs +279 -0
  543. data/rust/src/exemplar/constraints.rs +18 -0
  544. data/rust/src/exemplar/fielded.rs +280 -0
  545. data/rust/src/exemplar/json.rs +277 -0
  546. data/rust/src/exemplar/mod.rs +17 -0
  547. data/rust/src/exemplar/mutations.rs +80 -0
  548. data/rust/src/exemplar/queries.rs +33 -0
  549. data/rust/src/exemplar/reactions.rs +88 -0
  550. data/rust/src/exemplar/read_models.rs +48 -0
  551. data/rust/src/exemplar/registry.rs +166 -0
  552. data/rust/src/exemplar/types.rs +44 -0
  553. data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
  554. data/rust/src/kernel/attribute_shapes/list.rs +18 -0
  555. data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
  556. data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
  557. data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
  558. data/rust/src/kernel/cli.rs +585 -0
  559. data/rust/src/kernel/dispatch.rs +1090 -0
  560. data/rust/src/kernel/expr.rs +458 -0
  561. data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
  562. data/rust/src/kernel/expression_operators/comparison.rs +48 -0
  563. data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
  564. data/rust/src/kernel/expression_operators/logical.rs +13 -0
  565. data/rust/src/kernel/expression_operators/membership.rs +18 -0
  566. data/rust/src/kernel/expression_operators/mod.rs +68 -0
  567. data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
  568. data/rust/src/kernel/expression_operators/positional.rs +126 -0
  569. data/rust/src/kernel/expression_operators/presence.rs +101 -0
  570. data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
  571. data/rust/src/kernel/expression_operators/sized.rs +35 -0
  572. data/rust/src/kernel/expression_operators/text.rs +79 -0
  573. data/rust/src/kernel/expression_operators/to_string.rs +18 -0
  574. data/rust/src/kernel/json.rs +779 -0
  575. data/rust/src/kernel/mod.rs +133 -0
  576. data/rust/src/kernel/named_query.rs +219 -0
  577. data/rust/src/kernel/orchestrate.rs +1810 -0
  578. data/rust/src/kernel/pattern.rs +307 -0
  579. data/rust/src/kernel/query_comparators.rs +206 -0
  580. data/rust/src/kernel/query_ordering.rs +103 -0
  581. data/rust/src/kernel/read_model.rs +914 -0
  582. data/rust/src/kernel/reference_lookup.rs +149 -0
  583. data/rust/src/kernel/repository.rs +468 -0
  584. data/rust/src/kernel/routing.rs +612 -0
  585. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
  586. data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
  587. data/rust/src/kernel/vocab/field_hint.rs +70 -0
  588. data/rust/src/kernel/vocab/mod.rs +20 -0
  589. data/rust/src/kernel/vocab/query_comparator.rs +65 -0
  590. data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
  591. data/rust/src/lib.rs +8 -0
  592. data/rust/src/main.rs +16 -0
  593. data/rust/web/.gitignore +1 -0
  594. data/rust/web/Cargo.lock +119 -0
  595. data/rust/web/Cargo.toml +18 -0
  596. data/rust/web/src/lib.rs +8 -0
  597. metadata +477 -12
  598. data/lib/hecks/facade/cli_door.rb +0 -96
  599. data/lib/hecks/facade/cli_runner.rb +0 -127
  600. data/lib/hecks/mcp_door_scope.rb +0 -95
@@ -0,0 +1,264 @@
1
+ //! Rust port of `RustProjectPipeline.call` (`rust/project_rust_pipeline.rb`) —
2
+ //! this crate's own orchestration core.
3
+
4
+ use std::path::{Path, PathBuf};
5
+
6
+ use crate::build_artifact;
7
+ use crate::cargo_sync;
8
+ use crate::json::Json;
9
+ use crate::lineage_pass;
10
+ use crate::optional_pass;
11
+ use crate::resolve;
12
+ use crate::sidecars;
13
+ use crate::subprocess;
14
+ use crate::tmp::TempDir;
15
+
16
+ pub struct Options {
17
+ pub build_native: bool,
18
+ pub build_wasm: bool,
19
+ }
20
+
21
+ struct Chapter {
22
+ mod_name: String,
23
+ source_label: String,
24
+ ir_text: String,
25
+ }
26
+
27
+ const META_SOURCE_LABEL: &str = "the self-hosted language (lib/hecks/language/bluebook)";
28
+
29
+ pub fn run(root: &Path, domain: &str, opts: &Options) -> Result<(), String> {
30
+ let parser_dir = root.join("rust/parser");
31
+ let codegen_dir = root.join("rust/codegen");
32
+ ensure_binaries_built(&parser_dir, &codegen_dir)?;
33
+ let parser_bin = parser_dir.join("target/debug/hecks-parse");
34
+ let codegen_bin = codegen_dir.join("target/debug/hecks-codegen");
35
+
36
+ let domain_path = PathBuf::from(domain);
37
+ let target_mod_name = domain_path
38
+ .file_name()
39
+ .and_then(|s| s.to_str())
40
+ .ok_or_else(|| format!("could not determine a module name from domain path {domain:?}"))?
41
+ .to_string();
42
+
43
+ // Same guard, same reason as hecks project_rust's own default path (R5)
44
+ // — see `cargo_sync::valid_domain_mod_name`'s own header.
45
+ if !cargo_sync::valid_domain_mod_name(&target_mod_name) {
46
+ return Err(format!(
47
+ "domain name {target_mod_name:?} (from {domain:?}) can't be used as-is — it has to double as a Rust \
48
+ module identifier and a Cargo feature name, and this one is either not a plain lowercase identifier, \
49
+ is a Rust keyword, or collides with a reserved Cargo.toml key. Rename the domain directory."
50
+ ));
51
+ }
52
+
53
+ let bluebook_directory = domain_path.join("bluebook");
54
+ let bluebook_paths = resolve::bluebook_files(&bluebook_directory)?;
55
+ let first_bluebook = bluebook_paths.first().ok_or_else(|| format!("{} has no .bluebook files", domain_path.display()))?;
56
+ let hecksagon_candidate = bluebook_directory.join(format!("{target_mod_name}.hecksagon"));
57
+ let hecksagon_path = hecksagon_candidate.is_file().then_some(hecksagon_candidate);
58
+ let world_candidate = bluebook_directory.join(format!("{target_mod_name}.world"));
59
+ let world_path = world_candidate.is_file().then_some(world_candidate);
60
+
61
+ let target_chapter_name = resolve::header_chapter_name(first_bluebook)?;
62
+ let mut target_files = Vec::new();
63
+ for path in bluebook_paths {
64
+ if resolve::header_chapter_name(&path)? == target_chapter_name {
65
+ target_files.push(path);
66
+ }
67
+ }
68
+
69
+ let (uses_framework_names, uses_embryonaut_bluebook_names) = match &hecksagon_path {
70
+ Some(p) => (
71
+ resolve::resolve_uses_framework(&parser_bin, &target_chapter_name, p)?,
72
+ resolve::resolve_uses_embryonaut_bluebook(&parser_bin, &target_chapter_name, p)?,
73
+ ),
74
+ None => (Vec::new(), Vec::new()),
75
+ };
76
+
77
+ if let Some(p) = &hecksagon_path {
78
+ target_files.push(p.clone());
79
+ }
80
+ let target_ir_text = parse_chapter_with_optionals(&parser_bin, &target_chapter_name, &target_files)?;
81
+ // Only the target chapter gets a `lineage` key — a framework chapter or
82
+ // `meta` never does, matching `derive_lineage` (Ruby) re-`JSON.parse`ing
83
+ // rather than chaining a live object through both passes.
84
+ let mut target_ir = Json::parse(&target_ir_text).map_err(|e| format!("re-parsing target ir.json for lineage: {e}"))?;
85
+ lineage_pass::run(&mut target_ir, hecksagon_path.as_deref(), world_path.as_deref(), root)?;
86
+ let target_ir_text = crate::json::write(&target_ir);
87
+
88
+ // Every other chapter's `uses_framework` names, resolved through the
89
+ // same directory listing (`resolve::framework_members`) the Ruby
90
+ // pipeline itself calls.
91
+ let framework_members = resolve::framework_members(root)?;
92
+ let mut chapters: Vec<Chapter> = Vec::new();
93
+ for fw_name in &uses_framework_names {
94
+ let fw_path = framework_members
95
+ .iter()
96
+ .find(|(name, _)| name == fw_name)
97
+ .map(|(_, path)| path.clone())
98
+ .ok_or_else(|| {
99
+ let known: Vec<&str> = framework_members.iter().map(|(n, _)| n.as_str()).collect();
100
+ format!("hecks-build: uses_framework {fw_name:?} names no known framework member — known: {}", known.join(", "))
101
+ })?;
102
+ let fw_chapter_name = resolve::header_chapter_name(&fw_path)?;
103
+ if &fw_chapter_name != fw_name {
104
+ return Err(format!(
105
+ "hecks-build: {} declares chapter {fw_chapter_name:?}, but uses_framework named {fw_name:?}",
106
+ fw_path.display()
107
+ ));
108
+ }
109
+ let fw_ir_text = parse_chapter_with_optionals(&parser_bin, &fw_chapter_name, std::slice::from_ref(&fw_path))?;
110
+ chapters.push(Chapter {
111
+ mod_name: fw_name.to_lowercase(),
112
+ source_label: format!("{domain} (uses_framework {fw_name:?})"),
113
+ ir_text: fw_ir_text,
114
+ });
115
+ }
116
+
117
+ // Every vendored package's `uses_embryonaut_bluebook` names, resolved the
118
+ // same way `EmbryonautBluebook.load!` (Ruby) resolves them — without this,
119
+ // a vendored chapter would silently drop from the output.
120
+ for pkg_name in &uses_embryonaut_bluebook_names {
121
+ let pkg_files = resolve::vendored_bluebook_files(&domain_path, pkg_name)?;
122
+ let pkg_chapter_name = resolve::header_chapter_name(&pkg_files[0])?;
123
+ let expected_chapter_name = resolve::pascal(pkg_name);
124
+ if pkg_chapter_name != expected_chapter_name {
125
+ return Err(format!(
126
+ "hecks-build: {} declares chapter {pkg_chapter_name:?}, but uses_embryonaut_bluebook {pkg_name:?} \
127
+ expects {expected_chapter_name:?}",
128
+ pkg_files[0].display()
129
+ ));
130
+ }
131
+ let mut pkg_bluebooks = Vec::new();
132
+ for path in &pkg_files {
133
+ if resolve::header_chapter_name(path)? == pkg_chapter_name {
134
+ pkg_bluebooks.push(path.clone());
135
+ }
136
+ }
137
+ let pkg_ir_text = parse_chapter_with_optionals(&parser_bin, &pkg_chapter_name, &pkg_bluebooks)?;
138
+ chapters.push(Chapter {
139
+ // Derived from the declared chapter name (asserted equal to
140
+ // `expected_chapter_name` above), not the raw `pkg_name` — that
141
+ // would diverge the moment a package name has an underscore.
142
+ mod_name: expected_chapter_name.to_lowercase(),
143
+ source_label: format!("{domain} (uses_embryonaut_bluebook {pkg_name:?})"),
144
+ ir_text: pkg_ir_text,
145
+ });
146
+ }
147
+
148
+ // Guards against a `uses_framework`- and a `uses_embryonaut_bluebook`-
149
+ // derived entry sharing a `mod_name`, which would silently overwrite one
150
+ // chapter's sidecars with another's.
151
+ {
152
+ let mut seen: Vec<&str> = Vec::new();
153
+ for c in &chapters {
154
+ if seen.contains(&c.mod_name.as_str()) {
155
+ return Err(format!(
156
+ "hecks-build: two chapters both resolve to the same generated module {:?} — attach {} to at \
157
+ most one of them",
158
+ c.mod_name, target_chapter_name
159
+ ));
160
+ }
161
+ seen.push(&c.mod_name);
162
+ }
163
+ }
164
+
165
+ // The self-hosted language, compiled in too, under the same "Bluebook"
166
+ // chapter name.
167
+ let grammar_files = resolve::grammar_files(root)?;
168
+ let meta_ir_text = parse_chapter_with_optionals(&parser_bin, "Bluebook", &grammar_files)?;
169
+
170
+ let out_root = root.join("rust/src/generated");
171
+ std::fs::create_dir_all(&out_root).map_err(|e| format!("creating {}: {e}", out_root.display()))?;
172
+
173
+ // Scoped clearing — identical reasoning to both Ruby pipelines'
174
+ // own: multiple domains coexist on disk, so only this run's own
175
+ // directories are wiped first.
176
+ remove_dir_if_exists(&out_root.join("meta"))?;
177
+ remove_dir_if_exists(&out_root.join("active"))?;
178
+ remove_dir_if_exists(&out_root.join(&target_mod_name))?;
179
+ for c in &chapters {
180
+ remove_dir_if_exists(&out_root.join(&c.mod_name))?;
181
+ }
182
+
183
+ let tmp = TempDir::new("hecks-build-codegen")?;
184
+
185
+ let meta_ir_path = tmp.path().join("meta_ir.json");
186
+ std::fs::write(&meta_ir_path, &meta_ir_text).map_err(|e| format!("writing {}: {e}", meta_ir_path.display()))?;
187
+ run_codegen_full(&codegen_bin, &[out_root.to_string_lossy().to_string(), "meta".to_string(), META_SOURCE_LABEL.to_string(), meta_ir_path.to_string_lossy().to_string()])?;
188
+
189
+ let target_ir_path = tmp.path().join("target_ir.json");
190
+ std::fs::write(&target_ir_path, &target_ir_text).map_err(|e| format!("writing {}: {e}", target_ir_path.display()))?;
191
+
192
+ let mut codegen_args = vec![
193
+ out_root.to_string_lossy().to_string(),
194
+ target_mod_name.clone(),
195
+ domain.to_string(),
196
+ target_ir_path.to_string_lossy().to_string(),
197
+ ];
198
+ let mut chapter_ir_paths = Vec::new();
199
+ for (idx, c) in chapters.iter().enumerate() {
200
+ let ir_path = tmp.path().join(format!("chapter_{idx}_ir.json"));
201
+ std::fs::write(&ir_path, &c.ir_text).map_err(|e| format!("writing {}: {e}", ir_path.display()))?;
202
+ codegen_args.push(c.mod_name.clone());
203
+ codegen_args.push(c.source_label.clone());
204
+ codegen_args.push(ir_path.to_string_lossy().to_string());
205
+ chapter_ir_paths.push(ir_path);
206
+ }
207
+ run_codegen_full(&codegen_bin, &codegen_args)?;
208
+
209
+ sidecars::write(&out_root.join("meta"), &meta_ir_text, META_SOURCE_LABEL)?;
210
+ sidecars::write(&out_root.join(&target_mod_name), &target_ir_text, domain)?;
211
+ for c in &chapters {
212
+ sidecars::write(&out_root.join(&c.mod_name), &c.ir_text, &c.source_label)?;
213
+ }
214
+
215
+ let cargo_toml_path = root.join("rust/Cargo.toml");
216
+ cargo_sync::run(&out_root, &cargo_toml_path, &target_mod_name)?;
217
+
218
+ let rust_dir = root.join("rust");
219
+ if opts.build_native {
220
+ build_artifact::build_native(&rust_dir)?;
221
+ }
222
+ if opts.build_wasm {
223
+ build_artifact::build_wasm(root, &rust_dir, &target_mod_name)?;
224
+ }
225
+
226
+ Ok(())
227
+ }
228
+
229
+ // Parses via `hecks-parse chapter`, then runs `optional_pass::run` and
230
+ // re-serializes — matching `derive_append_optionals` (Ruby).
231
+ fn parse_chapter_with_optionals(parser_bin: &Path, chapter_name: &str, files: &[PathBuf]) -> Result<String, String> {
232
+ let parser_bin_str = parser_bin.to_string_lossy().to_string();
233
+ let mut args: Vec<String> = vec!["chapter".to_string(), "--chapter".to_string(), chapter_name.to_string()];
234
+ args.extend(files.iter().map(|p| p.to_string_lossy().to_string()));
235
+ let arg_refs: Vec<&str> = args.iter().map(String::as_str).collect();
236
+
237
+ let stdout = subprocess::run_capture(&parser_bin_str, &arg_refs)?;
238
+ let mut ir = Json::parse(&stdout).map_err(|e| format!("parsing hecks-parse chapter output for {chapter_name}: {e}"))?;
239
+ optional_pass::run(&mut ir);
240
+ Ok(crate::json::write(&ir))
241
+ }
242
+
243
+ fn run_codegen_full(codegen_bin: &Path, args: &[String]) -> Result<(), String> {
244
+ let codegen_bin_str = codegen_bin.to_string_lossy().to_string();
245
+ let mut full_args: Vec<String> = vec!["full".to_string()];
246
+ full_args.extend(args.iter().cloned());
247
+ let arg_refs: Vec<&str> = full_args.iter().map(String::as_str).collect();
248
+ subprocess::run(&codegen_bin_str, &arg_refs)
249
+ }
250
+
251
+ fn remove_dir_if_exists(path: &Path) -> Result<(), String> {
252
+ if path.exists() {
253
+ std::fs::remove_dir_all(path).map_err(|e| format!("removing {}: {e}", path.display()))?;
254
+ }
255
+ Ok(())
256
+ }
257
+
258
+ // Plain `cargo build` (debug profile) in each sibling crate directory,
259
+ // output suppressed unless it fails.
260
+ fn ensure_binaries_built(parser_dir: &Path, codegen_dir: &Path) -> Result<(), String> {
261
+ subprocess::cargo_build_quiet(parser_dir)?;
262
+ subprocess::cargo_build_quiet(codegen_dir)?;
263
+ Ok(())
264
+ }
@@ -0,0 +1,76 @@
1
+ // GENERATED by hecks project_reserved_names from the RustReservedWord and
2
+ // CargoReservedName vocabularies (lib/hecks/language/bluebook/
3
+ // vocabulary.bluebook). Do not hand-edit — re-run hecks project_reserved_names.
4
+
5
+ /// The `RustReservedWord` vocabulary, 49 entries.
6
+ pub const RUST_KEYWORDS: &[&str] = &[
7
+ "as",
8
+ "break",
9
+ "const",
10
+ "continue",
11
+ "crate",
12
+ "dyn",
13
+ "else",
14
+ "enum",
15
+ "extern",
16
+ "false",
17
+ "fn",
18
+ "for",
19
+ "if",
20
+ "impl",
21
+ "in",
22
+ "let",
23
+ "loop",
24
+ "match",
25
+ "mod",
26
+ "move",
27
+ "mut",
28
+ "pub",
29
+ "ref",
30
+ "return",
31
+ "self",
32
+ "Self",
33
+ "static",
34
+ "struct",
35
+ "super",
36
+ "trait",
37
+ "true",
38
+ "type",
39
+ "unsafe",
40
+ "use",
41
+ "where",
42
+ "while",
43
+ "abstract",
44
+ "become",
45
+ "box",
46
+ "do",
47
+ "final",
48
+ "macro",
49
+ "override",
50
+ "priv",
51
+ "typeof",
52
+ "unsized",
53
+ "virtual",
54
+ "yield",
55
+ "try",
56
+ ];
57
+
58
+ /// The `CargoReservedName` vocabulary, 16 entries.
59
+ pub const CARGO_RESERVED_DOMAIN_NAMES: &[&str] = &[
60
+ "name",
61
+ "version",
62
+ "edition",
63
+ "path",
64
+ "authors",
65
+ "license",
66
+ "description",
67
+ "default",
68
+ "features",
69
+ "package",
70
+ "lib",
71
+ "bin",
72
+ "dependencies",
73
+ "dev-dependencies",
74
+ "build-dependencies",
75
+ "workspace",
76
+ ];
@@ -0,0 +1,124 @@
1
+ //! Chapter resolution: header names, framework members and vendored packages, found by text
2
+ //! scanning and directory listing rather than by executing any DSL.
3
+
4
+ use std::path::{Path, PathBuf};
5
+
6
+ use crate::json::Json;
7
+ use crate::subprocess;
8
+
9
+ pub fn bluebook_files(directory: &Path) -> Result<Vec<PathBuf>, String> {
10
+ let mut files = Vec::new();
11
+ for entry in std::fs::read_dir(directory).map_err(|e| format!("reading {}: {e}", directory.display()))? {
12
+ let path = entry.map_err(|e| format!("reading {}: {e}", directory.display()))?.path();
13
+ if path.extension().and_then(|extension| extension.to_str()) == Some("bluebook") {
14
+ files.push(path);
15
+ }
16
+ }
17
+ files.sort();
18
+ Ok(files)
19
+ }
20
+
21
+ // Plain text scan of the `Hecks.bluebook "Name"` line; the file is never executed.
22
+ pub fn header_chapter_name(path: &Path) -> Result<String, String> {
23
+ let text = std::fs::read_to_string(path).map_err(|e| format!("reading {}: {e}", path.display()))?;
24
+ for line in text.lines() {
25
+ let trimmed = line.trim_start();
26
+ if let Some(rest) = trimmed.strip_prefix("Hecks.bluebook") {
27
+ if let Some(name) = extract_quoted(rest) {
28
+ return Ok(name);
29
+ }
30
+ }
31
+ }
32
+ Err(format!("{} has no 'Hecks.bluebook \"Name\"' header", path.display()))
33
+ }
34
+
35
+ fn extract_quoted(rest: &str) -> Option<String> {
36
+ let after_ws = rest.trim_start();
37
+ if !after_ws.starts_with('"') {
38
+ return None;
39
+ }
40
+ let inner = &after_ws[1..];
41
+ let end = inner.find('"')?;
42
+ Some(inner[..end].to_string())
43
+ }
44
+
45
+ // A directory listing, so a member is never missing from a hand-kept list.
46
+ pub fn framework_members(root: &Path) -> Result<Vec<(String, PathBuf)>, String> {
47
+ let dir = root.join("lib/hecks/framework/bluebook");
48
+ let mut members = Vec::new();
49
+ for entry in std::fs::read_dir(&dir).map_err(|e| format!("reading {}: {e}", dir.display()))? {
50
+ let entry = entry.map_err(|e| format!("reading {}: {e}", dir.display()))?;
51
+ let path = entry.path();
52
+ if path.extension().and_then(|e| e.to_str()) != Some("bluebook") {
53
+ continue;
54
+ }
55
+ let stem = path.file_stem().and_then(|s| s.to_str()).unwrap_or("").to_string();
56
+ members.push((pascal(&stem), path));
57
+ }
58
+ members.sort();
59
+ Ok(members)
60
+ }
61
+
62
+ pub fn pascal(text: &str) -> String {
63
+ text.split('_')
64
+ .map(|part| {
65
+ let mut chars = part.chars();
66
+ match chars.next() {
67
+ Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
68
+ None => String::new(),
69
+ }
70
+ })
71
+ .collect()
72
+ }
73
+
74
+ // Discovery, not a mirrored filename list, so a new concept cannot drift from this pipeline.
75
+ pub fn grammar_files(root: &Path) -> Result<Vec<PathBuf>, String> {
76
+ let dir = root.join("lib/hecks/language/bluebook");
77
+ bluebook_files(&dir)
78
+ }
79
+
80
+ pub fn resolve_uses_framework(parser_bin: &Path, chapter_name: &str, hecksagon_path: &Path) -> Result<Vec<String>, String> {
81
+ resolve_json(parser_bin, chapter_name, hecksagon_path, "uses_framework")
82
+ }
83
+
84
+ pub fn resolve_uses_embryonaut_bluebook(parser_bin: &Path, chapter_name: &str, hecksagon_path: &Path) -> Result<Vec<String>, String> {
85
+ resolve_json(parser_bin, chapter_name, hecksagon_path, "uses_embryonaut_bluebook")
86
+ }
87
+
88
+ fn resolve_json(parser_bin: &Path, chapter_name: &str, hecksagon_path: &Path, key: &str) -> Result<Vec<String>, String> {
89
+ let parser_bin_str = parser_bin.to_string_lossy().to_string();
90
+ let hecksagon_str = hecksagon_path.to_string_lossy().to_string();
91
+ let out = subprocess::run_capture(&parser_bin_str, &["resolve", "--chapter", chapter_name, &hecksagon_str])?;
92
+ let json = Json::parse(&out).map_err(|e| format!("parsing 'hecks-parse resolve' output: {e}\n{out}"))?;
93
+ let names = json.get(key).map(Json::each).unwrap_or(&[]);
94
+ Ok(names.iter().filter_map(Json::as_str).map(str::to_string).collect())
95
+ }
96
+
97
+ pub fn vendored_bluebook_files(domain: &Path, pkg_name: &str) -> Result<Vec<PathBuf>, String> {
98
+ let dir = domain.join("vendor").join("embryonaut_bluebooks").join(pkg_name).join("bluebook");
99
+ if !dir.is_dir() {
100
+ return Err(format!(
101
+ "uses_embryonaut_bluebook {pkg_name:?} names no vendored bluebook at {} — run hecks vendor {pkg_name}",
102
+ dir.display()
103
+ ));
104
+ }
105
+ bluebook_files(&dir)
106
+ }
107
+
108
+ #[cfg(test)]
109
+ mod tests {
110
+ use super::*;
111
+
112
+ #[test]
113
+ fn pascal_cases_snake_case_stems() {
114
+ assert_eq!(pascal("governance"), "Governance");
115
+ assert_eq!(pascal("console_settings"), "ConsoleSettings");
116
+ assert_eq!(pascal("identity"), "Identity");
117
+ }
118
+
119
+ #[test]
120
+ fn extracts_the_quoted_chapter_name() {
121
+ assert_eq!(extract_quoted(r#" "Pizzas""#), Some("Pizzas".to_string()));
122
+ assert_eq!(extract_quoted(r#" "Console Settings" do"#), Some("Console Settings".to_string()));
123
+ }
124
+ }
@@ -0,0 +1,25 @@
1
+ //! Finds the repo root by walking up from the current directory to `hecks.gemspec`.
2
+ //! Not `current_exe()`, which would tie the crate to its build output layout.
3
+
4
+ use std::path::{Path, PathBuf};
5
+
6
+ pub fn find() -> Result<PathBuf, String> {
7
+ let start = std::env::current_dir().map_err(|e| format!("reading current directory: {e}"))?;
8
+ find_from(&start)
9
+ }
10
+
11
+ fn find_from(start: &Path) -> Result<PathBuf, String> {
12
+ let mut dir = start.to_path_buf();
13
+ loop {
14
+ if dir.join("hecks.gemspec").is_file() {
15
+ return Ok(dir);
16
+ }
17
+ if !dir.pop() {
18
+ return Err(format!(
19
+ "could not find the hecks repo root (no 'hecks.gemspec' found walking up from {}) — \
20
+ run hecks-build from inside the repo",
21
+ start.display()
22
+ ));
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,73 @@
1
+ //! Writes each chapter's `ir.json` and `metadata.rs` sidecars.
2
+
3
+ /// Renders `text` as a Rust string literal. Not Ruby's `String#inspect`, whose `\#{` and bare
4
+ /// `\uXXXX` escapes are not valid Rust.
5
+ pub fn rust_string_literal(text: &str) -> String {
6
+ let mut out = String::with_capacity(text.len() + 2);
7
+ out.push('"');
8
+ for ch in text.chars() {
9
+ match ch {
10
+ '"' => out.push_str("\\\""),
11
+ '\\' => out.push_str("\\\\"),
12
+ '\n' => out.push_str("\\n"),
13
+ '\r' => out.push_str("\\r"),
14
+ '\t' => out.push_str("\\t"),
15
+ c if (c as u32) < 0x20 || (c as u32) == 0x7f => {
16
+ out.push_str(&format!("\\u{{{:x}}}", c as u32));
17
+ }
18
+ c => out.push(c),
19
+ }
20
+ }
21
+ out.push('"');
22
+ out
23
+ }
24
+
25
+ pub fn write(mod_dir: &std::path::Path, ir_text: &str, source_label: &str) -> Result<(std::path::PathBuf, std::path::PathBuf), String> {
26
+ std::fs::create_dir_all(mod_dir).map_err(|e| format!("creating {}: {e}", mod_dir.display()))?;
27
+
28
+ let ir_json_path = mod_dir.join("ir.json");
29
+ std::fs::write(&ir_json_path, ir_text).map_err(|e| format!("writing {}: {e}", ir_json_path.display()))?;
30
+
31
+ let metadata_path = mod_dir.join("metadata.rs");
32
+ let mut contents = String::new();
33
+ // Attribution text matches both Ruby pipelines so generated trees diff clean.
34
+ contents.push_str("// GENERATED by hecks project_rust — ");
35
+ contents.push_str(source_label);
36
+ contents.push_str("'s own canonical IR,\n");
37
+ contents.push_str("// embedded for runtime self-description. Not read by any dispatch\n");
38
+ contents.push_str("// function in this module — introspection only.\n");
39
+ contents.push_str("pub const IR_JSON: &str = ");
40
+ contents.push_str(&rust_string_literal(ir_text));
41
+ contents.push_str(";\n");
42
+ std::fs::write(&metadata_path, contents).map_err(|e| format!("writing {}: {e}", metadata_path.display()))?;
43
+
44
+ Ok((ir_json_path, metadata_path))
45
+ }
46
+
47
+ #[cfg(test)]
48
+ mod tests {
49
+ use super::*;
50
+
51
+ #[test]
52
+ fn escapes_quotes_backslashes_and_newlines() {
53
+ assert_eq!(rust_string_literal("abc\ndef"), "\"abc\\ndef\"");
54
+ assert_eq!(rust_string_literal("tab\there"), "\"tab\\there\"");
55
+ assert_eq!(rust_string_literal("quote\"here"), "\"quote\\\"here\"");
56
+ assert_eq!(rust_string_literal("back\\slash"), "\"back\\\\slash\"");
57
+ }
58
+
59
+ // A literal `#{` or `#@` passes through unchanged; Ruby's `\#{` is not a valid Rust escape.
60
+ // escape exists at all).
61
+ #[test]
62
+ fn leaves_a_literal_hash_brace_and_hash_at_untouched() {
63
+ assert_eq!(rust_string_literal("cost #{threshold}"), "\"cost #{threshold}\"");
64
+ assert_eq!(rust_string_literal("ivar #@foo"), "\"ivar #@foo\"");
65
+ }
66
+
67
+ // A control character becomes a braced `\u{...}`; Ruby's bare `\uXXXX` is not valid Rust.
68
+ #[test]
69
+ fn escapes_control_characters_as_braced_lowercase_hex() {
70
+ assert_eq!(rust_string_literal("\u{1}\u{1f}"), "\"\\u{1}\\u{1f}\"");
71
+ assert_eq!(rust_string_literal("\u{7f}"), "\"\\u{7f}\"");
72
+ }
73
+ }
@@ -0,0 +1,51 @@
1
+ //! Subprocess helpers: run a command, check its exit status, surface stderr on failure.
2
+ //! The crate reaches `hecks-parse`, `hecks-codegen` and `cargo` only through these.
3
+
4
+ use std::path::Path;
5
+ use std::process::{Command, Stdio};
6
+
7
+ pub fn run_capture(program: &str, args: &[&str]) -> Result<String, String> {
8
+ let output = Command::new(program).args(args).output().map_err(|e| format!("running {program} {}: {e}", args.join(" ")))?;
9
+ if !output.status.success() {
10
+ return Err(format!(
11
+ "{program} {} failed:\n{}",
12
+ args.join(" "),
13
+ String::from_utf8_lossy(&output.stderr)
14
+ ));
15
+ }
16
+ String::from_utf8(output.stdout).map_err(|e| format!("{program} {}: stdout was not valid UTF-8: {e}", args.join(" ")))
17
+ }
18
+
19
+ pub fn run(program: &str, args: &[&str]) -> Result<(), String> {
20
+ let status = Command::new(program).args(args).status().map_err(|e| format!("running {program} {}: {e}", args.join(" ")))?;
21
+ if !status.success() {
22
+ return Err(format!("{program} {} failed", args.join(" ")));
23
+ }
24
+ Ok(())
25
+ }
26
+
27
+ pub fn run_in(dir: &Path, program: &str, args: &[&str]) -> Result<(), String> {
28
+ let status = Command::new(program)
29
+ .args(args)
30
+ .current_dir(dir)
31
+ .status()
32
+ .map_err(|e| format!("running {program} {} in {}: {e}", args.join(" "), dir.display()))?;
33
+ if !status.success() {
34
+ return Err(format!("{program} {} failed in {}", args.join(" "), dir.display()));
35
+ }
36
+ Ok(())
37
+ }
38
+
39
+ pub fn cargo_build_quiet(dir: &Path) -> Result<(), String> {
40
+ let status = Command::new("cargo")
41
+ .arg("build")
42
+ .current_dir(dir)
43
+ .stdout(Stdio::null())
44
+ .stderr(Stdio::inherit())
45
+ .status()
46
+ .map_err(|e| format!("running cargo build in {}: {e}", dir.display()))?;
47
+ if !status.success() {
48
+ return Err(format!("cargo build failed in {} — run it there directly to see why", dir.display()));
49
+ }
50
+ Ok(())
51
+ }
@@ -0,0 +1,31 @@
1
+ //! A minimal, dependency-free RAII temp directory — `Dir.mktmpdir`'s
2
+ //! Rust equivalent, hand-rolled rather than pulling in the `tempfile`
3
+ //! crate (this crate's own no-dependency discipline, matching
4
+ //! `rust/parser`'s and `rust/codegen`'s own Cargo.toml).
5
+
6
+ use std::path::{Path, PathBuf};
7
+
8
+ pub struct TempDir {
9
+ path: PathBuf,
10
+ }
11
+
12
+ impl TempDir {
13
+ pub fn new(prefix: &str) -> Result<Self, String> {
14
+ let base = std::env::temp_dir();
15
+ let pid = std::process::id();
16
+ let nanos = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|d| d.as_nanos()).unwrap_or(0);
17
+ let path = base.join(format!("{prefix}-{pid}-{nanos}"));
18
+ std::fs::create_dir_all(&path).map_err(|e| format!("creating temp dir {}: {e}", path.display()))?;
19
+ Ok(Self { path })
20
+ }
21
+
22
+ pub fn path(&self) -> &Path {
23
+ &self.path
24
+ }
25
+ }
26
+
27
+ impl Drop for TempDir {
28
+ fn drop(&mut self) {
29
+ let _ = std::fs::remove_dir_all(&self.path);
30
+ }
31
+ }
@@ -0,0 +1,3 @@
1
+ # Link with lld; this crate has no native C library dependencies.
2
+ [target.x86_64-unknown-linux-gnu]
3
+ rustflags = ["-C", "link-arg=-fuse-ld=lld"]
@@ -0,0 +1 @@
1
+ /target
@@ -0,0 +1,7 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "hecks_codegen"
7
+ version = "0.1.0"