dsh-thesis 1.0.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/DESIGN.md +390 -0
- package/LICENSE +21 -0
- package/NOTICE.md +10 -0
- package/README.md +253 -0
- package/cordis.patch.yml +17 -0
- package/docs/host-api.md +640 -0
- package/lib/codewalk/commands.d.ts +23 -0
- package/lib/codewalk/commands.js +168 -0
- package/lib/codewalk/engine.d.ts +108 -0
- package/lib/codewalk/engine.js +449 -0
- package/lib/codewalk/errors.d.ts +31 -0
- package/lib/codewalk/errors.js +20 -0
- package/lib/codewalk/fs-types.d.ts +34 -0
- package/lib/codewalk/fs-types.js +10 -0
- package/lib/codewalk/gate.d.ts +30 -0
- package/lib/codewalk/gate.js +60 -0
- package/lib/codewalk/host-types.d.ts +198 -0
- package/lib/codewalk/host-types.js +11 -0
- package/lib/codewalk/prestep.d.ts +17 -0
- package/lib/codewalk/prestep.js +62 -0
- package/lib/codewalk/register.d.ts +23 -0
- package/lib/codewalk/register.js +31 -0
- package/lib/codewalk/skill.d.ts +15 -0
- package/lib/codewalk/skill.js +57 -0
- package/lib/codewalk/tools.d.ts +18 -0
- package/lib/codewalk/tools.js +314 -0
- package/lib/codewalk/types.d.ts +151 -0
- package/lib/codewalk/types.js +9 -0
- package/lib/commands.d.ts +33 -0
- package/lib/commands.js +60 -0
- package/lib/config.d.ts +125 -0
- package/lib/config.js +139 -0
- package/lib/dedup/commands.d.ts +21 -0
- package/lib/dedup/commands.js +93 -0
- package/lib/dedup/index.d.ts +75 -0
- package/lib/dedup/index.js +331 -0
- package/lib/dedup/normalize.d.ts +125 -0
- package/lib/dedup/normalize.js +329 -0
- package/lib/dedup/report.d.ts +114 -0
- package/lib/dedup/report.js +309 -0
- package/lib/dedup/rewrite.d.ts +71 -0
- package/lib/dedup/rewrite.js +228 -0
- package/lib/dedup/similarity.d.ts +169 -0
- package/lib/dedup/similarity.js +323 -0
- package/lib/gates/dangerous.d.ts +22 -0
- package/lib/gates/dangerous.js +47 -0
- package/lib/gates/detect.d.ts +54 -0
- package/lib/gates/detect.js +106 -0
- package/lib/gates/messages.d.ts +39 -0
- package/lib/gates/messages.js +74 -0
- package/lib/gates/prompt.d.ts +21 -0
- package/lib/gates/prompt.js +56 -0
- package/lib/gates/writing-intent.d.ts +49 -0
- package/lib/gates/writing-intent.js +68 -0
- package/lib/index.d.ts +36 -0
- package/lib/index.js +76 -0
- package/lib/ingest/code.d.ts +71 -0
- package/lib/ingest/code.js +356 -0
- package/lib/ingest/commands.d.ts +23 -0
- package/lib/ingest/commands.js +74 -0
- package/lib/ingest/docx.d.ts +29 -0
- package/lib/ingest/docx.js +92 -0
- package/lib/ingest/index.d.ts +179 -0
- package/lib/ingest/index.js +640 -0
- package/lib/ingest/ooxml.d.ts +58 -0
- package/lib/ingest/ooxml.js +393 -0
- package/lib/ingest/pdf.d.ts +86 -0
- package/lib/ingest/pdf.js +1016 -0
- package/lib/ingest/pptx.d.ts +32 -0
- package/lib/ingest/pptx.js +116 -0
- package/lib/ingest/text.d.ts +25 -0
- package/lib/ingest/text.js +180 -0
- package/lib/ingest/types.d.ts +48 -0
- package/lib/ingest/types.js +47 -0
- package/lib/ingest/xlsx.d.ts +72 -0
- package/lib/ingest/xlsx.js +411 -0
- package/lib/ingest/zip.d.ts +76 -0
- package/lib/ingest/zip.js +393 -0
- package/lib/intake/definitions.d.ts +65 -0
- package/lib/intake/definitions.js +42 -0
- package/lib/intake/gate-rules.d.ts +57 -0
- package/lib/intake/gate-rules.js +118 -0
- package/lib/intake/gate.d.ts +24 -0
- package/lib/intake/gate.js +86 -0
- package/lib/intake/index.d.ts +76 -0
- package/lib/intake/index.js +468 -0
- package/lib/intake/questions.d.ts +169 -0
- package/lib/intake/questions.js +720 -0
- package/lib/intake/spec.d.ts +66 -0
- package/lib/intake/spec.js +221 -0
- package/lib/intake/state.d.ts +192 -0
- package/lib/intake/state.js +420 -0
- package/lib/memory/recall.d.ts +69 -0
- package/lib/memory/recall.js +177 -0
- package/lib/memory/register.d.ts +37 -0
- package/lib/memory/register.js +52 -0
- package/lib/memory/service.d.ts +39 -0
- package/lib/memory/service.js +39 -0
- package/lib/memory/store.d.ts +45 -0
- package/lib/memory/store.js +123 -0
- package/lib/memory/tools.d.ts +19 -0
- package/lib/memory/tools.js +195 -0
- package/lib/memory/types.d.ts +55 -0
- package/lib/memory/types.js +6 -0
- package/lib/paper/commands.d.ts +13 -0
- package/lib/paper/commands.js +84 -0
- package/lib/paper/lib/aicheck.d.ts +38 -0
- package/lib/paper/lib/aicheck.js +241 -0
- package/lib/paper/lib/bibtex.d.ts +21 -0
- package/lib/paper/lib/bibtex.js +114 -0
- package/lib/paper/lib/check.d.ts +32 -0
- package/lib/paper/lib/check.js +215 -0
- package/lib/paper/lib/defense.d.ts +48 -0
- package/lib/paper/lib/defense.js +220 -0
- package/lib/paper/lib/docx.d.ts +35 -0
- package/lib/paper/lib/docx.js +213 -0
- package/lib/paper/lib/layout.d.ts +41 -0
- package/lib/paper/lib/layout.js +572 -0
- package/lib/paper/lib/ledger.d.ts +112 -0
- package/lib/paper/lib/ledger.js +349 -0
- package/lib/paper/lib/lit-api.d.ts +59 -0
- package/lib/paper/lib/lit-api.js +296 -0
- package/lib/paper/lib/lit-cache.d.ts +32 -0
- package/lib/paper/lib/lit-cache.js +91 -0
- package/lib/paper/lib/project.d.ts +29 -0
- package/lib/paper/lib/project.js +93 -0
- package/lib/paper/lib/review.d.ts +37 -0
- package/lib/paper/lib/review.js +194 -0
- package/lib/paper/lib/zip.d.ts +14 -0
- package/lib/paper/lib/zip.js +124 -0
- package/lib/paper/register.d.ts +20 -0
- package/lib/paper/register.js +183 -0
- package/lib/paper/tools/aicheck.d.ts +6 -0
- package/lib/paper/tools/aicheck.js +38 -0
- package/lib/paper/tools/build.d.ts +27 -0
- package/lib/paper/tools/build.js +166 -0
- package/lib/paper/tools/check.d.ts +7 -0
- package/lib/paper/tools/check.js +79 -0
- package/lib/paper/tools/decision.d.ts +13 -0
- package/lib/paper/tools/decision.js +53 -0
- package/lib/paper/tools/defense.d.ts +11 -0
- package/lib/paper/tools/defense.js +74 -0
- package/lib/paper/tools/init.d.ts +23 -0
- package/lib/paper/tools/init.js +99 -0
- package/lib/paper/tools/lit.d.ts +27 -0
- package/lib/paper/tools/lit.js +236 -0
- package/lib/paper/tools/progress.d.ts +18 -0
- package/lib/paper/tools/progress.js +77 -0
- package/lib/paper/tools/review.d.ts +11 -0
- package/lib/paper/tools/review.js +41 -0
- package/lib/ppt/actions.d.ts +97 -0
- package/lib/ppt/actions.js +263 -0
- package/lib/ppt/check.d.ts +64 -0
- package/lib/ppt/check.js +185 -0
- package/lib/ppt/commands.d.ts +28 -0
- package/lib/ppt/commands.js +71 -0
- package/lib/ppt/convert.d.ts +146 -0
- package/lib/ppt/convert.js +423 -0
- package/lib/ppt/index.d.ts +45 -0
- package/lib/ppt/index.js +57 -0
- package/lib/ppt/marp.d.ts +74 -0
- package/lib/ppt/marp.js +165 -0
- package/lib/ppt/outline.d.ts +206 -0
- package/lib/ppt/outline.js +695 -0
- package/lib/shared/define-tool.d.ts +77 -0
- package/lib/shared/define-tool.js +235 -0
- package/lib/shared/fs-errors.d.ts +50 -0
- package/lib/shared/fs-errors.js +90 -0
- package/lib/shared/index.d.ts +31 -0
- package/lib/shared/index.js +32 -0
- package/lib/shared/spawn.d.ts +38 -0
- package/lib/shared/spawn.js +50 -0
- package/lib/shared/text.d.ts +14 -0
- package/lib/shared/text.js +26 -0
- package/package.json +82 -0
- package/skills/code-walkthrough/SKILL.md +94 -0
- package/skills/code-walkthrough/references/examples.md +129 -0
- package/skills/paper-dedup/SKILL.md +58 -0
- package/skills/paper-intake/SKILL.md +64 -0
- package/skills/thesis-citation/SKILL.md +67 -0
- package/skills/thesis-defense/SKILL.md +87 -0
- package/skills/thesis-eng-design/SKILL.md +97 -0
- package/skills/thesis-inquiry/SKILL.md +55 -0
- package/skills/thesis-inquiry/references/intent-spec-template.md +39 -0
- package/skills/thesis-literature/SKILL.md +56 -0
- package/skills/thesis-opener/SKILL.md +77 -0
- package/skills/thesis-pipeline/SKILL.md +121 -0
- package/skills/thesis-writing/SKILL.md +86 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 跨会话事实的装配层:把 SQLite 事实库挂到 `ctx.memory`
|
|
3
|
+
* 并注册三个模型工具(`fact_search` / `fact_remember` / `fact_context`)。
|
|
4
|
+
*
|
|
5
|
+
* 落点:`$DSH_HOME/dsh-thesis-memory.db`(可用 `memoryPath` 覆盖)。**刻意用一个
|
|
6
|
+
* 全局库**而不是每篇论文一个库:装配发生在进程启动时、拿不到会话 cwd;而事实
|
|
7
|
+
* 里跨课题复用的内容(写作风格偏好、导师沟通习惯、学校通用规范)本来就应该
|
|
8
|
+
* 跨项目活着。课题专属内容用 key 前缀隔离:
|
|
9
|
+
* `thesis.<课题 slug>.<实体>.<属性>`。
|
|
10
|
+
*
|
|
11
|
+
* **面向学生的说法**:这是「记住你的学校和导师要求,换个会话不用重讲」的能力,
|
|
12
|
+
* 不是「记忆系统」。学生不需要知道它叫 memory。
|
|
13
|
+
*
|
|
14
|
+
* @module dsh-thesis/memory
|
|
15
|
+
*/
|
|
16
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
17
|
+
import type { RecallOptions } from './recall.ts';
|
|
18
|
+
import { type MemoryService } from './service.ts';
|
|
19
|
+
/**
|
|
20
|
+
* 默认库位置:`$DSH_HOME/dsh-thesis-memory.db`,否则 `~/.dsh-thesis-memory.db`。
|
|
21
|
+
*
|
|
22
|
+
* 只有一个位置,没有回退:本插件的包名从未以其它名字发布过,因此不存在
|
|
23
|
+
* 「数据躺在旧文件里、新文件是空的」这种需要兼容的历史包袱。
|
|
24
|
+
* 建这种回退只会留下一条永远不成立的分支。
|
|
25
|
+
*/
|
|
26
|
+
export declare function defaultMemoryPath(): string;
|
|
27
|
+
export interface FactRegistration {
|
|
28
|
+
readonly service: MemoryService;
|
|
29
|
+
readonly path: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 装配跨会话事实:provider + 三个模型工具,注册为 `ctx.memory`。
|
|
33
|
+
* Disposal 关闭数据库。
|
|
34
|
+
*/
|
|
35
|
+
export declare function registerFacts(ctx: Context, configured?: string): FactRegistration;
|
|
36
|
+
/** 装配「相关时把已确认事实放回上下文」。 */
|
|
37
|
+
export declare function installFactRecall(ctx: Context, options: RecallOptions): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 跨会话事实的装配层:把 SQLite 事实库挂到 `ctx.memory`
|
|
3
|
+
* 并注册三个模型工具(`fact_search` / `fact_remember` / `fact_context`)。
|
|
4
|
+
*
|
|
5
|
+
* 落点:`$DSH_HOME/dsh-thesis-memory.db`(可用 `memoryPath` 覆盖)。**刻意用一个
|
|
6
|
+
* 全局库**而不是每篇论文一个库:装配发生在进程启动时、拿不到会话 cwd;而事实
|
|
7
|
+
* 里跨课题复用的内容(写作风格偏好、导师沟通习惯、学校通用规范)本来就应该
|
|
8
|
+
* 跨项目活着。课题专属内容用 key 前缀隔离:
|
|
9
|
+
* `thesis.<课题 slug>.<实体>.<属性>`。
|
|
10
|
+
*
|
|
11
|
+
* **面向学生的说法**:这是「记住你的学校和导师要求,换个会话不用重讲」的能力,
|
|
12
|
+
* 不是「记忆系统」。学生不需要知道它叫 memory。
|
|
13
|
+
*
|
|
14
|
+
* @module dsh-thesis/memory
|
|
15
|
+
*/
|
|
16
|
+
import { homedir } from 'node:os';
|
|
17
|
+
import { join, resolve } from 'node:path';
|
|
18
|
+
import { installFactRecall as installRecall } from "./recall.js";
|
|
19
|
+
import { SqliteMemoryService } from "./service.js";
|
|
20
|
+
import { memoryTools } from "./tools.js";
|
|
21
|
+
/**
|
|
22
|
+
* 默认库位置:`$DSH_HOME/dsh-thesis-memory.db`,否则 `~/.dsh-thesis-memory.db`。
|
|
23
|
+
*
|
|
24
|
+
* 只有一个位置,没有回退:本插件的包名从未以其它名字发布过,因此不存在
|
|
25
|
+
* 「数据躺在旧文件里、新文件是空的」这种需要兼容的历史包袱。
|
|
26
|
+
* 建这种回退只会留下一条永远不成立的分支。
|
|
27
|
+
*/
|
|
28
|
+
export function defaultMemoryPath() {
|
|
29
|
+
const home = process.env.DSH_HOME?.trim();
|
|
30
|
+
const dir = home !== undefined && home !== '' ? home : homedir();
|
|
31
|
+
return join(dir, 'dsh-thesis-memory.db');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 装配跨会话事实:provider + 三个模型工具,注册为 `ctx.memory`。
|
|
35
|
+
* Disposal 关闭数据库。
|
|
36
|
+
*/
|
|
37
|
+
export function registerFacts(ctx, configured) {
|
|
38
|
+
const path = configured === ':memory:' || configured === undefined || configured.trim() === ''
|
|
39
|
+
? (configured ?? defaultMemoryPath())
|
|
40
|
+
: resolve(configured);
|
|
41
|
+
const service = new SqliteMemoryService(path);
|
|
42
|
+
ctx.provide('memory', service);
|
|
43
|
+
ctx.effect(() => () => service.close(), 'dsh-thesis.memory.closeDatabase');
|
|
44
|
+
for (const tool of memoryTools(service)) {
|
|
45
|
+
ctx.tools.register(tool);
|
|
46
|
+
}
|
|
47
|
+
return { service, path };
|
|
48
|
+
}
|
|
49
|
+
/** 装配「相关时把已确认事实放回上下文」。 */
|
|
50
|
+
export function installFactRecall(ctx, options) {
|
|
51
|
+
installRecall(ctx, options);
|
|
52
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 跨会话事实:SQLite provider 与它的类型契约。
|
|
3
|
+
*
|
|
4
|
+
* **刻意不继承 cordis 的 `Service` 基类**:provider 是个普通类,由
|
|
5
|
+
* `registerFacts` 通过 `ctx.provide('memory', service)` 注册。这样做的收益:
|
|
6
|
+
* 整个事实库可以在**没有宿主运行时**的环境里被构造与验证——装配测试
|
|
7
|
+
* 用一个假的 ctx 就能跑通 `apply()`,而不必把 cordis 拖进测试依赖。
|
|
8
|
+
*
|
|
9
|
+
* 面向学生的说法是「记住你的学校和导师要求,换个会话不用重讲」;
|
|
10
|
+
* `memory` 只是它在宿主里的服务名,不是学生要调用的工具。
|
|
11
|
+
*
|
|
12
|
+
* 业务语义在 {@link MemoryStore}(纯 SQLite);本文件只做参数校验边界。
|
|
13
|
+
*
|
|
14
|
+
* @module dsh-thesis/memory/service
|
|
15
|
+
*/
|
|
16
|
+
import type { MemoryContextOptions, MemoryEntry, MemoryInput, MemorySearchOptions, RememberResult } from './types.ts';
|
|
17
|
+
export type { MemoryContextOptions, MemoryEntry, MemoryInput, MemorySearchOptions, MemoryType, RememberResult, } from './types.ts';
|
|
18
|
+
/** 记忆能力的对外契约(`ctx.get('memory')` 拿到的就是这个形状)。 */
|
|
19
|
+
export interface MemoryService {
|
|
20
|
+
/** 创建或原地更新一条记忆。 */
|
|
21
|
+
remember(entry: MemoryInput): RememberResult;
|
|
22
|
+
/** 对 key 与 value 做大小写不敏感子串检索。 */
|
|
23
|
+
search(query: string, options?: MemorySearchOptions): MemoryEntry[];
|
|
24
|
+
/** 列出某个命名空间/前缀下的全部条目。 */
|
|
25
|
+
context(topic: string, options?: MemoryContextOptions): MemoryEntry[];
|
|
26
|
+
}
|
|
27
|
+
/** 唯一的 provider:一个 SQLite 文件(或 `:memory:`)。 */
|
|
28
|
+
export declare class SqliteMemoryService implements MemoryService {
|
|
29
|
+
private readonly store;
|
|
30
|
+
/**
|
|
31
|
+
* @param dbPath - SQLite 文件路径或 `:memory:`;父目录缺失时自动创建。
|
|
32
|
+
*/
|
|
33
|
+
constructor(dbPath: string);
|
|
34
|
+
/** 关闭数据库(插件卸载时由 `ctx.effect` 调用)。 */
|
|
35
|
+
close(): void;
|
|
36
|
+
remember(entry: MemoryInput): RememberResult;
|
|
37
|
+
search(query: string, options?: MemorySearchOptions): MemoryEntry[];
|
|
38
|
+
context(topic: string, options?: MemoryContextOptions): MemoryEntry[];
|
|
39
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 跨会话事实:SQLite provider 与它的类型契约。
|
|
3
|
+
*
|
|
4
|
+
* **刻意不继承 cordis 的 `Service` 基类**:provider 是个普通类,由
|
|
5
|
+
* `registerFacts` 通过 `ctx.provide('memory', service)` 注册。这样做的收益:
|
|
6
|
+
* 整个事实库可以在**没有宿主运行时**的环境里被构造与验证——装配测试
|
|
7
|
+
* 用一个假的 ctx 就能跑通 `apply()`,而不必把 cordis 拖进测试依赖。
|
|
8
|
+
*
|
|
9
|
+
* 面向学生的说法是「记住你的学校和导师要求,换个会话不用重讲」;
|
|
10
|
+
* `memory` 只是它在宿主里的服务名,不是学生要调用的工具。
|
|
11
|
+
*
|
|
12
|
+
* 业务语义在 {@link MemoryStore}(纯 SQLite);本文件只做参数校验边界。
|
|
13
|
+
*
|
|
14
|
+
* @module dsh-thesis/memory/service
|
|
15
|
+
*/
|
|
16
|
+
import { MemoryStore } from "./store.js";
|
|
17
|
+
/** 唯一的 provider:一个 SQLite 文件(或 `:memory:`)。 */
|
|
18
|
+
export class SqliteMemoryService {
|
|
19
|
+
store;
|
|
20
|
+
/**
|
|
21
|
+
* @param dbPath - SQLite 文件路径或 `:memory:`;父目录缺失时自动创建。
|
|
22
|
+
*/
|
|
23
|
+
constructor(dbPath) {
|
|
24
|
+
this.store = new MemoryStore(dbPath);
|
|
25
|
+
}
|
|
26
|
+
/** 关闭数据库(插件卸载时由 `ctx.effect` 调用)。 */
|
|
27
|
+
close() {
|
|
28
|
+
this.store.close();
|
|
29
|
+
}
|
|
30
|
+
remember(entry) {
|
|
31
|
+
return this.store.remember(entry);
|
|
32
|
+
}
|
|
33
|
+
search(query, options = {}) {
|
|
34
|
+
return this.store.search(query, options);
|
|
35
|
+
}
|
|
36
|
+
context(topic, options = {}) {
|
|
37
|
+
return this.store.context(topic, options);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 记忆存储:纯 SQLite 实现,**零 cordis 依赖**(可独立单测)。
|
|
3
|
+
*
|
|
4
|
+
* 与 `service.ts` 的分工遵循本仓库的通用约定:业务逻辑在 store 里,
|
|
5
|
+
* 宿主服务外壳(`ctx.memory`)只是它的适配器。这样记忆的语义
|
|
6
|
+
* (原地更新保留 createdAt、子串检索、前缀上下文)能在没有宿主
|
|
7
|
+
* 运行时的环境里被直接验证。
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-thesis/memory/store
|
|
10
|
+
*/
|
|
11
|
+
import type { MemoryContextOptions, MemoryEntry, MemoryInput, MemorySearchOptions, RememberResult } from './types.ts';
|
|
12
|
+
/** 记忆 key 规范化:去空白后不得为空。 */
|
|
13
|
+
export declare function normalizeKey(key: string): string;
|
|
14
|
+
/** 单次查询返回条数的上限:防止一次把整张表倒进上下文。 */
|
|
15
|
+
export declare const MAX_LIMIT = 500;
|
|
16
|
+
/** 把调用方给的 limit 夹到 `[1, MAX_LIMIT]`;缺省 50(而不是"不限制")。 */
|
|
17
|
+
export declare function clampLimit(limit: number | undefined): number;
|
|
18
|
+
/**
|
|
19
|
+
* SQLite 记忆存储。`:memory:` 打开进程内临时库(测试用)。
|
|
20
|
+
*
|
|
21
|
+
* 语义约定(与 `MemoryService` 的抽象契约一致):
|
|
22
|
+
* - `remember`:新 key 插入,已有 key 原地更新且保留 `createdAt`;
|
|
23
|
+
* - `search`:对 key 与 value 做大小写不敏感子串匹配,按 key 排序;
|
|
24
|
+
* - `context`:返回 key 等于 topic 或以 `topic.` 开头的全部条目。
|
|
25
|
+
*/
|
|
26
|
+
export declare class MemoryStore {
|
|
27
|
+
private readonly db;
|
|
28
|
+
constructor(dbPath: string);
|
|
29
|
+
/** 关闭数据库。幂等(插件卸载与测试清理都会调用)。 */
|
|
30
|
+
close(): void;
|
|
31
|
+
remember(entry: MemoryInput): RememberResult;
|
|
32
|
+
/**
|
|
33
|
+
* 检索事实。
|
|
34
|
+
*
|
|
35
|
+
* `query` 为空串时**不当作"匹配一切"**:必须同时给出 `namespace`,否则抛错——
|
|
36
|
+
* 否则 `search('')` 会静默返回整张表的前 N 条,调用方以为自己在做检索。
|
|
37
|
+
* 回灌路径要全量取用时请显式给 `namespace`(它内部按命名空间取)。
|
|
38
|
+
*
|
|
39
|
+
* `limit` 一律夹到 `[1, 500]`:负数或 0 以前会**完全绕开 SQL 的 LIMIT**,返回整张表。
|
|
40
|
+
*/
|
|
41
|
+
search(query: string, options?: MemorySearchOptions): MemoryEntry[];
|
|
42
|
+
context(topic: string, options?: MemoryContextOptions): MemoryEntry[];
|
|
43
|
+
private getRow;
|
|
44
|
+
private rows;
|
|
45
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 记忆存储:纯 SQLite 实现,**零 cordis 依赖**(可独立单测)。
|
|
3
|
+
*
|
|
4
|
+
* 与 `service.ts` 的分工遵循本仓库的通用约定:业务逻辑在 store 里,
|
|
5
|
+
* 宿主服务外壳(`ctx.memory`)只是它的适配器。这样记忆的语义
|
|
6
|
+
* (原地更新保留 createdAt、子串检索、前缀上下文)能在没有宿主
|
|
7
|
+
* 运行时的环境里被直接验证。
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-thesis/memory/store
|
|
10
|
+
*/
|
|
11
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
12
|
+
import { mkdirSync } from 'node:fs';
|
|
13
|
+
import { dirname, resolve } from 'node:path';
|
|
14
|
+
/** 记忆 key 规范化:去空白后不得为空。 */
|
|
15
|
+
export function normalizeKey(key) {
|
|
16
|
+
const trimmed = key.trim();
|
|
17
|
+
if (trimmed.length === 0) {
|
|
18
|
+
throw new Error('memory: key must be a non-empty string');
|
|
19
|
+
}
|
|
20
|
+
return trimmed;
|
|
21
|
+
}
|
|
22
|
+
/** 单次查询返回条数的上限:防止一次把整张表倒进上下文。 */
|
|
23
|
+
export const MAX_LIMIT = 500;
|
|
24
|
+
/** 把调用方给的 limit 夹到 `[1, MAX_LIMIT]`;缺省 50(而不是"不限制")。 */
|
|
25
|
+
export function clampLimit(limit) {
|
|
26
|
+
if (limit === undefined || !Number.isFinite(limit))
|
|
27
|
+
return 50;
|
|
28
|
+
return Math.min(MAX_LIMIT, Math.max(1, Math.floor(limit)));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* SQLite 记忆存储。`:memory:` 打开进程内临时库(测试用)。
|
|
32
|
+
*
|
|
33
|
+
* 语义约定(与 `MemoryService` 的抽象契约一致):
|
|
34
|
+
* - `remember`:新 key 插入,已有 key 原地更新且保留 `createdAt`;
|
|
35
|
+
* - `search`:对 key 与 value 做大小写不敏感子串匹配,按 key 排序;
|
|
36
|
+
* - `context`:返回 key 等于 topic 或以 `topic.` 开头的全部条目。
|
|
37
|
+
*/
|
|
38
|
+
export class MemoryStore {
|
|
39
|
+
db;
|
|
40
|
+
constructor(dbPath) {
|
|
41
|
+
if (dbPath !== ':memory:') {
|
|
42
|
+
const target = resolve(dbPath);
|
|
43
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
44
|
+
dbPath = target;
|
|
45
|
+
}
|
|
46
|
+
this.db = new DatabaseSync(dbPath);
|
|
47
|
+
this.db.exec('PRAGMA journal_mode = WAL');
|
|
48
|
+
this.db.exec(`
|
|
49
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
50
|
+
key TEXT PRIMARY KEY,
|
|
51
|
+
value TEXT NOT NULL,
|
|
52
|
+
type TEXT NOT NULL,
|
|
53
|
+
source TEXT NOT NULL,
|
|
54
|
+
confidence REAL NOT NULL,
|
|
55
|
+
created_at INTEGER NOT NULL,
|
|
56
|
+
updated_at INTEGER NOT NULL
|
|
57
|
+
) STRICT
|
|
58
|
+
`);
|
|
59
|
+
}
|
|
60
|
+
/** 关闭数据库。幂等(插件卸载与测试清理都会调用)。 */
|
|
61
|
+
close() {
|
|
62
|
+
this.db.close();
|
|
63
|
+
}
|
|
64
|
+
remember(entry) {
|
|
65
|
+
const key = normalizeKey(entry.key);
|
|
66
|
+
const now = Date.now();
|
|
67
|
+
const existing = this.getRow(key);
|
|
68
|
+
if (existing === undefined) {
|
|
69
|
+
this.db.prepare('INSERT INTO memories (key, value, type, source, confidence, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)').run(key, entry.value, entry.type, entry.source, entry.confidence, now, now);
|
|
70
|
+
return { action: 'created', key, value: entry.value };
|
|
71
|
+
}
|
|
72
|
+
this.db.prepare('UPDATE memories SET value = ?, type = ?, source = ?, confidence = ?, updated_at = ? WHERE key = ?').run(entry.value, entry.type, entry.source, entry.confidence, now, key);
|
|
73
|
+
return { action: 'updated', key, value: entry.value };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 检索事实。
|
|
77
|
+
*
|
|
78
|
+
* `query` 为空串时**不当作"匹配一切"**:必须同时给出 `namespace`,否则抛错——
|
|
79
|
+
* 否则 `search('')` 会静默返回整张表的前 N 条,调用方以为自己在做检索。
|
|
80
|
+
* 回灌路径要全量取用时请显式给 `namespace`(它内部按命名空间取)。
|
|
81
|
+
*
|
|
82
|
+
* `limit` 一律夹到 `[1, 500]`:负数或 0 以前会**完全绕开 SQL 的 LIMIT**,返回整张表。
|
|
83
|
+
*/
|
|
84
|
+
search(query, options = {}) {
|
|
85
|
+
if (query === '' && options.namespace === undefined) {
|
|
86
|
+
throw new Error('fact_search 需要一个非空 query,或一个 namespace(只给 namespace 表示「列出该命名空间下的全部事实」)。');
|
|
87
|
+
}
|
|
88
|
+
const clauses = [];
|
|
89
|
+
const args = [];
|
|
90
|
+
if (options.namespace !== undefined) {
|
|
91
|
+
clauses.push('key LIKE ?');
|
|
92
|
+
args.push(options.namespace + '.%');
|
|
93
|
+
}
|
|
94
|
+
if (query !== '') {
|
|
95
|
+
clauses.push('(key LIKE ? OR value LIKE ?)');
|
|
96
|
+
const pattern = `%${query}%`;
|
|
97
|
+
args.push(pattern, pattern);
|
|
98
|
+
}
|
|
99
|
+
const where = clauses.length > 0 ? ` WHERE ${clauses.join(' AND ')}` : '';
|
|
100
|
+
args.push(clampLimit(options.limit));
|
|
101
|
+
return this.rows(`SELECT key, value, type, source, confidence, created_at, updated_at FROM memories${where} ORDER BY key LIMIT ?`, args);
|
|
102
|
+
}
|
|
103
|
+
context(topic, options = {}) {
|
|
104
|
+
const args = [topic, topic + '.%', clampLimit(options.limit)];
|
|
105
|
+
return this.rows('SELECT key, value, type, source, confidence, created_at, updated_at FROM memories'
|
|
106
|
+
+ ' WHERE key = ? OR key LIKE ? ORDER BY key LIMIT ?', args);
|
|
107
|
+
}
|
|
108
|
+
getRow(key) {
|
|
109
|
+
return this.db.prepare('SELECT key, value, type, source, confidence, created_at, updated_at FROM memories WHERE key = ?').get(key);
|
|
110
|
+
}
|
|
111
|
+
rows(sql, args) {
|
|
112
|
+
const rows = this.db.prepare(sql).all(...args);
|
|
113
|
+
return rows.map(row => ({
|
|
114
|
+
key: row.key,
|
|
115
|
+
value: row.value,
|
|
116
|
+
type: row.type,
|
|
117
|
+
source: row.source,
|
|
118
|
+
confidence: row.confidence,
|
|
119
|
+
createdAt: row.created_at,
|
|
120
|
+
updatedAt: row.updated_at,
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 面向模型的跨会话事实工具定义:`fact_search` / `fact_remember` / `fact_context`,
|
|
3
|
+
* 三个工具共用同一个 {@link MemoryService}。
|
|
4
|
+
*
|
|
5
|
+
* 命名空间 `fact_*` 的含义:**跨会话仍然成立的稳定事实**——学校规范、导师要求、
|
|
6
|
+
* 你的写作偏好。它与 `thesis_*`(操作论文工作区里的东西)并列。
|
|
7
|
+
* 进度、临时任务、一次性的实验数字不属于这里(它们在进度台账与实验记录里)。
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-thesis/memory/tools
|
|
10
|
+
*/
|
|
11
|
+
import type { MemoryService } from './service.ts';
|
|
12
|
+
/**
|
|
13
|
+
* 三个面向模型的跨会话事实工具。
|
|
14
|
+
*
|
|
15
|
+
* 命名空间 `fact_*` 的含义:**跨会话仍然成立的稳定事实**——学校规范、导师要求、
|
|
16
|
+
* 你的写作偏好。它与 `thesis_*`(操作论文工作区里的东西)是并列的两类。
|
|
17
|
+
* 进度、临时任务、一次性的实验数字不属于这里(它们在进度台账与实验记录里)。
|
|
18
|
+
*/
|
|
19
|
+
export declare function memoryTools(service: MemoryService): unknown[];
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 面向模型的跨会话事实工具定义:`fact_search` / `fact_remember` / `fact_context`,
|
|
3
|
+
* 三个工具共用同一个 {@link MemoryService}。
|
|
4
|
+
*
|
|
5
|
+
* 命名空间 `fact_*` 的含义:**跨会话仍然成立的稳定事实**——学校规范、导师要求、
|
|
6
|
+
* 你的写作偏好。它与 `thesis_*`(操作论文工作区里的东西)并列。
|
|
7
|
+
* 进度、临时任务、一次性的实验数字不属于这里(它们在进度台账与实验记录里)。
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-thesis/memory/tools
|
|
10
|
+
*/
|
|
11
|
+
import { definePaperTool } from "../shared/index.js";
|
|
12
|
+
const MEMORY_TYPES = ['fact', 'preference', 'entity', 'relation'];
|
|
13
|
+
/** Resolve model-omitted fields into a complete write request. */
|
|
14
|
+
function resolveRememberInput(raw) {
|
|
15
|
+
const key = raw.key.trim();
|
|
16
|
+
if (key.length === 0) {
|
|
17
|
+
throw new Error('fact_remember: `key` must be a non-empty string');
|
|
18
|
+
}
|
|
19
|
+
if (raw.value.trim().length === 0) {
|
|
20
|
+
throw new Error('fact_remember: `value` must be a non-empty string');
|
|
21
|
+
}
|
|
22
|
+
const type = (raw.type ?? 'fact');
|
|
23
|
+
const confidence = raw.confidence ?? 1;
|
|
24
|
+
if (!Number.isFinite(confidence) || confidence < 0 || confidence > 1) {
|
|
25
|
+
throw new Error(`fact_remember: confidence must be in 0..1, got ${JSON.stringify(confidence)}`);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
key,
|
|
29
|
+
value: raw.value,
|
|
30
|
+
type,
|
|
31
|
+
source: raw.source?.trim() || 'manual',
|
|
32
|
+
confidence,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function renderSearchResults(results) {
|
|
36
|
+
if (results.length === 0)
|
|
37
|
+
return '没有找到相关记忆。';
|
|
38
|
+
return results.map(row => `${row.key} = ${row.value}`).join('\n');
|
|
39
|
+
}
|
|
40
|
+
/** Build the inline natural-language projection of a context listing. */
|
|
41
|
+
function renderContext(facts) {
|
|
42
|
+
if (facts.length === 0)
|
|
43
|
+
return '这个主题下还没有记忆。';
|
|
44
|
+
const byNamespace = new Map();
|
|
45
|
+
for (const fact of facts) {
|
|
46
|
+
const dot = fact.key.indexOf('.');
|
|
47
|
+
const namespace = dot === -1 ? fact.key : fact.key.slice(0, dot);
|
|
48
|
+
const rest = dot === -1 ? fact.key : fact.key.slice(dot + 1);
|
|
49
|
+
const rows = byNamespace.get(namespace) ?? [];
|
|
50
|
+
rows.push(`${rest}=${fact.value}`);
|
|
51
|
+
byNamespace.set(namespace, rows);
|
|
52
|
+
}
|
|
53
|
+
let out = '';
|
|
54
|
+
for (const [namespace, rows] of byNamespace) {
|
|
55
|
+
out += (out.length === 0 ? '' : '。') + `关于 ${namespace}: ${rows.join(', ')}`;
|
|
56
|
+
}
|
|
57
|
+
return `${out}。`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 三个面向模型的跨会话事实工具。
|
|
61
|
+
*
|
|
62
|
+
* 命名空间 `fact_*` 的含义:**跨会话仍然成立的稳定事实**——学校规范、导师要求、
|
|
63
|
+
* 你的写作偏好。它与 `thesis_*`(操作论文工作区里的东西)是并列的两类。
|
|
64
|
+
* 进度、临时任务、一次性的实验数字不属于这里(它们在进度台账与实验记录里)。
|
|
65
|
+
*/
|
|
66
|
+
export function memoryTools(service) {
|
|
67
|
+
return [
|
|
68
|
+
definePaperTool({
|
|
69
|
+
name: 'fact_search',
|
|
70
|
+
description: '在跨会话事实库里检索:对 key 与 value 做大小写不敏感的子串匹配(可选限定命名空间、限制条数)。'
|
|
71
|
+
+ '用于确认「上次记下的学校规范/导师要求/写作偏好还在不在」,以及回答用户「我之前说过什么」。',
|
|
72
|
+
parameters: {
|
|
73
|
+
query: { type: 'string', required: true, description: '要匹配的子串(同时匹配 key 与 value)' },
|
|
74
|
+
namespace: { type: 'string', description: '可选命名空间;只考虑该前缀下的 key(如 thesis 或 thesis.face-attendance)' },
|
|
75
|
+
limit: { type: 'integer', description: '返回条数上限,默认 10' },
|
|
76
|
+
},
|
|
77
|
+
output: {
|
|
78
|
+
schema: {
|
|
79
|
+
type: 'object',
|
|
80
|
+
additionalProperties: false,
|
|
81
|
+
properties: {
|
|
82
|
+
results: {
|
|
83
|
+
type: 'array',
|
|
84
|
+
required: true,
|
|
85
|
+
items: {
|
|
86
|
+
type: 'object',
|
|
87
|
+
additionalProperties: false,
|
|
88
|
+
properties: {
|
|
89
|
+
key: { type: 'string', required: true },
|
|
90
|
+
value: { type: 'string', required: true },
|
|
91
|
+
source: { type: 'string', required: true },
|
|
92
|
+
confidence: { type: 'number', required: true },
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
render: (_args, value) => [{ type: 'text', text: renderSearchResults(value.results) }],
|
|
99
|
+
},
|
|
100
|
+
async execute(args) {
|
|
101
|
+
const entries = service.search(args.query, {
|
|
102
|
+
...args.namespace !== undefined ? { namespace: args.namespace } : {},
|
|
103
|
+
limit: args.limit ?? 10,
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
results: entries.map(entry => ({
|
|
107
|
+
key: entry.key,
|
|
108
|
+
value: entry.value,
|
|
109
|
+
source: entry.source,
|
|
110
|
+
confidence: entry.confidence,
|
|
111
|
+
})),
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
}),
|
|
115
|
+
definePaperTool({
|
|
116
|
+
name: 'fact_remember',
|
|
117
|
+
description: '写入或更新一条跨会话事实(key 已存在则原地更新,保留原始创建时间)。'
|
|
118
|
+
+ '只记**跨会话仍然成立**的事实:用户偏好(user.*)、学校通用规范(school.*)、课题稳定事实(thesis.<课题>.*)。'
|
|
119
|
+
+ '不要把进度、临时任务或一次性实验数字写进来——那些在进度台账与实验记录里。',
|
|
120
|
+
parameters: {
|
|
121
|
+
key: { type: 'string', required: true, description: '记忆 key,三段式 `namespace.entity.attribute`,如 school.dedup.system' },
|
|
122
|
+
value: { type: 'string', required: true, description: '要记住的值' },
|
|
123
|
+
type: {
|
|
124
|
+
type: 'string',
|
|
125
|
+
enum: [...MEMORY_TYPES],
|
|
126
|
+
description: '分类:fact(事实)/ preference(偏好)/ entity(实体)/ relation(关系),默认 fact',
|
|
127
|
+
},
|
|
128
|
+
source: { type: 'string', description: '来源标注,默认 manual;如 intake(追问确认)、decision(决定日志)' },
|
|
129
|
+
confidence: { type: 'number', description: '置信度 0..1,默认 1' },
|
|
130
|
+
},
|
|
131
|
+
output: {
|
|
132
|
+
schema: {
|
|
133
|
+
type: 'object',
|
|
134
|
+
additionalProperties: false,
|
|
135
|
+
properties: {
|
|
136
|
+
action: { type: 'string', required: true, enum: ['created', 'updated'] },
|
|
137
|
+
key: { type: 'string', required: true },
|
|
138
|
+
value: { type: 'string', required: true },
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
render: (_args, value) => [{
|
|
142
|
+
type: 'text',
|
|
143
|
+
text: `${value.action === 'created' ? '已写入' : '已更新'}记忆 ${value.key} = ${value.value}`,
|
|
144
|
+
}],
|
|
145
|
+
},
|
|
146
|
+
async execute(args) {
|
|
147
|
+
const input = resolveRememberInput(args);
|
|
148
|
+
return service.remember(input);
|
|
149
|
+
},
|
|
150
|
+
}),
|
|
151
|
+
definePaperTool({
|
|
152
|
+
name: 'fact_context',
|
|
153
|
+
description: '取出某个命名空间/前缀下的全部事实作为上下文,同时给出自然语言投影与 key-value 列表。'
|
|
154
|
+
+ '开新会话时用它把「这个课题/这所学校已知的稳定事实」一次性拉回来。',
|
|
155
|
+
parameters: {
|
|
156
|
+
topic: { type: 'string', required: true, description: '命名空间或 key 前缀,如 thesis.face-attendance' },
|
|
157
|
+
limit: { type: 'integer', description: '返回条数上限,默认不限' },
|
|
158
|
+
},
|
|
159
|
+
output: {
|
|
160
|
+
schema: {
|
|
161
|
+
type: 'object',
|
|
162
|
+
additionalProperties: false,
|
|
163
|
+
properties: {
|
|
164
|
+
context: { type: 'string', required: true },
|
|
165
|
+
facts: {
|
|
166
|
+
type: 'array',
|
|
167
|
+
required: true,
|
|
168
|
+
items: {
|
|
169
|
+
type: 'object',
|
|
170
|
+
additionalProperties: false,
|
|
171
|
+
properties: {
|
|
172
|
+
key: { type: 'string', required: true },
|
|
173
|
+
value: { type: 'string', required: true },
|
|
174
|
+
confidence: { type: 'number', required: true },
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
render: (_args, value) => [{ type: 'text', text: value.context }],
|
|
181
|
+
},
|
|
182
|
+
async execute(args) {
|
|
183
|
+
const entries = service.context(args.topic, {
|
|
184
|
+
...args.limit !== undefined ? { limit: args.limit } : {},
|
|
185
|
+
});
|
|
186
|
+
const facts = entries.map(entry => ({
|
|
187
|
+
key: entry.key,
|
|
188
|
+
value: entry.value,
|
|
189
|
+
confidence: entry.confidence,
|
|
190
|
+
}));
|
|
191
|
+
return { context: renderContext(facts), facts };
|
|
192
|
+
},
|
|
193
|
+
}),
|
|
194
|
+
];
|
|
195
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 跨会话事实的纯类型:service 与面向模型的工具共用这套词汇。
|
|
3
|
+
*
|
|
4
|
+
* @module dsh-thesis/memory/types
|
|
5
|
+
*/
|
|
6
|
+
/** 分类一条事实:fact(事实)/ preference(偏好)/ entity(实体)/ relation(关系)。 */
|
|
7
|
+
export type MemoryType = 'fact' | 'preference' | 'entity' | 'relation';
|
|
8
|
+
/** 一次写入请求(交给 {@link MemoryService.remember})。 */
|
|
9
|
+
export interface MemoryInput {
|
|
10
|
+
/** 事实 key,约定三段式 `namespace.entity.attribute`。 */
|
|
11
|
+
key: string;
|
|
12
|
+
/** 要记住的值。 */
|
|
13
|
+
value: string;
|
|
14
|
+
/** 分类。 */
|
|
15
|
+
type: MemoryType;
|
|
16
|
+
/** 来源标注,如文件路径或 `manual`。 */
|
|
17
|
+
source: string;
|
|
18
|
+
/** 置信度,取值 `0..1`。 */
|
|
19
|
+
confidence: number;
|
|
20
|
+
}
|
|
21
|
+
/** 一条已存事实(读取时返回的形态)。 */
|
|
22
|
+
export interface MemoryEntry {
|
|
23
|
+
key: string;
|
|
24
|
+
value: string;
|
|
25
|
+
type: MemoryType;
|
|
26
|
+
source: string;
|
|
27
|
+
confidence: number;
|
|
28
|
+
/** 首次写入的时间戳(epoch 毫秒)。 */
|
|
29
|
+
createdAt: number;
|
|
30
|
+
/** 最近一次写入的时间戳(epoch 毫秒)。 */
|
|
31
|
+
updatedAt: number;
|
|
32
|
+
}
|
|
33
|
+
/** 一次成功写入的结果。 */
|
|
34
|
+
export interface RememberResult {
|
|
35
|
+
/** 新 key 为 `created`,已存在的 key 为 `updated`。 */
|
|
36
|
+
action: 'created' | 'updated';
|
|
37
|
+
key: string;
|
|
38
|
+
value: string;
|
|
39
|
+
}
|
|
40
|
+
/** {@link MemoryService.search} 的收窄选项。 */
|
|
41
|
+
export interface MemorySearchOptions {
|
|
42
|
+
/** 只考虑以该命名空间前缀开头的 key(`namespace.`)。 */
|
|
43
|
+
namespace?: string;
|
|
44
|
+
/**
|
|
45
|
+
* 最多返回条数。**缺省 50,一律夹到 `[1, 500]`**:
|
|
46
|
+
* 传给 SQL 的 LIMIT 不能省(否则一次检索会把整张表倒进上下文),
|
|
47
|
+
* 负数或 0 也不再被解释为「不限制」。
|
|
48
|
+
*/
|
|
49
|
+
limit?: number;
|
|
50
|
+
}
|
|
51
|
+
/** {@link MemoryService.context} 的收窄选项。 */
|
|
52
|
+
export interface MemoryContextOptions {
|
|
53
|
+
/** 最多返回条数;与 `search` 同一套夹取规则。 */
|
|
54
|
+
limit?: number;
|
|
55
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 斜杠命令:/thesis-status 与 /thesis-decide。
|
|
3
|
+
*
|
|
4
|
+
* 注:DSH 命令名只允许 [a-z][a-z0-9_-]*,因此使用 kebab-case
|
|
5
|
+
* (DESIGN.md 中的 /thesis:status 在此修正为 /thesis-status)。
|
|
6
|
+
* 其余命令(/thesis-lit、/thesis-check、/thesis-build)随 M2/M4 工具一并注册。
|
|
7
|
+
*/
|
|
8
|
+
import type { FileSystem } from '@deepseek-ai/dsh-fs';
|
|
9
|
+
export declare function statusCommand(fs: FileSystem): unknown;
|
|
10
|
+
export declare function decideCommand(fs: FileSystem): unknown;
|
|
11
|
+
export declare function litCommand(fs: FileSystem): unknown;
|
|
12
|
+
export declare function checkCommand(fs: FileSystem): unknown;
|
|
13
|
+
export declare function buildCommand(fs: FileSystem): unknown;
|