csdn-private-ai 0.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zhuyuanzheng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # CSDN Private AI
2
+
3
+ 在 VS Code 侧边栏里复用 CSDN 博客右侧 AI 助手的私有接口。
4
+
5
+ ## 功能
6
+
7
+ - 支持绑定一个 `blog.csdn.net/.../article/details/{articleId}` 链接,或直接输入纯数字 `articleId`
8
+ - 手动保存完整 CSDN Cookie 到 VS Code `SecretStorage`
9
+ - 文章校验仍走:
10
+ - `GET /phoenix/web/v1/assistant/ai-config`
11
+ - 当前聊天协议已切到浏览器真实在用的 smart chat 链路:
12
+ - `GET /aisearch/v2/api/smart/session/getBlogSessionId`
13
+ - `POST /aisearch/v2/api/stream/smart/chat/message/stream`
14
+ - 侧边栏线程和消息仍只保存在本地 `workspaceState`
15
+ - 插件不会主动调用远端历史读取或 `submitAnswer` 之类的提交接口
16
+ - 当前协议本身带 `sessionId`,服务端是否内部维护会话状态由 CSDN 决定,插件不额外做远端历史同步
17
+ - 每条 AI 回复右上角提供“复制”按钮,可一键把当前答案写入系统剪贴板
18
+ - 活动栏图标已改为 VS Code 兼容的单色 SVG,不再使用带底色的大方块
19
+ - 当前固定不注入文章正文,上游请求里始终按通用问答模式发送:
20
+ - `docIds: ""`
21
+ - `webSearch: "1"`
22
+
23
+ ## 当前协议说明
24
+
25
+ - 当前插件不再走旧的 `assistant/completion`。
26
+ - 现在的请求体已对齐到浏览器文章右侧 AI 的真实格式:
27
+ - `inputs.docIds`
28
+ - `inputs.modelId`
29
+ - `inputs.platform`
30
+ - `inputs.url`
31
+ - `inputs.webSearch`
32
+ - `query`
33
+ - `queryId`
34
+ - `sessionId`
35
+ - `trace_id`
36
+ - URL 上的 `sign` 现在按 `query + queryId + sessionId` 拼接后生成。
37
+ - 具体算法不是直接 `md5(queryString)`,而是:
38
+ - 先把拼好的 query string 按 UTF-8 转成 Base64
39
+ - 再做 `md5(\`[#\${md5(base64Query)}#]\`)`
40
+ - 网关签名使用当前浏览器 bundle 里的 smart chat AK/SK。
41
+ - GET 请求参与 HMAC 时,空 query 参数要按 CSDN 自己的 `$y` 逻辑规范化:
42
+ - 浏览器 URL 可以是 `type=`
43
+ - 但签名串里实际参与计算的是 `type`
44
+ - `getBlogSessionId` 当前真实返回里,`data` 可能不是纯字符串,而是 `{ sid, count }`
45
+ - SSE 解析按浏览器真实返回的事件流处理:
46
+ - `event: "message"` 追加文本
47
+ - `event: "message_end"` 结束生成
48
+ - 其他 workflow 事件默认只做状态判断,不直接拼进正文,避免重复输出
49
+
50
+ ## 开发调试
51
+
52
+ 1. `npm install`
53
+ 2. `npm run compile`
54
+ 3. 用 VS Code 打开当前项目根目录
55
+ 4. 按 `F5`,或者在“运行和调试”里选择 `运行 CSDN Private AI 插件`
56
+ 5. 弹出 `Extension Development Host` 后,打开左侧 `CSDN AI` 容器
57
+ 6. 点击 `绑定链接 / ID`
58
+ - 可以输入完整的 `blog.csdn.net/.../article/details/{articleId}` 链接
59
+ - 也可以在内网环境下直接输入纯数字 `articleId`
60
+ 7. 点击 `更新 CSDN Cookie`
61
+ - 支持直接粘贴纯 Cookie 值
62
+ - 也支持直接粘贴带 `Cookie:` 前缀的一整行
63
+ - 如果你复制的是多行请求头,插件会优先提取其中的 `Cookie:` 行
64
+ 8. 开始对话
65
+
66
+ ## 打包与发布
67
+
68
+ - 当前工程已经补好本地打包脚本,默认会把生成出来的 `.vsix` 一起放进 npm 包。
69
+ - VSIX 打包和 npm 打包现在分开控制:
70
+ - VSIX 打包走 `.vscodeignore`
71
+ - npm 打包走 `.npmignore`
72
+ - 生成 VSIX:
73
+ - `npm run package:vsix`
74
+ - 默认产物路径:`artifacts/csdn-private-ai-<version>.vsix`
75
+ - 生成 npm tarball:
76
+ - `npm run package:npm`
77
+ - 默认产物路径:`artifacts/csdn-private-ai-<version>.tgz`
78
+ - 一次性同时生成 VSIX 和 npm tarball:
79
+ - `npm run release:local`
80
+ - 实际发布到 npm:
81
+ - 先执行 `npm login`
82
+ - 先确认 `package.json` 里的 `name` 和 `version` 都是你要发布的值
83
+ - 再执行 `npm run publish:npm`
84
+ - 如果你只想先验证发布内容,不想真的发到 npm,可先执行:
85
+ - `npm publish --dry-run --access public --cache .npm-cache`
86
+ - `publish:npm` 会在真正发布前自动先跑一次 `package:vsix`,确保 npm 包里带的是最新版本的 `.vsix`
87
+ - 当前脚本默认依赖你本机已经全局安装好的 `vsce`
88
+ - npm 打包和发布脚本固定使用项目内的 `.npm-cache`,避免受系统全局 npm 缓存权限影响
89
+ - 仓库当前已补 `MIT` 许可证文件:`LICENSE`
90
+
91
+ ## 超时说明
92
+
93
+ - `csdnPrivateAi.requestTimeoutMs` 对普通 JSON 请求仍表示单次请求超时。
94
+ - 对 smart chat 流式对话,这个值现在表示“空闲超时”,不是整段生成的总时长上限。
95
+ - 只要 CSDN 还在持续返回 chunk,插件就不会因为回答太长而在 30 秒时被硬切断。
96
+ - 如果长回答仍然停在半截,优先把 `csdnPrivateAi.requestTimeoutMs` 调大到 `60000` 或 `120000` 再观察。
97
+
98
+ ## 调试配置
99
+
100
+ - 已提供 `.vscode/launch.json`
101
+ - 已提供 `.vscode/tasks.json`
102
+ - 默认调试入口:
103
+ - `运行 CSDN Private AI 插件`
104
+ - `监听并运行 CSDN Private AI 插件`
105
+
106
+ ## F5 没反应时先检查
107
+
108
+ 1. 当前打开的是不是本项目根目录,而不是上级目录或其他工作区。
109
+ 2. `node_modules` 是否已安装完成。
110
+ 3. `dist/extension.js` 是否已经生成。
111
+ 4. “运行和调试”面板里是否选中了 `运行 CSDN Private AI 插件`。
112
+ 5. 如果第一次进来没有任务缓存,先手动执行一次 `npm run compile` 再按 `F5`。
113
+ 6. 如果能发请求但立刻提示鉴权失败,先检查 Cookie 是否过期,或者是不是复制错了账号的 Cookie。
114
+ 7. 现在插件会自动清洗 `Cookie:` 前缀;如果还是鉴权失败,优先重新从已登录的 CSDN 页面复制最新 Cookie。
115
+ 8. 如果错误里出现 `HMAC signature does not match` 或“网关签名失败”,优先检查:
116
+ - `src/services/csdnSigner.ts`
117
+ - `src/services/csdnClient.ts`
118
+ 9. 如果错误里出现 `400105`,不要再先怀疑 Cookie。现在优先检查:
119
+ - 浏览器里同账号同文章是否真的能打开右侧 AI
120
+ - `src/services/csdnClient.ts` 的 smart chat 协议是否仍和网页一致
121
+ - `sessionId` 获取/创建流程是否变化
122
+ 10. 如果你刚改过代码或我刚帮你修过协议,记得先关闭旧的 `Extension Development Host`,再重新按一次 `F5`,否则你看到的可能还是上一版编译产物。
123
+ 11. 如果要继续排查,打开 VS Code 输出面板,切到 `CSDN Private AI`,看插件记录的 HTTP 状态码和业务错误。
124
+
125
+ ## 维护约定
126
+
127
+ - 后续每次改代码,都要同步更新 README。
128
+ - README 至少要同步三类信息:
129
+ - 本次改了什么功能或行为
130
+ - 调试方式有没有变化
131
+ - 已知风险、兼容性或使用前提有没有变化
132
+ - 如果改动影响用户使用路径,README 里的“开发调试”和“F5 没反应时先检查”也必须一起更新。
133
+
134
+ ## 后续维护重点
135
+
136
+ - 这是基于 CSDN 当前前端 bundle 对齐出来的私有协议,后续如果 CSDN 更新 AK/SK 或网关签名规则,优先修改 `src/services/csdnSigner.ts`。
137
+ - 如果文章绑定规则变化,或后续不再允许用纯数字 `articleId` 走兜底 URL,优先修改 `src/utils/article.ts`,并同步更新侧边栏文案和 README。
138
+ - 如果 VSIX 打包失败,优先检查全局 `vsce` 是否可用,以及 `.vscodeignore` 和 `package.json` 里的脚本是否还保持一致。
139
+ - 如果 npm 包里没有带上 `.vsix`,优先检查 `.npmignore`,以及发布前是否实际生成了 `artifacts/*.vsix`。
140
+ - 如果 CSDN 修改了 smart chat 的 URL `sign` 计算规则,优先修改 `src/services/csdnSigner.ts`。
141
+ - 如果再次出现“网关签名失败,但浏览器里同请求能用”,优先检查 `src/services/csdnSigner.ts` 里的 query `sign` 是否仍然是“UTF-8 Base64 + 双 MD5”。
142
+ - 如果只有 `getBlogSessionId` 这类 GET 接口报 `401/HMAC signature does not match`,优先检查 `src/services/csdnSigner.ts` 里空 query 参数是否仍按 `type` 而不是 `type=` 参与 HMAC。
143
+ - 如果 `getBlogSessionId` 成功但会话没有被复用,优先检查 `src/services/csdnClient.ts` 是否还兼容当前的 `{ sid, count }` 返回结构。
144
+ - 如果长文本生成到一半就停,优先检查 `src/services/csdnClient.ts` 的流式超时策略,不要再把流式请求当作“总时长超时”处理。
145
+ - 如果 CSDN 修改了 `queryId` / `trace_id` / `sessionId` 的生成规则,优先修改:
146
+ - `src/utils/request.ts`
147
+ - `src/webview/sidebarViewProvider.ts`
148
+ - 如果 CSDN 修改了聊天接口地址、请求体字段或 SSE 返回格式,优先修改 `src/services/csdnClient.ts`。
149
+ - 如果浏览器右侧 AI 还能用,但插件返回 `400105`,优先检查 `src/services/csdnClient.ts` 里的 `sessionId` 获取/创建流程和 smart chat 事件流解析。
150
+ - 如果 CSDN 修改了文章可用性判断逻辑,优先修改 `src/services/csdnClient.ts` 里的 `validateArticle`。
151
+ - 如果鉴权失败集中出现在用户首次配置阶段,先检查 `src/utils/cookie.ts` 的 Cookie 清洗逻辑是否还适配当前复制方式。
152
+ - 如果服务端返回新的业务错误码,优先补 `src/services/csdnClient.ts` 里的错误码映射,不要直接把所有错误都归因到 Cookie。
153
+ - 如果对话存储策略变了,优先修改 `src/services/threadStore.ts`。
154
+ - 如果侧边栏交互或消息协议变了,要同时修改:
155
+ - `src/webview/sidebarViewProvider.ts`
156
+ - `media/sidebar.js`
157
+ - `media/sidebar.css`
158
+ - 如果复制按钮或剪贴板行为变了,要同时检查 `src/webview/sidebarViewProvider.ts` 和 `media/sidebar.js` 的消息协议是否仍一致。
159
+ - 如果活动栏图标显示异常,优先检查 `media/icon.svg` 是否仍然使用 `currentColor` 单色路径,而不是带背景色的大面积填充。
160
+ - 插件不会把 Cookie 透传给 Webview,也不会把 Cookie 打进日志,这条约束后续不要破坏。
161
+
162
+ ## 当前实现变更记录
163
+
164
+ ### 0.0.1
165
+
166
+ - 初始化了桌面版 VS Code 扩展工程。
167
+ - 增加了侧边栏 Webview UI、文章绑定、Cookie 更新、停止生成、清空线程。
168
+ - 实现了 `ai-config` 校验、私有签名、流式请求和 SSE 解析。
169
+ - 实现了按 `articleId` 隔离的本地线程持久化。
170
+ - 增加了 `.vscode/launch.json` 和 `.vscode/tasks.json`,解决按 `F5` 没有调试入口的问题。
171
+ - 增加了 Cookie 归一化逻辑,兼容直接粘贴 `Cookie:` 整行或多行请求头中的 Cookie 内容。
172
+ - 将 `questionId` / `requestId` 生成规则对齐到 CSDN 官方前端实现。
173
+ - 增加了 `400105` 业务错误提示,避免把业务拒绝误判成 Cookie 鉴权失败。
174
+ - 补充了调试宿主重启说明,避免修改代码后仍然看到旧版本提示文案。
175
+ - 增加了错误日志输出到 `CSDN Private AI` 输出面板,并把 `401/403` 文案改成带 HTTP 状态码,方便区分真实鉴权失败和业务拒绝。
176
+ - 去掉了旧的统一鉴权失败文案;现在服务端业务消息里的鉴权类错误也会明确标成“服务端业务码 / 服务端业务消息”。
177
+ - 将旧的 `completion` 请求从 `fetch` 切换为 `node:https.request`,修复了真实请求里出现的 `HMAC signature does not match` 网关签名错误。
178
+ - 将聊天协议从旧的 `assistant/completion` 切换到浏览器当前真实使用的 `smart/session + smart/chat/message/stream` 链路。
179
+ - 本地线程现在会持久化 `sessionId`,并在发送前先走 `getBlogSessionId` 对齐当前 smart chat 会话。
180
+ - SSE 解析现在按 `message / message_end / workflow_finished` 事件处理,避免把 workflow 汇总字段重复拼进正文。
181
+ - 修正了 smart chat URL 上 `sign` 的生成逻辑,改为和当前 CSDN bundle 一致的“UTF-8 Base64 + 双 MD5”,解决 `HTTP 401 / HMAC signature does not match`。
182
+ - 修正了 GET 请求空 query 参数的 HMAC 规范化逻辑,和当前 CSDN bundle 保持一致,避免 `getBlogSessionId` 因 `type=` 与 `type` 差异导致 401。
183
+ - 补上了 `getBlogSessionId` 返回对象结构的兼容,避免服务端已返回真实 `sid` 时本地还退回随机 sessionId。
184
+ - 将流式请求从“整段请求总时长超时”改成“socket 空闲超时”,修复长代码生成到 30 秒左右被 `aborted / ECONNRESET` 截断的问题。
185
+ - 为每条 AI 回复增加了一键复制按钮,复制动作由扩展宿主写入系统剪贴板,避免依赖 Webview 自身的 clipboard 权限。
186
+ - 将活动栏图标替换为适合 VS Code 侧边栏容器的单色 SVG,修复显示成白色正方形的问题。
187
+ - 文章绑定现在支持直接输入纯数字 `articleId`,不再强依赖先粘贴完整文章链接,适配内网环境下无法访问博客页面的场景。
188
+ - 增加了 VSIX 和 npm 发布脚本,支持生成 `.vsix`、生成 npm tarball,并在 npm 发布前自动把最新 `.vsix` 带进包里。
189
+ - 将 VSIX 和 npm 的打包规则拆分为 `.vscodeignore` 与 `.npmignore` 两套,避免 `vsce` 因和 npm 文件白名单冲突而打包失败。
190
+ - 补充了 npm 发布前需要先 `npm login` 的说明,并验证了 `npm publish --dry-run` 下 tarball 确实会包含生成出来的 `.vsix`。
191
+ - 补充了 `MIT` 许可证文件,消除了 VSIX 打包时缺少 LICENSE 的警告前提。
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SIGNATURE_HEADER_ALLOWLIST = exports.CONFIG_KEYS = exports.DEFAULT_MAX_LOCAL_HISTORY = exports.DEFAULT_REQUEST_TIMEOUT_MS = exports.SMART_CHAT_APP_SECRET = exports.SMART_CHAT_APP_KEY = exports.SMART_CHAT_MESSAGE_STREAM_PATH = exports.SMART_BLOG_SESSION_PATH = exports.BIZAPI_BASE = exports.CSDN_AI_BASE = exports.BLOG_WEB_BASE = exports.OUTPUT_CHANNEL_NAME = exports.THREADS_KEY = exports.BOUND_ARTICLE_KEY = exports.SECRET_COOKIE_KEY = exports.VIEW_ID = exports.VIEW_CONTAINER_ID = exports.EXTENSION_NAMESPACE = void 0;
4
+ exports.EXTENSION_NAMESPACE = 'csdnPrivateAi';
5
+ exports.VIEW_CONTAINER_ID = 'csdnPrivateAi';
6
+ exports.VIEW_ID = 'csdnPrivateAi.sidebar';
7
+ exports.SECRET_COOKIE_KEY = 'csdnPrivateAi.cookie';
8
+ exports.BOUND_ARTICLE_KEY = 'csdnPrivateAi.boundArticle';
9
+ exports.THREADS_KEY = 'csdnPrivateAi.threads';
10
+ exports.OUTPUT_CHANNEL_NAME = 'CSDN Private AI';
11
+ exports.BLOG_WEB_BASE = 'https://blog.csdn.net/phoenix/web';
12
+ exports.CSDN_AI_BASE = 'https://ai.csdn.net';
13
+ exports.BIZAPI_BASE = 'https://bizapi.csdn.net';
14
+ exports.SMART_BLOG_SESSION_PATH = '/aisearch/v2/api/smart/session/getBlogSessionId';
15
+ exports.SMART_CHAT_MESSAGE_STREAM_PATH = '/aisearch/v2/api/stream/smart/chat/message/stream';
16
+ exports.SMART_CHAT_APP_KEY = '280526253';
17
+ exports.SMART_CHAT_APP_SECRET = '673BzMJHuGF8vQBfRyWpTrXwq5rSgRGD';
18
+ exports.DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
19
+ exports.DEFAULT_MAX_LOCAL_HISTORY = 40;
20
+ exports.CONFIG_KEYS = {
21
+ requestTimeoutMs: 'requestTimeoutMs',
22
+ maxLocalHistory: 'maxLocalHistory',
23
+ debug: 'debug'
24
+ };
25
+ exports.SIGNATURE_HEADER_ALLOWLIST = new Set([
26
+ 'x-ca-timestamp',
27
+ 'x-ca-signature',
28
+ 'x-ca-signature-headers',
29
+ 'x-ca-key',
30
+ 'x-ca-nonce'
31
+ ]);
32
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,mBAAmB,GAAG,eAAe,CAAC;AACtC,QAAA,iBAAiB,GAAG,eAAe,CAAC;AACpC,QAAA,OAAO,GAAG,uBAAuB,CAAC;AAClC,QAAA,iBAAiB,GAAG,sBAAsB,CAAC;AAC3C,QAAA,iBAAiB,GAAG,4BAA4B,CAAC;AACjD,QAAA,WAAW,GAAG,uBAAuB,CAAC;AACtC,QAAA,mBAAmB,GAAG,iBAAiB,CAAC;AAExC,QAAA,aAAa,GAAG,mCAAmC,CAAC;AACpD,QAAA,YAAY,GAAG,qBAAqB,CAAC;AACrC,QAAA,WAAW,GAAG,yBAAyB,CAAC;AACxC,QAAA,uBAAuB,GAAG,iDAAiD,CAAC;AAC5E,QAAA,8BAA8B,GAAG,mDAAmD,CAAC;AAErF,QAAA,kBAAkB,GAAG,WAAW,CAAC;AACjC,QAAA,qBAAqB,GAAG,kCAAkC,CAAC;AAE3D,QAAA,0BAA0B,GAAG,MAAM,CAAC;AACpC,QAAA,yBAAyB,GAAG,EAAE,CAAC;AAE/B,QAAA,WAAW,GAAG;IACzB,gBAAgB,EAAE,kBAAkB;IACpC,eAAe,EAAE,iBAAiB;IAClC,KAAK,EAAE,OAAO;CACN,CAAC;AAEE,QAAA,0BAA0B,GAAG,IAAI,GAAG,CAAC;IAChD,gBAAgB;IAChB,gBAAgB;IAChB,wBAAwB;IACxB,UAAU;IACV,YAAY;CACb,CAAC,CAAC"}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.activate = activate;
37
+ exports.deactivate = deactivate;
38
+ const vscode = __importStar(require("vscode"));
39
+ const constants_1 = require("./constants");
40
+ const csdnClient_1 = require("./services/csdnClient");
41
+ const storage_1 = require("./services/storage");
42
+ const threadStore_1 = require("./services/threadStore");
43
+ const sidebarViewProvider_1 = require("./webview/sidebarViewProvider");
44
+ function activate(context) {
45
+ const outputChannel = vscode.window.createOutputChannel(constants_1.OUTPUT_CHANNEL_NAME);
46
+ const getRuntimeOptions = () => {
47
+ const config = vscode.workspace.getConfiguration(constants_1.EXTENSION_NAMESPACE);
48
+ return {
49
+ timeoutMs: normalizeNumber(config.get(constants_1.CONFIG_KEYS.requestTimeoutMs, constants_1.DEFAULT_REQUEST_TIMEOUT_MS), constants_1.DEFAULT_REQUEST_TIMEOUT_MS, 3_000),
50
+ maxLocalHistory: normalizeNumber(config.get(constants_1.CONFIG_KEYS.maxLocalHistory, constants_1.DEFAULT_MAX_LOCAL_HISTORY), constants_1.DEFAULT_MAX_LOCAL_HISTORY, 10),
51
+ debug: config.get(constants_1.CONFIG_KEYS.debug, false)
52
+ };
53
+ };
54
+ const logger = {
55
+ debug(message, detail) {
56
+ if (!getRuntimeOptions().debug) {
57
+ return;
58
+ }
59
+ const timestamp = new Date().toISOString();
60
+ const suffix = detail ? ` ${JSON.stringify(detail)}` : '';
61
+ outputChannel.appendLine(`[${timestamp}] ${message}${suffix}`);
62
+ },
63
+ error(message, detail) {
64
+ const timestamp = new Date().toISOString();
65
+ const suffix = detail ? ` ${JSON.stringify(detail)}` : '';
66
+ outputChannel.appendLine(`[${timestamp}] ERROR ${message}${suffix}`);
67
+ }
68
+ };
69
+ const secretStore = new storage_1.SecretStore(context.secrets);
70
+ const threadStore = new threadStore_1.ThreadStore(context.workspaceState);
71
+ const client = new csdnClient_1.CsdnPrivateAiClient(() => ({
72
+ timeoutMs: getRuntimeOptions().timeoutMs,
73
+ debug: getRuntimeOptions().debug
74
+ }), logger);
75
+ const provider = new sidebarViewProvider_1.SidebarViewProvider(context.extensionUri, secretStore, threadStore, client, () => ({
76
+ maxLocalHistory: getRuntimeOptions().maxLocalHistory
77
+ }), logger);
78
+ context.subscriptions.push(outputChannel);
79
+ context.subscriptions.push(vscode.window.registerWebviewViewProvider('csdnPrivateAi.sidebar', provider, {
80
+ webviewOptions: {
81
+ retainContextWhenHidden: true
82
+ }
83
+ }));
84
+ context.subscriptions.push(vscode.commands.registerCommand('csdnPrivateAi.openSidebar', async () => {
85
+ await provider.reveal();
86
+ }));
87
+ context.subscriptions.push(vscode.commands.registerCommand('csdnPrivateAi.setArticleUrl', async (value) => {
88
+ await provider.reveal();
89
+ await provider.promptForArticleUrl(typeof value === 'string' ? value : '');
90
+ }));
91
+ context.subscriptions.push(vscode.commands.registerCommand('csdnPrivateAi.setCookie', async () => {
92
+ await provider.reveal();
93
+ await provider.promptForCookie();
94
+ }));
95
+ context.subscriptions.push(vscode.commands.registerCommand('csdnPrivateAi.clearThread', async () => {
96
+ await provider.clearCurrentThread();
97
+ }));
98
+ }
99
+ function deactivate() { }
100
+ function normalizeNumber(value, fallback, min) {
101
+ if (typeof value !== 'number' || Number.isNaN(value)) {
102
+ return fallback;
103
+ }
104
+ return Math.max(min, Math.floor(value));
105
+ }
106
+ //# sourceMappingURL=extension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"}