runpane 2.4.136 → 2.4.137

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.
@@ -15,6 +15,9 @@ exports.runSessionsSetAgent = runSessionsSetAgent;
15
15
  exports.runSessionsAssociate = runSessionsAssociate;
16
16
  exports.runSessionsDetach = runSessionsDetach;
17
17
  exports.runSessionsOverview = runSessionsOverview;
18
+ exports.runLockAcquire = runLockAcquire;
19
+ exports.runLockRelease = runLockRelease;
20
+ exports.runLockList = runLockList;
18
21
  exports.runPanesCost = runPanesCost;
19
22
  exports.runWorkspaceState = runWorkspaceState;
20
23
  exports.runWatch = runWatch;
@@ -29,13 +32,19 @@ exports.runPanelsCreate = runPanelsCreate;
29
32
  exports.runPanelsOutput = runPanelsOutput;
30
33
  exports.runPanelsInput = runPanelsInput;
31
34
  exports.runPanelsScreen = runPanelsScreen;
35
+ exports.runPanelsLastMessage = runPanelsLastMessage;
36
+ exports.runReport = runReport;
32
37
  exports.runPanelsSubmit = runPanelsSubmit;
38
+ exports.markSuggestionLine = markSuggestionLine;
39
+ exports.printPromptNotes = printPromptNotes;
33
40
  exports.runPanelsSubmitComposer = runPanelsSubmitComposer;
34
41
  exports.runPanelsWait = runPanelsWait;
35
42
  exports.runAgentsDoctor = runAgentsDoctor;
36
43
  exports.buildPanelInputRequest = buildPanelInputRequest;
37
44
  exports.buildPaneCreateRequest = buildPaneCreateRequest;
45
+ const node_crypto_1 = require("node:crypto");
38
46
  const node_fs_1 = __importDefault(require("node:fs"));
47
+ const node_path_1 = __importDefault(require("node:path"));
39
48
  const node_process_1 = require("node:process");
40
49
  const promises_1 = require("node:readline/promises");
41
50
  const boundaryDecoder_1 = require("./boundaryDecoder");
@@ -65,6 +74,7 @@ const paneSummarySchema = boundaryDecoder_1.boundary.object({
65
74
  name: boundaryDecoder_1.boundary.string,
66
75
  status: boundaryDecoder_1.boundary.string,
67
76
  agentStatus: boundaryDecoder_1.boundary.enumeration('active', 'idle'),
77
+ agentState: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('ready', 'working', 'blocked', 'none')),
68
78
  worktreePath: boundaryDecoder_1.boundary.string,
69
79
  repoId: boundaryDecoder_1.boundary.number,
70
80
  repoName: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
@@ -76,7 +86,7 @@ const paneSummarySchema = boundaryDecoder_1.boundary.object({
76
86
  ownership: boundaryDecoder_1.boundary.enumeration('pane', 'external'),
77
87
  });
78
88
  const panelBlockedSchema = boundaryDecoder_1.boundary.object({
79
- kind: boundaryDecoder_1.boundary.enumeration('codex-update', 'agent-prompt', 'submission_unverified', 'unknown'),
89
+ kind: boundaryDecoder_1.boundary.enumeration('codex-update', 'agent-prompt', 'submission_unverified', 'composer-unknown', 'unknown'),
80
90
  message: boundaryDecoder_1.boundary.string,
81
91
  suggestedCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
82
92
  });
@@ -100,6 +110,14 @@ const panelReadinessSchema = boundaryDecoder_1.boundary.object({
100
110
  nextCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
101
111
  });
102
112
  const verificationSchema = boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('observed', 'unverifiable'));
113
+ const deliverySchema = boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.object({
114
+ state: boundaryDecoder_1.boundary.enumeration('taken', 'queued', 'in-composer', 'unknown'),
115
+ evidence: boundaryDecoder_1.boundary.enumeration('transcript', 'screen', 'argv'),
116
+ }));
117
+ const promptWarningsSchema = boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.object({
118
+ code: boundaryDecoder_1.boundary.enumeration('leading-bang-runs-shell', 'leading-hash-memory', 'leading-slash-command', 'leading-at-mention'),
119
+ message: boundaryDecoder_1.boundary.string,
120
+ })));
103
121
  const initialInputSchema = boundaryDecoder_1.boundary.object({
104
122
  delivered: boundaryDecoder_1.boundary.boolean,
105
123
  submitted: boundaryDecoder_1.boundary.boolean,
@@ -108,6 +126,7 @@ const initialInputSchema = boundaryDecoder_1.boundary.object({
108
126
  sequenceName: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('codex-ctrl-enter-cr', 'enter-cr', 'argument')),
109
127
  verifiedSubmitted: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
110
128
  verification: verificationSchema,
129
+ delivery: deliverySchema,
111
130
  staged: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
112
131
  attempts: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
113
132
  sentAt: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
@@ -130,7 +149,52 @@ const archiveSafetySchema = boundaryDecoder_1.boundary.object({
130
149
  sha: boundaryDecoder_1.boundary.string,
131
150
  subject: boundaryDecoder_1.boundary.string,
132
151
  }))),
152
+ reason: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('external-worktree', 'main-repo', 'missing-project-context', 'git-error')),
153
+ worktreeWillRemain: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.literal(true)),
154
+ upstreamGone: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
155
+ mergedViaPr: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.object({
156
+ number: boundaryDecoder_1.boundary.number,
157
+ headOid: boundaryDecoder_1.boundary.string,
158
+ })),
159
+ });
160
+ const agentReportFields = {
161
+ state: boundaryDecoder_1.boundary.enumeration('ready', 'blocked', 'failed', 'done'),
162
+ pr: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
163
+ head: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
164
+ summary: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
165
+ summaryTruncated: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.literal(true)),
166
+ summaryPath: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
167
+ question: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
168
+ reportedAt: boundaryDecoder_1.boundary.string,
169
+ };
170
+ const agentReportSchema = boundaryDecoder_1.boundary.object(agentReportFields);
171
+ const reportResultSchema = boundaryDecoder_1.boundary.object({
172
+ ok: boundaryDecoder_1.boundary.literal(true),
173
+ generation: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
174
+ paneId: boundaryDecoder_1.boundary.string,
175
+ panelId: boundaryDecoder_1.boundary.string,
176
+ report: agentReportSchema,
177
+ sessionIds: boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.string),
133
178
  });
