@krosskinetic/pi-zg 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +84 -28
  2. package/extensions/pi-zg.ts +140 -73
  3. package/package.json +17 -4
package/README.md CHANGED
@@ -1,22 +1,23 @@
1
1
  **WORK IN PROGRESS / ALPHA**
2
2
 
3
- # pi-zg
3
+ # @krosskinetic/pi-zg
4
4
 
5
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.
6
+ [zvec-grep](https://github.com/) (`zg`) semantic code search into Pi: it offers
7
+ to build a missing index interactively, and gives the agent four tools
8
+ (`zg_search`, `zg_rg`, `zg_index`, `zg_status`) plus three commands
9
+ (`/zg-settings`, `/zg-status`, `/zg-index`). It calls an existing local `zg` CLI;
11
10
 
12
11
  ## Prerequisites
13
12
 
14
13
  Install `@zvec/zvec-grep` separately and ensure `zg` is on `PATH`.
14
+ This extension invokes that local CLI; it does not install, bundle, or
15
+ configure zvec-grep for you.
15
16
 
16
17
  ## Install into Pi
17
18
 
18
19
  ```bash
19
- pi install npm:pi-zg
20
+ pi install npm:@krosskinetic/pi-zg
20
21
  ```
21
22
 
22
23
  For local development, from a checkout of this repo:
@@ -25,22 +26,33 @@ For local development, from a checkout of this repo:
25
26
  pi -e .
26
27
  ```
27
28
 
28
- ## What it does
29
+ ## Quick start
30
+
31
+ 1. Install and configure `zg`, then verify that `zg version` works from your
32
+ project directory.
33
+ 2. Install this package and start Pi in the project you want to search.
34
+ 3. At session start, pi-zg checks whether `zg` is available and whether the
35
+ project has an index. Each `zg_search` refreshes the index first, so
36
+ results are never stale — no server daemon is used.
37
+ 4. Ask Pi a natural-language code-search question. Its `zg_search` tool
38
+ searches the index. If the project has not been indexed, pi-zg offers to
39
+ build one interactively.
29
40
 
30
- ### Shared server (`zg server`)
41
+ For example, ask: “Where is authentication token refresh implemented?” For an
42
+ exact identifier, literal, or regex search, Pi can use `zg_rg` instead.
31
43
 
32
- `zg` runs a shared, loopback daemon that other tools (Claude, Cursor, etc.,
33
- configured via `zg install`) may also use. This extension:
44
+ ## What it does
34
45
 
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.
46
+ ### Always-fresh direct searches
40
47
 
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.
48
+ This extension runs every search in **direct mode and refreshes the index before
49
+ answering** (`zg query --mode direct --refresh wait`). It does **not** use or manage
50
+ zg's shared server daemon — there is no background process to keep alive, start,
51
+ or shut down, so nothing can linger as an orphan between sessions.
52
+
53
+ Because each semantic search rebuilds any stale parts of the index first, results
54
+ are never stale: after editing a file, the next `zg_search` reflects the change.
55
+ This also means no index auto-refresh daemon needs to run at all.
44
56
 
45
57
  ### Tools (LLM-callable)
46
58
 
@@ -54,33 +66,77 @@ project has an initial index.
54
66
  does not require an index.
55
67
  - **`zg_index`** — build, rebuild, or drop the persistent index. Gated by
56
68
  prompt guidelines so the agent only uses it when the user explicitly asks.
69
+ - **`zg_status`** — report zg version and the current project's index status.
70
+ Reads pi's cached zg state, so no extra `zg` subprocess is spawned for it.
71
+
72
+ `zg_search` accepts a natural-language `query` and an optional `limit` of
73
+ 1–100 results (zg defaults to 7). `zg_rg` accepts a regex `pattern`, optional
74
+ paths, `fixedString` for literal matching, and one `glob` filter. Its output
75
+ and the output of the other tools are capped at 2,000 lines or 50 KB.
76
+
77
+
78
+ #### Choosing a search tool
79
+
80
+ Use the right tool for the kind of query, and don't reach for grep when semantic
81
+ search is the better fit:
82
+
83
+ - **`zg_search`** — find code by **meaning**. Use when you don't know the exact
84
+ identifiers or wording (“where is token refresh handled”, “how does the cache
85
+ layer work”). Keyword grep would miss these.
86
+ - **`zg_rg`** — find code by **exact text**: a known identifier, string literal, or
87
+ regex, honoring the project's ignore/glob rules.
88
+ - **Pi's built-in `grep`** — a quick literal scan when you don't need zg's
89
+ ignore rules or rg features.
57
90
 
91
+ In short: concept → `zg_search`; exact token/regex → `zg_rg`; everything is
92
+ refreshed before answering, so you always search current code.
58
93
  ### Commands (human-invoked)
59
94
 
60
- - **`/zg-status`** — zg version, server state, and index status/coverage.
95
+ - **`/zg-settings`** — interactive configuration for zg's default embedding
96
+ model, embedding device, and provider API key.
97
+ - **`/zg-status`** — zg version and index status/coverage.
61
98
  - **`/zg-index [--rebuild|--drop]`** — build, rebuild, or drop the index
62
99
  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.
100
+
101
+ ### Settings (`/zg-settings`)
102
+
103
+ `/zg-settings` exposes the configuration that most directly affects Pi search:
104
+
105
+ - **Default embedding model** — sets zg's persistent default for newly built
106
+ indexes, for example `local/potion-code-16m-v2` or
107
+ `qwen/text-embedding-v4`. Existing indexes keep their recorded embedding
108
+ schema.
109
+ - **Embedding device** — configures `auto`, `cpu`, `metal`, `vulkan`, or
110
+ `cuda` for a specified local model.
111
+ - **Provider API key** — saves credentials for a named embedding provider via
112
+ `zg config provider set`. The value is passed directly to zg and is not
113
+ shown in Pi notifications.
114
+
115
+ For advanced index-selection rules, remote endpoints, authentication, and
116
+ other less-common settings, use the underlying `zg` CLI directly.
65
117
 
66
118
  ### Status
67
119
 
68
- The footer shows `server ●/○` and `index ✓/✗` (colored via the active
69
- theme), refreshed at session start and at the start of every turn.
120
+ The footer shows `index ✓/✗` (colored via the active theme), refreshed at
121
+ session start and at the start of every turn.
70
122
 
71
123
  ### Flags
72
124
 
73
- - `--no-zg-autostart` — disable automatically starting the shared server.
74
125
  - `--no-zg-onboard` — disable the interactive "build an index?" offer;
75
126
  `zg_search` fails with a manual-fix message instead (useful for
76
127
  non-interactive/scripted `pi -p` runs).
77
128
 
129
+ Pass these when launching Pi, for example:
130
+
131
+ ```bash
132
+ pi --no-zg-onboard
133
+ ```
134
+
78
135
  ## Non-goals
79
136
 
80
137
  - Does not register zg's MCP server as an actual MCP tool source inside Pi
81
138
  — 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.
139
+ (`pi.exec`), stateful rather than re-deriving status via subprocess spawns
140
+ before every call.
84
141
  - Does not override Pi's built-in `grep` tool. `zg_search`/`zg_rg` are
85
142
  purely additive.
86
- - Does not auto-stop the shared `zg` server.
@@ -9,10 +9,9 @@ import { Type } from "typebox";
9
9
  * pi-zg: a native Pi integration for the zvec-grep (`zg`) CLI.
10
10
  *
11
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
12
+ * - Runs every search in direct mode, refreshing the index before answering so
13
+ * results are never stale (no background server daemon involved).
14
+ * - Caches zg's availability and index state per session (refreshed at
16
15
  * session_start and each turn_start) instead of re-deriving it with
17
16
  * extra `zg` subprocess spawns before every tool call.
18
17
  * - Offers to build a missing index interactively instead of just failing.
@@ -25,15 +24,12 @@ import { Type } from "typebox";
25
24
 
26
25
  const STATUS_KEY = "pi-zg";
27
26
  const DEFAULT_LOCAL_MODEL = "local/potion-code-16m-v2";
28
-
29
27
  interface ZgState {
30
28
  /** Whether refreshZgState has run at least once this session. */
31
29
  checked: boolean;
32
30
  /** Whether `zg` is on PATH. */
33
31
  available: boolean;
34
32
  version?: string;
35
- /** Whether the shared zg server daemon is up and ready. */
36
- serverRunning: boolean;
37
33
  /** Whether the current project has a ready index. */
38
34
  indexed: boolean;
39
35
  /** Whether the user already declined the "build an index?" offer this session. */
@@ -44,7 +40,6 @@ function createZgState(): ZgState {
44
40
  return {
45
41
  checked: false,
46
42
  available: false,
47
- serverRunning: false,
48
43
  indexed: false,
49
44
  declinedIndexOffer: false,
50
45
  };
@@ -65,12 +60,12 @@ function renderStatus(ctx: ExtensionContext, state: ZgState) {
65
60
  ctx.ui.setStatus(STATUS_KEY, theme.fg("dim", "zg: not found"));
66
61
  return;
67
62
  }
68
- const server = state.serverRunning ? theme.fg("success", "server\u25cf") : theme.fg("dim", "server\u25cb");
69
63
  const index = state.indexed ? theme.fg("success", "index\u2713") : theme.fg("warning", "index\u2717");
70
- ctx.ui.setStatus(STATUS_KEY, `${server} ${index}`);
64
+ ctx.ui.setStatus(STATUS_KEY, index);
71
65
  }
72
66
 
73
- /** Refresh cached zg availability/server/index state and update the footer. */
67
+
68
+ /** Refresh cached zg availability and index state, then update the footer. */
74
69
  async function refreshZgState(
75
70
  pi: ExtensionAPI,
76
71
  ctx: ExtensionContext,
@@ -83,17 +78,12 @@ async function refreshZgState(
83
78
  state.version = state.available ? version.stdout.trim() : undefined;
84
79
 
85
80
  if (!state.available) {
86
- state.serverRunning = false;
87
81
  state.indexed = false;
88
82
  renderStatus(ctx, state);
89
83
  return state;
90
84
  }
91
85
 
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;
86
+ const status = await execZg(pi, ["status", "--check-ready"], ctx, { signal, timeout: 5_000 });
97
87
  state.indexed = status.code === 0;
98
88
 
99
89
  renderStatus(ctx, state);
@@ -114,6 +104,83 @@ function parseHitCount(output: string): number | undefined {
114
104
  return match ? Number(match[1]) : undefined;
115
105
  }
116
106
 
107
+
108
+
109
+ async function configureDefaultModel(pi: ExtensionAPI, ctx: ExtensionContext): Promise<void> {
110
+ const model = await ctx.ui.input("Default embedding model", "e.g. local/potion-code-16m-v2 or qwen/text-embedding-v4");
111
+ if (!model?.trim()) return;
112
+ const result = await execZg(pi, ["config", "model", "set", model.trim(), "--default"], ctx);
113
+ if (result.code !== 0) {
114
+ ctx.ui.notify("Could not set the embedding model. Inspect zg configuration in a terminal for details.", "error");
115
+ return;
116
+ }
117
+ ctx.ui.notify(`Default embedding model set to ${model.trim()}. Existing indexes keep their current schema.`, "info");
118
+ }
119
+
120
+ async function configureEmbeddingDevice(pi: ExtensionAPI, ctx: ExtensionContext): Promise<void> {
121
+ const model = await ctx.ui.input("Model to configure", "e.g. local/potion-code-16m-v2");
122
+ if (!model?.trim()) return;
123
+ const device = await ctx.ui.select("Embedding device", ["auto", "cpu", "metal", "vulkan", "cuda", "Cancel"]);
124
+ if (!device || device === "Cancel") return;
125
+ const result = await execZg(pi, ["config", "model", "set", model.trim(), "--device", device], ctx);
126
+ if (result.code !== 0) {
127
+ ctx.ui.notify("Could not set the embedding device. Inspect zg configuration in a terminal for details.", "error");
128
+ return;
129
+ }
130
+ ctx.ui.notify(`Embedding device for ${model.trim()} set to ${device}.`, "info");
131
+ }
132
+
133
+ async function configureProviderKey(pi: ExtensionAPI, ctx: ExtensionContext): Promise<void> {
134
+ const provider = await ctx.ui.input("Embedding provider", "e.g. qwen");
135
+ if (!provider?.trim()) return;
136
+ const apiKey = await ctx.ui.input("API key", "Paste the provider API key");
137
+ if (!apiKey?.trim()) return;
138
+ const result = await execZg(pi, ["config", "provider", "set", provider.trim(), "--api-key", apiKey.trim()], ctx);
139
+ if (result.code !== 0) {
140
+ ctx.ui.notify("Could not save the provider API key. Inspect zg configuration in a terminal for details.", "error");
141
+ return;
142
+ }
143
+ ctx.ui.notify(`Credentials saved for ${provider.trim()}.`, "info");
144
+ }
145
+
146
+ async function openZgSettings(pi: ExtensionAPI, ctx: ExtensionContext, state: ZgState): Promise<void> {
147
+ if (!state.checked) await refreshZgState(pi, ctx, state);
148
+
149
+ while (true) {
150
+ const choice = await ctx.ui.select("zg settings", [
151
+ "Default embedding model",
152
+ "Embedding device",
153
+ "Provider API key",
154
+ "View active settings",
155
+ "Done",
156
+ ]);
157
+ if (!choice || choice === "Done") return;
158
+
159
+ switch (choice) {
160
+ case "Default embedding model":
161
+ await configureDefaultModel(pi, ctx);
162
+ break;
163
+ case "Embedding device":
164
+ await configureEmbeddingDevice(pi, ctx);
165
+ break;
166
+ case "Provider API key":
167
+ await configureProviderKey(pi, ctx);
168
+ break;
169
+ case "View active settings": {
170
+ await refreshZgState(pi, ctx, state);
171
+ const detail = await execZg(pi, ["status"], ctx);
172
+ ctx.ui.notify(
173
+ [
174
+ (detail.stdout || detail.stderr).trim(),
175
+ ].join("\n"),
176
+ state.indexed ? "info" : "warning",
177
+ );
178
+ break;
179
+ }
180
+ }
181
+ }
182
+ }
183
+
117
184
  /**
118
185
  * Lazily offer to build a missing index right where the LLM discovered it's
119
186
  * missing, instead of dead-ending with a "go run this command yourself" error.
@@ -140,7 +207,7 @@ async function offerToBuildIndex(
140
207
  }
141
208
 
142
209
  ctx.ui.setWorkingMessage("Building zg index...");
143
- let result = await execZg(pi, ["index"], ctx, { signal, timeout: 300_000 });
210
+ let result = await execZg(pi, ["index", "--mode", "direct"], ctx, { signal, timeout: 300_000 });
144
211
 
145
212
  if (result.code !== 0 && /embedding/i.test(result.stderr)) {
146
213
  // No default embedding model configured yet -- offer to set one and retry.
@@ -157,7 +224,10 @@ async function offerToBuildIndex(
157
224
  }
158
225
  if (model) {
159
226
  await execZg(pi, ["config", "model", "set", model, "--default"], ctx, { signal });
160
- result = await execZg(pi, ["index", "--embedding", model], ctx, { signal, timeout: 300_000 });
227
+ result = await execZg(pi, ["index", "--mode", "direct", "--embedding", model], ctx, {
228
+ signal,
229
+ timeout: 300_000,
230
+ });
161
231
  }
162
232
  }
163
233
 
@@ -176,29 +246,16 @@ async function offerToBuildIndex(
176
246
  export default function (pi: ExtensionAPI) {
177
247
  const state = createZgState();
178
248
 
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
249
  pi.registerFlag("no-zg-onboard", {
185
250
  description: "Disable the interactive offer to build a missing zg index; fail with a manual-fix message instead",
186
251
  type: "boolean",
187
252
  default: false,
188
253
  });
189
254
 
190
- pi.on("session_start", async (_event, ctx) => {
191
- await refreshZgState(pi, ctx, state);
255
+ pi.on("session_start", async (_event, ctx) => {
256
+ await refreshZgState(pi, ctx, state);
257
+ });
192
258
 
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
259
 
203
260
  pi.on("turn_start", async (_event, ctx) => {
204
261
  if (state.available) {
@@ -210,7 +267,7 @@ export default function (pi: ExtensionAPI) {
210
267
  name: "zg_search",
211
268
  label: "zg search",
212
269
  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.",
270
+ "Semantic (meaning-based) code search over the current project's zvec-grep index. The go-to when you want to find code by CONCEPT rather than exact text — e.g. where authentication is handled, or how a feature works — without knowing the precise identifiers. Each call refreshes the index first, so results are never stale; it offers to build the index interactively if none exists. Prefer over keyword grep when an exact-token search would miss relevant code. For precise identifiers, string literals, or regex, use zg_rg or the built-in grep tool instead. Returns at most 2,000 lines or 50 KB of CLI output.",
214
271
  promptSnippet: "Semantic search in the current project's zg index",
215
272
  parameters: Type.Object({
216
273
  query: Type.String({ minLength: 1, description: "Semantic code-search query" }),
@@ -237,7 +294,7 @@ export default function (pi: ExtensionAPI) {
237
294
  );
238
295
  }
239
296
 
240
- const args = ["query"];
297
+ const args = ["query", "--mode", "direct", "--refresh", "wait"];
241
298
  if (params.limit !== undefined) args.push("--limit", String(params.limit));
242
299
  args.push(params.query);
243
300
 
@@ -260,7 +317,7 @@ export default function (pi: ExtensionAPI) {
260
317
  name: "zg_rg",
261
318
  label: "zg managed ripgrep",
262
319
  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.",
320
+ "Exhaustive exact-match search via zvec-grep's managed ripgrep (`zg query --rg`). Use when you know the precise identifier, string literal, or regex to locate and want results that honor the project's configured ignore/glob rules (e.g. excluding node_modules). Prefer it over zg_search when you need literal/regex matches rather than meaning; prefer it over the built-in grep tool when you want rg's powers (globs, -F literal) with the project's ignore rules applied. Does not require an index.",
264
321
  promptSnippet: "Exhaustive managed ripgrep search via zg (respects project ignore rules)",
265
322
  parameters: Type.Object({
266
323
  pattern: Type.String({ minLength: 1, description: "Pattern to search for" }),
@@ -302,7 +359,7 @@ export default function (pi: ExtensionAPI) {
302
359
  name: "zg_index",
303
360
  label: "zg index",
304
361
  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.",
362
+ "Build, rebuild, or drop the current project's persistent zvec-grep index. Use only when the user explicitly asks: searches already refresh a stale index before answering, so this is mainly for the first-time build, an explicit rebuild, or dropping the index.",
306
363
  promptSnippet: "Explicitly build, rebuild, or drop the current project's zg index",
307
364
  promptGuidelines: [
308
365
  "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.",
@@ -323,7 +380,7 @@ export default function (pi: ExtensionAPI) {
323
380
  throw new Error("`zg` is not available on PATH. Install @zvec/zvec-grep separately before indexing.");
324
381
  }
325
382
 
326
- const args = ["index"];
383
+ const args = ["index", "--mode", "direct"];
327
384
  if (params.drop) args.push("--drop", "--yes");
328
385
  else if (params.rebuild) args.push("--rebuild");
329
386
 
@@ -341,8 +398,49 @@ export default function (pi: ExtensionAPI) {
341
398
  },
342
399
  });
343
400
 
401
+ pi.registerTool({
402
+ name: "zg_status",
403
+ label: "zg status",
404
+ description:
405
+ "Report zg availability and the current project's index status (ready or not). Use to confirm zg is set up and the index is current before relying on semantic search, or to diagnose why zg_search/zg_rg return nothing. Reads pi's cached state (refreshed for this call) and does not spawn a separate `zg` subprocess. For full index detail/coverage, humans can use `/zg-status`.",
406
+ promptSnippet: "Check zg availability and index status",
407
+ parameters: Type.Object({}),
408
+ async execute(_toolCallId, _params, signal, _onUpdate, ctx) {
409
+ if (!state.checked) await refreshZgState(pi, ctx, state, signal);
410
+ if (!state.available) {
411
+ throw new Error("`zg` is not available on PATH. Install @zvec/zvec-grep separately before checking status.");
412
+ }
413
+
414
+ await refreshZgState(pi, ctx, state, signal);
415
+ const index = state.indexed ? "index: ready" : "index: not ready";
416
+ return {
417
+ content: [
418
+ {
419
+ type: "text",
420
+ text: [
421
+ `zg: ${state.version || "available"}`,
422
+ index,
423
+ ].join("\n"),
424
+ },
425
+ ],
426
+ details: {
427
+ available: true,
428
+ version: state.version,
429
+ indexed: state.indexed,
430
+ },
431
+ };
432
+ },
433
+ });
434
+
435
+ pi.registerCommand("zg-settings", {
436
+ description: "Configure zg embedding model, device, and provider credentials",
437
+ handler: async (_args, ctx) => {
438
+ await openZgSettings(pi, ctx, state);
439
+ },
440
+ });
441
+
344
442
  pi.registerCommand("zg-status", {
345
- description: "Report zg version, server, and index status for this project",
443
+ description: "Report zg version and index status for this project",
346
444
  handler: async (_args, ctx) => {
347
445
  await refreshZgState(pi, ctx, state);
348
446
  if (!state.available) {
@@ -353,7 +451,6 @@ export default function (pi: ExtensionAPI) {
353
451
  const detail = await execZg(pi, ["status"], ctx);
354
452
  const lines = [
355
453
  `zg: ${state.version || "available"}`,
356
- `server: ${state.serverRunning ? "running" : "stopped"}`,
357
454
  "",
358
455
  (detail.stdout || detail.stderr).trim(),
359
456
  ];
@@ -378,7 +475,7 @@ export default function (pi: ExtensionAPI) {
378
475
  if (!confirmed) return;
379
476
  }
380
477
 
381
- const cmdArgs = ["index"];
478
+ const cmdArgs = ["index", "--mode", "direct"];
382
479
  if (drop) cmdArgs.push("--drop", "--yes");
383
480
  else if (rebuild) cmdArgs.push("--rebuild");
384
481
 
@@ -395,34 +492,4 @@ export default function (pi: ExtensionAPI) {
395
492
  },
396
493
  });
397
494
 
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
495
  }
package/package.json CHANGED
@@ -1,9 +1,16 @@
1
1
  {
2
2
  "name": "@krosskinetic/pi-zg",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Pi extension for zvec-grep (zg): semantic code search, managed ripgrep, and shared-server-aware index management",
5
5
  "type": "module",
6
- "keywords": ["pi-package", "pi", "pi-coding-agent", "zvec-grep", "semantic-search", "code-search"],
6
+ "keywords": [
7
+ "pi-package",
8
+ "pi",
9
+ "pi-coding-agent",
10
+ "zvec-grep",
11
+ "semantic-search",
12
+ "code-search"
13
+ ],
7
14
  "license": "MIT",
8
15
  "author": "KrossKinetic",
9
16
  "repository": {
@@ -13,9 +20,15 @@
13
20
  "homepage": "https://github.com/KrossKinetic/pi-zg#readme",
14
21
  "bugs": "https://github.com/KrossKinetic/pi-zg/issues",
15
22
  "pi": {
16
- "extensions": ["./extensions"]
23
+ "extensions": [
24
+ "./extensions"
25
+ ]
17
26
  },
18
- "files": ["extensions", "README.md", "LICENSE"],
27
+ "files": [
28
+ "extensions",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
19
32
  "peerDependencies": {
20
33
  "@earendil-works/pi-coding-agent": "*",
21
34
  "typebox": "*"