dsh-thesis 1.0.1 → 2.0.2
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 +1 -1
- package/NOTICE.md +1 -1
- package/README.md +51 -86
- package/docs/autopilot.md +73 -0
- package/docs/config.md +113 -0
- package/{DESIGN.md → docs/design.md} +69 -74
- package/docs/host-api.md +49 -6
- package/docs/release.md +138 -0
- package/docs/tools.md +76 -0
- package/docs/troubleshooting.md +88 -0
- package/docs/usage.md +87 -0
- package/lib/autopilot/index.d.ts +38 -0
- package/lib/autopilot/index.js +159 -0
- package/lib/autopilot/intent.d.ts +40 -0
- package/lib/autopilot/intent.js +82 -0
- package/lib/autopilot/messages.d.ts +23 -0
- package/lib/autopilot/messages.js +36 -0
- package/lib/autopilot/types.d.ts +60 -0
- package/lib/autopilot/types.js +10 -0
- package/lib/codewalk/engine.d.ts +1 -1
- package/lib/codewalk/engine.js +1 -1
- package/lib/codewalk/gate.d.ts +1 -1
- package/lib/codewalk/gate.js +1 -1
- package/lib/codewalk/host-types.d.ts +2 -31
- package/lib/codewalk/prestep.js +3 -3
- package/lib/codewalk/tools.js +2 -2
- package/lib/config.d.ts +17 -0
- package/lib/config.js +9 -1
- package/lib/dedup/index.js +0 -6
- package/lib/gates/messages.d.ts +7 -6
- package/lib/gates/messages.js +8 -5
- package/lib/index.d.ts +3 -1
- package/lib/index.js +10 -7
- package/lib/ingest/index.d.ts +1 -1
- package/lib/ingest/index.js +1 -3
- package/lib/intake/gate-rules.d.ts +1 -2
- package/lib/intake/gate-rules.js +2 -2
- package/lib/intake/index.d.ts +0 -17
- package/lib/intake/index.js +0 -51
- package/lib/intake/questions.d.ts +1 -1
- package/lib/intake/questions.js +1 -1
- package/lib/memory/recall.d.ts +1 -2
- package/lib/memory/recall.js +2 -2
- package/lib/paper/lib/layout.d.ts +1 -1
- package/lib/paper/lib/layout.js +2 -2
- package/lib/paper/lib/ledger.d.ts +1 -1
- package/lib/paper/lib/ledger.js +1 -1
- package/lib/paper/register.d.ts +2 -2
- package/lib/paper/register.js +2 -8
- package/lib/paper/tools/decision.js +1 -1
- package/lib/paper/tools/init.d.ts +1 -1
- package/lib/paper/tools/init.js +1 -1
- package/lib/ppt/index.d.ts +1 -2
- package/lib/ppt/index.js +1 -2
- package/lib/shared/define-tool.d.ts +1 -1
- package/lib/shared/define-tool.js +1 -1
- package/lib/shared/message-source.d.ts +21 -0
- package/lib/shared/message-source.js +19 -0
- package/package.json +17 -17
- package/skills/code-walkthrough/SKILL.md +5 -3
- package/skills/thesis-defense/SKILL.md +1 -1
- package/skills/thesis-pipeline/SKILL.md +3 -3
- package/lib/codewalk/commands.d.ts +0 -23
- package/lib/codewalk/commands.js +0 -168
- package/lib/commands.d.ts +0 -33
- package/lib/commands.js +0 -60
- package/lib/dedup/commands.d.ts +0 -21
- package/lib/dedup/commands.js +0 -93
- package/lib/ingest/commands.d.ts +0 -23
- package/lib/ingest/commands.js +0 -74
- package/lib/paper/commands.d.ts +0 -13
- package/lib/paper/commands.js +0 -84
- package/lib/ppt/commands.d.ts +0 -28
- package/lib/ppt/commands.js +0 -71
package/lib/gates/messages.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 闸门注入消息与决策理由的模板。
|
|
3
3
|
*
|
|
4
|
-
* 注入消息的 source 采用 `{ kind: 'plugin
|
|
5
|
-
* - `
|
|
4
|
+
* 注入消息的 source 采用 `{ kind: 'plugin:dsh-thesis', form: 'instructions' }`:
|
|
5
|
+
* - `kind` 是生产者自有标识。v4 会话格式禁止共享兜底 kind `plugin`,否则写会话日志
|
|
6
|
+
* 时直接抛 `format v4 message requires a producer-owned source kind`(见
|
|
7
|
+
* `shared/message-source.ts`);
|
|
6
8
|
* - `form` 声明这条上下文的语义形态(当前契约的取值域:instructions / catalog /
|
|
7
9
|
* snapshot / notice / relay / recall);
|
|
8
10
|
* - **不带 `sections`**:`sections` 只属于 `snapshot` 形态(见
|
|
@@ -16,12 +18,11 @@
|
|
|
16
18
|
* @module dsh-thesis/gates/messages
|
|
17
19
|
*/
|
|
18
20
|
import type { UserMessage } from '@deepseek-ai/dsh-llm';
|
|
19
|
-
/** 插件标识:注入消息 source
|
|
20
|
-
export
|
|
21
|
+
/** 插件标识:注入消息 source 的命名来源。 */
|
|
22
|
+
export { PLUGIN_ID } from '../shared/message-source.ts';
|
|
21
23
|
/** 注入消息的 source 基础形状(form 由调用方补充)。 */
|
|
22
24
|
export declare const PLUGIN_SOURCE: {
|
|
23
|
-
readonly kind: "plugin";
|
|
24
|
-
readonly plugin: "dsh-thesis";
|
|
25
|
+
readonly kind: "plugin:dsh-thesis";
|
|
25
26
|
};
|
|
26
27
|
/**
|
|
27
28
|
* 写作意图闸门注入给模型的指令。
|
package/lib/gates/messages.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 闸门注入消息与决策理由的模板。
|
|
3
3
|
*
|
|
4
|
-
* 注入消息的 source 采用 `{ kind: 'plugin
|
|
5
|
-
* - `
|
|
4
|
+
* 注入消息的 source 采用 `{ kind: 'plugin:dsh-thesis', form: 'instructions' }`:
|
|
5
|
+
* - `kind` 是生产者自有标识。v4 会话格式禁止共享兜底 kind `plugin`,否则写会话日志
|
|
6
|
+
* 时直接抛 `format v4 message requires a producer-owned source kind`(见
|
|
7
|
+
* `shared/message-source.ts`);
|
|
6
8
|
* - `form` 声明这条上下文的语义形态(当前契约的取值域:instructions / catalog /
|
|
7
9
|
* snapshot / notice / relay / recall);
|
|
8
10
|
* - **不带 `sections`**:`sections` 只属于 `snapshot` 形态(见
|
|
@@ -16,10 +18,11 @@
|
|
|
16
18
|
* @module dsh-thesis/gates/messages
|
|
17
19
|
*/
|
|
18
20
|
import { randomUUID } from 'node:crypto';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
import { THESIS_SOURCE } from "../shared/message-source.js";
|
|
22
|
+
/** 插件标识:注入消息 source 的命名来源。 */
|
|
23
|
+
export { PLUGIN_ID } from "../shared/message-source.js";
|
|
21
24
|
/** 注入消息的 source 基础形状(form 由调用方补充)。 */
|
|
22
|
-
export const PLUGIN_SOURCE =
|
|
25
|
+
export const PLUGIN_SOURCE = THESIS_SOURCE;
|
|
23
26
|
/**
|
|
24
27
|
* 写作意图闸门注入给模型的指令。
|
|
25
28
|
*
|
package/lib/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* dsh-thesis:论文与答辩全流程助手(DeepSeek Harness 单一插件)。
|
|
3
3
|
*
|
|
4
4
|
* 本文件是**唯一装配层**:把各能力挂到同一个插件 fiber 上,对外只有一行
|
|
5
|
-
* `dsh plugin add dsh-thesis`、一个 Config
|
|
5
|
+
* `dsh plugin add dsh-thesis`、一个 Config、一套技能。**没有斜杠命令**:
|
|
6
|
+
* 插件在论文工作区里自己把流程推起来(开头一道选择题 + 关卡拍板)。
|
|
6
7
|
*
|
|
7
8
|
* | 目录 | 职责 |
|
|
8
9
|
* |---|---|
|
|
@@ -14,6 +15,7 @@
|
|
|
14
15
|
* | `memory/` | 跨会话事实:学校规范、导师要求、写作偏好(学生不必直接调用) |
|
|
15
16
|
* | `codewalk/` | 代码演练:把 AI 写的系统拆成答辩讲得清的模块 |
|
|
16
17
|
* | `gates/` | 闸门:写作意图闸门 + 不可逆操作闸门 + 意图规格闸门 |
|
|
18
|
+
* | `autopilot/` | 自动驾驶:开头一道选择题 + 建目标自动续轮 + 关卡拍板(无斜杠命令) |
|
|
17
19
|
* | `shared/` | 工具胶水、工具定义器、文本与文件系统错误工具 |
|
|
18
20
|
*
|
|
19
21
|
* **一个领域模型**:材料 → 要求 → 九阶段 → 论文与答辩。学生的工具清单里
|
package/lib/index.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* dsh-thesis:论文与答辩全流程助手(DeepSeek Harness 单一插件)。
|
|
3
3
|
*
|
|
4
4
|
* 本文件是**唯一装配层**:把各能力挂到同一个插件 fiber 上,对外只有一行
|
|
5
|
-
* `dsh plugin add dsh-thesis`、一个 Config
|
|
5
|
+
* `dsh plugin add dsh-thesis`、一个 Config、一套技能。**没有斜杠命令**:
|
|
6
|
+
* 插件在论文工作区里自己把流程推起来(开头一道选择题 + 关卡拍板)。
|
|
6
7
|
*
|
|
7
8
|
* | 目录 | 职责 |
|
|
8
9
|
* |---|---|
|
|
@@ -14,6 +15,7 @@
|
|
|
14
15
|
* | `memory/` | 跨会话事实:学校规范、导师要求、写作偏好(学生不必直接调用) |
|
|
15
16
|
* | `codewalk/` | 代码演练:把 AI 写的系统拆成答辩讲得清的模块 |
|
|
16
17
|
* | `gates/` | 闸门:写作意图闸门 + 不可逆操作闸门 + 意图规格闸门 |
|
|
18
|
+
* | `autopilot/` | 自动驾驶:开头一道选择题 + 建目标自动续轮 + 关卡拍板(无斜杠命令) |
|
|
17
19
|
* | `shared/` | 工具胶水、工具定义器、文本与文件系统错误工具 |
|
|
18
20
|
*
|
|
19
21
|
* **一个领域模型**:材料 → 要求 → 九阶段 → 论文与答辩。学生的工具清单里
|
|
@@ -22,8 +24,8 @@
|
|
|
22
24
|
* @module dsh-thesis
|
|
23
25
|
*/
|
|
24
26
|
import { fileURLToPath } from 'node:url';
|
|
27
|
+
import { installAutopilot } from "./autopilot/index.js";
|
|
25
28
|
import { registerCodewalk } from "./codewalk/register.js";
|
|
26
|
-
import { registerDefenseCommand } from "./commands.js";
|
|
27
29
|
import { Config, resolveConfig } from "./config.js";
|
|
28
30
|
import { registerDedup } from "./dedup/index.js";
|
|
29
31
|
import { installDangerousGate } from "./gates/dangerous.js";
|
|
@@ -36,7 +38,7 @@ import { setWorkspaceRoot } from "./paper/lib/project.js";
|
|
|
36
38
|
import { registerPaper } from "./paper/register.js";
|
|
37
39
|
import { registerPpt } from "./ppt/index.js";
|
|
38
40
|
export const name = 'dsh-thesis';
|
|
39
|
-
export const inject = ['tools', 'fs'
|
|
41
|
+
export const inject = ['tools', 'fs'];
|
|
40
42
|
export { Config };
|
|
41
43
|
export { PAPER_DEFAULTS, resolveConfig } from "./config.js";
|
|
42
44
|
/** 随包发布的技能目录(`thesis_init` 复制到论文仓库 `.dsh/skills/`)。 */
|
|
@@ -55,20 +57,21 @@ export function apply(ctx, config = {}) {
|
|
|
55
57
|
registerFacts(ctx, resolved.memoryPath);
|
|
56
58
|
// 事实回灌:相关时自动把已确认的稳定事实放回上下文(不相关则完全静默)。
|
|
57
59
|
installFactRecall(ctx, resolved.recall);
|
|
58
|
-
// 论文工作区:11
|
|
60
|
+
// 论文工作区:11 个工具。
|
|
59
61
|
registerPaper(ctx, { skillsDir: SKILLS_DIR });
|
|
60
62
|
// 代码演练(答辩层):3 个工具 + 进度卡注入 + code-walkthrough 技能。
|
|
61
63
|
registerCodewalk(ctx, resolved.codeWalkthrough);
|
|
62
64
|
// 材料入口:Office 摄取 → 文本与材料清单。
|
|
63
65
|
registerIngest(ctx, { ingest: resolved.ingest });
|
|
64
|
-
//
|
|
66
|
+
// 意图规格:逐题追问状态机。
|
|
65
67
|
registerIntake(ctx, { intake: resolved.intake });
|
|
66
68
|
// 原创性自查:本地度量 + 改写处方 + 复测。
|
|
67
69
|
registerDedup(ctx, { similarity: resolved.similarity });
|
|
68
70
|
// 答辩:Markdown 幻灯 + 外部转换器探测。
|
|
69
71
|
registerPpt(ctx, { ppt: resolved.ppt });
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
+
// 自动驾驶:论文工作区里开口就问一次意图 → 建目标自动续轮;关卡由人拍板。
|
|
73
|
+
// 不提供任何斜杠命令:人只在「开头选一次」与「过关卡」两处出现。
|
|
74
|
+
installAutopilot(ctx, { ...resolved.autopilot, specRel: resolved.intake.specRel });
|
|
72
75
|
// 闸门:写作意图闸门 + 不可逆操作闸门 + 意图规格闸门。
|
|
73
76
|
installWritingGate(ctx, resolved.gates);
|
|
74
77
|
installDangerousGate(ctx, resolved.gates);
|
package/lib/ingest/index.d.ts
CHANGED
|
@@ -175,5 +175,5 @@ export interface RegisterIngestOptions {
|
|
|
175
175
|
/** 摄取配置(`maxBytes`/`maxChars`,来自 `src/config.ts`)。 */
|
|
176
176
|
readonly ingest: IngestOptions;
|
|
177
177
|
}
|
|
178
|
-
/** 注册 `thesis_ingest`(同步注册,走仓库统一的 `definePaperTool
|
|
178
|
+
/** 注册 `thesis_ingest`(同步注册,走仓库统一的 `definePaperTool`;本插件不提供斜杠命令)。 */
|
|
179
179
|
export declare function registerIngest(ctx: Context, options: RegisterIngestOptions): void;
|
package/lib/ingest/index.js
CHANGED
|
@@ -14,7 +14,6 @@ import { readdir, readFile, stat } from 'node:fs/promises';
|
|
|
14
14
|
import * as nodePath from 'node:path';
|
|
15
15
|
import { findThesisRoot } from "../paper/lib/project.js";
|
|
16
16
|
import { bulletList, definePaperTool, sessionCwd, textOutput } from "../shared/index.js";
|
|
17
|
-
import { ingestCommand } from "./commands.js";
|
|
18
17
|
import { codeLanguageOf, detectTechStack, isManifestFile, renderProjectSummary, summarizeSource, } from "./code.js";
|
|
19
18
|
import { extractDocx } from "./docx.js";
|
|
20
19
|
import { extractPdf } from "./pdf.js";
|
|
@@ -615,7 +614,7 @@ export function renderOutcome(outcome, maxChars) {
|
|
|
615
614
|
return text;
|
|
616
615
|
return `${text.slice(0, Math.max(0, maxChars - 20))}\n…(清单过长已截断)`;
|
|
617
616
|
}
|
|
618
|
-
/** 注册 `thesis_ingest`(同步注册,走仓库统一的 `definePaperTool
|
|
617
|
+
/** 注册 `thesis_ingest`(同步注册,走仓库统一的 `definePaperTool`;本插件不提供斜杠命令)。 */
|
|
619
618
|
export function registerIngest(ctx, options) {
|
|
620
619
|
ctx.tools.register(definePaperTool({
|
|
621
620
|
name: 'thesis_ingest',
|
|
@@ -636,5 +635,4 @@ export function registerIngest(ctx, options) {
|
|
|
636
635
|
return renderOutcome(outcome, options.ingest.maxChars);
|
|
637
636
|
},
|
|
638
637
|
}));
|
|
639
|
-
ctx.commands.register(ingestCommand(ctx.fs, options.ingest));
|
|
640
638
|
}
|
package/lib/intake/gate-rules.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @module dsh-thesis/intake/gate-rules
|
|
12
12
|
*/
|
|
13
|
+
import { THESIS_SOURCE } from "../shared/message-source.js";
|
|
13
14
|
/** 「要开始写正文/开题报告」的意图模式(中英文)。 */
|
|
14
15
|
const WRITING_INTENT_PATTERNS = [
|
|
15
16
|
// 中文:写/生成/起草 + 论文/正文/章节/开题/中期
|
|
@@ -114,8 +115,7 @@ export function makeIntakeGateMessage(status, specRel, id) {
|
|
|
114
115
|
role: 'user',
|
|
115
116
|
content: [{ type: 'text', text }],
|
|
116
117
|
source: {
|
|
117
|
-
|
|
118
|
-
plugin: 'dsh-thesis',
|
|
118
|
+
...THESIS_SOURCE,
|
|
119
119
|
form: 'instructions',
|
|
120
120
|
},
|
|
121
121
|
};
|
package/lib/intake/index.d.ts
CHANGED
|
@@ -57,20 +57,3 @@ export interface IntakeExecLike {
|
|
|
57
57
|
};
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
/** 命令返回值(宿主 `CommandResult` 的形状)。 */
|
|
61
|
-
export interface IntakeCommandResult {
|
|
62
|
-
readonly kind: 'success' | 'error';
|
|
63
|
-
readonly text?: string;
|
|
64
|
-
}
|
|
65
|
-
/** 把 `/thesis-intake` 的一行输入翻译成追问动作。 */
|
|
66
|
-
export declare function parseCommandInput(raw: string): IntakeArgs;
|
|
67
|
-
/**
|
|
68
|
-
* 注册命令 `/thesis-intake`(命令名只允许 `[a-z][a-z0-9_-]*`)。
|
|
69
|
-
*
|
|
70
|
-
* 用法:`/thesis-intake` 取下一个问题;`/thesis-intake status|spec|done|start`;
|
|
71
|
-
* `/thesis-intake answer school.name XX大学`;`/thesis-intake skip ref.samples 暂时没有`。
|
|
72
|
-
* `ctx.commands` 不可用(未装配命令服务的宿主)时静默跳过,不影响工具能力。
|
|
73
|
-
*/
|
|
74
|
-
export declare function registerIntakeCommand(ctx: Context, options: {
|
|
75
|
-
intake: IntakeSubOptions;
|
|
76
|
-
}): boolean;
|
package/lib/intake/index.js
CHANGED
|
@@ -414,55 +414,4 @@ export function registerIntake(ctx, options) {
|
|
|
414
414
|
return await definition.execute(rawArgs, exec);
|
|
415
415
|
},
|
|
416
416
|
}));
|
|
417
|
-
registerIntakeCommand(ctx, options);
|
|
418
|
-
}
|
|
419
|
-
/** 把 `/thesis-intake` 的一行输入翻译成追问动作。 */
|
|
420
|
-
export function parseCommandInput(raw) {
|
|
421
|
-
const text = raw.trim();
|
|
422
|
-
if (text === '')
|
|
423
|
-
return { action: 'ask' };
|
|
424
|
-
const [head, ...rest] = text.split(/\s+/);
|
|
425
|
-
switch (head) {
|
|
426
|
-
case 'start':
|
|
427
|
-
case 'ask':
|
|
428
|
-
case 'status':
|
|
429
|
-
case 'spec':
|
|
430
|
-
case 'done':
|
|
431
|
-
return { action: head };
|
|
432
|
-
case 'answer': {
|
|
433
|
-
const [id, ...words] = rest;
|
|
434
|
-
return { action: 'answer', question_id: id ?? '', answer: words.join(' ') };
|
|
435
|
-
}
|
|
436
|
-
case 'skip': {
|
|
437
|
-
const [id, ...words] = rest;
|
|
438
|
-
return { action: 'skip', question_id: id ?? '', reason: words.join(' ') };
|
|
439
|
-
}
|
|
440
|
-
default:
|
|
441
|
-
// 不认识的第一个词:当作问题 id 的简写,等价于 answer(模型/人最常这么用)。
|
|
442
|
-
return { action: 'answer', question_id: head ?? '', answer: rest.join(' ') };
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
/**
|
|
446
|
-
* 注册命令 `/thesis-intake`(命令名只允许 `[a-z][a-z0-9_-]*`)。
|
|
447
|
-
*
|
|
448
|
-
* 用法:`/thesis-intake` 取下一个问题;`/thesis-intake status|spec|done|start`;
|
|
449
|
-
* `/thesis-intake answer school.name XX大学`;`/thesis-intake skip ref.samples 暂时没有`。
|
|
450
|
-
* `ctx.commands` 不可用(未装配命令服务的宿主)时静默跳过,不影响工具能力。
|
|
451
|
-
*/
|
|
452
|
-
export function registerIntakeCommand(ctx, options) {
|
|
453
|
-
const commands = ctx.commands;
|
|
454
|
-
if (commands === undefined || typeof commands.register !== 'function')
|
|
455
|
-
return false;
|
|
456
|
-
commands.register({
|
|
457
|
-
name: 'thesis-intake',
|
|
458
|
-
description: '逐题追问:材料到手后把模糊要求变成意图规格(一次一个问题)',
|
|
459
|
-
input: { hint: 'answer <问题id> <答案>|skip <问题id> <理由>|status|spec|done(缺省取下一个问题)' },
|
|
460
|
-
async handler(invocation) {
|
|
461
|
-
const args = parseCommandInput(invocation.rawInput ?? '');
|
|
462
|
-
const text = await runIntake(ctx.fs, options.intake, args, sessionCwd(invocation), invocation.signal);
|
|
463
|
-
// 工具层已经把失败写成可读中文,这里统一按 success 返回(命令不做二次包装)。
|
|
464
|
-
return { kind: 'success', text };
|
|
465
|
-
},
|
|
466
|
-
});
|
|
467
|
-
return true;
|
|
468
417
|
}
|
|
@@ -23,7 +23,7 @@ import type { IntakeState } from './state.ts';
|
|
|
23
23
|
* 没有工具兑现的产出物,测试立刻变红——这样「问了一堆用不上的要求」无法退化。
|
|
24
24
|
*/
|
|
25
25
|
export type IntakeAffect = '格式检查' | '引用规范' | '字数分配' | '写作规范' | '原创性' | '答案PPT' | '答辩问答' | '文献检索';
|
|
26
|
-
/** 每个产出物由哪些工具兑现(工具名是契约,见
|
|
26
|
+
/** 每个产出物由哪些工具兑现(工具名是契约,见 docs/design.md §5)。 */
|
|
27
27
|
export declare const AFFECT_TOOLS: Readonly<Record<IntakeAffect, readonly string[]>>;
|
|
28
28
|
/** 轻校验结果:`ok:false` + `note` 表示「记录但标注问题」,不阻断对话。 */
|
|
29
29
|
export interface AnswerCheck {
|
package/lib/intake/questions.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @module dsh-thesis/intake
|
|
16
16
|
*/
|
|
17
|
-
/** 每个产出物由哪些工具兑现(工具名是契约,见
|
|
17
|
+
/** 每个产出物由哪些工具兑现(工具名是契约,见 docs/design.md §5)。 */
|
|
18
18
|
export const AFFECT_TOOLS = {
|
|
19
19
|
格式检查: ['thesis_check'],
|
|
20
20
|
引用规范: ['thesis_lit_search', 'thesis_lit_save', 'thesis_lit_note', 'thesis_check'],
|
package/lib/memory/recall.d.ts
CHANGED
package/lib/memory/recall.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { randomUUID } from 'node:crypto';
|
|
19
19
|
import { textOfBlocks } from "../shared/text.js";
|
|
20
|
+
import { THESIS_SOURCE } from "../shared/message-source.js";
|
|
20
21
|
/** 出厂默认值(与 `PAPER_DEFAULTS.recall` 保持一致,单一来源见 `src/config.ts`)。 */
|
|
21
22
|
export const RECALL_DEFAULTS = { maxEntries: 4, maxChars: 600, minKeywordLength: 2 };
|
|
22
23
|
/** 停用词(中英混合,只去最吵的一批;不求语言学完备)。 */
|
|
@@ -111,8 +112,7 @@ export function makeRecallMessage(entries, maxChars) {
|
|
|
111
112
|
role: 'user',
|
|
112
113
|
content: [{ type: 'text', text }],
|
|
113
114
|
source: {
|
|
114
|
-
|
|
115
|
-
plugin: 'dsh-thesis',
|
|
115
|
+
...THESIS_SOURCE,
|
|
116
116
|
form: 'snapshot',
|
|
117
117
|
sections: [{ name: '已确认事实', text }],
|
|
118
118
|
},
|
package/lib/paper/lib/layout.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 论文工作区布局与全部模板文件内容(
|
|
2
|
+
* 论文工作区布局与全部模板文件内容(docs/design.md §5 的落地)。
|
|
3
3
|
*
|
|
4
4
|
* thesis_init 按此生成目录树;模板内容与技能包(plugin/skills/)保持一致。
|
|
5
5
|
* 本模块只依赖 Node 内置能力。
|
|
@@ -186,7 +186,7 @@ ${HEADER_NOTE}
|
|
|
186
186
|
${HEADER_NOTE}
|
|
187
187
|
|
|
188
188
|
> 每个关键决定的留痕:内容、理由、备选。答辩时它是"我为什么这么写"的证据。
|
|
189
|
-
> 由 \`thesis_decide\` 工具或 /thesis
|
|
189
|
+
> 由 \`thesis_decide\` 工具或 /thesis decide 命令追加。
|
|
190
190
|
|
|
191
191
|
(暂无决定)
|
|
192
192
|
`,
|
package/lib/paper/lib/ledger.js
CHANGED
package/lib/paper/register.d.ts
CHANGED
package/lib/paper/register.js
CHANGED
|
@@ -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
|
}
|
|
@@ -10,7 +10,7 @@ import { DECISION_REL, findThesisRoot } from "../lib/project.js";
|
|
|
10
10
|
const DECISION_HEADER = `# 决定日志
|
|
11
11
|
|
|
12
12
|
> 每个关键决定的留痕:内容、理由、备选。答辩时它是"我为什么这么写"的证据。
|
|
13
|
-
> 由 thesis_decide 工具或 /thesis
|
|
13
|
+
> 由 thesis_decide 工具或 /thesis decide 命令追加。
|
|
14
14
|
|
|
15
15
|
`;
|
|
16
16
|
function deriveTitle(content) {
|
package/lib/paper/tools/init.js
CHANGED
package/lib/ppt/index.d.ts
CHANGED
|
@@ -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`
|
|
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`
|
|
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.
|
|
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.
|
|
19
|
+
* 编译产物;② `scripts/host-smoke.ts` 在真实 DSH 宿主上注册并执行工具(见 README「开发」)。
|
|
20
20
|
*
|
|
21
21
|
* @module dsh-thesis/shared/define-tool
|
|
22
22
|
*/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 注入消息的 source 约定。
|
|
3
|
+
*
|
|
4
|
+
* 宿主从 v4 会话格式起要求消息 source 是**生产者自有的 kind**:共享兜底值
|
|
5
|
+
* `plugin` 会被直接拒写,错误是 `format v4 message requires a producer-owned
|
|
6
|
+
* source kind`,而且发生在写会话日志时——整条会话都起不来。2.0.1 发布后真踩过。
|
|
7
|
+
*
|
|
8
|
+
* 第三方插件的规范形态是 `plugin:<包名>`:宿主的 v3→v4 迁移器给未知生产者生成的
|
|
9
|
+
* 就是这个值(`@deepseek-ai/dsh-session-format-v3-to-v4` 里的 `producerKind`),
|
|
10
|
+
* 因此旧会话迁移后与新消息同源同 kind,前端不会把同一类上下文认成两种东西。
|
|
11
|
+
*
|
|
12
|
+
* @module dsh-thesis/shared/message-source
|
|
13
|
+
*/
|
|
14
|
+
/** 插件标识(与 package.json 的 name 一致)。 */
|
|
15
|
+
export declare const PLUGIN_ID = "dsh-thesis";
|
|
16
|
+
/** 生产者自有 kind。**不要改回 `plugin`**,否则 v4 会话写不进去。 */
|
|
17
|
+
export declare const THESIS_SOURCE_KIND = "plugin:dsh-thesis";
|
|
18
|
+
/** 注入消息 source 的基础形状(`form`/`sections` 由调用方补充)。 */
|
|
19
|
+
export declare const THESIS_SOURCE: {
|
|
20
|
+
readonly kind: "plugin:dsh-thesis";
|
|
21
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 注入消息的 source 约定。
|
|
3
|
+
*
|
|
4
|
+
* 宿主从 v4 会话格式起要求消息 source 是**生产者自有的 kind**:共享兜底值
|
|
5
|
+
* `plugin` 会被直接拒写,错误是 `format v4 message requires a producer-owned
|
|
6
|
+
* source kind`,而且发生在写会话日志时——整条会话都起不来。2.0.1 发布后真踩过。
|
|
7
|
+
*
|
|
8
|
+
* 第三方插件的规范形态是 `plugin:<包名>`:宿主的 v3→v4 迁移器给未知生产者生成的
|
|
9
|
+
* 就是这个值(`@deepseek-ai/dsh-session-format-v3-to-v4` 里的 `producerKind`),
|
|
10
|
+
* 因此旧会话迁移后与新消息同源同 kind,前端不会把同一类上下文认成两种东西。
|
|
11
|
+
*
|
|
12
|
+
* @module dsh-thesis/shared/message-source
|
|
13
|
+
*/
|
|
14
|
+
/** 插件标识(与 package.json 的 name 一致)。 */
|
|
15
|
+
export const PLUGIN_ID = 'dsh-thesis';
|
|
16
|
+
/** 生产者自有 kind。**不要改回 `plugin`**,否则 v4 会话写不进去。 */
|
|
17
|
+
export const THESIS_SOURCE_KIND = `plugin:${PLUGIN_ID}`;
|
|
18
|
+
/** 注入消息 source 的基础形状(`form`/`sections` 由调用方补充)。 */
|
|
19
|
+
export const THESIS_SOURCE = { kind: THESIS_SOURCE_KIND };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-thesis",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
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
|
|
19
|
+
"docs"
|
|
21
20
|
],
|
|
22
21
|
"license": "MIT",
|
|
23
|
-
"author": "
|
|
22
|
+
"author": "booondenz",
|
|
24
23
|
"repository": {
|
|
25
24
|
"type": "git",
|
|
26
|
-
"url": "git+https://github.com/
|
|
25
|
+
"url": "git+https://github.com/booondenz/dsh-thesis.git"
|
|
27
26
|
},
|
|
28
|
-
"homepage": "https://github.com/
|
|
27
|
+
"homepage": "https://github.com/booondenz/dsh-thesis#readme",
|
|
29
28
|
"bugs": {
|
|
30
|
-
"url": "https://github.com/
|
|
29
|
+
"url": "https://github.com/booondenz/dsh-thesis/issues"
|
|
31
30
|
},
|
|
32
31
|
"keywords": [
|
|
33
32
|
"dsh",
|
|
@@ -49,19 +48,20 @@
|
|
|
49
48
|
}
|
|
50
49
|
},
|
|
51
50
|
"scripts": {
|
|
52
|
-
"clean": "node scripts/clean.
|
|
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\"
|
|
57
|
-
"test:e2e": "node tests/e2e/paper-full-flow.
|
|
58
|
-
"test:bench": "node tests/e2e/paper-full-flow.
|
|
59
|
-
"test:net": "node tests/e2e/paper-lit-real.
|
|
60
|
-
"test:host": "node scripts/host-smoke.
|
|
61
|
-
"test:host-load": "node scripts/host-verify.
|
|
62
|
-
"audit": "node scripts/audit-surface.
|
|
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.
|
|
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
67
|
"node": ">=22.16",
|
|
@@ -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
|
-
└─
|
|
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
|
-
|
|
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_*`
|
|
91
|
+
| **把系统搞懂、被追问到能自证** | **本技能**(配 `defense_code_*` 三个工具) |
|
|
90
92
|
|
|
91
93
|
## 完成的标准
|
|
92
94
|
|