179
+ const panelLastMessageResultSchema = boundaryDecoder_1.boundary.union(boundaryDecoder_1.boundary.object({
180
+ ok: boundaryDecoder_1.boundary.literal(true),
181
+ panelId: boundaryDecoder_1.boundary.string,
182
+ paneId: boundaryDecoder_1.boundary.string,
183
+ agentType: boundaryDecoder_1.boundary.enumeration('claude', 'codex'),
184
+ text: boundaryDecoder_1.boundary.string,
185
+ length: boundaryDecoder_1.boundary.number,
186
+ limit: boundaryDecoder_1.boundary.number,
187
+ truncated: boundaryDecoder_1.boundary.boolean,
188
+ }), boundaryDecoder_1.boundary.object({
189
+ ok: boundaryDecoder_1.boundary.literal(false),
190
+ panelId: boundaryDecoder_1.boundary.string,
191
+ paneId: boundaryDecoder_1.boundary.string,
192
+ reason: boundaryDecoder_1.boundary.literal('transcript-unavailable'),
193
+ message: boundaryDecoder_1.boundary.string,
194
+ }));
195
+ const archiveBlockCodeSchema = boundaryDecoder_1.boundary.enumeration('uncommitted-changes', 'unpushed-commits', 'uncommitted-and-unpushed', 'status-unknown');
196
+ const worktreeCleanupSchema = boundaryDecoder_1.boundary.enumeration('completed', 'failed', 'timeout', 'not-applicable');
197
+ const trashDeletionSchema = boundaryDecoder_1.boundary.enumeration('pending', 'done');
134
198
  const panelSummarySchema = boundaryDecoder_1.boundary.object({
135
199
  id: boundaryDecoder_1.boundary.string,
136
200
  panelId: boundaryDecoder_1.boundary.string,
@@ -140,10 +204,13 @@ const panelSummarySchema = boundaryDecoder_1.boundary.object({
140
204
  active: boundaryDecoder_1.boundary.boolean,
141
205
  initialized: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
142
206
  agentType: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
207
+ agentDetection: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('declared', 'command', 'process', 'screen')),
208
+ launchCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
143
209
  isCliPanel: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
144
210
  position: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
145
211
  createdAt: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
146
212
  lastActiveAt: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
213
+ report: boundaryDecoder_1.boundary.optional(agentReportSchema),
147
214
  });
148
215
  const repoListResultSchema = boundaryDecoder_1.boundary.object({
149
216
  ok: boundaryDecoder_1.boundary.literal(true),
@@ -256,6 +323,55 @@ const orchestrationPaneOverviewSchema = boundaryDecoder_1.boundary.object({
256
323
  prTitle: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
257
324
  prState: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
258
325
  })),
326
+ report: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.object({ ...agentReportFields, panelId: boundaryDecoder_1.boundary.nonEmptyString })),
327
+ });
328
+ const lockOwnerSchema = boundaryDecoder_1.boundary.object({
329
+ kind: boundaryDecoder_1.boundary.enumeration('pane', 'external'),
330
+ paneId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.nonEmptyString),
331
+ panelId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.nonEmptyString),
332
+ label: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
333
+ });
334
+ const lockRecordSchema = boundaryDecoder_1.boundary.object({
335
+ name: boundaryDecoder_1.boundary.nonEmptyString,
336
+ scope: boundaryDecoder_1.boundary.enumeration('session', 'global'),
337
+ sessionId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.nonEmptyString),
338
+ owner: lockOwnerSchema,
339
+ note: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
340
+ acquiredAt: boundaryDecoder_1.boundary.nonEmptyString,
341
+ expiresAt: boundaryDecoder_1.boundary.nonEmptyString,
342
+ ttlMs: boundaryDecoder_1.boundary.number,
343
+ });
344
+ const lockAcquireResultSchema = boundaryDecoder_1.boundary.union(boundaryDecoder_1.boundary.object({
345
+ ok: boundaryDecoder_1.boundary.literal(true),
346
+ acquired: boundaryDecoder_1.boundary.literal(true),
347
+ renewed: boundaryDecoder_1.boundary.boolean,
348
+ waitedMs: boundaryDecoder_1.boundary.number,
349
+ lock: lockRecordSchema,
350
+ }), boundaryDecoder_1.boundary.object({
351
+ ok: boundaryDecoder_1.boundary.literal(false),
352
+ acquired: boundaryDecoder_1.boundary.literal(false),
353
+ timedOut: boundaryDecoder_1.boundary.boolean,
354
+ waitedMs: boundaryDecoder_1.boundary.number,
355
+ heldBy: lockOwnerSchema,
356
+ expiresAt: boundaryDecoder_1.boundary.nonEmptyString,
357
+ lock: lockRecordSchema,
358
+ }));
359
+ const lockReleaseResultSchema = boundaryDecoder_1.boundary.union(boundaryDecoder_1.boundary.object({
360
+ ok: boundaryDecoder_1.boundary.literal(true),
361
+ released: boundaryDecoder_1.boundary.boolean,
362
+ forced: boundaryDecoder_1.boundary.boolean,
363
+ lock: boundaryDecoder_1.boundary.optional(lockRecordSchema),
364
+ }), boundaryDecoder_1.boundary.object({
365
+ ok: boundaryDecoder_1.boundary.literal(false),
366
+ released: boundaryDecoder_1.boundary.literal(false),
367
+ reason: boundaryDecoder_1.boundary.literal('not-owner'),
368
+ heldBy: lockOwnerSchema,
369
+ expiresAt: boundaryDecoder_1.boundary.nonEmptyString,
370
+ lock: lockRecordSchema,
371
+ }));
372
+ const lockListResultSchema = boundaryDecoder_1.boundary.object({
373
+ ok: boundaryDecoder_1.boundary.literal(true),
374
+ locks: boundaryDecoder_1.boundary.array(lockRecordSchema),
259
375
  });
260
376
  const runpaneSessionOverviewResultSchema = boundaryDecoder_1.boundary.object({
261
377
  ok: boundaryDecoder_1.boundary.literal(true),
@@ -268,6 +384,7 @@ const runpaneSessionOverviewResultSchema = boundaryDecoder_1.boundary.object({
268
384
  freshness: boundaryDecoder_1.boundary.enumeration('current', 'stale'),
269
385
  })),
270
386
  refreshedAt: boundaryDecoder_1.boundary.nonEmptyString,
387
+ locks: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(lockRecordSchema)),
271
388
  });
272
389
  function orchestrationReportSchemaFields() {
273
390
  return {
@@ -367,6 +484,8 @@ exports.paneCreateResultSchema = boundaryDecoder_1.boundary.object({
367
484
  ok: boundaryDecoder_1.boundary.boolean,
368
485
  error: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
369
486
  })),
487
+ promptFile: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
488
+ warnings: promptWarningsSchema,
370
489
  }), boundaryDecoder_1.boundary.object({
371
490
  ok: boundaryDecoder_1.boundary.literal(false),
372
491
  index: boundaryDecoder_1.boundary.number,
@@ -385,7 +504,7 @@ const paneArchiveResultSchema = boundaryDecoder_1.boundary.union(boundaryDecoder
385
504
  generation: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
386
505
  paneId: boundaryDecoder_1.boundary.string,
387
506
  blocked: boundaryDecoder_1.boundary.object({
388
- code: boundaryDecoder_1.boundary.enumeration('uncommitted-changes', 'unpushed-commits', 'uncommitted-and-unpushed', 'status-unknown'),
507
+ code: archiveBlockCodeSchema,
389
508
  message: boundaryDecoder_1.boundary.string,
390
509
  safetyCheck: archiveSafetySchema,
391
510
  }),
@@ -398,7 +517,7 @@ const paneArchiveResultSchema = boundaryDecoder_1.boundary.union(boundaryDecoder
398
517
  forced: boundaryDecoder_1.boundary.boolean,
399
518
  safetyCheck: archiveSafetySchema,
400
519
  blocked: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.object({
401
- code: boundaryDecoder_1.boundary.enumeration('uncommitted-changes', 'unpushed-commits', 'uncommitted-and-unpushed', 'status-unknown'),
520
+ code: archiveBlockCodeSchema,
402
521
  message: boundaryDecoder_1.boundary.string,
403
522
  safetyCheck: archiveSafetySchema,
404
523
  })),
@@ -408,10 +527,35 @@ const paneArchiveResultSchema = boundaryDecoder_1.boundary.union(boundaryDecoder
408
527
  paneId: boundaryDecoder_1.boundary.string,
409
528
  archived: boundaryDecoder_1.boundary.literal(true),
410
529
  forced: boundaryDecoder_1.boundary.boolean,
411
- worktreeCleanup: boundaryDecoder_1.boundary.enumeration('completed', 'failed', 'timeout', 'not-applicable'),
530
+ worktreeCleanup: worktreeCleanupSchema,
531
+ trashDeletion: boundaryDecoder_1.boundary.optional(trashDeletionSchema),
412
532
  worktreePath: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
413
533
  safetyCheck: archiveSafetySchema,
414
534
  }));
535
+ const paneArchiveBulkResultSchema = boundaryDecoder_1.boundary.object({
536
+ ok: boundaryDecoder_1.boundary.boolean,
537
+ sessionId: boundaryDecoder_1.boundary.string,
538
+ merged: boundaryDecoder_1.boundary.literal(true),
539
+ dryRun: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.literal(true)),
540
+ removeWorktree: boundaryDecoder_1.boundary.boolean,
541
+ archived: boundaryDecoder_1.boundary.number,
542
+ skipped: boundaryDecoder_1.boundary.number,
543
+ failed: boundaryDecoder_1.boundary.number,
544
+ items: boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.object({
545
+ paneId: boundaryDecoder_1.boundary.string,
546
+ name: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
547
+ outcome: boundaryDecoder_1.boundary.enumeration('archived', 'would-archive', 'skipped', 'failed'),
548
+ skipped: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.object({
549
+ code: boundaryDecoder_1.boundary.enumeration('uncommitted-changes', 'unpushed-commits', 'uncommitted-and-unpushed', 'status-unknown', 'missing-pane', 'already-archived', 'main-repo'),
550
+ message: boundaryDecoder_1.boundary.string,
551
+ })),
552
+ error: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
553
+ safetyCheck: boundaryDecoder_1.boundary.optional(archiveSafetySchema),
554
+ worktreeCleanup: boundaryDecoder_1.boundary.optional(worktreeCleanupSchema),
555
+ trashDeletion: boundaryDecoder_1.boundary.optional(trashDeletionSchema),
556
+ worktreePath: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
557
+ })),
558
+ });
415
559
  const panePinResultSchema = boundaryDecoder_1.boundary.object({
416
560
  ok: boundaryDecoder_1.boundary.literal(true),
417
561
  generation: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
@@ -452,6 +596,8 @@ const panelCreateResultSchema = boundaryDecoder_1.boundary.object({
452
596
  }),
453
597
  readiness: boundaryDecoder_1.boundary.optional(panelReadinessSchema),
454
598
  initialInput: boundaryDecoder_1.boundary.optional(initialInputSchema),
599
+ promptFile: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
600
+ warnings: promptWarningsSchema,
455
601
  nextCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
456
602
  });
