phonton-cli 0.17.1 → 0.19.1
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/README.md +126 -102
- package/npm/bin/phonton.js +2 -48
- package/npm/install.js +0 -15
- package/npm/test-wrapper.js +13 -108
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,120 +1,132 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="assets/readme/phonton-cli-logo.png" width="
|
|
2
|
+
<img src="assets/readme/phonton-cli-logo.png" width="128" alt="Phonton CLI logo">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
<h1 align="center">Phonton CLI
|
|
5
|
+
<h1 align="center">Phonton CLI — v0.19.0</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<strong>
|
|
9
|
-
|
|
8
|
+
<strong>Your keys. Your code. The autonomous coding agent that never phones home.</strong><br>
|
|
9
|
+
Phonton is a local-first agentic development environment (ADE) built around the loop: <code>goal ➔ plan ➔ edit ➔ verify ➔ review ➔ remember</code>.
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
|
-
<a href="https://github.com/phonton-dev/phonton-cli/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/phonton-dev/phonton-cli/actions/workflows/ci.yml/badge.svg"></a>
|
|
14
|
-
<a href="https://github.com/phonton-dev/phonton-cli/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/phonton-dev/phonton-cli?style=flat&label=stars"></a>
|
|
15
|
-
<img alt="release" src="https://img.shields.io/badge/release-v0.
|
|
13
|
+
<a href="https://github.com/phonton-dev/phonton-cli/actions/workflows/ci.yml"><img alt="CI Status" src="https://github.com/phonton-dev/phonton-cli/actions/workflows/ci.yml/badge.svg"></a>
|
|
14
|
+
<a href="https://github.com/phonton-dev/phonton-cli/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/phonton-dev/phonton-cli?style=flat&label=stars&color=ff69b4"></a>
|
|
15
|
+
<img alt="release" src="https://img.shields.io/badge/release-v0.19.0-6c63ff">
|
|
16
16
|
<img alt="license" src="https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue">
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
## 💡 What is Phonton?
|
|
22
|
+
|
|
23
|
+
Every AI coding assistant makes you trade privacy for autonomy. To get an agentic experience, you either hand your code to a SaaS vendor's proxy servers, or settle for inline autocompletion.
|
|
24
|
+
|
|
25
|
+
**Phonton is the first tool to deliver both: fully agentic development and absolute, uncompromising privacy.**
|
|
26
|
+
|
|
27
|
+
Phonton runs as a local-first, headless-ready terminal tool. Your code never leaves your machine. Your API keys go straight to Anthropic, OpenAI, Gemini, or Ollama. No intermediate proxy, no telemetry hooks, and no subscription required.
|
|
22
28
|
|
|
23
29
|
<p align="center">
|
|
24
|
-
<img src="assets/readme/phonton-cli-hero.png" alt="Phonton CLI hero with terminal UI preview">
|
|
30
|
+
<img src="assets/readme/phonton-cli-hero.png" alt="Phonton CLI hero with terminal UI preview" width="800">
|
|
25
31
|
</p>
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
---
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
## 🌟 Core Differentiators
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
npm install -g phonton-cli
|
|
37
|
+
### 1. Zero-Telemetry BYOK (Bring Your Own Key)
|
|
38
|
+
Phonton is proxy-free. Requests go directly to `api.anthropic.com`, `api.openai.com`, `generativelanguage.googleapis.com`, or your local `ollama` daemon. Phonton never intercepts your keys and never touches your code in transit. You can packet-capture the network to verify.
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
### 2. The Strict 4-Layer Verification Gate
|
|
41
|
+
Unlike other tools that silently write code and let LLM hallucinations ship, Phonton enforces a strict verification gate. Every diff must pass through **four layers** before it is marked as review-ready:
|
|
42
|
+
1. **Tree-Sitter Syntax check**
|
|
43
|
+
2. **Crate check (`cargo check`)**
|
|
44
|
+
3. **Workspace Check (Lints & Format)**
|
|
45
|
+
4. **Automated Test suite execution**
|
|
46
|
+
5. **Interactive Browser rendering check** (Playwright checks + Screenshots in `v0.19.0`)
|
|
38
47
|
|
|
39
|
-
|
|
48
|
+
On failure, verifier diagnostics are surgically fed back to the worker for recursive repair loops.
|
|
40
49
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
curl -fsSL https://raw.githubusercontent.com/phonton-dev/phonton-cli/main/scripts/install.sh | sh
|
|
44
|
-
```
|
|
50
|
+
### 3. Multi-Model Intelligence Routing
|
|
51
|
+
Phonton routes subtasks by complexity using tiered model mapping (`Local ➔ Cheap ➔ Standard ➔ Frontier`). It automatically escalates to a more powerful model only on verify failure. You pay pennies for boilerplate and invoke frontier intelligence only when a task demands it.
|
|
45
52
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/phonton-dev/phonton-cli/main/scripts/install.ps1)))
|
|
49
|
-
```
|
|
53
|
+
### 4. Semantic Memory Across Sessions
|
|
54
|
+
Phonton maintains a persistent SQLite store of architectural decisions, rejected approaches, and task history. The planner consults this memory on every goal decomposition, ensuring it never re-attempts approaches that failed before and builds upon approved design patterns.
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## ⚡ Quick Install
|
|
59
|
+
|
|
60
|
+
The easiest path to install is via npm. The wrapper automatically downloads the prebuilt binary for your platform.
|
|
55
61
|
|
|
56
|
-
Verify your installation:
|
|
57
62
|
```bash
|
|
63
|
+
# Install globally
|
|
64
|
+
npm install -g phonton-cli
|
|
65
|
+
|
|
66
|
+
# Verify your installation
|
|
58
67
|
phonton version
|
|
59
68
|
phonton doctor
|
|
60
69
|
```
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
### Alternative Installers
|
|
72
|
+
|
|
73
|
+
* **Shell Script (macOS/Linux)**:
|
|
74
|
+
```bash
|
|
75
|
+
curl -fsSL https://raw.githubusercontent.com/phonton-dev/phonton-cli/main/scripts/install.sh | sh
|
|
76
|
+
```
|
|
77
|
+
* **PowerShell (Windows)**:
|
|
78
|
+
```powershell
|
|
79
|
+
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/phonton-dev/phonton-cli/main/scripts/install.ps1)))
|
|
80
|
+
```
|
|
81
|
+
* **Cargo (From Source)**:
|
|
82
|
+
```bash
|
|
83
|
+
cargo install --git https://github.com/phonton-dev/phonton-cli --tag v0.19.0 phonton-cli --locked --force
|
|
84
|
+
```
|
|
65
85
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
```mermaid
|
|
69
|
-
flowchart LR
|
|
70
|
-
A["Goal"] --> B["Plan preview"]
|
|
71
|
-
B --> C["Repo-aware worker"]
|
|
72
|
-
C --> D["Verification gate"]
|
|
73
|
-
D --> E["Reviewable diff"]
|
|
74
|
-
E --> F["Memory and history"]
|
|
75
|
-
F --> B
|
|
76
|
-
```
|
|
86
|
+
---
|
|
77
87
|
|
|
78
|
-
|
|
88
|
+
## ⚖️ How We Compare
|
|
79
89
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
- **
|
|
90
|
+
| Feature | Phonton CLI | Claude Code | Cursor | Aider |
|
|
91
|
+
|---|---|---|---|---|
|
|
92
|
+
| **Privacy Model** | **100% Direct (No Proxy)** | Anthropic Proxy | Cursor Proxy | Direct (No Proxy) |
|
|
93
|
+
| **Telemetry** | **Zero** | Opt-out | Opt-out | Optional |
|
|
94
|
+
| **Multi-Model Support** | **All (BYOK & Local)** | Anthropic Only | Pre-selected | Many |
|
|
95
|
+
| **Subscription Fee** | **$0 (Open Source)** | Usage-based | $20/month | $0 (Open Source) |
|
|
96
|
+
| **Execution Loop** | **Full Plan/Edit/Verify** | Interactive Chat | Interactive Chat | Interactive Chat |
|
|
97
|
+
| **Verification Gates** | **Mandatory 4-Layer** | Manual/Run Command | Manual | Optional |
|
|
98
|
+
| **Memory Spine** | **Semantic SQLite** | None | Simple Context | None |
|
|
85
99
|
|
|
86
100
|
---
|
|
87
101
|
|
|
88
|
-
##
|
|
102
|
+
## 🔄 The Autonomous ADE Loop
|
|
89
103
|
|
|
90
|
-
|
|
104
|
+
```mermaid
|
|
105
|
+
flowchart TD
|
|
106
|
+
Goal["Goal (User Request)"] --> Plan["1. Goal Decomposition (Planner)"]
|
|
107
|
+
Plan --> Graph["2. PlanGraph & Conflict Groups Staged"]
|
|
108
|
+
Graph --> Dispatch["3. Concurrent / Serialized Worker Dispatch"]
|
|
109
|
+
Dispatch --> Edit["4. Bounded Code Modifications (Diff-Only)"]
|
|
110
|
+
Edit --> Verify{"5. Strict Verification Gate"}
|
|
111
|
+
Verify -- FAIL: Surgical Repair Prompt --> Edit
|
|
112
|
+
Verify -- PASS --> Review["6. Reviewable Handoff (HandoffPacket)"]
|
|
113
|
+
Review --> Remember["7. SQLite Memory & Session Snapshot Saved"]
|
|
114
|
+
```
|
|
91
115
|
|
|
92
|
-
|
|
116
|
+
---
|
|
93
117
|
|
|
94
|
-
|
|
95
|
-
|---|---|---|---|---|---|---|---|---:|
|
|
96
|
-
| **`02-bugfix`** | **Phonton v0.17.1** | **verified_success** | **38.6s** | **2,006** | **730** | **1,280** | **2,736** | **1** |
|
|
97
|
-
| | Claude Code | completed | 58.0s | 212 | 3,261 | 163,137 | 203,018 | 1 |
|
|
98
|
-
| | DeepSeek-TUI | completed | 88.2s | 28,490 | 1,210 | 22,400 | 52,100 | 1 |
|
|
99
|
-
| | Gemini CLI | completed | 199.8s | 95,008 | 1,948 | 113,770 | 214,287 | 1 |
|
|
100
|
-
| | Codex CLI | completed | 218.9s | 379,331 | 5,515 | 346,624 | 384,846 | 2 |
|
|
101
|
-
| **`03-refactor`** | **Phonton v0.17.1** | **verified_success** | **50.6s** | **5,164** | **5,034** | **768** | **10,198** | **2** |
|
|
102
|
-
| | Gemini CLI | completed | 118.4s | 76,079 | 5,092 | 453,239 | 536,583 | 2 |
|
|
103
|
-
| | DeepSeek-TUI | completed | 112.5s | 42,300 | 4,890 | 55,600 | 102,790 | 2 |
|
|
104
|
-
| | Claude Code | completed | 156.7s | 2,821 | 11,781 | 176,187 | 224,947 | 2 |
|
|
105
|
-
| | Codex CLI | completed | 229.0s | 451,983 | 8,479 | 412,416 | 460,462 | 2 |
|
|
118
|
+
## 🚀 New in v0.19.0: Swarm Planning & Pluggable Indices
|
|
106
119
|
|
|
107
|
-
|
|
108
|
-
* **
|
|
109
|
-
* **
|
|
110
|
-
* **
|
|
120
|
+
* **Conflict-Aware Swarm Scheduling (`PlanGraph`)**: Broad goals are decomposed into collaborative swarms. Overlapping touch scopes are isolated into Conflict Groups and serialized, while independent subtasks run concurrently to optimize execution time.
|
|
121
|
+
* **Pluggable Code Indexing**: Upgraded `phonton-index` with a pluggable `CodeRetriever` trait. Supports default high-performance `local-hnsw` search and external `qdrant` HTTP vector storage for larger enterprise repositories.
|
|
122
|
+
* **Dynamic MCP Capability Discovery**: Run `phonton mcp capabilities <server-id> [--yes]` to preview server info, exposed tools, and sandbox permission proposals safely before initiating any tool execution.
|
|
123
|
+
* **Robust Browser Verification**: Dynamically injected `NODE_PATH` resolution guarantees Playwright DOM and interaction tests run flawlessly on isolated temp directories and production workspaces alike.
|
|
111
124
|
|
|
112
125
|
---
|
|
113
126
|
|
|
114
|
-
## ⚙️
|
|
127
|
+
## ⚙️ Configuration
|
|
115
128
|
|
|
116
|
-
|
|
117
|
-
Phonton looks for credentials inside `~/.phonton/config.toml`. Create it with a minimal configuration:
|
|
129
|
+
Configure your direct providers and indexing backend in `~/.phonton/config.toml`:
|
|
118
130
|
|
|
119
131
|
```toml
|
|
120
132
|
[provider]
|
|
@@ -124,50 +136,62 @@ model = "deepseek-v4-flash"
|
|
|
124
136
|
[provider.keys]
|
|
125
137
|
deepseek = "sk-deepseek-api-key-here"
|
|
126
138
|
anthropic = "sk-ant-api-key-here"
|
|
139
|
+
openai = "sk-proj-openai-key-here"
|
|
140
|
+
|
|
141
|
+
[index]
|
|
142
|
+
backend = "local-hnsw"
|
|
127
143
|
```
|
|
128
144
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
|
|
145
|
+
To enable the external **Qdrant** backend:
|
|
146
|
+
|
|
147
|
+
```toml
|
|
148
|
+
[index]
|
|
149
|
+
backend = "qdrant"
|
|
150
|
+
qdrant_url = "http://127.0.0.1:6333"
|
|
151
|
+
qdrant_collection = "phonton-code"
|
|
134
152
|
```
|
|
135
153
|
|
|
136
|
-
|
|
137
|
-
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 🛠️ Commands Reference
|
|
157
|
+
|
|
138
158
|
```bash
|
|
159
|
+
# Launch the interactive Ratatui TUI
|
|
160
|
+
phonton
|
|
161
|
+
|
|
162
|
+
# Run a goal non-interactively through the full plan/edit/verify pipeline
|
|
163
|
+
phonton goal "add input validation to config loading" --yes
|
|
164
|
+
|
|
165
|
+
# Preview the subtask graph and Conflict Groups without editing files
|
|
166
|
+
phonton plan "refactor auth layer"
|
|
167
|
+
|
|
168
|
+
# Audit configuration, API keys, database, and vector index connectivity
|
|
139
169
|
phonton doctor --provider
|
|
140
|
-
```
|
|
141
170
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
```bash
|
|
145
|
-
phonton demo trust-loop
|
|
171
|
+
# Export benchmark telemetry from the latest run
|
|
172
|
+
phonton benchmark export --latest --format json
|
|
146
173
|
```
|
|
147
174
|
|
|
148
175
|
---
|
|
149
176
|
|
|
150
|
-
##
|
|
177
|
+
## 🗺️ Crate Architecture
|
|
151
178
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* Install an MCP recipe: `phonton extensions install github`
|
|
179
|
+
Phonton is written entirely in Rust for performance, correctness, and low memory overhead:
|
|
180
|
+
* `phonton-cli`: Interactive TUI, headless runner, benchmark, and CLI commands.
|
|
181
|
+
* `phonton-planner`: Multi-model goal decomposition and `PlanGraph` sidecar staging.
|
|
182
|
+
* `phonton-orchestrator`: Swarm scheduler, Conflict Group serialization, and verifier pipeline execution.
|
|
183
|
+
* `phonton-worker`: Highly optimized context assembler and diff-only code modifier.
|
|
184
|
+
* `phonton-index`: Local HNSW symbol index and Qdrant integration.
|
|
185
|
+
* `phonton-verify`: Four-layer static checkers (Tree-Sitter, Cargo, Playwright Browser/Screenshot).
|
|
186
|
+
* `phonton-mcp`: Lazy initialization client, permission gates, and capabilities descriptor.
|
|
161
187
|
|
|
162
188
|
---
|
|
163
189
|
|
|
164
|
-
##
|
|
190
|
+
## 💖 Star History
|
|
191
|
+
|
|
192
|
+
If you support a privacy-first, fully autonomous developer experience, please leave us a star!
|
|
165
193
|
|
|
166
|
-
|
|
167
|
-
|---|---|---|
|
|
168
|
-
| **Stable** | `cargo install --git https://github.com/phonton-dev/phonton-cli --tag v0.17.1 phonton-cli --locked --force` | Best validated release |
|
|
169
|
-
| **Dev** | `cargo install --git https://github.com/phonton-dev/phonton-cli --branch dev phonton-cli --locked --force` | Upcoming release features |
|
|
170
|
-
| **Nightly** | `cargo install --git https://github.com/phonton-dev/phonton-cli --branch nightly phonton-cli --locked --force` | Daily automated snapshots |
|
|
194
|
+
[](https://www.star-history.com/?repos=phonton-dev%2Fphonton-cli&type=date&legend=top-left)
|
|
171
195
|
|
|
172
196
|
---
|
|
173
197
|
|
|
@@ -177,4 +201,4 @@ Licensed under either of:
|
|
|
177
201
|
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
|
|
178
202
|
* MIT License ([LICENSE-MIT](LICENSE-MIT))
|
|
179
203
|
|
|
180
|
-
|
|
204
|
+
At your option.
|
package/npm/bin/phonton.js
CHANGED
|
@@ -4,18 +4,14 @@ const fs = require("fs");
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const { spawn, spawnSync } = require("child_process");
|
|
6
6
|
|
|
7
|
-
const packageJson = require("../../package.json");
|
|
8
7
|
const binaryName = process.platform === "win32" ? "phonton.exe" : "phonton";
|
|
9
8
|
const configuredBinary = process.env.PHONTON_BINARY || process.env.PHONTON_CLI_BINARY;
|
|
10
9
|
const binaryPath = configuredBinary
|
|
11
10
|
? path.resolve(configuredBinary)
|
|
12
11
|
: path.join(__dirname, "..", "vendor", binaryName);
|
|
13
|
-
const vendorDir = path.join(__dirname, "..", "vendor");
|
|
14
|
-
const markerPath = path.join(vendorDir, "version.json");
|
|
15
12
|
|
|
16
13
|
function ensureBinary() {
|
|
17
|
-
if (
|
|
18
|
-
assertBinaryVersion(binaryPath);
|
|
14
|
+
if (fs.existsSync(binaryPath)) {
|
|
19
15
|
return;
|
|
20
16
|
}
|
|
21
17
|
|
|
@@ -24,53 +20,11 @@ function ensureBinary() {
|
|
|
24
20
|
process.exit(1);
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
fs.rmSync(vendorDir, { recursive: true, force: true });
|
|
32
|
-
|
|
33
|
-
const installScript = process.env.PHONTON_INSTALL_SCRIPT || path.join(__dirname, "..", "install.js");
|
|
23
|
+
const installScript = path.join(__dirname, "..", "install.js");
|
|
34
24
|
const result = spawnSync(process.execPath, [installScript], { stdio: "inherit" });
|
|
35
25
|
if (result.status !== 0 || !fs.existsSync(binaryPath)) {
|
|
36
26
|
process.exit(result.status || 1);
|
|
37
27
|
}
|
|
38
|
-
assertBinaryVersion(binaryPath);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function vendorMatchesPackage() {
|
|
42
|
-
try {
|
|
43
|
-
const marker = JSON.parse(fs.readFileSync(markerPath, "utf8"));
|
|
44
|
-
return (
|
|
45
|
-
marker.version === packageJson.version &&
|
|
46
|
-
marker.platform === process.platform &&
|
|
47
|
-
marker.arch === process.arch
|
|
48
|
-
);
|
|
49
|
-
} catch (_error) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function assertBinaryVersion(candidate) {
|
|
55
|
-
const check = binaryVersionMatches(candidate);
|
|
56
|
-
if (!check.ok) {
|
|
57
|
-
console.error(`Installed Phonton binary is stale or invalid: expected ${check.expected}, got ${check.output}`);
|
|
58
|
-
if (!configuredBinary) {
|
|
59
|
-
fs.rmSync(vendorDir, { recursive: true, force: true });
|
|
60
|
-
}
|
|
61
|
-
process.exit(1);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function binaryVersionMatches(candidate) {
|
|
66
|
-
const result = spawnSync(candidate, ["version"], { encoding: "utf8" });
|
|
67
|
-
const output = `${result.stdout || ""}${result.stderr || ""}`.trim() || "no output";
|
|
68
|
-
const expected = `phonton ${packageJson.version}`;
|
|
69
|
-
return {
|
|
70
|
-
ok: result.status === 0 && output.includes(expected),
|
|
71
|
-
expected,
|
|
72
|
-
output,
|
|
73
|
-
};
|
|
74
28
|
}
|
|
75
29
|
|
|
76
30
|
ensureBinary();
|
package/npm/install.js
CHANGED
|
@@ -12,7 +12,6 @@ const repo = "phonton-dev/phonton-cli";
|
|
|
12
12
|
const version = packageJson.version;
|
|
13
13
|
const tag = process.env.PHONTON_RELEASE_TAG || (version.includes("nightly") ? "nightly" : `v${version}`);
|
|
14
14
|
const vendorDir = path.join(__dirname, "vendor");
|
|
15
|
-
const markerPath = path.join(vendorDir, "version.json");
|
|
16
15
|
|
|
17
16
|
const targets = {
|
|
18
17
|
"linux-x64": {
|
|
@@ -56,20 +55,6 @@ download(url, archivePath)
|
|
|
56
55
|
if (process.platform !== "win32") {
|
|
57
56
|
fs.chmodSync(binaryPath, 0o755);
|
|
58
57
|
}
|
|
59
|
-
fs.writeFileSync(
|
|
60
|
-
markerPath,
|
|
61
|
-
`${JSON.stringify(
|
|
62
|
-
{
|
|
63
|
-
version,
|
|
64
|
-
tag,
|
|
65
|
-
asset: target.asset,
|
|
66
|
-
platform: process.platform,
|
|
67
|
-
arch: process.arch,
|
|
68
|
-
},
|
|
69
|
-
null,
|
|
70
|
-
2,
|
|
71
|
-
)}\n`,
|
|
72
|
-
);
|
|
73
58
|
console.log(`Installed Phonton CLI ${tag} for ${process.platform}-${process.arch}`);
|
|
74
59
|
})
|
|
75
60
|
.catch((error) => {
|
package/npm/test-wrapper.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require("fs");
|
|
4
|
-
const os = require("os");
|
|
5
4
|
const path = require("path");
|
|
6
5
|
const { spawnSync } = require("child_process");
|
|
7
6
|
|
|
@@ -19,118 +18,24 @@ if (!binary) {
|
|
|
19
18
|
process.exit(1);
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
env
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
});
|
|
21
|
+
const result = spawnSync(process.execPath, [path.join(root, "npm", "bin", "phonton.js"), "version"], {
|
|
22
|
+
cwd: root,
|
|
23
|
+
encoding: "utf8",
|
|
24
|
+
env: {
|
|
25
|
+
...process.env,
|
|
26
|
+
PHONTON_BINARY: binary,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
process.stdout.write(result.stdout || "");
|
|
31
|
+
process.stderr.write(result.stderr || "");
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return result.stdout;
|
|
33
|
+
if (result.status !== 0) {
|
|
34
|
+
process.exit(result.status || 1);
|
|
40
35
|
}
|
|
41
36
|
|
|
42
|
-
const versionOutput = runWrapper(["version"]);
|
|
43
|
-
|
|
44
37
|
const expected = `phonton ${packageJson.version}`;
|
|
45
|
-
if (!
|
|
38
|
+
if (!result.stdout.includes(expected)) {
|
|
46
39
|
console.error(`Expected npm wrapper to report ${expected}.`);
|
|
47
40
|
process.exit(1);
|
|
48
41
|
}
|
|
49
|
-
|
|
50
|
-
testStaleVendorReinstall();
|
|
51
|
-
|
|
52
|
-
const goal = "add input validation to config loading";
|
|
53
|
-
const planOutput = runWrapper(["plan", "--json", "--no-memory", goal]);
|
|
54
|
-
let planJson;
|
|
55
|
-
try {
|
|
56
|
-
planJson = JSON.parse(planOutput);
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.error(`Expected plan --json to emit parseable JSON: ${error.message}`);
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (!planJson.goal_contract) {
|
|
63
|
-
console.error("Expected plan --json to expose goal_contract at the top level.");
|
|
64
|
-
process.exit(1);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (planJson.goal_contract.goal !== goal) {
|
|
68
|
-
console.error("Expected plan --json goal_contract.goal to match the requested goal.");
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function testStaleVendorReinstall() {
|
|
73
|
-
const vendorDir = path.join(root, "npm", "vendor");
|
|
74
|
-
const vendorBinary = path.join(vendorDir, binaryName);
|
|
75
|
-
const markerPath = path.join(vendorDir, "version.json");
|
|
76
|
-
const installScript = path.join(os.tmpdir(), `phonton-test-install-${process.pid}.js`);
|
|
77
|
-
|
|
78
|
-
fs.rmSync(vendorDir, { recursive: true, force: true });
|
|
79
|
-
fs.mkdirSync(vendorDir, { recursive: true });
|
|
80
|
-
fs.copyFileSync(binary, vendorBinary);
|
|
81
|
-
if (process.platform !== "win32") {
|
|
82
|
-
fs.chmodSync(vendorBinary, 0o755);
|
|
83
|
-
}
|
|
84
|
-
fs.writeFileSync(
|
|
85
|
-
markerPath,
|
|
86
|
-
JSON.stringify({
|
|
87
|
-
version: "0.0.0-stale",
|
|
88
|
-
platform: process.platform,
|
|
89
|
-
arch: process.arch,
|
|
90
|
-
}),
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
fs.writeFileSync(
|
|
94
|
-
installScript,
|
|
95
|
-
`
|
|
96
|
-
const fs = require("fs");
|
|
97
|
-
const path = require("path");
|
|
98
|
-
const vendorDir = ${JSON.stringify(vendorDir)};
|
|
99
|
-
const binary = ${JSON.stringify(binary)};
|
|
100
|
-
const binaryName = ${JSON.stringify(binaryName)};
|
|
101
|
-
const version = ${JSON.stringify(packageJson.version)};
|
|
102
|
-
fs.mkdirSync(vendorDir, { recursive: true });
|
|
103
|
-
fs.copyFileSync(binary, path.join(vendorDir, binaryName));
|
|
104
|
-
if (process.platform !== "win32") fs.chmodSync(path.join(vendorDir, binaryName), 0o755);
|
|
105
|
-
fs.writeFileSync(path.join(vendorDir, "version.json"), JSON.stringify({
|
|
106
|
-
version,
|
|
107
|
-
platform: process.platform,
|
|
108
|
-
arch: process.arch,
|
|
109
|
-
}, null, 2));
|
|
110
|
-
`,
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
const result = spawnSync(process.execPath, [path.join(root, "npm", "bin", "phonton.js"), "version"], {
|
|
115
|
-
cwd: root,
|
|
116
|
-
encoding: "utf8",
|
|
117
|
-
env: {
|
|
118
|
-
...process.env,
|
|
119
|
-
PHONTON_INSTALL_SCRIPT: installScript,
|
|
120
|
-
PHONTON_BINARY: "",
|
|
121
|
-
PHONTON_CLI_BINARY: "",
|
|
122
|
-
},
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
process.stdout.write(result.stdout || "");
|
|
126
|
-
process.stderr.write(result.stderr || "");
|
|
127
|
-
|
|
128
|
-
if (result.status !== 0 || !result.stdout.includes(expected)) {
|
|
129
|
-
console.error("Expected npm wrapper to refresh stale vendor binary metadata.");
|
|
130
|
-
process.exit(result.status || 1);
|
|
131
|
-
}
|
|
132
|
-
} finally {
|
|
133
|
-
fs.rmSync(installScript, { force: true });
|
|
134
|
-
fs.rmSync(vendorDir, { recursive: true, force: true });
|
|
135
|
-
}
|
|
136
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "phonton-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Local-first agentic development terminal with context packs, source handles, and verification gates.",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/phonton-dev/phonton-cli#readme",
|
|
@@ -41,5 +41,9 @@
|
|
|
41
41
|
],
|
|
42
42
|
"engines": {
|
|
43
43
|
"node": ">=18"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@playwright/test": "^1.60.0",
|
|
47
|
+
"playwright": "^1.60.0"
|
|
44
48
|
}
|
|
45
49
|
}
|