@page.su/ai-blog-cli 0.1.0-beta.1

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.
Files changed (146) hide show
  1. package/README.md +145 -0
  2. package/dist/api-client.d.ts +39 -0
  3. package/dist/api-client.d.ts.map +1 -0
  4. package/dist/api-client.js +163 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/api-client.test.d.ts +2 -0
  7. package/dist/api-client.test.d.ts.map +1 -0
  8. package/dist/api-client.test.js +83 -0
  9. package/dist/api-client.test.js.map +1 -0
  10. package/dist/cli.d.ts +3 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +74 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/commands/build.d.ts +4 -0
  15. package/dist/commands/build.d.ts.map +1 -0
  16. package/dist/commands/build.js +158 -0
  17. package/dist/commands/build.js.map +1 -0
  18. package/dist/commands/code-repo.d.ts +4 -0
  19. package/dist/commands/code-repo.d.ts.map +1 -0
  20. package/dist/commands/code-repo.js +102 -0
  21. package/dist/commands/code-repo.js.map +1 -0
  22. package/dist/commands/comments.d.ts +4 -0
  23. package/dist/commands/comments.d.ts.map +1 -0
  24. package/dist/commands/comments.js +53 -0
  25. package/dist/commands/comments.js.map +1 -0
  26. package/dist/commands/demo.d.ts +4 -0
  27. package/dist/commands/demo.d.ts.map +1 -0
  28. package/dist/commands/demo.js +72 -0
  29. package/dist/commands/demo.js.map +1 -0
  30. package/dist/commands/helpers.d.ts +21 -0
  31. package/dist/commands/helpers.d.ts.map +1 -0
  32. package/dist/commands/helpers.js +66 -0
  33. package/dist/commands/helpers.js.map +1 -0
  34. package/dist/commands/knowledge.d.ts +4 -0
  35. package/dist/commands/knowledge.d.ts.map +1 -0
  36. package/dist/commands/knowledge.js +146 -0
  37. package/dist/commands/knowledge.js.map +1 -0
  38. package/dist/commands/post.d.ts +4 -0
  39. package/dist/commands/post.d.ts.map +1 -0
  40. package/dist/commands/post.js +207 -0
  41. package/dist/commands/post.js.map +1 -0
  42. package/dist/commands/scout.d.ts +4 -0
  43. package/dist/commands/scout.d.ts.map +1 -0
  44. package/dist/commands/scout.js +48 -0
  45. package/dist/commands/scout.js.map +1 -0
  46. package/dist/commands/series.d.ts +4 -0
  47. package/dist/commands/series.d.ts.map +1 -0
  48. package/dist/commands/series.js +101 -0
  49. package/dist/commands/series.js.map +1 -0
  50. package/dist/commands/skills.d.ts +3 -0
  51. package/dist/commands/skills.d.ts.map +1 -0
  52. package/dist/commands/skills.js +79 -0
  53. package/dist/commands/skills.js.map +1 -0
  54. package/dist/commands/taxonomy.d.ts +4 -0
  55. package/dist/commands/taxonomy.d.ts.map +1 -0
  56. package/dist/commands/taxonomy.js +52 -0
  57. package/dist/commands/taxonomy.js.map +1 -0
  58. package/dist/commands/uploads.d.ts +4 -0
  59. package/dist/commands/uploads.d.ts.map +1 -0
  60. package/dist/commands/uploads.js +37 -0
  61. package/dist/commands/uploads.js.map +1 -0
  62. package/dist/config.d.ts +19 -0
  63. package/dist/config.d.ts.map +1 -0
  64. package/dist/config.js +84 -0
  65. package/dist/config.js.map +1 -0
  66. package/dist/config.test.d.ts +2 -0
  67. package/dist/config.test.d.ts.map +1 -0
  68. package/dist/config.test.js +53 -0
  69. package/dist/config.test.js.map +1 -0
  70. package/dist/index.d.ts +3 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +100 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/prompts/index.d.ts +9 -0
  75. package/dist/prompts/index.d.ts.map +1 -0
  76. package/dist/prompts/index.js +178 -0
  77. package/dist/prompts/index.js.map +1 -0
  78. package/dist/resources/syntax-spec.d.ts +23 -0
  79. package/dist/resources/syntax-spec.d.ts.map +1 -0
  80. package/dist/resources/syntax-spec.js +105 -0
  81. package/dist/resources/syntax-spec.js.map +1 -0
  82. package/dist/resources/syntax-spec.test.d.ts +2 -0
  83. package/dist/resources/syntax-spec.test.d.ts.map +1 -0
  84. package/dist/resources/syntax-spec.test.js +47 -0
  85. package/dist/resources/syntax-spec.test.js.map +1 -0
  86. package/dist/tools/build.d.ts +13 -0
  87. package/dist/tools/build.d.ts.map +1 -0
  88. package/dist/tools/build.js +181 -0
  89. package/dist/tools/build.js.map +1 -0
  90. package/dist/tools/code-repos.d.ts +5 -0
  91. package/dist/tools/code-repos.d.ts.map +1 -0
  92. package/dist/tools/code-repos.js +149 -0
  93. package/dist/tools/code-repos.js.map +1 -0
  94. package/dist/tools/comments.d.ts +12 -0
  95. package/dist/tools/comments.d.ts.map +1 -0
  96. package/dist/tools/comments.js +87 -0
  97. package/dist/tools/comments.js.map +1 -0
  98. package/dist/tools/demos.d.ts +5 -0
  99. package/dist/tools/demos.d.ts.map +1 -0
  100. package/dist/tools/demos.js +98 -0
  101. package/dist/tools/demos.js.map +1 -0
  102. package/dist/tools/glossary.d.ts +4 -0
  103. package/dist/tools/glossary.d.ts.map +1 -0
  104. package/dist/tools/glossary.js +139 -0
  105. package/dist/tools/glossary.js.map +1 -0
  106. package/dist/tools/helpers.d.ts +44 -0
  107. package/dist/tools/helpers.d.ts.map +1 -0
  108. package/dist/tools/helpers.js +65 -0
  109. package/dist/tools/helpers.js.map +1 -0
  110. package/dist/tools/knowledge.d.ts +4 -0
  111. package/dist/tools/knowledge.d.ts.map +1 -0
  112. package/dist/tools/knowledge.js +140 -0
  113. package/dist/tools/knowledge.js.map +1 -0
  114. package/dist/tools/math-concepts.d.ts +4 -0
  115. package/dist/tools/math-concepts.d.ts.map +1 -0
  116. package/dist/tools/math-concepts.js +158 -0
  117. package/dist/tools/math-concepts.js.map +1 -0
  118. package/dist/tools/posts.d.ts +35 -0
  119. package/dist/tools/posts.d.ts.map +1 -0
  120. package/dist/tools/posts.js +278 -0
  121. package/dist/tools/posts.js.map +1 -0
  122. package/dist/tools/scout.d.ts +10 -0
  123. package/dist/tools/scout.d.ts.map +1 -0
  124. package/dist/tools/scout.js +111 -0
  125. package/dist/tools/scout.js.map +1 -0
  126. package/dist/tools/series.d.ts +12 -0
  127. package/dist/tools/series.d.ts.map +1 -0
  128. package/dist/tools/series.js +120 -0
  129. package/dist/tools/series.js.map +1 -0
  130. package/dist/tools/syntax-capabilities.d.ts +15 -0
  131. package/dist/tools/syntax-capabilities.d.ts.map +1 -0
  132. package/dist/tools/syntax-capabilities.js +859 -0
  133. package/dist/tools/syntax-capabilities.js.map +1 -0
  134. package/dist/tools/taxonomy.d.ts +4 -0
  135. package/dist/tools/taxonomy.d.ts.map +1 -0
  136. package/dist/tools/taxonomy.js +73 -0
  137. package/dist/tools/taxonomy.js.map +1 -0
  138. package/dist/tools/uploads.d.ts +15 -0
  139. package/dist/tools/uploads.d.ts.map +1 -0
  140. package/dist/tools/uploads.js +56 -0
  141. package/dist/tools/uploads.js.map +1 -0
  142. package/dist/tools/workflows.d.ts +9 -0
  143. package/dist/tools/workflows.d.ts.map +1 -0
  144. package/dist/tools/workflows.js +249 -0
  145. package/dist/tools/workflows.js.map +1 -0
  146. package/package.json +41 -0
