skit-cli 0.0.1__tar.gz → 0.1.0__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.
- {skit_cli-0.0.1 → skit_cli-0.1.0}/PKG-INFO +10 -1
- {skit_cli-0.0.1 → skit_cli-0.1.0}/README.md +9 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/pyproject.toml +1 -1
- skit_cli-0.1.0/src/skit/__init__.py +20 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/cli.py +55 -23
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/config.py +22 -2
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/flows.py +12 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/locales/skit.pot +322 -284
- skit_cli-0.1.0/src/skit/locales/zh_CN/LC_MESSAGES/skit.mo +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/locales/zh_CN/LC_MESSAGES/skit.po +326 -285
- skit_cli-0.1.0/src/skit/locales/zh_TW/LC_MESSAGES/skit.mo +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/locales/zh_TW/LC_MESSAGES/skit.po +326 -285
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/tui.py +102 -7
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/tui_add.py +98 -6
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/tui_footer.py +34 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/tui_form.py +7 -2
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/tui_prefs.py +29 -4
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/tui_settings.py +5 -1
- skit_cli-0.0.1/src/skit/__init__.py +0 -3
- skit_cli-0.0.1/src/skit/locales/zh_CN/LC_MESSAGES/skit.mo +0 -0
- skit_cli-0.0.1/src/skit/locales/zh_TW/LC_MESSAGES/skit.mo +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/LICENSE +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/analyzer.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/argspec.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/argstate.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/atomic.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/editor.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/i18n.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/inlineform.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/launcher.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/metawriter.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/models.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/paths.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/pep723.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/promptform.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/reconcile.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/shim.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/store.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/theme.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/tokens.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/tui_health.py +0 -0
- {skit_cli-0.0.1 → skit_cli-0.1.0}/src/skit/uvman.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: skit-cli
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
4
|
Summary: Script launcher and parameter manager: pick a script, fill in a form, run — no more opening an IDE just to tweak constants.
|
|
5
5
|
Keywords: script,launcher,uv,tui,pep723,script-manager
|
|
6
6
|
Author: Yi-Ting Chiu
|
|
@@ -102,6 +102,15 @@ uv tool install git+https://github.com/t41372/skit # latest development
|
|
|
102
102
|
uvx --from git+https://github.com/t41372/skit skit --help # try it without installing
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
## Update
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
uv tool upgrade skit-cli # update to the latest release — also how you "check": it says up to date if you are
|
|
109
|
+
skit --version # the version you're on
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`uv tool upgrade` follows whatever source you installed from: PyPI installs track PyPI releases, `git+…` installs re-fetch the main branch.
|
|
113
|
+
|
|
105
114
|
## Uninstall
|
|
106
115
|
|
|
107
116
|
```bash
|
|
@@ -72,6 +72,15 @@ uv tool install git+https://github.com/t41372/skit # latest development
|
|
|
72
72
|
uvx --from git+https://github.com/t41372/skit skit --help # try it without installing
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
## Update
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv tool upgrade skit-cli # update to the latest release — also how you "check": it says up to date if you are
|
|
79
|
+
skit --version # the version you're on
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`uv tool upgrade` follows whatever source you installed from: PyPI installs track PyPI releases, `git+…` installs re-fetch the main branch.
|
|
83
|
+
|
|
75
84
|
## Uninstall
|
|
76
85
|
|
|
77
86
|
```bash
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Distribution name only ("skit" is admin-prohibited on PyPI); the import package,
|
|
3
3
|
# CLI command, and config dirs all stay "skit".
|
|
4
4
|
name = "skit-cli"
|
|
5
|
-
version = "0.0
|
|
5
|
+
version = "0.1.0"
|
|
6
6
|
description = "Script launcher and parameter manager: pick a script, fill in a form, run — no more opening an IDE just to tweak constants."
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
requires-python = ">=3.12"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""skit — a launcher and parameter manager for your scripts."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
5
|
+
|
|
6
|
+
# Textual ≥ 8.2.7 enables the kitty keyboard protocol's "report all keys" mode, which
|
|
7
|
+
# iTerm2 (3.6.x) implements in a way that fights the macOS IME: candidate-selection
|
|
8
|
+
# digits and Enter reach the app as raw key events and the composed CJK text is never
|
|
9
|
+
# delivered at all (iTerm2 issue 12906) — Chinese/Japanese/Korean typing breaks. No
|
|
10
|
+
# skit binding needs the protocol, so opt out before the first textual import
|
|
11
|
+
# (textual.constants reads this at import time). setdefault keeps an explicit user
|
|
12
|
+
# override (=0 re-enables) winning.
|
|
13
|
+
os.environ.setdefault("TEXTUAL_DISABLE_KITTY_KEY", "1")
|
|
14
|
+
|
|
15
|
+
# pyproject.toml is the single source of the version; installed distributions carry it
|
|
16
|
+
# as metadata (a wheel doesn't ship pyproject.toml), so read it from there.
|
|
17
|
+
try:
|
|
18
|
+
__version__ = version("skit-cli")
|
|
19
|
+
except PackageNotFoundError: # a bare checkout on sys.path, no installed dist
|
|
20
|
+
__version__ = "0.0.0+unknown"
|
|
@@ -536,16 +536,40 @@ def add(
|
|
|
536
536
|
gettext("Can't read %(path)s: %(error)s")
|
|
537
537
|
% {"path": str(resolved), "error": exc.strerror or str(exc)}
|
|
538
538
|
) from exc
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
539
|
+
# Interactive + mini-form style: host the SAME review panel the TUI's
|
|
540
|
+
# `a` opens (flags prefill it). Pipes/CI/--no-input/form=plain keep the
|
|
541
|
+
# line-prompt path — the non-interactive contract is untouched.
|
|
542
|
+
if (
|
|
543
|
+
not no_input
|
|
544
|
+
and _is_interactive()
|
|
545
|
+
and os.environ.get("TERM") != "dumb"
|
|
546
|
+
and config.load_form() == "tui"
|
|
547
|
+
):
|
|
548
|
+
from .tui_add import run_add_review
|
|
549
|
+
|
|
550
|
+
slug = run_add_review(
|
|
551
|
+
Path(path),
|
|
552
|
+
name=name,
|
|
553
|
+
description=description,
|
|
554
|
+
reference=ref,
|
|
555
|
+
deps=dep,
|
|
556
|
+
requires_python=python or "",
|
|
557
|
+
)
|
|
558
|
+
if slug is None:
|
|
559
|
+
console.print(f"[dim]{gettext('Cancelled — nothing was added.')}[/dim]")
|
|
560
|
+
raise typer.Exit(EXIT_CANCELLED)
|
|
561
|
+
entry = store.resolve(slug)
|
|
562
|
+
else:
|
|
563
|
+
entry, summary_deps, summary_managed, summary_secrets = _onboard_python(
|
|
564
|
+
Path(path),
|
|
565
|
+
text,
|
|
566
|
+
name=name,
|
|
567
|
+
description=description,
|
|
568
|
+
ref=ref,
|
|
569
|
+
deps_opt=dep,
|
|
570
|
+
python_opt=python,
|
|
571
|
+
no_input=no_input,
|
|
572
|
+
)
|
|
549
573
|
except store.StoreError as exc:
|
|
550
574
|
raise _fail(str(exc), 1) from exc
|
|
551
575
|
_print_add_summary(entry, summary_deps, summary_managed, summary_secrets)
|
|
@@ -772,13 +796,8 @@ def _collect_values(
|
|
|
772
796
|
|
|
773
797
|
|
|
774
798
|
# How a flows.RunOutcome failure maps to skit's exit-code contract (docker convention).
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
flows.FAIL_DRIFT: EXIT_SKIT,
|
|
778
|
-
flows.FAIL_LAUNCH: EXIT_SKIT,
|
|
779
|
-
flows.FAIL_NOT_EXECUTABLE: EXIT_NOT_EXECUTABLE,
|
|
780
|
-
flows.FAIL_MISSING: EXIT_NOT_FOUND,
|
|
781
|
-
}
|
|
799
|
+
# The numbers live in flows so the TUI's exit-after-run path shares them.
|
|
800
|
+
_FAILURE_EXIT = flows.FAILURE_EXIT_CODES
|
|
782
801
|
|
|
783
802
|
|
|
784
803
|
@app.command(
|
|
@@ -1461,7 +1480,7 @@ def doctor(
|
|
|
1461
1480
|
# config (git-config grammar: bare = list, KEY = read, KEY VALUE = write)
|
|
1462
1481
|
# --------------------------------------------------------------------------
|
|
1463
1482
|
|
|
1464
|
-
_CONFIG_KEYS = ("lang", "editor", "mirror", "form")
|
|
1483
|
+
_CONFIG_KEYS = ("lang", "editor", "mirror", "form", "after_run")
|
|
1465
1484
|
|
|
1466
1485
|
|
|
1467
1486
|
def _config_value(key: str) -> str:
|
|
@@ -1475,7 +1494,9 @@ def _config_value(key: str) -> str:
|
|
|
1475
1494
|
if key == "mirror":
|
|
1476
1495
|
m = config.load_mirror()
|
|
1477
1496
|
return m.pypi if m.enabled else "off"
|
|
1478
|
-
|
|
1497
|
+
if key == "form":
|
|
1498
|
+
return config.load_form()
|
|
1499
|
+
return config.load_after_run() # "after_run" — _CONFIG_KEYS guards the key set
|
|
1479
1500
|
|
|
1480
1501
|
|
|
1481
1502
|
def _config_set(key: str, value: str) -> None:
|
|
@@ -1499,22 +1520,33 @@ def _config_set(key: str, value: str) -> None:
|
|
|
1499
1520
|
f"[red]{gettext('Unknown mirror: %(name)s. Choose from: %(names)s') % {'name': escape(value), 'names': choices}}[/red]"
|
|
1500
1521
|
)
|
|
1501
1522
|
raise typer.Exit(EXIT_USAGE)
|
|
1502
|
-
|
|
1523
|
+
elif key == "form":
|
|
1503
1524
|
if value not in config.FORM_STYLES:
|
|
1504
1525
|
err_console.print(
|
|
1505
1526
|
f"[red]{gettext('Unknown form style: %(value)s. Choose from: tui, plain') % {'value': escape(value)}}[/red]"
|
|
1506
1527
|
)
|
|
1507
1528
|
raise typer.Exit(EXIT_USAGE)
|
|
1508
1529
|
config.save_form(value)
|
|
1530
|
+
else: # after_run
|
|
1531
|
+
if value not in config.AFTER_RUN_MODES:
|
|
1532
|
+
err_console.print(
|
|
1533
|
+
f"[red]{gettext('Unknown after-run behavior: %(value)s. Choose from: exit, stay') % {'value': escape(value)}}[/red]"
|
|
1534
|
+
)
|
|
1535
|
+
raise typer.Exit(EXIT_USAGE)
|
|
1536
|
+
config.save_after_run(value)
|
|
1509
1537
|
|
|
1510
1538
|
|
|
1511
1539
|
@app.command(
|
|
1512
1540
|
"config",
|
|
1513
|
-
help=gettext("Read or set skit's settings (language, editor, mirror, form style)."),
|
|
1514
|
-
epilog=gettext(
|
|
1541
|
+
help=gettext("Read or set skit's settings (language, editor, mirror, form style, after-run)."),
|
|
1542
|
+
epilog=gettext(
|
|
1543
|
+
"Examples: skit config · skit config lang zh-TW · skit config after_run stay"
|
|
1544
|
+
),
|
|
1515
1545
|
)
|
|
1516
1546
|
def config_cmd(
|
|
1517
|
-
key: str = typer.Argument(
|
|
1547
|
+
key: str = typer.Argument(
|
|
1548
|
+
None, help=gettext("Setting name: lang / editor / mirror / form / after_run")
|
|
1549
|
+
),
|
|
1518
1550
|
value: str = typer.Argument(
|
|
1519
1551
|
None, help=gettext('New value (omit to read; lang also accepts "auto")')
|
|
1520
1552
|
),
|
|
@@ -136,8 +136,10 @@ FORM_STYLES = ("tui", "plain")
|
|
|
136
136
|
|
|
137
137
|
|
|
138
138
|
def load_form() -> str:
|
|
139
|
-
"""Interactive-form style: "tui" (inline mini-form, the default) or
|
|
140
|
-
prompts).
|
|
139
|
+
"""Interactive-form style: "tui" (inline mini-form / review panel, the default) or
|
|
140
|
+
"plain" (line prompts). Consumed by the CLI's interactive flows — `skit run`
|
|
141
|
+
parameter collection and `skit add`'s review panel; the TUI workbench always uses
|
|
142
|
+
its own full screens."""
|
|
141
143
|
value = load_config().get("form", "") # pragma: no mutate — normalized below
|
|
142
144
|
return value if value in FORM_STYLES else "tui"
|
|
143
145
|
|
|
@@ -149,6 +151,24 @@ def save_form(style: str) -> None:
|
|
|
149
151
|
save_config(doc)
|
|
150
152
|
|
|
151
153
|
|
|
154
|
+
AFTER_RUN_MODES = ("exit", "stay")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def load_after_run() -> str:
|
|
158
|
+
"""What the TUI does when a launched script finishes: "exit" (the default — skit is
|
|
159
|
+
a launcher, so it quits and passes the script's exit code through) or "stay"
|
|
160
|
+
(banner + Enter returns to the Library, the workbench loop)."""
|
|
161
|
+
value = load_config().get("after_run", "") # pragma: no mutate — normalized below
|
|
162
|
+
return value if value in AFTER_RUN_MODES else "exit"
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def save_after_run(mode: str) -> None:
|
|
166
|
+
"""Persist the after-run behavior, preserving every other key."""
|
|
167
|
+
doc = _load_config_for_save()
|
|
168
|
+
doc["after_run"] = mode
|
|
169
|
+
save_config(doc)
|
|
170
|
+
|
|
171
|
+
|
|
152
172
|
@dataclass(frozen=True)
|
|
153
173
|
class MirrorConfig:
|
|
154
174
|
enabled: bool = False
|
|
@@ -485,6 +485,18 @@ FAIL_MISSING = "missing" # the launch target is gone from disk
|
|
|
485
485
|
FAIL_NOT_EXECUTABLE = "not_executable" # an exe exists but isn't +x
|
|
486
486
|
FAIL_LAUNCH = "launch" # any other launch failure
|
|
487
487
|
|
|
488
|
+
# Docker-convention process exit codes when the launch itself failed (the script's own
|
|
489
|
+
# exit code passes through untouched whenever it did run): skit failures are 125, an
|
|
490
|
+
# existing-but-unexecutable target 126, a missing target 127. Shared by `skit run` and
|
|
491
|
+
# the TUI's exit-after-run path so the contract can't fork.
|
|
492
|
+
FAILURE_EXIT_CODES = {
|
|
493
|
+
FAIL_BAD_VALUE: 125,
|
|
494
|
+
FAIL_DRIFT: 125,
|
|
495
|
+
FAIL_LAUNCH: 125,
|
|
496
|
+
FAIL_NOT_EXECUTABLE: 126,
|
|
497
|
+
FAIL_MISSING: 127,
|
|
498
|
+
}
|
|
499
|
+
|
|
488
500
|
|
|
489
501
|
@dataclass
|
|
490
502
|
class RunOutcome:
|