@krosskinetic/pi-zg 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 KrossKinetic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ **WORK IN PROGRESS / ALPHA**
2
+
3
+ # pi-zg
4
+
5
+ A [Pi](https://github.com/earendil-works/pi-mono) package that natively integrates
6
+ [zvec-grep](https://github.com/) (`zg`) semantic code search into Pi: it manages
7
+ `zg`'s shared server, offers to build a missing index interactively, and gives
8
+ the agent three tools (`zg_search`, `zg_rg`, `zg_index`) plus three commands
9
+ (`/zg-status`, `/zg-index`, `/zg-server`). It calls an existing local `zg` CLI;
10
+ it does not install or bundle zvec-grep itself.
11
+
12
+ ## Prerequisites
13
+
14
+ Install `@zvec/zvec-grep` separately and ensure `zg` is on `PATH`.
15
+
16
+ ## Install into Pi
17
+
18
+ ```bash
19
+ pi install npm:pi-zg
20
+ ```
21
+
22
+ For local development, from a checkout of this repo:
23
+
24
+ ```bash
25
+ pi -e .
26
+ ```
27
+
28
+ ## What it does
29
+
30
+ ### Shared server (`zg server`)
31
+
32
+ `zg` runs a shared, loopback daemon that other tools (Claude, Cursor, etc.,
33
+ configured via `zg install`) may also use. This extension:
34
+
35
+ - **Auto-starts** it at session start if it isn't already running
36
+ (`--no-zg-autostart` disables this). `zg server on` is idempotent, so this
37
+ is safe to run every session.
38
+ - **Never auto-stops it** — since it's shared, stopping it could break other
39
+ tools relying on it. Use `/zg-server off` to stop it explicitly.
40
+
41
+ With the server running, `zg query` refreshes the index in the background
42
+ automatically after file changes, so `zg_index` is rarely needed once a
43
+ project has an initial index.
44
+
45
+ ### Tools (LLM-callable)
46
+
47
+ - **`zg_search`** — semantic search over the project's zvec-grep index
48
+ (`zg query`). If no index exists and the UI supports it, offers to build
49
+ one interactively (including picking a default embedding model if none is
50
+ configured) instead of failing outright.
51
+ - **`zg_rg`** — exhaustive exact-match search via zvec-grep's managed
52
+ ripgrep (`zg query --rg`), respecting the project's configured
53
+ ignore/glob rules. Complements `zg_search` and Pi's built-in `grep` tool;
54
+ does not require an index.
55
+ - **`zg_index`** — build, rebuild, or drop the persistent index. Gated by
56
+ prompt guidelines so the agent only uses it when the user explicitly asks.
57
+
58
+ ### Commands (human-invoked)
59
+
60
+ - **`/zg-status`** — zg version, server state, and index status/coverage.
61
+ - **`/zg-index [--rebuild|--drop]`** — build, rebuild, or drop the index
62
+ directly, without going through the LLM. Confirms before `--drop`.
63
+ - **`/zg-server <on|off|status>`** — explicit manual control of the shared
64
+ daemon. Confirms before `off`, since other tools may depend on it.
65
+
66
+ ### Status
67
+
68
+ The footer shows `server ●/○` and `index ✓/✗` (colored via the active
69
+ theme), refreshed at session start and at the start of every turn.
70
+
71
+ ### Flags
72
+
73
+ - `--no-zg-autostart` — disable automatically starting the shared server.
74
+ - `--no-zg-onboard` — disable the interactive "build an index?" offer;
75
+ `zg_search` fails with a manual-fix message instead (useful for
76
+ non-interactive/scripted `pi -p` runs).
77
+
78
+ ## Non-goals
79
+
80
+ - Does not register zg's MCP server as an actual MCP tool source inside Pi
81
+ — Pi extensions have no MCP-client API, so integration stays CLI-based
82
+ (`pi.exec`), just daemon-aware and stateful rather than re-deriving status
83
+ via subprocess spawns before every call.
84
+ - Does not override Pi's built-in `grep` tool. `zg_search`/`zg_rg` are
85
+ purely additive.
86
+ - Does not auto-stop the shared `zg` server.
@@ -0,0 +1,428 @@
1
+ import {
2
+ truncateHead,
3
+ type ExtensionAPI,
4
+ type ExtensionContext,
5
+ } from "@earendil-works/pi-coding-agent";
6
+ import { Type } from "typebox";
7
+
8
+ /**
9
+ * pi-zg: a native Pi integration for the zvec-grep (`zg`) CLI.
10
+ *
11
+ * Beyond wrapping `zg query`/`zg index`, this extension:
12
+ * - Auto-starts zg's shared server at session start so queries get
13
+ * background index auto-refresh for free (never auto-stops it, since
14
+ * it's a daemon other agents/tools may also depend on).
15
+ * - Caches zg's availability/server/index state per session (refreshed at
16
+ * session_start and each turn_start) instead of re-deriving it with
17
+ * extra `zg` subprocess spawns before every tool call.
18
+ * - Offers to build a missing index interactively instead of just failing.
19
+ * - Exposes managed ripgrep (`zg query --rg`) as an additional tool.
20
+ *
21
+ * Non-goals: this does not register zg's MCP server as an actual MCP
22
+ * source (Pi extensions have no MCP-client API) and does not override the
23
+ * built-in `grep` tool.
24
+ */
25
+
26
+ const STATUS_KEY = "pi-zg";
27
+ const DEFAULT_LOCAL_MODEL = "local/potion-code-16m-v2";
28
+
29
+ interface ZgState {
30
+ /** Whether refreshZgState has run at least once this session. */
31
+ checked: boolean;
32
+ /** Whether `zg` is on PATH. */
33
+ available: boolean;
34
+ version?: string;
35
+ /** Whether the shared zg server daemon is up and ready. */
36
+ serverRunning: boolean;
37
+ /** Whether the current project has a ready index. */
38
+ indexed: boolean;
39
+ /** Whether the user already declined the "build an index?" offer this session. */
40
+ declinedIndexOffer: boolean;
41
+ }
42
+
43
+ function createZgState(): ZgState {
44
+ return {
45
+ checked: false,
46
+ available: false,
47
+ serverRunning: false,
48
+ indexed: false,
49
+ declinedIndexOffer: false,
50
+ };
51
+ }
52
+
53
+ async function execZg(
54
+ pi: ExtensionAPI,
55
+ args: string[],
56
+ ctx: ExtensionContext,
57
+ opts: { signal?: AbortSignal; timeout?: number } = {},
58
+ ) {
59
+ return pi.exec("zg", args, { cwd: ctx.cwd, signal: opts.signal, timeout: opts.timeout ?? 10_000 });
60
+ }
61
+
62
+ function renderStatus(ctx: ExtensionContext, state: ZgState) {
63
+ const theme = ctx.ui.theme;
64
+ if (!state.available) {
65
+ ctx.ui.setStatus(STATUS_KEY, theme.fg("dim", "zg: not found"));
66
+ return;
67
+ }
68
+ const server = state.serverRunning ? theme.fg("success", "server\u25cf") : theme.fg("dim", "server\u25cb");
69
+ const index = state.indexed ? theme.fg("success", "index\u2713") : theme.fg("warning", "index\u2717");
70
+ ctx.ui.setStatus(STATUS_KEY, `${server} ${index}`);
71
+ }
72
+
73
+ /** Refresh cached zg availability/server/index state and update the footer. */
74
+ async function refreshZgState(
75
+ pi: ExtensionAPI,
76
+ ctx: ExtensionContext,
77
+ state: ZgState,
78
+ signal?: AbortSignal,
79
+ ): Promise<ZgState> {
80
+ const version = await execZg(pi, ["version"], ctx, { signal, timeout: 5_000 });
81
+ state.checked = true;
82
+ state.available = version.code === 0;
83
+ state.version = state.available ? version.stdout.trim() : undefined;
84
+
85
+ if (!state.available) {
86
+ state.serverRunning = false;
87
+ state.indexed = false;
88
+ renderStatus(ctx, state);
89
+ return state;
90
+ }
91
+
92
+ const [server, status] = await Promise.all([
93
+ execZg(pi, ["server", "status", "--check-ready"], ctx, { signal, timeout: 5_000 }),
94
+ execZg(pi, ["status", "--check-ready"], ctx, { signal, timeout: 5_000 }),
95
+ ]);
96
+ state.serverRunning = server.code === 0;
97
+ state.indexed = status.code === 0;
98
+
99
+ renderStatus(ctx, state);
100
+ return state;
101
+ }
102
+
103
+ function compactOutput(output: string): string {
104
+ const truncated = truncateHead(output.trim(), {
105
+ maxLines: 2_000,
106
+ maxBytes: 50 * 1024,
107
+ });
108
+ return truncated.truncated ? `${truncated.content}\n\n[zg output truncated]` : truncated.content;
109
+ }
110
+
111
+ /** Best-effort hit count parsed from `zg query`'s "hits: N" summary line. */
112
+ function parseHitCount(output: string): number | undefined {
113
+ const match = output.match(/^hits:\s*(\d+)/m);
114
+ return match ? Number(match[1]) : undefined;
115
+ }
116
+
117
+ /**
118
+ * Lazily offer to build a missing index right where the LLM discovered it's
119
+ * missing, instead of dead-ending with a "go run this command yourself" error.
120
+ * Returns true if an index is ready after this call.
121
+ */
122
+ async function offerToBuildIndex(
123
+ pi: ExtensionAPI,
124
+ ctx: ExtensionContext,
125
+ state: ZgState,
126
+ signal: AbortSignal | undefined,
127
+ ): Promise<boolean> {
128
+ if (state.declinedIndexOffer || !ctx.hasUI || pi.getFlag("no-zg-onboard")) {
129
+ return false;
130
+ }
131
+
132
+ const build = await ctx.ui.confirm(
133
+ "Build zg index?",
134
+ `No zvec-grep index found for ${ctx.cwd}. Build one now? This runs \`zg index\` with the configured default embedding model.`,
135
+ { signal },
136
+ );
137
+ if (!build) {
138
+ state.declinedIndexOffer = true;
139
+ return false;
140
+ }
141
+
142
+ ctx.ui.setWorkingMessage("Building zg index...");
143
+ let result = await execZg(pi, ["index"], ctx, { signal, timeout: 300_000 });
144
+
145
+ if (result.code !== 0 && /embedding/i.test(result.stderr)) {
146
+ // No default embedding model configured yet -- offer to set one and retry.
147
+ const choice = await ctx.ui.select(
148
+ "No default embedding model configured. Choose one:",
149
+ [`${DEFAULT_LOCAL_MODEL} (local, no API key)`, "Enter a different model", "Cancel"],
150
+ { signal },
151
+ );
152
+ let model: string | undefined;
153
+ if (choice?.startsWith(DEFAULT_LOCAL_MODEL)) {
154
+ model = DEFAULT_LOCAL_MODEL;
155
+ } else if (choice === "Enter a different model") {
156
+ model = await ctx.ui.input("Embedding model", "provider/model-id", { signal });
157
+ }
158
+ if (model) {
159
+ await execZg(pi, ["config", "model", "set", model, "--default"], ctx, { signal });
160
+ result = await execZg(pi, ["index", "--embedding", model], ctx, { signal, timeout: 300_000 });
161
+ }
162
+ }
163
+
164
+ ctx.ui.setWorkingMessage();
165
+
166
+ if (result.code === 0) {
167
+ ctx.ui.notify("zg index built.", "info");
168
+ await refreshZgState(pi, ctx, state, signal);
169
+ return state.indexed;
170
+ }
171
+
172
+ ctx.ui.notify(`zg index failed: ${(result.stderr || result.stdout || "unknown error").trim()}`, "error");
173
+ return false;
174
+ }
175
+
176
+ export default function (pi: ExtensionAPI) {
177
+ const state = createZgState();
178
+
179
+ pi.registerFlag("no-zg-autostart", {
180
+ description: "Disable automatically starting the shared zg server at session start",
181
+ type: "boolean",
182
+ default: false,
183
+ });
184
+ pi.registerFlag("no-zg-onboard", {
185
+ description: "Disable the interactive offer to build a missing zg index; fail with a manual-fix message instead",
186
+ type: "boolean",
187
+ default: false,
188
+ });
189
+
190
+ pi.on("session_start", async (_event, ctx) => {
191
+ await refreshZgState(pi, ctx, state);
192
+
193
+ if (!pi.getFlag("no-zg-autostart") && state.available && !state.serverRunning) {
194
+ // Fire-and-forget: don't block startup on daemon warmup. `zg server on`
195
+ // is idempotent, so this is safe even if something else started it
196
+ // in the meantime.
197
+ execZg(pi, ["server", "on"], ctx, { timeout: 20_000 })
198
+ .then(() => refreshZgState(pi, ctx, state))
199
+ .catch(() => {});
200
+ }
201
+ });
202
+
203
+ pi.on("turn_start", async (_event, ctx) => {
204
+ if (state.available) {
205
+ await refreshZgState(pi, ctx, state);
206
+ }
207
+ });
208
+
209
+ pi.registerTool({
210
+ name: "zg_search",
211
+ label: "zg search",
212
+ description:
213
+ "Semantic code search over the current project's zvec-grep index. Requires zg on PATH; offers to build a missing index interactively when possible. With the zg server running, the index refreshes in the background automatically. Returns at most 2,000 lines or 50 KB of CLI output.",
214
+ promptSnippet: "Semantic search in the current project's zg index",
215
+ parameters: Type.Object({
216
+ query: Type.String({ minLength: 1, description: "Semantic code-search query" }),
217
+ limit: Type.Optional(
218
+ Type.Integer({
219
+ minimum: 1,
220
+ maximum: 100,
221
+ description: "Maximum results to return (1-100; zg defaults to 7)",
222
+ }),
223
+ ),
224
+ }),
225
+
226
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
227
+ if (!state.checked) await refreshZgState(pi, ctx, state, signal);
228
+ if (!state.available) {
229
+ throw new Error(
230
+ "`zg` is not available on PATH. Install @zvec/zvec-grep separately, then run `zg index` in this project.",
231
+ );
232
+ }
233
+
234
+ if (!state.indexed && !(await offerToBuildIndex(pi, ctx, state, signal))) {
235
+ throw new Error(
236
+ `This project does not appear to be indexed. Run \`zg index\` manually in ${ctx.cwd}, then retry.`,
237
+ );
238
+ }
239
+
240
+ const args = ["query"];
241
+ if (params.limit !== undefined) args.push("--limit", String(params.limit));
242
+ args.push(params.query);
243
+
244
+ const result = await execZg(pi, args, ctx, { signal, timeout: 30_000 });
245
+ if (result.code !== 0) {
246
+ // State may be stale (e.g. index dropped externally); refresh for next call.
247
+ await refreshZgState(pi, ctx, state, signal);
248
+ throw new Error((result.stderr || result.stdout || "zg query failed").trim());
249
+ }
250
+
251
+ const text = compactOutput(result.stdout);
252
+ return {
253
+ content: [{ type: "text", text: text || "No results found." }],
254
+ details: { query: params.query, limit: params.limit, hits: parseHitCount(result.stdout) },
255
+ };
256
+ },
257
+ });
258
+
259
+ pi.registerTool({
260
+ name: "zg_rg",
261
+ label: "zg managed ripgrep",
262
+ description:
263
+ "Exhaustive exact-match search via zvec-grep's managed ripgrep (`zg query --rg`). Respects this project's configured ignore/glob rules. Complements zg_search (semantic) and the built-in grep tool; does not require an index.",
264
+ promptSnippet: "Exhaustive managed ripgrep search via zg (respects project ignore rules)",
265
+ parameters: Type.Object({
266
+ pattern: Type.String({ minLength: 1, description: "Pattern to search for" }),
267
+ paths: Type.Optional(
268
+ Type.Array(Type.String(), { description: "Paths to restrict the search to (default: whole project)" }),
269
+ ),
270
+ fixedString: Type.Optional(Type.Boolean({ description: "Treat pattern as a literal string instead of a regex" })),
271
+ glob: Type.Optional(
272
+ Type.String({ description: "Include glob, e.g. '*.ts'; prefix with '!' to exclude, e.g. '!*.test.ts'" }),
273
+ ),
274
+ }),
275
+
276
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
277
+ if (!state.checked) await refreshZgState(pi, ctx, state, signal);
278
+ if (!state.available) {
279
+ throw new Error("`zg` is not available on PATH. Install @zvec/zvec-grep separately.");
280
+ }
281
+
282
+ const args = ["query", "--rg"];
283
+ if (params.fixedString) args.push("-F");
284
+ if (params.glob) args.push("-g", params.glob);
285
+ args.push("-e", params.pattern);
286
+ if (params.paths?.length) args.push(...params.paths);
287
+
288
+ const result = await execZg(pi, args, ctx, { signal, timeout: 30_000 });
289
+ if (result.code !== 0) {
290
+ throw new Error((result.stderr || result.stdout || "zg query --rg failed").trim());
291
+ }
292
+
293
+ const text = compactOutput(result.stdout);
294
+ return {
295
+ content: [{ type: "text", text: text || "No matches found." }],
296
+ details: { pattern: params.pattern, paths: params.paths },
297
+ };
298
+ },
299
+ });
300
+
301
+ pi.registerTool({
302
+ name: "zg_index",
303
+ label: "zg index",
304
+ description:
305
+ "Build, rebuild, or drop the current project's persistent zvec-grep index. Use only when the user explicitly asks: with the zg server running, an existing index already refreshes in the background after edits, so this is mainly for the first-time build, an explicit rebuild, or dropping the index.",
306
+ promptSnippet: "Explicitly build, rebuild, or drop the current project's zg index",
307
+ promptGuidelines: [
308
+ "Use zg_index only when the user explicitly requests indexing, rebuilding, or dropping the zg index; do not call it merely because zg_search reports a missing index -- that flow already offers to build it interactively.",
309
+ "Never pass drop: true unless the user explicitly asked to remove or reset the index.",
310
+ ],
311
+ parameters: Type.Object({
312
+ rebuild: Type.Optional(Type.Boolean({ description: "Rebuild the existing index from scratch" })),
313
+ drop: Type.Optional(
314
+ Type.Boolean({
315
+ description: "Permanently remove the index instead of building it. Only when the user explicitly asked to drop/reset it.",
316
+ }),
317
+ ),
318
+ }),
319
+
320
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
321
+ if (!state.checked) await refreshZgState(pi, ctx, state, signal);
322
+ if (!state.available) {
323
+ throw new Error("`zg` is not available on PATH. Install @zvec/zvec-grep separately before indexing.");
324
+ }
325
+
326
+ const args = ["index"];
327
+ if (params.drop) args.push("--drop", "--yes");
328
+ else if (params.rebuild) args.push("--rebuild");
329
+
330
+ const result = await execZg(pi, args, ctx, { signal, timeout: 300_000 });
331
+ if (result.code !== 0) {
332
+ throw new Error((result.stderr || result.stdout || "zg index failed").trim());
333
+ }
334
+
335
+ await refreshZgState(pi, ctx, state, signal);
336
+ const text = compactOutput(result.stdout || result.stderr);
337
+ return {
338
+ content: [{ type: "text", text: text || "zg index completed." }],
339
+ details: { rebuild: params.rebuild, drop: params.drop },
340
+ };
341
+ },
342
+ });
343
+
344
+ pi.registerCommand("zg-status", {
345
+ description: "Report zg version, server, and index status for this project",
346
+ handler: async (_args, ctx) => {
347
+ await refreshZgState(pi, ctx, state);
348
+ if (!state.available) {
349
+ ctx.ui.notify("zg: not found on PATH", "error");
350
+ return;
351
+ }
352
+
353
+ const detail = await execZg(pi, ["status"], ctx);
354
+ const lines = [
355
+ `zg: ${state.version || "available"}`,
356
+ `server: ${state.serverRunning ? "running" : "stopped"}`,
357
+ "",
358
+ (detail.stdout || detail.stderr).trim(),
359
+ ];
360
+ ctx.ui.notify(lines.join("\n"), state.indexed ? "info" : "warning");
361
+ },
362
+ });
363
+
364
+ pi.registerCommand("zg-index", {
365
+ description: "Build the zg index for this project. Use --rebuild to rebuild or --drop to remove it",
366
+ handler: async (args, ctx) => {
367
+ if (!state.available) {
368
+ ctx.ui.notify("zg: not found on PATH", "error");
369
+ return;
370
+ }
371
+
372
+ const flags = args.trim().split(/\s+/).filter(Boolean);
373
+ const drop = flags.includes("--drop");
374
+ const rebuild = flags.includes("--rebuild");
375
+
376
+ if (drop) {
377
+ const confirmed = await ctx.ui.confirm("Drop zg index?", `This permanently removes the index for ${ctx.cwd}.`);
378
+ if (!confirmed) return;
379
+ }
380
+
381
+ const cmdArgs = ["index"];
382
+ if (drop) cmdArgs.push("--drop", "--yes");
383
+ else if (rebuild) cmdArgs.push("--rebuild");
384
+
385
+ ctx.ui.setWorkingMessage(drop ? "Dropping zg index..." : "Building zg index...");
386
+ const result = await execZg(pi, cmdArgs, ctx, { timeout: 300_000 });
387
+ ctx.ui.setWorkingMessage();
388
+
389
+ await refreshZgState(pi, ctx, state);
390
+ if (result.code !== 0) {
391
+ ctx.ui.notify(`zg index failed: ${(result.stderr || result.stdout || "unknown error").trim()}`, "error");
392
+ return;
393
+ }
394
+ ctx.ui.notify(drop ? "Index dropped." : "Index ready.", "info");
395
+ },
396
+ });
397
+
398
+ pi.registerCommand("zg-server", {
399
+ description: "Control the shared zg server: /zg-server <on|off|status>",
400
+ handler: async (args, ctx) => {
401
+ if (!state.available) {
402
+ ctx.ui.notify("zg: not found on PATH", "error");
403
+ return;
404
+ }
405
+
406
+ const action = args.trim().toLowerCase() || "status";
407
+ if (action !== "on" && action !== "off" && action !== "status") {
408
+ ctx.ui.notify("Usage: /zg-server <on|off|status>", "warning");
409
+ return;
410
+ }
411
+
412
+ if (action === "off") {
413
+ const confirmed = await ctx.ui.confirm(
414
+ "Stop the shared zg server?",
415
+ "This daemon may be used by other agents/tools (Claude, Cursor, etc.) configured via `zg install`. Stopping it affects all of them, not just this session.",
416
+ );
417
+ if (!confirmed) return;
418
+ }
419
+
420
+ const result = await execZg(pi, ["server", action], ctx, { timeout: 20_000 });
421
+ await refreshZgState(pi, ctx, state);
422
+ ctx.ui.notify(
423
+ (result.stdout || result.stderr).trim() || `zg server ${action} done.`,
424
+ result.code === 0 ? "info" : "error",
425
+ );
426
+ },
427
+ });
428
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@krosskinetic/pi-zg",
3
+ "version": "0.1.0",
4
+ "description": "Pi extension for zvec-grep (zg): semantic code search, managed ripgrep, and shared-server-aware index management",
5
+ "type": "module",
6
+ "keywords": ["pi-package", "pi", "pi-coding-agent", "zvec-grep", "semantic-search", "code-search"],
7
+ "license": "MIT",
8
+ "author": "KrossKinetic",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/KrossKinetic/pi-zg.git"
12
+ },
13
+ "homepage": "https://github.com/KrossKinetic/pi-zg#readme",
14
+ "bugs": "https://github.com/KrossKinetic/pi-zg/issues",
15
+ "pi": {
16
+ "extensions": ["./extensions"]
17
+ },
18
+ "files": ["extensions", "README.md", "LICENSE"],
19
+ "peerDependencies": {
20
+ "@earendil-works/pi-coding-agent": "*",
21
+ "typebox": "*"
22
+ },
23
+ "devDependencies": {
24
+ "@earendil-works/pi-coding-agent": "^0.84.2",
25
+ "typebox": "^1.3.7",
26
+ "typescript": "^5.9.3"
27
+ },
28
+ "scripts": {
29
+ "typecheck": "tsc --noEmit"
30
+ }
31
+ }