dsh-kaogong 1.11.0 → 1.12.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/CLAUDE.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Commands
6
6
  - Build/类型门: `npm run build`(**tsc + scripts/bundle-client.mjs**:类型错误阻断 + 多文件产物拓扑序合并为宿主要求的单 combo)。**改完 .ts 必须 build(宿主编织的是 dist),改完任何 src/client/*.ts 也必须 build(client 产物是 bundler 合并的,裸 tsc 会把 dist/client/client.js 重写回裸 ESM → 宿主拒绝加载)**
7
- - Test 全量: `npm run test:all` = `node smoke.test.mjs`(**203 断言**,独立端口段 8495,publishRuntime=false,含 combo 格式/R9/R11/R8/兼容声明静态守卫 + v1.6/v1.7 真题卷·申论评改·配图·模考·大作文·深度题库端到端 + cycle-13 省份维度 R-P/R-N + cycle-15 记忆 R-MEM/三布局/流动粒子/白盒三件套 + **cycle-16 题库管理 R-P-01..05(/api/repos* 控制面+数据根四级解析+崩溃安全静态守卫)**)+ `node render.test.mjs`(**42 断言**,真实 React 18 + 真实 client.js 集成渲染,含专题枢纽/省份 chips/白盒流动图/图谱升级包/记忆跳回/**C16 题库面板「关于本项目」卡与安装请求**)。**两者都已接线 bundler**(scripts 先 tsc 再合并)
7
+ - Test 全量: `npm run test:all` = `node smoke.test.mjs`(**204 断言**,独立端口段 8495,publishRuntime=false,含 combo 格式/R9/R11/R8/兼容声明静态守卫 + v1.6/v1.7 真题卷·申论评改·配图·模考·大作文·深度题库端到端 + cycle-13 省份维度 R-P/R-N + cycle-15 记忆 R-MEM/三布局/流动粒子/白盒三件套 + **cycle-16/17 题库管理 R-P-01..06(/api/repos* 控制面+数据根四级解析+崩溃安全静态守卫+跨工作区缓存分槽隔离)**)+ `node render.test.mjs`(**42 断言**,真实 React 18 + 真实 client.js 集成渲染,含专题枢纽/省份 chips/白盒流动图/图谱升级包/记忆跳回/**C16 题库面板「关于本项目」卡与安装请求**)。**两者都已接线 bundler**(scripts 先 tsc 再合并)
8
8
  - **沙箱验证(禁主力直测)**: `node ../_dshcli/node_modules/@deepseek-ai/dsh/lib/bin.js --profile sb-kaogong --port 3181 --no-open`(token 行取 URL;插件崩只崩沙箱)
9
9
  - 热更新重载: `plugin_manager set_plugin include:kaogong enabled=false → true`(fiber 重挂载)
10
10
  - 安装/重装: `plugin_manager remove_bundle dsh-kaogong → install_bundle <绝对路径>`
@@ -88,3 +88,10 @@
88
88
  - **⑯(异步路由改造检查单)**:`handleApi` 变异步必须同步改**全部调用点**(同源 attachWebRoute + 独立端口 buildHttpServer 两处 `req.on('end')` 都要 async+await),并保留 try/catch 收敛 500。tsc 全绿 + smoke 全绿才算改完。
89
89
  - **⑰(面板元数据单一事实源)**:「关于本项目」卡的 GitHub/Release/Issue/npm 链接存 `SELF_META`(manifest),server `/api/repos` 透出 `self`,UI 只消费不硬编码;version 引用 `CAPABILITIES.plugin.version` 而非第二处字面量(版本三锚点守卫只认一处)。
90
90
  - **⑱(沙箱模拟安装态)**:验证「npm 安装后无数据」的正确方法 = 沙箱带 `KG_REPOS_DIR=空目录` 启动(present=0/requiredMissing=3),再走真实一键克隆→功能即时恢复(/api/method 从「参考文件未找到」变真实全文)→pull/browse/remove 全链路。**环境性缺陷用「干净环境复现 + 修复后同环境回归」闭环,不在开发态环境自欺。**
91
+
92
+ ## cycle-17 事故与教训(v1.12.0 隔离与显示修复 + 市场合规)
93
+ - **⑲(R20 缓存维度教训)**:图谱缓存全局单槽但响应内嵌 per-ws 的 `progress` → A 项目访问后 B 项目在 TTL 内读到 A 的进度(跨项目污染,用户可感知「我的数据怎么是别人的」)。修法 `Map<wsKey,slot>` + LRU 24。**规矩:给响应加缓存前,先列出响应的全部可变输入维度(ws/root/参数),缓存键必须覆盖其中「租户级」维度。**守卫=smoke R-P-06 静态断言 + 双 ws 运行时实证(X.day=7/Y.day=1)。
94
+ - **⑳(R21 windowsHide)**:`spawn('git')` 在 Windows 默认给子进程分配控制台——题库每次 clone/pull/探测都闪黑窗。宿主 GUI 插件的一切子进程 spawn 必须 `windowsHide:true`(probeGit 也不例外)。
95
+ - **㉑(R22 工具输出陈旧)**:`kaogong_launch` 手写「7 视图」模板,实际 15 视图——声明与呈现漂移。**面向模型/用户的文案也从事实源渲染**:views/tools/endpoints 计数取 `/api/capabilities`,repoRoot/pid 取 `/api/status`,数据就绪取 `/api/repos`。这是「声明 vs 运行态同源」纪律(v1.8 遥测事故)在呈现层的推论。
96
+ - **㉒(市场 peer 预发布陷阱)**:`>=0.2.0-rc.2 <0.4.0-0` 看似宽,node-semver 规则下**静默排除所有 rc**(预发布只匹配同 tuple 且带预发布标签的比较符)→ 用户装 rc 版宿主 ERESOLVE。修法:每段带预发布分支 `|| >=0.2.1-rc.0 <0.3.0-0 ||`。awesome-dsh-plugin 贡献规范明文要求,CI 检查 `dsh.bundle` 声明(只声明 `dsh.client` 不可安装是最常见被拒原因)。
97
+ - **㉓(GitHub 推送通道)**:Windows 上 HTTPS 443 直连 github.com 会被重置(`Recv failure: Connection was reset`),SSH 22 端口稳定——发布仓 remote 一律 SSH(`git@github.com:…`);Contents API 兜底适合单文件热修(注意 API 提交与本地分支会分叉,推送前先 `fetch + rebase origin/main`)。
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # dsh-kaogong — 考公备考整合插件(DSH 宿主原生面板)· v1.11.0
1
+ # dsh-kaogong — 考公备考整合插件(DSH 宿主原生面板)· v1.12.0
2
2
 
3
3
  > **一句话**:把 15 个优秀开源考公仓库整合为 DeepSeek Harness(DSH)宿主内的原生学习平台 ——
4
4
  > 刷题 / 错题本 SRS / 真题卷 / 整卷模考 / 申论评改 / 知识图谱 / 白盒可观测,完全离线可用。
@@ -13,7 +13,8 @@
13
13
  | | |
14
14
  |---|---|
15
15
  | 🏠 **宿主原生** | DSH Web GUI 双入口:左栏「考公学习」全屏沉浸面板 + 右侧 Sidebar 并排标签;同源路由零 CORS,非 iframe |
16
- | 📦 **一键式题库管理**(v1.11) | 必选/推荐/可选三级分装 · git 浅克隆/更新/删除 · 目录浏览 · 自定义数据根 · 镜像代理(gh-proxy 等)· 作业实时日志 |
16
+ | 📦 **一键式题库管理**(v1.11) | 必选/推荐/可选三级分装 · git 浅克隆/更新/删除 · 目录浏览 · 自定义数据根 · 镜像代理(gh-proxy 等)· 作业实时日志 · **「关于本项目」GitHub/Release/Issue/npm 跳转**(v1.12) |
17
+ | 🔒 **跨项目隔离**(v1.12) | 进度/记忆/图谱缓存全部按工作区命名空间分槽——不同项目使用本插件互不污染;Windows 静默子进程(无控制台闪现);工具输出实时取自能力矩阵(无陈旧模板) |
17
18
  | ✏️ **智能刷题** | 58,890 题行测真题 · 五箱 SRS 错题本(答错收集→回炉升箱→掌握)· 弱点加权抽题 · 键盘流 |
18
19
  | 💾 **专项刷题记忆**(v1.10) | 进入刷题/图形推理/深度题库自动显示「上次练到 xx 的 xx 题」,一键跳回原题 |
19
20
  | 📚 **真题卷 1,683 套** | 申论 944 / 行测 739(2008-2026)· 科目/省份/年份三维筛选 · 材料逐份折叠 · 题目配图 |
@@ -132,9 +133,9 @@ src/
132
133
 
133
134
  ```bash
134
135
  npm run build # tsc 类型门 → scripts/bundle-client.mjs 合并 12 模块为单 combo
135
- node smoke.test.mjs # 202 断言 E2E(信标/adopt/隔离/SRS闭环/图谱算法确定性/
136
- # 专项记忆 R-MEM/三布局/流动粒子/白盒三件套/题库管理 R-P-01..05 + 省份维度)
137
- node render.test.mjs # 41 断言真实 React 18 + 真实 client.js 集成渲染(零 role=alert 降级)
136
+ node smoke.test.mjs # 204 断言 E2E(信标/adopt/隔离/SRS闭环/图谱算法确定性/
137
+ # 专项记忆 R-MEM/三布局/流动粒子/白盒三件套/题库管理 R-P-01..06 含跨工作区缓存分槽隔离守卫)
138
+ node render.test.mjs # 42 断言真实 React 18 + 真实 client.js 集成渲染(零 role=alert 降级)
138
139
  ```
139
140
 
140
141
  ANIC 质量流程:`.cycles/`(intent→spec→plan→G0-G3 门禁→归档 15+ 循环;L4 全自主 + 人类门禁授权)。工程纪律与事故簿见 [CLAUDE.md](./CLAUDE.md)。
Binary file
Binary file
Binary file
@@ -76,27 +76,51 @@ export function apply(ctx) {
76
76
  });
77
77
  ctx.tools.register({
78
78
  name: 'kaogong_launch',
79
- description: '考公学习平台状态与引导。返回服务端口、启动方式与功能清单。平台内嵌于 DSH Web GUI 右侧边栏「考公学习」标签(引导页也有入口),完全离线可用。',
79
+ description: '考公学习平台状态与引导(全部字段实时取自服务,非硬编码)。平台双入口:左栏「考公学习」全屏面板 + 右侧 Sidebar 标签。完全离线可用;题库数据未就绪时引导用户到「📦 题库管理」一键安装。',
80
80
  parameters: { type: 'object', properties: { workspace: { type: 'string', description: '可选:当前项目工作区绝对路径(用于隔离进度查询)' } } },
81
81
  output: textOutput,
82
82
  async execute(args) {
83
- let status = { app: 'down' };
83
+ // cycle-17:消灭「工具输出陈旧显示」——视图/工具/端点/仓库/数据根全部来自
84
+ // /api/capabilities + /api/status + /api/repos 实时数据,杜绝手写模板漂移
85
+ let status = { app: 'down' }, caps = null, repos = null;
84
86
  try {
85
87
  status = await callApi('/api/status', args.workspace);
86
88
  }
87
89
  catch { }
90
+ try {
91
+ caps = await callApi('/api/capabilities');
92
+ }
93
+ catch { }
94
+ try {
95
+ repos = await callApi('/api/repos', args.workspace);
96
+ }
97
+ catch { }
88
98
  const up = status.app === CAPABILITIES.plugin.name;
99
+ const views = ((caps && caps.views) || []).map((v) => v.label);
100
+ const toolsN = ((caps && caps.tools) || []).length;
101
+ const epN = ((caps && caps.endpoints) || []).length;
89
102
  const lines = [
90
- '## 📚 考公学习平台',
91
- `**服务状态**: ${up ? `✅ ${base()}(${status.repos?.ready}/${status.repos?.total} 仓库就绪,运行 ${status.uptimeSec}s)` : `❌ 未就绪(宿主启动=${runtime.boot};查看 data/runtime.json 与 lifecycle.jsonl)`}`,
92
- '**GUI 入口**: DSH Web GUI 右侧边栏「考公学习」标签 / 引导页(Guide)入口',
93
- '', '### 离线功能',
94
- '- 仪表盘/刷题/30天计划/知识检索/方法论/知识图谱/可观测 7 视图',
95
- '', '### AI增强(可选)',
96
- '- kaogong_ai_tutor 错题辅导 · kaogong_ai_plan 个性化建议 · kaogong_ai_shenlun 申论批改',
103
+ `## 📚 考公学习平台 · v${(caps && caps.plugin && caps.plugin.version) || CAPABILITIES.plugin.version}`,
104
+ `**服务状态**: ${up ? `✅ ${base()}(同源路由 ${MOUNT_PATH}/* · 运行 ${status.uptimeSec}s · pid ${status.pid})` : `❌ 未就绪(宿主启动=${runtime.boot};查看 data/runtime.json 与 lifecycle.jsonl)`}`,
105
+ `**数据根**: ${status.repoRoot || '—'}(${repos && repos.rootSource === 'config' ? '自定义' : '自动解析'})`,
106
+ `**GUI 入口**: 左栏「考公学习」全屏面板(主)+ 右侧边栏标签摘要(引导页亦有入口)`,
107
+ '',
108
+ `### 离线功能(${views.length} 视图 · ${epN} 端点 · 实时清单)`,
109
+ views.length ? '- ' + views.join(' · ') : '- (能力矩阵未就绪)',
110
+ '',
111
+ `### AI 增强(可选 · ${toolsN} 工具)`,
112
+ '- 素材供模型加工模式;离线核心与模型解耦(无模型全部功能可用)',
97
113
  ];
98
- if (up)
99
- lines.push('', `**当前进度**:第${status.progress?.day}天 · ${status.progress?.answered}题 · 正确率${status.progress?.rate}%`);
114
+ if (up && repos) {
115
+ const miss = (repos.summary && repos.summary.requiredMissing) || [];
116
+ lines.push('', `### 题库数据:${repos.summary.present}/${repos.summary.total} 仓库就绪`);
117
+ if (miss.length)
118
+ lines.push(`⚠️ 必选缺失:${miss.join('、')} —— 打开「📦 题库管理」一键安装必选包(约 363MB,国内可先配 gh-proxy 镜像)`);
119
+ else
120
+ lines.push('✅ 必选/推荐数据齐备');
121
+ }
122
+ if (up && status.progress)
123
+ lines.push('', `**当前进度**:第${status.progress.day}天 · ${status.progress.answered}题 · 正确率${status.progress.rate}%`);
100
124
  return { text: lines.join('\n') };
101
125
  },
102
126
  });
@@ -71,7 +71,7 @@ function rebuildDomains() {
71
71
  if (changed) {
72
72
  resetPaperIndex();
73
73
  resetNaoku();
74
- graphCache = { ts: 0, data: null };
74
+ graphCache.clear();
75
75
  }
76
76
  return { root: next, changed };
77
77
  }
@@ -243,11 +243,15 @@ function lifecycleSnapshot() {
243
243
  return { stages, events: events.slice().reverse(), current: stages[currentIdx].stage };
244
244
  }
245
245
  // ══ 图谱快照(5s TTL 缓存;节点/边/指标/健康度)══
246
- let graphCache = { ts: 0, data: null };
246
+ // cycle-17 隔离修复:快照内嵌 progress(ws 相关字段),缓存必须按 wsKey 分槽——
247
+ // 否则工作区 A 先访问后,B 在 TTL 内命中同一份缓存,读到 A 的进度(跨项目污染)。
248
+ const graphCache = new Map();
247
249
  function graphSnapshot(wsRaw) {
250
+ const ck = domains.store.wsKey(wsRaw);
251
+ const hit = graphCache.get(ck);
248
252
  const now = Date.now();
249
- if (graphCache.data && now - graphCache.ts < 5000)
250
- return graphCache.data;
253
+ if (hit && hit.data && now - hit.ts < 5000)
254
+ return hit.data;
251
255
  const banks = {
252
256
  banks: Object.fromEntries(entries(REPOS).map(([k, v]) => [k, { desc: v, exists: exists(join(domains.root, k)) }])),
253
257
  ...repoStats(domains.root),
@@ -286,7 +290,12 @@ function graphSnapshot(wsRaw) {
286
290
  analytics,
287
291
  layout: layeredLayout(ge.nodes, ge.edges),
288
292
  };
289
- graphCache = { ts: now, data };
293
+ graphCache.set(ck, { ts: now, data });
294
+ if (graphCache.size > 24) { // 防无界增长:按时间戳清最旧槽(LRU 近似)
295
+ const oldest = [...graphCache.entries()].sort((a, b) => a[1].ts - b[1].ts).slice(0, graphCache.size - 24);
296
+ for (const [k] of oldest)
297
+ graphCache.delete(k);
298
+ }
290
299
  return data;
291
300
  }
292
301
  // ══ v1.8 图查询端点(邻域/最短路/影响面)══
@@ -30,7 +30,7 @@ function probeGit() {
30
30
  return gitProbe;
31
31
  gitProbe = new Promise((res) => {
32
32
  try {
33
- const p = spawn('git', ['--version'], { stdio: 'ignore' });
33
+ const p = spawn('git', ['--version'], { stdio: 'ignore', windowsHide: true });
34
34
  p.on('error', () => res(false));
35
35
  p.on('close', (code) => res(code === 0));
36
36
  }
@@ -75,7 +75,9 @@ export function makeRepoManager({ getRoot, onRootChanged }) {
75
75
  jobs.set(key, job);
76
76
  let proc = null;
77
77
  try {
78
- proc = spawn('git', args, { stdio: ['ignore', 'pipe', 'pipe'], env: { ...process.env, GIT_TERMINAL_PROMPT: '0', 'GIT_CONFIG_NOSYSTEM': '1' } });
78
+ // windowsHide: true —— Windows 关键项:不加则每次 clone/pull 闪现黑色控制台窗口
79
+ // (「调用插件时命令窗口闪烁」问题的根因;宿主 GUI 环境必须静默执行子进程)
80
+ proc = spawn('git', args, { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, env: { ...process.env, GIT_TERMINAL_PROMPT: '0', 'GIT_CONFIG_NOSYSTEM': '1' } });
79
81
  }
80
82
  catch (e) {
81
83
  job.state = 'failed';
@@ -16,7 +16,7 @@ const entries = (o) => Object.entries(o || {});
16
16
  */
