@nklisch/pi-enhanced 0.2.0 → 0.2.1

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 (64) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/node_modules/@nklisch/pi-background-tasks/CHANGELOG.md +7 -0
  3. package/node_modules/@nklisch/pi-background-tasks/extensions/background-tasks.test.ts +105 -0
  4. package/node_modules/@nklisch/pi-background-tasks/extensions/background-tasks.ts +131 -44
  5. package/node_modules/@nklisch/pi-background-tasks/package.json +1 -1
  6. package/node_modules/@nklisch/pi-background-tasks/skills/background-tasks/SKILL.md +6 -7
  7. package/node_modules/@nklisch/pi-clearance/native/clearance-core.win32-x64-msvc.node +0 -0
  8. package/node_modules/@nklisch/pi-clearance/package.json +1 -1
  9. package/node_modules/@nklisch/pi-clearance/src/config/config-command-writer.ts +34 -17
  10. package/node_modules/@nklisch/pi-clearance/src/index.ts +34 -3
  11. package/node_modules/@nklisch/pi-clearance/src/packs/package-registration.ts +63 -36
  12. package/node_modules/@nklisch/pi-clearance/src/runtime/allow-request-message.ts +40 -1
  13. package/node_modules/@nklisch/pi-clearance/src/runtime/command-registry.ts +22 -2
  14. package/node_modules/@nklisch/pi-clearance/src/runtime/command-transforms.ts +50 -29
  15. package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/native-ui.ts +233 -49
  16. package/node_modules/@nklisch/pi-clearance/src/runtime/policy-cache.ts +19 -5
  17. package/node_modules/@nklisch/pi-conveniences/extensions/context-window-footer.ts +48 -13
  18. package/node_modules/@nklisch/pi-conveniences/package.json +1 -1
  19. package/node_modules/@nklisch/pi-fff-compat/extensions/fff-compat-search.ts +49 -42
  20. package/node_modules/@nklisch/pi-fff-compat/extensions/finder-lifecycle.ts +92 -0
  21. package/node_modules/@nklisch/pi-fff-compat/package.json +1 -1
  22. package/node_modules/@nklisch/pi-model-modes/package.json +1 -1
  23. package/node_modules/@nklisch/pi-model-modes/src/command-message.ts +30 -0
  24. package/node_modules/@nklisch/pi-model-modes/src/commands.ts +31 -15
  25. package/node_modules/@nklisch/pi-model-modes/src/style-command.ts +25 -14
  26. package/node_modules/@nklisch/pi-plugins/README.md +2 -2
  27. package/node_modules/@nklisch/pi-plugins/dist/application/subagent-hook-runtime.js +4 -1
  28. package/node_modules/@nklisch/pi-plugins/dist/application/subagent-hook-runtime.js.map +1 -1
  29. package/node_modules/@nklisch/pi-plugins/dist/composition/background-update-coordinator.js +12 -3
  30. package/node_modules/@nklisch/pi-plugins/dist/composition/background-update-coordinator.js.map +1 -1
  31. package/node_modules/@nklisch/pi-plugins/dist/infrastructure/process/command-runner.d.ts +1 -0
  32. package/node_modules/@nklisch/pi-plugins/dist/infrastructure/process/command-runner.js +19 -11
  33. package/node_modules/@nklisch/pi-plugins/dist/infrastructure/process/command-runner.js.map +1 -1
  34. package/node_modules/@nklisch/pi-plugins/dist/pi/hooks/pi-hook-decision-adapter.js +36 -7
  35. package/node_modules/@nklisch/pi-plugins/dist/pi/hooks/pi-hook-decision-adapter.js.map +1 -1
  36. package/node_modules/@nklisch/pi-plugins/dist/pi/manager/plugin-manager-component.js +14 -3
  37. package/node_modules/@nklisch/pi-plugins/dist/pi/manager/plugin-manager-component.js.map +1 -1
  38. package/node_modules/@nklisch/pi-plugins/dist/pi/manager/plugin-manager-session.js +153 -54
  39. package/node_modules/@nklisch/pi-plugins/dist/pi/manager/plugin-manager-session.js.map +1 -1
  40. package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager-lifecycle.js +35 -8
  41. package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager-lifecycle.js.map +1 -1
  42. package/node_modules/@nklisch/pi-plugins/dist/runtime/mcp/pi-mcp-adapter-package.js +1 -1
  43. package/node_modules/@nklisch/pi-plugins/dist/runtime/mcp/pi-mcp-adapter-runtime.js +1 -1
  44. package/node_modules/@nklisch/pi-plugins/dist/runtime/subagents/pi-subagents-package.js +1 -1
  45. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/CHANGELOG.md +7 -0
  46. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/package.json +1 -1
  47. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/custom-agents.ts +22 -17
  48. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/debug.ts +18 -0
  49. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/child-lifecycle.ts +22 -4
  50. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/concurrency-limiter.ts +32 -8
  51. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/create-subagent-session.ts +8 -7
  52. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/lifecycle-interceptor.ts +25 -6
  53. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/run-listeners.ts +6 -2
  54. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-manager.ts +31 -16
  55. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-session.ts +70 -32
  56. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent.ts +55 -50
  57. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/workspace-bracket.ts +6 -2
  58. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/record-observer.ts +37 -34
  59. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/subagent-events-observer.ts +15 -14
  60. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/foreground-runner.ts +31 -26
  61. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/agent-widget.ts +51 -26
  62. package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigator.ts +100 -46
  63. package/node_modules/@nklisch/pi-plugins/package.json +3 -3
  64. package/package.json +3 -3
