nabla-cli 0.5.0__tar.gz → 0.5.2__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 (35) hide show
  1. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/PKG-INFO +1 -1
  2. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/__init__.py +1 -1
  3. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/cli.py +46 -19
  4. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/ui.py +15 -3
  5. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla_cli.egg-info/PKG-INFO +1 -1
  6. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/pyproject.toml +1 -1
  7. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/README.md +0 -0
  8. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/__main__.py +0 -0
  9. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/branding.py +0 -0
  10. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/config.py +0 -0
  11. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/contract.py +0 -0
  12. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/induce.py +0 -0
  13. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/profile.py +0 -0
  14. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/prompt_recon.py +0 -0
  15. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/recorder.py +0 -0
  16. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/samplegen.py +0 -0
  17. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/scanner.py +0 -0
  18. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/schema_resolver.py +0 -0
  19. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/schemas/site_profile.schema.json +0 -0
  20. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla/term.py +0 -0
  21. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla_cli.egg-info/SOURCES.txt +0 -0
  22. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla_cli.egg-info/dependency_links.txt +0 -0
  23. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla_cli.egg-info/entry_points.txt +0 -0
  24. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla_cli.egg-info/requires.txt +0 -0
  25. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/nabla_cli.egg-info/top_level.txt +0 -0
  26. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/setup.cfg +0 -0
  27. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/tests/test_cli_ux.py +0 -0
  28. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/tests/test_config.py +0 -0
  29. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/tests/test_e2e_profile.py +0 -0
  30. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/tests/test_induce.py +0 -0
  31. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/tests/test_prompt_recon.py +0 -0
  32. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/tests/test_recorder.py +0 -0
  33. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/tests/test_samplegen.py +0 -0
  34. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/tests/test_scanner.py +0 -0
  35. {nabla_cli-0.5.0 → nabla_cli-0.5.2}/tests/test_schema_resolver.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nabla-cli
3
- Version: 0.5.0
3
+ Version: 0.5.2
4
4
  Summary: Call-site harvester: scan OpenAI call sites, record real traffic, emit site profiles
5
5
  License: MIT
6
6
  Requires-Python: >=3.11
@@ -1,3 +1,3 @@
1
1
  """nabla — call-site harvester CLI (pre-Phase-0)."""
2
2
 
3
- __version__ = "0.5.0"
3
+ __version__ = "0.5.2"
@@ -488,10 +488,9 @@ def _cmd_record(args) -> int:
488
488
  rail(_out, f"using {conventional} (found by convention; pass --inputs to override)")
489
489
  source = RecordSource(kind="samples", samples_file=str(conventional))
490
490
  else:
491
- source, err = _generate_samples_source(args, site, Path(f"{site.symbol}.inputs.jsonl"))
491
+ source, source_kind, err = _resolve_inputs_interactively(args, site)
492
492
  if err is not None:
493
493
  return err
494
- source_kind = "generated_samples"
495
494
 
496
495
  on_progress = None
497
496
  progress = None
@@ -538,26 +537,54 @@ def _cmd_record(args) -> int:
538
537
  return 0
539
538
 
540
539
 
541
- def _generate_samples_source(args, site, out_path: Path):
542
- """No samples given and none found by convention: generate synthetic
543
- inputs with the configured provider, persist them for inspection, and
544
- record through them. Returns (RecordSource, None) or (None, exit_code)."""
545
- from .induce import InduceError
546
- from .prompt_recon import reconstruct
547
- from .samplegen import SampleGenError, generate_samples
540
+ def _resolve_inputs_interactively(args, site):
541
+ """No --inputs given and no conventional file found. Interactively, ask
542
+ where inputs come from (generate N / custom count / own file); otherwise
543
+ generate the default quietly. Returns (source, source_kind, exit_code)
544
+ with exit_code None on success."""
545
+ from .ui import prompt_text, select
548
546
 
549
547
  n = args.num_samples
