u1s1-cli 0.19.3 → 0.19.5

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.
@@ -26,6 +26,14 @@ export declare function writeWebToolsExtension(cfg: CliConfig, features: {
26
26
  webFetchRender: boolean;
27
27
  imageGen: boolean;
28
28
  }): void;
29
+ /**
30
+ * 生成「OpenRouter 应用归因」扩展到 <agentDir>/extensions/u1s1-attribution.js。
31
+ * 用户自己配 OPENROUTER_API_KEY 直连时,pi 内置的归因头归到 pi.dev 名下(且受遥测
32
+ * 开关控制);这里用 before_provider_headers 钩子覆盖为 u1s1,让这部分流量也计入
33
+ * u1s1 的 OpenRouter 公开排行与数据分析(openrouter.ai/docs/app-attribution)。
34
+ * 只在请求目标确认为 OpenRouter 时才改头,其它供应商不加多余头。
35
+ */
36
+ export declare function writeAttributionExtension(): void;
29
37
  /**
30
38
  * 生成「精简 UI」扩展到 <agentDir>/extensions/u1s1-compact-ui.js:
31
39
  * - 隐藏内置工具调用(read/bash/edit/write/grep/find/ls),出错才显示一行;ctrl+o 可展开
@@ -1,5 +1,6 @@
1
1
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { dirname, join } from "node:path";
3
4
  import { agentDir, CUSTOM_ENDPOINTS, ENDPOINT_ID_RE, endpointKeyEnvName, MODELS, PROVIDER_ID, VERSION, } from "./config.js";
4
5
  const BRAND_APPEND = `## u1s1
5
6
 
@@ -50,6 +51,21 @@ export function ensureBrandPrompt(shell) {
50
51
  writeFileSync(p, content);
51
52
  }
52
53
  }
54
+ /**
55
+ * 当前捆绑的 pi 引擎版本号。pi 的包 exports 只有 "import" 条目,
56
+ * require.resolve 会报 ERR_PACKAGE_PATH_NOT_EXPORTED,必须走
57
+ * import.meta.resolve;拿到入口文件(dist/index.js)后向上一级找包根。
58
+ */
59
+ function bundledPiVersion() {
60
+ try {
61
+ const entry = fileURLToPath(import.meta.resolve("@earendil-works/pi-coding-agent"));
62
+ const pkg = JSON.parse(readFileSync(join(dirname(entry), "..", "package.json"), "utf8"));
63
+ return typeof pkg.version === "string" ? pkg.version : undefined;
64
+ }
65
+ catch {
66
+ return undefined;
67
+ }
68
+ }
53
69
  /** Defaults that don't overwrite values the user already set. */
54
70
  export function ensureDefaultSettings() {
55
71
  mkdirSync(agentDir, { recursive: true });
@@ -105,6 +121,16 @@ export function ensureDefaultSettings() {
105
121
  delete settings.theme;
106
122
  changed = true;
107
123
  }
124
+ // 屏蔽 pi 引擎的启动更新日志(What's New):那是上游英文 changelog,且 pi 的
125
+ // 版本号体系(0.84.x)和 u1s1(0.19.x)完全对不上——settings 里「上次看到的
126
+ // 版本」一旦缺失或偏旧,升级后启动会一次性灌出几十条英文更新说明。
127
+ // u1s1 的版本动态走公告横幅和 u1s1 update,这里每次启动都把该记录钉死在
128
+ // 当前捆绑的引擎版本上,保证启动时永不弹 changelog。
129
+ const piVersion = bundledPiVersion();
130
+ if (piVersion && settings["lastChangelogVersion"] !== piVersion) {
131
+ settings["lastChangelogVersion"] = piVersion;
132
+ changed = true;
133
+ }
108
134
  if (changed)
109
135
  writeFileSync(p, JSON.stringify(settings, null, 2) + "\n");
110
136
  }
@@ -162,6 +188,27 @@ export function writeWebToolsExtension(cfg, features) {
162
188
  subagentBlock +
163
189
  `}\n`);
164
190
  }