457
603
  const panelOutputResultSchema = boundaryDecoder_1.boundary.object({
@@ -490,6 +636,7 @@ exports.panelScreenResultSchema = boundaryDecoder_1.boundary.object({
490
636
  composer: boundaryDecoder_1.boundary.object({
491
637
  isPresent: boundaryDecoder_1.boundary.boolean,
492
638
  hasUndeliveredText: boundaryDecoder_1.boundary.boolean,
639
+ ghostText: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
493
640
  }),
494
641
  nextCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
495
642
  });
@@ -503,8 +650,11 @@ exports.panelSubmitResultSchema = boundaryDecoder_1.boundary.object({
503
650
  sequenceName: boundaryDecoder_1.boundary.enumeration('codex-ctrl-enter-cr', 'enter-cr', 'tab'),
504
651
  verifiedSubmitted: boundaryDecoder_1.boundary.boolean,
505
652
  verification: verificationSchema,
653
+ delivery: deliverySchema,
506
654
  sentAt: boundaryDecoder_1.boundary.string,
507
655
  blocked: boundaryDecoder_1.boundary.optional(panelBlockedSchema),
656
+ promptFile: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
657
+ warnings: promptWarningsSchema,
508
658
  nextCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
509
659
  });
510
660
  const panelSubmitComposerResultSchema = boundaryDecoder_1.boundary.object({
@@ -517,6 +667,7 @@ const panelSubmitComposerResultSchema = boundaryDecoder_1.boundary.object({
517
667
  sequenceName: boundaryDecoder_1.boundary.enumeration('codex-ctrl-enter-cr', 'enter-cr', 'tab'),
518
668
  verifiedSubmitted: boundaryDecoder_1.boundary.boolean,
519
669
  verification: verificationSchema,
670
+ delivery: deliverySchema,
520
671
  sentAt: boundaryDecoder_1.boundary.string,
521
672
  blocked: boundaryDecoder_1.boundary.optional(panelBlockedSchema),
522
673
  nextCommand: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
@@ -554,7 +705,7 @@ const agentDoctorResultSchema = boundaryDecoder_1.boundary.object({
554
705
  })),
555
706
  warnings: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.string)),
556
707
  });
557
- const workspaceEntryKindSchema = boundaryDecoder_1.boundary.enumeration('agent.ready', 'agent.busy', 'agent.blocked', 'agent.unknown', 'agent.idle', 'pane.created', 'pane.gone', 'panel.exited');
708
+ 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');
558
709
  const agentStateSchema = boundaryDecoder_1.boundary.enumeration('blocked', 'working', 'idle', 'unknown');
559
710
  const workspacePanelSummarySchema = boundaryDecoder_1.boundary.object({
560
711
  panelId: boundaryDecoder_1.boundary.string,
@@ -576,7 +727,7 @@ const workspaceEntrySchema = boundaryDecoder_1.boundary.object({
576
727
  agentType: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
577
728
  from: boundaryDecoder_1.boundary.optional(agentStateSchema),
578
729
  to: boundaryDecoder_1.boundary.optional(agentStateSchema),
579
- source: boundaryDecoder_1.boundary.enumeration('agent', 'exit', 'session'),
730
+ source: boundaryDecoder_1.boundary.enumeration('agent', 'exit', 'session', 'github'),
580
731
  reason: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.nullable(boundaryDecoder_1.boundary.string)),
581
732
  settledMs: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
582
733
  idleMs: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
@@ -585,7 +736,14 @@ const workspaceEntrySchema = boundaryDecoder_1.boundary.object({
585
736
  heldInputPresent: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
586
737
  exitCode: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
587
738
  baseline: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.literal(true)),
739
+ replay: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.literal(true)),
588
740
  changedWhileAway: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
741
+ sessionId: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
742
+ sessionName: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
743
+ pr: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.object({ number: boundaryDecoder_1.boundary.number, url: boundaryDecoder_1.boundary.string, headOid: boundaryDecoder_1.boundary.string })),
744
+ checks: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('passed', 'failed')),
745
+ failingChecks: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.string)),
746
+ report: boundaryDecoder_1.boundary.optional(agentReportSchema),
589
747
  panels: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.array(workspacePanelSummarySchema)),
590
748
  });
591
749
  exports.workspaceStateResultSchema = boundaryDecoder_1.boundary.object({
@@ -604,20 +762,24 @@ const workspaceWaitResultSchema = boundaryDecoder_1.boundary.object({
604
762
  reset: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.object({
605
763
  reason: boundaryDecoder_1.boundary.enumeration('first-use', 'epoch-changed', 'cursor-truncated', 'unknown-consumer'),
606
764
  })),
765
+ session: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.object({ id: boundaryDecoder_1.boundary.string, name: boundaryDecoder_1.boundary.string })),
607
766
  nextCommand: boundaryDecoder_1.boundary.string,
608
767
  });
609
768
  const repoSelectorSchema = boundaryDecoder_1.boundary.union(boundaryDecoder_1.boundary.nonEmptyString, boundaryDecoder_1.boundary.object({ id: boundaryDecoder_1.boundary.number }), boundaryDecoder_1.boundary.object({ path: boundaryDecoder_1.boundary.string }), boundaryDecoder_1.boundary.object({ name: boundaryDecoder_1.boundary.string }), boundaryDecoder_1.boundary.object({ active: boundaryDecoder_1.boundary.literal(true) }));
610
769
  const paneToolInputSchema = boundaryDecoder_1.boundary.object({
611
770
  agent: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
612
771
  command: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
772
+ agentType: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
613
773
  title: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
614
774
  initialInput: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
775
+ initialInputAsFilePointer: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
615
776
  });
