dsh-thesis 1.0.0 → 2.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.
Files changed (73) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE.md +1 -1
  3. package/README.md +48 -204
  4. package/docs/autopilot.md +73 -0
  5. package/docs/config.md +113 -0
  6. package/{DESIGN.md → docs/design.md} +94 -73
  7. package/docs/host-api.md +728 -640
  8. package/docs/release.md +126 -0
  9. package/docs/tools.md +76 -0
  10. package/docs/troubleshooting.md +88 -0
  11. package/docs/usage.md +87 -0
  12. package/lib/autopilot/index.d.ts +38 -0
  13. package/lib/autopilot/index.js +159 -0
  14. package/lib/autopilot/intent.d.ts +40 -0
  15. package/lib/autopilot/intent.js +82 -0
  16. package/lib/autopilot/messages.d.ts +22 -0
  17. package/lib/autopilot/messages.js +35 -0
  18. package/lib/autopilot/types.d.ts +60 -0
  19. package/lib/autopilot/types.js +10 -0
  20. package/lib/codewalk/engine.d.ts +1 -1
  21. package/lib/codewalk/engine.js +1 -1
  22. package/lib/codewalk/gate.d.ts +1 -1
  23. package/lib/codewalk/gate.js +1 -1
  24. package/lib/codewalk/host-types.d.ts +4 -31
  25. package/lib/codewalk/prestep.js +1 -1
  26. package/lib/codewalk/tools.js +2 -2
  27. package/lib/config.d.ts +17 -0
  28. package/lib/config.js +9 -1
  29. package/lib/dedup/index.js +0 -6
  30. package/lib/gates/messages.d.ts +7 -3
  31. package/lib/gates/messages.js +7 -4
  32. package/lib/index.d.ts +3 -1
  33. package/lib/index.js +10 -7
  34. package/lib/ingest/index.d.ts +1 -1
  35. package/lib/ingest/index.js +1 -3
  36. package/lib/intake/gate-rules.d.ts +6 -5
  37. package/lib/intake/gate-rules.js +6 -2
  38. package/lib/intake/index.d.ts +0 -17
  39. package/lib/intake/index.js +0 -51
  40. package/lib/intake/questions.d.ts +1 -1
  41. package/lib/intake/questions.js +1 -1
  42. package/lib/paper/lib/docx.js +70 -70
  43. package/lib/paper/lib/layout.d.ts +1 -1
  44. package/lib/paper/lib/layout.js +372 -372
  45. package/lib/paper/lib/ledger.d.ts +1 -1
  46. package/lib/paper/lib/ledger.js +1 -1
  47. package/lib/paper/lib/lit-cache.js +7 -7
  48. package/lib/paper/register.d.ts +2 -2
  49. package/lib/paper/register.js +2 -8
  50. package/lib/paper/tools/decision.js +5 -5
  51. package/lib/paper/tools/init.d.ts +1 -1
  52. package/lib/paper/tools/init.js +1 -1
  53. package/lib/paper/tools/lit.js +32 -32
  54. package/lib/ppt/index.d.ts +1 -2
  55. package/lib/ppt/index.js +1 -2
  56. package/lib/shared/define-tool.d.ts +1 -1
  57. package/lib/shared/define-tool.js +1 -1
  58. package/package.json +26 -21
  59. package/skills/code-walkthrough/SKILL.md +5 -3
  60. package/skills/thesis-defense/SKILL.md +1 -1
  61. package/skills/thesis-pipeline/SKILL.md +3 -3
  62. package/lib/codewalk/commands.d.ts +0 -23
  63. package/lib/codewalk/commands.js +0 -168
  64. package/lib/commands.d.ts +0 -33
  65. package/lib/commands.js +0 -60
  66. package/lib/dedup/commands.d.ts +0 -21
  67. package/lib/dedup/commands.js +0 -93
  68. package/lib/ingest/commands.d.ts +0 -23
  69. package/lib/ingest/commands.js +0 -74
  70. package/lib/paper/commands.d.ts +0 -13
  71. package/lib/paper/commands.js +0 -84
  72. package/lib/ppt/commands.d.ts +0 -28
  73. package/lib/ppt/commands.js +0 -71
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 进度台账、时间线、决定日志的数据模型与读写逻辑。
3
3
  *
4
- * 设计要点(见 DESIGN.md §5):
4
+ * 设计要点(见 docs/design.md §5):
5
5
  * - 台账的机器真相是一个 JSON 状态块,藏在 Markdown 的 `<!-- thesis:state -->`
6
6
  * HTML 注释里;表格等人类可读部分由 renderLedger 每次重绘,两者永不失步。
7
7
  * - 关卡闸门(G1/G2/G3/G4)在工具层强制执行,不是"靠 AI 自觉":
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 进度台账、时间线、决定日志的数据模型与读写逻辑。
3
3
  *
4
- * 设计要点(见 DESIGN.md §5):
4
+ * 设计要点(见 docs/design.md §5):
5
5
  * - 台账的机器真相是一个 JSON 状态块,藏在 Markdown 的 `<!-- thesis:state -->`
