runpane 2.4.180 → 2.4.181

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.
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.workspaceStateResultSchema = exports.panelSubmitResultSchema = exports.panelScreenResultSchema = exports.panelCreateResultSchema = exports.panelListResultSchema = exports.paneCreateResultSchema = exports.paneListResultSchema = exports.repoListResultSchema = void 0;
6
+ exports.workspaceStateResultSchema = exports.panelSubmitResultSchema = exports.panelScreenResultSchema = exports.panelCreateResultSchema = exports.panelListResultSchema = exports.paneCreateResultSchema = exports.runpaneSessionResultSchema = exports.runpaneSessionListResultSchema = exports.paneListResultSchema = exports.repoListResultSchema = void 0;
7
7
  exports.runReposList = runReposList;
8
8
  exports.runReposAdd = runReposAdd;
9
9
  exports.runPanesList = runPanesList;
@@ -41,6 +41,7 @@ exports.markSuggestionLine = markSuggestionLine;
41
41
  exports.printPromptNotes = printPromptNotes;
42
42
  exports.runPanelsSubmitComposer = runPanelsSubmitComposer;
43
43
  exports.runPanelsWait = runPanelsWait;
44
+ exports.runPanelsResume = runPanelsResume;
44
45
  exports.runAgentsDoctor = runAgentsDoctor;
45
46
  exports.buildPanelInputRequest = buildPanelInputRequest;
46
47
  exports.buildPanelCreateRequest = buildPanelCreateRequest;
@@ -54,6 +55,7 @@ const boundaryDecoder_1 = require("./boundaryDecoder");
54
55
  const daemonClient_1 = require("./daemonClient");
55
56
  const contract_1 = require("./generated/contract");
56
57
  const commands_1 = require("./commands");
58
+ const sessionPayload_1 = require("./sessionPayload");
57
59
  const watchLines_1 = require("./watchLines");
58
60
  const agentSchema = boundaryDecoder_1.boundary.enumeration(...contract_1.RUNPANE_CONTRACT.enums.agents);
59
61
  const orchestrationAgentSchema = boundaryDecoder_1.boundary.enumeration('claude', 'codex', 'cursor');
@@ -96,6 +98,7 @@ const panelBlockedSchema = boundaryDecoder_1.boundary.object({
96
98
  });
97
99
  const panelStateSchema = boundaryDecoder_1.boundary.object({
98
100
  initialized: boundaryDecoder_1.boundary.boolean,
101
+ running: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
99
102
  isAlternateScreen: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
100
103
  activityStatus: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('active', 'idle')),
101
104
  isCliReady: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
@@ -103,6 +106,10 @@ const panelStateSchema = boundaryDecoder_1.boundary.object({
103
106
  agentType: boundaryDecoder_1.boundary.optional(agentSchema),
104
107
  lastActivity: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
105
108
  });
109
+ const panelReadinessReasonSchema = boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.object({
110
+ code: boundaryDecoder_1.boundary.enumeration('no-agent-detected', 'agent-not-ready', 'command-exited'),
111
+ message: boundaryDecoder_1.boundary.string,
112
+ }));
106
113
  const panelReadinessSchema = boundaryDecoder_1.boundary.object({
107
114
  ok: boundaryDecoder_1.boundary.boolean,
108
115
  condition: boundaryDecoder_1.boundary.string,
@@ -111,6 +118,7 @@ const panelReadinessSchema = boundaryDecoder_1.boundary.object({
111
118
  elapsedMs: boundaryDecoder_1.boundary.number,
112
119
  state: panelStateSchema,
113
120
  blocked: boundaryDecoder_1.boundary.optional(panelBlockedSchema),
121
+ reason: panelReadinessReasonSchema,
114
122
  nextCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
115
123
  });
116
124
  const verificationSchema = boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('observed', 'unverifiable'));
@@ -180,6 +188,7 @@ const reportResultSchema = boundaryDecoder_1.boundary.object({
180
188
  panelId: boundaryDecoder_1.boundary.string,
181
189
  report: agentReportSchema,
182
190
  sessionIds: boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.string),
191
+ liveWatchers: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
183
192
  });