191
+ /**
192
+ * 生成「OpenRouter 应用归因」扩展到 <agentDir>/extensions/u1s1-attribution.js。
193
+ * 用户自己配 OPENROUTER_API_KEY 直连时,pi 内置的归因头归到 pi.dev 名下(且受遥测
194
+ * 开关控制);这里用 before_provider_headers 钩子覆盖为 u1s1,让这部分流量也计入
195
+ * u1s1 的 OpenRouter 公开排行与数据分析(openrouter.ai/docs/app-attribution)。
196
+ * 只在请求目标确认为 OpenRouter 时才改头,其它供应商不加多余头。
197
+ */
198
+ export function writeAttributionExtension() {
199
+ const dir = join(agentDir, "extensions");
200
+ mkdirSync(dir, { recursive: true });
201
+ writeFileSync(join(dir, "u1s1-attribution.js"), `// 由 u1s1 每次启动自动生成,请勿手改\n` +
202
+ `export default async function (pi) {\n` +
203
+ ` pi.on("before_provider_headers", (event, ctx) => {\n` +
204
+ ` const m = ctx.model;\n` +
205
+ ` if (!m || !(m.provider === "openrouter" || String(m.baseUrl ?? "").includes("openrouter.ai"))) return;\n` +
206
+ ` event.headers["HTTP-Referer"] = "https://u1s1.io";\n` +
207
+ ` event.headers["X-OpenRouter-Title"] = "u1s1";\n` +
208
+ ` event.headers["X-OpenRouter-Categories"] = "cli-agent";\n` +
209
+ ` });\n` +
210
+ `}\n`);
211
+ }
165
212
  /**
166
213
  * 生成「精简 UI」扩展到 <agentDir>/extensions/u1s1-compact-ui.js:
167
214
  * - 隐藏内置工具调用(read/bash/edit/write/grep/find/ls),出错才显示一行;ctrl+o 可展开
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { execSync, spawnSync } from "node:child_process";
3
3
  import { writeFileSync } from "node:fs";
4
- import { cleanupBrandThemes, endpointKeyEnv, endpointProviderEntry, ensureBrandPrompt, ensureDefaultSettings, ensureProviderModels, ensureWorkflowPromptTemplate, scrubForeignProviderEnv, toProviderModels, writeCompactUiExtension, writeWebToolsExtension, } from "./agent-setup.js";
4
+ import { cleanupBrandThemes, endpointKeyEnv, endpointProviderEntry, ensureBrandPrompt, ensureDefaultSettings, ensureProviderModels, ensureWorkflowPromptTemplate, scrubForeignProviderEnv, toProviderModels, writeAttributionExtension, writeCompactUiExtension, writeWebToolsExtension, } from "./agent-setup.js";
5
5
  import { printConsoleBanner } from "./brand.js";
6
6
  import { agentDir, apiModelToDef, CUSTOM_ENDPOINTS, isPortableInstall, loadConfig, MODELS, persistPreferredModel, PROVIDER_ID, readSettings, refValid, resolvePreferredModel, setModelsFromApi, VERSION, } from "./config.js";
7
7
  import { registerLoopCommand } from "./loop.js";
@@ -175,6 +175,8 @@ async function runAgent(cfg, args) {
175
175
  });
176
176
  // 精简 UI:隐藏工具调用 + 汇总行 + 隐藏思考标签(同样投影到 agentDir/extensions)
177
177
  writeCompactUiExtension();
178
+ // OpenRouter 应用归因:直连流量计入 u1s1 的公开排行
179
+ writeAttributionExtension();
178
180
  ensureTmuxKeyboardProtocol();
179
181
  // must be set before pi reads them (getAgentDir() reads at call time, env at import is fine too)
180
182
  process.env["PI_CODING_AGENT_DIR"] = agentDir;
package/dist/web.js CHANGED
@@ -2,7 +2,7 @@ import { spawn, spawnSync } from "node:child_process";
2
2
  import { mkdirSync } from "node:fs";
3
3
  import { createRequire } from "node:module";
4
4
  import { dirname, join } from "node:path";
5
- import { cleanupBrandThemes, endpointKeyEnv, ensureAuthCredential, ensureBrandPrompt, ensureWorkflowPromptTemplate, ensureDefaultSettings, ensureProviderModels, scrubForeignProviderEnv, writeWebToolsExtension, } from "./agent-setup.js";
5
+ import { cleanupBrandThemes, endpointKeyEnv, ensureAuthCredential, ensureBrandPrompt, ensureWorkflowPromptTemplate, ensureDefaultSettings, ensureProviderModels, scrubForeignProviderEnv, writeAttributionExtension, writeWebToolsExtension, } from "./agent-setup.js";
6
6
  import { agentDir, apiModelToDef, resolvePreferredModel, setModelsFromApi, u1s1Dir, writeAgentDefaultModel, } from "./config.js";
7
7
  import { ensureSearchTools } from "./search-tools.js";
8
8
  import { ensureUsableShell } from "./shell-doctor.js";
@@ -58,6 +58,8 @@ export async function prepareWebEnv(cfg) {
58
58
  webFetchRender: webFetchRenderEnabled,
59
59
  imageGen: imageGenEnabled,
60
60
  });
61
+ // OpenRouter 应用归因:直连流量计入 u1s1 的公开排行(与 TUI 同源)
62
+ writeAttributionExtension();
61
63
  // 网页版新会话从 settings.json 的 defaultModel 取模型(TUI 是每次传 --model),
62
64
  // 确保它有值;resolvePreferredModel 优先尊重已有的 in-session 选择,不会回退覆盖。
63
65
  const pref = resolvePreferredModel(cfg);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u1s1-cli",
3
- "version": "0.19.3",
3
+ "version": "0.19.5",
4
4
  "description": "u1s1 — 有一说一,最省心的 AI 编程搭子。终端里用中文说需求,AI 帮你读文件、改代码、跑命令。",
5
5
  "type": "module",
6
6
  "bin": {
@@ -43,8 +43,8 @@
43
43
  "license": "MIT",
44
44
  "homepage": "https://u1s1.io",
45
45
  "dependencies": {
46
- "@earendil-works/pi-coding-agent": "0.84.2",
47
- "@earendil-works/pi-tui": "0.84.2",
46
+ "@earendil-works/pi-coding-agent": "0.84.3",
47
+ "@earendil-works/pi-tui": "0.84.3",
48
48
  "typebox": "1.3.7"
49
49
  },
50
50
  "optionalDependencies": {