@itradingai/aiwiki 0.2.7 → 0.2.8

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
@@ -1,4 +1,4 @@
1
- ![AIWiki 宣传图](docs/assets/aiwiki-hero.png)
1
+ ![AIWiki 宣传图](https://raw.githubusercontent.com/iTradingAI/aiwiki/refs/heads/main/docs/assets/aiwiki-hero.png)
2
2
 
3
3
  # AIWiki
4
4
 
@@ -14,7 +14,32 @@ AIWiki 的重点不是替代 Agent 抓网页,而是把 Agent 已经读到的
14
14
  - `2026-05-07`:新增 Codex skill 安装能力,并补上 Agent 协议安装引导,让宿主 Agent 在正式入库前更容易完成对接。
15
15
  - `2026-05-07`:持续打磨初始化体验,修复 setup 提示问题,避免静默套用默认值,并把首次使用流程改成交互式引导。
16
16
 
17
- ## 安装与初始化
17
+ ## 直接发给 AI 帮你安装
18
+
19
+ 如果你希望让 Codex、Claude Code、QClaw、OpenClaw 等 AI 直接帮你完成安装和配置,可以把下面这段话原样发给它,注意修改下你的知识库路径:
20
+
21
+ ```text
22
+ 请帮我安装并配置 AIWiki。
23
+ 安装命令:npm install -g @itradingai/aiwiki@latest
24
+ 我的知识库路径:F:\knowledges
25
+
26
+ 要求:
27
+ 1. 先检查本机 Node.js 是否满足 >=20。
28
+ 2. 如果还没安装 AIWiki,就安装最新版 `@itradingai/aiwiki`。
29
+ 3. 执行 `aiwiki setup --path "我的知识库路径" --yes`,帮我完成知识库初始化。
30
+ 4. 执行 `aiwiki agent list` 检查当前环境支持哪些宿主 Agent。
31
+ 5. 优先为当前 AI/Agent 安装 AIWiki 对接;如果能自动安装,就执行 `aiwiki agent install` 或对应的 `--agent` 命令。
32
+ 6. 如果当前 Agent 不支持自动安装,就执行 `aiwiki prompt agent`,然后把生成的对接协议整理好,告诉我应该粘贴到哪里。
33
+ 7. 完成后,再执行 `aiwiki doctor` 和 `aiwiki status`,确认安装和配置是否正常。
34
+ 8. 最后告诉我:
35
+ - 实际执行了哪些命令
36
+ - 知识库路径是什么
37
+ - Agent 对接是否完成
38
+ - 如果还差手动步骤,明确告诉我下一步怎么做
39
+ ```
40
+
41
+
42
+ ## 手动安装与初始化
18
43
 
19
44
  一次性运行交互式 setup:
20
45
 
@@ -30,7 +55,7 @@ CLI 会询问知识库路径。直接回车会使用默认目录,确认后会
30
55
  npx @itradingai/aiwiki@latest setup --path "F:\knowledge_data\aiwiki" --yes
31
56
  ```
32
57
 
33
- 如果希望长期使用全局命令:
58
+ 如果希望**长期使用**全局命令:
34
59
 
35
60
  ```bash
36
61
  npm install -g @itradingai/aiwiki@latest
@@ -45,34 +70,6 @@ npm install -g @itradingai/aiwiki@latest
45
70
 
46
71
  要求 Node.js `>=20`。
47
72
 
48
- ## 直接发给 AI 帮你安装
49
-
50
- 如果你希望让 Codex、Claude Code、QClaw、OpenClaw 等 AI 直接帮你完成安装和配置,可以把下面这段话原样发给它,注意修改下你的知识库路径:
51
-
52
- ```text
53
- 请帮我安装并配置 AIWiki。
54
-
55
- 要求:
56
- 1. 先检查本机 Node.js 是否满足 >=20。
57
- 2. 如果还没安装 AIWiki,就安装最新版 `@itradingai/aiwiki`。
58
- 3. 执行 `aiwiki setup`,帮我完成知识库初始化;把知识库路径设为 `F:\knowledge_data\aiwiki`。
59
- 4. 执行 `aiwiki agent list` 检查当前环境支持哪些宿主 Agent。
60
- 5. 优先为当前 AI/Agent 安装 AIWiki 对接;如果能自动安装,就执行 `aiwiki agent install` 或对应的 `--agent` 命令。
61
- 6. 如果当前 Agent 不支持自动安装,就执行 `aiwiki prompt agent`,然后把生成的对接协议整理好,告诉我应该粘贴到哪里。
62
- 7. 完成后,再执行 `aiwiki doctor` 和 `aiwiki status`,确认安装和配置是否正常。
63
- 8. 最后告诉我:
64
- - 实际执行了哪些命令
65
- - 知识库路径是什么
66
- - Agent 对接是否完成
67
- - 如果还差手动步骤,明确告诉我下一步怎么做
68
- ```
69
-
70
- 如果你已经确定知识库路径,也可以把上面第 3 步改成直接执行:
71
-
72
- ```bash
73
- aiwiki setup --path "F:\knowledge_data\aiwiki" --yes
74
- ```
75
-
76
73
  ## 让宿主 Agent 学会 AIWiki
77
74
 
78
75
  初始化知识库后,先扫描本机支持的宿主 Agent:
@@ -109,7 +106,7 @@ aiwiki prompt agent
109
106
  完成 setup 和 Agent 安装后,对宿主 Agent 发送:
110
107
 
111
108
  ```text
112
- 入库 https://example.com/article
109
+ 入库 https://mp.weixin.qq.com/s/5i9UJdBOhCB2a1EVp0lVXQ
113
110
  ```
114
111
 
115
112
  宿主 Agent 读取网页后,通过 `aiwiki ingest-agent --stdin` 把结构化内容交给 AIWiki CLI。用户不需要手动保存 payload,也不需要每次输入 `--path`。
@@ -176,6 +173,7 @@ aiwiki ingest-url <url> --content-file <file>
176
173
  - 使用说明:[docs/USAGE.md](docs/USAGE.md)
177
174
  - Agent 对接协议:[docs/AGENT_HANDOFF.md](docs/AGENT_HANDOFF.md)
178
175
  - Obsidian + Dataview 方案:[docs/OBSIDIAN_DATAVIEW_PLAN.md](docs/OBSIDIAN_DATAVIEW_PLAN.md)
176
+ - 发布检查:[docs/RELEASE.md](docs/RELEASE.md)
179
177
  - 架构图:[docs/architecture.svg](docs/architecture.svg)
180
178
 
181
179
  ## 联系与交流
@@ -185,12 +183,12 @@ aiwiki ingest-url <url> --content-file <file>
185
183
  <table>
186
184
  <tr>
187
185
  <td align="center" width="50%">
188
- <img src="docs/assets/join-group.png" alt="扫码进群交流" width="360">
186
+ <img src="https://raw.githubusercontent.com/iTradingAI/aiwiki/refs/heads/main/docs/assets/join-group.png" alt="扫码进群交流" width="360">
189
187
  <br>
190
188
  <strong>扫码进群</strong>
191
189
  </td>
192
190
  <td align="center" width="50%">
193
- <img src="docs/assets/wechat-official-account.png" alt="扫码关注公众号" width="360">
191
+ <img src="https://raw.githubusercontent.com/iTradingAI/aiwiki/refs/heads/main/docs/assets/wechat-official-account.png" alt="扫码关注公众号" width="360">
194
192
  <br>
195
193
  <strong>关注公众号</strong>
196
194
  </td>
package/dist/src/app.js CHANGED
@@ -7,13 +7,12 @@ import { flagBool, flagString, parseArgs } from "./args.js";
7
7
  import { ingestFile, ingestPayload } from "./ingest.js";
8
8
  import { CliError, writeLine } from "./output.js";
9
9
  import { confirmInit, directorySummary, doctor, exists, initWorkspace, promptForSetup, promptForInitPath, readConfig, resolveWorkspace, setDefaultWorkspace, statusSummary } from "./workspace.js";
10
- export const VERSION = "0.2.7";
11
10
  export async function runCli(argv, streams = { stdout: process.stdout, stderr: process.stderr }) {
12
11
  try {
13
12
  const args = parseArgs(argv);
14
13
  const [command, subcommand] = args.positional;
15
14
  if (args.flags.has("version") || command === "version" || command === "-v") {
16
- writeLine(streams.stdout, `aiwiki ${VERSION}`);
15
+ writeLine(streams.stdout, `aiwiki ${await packageVersion()}`);
17
16
  return 0;
18
17
  }
19
18
  if (args.flags.has("help") || !command || command === "help" || command === "-h") {
@@ -415,3 +414,12 @@ function parseJson(text) {
415
414
  throw new CliError("payload must be valid JSON");
416
415
  }
417
416
  }
417
+ async function packageVersion() {
418
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
419
+ const text = await fs.readFile(path.join(packageRoot, "package.json"), "utf8");
420
+ const parsed = JSON.parse(text);
421
+ if (typeof parsed.version !== "string") {
422
+ throw new CliError("package.json is missing version");
423
+ }
424
+ return parsed.version;
425
+ }
@@ -0,0 +1,76 @@
1
+ export function repairMojibake(value) {
2
+ if (!value || !looksLikeUtf8Mojibake(value)) {
3
+ return { value, repaired: false };
4
+ }
5
+ const repaired = decodeUtf8BytesFromLatin1(value) ?? decodeUtf8BytesFromCp1252(value);
6
+ if (!repaired || scoreText(repaired) <= scoreText(value)) {
7
+ return { value, repaired: false };
8
+ }
9
+ return { value: repaired, repaired: true };
10
+ }
11
+ function looksLikeUtf8Mojibake(value) {
12
+ return /(?:Ã|Â|â€|“|”|’|å|ç|è|é|ä|æ|ï¼|ã€)/.test(value);
13
+ }
14
+ function decodeUtf8BytesFromLatin1(value) {
15
+ try {
16
+ return Buffer.from(value, "latin1").toString("utf8");
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ }
22
+ function decodeUtf8BytesFromCp1252(value) {
23
+ const bytes = [];
24
+ for (const char of value) {
25
+ const code = char.codePointAt(0);
26
+ if (code === undefined) {
27
+ continue;
28
+ }
29
+ const mapped = cp1252ReverseMap.get(code);
30
+ if (mapped !== undefined) {
31
+ bytes.push(mapped);
32
+ }
33
+ else if (code <= 0xff) {
34
+ bytes.push(code);
35
+ }
36
+ else {
37
+ return undefined;
38
+ }
39
+ }
40
+ return Buffer.from(bytes).toString("utf8");
41
+ }
42
+ function scoreText(value) {
43
+ const cjk = [...value].filter((char) => /[\u4e00-\u9fff]/u.test(char)).length;
44
+ const mojibake = (value.match(/(?:Ã|Â|â€|“|”|’|å|ç|è|é|ä|æ|ï¼|ã€)/g) ?? []).length;
45
+ const replacement = (value.match(/\uFFFD/g) ?? []).length;
46
+ return cjk * 4 - mojibake * 20 - replacement * 50;
47
+ }
48
+ const cp1252ReverseMap = new Map([
49
+ [0x20ac, 0x80],
50
+ [0x201a, 0x82],
51
+ [0x0192, 0x83],
52
+ [0x201e, 0x84],
53
+ [0x2026, 0x85],
54
+ [0x2020, 0x86],
55
+ [0x2021, 0x87],
56
+ [0x02c6, 0x88],
57
+ [0x2030, 0x89],
58
+ [0x0160, 0x8a],
59
+ [0x2039, 0x8b],
60
+ [0x0152, 0x8c],
61
+ [0x017d, 0x8e],
62
+ [0x2018, 0x91],
63
+ [0x2019, 0x92],
64
+ [0x201c, 0x93],
65
+ [0x201d, 0x94],
66
+ [0x2022, 0x95],
67
+ [0x2013, 0x96],
68
+ [0x2014, 0x97],
69
+ [0x02dc, 0x98],
70
+ [0x2122, 0x99],
71
+ [0x0161, 0x9a],
72
+ [0x203a, 0x9b],
73
+ [0x0153, 0x9c],
74
+ [0x017e, 0x9e],
75
+ [0x0178, 0x9f]
76
+ ]);
@@ -1,3 +1,4 @@
1
+ import { repairMojibake } from "./encoding.js";
1
2
  export function normalizePayload(raw, runStartedAt) {
2
3
  if (!isRecord(raw)) {
3
4
  throw new Error("payload must be a JSON object");
@@ -105,79 +106,3 @@ function stringValue(value) {
105
106
  function isRecord(value) {
106
107
  return typeof value === "object" && value !== null && !Array.isArray(value);
107
108
  }
108
- function repairMojibake(value) {
109
- if (!value || !looksLikeUtf8Mojibake(value)) {
110
- return { value, repaired: false };
111
- }
112
- const repaired = decodeUtf8BytesFromLatin1(value) ?? decodeUtf8BytesFromCp1252(value);
113
- if (!repaired || scoreText(repaired) <= scoreText(value)) {
114
- return { value, repaired: false };
115
- }
116
- return { value: repaired, repaired: true };
117
- }
118
- function looksLikeUtf8Mojibake(value) {
119
- return /(?:Ã|Â|â€|“|”|’|å|ç|è|é|ä|æ|ï¼|ã€)/.test(value);
120
- }
121
- function decodeUtf8BytesFromLatin1(value) {
122
- try {
123
- return Buffer.from(value, "latin1").toString("utf8");
124
- }
125
- catch {
126
- return undefined;
127
- }
128
- }
129
- function decodeUtf8BytesFromCp1252(value) {
130
- const bytes = [];
131
- for (const char of value) {
132
- const code = char.codePointAt(0);
133
- if (code === undefined) {
134
- continue;
135
- }
136
- const mapped = cp1252ReverseMap.get(code);
137
- if (mapped !== undefined) {
138
- bytes.push(mapped);
139
- }
140
- else if (code <= 0xff) {
141
- bytes.push(code);
142
- }
143
- else {
144
- return undefined;
145
- }
146
- }
147
- return Buffer.from(bytes).toString("utf8");
148
- }
149
- function scoreText(value) {
150
- const cjk = [...value].filter((char) => /[\u4e00-\u9fff]/u.test(char)).length;
151
- const mojibake = (value.match(/(?:Ã|Â|â€|“|”|’|å|ç|è|é|ä|æ|ï¼|ã€)/g) ?? []).length;
152
- const replacement = (value.match(/\uFFFD/g) ?? []).length;
153
- return cjk * 4 - mojibake * 20 - replacement * 50;
154
- }
155
- const cp1252ReverseMap = new Map([
156
- [0x20ac, 0x80],
157
- [0x201a, 0x82],
158
- [0x0192, 0x83],
159
- [0x201e, 0x84],
160
- [0x2026, 0x85],
161
- [0x2020, 0x86],
162
- [0x2021, 0x87],
163
- [0x02c6, 0x88],
164
- [0x2030, 0x89],
165
- [0x0160, 0x8a],
166
- [0x2039, 0x8b],
167
- [0x0152, 0x8c],
168
- [0x017d, 0x8e],
169
- [0x2018, 0x91],
170
- [0x2019, 0x92],
171
- [0x201c, 0x93],
172
- [0x201d, 0x94],
173
- [0x2022, 0x95],
174
- [0x2013, 0x96],
175
- [0x2014, 0x97],
176
- [0x02dc, 0x98],
177
- [0x2122, 0x99],
178
- [0x0161, 0x9a],
179
- [0x203a, 0x9b],
180
- [0x0153, 0x9c],
181
- [0x017e, 0x9e],
182
- [0x0178, 0x9f]
183
- ]);
@@ -35,7 +35,19 @@ AIWiki CLI 不做通用网页抓取。网页读取失败时,Agent 仍然要调
35
35
  aiwiki ingest-agent --stdin
36
36
  ```
37
37
 
38
- 7. 读取 CLI 输出,向用户回复入库状态、契合度、摘要、资料卡、处理记录和 Obsidian 审阅入口。
38
+ 7. 如果当前 shell、终端或宿主环境无法保证 stdin UTF-8,先把 payload 写成 UTF-8 JSON 文件,再调用:
39
+
40
+ ```bash
41
+ aiwiki ingest-agent --payload <utf8-json-file>
42
+ ```
43
+
44
+ 8. 读取 CLI 输出,向用户回复入库状态、契合度、摘要、资料卡、处理记录和 Obsidian 审阅入口。
45
+
46
+ ## 编码要求
47
+
48
+ payload 必须是 UTF-8 JSON。Windows PowerShell、批处理、第三方 Agent shell bridge 可能会把中文 JSON 管道按非 UTF-8 编码传递;遇到中文乱码、`payload must be valid JSON` 或无法确认管道编码时,使用 `--payload <utf8-json-file>`。
49
+
50
+ AIWiki 会修复常见 UTF-8 mojibake,但这只是兜底;宿主 Agent 仍应尽量传入干净 UTF-8。
39
51
 
40
52
  ## 成功 payload
41
53
 
@@ -0,0 +1,59 @@
1
+ # AIWiki 发布检查
2
+
3
+ 发布前先确认本地工作区只包含本次发布需要的改动:
4
+
5
+ ```bash
6
+ git status --short --branch
7
+ npm run release:check
8
+ ```
9
+
10
+ `release:check` 会执行测试、构建、`npm pack --dry-run`、CLI 版本一致性检查,以及一次临时知识库入库检查。
11
+
12
+ ## 版本号
13
+
14
+ 版本号以 `package.json` 为唯一来源。CLI 的 `aiwiki --version` 会运行时读取 `package.json`,不要在源码里另写一份版本常量。
15
+
16
+ 升级版本:
17
+
18
+ ```bash
19
+ npm version patch --no-git-tag-version
20
+ ```
21
+
22
+ ## npm 发布
23
+
24
+ 发布前确认 npm 登录账号:
25
+
26
+ ```bash
27
+ npm whoami
28
+ ```
29
+
30
+ 正式发布:
31
+
32
+ ```bash
33
+ npm publish --access public
34
+ ```
35
+
36
+ 如果账号开启了 publish 2FA,普通 token 可能只能 `whoami`,但发布时仍会要求 OTP。此时有两种方式:
37
+
38
+ ```bash
39
+ npm publish --access public --otp <OTP>
40
+ ```
41
+
42
+ 或使用 npm Automation token 写入用户级 `.npmrc`:
43
+
44
+ ```bash
45
+ npm config set //registry.npmjs.org/:_authToken "<NPM_AUTOMATION_TOKEN>"
46
+ ```
47
+
48
+ 发布后验证:
49
+
50
+ ```bash
51
+ npm view @itradingai/aiwiki version
52
+ npm view @itradingai/aiwiki versions --json
53
+ ```
54
+
55
+ ## 包体积
56
+
57
+ npm 包只应包含 CLI 运行和用户文档所需文件。README 中的图片使用 GitHub raw 链接展示,`docs/assets/` 不进入 npm 包。
58
+
59
+ 如果 `npm pack --dry-run` 输出里出现 `docs/assets/`,说明包内容配置回退了,需要先修复 `package.json.files`。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itradingai/aiwiki",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "type": "module",
5
5
  "description": "Agent-first local knowledge production CLI for a single knowledge base.",
6
6
  "license": "MIT",
@@ -22,7 +22,8 @@
22
22
  "files": [
23
23
  "dist/src",
24
24
  "README.md",
25
- "docs",
25
+ "docs/*.md",
26
+ "docs/architecture.svg",
26
27
  "skill"
27
28
  ],
28
29
  "bin": {
@@ -32,6 +33,7 @@
32
33
  "build": "tsc -p tsconfig.json",
33
34
  "test": "npm run build && node --test \"dist/tests/*.test.js\"",
34
35
  "check": "npm run test",
36
+ "release:check": "npm test && node scripts/release-check.mjs",
35
37
  "prepack": "npm run build"
36
38
  },
37
39
  "devDependencies": {
package/skill/SKILL.md CHANGED
@@ -21,6 +21,12 @@ The host Agent reads the webpage or user-provided body, then passes structured c
21
21
  aiwiki ingest-agent --stdin
22
22
  ```
23
23
 
24
+ If the current shell or Agent bridge cannot guarantee UTF-8 stdin, write the payload as a UTF-8 JSON file and call:
25
+
26
+ ```bash
27
+ aiwiki ingest-agent --payload <utf8-json-file>
28
+ ```
29
+
24
30
  For local files, call:
25
31
 
26
32
  ```bash
Binary file
Binary file