@jiangzhx/adcli 0.1.1 → 0.1.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/README.md CHANGED
@@ -36,12 +36,28 @@ adcli doc search "广告消耗"
36
36
  https://adcli.jiangzhx.com/search-index.json
37
37
  ```
38
38
 
39
+ 首次搜索会下载索引并缓存到系统标准缓存目录。也可以手动更新:
40
+
41
+ ```bash
42
+ adcli doc sync
43
+ adcli doc search "广告消耗" --refresh
44
+ ```
45
+
39
46
  本地调试可指定索引:
40
47
 
41
48
  ```bash
42
49
  adcli doc search "广告消耗" --index public/search-index.json
43
50
  ```
44
51
 
52
+ 给 AI / Agent 使用文档包:
53
+
54
+ ```bash
55
+ adcli list
56
+ adcli list kuaishou
57
+ adcli llms
58
+ adcli prompt
59
+ ```
60
+
45
61
  ## 常用命令
46
62
 
47
63
  ```bash
@@ -67,7 +83,7 @@ bun run build:search-index
67
83
  本地搜索已发布文档:
68
84
 
69
85
  ```bash
70
- bun run adcli doc search "广告消耗"
86
+ adcli doc search "广告消耗"
71
87
  ```
72
88
 
73
89
  完整命令清单见 [docs/commands.md](docs/commands.md)。
package/dist/cli.js CHANGED
@@ -1,9 +1,159 @@
1
1
  #!/usr/bin/env node
2
2
  // @bun
3
3
 