184
193
  const panelLastMessageResultSchema = boundaryDecoder_1.boundary.union(boundaryDecoder_1.boundary.object({
185
194
  ok: boundaryDecoder_1.boundary.literal(true),
@@ -208,14 +217,18 @@ const panelSummarySchema = boundaryDecoder_1.boundary.object({
208
217
  title: boundaryDecoder_1.boundary.string,
209
218
  active: boundaryDecoder_1.boundary.boolean,
210
219
  initialized: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
220
+ running: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
211
221
  agentType: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
212
222
  agentDetection: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('declared', 'command', 'process', 'screen')),
213
223
  launchCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
214
224
  isCliPanel: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
225
+ dock: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
215
226
  position: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
216
227
  createdAt: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
217
228
  lastActiveAt: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
218
229
  report: boundaryDecoder_1.boundary.optional(agentReportSchema),
230
+ resumeId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
231
+ resumeSource: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('agent-farm', 'configured', 'agent')),
219
232
  });
220
233
  exports.repoListResultSchema = boundaryDecoder_1.boundary.object({
221
234
  ok: boundaryDecoder_1.boundary.literal(true),
@@ -293,12 +306,12 @@ const orchestrationSessionRecordSchema = boundaryDecoder_1.boundary.object({
293
306
  createdAt: boundaryDecoder_1.boundary.nonEmptyString,
294
307
  updatedAt: boundaryDecoder_1.boundary.nonEmptyString,
295
308
  });
296
- const runpaneSessionListResultSchema = boundaryDecoder_1.boundary.object({
309
+ exports.runpaneSessionListResultSchema = boundaryDecoder_1.boundary.object({
297
310
  ok: boundaryDecoder_1.boundary.literal(true),
298
311
  sessions: boundaryDecoder_1.boundary.array(orchestrationSessionRecordSchema),
299
312
  selectedSessionId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.nonEmptyString),
300
313
  });
301
- const runpaneSessionResultSchema = boundaryDecoder_1.boundary.object({
314
+ exports.runpaneSessionResultSchema = boundaryDecoder_1.boundary.object({
302
315
  ok: boundaryDecoder_1.boundary.literal(true),
303
316
  session: orchestrationSessionRecordSchema,
304
317
  panelId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.nonEmptyString),
@@ -507,6 +520,12 @@ exports.paneCreateResultSchema = boundaryDecoder_1.boundary.object({
507
520
  position: boundaryDecoder_1.boundary.number,
508
521
  message: boundaryDecoder_1.boundary.string,
509
522
  })),
523
+ base: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.object({
524
+ ref: boundaryDecoder_1.boundary.string,
525
+ commit: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
526
+ refresh: boundaryDecoder_1.boundary.enumeration('fetched', 'recent', 'skipped', 'failed'),
527
+ notice: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
528
+ })),
510
529
  }), boundaryDecoder_1.boundary.object({
511
530
  ok: boundaryDecoder_1.boundary.literal(false),
512
531
  index: boundaryDecoder_1.boundary.number,
@@ -620,6 +639,45 @@ exports.panelListResultSchema = boundaryDecoder_1.boundary.object({
620
639
  paneId: boundaryDecoder_1.boundary.string,
621
640
  panels: boundaryDecoder_1.boundary.array(panelSummarySchema),
622
641
  });
642
+ const panelResumeManyResultSchema = boundaryDecoder_1.boundary.object({
643
+ ok: boundaryDecoder_1.boundary.boolean,
644
+ scope: boundaryDecoder_1.boundary.object({
645
+ kind: boundaryDecoder_1.boundary.enumeration('session', 'all-stopped'),
646
+ sessionId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
647
+ sessionName: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
648
+ }),
649
+ resumed: boundaryDecoder_1.boundary.number,
650
+ alreadyRunning: boundaryDecoder_1.boundary.number,
651
+ failed: boundaryDecoder_1.boundary.number,
652
+ notReady: boundaryDecoder_1.boundary.number,
653
+ concurrency: boundaryDecoder_1.boundary.number,
654
+ items: boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.object({
655
+ ok: boundaryDecoder_1.boundary.boolean,
656
+ panelId: boundaryDecoder_1.boundary.string,
657
+ paneId: boundaryDecoder_1.boundary.string,
658
+ paneName: boundaryDecoder_1.boundary.string,
659
+ panelTitle: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
660
+ agentType: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
661
+ action: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('resumed', 'already-running')),
662
+ message: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
663
+ agentSessionId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
664
+ readiness: boundaryDecoder_1.boundary.optional(panelReadinessSchema),
665
+ error: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
666
+ })),
667
+ nextCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
668
+ });
669
+ const panelResumeResultSchema = boundaryDecoder_1.boundary.object({
670
+ ok: boundaryDecoder_1.boundary.boolean,
671
+ panelId: boundaryDecoder_1.boundary.string,
672
+ paneId: boundaryDecoder_1.boundary.string,
673
+ action: boundaryDecoder_1.boundary.enumeration('resumed', 'already-running'),
674
+ message: boundaryDecoder_1.boundary.string,
675
+ agentType: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
676
+ agentSessionId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
677
+ panel: panelSummarySchema,
678
+ readiness: boundaryDecoder_1.boundary.optional(panelReadinessSchema),
679
+ nextCommand: boundaryDecoder_1.boundary.string,
680
+ });
623
681
  exports.panelCreateResultSchema = boundaryDecoder_1.boundary.object({
624
682
  ok: boundaryDecoder_1.boundary.boolean,
625
683
  generation: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
@@ -719,6 +777,8 @@ const panelWaitResultSchema = boundaryDecoder_1.boundary.object({
719
777
  elapsedMs: boundaryDecoder_1.boundary.number,
720
778
  state: panelStateSchema,
721
779
  blocked: boundaryDecoder_1.boundary.optional(panelBlockedSchema),
780
+ reason: panelReadinessReasonSchema,
781
+ stopped: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.literal(true)),
722
782
  nextCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
723
783
  panelId: boundaryDecoder_1.boundary.string,
724
784
  paneId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
@@ -744,13 +804,14 @@ const agentDoctorResultSchema = boundaryDecoder_1.boundary.object({
744
804
  })),
745
805
  warnings: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.string)),
746
806
  });
747
- const workspaceEntryKindSchema = boundaryDecoder_1.boundary.enumeration('agent.ready', 'agent.busy', 'agent.blocked', 'agent.unknown', 'agent.idle', 'pane.created', 'pane.gone', 'panel.exited', 'pane.associated', 'pane.detached', 'pr.conflicted', 'pr.checks', 'pr.merged', 'agent.report');
807
+ const workspaceEntryKindSchema = boundaryDecoder_1.boundary.enumeration('agent.ready', 'agent.busy', 'agent.blocked', 'agent.unknown', 'agent.idle', 'pane.created', 'pane.gone', 'panel.exited', 'panel.stopped', 'pane.associated', 'pane.detached', 'pr.conflicted', 'pr.checks', 'pr.merged', 'agent.report');
748
808
  const agentStateSchema = boundaryDecoder_1.boundary.enumeration('blocked', 'working', 'idle', 'unknown');
749
809
  const workspacePanelSummarySchema = boundaryDecoder_1.boundary.object({
750
810
  panelId: boundaryDecoder_1.boundary.string,
751
811
  title: boundaryDecoder_1.boundary.string,
752
812
  agentType: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
753
813
  agentState: boundaryDecoder_1.boundary.optional(agentStateSchema),
814
+ running: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
754
815
  });
755
816
  const workspaceEntrySchema = boundaryDecoder_1.boundary.object({
756
817
  gen: boundaryDecoder_1.boundary.number,
@@ -774,6 +835,7 @@ const workspaceEntrySchema = boundaryDecoder_1.boundary.object({
774
835
  heldInput: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
775
836
  heldInputPresent: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
776
837
  exitCode: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
838
+ running: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
777
839
  baseline: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.literal(true)),
778
840
  replay: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.literal(true)),
779
841
  changedWhileAway: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
@@ -901,7 +963,7 @@ async function runPanesList(parsed) {
901
963
  return 0;
902
964
  }
903
965
  async function runSessionsList(parsed) {
904
- const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:list', [], runpaneSessionListResultSchema, {
966
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:list', [], exports.runpaneSessionListResultSchema, {
905
967
  paneDir: parsed.paneDir,
906
968
  });
907
969
  if (parsed.json) {
@@ -918,15 +980,15 @@ async function runSessionsList(parsed) {
918
980
  async function runSessionsCreate(parsed) {
919
981
  if (!parsed.fromJson)
920
982
  throw new Error('runpane sessions create requires --from-json <path|->.');
921
- const input = parseSessionCreatePayload(JSON.parse(stripUtf8Bom(readInputSource(parsed.fromJson))));
922
- const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:create', [input], runpaneSessionResultSchema, {
983
+ const input = (0, sessionPayload_1.parseSessionCreatePayload)(JSON.parse(stripUtf8Bom(readInputSource(parsed.fromJson))));
984
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:create', [input], exports.runpaneSessionResultSchema, {
923
985
  paneDir: parsed.paneDir,
924
986
  });
925
987
  return printSessionResult(result, parsed.json, 'Created');
926
988
  }
927
989
  async function runSessionsGet(parsed) {
928
990
  const selector = sessionSelectorFromParsed(parsed);
929
- const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:get', [selector], runpaneSessionResultSchema, {
991
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:get', [selector], exports.runpaneSessionResultSchema, {
930
992
  paneDir: parsed.paneDir,
931
993
  });
932
994
  return printSessionResult(result, parsed.json, '');
@@ -934,8 +996,8 @@ async function runSessionsGet(parsed) {
934
996
  async function runSessionsUpdate(parsed) {
935
997
  if (!parsed.fromJson)
936
998
  throw new Error('runpane sessions update requires --from-json <path|->.');
937
- const input = parseSessionUpdatePayload(JSON.parse(stripUtf8Bom(readInputSource(parsed.fromJson))));
938
- const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:update', [{ selector: sessionSelectorFromParsed(parsed), input }], runpaneSessionResultSchema, {
999
+ const input = (0, sessionPayload_1.parseSessionUpdatePayload)(JSON.parse(stripUtf8Bom(readInputSource(parsed.fromJson))));
1000
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:update', [{ selector: sessionSelectorFromParsed(parsed), input }], exports.runpaneSessionResultSchema, {
939
1001
  paneDir: parsed.paneDir,
940
1002
  });
941
1003
  return printSessionResult(result, parsed.json, 'Updated');
@@ -943,14 +1005,14 @@ async function runSessionsUpdate(parsed) {
943
1005
  async function runSessionsPin(parsed, pinned) {
944
1006
  const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:update', [{
945
1007
  selector: sessionSelectorFromParsed(parsed), input: { isPinned: pinned },
946
- }], runpaneSessionResultSchema, { paneDir: parsed.paneDir });
1008
+ }], exports.runpaneSessionResultSchema, { paneDir: parsed.paneDir });
947
1009
  return printSessionResult(result, parsed.json, pinned ? 'Pinned' : 'Unpinned');