17
17
  // ── 能力清单(与 index.js / client.js / ui 实际注册保持同步)──
18
18
  export const CAPABILITIES = {
19
- plugin: { id: 'kaogong', name: 'dsh-kaogong', version: '1.11.0', mode: 'offline-first' },
19
+ plugin: { id: 'kaogong', name: 'dsh-kaogong', version: '1.12.0', mode: 'offline-first' },
20
20
  // 宿主 UI 双入口(client 半注册;图谱与可观测面板消费此声明)
21
21
  entries: [
22
22
  { id: 'panel', kind: 'left-immersive', slots: ['sidebar.panellist', 'main'], desc: '左栏图标 + 中央全屏原生面板(同源路由渲染)' },
@@ -1,145 +1,117 @@
1
- # API 参考(v1.7.2)
1
+ # API 参考(v1.12.0 · 51 端点 · 与 src/shared/manifest.ts 逐条同步)
2
2
 
3
3
  > 所有端点前缀:宿主通道 `/kaogong/api/*`,独立端口通道 `/api/*`(两侧都接受带前缀路径)。
4
- > 隔离参数:`?ws=<workspace>`(缺省为 `default`)。
5
- > **本文件与 `src/shared/manifest.js` 必须同步**;改端点先改 manifest。
4
+ > 隔离参数:`?ws=<workspace>`(缺省为 `default`;服务端 slug+sha1-8 命名空间分文件)。
5
+ > **本文件与 `src/shared/manifest.ts` CAPABILITIES.endpoints 必须同步**(能力对账以 manifest 为准,孤儿/漂移会被白盒面板点亮)。
6
+ > 错误约定:业务性失败返回 `{error: '…'}` 且 **HTTP 200**(UI 卡片级降级,绝不 5xx 冒泡);仅基础设施异常才 500。
6
7
 
7
- ## 一、核心(coreApi)
8
+ ## 一、核心信标与统计(coreApi)
8
9
 
9
10
  | 端点 | 方法 | 说明 | 主要返回 |
10
11
  |---|---|---|---|
11
- | `/api/status` | GET | 插件状态信标 | `{app, version, port, pid, uptimeSec, repos:{ready,total}, ws, progress}` |
12
- | `/api/stats` | GET | 学习统计 | `{days[], streak, answered, rate, mastery{}, wrong:{open,mastered}}` |
13
- | `/api/graph` | GET | 知识图谱快照 | `{nodes[], edges[], metrics:{V,E,density,components}, rank[], health{total,factors}}` |
14
- | `/api/telemetry` | GET | 遥测(环形 p50/p95) | `{uptimeSec, totalRequests, qpsWindow, coverage, endpoints{}}` |
15
- | `/api/capabilities` | GET | 能力矩阵对账 | `{endpoints[], tools[], views[], entries[], channels[]}` |
16
- | `/api/workspaces` | GET | 命名空间清单 | `{list[]}` |
17
- | `/api/progress` | GET | 进度全文 | 进度对象 |
18
- | `/api/check` | POST | 判分并落进度 | `{isCorrect, correctAnswer, analysis, wrongEvent, progress}` |
12
+ | `/api/status` | GET | 插件状态信标(client 通道发现依据:`app==='dsh-kaogong'`) | `{app, port, pid, uptimeSec, repos:{ready,total}, repoRoot, db, ws, progress}` |
13
+ | `/api/stats` | GET | 学习统计 | `{days[14], streak, mastery{}, wrong:{open,mastered}, day, answered, correct, rate}` |
14
+ | `/api/progress` | GET/POST | 进度读/写(day 夹取 1..30;reset 清空答题域但保留 wrongBook 之外字段) | 进度对象 |
15
+ | `/api/workspaces` | GET | 命名空间清单(可观测面板消费) | `{workspaces:[{ns,day,answered,rate,lastActive,label}]}` |
19
16
 
20
- `/api/check` 请求体:`{question: <完整题对象>, answer: 'A', label?: string}`
21
-
22
- ## 二、题库/计划/方法论(dataApi)
17
+ ## 二、抽题 / 判分 / 错题本 SRS(srsApi)
23
18
 
24
19
  | 端点 | 方法 | 说明 |
25
20
  |---|---|---|
26
- | `/api/questions?module=&count=&sort=srs` | GET | 抽题(`sort=srs` 走错题回炉 + 弱点加权) |
27
- | `/api/banks` | GET | 题库清单(15 仓库就绪状态) |
28
- | `/api/modules` | GET | 模块及题量 |
29
- | `/api/plan?day=` | GET/POST | 30 天计划读取/更新 |
30
- | `/api/method?topic=` | GET | 方法论参考(10 主题) |
31
- | `/api/search?q=` | GET | 15 仓库全文检索 |
32
- | `/api/wrong` | GET | 错题本(五箱 SRS) |
33
- | `/api/wrong/remove` | POST | 移除错题 |
21
+ | `/api/questions?module=&count=` | GET | 随机抽题(xingcezhenti 目录解析) |
22
+ | `/api/questions?module=&count=&sort=srs` | GET | SRS 调度:未掌握错题按 lastAt 最久先回炉;无错题按模块弱点加权 `1/(rate+0.15)` |
23
+ | `/api/check` | POST | 判分 + 落进度 + 错题钩子;体 `{question:<完整题对象含 correctAnswer>, answer:'A', label?}` → `{isCorrect, correctAnswer, analysis, wrongEvent, progress}` |
24
+ | `/api/wrong?module=` | GET | 错题清单(五箱:box 1..5;mastered=box≥3∧连对2;300 环形淘汰) |
25
+ | `/api/wrong/remove` | POST | 按 `{sig}` 移除 |
26
+ | `/api/memory` | GET/POST | **专项刷题记忆**(v1.10):`progress.memory[kind]`;POST 体 `{kind, data}`,kind 白名单 `^[a-z][a-z0-9-]{0,31}$`、data ≤8KB、12-kind LRU;消费方=practice/tuxing/deep 三专项视图(进入读横幅「上次练到 xx」,翻题静默回写,一键跳回**原题对象**) |
34
27
 
35
28
  ## 三、真题卷 / 专题 / 申论(paperApi)
36
29
 
37
30
  | 端点 | 方法 | 说明 |
38
31
  |---|---|---|
39
- | `/api/papers?subject=&exam=&year=&q=` | GET | 试卷列表(**1683 套**)+ 科目聚合 |
40
- | `/api/paper?id=` | GET | 单卷详情:材料 + 题目 + 参考答案(图片已改写为端点 URL) |
41
- | `/api/topics` | GET | **专题树**(见下) |
42
- | `/api/essay/list?type=&limit=` | GET | 申论题目聚合(五类题型筛选) |
43
- | `/api/essay/grade` | POST | 小题评分(采分点制) |
44
- | `/api/essay/article` | POST | 大作文评分(字数分档 + 结构论证) |
45
- | `/api/essay/history` | GET | 申论练习历史 + 均分率 |
46
- | `/api/paper-img?id=&p=` | GET | **二进制**:试卷配图 |
47
- | `/api/paper/exam/start?id=` | GET | 整卷模考开始(**不下发答案**) |
48
- | `/api/paper/exam/submit` | POST | 交卷计分 + 模块分布 |
49
- | `/api/paper/exam/history` | GET | 模考历史 + 均分率 |
50
-
51
- ### `/api/topics` 返回结构(v1.7.1)
52
-
53
- ```json
54
- {
55
- "channels": [
56
- {
57
- "id": "xingce", "name": "行测", "icon": "📐",
58
- "desc": "深度题库 27506 题 + 真题卷 739 套",
59
- "topics": [
60
- { "id": "xc:module:判断推理", "kind": "module", "title": "判断推理",
61
- "questionCount": 7749, "desc": "深度题库 7749 题(含解题链标注)",
62
- "entry": { "view": "practice", "params": { "module": "判断推理" } } },
63
- { "id": "xc:cat:图形推理", "kind": "category", "title": "图形推理",
64
- "questionCount": 1234, "entry": { "view": "deepbank", "params": { "category": "图形推理" } } }
65
- ],
66
- "entries": [
67
- { "label": "刷题(SRS)", "view": "practice", "params": {} },
68
- { "label": "深度题库", "view": "deepbank", "params": {} },
69
- { "label": "整卷模考", "view": "exam", "params": {} },
70
- { "label": "真题卷库", "view": "papers", "params": { "subject": "行测" } }
71
- ]
72
- },
73
- { "id": "shenlun", "name": "申论", "icon": "✍️", "topics": [ /* 五类题型 */ ], "entries": [ /* 2 个 */ ] }
74
- ],
75
- "stats": { "paperTotal": 1683, "essayPapers": 944, "xingcePapers": 739, "naokuTotal": 27506 }
76
- }
77
- ```
78
-
79
- `entry` 是**统一练习路由**:UI 点击后 `onGo(entry.view, entry.params)` → 切视图并传参。
80
-
81
- ### 申论评分契约
82
-
83
- **小题** `/api/essay/grade` 权重:要点覆盖 50% / 结构 20% / 字数 15% / 语言 15%
84
-
85
- ```json
86
- { "score": 16.5, "max": 20, "chars": 182, "limit": 300,
87
- "dims": { "coverage": 78, "structure": 80, "length": 85, "language": 100 },
88
- "hitTerms": ["如何走新型工业化道路"], "missingTerms": ["如何提高国家粮食安全"],
89
- "feedback": ["要点覆盖中等,可再补充 2-3 个关键点"] }
90
- ```
91
-
92
- **大作文** `/api/essay/article`:
93
-
94
- ```json
95
- { "score": 28.6, "max": 40, "chars": 181, "limit": 1000,
96
- "lengthBand": "严重不足", "lengthPenalty": 5,
97
- "dims": { "structure": 100, "argument": 25, "language": 80 },
98
- "elements": { "hasOpening": true, "subPoints": 3, "hasEnding": true, "argMarkers": 2 },
99
- "feedback": ["字数严重不足(181/1000),考场按档约扣 5 分"] }
100
- ```
101
-
102
- ## 四、深度题库(naokuApi · 27506 题五维标注)
32
+ | `/api/papers?subject=&exam=&year=&province=&q=` | GET | 试卷列表(**1683 套**:申论 944/行测 739)+ subjects/provinces facet(≥35 省,码点升序;索引 v2 + 磁盘快照 + 分块预热) |
33
+ | `/api/paper?id=` | GET | 单卷详情:给定材料分段 + 题目(分值/要求)+ 参考答案;配图已改写为端点 URL |
34
+ | `/api/topics` | GET | 专题树(channels[xingce/shenlun] + topics + entries 统一练习路由 `{view, params}`) |
35
+ | `/api/essay/list?type=&limit=` | GET | 申论题目聚合(五类题型) |
36
+ | `/api/essay/grade` | POST | 小题离线评分:要点覆盖 50%/结构 20%/字数 15%/语言 15% → `{score,max,dims,hitTerms,missingTerms,feedback}` |
37
+ | `/api/essay/article` | POST | 大作文:字数五档 + 结构要素 + 论证标志 → `{lengthBand,lengthPenalty,elements,…}` |
38
+ | `/api/essay/history` | GET | 申论历史 + avgRatio(dashboard/obs 消费) |
39
+ | `/api/paper/exam/start?id=` | GET | 整卷模考开始(**不下发答案防作弊**) |
40
+ | `/api/paper/exam/submit` | POST | 服务端比对交卷 → 模块得分分布 + 错题清单 |
41
+ | `/api/paper/exam/history` | GET | 模考历史 + avgRate |
42
+ | `/api/paper-img?id=&p=` | GET | **二进制**:试卷配图(基准目录=dirname(paperId)) |
43
+
44
+ ## 四、深度题库(naokuApi · GongkaoNaoku 27506 题五维标注)
103
45
 
104
46
  | 端点 | 方法 | 说明 |
105
47
  |---|---|---|
106
- | `/api/naoku/status` | GET | 题库状态 + 标注覆盖率 + 模块/题型分布 |
107
- | `/api/naoku/questions?module=&category=&kadian=&count=` | GET | 抽题(含五维标注 + 配图 markdown) |
108
- | `/api/naoku/kadian?q=&limit=` | GET | 知识点检索(考点 → 思路) |
48
+ | `/api/naoku/status` | GET | 就绪状态 + 覆盖率 + 分布(node:sqlite 只读,动态 import) |
49
+ | `/api/naoku/questions?module=&category=&kadian=&count=` | GET | 抽题(五维标注 + 配图 markdown) |
50
+ | `/api/naoku/kadian?q=&limit=` | GET | 知识点检索(考点→思路) |
109
51
  | `/api/naoku/practice?kadian=&count=` | GET | 按知识点刷题 |
110
- | `/api/naoku-img?p=` | GET | **二进制**:深度题库配图 |
52
+ | `/api/naoku/papers?category=` | GET | 考点→试卷反查 |
53
+ | `/api/naoku/categories` | GET | 考点清单 |
54
+ | `/api/naoku-img?p=` | GET | **二进制**:配图(webp 磁盘记 png 由 resolveNaokuImage 换扩展) |
55
+
56
+ 五维字段:`kadian`考点定位(100%) · `reasoning`推理链(100%) · `fastest`最快解法(41%) · `pitfalls`易错点(41%) · `mother`母题思维(部分)。
111
57
 
112
- 五维标注字段:
58
+ ## 五、图形推理(tuxingApi · gk-tuxing 354 题 13 规律)
113
59
 
114
- | 字段 | 含义 | 覆盖 |
60
+ | 端点 | 方法 | 说明 |
115
61
  |---|---|---|
116
- | `kadian` | 考点定位(考什么) | 100% |
117
- | `reasoning` | 解题推理链(怎么想) | 100% |
118
- | `fastest` | 最快解法(考场用) | 41% |
119
- | `pitfalls` | 易错点 | 41% |
120
- | `mother` | 母题思维 | 部分 |
62
+ | `/api/tuxing/cats` | GET | 规律分类(按题量排序) |
63
+ | `/api/tuxing/list?cat=&limit=` | GET | 抽题列表(含 ans/exp/acc/trap 四字段) |
64
+ | `/api/tuxing/q?id=` | GET | 单题详情 |
65
+ | `/api/tuxing-img?f=` | GET | **二进制**:题干图(354 张本地图) |
121
66
 
122
- ## 五、工具(host 半,模型可见)
67
+ ## 六、计划 / 检索 / 方法论(dataApi)
123
68
 
124
- | 工具 | 类 | 说明 |
69
+ | 端点 | 方法 | 说明 |
70
+ |---|---|---|
71
+ | `/api/plan?day=` | GET | 30 天四阶段计划(正则状态机解析 study-plan.md) |
72
+ | `/api/search?q=&repo=` | GET | 全文检索(DFS 限深 3 + 命中 15 早停) |
73
+ | `/api/method?topic=` | GET | 方法论正文(10 主题,kaogong-skill references) |
74
+ | `/api/methods` | GET | 方法论目录(含每主题 exists) |
75
+ | `/api/banks` · `/api/modules` | GET | 仓库就绪 / 模块题量索引 |
76
+
77
+ ## 七、图谱与可观测(coreApi · 白盒链路)
78
+
79
+ | 端点 | 方法 | 说明 |
80
+ |---|---|---|
81
+ | `/api/graph` | GET | 图谱快照(5s TTL **按 wsKey 分槽缓存**,v1.12 隔离修复):`{nodes,edges,metrics{V,E,density,orphans,components},rank,health,banks,nodeMeta,edgeMeta,analytics{degree,degreeStats,communities,clustering,betweenness,layers},layout,progress}` |
82
+ | `/api/graph/neighborhood?node=&depth=1..3` | GET | k 跳邻域子图(未知节点→`{error}` 200) |
83
+ | `/api/graph/path?from=&to=` | GET | 无向 BFS 最短路(路径分析) |
84
+ | `/api/graph/impact?node=` | GET | 反向可达影响面 |
85
+ | `/api/lifecycle` | GET | 生命周期状态机:`{stages[{stage,desc,state,at}], events[≤50 倒序], current}`(lifecycle.jsonl 环形 300 合成) |
86
+ | `/api/telemetry` | GET | 遥测:`{uptimeSec,qpsWindow,totalRequests,endpoints{path:{count,errors,errRate,p50,p95,lastActive,series[≤100]}},coverage,histogram{p50..max},topSlow[10],alerts[]}`(**路径口径=相对挂载点逻辑路径**,v1.8 假阳性事故固化) |
87
+ | `/api/capabilities` | GET | 能力矩阵 + 对账:`{...CAPABILITIES, runtime, orphans, reconciliation{orphanEndpoints,orphanViews,unconsumedEndpoints,missingProducers}, lifecycle}` |
88
+
89
+ ## 八、题库管理(repoManager · v1.11 一键式安装 · v1.12 增 self)
90
+
91
+ | 端点 | 方法 | 说明 |
125
92
  |---|---|---|
126
- | `kaogong_launch` | 离线 | 平台状态与引导 |
127
- | `kaogong_ai_tutor` | 可选 AI | 错题辅导(拉方法论 + 知识片段) |
128
- | `kaogong_ai_plan` | 可选 AI | 个性化学习建议(读进度) |
129
- | `kaogong_ai_shenlun` | 可选 AI | 申论批改素材 |
130
- | `kaogong_ai_essay_review` | 可选 AI | **深度点评**:离线基线分 + 方法论 → 交模型 |
93
+ | `/api/repos` | GET | 总览:`{root, rootSource, mirror, git(bool 探测), self(SELF_META), repos[15]{key,tier,size,desc,upstream,present,isGit,files,job}, summary{total,present,requiredMissing,running,tiers}}` |
94
+ | `/api/repos/install` | POST | `{key}` → 无仓库 `git clone --depth 1`;有 `.git` `pull --ff-only`;非 git 目录拒绝覆盖;并发上限 2;镜像前缀自动拼接;**windowsHide 静默子进程**(v1.12 修控制台闪现) |
95
+ | `/api/repos/job?key=` | GET | 作业状态 `{state:running|done|failed|canceled, action, url, log[], elapsedSec, error}` |
96
+ | `/api/repos/cancel` | POST | SIGTERM 在途作业 |
97
+ | `/api/repos/remove` | POST | 删除本地数据目录(学习进度不受影响;作业中拒绝) |
98
+ | `/api/repos/browse?key=&sub=` | GET | 目录浏览(≤300 条目;`isInside` 路径穿越防线) |
99
+ | `/api/repos/config` | POST | `{root?, mirror?}` 持久化数据根/镜像(原子写 repos-config.json;root='' 回自动解析);变更后域重建 + 三级缓存失效 |
100
+
101
+ 数据根解析优先级:env `KG_REPOS_DIR` > `data/repos-config.json` > 开发态上级(含任一登记仓库)> `data/repos` 托管默认。
131
102
 
132
- `kaogong_ai_essay_review` 参数:`{paperId?, no?, question?, answer, mode?: 'essay'|'article', workspace?}`
103
+ ## 九、工具(host 半 · 5 个 · 均声明 output:{schema,render})
133
104
 
134
- ## 六、视图清单(13)
105
+ | 工具 | 类 | 说明 |
106
+ |---|---|---|
107
+ | `kaogong_launch` | 离线 | 平台状态引导(v1.12:**全部字段实时取自 /api/status + /api/capabilities + /api/repos**,杜绝模板陈旧漂移;数据缺失时引导一键安装) |
108
+ | `kaogong_ai_tutor` | 可选 AI | 错题辅导素材(method + search) |
109
+ | `kaogong_ai_plan` | 可选 AI | 个性化建议素材(progress 弱项排序) |
110
+ | `kaogong_ai_shenlun` | 可选 AI | 申论批改素材(method + 题目 + 作答) |
111
+ | `kaogong_ai_essay_review` | 可选 AI | 深度点评:先调离线 grade/article 基线分再交模型;参数 `{paperId?, no?, question?, answer, mode?:'essay'|'article', workspace?}` |
135
112
 
136
- `dashboard`(仪表盘) · `practice`(刷题) · `deepbank`(深度题库) · `exam`(模考) · `papers`(真题卷) · `topics`(专题) · `essay`(申论) · `wrongbook`(错题本) · `plan`(计划) · `search`(检索) · `method`(方法论) · `graph`(图谱) · `observability`(可观测)
113
+ ## 十、视图清单(15)
137
114
 
138
- ## 七、错误码约定
115
+ `dashboard`仪表盘 · `practice`刷题 · `deepbank`深度题库 · `tuxing`图形推理 · `exam`模考 · `papers`真题卷 · `topics`专题 · `essay`申论 · `wrongbook`错题本 · `plan`计划 · `search`检索 · `method`方法论 · `graph`图谱 · `repos`题库管理 · `observability`可观测
139
116
 
140
- | 场景 | 返回 |
141
- |---|---|
142
- | 参数缺失 | `{error: '缺少 xxx 参数'}` |
143
- | 资源不存在 | `{error: '试卷不存在: <id>'}` |
144
- | 能力不可用 | `{fallback: true, hint: '...'}`(不抛错,UI 显示降级提示) |
145
- | 二进制端点 | HTTP 400/403/404/415 + 纯文本 body |
117
+ 一级导航七项(学习/题库/复盘/管理分组):仪表盘/模考/真题卷/专题/错题本/图谱/可观测 + 题库管理;practice/deepbank/tuxing/essay 经专题枢纽分区触达,路由仍直达。
@@ -24,7 +24,7 @@ DSH 插件由 **Host 半** 与 **Client 半** 组成,两者运行在不同进
24
24
  │ src/client/client.js combo 工厂:注册左栏面板 + 右侧标签 │
25
25
  │ ├─ sidebar.panellist → 左栏「📚 考公学习」图标 │
26
26
  │ ├─ sidebar.right.pane.tab → 右侧并排标签 │
27
- │ └─ 13 个原生 React 视图(同一文件内,见 §4) │
27
+ │ └─ 15 个原生 React 视图(12 模块合并 combo,见 §4) │
28
28
  │ │
29
29
  │ src/ui/index.html 零依赖 SPA(独立端口通道的完整界面) │
30
30
  └──────────────────────────────────────────────────────────────────────┘
@@ -54,22 +54,31 @@ ctx.inject(['webServer'], (injected) => {
54
54
  - 服务启动**只能** `startServer(...).catch(...)`:`listen` 的 EADDRINUSE 是异步事件,`try/catch` 捕不到(cycle-0 曾击杀宿主)。
55
55
  - 本代资源一律**闭包局部变量**,cleanup 只清自己那代(R7 热重载竞态)。
56
56
 
57
- ## 3. Server 层:域链分发
57
+ ## 3. Server 层:域链分发 + 数据根重建(v1.11+)
58
58
 
59
59
  ```js
60
- // src/server/http.js
61
- function handleApi(path, params, post, method, wsRaw, port) {
62
- return srsApi(...) // 错题本 SRS
63
- ?? naokuApi.handle(...) // 深度题库(27506 题)
64
- ?? paperApi.handle(...) // 真题卷/专题/申论评改/模考
65
- ?? dataApi(...) // 题库/计划/方法论/检索
66
- ?? coreApi(...) // status/stats/graph/telemetry/capabilities
60
+ // src/server/http.js —— cycle-16 起 handleApi 异步(repoManager 作业面)
61
+ async function handleApi(path, params, post, method, wsRaw, port) {
62
+ if (path.startsWith('/api/repos')) { const r = await repoManager.handle(...); if (r) return r }
63
+ return domains.srsApi(...) // 错题本 SRS + 专项记忆
64
+ ?? domains.tuxingApi.handle(...) // 图形推理
65
+ ?? domains.naokuApi.handle(...) // 深度题库(27506 题)
66
+ ?? domains.paperApi.handle(...) // 真题卷/专题/申论评改/模考
67
+ ?? domains.dataApi(...) // 题库/计划/方法论/检索
68
+ ?? coreApi(...) // status/stats/graph/telemetry/capabilities
67
69
  }
68
70
  ```
69
71
 
72
+ - **数据根四级解析**(v1.11 一键式安装的基座):`buildDomains(root)` 集中装配全部域,
73
+ root 由 `dataRoot.resolveReposRoot()` 解析(env `KG_REPOS_DIR` > `data/repos-config.json`
74
+ > 开发态上级目录 > `data/repos` 托管默认)。安装/删除/换根 → `rebuildDomains()`:
75
+ 新 root 重建域 + 三级缓存失效(`resetPaperIndex` / `resetNaoku` / `graphCache.clear`)。
76
+ **纪律:路径是运行期事实,不是加载期常量**(教训⑫⑬)。
70
77
  - 域模块返回 `undefined` 表示「不是我的路由」,继续下一个;返回对象即响应体。
71
- - **二进制端点**(`/api/paper-img`、`/api/naoku-img`)在 JSON 链路**之前**分流,直接 `pipe` 文件流。
72
- - 隔离:所有写路径按 `?ws=<workspace>` 哈希命名,落 `data/progress/<slug>-<hash8>.json`。
78
+ - **二进制端点**(`/api/paper-img`、`/api/naoku-img`、`/api/tuxing-img`)在 JSON 链路**之前**分流,直接 `pipe` 文件流。
79
+ - 隔离:所有写路径按 `?ws=<workspace>` 哈希命名,落 `data/progress/<slug>-<hash8>.json`;
80
+ **图谱快照缓存按 wsKey 分槽**(v1.12:快照内嵌 progress 是 ws 相关字段,全局单槽缓存会跨工作区泄漏——LRU 上限 24 槽)。
81
+ - 崩溃安全:spawn git 子进程 `windowsHide:true` + `on('error')` 全接住 + `GIT_TERMINAL_PROMPT=0`(v1.12 修控制台窗口闪现;一切外部异步错误挂回作业状态,绝不冒泡)。
73
82
 
74
83
  ## 4. Client 半:combo 工厂(关键约束)
75
84
 
@@ -98,7 +107,11 @@ window.__ModuleLoader__.load({
98
107
  | factory 必须 `return {inject, apply}` | `invalid plugin, expected apply, received undefined` | 加载器取返回值为插件定义(R11b) |
99
108
  | **不得 require 本地文件** | 加载失败 | `require` 只解析宿主模块表内的**包**,无相对路径 |
100
109
 
101
- → 所以 `client.js` 是**单文件 1200 行、13 个视图**。这不是懒,是加载器约束。复杂度预算因此设为 180(见 `.cycles/config.yml`)。
110
+ → 源码是 `src/client/*.ts` **12 个真 ESM 模块**(cycle-13 T-025 拆分:ui-kit / study-view / papers-view / graph-analytics / graph-physics / graph-transition / graph-canvas / graph-engine / graph-view / obs-view / repos-view / client),
111
+ tsc 产出多文件后由 `scripts/bundle-client.mjs` 按 **DFS 拓扑序**合并回单文件 combo。
112
+ 铁律:不重命名标识符、不压缩、不删注释;合并后共享 factory **单一作用域 → 全部文件顶层名必须唯一**
113
+ (前缀纪律:graph 系 `graph*/KG_*`、study 系 `kg*/Kg*`、obs 系 `Obs*`、repos 系 `rp*/Rp*/RP_*`)。
114
+ 复杂度预算 180(`.cycles/config.yml`),超预算按「只读纯函数外提 + 闭包值同名参数穿线」模式拆分。
102
115
 
103
116
  ### 样式注入
104
117
 
@@ -117,7 +130,7 @@ ctx.effect(() => {
117
130
 
118
131
  | 入口 | 机制 | 数量 |
119
132
  |---|---|---|
120
- | 左栏面板 | `sidebar.panellist` 图标(svg 带 `data-dsh-panel-entry`) + `main` keyed slot 全屏页 | 1 个图标 → 13 视图 |
133
+ | 左栏面板 | `sidebar.panellist` 图标(svg 带 `data-dsh-panel-entry`) + `main` keyed slot 全屏页 | 1 个图标 → 15 视图 |
121
134
  | 右侧标签 | `sidebarRightTabs.register()` + `sidebar.right.pane.tab` keyed slot **双注册同 id** | 1 个标签 → 同一套视图 |
122
135
 
123
136
  图标**不要自己绑 click**——shell 用 `data-dsh-panel-entry` 做事件委托,自己绑会双重触发。
@@ -127,7 +140,7 @@ ctx.effect(() => {
127
140
  | 模式 | 视图 | 说明 |
128
141
  |---|---|---|
129
142
  | **父 effect 驱动** | dashboard / wrongbook / graph / obs | 父组件 `useEffect` 按 `view` 拉数据,`setData({kind,...})`,子视图只渲染 |
130
- | **子组件自管** | papers / topics / essay / practice / exam / deepbank | 子组件内 `useEffect` 自行 fetch;父只负责挂载与传参 |
143
+ | **子组件自管** | papers / topics / essay / practice / exam / deepbank / tuxing / repos | 子组件内 `useEffect` 自行 fetch;父只负责挂载与传参 |
131
144
 
132
145
  子组件自管的理由:避免父 effect 的 `data` 状态与「提交后重挂载换题」互相干扰(v1.6 刷题 bug 的根因)。
133
146
 
@@ -143,3 +156,7 @@ ctx.effect(() => {
143
156
  | 1.6 | 真题卷 | 1683 套卷、专题、申论离线评改 |
144
157
  | 1.7 | 深度 + 完整交互 | 27506 题五维标注、整卷模考、大作文分档、配图 |
145
158
  | 1.7.2 | 回归修复 | R15 组件丢失、R14 视图覆盖补齐、docs/agents |
159
+ | 1.8–1.9 | 图谱与白盒 | 交互图谱引擎(FR/预收敛/标签去重叠)、算法族 9 个、白盒面板、专题枢纽、省份维度、环形布局前夜 |
160
+ | 1.10 | 专项刷题记忆 | /api/memory(kind 白名单+8KB+LRU)、三专项视图「上次练到」横幅一键跳回原题、图谱第三布局环形 + 边流动粒子、白盒三件套 |
161
+ | 1.11 | 一键式题库管理 | 数据根四级解析 + 域工厂重建、repoManager(clone/pull/删除/浏览/作业面/镜像代理)、repos-view 面板 + 关于本项目卡、REPOS_META 15 仓库分级注册表、发布卫生(GitHub + npm) |
162
+ | 1.12 | 隔离与显示修复 | 图谱缓存按 wsKey 分槽(跨项目不互染)、spawn windowsHide(控制台闪现根因)、kaogong_launch 输出全实时化(模板陈旧根因)、peer 预发布分支(市场规范)、市场合规(topic/icon/screenshots) |
@@ -11,7 +11,7 @@ client 半就是 React 18 应用:
11
11
  ```js
12
12
  const React = require('react') // 宿主模块表提供,无需打包
13
13
  const h = React.createElement
14
- // 13 个视图全部是函数组件,用 hooks:
14
+ // 15 个视图全部是函数组件,用 hooks:
15
15
  const [view, setView] = React.useState('dashboard')
16
16
  React.useEffect(() => { /* fetch */ }, [view])
17
17
  React.useCallback(...) / React.useRef(...) / React.useMemo(...)
@@ -41,10 +41,10 @@ React.useCallback(...) / React.useRef(...) / React.useMemo(...)
41
41
 
42
42
  | TS 能拦住的问题 | 本项目的替代防线 |
43
43
  |---|---|
44
- | 未定义标识符(如 R15 的 `NativeDeepBankView is not defined`) | `node --check`(语法通过但引用未定义查不出)→ **靠 render.test 真挂载每个视图**(R15 后已覆盖全部 13 视图) |
44
+ | 未定义标识符(如 R15 的 `NativeDeepBankView is not defined`) | `node --check`(语法通过但引用未定义查不出)→ **靠 render.test 真挂载每个视图**(R15 后已覆盖全部 15 视图) |
45
45
  | prop 形状不匹配(R12 的 `props.data.metrics` 读到 undefined) | **render.test mock 全端点真实形状 + 每次切换断言无 `role="alert"`** |
46
46
  | 字符串枚举拼错(如 `view === 'deepbank'`) | smoke 静态断言 + 真机点击验证 |
47
- | 后端响应结构漂移 | smoke 端到端断言(80 条,跑真实 server + 真实数据) |
47
+ | 后端响应结构漂移 | smoke 端到端断言(204 条,跑真实 server + 真实数据) |
48
48
 
49
49
  这些防线**能覆盖大部分类型错误**,但确实不如编译器早——R15 就是漏到了真机才发现(因为 render 测试当时只点了 3 个视图)。
50
50
 
@@ -106,6 +106,18 @@ function MyView({ api }) {
106
106
  - 返回 `undefined` = 不归我管;返回对象 = 响应体(自动 JSON 序列化)。
107
107
  - **二进制端点**必须注册在 JSON 链路之前,并做:路径穿越防护(`resolve` 后必须仍在根内)+ 扩展名白名单 + `writeHead` 失败保护(头已发出不得二次写)。
108
108
  - 新端点三件套:**manifest 声明 → server 实现 → UI 消费**,缺一 drift。
109
+ - **路径是运行期事实**(R19):数据根一律经 `dataRoot.resolveReposRoot()` 解析;变更走 `rebuildDomains()`(域重建 + resetPaperIndex/resetNaoku/graphCache 三失效),禁止新增加载期硬编码路径。
110
+ - **缓存键覆盖响应的全部可变输入维度**(R20):响应含 per-ws 字段(如 progress)时,缓存必须按 wsKey 分槽并设上限(graphCache Map + LRU 24)。
111
+ - **子进程纪律**(R21/cycle-0 同族):`spawn` 一律 `windowsHide: true`(Windows 控制台闪现)+ `GIT_TERMINAL_PROMPT=0` 类无交互开关 + `on('error')` 与 close 非零码全部收敛为作业状态;外部异步错误绝不冒泡。
112
+ - **面向模型/用户的文案从事实源渲染**(R22):工具输出、引导文案一律取自 `/api/capabilities` 等实时端点,不手写模板(防声明/呈现漂移)。
113
+ - 业务性失败返回 `{error}` + HTTP 200(UI 卡片级降级);仅基础设施异常才 5xx。
114
+
115
+ ### 2.3b 市场与发布纪律(v1.12 新增)
116
+
117
+ - peer/engines 范围必须带**显式预发布分支**(`>=A <B-0 || >=B-rc.0 <C-0 || …`)——无预发布分支的宽范围静默排除所有 rc(node-semver 规则),用户 ERESOLVE。
118
+ - 发布走**独立干净快照目录**(无 `data/`、`.dsh/`、`.cycles/`、开发仓 git 历史);`npm pack --dry-run` 是包卫生的机器证据。
119
+ - GitHub 推送优先 **SSH**(Windows 下 HTTPS 443 易被重置,22 端口稳定)。
120
+ - 市场投稿 = 一个 YAML 文件(`data/plugins/<owner>__<repo>.yml`);仓库需 topic `dsh-plugin`、`dsh.bundle` 声明、真实代码、描述数字与代码核对属实。
109
121
 
110
122
  ### 2.4 适配器纪律
111
123
 
@@ -1,20 +1,31 @@
1
1
  # 数据源与适配器
2
2
 
3
- > 15 个开源仓库 → 三个适配器。原则:**只读**源仓库,慢操作做缓存,平台能力做降级。
4
-
5
- ## 一、仓库地图(工作区 `D:\Projects\TraeProjects\kaogong`)
6
-
7
- | 仓库 | 规模 | 内容 | 本项目用途 |
8
- |---|---|---|---|
9
- | **gwy-zhenti** | 1806 md + **114849 图** | 真题卷(**1683 套**:申论 944 / 行测 739,2008–2026) | ✅ 真题卷库 / 申论 / 模考 / 配图 |
10
- | **GongkaoNaoku** | 147MB db 分片 | **27506 题五维标注**(考点/推理链/速解/易错/母题) | ✅ 深度题库 |
11
- | **xingcezhenti** | 39051 图 + 分模块 | 行测分模块题 + 图片库 | ✅ 深度题库配图来源 |
12
- | **kaogong-skill** | 80 文件 | 方法论 10 主题 | ✅ 方法论视图 / AI 工具素材 |
13
- | **xingce-app** | 325 文件 | 行测应用 | 部分(题库) |
14
- | **gk-tuxing** | 390 文件 | 图形推理专题站 | 规划中(T-023) |
15
- | **qiuzhao-epi-bank** | 72 文件 | 求职 EPI 题库 | 参考 |
16
- | **civil-exam-agent** | 95 文件 | Agent 实验 | 参考 |
17
- | **developer2gwy** / **sakib** / **NovaForge** / **yunduanqiqu** / **kaogongzhentizhengliu** / **AdministrativeAptitudeTest** / **Exam_Database** | 小 | 笔记/工具/镜像 | 备用 |
3
+ > 15 个开源仓库 → 适配器层。原则:**只读**源仓库,慢操作做缓存,平台能力做降级。
4
+ > **v1.11 关键变化:数据根可配置**。npm/GitHub 安装态下插件包内不含数据(~2.2GB,归上游作者),
5
+ > 数据根四级解析:env `KG_REPOS_DIR` > `data/repos-config.json` > 开发态上级目录 > `data/repos` 托管默认;
6
+ > 用户在「📦 题库管理」一键克隆(分级:必选/推荐/可选),安装/删除后域重建 + 三级缓存失效。
7
+
8
+ ## 一、仓库地图(根=运行期解析的数据根,见上;开发态识别为工作区上级目录)
9
+
10
+ | 仓库 | tier | pack | 内容 | 本项目用途 |
11
+ |---|---|---|---|---|
12
+ | **xingcezhenti** | 必选 | 341MB | 515 套卷 58890 题分模块 + 39051 图 | ✅ 刷题硬依赖 / 深度题库配图来源 |
13
+ | **kaogong-skill** | 必选 | 3MB | 方法论 10 主题 | ✅ 方法论视图 / AI 工具素材 |
14
+ | **gk-tuxing** | 必选 | 19MB | 图形推理 354 题逐题解析(13 规律) | ✅ 图推视图(T-023 已落地) |
15
+ | **gwy-zhenti** | 推荐 | 626MB | 真题卷 **1683 套**(申论 944/行测 739,2008–2026)+ 114849 图 | ✅ 真题卷库 / 申论 / 模考 / 配图 |
16
+ | **GongkaoNaoku** | 推荐 | 120MB | **27506 题五维标注** db 分片 | ✅ 深度题库 |
17
+ | kaogongzhentizhengliu | 可选 | 208MB | 22375 篇考点重组深度笔记 | 检索增强 |
18
+ | AdministrativeAptitudeTest | 可选 | 2MB | 近二十年国考省考选调生试卷 PDF | 打印模考 |
19
+ | NovaForge | 可选 | 3MB | 通用笔记模板(LaTeX/Typst/Markdown) | 备用 |
20
+ | sakib | 可选 | 1MB | 公考知识文档库 | 检索增强 |
21
+ | developer2gwy | 可选 | 1MB | 程序员上岸公考实践指南 | 备用 |
22
+ | Exam_Database | 可选 | 131MB | 多渠道考公素材题库 | 检索增强 |
23
+ | qiuzhao-epi-bank | 可选 | 486MB | 秋招行测/银行 EPI 697 题 PWA | 参考 |
24
+ | xingce-app | 可选 | 46MB | 离线行测 App(22298 题 Android) | 数据参考 |
25
+ | civil-exam-agent | 可选 | 276MB | 公考督导智能体系统 | 参考 |
26
+ | yunduanqiqu | 可选 | 5MB | 申论范文/面试真题/素材分享 | 备用 |
27
+
28
+ > 注册表真值 = `src/shared/manifest.ts` 的 `REPOS_META`(含 upstream 真实地址);本表与其同步。
18
29
 
19
30
  ## 二、适配器一览
20
31
 
@@ -89,10 +100,10 @@
89
100
 
90
101
  1. 勘察真实结构(**必须看原始字节**,不能凭假设——CRLF、中文键、图片扩展名都踩过坑)。
91
102
  2. 写适配器到 `src/adapters/`,只读 + 加缓存。
92
- 3. 若产出新端点 → 先改 `manifest.js`。
93
- 4. 在 `src/server/` 加域模块并挂进 `handleApi` 链。
94
- 5. smoke 加**真实数据**端到端断言(不要 mock)。
95
- 6. 更新本文件。
103
+ 3. 若产出新端点 → 先改 `manifest.js`(端点 + REPOS_META 若为新仓库要登记 tier/upstream)。
104
+ 4. 在 `src/server/` 加域模块并挂进 `handleApi` 链(域工厂 `buildDomains` 内装配,保证换根重建覆盖它)。
105
+ 5. smoke 加**真实数据**端到端断言(不要 mock);运行时断言置于 §11b 长阻塞之前、§12 关服务器之前(教训⑤⑧)。
106
+ 6. 更新本文件 + API-REFERENCE。
96
107
 
97
108
  ## 五、性能基线(实测)
98
109
 
@@ -16,9 +16,10 @@
16
16
  | **样式** | `styles.insert(css)`(可能不存在)→ `<style>` 兜底 | 全部 UI 样式 | combo 环境未必有 `styles` 全局(R11) |
17
17
  | **本地化** | `ctx.locale.register({...})` | 面板文案 `t()` | 注册必须在 `try/catch` 内,locale 服务缺失时降级为原文 |
18
18
  | **生命周期/热重载** | `ctx.effect(fn, label)` | 路由挂载、样式注入 | 本代资源一律闭包局部变量;模块级可变状态 + cleanup = 热重载竞态源(R7) |
19
- | **兼容性闸门** | `package.json` 的 `peerDependencies` + `engines.dsh` + `dsh.compatibility.dshReleases` | 三处都声明 | 缺声明时 guardian 报「兼容性未知」,闸门无法保护 |
19
+ | **兼容性闸门** | `package.json` 的 `peerDependencies` + `engines.dsh` + `dsh.compatibility.dshReleases` | 三处都声明;**peer 范围带显式预发布分支**(`>=0.2.0-rc.2 <0.2.1-0 || >=0.2.1-rc.0 <0.3.0-0 || >=0.3.0-rc.0 <0.4.0-0`——node-semver 对无预发布分支的宽范围会静默排除所有 rc 版,用户 ERESOLVE;awesome-dsh-plugin 贡献规范明文要求) | 缺声明时 guardian 报「兼容性未知」,闸门无法保护 |
20
20
  | **Plugin Manager** | `plugin_manager install_bundle / set_plugin` | 安装与热重载 | 重装前先 `remove_bundle`;`link:` 挂载改源码即刻生效 |
21
- | **Node 内置能力** | `node:sqlite`(22.19+)、`node:crypto`、`node:fs` | 深度题库只读查询、签名、索引 | `node:sqlite` 必须**动态 import**(顶层 import 会让旧 Node 整插件加载失败) |
21
+ | **Node 内置能力** | `node:sqlite`(22.19+)、`node:crypto`、`node:fs`、`node:child_process` | 深度题库只读查询、签名、索引、**题库一键克隆(spawn git)** | `node:sqlite` 必须**动态 import**(顶层 import 会让旧 Node 整插件加载失败);spawn 必须 `windowsHide:true`(否则 Windows 每次调用闪控制台窗口,v1.12 修)+ `on('error')` 接住 + `GIT_TERMINAL_PROMPT=0` 防无 TTY 挂起 |
22
+ | **插件市场元数据** | `dsh.bundle.patch` + `dsh.client` + `icon.svg` + `assets/icon-180.png` + `screenshots.json` + GitHub topic `dsh-plugin` | awesome-dsh-plugin / dsh-market 收录形态(v1.12 齐备) | 市场条目 YAML 只放 `data/plugins/<owner>__<repo>.yml` 一个文件提交;npm 包的 `repository` 字段必须回指仓库(自动关联下载量) |
22
23
 
23
24
  ## 二、尚未使用、但值得接的能力
24
25
 
@@ -1,4 +1,4 @@
1
- # 事故簿(R1–R15)
1
+ # 事故簿(R1–R22)
2
2
 
3
3
  > 每条都含:现象 → 根因 → 修复 → **守卫**(防止再次发生)。
4
4
  > 新增事故请追加,并在 `smoke.test.mjs` / `render.test.mjs` 落对应断言。
@@ -122,3 +122,49 @@
122
122
  - **现象**:smoke 报 `does not provide an export named 'gradeEssayArticle'`。
123
123
  - **根因**:拆 `paperParse.js` 时删除正则匹配范围过宽,误删该函数。
124
124
  - **修复**:重建;教训同 R15(结构性删除要点名核对导出清单)。
125
+
126
+ ## cycle-15/16/17 新增
127
+
128
+ ### R16 · 图谱「打不开」假象(永久 spinner)
129
+ - **现象**:重复点同一导航项后卡 spinner。
130
+ - **根因**:`setView` 无条件 `setData(null)`,但父 effect 依赖 `[channel, view, api, tick]`——view 未变则不重跑,data 永远 null。
131
+ - **修复**:命中同一视图时自增 `tick` 强制重取。
132
+ - **守卫**:「视图重入」契约(CLAUDE.md v1.8);教训:**清空数据 + 依赖驱动重取组合必须有显式刷新令牌参与依赖**。
133
+
134
+ ### R17 · 力学参数失衡致图谱塌缩
135
+ - **现象**:141 节点全图挤成中心一团,标签 100% 重叠。
136
+ - **根因**:魔数 `LINK=90/REP=9000` 在 V≈140 时弹簧+向心压过斥力。
137
+ - **修复**:Fruchterman-Reingold 按节点数标定(`k=sqrt(area/V)`)+ 预收敛 `relax(140)` + `fit()`。
138
+ - **教训**:力导向参数必须随规模归一,布局后必须适配视口。
139
+
140
+ ### R18 · 预热与同步重建双路争抢(性能倒退)
141
+ - **现象**:冷启动首查 31.5s,比纯同步基线还差。
142
+ - **根因**:分块预热与请求触发的同步 `buildPaperIndex` 并发扫盘互相争抢。
143
+ - **修复**:`prewarmRun` 代际令牌——同步路径启动即作废在途预热;smoke harness 传 `prewarm:false`。
144
+ - **教训**:预热是「尽力而为」,请求路径永远有同步兜底。
145
+
146
+ ### R19 · 安装态数据全缺(发布根本问题)
147
+ - **现象**:npm/GitHub 单独安装后 15 仓库全部 absent,功能空转。
148
+ - **根因**:`REPO_ROOT=上级目录` 是开发态假设;题库 ~2.2GB 且各有上游版权不能随包分发。
149
+ - **修复**:数据根四级解析(dataRoot.ts)+ 域工厂重建(buildDomains/rebuildDomains)+ 题库管理一键克隆(repoManager + repos-view)。
150
+ - **守卫**:smoke R-P-05 静态守卫 + 沙箱 `KG_REPOS_DIR=空目录` 端到端(克隆→功能即时恢复→pull/browse/remove)。
151
+ - **教训**:**路径是运行期事实,不是加载期常量**。
152
+
153
+ ### R20 · 图谱缓存跨工作区泄漏
154
+ - **现象**:A 项目访问 `/api/graph` 后,B 项目在 5s TTL 内命中同一缓存,读到 A 的 `progress`(跨项目污染)。
155
+ - **根因**:graphCache 是全局单槽,但快照内嵌 ws 相关字段。
156
+ - **修复**:缓存改 `Map<wsKey, {ts,data}>` 分槽 + LRU 上限 24 槽。
157
+ - **守卫**:smoke R-P-06 静态守卫 + 运行时双 ws 断言(X.day=7 / Y.day=1)。
158
+ - **教训**:**缓存键必须覆盖响应的全部可变输入维度**——凡响应含 per-tenant 字段,缓存必须 per-tenant。
159
+
160
+ ### R21 · Windows 控制台窗口闪现(「命令窗口显示问题」)
161
+ - **现象**:题库安装/更新时桌面每次弹出黑色 cmd 窗口。
162
+ - **根因**:`spawn('git', …)` 未设 `windowsHide:true`(Node 在 Windows 默认给子进程分配控制台)。
163
+ - **修复**:全部 spawn(含 probeGit)加 `windowsHide:true`;配套 `GIT_TERMINAL_PROMPT=0` 防无 TTY 凭据提示挂起。
164
+ - **教训**:**宿主 GUI 插件里一切 spawn/exec 默认 windowsHide:true**,这是桌面体验硬约束。
165
+
166
+ ### R22 · 工具输出陈旧(「调用时显示问题」另一半)
167
+ - **现象**:`kaogong_launch` 报「7 视图」,实际 15 视图;入口描述停留在「右侧标签」。
168
+ - **根因**:工具 execute 里手写文案模板,与 manifest 演进脱钩(声明/呈现漂移)。
169
+ - **修复**:输出全部实时取自 `/api/capabilities`(views/tools/endpoints 计数)+ `/api/status`(repoRoot/pid)+ `/api/repos`(数据就绪与缺失引导)。
170
+ - **守卫**:「凡声明 vs 运行态对账,两侧口径必须同源」纪律的呈现层推论——**面向用户/模型的文案也从事实源渲染,不手写**。
@@ -20,20 +20,24 @@
20
20
 
21
21
  | 文档 | 内容 | 维护触发条件 |
22
22
  |---|---|---|
23
- | [ARCHITECTURE.md](./ARCHITECTURE.md) | 双半结构、combo 工厂、数据流、分层与职责 | 新增分层/入口时 |
24
- | [API-REFERENCE.md](./API-REFERENCE.md) | 33 个端点 + 5 个工具 + 13 个视图的契约 | 改端点时(必须同步) |
23
+ | [ARCHITECTURE.md](./ARCHITECTURE.md) | 双半结构、combo 工厂、域工厂重建与数据根四级解析、分层与职责 | 新增分层/入口/域时 |
24
+ | [API-REFERENCE.md](./API-REFERENCE.md) | 51 个端点 + 5 个工具 + 15 个视图的契约 | 改端点时(必须同步) |
25
25
  | [CONVENTIONS.md](./CONVENTIONS.md) | 编码规范、技术选型理由、纪律条款 | 引入新约定时 |
26
- | [DSH-HOST-CAPABILITIES.md](./DSH-HOST-CAPABILITIES.md) | 宿主能力盘点:已用/可用未用 | 发现新宿主能力时 |
27
- | [DATA-SOURCES.md](./DATA-SOURCES.md) | 15 仓库存量、3 个适配器、字段映射 | 接入新仓库时 |
28
- | [TESTING.md](./TESTING.md) | 测试金字塔、发布流程、ANIC 循环 | 测试策略变化时 |
29
- | [INCIDENTS.md](./INCIDENTS.md) | R1–R15 事故簿(根因+修复+守卫) | 每次线上/真机事故后 |
26
+ | [DSH-HOST-CAPABILITIES.md](./DSH-HOST-CAPABILITIES.md) | 宿主能力盘点:已用/可用未用/市场合规 | 发现新宿主能力时 |
27
+ | [DATA-SOURCES.md](./DATA-SOURCES.md) | 15 仓库分级注册表(tier/upstream/体积)、适配器、字段映射 | 接入新仓库时 |
28
+ | [TESTING.md](./TESTING.md) | 测试金字塔、发布流程(GitHub SSH + npm + 市场合规清单)、ANIC 循环 | 测试/发布策略变化时 |
29
+ | [INCIDENTS.md](./INCIDENTS.md) | R1–R22 事故簿(根因+修复+守卫) | 每次线上/真机事故后 |
30
30
  | [ROADMAP.md](./ROADMAP.md) | 技术债清单与演进方向 | 每轮迭代收口时 |
31
31
 
32
32
  ## 铁律(违反即回归)
33
33
 
34
34
  1. **改端点先改 manifest**(`src/shared/manifest.js` 是 SSOT),否则能力矩阵漂移。
35
35
  2. **client 半必须是 combo 工厂格式**,无顶层 `export`,factory 尾部必须 `return { inject, apply }`。
36
- 3. **client 半不得拆本地文件**(加载器只支持包级 `require`)——这是 client.js 单文件的合法理由。
36
+ 3. **client 源码可拆多模块,但顶层名必须全局唯一**(bundler 合并后共享单一作用域,重名即 SyntaxError)——改完任何 `src/client/*.ts` 必须 `npm run build`。
37
37
  4. **子视图必须作为组件挂载**(`h(Comp, props)`),禁止函数直调(R9 白屏事故)。
38
38
  5. **每次视图切换必须有 render 断言覆盖**(R12/R15 的教训:漏测即漏检)。
39
39
  6. **沙箱验证通过才允许动主力 profile**(S9.5 纪律)。
40
+ 7. **路径是运行期事实,不是加载期常量**:数据根走四级解析;变更即域重建 + 三级缓存失效(R19)。
41
+ 8. **响应含 per-tenant 字段时缓存必须 per-tenant**(R20 跨工作区泄漏)。
42
+ 9. **一切子进程 spawn 默认 `windowsHide:true` + `on('error')` 接住**(R21/cycle-0 同族)。
43
+ 10. **面向用户/模型的文案从事实源渲染,不手写模板**(R22 输出陈旧)。
@@ -2,39 +2,41 @@
2
2
 
3
3
  > 债务清单同步 `.cycles/tech-debt/backlog.md`。每轮迭代收口时更新状态。
4
4
 
5
- ## 当前状态(v1.7.5)
5
+ ## 当前状态(v1.12.0)
6
6
 
7
7
  | 维度 | 数据 |
8
8
  |---|---|
9
9
  | 真题卷 | 1683 套(申论 944 / 行测 739,2008–2026) |
10
10
  | 深度题库 | 27506 题(知识点覆盖 100%,速解 41%,含图 10647) |
11
11
  | 本地图片 | 11 万+(试卷配图 + 354 张图推题图) |
12
- | 视图 | 14 个原生 React 视图 + 1 个会话输入栏控件 |
13
- | 端点 | 39 个 |
14
- | 工具 | 5 个(1 离线 + 4 可选 AI) |
15
- | 断言 | smoke 86 + render 11 |
12
+ | 视图 | 15 个原生 React 视图(含题库管理 repos) |
13
+ | 端点 | 51 个 |
14
+ | 工具 | 5 个(1 离线 + 4 可选 AI,输出全部实时取自能力矩阵) |
15
+ | 断言 | smoke 204 + render 42 |
16
+ | 数据根 | 四级可配置(env/config/开发态上级/托管默认)+ 一键克隆分级 |
17
+ | 发布 | GitHub(SSH)+ npm + 市场合规齐备 |
16
18
 
17
19
  ## 待办(按价值排序)
18
20
 
19
- ### T-019 · 试卷按考点筛选
20
- - 现状:只能按 科目 + 年份 筛。
21
- - 目标:用 naoku 的 `category`/`kadian` 反查卷内题号 → 支持「图形推理」这类考点直达试卷。
21
+ ### T-026 · 图谱「学习画像」叠加层
22
+ - 现状:图谱反映插件结构(模块/端点/视图),学习洞察只在仪表盘卡片。
23
+ - 目标:把「考点掌握」按 PageRank/社区着色叠加到图谱(用户画像与系统画像合一),支持「弱区高亮」模式。
22
24
 
23
- ### T-020 · 图谱 / 可观测接入学习洞察
24
- - 现状:图谱只反映插件结构(模块依赖),可观测只反映 runtime 指标。
25
- - 目标:图谱加「考点掌握热力」,可观测加「做题质量趋势 / 考点雷达」。让用户看到**自己的**画像而非系统画像。
25
+ ### T-027 · 学习计划智能化(原 T-025 延续)
26
+ - 现状:30 天四阶段静态日历 + 手动滑杆。
27
+ - 目标:按「剩余天数 + 各模块正确率 + 错题积压」自动排程(弱点加权已有 SRS 基础)。
26
28
 
27
- ### T-021 · 材料-题目联动
28
- - 现状:申论材料 11 段,题目说「关联材料 1、3、5」,但材料区不联动。
29
- - 目标:点关联段号 → 滚动并高亮对应材料段。
29
+ ### T-028 · 题库增量更新与断点续传
30
+ - 现状:pull --ff-only 全量;大仓库(626MB)弱网失败需手动重来。
31
+ - 目标:作业失败自动重试 + `git fetch --depth 1` 增量;镜像不可用自动回落直连。
30
32
 
31
- ### T-023 · 图形推理专题站整合(gk-tuxing)
32
- - 仓库有 390 文件专门做图形推理。当前仅通过题目配图间接使用。
33
- - 目标:做「图形推理专项」视图(按规律类型分类:数量/位置/样式/属性)。
33
+ ### T-029 · 设置面板接入宿主 settings
34
+ - 现状:主题/倒计时/每日目标等无用户可调面(README 能力矩阵登记为 ⏸)。
35
+ - 目标:`ctx.settings` 配置表单(宿主能力矩阵「未用缝」的正当启用场景)。
34
36
 
35
- ### T-025 · 学习计划智能化
36
- - 现状:30 天四阶段静态日历 + 手动滑杆。
37
- - 目标:按「剩余天数 + 各模块正确率 + 错题积压」自动排程。
37
+ ### T-030 · awesome-dsh-plugin 收录 PR
38
+ - 现状:合规项已全部就绪(见 TESTING.md §五b 清单)。
39
+ - 目标:向 awesome-dsh-plugin 提 `data/plugins/xuanyuanchumo__dsh-kaogong.yml`(category: `docs` 或 `tools`,描述取自实测数字)。
38
40
 
39
41
  ## 已清偿
40
42
 
@@ -49,9 +51,15 @@
49
51
  | T-019 | 考点→试卷反查(papersByCategory + 按考点模式) | cycle-10 |
50
52
  | T-020 | 学习洞察(考点掌握热力 + 学习质量) | cycle-10 |
51
53
  | T-021 | 材料-题目联动高亮 | cycle-10 |
52
- | T-023 | 图形推理专项(按规律分类,最小可用) | cycle-10 |
53
- | T-023 | **完整版**:354 题 / 13 类规律 / 原创思路(gk-tuxing 全量整合) | cycle-11 |
54
+ | T-023 | 图形推理专项(354 题 / 13 规律 / 原创思路,gk-tuxing 全量) | cycle-11 |
54
55
  | T-024 | 会话内练题(conversation.input.left 控件) | cycle-11 |
56
+ | T-025 | client 多模块真 ESM 拆分 + 构建期 bundler(combo 契约不变) | cycle-13 |
57
+ | — | 专项刷题记忆 /api/memory + 三视图跳回原题 | cycle-15 |
58
+ | — | 图谱环形布局 + 边流动粒子 + 白盒三件套 | cycle-15 |
59
+ | — | 一键式题库管理(数据根四级/域重建/分级克隆/镜像代理/管理面板) | cycle-16 |
60
+ | — | GitHub + npm 发布;市场合规(topic/icon/screenshots/peer 预发布分支) | cycle-16/17 |
61
+ | — | 图谱缓存按 wsKey 分槽(跨项目隔离,R20) | cycle-17 |
62
+ | — | spawn windowsHide 控制台闪现修复(R21)+ 工具输出实时化(R22) | cycle-17 |
55
63
 
56
64
  ## 演进原则
57
65
 
@@ -6,20 +6,20 @@
6
6
  ┌─────────────────────────────┐
7
7
  ⑤ │ 真机(沙箱 GUI 浏览器) │ 人工+Playwright,5–10 min
8
8
  ├─────────────────────────────┤
9
- ④ │ render.test.mjs 11 断言 │ 真实 React 18 + 真实 client.js,~8s
9
+ ④ │ render.test.mjs 42 断言 │ 真实 React 18 + 真实 client.js,~8s
10
10
  ├─────────────────────────────┤
11
- ③ │ smoke.test.mjs 80 断言 │ 真实 server + 真实数据,~20s
11
+ ③ │ smoke.test.mjs 204 断言 │ 真实 server + 真实数据,~25s
12
12
  ├─────────────────────────────┤
13
- ② │ npm run build(tsc 类型检查+编译)│ ~4s
13
+ ② │ npm run build(tsc 类型检查+编译+bundler 合并 12 模块)│ ~4s
14
14
  └─────────────────────────────┘
15
15
  ```
16
16
 
17
17
  | 层 | 命令 | 覆盖 | 不在覆盖内的 |
18
18
  |---|---|---|---|
19
- | ② 类型 | `npm run build` | **TS 类型错误阻断**(含未定义标识符 R15)、编译产物 | 运行时行为 |
20
- | ③ 冒烟 | `node smoke.test.mjs` | 端点契约、真实数据解析、评分算法、边界/降级、静态守卫 | 浏览器渲染 |
21
- | ④ 渲染 | `node render.test.mjs` | combo 注册、13 视图挂载、hook 稳定性、降级检测 | 真实网络/样式 |
22
- | ⑤ 真机 | 沙箱 + 浏览器 | 视觉、交互、真实加载路径 | 自动化回归 |
19
+ | ② 类型 | `npm run build` | **TS 类型错误阻断**(含未定义标识符 R15)、编译产物、combo 合并终检 | 运行时行为 |
20
+ | ③ 冒烟 | `node smoke.test.mjs` | 端点契约、真实数据解析、评分算法、边界/降级、静态守卫、**题库管理控制面(不真克隆)** | 浏览器渲染 |
21
+ | ④ 渲染 | `node render.test.mjs` | combo 注册、**15 视图挂载**、hook 稳定性、降级检测、键盘行为、安装按钮真实发请求 | 真实网络/样式 |
22
+ | ⑤ 真机 | 沙箱 + 浏览器 | 视觉、交互、真实加载路径、**一键克隆端到端**(`KG_REPOS_DIR=空目录` 模拟安装态) | 自动化回归 |
23
23
 
24
24
  **关键教训**:② 通过 ≠ 能跑。T-022 后宿主编织 `dist/`,smoke 有「dist mtime >= src mtime」新鲜度门,忘记 build 会直接失败。R15(组件定义丢失)语法合法、smoke 绿、render 当时只点 3 个视图 → 到真机才炸。所以 ④ 必须覆盖**每一个导航视图**。
25
25
 
@@ -27,9 +27,9 @@
27
27
 
28
28
  ```bash
29
29
  cd dsh-kaogong
30
- npm run build # tsc:类型检查 + 产出 dist
31
- node smoke.test.mjs # 必须 80/80
32
- node render.test.mjs # 必须 11/11
30
+ npm run build # tsc:类型检查 + 产出 dist + bundler 合并
31
+ node smoke.test.mjs # 必须 204/204
32
+ node render.test.mjs # 必须 42/42
33
33
  ```
34
34
 
35
35
  输出必须贴进交付说明。任一失败不得提交。
@@ -83,6 +83,49 @@ plugin_manager({ action: 'set_plugin', target: 'include:kaogong', enabled: true
83
83
 
84
84
  装/重装:`remove_bundle` → `install_bundle <绝对路径>`。`link:` 挂载改源码即刻生效,但**必须热重载**才重新加载 fiber。
85
85
 
86
+ ## 五b、发布流程(GitHub + npm + 插件市场)
87
+
88
+ **发布走独立干净快照目录**(不在开发仓打 tag 直推——开发仓历史含 147MB 数据 blob 与 `.cycles/`):
89
+
90
+ ```bash
91
+ # 1) 干净快照:源码 + dist + 文档 + 测试;绝不含 data/ .dsh/ .cycles/ node_modules/
92
+ mkdir _publish-kaogong && cp -r dsh-kaogong/{src,dist,locale,scripts,docs,assets,icon.svg,\
93
+ package.json,cordis.patch.yml,smoke.test.mjs,render.test.mjs,README.md,CLAUDE.md,LICENSE,\
94
+ screenshots.json,.gitignore} _publish-kaogong/
95
+ rm -rf _publish-kaogong/data _publish-kaogong/cordis.local.yml
96
+
97
+ # 2) 卫生核验(机器证据,不靠记忆)
98
+ npm pack --dry-run # 期望 ~320KB / ~54 文件,无数据无凭据
99
+ git -C _publish-kaogong ls-files | grep -E '^data/|\.env|token' # 必须空
100
+
101
+ # 3) GitHub(SSH 优先:Windows 下 HTTPS 443 易被重置,SSH 22 稳定)
102
+ git init -b main && git add -A && git commit -m "vX.Y.Z — <主题>"
103
+ git remote add origin git@github.com:xuanyuanchumo/dsh-kaogong.git
104
+ git push origin main && git tag vX.Y.Z && git push origin vX.Y.Z
105
+
106
+ # 4) npm(token 走环境变量引用,不落盘;registry 显式指官方源,本机全局是 npmmirror)
107
+ printf '//registry.npmjs.org/:_authToken=${NPM_TOKEN}\nregistry=https://registry.npmjs.org/\n' > .npmrc.publish
108
+ npm publish --userconfig .npmrc.publish --access public
109
+ npm view dsh-kaogong version dist.fileCount --registry=https://registry.npmjs.org
110
+ ```
111
+
112
+ **首次发布可能 409 Conflict**(registry 对刚下架同名包的 packument 异步处理锁)→ 等 30s 重试。
113
+ 发布后 `npm view` 可能先显示 `0.0.0-stage` 占位,约 1 分钟落位真实版本(异步处理,非失败)。
114
+
115
+ **插件市场(awesome-dsh-plugin)合规清单**(`contributing.md` 硬要求,CI 会逐条查):
116
+
117
+ | 项 | 本仓状态 |
118
+ |---|---|
119
+ | `package.json` 声明 `dsh.bundle.patch`(只声明 `dsh.client` **不可安装**,最常见被拒原因) | ✅ cordis.patch.yml |
120
+ | 仓库有真实可运行代码(非占位/纯 README) | ✅ |
121
+ | 仓库创建满 1 天(CI 自动查) | ⏳ 按提交 PR 当日计 |
122
+ | GitHub topic `dsh-plugin` | ✅ |
123
+ | peer 范围含**显式预发布分支**(否则静默排除所有 rc,用户 ERESOLVE) | ✅ 三段 `\|\|` |
124
+ | npm 包 `repository` 回指该仓库(自动关联下载量;手写 `npm:` 键会被拒) | ✅ |
125
+ | 描述**只说功能、必须属实**(写「51 端点」就得真有 51 个) | ✅ 数字取自 manifest 实测 |
126
+ | 投稿方式:一个 PR 一个文件 `data/plugins/xuanyuanchumo__dsh-kaogong.yml`(README 由脚本生成,勿手改) | ⏳ 待提 PR |
127
+ | 可选:`icon:` 指向 GitHub 托管位图(`assets/icon-180.png`)、本仓 `screenshots.json` 声明 1–8 张 | ✅ 两者齐备 |
128
+
86
129
  ## 六、ANIC 循环(L4 自主)
87
130
 
88
131
  每轮迭代收口:
package/icon.svg ADDED
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="none" stroke="url(#kgg)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <defs>
3
+ <linearGradient id="kgg" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse">
4
+ <stop stop-color="#6366f1"/>
5
+ <stop offset="1" stop-color="#8b5cf6"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <path d="M4 6.4A2.4 2.4 0 0 1 6.4 4H14v24.8H6.4A2.4 2.4 0 0 1 4 26.4z"/>
9
+ <path d="M28 6.4A2.4 2.4 0 0 0 25.6 4H18v24.8h7.6A2.4 2.4 0 0 0 28 26.4z"/>
10
+ <path d="M8 10h3M21 10h3M8 14h3M21 14h3"/>
11
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-kaogong",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "考公备考整合插件 — 一键式题库管理(必选/推荐/可选分级+镜像代理) · 离线可视化 · 双入口 · SRS错题本 · 专项刷题记忆 · 白盒可观测",
5
5
  "homepage": "https://github.com/xuanyuanchumo/dsh-kaogong#readme",
6
6
  "repository": {
@@ -14,11 +14,11 @@
14
14
  "main": "dist/host/index.js",
15
15
  "peerDependencies": {
16
16
  "@deepseek-ai/cordis": "^4.0.1",
17
- "@deepseek-ai/dsh": ">=0.2.0-rc.2 <0.4.0-0"
17
+ "@deepseek-ai/dsh": ">=0.2.0-rc.2 <0.2.1-0 || >=0.2.1-rc.0 <0.3.0-0 || >=0.3.0-rc.0 <0.4.0-0"
18
18
  },
19
19
  "engines": {
20
20
  "node": ">=22.19",
21
- "dsh": ">=0.2.0-rc.2 <0.4.0-0"
21
+ "dsh": ">=0.2.0-rc.2 <0.2.1-0 || >=0.2.1-rc.0 <0.3.0-0 || >=0.3.0-rc.0 <0.4.0-0"
22
22
  },
23
23
  "exports": {
24
24
  ".": "./dist/host/index.js",
@@ -33,6 +33,9 @@
33
33
  "src/shared/types.ts",
34
34
  "locale",
35
35
  "docs",
36
+ "assets",
37
+ "screenshots.json",
38
+ "icon.svg",
36
39
  "README.md",
37
40
  "CLAUDE.md"
38
41
  ],
@@ -0,0 +1,6 @@
1
+ [
2
+ "assets/screenshot-1-dashboard.png",
3
+ "assets/screenshot-2-graph.png",
4
+ "assets/screenshot-3-observability.png",
5
+ "assets/screenshot-4-repos.png"
6
+ ]