command_tower 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/command_tower/application_controller.rb +1 -0
  3. data/app/controllers/concerns/command_tower/execution/client_compatibility_boundary.rb +39 -0
  4. data/app/errors/command_tower/errors/client_update_required_error.rb +27 -0
  5. data/app/serializers/command_tower/serializers/messaging/inbox.rb +2 -1
  6. data/app/services/command_tower/email_theme/resolver.rb +45 -0
  7. data/app/services/command_tower/messaging/notification_types/declaration.rb +14 -1
  8. data/app/services/command_tower/messaging/rendering/channel_renderer.rb +44 -13
  9. data/app/services/command_tower/messaging/rendering/inbox_document.rb +131 -0
  10. data/app/services/command_tower/messaging/rendering/inbox_document_renderer.rb +207 -0
  11. data/app/services/command_tower/messaging/rendering/template_resolver.rb +128 -0
  12. data/app/services/command_tower/services/client_compatibility/evaluate.rb +219 -0
  13. data/app/services/command_tower/services/messaging/inbox.rb +8 -1
  14. data/app/views/command_tower/email_verification_mailer/verify_email.html.erb +18 -17
  15. data/app/views/command_tower/messaging/rendering/email.html.erb +6 -5
  16. data/app/views/command_tower/password_reset_mailer/reset_password.html.erb +24 -23
  17. data/app/workflows/command_tower/workflows/auth/plain_text/login_workflow.rb +3 -0
  18. data/app/workflows/command_tower/workflows/auth/session/show_workflow.rb +3 -0
  19. data/app/workflows/command_tower/workflows/client_compatibility/evaluate_workflow.rb +83 -0
  20. data/app/workflows/command_tower/workflows/client_compatibility/recommendation_meta.rb +25 -0
  21. data/docs/api_reference.md +13 -2
  22. data/docs/extending.md +2 -1
  23. data/docs/host_integration_guide.md +35 -0
  24. data/docs/messaging_integration_guide.md +38 -0
  25. data/docs/upgrades/0.17.0.md +33 -0
  26. data/docs/upgrades/README.md +1 -0
  27. data/lib/command_tower/client_compatibility/version.rb +45 -0
  28. data/lib/command_tower/client_compatibility.rb +23 -0
  29. data/lib/command_tower/configuration/config.rb +6 -0
  30. data/lib/command_tower/configuration/email_theme/config.rb +69 -0
  31. data/lib/command_tower/configuration/registry/client_compatibility/binding_definition.rb +42 -0
  32. data/lib/command_tower/configuration/registry/client_compatibility/config.rb +353 -0
  33. data/lib/command_tower/configuration/registry/client_compatibility/contract_definition.rb +16 -0
  34. data/lib/command_tower/configuration/registry/client_compatibility/entity_requirement_definition.rb +67 -0
  35. data/lib/command_tower/configuration/registry/client_compatibility/minimum_overrides.rb +46 -0
  36. data/lib/command_tower/configuration/registry/client_compatibility/platform_definition.rb +66 -0
  37. data/lib/command_tower/configuration/registry/config.rb +14 -0
  38. data/lib/command_tower/configuration/registry/inbox_presentations/config.rb +105 -0
  39. data/lib/command_tower/configuration/registry/inbox_presentations/presentation_definition.rb +71 -0
  40. data/lib/command_tower/current.rb +1 -0
  41. data/lib/command_tower/engine.rb +4 -0
  42. data/lib/command_tower/inbox_presentations.rb +19 -0
  43. data/lib/command_tower/version.rb +1 -1
  44. metadata +24 -2
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "class_composer"
4
+
5
+ module CommandTower
6
+ module Configuration
7
+ module Registry
8
+ module InboxPresentations
9
+ class PresentationDefinition
10
+ include ClassComposer::Generator
11
+
12
+ add_composer :composer_class,
13
+ desc: "String class name of the registered presentation composer " \
14
+ "(`.call(communication:, recipient_id:) -> Hash`), resolved via `.constantize` " \
15
+ "at InboxDocumentRenderer render time — never at registration time",
16
+ allowed: String,
17
+ default: ""
18
+
19
+ # Explicit output projection (Rich Messaging corrective slice —
20
+ # ServiceResult/context leak fix). `InboxDocumentRenderer#presentation_block`
21
+ # slices the composer's raw result down to exactly these keys before
22
+ # it ever reaches `content.blocks[].data` — every other key (declared
23
+ # `ApplicationService` inputs, incidental intermediate context state,
24
+ # or anything else a composer happens to set) is dropped
25
+ # unconditionally, regardless of whether the composer is an
26
+ # `ApplicationService` or a plain Hash-returning class. This is a
27
+ # declared allow-list owned by the registration, not an inference
28
+ # from `ServiceResult`/`ApplicationService` argument metadata.
29
+ add_composer :output_keys,
30
+ desc: "Array of Symbol keys that are the ONLY keys copied from the composer's " \
31
+ "result onto the Inbox wire (`content.blocks[].data`) — every other " \
32
+ "context/result key (composer inputs, intermediate state, anything else) " \
33
+ "is dropped at render time, regardless of composer shape",
34
+ allowed: Array,
35
+ default: []
36
+
37
+ attr_accessor :owner, :id
38
+
39
+ def validate_definition!(key:)
40
+ self.id = key.to_s
41
+ self.owner = owner&.to_sym || :host
42
+ self.composer_class = require_present_string!(composer_class, field: "composer_class", key:)
43
+ self.output_keys = require_present_output_keys!(output_keys, key:)
44
+ end
45
+
46
+ private
47
+
48
+ def require_present_string!(value, field:, key:)
49
+ text = value.to_s.strip
50
+ if text.empty?
51
+ raise CommandTower::InboxPresentations::InvalidPresentationDefinitionError,
52
+ "inbox presentation #{key} is missing #{field}"
53
+ end
54
+
55
+ text
56
+ end
57
+
58
+ def require_present_output_keys!(value, key:)
59
+ keys = Array(value).map { |entry| entry.to_s.strip }
60
+ if keys.empty? || keys.any?(&:empty?)
61
+ raise CommandTower::InboxPresentations::InvalidPresentationDefinitionError,
62
+ "inbox presentation #{key} is missing output_keys"
63
+ end
64
+
65
+ keys.map(&:to_sym)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -15,5 +15,6 @@ module CommandTower
15
15
  attribute :impersonation_activity_recorded, default: false