6
6
  * HTML 注释里;表格等人类可读部分由 renderLedger 每次重绘,两者永不失步。
7
7
  * - 关卡闸门(G1/G2/G3/G4)在工具层强制执行,不是"靠 AI 自觉":
@@ -57,13 +57,13 @@ export function mergeRecords(cache, records) {
57
57
  next[record.id] = record;
58
58
  return { version: 1, records: next };
59
59
  }
60
- const RECORD_HEADER = `# 文献检索记录
61
-
62
- > 每次检索留痕:哪个库、什么关键词、命中多少、收录哪些。
63
- > 这是"零假文献"的审计证据。
64
-
65
- | 日期 | 动作 | 数据库 | 关键词/文献 | 命中 | 备注 |
66
- |---|---|---|---|---|---|
60
+ const RECORD_HEADER = `# 文献检索记录
61
+
62
+ > 每次检索留痕:哪个库、什么关键词、命中多少、收录哪些。
63
+ > 这是"零假文献"的审计证据。
64
+
65
+ | 日期 | 动作 | 数据库 | 关键词/文献 | 命中 | 备注 |
66
+ |---|---|---|---|---|---|
67
67
  `;
68
68
  export async function appendLitRecord(fs, root, row, signal) {
69
69
  const path = nodePath.join(root, LIT_RECORD_REL);
@@ -1,8 +1,8 @@
1
1
  /**
2
- * 论文工作区的工具与命令装配:台账、关卡、文献、评审、检查、构建、答辩素材。
2
+ * 论文工作区的工具装配:台账、关卡、文献、评审、检查、构建、答辩素材。
3
3
  *
4
4
  * 纯业务逻辑在 `paper/tools/*.ts` 与 `paper/lib/*.ts`(零 cordis 依赖、可独立
5
- * 测试);本文件只做 `defineTool` / 命令注册的胶水。
5
+ * 测试);本文件只做 `defineTool` 的胶水。
6
6
  *
7
7
  * @module dsh-thesis/paper
8
8
  */
@@ -1,13 +1,12 @@
1
1
  /**
2
- * 论文工作区的工具与命令装配:台账、关卡、文献、评审、检查、构建、答辩素材。
2
+ * 论文工作区的工具装配:台账、关卡、文献、评审、检查、构建、答辩素材。
3
3
  *
4
4
  * 纯业务逻辑在 `paper/tools/*.ts` 与 `paper/lib/*.ts`(零 cordis 依赖、可独立
5
- * 测试);本文件只做 `defineTool` / 命令注册的胶水。
5
+ * 测试);本文件只做 `defineTool` 的胶水。
6
6
  *
7
7
  * @module dsh-thesis/paper
8
8
  */
9
9
  import { definePaperTool, sessionCwd, textOutput, writeBinary } from "../shared/index.js";
10
- import { buildCommand, checkCommand, decideCommand, litCommand, statusCommand } from "./commands.js";
11
10
  import { initSummary, runInit } from "./tools/init.js";
12
11
  import { runProgress } from "./tools/progress.js";
13
12
  import { runDecision } from "./tools/decision.js";
@@ -175,9 +174,4 @@ export function registerPaper(ctx, options) {
175
174
  return await runDefensePrep(ctx.fs, sessionCwd(exec), exec.signal);
176
175
  },
177
176
  }));
178
- ctx.commands.register(statusCommand(ctx.fs));
179
- ctx.commands.register(decideCommand(ctx.fs));
180
- ctx.commands.register(litCommand(ctx.fs));
181
- ctx.commands.register(checkCommand(ctx.fs));
182
- ctx.commands.register(buildCommand(ctx.fs));
183
177
  }
@@ -7,11 +7,11 @@ import * as nodePath from 'node:path';
7
7
  import { describeReadFailure, isMissingError } from "../../shared/fs-errors.js";
8
8
  import { appendDecision, countDecisions } from "../lib/ledger.js";
9
9
  import { DECISION_REL, findThesisRoot } from "../lib/project.js";
