u1s1-cli 1.14.1 → 1.14.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/dist/device-auth.d.ts +16 -0
- package/dist/device-auth.js +38 -1
- package/dist/index.js +3 -1
- package/dist/telemetry.d.ts +2 -2
- package/package.json +1 -1
package/dist/device-auth.d.ts
CHANGED
|
@@ -54,6 +54,22 @@ interface SigningProxy {
|
|
|
54
54
|
/** Attach a fresh (self-healing) attestation header to an outbound proxy request. */
|
|
55
55
|
export declare function attachAttestationHeader(holder: AttestationHolder, headers: Headers): Promise<void>;
|
|
56
56
|
export type ClientSurface = "terminal" | "web" | "desktop" | "cloud";
|
|
57
|
+
/** What a failed gateway fetch looked like at the socket level; never carries request content. */
|
|
58
|
+
export interface GatewayFetchFailure {
|
|
59
|
+
/** Node/undici error code such as ECONNRESET or UND_ERR_CONNECT_TIMEOUT; "unknown" when absent. */
|
|
60
|
+
code: string;
|
|
61
|
+
/** One-line message for the user and the retry classifier, e.g. "fetch failed (ECONNRESET: read ECONNRESET)". */
|
|
62
|
+
detail: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* undici reports every transport failure as a bare "fetch failed" and puts the
|
|
66
|
+
* real reason (reset, DNS, TLS, connect timeout) in `cause`, sometimes as an
|
|
67
|
+
* AggregateError from happy eyeballs. Keep the original message first so the
|
|
68
|
+
* agent's retry patterns still match.
|
|
69
|
+
*/
|
|
70
|
+
export declare function describeFetchFailure(error: unknown): GatewayFetchFailure;
|
|
71
|
+
/** One listener per process (telemetry); failures are reported only when the local caller is still waiting. */
|
|
72
|
+
export declare function onGatewayFetchFailure(listener: ((failure: GatewayFetchFailure) => void) | undefined): void;
|
|
57
73
|
/**
|
|
58
74
|
* pi accepts static provider headers only. Keep it behind a loopback proxy that
|
|
59
75
|
* replaces the local bearer credential with a fresh DPoP proof per request.
|
package/dist/device-auth.js
CHANGED
|
@@ -209,6 +209,36 @@ function clientSurface(fallback) {
|
|
|
209
209
|
}
|
|
210
210
|
return process.versions.electron ? "desktop" : fallback;
|
|
211
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* undici reports every transport failure as a bare "fetch failed" and puts the
|
|
214
|
+
* real reason (reset, DNS, TLS, connect timeout) in `cause`, sometimes as an
|
|
215
|
+
* AggregateError from happy eyeballs. Keep the original message first so the
|
|
216
|
+
* agent's retry patterns still match.
|
|
217
|
+
*/
|
|
218
|
+
export function describeFetchFailure(error) {
|
|
219
|
+
const message = error instanceof Error ? error.message : "signing proxy failed";
|
|
220
|
+
let cause = error instanceof Error ? error.cause : undefined;
|
|
221
|
+
if (cause instanceof AggregateError && cause.errors.length)
|
|
222
|
+
cause = cause.errors[0];
|
|
223
|
+
const causeRecord = typeof cause === "object" && cause !== null ? cause : {};
|
|
224
|
+
const code = typeof causeRecord.code === "string" && causeRecord.code
|
|
225
|
+
? causeRecord.code
|
|
226
|
+
: typeof error?.code === "string"
|
|
227
|
+
? error.code
|
|
228
|
+
: "unknown";
|
|
229
|
+
const causeMessage = typeof causeRecord.message === "string" ? causeRecord.message.split("\n")[0].slice(0, 200) : "";
|
|
230
|
+
if (!causeMessage && code === "unknown")
|
|
231
|
+
return { code, detail: message };
|
|
232
|
+
const reason = causeMessage && !causeMessage.includes(code) && code !== "unknown"
|
|
233
|
+
? `${code}: ${causeMessage}`
|
|
234
|
+
: causeMessage || code;
|
|
235
|
+
return { code, detail: `${message} (${reason})` };
|
|
236
|
+
}
|
|
237
|
+
let gatewayFetchFailureListener;
|
|
238
|
+
/** One listener per process (telemetry); failures are reported only when the local caller is still waiting. */
|
|
239
|
+
export function onGatewayFetchFailure(listener) {
|
|
240
|
+
gatewayFetchFailureListener = listener;
|
|
241
|
+
}
|
|
212
242
|
/**
|
|
213
243
|
* pi accepts static provider headers only. Keep it behind a loopback proxy that
|
|
214
244
|
* replaces the local bearer credential with a fresh DPoP proof per request.
|
|
@@ -289,7 +319,14 @@ export async function ensureSigningProxy(cfg, fallbackClient = "terminal", attes
|
|
|
289
319
|
res.writeHead(502, { "content-type": "application/json" });
|
|
290
320
|
// 说明放前面给用户看;原始英文错误保留在括号里,pi 的重试分类正则
|
|
291
321
|
// (fetch failed / timeout 等)和排查都还认得
|
|
292
|
-
const
|
|
322
|
+
const failure = describeFetchFailure(error);
|
|
323
|
+
try {
|
|
324
|
+
gatewayFetchFailureListener?.(failure);
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
// Diagnostics must never change the response the agent sees.
|
|
328
|
+
}
|
|
329
|
+
const raw = failure.detail;
|
|
293
330
|
const message = tr(`连不上 u1s1 服务器,检查一下网络?(${raw})`, `Can't reach the u1s1 server. Check your network? (${raw})`);
|
|
294
331
|
res.end(JSON.stringify({ error: { message } }));
|
|
295
332
|
}
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { ensureSearchTools } from "./search-tools.js";
|
|
|
10
10
|
import { ensureUsableShell } from "./shell-doctor.js";
|
|
11
11
|
import { applyBrandUi, setAnnouncement, setUpdateNotice } from "./style.js";
|
|
12
12
|
import { AccessDeniedError, AuthError, fetchModels, loadCustomEndpoints, readJsonResponseCapped } from "./api.js";
|
|
13
|
-
import { ensureSigningProxy } from "./device-auth.js";
|
|
13
|
+
import { ensureSigningProxy, onGatewayFetchFailure } from "./device-auth.js";
|
|
14
14
|
import { installChildEnvGuard } from "./secret-env.js";
|
|
15
15
|
import { deployHintText, markNudge, shouldShowDeployHint } from "./nudges.js";
|
|
16
16
|
import { createGatewayTelemetry } from "./telemetry.js";
|
|
@@ -282,6 +282,8 @@ async function runAgent(cfg, args) {
|
|
|
282
282
|
let firstTaskDoneSent = false;
|
|
283
283
|
let sessionEndSent = false;
|
|
284
284
|
telemetry.track("session_start", { surface: "terminal" });
|
|
285
|
+
// 「连不上 u1s1 服务器」只在用户本机可见;记下底层错误码,网络恢复后随批次上报
|
|
286
|
+
onGatewayFetchFailure((failure) => telemetry.track("gateway_unreachable", { code: failure.code, surface: "terminal" }));
|
|
285
287
|
const trackSessionEnd = () => {
|
|
286
288
|
if (sessionEndSent)
|
|
287
289
|
return;
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { type CliConfig } from "./config.js";
|
|
2
2
|
/**
|
|
3
3
|
* 客户端事件上报(运营清单 C1):只报「会话开始/结束、首次工具成功、首次任务
|
|
4
|
-
*
|
|
4
|
+
* 完成、部署完成、连不上网关(只带错误码)」几个节点,不采任何内容。事件先在内存排队,每 30 秒或退出时
|
|
5
5
|
* 批量 POST /v1/telemetry(每批最多 20 条),失败静默丢弃,绝不阻塞界面、
|
|
6
6
|
* 绝不拖慢退出(退出冲刷最多等 1 秒)。
|
|
7
7
|
*
|
|
8
8
|
* 关闭方式:环境变量 U1S1_TELEMETRY=0,或 ~/.u1s1/agent/settings.json 里
|
|
9
9
|
* "telemetry": false。关闭后 track 直接丢,不打印任何东西。
|
|
10
10
|
*/
|
|
11
|
-
export type TelemetryEventName = "session_start" | "session_end" | "first_tool_success" | "first_task_done" | "deploy_done";
|
|
11
|
+
export type TelemetryEventName = "session_start" | "session_end" | "first_tool_success" | "first_task_done" | "deploy_done" | "gateway_unreachable";
|
|
12
12
|
export interface TelemetryEvent {
|
|
13
13
|
name: TelemetryEventName;
|
|
14
14
|
/** epoch ms */
|