dsh-thesis 2.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/docs/host-api.md CHANGED
@@ -436,7 +436,14 @@ type PreStepDecision = { kind: 'reject' } | { kind: 'enter'; messages: UserMessa
436
436
 
437
437
  `next()` 保持当前 messages;返回值替换进入该步骤的消息,或拒绝该步骤(mode `waterfall`,按 agent 作用域过滤派发)。
438
438
  注入物必须是 `UserMessage`:`{ id, role: 'user', content: ContentBlock[], source }`,`source` 用
439
- `{ kind: 'plugin', plugin: '<name>' } & ContextFormed`(`form: 'instructions' | 'catalog' | 'snapshot' | 'notice' | 'relay' | 'recall'`)。
439
+ `{ kind: 'plugin:<name>' } & ContextFormed`(`form: 'instructions' | 'catalog' | 'snapshot' | 'notice' | 'relay' | 'recall'`)。
440
+
441
+ > **`kind` 必须是生产者自有值。** 从 v4 会话格式起,共享兜底 kind `plugin` 会被直接拒写:
442
+ > `format v4 message requires a producer-owned source kind`,而且是在落会话日志时抛,
443
+ > 整条会话起不来。第三方插件的规范写法是 `plugin:<包名>`——宿主的 v3→v4 迁移器
444
+ > (`@deepseek-ai/dsh-session-format-v3-to-v4` 的 `producerKind`)给未知生产者生成的就是它,
445
+ > 这样旧会话迁移后与新消息同源同 kind。本插件踩过:2.0.1 用了 `kind: 'plugin'`,
446
+ > 论文工作区里的新会话一开就报上面那句。
440
447
  `form` 决定客户端怎么渲染,且**每个形态只带自己那几个字段**(`ContextFormed` 是判别联合):
441
448
  `sections` 只属于 `snapshot`,`summary` 只属于 `notice`,`instructions` 的渲染依据是
442
449
  `changes`(工作区指令文件的改动清单,见 `dsh-agent-instructions`)。
@@ -459,7 +466,7 @@ export function registerPreStep(ctx: Context, buildCard: (cwd: string) => Promis
459
466
  kind: 'enter',
460
467
  messages: [...decision.messages, {
461
468
  id: randomUUID(), role: 'user', content: [{ type: 'text', text: note }],
462
- source: { kind: 'plugin', plugin: 'my-plugin', form: 'snapshot', sections: [{ name: 'my-plugin', text: note }] },
469
+ source: { kind: 'plugin:my-plugin', form: 'snapshot', sections: [{ name: 'my-plugin', text: note }] },
463
470
  }],
464
471
  }
465
472
  }, { prepend: true })
package/docs/release.md CHANGED
@@ -18,6 +18,16 @@
18
18
  | Workflow filename | `publish.yml`(只写文件名,不带路径)|
19
19
  | Environment name | **留空**(除非 workflow 里写了 `environment:`)|
20
20
 
21
+ 同一页下方的 **Allowed actions**:
22
+
23
+ | 选项 | 勾不勾 | 为什么 |
24
+ |---|---|---|
25
+ | stage publish | 强制,改不了 | — |
26
+ | **Allow npm publish** | **勾上** | 不勾的话 `npm publish` 会被拒(`403 OIDC permission denied for this action`),只接受 `npm stage publish`,每次发版还得你到网页上做 2FA 批准 |
27
+ | Allow npm dist-tag | 不用勾 | `npm publish` 会自动把 `latest` 指过去;我们没有 `npm dist-tag` 操作 |
28
+
29
+ > 黄色提示条只说「provider 与必填字段建好后不能改」,`Allowed actions` 的两个勾选框随时可以改。
30
+
21
31
  2. 确认仓库是 **public**:私有仓库发不出 provenance。
22
32
  3. 不需要 `NPM_TOKEN`,**之前建过的话建议在 Settings → Secrets 里删掉**,免得以后误用。
23
33
 
@@ -103,6 +113,8 @@ Actions → publish → Run workflow:只做打包预览,**不会发布**。
103
113
  | 现象 | 原因 |
104
114
  |---|---|
105
115
  | `EOTP` / `This operation requires a one-time password` | 用的是需要 OTP 的 token(2FA 账号的 Granular / Publish token)。CI 里没人能输 OTP:改用可信发布,或换 Classic → Automation token |
116
+ | 发布被拒,提示只能 `npm stage publish` | 可信发布里没勾 **Allow publish directly**(默认只允许 stage)|
117
+ | `403 … OIDC permission denied for this action` | 同一条:OIDC 认证已经通过(组织/仓库/workflow 名字都对),只是没给「直接发布」权限。去包设置里编辑那条配置,勾上 **Allow npm publish** |
106
118
  | `401 Unauthorized` | token 过期(Automation token 有 90/180 天寿命),或可信发布配置里 workflow 文件名写错 |
107
119
  | `npm ci … not in sync` | 改了 `package.json` 的依赖/peer 却没跑 `npm install --package-lock-only` |
108
120
  | `403 … cannot publish over previously published version` | 版本号没升;这条在 workflow 里已被「已存在则跳过」挡住,手动发版时要注意 |
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * 自动驾驶注入的消息与关卡确认文案。
3
3
  *