4
- // src/cli.ts
5
- import { readFile } from "fs/promises";
6
- import path from "path";
4
+ // src/lib/search/cache.ts
5
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
6
+ import path2 from "node:path";
7
+
8
+ // node_modules/env-paths/index.js
9
+ import path from "node:path";
10
+ import os from "node:os";
11
+ import process2 from "node:process";
12
+
13
+ // node_modules/is-safe-filename/index.js
14
+ var unsafeFilenameFixtures = Object.freeze([
15
+ "",
16
+ " ",
17
+ ".",
18
+ "..",
19
+ " .",
20
+ ". ",
21
+ " ..",
22
+ ".. ",
23
+ "../",
24
+ "../foo",
25
+ "foo/../bar",
26
+ "foo/bar",
27
+ "foo\\bar",
28
+ "foo\x00bar"
29
+ ]);
30
+ function isSafeFilename(filename) {
31
+ if (typeof filename !== "string") {
32
+ return false;
33
+ }
34
+ const trimmed = filename.trim();
35
+ return trimmed !== "" && trimmed !== "." && trimmed !== ".." && !filename.includes("/") && !filename.includes("\\") && !filename.includes("\x00");
36
+ }
37
+ function assertSafeFilename(filename) {
38
+ if (typeof filename !== "string") {
39
+ throw new TypeError("Expected a string");
40
+ }
41
+ if (!isSafeFilename(filename)) {
42
+ throw new Error(`Unsafe filename: ${JSON.stringify(filename)}`);
43
+ }
44
+ }
45
+
46
+ // node_modules/env-paths/index.js
47
+ var homedir = os.homedir();
48
+ var tmpdir = os.tmpdir();
49
+ var { env } = process2;
50
+ var macos = (name) => {
51
+ const library = path.join(homedir, "Library");
52
+ return {
53
+ data: path.join(library, "Application Support", name),
54
+ config: path.join(library, "Preferences", name),
55
+ cache: path.join(library, "Caches", name),
56
+ log: path.join(library, "Logs", name),
57
+ temp: path.join(tmpdir, name)
58
+ };
59
+ };
60
+ var windows = (name) => {
61
+ const appData = env.APPDATA || path.join(homedir, "AppData", "Roaming");
62
+ const localAppData = env.LOCALAPPDATA || path.join(homedir, "AppData", "Local");
63
+ return {
64
+ data: path.join(localAppData, name, "Data"),
65
+ config: path.join(appData, name, "Config"),
66
+ cache: path.join(localAppData, name, "Cache"),
67
+ log: path.join(localAppData, name, "Log"),
68
+ temp: path.join(tmpdir, name)
69
+ };
70
+ };
71
+ var linux = (name) => {
72
+ const username = path.basename(homedir);
73
+ return {
74
+ data: path.join(env.XDG_DATA_HOME || path.join(homedir, ".local", "share"), name),
75
+ config: path.join(env.XDG_CONFIG_HOME || path.join(homedir, ".config"), name),
76
+ cache: path.join(env.XDG_CACHE_HOME || path.join(homedir, ".cache"), name),
77
+ log: path.join(env.XDG_STATE_HOME || path.join(homedir, ".local", "state"), name),
78
+ temp: path.join(tmpdir, username, name)
79
+ };
80
+ };
81
+ function envPaths(name, { suffix = "nodejs" } = {}) {
82
+ assertSafeFilename(name);
83
+ if (suffix) {
84
+ name += `-${suffix}`;
85
+ }
86
+ assertSafeFilename(name);
87
+ if (process2.platform === "darwin") {
88
+ return macos(name);
89
+ }
90
+ if (process2.platform === "win32") {
91
+ return windows(name);
92
+ }
93
+ return linux(name);
94
+ }
95
+
96
+ // src/lib/search/cache.ts
97
+ var defaultSearchIndexUrl = "https://adcli.jiangzhx.com/search-index.json";
98
+ function getSearchIndexCacheInfo(options = {}) {
99
+ const cacheDir = options.cacheDir ?? envPaths("adcli", { suffix: "" }).cache;
100
+ return {
101
+ cachePath: path2.join(cacheDir, "search-index.json"),
102
+ indexUrl: options.indexUrl ?? defaultSearchIndexUrl
103
+ };
104
+ }
105
+ async function loadSearchIndex(options = {}) {
106
+ if (options.index) {
107
+ return await loadExplicitSearchIndex(options.index, options.fetcher);
108
+ }
109
+ const cacheInfo = getSearchIndexCacheInfo(options);
110
+ if (!options.refresh) {
111
+ try {
112
+ return JSON.parse(await readFile(cacheInfo.cachePath, "utf8"));
113
+ } catch (error) {
114
+ if (!isNotFoundError(error)) {
115
+ throw error;
116
+ }
117
+ }
118
+ }
119
+ return await refreshSearchIndex(options);
120
+ }
121
+ async function refreshSearchIndex(options = {}) {
122
+ const cacheInfo = getSearchIndexCacheInfo(options);
123
+ const index = await fetchSearchIndex(cacheInfo.indexUrl, options.fetcher);
124
+ await writeCachedSearchIndex(cacheInfo.cachePath, index);
125
+ return index;
126
+ }
127
+ async function loadExplicitSearchIndex(index, fetcher = fetch) {
128
+ if (/^https?:\/\//i.test(index)) {
129
+ return await fetchSearchIndex(index, fetcher);
130
+ }
131
+ try {
132
+ return JSON.parse(await readFile(path2.resolve(index), "utf8"));
133
+ } catch (error) {
134
+ if (isNotFoundError(error)) {
135
+ throw new Error(`missing search index: ${path2.relative(process.cwd(), path2.resolve(index))}`);
136
+ }
137
+ throw error;
138
+ }
139
+ }
140
+ async function fetchSearchIndex(indexUrl, fetcher = fetch) {
141
+ const response = await fetcher(indexUrl);
142
+ if (!response.ok) {
143
+ throw new Error(`failed to fetch search index: ${indexUrl} (${response.status})`);
144
+ }
145
+ return await response.json();
146
+ }
147
+ async function writeCachedSearchIndex(cachePath, index) {
148
+ await mkdir(path2.dirname(cachePath), { recursive: true });
149
+ const tempPath = `${cachePath}.${process.pid}.tmp`;
150
+ await writeFile(tempPath, `${JSON.stringify(index)}
151
+ `, "utf8");
152
+ await rename(tempPath, cachePath);
153
+ }
154
+ function isNotFoundError(error) {
155
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
156
+ }
7
157
 
8
158
  // node_modules/minisearch/dist/es/index.js
9
159
  var ENTRIES = "ENTRIES";
