unfold-deploy 0.1.0 → 0.2.0
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.
- package/CHANGELOG.md +9 -1
- package/README.md +44 -7
- package/demos/claude-success.json +72 -0
- package/demos/codex-checks-failing.json +62 -0
- package/demos/gcloud-deploy-failure.json +616 -0
- package/demos/gcloud-success.json +608 -0
- package/dist/cli.js +15 -7
- package/dist/commands/demo.js +22 -8
- package/dist/commands/observe.js +17 -2
- package/dist/commands/replay.js +16 -1
- package/dist/commands/run.js +1 -1
- package/dist/core/errors.js +3 -0
- package/dist/core/flow.js +12 -1
- package/dist/core/session.js +36 -5
- package/dist/core/terminal.js +4 -2
- package/dist/providers/agents/claude.js +205 -0
- package/dist/providers/agents/codex.js +152 -0
- package/dist/providers/agents/shared.js +119 -0
- package/dist/providers/gcloud/index.js +39 -0
- package/dist/providers/gcloud/parser.js +149 -0
- package/dist/providers/gcloud/stages.js +55 -0
- package/dist/providers/index.js +4 -1
- package/dist/providers/vercel/index.js +1 -0
- package/dist/providers/vercel/stages.js +3 -0
- package/dist/tui/render.js +14 -7
- package/dist/ui/app.js +6 -6
- package/package.json +12 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.2.0 (2026-11-05)
|
|
4
|
+
|
|
5
|
+
- `unfold gcloud`: Cloud Run deploys (`gcloud run deploy`) as Prepare → Build → Deploy → Live, with build and revision log links, troubleshooting links, and readable errors from gcloud's HTML error pages.
|
|
6
|
+
- `unfold claude "<task>"` and `unfold codex "<task>"`: run Claude Code or Codex non-interactively and show Start → Explore → Change → Verify → Done, with files changed, checks run, the final answer and cost or tokens. Verify is only confirmed by a passing check.
|
|
7
|
+
- Providers that emit JSON events are shown as readable lines instead of raw JSON; their saved runs replay from recorded events.
|
|
8
|
+
- New demos: `gcloud success`, `gcloud deploy-failure`, `claude success`, `codex checks-failing` (`unfold demo <provider> <name>`).
|
|
9
|
+
- Summary headlines and labels now come from the provider ("Deployed", "Done", …).
|
|
10
|
+
|
|
11
|
+
## 0.1.0 (2026-11-05)
|
|
4
12
|
|
|
5
13
|
First release.
|
|
6
14
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
**Watch what happens after you hit Enter.**
|
|
4
4
|
|
|
5
|
-
Unfold wraps a CLI command and shows what it's doing as a flow, right in your terminal. The command's own output and prompts work exactly as before, and a small panel pinned to the bottom of the terminal tracks each stage as it happens.
|
|
5
|
+
Unfold wraps a CLI command and shows what it's doing as a flow, right in your terminal. The command's own output and prompts work exactly as before, and a small panel pinned to the bottom of the terminal tracks each stage as it happens.
|
|
6
|
+
|
|
7
|
+
| Command | Wraps | Flow |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| `unfold vercel` | `vercel deploy` | Prepare → Upload → Build → Preview |
|
|
10
|
+
| `unfold gcloud` | `gcloud run deploy` (Cloud Run) | Prepare → Build → Deploy → Live |
|
|
11
|
+
| `unfold claude "<task>"` | Claude Code, non-interactive | Start → Explore → Change → Verify → Done |
|
|
12
|
+
| `unfold codex "<task>"` | Codex CLI, non-interactive | Start → Explore → Change → Verify → Done |
|
|
6
13
|
|
|
7
14
|
```
|
|
8
15
|
Vercel CLI 65.2.0
|
|
@@ -35,15 +42,19 @@ npm install -g unfold-deploy
|
|
|
35
42
|
|
|
36
43
|
The package is `unfold-deploy`; the command is `unfold`. To try it without installing, prefix commands with `npx unfold-deploy` (for example `npx unfold-deploy demo success`).
|
|
37
44
|
|
|
38
|
-
## Try it without
|
|
45
|
+
## Try it without an account
|
|
39
46
|
|
|
40
47
|
The demos play recorded terminal output through the same pipeline a real run uses:
|
|
41
48
|
|
|
42
49
|
```sh
|
|
43
|
-
unfold demo success
|
|
44
|
-
unfold demo build-failure
|
|
45
|
-
unfold demo interrupted
|
|
46
|
-
unfold
|
|
50
|
+
unfold demo success # Vercel: a preview deploy that succeeds
|
|
51
|
+
unfold demo build-failure # Vercel: the build fails on a TypeScript error
|
|
52
|
+
unfold demo interrupted # Vercel: Ctrl+C while building
|
|
53
|
+
unfold demo gcloud success # Cloud Run: a source deploy that goes live
|
|
54
|
+
unfold demo gcloud deploy-failure # Cloud Run: the container never listens on $PORT
|
|
55
|
+
unfold demo claude success # Claude Code fixes a failing test and confirms it
|
|
56
|
+
unfold demo codex checks-failing # Codex finishes, but the tests still fail
|
|
57
|
+
unfold show # explore the run you just watched
|
|
47
58
|
```
|
|
48
59
|
|
|
49
60
|
Add `--speed 2` to play faster. Press Ctrl+C during any demo to see the interrupted state.
|
|
@@ -67,6 +78,31 @@ unfold vercel --yes # any vercel deploy flags pass straight through
|
|
|
67
78
|
|
|
68
79
|
Unfold options: `--fix claude|codex` (see below), `--no-panel` (no pinned panel, summary only), `--speed <n>` (demos and replays).
|
|
69
80
|
|
|
81
|
+
## Deploy to Cloud Run
|
|
82
|
+
|
|
83
|
+
You need the Google Cloud CLI, logged in (`gcloud auth login`) with a project set. From your service's folder:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
unfold gcloud --source . --region us-central1 # runs: gcloud run deploy --source . --region us-central1
|
|
87
|
+
unfold gcloud my-api --image us-docker.pkg.dev/… # prebuilt image: no Build stage
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Everything after `unfold gcloud` goes to `gcloud run deploy`, and its questions (service name, region, unauthenticated access) still appear in your terminal. On failure the summary shows the error, the Cloud Build or revision logs link, and the troubleshooting link gcloud printed. HTML error pages gcloud sometimes prints are reduced to their readable sentence.
|
|
91
|
+
|
|
92
|
+
## Watch a coding agent: Claude Code and Codex
|
|
93
|
+
|
|
94
|
+
Unfold runs the agent in its non-interactive mode, which reports every step as a structured event, and shows it as a flow: what it read (**Explore**), which files it edited (**Change**), whether checks such as `npm test` or `tsc` passed (**Verify**), and its final answer (**Done**). The summary lists the files changed, the answer, and the cost or token use.
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
unfold claude "fix the failing test" --allowedTools Read Edit "Bash(npm test)"
|
|
98
|
+
unfold claude "add input validation to the signup form" --permission-mode acceptEdits
|
|
99
|
+
unfold codex "fix the failing test" --sandbox workspace-write
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- Non-interactive agents can't stop to ask for permission. Give Claude Code the tools it needs with `--allowedTools` or `--permission-mode acceptEdits`; give Codex write access with `--sandbox workspace-write`. Denied tools are listed in the summary.
|
|
103
|
+
- **Verify is only confirmed when a check passes.** If the agent never runs one, or the last one failed, Verify stays `?` with the reason, even when the agent says it's done.
|
|
104
|
+
- Edits go straight to your working tree. Review them with `git diff`.
|
|
105
|
+
|
|
70
106
|
### Browser view (optional)
|
|
71
107
|
|
|
72
108
|
Nothing is served unless you ask for it. Add `--web` to also open the flow in a local browser page, for example `unfold vercel --web` or `unfold show --web`. The page is served on `127.0.0.1` only. With `--web` you can also use `--no-open`, `--once` (exit when the run ends) and `--port <n>` (default 4317).
|
|
@@ -99,7 +135,8 @@ Try it without an account: `unfold demo build-failure`.
|
|
|
99
135
|
|
|
100
136
|
## Troubleshooting
|
|
101
137
|
|
|
102
|
-
- **"Could not find vercel on your PATH"**: install
|
|
138
|
+
- **"Could not find vercel / gcloud / claude / codex on your PATH"**: install that CLI and log in to it first; Unfold prints the install command.
|
|
139
|
+
- **Agent stopped without changing anything**: it probably wasn't allowed to. Check "Permission denied" in the summary and allow the tool (see above).
|
|
103
140
|
- **Stuck at a Vercel question**: Unfold passes your keystrokes straight to the Vercel CLI, so answer it as usual. In scripts, pass `--yes` and `--scope <team>`.
|
|
104
141
|
- **"Unfold didn't recognize any of this output"**: your Vercel CLI may print a format Unfold doesn't know yet. The deploy itself is unaffected. Please open an issue and include your `vercel --version`.
|
|
105
142
|
- **No live panel**: the panel needs a terminal at least 50×12 and the `node-pty` package. On Linux without build tools, node-pty may not install; Unfold then runs the CLI through the system `script` command, prints only the summary, and keeps prompts working. `UNFOLD_TERMINAL=script` or `UNFOLD_TERMINAL=pipe` forces a fallback, and `--no-panel` turns the panel off.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"provider": "claude",
|
|
3
|
+
"description": "Claude Code fixes a failing test and confirms it with npm test.",
|
|
4
|
+
"command": [
|
|
5
|
+
"claude",
|
|
6
|
+
"-p",
|
|
7
|
+
"Fix the failing test",
|
|
8
|
+
"--permission-mode",
|
|
9
|
+
"acceptEdits",
|
|
10
|
+
"--output-format",
|
|
11
|
+
"stream-json",
|
|
12
|
+
"--verbose"
|
|
13
|
+
],
|
|
14
|
+
"cwd": "/home/dev/tiny-app",
|
|
15
|
+
"exitCode": 0,
|
|
16
|
+
"signal": null,
|
|
17
|
+
"interrupted": false,
|
|
18
|
+
"chunks": [
|
|
19
|
+
{
|
|
20
|
+
"t": 300,
|
|
21
|
+
"d": "{\"type\":\"system\",\"subtype\":\"init\",\"cwd\":\"/home/dev/tiny-app\",\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\",\"model\":\"claude-opus-5-5\",\"permissionMode\":\"acceptEdits\",\"claude_code_version\":\"2.1.292\",\"tools\":[\"Read\",\"Edit\",\"Bash\"]}\r\n"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"t": 1800,
|
|
25
|
+
"d": "{\"type\":\"assistant\",\"message\":{\"content\":[{\"type\":\"text\",\"text\":\"I'll look at the code and run the tests first.\"}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"t": 2700,
|
|
29
|
+
"d": "{\"type\":\"assistant\",\"message\":{\"content\":[{\"type\":\"tool_use\",\"id\":\"t1\",\"name\":\"Read\",\"input\":{\"file_path\":\"/home/dev/tiny-app/sum.js\"}}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"t": 3000,
|
|
33
|
+
"d": "{\"type\":\"user\",\"message\":{\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"t1\",\"content\":\"1\\texport function sum(a, b) {\\n2\\t return a - b;\\n3\\t}\\n\",\"is_error\":false}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"t": 4200,
|
|
37
|
+
"d": "{\"type\":\"assistant\",\"message\":{\"content\":[{\"type\":\"tool_use\",\"id\":\"t2\",\"name\":\"Bash\",\"input\":{\"command\":\"npm test\",\"description\":\"Run the tests\"}}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"t": 6000,
|
|
41
|
+
"d": "{\"type\":\"user\",\"message\":{\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"t2\",\"content\":\"Exit code 1\\nAssertionError [ERR_ASSERTION]: Expected values to be strictly equal:\\n\\n-1 !== 5\\n\",\"is_error\":true}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"t": 7400,
|
|
45
|
+
"d": "{\"type\":\"assistant\",\"message\":{\"content\":[{\"type\":\"text\",\"text\":\"`sum` subtracts instead of adding. Fixing it.\"}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"t": 8500,
|
|
49
|
+
"d": "{\"type\":\"assistant\",\"message\":{\"content\":[{\"type\":\"tool_use\",\"id\":\"t3\",\"name\":\"Edit\",\"input\":{\"file_path\":\"/home/dev/tiny-app/sum.js\",\"old_string\":\"return a - b;\",\"new_string\":\"return a + b;\"}}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"t": 8800,
|
|
53
|
+
"d": "{\"type\":\"user\",\"message\":{\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"t3\",\"content\":\"The file /home/dev/tiny-app/sum.js has been updated.\",\"is_error\":false}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"t": 9700,
|
|
57
|
+
"d": "{\"type\":\"assistant\",\"message\":{\"content\":[{\"type\":\"tool_use\",\"id\":\"t4\",\"name\":\"Bash\",\"input\":{\"command\":\"npm test\",\"description\":\"Run the tests again\"}}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"t": 11400,
|
|
61
|
+
"d": "{\"type\":\"user\",\"message\":{\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"t4\",\"content\":\"> tiny-app@1.0.0 test\\n> node test.js\\n\\nok\\n\",\"is_error\":false}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"t": 12600,
|
|
65
|
+
"d": "{\"type\":\"assistant\",\"message\":{\"content\":[{\"type\":\"text\",\"text\":\"Fixed `sum` in sum.js: it returned `a - b` instead of `a + b`. `npm test` now passes.\"}]},\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"t": 12800,
|
|
69
|
+
"d": "{\"type\":\"result\",\"subtype\":\"success\",\"is_error\":false,\"duration_ms\":13800,\"num_turns\":6,\"result\":\"Fixed `sum` in sum.js: it returned `a - b` instead of `a + b`. `npm test` now passes.\",\"total_cost_usd\":0.1876,\"permission_denials\":[],\"session_id\":\"7b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d\"}\r\n"
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"provider": "codex",
|
|
3
|
+
"description": "Codex edits a date helper, but the tests still fail when it stops.",
|
|
4
|
+
"command": [
|
|
5
|
+
"codex",
|
|
6
|
+
"exec",
|
|
7
|
+
"--json",
|
|
8
|
+
"Fix the time zone bug in startOfDay",
|
|
9
|
+
"--sandbox",
|
|
10
|
+
"workspace-write"
|
|
11
|
+
],
|
|
12
|
+
"cwd": "/home/dev/tiny-app",
|
|
13
|
+
"exitCode": 0,
|
|
14
|
+
"signal": null,
|
|
15
|
+
"interrupted": false,
|
|
16
|
+
"chunks": [
|
|
17
|
+
{
|
|
18
|
+
"t": 300,
|
|
19
|
+
"d": "{\"type\":\"thread.started\",\"thread_id\":\"01a1ae40-5b6c-7d8e-9f01-23456789abcd\"}\r\n"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"t": 400,
|
|
23
|
+
"d": "{\"type\":\"turn.started\"}\r\n"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"t": 2600,
|
|
27
|
+
"d": "{\"type\":\"item.completed\",\"item\":{\"id\":\"item_0\",\"type\":\"agent_message\",\"text\":\"I'll read the date helper and its tests, then fix the time zone bug.\"}}\r\n"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"t": 3500,
|
|
31
|
+
"d": "{\"type\":\"item.started\",\"item\":{\"id\":\"item_1\",\"type\":\"command_execution\",\"command\":\"/bin/zsh -lc \\\"cat src/dates.js test/dates.test.js\\\"\",\"aggregated_output\":\"\",\"exit_code\":null,\"status\":\"in_progress\"}}\r\n"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"t": 3800,
|
|
35
|
+
"d": "{\"type\":\"item.completed\",\"item\":{\"id\":\"item_1\",\"type\":\"command_execution\",\"command\":\"/bin/zsh -lc \\\"cat src/dates.js test/dates.test.js\\\"\",\"aggregated_output\":\"export function startOfDay(d) { … }\\n\",\"exit_code\":0,\"status\":\"completed\"}}\r\n"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"t": 6400,
|
|
39
|
+
"d": "{\"type\":\"item.started\",\"item\":{\"id\":\"item_2\",\"type\":\"file_change\",\"changes\":[{\"path\":\"/home/dev/tiny-app/src/dates.js\",\"kind\":\"update\"}],\"status\":\"in_progress\"}}\r\n"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"t": 6600,
|
|
43
|
+
"d": "{\"type\":\"item.completed\",\"item\":{\"id\":\"item_2\",\"type\":\"file_change\",\"changes\":[{\"path\":\"/home/dev/tiny-app/src/dates.js\",\"kind\":\"update\"}],\"status\":\"completed\"}}\r\n"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"t": 7400,
|
|
47
|
+
"d": "{\"type\":\"item.started\",\"item\":{\"id\":\"item_3\",\"type\":\"command_execution\",\"command\":\"/bin/zsh -lc \\\"npm test\\\"\",\"aggregated_output\":\"\",\"exit_code\":null,\"status\":\"in_progress\"}}\r\n"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"t": 9800,
|
|
51
|
+
"d": "{\"type\":\"item.completed\",\"item\":{\"id\":\"item_3\",\"type\":\"command_execution\",\"command\":\"/bin/zsh -lc \\\"npm test\\\"\",\"aggregated_output\":\"> tiny-app@1.0.0 test\\n> node --test\\n\\n✖ startOfDay keeps the local date (2.1ms)\\n AssertionError: Expected \\\"2026-11-05\\\" but got \\\"2026-11-04\\\"\\n\\nℹ tests 6 pass 5 fail 1\\n\",\"exit_code\":1,\"status\":\"failed\"}}\r\n"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"t": 12400,
|
|
55
|
+
"d": "{\"type\":\"item.completed\",\"item\":{\"id\":\"item_4\",\"type\":\"agent_message\",\"text\":\"I changed startOfDay to use local time, but one test still fails: it expects 2026-11-05 and gets 2026-11-04, so the test itself may assume UTC. Can you confirm which time zone the dates should use?\"}}\r\n"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"t": 12600,
|
|
59
|
+
"d": "{\"type\":\"turn.completed\",\"usage\":{\"input_tokens\":64210,\"cached_input_tokens\":51200,\"output_tokens\":812}}\r\n"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|