4
- * 与闸门消息共用同一条 source 约定:`{ kind: 'plugin', plugin: 'dsh-thesis', form: 'instructions' }`。
4
+ * 与闸门消息共用同一条 source 约定:`{ kind: 'plugin:dsh-thesis', form: 'instructions' }`
5
+ * (v4 会话格式禁止兜底 kind `plugin`,见 `shared/message-source.ts`)。
5
6
  * `form` 是宿主渲染指令的语义形态;`sections` 只属于 snapshot 形态,这里不写。
6
7
  *
7
8
  * @module dsh-thesis/autopilot
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * 自动驾驶注入的消息与关卡确认文案。
3
3
  *
4
- * 与闸门消息共用同一条 source 约定:`{ kind: 'plugin', plugin: 'dsh-thesis', form: 'instructions' }`。
4
+ * 与闸门消息共用同一条 source 约定:`{ kind: 'plugin:dsh-thesis', form: 'instructions' }`
5
+ * (v4 会话格式禁止兜底 kind `plugin`,见 `shared/message-source.ts`)。
5
6
  * `form` 是宿主渲染指令的语义形态;`sections` 只属于 snapshot 形态,这里不写。
6
7
  *
7
8
  * @module dsh-thesis/autopilot
@@ -91,8 +91,8 @@ export interface InjectedUserMessageShape {
91
91
  readonly role: 'user';
92
92
  readonly content: readonly TextBlockShape[];
93
93
  readonly source: {
94
- readonly kind: 'plugin';
95
- readonly plugin: string;
94
+ /** 生产者自有 kind(本插件是 `plugin:dsh-thesis`);v4 会话格式不接受兜底值 `plugin`。 */
95
+ readonly kind: string;
96
96
  /** 上下文形态:instructions / catalog / snapshot / notice / relay / recall(可缺省 = 不透明)。 */
97
97
  readonly form?: string;
98
98
  /** 只有 `form: 'snapshot'` 携带分节;`instructions` 形态的有效字段是 `changes`。 */
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import { AiLearningEngine } from "./engine.js";
12
12
  import { newMessageId } from "./tools.js";
13
+ import { THESIS_SOURCE } from "../shared/message-source.js";
13
14
  /** 为一份状态快照构造注入用的进度消息。 */
14
15
  export function buildProgressMessage(state) {
15
16
  const text = [
@@ -24,8 +25,7 @@ export function buildProgressMessage(state) {
24
25
  role: 'user',
25
26
  content: [{ type: 'text', text: full }],
26
27
  source: {
27
- kind: 'plugin',
28
- plugin: 'dsh-thesis',
28
+ ...THESIS_SOURCE,
29
29
  form: 'snapshot',
30
30
  sections: [{ name: '代码演练进度', text: full }],
31
31
  },
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * 闸门注入消息与决策理由的模板。
3
3
  *
4
- * 注入消息的 source 采用 `{ kind: 'plugin', plugin: 'dsh-thesis', form: 'instructions' }`:
5
- * - `plugin` 是生产者标识(GUI 用它做行首标签,也用于防重入识别"这已经是闸门消息");
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.plugin 的值。 */
20
- export declare const PLUGIN_ID = "dsh-thesis";
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
  * 写作意图闸门注入给模型的指令。
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * 闸门注入消息与决策理由的模板。
3
3
  *
4
- * 注入消息的 source 采用 `{ kind: 'plugin', plugin: 'dsh-thesis', form: 'instructions' }`:
5
- * - `plugin` 是生产者标识(GUI 用它做行首标签,也用于防重入识别"这已经是闸门消息");
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
- /** 插件标识:注入消息 source.plugin 的值。 */
20
- export const PLUGIN_ID = 'dsh-thesis';
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 = { kind: 'plugin', plugin: PLUGIN_ID };
25
+ export const PLUGIN_SOURCE = THESIS_SOURCE;
23
26
  /**
24
27
  * 写作意图闸门注入给模型的指令。
25
28
  *
@@ -52,7 +52,6 @@ export declare function makeIntakeGateMessage(status: SpecStatus, specRel: strin
52
52
  }>;
53
53
  source: {
54
54
  kind: string;
55
- plugin: string;
56
- form: string;
55
+ form: 'instructions';
57
56
  };
58
57
  };
@@ -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
- kind: 'plugin',
118
- plugin: 'dsh-thesis',
118
+ ...THESIS_SOURCE,
119
119
  form: 'instructions',
120
120
  },
121
121
  };
@@ -53,8 +53,7 @@ export declare function makeRecallMessage(entries: readonly MemoryEntry[], maxCh
53
53
  }>;
54
54
  source: {
55
55
  kind: string;
56
- plugin: string;
57
- form: string;
56
+ form: 'snapshot';
58
57
  sections: Array<{
59
58
  name: string;
60
59
  text: string;
@@ -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
- kind: 'plugin',
115
- plugin: 'dsh-thesis',
115
+ ...THESIS_SOURCE,
116
116
  form: 'snapshot',
117
117
  sections: [{ name: '已确认事实', text }],
118
118
  },
@@ -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": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "论文与答辩全流程助手(DeepSeek Harness 插件):材料摄取 → 逐题追问 → 文献检索 → 逐章写作与评审 → 原创性自查与合规 → Word/答辩幻灯生产,全流程留痕,并跨会话记住学校规范与导师要求。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",