@pi-unipi/background-tasks 2.12.0 → 2.13.0

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/README.md CHANGED
@@ -74,6 +74,22 @@ subscription OAuth attribution, exact-match system-prompt sanitization, and
74
74
  cache-retention policy for Anthropic routes. Duplicate installed copies resolve
75
75
  ownership through an EventBus claim; later copies go inert.
76
76
 
77
+ ## Shared registry (for sibling extensions)
78
+
79
+ Other packages can read the live task registry synchronously — no events, no polling:
80
+
81
+ ```ts
82
+ import { getSharedTaskRegistry } from "@pi-unipi/background-tasks";
83
+
84
+ const tasks = getSharedTaskRegistry()?.allTasks() ?? [];
85
+ const running = tasks.filter((t) => t.status === "running").length;
86
+ ```
87
+
88
+ The registry is published on `globalThis` under a `Symbol.for` key at extension
89
+ init and `session_start`, and cleared on `session_shutdown` (counts are
90
+ per-session). Returns `undefined` when the module is disabled — callers must
91
+ treat that as "no data", e.g. the footer's glance process line does.
92
+
77
93
  ## Differences from the reference
78
94
 
79
95
  - Commands live in the `/unipi:*` namespace; env prefix is `UNIPI_BG_*`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/background-tasks",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "description": "Background tasks for UniPi — durable shell jobs, delegated agents, attested Pi runs, and fixed-purpose Fusion workflows",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/index.ts CHANGED
@@ -19,10 +19,14 @@ import {
19
19
  import { registerToolsAndCommands } from "./tools.js";
20
20
  import { registerFusionExtension } from "./fusion-extension.js";
21
21
  import { registerDelegateExtension } from "./delegate-extension.js";
22
+ import { setSharedTaskRegistry, clearSharedTaskRegistry } from "./registry-shared.js";
22
23
  import { taskDisplayName, type BgTask, type StartAttestedPiTaskOptions, type StartTaskOptions } from "./types.js";
23
24
 
24
25
  const STATUS_INTERVAL_MS = 1000;
25
26
 
27
+ // Direct synchronous access for sibling extensions (footer process one-liner).
28
+ export { getSharedTaskRegistry } from "./registry-shared.js";
29
+
26
30
  export default function backgroundTasksExtension(pi: ExtensionAPI): void {
27
31
  const { config, warnings } = loadBackgroundTasksConfig(process.cwd());
28
32
 
@@ -53,6 +57,8 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
53
57
  eventService.publishTerminal(task);
54
58
  },
55
59
  });
60
+ setSharedTaskRegistry(registry);
61
+
56
62
  const eventService: BackgroundTaskExtensionService = installBackgroundTaskExtensionApi({
57
63
  events: pi.events,
58
64
  registry,
@@ -253,6 +259,7 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
253
259
 
254
260
  pi.on("session_start", async (_event, ctx) => {
255
261
  registry.setShuttingDown(false);
262
+ setSharedTaskRegistry(registry);
256
263
  currentCtx = ctx;
257
264
  await registry.ensureRuntimeDir(ctx);
258
265
  updateUi(ctx);
@@ -264,6 +271,7 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
264
271
 
265
272
  pi.on("session_shutdown", async (_event, ctx) => {
266
273
  registry.setShuttingDown(true);
274
+ clearSharedTaskRegistry();
267
275
  currentCtx = undefined;
268
276
  if (statusInterval) {
269
277
  clearInterval(statusInterval);
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Shared BackgroundTaskRegistry accessor
3
+ *
4
+ * Exposes the live registry to sibling extensions (e.g. @pi-unipi/footer)
5
+ * without events or request/response channels — direct synchronous reads of
6
+ * `allTasks()`.
7
+ *
8
+ * Stored on globalThis under a `Symbol.for` key so the singleton is shared
9
+ * even if this package ends up instantiated more than once (duplicate
10
+ * node_modules copies would otherwise each hold their own module state).
11
+ */
12
+
13
+ import type { BackgroundTaskRegistry } from "./registry.js";
14
+
15
+ const SHARED_REGISTRY_KEY = Symbol.for("unipi.background-tasks.shared-registry");
16
+
17
+ /** Publish the live registry (idempotent; later calls overwrite). */
18
+ export function setSharedTaskRegistry(registry: BackgroundTaskRegistry): void {
19
+ (globalThis as unknown as Record<symbol, unknown>)[SHARED_REGISTRY_KEY] = registry;
20
+ }
21
+
22
+ /** Read the live registry, or undefined when background-tasks is not loaded. */
23
+ export function getSharedTaskRegistry(): BackgroundTaskRegistry | undefined {
24
+ return (globalThis as unknown as Record<symbol, unknown>)[SHARED_REGISTRY_KEY] as
25
+ | BackgroundTaskRegistry
26
+ | undefined;
27
+ }
28
+
29
+ /** Drop the shared reference (used on session shutdown so readers see a clean slate). */
30
+ export function clearSharedTaskRegistry(): void {
31
+ delete (globalThis as unknown as Record<symbol, unknown>)[SHARED_REGISTRY_KEY];
32
+ }