616
777
  const paneCreateRequestInputSchema = boundaryDecoder_1.boundary.object({
617
778
  repo: repoSelectorSchema,
618
779
  panes: boundaryDecoder_1.boundary.array(boundaryDecoder_1.boundary.object({
619
780
  name: boundaryDecoder_1.boundary.string,
620
781
  worktreeName: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
782
+ branch: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
621
783
  baseBranch: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
622
784
  sessionPrompt: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.string),
623
785
  pinned: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
@@ -646,6 +808,8 @@ const paneAdoptRequestInputSchema = boundaryDecoder_1.boundary.object({
646
808
  launch: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
647
809
  })),
648
810
  dryRun: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
811
+ waitReady: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
812
+ readyTimeoutMs: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.number),
649
813
  noFocus: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
650
814
  focus: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.boolean),
651
815
  source: boundaryDecoder_1.boundary.optional(boundaryDecoder_1.boundary.enumeration('user', 'agent')),
@@ -775,9 +939,123 @@ async function runSessionsOverview(parsed) {
775
939
  for (const pane of result.panes) {
776
940
  const details = pane.missing ? 'missing' : pane.archived ? 'archived' : pane.panels.map(panel => `${panel.title}=${panel.state}`).join(', ') || 'no terminal panels';
777
941
  console.log(` ${pane.name}: ${details}`);
942
+ if (pane.report) {
943
+ console.log(` report ${(0, watchLines_1.describeReport)(pane.report)} (panel ${pane.report.panelId}, ${pane.report.reportedAt})`);
944
+ }
945
+ }
946
+ for (const lock of result.locks ?? []) {
947
+ console.log(` lock ${formatLockLine(lock)}`);
948
+ }
949
+ return 0;
950
+ }
951
+ /** One daemon call waits at most this long; longer waits chain calls, each blocking in the daemon. */
952
+ const LOCK_WAIT_PER_CALL_MS = 120_000;
953
+ async function runLockAcquire(parsed) {
954
+ const name = requireLockName(parsed, 'acquire');
955
+ if (parsed.lockTtlMs === undefined)
956
+ throw new Error('runpane lock acquire requires --ttl <duration>, such as --ttl 30m.');
957
+ const request = { name, ttlMs: parsed.lockTtlMs, note: parsed.note, owner: lockOwnerFromParsed(parsed, false) };
958
+ const waitMs = parsed.lockWaitMs ?? 0;
959
+ const startedAt = Date.now();
960
+ let result;
961
+ for (;;) {
962
+ const callWaitMs = Math.min(Math.max(0, waitMs - (Date.now() - startedAt)), LOCK_WAIT_PER_CALL_MS);
963
+ result = await (0, daemonClient_1.invokeDaemon)('runpane:locks:acquire', [{ ...request, waitMs: callWaitMs }], lockAcquireResultSchema, {
964
+ paneDir: parsed.paneDir,
965
+ timeoutMs: callWaitMs + 15_000,
966
+ });
967
+ // Only a call that waited out its whole window without the lock coming free chains another.
968
+ if (result.ok || !result.timedOut || Date.now() - startedAt >= waitMs)
969
+ break;
970
+ }
971
+ const final = { ...result, waitedMs: Date.now() - startedAt };
972
+ if (parsed.json) {
973
+ printJson(final);
974
+ }
975
+ else if (final.ok) {
976
+ console.log(`${final.renewed ? 'Renewed' : 'Acquired'} lock ${formatLockLine(final.lock)}`);
977
+ }
978
+ else {
979
+ console.log(`Lock ${final.lock.name} is held by ${formatLockOwner(final.heldBy)} until ${final.expiresAt}${final.lock.note ? ` (${final.lock.note})` : ''}.`);
980
+ }
981
+ return final.ok ? 0 : 1;
982
+ }
983
+ async function runLockRelease(parsed) {
984
+ const name = requireLockName(parsed, 'release');
985
+ const request = {
986
+ name,
987
+ force: parsed.force || undefined,
988
+ sessionId: parsed.sessionId?.trim() || undefined,
989
+ owner: lockOwnerFromParsed(parsed, parsed.force === true),
990
+ };
991
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:locks:release', [request], lockReleaseResultSchema, { paneDir: parsed.paneDir });
992
+ if (parsed.json) {
993
+ printJson(result);
994
+ }
995
+ else if (!result.ok) {
996
+ console.log(`Lock ${name} is held by ${formatLockOwner(result.heldBy)} until ${result.expiresAt}; only its owner can release it. Rerun with --force to release it anyway.`);
997
+ }
998
+ else if (result.released) {
999
+ console.log(`${result.forced ? 'Force-released' : 'Released'} lock ${name}.`);
778
1000
  }
1001
+ else {
1002
+ console.log(`Lock ${name} was not held.`);
1003
+ }
1004
+ return result.ok ? 0 : 1;
1005
+ }
1006
+ async function runLockList(parsed) {
1007
+ const sessionId = parsed.sessionId?.trim() || undefined;
1008
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:locks:list', [{ sessionId }], lockListResultSchema, { paneDir: parsed.paneDir });
1009
+ if (parsed.json) {
1010
+ printJson(result);
1011
+ return 0;
1012
+ }
1013
+ for (const lock of result.locks)
1014
+ console.log(formatLockLine(lock));
1015
+ if (result.locks.length === 0)
1016
+ console.log('No locks held.');
779
1017
  return 0;
780
1018
  }
1019
+ function requireLockName(parsed, action) {
1020
+ const name = parsed.name?.trim();
1021
+ if (!name)
1022
+ throw new Error(`runpane lock ${action} requires --name <name>.`);
1023
+ return name;
1024
+ }
1025
+ /**
1026
+ * The caller owns the lock: --pane/--panel when given, else the Pane terminal
1027
+ * it runs in ($PANE_SESSION_ID/$PANE_PANEL_ID). Outside Pane, --note names the owner.
1028
+ */
1029
+ function lockOwnerFromParsed(parsed, forced) {
1030
+ const explicit = Boolean(parsed.paneId || parsed.panelId);
1031
+ const paneId = explicit ? parsed.paneId : process.env.PANE_SESSION_ID?.trim() || undefined;
1032
+ const panelId = explicit ? parsed.panelId : process.env.PANE_PANEL_ID?.trim() || undefined;
1033
+ const owner = {};
1034
+ if (paneId || panelId) {
1035
+ if (paneId)
1036
+ owner.paneId = paneId;
1037
+ if (panelId)
1038
+ owner.panelId = panelId;
1039
+ return owner;
1040
+ }
1041
+ const label = parsed.note?.trim();
1042
+ if (!label && !forced) {
1043
+ throw new Error('Outside a Pane terminal, pass --note <text> to say who holds the lock (or --pane/--panel to act for a Pane).');
1044
+ }
1045
+ if (label)
1046
+ owner.label = label;
1047
+ return owner;
1048
+ }
1049
+ function formatLockOwner(owner) {
1050
+ if (owner.kind === 'external')
1051
+ return `external "${owner.label ?? ''}"`;
1052
+ return owner.panelId ? `pane ${owner.paneId} panel ${owner.panelId}` : `pane ${owner.paneId}`;
1053
+ }
1054
+ function formatLockLine(lock) {
1055
+ const scope = lock.scope === 'session' ? `session ${lock.sessionId}` : 'global';
1056
+ const note = lock.note ? ` (${lock.note})` : '';
1057
+ return `${lock.name} [${scope}] held by ${formatLockOwner(lock.owner)} until ${lock.expiresAt}${note}`;
1058
+ }
781
1059
  function sessionSelectorFromParsed(parsed) {
782
1060
  const sessionId = parsed.sessionId?.trim();
783
1061
  if (!sessionId)
@@ -867,12 +1145,21 @@ async function runWatch(parsed) {
867
1145
  ? undefined
868
1146
  : parsed.agentsOnly || parsed.follow ? true : undefined;
869
1147
  const includeHeldInput = parsed.includeHeldInput && !parsed.noHeldInput ? true : undefined;
1148
+ // Lines mode turns presence into STUCK; JSON mode passes heldInputPresent through as the equivalent.
870
1149
  const includeHeldInputPresence = defaults.includeHeldInputPresence
871
- && !parsed.noHeldInput && parsed.follow && format === 'lines' ? true : undefined;
1150
+ && !parsed.noHeldInput && parsed.follow ? true : undefined;
872
1151
  const cadenceValueFlagPresent = (0, commands_1.hasCadenceValueFlag)(parsed);
873
1152
  // Cadence state lives in the daemon per named consumer, so an anonymous follower names itself.
1153
+ // A Session watch is named after the Session, so it survives an orchestrator agent switch.
1154
+ const sessionCursor = parsed.sessionId ? sessionWatchCursorName(parsed.sessionId) : undefined;
1155
+ const panelCursor = process.env.PANE_PANEL_ID ? derivedWatchCursorName('panel', process.env.PANE_PANEL_ID) : undefined;
874
1156
  const watchAs = parsed.watchAs
875
- ?? (parsed.follow ? process.env.PANE_PANEL_ID || (cadenceValueFlagPresent ? `follow-${process.pid}` : undefined) : undefined);
1157
+ ?? (parsed.follow ? sessionCursor || panelCursor || (cadenceValueFlagPresent ? `follow-${process.pid}` : undefined) : undefined);
1158
+ // --quiet drops lines that only prove liveness; --self-test still prints its WATCH OK result.
1159
+ const emitControlLine = (line) => {
1160
+ if (!parsed.quiet)
1161
+ emitWatchLine(line);
1162
+ };
876
1163
  const request = {
877
1164
  as: watchAs,
878
1165
  since: parsed.watchSince,
@@ -881,6 +1168,8 @@ async function runWatch(parsed) {
881
1168
  limit: parsed.limit,
882
1169
  kinds: parsed.watchKinds,
883
1170
  paneIds: parsed.watchPaneIds,
1171
+ // The daemon resolves the Session (id or exact name) and re-reads its Panes on every read.
1172
+ session: parsed.sessionId,
884
1173
  excludePaneIds: parsed.watchExcludePaneIds,
885
1174
  repo: parsed.repo,
886
1175
  nameContains: parsed.nameContains,
@@ -914,12 +1203,20 @@ async function runWatch(parsed) {
914
1203
  timeoutMs: timeoutMs + 5_000,
915
1204
  eventInclude: [],
916
1205
  });
1206
+ if (request.session && !result.session) {
1207
+ // An older daemon ignores the unknown field and would watch every Pane instead.
1208
+ throw new Error('This Pane daemon does not support runpane watch --session; update Pane, or pass one --pane per Session Pane.');
1209
+ }
917
1210
  if (failingCode) {
918
- emitWatchLine((0, watchLines_1.formatNonEntry)('_reconnected', { generation: result.generation }, format));
1211
+ emitControlLine((0, watchLines_1.formatNonEntry)('_reconnected', { generation: result.generation }, format));
919
1212
  failingCode = undefined;
920
1213
  }
921
1214
  if (!armed && (parsed.follow || parsed.selfTest)) {
922
- emitWatchLine((0, watchLines_1.formatNonEntry)('_ok', { generation: result.generation, epoch: result.epoch }, format));
1215
+ const okLine = (0, watchLines_1.formatNonEntry)('_ok', { generation: result.generation, epoch: result.epoch }, format);
1216
+ if (parsed.selfTest)
1217
+ emitWatchLine(okLine);
1218
+ else
1219
+ emitControlLine(okLine);
923
1220
  armed = true;
924
1221
  if (parsed.selfTest)
925
1222
  return 0;
@@ -927,7 +1224,7 @@ async function runWatch(parsed) {
927
1224
  for (const line of (0, watchLines_1.formatWaitResult)(result, format))
928
1225
  emitWatchLine(line);
929
1226
  if (heartbeatMs > 0 && Date.now() - lastHeartbeatAt >= heartbeatMs) {
930
- emitWatchLine((0, watchLines_1.formatNonEntry)('_heartbeat', {
1227
+ emitControlLine((0, watchLines_1.formatNonEntry)('_heartbeat', {
931
1228
  generation: result.generation,
932
1229
  at: new Date().toISOString(),
933
1230
  }, format));
@@ -958,6 +1255,27 @@ async function runWatch(parsed) {
958
1255
  function emitWatchLine(line) {
959
1256
  node_process_1.stdout.write(`${line}\n`);
960
1257
  }
1258
+ /** Names older daemons accept; the daemon itself allows up to 128 characters. */
1259
+ const PORTABLE_WATCH_CURSOR_PATTERN = /^[A-Za-z0-9._-]{1,64}$/u;
1260
+ /**
1261
+ * Returns a derived watch cursor name (one runpane builds from an ID, not one the user typed)
1262
+ * that every daemon accepts. A name that is too long or has other characters becomes
1263
+ * `<prefix>-<first 12 hex chars of its sha256>`, which is stable across runs.
1264
+ */
1265
+ function derivedWatchCursorName(prefix, name) {
1266
+ if (PORTABLE_WATCH_CURSOR_PATTERN.test(name))
1267
+ return name;
1268
+ return `${prefix}-${(0, node_crypto_1.createHash)('sha256').update(name).digest('hex').slice(0, 12)}`;
1269
+ }
1270
+ /**
1271
+ * Default cursor for `watch --session`: `session-<uuid>` for a Session id
1272
+ * (`__orchestration_session_<uuid>__`), `session-<name>` for a name, shortened like any
1273
+ * derived name when it is longer than 64 characters or has other characters.
1274
+ */
1275
+ function sessionWatchCursorName(session) {
1276
+ const uuid = /^__orchestration_session_(.+)__$/u.exec(session)?.[1];
1277
+ return derivedWatchCursorName('session', `session-${uuid ?? session}`);
1278
+ }
961
1279
  function watchErrorCode(error) {
962
1280
  return error instanceof daemonClient_1.PaneDaemonClientError ? error.code ?? 'PaneDaemonClientError' : error.name || 'Error';
963
1281
  }
@@ -1012,6 +1330,9 @@ async function runPanesAdopt(parsed) {
1012
1330
  if (!parsed.repo || !parsed.repoPath || !parsed.name) {
1013
1331
  throw new Error('runpane panes adopt requires --repo, --path, and --name.');
1014
1332
  }
1333
+ if (!parsed.launch && (parsed.initialInput !== undefined || parsed.initialInputFile !== undefined || parsed.waitReady)) {
1334
+ throw new Error('runpane panes adopt only sends a prompt or waits for readiness with --launch. Add --launch to start the agent now.');
1335
+ }
1015
1336
  const tool = await buildToolSpec(parsed, 'panes adopt');
1016
1337
  request = {
1017
1338
  repo: parsed.repo,
@@ -1026,6 +1347,8 @@ async function runPanesAdopt(parsed) {
1026
1347
  launch: parsed.launch || undefined,
1027
1348
  }],
1028
1349
  dryRun: parsed.dryRun || undefined,
1350
+ waitReady: parsed.waitReady || undefined,
1351
+ readyTimeoutMs: parsed.readyTimeoutMs,
1029
1352
  noFocus: parsed.noFocus || undefined,
1030
1353
  focus: parsed.focus || undefined,
1031
1354
  source: parsed.source === 'user' || parsed.source === 'agent' ? parsed.source : undefined,
@@ -1035,7 +1358,7 @@ async function runPanesAdopt(parsed) {
1035
1358
  await confirmPaneAdopt(parsed, request);
1036
1359
  const result = await (0, daemonClient_1.invokeDaemon)('runpane:panes:adopt', [request], exports.paneCreateResultSchema, {
1037
1360
  paneDir: parsed.paneDir,
1038
- timeoutMs: 120_000,
1361
+ timeoutMs: 120_000 + (request.waitReady ? (request.readyTimeoutMs ?? 30_000) : 0),
1039
1362
  });
1040
1363
  if (parsed.json)
1041
1364
  printJson(result);
@@ -1044,8 +1367,11 @@ async function runPanesAdopt(parsed) {
1044
1367
  return result.ok ? 0 : 1;
1045
1368
  }
1046
1369
  async function runPanesArchive(parsed) {
1370
+ if (parsed.sessionId) {
1371
+ return runPanesArchiveSession(parsed, parsed.sessionId);
1372
+ }
1047
1373
  if (!parsed.paneId) {
1048
- throw new Error('runpane panes archive requires --pane.');
1374
+ throw new Error('runpane panes archive requires --pane (or --session with --merged).');
1049
1375
  }
1050
1376
  const request = {
1051
1377
  paneId: parsed.paneId,
@@ -1056,7 +1382,9 @@ async function runPanesArchive(parsed) {
1056
1382
  request.source = parsed.source;
1057
1383
  if (parsed.dryRun)
1058
1384
  request.dryRun = true;
1059
- await confirmPaneArchive(parsed, request);
1385
+ if (parsed.removeWorktree)
1386
+ request.removeWorktree = true;
1387
+ await confirmPaneArchive(parsed, `Archive pane ${request.paneId}${request.force ? ' (including any uncommitted or unpushed work)' : ''}`);
1060
1388
  const result = await (0, daemonClient_1.invokeDaemon)('runpane:panes:archive', [request], paneArchiveResultSchema, {
1061
1389
  paneDir: parsed.paneDir,
1062
1390
  timeoutMs: 40_000,
@@ -1069,6 +1397,31 @@ async function runPanesArchive(parsed) {
1069
1397
  }
1070
1398
  return result.ok ? 0 : 1;
1071
1399
  }
1400
+ async function runPanesArchiveSession(parsed, sessionId) {
1401
+ if (!parsed.merged) {
1402
+ throw new Error('runpane panes archive --session requires --merged.');
1403
+ }
1404
+ const request = { sessionId, merged: true };
1405
+ if (parsed.source === 'user' || parsed.source === 'agent')
1406
+ request.source = parsed.source;
1407
+ if (parsed.dryRun)
1408
+ request.dryRun = true;
1409
+ if (parsed.removeWorktree)
1410
+ request.removeWorktree = true;
1411
+ await confirmPaneArchive(parsed, `Archive every merged or pushed Pane in Session ${sessionId}`);
1412
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:panes:archive', [request], paneArchiveBulkResultSchema, {
1413
+ paneDir: parsed.paneDir,
1414
+ // Each Pane refreshes its upstream and may wait for its worktree removal.
1415
+ timeoutMs: 600_000,
1416
+ });
1417
+ if (parsed.json) {
1418
+ printJson(result);
1419
+ }
1420
+ else {
1421
+ printPaneArchiveBulkResult(result);
1422
+ }
1423
+ return result.ok ? 0 : 1;
1424
+ }
1072
1425
  async function runPanesPin(parsed, pinned) {
1073
1426
  if (!parsed.paneId) {
1074
1427
  throw new Error(`runpane panes ${pinned ? 'pin' : 'unpin'} requires --pane.`);
@@ -1218,12 +1571,84 @@ async function runPanelsScreen(parsed) {
1218
1571
  printJson(result);
1219
1572
  return 0;
1220
1573
  }
1221
- node_process_1.stdout.write(result.text);
1222
- if (result.text && !result.text.endsWith('\n')) {
1574
+ const text = markSuggestionLine(result.text, result.composer.ghostText);
1575
+ node_process_1.stdout.write(text);
1576
+ if (text && !text.endsWith('\n')) {
1223
1577
  node_process_1.stdout.write('\n');
1224
1578
  }
1225
1579
  return 0;
1226
1580
  }
1581
+ async function runPanelsLastMessage(parsed) {
1582
+ if (!parsed.panelId) {
1583
+ throw new Error('runpane panels last-message requires --panel.');
1584
+ }
1585
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:panels:last-message', [{
1586
+ panelId: parsed.panelId,
1587
+ limit: parsed.limit,
1588
+ }], panelLastMessageResultSchema, {
1589
+ paneDir: parsed.paneDir,
1590
+ });
1591
+ if (parsed.json) {
1592
+ printJson(result);
1593
+ }
1594
+ else if (result.ok) {
1595
+ node_process_1.stdout.write(result.text);
1596
+ if (result.text && !result.text.endsWith('\n'))
1597
+ node_process_1.stdout.write('\n');
1598
+ if (result.truncated)
1599
+ console.error(`(showing the last ${result.limit} of ${result.length} characters)`);
1600
+ }
1601
+ else {
1602
+ console.error(`${result.reason}: ${result.message}`);
1603
+ }
1604
+ return result.ok ? 0 : 1;
1605
+ }
1606
+ /** Where a report is for: explicit --panel (with an optional --pane), else the Pane terminal's own panel. */
1607
+ function resolveReportIdentity(parsed, env = process.env) {
1608
+ if (parsed.paneId || parsed.panelId) {
1609
+ if (!parsed.panelId) {
1610
+ throw new Error('runpane report --pane also needs --panel <panel-id>. Find it with `runpane panels list --pane <pane-id>`.');
1611
+ }
1612
+ return parsed.paneId ? { paneId: parsed.paneId, panelId: parsed.panelId } : { panelId: parsed.panelId };
1613
+ }
1614
+ const panelId = env.PANE_PANEL_ID?.trim();
1615
+ if (!panelId) {
1616
+ throw new Error('runpane report cannot tell which panel is reporting. Run it inside a Pane terminal '
1617
+ + '(which sets PANE_SESSION_ID and PANE_PANEL_ID), or pass --pane <pane-id> --panel <panel-id>.');
1618
+ }
1619
+ const paneId = env.PANE_SESSION_ID?.trim();
1620
+ return paneId ? { paneId, panelId } : { panelId };
1621
+ }
1622
+ /** The CLIs send one character past the daemon's 16,000 so it still marks an overlong summary truncated. */
1623
+ const MAX_SENT_SUMMARY_LENGTH = 16_001;
1624
+ async function runReport(parsed, env = process.env) {
1625
+ const identity = resolveReportIdentity(parsed, env);
1626
+ const summaryText = parsed.summaryFile !== undefined
1627
+ ? stripUtf8Bom(readInputSource(parsed.summaryFile))
1628
+ : parsed.summary;
1629
+ const summaryPath = parsed.summaryFile !== undefined && parsed.summaryFile !== '-'
1630
+ ? node_path_1.default.resolve(parsed.summaryFile)
1631
+ : undefined;
1632
+ const result = await (0, daemonClient_1.invokeDaemon)('runpane:report', [{
1633
+ ...identity,
1634
+ state: parsed.reportState,
1635
+ pr: parsed.reportPr,
1636
+ head: parsed.reportHead,
1637
+ summary: summaryText?.slice(0, MAX_SENT_SUMMARY_LENGTH),
1638
+ summaryPath,
1639
+ question: parsed.question,
1640
+ }], reportResultSchema, {
1641
+ paneDir: parsed.paneDir,
1642
+ });
1643
+ if (parsed.json) {
1644
+ printJson(result);
1645
+ }
1646
+ else {
1647
+ const sessions = result.sessionIds.length > 0 ? ` Recorded on Session ${result.sessionIds.join(', ')}.` : '';
1648
+ console.log(`Reported ${(0, watchLines_1.describeReport)(result.report)} for panel ${result.panelId}.${sessions}`);
1649
+ }
1650
+ return 0;
1651
+ }
1227
1652
  async function runPanelsSubmit(parsed) {
1228
1653
  const request = buildPanelInputRequest(parsed, 'submit');
1229
1654
  await confirmPanelInput(parsed, request, 'submit');
@@ -1237,15 +1662,50 @@ async function runPanelsSubmit(parsed) {
1237
1662
  const verb = result.ok ? 'Submitted' : 'Could not verify';
1238
1663
  const verified = result.verifiedSubmitted ? ' verified' : ' unverified';
1239
1664
  console.log(`${verb} ${result.inputBytes} byte${result.inputBytes === 1 ? '' : 's'} via ${result.sequenceName} to panel ${result.panelId}.${verified}`);
1665
+ printDelivery(result.delivery);
1240
1666
  if (result.blocked) {
1241
1667
  console.log(`Blocked: ${result.blocked.message}`);
1242
1668
  }
1669
+ printPromptNotes(result);
1243
1670
  if (result.nextCommand) {
1244
1671
  console.log(`Next: ${result.nextCommand}`);
1245
1672
  }
1246
1673
  }
1247
1674
  return result.ok ? 0 : 1;
1248
1675
  }
1676
+ /** Where the prompt went, for human output: `Delivery: queued (transcript)`. */
1677
+ function printDelivery(delivery, prefix = '') {
1678
+ if (delivery) {
1679
+ console.log(`${prefix}Delivery: ${delivery.state} (${delivery.evidence})`);
1680
+ }
1681
+ }
1682
+ /**
1683
+ * Mark the composer line that shows ghost text (a placeholder or the agent's
1684
+ * suggested next prompt), so it does not read as typed input.
1685
+ */
1686
+ function markSuggestionLine(text, ghostText) {
1687
+ const ghost = ghostText?.split('\n')[0]?.trim();
1688
+ if (!ghost)
1689
+ return text;
1690
+ const lines = text.split('\n');
1691
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
1692
+ const line = lines[index].trim();
1693
+ if (/^[❯›>]/u.test(line) && line.includes(ghost)) {
1694
+ lines[index] = `${lines[index].trimEnd()} ⟨suggestion⟩`;
1695
+ break;
1696
+ }
1697
+ }
1698
+ return lines.join('\n');
1699
+ }
1700
+ /** The prompt file Pane wrote and any leading-character warnings, for human output. */
1701
+ function printPromptNotes(result, prefix = '') {
1702
+ if (result.promptFile) {
1703
+ console.log(`${prefix}Prompt file: ${result.promptFile}`);
1704
+ }
1705
+ for (const warning of result.warnings ?? []) {
1706
+ console.log(`${prefix}Warning (${warning.code}): ${warning.message}`);
1707
+ }
1708
+ }
1249
1709
  async function runPanelsSubmitComposer(parsed) {
1250
1710
  if (!parsed.panelId) {
1251
1711
  throw new Error('runpane panels submit-composer requires --panel.');
@@ -1263,6 +1723,7 @@ async function runPanelsSubmitComposer(parsed) {
1263
1723
  else {
1264
1724
  const verified = result.verifiedSubmitted ? ' verified' : ' unverified';
1265
1725
  console.log(`${result.ok ? 'Submitted' : 'Could not verify'} composer with ${result.sequenceName} to panel ${result.panelId}.${verified}`);
1726
+ printDelivery(result.delivery);
1266
1727
  if (result.blocked) {
1267
1728
  console.log(`Blocked: ${result.blocked.message}`);
1268
1729
  }
@@ -1332,11 +1793,15 @@ function buildPanelInputRequest(parsed, command = 'input') {
1332
1793
  throw new Error(`runpane panels ${command} requires --text, --keys, or --input-file.`);
1333
1794
  }
1334
1795
  if (parsed.keys !== undefined && command !== 'input') {
1335
- throw new Error('--keys is for panels input; panels submit sends text followed by Enter.');
1796
+ throw new Error('--keys is for panels input; panels submit sends text followed by the agent submit key.');
1797
+ }
1798
+ if (parsed.asFilePointer && command !== 'submit') {
1799
+ throw new Error('--as-file-pointer is for panels submit; panels input sends exact bytes.');
1336
1800
  }
1337
1801
  return {
1338
1802
  panelId: parsed.panelId,
1339
1803
  input: parsed.keys ? keysToBytes(parsed.keys) : parsed.panelInputFile ? readInputSource(parsed.panelInputFile) : parsed.panelInput ?? '',
1804
+ asFilePointer: parsed.asFilePointer || undefined,
1340
1805
  };
1341
1806
  }
1342
1807
  /** `--keys down,enter`: named keys from the contract, or a single literal character each. */
@@ -1421,6 +1886,7 @@ async function buildPaneCreateRequest(parsed) {
1421
1886
  panes: [{
1422
1887
  name: parsed.name,
1423
1888
  worktreeName: parsed.worktreeName,
1889
+ branch: parsed.branch,
1424
1890
  baseBranch: parsed.baseBranch,
1425
1891
  pinned: resolvePinnedOverride(parsed) ?? true,
1426
1892
  tool,
@@ -1478,10 +1944,22 @@ async function confirmRepoAdd(parsed, request) {
1478
1944
  }
1479
1945
  }
1480
1946
  async function buildToolSpec(parsed, command = 'panes create') {
1481
- if (parsed.agent && parsed.toolCommand) {
1482
- throw new Error('Use either --agent or --tool-command, not both.');
1483
- }
1484
1947
  const initialInput = resolveInitialInput(parsed);
1948
+ if (parsed.asFilePointer && initialInput === undefined) {
1949
+ throw new Error(`--as-file-pointer needs a prompt: pass --prompt or --initial-input-file to runpane ${command}.`);
1950
+ }
1951
+ const initialInputAsFilePointer = parsed.asFilePointer || undefined;
1952
+ // With --tool-command, --agent names the agent the command runs (a wrapper
1953
+ // such as `agent-farm run`); Pane launches the command unchanged.
1954
+ if (parsed.toolCommand && parsed.agent) {
1955
+ return {
1956
+ command: parsed.toolCommand,
1957
+ agentType: parsed.agent,
1958
+ title: parsed.title,
1959
+ initialInput,
1960
+ initialInputAsFilePointer,
1961
+ };
1962
+ }
1485
1963
  let agent = parsed.agent;
1486
1964
  if (!agent && !parsed.toolCommand) {
1487
1965
  if (!isInteractiveShell()) {
@@ -1494,6 +1972,7 @@ async function buildToolSpec(parsed, command = 'panes create') {
1494
1972
  agent,
1495
1973
  title: parsed.title,
1496
1974
  initialInput,
1975
+ initialInputAsFilePointer,
1497
1976
  };
1498
1977
  }
1499
1978
  if (!parsed.toolCommand) {
@@ -1503,11 +1982,12 @@ async function buildToolSpec(parsed, command = 'panes create') {
1503
1982
  command: parsed.toolCommand,
1504
1983
  title: parsed.title,
1505
1984
  initialInput,
1985
+ initialInputAsFilePointer,
1506
1986
  };
1507
1987
  }
1508
1988
  function resolveInitialInput(parsed) {
1509
1989
  if (parsed.initialInput && parsed.initialInputFile) {
1510
- throw new Error('Use either --initial-input/--prompt or --initial-input-file, not both.');
1990
+ throw new Error('Use either --initial-input/--prompt or --initial-input-file/--prompt-file, not both.');
1511
1991
  }
1512
1992
  if (parsed.initialInputFile) {
1513
1993
  return readInputSource(parsed.initialInputFile);
@@ -1549,7 +2029,7 @@ async function confirmPaneAdopt(parsed, request) {
1549
2029
  rl.close();
1550
2030
  }
1551
2031
  }
1552
- async function confirmPaneArchive(parsed, request) {
2032
+ async function confirmPaneArchive(parsed, question) {
1553
2033
  if (parsed.dryRun || parsed.yes) {
1554
2034
  return;
1555
2035
  }
@@ -1558,8 +2038,7 @@ async function confirmPaneArchive(parsed, request) {
1558
2038
  }
1559
2039
  const rl = (0, promises_1.createInterface)({ input: node_process_1.stdin, output: node_process_1.stdout });
1560
2040
  try {
1561
- const suffix = request.force ? ' (including any uncommitted or unpushed work)' : '';
1562
- const answer = (await rl.question(`Archive pane ${request.paneId}${suffix}? [y/N] `)).trim().toLowerCase();
2041
+ const answer = (await rl.question(`${question}? [y/N] `)).trim().toLowerCase();
1563
2042
  if (answer !== 'y' && answer !== 'yes') {
1564
2043
  throw new Error('Cancelled.');
1565
2044
  }
@@ -1735,6 +2214,12 @@ function workspaceLabel(kind) {
1735
2214
  'pane.created': 'NEW',
1736
2215
  'pane.gone': 'GONE',
1737
2216
  'panel.exited': 'EXIT',
2217
+ 'pane.associated': 'JOINED',
2218
+ 'pane.detached': 'LEFT',
2219
+ 'pr.conflicted': 'PR CONFLICTED',
2220
+ 'pr.checks': 'PR CHECKS',
2221
+ 'pr.merged': 'PR MERGED',
2222
+ 'agent.report': 'REPORT',
1738
2223
  };
1739
2224
  return labels[kind];
1740
2225
  }
@@ -1804,6 +2289,7 @@ function printPaneCreateResult(result) {
1804
2289
  ? ` Associated with Session ${item.association.sessionId}`
1805
2290
  : ` Not associated with Session ${item.association.sessionId}: ${item.association.error ?? 'unknown error'}`);
1806
2291
  }
2292
+ printPromptNotes(item, ' ');
1807
2293
  if (item.nextCommand) {
1808
2294
  console.log(` Next: ${item.nextCommand}`);
1809
2295
  }
@@ -1828,11 +2314,44 @@ function printPaneArchiveResult(result) {
1828
2314
  console.error(`Next: ${result.nextCommand}`);
1829
2315
  return;
1830
2316
  }
1831
- console.log(`Archived pane ${result.paneId}${result.forced ? ' (forced)' : ''}. Worktree cleanup: ${result.worktreeCleanup}.`);
2317
+ const trash = result.trashDeletion === 'pending' ? ' (files are still being deleted in the background)' : '';
2318
+ console.log(`Archived pane ${result.paneId}${result.forced ? ' (forced)' : ''}. Worktree cleanup: ${result.worktreeCleanup}${trash}.`);
2319
+ printArchiveSkipReason(result.safetyCheck);
2320
+ if (result.safetyCheck.mergedViaPr) {
2321
+ console.log(`Merged via PR #${result.safetyCheck.mergedViaPr.number} (head ${result.safetyCheck.mergedViaPr.headOid}).`);
2322
+ }
2323
+ }
2324
+ function printPaneArchiveBulkResult(result) {
2325
+ const verb = result.dryRun ? 'Would archive' : 'Archived';
2326
+ console.log(`${verb} ${result.archived} Pane(s) in Session ${result.sessionId}; skipped ${result.skipped}; failed ${result.failed}.`);
2327
+ for (const item of result.items) {
2328
+ const label = item.name ? `${item.name} (${item.paneId})` : item.paneId;
2329
+ if (item.outcome === 'skipped') {
2330
+ console.log(` skipped ${label}: ${item.skipped?.code ?? 'unknown'} - ${item.skipped?.message ?? ''}`);
2331
+ }
2332
+ else if (item.outcome === 'failed') {
2333
+ console.error(` failed ${label}: ${item.error ?? 'unknown error'}`);
2334
+ }
2335
+ else {
2336
+ const merged = item.safetyCheck?.mergedViaPr ? ` merged via PR #${item.safetyCheck.mergedViaPr.number}` : '';
2337
+ const trash = item.trashDeletion === 'pending' ? ', files deleting in background' : '';
2338
+ const cleanup = item.worktreeCleanup ? ` worktree ${item.worktreeCleanup}${trash}` : '';
2339
+ console.log(` ${item.outcome} ${label}${merged}${cleanup}`);
2340
+ }
2341
+ }
2342
+ }
2343
+ function printArchiveSkipReason(safetyCheck, print = console.log) {
2344
+ if (!safetyCheck.reason)
2345
+ return;
2346
+ print(`Safety check skipped: ${safetyCheck.reason}${safetyCheck.worktreeWillRemain ? '; the worktree stays on disk' : ''}.`);
1832
2347
  }
1833
2348
  function printArchiveCommitEvidence(safetyCheck, print = console.log) {
2349
+ printArchiveSkipReason(safetyCheck, print);
1834
2350
  if (safetyCheck.upstream) {
1835
- print(`Upstream: ${safetyCheck.upstream}${safetyCheck.upstreamRefreshed ? ' (refreshed)' : ''}`);
2351
+ print(`Upstream: ${safetyCheck.upstream}${safetyCheck.upstreamRefreshed ? ' (refreshed)' : ''}${safetyCheck.upstreamGone ? ' (gone from the remote)' : ''}`);
2352
+ }
2353
+ if (safetyCheck.mergedViaPr) {
2354
+ print(`Merged via PR #${safetyCheck.mergedViaPr.number} (head ${safetyCheck.mergedViaPr.headOid})`);
1836
2355
  }
1837
2356
  for (const commit of safetyCheck.unpushedCommitDetails ?? []) {
1838
2357
  print(`Unpushed: ${commit.sha} ${commit.subject}`);
@@ -1847,6 +2366,7 @@ function printPanelCreateResult(result) {
1847
2366
  }
1848
2367
  }
1849
2368
  printInitialInputDelivery(result.initialInput);
2369
+ printPromptNotes(result);
1850
2370
  if (result.nextCommand) {
1851
2371
  console.log(`Next: ${result.nextCommand}`);
1852
2372
  }
@@ -1864,6 +2384,7 @@ function printInitialInputDelivery(initialInput, prefix = '') {
1864
2384
  const attempts = initialInput.attempts === undefined ? '' : ` after ${initialInput.attempts} attempt${initialInput.attempts === 1 ? '' : 's'}`;
1865
2385
  const staged = initialInput.staged === undefined ? '' : `; staged: ${initialInput.staged ? 'yes' : 'no'}`;
1866
2386
  console.log(`${prefix}Initial input: ${status}${strategy}${attempts}${staged}`);
2387
+ printDelivery(initialInput.delivery, prefix);
1867
2388
  if (initialInput.blocked) {
1868
2389
  console.log(`${prefix}Initial input blocked: ${initialInput.blocked.message}`);
1869
2390
  }
@@ -1923,7 +2444,8 @@ function printPanelListResult(result) {
1923
2444
  const marker = panel.active ? '*' : ' ';
1924
2445
  const initialized = panel.initialized === undefined ? '' : panel.initialized ? ' initialized' : ' not-initialized';
1925
2446
  const agent = panel.agentType ? ` ${panel.agentType}` : '';
1926
- console.log(`${marker} ${panel.id}\t${panel.type}\t${panel.title}${initialized}${agent}`);
2447
+ const detection = panel.agentDetection && panel.agentDetection !== 'command' ? ` (${panel.agentDetection})` : '';
2448
+ console.log(`${marker} ${panel.id}\t${panel.type}\t${panel.title}${initialized}${agent}${detection}`);
1927
2449
  }
1928
2450
  }
1929
2451
  function isInteractiveShell() {
@@ -1949,6 +2471,7 @@ function parsePaneCreateItemPayload(value, index) {
1949
2471
  return {
1950
2472
  name: value.name,
1951
2473
  worktreeName: value.worktreeName,
2474
+ branch: value.branch,
1952
2475
  baseBranch: value.baseBranch,
1953
2476
  sessionPrompt: value.sessionPrompt,
1954
2477
  pinned: value.pinned,
@@ -1968,13 +2491,23 @@ function parsePaneToolSpecPayload(value, index) {
1968
2491
  agent,
1969
2492
  title: value.title,
1970
2493
  initialInput: value.initialInput,
2494
+ initialInputAsFilePointer: value.initialInputAsFilePointer,
1971
2495
  };
1972
2496
  }
1973
2497
  if (value.command !== undefined && value.command.trim().length > 0) {
2498
+ let agentType;
2499
+ try {
2500
+ agentType = value.agentType === undefined ? undefined : (0, boundaryDecoder_1.decodeBoundary)(value.agentType, agentSchema);
2501
+ }
2502
+ catch {
2503
+ throw new Error(`--from-json pane ${index} includes an unsupported agentType.`);
2504
+ }
1974
2505
  return {
1975
2506
  command: value.command,
2507
+ agentType,
1976
2508
  title: value.title,
1977
2509
  initialInput: value.initialInput,
2510
+ initialInputAsFilePointer: value.initialInputAsFilePointer,
1978
2511
  };
1979
2512
  }
1980
2513
  throw new Error(`--from-json pane ${index} tool must include agent or command.`);