16
16
  attribute :remote_ip
17
17
  attribute :user_agent
18
+ attribute :client_compatibility_recommendation
18
19
  end
19
20
  end
@@ -22,12 +22,15 @@ module CommandTower
22
22
  # ensure defaults are instantiated and all variables are assigned
23
23
  CommandTower.config.class_composer_assign_defaults!(children: true)
24
24
  CommandTower::CredentialResolution::SmtpActionMailerBridge.apply!
25
+ CommandTower.config.registry.client_compatibility.apply_env_overlay!
25
26
 
26
27
  unless Rails.env.test?
27
28
  CommandTower.config.impersonation.validate!
28
29
  CommandTower.config.registry.audit.finalize!
29
30
  CommandTower.config.registry.admin_workspace.finalize!
30
31
  CommandTower.config.registry.principal_capabilities.finalize!
32
+ CommandTower.config.registry.client_compatibility.finalize!
33
+ CommandTower.config.registry.inbox_presentations.finalize!
31
34
  CommandTower.config.admin_scope.finalize!
32
35
  # Now that we can confirm all variables are defined, freeze all objects an their children
33
36
  CommandTower.config.class_composer_freeze_objects!(behavior: :raise, children: true)
@@ -62,6 +65,7 @@ module CommandTower
62
65
  entities = CommandTower::Authorization::Entity.entities
63
66
  CommandTower.config.registry.admin_workspace.validate_required_entities!(entities)
64
67
  CommandTower.config.registry.principal_capabilities.validate_required_entities!(entities)
68
+ CommandTower.config.registry.client_compatibility.validate!(entities)
65
69
  CommandTower.config.admin_scope.validate_scoped_tools!
66
70
  end
