adopt-cli 0.4.0__tar.gz → 0.4.1__tar.gz

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 (53) hide show
  1. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/PKG-INFO +1 -1
  2. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/pyproject.toml +1 -1
  3. adopt_cli-0.4.1/src/adopt_cli/_build_info.py +6 -0
  4. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/answer.py +19 -1
  5. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/boundary.py +2 -2
  6. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/coverage.py +45 -6
  7. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/handover.py +7 -2
  8. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/policy.py +2 -2
  9. adopt_cli-0.4.0/src/adopt_cli/_build_info.py +0 -6
  10. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/.gitignore +0 -0
  11. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/LICENSE +0 -0
  12. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/NOTICE +0 -0
  13. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/__init__.py +0 -0
  14. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/__init__.py +0 -0
  15. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_ask_support.py +0 -0
  16. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_ci_sense_probes.py +0 -0
  17. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_ci_sense_support.py +0 -0
  18. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_draft_support.py +0 -0
  19. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_drafting.py +0 -0
  20. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_handover_support.py +0 -0
  21. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_knowledge_support.py +0 -0
  22. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_map_support.py +0 -0
  23. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_pack_support.py +0 -0
  24. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_probe_support.py +0 -0
  25. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_refresh_support.py +0 -0
  26. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_remote_support.py +0 -0
  27. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/_review_remote.py +0 -0
  28. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/agent.py +0 -0
  29. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/ask.py +0 -0
  30. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/ci_sense.py +0 -0
  31. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/detect.py +0 -0
  32. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/doctor.py +0 -0
  33. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/draft.py +0 -0
  34. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/freshness.py +0 -0
  35. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/identity.py +0 -0
  36. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/init.py +0 -0
  37. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/interchange.py +0 -0
  38. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/knowledge.py +0 -0
  39. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/map_command.py +0 -0
  40. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/pack.py +0 -0
  41. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/probe.py +0 -0
  42. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/pull.py +0 -0
  43. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/refresh.py +0 -0
  44. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/serve.py +0 -0
  45. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/store.py +0 -0
  46. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/commands/version.py +0 -0
  47. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/config.py +0 -0
  48. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/json_out.py +0 -0
  49. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/main.py +0 -0
  50. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/py.typed +0 -0
  51. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/remote.py +0 -0
  52. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/replica.py +0 -0
  53. {adopt_cli-0.4.0 → adopt_cli-0.4.1}/src/adopt_cli/store_option.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: adopt-cli
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: The adopt command surface: config resolution, JSON mode, exit codes.
5
5
  Project-URL: Homepage, https://github.com/onboardux/onboard-core
6
6
  Project-URL: Source, https://github.com/onboardux/onboard-core
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "adopt-cli"
3
- version = "0.4.0"
3
+ version = "0.4.1"
4
4
  description = "The adopt command surface: config resolution, JSON mode, exit codes."
5
5
  requires-python = ">=3.12"
6
6
  license = "Apache-2.0"
@@ -0,0 +1,6 @@
1
+ """Generated by scripts/embed_build_info.py; do not edit in a release build."""
2
+
3
+ from typing import Final
4
+
5
+ SBOM_SHA256: Final[str | None] = '6742b345c4d8f4d20905a7e8ca33afd66dd98e023cb9d13fb8982d3f2a3cd493'
6
+ BUILD_ID: Final[str | None] = 'github:onboardux/onboard-core:34466475060:1:d639bc04586bda49c77f2b8c71865ceba74f2a0b'
@@ -63,6 +63,8 @@ class _Items(Protocol):
63
63
  self, *, revision_id: str, source_type: SourceType, source_ref: str
64
64
  ) -> str: ...
65
65
 
66
+ def tag_audience(self, *, item_id: str, audience: str) -> bool: ...
67
+
66
68
 
67
69
  class _Bindings(Protocol):
