pi-awaken 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 (2) hide show
  1. package/index.ts +26 -10
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -22,7 +22,7 @@ const sleep = (ms: number) => new Promise((done) => setTimeout(done, ms));
22
22
 
23
23
  function installCli() {
24
24
  const target = join(agentBin(), "pi-wake");
25
- const shim = `#!/bin/sh\nexec node "${cliPath}" "$@"\n`;
25
+ const shim = `#!/bin/sh\nexec "${process.execPath}" "${cliPath}" "$@"\n`;
26
26
  try {
27
27
  if (existsSync(target) && readFileSync(target, "utf8") === shim) return;
28
28
  mkdirSync(agentBin(), { recursive: true });
@@ -93,29 +93,40 @@ export default function (pi: ExtensionAPI) {
93
93
  if (queued.has(wake.key)) return;
94
94
  queued.add(wake.key);
95
95
  queue.push(wake);
96
- flushTimer ??= setTimeout(flush, FLUSH_MS);
96
+ flushTimer ??= setTimeout(() => guarded(flush), FLUSH_MS);
97
97
  };
98
98
 
99
+ function guarded(fn: () => void) {
100
+ try {
101
+ fn();
102
+ } catch (error) {
103
+ if (error instanceof Error && error.message.includes("ctx is stale")) shutdown();
104
+ else throw error;
105
+ }
106
+ }
107
+
99
108
  function flush() {
100
109
  flushTimer = undefined;
101
110
  const s = store;
102
111
  const items = queue.splice(0);
103
112
  if (!s || !items.length) return;
104
- const body = items.map(renderWake).join("\n\n");
105
- const title = items.length > 1 ? `[pi-wake] ${items.length} background events` : "[pi-wake]";
113
+ const fresh = items.filter((item) => item.kind !== "exit" || !s.get(item.job.id)?.delivered);
114
+ for (const item of items) queued.delete(item.key);
115
+ if (!fresh.length) return;
116
+ const body = fresh.map(renderWake).join("\n\n");
117
+ const title = fresh.length > 1 ? `[pi-wake] ${fresh.length} background events` : "[pi-wake]";
106
118
  pi.sendMessage(
107
119
  {
108
120
  customType: "pi-wake",
109
121
  content: `${title}\n${body}`,
110
122
  display: true,
111
- details: { events: items.map((item) => item.key) },
123
+ details: { events: fresh.map((item) => item.key) },
112
124
  },
113
125
  { triggerTurn: true, deliverAs: "steer" },
114
126
  );
115
- for (const item of items) {
127
+ for (const item of fresh) {
116
128
  if (item.kind === "exit") s.markDelivered(item.job.id);
117
129
  if (item.kind === "message") s.consume(item.message.file);
118
- queued.delete(item.key);
119
130
  }
120
131
  }
121
132
 
@@ -186,7 +197,7 @@ export default function (pi: ExtensionAPI) {
186
197
  store.ensure();
187
198
  JobStore.prune();
188
199
  installCli();
189
- pollTimer = setInterval(tick, POLL_MS);
200
+ pollTimer = setInterval(() => guarded(tick), POLL_MS);
190
201
  pollTimer.unref?.();
191
202
  tick();
192
203
  });
@@ -245,8 +256,13 @@ export default function (pi: ExtensionAPI) {
245
256
  PATH: [agentBin(), process.env.PATH ?? ""].join(delimiter),
246
257
  },
247
258
  });
248
- const early = await waitForExit(s, job.id, INLINE_WINDOW_MS, signal);
249
- if (early) return finishedResult(s, early);
259
+ busy.add(job.id);
260
+ try {
261
+ const early = await waitForExit(s, job.id, INLINE_WINDOW_MS, signal);
262
+ if (early) return finishedResult(s, early);
263
+ } finally {
264
+ busy.delete(job.id);
265
+ }
250
266
  tick();
251
267
  const text = [
252
268
  `Started ${header(job)} in the background (pid ${job.pid}).`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-awaken",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Pi extension: run long shell scripts in the background and get woken when they finish, match output, or anything calls pi-wake.",
5
5
  "type": "module",
6
6
  "keywords": [