@@ -61,8 +61,9 @@ export function createCachingPolicyResolver(
61
61
 
62
62
  return {
63
63
  resolve: (ctx) => {
64
- const registeredToolNames = stableToolNames(
65
- safeRegisteredToolNames(options.registeredToolNames, ctx),
64
+ const registeredToolNames = safeRegisteredToolNames(
65
+ options.registeredToolNames,
66
+ ctx,
66
67
  );
67
68
  const cacheKey = cacheKeyFor(ctx.cwd, registeredToolNames);
68
69
  const cached = cache.get(cacheKey);
@@ -185,7 +186,17 @@ async function attachNativePolicy(
185
186
  }
186
187
 
187
188
  function freeResolvedNativePolicy(result: PolicyResolverResult): void {
188
- if (result.ok) result.policy.nativePolicy?.free();
189
+ if (!result.ok) return;
190
+ try {
191
+ result.policy.nativePolicy?.free();
192
+ } catch (error) {
193
+ // Invalidation retires cached policies on a detached promise continuation.
194
+ // A native finalizer failure is operationally important but must not become
195
+ // an unhandled rejection that terminates Pi.
196
+ console.error(
197
+ `Pi Clearance native policy cleanup failed: ${errorMessage(error)}`,
198
+ );
199
+ }
189
200
  }
190
201
 
191
202
  function composerResultToPolicyResult(
@@ -245,15 +256,18 @@ function packageRegistrationIssueWarning(
245
256
  function safeRegisteredToolNames(
246
257
  provider: ((ctx: ExtensionContext) => readonly string[]) | undefined,
247
258
  ctx: ExtensionContext,
248
- ): readonly unknown[] {
259
+ ): readonly string[] {
249
260
  if (provider === undefined) {
250
261
  return [];
251
262
  }
252
263
 
253
264
  try {
254
265
  const toolNames = provider(ctx) as readonly unknown[];
255
- return Array.isArray(toolNames) ? toolNames : [];
266
+ return Array.isArray(toolNames) ? stableToolNames(toolNames) : [];
256
267
  } catch {
268
+ // The host tool catalog is an extension-owned snapshot boundary. A
269
+ // malformed array or throwing getter must degrade to no conditional tools,
270
+ // not escape before the resolver's structured failure path is attached.
257
271
  return [];
258
272
  }
259
273
  }
@@ -268,9 +268,10 @@ function installFooter(ctx: ExtensionContext, pi: ExtensionAPI): void {
268
268
  dispose: unsubscribe,
269
269
  invalidate() {},
270
270
  render(width: number): string[] {
271
- if (width <= 0) return [""];
271
+ try {
272
+ if (width <= 0) return [""];
272
273
 
273
- const model = formatModelName(ctx.model?.id);
274
+ const model = formatModelName(ctx.model?.id);
274
275
  const modelLabel = formatModelLabel(theme, model, pi.getThinkingLevel());
275
276
  const branch = footerData.getGitBranch();
276
277
  const branchLabel = branch ? `git ${branch}` : "no git";
@@ -331,13 +332,21 @@ function installFooter(ctx: ExtensionContext, pi: ExtensionAPI): void {
331
332
  return [formatFooterLine(width, leftCompact, rightCompact)];
332
333
  }
333
334
 
334
- return [
335
- truncateToWidth(
336
- [theme.fg("accent", "◆"), modelLabel, rightCompact].join(" "),
337
- width,
338
- "",
339
- ),
340
- ];
335
+ return [
336
+ truncateToWidth(
337
+ [theme.fg("accent", "◆"), modelLabel, rightCompact].join(" "),
338
+ width,
339
+ "",
340
+ ),
341
+ ];
342
+ } catch (error) {
343
+ // Pi may request one final render while a replaced session tears its
344
+ // footer down. A rendering failure degrades this cosmetic surface.
345
+ logOperationalError(
346
+ `[context-window-footer] render failed: ${describeError(error)}`,
347
+ );
348
+ return [truncateToWidth("context footer unavailable", Math.max(0, width), "")];
349
+ }
341
350
  },
342
351
  };
343
352
  });
@@ -352,6 +361,22 @@ function clearFooter(ctx: ExtensionContext): void {
352
361
  footerInstalled = false;
353
362
  }
354
363
 
364
+ function describeError(error: unknown): string {
365
+ try {
366
+ return error instanceof Error ? error.message : String(error);
367
+ } catch {
368
+ return "unprintable error";
369
+ }
370
+ }
371
+
372
+ function logOperationalError(message: string): void {
373
+ try {
374
+ console.error(message);
375
+ } catch {
376
+ // stderr can be unavailable during process teardown.
377
+ }
378
+ }
379
+
355
380
  function scheduleInstallFooter(ctx: ExtensionContext, pi: ExtensionAPI): void {
356
381
  if (!ctx.hasUI || !enabled) return;
357
382
 
@@ -366,10 +391,20 @@ function scheduleInstallFooter(ctx: ExtensionContext, pi: ExtensionAPI): void {
366
391
  try {
367
392
  installFooter(ctx, pi);
368
393
  } catch (error) {
369
- // A reload/session switch can stale the captured context between scheduling
370
- // and execution. Ignore that narrow race; the next session_start reapplies.
371
- if (!(error instanceof Error && error.message.includes("stale after session replacement"))) {
372
- throw error;
394
+ // Timer callbacks run outside Pi's awaited extension boundary. A stale
395
+ // context is expected during replacement; every other operational
396
+ // failure is diagnostic, but none may escape and terminate Pi.
397
+ const message = describeError(error);
398
+ if (!message.includes("stale after session replacement")) {
399
+ clearPendingTimers();
400
+ logOperationalError(`[context-window-footer] install failed: ${message}`);
401
+ try {
402
+ ctx.ui.notify(`Context footer could not be installed: ${message}`, "error");
403
+ } catch (notifyError) {
404
+ logOperationalError(
405
+ `[context-window-footer] error notification failed: ${describeError(notifyError)}`,
406
+ );
407
+ }
373
408
  }
374
409
  }
375
410
  }, delayMs);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nklisch/pi-conveniences",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Small drop-in quality-of-life conveniences for Pi — /exit, .agents/AGENTS.md context loading, context-window footer, and subagent model listing.",
5
5
  "author": {
6
6
  "name": "nklisch"
@@ -26,6 +26,7 @@ import { statSync } from "node:fs";
26
26
  import path from "node:path";
27
27
  import { Type } from "@earendil-works/pi-ai";
28
28
  import { type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
29
+ import { createGenerationGuardedFinderLifecycle } from "./finder-lifecycle.js";
29
30
 
30
31
  const EXTENSION_NAME = "pi-fff-compat";
31
32
  const PACKAGE_HINT = "bundled dependency of @nklisch/pi-fff-compat";
@@ -154,9 +155,6 @@ type Truncation = {
154
155
  };
155
156
 
156
157
  let fffModulePromise: Promise<FffModule> | null = null;
157
- let finder: FffFinder | null = null;
158
- let finderCwd: string | null = null;
159
- let finderPromise: { cwd: string; promise: Promise<FffFinder> } | null = null;
160
158
  let activeCwd = process.cwd();
161
159
 
162
160
  function envFlagEnabled(value: string | undefined): boolean {
@@ -195,7 +193,7 @@ function loadFffModule(): Promise<FffModule> {
195
193
  if (!fffModulePromise) {
196
194
  fffModulePromise = (async () => {
197
195
  try {
198
- return (await import("@ff-labs/fff-node")) as FffModule;
196
+ return (await import("@ff-labs/fff-node")) as unknown as FffModule;
199
197
  } catch (error) {
200
198
  throw new Error(
201
199
  `Failed to load @ff-labs/fff-node (${PACKAGE_HINT}): ${error instanceof Error ? error.message : String(error)}`,
@@ -206,44 +204,38 @@ function loadFffModule(): Promise<FffModule> {
206
204
  return fffModulePromise;
207
205
  }
208
206
 
209
- async function ensureFinder(cwd: string): Promise<FffFinder> {
210
- if (finder && !finder.isDestroyed && finderCwd === cwd) return finder;
211
- if (finderPromise && finderPromise.cwd === cwd) return finderPromise.promise;
212
-
213
- finderPromise = {
214
- cwd,
215
- promise: (async () => {
216
- destroyFinder();
217
- const { FileFinder } = await loadFffModule();
218
- const created = FileFinder.create({
219
- basePath: cwd,
220
- frecencyDbPath: process.env.FFF_FRECENCY_DB,
221
- historyDbPath: process.env.FFF_HISTORY_DB,
222
- aiMode: true,
223
- enableHomeDirScanning: envFlagEnabled(process.env[HOME_SCAN_ENV]),
224
- enableFsRootScanning: envFlagEnabled(process.env.FFF_ENABLE_ROOT_SCAN),
225
- disableWatch: envFlagEnabled(process.env[DISABLE_WATCH_ENV]),
226
- });
227
- if (!created.ok) throw new Error(`Failed to create FFF finder: ${created.error}`);
228
-
229
- finder = created.value;
230
- finderCwd = cwd;
231
-
232
- const scan = await finder.waitForScan(INITIAL_SCAN_WAIT_MS);
233
- if (!scan.ok) throw new Error(`FFF scan failed: ${scan.error}`);
234
- return finder;
235
- })().finally(() => {
236
- finderPromise = null;
237
- }),
238
- };
207
+ const finderLifecycle = createGenerationGuardedFinderLifecycle<FffFinder>(async (cwd) => {
208
+ const { FileFinder } = await loadFffModule();
209
+ const created = FileFinder.create({
210
+ basePath: cwd,
211
+ frecencyDbPath: process.env.FFF_FRECENCY_DB,
212
+ historyDbPath: process.env.FFF_HISTORY_DB,
213
+ aiMode: true,
214
+ enableHomeDirScanning: envFlagEnabled(process.env[HOME_SCAN_ENV]),
215
+ enableFsRootScanning: envFlagEnabled(process.env.FFF_ENABLE_ROOT_SCAN),
216
+ disableWatch: envFlagEnabled(process.env[DISABLE_WATCH_ENV]),
217
+ });
218
+ if (!created.ok) throw new Error(`Failed to create FFF finder: ${created.error}`);
239
219
 
240
- return finderPromise.promise;
241
- }
220
+ const candidate = created.value;
221
+ try {
222
+ const scan = await candidate.waitForScan(INITIAL_SCAN_WAIT_MS);
223
+ if (!scan.ok) throw new Error(`FFF scan failed: ${scan.error}`);
224
+ return candidate;
225
+ } catch (error) {
226
+ if (!candidate.isDestroyed) {
227
+ try {
228
+ candidate.destroy();
229
+ } catch {
230
+ // Preserve the scan/create failure; lifecycle cleanup is best effort.
231
+ }
232
+ }
233
+ throw error;
234
+ }
235
+ });
242
236
 
243
- function destroyFinder(): void {
244
- if (finder && !finder.isDestroyed) finder.destroy();
245
- finder = null;
246
- finderCwd = null;
237
+ function ensureFinder(cwd: string): Promise<FffFinder> {
238
+ return finderLifecycle.ensure(cwd);
247
239
  }
248
240
 
249
241
  function truncateLine(line: string): { text: string; wasTruncated: boolean } {
@@ -408,6 +400,21 @@ const findSchema = Type.Object({
408
400
  limit: Type.Optional(Type.Number({ description: `Maximum number of results (default ${DEFAULT_FIND_LIMIT})` })),
409
401
  });
410
402
 
403
+ function reportInitializationFailure(ctx: ExtensionContext, error: unknown): void {
404
+ let detail = "unknown failure";
405
+ try { detail = error instanceof Error ? error.message : String(error); }
406
+ catch { detail = "unreadable failure"; }
407
+ const message = `${EXTENSION_NAME} init failed: ${detail}`;
408
+ try {
409
+ ctx.ui.notify(message, "error");
410
+ } catch {
411
+ // Initialization can settle after session replacement. The old UI is then
412
+ // intentionally stale, so fall back to a process diagnostic without
413
+ // allowing either reporting sink to escape the awaited host boundary.
414
+ try { console.error(message); } catch { /* no safe reporting sink remains */ }
415
+ }
416
+ }
417
+
411
418
  const grepSchema = Type.Object({
412
419
  pattern: Type.String({ description: "Search pattern" }),
413
420
  path: Type.Optional(Type.String({ description: "Directory or file to search in (default: current directory)" })),
@@ -449,12 +456,12 @@ export default function fffCompatSearch(pi: ExtensionAPI) {
449
456
  try {
450
457
  await ensureFinder(activeCwd);
451
458
  } catch (error) {
452
- ctx.ui.notify(`${EXTENSION_NAME} init failed: ${error instanceof Error ? error.message : String(error)}`, "error");
459
+ reportInitializationFailure(ctx, error);
453
460
  }
454
461
  });
455
462
 
456
463
  pi.on("session_shutdown", async () => {
457
- destroyFinder();
464
+ finderLifecycle.revoke();
458
465
  });
459
466
 
460
467
  pi.registerTool({
@@ -0,0 +1,92 @@
1
+ export interface FinderLike {
2
+ readonly isDestroyed: boolean;
3
+ destroy(): void;
4
+ }
5
+
6
+ interface CurrentFinder<F extends FinderLike> {
7
+ cwd: string;
8
+ generation: number;
9
+ finder: F;
10
+ }
11
+
12
+ interface PendingFinder<F extends FinderLike> {
13
+ cwd: string;
14
+ generation: number;
15
+ promise: Promise<F>;
16
+ }
17
+
18
+ /**
19
+ * Own the asynchronous finder lifecycle separately from the Pi event seam.
20
+ * A scan can outlive session_shutdown; the generation check prevents that late
21
+ * completion from becoming the finder for a replacement session.
22
+ */
23
+ export function createGenerationGuardedFinderLifecycle<F extends FinderLike>(
24
+ createFinder: (cwd: string) => Promise<F>,
25
+ ): {
26
+ ensure(cwd: string): Promise<F>;
27
+ revoke(): void;
28
+ } {
29
+ let generation = 0;
30
+ let current: CurrentFinder<F> | null = null;
31
+ let pending: PendingFinder<F> | null = null;
32
+
33
+ function destroyQuietly(candidate: F | null): void {
34
+ if (candidate === null || candidate.isDestroyed) return;
35
+ // A stale finder has no live session context in which to report a cleanup
36
+ // failure. Do not let best-effort shutdown cleanup reject the host event.
37
+ try {
38
+ candidate.destroy();
39
+ } catch {
40
+ // The lifecycle is already revoked; there is no safe session state to
41
+ // repopulate, which is the guarantee this cleanup protects.
42
+ }
43
+ }
44
+
45
+ function revoke(): void {
46
+ generation++;
47
+ const old = current;
48
+ current = null;
49
+ destroyQuietly(old?.finder ?? null);
50
+ }
51
+
52
+ function ensure(cwd: string): Promise<F> {
53
+ if (current?.finder.isDestroyed) current = null;
54
+ if (current?.cwd === cwd) return Promise.resolve(current.finder);
55
+ if (pending?.cwd === cwd && pending.generation === generation) return pending.promise;
56
+
57
+ // A different workspace, or a new session after revocation, invalidates
58
+ // every earlier initialization. Its late result will be destroyed below.
59
+ generation++;
60
+ const requestedGeneration = generation;
61
+ const old = current;
62
+ current = null;
63
+ destroyQuietly(old?.finder ?? null);
64
+
65
+ const initialization = (async (): Promise<F> => {
66
+ let candidate: F | null = null;
67
+ try {
68
+ candidate = await createFinder(cwd);
69
+ if (requestedGeneration !== generation) {
70
+ throw new Error("FFF finder initialization was revoked");
71
+ }
72
+ current = { cwd, generation: requestedGeneration, finder: candidate };
73
+ return candidate;
74
+ } catch (error) {
75
+ // If creation itself fails after allocating a finder, the factory owns
76
+ // cleanup. A completed-but-invalidated candidate is closed exactly once
77
+ // here, before its rejected promise reaches the old session callback.
78
+ if (candidate !== null && current?.finder !== candidate) destroyQuietly(candidate);
79
+ throw error;
80
+ }
81
+ })();
82
+
83
+ let guardedPromise!: Promise<F>;
84
+ guardedPromise = initialization.finally(() => {
85
+ if (pending?.promise === guardedPromise) pending = null;
86
+ });
87
+ pending = { cwd, generation: requestedGeneration, promise: guardedPromise };
88
+ return guardedPromise;
89
+ }
90
+
91
+ return { ensure, revoke };
92
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nklisch/pi-fff-compat",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Fast FFF-backed file search through Pi-native find/grep semantics — glob-only file lookup and exact regex/literal grep with no fuzzy fallback.",
5
5
  "author": {
6
6
  "name": "nklisch"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nklisch/pi-model-modes",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "A pi extension that adapts the system prompt per model/mode.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -0,0 +1,30 @@
1
+ import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
+
3
+ /**
4
+ * Send a display-only command panel without allowing a runtime Promise return
5
+ * from pi.sendMessage to become an unhandled rejection. The published type is
6
+ * void, but newer hosts may return a Promise while session replacement or a
7
+ * stale command context is being detected.
8
+ */
9
+ export async function sendCommandMessageSafely(
10
+ pi: Pick<ExtensionAPI, "sendMessage">,
11
+ ctx: Pick<ExtensionCommandContext, "ui">,
12
+ message: Parameters<ExtensionAPI["sendMessage"]>[0],
13
+ surface: string,
14
+ ): Promise<void> {
15
+ try {
16
+ await Promise.resolve(pi.sendMessage(message));
17
+ } catch (error) {
18
+ // The command context can be stale too, so notification is best effort.
19
+ // The send failure has already been consumed; neither path may escape as
20
+ // an unhandled rejection or replace the command's primary outcome.
21
+ try {
22
+ ctx.ui.notify(
23
+ `${surface}: status panel unavailable (${error instanceof Error ? error.message : String(error)})`,
24
+ "error",
25
+ );
26
+ } catch {
27
+ // A stale UI context has no safe recovery channel at this boundary.
28
+ }
29
+ }
30
+ }
@@ -26,6 +26,7 @@ import {
26
26
  } from "./autocomplete.js";
27
27
  import { assembleForInspect, getLastBaseSystemPrompt } from "./handler.js";
28
28
  import { parseScalarDefaultArgs } from "./command-parse-utils.js";
29
+ import { sendCommandMessageSafely } from "./command-message.js";
29
30
  import {
30
31
  writeDefaultToConfig,
31
32
  readDefaultSources,
@@ -427,11 +428,16 @@ export function registerModeCommand(pi: ExtensionAPI): void {
427
428
  modeError = (err as Error).message;
428
429
  }
429
430
  const presets = listPresetNames();
430
- pi.sendMessage({
431
- customType: MODE_LISTING_MESSAGE_TYPE,
432
- content: formatModeListing(source, specName, mode, modeError, presets),
433
- display: true,
434
- });
431
+ await sendCommandMessageSafely(
432
+ pi,
433
+ ctx,
434
+ {
435
+ customType: MODE_LISTING_MESSAGE_TYPE,
436
+ content: formatModeListing(source, specName, mode, modeError, presets),
437
+ display: true,
438
+ },
439
+ "/mode",
440
+ );
435
441
  return;
436
442
  }
437
443
 
@@ -446,11 +452,16 @@ export function registerModeCommand(pi: ExtensionAPI): void {
446
452
  if (parsed.kind === "display") {
447
453
  const sources = readDefaultSources(ctx.cwd);
448
454
  const effective = effectiveDefaultSource(ctx.cwd);
449
- pi.sendMessage({
450
- customType: MODE_DEFAULT_MESSAGE_TYPE,
451
- content: formatDefaultListing(sources.global, sources.project, effective),
452
- display: true,
453
- });
455
+ await sendCommandMessageSafely(
456
+ pi,
457
+ ctx,
458
+ {
459
+ customType: MODE_DEFAULT_MESSAGE_TYPE,
460
+ content: formatDefaultListing(sources.global, sources.project, effective),
461
+ display: true,
462
+ },
463
+ "/mode default",
464
+ );
454
465
  return;
455
466
  }
456
467
 
@@ -622,11 +633,16 @@ export function registerModeInspectCommand(pi: ExtensionAPI): void {
622
633
  styleInfo,
623
634
  assembledPrompt,
624
635
  );
625
- pi.sendMessage({
626
- customType: MODE_INSPECT_MESSAGE_TYPE,
627
- content,
628
- display: true,
629
- });
636
+ await sendCommandMessageSafely(
637
+ pi,
638
+ ctx,
639
+ {
640
+ customType: MODE_INSPECT_MESSAGE_TYPE,
641
+ content,
642
+ display: true,
643
+ },
644
+ "/mode:inspect",
645
+ );
630
646
  },
631
647
  });
632
648
  }
@@ -1,5 +1,6 @@
1
1
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
2
  import { parseScalarDefaultArgs } from "./command-parse-utils.js";
3
+ import { sendCommandMessageSafely } from "./command-message.js";
3
4
  import {
4
5
  DEFAULT_OFF,
5
6
  effectiveStyleDefaultSource,
@@ -166,11 +167,16 @@ export function registerStyleCommand(pi: ExtensionAPI): void {
166
167
  } catch (cause) {
167
168
  if (!("error" in effective)) effective = { error: (cause as Error).message };
168
169
  }
169
- pi.sendMessage({
170
- customType: STYLE_LISTING_MESSAGE_TYPE,
171
- content: formatStyleListing(effective, styles),
172
- display: true,
173
- });
170
+ await sendCommandMessageSafely(
171
+ pi,
172
+ ctx,
173
+ {
174
+ customType: STYLE_LISTING_MESSAGE_TYPE,
175
+ content: formatStyleListing(effective, styles),
176
+ display: true,
177
+ },
178
+ "/style",
179
+ );
174
180
  return;
175
181
  }
176
182
 
@@ -182,15 +188,20 @@ export function registerStyleCommand(pi: ExtensionAPI): void {
182
188
  }
183
189
  if (parsed.kind === "display") {
184
190
  const sources = readStyleDefaultSources(ctx.cwd);
185
- pi.sendMessage({
186
- customType: STYLE_DEFAULT_MESSAGE_TYPE,
187
- content: formatStyleDefaultListing(
188
- sources.global,
189
- sources.project,
190
- effectiveStyleDefaultSource(ctx.cwd),
191
- ),
192
- display: true,
193
- });
191
+ await sendCommandMessageSafely(
192
+ pi,
193
+ ctx,
194
+ {
195
+ customType: STYLE_DEFAULT_MESSAGE_TYPE,
196
+ content: formatStyleDefaultListing(
197
+ sources.global,
198
+ sources.project,
199
+ effectiveStyleDefaultSource(ctx.cwd),
200
+ ),
201
+ display: true,
202
+ },
203
+ "/style default",
204
+ );
194
205
  return;
195
206
  }
196
207
 
@@ -61,8 +61,8 @@ Marketplace-derived network access is origin-authorized and DNS-pinned. Credenti
61
61
 
62
62
  The current production package pins:
63
63
 
64
- - `@nklisch/pi-mcp-adapter@2.20.1-nklisch.1`
65
- - `@nklisch/pi-subagents@18.1.0-nklisch.1`
64
+ - `@nklisch/pi-mcp-adapter@2.21.0-nklisch.1`
65
+ - `@nklisch/pi-subagents@18.1.0-nklisch.2`
66
66
 
67
67
  Executable dependencies are checked against their declared package shape before import: exact name and version, license, engine and peer ranges, required exports, and declared Pi resources. The MCP and subagent packages are transitive dependencies: one top-level `pi install npm:@nklisch/pi-plugins` installs and activates both through verified wrappers, so they do not need separate `pi install` entries. The bundled subagent loader reuses Pi's already-loaded coding-agent, AI, and TUI module identities rather than installing a second Pi runtime tree. Package, API, runtime-range, or behavioral drift makes the affected capability unavailable rather than partially activating it. Subagent lifecycle conformance remains a separate qualification contract.
68
68
 
@@ -71,7 +71,10 @@ export async function registerSubagentHookRuntime(input) {
71
71
  return disposePromise;
72
72
  };
73
73
  const onRuntimeAbort = () => {
74
- void dispose();
74
+ // Abort dispatch is synchronous and detached from the caller. The explicit
75
+ // dispose() API still reports this failure, while shutdown must consume the
76
+ // rejection here so a provider cleanup error cannot become unhandled.
77
+ void dispose().catch(() => undefined);
75
78
  };
76
79
  input.runtimeSignal.addEventListener("abort", onRuntimeAbort, { once: true });
77
80
  let evidence;
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-hook-runtime.js","sourceRoot":"","sources":["../../src/application/subagent-hook-runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subagent-hook-runtime.js","sourceRoot":"","sources":["../../src/application/subagent-hook-runtime.ts"],"names":[],"mappings":"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"}
@@ -62,11 +62,20 @@ export function createBackgroundUpdateCoordinator(dependencies) {
62
62
  const ownedController = controller;
63
63
  // Deliberately do not await this task: local startup is complete before
64
64
  // any notification publisher, marketplace adapter, or timer participates.
65
- task = dependencies.scheduler.run(ownedController.signal, maintain).catch((error) => {
65
+ // Scheduler adapters are foreign operational boundaries and may throw
66
+ // before returning a promise; normalize both sync throws and rejections
67
+ // into degraded status so detached startup can never reject into Node.
68
+ try {
69
+ task = Promise.resolve(dependencies.scheduler.run(ownedController.signal, maintain)).catch(() => {
70
+ if (!ownedController.signal.aborted)
71
+ dependencies.schedulerStatus?.degrade();
72
+ });
73
+ }
74
+ catch {
66
75
  if (!ownedController.signal.aborted)
67
76
  dependencies.schedulerStatus?.degrade();
68
- void error;
69
- });
77
+ task = Promise.resolve();
78
+ }
70
79
  },
71
80
  wake() {
72
81
  if (closePromise === undefined)
@@ -1 +1 @@
1
- {"version":3,"file":"background-update-coordinator.js","sourceRoot":"","sources":["../../src/composition/background-update-coordinator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"background-update-coordinator.js","sourceRoot":"","sources":["../../src/composition/background-update-coordinator.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ export declare class CommandRunnerError extends Error {
9
9
  }
10
10
  type RunnerOptions = Readonly<{
11
11
  killGraceMs?: number;
12
+ platform?: NodeJS.Platform;
12
13
  }>;
13
14
  /**
14
15
  * The single Node process primitive. Both source acquisition and hook runtime