@@ -131,9 +281,9 @@ class SearchableMap {
131
281
  if (!prefix.startsWith(this._prefix)) {
132
282
  throw new Error("Mismatched prefix");
133
283
  }
134
- const [node, path] = trackDown(this._tree, prefix.slice(this._prefix.length));
284
+ const [node, path3] = trackDown(this._tree, prefix.slice(this._prefix.length));
135
285
  if (node === undefined) {
136
- const [parentNode, key] = last(path);
286
+ const [parentNode, key] = last(path3);
137
287
  for (const k of parentNode.keys()) {
138
288
  if (k !== LEAF && k.startsWith(key)) {
139
289
  const node2 = new Map;
@@ -231,18 +381,18 @@ class SearchableMap {
231
381
  return SearchableMap.from(Object.entries(object));
232
382
  }
233
383
  }
234
- var trackDown = (tree, key, path = []) => {
384
+ var trackDown = (tree, key, path3 = []) => {
235
385
  if (key.length === 0 || tree == null) {
236
- return [tree, path];
386
+ return [tree, path3];
237
387
  }
238
388
  for (const k of tree.keys()) {
239
389
  if (k !== LEAF && key.startsWith(k)) {
240
- path.push([tree, k]);
241
- return trackDown(tree.get(k), key.slice(k.length), path);
390
+ path3.push([tree, k]);
391
+ return trackDown(tree.get(k), key.slice(k.length), path3);
242
392
  }
243
393
  }
244
- path.push([tree, key]);
245
- return trackDown(undefined, "", path);
394
+ path3.push([tree, key]);
395
+ return trackDown(undefined, "", path3);
246
396
  };
247
397
  var lookup = (tree, key) => {
248
398
  if (key.length === 0 || tree == null) {
@@ -285,38 +435,38 @@ var createPath = (node, key) => {
285
435
  return node;
286
436
  };
287
437
  var remove = (tree, key) => {
288
- const [node, path] = trackDown(tree, key);
438
+ const [node, path3] = trackDown(tree, key);
289
439
  if (node === undefined) {
290
440
  return;
291
441
  }
292
442
  node.delete(LEAF);
293
443
  if (node.size === 0) {
294
- cleanup(path);
444
+ cleanup(path3);
295
445
  } else if (node.size === 1) {
296
446
  const [key2, value] = node.entries().next().value;
297
- merge(path, key2, value);
447
+ merge(path3, key2, value);
298
448
  }
299
449
  };
300
- var cleanup = (path) => {
301
- if (path.length === 0) {
450
+ var cleanup = (path3) => {
451
+ if (path3.length === 0) {
302
452
  return;
303
453
  }
304
- const [node, key] = last(path);
454
+ const [node, key] = last(path3);
305
455
  node.delete(key);
306
456
  if (node.size === 0) {
307
- cleanup(path.slice(0, -1));
457
+ cleanup(path3.slice(0, -1));
308
458
  } else if (node.size === 1) {
309
459
  const [key2, value] = node.entries().next().value;
310
460
  if (key2 !== LEAF) {
311
- merge(path.slice(0, -1), key2, value);
461
+ merge(path3.slice(0, -1), key2, value);
312
462
  }
313
463
  }
314
464
  };
315
- var merge = (path, key, value) => {
316
- if (path.length === 0) {
465
+ var merge = (path3, key, value) => {
466
+ if (path3.length === 0) {
317
467
  return;
318
468
  }
319
- const [node, nodeKey] = last(path);
469
+ const [node, nodeKey] = last(path3);
320
470
  node.set(nodeKey + key, value);
321
471
  node.delete(nodeKey);
322
472
  };
@@ -1274,14 +1424,29 @@ function compact(value) {
1274
1424
  }
1275
1425
 
1276
1426
  // src/cli.ts
1277
- var defaultSearchIndexUrl = "https://adcli.jiangzhx.com/search-index.json";
1278
1427
  var help = `adcli
1279
1428
 
1280
1429
  Usage:
1281
- adcli doc search <query> [--index ${defaultSearchIndexUrl}] [--platform tencent_ads] [--limit 10] [--json]
1430
+ adcli list [platform] [--json]
1431
+ adcli doc <command>
1432
+ adcli prompt
1433
+ adcli llms
1282
1434
 
1283
1435
  Commands:
1284
- doc search Search published advertising API docs
1436
+ list List supported advertising platforms and capabilities
1437
+ doc Search and sync published advertising API docs
1438
+ prompt Print an AI/Agent instruction prompt for using the docs pack
1439
+ llms Print LLM-readable docs pack entry URLs
1440
+ `;
1441
+ var docHelp = `adcli doc
1442
+
1443
+ Usage:
1444
+ adcli doc search <query> [--platform tencent_ads] [--limit 10] [--json] [--refresh]
1445
+ adcli doc sync
1446
+
1447
+ Commands:
1448
+ search Search published advertising API docs
1449
+ sync Download and cache the latest search index
1285
1450
  `;
1286
1451
  async function main() {
1287
1452
  const args = parseArgs(process.argv.slice(2));
@@ -1289,6 +1454,34 @@ async function main() {
1289
1454
  console.log(help.trim());
1290
1455
  return;
1291
1456
  }
1457
+ if (args.domain === "list") {
1458
+ const index2 = await loadSearchIndex({ index: args.index, refresh: args.refresh });
1459
+ printDocList(index2, args);
1460
+ return;
1461
+ }
1462
+ if (args.domain === "doc" && (!args.command || args.command === "--help" || args.command === "-h" || args.command === "help")) {
1463
+ console.log(docHelp.trim());
1464
+ return;
1465
+ }
1466
+ if (args.domain === "doc" && args.command === "sync") {
1467
+ const index2 = await refreshSearchIndex();
1468
+ const cache = getSearchIndexCacheInfo();
1469
+ console.log(`Synced ${index2.documents.length} docs to ${cache.cachePath}`);
1470
+ return;
1471
+ }
1472
+ if (args.domain === "doc" && args.command === "list") {
1473
+ const index2 = await loadSearchIndex({ index: args.index, refresh: args.refresh });
1474
+ printDocList(index2, args);
1475
+ return;
1476
+ }
1477
+ if (args.domain === "prompt") {
1478
+ printLlms({ ...args, domain: "llms", command: "prompt" });
1479
+ return;
1480
+ }
1481
+ if (args.domain === "llms") {
1482
+ printLlms(args);
1483
+ return;
1484
+ }
1292
1485
  if (args.domain !== "doc" || args.command !== "search") {
1293
1486
  throw new Error(`unknown command: ${[args.domain, args.command].filter(Boolean).join(" ")}`);
1294
1487
  }
@@ -1296,7 +1489,7 @@ async function main() {
1296
1489
  if (!query) {
1297
1490
  throw new Error("missing search query");
1298
1491
  }
1299
- const index = await loadSearchIndex(args.index);
1492
+ const index = await loadSearchIndex({ index: args.index, refresh: args.refresh });
1300
1493
  const results = await searchDocuments({
1301
1494
  query,
1302
1495
  documents: index.documents,
@@ -1322,14 +1515,102 @@ async function main() {
1322
1515
  console.log(` Score: ${result.score.toFixed(2)}`);
1323
1516
  }
1324
1517
  }
1518
+ function printDocList(index, args) {
1519
+ const platformFilter = args.command;
1520
+ const platforms = [...new Set(index.documents.map((document) => document.platform))].sort().filter((platform) => !platformFilter || platform === platformFilter).map((platform) => {
1521
+ const documents = index.documents.filter((document) => document.platform === platform);
1522
+ return {
1523
+ platform,
1524
+ capabilities: [
1525
+ {
1526
+ name: "doc",
1527
+ documents: documents.length,
1528
+ index_url: `https://adcli.jiangzhx.com/${platform}/index.md`,
1529
+ commands: [
1530
+ `adcli doc search <query> --platform ${platform}`
1531
+ ]
1532
+ }
1533
+ ]
1534
+ };
1535
+ });
1536
+ if (platformFilter && platforms.length === 0) {
1537
+ throw new Error(`unsupported platform: ${platformFilter}`);
1538
+ }
1539
+ if (args.json) {
1540
+ console.log(JSON.stringify({ platforms }, null, 2));
1541
+ return;
1542
+ }
1543
+ for (const item of platforms) {
1544
+ console.log(item.platform);
1545
+ for (const capability of item.capabilities) {
1546
+ console.log(` ${capability.name}`);
1547
+ for (const command of capability.commands) {
1548
+ console.log(` ${command}`);
1549
+ }
1550
+ console.log(` docs: ${capability.documents}`);
1551
+ console.log(` index: ${capability.index_url}`);
1552
+ }
1553
+ }
1554
+ }
1555
+ function printLlms(args) {
1556
+ const payload = {
1557
+ name: "AdCLI Docs Pack",
1558
+ base_url: "https://adcli.jiangzhx.com",
1559
+ llms_txt: "https://adcli.jiangzhx.com/llms.txt",
1560
+ llms_full_txt: "https://adcli.jiangzhx.com/llms-full.txt",
1561
+ search_index: "https://adcli.jiangzhx.com/search-index.json",
1562
+ platform_indexes: [
1563
+ "https://adcli.jiangzhx.com/kuaishou/index.md",
1564
+ "https://adcli.jiangzhx.com/oceanengine/index.md",
1565
+ "https://adcli.jiangzhx.com/tencent_ads/index.md"
1566
+ ]
1567
+ };
1568
+ if (args.json) {
1569
+ console.log(JSON.stringify(payload, null, 2));
1570
+ return;
1571
+ }
1572
+ if (args.command === "prompt") {
1573
+ console.log([
1574
+ "Use the AdCLI advertising API docs pack when answering advertising platform API questions.",
1575
+ "",
1576
+ `Start with: ${payload.llms_txt}`,
1577
+ `Use full index when needed: ${payload.llms_full_txt}`,
1578
+ `Use search index for local/tool search: ${payload.search_index}`,
1579
+ "",
1580
+ "Rules:",
1581
+ "- Prefer the Markdown docs from this docs pack over memory.",
1582
+ "- Cite the specific platform document URL or source URL used.",
1583
+ "- If a query names a platform, keep that platform as the primary context but do not ignore relevant cross-platform differences.",
1584
+ "- For API testing or implementation, identify method, path, auth requirement, parameters, response fields, and known limits.",
1585
+ "- If the docs are incomplete or ambiguous, say what is missing instead of guessing."
1586
+ ].join(`
1587
+ `));
1588
+ return;
1589
+ }
1590
+ console.log([
1591
+ "AdCLI Docs Pack",
1592
+ "",
1593
+ `llms.txt: ${payload.llms_txt}`,
1594
+ `llms-full.txt: ${payload.llms_full_txt}`,
1595
+ `search index: ${payload.search_index}`,
1596
+ "",
1597
+ "Platform indexes:",
1598
+ ...payload.platform_indexes.map((url) => `- ${url}`),
1599
+ "",
1600
+ "Prompt for AI/Agent:",
1601
+ " adcli llms prompt"
1602
+ ].join(`
1603
+ `));
1604
+ }
1325
1605
  function parseArgs(argv) {
1326
1606
  const args = {
1327
1607
  domain: argv[0],
1328
1608
  command: argv[1],
1329
1609
  query: [],
1330
- index: process.env.ADCLI_SEARCH_INDEX ?? defaultSearchIndexUrl,
1610
+ index: process.env.ADCLI_SEARCH_INDEX,
1331
1611
  limit: 10,
1332
- json: false
1612
+ json: false,
1613
+ refresh: false
1333
1614
  };
1334
1615
  for (let index = 2;index < argv.length; index += 1) {
1335
1616
  const value = argv[index];
@@ -1342,6 +1623,10 @@ function parseArgs(argv) {
1342
1623
  index += 1;
1343
1624
  continue;
1344
1625
  }
1626
+ if (value === "--refresh") {
1627
+ args.refresh = true;
1628
+ continue;
1629
+ }
1345
1630
  if (value === "--limit") {
1346
1631
  args.limit = Number.parseInt(argv[index + 1] ?? "", 10);
1347
1632
  index += 1;
@@ -1359,24 +1644,6 @@ function parseArgs(argv) {
1359
1644
  }
1360
1645
  return args;
1361
1646
  }
1362
- async function loadSearchIndex(index) {
1363
- if (/^https?:\/\//i.test(index)) {
1364
- const response = await fetch(index);
1365
- if (!response.ok) {
1366
- throw new Error(`failed to fetch search index: ${index} (${response.status})`);
1367
- }
1368
- return await response.json();
1369
- }
1370
- const indexPath = path.resolve(index);
1371
- try {
1372
- return JSON.parse(await readFile(indexPath, "utf8"));
1373
- } catch (error) {
1374
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {
1375
- throw new Error(`missing search index: ${path.relative(process.cwd(), indexPath)}. Use --index ${defaultSearchIndexUrl} or run: bun run build:search-index`);
1376
- }
1377
- throw error;
1378
- }
1379
- }
1380
1647
  main().catch((error) => {
1381
1648
  console.error(error instanceof Error ? error.message : error);
1382
1649
  process.exit(1);
package/docs/commands.md CHANGED
@@ -7,27 +7,43 @@
7
7
 
8
8
  ## 对外 CLI
9
9
 
10
- ### `adcli doc search`
10
+ ### `adcli list`
11
11
 
12
- 搜索已经发布到线上 docs pack 的广告平台文档。全局安装后直接使用:
12
+ 列出当前支持的广告平台和能力。
13
13
 
14
14
  ```bash
15
- adcli doc search "广告消耗"
15
+ adcli list
16
+ adcli list kuaishou
17
+ adcli list --json
16
18
  ```
17
19
 
18
- 项目内开发时也可以用:
20
+ 当前能力:
21
+
22
+ - `doc`: 已发布的文档查询能力,对应命令形态是 `adcli doc search <query> --platform <platform>`。
23
+
24
+ 这个命令会读取本地缓存;缓存不存在时会下载线上 `search-index.json`。
25
+
26
+ 兼容命令:
19
27
 
20
28
  ```bash
21
- bun run adcli doc search "广告消耗"
29
+ adcli doc list
30
+ ```
31
+
32
+ ### `adcli doc search`
33
+
34
+ 搜索已经发布到线上 docs pack 的广告平台文档。全局安装后直接使用:
35
+
36
+ ```bash
37
+ adcli doc search "广告消耗"
22
38
  ```
23
39
 
24
40
  支持参数:
25
41
 
26
42
  ```bash
27
- bun run adcli doc search "广告消耗" --limit 5
28
- bun run adcli doc search "广告消耗" --json
29
- bun run adcli doc search "广告消耗" --index public/search-index.json
30
- bun run adcli doc search "广告消耗" --platform tencent_ads
43
+ adcli doc search "广告消耗" --limit 5
44
+ adcli doc search "广告消耗" --json
45
+ adcli doc search "广告消耗" --index public/search-index.json
46
+ adcli doc search "广告消耗" --platform tencent_ads
31
47
  ```
32
48
 
33
49
  全局 CLI 默认读取:
@@ -36,6 +52,19 @@ bun run adcli doc search "广告消耗" --platform tencent_ads
36
52
  https://adcli.jiangzhx.com/search-index.json
37
53
  ```
38
54
 
55
+ 第一次搜索会下载索引并写入系统标准缓存目录:
56
+
57
+ - macOS: `~/Library/Caches/adcli/search-index.json`
58
+ - Linux: `${XDG_CACHE_HOME:-~/.cache}/adcli/search-index.json`
59
+ - Windows: `%LOCALAPPDATA%/adcli/Cache/search-index.json`
60
+
61
+ 主动更新缓存:
62
+
63
+ ```bash
64
+ adcli doc sync
65
+ adcli doc search "广告消耗" --refresh
66
+ ```
67
+
39
68
  也可以用环境变量覆盖:
40
69
 
41
70
  ```bash
@@ -54,6 +83,38 @@ ADCLI_SEARCH_INDEX=https://example.com/search-index.json adcli doc search "广
54
83
 
55
84
  查询词中包含平台别名时会提升对应平台的排序权重,例如 `广点通`、`腾讯广告` 会提升 `tencent_ads` 文档,但不会硬过滤其他平台。需要明确限制平台时,使用 `--platform tencent_ads`。
56
85
 
86
+ ### `adcli llms`
87
+
88
+ 输出给 AI / Agent 使用的 docs pack 入口。
89
+
90
+ ```bash
91
+ adcli llms
92
+ adcli llms --json
93
+ ```
94
+
95
+ 输出包括:
96
+
97
+ - `llms.txt`
98
+ - `llms-full.txt`
99
+ - `search-index.json`
100
+ - 各平台 index
101
+
102
+ ### `adcli prompt`
103
+
104
+ 输出一段可复制给 AI / Agent 的使用说明。
105
+
106
+ ```bash
107
+ adcli prompt
108
+ ```
109
+
110
+ 这段 prompt 会要求 AI 优先使用 AdCLI 发布的 Markdown 文档,引用具体来源,并在文档不足时明确说明缺口。
111
+
112
+ 兼容命令:
113
+
114
+ ```bash
115
+ adcli llms prompt
116
+ ```
117
+
57
118
  ## 采集命令
58
119
 
59
120
  ### `bun run discover:sources`
@@ -195,7 +256,7 @@ bun run lint
195
256
 
196
257
  ## 当前边界
197
258
 
198
- `adcli` CLI 当前只支持 `doc search`。采集、构建和校验还停留在 `bun run ...` 工程命令层。
259
+ `adcli` CLI 当前支持 `doc search`、`doc sync` 和 `llms` 入口。采集、构建和校验还停留在 `bun run ...` 工程命令层。
199
260
 
200
261
  后续如果要把项目产品化成完整 CLI,可以逐步把这些能力收进 `adcli`:
201
262
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jiangzhx/adcli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "CLI for searching hosted advertising platform API docs.",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.10",
@@ -49,6 +49,7 @@
49
49
  "typescript-eslint": "^8.59.3"
50
50
  },
51
51
  "dependencies": {
52
+ "env-paths": "^4.0.0",
52
53
  "minisearch": "^7.2.0"
53
54
  }
54
55
  }