@tigorhutasuhut/pi-rules 0.2.0 → 0.2.2
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/discovery.d.ts +57 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +251 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +190 -0
- package/dist/index.js.map +1 -0
- package/dist/matching.d.ts +5 -0
- package/dist/matching.d.ts.map +1 -0
- package/dist/matching.js +33 -0
- package/dist/matching.js.map +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import Type from "typebox";
|
|
2
|
+
import type { DiscoveryResult, Rule, RuleDiagnostic } from "./types.js";
|
|
3
|
+
declare const RULE_SOURCE_SCHEMA: Type.TObject<{
|
|
4
|
+
scope: Type.TUnion<[Type.TLiteral<"repo">, Type.TLiteral<"user">]>;
|
|
5
|
+
kind: Type.TUnion<[Type.TLiteral<"pi">, Type.TLiteral<"agents">, Type.TLiteral<"claude">]>;
|
|
6
|
+
}>;
|
|
7
|
+
export declare const RULE_CONFIG_SCHEMA: Type.TObject<{
|
|
8
|
+
enabled: Type.TOptional<Type.TBoolean>;
|
|
9
|
+
sources: Type.TArray<Type.TObject<{
|
|
10
|
+
scope: Type.TUnion<[Type.TLiteral<"repo">, Type.TLiteral<"user">]>;
|
|
11
|
+
kind: Type.TUnion<[Type.TLiteral<"pi">, Type.TLiteral<"agents">, Type.TLiteral<"claude">]>;
|
|
12
|
+
}>>;
|
|
13
|
+
nudges: Type.TOptional<Type.TObject<{
|
|
14
|
+
afterCommit: Type.TOptional<Type.TBoolean>;
|
|
15
|
+
}>>;
|
|
16
|
+
}>;
|
|
17
|
+
export declare const RULE_CONFIG_PATCH_SCHEMA: Type.TObject<{
|
|
18
|
+
enabled: Type.TOptional<Type.TBoolean>;
|
|
19
|
+
sources: Type.TOptional<Type.TArray<Type.TObject<{
|
|
20
|
+
scope: Type.TUnion<[Type.TLiteral<"repo">, Type.TLiteral<"user">]>;
|
|
21
|
+
kind: Type.TUnion<[Type.TLiteral<"pi">, Type.TLiteral<"agents">, Type.TLiteral<"claude">]>;
|
|
22
|
+
}>>>;
|
|
23
|
+
nudges: Type.TOptional<Type.TObject<{
|
|
24
|
+
afterCommit: Type.TOptional<Type.TBoolean>;
|
|
25
|
+
}>>;
|
|
26
|
+
}>;
|
|
27
|
+
export type RuleSource = Type.Static<typeof RULE_SOURCE_SCHEMA>;
|
|
28
|
+
export type RuleConfig = Type.Static<typeof RULE_CONFIG_SCHEMA>;
|
|
29
|
+
export type RuleConfigPatch = Type.Static<typeof RULE_CONFIG_PATCH_SCHEMA>;
|
|
30
|
+
export declare const DEFAULT_RULE_SOURCES: RuleSource[];
|
|
31
|
+
interface DiscoveryOptions {
|
|
32
|
+
env?: NodeJS.ProcessEnv;
|
|
33
|
+
home?: string;
|
|
34
|
+
sources?: RuleSource[];
|
|
35
|
+
}
|
|
36
|
+
export interface RuleConfigResult {
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
sources: RuleSource[];
|
|
39
|
+
nudgeAfterCommit: boolean;
|
|
40
|
+
configPath?: string;
|
|
41
|
+
diagnostic?: RuleDiagnostic;
|
|
42
|
+
}
|
|
43
|
+
type ParseResult = {
|
|
44
|
+
rule: Rule;
|
|
45
|
+
} | {
|
|
46
|
+
diagnostic: RuleDiagnostic;
|
|
47
|
+
};
|
|
48
|
+
export declare function validateRuleConfigPatch(value: unknown): {
|
|
49
|
+
config: RuleConfigPatch;
|
|
50
|
+
} | {
|
|
51
|
+
reason: string;
|
|
52
|
+
};
|
|
53
|
+
export declare function loadRuleConfig(cwd: string, options?: DiscoveryOptions): Promise<RuleConfigResult>;
|
|
54
|
+
export declare function discoverRules(cwd: string, options?: DiscoveryOptions): Promise<DiscoveryResult>;
|
|
55
|
+
export declare function parseRuleFile(sourcePath: string, sourceLabel: string): Promise<ParseResult>;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAGA,OAAO,IAAI,MAAM,SAAS,CAAC;AAG3B,OAAO,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKxE,QAAA,MAAM,kBAAkB;;;EAGtB,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;EAI7B,CAAC;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;EAAmC,CAAC;AAKzE,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE3E,eAAO,MAAM,oBAAoB,EAAE,UAAU,EAO5C,CAAC;AAOF,UAAU,gBAAgB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,cAAc,CAAC;CAC7B;AAED,KAAK,WAAW,GAAG;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,UAAU,EAAE,cAAc,CAAA;CAAE,CAAC;AAEnE,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAKxG;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwC3G;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAyBzG;AAED,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA0EjG"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import Type from "typebox";
|
|
5
|
+
import Schema from "typebox/schema";
|
|
6
|
+
import { parseDocument } from "yaml";
|
|
7
|
+
const FRONTMATTER_RE = /^\uFEFF?---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
|
|
8
|
+
const SUPPORTED_FIELDS = new Set(["paths"]);
|
|
9
|
+
const RULE_SOURCE_SCHEMA = Type.Object({
|
|
10
|
+
scope: Type.Union([Type.Literal("repo"), Type.Literal("user")]),
|
|
11
|
+
kind: Type.Union([Type.Literal("pi"), Type.Literal("agents"), Type.Literal("claude")]),
|
|
12
|
+
});
|
|
13
|
+
export const RULE_CONFIG_SCHEMA = Type.Object({
|
|
14
|
+
enabled: Type.Optional(Type.Boolean()),
|
|
15
|
+
sources: Type.Array(RULE_SOURCE_SCHEMA),
|
|
16
|
+
nudges: Type.Optional(Type.Object({ afterCommit: Type.Optional(Type.Boolean()) })),
|
|
17
|
+
});
|
|
18
|
+
export const RULE_CONFIG_PATCH_SCHEMA = Type.Partial(RULE_CONFIG_SCHEMA);
|
|
19
|
+
const RULE_CONFIG_VALIDATOR = Schema.Compile(RULE_CONFIG_SCHEMA);
|
|
20
|
+
const RULE_CONFIG_PATCH_VALIDATOR = Schema.Compile(RULE_CONFIG_PATCH_SCHEMA);
|
|
21
|
+
export const DEFAULT_RULE_SOURCES = [
|
|
22
|
+
{ scope: "repo", kind: "pi" },
|
|
23
|
+
{ scope: "repo", kind: "agents" },
|
|
24
|
+
{ scope: "repo", kind: "claude" },
|
|
25
|
+
{ scope: "user", kind: "pi" },
|
|
26
|
+
{ scope: "user", kind: "agents" },
|
|
27
|
+
{ scope: "user", kind: "claude" },
|
|
28
|
+
];
|
|
29
|
+
export function validateRuleConfigPatch(value) {
|
|
30
|
+
if (RULE_CONFIG_PATCH_VALIDATOR.Check(value))
|
|
31
|
+
return { config: value };
|
|
32
|
+
const [, errors] = RULE_CONFIG_PATCH_VALIDATOR.Errors(value);
|
|
33
|
+
const first = errors[0];
|
|
34
|
+
return { reason: first ? `${first.instancePath || "/"}: ${first.message}` : "schema validation failed" };
|
|
35
|
+
}
|
|
36
|
+
export async function loadRuleConfig(cwd, options = {}) {
|
|
37
|
+
const home = options.home ?? os.homedir();
|
|
38
|
+
const env = options.env ?? process.env;
|
|
39
|
+
const piCodingAgentDirectory = resolvePiCodingAgentDirectory(env, home);
|
|
40
|
+
const candidates = [path.join(cwd, ".pi", "rules.json"), path.join(piCodingAgentDirectory, "rules.json")];
|
|
41
|
+
for (const configPath of candidates) {
|
|
42
|
+
let content;
|
|
43
|
+
try {
|
|
44
|
+
content = await readFile(configPath, "utf8");
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const code = getErrorCode(error);
|
|
48
|
+
if (code === "ENOENT")
|
|
49
|
+
continue;
|
|
50
|
+
return invalidConfig(configPath, labelPath(configPath, cwd, home), `unreadable: ${code}`);
|
|
51
|
+
}
|
|
52
|
+
let value;
|
|
53
|
+
try {
|
|
54
|
+
value = JSON.parse(content);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
58
|
+
return invalidConfig(configPath, labelPath(configPath, cwd, home), `invalid JSON: ${message}`);
|
|
59
|
+
}
|
|
60
|
+
if (!RULE_CONFIG_VALIDATOR.Check(value)) {
|
|
61
|
+
const [, errors] = RULE_CONFIG_VALIDATOR.Errors(value);
|
|
62
|
+
const first = errors[0];
|
|
63
|
+
const reason = first ? `${first.instancePath || "/"}: ${first.message}` : "schema validation failed";
|
|
64
|
+
return invalidConfig(configPath, labelPath(configPath, cwd, home), reason);
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
enabled: value.enabled ?? true,
|
|
68
|
+
sources: value.sources,
|
|
69
|
+
nudgeAfterCommit: value.nudges?.afterCommit ?? false,
|
|
70
|
+
configPath,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return { enabled: true, sources: DEFAULT_RULE_SOURCES, nudgeAfterCommit: false };
|
|
74
|
+
}
|
|
75
|
+
export async function discoverRules(cwd, options = {}) {
|
|
76
|
+
const home = options.home ?? os.homedir();
|
|
77
|
+
const env = options.env ?? process.env;
|
|
78
|
+
const roots = (options.sources ?? DEFAULT_RULE_SOURCES).map((source) => resolveRuleRoot(source, cwd, env, home));
|
|
79
|
+
for (const root of roots) {
|
|
80
|
+
const files = await findMarkdownFiles(root.directory);
|
|
81
|
+
if (files.length === 0)
|
|
82
|
+
continue;
|
|
83
|
+
const rules = [];
|
|
84
|
+
const diagnostics = [];
|
|
85
|
+
for (const relativePath of files) {
|
|
86
|
+
const sourcePath = path.join(root.directory, ...relativePath.split("/"));
|
|
87
|
+
const sourceLabel = `${root.label}/${relativePath}`;
|
|
88
|
+
const parsed = await parseRuleFile(sourcePath, sourceLabel);
|
|
89
|
+
if ("rule" in parsed) {
|
|
90
|
+
rules.push(parsed.rule);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
diagnostics.push(parsed.diagnostic);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return { rules, diagnostics };
|
|
97
|
+
}
|
|
98
|
+
return { rules: [], diagnostics: [] };
|
|
99
|
+
}
|
|
100
|
+
export async function parseRuleFile(sourcePath, sourceLabel) {
|
|
101
|
+
let content;
|
|
102
|
+
try {
|
|
103
|
+
content = await readFile(sourcePath, "utf8");
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
const code = getErrorCode(error);
|
|
107
|
+
return { diagnostic: { sourceLabel, reason: `unreadable: ${code}` } };
|
|
108
|
+
}
|
|
109
|
+
const frontmatter = content.match(FRONTMATTER_RE);
|
|
110
|
+
if (!frontmatter) {
|
|
111
|
+
if (/^\uFEFF?---(?:\r?\n|$)/.test(content)) {
|
|
112
|
+
return { diagnostic: { sourceLabel, reason: "unclosed frontmatter" } };
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
rule: {
|
|
116
|
+
id: sourcePath,
|
|
117
|
+
sourcePath,
|
|
118
|
+
sourceLabel,
|
|
119
|
+
body: content.replace(/^\uFEFF/, ""),
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
let raw;
|
|
124
|
+
try {
|
|
125
|
+
const document = parseDocument(frontmatter[1] ?? "", { logLevel: "silent" });
|
|
126
|
+
if (document.errors.length > 0) {
|
|
127
|
+
return {
|
|
128
|
+
diagnostic: {
|
|
129
|
+
sourceLabel,
|
|
130
|
+
reason: `invalid YAML: ${document.errors[0]?.message ?? "unknown error"}`,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
raw = document.toJS();
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
return {
|
|
138
|
+
diagnostic: {
|
|
139
|
+
sourceLabel,
|
|
140
|
+
reason: `invalid YAML: ${error instanceof Error ? error.message : String(error)}`,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (raw !== null && (typeof raw !== "object" || Array.isArray(raw))) {
|
|
145
|
+
return { diagnostic: { sourceLabel, reason: "frontmatter must be a mapping" } };
|
|
146
|
+
}
|
|
147
|
+
const record = (raw ?? {});
|
|
148
|
+
const unsupported = Object.keys(record).filter((field) => !SUPPORTED_FIELDS.has(field));
|
|
149
|
+
if (unsupported.length > 0) {
|
|
150
|
+
return {
|
|
151
|
+
diagnostic: {
|
|
152
|
+
sourceLabel,
|
|
153
|
+
reason: `unsupported frontmatter field${unsupported.length === 1 ? "" : "s"}: ${unsupported.join(", ")}`,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const paths = normalizePaths(record.paths);
|
|
158
|
+
if (paths && "reason" in paths) {
|
|
159
|
+
return { diagnostic: { sourceLabel, reason: paths.reason } };
|
|
160
|
+
}
|
|
161
|
+
const rule = {
|
|
162
|
+
id: sourcePath,
|
|
163
|
+
sourcePath,
|
|
164
|
+
sourceLabel,
|
|
165
|
+
body: content.slice(frontmatter[0].length),
|
|
166
|
+
};
|
|
167
|
+
if (paths) {
|
|
168
|
+
rule.paths = paths;
|
|
169
|
+
}
|
|
170
|
+
return { rule };
|
|
171
|
+
}
|
|
172
|
+
async function findMarkdownFiles(directory) {
|
|
173
|
+
let entries;
|
|
174
|
+
try {
|
|
175
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
if (getErrorCode(error) === "ENOENT")
|
|
179
|
+
return [];
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
const files = [];
|
|
183
|
+
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
184
|
+
for (const entry of entries) {
|
|
185
|
+
if (entry.isSymbolicLink())
|
|
186
|
+
continue;
|
|
187
|
+
if (entry.isDirectory()) {
|
|
188
|
+
const nested = await findMarkdownFiles(path.join(directory, entry.name));
|
|
189
|
+
files.push(...nested.map((relativePath) => `${entry.name}/${relativePath}`));
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
193
|
+
files.push(entry.name);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return files;
|
|
197
|
+
}
|
|
198
|
+
function resolvePiCodingAgentDirectory(env, home) {
|
|
199
|
+
return env.PI_CODING_AGENT_DIR || path.join(env.PI_CONFIG_DIR || path.join(home, ".pi"), "agent");
|
|
200
|
+
}
|
|
201
|
+
function resolveRuleRoot(source, cwd, env, home) {
|
|
202
|
+
if (source.scope === "repo") {
|
|
203
|
+
return { directory: path.join(cwd, `.${source.kind}`, "rules"), label: `.${source.kind}/rules` };
|
|
204
|
+
}
|
|
205
|
+
if (source.kind === "pi") {
|
|
206
|
+
const directory = path.join(resolvePiCodingAgentDirectory(env, home), "rules");
|
|
207
|
+
return { directory, label: labelDirectory(directory, home) };
|
|
208
|
+
}
|
|
209
|
+
if (source.kind === "agents") {
|
|
210
|
+
return { directory: path.join(home, ".agents", "rules"), label: "~/.agents/rules" };
|
|
211
|
+
}
|
|
212
|
+
const directory = path.join(env.CLAUDE_CONFIG_DIR || path.join(home, ".claude"), "rules");
|
|
213
|
+
return { directory, label: labelDirectory(directory, home) };
|
|
214
|
+
}
|
|
215
|
+
function invalidConfig(configPath, sourceLabel, reason) {
|
|
216
|
+
return { enabled: false, sources: [], nudgeAfterCommit: false, configPath, diagnostic: { sourceLabel, reason } };
|
|
217
|
+
}
|
|
218
|
+
function labelPath(target, cwd, home) {
|
|
219
|
+
const relative = path.relative(cwd, target);
|
|
220
|
+
if (relative !== "" && relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)) {
|
|
221
|
+
return relative.split(path.sep).join("/");
|
|
222
|
+
}
|
|
223
|
+
return labelDirectory(target, home);
|
|
224
|
+
}
|
|
225
|
+
function normalizePaths(raw) {
|
|
226
|
+
if (raw === undefined)
|
|
227
|
+
return undefined;
|
|
228
|
+
const values = typeof raw === "string" ? [raw] : raw;
|
|
229
|
+
if (!Array.isArray(values) || !values.every((value) => typeof value === "string")) {
|
|
230
|
+
return { reason: "paths must be a string or string list" };
|
|
231
|
+
}
|
|
232
|
+
const normalized = values.map((value) => value.trim());
|
|
233
|
+
if (normalized.length === 0 || normalized.some((value) => value.length === 0)) {
|
|
234
|
+
return { reason: "paths must contain at least one non-empty glob" };
|
|
235
|
+
}
|
|
236
|
+
return normalized;
|
|
237
|
+
}
|
|
238
|
+
function labelDirectory(directory, home) {
|
|
239
|
+
const relative = path.relative(home, directory);
|
|
240
|
+
if (relative !== "" && relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)) {
|
|
241
|
+
return `~/${relative.split(path.sep).join("/")}`;
|
|
242
|
+
}
|
|
243
|
+
return directory.split(path.sep).join("/");
|
|
244
|
+
}
|
|
245
|
+
function getErrorCode(error) {
|
|
246
|
+
if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string") {
|
|
247
|
+
return error.code;
|
|
248
|
+
}
|
|
249
|
+
return "EUNKNOWN";
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ExtensionAPI, ToolResultEvent } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { RuleConfigPatch } from "./discovery.js";
|
|
3
|
+
import type { PendingRule } from "./types.js";
|
|
4
|
+
export declare const CUSTOM_MESSAGE_TYPE = "pi-rules-injection";
|
|
5
|
+
export declare const NUDGE_MESSAGE_TYPE = "pi-rules-nudge";
|
|
6
|
+
export declare const CONFIG_EVENT = "pi-rules:config";
|
|
7
|
+
export declare function emitPiRulesConfig(pi: Pick<ExtensionAPI, "events">, config: RuleConfigPatch): void;
|
|
8
|
+
export declare function makeExtension(): (pi: ExtensionAPI) => void;
|
|
9
|
+
export declare function isSuccessfulGitCommit(event: ToolResultEvent): boolean;
|
|
10
|
+
export declare function createInjection(entries: PendingRule[]): {
|
|
11
|
+
customType: string;
|
|
12
|
+
content: string;
|
|
13
|
+
display: boolean;
|
|
14
|
+
details: {
|
|
15
|
+
sources: string[];
|
|
16
|
+
targets: {
|
|
17
|
+
[k: string]: string[];
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
declare const _default: (pi: ExtensionAPI) => void;
|
|
22
|
+
export default _default;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAGrF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,KAAK,EAAE,WAAW,EAA8B,MAAM,YAAY,CAAC;AAE1E,eAAO,MAAM,mBAAmB,uBAAuB,CAAC;AACxD,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AACnD,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAE9C,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,EAChC,MAAM,EAAE,eAAe,GACtB,IAAI,CAEN;AAID,wBAAgB,aAAa,SACf,YAAY,KAAG,IAAI,CAuJhC;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAMrE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE;;;;;;;;;;EAcrD;6BA/Ka,YAAY,KAAG,IAAI;AAyLjC,wBAA+B"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { Text } from "@earendil-works/pi-tui";
|
|
2
|
+
import { DEFAULT_RULE_SOURCES, discoverRules, loadRuleConfig, validateRuleConfigPatch } from "./discovery.js";
|
|
3
|
+
import { extractTarget, ruleMatchesTarget } from "./matching.js";
|
|
4
|
+
export const CUSTOM_MESSAGE_TYPE = "pi-rules-injection";
|
|
5
|
+
export const NUDGE_MESSAGE_TYPE = "pi-rules-nudge";
|
|
6
|
+
export const CONFIG_EVENT = "pi-rules:config";
|
|
7
|
+
export function emitPiRulesConfig(pi, config) {
|
|
8
|
+
pi.events.emit(CONFIG_EVENT, config);
|
|
9
|
+
}
|
|
10
|
+
const NUDGE_CONTENT = `A successful git commit just completed. Review the committed work for a durable, repository-specific convention that future agents would otherwise miss. If one exists, create or update the smallest appropriate rule and prefer paths frontmatter when its scope is limited. Do nothing when no durable rule is warranted. Do not commit or push changes created by this nudge.`;
|
|
11
|
+
export function makeExtension() {
|
|
12
|
+
return (pi) => {
|
|
13
|
+
let config = {
|
|
14
|
+
enabled: true,
|
|
15
|
+
sources: DEFAULT_RULE_SOURCES,
|
|
16
|
+
nudges: { afterCommit: false },
|
|
17
|
+
};
|
|
18
|
+
let rules = [];
|
|
19
|
+
let pendingRuleNudge = false;
|
|
20
|
+
let reportWarning = (message) => {
|
|
21
|
+
process.stderr.write(`${message}\n`);
|
|
22
|
+
};
|
|
23
|
+
const injectedRuleIds = new Set();
|
|
24
|
+
const turnTargets = new Set();
|
|
25
|
+
const stopConfigListener = pi.events.on(CONFIG_EVENT, (value) => {
|
|
26
|
+
const validation = validateRuleConfigPatch(value);
|
|
27
|
+
if ("reason" in validation) {
|
|
28
|
+
reportWarning(`[pi-rules] rejected ${CONFIG_EVENT}: ${validation.reason}`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
config = { ...config, ...validation.config };
|
|
32
|
+
if (config.enabled === false) {
|
|
33
|
+
pendingRuleNudge = false;
|
|
34
|
+
turnTargets.clear();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
pi.on("session_shutdown", stopConfigListener);
|
|
38
|
+
pi.registerMessageRenderer(CUSTOM_MESSAGE_TYPE, (message, { expanded }, theme) => {
|
|
39
|
+
const details = message.details;
|
|
40
|
+
const sourceLines = (details?.sources ?? ["(unknown)"]).map((source) => `↳ ${source}`).join("\n");
|
|
41
|
+
const summary = `Loaded rules:\n${sourceLines}`;
|
|
42
|
+
if (!expanded) {
|
|
43
|
+
return new Text(theme.fg("muted", summary), 0, 0);
|
|
44
|
+
}
|
|
45
|
+
const targetLines = details?.sources
|
|
46
|
+
.map((source) => {
|
|
47
|
+
const targets = details.targets[source] ?? [];
|
|
48
|
+
return targets.length > 0 ? `${source} → ${targets.join(", ")}` : `${source} → unconditional`;
|
|
49
|
+
})
|
|
50
|
+
.join("\n");
|
|
51
|
+
const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content, null, 2);
|
|
52
|
+
return new Text(`${theme.fg("accent", "Loaded rules:")}\n${theme.fg("muted", sourceLines)}\n\n${theme.fg("dim", targetLines ?? "")}\n\n${content}`, 0, 0);
|
|
53
|
+
});
|
|
54
|
+
pi.registerMessageRenderer(NUDGE_MESSAGE_TYPE, (message, { expanded }, theme) => {
|
|
55
|
+
const summary = "Rule nudge: review committed work";
|
|
56
|
+
if (!expanded)
|
|
57
|
+
return new Text(theme.fg("muted", summary), 0, 0);
|
|
58
|
+
const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content, null, 2);
|
|
59
|
+
return new Text(`${theme.fg("accent", summary)}\n\n${content}`, 0, 0);
|
|
60
|
+
});
|
|
61
|
+
const reloadConfig = async (cwd) => {
|
|
62
|
+
const result = await loadRuleConfig(cwd);
|
|
63
|
+
config = {
|
|
64
|
+
enabled: result.enabled,
|
|
65
|
+
sources: result.sources,
|
|
66
|
+
nudges: { afterCommit: result.nudgeAfterCommit },
|
|
67
|
+
};
|
|
68
|
+
if (result.diagnostic) {
|
|
69
|
+
reportWarning(`[pi-rules] invalid config ${result.diagnostic.sourceLabel}: ${result.diagnostic.reason}`);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const reloadRules = async (cwd) => {
|
|
73
|
+
const discovery = await discoverRules(cwd, { sources: config.sources ?? DEFAULT_RULE_SOURCES });
|
|
74
|
+
for (const diagnostic of discovery.diagnostics) {
|
|
75
|
+
reportWarning(`[pi-rules] skipped ${diagnostic.sourceLabel}: ${diagnostic.reason}`);
|
|
76
|
+
}
|
|
77
|
+
return discovery.rules;
|
|
78
|
+
};
|
|
79
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
80
|
+
reportWarning = ctx.hasUI
|
|
81
|
+
? (message) => ctx.ui.notify(message, "warning")
|
|
82
|
+
: (message) => process.stderr.write(`${message}\n`);
|
|
83
|
+
await reloadConfig(ctx.cwd);
|
|
84
|
+
rules = config.enabled !== false ? await reloadRules(ctx.cwd) : [];
|
|
85
|
+
pendingRuleNudge = false;
|
|
86
|
+
injectedRuleIds.clear();
|
|
87
|
+
turnTargets.clear();
|
|
88
|
+
});
|
|
89
|
+
pi.on("before_agent_start", async (_event, ctx) => {
|
|
90
|
+
if (config.enabled === false)
|
|
91
|
+
return;
|
|
92
|
+
rules = await reloadRules(ctx.cwd);
|
|
93
|
+
const unconditional = freshUnconditionalRules(rules, injectedRuleIds);
|
|
94
|
+
if (unconditional.length === 0)
|
|
95
|
+
return;
|
|
96
|
+
const injection = createInjection(unconditional.map((rule) => ({ rule, targets: new Set() })));
|
|
97
|
+
for (const rule of unconditional)
|
|
98
|
+
injectedRuleIds.add(rule.id);
|
|
99
|
+
return { message: injection };
|
|
100
|
+
});
|
|
101
|
+
pi.on("tool_result", (event, ctx) => {
|
|
102
|
+
if (config.enabled === false)
|
|
103
|
+
return;
|
|
104
|
+
const target = extractTarget(event, ctx.cwd);
|
|
105
|
+
if (target)
|
|
106
|
+
turnTargets.add(target);
|
|
107
|
+
if (config.nudges?.afterCommit && isSuccessfulGitCommit(event))
|
|
108
|
+
pendingRuleNudge = true;
|
|
109
|
+
});
|
|
110
|
+
pi.on("agent_settled", () => {
|
|
111
|
+
if (!pendingRuleNudge)
|
|
112
|
+
return;
|
|
113
|
+
pendingRuleNudge = false;
|
|
114
|
+
if (config.enabled === false || !config.nudges?.afterCommit)
|
|
115
|
+
return;
|
|
116
|
+
pi.sendMessage({ customType: NUDGE_MESSAGE_TYPE, content: NUDGE_CONTENT, display: true }, { deliverAs: "followUp", triggerTurn: true });
|
|
117
|
+
});
|
|
118
|
+
pi.on("turn_end", async (_event, ctx) => {
|
|
119
|
+
if (config.enabled === false) {
|
|
120
|
+
turnTargets.clear();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
rules = await reloadRules(ctx.cwd);
|
|
124
|
+
const pending = rules
|
|
125
|
+
.flatMap((rule) => {
|
|
126
|
+
if (injectedRuleIds.has(rule.id))
|
|
127
|
+
return [];
|
|
128
|
+
if (!rule.paths)
|
|
129
|
+
return [{ rule, targets: new Set() }];
|
|
130
|
+
const targets = new Set([...turnTargets].filter((target) => ruleMatchesTarget(rule, target)));
|
|
131
|
+
return targets.size > 0 ? [{ rule, targets }] : [];
|
|
132
|
+
})
|
|
133
|
+
.sort(comparePendingRules);
|
|
134
|
+
turnTargets.clear();
|
|
135
|
+
if (pending.length === 0)
|
|
136
|
+
return;
|
|
137
|
+
pi.sendMessage(createInjection(pending), { deliverAs: "steer" });
|
|
138
|
+
for (const entry of pending)
|
|
139
|
+
injectedRuleIds.add(entry.rule.id);
|
|
140
|
+
});
|
|
141
|
+
pi.on("session_compact", async (_event, ctx) => {
|
|
142
|
+
injectedRuleIds.clear();
|
|
143
|
+
turnTargets.clear();
|
|
144
|
+
await reloadConfig(ctx.cwd);
|
|
145
|
+
if (config.enabled === false) {
|
|
146
|
+
rules = [];
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
rules = await reloadRules(ctx.cwd);
|
|
150
|
+
const unconditional = freshUnconditionalRules(rules, injectedRuleIds);
|
|
151
|
+
if (unconditional.length === 0)
|
|
152
|
+
return;
|
|
153
|
+
const entries = unconditional.map((rule) => ({ rule, targets: new Set() }));
|
|
154
|
+
pi.sendMessage(createInjection(entries));
|
|
155
|
+
for (const rule of unconditional)
|
|
156
|
+
injectedRuleIds.add(rule.id);
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
export function isSuccessfulGitCommit(event) {
|
|
161
|
+
if (event.toolName !== "bash" || event.isError)
|
|
162
|
+
return false;
|
|
163
|
+
const command = event.input.command;
|
|
164
|
+
if (typeof command !== "string")
|
|
165
|
+
return false;
|
|
166
|
+
// ponytail: recognize direct git/rtk commands; compare HEAD if alias and wrapper support becomes necessary.
|
|
167
|
+
return /(?:^|(?:&&|\|\||[;\n(])\s*)(?:rtk\s+)?git(?:\s+-C\s+(?:"[^"]*"|'[^']*'|\S+))?\s+commit(?:\s|$)/.test(command);
|
|
168
|
+
}
|
|
169
|
+
export function createInjection(entries) {
|
|
170
|
+
const sorted = [...entries].sort(comparePendingRules);
|
|
171
|
+
const sources = sorted.map((entry) => entry.rule.sourceLabel);
|
|
172
|
+
const targets = Object.fromEntries(sorted.map((entry) => [entry.rule.sourceLabel, [...entry.targets].sort()]));
|
|
173
|
+
const body = sorted
|
|
174
|
+
.map((entry) => `## Rule: ${entry.rule.sourceLabel}\n\n${entry.rule.body}`)
|
|
175
|
+
.join("\n\n---\n\n");
|
|
176
|
+
return {
|
|
177
|
+
customType: CUSTOM_MESSAGE_TYPE,
|
|
178
|
+
content: body,
|
|
179
|
+
display: true,
|
|
180
|
+
details: { sources, targets },
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function freshUnconditionalRules(rules, injectedRuleIds) {
|
|
184
|
+
return rules.filter((rule) => !rule.paths && !injectedRuleIds.has(rule.id));
|
|
185
|
+
}
|
|
186
|
+
function comparePendingRules(left, right) {
|
|
187
|
+
return left.rule.sourceLabel.localeCompare(right.rule.sourceLabel);
|
|
188
|
+
}
|
|
189
|
+
export default makeExtension();
|
|
190
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ToolResultEvent } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { Rule } from "./types.js";
|
|
3
|
+
export declare function extractTarget(event: ToolResultEvent, cwd: string): string | undefined;
|
|
4
|
+
export declare function ruleMatchesTarget(rule: Rule, target: string): boolean;
|
|
5
|
+
//# sourceMappingURL=matching.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matching.d.ts","sourceRoot":"","sources":["../src/matching.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAiBrF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAIrE"}
|
package/dist/matching.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import picomatch from "picomatch";
|
|
3
|
+
const FILE_TOOLS = new Set(["read", "edit", "write"]);
|
|
4
|
+
export function extractTarget(event, cwd) {
|
|
5
|
+
if (event.isError || !FILE_TOOLS.has(event.toolName))
|
|
6
|
+
return undefined;
|
|
7
|
+
const rawPath = event.input.path;
|
|
8
|
+
if (typeof rawPath !== "string" || rawPath.trim().length === 0)
|
|
9
|
+
return undefined;
|
|
10
|
+
const withoutAt = rawPath.startsWith("@") ? rawPath.slice(1) : rawPath;
|
|
11
|
+
const absolutePath = path.resolve(cwd, withoutAt);
|
|
12
|
+
const relativePath = path.relative(cwd, absolutePath);
|
|
13
|
+
if (relativePath.length === 0 ||
|
|
14
|
+
relativePath === ".." ||
|
|
15
|
+
relativePath.startsWith(`..${path.sep}`) ||
|
|
16
|
+
path.isAbsolute(relativePath)) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
return toPosixPath(relativePath);
|
|
20
|
+
}
|
|
21
|
+
export function ruleMatchesTarget(rule, target) {
|
|
22
|
+
if (!rule.paths)
|
|
23
|
+
return false;
|
|
24
|
+
const patterns = rule.paths.map(normalizePattern);
|
|
25
|
+
return picomatch.isMatch(target, patterns, { dot: true });
|
|
26
|
+
}
|
|
27
|
+
function normalizePattern(pattern) {
|
|
28
|
+
return toPosixPath(pattern).replace(/^\.\//, "");
|
|
29
|
+
}
|
|
30
|
+
function toPosixPath(value) {
|
|
31
|
+
return value.split(path.sep).join("/");
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=matching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matching.js","sourceRoot":"","sources":["../src/matching.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,SAAS,MAAM,WAAW,CAAC;AAIlC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtD,MAAM,UAAU,aAAa,CAAC,KAAsB,EAAE,GAAW;IAC/D,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IACvE,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;IACjC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAEjF,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACvE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAClD,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACtD,IACE,YAAY,CAAC,MAAM,KAAK,CAAC;QACzB,YAAY,KAAK,IAAI;QACrB,YAAY,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;QACxC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAC7B,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,WAAW,CAAC,YAAY,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAU,EAAE,MAAc;IAC1D,IAAI,CAAC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClD,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe;IACvC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface Rule {
|
|
2
|
+
id: string;
|
|
3
|
+
sourcePath: string;
|
|
4
|
+
sourceLabel: string;
|
|
5
|
+
body: string;
|
|
6
|
+
paths?: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface RuleDiagnostic {
|
|
9
|
+
sourceLabel: string;
|
|
10
|
+
reason: string;
|
|
11
|
+
}
|
|
12
|
+
export interface DiscoveryResult {
|
|
13
|
+
rules: Rule[];
|
|
14
|
+
diagnostics: RuleDiagnostic[];
|
|
15
|
+
}
|
|
16
|
+
export interface RuleInjectionDetails {
|
|
17
|
+
sources: string[];
|
|
18
|
+
targets: Record<string, string[]>;
|
|
19
|
+
}
|
|
20
|
+
export interface PendingRule {
|
|
21
|
+
rule: Rule;
|
|
22
|
+
targets: Set<string>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACtB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tigorhutasuhut/pi-rules",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Claude-compatible project rules for Pi agents and subagents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
22
22
|
"typecheck": "tsc --noEmit",
|
|
23
23
|
"test": "npm run build && node --test test/*.test.js",
|
|
24
|
-
"check": "npm run
|
|
24
|
+
"check:pack": "npm pack --dry-run --json --ignore-scripts | node -e \"let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const [{files}]=JSON.parse(s);if(!files.some(f=>f.path==='dist/index.js'))throw new Error('dist/index.js missing from npm package')})\"",
|
|
25
|
+
"check": "npm run typecheck && npm test && npm run check:pack",
|
|
25
26
|
"prepack": "npm run build"
|
|
26
27
|
},
|
|
27
28
|
"dependencies": {
|