@thurstonsand/pi-agent-switchboard 0.8.0 → 0.9.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 (2) hide show
  1. package/index.js +20 -8
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -89,10 +89,11 @@ class Db {
89
89
  }
90
90
 
91
91
  // packages/shared/src/index.ts
92
- var SCHEMA_VERSION = 7;
92
+ var SCHEMA_VERSION = 8;
93
93
  var VIEWS = ["agent", "editor", "split"];
94
94
  var HARNESSES = ["pi", "claude", "codex"];
95
95
  var SNOOZE_PRESETS = ["one_hour", "one_day", "monday", "next_message"];
96
+ var RELOAD_MODES = ["continue", "idle"];
96
97
  function stateDir() {
97
98
  return join(process.env.XDG_STATE_HOME || join(homedir(), ".local/state"), "agent-switchboard");
98
99
  }
@@ -215,7 +216,8 @@ function settle(db, s) {
215
216
  harnessTitled(db, s.sessionId, s.title);
216
217
  db.run("UPDATE sessions SET phase = 'idle', last_settled_at = ?, cwd = ?, project_root = ?, branch = ?, title = coalesce(?, title) WHERE session_id = ?", Date.now(), s.cwd, projectRoot(s.cwd), branch(s.cwd), s.title, s.sessionId);
217
218
  db.run("UPDATE runtimes SET cwd = ?, project_root = ? WHERE tmux_session = ?", s.cwd, projectRoot(s.cwd), s.host);
218
- return { archived: isArchived(db, s.sessionId) };
219
+ const reloading = db.get("SELECT 1 FROM marks WHERE session_id = ? AND reload IS NOT NULL", s.sessionId);
220
+ return { quit: isArchived(db, s.sessionId) || Boolean(reloading) };
219
221
  });
220
222
  }
221
223
  function turnErrored(db, sessionId) {
@@ -241,7 +243,10 @@ function titleOf(db, sessionId) {
241
243
  return row?.title ?? null;
242
244
  }
243
245
  function endHosting(db, host) {
244
- recordTx(db, () => db.run("DELETE FROM runtimes WHERE tmux_session = ?", host));
246
+ recordTx(db, () => {
247
+ db.run("DELETE FROM runtimes WHERE tmux_session = ?", host);
248
+ db.run("DELETE FROM launches WHERE tmux_session = ?", host);
249
+ });
245
250
  }
246
251
  function isArchived(db, sessionId) {
247
252
  return Boolean(db.get("SELECT 1 FROM sessions s JOIN marks m USING (session_id) WHERE s.session_id = ? AND m.archived_at >= s.last_prompt_at", sessionId));
@@ -251,7 +256,7 @@ function markArchived(db, sessionId) {
251
256
  return false;
252
257
  const now = Date.now();
253
258
  db.run(`INSERT INTO marks (session_id, archived_at) VALUES (?, ?)
254
- ON CONFLICT (session_id) DO UPDATE SET archived_at = excluded.archived_at, snoozed_at = NULL, snoozed_until = NULL`, sessionId, now);
259
+ ON CONFLICT (session_id) DO UPDATE SET archived_at = excluded.archived_at, snoozed_at = NULL, snoozed_until = NULL, reload = NULL`, sessionId, now);
255
260
  db.run("UPDATE messages SET cancelled_at = ? WHERE target_id = ? AND delivered_at IS NULL AND cancelled_at IS NULL", now, sessionId);
256
261
  db.run("UPDATE schedules SET cancelled_at = ? WHERE target_id = ? AND next_at IS NOT NULL AND cancelled_at IS NULL", now, sessionId);
257
262
  return true;
@@ -436,7 +441,10 @@ var TOOLS = {
436
441
  "Unarchiving doesn't restart a session; session_send_message wakes it.",
437
442
  "Snooze or unsnooze only when the user asks.",
438
443
  "Group sessions when the user asks, or to keep sessions you started for one piece of work together. Reuse a Group session_reachable lists in that Project rather than inventing a near-duplicate.",
439
- "Retitle a session when the user asks, or when its title no longer says what it is working on."
444
+ "Retitle a session when the user asks, or when its title no longer says what it is working on.",
445
+ "Reload a session when the user asks, or when you changed something it reads only at startup (its AGENTS.md or CLAUDE.md, settings, extensions, plugins, skills, or MCP servers) and it needs the change now.",
446
+ "Reloading this session restarts it when this turn ends: call it last, then end with a brief final message. With continue, it starts a turn on its own once it's back; with idle, it waits for the user.",
447
+ "Reloading another session with continue restarts it at once, cutting off a running turn, its tools, and its background work, then picks that turn back up; an idle or dormant one starts a turn."
440
448
  ],
441
449
  parameters: Type.Object({
442
450
  session: Type.Optional(session),
@@ -451,6 +459,9 @@ var TOOLS = {
451
459
  title: Type.Optional(Type.String({ description: "A new, short title." })),
452
460
  snooze: Type.Optional(Type.Union([...[...SNOOZE_PRESETS, "off"].map((preset) => Type.Literal(preset)), Type.Object({ until: Type.String() })], {
453
461
  description: 'How long to snooze it, off to unsnooze, or {"until":"2026-11-05T09:00:00-08:00"} for a set time.'
462
+ })),
463
+ reload: Type.Optional(Type.Union(RELOAD_MODES.map((mode) => Type.Literal(mode)), {
464
+ description: "Restart the session's agent process on the same conversation, so it reads its instructions and configuration afresh. continue: it carries on working afterward. idle: it waits for its next prompt."
454
465
  }))
455
466
  }),
456
467
  readOnly: false
@@ -773,13 +784,13 @@ ${details.body}`, 0, 0);
773
784
  writeFor(ctx, (db, id) => {
774
785
  if (stopReason === "error" && !event.aborted)
775
786
  turnErrored(db, id);
776
- const { archived } = settle(db, {
787
+ const { quit } = settle(db, {
777
788
  host: proc.launch.tmuxSession,
778
789
  sessionId: id,
779
790
  cwd: ctx.cwd,
780
791
  title: ctx.sessionManager.getSessionName() ?? null
781
792
  });
782
- if (archived)
793
+ if (quit)
783
794
  ctx.shutdown();
784
795
  });
785
796
  });
@@ -970,7 +981,8 @@ ${details.body}`, 0, 0);
970
981
  args.archived === false ? "unarchive" : "",
971
982
  args.snooze !== undefined ? `snooze ${snoozeText(args.snooze)}` : "",
972
983
  args.group === null ? "ungroup" : args.group !== undefined ? `group ${args.group}` : "",
973
- args.title !== undefined ? `retitle as "${args.title}"` : ""
984
+ args.title !== undefined ? `retitle as "${args.title}"` : "",
985
+ args.reload !== undefined ? `reload · ${args.reload}` : ""
974
986
  ].filter(Boolean);
975
987
  if (args.title !== undefined)
976
988
  return parts.join(" · ");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thurstonsand/pi-agent-switchboard",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "description": "Records managed pi sessions for Agent Switchboard (swb)",
6
6
  "license": "MIT",