@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,171 @@
|
|
|
1
|
+
// src/compile/resolve-use.ts — v15.x PR5 use Profile 单继承展开
|
|
2
|
+
//
|
|
3
|
+
// 设计源:.pt/docs/designs/pt-asset-pack.md §5.3.2(展开算法)/ §5.3.3(菱形 M4)
|
|
4
|
+
// §5.4(Group 合并)/ §5.5(越权校验)/ §5.6(错误信息)
|
|
5
|
+
//
|
|
6
|
+
// 关键纪律:
|
|
7
|
+
// - parseUseRef 直接复用 parseRef(PR3a 已实现 @pack/name + 无前缀→selfPack 两种语义)
|
|
8
|
+
// - 菱形用路径 visited(每层 new Set(visited)),不加 memo(M4)
|
|
9
|
+
// - 越权校验 use 场景 error(§5.5.1 S7)
|
|
10
|
+
// - mergeProfile blueprint 覆盖用 `||`(frontmatter blueprint 缺省 "" 非 undefined)
|
|
11
|
+
import { parseRef } from "../parse/ref-resolver.js";
|
|
12
|
+
// ==================== §5.6:错误类型 ====================
|
|
13
|
+
/** §5.6 错误类型:use 目标 Profile 不存在。 */
|
|
14
|
+
export class UseTargetNotFound extends Error {
|
|
15
|
+
useRef;
|
|
16
|
+
resolvedKey;
|
|
17
|
+
loadedPacks;
|
|
18
|
+
constructor(useRef, resolvedKey, loadedPacks) {
|
|
19
|
+
super(`Profile use: "${useRef}" — profile not found (resolved: ${resolvedKey}). ` +
|
|
20
|
+
`Loaded profiles: [${loadedPacks.flatMap((p) => p.name).join(", ")}]. ` +
|
|
21
|
+
`Hint: 检查 use 引用的 pack/name 拼写,或确认目标 pack 已加载`);
|
|
22
|
+
this.useRef = useRef;
|
|
23
|
+
this.resolvedKey = resolvedKey;
|
|
24
|
+
this.loadedPacks = loadedPacks;
|
|
25
|
+
this.name = "UseTargetNotFound";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** §5.6 错误类型:use 链循环。 */
|
|
29
|
+
export class UseChainCycle extends Error {
|
|
30
|
+
chain;
|
|
31
|
+
constructor(chain) {
|
|
32
|
+
super(`use chain cycle detected: ${chain.join(" → ")}`);
|
|
33
|
+
this.chain = chain;
|
|
34
|
+
this.name = "UseChainCycle";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** §5.6 错误类型:Blueprint group 越权(use 场景,error 阻断激活)。 */
|
|
38
|
+
export class BlueprintGroupOutOfScope extends Error {
|
|
39
|
+
profileName;
|
|
40
|
+
outOfScopeGroups;
|
|
41
|
+
blueprintName;
|
|
42
|
+
allowedSlots;
|
|
43
|
+
constructor(profileName, outOfScopeGroups, blueprintName, allowedSlots) {
|
|
44
|
+
super(`Profile "${profileName}" expanded groups: [${outOfScopeGroups.join(", ")}] ` +
|
|
45
|
+
`— group(s) not in blueprint "${blueprintName}" slots [${allowedSlots.join(", ")}]. ` +
|
|
46
|
+
`Hint: 在 self.groups 中显式重写越权 group,或改回 use 的 blueprint`);
|
|
47
|
+
this.profileName = profileName;
|
|
48
|
+
this.outOfScopeGroups = outOfScopeGroups;
|
|
49
|
+
this.blueprintName = blueprintName;
|
|
50
|
+
this.allowedSlots = allowedSlots;
|
|
51
|
+
this.name = "BlueprintGroupOutOfScope";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// ==================== §5.3.2:expandProfile 主算法 ====================
|
|
55
|
+
/**
|
|
56
|
+
* §5.3.2 expandProfile——递归展开 use 链。
|
|
57
|
+
*
|
|
58
|
+
* @param self 当前 Profile(已带 sourcePack)
|
|
59
|
+
* @param profileByQualifiedName key="pack/name" 的 Profile 视图(= workingSet.profiles 转换)
|
|
60
|
+
* @param blueprintByQualifiedName key="pack/name" 的 Blueprint 视图(越权校验用)
|
|
61
|
+
* @param loadedPacks 错误信息展示用
|
|
62
|
+
* @param visited 路径 visited(循环检测)——每层递归 new Set(visited),菱形不误报
|
|
63
|
+
* @param ctx adapterCtx(错误信息可走 notify 三通道 fallback——errors 已 throw,此参数备用)
|
|
64
|
+
* @returns 展开后的 Profile(合并 use 链结果,self 优先)
|
|
65
|
+
*/
|
|
66
|
+
export function expandProfile(self, profileByQualifiedName, blueprintByQualifiedName, loadedPacks, visited = new Set(), _ctx) {
|
|
67
|
+
const key = `${self.sourcePack ?? ""}/${self.name}`;
|
|
68
|
+
// 步骤 2:循环检测(路径 visited)
|
|
69
|
+
if (visited.has(key)) {
|
|
70
|
+
throw new UseChainCycle([...visited, key]);
|
|
71
|
+
}
|
|
72
|
+
const nextVisited = new Set(visited);
|
|
73
|
+
nextVisited.add(key);
|
|
74
|
+
// 步骤 4:叶子 Profile——不写 use 直接返回 self(back-compat 早退)
|
|
75
|
+
if (!self.use) {
|
|
76
|
+
return self;
|
|
77
|
+
}
|
|
78
|
+
// 步骤 5:解析 use 引用(复用 parseRef——已含 @prj/@gbl/@pt 别名归一)
|
|
79
|
+
const useRef = parseRef(self.use, self.sourcePack ?? "");
|
|
80
|
+
let useKey = `${useRef.pack}/${useRef.name}`;
|
|
81
|
+
let useProfile = profileByQualifiedName.get(useKey);
|
|
82
|
+
// v15.x PR3a back-compat(§4.4):无前缀 ref 跨 packs fallback(与 transpile findBlueprint 一致)
|
|
83
|
+
// 限定 @pack/name 不 fallback——严格语义
|
|
84
|
+
if (!useProfile && !self.use.startsWith("@")) {
|
|
85
|
+
for (const fallbackPack of loadedPacks.map((p) => p.name)) {
|
|
86
|
+
if (fallbackPack === useRef.pack)
|
|
87
|
+
continue;
|
|
88
|
+
const fallback = profileByQualifiedName.get(`${fallbackPack}/${useRef.name}`);
|
|
89
|
+
if (fallback) {
|
|
90
|
+
useProfile = fallback;
|
|
91
|
+
useKey = `${fallbackPack}/${useRef.name}`;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (!useProfile) {
|
|
97
|
+
throw new UseTargetNotFound(self.use, useKey, loadedPacks);
|
|
98
|
+
}
|
|
99
|
+
// 步骤 6:递归展开 use Profile(每层独立 visited——菱形不误报)
|
|
100
|
+
const useExpanded = expandProfile(useProfile, profileByQualifiedName, blueprintByQualifiedName, loadedPacks, nextVisited, // 路径 visited,非全图 visited(§5.3.3)
|
|
101
|
+
_ctx);
|
|
102
|
+
// 步骤 7:合并 self ⊕ useExpanded(§5.2 表)
|
|
103
|
+
const merged = mergeProfile(self, useExpanded);
|
|
104
|
+
// 步骤 8:越权校验——use 场景 error(§5.5.1 S7)
|
|
105
|
+
validateGroupScopeForUse(merged, self, blueprintByQualifiedName);
|
|
106
|
+
return merged;
|
|
107
|
+
}
|
|
108
|
+
// ==================== §5.2:mergeProfile ====================
|
|
109
|
+
/** §5.2 合并规则:self ⊕ useExpanded。
|
|
110
|
+
* - name:self 强制覆盖(不继承,§5.2 唯一不继承字段)
|
|
111
|
+
* - blueprint:self.blueprint || useExpanded.blueprint(覆盖;空字符串=未写→继承)
|
|
112
|
+
* - tagline:self.tagline ?? useExpanded.tagline(覆盖)
|
|
113
|
+
* - domains:dedupByName([...useExpanded.domains, ...self.domains])(追加,self 优先去重)
|
|
114
|
+
* - groups:mergeGroupsByName(同名 self 替换整个 use group;§5.4) */
|
|
115
|
+
function mergeProfile(self, useExpanded) {
|
|
116
|
+
return {
|
|
117
|
+
name: self.name, // 强制覆盖
|
|
118
|
+
blueprint: self.blueprint || useExpanded.blueprint, // || 而非 ??:空字符串 falsy
|
|
119
|
+
tagline: self.tagline ?? useExpanded.tagline,
|
|
120
|
+
domains: dedupByName([...useExpanded.domains, ...self.domains]),
|
|
121
|
+
groups: mergeGroupsByName(useExpanded.groups, self.groups),
|
|
122
|
+
use: undefined, // 展开后 Profile 不再带 use(已消化,避免下游重复展开)
|
|
123
|
+
sourcePack: self.sourcePack, // 身份不变
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** §5.2 domains 追加去重——后者(self)优先,保留首次插入顺序。 */
|
|
127
|
+
function dedupByName(domains) {
|
|
128
|
+
const seen = new Set();
|
|
129
|
+
const result = [];
|
|
130
|
+
for (const d of domains) {
|
|
131
|
+
if (seen.has(d))
|
|
132
|
+
continue;
|
|
133
|
+
seen.add(d);
|
|
134
|
+
result.push(d);
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
/** §5.4 mergeGroupsByName——self 同名 group 整个替换 use 的(含 modules + domains)。
|
|
139
|
+
* modules 列表是替换不是 union(§5.4 明示)。 */
|
|
140
|
+
function mergeGroupsByName(useGroups, selfGroups) {
|
|
141
|
+
const result = [];
|
|
142
|
+
for (const useGroup of useGroups) {
|
|
143
|
+
const selfMatch = selfGroups.find((g) => g.name === useGroup.name);
|
|
144
|
+
result.push(selfMatch ?? useGroup); // self 替换整个 group
|
|
145
|
+
}
|
|
146
|
+
for (const selfGroup of selfGroups) {
|
|
147
|
+
if (!useGroups.find((g) => g.name === selfGroup.name)) {
|
|
148
|
+
result.push(selfGroup); // self 独有 group 追加
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
// ==================== §5.5:use 场景越权校验 ====================
|
|
154
|
+
/** §5.5 越权校验——use 场景 error。
|
|
155
|
+
* 合并后 groups 的所有 group.name 必须在 self.blueprint 的 slots 里。
|
|
156
|
+
* blueprint 查不到时 return(transpile.ts 会另行报"未知 Blueprint",不重复)。 */
|
|
157
|
+
function validateGroupScopeForUse(merged, self, blueprintByQualifiedName) {
|
|
158
|
+
if (!merged.blueprint)
|
|
159
|
+
return; // 无 blueprint 不校验(与今天一致)
|
|
160
|
+
const { pack: bpPack, name: bpName } = parseRef(merged.blueprint, self.sourcePack ?? "");
|
|
161
|
+
const bpEntry = blueprintByQualifiedName.get(`${bpPack}/${bpName}`);
|
|
162
|
+
if (!bpEntry)
|
|
163
|
+
return; // blueprint 查不到不校验(transpile 另行报错)
|
|
164
|
+
const allowedSlots = bpEntry.asset.groups.map((g) => g.name);
|
|
165
|
+
const outOfScope = merged.groups
|
|
166
|
+
.map((g) => g.name)
|
|
167
|
+
.filter((name) => !allowedSlots.includes(name));
|
|
168
|
+
if (outOfScope.length > 0) {
|
|
169
|
+
throw new BlueprintGroupOutOfScope(merged.name, outOfScope, merged.blueprint, allowedSlots);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Checklist, ExternalRef, FlowTemplate, Rule, Term } from "../schema.js";
|
|
2
|
+
/** unknown 是否为数组。 */
|
|
3
|
+
export declare function isArray(x: unknown): x is unknown[];
|
|
4
|
+
/** unknown 是否为非空数组。 */
|
|
5
|
+
export declare function isNonEmptyArray<T>(x: unknown): x is T[];
|
|
6
|
+
/** unknown 是否为索引签名对象(非数组的 object)。 */
|
|
7
|
+
export declare function isRecord(x: unknown): x is Record<string, unknown>;
|
|
8
|
+
/** unknown 是否为 Term[]。 */
|
|
9
|
+
export declare function isTermArray(x: unknown): x is Term[];
|
|
10
|
+
/** unknown 是否为 Rule[]。 */
|
|
11
|
+
export declare function isRuleArray(x: unknown): x is Rule[];
|
|
12
|
+
/** 校验元素是否具备 FlowTemplate 最小形状({ name, intent, steps[] })。 */
|
|
13
|
+
export declare function isFlowTemplateLike(x: unknown): x is FlowTemplate;
|
|
14
|
+
/** unknown 是否为 FlowTemplate[]。 */
|
|
15
|
+
export declare function isFlowTemplateArray(x: unknown): x is FlowTemplate[];
|
|
16
|
+
/** unknown 是否为 Trigger 项[]。 */
|
|
17
|
+
export declare function isTriggerItemArray(x: unknown): x is Array<{
|
|
18
|
+
name: string;
|
|
19
|
+
desc?: string;
|
|
20
|
+
hint?: string;
|
|
21
|
+
}>;
|
|
22
|
+
/** unknown 是否为 Checklist[]。 */
|
|
23
|
+
export declare function isChecklistArray(x: unknown): x is Checklist[];
|
|
24
|
+
export declare function isExternalRefArray(x: unknown): x is ExternalRef[];
|
|
25
|
+
/** 通用 fallback 形态:H3 + name + desc 列表项(用于未注册 type 的聚合段输出)。 */
|
|
26
|
+
export declare function isNamedItemArray(x: unknown): x is Array<{
|
|
27
|
+
name: string;
|
|
28
|
+
desc?: string;
|
|
29
|
+
}>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// src/compile/type-guards.ts — Domain.modules 内容类型守卫(pt-quality #1)
|
|
2
|
+
//
|
|
3
|
+
// Domain.modules 的 H2 段内容是 unknown(type hole),消费者用 type guard 收窄,
|
|
4
|
+
// 不用 as 断言。type guard 集中管理,新增内容类型加一个 isXxxArray。
|
|
5
|
+
//
|
|
6
|
+
// 与 schema.ts 的区别:schema.ts 定义契约(Term/Rule/FlowTemplate 等结构),
|
|
7
|
+
// type-guards.ts 定义运行时收窄("这个 unknown 是不是 Term[]?")。
|
|
8
|
+
// ==================== 通用守卫 ====================
|
|
9
|
+
/** unknown 是否为数组。 */
|
|
10
|
+
export function isArray(x) {
|
|
11
|
+
return Array.isArray(x);
|
|
12
|
+
}
|
|
13
|
+
/** unknown 是否为非空数组。 */
|
|
14
|
+
export function isNonEmptyArray(x) {
|
|
15
|
+
return Array.isArray(x) && x.length > 0;
|
|
16
|
+
}
|
|
17
|
+
/** unknown 是否为索引签名对象(非数组的 object)。 */
|
|
18
|
+
export function isRecord(x) {
|
|
19
|
+
return !!x && typeof x === "object" && !Array.isArray(x);
|
|
20
|
+
}
|
|
21
|
+
// ==================== Term[] 守卫 ====================
|
|
22
|
+
/** 校验元素是否具备 Term 最小形状({ name: string })。
|
|
23
|
+
* v9.2:Term 加可选 fields/note 后仍只检查 name(最小形状),不强制 desc——
|
|
24
|
+
* 这样 parse 阶段产出的 Term 即使 desc 为空也过关,renderer 走 `else lines.push("- name")` 分支。
|
|
25
|
+
* fields/note 是可选,向后兼容旧 IR。 */
|
|
26
|
+
function isTermLike(x) {
|
|
27
|
+
return !!x && typeof x === "object" && typeof x.name === "string";
|
|
28
|
+
}
|
|
29
|
+
/** unknown 是否为 Term[]。 */
|
|
30
|
+
export function isTermArray(x) {
|
|
31
|
+
return Array.isArray(x) && x.every(isTermLike);
|
|
32
|
+
}
|
|
33
|
+
// ==================== Rule[] 守卫 ====================
|
|
34
|
+
/** 校验元素是否具备 Rule 最小形状({ type: "ban"|"invariant", check: string })。 */
|
|
35
|
+
function isRuleLike(x) {
|
|
36
|
+
if (!x || typeof x !== "object")
|
|
37
|
+
return false;
|
|
38
|
+
const r = x;
|
|
39
|
+
return (r.type === "ban" || r.type === "invariant") && typeof r.check === "string";
|
|
40
|
+
}
|
|
41
|
+
/** unknown 是否为 Rule[]。 */
|
|
42
|
+
export function isRuleArray(x) {
|
|
43
|
+
return Array.isArray(x) && x.every(isRuleLike);
|
|
44
|
+
}
|
|
45
|
+
// ==================== FlowTemplate[] 守卫 ====================
|
|
46
|
+
/** 校验元素是否具备 FlowTemplate 最小形状({ name, intent, steps[] })。 */
|
|
47
|
+
export function isFlowTemplateLike(x) {
|
|
48
|
+
if (!x || typeof x !== "object")
|
|
49
|
+
return false;
|
|
50
|
+
const t = x;
|
|
51
|
+
return typeof t.name === "string" && typeof t.intent === "string" && Array.isArray(t.steps);
|
|
52
|
+
}
|
|
53
|
+
/** unknown 是否为 FlowTemplate[]。 */
|
|
54
|
+
export function isFlowTemplateArray(x) {
|
|
55
|
+
return Array.isArray(x) && x.every(isFlowTemplateLike);
|
|
56
|
+
}
|
|
57
|
+
// ==================== Trigger 项[] 守卫 ====================
|
|
58
|
+
/** Trigger 段形态:H3 项数组(每项 { name, desc?, hint? })。
|
|
59
|
+
* v9 新增——Trigger 段是索引段,H3 + desc/hint 列表。 */
|
|
60
|
+
function isTriggerItemLike(x) {
|
|
61
|
+
if (!x || typeof x !== "object")
|
|
62
|
+
return false;
|
|
63
|
+
const t = x;
|
|
64
|
+
return (typeof t.name === "string" &&
|
|
65
|
+
(t.desc === undefined || typeof t.desc === "string") &&
|
|
66
|
+
(t.hint === undefined || typeof t.hint === "string"));
|
|
67
|
+
}
|
|
68
|
+
/** unknown 是否为 Trigger 项[]。 */
|
|
69
|
+
export function isTriggerItemArray(x) {
|
|
70
|
+
return Array.isArray(x) && x.every(isTriggerItemLike);
|
|
71
|
+
}
|
|
72
|
+
// ==================== Checklist[] 守卫(Phase term-P9.2) ====================
|
|
73
|
+
/** Phase term-P9.2:校验 Checklist 最小形状({ name: string, items: string[] })。 */
|
|
74
|
+
function isChecklistLike(x) {
|
|
75
|
+
if (!x || typeof x !== "object")
|
|
76
|
+
return false;
|
|
77
|
+
const c = x;
|
|
78
|
+
return (typeof c.name === "string" &&
|
|
79
|
+
Array.isArray(c.items) &&
|
|
80
|
+
c.items.every((i) => typeof i === "string"));
|
|
81
|
+
}
|
|
82
|
+
/** unknown 是否为 Checklist[]。 */
|
|
83
|
+
export function isChecklistArray(x) {
|
|
84
|
+
return Array.isArray(x) && x.every(isChecklistLike);
|
|
85
|
+
}
|
|
86
|
+
// ==================== ExternalRef[] 守卫 ====================
|
|
87
|
+
function isExternalRefLike(x) {
|
|
88
|
+
if (!x || typeof x !== "object")
|
|
89
|
+
return false;
|
|
90
|
+
const r = x;
|
|
91
|
+
return typeof r.name === "string" && typeof r.path === "string";
|
|
92
|
+
}
|
|
93
|
+
export function isExternalRefArray(x) {
|
|
94
|
+
return Array.isArray(x) && x.every(isExternalRefLike);
|
|
95
|
+
}
|
|
96
|
+
// ==================== 通用 fallback 守卫(带 name 字段的项) ====================
|
|
97
|
+
/** 通用 fallback 形态:H3 + name + desc 列表项(用于未注册 type 的聚合段输出)。 */
|
|
98
|
+
export function isNamedItemArray(x) {
|
|
99
|
+
if (!Array.isArray(x))
|
|
100
|
+
return false;
|
|
101
|
+
return x.every((it) => {
|
|
102
|
+
if (!it || typeof it !== "object")
|
|
103
|
+
return false;
|
|
104
|
+
const t = it;
|
|
105
|
+
return typeof t.name === "string" && (t.desc === undefined || typeof t.desc === "string");
|
|
106
|
+
});
|
|
107
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** 读项目 settings.json 的指定 dotted key。文件不存在/解析失败 → undefined */
|
|
2
|
+
export declare function readProjectSetting<T = unknown>(cwd: string, dottedKey: string): Promise<T | undefined>;
|
|
3
|
+
/** 列出可选 Profile 名:项目 + 内建合并,同名时项目覆盖内建。
|
|
4
|
+
* 必须与 mdAdapter.load 的合并语义一致——否则选择器/补全看不到内建 profile
|
|
5
|
+
* (如 builtin `pt`),但 transpile 又能加载,造成“选不到却能手敲”的不一致
|
|
6
|
+
* (issue: 内建 pt 无法通过 pt-profile 选择)。 */
|
|
7
|
+
export declare function listProfiles(cwd: string): Promise<string[]>;
|
|
8
|
+
export interface ProfileMeta {
|
|
9
|
+
name: string;
|
|
10
|
+
tagline?: string;
|
|
11
|
+
source: "project" | "settings" | "global" | "builtin";
|
|
12
|
+
/** v15.x PR3(§7.2):pack 身份(reserved 短名 prj/gbl/pt 或 manifest.name)。 */
|
|
13
|
+
pack: string;
|
|
14
|
+
/** v15.x §4.4.4(缺口 4):reserved pack 的位置别名(prj/gbl/pt),非 reserved 为 undefined。
|
|
15
|
+
* UI 显示层用——reserved 显位置别名,settings 显 pack 名。 */
|
|
16
|
+
reservedAlias?: "prj" | "gbl" | "pt";
|
|
17
|
+
}
|
|
18
|
+
export declare function listProfilesWithTagline(cwd: string): Promise<ProfileMeta[]>;
|
|
19
|
+
/** 把 ProfileMeta 列表转成选择器展示标签(`[@pack] name — tagline`,§7.3)。
|
|
20
|
+
* v15.x §4.4.4(缺口 4):reserved pack 显 reservedAlias(位置别名),settings pack 显 pack 名。
|
|
21
|
+
* tagline 缺省 → 纯名。空 tagline 也走纯名。 */
|
|
22
|
+
export declare function formatProfileLabels(profiles: ProfileMeta[]): string[];
|
|
23
|
+
/** 自动探测:只看项目级 Profile,不把内建 guide 计入用户项目选择。 */
|
|
24
|
+
export declare function detectSingleProfile(cwd: string): Promise<string | null>;
|
|
25
|
+
/** 默认兜底:项目无单 Profile 时,读 settings `pt.default-profile`。
|
|
26
|
+
* - 未设 → 返回内建 "guide"(装包即用,真默认)
|
|
27
|
+
* - "none" → 返回 null(用户明确不要自动加载)
|
|
28
|
+
* - 具体名 → 返回该名(用户自定义默认 Profile)
|
|
29
|
+
* 与 detectSingleProfile 分离:auto 是项目探测(pickedFrom="auto"),
|
|
30
|
+
* default 是兜底机制(pickedFrom="default"),来源可观测。 */
|
|
31
|
+
export declare function detectDefaultProfile(cwd: string): Promise<string | null>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// src/config.ts — 读项目 settings + 探测 Profile
|
|
2
|
+
// ExtensionAPI 无 getSettings,需自读 .pi/settings.json(用 CONFIG_DIR_NAME,不硬编码 .pi)。
|
|
3
|
+
//
|
|
4
|
+
// v9:用户面是 Profile(.pt/assets/profiles/*.profile.md),不是 Blueprint。
|
|
5
|
+
//
|
|
6
|
+
// v14.x(tagline):加 listProfilesWithTagline() — /pt-profile 选择器展示 tagline 用。
|
|
7
|
+
import { CONFIG_DIR_NAME } from "@earendil-works/pi-coding-agent";
|
|
8
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { BUILTIN_ASSETS_DIR, PROFILES_DIR } from "./constants.js";
|
|
11
|
+
import { isRecord } from "./compile/type-guards.js";
|
|
12
|
+
/** 读项目 settings.json 的指定 dotted key。文件不存在/解析失败 → undefined */
|
|
13
|
+
export async function readProjectSetting(cwd, dottedKey) {
|
|
14
|
+
const path = join(cwd, CONFIG_DIR_NAME, "settings.json");
|
|
15
|
+
let json;
|
|
16
|
+
try {
|
|
17
|
+
const raw = await readFile(path, "utf8");
|
|
18
|
+
json = JSON.parse(raw);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return dottedKey.split(".").reduce((acc, k) => {
|
|
24
|
+
if (isRecord(acc) && k in acc) {
|
|
25
|
+
return acc[k];
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}, json);
|
|
29
|
+
}
|
|
30
|
+
/** 列出可选 Profile 名:项目 + 内建合并,同名时项目覆盖内建。
|
|
31
|
+
* 必须与 mdAdapter.load 的合并语义一致——否则选择器/补全看不到内建 profile
|
|
32
|
+
* (如 builtin `pt`),但 transpile 又能加载,造成“选不到却能手敲”的不一致
|
|
33
|
+
* (issue: 内建 pt 无法通过 pt-profile 选择)。 */
|
|
34
|
+
export async function listProfiles(cwd) {
|
|
35
|
+
const project = await listProfileNamesIn(join(cwd, PROFILES_DIR));
|
|
36
|
+
const builtin = await listProfileNamesIn(join(BUILTIN_ASSETS_DIR, "profiles"));
|
|
37
|
+
const projectNames = new Set(project);
|
|
38
|
+
const merged = [...project, ...builtin.filter((n) => !projectNames.has(n))];
|
|
39
|
+
return merged.sort();
|
|
40
|
+
}
|
|
41
|
+
/** 扫描某个 profiles 目录提取 Profile 名(去 .profile.md 后缀)。目录不存在返空。 */
|
|
42
|
+
async function listProfileNamesIn(dir) {
|
|
43
|
+
try {
|
|
44
|
+
const files = await readdir(dir);
|
|
45
|
+
const names = [];
|
|
46
|
+
for (const f of files) {
|
|
47
|
+
if (!f.endsWith(".md"))
|
|
48
|
+
continue;
|
|
49
|
+
const base = f.slice(0, -3); // 去 .md
|
|
50
|
+
if (base.endsWith(".profile")) {
|
|
51
|
+
names.push(base.slice(0, -8)); // 去 .profile
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return names;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** 从某个 profile 文件里粗读 tagline(只读 frontmatter,不走全 parse)。
|
|
61
|
+
* 用途:/pt-profile 选择器拼选项 — 不必全 parse profile (可能慢)。
|
|
62
|
+
* 返回 undefined 表示无 tagline 或读失败(缺省走纯名选项)。 */
|
|
63
|
+
// v15.x PR3:readTaglineFromFile 在新 listProfilesWithTagline 实现中已不用(pack.loadProfiles
|
|
64
|
+
// 返 Profile 对象含 tagline 字段),但保留作为其他代码(readProjectSetting)的辅助。
|
|
65
|
+
// 移除 unused:原 _readTaglineFromFile 实现见 git history。
|
|
66
|
+
/** Profile 名 + tagline 列表(项目 + builtin 合并;同名项目覆盖)。
|
|
67
|
+
* builtin 没 tagline 的 profile 返 undefined(选择器退化为纯名)。
|
|
68
|
+
* v15.x PR3(§7.2):加 pack + source(4 类)——选择器显示 [@pack] 前缀;source 区分打包类型。 */
|
|
69
|
+
/** v15.x §4.4.4(位置 alias 表):reserved pack 的位置别名。reserved pack 才有,非 reserved 为 undefined。
|
|
70
|
+
* UI 显示层用——reserved 显位置别名,settings 显 pack 名(§4.4.4 双层语义)。 */
|
|
71
|
+
const RESERVED_ALIAS = new Map([
|
|
72
|
+
["project", "prj"],
|
|
73
|
+
["global", "gbl"],
|
|
74
|
+
["builtin", "pt"],
|
|
75
|
+
]);
|
|
76
|
+
export async function listProfilesWithTagline(cwd) {
|
|
77
|
+
// v15.x PR4(§4.4.3 #5 + §6.1):扫所有 pack 含 settings
|
|
78
|
+
// 顺序与 mdAdapter.load 一致(settings 倒序后者赢)——选择器展示优先级与实际加载一致
|
|
79
|
+
const { loadProjectPack, loadSettingsPacks, loadGlobalPack, loadBuiltinPack } = await import("./asset-pack/loader.js");
|
|
80
|
+
const projectPack = await loadProjectPack(cwd);
|
|
81
|
+
const settingsPacks = await loadSettingsPacks(cwd);
|
|
82
|
+
const globalPack = await loadGlobalPack();
|
|
83
|
+
const builtinPack = await loadBuiltinPack();
|
|
84
|
+
const packs = [projectPack, ...settingsPacks.slice().reverse(), globalPack, builtinPack];
|
|
85
|
+
const metas = [];
|
|
86
|
+
for (const pack of packs) {
|
|
87
|
+
const profiles = await pack.loadProfiles();
|
|
88
|
+
for (const p of profiles) {
|
|
89
|
+
if (metas.some((m) => m.name === p.name))
|
|
90
|
+
continue; // 前者赢
|
|
91
|
+
metas.push({
|
|
92
|
+
name: p.name,
|
|
93
|
+
tagline: p.tagline,
|
|
94
|
+
source: pack.source,
|
|
95
|
+
pack: pack.name,
|
|
96
|
+
reservedAlias: RESERVED_ALIAS.get(pack.source),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
metas.sort((a, b) => a.name.localeCompare(b.name));
|
|
101
|
+
return metas;
|
|
102
|
+
}
|
|
103
|
+
/** 把 ProfileMeta 列表转成选择器展示标签(`[@pack] name — tagline`,§7.3)。
|
|
104
|
+
* v15.x §4.4.4(缺口 4):reserved pack 显 reservedAlias(位置别名),settings pack 显 pack 名。
|
|
105
|
+
* tagline 缺省 → 纯名。空 tagline 也走纯名。 */
|
|
106
|
+
export function formatProfileLabels(profiles) {
|
|
107
|
+
return profiles.map((p) => {
|
|
108
|
+
const label = p.reservedAlias ?? p.pack;
|
|
109
|
+
const prefix = label ? `[@${label}] ` : "";
|
|
110
|
+
const tagline = p.tagline ? ` — ${p.tagline}` : "";
|
|
111
|
+
return `${prefix}${p.name}${tagline}`;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/** 自动探测:只看项目级 Profile,不把内建 guide 计入用户项目选择。 */
|
|
115
|
+
export async function detectSingleProfile(cwd) {
|
|
116
|
+
const project = await listProfileNamesIn(join(cwd, PROFILES_DIR));
|
|
117
|
+
return project.length === 1 ? project[0] : null;
|
|
118
|
+
}
|
|
119
|
+
/** 默认兜底:项目无单 Profile 时,读 settings `pt.default-profile`。
|
|
120
|
+
* - 未设 → 返回内建 "guide"(装包即用,真默认)
|
|
121
|
+
* - "none" → 返回 null(用户明确不要自动加载)
|
|
122
|
+
* - 具体名 → 返回该名(用户自定义默认 Profile)
|
|
123
|
+
* 与 detectSingleProfile 分离:auto 是项目探测(pickedFrom="auto"),
|
|
124
|
+
* default 是兜底机制(pickedFrom="default"),来源可观测。 */
|
|
125
|
+
export async function detectDefaultProfile(cwd) {
|
|
126
|
+
const setting = await readProjectSetting(cwd, "pt.default-profile");
|
|
127
|
+
if (setting === undefined)
|
|
128
|
+
return "guide"; // 未设 → 内建兜底
|
|
129
|
+
if (setting === "none")
|
|
130
|
+
return null; // 明确关闭
|
|
131
|
+
const trimmed = setting.trim();
|
|
132
|
+
return trimmed || null;
|
|
133
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** .pt/ 资产根目录 */
|
|
2
|
+
export declare const ASSETS_DIR = ".pt/assets";
|
|
3
|
+
/** Domain md 目录(type=term/workflow/stack/扩展) */
|
|
4
|
+
export declare const DOMAINS_DIR = ".pt/assets/domains";
|
|
5
|
+
/** Blueprint yaml 目录(v9 结构层——groups: name + inject + modules,跨项目复用) */
|
|
6
|
+
export declare const BLUEPRINTS_DIR = ".pt/assets/blueprints";
|
|
7
|
+
/** Profile md 目录(v9 配置层——blueprint + domains + groups H2 实例化) */
|
|
8
|
+
export declare const PROFILES_DIR = ".pt/assets/profiles";
|
|
9
|
+
/** AgentContext 物理缓存目录(Blueprint.compilation.cacheDir 默认值)。
|
|
10
|
+
* Phase term-P1:.pt/cache/contexts → .pt/cache/agent-contexts(Context IR 改名 AgentContext 同步)。 */
|
|
11
|
+
export declare const CACHE_DIR = ".pt/cache/agent-contexts";
|
|
12
|
+
/** /pt raw 输出目录(segment dump) */
|
|
13
|
+
export declare const RAW_DIR = ".pt/cache/raws";
|
|
14
|
+
/** /pt full 输出目录(完整 systemPrompt dump) */
|
|
15
|
+
export declare const FULL_DIR = ".pt/cache/fulls";
|
|
16
|
+
/** /pt manual 输出目录(手册实例文档) */
|
|
17
|
+
export declare const MANUAL_DIR = ".pt/manuals";
|
|
18
|
+
export declare const BUILTIN_ASSETS_DIR: string;
|
|
19
|
+
/** Domain 的 Scene 段(Phase term-P9.3:统一为 Term[],含可选 path 字段)
|
|
20
|
+
* 拆 Type 后 Scene 不再按 type 分发 schema——一个 H2 段一个 schema(Term[])。 */
|
|
21
|
+
export declare const MOD_SCENE = "Scene";
|
|
22
|
+
/** Domain 的 Trigger 段(v9 索引段——H3 + desc/hint 列表) */
|
|
23
|
+
export declare const MOD_TRIGGER = "Trigger";
|
|
24
|
+
/** Domain 的 Rules 段(Phase term-P9.2:从 Manual 拆出)—— Rule[](pt-quality 等) */
|
|
25
|
+
export declare const MOD_RULES = "Rules";
|
|
26
|
+
/** Domain 的 Flows 段(Phase term-P9.2:从 Manual 拆出)—— FlowTemplate[](dev-workflow 等) */
|
|
27
|
+
export declare const MOD_FLOWS = "Flows";
|
|
28
|
+
/** Domain 的 Checklists 段(Phase term-P9.2:新增)—— Checklist[](pt-collab 等) */
|
|
29
|
+
export declare const MOD_CHECKLISTS = "Checklists";
|
|
30
|
+
/** Phase term-P8:会话参与者信息段——me Domain 专用,Term[] 与 Scene 同构,复用 renderSceneModule。
|
|
31
|
+
* 与 Scene 的区别:语义上是"会话参与者描述"(who am I + goal + how we collaborate),
|
|
32
|
+
* 不是"领域场景元数据"。拆出来让 Blueprint 模块清单更具语义化。 */
|
|
33
|
+
export declare const MOD_PARTICIPANT = "Participant";
|
|
34
|
+
/** Phase modules-to-profile-complete:user-info Domain 专用段名。Phase term-P8 时叫 "Participant",
|
|
35
|
+
* 本 phase 拆分为 "User"(user-info)和 "Agent"(agent-info)——段名 = 命名空间,
|
|
36
|
+
* 限定到单个 domain 通过专用段名实现,避免 modName 形态 3(domain:段.项)的重复写引用。 */
|
|
37
|
+
export declare const MOD_USER = "User";
|
|
38
|
+
/** agent-info Domain 专用段名——同上拆分理由。 */
|
|
39
|
+
export declare const MOD_AGENT = "Agent";
|
|
40
|
+
/** Domain 的 Term 段(fallback term 形态,未指定 type 默认走 Term[]) */
|
|
41
|
+
export declare const MOD_TERM = "Term";
|
|
42
|
+
/** Blueprint 文件名后缀标记(v9 命名约定:<name>.blueprint.yaml,Phase term-P4.5)
|
|
43
|
+
* 用于识别 Blueprint 资产——保留 .blueprint 部分以便从文件名提取蓝本名。 */
|
|
44
|
+
export declare const SUFFIX_BLUEPRINT = ".blueprint";
|
|
45
|
+
/** Blueprint 文件扩展名(Phase term-P4.5:载体从 .md 转 .yaml) */
|
|
46
|
+
export declare const SUFFIX_BLUEPRINT_YAML = ".blueprint.yaml";
|
|
47
|
+
/** Profile 文件名后缀(v9 命名约定:<name>.profile.md) */
|
|
48
|
+
export declare const SUFFIX_PROFILE = ".profile";
|
|
49
|
+
/** Domain 文件后缀(.md 即可,无 type 后缀) */
|
|
50
|
+
export declare const SUFFIX_MD = ".md";
|
|
51
|
+
/** Pi Agent adapter 名 */
|
|
52
|
+
export declare const AGENT_PI = "pi";
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// src/constants.ts — 路径常量 + Domain H2 段名常量(pt-quality #4 + #5)
|
|
2
|
+
//
|
|
3
|
+
// 路径常量集中管理:资产/缓存/输出目录
|
|
4
|
+
// 模块名常量:Domain 的 H2 段名(Scene/Trigger/Manual/Term)
|
|
5
|
+
//
|
|
6
|
+
// 注意:聚合组名(Blueprint groups[].name,如"会话背景"/"参考手册")是人类自定义的语义名,
|
|
7
|
+
// 不应常量化——常量化的是 Domain 内的 H2 段名(v9 资产的标准段)。
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
// ==================== 路径常量 ====================
|
|
11
|
+
//
|
|
12
|
+
// .pt/ 目录布局规范(v11 重排):
|
|
13
|
+
// .pt/assets/ 入 git — 转译资产(domains / blueprints / profiles)
|
|
14
|
+
// .pt/docs/ 入 git — 文档(designs 设计与执行 / issues 问题跟踪)
|
|
15
|
+
// .pt/manuals/ gitignore — pt_manual 工作文档
|
|
16
|
+
// .pt/cache/ gitignore — 运行产物(contexts 编译 / fulls 完整 prompt / raws segment)
|
|
17
|
+
// .pt/logs/ gitignore — NDJSON trace
|
|
18
|
+
//
|
|
19
|
+
// 规范源:asset-workflow domain 的 `directory-layout` 场景是 .pt/ 布局的声明式 spec
|
|
20
|
+
// (用户可改该 Domain 调整布局)。当前代码路径仍读本文件常量;未来计划让转译层
|
|
21
|
+
// 直接读 Domain 配置(届时删除下方硬编码,由 parse → compile 注入)。
|
|
22
|
+
// 改路径时务必同步改 asset-workflow.md 的 directory-layout 场景。
|
|
23
|
+
/** .pt/ 资产根目录 */
|
|
24
|
+
export const ASSETS_DIR = ".pt/assets";
|
|
25
|
+
/** Domain md 目录(type=term/workflow/stack/扩展) */
|
|
26
|
+
export const DOMAINS_DIR = `${ASSETS_DIR}/domains`;
|
|
27
|
+
/** Blueprint yaml 目录(v9 结构层——groups: name + inject + modules,跨项目复用) */
|
|
28
|
+
export const BLUEPRINTS_DIR = `${ASSETS_DIR}/blueprints`;
|
|
29
|
+
/** Profile md 目录(v9 配置层——blueprint + domains + groups H2 实例化) */
|
|
30
|
+
export const PROFILES_DIR = `${ASSETS_DIR}/profiles`;
|
|
31
|
+
/** AgentContext 物理缓存目录(Blueprint.compilation.cacheDir 默认值)。
|
|
32
|
+
* Phase term-P1:.pt/cache/contexts → .pt/cache/agent-contexts(Context IR 改名 AgentContext 同步)。 */
|
|
33
|
+
export const CACHE_DIR = ".pt/cache/agent-contexts";
|
|
34
|
+
/** /pt raw 输出目录(segment dump) */
|
|
35
|
+
export const RAW_DIR = ".pt/cache/raws";
|
|
36
|
+
/** /pt full 输出目录(完整 systemPrompt dump) */
|
|
37
|
+
export const FULL_DIR = ".pt/cache/fulls";
|
|
38
|
+
/** /pt manual 输出目录(手册实例文档) */
|
|
39
|
+
export const MANUAL_DIR = ".pt/manuals";
|
|
40
|
+
/** 内建资产根目录(随 npm 包发布,跨项目复用)。
|
|
41
|
+
* 用 import.meta.url 定位包自身路径——不能用 cwd 相对路径(外部用户 cwd ≠ 包路径)。
|
|
42
|
+
* mdAdapter fallback:项目 .pt/assets/ 优先,内建补充;同名时项目覆盖内建。 */
|
|
43
|
+
const SRC_DIR = dirname(fileURLToPath(import.meta.url));
|
|
44
|
+
export const BUILTIN_ASSETS_DIR = join(SRC_DIR, "builtin", "assets");
|
|
45
|
+
// ==================== Domain H2 段名常量 ====================
|
|
46
|
+
/** Domain 的 Scene 段(Phase term-P9.3:统一为 Term[],含可选 path 字段)
|
|
47
|
+
* 拆 Type 后 Scene 不再按 type 分发 schema——一个 H2 段一个 schema(Term[])。 */
|
|
48
|
+
export const MOD_SCENE = "Scene";
|
|
49
|
+
/** Domain 的 Trigger 段(v9 索引段——H3 + desc/hint 列表) */
|
|
50
|
+
export const MOD_TRIGGER = "Trigger";
|
|
51
|
+
/** Domain 的 Rules 段(Phase term-P9.2:从 Manual 拆出)—— Rule[](pt-quality 等) */
|
|
52
|
+
export const MOD_RULES = "Rules";
|
|
53
|
+
/** Domain 的 Flows 段(Phase term-P9.2:从 Manual 拆出)—— FlowTemplate[](dev-workflow 等) */
|
|
54
|
+
export const MOD_FLOWS = "Flows";
|
|
55
|
+
/** Domain 的 Checklists 段(Phase term-P9.2:新增)—— Checklist[](pt-collab 等) */
|
|
56
|
+
export const MOD_CHECKLISTS = "Checklists";
|
|
57
|
+
/** Phase term-P8:会话参与者信息段——me Domain 专用,Term[] 与 Scene 同构,复用 renderSceneModule。
|
|
58
|
+
* 与 Scene 的区别:语义上是"会话参与者描述"(who am I + goal + how we collaborate),
|
|
59
|
+
* 不是"领域场景元数据"。拆出来让 Blueprint 模块清单更具语义化。 */
|
|
60
|
+
export const MOD_PARTICIPANT = "Participant";
|
|
61
|
+
/** Phase modules-to-profile-complete:user-info Domain 专用段名。Phase term-P8 时叫 "Participant",
|
|
62
|
+
* 本 phase 拆分为 "User"(user-info)和 "Agent"(agent-info)——段名 = 命名空间,
|
|
63
|
+
* 限定到单个 domain 通过专用段名实现,避免 modName 形态 3(domain:段.项)的重复写引用。 */
|
|
64
|
+
export const MOD_USER = "User";
|
|
65
|
+
/** agent-info Domain 专用段名——同上拆分理由。 */
|
|
66
|
+
export const MOD_AGENT = "Agent";
|
|
67
|
+
/** Domain 的 Term 段(fallback term 形态,未指定 type 默认走 Term[]) */
|
|
68
|
+
export const MOD_TERM = "Term";
|
|
69
|
+
// ==================== 资产文件名后缀 ====================
|
|
70
|
+
/** Blueprint 文件名后缀标记(v9 命名约定:<name>.blueprint.yaml,Phase term-P4.5)
|
|
71
|
+
* 用于识别 Blueprint 资产——保留 .blueprint 部分以便从文件名提取蓝本名。 */
|
|
72
|
+
export const SUFFIX_BLUEPRINT = ".blueprint";
|
|
73
|
+
/** Blueprint 文件扩展名(Phase term-P4.5:载体从 .md 转 .yaml) */
|
|
74
|
+
export const SUFFIX_BLUEPRINT_YAML = ".blueprint.yaml";
|
|
75
|
+
/** Profile 文件名后缀(v9 命名约定:<name>.profile.md) */
|
|
76
|
+
export const SUFFIX_PROFILE = ".profile";
|
|
77
|
+
/** Domain 文件后缀(.md 即可,无 type 后缀) */
|
|
78
|
+
export const SUFFIX_MD = ".md";
|
|
79
|
+
// ==================== Agent 名常量 ====================
|
|
80
|
+
/** Pi Agent adapter 名 */
|
|
81
|
+
export const AGENT_PI = "pi";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 跨层复用的诊断辅助函数。
|
|
3
|
+
*
|
|
4
|
+
* 从 v0.x 起散落在 parse/index.ts / transpile.ts / index.ts 三处,逐字节相同。
|
|
5
|
+
* P0 抽到此处统一来源,避免改动重复。
|
|
6
|
+
*/
|
|
7
|
+
import type { SourceAdapterContext } from "./schema.js";
|
|
8
|
+
/** 把 unknown error 序列化成可读字符串。 */
|
|
9
|
+
export declare function errMsg(e: unknown): string;
|
|
10
|
+
/** 三通道 fallback: log → notify → console(pt-quality #9 + 自定义细节)。
|
|
11
|
+
* 顺序:log 优先(持久 trace),再 notify(UI 瞬时),最后 console(debug 兜底)。
|
|
12
|
+
* v10.x:增 details 参数,让 log/UI 用户能看到 structured 上下文。 */
|
|
13
|
+
export declare function reportWarn(adapterCtx: SourceAdapterContext | undefined, msg: string, details?: Record<string, unknown>): void;
|
|
14
|
+
export declare function reportError(adapterCtx: SourceAdapterContext | undefined, msg: string, details?: Record<string, unknown>): void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 跨层复用的诊断辅助函数。
|
|
3
|
+
*
|
|
4
|
+
* 从 v0.x 起散落在 parse/index.ts / transpile.ts / index.ts 三处,逐字节相同。
|
|
5
|
+
* P0 抽到此处统一来源,避免改动重复。
|
|
6
|
+
*/
|
|
7
|
+
/** 把 unknown error 序列化成可读字符串。 */
|
|
8
|
+
export function errMsg(e) {
|
|
9
|
+
return e instanceof Error ? e.message : String(e);
|
|
10
|
+
}
|
|
11
|
+
/** 三通道 fallback: log → notify → console(pt-quality #9 + 自定义细节)。
|
|
12
|
+
* 顺序:log 优先(持久 trace),再 notify(UI 瞬时),最后 console(debug 兜底)。
|
|
13
|
+
* v10.x:增 details 参数,让 log/UI 用户能看到 structured 上下文。 */
|
|
14
|
+
export function reportWarn(adapterCtx, msg, details) {
|
|
15
|
+
if (adapterCtx?.log)
|
|
16
|
+
adapterCtx.log.warn(msg, details);
|
|
17
|
+
if (adapterCtx?.notify)
|
|
18
|
+
adapterCtx.notify(msg, "warning");
|
|
19
|
+
if (!adapterCtx?.log && !adapterCtx?.notify)
|
|
20
|
+
console.warn(`[pt] ${msg}`);
|
|
21
|
+
}
|
|
22
|
+
export function reportError(adapterCtx, msg, details) {
|
|
23
|
+
if (adapterCtx?.log)
|
|
24
|
+
adapterCtx.log.error(msg, details);
|
|
25
|
+
if (adapterCtx?.notify)
|
|
26
|
+
adapterCtx.notify(msg, "error");
|
|
27
|
+
if (!adapterCtx?.log && !adapterCtx?.notify)
|
|
28
|
+
console.error(`[pt] ${msg}`);
|
|
29
|
+
}
|
package/dist/index.d.ts
ADDED