@usepipr/runtime 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +8 -5
- package/dist/{commands-DA0Ij4Di.d.mts → commands-CF59DZXx.d.mts} +2 -2
- package/dist/{commands-DA0Ij4Di.d.mts.map → commands-CF59DZXx.d.mts.map} +1 -1
- package/dist/{commands-B9qNW4pk.mjs → commands-DgZU7tf7.mjs} +474 -334
- package/dist/commands-DgZU7tf7.mjs.map +1 -0
- package/dist/index.d.mts +16 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +117 -15
- package/dist/index.mjs.map +1 -1
- package/dist/internal/action-result.d.mts +4 -2
- package/dist/internal/action-result.d.mts.map +1 -1
- package/dist/internal/action-result.mjs +28 -12
- package/dist/internal/action-result.mjs.map +1 -1
- package/dist/internal/docs.mjs +1 -1
- package/dist/internal/pipr-result.d.mts +24 -0
- package/dist/internal/pipr-result.d.mts.map +1 -0
- package/dist/internal/pipr-result.mjs +126 -0
- package/dist/internal/pipr-result.mjs.map +1 -0
- package/dist/internal/testing.d.mts +11 -11
- package/dist/internal/testing.d.mts.map +1 -1
- package/dist/internal/testing.mjs +1 -1
- package/dist/main-comment-envelope-DFirHYhW.mjs +69 -0
- package/dist/main-comment-envelope-DFirHYhW.mjs.map +1 -0
- package/dist/{official-github-workflow-Bjlu-FL3.mjs → official-github-workflow-DNzV5Z70.mjs} +183 -33
- package/dist/official-github-workflow-DNzV5Z70.mjs.map +1 -0
- package/dist/{types-BAis_Lwm.d.mts → types-Dn1U3MDG.d.mts} +30 -18
- package/dist/types-Dn1U3MDG.d.mts.map +1 -0
- package/package.json +16 -8
- package/dist/commands-B9qNW4pk.mjs.map +0 -1
- package/dist/official-github-workflow-Bjlu-FL3.mjs.map +0 -1
- package/dist/types-BAis_Lwm.d.mts.map +0 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { t as parseGeneratedMainCommentEnvelope } from "../main-comment-envelope-DFirHYhW.mjs";
|
|
2
|
+
import { parsePiprResult } from "@usepipr/sdk";
|
|
3
|
+
//#region src/internal/pipr-result.ts
|
|
4
|
+
const genericFailureMessage = "Pipr failed; see the Action log for details.";
|
|
5
|
+
const publicationFailureMessage = "Pipr could not complete publication; see the Action log for details.";
|
|
6
|
+
function toPiprResult(input) {
|
|
7
|
+
return parsePiprResult(input.source === "local" ? localResult(input.result) : hostResult(input.result));
|
|
8
|
+
}
|
|
9
|
+
function toPiprErrorResult(_error) {
|
|
10
|
+
const result = parsePiprResult({
|
|
11
|
+
formatVersion: 2,
|
|
12
|
+
kind: "error",
|
|
13
|
+
message: genericFailureMessage
|
|
14
|
+
});
|
|
15
|
+
if (result.kind !== "error") throw new Error("Pipr error result schema returned an unexpected result kind");
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
function localResult(result) {
|
|
19
|
+
if (result.kind === "skipped") return {
|
|
20
|
+
formatVersion: 2,
|
|
21
|
+
kind: "skipped",
|
|
22
|
+
reason: result.skipReason
|
|
23
|
+
};
|
|
24
|
+
return reviewResult(result, { state: "disabled" });
|
|
25
|
+
}
|
|
26
|
+
function hostResult(result) {
|
|
27
|
+
switch (result.kind) {
|
|
28
|
+
case "ignored": return {
|
|
29
|
+
formatVersion: 2,
|
|
30
|
+
kind: "ignored",
|
|
31
|
+
reason: result.reason
|
|
32
|
+
};
|
|
33
|
+
case "dry-run": return {
|
|
34
|
+
formatVersion: 2,
|
|
35
|
+
kind: "dry-run"
|
|
36
|
+
};
|
|
37
|
+
case "command-help": return {
|
|
38
|
+
formatVersion: 2,
|
|
39
|
+
kind: "command-help",
|
|
40
|
+
reason: result.reason,
|
|
41
|
+
mainComment: result.body
|
|
42
|
+
};
|
|
43
|
+
case "command-response": return {
|
|
44
|
+
formatVersion: 2,
|
|
45
|
+
kind: "command-response",
|
|
46
|
+
run: publicRunSummary(result.run),
|
|
47
|
+
mainComment: result.response.body,
|
|
48
|
+
publication: {
|
|
49
|
+
state: "completed",
|
|
50
|
+
action: result.publication.action
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
case "verifier": return {
|
|
54
|
+
formatVersion: 2,
|
|
55
|
+
kind: "verifier",
|
|
56
|
+
run: publicRunSummary(result.run),
|
|
57
|
+
publication: {
|
|
58
|
+
state: "completed",
|
|
59
|
+
inlineResolutionErrorCount: result.errors.length
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
case "review": return reviewResult(result.review, {
|
|
63
|
+
state: "completed",
|
|
64
|
+
mainComment: { action: result.publication.mainComment.action },
|
|
65
|
+
inlineComments: result.publication.inlineComments,
|
|
66
|
+
inlinePublicationErrorCount: result.publication.metadata.inlinePublicationErrors.length,
|
|
67
|
+
inlineResolutionErrorCount: result.publication.metadata.inlineResolutionErrors.length
|
|
68
|
+
});
|
|
69
|
+
case "publication-error": return publicationErrorResult(result.publication);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function reviewResult(review, publication) {
|
|
73
|
+
return {
|
|
74
|
+
formatVersion: 2,
|
|
75
|
+
kind: "review",
|
|
76
|
+
run: publicRunSummary(review.run),
|
|
77
|
+
mainComment: stripPiprMainCommentMarkers(review.mainComment),
|
|
78
|
+
inlineFindings: review.inlineCommentDrafts.map((draft) => draft.finding),
|
|
79
|
+
droppedFindings: review.validated.droppedFindings,
|
|
80
|
+
taskChecks: review.taskChecks,
|
|
81
|
+
repairAttempted: review.repairAttempted,
|
|
82
|
+
publication
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function publicRunSummary(run) {
|
|
86
|
+
const bounded = (value) => value.slice(0, 200);
|
|
87
|
+
return {
|
|
88
|
+
...run,
|
|
89
|
+
id: bounded(run.id),
|
|
90
|
+
baseSha: bounded(run.baseSha),
|
|
91
|
+
headSha: bounded(run.headSha),
|
|
92
|
+
tasks: run.tasks.slice(0, 200).map(bounded),
|
|
93
|
+
models: run.models.slice(0, 20).map(bounded)
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function publicationErrorResult(publication) {
|
|
97
|
+
return {
|
|
98
|
+
formatVersion: 2,
|
|
99
|
+
kind: "publication-error",
|
|
100
|
+
message: publicationFailureMessage,
|
|
101
|
+
...publication ? { publication: {
|
|
102
|
+
inlineComments: publication.inlineComments,
|
|
103
|
+
inlinePublicationErrorCount: publication.metadata.inlinePublicationErrors.length,
|
|
104
|
+
inlineResolutionErrorCount: publication.metadata.inlineResolutionErrors.length
|
|
105
|
+
} } : {}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function stripPiprMainCommentMarkers(mainComment) {
|
|
109
|
+
const lines = mainComment.split("\n");
|
|
110
|
+
const envelope = parseGeneratedMainCommentEnvelope(lines);
|
|
111
|
+
const generatedMarkerIndexes = /* @__PURE__ */ new Set([
|
|
112
|
+
envelope.mainMarkerIndex,
|
|
113
|
+
envelope.headerMarkerIndex,
|
|
114
|
+
envelope.statsMarkerIndex,
|
|
115
|
+
envelope.statsRange?.start ?? -1,
|
|
116
|
+
envelope.statsRange?.end ?? -1,
|
|
117
|
+
lines[envelope.footerIndex] === "<!-- pipr:footer:hidden -->" ? envelope.footerIndex : -1
|
|
118
|
+
]);
|
|
119
|
+
const visibleLines = lines.filter((_line, index) => !generatedMarkerIndexes.has(index));
|
|
120
|
+
const firstContentLine = visibleLines.findIndex((line) => line !== "");
|
|
121
|
+
return firstContentLine === -1 ? "" : visibleLines.slice(firstContentLine).join("\n");
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
export { stripPiprMainCommentMarkers, toPiprErrorResult, toPiprResult };
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=pipr-result.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipr-result.mjs","names":[],"sources":["../../src/internal/pipr-result.ts"],"sourcesContent":["import { type PiprResult, type PiprRunSummary, parsePiprResult } from \"@usepipr/sdk\";\nimport type { HostRunCommandResult, LocalReviewCommandResult } from \"../host-run/types.js\";\nimport { mainCommentFooterHiddenMarker } from \"../review/comment-branding.js\";\nimport { parseGeneratedMainCommentEnvelope } from \"../review/main-comment-envelope.js\";\nimport type { PublicationError } from \"../review/publication-result.js\";\n\nconst genericFailureMessage = \"Pipr failed; see the Action log for details.\";\nconst publicationFailureMessage =\n \"Pipr could not complete publication; see the Action log for details.\";\n\ntype ResultInput =\n | { source: \"host\"; result: HostRunCommandResult }\n | { source: \"local\"; result: LocalReviewCommandResult }\n | {\n source: \"host\";\n result: { kind: \"publication-error\"; publication: PublicationError[\"result\"] };\n };\n\nexport function toPiprResult(input: ResultInput): PiprResult {\n return parsePiprResult(\n input.source === \"local\" ? localResult(input.result) : hostResult(input.result),\n );\n}\n\nexport function toPiprErrorResult(_error: unknown): Extract<PiprResult, { kind: \"error\" }> {\n const result = parsePiprResult({\n formatVersion: 2,\n kind: \"error\",\n message: genericFailureMessage,\n });\n if (result.kind !== \"error\") {\n throw new Error(\"Pipr error result schema returned an unexpected result kind\");\n }\n return result;\n}\n\nfunction localResult(result: LocalReviewCommandResult): PiprResult {\n if (result.kind === \"skipped\") {\n return { formatVersion: 2, kind: \"skipped\", reason: result.skipReason };\n }\n return reviewResult(result, { state: \"disabled\" });\n}\n\nfunction hostResult(\n result:\n | HostRunCommandResult\n | { kind: \"publication-error\"; publication: PublicationError[\"result\"] },\n): PiprResult {\n switch (result.kind) {\n case \"ignored\":\n return { formatVersion: 2, kind: \"ignored\", reason: result.reason };\n case \"dry-run\":\n return { formatVersion: 2, kind: \"dry-run\" };\n case \"command-help\":\n return {\n formatVersion: 2,\n kind: \"command-help\",\n reason: result.reason,\n mainComment: result.body,\n };\n case \"command-response\":\n return {\n formatVersion: 2,\n kind: \"command-response\",\n run: publicRunSummary(result.run),\n mainComment: result.response.body,\n publication: { state: \"completed\", action: result.publication.action },\n };\n case \"verifier\":\n return {\n formatVersion: 2,\n kind: \"verifier\",\n run: publicRunSummary(result.run),\n publication: { state: \"completed\", inlineResolutionErrorCount: result.errors.length },\n };\n case \"review\":\n return reviewResult(result.review, {\n state: \"completed\",\n mainComment: { action: result.publication.mainComment.action },\n inlineComments: result.publication.inlineComments,\n inlinePublicationErrorCount: result.publication.metadata.inlinePublicationErrors.length,\n inlineResolutionErrorCount: result.publication.metadata.inlineResolutionErrors.length,\n });\n case \"publication-error\":\n return publicationErrorResult(result.publication);\n }\n}\n\nfunction reviewResult(\n review: Extract<LocalReviewCommandResult, { kind: \"review\" }>,\n publication: Extract<PiprResult, { kind: \"review\" }>[\"publication\"],\n): PiprResult {\n return {\n formatVersion: 2,\n kind: \"review\",\n run: publicRunSummary(review.run),\n mainComment: stripPiprMainCommentMarkers(review.mainComment),\n inlineFindings: review.inlineCommentDrafts.map((draft) => draft.finding),\n droppedFindings: review.validated.droppedFindings,\n taskChecks: review.taskChecks,\n repairAttempted: review.repairAttempted,\n publication,\n };\n}\n\nfunction publicRunSummary(run: PiprRunSummary): PiprRunSummary {\n const bounded = (value: string) => value.slice(0, 200);\n return {\n ...run,\n id: bounded(run.id),\n baseSha: bounded(run.baseSha),\n headSha: bounded(run.headSha),\n tasks: run.tasks.slice(0, 200).map(bounded),\n models: run.models.slice(0, 20).map(bounded),\n };\n}\n\nfunction publicationErrorResult(\n publication: PublicationError[\"result\"],\n): Extract<PiprResult, { kind: \"publication-error\" }> {\n return {\n formatVersion: 2,\n kind: \"publication-error\",\n message: publicationFailureMessage,\n ...(publication\n ? {\n publication: {\n inlineComments: publication.inlineComments,\n inlinePublicationErrorCount: publication.metadata.inlinePublicationErrors.length,\n inlineResolutionErrorCount: publication.metadata.inlineResolutionErrors.length,\n },\n }\n : {}),\n };\n}\n\nexport function stripPiprMainCommentMarkers(mainComment: string): string {\n const lines = mainComment.split(\"\\n\");\n const envelope = parseGeneratedMainCommentEnvelope(lines);\n const generatedMarkerIndexes = new Set([\n envelope.mainMarkerIndex,\n envelope.headerMarkerIndex,\n envelope.statsMarkerIndex,\n envelope.statsRange?.start ?? -1,\n envelope.statsRange?.end ?? -1,\n lines[envelope.footerIndex] === mainCommentFooterHiddenMarker ? envelope.footerIndex : -1,\n ]);\n const visibleLines = lines.filter((_line, index) => !generatedMarkerIndexes.has(index));\n const firstContentLine = visibleLines.findIndex((line) => line !== \"\");\n return firstContentLine === -1 ? \"\" : visibleLines.slice(firstContentLine).join(\"\\n\");\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as runHostRunCommandWithDependencies } from "../commands-
|
|
2
|
-
import { a as HostRunCommandResult, b as RepositoryPermission, f as piBuiltinToolNames, g as SecretRedactor, h as piThinkingLevels, k as RepositoryRef, m as piRequiredCliFlags, p as piReadOnlyToolNames, w as ChangeRequestRef, y as CodeHostAdapter } from "../types-
|
|
1
|
+
import { r as runHostRunCommandWithDependencies } from "../commands-CF59DZXx.mjs";
|
|
2
|
+
import { a as HostRunCommandResult, b as RepositoryPermission, f as piBuiltinToolNames, g as SecretRedactor, h as piThinkingLevels, k as RepositoryRef, m as piRequiredCliFlags, p as piReadOnlyToolNames, w as ChangeRequestRef, y as CodeHostAdapter } from "../types-Dn1U3MDG.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/hosts/github/command.d.ts
|
|
5
5
|
type GitHubPullRequestDetails = {
|
|
@@ -38,23 +38,23 @@ declare const githubIssueCommentSchema: z.ZodPipe<z.ZodObject<{
|
|
|
38
38
|
} | undefined;
|
|
39
39
|
}>>;
|
|
40
40
|
declare const githubReviewCommentSchema: z.ZodPipe<z.ZodObject<{
|
|
41
|
+
id: z.ZodNumber;
|
|
42
|
+
body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
41
43
|
path: z.ZodOptional<z.ZodString>;
|
|
42
44
|
commit_id: z.ZodOptional<z.ZodString>;
|
|
43
45
|
line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
44
46
|
start_line: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
45
47
|
side: z.ZodOptional<z.ZodEnum<{
|
|
46
|
-
RIGHT: "RIGHT";
|
|
47
48
|
LEFT: "LEFT";
|
|
49
|
+
RIGHT: "RIGHT";
|
|
48
50
|
}>>;
|
|
49
51
|
start_side: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
50
|
-
RIGHT: "RIGHT";
|
|
51
52
|
LEFT: "LEFT";
|
|
53
|
+
RIGHT: "RIGHT";
|
|
52
54
|
}>>>;
|
|
53
55
|
user: z.ZodOptional<z.ZodObject<{
|
|
54
56
|
login: z.ZodString;
|
|
55
57
|
}, z.core.$loose>>;
|
|
56
|
-
id: z.ZodNumber;
|
|
57
|
-
body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
58
58
|
}, z.core.$loose>, z.ZodTransform<{
|
|
59
59
|
id: number;
|
|
60
60
|
body: string | null | undefined;
|
|
@@ -63,22 +63,22 @@ declare const githubReviewCommentSchema: z.ZodPipe<z.ZodObject<{
|
|
|
63
63
|
commitId: string | undefined;
|
|
64
64
|
line: number | undefined;
|
|
65
65
|
startLine: number | undefined;
|
|
66
|
-
side: "
|
|
67
|
-
startSide: "
|
|
66
|
+
side: "LEFT" | "RIGHT" | undefined;
|
|
67
|
+
startSide: "LEFT" | "RIGHT" | undefined;
|
|
68
68
|
}, {
|
|
69
69
|
[x: string]: unknown;
|
|
70
70
|
id: number;
|
|
71
|
+
body?: string | null | undefined;
|
|
71
72
|
path?: string | undefined;
|
|
72
73
|
commit_id?: string | undefined;
|
|
73
74
|
line?: number | null | undefined;
|
|
74
75
|
start_line?: number | null | undefined;
|
|
75
|
-
side?: "
|
|
76
|
-
start_side?: "
|
|
76
|
+
side?: "LEFT" | "RIGHT" | undefined;
|
|
77
|
+
start_side?: "LEFT" | "RIGHT" | null | undefined;
|
|
77
78
|
user?: {
|
|
78
79
|
[x: string]: unknown;
|
|
79
80
|
login: string;
|
|
80
81
|
} | undefined;
|
|
81
|
-
body?: string | null | undefined;
|
|
82
82
|
}>>;
|
|
83
83
|
declare const githubReviewThreadSchema: z.ZodObject<{
|
|
84
84
|
id: z.ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.mts","names":[],"sources":["../../src/hosts/github/command.ts","../../src/hosts/github/publication-client.ts","../../src/hosts/github/adapter.ts","../../src/shared/secret-redactor.ts"],"mappings":";;;;KAiDY;EACV,YAAY;EACZ,QAAQ;;KAGE;EACV,eAAe;IACb,YAAY;IACZ;MACE,QAAQ;EACZ,wBAAwB;IACtB,YAAY;IACZ;MACE,QAAQ;;;;cChDR,0BAAwB,EAAA,QAAA,EAAA;;;;;;;;;;;;;;;;;;;cAMxB,2BAAyB,EAAA,QAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA2BzB,0BAAwB,EAAA
|
|
1
|
+
{"version":3,"file":"testing.d.mts","names":[],"sources":["../../src/hosts/github/command.ts","../../src/hosts/github/publication-client.ts","../../src/hosts/github/adapter.ts","../../src/shared/secret-redactor.ts"],"mappings":";;;;KAiDY;EACV,YAAY;EACZ,QAAQ;;KAGE;EACV,eAAe;IACb,YAAY;IACZ;MACE,QAAQ;EACZ,wBAAwB;IACtB,YAAY;IACZ;MACE,QAAQ;;;;cChDR,0BAAwB,EAAA,QAAA,EAAA;;;;;;;;;;;;;;;;;;;cAMxB,2BAAyB,EAAA,QAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA2BzB,0BAAwB,EAAA;;;;GAI5B,EAAA,KAAA;cAoEI,sBAAoB,EAAA;;;GAGxB,EAAA,KAAA;KAEU,qBAAqB,EAAE,aAAa;KACpC,sBAAsB,EAAE,aAAa;KACrC,qBAAqB,EAAE,aAAa;KACpC,iBAAiB,EAAE,aAAa;KAEhC;EACV,6BAA6B;EAC7B,sBAAsB;IAAW;IAAc;MAA8B;EAC7E,kBAAkB;IAAW;IAAc;MAAwB,QAAQ;EAC3E,mBAAmB;IACjB;IACA;IACA;MACE;IAAU;;EACd,mBAAmB;IACjB;IACA;IACA;MACE;IAAU;;EACd,mBAAmB;IACjB;IACA;MACE,QAAQ;EACZ,kBAAkB;IAChB;IACA;MACE,QAAQ;EACZ,oBAAoB;IAClB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;MACE;IAAU;;EACd,yBAAyB;IACvB;IACA;IACA;IACA;MACE;IAAU;;EACd,oBAAoB;IAAW;MAAqB;EACpD,eAAe;IACb;IACA;IACA;IACA;MACE,QAAQ;EACZ,eAAe;IACb;IACA;IACA;IACA;IACA;MACE;;;;KChKM;EACV,MAAM,OAAO;EACb,gBAAgB;EAChB,oBAAoB;;iBAGN,wBAAwB,UAAS,2BAAgC;;;iBCxBjE,0BAA0B;EAAY,MAAM,OAAO;IAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as piReadOnlyToolNames, g as piBuiltinToolNames, l as createGitHubHostAdapter, m as createKnownSecretRedactor, r as runHostRunCommandWithDependencies, v as piRequiredCliFlags, y as piThinkingLevels } from "../commands-
|
|
1
|
+
import { _ as piReadOnlyToolNames, g as piBuiltinToolNames, l as createGitHubHostAdapter, m as createKnownSecretRedactor, r as runHostRunCommandWithDependencies, v as piRequiredCliFlags, y as piThinkingLevels } from "../commands-DgZU7tf7.mjs";
|
|
2
2
|
export { createGitHubHostAdapter, createKnownSecretRedactor, piBuiltinToolNames, piReadOnlyToolNames, piRequiredCliFlags, piThinkingLevels, runHostRunCommandWithDependencies };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//#region src/review/comment-branding.ts
|
|
2
|
+
const piprLogoUrl = "https://pipr.run/images/pipr/pipr-mark.svg";
|
|
3
|
+
const piprRepositoryUrl = "https://github.com/somus/pipr";
|
|
4
|
+
const mainCommentTitle = `# <img src="${piprLogoUrl}" width="22" height="22" alt=""> Pipr Review`;
|
|
5
|
+
const mainCommentTitles = /* @__PURE__ */ new Set([
|
|
6
|
+
"# pipr Review",
|
|
7
|
+
"# Pipr Review",
|
|
8
|
+
mainCommentTitle
|
|
9
|
+
]);
|
|
10
|
+
const mainCommentHeaderHiddenMarker = "<!-- pipr:header:hidden -->";
|
|
11
|
+
const mainCommentFooterHiddenMarker = "<!-- pipr:footer:hidden -->";
|
|
12
|
+
const reviewStatsStartMarker = "<!-- pipr:stats:start -->";
|
|
13
|
+
const reviewStatsEndMarker = "<!-- pipr:stats:end -->";
|
|
14
|
+
const reviewStatsHiddenMarker = "<!-- pipr:stats:hidden -->";
|
|
15
|
+
const escapedRepositoryUrl = piprRepositoryUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16
|
+
const mainCommentAttributionSource = `Review generated by \\[Pipr\\]\\(${escapedRepositoryUrl}\\) for commit \`[^\`]+\`\\.(?: Config SDK \\d+\\.\\d+\\.\\d+ is behind (?:Pipr \\d+\\.\\d+\\.\\d+|\\[Pipr \\d+\\.\\d+\\.\\d+\\]\\(${escapedRepositoryUrl}/releases/tag/v\\d+\\.\\d+\\.\\d+\\))\\.)?`;
|
|
17
|
+
const mainCommentAttributionTextPattern = new RegExp(`^${mainCommentAttributionSource}$`);
|
|
18
|
+
const mainCommentAttributionPattern = new RegExp(`^<sub>${mainCommentAttributionSource}</sub>$`);
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/review/main-comment-envelope.ts
|
|
21
|
+
const generatedReviewStatsShape = [
|
|
22
|
+
/^$/,
|
|
23
|
+
/^\| Metric \| Total \|$/,
|
|
24
|
+
/^\| --- \| ---: \|$/,
|
|
25
|
+
/^\| Models \| .+ \|$/,
|
|
26
|
+
/^\| Agent runs \| \d+ \|$/,
|
|
27
|
+
/^\| Elapsed \| .+ \|$/,
|
|
28
|
+
/^\| Input tokens \| (?:Unavailable|[\d,]+(?: \(reported\))?) \|$/,
|
|
29
|
+
/^\| Output tokens \| (?:Unavailable|[\d,]+(?: \(reported\))?) \|$/,
|
|
30
|
+
/^\| Cost \(USD\) \| (?:Unavailable|\$\d+(?:\.\d+)?(?:e[+-]?\d+)?(?: \(reported\))?) \|$/,
|
|
31
|
+
/^$/,
|
|
32
|
+
/^<\/details>$/,
|
|
33
|
+
/^<!-- pipr:stats:end -->$/
|
|
34
|
+
];
|
|
35
|
+
function parseGeneratedMainCommentEnvelope(lines) {
|
|
36
|
+
const mainMarkerIndex = lines.findIndex((line) => line.startsWith("<!-- pipr:main-comment "));
|
|
37
|
+
const headerCandidateOffset = lines.slice(mainMarkerIndex + 1).findIndex((line) => line !== "");
|
|
38
|
+
const headerCandidateIndex = mainMarkerIndex + 1 + headerCandidateOffset;
|
|
39
|
+
const headerMarkerIndex = mainMarkerIndex >= 0 && headerCandidateOffset >= 0 && lines[headerCandidateIndex] === "<!-- pipr:header:hidden -->" ? headerCandidateIndex : -1;
|
|
40
|
+
const lastLineIndex = lines.findLastIndex((line) => line !== "");
|
|
41
|
+
const lastLine = lines[lastLineIndex] ?? "";
|
|
42
|
+
const footerIndex = lastLine === "<!-- pipr:footer:hidden -->" || mainCommentAttributionPattern.test(lastLine) ? lastLineIndex : -1;
|
|
43
|
+
const lastContentIndex = lines.slice(0, footerIndex < 0 ? lines.length : footerIndex).findLastIndex((line) => line !== "");
|
|
44
|
+
return {
|
|
45
|
+
mainMarkerIndex,
|
|
46
|
+
headerMarkerIndex,
|
|
47
|
+
statsMarkerIndex: lines[lastContentIndex] === "<!-- pipr:stats:hidden -->" ? lastContentIndex : -1,
|
|
48
|
+
statsRange: generatedReviewStatsRange(lines, footerIndex),
|
|
49
|
+
footerIndex
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function generatedReviewStatsRange(lines, generatedFooterIndex) {
|
|
53
|
+
const end = lines.slice(0, generatedFooterIndex < 0 ? lines.length : generatedFooterIndex).findLastIndex((line) => line !== "");
|
|
54
|
+
if (end < 0 || lines[end] !== "<!-- pipr:stats:end -->" || lines[end - 1] !== "</details>") return;
|
|
55
|
+
const start = lines.lastIndexOf(reviewStatsStartMarker, end - 2);
|
|
56
|
+
if (start < 0 || lines[start + 1] !== "<details>" || lines[start + 2] !== "<summary>Review stats</summary>" || !matchesGeneratedReviewStatsShape(lines, start, end)) return;
|
|
57
|
+
return {
|
|
58
|
+
start,
|
|
59
|
+
end
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function matchesGeneratedReviewStatsShape(lines, start, end) {
|
|
63
|
+
const generatedShape = lines.slice(start + 3, end + 1);
|
|
64
|
+
return generatedShape.length === generatedReviewStatsShape.length && generatedReviewStatsShape.every((pattern, index) => pattern.test(generatedShape[index] ?? ""));
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { mainCommentTitle as a, reviewStatsEndMarker as c, mainCommentHeaderHiddenMarker as i, reviewStatsHiddenMarker as l, mainCommentAttributionTextPattern as n, mainCommentTitles as o, mainCommentFooterHiddenMarker as r, piprRepositoryUrl as s, parseGeneratedMainCommentEnvelope as t, reviewStatsStartMarker as u };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=main-comment-envelope-DFirHYhW.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-comment-envelope-DFirHYhW.mjs","names":[],"sources":["../src/review/comment-branding.ts","../src/review/main-comment-envelope.ts"],"sourcesContent":["const piprLogoUrl = \"https://pipr.run/images/pipr/pipr-mark.svg\";\nexport const piprRepositoryUrl = \"https://github.com/somus/pipr\";\n\nexport const mainCommentTitle = `# <img src=\"${piprLogoUrl}\" width=\"22\" height=\"22\" alt=\"\"> Pipr Review`;\n\nexport const mainCommentTitles = new Set([\"# pipr Review\", \"# Pipr Review\", mainCommentTitle]);\nexport const mainCommentHeaderHiddenMarker = \"<!-- pipr:header:hidden -->\";\nexport const mainCommentFooterHiddenMarker = \"<!-- pipr:footer:hidden -->\";\nexport const reviewStatsStartMarker = \"<!-- pipr:stats:start -->\";\nexport const reviewStatsEndMarker = \"<!-- pipr:stats:end -->\";\nexport const reviewStatsHiddenMarker = \"<!-- pipr:stats:hidden -->\";\n\nconst escapedRepositoryUrl = piprRepositoryUrl.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\nconst mainCommentAttributionSource = `Review generated by \\\\[Pipr\\\\]\\\\(${escapedRepositoryUrl}\\\\) for commit \\`[^\\`]+\\`\\\\.(?: Config SDK \\\\d+\\\\.\\\\d+\\\\.\\\\d+ is behind (?:Pipr \\\\d+\\\\.\\\\d+\\\\.\\\\d+|\\\\[Pipr \\\\d+\\\\.\\\\d+\\\\.\\\\d+\\\\]\\\\(${escapedRepositoryUrl}/releases/tag/v\\\\d+\\\\.\\\\d+\\\\.\\\\d+\\\\))\\\\.)?`;\n\nexport const mainCommentAttributionTextPattern = new RegExp(`^${mainCommentAttributionSource}$`);\n\nexport const mainCommentAttributionPattern = new RegExp(\n `^<sub>${mainCommentAttributionSource}</sub>$`,\n);\n","import {\n mainCommentAttributionPattern,\n mainCommentFooterHiddenMarker,\n mainCommentHeaderHiddenMarker,\n reviewStatsEndMarker,\n reviewStatsHiddenMarker,\n reviewStatsStartMarker,\n} from \"./comment-branding.js\";\n\nconst generatedReviewStatsShape = [\n /^$/,\n /^\\| Metric \\| Total \\|$/,\n /^\\| --- \\| ---: \\|$/,\n /^\\| Models \\| .+ \\|$/,\n /^\\| Agent runs \\| \\d+ \\|$/,\n /^\\| Elapsed \\| .+ \\|$/,\n /^\\| Input tokens \\| (?:Unavailable|[\\d,]+(?: \\(reported\\))?) \\|$/,\n /^\\| Output tokens \\| (?:Unavailable|[\\d,]+(?: \\(reported\\))?) \\|$/,\n /^\\| Cost \\(USD\\) \\| (?:Unavailable|\\$\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?(?: \\(reported\\))?) \\|$/,\n /^$/,\n /^<\\/details>$/,\n /^<!-- pipr:stats:end -->$/,\n];\n\nexport type GeneratedMainCommentEnvelope = {\n mainMarkerIndex: number;\n headerMarkerIndex: number;\n statsMarkerIndex: number;\n statsRange: { start: number; end: number } | undefined;\n footerIndex: number;\n};\n\nexport function parseGeneratedMainCommentEnvelope(lines: string[]): GeneratedMainCommentEnvelope {\n const mainMarkerIndex = lines.findIndex((line) => line.startsWith(\"<!-- pipr:main-comment \"));\n const headerCandidateOffset = lines.slice(mainMarkerIndex + 1).findIndex((line) => line !== \"\");\n const headerCandidateIndex = mainMarkerIndex + 1 + headerCandidateOffset;\n const headerMarkerIndex =\n mainMarkerIndex >= 0 &&\n headerCandidateOffset >= 0 &&\n lines[headerCandidateIndex] === mainCommentHeaderHiddenMarker\n ? headerCandidateIndex\n : -1;\n const lastLineIndex = lines.findLastIndex((line) => line !== \"\");\n const lastLine = lines[lastLineIndex] ?? \"\";\n const footerIndex =\n lastLine === mainCommentFooterHiddenMarker || mainCommentAttributionPattern.test(lastLine)\n ? lastLineIndex\n : -1;\n const lastContentIndex = lines\n .slice(0, footerIndex < 0 ? lines.length : footerIndex)\n .findLastIndex((line) => line !== \"\");\n const statsMarkerIndex =\n lines[lastContentIndex] === reviewStatsHiddenMarker ? lastContentIndex : -1;\n\n return {\n mainMarkerIndex,\n headerMarkerIndex,\n statsMarkerIndex,\n statsRange: generatedReviewStatsRange(lines, footerIndex),\n footerIndex,\n };\n}\n\nfunction generatedReviewStatsRange(\n lines: string[],\n generatedFooterIndex: number,\n): { start: number; end: number } | undefined {\n const end = lines\n .slice(0, generatedFooterIndex < 0 ? lines.length : generatedFooterIndex)\n .findLastIndex((line) => line !== \"\");\n if (end < 0 || lines[end] !== reviewStatsEndMarker || lines[end - 1] !== \"</details>\") {\n return undefined;\n }\n const start = lines.lastIndexOf(reviewStatsStartMarker, end - 2);\n if (\n start < 0 ||\n lines[start + 1] !== \"<details>\" ||\n lines[start + 2] !== \"<summary>Review stats</summary>\" ||\n !matchesGeneratedReviewStatsShape(lines, start, end)\n ) {\n return undefined;\n }\n return { start, end };\n}\n\nfunction matchesGeneratedReviewStatsShape(lines: string[], start: number, end: number): boolean {\n const generatedShape = lines.slice(start + 3, end + 1);\n return (\n generatedShape.length === generatedReviewStatsShape.length &&\n generatedReviewStatsShape.every((pattern, index) => pattern.test(generatedShape[index] ?? \"\"))\n );\n}\n"],"mappings":";AAAA,MAAM,cAAc;AACpB,MAAa,oBAAoB;AAEjC,MAAa,mBAAmB,eAAe,YAAY;AAE3D,MAAa,oCAAoB,IAAI,IAAI;CAAC;CAAiB;CAAiB;AAAgB,CAAC;AAC7F,MAAa,gCAAgC;AAC7C,MAAa,gCAAgC;AAC7C,MAAa,yBAAyB;AACtC,MAAa,uBAAuB;AACpC,MAAa,0BAA0B;AAEvC,MAAM,uBAAuB,kBAAkB,QAAQ,uBAAuB,MAAM;AACpF,MAAM,+BAA+B,oCAAoC,qBAAqB,qIAAqI,qBAAqB;AAExP,MAAa,oCAAoC,IAAI,OAAO,IAAI,6BAA6B,EAAE;AAE/F,MAAa,gCAAgC,IAAI,OAC/C,SAAS,6BAA6B,QACxC;;;ACVA,MAAM,4BAA4B;CAChC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAUA,SAAgB,kCAAkC,OAA+C;CAC/F,MAAM,kBAAkB,MAAM,WAAW,SAAS,KAAK,WAAW,yBAAyB,CAAC;CAC5F,MAAM,wBAAwB,MAAM,MAAM,kBAAkB,CAAC,CAAC,CAAC,WAAW,SAAS,SAAS,EAAE;CAC9F,MAAM,uBAAuB,kBAAkB,IAAI;CACnD,MAAM,oBACJ,mBAAmB,KACnB,yBAAyB,KACzB,MAAM,0BAAA,gCACF,uBACA;CACN,MAAM,gBAAgB,MAAM,eAAe,SAAS,SAAS,EAAE;CAC/D,MAAM,WAAW,MAAM,kBAAkB;CACzC,MAAM,cACJ,aAAA,iCAA8C,8BAA8B,KAAK,QAAQ,IACrF,gBACA;CACN,MAAM,mBAAmB,MACtB,MAAM,GAAG,cAAc,IAAI,MAAM,SAAS,WAAW,CAAC,CACtD,eAAe,SAAS,SAAS,EAAE;CAItC,OAAO;EACL;EACA;EACA,kBALA,MAAM,sBAAA,+BAAgD,mBAAmB;EAMzE,YAAY,0BAA0B,OAAO,WAAW;EACxD;CACF;AACF;AAEA,SAAS,0BACP,OACA,sBAC4C;CAC5C,MAAM,MAAM,MACT,MAAM,GAAG,uBAAuB,IAAI,MAAM,SAAS,oBAAoB,CAAC,CACxE,eAAe,SAAS,SAAS,EAAE;CACtC,IAAI,MAAM,KAAK,MAAM,SAAA,6BAAiC,MAAM,MAAM,OAAO,cACvE;CAEF,MAAM,QAAQ,MAAM,YAAY,wBAAwB,MAAM,CAAC;CAC/D,IACE,QAAQ,KACR,MAAM,QAAQ,OAAO,eACrB,MAAM,QAAQ,OAAO,qCACrB,CAAC,iCAAiC,OAAO,OAAO,GAAG,GAEnD;CAEF,OAAO;EAAE;EAAO;CAAI;AACtB;AAEA,SAAS,iCAAiC,OAAiB,OAAe,KAAsB;CAC9F,MAAM,iBAAiB,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;CACrD,OACE,eAAe,WAAW,0BAA0B,UACpD,0BAA0B,OAAO,SAAS,UAAU,QAAQ,KAAK,eAAe,UAAU,EAAE,CAAC;AAEjG"}
|
package/dist/{official-github-workflow-Bjlu-FL3.mjs → official-github-workflow-DNzV5Z70.mjs}
RENAMED
|
@@ -281,7 +281,7 @@ export default definePipr((pipr) => {
|
|
|
281
281
|
"| --- | ---: |",
|
|
282
282
|
\`| Inline findings | \${result.inlineFindings.length} |\`,
|
|
283
283
|
"",
|
|
284
|
-
context.
|
|
284
|
+
context.run.trigger === "local" ? localInlineFindingSummary : inlineFindingSummary,
|
|
285
285
|
].join("\\n"),
|
|
286
286
|
inlineFindings: result.inlineFindings,
|
|
287
287
|
};
|
|
@@ -1222,10 +1222,10 @@ export default definePipr((pipr) => {
|
|
|
1222
1222
|
const pluginToolReviewRecipe = {
|
|
1223
1223
|
id: "plugin-tool-review",
|
|
1224
1224
|
title: "Plugin Tool Review",
|
|
1225
|
-
description: "Typed R2-backed memory plugin
|
|
1225
|
+
description: "Typed R2-backed memory plugin with search-only review and explicit maintainer curation.",
|
|
1226
1226
|
sourceTools: ["Cloudflare R2", "Reviewer memory"],
|
|
1227
1227
|
configTs: `import { definePipr } from "@usepipr/sdk";
|
|
1228
|
-
import { r2MemoryPlugin } from "./r2-memory";
|
|
1228
|
+
import { memoryLimits, r2MemoryPlugin } from "./r2-memory";
|
|
1229
1229
|
|
|
1230
1230
|
export default definePipr((pipr) => {
|
|
1231
1231
|
const model = pipr.model({
|
|
@@ -1277,8 +1277,44 @@ export default definePipr((pipr) => {
|
|
|
1277
1277
|
},
|
|
1278
1278
|
});
|
|
1279
1279
|
|
|
1280
|
+
const rememberTask = pipr.task<{ lesson: string }>({
|
|
1281
|
+
name: "remember-review-memory",
|
|
1282
|
+
async run(ctx, input) {
|
|
1283
|
+
if (!ctx.command) {
|
|
1284
|
+
throw new Error("remember-review-memory is a command-only task");
|
|
1285
|
+
}
|
|
1286
|
+
const lesson = input.lesson.trim();
|
|
1287
|
+
if (lesson.length === 0) {
|
|
1288
|
+
await ctx.command.reply("Usage: @pipr remember <lesson...>");
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
if (lesson.length > memoryLimits.bodyCharacters) {
|
|
1292
|
+
await ctx.command.reply(
|
|
1293
|
+
"Reviewer memory must be " + memoryLimits.bodyCharacters + " characters or fewer.",
|
|
1294
|
+
);
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
const stored = await memory.curate(
|
|
1298
|
+
{
|
|
1299
|
+
subject: lesson.slice(0, memoryLimits.subjectCharacters),
|
|
1300
|
+
body: lesson,
|
|
1301
|
+
tags: ["maintainer-curated"],
|
|
1302
|
+
},
|
|
1303
|
+
ctx,
|
|
1304
|
+
);
|
|
1305
|
+
await ctx.command.reply("Stored reviewer memory \`" + stored.id + "\`.");
|
|
1306
|
+
},
|
|
1307
|
+
});
|
|
1308
|
+
|
|
1280
1309
|
pipr.on.changeRequest({ actions: ["opened", "updated"], task });
|
|
1281
1310
|
pipr.command({ pattern: "@pipr memory-review", permission: "write", task });
|
|
1311
|
+
pipr.command({
|
|
1312
|
+
pattern: "@pipr remember <lesson...>",
|
|
1313
|
+
permission: "write",
|
|
1314
|
+
description: "Store an explicit maintainer-curated reviewer lesson.",
|
|
1315
|
+
parse: (args) => ({ lesson: args.lesson ?? "" }),
|
|
1316
|
+
task: rememberTask,
|
|
1317
|
+
});
|
|
1282
1318
|
});
|
|
1283
1319
|
`,
|
|
1284
1320
|
files: [{
|
|
@@ -1286,22 +1322,55 @@ export default definePipr((pipr) => {
|
|
|
1286
1322
|
contents: `import { S3Client } from "bun";
|
|
1287
1323
|
import { definePlugin, type SecretRef, type TaskContext, z } from "@usepipr/sdk";
|
|
1288
1324
|
|
|
1325
|
+
export const memoryLimits = {
|
|
1326
|
+
subjectCharacters: 120,
|
|
1327
|
+
bodyCharacters: 4000,
|
|
1328
|
+
tagCount: 12,
|
|
1329
|
+
tagCharacters: 50,
|
|
1330
|
+
queryCharacters: 500,
|
|
1331
|
+
resultDefault: 5,
|
|
1332
|
+
resultMinimum: 1,
|
|
1333
|
+
resultMaximum: 20,
|
|
1334
|
+
searchObjectMaximum: 2000,
|
|
1335
|
+
} as const;
|
|
1336
|
+
|
|
1337
|
+
const memorySource = z.strictObject({
|
|
1338
|
+
kind: z.enum(["maintainer-command", "agent-tool"]),
|
|
1339
|
+
runId: z.string().min(1).max(200),
|
|
1340
|
+
platform: z.string().min(1).max(50),
|
|
1341
|
+
changeRequestNumber: z.number().int().nonnegative().optional(),
|
|
1342
|
+
headSha: z.string().min(1).max(200),
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1289
1345
|
const memoryItem = z.strictObject({
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1346
|
+
id: z.string().uuid().optional(),
|
|
1347
|
+
subject: z.string().trim().min(1).max(memoryLimits.subjectCharacters),
|
|
1348
|
+
body: z.string().trim().min(1).max(memoryLimits.bodyCharacters),
|
|
1349
|
+
tags: z
|
|
1350
|
+
.array(z.string().trim().min(1).max(memoryLimits.tagCharacters))
|
|
1351
|
+
.max(memoryLimits.tagCount)
|
|
1352
|
+
.optional(),
|
|
1353
|
+
source: memorySource.optional(),
|
|
1354
|
+
updatedAt: z.string().max(50).optional(),
|
|
1294
1355
|
});
|
|
1295
1356
|
|
|
1296
1357
|
const memorySearchInput = z.strictObject({
|
|
1297
|
-
query: z.string(),
|
|
1298
|
-
limit: z
|
|
1358
|
+
query: z.string().trim().min(1).max(memoryLimits.queryCharacters),
|
|
1359
|
+
limit: z
|
|
1360
|
+
.number()
|
|
1361
|
+
.int()
|
|
1362
|
+
.min(memoryLimits.resultMinimum)
|
|
1363
|
+
.max(memoryLimits.resultMaximum)
|
|
1364
|
+
.optional(),
|
|
1299
1365
|
});
|
|
1300
1366
|
|
|
1301
1367
|
const memoryStoreInput = z.strictObject({
|
|
1302
|
-
subject: z.string(),
|
|
1303
|
-
body: z.string(),
|
|
1304
|
-
tags: z
|
|
1368
|
+
subject: z.string().trim().min(1).max(memoryLimits.subjectCharacters),
|
|
1369
|
+
body: z.string().trim().min(1).max(memoryLimits.bodyCharacters),
|
|
1370
|
+
tags: z
|
|
1371
|
+
.array(z.string().trim().min(1).max(memoryLimits.tagCharacters))
|
|
1372
|
+
.max(memoryLimits.tagCount)
|
|
1373
|
+
.optional(),
|
|
1305
1374
|
});
|
|
1306
1375
|
|
|
1307
1376
|
type MemoryItem = ReturnType<typeof memoryItem.parse>;
|
|
@@ -1328,6 +1397,7 @@ export function r2MemoryPlugin(options: R2MemoryOptions) {
|
|
|
1328
1397
|
id: "memory/search-output",
|
|
1329
1398
|
schema: z.strictObject({
|
|
1330
1399
|
memories: z.array(memoryItem),
|
|
1400
|
+
skippedObjects: z.number().int().nonnegative(),
|
|
1331
1401
|
}),
|
|
1332
1402
|
});
|
|
1333
1403
|
const storeInput = pipr.schema({
|
|
@@ -1339,6 +1409,7 @@ export function r2MemoryPlugin(options: R2MemoryOptions) {
|
|
|
1339
1409
|
schema: z.strictObject({
|
|
1340
1410
|
stored: z.boolean(),
|
|
1341
1411
|
key: z.string(),
|
|
1412
|
+
id: z.string().uuid(),
|
|
1342
1413
|
}),
|
|
1343
1414
|
});
|
|
1344
1415
|
|
|
@@ -1361,12 +1432,15 @@ export function r2MemoryPlugin(options: R2MemoryOptions) {
|
|
|
1361
1432
|
input: storeInput,
|
|
1362
1433
|
output: storeOutput,
|
|
1363
1434
|
async run({ input, ctx, signal }) {
|
|
1364
|
-
return await storeMemory(input, ctx, options, signal);
|
|
1435
|
+
return await storeMemory(input, ctx, options, "agent-tool", signal);
|
|
1365
1436
|
},
|
|
1366
1437
|
toModelOutput(output) {
|
|
1367
1438
|
return output;
|
|
1368
1439
|
},
|
|
1369
1440
|
}),
|
|
1441
|
+
curate(input: MemoryStoreInput, ctx: TaskContext, signal?: AbortSignal) {
|
|
1442
|
+
return storeMemory(input, ctx, options, "maintainer-command", signal);
|
|
1443
|
+
},
|
|
1370
1444
|
};
|
|
1371
1445
|
});
|
|
1372
1446
|
}
|
|
@@ -1376,29 +1450,52 @@ async function searchMemory(
|
|
|
1376
1450
|
ctx: TaskContext,
|
|
1377
1451
|
options: R2MemoryOptions,
|
|
1378
1452
|
signal?: AbortSignal,
|
|
1379
|
-
): Promise<{ memories: MemoryItem[] }> {
|
|
1453
|
+
): Promise<{ memories: MemoryItem[]; skippedObjects: number }> {
|
|
1380
1454
|
signal?.throwIfAborted();
|
|
1381
1455
|
const bucket = r2Bucket(ctx, options);
|
|
1382
|
-
const listed = await bucket.list({ prefix: memoryPrefix(ctx, options) + "/", maxKeys: 200 });
|
|
1383
1456
|
const memories: MemoryItem[] = [];
|
|
1457
|
+
let continuationToken: string | undefined;
|
|
1458
|
+
let scannedObjects = 0;
|
|
1459
|
+
let skippedObjects = 0;
|
|
1384
1460
|
|
|
1385
|
-
|
|
1461
|
+
do {
|
|
1386
1462
|
signal?.throwIfAborted();
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1463
|
+
const listed = await bucket.list({
|
|
1464
|
+
prefix: memoryPrefix(ctx, options) + "/",
|
|
1465
|
+
maxKeys: 200,
|
|
1466
|
+
continuationToken,
|
|
1467
|
+
});
|
|
1468
|
+
|
|
1469
|
+
const objects = (listed.contents ?? []).slice(
|
|
1470
|
+
0,
|
|
1471
|
+
memoryLimits.searchObjectMaximum - scannedObjects,
|
|
1472
|
+
);
|
|
1473
|
+
scannedObjects += objects.length;
|
|
1474
|
+
for (const object of objects) {
|
|
1475
|
+
signal?.throwIfAborted();
|
|
1476
|
+
try {
|
|
1477
|
+
const value = memoryItem.parse(await bucket.file(object.key).json());
|
|
1478
|
+
if (matchesMemory(value, input.query)) {
|
|
1479
|
+
memories.push(value);
|
|
1480
|
+
}
|
|
1481
|
+
} catch {
|
|
1482
|
+
// Exclude malformed or concurrently deleted objects and report the count.
|
|
1483
|
+
skippedObjects += 1;
|
|
1391
1484
|
}
|
|
1392
|
-
} catch {
|
|
1393
|
-
// Ignore malformed or concurrently deleted memory objects.
|
|
1394
1485
|
}
|
|
1395
|
-
}
|
|
1396
1486
|
|
|
1397
|
-
|
|
1487
|
+
continuationToken = listed.isTruncated ? listed.nextContinuationToken : undefined;
|
|
1488
|
+
} while (continuationToken && scannedObjects < memoryLimits.searchObjectMaximum);
|
|
1489
|
+
|
|
1490
|
+
const limit = Math.min(
|
|
1491
|
+
Math.max(Math.trunc(input.limit ?? memoryLimits.resultDefault), memoryLimits.resultMinimum),
|
|
1492
|
+
memoryLimits.resultMaximum,
|
|
1493
|
+
);
|
|
1398
1494
|
return {
|
|
1399
1495
|
memories: memories
|
|
1400
1496
|
.sort((left, right) => (right.updatedAt ?? "").localeCompare(left.updatedAt ?? ""))
|
|
1401
1497
|
.slice(0, limit),
|
|
1498
|
+
skippedObjects,
|
|
1402
1499
|
};
|
|
1403
1500
|
}
|
|
1404
1501
|
|
|
@@ -1406,14 +1503,53 @@ async function storeMemory(
|
|
|
1406
1503
|
input: MemoryStoreInput,
|
|
1407
1504
|
ctx: TaskContext,
|
|
1408
1505
|
options: R2MemoryOptions,
|
|
1506
|
+
sourceKind: "maintainer-command" | "agent-tool",
|
|
1409
1507
|
signal?: AbortSignal,
|
|
1410
|
-
): Promise<{ stored: boolean; key: string }> {
|
|
1508
|
+
): Promise<{ stored: boolean; key: string; id: string }> {
|
|
1411
1509
|
signal?.throwIfAborted();
|
|
1412
1510
|
const bucket = r2Bucket(ctx, options);
|
|
1413
|
-
const
|
|
1414
|
-
const
|
|
1511
|
+
const parsedInput = memoryStoreInput.parse(input);
|
|
1512
|
+
const curatedKey =
|
|
1513
|
+
sourceKind === "maintainer-command"
|
|
1514
|
+
? memoryPrefix(ctx, options) +
|
|
1515
|
+
"/maintainer-command/" +
|
|
1516
|
+
encodeURIComponent(ctx.run.id) +
|
|
1517
|
+
".json"
|
|
1518
|
+
: undefined;
|
|
1519
|
+
|
|
1520
|
+
const id = curatedKey ? await stableCommandMemoryId(ctx.run.id) : crypto.randomUUID();
|
|
1521
|
+
const entry = memoryItem.parse({
|
|
1522
|
+
...parsedInput,
|
|
1523
|
+
id,
|
|
1524
|
+
source: {
|
|
1525
|
+
kind: sourceKind,
|
|
1526
|
+
runId: ctx.run.id,
|
|
1527
|
+
platform: ctx.platform.id,
|
|
1528
|
+
changeRequestNumber: ctx.change.number,
|
|
1529
|
+
headSha: ctx.change.head.sha,
|
|
1530
|
+
},
|
|
1531
|
+
updatedAt: new Date().toISOString(),
|
|
1532
|
+
});
|
|
1533
|
+
const key = curatedKey ?? memoryKey(id, parsedInput.subject, ctx, options);
|
|
1415
1534
|
await bucket.write(key, JSON.stringify(entry, null, 2), { type: "application/json" });
|
|
1416
|
-
return { stored: true, key };
|
|
1535
|
+
return { stored: true, key, id };
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
async function stableCommandMemoryId(runId: string): Promise<string> {
|
|
1539
|
+
const digest = new Uint8Array(
|
|
1540
|
+
await crypto.subtle.digest(
|
|
1541
|
+
"SHA-256",
|
|
1542
|
+
new TextEncoder().encode("pipr-memory/maintainer-command/" + runId),
|
|
1543
|
+
),
|
|
1544
|
+
);
|
|
1545
|
+
digest[6] = (digest[6]! & 0x0f) | 0x50;
|
|
1546
|
+
digest[8] = (digest[8]! & 0x3f) | 0x80;
|
|
1547
|
+
const hex = Array.from(digest.slice(0, 16), (byte) => byte.toString(16).padStart(2, "0")).join(
|
|
1548
|
+
"",
|
|
1549
|
+
);
|
|
1550
|
+
return [hex.slice(0, 8), hex.slice(8, 12), hex.slice(12, 16), hex.slice(16, 20), hex.slice(20)].join(
|
|
1551
|
+
"-",
|
|
1552
|
+
);
|
|
1417
1553
|
}
|
|
1418
1554
|
|
|
1419
1555
|
function r2Bucket(ctx: TaskContext, options: R2MemoryOptions): S3Client {
|
|
@@ -1444,14 +1580,26 @@ function cleanPathSegment(value: string): string {
|
|
|
1444
1580
|
);
|
|
1445
1581
|
}
|
|
1446
1582
|
|
|
1447
|
-
function memoryKey(
|
|
1583
|
+
function memoryKey(
|
|
1584
|
+
id: string,
|
|
1585
|
+
subject: string,
|
|
1586
|
+
ctx: TaskContext,
|
|
1587
|
+
options: R2MemoryOptions,
|
|
1588
|
+
): string {
|
|
1448
1589
|
const slug = subject
|
|
1449
1590
|
.toLowerCase()
|
|
1450
1591
|
.replace(/[^a-z0-9]+/g, "-")
|
|
1451
1592
|
.replace(/^-|-$/g, "")
|
|
1452
1593
|
.slice(0, 60);
|
|
1453
1594
|
return (
|
|
1454
|
-
memoryPrefix(ctx, options) +
|
|
1595
|
+
memoryPrefix(ctx, options) +
|
|
1596
|
+
"/" +
|
|
1597
|
+
new Date().toISOString() +
|
|
1598
|
+
"-" +
|
|
1599
|
+
id +
|
|
1600
|
+
"-" +
|
|
1601
|
+
(slug || "memory") +
|
|
1602
|
+
".json"
|
|
1455
1603
|
);
|
|
1456
1604
|
}
|
|
1457
1605
|
|
|
@@ -1488,7 +1636,9 @@ function matchesMemory(item: MemoryItem, query: string): boolean {
|
|
|
1488
1636
|
|
|
1489
1637
|
This recipe uses Bun's S3-compatible client against Cloudflare R2. R2 credentials are declared with \`pipr.secret(...)\`, then resolved inside tool execution with \`ctx.secret(...)\`. The generated GitHub workflow maps \`PIPR_R2_MEMORY_BUCKET\`, \`PIPR_R2_MEMORY_ENDPOINT\`, \`PIPR_R2_MEMORY_ACCESS_KEY_ID\`, and \`PIPR_R2_MEMORY_SECRET_ACCESS_KEY\` repository secrets into matching runtime environment variables.
|
|
1490
1638
|
|
|
1491
|
-
R2 is object storage, not a search index. The sample
|
|
1639
|
+
R2 is object storage, not a search index. The sample paginates up to 2,000 JSON memory objects under \`prefix/repository-owner/repository-name\` and filters them locally, which keeps each search bounded and is enough for small reviewer-memory sets. Change \`prefix\` in \`.pipr/config.ts\` when multiple repositories share one bucket; Pipr still adds the repository scope below it. The generated defaults cap subjects at 120 characters, bodies at 4,000 characters, tags at 12 entries of 50 characters, queries at 500 characters, and results at 20. Existing entries without ids or provenance remain readable when they satisfy those bounds. Search results include \`skippedObjects\`, the number of malformed, unavailable, or over-limit objects excluded during that search, so upgrades do not hide incompatible entries without a diagnostic.
|
|
1640
|
+
|
|
1641
|
+
The generated reviewer treats memory as untrusted historical context and requires current repository evidence for findings. It only searches memory by default. A repository user with write permission can store one bounded, provenance-bearing lesson with \`@pipr remember <lesson...>\`; re-delivery of the same command run deterministically reuses its stored object and UUID. Full review summaries and human feedback are not persisted automatically; feedback collection, eval generation, scheduling, and proposal pull requests remain user-owned extensions.
|
|
1492
1642
|
|
|
1493
1643
|
`
|
|
1494
1644
|
};
|
|
@@ -2703,7 +2853,7 @@ function isOfficialInitRecipeId(recipe) {
|
|
|
2703
2853
|
}
|
|
2704
2854
|
//#endregion
|
|
2705
2855
|
//#region src/config/official-github-workflow.ts
|
|
2706
|
-
const defaultWorkflowActionRef = "somus/pipr@v0.
|
|
2856
|
+
const defaultWorkflowActionRef = "somus/pipr@v0.5.0";
|
|
2707
2857
|
/** Internal shared renderer for `pipr init` and generated recipe docs. */
|
|
2708
2858
|
function renderOfficialGithubWorkflow(options = {}) {
|
|
2709
2859
|
const relativeConfigDir = options.relativeConfigDir ?? ".pipr";
|
|
@@ -2748,4 +2898,4 @@ function githubExpression(expression) {
|
|
|
2748
2898
|
//#endregion
|
|
2749
2899
|
export { officialInitRecipeWorkflowEnvSecrets as a, officialInitRecipeFiles as i, listOfficialInitRecipes as n, supportedOfficialInitRecipes as o, officialInitRecipeConfigTs as r, renderOfficialGithubWorkflow as t };
|
|
2750
2900
|
|
|
2751
|
-
//# sourceMappingURL=official-github-workflow-
|
|
2901
|
+
//# sourceMappingURL=official-github-workflow-DNzV5Z70.mjs.map
|