@usepipr/runtime 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,74 @@
1
+ import { z } from "zod";
2
+ //#region src/pi/contract.ts
3
+ const piThinkingLevels = [
4
+ "off",
5
+ "minimal",
6
+ "low",
7
+ "medium",
8
+ "high",
9
+ "xhigh"
10
+ ];
11
+ const piBuiltinToolNames = [
12
+ "read",
13
+ "bash",
14
+ "edit",
15
+ "write",
16
+ "grep",
17
+ "find",
18
+ "ls"
19
+ ];
20
+ const piReadOnlyToolNames = [
21
+ "read",
22
+ "grep",
23
+ "find",
24
+ "ls"
25
+ ];
26
+ const piRequiredCliFlags = [
27
+ "--provider",
28
+ "--model",
29
+ "--system-prompt",
30
+ "--mode",
31
+ "--print",
32
+ "--no-session",
33
+ "--session-dir",
34
+ "--tools",
35
+ "--extension",
36
+ "--no-context-files",
37
+ "--no-approve",
38
+ "--no-extensions",
39
+ "--no-skills",
40
+ "--no-prompt-templates",
41
+ "--no-themes",
42
+ "--thinking"
43
+ ];
44
+ const nonEmptyStringSchema = z.string().min(1);
45
+ const piProviderIdSchema = z.string().regex(/^[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)*$/);
46
+ const piApiKeyEnvNameSchema = z.string().regex(/^[A-Z_][A-Z0-9_]*$/);
47
+ const piThinkingLevelSchema = z.enum(piThinkingLevels);
48
+ const piReadOnlyToolNamesSchema = z.tuple([
49
+ z.literal("read"),
50
+ z.literal("grep"),
51
+ z.literal("find"),
52
+ z.literal("ls")
53
+ ]);
54
+ const piProviderProfileSchema = z.strictObject({
55
+ id: piProviderIdSchema,
56
+ provider: nonEmptyStringSchema,
57
+ model: nonEmptyStringSchema,
58
+ apiKeyEnv: piApiKeyEnvNameSchema,
59
+ thinking: piThinkingLevelSchema.optional()
60
+ });
61
+ const piProviderInvocationSchema = z.strictObject({
62
+ provider: nonEmptyStringSchema,
63
+ model: nonEmptyStringSchema,
64
+ apiKeyEnv: piApiKeyEnvNameSchema,
65
+ thinking: piThinkingLevelSchema,
66
+ tools: piReadOnlyToolNamesSchema
67
+ });
68
+ function parsePiProviderInvocation(value) {
69
+ return piProviderInvocationSchema.parse(value);
70
+ }
71
+ //#endregion
72
+ export { piRequiredCliFlags as a, piReadOnlyToolNames as i, piBuiltinToolNames as n, piThinkingLevels as o, piProviderProfileSchema as r, parsePiProviderInvocation as t };
73
+
74
+ //# sourceMappingURL=contract-BsL98-bI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-BsL98-bI.mjs","names":[],"sources":["../src/pi/contract.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const piThinkingLevels = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"] as const;\nexport const piBuiltinToolNames = [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\"] as const;\nexport const piReadOnlyToolNames = [\"read\", \"grep\", \"find\", \"ls\"] as const;\nexport type PiReadOnlyToolName = (typeof piReadOnlyToolNames)[number];\nexport const piRequiredCliFlags = [\n \"--provider\",\n \"--model\",\n \"--system-prompt\",\n \"--mode\",\n \"--print\",\n \"--no-session\",\n \"--session-dir\",\n \"--tools\",\n \"--extension\",\n \"--no-context-files\",\n \"--no-approve\",\n \"--no-extensions\",\n \"--no-skills\",\n \"--no-prompt-templates\",\n \"--no-themes\",\n \"--thinking\",\n] as const;\n\nconst nonEmptyStringSchema = z.string().min(1);\nconst piProviderIdSchema = z.string().regex(/^[A-Za-z0-9_.-]+(?:\\/[A-Za-z0-9_.-]+)*$/);\nconst piApiKeyEnvNameSchema = z.string().regex(/^[A-Z_][A-Z0-9_]*$/);\n\nconst piThinkingLevelSchema = z.enum(piThinkingLevels);\nconst piReadOnlyToolNamesSchema = z.tuple([\n z.literal(\"read\"),\n z.literal(\"grep\"),\n z.literal(\"find\"),\n z.literal(\"ls\"),\n]);\n\nexport const piProviderProfileSchema = z.strictObject({\n id: piProviderIdSchema,\n provider: nonEmptyStringSchema,\n model: nonEmptyStringSchema,\n apiKeyEnv: piApiKeyEnvNameSchema,\n thinking: piThinkingLevelSchema.optional(),\n});\n\nconst piProviderInvocationSchema = z.strictObject({\n provider: nonEmptyStringSchema,\n model: nonEmptyStringSchema,\n apiKeyEnv: piApiKeyEnvNameSchema,\n thinking: piThinkingLevelSchema,\n tools: piReadOnlyToolNamesSchema,\n});\n\nexport type PiProviderProfile = z.infer<typeof piProviderProfileSchema>;\nexport type PiProviderInvocation = z.infer<typeof piProviderInvocationSchema>;\n\nexport function parsePiProviderProfile(value: unknown): PiProviderProfile {\n return piProviderProfileSchema.parse(value);\n}\n\nexport function parsePiProviderInvocation(value: unknown): PiProviderInvocation {\n return piProviderInvocationSchema.parse(value);\n}\n"],"mappings":";;AAEA,MAAa,mBAAmB;CAAC;CAAO;CAAW;CAAO;CAAU;CAAQ;AAAO;AACnF,MAAa,qBAAqB;CAAC;CAAQ;CAAQ;CAAQ;CAAS;CAAQ;CAAQ;AAAI;AACxF,MAAa,sBAAsB;CAAC;CAAQ;CAAQ;CAAQ;AAAI;AAEhE,MAAa,qBAAqB;CAChC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,uBAAuB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;AAC7C,MAAM,qBAAqB,EAAE,OAAO,CAAC,CAAC,MAAM,yCAAyC;AACrF,MAAM,wBAAwB,EAAE,OAAO,CAAC,CAAC,MAAM,oBAAoB;AAEnE,MAAM,wBAAwB,EAAE,KAAK,gBAAgB;AACrD,MAAM,4BAA4B,EAAE,MAAM;CACxC,EAAE,QAAQ,MAAM;CAChB,EAAE,QAAQ,MAAM;CAChB,EAAE,QAAQ,MAAM;CAChB,EAAE,QAAQ,IAAI;AAChB,CAAC;AAED,MAAa,0BAA0B,EAAE,aAAa;CACpD,IAAI;CACJ,UAAU;CACV,OAAO;CACP,WAAW;CACX,UAAU,sBAAsB,SAAS;AAC3C,CAAC;AAED,MAAM,6BAA6B,EAAE,aAAa;CAChD,UAAU;CACV,OAAO;CACP,WAAW;CACX,UAAU;CACV,OAAO;AACT,CAAC;AASD,SAAgB,0BAA0B,OAAsC;CAC9E,OAAO,2BAA2B,MAAM,KAAK;AAC/C"}
@@ -0,0 +1,10 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/pi/contract.d.ts
4
+ declare const piThinkingLevels: readonly ["off", "minimal", "low", "medium", "high", "xhigh"];
5
+ declare const piBuiltinToolNames: readonly ["read", "bash", "edit", "write", "grep", "find", "ls"];
6
+ declare const piReadOnlyToolNames: readonly ["read", "grep", "find", "ls"];
7
+ declare const piRequiredCliFlags: readonly ["--provider", "--model", "--system-prompt", "--mode", "--print", "--no-session", "--session-dir", "--tools", "--extension", "--no-context-files", "--no-approve", "--no-extensions", "--no-skills", "--no-prompt-templates", "--no-themes", "--thinking"];
8
+ //#endregion
9
+ export { piThinkingLevels as i, piReadOnlyToolNames as n, piRequiredCliFlags as r, piBuiltinToolNames as t };
10
+ //# sourceMappingURL=contract-D-zqnrkd.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-D-zqnrkd.d.mts","names":[],"sources":["../src/pi/contract.ts"],"mappings":";;;cAEa,gBAAA;AAAA,cACA,kBAAA;AAAA,cACA,mBAAA;AAAA,cAEA,kBAAA"}
@@ -0,0 +1,2 @@
1
+ import { l as ActionCommandResult, n as runActionCommandWithDependencies, v as GitHubPublicationClient, y as PublicationError } from "../commands-C7OX2Jnd.mjs";
2
+ export { type ActionCommandResult, type GitHubPublicationClient, PublicationError, runActionCommandWithDependencies };
@@ -0,0 +1,2 @@
1
+ import { c as PublicationError, n as runActionCommandWithDependencies } from "../commands-CUdKCUFa.mjs";
2
+ export { PublicationError, runActionCommandWithDependencies };
@@ -0,0 +1,2 @@
1
+ import { i as piThinkingLevels, n as piReadOnlyToolNames, r as piRequiredCliFlags, t as piBuiltinToolNames } from "../contract-D-zqnrkd.mjs";
2
+ export { piBuiltinToolNames, piReadOnlyToolNames, piRequiredCliFlags, piThinkingLevels };
@@ -0,0 +1,2 @@
1
+ import { a as piRequiredCliFlags, i as piReadOnlyToolNames, n as piBuiltinToolNames, o as piThinkingLevels } from "../contract-BsL98-bI.mjs";
2
+ export { piBuiltinToolNames, piReadOnlyToolNames, piRequiredCliFlags, piThinkingLevels };
@@ -0,0 +1,29 @@
1
+ import { A as OfficialInitAdapter, C as DiffManifest, D as RepositoryRef, E as ProviderConfig, O as RuntimeSettings, S as ChangeRequestRef, T as PlatformInfo, _ as ActionLogSink, a as runInspectCommand, b as PublicationResult, c as ActionCommandOptions, d as DryRunCommandResult, f as InitCommandOptions, g as RuntimeCommandOptions, h as LocalReviewCommandResult, i as runInitCommand, j as supportedOfficialInitAdapters, k as InitTypeSupportMode, l as ActionCommandResult, m as LocalReviewCommandOptions, o as runLocalReviewCommand, p as InspectCommandResult, r as runDryRunCommand, s as runValidateCommand, t as runActionCommand, u as DryRunCommandOptions, w as PiprConfig, x as ChangeRequestEventContext, y as PublicationError } from "./commands-C7OX2Jnd.mjs";
2
+
3
+ //#region src/config/recipes/types.d.ts
4
+ type OfficialInitRecipeFile = {
5
+ relativePath: string;
6
+ contents: string;
7
+ };
8
+ type OfficialInitRecipeWorkflowEnvSecret = {
9
+ env: string;
10
+ secret: string;
11
+ };
12
+ type OfficialInitRecipe = {
13
+ id: string;
14
+ title: string;
15
+ description: string;
16
+ sourceTools: readonly string[];
17
+ configTs: string;
18
+ files?: readonly OfficialInitRecipeFile[];
19
+ workflowEnvSecrets?: readonly OfficialInitRecipeWorkflowEnvSecret[];
20
+ docsDetailsMdx?: string;
21
+ };
22
+ //#endregion
23
+ //#region src/config/recipes.d.ts
24
+ declare const supportedOfficialInitRecipes: readonly ["default-review", "bug-hunter", "security-sast", "quality-gate", "diff-diagnostics", "pr-hygiene", "dependency-risk", "ci-triage-command", "multi-agent-review", "plugin-tool-review", "pr-briefing", "interactive-ask", "changelog-draft"];
25
+ type OfficialInitRecipeId = (typeof supportedOfficialInitRecipes)[number];
26
+ declare function listOfficialInitRecipes(): OfficialInitRecipe[];
27
+ //#endregion
28
+ export { type ActionCommandOptions, type ActionCommandResult, type ActionLogSink, type ChangeRequestEventContext, type ChangeRequestRef, type DiffManifest, type DryRunCommandOptions, type DryRunCommandResult, type InitCommandOptions, type InitTypeSupportMode, type InspectCommandResult, type LocalReviewCommandOptions, type LocalReviewCommandResult, type OfficialInitAdapter, type OfficialInitRecipe, type OfficialInitRecipeFile, type OfficialInitRecipeId, type PiprConfig, type PlatformInfo, type ProviderConfig, PublicationError, type PublicationResult, type RepositoryRef, type RuntimeCommandOptions, type RuntimeSettings, listOfficialInitRecipes, runActionCommand, runDryRunCommand, runInitCommand, runInspectCommand, runLocalReviewCommand, runValidateCommand, supportedOfficialInitAdapters, supportedOfficialInitRecipes };
29
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/config/recipes/types.ts","../src/config/recipes.ts"],"mappings":";;;KAAY,sBAAA;EACV,YAAA;EACA,QAAQ;AAAA;AAAA,KAGE,mCAAA;EACV,GAAA;EACA,MAAM;AAAA;AAAA,KAGI,kBAAA;EACV,EAAA;EACA,KAAA;EACA,WAAA;EACA,WAAA;EACA,QAAA;EACA,KAAA,YAAiB,sBAAA;EACjB,kBAAA,YAA8B,mCAAmC;EACjE,cAAA;AAAA;;;cCCW,4BAAA;AAAA,KAgBD,oBAAA,WAA+B,4BAA4B;AAAA,iBAmBvD,uBAAA,IAA2B,kBAAkB"}
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { a as runInspectCommand, c as PublicationError, d as supportedOfficialInitRecipes, i as runInitCommand, l as supportedOfficialInitAdapters, o as runLocalReviewCommand, r as runDryRunCommand, s as runValidateCommand, t as runActionCommand, u as listOfficialInitRecipes } from "./commands-CUdKCUFa.mjs";
2
+ export { PublicationError, listOfficialInitRecipes, runActionCommand, runDryRunCommand, runInitCommand, runInspectCommand, runLocalReviewCommand, runValidateCommand, supportedOfficialInitAdapters, supportedOfficialInitRecipes };
@@ -0,0 +1,25 @@
1
+ //#region src/pi/runtime-tools-extension.d.ts
2
+ type PiExtensionHost = {
3
+ registerTool(tool: PiTool): void;
4
+ };
5
+ type PiTool = {
6
+ name: string;
7
+ label: string;
8
+ description: string;
9
+ parameters: Record<string, unknown>;
10
+ execute: (toolCallId: string, params: unknown, signal?: unknown, onUpdate?: unknown, ctx?: {
11
+ cwd?: unknown;
12
+ }) => Promise<ToolResult>;
13
+ };
14
+ type ToolResult = {
15
+ content: Array<{
16
+ type: "text";
17
+ text: string;
18
+ }>;
19
+ details: unknown;
20
+ };
21
+ /** Registers pipr runtime read tools and config-defined custom tools with Pi. */
22
+ declare function piprRuntimeTools(pi: PiExtensionHost): void;
23
+ //#endregion
24
+ export { piprRuntimeTools as default };
25
+ //# sourceMappingURL=runtime-tools-extension.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-tools-extension.d.mts","names":[],"sources":["../../src/pi/runtime-tools-extension.ts"],"mappings":";KAkBK,eAAA;EACH,YAAA,CAAa,IAAA,EAAM,MAAM;AAAA;AAAA,KAGtB,MAAA;EACH,IAAA;EACA,KAAA;EACA,WAAA;EACA,UAAA,EAAY,MAAA;EACZ,OAAA,GACE,UAAA,UACA,MAAA,WACA,MAAA,YACA,QAAA,YACA,GAAA;IAAQ,GAAA;EAAA,MACL,OAAA,CAAQ,UAAA;AAAA;AAAA,KAGV,UAAA;EACH,OAAA,EAAS,KAAK;IAAG,IAAA;IAAc,IAAA;EAAA;EAC/B,OAAA;AAAA;;iBA2BsB,gBAAA,CAAiB,EAAmB,EAAf,eAAe"}
@@ -0,0 +1,201 @@
1
+ import { a as readDiffFromRuntimeData, c as resolveReadAtRefRequest, i as readAtRefParams, l as unavailableReadAtRefResult, n as boundedLineSlice, o as readDiffParams, s as resolveAllowedPath, t as assertNoSymlinkPath } from "../runtime-tools-core-CW1xenzy.mjs";
2
+ import path from "node:path";
3
+ import { z } from "zod";
4
+ import { compact } from "lodash-es";
5
+ import { readFileSync } from "node:fs";
6
+ //#region src/pi/runtime-tools-extension.ts
7
+ const customToolDataSchema = z.strictObject({ tools: z.array(z.strictObject({
8
+ name: z.string().min(1),
9
+ description: z.string().optional()
10
+ })) });
11
+ const customToolBridgePayloadSchema = z.record(z.string(), z.unknown());
12
+ const readableBaseSnapshotSchema = z.looseObject({
13
+ path: z.string(),
14
+ ref: z.enum(["base", "head"]),
15
+ sourcePath: z.string(),
16
+ rangeId: z.string(),
17
+ startLine: z.number(),
18
+ endLine: z.number(),
19
+ available: z.literal(true),
20
+ relativePath: z.string(),
21
+ bytes: z.number().optional(),
22
+ truncated: z.boolean().optional()
23
+ });
24
+ /** Registers pipr runtime read tools and config-defined custom tools with Pi. */
25
+ function piprRuntimeTools(pi) {
26
+ const registrations = toolRegistrations();
27
+ if (registrations.length === 0) throw new Error("PIPR_RUNTIME_TOOLS_DATA or PIPR_CUSTOM_TOOLS_DATA is required");
28
+ for (const registration of registrations) registration.register(pi, registration.dataPath);
29
+ }
30
+ function toolRegistrations() {
31
+ return compact([registration(runtimeDataPath(), registerRuntimeReadTools), registration(customToolsDataPath(), registerCustomTools)]);
32
+ }
33
+ function registration(dataPath, register) {
34
+ return dataPath ? {
35
+ dataPath,
36
+ register
37
+ } : void 0;
38
+ }
39
+ function registerRuntimeReadTools(pi, dataPath) {
40
+ const dataRoot = path.dirname(dataPath);
41
+ pi.registerTool({
42
+ name: "pipr_read_diff",
43
+ label: "Read pipr Diff Manifest",
44
+ description: "Read bounded full Diff Manifest data by path and/or range id.",
45
+ parameters: {
46
+ type: "object",
47
+ additionalProperties: false,
48
+ properties: {
49
+ path: { type: "string" },
50
+ rangeId: { type: "string" }
51
+ }
52
+ },
53
+ async execute(_toolCallId, params) {
54
+ return textResult(readDiffFromRuntimeData(await Bun.file(dataPath).json(), readDiffParams(params)));
55
+ }
56
+ });
57
+ pi.registerTool({
58
+ name: "pipr_read_at_ref",
59
+ label: "Read pipr file at ref",
60
+ description: "Read bounded file content for a Diff Manifest path at base or head.",
61
+ parameters: {
62
+ type: "object",
63
+ additionalProperties: false,
64
+ required: [
65
+ "path",
66
+ "ref",
67
+ "rangeId"
68
+ ],
69
+ properties: {
70
+ path: { type: "string" },
71
+ ref: {
72
+ type: "string",
73
+ enum: ["base", "head"]
74
+ },
75
+ rangeId: { type: "string" }
76
+ }
77
+ },
78
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
79
+ const cwd = typeof ctx?.cwd === "string" ? ctx.cwd : "";
80
+ return textResult(await readAtRef(dataRoot, await Bun.file(dataPath).json(), readAtRefParams(params), cwd));
81
+ }
82
+ });
83
+ }
84
+ function registerCustomTools(pi, dataPath) {
85
+ const bridgeUrl = customToolBridgeUrl();
86
+ const bridgeToken = customToolBridgeToken();
87
+ const data = customToolDataSchema.parse(JSON.parse(readFileSync(dataPath, "utf8")));
88
+ for (const tool of data.tools) pi.registerTool({
89
+ name: tool.name,
90
+ label: tool.name,
91
+ description: tool.description ?? "pipr custom config tool.",
92
+ parameters: {
93
+ type: "object",
94
+ additionalProperties: true
95
+ },
96
+ async execute(_toolCallId, params) {
97
+ return textResult(await callCustomTool(bridgeUrl, bridgeToken, tool.name, params));
98
+ }
99
+ });
100
+ }
101
+ function runtimeDataPath() {
102
+ const dataPath = process.env.PIPR_RUNTIME_TOOLS_DATA;
103
+ if (!dataPath) return;
104
+ if (!path.isAbsolute(dataPath)) throw new Error("PIPR_RUNTIME_TOOLS_DATA must be an absolute path");
105
+ return dataPath;
106
+ }
107
+ function customToolsDataPath() {
108
+ const dataPath = process.env.PIPR_CUSTOM_TOOLS_DATA;
109
+ if (!dataPath) return;
110
+ if (!path.isAbsolute(dataPath)) throw new Error("PIPR_CUSTOM_TOOLS_DATA must be an absolute path");
111
+ return dataPath;
112
+ }
113
+ function customToolBridgeUrl() {
114
+ const value = process.env.PIPR_CUSTOM_TOOLS_BRIDGE_URL;
115
+ if (!value) throw new Error("PIPR_CUSTOM_TOOLS_BRIDGE_URL is required for pipr custom tools");
116
+ return value;
117
+ }
118
+ function customToolBridgeToken() {
119
+ const value = process.env.PIPR_CUSTOM_TOOLS_BRIDGE_TOKEN;
120
+ if (!value) throw new Error("PIPR_CUSTOM_TOOLS_BRIDGE_TOKEN is required for pipr custom tools");
121
+ return value;
122
+ }
123
+ async function callCustomTool(bridgeUrl, bridgeToken, tool, params) {
124
+ const response = await fetch(`${bridgeUrl}/call`, {
125
+ method: "POST",
126
+ headers: {
127
+ authorization: `Bearer ${bridgeToken}`,
128
+ "content-type": "application/json"
129
+ },
130
+ body: JSON.stringify({
131
+ tool,
132
+ params
133
+ })
134
+ });
135
+ const payload = await parseCustomToolBridgePayload(response, tool);
136
+ assertCustomToolBridgeOk(response, payload, tool);
137
+ return Reflect.get(payload, "result");
138
+ }
139
+ async function parseCustomToolBridgePayload(response, tool) {
140
+ try {
141
+ return customToolBridgePayloadSchema.parse(await response.json());
142
+ } catch {
143
+ throw new Error(`Custom tool '${tool}' returned invalid bridge response`);
144
+ }
145
+ }
146
+ function assertCustomToolBridgeOk(response, payload, tool) {
147
+ if (!response.ok || Reflect.get(payload, "ok") !== true) {
148
+ const error = Reflect.get(payload, "error");
149
+ throw new Error(typeof error === "string" ? error : `Custom tool '${tool}' failed`);
150
+ }
151
+ }
152
+ function textResult(value) {
153
+ return {
154
+ content: [{
155
+ type: "text",
156
+ text: JSON.stringify(value, null, 2)
157
+ }],
158
+ details: value
159
+ };
160
+ }
161
+ async function readAtRef(dataRoot, data, params, cwd) {
162
+ const request = resolveReadAtRefRequest(data.manifest, params);
163
+ if (!request.window) return unavailableReadAtRefResult(request);
164
+ if (params.ref === "base") return await readBaseSnapshot(dataRoot, data.baseRanges[params.rangeId], params, request);
165
+ return await readHeadWorkspaceFile(cwd, data.toolResponseMaxBytes, params, request);
166
+ }
167
+ async function readBaseSnapshot(dataRoot, snapshot, params, request) {
168
+ const readable = readableBaseSnapshotSchema.safeParse(snapshot);
169
+ if (!readable.success) return snapshot ?? unavailableReadAtRefResult(request);
170
+ const snapshotData = readable.data;
171
+ return {
172
+ path: params.path,
173
+ ref: params.ref,
174
+ sourcePath: request.sourcePath,
175
+ rangeId: params.rangeId,
176
+ startLine: snapshotData.startLine,
177
+ endLine: snapshotData.endLine,
178
+ available: true,
179
+ content: await Bun.file(path.join(dataRoot, snapshotData.relativePath)).text(),
180
+ bytes: snapshotData.bytes,
181
+ truncated: snapshotData.truncated
182
+ };
183
+ }
184
+ async function readHeadWorkspaceFile(cwd, maxBytes, params, request) {
185
+ if (!request.window) return unavailableReadAtRefResult(request);
186
+ const target = resolveAllowedPath(cwd, request.sourcePath);
187
+ await assertNoSymlinkPath(cwd, request.sourcePath);
188
+ return {
189
+ path: params.path,
190
+ ref: params.ref,
191
+ sourcePath: request.sourcePath,
192
+ rangeId: params.rangeId,
193
+ startLine: request.window.startLine,
194
+ endLine: request.window.endLine,
195
+ ...boundedLineSlice(await Bun.file(target).text(), request.window, maxBytes)
196
+ };
197
+ }
198
+ //#endregion
199
+ export { piprRuntimeTools as default };
200
+
201
+ //# sourceMappingURL=runtime-tools-extension.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-tools-extension.mjs","names":[],"sources":["../../src/pi/runtime-tools-extension.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { compact } from \"lodash-es\";\nimport { z } from \"zod\";\nimport {\n assertNoSymlinkPath,\n type BaseRangeSnapshot,\n boundedLineSlice,\n type ReadAtRefParams,\n type RuntimeToolData,\n readAtRefParams,\n readDiffFromRuntimeData,\n readDiffParams,\n resolveAllowedPath,\n resolveReadAtRefRequest,\n unavailableReadAtRefResult,\n} from \"./runtime-tools-core.js\";\n\ntype PiExtensionHost = {\n registerTool(tool: PiTool): void;\n};\n\ntype PiTool = {\n name: string;\n label: string;\n description: string;\n parameters: Record<string, unknown>;\n execute: (\n toolCallId: string,\n params: unknown,\n signal?: unknown,\n onUpdate?: unknown,\n ctx?: { cwd?: unknown },\n ) => Promise<ToolResult>;\n};\n\ntype ToolResult = {\n content: Array<{ type: \"text\"; text: string }>;\n details: unknown;\n};\n\nconst customToolDataSchema = z.strictObject({\n tools: z.array(\n z.strictObject({\n name: z.string().min(1),\n description: z.string().optional(),\n }),\n ),\n});\n\nconst customToolBridgePayloadSchema = z.record(z.string(), z.unknown());\nconst readableBaseSnapshotSchema = z.looseObject({\n path: z.string(),\n ref: z.enum([\"base\", \"head\"]),\n sourcePath: z.string(),\n rangeId: z.string(),\n startLine: z.number(),\n endLine: z.number(),\n available: z.literal(true),\n relativePath: z.string(),\n bytes: z.number().optional(),\n truncated: z.boolean().optional(),\n});\n\n/** Registers pipr runtime read tools and config-defined custom tools with Pi. */\nexport default function piprRuntimeTools(pi: PiExtensionHost): void {\n const registrations = toolRegistrations();\n if (registrations.length === 0) {\n throw new Error(\"PIPR_RUNTIME_TOOLS_DATA or PIPR_CUSTOM_TOOLS_DATA is required\");\n }\n for (const registration of registrations) {\n registration.register(pi, registration.dataPath);\n }\n}\n\nfunction toolRegistrations(): Array<{\n dataPath: string;\n register(pi: PiExtensionHost, dataPath: string): void;\n}> {\n return compact([\n registration(runtimeDataPath(), registerRuntimeReadTools),\n registration(customToolsDataPath(), registerCustomTools),\n ]);\n}\n\nfunction registration(\n dataPath: string | undefined,\n register: (pi: PiExtensionHost, dataPath: string) => void,\n) {\n return dataPath ? { dataPath, register } : undefined;\n}\n\nfunction registerRuntimeReadTools(pi: PiExtensionHost, dataPath: string): void {\n const dataRoot = path.dirname(dataPath);\n\n pi.registerTool({\n name: \"pipr_read_diff\",\n label: \"Read pipr Diff Manifest\",\n description: \"Read bounded full Diff Manifest data by path and/or range id.\",\n parameters: {\n type: \"object\",\n additionalProperties: false,\n properties: {\n path: { type: \"string\" },\n rangeId: { type: \"string\" },\n },\n },\n async execute(_toolCallId, params) {\n const data = (await Bun.file(dataPath).json()) as RuntimeToolData;\n const result = readDiffFromRuntimeData(data, readDiffParams(params));\n return textResult(result);\n },\n });\n\n pi.registerTool({\n name: \"pipr_read_at_ref\",\n label: \"Read pipr file at ref\",\n description: \"Read bounded file content for a Diff Manifest path at base or head.\",\n parameters: {\n type: \"object\",\n additionalProperties: false,\n required: [\"path\", \"ref\", \"rangeId\"],\n properties: {\n path: { type: \"string\" },\n ref: { type: \"string\", enum: [\"base\", \"head\"] },\n rangeId: { type: \"string\" },\n },\n },\n async execute(_toolCallId, params, _signal, _onUpdate, ctx) {\n const cwd = typeof ctx?.cwd === \"string\" ? ctx.cwd : \"\";\n const data = (await Bun.file(dataPath).json()) as RuntimeToolData;\n const result = await readAtRef(dataRoot, data, readAtRefParams(params), cwd);\n return textResult(result);\n },\n });\n}\n\nfunction registerCustomTools(pi: PiExtensionHost, dataPath: string): void {\n const bridgeUrl = customToolBridgeUrl();\n const bridgeToken = customToolBridgeToken();\n const data = customToolDataSchema.parse(JSON.parse(readFileSync(dataPath, \"utf8\")));\n for (const tool of data.tools) {\n pi.registerTool({\n name: tool.name,\n label: tool.name,\n description: tool.description ?? \"pipr custom config tool.\",\n parameters: {\n type: \"object\",\n additionalProperties: true,\n },\n async execute(_toolCallId, params) {\n const result = await callCustomTool(bridgeUrl, bridgeToken, tool.name, params);\n return textResult(result);\n },\n });\n }\n}\n\nfunction runtimeDataPath(): string | undefined {\n const dataPath = process.env.PIPR_RUNTIME_TOOLS_DATA;\n if (!dataPath) {\n return undefined;\n }\n if (!path.isAbsolute(dataPath)) {\n throw new Error(\"PIPR_RUNTIME_TOOLS_DATA must be an absolute path\");\n }\n return dataPath;\n}\n\nfunction customToolsDataPath(): string | undefined {\n const dataPath = process.env.PIPR_CUSTOM_TOOLS_DATA;\n if (!dataPath) {\n return undefined;\n }\n if (!path.isAbsolute(dataPath)) {\n throw new Error(\"PIPR_CUSTOM_TOOLS_DATA must be an absolute path\");\n }\n return dataPath;\n}\n\nfunction customToolBridgeUrl(): string {\n const value = process.env.PIPR_CUSTOM_TOOLS_BRIDGE_URL;\n if (!value) {\n throw new Error(\"PIPR_CUSTOM_TOOLS_BRIDGE_URL is required for pipr custom tools\");\n }\n return value;\n}\n\nfunction customToolBridgeToken(): string {\n const value = process.env.PIPR_CUSTOM_TOOLS_BRIDGE_TOKEN;\n if (!value) {\n throw new Error(\"PIPR_CUSTOM_TOOLS_BRIDGE_TOKEN is required for pipr custom tools\");\n }\n return value;\n}\n\nasync function callCustomTool(\n bridgeUrl: string,\n bridgeToken: string,\n tool: string,\n params: unknown,\n): Promise<unknown> {\n const response = await fetch(`${bridgeUrl}/call`, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${bridgeToken}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({ tool, params }),\n });\n const payload = await parseCustomToolBridgePayload(response, tool);\n assertCustomToolBridgeOk(response, payload, tool);\n return Reflect.get(payload, \"result\");\n}\n\nasync function parseCustomToolBridgePayload(\n response: Response,\n tool: string,\n): Promise<Record<string, unknown>> {\n try {\n return customToolBridgePayloadSchema.parse(await response.json());\n } catch {\n throw new Error(`Custom tool '${tool}' returned invalid bridge response`);\n }\n}\n\nfunction assertCustomToolBridgeOk(\n response: Response,\n payload: Record<string, unknown>,\n tool: string,\n): void {\n if (!response.ok || Reflect.get(payload, \"ok\") !== true) {\n const error = Reflect.get(payload, \"error\");\n throw new Error(typeof error === \"string\" ? error : `Custom tool '${tool}' failed`);\n }\n}\n\nfunction textResult(value: unknown): ToolResult {\n return {\n content: [{ type: \"text\", text: JSON.stringify(value, null, 2) }],\n details: value,\n };\n}\n\nasync function readAtRef(\n dataRoot: string,\n data: RuntimeToolData,\n params: ReadAtRefParams,\n cwd: string,\n): Promise<unknown> {\n const request = resolveReadAtRefRequest(data.manifest, params);\n if (!request.window) {\n return unavailableReadAtRefResult(request);\n }\n if (params.ref === \"base\") {\n return await readBaseSnapshot(dataRoot, data.baseRanges[params.rangeId], params, request);\n }\n return await readHeadWorkspaceFile(cwd, data.toolResponseMaxBytes, params, request);\n}\n\nasync function readBaseSnapshot(\n dataRoot: string,\n snapshot: BaseRangeSnapshot | undefined,\n params: ReadAtRefParams,\n request: ReturnType<typeof resolveReadAtRefRequest>,\n): Promise<unknown> {\n const readable = readableBaseSnapshotSchema.safeParse(snapshot);\n if (!readable.success) {\n return snapshot ?? unavailableReadAtRefResult(request);\n }\n const snapshotData = readable.data;\n return {\n path: params.path,\n ref: params.ref,\n sourcePath: request.sourcePath,\n rangeId: params.rangeId,\n startLine: snapshotData.startLine,\n endLine: snapshotData.endLine,\n available: true,\n content: await Bun.file(path.join(dataRoot, snapshotData.relativePath)).text(),\n bytes: snapshotData.bytes,\n truncated: snapshotData.truncated,\n };\n}\n\nasync function readHeadWorkspaceFile(\n cwd: string,\n maxBytes: number,\n params: ReadAtRefParams,\n request: ReturnType<typeof resolveReadAtRefRequest>,\n): Promise<unknown> {\n if (!request.window) {\n return unavailableReadAtRefResult(request);\n }\n const target = resolveAllowedPath(cwd, request.sourcePath);\n await assertNoSymlinkPath(cwd, request.sourcePath);\n return {\n path: params.path,\n ref: params.ref,\n sourcePath: request.sourcePath,\n rangeId: params.rangeId,\n startLine: request.window.startLine,\n endLine: request.window.endLine,\n ...boundedLineSlice(await Bun.file(target).text(), request.window, maxBytes),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,174 @@
1
+ import { lstat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { z } from "zod";
4
+ //#region src/diff/ranges.ts
5
+ function createDiffRangeIndex(manifest) {
6
+ const filesByPath = new Map(manifest.files.map((file) => [file.path, file]));
7
+ const rangesById = /* @__PURE__ */ new Map();
8
+ for (const file of manifest.files) for (const range of file.commentableRanges) rangesById.set(range.id, {
9
+ file,
10
+ range
11
+ });
12
+ return {
13
+ fileByPath(filePath) {
14
+ return filesByPath.get(filePath);
15
+ },
16
+ excludedReason(filePath) {
17
+ return filesByPath.get(filePath)?.excludedReason;
18
+ },
19
+ findRange(rangeId) {
20
+ return rangesById.get(rangeId);
21
+ },
22
+ rangeById(rangeId) {
23
+ return rangesById.get(rangeId)?.range;
24
+ },
25
+ requireFile(filePath) {
26
+ const file = filesByPath.get(filePath);
27
+ if (!file) throw new Error(`Path '${filePath}' is not in the Diff Manifest`);
28
+ return file;
29
+ },
30
+ requireRangeInFile(file, rangeId) {
31
+ const range = file.commentableRanges.find((item) => item.id === rangeId);
32
+ if (range) return range;
33
+ if (rangesById.has(rangeId)) throw new Error(`Diff Manifest range '${rangeId}' is not in path '${file.path}'`);
34
+ throw new Error(`Unknown Diff Manifest range '${rangeId}'`);
35
+ },
36
+ requireHunk(file, range) {
37
+ const hunk = file.hunks.find((item) => item.hunkIndex === range.hunkIndex && item.contentHash === range.hunkContentHash);
38
+ if (!hunk) throw new Error(`Diff Manifest range '${range.id}' has no matching hunk`);
39
+ return hunk;
40
+ }
41
+ };
42
+ }
43
+ //#endregion
44
+ //#region src/pi/runtime-tools-core.ts
45
+ const readAtRefContextLines = 3;
46
+ const readDiffParamsSchema = z.preprocess((params) => {
47
+ const record = typeof params === "object" && params !== null && !Array.isArray(params) ? params : {};
48
+ return {
49
+ path: typeof record.path === "string" ? record.path : void 0,
50
+ rangeId: typeof record.rangeId === "string" ? record.rangeId : void 0
51
+ };
52
+ }, z.object({
53
+ path: z.string().optional(),
54
+ rangeId: z.string().optional()
55
+ }));
56
+ const readAtRefParamsSchema = z.preprocess((params) => typeof params === "object" && params !== null && !Array.isArray(params) ? params : {}, z.object({
57
+ path: z.unknown(),
58
+ ref: z.enum(["base", "head"], { error: (issue) => `Unsupported ref '${String(issue.input)}'` }),
59
+ rangeId: z.string({ error: "rangeId must be a string" })
60
+ }));
61
+ function readDiffFromRuntimeData(data, params) {
62
+ const { rangeId } = params;
63
+ const filePath = params.path === void 0 ? void 0 : parseManifestPath(params.path);
64
+ const ranges = createDiffRangeIndex(data.manifest);
65
+ if (filePath !== void 0) ranges.requireFile(filePath);
66
+ if (rangeId !== void 0 && !ranges.findRange(rangeId)) throw new Error(`Unknown Diff Manifest range '${rangeId}'`);
67
+ return boundedJson({ files: data.manifest.files.filter((file) => filePath === void 0 || file.path === filePath).map((file) => filterManifestFileRanges(file, rangeId)).filter((file) => rangeId === void 0 || file.commentableRanges.length > 0) }, data.toolResponseMaxBytes);
68
+ }
69
+ function boundedJson(value, maxBytes) {
70
+ const text = JSON.stringify(value, null, 2);
71
+ const bytes = Buffer.byteLength(text, "utf8");
72
+ if (bytes <= maxBytes) return {
73
+ truncated: false,
74
+ bytes,
75
+ value
76
+ };
77
+ return {
78
+ truncated: true,
79
+ bytes,
80
+ maxBytes,
81
+ text: Buffer.from(text, "utf8").subarray(0, maxBytes).toString("utf8")
82
+ };
83
+ }
84
+ function boundedLineSlice(content, window, maxBytes) {
85
+ const lines = content.match(/[^\n]*(?:\n|$)/g) ?? [];
86
+ if (lines.at(-1) === "") lines.pop();
87
+ const slice = lines.slice(window.startLine - 1, window.endLine).join("");
88
+ const buffer = Buffer.from(slice, "utf8");
89
+ return {
90
+ available: true,
91
+ content: buffer.subarray(0, maxBytes).toString("utf8"),
92
+ bytes: buffer.byteLength,
93
+ truncated: buffer.byteLength > maxBytes
94
+ };
95
+ }
96
+ function resolveReadAtRefRequest(manifest, params) {
97
+ const filePath = parseManifestPath(params.path);
98
+ const ranges = createDiffRangeIndex(manifest);
99
+ const file = ranges.requireFile(filePath);
100
+ const range = ranges.requireRangeInFile(file, params.rangeId);
101
+ const hunk = ranges.requireHunk(file, range);
102
+ const sourcePath = parseManifestPath(params.ref === "base" ? file.previousPath ?? file.path : file.path);
103
+ return {
104
+ file,
105
+ range,
106
+ hunk,
107
+ ref: params.ref,
108
+ sourcePath,
109
+ window: lineWindowForRange(range, hunk, params.ref)
110
+ };
111
+ }
112
+ function unavailableReadAtRefResult(request) {
113
+ return {
114
+ path: request.file.path,
115
+ ref: request.ref,
116
+ sourcePath: request.sourcePath,
117
+ rangeId: request.range.id,
118
+ startLine: 0,
119
+ endLine: 0,
120
+ available: false
121
+ };
122
+ }
123
+ function parseManifestPath(filePath) {
124
+ if (typeof filePath !== "string" || filePath.length === 0 || filePath.includes("\0") || path.isAbsolute(filePath) || filePath.split(/[\\/]/).some((part) => part === ".." || part === ".git" || part === "")) throw new Error(`Unsafe manifest path '${String(filePath)}'`);
125
+ return filePath;
126
+ }
127
+ function resolveAllowedPath(root, filePath) {
128
+ const resolved = path.resolve(root, filePath);
129
+ const relative = path.relative(root, resolved);
130
+ if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`Path '${filePath}' resolves outside the workspace`);
131
+ return resolved;
132
+ }
133
+ async function assertNoSymlinkPath(root, filePath) {
134
+ const parts = filePath.split(/[\\/]/);
135
+ let current = root;
136
+ for (const part of parts) {
137
+ current = path.join(current, part);
138
+ if ((await lstat(current)).isSymbolicLink()) throw new Error(`Path '${filePath}' crosses a symlink`);
139
+ }
140
+ }
141
+ function readDiffParams(params) {
142
+ return readDiffParamsSchema.parse(params);
143
+ }
144
+ function readAtRefParams(params) {
145
+ const parsed = readAtRefParamsSchema.parse(params);
146
+ return {
147
+ path: parseManifestPath(parsed.path),
148
+ ref: parsed.ref,
149
+ rangeId: parsed.rangeId
150
+ };
151
+ }
152
+ function filterManifestFileRanges(file, rangeId) {
153
+ if (rangeId === void 0) return file;
154
+ return {
155
+ ...file,
156
+ commentableRanges: file.commentableRanges.filter((range) => range.id === rangeId)
157
+ };
158
+ }
159
+ function lineWindowForRange(range, hunk, ref) {
160
+ const targetSide = ref === "base" ? "LEFT" : "RIGHT";
161
+ if (range.side !== targetSide) return;
162
+ const hunkStart = ref === "base" ? hunk.oldStart : hunk.newStart;
163
+ const hunkLines = ref === "base" ? hunk.oldLines : hunk.newLines;
164
+ if (hunkLines === 0) return;
165
+ const hunkEnd = hunkStart + hunkLines - 1;
166
+ return {
167
+ startLine: Math.max(hunkStart, range.startLine - readAtRefContextLines),
168
+ endLine: Math.min(hunkEnd, range.endLine + readAtRefContextLines)
169
+ };
170
+ }
171
+ //#endregion
172
+ export { readDiffFromRuntimeData as a, resolveReadAtRefRequest as c, readAtRefParams as i, unavailableReadAtRefResult as l, boundedLineSlice as n, readDiffParams as o, parseManifestPath as r, resolveAllowedPath as s, assertNoSymlinkPath as t, createDiffRangeIndex as u };
173
+
174
+ //# sourceMappingURL=runtime-tools-core-CW1xenzy.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-tools-core-CW1xenzy.mjs","names":[],"sources":["../src/diff/ranges.ts","../src/pi/runtime-tools-core.ts"],"sourcesContent":["import type { CommentableRange, DiffHunk, DiffManifest, DiffManifestFile } from \"../types.js\";\n\nexport type DiffRangeMatch = {\n file: DiffManifestFile;\n range: CommentableRange;\n};\n\nexport type DiffRangeIndex = {\n fileByPath(filePath: string): DiffManifestFile | undefined;\n excludedReason(filePath: string): string | undefined;\n findRange(rangeId: string): DiffRangeMatch | undefined;\n rangeById(rangeId: string): CommentableRange | undefined;\n requireFile(filePath: string): DiffManifestFile;\n requireRangeInFile(file: DiffManifestFile, rangeId: string): CommentableRange;\n requireHunk(file: DiffManifestFile, range: CommentableRange): DiffHunk;\n};\n\nexport function createDiffRangeIndex(manifest: DiffManifest): DiffRangeIndex {\n const filesByPath = new Map(manifest.files.map((file) => [file.path, file]));\n const rangesById = new Map<string, DiffRangeMatch>();\n for (const file of manifest.files) {\n for (const range of file.commentableRanges) {\n rangesById.set(range.id, { file, range });\n }\n }\n\n return {\n fileByPath(filePath) {\n return filesByPath.get(filePath);\n },\n excludedReason(filePath) {\n return filesByPath.get(filePath)?.excludedReason;\n },\n findRange(rangeId) {\n return rangesById.get(rangeId);\n },\n rangeById(rangeId) {\n return rangesById.get(rangeId)?.range;\n },\n requireFile(filePath) {\n const file = filesByPath.get(filePath);\n if (!file) {\n throw new Error(`Path '${filePath}' is not in the Diff Manifest`);\n }\n return file;\n },\n requireRangeInFile(file, rangeId) {\n const range = file.commentableRanges.find((item) => item.id === rangeId);\n if (range) {\n return range;\n }\n if (rangesById.has(rangeId)) {\n throw new Error(`Diff Manifest range '${rangeId}' is not in path '${file.path}'`);\n }\n throw new Error(`Unknown Diff Manifest range '${rangeId}'`);\n },\n requireHunk(file, range) {\n const hunk = file.hunks.find(\n (item) => item.hunkIndex === range.hunkIndex && item.contentHash === range.hunkContentHash,\n );\n if (!hunk) {\n throw new Error(`Diff Manifest range '${range.id}' has no matching hunk`);\n }\n return hunk;\n },\n };\n}\n","import { lstat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { createDiffRangeIndex } from \"../diff/ranges.js\";\nimport type { CommentableRange, DiffHunk, DiffManifest, DiffManifestFile } from \"../types.js\";\n\nconst readAtRefContextLines = 3;\n\nexport type ReadDiffParams = {\n path?: string;\n rangeId?: string;\n};\n\nexport type ReadAtRefParams = {\n path: string;\n ref: \"base\" | \"head\";\n rangeId: string;\n};\n\nexport type RuntimeToolData = {\n manifest: DiffManifest;\n toolResponseMaxBytes: number;\n baseRanges: Record<string, BaseRangeSnapshot>;\n};\n\nexport type BaseRangeSnapshot = {\n path: string;\n ref: \"base\" | \"head\";\n sourcePath: string;\n rangeId: string;\n startLine: number;\n endLine: number;\n available: boolean;\n relativePath?: string;\n bytes?: number;\n truncated?: boolean;\n};\n\nexport type ReadAtRefRequest = {\n file: DiffManifestFile;\n range: CommentableRange;\n hunk: DiffHunk;\n ref: \"base\" | \"head\";\n sourcePath: string;\n window: LineWindow | undefined;\n};\n\nexport type LineWindow = {\n startLine: number;\n endLine: number;\n};\n\nexport type LineSliceResult = {\n available: true;\n content: string;\n bytes: number;\n truncated: boolean;\n};\n\nconst readDiffParamsSchema = z.preprocess(\n (params) => {\n const record =\n typeof params === \"object\" && params !== null && !Array.isArray(params)\n ? (params as Record<string, unknown>)\n : {};\n return {\n path: typeof record.path === \"string\" ? record.path : undefined,\n rangeId: typeof record.rangeId === \"string\" ? record.rangeId : undefined,\n };\n },\n z.object({\n path: z.string().optional(),\n rangeId: z.string().optional(),\n }),\n);\n\nconst readAtRefParamsSchema = z.preprocess(\n (params) =>\n typeof params === \"object\" && params !== null && !Array.isArray(params) ? params : {},\n z.object({\n path: z.unknown(),\n ref: z.enum([\"base\", \"head\"], {\n error: (issue) => `Unsupported ref '${String(issue.input)}'`,\n }),\n rangeId: z.string({ error: \"rangeId must be a string\" }),\n }),\n);\n\nexport function readDiffFromRuntimeData(data: RuntimeToolData, params: ReadDiffParams): unknown {\n const { rangeId } = params;\n const filePath = params.path === undefined ? undefined : parseManifestPath(params.path);\n const ranges = createDiffRangeIndex(data.manifest);\n if (filePath !== undefined) {\n ranges.requireFile(filePath);\n }\n if (rangeId !== undefined && !ranges.findRange(rangeId)) {\n throw new Error(`Unknown Diff Manifest range '${rangeId}'`);\n }\n const files = data.manifest.files\n .filter((file) => filePath === undefined || file.path === filePath)\n .map((file) => filterManifestFileRanges(file, rangeId))\n .filter((file) => rangeId === undefined || file.commentableRanges.length > 0);\n return boundedJson({ files }, data.toolResponseMaxBytes);\n}\n\nfunction boundedJson(value: unknown, maxBytes: number): unknown {\n const text = JSON.stringify(value, null, 2);\n const bytes = Buffer.byteLength(text, \"utf8\");\n if (bytes <= maxBytes) {\n return { truncated: false, bytes, value };\n }\n return {\n truncated: true,\n bytes,\n maxBytes,\n text: Buffer.from(text, \"utf8\").subarray(0, maxBytes).toString(\"utf8\"),\n };\n}\n\nexport function boundedLineSlice(\n content: string,\n window: LineWindow,\n maxBytes: number,\n): LineSliceResult {\n const lines = content.match(/[^\\n]*(?:\\n|$)/g) ?? [];\n if (lines.at(-1) === \"\") {\n lines.pop();\n }\n const slice = lines.slice(window.startLine - 1, window.endLine).join(\"\");\n const buffer = Buffer.from(slice, \"utf8\");\n return {\n available: true,\n content: buffer.subarray(0, maxBytes).toString(\"utf8\"),\n bytes: buffer.byteLength,\n truncated: buffer.byteLength > maxBytes,\n };\n}\n\nexport function resolveReadAtRefRequest(\n manifest: DiffManifest,\n params: ReadAtRefParams,\n): ReadAtRefRequest {\n const filePath = parseManifestPath(params.path);\n const ranges = createDiffRangeIndex(manifest);\n const file = ranges.requireFile(filePath);\n const range = ranges.requireRangeInFile(file, params.rangeId);\n const hunk = ranges.requireHunk(file, range);\n const sourcePath = parseManifestPath(\n params.ref === \"base\" ? (file.previousPath ?? file.path) : file.path,\n );\n return {\n file,\n range,\n hunk,\n ref: params.ref,\n sourcePath,\n window: lineWindowForRange(range, hunk, params.ref),\n };\n}\n\nexport function unavailableReadAtRefResult(request: ReadAtRefRequest): BaseRangeSnapshot {\n return {\n path: request.file.path,\n ref: request.ref,\n sourcePath: request.sourcePath,\n rangeId: request.range.id,\n startLine: 0,\n endLine: 0,\n available: false,\n };\n}\n\nexport function parseManifestPath(filePath: unknown): string {\n if (\n typeof filePath !== \"string\" ||\n filePath.length === 0 ||\n filePath.includes(\"\\0\") ||\n path.isAbsolute(filePath) ||\n filePath.split(/[\\\\/]/).some((part) => part === \"..\" || part === \".git\" || part === \"\")\n ) {\n throw new Error(`Unsafe manifest path '${String(filePath)}'`);\n }\n return filePath;\n}\n\nexport function resolveAllowedPath(root: string, filePath: string): string {\n const resolved = path.resolve(root, filePath);\n const relative = path.relative(root, resolved);\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(`Path '${filePath}' resolves outside the workspace`);\n }\n return resolved;\n}\n\nexport async function assertNoSymlinkPath(root: string, filePath: string): Promise<void> {\n const parts = filePath.split(/[\\\\/]/);\n let current = root;\n for (const part of parts) {\n current = path.join(current, part);\n const stats = await lstat(current);\n if (stats.isSymbolicLink()) {\n throw new Error(`Path '${filePath}' crosses a symlink`);\n }\n }\n}\n\nexport function readDiffParams(params: unknown): ReadDiffParams {\n return readDiffParamsSchema.parse(params);\n}\n\nexport function readAtRefParams(params: unknown): ReadAtRefParams {\n const parsed = readAtRefParamsSchema.parse(params);\n return { path: parseManifestPath(parsed.path), ref: parsed.ref, rangeId: parsed.rangeId };\n}\n\nfunction filterManifestFileRanges(\n file: DiffManifestFile,\n rangeId: string | undefined,\n): DiffManifestFile {\n if (rangeId === undefined) {\n return file;\n }\n return {\n ...file,\n commentableRanges: file.commentableRanges.filter((range) => range.id === rangeId),\n };\n}\n\nfunction lineWindowForRange(\n range: CommentableRange,\n hunk: DiffHunk,\n ref: \"base\" | \"head\",\n): LineWindow | undefined {\n const targetSide: CommentableRange[\"side\"] = ref === \"base\" ? \"LEFT\" : \"RIGHT\";\n if (range.side !== targetSide) {\n return undefined;\n }\n const hunkStart = ref === \"base\" ? hunk.oldStart : hunk.newStart;\n const hunkLines = ref === \"base\" ? hunk.oldLines : hunk.newLines;\n if (hunkLines === 0) {\n return undefined;\n }\n const hunkEnd = hunkStart + hunkLines - 1;\n return {\n startLine: Math.max(hunkStart, range.startLine - readAtRefContextLines),\n endLine: Math.min(hunkEnd, range.endLine + readAtRefContextLines),\n };\n}\n"],"mappings":"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"}