@poping/yome 0.0.4 → 0.0.6
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/dist/commands/mesh.d.ts +15 -0
- package/dist/commands/mesh.js +282 -0
- package/dist/commands/mesh.js.map +1 -0
- package/dist/daemon/index.js +7 -2
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/systemd.d.ts +7 -0
- package/dist/daemon/systemd.js +87 -0
- package/dist/daemon/systemd.js.map +1 -0
- package/dist/index.js +29 -3
- package/dist/index.js.map +1 -1
- package/dist/llm.d.ts +14 -2
- package/dist/llm.js +266 -201
- package/dist/llm.js.map +1 -1
- package/dist/mesh/capabilities.d.ts +6 -0
- package/dist/mesh/capabilities.js +66 -0
- package/dist/mesh/capabilities.js.map +1 -0
- package/dist/mesh/device-id.d.ts +28 -0
- package/dist/mesh/device-id.js +105 -0
- package/dist/mesh/device-id.js.map +1 -0
- package/dist/mesh/device-registrar.d.ts +33 -0
- package/dist/mesh/device-registrar.js +131 -0
- package/dist/mesh/device-registrar.js.map +1 -0
- package/dist/mesh/index.d.ts +28 -0
- package/dist/mesh/index.js +71 -0
- package/dist/mesh/index.js.map +1 -0
- package/dist/mesh/partykit-client.d.ts +43 -0
- package/dist/mesh/partykit-client.js +195 -0
- package/dist/mesh/partykit-client.js.map +1 -0
- package/dist/mesh/rpc-handler.d.ts +28 -0
- package/dist/mesh/rpc-handler.js +201 -0
- package/dist/mesh/rpc-handler.js.map +1 -0
- package/dist/mesh/thread-stream.d.ts +109 -0
- package/dist/mesh/thread-stream.js +110 -0
- package/dist/mesh/thread-stream.js.map +1 -0
- package/dist/mesh/ticket.d.ts +33 -0
- package/dist/mesh/ticket.js +127 -0
- package/dist/mesh/ticket.js.map +1 -0
- package/dist/mesh/types.d.ts +83 -0
- package/dist/mesh/types.js +9 -0
- package/dist/mesh/types.js.map +1 -0
- package/dist/ui/MeshApp.d.ts +9 -0
- package/dist/ui/MeshApp.js +226 -0
- package/dist/ui/MeshApp.js.map +1 -0
- package/dist/withRetry.d.ts +14 -0
- package/dist/withRetry.js +106 -0
- package/dist/withRetry.js.map +1 -0
- package/dist/yomeSkills/cli.d.ts +5 -1
- package/dist/yomeSkills/cli.js +24 -2
- package/dist/yomeSkills/cli.js.map +1 -1
- package/dist/yomeSkills/webLogin.d.ts +37 -0
- package/dist/yomeSkills/webLogin.js +114 -0
- package/dist/yomeSkills/webLogin.js.map +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-stream.js","sourceRoot":"","sources":["../../src/mesh/thread-stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { WsTicketResponse } from './types.js';
|
|
2
|
+
export declare class MintTicketError extends Error {
|
|
3
|
+
code: string;
|
|
4
|
+
httpStatus?: number | undefined;
|
|
5
|
+
constructor(message: string, code: string, httpStatus?: number | undefined);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Request a fresh WS ticket. The caller is responsible for caching
|
|
9
|
+
* (TicketCache below). Throws MintTicketError on any failure.
|
|
10
|
+
*/
|
|
11
|
+
export declare function mintWsTicket(opts?: {
|
|
12
|
+
hubBase?: string;
|
|
13
|
+
fetcher?: typeof fetch;
|
|
14
|
+
cliVersion?: string;
|
|
15
|
+
}): Promise<WsTicketResponse>;
|
|
16
|
+
/**
|
|
17
|
+
* Tiny in-memory cache that proactively refreshes the ticket before it
|
|
18
|
+
* expires. Owned by the long-running mesh daemon process. NOT persisted
|
|
19
|
+
* to disk — short-lived JWTs are deliberately ephemeral.
|
|
20
|
+
*
|
|
21
|
+
* Refresh strategy: re-mint when ≤ 60s remains. PartyKit only checks
|
|
22
|
+
* the JWT at WS handshake time (not per message), so we don't strictly
|
|
23
|
+
* need to refresh during a live connection — but we cache for reconnects.
|
|
24
|
+
*/
|
|
25
|
+
export declare class TicketCache {
|
|
26
|
+
private mintFn;
|
|
27
|
+
private current;
|
|
28
|
+
private expiresAtMs;
|
|
29
|
+
private inflight;
|
|
30
|
+
constructor(mintFn?: () => Promise<WsTicketResponse>);
|
|
31
|
+
get(): Promise<WsTicketResponse>;
|
|
32
|
+
invalidate(): void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// PAT → short-lived WS ticket exchange.
|
|
2
|
+
//
|
|
3
|
+
// We hold a long-lived opaque `yome_token` (from `yome login`) on disk
|
|
4
|
+
// and use it to mint short-lived JWTs that PartyKit can verify with the
|
|
5
|
+
// existing Supabase-JWT HS256 path. This is the same pattern GitHub
|
|
6
|
+
// CLI / Vercel CLI / Supabase CLI use: never put a service-grade JWT
|
|
7
|
+
// or refresh_token on disk; only ever hold a revocable PAT.
|
|
8
|
+
//
|
|
9
|
+
// See cli/MIGRATION.md "Auth design" for the full rationale.
|
|
10
|
+
import { readAuthState } from '../yomeSkills/auth.js';
|
|
11
|
+
import { getHubBase } from '../yomeSkills/login.js';
|
|
12
|
+
import { getOrCreateDeviceId, safeHostname, currentPlatform } from './device-id.js';
|
|
13
|
+
const TICKET_ENDPOINT_PATH = '/api/cli/mesh/ws-ticket';
|
|
14
|
+
/** Stable User-Agent for hub logs. */
|
|
15
|
+
function userAgent() {
|
|
16
|
+
// Bumping is fine; this is a label, not a contract.
|
|
17
|
+
return `yome-cli/0.x mesh/1 ${currentPlatform()}`;
|
|
18
|
+
}
|
|
19
|
+
export class MintTicketError extends Error {
|
|
20
|
+
code;
|
|
21
|
+
httpStatus;
|
|
22
|
+
constructor(message, code, httpStatus) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.code = code;
|
|
25
|
+
this.httpStatus = httpStatus;
|
|
26
|
+
this.name = 'MintTicketError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Request a fresh WS ticket. The caller is responsible for caching
|
|
31
|
+
* (TicketCache below). Throws MintTicketError on any failure.
|
|
32
|
+
*/
|
|
33
|
+
export async function mintWsTicket(opts = {}) {
|
|
34
|
+
const auth = readAuthState();
|
|
35
|
+
if (!auth?.yome_token) {
|
|
36
|
+
throw new MintTicketError('Not logged in. Run `yome login` first.', 'not_logged_in');
|
|
37
|
+
}
|
|
38
|
+
const hubBase = (opts.hubBase ?? getHubBase()).replace(/\/+$/, '');
|
|
39
|
+
const fetcher = opts.fetcher ?? fetch;
|
|
40
|
+
const body = {
|
|
41
|
+
deviceId: getOrCreateDeviceId(),
|
|
42
|
+
hostname: safeHostname(),
|
|
43
|
+
platform: currentPlatform(),
|
|
44
|
+
cliVersion: opts.cliVersion,
|
|
45
|
+
};
|
|
46
|
+
const controller = new AbortController();
|
|
47
|
+
const timer = setTimeout(() => controller.abort(), 30_000);
|
|
48
|
+
let resp;
|
|
49
|
+
try {
|
|
50
|
+
resp = await fetcher(`${hubBase}${TICKET_ENDPOINT_PATH}`, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers: {
|
|
53
|
+
'Content-Type': 'application/json',
|
|
54
|
+
'Authorization': `Bearer ${auth.yome_token}`,
|
|
55
|
+
'User-Agent': userAgent(),
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify(body),
|
|
58
|
+
signal: controller.signal,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
throw new MintTicketError(`Network error contacting hub: ${err.message}`, 'network');
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
clearTimeout(timer);
|
|
66
|
+
}
|
|
67
|
+
let json;
|
|
68
|
+
try {
|
|
69
|
+
json = await resp.json();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
throw new MintTicketError(`Hub returned non-JSON (HTTP ${resp.status}).`, 'bad_response', resp.status);
|
|
73
|
+
}
|
|
74
|
+
if (!resp.ok || !json.ok) {
|
|
75
|
+
const e = json;
|
|
76
|
+
throw new MintTicketError(e.error ?? `Hub rejected ticket request (HTTP ${resp.status}).`, e.code ?? 'hub_error', resp.status);
|
|
77
|
+
}
|
|
78
|
+
const ok = json;
|
|
79
|
+
if (!ok.ws_token || !ok.userId || !ok.partykit_host) {
|
|
80
|
+
throw new MintTicketError('Hub response missing required fields (ws_token / userId / partykit_host).', 'bad_response', resp.status);
|
|
81
|
+
}
|
|
82
|
+
return ok;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Tiny in-memory cache that proactively refreshes the ticket before it
|
|
86
|
+
* expires. Owned by the long-running mesh daemon process. NOT persisted
|
|
87
|
+
* to disk — short-lived JWTs are deliberately ephemeral.
|
|
88
|
+
*
|
|
89
|
+
* Refresh strategy: re-mint when ≤ 60s remains. PartyKit only checks
|
|
90
|
+
* the JWT at WS handshake time (not per message), so we don't strictly
|
|
91
|
+
* need to refresh during a live connection — but we cache for reconnects.
|
|
92
|
+
*/
|
|
93
|
+
export class TicketCache {
|
|
94
|
+
mintFn;
|
|
95
|
+
current = null;
|
|
96
|
+
expiresAtMs = 0;
|
|
97
|
+
inflight = null;
|
|
98
|
+
constructor(mintFn = mintWsTicket) {
|
|
99
|
+
this.mintFn = mintFn;
|
|
100
|
+
}
|
|
101
|
+
async get() {
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
const safetyWindowMs = 60_000;
|
|
104
|
+
if (this.current && now < this.expiresAtMs - safetyWindowMs) {
|
|
105
|
+
return this.current;
|
|
106
|
+
}
|
|
107
|
+
if (this.inflight)
|
|
108
|
+
return this.inflight;
|
|
109
|
+
this.inflight = (async () => {
|
|
110
|
+
const fresh = await this.mintFn();
|
|
111
|
+
this.current = fresh;
|
|
112
|
+
this.expiresAtMs = Date.now() + fresh.expires_in * 1000;
|
|
113
|
+
return fresh;
|
|
114
|
+
})();
|
|
115
|
+
try {
|
|
116
|
+
return await this.inflight;
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
this.inflight = null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
invalidate() {
|
|
123
|
+
this.current = null;
|
|
124
|
+
this.expiresAtMs = 0;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=ticket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ticket.js","sourceRoot":"","sources":["../../src/mesh/ticket.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export type CommandDomain = 'bash' | 'fs' | 'git' | 'docker' | 'k8s' | 'systemd' | 'pkg' | 'log' | 'net' | 'svc' | 'cal' | 'rem' | 'note' | 'xl' | 'ppt' | 'doc' | 'kn' | 'num' | 'pg' | 'web' | 'mind' | 'term' | 'lark' | 'ps' | 'sp' | 'notif' | 'chat' | 'app' | 'cur' | 'cap' | 'wf' | 'watch';
|
|
2
|
+
export interface WsDeviceRegister {
|
|
3
|
+
type: 'mesh:register';
|
|
4
|
+
hostname: string;
|
|
5
|
+
model: string;
|
|
6
|
+
capabilities: string[];
|
|
7
|
+
installedApps: string[];
|
|
8
|
+
alias?: string;
|
|
9
|
+
deviceDescription?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface WsDeviceUpdate {
|
|
12
|
+
type: 'mesh:update-device';
|
|
13
|
+
deviceId?: string;
|
|
14
|
+
alias?: string;
|
|
15
|
+
deviceDescription?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface WsHeartbeat {
|
|
18
|
+
type: 'mesh:heartbeat';
|
|
19
|
+
deviceId: string;
|
|
20
|
+
}
|
|
21
|
+
export interface WsRpcResponse {
|
|
22
|
+
type: 'rpc:cal-response';
|
|
23
|
+
requestId: string;
|
|
24
|
+
stdout: string;
|
|
25
|
+
stderr: string;
|
|
26
|
+
exitCode: number;
|
|
27
|
+
}
|
|
28
|
+
export type WsClientFrame = WsDeviceRegister | WsDeviceUpdate | WsHeartbeat | WsRpcResponse;
|
|
29
|
+
export interface WsConnected {
|
|
30
|
+
type: 'connected';
|
|
31
|
+
clientType: 'ios' | 'mac' | 'web' | 'desktop';
|
|
32
|
+
userId: string;
|
|
33
|
+
}
|
|
34
|
+
export interface WsRpcRequest {
|
|
35
|
+
type: 'rpc:cal-request';
|
|
36
|
+
requestId: string;
|
|
37
|
+
command: string;
|
|
38
|
+
parsed: {
|
|
39
|
+
domain: CommandDomain;
|
|
40
|
+
action: string;
|
|
41
|
+
args: Record<string, string>;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export interface WsDeviceUpdated {
|
|
45
|
+
type: 'device-updated';
|
|
46
|
+
devices: Array<{
|
|
47
|
+
deviceId: string;
|
|
48
|
+
userId: string;
|
|
49
|
+
hostname: string;
|
|
50
|
+
model: string;
|
|
51
|
+
status: 'online' | 'busy' | 'offline';
|
|
52
|
+
capabilities: string[];
|
|
53
|
+
installedApps: string[];
|
|
54
|
+
currentTask?: string;
|
|
55
|
+
lastHeartbeat: number;
|
|
56
|
+
alias?: string;
|
|
57
|
+
deviceDescription?: string;
|
|
58
|
+
}>;
|
|
59
|
+
}
|
|
60
|
+
export type WsServerFrame = WsConnected | WsRpcRequest | WsDeviceUpdated | {
|
|
61
|
+
type: string;
|
|
62
|
+
[k: string]: unknown;
|
|
63
|
+
};
|
|
64
|
+
export interface WsTicketRequest {
|
|
65
|
+
deviceId: string;
|
|
66
|
+
hostname: string;
|
|
67
|
+
platform: 'linux' | 'darwin' | 'win32' | string;
|
|
68
|
+
/** Optional cli version string for hub-side analytics. */
|
|
69
|
+
cliVersion?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface WsTicketResponse {
|
|
72
|
+
ok: boolean;
|
|
73
|
+
/** Short-lived JWT (HS256 by Supabase JWT secret), sub=userId, aud=partykit. */
|
|
74
|
+
ws_token: string;
|
|
75
|
+
/** Seconds until ws_token expires. */
|
|
76
|
+
expires_in: number;
|
|
77
|
+
userId: string;
|
|
78
|
+
deviceId: string;
|
|
79
|
+
/** Host + room hint. e.g. "yome.party.yome.work". Room id is userId. */
|
|
80
|
+
partykit_host: string;
|
|
81
|
+
error?: string;
|
|
82
|
+
code?: string;
|
|
83
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Mesh wire-protocol types.
|
|
2
|
+
//
|
|
3
|
+
// Mirror of the relevant subset of `Server/agent/types.ts` so that
|
|
4
|
+
// cli ↔ PartyKit speak the same JSON frames as iOS / macOS already do.
|
|
5
|
+
// Kept manually-maintained (not generated) because cli is a separate npm
|
|
6
|
+
// package and we want this protocol surface to be stable + reviewable as
|
|
7
|
+
// part of the cli PR.
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/mesh/types.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,EAAE;AACF,mEAAmE;AACnE,uEAAuE;AACvE,yEAAyE;AACzE,yEAAyE;AACzE,sBAAsB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { MeshDaemon } from '../mesh/index.js';
|
|
3
|
+
interface MeshAppProps {
|
|
4
|
+
daemon: MeshDaemon;
|
|
5
|
+
/** Override initial thread (e.g. resume). Otherwise server picks. */
|
|
6
|
+
initialThreadId?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function MeshApp({ daemon, initialThreadId }: MeshAppProps): React.ReactElement;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// MeshApp — Ink TUI that participates in a Yome thread as a thin client.
|
|
3
|
+
//
|
|
4
|
+
// This is the cli analogue of macOS Yome.app / iOS Yome's chat surface:
|
|
5
|
+
// - it owns NO local agent loop
|
|
6
|
+
// - it does NO LLM call
|
|
7
|
+
// - every keystroke that "submits" becomes a `{type:'message'}` ws frame
|
|
8
|
+
// - every render comes from PartyKit-broadcast events
|
|
9
|
+
//
|
|
10
|
+
// Mounted by `yome mesh start --tui`: the mesh daemon is already running
|
|
11
|
+
// (PartyKitClient + DeviceRegistrar + RpcHandler), so we just plug a
|
|
12
|
+
// ThreadStream into the same client.
|
|
13
|
+
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
14
|
+
import { Box, Text, useApp, useInput } from 'ink';
|
|
15
|
+
import { MessageList, getToolLabel, getToolDetail } from './MessageList.js';
|
|
16
|
+
import { InputBar } from './InputBar.js';
|
|
17
|
+
import { ThreadStream } from '../mesh/thread-stream.js';
|
|
18
|
+
let _msgIdSeq = 0;
|
|
19
|
+
const nextMsgId = () => ++_msgIdSeq;
|
|
20
|
+
export function MeshApp({ daemon, initialThreadId }) {
|
|
21
|
+
const { exit } = useApp();
|
|
22
|
+
const [messages, setMessages] = useState([]);
|
|
23
|
+
const [streamText, setStreamText] = useState('');
|
|
24
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
25
|
+
const [inputValue, setInputValue] = useState('');
|
|
26
|
+
const [threadId, setThreadId] = useState(initialThreadId);
|
|
27
|
+
const [deviceCount, setDeviceCount] = useState(0);
|
|
28
|
+
// Stable references across renders.
|
|
29
|
+
const streamRef = useRef(null);
|
|
30
|
+
// Buffer in-flight text deltas keyed by runId so concurrent runs
|
|
31
|
+
// (rare but possible if the user has 2 threads open via iOS) don't
|
|
32
|
+
// smear into each other.
|
|
33
|
+
const liveTextByRunRef = useRef(new Map());
|
|
34
|
+
// Tool-use id -> message id so a later `agent:tool-result` can
|
|
35
|
+
// mutate the right tool_start row (mark `done: true`).
|
|
36
|
+
const toolMsgIdByUseRef = useRef(new Map());
|
|
37
|
+
const pushMessage = useCallback((msg) => {
|
|
38
|
+
const m = { ...msg, id: msg.id ?? nextMsgId() };
|
|
39
|
+
setMessages((prev) => [...prev, m]);
|
|
40
|
+
return m.id;
|
|
41
|
+
}, []);
|
|
42
|
+
const markToolDone = useCallback((toolUseId) => {
|
|
43
|
+
const msgId = toolMsgIdByUseRef.current.get(toolUseId);
|
|
44
|
+
if (msgId == null)
|
|
45
|
+
return;
|
|
46
|
+
setMessages((prev) => prev.map((m) => (m.id === msgId ? { ...m, done: true } : m)));
|
|
47
|
+
}, []);
|
|
48
|
+
const handleEvent = useCallback((event) => {
|
|
49
|
+
switch (event.type) {
|
|
50
|
+
case 'thread:sync':
|
|
51
|
+
case 'thread:created': {
|
|
52
|
+
const next = event.threadId;
|
|
53
|
+
if (typeof next === 'string')
|
|
54
|
+
setThreadId(next);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
case 'thread:user-message': {
|
|
58
|
+
// Echo of another device sending a user-message into this
|
|
59
|
+
// thread (e.g. iOS user typed). The server already excludes the
|
|
60
|
+
// sending connection, so seeing this here means "someone else
|
|
61
|
+
// talked".
|
|
62
|
+
const content = String(event.content ?? '');
|
|
63
|
+
if (content)
|
|
64
|
+
pushMessage({ type: 'user', content });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
case 'agent:start': {
|
|
68
|
+
setIsRunning(true);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
case 'agent:user-message': {
|
|
72
|
+
// Server-confirmed user message (echoed back including our own).
|
|
73
|
+
// We rely on `thread:user-message` for cross-device echoes and
|
|
74
|
+
// do NOT also render this — otherwise users see duplicates.
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
case 'agent:text-delta': {
|
|
78
|
+
const { runId, delta } = event;
|
|
79
|
+
if (!delta)
|
|
80
|
+
return;
|
|
81
|
+
const buf = liveTextByRunRef.current.get(runId);
|
|
82
|
+
if (!buf) {
|
|
83
|
+
const id = nextMsgId();
|
|
84
|
+
liveTextByRunRef.current.set(runId, { msgId: id, text: delta });
|
|
85
|
+
setStreamText(delta);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
buf.text += delta;
|
|
89
|
+
setStreamText(buf.text);
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
case 'agent:text-done': {
|
|
94
|
+
const { runId, fullText } = event;
|
|
95
|
+
const buf = liveTextByRunRef.current.get(runId);
|
|
96
|
+
const final = fullText ?? buf?.text ?? '';
|
|
97
|
+
if (final) {
|
|
98
|
+
pushMessage({ type: 'text', content: final, id: buf?.msgId });
|
|
99
|
+
}
|
|
100
|
+
liveTextByRunRef.current.delete(runId);
|
|
101
|
+
setStreamText('');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
case 'agent:tool-use': {
|
|
105
|
+
const { toolUseId, name, input } = event;
|
|
106
|
+
const id = nextMsgId();
|
|
107
|
+
toolMsgIdByUseRef.current.set(toolUseId, id);
|
|
108
|
+
const label = getToolLabel(name);
|
|
109
|
+
const summary = getToolDetail(name, input ?? {});
|
|
110
|
+
pushMessage({
|
|
111
|
+
type: 'tool_start',
|
|
112
|
+
content: '',
|
|
113
|
+
toolName: name,
|
|
114
|
+
toolLabel: label,
|
|
115
|
+
toolSummary: summary,
|
|
116
|
+
done: false,
|
|
117
|
+
id,
|
|
118
|
+
});
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
case 'agent:tool-result': {
|
|
122
|
+
const { toolUseId, exitCode, result } = event;
|
|
123
|
+
markToolDone(toolUseId);
|
|
124
|
+
const name = (() => {
|
|
125
|
+
// Recover tool name from the matching tool_start row to keep
|
|
126
|
+
// ToolResult formatting consistent.
|
|
127
|
+
const msgId = toolMsgIdByUseRef.current.get(toolUseId);
|
|
128
|
+
if (msgId == null)
|
|
129
|
+
return '';
|
|
130
|
+
const m = (messagesRef.current ?? []).find((mm) => mm.id === msgId);
|
|
131
|
+
return m?.toolName ?? '';
|
|
132
|
+
})();
|
|
133
|
+
if (result) {
|
|
134
|
+
pushMessage({ type: 'tool_result', toolName: name, content: result });
|
|
135
|
+
}
|
|
136
|
+
if (exitCode !== 0) {
|
|
137
|
+
pushMessage({ type: 'error', content: `tool exited ${exitCode}` });
|
|
138
|
+
}
|
|
139
|
+
toolMsgIdByUseRef.current.delete(toolUseId);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
case 'agent:done': {
|
|
143
|
+
setIsRunning(false);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
case 'agent:error': {
|
|
147
|
+
const msg = String(event.message ?? 'unknown error');
|
|
148
|
+
pushMessage({ type: 'error', content: msg });
|
|
149
|
+
setIsRunning(false);
|
|
150
|
+
setStreamText('');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
case 'agent:retry': {
|
|
154
|
+
// Surface as a dim hint, not a hard error.
|
|
155
|
+
const attempt = event.attempt;
|
|
156
|
+
pushMessage({ type: 'error', content: `(retrying${attempt ? ` #${attempt}` : ''}…)` });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
case 'agent:quota-exceeded': {
|
|
160
|
+
const reason = String(event.reason ?? 'quota exceeded');
|
|
161
|
+
pushMessage({ type: 'error', content: `quota: ${reason}` });
|
|
162
|
+
setIsRunning(false);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
case 'device-updated': {
|
|
166
|
+
const devs = event.devices ?? [];
|
|
167
|
+
setDeviceCount(Array.isArray(devs) ? devs.length : 0);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
default:
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}, [pushMessage, markToolDone]);
|
|
174
|
+
// Keep a ref to the latest messages so the tool-result handler above
|
|
175
|
+
// can look up the matching tool_start name without re-binding the
|
|
176
|
+
// event callback on every state change.
|
|
177
|
+
const messagesRef = useRef(messages);
|
|
178
|
+
useEffect(() => { messagesRef.current = messages; }, [messages]);
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
const stream = new ThreadStream({
|
|
181
|
+
client: daemon.client,
|
|
182
|
+
initialThreadId,
|
|
183
|
+
});
|
|
184
|
+
stream.start();
|
|
185
|
+
const off = stream.on(handleEvent);
|
|
186
|
+
streamRef.current = stream;
|
|
187
|
+
return () => {
|
|
188
|
+
off();
|
|
189
|
+
stream.stop();
|
|
190
|
+
streamRef.current = null;
|
|
191
|
+
};
|
|
192
|
+
}, [daemon, initialThreadId, handleEvent]);
|
|
193
|
+
const handleSubmit = useCallback(async (raw) => {
|
|
194
|
+
const value = raw.trim();
|
|
195
|
+
if (!value)
|
|
196
|
+
return;
|
|
197
|
+
setInputValue('');
|
|
198
|
+
pushMessage({ type: 'user', content: value });
|
|
199
|
+
setIsRunning(true);
|
|
200
|
+
try {
|
|
201
|
+
await streamRef.current?.sendUserMessage(value);
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
pushMessage({ type: 'error', content: `send failed: ${err.message}` });
|
|
205
|
+
setIsRunning(false);
|
|
206
|
+
}
|
|
207
|
+
}, [pushMessage]);
|
|
208
|
+
// Ctrl-C twice or `/exit` to leave. First Ctrl-C clears input; second
|
|
209
|
+
// exits. Matches what App.tsx does so muscle memory survives.
|
|
210
|
+
const ctrlCRef = useRef(0);
|
|
211
|
+
useInput((input, key) => {
|
|
212
|
+
if (key.ctrl && (input === 'c' || input === 'C')) {
|
|
213
|
+
const now = Date.now();
|
|
214
|
+
if (now - ctrlCRef.current < 1500 || inputValue.length === 0) {
|
|
215
|
+
exit();
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
ctrlCRef.current = now;
|
|
219
|
+
setInputValue('');
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
const loopName = threadId ? `mesh • ${threadId.slice(0, 8)}` : 'mesh';
|
|
223
|
+
const banner = `${deviceCount > 0 ? `${deviceCount} devices online` : 'connecting…'}`;
|
|
224
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: "#E87B35", bold: true, children: "Yome mesh " }), _jsxs(Text, { dimColor: true, children: ["\u2014 ", banner] })] }), _jsx(MessageList, { messages: messages, streamText: streamText, isRunning: isRunning }), _jsx(InputBar, { value: inputValue, onChange: setInputValue, onSubmit: handleSubmit, loopName: loopName })] }));
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=MeshApp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MeshApp.js","sourceRoot":"","sources":["../../src/ui/MeshApp.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface RetryNotice {
|
|
2
|
+
attempt: number;
|
|
3
|
+
maxRetries: number;
|
|
4
|
+
delayMs: number;
|
|
5
|
+
error: string;
|
|
6
|
+
}
|
|
7
|
+
export interface RetryOptions {
|
|
8
|
+
maxRetries?: number;
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
onRetryNotice?: (n: RetryNotice) => void;
|
|
11
|
+
label?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function isRetryableError(err: unknown): boolean;
|
|
14
|
+
export declare function withRetry<T>(operation: (attempt: number) => Promise<T>, opts?: RetryOptions): Promise<T>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// withRetry.ts — exponential-backoff retry for LLM/API calls.
|
|
2
|
+
// Mirrors Server/agent/withRetry.ts. Kept in-tree so the CLI stays a
|
|
3
|
+
// self-contained npm package with no cross-repo imports.
|
|
4
|
+
const BASE_DELAY_MS = 500;
|
|
5
|
+
const MAX_DELAY_MS = 32_000;
|
|
6
|
+
const DEFAULT_MAX_RETRIES = 4;
|
|
7
|
+
function extractStatus(msg) {
|
|
8
|
+
const m = msg.match(/API error (\d+)/);
|
|
9
|
+
if (!m)
|
|
10
|
+
return null;
|
|
11
|
+
const s = parseInt(m[1], 10);
|
|
12
|
+
return Number.isFinite(s) ? s : null;
|
|
13
|
+
}
|
|
14
|
+
function extractRetryAfterMs(msg) {
|
|
15
|
+
const m = msg.match(/retry[-\s]?after[:\s]+(\d+)/i);
|
|
16
|
+
if (!m)
|
|
17
|
+
return null;
|
|
18
|
+
const sec = parseInt(m[1], 10);
|
|
19
|
+
return Number.isFinite(sec) ? sec * 1000 : null;
|
|
20
|
+
}
|
|
21
|
+
export function isRetryableError(err) {
|
|
22
|
+
if (!err)
|
|
23
|
+
return false;
|
|
24
|
+
if (err instanceof Error && err.name === 'AbortError')
|
|
25
|
+
return false;
|
|
26
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
27
|
+
if (err instanceof Error && err.name === 'StreamIdleTimeoutError')
|
|
28
|
+
return true;
|
|
29
|
+
if (/Stream idle timeout/i.test(msg))
|
|
30
|
+
return true;
|
|
31
|
+
const status = extractStatus(msg);
|
|
32
|
+
if (status !== null) {
|
|
33
|
+
if (status === 408 || status === 409 || status === 429)
|
|
34
|
+
return true;
|
|
35
|
+
if (status >= 500)
|
|
36
|
+
return true;
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if (/ECONNRESET|EPIPE|ETIMEDOUT|ENOTFOUND|ECONNREFUSED|EAI_AGAIN/i.test(msg) ||
|
|
40
|
+
/socket hang up|socket disconnected|network[_ ]?error|fetch failed|terminated/i.test(msg) ||
|
|
41
|
+
/other side closed|premature close/i.test(msg)) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
function getDelayMs(attempt, msg) {
|
|
47
|
+
const retryAfter = extractRetryAfterMs(msg);
|
|
48
|
+
if (retryAfter !== null)
|
|
49
|
+
return Math.min(retryAfter, MAX_DELAY_MS);
|
|
50
|
+
const base = Math.min(BASE_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);
|
|
51
|
+
const jitter = Math.random() * 0.25 * base;
|
|
52
|
+
return Math.round(base + jitter);
|
|
53
|
+
}
|
|
54
|
+
function isAborted(signal) {
|
|
55
|
+
return !!signal?.aborted;
|
|
56
|
+
}
|
|
57
|
+
function sleep(ms, signal) {
|
|
58
|
+
return new Promise((resolve, reject) => {
|
|
59
|
+
if (isAborted(signal)) {
|
|
60
|
+
reject(new Error('aborted'));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const t = setTimeout(() => {
|
|
64
|
+
if (signal)
|
|
65
|
+
signal.removeEventListener('abort', onAbort);
|
|
66
|
+
resolve();
|
|
67
|
+
}, ms);
|
|
68
|
+
const onAbort = () => {
|
|
69
|
+
clearTimeout(t);
|
|
70
|
+
reject(new Error('aborted'));
|
|
71
|
+
};
|
|
72
|
+
if (signal)
|
|
73
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
export async function withRetry(operation, opts = {}) {
|
|
77
|
+
const max = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
78
|
+
const label = opts.label ?? 'llm';
|
|
79
|
+
let last;
|
|
80
|
+
for (let attempt = 1; attempt <= max + 1; attempt++) {
|
|
81
|
+
if (isAborted(opts.signal))
|
|
82
|
+
throw new Error('aborted');
|
|
83
|
+
try {
|
|
84
|
+
return await operation(attempt);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
last = err;
|
|
88
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
89
|
+
if (isAborted(opts.signal))
|
|
90
|
+
throw err;
|
|
91
|
+
if (attempt > max || !isRetryableError(err))
|
|
92
|
+
throw err;
|
|
93
|
+
const delayMs = getDelayMs(attempt, msg);
|
|
94
|
+
console.warn(`[withRetry:${label}] attempt ${attempt}/${max + 1} failed: ${msg} — retrying in ${delayMs}ms`);
|
|
95
|
+
opts.onRetryNotice?.({ attempt, maxRetries: max, delayMs, error: msg });
|
|
96
|
+
try {
|
|
97
|
+
await sleep(delayMs, opts.signal);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
throw last;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=withRetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withRetry.js","sourceRoot":"","sources":["../src/withRetry.ts"],"names":[],"mappings":"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"}
|