ever-terminal 1.0.0 → 1.0.2
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 +2 -26
- package/dist/claude/provider.js +12 -12
- package/dist/claude/session.js +76 -42
- package/dist/cli.js +7 -0
- package/dist/routes/core.js +6 -6
- package/package.json +3 -11
package/README.md
CHANGED
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
`ever-terminal` is designed to be used with the Even App.
|
|
4
4
|
|
|
5
|
-
> Building glasses-native apps instead of mirroring your laptop? See [@evenrealities/even_hub_sdk](https://www.npmjs.com/package/@evenrealities/even_hub_sdk).
|
|
6
|
-
|
|
7
5
|
Supports macOS, Linux, Windows.
|
|
8
6
|
|
|
9
7
|
---
|
|
10
8
|
|
|
11
9
|
## Requirements
|
|
12
10
|
|
|
13
|
-
- **Node.js
|
|
11
|
+
- **Node.js 22+** — check with `node --version`. Install from [nodejs.org](https://nodejs.org), or `brew install node` (macOS), or your distro's package manager (Linux).
|
|
14
12
|
- An **Even Realities G2** + **R1 ring**, paired through the Even app (iOS/Android).
|
|
15
13
|
- Optional but recommended: a [Tailscale](https://tailscale.com) account signed in on both your laptop and phone — gives you a stable private network without needing the public-tunnel providers below.
|
|
16
14
|
|
|
@@ -235,29 +233,7 @@ For anything else: `ever-terminal --verbose --log-file ./debug.log`, reproduce,
|
|
|
235
233
|
|
|
236
234
|
## Changelog
|
|
237
235
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
- optimize codex session history performance for large session (windows)
|
|
241
|
-
- add `--expose ngrok` support (need to sign in elsewhere first)
|
|
242
|
-
|
|
243
|
-
### 0.8.0
|
|
244
|
-
|
|
245
|
-
- codex now only starts a background process when necessary
|
|
246
|
-
|
|
247
|
-
### 0.7.9
|
|
248
|
-
|
|
249
|
-
- add debug timing for codex history api
|
|
250
|
-
- fix middle deny behavior in multiple permission requests
|
|
251
|
-
|
|
252
|
-
### 0.7.8
|
|
253
|
-
|
|
254
|
-
- add update check api
|
|
255
|
-
|
|
256
|
-
### 0.7.7
|
|
257
|
-
|
|
258
|
-
- improve codex support with `ever-terminal codex` wrapper which can sync
|
|
259
|
-
messages between codex cli and glasses
|
|
260
|
-
- internal refactoring
|
|
236
|
+
Releases are automated via [semantic-release](https://semantic-release.gitbook.io/) — see the [version history on npm](https://www.npmjs.com/package/ever-terminal?activeTab=versions).
|
|
261
237
|
|
|
262
238
|
---
|
|
263
239
|
|
package/dist/claude/provider.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { readFileSync, existsSync, readdirSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
+
import { exec } from "node:child_process";
|
|
5
|
+
import { promisify } from "node:util";
|
|
4
6
|
import { listSessions, getSessionMessages, } from "@anthropic-ai/claude-agent-sdk";
|
|
7
|
+
const execAsync = promisify(exec);
|
|
5
8
|
import { ClaudeSession } from "./session.js";
|
|
6
9
|
/** Find the jsonl file for a Claude session by scanning project dirs. */
|
|
7
10
|
function findSessionFile(sessionId) {
|
|
@@ -55,11 +58,11 @@ export function claudeSessionStatus(sessionId) {
|
|
|
55
58
|
if (text.includes("Request interrupted by user"))
|
|
56
59
|
return "idle";
|
|
57
60
|
}
|
|
58
|
-
if (last.timestamp)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
if (!last.timestamp)
|
|
62
|
+
return "idle"; // ponytail: no timestamp → not in-progress
|
|
63
|
+
const ageMs = Date.now() - new Date(last.timestamp).getTime();
|
|
64
|
+
if (ageMs > 120_000)
|
|
65
|
+
return "idle";
|
|
63
66
|
return "busy";
|
|
64
67
|
}
|
|
65
68
|
// ── Provider factory ────────────────────────────────────
|
|
@@ -108,11 +111,11 @@ export function createClaudeProvider(emit) {
|
|
|
108
111
|
"";
|
|
109
112
|
return { sessionId: resolvedId, provider: "claude" };
|
|
110
113
|
}
|
|
111
|
-
function respondPermission(sessionId, decision) {
|
|
112
|
-
sessions.get(sessionId)?.respondPermission(decision);
|
|
114
|
+
function respondPermission(sessionId, decision, toolUseId) {
|
|
115
|
+
sessions.get(sessionId)?.respondPermission(decision, toolUseId);
|
|
113
116
|
}
|
|
114
|
-
function respondQuestion(sessionId, answer) {
|
|
115
|
-
sessions.get(sessionId)?.respondQuestion(answer);
|
|
117
|
+
function respondQuestion(sessionId, answer, toolUseId) {
|
|
118
|
+
sessions.get(sessionId)?.respondQuestion(answer, toolUseId);
|
|
116
119
|
}
|
|
117
120
|
function interrupt(sessionId) {
|
|
118
121
|
sessions.get(sessionId)?.interrupt();
|
|
@@ -144,9 +147,6 @@ export function createClaudeProvider(emit) {
|
|
|
144
147
|
}));
|
|
145
148
|
}
|
|
146
149
|
async function getInfo() {
|
|
147
|
-
const { exec } = await import("node:child_process");
|
|
148
|
-
const { promisify } = await import("node:util");
|
|
149
|
-
const execAsync = promisify(exec);
|
|
150
150
|
let version = "";
|
|
151
151
|
try {
|
|
152
152
|
const { stdout } = await execAsync("claude --version", {
|
package/dist/claude/session.js
CHANGED
|
@@ -2,6 +2,8 @@ import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { summarizeClaudeToolCall } from "./summarize.js";
|
|
4
4
|
import { debugLog } from "../debug.js";
|
|
5
|
+
// ponytail: shell metachar check — rejects chained commands, keeps the regex simple
|
|
6
|
+
const SHELL_META = /[&|;`$><\n]/;
|
|
5
7
|
function buildClaudePermissionOptions(suggestions, description) {
|
|
6
8
|
const options = [{ text: "Yes", key: "allow" }];
|
|
7
9
|
const alwaysText = describeClaudePermissionSuggestions(suggestions, description);
|
|
@@ -71,8 +73,8 @@ export class ClaudeSession {
|
|
|
71
73
|
statsTimer = null;
|
|
72
74
|
queryHandle = null;
|
|
73
75
|
runningQuery = null;
|
|
74
|
-
pendingPermissions =
|
|
75
|
-
pendingQuestions =
|
|
76
|
+
pendingPermissions = new Map();
|
|
77
|
+
pendingQuestions = new Map();
|
|
76
78
|
alwaysAllowedTools = new Set();
|
|
77
79
|
pendingToolCalls = new Map();
|
|
78
80
|
/** Tracks the type of the currently-open content block ("thinking" | "text" | null). */
|
|
@@ -99,8 +101,7 @@ export class ClaudeSession {
|
|
|
99
101
|
/** Tracked session status: 'awaiting' if there's an unanswered permission
|
|
100
102
|
* request or user question, otherwise 'busy'/'idle' based on _busy. */
|
|
101
103
|
get status() {
|
|
102
|
-
if (this.pendingPermissions.
|
|
103
|
-
this.pendingQuestions.length > 0) {
|
|
104
|
+
if (this.pendingPermissions.size > 0 || this.pendingQuestions.size > 0) {
|
|
104
105
|
return "awaiting";
|
|
105
106
|
}
|
|
106
107
|
return this._busy ? "busy" : "idle";
|
|
@@ -113,10 +114,11 @@ export class ClaudeSession {
|
|
|
113
114
|
this.idResolve = resolve;
|
|
114
115
|
});
|
|
115
116
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
let timer;
|
|
118
|
+
const timeout = new Promise((_, reject) => {
|
|
119
|
+
timer = setTimeout(() => reject(new Error("Timed out waiting for session ID")), timeoutMs);
|
|
120
|
+
});
|
|
121
|
+
return Promise.race([this.idPromise, timeout]).finally(() => clearTimeout(timer));
|
|
120
122
|
}
|
|
121
123
|
onIdReady(cb) {
|
|
122
124
|
if (this.sessionId) {
|
|
@@ -153,37 +155,50 @@ export class ClaudeSession {
|
|
|
153
155
|
}
|
|
154
156
|
/**
|
|
155
157
|
* Wait for a user response with timeout and SDK abort signal as fallbacks.
|
|
156
|
-
* Multiple requests can be pending (e.g. subagents);
|
|
158
|
+
* Multiple requests can be pending (e.g. subagents); keyed by toolUseId.
|
|
157
159
|
*/
|
|
158
|
-
waitForUser(
|
|
160
|
+
waitForUser(map, toolUseId, signal, timeoutMs, defaultValue) {
|
|
159
161
|
return new Promise((resolve) => {
|
|
160
162
|
let settled = false;
|
|
161
|
-
const entry = (value) => finish(value);
|
|
162
163
|
const finish = (value) => {
|
|
163
164
|
if (settled)
|
|
164
165
|
return;
|
|
165
166
|
settled = true;
|
|
166
167
|
clearTimeout(timer);
|
|
167
168
|
signal.removeEventListener("abort", onAbort);
|
|
168
|
-
|
|
169
|
-
if (idx !== -1)
|
|
170
|
-
queue.splice(idx, 1);
|
|
169
|
+
map.delete(toolUseId);
|
|
171
170
|
resolve(value);
|
|
172
171
|
};
|
|
173
172
|
const timer = setTimeout(() => finish(defaultValue), timeoutMs);
|
|
174
173
|
const onAbort = () => finish(defaultValue);
|
|
175
174
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
176
|
-
|
|
175
|
+
map.set(toolUseId, (value) => finish(value));
|
|
177
176
|
});
|
|
178
177
|
}
|
|
179
|
-
respondPermission(decision) {
|
|
180
|
-
this.pendingPermissions
|
|
178
|
+
respondPermission(decision, toolUseId) {
|
|
179
|
+
const resolver = this.resolveFromPending(this.pendingPermissions, toolUseId);
|
|
180
|
+
resolver?.({
|
|
181
181
|
allow: decision === "allow" || decision === "allowAlways",
|
|
182
182
|
allowAlways: decision === "allowAlways",
|
|
183
183
|
});
|
|
184
184
|
}
|
|
185
|
-
respondQuestion(answer) {
|
|
186
|
-
this.pendingQuestions
|
|
185
|
+
respondQuestion(answer, toolUseId) {
|
|
186
|
+
const resolver = this.resolveFromPending(this.pendingQuestions, toolUseId);
|
|
187
|
+
resolver?.(answer);
|
|
188
|
+
}
|
|
189
|
+
/** Resolve a pending entry by toolUseId (exact match) or fall back to the oldest entry. */
|
|
190
|
+
resolveFromPending(map, toolUseId) {
|
|
191
|
+
if (toolUseId && map.has(toolUseId)) {
|
|
192
|
+
const fn = map.get(toolUseId);
|
|
193
|
+
map.delete(toolUseId);
|
|
194
|
+
return fn;
|
|
195
|
+
}
|
|
196
|
+
// ponytail: fallback to oldest entry for clients that don't send toolUseId yet
|
|
197
|
+
const first = map.entries().next();
|
|
198
|
+
if (first.done)
|
|
199
|
+
return undefined;
|
|
200
|
+
map.delete(first.value[0]);
|
|
201
|
+
return first.value[1];
|
|
187
202
|
}
|
|
188
203
|
stopStatsTimer() {
|
|
189
204
|
if (this.statsTimer) {
|
|
@@ -246,7 +261,7 @@ export class ClaudeSession {
|
|
|
246
261
|
options: {
|
|
247
262
|
resume: this.sessionId,
|
|
248
263
|
cwd: this.lockedCwd,
|
|
249
|
-
model: "claude-opus-4-
|
|
264
|
+
model: process.env.CLAUDE_MODEL || "claude-opus-4-8",
|
|
250
265
|
allowedTools: [
|
|
251
266
|
"Read",
|
|
252
267
|
"Edit",
|
|
@@ -283,7 +298,7 @@ export class ClaudeSession {
|
|
|
283
298
|
},
|
|
284
299
|
includePartialMessages: true,
|
|
285
300
|
maxTurns: 50,
|
|
286
|
-
|
|
301
|
+
// ponytail: omit settingSources to load all three (user/project/local), matching CLI defaults
|
|
287
302
|
stderr: (data) => {
|
|
288
303
|
const trimmed = data.trim();
|
|
289
304
|
if (trimmed)
|
|
@@ -337,6 +352,7 @@ export class ClaudeSession {
|
|
|
337
352
|
});
|
|
338
353
|
}
|
|
339
354
|
interrupt() {
|
|
355
|
+
this.promptQueue.length = 0;
|
|
340
356
|
this.queryHandle?.interrupt().catch(() => { });
|
|
341
357
|
}
|
|
342
358
|
async close() {
|
|
@@ -346,8 +362,9 @@ export class ClaudeSession {
|
|
|
346
362
|
};
|
|
347
363
|
console.log(`[session] close: session=${this.sessionId ?? "none"} had=${JSON.stringify(had)}`);
|
|
348
364
|
this.stopStatsTimer();
|
|
349
|
-
this.pendingPermissions.
|
|
350
|
-
this.pendingQuestions.
|
|
365
|
+
this.pendingPermissions.clear();
|
|
366
|
+
this.pendingQuestions.clear();
|
|
367
|
+
this.pendingToolCalls.clear();
|
|
351
368
|
this.promptQueue.length = 0;
|
|
352
369
|
if (this.queryHandle) {
|
|
353
370
|
this.queryHandle.close();
|
|
@@ -364,6 +381,8 @@ export class ClaudeSession {
|
|
|
364
381
|
async reset(cwd) {
|
|
365
382
|
await this.close();
|
|
366
383
|
this.sessionId = undefined;
|
|
384
|
+
this.idPromise = null;
|
|
385
|
+
this.idResolve = null;
|
|
367
386
|
this.lockedCwd = cwd;
|
|
368
387
|
}
|
|
369
388
|
// ── Tool handlers ──────────────────────────────────
|
|
@@ -376,21 +395,23 @@ export class ClaudeSession {
|
|
|
376
395
|
console.log(`[session] Auto-approve (allowAlways): ${toolName}`);
|
|
377
396
|
return { behavior: "allow", updatedInput: input };
|
|
378
397
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
"
|
|
382
|
-
"
|
|
383
|
-
"
|
|
398
|
+
// ponytail: known safe read-only tools — auto-allow, no prompt
|
|
399
|
+
const READ_ONLY_TOOLS = new Set([
|
|
400
|
+
"Read",
|
|
401
|
+
"Glob",
|
|
402
|
+
"Grep",
|
|
403
|
+
"WebSearch",
|
|
404
|
+
"WebFetch",
|
|
405
|
+
"ToolSearch",
|
|
406
|
+
"ListMcpResources",
|
|
407
|
+
"ReadMcpResource",
|
|
408
|
+
"ExitPlanMode",
|
|
409
|
+
"TaskOutput",
|
|
410
|
+
"TaskGet",
|
|
411
|
+
"TaskList",
|
|
384
412
|
]);
|
|
385
|
-
if (
|
|
386
|
-
return
|
|
387
|
-
}
|
|
388
|
-
if (toolName === "Bash") {
|
|
389
|
-
const cmd = String(input.command || "").trim();
|
|
390
|
-
if (/^\s*(ls|cat|head|tail|wc|pwd|echo|printf|date|whoami|which|where|type|file|stat|du|df|env|printenv|uname|hostname|id|git\s+(status|log|diff|branch|show|remote|rev-parse))\b/.test(cmd)) {
|
|
391
|
-
return { behavior: "allow", updatedInput: input };
|
|
392
|
-
}
|
|
393
|
-
return this.handlePermissionConfirm(toolName, input, options.toolUseID, options.signal, options.suggestions);
|
|
413
|
+
if (READ_ONLY_TOOLS.has(toolName)) {
|
|
414
|
+
return { behavior: "allow", updatedInput: input };
|
|
394
415
|
}
|
|
395
416
|
if (toolName === "TodoWrite") {
|
|
396
417
|
const todos = input.todos || [];
|
|
@@ -420,8 +441,18 @@ export class ClaudeSession {
|
|
|
420
441
|
}
|
|
421
442
|
return { behavior: "allow", updatedInput: input };
|
|
422
443
|
}
|
|
423
|
-
|
|
424
|
-
|
|
444
|
+
if (toolName === "Bash") {
|
|
445
|
+
const cmd = String(input.command || "").trim();
|
|
446
|
+
// ponytail: only auto-allow simple read-only commands with NO shell metachars
|
|
447
|
+
if (!SHELL_META.test(cmd) &&
|
|
448
|
+
/^\s*(ls|cat|head|tail|wc|pwd|echo|printf|date|whoami|which|where|type|file|stat|du|df|env|printenv|uname|hostname|id|git\s+(status|log|diff|branch|show|remote|rev-parse))\b/.test(cmd)) {
|
|
449
|
+
return { behavior: "allow", updatedInput: input };
|
|
450
|
+
}
|
|
451
|
+
return this.handlePermissionConfirm(toolName, input, options.toolUseID, options.signal, options.suggestions);
|
|
452
|
+
}
|
|
453
|
+
// ponytail: everything else (Write, MCP tools, Agent, Skill, etc.) — prompt the user
|
|
454
|
+
console.log(`[session] canUseTool prompt-required: ${toolName} input_keys=${Object.keys(input).join(",")}`);
|
|
455
|
+
return this.handlePermissionConfirm(toolName, input, options.toolUseID, options.signal, options.suggestions);
|
|
425
456
|
}
|
|
426
457
|
async handleAskUserQuestion(toolInput, toolUseID, signal) {
|
|
427
458
|
const questions = toolInput.questions || [];
|
|
@@ -440,7 +471,7 @@ export class ClaudeSession {
|
|
|
440
471
|
})),
|
|
441
472
|
toolUseId: toolUseID,
|
|
442
473
|
});
|
|
443
|
-
const answer = await this.waitForUser(this.pendingQuestions, signal, 120000, "skip");
|
|
474
|
+
const answer = await this.waitForUser(this.pendingQuestions, toolUseID, signal, 120000, "skip");
|
|
444
475
|
let answers = {};
|
|
445
476
|
try {
|
|
446
477
|
answers = JSON.parse(answer);
|
|
@@ -493,7 +524,7 @@ export class ClaudeSession {
|
|
|
493
524
|
options: permissionOptions,
|
|
494
525
|
suggestions: suggestions ?? null,
|
|
495
526
|
});
|
|
496
|
-
const result = await this.waitForUser(this.pendingPermissions, signal, 60000, { allow: false, allowAlways: false });
|
|
527
|
+
const result = await this.waitForUser(this.pendingPermissions, toolUseID, signal, 60000, { allow: false, allowAlways: false });
|
|
497
528
|
let sdkDecision;
|
|
498
529
|
if (result.allowAlways) {
|
|
499
530
|
this.alwaysAllowedTools.add(toolName);
|
|
@@ -674,7 +705,10 @@ export class ClaudeSession {
|
|
|
674
705
|
let outputTokens = 0;
|
|
675
706
|
if (msg.modelUsage) {
|
|
676
707
|
for (const m of Object.values(msg.modelUsage)) {
|
|
677
|
-
inputTokens +=
|
|
708
|
+
inputTokens +=
|
|
709
|
+
(m.inputTokens ?? 0) +
|
|
710
|
+
(m.cacheReadInputTokens ?? 0) +
|
|
711
|
+
(m.cacheCreationInputTokens ?? 0);
|
|
678
712
|
outputTokens += m.outputTokens ?? 0;
|
|
679
713
|
}
|
|
680
714
|
}
|
package/dist/cli.js
CHANGED
|
@@ -64,6 +64,11 @@ const optionDefinitions = {
|
|
|
64
64
|
type: "string",
|
|
65
65
|
describe: "Tee all logs to a file (default: ./ever-terminal-<ts>.log)",
|
|
66
66
|
},
|
|
67
|
+
model: {
|
|
68
|
+
alias: "m",
|
|
69
|
+
type: "string",
|
|
70
|
+
describe: "Claude model (default: claude-opus-4-8)",
|
|
71
|
+
},
|
|
67
72
|
verbose: {
|
|
68
73
|
type: "boolean",
|
|
69
74
|
describe: "Print raw SDK messages for debugging",
|
|
@@ -178,6 +183,8 @@ async function run(argv) {
|
|
|
178
183
|
process.env.PROJECT_DIR = resolve(argv.cwd);
|
|
179
184
|
if (argv.provider)
|
|
180
185
|
process.env.DEFAULT_PROVIDER = argv.provider;
|
|
186
|
+
if (argv.model)
|
|
187
|
+
process.env.CLAUDE_MODEL = argv.model;
|
|
181
188
|
if (argv.verbose)
|
|
182
189
|
process.env.VERBOSE = "1";
|
|
183
190
|
{
|
package/dist/routes/core.js
CHANGED
|
@@ -136,8 +136,8 @@ router.post("/prompt", async (req, res) => {
|
|
|
136
136
|
});
|
|
137
137
|
// POST /api/permission-response
|
|
138
138
|
router.post("/permission-response", (req, res) => {
|
|
139
|
-
const { sessionId, decision, provider } = req.body ?? {};
|
|
140
|
-
console.log(`[permission-response] sessionId=${sessionId ?? "(none)"} provider=${provider ?? "(default)"} decision=${decision ?? "deny"}`);
|
|
139
|
+
const { sessionId, decision, provider, toolUseId } = req.body ?? {};
|
|
140
|
+
console.log(`[permission-response] sessionId=${sessionId ?? "(none)"} provider=${provider ?? "(default)"} decision=${decision ?? "deny"} toolUseId=${toolUseId ?? "(none)"}`);
|
|
141
141
|
debugLog("api", "permission-response body", toOneLineJson(req.body ?? {}));
|
|
142
142
|
if (!sessionId) {
|
|
143
143
|
res.status(400).json({ error: "Missing 'sessionId'" });
|
|
@@ -148,13 +148,13 @@ router.post("/permission-response", (req, res) => {
|
|
|
148
148
|
res.status(404).json({ error: "Session not found" });
|
|
149
149
|
return;
|
|
150
150
|
}
|
|
151
|
-
targetProvider.respondPermission(sessionId, decision || "deny");
|
|
151
|
+
targetProvider.respondPermission(sessionId, decision || "deny", toolUseId);
|
|
152
152
|
res.json({ ok: true });
|
|
153
153
|
});
|
|
154
154
|
// POST /api/question-response
|
|
155
155
|
router.post("/question-response", (req, res) => {
|
|
156
|
-
const { sessionId, answer, provider } = req.body ?? {};
|
|
157
|
-
console.log(`[question-response] sessionId=${sessionId ?? "(none)"} provider=${provider ?? "(default)"} answer=${String(answer ?? "skip").slice(0, 120)}`);
|
|
156
|
+
const { sessionId, answer, provider, toolUseId } = req.body ?? {};
|
|
157
|
+
console.log(`[question-response] sessionId=${sessionId ?? "(none)"} provider=${provider ?? "(default)"} answer=${String(answer ?? "skip").slice(0, 120)} toolUseId=${toolUseId ?? "(none)"}`);
|
|
158
158
|
debugLog("api", "question-response body", toOneLineJson(req.body ?? {}));
|
|
159
159
|
if (!sessionId) {
|
|
160
160
|
res.status(400).json({ error: "Missing 'sessionId'" });
|
|
@@ -165,7 +165,7 @@ router.post("/question-response", (req, res) => {
|
|
|
165
165
|
res.status(404).json({ error: "Session not found" });
|
|
166
166
|
return;
|
|
167
167
|
}
|
|
168
|
-
targetProvider.respondQuestion(sessionId, answer || "skip");
|
|
168
|
+
targetProvider.respondQuestion(sessionId, answer || "skip", toolUseId);
|
|
169
169
|
res.json({ ok: true });
|
|
170
170
|
});
|
|
171
171
|
// POST /api/interrupt
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ever-terminal",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Ever Terminal — AI Coding CLI on Smart Glasses & Flutter App",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,29 +21,21 @@
|
|
|
21
21
|
"ever-terminal": "dist/cli.js"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
|
-
"dist/"
|
|
25
|
-
"!dist/index-evenhub.js",
|
|
26
|
-
"!dist/routes/audio.js",
|
|
27
|
-
"!dist/asr.js",
|
|
28
|
-
"!dist/at-file.js",
|
|
29
|
-
"!dist/startup/evenhub.js"
|
|
24
|
+
"dist/"
|
|
30
25
|
],
|
|
31
26
|
"scripts": {
|
|
32
27
|
"start": "tsx src/index.ts",
|
|
33
28
|
"dev": "tsx watch src/index.ts",
|
|
34
29
|
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
35
|
-
"build:evenhub": "rm -rf dist public && tsc -p tsconfig.build.json && pnpm run copy-frontend",
|
|
36
30
|
"build:bundle": "esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.mjs --packages=external",
|
|
37
31
|
"start:prod": "node dist/index.mjs",
|
|
38
|
-
"copy-frontend": "node -e \"const fs=require('fs');fs.cpSync('../frontend/dist','public',{recursive:true})\"",
|
|
39
32
|
"prepack": "pnpm run build",
|
|
40
|
-
"pack:evenhub": "V=$(node -p \"require('./package.json').version\") && pnpm run build:evenhub && node -e \"const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json','utf8'));p.files=['dist/','public/'];fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\\n');\" && pnpm pack --ignore-scripts && git checkout package.json && mv ever-terminal-$V.tgz ever-terminal-evenhub-$V.tgz",
|
|
41
33
|
"lint": "oxlint src",
|
|
42
34
|
"test": "node --import tsx --test \"src/**/*.test.ts\"",
|
|
43
35
|
"typecheck": "tsc --noEmit"
|
|
44
36
|
},
|
|
45
37
|
"engines": {
|
|
46
|
-
"node": ">=
|
|
38
|
+
"node": ">=22"
|
|
47
39
|
},
|
|
48
40
|
"dependencies": {
|
|
49
41
|
"@anthropic-ai/claude-agent-sdk": "^0.3.195",
|