package/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # @page.su/ai-blog-cli
2
+
3
+ CLI tool for AI agents and humans to write, manage, and publish posts on ai-blog.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ # Global install (recommended)
9
+ npm install -g @page.su/ai-blog-cli
10
+
11
+ # Or use with npx (no install needed)
12
+ npx @page.su/ai-blog-cli post list --json
13
+ ```
14
+
15
+ ## Configuration
16
+
17
+ Create a token at `/admin/settings/tokens` in your ai-blog admin panel, then configure via one of these methods:
18
+
19
+ ### Option A: ~/.aib.env file (recommended)
20
+
21
+ ```bash
22
+ # Create ~/.aib.env with your credentials
23
+ cat > ~/.aib.env << 'EOF'
24
+ AI_BLOG_BASE_URL=https://your-blog.example.com
25
+ AI_BLOG_PAT=aib_pat_your_token_here
26
+ EOF
27
+ ```
28
+
29
+ ### Option B: Environment variables
30
+
31
+ ```bash
32
+ export AI_BLOG_BASE_URL=https://your-blog.example.com
33
+ export AI_BLOG_PAT=aib_pat_your_token_here
34
+ ```
35
+
36
+ ### Option C: Local .aib.env (project-level override)
37
+
38
+ Create `.aib.env` in your project directory. Overrides `~/.aib.env` but not environment variables.
39
+
40
+ ### Configuration priority
41
+
42
+ 1. Environment variables (highest)
43
+ 2. `./.aib.env` (current directory)
44
+ 3. `~/.aib.env` (home directory, lowest)
45
+
46
+ ### Optional settings
47
+
48
+ | Variable | Default | Description |
49
+ |---|---|---|
50
+ | `AI_BLOG_REQUEST_TIMEOUT_MS` | `30000` | HTTP request timeout in milliseconds |
51
+
52
+ ## Quick start
53
+
54
+ ```bash
55
+ # View skills reference (~500 tokens, for Agent system prompts)
56
+ aib skills
57
+
58
+ # View all commands
59
+ aib --help
60
+
61
+ # View command group details
62
+ aib post --help
63
+
64
+ # Posts
65
+ aib post list --json
66
+ aib post create --title "Title" --content-file draft.md --status draft
67
+ aib post validate --content-file draft.md
68
+ aib post publish <id>
69
+
70
+ # Large posts (save tokens)
71
+ aib post outline <id>
72
+ aib post section <id> --index 3
73
+ aib post replace-section <id> --index 3 --content-file new.md
74
+
75
+ # Taxonomy
76
+ aib taxonomy list --json
77
+
78
+ # Knowledge
79
+ aib knowledge find "Promise"
80
+
81
+ # Scout research
82
+ aib scout search "LangGraph" --min-score 7 --json
83
+ ```
84
+
85
+ ## Commands
86
+
87
+ | Command group | Description |
88
+ |---|---|
89
+ | `aib post` | Create, read, update, delete, validate posts |
90
+ | `aib demo` | Manage interactive live demos |
91
+ | `aib code-repo` | Manage code repositories (N:1 sharing) |
92
+ | `aib build` | Build advanced markdown syntax blocks |
93
+ | `aib knowledge` | Manage knowledge entries (terms & math) |
94
+ | `aib scout` | Search Scout collected tech items |
95
+ | `aib series` | Manage article series |
96
+ | `aib taxonomy` | Manage categories and tags |
97
+ | `aib comment` | Create comments and manage AI bots |
98
+ | `aib upload` | Upload images to blog OSS |
99
+ | `aib skills` | Output skills reference for Agent prompts |
100
+
101
+ ## Conventions
102
+
103
+ - Add `--json` to any command for structured JSON output
104
+ - Use `--content-file <path>` for large content (avoids arg length limits)
105
+ - Pipe support: `cat draft.md | aib post validate --stdin`
106
+ - Call `aib <command> --help` for detailed usage
107
+
108
+ ## Agent integration
109
+
110
+ ### Python (subprocess)
111
+
112
+ ```python
113
+ import subprocess, json
114
+
115
+ # Get skills reference for system prompt
116
+ skills = subprocess.run(["aib", "skills"], capture_output=True, text=True).stdout
117
+
118
+ # Execute commands and parse JSON
119
+ result = subprocess.run(["aib", "post", "list", "--json"], capture_output=True, text=True)
120
+ posts = json.loads(result.stdout)
121
+ ```
122
+
123
+ ### Qoder / Cursor / Claude Code
124
+
125
+ Agents with shell access can call `aib` directly. Inject `aib skills` output into the system prompt for command discovery.
126
+
127
+ ## Development
128
+
129
+ ```bash
130
+ # Build
131
+ pnpm build
132
+
133
+ # Dev mode (tsx watch)
134
+ pnpm dev
135
+
136
+ # Test
137
+ pnpm test
138
+
139
+ # Publish
140
+ npm publish --access public
141
+ ```
142
+
143
+ ## License
144
+
145
+ MIT
@@ -0,0 +1,39 @@
1
+ import type { CliConfig } from "./config.js";
2
+ /**
3
+ * 对 ai-blog `/api/cli/**` 的薄 HTTP 客户端。
4
+ *
5
+ * 设计要点:
6
+ * - 自动注入 `Authorization: Bearer <PAT>` 与 `Content-Type: application/json`
7
+ * - 自动加 AbortController 超时(避免 stdio 长 hang)
8
+ * - 把非 2xx 响应统一抛 `ApiClientError`,含 status / message / issues 三类信息,
9
+ * 上层 tool 可以直接把 message 透传给 AI 客户端
10
+ */
11
+ export declare class ApiClientError extends Error {
12
+ readonly status: number;
13
+ readonly issues?: unknown;
14
+ constructor(message: string, status: number, issues?: unknown);
15
+ }
16
+ export interface ApiClient {
17
+ /** 通用 GET,path 以 `/api/cli/...` 开头 */
18
+ get<T>(path: string, query?: Record<string, string | number | undefined>): Promise<T>;
19
+ /** 通用 POST */
20
+ post<T>(path: string, body?: unknown): Promise<T>;
21
+ /** 通用 PATCH */
22
+ patch<T>(path: string, body?: unknown): Promise<T>;
23
+ /** 通用 DELETE */
24
+ delete<T>(path: string): Promise<T>;
25
+ /** 把响应体当成原始文本读取(用于 syntax-spec 资源) */
26
+ getText(path: string): Promise<string>;
27
+ }
28
+ /**
29
+ * 当前 CLI 对应的 API 版本号。
30
+ *
31
+ * 此版本号对应后端 `CLI_API_CURRENT_VERSION` 常量。
32
+ * CLI 升级时应同步更新此值,确保与后端兼容。
33
+ *
34
+ * 格式:YYYY-MM-DD(日期版本号,类似 Stripe/GitHub 风格)
35
+ */
36
+ export declare const CLI_CLIENT_API_VERSION = "2026-05-12";
37
+ /** 工厂函数:根据配置创建一个 ApiClient 实例 */
38
+ export declare function createApiClient(config: CliConfig): ApiClient;
39
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;;;;GAQG;AAEH,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;gBACd,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO;CAM9D;AAED,MAAM,WAAW,SAAS;IACxB,sCAAsC;IACtC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACtF,cAAc;IACd,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAClD,eAAe;IACf,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACnD,gBAAgB;IAChB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACpC,sCAAsC;IACtC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACxC;AA8DD;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,iCAAiC;AACjC,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAoF5D"}
@@ -0,0 +1,163 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ /**
5
+ * 对 ai-blog `/api/cli/**` 的薄 HTTP 客户端。
6
+ *
7
+ * 设计要点:
8
+ * - 自动注入 `Authorization: Bearer <PAT>` 与 `Content-Type: application/json`
9
+ * - 自动加 AbortController 超时(避免 stdio 长 hang)
10
+ * - 把非 2xx 响应统一抛 `ApiClientError`,含 status / message / issues 三类信息,
11
+ * 上层 tool 可以直接把 message 透传给 AI 客户端
12
+ */
13
+ export class ApiClientError extends Error {
14
+ status;
15
+ issues;
16
+ constructor(message, status, issues) {
17
+ super(message);
18
+ this.name = "ApiClientError";
19
+ this.status = status;
20
+ this.issues = issues;
21
+ }
22
+ }
23
+ /** 由 baseUrl + path + query 拼出完整 URL */
24
+ function buildUrl(baseUrl, path, query) {
25
+ const url = new URL(path.startsWith("/") ? path : `/${path}`, baseUrl);
26
+ if (query) {
27
+ for (const [key, value] of Object.entries(query)) {
28
+ if (value === undefined || value === null) {
29
+ continue;
30
+ }
31
+ url.searchParams.set(key, String(value));
32
+ }
33
+ }
34
+ return url.toString();
35
+ }
36
+ /** 从 fetch Response 解析错误,抛 ApiClientError */
37
+ async function throwApiError(response) {
38
+ let message = `Request failed with status ${response.status}`;
39
+ let issues;
40
+ try {
41
+ const data = (await response.json());
42
+ if (typeof data.message === "string" && data.message) {
43
+ message = data.message;
44
+ }
45
+ if (data.issues !== undefined) {
46
+ issues = data.issues;
47
+ }
48
+ }
49
+ catch {
50
+ // 非 JSON 响应,保留默认 message
51
+ }
52
+ throw new ApiClientError(message, response.status, issues);
53
+ }
54
+ /**
55
+ * 从 package.json 读取版本号。
56
+ *
57
+ * 编译后 dist/api-client.js 位于 dist/ 目录,package.json 在上一级。
58
+ * 首次读取后缓存,避免重复 I/O。
59
+ */
60
+ let cachedVersion;
61
+ function readPackageVersion() {
62
+ if (cachedVersion === undefined) {
63
+ try {
64
+ // 编译后 dist/ 下运行时 import.meta.url 指向 dist/api-client.js
65
+ const distDir = dirname(fileURLToPath(import.meta.url));
66
+ const pkgPath = resolve(distDir, "..", "package.json");
67
+ const raw = readFileSync(pkgPath, "utf-8");
68
+ const pkg = JSON.parse(raw);
69
+ cachedVersion = pkg.version ?? "0.0.0";
70
+ }
71
+ catch {
72
+ cachedVersion = "0.0.0";
73
+ }
74
+ }
75
+ return cachedVersion;
76
+ }
77
+ /**
78
+ * 当前 CLI 对应的 API 版本号。
79
+ *
80
+ * 此版本号对应后端 `CLI_API_CURRENT_VERSION` 常量。
81
+ * CLI 升级时应同步更新此值,确保与后端兼容。
82
+ *
83
+ * 格式:YYYY-MM-DD(日期版本号,类似 Stripe/GitHub 风格)
84
+ */
85
+ export const CLI_CLIENT_API_VERSION = "2026-05-12";
86
+ /** 工厂函数:根据配置创建一个 ApiClient 实例 */
87
+ export function createApiClient(config) {
88
+ const serverVersion = readPackageVersion();
89
+ const baseHeaders = {
90
+ Authorization: `Bearer ${config.pat}`,
91
+ "User-Agent": `ai-blog-cli/${serverVersion}`,
92
+ "x-api-version": CLI_CLIENT_API_VERSION,
93
+ };
94
+ /** 统一发起请求的内部实现 */
95
+ async function request(method, path, init = {}) {
96
+ const controller = new AbortController();
97
+ const timer = setTimeout(() => controller.abort(), config.requestTimeoutMs);
98
+ try {
99
+ const headers = { ...baseHeaders };
100
+ let body;
101
+ if (init.body !== undefined) {
102
+ headers["Content-Type"] = "application/json";
103
+ body = JSON.stringify(init.body);
104
+ }
105
+ const response = await fetch(buildUrl(config.baseUrl, path, init.query), {
106
+ method,
107
+ headers,
108
+ body,
109
+ signal: controller.signal,
110
+ });
111
+ if (!response.ok) {
112
+ return throwApiError(response);
113
+ }
114
+ // 204 No Content
115
+ if (response.status === 204) {
116
+ return undefined;
117
+ }
118
+ const contentType = response.headers.get("content-type") ?? "";
119
+ if (contentType.includes("application/json")) {
120
+ return (await response.json());
121
+ }
122
+ // 非 JSON 响应(如 text/markdown)当字符串返回
123
+ return (await response.text());
124
+ }
125
+ finally {
126
+ clearTimeout(timer);
127
+ }
128
+ }
129
+ return {
130
+ get(path, query) {
131
+ return request("GET", path, { query });
132
+ },
133
+ post(path, body) {
134
+ return request("POST", path, { body });
135
+ },
136
+ patch(path, body) {
137
+ return request("PATCH", path, { body });
138
+ },
139
+ delete(path) {
140
+ return request("DELETE", path);
141
+ },
142
+ async getText(path) {
143
+ // 直接绕过 JSON 自动反序列化,单独走一遍以拿到原始文本
144
+ const controller = new AbortController();
145
+ const timer = setTimeout(() => controller.abort(), config.requestTimeoutMs);
146
+ try {
147
+ const response = await fetch(buildUrl(config.baseUrl, path), {
148
+ method: "GET",
149
+ headers: baseHeaders,
150
+ signal: controller.signal,
151
+ });
152
+ if (!response.ok) {
153
+ return throwApiError(response);
154
+ }
155
+ return await response.text();
156
+ }
157
+ finally {
158
+ clearTimeout(timer);
159
+ }
160
+ },
161
+ };
162
+ }
163
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=api-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.test.d.ts","sourceRoot":"","sources":["../src/api-client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,83 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { ApiClientError, createApiClient } from "./api-client.js";
3
+ /**
4
+ * 验证 ApiClient:
5
+ * - 自动注入 Authorization 头
6
+ * - 自动 JSON 序列化与反序列化
7
+ * - 非 2xx 响应抛 ApiClientError,含 message / issues
8
+ * - getText 直接返回原始字符串
9
+ */
10
+ describe("createApiClient", () => {
11
+ const config = {
12
+ baseUrl: "https://example.com",
13
+ pat: "aib_pat_xxxxxx",
14
+ requestTimeoutMs: 1_000,
15
+ };
16
+ let fetchSpy;
17
+ beforeEach(() => {
18
+ fetchSpy = vi.spyOn(globalThis, "fetch");
19
+ });
20
+ afterEach(() => {
21
+ fetchSpy.mockRestore();
22
+ });
23
+ it("get 成功时返回 JSON 数据并自动带 Authorization", async () => {
24
+ fetchSpy.mockResolvedValue(new Response(JSON.stringify({ ok: true, items: [1, 2] }), {
25
+ status: 200,
26
+ headers: { "content-type": "application/json" },
27
+ }));
28
+ const client = createApiClient(config);
29
+ const result = await client.get("/api/cli/posts", { limit: 5 });
30
+ expect(result.items).toEqual([1, 2]);
31
+ const callArgs = fetchSpy.mock.calls[0];
32
+ expect(callArgs[0]).toBe("https://example.com/api/cli/posts?limit=5");
33
+ const init = callArgs[1];
34
+ const headers = init.headers;
35
+ expect(headers.Authorization).toBe(`Bearer ${config.pat}`);
36
+ });
37
+ it("post 自动 JSON 序列化 body 并带 Content-Type", async () => {
38
+ fetchSpy.mockResolvedValue(new Response(JSON.stringify({ ok: true }), {
39
+ status: 200,
40
+ headers: { "content-type": "application/json" },
41
+ }));
42
+ const client = createApiClient(config);
43
+ await client.post("/api/cli/build/image", { url: "https://x", alt: "y" });
44
+ const init = fetchSpy.mock.calls[0][1];
45
+ expect(init.method).toBe("POST");
46
+ expect(init.body).toBe(JSON.stringify({ url: "https://x", alt: "y" }));
47
+ const headers = init.headers;
48
+ expect(headers["Content-Type"]).toBe("application/json");
49
+ });
50
+ it("非 2xx 响应抛 ApiClientError,并保留 message / issues", async () => {
51
+ fetchSpy.mockResolvedValue(new Response(JSON.stringify({ message: "Invalid payload", issues: { fieldErrors: { title: ["required"] } } }), {
52
+ status: 400,
53
+ headers: { "content-type": "application/json" },
54
+ }));
55
+ const client = createApiClient(config);
56
+ await expect(client.post("/api/cli/posts", {})).rejects.toMatchObject({
57
+ name: "ApiClientError",
58
+ status: 400,
59
+ message: "Invalid payload",
60
+ });
61
+ });
62
+ it("ApiClientError 是 Error 子类,instanceof 检查通过", async () => {
63
+ fetchSpy.mockResolvedValue(new Response("oops", { status: 500 }));
64
+ const client = createApiClient(config);
65
+ try {
66
+ await client.get("/api/cli/posts");
67
+ throw new Error("expected throw");
68
+ }
69
+ catch (error) {
70
+ expect(error).toBeInstanceOf(ApiClientError);
71
+ }
72
+ });
73
+ it("getText 直接返回原始文本", async () => {
74
+ fetchSpy.mockResolvedValue(new Response("# Hello", {
75
+ status: 200,
76
+ headers: { "content-type": "text/markdown" },
77
+ }));
78
+ const client = createApiClient(config);
79
+ const text = await client.getText("/api/cli/syntax-spec/overview");
80
+ expect(text).toBe("# Hello");
81
+ });
82
+ });
83
+ //# sourceMappingURL=api-client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.test.js","sourceRoot":"","sources":["../src/api-client.test.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname, resolve } from "node:path";
5
+ import { Command } from "commander";
6
+ import { createApiClient } from "./api-client.js";
7
+ import { loadCliConfig } from "./config.js";
8
+ import { registerPostCommands } from "./commands/post.js";
9
+ import { registerDemoCommands } from "./commands/demo.js";
10
+ import { registerCodeRepoCommands } from "./commands/code-repo.js";
11
+ import { registerBuildCommands } from "./commands/build.js";
12
+ import { registerKnowledgeCommands } from "./commands/knowledge.js";
13
+ import { registerScoutCommands } from "./commands/scout.js";
14
+ import { registerSeriesCommands } from "./commands/series.js";
15
+ import { registerTaxonomyCommands } from "./commands/taxonomy.js";
16
+ import { registerCommentCommands } from "./commands/comments.js";
17
+ import { registerUploadCommands } from "./commands/uploads.js";
18
+ import { registerSkillsCommand } from "./commands/skills.js";
19
+ function readOwnVersion() {
20
+ const distDir = dirname(fileURLToPath(import.meta.url));
21
+ const pkgPath = resolve(distDir, "..", "package.json");
22
+ try {
23
+ const raw = readFileSync(pkgPath, "utf-8");
24
+ const pkg = JSON.parse(raw);
25
+ return pkg.version ?? "0.0.0";
26
+ }
27
+ catch {
28
+ return "0.0.0";
29
+ }
30
+ }
31
+ /**
32
+ * 创建延迟初始化的 ApiClient 代理。
33
+ *
34
+ * 在实际方法被调用时才加载配置和创建客户端,
35
+ * 这样 --help / --version / skills 等命令不需要环境变量也能运行。
36
+ */
37
+ function createLazyApi() {
38
+ let cached = null;
39
+ return new Proxy({}, {
40
+ get(_, prop) {
41
+ if (cached === null) {
42
+ const config = loadCliConfig();
43
+ cached = createApiClient(config);
44
+ }
45
+ const value = Reflect.get(cached, prop);
46
+ return typeof value === "function" ? value.bind(cached) : value;
47
+ },
48
+ });
49
+ }
50
+ async function main() {
51
+ const api = createLazyApi();
52
+ const program = new Command();
53
+ program
54
+ .name("aib")
55
+ .description("AI Blog CLI — write, manage, and publish posts")
56
+ .version(readOwnVersion());
57
+ registerPostCommands(program, api);
58
+ registerDemoCommands(program, api);
59
+ registerCodeRepoCommands(program, api);
60
+ registerBuildCommands(program, api);
61
+ registerKnowledgeCommands(program, api);
62
+ registerScoutCommands(program, api);
63
+ registerSeriesCommands(program, api);
64
+ registerTaxonomyCommands(program, api);
65
+ registerCommentCommands(program, api);
66
+ registerUploadCommands(program, api);
67
+ registerSkillsCommand(program);
68
+ program.parse();
69
+ }
70
+ main().catch((error) => {
71
+ console.error(`aib: ${error instanceof Error ? error.message : String(error)}`);
72
+ process.exit(1);
73
+ });
74
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerBuildCommands(program: Command, api: ApiClient): void;
4
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGlD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CA6I5E"}