@huyuan-ai/cli 1.3.0 → 1.4.0

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/UPGRADE.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  本文档说明各版本相对上一版本的重要变更,以及从旧版升级时的注意点。
4
4
 
5
+ ## 1.4.0
6
+
7
+ ### 变更
8
+
9
+ - **`doubao ask-with-citations`**:助手正文判稳与内置 `doubao/ask` 对齐,复用 OpenCLI `waitForDoubaoResponse`(不再使用自研的 `message_text_content` 间隔采样)。
10
+ - **引用采集**:回答返回后增加短轮询,等待参考资料入口(按钮或「参考 N 篇资料」文案)就绪后再打开面板抓取 JSON,减少空引用。
11
+
12
+ ### 破坏性变更
13
+
14
+ - 移除 CLI 选项 **`--answer-stable-gap-ms`**。若脚本或别名中仍传入该参数,请删除;正文等待时长仅由 **`--timeout`** 控制(与 `doubao ask` 一致)。
15
+
16
+ ## 1.3.1
17
+
18
+ ### 修复
19
+
20
+ - **全局安装后 `huyuan-opencli` 首次运行**:补齐随包发布的 `vendor/opencli/scripts/` 与 `vendor/opencli/package.json`,使 OpenCLI 首次运行时的 `fetch-adapters` 能正确解析路径并读取版本(不再出现 `Cannot find module .../fetch-adapters.js`)。
21
+
5
22
  ## 1.3.0
6
23
 
7
24
  ### 新增
