@trevonistrevon/pi-loop 0.4.5 → 0.4.6

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
@@ -107,6 +107,8 @@ Only task counts and the single active/next task are shown in the widget so atte
107
107
  | `PI_LOOP_SCOPE` | `memory` (ephemeral), `session` (per-session file), `project` (shared) | `session` |
108
108
  | `PI_LOOP_DEBUG` | Debug logging to stderr | unset |
109
109
 
110
+ In `session` scope (default), loop and task files are saved per session ID (e.g. `.pi/tasks/tasks-<sessionId>.json`) so concurrent sessions and worktree agents do not share state. In `memory` scope nothing persists to disk.
111
+
110
112
  ## Limits
111
113
 
112
114
  25 active loops, 25 running monitors. Recurring loops expire after 7 days.
package/dist/index.js CHANGED
@@ -53,9 +53,14 @@ export default function (pi) {
53
53
  return undefined;
54
54
  return join(process.cwd(), ".pi", "loops", "loops.json");
55
55
  }
56
- function resolveTaskStorePath() {
56
+ function resolveTaskStorePath(sessionId) {
57
57
  if (loopScope === "memory")
58
58
  return undefined;
59
+ if (loopScope === "session" && sessionId) {
60
+ return join(process.cwd(), ".pi", "tasks", `tasks-${sessionId}.json`);
61
+ }
62
+ if (loopScope === "session")
63
+ return undefined;
59
64
  return join(process.cwd(), ".pi", "tasks", "tasks.json");
60
65
  }
61
66
  let store = new LoopStore(resolveStorePath());
@@ -319,6 +324,7 @@ export default function (pi) {
319
324
  let storeUpgraded = false;
320
325
  let persistedShown = false;
321
326
  let _latestCtx;
327
+ let _sessionId;
322
328
  function upgradeStoreIfNeeded(ctx) {
323
329
  if (storeUpgraded)
324
330
  return;
@@ -347,6 +353,7 @@ export default function (pi) {
347
353
  }
348
354
  pi.on("turn_start", async (_event, ctx) => {
349
355
  _latestCtx = ctx;
356
+ _sessionId = ctx.sessionManager.getSessionId();
350
357
  widget.setUICtx(ctx.ui);
351
358
  upgradeStoreIfNeeded(ctx);
352
359
  widget.update();
@@ -381,6 +388,7 @@ export default function (pi) {
381
388
  triggerSystem.stop();
382
389
  agentRunning = false;
383
390
  pendingNotifications.clear();
391
+ _sessionId = undefined;
384
392
  const isResume = event?.reason === "resume";
385
393
  storeUpgraded = false;
386
394
  persistedShown = false;
@@ -995,7 +1003,7 @@ Use MonitorList to find the monitor ID, then stop it with this tool.`,
995
1003
  setTimeout(async () => {
996
1004
  if (tasksAvailable || nativeTasksRegistered)
997
1005
  return;
998
- nativeTaskStore = new TaskStore(resolveTaskStorePath());
1006
+ nativeTaskStore = new TaskStore(resolveTaskStorePath(_sessionId));
999
1007
  nativeTasksRegistered = true;
1000
1008
  const taskStore = nativeTaskStore;
1001
1009
  pi.registerCommand("tasks", {
@@ -1032,6 +1040,7 @@ Fields:
1032
1040
  - metadata: optional tags/metadata`,
1033
1041
  promptGuidelines: [
1034
1042
  "Use TaskCreate to track complex multi-step work across turns.",
1043
+ "Break work into small, independently completable tasks. A task should be finishable in one focused session — if a task would take multiple turns, split it further.",
1035
1044
  "TaskCreate accepts `subject` and `description` parameters only — do not invent extra fields unless the schema explicitly adds them.",
1036
1045
  ],
1037
1046
  parameters: Type.Object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trevonistrevon/pi-loop",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "A pi extension for cron/event-based agent re-wake loops and background process monitoring.",
5
5
  "author": "trevonistrevon",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -73,8 +73,12 @@ export default function (pi: ExtensionAPI) {
73
73
  return join(process.cwd(), ".pi", "loops", "loops.json");
74
74
  }
75
75
 
76
- function resolveTaskStorePath(): string | undefined {
76
+ function resolveTaskStorePath(sessionId?: string): string | undefined {
77
77
  if (loopScope === "memory") return undefined;
78
+ if (loopScope === "session" && sessionId) {
79
+ return join(process.cwd(), ".pi", "tasks", `tasks-${sessionId}.json`);
80
+ }
81
+ if (loopScope === "session") return undefined;
78
82
  return join(process.cwd(), ".pi", "tasks", "tasks.json");
79
83
  }
80
84
 
@@ -349,6 +353,7 @@ export default function (pi: ExtensionAPI) {
349
353
  let storeUpgraded = false;
350
354
  let persistedShown = false;
351
355
  let _latestCtx: ExtensionContext | undefined;
356
+ let _sessionId: string | undefined;
352
357
 
353
358
  function upgradeStoreIfNeeded(ctx: ExtensionContext) {
354
359
  if (storeUpgraded) return;
@@ -378,6 +383,7 @@ export default function (pi: ExtensionAPI) {
378
383
 
379
384
  pi.on("turn_start", async (_event, ctx) => {
380
385
  _latestCtx = ctx;
386
+ _sessionId = ctx.sessionManager.getSessionId();
381
387
  widget.setUICtx(ctx.ui);
382
388
  upgradeStoreIfNeeded(ctx);
383
389
  widget.update();
@@ -417,6 +423,7 @@ export default function (pi: ExtensionAPI) {
417
423
  triggerSystem.stop();
418
424
  agentRunning = false;
419
425
  pendingNotifications.clear();
426
+ _sessionId = undefined;
420
427
 
421
428
  const isResume = event?.reason === "resume";
422
429
  storeUpgraded = false;
@@ -1076,7 +1083,7 @@ Use MonitorList to find the monitor ID, then stop it with this tool.`,
1076
1083
 
1077
1084
  setTimeout(async () => {
1078
1085
  if (tasksAvailable || nativeTasksRegistered) return;
1079
- nativeTaskStore = new TaskStore(resolveTaskStorePath());
1086
+ nativeTaskStore = new TaskStore(resolveTaskStorePath(_sessionId));
1080
1087
  nativeTasksRegistered = true;
1081
1088
  const taskStore = nativeTaskStore;
1082
1089
 
@@ -1115,6 +1122,7 @@ Fields:
1115
1122
  - metadata: optional tags/metadata`,
1116
1123
  promptGuidelines: [
1117
1124
  "Use TaskCreate to track complex multi-step work across turns.",
1125
+ "Break work into small, independently completable tasks. A task should be finishable in one focused session — if a task would take multiple turns, split it further.",
1118
1126
  "TaskCreate accepts `subject` and `description` parameters only — do not invent extra fields unless the schema explicitly adds them.",
1119
1127
  ],
1120
1128
  parameters: Type.Object({