550
- if n is None:
551
- if _out.is_terminal and sys.stdin.isatty():
552
- from .ui import select
553
- options = [
554
- ("5", "quick lookfastest, fewest credits"),
555
- ("10", "balanced decent goal inference"),
556
- ("20", "handoff floor slowest, most credits"),
557
- ]
558
- n = int(options[select(_out, "Synthetic inputs", options)][0])
548
+ if n is None and _out.is_terminal and sys.stdin.isatty():
549
+ options = [
550
+ ("generate 5", "synthetic inputs — quick look, fewest credits"),
551
+ ("generate 10", "synthetic inputs — balanced"),
552
+ ("generate 20", "synthetic inputshandoff floor, most credits"),
553
+ ("custom count", "type how many synthetic inputs to generate"),
554
+ ("my own file", "type a path to your JSONL of inputs"),
555
+ ]
556
+ choice = select(_out, "Inputs", options)
557
+ if choice == 3:
558
+ while True:
559
+ typed = prompt_text(_out, "How many", default="5")
560
+ if typed.isdigit() and int(typed) > 0:
561
+ n = int(typed)
562
+ break
563
+ _warn("enter a positive number")
564
+ elif choice == 4:
565
+ while True:
566
+ typed = prompt_text(_out, "Path to JSONL")
567
+ if typed and Path(typed).exists():
568
+ return RecordSource(kind="samples", samples_file=typed), None, None
569
+ _warn(f"{typed or '(empty)'} not found — try again, or Ctrl+C to abort")
559
570
  else:
560
- n = 5
571
+ n = (5, 10, 20)[choice]
572
+ elif n is None:
573
+ n = 5
574
+
575
+ source, err = _generate_samples_source(args, site, Path(f"{site.symbol}.inputs.jsonl"), n)
576
+ if err is not None:
577
+ return None, None, err
578
+ return source, "generated_samples", None
579
+
580
+
581
+ def _generate_samples_source(args, site, out_path: Path, n: int):
582
+ """Generate synthetic inputs with the configured provider, persist them
583
+ for inspection, and record through them. Returns (RecordSource, None)
584
+ or (None, exit_code)."""
585
+ from .induce import InduceError
586
+ from .prompt_recon import reconstruct
587
+ from .samplegen import SampleGenError, generate_samples
561
588
 
562
589
  template = reconstruct(site, args.repo)
563
590
  schema, _ = resolve_schema(site, args.repo)
@@ -23,8 +23,8 @@ from rich.text import Text
23
23
 
24
24
  RAIL = "│"
25
25
  _POINTER = "❯"
26
- _ON = ""
27
- _OFF = ""
26
+ _ON = "[∇]" # selected: the brand mark, filled in
27
+ _OFF = "[ ]"
28
28
 
29
29
 
30
30
  # ---------------------------------------------------------------------------
@@ -111,7 +111,7 @@ def select(console: Console, label: str, options: list[tuple[str, str]],
111
111
  row.append(f"{name:<{name_width}}", style="bold cyan")
112
112
  else:
113
113
  # Unselected is quieter, never grey — grey reads as disabled.
114
- row.append(f" {_OFF} ", style="dim")
114
+ row.append(f" {_OFF} ", style="")
115
115
  row.append(f"{name:<{name_width}}")
116
116
  row.append(f" {desc}", style="dim")
117
117
  console.print(row)
@@ -141,6 +141,18 @@ def select(console: Console, label: str, options: list[tuple[str, str]],
141
141
  return idx
142
142
 
143
143
 
144
+ def prompt_text(console: Console, label: str, default: str = "") -> str:
145
+ """Typed input on the rail: styled label, plain typing, default on enter."""
146
+ prompt = Text(f"{RAIL} ", style="dim")
147
+ prompt.append(label, style="bold")
148
+ if default:
149
+ prompt.append(f" [{default}]", style="dim")
150
+ prompt.append(" ")
151
+ console.print(prompt, end="")
152
+ value = input().strip()
153
+ return value or default
154
+
155
+
144
156
  # ---------------------------------------------------------------------------
145
157
  # Progress
146
158
  # ---------------------------------------------------------------------------
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nabla-cli
3
- Version: 0.5.0
3
+ Version: 0.5.2
4
4
  Summary: Call-site harvester: scan OpenAI call sites, record real traffic, emit site profiles
5
5
  License: MIT
6
6
  Requires-Python: >=3.11
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nabla-cli"
3
- version = "0.5.0"
3
+ version = "0.5.2"
4
4
  description = "Call-site harvester: scan OpenAI call sites, record real traffic, emit site profiles"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
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