@tekmidian/pai 0.45.0 → 0.47.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.
Files changed (34) hide show
  1. package/dist/{chain-DAEC9AU7.mjs → chain-CNSa0A3G.mjs} +2 -2
  2. package/dist/{chain-DAEC9AU7.mjs.map → chain-CNSa0A3G.mjs.map} +1 -1
  3. package/dist/cli/index.mjs +4 -4
  4. package/dist/cli/program.mjs +4 -4
  5. package/dist/daemon/index.mjs +2 -2
  6. package/dist/{daemon-Dq2ZSdex.mjs → daemon-CYpVy_Dw.mjs} +2 -2
  7. package/dist/{daemon-DNBEFHaj.mjs → daemon-DZ4Q0jrs.mjs} +2 -2
  8. package/dist/{daemon-DNBEFHaj.mjs.map → daemon-DZ4Q0jrs.mjs.map} +1 -1
  9. package/dist/daemon-mcp/index.mjs +3 -3
  10. package/dist/{fallback-CxGDTXWt.mjs → fallback-IeR2FrFn.mjs} +6 -6
  11. package/dist/fallback-IeR2FrFn.mjs.map +1 -0
  12. package/dist/hooks/load-core-context.mjs +9 -11
  13. package/dist/hooks/load-core-context.mjs.map +3 -3
  14. package/dist/hooks/load-project-context.mjs +59 -6
  15. package/dist/hooks/load-project-context.mjs.map +3 -3
  16. package/dist/hooks/worker-status-line.mjs +23 -4
  17. package/dist/hooks/worker-status-line.mjs.map +3 -3
  18. package/dist/{planner-B4DvNpXd.mjs → planner-Cn8HmT7l.mjs} +3 -3
  19. package/dist/{planner-B4DvNpXd.mjs.map → planner-Cn8HmT7l.mjs.map} +1 -1
  20. package/dist/{program-DvuMelhj.mjs → program-BxpeczCx.mjs} +4123 -4003
  21. package/dist/program-BxpeczCx.mjs.map +1 -0
  22. package/dist/{run-BgExF8Xg.mjs → run-Cls0YGgV.mjs} +43 -6
  23. package/dist/run-Cls0YGgV.mjs.map +1 -0
  24. package/docs/commands/config.md +1 -1
  25. package/package.json +1 -1
  26. package/src/hooks/ts/lib/frontmatter.test.ts +19 -0
  27. package/src/hooks/ts/lib/frontmatter.ts +10 -0
  28. package/src/hooks/ts/lib/handover-budget.test.ts +124 -0
  29. package/src/hooks/ts/lib/handover-budget.ts +94 -0
  30. package/src/hooks/ts/session-start/load-core-context.ts +6 -15
  31. package/src/hooks/ts/session-start/load-project-context.ts +9 -6
  32. package/dist/fallback-CxGDTXWt.mjs.map +0 -1
  33. package/dist/program-DvuMelhj.mjs.map +0 -1
  34. package/dist/run-BgExF8Xg.mjs.map +0 -1
@@ -410,6 +410,43 @@ function alive(pid) {
410
410
  return false;
411
411
  }
412
412
  }
413
+ /**
414
+ * Whether `status.pid` still names the process that was started as this
415
+ * worker, not a later, unrelated process the OS handed the same pid to after
416
+ * the worker exited. `alive()` alone can't tell these apart — a pid observed
417
+ * live on 2026-09-19 (worker 20260919-083549-90913) had been reused, and
418
+ * `pai worker kill` signalled the wrong, unrelated process. `ps -o lstart=`
419
+ * reads the running process's actual start time and compares it against the
420
+ * status file's own `started` stamp; a reused pid almost never starts within
421
+ * 120s of the original, so a wider drift means "different process".
422
+ */
423
+ function ownsPid(status) {
424
+ if (status.pid <= 0 || !alive(status.pid)) return false;
425
+ try {
426
+ const out = execFileSync("ps", [
427
+ "-o",
428
+ "lstart=",
429
+ "-p",
430
+ String(status.pid)
431
+ ], {
432
+ encoding: "utf8",
433
+ env: {
434
+ ...process.env,
435
+ LC_ALL: "C"
436
+ }
437
+ }).trim();
438
+ const psStart = Date.parse(out);
439
+ const started = Date.parse(status.started.replace(" ", "T"));
440
+ if (Number.isNaN(psStart) || Number.isNaN(started)) return alive(status.pid);
441
+ return Math.abs(psStart - started) <= 12e4;
442
+ } catch {
443
+ return alive(status.pid);
444
+ }
445
+ }
446
+ /** Whether a status is both marked "running" and still owns its recorded pid. */
447
+ function isLive(status) {
448
+ return status.state === "running" && ownsPid(status);
449
+ }
413
450
  /** "42s" under 90s, "7m" above — the coarse age the table and bar show. */
