pi-weave 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-weave",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "An agent-native knowledge workspace for your life and your code. Smart notepad + repository exploration, readable by humans and agents alike.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: weave-notepad
3
- description: Take and retrieve durable notes in the pi-weave vault. Use when the user asks to remember something or to start/add to a note (aliases: notes, ai note, note-taking, note-taker), or when answering questions about past decisions, people, or projects. Also handles interview note-taking where raw dictations are appended AND expanded.
3
+ description: "Take and retrieve durable notes in the pi-weave vault. Use when the user asks to remember something or to start/add to a note (aliases: notes, ai note, note-taking, note-taker), or when answering questions about past decisions, people, or projects. Also handles interview note-taking where raw dictations are appended AND expanded."
4
4
  ---
5
5
 
6
6
  # Weave Notepad
package/src/pi/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
1
+ import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import {
3
3
  buildRepoIndex,
4
4
  findGitRoot,
@@ -32,6 +32,32 @@ export default function piWeave(pi: ExtensionAPI): void {
32
32
  // Session-scoped viewer: lazy start on first /weave-view, never from the
33
33
  // factory (extension rules); idempotent stop on session_shutdown.
34
34
  let viewer: ViewerServer | null = null;
35
+ let lastCtx: ExtensionContext | ExtensionCommandContext | null = null;
36
+ let lastStatusText: string | undefined = undefined;
37
+ let isActive = false;
38
+
39
+ function updateStatus(ctx?: ExtensionContext | ExtensionCommandContext, text?: string): void {
40
+ if (ctx) lastCtx = ctx;
41
+ const c = ctx || lastCtx;
42
+ if (!c?.ui?.setStatus) return;
43
+ if (text !== undefined) {
44
+ lastStatusText = text;
45
+ }
46
+ if (!lastStatusText) {
47
+ c.ui.setStatus("weave", undefined);
48
+ return;
49
+ }
50
+ let theme: { fg?: (slot: string, text: string) => string } | undefined;
51
+ try {
52
+ theme = (c.ui as unknown as { theme?: { fg?: (slot: string, text: string) => string } })?.theme;
53
+ } catch {
54
+ // ignore
55
+ }
56
+ const indicator = (isActive || inFlightDeepScans.size > 0)
57
+ ? (theme?.fg ? theme.fg("accent", "●") : "●")
58
+ : (theme?.fg ? theme.fg("dim", "○") : "○");
59
+ c.ui.setStatus("weave", `${indicator} ${lastStatusText}`);
60
+ }
35
61
 
36
62
  pi.on("session_shutdown", async () => {
37
63
  const server = viewer;
@@ -39,9 +65,19 @@ export default function piWeave(pi: ExtensionAPI): void {
39
65
  await server?.stop();
40
66
  });
41
67
 
68
+ pi.on("agent_start", async (_event, ctx) => {
69
+ isActive = true;
70
+ updateStatus(ctx);
71
+ });
72
+
73
+ pi.on("agent_end", async (_event, ctx) => {
74
+ isActive = false;
75
+ updateStatus(ctx);
76
+ });
77
+
42
78
  pi.on("session_start", async (_event, ctx) => {
43
79
  const status = await getWorkspaceStatus(ctx.cwd);
44
- ctx.ui.setStatus("weave", formatStatusLine(status));
80
+ updateStatus(ctx, formatStatusLine(status));
45
81
 
46
82
  if (!ctx.hasUI) return;
47
83
  const repo = status.repository;
@@ -105,13 +141,13 @@ export default function piWeave(pi: ExtensionAPI): void {
105
141
  // Compute the settled status here (no git-lock contention) and let
106
142
  // the background scan restore it when it finishes.
107
143
  const status = await getWorkspaceStatus(ctx.cwd);
108
- startDeepScan(root, ctx, status);
144
+ startDeepScan(root, ctx, status, updateStatus);
109
145
  }
110
146
  return; // the background scan owns the status line until it settles
111
147
  }
112
148
 
113
149
  const status = await getWorkspaceStatus(ctx.cwd);
114
- ctx.ui.setStatus("weave", formatStatusLine(status));
150
+ updateStatus(ctx, formatStatusLine(status));
115
151
  },
116
152
  });
117
153
 
@@ -156,15 +192,26 @@ export async function deepScanDone(root: string): Promise<void | undefined> {
156
192
  * cancellation is reported via a notification. `baseStatus` is the workspace
157
193
  * status captured before the scan and restored when it settles.
158
194
  */
159
- function startDeepScan(root: string, ctx: ExtensionCommandContext, baseStatus: WorkspaceStatus): void {
195
+ function startDeepScan(
196
+ root: string,
197
+ ctx: ExtensionCommandContext,
198
+ baseStatus: WorkspaceStatus,
199
+ updateStatus: (ctx?: ExtensionContext | ExtensionCommandContext, text?: string) => void,
200
+ ): void {
160
201
  const controller = new AbortController();
161
- const done = (async () => {
202
+ let doneResolve: () => void;
203
+ const done = new Promise<void>((resolve) => {
204
+ doneResolve = resolve;
205
+ });
206
+ inFlightDeepScans.set(root, { controller, done });
207
+
208
+ void (async () => {
162
209
  try {
163
- ctx.ui.setStatus("weave", "🧵 deep scan: starting…");
210
+ updateStatus(ctx, "🧵 deep scan: starting…");
164
211
  const outcome = await deepScanRepository(root, ctx, {
165
212
  onProgress: ({ current, total, path }) => {
166
213
  const pct = total > 0 ? Math.round((current / total) * 100) : 100;
167
- ctx.ui.setStatus("weave", `🧵 deep scan: ${current}/${total} (${pct}%) — ${path}`);
214
+ updateStatus(ctx, `🧵 deep scan: ${current}/${total} (${pct}%) — ${path}`);
168
215
  },
169
216
  signal: controller.signal,
170
217
  });
@@ -183,9 +230,9 @@ function startDeepScan(root: string, ctx: ExtensionCommandContext, baseStatus: W
183
230
  } finally {
184
231
  // Restore the settled status before removing the map entry, so a caller
185
232
  // awaiting deepScanDone() observes the settled status line.
186
- ctx.ui.setStatus("weave", formatStatusLine(baseStatus));
187
233
  inFlightDeepScans.delete(root);
234
+ updateStatus(ctx, formatStatusLine(baseStatus));
235
+ doneResolve!();
188
236
  }
189
237
  })();
190
- inFlightDeepScans.set(root, { controller, done });
191
238
  }
@@ -60,7 +60,14 @@ export async function runWeaveViewTui(ctx: ExtensionCommandContext): Promise<voi
60
60
 
61
61
  // Refresh the status line after close (a /weave-scan may have landed meanwhile).
62
62
  const status = await getWorkspaceStatus(ctx.cwd);
63
- ctx.ui.setStatus("weave", formatStatusLine(status));
63
+ let theme: { fg?: (slot: string, text: string) => string } | undefined;
64
+ try {
65
+ theme = (ctx.ui as unknown as { theme?: { fg?: (slot: string, text: string) => string } })?.theme;
66
+ } catch {
67
+ // ignore
68
+ }
69
+ const indicator = theme?.fg ? theme.fg("dim", "○") : "○";
70
+ ctx.ui.setStatus("weave", `${indicator} ${formatStatusLine(status)}`);
64
71
  }
65
72
 
66
73
  /** Test seam: build the model the explorer opens with, without a terminal. */