substratum-cli 0.2.0__tar.gz → 0.2.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.
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/PKG-INFO +1 -1
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/__init__.py +1 -1
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/_boot.py +5 -3
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/session.py +50 -9
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli.egg-info/PKG-INFO +1 -1
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/README.md +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/pyproject.toml +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/setup.cfg +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/README.md +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/__main__.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/_update.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/_vendor/__init__.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/_vendor/_pro_test_derive.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/_wordmark.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/account.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/build_state.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/cli.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/codes.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/__init__.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/apply.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/auth.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/commit.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/explain.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/failing.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/fix.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/history.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/init_cmd.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/pr.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/replay.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/scaffold.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/show.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/undo.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/verify.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/commands/write.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/config.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/diffs.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/engine.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/gitio.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/langscan.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/product_ops.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/refusals.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/remote.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/render.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/result.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/run_store.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/runid.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli/style.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli.egg-info/SOURCES.txt +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli.egg-info/dependency_links.txt +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli.egg-info/entry_points.txt +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli.egg-info/requires.txt +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/substratum_cli.egg-info/top_level.txt +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_adaptive_prior.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_alias_warrant_trace.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_bidirectional_gate_contracts.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_coherence_evolution.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_coherences.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_connection_web_api.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_cross_entity_scoping.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_data.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_de28_negation_refuse.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_definite_description_handler.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_demo_regression_catalog.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_demo_response_shape.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_e1_e2_field_alignment.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_extraction_class_write_time.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_falsification_predictions.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_gap_d_wh_normalization.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_inference.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_inflection_cvc_rule.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_inflection_irregular.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_intervention.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_invariant.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_legal_citation_handler.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_lens_noop_seam.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_markup_tag_handler.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_nl_parser.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_nl_parser_adversarial.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_noise.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_pass2_contextual.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_perspectives.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_polysemous_token_alias_guard.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_possessive_normalization.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_predicate_canon.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_projection_gate.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_projection_gate_tag_question.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_query_normalizer.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_records_answer_format.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_referent_aboutness_gate.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_referent_quality_gate.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_refuse_message_topic_neutrality.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_relation_detection.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_relaxation.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_residual_content_gate.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_reverse_lookup_subject_filter.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_sec_statement_aliases.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_span_lens.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_span_lens_query_integration.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_substrate.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_synonymy_detector.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_table_ingest.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_triple_ingest.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_two_phase_schema.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_user_asserted_aliases.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_v2_api.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_v2_api_claims.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_v2_claim_determinism.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_word_role.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_word_role_wiring.py +0 -0
- {substratum_cli-0.2.0 → substratum_cli-0.2.1}/tests/test_xbrl_doc_aliases.py +0 -0
|
@@ -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.
|
|
8
|
+
__version__ = "0.2.1"
|
|
@@ -145,16 +145,18 @@ def render(name, census, langs, libname, patterns, warm, standing, version,
|
|
|
145
145
|
# fix + write run on the hosted engine; summarize/failing/verify run offline. Say so BEFORE they hit
|
|
146
146
|
# a NO_ENGINE refusal, and pick an ask-example that actually works in their current state.
|
|
147
147
|
ask_ex = '"fix the failing test"' if logged_in else '"what does this codebase do?"'
|
|
148
|
+
# the signpost text aligns at col 4 -- the same column as the welcome-back text -- so the whole bottom
|
|
149
|
+
# "here is what you can do" region reads as one clean left edge instead of jutting out under the box.
|
|
148
150
|
out += [""]
|
|
149
151
|
if update_to: # a pip package cannot self-update; hand over the one command
|
|
150
152
|
arrow = "^" if ascii_mode else "↑"
|
|
151
|
-
out += ["
|
|
153
|
+
out += [" " + c(GO, f"{arrow} update") + c(LAB, f" Substratum {update_to} is available")
|
|
152
154
|
+ c(CH, f" {dot} ") + c(GO, "pip install --upgrade substratum-cli")]
|
|
153
155
|
if not logged_in:
|
|
154
|
-
out += ["
|
|
156
|
+
out += [" " + c(GO, "login") + c(LAB, " to ") + c(DAT, "fix") + c(LAB, " and ") + c(DAT, "write")
|
|
155
157
|
+ c(LAB, " code (connects the engine)")
|
|
156
158
|
+ c(CH, f" {dot} ") + c(LAB, "summarize, failing, verify work offline")]
|
|
157
|
-
out += ["
|
|
159
|
+
out += [" " + c(GO, "help") + c(LAB, " see everything you can do")
|
|
158
160
|
+ c(CH, f" {dot} ") + c(LAB, "or just ask: ") + c(GO, ask_ex)]
|
|
159
161
|
return out
|
|
160
162
|
|
|
@@ -12,6 +12,7 @@ model, the run store, and the gate are all identical. The session adds no new en
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
14
|
import os
|
|
15
|
+
import re
|
|
15
16
|
import shlex
|
|
16
17
|
import sys
|
|
17
18
|
import threading
|
|
@@ -179,6 +180,15 @@ class Session:
|
|
|
179
180
|
return None, True
|
|
180
181
|
self._say(" " + self._paint(recalled, _DIM)) # echo what is being re-run
|
|
181
182
|
line = recalled
|
|
183
|
+
# plain-language re-run: "run 12" replays history line 12 (clearer than the cryptic "!" syntax)
|
|
184
|
+
_rm = re.match(r"^run\s+(-?\d+)$", line)
|
|
185
|
+
if _rm:
|
|
186
|
+
recalled = self._recall(_rm.group(1))
|
|
187
|
+
if recalled is None:
|
|
188
|
+
self._say(f" no history line {_rm.group(1)} -- type history to see them", _CYAN)
|
|
189
|
+
return None, True
|
|
190
|
+
self._say(" " + self._paint(recalled, _DIM))
|
|
191
|
+
line = recalled
|
|
182
192
|
try:
|
|
183
193
|
parts = shlex.split(line)
|
|
184
194
|
except ValueError:
|
|
@@ -254,7 +264,7 @@ class Session:
|
|
|
254
264
|
{"login": auth.cmd_login, "logout": auth.cmd_logout, "whoami": auth.cmd_whoami}[cmd]()
|
|
255
265
|
return None, True
|
|
256
266
|
if cmd in ("history", "hist"):
|
|
257
|
-
self._history_cmd()
|
|
267
|
+
self._history_cmd(" ".join(args))
|
|
258
268
|
return None, True
|
|
259
269
|
if cmd in ("runs", "log"):
|
|
260
270
|
from .commands.history import cmd_runs
|
|
@@ -302,15 +312,46 @@ class Session:
|
|
|
302
312
|
return c
|
|
303
313
|
return None
|
|
304
314
|
|
|
305
|
-
def _history_cmd(self):
|
|
306
|
-
|
|
307
|
-
|
|
315
|
+
def _history_cmd(self, arg=""):
|
|
316
|
+
# The trail is PERSISTENT (grows across sessions, can be hundreds), so never dump it all: show a
|
|
317
|
+
# recent window with the total, let `history <word>` search and `history all` widen. Re-run is a
|
|
318
|
+
# plain verb -- `run <n>` -- not the cryptic bash `!` (which still works for shell muscle memory).
|
|
319
|
+
from . import style as S
|
|
320
|
+
pn = S.Painter(self.color)
|
|
321
|
+
h = self._history
|
|
322
|
+
if not h:
|
|
323
|
+
self._say(" " + pn("no commands yet", S.CHROME))
|
|
324
|
+
return
|
|
325
|
+
arg = (arg or "").strip()
|
|
326
|
+
total = len(h)
|
|
327
|
+
indexed = list(enumerate(h, 1))
|
|
328
|
+
if arg == "all":
|
|
329
|
+
items = indexed[-60:]
|
|
330
|
+
head = f"showing last {len(items)} of {total}"
|
|
331
|
+
elif arg:
|
|
332
|
+
hits = [(i, c) for i, c in indexed if arg.lower() in c.lower()]
|
|
333
|
+
items = hits[-40:]
|
|
334
|
+
head = (f"{len(hits)} match" + ("" if len(hits) == 1 else "es") + f' for "{arg}"'
|
|
335
|
+
+ (" (last 40)" if len(hits) > 40 else ""))
|
|
336
|
+
else:
|
|
337
|
+
items = indexed[-15:]
|
|
338
|
+
head = (f"last {len(items)} of {total}" if total > len(items)
|
|
339
|
+
else f"{total} command" + ("" if total == 1 else "s"))
|
|
340
|
+
self._say(" " + pn("history", S.BOLD) + " " + pn(head, S.LABEL))
|
|
341
|
+
w = len(str(total))
|
|
342
|
+
for i, c in items:
|
|
343
|
+
self._say(" " + pn(str(i).rjust(w), S.CHROME) + " "
|
|
344
|
+
+ pn(S.ellipsize(c, S.read_width() - w - 8), S.LABEL))
|
|
345
|
+
if not items:
|
|
346
|
+
self._say(" " + pn(f'nothing matches "{arg}" -- try another word', S.CHROME))
|
|
308
347
|
return
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
348
|
+
eg = items[-1][0] # a concrete number the user can copy
|
|
349
|
+
bits = [pn("run " + str(eg), S.GOLD) + pn(" replays that line", S.CHROME)]
|
|
350
|
+
if not arg:
|
|
351
|
+
bits.append(pn("history <word>", S.GOLD) + pn(" searches", S.CHROME))
|
|
352
|
+
if total > len(items):
|
|
353
|
+
bits.append(pn("history all", S.GOLD) + pn(" shows more", S.CHROME))
|
|
354
|
+
self._say(" " + pn(" · ", S.CHROME).join(bits))
|
|
314
355
|
|
|
315
356
|
# ---- natural-language router (closed-class, deterministic, no LLM) ----
|
|
316
357
|
def _route_nl(self, line: str):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|