hecks 2.9.0 → 3.0.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.
- checksums.yaml +4 -4
- data/exe/hecks +51 -6
- data/lib/hecks/adapters/driven/heki/journal.rb +1 -1
- data/lib/hecks/adapters/driven/lambda/client.rb +1 -1
- data/lib/hecks/adapters/driven/lambda.rb +1 -1
- data/lib/hecks/adapters/driven/memory.rb +16 -3
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +6 -2
- data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
- data/lib/hecks/adapters/driven/postgres.rb +4 -2
- data/lib/hecks/adapters/driven/prism.rb +41 -8
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +73 -16
- data/lib/hecks/behaviors/expectations.rb +1 -1
- data/lib/hecks/behaviors.rb +1 -1
- data/lib/hecks/bench/cli.rb +62 -0
- data/lib/hecks/bench/environment.rb +71 -0
- data/lib/hecks/bench/postgres_probe.rb +30 -0
- data/lib/hecks/bench/report.rb +76 -0
- data/lib/hecks/bench/ruby_runner.rb +93 -0
- data/lib/hecks/bench/run.rb +55 -0
- data/lib/hecks/bench/rust_runner.rb +101 -0
- data/lib/hecks/bench/stats.rb +46 -0
- data/lib/hecks/bench/suite.rb +98 -0
- data/lib/hecks/bench/workload.rb +89 -0
- data/lib/hecks/bench.rb +17 -0
- data/lib/hecks/bluebook/assembly/contracts.rb +2 -0
- data/lib/hecks/bluebook/attribute.rb +1 -1
- data/lib/hecks/bluebook/behaviour/aggregate.rb +30 -1
- data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -0
- data/lib/hecks/bluebook/chapter.rb +6 -2
- data/lib/hecks/bluebook/domain_port.rb +36 -5
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +10 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +8 -0
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -1
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +31 -3
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +122 -3
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +1 -1
- data/lib/hecks/bluebook/dsl/query_builder.rb +27 -1
- data/lib/hecks/bluebook/dsl/rule_reference.rb +1 -1
- data/lib/hecks/bluebook/dsl/world_builder.rb +29 -2
- data/lib/hecks/bluebook/expression/canonical_form.rb +1 -1
- data/lib/hecks/bluebook/expression/resolver.rb +3 -2
- data/lib/hecks/bluebook/hexagon.rb +13 -5
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +1 -0
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +4 -1
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
- data/lib/hecks/bluebook/meta_validator.rb +9 -4
- data/lib/hecks/bluebook/model_check.rb +23 -0
- data/lib/hecks/bluebook/pattern_subset.rb +38 -0
- data/lib/hecks/bluebook/query.rb +20 -5
- data/lib/hecks/bluebook/smoke_test.rb +1 -1
- data/lib/hecks/canonical_json.rb +30 -0
- data/lib/hecks/chapters.rb +102 -0
- data/lib/hecks/cli/behaviors.rb +61 -0
- data/lib/hecks/cli/canonicalise.rb +25 -0
- data/lib/hecks/cli/check_engine_agreement.rb +32 -0
- data/lib/hecks/cli/check_era.rb +88 -0
- data/lib/hecks/cli/console.rb +66 -0
- data/lib/hecks/cli/deploy_template_diff.rb +40 -0
- data/lib/hecks/cli/doc_coverage.rb +32 -0
- data/lib/hecks/cli/document.rb +2 -2
- data/lib/hecks/cli/expression_projection.rb +41 -0
- data/lib/hecks/cli/follow.rb +88 -0
- data/lib/hecks/cli/history.rb +44 -0
- data/lib/hecks/cli/ir.rb +1 -1
- data/lib/hecks/cli/mcp.rb +3 -3
- data/lib/hecks/cli/model_check.rb +7 -4
- data/lib/hecks/cli/pattern_cases.rb +47 -0
- data/lib/hecks/cli/present.rb +39 -0
- data/lib/hecks/cli/project_cli.rb +224 -32
- data/lib/hecks/cli/project_diagrams.rb +4 -3
- data/lib/hecks/cli/project_glossary.rb +44 -0
- data/lib/hecks/cli/reference.rb +46 -0
- data/lib/hecks/cli/refresh_projections.rb +44 -0
- data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
- data/lib/hecks/cli/release.rb +70 -0
- data/lib/hecks/cli/release_gem.rb +59 -0
- data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
- data/lib/hecks/cli/rspec_shard_files.rb +66 -0
- data/lib/hecks/cli/run.rb +3 -3
- data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
- data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
- data/lib/hecks/cli/shape.rb +70 -0
- data/lib/hecks/cli/smoke_http.rb +230 -0
- data/lib/hecks/cli/smoke_test.rb +5 -3
- data/lib/hecks/cli/spec_example.rb +27 -0
- data/lib/hecks/cli/statements.rb +32 -0
- data/lib/hecks/cli/stores.rb +4 -5
- data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
- data/lib/hecks/cli.rb +201 -52
- data/lib/hecks/codemod.rb +324 -0
- data/lib/hecks/corpus.rb +423 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +591 -23
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -4
- data/lib/hecks/deploy/oidc.json +82 -2
- data/lib/hecks/doc/reference.rb +351 -0
- data/lib/hecks/doors/cli_door.rb +196 -0
- data/lib/hecks/doors/cli_runner.rb +297 -0
- data/lib/hecks/{facade → doors}/command_request.rb +1 -1
- data/lib/hecks/{facade → doors}/handle.rb +2 -2
- data/lib/hecks/{facade → doors}/json_door.rb +4 -4
- data/lib/hecks/doors/launcher_options.rb +129 -0
- data/lib/hecks/{cli → doors}/mcp_door.rb +7 -7
- data/lib/hecks/doors/mcp_door_scope.rb +97 -0
- data/lib/hecks/{facade/surface → doors/ruby_door}/aggregate_door.rb +8 -3
- data/lib/hecks/{facade/surface → doors/ruby_door}/chapter.rb +3 -3
- data/lib/hecks/{facade/surface.rb → doors/ruby_door.rb} +36 -5
- data/lib/hecks/doors.rb +61 -0
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +1 -1
- data/lib/hecks/embryonaut_bluebook.rb +1 -1
- data/lib/hecks/engine_agreement.rb +156 -0
- data/lib/hecks/facade.rb +24 -37
- data/lib/hecks/forms/app.rb +6 -6
- data/lib/hecks/forms/banking_presentation.rb +50 -0
- data/lib/hecks/forms/field_shape.rb +2 -1
- data/lib/hecks/forms/port_argument.rb +1 -1
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
- data/lib/hecks/fuzzing/combination_miner.rb +86 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
- data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
- data/lib/hecks/fuzzing/differential.rb +156 -0
- data/lib/hecks/fuzzing/domain_generator.rb +615 -0
- data/lib/hecks/fuzzing/era_boundary.rb +71 -0
- data/lib/hecks/fuzzing/form_census.rb +136 -0
- data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
- data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
- data/lib/hecks/fuzzing/outside_world.rb +45 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
- data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
- data/lib/hecks/fuzzing/properties/guards.rb +190 -0
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
- data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
- data/lib/hecks/fuzzing/properties/querying.rb +175 -0
- data/lib/hecks/fuzzing/properties.rb +162 -0
- data/lib/hecks/fuzzing/qa_settings.rb +123 -0
- data/lib/hecks/fuzzing/replay.rb +505 -0
- data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
- data/lib/hecks/fuzzing/self_consistency.rb +339 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
- data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
- data/lib/hecks/fuzzing/shrinker.rb +166 -0
- data/lib/hecks/fuzzing/structural_skips.rb +33 -0
- data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
- data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
- data/lib/hecks/fuzzing/value_generator.rb +216 -0
- data/lib/hecks/fuzzing.rb +23 -0
- data/lib/hecks/grammar/evolve.rb +336 -0
- data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
- data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
- data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
- data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
- data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
- data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
- data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
- data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
- data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
- data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
- data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
- data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
- data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
- data/lib/hecks/hecks/adapters/git.adapter +7 -0
- data/lib/hecks/hecks/adapters/git.rb +102 -0
- data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
- data/lib/hecks/hecks/adapters/host_http.rb +65 -0
- data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
- data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
- data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
- data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
- data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
- data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
- data/lib/hecks/hecks/adapters/local_files.rb +46 -0
- data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
- data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
- data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
- data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
- data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
- data/lib/hecks/hecks/adapters/shell.adapter +7 -0
- data/lib/hecks/hecks/adapters/shell.rb +49 -0
- data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
- data/lib/hecks/hecks/adapters/terminal.rb +74 -0
- data/lib/hecks/hecks/codebase.behaviors +172 -0
- data/lib/hecks/hecks/codebase.bluebook +2453 -0
- data/lib/hecks/hecks/context_map.hecksagon +13 -0
- data/lib/hecks/hecks/custodian.behaviors +179 -0
- data/lib/hecks/hecks/custodian.bluebook +1847 -0
- data/lib/hecks/hecks/deploy.behaviors +74 -0
- data/lib/hecks/hecks/deploy.world +12 -0
- data/lib/hecks/hecks/environments/memory.world +10 -0
- data/lib/hecks/hecks/governance.world +7 -0
- data/lib/hecks/hecks/hecks.behaviors +62 -0
- data/lib/hecks/hecks/hecks.bluebook +124 -0
- data/lib/hecks/hecks/hecks.hecksagon +390 -0
- data/lib/hecks/hecks/hecks.world +42 -0
- data/lib/hecks/kernel_capabilities.rb +194 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +11 -0
- data/lib/hecks/language/bluebook/query.bluebook +7 -0
- data/lib/hecks/language/bluebook/vocabulary.bluebook +4 -4
- data/lib/hecks/language/hecksagon/domain_port.bluebook +10 -0
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +20 -0
- data/lib/hecks/mcp_stdio_guard.rb +2 -2
- data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
- data/lib/hecks/persistence_legacy_fixture.rb +113 -0
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +8 -5
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +4 -1
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +15 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +32 -15
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +6 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +43 -24
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
- data/lib/hecks/ports/persistence/state_codec.rb +24 -5
- data/lib/hecks/projection_files.rb +285 -0
- data/lib/hecks/projections/bootstrap_table.rb +1 -1
- data/lib/hecks/projections/deploy/fargate.rb +5 -5
- data/lib/hecks/projections/deploy/lambda.rb +43 -32
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/preview/template.rb +1 -1
- data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
- data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
- data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/shared.rb +1 -1
- data/lib/hecks/projections/diagrams.rb +3 -3
- data/lib/hecks/projections/model/deviations.rb +1 -1
- data/lib/hecks/projections/parser_table.rb +4 -4
- data/lib/hecks/projections/reference.rb +2 -3
- data/lib/hecks/projections/rust_vocabulary.rb +1 -1
- data/lib/hecks/projector/cli_projector.rb +106 -37
- data/lib/hecks/projector.rb +1 -1
- data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
- data/lib/hecks/quality_control/adapters/agent.rb +58 -0
- data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
- data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
- data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
- data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
- data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
- data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
- data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
- data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
- data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
- data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
- data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
- data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
- data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
- data/lib/hecks/quality_control/cli/child.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
- data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
- data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
- data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
- data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
- data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
- data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
- data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
- data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
- data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
- data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
- data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
- data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
- data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
- data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
- data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
- data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
- data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
- data/lib/hecks/query_ir.rb +346 -0
- data/lib/hecks/query_ir_mcp.rb +198 -0
- data/lib/hecks/release/runner/ci_publisher.rb +2 -2
- data/lib/hecks/release/runner/clean_tree.rb +42 -0
- data/lib/hecks/release/runner/console.rb +6 -0
- data/lib/hecks/release/runner/gem_publisher.rb +14 -7
- data/lib/hecks/release/runner/npm_publisher.rb +6 -36
- data/lib/hecks/release/runner/preflight.rb +26 -2
- data/lib/hecks/release/runner/published.rb +8 -26
- data/lib/hecks/release/runner/tagger.rb +30 -15
- data/lib/hecks/release/runner.rb +57 -6
- data/lib/hecks/router/namespace_installer.rb +3 -3
- data/lib/hecks/runtime/adapter_lookup.rb +124 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +4 -0
- data/lib/hecks/runtime/dependency_planning.rb +20 -2
- data/lib/hecks/runtime/dispatcher.rb +53 -3
- data/lib/hecks/runtime/interpreting.rb +3 -0
- data/lib/hecks/runtime/loader.rb +65 -12
- data/lib/hecks/runtime/outbox.rb +1 -1
- data/lib/hecks/runtime/policy_interpreter.rb +5 -2
- data/lib/hecks/runtime/port_operation_interpreter.rb +2 -10
- data/lib/hecks/runtime/query_interpreter.rb +77 -0
- data/lib/hecks/runtime/reaction_outcome.rb +89 -0
- data/lib/hecks/runtime/refusal_wording.rb +23 -1
- data/lib/hecks/runtime/registry/verification.rb +163 -4
- data/lib/hecks/runtime/registry.rb +57 -3
- data/lib/hecks/runtime/remote_dispatcher.rb +31 -2
- data/lib/hecks/runtime/value/coercion.rb +23 -135
- data/lib/hecks/runtime/value/field_checks.rb +172 -0
- data/lib/hecks/runtime/value.rb +4 -1
- data/lib/hecks/runtime.rb +20 -6
- data/lib/hecks/rust_build/conformance.rb +158 -0
- data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
- data/lib/hecks/rust_build/coverage.rb +218 -0
- data/lib/hecks/rust_build/native_build.rb +124 -0
- data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
- data/lib/hecks/rust_build/project_rust.rb +332 -0
- data/lib/hecks/rust_build/wasm.rb +105 -0
- data/lib/hecks/rust_build/wasm_browser.rb +113 -0
- data/lib/hecks/rust_build.rb +144 -0
- data/lib/hecks/storehouse.rb +16 -16
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +2 -2
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +1 -1
- data/lib/hecks/three_zero/forms.yml +127 -0
- data/lib/hecks/three_zero.rb +12 -0
- data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
- data/lib/hecks/tools/comment_style.rb +1070 -0
- data/lib/hecks/tools/corpus_report.rb +87 -0
- data/lib/hecks/tools/deploy_recipe.rb +255 -0
- data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
- data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
- data/lib/hecks/tools/era_projection_backfill.rb +94 -0
- data/lib/hecks/tools/era_reattest.rb +146 -0
- data/lib/hecks/tools/evolve_run.rb +189 -0
- data/lib/hecks/tools/fuzz_sweep.rb +373 -0
- data/lib/hecks/tools/heki_compaction.rb +100 -0
- data/lib/hecks/tools/hoist_local_givens.rb +246 -0
- data/lib/hecks/tools/journal_compaction.rb +89 -0
- data/lib/hecks/tools/oidc_manifests.rb +70 -0
- data/lib/hecks/tools/query_ir_run.rb +81 -0
- data/lib/hecks/tools/regeneration_run.rb +166 -0
- data/lib/hecks/tools/rust_comment_style.rb +642 -0
- data/lib/hecks/tools/sequence_script.rb +62 -0
- data/lib/hecks/tools/tail_merge.rb +117 -0
- data/lib/hecks/tools/tenant_provisioning.rb +142 -0
- data/lib/hecks/tools/translation_audit.rb +208 -0
- data/lib/hecks/tools/translation_scaffold.rb +131 -0
- data/lib/hecks/tools.rb +86 -0
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks.rb +32 -15
- data/qa/settings.yml +66 -0
- data/rust/.cargo/config.toml +6 -0
- data/rust/.gitignore +2 -0
- data/rust/Cargo.lock +54 -0
- data/rust/Cargo.toml +61 -0
- data/rust/build/.cargo/config.toml +3 -0
- data/rust/build/.gitignore +1 -0
- data/rust/build/Cargo.lock +7 -0
- data/rust/build/Cargo.toml +19 -0
- data/rust/build/src/build_artifact.rs +47 -0
- data/rust/build/src/cargo_sync.rs +248 -0
- data/rust/build/src/json.rs +421 -0
- data/rust/build/src/lineage_pass.rs +285 -0
- data/rust/build/src/main.rs +51 -0
- data/rust/build/src/optional_pass.rs +150 -0
- data/rust/build/src/pipeline.rs +264 -0
- data/rust/build/src/reserved_names.rs +76 -0
- data/rust/build/src/resolve.rs +124 -0
- data/rust/build/src/root.rs +25 -0
- data/rust/build/src/sidecars.rs +73 -0
- data/rust/build/src/subprocess.rs +51 -0
- data/rust/build/src/tmp.rs +31 -0
- data/rust/codegen/.cargo/config.toml +3 -0
- data/rust/codegen/.gitignore +1 -0
- data/rust/codegen/Cargo.lock +7 -0
- data/rust/codegen/Cargo.toml +20 -0
- data/rust/codegen/src/attr.rs +32 -0
- data/rust/codegen/src/bridging.rs +481 -0
- data/rust/codegen/src/commands.rs +1226 -0
- data/rust/codegen/src/constraints.rs +109 -0
- data/rust/codegen/src/dependency_planning.rs +209 -0
- data/rust/codegen/src/domain_generator.rs +1288 -0
- data/rust/codegen/src/exemplar.rs +230 -0
- data/rust/codegen/src/expr_emitter.rs +87 -0
- data/rust/codegen/src/fielded.rs +192 -0
- data/rust/codegen/src/hecks_naming.rs +33 -0
- data/rust/codegen/src/json.rs +335 -0
- data/rust/codegen/src/json_codec.rs +697 -0
- data/rust/codegen/src/literal.rs +207 -0
- data/rust/codegen/src/main.rs +290 -0
- data/rust/codegen/src/manifest.rs +227 -0
- data/rust/codegen/src/mutations.rs +784 -0
- data/rust/codegen/src/naming.rs +286 -0
- data/rust/codegen/src/ports.rs +208 -0
- data/rust/codegen/src/prelude.rs +116 -0
- data/rust/codegen/src/queries.rs +786 -0
- data/rust/codegen/src/reactions.rs +532 -0
- data/rust/codegen/src/read_models.rs +697 -0
- data/rust/codegen/src/reference_specs.rs +40 -0
- data/rust/codegen/src/registry.rs +966 -0
- data/rust/codegen/src/reserved_names.rs +76 -0
- data/rust/codegen/src/shared.rs +93 -0
- data/rust/codegen/src/skip_reason.rs +25 -0
- data/rust/codegen/src/types.rs +362 -0
- data/rust/host/.cargo/config.toml +3 -0
- data/rust/host/.gitignore +1 -0
- data/rust/host/Cargo.lock +4297 -0
- data/rust/host/Cargo.toml +61 -0
- data/rust/host/HECKS_RELEASE +1 -0
- data/rust/host/rds-ca-bundle.pem +2736 -0
- data/rust/host/src/api.rs +1596 -0
- data/rust/host/src/approval.rs +652 -0
- data/rust/host/src/auth.rs +1287 -0
- data/rust/host/src/bin/expr_harness.rs +46 -0
- data/rust/host/src/bin/lineage_harness.rs +119 -0
- data/rust/host/src/bin/mint_harness.rs +135 -0
- data/rust/host/src/checkout.rs +265 -0
- data/rust/host/src/dispatch.rs +1443 -0
- data/rust/host/src/expr_json.rs +1117 -0
- data/rust/host/src/field_hints.rs +52 -0
- data/rust/host/src/ir.rs +733 -0
- data/rust/host/src/journal.rs +874 -0
- data/rust/host/src/lambda_client.rs +378 -0
- data/rust/host/src/log.rs +147 -0
- data/rust/host/src/main.rs +474 -0
- data/rust/host/src/mint.rs +1865 -0
- data/rust/host/src/payments/keystore.rs +330 -0
- data/rust/host/src/payments/tests.rs +1400 -0
- data/rust/host/src/payments.rs +767 -0
- data/rust/host/src/presentation.rs +698 -0
- data/rust/host/src/presentation_write.rs +1431 -0
- data/rust/host/src/query_step.rs +149 -0
- data/rust/host/src/rate_limit.rs +904 -0
- data/rust/host/src/reference_transform.rs +241 -0
- data/rust/host/src/reference_validate.rs +338 -0
- data/rust/host/src/resend.rs +296 -0
- data/rust/host/src/secrets.rs +106 -0
- data/rust/host/src/server.rs +663 -0
- data/rust/host/src/storage_shape.rs +175 -0
- data/rust/host/src/test_pg.rs +40 -0
- data/rust/host/src/ui_schema.rs +1351 -0
- data/rust/host/src/wasm_runner.rs +191 -0
- data/rust/host/src/web/newsletter/cooldown.rs +126 -0
- data/rust/host/src/web/newsletter/tests.rs +104 -0
- data/rust/host/src/web/newsletter.rs +310 -0
- data/rust/host/src/web/newsletter_send.rs +357 -0
- data/rust/host/src/web/registrations.rs +1505 -0
- data/rust/host/src/web.rs +2937 -0
- data/rust/lsp/.gitignore +1 -0
- data/rust/lsp/Cargo.lock +7 -0
- data/rust/lsp/Cargo.toml +16 -0
- data/rust/lsp/README.md +133 -0
- data/rust/lsp/src/diagnostics.rs +165 -0
- data/rust/lsp/src/json.rs +385 -0
- data/rust/lsp/src/main.rs +399 -0
- data/rust/lsp/src/outline.rs +177 -0
- data/rust/lsp/src/rpc.rs +67 -0
- data/rust/parser/.cargo/config.toml +5 -0
- data/rust/parser/.gitignore +1 -0
- data/rust/parser/Cargo.lock +7 -0
- data/rust/parser/Cargo.toml +21 -0
- data/rust/parser/src/build/closed_sets.rs +27 -0
- data/rust/parser/src/build/identity.rs +276 -0
- data/rust/parser/src/build/mod.rs +12 -0
- data/rust/parser/src/build/naming.rs +141 -0
- data/rust/parser/src/build/pattern_subset.rs +161 -0
- data/rust/parser/src/build/query_derive.rs +72 -0
- data/rust/parser/src/build/query_inference.rs +269 -0
- data/rust/parser/src/build/query_options.rs +100 -0
- data/rust/parser/src/build/read_model.rs +94 -0
- data/rust/parser/src/build/references.rs +32 -0
- data/rust/parser/src/canonical.rs +114 -0
- data/rust/parser/src/diag.rs +55 -0
- data/rust/parser/src/emit.rs +953 -0
- data/rust/parser/src/expr/ast_json.rs +147 -0
- data/rust/parser/src/expr/evaluator.rs +81 -0
- data/rust/parser/src/expr/mod.rs +84 -0
- data/rust/parser/src/expr/resolver.rs +497 -0
- data/rust/parser/src/ir.rs +387 -0
- data/rust/parser/src/keywords.rs +585 -0
- data/rust/parser/src/lex.rs +662 -0
- data/rust/parser/src/main.rs +252 -0
- data/rust/parser/src/parse/aggregate.rs +612 -0
- data/rust/parser/src/parse/chapter.rs +517 -0
- data/rust/parser/src/parse/command.rs +637 -0
- data/rust/parser/src/parse/domain_port.rs +127 -0
- data/rust/parser/src/parse/entity.rs +527 -0
- data/rust/parser/src/parse/file.rs +67 -0
- data/rust/parser/src/parse/hecksagon.rs +231 -0
- data/rust/parser/src/parse/lifecycle.rs +162 -0
- data/rust/parser/src/parse/mod.rs +1262 -0
- data/rust/parser/src/parse/policy.rs +87 -0
- data/rust/parser/src/parse/process_manager.rs +305 -0
- data/rust/parser/src/parse/query.rs +100 -0
- data/rust/parser/src/parse/read_model.rs +214 -0
- data/rust/parser/src/parse/value_object.rs +250 -0
- data/rust/parser/src/ruby_value.rs +422 -0
- data/rust/project/bridging.rb +257 -0
- data/rust/project/commands.rb +877 -0
- data/rust/project/constraints.rb +86 -0
- data/rust/project/dependency_planning.rb +178 -0
- data/rust/project/domain_generator.rb +980 -0
- data/rust/project/exemplar.rb +148 -0
- data/rust/project/expr_emitter.rb +72 -0
- data/rust/project/fielded.rb +141 -0
- data/rust/project/json_codec.rb +641 -0
- data/rust/project/mutations.rb +721 -0
- data/rust/project/naming.rb +205 -0
- data/rust/project/ports.rb +65 -0
- data/rust/project/queries.rb +493 -0
- data/rust/project/reactions.rb +317 -0
- data/rust/project/read_models.rb +690 -0
- data/rust/project/reference_specs.rb +27 -0
- data/rust/project/registry.rb +396 -0
- data/rust/project/skip_reason.rb +29 -0
- data/rust/project/types.rb +225 -0
- data/rust/project/write_if_changed.rb +83 -0
- data/rust/project.rb +30 -0
- data/rust/project_rust_pipeline.rb +383 -0
- data/rust/src/exemplar/commands.rs +279 -0
- data/rust/src/exemplar/constraints.rs +18 -0
- data/rust/src/exemplar/fielded.rs +280 -0
- data/rust/src/exemplar/json.rs +277 -0
- data/rust/src/exemplar/mod.rs +17 -0
- data/rust/src/exemplar/mutations.rs +80 -0
- data/rust/src/exemplar/queries.rs +33 -0
- data/rust/src/exemplar/reactions.rs +88 -0
- data/rust/src/exemplar/read_models.rs +48 -0
- data/rust/src/exemplar/registry.rs +166 -0
- data/rust/src/exemplar/types.rs +44 -0
- data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
- data/rust/src/kernel/attribute_shapes/list.rs +18 -0
- data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
- data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
- data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
- data/rust/src/kernel/cli.rs +585 -0
- data/rust/src/kernel/dispatch.rs +1090 -0
- data/rust/src/kernel/expr.rs +458 -0
- data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
- data/rust/src/kernel/expression_operators/comparison.rs +48 -0
- data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
- data/rust/src/kernel/expression_operators/logical.rs +13 -0
- data/rust/src/kernel/expression_operators/membership.rs +18 -0
- data/rust/src/kernel/expression_operators/mod.rs +68 -0
- data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
- data/rust/src/kernel/expression_operators/positional.rs +126 -0
- data/rust/src/kernel/expression_operators/presence.rs +101 -0
- data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
- data/rust/src/kernel/expression_operators/sized.rs +35 -0
- data/rust/src/kernel/expression_operators/text.rs +79 -0
- data/rust/src/kernel/expression_operators/to_string.rs +18 -0
- data/rust/src/kernel/json.rs +779 -0
- data/rust/src/kernel/mod.rs +133 -0
- data/rust/src/kernel/named_query.rs +219 -0
- data/rust/src/kernel/orchestrate.rs +1810 -0
- data/rust/src/kernel/pattern.rs +307 -0
- data/rust/src/kernel/query_comparators.rs +206 -0
- data/rust/src/kernel/query_ordering.rs +103 -0
- data/rust/src/kernel/read_model.rs +914 -0
- data/rust/src/kernel/reference_lookup.rs +149 -0
- data/rust/src/kernel/repository.rs +468 -0
- data/rust/src/kernel/routing.rs +612 -0
- data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
- data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
- data/rust/src/kernel/vocab/field_hint.rs +70 -0
- data/rust/src/kernel/vocab/mod.rs +20 -0
- data/rust/src/kernel/vocab/query_comparator.rs +65 -0
- data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
- data/rust/src/lib.rs +8 -0
- data/rust/src/main.rs +16 -0
- data/rust/web/.gitignore +1 -0
- data/rust/web/Cargo.lock +119 -0
- data/rust/web/Cargo.toml +18 -0
- data/rust/web/src/lib.rs +8 -0
- metadata +477 -12
- data/lib/hecks/facade/cli_door.rb +0 -96
- data/lib/hecks/facade/cli_runner.rb +0 -127
- data/lib/hecks/mcp_door_scope.rb +0 -95
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
require_relative "naming"
|
|
2
|
+
require_relative "runtime/registry"
|
|
3
|
+
require_relative "bluebook/meta_validator"
|
|
4
|
+
|
|
5
|
+
module Hecks
|
|
6
|
+
# The chapters the gem carries that a hecksagon can attach by name (ADR 0080): the language
|
|
7
|
+
# declared in itself, Expression, Tenancy, Deploy and QualityControl. Framework members stay in
|
|
8
|
+
# `Framework`.
|
|
9
|
+
#
|
|
10
|
+
# A chapter is named by the `Hecks.bluebook "Name"` header of its files, and may span several.
|
|
11
|
+
# Beside its bluebook a chapter may carry what every hecksagon attaching it needs, whatever
|
|
12
|
+
# its store: `<snake_name>.ports.hecksagon` (the ports it declares, as a `Hecks.hecksagon`
|
|
13
|
+
# block that merges into the attaching one) and `adapters/*.adapter` (the adapters binding them).
|
|
14
|
+
module Chapters
|
|
15
|
+
# Where attachable chapters live, relative to `lib/hecks/`.
|
|
16
|
+
GLOBS = %w[language/**/*.bluebook grammar/expression.bluebook tenancy/bluebook/*.bluebook
|
|
17
|
+
deploy/bluebook/*.bluebook quality_control/*.bluebook].freeze
|
|
18
|
+
|
|
19
|
+
# Every attachable chapter, by name, with the files that declare it.
|
|
20
|
+
#
|
|
21
|
+
# @return [Hash{String => Array<String>}] chapter name to its files' absolute paths, sorted
|
|
22
|
+
def self.index
|
|
23
|
+
@index ||= GLOBS.flat_map { |glob| Dir.glob(File.join(__dir__, glob)) }.sort
|
|
24
|
+
.group_by { |path| chapter_name(path) }
|
|
25
|
+
.reject { |name, _| name.nil? }
|
|
26
|
+
.freeze
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Loads a chapter's files into the current registry, unless it already holds the chapter.
|
|
30
|
+
#
|
|
31
|
+
# The files load together inside `MetaValidator.defer`, so a chapter spread over several files
|
|
32
|
+
# is judged once, whole. The chapter's ports file and adapters load after it, since a port
|
|
33
|
+
# names the chapter's aggregates.
|
|
34
|
+
#
|
|
35
|
+
# @param name [String] the chapter's name, such as `"Deploy"`
|
|
36
|
+
# @return [Boolean, nil] true when this call loaded the chapter, nil when it was already held
|
|
37
|
+
# @raise [Runtime::WiringError] if no attachable chapter has that name
|
|
38
|
+
def self.load!(name)
|
|
39
|
+
paths = index.fetch(name.to_s) do
|
|
40
|
+
raise Runtime::WiringError,
|
|
41
|
+
"no attachable chapter named #{name.inspect} — known: #{index.keys.join(', ')}"
|
|
42
|
+
end
|
|
43
|
+
registry = Hecks.current_registry or
|
|
44
|
+
raise Runtime::WiringError, "attaches #{name.to_s.inspect} outside a boot: no registry is open"
|
|
45
|
+
return refuse_own_chapter(registry, name.to_s) if registry.bluebook(name.to_s)
|
|
46
|
+
|
|
47
|
+
load_atomically(registry, name.to_s, paths)
|
|
48
|
+
true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Loads a chapter whole or not at all: a raise anywhere leaves the registry as it was, so a
|
|
52
|
+
# retry loads the chapter again instead of finding a half-built one already held.
|
|
53
|
+
def self.load_atomically(registry, name, paths)
|
|
54
|
+
queued = Bluebook::MetaValidator.deferred_chapters.dup
|
|
55
|
+
ports = registry.ports.keys
|
|
56
|
+
adapters = registry.adapters.keys
|
|
57
|
+
Bluebook::MetaValidator.defer { paths.each { |path| Kernel.load(path) } }
|
|
58
|
+
Bluebook::MetaValidator.judge_deferred!(registry)
|
|
59
|
+
load_wiring(name, paths)
|
|
60
|
+
rescue Exception # rubocop:disable Lint/RescueException -- rolls back, then re-raises
|
|
61
|
+
registry.forget_chapter(name)
|
|
62
|
+
Bluebook::MetaValidator.deferred_chapters.replace(queued)
|
|
63
|
+
registry.ports.delete_if { |key, _| !ports.include?(key) }
|
|
64
|
+
registry.adapters.delete_if { |key, _| !adapters.include?(key) }
|
|
65
|
+
raise
|
|
66
|
+
end
|
|
67
|
+
private_class_method :load_atomically
|
|
68
|
+
|
|
69
|
+
# Returns nil for a chapter this gem already loaded; raises for a chapter of the same name
|
|
70
|
+
# that a user's own file declared, which `attaches` would otherwise silently take for the
|
|
71
|
+
# gem's.
|
|
72
|
+
def self.refuse_own_chapter(registry, name)
|
|
73
|
+
foreign = Array(registry.bluebook_sources[name]).compact
|
|
74
|
+
.reject { |path| File.expand_path(path).start_with?("#{__dir__}/") }
|
|
75
|
+
return if foreign.empty?
|
|
76
|
+
|
|
77
|
+
raise Runtime::WiringError,
|
|
78
|
+
"attaches #{name.inspect}, but a chapter named #{name.inspect} is already declared in " \
|
|
79
|
+
"#{foreign.join(', ')} — rename it, since the gem's own #{name} chapter cannot merge into it"
|
|
80
|
+
end
|
|
81
|
+
private_class_method :refuse_own_chapter
|
|
82
|
+
|
|
83
|
+
# Loads what a chapter ships beside its bluebook: its ports file, then its adapters.
|
|
84
|
+
#
|
|
85
|
+
# @param name [String] the chapter's name
|
|
86
|
+
# @param paths [Array<String>] the chapter's bluebook files
|
|
87
|
+
# @return [void]
|
|
88
|
+
def self.load_wiring(name, paths)
|
|
89
|
+
directory = File.dirname(paths.first)
|
|
90
|
+
ports = File.join(directory, "#{Naming.snake(name)}.ports.hecksagon")
|
|
91
|
+
Kernel.load(ports) if File.file?(ports)
|
|
92
|
+
Dir.glob(File.join(directory, "adapters", "*.adapter")).each { |adapter| Kernel.load(adapter) }
|
|
93
|
+
end
|
|
94
|
+
private_class_method :load_wiring
|
|
95
|
+
|
|
96
|
+
# The name a file's `Hecks.bluebook "Name"` header declares, or nil for a file without one.
|
|
97
|
+
def self.chapter_name(path)
|
|
98
|
+
File.foreach(path) { |line| return Regexp.last_match(1) if line =~ /\A\s*Hecks\.bluebook\s+"([^"]+)"/ }
|
|
99
|
+
nil
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require_relative "../../hecks"
|
|
2
|
+
require_relative "../behaviors"
|
|
3
|
+
|
|
4
|
+
module Hecks
|
|
5
|
+
module CLI
|
|
6
|
+
# The command behind `hecks run_behaviors` and Custodian's `Operation.RunBehaviors`: runs
|
|
7
|
+
# `.behaviors` files and reports pass, fail or error per test (docs/guides/behaviors.md).
|
|
8
|
+
module Behaviors
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
# Runs one `.behaviors` file, or every one under a directory, and exits with the verdict.
|
|
12
|
+
#
|
|
13
|
+
# @param argv [Array<String>] the file or directory to run
|
|
14
|
+
# @param program [String] the name the usage message calls this command by
|
|
15
|
+
# @return [void]
|
|
16
|
+
# @raise [SystemExit] always: 0 when every test passed, 1 when any failed, errored or did
|
|
17
|
+
# not parse, or when a directory holds no `.behaviors` file
|
|
18
|
+
def call(argv, program:)
|
|
19
|
+
target = argv.first or abort "usage: #{program} <file.behaviors | directory>"
|
|
20
|
+
abort "no such file or directory: #{target}" unless File.exist?(target)
|
|
21
|
+
|
|
22
|
+
if File.directory?(target)
|
|
23
|
+
sweep = Hecks::Behaviors.run_all(target)
|
|
24
|
+
abort "no .behaviors files under #{target}" if sweep.files_swept.zero?
|
|
25
|
+
|
|
26
|
+
sweep.files.each { |file| report_file(file) }
|
|
27
|
+
summary = sweep.summary
|
|
28
|
+
puts
|
|
29
|
+
puts "#{sweep.files_swept} file(s) swept — #{summary[:total]} test(s): " \
|
|
30
|
+
"#{summary[:passed]} passed, #{summary[:failed]} failed, #{summary[:errored]} errored, " \
|
|
31
|
+
"#{summary[:parse_errors]} file(s) failed to parse"
|
|
32
|
+
else
|
|
33
|
+
result = Hecks::Behaviors.run(target)
|
|
34
|
+
report_file(result)
|
|
35
|
+
summary = Hecks::Behaviors.summarize([result])
|
|
36
|
+
end
|
|
37
|
+
exit(bad?(summary) ? 1 : 0)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @api private
|
|
41
|
+
def report_file(result)
|
|
42
|
+
puts result.path
|
|
43
|
+
if result.parse_error
|
|
44
|
+
puts " PARSE ERROR — #{result.parse_error}"
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
result.runs.each do |run|
|
|
49
|
+
marker = { pass: "ok", fail: "FAIL", error: "ERROR" }.fetch(run.status)
|
|
50
|
+
puts " #{marker.ljust(5)} #{run.description}"
|
|
51
|
+
puts " #{run.message}" if run.message
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @api private
|
|
56
|
+
def bad?(summary)
|
|
57
|
+
((summary[:failed] || 0) + (summary[:errored] || 0) + (summary[:parse_errors] || 0)).positive?
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../canonical_json"
|
|
4
|
+
|
|
5
|
+
module Hecks
|
|
6
|
+
module CLI
|
|
7
|
+
# The command behind `hecks canonicalise`: prints a JSON document with every object's keys
|
|
8
|
+
# sorted, recursively. Key order is not semantics, so a diff a person reads should not have
|
|
9
|
+
# to notice it moved.
|
|
10
|
+
module Canonicalise
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
# Prints the document at the path in `argv`, canonicalised.
|
|
14
|
+
#
|
|
15
|
+
# @param argv [Array<String>] the path of the JSON file, first
|
|
16
|
+
# @param out [IO] where the document goes
|
|
17
|
+
# @return [Integer] the exit status, always 0
|
|
18
|
+
# @raise [IndexError] when no path is given
|
|
19
|
+
def call(argv, out: $stdout)
|
|
20
|
+
out.puts Hecks::CanonicalJson.pretty(File.read(argv.fetch(0)))
|
|
21
|
+
0
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../hecks"
|
|
4
|
+
require_relative "../engine_agreement"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module CLI
|
|
8
|
+
# The command behind `hecks check_engine_agreement`: fails when a query engine re-grows its
|
|
9
|
+
# own comparator dispatch, or when a declared comparator lacks a shared `Comparison` case or
|
|
10
|
+
# a cross-engine agreement spec. Grep-based.
|
|
11
|
+
module CheckEngineAgreement
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
# Checks the tree and prints the verdict.
|
|
15
|
+
#
|
|
16
|
+
# @param root [String] the repository root to check
|
|
17
|
+
# @param out [IO] where a clean verdict goes
|
|
18
|
+
# @param err [IO] where the problems go
|
|
19
|
+
# @return [Integer] 0 when clean, 1 with problems
|
|
20
|
+
def call(root:, out: $stdout, err: $stderr)
|
|
21
|
+
finding = Hecks::EngineAgreement.check(root: root)
|
|
22
|
+
if finding.problems.empty?
|
|
23
|
+
out.puts Hecks::EngineAgreement.clean_line(finding)
|
|
24
|
+
return 0
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
err.puts Hecks::EngineAgreement.problem_lines(finding)
|
|
28
|
+
1
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require_relative "../ports/persistence/plugins/era/expected_era"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module CLI
|
|
5
|
+
# The command behind `hecks check_era` and Custodian's `Host.CheckEra`: asks a running host
|
|
6
|
+
# which era it reports and compares it with an allow-list file. Read-only: one GET, no writes.
|
|
7
|
+
module CheckEra
|
|
8
|
+
USAGE = "usage: hecks check_era <url> <expected-era-file> [--timeout=<seconds>]".freeze
|
|
9
|
+
|
|
10
|
+
# What a check found.
|
|
11
|
+
#
|
|
12
|
+
# @!attribute [r] verdict
|
|
13
|
+
# @return [Runtime::EraCheck::ExpectedEra::Verdict] the era compared with the list
|
|
14
|
+
# @!attribute [r] version
|
|
15
|
+
# @return [String] the gem version the host reports, empty when it reports none
|
|
16
|
+
# @!attribute [r] line
|
|
17
|
+
# @return [String] the sentence `hecks check_era` prints for this finding
|
|
18
|
+
Finding = Struct.new(:verdict, :version, :line)
|
|
19
|
+
|
|
20
|
+
module_function
|
|
21
|
+
|
|
22
|
+
# Fetches the host's `/version` and compares its era with the allow-list file.
|
|
23
|
+
#
|
|
24
|
+
# @param url [String] the host's base URL, or its `/version` URL
|
|
25
|
+
# @param file [String] path of the allow-list file
|
|
26
|
+
# @param timeout [Numeric] seconds allowed for connecting and for reading
|
|
27
|
+
# @return [Finding] the comparison, whether or not the era is listed
|
|
28
|
+
# @raise [Errno::ENOENT, Errno::EACCES] if the file cannot be read
|
|
29
|
+
# @raise [Runtime::EraCheck::ExpectedEra::Unreachable] if the host cannot be reached
|
|
30
|
+
# @raise [Runtime::EraCheck::ExpectedEra::BadResponse] if it answers no era
|
|
31
|
+
def assess(url, file, timeout: 10)
|
|
32
|
+
expected = Runtime::EraCheck::ExpectedEra
|
|
33
|
+
allowed = expected.parse(File.read(file))
|
|
34
|
+
document = expected.fetch_version(url, timeout: timeout)
|
|
35
|
+
verdict = expected.verdict(document.fetch("era"), allowed)
|
|
36
|
+
Finding.new(verdict, document.fetch("version"), sentence(verdict, file))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Runs `hecks check_era`: prints the finding and answers the exit status.
|
|
40
|
+
#
|
|
41
|
+
# @param argv [Array<String>] the url, the allow-list file and an optional `--timeout=N`
|
|
42
|
+
# @param out [IO] where a finding goes
|
|
43
|
+
# @param err [IO] where a refusal goes
|
|
44
|
+
# @return [Integer] 0 when the era is expected or unlisted, 1 on a mismatch, 2 on bad
|
|
45
|
+
# usage or an unreadable file, 3 when the host cannot be reached or answers no era
|
|
46
|
+
def run(argv, out: $stdout, err: $stderr)
|
|
47
|
+
timeout = 10
|
|
48
|
+
args = argv.reject do |arg|
|
|
49
|
+
next false unless arg.start_with?("--timeout=")
|
|
50
|
+
|
|
51
|
+
timeout = arg.delete_prefix("--timeout=").to_f
|
|
52
|
+
true
|
|
53
|
+
end
|
|
54
|
+
url, file = args
|
|
55
|
+
return usage(err) unless url && file && args.size == 2 && timeout.positive?
|
|
56
|
+
|
|
57
|
+
finding = assess(url, file, timeout: timeout)
|
|
58
|
+
(finding.verdict.ok? ? out : err).puts(finding.line)
|
|
59
|
+
finding.verdict.ok? ? 0 : 1
|
|
60
|
+
rescue Errno::ENOENT, Errno::EACCES => e
|
|
61
|
+
err.puts("cannot read #{file}: #{e.message}")
|
|
62
|
+
2
|
|
63
|
+
rescue Runtime::EraCheck::ExpectedEra::Unreachable, Runtime::EraCheck::ExpectedEra::BadResponse => e
|
|
64
|
+
err.puts("era check failed: #{e.message}")
|
|
65
|
+
3
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @param verdict [Runtime::EraCheck::ExpectedEra::Verdict] the comparison
|
|
69
|
+
# @param file [String] the allow-list file, named in the sentence
|
|
70
|
+
# @return [String] the one line that says what the comparison found
|
|
71
|
+
def sentence(verdict, file)
|
|
72
|
+
case verdict.status
|
|
73
|
+
when :match
|
|
74
|
+
"era #{verdict.era} is expected (#{verdict.allowed.join(', ')})"
|
|
75
|
+
when :unlisted
|
|
76
|
+
"host reports era #{verdict.era}; #{file} lists no era, so nothing was compared"
|
|
77
|
+
else
|
|
78
|
+
"host reports era #{verdict.era}, which is not in #{file} (expected: #{verdict.allowed.join(', ')})"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def usage(err)
|
|
83
|
+
err.puts(USAGE)
|
|
84
|
+
2
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require_relative "../../hecks"
|
|
2
|
+
require "irb"
|
|
3
|
+
# The era/lineage subsystem is a persistence plugin core does not require by default (ADR 0033);
|
|
4
|
+
# a domain passed to the console may bind it.
|
|
5
|
+
require_relative "../ports/persistence/plugins/era"
|
|
6
|
+
|
|
7
|
+
module Hecks
|
|
8
|
+
module CLI
|
|
9
|
+
# The command behind `hecks console` and Custodian's `Operation.OpenConsole`: boots a domain
|
|
10
|
+
# (pizzas on Memory by default) and drops into IRB with its door installed, for dispatching a
|
|
11
|
+
# real command by hand. No argument needs no database (ADR 0073); a domain directory boots as
|
|
12
|
+
# it is wired, which may bind PostgresEra.
|
|
13
|
+
module Console
|
|
14
|
+
PIZZAS = File.expand_path("../../../examples/pizzas", __dir__)
|
|
15
|
+
|
|
16
|
+
DEFAULT_FILES = [
|
|
17
|
+
File.join(PIZZAS, "bluebook/pizzas.bluebook"),
|
|
18
|
+
File.join(PIZZAS, "pizzas_behaviors.hecksagon")
|
|
19
|
+
].freeze
|
|
20
|
+
|
|
21
|
+
module_function
|
|
22
|
+
|
|
23
|
+
# Boots the domain, prints what it declares, and starts IRB; returns when the session ends.
|
|
24
|
+
#
|
|
25
|
+
# @param domain [String, nil] a domain directory; the bundled pizzas domain when nil
|
|
26
|
+
# @param launcher [#call] starts the interactive session; IRB unless a caller stands in
|
|
27
|
+
# @return [Runtime] the runtime the session ran against
|
|
28
|
+
def call(domain = nil, launcher: -> { IRB.start(__FILE__) })
|
|
29
|
+
runtime = domain ? Hecks.boot(domain) : Hecks.boot_files(DEFAULT_FILES)
|
|
30
|
+
puts overview(runtime)
|
|
31
|
+
puts banner
|
|
32
|
+
launcher.call
|
|
33
|
+
runtime
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @param runtime [Runtime] a booted domain
|
|
37
|
+
# @return [String] each chapter's vision and its aggregates' commands
|
|
38
|
+
def overview(runtime)
|
|
39
|
+
runtime.registry.bluebooks.each_value.map do |bluebook|
|
|
40
|
+
aggregates = bluebook.aggregates.map do |aggregate|
|
|
41
|
+
commands = aggregate.commands.map { |command| "#{Naming.snake(command.hecks_name)}!" }.sort.join(", ")
|
|
42
|
+
" #{aggregate.name}: #{commands}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
"\n #{bluebook.name} — #{bluebook.vision}\n#{aggregates.join("\n")}\n"
|
|
46
|
+
end.join
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [String] the version and a first session to try against the pizzas domain
|
|
50
|
+
def banner
|
|
51
|
+
<<~BANNER
|
|
52
|
+
|
|
53
|
+
hecks #{Hecks::VERSION}
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
order = Order.create_pizza!(name: { value: "Margherita" }, pizza: { price_cents: { cents: 1200 }, size: { value: "large" } })
|
|
57
|
+
order.add_topping!(topping: { value: "Basil" }, amount: { value: 3 })
|
|
58
|
+
order.purchase!(customer_name: { value: "Chris" }, amount: { cents: 1200 })
|
|
59
|
+
order.status
|
|
60
|
+
order.events.last
|
|
61
|
+
|
|
62
|
+
BANNER
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "optparse"
|
|
4
|
+
require_relative "../projections/deploy/template_diff"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module CLI
|
|
8
|
+
# The command behind `hecks deploy diff` and `hecks deploy diff`: compares two
|
|
9
|
+
# CloudFormation templates offline and reports differences by logical id; `--strict` also
|
|
10
|
+
# counts cosmetic differences (comments, key order).
|
|
11
|
+
module DeployTemplateDiff
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
# Prints the comparison and answers the exit status.
|
|
15
|
+
#
|
|
16
|
+
# @param argv [Array<String>] `<before.yaml> <after.yaml> [--json] [--strict]`
|
|
17
|
+
# @param program [String] the name the usage message calls this command by
|
|
18
|
+
# @return [Integer] 0 when the templates match, 1 when they differ, 2 for bad input
|
|
19
|
+
# @raise [SystemExit] when there are not exactly two templates
|
|
20
|
+
def call(argv, program: "hecks deploy diff")
|
|
21
|
+
options = { json: false, strict: false }
|
|
22
|
+
parser = OptionParser.new do |opts|
|
|
23
|
+
opts.banner = "usage: #{program} <before.yaml> <after.yaml> [--json] [--strict]"
|
|
24
|
+
opts.on("--json", "write the report as JSON") { options[:json] = true }
|
|
25
|
+
opts.on("--strict", "count cosmetic differences too") { options[:strict] = true }
|
|
26
|
+
end
|
|
27
|
+
files = parser.parse(argv)
|
|
28
|
+
abort parser.banner unless files.size == 2
|
|
29
|
+
|
|
30
|
+
diff = Hecks::Projections::Deploy::TemplateDiff
|
|
31
|
+
report = diff.diff_files(files[0], files[1], strict: options[:strict])
|
|
32
|
+
puts(options[:json] ? diff.render_json(report) : diff.render(report))
|
|
33
|
+
report.different? ? 1 : 0
|
|
34
|
+
rescue ArgumentError => e
|
|
35
|
+
warn e.message
|
|
36
|
+
2
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../hecks"
|
|
4
|
+
require_relative "../doc/reference"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module CLI
|
|
8
|
+
# The command behind `hecks measure_doc_coverage`: refuses unless every live word in
|
|
9
|
+
# `docs/implemented/reference/` has prose and a running example. It checks that an example
|
|
10
|
+
# exists; `spec/reference_doctest_spec.rb` checks that it passes. `ruby skip` fences and
|
|
11
|
+
# hidden `<!-- doctest:boot -->` blocks do not count as examples.
|
|
12
|
+
module DocCoverage
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
# Prints the coverage report.
|
|
16
|
+
#
|
|
17
|
+
# @param root [String] the repository root
|
|
18
|
+
# @param out [IO] where the report goes
|
|
19
|
+
# @param err [IO] where the refusal goes
|
|
20
|
+
# @return [Integer] 0 when every word is covered, 1 otherwise
|
|
21
|
+
def call(root:, out: $stdout, err: $stderr)
|
|
22
|
+
clean, report = Hecks::Doc::Reference.coverage_report(File.join(root, "docs/implemented/reference"))
|
|
23
|
+
out.puts report
|
|
24
|
+
return 0 if clean
|
|
25
|
+
|
|
26
|
+
err.puts "docs/implemented/reference/ is behind the language. " \
|
|
27
|
+
"Regenerate with hecks project_reference to see the words in place."
|
|
28
|
+
1
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/hecks/cli/document.rb
CHANGED
|
@@ -2,7 +2,7 @@ require_relative "../../hecks"
|
|
|
2
2
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module CLI
|
|
5
|
-
# The command behind `
|
|
5
|
+
# The command behind `hecks docs` and `hecks narrate`:
|
|
6
6
|
# one domain's document, projected from its own bluebook, to stdout.
|
|
7
7
|
#
|
|
8
8
|
# Nothing is written for the caller: redirect it, so git decides whether it drifted.
|
|
@@ -31,7 +31,7 @@ module Hecks
|
|
|
31
31
|
refuse_without_domain(program, root) unless path
|
|
32
32
|
|
|
33
33
|
begin
|
|
34
|
-
runtime = Hecks.boot(path,
|
|
34
|
+
runtime = Hecks.boot(path, install_doors: false)
|
|
35
35
|
rescue StandardError => e
|
|
36
36
|
abort "cannot read #{path}: #{e.message.lines.first.strip}"
|
|
37
37
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../projection_files"
|
|
4
|
+
|
|
5
|
+
module Hecks
|
|
6
|
+
module CLI
|
|
7
|
+
# The command behind `hecks project_expression_tables`: projects the expression machinery's
|
|
8
|
+
# operator and normalisation tables from the grammar chapter into
|
|
9
|
+
# `lib/hecks/bluebook/expression/projection.json`.
|
|
10
|
+
#
|
|
11
|
+
# It never redirects with `>`: the shell would truncate the file the framework requires at
|
|
12
|
+
# boot. The default mode replaces the file atomically, and it refuses a projection that drops
|
|
13
|
+
# a self-bearing operator (one the chapter's own `status != "retired"` givens evaluate
|
|
14
|
+
# through), since that would wedge every later boot. Recover a broken file with
|
|
15
|
+
# `git checkout -- lib/hecks/bluebook/expression/projection.json`.
|
|
16
|
+
module ExpressionProjection
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
# Rewrites the projection file, or with `--stdout` prints it instead.
|
|
20
|
+
#
|
|
21
|
+
# @param argv [Array<String>] `--stdout` for the diff mode
|
|
22
|
+
# @param out [IO] where the result goes
|
|
23
|
+
# @return [Integer] the exit status, 0 once written or printed
|
|
24
|
+
# @raise [SystemExit] with the refusal when the projection drops a self-bearing operator
|
|
25
|
+
def call(argv, out: $stdout)
|
|
26
|
+
result = begin
|
|
27
|
+
Hecks::ProjectionFiles.build(:expression_tables)
|
|
28
|
+
rescue Hecks::ProjectionFiles::Refused => e
|
|
29
|
+
abort e.message
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if argv.include?("--stdout")
|
|
33
|
+
out.print result.content.values.first
|
|
34
|
+
else
|
|
35
|
+
out.puts Hecks::ProjectionFiles.write(:expression_tables)
|
|
36
|
+
end
|
|
37
|
+
0
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "optparse"
|
|
5
|
+
require_relative "../../hecks"
|
|
6
|
+
|
|
7
|
+
module Hecks
|
|
8
|
+
module CLI
|
|
9
|
+
# The command behind `hecks follow`: live-tails a domain's persisted event log as JSON lines.
|
|
10
|
+
#
|
|
11
|
+
# Events are one table per domain, so this polls the first repository that answers `:events`
|
|
12
|
+
# and diffs its size each tick, filtering client-side when `--aggregate` is given.
|
|
13
|
+
module Follow
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
# Tails until interrupted.
|
|
17
|
+
#
|
|
18
|
+
# @param argv [Array<String>] `<domain> [--aggregate name] [--interval seconds] [--from-now]`
|
|
19
|
+
# @param program [String] the name the usage message calls this command by
|
|
20
|
+
# @return [void]
|
|
21
|
+
# @raise [SystemExit] when no domain is named or no adapter persists an event log
|
|
22
|
+
def call(argv, program: "hecks follow")
|
|
23
|
+
argv = argv.dup
|
|
24
|
+
domain_name = argv.shift or abort "usage: #{program} <domain> [options]"
|
|
25
|
+
options = parse(argv, program)
|
|
26
|
+
repository = event_repository(Hecks.boot(domain_name), domain_name, program)
|
|
27
|
+
tail(repository, options)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @param argv [Array<String>] the options after the domain; consumed in place
|
|
31
|
+
# @param program [String] the name the usage banner calls this command by
|
|
32
|
+
# @return [Hash] `:interval`, `:from_now` and, when given, `:aggregate`
|
|
33
|
+
def parse(argv, program)
|
|
34
|
+
options = { interval: 0.5, from_now: false }
|
|
35
|
+
OptionParser.new do |parser|
|
|
36
|
+
parser.banner = "usage: #{program} <domain> [options]"
|
|
37
|
+
parser.on("-a", "--aggregate=NAME", "Only follow events for this aggregate (e.g. Order)") do |name|
|
|
38
|
+
options[:aggregate] = name
|
|
39
|
+
end
|
|
40
|
+
parser.on("-i", "--interval=SECONDS", Float, "Poll interval in seconds (default: 0.5)") { |v| options[:interval] = v }
|
|
41
|
+
parser.on("--from-now", "Skip existing events; only print ones emitted from now on") { options[:from_now] = true }
|
|
42
|
+
end.parse!(argv)
|
|
43
|
+
options
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @param runtime [Runtime] a booted domain
|
|
47
|
+
# @param domain_name [String] its name, for the refusal
|
|
48
|
+
# @param program [String] the name the refusal calls this command by
|
|
49
|
+
# @return [Object] the first repository that answers `:events`
|
|
50
|
+
# @raise [SystemExit] when none does
|
|
51
|
+
def event_repository(runtime, domain_name, program)
|
|
52
|
+
repositories = runtime.registry.bluebooks.flat_map do |bluebook_domain, bluebook|
|
|
53
|
+
bluebook.aggregates.map { |aggregate| runtime.registry.repository(bluebook_domain, aggregate) }
|
|
54
|
+
end
|
|
55
|
+
repositories.find { |repo| repo.respond_to?(:events) } or
|
|
56
|
+
abort "#{program}: no adapter in #{domain_name} persists an event log"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Says whether `event` passes the `--aggregate` filter: a bare name matched
|
|
60
|
+
# case-insensitively, or the exact name.
|
|
61
|
+
#
|
|
62
|
+
# @param event [Object] a logged event
|
|
63
|
+
# @param filter [String, nil] the aggregate name asked for
|
|
64
|
+
# @return [Boolean]
|
|
65
|
+
def matches?(event, filter)
|
|
66
|
+
filter.nil? || event.aggregate.to_s.split("::").last.casecmp?(filter) || event.aggregate == filter
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @param repository [Object] answers `events`
|
|
70
|
+
# @param options [Hash] the parsed options
|
|
71
|
+
# @return [void]
|
|
72
|
+
def tail(repository, options)
|
|
73
|
+
seen = options[:from_now] ? repository.events.size : 0
|
|
74
|
+
$stdout.sync = true
|
|
75
|
+
trap("INT") { exit }
|
|
76
|
+
|
|
77
|
+
loop do
|
|
78
|
+
events = repository.events
|
|
79
|
+
if events.size > seen
|
|
80
|
+
events[seen..].each { |event| puts JSON.generate(event.to_h) if matches?(event, options[:aggregate]) }
|
|
81
|
+
seen = events.size
|
|
82
|
+
end
|
|
83
|
+
sleep options[:interval]
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require_relative "../../hecks"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module CLI
|
|
8
|
+
# The command behind `hecks history` and `hecks history`: every journal entry a domain's
|
|
9
|
+
# append-only adapters hold, as JSON, the full write history rather than the current head.
|
|
10
|
+
module History
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
# Boots the domain `argv` names and prints its history as one JSON document.
|
|
14
|
+
#
|
|
15
|
+
# @param argv [Array<String>] the domain directory, first
|
|
16
|
+
# @param program [String] the name the usage message calls this command by
|
|
17
|
+
# @return [void]
|
|
18
|
+
# @raise [SystemExit] when `argv` is empty
|
|
19
|
+
def call(argv, program: "hecks history")
|
|
20
|
+
domain = argv.first or abort "usage: #{program} <domain>"
|
|
21
|
+
puts JSON.generate(document(Hecks.boot(domain).registry))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @param registry [Runtime::Registry] a booted domain's registry
|
|
25
|
+
# @return [Hash{String => Array<Hash>}] each aggregate's storage name mapped to its entries
|
|
26
|
+
def document(registry)
|
|
27
|
+
registry.bluebooks.each_with_object({}) do |(name, bluebook), all|
|
|
28
|
+
bluebook.aggregates.each do |aggregate|
|
|
29
|
+
all[aggregate.storage_name] = entries(registry.repository(name, aggregate))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @param repository [Object] an aggregate's repository
|
|
35
|
+
# @return [Array<Hash{String => Object}>] its journal entries; empty
|
|
36
|
+
# when it is not append-only
|
|
37
|
+
def entries(repository)
|
|
38
|
+
return [] unless repository.is_a?(Ports::Persistence::AppendOnly)
|
|
39
|
+
|
|
40
|
+
repository.entries.map { |entry| { "operation" => entry.operation, "id" => entry.id, "state" => entry.state } }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/hecks/cli/ir.rb
CHANGED
|
@@ -5,7 +5,7 @@ require_relative "../ports/persistence/plugins/era"
|
|
|
5
5
|
|
|
6
6
|
module Hecks
|
|
7
7
|
module CLI
|
|
8
|
-
# The command behind `
|
|
8
|
+
# The command behind `hecks ir`: a booted domain's IR as JSON, the
|
|
9
9
|
# same `to_h` the golden specs pin and `StorageShape` hashes into an era.
|
|
10
10
|
module Ir
|
|
11
11
|
module_function
|
data/lib/hecks/cli/mcp.rb
CHANGED
|
@@ -2,7 +2,7 @@ require_relative "../mcp_stdio_guard"
|
|
|
2
2
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module CLI
|
|
5
|
-
# The command behind `
|
|
5
|
+
# The command behind `hecks mcp`: the MCP door onto the
|
|
6
6
|
# storehouse bus, over stdio only.
|
|
7
7
|
#
|
|
8
8
|
# This file loads nothing but `McpStdioGuard`, so the transport check runs
|
|
@@ -23,8 +23,8 @@ module Hecks
|
|
|
23
23
|
# set up for stdio
|
|
24
24
|
def call(argv)
|
|
25
25
|
McpStdioGuard.enforce_stdio!(server: SERVER, argv: argv)
|
|
26
|
-
require_relative "mcp_door"
|
|
27
|
-
McpDoor.serve
|
|
26
|
+
require_relative "../doors/mcp_door"
|
|
27
|
+
Doors::McpDoor.serve
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
end
|