67
71
  CommandTower::Logging::Subscriber.attach!
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CommandTower
4
+ # Rich Messaging Slice 2.5 — registry of registered Inbox presentation
5
+ # capabilities (semantic keys such as `pickem.make_picks`) mapped to a
6
+ # trusted, host- or CommandTower-owned composer class. See
7
+ # artifacts/visual-improvements/rich-messaging/authority/RICH_MESSAGING_PRESENTATION_AUTHORITY.md
8
+ # Part I and
9
+ # artifacts/visual-improvements/rich-messaging/authority/RICH_MESSAGING_RUBY_INBOX_DEFINITION_DISCOVERY.md §9.
10
+ module InboxPresentations
11
+ class Error < CommandTower::Error; end
12
+
13
+ class UnregisteredCapabilityError < Error; end
14
+ class DuplicateCapabilityError < Error; end
15
+ class InvalidKeyError < Error; end
16
+ class InvalidPresentationDefinitionError < Error; end
17
+ class FrozenRegistryError < Error; end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CommandTower
4
- VERSION = "0.16.0"
4
+ VERSION = "0.17.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: command_tower
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - matt-taylor
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-07 00:00:00.000000000 Z
11
+ date: 2026-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phonelib
@@ -231,6 +231,7 @@ files:
231
231
  - app/controllers/concerns/command_tower/auth/invalid_credentials_deserializer_renderer.rb
232
232
  - app/controllers/concerns/command_tower/auth/password_recovery_session_boundary.rb
233
233
  - app/controllers/concerns/command_tower/auth/signup_session_boundary.rb
234
+ - app/controllers/concerns/command_tower/execution/client_compatibility_boundary.rb
234
235
  - app/controllers/concerns/command_tower/execution/http_boundary.rb
235
236
  - app/deserializers/command_tower/deserializers/admin/messaging/create_announcement_deserializer.rb
236
237
  - app/deserializers/command_tower/deserializers/admin/scope_parameter.rb
@@ -309,6 +310,7 @@ files:
309
310
  - app/errors/command_tower/errors/auth/signup_session_rate_limit_error.rb
310
311
  - app/errors/command_tower/errors/auth/verification_code_invalid_error.rb
311
312
  - app/errors/command_tower/errors/auth/verification_send_failed_error.rb
313
+ - app/errors/command_tower/errors/client_update_required_error.rb
312
314
  - app/errors/command_tower/errors/continuation_exhausted_error.rb
313
315
  - app/errors/command_tower/errors/forbidden_error.rb
314
316
  - app/errors/command_tower/errors/internal_error.rb
@@ -409,6 +411,7 @@ files:
409
411
  - app/services/command_tower/clients/transport/request.rb
410
412
  - app/services/command_tower/clients/transport/response.rb
411
413
  - app/services/command_tower/clients/url.rb
414
+ - app/services/command_tower/email_theme/resolver.rb
412
415
  - app/services/command_tower/identity/phone/normalizer.rb
413
416
  - app/services/command_tower/identity/phone_verification/sms_configuration.rb
414
417
  - app/services/command_tower/identity/phone_verification/sms_transport.rb
@@ -592,11 +595,14 @@ files:
592
595
  - app/services/command_tower/messaging/recipient_readiness/recipient_result.rb
593
596
  - app/services/command_tower/messaging/recipient_readiness/unknown_channel_error.rb
594
597
  - app/services/command_tower/messaging/rendering/channel_renderer.rb
598
+ - app/services/command_tower/messaging/rendering/inbox_document.rb
599
+ - app/services/command_tower/messaging/rendering/inbox_document_renderer.rb
595
600
  - app/services/command_tower/messaging/rendering/render_error.rb
596
601
  - app/services/command_tower/messaging/rendering/rendered_payload.rb
597
602
  - app/services/command_tower/messaging/rendering/rendered_push_payload.rb
598
603
  - app/services/command_tower/messaging/rendering/rendered_pushover_payload.rb
599
604
  - app/services/command_tower/messaging/rendering/rendered_sms_payload.rb
605
+ - app/services/command_tower/messaging/rendering/template_resolver.rb
600
606
  - app/services/command_tower/secrets.rb
601
607
  - app/services/command_tower/secrets/cleanse.rb
602
608
  - app/services/command_tower/secrets/generate.rb
@@ -660,6 +666,7 @@ files:
660
666
  - app/services/command_tower/services/auth/signup_session/validate.rb
661
667
  - app/services/command_tower/services/auth/tombstone_user.rb
662
668
  - app/services/command_tower/services/auth/username_availability.rb
669
+ - app/services/command_tower/services/client_compatibility/evaluate.rb
663
670
  - app/services/command_tower/services/impersonation/create.rb
