phewsh 0.12.0 → 0.12.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 +1 -1
- package/commands/serve.js +36 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Connect the web app to your local machine for real-time task execution:
|
|
|
23
23
|
phewsh serve
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
This starts a bridge on `localhost:7483`. Open [phewsh.com/intent](https://phewsh.com/intent) and go to the Work tab — you'll see a green "Live" indicator. Agent tasks get a "Run Live" button that executes
|
|
26
|
+
This starts a bridge on `localhost:7483`. Open [phewsh.com/intent](https://phewsh.com/intent) and go to the Work tab — you'll see a green "Live" indicator. Agent tasks get a "Run Live" button that executes on your machine through whichever agent CLIs you have installed: **Claude Code, Codex, Gemini, Cursor Agent, OpenCode**. PHEWSH detects them automatically and every run leaves a receipt (`phewsh receipts`).
|
|
27
27
|
|
|
28
28
|
## Interactive Shell
|
|
29
29
|
|
package/commands/serve.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
// phewsh serve — HTTP bridge server for live execution from the web UI
|
|
2
2
|
//
|
|
3
|
-
// Starts a local server that the PHEWSH web app connects to for live task
|
|
4
|
-
// When running, the web UI shows a green "Live" indicator and
|
|
3
|
+
// Starts a local server that the PHEWSH web app connects to for live task
|
|
4
|
+
// execution. When running, the web UI shows a green "Live" indicator and
|
|
5
|
+
// "Run Live" buttons for every agent CLI installed on this machine —
|
|
6
|
+
// Claude Code, Codex, Gemini, Cursor Agent, OpenCode. PHEWSH is not a
|
|
7
|
+
// harness; it dispatches to the harnesses you already have, and every run
|
|
8
|
+
// leaves a receipt (~/.phewsh/ — see `phewsh receipts`).
|
|
5
9
|
//
|
|
6
10
|
// Usage:
|
|
7
11
|
// phewsh serve Start on default port (7483)
|
|
@@ -31,15 +35,27 @@ function getPort() {
|
|
|
31
35
|
|
|
32
36
|
// ─── Runtime Detection ─────────────────────────────────────────────────────
|
|
33
37
|
|
|
38
|
+
// Harness runners — how to invoke each agent CLI headlessly. PHEWSH is not a
|
|
39
|
+
// harness; it's the layer that dispatches to whichever harnesses you have.
|
|
40
|
+
// Detection is honest: a runtime is only "connected" if its binary is on PATH.
|
|
41
|
+
const RUNNERS = {
|
|
42
|
+
'claude-code': { bin: 'claude', label: 'Claude Code', args: (p) => ['-p', p, '--output-format', 'text'] },
|
|
43
|
+
'codex': { bin: 'codex', label: 'Codex CLI', args: (p) => ['exec', p] },
|
|
44
|
+
'gemini': { bin: 'gemini', label: 'Gemini CLI', args: (p) => ['-p', p] },
|
|
45
|
+
'cursor': { bin: 'cursor-agent', label: 'Cursor Agent', args: (p) => ['-p', p, '--output-format', 'text'] },
|
|
46
|
+
'opencode': { bin: 'opencode', label: 'OpenCode', args: (p) => ['run', p] },
|
|
47
|
+
};
|
|
48
|
+
|
|
34
49
|
function detectRuntimes() {
|
|
35
50
|
const runtimes = [];
|
|
36
51
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
for (const [id, r] of Object.entries(RUNNERS)) {
|
|
53
|
+
let connected = false;
|
|
54
|
+
try {
|
|
55
|
+
execSync(`which ${r.bin}`, { stdio: 'pipe' });
|
|
56
|
+
connected = true;
|
|
57
|
+
} catch { /* not installed */ }
|
|
58
|
+
runtimes.push({ id, label: r.label, connected });
|
|
43
59
|
}
|
|
44
60
|
|
|
45
61
|
// Always report human as available
|
|
@@ -87,8 +103,9 @@ async function executeJob(jobId) {
|
|
|
87
103
|
|
|
88
104
|
const { runtimeId, packet } = job;
|
|
89
105
|
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
const runner = RUNNERS[runtimeId];
|
|
107
|
+
if (runner) {
|
|
108
|
+
await executeViaHarness(job, packet, runner);
|
|
92
109
|
} else {
|
|
93
110
|
job.status = 'error';
|
|
94
111
|
job.error = `Runtime ${runtimeId} not supported for live execution yet`;
|
|
@@ -96,7 +113,7 @@ async function executeJob(jobId) {
|
|
|
96
113
|
}
|
|
97
114
|
}
|
|
98
115
|
|
|
99
|
-
async function
|
|
116
|
+
async function executeViaHarness(job, packet, runner) {
|
|
100
117
|
// Build a prompt from the dispatch packet
|
|
101
118
|
const prompt = [
|
|
102
119
|
`# Task: ${packet.objective?.task || 'Execute task'}`,
|
|
@@ -115,15 +132,17 @@ async function executeViaClaude(job, packet) {
|
|
|
115
132
|
].filter(Boolean).join('\n');
|
|
116
133
|
|
|
117
134
|
return new Promise((resolve) => {
|
|
118
|
-
job.statusText =
|
|
135
|
+
job.statusText = `Launching ${runner.label}...`;
|
|
119
136
|
|
|
120
|
-
|
|
121
|
-
const child = spawn('claude', ['-p', prompt, '--output-format', 'text'], {
|
|
137
|
+
const child = spawn(runner.bin, runner.args(prompt), {
|
|
122
138
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
123
139
|
env: { ...process.env },
|
|
124
140
|
cwd: process.cwd(),
|
|
125
141
|
});
|
|
126
142
|
|
|
143
|
+
// Some harnesses (codex exec, gemini) wait for stdin EOF before running.
|
|
144
|
+
child.stdin.end();
|
|
145
|
+
|
|
127
146
|
let stdout = '';
|
|
128
147
|
let stderr = '';
|
|
129
148
|
|
|
@@ -149,7 +168,7 @@ async function executeViaClaude(job, packet) {
|
|
|
149
168
|
console.log(` ${green('✓')} Job ${job.jobId.slice(0, 8)} completed`);
|
|
150
169
|
} else {
|
|
151
170
|
job.status = 'error';
|
|
152
|
-
job.error = stderr.trim() ||
|
|
171
|
+
job.error = stderr.trim() || `${runner.label} exited with code ${code}`;
|
|
153
172
|
job.statusText = 'Failed';
|
|
154
173
|
console.log(` ${yellow('✗')} Job ${job.jobId.slice(0, 8)} failed: ${job.error.slice(0, 100)}`);
|
|
155
174
|
}
|
|
@@ -160,11 +179,11 @@ async function executeViaClaude(job, packet) {
|
|
|
160
179
|
taskId: packet?.id || job.actionId || job.jobId,
|
|
161
180
|
result: success ? job.result : job.error,
|
|
162
181
|
success,
|
|
163
|
-
agentId:
|
|
182
|
+
agentId: job.runtimeId,
|
|
164
183
|
executor: 'phewsh-serve',
|
|
165
184
|
reportedAt: new Date().toISOString(),
|
|
166
185
|
});
|
|
167
|
-
recordSessionEvent(
|
|
186
|
+
recordSessionEvent(job.runtimeId, 'web', 'task_complete', {
|
|
168
187
|
taskId: packet?.id || job.actionId || job.jobId,
|
|
169
188
|
success,
|
|
170
189
|
result: (success ? job.result : job.error || '').slice(0, 200),
|