substratum-cli 0.2.3__tar.gz → 0.2.5__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 (111) hide show
  1. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/PKG-INFO +1 -1
  2. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/__init__.py +1 -1
  3. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/_vendor/client_gate.py +6 -2
  4. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/apply.py +2 -2
  5. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/failing.py +2 -1
  6. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/pr.py +1 -1
  7. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/gitio.py +10 -3
  8. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/session.py +11 -3
  9. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli.egg-info/PKG-INFO +1 -1
  10. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/README.md +0 -0
  11. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/pyproject.toml +0 -0
  12. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/setup.cfg +0 -0
  13. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/README.md +0 -0
  14. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/__main__.py +0 -0
  15. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/_boot.py +0 -0
  16. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/_update.py +0 -0
  17. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/_vendor/__init__.py +0 -0
  18. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/_vendor/_pro_test_derive.py +0 -0
  19. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/_wordmark.py +0 -0
  20. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/account.py +0 -0
  21. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/build_state.py +0 -0
  22. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/cli.py +0 -0
  23. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/codes.py +0 -0
  24. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/__init__.py +0 -0
  25. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/auth.py +0 -0
  26. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/commit.py +0 -0
  27. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/explain.py +0 -0
  28. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/fix.py +0 -0
  29. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/history.py +0 -0
  30. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/init_cmd.py +0 -0
  31. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/replay.py +0 -0
  32. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/scaffold.py +0 -0
  33. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/show.py +0 -0
  34. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/undo.py +0 -0
  35. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/verify.py +0 -0
  36. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/commands/write.py +0 -0
  37. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/config.py +0 -0
  38. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/diffs.py +0 -0
  39. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/engine.py +0 -0
  40. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/langscan.py +0 -0
  41. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/product_ops.py +0 -0
  42. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/refusals.py +0 -0
  43. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/remote.py +0 -0
  44. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/render.py +0 -0
  45. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/result.py +0 -0
  46. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/run_store.py +0 -0
  47. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/runid.py +0 -0
  48. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli/style.py +0 -0
  49. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli.egg-info/SOURCES.txt +0 -0
  50. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli.egg-info/dependency_links.txt +0 -0
  51. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli.egg-info/entry_points.txt +0 -0
  52. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli.egg-info/requires.txt +0 -0
  53. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/substratum_cli.egg-info/top_level.txt +0 -0
  54. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_adaptive_prior.py +0 -0
  55. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_alias_warrant_trace.py +0 -0
  56. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_bidirectional_gate_contracts.py +0 -0
  57. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_coherence_evolution.py +0 -0
  58. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_coherences.py +0 -0
  59. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_connection_web_api.py +0 -0
  60. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_cross_entity_scoping.py +0 -0
  61. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_data.py +0 -0
  62. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_de28_negation_refuse.py +0 -0
  63. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_definite_description_handler.py +0 -0
  64. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_demo_regression_catalog.py +0 -0
  65. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_demo_response_shape.py +0 -0
  66. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_e1_e2_field_alignment.py +0 -0
  67. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_extraction_class_write_time.py +0 -0
  68. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_falsification_predictions.py +0 -0
  69. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_gap_d_wh_normalization.py +0 -0
  70. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_inference.py +0 -0
  71. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_inflection_cvc_rule.py +0 -0
  72. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_inflection_irregular.py +0 -0
  73. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_intervention.py +0 -0
  74. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_invariant.py +0 -0
  75. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_legal_citation_handler.py +0 -0
  76. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_lens_noop_seam.py +0 -0
  77. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_markup_tag_handler.py +0 -0
  78. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_nl_parser.py +0 -0
  79. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_nl_parser_adversarial.py +0 -0
  80. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_noise.py +0 -0
  81. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_pass2_contextual.py +0 -0
  82. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_perspectives.py +0 -0
  83. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_polysemous_token_alias_guard.py +0 -0
  84. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_possessive_normalization.py +0 -0
  85. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_predicate_canon.py +0 -0
  86. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_projection_gate.py +0 -0
  87. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_projection_gate_tag_question.py +0 -0
  88. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_query_normalizer.py +0 -0
  89. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_records_answer_format.py +0 -0
  90. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_referent_aboutness_gate.py +0 -0
  91. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_referent_quality_gate.py +0 -0
  92. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_refuse_message_topic_neutrality.py +0 -0
  93. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_relation_detection.py +0 -0
  94. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_relaxation.py +0 -0
  95. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_residual_content_gate.py +0 -0
  96. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_reverse_lookup_subject_filter.py +0 -0
  97. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_sec_statement_aliases.py +0 -0
  98. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_span_lens.py +0 -0
  99. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_span_lens_query_integration.py +0 -0
  100. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_substrate.py +0 -0
  101. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_synonymy_detector.py +0 -0
  102. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_table_ingest.py +0 -0
  103. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_triple_ingest.py +0 -0
  104. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_two_phase_schema.py +0 -0
  105. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_user_asserted_aliases.py +0 -0
  106. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_v2_api.py +0 -0
  107. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_v2_api_claims.py +0 -0
  108. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_v2_claim_determinism.py +0 -0
  109. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_word_role.py +0 -0
  110. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_word_role_wiring.py +0 -0
  111. {substratum_cli-0.2.3 → substratum_cli-0.2.5}/tests/test_xbrl_doc_aliases.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: substratum-cli
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Substratum: verified-or-refused code, with provenance. The terminal over the comprehension engine.
5
5
  Author: Substratum