948
1010
  }
949
1011
  async function runSessionsSetAgent(parsed) {
950
1012
  const selector = sessionSelectorFromParsed(parsed);
951
1013
  if (!parsed.agent)
952
1014
  throw new Error('runpane sessions set-agent requires --agent.');
953
- const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:set-agent', [{ selector, agent: parsed.agent }], runpaneSessionResultSchema, {
1015
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:set-agent', [{ selector, agent: parsed.agent }], exports.runpaneSessionResultSchema, {
954
1016
  paneDir: parsed.paneDir,
955
1017
  });
956
1018
  return printSessionResult(result, parsed.json, 'Updated agent for');
@@ -962,12 +1024,12 @@ async function runSessionsAssociate(parsed) {
962
1024
  const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:associate', [{ selector, association: {
963
1025
  paneId: parsed.paneId,
964
1026
  panelIds: parsed.panelId ? [parsed.panelId] : undefined,
965
- } }], runpaneSessionResultSchema, { paneDir: parsed.paneDir });
1027
+ } }], exports.runpaneSessionResultSchema, { paneDir: parsed.paneDir });
966
1028
  return printSessionResult(result, parsed.json, 'Associated');
967
1029
  }
968
1030
  async function runSessionsDetach(parsed) {
969
1031
  const selector = sessionSelectorFromParsed(parsed);
970
- const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:detach', [{ selector, paneId: parsed.paneId }], runpaneSessionResultSchema, {
1032
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:sessions:detach', [{ selector, paneId: parsed.paneId }], exports.runpaneSessionResultSchema, {
971
1033
  paneDir: parsed.paneDir,
972
1034
  });