@@ -1 +1 @@
1
- {"version":3,"file":"doubao-ask-with-citations.d.ts","sourceRoot":"","sources":["../../../../src/integrations/opencli/commands/doubao-ask-with-citations.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B"}
1
+ {"version":3,"file":"doubao-ask-with-citations.d.ts","sourceRoot":"","sources":["../../../../src/integrations/opencli/commands/doubao-ask-with-citations.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B"}
@@ -2,8 +2,41 @@
2
2
  * 注册 `doubao/ask-with-citations`:在 `bootstrapOpencli` 的 discoverClis 之后执行,
3
3
  * 与内置 `doubao/ask` 并列,不修改 vendor/opencli 源码。
4
4
  */
5
- import { DOUBAO_DOMAIN, sendDoubaoMessage } from '../../../../vendor/opencli/dist/clis/doubao/utils.js';
5
+ import { DOUBAO_DOMAIN, getDoubaoTranscriptLines, getDoubaoVisibleTurns, sendDoubaoMessage, waitForDoubaoResponse, } from '../../../../vendor/opencli/dist/clis/doubao/utils.js';
6
6
  import { cli, Strategy } from '../../../../vendor/opencli/dist/src/registry.js';
7
+ /** 回答结束后,等待引用入口挂载的最长时间(秒),与 `timeout` 无关的独立预算 */
8
+ const REFERENCE_ENTRY_WAIT_SECONDS = 30;
9
+ /** 不点击:仅探测最后一条助手消息是否已出现引用入口(按钮或「参考 N 篇资料」文案) */
10
+ function getReferenceEntryProbeScript() {
11
+ return `
12
+ (() => {
13
+ const messageList = document.querySelector('[data-testid="message-list"]');
14
+ if (!messageList) return { ready: false };
15
+ const unions = Array.from(messageList.querySelectorAll('[data-testid="union_message"]'));
16
+ const lastAssistant = [...unions].reverse().find((u) =>
17
+ u.querySelector('[data-testid="receive_message"]')
18
+ );
19
+ if (!lastAssistant) return { ready: false };
20
+ const btn = lastAssistant.querySelector('[data-testid="search-reference-ui-v3"]');
21
+ if (btn && btn instanceof HTMLElement) return { ready: true };
22
+ const textProbe = lastAssistant.innerText || '';
23
+ if (/参考\\s*\\d+\\s*篇资料/.test(textProbe)) return { ready: true };
24
+ return { ready: false };
25
+ })()
26
+ `;
27
+ }
28
+ async function waitForReferenceEntryReady(page, maxSeconds, verbose) {
29
+ const deadline = Date.now() + Math.max(1, maxSeconds) * 1000;
30
+ while (Date.now() < deadline) {
31
+ const raw = await page.evaluate(getReferenceEntryProbeScript());
32
+ if (raw?.ready)
33
+ return;
34
+ await page.wait(0.5);
35
+ }
36
+ if (verbose) {
37
+ process.stderr.write('[doubao/ask-with-citations] 引用入口在超时内未就绪,仍将尝试打开面板\n');
38
+ }
39
+ }
7
40
  function getClickReferenceEntryScript() {
8
41
  return `
9
42
  (() => {
@@ -100,99 +133,6 @@ function normalizeUrl(url) {
100
133
  return url;
101
134
  }
102
135
  }
103
- /**
104
- * 豆包检索会先出现「正在搜索」「找到 N 篇资料」等占位。
105
- * 判稳改为:仅看最后一条 message_text_content;占位文本不参与终稿;流式结束用两次采样间隔(默认 5s)文本相同。
106
- */
107
- function isTransientAssistantReply(text) {
108
- const t = text.trim();
109
- if (!t)
110
- return true;
111
- if (t.length > 200)
112
- return false;
113
- if (/\n/.test(t) && t.length > 80)
114
- return false;
115
- // 检索中间态:仅「篇数/找到」提示、尚无正文(易与最终回答混淆)
116
- if (t.length <= 48) {
117
- if (/^(已)?找到\s*\d+\s*篇(资料|结果|内容)?[\s…\.]*$/u.test(t))
118
- return true;
119
- if (/^参考\s*\d+\s*篇资料[\s…\.]*$/u.test(t))
120
- return true;
121
- }
122
- // 短句且仍以「正在…搜索/思考」为主,视为占位(避免「正在为您搜索…」等变体被当成最终答案)
123
- if (t.length < 100 && /^正在(联网)?(搜索|检索|查找|分析|思考|生成)/u.test(t))
124
- return true;
125
- if (t.length < 80
126
- && /^(搜索中|思考中|生成中|请稍候|加载中|联网搜索|正在联网)/u.test(t)) {
127
- return true;
128
- }
129
- return /^(正在(联网)?(搜索|检索|查找|分析|思考|生成)[\s…\.]*|搜索中|思考中|生成中|请稍候|加载中|联网搜索[中…\.]*)$/u.test(t);
130
- }
131
- function sanitizeAssistantText(value, promptText) {
132
- return value
133
- .replace(promptText, '')
134
- .replace(/内容由豆包 AI 生成/g, '')
135
- .replace(/在此处拖放文件/g, '')
136
- .replace(/文件数量:.*$/g, '')
137
- .replace(/\{"namedChunks".*$/g, '')
138
- .replace(/window\._SSR_DATA.*$/g, '')
139
- .trim();
140
- }
141
- /** 与 Puppeteer 脚本一致:最后一条助手 message_text_content 的 innerText */
142
- function getLastAssistantMessageTextContentScript() {
143
- return `
144
- (() => {
145
- const nodes = document.querySelectorAll(
146
- '[data-testid="receive_message"] [data-testid="message_text_content"]'
147
- );
148
- const last = nodes.length > 0 ? nodes[nodes.length - 1] : null;
149
- return last ? (last.innerText || '').trim() : '';
150
- })()
151
- `;
152
- }
153
- /**
154
- * 以 DOM 最后一条正文为准;间隔 stableGapMs 两次采样文本相同且非占位 → 流式结束(借鉴外部 Puppeteer 判稳)。
155
- */
156
- async function waitForLastMessageTextContentStable(page, promptText, timeoutSeconds, stableGapMs) {
157
- const deadline = Date.now() + Math.max(1, timeoutSeconds) * 1000;
158
- const gapSec = Math.max(0.5, stableGapMs / 1000);
159
- let lastSubstantive = '';
160
- let firstPoll = true;
161
- while (Date.now() < deadline) {
162
- const raw = await page.evaluate(getLastAssistantMessageTextContentScript());
163
- const t1 = sanitizeAssistantText(typeof raw === 'string' ? raw : '', promptText);
164
- if (!t1) {
165
- const rest = (deadline - Date.now()) / 1000;
166
- await page.wait(Math.min(firstPoll ? 1.5 : 2, Math.max(0.1, rest)));
167
- firstPoll = false;
168
- continue;
169
- }
170
- if (isTransientAssistantReply(t1)) {
171
- const rest = (deadline - Date.now()) / 1000;
172
- await page.wait(Math.min(2, Math.max(0.1, rest)));
173
- firstPoll = false;
174
- continue;
175
- }
176
- lastSubstantive = t1;
177
- const remainingMs = deadline - Date.now();
178
- if (remainingMs < stableGapMs) {
179
- break;
180
- }
181
- await page.wait(gapSec);
182
- const raw2 = await page.evaluate(getLastAssistantMessageTextContentScript());
183
- const t2 = sanitizeAssistantText(typeof raw2 === 'string' ? raw2 : '', promptText);
184
- if (t1 === t2 && !isTransientAssistantReply(t2)) {
185
- return t2;
186
- }
187
- if (!isTransientAssistantReply(t2) && t2.length > 0) {
188
- lastSubstantive = t2;
189
- }
190
- const rest = (deadline - Date.now()) / 1000;
191
- await page.wait(Math.min(1, Math.max(0.1, rest)));
192
- firstPoll = false;
193
- }
194
- return lastSubstantive;
195
- }
196
136
  async function waitForCitationPanel(page, maxSeconds) {
197
137
  const deadline = Date.now() + maxSeconds * 1000;
198
138
  while (Date.now() < deadline) {
@@ -285,12 +225,6 @@ cli({
285
225
  help: 'Max seconds to wait for reference panel items after click (default: 25)',
286
226
  default: '25',
287
227
  },
288
- {
289
- name: 'answerStableGapMs',
290
- required: false,
291
- help: 'Milliseconds between two samples of last assistant message_text_content for stream-done (default: 5000)',
292
- default: '5000',
293
- },
294
228
  ],
295
229
  columns: ['Role', 'Text', 'Citations'],
296
230
  func: async (page, kwargs, debug) => {
@@ -298,10 +232,11 @@ cli({
298
232
  const timeout = parseInt(String(kwargs.timeout ?? '60'), 10) || 60;
299
233
  const summaryMaxChars = parseInt(String(kwargs.citationSummaryMaxChars ?? '2000'), 10);
300
234
  const panelWaitSeconds = parseInt(String(kwargs.citationPanelWaitSeconds ?? '25'), 10) || 25;
301
- const answerStableGapMs = Math.max(500, parseInt(String(kwargs.answerStableGapMs ?? '5000'), 10) || 5000);
302
235
  const verbose = debug === true;
236
+ const beforeTurns = await getDoubaoVisibleTurns(page);
237
+ const beforeLines = await getDoubaoTranscriptLines(page);
303
238
  await sendDoubaoMessage(page, text);
304
- const response = await waitForLastMessageTextContentStable(page, text, timeout, answerStableGapMs);
239
+ const response = await waitForDoubaoResponse(page, beforeLines, beforeTurns, text, timeout);
305
240
  if (!response) {
306
241
  return [
307
242
  { Role: 'User', Text: text, Citations: '[]' },
@@ -312,6 +247,7 @@ cli({
312
247
  },
313
248
  ];
314
249
  }
250
+ await waitForReferenceEntryReady(page, REFERENCE_ENTRY_WAIT_SECONDS, verbose);
315
251
  const { citations } = await collectCitationsFromPanel(page, { panelWaitSeconds, summaryMaxChars: Number.isFinite(summaryMaxChars) ? summaryMaxChars : 2000 }, verbose);
316
252
  const citationsJson = JSON.stringify(citations);
317
253
  return [
@@ -1 +1 @@
1
- {"version":3,"file":"doubao-ask-with-citations.js","sourceRoot":"","sources":["../../../../src/integrations/opencli/commands/doubao-ask-with-citations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doubao-ask-with-citations.js","sourceRoot":"","sources":["../../../../src/integrations/opencli/commands/doubao-ask-with-citations.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,6 @@ export type DoubaoAskWithCitationsCliOptions = {
3
3
  timeout: string;
4
4
  citationSummaryMaxChars: string;
5
5
  citationPanelWaitSeconds: string;
6
- answerStableGapMs: string;
7
6
  format: string;
8
7
  verbose: boolean;
9
8
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ask-with-citations.d.ts","sourceRoot":"","sources":["../../../src/sites/doubao/ask-with-citations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,MAAM,gCAAgC,GAAG;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB,EAAE,MAAM,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gCAAgC,EACzC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,CAqBf"}
1
+ {"version":3,"file":"ask-with-citations.d.ts","sourceRoot":"","sources":["../../../src/sites/doubao/ask-with-citations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,MAAM,gCAAgC,GAAG;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB,EAAE,MAAM,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gCAAgC,EACzC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,CAoBf"}
@@ -14,7 +14,6 @@ export async function runDoubaoAskWithCitations(prompt, options, command) {
14
14
  timeout: options.timeout ?? '60',
15
15
  citationSummaryMaxChars: options.citationSummaryMaxChars ?? '2000',
16
16
  citationPanelWaitSeconds: options.citationPanelWaitSeconds ?? '25',
17
- answerStableGapMs: options.answerStableGapMs ?? '5000',
18
17
  };
19
18
  await executeOpencliRegistryCommand('doubao/ask-with-citations', kwargs, command, { format: options.format, verbose: options.verbose });
20
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ask-with-citations.js","sourceRoot":"","sources":["../../../src/sites/doubao/ask-with-citations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,wDAAwD,CAAC;AACvG,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAW7C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAc,EACd,OAAyC,EACzC,OAAgB;IAEhB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAqC;QAC/C,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;QAChC,uBAAuB,EAAE,OAAO,CAAC,uBAAuB,IAAI,MAAM;QAClE,wBAAwB,EAAE,OAAO,CAAC,wBAAwB,IAAI,IAAI;QAClE,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,MAAM;KACvD,CAAC;IAEF,MAAM,6BAA6B,CACjC,2BAA2B,EAC3B,MAAM,EACN,OAAO,EACP,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CACrD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"ask-with-citations.js","sourceRoot":"","sources":["../../../src/sites/doubao/ask-with-citations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,wDAAwD,CAAC;AACvG,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAU7C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAc,EACd,OAAyC,EACzC,OAAgB;IAEhB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAqC;QAC/C,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;QAChC,uBAAuB,EAAE,OAAO,CAAC,uBAAuB,IAAI,MAAM;QAClE,wBAAwB,EAAE,OAAO,CAAC,wBAAwB,IAAI,IAAI;KACnE,CAAC;IAEF,MAAM,6BAA6B,CACjC,2BAA2B,EAC3B,MAAM,EACN,OAAO,EACP,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CACrD,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/sites/doubao/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmDrD"}
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/sites/doubao/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8CrD"}
@@ -20,7 +20,6 @@ export function registerDoubao(program) {
20
20
  .option('--timeout <seconds>', '等待回复的最长时间(秒)', '60')
21
21
  .option('--citation-summary-max-chars <n>', '每条引用摘要的最大字符数(0 表示不截断)', '2000')
22
22
  .option('--citation-panel-wait-seconds <n>', '点击「参考 N 篇资料」后等待面板出现的最长时间(秒)', '25')
23
- .option('--answer-stable-gap-ms <ms>', '判定助手正文流式结束:两次采样最后一条 message_text_content 的间隔(毫秒,默认 5000)', '5000')
24
23
  .option('-f, --format <fmt>', '输出格式: json, table, plain, yaml, md, csv(默认 json)', 'json')
25
24
  .option('-v, --verbose', '调试输出', false)
26
25
  .action(async (prompt, options, command) => {
@@ -1 +1 @@
1
- {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/sites/doubao/register.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAA4B,MAAM,UAAU,CAAC;AAClE,OAAO,EACL,yBAAyB,GAE1B,MAAM,yBAAyB,CAAC;AAEjC,8DAA8D;AAC9D,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC;IAE3E,MAAM;SACH,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,iBAAiB,CAAC;SAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;SAC5B,MAAM,CAAC,qBAAqB,EAAE,cAAc,EAAE,IAAI,CAAC;SACnD,MAAM,CAAC,oBAAoB,EAAE,yCAAyC,EAAE,OAAO,CAAC;SAChF,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,CAAC;SACtC,MAAM,CACL,KAAK,EACH,MAAc,EACd,OAA4B,EAC5B,OAAgB,EAChB,EAAE;QACF,MAAM,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC,CACF,CAAC;IAEJ,MAAM;SACH,OAAO,CAAC,oBAAoB,CAAC;SAC7B,WAAW,CAAC,iCAAiC,CAAC;SAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;SAC5B,MAAM,CAAC,qBAAqB,EAAE,cAAc,EAAE,IAAI,CAAC;SACnD,MAAM,CACL,kCAAkC,EAClC,uBAAuB,EACvB,MAAM,CACP;SACA,MAAM,CACL,mCAAmC,EACnC,6BAA6B,EAC7B,IAAI,CACL;SACA,MAAM,CACL,6BAA6B,EAC7B,0DAA0D,EAC1D,MAAM,CACP;SACA,MAAM,CAAC,oBAAoB,EAAE,kDAAkD,EAAE,MAAM,CAAC;SACxF,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,CAAC;SACtC,MAAM,CACL,KAAK,EACH,MAAc,EACd,OAAyC,EACzC,OAAgB,EAChB,EAAE;QACF,MAAM,yBAAyB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC,CACF,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/sites/doubao/register.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAA4B,MAAM,UAAU,CAAC;AAClE,OAAO,EACL,yBAAyB,GAE1B,MAAM,yBAAyB,CAAC;AAEjC,8DAA8D;AAC9D,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC;IAE3E,MAAM;SACH,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,iBAAiB,CAAC;SAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;SAC5B,MAAM,CAAC,qBAAqB,EAAE,cAAc,EAAE,IAAI,CAAC;SACnD,MAAM,CAAC,oBAAoB,EAAE,yCAAyC,EAAE,OAAO,CAAC;SAChF,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,CAAC;SACtC,MAAM,CACL,KAAK,EACH,MAAc,EACd,OAA4B,EAC5B,OAAgB,EAChB,EAAE;QACF,MAAM,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC,CACF,CAAC;IAEJ,MAAM;SACH,OAAO,CAAC,oBAAoB,CAAC;SAC7B,WAAW,CAAC,iCAAiC,CAAC;SAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;SAC5B,MAAM,CAAC,qBAAqB,EAAE,cAAc,EAAE,IAAI,CAAC;SACnD,MAAM,CACL,kCAAkC,EAClC,uBAAuB,EACvB,MAAM,CACP;SACA,MAAM,CACL,mCAAmC,EACnC,6BAA6B,EAC7B,IAAI,CACL;SACA,MAAM,CAAC,oBAAoB,EAAE,kDAAkD,EAAE,MAAM,CAAC;SACxF,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,CAAC;SACtC,MAAM,CACL,KAAK,EACH,MAAc,EACd,OAAyC,EACzC,OAAgB,EAChB,EAAE;QACF,MAAM,yBAAyB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC,CACF,CAAC;AACN,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huyuan-ai/cli",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -29,6 +29,8 @@
29
29
  "files": [
30
30
  "dist",
31
31
  "vendor/opencli/dist",
32
+ "vendor/opencli/package.json",
33
+ "vendor/opencli/scripts",
32
34
  "README.md",
33
35
  "UPGRADE.md"
34
36
  ],
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@jackwener/opencli",
3
+ "version": "1.6.7",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "Make any website or Electron App your CLI. AI-powered.",
8
+ "engines": {
9
+ "node": ">=20.0.0"
10
+ },
11
+ "type": "module",
12
+ "main": "dist/src/main.js",
13
+ "bin": {
14
+ "opencli": "dist/src/main.js"
15
+ },
16
+ "exports": {
17
+ ".": "./dist/src/main.js",
18
+ "./registry": "./dist/src/registry-api.js",
19
+ "./errors": "./dist/src/errors.js",
20
+ "./types": "./dist/src/types.js",
21
+ "./utils": "./dist/src/utils.js",
22
+ "./logger": "./dist/src/logger.js",
23
+ "./launcher": "./dist/src/launcher.js",
24
+ "./browser/cdp": "./dist/src/browser/cdp.js",
25
+ "./browser/page": "./dist/src/browser/page.js",
26
+ "./browser/utils": "./dist/src/browser/utils.js",
27
+ "./download": "./dist/src/download/index.js",
28
+ "./download/article-download": "./dist/src/download/article-download.js",
29
+ "./download/media-download": "./dist/src/download/media-download.js",
30
+ "./download/progress": "./dist/src/download/progress.js",
31
+ "./pipeline": "./dist/src/pipeline/index.js"
32
+ },
33
+ "files": [
34
+ "dist/src/",
35
+ "dist/clis/",
36
+ "dist/cli-manifest.json",
37
+ "scripts/",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "scripts": {
42
+ "dev": "tsx src/main.ts",
43
+ "dev:bun": "bun src/main.ts",
44
+ "build": "npm run clean-dist && tsc && npm run clean-yaml && npm run copy-yaml && npm run build-manifest",
45
+ "build-manifest": "node dist/src/build-manifest.js",
46
+ "clean-dist": "node scripts/clean-dist.cjs",
47
+ "clean-yaml": "node scripts/clean-yaml.cjs",
48
+ "copy-yaml": "node scripts/copy-yaml.cjs",
49
+ "start": "node dist/src/main.js",
50
+ "start:bun": "bun dist/src/main.js",
51
+ "postinstall": "node scripts/postinstall.js || true; node scripts/fetch-adapters.js || true",
52
+ "typecheck": "tsc --noEmit",
53
+ "lint": "tsc --noEmit",
54
+ "prepare": "[ -d src ] && npm run build || true",
55
+ "prepublishOnly": "npm run build",
56
+ "test": "vitest run --project unit",
57
+ "test:bun": "bun vitest run --project unit",
58
+ "test:adapter": "vitest run --project adapter",
59
+ "test:all": "vitest run",
60
+ "test:e2e": "vitest run --project e2e",
61
+ "docs:dev": "vitepress dev docs",
62
+ "docs:build": "vitepress build docs",
63
+ "docs:preview": "vitepress preview docs"
64
+ },
65
+ "keywords": [
66
+ "cli",
67
+ "browser",
68
+ "web",
69
+ "ai"
70
+ ],
71
+ "author": "jackwener",
72
+ "license": "Apache-2.0",
73
+ "repository": {
74
+ "type": "git",
75
+ "url": "git+https://github.com/jackwener/opencli.git"
76
+ },
77
+ "dependencies": {
78
+ "chalk": "^5.3.0",
79
+ "cli-table3": "^0.6.5",
80
+ "commander": "^14.0.3",
81
+ "js-yaml": "^4.1.0",
82
+ "turndown": "^7.2.2",
83
+ "undici": "^7.24.6",
84
+ "ws": "^8.18.0"
85
+ },
86
+ "devDependencies": {
87
+ "@types/js-yaml": "^4.0.9",
88
+ "@types/node": "^22.13.10",
89
+ "@types/turndown": "^5.0.6",
90
+ "@types/ws": "^8.5.13",
91
+ "tsx": "^4.19.3",
92
+ "typescript": "^6.0.2",
93
+ "vitepress": "^1.6.4",
94
+ "vitest": "^4.1.0"
95
+ }
96
+ }
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env bash
2
+ # check-doc-coverage.sh — Verify every adapter in clis/ has a doc page.
3
+ #
4
+ # Exit codes:
5
+ # 0 — all adapters have docs
6
+ # 1 — at least one adapter is missing documentation
7
+ #
8
+ # Usage:
9
+ # bash scripts/check-doc-coverage.sh # report only
10
+ # bash scripts/check-doc-coverage.sh --strict # exit 1 on missing docs
11
+
12
+ set -euo pipefail
13
+
14
+ STRICT=false
15
+ if [[ "${1:-}" == "--strict" ]]; then
16
+ STRICT=true
17
+ fi
18
+
19
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
+ ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
21
+
22
+ SRC_DIR="$ROOT_DIR/clis"
23
+ DOCS_DIR="$ROOT_DIR/docs/adapters"
24
+
25
+ missing=()
26
+ covered=0
27
+ total=0
28
+
29
+ for adapter_dir in "$SRC_DIR"/*/; do
30
+ adapter_name="$(basename "$adapter_dir")"
31
+ # Skip internal directories (e.g., _shared)
32
+ [[ "$adapter_name" == _* ]] && continue
33
+ total=$((total + 1))
34
+
35
+ # Check if doc exists in browser/ or desktop/ subdirectories
36
+ if [[ -f "$DOCS_DIR/browser/$adapter_name.md" ]] || \
37
+ [[ -f "$DOCS_DIR/desktop/$adapter_name.md" ]]; then
38
+ covered=$((covered + 1))
39
+ else
40
+ # Handle directory name mismatches (e.g., discord-app -> discord)
41
+ alt_name="${adapter_name%-app}"
42
+ if [[ "$alt_name" != "$adapter_name" ]] && \
43
+ { [[ -f "$DOCS_DIR/browser/$alt_name.md" ]] || \
44
+ [[ -f "$DOCS_DIR/desktop/$alt_name.md" ]]; }; then
45
+ covered=$((covered + 1))
46
+ else
47
+ missing+=("$adapter_name")
48
+ fi
49
+ fi
50
+ done
51
+
52
+ echo "📊 Doc Coverage: $covered/$total adapters documented"
53
+ echo ""
54
+
55
+ if [[ ${#missing[@]} -gt 0 ]]; then
56
+ echo "⚠️ Missing docs for ${#missing[@]} adapter(s):"
57
+ for name in "${missing[@]}"; do
58
+ echo " - $name → create docs/adapters/browser/$name.md or docs/adapters/desktop/$name.md"
59
+ done
60
+ echo ""
61
+ if $STRICT; then
62
+ echo "❌ Doc check failed (--strict mode)."
63
+ exit 1
64
+ else
65
+ echo "💡 Run with --strict to fail CI on missing docs."
66
+ exit 0
67
+ fi
68
+ else
69
+ echo "✅ All adapters have documentation."
70
+ exit 0
71
+ fi
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Remove dist/ before a fresh build so deleted adapters do not leave stale
3
+ * compiled files behind in dist/clis/.
4
+ */
5
+ const { existsSync, rmSync } = require('fs');
6
+
7
+ if (existsSync('dist')) {
8
+ rmSync('dist', { recursive: true, force: true });
9
+ }
10
+
11
+ if (existsSync('tsconfig.tsbuildinfo')) {
12
+ rmSync('tsconfig.tsbuildinfo', { force: true });
13
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Clean YAML files from dist/clis/ before copying fresh ones.
3
+ */
4
+ const { readdirSync, rmSync, existsSync, statSync } = require('fs');
5
+ const path = require('path');
6
+
7
+ function walk(dir) {
8
+ if (!existsSync(dir)) return;
9
+ for (const f of readdirSync(dir)) {
10
+ const fp = path.join(dir, f);
11
+ if (statSync(fp).isDirectory()) {
12
+ walk(fp);
13
+ } else if (/\.ya?ml$/.test(f)) {
14
+ rmSync(fp);
15
+ }
16
+ }
17
+ }
18
+
19
+ walk('dist/clis');
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Copy YAML files from clis/ to dist/clis/.
3
+ */
4
+ const { readdirSync, copyFileSync, mkdirSync, existsSync, statSync } = require('fs');
5
+ const path = require('path');
6
+
7
+ function walk(src, dst) {
8
+ if (!existsSync(src)) return;
9
+ for (const f of readdirSync(src)) {
10
+ const sp = path.join(src, f);
11
+ const dp = path.join(dst, f);
12
+ if (statSync(sp).isDirectory()) {
13
+ walk(sp, dp);
14
+ } else if (/\.ya?ml$/.test(f)) {
15
+ mkdirSync(path.dirname(dp), { recursive: true });
16
+ copyFileSync(sp, dp);
17
+ }
18
+ }
19
+ }
20
+
21
+ walk('clis', 'dist/clis');
22
+
23
+ // Copy external CLI registry to dist/
24
+ const extSrc = 'src/external-clis.yaml';
25
+ if (existsSync(extSrc)) {
26
+ mkdirSync('dist/src', { recursive: true });
27
+ copyFileSync(extSrc, 'dist/src/external-clis.yaml');
28
+ }
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Copy official CLI adapters from the installed package to ~/.opencli/clis/.
5
+ *
6
+ * Update strategy (file-level granularity via adapter-manifest.json):
7
+ * - Official files (in new manifest) are unconditionally overwritten
8
+ * - Removed official files (in old manifest but not new) are cleaned up
9
+ * - User-created files (never in any manifest) are preserved
10
+ * - Skips if already installed at the same version
11
+ *
12
+ * Only runs on global install (npm install -g) or explicit OPENCLI_FETCH=1.
13
+ * No network calls — copies directly from dist/clis/ in the installed package.
14
+ *
15
+ * This is an ESM script (package.json type: module). No TypeScript, no src/ imports.
16
+ */
17
+
18
+ import { existsSync, mkdirSync, rmSync, cpSync, readFileSync, writeFileSync, readdirSync, statSync, unlinkSync } from 'node:fs';
19
+ import { join, resolve, dirname } from 'node:path';
20
+ import { homedir } from 'node:os';
21
+
22
+ const OPENCLI_DIR = join(homedir(), '.opencli');
23
+ const USER_CLIS_DIR = join(OPENCLI_DIR, 'clis');
24
+ const MANIFEST_PATH = join(OPENCLI_DIR, 'adapter-manifest.json');
25
+ const PACKAGE_ROOT = resolve(import.meta.dirname, '..');
26
+ const BUILTIN_CLIS = join(PACKAGE_ROOT, 'dist', 'clis');
27
+
28
+ function log(msg) {
29
+ console.log(`[opencli] ${msg}`);
30
+ }
31
+
32
+ function getPackageVersion() {
33
+ try {
34
+ return JSON.parse(readFileSync(join(PACKAGE_ROOT, 'package.json'), 'utf-8')).version;
35
+ } catch {
36
+ return 'unknown';
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Read existing manifest. Returns { version, files } or null.
42
+ */
43
+ function readManifest() {
44
+ try {
45
+ return JSON.parse(readFileSync(MANIFEST_PATH, 'utf-8'));
46
+ } catch {
47
+ return null;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Collect all relative file paths under a directory.
53
+ */
54
+ function walkFiles(dir, prefix = '') {
55
+ const results = [];
56
+ if (!existsSync(dir)) return results;
57
+ for (const entry of readdirSync(dir)) {
58
+ const full = join(dir, entry);
59
+ const rel = prefix ? `${prefix}/${entry}` : entry;
60
+ if (statSync(full).isDirectory()) {
61
+ results.push(...walkFiles(full, rel));
62
+ } else {
63
+ results.push(rel);
64
+ }
65
+ }
66
+ return results;
67
+ }
68
+
69
+ /**
70
+ * Remove empty parent directories up to (but not including) stopAt.
71
+ */
72
+ function pruneEmptyDirs(filePath, stopAt) {
73
+ let dir = dirname(filePath);
74
+ while (dir !== stopAt && dir.startsWith(stopAt)) {
75
+ try {
76
+ const entries = readdirSync(dir);
77
+ if (entries.length > 0) break;
78
+ rmSync(dir);
79
+ dir = dirname(dir);
80
+ } catch {
81
+ break;
82
+ }
83
+ }
84
+ }
85
+
86
+ export function fetchAdapters() {
87
+ const currentVersion = getPackageVersion();
88
+ const oldManifest = readManifest();
89
+
90
+ // Skip if already installed at the same version (unless forced via OPENCLI_FETCH=1)
91
+ const isForced = process.env.OPENCLI_FETCH === '1';
92
+ if (!isForced && currentVersion !== 'unknown' && oldManifest?.version === currentVersion) {
93
+ log(`Adapters already up to date (v${currentVersion})`);
94
+ return;
95
+ }
96
+
97
+ if (!existsSync(BUILTIN_CLIS)) {
98
+ log('Warning: dist/clis/ not found in package — skipping adapter copy');
99
+ return;
100
+ }
101
+
102
+ const newOfficialFiles = new Set(walkFiles(BUILTIN_CLIS));
103
+ const oldOfficialFiles = new Set(oldManifest?.files ?? []);
104
+ mkdirSync(USER_CLIS_DIR, { recursive: true });
105
+
106
+ // 1. Copy official files (unconditionally overwrite)
107
+ let copied = 0;
108
+ for (const relPath of newOfficialFiles) {
109
+ const src = join(BUILTIN_CLIS, relPath);
110
+ const dst = join(USER_CLIS_DIR, relPath);
111
+ mkdirSync(dirname(dst), { recursive: true });
112
+ cpSync(src, dst, { force: true });
113
+ copied++;
114
+ }
115
+
116
+ // 2. Remove files that were official but are no longer (upstream deleted)
117
+ let removed = 0;
118
+ for (const relPath of oldOfficialFiles) {
119
+ if (!newOfficialFiles.has(relPath)) {
120
+ const dst = join(USER_CLIS_DIR, relPath);
121
+ try {
122
+ unlinkSync(dst);
123
+ pruneEmptyDirs(dst, USER_CLIS_DIR);
124
+ removed++;
125
+ } catch {
126
+ // File may not exist locally
127
+ }
128
+ }
129
+ }
130
+
131
+ // 3. Write updated manifest
132
+ writeFileSync(MANIFEST_PATH, JSON.stringify({
133
+ version: currentVersion,
134
+ files: [...newOfficialFiles].sort(),
135
+ updatedAt: new Date().toISOString(),
136
+ }, null, 2));
137
+
138
+ log(`Installed ${copied} adapter files to ${USER_CLIS_DIR}` +
139
+ (removed > 0 ? `, removed ${removed} deprecated files` : ''));
140
+ }
141
+
142
+ function main() {
143
+ // Skip in CI
144
+ if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) return;
145
+ // Allow opt-out
146
+ if (process.env.OPENCLI_SKIP_FETCH === '1') return;
147
+
148
+ // Only run on global install, explicit trigger, or first-run fallback
149
+ const isGlobal = process.env.npm_config_global === 'true';
150
+ const isExplicit = process.env.OPENCLI_FETCH === '1';
151
+ const isFirstRun = process.env._OPENCLI_FIRST_RUN === '1';
152
+ if (!isGlobal && !isExplicit && !isFirstRun) return;
153
+
154
+ fetchAdapters();
155
+ }
156
+
157
+ main();
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * postinstall script — install shell completion files and print setup instructions.
5
+ *
6
+ * Detects the user's default shell and writes the completion script to the
7
+ * standard completion directory. For zsh and bash, the script prints manual
8
+ * instructions instead of modifying rc files (~/.zshrc, ~/.bashrc) — this
9
+ * avoids breaking multi-line shell commands and other fragile rc structures.
10
+ * Fish completions work automatically without rc changes.
11
+ *
12
+ * Supported shells: bash, zsh, fish.
13
+ *
14
+ * This script is intentionally plain Node.js (no TypeScript, no imports from
15
+ * the main source tree) so that it can run without a build step.
16
+ */
17
+
18
+ import { mkdirSync, writeFileSync, existsSync } from 'node:fs';
19
+ import { join } from 'node:path';
20
+ import { homedir } from 'node:os';
21
+
22
+
23
+ // ── Completion script content ──────────────────────────────────────────────
24
+
25
+ const BASH_COMPLETION = `# Bash completion for opencli (auto-installed)
26
+ _opencli_completions() {
27
+ local cur words cword
28
+ _get_comp_words_by_ref -n : cur words cword
29
+
30
+ local completions
31
+ completions=$(opencli --get-completions --cursor "$cword" "\${words[@]:1}" 2>/dev/null)
32
+
33
+ COMPREPLY=( $(compgen -W "$completions" -- "$cur") )
34
+ __ltrim_colon_completions "$cur"
35
+ }
36
+ complete -F _opencli_completions opencli
37
+ `;
38
+
39
+ const ZSH_COMPLETION = `#compdef opencli
40
+ # Zsh completion for opencli (auto-installed)
41
+ _opencli() {
42
+ local -a completions
43
+ local cword=$((CURRENT - 1))
44
+ completions=(\${(f)"$(opencli --get-completions --cursor "$cword" "\${words[@]:1}" 2>/dev/null)"})
45
+ compadd -a completions
46
+ }
47
+ _opencli
48
+ `;
49
+
50
+ const FISH_COMPLETION = `# Fish completion for opencli (auto-installed)
51
+ complete -c opencli -f -a '(
52
+ set -l tokens (commandline -cop)
53
+ set -l cursor (count (commandline -cop))
54
+ opencli --get-completions --cursor $cursor $tokens[2..] 2>/dev/null
55
+ )'
56
+ `;
57
+
58
+ // ── Helpers ────────────────────────────────────────────────────────────────
59
+
60
+ function detectShell() {
61
+ const shell = process.env.SHELL || '';
62
+ if (shell.includes('zsh')) return 'zsh';
63
+ if (shell.includes('bash')) return 'bash';
64
+ if (shell.includes('fish')) return 'fish';
65
+ return null;
66
+ }
67
+
68
+ function ensureDir(dir) {
69
+ if (!existsSync(dir)) {
70
+ mkdirSync(dir, { recursive: true });
71
+ }
72
+ }
73
+
74
+ // ── Main ───────────────────────────────────────────────────────────────────
75
+
76
+ function main() {
77
+ // Skip in CI environments
78
+ if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) {
79
+ return;
80
+ }
81
+
82
+ // Only install completion for global installs and npm link
83
+ const isGlobal = process.env.npm_config_global === 'true';
84
+ if (!isGlobal) {
85
+ return;
86
+ }
87
+
88
+ const shell = detectShell();
89
+ if (!shell) {
90
+ // Cannot determine shell; silently skip
91
+ return;
92
+ }
93
+
94
+ const home = homedir();
95
+
96
+ try {
97
+ switch (shell) {
98
+ case 'zsh': {
99
+ const completionsDir = join(home, '.zsh', 'completions');
100
+ const completionFile = join(completionsDir, '_opencli');
101
+ ensureDir(completionsDir);
102
+ writeFileSync(completionFile, ZSH_COMPLETION, 'utf8');
103
+
104
+ console.log(`✓ Zsh completion installed to ${completionFile}`);
105
+ console.log('');
106
+ console.log(' \x1b[1mTo enable, add these lines to your ~/.zshrc:\x1b[0m');
107
+ console.log(` fpath=(${completionsDir} $fpath)`);
108
+ console.log(' autoload -Uz compinit && compinit');
109
+ console.log('');
110
+ console.log(' If you already have compinit (oh-my-zsh, zinit, etc.), just add the fpath line \x1b[1mbefore\x1b[0m it.');
111
+ console.log(' Then restart your shell or run: \x1b[36mexec zsh\x1b[0m');
112
+ break;
113
+ }
114
+ case 'bash': {
115
+ const userCompDir = join(home, '.bash_completion.d');
116
+ const completionFile = join(userCompDir, 'opencli');
117
+ ensureDir(userCompDir);
118
+ writeFileSync(completionFile, BASH_COMPLETION, 'utf8');
119
+
120
+ console.log(`✓ Bash completion installed to ${completionFile}`);
121
+ console.log('');
122
+ console.log(' \x1b[1mTo enable, add this line to your ~/.bashrc:\x1b[0m');
123
+ console.log(` [ -f "${completionFile}" ] && source "${completionFile}"`);
124
+ console.log('');
125
+ console.log(' Then restart your shell or run: \x1b[36msource ~/.bashrc\x1b[0m');
126
+ break;
127
+ }
128
+ case 'fish': {
129
+ const completionsDir = join(home, '.config', 'fish', 'completions');
130
+ const completionFile = join(completionsDir, 'opencli.fish');
131
+ ensureDir(completionsDir);
132
+ writeFileSync(completionFile, FISH_COMPLETION, 'utf8');
133
+
134
+ console.log(`✓ Fish completion installed to ${completionFile}`);
135
+ console.log(` Restart your shell to activate.`);
136
+ break;
137
+ }
138
+ }
139
+ } catch (err) {
140
+ // Completion install is best-effort; never fail the package install
141
+ if (process.env.OPENCLI_VERBOSE) {
142
+ console.error(`Warning: Could not install shell completion: ${err.message}`);
143
+ }
144
+ }
145
+
146
+ // ── Spotify credentials template ────────────────────────────────────
147
+ const opencliDir = join(home, '.opencli');
148
+ const spotifyEnvFile = join(opencliDir, 'spotify.env');
149
+ ensureDir(opencliDir);
150
+ if (!existsSync(spotifyEnvFile)) {
151
+ writeFileSync(spotifyEnvFile,
152
+ `# Spotify credentials — get them at https://developer.spotify.com/dashboard\n` +
153
+ `# Add http://127.0.0.1:8888/callback as a Redirect URI in your Spotify app\n` +
154
+ `SPOTIFY_CLIENT_ID=your_spotify_client_id_here\n` +
155
+ `SPOTIFY_CLIENT_SECRET=your_spotify_client_secret_here\n`,
156
+ 'utf8'
157
+ );
158
+ console.log(`✓ Spotify credentials template created at ${spotifyEnvFile}`);
159
+ console.log(` Edit the file and add your Client ID and Secret, then run: opencli spotify auth`);
160
+ }
161
+
162
+ // ── Browser Bridge setup hint ───────────────────────────────────────
163
+ console.log('');
164
+ console.log(' \x1b[1mNext step — Browser Bridge setup\x1b[0m');
165
+ console.log(' Browser commands (bilibili, zhihu, twitter...) require the extension:');
166
+ console.log(' 1. Download: https://github.com/jackwener/opencli/releases');
167
+ console.log(' 2. In Chrome or Chromium, open chrome://extensions → enable Developer Mode → Load unpacked');
168
+ console.log('');
169
+ console.log(' Then run \x1b[36mopencli doctor\x1b[0m to verify.');
170
+ console.log('');
171
+ }
172
+
173
+ main();
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from 'node:child_process';
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+
7
+ const site = process.argv[2]?.trim();
8
+
9
+ if (!site) {
10
+ console.error('Usage: npm run test:site -- <site>');
11
+ process.exit(1);
12
+ }
13
+
14
+ const repoRoot = path.resolve(new URL('..', import.meta.url).pathname);
15
+ const srcDir = path.join(repoRoot, 'src');
16
+
17
+ function runStep(label, command, args) {
18
+ console.log(`\n==> ${label}`);
19
+ const result = spawnSync(command, args, {
20
+ cwd: repoRoot,
21
+ stdio: 'inherit',
22
+ env: process.env,
23
+ });
24
+
25
+ if (result.status !== 0) {
26
+ process.exit(result.status ?? 1);
27
+ }
28
+ }
29
+
30
+ function walk(dir) {
31
+ const files = [];
32
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
33
+ const fullPath = path.join(dir, entry.name);
34
+ if (entry.isDirectory()) {
35
+ files.push(...walk(fullPath));
36
+ } else {
37
+ files.push(fullPath);
38
+ }
39
+ }
40
+ return files;
41
+ }
42
+
43
+ function toPosix(filePath) {
44
+ return filePath.split(path.sep).join('/');
45
+ }
46
+
47
+ function findSiteTests() {
48
+ return walk(srcDir)
49
+ .filter(filePath => filePath.endsWith('.test.ts'))
50
+ .filter(filePath => {
51
+ const normalized = toPosix(path.relative(repoRoot, filePath));
52
+ return normalized.includes(`/clis/${site}/`) || normalized.includes(`/${site}.test.ts`);
53
+ })
54
+ .sort();
55
+ }
56
+
57
+ runStep('Typecheck', 'npm', ['run', 'typecheck']);
58
+ runStep('Targeted verify', 'npx', ['tsx', 'src/main.ts', 'verify', site]);
59
+
60
+ const testFiles = findSiteTests();
61
+ if (testFiles.length === 0) {
62
+ console.log(`\nNo site-specific vitest files found for "${site}". Skipping full vitest run.`);
63
+ process.exit(0);
64
+ }
65
+
66
+ runStep(
67
+ `Site tests (${site})`,
68
+ 'npx',
69
+ ['vitest', 'run', ...testFiles.map(filePath => path.relative(repoRoot, filePath))],
70
+ );