68
70
  def create(
@@ -113,6 +115,14 @@ ScopeOption = Annotated[
113
115
  str | None,
114
116
  typer.Option("--scope", help="firm/engagement/system/environment. Defaults to the store's."),
115
117
  ]
118
+ AudienceOption = Annotated[
119
+ list[str] | None,
120
+ typer.Option(
121
+ "--audience",
122
+ help="Who the answer is for. Repeatable. Defaults to the same audience "
123
+ "`adopt ingest` gives an untagged document.",
124
+ ),
125
+ ]
116
126
  ActorOption = Annotated[str | None, typer.Option("--actor", help="Who answered.")]
117
127
  JsonOption = Annotated[bool, typer.Option("--json", help="Emit the strict JSON envelope only.")]
118
128
 
@@ -124,11 +134,12 @@ def answer(
124
134
  title: TitleOption = None,
125
135
  scope: ScopeOption = None,
126
136
  store: StoreOption = None,
137
+ audience: AudienceOption = None,
127
138
  actor: ActorOption = None,
128
139
  json_output: JsonOption = False,
129
140
  ) -> None:
130
141
  """Bank a human's answer as confirmed knowledge and resolve the question."""
131
- from adopt_ask.capture import capture_answer, identities_to_bind
142
+ from adopt_ask.capture import DEFAULT_AUDIENCES, capture_answer, identities_to_bind
132
143
 
133
144
  from adopt_cli.commands._remote_support import configured_remote
134
145
 
@@ -169,6 +180,10 @@ def answer(
169
180
  title=title or existing.question or f"Answer to {escalation_id}",
170
181
  body_md=text,
171
182
  identity_ids=identity_ids,
183
+ # `DEFAULT_AUDIENCES` rather than a literal here: the default lives
184
+ # in `adopt_ask.capture` beside the rule it protects, so the CLI and
185
+ # the plane cannot drift into tagging captured answers differently.
186
+ audiences=tuple(audience) if audience else DEFAULT_AUDIENCES,
172
187
  actor_id=actor,
173
188
  unmatched_uris=unmatched,
174
189
  )
@@ -248,6 +263,9 @@ class _StoreAdapter:
248
263
  source_ref=source_ref,
249
264
  )
250
265
 
266
+ def tag_audience(self, *, item_id: str, audience: str) -> object:
267
+ return self._handle.items().tag_audience(item_id=item_id, audience=audience)
268
+
251
269
  def bind(self, *, item_id: str, identity_id: str, is_load_bearing: bool) -> str:
