@usepipr/sdk 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-DMjdjJV4.d.mts → index-PElu31GO.d.mts} +199 -160
- package/dist/index-PElu31GO.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +628 -1
- package/dist/index.mjs.map +1 -0
- package/dist/internal.d.mts +16 -5
- package/dist/internal.d.mts.map +1 -1
- package/dist/internal.mjs +2 -4
- package/dist/internal.mjs.map +1 -1
- package/dist/prompt-render-BWiLG-qu.mjs +52 -0
- package/dist/prompt-render-BWiLG-qu.mjs.map +1 -0
- package/package.json +2 -10
- package/dist/index-DMjdjJV4.d.mts.map +0 -1
- package/dist/prompt-render-CHlrR9Sa.mjs +0 -13
- package/dist/prompt-render-CHlrR9Sa.mjs.map +0 -1
- package/dist/review.d.mts +0 -2
- package/dist/review.mjs +0 -2
- package/dist/src-CR3NktDT.mjs +0 -599
- package/dist/src-CR3NktDT.mjs.map +0 -1
- package/dist/tools.d.mts +0 -2
- package/dist/tools.mjs +0 -1
package/dist/src-CR3NktDT.mjs
DELETED
|
@@ -1,599 +0,0 @@
|
|
|
1
|
-
import { t as renderPromptValue } from "./prompt-render-CHlrR9Sa.mjs";
|
|
2
|
-
import { z, z as z$1 } from "zod";
|
|
3
|
-
//#region src/prompt.ts
|
|
4
|
-
/** Creates trimmed Markdown from a template literal with common indentation removed. */
|
|
5
|
-
function md(strings, ...values) {
|
|
6
|
-
let text = "";
|
|
7
|
-
for (let index = 0; index < strings.length; index += 1) {
|
|
8
|
-
text += strings[index] ?? "";
|
|
9
|
-
if (index < values.length) text += String(values[index] ?? "");
|
|
10
|
-
}
|
|
11
|
-
return stripCommonIndent(text).trim();
|
|
12
|
-
}
|
|
13
|
-
/** Removes common leading indentation from multiline text. */
|
|
14
|
-
function stripCommonIndent(value) {
|
|
15
|
-
const lines = value.replaceAll(" ", " ").split(/\r?\n/);
|
|
16
|
-
const nonEmpty = lines.filter((line) => line.trim().length > 0);
|
|
17
|
-
const indent = Math.min(...nonEmpty.map((line) => line.match(/^ */)?.[0].length ?? 0));
|
|
18
|
-
return lines.map((line) => line.slice(indent)).join("\n");
|
|
19
|
-
}
|
|
20
|
-
//#endregion
|
|
21
|
-
//#region src/review-contract.ts
|
|
22
|
-
const nonEmptyStringSchema = z.string().min(1);
|
|
23
|
-
const positiveIntegerSchema = z.number().int().positive();
|
|
24
|
-
/** Zod schema for a review summary. */
|
|
25
|
-
const reviewSummarySchema = z.strictObject({
|
|
26
|
-
title: nonEmptyStringSchema.optional(),
|
|
27
|
-
body: nonEmptyStringSchema
|
|
28
|
-
});
|
|
29
|
-
/** Zod schema for one inline review finding. */
|
|
30
|
-
const reviewFindingSchema = z.strictObject({
|
|
31
|
-
body: nonEmptyStringSchema,
|
|
32
|
-
path: nonEmptyStringSchema,
|
|
33
|
-
rangeId: nonEmptyStringSchema,
|
|
34
|
-
side: z.enum(["RIGHT", "LEFT"]),
|
|
35
|
-
startLine: positiveIntegerSchema,
|
|
36
|
-
endLine: positiveIntegerSchema,
|
|
37
|
-
suggestedFix: nonEmptyStringSchema.optional()
|
|
38
|
-
});
|
|
39
|
-
/** Zod schema for pipr's core pull request review result. */
|
|
40
|
-
const reviewResultSchema = z.strictObject({
|
|
41
|
-
summary: reviewSummarySchema,
|
|
42
|
-
inlineFindings: z.array(reviewFindingSchema)
|
|
43
|
-
});
|
|
44
|
-
/** Parses model output for pipr's main pull request review schema. */
|
|
45
|
-
function parseReviewResult(value) {
|
|
46
|
-
return reviewResultSchema.parse(value);
|
|
47
|
-
}
|
|
48
|
-
/** Parses a review summary value. */
|
|
49
|
-
function parseReviewSummary(value) {
|
|
50
|
-
return reviewSummarySchema.parse(value);
|
|
51
|
-
}
|
|
52
|
-
/** Parses one inline review finding. */
|
|
53
|
-
function parseReviewFinding(value) {
|
|
54
|
-
return reviewFindingSchema.parse(value);
|
|
55
|
-
}
|
|
56
|
-
/** Returns a small valid example for the main pull request review schema. */
|
|
57
|
-
function reviewSchemaExample() {
|
|
58
|
-
return {
|
|
59
|
-
summary: {
|
|
60
|
-
title: "Optional concise review title.",
|
|
61
|
-
body: "Concise pull request review summary."
|
|
62
|
-
},
|
|
63
|
-
inlineFindings: [{
|
|
64
|
-
body: "Specific issue and why it matters.",
|
|
65
|
-
path: "src/example.ts",
|
|
66
|
-
rangeId: "rng_example",
|
|
67
|
-
side: "RIGHT",
|
|
68
|
-
startLine: 1,
|
|
69
|
-
endLine: 1,
|
|
70
|
-
suggestedFix: "return safeValue;"
|
|
71
|
-
}]
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
//#endregion
|
|
75
|
-
//#region src/schema.ts
|
|
76
|
-
const coreReviewOutputSchemaId = "core/pr-review";
|
|
77
|
-
/** Defines a typed schema from a Zod schema. */
|
|
78
|
-
function schema(definition) {
|
|
79
|
-
if (!definition || typeof definition.id !== "string") throw new Error("pipr.schema requires { id, schema }");
|
|
80
|
-
assertUserSchemaId(definition.id);
|
|
81
|
-
return createZodSchema(definition.id, definition.schema);
|
|
82
|
-
}
|
|
83
|
-
/** Defines a typed schema from JSON Schema. The generic type is caller supplied. */
|
|
84
|
-
function jsonSchema(definition) {
|
|
85
|
-
if (!definition || typeof definition.id !== "string") throw new Error("pipr.jsonSchema requires { id, schema }");
|
|
86
|
-
assertUserSchemaId(definition.id);
|
|
87
|
-
const zodSchema = z.fromJSONSchema(definition.schema);
|
|
88
|
-
return createSchema(definition.id, (value) => zodSchema.parse(value), definition.schema);
|
|
89
|
-
}
|
|
90
|
-
/** Built-in schemas available as reusable agent output contracts. */
|
|
91
|
-
const schemas = {
|
|
92
|
-
review: createZodSchema(coreReviewOutputSchemaId, reviewResultSchema),
|
|
93
|
-
summary: createZodSchema("core/summary", reviewSummarySchema)
|
|
94
|
-
};
|
|
95
|
-
function createSchema(id, parseValue, schemaJson) {
|
|
96
|
-
return {
|
|
97
|
-
kind: "pipr.schema",
|
|
98
|
-
id,
|
|
99
|
-
jsonSchema: schemaJson,
|
|
100
|
-
parse(value) {
|
|
101
|
-
return parseValue(value);
|
|
102
|
-
},
|
|
103
|
-
safeParse(value) {
|
|
104
|
-
try {
|
|
105
|
-
return {
|
|
106
|
-
success: true,
|
|
107
|
-
data: parseValue(value)
|
|
108
|
-
};
|
|
109
|
-
} catch (error) {
|
|
110
|
-
return {
|
|
111
|
-
success: false,
|
|
112
|
-
error: error instanceof Error ? error : new Error(String(error))
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
function createZodSchema(id, zodSchema) {
|
|
119
|
-
return createSchema(id, (value) => zodSchema.parse(value), jsonSchemaFromZod(id, zodSchema));
|
|
120
|
-
}
|
|
121
|
-
function assertUserSchemaId(id) {
|
|
122
|
-
if (id.startsWith("core/")) throw new Error(`Schema id '${id}' uses the reserved core/ namespace`);
|
|
123
|
-
}
|
|
124
|
-
function jsonSchemaFromZod(id, schemaDefinition) {
|
|
125
|
-
try {
|
|
126
|
-
return z.toJSONSchema(schemaDefinition);
|
|
127
|
-
} catch (error) {
|
|
128
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
129
|
-
throw new Error(`Schema '${id}' could not be converted to JSON Schema. Use JSON-Schema-representable Zod or pipr.jsonSchema<T>(). ${detail}`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
//#endregion
|
|
133
|
-
//#region src/builder.ts
|
|
134
|
-
const configFactoryBrand = Symbol.for("pipr.config.factory");
|
|
135
|
-
const builtinReadOnlyToolBrand = Symbol.for("pipr.builtin.readOnlyTool");
|
|
136
|
-
/** Defines a synchronous pipr configuration factory. */
|
|
137
|
-
function definePipr(configure) {
|
|
138
|
-
return {
|
|
139
|
-
kind: "pipr.config-factory",
|
|
140
|
-
[configFactoryBrand]: true,
|
|
141
|
-
build() {
|
|
142
|
-
const builder = createBuilder();
|
|
143
|
-
const result = configure(builder.api);
|
|
144
|
-
if (typeof result === "object" && result !== null && typeof Reflect.get(result, "then") === "function") throw new Error("definePipr configuration callback must be synchronous");
|
|
145
|
-
return builder.plan();
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
/** Defines a typed pipr plugin installer. */
|
|
150
|
-
function definePlugin(setup) {
|
|
151
|
-
return { setup };
|
|
152
|
-
}
|
|
153
|
-
function createBuilder() {
|
|
154
|
-
const models = [];
|
|
155
|
-
const agents = [];
|
|
156
|
-
const tasks = [];
|
|
157
|
-
const changeRequestTriggers = [];
|
|
158
|
-
const commands = [];
|
|
159
|
-
const tools = [];
|
|
160
|
-
const publication = {};
|
|
161
|
-
let checks;
|
|
162
|
-
let limits;
|
|
163
|
-
const api = {
|
|
164
|
-
tools: { readOnly: [{
|
|
165
|
-
kind: "pipr.tool",
|
|
166
|
-
name: "readOnly",
|
|
167
|
-
[builtinReadOnlyToolBrand]: true
|
|
168
|
-
}] },
|
|
169
|
-
schemas,
|
|
170
|
-
on: { changeRequest(options) {
|
|
171
|
-
if (!Array.isArray(options.actions) || !options.task) throw new Error("pipr.on.changeRequest requires { actions, task }");
|
|
172
|
-
changeRequestTriggers.push({
|
|
173
|
-
actions: options.actions,
|
|
174
|
-
task: options.task
|
|
175
|
-
});
|
|
176
|
-
} },
|
|
177
|
-
secret(options) {
|
|
178
|
-
if (!options || typeof options.name !== "string") throw new Error("pipr.secret requires { name }");
|
|
179
|
-
if (!/^[A-Z_][A-Z0-9_]*$/.test(options.name)) throw new Error(`Secret '${options.name}' must be an environment variable name`);
|
|
180
|
-
return {
|
|
181
|
-
kind: "pipr.secret",
|
|
182
|
-
name: options.name
|
|
183
|
-
};
|
|
184
|
-
},
|
|
185
|
-
model(options) {
|
|
186
|
-
if (!options || typeof options.provider !== "string" || typeof options.model !== "string") throw new Error("pipr.model requires { provider, model }");
|
|
187
|
-
if (!options.provider || !options.model) throw new Error("pipr.model requires provider and model");
|
|
188
|
-
const profile = {
|
|
189
|
-
kind: "pipr.model",
|
|
190
|
-
id: options.id ?? `${options.provider}/${options.model}`,
|
|
191
|
-
provider: options.provider,
|
|
192
|
-
model: options.model,
|
|
193
|
-
apiKey: options.apiKey,
|
|
194
|
-
options: options.options
|
|
195
|
-
};
|
|
196
|
-
models.push(profile);
|
|
197
|
-
return profile;
|
|
198
|
-
},
|
|
199
|
-
agent(definition) {
|
|
200
|
-
const agent = createAgent(definition);
|
|
201
|
-
agents.push(agent);
|
|
202
|
-
return agent;
|
|
203
|
-
},
|
|
204
|
-
task(definition) {
|
|
205
|
-
if (!definition.name || typeof definition.run !== "function") throw new Error("pipr.task requires { name, run }");
|
|
206
|
-
const task = {
|
|
207
|
-
kind: "pipr.task",
|
|
208
|
-
name: definition.name,
|
|
209
|
-
check: definition.check,
|
|
210
|
-
...definition.local === false ? { local: false } : {},
|
|
211
|
-
handler: definition.run
|
|
212
|
-
};
|
|
213
|
-
tasks.push(task);
|
|
214
|
-
return task;
|
|
215
|
-
},
|
|
216
|
-
reviewer(options) {
|
|
217
|
-
return createReviewer(api, options);
|
|
218
|
-
},
|
|
219
|
-
review(options) {
|
|
220
|
-
assertKnownReviewRecipeOptions(options);
|
|
221
|
-
registerReviewRecipe(api, publication, options);
|
|
222
|
-
},
|
|
223
|
-
config(options) {
|
|
224
|
-
if (!options || typeof options !== "object") throw new Error("pipr.config requires an options object");
|
|
225
|
-
mergePublicationConfig(publication, options.publication);
|
|
226
|
-
checks = mergeConfigField("checks", checks, options.checks);
|
|
227
|
-
limits = mergeLimits(limits, options.limits);
|
|
228
|
-
},
|
|
229
|
-
command(options) {
|
|
230
|
-
if (typeof options.pattern !== "string" || !options.task) throw new Error("pipr.command requires { pattern, task }");
|
|
231
|
-
const pattern = options.pattern;
|
|
232
|
-
const tokens = pattern.trim().split(/\s+/).filter(Boolean);
|
|
233
|
-
if (tokens.length === 0) throw new Error("Command pattern must not be empty");
|
|
234
|
-
if (tokens[0] !== "@pipr") throw new Error(`Command pattern '${pattern}' must start with @pipr`);
|
|
235
|
-
assertSupportedCommandRestCapture(pattern);
|
|
236
|
-
commands.push({
|
|
237
|
-
pattern,
|
|
238
|
-
permission: options.permission ?? "write",
|
|
239
|
-
description: options.description,
|
|
240
|
-
parse: options.parse,
|
|
241
|
-
task: options.task
|
|
242
|
-
});
|
|
243
|
-
},
|
|
244
|
-
checks(options) {
|
|
245
|
-
checks = mergeConfigField("checks", checks, options);
|
|
246
|
-
},
|
|
247
|
-
limits(options) {
|
|
248
|
-
limits = mergeLimits(limits, options);
|
|
249
|
-
},
|
|
250
|
-
use(plugin) {
|
|
251
|
-
return plugin.setup(api);
|
|
252
|
-
},
|
|
253
|
-
tool(definition) {
|
|
254
|
-
if (definition.name === "readOnly") throw new Error("Tool name 'readOnly' is reserved for pipr built-in tools");
|
|
255
|
-
const execute = definition.execute;
|
|
256
|
-
let run = definition.run;
|
|
257
|
-
if (!run && !execute) throw new Error(`Tool '${definition.name}' must define run`);
|
|
258
|
-
if (!run) {
|
|
259
|
-
const executeTool = execute;
|
|
260
|
-
if (!executeTool) throw new Error(`Tool '${definition.name}' must define run`);
|
|
261
|
-
run = (options) => executeTool(options.ctx, options.input);
|
|
262
|
-
}
|
|
263
|
-
const tool = {
|
|
264
|
-
kind: "pipr.tool",
|
|
265
|
-
...definition,
|
|
266
|
-
run
|
|
267
|
-
};
|
|
268
|
-
tools.push(tool);
|
|
269
|
-
return tool;
|
|
270
|
-
},
|
|
271
|
-
schema,
|
|
272
|
-
jsonSchema,
|
|
273
|
-
prompt(strings, ...values) {
|
|
274
|
-
let text = "";
|
|
275
|
-
for (let index = 0; index < strings.length; index += 1) {
|
|
276
|
-
text += strings[index] ?? "";
|
|
277
|
-
if (index < values.length) text += renderPromptValue(values[index]);
|
|
278
|
-
}
|
|
279
|
-
return {
|
|
280
|
-
kind: "pipr.prompt",
|
|
281
|
-
value: stripCommonIndent(text).trim()
|
|
282
|
-
};
|
|
283
|
-
},
|
|
284
|
-
section(title, value) {
|
|
285
|
-
return {
|
|
286
|
-
kind: "pipr.prompt",
|
|
287
|
-
value: `## ${title}\n\n${renderPromptValue(value)}`
|
|
288
|
-
};
|
|
289
|
-
},
|
|
290
|
-
json(value, options) {
|
|
291
|
-
const text = JSON.stringify(value, null, options?.pretty === false ? 0 : 2);
|
|
292
|
-
if (options?.maxCharacters !== void 0 && text.length > options.maxCharacters) throw new Error(`JSON prompt value exceeded ${options.maxCharacters} characters`);
|
|
293
|
-
return {
|
|
294
|
-
kind: "pipr.prompt",
|
|
295
|
-
value: text
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
return {
|
|
300
|
-
api,
|
|
301
|
-
plan() {
|
|
302
|
-
assertUnique(tasks.map((task) => task.name), "task");
|
|
303
|
-
assertUnique(commands.map((command) => command.pattern), "command");
|
|
304
|
-
assertModelIdentity(models);
|
|
305
|
-
return {
|
|
306
|
-
models,
|
|
307
|
-
agents,
|
|
308
|
-
tasks,
|
|
309
|
-
changeRequestTriggers,
|
|
310
|
-
commands,
|
|
311
|
-
tools,
|
|
312
|
-
publication,
|
|
313
|
-
checks,
|
|
314
|
-
limits
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
function registerReviewRecipe(api, publication, options) {
|
|
320
|
-
const id = options.id;
|
|
321
|
-
registerReviewRecipeEntrypoints(api, createReviewRecipeTask(api, id, options.reviewer ?? createReviewer(api, reviewRecipeReviewerOptions(options, id)), options), options);
|
|
322
|
-
updateReviewRecipePublication(publication, options);
|
|
323
|
-
}
|
|
324
|
-
const reviewRecipeOptionKeys = new Set([
|
|
325
|
-
"id",
|
|
326
|
-
"entrypoints",
|
|
327
|
-
"inlineComments",
|
|
328
|
-
"comment",
|
|
329
|
-
"check",
|
|
330
|
-
"timeout",
|
|
331
|
-
"paths",
|
|
332
|
-
"reviewer",
|
|
333
|
-
"name",
|
|
334
|
-
"model",
|
|
335
|
-
"fallbacks",
|
|
336
|
-
"instructions",
|
|
337
|
-
"prompt",
|
|
338
|
-
"tools"
|
|
339
|
-
]);
|
|
340
|
-
const reviewRecipeEntrypointKeys = new Set(["changeRequest", "command"]);
|
|
341
|
-
function assertKnownReviewRecipeOptions(options) {
|
|
342
|
-
const unknownKeys = Object.keys(options).filter((key) => !reviewRecipeOptionKeys.has(key));
|
|
343
|
-
if (unknownKeys.length > 0) throw new Error(`pipr.review received unsupported option fields: ${unknownKeys.join(", ")}.`);
|
|
344
|
-
const entrypoints = options.entrypoints;
|
|
345
|
-
if (entrypoints && typeof entrypoints === "object") {
|
|
346
|
-
const unknownEntrypointKeys = Object.keys(entrypoints).filter((key) => !reviewRecipeEntrypointKeys.has(key));
|
|
347
|
-
if (unknownEntrypointKeys.length > 0) throw new Error(`pipr.review entrypoints received unsupported fields: ${unknownEntrypointKeys.join(", ")}.`);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
function reviewRecipeReviewerOptions(options, name) {
|
|
351
|
-
if (!options.model || !options.instructions) throw new Error("pipr.review requires model and instructions when reviewer is not provided");
|
|
352
|
-
return {
|
|
353
|
-
name,
|
|
354
|
-
model: options.model,
|
|
355
|
-
fallbacks: options.fallbacks,
|
|
356
|
-
instructions: options.instructions,
|
|
357
|
-
prompt: options.prompt,
|
|
358
|
-
tools: options.tools,
|
|
359
|
-
timeout: options.timeout
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
function createReviewer(api, options) {
|
|
363
|
-
return api.agent({
|
|
364
|
-
name: options.name ?? "reviewer",
|
|
365
|
-
model: options.model,
|
|
366
|
-
fallbacks: options.fallbacks,
|
|
367
|
-
instructions: options.instructions,
|
|
368
|
-
tools: options.tools ?? api.tools.readOnly,
|
|
369
|
-
output: api.schemas.review,
|
|
370
|
-
timeout: options.timeout,
|
|
371
|
-
prompt: options.prompt ?? (() => api.prompt`
|
|
372
|
-
Review this change.
|
|
373
|
-
`)
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
function createReviewRecipeTask(api, id, agent, options) {
|
|
377
|
-
return api.task({
|
|
378
|
-
name: id,
|
|
379
|
-
check: options.check,
|
|
380
|
-
async run(context) {
|
|
381
|
-
const manifest = await context.change.diffManifest({
|
|
382
|
-
compressed: true,
|
|
383
|
-
paths: options.paths
|
|
384
|
-
});
|
|
385
|
-
if (options.paths && manifest.files.length === 0) {
|
|
386
|
-
context.check.neutral("No changed files matched this review's path scope.");
|
|
387
|
-
await context.comment({ main: "No changed files matched this review's path scope." });
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
|
-
const result = await context.pi.run(agent, {
|
|
391
|
-
manifest,
|
|
392
|
-
change: context.change
|
|
393
|
-
}, {
|
|
394
|
-
timeout: options.timeout,
|
|
395
|
-
paths: options.paths
|
|
396
|
-
});
|
|
397
|
-
const source = typeof options.comment === "function" ? await options.comment(result, {
|
|
398
|
-
review: { id },
|
|
399
|
-
repository: context.repository,
|
|
400
|
-
change: context.change,
|
|
401
|
-
platform: context.platform
|
|
402
|
-
}) : options.comment ?? defaultReviewComment(result, options.inlineComments !== false);
|
|
403
|
-
await context.comment(source);
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
function defaultReviewComment(result, includeInlineFindings) {
|
|
408
|
-
return {
|
|
409
|
-
main: includeInlineFindings ? defaultReviewMarkdown(result) : result.summary.body,
|
|
410
|
-
...includeInlineFindings ? { inlineFindings: result.inlineFindings } : {}
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
function defaultReviewMarkdown(result) {
|
|
414
|
-
const findings = result.inlineFindings.length === 0 ? "No inline findings." : result.inlineFindings.map((finding) => `- ${finding.body}`).join("\n");
|
|
415
|
-
return `## Summary\n\n${result.summary.body}\n\n## Findings\n\n${findings}`;
|
|
416
|
-
}
|
|
417
|
-
function registerReviewRecipeEntrypoints(api, task, options) {
|
|
418
|
-
const changeRequest = reviewChangeRequestEntrypoint(options);
|
|
419
|
-
if (changeRequest) api.on.changeRequest({
|
|
420
|
-
actions: changeRequest,
|
|
421
|
-
task
|
|
422
|
-
});
|
|
423
|
-
const command = reviewCommandEntrypoint(options);
|
|
424
|
-
if (command) api.command({
|
|
425
|
-
pattern: command.pattern,
|
|
426
|
-
...command.options,
|
|
427
|
-
task
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
function reviewChangeRequestEntrypoint(options) {
|
|
431
|
-
const entrypoint = options.entrypoints?.changeRequest;
|
|
432
|
-
return entrypoint === false ? void 0 : entrypoint ?? [
|
|
433
|
-
"opened",
|
|
434
|
-
"updated",
|
|
435
|
-
"reopened",
|
|
436
|
-
"ready"
|
|
437
|
-
];
|
|
438
|
-
}
|
|
439
|
-
function reviewCommandEntrypoint(options) {
|
|
440
|
-
const entrypoint = options.entrypoints?.command;
|
|
441
|
-
if (entrypoint === false) return;
|
|
442
|
-
if (typeof entrypoint === "object") return reviewObjectCommandEntrypoint(entrypoint);
|
|
443
|
-
return reviewStringCommandEntrypoint(entrypoint);
|
|
444
|
-
}
|
|
445
|
-
function reviewObjectCommandEntrypoint(entrypoint) {
|
|
446
|
-
return {
|
|
447
|
-
pattern: entrypoint.pattern ?? "@pipr review",
|
|
448
|
-
options: {
|
|
449
|
-
permission: entrypoint.permission ?? "write",
|
|
450
|
-
description: entrypoint.description
|
|
451
|
-
}
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
function reviewStringCommandEntrypoint(entrypoint) {
|
|
455
|
-
return {
|
|
456
|
-
pattern: entrypoint ?? "@pipr review",
|
|
457
|
-
options: { permission: "write" }
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
function updateReviewRecipePublication(publication, options) {
|
|
461
|
-
const maxInlineComments = options.inlineComments === false ? 0 : options.inlineComments?.max ?? 5;
|
|
462
|
-
if (publication.maxInlineComments !== void 0 && publication.maxInlineComments !== maxInlineComments) throw new Error("pipr.review inlineComments settings must match across review recipes");
|
|
463
|
-
publication.maxInlineComments = maxInlineComments;
|
|
464
|
-
}
|
|
465
|
-
function mergePublicationConfig(target, next) {
|
|
466
|
-
if (!next) return;
|
|
467
|
-
if (next.maxInlineComments !== void 0) {
|
|
468
|
-
if (target.maxInlineComments !== void 0 && target.maxInlineComments !== next.maxInlineComments) throw new Error("pipr.config publication.maxInlineComments conflicts with existing value");
|
|
469
|
-
target.maxInlineComments = next.maxInlineComments;
|
|
470
|
-
}
|
|
471
|
-
if (next.autoResolve !== void 0) {
|
|
472
|
-
if (target.autoResolve !== void 0 && stableJson(target.autoResolve) !== stableJson(next.autoResolve)) throw new Error("pipr.config publication.autoResolve conflicts with existing value");
|
|
473
|
-
target.autoResolve = next.autoResolve;
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
function mergeConfigField(name, current, next) {
|
|
477
|
-
if (next === void 0) return current;
|
|
478
|
-
if (current !== void 0 && stableJson(current) !== stableJson(next)) throw new Error(`pipr.config ${name} conflicts with existing value`);
|
|
479
|
-
return next;
|
|
480
|
-
}
|
|
481
|
-
function mergeLimits(current, next) {
|
|
482
|
-
if (!next) return current;
|
|
483
|
-
assertRuntimeLimitConflicts(current, next);
|
|
484
|
-
return {
|
|
485
|
-
...current,
|
|
486
|
-
...next,
|
|
487
|
-
diffManifest: next.diffManifest ?? current?.diffManifest ? {
|
|
488
|
-
...current?.diffManifest,
|
|
489
|
-
...next.diffManifest
|
|
490
|
-
} : void 0
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
function assertRuntimeLimitConflicts(current, next) {
|
|
494
|
-
const currentRecord = current;
|
|
495
|
-
for (const [key, value] of Object.entries(next)) {
|
|
496
|
-
if (key === "diffManifest") continue;
|
|
497
|
-
if (value !== void 0 && currentRecord?.[key] !== void 0 && stableJson(currentRecord[key]) !== stableJson(value)) throw new Error(`pipr.config limits.${key} conflicts with existing value`);
|
|
498
|
-
}
|
|
499
|
-
assertDiffManifestLimitConflicts(current, next);
|
|
500
|
-
}
|
|
501
|
-
function assertDiffManifestLimitConflicts(current, next) {
|
|
502
|
-
if (current?.diffManifest && next.diffManifest) {
|
|
503
|
-
for (const [key, value] of Object.entries(next.diffManifest)) if (value !== void 0 && current.diffManifest[key] !== void 0 && current.diffManifest[key] !== value) throw new Error(`pipr.config limits.diffManifest.${key} conflicts with existing value`);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
function createAgent(definition) {
|
|
507
|
-
return {
|
|
508
|
-
kind: "pipr.agent",
|
|
509
|
-
name: definition.name,
|
|
510
|
-
definition,
|
|
511
|
-
extend(patch) {
|
|
512
|
-
return createAgent({
|
|
513
|
-
...definition,
|
|
514
|
-
...patch,
|
|
515
|
-
instructions: patch.instructions === void 0 ? definition.instructions : {
|
|
516
|
-
kind: "pipr.prompt",
|
|
517
|
-
value: `${renderPromptValue(definition.instructions)}\n\n${renderPromptValue(patch.instructions)}`.trim()
|
|
518
|
-
}
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
function assertUnique(values, label) {
|
|
524
|
-
const seen = /* @__PURE__ */ new Set();
|
|
525
|
-
for (const value of values) {
|
|
526
|
-
if (seen.has(value)) throw new Error(`Duplicate ${label} '${value}'`);
|
|
527
|
-
seen.add(value);
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
function assertSupportedCommandRestCapture(pattern) {
|
|
531
|
-
const parts = pattern.match(/\[[^\]]+\]|[^\s]+/g) ?? [];
|
|
532
|
-
for (const [index, part] of parts.entries()) {
|
|
533
|
-
if (part.startsWith("[") && part.endsWith("]")) {
|
|
534
|
-
const optionalRest = part.slice(1, -1).trim().split(/\s+/).find(isRestCaptureToken);
|
|
535
|
-
if (optionalRest) throw new Error(finalRequiredRestCaptureMessage(optionalRest));
|
|
536
|
-
continue;
|
|
537
|
-
}
|
|
538
|
-
if (isRestCaptureToken(part) && index !== parts.length - 1) throw new Error(finalRequiredRestCaptureMessage(part));
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
function isRestCaptureToken(value) {
|
|
542
|
-
return /^<[a-z0-9-]+\.\.\.>$/.test(value);
|
|
543
|
-
}
|
|
544
|
-
function finalRequiredRestCaptureMessage(token) {
|
|
545
|
-
return `Rest capture '${token}' must be the final required command pattern token`;
|
|
546
|
-
}
|
|
547
|
-
function assertModelIdentity(models) {
|
|
548
|
-
const ids = /* @__PURE__ */ new Set();
|
|
549
|
-
const effectiveConfigs = /* @__PURE__ */ new Map();
|
|
550
|
-
const providerModels = /* @__PURE__ */ new Map();
|
|
551
|
-
for (const model of models) {
|
|
552
|
-
const effectiveConfig = stableJson({
|
|
553
|
-
provider: model.provider,
|
|
554
|
-
model: model.model,
|
|
555
|
-
apiKeyEnv: model.apiKey?.name,
|
|
556
|
-
options: model.options
|
|
557
|
-
});
|
|
558
|
-
const providerModel = `${model.provider}/${model.model}`;
|
|
559
|
-
assertUniqueModelId({
|
|
560
|
-
model,
|
|
561
|
-
providerModel,
|
|
562
|
-
effectiveConfig,
|
|
563
|
-
ids,
|
|
564
|
-
effectiveConfigs
|
|
565
|
-
});
|
|
566
|
-
ids.add(model.id);
|
|
567
|
-
const existingConfigId = effectiveConfigs.get(effectiveConfig);
|
|
568
|
-
if (existingConfigId) throw new Error(`Duplicate model config for '${model.id}'. Reuse model '${existingConfigId}' instead.`);
|
|
569
|
-
effectiveConfigs.set(effectiveConfig, model.id);
|
|
570
|
-
assertExplicitIdForRepeatedProviderModel(model, providerModel, providerModels);
|
|
571
|
-
providerModels.set(providerModel, model.id);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
function assertUniqueModelId(options) {
|
|
575
|
-
if (!options.ids.has(options.model.id)) return;
|
|
576
|
-
if (options.model.id !== options.providerModel) throw new Error(`Duplicate model id '${options.model.id}'`);
|
|
577
|
-
const existingConfigId = options.effectiveConfigs.get(options.effectiveConfig);
|
|
578
|
-
if (existingConfigId) throw new Error(`Duplicate model config for '${options.model.id}'. Reuse model '${existingConfigId}' instead.`);
|
|
579
|
-
throw explicitModelIdError(options.providerModel);
|
|
580
|
-
}
|
|
581
|
-
function assertExplicitIdForRepeatedProviderModel(model, providerModel, providerModels) {
|
|
582
|
-
const existingProviderModelId = providerModels.get(providerModel);
|
|
583
|
-
if (existingProviderModelId && (model.id === providerModel || existingProviderModelId === providerModel)) throw explicitModelIdError(providerModel);
|
|
584
|
-
}
|
|
585
|
-
function explicitModelIdError(providerModel) {
|
|
586
|
-
return /* @__PURE__ */ new Error(`Model '${providerModel}' is configured more than once with different options. Add an explicit id.`);
|
|
587
|
-
}
|
|
588
|
-
function stableJson(value) {
|
|
589
|
-
return JSON.stringify(stableJsonValue(value));
|
|
590
|
-
}
|
|
591
|
-
function stableJsonValue(value) {
|
|
592
|
-
if (Array.isArray(value)) return value.map(stableJsonValue);
|
|
593
|
-
if (typeof value === "object" && value !== null) return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, stableJsonValue(item)]));
|
|
594
|
-
return value;
|
|
595
|
-
}
|
|
596
|
-
//#endregion
|
|
597
|
-
export { schema as a, parseReviewResult as c, reviewResultSchema as d, reviewSchemaExample as f, jsonSchema as i, parseReviewSummary as l, md as m, definePipr as n, schemas as o, reviewSummarySchema as p, definePlugin as r, parseReviewFinding as s, z$1 as t, reviewFindingSchema as u };
|
|
598
|
-
|
|
599
|
-
//# sourceMappingURL=src-CR3NktDT.mjs.map
|