typesafeai-cli 0.3.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.
- typesafeai_cli-0.3.1/.gitignore +14 -0
- typesafeai_cli-0.3.1/LICENSE +21 -0
- typesafeai_cli-0.3.1/PKG-INFO +137 -0
- typesafeai_cli-0.3.1/README.md +113 -0
- typesafeai_cli-0.3.1/examples/README.md +15 -0
- typesafeai_cli-0.3.1/examples/code-change/questions.json +25 -0
- typesafeai_cli-0.3.1/examples/code-change/state.json +10 -0
- typesafeai_cli-0.3.1/examples/ticket/questions.json +24 -0
- typesafeai_cli-0.3.1/examples/ticket/state.json +4 -0
- typesafeai_cli-0.3.1/install.sh +125 -0
- typesafeai_cli-0.3.1/pyproject.toml +55 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/__init__.py +1 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/cli.py +93 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/client.py +106 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/__init__.py +0 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/agent.py +12 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/ask.py +90 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/auth.py +28 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/decide.py +43 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/eval.py +37 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/extract.py +83 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/find.py +53 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/models.py +30 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/oneshot.py +91 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/rank.py +49 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/screen.py +38 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/skills.py +138 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/smoke.py +35 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/suggest_skill.py +48 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/commands/verify.py +53 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/config.py +37 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/data/__init__.py +0 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/data/typesafe-ai/CLI.md +7 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/data/typesafe-ai/SKILL.md +149 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/data/typesafe-cli/SKILL.md +137 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/detect.py +83 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/format.py +22 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/help.py +36 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/io.py +17 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/questions.py +96 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/recipes/__init__.py +3 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/recipes/decide.py +64 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/recipes/extract.py +42 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/recipes/find.py +90 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/recipes/rank.py +97 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/recipes/screen.py +68 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/recipes/skills.py +148 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/recipes/thresholds.py +24 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/recipes/verify.py +48 -0
- typesafeai_cli-0.3.1/src/typesafe_cli/schema.py +150 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 typesafeai-cli contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: typesafeai-cli
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Agent CLI for TypeSafe System One (Jev)
|
|
5
|
+
Project-URL: Homepage, https://github.com/maddygoround/typesafeai-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/maddygoround/typesafeai-cli
|
|
7
|
+
Project-URL: Issues, https://github.com/maddygoround/typesafeai-cli/issues
|
|
8
|
+
Project-URL: Releases, https://github.com/maddygoround/typesafeai-cli/releases
|
|
9
|
+
Author: safeaiforeveryone
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: cli,jev,typesafe
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Utilities
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: typer>=0.12
|
|
22
|
+
Requires-Dist: typesafe-sdk>=0.6.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# TypeSafe agent CLI
|
|
26
|
+
|
|
27
|
+
`typesafe` is an **agent CLI** for [TypeSafe](https://typesafe.ai) **Jev**.
|
|
28
|
+
|
|
29
|
+
It is meant to be invoked by coding agents (Grok, Codex, Claude Code, Cursor, and anything else that can run a shell command). You can run it yourself while you debug; the usual caller is an agent.
|
|
30
|
+
|
|
31
|
+
Jev does not chat. The agent gathers a small JSON document (`state`) and typed questions (`noul`, `choice`, `score`). This CLI sends that to `POST /v1/systemone` and prints probabilities on stdout. Jev never sees the repo unless the agent copies the relevant slices into `state`.
|
|
32
|
+
|
|
33
|
+
You do not hand-write production payloads every day. Install the **typesafe-cli** skill, and the agent writes the JSON (in a temp directory, not in git). The files under [`examples/`](examples/) exist so you can see the shape, and so you can run a call without inventing one.
|
|
34
|
+
|
|
35
|
+
## JSON shape
|
|
36
|
+
|
|
37
|
+
Two files. Names are yours; types are not.
|
|
38
|
+
|
|
39
|
+
**`state.json`** — named fields the questions will point at:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"message": "I was charged twice for order A-104. Please refund the duplicate.",
|
|
44
|
+
"policy": "Duplicate charges are eligible for an immediate refund."
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**`questions.json`** — one judgment per id. `instructions` should backtick those fields (`` `message` ``):
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"refund_requested": {
|
|
53
|
+
"type": "noul",
|
|
54
|
+
"instructions": "Does `message` request a refund?"
|
|
55
|
+
},
|
|
56
|
+
"intent": {
|
|
57
|
+
"type": "choice",
|
|
58
|
+
"instructions": "What does `message` ask for?",
|
|
59
|
+
"criteria": {
|
|
60
|
+
"refund": "The customer wants money returned",
|
|
61
|
+
"information": "Explanation only",
|
|
62
|
+
"other": "Something else"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Full copies, including a **code-change** example with `files[].hunk`:
|
|
69
|
+
|
|
70
|
+
| Sample | Files |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| Support ticket | [`examples/ticket/state.json`](examples/ticket/state.json), [`questions.json`](examples/ticket/questions.json) |
|
|
73
|
+
| Skill / code slice | [`examples/code-change/state.json`](examples/code-change/state.json), [`questions.json`](examples/code-change/questions.json) |
|
|
74
|
+
| How to run them | [`examples/README.md`](examples/README.md) |
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
WORKDIR="${TMPDIR:-/tmp}/codex/typesafeai-cli"
|
|
78
|
+
mkdir -p "$WORKDIR"
|
|
79
|
+
cp examples/ticket/*.json "$WORKDIR/"
|
|
80
|
+
typesafe ask --state-file "$WORKDIR/state.json" --questions-file "$WORKDIR/questions.json"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
One-liners skip files: `typesafe noul "Does this request a refund?" --state "I was charged twice."`
|
|
84
|
+
|
|
85
|
+
If `data.model` looks like `jev-1.13.0`, the request reached TypeSafe. `auth status` does not.
|
|
86
|
+
|
|
87
|
+
## What the agent is supposed to do
|
|
88
|
+
|
|
89
|
+
1. `typesafe skills install` (once) so **typesafe-cli** and the official TypeSafe skill are on disk.
|
|
90
|
+
2. `typesafe auth status` — read `has_key` only. Agents must not print or open `TYPESAFE_*` or key files.
|
|
91
|
+
3. Write questions first. Each instruction backticks the state paths it needs. That list is what to collect.
|
|
92
|
+
4. Fill only those paths. If a path is code, put the hunk body in, not a filename.
|
|
93
|
+
5. Write JSON under `${TMPDIR:-/tmp}/codex/<project>/`, never in the git tree.
|
|
94
|
+
6. `typesafe ask`. Apply thresholds in the agent (a noul near `0.5` is unsure). Jev does not pick the next tool.
|
|
95
|
+
|
|
96
|
+
`typesafe agent schema` is the machine-readable command list. `--agent` makes `--help` JSON.
|
|
97
|
+
|
|
98
|
+
## Install
|
|
99
|
+
|
|
100
|
+
Python 3.10+ and a key from the [TypeSafe console](https://console.typesafe.ai/settings/keys).
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
export TYPESAFE_API_KEY=apikey_…
|
|
104
|
+
|
|
105
|
+
pip install typesafeai-cli
|
|
106
|
+
# or: pipx install typesafeai-cli
|
|
107
|
+
# or clone, then: uv sync && uv run typesafe --help
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`install.sh` on the repo and on each release can also install the GitHub wheel. Optional: `TYPESAFE_BASE_URL`, `TYPESAFE_DEFAULT_MODEL`. `--key` / `--creds` are for scripts, not for agents scraping secrets.
|
|
111
|
+
|
|
112
|
+
## Commands
|
|
113
|
+
|
|
114
|
+
| | |
|
|
115
|
+
| --- | --- |
|
|
116
|
+
| `typesafe ask` | State file + questions file |
|
|
117
|
+
| `typesafe noul` / `choice` / `score` | One question |
|
|
118
|
+
| `typesafe find` | Search a local file by plain-language query |
|
|
119
|
+
| `typesafe rank` | Rerank a JSON shortlist |
|
|
120
|
+
| `typesafe extract` | Pick a verbatim span (email / phone / money / `--candidates`) |
|
|
121
|
+
| `typesafe verify` | Check a claim against a source (missing quote → fabricated) |
|
|
122
|
+
| `typesafe screen` | Jailbreak / injection / sensitive-data / harm gate |
|
|
123
|
+
| `typesafe suggest-skill` | At most one skill name, or none |
|
|
124
|
+
| `typesafe decide` | Map nouls/choices to no / uncertain / yes (no HTTP) |
|
|
125
|
+
| `typesafe models` | Aliases (`jev-latest`, …) |
|
|
126
|
+
| `typesafe smoke` | Live docs quickstart |
|
|
127
|
+
| `typesafe auth status` | `has_key`; never prints the key |
|
|
128
|
+
| `typesafe agent schema` | JSON command tree |
|
|
129
|
+
| `typesafe skills install` | Official TypeSafe skill + **typesafe-cli** |
|
|
130
|
+
|
|
131
|
+
Exit `0` answered, `1` request failed (including missing key on `ask`), `2` bad flags or questions (no HTTP).
|
|
132
|
+
|
|
133
|
+
## Releases
|
|
134
|
+
|
|
135
|
+
A merge to `main` that passes CI ships automatically: patch bump, tag `vX.Y.Z`, GitHub release, PyPI (`release.yml`, environment `pypi`). Start the merge commit with `[skip release]` to skip. For a minor or major, run **Prepare Release** and pick the bump.
|
|
136
|
+
|
|
137
|
+
Match `version` in `pyproject.toml` to `__version__` in `src/typesafe_cli/__init__.py` if you tag by hand.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# TypeSafe agent CLI
|
|
2
|
+
|
|
3
|
+
`typesafe` is an **agent CLI** for [TypeSafe](https://typesafe.ai) **Jev**.
|
|
4
|
+
|
|
5
|
+
It is meant to be invoked by coding agents (Grok, Codex, Claude Code, Cursor, and anything else that can run a shell command). You can run it yourself while you debug; the usual caller is an agent.
|
|
6
|
+
|
|
7
|
+
Jev does not chat. The agent gathers a small JSON document (`state`) and typed questions (`noul`, `choice`, `score`). This CLI sends that to `POST /v1/systemone` and prints probabilities on stdout. Jev never sees the repo unless the agent copies the relevant slices into `state`.
|
|
8
|
+
|
|
9
|
+
You do not hand-write production payloads every day. Install the **typesafe-cli** skill, and the agent writes the JSON (in a temp directory, not in git). The files under [`examples/`](examples/) exist so you can see the shape, and so you can run a call without inventing one.
|
|
10
|
+
|
|
11
|
+
## JSON shape
|
|
12
|
+
|
|
13
|
+
Two files. Names are yours; types are not.
|
|
14
|
+
|
|
15
|
+
**`state.json`** — named fields the questions will point at:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"message": "I was charged twice for order A-104. Please refund the duplicate.",
|
|
20
|
+
"policy": "Duplicate charges are eligible for an immediate refund."
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**`questions.json`** — one judgment per id. `instructions` should backtick those fields (`` `message` ``):
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"refund_requested": {
|
|
29
|
+
"type": "noul",
|
|
30
|
+
"instructions": "Does `message` request a refund?"
|
|
31
|
+
},
|
|
32
|
+
"intent": {
|
|
33
|
+
"type": "choice",
|
|
34
|
+
"instructions": "What does `message` ask for?",
|
|
35
|
+
"criteria": {
|
|
36
|
+
"refund": "The customer wants money returned",
|
|
37
|
+
"information": "Explanation only",
|
|
38
|
+
"other": "Something else"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Full copies, including a **code-change** example with `files[].hunk`:
|
|
45
|
+
|
|
46
|
+
| Sample | Files |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| Support ticket | [`examples/ticket/state.json`](examples/ticket/state.json), [`questions.json`](examples/ticket/questions.json) |
|
|
49
|
+
| Skill / code slice | [`examples/code-change/state.json`](examples/code-change/state.json), [`questions.json`](examples/code-change/questions.json) |
|
|
50
|
+
| How to run them | [`examples/README.md`](examples/README.md) |
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
WORKDIR="${TMPDIR:-/tmp}/codex/typesafeai-cli"
|
|
54
|
+
mkdir -p "$WORKDIR"
|
|
55
|
+
cp examples/ticket/*.json "$WORKDIR/"
|
|
56
|
+
typesafe ask --state-file "$WORKDIR/state.json" --questions-file "$WORKDIR/questions.json"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
One-liners skip files: `typesafe noul "Does this request a refund?" --state "I was charged twice."`
|
|
60
|
+
|
|
61
|
+
If `data.model` looks like `jev-1.13.0`, the request reached TypeSafe. `auth status` does not.
|
|
62
|
+
|
|
63
|
+
## What the agent is supposed to do
|
|
64
|
+
|
|
65
|
+
1. `typesafe skills install` (once) so **typesafe-cli** and the official TypeSafe skill are on disk.
|
|
66
|
+
2. `typesafe auth status` — read `has_key` only. Agents must not print or open `TYPESAFE_*` or key files.
|
|
67
|
+
3. Write questions first. Each instruction backticks the state paths it needs. That list is what to collect.
|
|
68
|
+
4. Fill only those paths. If a path is code, put the hunk body in, not a filename.
|
|
69
|
+
5. Write JSON under `${TMPDIR:-/tmp}/codex/<project>/`, never in the git tree.
|
|
70
|
+
6. `typesafe ask`. Apply thresholds in the agent (a noul near `0.5` is unsure). Jev does not pick the next tool.
|
|
71
|
+
|
|
72
|
+
`typesafe agent schema` is the machine-readable command list. `--agent` makes `--help` JSON.
|
|
73
|
+
|
|
74
|
+
## Install
|
|
75
|
+
|
|
76
|
+
Python 3.10+ and a key from the [TypeSafe console](https://console.typesafe.ai/settings/keys).
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
export TYPESAFE_API_KEY=apikey_…
|
|
80
|
+
|
|
81
|
+
pip install typesafeai-cli
|
|
82
|
+
# or: pipx install typesafeai-cli
|
|
83
|
+
# or clone, then: uv sync && uv run typesafe --help
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`install.sh` on the repo and on each release can also install the GitHub wheel. Optional: `TYPESAFE_BASE_URL`, `TYPESAFE_DEFAULT_MODEL`. `--key` / `--creds` are for scripts, not for agents scraping secrets.
|
|
87
|
+
|
|
88
|
+
## Commands
|
|
89
|
+
|
|
90
|
+
| | |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| `typesafe ask` | State file + questions file |
|
|
93
|
+
| `typesafe noul` / `choice` / `score` | One question |
|
|
94
|
+
| `typesafe find` | Search a local file by plain-language query |
|
|
95
|
+
| `typesafe rank` | Rerank a JSON shortlist |
|
|
96
|
+
| `typesafe extract` | Pick a verbatim span (email / phone / money / `--candidates`) |
|
|
97
|
+
| `typesafe verify` | Check a claim against a source (missing quote → fabricated) |
|
|
98
|
+
| `typesafe screen` | Jailbreak / injection / sensitive-data / harm gate |
|
|
99
|
+
| `typesafe suggest-skill` | At most one skill name, or none |
|
|
100
|
+
| `typesafe decide` | Map nouls/choices to no / uncertain / yes (no HTTP) |
|
|
101
|
+
| `typesafe models` | Aliases (`jev-latest`, …) |
|
|
102
|
+
| `typesafe smoke` | Live docs quickstart |
|
|
103
|
+
| `typesafe auth status` | `has_key`; never prints the key |
|
|
104
|
+
| `typesafe agent schema` | JSON command tree |
|
|
105
|
+
| `typesafe skills install` | Official TypeSafe skill + **typesafe-cli** |
|
|
106
|
+
|
|
107
|
+
Exit `0` answered, `1` request failed (including missing key on `ask`), `2` bad flags or questions (no HTTP).
|
|
108
|
+
|
|
109
|
+
## Releases
|
|
110
|
+
|
|
111
|
+
A merge to `main` that passes CI ships automatically: patch bump, tag `vX.Y.Z`, GitHub release, PyPI (`release.yml`, environment `pypi`). Start the merge commit with `[skip release]` to skip. For a minor or major, run **Prepare Release** and pick the bump.
|
|
112
|
+
|
|
113
|
+
Match `version` in `pyproject.toml` to `__version__` in `src/typesafe_cli/__init__.py` if you tag by hand.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Samples for the TypeSafe **agent CLI**. How to run them, install, and what agents should do lives in the [project README](../README.md).
|
|
2
|
+
|
|
3
|
+
| Directory | What it is |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| [ticket/](ticket/) | Support message → refund / intent / frustration |
|
|
6
|
+
| [code-change/](code-change/) | A skill hunk → whether agents must attach real code |
|
|
7
|
+
|
|
8
|
+
Copy these into a temp dir before a live call (agents use `${TMPDIR:-/tmp}/codex/<project>/`, not the git tree):
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
WORKDIR="${TMPDIR:-/tmp}/codex/typesafeai-cli"
|
|
12
|
+
mkdir -p "$WORKDIR"
|
|
13
|
+
cp examples/ticket/*.json "$WORKDIR/"
|
|
14
|
+
typesafe ask --state-file "$WORKDIR/state.json" --questions-file "$WORKDIR/questions.json"
|
|
15
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"enough_code_in_state": {
|
|
3
|
+
"type": "noul",
|
|
4
|
+
"instructions": "Does `files[0].hunk` require the agent to put the actual code slice into state when a question path is code, rather than a path or 'see the PR'?"
|
|
5
|
+
},
|
|
6
|
+
"what_to_do": {
|
|
7
|
+
"type": "choice",
|
|
8
|
+
"instructions": "Given `task` and `files[0].hunk`, what should we do with this skill?",
|
|
9
|
+
"criteria": {
|
|
10
|
+
"keep": "Keep questions-first collection; do not add a job catalog",
|
|
11
|
+
"thin": "Cut the skill down to command examples only",
|
|
12
|
+
"expand": "Add per-job recipes (diff, CI, routing, …)",
|
|
13
|
+
"abstain": "Not enough in state to decide"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"clarity": {
|
|
17
|
+
"type": "score",
|
|
18
|
+
"instructions": "How clearly does `files[0].hunk` tell an agent to attach real code when the judgment is about a change?",
|
|
19
|
+
"criteria": [
|
|
20
|
+
"Silent; agents would send only a path",
|
|
21
|
+
"Mentions code but easy to skip the hunk",
|
|
22
|
+
"Clear: a code path must contain the slice"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"task": "An agent is about to call Jev on a pull request. Decide whether the typesafe-cli skill tells that agent to attach real code, or only a file path.",
|
|
3
|
+
"files": [
|
|
4
|
+
{
|
|
5
|
+
"path": "src/typesafe_cli/data/typesafe-cli/SKILL.md",
|
|
6
|
+
"line_range": "50-74",
|
|
7
|
+
"hunk": "### 2. Name the decision, then write the questions\n\nDo not start by dumping context. TypeSafe's contract is the questions: they name the fields Jev is allowed to look at.\n\nThen write `$WORKDIR/questions.json`. Each question's `instructions` must point at named paths with backticks (`task`, `files[0].hunk`, `tools`). Those paths **are** the collection list.\n\n### 3. Fill only those fields\n\nIf a path is code (`files[0].hunk`), the value must be the slice (path + line range + body), not a filename and not \"see the PR.\" Prefer under ~8k tokens of code. Do not send the tree.\n"
|
|
8
|
+
}
|
|
9
|
+
]
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"refund_requested": {
|
|
3
|
+
"type": "noul",
|
|
4
|
+
"instructions": "Does `message` request a refund?"
|
|
5
|
+
},
|
|
6
|
+
"intent": {
|
|
7
|
+
"type": "choice",
|
|
8
|
+
"instructions": "What does `message` ask for?",
|
|
9
|
+
"criteria": {
|
|
10
|
+
"refund": "The customer wants money returned",
|
|
11
|
+
"information": "The customer wants an explanation only",
|
|
12
|
+
"other": "Something else"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"frustration": {
|
|
16
|
+
"type": "score",
|
|
17
|
+
"instructions": "How frustrated does the customer sound in `message`?",
|
|
18
|
+
"criteria": [
|
|
19
|
+
"Calm and factual",
|
|
20
|
+
"Annoyed but civil",
|
|
21
|
+
"Very angry"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Optional installer for the typesafe CLI. Prefer pipx if you have it:
|
|
3
|
+
# pipx install typesafeai-cli
|
|
4
|
+
#
|
|
5
|
+
# This script installs the wheel from the GitHub release (Pup-style
|
|
6
|
+
# "download the artifact") or from PyPI.
|
|
7
|
+
#
|
|
8
|
+
# ./install.sh
|
|
9
|
+
# TYPESAFE_CLI_VERSION=v0.2.0 ./install.sh
|
|
10
|
+
# TYPESAFE_CLI_FROM=pypi ./install.sh
|
|
11
|
+
#
|
|
12
|
+
# Env:
|
|
13
|
+
# TYPESAFE_CLI_VERSION tag like v0.2.0, or "latest" (default)
|
|
14
|
+
# TYPESAFE_CLI_FROM github (default) or pypi
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
REPO="${TYPESAFE_CLI_REPO:-maddygoround/typesafeai-cli}"
|
|
18
|
+
PKG="${TYPESAFE_CLI_PKG:-typesafeai-cli}"
|
|
19
|
+
BIN="${TYPESAFE_CLI_BIN:-typesafe}"
|
|
20
|
+
VERSION="${TYPESAFE_CLI_VERSION:-latest}"
|
|
21
|
+
FROM="${TYPESAFE_CLI_FROM:-github}"
|
|
22
|
+
API="https://api.github.com/repos/${REPO}"
|
|
23
|
+
|
|
24
|
+
say() { printf '%s\n' "$*" >&2; }
|
|
25
|
+
die() { say "install.sh: $*"; exit 1; }
|
|
26
|
+
|
|
27
|
+
need_python() {
|
|
28
|
+
if ! command -v python3 >/dev/null 2>&1; then
|
|
29
|
+
die "python3 is required (3.10+)"
|
|
30
|
+
fi
|
|
31
|
+
python3 - <<'PY'
|
|
32
|
+
import sys
|
|
33
|
+
if sys.version_info < (3, 10):
|
|
34
|
+
raise SystemExit(f"python 3.10+ required, found {sys.version.split()[0]}")
|
|
35
|
+
PY
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
resolve_tag() {
|
|
39
|
+
if [ "$VERSION" != "latest" ]; then
|
|
40
|
+
case "$VERSION" in
|
|
41
|
+
v*) printf '%s\n' "$VERSION" ;;
|
|
42
|
+
*) printf 'v%s\n' "$VERSION" ;;
|
|
43
|
+
esac
|
|
44
|
+
return
|
|
45
|
+
fi
|
|
46
|
+
python3 - <<PY
|
|
47
|
+
import json, urllib.request
|
|
48
|
+
url = "${API}/releases/latest"
|
|
49
|
+
req = urllib.request.Request(url, headers={"Accept": "application/vnd.github+json", "User-Agent": "typesafe-install"})
|
|
50
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
51
|
+
data = json.load(resp)
|
|
52
|
+
tag = data.get("tag_name") or ""
|
|
53
|
+
if not tag:
|
|
54
|
+
raise SystemExit("could not resolve latest GitHub release")
|
|
55
|
+
print(tag)
|
|
56
|
+
PY
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
wheel_url_for_tag() {
|
|
60
|
+
local tag="$1"
|
|
61
|
+
python3 - <<PY
|
|
62
|
+
import json, urllib.request
|
|
63
|
+
url = "${API}/releases/tags/${tag}"
|
|
64
|
+
req = urllib.request.Request(url, headers={"Accept": "application/vnd.github+json", "User-Agent": "typesafe-install"})
|
|
65
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
66
|
+
data = json.load(resp)
|
|
67
|
+
for asset in data.get("assets") or []:
|
|
68
|
+
name = asset.get("name") or ""
|
|
69
|
+
if name.endswith(".whl"):
|
|
70
|
+
print(asset["browser_download_url"])
|
|
71
|
+
break
|
|
72
|
+
else:
|
|
73
|
+
raise SystemExit("no wheel on GitHub release ${tag}")
|
|
74
|
+
PY
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
have() { command -v "$1" >/dev/null 2>&1; }
|
|
78
|
+
|
|
79
|
+
install_spec() {
|
|
80
|
+
local spec="$1"
|
|
81
|
+
if have pipx; then
|
|
82
|
+
pipx install --force "$spec"
|
|
83
|
+
elif have uv; then
|
|
84
|
+
uv tool install --force "$spec"
|
|
85
|
+
else
|
|
86
|
+
say "pipx/uv not found; using python3 -m pip --user"
|
|
87
|
+
python3 -m pip install --user --upgrade "$spec"
|
|
88
|
+
fi
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
main() {
|
|
92
|
+
need_python
|
|
93
|
+
if [ "$FROM" = "pypi" ]; then
|
|
94
|
+
local spec
|
|
95
|
+
if [ "$VERSION" = "latest" ]; then
|
|
96
|
+
spec="$PKG"
|
|
97
|
+
else
|
|
98
|
+
spec="${PKG}==${VERSION#v}"
|
|
99
|
+
fi
|
|
100
|
+
say "installing ${spec} from PyPI"
|
|
101
|
+
install_spec "$spec"
|
|
102
|
+
else
|
|
103
|
+
local tag url tmp
|
|
104
|
+
tag="$(resolve_tag)"
|
|
105
|
+
say "using GitHub release ${tag}"
|
|
106
|
+
url="$(wheel_url_for_tag "$tag")"
|
|
107
|
+
say "wheel ${url}"
|
|
108
|
+
tmp="$(mktemp -d)"
|
|
109
|
+
trap 'rm -rf "$tmp"' EXIT
|
|
110
|
+
python3 - <<PY
|
|
111
|
+
import urllib.request
|
|
112
|
+
urllib.request.urlretrieve("${url}", "${tmp}/pkg.whl")
|
|
113
|
+
PY
|
|
114
|
+
install_spec "${tmp}/pkg.whl"
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
if have "$BIN"; then
|
|
118
|
+
say "ok: $(command -v "$BIN")"
|
|
119
|
+
else
|
|
120
|
+
say "installed the package, but '${BIN}' is not on PATH."
|
|
121
|
+
say "add ~/.local/bin to PATH, then run: ${BIN} --help"
|
|
122
|
+
fi
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
main "$@"
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "typesafeai-cli"
|
|
3
|
+
version = "0.3.1"
|
|
4
|
+
description = "Agent CLI for TypeSafe System One (Jev)"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
requires-python = ">=3.10"
|
|
8
|
+
authors = [{ name = "safeaiforeveryone" }]
|
|
9
|
+
keywords = ["typesafe", "jev", "cli"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Environment :: Console",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.10",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Topic :: Utilities",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"typesafe-sdk>=0.6.0",
|
|
21
|
+
"typer>=0.12",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://github.com/maddygoround/typesafeai-cli"
|
|
26
|
+
Repository = "https://github.com/maddygoround/typesafeai-cli"
|
|
27
|
+
Issues = "https://github.com/maddygoround/typesafeai-cli/issues"
|
|
28
|
+
Releases = "https://github.com/maddygoround/typesafeai-cli/releases"
|
|
29
|
+
|
|
30
|
+
[project.scripts]
|
|
31
|
+
typesafe = "typesafe_cli.cli:app"
|
|
32
|
+
|
|
33
|
+
[build-system]
|
|
34
|
+
requires = ["hatchling"]
|
|
35
|
+
build-backend = "hatchling.build"
|
|
36
|
+
|
|
37
|
+
[tool.hatch.build.targets.wheel]
|
|
38
|
+
packages = ["src/typesafe_cli"]
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.sdist]
|
|
41
|
+
include = [
|
|
42
|
+
"/src",
|
|
43
|
+
"/examples",
|
|
44
|
+
"/install.sh",
|
|
45
|
+
"/README.md",
|
|
46
|
+
"/LICENSE",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[dependency-groups]
|
|
50
|
+
dev = ["pytest>=8"]
|
|
51
|
+
|
|
52
|
+
[tool.pytest.ini_options]
|
|
53
|
+
pythonpath = ["src"]
|
|
54
|
+
testpaths = ["tests"]
|
|
55
|
+
addopts = "-q"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.1"
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from typesafe_cli.commands.agent import schema as agent_schema
|
|
6
|
+
from typesafe_cli.commands.ask import ask
|
|
7
|
+
from typesafe_cli.commands.auth import status as auth_status
|
|
8
|
+
from typesafe_cli.commands.decide import decide
|
|
9
|
+
from typesafe_cli.commands.extract import extract
|
|
10
|
+
from typesafe_cli.commands.find import find
|
|
11
|
+
from typesafe_cli.commands.models import models
|
|
12
|
+
from typesafe_cli.commands.oneshot import choice, noul, score
|
|
13
|
+
from typesafe_cli.commands.rank import rank
|
|
14
|
+
from typesafe_cli.commands.screen import screen
|
|
15
|
+
from typesafe_cli.commands.skills import install as skills_install
|
|
16
|
+
from typesafe_cli.commands.skills import list_skills
|
|
17
|
+
from typesafe_cli.commands.smoke import smoke
|
|
18
|
+
from typesafe_cli.commands.suggest_skill import suggest_skill
|
|
19
|
+
from typesafe_cli.commands.verify import verify
|
|
20
|
+
from typesafe_cli.help import AgentCommand, AgentGroup
|
|
21
|
+
|
|
22
|
+
app = typer.Typer(
|
|
23
|
+
name="typesafe",
|
|
24
|
+
cls=AgentGroup,
|
|
25
|
+
no_args_is_help=True,
|
|
26
|
+
add_completion=False,
|
|
27
|
+
pretty_exceptions_enable=False,
|
|
28
|
+
help="Agent CLI for TypeSafe System One (Jev). Typed judgments, not chat. Agents must not read TYPESAFE_* env vars or key files; use typesafe auth status.",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _on_agent(args: bool = False) -> bool:
|
|
33
|
+
if args:
|
|
34
|
+
from typesafe_cli.detect import set_force_agent
|
|
35
|
+
|
|
36
|
+
set_force_agent(True)
|
|
37
|
+
return args
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _on_no_agent(args: bool = False) -> bool:
|
|
41
|
+
if args:
|
|
42
|
+
from typesafe_cli.detect import set_force_agent
|
|
43
|
+
|
|
44
|
+
set_force_agent(False)
|
|
45
|
+
return args
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@app.callback()
|
|
49
|
+
def _global_options(
|
|
50
|
+
agent: bool = typer.Option(
|
|
51
|
+
False,
|
|
52
|
+
"--agent",
|
|
53
|
+
help="Force agent mode (JSON help/schema)",
|
|
54
|
+
is_eager=True,
|
|
55
|
+
callback=_on_agent,
|
|
56
|
+
),
|
|
57
|
+
no_agent: bool = typer.Option(
|
|
58
|
+
False,
|
|
59
|
+
"--no-agent",
|
|
60
|
+
help="Disable agent mode",
|
|
61
|
+
is_eager=True,
|
|
62
|
+
callback=_on_no_agent,
|
|
63
|
+
),
|
|
64
|
+
) -> None:
|
|
65
|
+
del agent, no_agent
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
auth_app = typer.Typer(cls=AgentGroup, no_args_is_help=True, help="Authentication helpers")
|
|
69
|
+
auth_app.command("status", cls=AgentCommand)(auth_status)
|
|
70
|
+
app.add_typer(auth_app, name="auth")
|
|
71
|
+
|
|
72
|
+
agent_app = typer.Typer(cls=AgentGroup, no_args_is_help=True, help="Agent discovery")
|
|
73
|
+
agent_app.command("schema", cls=AgentCommand)(agent_schema)
|
|
74
|
+
app.add_typer(agent_app, name="agent")
|
|
75
|
+
|
|
76
|
+
skills_app = typer.Typer(cls=AgentGroup, no_args_is_help=True, help="Install the official TypeSafe skill")
|
|
77
|
+
skills_app.command("install", cls=AgentCommand)(skills_install)
|
|
78
|
+
skills_app.command("list", cls=AgentCommand)(list_skills)
|
|
79
|
+
app.add_typer(skills_app, name="skills")
|
|
80
|
+
|
|
81
|
+
app.command("ask", cls=AgentCommand)(ask)
|
|
82
|
+
app.command("noul", cls=AgentCommand)(noul)
|
|
83
|
+
app.command("choice", cls=AgentCommand)(choice)
|
|
84
|
+
app.command("score", cls=AgentCommand)(score)
|
|
85
|
+
app.command("find", cls=AgentCommand)(find)
|
|
86
|
+
app.command("rank", cls=AgentCommand)(rank)
|
|
87
|
+
app.command("extract", cls=AgentCommand)(extract)
|
|
88
|
+
app.command("verify", cls=AgentCommand)(verify)
|
|
89
|
+
app.command("screen", cls=AgentCommand)(screen)
|
|
90
|
+
app.command("suggest-skill", cls=AgentCommand)(suggest_skill)
|
|
91
|
+
app.command("decide", cls=AgentCommand)(decide)
|
|
92
|
+
app.command("models", cls=AgentCommand)(models)
|
|
93
|
+
app.command("smoke", cls=AgentCommand)(smoke)
|