664
671
  - app/services/command_tower/services/impersonation/end.rb
665
672
  - app/services/command_tower/services/impersonation/record_activity.rb
@@ -737,6 +744,8 @@ files:
737
744
  - app/workflows/command_tower/workflows/auth/signup_session/authenticate_workflow.rb
738
745
  - app/workflows/command_tower/workflows/auth/signup_session/create_workflow.rb
739
746
  - app/workflows/command_tower/workflows/auth/username_availability_workflow.rb
747
+ - app/workflows/command_tower/workflows/client_compatibility/evaluate_workflow.rb
748
+ - app/workflows/command_tower/workflows/client_compatibility/recommendation_meta.rb
740
749
  - app/workflows/command_tower/workflows/impersonation/error_mapping.rb
741
750
  - app/workflows/command_tower/workflows/impersonation/start_workflow.rb
742
751
  - app/workflows/command_tower/workflows/impersonation/stop_workflow.rb
@@ -816,6 +825,7 @@ files:
816
825
  - docs/upgrades/0.14.0.md
817
826
  - docs/upgrades/0.15.0.md
818
827
  - docs/upgrades/0.16.0.md
828
+ - docs/upgrades/0.17.0.md
819
829
  - docs/upgrades/README.md
820
830
  - lib/command_tower.rb
821
831
  - lib/command_tower/admin_scope.rb
@@ -838,6 +848,8 @@ files:
838
848
  - lib/command_tower/authorization/effective_entity_grants.rb
839
849
  - lib/command_tower/authorization/entity.rb
840
850
  - lib/command_tower/authorization/role.rb
851
+ - lib/command_tower/client_compatibility.rb
852
+ - lib/command_tower/client_compatibility/version.rb
841
853
  - lib/command_tower/configuration/account_deletion/config.rb
842
854
  - lib/command_tower/configuration/admin/config.rb
843
855
  - lib/command_tower/configuration/admin_scope/config.rb
@@ -850,6 +862,7 @@ files:
850
862
  - lib/command_tower/configuration/credentials/smtp.rb
851
863
  - lib/command_tower/configuration/credentials/twilio.rb
852
864
  - lib/command_tower/configuration/email/config.rb
865
+ - lib/command_tower/configuration/email_theme/config.rb
853
866
  - lib/command_tower/configuration/identity/config.rb
854
867
  - lib/command_tower/configuration/identity/phone_verification.rb
855
868
  - lib/command_tower/configuration/impersonation/config.rb
@@ -873,7 +886,15 @@ files:
873
886
  - lib/command_tower/configuration/registry/admin_workspace/tool_definition.rb
874
887
  - lib/command_tower/configuration/registry/audit/config.rb
875
888
  - lib/command_tower/configuration/registry/audit/event_definition.rb
889
+ - lib/command_tower/configuration/registry/client_compatibility/binding_definition.rb
890
+ - lib/command_tower/configuration/registry/client_compatibility/config.rb
891
+ - lib/command_tower/configuration/registry/client_compatibility/contract_definition.rb
892
+ - lib/command_tower/configuration/registry/client_compatibility/entity_requirement_definition.rb
893
+ - lib/command_tower/configuration/registry/client_compatibility/minimum_overrides.rb
894
+ - lib/command_tower/configuration/registry/client_compatibility/platform_definition.rb
876
895
  - lib/command_tower/configuration/registry/config.rb
896
+ - lib/command_tower/configuration/registry/inbox_presentations/config.rb
897
+ - lib/command_tower/configuration/registry/inbox_presentations/presentation_definition.rb
877
898
  - lib/command_tower/configuration/registry/principal_capabilities/capability_definition.rb
878
899
  - lib/command_tower/configuration/registry/principal_capabilities/config.rb
879
900
  - lib/command_tower/configuration/signup_session/config.rb
@@ -896,6 +917,7 @@ files:
896
917
  - lib/command_tower/impersonation/apply_overlay.rb
897
918
  - lib/command_tower/impersonation/clear_overlay_for_audit.rb
898
919
  - lib/command_tower/impersonation/establish_identity.rb
920
+ - lib/command_tower/inbox_presentations.rb
899
921
  - lib/command_tower/install/baseline.rb
900
922
  - lib/command_tower/install/doctor.rb
901
923
  - lib/command_tower/intervention/severity.rb