973
1035
  return printSessionResult(result, parsed.json, 'Detached');
@@ -1107,44 +1169,6 @@ function sessionSelectorFromParsed(parsed) {
1107
1169
  throw new Error('Named Session id or name is required via --session.');
1108
1170
  return { sessionId };
1109
1171
  }
1110
- function parseSessionCreatePayload(value) {
1111
- return (0, boundaryDecoder_1.decodeBoundary)(value, boundaryDecoder_1.boundary.object({
1112
- runtime: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('windows', 'wsl')),
1113
- wslDistribution: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.nonEmptyString),
1114
- name: boundaryDecoder_1.boundary.nonEmptyString,
1115
- isPinned: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
1116
- agent: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('codex', 'claude', 'cursor')),
1117
- launchCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1118
- profile: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1119
- goal: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1120
- context: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1121
- decisions: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.string)),
1122
- blockers: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.string)),
1123
- nextAction: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1124
- evidence: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(orchestrationLinkSchema)),
1125
- outputs: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(orchestrationLinkSchema)),
1126
- }));
1127
- }
1128
- function parseSessionUpdatePayload(value) {
1129
- return (0, boundaryDecoder_1.decodeBoundary)(value, boundaryDecoder_1.boundary.object({
1130
- name: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1131
- archived: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
1132
- isPinned: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
1133
- agent: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('codex', 'claude', 'cursor')),
1134
- launchCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1135
- profile: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1136
- goal: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1137
- context: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1138
- decisions: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.string)),
1139
- blockers: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.string)),
1140
- nextAction: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
1141
- evidence: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(orchestrationLinkSchema)),
1142
- outputs: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(orchestrationLinkSchema)),
1143
- report: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.nullable(orchestrationReportSchema)),
1144
- expectedRevision: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
1145
- source: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('user', 'agent')),
1146
- }));
1147
- }
1148
1172
  function printSessionResult(result, json, action) {
1149
1173
  if (json) {
1150
1174
  printJson(result);
@@ -1191,22 +1215,34 @@ async function runWatch(parsed) {
1191
1215
  }
1192
1216
  const defaults = contract_1.RUNPANE_CONTRACT.defaults.watch;
1193
1217
  const format = parsed.watchFormat ?? (parsed.json ? 'json' : 'lines');
1218
+ // --until-event takes --follow's scope defaults; it only stops after the first event.
1219
+ const keepsWaiting = parsed.follow || parsed.untilEvent;
1194
1220
  const heartbeatMs = (0, watchLines_1.effectiveWatchHeartbeatMs)(parsed.heartbeatSeconds ?? (parsed.follow ? defaults.heartbeatSeconds : 0));
1195
- const idleAfterMs = parsed.idleAfterMs ?? (parsed.follow ? defaults.idleAfterMs : 0);
1221
+ const idleAfterMs = parsed.idleAfterMs ?? (keepsWaiting ? defaults.idleAfterMs : 0);
1196
1222
  const effectiveAgentsOnly = parsed.includeShells
1197
1223
  ? undefined
1198
- : parsed.agentsOnly || parsed.follow ? true : undefined;
1224
+ : parsed.agentsOnly || keepsWaiting ? true : undefined;
1199
1225
  const includeHeldInput = parsed.includeHeldInput && !parsed.noHeldInput ? true : undefined;
1200
1226
  // Lines mode turns presence into STUCK; JSON mode passes heldInputPresent through as the equivalent.
1201
1227
  const includeHeldInputPresence = defaults.includeHeldInputPresence
1202
- && !parsed.noHeldInput && parsed.follow ? true : undefined;
1228
+ && !parsed.noHeldInput && keepsWaiting ? true : undefined;
1203
1229
  const cadenceValueFlagPresent = (0, commands_1.hasCadenceValueFlag)(parsed);
1230
+ const ownPanelId = process.env.PANE_PANEL_ID?.trim() || undefined;
1204
1231
  // Cadence state lives in the daemon per named consumer, so an anonymous follower names itself.
1205
1232
  // A Session watch is named after the Session, so it survives an orchestrator agent switch.
1206
1233
  const sessionCursor = parsed.sessionId ? sessionWatchCursorName(parsed.sessionId) : undefined;
1207
- const panelCursor = process.env.PANE_PANEL_ID ? derivedWatchCursorName('panel', process.env.PANE_PANEL_ID) : undefined;
1234
+ const panelCursor = ownPanelId ? derivedWatchCursorName('panel', ownPanelId) : undefined;
1235
+ // An --until-event re-arm resumes where the last one stopped, under a name apart from the
1236
+ // panel's --follow cursor so it never takes over a running monitor.
1237
+ const untilEventCursor = ownPanelId && parsed.watchSince === undefined
1238
+ ? derivedWatchCursorName('until', `until-${ownPanelId}`)
1239
+ : undefined;
1208
1240
  const watchAs = parsed.watchAs
1241
+ ?? (parsed.untilEvent ? untilEventCursor : undefined)
1209
1242
  ?? (parsed.follow ? sessionCursor || panelCursor || (cadenceValueFlagPresent ? `follow-${process.pid}` : undefined) : undefined);
1243
+ // Under --until-event, --timeout-ms is the deadline for the whole wait, not for one daemon call.
1244
+ const deadlineAt = parsed.untilEvent && parsed.timeoutMs !== undefined ? Date.now() + parsed.timeoutMs : undefined;
1245
+ exitWhenReaderCloses();
1210
1246
  // --quiet drops lines that only prove liveness; --self-test still prints its WATCH OK result.
1211
1247
  const emitControlLine = (line) => {
1212
1248
  if (!parsed.quiet)
@@ -1239,9 +1275,15 @@ async function runWatch(parsed) {
1239
1275
  let failingCode;
1240
1276
  let lastFailureAt = 0;
1241
1277
  let lastHeartbeatAt = Date.now();
1242
- let anonymousIdleWindowStartMs = !watchAs && parsed.follow ? 0 : undefined;
1278
+ let anonymousIdleWindowStartMs = !watchAs && keepsWaiting ? 0 : undefined;
1243
1279
  do {
1244
- const requestedWaitMs = parsed.timeoutMs ?? (heartbeatMs > 0 ? heartbeatMs : 60_000);
1280
+ if (deadlineAt !== undefined && Date.now() >= deadlineAt) {
1281
+ emitControlLine((0, watchLines_1.formatNonEntry)('_timeout', { timeoutMs: parsed.timeoutMs }, format));
1282
+ return 124;
1283
+ }
1284
+ const requestedWaitMs = deadlineAt !== undefined
1285
+ ? deadlineAt - Date.now()
1286
+ : parsed.timeoutMs ?? (heartbeatMs > 0 ? heartbeatMs : parsed.untilEvent ? 120_000 : 60_000);
1245
1287
  const heartbeatWaitMs = heartbeatMs > 0
1246
1288
  ? Math.max(0, heartbeatMs - (Date.now() - lastHeartbeatAt))
1247
1289
  : requestedWaitMs;
@@ -1263,7 +1305,7 @@ async function runWatch(parsed) {
1263
1305
  emitControlLine((0, watchLines_1.formatNonEntry)('_reconnected', { generation: result.generation }, format));
1264
1306
  failingCode = undefined;
1265
1307
  }
1266
- if (!armed && (parsed.follow || parsed.selfTest)) {
1308
+ if (!armed && (keepsWaiting || parsed.selfTest)) {
1267
1309
  const okLine = (0, watchLines_1.formatNonEntry)('_ok', { generation: result.generation, epoch: result.epoch }, format);
1268
1310
  if (parsed.selfTest)
1269
1311
  emitWatchLine(okLine);
@@ -1273,8 +1315,25 @@ async function runWatch(parsed) {
1273
1315
  if (parsed.selfTest)
1274
1316
  return 0;
1275
1317
  }
1276
- for (const line of (0, watchLines_1.formatWaitResult)(result, format))
1277
- emitWatchLine(line);
1318
+ if (parsed.untilEvent) {
1319
+ // A reset restates current state; it never ends the wait. Nor does the caller's own panel.
1320
+ if (result.reset || result.dropped !== undefined) {
1321
+ for (const line of (0, watchLines_1.formatWaitResult)(result, format))
1322
+ emitControlLine(line);
1323
+ }
1324
+ else {
1325
+ const entries = ownPanelId ? result.entries.filter(entry => entry.panelId !== ownPanelId) : result.entries;
1326
+ if (entries.length > 0) {
1327
+ for (const line of (0, watchLines_1.formatWaitResult)({ ...result, entries }, format))
1328
+ emitWatchLine(line);
1329
+ return 0;
1330
+ }
1331
+ }
1332
+ }
1333
+ else {
1334
+ for (const line of (0, watchLines_1.formatWaitResult)(result, format))
1335
+ emitWatchLine(line);
1336
+ }
1278
1337
  if (heartbeatMs > 0 && Date.now() - lastHeartbeatAt >= heartbeatMs) {
1279
1338
  emitControlLine((0, watchLines_1.formatNonEntry)('_heartbeat', {
1280
1339
  generation: result.generation,
@@ -1284,13 +1343,13 @@ async function runWatch(parsed) {
1284
1343
  }
1285
1344
  if (!watchAs) {
1286
1345
  request.since = result.generation;
1287
- if (parsed.follow)
1346
+ if (keepsWaiting)
1288
1347
  anonymousIdleWindowStartMs = Date.now();
1289
1348
  }
1290
1349
  }
1291
1350
  catch (error) {
1292
1351
  const watchError = error instanceof Error ? error : new Error(String(error));
1293
- if (!parsed.follow || !isRetryableWatchError(watchError)) {
1352
+ if (!keepsWaiting || !isRetryableWatchError(watchError)) {
1294
1353
  return emitWatchFailure(watchError, format);
1295
1354
  }
1296
1355
  const code = watchErrorCode(watchError);
@@ -1301,12 +1360,22 @@ async function runWatch(parsed) {
1301
1360
  failingCode = code;
1302
1361
  await new Promise(resolve => setTimeout(resolve, 1_000));
1303
1362
  }
1304
- } while (parsed.follow);
1363
+ } while (keepsWaiting);
1305
1364
  return 0;
1306
1365
  }
1307
1366
  function emitWatchLine(line) {
1308
1367
  node_process_1.stdout.write(`${line}\n`);
1309
1368
  }
1369
+ /** Codes a stdout write fails with once its reader is gone: a pipe, a socket pair (macOS), or Windows. */
1370
+ const CLOSED_READER_CODES = new Set(['EPIPE', 'ENOTCONN', 'ECONNRESET', 'EOF']);
1371
+ /** A reader that exits early (`| head -1`) closes stdout; the next write then ends the watch cleanly. */
1372
+ function exitWhenReaderCloses() {
1373
+ node_process_1.stdout.on('error', (error) => {
1374
+ if (!CLOSED_READER_CODES.has(error.code ?? ''))
1375
+ throw error;
1376
+ process.exit(0);
1377
+ });
1378
+ }
1310
1379
  /** Names older daemons accept; the daemon itself allows up to 128 characters. */
1311
1380
  const PORTABLE_WATCH_CURSOR_PATTERN = /^[A-Za-z0-9._-]{1,64}$/u;
1312
1381
  /**
@@ -1731,11 +1800,29 @@ async function runReport(parsed, env = process.env) {
1731
1800
  printJson(result);
1732
1801
  }
1733
1802
  else {
1734
- const sessions = result.sessionIds.length > 0 ? ` Recorded on Session ${result.sessionIds.join(', ')}.` : '';
1735
- console.log(`Reported ${(0, watchLines_1.describeReport)(result.report)} for panel ${result.panelId}.${sessions}`);
1803
+ for (const line of describeReportDelivery(result))
1804
+ console.log(line);
1736
1805
  }
1737
1806
  return 0;
1738
1807
  }
1808
+ /**
1809
+ * What `runpane report` prints: the report, who recorded it, and how many watches were waiting.
1810
+ * Zero waiting watchers means nobody is waiting right now, not that the report is lost.
1811
+ */
1812
+ function describeReportDelivery(result) {
1813
+ const sessions = result.sessionIds.length > 0 ? ` Recorded on Session ${result.sessionIds.join(', ')}.` : '';
1814
+ const watchers = result.liveWatchers ?? 0;
1815
+ const delivered = watchers > 0 ? ` Delivered to ${watchers} waiting watcher${watchers === 1 ? '' : 's'}.` : '';
1816
+ const lines = [`Reported ${(0, watchLines_1.describeReport)(result.report)} for panel ${result.panelId}.${sessions}${delivered}`];
1817
+ if (result.sessionIds.length > 0 || watchers > 0)
1818
+ return lines;
1819
+ const stored = `It is stored on the panel (runpane agents status --panel ${result.panelId})`;
1820
+ lines.push(result.liveWatchers === undefined
1821
+ ? `No Session recorded this report. ${stored}, and only watchers that list agent.report receive it.`
1822
+ : `No Session recorded this report and no watcher was waiting for it. ${stored}, `
1823
+ + 'and a watch with a named cursor (runpane watch --as <name> --kinds agent.report) still receives it when it next waits.');
1824
+ return lines;
1825
+ }
1739
1826
  async function runPanelsSubmit(parsed) {
1740
1827
  const request = buildPanelInputRequest(parsed, 'submit');
1741
1828
  await confirmPanelInput(parsed, request, 'submit');
@@ -1843,6 +1930,34 @@ async function runPanelsWait(parsed) {
1843
1930
  printPanelWaitResult(result);
1844
1931
  return result.ok ? 0 : 1;
1845
1932
  }
1933
+ async function runPanelsResume(parsed) {
1934
+ const scopes = [parsed.panelId, parsed.sessionId, parsed.allStopped].filter(Boolean).length;
1935
+ if (scopes !== 1) {
1936
+ throw new Error('runpane panels resume requires exactly one of --panel, --session, or --all-stopped.');
1937
+ }
1938
+ if (parsed.panelId && parsed.concurrency !== undefined) {
1939
+ throw new Error('runpane panels resume --concurrency applies only to --session or --all-stopped.');
1940
+ }
1941
+ await confirmPanelResume(parsed);
1942
+ if (!parsed.panelId) {
1943
+ return runPanelsResumeMany(parsed);
1944
+ }
1945
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:panels:resume', [{
1946
+ panelId: parsed.panelId,
1947
+ waitReady: parsed.waitReady,
1948
+ readyTimeoutMs: parsed.readyTimeoutMs,
1949
+ }], panelResumeResultSchema, {
1950
+ paneDir: parsed.paneDir,
1951
+ timeoutMs: (parsed.readyTimeoutMs ?? 30_000) + 10_000,
1952
+ });
1953
+ if (parsed.json) {
1954
+ printJson(result);
1955
+ }
1956
+ else {
1957
+ printPanelResumeResult(result);
1958
+ }
1959
+ return result.ok ? 0 : 1;
1960
+ }
1846
1961
  async function runAgentsDoctor(parsed) {
1847
1962
  if (!parsed.agent) {
1848
1963
  throw new Error(`runpane agents doctor requires --agent ${contract_1.RUNPANE_CONTRACT.enums.agents.join('|')}.`);
@@ -2255,6 +2370,27 @@ async function confirmPanelInput(parsed, request, command = 'input') {
2255
2370
  rl.close();
2256
2371
  }
2257
2372
  }
2373
+ async function confirmPanelResume(parsed) {
2374
+ if (parsed.yes) {
2375
+ return;
2376
+ }
2377
+ if (!isInteractiveShell()) {
2378
+ throw new Error('runpane panels resume restarts a Pane terminal. Rerun with --yes in non-interactive shells.');
2379
+ }
2380
+ const rl = (0, promises_1.createInterface)({ input: node_process_1.stdin, output: node_process_1.stdout });
2381
+ try {
2382
+ const target = parsed.panelId
2383
+ ? `panel ${parsed.panelId}`
2384
+ : parsed.sessionId ? `every stopped agent panel in Session ${parsed.sessionId}` : 'every stopped agent panel';
2385
+ const answer = (await rl.question(`Resume ${target}? [y/N] `)).trim().toLowerCase();
2386
+ if (answer !== 'y' && answer !== 'yes') {
2387
+ throw new Error('Cancelled.');
2388
+ }
2389
+ }
2390
+ finally {
2391
+ rl.close();
2392
+ }
2393
+ }
2258
2394
  async function confirmPanelSubmitComposer(parsed) {
2259
2395
  if (parsed.yes) {
2260
2396
  return;
@@ -2326,6 +2462,7 @@ function workspaceLabel(kind) {
2326
2462
  'pane.created': 'NEW',
2327
2463
  'pane.gone': 'GONE',
2328
2464
  'panel.exited': 'EXIT',
2465
+ 'panel.stopped': 'STOPPED',
2329
2466
  'pane.associated': 'JOINED',
2330
2467
  'pane.detached': 'LEFT',
2331
2468
  'pr.conflicted': 'PR CONFLICTED',
@@ -2393,12 +2530,8 @@ function printPaneCreateResult(result, dryRun = false, action = 'create') {
2393
2530
  continue;
2394
2531
  }
2395
2532
  console.log(`Created ${item.name ?? `pane ${item.index}`}: session ${item.sessionId ?? 'unknown'} panel ${item.panelId ?? 'unknown'}${worktree}`);
2396
- if (item.readiness) {
2397
- console.log(` Ready: ${item.readiness.ok ? 'yes' : item.readiness.timedOut ? 'timed out' : 'blocked'} after ${item.readiness.elapsedMs}ms`);
2398
- if (item.readiness.blocked) {
2399
- console.log(` Blocked: ${item.readiness.blocked.message}`);
2400
- }
2401
- }
2533
+ if (item.readiness)
2534
+ printReadiness(item.readiness, ' ');
2402
2535
  printInitialInputDelivery(item.initialInput, ' ');
2403
2536
  if (item.association) {
2404
2537
  console.log(item.association.ok
@@ -2406,6 +2539,9 @@ function printPaneCreateResult(result, dryRun = false, action = 'create') {
2406
2539
  : ` Not associated with Session ${item.association.sessionId}: ${item.association.error ?? 'unknown error'}`);
2407
2540
  }
2408
2541
  printPromptNotes(item, ' ');
2542
+ if (item.base?.notice) {
2543
+ console.log(` ! ${item.base.notice}`);
2544
+ }
2409
2545
  if (item.setupQueue) {
2410
2546
  console.log(` ${item.setupQueue.message}`);
2411
2547
  }
@@ -2478,18 +2614,32 @@ function printArchiveCommitEvidence(safetyCheck, print = console.log) {
2478
2614
  }
2479
2615
  function printPanelCreateResult(result) {
2480
2616
  console.log(`Created panel ${result.panelId} in pane ${result.paneId}: ${result.title}${result.active ? ' active' : ' background'}`);
2481
- if (result.readiness) {
2482
- console.log(`Ready: ${result.readiness.ok ? 'yes' : result.readiness.timedOut ? 'timed out' : 'blocked'} after ${result.readiness.elapsedMs}ms`);
2483
- if (result.readiness.blocked) {
2484
- console.log(`Blocked: ${result.readiness.blocked.message}`);
2485
- }
2486
- }
2617
+ if (result.readiness)
2618
+ printReadiness(result.readiness);
2487
2619
  printInitialInputDelivery(result.initialInput);
2488
2620
  printPromptNotes(result);
2489
2621
  if (result.nextCommand) {
2490
2622
  console.log(`Next: ${result.nextCommand}`);
2491
2623
  }
2492
2624
  }
2625
+ /** One-line status for a bulk resume item that resumed but did not become ready. */
2626
+ function notReadySummary(readiness) {
2627
+ if (readiness.blocked)
2628
+ return `blocked: ${readiness.blocked.message}`;
2629
+ const state = readiness.reason?.code === 'command-exited' ? 'command exited' : 'not ready';
2630
+ return readiness.reason ? `${state}: ${readiness.reason.message}` : state;
2631
+ }
2632
+ function printReadiness(readiness, prefix = '') {
2633
+ const state = readiness.ok ? 'yes'
2634
+ : readiness.blocked ? 'blocked'
2635
+ : readiness.reason?.code === 'command-exited' ? 'command exited'
2636
+ : readiness.timedOut ? 'timed out' : 'no';
2637
+ console.log(`${prefix}Ready: ${state} after ${readiness.elapsedMs}ms`);
2638
+ if (readiness.blocked)
2639
+ console.log(`${prefix}Blocked: ${readiness.blocked.message}`);
2640
+ if (readiness.reason)
2641
+ console.log(`${prefix}Why: ${readiness.reason.message}`);
2642
+ }
2493
2643
  function printInitialInputDelivery(initialInput, prefix = '') {
2494
2644
  if (!initialInput) {
2495
2645
  return;
@@ -2511,10 +2661,51 @@ function printInitialInputDelivery(initialInput, prefix = '') {
2511
2661
  console.log(`${prefix}Initial input error: ${initialInput.error.message}`);
2512
2662
  }
2513
2663
  }
2664
+ /** Time the daemon gets to restart every panel in scope, before any readiness wait. */
2665
+ const RESUME_MANY_RESTART_BUDGET_MS = 5 * 60_000;
2666
+ async function runPanelsResumeMany(parsed) {
2667
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:panels:resume-many', [{
2668
+ sessionId: parsed.sessionId,
2669
+ allStopped: parsed.allStopped || undefined,
2670
+ waitReady: parsed.waitReady,
2671
+ readyTimeoutMs: parsed.readyTimeoutMs,
2672
+ concurrency: parsed.concurrency,
2673
+ }], panelResumeManyResultSchema, {
2674
+ paneDir: parsed.paneDir,
2675
+ // The resumed panels wait together, so the wait adds one --ready-timeout-ms however many there are.
2676
+ timeoutMs: RESUME_MANY_RESTART_BUDGET_MS + (parsed.waitReady ? parsed.readyTimeoutMs ?? 30_000 : 0),
2677
+ });
2678
+ if (parsed.json) {
2679
+ printJson(result);
2680
+ }
2681
+ else {
2682
+ const scope = result.scope.kind === 'session' ? `Session ${result.scope.sessionName}` : 'every Pane';
2683
+ const notReady = result.notReady > 0 ? `, ${result.notReady} not ready` : '';
2684
+ console.log(`Resumed ${result.resumed} stopped agent panel${result.resumed === 1 ? '' : 's'} in ${scope}, ${result.concurrency} at a time; ${result.alreadyRunning} already running, ${result.failed} failed${notReady}.`);
2685
+ for (const item of result.items) {
2686
+ const status = item.error
2687
+ ? `failed: ${item.error}`
2688
+ : item.readiness && !item.readiness.ok
2689
+ ? notReadySummary(item.readiness)
2690
+ : item.action ?? 'resumed';
2691
+ console.log(`${item.ok ? 'OK' : 'FAIL'} ${item.paneName} panel ${item.panelId}: ${status}`);
2692
+ }
2693
+ }
2694
+ return result.ok ? 0 : 1;
2695
+ }
2696
+ function printPanelResumeResult(result) {
2697
+ console.log(`${result.action === 'resumed' ? 'Resumed' : 'Already running:'} panel ${result.panelId} in pane ${result.paneId}. ${result.message}`);
2698
+ if (result.readiness)
2699
+ printReadiness(result.readiness);
2700
+ console.log(`Next: ${result.nextCommand}`);
2701
+ }
2514
2702
  function printPanelWaitResult(result) {
2515
2703
  if (result.ok) {
2516
2704
  console.log(`Matched ${result.condition} for panel ${result.panelId} after ${result.elapsedMs}ms.`);
2517
2705
  }
2706
+ else if (result.stopped && !result.timedOut) {
2707
+ console.log(`Panel ${result.panelId} is not running, so it cannot become ${result.condition}.`);
2708
+ }
2518
2709
  else if (result.blocked) {
2519
2710
  console.log(`Blocked waiting for ${result.condition} on panel ${result.panelId}: ${result.blocked.message}`);
2520
2711
  }
@@ -2524,7 +2715,10 @@ function printPanelWaitResult(result) {
2524
2715
  else {
2525
2716
  console.log(`Did not match ${result.condition} for panel ${result.panelId}.`);
2526
2717
  }
2718
+ if (result.reason)
2719
+ console.log(`Why: ${result.reason.message}`);
2527
2720
  const statusParts = [
2721
+ result.state.running === false ? 'stopped' : undefined,
2528
2722
  result.state.initialized ? 'initialized' : 'not-initialized',
2529
2723
  result.state.activityStatus,
2530
2724
  result.state.isCliReady === undefined ? undefined : result.state.isCliReady ? 'cli-ready' : 'cli-not-ready',
@@ -2562,9 +2756,11 @@ function printPanelListResult(result) {
2562
2756
  for (const panel of result.panels) {
2563
2757
  const marker = panel.active ? '*' : ' ';
2564
2758
  const initialized = panel.initialized === undefined ? '' : panel.initialized ? ' initialized' : ' not-initialized';
2759
+ const stopped = panel.running === false ? ' stopped' : '';
2565
2760
  const agent = panel.agentType ? ` ${panel.agentType}` : '';
2566
2761
  const detection = panel.agentDetection && panel.agentDetection !== 'command' ? ` (${panel.agentDetection})` : '';
2567
- console.log(`${marker} ${panel.id}\t${panel.type}\t${panel.title}${initialized}${agent}${detection}`);
2762
+ const resume = panel.resumeId ? ` resume ${panel.resumeId}` : '';
2763
+ console.log(`${marker} ${panel.id}\t${panel.type}\t${panel.title}${initialized}${stopped}${agent}${detection}${resume}`);
2568
2764
  }
2569
2765
  }
2570
2766
  function isInteractiveShell() {