414
451
  function ageOf(ts, now = /* @__PURE__ */ new Date()) {
415
452
  const t = Date.parse(ts.replace(" ", "T"));
@@ -1199,7 +1236,7 @@ function workerDepth(statuses, id, opts) {
1199
1236
  }
1200
1237
  /** Children of `parent` that are still running, oldest first. */
1201
1238
  function runningChildren(statuses, parent) {
1202
- return statuses.filter((s) => s.parent === parent && s.state === "running" && alive(s.pid));
1239
+ return statuses.filter((s) => s.parent === parent && isLive(s));
1203
1240
  }
1204
1241
  /**
1205
1242
  * Would starting a child of `parent` stay within the caps? Throws with a
@@ -1279,7 +1316,7 @@ function createOperatorServer(logDir, id, onLine) {
1279
1316
  function sayToWorker(logDir, id, text, timeoutMs = 4e3) {
1280
1317
  const status = loadStatus(logDir, id);
1281
1318
  if (!status) return Promise.reject(/* @__PURE__ */ new Error(`no worker named "${id}"`));
1282
- if (status.state !== "running" || !alive(status.pid)) return Promise.reject(/* @__PURE__ */ new Error(`worker ${id} is not running (state: ${status.state}) — continue it instead with: pai worker resume ${id} "<text>"`));
1319
+ if (!isLive(status)) return Promise.reject(/* @__PURE__ */ new Error(`worker ${id} is not running (state: ${status.state}) — continue it instead with: pai worker resume ${id} "<text>"`));
1283
1320
  const path = operatorSocketPath(logDir, id);
1284
1321
  if (!existsSync(path)) return Promise.reject(/* @__PURE__ */ new Error(`worker ${id} has no operator socket (${path}) — it may predate this PAI version`));
1285
1322
  return new Promise((resolve, reject) => {
@@ -1393,7 +1430,7 @@ async function deliverHandoff(logDir, h, deps = {}, now = /* @__PURE__ */ new Da
1393
1430
  appendHandoff(logDir, h, now);
1394
1431
  const say = deps.say ?? ((id, text) => sayToWorker(logDir, id, text));
1395
1432
  const parent = loadStatus(logDir, h.to);
1396
- if (parent && parent.state === "running" && alive(parent.pid)) try {
1433
+ if (parent && isLive(parent)) try {
1397
1434
  await say(h.to, handoffMessage(h));
1398
1435
  } catch {}
1399
1436
  return h;
@@ -2640,7 +2677,7 @@ async function runWorker(opts) {
2640
2677
  const logDir = workersLogDir(config);
2641
2678
  mkdirSync(logDir, { recursive: true });
2642
2679
  if (opts.className === "plan" && !opts._planner) {
2643
- const { runPlanner } = await import("./planner-B4DvNpXd.mjs");
2680
+ const { runPlanner } = await import("./planner-Cn8HmT7l.mjs");
2644
2681
  return runPlanner(opts);
2645
2682
  }
2646
2683
  const parent = launchParent(opts.parent);
@@ -3538,5 +3575,5 @@ function resultFromOutput(out) {
3538
3575
  }
3539
3576
 
3540
3577
  //#endregion
3541
- export { loadStatus as A, describeMcp as B, ledgerSummary as C, contextLabel as D, alive as E, setWorkerLabel as F, waitForTerminalStatus as I, longInlinePromptHint as L, newWorkerId as M, nowStamp as N, contextPercent as O, saveStatus as P, parseRunnerArgs as R, appendLedger as S, ageOf as T, expandMcpNames as V, currentTabKey as _, projectLaunchConfig as a, sessionTag as b, discardWorker as c, readInbox as d, sayToWorker as f, openPaneForWorker as g, openFollowPane as h, usageContextTokens as i, loadStatuses as j, isChatPane as k, mergeWorker as l, checkPaneForWorker as m, runWorker as n, parseWorkerReport as o, workerDepth as p, testProvider as r, renderReport as s, printResult as t, handoffFromInside as u, itermForClaudeSession as v, UNLABELED as w, workerInScope as x, resolveSession as y, shortText as z };
3542
- //# sourceMappingURL=run-BgExF8Xg.mjs.map
3578
+ export { isLive as A, parseRunnerArgs as B, ledgerSummary as C, contextLabel as D, alive as E, ownsPid as F, describeMcp as H, saveStatus as I, setWorkerLabel as L, loadStatuses as M, newWorkerId as N, contextPercent as O, nowStamp as P, waitForTerminalStatus as R, appendLedger as S, ageOf as T, expandMcpNames as U, shortText as V, currentTabKey as _, projectLaunchConfig as a, sessionTag as b, discardWorker as c, readInbox as d, sayToWorker as f, openPaneForWorker as g, openFollowPane as h, usageContextTokens as i, loadStatus as j, isChatPane as k, mergeWorker as l, checkPaneForWorker as m, runWorker as n, parseWorkerReport as o, workerDepth as p, testProvider as r, renderReport as s, printResult as t, handoffFromInside as u, itermForClaudeSession as v, UNLABELED as w, workerInScope as x, resolveSession as y, longInlinePromptHint as z };
3579
+ //# sourceMappingURL=run-Cls0YGgV.mjs.map