craftkit 0.3.0__tar.gz → 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.
- {craftkit-0.3.0/craftkit.egg-info → craftkit-0.3.1}/PKG-INFO +20 -6
- {craftkit-0.3.0 → craftkit-0.3.1}/README.md +19 -5
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/__init__.py +1 -1
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/agent.py +73 -13
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/cli.py +30 -3
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/home.py +14 -3
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/tables.py +20 -2
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/ui.py +12 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/workspace.py +3 -2
- {craftkit-0.3.0 → craftkit-0.3.1/craftkit.egg-info}/PKG-INFO +20 -6
- {craftkit-0.3.0 → craftkit-0.3.1}/pyproject.toml +1 -1
- {craftkit-0.3.0 → craftkit-0.3.1}/LICENSE-APACHE +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/LICENSE-MIT +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/SKILL.md +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/__main__.py +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/banner.py +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/brief.py +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/browser.py +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/checks.py +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/png.py +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/proc.py +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craft_kit/study.py +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craftkit.egg-info/SOURCES.txt +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craftkit.egg-info/dependency_links.txt +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craftkit.egg-info/entry_points.txt +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craftkit.egg-info/requires.txt +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/craftkit.egg-info/top_level.txt +0 -0
- {craftkit-0.3.0 → craftkit-0.3.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: craftkit
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Study → build → check → refine any software, from the terminal, with your coding agent.
|
|
5
5
|
License-Expression: MIT OR Apache-2.0
|
|
6
6
|
Keywords: cli,coding-agent,claude-code,codex,gemini,rebuild,skill
|
|
@@ -23,7 +23,7 @@ Dynamic: license-file
|
|
|
23
23
|
> **In English:** `craft` rebuilds any software (website, CLI, app, game, library) with the coding
|
|
24
24
|
> agent you already use (Claude Code, Codex, Gemini CLI): it studies the original, briefs the agent,
|
|
25
25
|
> checks the result against the original and sends it back until it holds. Install with
|
|
26
|
-
> `npm install -g craftkit` or `pipx install craftkit`, then type `craft`.
|
|
26
|
+
> `npm install -g craftkit-cli` or `pipx install craftkit`, then type `craft`.
|
|
27
27
|
|
|
28
28
|
La méthode de Craft Anything, réduite à l'essentiel : **étudier → construire → vérifier → affiner**,
|
|
29
29
|
pour recréer ou construire n'importe quel logiciel (site web, outil en ligne de commande, application,
|
|
@@ -66,16 +66,16 @@ construction bleu, affinage violet, vérification ambre, prêt vert.
|
|
|
66
66
|
Gratuit, au choix :
|
|
67
67
|
|
|
68
68
|
```sh
|
|
69
|
-
npm install -g craftkit
|
|
70
|
-
pipx install craftkit
|
|
69
|
+
npm install -g craftkit-cli # avec Node ; il faut aussi Python 3.9+ sur la machine
|
|
70
|
+
pipx install craftkit # ou : uv tool install craftkit
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
Pour l'essayer sans rien installer : `npx craftkit` ou `uvx craftkit`.
|
|
73
|
+
Pour l'essayer sans rien installer : `npx craftkit-cli` ou `uvx craftkit`.
|
|
74
74
|
Ensuite, le skill pour Claude Code (tous les projets) : `craft skill --install ~/.claude/skills`.
|
|
75
75
|
|
|
76
76
|
Les deux paquets contiennent exactement le même programme Python (aucune dépendance) ; celui de npm
|
|
77
77
|
le lance avec le Python de la machine (`CRAFT_PYTHON=/chemin/vers/python3` pour en choisir un).
|
|
78
|
-
Mise à jour : `npm update -g craftkit`, `pipx upgrade craftkit` ou `uv tool upgrade craftkit`.
|
|
78
|
+
Mise à jour : `npm update -g craftkit-cli`, `pipx upgrade craftkit` ou `uv tool upgrade craftkit`.
|
|
79
79
|
|
|
80
80
|
Depuis les sources : `pipx install .` dans ce dossier, ou `python3 -m craft_kit …` sans installer.
|
|
81
81
|
|
|
@@ -122,6 +122,7 @@ craft open # ouvrir le résultat
|
|
|
122
122
|
| `craft status` | où en est le projet |
|
|
123
123
|
| `craft answer` | répondre aux questions de l'agent |
|
|
124
124
|
| `craft brief` | afficher la tâche, pour la coller dans n'importe quel agent |
|
|
125
|
+
| `craft agents` | les agents de code installés, et comment en installer un |
|
|
125
126
|
| `craft skill [--install DOSSIER]` | afficher ou installer le SKILL.md |
|
|
126
127
|
|
|
127
128
|
Options de `new` : `--kind website|cli|app|game|tool`, `--stack rust|python|react|html|…`,
|
|
@@ -149,6 +150,19 @@ propres outils.
|
|
|
149
150
|
|
|
150
151
|
## Agents
|
|
151
152
|
|
|
153
|
+
`craft` n'écrit pas le code lui-même : il faut un agent de code sur la machine. Sans agent, `craft`
|
|
154
|
+
le dit dès l'écran d'accueil, à `craft new` et au début de `craft run` (avant l'étude), avec les
|
|
155
|
+
commandes exactes ; `craft agents` montre ce qui est trouvé :
|
|
156
|
+
|
|
157
|
+
| Agent | Installer | Puis, une fois |
|
|
158
|
+
|-------|-----------|----------------|
|
|
159
|
+
| Claude Code | `npm install -g @anthropic-ai/claude-code` (ou `curl -fsSL https://claude.ai/install.sh \| bash`) | lancer `claude` et se connecter |
|
|
160
|
+
| Codex | `npm install -g @openai/codex` | lancer `codex` et se connecter |
|
|
161
|
+
| Gemini CLI | `npm install -g @google/gemini-cli` (ou `brew install gemini-cli`) | lancer `gemini` et se connecter (offre gratuite avec un compte Google) |
|
|
162
|
+
|
|
163
|
+
Sans agent du tout : `craft brief` affiche la tâche, à coller dans n'importe quel assistant de code
|
|
164
|
+
(Cursor, Copilot…) ouvert dans le dossier du projet, puis `craft check`.
|
|
165
|
+
|
|
152
166
|
Ordre par défaut : `claude`, `codex`, `gemini` (le premier installé). Choisir : `--agent codex` ou
|
|
153
167
|
`CRAFT_AGENT=codex`. La tâche est envoyée sur l'entrée standard (jamais en argument : elle peut être
|
|
154
168
|
longue). Ajouter ou modifier un agent dans `~/.config/craft/agents.json` :
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> **In English:** `craft` rebuilds any software (website, CLI, app, game, library) with the coding
|
|
4
4
|
> agent you already use (Claude Code, Codex, Gemini CLI): it studies the original, briefs the agent,
|
|
5
5
|
> checks the result against the original and sends it back until it holds. Install with
|
|
6
|
-
> `npm install -g craftkit` or `pipx install craftkit`, then type `craft`.
|
|
6
|
+
> `npm install -g craftkit-cli` or `pipx install craftkit`, then type `craft`.
|
|
7
7
|
|
|
8
8
|
La méthode de Craft Anything, réduite à l'essentiel : **étudier → construire → vérifier → affiner**,
|
|
9
9
|
pour recréer ou construire n'importe quel logiciel (site web, outil en ligne de commande, application,
|
|
@@ -46,16 +46,16 @@ construction bleu, affinage violet, vérification ambre, prêt vert.
|
|
|
46
46
|
Gratuit, au choix :
|
|
47
47
|
|
|
48
48
|
```sh
|
|
49
|
-
npm install -g craftkit
|
|
50
|
-
pipx install craftkit
|
|
49
|
+
npm install -g craftkit-cli # avec Node ; il faut aussi Python 3.9+ sur la machine
|
|
50
|
+
pipx install craftkit # ou : uv tool install craftkit
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
Pour l'essayer sans rien installer : `npx craftkit` ou `uvx craftkit`.
|
|
53
|
+
Pour l'essayer sans rien installer : `npx craftkit-cli` ou `uvx craftkit`.
|
|
54
54
|
Ensuite, le skill pour Claude Code (tous les projets) : `craft skill --install ~/.claude/skills`.
|
|
55
55
|
|
|
56
56
|
Les deux paquets contiennent exactement le même programme Python (aucune dépendance) ; celui de npm
|
|
57
57
|
le lance avec le Python de la machine (`CRAFT_PYTHON=/chemin/vers/python3` pour en choisir un).
|
|
58
|
-
Mise à jour : `npm update -g craftkit`, `pipx upgrade craftkit` ou `uv tool upgrade craftkit`.
|
|
58
|
+
Mise à jour : `npm update -g craftkit-cli`, `pipx upgrade craftkit` ou `uv tool upgrade craftkit`.
|
|
59
59
|
|
|
60
60
|
Depuis les sources : `pipx install .` dans ce dossier, ou `python3 -m craft_kit …` sans installer.
|
|
61
61
|
|
|
@@ -102,6 +102,7 @@ craft open # ouvrir le résultat
|
|
|
102
102
|
| `craft status` | où en est le projet |
|
|
103
103
|
| `craft answer` | répondre aux questions de l'agent |
|
|
104
104
|
| `craft brief` | afficher la tâche, pour la coller dans n'importe quel agent |
|
|
105
|
+
| `craft agents` | les agents de code installés, et comment en installer un |
|
|
105
106
|
| `craft skill [--install DOSSIER]` | afficher ou installer le SKILL.md |
|
|
106
107
|
|
|
107
108
|
Options de `new` : `--kind website|cli|app|game|tool`, `--stack rust|python|react|html|…`,
|
|
@@ -129,6 +130,19 @@ propres outils.
|
|
|
129
130
|
|
|
130
131
|
## Agents
|
|
131
132
|
|
|
133
|
+
`craft` n'écrit pas le code lui-même : il faut un agent de code sur la machine. Sans agent, `craft`
|
|
134
|
+
le dit dès l'écran d'accueil, à `craft new` et au début de `craft run` (avant l'étude), avec les
|
|
135
|
+
commandes exactes ; `craft agents` montre ce qui est trouvé :
|
|
136
|
+
|
|
137
|
+
| Agent | Installer | Puis, une fois |
|
|
138
|
+
|-------|-----------|----------------|
|
|
139
|
+
| Claude Code | `npm install -g @anthropic-ai/claude-code` (ou `curl -fsSL https://claude.ai/install.sh \| bash`) | lancer `claude` et se connecter |
|
|
140
|
+
| Codex | `npm install -g @openai/codex` | lancer `codex` et se connecter |
|
|
141
|
+
| Gemini CLI | `npm install -g @google/gemini-cli` (ou `brew install gemini-cli`) | lancer `gemini` et se connecter (offre gratuite avec un compte Google) |
|
|
142
|
+
|
|
143
|
+
Sans agent du tout : `craft brief` affiche la tâche, à coller dans n'importe quel assistant de code
|
|
144
|
+
(Cursor, Copilot…) ouvert dans le dossier du projet, puis `craft check`.
|
|
145
|
+
|
|
132
146
|
Ordre par défaut : `claude`, `codex`, `gemini` (le premier installé). Choisir : `--agent codex` ou
|
|
133
147
|
`CRAFT_AGENT=codex`. La tâche est envoyée sur l'entrée standard (jamais en argument : elle peut être
|
|
134
148
|
longue). Ajouter ou modifier un agent dans `~/.config/craft/agents.json` :
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
|
|
6
6
|
import json
|
|
7
7
|
import os
|
|
8
|
+
import sys
|
|
8
9
|
from typing import Optional
|
|
9
10
|
|
|
10
11
|
from . import proc, tables
|
|
@@ -15,19 +16,74 @@ TURN_TIMEOUT = float(os.environ.get("CRAFT_TURN_TIMEOUT", 3 * 3600))
|
|
|
15
16
|
IDLE_TIMEOUT = float(os.environ.get("CRAFT_IDLE_TIMEOUT", 20 * 60))
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
def
|
|
19
|
+
def installed(table: Optional[dict] = None) -> list[str]:
|
|
20
|
+
"""The agents whose program is on this computer, in order of preference."""
|
|
21
|
+
table = table or tables.agents()
|
|
22
|
+
return [n for n in tables.AGENT_ORDER if n in table and proc.which(table[n]["argv"][0])]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def guide(ui: UI, names: Optional[list] = None) -> None:
|
|
26
|
+
"""How to install and sign in to a coding agent, with the exact commands."""
|
|
27
|
+
table = tables.agents()
|
|
28
|
+
names = [n for n in (names or tables.AGENT_ORDER) if n in table]
|
|
29
|
+
platform = sys.platform if sys.platform in ("darwin", "win32") else "linux"
|
|
30
|
+
ui.say("")
|
|
31
|
+
ui.say(f" craft doesn't write code itself: a coding agent does. {'Install it' if len(names) == 1 else 'Install one of these'}, then sign in once:")
|
|
32
|
+
ui.say("")
|
|
33
|
+
width = max([len(table[n].get("title", n)) for n in names] + [8]) + 3
|
|
34
|
+
for n in names:
|
|
35
|
+
spec = table[n]
|
|
36
|
+
title = spec.get("title", n)
|
|
37
|
+
install = spec.get("install") or f"install `{spec['argv'][0]}` and put it on your PATH"
|
|
38
|
+
ui.say(f" {ui.bold(f'{title:<{width}}')}{install}")
|
|
39
|
+
alt = (spec.get("alt") or {}).get(platform)
|
|
40
|
+
if alt:
|
|
41
|
+
ui.say(f" {' ' * width}{ui.dim('or:')} {alt}")
|
|
42
|
+
if spec.get("login"):
|
|
43
|
+
ui.say(f" {' ' * width}{ui.dim('then ' + spec['login'])}")
|
|
44
|
+
if not proc.which("npm"):
|
|
45
|
+
ui.say("")
|
|
46
|
+
ui.say(f" {ui.yellow('npm')} isn't on this computer: it comes with Node.js ({tables.NODE_URL}).")
|
|
47
|
+
ui.say("")
|
|
48
|
+
ui.say(f" {ui.dim('Then:')} craft run {ui.dim('· see what is found:')} craft agents")
|
|
49
|
+
ui.say(f" {ui.dim('No agent here? craft brief prints the task: paste it into any coding assistant')}")
|
|
50
|
+
ui.say(f" {ui.dim('(Cursor, Copilot, …) opened in the project folder, then run')} craft check{ui.dim('.')}")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def no_agent() -> CraftError:
|
|
54
|
+
return CraftError("No coding agent found on this computer (Claude Code, Codex or Gemini CLI).", guide=guide)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def resolve(remembered: Optional[str], asked: Optional[str]) -> tuple[str, dict, Optional[str]]:
|
|
58
|
+
"""The agent for a project: (name, spec, the remembered agent that's gone, if any). Raises a
|
|
59
|
+
CraftError with install steps when none can run."""
|
|
60
|
+
if not asked and not os.environ.get("CRAFT_AGENT") and remembered and remembered not in installed():
|
|
61
|
+
name, spec = pick(None)
|
|
62
|
+
return name, spec, remembered
|
|
63
|
+
name, spec = pick(asked or remembered)
|
|
64
|
+
return name, spec, None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def pick(name: Optional[str], strict: bool = True) -> tuple[str, dict]:
|
|
68
|
+
"""The agent to use. An agent asked for by name must be installed; one only remembered from an
|
|
69
|
+
earlier run gives way to another installed agent."""
|
|
19
70
|
table = tables.agents()
|
|
20
|
-
|
|
21
|
-
if
|
|
22
|
-
if
|
|
71
|
+
explicit = name or os.environ.get("CRAFT_AGENT")
|
|
72
|
+
if explicit:
|
|
73
|
+
if explicit == "none":
|
|
23
74
|
raise CraftError("No agent: the brief is in BRIEF.md.", "Paste BRIEF.md into any coding agent opened in this folder, then run `craft check`.")
|
|
24
|
-
if
|
|
25
|
-
raise CraftError(f"Unknown agent “{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
75
|
+
if explicit not in table:
|
|
76
|
+
raise CraftError(f"Unknown agent “{explicit}”.", f"Known: {', '.join(table)}. Add one in {tables.config_dir() / 'agents.json'}.")
|
|
77
|
+
if proc.which(table[explicit]["argv"][0]) or not strict:
|
|
78
|
+
return explicit, table[explicit]
|
|
79
|
+
title = table[explicit].get("title", explicit)
|
|
80
|
+
others = [n for n in installed(table) if n != explicit]
|
|
81
|
+
hint = f" ({', '.join(others)} is installed: craft run --agent {others[0]})" if others else ""
|
|
82
|
+
raise CraftError(f"{title} isn't installed, or isn't on your PATH{hint}.", guide=lambda ui: guide(ui, [explicit]))
|
|
83
|
+
found = installed(table)
|
|
84
|
+
if found:
|
|
85
|
+
return found[0], table[found[0]]
|
|
86
|
+
raise no_agent()
|
|
31
87
|
|
|
32
88
|
|
|
33
89
|
TOOL_KINDS = {
|
|
@@ -122,7 +178,10 @@ def _describe_tool(name: str, args: dict, root: str = "") -> str:
|
|
|
122
178
|
|
|
123
179
|
|
|
124
180
|
def turn(p: Project, message: str, ui: UI, agent: Optional[str], label: str) -> str:
|
|
125
|
-
name, spec =
|
|
181
|
+
name, spec, gone = resolve(p.state.get("agent"), agent)
|
|
182
|
+
if gone:
|
|
183
|
+
ui.note(f"{gone} isn't on this computer any more; using {name}.")
|
|
184
|
+
p.state["session"] = None
|
|
126
185
|
p.state["agent"] = name
|
|
127
186
|
p.state["turns"] = p.state.get("turns", 0) + 1
|
|
128
187
|
rd = p.root / "checks" / f"turn-{p.state['turns']}"
|
|
@@ -159,7 +218,8 @@ def turn(p: Project, message: str, ui: UI, agent: Optional[str], label: str) ->
|
|
|
159
218
|
p.save()
|
|
160
219
|
if not r.ok or (reader is not None and reader.is_error):
|
|
161
220
|
why = r.error or (f"exit {r.code}" if r.code else "it reported an error")
|
|
162
|
-
|
|
221
|
+
login = f"If it needs signing in: {spec['login']}.\n" if spec.get("login") else ""
|
|
222
|
+
raise CraftError(f"{name} stopped: {why}.\n{r.tail(12)}", f"{login}Full output: {rd / 'agent.log'}. Fix the cause, then `craft run` carries on.")
|
|
163
223
|
reply = reader.reply if reader is not None else r.tail(40)
|
|
164
224
|
write_atomic(rd / "reply.md", reply)
|
|
165
225
|
return reply
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
craft answer answer the builder's questions
|
|
9
9
|
craft brief print the builder's brief (to paste into any agent)
|
|
10
10
|
craft open open the result
|
|
11
|
+
craft agents which coding agents are installed, and how to get one
|
|
11
12
|
craft skill [--install DIR] print or install the SKILL.md this tool follows
|
|
12
13
|
"""
|
|
13
14
|
|
|
@@ -114,6 +115,7 @@ def finish(p: Project, ui: UI, res: Optional[dict], reply: str) -> None:
|
|
|
114
115
|
|
|
115
116
|
def loop(p: Project, ui: UI, message: Optional[str], agent_name: Optional[str]) -> int:
|
|
116
117
|
s = p.state
|
|
118
|
+
agent.resolve(s.get("agent"), agent_name) # no agent: say how to get one now, not after the study
|
|
117
119
|
if message: # a new request resets the refinement budget; retries never do
|
|
118
120
|
s["rounds_used"] = 0
|
|
119
121
|
s["unchanged"] = 0
|
|
@@ -194,6 +196,32 @@ def cmd_new(a, ui: UI) -> int:
|
|
|
194
196
|
ui.header(p.state["name"], f"{kind} · {stack} · {p.mode()}")
|
|
195
197
|
ui.step("done", "new", str(folder))
|
|
196
198
|
ui.say(f" {ui.dim('add pictures to')} {folder / 'reference'}{ui.dim(', then:')} cd {folder.name} && craft run")
|
|
199
|
+
if not agent.installed():
|
|
200
|
+
ui.say("")
|
|
201
|
+
ui.warn("No coding agent found yet: `craft run` needs one.")
|
|
202
|
+
agent.guide(ui)
|
|
203
|
+
return 0
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def cmd_agents(a, ui: UI) -> int:
|
|
207
|
+
table = tables.agents()
|
|
208
|
+
found = agent.installed(table)
|
|
209
|
+
for n in tables.AGENT_ORDER:
|
|
210
|
+
if n not in table:
|
|
211
|
+
continue
|
|
212
|
+
spec = table[n]
|
|
213
|
+
title = spec.get("title", n)
|
|
214
|
+
where = agent.proc.which(spec["argv"][0])
|
|
215
|
+
if where:
|
|
216
|
+
ui.step("done", n, f"{title} · {where}" + (" ← used by default" if found and n == found[0] else ""), stage="ready")
|
|
217
|
+
else:
|
|
218
|
+
ui.step("todo", n, f"{title} · not installed" + (f": {spec.get('install', 'install ' + spec['argv'][0])}" if found else ""))
|
|
219
|
+
if not found:
|
|
220
|
+
ui.say("")
|
|
221
|
+
ui.warn("No coding agent found.")
|
|
222
|
+
agent.guide(ui)
|
|
223
|
+
else:
|
|
224
|
+
ui.say(f" {ui.dim('pick another with')} craft run --agent NAME {ui.dim('or')} CRAFT_AGENT=NAME")
|
|
197
225
|
return 0
|
|
198
226
|
|
|
199
227
|
|
|
@@ -336,6 +364,7 @@ def parser() -> argparse.ArgumentParser:
|
|
|
336
364
|
("open", cmd_open, "open the result")):
|
|
337
365
|
sub.add_parser(name, help=hlp).set_defaults(fn=fn)
|
|
338
366
|
sub.add_parser("home", help="the home screen: past creations and a new project").set_defaults(fn=cmd_home)
|
|
367
|
+
sub.add_parser("agents", help="which coding agents are installed, and how to get one").set_defaults(fn=cmd_agents)
|
|
339
368
|
s = sub.add_parser("skill", help="print or install SKILL.md")
|
|
340
369
|
s.add_argument("--install", metavar="DIR", help="skills folder, e.g. ~/.claude/skills")
|
|
341
370
|
s.set_defaults(fn=cmd_skill)
|
|
@@ -370,9 +399,7 @@ def main(argv: Optional[list] = None) -> int:
|
|
|
370
399
|
try:
|
|
371
400
|
return a.fn(a, ui)
|
|
372
401
|
except CraftError as e:
|
|
373
|
-
ui.
|
|
374
|
-
if e.fix:
|
|
375
|
-
ui.say(f" {ui.dim(e.fix)}")
|
|
402
|
+
ui.report(e)
|
|
376
403
|
return 2
|
|
377
404
|
except KeyboardInterrupt:
|
|
378
405
|
ui.say("")
|
|
@@ -145,6 +145,12 @@ class Home:
|
|
|
145
145
|
self.line()
|
|
146
146
|
if describe:
|
|
147
147
|
self.describe()
|
|
148
|
+
from . import agent
|
|
149
|
+
|
|
150
|
+
if not agent.installed(): # say it before anyone starts a project
|
|
151
|
+
ui = self.ui
|
|
152
|
+
self.line(f" {ui.yellow('!')} No coding agent found: install Claude Code, Codex or Gemini CLI {ui.dim('(details: craft agents)')}")
|
|
153
|
+
self.line()
|
|
148
154
|
|
|
149
155
|
def describe(self) -> None:
|
|
150
156
|
"""What the tool does, in a few lines, on the home screen."""
|
|
@@ -203,9 +209,7 @@ class Home:
|
|
|
203
209
|
try:
|
|
204
210
|
pause = action() is not False
|
|
205
211
|
except CraftError as e:
|
|
206
|
-
self.ui.
|
|
207
|
-
if e.fix:
|
|
208
|
-
self.ui.say(f" {self.ui.dim(e.fix)}")
|
|
212
|
+
self.ui.report(e)
|
|
209
213
|
except KeyboardInterrupt:
|
|
210
214
|
self.ui.say(f"\n {self.ui.dim('stopped')}")
|
|
211
215
|
if pause:
|
|
@@ -357,6 +361,13 @@ class Home:
|
|
|
357
361
|
p = Project.create(folder, target, request, kind, stack, deep, allow_run)
|
|
358
362
|
ui.step("done", "new", f"{folder} · {kind} · {stack} · {p.mode()}")
|
|
359
363
|
result["path"] = str(folder)
|
|
364
|
+
from . import agent
|
|
365
|
+
|
|
366
|
+
if not agent.installed():
|
|
367
|
+
ui.say("")
|
|
368
|
+
ui.warn("No coding agent found yet: building needs one.")
|
|
369
|
+
agent.guide(ui)
|
|
370
|
+
return True
|
|
360
371
|
if ui.choose("Start building now?", ["Yes, start", "Later"]).startswith("Yes"):
|
|
361
372
|
ui.say("")
|
|
362
373
|
from . import cli
|
|
@@ -93,10 +93,28 @@ AGENTS: dict[str, dict] = {
|
|
|
93
93
|
"stream": "claude-json",
|
|
94
94
|
"resume": ["--resume", "{session}"],
|
|
95
95
|
"lost": "No conversation found",
|
|
96
|
+
"title": "Claude Code",
|
|
97
|
+
"install": "npm install -g @anthropic-ai/claude-code",
|
|
98
|
+
"alt": {"darwin": "curl -fsSL https://claude.ai/install.sh | bash", "linux": "curl -fsSL https://claude.ai/install.sh | bash", "win32": "irm https://claude.ai/install.ps1 | iex (PowerShell)"},
|
|
99
|
+
"login": "run `claude` once and sign in (Claude account or API key)",
|
|
100
|
+
},
|
|
101
|
+
"codex": {
|
|
102
|
+
"argv": ["codex", "exec", "--full-auto", "-"],
|
|
103
|
+
"stream": "text",
|
|
104
|
+
"title": "Codex",
|
|
105
|
+
"install": "npm install -g @openai/codex",
|
|
106
|
+
"login": "run `codex` once and sign in (ChatGPT account or API key)",
|
|
107
|
+
},
|
|
108
|
+
"gemini": {
|
|
109
|
+
"argv": ["gemini", "--yolo"],
|
|
110
|
+
"stream": "text",
|
|
111
|
+
"title": "Gemini CLI",
|
|
112
|
+
"install": "npm install -g @google/gemini-cli",
|
|
113
|
+
"alt": {"darwin": "brew install gemini-cli"},
|
|
114
|
+
"login": "run `gemini` once and sign in (a Google account has a free tier)",
|
|
96
115
|
},
|
|
97
|
-
"codex": {"argv": ["codex", "exec", "--full-auto", "-"], "stream": "text"},
|
|
98
|
-
"gemini": {"argv": ["gemini", "--yolo"], "stream": "text"},
|
|
99
116
|
}
|
|
117
|
+
NODE_URL = "https://nodejs.org" # npm, used by the install commands above, comes with Node.js
|
|
100
118
|
AGENT_ORDER = ["claude", "codex", "gemini"]
|
|
101
119
|
|
|
102
120
|
|
|
@@ -152,6 +152,18 @@ class UI:
|
|
|
152
152
|
def error(self, text: str) -> None:
|
|
153
153
|
self.say(f" {self.red('✗')} {text}")
|
|
154
154
|
|
|
155
|
+
def warn(self, text: str) -> None:
|
|
156
|
+
self.say(f" {self.yellow('!')} {text}")
|
|
157
|
+
|
|
158
|
+
def report(self, e) -> None:
|
|
159
|
+
"""A CraftError: what went wrong, then what to do (its guide, or its one-line fix)."""
|
|
160
|
+
self.error(e.message)
|
|
161
|
+
if getattr(e, "guide", None):
|
|
162
|
+
e.guide(self)
|
|
163
|
+
elif getattr(e, "fix", ""):
|
|
164
|
+
for line in e.fix.splitlines():
|
|
165
|
+
self.say(f" {self.dim(line)}")
|
|
166
|
+
|
|
155
167
|
def live(self, label: str, stage: Optional[str] = None) -> "Live":
|
|
156
168
|
return Live(self, label, stage)
|
|
157
169
|
|
|
@@ -35,10 +35,11 @@ IGNORED = {"node_modules", "target", "dist", "out", "build", ".git", "__pycache_
|
|
|
35
35
|
class CraftError(Exception):
|
|
36
36
|
"""A failure with a plain-English remediation."""
|
|
37
37
|
|
|
38
|
-
def __init__(self, message: str, fix: str = ""):
|
|
38
|
+
def __init__(self, message: str, fix: str = "", guide=None):
|
|
39
39
|
super().__init__(message)
|
|
40
40
|
self.message = message
|
|
41
41
|
self.fix = fix
|
|
42
|
+
self.guide = guide # optional callable(ui): a longer, formatted remediation
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
def write_atomic(path: Path, data: str) -> None:
|
|
@@ -203,7 +204,7 @@ class Project:
|
|
|
203
204
|
raise CraftError(f"{root / STATE} can't be read.", "Fix or delete the file; it is JSON.")
|
|
204
205
|
v = state.get("version")
|
|
205
206
|
if not isinstance(v, int) or v > VERSION:
|
|
206
|
-
raise CraftError(f"{STATE} says version {v}; this craft reads version {VERSION}.", "Update craft (`pipx upgrade craftkit`, `uv tool upgrade craftkit` or `npm update -g craftkit`).")
|
|
207
|
+
raise CraftError(f"{STATE} says version {v}; this craft reads version {VERSION}.", "Update craft (`pipx upgrade craftkit`, `uv tool upgrade craftkit` or `npm update -g craftkit-cli`).")
|
|
207
208
|
# migrations go here as versions are added
|
|
208
209
|
state.setdefault("steps", {s: "todo" for s in STEPS})
|
|
209
210
|
remember(root)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: craftkit
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Study → build → check → refine any software, from the terminal, with your coding agent.
|
|
5
5
|
License-Expression: MIT OR Apache-2.0
|
|
6
6
|
Keywords: cli,coding-agent,claude-code,codex,gemini,rebuild,skill
|
|
@@ -23,7 +23,7 @@ Dynamic: license-file
|
|
|
23
23
|
> **In English:** `craft` rebuilds any software (website, CLI, app, game, library) with the coding
|
|
24
24
|
> agent you already use (Claude Code, Codex, Gemini CLI): it studies the original, briefs the agent,
|
|
25
25
|
> checks the result against the original and sends it back until it holds. Install with
|
|
26
|
-
> `npm install -g craftkit` or `pipx install craftkit`, then type `craft`.
|
|
26
|
+
> `npm install -g craftkit-cli` or `pipx install craftkit`, then type `craft`.
|
|
27
27
|
|
|
28
28
|
La méthode de Craft Anything, réduite à l'essentiel : **étudier → construire → vérifier → affiner**,
|
|
29
29
|
pour recréer ou construire n'importe quel logiciel (site web, outil en ligne de commande, application,
|
|
@@ -66,16 +66,16 @@ construction bleu, affinage violet, vérification ambre, prêt vert.
|
|
|
66
66
|
Gratuit, au choix :
|
|
67
67
|
|
|
68
68
|
```sh
|
|
69
|
-
npm install -g craftkit
|
|
70
|
-
pipx install craftkit
|
|
69
|
+
npm install -g craftkit-cli # avec Node ; il faut aussi Python 3.9+ sur la machine
|
|
70
|
+
pipx install craftkit # ou : uv tool install craftkit
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
Pour l'essayer sans rien installer : `npx craftkit` ou `uvx craftkit`.
|
|
73
|
+
Pour l'essayer sans rien installer : `npx craftkit-cli` ou `uvx craftkit`.
|
|
74
74
|
Ensuite, le skill pour Claude Code (tous les projets) : `craft skill --install ~/.claude/skills`.
|
|
75
75
|
|
|
76
76
|
Les deux paquets contiennent exactement le même programme Python (aucune dépendance) ; celui de npm
|
|
77
77
|
le lance avec le Python de la machine (`CRAFT_PYTHON=/chemin/vers/python3` pour en choisir un).
|
|
78
|
-
Mise à jour : `npm update -g craftkit`, `pipx upgrade craftkit` ou `uv tool upgrade craftkit`.
|
|
78
|
+
Mise à jour : `npm update -g craftkit-cli`, `pipx upgrade craftkit` ou `uv tool upgrade craftkit`.
|
|
79
79
|
|
|
80
80
|
Depuis les sources : `pipx install .` dans ce dossier, ou `python3 -m craft_kit …` sans installer.
|
|
81
81
|
|
|
@@ -122,6 +122,7 @@ craft open # ouvrir le résultat
|
|
|
122
122
|
| `craft status` | où en est le projet |
|
|
123
123
|
| `craft answer` | répondre aux questions de l'agent |
|
|
124
124
|
| `craft brief` | afficher la tâche, pour la coller dans n'importe quel agent |
|
|
125
|
+
| `craft agents` | les agents de code installés, et comment en installer un |
|
|
125
126
|
| `craft skill [--install DOSSIER]` | afficher ou installer le SKILL.md |
|
|
126
127
|
|
|
127
128
|
Options de `new` : `--kind website|cli|app|game|tool`, `--stack rust|python|react|html|…`,
|
|
@@ -149,6 +150,19 @@ propres outils.
|
|
|
149
150
|
|
|
150
151
|
## Agents
|
|
151
152
|
|
|
153
|
+
`craft` n'écrit pas le code lui-même : il faut un agent de code sur la machine. Sans agent, `craft`
|
|
154
|
+
le dit dès l'écran d'accueil, à `craft new` et au début de `craft run` (avant l'étude), avec les
|
|
155
|
+
commandes exactes ; `craft agents` montre ce qui est trouvé :
|
|
156
|
+
|
|
157
|
+
| Agent | Installer | Puis, une fois |
|
|
158
|
+
|-------|-----------|----------------|
|
|
159
|
+
| Claude Code | `npm install -g @anthropic-ai/claude-code` (ou `curl -fsSL https://claude.ai/install.sh \| bash`) | lancer `claude` et se connecter |
|
|
160
|
+
| Codex | `npm install -g @openai/codex` | lancer `codex` et se connecter |
|
|
161
|
+
| Gemini CLI | `npm install -g @google/gemini-cli` (ou `brew install gemini-cli`) | lancer `gemini` et se connecter (offre gratuite avec un compte Google) |
|
|
162
|
+
|
|
163
|
+
Sans agent du tout : `craft brief` affiche la tâche, à coller dans n'importe quel assistant de code
|
|
164
|
+
(Cursor, Copilot…) ouvert dans le dossier du projet, puis `craft check`.
|
|
165
|
+
|
|
152
166
|
Ordre par défaut : `claude`, `codex`, `gemini` (le premier installé). Choisir : `--agent codex` ou
|
|
153
167
|
`CRAFT_AGENT=codex`. La tâche est envoyée sur l'entrée standard (jamais en argument : elle peut être
|
|
154
168
|
longue). Ajouter ou modifier un agent dans `~/.config/craft/agents.json` :
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "craftkit"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.1"
|
|
8
8
|
description = "Study → build → check → refine any software, from the terminal, with your coding agent."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
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
|