u1s1-cli 0.20.1 → 0.20.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.
@@ -1,5 +1,5 @@
1
1
  import { webcrypto } from "node:crypto";
2
- import type { CliConfig } from "./config.js";
2
+ import { type CliConfig } from "./config.js";
3
3
  export declare function hasDeviceCredential(cfg: CliConfig): boolean;
4
4
  export declare function generateDeviceKeyPair(): Promise<{
5
5
  privateJwk: webcrypto.JsonWebKey;
@@ -12,10 +12,12 @@ interface SigningProxy {
12
12
  baseUrl: string;
13
13
  localKey: string;
14
14
  token: string;
15
+ client: ClientSurface;
15
16
  }
17
+ export type ClientSurface = "terminal" | "web" | "desktop" | "cloud";
16
18
  /**
17
19
  * pi accepts static provider headers only. Keep it behind a loopback proxy that
18
20
  * replaces the local bearer credential with a fresh DPoP proof per request.
19
21
  */
20
- export declare function ensureSigningProxy(cfg: CliConfig): Promise<SigningProxy>;
22
+ export declare function ensureSigningProxy(cfg: CliConfig, fallbackClient?: ClientSurface): Promise<SigningProxy>;
21
23
  export {};
@@ -1,5 +1,6 @@
1
1
  import { createHash, randomBytes, randomUUID, webcrypto } from "node:crypto";
2
2
  import { createServer } from "node:http";
3
+ import { VERSION } from "./config.js";
3
4
  const enc = new TextEncoder();
4
5
  let cachedPrivate;
5
6
  function b64url(value) {
@@ -86,15 +87,23 @@ function requestHeaders(input) {
86
87
  return headers;
87
88
  }
88
89
  let signingProxy;
90
+ function clientSurface(fallback) {
91
+ const explicit = process.env["U1S1_CLIENT"];
92
+ if (explicit === "terminal" || explicit === "web" || explicit === "desktop" || explicit === "cloud") {
93
+ return explicit;
94
+ }
95
+ return process.versions.electron ? "desktop" : fallback;
96
+ }
89
97
  /**
90
98
  * pi accepts static provider headers only. Keep it behind a loopback proxy that
91
99
  * replaces the local bearer credential with a fresh DPoP proof per request.
92
100
  */
93
- export async function ensureSigningProxy(cfg) {
101
+ export async function ensureSigningProxy(cfg, fallbackClient = "terminal") {
94
102
  if (!hasDeviceCredential(cfg))
95
103
  throw new Error("当前安装需要重新登录,以创建设备凭证");
104
+ const client = clientSurface(fallbackClient);
96
105
  const current = signingProxy;
97
- if (current && current.token === cfg.deviceToken)
106
+ if (current && current.token === cfg.deviceToken && current.client === client)
98
107
  return current;
99
108
  const localKey = `local-${randomBytes(32).toString("hex")}`;
100
109
  const upstreamOrigin = new URL(cfg.baseUrl).origin;
@@ -118,9 +127,15 @@ export async function ensureSigningProxy(cfg) {
118
127
  for await (const chunk of req)
119
128
  chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
120
129
  const body = chunks.length ? Buffer.concat(chunks) : undefined;
130
+ const outboundHeaders = requestHeaders(req.headers);
131
+ // Set these at the final local hop so model calls and extension tools share
132
+ // exactly the same attribution, regardless of their upstream SDK defaults.
133
+ outboundHeaders.set("x-u1s1-client", client);
134
+ outboundHeaders.set("x-u1s1-version", VERSION);
135
+ outboundHeaders.set("x-u1s1-platform", `${process.platform}-${process.arch}`);
121
136
  const upstream = await authorizedFetch(cfg, target, {
122
137
  method: req.method ?? "GET",
123
- headers: requestHeaders(req.headers),
138
+ headers: outboundHeaders,
124
139
  body,
125
140
  });
126
141
  const headers = {};
@@ -148,6 +163,6 @@ export async function ensureSigningProxy(cfg) {
148
163
  });
149
164
  server.unref();
150
165
  const port = server.address().port;
151
- signingProxy = { baseUrl: `http://127.0.0.1:${port}/v1`, localKey, token: cfg.deviceToken };
166
+ signingProxy = { baseUrl: `http://127.0.0.1:${port}/v1`, localKey, token: cfg.deviceToken, client };
152
167
  return signingProxy;
153
168
  }
package/dist/web.js CHANGED
@@ -47,7 +47,7 @@ export async function prepareWebEnv(cfg) {
47
47
  console.error(" 获取模型列表失败,使用内置列表:", e.message);
48
48
  }
49
49
  await endpointsReady;
50
- const signing = await ensureSigningProxy(cfg);
50
+ const signing = await ensureSigningProxy(cfg, "web");
51
51
  const officialCfg = { ...cfg, baseUrl: signing.baseUrl, apiKey: signing.localKey };
52
52
  ensureBrandPrompt(await shellReady);
53
53
  // /workflow 提示词模板与 TUI 同源,web/桌面版也要有
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u1s1-cli",
3
- "version": "0.20.1",
3
+ "version": "0.20.2",
4
4
  "description": "u1s1 — 有一说一,最省心的 AI 编程搭子。终端里用中文说需求,AI 帮你读文件、改代码、跑命令。",
5
5
  "type": "module",
6
6
  "bin": {