10
- const DECISION_HEADER = `# 决定日志
11
-
12
- > 每个关键决定的留痕:内容、理由、备选。答辩时它是"我为什么这么写"的证据。
13
- > 由 thesis_decide 工具或 /thesis-decide 命令追加。
14
-
10
+ const DECISION_HEADER = `# 决定日志
11
+
12
+ > 每个关键决定的留痕:内容、理由、备选。答辩时它是"我为什么这么写"的证据。
13
+ > 由 thesis_decide 工具或 /thesis decide 命令追加。
14
+
15
15
  `;
16
16
  function deriveTitle(content) {
17
17
  const firstLine = content.split('\n')[0].trim();
@@ -1,5 +1,5 @@
1
1
  /**
2
- * thesis_init:一键生成论文工作区(DESIGN.md §5 目录结构 + 技能包 + git 初始化)。
2
+ * thesis_init:一键生成论文工作区(docs/design.md §5 目录结构 + 技能包 + git 初始化)。
3
3
  *
4
4
  * 校验规则:
5
5
  * - root 必须是绝对路径;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * thesis_init:一键生成论文工作区(DESIGN.md §5 目录结构 + 技能包 + git 初始化)。
2
+ * thesis_init:一键生成论文工作区(docs/design.md §5 目录结构 + 技能包 + git 初始化)。
3
3
  *
4
4
  * 校验规则:
5
5
  * - root 必须是绝对路径;
@@ -12,10 +12,10 @@ import { searchLiterature, LIT_SOURCES, } from "../lib/lit-api.js";
12
12
  import { appendLitRecord, loadCache, mergeRecords, NOTES_DIR_REL, REFS_BIB_REL, saveCache, saveRow, searchRow, } from "../lib/lit-cache.js";
13
13
  import { bibKeyFor, buildBibtex, dedupeKey, parseBibDois, parseBibKeys } from "../lib/bibtex.js";
14
14
  import { findThesisRoot } from "../lib/project.js";
15
- const BIB_HEADER = `% 文献库(BibTeX)。
16
- % 红线:本文件只收录真实检索到的文献(由 thesis_lit_search/save 写入)。
17
- % 每条必须含 DOI 或 URL。引用格式遵循 GB/T 7714-2015(顺序编码制)。
18
-
15
+ const BIB_HEADER = `% 文献库(BibTeX)。
16
+ % 红线:本文件只收录真实检索到的文献(由 thesis_lit_search/save 写入)。
17
+ % 每条必须含 DOI 或 URL。引用格式遵循 GB/T 7714-2015(顺序编码制)。
18
+
19
19
  `;
