@saifymatteo/pi-extensions 0.1.3 → 0.1.5
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/CHANGELOG.md +28 -0
- package/package.json +2 -1
- package/packages/pi-bg-bash/AGENTS.md +29 -0
- package/packages/pi-bg-bash/CHANGELOG.md +25 -0
- package/packages/pi-bg-bash/package.json +2 -1
- package/packages/pi-bg-bash/src/index.ts +189 -99
- package/packages/pi-bg-bash/src/lib/output.ts +31 -0
- package/packages/pi-bg-bash/src/lib/panel.ts +155 -0
- package/packages/pi-bg-bash/src/lib/process-control.ts +221 -0
- package/packages/pi-bg-bash/src/lib/windows-console.ts +169 -0
- package/packages/pi-bg-bash/test/job-controls.test.mjs +347 -0
- package/packages/pi-bg-bash/test/native-process-control.test.mjs +126 -0
- package/packages/pi-bg-bash/test/output.test.mjs +28 -0
- package/packages/pi-bg-bash/test/panel.test.mjs +146 -0
- package/packages/pi-bg-bash/test/process-control.test.mjs +300 -0
- package/packages/pi-bg-bash/test/windows-console.test.mjs +221 -0
- package/packages/pi-claude-usage/CHANGELOG.md +18 -0
- package/packages/pi-claude-usage/package.json +2 -1
- package/packages/pi-clipboard-image/CHANGELOG.md +18 -0
- package/packages/pi-clipboard-image/package.json +2 -1
- package/packages/pi-codeblock-borders/CHANGELOG.md +18 -0
- package/packages/pi-codeblock-borders/package.json +2 -1
- package/packages/pi-codegraph/CHANGELOG.md +25 -0
- package/packages/pi-codegraph/package.json +2 -1
- package/packages/pi-codegraph/src/index.ts +67 -27
- package/packages/pi-compact-tools/CHANGELOG.md +18 -0
- package/packages/pi-compact-tools/package.json +2 -1
- package/packages/pi-decisions/CHANGELOG.md +18 -0
- package/packages/pi-decisions/package.json +2 -1
- package/packages/pi-load-pi-dotenv/CHANGELOG.md +18 -0
- package/packages/pi-load-pi-dotenv/package.json +2 -1
- package/packages/pi-model-go/CHANGELOG.md +18 -0
- package/packages/pi-model-go/package.json +2 -1
- package/packages/pi-prestart-working/CHANGELOG.md +18 -0
- package/packages/pi-prestart-working/package.json +2 -1
- package/packages/pi-root-guard/CHANGELOG.md +18 -0
- package/packages/pi-root-guard/package.json +2 -1
- package/packages/pi-session-finder/CHANGELOG.md +18 -0
- package/packages/pi-session-finder/package.json +2 -1
- package/packages/pi-session-id/CHANGELOG.md +18 -0
- package/packages/pi-session-id/package.json +2 -1
- package/packages/pi-session-nav/CHANGELOG.md +18 -0
- package/packages/pi-session-nav/package.json +2 -1
- package/packages/pi-session-rename/CHANGELOG.md +18 -0
- package/packages/pi-session-rename/package.json +2 -1
- package/packages/pi-session-retention/AGENTS.md +15 -0
- package/packages/pi-session-retention/CHANGELOG.md +25 -0
- package/packages/pi-session-retention/package.json +2 -1
- package/packages/pi-session-retention/src/index.ts +43 -4
- package/packages/pi-session-retention/test/startup.test.mjs +229 -0
- package/packages/pi-skill-usage-log/CHANGELOG.md +18 -0
- package/packages/pi-skill-usage-log/package.json +2 -1
- package/packages/pi-tool-usage-log/CHANGELOG.md +18 -0
- package/packages/pi-tool-usage-log/package.json +2 -1
- package/packages/pi-tts/CHANGELOG.md +18 -0
- package/packages/pi-tts/package.json +2 -1
- package/packages/pi-user-image-previews/CHANGELOG.md +18 -0
- package/packages/pi-user-image-previews/package.json +2 -1
- package/packages/pi-vision/CHANGELOG.md +18 -0
- package/packages/pi-vision/package.json +2 -1
- package/packages/pi-wait/CHANGELOG.md +18 -0
- package/packages/pi-wait/package.json +2 -1
- package/packages/pi-zvec/CHANGELOG.md +25 -0
- package/packages/pi-zvec/package.json +2 -1
- package/packages/pi-zvec/src/index.ts +81 -39
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// vector → semantic-only
|
|
16
16
|
// hybrid/auto → positional hybrid query
|
|
17
17
|
// - /zvec-init /zvec-sync /zvec-status
|
|
18
|
-
// - session_start : CLI check (report once if missing), config setup,
|
|
18
|
+
// - session_start : non-blocking CLI check (report once if missing), config setup,
|
|
19
19
|
// index discovery by walking up from cwd for .zvec-grep/,
|
|
20
20
|
// startup sync when indexed, auto-index when not (bounded
|
|
21
21
|
// by home dir / filesystem root)
|
|
@@ -55,7 +55,6 @@
|
|
|
55
55
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
56
56
|
import { Type } from "typebox";
|
|
57
57
|
import { appendFileSync, existsSync, realpathSync } from "node:fs";
|
|
58
|
-
import { execSync } from "node:child_process";
|
|
59
58
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
60
59
|
import { homedir } from "node:os";
|
|
61
60
|
import * as path from "node:path";
|
|
@@ -248,19 +247,21 @@ function textResult(text: string) {
|
|
|
248
247
|
// package's JS entry once and drive it with `node` directly: no shell involved,
|
|
249
248
|
// every argument preserved verbatim.
|
|
250
249
|
let zgJsEntry: string | null | undefined;
|
|
251
|
-
function resolveZgJsEntry(): string | null {
|
|
250
|
+
async function resolveZgJsEntry(pi: ExtensionAPI, signal?: AbortSignal): Promise<string | null> {
|
|
251
|
+
signal?.throwIfAborted();
|
|
252
252
|
if (zgJsEntry !== undefined) return zgJsEntry;
|
|
253
|
-
zgJsEntry = null;
|
|
254
253
|
try {
|
|
255
|
-
const
|
|
256
|
-
encoding: "utf8",
|
|
254
|
+
const result = await pi.exec("cmd.exe", ["/d", "/s", "/c", "npm", "root", "-g"], {
|
|
257
255
|
timeout: CLI_CHECK_TIMEOUT_MS,
|
|
258
|
-
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
|
|
256
|
+
signal,
|
|
257
|
+
});
|
|
258
|
+
signal?.throwIfAborted();
|
|
259
|
+
const entry = path.join(result.stdout.trim(), "@zvec", "zvec-grep", "dist", "cli", "index.js");
|
|
260
|
+
zgJsEntry = result.code === 0 && !result.killed && existsSync(entry) ? entry : null;
|
|
262
261
|
} catch {
|
|
263
|
-
|
|
262
|
+
// Cancellation is not a missing installation and must not poison the cache.
|
|
263
|
+
signal?.throwIfAborted();
|
|
264
|
+
zgJsEntry = null;
|
|
264
265
|
}
|
|
265
266
|
return zgJsEntry;
|
|
266
267
|
}
|
|
@@ -271,11 +272,12 @@ async function execZg(
|
|
|
271
272
|
options: { signal?: AbortSignal; timeout?: number; cwd?: string } = {},
|
|
272
273
|
) {
|
|
273
274
|
if (process.platform === "win32") {
|
|
274
|
-
const entry = resolveZgJsEntry();
|
|
275
|
+
const entry = await resolveZgJsEntry(pi, options.signal);
|
|
275
276
|
if (entry) {
|
|
276
277
|
try {
|
|
277
278
|
return await pi.exec("node", [entry, ...args], options);
|
|
278
279
|
} catch {
|
|
280
|
+
options.signal?.throwIfAborted();
|
|
279
281
|
/* node missing from PATH: fall back to the shim below */
|
|
280
282
|
}
|
|
281
283
|
}
|
|
@@ -369,16 +371,26 @@ function sessionIdOf(ctx: ExtensionContext): string {
|
|
|
369
371
|
}
|
|
370
372
|
|
|
371
373
|
export default function zvec(pi: ExtensionAPI) {
|
|
372
|
-
|
|
374
|
+
let initialization: Promise<void> | null = null;
|
|
375
|
+
let cliCheck: Promise<boolean> | null = null;
|
|
376
|
+
|
|
377
|
+
// Share a cancellable probe across startup and concurrent first calls.
|
|
373
378
|
async function ensureCli(pi2: ExtensionAPI): Promise<boolean> {
|
|
374
379
|
if (cliAvailable !== null) return cliAvailable;
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
380
|
+
const gen = sessionGen;
|
|
381
|
+
const signal = runtimeAbort.signal;
|
|
382
|
+
cliCheck ??= (async () => {
|
|
383
|
+
try {
|
|
384
|
+
const r = await execZg(pi2, ["version"], { timeout: CLI_CHECK_TIMEOUT_MS, signal });
|
|
385
|
+
if (gen !== sessionGen || signal.aborted) return false;
|
|
386
|
+
cliAvailable = r.code === 0 && !r.killed;
|
|
387
|
+
} catch {
|
|
388
|
+
if (gen !== sessionGen || signal.aborted) return false;
|
|
389
|
+
cliAvailable = false;
|
|
390
|
+
}
|
|
391
|
+
return cliAvailable === true;
|
|
392
|
+
})();
|
|
393
|
+
return cliCheck;
|
|
382
394
|
}
|
|
383
395
|
|
|
384
396
|
// ── UI helpers: drop writes from a replaced session, never crash pi ───
|
|
@@ -517,7 +529,14 @@ export default function zvec(pi: ExtensionAPI) {
|
|
|
517
529
|
limit: Type.Optional(Type.Integer({ description: "Maximum results per group" })),
|
|
518
530
|
}),
|
|
519
531
|
execute: async (_toolCallId, params, signal, _onUpdate, ctx) => {
|
|
520
|
-
|
|
532
|
+
const lifecycle = runtimeAbort.signal;
|
|
533
|
+
await initialization;
|
|
534
|
+
lifecycle.throwIfAborted();
|
|
535
|
+
signal?.throwIfAborted();
|
|
536
|
+
const available = await ensureCli(pi);
|
|
537
|
+
lifecycle.throwIfAborted();
|
|
538
|
+
signal?.throwIfAborted();
|
|
539
|
+
if (!available) return textResult(INSTALL_HINT);
|
|
521
540
|
const root = params.path ? path.resolve(params.path) : (findIndexRoot(ctx.cwd) ?? ctx.cwd);
|
|
522
541
|
const mode: SearchMode = params.mode ?? "auto";
|
|
523
542
|
const args = buildSearchArgs({
|
|
@@ -582,6 +601,8 @@ export default function zvec(pi: ExtensionAPI) {
|
|
|
582
601
|
const token = indexes ? ++opSeq : 0;
|
|
583
602
|
if (token) currentOpToken = token;
|
|
584
603
|
try {
|
|
604
|
+
await initialization;
|
|
605
|
+
if (gen !== sessionGen || runtimeAbort.signal.aborted) return;
|
|
585
606
|
await command.handler(args, ctx);
|
|
586
607
|
} catch (err) {
|
|
587
608
|
reportError(ctx, gen, `Zvec command /${name} failed`, err instanceof Error ? (err.stack ?? err.message) : String(err));
|
|
@@ -686,29 +707,23 @@ export default function zvec(pi: ExtensionAPI) {
|
|
|
686
707
|
|
|
687
708
|
// ── session_start: CLI check → config → auto-index / startup sync ─────
|
|
688
709
|
// ── session_shutdown: kill in-flight zg children, invalidate UI writes ──
|
|
689
|
-
pi.on("session_shutdown", () => {
|
|
710
|
+
pi.on("session_shutdown", async () => {
|
|
690
711
|
cancelRetry();
|
|
691
712
|
runtimeAbort.abort();
|
|
692
713
|
sessionGen++;
|
|
693
714
|
currentOpToken = 0;
|
|
694
715
|
pendingSync = false;
|
|
695
716
|
latestCtx = null;
|
|
717
|
+
const pending = initialization;
|
|
718
|
+
initialization = null;
|
|
719
|
+
cliCheck = null;
|
|
720
|
+
await pending?.catch(() => {});
|
|
696
721
|
});
|
|
697
722
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
runtimeAbort = new AbortController();
|
|
701
|
-
const gen = ++sessionGen;
|
|
702
|
-
cancelRetry();
|
|
703
|
-
retriesExhausted = false;
|
|
704
|
-
state = null;
|
|
705
|
-
latestCtx = ctx;
|
|
706
|
-
currentOpToken = 0; // invalidate any op from a replaced session
|
|
707
|
-
pendingSync = false;
|
|
708
|
-
status(ctx, gen, undefined);
|
|
709
|
-
|
|
723
|
+
async function initialize(ctx: ExtensionContext, gen: number, signal: AbortSignal) {
|
|
724
|
+
if (gen !== sessionGen || signal.aborted) return;
|
|
710
725
|
if (!(await ensureCli(pi))) {
|
|
711
|
-
if (gen !== sessionGen) return;
|
|
726
|
+
if (gen !== sessionGen || signal.aborted) return;
|
|
712
727
|
if (ctx.hasUI && !notifiedMissing) {
|
|
713
728
|
notifiedMissing = true;
|
|
714
729
|
reportError(ctx, gen, INSTALL_HINT);
|
|
@@ -716,26 +731,53 @@ export default function zvec(pi: ExtensionAPI) {
|
|
|
716
731
|
return;
|
|
717
732
|
}
|
|
718
733
|
|
|
734
|
+
if (gen !== sessionGen || signal.aborted) return;
|
|
719
735
|
await ensureGlobalConfig();
|
|
736
|
+
if (gen !== sessionGen || signal.aborted) return;
|
|
720
737
|
const indexedRoot = findIndexRoot(ctx.cwd);
|
|
721
738
|
const projectRoot = indexedRoot ?? ctx.cwd;
|
|
722
|
-
const globalCfg = await
|
|
723
|
-
|
|
739
|
+
const [globalCfg, projectCfg] = await Promise.all([
|
|
740
|
+
readConfigFile(globalConfigPath()),
|
|
741
|
+
readConfigFile(path.join(projectRoot, ".pi", "zvec.json")),
|
|
742
|
+
]);
|
|
724
743
|
const config: ZvecConfig = {
|
|
725
744
|
autoInit: boolOr(projectCfg, globalCfg, "autoInit"),
|
|
726
745
|
syncOnSettle: boolOr(projectCfg, globalCfg, "syncOnSettle"),
|
|
727
746
|
embedding: embeddingOr(projectCfg, globalCfg),
|
|
728
747
|
};
|
|
729
|
-
if (gen !== sessionGen) return;
|
|
748
|
+
if (gen !== sessionGen || signal.aborted) return;
|
|
730
749
|
state = { config, projectRoot, indexed: indexedRoot !== null };
|
|
731
750
|
|
|
751
|
+
// A manual init/sync requested during setup already owns the writer slot.
|
|
752
|
+
if (currentOpToken !== 0) return;
|
|
732
753
|
if (indexedRoot !== null) {
|
|
733
754
|
await ensureIndexGitignore(indexedRoot);
|
|
734
755
|
// Startup sync on the index owner (not cwd — cwd may be a subdir).
|
|
735
|
-
if (gen === sessionGen && ctx.hasUI) spawnOp("sync", ctx, gen, projectRoot);
|
|
756
|
+
if (gen === sessionGen && !signal.aborted && currentOpToken === 0 && ctx.hasUI) spawnOp("sync", ctx, gen, projectRoot);
|
|
736
757
|
} else if (config.autoInit && ctx.hasUI && !isHomeOrRoot(ctx.cwd)) {
|
|
737
758
|
spawnOp("init", ctx, gen, ctx.cwd);
|
|
738
759
|
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
pi.on("session_start", (_event, ctx) => {
|
|
763
|
+
runtimeAbort.abort();
|
|
764
|
+
runtimeAbort = new AbortController();
|
|
765
|
+
const signal = runtimeAbort.signal;
|
|
766
|
+
const gen = ++sessionGen;
|
|
767
|
+
cancelRetry();
|
|
768
|
+
retriesExhausted = false;
|
|
769
|
+
state = null;
|
|
770
|
+
latestCtx = ctx;
|
|
771
|
+
currentOpToken = 0;
|
|
772
|
+
pendingSync = false;
|
|
773
|
+
cliCheck = null;
|
|
774
|
+
status(ctx, gen, undefined);
|
|
775
|
+
|
|
776
|
+
// Startup never waits; early tool/command calls share this setup promise.
|
|
777
|
+
initialization = Promise.resolve().then(() => initialize(ctx, gen, signal));
|
|
778
|
+
void initialization.catch((error) => {
|
|
779
|
+
if (!signal.aborted) reportError(ctx, gen, "Zvec startup failed", error instanceof Error ? error.message : String(error));
|
|
780
|
+
});
|
|
739
781
|
});
|
|
740
782
|
|
|
741
783
|
// ── agent_settled: single-flight incremental index after each turn ────
|