252
270
  binding_id, _revision_id = self._handle.bindings().create(
253
271
  item_id=item_id, identity_id=identity_id, is_load_bearing=is_load_bearing
@@ -57,8 +57,8 @@ ScopeOption = Annotated[
57
57
  str | None,
58
58
  typer.Option(
59
59
  "--scope",
60
- help="firm/engagement/system[/environment]. Given, the boundary is written to "
61
- "the store; omitted, it is computed and reported without writing.",
60
+ help="firm/engagement/system, optionally with /environment. Given, the boundary is "
61
+ "written to the store; omitted, it is computed and reported without writing.",
62
62
  ),
63
63
  ]
64
64
  ArchetypeOption = Annotated[
@@ -30,12 +30,23 @@ app = typer.Typer(
30
30
  )
31
31
 
32
32
  SystemOption = Annotated[
33
- str,
34
- typer.Option("--system", help="The system id to evaluate.", show_default=False),
33
+ str | None,
34
+ typer.Option("--system", help="System id or slug to evaluate.", show_default=False),
35
+ ]
36
+ ScopeOption = Annotated[
37
+ str | None,
38
+ typer.Option(
39
+ "--scope",
40
+ help="firm/engagement/system, optionally with /environment. The alternative to "
41
+ "--system, and the string `adopt init` already took.",
42
+ ),
35
43
  ]
36
44
  EnvironmentOption = Annotated[
37
45
  str | None,
38
- typer.Option("--environment", help="One environment id. Omit for every environment."),
46
+ typer.Option(
47
+ "--environment",
48
+ help="One environment id. Omit for every environment, or name one in --scope.",
49
+ ),
39
50
  ]
40
51
  StoreOption = Annotated[
41
52
  Path | None,
@@ -53,13 +64,27 @@ JsonOption = Annotated[bool, typer.Option("--json", help="Emit the strict JSON e
53
64
 
54
65
  @app.command()
55
66
  def recompute(
56
- system: SystemOption,
67
+ system: SystemOption = None,
68
+ scope: ScopeOption = None,
57
69
  environment: EnvironmentOption = None,
58
70
  store: StoreOption = None,
59
71
  rebuild: RebuildOption = False,
60
72
  json_output: JsonOption = False,
61
73
  ) -> None:
62
- """Evaluate the six inputs of contracts §6 for every identity in scope."""
74
+ """Evaluate the six inputs of contracts §6 for every identity in scope.
75
+
76
+ **`--scope` exists because this command is the remedy for an alarm, and the
77
+ remedy has to be reachable.** `COVERAGE_CACHE_DISAGREEMENT` fires on every
78
+ `adopt gaps` and `adopt pack` once a binding is confirmed, and clearing it
79
+ needs this verb -- which took a system **id** that no verb printed. `store
80
+ info` reports counts, `store doctor` reports findings, and the only command
81
+ that ever surfaced a system id was `adopt handover start`, which opens a
82
+ handover event as a side effect. An operator was left reading the SQLite
83
+ file by hand to silence an alarm the product raised at them, so the scope
84
+ string they typed into `adopt init` is now accepted here too.
85
+ """
86
+ from adopt_cli.commands._handover_support import resolve_system
87
+
63
88
  with open_configured_store(
64
89
  store,
65
90
  read_only=not rebuild,
@@ -69,7 +94,21 @@ def recompute(
69
94
  # nothing a later `adopt pull` overwrites was canon.
70
95
  non_canon_reason="--rebuild writes only the coverage cache, never canon",
71
96
  ) as handle:
72
- result = recompute_coverage(handle.coverage_records(), system, environment)
97
+ # `resolve_system` rather than a second resolver: it already accepts an
98
+ # id, a slug or a scope path, refuses both at once, and with neither
99
+ # falls through to `resolve_scope`, which returns the store's only
100
+ # environment and **refuses rather than guessing** when there are
101
+ # several. A second implementation would be a second answer to "which
102
+ # system is this", which is how two verbs come to disagree about a store.
103
+ target = resolve_system(handle, system=system, scope=scope)
104
+ result = recompute_coverage(
105
+ handle.coverage_records(),
106
+ target.system_id,
107
+ # An explicit `--environment` wins over one named in `--scope`: it is
108
+ # the narrower statement of the two, and it names an id rather than a
109
+ # slug, so it cannot be the vaguer thing the operator meant.
110
+ environment or target.environment_id,
111
+ )
73
112
  rebuilt = rebuild_cache(handle.backend, result) if rebuild else 0
74
113
 
75
114
  payload = {
@@ -47,7 +47,8 @@ SystemOption = Annotated[
47
47
  ScopeOption = Annotated[
48
48
  str | None,
49
49
  typer.Option(
50
- "--scope", help="firm/engagement/system[/environment]. Narrows to one environment."
50
+ "--scope",
51
+ help="firm/engagement/system, optionally with /environment. Narrows to one environment.",
51
52
  ),
52
53
  ]
53
54
  OwnerOption = Annotated[
@@ -396,7 +397,11 @@ def verify(
396
397
  raise AdoptError(
397
398
  ErrorCode.HANDOVER_CHECKLIST_INVALID,
398
399
  message=f"{checklist} is not valid YAML: {error}",
399
- hint="See `docs/handover-checklist.example.yaml` for the shape.",
400
+ hint="A checklist is a mapping with a `tasks:` list, each task carrying `id`, "
401
+ "`task` and `outcome` (pass | fail | skipped). The annotated example is "
402
+ "docs/handover-checklist.example.yaml in the source tree, or "
403
+ "https://github.com/onboardux/onboard-core/blob/main/"
404
+ "docs/handover-checklist.example.yaml.",
400
405
  ) from error
401
406
  if not isinstance(raw, dict):
402
407
  raise AdoptError(
@@ -39,8 +39,8 @@ ScopeOption = Annotated[
39
39
  str | None,
40
40
  typer.Option(
41
41
  "--scope",
42
- help="firm/engagement/system[/environment], to validate against the boundary "
43
- "declared for that scope. Omitted, the strictest default boundary is used.",
42
+ help="firm/engagement/system, optionally with /environment, to validate against the "
43
+ "boundary declared for that scope. Omitted, the strictest default boundary is used.",
44
44
  ),
45
45
  ]
46
46
  StoreOption = Annotated[Path | None, typer.Option("--store", help="Store path override.")]
@@ -1,6 +0,0 @@
1
- """Generated by scripts/embed_build_info.py; do not edit in a release build."""
2
-
3
- from typing import Final
4
-
5
- SBOM_SHA256: Final[str | None] = '86636f02cad8578ffdc6c4b39fe311c0a8191cafd5fcb323ddb732447dc6b0c8'
6
- BUILD_ID: Final[str | None] = 'github:onboardux/onboard-core:34144382673:1:a1b32208f0a296bc708e283d860023ce7fdf4609'
File without changes
File without changes
File without changes