@istuen/pt 0.1.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/LICENSE +21 -0
- package/README.md +219 -0
- package/dist/agent/api-bridge.d.ts +8 -0
- package/dist/agent/api-bridge.js +83 -0
- package/dist/agent/index.d.ts +2 -0
- package/dist/agent/index.js +3 -0
- package/dist/agent/pi-adapter.d.ts +35 -0
- package/dist/agent/pi-adapter.js +251 -0
- package/dist/agent/registry.d.ts +4 -0
- package/dist/agent/registry.js +40 -0
- package/dist/asset-health.d.ts +50 -0
- package/dist/asset-health.js +267 -0
- package/dist/asset-pack/loader.d.ts +47 -0
- package/dist/asset-pack/loader.js +121 -0
- package/dist/asset-pack/manifest.d.ts +23 -0
- package/dist/asset-pack/manifest.js +96 -0
- package/dist/asset-pack/md-file-pack.d.ts +41 -0
- package/dist/asset-pack/md-file-pack.js +153 -0
- package/dist/asset-pack/validate.d.ts +55 -0
- package/dist/asset-pack/validate.js +131 -0
- package/dist/builtin/assets/blueprints/dev-knowledge.blueprint.yaml +13 -0
- package/dist/builtin/assets/domains/agent-info.md +15 -0
- package/dist/builtin/assets/domains/authoring.md +201 -0
- package/dist/builtin/assets/domains/pack-repair.md +47 -0
- package/dist/builtin/assets/domains/project-analysis.md +52 -0
- package/dist/builtin/assets/domains/usage.md +81 -0
- package/dist/builtin/assets/domains/user-info.md +15 -0
- package/dist/builtin/assets/profiles/guide.profile.md +28 -0
- package/dist/commands.d.ts +69 -0
- package/dist/commands.js +344 -0
- package/dist/compile/agent-context.d.ts +48 -0
- package/dist/compile/agent-context.js +423 -0
- package/dist/compile/index.d.ts +1 -0
- package/dist/compile/index.js +5 -0
- package/dist/compile/resolve-use.d.ts +36 -0
- package/dist/compile/resolve-use.js +171 -0
- package/dist/compile/type-guards.d.ts +29 -0
- package/dist/compile/type-guards.js +107 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.js +133 -0
- package/dist/constants.d.ts +52 -0
- package/dist/constants.js +81 -0
- package/dist/diagnostics.d.ts +14 -0
- package/dist/diagnostics.js +29 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +838 -0
- package/dist/injection-status.d.ts +45 -0
- package/dist/injection-status.js +134 -0
- package/dist/log.d.ts +64 -0
- package/dist/log.js +139 -0
- package/dist/manual-session.d.ts +24 -0
- package/dist/manual-session.js +152 -0
- package/dist/manual-track.d.ts +35 -0
- package/dist/manual-track.js +107 -0
- package/dist/parse/blueprint.d.ts +5 -0
- package/dist/parse/blueprint.js +59 -0
- package/dist/parse/domain-renderers.d.ts +8 -0
- package/dist/parse/domain-renderers.js +115 -0
- package/dist/parse/domain.d.ts +7 -0
- package/dist/parse/domain.js +69 -0
- package/dist/parse/index.d.ts +9 -0
- package/dist/parse/index.js +223 -0
- package/dist/parse/profile.d.ts +18 -0
- package/dist/parse/profile.js +117 -0
- package/dist/parse/ref-resolver.d.ts +63 -0
- package/dist/parse/ref-resolver.js +174 -0
- package/dist/parse/shared.d.ts +76 -0
- package/dist/parse/shared.js +273 -0
- package/dist/profile-persist.d.ts +22 -0
- package/dist/profile-persist.js +53 -0
- package/dist/render/cache.d.ts +15 -0
- package/dist/render/cache.js +135 -0
- package/dist/render/index.d.ts +3 -0
- package/dist/render/index.js +14 -0
- package/dist/render/session-inject.d.ts +5 -0
- package/dist/render/session-inject.js +24 -0
- package/dist/render/turn-inject.d.ts +36 -0
- package/dist/render/turn-inject.js +248 -0
- package/dist/schema.d.ts +448 -0
- package/dist/schema.js +45 -0
- package/dist/session.d.ts +82 -0
- package/dist/session.js +102 -0
- package/dist/slog.d.ts +3 -0
- package/dist/slog.js +27 -0
- package/dist/transpile.d.ts +34 -0
- package/dist/transpile.js +220 -0
- package/dist/verify/file-hash.d.ts +2 -0
- package/dist/verify/file-hash.js +30 -0
- package/dist/verify/fs-content-match.d.ts +2 -0
- package/dist/verify/fs-content-match.js +26 -0
- package/dist/verify/fs-exists.d.ts +2 -0
- package/dist/verify/fs-exists.js +13 -0
- package/dist/verify/fs-not-exists.d.ts +2 -0
- package/dist/verify/fs-not-exists.js +13 -0
- package/dist/verify/git-status-clean.d.ts +2 -0
- package/dist/verify/git-status-clean.js +19 -0
- package/dist/verify/index.d.ts +7 -0
- package/dist/verify/index.js +46 -0
- package/dist/verify/lint-check.d.ts +2 -0
- package/dist/verify/lint-check.js +17 -0
- package/dist/verify/read-stderr.d.ts +5 -0
- package/dist/verify/read-stderr.js +20 -0
- package/dist/verify/ref-check.d.ts +13 -0
- package/dist/verify/ref-check.js +88 -0
- package/dist/verify/test-pass.d.ts +2 -0
- package/dist/verify/test-pass.js +17 -0
- package/dist/verify/ts-compiles.d.ts +2 -0
- package/dist/verify/ts-compiles.js +17 -0
- package/package.json +62 -0
- package/src/agent/api-bridge.ts +105 -0
- package/src/agent/index.ts +4 -0
- package/src/agent/pi-adapter.ts +326 -0
- package/src/agent/registry.ts +44 -0
- package/src/asset-health.ts +327 -0
- package/src/asset-pack/loader.ts +141 -0
- package/src/asset-pack/manifest.ts +118 -0
- package/src/asset-pack/md-file-pack.ts +202 -0
- package/src/asset-pack/validate.ts +186 -0
- package/src/builtin/assets/blueprints/dev-knowledge.blueprint.yaml +13 -0
- package/src/builtin/assets/domains/agent-info.md +15 -0
- package/src/builtin/assets/domains/authoring.md +201 -0
- package/src/builtin/assets/domains/pack-repair.md +47 -0
- package/src/builtin/assets/domains/project-analysis.md +52 -0
- package/src/builtin/assets/domains/usage.md +81 -0
- package/src/builtin/assets/domains/user-info.md +15 -0
- package/src/builtin/assets/profiles/guide.profile.md +28 -0
- package/src/commands.ts +405 -0
- package/src/compile/agent-context.ts +487 -0
- package/src/compile/index.ts +5 -0
- package/src/compile/resolve-use.ts +208 -0
- package/src/compile/type-guards.ts +132 -0
- package/src/config.ts +154 -0
- package/src/constants.ts +104 -0
- package/src/diagnostics.ts +36 -0
- package/src/index.ts +1028 -0
- package/src/injection-status.ts +155 -0
- package/src/log.ts +173 -0
- package/src/manual-session.ts +190 -0
- package/src/manual-track.ts +127 -0
- package/src/parse/blueprint.ts +82 -0
- package/src/parse/domain-renderers.ts +120 -0
- package/src/parse/domain.ts +78 -0
- package/src/parse/index.ts +266 -0
- package/src/parse/profile.ts +139 -0
- package/src/parse/ref-resolver.ts +198 -0
- package/src/parse/shared.ts +331 -0
- package/src/profile-persist.ts +60 -0
- package/src/render/cache.ts +150 -0
- package/src/render/index.ts +14 -0
- package/src/render/session-inject.ts +26 -0
- package/src/render/turn-inject.ts +278 -0
- package/src/schema.ts +542 -0
- package/src/session.ts +190 -0
- package/src/slog.ts +32 -0
- package/src/transpile.ts +302 -0
- package/src/verify/file-hash.ts +29 -0
- package/src/verify/fs-content-match.ts +28 -0
- package/src/verify/fs-exists.ts +14 -0
- package/src/verify/fs-not-exists.ts +17 -0
- package/src/verify/git-status-clean.ts +23 -0
- package/src/verify/index.ts +57 -0
- package/src/verify/lint-check.ts +21 -0
- package/src/verify/read-stderr.ts +24 -0
- package/src/verify/ref-check.ts +118 -0
- package/src/verify/test-pass.ts +18 -0
- package/src/verify/ts-compiles.ts +21 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
// src/parse/shared.ts — 通用 MD 词法+语法(domain/blueprint/profile 共享)
|
|
2
|
+
//
|
|
3
|
+
// Phase 7.3:从原 src/parse/{parser,types}.ts 抽公共部分。
|
|
4
|
+
// - Domain/Blueprint/Profile adapter 都按 H2 段解析,H3 子项 → Item。
|
|
5
|
+
// - 共享 frontmatter 解析、H2 段切分、H3 项解析、scalar 值解析。
|
|
6
|
+
// - 共享 Asset/Section/Item 类型。
|
|
7
|
+
//
|
|
8
|
+
// Phase 9.3:v9 适配 — Channel 删除(Channel 留作未来 Connector),inferKind 用 frontmatter 字段。
|
|
9
|
+
// AssetKind 去除 "channel"——但保留 type 值以防历史资源解析时遗留错误。
|
|
10
|
+
import { readFile } from "node:fs/promises";
|
|
11
|
+
// ==================== 词法/语法(共享) ====================
|
|
12
|
+
/** 读 asset 文件并解析 frontmatter + H2 段。 */
|
|
13
|
+
export async function readAsset(path) {
|
|
14
|
+
const raw = await readFile(path, "utf8");
|
|
15
|
+
const { fm, body } = parseFrontmatter(raw);
|
|
16
|
+
// 从文件路径末尾推 name(无后缀)
|
|
17
|
+
const fileName = path.split("/").pop() ?? "";
|
|
18
|
+
const name = fileName.replace(/\.[^.]+$/, "");
|
|
19
|
+
// Phase term-P9.3:type 字段已删——kind 推断逻辑仅保留为兼容(无 caller 实际使用)。
|
|
20
|
+
// 资产加载走目录路由(src/parse/index.ts loadAllDomains / loadAllBlueprints / loadAllProfiles),
|
|
21
|
+
// 不依赖 readAsset 的 kind 字段。
|
|
22
|
+
const kind = "domain"; // 默认值——保留 AssetKind 联合类型以备未来扩展
|
|
23
|
+
const sectionsArr = splitSections(body);
|
|
24
|
+
const sections = {};
|
|
25
|
+
for (const sec of sectionsArr) {
|
|
26
|
+
const key = sec.heading.replace(/^#+\s*/, "").trim();
|
|
27
|
+
sections[key] = { heading: sec.heading, raw: sec.raw, items: parseItems(sec.raw) };
|
|
28
|
+
}
|
|
29
|
+
return { kind, name, frontmatter: fm, body, sections };
|
|
30
|
+
}
|
|
31
|
+
/** 解析 frontmatter --- ... --- 块(简易:key: value / key: [a, b] / key: { ... }) */
|
|
32
|
+
export function parseFrontmatter(text) {
|
|
33
|
+
const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
34
|
+
if (!m)
|
|
35
|
+
return { fm: {}, body: text };
|
|
36
|
+
const fm = {};
|
|
37
|
+
for (const line of m[1].split(/\r?\n/)) {
|
|
38
|
+
const kv = line.match(/^([a-zA-Z_][\w-]*)\s*:\s*(.*)$/);
|
|
39
|
+
if (!kv)
|
|
40
|
+
continue;
|
|
41
|
+
const key = kv[1];
|
|
42
|
+
const val = kv[2].trim();
|
|
43
|
+
fm[key] = parseScalar(val);
|
|
44
|
+
}
|
|
45
|
+
return { fm, body: m[2] };
|
|
46
|
+
}
|
|
47
|
+
/** 解析 scalar 值:string / string[] / 嵌套对象(YAML 子集)。
|
|
48
|
+
* 嵌套值通过 parseScalar 递归解析,支持任意深度。 */
|
|
49
|
+
function parseScalar(val) {
|
|
50
|
+
if (!val)
|
|
51
|
+
return "";
|
|
52
|
+
// [a, b]
|
|
53
|
+
const arrMatch = val.match(/^\[(.*)\]$/);
|
|
54
|
+
if (arrMatch) {
|
|
55
|
+
return arrMatch[1]
|
|
56
|
+
.split(",")
|
|
57
|
+
.map((s) => unquote(s.trim()))
|
|
58
|
+
.filter((s) => s !== "");
|
|
59
|
+
}
|
|
60
|
+
// { key: value, ... } → 嵌套对象
|
|
61
|
+
if (/^\{.*\}$/.test(val.trim())) {
|
|
62
|
+
return parseInlineObject(val.trim());
|
|
63
|
+
}
|
|
64
|
+
return unquote(val);
|
|
65
|
+
}
|
|
66
|
+
function parseInlineObject(s) {
|
|
67
|
+
const inner = s.slice(1, -1).trim();
|
|
68
|
+
if (!inner)
|
|
69
|
+
return {};
|
|
70
|
+
const out = {};
|
|
71
|
+
for (const part of splitTopLevel(inner, ",")) {
|
|
72
|
+
const kv = part.match(/^\s*([a-zA-Z_][\w-]*)\s*:\s*(.+)$/);
|
|
73
|
+
if (kv)
|
|
74
|
+
out[kv[1]] = parseScalar(kv[2].trim());
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
function splitTopLevel(s, sep) {
|
|
79
|
+
const out = [];
|
|
80
|
+
let depth = 0;
|
|
81
|
+
let buf = "";
|
|
82
|
+
for (const ch of s) {
|
|
83
|
+
if (ch === "{" || ch === "[")
|
|
84
|
+
depth++;
|
|
85
|
+
else if (ch === "}" || ch === "]")
|
|
86
|
+
depth--;
|
|
87
|
+
if (ch === sep && depth === 0) {
|
|
88
|
+
out.push(buf);
|
|
89
|
+
buf = "";
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
buf += ch;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (buf.trim())
|
|
96
|
+
out.push(buf);
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
function unquote(s) {
|
|
100
|
+
if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
|
|
101
|
+
return s.slice(1, -1);
|
|
102
|
+
}
|
|
103
|
+
return s;
|
|
104
|
+
}
|
|
105
|
+
/** 按 `## ` 切 H2 段。H1 `# ` 不在此处理(asset 一般只有 1 个 H1 当标题) */
|
|
106
|
+
export function splitSections(body) {
|
|
107
|
+
const lines = body.split(/\r?\n/);
|
|
108
|
+
const sections = [];
|
|
109
|
+
let cur = null;
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
const h2 = line.match(/^##\s+(.+)$/);
|
|
112
|
+
if (h2) {
|
|
113
|
+
if (cur)
|
|
114
|
+
sections.push({ heading: cur.heading, raw: cur.lines.join("\n") });
|
|
115
|
+
cur = { heading: line.trim(), lines: [] };
|
|
116
|
+
}
|
|
117
|
+
else if (cur) {
|
|
118
|
+
cur.lines.push(line);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (cur)
|
|
122
|
+
sections.push({ heading: cur.heading, raw: cur.lines.join("\n") });
|
|
123
|
+
return sections;
|
|
124
|
+
}
|
|
125
|
+
/** 把段内 markdown 解析成 Item[]:
|
|
126
|
+
* - 有 H3 (`### name`) → 每个 H3 是一个 item,下属 `- key: value` 是 fields
|
|
127
|
+
* - 无 H3,整段就是 list → 顶层 `- key: value` / `- name` 直接作为 items
|
|
128
|
+
*
|
|
129
|
+
* 顶层 list 支持两种行形态:
|
|
130
|
+
* - `- key: value` → { name: "key", fields: { key: value } }
|
|
131
|
+
* - `- name` → { name: "name", fields: {} }(裸名列表,例 ## Modules 段)
|
|
132
|
+
*/
|
|
133
|
+
export function parseItems(sectionRaw) {
|
|
134
|
+
const lines = sectionRaw.split(/\r?\n/);
|
|
135
|
+
const hasH3 = lines.some((l) => /^###\s+/.test(l));
|
|
136
|
+
if (hasH3) {
|
|
137
|
+
const items = [];
|
|
138
|
+
let cur = null;
|
|
139
|
+
for (const line of lines) {
|
|
140
|
+
const h3 = line.match(/^###\s+(.+)$/);
|
|
141
|
+
if (h3) {
|
|
142
|
+
if (cur)
|
|
143
|
+
items.push(cur);
|
|
144
|
+
cur = { name: h3[1].trim(), fields: {} };
|
|
145
|
+
}
|
|
146
|
+
else if (cur) {
|
|
147
|
+
const fv = line.match(/^\s*-\s+([a-zA-Z_][\w-]*)\s*:\s*(.+)$/);
|
|
148
|
+
if (fv)
|
|
149
|
+
cur.fields[fv[1]] = parseScalar(fv[2].trim());
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (cur)
|
|
153
|
+
items.push(cur);
|
|
154
|
+
return items;
|
|
155
|
+
}
|
|
156
|
+
// 无 H3:顶层 list 直接当 items(支持 `- key: value` 和 `- name` 两种行)
|
|
157
|
+
const items = [];
|
|
158
|
+
for (const line of lines) {
|
|
159
|
+
const fv = line.match(/^\s*-\s+([a-zA-Z_][\w-]*)\s*:\s*(.+)$/);
|
|
160
|
+
if (fv) {
|
|
161
|
+
items.push({
|
|
162
|
+
name: fv[1],
|
|
163
|
+
fields: { [fv[1]]: parseScalar(fv[2].trim()) },
|
|
164
|
+
});
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const bare = line.match(/^\s*-\s+(.+?)\s*$/);
|
|
168
|
+
if (bare) {
|
|
169
|
+
items.push({ name: bare[1].trim(), fields: {} });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return items;
|
|
173
|
+
}
|
|
174
|
+
// ==================== 字段取值辅助(共享) ====================
|
|
175
|
+
/** 把 unknown 收窄为 string(数组则 join)。无值 → ""。 */
|
|
176
|
+
export function s(v) {
|
|
177
|
+
if (typeof v === "string")
|
|
178
|
+
return v;
|
|
179
|
+
if (Array.isArray(v))
|
|
180
|
+
return v.filter((x) => typeof x === "string").join(", ");
|
|
181
|
+
return "";
|
|
182
|
+
}
|
|
183
|
+
/** 把 unknown 收窄为 string[](单值包成 1-数组)。无值 → []。 */
|
|
184
|
+
export function sArr(v) {
|
|
185
|
+
if (Array.isArray(v))
|
|
186
|
+
return v.filter((x) => typeof x === "string");
|
|
187
|
+
if (typeof v === "string" && v)
|
|
188
|
+
return [v];
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
/** 从一个 H2 段里取某个字段的标量值(兼容裸值 / 顶层 list `- key: value` / H3 项 fields.key)。
|
|
192
|
+
* 用途:Blueprint 聚合组 H2 下读 inject/mode,Profile 聚合组 H2 下读 ### Domains 追加列表。 */
|
|
193
|
+
export function extractFieldValue(section, key) {
|
|
194
|
+
if (!section)
|
|
195
|
+
return "";
|
|
196
|
+
// 1. 顶层 list 行:`- inject: session`
|
|
197
|
+
for (const item of section.items) {
|
|
198
|
+
const v = item.fields[key];
|
|
199
|
+
if (v !== undefined) {
|
|
200
|
+
const sv = s(v);
|
|
201
|
+
if (sv)
|
|
202
|
+
return sv;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// 2. 裸值段(## H2 后第一行非空文本)—— 取第一个匹配 `key: value` 的行
|
|
206
|
+
for (const line of section.raw.split(/\r?\n/)) {
|
|
207
|
+
const m = line.match(new RegExp(`^\\s*${key}\\s*:\\s*(.+?)\\s*$`));
|
|
208
|
+
if (m) {
|
|
209
|
+
return s(parseScalar(m[1].trim()));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return "";
|
|
213
|
+
}
|
|
214
|
+
/** 同 extractBareListUnderH3(section, "Modules") 的别名(Channel 用)。 */
|
|
215
|
+
export function extractModulesList(section) {
|
|
216
|
+
return extractBareListUnderH3(section, "Modules");
|
|
217
|
+
}
|
|
218
|
+
/** 同 extractBareListUnderH3(section, "Domains") 的别名(Blueprint 用)。 */
|
|
219
|
+
export function extractDomainsList(section) {
|
|
220
|
+
return extractBareListUnderH3(section, "Domains");
|
|
221
|
+
}
|
|
222
|
+
/** 从一个 H2 段下取指定 H3 名下的所有裸名列表项(`- name`)。
|
|
223
|
+
* 用途:Blueprint `## 会话背景` → `### Modules` 列 Domain Schema Name;
|
|
224
|
+
* Profile `## 会话背景` → `### Domains` 列参与本聚合组的 Domain 名。
|
|
225
|
+
*
|
|
226
|
+
* 行为:扫描 section.raw,找到 `### <h3Name>` 行后收集紧随其后的 `- name` 行
|
|
227
|
+
* (无 `key: value`),遇下一个 H3 或段尾终止。
|
|
228
|
+
*
|
|
229
|
+
* 兼容:若 H3 项的 fields.modules / fields.refs 是数组(旧写法),也支持。 */
|
|
230
|
+
export function extractBareListUnderH3(section, h3Name) {
|
|
231
|
+
if (!section)
|
|
232
|
+
return [];
|
|
233
|
+
// 兼容路径:若 fields 里有数组字段(旧写法 `### Modules` 下用 `- modules: [Scene]` 等)
|
|
234
|
+
const item = section.items.find((it) => it.name === h3Name);
|
|
235
|
+
if (item) {
|
|
236
|
+
const arr = item.fields.modules ?? item.fields.refs;
|
|
237
|
+
if (Array.isArray(arr)) {
|
|
238
|
+
const strs = arr.filter((x) => typeof x === "string");
|
|
239
|
+
if (strs.length > 0)
|
|
240
|
+
return strs;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// 主路径:扫 raw text 找 H3 + 后随的 `- name` 行
|
|
244
|
+
const lines = section.raw.split(/\r?\n/);
|
|
245
|
+
const out = [];
|
|
246
|
+
let inTarget = false;
|
|
247
|
+
for (const line of lines) {
|
|
248
|
+
const h3 = line.match(/^###\s+(.+)$/);
|
|
249
|
+
if (h3) {
|
|
250
|
+
const name = h3[1].trim();
|
|
251
|
+
inTarget = name === h3Name;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (!inTarget)
|
|
255
|
+
continue;
|
|
256
|
+
// 裸名行:`- Scene` / `- pt-architecture`(无冒号或冒号后无值)
|
|
257
|
+
const bare = line.match(/^\s*-\s+([^\s:]+)\s*$/);
|
|
258
|
+
if (bare) {
|
|
259
|
+
out.push(bare[1].trim());
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
// H4 段也终止(子嵌套不展开)
|
|
263
|
+
if (/^#+\s/.test(line))
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
return out;
|
|
267
|
+
}
|
|
268
|
+
// Phase term-P9.5:删除 inferKind / inferKindFromFrontmatter 死代码。
|
|
269
|
+
// Type 字段删除(P9.3)+ Blueprint 转 YAML(P4.5)后,asset kind 推断链路(frontmatter
|
|
270
|
+
// type/agent + H2 Slots/Tools/Compilation 识别)全部失去作用——资产加载按目录路由
|
|
271
|
+
// (src/parse/index.ts loadAllDomains/Blueprints/Profiles),不依赖 readAsset 的 kind 字段。
|
|
272
|
+
// AssetKind 联合类型保留(供未来扩展),具体推断函数清理。
|
|
273
|
+
// Channel 已删除,Domain 走通用 term 形态。 */
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
/** session JSONL 通用接口的最小子集(结构类型,不用 ReadonlySessionManager——不在 pi 包顶层 export)。 */
|
|
3
|
+
export interface MinimalSessionManager {
|
|
4
|
+
getEntries(): Array<{
|
|
5
|
+
type: string;
|
|
6
|
+
customType?: string;
|
|
7
|
+
data?: unknown;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
/** session JSONL 中持久化 activeProfile 的 custom entry customType。
|
|
11
|
+
* 用 `pt:` 命名空间避免污染 pi 通用命名空间。 */
|
|
12
|
+
export declare const PT_PROFILE_ENTRY = "pt:active-profile";
|
|
13
|
+
/** 从 session JSONL 读上次保存的 profile。
|
|
14
|
+
* - 反向遍历 entries,取最后一个 `pt:active-profile`(最新一次切换覆盖前一次)。
|
|
15
|
+
* - 静默 fallback:SessionManager 不可用 / ephemeral session / entry 损坏 → 返 undefined。
|
|
16
|
+
* - 不校验 profile 是否仍存在于 assets——校验留给 transpileActive(transpile 失败会被 session_start catch)。
|
|
17
|
+
* - 用结构类型而非 `ReadonlySessionManager`(该类型不在 pi 包顶层 export.d.ts 里)。 */
|
|
18
|
+
export declare function readProfileFromSession(sessionManager: MinimalSessionManager): string | undefined;
|
|
19
|
+
/** 把当前 activeProfile 写入 session JSONL(Pi 自带持久化)。
|
|
20
|
+
* - 用 `pi.appendEntry()`(dist/core/extensions/types.d.ts:78 官方 API)。
|
|
21
|
+
* - 失败静默(ephemeral session / 旧版 pi 无此 API)——内存中 activeProfile 仍可用本进程。 */
|
|
22
|
+
export declare function persistProfileToSession(pi: ExtensionAPI, name: string): void;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// src/profile-persist.ts — Session JSONL profile 持久化(P1.4 抽出)
|
|
2
|
+
//
|
|
3
|
+
// v10.x:用 pi.appendEntry() 把 activeProfile 写到 session JSONL。
|
|
4
|
+
// - 读:反向遍历 entries,取最后一个 pt:active-profile(最新覆盖前一次)。
|
|
5
|
+
// - 写:appendEntry,失败静默(ephemeral session / 旧版 pi 无此 API)。
|
|
6
|
+
//
|
|
7
|
+
// MinimalSessionManager 是 session JSONL 通用接口的最小子集(profile + manual 持久化共用)。
|
|
8
|
+
// P1 范围内放这里;未来 contract/ 迁移(P2+)时可考虑抽到 src/contract/。
|
|
9
|
+
import { errMsg } from "./diagnostics.js";
|
|
10
|
+
/** session JSONL 中持久化 activeProfile 的 custom entry customType。
|
|
11
|
+
* 用 `pt:` 命名空间避免污染 pi 通用命名空间。 */
|
|
12
|
+
export const PT_PROFILE_ENTRY = "pt:active-profile";
|
|
13
|
+
/** 从 session JSONL 读上次保存的 profile。
|
|
14
|
+
* - 反向遍历 entries,取最后一个 `pt:active-profile`(最新一次切换覆盖前一次)。
|
|
15
|
+
* - 静默 fallback:SessionManager 不可用 / ephemeral session / entry 损坏 → 返 undefined。
|
|
16
|
+
* - 不校验 profile 是否仍存在于 assets——校验留给 transpileActive(transpile 失败会被 session_start catch)。
|
|
17
|
+
* - 用结构类型而非 `ReadonlySessionManager`(该类型不在 pi 包顶层 export.d.ts 里)。 */
|
|
18
|
+
export function readProfileFromSession(sessionManager) {
|
|
19
|
+
try {
|
|
20
|
+
const entries = sessionManager.getEntries();
|
|
21
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
22
|
+
const e = entries[i];
|
|
23
|
+
if (e && e.type === "custom" && e.customType === PT_PROFILE_ENTRY) {
|
|
24
|
+
const data = e.data;
|
|
25
|
+
if (data && typeof data === "object") {
|
|
26
|
+
const profile = data.profile;
|
|
27
|
+
if (typeof profile === "string" && profile.trim()) {
|
|
28
|
+
return profile.trim();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// SessionManager 异常(如不存在 / 旧版 pi)→ 静默
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
/** 把当前 activeProfile 写入 session JSONL(Pi 自带持久化)。
|
|
40
|
+
* - 用 `pi.appendEntry()`(dist/core/extensions/types.d.ts:78 官方 API)。
|
|
41
|
+
* - 失败静默(ephemeral session / 旧版 pi 无此 API)——内存中 activeProfile 仍可用本进程。 */
|
|
42
|
+
export function persistProfileToSession(pi, name) {
|
|
43
|
+
try {
|
|
44
|
+
if (typeof pi.appendEntry !== "function")
|
|
45
|
+
return;
|
|
46
|
+
pi.appendEntry(PT_PROFILE_ENTRY, { profile: name });
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
// P1.4 边界:slog 是 index.ts 本地函数,profile-persist 不反向依赖 index。
|
|
50
|
+
// 直接 console.warn 兜底(与 slog 行为一致)。未来抽 log 工具时统一接入。
|
|
51
|
+
console.warn(`[pt] persistProfileToSession failed:`, { profileName: name, err: errMsg(e) });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AgentContext } from "../schema.js";
|
|
2
|
+
/** v15.x PR2(§8.3):cache 文件名 <pack>__<profile>.agent-context.md,
|
|
3
|
+
* sanitize 非法字符为 _(pack 名已是 kebab-case 通常不需要;profile 名可能含特殊字符)。 */
|
|
4
|
+
declare function cacheFileName(packName: string, profileName: string): string;
|
|
5
|
+
/** 把 AgentContext IR 序列化并写入 <CACHE_DIR>/<pack>__<name>.agent-context.md。
|
|
6
|
+
* 文件头:source-hash: <hash>(缓存失效依据)+ pack: <packName>。 */
|
|
7
|
+
export declare function saveAgentContext(cwd: string, ctx: AgentContext): Promise<string>;
|
|
8
|
+
/** 读 <CACHE_DIR>/<pack>__<name>.agent-context.md 并校验 sourceHash。
|
|
9
|
+
* - 文件不存在 → 触发 §9.4.1 旧缓存清理:检测旧名 <name>.agent-context.md → 删除 → 返 null(重编译)
|
|
10
|
+
* - 文件存在但 hash 不一致 → 返 null(需重编译覆盖)
|
|
11
|
+
* - 命中 → 返 AgentContext IR
|
|
12
|
+
* v15.x PR2(§8.3):签名加 packName 参数;旧名 <profile>.agent-context.md 自动清理迁移。 */
|
|
13
|
+
export declare function loadAgentContext(cwd: string, packName: string, name: string, expectedHash: string): Promise<AgentContext | null>;
|
|
14
|
+
/** v15.x PR2(§8.3):导出 cacheFileName 给测试用。 */
|
|
15
|
+
export { cacheFileName };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// src/render/cache.ts — AgentContext 文件读写 + hash 校验
|
|
2
|
+
//
|
|
3
|
+
// v9 失效策略:sourceHash = hash(Profile + Blueprint + Domains) 组合。
|
|
4
|
+
// 三者任一变化即失效重编译。
|
|
5
|
+
//
|
|
6
|
+
// v15.x PR2(§8.1):sourceHash 加 packs 维度——pack 内容变化触发失效。
|
|
7
|
+
// v15.x PR2(§8.3):cache 文件名 <pack>__<profile>.agent-context.md(sanitize 特殊字符)。
|
|
8
|
+
// v15.x PR2(§9.4.1):旧缓存清理——loadAgentContext 检测旧名 → 删除 → 触发重编译。
|
|
9
|
+
//
|
|
10
|
+
// Phase term-P1:Context IR → AgentContext 改名同步——
|
|
11
|
+
// - 文件后缀 .context.md → .agent-context.md
|
|
12
|
+
// - saveContext → saveAgentContext / loadContext → loadAgentContext
|
|
13
|
+
// - serializeContext → serializeAgentContext / deserializeContext → deserializeAgentContext
|
|
14
|
+
//
|
|
15
|
+
// Phase term-P4.2:cacheDir 改用 constants.CACHE_DIR 常量(替代 Blueprint.compilation.cacheDir)。
|
|
16
|
+
// split 硬编码 single-file(唯一选项,by-injection-point 已 YAGNI 移除)。
|
|
17
|
+
// 签名删 compilation 参数。
|
|
18
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
19
|
+
import { join } from "node:path";
|
|
20
|
+
import { CACHE_DIR } from "../constants.js";
|
|
21
|
+
/** v15.x PR2(§8.3):cache 文件名 <pack>__<profile>.agent-context.md,
|
|
22
|
+
* sanitize 非法字符为 _(pack 名已是 kebab-case 通常不需要;profile 名可能含特殊字符)。 */
|
|
23
|
+
function cacheFileName(packName, profileName) {
|
|
24
|
+
const sanitize = (s) => s.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
25
|
+
return `${sanitize(packName)}__${sanitize(profileName)}.agent-context.md`;
|
|
26
|
+
}
|
|
27
|
+
/** 把 AgentContext IR 序列化并写入 <CACHE_DIR>/<pack>__<name>.agent-context.md。
|
|
28
|
+
* 文件头:source-hash: <hash>(缓存失效依据)+ pack: <packName>。 */
|
|
29
|
+
export async function saveAgentContext(cwd, ctx) {
|
|
30
|
+
const dir = join(cwd, CACHE_DIR);
|
|
31
|
+
await mkdir(dir, { recursive: true });
|
|
32
|
+
// v15.x PR2(§8.3):cache 文件名 <pack>__<profile>.agent-context.md
|
|
33
|
+
const file = join(dir, cacheFileName(ctx.packName, ctx.name));
|
|
34
|
+
const body = serializeAgentContext(ctx);
|
|
35
|
+
await writeFile(file, body, "utf8");
|
|
36
|
+
return file;
|
|
37
|
+
}
|
|
38
|
+
/** 读 <CACHE_DIR>/<pack>__<name>.agent-context.md 并校验 sourceHash。
|
|
39
|
+
* - 文件不存在 → 触发 §9.4.1 旧缓存清理:检测旧名 <name>.agent-context.md → 删除 → 返 null(重编译)
|
|
40
|
+
* - 文件存在但 hash 不一致 → 返 null(需重编译覆盖)
|
|
41
|
+
* - 命中 → 返 AgentContext IR
|
|
42
|
+
* v15.x PR2(§8.3):签名加 packName 参数;旧名 <profile>.agent-context.md 自动清理迁移。 */
|
|
43
|
+
export async function loadAgentContext(cwd, packName, name, expectedHash) {
|
|
44
|
+
const file = join(cwd, CACHE_DIR, cacheFileName(packName, name));
|
|
45
|
+
let raw;
|
|
46
|
+
try {
|
|
47
|
+
raw = await readFile(file, "utf8");
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// §9.4.1:旧缓存清理——新名不存在时尝试旧名
|
|
51
|
+
return await tryLoadOldCacheAndCleanup(cwd, name, expectedHash);
|
|
52
|
+
}
|
|
53
|
+
const ctx = deserializeAgentContext(name, raw);
|
|
54
|
+
if (!ctx)
|
|
55
|
+
return null;
|
|
56
|
+
if (ctx.sourceHash !== expectedHash)
|
|
57
|
+
return null; // 失效,需重编译
|
|
58
|
+
return ctx;
|
|
59
|
+
}
|
|
60
|
+
/** v15.x PR2(§9.4.1):旧缓存清理——升级后旧名 <profile>.agent-context.md 检测 + 删除。
|
|
61
|
+
* 旧文件存在时删除(无论 hash 是否匹配),返 null 触发 saveAgentContext 以新名重写。
|
|
62
|
+
* 未传 packName 也能工作(旧名无 pack 概念,默认归 "prj"——但会被清理掉,不会真用到)。 */
|
|
63
|
+
async function tryLoadOldCacheAndCleanup(cwd, name, _expectedHash) {
|
|
64
|
+
const oldFile = join(cwd, CACHE_DIR, `${name}.agent-context.md`);
|
|
65
|
+
try {
|
|
66
|
+
await readFile(oldFile, "utf8");
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null; // 旧名也不存在——首次加载
|
|
70
|
+
}
|
|
71
|
+
// 旧文件存在——无论 hash 是否匹配都删除(新名格式不同,重编译)
|
|
72
|
+
await rm(oldFile, { force: true });
|
|
73
|
+
return null; // 返 null 触发 saveAgentContext 以新名重写
|
|
74
|
+
}
|
|
75
|
+
// ==================== 序列化/反序列化 ====================
|
|
76
|
+
/** AgentContext IR → 文件内容(含 sourceHash 头 + pack 字段)。 */
|
|
77
|
+
function serializeAgentContext(ctx) {
|
|
78
|
+
const lines = [];
|
|
79
|
+
lines.push("---");
|
|
80
|
+
lines.push(`source-hash: ${ctx.sourceHash}`);
|
|
81
|
+
lines.push(`pack: ${ctx.packName}`); // v15.x PR2 新增
|
|
82
|
+
lines.push(`profile: ${ctx.name}`);
|
|
83
|
+
lines.push(`blueprint: ${ctx.blueprint}`);
|
|
84
|
+
lines.push("---");
|
|
85
|
+
lines.push("");
|
|
86
|
+
for (const [h2Name, content] of Object.entries(ctx.modules)) {
|
|
87
|
+
lines.push(`## ${h2Name}`);
|
|
88
|
+
lines.push("");
|
|
89
|
+
lines.push(content);
|
|
90
|
+
lines.push("");
|
|
91
|
+
}
|
|
92
|
+
return lines.join("\n").trimEnd();
|
|
93
|
+
}
|
|
94
|
+
/** 文件内容 → AgentContext IR。返 null 表示格式损坏。 */
|
|
95
|
+
function deserializeAgentContext(name, raw) {
|
|
96
|
+
const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
97
|
+
if (!fmMatch)
|
|
98
|
+
return null;
|
|
99
|
+
const fm = {};
|
|
100
|
+
for (const line of fmMatch[1].split(/\r?\n/)) {
|
|
101
|
+
const kv = line.match(/^([a-zA-Z_-]+)\s*:\s*(.+)$/);
|
|
102
|
+
if (kv)
|
|
103
|
+
fm[kv[1]] = kv[2].trim();
|
|
104
|
+
}
|
|
105
|
+
const hash = fm["source-hash"];
|
|
106
|
+
const fmName = fm.profile ?? fm.name ?? name;
|
|
107
|
+
const fmBlueprint = fm.blueprint ?? "";
|
|
108
|
+
// v15.x PR2(§9.4.1):旧 cache 无 pack 字段时兜底 "prj"——但 §9.4.1 tryLoadOldCacheAndCleanup
|
|
109
|
+
// 会先删除旧文件,不会真用到兜底。这里兜底仅为 deserialize 容错。
|
|
110
|
+
const fmPack = fm.pack ?? "prj";
|
|
111
|
+
if (!hash)
|
|
112
|
+
return null;
|
|
113
|
+
const body = fmMatch[2];
|
|
114
|
+
const modules = {};
|
|
115
|
+
// 按 ## H2 切分(保留段内换行)
|
|
116
|
+
const sectionRe = /^## (.+)$/gm;
|
|
117
|
+
const matches = [];
|
|
118
|
+
let m;
|
|
119
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: standard regex exec loop pattern
|
|
120
|
+
while ((m = sectionRe.exec(body)) !== null) {
|
|
121
|
+
matches.push({ name: m[1].trim(), start: m.index + m[0].length + 1, end: body.length });
|
|
122
|
+
}
|
|
123
|
+
// 排序每个段的结束位置
|
|
124
|
+
for (let i = 0; i < matches.length; i++) {
|
|
125
|
+
const cur = matches[i];
|
|
126
|
+
const next = matches[i + 1];
|
|
127
|
+
cur.end = next ? next.start - `## ${next.name}`.length - 2 : body.length;
|
|
128
|
+
}
|
|
129
|
+
for (const sec of matches) {
|
|
130
|
+
modules[sec.name] = body.slice(sec.start, sec.end).trim();
|
|
131
|
+
}
|
|
132
|
+
return { name: fmName, blueprint: fmBlueprint, sourceHash: hash, modules, packName: fmPack };
|
|
133
|
+
}
|
|
134
|
+
/** v15.x PR2(§8.3):导出 cacheFileName 给测试用。 */
|
|
135
|
+
export { cacheFileName };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/render/index.ts — Render 后端入口
|
|
2
|
+
//
|
|
3
|
+
// Phase 9.5:v9 后端入口。
|
|
4
|
+
// - session-inject.ts : AgentContext 聚合组 → Session Inject 字符串(按 Blueprint inject=session 聚合)
|
|
5
|
+
// - turn-inject.ts : FlowTemplate + 参数 → Turn Inject(/manual:xxx + /<flow-name>)
|
|
6
|
+
// AgentAdapter 内部映射到 Pi 的 system_prompt/context_message
|
|
7
|
+
// - cache.ts : AgentContext 文件读写 + hash 校验(用 constants.CACHE_DIR 常量,P4.2)
|
|
8
|
+
//
|
|
9
|
+
// Phase term-P1:Context IR → AgentContext 改名同步——
|
|
10
|
+
// - saveContext/loadContext → saveAgentContext/loadAgentContext
|
|
11
|
+
// Phase term-P4.3:render 函数名 + 文件名对齐 session/turn。
|
|
12
|
+
export { renderSessionInject } from "./session-inject.js";
|
|
13
|
+
export { bindFlowTemplate, findFlowInBlueprint, renderTurnInject } from "./turn-inject.js";
|
|
14
|
+
export { saveAgentContext, loadAgentContext } from "./cache.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AgentContext, Blueprint } from "../schema.js";
|
|
2
|
+
/** AgentContext 聚合组聚合 → Session Inject 字符串。
|
|
3
|
+
* v9:遍历 Blueprint.groups,聚合所有 inject=session 的聚合组内容。
|
|
4
|
+
* AgentAdapter 内部把 Session Inject 注入到 Agent 的 session 级(Pi: system_prompt 事件)。 */
|
|
5
|
+
export declare function renderSessionInject(ctx: AgentContext, blueprint: Blueprint): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// src/render/session-inject.ts — AgentContext 聚合组 → Session Inject 字符串
|
|
2
|
+
//
|
|
3
|
+
// Phase 9.5:v9 后端通用化——遍历 Blueprint.groups(不再 Channel.groups),
|
|
4
|
+
// 聚合所有 inject=session 的聚合组内容。
|
|
5
|
+
//
|
|
6
|
+
// renderSessionInject(ctx, blueprint) → string
|
|
7
|
+
// 设计上保留函数包装,便于将来在渲染阶段做最终修整(如日志、注入标记)。
|
|
8
|
+
//
|
|
9
|
+
// Phase term-P1:参数类型 Context → AgentContext(IR 改名同步)。
|
|
10
|
+
// Phase term-P4.3:函数名 renderSystemPrompt → renderSessionInject;inject 语义值 system_prompt → session。
|
|
11
|
+
/** AgentContext 聚合组聚合 → Session Inject 字符串。
|
|
12
|
+
* v9:遍历 Blueprint.groups,聚合所有 inject=session 的聚合组内容。
|
|
13
|
+
* AgentAdapter 内部把 Session Inject 注入到 Agent 的 session 级(Pi: system_prompt 事件)。 */
|
|
14
|
+
export function renderSessionInject(ctx, blueprint) {
|
|
15
|
+
const parts = [];
|
|
16
|
+
for (const group of blueprint.groups) {
|
|
17
|
+
if (group.inject === "session") {
|
|
18
|
+
const content = ctx.modules[group.name];
|
|
19
|
+
if (content)
|
|
20
|
+
parts.push(content);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return parts.join("\n\n");
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AgentContext, Blueprint, Domain, FlowTemplate, Profile } from "../schema.js";
|
|
2
|
+
/** FlowTemplate + 元数据(adapter 附加的 _vars)。_vars 优先于 argument-hint fallback。 */
|
|
3
|
+
export type BoundableTemplate = FlowTemplate & {
|
|
4
|
+
_vars?: string[];
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* 给定 AgentContext + Blueprint + Domains + args(形如 "/manual:pt-quality" 或 "/risk-check 客户A 5000"),
|
|
8
|
+
* 展开目标 Domain 的 Manual 段内容或 FlowTemplate。
|
|
9
|
+
*
|
|
10
|
+
* v9 触发:
|
|
11
|
+
* - /manual:<domain-name>:注入该 Domain 的 Manual 段内容(term→Rule checklist / workflow→FlowTemplate 列表)
|
|
12
|
+
* - /<flow-name> <args>:展开 workflow-Domain 的 FlowTemplate(v8 逻辑保留)
|
|
13
|
+
*
|
|
14
|
+
* Phase term-P4.3:AgentAdapter 内部把 Turn Inject 注入到 Agent 的 turn 级(Pi: input 事件 transform)。
|
|
15
|
+
*
|
|
16
|
+
* v13.x(issue pt-turn-inject-not-profile-scoped):加 profile 参数——
|
|
17
|
+
* - domain 维度:调用方(adapter)应已用 filterDomainsByProfile 过滤 domains,renderTurnInject
|
|
18
|
+
* 不再二次过滤(信任传入的 domains scope)
|
|
19
|
+
* - modules 维度(阶段 2):从 blueprint 的 inject=turn 聚合组 + profile 同名 ProfileGroup.modules 算
|
|
20
|
+
* 白名单,/manual:<domain> 只渲染白名单内的段,/<flow-name> 只在白名单含 Flows 段时查找。
|
|
21
|
+
* profile 为 null 或无 turn 聚合组 → 白名单 null = 不限制(向后兼容)。
|
|
22
|
+
*/
|
|
23
|
+
export declare function renderTurnInject(_ctx: AgentContext, blueprint: Blueprint, domains: Domain[], profile: Profile | null, args: string): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* 把 FlowTemplate 模板 + 用户参数 展开为完整手册 markdown。
|
|
26
|
+
* 错误 / 缺失变量 → 留为字面量(不抛异常)。
|
|
27
|
+
*/
|
|
28
|
+
export declare function bindFlowTemplate(tpl: BoundableTemplate, args: string): string;
|
|
29
|
+
/** 在 Blueprint 聚合组(inject=turn)的引用域中按名查找 FlowTemplate(跨 Domain)。
|
|
30
|
+
* v13.x(issue pt-turn-inject-not-profile-scoped):加 profile 参数——内部算 mods 白名单,
|
|
31
|
+
* 白名单不含 Flows 段时返 undefined(Profile "参考手册"### Modules 未声明 Flows 则 /<flow-name> 触发失效)。
|
|
32
|
+
* Phase term-P4.3 + term-final:inject 语义值 turn(原 context_message → turn → 现聚合组 inject=turn)。 */
|
|
33
|
+
export declare function findFlowInBlueprint(blueprint: Blueprint, domains: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
modules: Record<string, unknown>;
|
|
36
|
+
}>, tplName: string, profile?: Profile | null): BoundableTemplate | undefined;
|