@dyyz1993/pi-coding-agent 0.69.17 → 0.69.23
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/core/agent-session.d.ts +12 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +208 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/client-channel.d.ts +61 -0
- package/dist/core/extensions/client-channel.d.ts.map +1 -0
- package/dist/core/extensions/client-channel.js +67 -0
- package/dist/core/extensions/client-channel.js.map +1 -0
- package/dist/core/extensions/index.d.ts +3 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -0
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +13 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +8 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +49 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/include-resolver.d.ts +18 -0
- package/dist/core/include-resolver.d.ts.map +1 -0
- package/dist/core/include-resolver.js +304 -0
- package/dist/core/include-resolver.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +17 -4
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/session-manager.d.ts +8 -4
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +29 -6
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/storage.d.ts +24 -0
- package/dist/core/storage.d.ts.map +1 -0
- package/dist/core/storage.js +55 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/core/tools/path-security.d.ts +15 -0
- package/dist/core/tools/path-security.d.ts.map +1 -0
- package/dist/core/tools/path-security.js +76 -0
- package/dist/core/tools/path-security.js.map +1 -0
- package/dist/core/tools/strip-markdown.d.ts +2 -0
- package/dist/core/tools/strip-markdown.d.ts.map +1 -0
- package/dist/core/tools/strip-markdown.js +8 -0
- package/dist/core/tools/strip-markdown.js.map +1 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client-types.d.ts +1 -0
- package/dist/modes/rpc/rpc-client-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-types.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +1 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +5 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +9 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +9 -5
- package/dist/rules-engine/cache.d.ts +0 -4
- package/dist/rules-engine/cache.d.ts.map +0 -1
- package/dist/rules-engine/cache.js +0 -32
- package/dist/rules-engine/cache.js.map +0 -1
- package/dist/rules-engine/config.d.ts +0 -8
- package/dist/rules-engine/config.d.ts.map +0 -1
- package/dist/rules-engine/config.js +0 -56
- package/dist/rules-engine/config.js.map +0 -1
- package/dist/rules-engine/index.d.ts +0 -10
- package/dist/rules-engine/index.d.ts.map +0 -1
- package/dist/rules-engine/index.js +0 -393
- package/dist/rules-engine/index.js.map +0 -1
- package/dist/rules-engine/injector.d.ts +0 -5
- package/dist/rules-engine/injector.d.ts.map +0 -1
- package/dist/rules-engine/injector.js +0 -57
- package/dist/rules-engine/injector.js.map +0 -1
- package/dist/rules-engine/loader.d.ts +0 -8
- package/dist/rules-engine/loader.d.ts.map +0 -1
- package/dist/rules-engine/loader.js +0 -190
- package/dist/rules-engine/loader.js.map +0 -1
- package/dist/rules-engine/matcher.d.ts +0 -3
- package/dist/rules-engine/matcher.d.ts.map +0 -1
- package/dist/rules-engine/matcher.js +0 -48
- package/dist/rules-engine/matcher.js.map +0 -1
- package/dist/rules-engine/types.d.ts +0 -150
- package/dist/rules-engine/types.d.ts.map +0 -1
- package/dist/rules-engine/types.js +0 -2
- package/dist/rules-engine/types.js.map +0 -1
- package/examples/extensions/auto-session-title.ts +0 -82
- package/examples/extensions/file-snapshot.ts +0 -417
- package/examples/extensions/subagent/README.md +0 -172
- package/examples/extensions/subagent/agents/planner.md +0 -37
- package/examples/extensions/subagent/agents/reviewer.md +0 -35
- package/examples/extensions/subagent/agents/scout.md +0 -50
- package/examples/extensions/subagent/agents/worker.md +0 -24
- package/examples/extensions/subagent/agents.ts +0 -126
- package/examples/extensions/subagent/index.ts +0 -987
- package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
- package/examples/extensions/subagent/prompts/implement.md +0 -10
- package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
- package/examples/extensions/subagent-v2/index.ts +0 -849
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
function splitComma(val) {
|
|
4
|
-
const result = [];
|
|
5
|
-
let depth = 0;
|
|
6
|
-
let current = "";
|
|
7
|
-
for (const ch of val) {
|
|
8
|
-
if (ch === "{" || ch === "(" || ch === "[")
|
|
9
|
-
depth++;
|
|
10
|
-
else if (ch === "}" || ch === ")" || ch === "]")
|
|
11
|
-
depth--;
|
|
12
|
-
if (ch === "," && depth === 0) {
|
|
13
|
-
const trimmed = current.trim().replace(/^["']|["']$/g, "");
|
|
14
|
-
if (trimmed)
|
|
15
|
-
result.push(trimmed);
|
|
16
|
-
current = "";
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
current += ch;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
const trimmed = current.trim().replace(/^["']|["']$/g, "");
|
|
23
|
-
if (trimmed)
|
|
24
|
-
result.push(trimmed);
|
|
25
|
-
return result;
|
|
26
|
-
}
|
|
27
|
-
export function parseFrontmatter(content) {
|
|
28
|
-
const frontmatterRegex = /^---\r?\n([\s\S]*?)\n?---\r?\n([\s\S]*)$/;
|
|
29
|
-
const match = content.match(frontmatterRegex);
|
|
30
|
-
if (!match) {
|
|
31
|
-
return { data: {}, body: content };
|
|
32
|
-
}
|
|
33
|
-
const [, frontmatterStr, body] = match;
|
|
34
|
-
const data = {};
|
|
35
|
-
const lines = frontmatterStr.split("\n");
|
|
36
|
-
let i = 0;
|
|
37
|
-
while (i < lines.length) {
|
|
38
|
-
const line = lines[i];
|
|
39
|
-
const colonIndex = line.indexOf(":");
|
|
40
|
-
if (colonIndex === -1) {
|
|
41
|
-
i++;
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
const rawKey = line.slice(0, colonIndex).trim();
|
|
45
|
-
let value = line.slice(colonIndex + 1).trim();
|
|
46
|
-
if (value === "" || value === "null" || value === "undefined") {
|
|
47
|
-
const listItems = [];
|
|
48
|
-
let j = i + 1;
|
|
49
|
-
while (j < lines.length) {
|
|
50
|
-
const subLine = lines[j];
|
|
51
|
-
if (subLine.match(/^\s*-\s+/)) {
|
|
52
|
-
listItems.push(subLine
|
|
53
|
-
.replace(/^\s*-\s+/, "")
|
|
54
|
-
.trim()
|
|
55
|
-
.replace(/^["']|["']$/g, ""));
|
|
56
|
-
j++;
|
|
57
|
-
}
|
|
58
|
-
else if (subLine.trim() === "" || subLine.match(/^\s+/)) {
|
|
59
|
-
j++;
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
if (listItems.length > 0) {
|
|
66
|
-
const camelKey = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
67
|
-
data[camelKey] = listItems;
|
|
68
|
-
i = j;
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
value = null;
|
|
72
|
-
}
|
|
73
|
-
else if (value.startsWith("[") && value.endsWith("]")) {
|
|
74
|
-
try {
|
|
75
|
-
value = JSON.parse(value.replace(/'/g, '"'));
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
value = value
|
|
79
|
-
.slice(1, -1)
|
|
80
|
-
.split(",")
|
|
81
|
-
.map((v) => v.trim().replace(/^["']|["']$/g, ""));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
else if (value.startsWith('"') && value.endsWith('"')) {
|
|
85
|
-
value = value.slice(1, -1);
|
|
86
|
-
}
|
|
87
|
-
else if (value.startsWith("'") && value.endsWith("'")) {
|
|
88
|
-
value = value.slice(1, -1);
|
|
89
|
-
}
|
|
90
|
-
const camelKey = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
91
|
-
if (camelKey === "paths" && typeof value === "string") {
|
|
92
|
-
data[camelKey] = splitComma(value);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
data[camelKey] = value;
|
|
96
|
-
}
|
|
97
|
-
i++;
|
|
98
|
-
}
|
|
99
|
-
return { data, body: body.trim() };
|
|
100
|
-
}
|
|
101
|
-
function extractTitle(body) {
|
|
102
|
-
for (const line of body.split("\n")) {
|
|
103
|
-
const trimmed = line.trim();
|
|
104
|
-
if (trimmed) {
|
|
105
|
-
return trimmed.replace(/^#+\s*/, "").replace(/\*\*/g, "");
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return "Untitled Rule";
|
|
109
|
-
}
|
|
110
|
-
function parsePaths(raw) {
|
|
111
|
-
if (!raw)
|
|
112
|
-
return [];
|
|
113
|
-
if (typeof raw === "string") {
|
|
114
|
-
return raw
|
|
115
|
-
.split(",")
|
|
116
|
-
.map((g) => g.trim())
|
|
117
|
-
.filter(Boolean);
|
|
118
|
-
}
|
|
119
|
-
if (Array.isArray(raw))
|
|
120
|
-
return raw;
|
|
121
|
-
return [];
|
|
122
|
-
}
|
|
123
|
-
export function parseRuleFile(filePath, content) {
|
|
124
|
-
const { data, body } = parseFrontmatter(content);
|
|
125
|
-
const paths = parsePaths(data.paths);
|
|
126
|
-
const isUnconditional = paths.length === 0 || (paths.length === 1 && paths[0] === "**");
|
|
127
|
-
const frontmatter = {};
|
|
128
|
-
if (data.description && typeof data.description === "string")
|
|
129
|
-
frontmatter.description = data.description;
|
|
130
|
-
if (data.severity && typeof data.severity === "string")
|
|
131
|
-
frontmatter.severity = data.severity;
|
|
132
|
-
if (data.paths)
|
|
133
|
-
frontmatter.paths = paths;
|
|
134
|
-
if (data.allowedTools)
|
|
135
|
-
frontmatter.allowedTools =
|
|
136
|
-
typeof data.allowedTools === "string" ? [data.allowedTools] : data.allowedTools;
|
|
137
|
-
if (data.whenToUse && typeof data.whenToUse === "string")
|
|
138
|
-
frontmatter.whenToUse = data.whenToUse;
|
|
139
|
-
if (data.notifyOnMatch !== undefined)
|
|
140
|
-
frontmatter.notifyOnMatch = data.notifyOnMatch === "true" || data.notifyOnMatch === true;
|
|
141
|
-
if (data.skipInPrompt !== undefined)
|
|
142
|
-
frontmatter.skipInPrompt = data.skipInPrompt === "true" || data.skipInPrompt === true;
|
|
143
|
-
return {
|
|
144
|
-
name: path.basename(filePath, ".md"),
|
|
145
|
-
filePath,
|
|
146
|
-
title: extractTitle(body),
|
|
147
|
-
content: body.trim(),
|
|
148
|
-
scope: "project",
|
|
149
|
-
source: "",
|
|
150
|
-
frontmatter,
|
|
151
|
-
isUnconditional,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
function scanDir(dir, files = []) {
|
|
155
|
-
if (!fs.existsSync(dir))
|
|
156
|
-
return files;
|
|
157
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
158
|
-
for (const entry of entries) {
|
|
159
|
-
const fullPath = path.join(dir, entry.name);
|
|
160
|
-
if (entry.isDirectory()) {
|
|
161
|
-
scanDir(fullPath, files);
|
|
162
|
-
}
|
|
163
|
-
else if (entry.isFile() && (entry.name.endsWith(".md") || entry.name.endsWith(".mdc"))) {
|
|
164
|
-
files.push(fullPath);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return files;
|
|
168
|
-
}
|
|
169
|
-
export function loadRules(rulesDir) {
|
|
170
|
-
const rules = [];
|
|
171
|
-
const unconditional = [];
|
|
172
|
-
const conditional = [];
|
|
173
|
-
if (!fs.existsSync(rulesDir)) {
|
|
174
|
-
return { rules, unconditional, conditional, loadedAt: Date.now() };
|
|
175
|
-
}
|
|
176
|
-
const files = scanDir(rulesDir);
|
|
177
|
-
for (const filePath of files) {
|
|
178
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
179
|
-
const rule = parseRuleFile(filePath, content);
|
|
180
|
-
rules.push(rule);
|
|
181
|
-
if (rule.isUnconditional) {
|
|
182
|
-
unconditional.push(rule);
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
conditional.push(rule);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return { rules, unconditional, conditional, loadedAt: Date.now() };
|
|
189
|
-
}
|
|
190
|
-
//# sourceMappingURL=loader.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/rules-engine/loader.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { ParsedRule, RuleCache, RuleFrontmatter } from \"./types.js\";\n\nfunction splitComma(val: string): string[] {\n\tconst result: string[] = [];\n\tlet depth = 0;\n\tlet current = \"\";\n\tfor (const ch of val) {\n\t\tif (ch === \"{\" || ch === \"(\" || ch === \"[\") depth++;\n\t\telse if (ch === \"}\" || ch === \")\" || ch === \"]\") depth--;\n\n\t\tif (ch === \",\" && depth === 0) {\n\t\t\tconst trimmed = current.trim().replace(/^[\"']|[\"']$/g, \"\");\n\t\t\tif (trimmed) result.push(trimmed);\n\t\t\tcurrent = \"\";\n\t\t} else {\n\t\t\tcurrent += ch;\n\t\t}\n\t}\n\tconst trimmed = current.trim().replace(/^[\"']|[\"']$/g, \"\");\n\tif (trimmed) result.push(trimmed);\n\treturn result;\n}\n\nexport function parseFrontmatter(content: string): { data: Record<string, unknown>; body: string } {\n\tconst frontmatterRegex = /^---\\r?\\n([\\s\\S]*?)\\n?---\\r?\\n([\\s\\S]*)$/;\n\tconst match = content.match(frontmatterRegex);\n\n\tif (!match) {\n\t\treturn { data: {}, body: content };\n\t}\n\n\tconst [, frontmatterStr, body] = match;\n\tconst data: Record<string, unknown> = {};\n\n\tconst lines = frontmatterStr.split(\"\\n\");\n\tlet i = 0;\n\twhile (i < lines.length) {\n\t\tconst line = lines[i];\n\t\tconst colonIndex = line.indexOf(\":\");\n\t\tif (colonIndex === -1) {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst rawKey = line.slice(0, colonIndex).trim();\n\t\tlet value: string | string[] | null = line.slice(colonIndex + 1).trim();\n\n\t\tif (value === \"\" || value === \"null\" || value === \"undefined\") {\n\t\t\tconst listItems: string[] = [];\n\t\t\tlet j = i + 1;\n\t\t\twhile (j < lines.length) {\n\t\t\t\tconst subLine = lines[j];\n\t\t\t\tif (subLine.match(/^\\s*-\\s+/)) {\n\t\t\t\t\tlistItems.push(\n\t\t\t\t\t\tsubLine\n\t\t\t\t\t\t\t.replace(/^\\s*-\\s+/, \"\")\n\t\t\t\t\t\t\t.trim()\n\t\t\t\t\t\t\t.replace(/^[\"']|[\"']$/g, \"\"),\n\t\t\t\t\t);\n\t\t\t\t\tj++;\n\t\t\t\t} else if (subLine.trim() === \"\" || subLine.match(/^\\s+/)) {\n\t\t\t\t\tj++;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (listItems.length > 0) {\n\t\t\t\tconst camelKey = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\n\t\t\t\tdata[camelKey] = listItems;\n\t\t\t\ti = j;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvalue = null;\n\t\t} else if (value.startsWith(\"[\") && value.endsWith(\"]\")) {\n\t\t\ttry {\n\t\t\t\tvalue = JSON.parse(value.replace(/'/g, '\"'));\n\t\t\t} catch {\n\t\t\t\tvalue = (value as string)\n\t\t\t\t\t.slice(1, -1)\n\t\t\t\t\t.split(\",\")\n\t\t\t\t\t.map((v: string) => v.trim().replace(/^[\"']|[\"']$/g, \"\"));\n\t\t\t}\n\t\t} else if (value.startsWith('\"') && value.endsWith('\"')) {\n\t\t\tvalue = value.slice(1, -1);\n\t\t} else if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n\t\t\tvalue = value.slice(1, -1);\n\t\t}\n\n\t\tconst camelKey = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\n\n\t\tif (camelKey === \"paths\" && typeof value === \"string\") {\n\t\t\tdata[camelKey] = splitComma(value);\n\t\t} else {\n\t\t\tdata[camelKey] = value;\n\t\t}\n\t\ti++;\n\t}\n\n\treturn { data, body: body.trim() };\n}\n\nfunction extractTitle(body: string): string {\n\tfor (const line of body.split(\"\\n\")) {\n\t\tconst trimmed = line.trim();\n\t\tif (trimmed) {\n\t\t\treturn trimmed.replace(/^#+\\s*/, \"\").replace(/\\*\\*/g, \"\");\n\t\t}\n\t}\n\treturn \"Untitled Rule\";\n}\n\nfunction parsePaths(raw: unknown): string[] {\n\tif (!raw) return [];\n\tif (typeof raw === \"string\") {\n\t\treturn raw\n\t\t\t.split(\",\")\n\t\t\t.map((g) => g.trim())\n\t\t\t.filter(Boolean);\n\t}\n\tif (Array.isArray(raw)) return raw as string[];\n\treturn [];\n}\n\nexport function parseRuleFile(filePath: string, content: string): ParsedRule {\n\tconst { data, body } = parseFrontmatter(content);\n\tconst paths = parsePaths(data.paths);\n\tconst isUnconditional = paths.length === 0 || (paths.length === 1 && paths[0] === \"**\");\n\n\tconst frontmatter: RuleFrontmatter = {};\n\tif (data.description && typeof data.description === \"string\") frontmatter.description = data.description;\n\tif (data.severity && typeof data.severity === \"string\")\n\t\tfrontmatter.severity = data.severity as ParsedRule[\"frontmatter\"][\"severity\"];\n\tif (data.paths) frontmatter.paths = paths;\n\tif (data.allowedTools)\n\t\tfrontmatter.allowedTools =\n\t\t\ttypeof data.allowedTools === \"string\" ? [data.allowedTools] : (data.allowedTools as string[]);\n\tif (data.whenToUse && typeof data.whenToUse === \"string\") frontmatter.whenToUse = data.whenToUse;\n\tif (data.notifyOnMatch !== undefined)\n\t\tfrontmatter.notifyOnMatch = data.notifyOnMatch === \"true\" || data.notifyOnMatch === true;\n\tif (data.skipInPrompt !== undefined)\n\t\tfrontmatter.skipInPrompt = data.skipInPrompt === \"true\" || data.skipInPrompt === true;\n\n\treturn {\n\t\tname: path.basename(filePath, \".md\"),\n\t\tfilePath,\n\t\ttitle: extractTitle(body),\n\t\tcontent: body.trim(),\n\t\tscope: \"project\",\n\t\tsource: \"\",\n\t\tfrontmatter,\n\t\tisUnconditional,\n\t};\n}\n\nfunction scanDir(dir: string, files: string[] = []): string[] {\n\tif (!fs.existsSync(dir)) return files;\n\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\tfor (const entry of entries) {\n\t\tconst fullPath = path.join(dir, entry.name);\n\t\tif (entry.isDirectory()) {\n\t\t\tscanDir(fullPath, files);\n\t\t} else if (entry.isFile() && (entry.name.endsWith(\".md\") || entry.name.endsWith(\".mdc\"))) {\n\t\t\tfiles.push(fullPath);\n\t\t}\n\t}\n\treturn files;\n}\n\nexport function loadRules(rulesDir: string): RuleCache {\n\tconst rules: ParsedRule[] = [];\n\tconst unconditional: ParsedRule[] = [];\n\tconst conditional: ParsedRule[] = [];\n\n\tif (!fs.existsSync(rulesDir)) {\n\t\treturn { rules, unconditional, conditional, loadedAt: Date.now() };\n\t}\n\n\tconst files = scanDir(rulesDir);\n\n\tfor (const filePath of files) {\n\t\tconst content = fs.readFileSync(filePath, \"utf-8\");\n\t\tconst rule = parseRuleFile(filePath, content);\n\t\trules.push(rule);\n\t\tif (rule.isUnconditional) {\n\t\t\tunconditional.push(rule);\n\t\t} else {\n\t\t\tconditional.push(rule);\n\t\t}\n\t}\n\n\treturn { rules, unconditional, conditional, loadedAt: Date.now() };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../../src/rules-engine/matcher.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAoClE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAIzE","sourcesContent":["export function matchGlob(pattern: string, target: string): boolean {\n\tif (!pattern || !target) return false;\n\n\tconst normalizedTarget = target.replace(/\\\\/g, \"/\");\n\tlet i = 0;\n\tlet re = \"\";\n\n\twhile (i < pattern.length) {\n\t\tconst ch = pattern[i];\n\t\tif (ch === \"*\") {\n\t\t\tif (pattern[i + 1] === \"*\") {\n\t\t\t\tre += \".*\";\n\t\t\t\ti += 2;\n\t\t\t\tif (pattern[i] === \"/\") i++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tre += \"[^/]*\";\n\t\t} else if (ch === \"?\") {\n\t\t\tre += \"[^/]\";\n\t\t} else if (ch === \".\") {\n\t\t\tre += \"\\\\.\";\n\t\t} else if (ch === \"{\") {\n\t\t\tconst close = pattern.indexOf(\"}\", i);\n\t\t\tif (close !== -1) {\n\t\t\t\tre += `(${pattern.slice(i + 1, close).replace(/,/g, \"|\")})`;\n\t\t\t\ti = close;\n\t\t\t} else {\n\t\t\t\tre += ch;\n\t\t\t}\n\t\t} else {\n\t\t\tre += ch;\n\t\t}\n\t\ti++;\n\t}\n\n\treturn new RegExp(`^${re}$`).test(normalizedTarget);\n}\n\nexport function matchesAnyGlob(globs: string[], filePath: string): boolean {\n\tif (!filePath || globs.length === 0) return false;\n\tconst normalized = filePath.replace(/\\\\/g, \"/\");\n\treturn globs.some((g) => matchGlob(g, normalized));\n}\n"]}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
export function matchGlob(pattern, target) {
|
|
2
|
-
if (!pattern || !target)
|
|
3
|
-
return false;
|
|
4
|
-
const normalizedTarget = target.replace(/\\/g, "/");
|
|
5
|
-
let i = 0;
|
|
6
|
-
let re = "";
|
|
7
|
-
while (i < pattern.length) {
|
|
8
|
-
const ch = pattern[i];
|
|
9
|
-
if (ch === "*") {
|
|
10
|
-
if (pattern[i + 1] === "*") {
|
|
11
|
-
re += ".*";
|
|
12
|
-
i += 2;
|
|
13
|
-
if (pattern[i] === "/")
|
|
14
|
-
i++;
|
|
15
|
-
continue;
|
|
16
|
-
}
|
|
17
|
-
re += "[^/]*";
|
|
18
|
-
}
|
|
19
|
-
else if (ch === "?") {
|
|
20
|
-
re += "[^/]";
|
|
21
|
-
}
|
|
22
|
-
else if (ch === ".") {
|
|
23
|
-
re += "\\.";
|
|
24
|
-
}
|
|
25
|
-
else if (ch === "{") {
|
|
26
|
-
const close = pattern.indexOf("}", i);
|
|
27
|
-
if (close !== -1) {
|
|
28
|
-
re += `(${pattern.slice(i + 1, close).replace(/,/g, "|")})`;
|
|
29
|
-
i = close;
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
re += ch;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
re += ch;
|
|
37
|
-
}
|
|
38
|
-
i++;
|
|
39
|
-
}
|
|
40
|
-
return new RegExp(`^${re}$`).test(normalizedTarget);
|
|
41
|
-
}
|
|
42
|
-
export function matchesAnyGlob(globs, filePath) {
|
|
43
|
-
if (!filePath || globs.length === 0)
|
|
44
|
-
return false;
|
|
45
|
-
const normalized = filePath.replace(/\\/g, "/");
|
|
46
|
-
return globs.some((g) => matchGlob(g, normalized));
|
|
47
|
-
}
|
|
48
|
-
//# sourceMappingURL=matcher.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"matcher.js","sourceRoot":"","sources":["../../src/rules-engine/matcher.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,MAAc,EAAW;IACnE,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACpD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,EAAE,GAAG,EAAE,CAAC;IAEZ,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAChB,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC5B,EAAE,IAAI,IAAI,CAAC;gBACX,CAAC,IAAI,CAAC,CAAC;gBACP,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG;oBAAE,CAAC,EAAE,CAAC;gBAC5B,SAAS;YACV,CAAC;YACD,EAAE,IAAI,OAAO,CAAC;QACf,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACvB,EAAE,IAAI,MAAM,CAAC;QACd,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACvB,EAAE,IAAI,KAAK,CAAC;QACb,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACtC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBAClB,EAAE,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC;gBAC5D,CAAC,GAAG,KAAK,CAAC;YACX,CAAC;iBAAM,CAAC;gBACP,EAAE,IAAI,EAAE,CAAC;YACV,CAAC;QACF,CAAC;aAAM,CAAC;YACP,EAAE,IAAI,EAAE,CAAC;QACV,CAAC;QACD,CAAC,EAAE,CAAC;IACL,CAAC;IAED,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAAA,CACpD;AAED,MAAM,UAAU,cAAc,CAAC,KAAe,EAAE,QAAgB,EAAW;IAC1E,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAClD,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAChD,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AAAA,CACnD","sourcesContent":["export function matchGlob(pattern: string, target: string): boolean {\n\tif (!pattern || !target) return false;\n\n\tconst normalizedTarget = target.replace(/\\\\/g, \"/\");\n\tlet i = 0;\n\tlet re = \"\";\n\n\twhile (i < pattern.length) {\n\t\tconst ch = pattern[i];\n\t\tif (ch === \"*\") {\n\t\t\tif (pattern[i + 1] === \"*\") {\n\t\t\t\tre += \".*\";\n\t\t\t\ti += 2;\n\t\t\t\tif (pattern[i] === \"/\") i++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tre += \"[^/]*\";\n\t\t} else if (ch === \"?\") {\n\t\t\tre += \"[^/]\";\n\t\t} else if (ch === \".\") {\n\t\t\tre += \"\\\\.\";\n\t\t} else if (ch === \"{\") {\n\t\t\tconst close = pattern.indexOf(\"}\", i);\n\t\t\tif (close !== -1) {\n\t\t\t\tre += `(${pattern.slice(i + 1, close).replace(/,/g, \"|\")})`;\n\t\t\t\ti = close;\n\t\t\t} else {\n\t\t\t\tre += ch;\n\t\t\t}\n\t\t} else {\n\t\t\tre += ch;\n\t\t}\n\t\ti++;\n\t}\n\n\treturn new RegExp(`^${re}$`).test(normalizedTarget);\n}\n\nexport function matchesAnyGlob(globs: string[], filePath: string): boolean {\n\tif (!filePath || globs.length === 0) return false;\n\tconst normalized = filePath.replace(/\\\\/g, \"/\");\n\treturn globs.some((g) => matchGlob(g, normalized));\n}\n"]}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
export type RuleSeverity = "critical" | "high" | "medium" | "low" | "hint";
|
|
2
|
-
export type RuleScope = "user" | "pi" | "project" | "managed";
|
|
3
|
-
export interface RuleFrontmatter {
|
|
4
|
-
paths?: string[];
|
|
5
|
-
description?: string;
|
|
6
|
-
severity?: RuleSeverity;
|
|
7
|
-
allowedTools?: string[];
|
|
8
|
-
whenToUse?: string;
|
|
9
|
-
version?: string;
|
|
10
|
-
model?: string;
|
|
11
|
-
skills?: string;
|
|
12
|
-
effort?: string;
|
|
13
|
-
userInvocable?: string;
|
|
14
|
-
context?: "inline" | "fork";
|
|
15
|
-
agent?: string;
|
|
16
|
-
shell?: string;
|
|
17
|
-
notifyOnMatch?: boolean;
|
|
18
|
-
skipInPrompt?: boolean;
|
|
19
|
-
}
|
|
20
|
-
export interface ParsedRule {
|
|
21
|
-
name: string;
|
|
22
|
-
filePath: string;
|
|
23
|
-
title: string;
|
|
24
|
-
content: string;
|
|
25
|
-
scope: RuleScope;
|
|
26
|
-
source: string;
|
|
27
|
-
frontmatter: RuleFrontmatter;
|
|
28
|
-
isUnconditional: boolean;
|
|
29
|
-
}
|
|
30
|
-
export interface RuleCache {
|
|
31
|
-
rules: ParsedRule[];
|
|
32
|
-
unconditional: ParsedRule[];
|
|
33
|
-
conditional: ParsedRule[];
|
|
34
|
-
loadedAt: number;
|
|
35
|
-
}
|
|
36
|
-
export interface CachedRules {
|
|
37
|
-
rules: ParsedRule[];
|
|
38
|
-
loadedAt: number;
|
|
39
|
-
}
|
|
40
|
-
export interface RulesConfig {
|
|
41
|
-
cacheTTL: number;
|
|
42
|
-
notifyOnLoad: boolean;
|
|
43
|
-
notifyOnMatch: boolean;
|
|
44
|
-
dirs?: {
|
|
45
|
-
user?: string[];
|
|
46
|
-
pi?: string[];
|
|
47
|
-
project?: string[];
|
|
48
|
-
managed?: string[];
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
export interface RuleDetail {
|
|
52
|
-
name: string;
|
|
53
|
-
title: string;
|
|
54
|
-
filePath: string;
|
|
55
|
-
scope: RuleScope;
|
|
56
|
-
source: string;
|
|
57
|
-
severity: RuleSeverity;
|
|
58
|
-
isUnconditional: boolean;
|
|
59
|
-
paths: string[];
|
|
60
|
-
description?: string;
|
|
61
|
-
}
|
|
62
|
-
export interface ScannedDir {
|
|
63
|
-
dir: string;
|
|
64
|
-
fileCount: number;
|
|
65
|
-
ruleNames: string[];
|
|
66
|
-
}
|
|
67
|
-
export interface MatchedRuleDetail {
|
|
68
|
-
name: string;
|
|
69
|
-
title: string;
|
|
70
|
-
severity: RuleSeverity;
|
|
71
|
-
matchedGlob: string;
|
|
72
|
-
}
|
|
73
|
-
export interface MatchRecord {
|
|
74
|
-
filePath: string;
|
|
75
|
-
ruleNames: string[];
|
|
76
|
-
toolName: string;
|
|
77
|
-
toolCallId: string;
|
|
78
|
-
severity: "info" | "warning";
|
|
79
|
-
timestamp: number;
|
|
80
|
-
matchedRuleDetails?: MatchedRuleDetail[];
|
|
81
|
-
}
|
|
82
|
-
export interface LifecycleEntry {
|
|
83
|
-
event: "loaded" | "restored" | "injected" | "reloaded" | "unloaded" | "expired";
|
|
84
|
-
message: string;
|
|
85
|
-
ruleCount?: number;
|
|
86
|
-
timestamp: number;
|
|
87
|
-
details?: {
|
|
88
|
-
scannedDirs?: ScannedDir[];
|
|
89
|
-
configSource?: string;
|
|
90
|
-
cacheHit?: boolean;
|
|
91
|
-
injectedRules?: Array<{
|
|
92
|
-
name: string;
|
|
93
|
-
promptDelta: number;
|
|
94
|
-
}>;
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
export interface SnapshotPayload {
|
|
98
|
-
type: "snapshot";
|
|
99
|
-
rules: RuleDetail[];
|
|
100
|
-
injectedRuleNames: string[];
|
|
101
|
-
totalRules: number;
|
|
102
|
-
unconditionalCount: number;
|
|
103
|
-
conditionalCount: number;
|
|
104
|
-
matchHistory: MatchRecord[];
|
|
105
|
-
lifecycleLog: LifecycleEntry[];
|
|
106
|
-
loadedAt: number;
|
|
107
|
-
cacheTTL: number;
|
|
108
|
-
}
|
|
109
|
-
export interface MatchedPayload {
|
|
110
|
-
type: "matched";
|
|
111
|
-
filePath: string;
|
|
112
|
-
matchedRules: MatchedRuleDetail[];
|
|
113
|
-
toolName: string;
|
|
114
|
-
toolCallId: string;
|
|
115
|
-
severity: "info" | "warning";
|
|
116
|
-
timestamp: number;
|
|
117
|
-
}
|
|
118
|
-
export interface InjectedPayload {
|
|
119
|
-
type: "injected";
|
|
120
|
-
ruleNames: string[];
|
|
121
|
-
systemPromptLength: number;
|
|
122
|
-
}
|
|
123
|
-
export interface ReloadedPayload {
|
|
124
|
-
type: "reloaded";
|
|
125
|
-
rules: RuleDetail[];
|
|
126
|
-
loadedAt: number;
|
|
127
|
-
}
|
|
128
|
-
export interface UnloadedPayload {
|
|
129
|
-
type: "unloaded";
|
|
130
|
-
reason: string;
|
|
131
|
-
}
|
|
132
|
-
export type RulesChannelEvent = SnapshotPayload | MatchedPayload | InjectedPayload | ReloadedPayload | UnloadedPayload;
|
|
133
|
-
export interface RulesChannelContract {
|
|
134
|
-
methods: {
|
|
135
|
-
getSnapshot: {
|
|
136
|
-
params: {
|
|
137
|
-
cwd?: string;
|
|
138
|
-
};
|
|
139
|
-
return: SnapshotPayload;
|
|
140
|
-
};
|
|
141
|
-
};
|
|
142
|
-
events: {
|
|
143
|
-
snapshot: SnapshotPayload;
|
|
144
|
-
matched: MatchedPayload;
|
|
145
|
-
injected: InjectedPayload;
|
|
146
|
-
reloaded: ReloadedPayload;
|
|
147
|
-
unloaded: UnloadedPayload;
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/rules-engine/types.ts"],"names":[],"mappings":"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","sourcesContent":["export type RuleSeverity = \"critical\" | \"high\" | \"medium\" | \"low\" | \"hint\";\n\nexport type RuleScope = \"user\" | \"pi\" | \"project\" | \"managed\";\n\nexport interface RuleFrontmatter {\n\tpaths?: string[];\n\tdescription?: string;\n\tseverity?: RuleSeverity;\n\tallowedTools?: string[];\n\twhenToUse?: string;\n\tversion?: string;\n\tmodel?: string;\n\tskills?: string;\n\teffort?: string;\n\tuserInvocable?: string;\n\tcontext?: \"inline\" | \"fork\";\n\tagent?: string;\n\tshell?: string;\n\tnotifyOnMatch?: boolean;\n\tskipInPrompt?: boolean;\n}\n\nexport interface ParsedRule {\n\tname: string;\n\tfilePath: string;\n\ttitle: string;\n\tcontent: string;\n\tscope: RuleScope;\n\tsource: string;\n\tfrontmatter: RuleFrontmatter;\n\tisUnconditional: boolean;\n}\n\nexport interface RuleCache {\n\trules: ParsedRule[];\n\tunconditional: ParsedRule[];\n\tconditional: ParsedRule[];\n\tloadedAt: number;\n}\n\nexport interface CachedRules {\n\trules: ParsedRule[];\n\tloadedAt: number;\n}\n\nexport interface RulesConfig {\n\tcacheTTL: number;\n\tnotifyOnLoad: boolean;\n\tnotifyOnMatch: boolean;\n\tdirs?: {\n\t\tuser?: string[];\n\t\tpi?: string[];\n\t\tproject?: string[];\n\t\tmanaged?: string[];\n\t};\n}\n\nexport interface RuleDetail {\n\tname: string;\n\ttitle: string;\n\tfilePath: string;\n\tscope: RuleScope;\n\tsource: string;\n\tseverity: RuleSeverity;\n\tisUnconditional: boolean;\n\tpaths: string[];\n\tdescription?: string;\n}\n\nexport interface ScannedDir {\n\tdir: string;\n\tfileCount: number;\n\truleNames: string[];\n}\n\nexport interface MatchedRuleDetail {\n\tname: string;\n\ttitle: string;\n\tseverity: RuleSeverity;\n\tmatchedGlob: string;\n}\n\nexport interface MatchRecord {\n\tfilePath: string;\n\truleNames: string[];\n\ttoolName: string;\n\ttoolCallId: string;\n\tseverity: \"info\" | \"warning\";\n\ttimestamp: number;\n\tmatchedRuleDetails?: MatchedRuleDetail[];\n}\n\nexport interface LifecycleEntry {\n\tevent: \"loaded\" | \"restored\" | \"injected\" | \"reloaded\" | \"unloaded\" | \"expired\";\n\tmessage: string;\n\truleCount?: number;\n\ttimestamp: number;\n\tdetails?: {\n\t\tscannedDirs?: ScannedDir[];\n\t\tconfigSource?: string;\n\t\tcacheHit?: boolean;\n\t\tinjectedRules?: Array<{ name: string; promptDelta: number }>;\n\t};\n}\n\nexport interface SnapshotPayload {\n\ttype: \"snapshot\";\n\trules: RuleDetail[];\n\tinjectedRuleNames: string[];\n\ttotalRules: number;\n\tunconditionalCount: number;\n\tconditionalCount: number;\n\tmatchHistory: MatchRecord[];\n\tlifecycleLog: LifecycleEntry[];\n\tloadedAt: number;\n\tcacheTTL: number;\n}\n\nexport interface MatchedPayload {\n\ttype: \"matched\";\n\tfilePath: string;\n\tmatchedRules: MatchedRuleDetail[];\n\ttoolName: string;\n\ttoolCallId: string;\n\tseverity: \"info\" | \"warning\";\n\ttimestamp: number;\n}\n\nexport interface InjectedPayload {\n\ttype: \"injected\";\n\truleNames: string[];\n\tsystemPromptLength: number;\n}\n\nexport interface ReloadedPayload {\n\ttype: \"reloaded\";\n\trules: RuleDetail[];\n\tloadedAt: number;\n}\n\nexport interface UnloadedPayload {\n\ttype: \"unloaded\";\n\treason: string;\n}\n\nexport type RulesChannelEvent = SnapshotPayload | MatchedPayload | InjectedPayload | ReloadedPayload | UnloadedPayload;\n\nexport interface RulesChannelContract {\n\tmethods: {\n\t\tgetSnapshot: {\n\t\t\tparams: { cwd?: string };\n\t\t\treturn: SnapshotPayload;\n\t\t};\n\t};\n\tevents: {\n\t\tsnapshot: SnapshotPayload;\n\t\tmatched: MatchedPayload;\n\t\tinjected: InjectedPayload;\n\t\treloaded: ReloadedPayload;\n\t\tunloaded: UnloadedPayload;\n\t};\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/rules-engine/types.ts"],"names":[],"mappings":"","sourcesContent":["export type RuleSeverity = \"critical\" | \"high\" | \"medium\" | \"low\" | \"hint\";\n\nexport type RuleScope = \"user\" | \"pi\" | \"project\" | \"managed\";\n\nexport interface RuleFrontmatter {\n\tpaths?: string[];\n\tdescription?: string;\n\tseverity?: RuleSeverity;\n\tallowedTools?: string[];\n\twhenToUse?: string;\n\tversion?: string;\n\tmodel?: string;\n\tskills?: string;\n\teffort?: string;\n\tuserInvocable?: string;\n\tcontext?: \"inline\" | \"fork\";\n\tagent?: string;\n\tshell?: string;\n\tnotifyOnMatch?: boolean;\n\tskipInPrompt?: boolean;\n}\n\nexport interface ParsedRule {\n\tname: string;\n\tfilePath: string;\n\ttitle: string;\n\tcontent: string;\n\tscope: RuleScope;\n\tsource: string;\n\tfrontmatter: RuleFrontmatter;\n\tisUnconditional: boolean;\n}\n\nexport interface RuleCache {\n\trules: ParsedRule[];\n\tunconditional: ParsedRule[];\n\tconditional: ParsedRule[];\n\tloadedAt: number;\n}\n\nexport interface CachedRules {\n\trules: ParsedRule[];\n\tloadedAt: number;\n}\n\nexport interface RulesConfig {\n\tcacheTTL: number;\n\tnotifyOnLoad: boolean;\n\tnotifyOnMatch: boolean;\n\tdirs?: {\n\t\tuser?: string[];\n\t\tpi?: string[];\n\t\tproject?: string[];\n\t\tmanaged?: string[];\n\t};\n}\n\nexport interface RuleDetail {\n\tname: string;\n\ttitle: string;\n\tfilePath: string;\n\tscope: RuleScope;\n\tsource: string;\n\tseverity: RuleSeverity;\n\tisUnconditional: boolean;\n\tpaths: string[];\n\tdescription?: string;\n}\n\nexport interface ScannedDir {\n\tdir: string;\n\tfileCount: number;\n\truleNames: string[];\n}\n\nexport interface MatchedRuleDetail {\n\tname: string;\n\ttitle: string;\n\tseverity: RuleSeverity;\n\tmatchedGlob: string;\n}\n\nexport interface MatchRecord {\n\tfilePath: string;\n\truleNames: string[];\n\ttoolName: string;\n\ttoolCallId: string;\n\tseverity: \"info\" | \"warning\";\n\ttimestamp: number;\n\tmatchedRuleDetails?: MatchedRuleDetail[];\n}\n\nexport interface LifecycleEntry {\n\tevent: \"loaded\" | \"restored\" | \"injected\" | \"reloaded\" | \"unloaded\" | \"expired\";\n\tmessage: string;\n\truleCount?: number;\n\ttimestamp: number;\n\tdetails?: {\n\t\tscannedDirs?: ScannedDir[];\n\t\tconfigSource?: string;\n\t\tcacheHit?: boolean;\n\t\tinjectedRules?: Array<{ name: string; promptDelta: number }>;\n\t};\n}\n\nexport interface SnapshotPayload {\n\ttype: \"snapshot\";\n\trules: RuleDetail[];\n\tinjectedRuleNames: string[];\n\ttotalRules: number;\n\tunconditionalCount: number;\n\tconditionalCount: number;\n\tmatchHistory: MatchRecord[];\n\tlifecycleLog: LifecycleEntry[];\n\tloadedAt: number;\n\tcacheTTL: number;\n}\n\nexport interface MatchedPayload {\n\ttype: \"matched\";\n\tfilePath: string;\n\tmatchedRules: MatchedRuleDetail[];\n\ttoolName: string;\n\ttoolCallId: string;\n\tseverity: \"info\" | \"warning\";\n\ttimestamp: number;\n}\n\nexport interface InjectedPayload {\n\ttype: \"injected\";\n\truleNames: string[];\n\tsystemPromptLength: number;\n}\n\nexport interface ReloadedPayload {\n\ttype: \"reloaded\";\n\trules: RuleDetail[];\n\tloadedAt: number;\n}\n\nexport interface UnloadedPayload {\n\ttype: \"unloaded\";\n\treason: string;\n}\n\nexport type RulesChannelEvent = SnapshotPayload | MatchedPayload | InjectedPayload | ReloadedPayload | UnloadedPayload;\n\nexport interface RulesChannelContract {\n\tmethods: {\n\t\tgetSnapshot: {\n\t\t\tparams: { cwd?: string };\n\t\t\treturn: SnapshotPayload;\n\t\t};\n\t};\n\tevents: {\n\t\tsnapshot: SnapshotPayload;\n\t\tmatched: MatchedPayload;\n\t\tinjected: InjectedPayload;\n\t\treloaded: ReloadedPayload;\n\t\tunloaded: UnloadedPayload;\n\t};\n}\n"]}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto Session Title Extension
|
|
3
|
-
*
|
|
4
|
-
* Automatically generates a short, descriptive title for the session
|
|
5
|
-
* based on the first user message using an LLM call.
|
|
6
|
-
*
|
|
7
|
-
* Behavior:
|
|
8
|
-
* - Triggers on the first turn_end event (turnIndex === 0)
|
|
9
|
-
* - Skips if the session already has a name
|
|
10
|
-
* - Uses pi.callLLM() with the user's first message to generate a title
|
|
11
|
-
* - Cleans LLM output: strips think tags, takes first non-empty line, truncates to 100 chars
|
|
12
|
-
* - On failure: silently ignores (does not block the session)
|
|
13
|
-
*
|
|
14
|
-
* Usage:
|
|
15
|
-
* pi --extension examples/extensions/auto-session-title.ts
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import type { ExtensionAPI, SessionEntry, SessionMessageEntry } from "@dyyz1993/pi-coding-agent";
|
|
19
|
-
|
|
20
|
-
const TITLE_PROMPT =
|
|
21
|
-
"Generate a very short title (max 50 characters) for a coding conversation that starts with this message. Output ONLY the title, nothing else. No quotes, no punctuation at the end.";
|
|
22
|
-
|
|
23
|
-
const MAX_TITLE_LENGTH = 100;
|
|
24
|
-
const MAX_LLM_TOKENS = 30;
|
|
25
|
-
|
|
26
|
-
function extractFirstUserText(entries: SessionEntry[]): string {
|
|
27
|
-
for (const entry of entries) {
|
|
28
|
-
if (entry.type !== "message") continue;
|
|
29
|
-
const msg = (entry as SessionMessageEntry).message;
|
|
30
|
-
if (msg.role !== "user") continue;
|
|
31
|
-
const content = msg.content;
|
|
32
|
-
if (typeof content === "string") return content;
|
|
33
|
-
if (Array.isArray(content)) {
|
|
34
|
-
const texts = content
|
|
35
|
-
.filter((c): c is { type: "text"; text: string } => c.type === "text" && typeof c.text === "string")
|
|
36
|
-
.map((c) => c.text)
|
|
37
|
-
.join("\n");
|
|
38
|
-
if (texts) return texts;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return "";
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function cleanLLMTitle(raw: string): string {
|
|
45
|
-
const withoutThink = raw.replace(/<think[\s\S]*?<\/think\s*>?/g, "");
|
|
46
|
-
return (
|
|
47
|
-
withoutThink
|
|
48
|
-
.split("\n")
|
|
49
|
-
.map((l) => l.trim())
|
|
50
|
-
.filter(Boolean)[0]
|
|
51
|
-
?.slice(0, MAX_TITLE_LENGTH)
|
|
52
|
-
.trim() ?? ""
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export default function autoSessionTitle(pi: ExtensionAPI) {
|
|
57
|
-
pi.on("turn_end", async (event, ctx) => {
|
|
58
|
-
if (event.turnIndex !== 0) return;
|
|
59
|
-
|
|
60
|
-
if (pi.getSessionName()) return;
|
|
61
|
-
|
|
62
|
-
const entries = ctx.sessionManager.getEntries();
|
|
63
|
-
const userText = extractFirstUserText(entries);
|
|
64
|
-
if (!userText) return;
|
|
65
|
-
|
|
66
|
-
let title = "";
|
|
67
|
-
try {
|
|
68
|
-
title = await pi.callLLM({
|
|
69
|
-
systemPrompt: TITLE_PROMPT,
|
|
70
|
-
messages: [{ role: "user", content: userText }],
|
|
71
|
-
maxTokens: MAX_LLM_TOKENS,
|
|
72
|
-
});
|
|
73
|
-
} catch {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const cleaned = cleanLLMTitle(title);
|
|
78
|
-
if (cleaned) {
|
|
79
|
-
pi.setSessionName(cleaned);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|