20
20
  async function thesisRoot(fs, cwd, signal) {
21
21
  const root = await findThesisRoot(fs, cwd, signal);
@@ -129,34 +129,34 @@ function noteTemplate(record, bibKey) {
129
129
  meta.push(`URL:${record.url}`);
130
130
  if (record.citationCount !== undefined)
131
131
  meta.push(`被引 ${record.citationCount} 次`);
132
- return `# ${record.title}(${authorText},${record.year ?? '年份未知'},${record.venue || '出处未知'})
133
-
134
- > ${meta.join(';')}
135
- > 笔记模板见技能 thesis-literature;写论文时从这里取"可用引用句"。
136
-
137
- ## 这篇解决什么问题
138
-
139
- (待补)
140
-
141
- ## 方法/技术要点(3-5 条,用自己的话)
142
-
143
- (待补)
144
-
145
- ## 实验与结论(数据集/指标/结果)
146
-
147
- (待补)
148
-
149
- ## 与我课题的关系
150
-
151
- (待补:借鉴什么 / 对比什么 / 差异在哪)
152
-
153
- ## 可用引用句
154
-
155
- (待补:1-2 句,注明放哪一章)
156
-
157
- ## 摘要(原始)
158
-
159
- ${record.abstract ?? '(检索记录无摘要;请从原文自行摘录)'}
132
+ return `# ${record.title}(${authorText},${record.year ?? '年份未知'},${record.venue || '出处未知'})
133
+
134
+ > ${meta.join(';')}
135
+ > 笔记模板见技能 thesis-literature;写论文时从这里取"可用引用句"。
136
+
137
+ ## 这篇解决什么问题
138
+
139
+ (待补)
140
+
141
+ ## 方法/技术要点(3-5 条,用自己的话)
142
+
143
+ (待补)
144
+
145
+ ## 实验与结论(数据集/指标/结果)
146
+
147
+ (待补)
148
+
149
+ ## 与我课题的关系
150
+
151
+ (待补:借鉴什么 / 对比什么 / 差异在哪)
152
+
153
+ ## 可用引用句
154
+
155
+ (待补:1-2 句,注明放哪一章)
156
+
157
+ ## 摘要(原始)
158
+
159
+ ${record.abstract ?? '(检索记录无摘要;请从原文自行摘录)'}
160
160
  `;
161
161
  }
162
162
  /** 从 refs.bib 中按 key 提取最小记录(供 note 在缓存缺失时使用)。 */
@@ -24,11 +24,10 @@ export { checkDeck, renderCheckReport, verifyAnchors } from './check.ts';
24
24
  export type { CheckResult, SlideIssue } from './check.ts';
25
25
  export { runPptAction, runOutline, runCheckAction, runConvertAction, runGuideAction, planFromInputs, PPT_RELS } from './actions.ts';
26
26
  export type { PptArgs, PptDeps, PptActionResult, DeckCheck } from './actions.ts';
27
- export { handlePptCommand, parsePptCommandInput } from './commands.ts';
28
27
  /** `thesis_slides` 的工具描述(中文,面向模型与用户)。 */
29
28
  export declare const PPT_TOOL_DESCRIPTION: string;
30
29
  /**
31
- * 注册 `thesis_slides` 工具与 `/thesis-defense` 命令。
30
+ * 注册 `thesis_slides` 工具。
32
31
  *
33
32
  * 二进制例外(与 `thesis_build` 一致,文档化):pptx 由外部命令直接写在目标路径,
34
33
  * `ctx.fs` 无二进制写入能力,故落盘钩子用 node:fs({@link writeBinary});
package/lib/ppt/index.js CHANGED
@@ -18,14 +18,13 @@ export { renderMarp, parseMarp, parseFrontmatter, findUnsafeMarkdown, sanitizeTh
18
18
  export { detectEngines, convert, conversionGuide, renderConversionNotes, guideCommands } from "./convert.js";
19
19
  export { checkDeck, renderCheckReport, verifyAnchors } from "./check.js";
20
20
  export { runPptAction, runOutline, runCheckAction, runConvertAction, runGuideAction, planFromInputs, PPT_RELS } from "./actions.js";
21
- export { handlePptCommand, parsePptCommandInput } from "./commands.js";
22
21
  /** `thesis_slides` 的工具描述(中文,面向模型与用户)。 */
23
22
  export const PPT_TOOL_DESCRIPTION = '答辩幻灯(Markdown 为准,pptx 交给外部工具):outline 依据 07-答辩/答辩素材.md 生成 Marp 兼容的 07-答辩/PPT.md(10-12 页骨架、每页 3-6 条要点、讲稿注释、证据锚点;默认不覆盖已有文件,force 时先备份);' +
24
23
  'convert 探测 marp / npx marp-cli / pandoc 并执行转换产出 07-答辩/PPT.pptx(失败抛错并给出确切命令,绝不假装成功);' +
25
24
  'check 做确定性质量检查(页数/要点数/字数/讲稿/锚点/待补充标记/预计时长 8-12 分钟)并逐条定位;guide 只输出转换指引。' +
26
25
  '无论成败都写 07-答辩/PPT转换说明.md(探测结果 + 命令 + 退出码 + 输出摘要)。';
27
26
  /**
28
- * 注册 `thesis_slides` 工具与 `/thesis-defense` 命令。
27
+ * 注册 `thesis_slides` 工具。
29
28
  *
30
29
  * 二进制例外(与 `thesis_build` 一致,文档化):pptx 由外部命令直接写在目标路径,
31
30
  * `ctx.fs` 无二进制写入能力,故落盘钩子用 node:fs({@link writeBinary});
@@ -16,7 +16,7 @@
16
16
  * 并提供同样的"参数违规 → `INVALID_ARGS`"行为。
17
17
  *
18
18
  * 编译结果的一致性由两件事兜底:① `tests/shared-define-tool.test.ts` 逐例断言
19
- * 编译产物;② `scripts/host-smoke.mjs` 在真实 DSH 宿主上注册并执行工具(见 README「开发」)。
19
+ * 编译产物;② `scripts/host-smoke.ts` 在真实 DSH 宿主上注册并执行工具(见 README「开发」)。
20
20
  *
21
21
  * @module dsh-thesis/shared/define-tool
22
22
  */
@@ -16,7 +16,7 @@
16
16
  * 并提供同样的"参数违规 → `INVALID_ARGS`"行为。
17
17
  *
18
18
  * 编译结果的一致性由两件事兜底:① `tests/shared-define-tool.test.ts` 逐例断言
19
- * 编译产物;② `scripts/host-smoke.mjs` 在真实 DSH 宿主上注册并执行工具(见 README「开发」)。
19
+ * 编译产物;② `scripts/host-smoke.ts` 在真实 DSH 宿主上注册并执行工具(见 README「开发」)。
20
20
  *
21
21
  * @module dsh-thesis/shared/define-tool
22
22
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-thesis",
3
- "version": "1.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "论文与答辩全流程助手(DeepSeek Harness 插件):材料摄取 → 逐题追问 → 文献检索 → 逐章写作与评审 → 原创性自查与合规 → Word/答辩幻灯生产,全流程留痕,并跨会话记住学校规范与导师要求。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -15,19 +15,18 @@
15
15
  "skills",
16
16
  "cordis.patch.yml",
17
17
  "README.md",
18
- "DESIGN.md",
19
18
  "NOTICE.md",
20
- "docs/host-api.md"
19
+ "docs"
21
20
  ],
22
21
  "license": "MIT",
23
- "author": "Paloma966",
22
+ "author": "booondenz",
24
23
  "repository": {
25
24
  "type": "git",
26
- "url": "git+https://github.com/Paloma966/dsh-thesis.git"
25
+ "url": "git+https://github.com/booondenz/dsh-thesis.git"
27
26
  },
28
- "homepage": "https://github.com/Paloma966/dsh-thesis#readme",
27
+ "homepage": "https://github.com/booondenz/dsh-thesis#readme",
29
28
  "bugs": {
30
- "url": "https://github.com/Paloma966/dsh-thesis/issues"
29
+ "url": "https://github.com/booondenz/dsh-thesis/issues"
31
30
  },
32
31
  "keywords": [
33
32
  "dsh",
@@ -49,31 +48,37 @@
49
48
  }
50
49
  },
51
50
  "scripts": {
52
- "clean": "node scripts/clean.mjs",
51
+ "clean": "node scripts/clean.ts",
53
52
  "build": "npm run clean && tsc -p tsconfig.json",
54
53
  "typecheck": "tsc -p tsconfig.test.json",
54
+ "typecheck:scripts": "tsc -p tsconfig.scripts.json",
55
55
  "test": "node --test tests/",
56
- "test:sandbox": "node --test --test-isolation=none \"tests/**/*.test.ts\" \"tests/**/*.test.mjs\"",
57
- "test:e2e": "node tests/e2e/paper-full-flow.mjs",
58
- "test:bench": "node tests/e2e/paper-full-flow.mjs",
59
- "test:net": "node tests/e2e/paper-lit-real.mjs",
60
- "test:host": "node scripts/host-smoke.mjs && node .host-smoke/app/run.mjs",
61
- "test:host-load": "node scripts/host-verify.mjs",
62
- "audit": "node scripts/audit-surface.mjs",
63
- "verify": "npm run build && npm run typecheck && npm run test:sandbox && npm run audit && npm run test:e2e",
64
- "prepublishOnly": "node scripts/prepublish-guard.mjs"
56
+ "test:sandbox": "node --test --test-isolation=none \"tests/**/*.test.ts\"",
57
+ "test:e2e": "node tests/e2e/paper-full-flow.ts",
58
+ "test:bench": "node tests/e2e/paper-full-flow.ts",
59
+ "test:net": "node tests/e2e/paper-lit-real.ts",
60
+ "test:host": "node scripts/host-smoke.ts && node .host-smoke/app/run.ts",
61
+ "test:host-load": "node scripts/host-verify.ts",
62
+ "audit": "node scripts/audit-surface.ts",
63
+ "verify": "npm run build && npm run typecheck && npm run typecheck:scripts && npm run test:sandbox && npm run audit && npm run test:e2e",
64
+ "prepublishOnly": "node scripts/prepublish-guard.ts"
65
65
  },
66
66
  "engines": {
67
- "node": ">=22.16"
67
+ "node": ">=22.16",
68
+ "dsh": ">=0.2.0-rc.2 <0.3.0-0"
68
69
  },
69
70
  "peerDependencies": {
70
71
  "@deepseek-ai/schemastery": "^3.18.2",
71
72
  "@deepseek-ai/cordis": "^4.0.2",
72
- "@deepseek-ai/dsh-tools": "^0.1.0"
73
+ "@deepseek-ai/dsh-tools": ">=0.2.0-rc.2 <0.3.0-0"
73
74
  },
74
75
  "peerDependenciesMeta": {
75
- "@deepseek-ai/cordis": { "optional": true },
76
- "@deepseek-ai/dsh-tools": { "optional": true }
76
+ "@deepseek-ai/cordis": {
77
+ "optional": true
78
+ },
79
+ "@deepseek-ai/dsh-tools": {
80
+ "optional": true
81
+ }
77
82
  },
78
83
  "devDependencies": {
79
84
  "@deepseek-ai/schemastery": "^3.18.2",
@@ -40,7 +40,7 @@ defense_code_next # 2. 取当前里程碑:todo 列表 + 验证门 +
40
40
  ├─ defense_code_update action=ask_question # 3. 提一个追问
41
41
  ├─ 学生回答 → 你对照 expected 评分 → action=assess_answer passed=true/false
42
42
  ├─ 学生卡住 → action=give_hint(一次一条,不要一次给完)
43
- └─ /thesis-defense check <里程碑> # 4. 真跑验证门
43
+ └─ defense_code_update action=check_gate <里程碑> # 4. 真跑验证门
44
44
  ↓
45
45
  全部问题通过 + 验证门为绿 → 里程碑 verified
46
46
  ↓
@@ -50,9 +50,11 @@ defense_code_update action=advance_phase # 5. 直到 complete
50
50
  ## 第一次使用:建立演练
51
51
 
52
52
  ```
53
- /thesis-defense new <你的项目绝对路径> [--lang go] [--level beginner|intermediate|advanced] [--module 子模块]
53
+ defense_code_update action=new path=<你的项目绝对路径> lang=go level=beginner module=子模块
54
54
  ```
55
55
 
56
+ (本插件没有斜杠命令:所有动作都由你调 `defense_code_*` 工具完成。)
57
+
56
58
  然后由你(AI)分析项目并把结构登记成 todo 与里程碑:
57
59
 
58
60
  - `defense_code_update action=upsert_todo`:一个可动手的小任务(读数据模型、实现某个 CRUD、接一个接口)。
@@ -86,7 +88,7 @@ defense_code_update action=advance_phase # 5. 直到 complete
86
88
  |---|---|
87
89
  | 论文怎么组织、章节怎么验收 | `thesis-writing` / `thesis-pipeline` |
88
90
  | 答辩幻灯结构与问题库 | `thesis-defense` |
89
- | **把系统搞懂、被追问到能自证** | **本技能**(配 `defense_code_*` 三个工具与 `/thesis-defense` 命令) |
91
+ | **把系统搞懂、被追问到能自证** | **本技能**(配 `defense_code_*` 三个工具) |
90
92
 
91
93
  ## 完成的标准
92
94
 
@@ -74,7 +74,7 @@ thesis_slides convert → 探测 marp / npx marp-cli / pandoc;有则产
74
74
  thesis_slides guide → 只输出转换指引,不执行
75
75
  ```
76
76
 
77
- 等价斜杠命令:`/thesis-defense prepare [页数] [undergrad|master] [force]`、`convert`、`check`、`guide`。
77
+ 本插件没有斜杠命令:幻灯侧全部通过 `thesis_slides` 工具驱动(`action` 取 `outline` / `convert` / `check` / `guide`)。
78
78
 
79
79
  硬约束(`check` 会逐条查):每页要点 3-6 条、单条 ≤ 30 字、每页必须有讲稿与证据锚点、
80
80
  不得出现"待补充/TODO"、预计时长 8-12 分钟(每页 40-60 秒)。
@@ -77,7 +77,7 @@ description: 计算机类本科毕业设计全流程总纲。任何涉及论文
77
77
  - 答辩前要讲清自己的系统:加载 `code-walkthrough`
78
78
  - 写作要求被质疑、导师口径模糊:加载 `thesis-inquiry`
79
79
 
80
- ## 插件工具地图(dsh-thesis 全集:21 个工具 / 9 个命令)
80
+ ## 插件工具地图(dsh-thesis 全集:21 个工具 / 1 条命令 9 个动词)
81
81
 
82
82
  命名空间规则:`thesis_*` 操作论文工作区里的东西;`fact_*` 操作跨会话的稳定事实;
83
83
  `defense_code_*` 是答辩层的代码演练。
@@ -91,9 +91,9 @@ description: 计算机类本科毕业设计全流程总纲。任何涉及论文
91
91
  | 写作 | `thesis_review` / `thesis_check` / `thesis_build` | 逐章评审 → 全文一致性检查 → Word 构建 |
92
92
  | 合规 | `thesis_stylecheck` / `thesis_originality` | 写作风格自查(AI 味)/ 原创性本地度量与复测 |
93
93
  | 答辩 | `thesis_defense` / `thesis_slides` | 答辩素材与问题库 / 幻灯 Markdown 与 pptx 转换 |
94
- | 答辩 | `defense_code_status` / `defense_code_next` / `defense_code_update` | 代码演练:把系统拆成讲得清的模块(`/thesis-defense` 命令) |
94
+ | 答辩 | `defense_code_status` / `defense_code_next` / `defense_code_update` | 代码演练:把系统拆成讲得清的模块 |
95
95
  | 事实 | `fact_search` / `fact_remember` / `fact_context` | 跨会话事实(学校规范、导师要求、写作偏好) |
96
- | 命令 | `/thesis-status` `/thesis-decide` `/thesis-lit` `/thesis-check` `/thesis-build` `/thesis-ingest` `/thesis-intake` `/thesis-originality` `/thesis-defense` | 上述工具的斜杠入口 |
96
+ | 入口 | 无斜杠命令 | 本插件不提供命令行:在论文工作区开口说话,插件问一道选择题后自己推进;过 G1-G4 时由人拍板 |
97
97
 
98
98
  ## 会话入口顺序(新会话照这个走)
99
99
 
@@ -1,23 +0,0 @@
1
- /**
2
- * 人类可用的 `/thesis-defense` 命令:`new`、`status`、`check`。
3
- *
4
- * 只有在组合了命令适配器时才通过 `ctx.commands` 注册(交互式部署);纯 headless
5
- * 与仅 ACP 的组合没有命令注册表,直接跳过这一层表面。命令面的结果直接渲染,
6
- * 不进入模型历史。
7
- *
8
- * @module dsh-thesis/codewalk
9
- */
10
- import type { Context } from '@deepseek-ai/cordis';
11
- import { AiLearningEngine } from './engine.ts';
12
- import type { CommandInvocationShape, CommandResultShape } from './host-types.ts';
13
- /** 代码演练侧的子命令(与幻灯侧区分)。 */
14
- export declare const CODEWALK_SUBCOMMANDS: readonly string[];
15
- /** 命令的展示元信息(装配层注册 `/thesis-defense` 时使用)。 */
16
- export declare const CODEWALK_COMMAND_HINT = "new <\u539F\u59CB\u9879\u76EE\u8DEF\u5F84> [--lang go] [--level beginner] [--module pkg] | status | check [\u91CC\u7A0B\u7891]";
17
- /**
18
- * 代码演练侧的命令处理器(由装配层在 `/thesis-defense` 下调度)。
19
- *
20
- * `rawInput` 是命令名之后的全部输入;本函数只认代码演练侧的子命令
21
- * (`new` / `status` / `check`),其余一律交回装配层。
22
- */
23
- export declare function handleCodewalkCommand(ctx: Context, engine: AiLearningEngine, invocation: CommandInvocationShape): Promise<CommandResultShape>;
@@ -1,168 +0,0 @@
1
- /**
2
- * 人类可用的 `/thesis-defense` 命令:`new`、`status`、`check`。
3
- *
4
- * 只有在组合了命令适配器时才通过 `ctx.commands` 注册(交互式部署);纯 headless
5
- * 与仅 ACP 的组合没有命令注册表,直接跳过这一层表面。命令面的结果直接渲染,
6
- * 不进入模型历史。
7
- *
8
- * @module dsh-thesis/codewalk
9
- */
10
- import { AiLearningEngine } from "./engine.js";
11
- import { isLearningError } from "./errors.js";
12
- import { runMilestoneGate } from "./gate.js";
13
- const DEFAULT_LANGUAGE = 'go';
14
- const LEVELS = ['beginner', 'intermediate', 'advanced'];
15
- /** 会话没有工作目录时的统一答复。 */
16
- const NO_WORKSPACE = {
17
- kind: 'error',
18
- text: '本次会话没有工作目录,无法定位代码演练状态。请在论文工作区目录里打开会话。',
19
- };
20
- /** 代码演练侧的子命令(与幻灯侧区分)。 */
21
- export const CODEWALK_SUBCOMMANDS = ['new', 'status', 'check'];
22
- /** 命令的展示元信息(装配层注册 `/thesis-defense` 时使用)。 */
23
- export const CODEWALK_COMMAND_HINT = 'new <原始项目路径> [--lang go] [--level beginner] [--module pkg] | status | check [里程碑]';
24
- /**
25
- * 代码演练侧的命令处理器(由装配层在 `/thesis-defense` 下调度)。
26
- *
27
- * `rawInput` 是命令名之后的全部输入;本函数只认代码演练侧的子命令
28
- * (`new` / `status` / `check`),其余一律交回装配层。
29
- */
30
- export async function handleCodewalkCommand(ctx, engine, invocation) {
31
- try {
32
- const tokens = invocation.rawInput.trim().split(/\s+/);
33
- const sub = tokens[0] ?? '';
34
- const args = tokens.slice(1);
35
- if (sub === 'new')
36
- return await handleNew(engine, invocation, args);
37
- if (sub === 'status')
38
- return await handleStatus(engine, invocation);
39
- if (sub === 'check')
40
- return await handleCheck(ctx, engine, invocation, args);
41
- return { kind: 'error', text: `未知子命令 "${sub}";代码演练侧应为 new | status | check` };
42
- }
43
- catch (error) {
44
- if (isLearningError(error))
45
- return { kind: 'error', text: error.message };
46
- const message = error instanceof Error ? error.message : String(error);
47
- return { kind: 'error', text: `内部错误:${message}` };
48
- }
49
- }
50
- function parseNewArgs(args) {
51
- const options = { language: DEFAULT_LANGUAGE, level: 'beginner' };
52
- const positional = [];
53
- for (let index = 0; index < args.length; index += 1) {
54
- const arg = args[index];
55
- if (arg === '--lang' || arg === '--level' || arg === '--module') {
56
- const value = args[index + 1];
57
- if (value === undefined)
58
- continue;
59
- if (arg === '--lang')
60
- options.language = value;
61
- else if (arg === '--level')
62
- options.level = value;
63
- else
64
- options.module = value;
65
- index += 1;
66
- continue;
67
- }
68
- if (arg.startsWith('--lang='))
69
- options.language = arg.slice('--lang='.length);
70
- else if (arg.startsWith('--level='))
71
- options.level = arg.slice('--level='.length);
72
- else if (arg.startsWith('--module='))
73
- options.module = arg.slice('--module='.length);
74
- else
75
- positional.push(arg);
76
- }
77
- const first = positional[0];
78
- if (first !== undefined)
79
- options.path = first;
80
- return options;
81
- }
82
- async function handleNew(engine, invocation, args) {
83
- const options = parseNewArgs(args);
84
- if (options.path === undefined) {
85
- return {
86
- kind: 'error',
87
- text: '用法:/thesis-defense new <原始项目路径> [--lang go] [--level beginner] [--module pkg]',
88
- };
89
- }
90
- if (!LEVELS.includes(options.level)) {
91
- return { kind: 'error', text: `非法的 level "${options.level}";应为 ${LEVELS.join(' | ')}` };
92
- }
93
- const cwd = invocation.agent.session.header.cwd;
94
- if (cwd === undefined || cwd === '')
95
- return NO_WORKSPACE;
96
- const state = await engine.create(cwd, {
97
- origin: { path: options.path, language: options.language },
98
- scope: { level: options.level, ...(options.module !== undefined ? { module: options.module } : {}) },
99
- });
100
- return {
101
- kind: 'success',
102
- text: `已为 ${options.path} 创建代码演练(${options.language},${options.level})。\n` +
103
- `${engine.describe(state)}\n` +
104
- `下一步:让 AI 分析该项目,用 defense_code_update 工具登记 todo 与里程碑。`,
105
- };
106
- }
107
- async function handleStatus(engine, invocation) {
108
- const cwd = invocation.agent.session.header.cwd;
109
- if (cwd === undefined || cwd === '')
110
- return NO_WORKSPACE;
111
- const state = await engine.load(cwd);
112
- if (state === undefined) {
113
- return { kind: 'error', text: `${cwd} 下没有代码演练状态;请先执行 "/thesis-defense new <原始项目路径>"` };
114
- }
115
- return { kind: 'success', text: engine.describe(state) };
116
- }
117
- async function handleCheck(ctx, engine, invocation, args) {
118
- const cwd = invocation.agent.session.header.cwd;
119
- if (cwd === undefined || cwd === '')
120
- return NO_WORKSPACE;
121
- const state = await engine.load(cwd);
122
- if (state === undefined) {
123
- return { kind: 'error', text: `${cwd} 下没有代码演练状态;请先执行 "/thesis-defense new <原始项目路径>"` };
124
- }
125
- const milestone = pickMilestone(state.milestones, args[0]);
126
- if (milestone === undefined) {
127
- return {
128
- kind: 'error',
129
- text: args[0] === undefined
130
- ? '当前没有 in_progress 或 failed 的里程碑,没有可检查的对象'
131
- : `未知里程碑 "${args[0]}"`,
132
- };
133
- }
134
- if (milestone.status === 'failed')
135
- engine.retryMilestone(state, milestone.id);
136
- const settled = await runMilestoneGate(ctx, engine, cwd, state, milestone, invocation.signal, invocation.agent.session);
137
- if (settled.interrupted) {
138
- return { kind: 'error', text: `验证门 "${settled.command.join(' ')}" 被中断;该里程碑已标记为 failed` };
139
- }
140
- if (settled.outcome.kind === 'failed') {
141
- return {
142
- kind: 'error',
143
- text: `验证门 "${settled.command.join(' ')}" 失败,退出码 ${settled.exitCode};该里程碑已标记为 failed。\n` +
144
- (settled.stderr.trim() === '' ? `stdout 末尾:\n${settled.stdout}` : `stderr 末尾:\n${settled.stderr}`),
145
- };
146
- }
147
- if (settled.outcome.kind === 'pending-questions') {
148
- return {
149
- kind: 'success',
150
- text: `验证门 "${settled.command.join(' ')}" 通过,但仍有 ${milestone.questions.filter((question) => question.status !== 'passed').length} 个问题未通过。\n` +
151
- '让 AI 把追问做完;当验证门为绿且全部问题通过时,该里程碑才算 verified。',
152
- };
153
- }
154
- const next = state.milestones.find((entry) => entry.status === 'in_progress');
155
- const complete = state.phase === 'complete';
156
- return {
157
- kind: 'success',
158
- text: `验证门 "${settled.command.join(' ')}" 通过 —— 里程碑 "${milestone.id}" 已验证。\n` +
159
- (complete ? '全部里程碑已验证:本次代码演练完成。' : `下一个里程碑:${next?.title ?? '无'}。`),
160
- };
161
- }
162
- function pickMilestone(milestones, requestedId) {
163
- if (requestedId !== undefined) {
164
- return milestones.find((milestone) => milestone.id === requestedId);
165
- }
166
- return (milestones.find((milestone) => milestone.status === 'in_progress') ??
167
- milestones.find((milestone) => milestone.status === 'failed'));
168
- }
package/lib/commands.d.ts DELETED
@@ -1,33 +0,0 @@
1
- /**
2
- * 斜杠命令的聚合层。
3
- *
4
- * `/thesis-defense` 同时覆盖**答辩幻灯**与**代码演练**两块能力,因此它的注册
5
- * 放在装配层:`ppt/` 与 `codewalk/` 各自导出处理器,由本文件按子命令调度,
6
- * 两个模块之间没有反向依赖(见 DESIGN.md 的分层规则)。
7
- *
8
- * 命令只做薄封装:解析输入 → 交给对应模块的纯逻辑入口,因此命令行为与工具完全一致。
9
- *
10
- * @module dsh-thesis/commands
11
- */
12
- import type { CommandInvocation, CommandResult } from '@deepseek-ai/dsh-commands';
13
- import type { Context } from '@deepseek-ai/cordis';
14
- import type { PptOptions } from './config.ts';
15
- import type { PptDeps } from './ppt/actions.ts';
16
- /** 答辩命令两侧的子命令集合(仅用于错误提示)。 */
17
- export declare const DEFENSE_COMMAND_HINT = "prepare | convert | check | guide [\u9875\u6570] [undergrad|master] [force] | new <\u539F\u59CB\u9879\u76EE\u8DEF\u5F84> [--lang go] [--level beginner] [--module pkg] | status | check [\u91CC\u7A0B\u7891]";
18
- /**
19
- * 注册 `/thesis-defense`:答辩幻灯 + 代码演练。
20
- *
21
- * 幻灯侧子命令:`prepare`(= outline)/ `convert` / `check` / `guide`;
22
- * 代码演练侧子命令:`new` / `status` / `check`。`check` 两侧同名,按是否给出
23
- * 里程碑参数区分——幻灯侧的 check 不接受位置参数。
24
- *
25
- * headless/ACP 组合没有命令面时静默跳过。
26
- */
27
- export declare function registerDefenseCommand(ctx: Context, options: {
28
- ppt: PptOptions;
29
- }, deps?: PptDeps): void;
30
- /** 按子命令把一次 `/thesis-defense` 调用分派到幻灯侧或代码演练侧。 */
31
- export declare function dispatchDefenseCommand(ctx: Context, options: {
32
- ppt: PptOptions;
33
- }, invocation: CommandInvocation, deps?: PptDeps): Promise<CommandResult>;