agent-trellis 0.19.0 → 0.21.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/dist/adapters/claude-code.js +2 -2
- package/dist/adapters/codex.js +3 -3
- package/dist/adapters/jsonMcp.d.ts +1 -1
- package/dist/adapters/jsonMcp.js +2 -2
- package/dist/adapters/kimi-code.js +2 -2
- package/dist/adapters/kiro.js +11 -9
- package/dist/adapters/mcpPlan.d.ts +1 -1
- package/dist/adapters/mcpPlan.js +35 -12
- package/dist/adapters/pi.js +5 -5
- package/dist/adapters/zcode.d.ts +1 -1
- package/dist/adapters/zcode.js +6 -6
- package/dist/cli.js +12 -1
- package/dist/commands/doctor.d.ts +9 -1
- package/dist/commands/doctor.js +92 -7
- package/dist/commands/evolve.d.ts +43 -0
- package/dist/commands/evolve.js +479 -0
- package/dist/commands/mcp.js +1 -1
- package/dist/commands/mcpAuth.js +1 -1
- package/dist/commands/mcpGateway.d.ts +30 -2
- package/dist/commands/mcpGateway.js +44 -10
- package/dist/commands/mcpImport.js +2 -1
- package/dist/commands/secretsAudit.d.ts +1 -1
- package/dist/commands/secretsAudit.js +36 -13
- package/dist/evolve/agentView.d.ts +32 -0
- package/dist/evolve/agentView.js +34 -0
- package/dist/evolve/apply.d.ts +71 -0
- package/dist/evolve/apply.js +162 -0
- package/dist/evolve/archive.d.ts +23 -0
- package/dist/evolve/archive.js +58 -0
- package/dist/evolve/erase.d.ts +17 -0
- package/dist/evolve/erase.js +65 -0
- package/dist/evolve/extension.d.ts +37 -0
- package/dist/evolve/extension.js +63 -0
- package/dist/evolve/gate.d.ts +95 -0
- package/dist/evolve/gate.js +295 -0
- package/dist/evolve/importHistory.d.ts +91 -0
- package/dist/evolve/importHistory.js +239 -0
- package/dist/evolve/jobMain.d.ts +22 -0
- package/dist/evolve/jobMain.js +52 -0
- package/dist/evolve/jobRun.d.ts +94 -0
- package/dist/evolve/jobRun.js +273 -0
- package/dist/evolve/jobShell.d.ts +46 -0
- package/dist/evolve/jobShell.js +75 -0
- package/dist/evolve/l2.d.ts +93 -0
- package/dist/evolve/l2.js +81 -0
- package/dist/evolve/lesson.d.ts +57 -0
- package/dist/evolve/lesson.js +97 -0
- package/dist/evolve/pending.d.ts +69 -0
- package/dist/evolve/pending.js +116 -0
- package/dist/evolve/probeWorkspace.d.ts +57 -0
- package/dist/evolve/probeWorkspace.js +69 -0
- package/dist/evolve/propose.d.ts +73 -0
- package/dist/evolve/propose.js +136 -0
- package/dist/evolve/recorder.d.ts +68 -0
- package/dist/evolve/recorder.js +169 -0
- package/dist/evolve/report.d.ts +26 -0
- package/dist/evolve/report.js +37 -0
- package/dist/evolve/reportView.d.ts +96 -0
- package/dist/evolve/reportView.js +311 -0
- package/dist/evolve/risk.d.ts +106 -0
- package/dist/evolve/risk.js +224 -0
- package/dist/evolve/sources.d.ts +19 -0
- package/dist/evolve/sources.js +29 -0
- package/dist/evolve/stateDir.d.ts +21 -0
- package/dist/evolve/stateDir.js +56 -0
- package/dist/evolve/surface.d.ts +34 -0
- package/dist/evolve/surface.js +72 -0
- package/dist/evolve/trajectory.d.ts +25 -0
- package/dist/evolve/trajectory.js +88 -0
- package/dist/evolve/treeToCanonical.d.ts +28 -0
- package/dist/evolve/treeToCanonical.js +79 -0
- package/dist/evolve/trellisSubstrate.d.ts +65 -0
- package/dist/evolve/trellisSubstrate.js +154 -0
- package/dist/evolve/trigger.d.ts +177 -0
- package/dist/evolve/trigger.js +400 -0
- package/dist/evolve/types.d.ts +126 -0
- package/dist/evolve/types.js +15 -0
- package/dist/evolve/validate.d.ts +139 -0
- package/dist/evolve/validate.js +315 -0
- package/dist/host/checks.d.ts +57 -0
- package/dist/host/checks.js +126 -0
- package/dist/host/delivery.d.ts +42 -0
- package/dist/host/delivery.js +59 -0
- package/dist/host/edits.d.ts +87 -0
- package/dist/host/edits.js +102 -0
- package/dist/host/hostEvents.d.ts +74 -0
- package/dist/host/hostEvents.js +45 -0
- package/dist/host/index.d.ts +22 -0
- package/dist/host/index.js +17 -0
- package/dist/host/levels.d.ts +106 -0
- package/dist/host/levels.js +206 -0
- package/dist/host/staging.d.ts +56 -0
- package/dist/host/staging.js +106 -0
- package/dist/host/surface.d.ts +36 -0
- package/dist/host/surface.js +20 -0
- package/dist/lib/backup.js +12 -3
- package/dist/lib/envVarNames.js +7 -0
- package/dist/lib/fsAtomic.d.ts +7 -0
- package/dist/lib/fsAtomic.js +14 -0
- package/dist/lib/hostEventBus.d.ts +47 -0
- package/dist/lib/hostEventBus.js +94 -0
- package/dist/lib/hostExtensions.d.ts +75 -0
- package/dist/lib/hostExtensions.js +196 -0
- package/dist/lib/mcpConnect.d.ts +1 -1
- package/dist/lib/mcpConnect.js +19 -8
- package/dist/lib/mcpMigrateRead.js +14 -2
- package/dist/lib/mcpRuntime.d.ts +12 -1
- package/dist/lib/mcpRuntime.js +34 -2
- package/dist/lib/mcpToolRegistry.d.ts +18 -2
- package/dist/lib/mcpToolRegistry.js +29 -9
- package/dist/lib/secretEnv.d.ts +53 -8
- package/dist/lib/secretEnv.js +78 -15
- package/dist/lib/tomlSection.js +3 -2
- package/dist/lib/workspaceDoctor.d.ts +1 -1
- package/dist/lib/workspaceDoctor.js +8 -4
- package/dist/lib/workspaceMcp.d.ts +1 -1
- package/dist/lib/workspaceMcp.js +5 -5
- package/dist/pi-bridge/bundle.js +42236 -2701
- package/dist/pi-bridge/index.js +2 -2
- package/docs/magpie-gateway-research.md +422 -0
- package/docs/research.md +4 -1
- package/docs/roadmap.md +22 -12
- package/docs/runtime-infra.md +41 -22
- package/docs/self-evolution.md +138 -44
- package/package.json +8 -2
- package/schema/secrets.policy.example.yaml +5 -0
- package/schema/servers.example.yaml +5 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gateway 进程内信号 recorder(trellis-evolve 任务 11.1)。
|
|
3
|
+
*
|
|
4
|
+
* 订阅托管事件总线(8.3),把事件元数据写入信号存储:
|
|
5
|
+
* - 字段白名单:事件对象本身只有 metadata(8.2 类型层强制),写入侧
|
|
6
|
+
* 再按 Signal 信封逐字段拷贝,载荷载体永远不入库;
|
|
7
|
+
* - secrets 擦除:所有字符串字段写入前经 eraseSecrets;
|
|
8
|
+
* - 层归属:session_start 事件的 workspaceRoot 派生——该会话内全部
|
|
9
|
+
* 信号归属该 workspace 层,无归属记全局层;
|
|
10
|
+
* - 按进程分文件、只追加:每个 gateway 进程一个
|
|
11
|
+
* `signals/<pid>-<startMs>.jsonl`,进程内并发会话写同一文件
|
|
12
|
+
* (单次 append 合并当轮缓冲,逐行 JSON),跨进程各写各文件,无全局锁;
|
|
13
|
+
* - 异步落盘(review-fixes ❌4):`handle` 只入内存队列,事件循环内
|
|
14
|
+
* 批量落盘,热路径(工具调用事件)不碰磁盘;会话边界事件
|
|
15
|
+
* (session_start/session_end)同步收口——边界事件正是触发判定的
|
|
16
|
+
* 运行点(补偿判定/会话结束判定),判定必须看得到含当前边界事件
|
|
17
|
+
* 在内的全部已记录信号;`flush()` 供测试与收尾。信号非审计级
|
|
18
|
+
* (读取侧坏行容错同源),崩溃丢当轮缓冲可接受;
|
|
19
|
+
* - off 零副作用:`enabled()` 为 false 时连目录与文件都不创建。
|
|
20
|
+
*/
|
|
21
|
+
import type { HostEvent } from "../host/hostEvents.js";
|
|
22
|
+
import type { Signal } from "./types.js";
|
|
23
|
+
export interface SignalRecorderOptions {
|
|
24
|
+
homeDir: string;
|
|
25
|
+
/** 级别开关(off 或 workspace 覆盖为 off 时返回 false)。缺省恒开。 */
|
|
26
|
+
enabled?: () => boolean;
|
|
27
|
+
/** 采集时间源(测试注入固定时钟);缺省 Date.now。 */
|
|
28
|
+
now?: () => number;
|
|
29
|
+
}
|
|
30
|
+
export interface SignalRecorder {
|
|
31
|
+
/** 本进程的信号文件路径(首写前文件不存在)。 */
|
|
32
|
+
readonly filePath: string;
|
|
33
|
+
/** 事件总线订阅者形态;返回值忽略(写入为队列化批量落盘)。 */
|
|
34
|
+
handle(event: HostEvent): void;
|
|
35
|
+
/** 立即落盘当轮缓冲(测试与收尾用;平时 setImmediate 批量落盘)。 */
|
|
36
|
+
flush(): void;
|
|
37
|
+
}
|
|
38
|
+
/** 进化自身活动的 agent 标识(作业/探针会话以此自称)。 */
|
|
39
|
+
export declare const EVOLVE_SELF_AGENT = "trellis-evolve";
|
|
40
|
+
/** 进化自身活动的会话标识前缀(11.5 的作业会话命名约定)。 */
|
|
41
|
+
export declare const EVOLVE_SELF_SESSION_PREFIX = "evolve-job-";
|
|
42
|
+
/** 防自激(11.3):进化系统自身的调用/编辑不进信号——否则作业会把自己
|
|
43
|
+
* 的活动记成信号、再触发下一轮作业。识别靠自身标识约定;编辑面本身不经
|
|
44
|
+
* 事件总线,结构上就不产生信号。 */
|
|
45
|
+
export declare function isEvolveSelfActivity(event: HostEvent): boolean;
|
|
46
|
+
export declare function createSignalRecorder(options: SignalRecorderOptions): SignalRecorder;
|
|
47
|
+
/** 本进程的信号文件路径(按进程分文件;首写前文件不存在)。 */
|
|
48
|
+
export declare function signalFilePath(homeDir: string, startMs: number): string;
|
|
49
|
+
/** 只追加一行信号(单行 JSON;JSON.stringify 转义字符串内换行,行边界
|
|
50
|
+
* 天然成立;新建文件 0600——信号含 workspace 路径等机器信息,不收世界
|
|
51
|
+
* 可读)。11.2 的用户纠正上报走本单行入口;recorder 经批量入口
|
|
52
|
+
* `appendSignalLines`(同一写入路径)。 */
|
|
53
|
+
export declare function appendSignalLine(filePath: string, signal: Signal): void;
|
|
54
|
+
/** 批量只追加(同一 turn 的信号合并为一次 append;recorder 异步落盘用)。 */
|
|
55
|
+
export declare function appendSignalLines(filePath: string, signals: readonly Signal[]): void;
|
|
56
|
+
/**
|
|
57
|
+
* 读回一个信号文件的全部记录(测试与作业评估用;文件不存在返回空)。
|
|
58
|
+
* 容错:崩溃撕行(最后一次 append 只写了一部分)跳过该行继续——信号
|
|
59
|
+
* 不是审计级数据(对照 archive 的严格带行号抛错),一行损坏不应瘫痪
|
|
60
|
+
* 触发器/作业整条链。
|
|
61
|
+
*/
|
|
62
|
+
export declare function readSignals(filePath: string): Signal[];
|
|
63
|
+
/**
|
|
64
|
+
* 合并读回全部进程信号文件里 `collectedAt > sinceMs`(null = 全部)的
|
|
65
|
+
* 记录(11.5 作业评估用;与 `trigger` 的 countPendingSignals 同一目录
|
|
66
|
+
* 遍历约定)。读取零副作用:不建目录、不排序语义(按文件名+行序)。
|
|
67
|
+
*/
|
|
68
|
+
export declare function readAllSignals(homeDir: string, sinceMs: number | null): Signal[];
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gateway 进程内信号 recorder(trellis-evolve 任务 11.1)。
|
|
3
|
+
*
|
|
4
|
+
* 订阅托管事件总线(8.3),把事件元数据写入信号存储:
|
|
5
|
+
* - 字段白名单:事件对象本身只有 metadata(8.2 类型层强制),写入侧
|
|
6
|
+
* 再按 Signal 信封逐字段拷贝,载荷载体永远不入库;
|
|
7
|
+
* - secrets 擦除:所有字符串字段写入前经 eraseSecrets;
|
|
8
|
+
* - 层归属:session_start 事件的 workspaceRoot 派生——该会话内全部
|
|
9
|
+
* 信号归属该 workspace 层,无归属记全局层;
|
|
10
|
+
* - 按进程分文件、只追加:每个 gateway 进程一个
|
|
11
|
+
* `signals/<pid>-<startMs>.jsonl`,进程内并发会话写同一文件
|
|
12
|
+
* (单次 append 合并当轮缓冲,逐行 JSON),跨进程各写各文件,无全局锁;
|
|
13
|
+
* - 异步落盘(review-fixes ❌4):`handle` 只入内存队列,事件循环内
|
|
14
|
+
* 批量落盘,热路径(工具调用事件)不碰磁盘;会话边界事件
|
|
15
|
+
* (session_start/session_end)同步收口——边界事件正是触发判定的
|
|
16
|
+
* 运行点(补偿判定/会话结束判定),判定必须看得到含当前边界事件
|
|
17
|
+
* 在内的全部已记录信号;`flush()` 供测试与收尾。信号非审计级
|
|
18
|
+
* (读取侧坏行容错同源),崩溃丢当轮缓冲可接受;
|
|
19
|
+
* - off 零副作用:`enabled()` 为 false 时连目录与文件都不创建。
|
|
20
|
+
*/
|
|
21
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
|
|
22
|
+
import { dirname, join } from "node:path";
|
|
23
|
+
import { eraseSecrets } from "./erase.js";
|
|
24
|
+
import { evolveStateDir } from "./stateDir.js";
|
|
25
|
+
/** 进化自身活动的 agent 标识(作业/探针会话以此自称)。 */
|
|
26
|
+
export const EVOLVE_SELF_AGENT = "trellis-evolve";
|
|
27
|
+
/** 进化自身活动的会话标识前缀(11.5 的作业会话命名约定)。 */
|
|
28
|
+
export const EVOLVE_SELF_SESSION_PREFIX = "evolve-job-";
|
|
29
|
+
/** 防自激(11.3):进化系统自身的调用/编辑不进信号——否则作业会把自己
|
|
30
|
+
* 的活动记成信号、再触发下一轮作业。识别靠自身标识约定;编辑面本身不经
|
|
31
|
+
* 事件总线,结构上就不产生信号。 */
|
|
32
|
+
export function isEvolveSelfActivity(event) {
|
|
33
|
+
return event.agent === EVOLVE_SELF_AGENT || event.session.startsWith(EVOLVE_SELF_SESSION_PREFIX);
|
|
34
|
+
}
|
|
35
|
+
export function createSignalRecorder(options) {
|
|
36
|
+
const now = options.now ?? Date.now;
|
|
37
|
+
const enabled = options.enabled ?? (() => true);
|
|
38
|
+
const filePath = signalFilePath(options.homeDir, now());
|
|
39
|
+
const layerBySession = new Map();
|
|
40
|
+
function layerFor(event) {
|
|
41
|
+
if (event.kind === "session_start") {
|
|
42
|
+
const layer = event.workspaceRoot === null ? { kind: "global" } : { kind: "workspace", root: event.workspaceRoot };
|
|
43
|
+
layerBySession.set(event.session, layer);
|
|
44
|
+
return layer;
|
|
45
|
+
}
|
|
46
|
+
return layerBySession.get(event.session) ?? { kind: "global" };
|
|
47
|
+
}
|
|
48
|
+
function toSignal(event) {
|
|
49
|
+
const common = {
|
|
50
|
+
source: "gateway-event",
|
|
51
|
+
stableId: null,
|
|
52
|
+
collectedAt: now(),
|
|
53
|
+
layer: layerFor(event),
|
|
54
|
+
};
|
|
55
|
+
const identity = {
|
|
56
|
+
ts: event.ts,
|
|
57
|
+
agent: eraseSecrets(event.agent),
|
|
58
|
+
session: eraseSecrets(event.session),
|
|
59
|
+
};
|
|
60
|
+
switch (event.kind) {
|
|
61
|
+
case "tool_call":
|
|
62
|
+
return {
|
|
63
|
+
...common,
|
|
64
|
+
...identity,
|
|
65
|
+
kind: "tool-call",
|
|
66
|
+
provider: eraseSecrets(event.provider),
|
|
67
|
+
tool: eraseSecrets(event.tool),
|
|
68
|
+
durationMs: event.durationMs,
|
|
69
|
+
result: event.result,
|
|
70
|
+
};
|
|
71
|
+
case "session_start":
|
|
72
|
+
return { ...common, ...identity, kind: "session-start" };
|
|
73
|
+
case "session_end":
|
|
74
|
+
return { ...common, ...identity, kind: "session-end" };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// 队列化批量落盘:handle 只入队,一个事件循环 turn 内合并为一次 append
|
|
78
|
+
// (热路径不碰磁盘)。会话边界事件在边界同步收口——边界事件正是触发
|
|
79
|
+
// 判定的运行点(订阅者顺序在 recorder 之后),判定读盘时必须看得到含
|
|
80
|
+
// 本事件在内的全部信号;其余事件靠 setImmediate 合并。
|
|
81
|
+
const pending = [];
|
|
82
|
+
let flushScheduled = false;
|
|
83
|
+
function flush() {
|
|
84
|
+
flushScheduled = false;
|
|
85
|
+
if (pending.length === 0)
|
|
86
|
+
return;
|
|
87
|
+
const batch = pending.splice(0, pending.length);
|
|
88
|
+
appendSignalLines(filePath, batch);
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
filePath,
|
|
92
|
+
handle(event) {
|
|
93
|
+
if (!enabled())
|
|
94
|
+
return;
|
|
95
|
+
if (isEvolveSelfActivity(event))
|
|
96
|
+
return;
|
|
97
|
+
pending.push(toSignal(event));
|
|
98
|
+
if (event.kind === "session_end" || event.kind === "session_start") {
|
|
99
|
+
flush();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!flushScheduled) {
|
|
103
|
+
flushScheduled = true;
|
|
104
|
+
setImmediate(flush);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
flush,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/** 本进程的信号文件路径(按进程分文件;首写前文件不存在)。 */
|
|
111
|
+
export function signalFilePath(homeDir, startMs) {
|
|
112
|
+
return join(evolveStateDir(homeDir), "signals", `${process.pid}-${startMs}.jsonl`);
|
|
113
|
+
}
|
|
114
|
+
/** 只追加一行信号(单行 JSON;JSON.stringify 转义字符串内换行,行边界
|
|
115
|
+
* 天然成立;新建文件 0600——信号含 workspace 路径等机器信息,不收世界
|
|
116
|
+
* 可读)。11.2 的用户纠正上报走本单行入口;recorder 经批量入口
|
|
117
|
+
* `appendSignalLines`(同一写入路径)。 */
|
|
118
|
+
export function appendSignalLine(filePath, signal) {
|
|
119
|
+
appendSignalLines(filePath, [signal]);
|
|
120
|
+
}
|
|
121
|
+
/** 批量只追加(同一 turn 的信号合并为一次 append;recorder 异步落盘用)。 */
|
|
122
|
+
export function appendSignalLines(filePath, signals) {
|
|
123
|
+
if (signals.length === 0)
|
|
124
|
+
return;
|
|
125
|
+
mkdirSync(dirname(filePath), { recursive: true, mode: 0o700 });
|
|
126
|
+
appendFileSync(filePath, signals.map((signal) => JSON.stringify(signal) + "\n").join(""), { mode: 0o600 });
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 读回一个信号文件的全部记录(测试与作业评估用;文件不存在返回空)。
|
|
130
|
+
* 容错:崩溃撕行(最后一次 append 只写了一部分)跳过该行继续——信号
|
|
131
|
+
* 不是审计级数据(对照 archive 的严格带行号抛错),一行损坏不应瘫痪
|
|
132
|
+
* 触发器/作业整条链。
|
|
133
|
+
*/
|
|
134
|
+
export function readSignals(filePath) {
|
|
135
|
+
if (!existsSync(filePath))
|
|
136
|
+
return [];
|
|
137
|
+
const signals = [];
|
|
138
|
+
for (const line of readFileSync(filePath, "utf-8").split("\n")) {
|
|
139
|
+
if (line === "")
|
|
140
|
+
continue;
|
|
141
|
+
try {
|
|
142
|
+
signals.push(JSON.parse(line));
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// 坏行跳过(见头注释)。
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return signals;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 合并读回全部进程信号文件里 `collectedAt > sinceMs`(null = 全部)的
|
|
152
|
+
* 记录(11.5 作业评估用;与 `trigger` 的 countPendingSignals 同一目录
|
|
153
|
+
* 遍历约定)。读取零副作用:不建目录、不排序语义(按文件名+行序)。
|
|
154
|
+
*/
|
|
155
|
+
export function readAllSignals(homeDir, sinceMs) {
|
|
156
|
+
const dir = join(evolveStateDir(homeDir), "signals");
|
|
157
|
+
if (!existsSync(dir))
|
|
158
|
+
return [];
|
|
159
|
+
const out = [];
|
|
160
|
+
for (const name of readdirSync(dir).sort()) {
|
|
161
|
+
if (!name.endsWith(".jsonl"))
|
|
162
|
+
continue;
|
|
163
|
+
for (const signal of readSignals(join(dir, name))) {
|
|
164
|
+
if (sinceMs === null || signal.collectedAt > sinceMs)
|
|
165
|
+
out.push(signal);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent 可调用的用户纠正上报入口(trellis-evolve 任务 11.2)。
|
|
3
|
+
*
|
|
4
|
+
* 内容级信号不从事件流捞(8.2 白名单的必然推论,见 design 9.4①):用户
|
|
5
|
+
* 纠正文本一律走本入口显式上报。文本写入前过 secrets 擦除;原始文本不
|
|
6
|
+
* 入库;层归属由调用方观察到的 workspace root 派生,root 本身不独立入库
|
|
7
|
+
* (只随 layer 保留)。与 recorder 共用按进程分文件的只追加写入路径。
|
|
8
|
+
*/
|
|
9
|
+
import type { UserCorrectionSignal } from "./types.js";
|
|
10
|
+
/** 本进程用户纠正上报所写的信号文件路径。 */
|
|
11
|
+
export declare function userCorrectionFilePath(homeDir: string): string;
|
|
12
|
+
export interface UserCorrectionReport {
|
|
13
|
+
homeDir: string;
|
|
14
|
+
agent: string;
|
|
15
|
+
session: string;
|
|
16
|
+
/** 用户纠正文本原文;写入前擦除,原始文本不入库。 */
|
|
17
|
+
text: string;
|
|
18
|
+
/** 会话观察到的 workspace root;null/缺省记全局层。 */
|
|
19
|
+
workspaceRoot?: string | null;
|
|
20
|
+
/** 级别开关(off 返回 null 且不写入)。缺省恒开。 */
|
|
21
|
+
enabled?: () => boolean;
|
|
22
|
+
/** 采集时间源(测试注入固定时钟);缺省 Date.now。 */
|
|
23
|
+
now?: () => number;
|
|
24
|
+
}
|
|
25
|
+
/** 上报一条用户纠正;返回写入的信号,off 时返回 null。 */
|
|
26
|
+
export declare function reportUserCorrection(report: UserCorrectionReport): UserCorrectionSignal | null;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent 可调用的用户纠正上报入口(trellis-evolve 任务 11.2)。
|
|
3
|
+
*
|
|
4
|
+
* 内容级信号不从事件流捞(8.2 白名单的必然推论,见 design 9.4①):用户
|
|
5
|
+
* 纠正文本一律走本入口显式上报。文本写入前过 secrets 擦除;原始文本不
|
|
6
|
+
* 入库;层归属由调用方观察到的 workspace root 派生,root 本身不独立入库
|
|
7
|
+
* (只随 layer 保留)。与 recorder 共用按进程分文件的只追加写入路径。
|
|
8
|
+
*/
|
|
9
|
+
import { eraseSecrets } from "./erase.js";
|
|
10
|
+
import { appendSignalLine, signalFilePath } from "./recorder.js";
|
|
11
|
+
/** 与 recorder 同款"按进程分文件":进程内所有上报进同一文件。 */
|
|
12
|
+
const PROCESS_START_MS = Date.now();
|
|
13
|
+
/** 本进程用户纠正上报所写的信号文件路径。 */
|
|
14
|
+
export function userCorrectionFilePath(homeDir) {
|
|
15
|
+
return signalFilePath(homeDir, PROCESS_START_MS);
|
|
16
|
+
}
|
|
17
|
+
/** 上报一条用户纠正;返回写入的信号,off 时返回 null。 */
|
|
18
|
+
export function reportUserCorrection(report) {
|
|
19
|
+
if (report.enabled !== undefined && !report.enabled())
|
|
20
|
+
return null;
|
|
21
|
+
const now = report.now ?? Date.now;
|
|
22
|
+
const signal = {
|
|
23
|
+
kind: "user-correction",
|
|
24
|
+
source: "agent-report",
|
|
25
|
+
stableId: null,
|
|
26
|
+
collectedAt: now(),
|
|
27
|
+
layer: report.workspaceRoot == null
|
|
28
|
+
? { kind: "global" }
|
|
29
|
+
: { kind: "workspace", root: report.workspaceRoot },
|
|
30
|
+
ts: now(),
|
|
31
|
+
agent: eraseSecrets(report.agent),
|
|
32
|
+
session: eraseSecrets(report.session),
|
|
33
|
+
text: eraseSecrets(report.text),
|
|
34
|
+
};
|
|
35
|
+
appendSignalLine(userCorrectionFilePath(report.homeDir), signal);
|
|
36
|
+
return signal;
|
|
37
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 进化可视化聚合层(trellis-evolve-visualization 任务 1.1)。
|
|
3
|
+
*
|
|
4
|
+
* 单一计算源:从三个只读来源(~/.trellis/evolve/archive/records.jsonl、
|
|
5
|
+
* evolve/pending/*.json、evolve.yaml)聚合出 `EvolveReport`,CLI 的
|
|
6
|
+
* `evolve report` / `status --json` 与 GUI sidecar 路由只是它的渲染/传输
|
|
7
|
+
* 壳——绝不维护第二份独立计算(gui-sidecar-api 的"读视图镜像 CLI"规约)。
|
|
8
|
+
*
|
|
9
|
+
* 只读零副作用:本模块永不 mkdir/append/write;全部指标可从档案重算,
|
|
10
|
+
* 每条趋势指标带口径说明(spec"趋势指标只来自真实测量")。数值评分
|
|
11
|
+
* (0-100 健康分之类)一律不合成——分数轴等 L2 探针任务集落地后另行变更。
|
|
12
|
+
*/
|
|
13
|
+
import { type EditOp, type Level, type SurfaceLayer } from "../host/index.js";
|
|
14
|
+
/** 时间线一环:阶段、时间戳(ISO)与可读说明。 */
|
|
15
|
+
export interface TimelineStep {
|
|
16
|
+
readonly stage: "proposed" | "discarded" | "verdict" | "decision" | "applied" | "lesson";
|
|
17
|
+
readonly at: string;
|
|
18
|
+
readonly note: string;
|
|
19
|
+
}
|
|
20
|
+
/** 前后测量(来自 L1 verdict 档案;无 verdict 时为 null,不推断)。 */
|
|
21
|
+
export interface ProposalMeasurement {
|
|
22
|
+
readonly decision: string;
|
|
23
|
+
readonly reason: string;
|
|
24
|
+
readonly targetIds: readonly string[];
|
|
25
|
+
readonly resolvedIds: readonly string[];
|
|
26
|
+
readonly introduced: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
/** 一条提案的全生命周期追踪(缺口如实呈现,不伪造补齐)。 */
|
|
29
|
+
export interface ProposalTrace {
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly summary: string;
|
|
32
|
+
readonly kind: string;
|
|
33
|
+
readonly riskClass: string | null;
|
|
34
|
+
readonly layer: SurfaceLayer | null;
|
|
35
|
+
/** 终态:discarded(校验/L1 丢弃)/ pending / approved(待应用)/
|
|
36
|
+
* rejected / applied(已应用)。 */
|
|
37
|
+
readonly status: "discarded" | "pending" | "approved" | "rejected" | "applied";
|
|
38
|
+
readonly chain: readonly TimelineStep[];
|
|
39
|
+
/** 最近一次 L1 测量;整条提案无 verdict 档案时 null。 */
|
|
40
|
+
readonly measurement: ProposalMeasurement | null;
|
|
41
|
+
readonly edits: readonly EditOp[];
|
|
42
|
+
/** 应用时的备份会话标识(可据此回滚);未应用为 null。 */
|
|
43
|
+
readonly backupRunId: string | null;
|
|
44
|
+
/** 蒸馏的 lesson id;无为 null。 */
|
|
45
|
+
readonly lessonId: string | null;
|
|
46
|
+
}
|
|
47
|
+
/** 趋势指标(全部可从档案重算;口径随数据导出)。 */
|
|
48
|
+
export interface TrendMetric {
|
|
49
|
+
readonly id: string;
|
|
50
|
+
readonly label: string;
|
|
51
|
+
/** 数值指标;无测量时 null(GUI 显示"无测量记录"而非 0)。 */
|
|
52
|
+
readonly value: number | null;
|
|
53
|
+
/** 数据口径:由哪类档案记录聚得(可重算依据)。 */
|
|
54
|
+
readonly source: string;
|
|
55
|
+
}
|
|
56
|
+
/** 一次作业运行(job-run 档案)。 */
|
|
57
|
+
export interface JobRunEntry {
|
|
58
|
+
readonly startedAt: string;
|
|
59
|
+
readonly endedAt: string | null;
|
|
60
|
+
readonly ok: boolean;
|
|
61
|
+
readonly error: string | null;
|
|
62
|
+
/** 触发来源(run-backfill D1);旧档案无字段视作 `event`。 */
|
|
63
|
+
readonly trigger: "event" | "manual" | "chain";
|
|
64
|
+
readonly summary: {
|
|
65
|
+
readonly signalsConsidered: number | null;
|
|
66
|
+
readonly enqueued: number | null;
|
|
67
|
+
readonly autoAdopted: number | null;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** 可视化状态:未开启 / 已开启未运行 / 有运行历史。 */
|
|
71
|
+
export type EvolveViewState = "not-enabled" | "enabled-idle" | "active";
|
|
72
|
+
export interface EvolveReport {
|
|
73
|
+
readonly state: EvolveViewState;
|
|
74
|
+
readonly levels: {
|
|
75
|
+
readonly defaultLevel: Level | null;
|
|
76
|
+
readonly agents: Readonly<Record<string, Level>>;
|
|
77
|
+
readonly workspaces: Readonly<Record<string, Level>>;
|
|
78
|
+
};
|
|
79
|
+
readonly counts: {
|
|
80
|
+
readonly pending: number;
|
|
81
|
+
readonly approved: number;
|
|
82
|
+
readonly rejected: number;
|
|
83
|
+
/** 已批准但未应用(可经 `trellis evolve apply` 消化)。 */
|
|
84
|
+
readonly approvedUnapplied: number;
|
|
85
|
+
};
|
|
86
|
+
readonly timeline: readonly ProposalTrace[];
|
|
87
|
+
readonly trends: readonly TrendMetric[];
|
|
88
|
+
readonly jobRuns: readonly JobRunEntry[];
|
|
89
|
+
readonly notices: readonly string[];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 聚合进化报告(纯读)。timeline 按提案 id 关联 proposal / proposal-reject /
|
|
93
|
+
* verdict / proposal-decision / apply-run / lesson 档案;链上缺环如实标注,
|
|
94
|
+
* 不推断补齐。
|
|
95
|
+
*/
|
|
96
|
+
export declare function buildEvolveReport(homeDir: string): EvolveReport;
|