@coralai/sps-cli 0.58.14 → 0.58.15
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/README.md +2 -14
- package/dist/commands/agentCommand.d.ts.map +1 -1
- package/dist/commands/agentCommand.js +29 -26
- package/dist/commands/agentCommand.js.map +1 -1
- package/dist/commands/memoryCommand.d.ts +2 -0
- package/dist/commands/memoryCommand.d.ts.map +1 -0
- package/dist/commands/memoryCommand.js +263 -0
- package/dist/commands/memoryCommand.js.map +1 -0
- package/dist/commands/projectInit.d.ts.map +1 -1
- package/dist/commands/projectInit.js +21 -0
- package/dist/commands/projectInit.js.map +1 -1
- package/dist/commands/tick.d.ts.map +1 -1
- package/dist/commands/tick.js +1 -19
- package/dist/commands/tick.js.map +1 -1
- package/dist/console/index.d.ts.map +1 -1
- package/dist/console/index.js +2 -0
- package/dist/console/index.js.map +1 -1
- package/dist/console/routes/memory.d.ts +11 -0
- package/dist/console/routes/memory.d.ts.map +1 -0
- package/dist/console/routes/memory.js +63 -0
- package/dist/console/routes/memory.js.map +1 -0
- package/dist/console/routes/system.d.ts.map +1 -1
- package/dist/console/routes/system.js +6 -3
- package/dist/console/routes/system.js.map +1 -1
- package/dist/console-assets/assets/index-DENsMsFy.css +10 -0
- package/dist/console-assets/assets/{index-BiGbp-FL.js → index-R6Y8wve3.js} +194 -194
- package/dist/console-assets/index.html +2 -2
- package/dist/core/agents/AcpBackend.d.ts +2 -0
- package/dist/core/agents/AcpBackend.d.ts.map +1 -1
- package/dist/core/agents/AcpBackend.js +5 -0
- package/dist/core/agents/AcpBackend.js.map +1 -1
- package/dist/core/agents/ClaudeSdkBackend.d.ts +0 -1
- package/dist/core/agents/ClaudeSdkBackend.d.ts.map +1 -1
- package/dist/core/agents/ClaudeSdkBackend.js +1 -1
- package/dist/core/agents/ClaudeSdkBackend.js.map +1 -1
- package/dist/core/agents/CodexAppServerBackend.d.ts +0 -1
- package/dist/core/agents/CodexAppServerBackend.d.ts.map +1 -1
- package/dist/core/agents/CodexAppServerBackend.js +1 -1
- package/dist/core/agents/CodexAppServerBackend.js.map +1 -1
- package/dist/core/agents/OpenAiAgentBackend.d.ts +0 -2
- package/dist/core/agents/OpenAiAgentBackend.d.ts.map +1 -1
- package/dist/core/agents/OpenAiAgentBackend.js +5 -4
- package/dist/core/agents/OpenAiAgentBackend.js.map +1 -1
- package/dist/core/agents/resolveBackend.d.ts +0 -1
- package/dist/core/agents/resolveBackend.d.ts.map +1 -1
- package/dist/core/agents/resolveBackend.js +3 -4
- package/dist/core/agents/resolveBackend.js.map +1 -1
- package/dist/core/codegraph/claudeMdRule.d.ts +7 -0
- package/dist/core/codegraph/claudeMdRule.d.ts.map +1 -0
- package/dist/core/codegraph/claudeMdRule.js +79 -0
- package/dist/core/codegraph/claudeMdRule.js.map +1 -0
- package/dist/core/memory2/capture.d.ts +33 -0
- package/dist/core/memory2/capture.d.ts.map +1 -0
- package/dist/core/memory2/capture.js +91 -0
- package/dist/core/memory2/capture.js.map +1 -0
- package/dist/core/memory2/claudeMdRule.d.ts +7 -0
- package/dist/core/memory2/claudeMdRule.d.ts.map +1 -0
- package/dist/core/memory2/claudeMdRule.js +65 -0
- package/dist/core/memory2/claudeMdRule.js.map +1 -0
- package/dist/core/memory2/config.d.ts +20 -0
- package/dist/core/memory2/config.d.ts.map +1 -0
- package/dist/core/memory2/config.js +26 -0
- package/dist/core/memory2/config.js.map +1 -0
- package/dist/core/memory2/digest.d.ts +16 -0
- package/dist/core/memory2/digest.d.ts.map +1 -0
- package/dist/core/memory2/digest.js +52 -0
- package/dist/core/memory2/digest.js.map +1 -0
- package/dist/core/memory2/gc.d.ts +9 -0
- package/dist/core/memory2/gc.d.ts.map +1 -0
- package/dist/core/memory2/gc.js +45 -0
- package/dist/core/memory2/gc.js.map +1 -0
- package/dist/core/memory2/inject.d.ts +16 -0
- package/dist/core/memory2/inject.d.ts.map +1 -0
- package/dist/core/memory2/inject.js +45 -0
- package/dist/core/memory2/inject.js.map +1 -0
- package/dist/core/memory2/lock.d.ts +7 -0
- package/dist/core/memory2/lock.d.ts.map +1 -0
- package/dist/core/memory2/lock.js +59 -0
- package/dist/core/memory2/lock.js.map +1 -0
- package/dist/core/memory2/migrate.d.ts +12 -0
- package/dist/core/memory2/migrate.d.ts.map +1 -0
- package/dist/core/memory2/migrate.js +119 -0
- package/dist/core/memory2/migrate.js.map +1 -0
- package/dist/core/memory2/redact.d.ts +21 -0
- package/dist/core/memory2/redact.d.ts.map +1 -0
- package/dist/core/memory2/redact.js +116 -0
- package/dist/core/memory2/redact.js.map +1 -0
- package/dist/core/memory2/retrieve.d.ts +16 -0
- package/dist/core/memory2/retrieve.d.ts.map +1 -0
- package/dist/core/memory2/retrieve.js +70 -0
- package/dist/core/memory2/retrieve.js.map +1 -0
- package/dist/core/memory2/store.d.ts +30 -0
- package/dist/core/memory2/store.d.ts.map +1 -0
- package/dist/core/memory2/store.js +217 -0
- package/dist/core/memory2/store.js.map +1 -0
- package/dist/core/memory2/types.d.ts +53 -0
- package/dist/core/memory2/types.d.ts.map +1 -0
- package/dist/core/memory2/types.js +12 -0
- package/dist/core/memory2/types.js.map +1 -0
- package/dist/engines/StageEngine.d.ts.map +1 -1
- package/dist/engines/StageEngine.js +13 -8
- package/dist/engines/StageEngine.js.map +1 -1
- package/dist/main.js +17 -154
- package/dist/main.js.map +1 -1
- package/dist/manager/worker-manager-impl.d.ts +10 -0
- package/dist/manager/worker-manager-impl.d.ts.map +1 -1
- package/dist/manager/worker-manager-impl.js +50 -5
- package/dist/manager/worker-manager-impl.js.map +1 -1
- package/dist/providers/llm/workerTools.js +1 -1
- package/dist/providers/mcp/spsMcpServer.d.ts +13 -7
- package/dist/providers/mcp/spsMcpServer.d.ts.map +1 -1
- package/dist/providers/mcp/spsMcpServer.js +90 -28
- package/dist/providers/mcp/spsMcpServer.js.map +1 -1
- package/dist/providers/mcp/spsMcpStdio.js +3 -15
- package/dist/providers/mcp/spsMcpStdio.js.map +1 -1
- package/dist/providers/mcp/spsMcpStdioConfig.d.ts +2 -1
- package/dist/providers/mcp/spsMcpStdioConfig.d.ts.map +1 -1
- package/dist/providers/mcp/spsMcpStdioConfig.js +3 -1
- package/dist/providers/mcp/spsMcpStdioConfig.js.map +1 -1
- package/dist/services/MemoryService.d.ts +69 -0
- package/dist/services/MemoryService.d.ts.map +1 -0
- package/dist/services/MemoryService.js +178 -0
- package/dist/services/MemoryService.js.map +1 -0
- package/dist/services/SystemService.d.ts +17 -3
- package/dist/services/SystemService.d.ts.map +1 -1
- package/dist/services/SystemService.js +75 -17
- package/dist/services/SystemService.js.map +1 -1
- package/dist/services/container.d.ts +2 -0
- package/dist/services/container.d.ts.map +1 -1
- package/dist/services/container.js +2 -0
- package/dist/services/container.js.map +1 -1
- package/package.json +1 -2
- package/project-template/.claude/CLAUDE.md +0 -23
- package/skills/sps-pipeline/SKILL.md +12 -15
- package/dist/console-assets/assets/index-BHtTCxMY.css +0 -10
- package/dist/core/memory.d.ts +0 -85
- package/dist/core/memory.d.ts.map +0 -1
- package/dist/core/memory.js +0 -374
- package/dist/core/memory.js.map +0 -1
- package/dist/core/memoryIngest.d.ts +0 -18
- package/dist/core/memoryIngest.d.ts.map +0 -1
- package/dist/core/memoryIngest.js +0 -56
- package/dist/core/memoryIngest.js.map +0 -1
- package/dist/core/memoryProvider.d.ts +0 -63
- package/dist/core/memoryProvider.d.ts.map +0 -1
- package/dist/core/memoryProvider.js +0 -205
- package/dist/core/memoryProvider.js.map +0 -1
- package/dist/core/transcriptIngest.d.ts +0 -37
- package/dist/core/transcriptIngest.d.ts.map +0 -1
- package/dist/core/transcriptIngest.js +0 -137
- package/dist/core/transcriptIngest.js.map +0 -1
- package/skills/sps-memory/SKILL.md +0 -51
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/memory2/redact
|
|
3
|
+
* @description 写入前敏感信息过滤(设计 §5.1,**默认必开**)。自动捕获 + agent 主动 memory_save
|
|
4
|
+
* 都经此:命中密钥/凭据/私有路径 → 打码 [REDACTED];命中高危(私钥/AWS key)→ 整条丢弃。
|
|
5
|
+
* 规则可经 ~/.coral/memory/redact.rules 追加;SPS_MEMORY_REDACT=off 关(不建议)。
|
|
6
|
+
* 纯正则、零 LLM——不依赖模型自觉。
|
|
7
|
+
* @layer core
|
|
8
|
+
* @boundedContext memory
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { memoryRoot } from './store.js';
|
|
13
|
+
const MASK = '[REDACTED]';
|
|
14
|
+
/** 高危:命中即丢弃整条(不打码,连带上下文一起弃)。 */
|
|
15
|
+
const DROP_RULES = [
|
|
16
|
+
{ re: /-----BEGIN (?:[A-Z ]+ )?PRIVATE KEY-----/g, kind: 'drop', label: 'private-key' },
|
|
17
|
+
{ re: /\bAKIA[0-9A-Z]{16}\b/g, kind: 'drop', label: 'aws-access-key' },
|
|
18
|
+
];
|
|
19
|
+
/** 打码:命中片段替换为 [REDACTED]。 */
|
|
20
|
+
const MASK_RULES = [
|
|
21
|
+
// 密钥/令牌前缀
|
|
22
|
+
{ re: /\bsk-[A-Za-z0-9_-]{16,}\b/g, kind: 'mask', label: 'sk-token' },
|
|
23
|
+
{ re: /\bgh[oprsu]_[A-Za-z0-9]{16,}\b/g, kind: 'mask', label: 'github-token' },
|
|
24
|
+
{ re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, kind: 'mask', label: 'slack-token' },
|
|
25
|
+
{ re: /\bBearer\s+[A-Za-z0-9._~+/-]{12,}=*/g, kind: 'mask', label: 'bearer' },
|
|
26
|
+
// 凭据 URL:scheme://user:pass@host
|
|
27
|
+
{ re: /\b[a-z][a-z0-9+.-]*:\/\/[^\s:@/]+:[^\s:@/]+@[^\s/]+/g, kind: 'mask', label: 'credential-url' },
|
|
28
|
+
// .env 式 KEY=value(仅敏感键名)
|
|
29
|
+
{ re: /\b[A-Z0-9_]*(?:SECRET|TOKEN|API[_-]?KEY|PASSWORD|PASSWD|PASS|DSN|PRIVATE[_-]?KEY|ACCESS[_-]?KEY)[A-Z0-9_]*\s*[=:]\s*['"]?[^\s'"]+/gi, kind: 'mask', label: 'env-secret' },
|
|
30
|
+
// 私有绝对路径
|
|
31
|
+
{ re: /\/Users\/[^/\s'"]+/g, kind: 'mask', label: 'macos-home' },
|
|
32
|
+
{ re: /\/home\/[^/\s'"]+/g, kind: 'mask', label: 'linux-home' },
|
|
33
|
+
// 内网 IP(RFC1918 + loopback)
|
|
34
|
+
{ re: /\b(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3})\b/g, kind: 'mask', label: 'internal-ip' },
|
|
35
|
+
];
|
|
36
|
+
let extraCache = null;
|
|
37
|
+
/**
|
|
38
|
+
* 读 ~/.coral/memory/redact.rules 的追加规则。每行一条正则,`drop:` 前缀=高危丢弃;
|
|
39
|
+
* `#` 开头=注释。非法正则跳过。惰性加载 + 缓存(SPS_MEMORY_ROOT 变了会失效由测试用 resetRedactCache 处理)。
|
|
40
|
+
*/
|
|
41
|
+
function loadExtraRules() {
|
|
42
|
+
if (extraCache)
|
|
43
|
+
return extraCache;
|
|
44
|
+
extraCache = [];
|
|
45
|
+
const p = join(memoryRoot(), 'redact.rules');
|
|
46
|
+
if (!existsSync(p))
|
|
47
|
+
return extraCache;
|
|
48
|
+
for (const raw of readFileSync(p, 'utf-8').split(/\r?\n/)) {
|
|
49
|
+
const line = raw.trim();
|
|
50
|
+
if (!line || line.startsWith('#'))
|
|
51
|
+
continue;
|
|
52
|
+
const drop = line.startsWith('drop:');
|
|
53
|
+
const src = drop ? line.slice(5).trim() : line;
|
|
54
|
+
try {
|
|
55
|
+
extraCache.push({ re: new RegExp(src, 'g'), kind: drop ? 'drop' : 'mask', label: `custom:${src.slice(0, 24)}` });
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
/* 非法正则跳过 */
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return extraCache;
|
|
62
|
+
}
|
|
63
|
+
/** 测试用:清空追加规则缓存(改了 SPS_MEMORY_ROOT/redact.rules 后调用)。 */
|
|
64
|
+
export function resetRedactCache() {
|
|
65
|
+
extraCache = null;
|
|
66
|
+
}
|
|
67
|
+
function isOff() {
|
|
68
|
+
return (process.env.SPS_MEMORY_REDACT ?? '').toLowerCase() === 'off';
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 对一条记忆(title+body 合起来判)做脱敏。命中 drop 规则→dropped=true;否则对命中 mask 规则的片段打码。
|
|
72
|
+
* SPS_MEMORY_REDACT=off 时原样返回。
|
|
73
|
+
*/
|
|
74
|
+
export function redactEntry(title, body) {
|
|
75
|
+
if (isOff())
|
|
76
|
+
return { title, body, dropped: false, reasons: [] };
|
|
77
|
+
const rules = [...DROP_RULES, ...MASK_RULES, ...loadExtraRules()];
|
|
78
|
+
const reasons = new Set();
|
|
79
|
+
const combined = `${title}\n${body}`;
|
|
80
|
+
// 先判高危丢弃(任一 drop 规则命中整条 → 弃)。
|
|
81
|
+
for (const r of rules) {
|
|
82
|
+
if (r.kind !== 'drop')
|
|
83
|
+
continue;
|
|
84
|
+
r.re.lastIndex = 0;
|
|
85
|
+
if (r.re.test(combined))
|
|
86
|
+
reasons.add(r.label);
|
|
87
|
+
}
|
|
88
|
+
if (reasons.size > 0) {
|
|
89
|
+
return { title: '', body: '', dropped: true, reasons: [...reasons] };
|
|
90
|
+
}
|
|
91
|
+
// 再逐条 mask。
|
|
92
|
+
let t = title;
|
|
93
|
+
let b = body;
|
|
94
|
+
for (const r of rules) {
|
|
95
|
+
if (r.kind !== 'mask')
|
|
96
|
+
continue;
|
|
97
|
+
r.re.lastIndex = 0;
|
|
98
|
+
if (r.re.test(t) || r.re.test(b)) {
|
|
99
|
+
reasons.add(r.label);
|
|
100
|
+
r.re.lastIndex = 0;
|
|
101
|
+
t = t.replace(r.re, MASK);
|
|
102
|
+
b = b.replace(r.re, MASK);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { title: t, body: b, dropped: false, reasons: [...reasons] };
|
|
106
|
+
}
|
|
107
|
+
/** 写入被拒(命中高危):调用方据此提示"已丢弃"。 */
|
|
108
|
+
export class RedactedEntryDropped extends Error {
|
|
109
|
+
reasons;
|
|
110
|
+
constructor(reasons) {
|
|
111
|
+
super(`记忆写入被拒:命中敏感信息(${reasons.join(', ')})`);
|
|
112
|
+
this.name = 'RedactedEntryDropped';
|
|
113
|
+
this.reasons = reasons;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../../src/core/memory2/redact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MemoryEntry, ScopeRef } from './types.js';
|
|
2
|
+
export interface SearchHit {
|
|
3
|
+
entry: MemoryEntry;
|
|
4
|
+
score: number;
|
|
5
|
+
}
|
|
6
|
+
export interface SearchOpts {
|
|
7
|
+
tags?: string[];
|
|
8
|
+
limit?: number;
|
|
9
|
+
}
|
|
10
|
+
/** 分词:拉丁词 + 数字 + 单个 CJK 字。 */
|
|
11
|
+
export declare function tokenize(s: string): string[];
|
|
12
|
+
/** 对给定条目集按 query 做 BM25 + tag 过滤 + salience 加权排序。纯函数(便于测试/组合)。 */
|
|
13
|
+
export declare function searchEntries(entries: MemoryEntry[], query: string, opts?: SearchOpts): SearchHit[];
|
|
14
|
+
/** 跨多个作用域检索(如 worker = project + global)。 */
|
|
15
|
+
export declare function recall(refs: ScopeRef[], query: string, opts?: SearchOpts): SearchHit[];
|
|
16
|
+
//# sourceMappingURL=retrieve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retrieve.d.ts","sourceRoot":"","sources":["../../../src/core/memory2/retrieve.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAExD,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,8BAA8B;AAC9B,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAK5C;AAKD,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,SAAS,EAAE,CA6CvG;AAED,6CAA6C;AAC7C,wBAAgB,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,SAAS,EAAE,CAG1F"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/memory2/retrieve
|
|
3
|
+
* @description 纯内存相关性检索(修旧系统 C1 的零相关性)。BM25 + tag 过滤 + salience 加权。
|
|
4
|
+
* 零 DB、零依赖,任何 Node 可跑(设计 §4);store 大再上可选 FTS5(后续 P6)。
|
|
5
|
+
* 中文按单字分词 + 拉丁按词——小规模够用。
|
|
6
|
+
* @layer core
|
|
7
|
+
* @boundedContext memory
|
|
8
|
+
*/
|
|
9
|
+
import { listEntries } from './store.js';
|
|
10
|
+
/** 分词:拉丁词 + 数字 + 单个 CJK 字。 */
|
|
11
|
+
export function tokenize(s) {
|
|
12
|
+
const lower = s.toLowerCase();
|
|
13
|
+
const latin = lower.match(/[a-z0-9]+/g) ?? [];
|
|
14
|
+
const cjk = lower.match(/[一-鿿]/g) ?? [];
|
|
15
|
+
return [...latin, ...cjk];
|
|
16
|
+
}
|
|
17
|
+
const K1 = 1.5;
|
|
18
|
+
const B = 0.75;
|
|
19
|
+
/** 对给定条目集按 query 做 BM25 + tag 过滤 + salience 加权排序。纯函数(便于测试/组合)。 */
|
|
20
|
+
export function searchEntries(entries, query, opts = {}) {
|
|
21
|
+
const limit = opts.limit ?? 6;
|
|
22
|
+
let cand = entries;
|
|
23
|
+
if (opts.tags?.length) {
|
|
24
|
+
const want = new Set(opts.tags.map((t) => t.toLowerCase()));
|
|
25
|
+
cand = cand.filter((e) => e.tags.some((t) => want.has(t.toLowerCase())));
|
|
26
|
+
}
|
|
27
|
+
const qTokens = tokenize(query);
|
|
28
|
+
if (qTokens.length === 0) {
|
|
29
|
+
// 无查询词 → 按 salience 再新鲜度
|
|
30
|
+
return cand
|
|
31
|
+
.slice()
|
|
32
|
+
.sort((a, b) => b.salience - a.salience || b.updated.localeCompare(a.updated))
|
|
33
|
+
.slice(0, limit)
|
|
34
|
+
.map((entry) => ({ entry, score: 0 }));
|
|
35
|
+
}
|
|
36
|
+
const N = cand.length;
|
|
37
|
+
const docs = cand.map((e) => tokenize(`${e.title} ${e.tags.join(' ')} ${e.body}`));
|
|
38
|
+
const avgdl = N ? docs.reduce((s, d) => s + d.length, 0) / N : 0;
|
|
39
|
+
const df = new Map();
|
|
40
|
+
for (const d of docs)
|
|
41
|
+
for (const t of new Set(d))
|
|
42
|
+
df.set(t, (df.get(t) ?? 0) + 1);
|
|
43
|
+
const hits = cand.map((entry, i) => {
|
|
44
|
+
const d = docs[i];
|
|
45
|
+
const dl = d.length;
|
|
46
|
+
const tf = new Map();
|
|
47
|
+
for (const t of d)
|
|
48
|
+
tf.set(t, (tf.get(t) ?? 0) + 1);
|
|
49
|
+
let bm = 0;
|
|
50
|
+
for (const t of qTokens) {
|
|
51
|
+
const f = tf.get(t) ?? 0;
|
|
52
|
+
if (!f)
|
|
53
|
+
continue;
|
|
54
|
+
const n = df.get(t) ?? 0;
|
|
55
|
+
const idf = Math.log(1 + (N - n + 0.5) / (n + 0.5));
|
|
56
|
+
bm += idf * ((f * (K1 + 1)) / (f + K1 * (1 - B + (B * dl) / (avgdl || 1))));
|
|
57
|
+
}
|
|
58
|
+
return { entry, score: bm * (0.8 + 0.1 * entry.salience) };
|
|
59
|
+
});
|
|
60
|
+
return hits
|
|
61
|
+
.filter((h) => h.score > 0)
|
|
62
|
+
.sort((a, b) => b.score - a.score)
|
|
63
|
+
.slice(0, limit);
|
|
64
|
+
}
|
|
65
|
+
/** 跨多个作用域检索(如 worker = project + global)。 */
|
|
66
|
+
export function recall(refs, query, opts = {}) {
|
|
67
|
+
const all = refs.flatMap((r) => listEntries(r));
|
|
68
|
+
return searchEntries(all, query, opts);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=retrieve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retrieve.js","sourceRoot":"","sources":["../../../src/core/memory2/retrieve.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAYzC,8BAA8B;AAC9B,MAAM,UAAU,QAAQ,CAAC,CAAS;IAChC,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAC9C,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACxC,OAAO,CAAC,GAAG,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,EAAE,GAAG,GAAG,CAAC;AACf,MAAM,CAAC,GAAG,IAAI,CAAC;AAEf,kEAAkE;AAClE,MAAM,UAAU,aAAa,CAAC,OAAsB,EAAE,KAAa,EAAE,OAAmB,EAAE;IACxF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;IAE9B,IAAI,IAAI,GAAG,OAAO,CAAC;IACnB,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC5D,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,yBAAyB;QACzB,OAAO,IAAI;aACR,KAAK,EAAE;aACP,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;aAC7E,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;aACf,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IACtB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,MAAM,EAAE,GAAG,IAAI,GAAG,EAAkB,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,KAAK,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;YAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAElF,MAAM,IAAI,GAAgB,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC9C,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACnB,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC;QACpB,MAAM,EAAE,GAAG,IAAI,GAAG,EAAkB,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,CAAC;YAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACnD,IAAI,EAAE,GAAG,CAAC,CAAC;QACX,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACzB,IAAI,CAAC,CAAC;gBAAE,SAAS;YACjB,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACzB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YACpD,EAAE,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9E,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI;SACR,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;SAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;SACjC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACrB,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,MAAM,CAAC,IAAgB,EAAE,KAAa,EAAE,OAAmB,EAAE;IAC3E,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,OAAO,aAAa,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type MemoryEntry, type SaveInput, type ScopeRef } from './types.js';
|
|
2
|
+
/** 记忆根目录。`SPS_MEMORY_ROOT` 可覆盖(测试用),否则 ~/.coral/memory。 */
|
|
3
|
+
export declare function memoryRoot(): string;
|
|
4
|
+
/** 某作用域的存储目录。project/agent 缺参数会抛(调用方保证)。 */
|
|
5
|
+
export declare function scopeDir(ref: ScopeRef): string;
|
|
6
|
+
/** 生成裸 id:m-<10 hex>。 */
|
|
7
|
+
export declare function newMemoryId(): string;
|
|
8
|
+
/**
|
|
9
|
+
* 保存:无 id → 新建(分配 id + created);有 id → 更新(保 created,刷 updated)。原子落盘。
|
|
10
|
+
* 写入前必过脱敏(§5.1,默认开):打码敏感片段;命中高危 → 抛 RedactedEntryDropped(调用方提示丢弃)。
|
|
11
|
+
*/
|
|
12
|
+
export declare function saveEntry(ref: ScopeRef, input: SaveInput): MemoryEntry;
|
|
13
|
+
/** 读一条;不存在 / 已 tombstone 返回 null。 */
|
|
14
|
+
export declare function readEntry(ref: ScopeRef, id: string): MemoryEntry | null;
|
|
15
|
+
/** 列该作用域全部 entry(跳过 tombstone;坏文件跳过)。 */
|
|
16
|
+
export declare function listEntries(ref: ScopeRef): MemoryEntry[];
|
|
17
|
+
/** 软删:`<id>.md` → `<id>.md.deleted`(tombstone);list/reindex 不再见到。返回是否删了。 */
|
|
18
|
+
export declare function deleteEntry(ref: ScopeRef, id: string): boolean;
|
|
19
|
+
/** 枚举 store 里所有存在的作用域(global + 每个 project + 每个 agent),供跨搜/gc 遍历。 */
|
|
20
|
+
export declare function listAllScopes(): ScopeRef[];
|
|
21
|
+
/**
|
|
22
|
+
* 提升/搬移一条记忆到另一作用域(设计 §2,仅手动)。读源 → 以新 id 写入目标(经 saveEntry 过脱敏,
|
|
23
|
+
* 命中高危会抛 RedactedEntryDropped)→ move 时软删源。返回落到目标的新 entry;源不存在返回 null。
|
|
24
|
+
*/
|
|
25
|
+
export declare function promoteEntry(from: ScopeRef, id: string, to: ScopeRef, opts?: {
|
|
26
|
+
move?: boolean;
|
|
27
|
+
}): MemoryEntry | null;
|
|
28
|
+
/** 硬删所有 tombstone(gc 用)。返回清理数。 */
|
|
29
|
+
export declare function purgeTombstones(ref: ScopeRef): number;
|
|
30
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/core/memory2/store.ts"],"names":[],"mappings":"AAeA,OAAO,EAIL,KAAK,WAAW,EAEhB,KAAK,SAAS,EACd,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAEpB,2DAA2D;AAC3D,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,4CAA4C;AAC5C,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,CAY9C;AAUD,yBAAyB;AACzB,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AA6DD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,GAAG,WAAW,CAoBtE;AAED,qCAAqC;AACrC,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAQvE;AAED,yCAAyC;AACzC,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,GAAG,WAAW,EAAE,CAcxD;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAK9D;AAED,oEAAoE;AACpE,wBAAgB,aAAa,IAAI,QAAQ,EAAE,CAa1C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,WAAW,GAAG,IAAI,CASxH;AAED,kCAAkC;AAClC,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,CAWrD"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/memory2/store
|
|
3
|
+
* @description 本地记忆 v2 存储核心:entry 的 CRUD + 原子落盘 + id 分配 + 作用域路径。
|
|
4
|
+
* markdown 是唯一真源;frontmatter 走健壮的 flatfile/frontmatter(修旧系统 C4)。
|
|
5
|
+
* 无冲突并发:一条一 `<id>.md`(randomUUID)+ temp 写 + rename(见 §6)。
|
|
6
|
+
* 删除 = 软 tombstone(`<id>.md.deleted`),list/reindex 只认 `.md`;gc 再硬删。
|
|
7
|
+
* @layer core
|
|
8
|
+
* @boundedContext memory
|
|
9
|
+
*/
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
import { join, resolve } from 'node:path';
|
|
14
|
+
import { joinFrontmatter, parseFrontmatter } from '../flatfile/frontmatter.js';
|
|
15
|
+
import { redactEntry, RedactedEntryDropped } from './redact.js';
|
|
16
|
+
import { MEMORY_CATEGORIES, MEMORY_SOURCES, } from './types.js';
|
|
17
|
+
/** 记忆根目录。`SPS_MEMORY_ROOT` 可覆盖(测试用),否则 ~/.coral/memory。 */
|
|
18
|
+
export function memoryRoot() {
|
|
19
|
+
return process.env.SPS_MEMORY_ROOT || resolve(homedir(), '.coral', 'memory');
|
|
20
|
+
}
|
|
21
|
+
/** 某作用域的存储目录。project/agent 缺参数会抛(调用方保证)。 */
|
|
22
|
+
export function scopeDir(ref) {
|
|
23
|
+
const root = memoryRoot();
|
|
24
|
+
switch (ref.scope) {
|
|
25
|
+
case 'global':
|
|
26
|
+
return join(root, 'global');
|
|
27
|
+
case 'project':
|
|
28
|
+
if (!ref.project)
|
|
29
|
+
throw new Error('project scope requires project name');
|
|
30
|
+
return join(root, 'projects', ref.project);
|
|
31
|
+
case 'agent':
|
|
32
|
+
if (!ref.agentId)
|
|
33
|
+
throw new Error('agent scope requires agentId');
|
|
34
|
+
return join(root, 'agents', ref.agentId);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function entriesDir(ref) {
|
|
38
|
+
return join(scopeDir(ref), 'entries');
|
|
39
|
+
}
|
|
40
|
+
function entryPath(ref, id) {
|
|
41
|
+
return join(entriesDir(ref), `${id}.md`);
|
|
42
|
+
}
|
|
43
|
+
/** 生成裸 id:m-<10 hex>。 */
|
|
44
|
+
export function newMemoryId() {
|
|
45
|
+
return `m-${randomUUID().replace(/-/g, '').slice(0, 10)}`;
|
|
46
|
+
}
|
|
47
|
+
/** 原子写文件:写 tmp 再 rename(POSIX 原子);跨写者不冲突(不同 id 不同文件)。 */
|
|
48
|
+
function atomicWrite(path, content) {
|
|
49
|
+
mkdirSync(join(path, '..'), { recursive: true });
|
|
50
|
+
const tmp = `${path}.tmp-${randomUUID().slice(0, 8)}`;
|
|
51
|
+
writeFileSync(tmp, content);
|
|
52
|
+
renameSync(tmp, path);
|
|
53
|
+
}
|
|
54
|
+
function coerceCategory(v) {
|
|
55
|
+
return MEMORY_CATEGORIES.includes(v) ? v : 'note';
|
|
56
|
+
}
|
|
57
|
+
function coerceSource(v) {
|
|
58
|
+
return MEMORY_SOURCES.includes(v) ? v : 'agent';
|
|
59
|
+
}
|
|
60
|
+
function coerceTags(v) {
|
|
61
|
+
if (Array.isArray(v))
|
|
62
|
+
return v.map((t) => String(t)).filter(Boolean);
|
|
63
|
+
if (typeof v === 'string' && v.trim())
|
|
64
|
+
return v.split(',').map((t) => t.trim()).filter(Boolean);
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
function coerceSalience(v) {
|
|
68
|
+
const n = Number(v);
|
|
69
|
+
return Number.isFinite(n) ? Math.min(5, Math.max(1, Math.round(n))) : 3;
|
|
70
|
+
}
|
|
71
|
+
/** 序列化 entry → markdown(frontmatter + 正文)。 */
|
|
72
|
+
function serialize(e) {
|
|
73
|
+
const data = {
|
|
74
|
+
id: e.id,
|
|
75
|
+
title: e.title,
|
|
76
|
+
scope: e.scope,
|
|
77
|
+
category: e.category,
|
|
78
|
+
tags: e.tags,
|
|
79
|
+
salience: e.salience,
|
|
80
|
+
source: e.source,
|
|
81
|
+
...(e.project ? { project: e.project } : {}),
|
|
82
|
+
created: e.created,
|
|
83
|
+
updated: e.updated,
|
|
84
|
+
};
|
|
85
|
+
return joinFrontmatter(data, e.body.endsWith('\n') ? e.body : `${e.body}\n`);
|
|
86
|
+
}
|
|
87
|
+
/** 反序列化 markdown → entry(缺字段给默认;坏 frontmatter 不阻塞)。 */
|
|
88
|
+
function deserialize(scope, id, md) {
|
|
89
|
+
const { data, body } = parseFrontmatter(md);
|
|
90
|
+
return {
|
|
91
|
+
id: typeof data.id === 'string' ? data.id : id,
|
|
92
|
+
title: typeof data.title === 'string' ? data.title : id,
|
|
93
|
+
scope: data.scope ?? scope,
|
|
94
|
+
category: coerceCategory(data.category),
|
|
95
|
+
tags: coerceTags(data.tags),
|
|
96
|
+
salience: coerceSalience(data.salience),
|
|
97
|
+
source: coerceSource(data.source),
|
|
98
|
+
project: typeof data.project === 'string' ? data.project : undefined,
|
|
99
|
+
created: typeof data.created === 'string' ? data.created : new Date().toISOString(),
|
|
100
|
+
updated: typeof data.updated === 'string' ? data.updated : new Date().toISOString(),
|
|
101
|
+
body: body.trim(),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 保存:无 id → 新建(分配 id + created);有 id → 更新(保 created,刷 updated)。原子落盘。
|
|
106
|
+
* 写入前必过脱敏(§5.1,默认开):打码敏感片段;命中高危 → 抛 RedactedEntryDropped(调用方提示丢弃)。
|
|
107
|
+
*/
|
|
108
|
+
export function saveEntry(ref, input) {
|
|
109
|
+
const now = new Date().toISOString();
|
|
110
|
+
const red = redactEntry(input.title, input.body);
|
|
111
|
+
if (red.dropped)
|
|
112
|
+
throw new RedactedEntryDropped(red.reasons);
|
|
113
|
+
const existing = input.id ? readEntry(ref, input.id) : null;
|
|
114
|
+
const entry = {
|
|
115
|
+
id: input.id ?? newMemoryId(),
|
|
116
|
+
title: red.title,
|
|
117
|
+
scope: ref.scope,
|
|
118
|
+
category: input.category ?? existing?.category ?? 'note',
|
|
119
|
+
tags: input.tags ?? existing?.tags ?? [],
|
|
120
|
+
salience: input.salience ?? existing?.salience ?? 3,
|
|
121
|
+
source: input.source ?? existing?.source ?? 'agent',
|
|
122
|
+
project: input.project ?? existing?.project ?? (ref.scope === 'project' ? ref.project : ref.scope === 'agent' ? ref.agentId : undefined),
|
|
123
|
+
created: existing?.created ?? now,
|
|
124
|
+
updated: now,
|
|
125
|
+
body: red.body,
|
|
126
|
+
};
|
|
127
|
+
atomicWrite(entryPath(ref, entry.id), serialize(entry));
|
|
128
|
+
return entry;
|
|
129
|
+
}
|
|
130
|
+
/** 读一条;不存在 / 已 tombstone 返回 null。 */
|
|
131
|
+
export function readEntry(ref, id) {
|
|
132
|
+
const p = entryPath(ref, id);
|
|
133
|
+
if (!existsSync(p))
|
|
134
|
+
return null;
|
|
135
|
+
try {
|
|
136
|
+
return deserialize(ref.scope, id, readFileSync(p, 'utf-8'));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** 列该作用域全部 entry(跳过 tombstone;坏文件跳过)。 */
|
|
143
|
+
export function listEntries(ref) {
|
|
144
|
+
const dir = entriesDir(ref);
|
|
145
|
+
if (!existsSync(dir))
|
|
146
|
+
return [];
|
|
147
|
+
const out = [];
|
|
148
|
+
for (const name of readdirSync(dir)) {
|
|
149
|
+
if (!name.endsWith('.md'))
|
|
150
|
+
continue; // .md.deleted / .tmp-* 天然跳过
|
|
151
|
+
const id = name.slice(0, -3);
|
|
152
|
+
try {
|
|
153
|
+
out.push(deserialize(ref.scope, id, readFileSync(join(dir, name), 'utf-8')));
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
/* 坏文件跳过 */
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
/** 软删:`<id>.md` → `<id>.md.deleted`(tombstone);list/reindex 不再见到。返回是否删了。 */
|
|
162
|
+
export function deleteEntry(ref, id) {
|
|
163
|
+
const p = entryPath(ref, id);
|
|
164
|
+
if (!existsSync(p))
|
|
165
|
+
return false;
|
|
166
|
+
renameSync(p, `${p}.deleted`);
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
/** 枚举 store 里所有存在的作用域(global + 每个 project + 每个 agent),供跨搜/gc 遍历。 */
|
|
170
|
+
export function listAllScopes() {
|
|
171
|
+
const root = memoryRoot();
|
|
172
|
+
const refs = [];
|
|
173
|
+
if (existsSync(join(root, 'global')))
|
|
174
|
+
refs.push({ scope: 'global' });
|
|
175
|
+
const projectsDir = join(root, 'projects');
|
|
176
|
+
if (existsSync(projectsDir)) {
|
|
177
|
+
for (const p of readdirSync(projectsDir))
|
|
178
|
+
refs.push({ scope: 'project', project: p });
|
|
179
|
+
}
|
|
180
|
+
const agentsDir = join(root, 'agents');
|
|
181
|
+
if (existsSync(agentsDir)) {
|
|
182
|
+
for (const a of readdirSync(agentsDir))
|
|
183
|
+
refs.push({ scope: 'agent', agentId: a });
|
|
184
|
+
}
|
|
185
|
+
return refs;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* 提升/搬移一条记忆到另一作用域(设计 §2,仅手动)。读源 → 以新 id 写入目标(经 saveEntry 过脱敏,
|
|
189
|
+
* 命中高危会抛 RedactedEntryDropped)→ move 时软删源。返回落到目标的新 entry;源不存在返回 null。
|
|
190
|
+
*/
|
|
191
|
+
export function promoteEntry(from, id, to, opts = {}) {
|
|
192
|
+
const src = readEntry(from, id);
|
|
193
|
+
if (!src)
|
|
194
|
+
return null;
|
|
195
|
+
const saved = saveEntry(to, {
|
|
196
|
+
title: src.title, body: src.body, category: src.category, tags: src.tags,
|
|
197
|
+
salience: src.salience, source: src.source,
|
|
198
|
+
});
|
|
199
|
+
if (opts.move)
|
|
200
|
+
deleteEntry(from, id);
|
|
201
|
+
return saved;
|
|
202
|
+
}
|
|
203
|
+
/** 硬删所有 tombstone(gc 用)。返回清理数。 */
|
|
204
|
+
export function purgeTombstones(ref) {
|
|
205
|
+
const dir = entriesDir(ref);
|
|
206
|
+
if (!existsSync(dir))
|
|
207
|
+
return 0;
|
|
208
|
+
let n = 0;
|
|
209
|
+
for (const name of readdirSync(dir)) {
|
|
210
|
+
if (name.endsWith('.md.deleted')) {
|
|
211
|
+
rmSync(join(dir, name));
|
|
212
|
+
n++;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return n;
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/core/memory2/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/memory2/types
|
|
3
|
+
* @description 本地记忆系统 v2 的数据模型。设计:docs/design/memory-v2.md §1。
|
|
4
|
+
* markdown(entry)是唯一真源;这里只定义条目/作用域的类型。
|
|
5
|
+
* @layer core
|
|
6
|
+
* @boundedContext memory
|
|
7
|
+
*/
|
|
8
|
+
/** 作用域:global 跨项目 / project 单项目 / agent(harness 会话)。 */
|
|
9
|
+
export type MemoryScope = 'global' | 'project' | 'agent';
|
|
10
|
+
/** 类别(旧 type 降级为此)。note = 自动捕获的一般笔记的兜底类。 */
|
|
11
|
+
export declare const MEMORY_CATEGORIES: readonly ["convention", "decision", "gotcha", "pattern", "reference", "note"];
|
|
12
|
+
export type MemoryCategory = (typeof MEMORY_CATEGORIES)[number];
|
|
13
|
+
/** 出处:agent 主动写 / capture 自动捕获 / human 人(CLI/Console)。 */
|
|
14
|
+
export declare const MEMORY_SOURCES: readonly ["agent", "capture", "human"];
|
|
15
|
+
export type MemorySource = (typeof MEMORY_SOURCES)[number];
|
|
16
|
+
/** 一条记忆(= 一个 `<id>.md`,frontmatter + 正文)。 */
|
|
17
|
+
export interface MemoryEntry {
|
|
18
|
+
/** 本地裸 id(如 m-3f9a2f8b1c);工具/服务层再加 `local:` 前缀。 */
|
|
19
|
+
id: string;
|
|
20
|
+
title: string;
|
|
21
|
+
scope: MemoryScope;
|
|
22
|
+
category: MemoryCategory;
|
|
23
|
+
tags: string[];
|
|
24
|
+
/** 显著度 1..5,驱动 digest 选择与衰减。 */
|
|
25
|
+
salience: number;
|
|
26
|
+
source: MemorySource;
|
|
27
|
+
/** project scope 存项目名;agent scope 存 agentId;global 存来源项目(提升时)。 */
|
|
28
|
+
project?: string;
|
|
29
|
+
/** ISO 时间。 */
|
|
30
|
+
created: string;
|
|
31
|
+
updated: string;
|
|
32
|
+
body: string;
|
|
33
|
+
}
|
|
34
|
+
/** 定位一个作用域的存储目录。 */
|
|
35
|
+
export interface ScopeRef {
|
|
36
|
+
scope: MemoryScope;
|
|
37
|
+
/** scope=project 时必填。 */
|
|
38
|
+
project?: string;
|
|
39
|
+
/** scope=agent 时必填。 */
|
|
40
|
+
agentId?: string;
|
|
41
|
+
}
|
|
42
|
+
/** 保存入参:不带 id/时间戳 = 新建;带 id = 更新。 */
|
|
43
|
+
export interface SaveInput {
|
|
44
|
+
id?: string;
|
|
45
|
+
title: string;
|
|
46
|
+
body: string;
|
|
47
|
+
category?: MemoryCategory;
|
|
48
|
+
tags?: string[];
|
|
49
|
+
salience?: number;
|
|
50
|
+
source?: MemorySource;
|
|
51
|
+
project?: string;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/memory2/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,wDAAwD;AACxD,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAEzD,4CAA4C;AAC5C,eAAO,MAAM,iBAAiB,+EAAgF,CAAC;AAC/G,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,0DAA0D;AAC1D,eAAO,MAAM,cAAc,wCAAyC,CAAC;AACrE,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,6CAA6C;AAC7C,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,EAAE,cAAc,CAAC;IACzB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;IACrB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oBAAoB;AACpB,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,WAAW,CAAC;IACnB,yBAAyB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qCAAqC;AACrC,MAAM,WAAW,SAAS;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/memory2/types
|
|
3
|
+
* @description 本地记忆系统 v2 的数据模型。设计:docs/design/memory-v2.md §1。
|
|
4
|
+
* markdown(entry)是唯一真源;这里只定义条目/作用域的类型。
|
|
5
|
+
* @layer core
|
|
6
|
+
* @boundedContext memory
|
|
7
|
+
*/
|
|
8
|
+
/** 类别(旧 type 降级为此)。note = 自动捕获的一般笔记的兜底类。 */
|
|
9
|
+
export const MEMORY_CATEGORIES = ['convention', 'decision', 'gotcha', 'pattern', 'reference', 'note'];
|
|
10
|
+
/** 出处:agent 主动写 / capture 自动捕获 / human 人(CLI/Console)。 */
|
|
11
|
+
export const MEMORY_SOURCES = ['agent', 'capture', 'human'];
|
|
12
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/memory2/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,4CAA4C;AAC5C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,CAAU,CAAC;AAG/G,0DAA0D;AAC1D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAU,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StageEngine.d.ts","sourceRoot":"","sources":["../../src/engines/StageEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"StageEngine.d.ts","sourceRoot":"","sources":["../../src/engines/StageEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAIjG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEhE,OAAO,KAAK,EAAmC,aAAa,EAAE,MAAM,8BAA8B,CAAC;AACnG,OAAO,KAAK,EAAsC,aAAa,EAAqB,MAAM,oBAAoB,CAAC;AAe/G;;;;;;;;;GASG;AACH,qBAAa,WAAW;IAKpB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,WAAW;IAEnB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,QAAQ,CAAC;IAZnB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,YAAY,CAAe;gBAGzB,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,eAAe,EACtB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,WAAW,EAChC,YAAY,EAAE,WAAW,EACjB,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,sBAAsB,EACvC,QAAQ,CAAC,EAAE,QAAQ,YAAA;IAM7B,2BAA2B;IAC3B,IAAI,IAAI,IAAI,MAAM,CAA4B;IAE9C,mFAAmF;IACnF,IAAI,YAAY,IAAI,OAAO,CAAkC;IAE7D,iFAAiF;IACjF,IAAI,WAAW,IAAI,OAAO,CAAqD;IAE/E,2DAA2D;IAGrD,IAAI,CAAC,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,aAAa,CAAC;YA0HrD,gBAAgB;YAgChB,kBAAkB;IAgEhC,wEAAwE;IACxE,OAAO,CAAC,cAAc;YAKR,gBAAgB;YA2GhB,kBAAkB;IAkChC;;;OAGG;YACW,cAAc;YAkHd,eAAe;YAmDf,WAAW;YAuBX,YAAY;YAqIZ,2BAA2B;YAe3B,4BAA4B;IA6C1C,OAAO,CAAC,sBAAsB;IA2B9B;;;;;OAKG;IACH,OAAO,CAAC,2BAA2B;IAInC,OAAO,CAAC,gBAAgB;IA6CxB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,UAAU;YAIJ,oBAAoB;IAgBlC;;;;;;;;;OASG;YACW,iBAAiB;IA2E/B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,WAAW;YAWL,mBAAmB;YAyBnB,YAAY;YAQZ,YAAY;YAMZ,WAAW;YAMX,UAAU;IAKxB,OAAO,CAAC,QAAQ;IAYhB;;;OAGG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,aAAa,CAAC;CA6EzF;AAID;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,EAC3B,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAC3B,mBAAmB,EAAE,MAAM,GAAG,SAAS,GACtC,MAAM,EAAE,CAeV;AAED,iDAAiD;AACjD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAE/D"}
|
|
@@ -21,11 +21,12 @@ import { resolve } from 'node:path';
|
|
|
21
21
|
import { jsonlExists } from '../core/claudeJsonl.js';
|
|
22
22
|
import { resolveGitlabProjectId, resolveWorkflowTransport } from '../core/config.js';
|
|
23
23
|
import { Logger } from '../core/logger.js';
|
|
24
|
-
import { buildWorkerMemoryInstructions, resolveMemoryConfig } from '../core/memoryProvider.js';
|
|
25
24
|
import { getPipelineSession, setPipelineSession } from '../core/pipelineSession.js';
|
|
26
25
|
import { RuntimeStore } from '../core/runtimeStore.js';
|
|
27
26
|
import { buildPhasePrompt, buildTaskPrompt } from '../core/taskPrompts.js';
|
|
28
27
|
import { hasGraph, syncGraph } from '../core/codegraph/CodeGraphService.js';
|
|
28
|
+
import { captureFlush } from '../core/memory2/capture.js';
|
|
29
|
+
// 记忆注入(buildWorkerMemoryInstructions / resolveMemoryConfig)已随记忆 v2 重构移除。
|
|
29
30
|
// branchPushed/branchCommitsAhead removed — no worktree/branch management
|
|
30
31
|
const SKIP_LABELS = ['BLOCKED', 'NEEDS-FIX', 'CONFLICT', 'WAITING-CONFIRMATION', 'STALE-RUNTIME'];
|
|
31
32
|
// CLEANUP_LABELS: cleared when a card re-enters a stage (backlog prepare step).
|
|
@@ -440,6 +441,16 @@ export class StageEngine {
|
|
|
440
441
|
this.log.warn(`seq ${seq}: 代码图谱同步失败(忽略,不阻断流水线): ${msg}`);
|
|
441
442
|
}
|
|
442
443
|
}
|
|
444
|
+
// Step 1.6: 记忆自动捕获 flush(记忆 v2 §3 写路终点)——从该卡 buffer 抽结论段 → 去重 → 落 store
|
|
445
|
+
// (source: capture);worker-manager 在 dispatch 前已起订缓冲。失败只告警、不阻断卡片完成。
|
|
446
|
+
try {
|
|
447
|
+
const outcome = captureFlush(this.ctx.projectName, String(seq));
|
|
448
|
+
if ('saved' in outcome)
|
|
449
|
+
this.log.ok(`seq ${seq}: 记忆已捕获 ${outcome.saved.id}`);
|
|
450
|
+
}
|
|
451
|
+
catch (err) {
|
|
452
|
+
this.log.warn(`seq ${seq}: 记忆捕获失败(忽略): ${err instanceof Error ? err.message : String(err)}`);
|
|
453
|
+
}
|
|
443
454
|
// Step 2: Release claim
|
|
444
455
|
try {
|
|
445
456
|
await this.taskBackend.releaseClaim(seq);
|
|
@@ -799,11 +810,7 @@ export class StageEngine {
|
|
|
799
810
|
projectRules = projectRules ? `${projectRules}\n\n${agentsRules}` : agentsRules;
|
|
800
811
|
}
|
|
801
812
|
}
|
|
802
|
-
//
|
|
803
|
-
// 这里只下发「收尾写记忆」的引导,且按后端不同(none → 无;builtin → 文件记忆 CLI;
|
|
804
|
-
// agentmemory/custom → 语义库)。ENABLE_MEMORY=false 兼容旧开关(等同 none)。
|
|
805
|
-
const { provider: memProvider } = resolveMemoryConfig(this.ctx.config.raw);
|
|
806
|
-
const knowledge = buildWorkerMemoryInstructions(this.ctx.projectName, memProvider);
|
|
813
|
+
// 记忆注入已随本地记忆系统 v2 重构移除(见 docs/design/memory-v2.md);v2 会在派卡时重新注入。
|
|
807
814
|
const promptCtx = {
|
|
808
815
|
taskSeq: card.seq,
|
|
809
816
|
taskTitle: card.title,
|
|
@@ -816,7 +823,6 @@ export class StageEngine {
|
|
|
816
823
|
gitlabProjectId: resolveGitlabProjectId(this.ctx.config),
|
|
817
824
|
skillContent,
|
|
818
825
|
projectRules: projectRules || undefined,
|
|
819
|
-
knowledge,
|
|
820
826
|
// v0.50.18:COMPLETION_SIGNAL env 覆盖默认 "done"
|
|
821
827
|
completionSignal: this.ctx.config.raw.COMPLETION_SIGNAL || undefined,
|
|
822
828
|
};
|
|
@@ -836,7 +842,6 @@ export class StageEngine {
|
|
|
836
842
|
this.log.ok(`Skills: ${skills.join(', ')}`);
|
|
837
843
|
return formatSkillRequirement(skills);
|
|
838
844
|
}
|
|
839
|
-
// loadProjectKnowledge removed — replaced by memory system (buildMemoryContext)
|
|
840
845
|
// ─── Worktree cleanup (last stage only) ────────────────────────
|
|
841
846
|
// ─── Common helpers ────────────────────────────────────────────
|
|
842
847
|
shouldSkip(card) {
|