6
6
  License: LicenseRef-Proprietary
@@ -5,4 +5,4 @@ Import budget: this package is stdlib-only; the ONLY module reaching into backen
5
5
  """
6
6
  # SINGLE SOURCE OF TRUTH for the release version. pyproject reads this (dynamic version), the boot shows
7
7
  # it, and the update-check compares against it. To cut a release, bump ONLY this line, then publish.
8
- __version__ = "0.2.3"
8
+ __version__ = "0.2.5"
@@ -51,8 +51,11 @@ def _run(cmd: Sequence[str], cwd: str, timeout: int) -> Tuple[Optional[int], str
51
51
  # SHADOWED by the stale pyc (timestamp validation is second-granular), and the
52
52
  # with-patch run silently re-imports the buggy module -- the differential then
53
53
  # reports TEST_FAILED for a genuine fix (or worse directions on other shapes).
54
+ # errors="replace": test output is arbitrary user bytes (a test may print binary or a
55
+ # non-UTF-8 traceback); strict decode would raise UnicodeDecodeError and crash the gate.
56
+ # The verdict is the return code, never the decoded text, so replacement is verdict-neutral.
54
57
  r = subprocess.run(list(cmd), cwd=cwd, capture_output=True, text=True,
55
- timeout=timeout,
58
+ errors="replace", timeout=timeout,
56
59
  env=dict(os.environ, PYTHONHASHSEED="0", TMPDIR="/tmp",
57
60
  PYTHONDONTWRITEBYTECODE="1"))
58
61
  return r.returncode, (r.stdout + "\n" + r.stderr)[-4000:]
@@ -122,7 +125,8 @@ def run_client_gate(repo_dir: str, base_commit: str, edits: Dict[str, str],
122
125
  wt = tempfile.mkdtemp(prefix="cg_wt_", dir=os.environ.get("TMPDIR") or None)
123
126
  try:
124
127
  r = subprocess.run(["git", "-C", repo_dir, "worktree", "add", "--detach", "-f",
125
- wt, base_commit], capture_output=True, text=True, timeout=120)
128
+ wt, base_commit], capture_output=True, text=True,
129
+ errors="replace", timeout=120)
126
130
  if r.returncode != 0:
127
131
  return ClientGateResult(False, "GATE_WORKTREE_FAILED", r.stderr[-300:])
128
132
  cmd = resolve_test_command(wt, test_cmd, test_paths)
@@ -35,10 +35,10 @@ def cmd_apply(repo: str, run_id: str) -> "_result.SubstratumResult":
35
35
  patch = fh.name
36
36
  try:
37
37
  r = subprocess.run(["git", "-C", repo, "apply", "--index", patch],
38
- capture_output=True, text=True)
38
+ capture_output=True, text=True, errors="replace")
39
39
  if r.returncode != 0:
40
40
  r2 = subprocess.run(["git", "-C", repo, "apply", "--3way", patch],
41
- capture_output=True, text=True)
41
+ capture_output=True, text=True, errors="replace")
42
42
  if r2.returncode != 0:
43
43
  return _result.make(codes.REFUSED, run_id, "apply", code=codes.APPLY_STATE_DRIFT,
44
44
  refusal=refusals.build(codes.APPLY_STATE_DRIFT,
@@ -117,7 +117,8 @@ def cmd_failing(repo: str, path: Optional[str] = None, test_command: Optional[st
117
117
  if path:
118
118
  run_argv.append(path)
119
119
  try:
120
- r = subprocess.run(run_argv, cwd=repo, capture_output=True, text=True, timeout=timeout,
120
+ r = subprocess.run(run_argv, cwd=repo, capture_output=True, text=True,
121
+ errors="replace", timeout=timeout,
121
122
  env={**os.environ, "TMPDIR": "/tmp", "CI": "1", "NO_COLOR": "1"})
122
123
  except subprocess.TimeoutExpired:
123
124
  return _refuse(rid, codes.GATE_PRECONDITION, f"the test suite did not finish within {timeout}s")
@@ -66,7 +66,7 @@ def cmd_pr(repo: str, run_id: str = None, title: str = None) -> "_result.Substra
66
66
  if gh:
67
67
  title = title or f"Substratum verified: {res.operation} {target}"[:100]
68
68
  r = subprocess.run([gh, "pr", "create", "--title", title, "--body", body],
69
- cwd=repo, capture_output=True, text=True, timeout=60)
69
+ cwd=repo, capture_output=True, text=True, errors="replace", timeout=60)
70
70
  if r.returncode == 0:
71
71
  return _result.make(codes.PASS, run_id, "pr",
72
72
  data={"url": r.stdout.strip(), "branch": branch, "certified": run_id})
@@ -7,8 +7,13 @@ from typing import List, Optional
7
7
 
8
8
 
9
9
  def _git(repo: str, *args: str, timeout: int = 60) -> subprocess.CompletedProcess:
10
+ # errors="replace": git output carries arbitrary working-tree bytes (a `diff` of a large file
11
+ # git treats as text but that holds a non-UTF-8 byte; a non-ASCII untracked filename). Strict
12
+ # decode would raise UnicodeDecodeError -- this runs on EVERY command via the run-id dirty-hash,
13
+ # so a single binary-ish file in the user's tree would crash the whole CLI. Replacement is
14
+ # deterministic (same bytes -> same text -> same hash), so the run-id story is preserved.
10
15
  return subprocess.run(["git", "-C", repo, *args], capture_output=True, text=True,
11
- timeout=timeout)
16
+ errors="replace", timeout=timeout)
12
17
 
13
18
 
14
19
  def is_git_repo(repo: str) -> bool:
@@ -23,11 +28,13 @@ def apply_reverse(repo: str, diff_text: str) -> tuple[bool, str]:
23
28
  if not diff_text.strip():
24
29
  return False, "empty diff"
25
30
  r = subprocess.run(["git", "-C", repo, "apply", "--reverse", "--3way", "-"],
26
- input=diff_text, capture_output=True, text=True, timeout=60)
31
+ input=diff_text, capture_output=True, text=True,
32
+ errors="replace", timeout=60)
27
33
  if r.returncode == 0:
28
34
  return True, "reverted"
29
35
  r2 = subprocess.run(["git", "-C", repo, "apply", "--reverse", "-"],
30
- input=diff_text, capture_output=True, text=True, timeout=60)
36
+ input=diff_text, capture_output=True, text=True,
37
+ errors="replace", timeout=60)
31
38
  if r2.returncode == 0:
32
39
  return True, "reverted"
33
40
  err = (r.stderr or r2.stderr or "").strip().splitlines()
@@ -592,7 +592,7 @@ class Session:
592
592
  head("MEMORY & PROOF")
593
593
  row("runs", "all you have done, and which refusals became fixes")
594
594
  row("show <run>", "see a run; replay <run> re-runs it byte-identical")
595
- row("history", "re-run earlier commands (!<n> !! !<prefix>)")
595
+ row("history", "the whole build trail; history <word> searches; run <n> replays a line")
596
596
  head("SETUP")
597
597
  row("doctor / init", "check the environment / what this repo can gate")
598
598
  row("login", "connect the hosted engine for fix and write")
@@ -619,6 +619,7 @@ class Session:
619
619
  self.banner()
620
620
  from . import style as S
621
621
  prompt = (S.GOLD + S.g("brand") + " " + S.RESET) if self.color else (S.g("brand") + " ")
622
+ exit_hints = 0
622
623
  while True:
623
624
  try:
624
625
  line = input(prompt)
@@ -626,7 +627,13 @@ class Session:
626
627
  sys.stdout.write("\n")
627
628
  _leave()
628
629
  except KeyboardInterrupt:
630
+ # Ctrl-C clears the current line (readline behavior); it does NOT exit. Users spam it
631
+ # trying to leave and just get blank lines, so surface the real exit the first few
632
+ # times, then stay quiet for power users who use Ctrl-C to clear a half-typed line.
629
633
  sys.stdout.write("\n")
634
+ if exit_hints < 3:
635
+ self._say(" Ctrl-C clears the line. to leave, type /exit (or press Ctrl-D)", _DIM)
636
+ exit_hints += 1
630
637
  continue
631
638
  try:
632
639
  res, keep = self.handle(line)
@@ -638,8 +645,9 @@ class Session:
638
645
  sys.stdout.write("\n")
639
646
  self._say(" cancelled (session still warm)", _CYAN)
640
647
  continue
641
- except Exception as e: # a command fault must not kill the session
642
- self._say(f" error: {e}", _CYAN)
648
+ except Exception as e: # belt: the ops refuse, never raise -- but a fault must not kill the session
649
+ self._say(f" unexpected internal error: {e}", _CYAN)
650
+ self._say(" the session is still warm; retry or try a different request", _DIM)
643
651
  continue
644
652
  if not keep:
645
653
  _leave()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: substratum-cli
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Substratum: verified-or-refused code, with provenance. The terminal over the comprehension engine.
5
5
  Author: Substratum
6
6
  License: LicenseRef-Proprietary
File without changes
File without changes