@overdeck/contracts 0.60.0 → 0.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -5,6 +5,8 @@ import * as RpcGroup from "effect/unstable/rpc/RpcGroup";
5
5
  const BackendPane = Schema.Struct({
6
6
  /** Stable pane identity: the backend-native pane handle. */
7
7
  id: Schema.String,
8
+ /** Overdeck agent id: Herdr `agentId` token or live agent name; tmux session name (PAN-3920). */
9
+ agentId: Schema.optional(Schema.String),
8
10
  /** Issue the pane belongs to; absent for operator conversations. */
9
11
  issue: Schema.optional(Schema.String),
10
12
  role: Schema.Literals([
@@ -14,7 +16,8 @@ const BackendPane = Schema.Struct({
14
16
  "test",
15
17
  "uat",
16
18
  "strike",
17
- "plan"
19
+ "plan",
20
+ "conversation"
18
21
  ]),
19
22
  harness: Schema.String,
20
23
  model: Schema.String,
@@ -145,9 +148,17 @@ const MEMBERSHIP_UNAVAILABLE_REASONS = [
145
148
  "repo_unavailable",
146
149
  "default_branch_unresolved",
147
150
  "forge_unavailable",
151
+ "forge_transient",
148
152
  "tracker_unconfigured",
149
153
  "gather_failed"
150
154
  ];
155
+ /**
156
+ * PAN-3527 — the membership snapshot has not been gathered yet (a freshly
157
+ * restarted server warming its cache). Sent with HTTP 503 and a `Retry-After`
158
+ * header. Unlike `PipelineMembershipUnavailableBody` (a settled answer about
159
+ * the project), this is a temporary state: callers retry it.
160
+ */
161
+ const PIPELINE_MEMBERSHIP_LOADING_CODE = "snapshot_loading";
151
162
  const AgentId = Schema.String;
152
163
  const SequenceNumber = Schema.Number;
153
164
  const AgentStatus = Schema.Literals([
@@ -166,7 +177,8 @@ const Role = Schema.Literals([
166
177
  "flywheel",
167
178
  "strike",
168
179
  "sequencer",
169
- "knowledge"
180
+ "knowledge",
181
+ "worker"
170
182
  ]);
171
183
  const AgentResolution = Schema.Literals([
172
184
  "working",
@@ -325,6 +337,12 @@ const AgentSnapshot = Schema.Struct({
325
337
  phase: Schema.optional(Schema.String),
326
338
  workType: Schema.optional(Schema.String),
327
339
  roleRunHead: Schema.optional(Schema.String),
340
+ /** The agent has a live pane on its terminal backend (Herdr or tmux). */
341
+ hasLivePane: Schema.optional(Schema.Boolean),
342
+ /**
343
+ * @deprecated Misnamed alias of `hasLivePane`: true for a live pane on either
344
+ * backend, not only a tmux session. Still populated for compatibility (#4105).
345
+ */
328
346
  hasLiveTmuxSession: Schema.optional(Schema.Boolean),
329
347
  stoppedByUser: Schema.optional(Schema.Boolean),
330
348
  paused: Schema.optional(Schema.Boolean),
@@ -439,6 +457,39 @@ const ProjectCiSnapshot = Schema.Struct({
439
457
  /** Newest `observedAt` folded into this record. */
440
458
  updatedAt: Schema.String
441
459
  });
460
+ /**
461
+ * Where an in-flight dashboard self-deploy (`pan reload`) stands.
462
+ *
463
+ * `building` the reload holds the restart lock and is building from origin/main;
464
+ * `awaiting-approval` the build is ready and the reload waits on the restart gate;
465
+ * `restarting` the operator approved and the old dashboard is being replaced;
466
+ * `failed` the last reload recorded a failure (visible for a short window).
467
+ */
468
+ const ProjectDeployPhase = Schema.Literals([
469
+ "building",
470
+ "awaiting-approval",
471
+ "restarting",
472
+ "failed"
473
+ ]);
474
+ /**
475
+ * One project's deploy, derived on the server from live runtime files: the
476
+ * restart lock, the restart gate, the restart-status journal and the reload
477
+ * process's own stdout. Nothing here is stored; a server restart re-derives it.
478
+ */
479
+ const ProjectDeploySnapshot = Schema.Struct({
480
+ projectKey: Schema.String,
481
+ trigger: Schema.String,
482
+ phase: ProjectDeployPhase,
483
+ /** The deploying process, while it is alive. */
484
+ pid: Schema.optional(Schema.Number),
485
+ /** When the server first observed this deploy (for `failed`, when it failed). */
486
+ startedAt: Schema.String,
487
+ error: Schema.optional(Schema.String),
488
+ /** The reload's output file, when its stdout is a regular file. */
489
+ logPath: Schema.optional(Schema.String),
490
+ /** Last lines of `logPath`. */
491
+ logTail: Schema.optional(Schema.Array(Schema.String))
492
+ });
442
493
  /** What kind of process asked for the voluntary dashboard restart. */
443
494
  const RestartGateKind = Schema.Literals([
444
495
  "deploy",
@@ -508,6 +559,8 @@ const DashboardSnapshot = Schema.Struct({
508
559
  embedProgressBySessionId: Schema.optional(Schema.Record(Schema.String, EmbedProgressSnapshot)),
509
560
  ciByProjectKey: Schema.optional(Schema.Record(Schema.String, ProjectCiSnapshot)),
510
561
  restartGate: Schema.optional(RestartGateSnapshot),
562
+ /** PAN-3751 — in-flight deploys keyed by project key. */
563
+ deployByProjectKey: Schema.optional(Schema.Record(Schema.String, ProjectDeploySnapshot)),
511
564
  timestamp: Schema.String
512
565
  });
513
566
  const ResourceStats = Schema.Struct({ containers: Schema.Array(Schema.Struct({
@@ -762,6 +815,95 @@ const ScanResult = Schema.Struct({
762
815
  durationMs: Schema.Number
763
816
  });
764
817
  //#endregion
818
+ //#region src/pull-request-links.ts
819
+ const PullRequestLinkSource = Schema.Literals([
820
+ "manual",
821
+ "agent",
822
+ "created",
823
+ "branch"
824
+ ]);
825
+ const PullRequestKey = Schema.Struct({
826
+ host: Schema.String,
827
+ repository: Schema.String,
828
+ number: Schema.Number
829
+ });
830
+ const PullRequestState = Schema.Literals([
831
+ "open",
832
+ "merged",
833
+ "closed"
834
+ ]);
835
+ const PullRequestSnapshot = Schema.Struct({
836
+ state: PullRequestState,
837
+ isDraft: Schema.Boolean,
838
+ title: Schema.String,
839
+ headBranch: Schema.NullOr(Schema.String),
840
+ baseBranch: Schema.NullOr(Schema.String),
841
+ reviewState: PrReviewState,
842
+ checks: PrChecksState,
843
+ mergeable: Schema.NullOr(Schema.Boolean),
844
+ additions: Schema.NullOr(Schema.Number),
845
+ deletions: Schema.NullOr(Schema.Number),
846
+ changedFiles: Schema.NullOr(Schema.Number),
847
+ author: Schema.NullOr(Schema.String),
848
+ /** Forge timestamp, ISO. */
849
+ updatedAt: Schema.NullOr(Schema.String),
850
+ mergedAt: Schema.NullOr(Schema.String),
851
+ closedAt: Schema.NullOr(Schema.String),
852
+ /** When Overdeck last read the PR, ISO. */
853
+ syncedAt: Schema.String
854
+ });
855
+ const PullRequestLink = Schema.Struct({
856
+ ...PullRequestKey.fields,
857
+ url: Schema.String,
858
+ source: PullRequestLinkSource,
859
+ linkedAt: Schema.String,
860
+ dismissedAt: Schema.NullOr(Schema.String),
861
+ snapshot: Schema.NullOr(PullRequestSnapshot)
862
+ });
863
+ const ConversationPullRequests = Schema.Struct({
864
+ links: Schema.Array(PullRequestLink),
865
+ effective: Schema.NullOr(PullRequestLink)
866
+ });
867
+ /** One conversation linked to a PR — the reverse index (PR → conversations). */
868
+ const PullRequestLinkedConversation = Schema.Struct({
869
+ /** The /conv/<id> number. */
870
+ id: Schema.Number,
871
+ name: Schema.String,
872
+ title: Schema.NullOr(Schema.String),
873
+ source: PullRequestLinkSource,
874
+ linkedAt: Schema.String
875
+ });
876
+ /** One live link across all conversations, for the Pull requests list. */
877
+ const PullRequestLinkListing = Schema.Struct({
878
+ ...PullRequestLink.fields,
879
+ conversationId: Schema.Number,
880
+ conversationName: Schema.String,
881
+ conversationTitle: Schema.NullOr(Schema.String),
882
+ /** The conversation's effective project, or null when none resolves. */
883
+ projectKey: Schema.NullOr(Schema.String)
884
+ });
885
+ function stateRank(link) {
886
+ if (link.snapshot === null) return 1;
887
+ if (link.snapshot.state === "open") return 0;
888
+ if (link.snapshot.state === "merged") return 2;
889
+ return 3;
890
+ }
891
+ function recency(link) {
892
+ return Date.parse(link.snapshot?.updatedAt ?? link.linkedAt) || 0;
893
+ }
894
+ /**
895
+ * The one PR shown on a conversation: explicit links before branch links,
896
+ * open before merged before closed, most recently updated among equals.
897
+ * Dismissed links never count.
898
+ */
899
+ function resolveEffectivePullRequest(links) {
900
+ const live = links.filter((link) => link.dismissedAt === null);
901
+ const explicit = live.filter((link) => link.source !== "branch");
902
+ const pool = explicit.length > 0 ? explicit : live;
903
+ if (pool.length === 0) return null;
904
+ return [...pool].sort((a, b) => stateRank(a) - stateRank(b) || recency(b) - recency(a))[0] ?? null;
905
+ }
906
+ //#endregion
765
907
  //#region src/memory.ts
766
908
  const MemoryAgentRole = Schema.Union([Role, Schema.Literal("conversation")]);
767
909
  const MemoryIdentity = Schema.Struct({
@@ -1019,6 +1161,9 @@ const AgentHealthSnapshot = Schema.Struct({
1019
1161
  kind: Schema.optional(AgentHealthKind),
1020
1162
  status: AgentHealthStatus,
1021
1163
  lifecycle: Schema.optional(SpecialistLifecycle),
1164
+ /** The agent has a live pane on the selected terminal backend (Herdr or tmux). */
1165
+ hasLivePane: Schema.optional(Schema.Boolean),
1166
+ /** @deprecated Alias of `hasLivePane` kept for existing readers; true on either backend, not only tmux. */
1022
1167
  tmuxActive: Schema.optional(Schema.Boolean),
1023
1168
  memoryBytes: Schema.optional(Schema.Number),
1024
1169
  memoryGb: Schema.optional(Schema.Number),
@@ -1286,6 +1431,20 @@ const RestartGateChangedEvent = Schema.Struct({
1286
1431
  timestamp: Schema.String,
1287
1432
  payload: RestartGateSnapshot
1288
1433
  });
1434
+ /**
1435
+ * The set of in-flight project deploys changed (PAN-3751).
1436
+ *
1437
+ * The payload is the COMPLETE projection keyed by project key, so the reducer
1438
+ * is a plain replace. The server derives it from runtime files (restart lock,
1439
+ * restart gate, restart-status journal) and emits it in-memory only, like
1440
+ * `restart_gate.changed`: it is never persisted and never replayed at boot.
1441
+ */
1442
+ const ProjectDeployChangedEvent = Schema.Struct({
1443
+ type: Schema.Literal("project.deploy_changed"),
1444
+ sequence: SequenceNumber,
1445
+ timestamp: Schema.String,
1446
+ payload: Schema.Struct({ deploys: Schema.Record(Schema.String, ProjectDeploySnapshot) })
1447
+ });
1289
1448
  /** Replaces socket.io `agents:changed` (event: 'started') */
1290
1449
  const AgentStartedEvent = Schema.Struct({
1291
1450
  type: Schema.Literal("agent.started"),
@@ -1375,6 +1534,9 @@ const AgentStatusChangedEvent = Schema.Struct({
1375
1534
  workspaceId: Schema.optional(Schema.String),
1376
1535
  status: AgentStatus,
1377
1536
  previousStatus: Schema.optional(AgentStatus),
1537
+ /** The agent has a live pane on its terminal backend (Herdr or tmux). */
1538
+ hasLivePane: Schema.optional(Schema.Boolean),
1539
+ /** @deprecated Alias of `hasLivePane`, kept for events written before it existed (#4105). */
1378
1540
  hasLiveTmuxSession: Schema.optional(Schema.Boolean),
1379
1541
  stoppedByUser: Schema.optional(Schema.Boolean),
1380
1542
  stoppedByPause: Schema.optional(Schema.Boolean),
@@ -2441,6 +2603,17 @@ const ConversationTitleChangedEvent = Schema.Struct({
2441
2603
  titleSource: Schema.String
2442
2604
  })
2443
2605
  });
2606
+ /** Emitted (in-memory only) when a conversation's pull-request links or their
2607
+ * snapshots change (PAN-3822), so the list and open panel refresh the badge. */
2608
+ const ConversationPullRequestsChangedEvent = Schema.Struct({
2609
+ type: Schema.Literal("conversation.pull_requests_changed"),
2610
+ sequence: SequenceNumber,
2611
+ timestamp: Schema.String,
2612
+ payload: Schema.Struct({
2613
+ conversationName: Schema.String,
2614
+ effective: Schema.NullOr(PullRequestLink)
2615
+ })
2616
+ });
2444
2617
  /** Emitted (in-memory only) when a PermissionRequest hook fires or resolves for a conversation. */
2445
2618
  const ConversationPermissionChangedEvent = Schema.Struct({
2446
2619
  type: Schema.Literal("conversation.permission_changed"),
@@ -2575,6 +2748,7 @@ const DomainEvent = Schema.Union([
2575
2748
  ProjectCiSuiteObservedEvent,
2576
2749
  ProjectCiHeadObservedEvent,
2577
2750
  RestartGateChangedEvent,
2751
+ ProjectDeployChangedEvent,
2578
2752
  AgentCreatedEvent,
2579
2753
  AgentEnrichmentChangedEvent,
2580
2754
  AgentStartedEvent,
@@ -2665,6 +2839,7 @@ const DomainEvent = Schema.Union([
2665
2839
  ConversationCreatedEvent,
2666
2840
  ConversationMovedEvent,
2667
2841
  ConversationTitleChangedEvent,
2842
+ ConversationPullRequestsChangedEvent,
2668
2843
  ConversationPermissionChangedEvent,
2669
2844
  ScanStartedEvent,
2670
2845
  ScanProgressEvent,
@@ -3478,6 +3653,7 @@ const INITIAL_READ_MODEL_STATE = {
3478
3653
  embedProgressBySessionId: {},
3479
3654
  ciByProjectKey: {},
3480
3655
  restartGate: null,
3656
+ deployByProjectKey: {},
3481
3657
  agentIdBySessionId: {},
3482
3658
  dashboardLifecycle: {
3483
3659
  active: false,
@@ -3608,14 +3784,29 @@ function syncSnapshot(state, snapshot) {
3608
3784
  embedProgressBySessionId: snapshot.embedProgressBySessionId ?? {},
3609
3785
  ciByProjectKey: snapshot.ciByProjectKey ?? state.ciByProjectKey,
3610
3786
  restartGate: snapshot.restartGate ?? state.restartGate,
3787
+ deployByProjectKey: snapshot.deployByProjectKey ?? state.deployByProjectKey,
3611
3788
  agentIdBySessionId
3612
3789
  };
3613
3790
  }
3791
+ /**
3792
+ * #4105 — `hasLivePane` and its deprecated alias `hasLiveTmuxSession` carry one
3793
+ * fact. An agent snapshot from a stored event may carry only the old name; fill
3794
+ * whichever one is missing so readers of either name agree.
3795
+ */
3796
+ function withPaneLivenessAlias(agent) {
3797
+ const pane = agent.hasLivePane ?? agent.hasLiveTmuxSession;
3798
+ if (pane === void 0 || agent.hasLivePane === pane && agent.hasLiveTmuxSession === pane) return agent;
3799
+ return {
3800
+ ...agent,
3801
+ hasLivePane: pane,
3802
+ hasLiveTmuxSession: pane
3803
+ };
3804
+ }
3614
3805
  function applyEvent(state, event) {
3615
3806
  switch (event.type) {
3616
3807
  case "agent.created": {
3617
3808
  const existing = state.agentsById[event.payload.agentId];
3618
- const agent = event.payload.agent;
3809
+ const agent = withPaneLivenessAlias(event.payload.agent);
3619
3810
  const nextAgentIdBySessionId = agent.sessionId ? {
3620
3811
  ...state.agentIdBySessionId,
3621
3812
  [agent.sessionId]: agent.id
@@ -3634,7 +3825,7 @@ function applyEvent(state, event) {
3634
3825
  };
3635
3826
  }
3636
3827
  case "agent.started": {
3637
- const agent = event.payload.agent;
3828
+ const agent = withPaneLivenessAlias(event.payload.agent);
3638
3829
  const nextAgentIdBySessionId = agent.sessionId ? {
3639
3830
  ...state.agentIdBySessionId,
3640
3831
  [agent.sessionId]: agent.id
@@ -3684,6 +3875,7 @@ function applyEvent(state, event) {
3684
3875
  [event.payload.agentId]: {
3685
3876
  ...stoppedAgent,
3686
3877
  status: "stopped",
3878
+ hasLivePane: false,
3687
3879
  hasLiveTmuxSession: false,
3688
3880
  lastActivity: event.timestamp
3689
3881
  }
@@ -3745,6 +3937,7 @@ function applyEvent(state, event) {
3745
3937
  status: event.payload.status
3746
3938
  };
3747
3939
  for (const field of [
3940
+ "hasLivePane",
3748
3941
  "hasLiveTmuxSession",
3749
3942
  "stoppedByUser",
3750
3943
  "stoppedByPause",
@@ -3789,7 +3982,15 @@ function applyEvent(state, event) {
3789
3982
  if (value === null || value === void 0) delete base[field];
3790
3983
  else base[field] = value;
3791
3984
  }
3792
- const sessionAlive = event.payload.hasLiveTmuxSession === true;
3985
+ const payloadPane = event.payload.hasLivePane ?? event.payload.hasLiveTmuxSession;
3986
+ if ("hasLivePane" in event.payload || "hasLiveTmuxSession" in event.payload) if (payloadPane === null || payloadPane === void 0) {
3987
+ delete base["hasLivePane"];
3988
+ delete base["hasLiveTmuxSession"];
3989
+ } else {
3990
+ base["hasLivePane"] = payloadPane;
3991
+ base["hasLiveTmuxSession"] = payloadPane;
3992
+ }
3993
+ const sessionAlive = payloadPane === true;
3793
3994
  if (event.payload.status !== "running" && event.payload.status !== "starting" && !sessionAlive) {
3794
3995
  delete base["hasPendingQuestion"];
3795
3996
  delete base["pendingQuestionCount"];
@@ -3998,6 +4199,11 @@ function applyEvent(state, event) {
3998
4199
  ...event.payload.lastOutcome === void 0 ? {} : { lastOutcome: event.payload.lastOutcome }
3999
4200
  }
4000
4201
  };
4202
+ case "project.deploy_changed": return {
4203
+ ...state,
4204
+ sequence: Math.max(state.sequence, event.sequence),
4205
+ deployByProjectKey: event.payload.deploys
4206
+ };
4001
4207
  case "resources.updated": return {
4002
4208
  ...state,
4003
4209
  sequence: Math.max(state.sequence, event.sequence),
@@ -4710,6 +4916,10 @@ function applyEvent(state, event) {
4710
4916
  ...state,
4711
4917
  conversationsListRevision: state.conversationsListRevision + 1
4712
4918
  };
4919
+ case "conversation.pull_requests_changed": return {
4920
+ ...state,
4921
+ conversationsListRevision: state.conversationsListRevision + 1
4922
+ };
4713
4923
  case "conversation.permission_changed": {
4714
4924
  const { conversationName, waiting } = event.payload;
4715
4925
  if (!waiting) {
@@ -5066,34 +5276,142 @@ const FlywheelStatsTrend = Schema.Literals([
5066
5276
  "down",
5067
5277
  "flat"
5068
5278
  ]);
5069
- const FlywheelStatsCriterionValueObject = Schema.Record(Schema.String, Schema.Json);
5070
- const FlywheelStatsCriterionValue = Schema.Union([Schema.Number, FlywheelStatsCriterionValueObject]);
5071
- const FlywheelStatsCriterion = Schema.Struct({
5072
- label: Schema.String,
5073
- value: FlywheelStatsCriterionValue,
5074
- target: FlywheelStatsCriterionValue,
5279
+ const FlywheelSubstrateSeverity = Schema.Literals([
5280
+ "P0",
5281
+ "P1",
5282
+ "P2",
5283
+ "unknown"
5284
+ ]);
5285
+ const FlywheelStatsWindow = Schema.Struct({
5286
+ days: Schema.Number,
5287
+ since: Schema.String,
5288
+ until: Schema.String
5289
+ });
5290
+ /** c1: substrate bugs filed per merged PR in the window. */
5291
+ const FlywheelBugRateCriterion = Schema.Struct({
5292
+ /** `null` when no PR merged in the window (the rate is undefined). */
5293
+ value: Schema.NullOr(Schema.Number),
5294
+ count: Schema.Number,
5295
+ denominator: Schema.Number,
5296
+ status: FlywheelStatsCriterionStatus,
5297
+ trend: FlywheelStatsTrend,
5298
+ dataSufficient: Schema.Boolean
5299
+ });
5300
+ /** c2: P0 substrate bugs filed in the window. */
5301
+ const FlywheelP0Criterion = Schema.Struct({
5302
+ value: Schema.Number,
5075
5303
  status: FlywheelStatsCriterionStatus,
5076
- trend: Schema.optional(FlywheelStatsTrend),
5077
- sampleSize: Schema.Number,
5304
+ trend: FlywheelStatsTrend,
5078
5305
  dataSufficient: Schema.Boolean
5079
5306
  });
5080
- const FlywheelStatsCriteria = Schema.Struct({
5081
- c1_bugRate: FlywheelStatsCriterion,
5082
- c2_p0Bugs: FlywheelStatsCriterion,
5083
- c3_passRate: FlywheelStatsCriterion,
5084
- c4_mttr: FlywheelStatsCriterion,
5085
- c5_intervention: FlywheelStatsCriterion,
5086
- c6_timeConsistency: FlywheelStatsCriterion,
5087
- c7_flake: FlywheelStatsCriterion
5307
+ const FlywheelSubstrateBugRow = Schema.Struct({
5308
+ number: Schema.Number,
5309
+ title: Schema.String,
5310
+ createdAt: Schema.String,
5311
+ closedAt: Schema.NullOr(Schema.String),
5312
+ severity: FlywheelSubstrateSeverity
5088
5313
  });
5089
5314
  const FlywheelStats = Schema.Struct({
5090
- window: Schema.String,
5315
+ window: FlywheelStatsWindow,
5091
5316
  generatedAt: Schema.String,
5092
- criteria: FlywheelStatsCriteria
5317
+ criteria: Schema.Struct({
5318
+ c1_bugRate: FlywheelBugRateCriterion,
5319
+ c2_p0Bugs: FlywheelP0Criterion
5320
+ }),
5321
+ bugs: Schema.Array(FlywheelSubstrateBugRow)
5093
5322
  });
5094
5323
  const decodeFlywheelStats = Schema.decodeUnknownSync(FlywheelStats);
5095
5324
  const encodeFlywheelStats = Schema.encodeSync(FlywheelStats);
5096
5325
  //#endregion
5326
+ //#region src/flywheel-derived.ts
5327
+ /** The loop's phases, as the skill reports them in its tick marker. */
5328
+ const TickMarkerPhase = Schema.Literals([
5329
+ "orient",
5330
+ "pick",
5331
+ "launch",
5332
+ "watch",
5333
+ "park",
5334
+ "idle",
5335
+ "stopping"
5336
+ ]);
5337
+ /**
5338
+ * One parsed tick marker line:
5339
+ * `flywheel-tick: tick=<n> pick=<ID|none> phase=<phase> in-flight=<ID,…|none> needs-you=<text|none>`.
5340
+ */
5341
+ const TickMarker = Schema.Struct({
5342
+ tick: Schema.Number,
5343
+ pick: Schema.NullOr(Schema.String),
5344
+ phase: TickMarkerPhase,
5345
+ inFlight: Schema.Array(Schema.String),
5346
+ needsYou: Schema.NullOr(Schema.String)
5347
+ });
5348
+ /** `running` = row + live session; `paused` = row, no live session; `idle` = no row. */
5349
+ const FlywheelRunState = Schema.Literals([
5350
+ "running",
5351
+ "paused",
5352
+ "idle"
5353
+ ]);
5354
+ /** Age of the last tick: ≤ 60 s live, ≤ 20 min breathing, older stalled. */
5355
+ const FlywheelFreshness = Schema.Literals([
5356
+ "live",
5357
+ "breathing",
5358
+ "stalled"
5359
+ ]);
5360
+ const FlywheelConversationSummary = Schema.Struct({
5361
+ name: Schema.String,
5362
+ id: Schema.Number,
5363
+ title: Schema.NullOr(Schema.String),
5364
+ model: Schema.NullOr(Schema.String),
5365
+ harness: Schema.NullOr(Schema.String),
5366
+ cwd: Schema.String,
5367
+ sessionAlive: Schema.Boolean
5368
+ });
5369
+ const FlywheelLastTick = Schema.Struct({
5370
+ tick: Schema.Number,
5371
+ pick: Schema.NullOr(Schema.String),
5372
+ phase: TickMarkerPhase,
5373
+ inFlight: Schema.Array(Schema.String),
5374
+ needsYou: Schema.NullOr(Schema.String),
5375
+ /** The assistant message's `createdAt`. */
5376
+ at: Schema.String
5377
+ });
5378
+ const FlywheelPolicies = Schema.Struct({
5379
+ auto_pickup_backlog: Schema.Boolean,
5380
+ require_uat_before_merge: Schema.Boolean,
5381
+ merge_train_enabled: Schema.Boolean
5382
+ });
5383
+ const FlywheelJournalSummary = Schema.Struct({
5384
+ at: Schema.String,
5385
+ type: Schema.String,
5386
+ source: Schema.optional(Schema.String)
5387
+ });
5388
+ const FlywheelInFlightRow = Schema.Struct({
5389
+ issueId: Schema.String,
5390
+ state: IssueState,
5391
+ attention: Schema.optional(IssueAttention),
5392
+ pr: Schema.optional(DerivedPrState),
5393
+ lastJournal: Schema.NullOr(FlywheelJournalSummary)
5394
+ });
5395
+ const FlywheelOrderBookSummary = Schema.Struct({
5396
+ id: Schema.String,
5397
+ name: Schema.String,
5398
+ status: Schema.String,
5399
+ landed: Schema.Number,
5400
+ total: Schema.Number
5401
+ });
5402
+ const FlywheelDerivedStatus = Schema.Struct({
5403
+ run: FlywheelRunState,
5404
+ conversation: Schema.NullOr(FlywheelConversationSummary),
5405
+ lastTick: Schema.NullOr(FlywheelLastTick),
5406
+ freshness: Schema.NullOr(FlywheelFreshness),
5407
+ policies: FlywheelPolicies,
5408
+ inFlight: Schema.Array(FlywheelInFlightRow),
5409
+ orderBook: Schema.NullOr(FlywheelOrderBookSummary),
5410
+ projectRoot: Schema.String,
5411
+ generatedAt: Schema.String
5412
+ });
5413
+ const decodeFlywheelDerivedStatus = Schema.decodeUnknownSync(FlywheelDerivedStatus);
5414
+ //#endregion
5097
5415
  //#region src/orders.ts
5098
5416
  const OrderBookLane = Schema.Literals(["A", "B"]);
5099
5417
  const OrderBookStatus = Schema.Literals([
@@ -6651,6 +6969,20 @@ const COMPOSER_COMMAND_MANIFEST = [
6651
6969
  "aliases": [],
6652
6970
  "category": "Lifecycle"
6653
6971
  },
6972
+ {
6973
+ "id": "pan-untroubled",
6974
+ "path": ["untroubled"],
6975
+ "display": "/pan untroubled",
6976
+ "description": "Clear an agent troubled gate without spawning it",
6977
+ "args": [{
6978
+ "name": "id",
6979
+ "required": true,
6980
+ "variadic": false
6981
+ }],
6982
+ "options": [],
6983
+ "aliases": [],
6984
+ "category": "Lifecycle"
6985
+ },
6654
6986
  {
6655
6987
  "id": "pan-fork",
6656
6988
  "path": ["fork"],
@@ -6731,10 +7063,16 @@ const COMPOSER_COMMAND_MANIFEST = [
6731
7063
  },
6732
7064
  {
6733
7065
  "flags": "--issue <id>",
6734
- "description": "Issue ID to associate with the new conversation",
7066
+ "description": "Issue ID to associate with the new conversation; without --cwd the new conversation starts in the issue workspace when it exists",
6735
7067
  "required": true,
6736
7068
  "valueHint": "id"
6737
7069
  },
7070
+ {
7071
+ "flags": "--role <role>",
7072
+ "description": "Pane role for the new conversation: conversation (default), work, review, test, plan. With --issue, review makes the handoff the issue's Review row",
7073
+ "required": true,
7074
+ "valueHint": "role"
7075
+ },
6738
7076
  {
6739
7077
  "flags": "--title <title>",
6740
7078
  "description": "Title for the new conversation; defaults to \"Handoff: <focus>\" (first ~70 chars) or \"Handoff: <source title>\" without focus",
@@ -7143,7 +7481,7 @@ const COMPOSER_COMMAND_MANIFEST = [
7143
7481
  },
7144
7482
  {
7145
7483
  "flags": "--force",
7146
- "description": "Clear paused and pending-operator-decision gates and start anyway",
7484
+ "description": "Clear paused, troubled, and pending-operator-decision gates and start anyway",
7147
7485
  "required": false,
7148
7486
  "valueHint": null
7149
7487
  },
@@ -8098,7 +8436,7 @@ const COMPOSER_COMMAND_MANIFEST = [
8098
8436
  "id": "pan-workspace-reap",
8099
8437
  "path": ["workspace", "reap"],
8100
8438
  "display": "/pan workspace reap",
8101
- "description": "List or remove orphaned unhealthy workspace Docker stacks",
8439
+ "description": "List or remove orphaned unhealthy workspace Docker stacks and orphaned workspace networks",
8102
8440
  "args": [],
8103
8441
  "options": [
8104
8442
  {
@@ -8109,7 +8447,7 @@ const COMPOSER_COMMAND_MANIFEST = [
8109
8447
  },
8110
8448
  {
8111
8449
  "flags": "--apply",
8112
- "description": "Run docker compose down -v --remove-orphans for candidates",
8450
+ "description": "Run docker compose down -v --remove-orphans for stack candidates and remove orphaned workspace networks",
8113
8451
  "required": false,
8114
8452
  "valueHint": null
8115
8453
  },
@@ -9655,6 +9993,12 @@ const COMPOSER_COMMAND_MANIFEST = [
9655
9993
  "required": false,
9656
9994
  "valueHint": null
9657
9995
  },
9996
+ {
9997
+ "flags": "--repair-ignore",
9998
+ "description": "Only remove Overdeck's legacy .pan/ line from .gitignore and commit that file (no copy)",
9999
+ "required": false,
10000
+ "valueHint": null
10001
+ },
9658
10002
  {
9659
10003
  "flags": "--state-root <dir>",
9660
10004
  "description": "Override the state worktree root (tests / odd setups)",
@@ -9905,96 +10249,21 @@ const COMPOSER_COMMAND_MANIFEST = [
9905
10249
  "valueHint": "notes"
9906
10250
  },
9907
10251
  {
9908
- "flags": "--run-id <runId>",
9909
- "description": "Review cycle ID used to deduplicate review feedback",
10252
+ "flags": "--tested-sha <sha>",
10253
+ "description": "Test/UAT only: the commit the run exercised (git rev-parse HEAD before the gates)",
9910
10254
  "required": true,
9911
- "valueHint": "runId"
9912
- }
9913
- ],
9914
- "aliases": [],
9915
- "category": "Admin"
9916
- },
9917
- {
9918
- "id": "pan-admin-specialists-logs",
9919
- "path": [
9920
- "admin",
9921
- "specialists",
9922
- "logs"
9923
- ],
9924
- "display": "/pan admin specialists logs",
9925
- "description": "View specialist run logs",
9926
- "args": [
9927
- {
9928
- "name": "project",
9929
- "required": false,
9930
- "variadic": false
9931
- },
9932
- {
9933
- "name": "type",
9934
- "required": false,
9935
- "variadic": false
9936
- },
9937
- {
9938
- "name": "runId",
9939
- "required": false,
9940
- "variadic": false
9941
- }
9942
- ],
9943
- "options": [
9944
- {
9945
- "flags": "--json",
9946
- "description": "Output in JSON format",
9947
- "required": false,
9948
- "valueHint": null
10255
+ "valueHint": "sha"
9949
10256
  },
9950
10257
  {
9951
- "flags": "--limit <count>",
9952
- "description": "Number of runs to show (default: 10)",
10258
+ "flags": "--run-id <runId>",
10259
+ "description": "Review cycle ID used to deduplicate review feedback",
9953
10260
  "required": true,
9954
- "valueHint": "count"
9955
- },
9956
- {
9957
- "flags": "--tail",
9958
- "description": "Follow active run log in real-time",
9959
- "required": false,
9960
- "valueHint": null
10261
+ "valueHint": "runId"
9961
10262
  }
9962
10263
  ],
9963
10264
  "aliases": [],
9964
10265
  "category": "Admin"
9965
10266
  },
9966
- {
9967
- "id": "pan-admin-specialists-cleanup-logs",
9968
- "path": [
9969
- "admin",
9970
- "specialists",
9971
- "cleanup-logs"
9972
- ],
9973
- "display": "/pan admin specialists cleanup-logs",
9974
- "description": "Clean up old specialist logs",
9975
- "args": [{
9976
- "name": "project",
9977
- "required": false,
9978
- "variadic": false
9979
- }, {
9980
- "name": "type",
9981
- "required": false,
9982
- "variadic": false
9983
- }],
9984
- "options": [{
9985
- "flags": "--force",
9986
- "description": "Skip confirmation prompt",
9987
- "required": false,
9988
- "valueHint": null
9989
- }, {
9990
- "flags": "--all",
9991
- "description": "Clean up logs for all projects",
9992
- "required": false,
9993
- "valueHint": null
9994
- }],
9995
- "aliases": [],
9996
- "category": "Admin"
9997
- },
9998
10267
  {
9999
10268
  "id": "pan-admin-remote",
10000
10269
  "path": ["admin", "remote"],
@@ -10885,6 +11154,80 @@ const COMPOSER_COMMAND_MANIFEST = [
10885
11154
  "aliases": [],
10886
11155
  "category": "Conversation"
10887
11156
  },
11157
+ {
11158
+ "id": "pan-conversations-link-pr",
11159
+ "path": ["conversations", "link-pr"],
11160
+ "display": "/pan conversations link-pr",
11161
+ "description": "Link a pull request (URL, #42, or owner/repo#42) to a conversation",
11162
+ "args": [{
11163
+ "name": "query",
11164
+ "required": true,
11165
+ "variadic": false
11166
+ }, {
11167
+ "name": "ref",
11168
+ "required": true,
11169
+ "variadic": false
11170
+ }],
11171
+ "options": [{
11172
+ "flags": "--source <source>",
11173
+ "description": "agent or manual (default: agent inside an agent, else manual)",
11174
+ "required": true,
11175
+ "valueHint": "source"
11176
+ }],
11177
+ "aliases": [],
11178
+ "category": "Conversation"
11179
+ },
11180
+ {
11181
+ "id": "pan-conversations-unlink-pr",
11182
+ "path": ["conversations", "unlink-pr"],
11183
+ "display": "/pan conversations unlink-pr",
11184
+ "description": "Unlink a pull request from a conversation (the sweep will not re-add it)",
11185
+ "args": [{
11186
+ "name": "query",
11187
+ "required": true,
11188
+ "variadic": false
11189
+ }, {
11190
+ "name": "ref",
11191
+ "required": true,
11192
+ "variadic": false
11193
+ }],
11194
+ "options": [],
11195
+ "aliases": [],
11196
+ "category": "Conversation"
11197
+ },
11198
+ {
11199
+ "id": "pan-conversations-prs",
11200
+ "path": ["conversations", "prs"],
11201
+ "display": "/pan conversations prs",
11202
+ "description": "List the pull requests linked to a conversation (* = the one shown)",
11203
+ "args": [{
11204
+ "name": "query",
11205
+ "required": true,
11206
+ "variadic": false
11207
+ }],
11208
+ "options": [{
11209
+ "flags": "--json",
11210
+ "description": "Output { links, effective } as JSON",
11211
+ "required": false,
11212
+ "valueHint": null
11213
+ }],
11214
+ "aliases": [],
11215
+ "category": "Conversation"
11216
+ },
11217
+ {
11218
+ "id": "pan-conversations-auto-archive-on-merge",
11219
+ "path": ["conversations", "auto-archive-on-merge"],
11220
+ "display": "/pan conversations auto-archive-on-merge",
11221
+ "description": "Show or set (on|off) archiving operator conversations once all their linked PRs are merged or closed (default off)",
11222
+ "args": [{
11223
+ "name": "value",
11224
+ "required": false,
11225
+ "variadic": false
11226
+ }],
11227
+ "options": [],
11228
+ "aliases": [],
11229
+ "category": "Conversation"
11230
+ },
10888
11231
  {
10889
11232
  "id": "pan-conversations-heal",
10890
11233
  "path": ["conversations", "heal"],
@@ -11353,40 +11696,314 @@ const COMPOSER_COMMAND_MANIFEST = [
11353
11696
  "category": "CLI"
11354
11697
  },
11355
11698
  {
11356
- "id": "pan-flywheel",
11357
- "path": ["flywheel"],
11358
- "display": "/pan flywheel",
11359
- "description": "Start, stop, or check the flywheel conversation",
11699
+ "id": "pan-worker",
11700
+ "path": ["worker"],
11701
+ "display": "/pan worker",
11702
+ "description": "Registered workers: spawn an issue-linked agent and get its report back; register external agents",
11360
11703
  "args": [],
11361
11704
  "options": [],
11362
11705
  "aliases": [],
11363
- "category": "Flywheel"
11706
+ "category": "CLI"
11364
11707
  },
11365
11708
  {
11366
- "id": "pan-flywheel-start",
11367
- "path": ["flywheel", "start"],
11368
- "display": "/pan flywheel start",
11369
- "description": "Launch a conversation running /pan-flywheel",
11709
+ "id": "pan-worker-run",
11710
+ "path": ["worker", "run"],
11711
+ "display": "/pan worker run",
11712
+ "description": "Start a worker for an issue and wait for its report (exit 0 done, 4 blocked/failed, 2 no report, 3 timeout, 1 error)",
11370
11713
  "args": [],
11371
11714
  "options": [
11372
11715
  {
11373
- "flags": "--model <model>",
11374
- "description": "Model for the flywheel conversation",
11716
+ "flags": "--issue <id>",
11717
+ "description": "Issue the worker belongs to (required)",
11375
11718
  "required": true,
11376
- "valueHint": "model"
11719
+ "valueHint": "id"
11377
11720
  },
11378
11721
  {
11379
- "flags": "--harness <harness>",
11380
- "description": "Harness for the flywheel conversation",
11722
+ "flags": "--prompt <text>",
11723
+ "description": "The brief, inline",
11381
11724
  "required": true,
11382
- "valueHint": "harness"
11725
+ "valueHint": "text"
11383
11726
  },
11384
11727
  {
11385
- "flags": "--cwd <path>",
11386
- "description": "Working directory (default: cwd)",
11728
+ "flags": "--brief <file>",
11729
+ "description": "The brief, from a file",
11387
11730
  "required": true,
11388
- "valueHint": "path"
11389
- }
11731
+ "valueHint": "file"
11732
+ },
11733
+ {
11734
+ "flags": "--model <model>",
11735
+ "description": "Model override (default: roles.worker.model)",
11736
+ "required": true,
11737
+ "valueHint": "model"
11738
+ },
11739
+ {
11740
+ "flags": "--harness <harness>",
11741
+ "description": "Harness override (default: routed from the model)",
11742
+ "required": true,
11743
+ "valueHint": "harness"
11744
+ },
11745
+ {
11746
+ "flags": "--read-only",
11747
+ "description": "Run in the issue workspace with git writes blocked",
11748
+ "required": false,
11749
+ "valueHint": null
11750
+ },
11751
+ {
11752
+ "flags": "--cwd <path>",
11753
+ "description": "Working directory inside the issue workspace",
11754
+ "required": true,
11755
+ "valueHint": "path"
11756
+ },
11757
+ {
11758
+ "flags": "--parent <id>",
11759
+ "description": "Spawning agent or conversation (default: $OVERDECK_AGENT_ID, then $OVERDECK_CONVERSATION)",
11760
+ "required": true,
11761
+ "valueHint": "id"
11762
+ },
11763
+ {
11764
+ "flags": "--name <label>",
11765
+ "description": "Label shown in the Agents Directory",
11766
+ "required": true,
11767
+ "valueHint": "label"
11768
+ },
11769
+ {
11770
+ "flags": "--detach",
11771
+ "description": "Print the worker id and return without waiting",
11772
+ "required": false,
11773
+ "valueHint": null
11774
+ },
11775
+ {
11776
+ "flags": "--timeout <seconds>",
11777
+ "description": "Stop waiting after this many seconds (exit 3; the worker keeps running)",
11778
+ "required": true,
11779
+ "valueHint": "seconds"
11780
+ },
11781
+ {
11782
+ "flags": "--stop-after-report",
11783
+ "description": "Stop the worker after its first report",
11784
+ "required": false,
11785
+ "valueHint": null
11786
+ }
11787
+ ],
11788
+ "aliases": [],
11789
+ "category": "CLI"
11790
+ },
11791
+ {
11792
+ "id": "pan-worker-wait",
11793
+ "path": ["worker", "wait"],
11794
+ "display": "/pan worker wait",
11795
+ "description": "Wait for a worker's report (same exit codes as run); the status line names its seq",
11796
+ "args": [{
11797
+ "name": "worker-id",
11798
+ "required": true,
11799
+ "variadic": false
11800
+ }],
11801
+ "options": [{
11802
+ "flags": "--after <seq>",
11803
+ "description": "Return the next report after this seq (default: the newest report, whenever written)",
11804
+ "required": true,
11805
+ "valueHint": "seq"
11806
+ }, {
11807
+ "flags": "--timeout <seconds>",
11808
+ "description": "Stop waiting after this many seconds (exit 3)",
11809
+ "required": true,
11810
+ "valueHint": "seconds"
11811
+ }],
11812
+ "aliases": [],
11813
+ "category": "CLI"
11814
+ },
11815
+ {
11816
+ "id": "pan-worker-report",
11817
+ "path": ["worker", "report"],
11818
+ "display": "/pan worker report",
11819
+ "description": "Record a worker's report (run by the worker itself)",
11820
+ "args": [{
11821
+ "name": "worker-id",
11822
+ "required": true,
11823
+ "variadic": false
11824
+ }],
11825
+ "options": [
11826
+ {
11827
+ "flags": "--file <path>",
11828
+ "description": "Read the Markdown report from a file",
11829
+ "required": true,
11830
+ "valueHint": "path"
11831
+ },
11832
+ {
11833
+ "flags": "--stdin",
11834
+ "description": "Read the Markdown report from stdin",
11835
+ "required": false,
11836
+ "valueHint": null
11837
+ },
11838
+ {
11839
+ "flags": "--status <status>",
11840
+ "description": "done | blocked | failed (default: done)",
11841
+ "required": true,
11842
+ "valueHint": "status"
11843
+ }
11844
+ ],
11845
+ "aliases": [],
11846
+ "category": "CLI"
11847
+ },
11848
+ {
11849
+ "id": "pan-worker-list",
11850
+ "path": ["worker", "list"],
11851
+ "display": "/pan worker list",
11852
+ "description": "List workers with their parent, live state and newest report",
11853
+ "args": [],
11854
+ "options": [
11855
+ {
11856
+ "flags": "--issue <id>",
11857
+ "description": "Only this issue's workers",
11858
+ "required": true,
11859
+ "valueHint": "id"
11860
+ },
11861
+ {
11862
+ "flags": "--parent <id>",
11863
+ "description": "Only workers of this parent",
11864
+ "required": true,
11865
+ "valueHint": "id"
11866
+ },
11867
+ {
11868
+ "flags": "--json",
11869
+ "description": "Print JSON",
11870
+ "required": false,
11871
+ "valueHint": null
11872
+ }
11873
+ ],
11874
+ "aliases": [],
11875
+ "category": "CLI"
11876
+ },
11877
+ {
11878
+ "id": "pan-worker-register",
11879
+ "path": ["worker", "register"],
11880
+ "display": "/pan worker register",
11881
+ "description": "Record an agent another tool launched so the Agents Directory shows it (read-only; prints its id)",
11882
+ "args": [],
11883
+ "options": [
11884
+ {
11885
+ "flags": "--source <name>",
11886
+ "description": "Who launched it ([a-z0-9-], not codex-plugin) (required)",
11887
+ "required": true,
11888
+ "valueHint": "name"
11889
+ },
11890
+ {
11891
+ "flags": "--external-id <id>",
11892
+ "description": "The launcher's id for it (required)",
11893
+ "required": true,
11894
+ "valueHint": "id"
11895
+ },
11896
+ {
11897
+ "flags": "--harness <harness>",
11898
+ "description": "codex, claude-code, … (required)",
11899
+ "required": true,
11900
+ "valueHint": "harness"
11901
+ },
11902
+ {
11903
+ "flags": "--model <model>",
11904
+ "description": "Model it runs",
11905
+ "required": true,
11906
+ "valueHint": "model"
11907
+ },
11908
+ {
11909
+ "flags": "--cwd <path>",
11910
+ "description": "Its working directory",
11911
+ "required": true,
11912
+ "valueHint": "path"
11913
+ },
11914
+ {
11915
+ "flags": "--issue <id>",
11916
+ "description": "Issue it works on",
11917
+ "required": true,
11918
+ "valueHint": "id"
11919
+ },
11920
+ {
11921
+ "flags": "--parent <id>",
11922
+ "description": "Spawning agent id, conversation tmux session, or claude-session:<uuid>",
11923
+ "required": true,
11924
+ "valueHint": "id"
11925
+ },
11926
+ {
11927
+ "flags": "--label <text>",
11928
+ "description": "Label shown in the Agents Directory",
11929
+ "required": true,
11930
+ "valueHint": "text"
11931
+ },
11932
+ {
11933
+ "flags": "--pid <n>",
11934
+ "description": "Its process id (liveness is read from it)",
11935
+ "required": true,
11936
+ "valueHint": "n"
11937
+ },
11938
+ {
11939
+ "flags": "--transcript <path>",
11940
+ "description": "Its transcript file",
11941
+ "required": true,
11942
+ "valueHint": "path"
11943
+ },
11944
+ {
11945
+ "flags": "--session-id <id>",
11946
+ "description": "Its session or thread id",
11947
+ "required": true,
11948
+ "valueHint": "id"
11949
+ },
11950
+ {
11951
+ "flags": "--json",
11952
+ "description": "Print { id, created }",
11953
+ "required": false,
11954
+ "valueHint": null
11955
+ }
11956
+ ],
11957
+ "aliases": [],
11958
+ "category": "CLI"
11959
+ },
11960
+ {
11961
+ "id": "pan-flywheel",
11962
+ "path": ["flywheel"],
11963
+ "display": "/pan flywheel",
11964
+ "description": "Start, stop, pause, resume, or inspect the flywheel conversation",
11965
+ "args": [],
11966
+ "options": [],
11967
+ "aliases": [],
11968
+ "category": "Flywheel"
11969
+ },
11970
+ {
11971
+ "id": "pan-flywheel-start",
11972
+ "path": ["flywheel", "start"],
11973
+ "display": "/pan flywheel start",
11974
+ "description": "Launch a conversation running /pan-flywheel",
11975
+ "args": [],
11976
+ "options": [
11977
+ {
11978
+ "flags": "--model <model>",
11979
+ "description": "Model for the flywheel conversation",
11980
+ "required": true,
11981
+ "valueHint": "model"
11982
+ },
11983
+ {
11984
+ "flags": "--harness <harness>",
11985
+ "description": "Harness for the flywheel conversation",
11986
+ "required": true,
11987
+ "valueHint": "harness"
11988
+ },
11989
+ {
11990
+ "flags": "--cwd <path>",
11991
+ "description": "Working directory (default: cwd)",
11992
+ "required": true,
11993
+ "valueHint": "path"
11994
+ },
11995
+ {
11996
+ "flags": "--orders <book-id>",
11997
+ "description": "Order book the flywheel works from",
11998
+ "required": true,
11999
+ "valueHint": "book-id"
12000
+ },
12001
+ {
12002
+ "flags": "--fresh",
12003
+ "description": "Replace a paused flywheel conversation instead of refusing",
12004
+ "required": false,
12005
+ "valueHint": null
12006
+ }
11390
12007
  ],
11391
12008
  "aliases": [],
11392
12009
  "category": "Flywheel"
@@ -11395,7 +12012,52 @@ const COMPOSER_COMMAND_MANIFEST = [
11395
12012
  "id": "pan-flywheel-stop",
11396
12013
  "path": ["flywheel", "stop"],
11397
12014
  "display": "/pan flywheel stop",
11398
- "description": "Stop the flywheel conversation",
12015
+ "description": "Ask the loop to write its report, wait for it, then pause",
12016
+ "args": [],
12017
+ "options": [{
12018
+ "flags": "--timeout <ms>",
12019
+ "description": "How long to wait for the report (default 120000)",
12020
+ "required": true,
12021
+ "valueHint": "ms"
12022
+ }],
12023
+ "aliases": [],
12024
+ "category": "Flywheel"
12025
+ },
12026
+ {
12027
+ "id": "pan-flywheel-abort",
12028
+ "path": ["flywheel", "abort"],
12029
+ "display": "/pan flywheel abort",
12030
+ "description": "Stop the flywheel conversation without a report",
12031
+ "args": [],
12032
+ "options": [],
12033
+ "aliases": [],
12034
+ "category": "Flywheel"
12035
+ },
12036
+ {
12037
+ "id": "pan-flywheel-pause",
12038
+ "path": ["flywheel", "pause"],
12039
+ "display": "/pan flywheel pause",
12040
+ "description": "Stop the flywheel session, keeping its conversation and transcript",
12041
+ "args": [],
12042
+ "options": [],
12043
+ "aliases": [],
12044
+ "category": "Flywheel"
12045
+ },
12046
+ {
12047
+ "id": "pan-flywheel-resume",
12048
+ "path": ["flywheel", "resume"],
12049
+ "display": "/pan flywheel resume",
12050
+ "description": "Respawn a paused flywheel and re-send /pan-flywheel",
12051
+ "args": [],
12052
+ "options": [],
12053
+ "aliases": [],
12054
+ "category": "Flywheel"
12055
+ },
12056
+ {
12057
+ "id": "pan-flywheel-report",
12058
+ "path": ["flywheel", "report"],
12059
+ "display": "/pan flywheel report",
12060
+ "description": "Ask a running loop for its report, or print .pan/flywheel/report.md",
11399
12061
  "args": [],
11400
12062
  "options": [],
11401
12063
  "aliases": [],
@@ -11405,7 +12067,7 @@ const COMPOSER_COMMAND_MANIFEST = [
11405
12067
  "id": "pan-flywheel-status",
11406
12068
  "path": ["flywheel", "status"],
11407
12069
  "display": "/pan flywheel status",
11408
- "description": "Say whether the flywheel conversation is running",
12070
+ "description": "Show the derived flywheel status: run, last tick, policies, in-flight issues, order book",
11409
12071
  "args": [],
11410
12072
  "options": [{
11411
12073
  "flags": "--json",
@@ -11416,6 +12078,26 @@ const COMPOSER_COMMAND_MANIFEST = [
11416
12078
  "aliases": [],
11417
12079
  "category": "Flywheel"
11418
12080
  },
12081
+ {
12082
+ "id": "pan-flywheel-stats",
12083
+ "path": ["flywheel", "stats"],
12084
+ "display": "/pan flywheel stats",
12085
+ "description": "Substrate-bug discovery rate and P0 count, computed from the tracker and forge",
12086
+ "args": [],
12087
+ "options": [{
12088
+ "flags": "--json",
12089
+ "description": "Output as JSON",
12090
+ "required": false,
12091
+ "valueHint": null
12092
+ }, {
12093
+ "flags": "--window <days>",
12094
+ "description": "Window in days (default 30)",
12095
+ "required": true,
12096
+ "valueHint": "days"
12097
+ }],
12098
+ "aliases": [],
12099
+ "category": "Flywheel"
12100
+ },
11419
12101
  {
11420
12102
  "id": "pan-merge",
11421
12103
  "path": ["merge"],
@@ -11855,9 +12537,27 @@ const COMPOSER_COMMAND_MANIFEST = [
11855
12537
  "required": true,
11856
12538
  "valueHint": "duration"
11857
12539
  },
12540
+ {
12541
+ "flags": "--deacon",
12542
+ "description": "Start Cloister/Deacon on the reloaded dashboard (always on after a reload)",
12543
+ "required": false,
12544
+ "valueHint": null
12545
+ },
11858
12546
  {
11859
12547
  "flags": "--no-deacon",
11860
- "description": "Skip Cloister/Deacon auto-start after reload",
12548
+ "description": "Refused: a Deacon-off dashboard is a peer and cannot hold the host dashboard port",
12549
+ "required": false,
12550
+ "valueHint": null
12551
+ },
12552
+ {
12553
+ "flags": "--resume",
12554
+ "description": "Enable agent auto-resume on the reloaded dashboard (default: keep the running dashboard's resume gate)",
12555
+ "required": false,
12556
+ "valueHint": null
12557
+ },
12558
+ {
12559
+ "flags": "--no-resume",
12560
+ "description": "Disable agent auto-resume on the reloaded dashboard (default: keep the running dashboard's resume gate)",
11861
12561
  "required": false,
11862
12562
  "valueHint": null
11863
12563
  }
@@ -12699,9 +13399,7 @@ const COMPOSER_COMMAND_MANIFEST = [
12699
13399
  ];
12700
13400
  const COMPOSER_COMMAND_INSERT_OVERRIDES = {
12701
13401
  "plan finalize": "/pan plan finalize ",
12702
- "admin specialists done": "/pan admin specialists done",
12703
- "admin specialists logs": "/pan admin specialists logs",
12704
- "admin specialists cleanup-logs": "/pan admin specialists cleanup-logs"
13402
+ "admin specialists done": "/pan admin specialists done"
12705
13403
  };
12706
13404
  const COMPOSER_COMMAND_VARIANTS = [
12707
13405
  {
@@ -12879,7 +13577,8 @@ const AGENT_ROLES = [
12879
13577
  "test",
12880
13578
  "uat",
12881
13579
  "strike",
12882
- "plan"
13580
+ "plan",
13581
+ "conversation"
12883
13582
  ];
12884
13583
  function isTerminalBackendName(value) {
12885
13584
  return typeof value === "string" && TERMINAL_BACKEND_NAMES.includes(value);
@@ -12888,6 +13587,182 @@ function isAgentRole(value) {
12888
13587
  return typeof value === "string" && AGENT_ROLES.includes(value);
12889
13588
  }
12890
13589
  //#endregion
12891
- export { ACP_BEHAVIOR, AGENT_ROLES, Activity, ActivityDetailedEvent, ActivityEntryEvent, ActivityTtsEvent, ActivityUpdatedEvent, AdmissionState, AgentActivityChangedEvent, AgentChannelReply, AgentChannelReplyEvent, AgentCompletedEvent, AgentContextSaturationChangedEvent, AgentCreatedEvent, AgentCurrentIssueSetEvent, AgentEnrichmentChangedEvent, AgentHealthKind, AgentHealthSnapshot, AgentHealthStatus, AgentHeartbeatDeadEvent, AgentHookFiredEvent, AgentId, AgentMessageReceivedEvent, AgentModelSetEvent, AgentOutput, AgentOutputReceivedEvent, AgentPermissionRequestedEvent, AgentPermissionResolvedEvent, AgentResolution, AgentResolutionChangedEvent, AgentRuntimeSnapshot, AgentSnapshot, AgentStartedEvent, AgentStateRestoredEvent, AgentStatus, AgentStatusChangedEvent, AgentStoppedEvent, AgentThinkingStartedEvent, AgentThinkingStoppedEvent, AgentTurnDiffCompletedEvent, AgentWaitingClearedEvent, AgentWaitingStartedEvent, ArtifactAgentHarness, ArtifactAgentRole, ArtifactCreateResponse, ArtifactDetailResponse, ArtifactHash, ArtifactId, ArtifactLifecycleState, ArtifactListEntry, ArtifactListResponse, ArtifactMetadata, ArtifactPublishResponse, ArtifactSlug, ArtifactStatusResponse, ArtifactUnshareResponse, ArtifactUrls, ArtifactValidationCode, ArtifactValidationFinding, ArtifactValidationResult, BackendPane, BackendPaneChangedEvent, BackendPaneRemovedEvent, BeadsFreshnessChangedEvent, CHANNEL_REPLY_KIND_VALUES, CLAUDE_CODE_BEHAVIOR, CODEX_BEHAVIOR, COMPOSER_COMMAND_INSERT_OVERRIDES, COMPOSER_COMMAND_MANIFEST, COMPOSER_COMMAND_VARIANTS, CONTEXT_LAYER_KINDS, CONTEXT_PREVIEW_HARNESSES, ChannelPermissionRequestSnapshot, ChannelReplyArtifactRef, ChannelReplyKind, ChatMessage, ClaudeChannelPermissionBehavior, CompactBoundary, ContextEditableLayerRecord, ContextHarnessPreviews, ContextLayerDraft, ContextLayerKind, ContextLayerSaveRequest, ContextLayerSaveResponse, ContextLayerTarget, ContextLayersResponse, ContextPreviewDiagnostic, ContextPreviewHarness, ContextPreviewRequest, ContextPreviewResponse, ContextProjectSummary, ContextSyncRequest, ContextSyncResponse, ContextSyncTarget, ContextUsage, ContextWorkspaceSummary, ConversationCompactingChangedEvent, ConversationCostSummary, ConversationCreatedEvent, ConversationEvent, ConversationFilter, ConversationMovedEvent, ConversationPermissionChangedEvent, ConversationResponse, ConversationTitleChangedEvent, CostEventRecordedEvent, DEFAULT_MAX_MEMORY_OBSERVATIONS_PER_ISSUE, DEFAULT_MAX_TURN_DIFF_SUMMARIES_PER_AGENT, DashboardLifecycleCompletedEvent, DashboardLifecycleFailedEvent, DashboardLifecycleStartedEvent, DashboardSnapshot, DeepWipeRpc, DeployStalenessSnapshot, DerivedBranchState, DerivedIssueState, DerivedPrState, DiscoveredSessionSnapshot, DomainEvent, EDITORS, EditorIdSchema, EmbedProgressEvent, EmbedProgressSnapshot, EmbedSessionsRpc, EnrichCompleteEvent, EnrichProgressEvent, EnrichProgressSnapshot, EnrichSessionsRpc, EnrichStatsSnapshot, ExtractionProviderConfig, ExtractionProviderTarget, FeatureNode, FeatureRegistryEntry, FeatureRegistryStatus, FlywheelAgent, FlywheelAgentStatus, FlywheelEffort, FlywheelHarness, FlywheelHeadline, FlywheelHttpUrl, FlywheelOrchestrator, FlywheelOrders, FlywheelParkedItem, FlywheelPipelineItem, FlywheelPipelineStatus, FlywheelPipelineVerb, FlywheelRunId, FlywheelScope, FlywheelStats, FlywheelStatsCriteria, FlywheelStatsCriterion, FlywheelStatsCriterionStatus, FlywheelStatsCriterionValue, FlywheelStatsCriterionValueObject, FlywheelStatsTrend, FlywheelStatus, FlywheelSubstrateBug, FlywheelSubstrateBugStatus, FlywheelSuggestion, FlywheelSuggestionAction, FlywheelSuggestionPriority, FlywheelSystemStatus, GetAvailableEditorsRpc, GetConversationCostByWorkspaceRpc, GetConversationCostRpc, GetConversationStatsRpc, GetDiscoveredSessionRpc, GetSessionsFeedFacetsRpc, GetSnapshotRpc, GlobalContextLayerRecord, GlobalContextLayerTarget, HOOK_INVENTORY, HealthReason, HealthState, HostHealthMetrics, HostPlatform, HygieneFinding, HygienePullRequest, HygieneReport, INITIAL_READ_MODEL_STATE, ISSUE_ATTENTIONS, ISSUE_STATES, ISSUE_STATE_PRECEDENCE, IssueAttention, IssueId, IssueState, IssueStateChangedEvent, IssueStatusChangedEvent, IssueTransitionedEvent, IssuesDeltaEvent, IssuesSnapshotEvent, IssuesUpdatedEvent, KIMI_CODE_BEHAVIOR, KNOWN_HARNESSES, LegacySystemHealthSummary, LegacyWebhookRelaySummary, LinearMcpAuthCallbackRelayedEvent, LinearMcpAuthHealthyEvent, LinearMcpAuthNotifiedEvent, LinearMcpAuthRequiredEvent, ListDiscoveredSessionsRpc, ListSessionsFeedRpc, MAX_CHANNEL_REPLY_ARTIFACT_LABEL_LENGTH, MAX_CHANNEL_REPLY_ARTIFACT_REFS, MAX_CHANNEL_REPLY_ARTIFACT_URI_LENGTH, MAX_CHANNEL_REPLY_SUMMARY_LENGTH, MEMBERSHIP_UNAVAILABLE_REASONS, MUSE_BEHAVIOR, MemoryAgentRole, MemoryHealthChangedEvent, MemoryIdentity, MemoryObservation, MemoryObservationCreatedEvent, MemoryResetMarkerCreatedEvent, MemoryRollupTriggeredEvent, MemoryStatus, MemoryStatusPhase, MemoryStatusUpdatedEvent, MemoryTokenUsage, MergeReadyEvent, ModelOrigin, ModelOriginEntry, OHMYPI_BEHAVIOR, OPENCODE_BEHAVIOR, OVERDECK_AGENT_PROTOCOL_VERSION, OVERDECK_DASHBOARD_PROTOCOL_VERSION, OpenInEditorInput, OperatorInterventionEvent, OrderBook, OrderBookIndexEntry, OrderBookItem, OrderBookLane, OrderBookPosture, OrderBookSettings, OrderBookStatus, PanRpcError, PanRpcGroup, PendingTurn, PipelineReviewCompletedEvent, PipelineReviewStartedEvent, PipelineTestCompletedEvent, PipelineTestStartedEvent, PipelineVerificationFailedEvent, PipelineVerificationStartedEvent, PlanItemStatusChangedEvent, PlanItemsUnblockedEvent, PlanSubitemStatusChangedEvent, PlanningFailedEvent, PlanningStartedEvent, PlanningSyncEvent, PrChecksState, PrReviewState, ProjectCiHeadObservedEvent, ProjectCiSnapshot, ProjectCiSuite, ProjectCiSuiteObservedEvent, ProjectContextLayerRecord, ProjectContextLayerTarget, ProjectSessionTree, ProposedPlan, RagDecision, RagDecisionSource, ReadFileAtPathInput, ReadFileAtPathResult, ReadFileAtPathRpc, ReadWorkspaceFileInput, ReadWorkspaceFileResult, ReadWorkspaceFileRpc, ReplayEventsRpc, ResetMarker, ResetMarkerScope, ResizeTerminalRpc, ResolveFilePathExistsInput, ResolveFilePathExistsResult, ResolveFilePathExistsRpc, ResourceStats, ResourcesUpdatedEvent, RestartGateChangedEvent, RestartGateKind, RestartGateOutcome, RestartGateRequest, RestartGateSnapshot, ReviewApprovedEvent, ReviewCoordinatorDiedEvent, ReviewCoordinatorStartedEvent, ReviewReviewerCompletedEvent, ReviewReviewerStartedEvent, ReviewSpecialistTimedOutEvent, ReviewVerdictDispatchedEvent, ReviewVerdictRejectedEvent, ReviewVerdictRestoreBlockedEvent, ReviewerRoundMetadata, ReviewerRoundSummary, Role, ScanCompleteEvent, ScanConversationsRpc, ScanProgressEvent, ScanProgressSnapshot, ScanResult, ScanStartedEvent, SearchConversationsRpc, SendTerminalInputRpc, SequenceNumber, ServiceHealthSnapshot, ServiceHealthStatus, SessionNode, SessionNodePresence, SessionNodeType, SessionTreeDelta, SessionsFeedFacetsSnapshot, SessionsFeedRowSnapshot, SessionsFeedSource, ShadowInferenceUpdateEvent, ShellOpenInEditorRpc, SpecialistCompletedEvent, SpecialistFailedEvent, SpecialistLifecycle, SpecialistStartedEvent, StartAgentRpc, StartPlanningRpc, SubagentSummary, SubscribeAgentOutputRpc, SubscribeConversationMessagesRpc, SubscribeDomainEventsRpc, SubscribeIssueEventsRpc, SubscribeProjectSessionTreeRpc, SubscribeTerminalRpc, SubstrateBugFiledEvent, SweepEscalatedEvent, SweepRecommendationEvent, SweepScanEvent, SystemHealthConsumer, SystemHealthSeverityChangedEvent, SystemHealthSnapshot, SystemHeartbeatEvent, TELEMETRY_CLI_VERBS, TELEMETRY_EVENT_CATALOG, TELEMETRY_EVENT_NAMES, TELEMETRY_PROPERTY_DOMAINS, TERMINAL_BACKEND_NAMES, TerminalCloseRpc, TerminalOpenRpc, TerminalOutput, TerminalResizeRpc, TerminalWriteRpc, TestPassedEvent, ThinkingState, TurnDiffFileChange, TurnDiffSummary, WIRED_HOOK_INVENTORY, WIRED_HOOK_NAMES, WS_METHODS, WaitingReason, WaitingState, WorkCompletedEvent, WorkLogEntry, WorkspaceAbortedEvent, WorkspaceArtifactsResponse, WorkspaceContextLayerRecord, WorkspaceContextLayerTarget, WorkspaceCreatedEvent, WorkspaceDeletedEvent, WorkspaceDestroyedEvent, WorkspaceWipeStartedEvent, WriteFileAtPathInput, WriteFileAtPathResult, WriteFileAtPathRpc, applyEvent, applyEvents, applyIssueDelta, compareIssueIds, createIssueDelta, decodeFlywheelStats, deriveProjectCi, encodeFlywheelStats, getHarness, getHarnessBehavior, getMaxMemoryObservationsPerIssue, getMaxTurnDiffSummariesPerAgent, getRuntimeBehavior, isAgentRole, isAgentSessionName, isChannelReplyKind, isIssueAttention, isIssueState, isTerminalBackendName, isTerminalTurnDiffSummaryStatus, normalizeChannelReplyPayload, omitTurnDiffSummariesForAgent, projectLegacySystemHealthSummary, syncSnapshot, trimMemoryObservations, trimTurnDiffSummaries };
13590
+ //#region src/agent-directory.ts
13591
+ const DirectoryEntryKind = Schema.Literals([
13592
+ "agent",
13593
+ "conversation",
13594
+ "subagent",
13595
+ "external"
13596
+ ]);
13597
+ const DirectoryEntryState = Schema.Literals([
13598
+ "working",
13599
+ "idle",
13600
+ "blocked",
13601
+ "done",
13602
+ "stopped",
13603
+ "unknown"
13604
+ ]);
13605
+ const DirectoryEntrySource = Schema.Literals([
13606
+ "overdeck",
13607
+ "pane",
13608
+ "conversation",
13609
+ "claude-subagent",
13610
+ "codex-subagent",
13611
+ "registered",
13612
+ "codex-plugin"
13613
+ ]);
13614
+ const DirectoryTranscriptRef = Schema.Union([
13615
+ Schema.Struct({
13616
+ route: Schema.Literal("agent"),
13617
+ agentId: Schema.String
13618
+ }),
13619
+ Schema.Struct({
13620
+ route: Schema.Literal("agent-subagent"),
13621
+ agentId: Schema.String,
13622
+ subagentId: Schema.String
13623
+ }),
13624
+ Schema.Struct({
13625
+ route: Schema.Literal("conversation"),
13626
+ conversationName: Schema.String
13627
+ }),
13628
+ Schema.Struct({
13629
+ route: Schema.Literal("conversation-subagent"),
13630
+ conversationName: Schema.String,
13631
+ subagentId: Schema.String
13632
+ })
13633
+ ]);
13634
+ const DirectoryEntryLocation = Schema.Literals(["local", "remote"]);
13635
+ const DirectoryPauseBy = Schema.Literals([
13636
+ "operator",
13637
+ "scheduler",
13638
+ "machine"
13639
+ ]);
13640
+ const DirectoryPause = Schema.Struct({
13641
+ by: DirectoryPauseBy,
13642
+ reason: Schema.NullOr(Schema.String),
13643
+ since: Schema.NullOr(Schema.String)
13644
+ });
13645
+ const DirectoryEntry = Schema.Struct({
13646
+ id: Schema.String,
13647
+ kind: DirectoryEntryKind,
13648
+ label: Schema.String,
13649
+ location: DirectoryEntryLocation,
13650
+ /** projects.yaml key; `unassigned` when none (D5). */
13651
+ projectKey: Schema.String,
13652
+ /** Uppercase issue id, e.g. `PAN-3920`. */
13653
+ issueId: Schema.NullOr(Schema.String),
13654
+ /** The issue's title from the dashboard's tracker cache; null when unknown. */
13655
+ issueTitle: Schema.NullOr(Schema.String),
13656
+ parentId: Schema.NullOr(Schema.String),
13657
+ role: Schema.NullOr(Schema.String),
13658
+ /** `unknown` when not known. */
13659
+ harness: Schema.String,
13660
+ /** `unknown` when not known. */
13661
+ model: Schema.String,
13662
+ state: DirectoryEntryState,
13663
+ startedAt: Schema.NullOr(Schema.String),
13664
+ lastActivityAt: Schema.NullOr(Schema.String),
13665
+ costUsd: Schema.NullOr(Schema.Number),
13666
+ source: DirectoryEntrySource,
13667
+ transcript: Schema.NullOr(DirectoryTranscriptRef),
13668
+ /** The pause gate from state.json, native agents only (PAN-4197). */
13669
+ pause: Schema.optional(DirectoryPause)
13670
+ });
13671
+ /**
13672
+ * `window`: live entries plus finished ones active inside `windowHours`.
13673
+ * `live` (PAN-4197): what is running or waiting now; `windowHours` is 0.
13674
+ */
13675
+ const DirectoryScope = Schema.Literals(["window", "live"]);
13676
+ const AgentDirectoryResponse = Schema.Struct({
13677
+ generatedAt: Schema.String,
13678
+ windowHours: Schema.Number,
13679
+ scope: Schema.optional(DirectoryScope),
13680
+ entries: Schema.Array(DirectoryEntry)
13681
+ });
13682
+ //#endregion
13683
+ //#region src/companion-terminal.ts
13684
+ /**
13685
+ * Which companion terminal a conversation gets, or `null` for "keep the
13686
+ * owner pane as TERMINAL". A Codex conversation still on the legacy
13687
+ * `codex.transport: tui` runs the native TUI in its owner pane; the server
13688
+ * adapter reports that as `unsupported` and points at the runtime pane.
13689
+ */
13690
+ function companionTerminalKindFor(conversation) {
13691
+ if (conversation.harness === "opencode") return "opencode-attach";
13692
+ if (conversation.harness === "codex") return "codex-resume-remote";
13693
+ return null;
13694
+ }
13695
+ /** Body keys each mutation accepts. Anything else is rejected as target injection. */
13696
+ const COMPANION_TERMINAL_OPEN_BODY_KEYS = [];
13697
+ const COMPANION_TERMINAL_CLOSE_BODY_KEYS = ["generation"];
13698
+ //#endregion
13699
+ //#region src/pull-request-ref.ts
13700
+ const SCHEME = String.raw`(?:https?:\/\/)?`;
13701
+ const HOST = String.raw`([a-z0-9.-]+(?::\d+)?)`;
13702
+ const TAIL = String.raw`(?:\/[^?#]*)?(?:[?#].*)?$`;
13703
+ const GITLAB_MR = new RegExp(String.raw`^${SCHEME}${HOST}\/((?:[\w.-]+\/)+[\w.-]+)\/-\/merge_requests\/(\d+)${TAIL}`, "i");
13704
+ const GITHUB_PR = new RegExp(String.raw`^${SCHEME}${HOST}\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)${TAIL}`, "i");
13705
+ const GITLAB_MR_LEGACY = new RegExp(String.raw`^${SCHEME}${HOST}\/((?:[\w.-]+\/)+[\w.-]+)\/merge_requests\/(\d+)${TAIL}`, "i");
13706
+ const SHORT_REF = /^(?:((?:[\w.-]+\/)+[\w.-]+))?[#!](\d+)$/;
13707
+ function canonicalPullRequestUrl(key, forge) {
13708
+ return forge === "gitlab" ? `https://${key.host}/${key.repository}/-/merge_requests/${key.number}` : `https://${key.host}/${key.repository}/pull/${key.number}`;
13709
+ }
13710
+ function build(host, repository, number, forge) {
13711
+ if (!Number.isSafeInteger(number) || number <= 0) return null;
13712
+ const key = {
13713
+ host: host.toLowerCase(),
13714
+ repository: repository.toLowerCase().replace(/\.git$/, ""),
13715
+ number
13716
+ };
13717
+ return {
13718
+ ...key,
13719
+ forge,
13720
+ url: canonicalPullRequestUrl(key, forge)
13721
+ };
13722
+ }
13723
+ /**
13724
+ * Accepts a full PR/MR URL, `#42`, or `owner/repo#42` (`!42` for GitLab MRs).
13725
+ * The short forms need `defaultRepo` for host and forge (`#42` for the
13726
+ * repository too) and return null without it. Anything else returns null.
13727
+ */
13728
+ function parsePullRequestRef(input, defaultRepo) {
13729
+ const text = input.trim();
13730
+ if (!text) return null;
13731
+ for (const [pattern, forge] of [
13732
+ [GITLAB_MR, "gitlab"],
13733
+ [GITHUB_PR, "github"],
13734
+ [GITLAB_MR_LEGACY, "gitlab"]
13735
+ ]) {
13736
+ const match = pattern.exec(text);
13737
+ if (match) return build(match[1], match[2], Number(match[3]), forge);
13738
+ }
13739
+ const short = SHORT_REF.exec(text);
13740
+ if (!short || !defaultRepo) return null;
13741
+ return build(defaultRepo.host, short[1] ?? defaultRepo.repository, Number(short[2]), defaultRepo.forge);
13742
+ }
13743
+ /**
13744
+ * The repository behind a git remote URL (https, ssh://, or scp-style), or null
13745
+ * when the host names neither GitHub nor GitLab.
13746
+ */
13747
+ function repoFromRemoteUrl(remote) {
13748
+ if (!remote) return null;
13749
+ const text = remote.trim();
13750
+ const match = /^[a-z][a-z0-9+.-]*:\/\/(?:[^@/]*@)?([^/:]+)(?::\d+)?\/(.+?)(?:\.git)?\/?$/i.exec(text) ?? /^(?:[^@/]+@)?([^/:]+):(.+?)(?:\.git)?\/?$/i.exec(text);
13751
+ if (!match) return null;
13752
+ const host = match[1].toLowerCase();
13753
+ const forge = host.includes("gitlab") ? "gitlab" : host.includes("github") ? "github" : null;
13754
+ if (!forge) return null;
13755
+ return {
13756
+ host,
13757
+ repository: match[2].toLowerCase(),
13758
+ forge
13759
+ };
13760
+ }
13761
+ /** True when the ref's host and repository match one of the configured repos. */
13762
+ function isConfiguredPullRequestRepo(ref, repos) {
13763
+ return repos.some((repo) => repo.host === ref.host && repo.repository === ref.repository);
13764
+ }
13765
+ //#endregion
13766
+ export { ACP_BEHAVIOR, AGENT_ROLES, Activity, ActivityDetailedEvent, ActivityEntryEvent, ActivityTtsEvent, ActivityUpdatedEvent, AdmissionState, AgentActivityChangedEvent, AgentChannelReply, AgentChannelReplyEvent, AgentCompletedEvent, AgentContextSaturationChangedEvent, AgentCreatedEvent, AgentCurrentIssueSetEvent, AgentDirectoryResponse, AgentEnrichmentChangedEvent, AgentHealthKind, AgentHealthSnapshot, AgentHealthStatus, AgentHeartbeatDeadEvent, AgentHookFiredEvent, AgentId, AgentMessageReceivedEvent, AgentModelSetEvent, AgentOutput, AgentOutputReceivedEvent, AgentPermissionRequestedEvent, AgentPermissionResolvedEvent, AgentResolution, AgentResolutionChangedEvent, AgentRuntimeSnapshot, AgentSnapshot, AgentStartedEvent, AgentStateRestoredEvent, AgentStatus, AgentStatusChangedEvent, AgentStoppedEvent, AgentThinkingStartedEvent, AgentThinkingStoppedEvent, AgentTurnDiffCompletedEvent, AgentWaitingClearedEvent, AgentWaitingStartedEvent, ArtifactAgentHarness, ArtifactAgentRole, ArtifactCreateResponse, ArtifactDetailResponse, ArtifactHash, ArtifactId, ArtifactLifecycleState, ArtifactListEntry, ArtifactListResponse, ArtifactMetadata, ArtifactPublishResponse, ArtifactSlug, ArtifactStatusResponse, ArtifactUnshareResponse, ArtifactUrls, ArtifactValidationCode, ArtifactValidationFinding, ArtifactValidationResult, BackendPane, BackendPaneChangedEvent, BackendPaneRemovedEvent, BeadsFreshnessChangedEvent, CHANNEL_REPLY_KIND_VALUES, CLAUDE_CODE_BEHAVIOR, CODEX_BEHAVIOR, COMPANION_TERMINAL_CLOSE_BODY_KEYS, COMPANION_TERMINAL_OPEN_BODY_KEYS, COMPOSER_COMMAND_INSERT_OVERRIDES, COMPOSER_COMMAND_MANIFEST, COMPOSER_COMMAND_VARIANTS, CONTEXT_LAYER_KINDS, CONTEXT_PREVIEW_HARNESSES, ChannelPermissionRequestSnapshot, ChannelReplyArtifactRef, ChannelReplyKind, ChatMessage, ClaudeChannelPermissionBehavior, CompactBoundary, ContextEditableLayerRecord, ContextHarnessPreviews, ContextLayerDraft, ContextLayerKind, ContextLayerSaveRequest, ContextLayerSaveResponse, ContextLayerTarget, ContextLayersResponse, ContextPreviewDiagnostic, ContextPreviewHarness, ContextPreviewRequest, ContextPreviewResponse, ContextProjectSummary, ContextSyncRequest, ContextSyncResponse, ContextSyncTarget, ContextUsage, ContextWorkspaceSummary, ConversationCompactingChangedEvent, ConversationCostSummary, ConversationCreatedEvent, ConversationEvent, ConversationFilter, ConversationMovedEvent, ConversationPermissionChangedEvent, ConversationPullRequests, ConversationPullRequestsChangedEvent, ConversationResponse, ConversationTitleChangedEvent, CostEventRecordedEvent, DEFAULT_MAX_MEMORY_OBSERVATIONS_PER_ISSUE, DEFAULT_MAX_TURN_DIFF_SUMMARIES_PER_AGENT, DashboardLifecycleCompletedEvent, DashboardLifecycleFailedEvent, DashboardLifecycleStartedEvent, DashboardSnapshot, DeepWipeRpc, DeployStalenessSnapshot, DerivedBranchState, DerivedIssueState, DerivedPrState, DirectoryEntry, DirectoryEntryKind, DirectoryEntryLocation, DirectoryEntrySource, DirectoryEntryState, DirectoryPause, DirectoryPauseBy, DirectoryScope, DirectoryTranscriptRef, DiscoveredSessionSnapshot, DomainEvent, EDITORS, EditorIdSchema, EmbedProgressEvent, EmbedProgressSnapshot, EmbedSessionsRpc, EnrichCompleteEvent, EnrichProgressEvent, EnrichProgressSnapshot, EnrichSessionsRpc, EnrichStatsSnapshot, ExtractionProviderConfig, ExtractionProviderTarget, FeatureNode, FeatureRegistryEntry, FeatureRegistryStatus, FlywheelAgent, FlywheelAgentStatus, FlywheelBugRateCriterion, FlywheelConversationSummary, FlywheelDerivedStatus, FlywheelEffort, FlywheelFreshness, FlywheelHarness, FlywheelHeadline, FlywheelHttpUrl, FlywheelInFlightRow, FlywheelJournalSummary, FlywheelLastTick, FlywheelOrchestrator, FlywheelOrderBookSummary, FlywheelOrders, FlywheelP0Criterion, FlywheelParkedItem, FlywheelPipelineItem, FlywheelPipelineStatus, FlywheelPipelineVerb, FlywheelPolicies, FlywheelRunId, FlywheelRunState, FlywheelScope, FlywheelStats, FlywheelStatsCriterionStatus, FlywheelStatsTrend, FlywheelStatsWindow, FlywheelStatus, FlywheelSubstrateBug, FlywheelSubstrateBugRow, FlywheelSubstrateBugStatus, FlywheelSubstrateSeverity, FlywheelSuggestion, FlywheelSuggestionAction, FlywheelSuggestionPriority, FlywheelSystemStatus, GetAvailableEditorsRpc, GetConversationCostByWorkspaceRpc, GetConversationCostRpc, GetConversationStatsRpc, GetDiscoveredSessionRpc, GetSessionsFeedFacetsRpc, GetSnapshotRpc, GlobalContextLayerRecord, GlobalContextLayerTarget, HOOK_INVENTORY, HealthReason, HealthState, HostHealthMetrics, HostPlatform, HygieneFinding, HygienePullRequest, HygieneReport, INITIAL_READ_MODEL_STATE, ISSUE_ATTENTIONS, ISSUE_STATES, ISSUE_STATE_PRECEDENCE, IssueAttention, IssueId, IssueState, IssueStateChangedEvent, IssueStatusChangedEvent, IssueTransitionedEvent, IssuesDeltaEvent, IssuesSnapshotEvent, IssuesUpdatedEvent, KIMI_CODE_BEHAVIOR, KNOWN_HARNESSES, LegacySystemHealthSummary, LegacyWebhookRelaySummary, LinearMcpAuthCallbackRelayedEvent, LinearMcpAuthHealthyEvent, LinearMcpAuthNotifiedEvent, LinearMcpAuthRequiredEvent, ListDiscoveredSessionsRpc, ListSessionsFeedRpc, MAX_CHANNEL_REPLY_ARTIFACT_LABEL_LENGTH, MAX_CHANNEL_REPLY_ARTIFACT_REFS, MAX_CHANNEL_REPLY_ARTIFACT_URI_LENGTH, MAX_CHANNEL_REPLY_SUMMARY_LENGTH, MEMBERSHIP_UNAVAILABLE_REASONS, MUSE_BEHAVIOR, MemoryAgentRole, MemoryHealthChangedEvent, MemoryIdentity, MemoryObservation, MemoryObservationCreatedEvent, MemoryResetMarkerCreatedEvent, MemoryRollupTriggeredEvent, MemoryStatus, MemoryStatusPhase, MemoryStatusUpdatedEvent, MemoryTokenUsage, MergeReadyEvent, ModelOrigin, ModelOriginEntry, OHMYPI_BEHAVIOR, OPENCODE_BEHAVIOR, OVERDECK_AGENT_PROTOCOL_VERSION, OVERDECK_DASHBOARD_PROTOCOL_VERSION, OpenInEditorInput, OperatorInterventionEvent, OrderBook, OrderBookIndexEntry, OrderBookItem, OrderBookLane, OrderBookPosture, OrderBookSettings, OrderBookStatus, PIPELINE_MEMBERSHIP_LOADING_CODE, PanRpcError, PanRpcGroup, PendingTurn, PipelineReviewCompletedEvent, PipelineReviewStartedEvent, PipelineTestCompletedEvent, PipelineTestStartedEvent, PipelineVerificationFailedEvent, PipelineVerificationStartedEvent, PlanItemStatusChangedEvent, PlanItemsUnblockedEvent, PlanSubitemStatusChangedEvent, PlanningFailedEvent, PlanningStartedEvent, PlanningSyncEvent, PrChecksState, PrReviewState, ProjectCiHeadObservedEvent, ProjectCiSnapshot, ProjectCiSuite, ProjectCiSuiteObservedEvent, ProjectContextLayerRecord, ProjectContextLayerTarget, ProjectDeployChangedEvent, ProjectDeployPhase, ProjectDeploySnapshot, ProjectSessionTree, ProposedPlan, PullRequestKey, PullRequestLink, PullRequestLinkListing, PullRequestLinkSource, PullRequestLinkedConversation, PullRequestSnapshot, PullRequestState, RagDecision, RagDecisionSource, ReadFileAtPathInput, ReadFileAtPathResult, ReadFileAtPathRpc, ReadWorkspaceFileInput, ReadWorkspaceFileResult, ReadWorkspaceFileRpc, ReplayEventsRpc, ResetMarker, ResetMarkerScope, ResizeTerminalRpc, ResolveFilePathExistsInput, ResolveFilePathExistsResult, ResolveFilePathExistsRpc, ResourceStats, ResourcesUpdatedEvent, RestartGateChangedEvent, RestartGateKind, RestartGateOutcome, RestartGateRequest, RestartGateSnapshot, ReviewApprovedEvent, ReviewCoordinatorDiedEvent, ReviewCoordinatorStartedEvent, ReviewReviewerCompletedEvent, ReviewReviewerStartedEvent, ReviewSpecialistTimedOutEvent, ReviewVerdictDispatchedEvent, ReviewVerdictRejectedEvent, ReviewVerdictRestoreBlockedEvent, ReviewerRoundMetadata, ReviewerRoundSummary, Role, ScanCompleteEvent, ScanConversationsRpc, ScanProgressEvent, ScanProgressSnapshot, ScanResult, ScanStartedEvent, SearchConversationsRpc, SendTerminalInputRpc, SequenceNumber, ServiceHealthSnapshot, ServiceHealthStatus, SessionNode, SessionNodePresence, SessionNodeType, SessionTreeDelta, SessionsFeedFacetsSnapshot, SessionsFeedRowSnapshot, SessionsFeedSource, ShadowInferenceUpdateEvent, ShellOpenInEditorRpc, SpecialistCompletedEvent, SpecialistFailedEvent, SpecialistLifecycle, SpecialistStartedEvent, StartAgentRpc, StartPlanningRpc, SubagentSummary, SubscribeAgentOutputRpc, SubscribeConversationMessagesRpc, SubscribeDomainEventsRpc, SubscribeIssueEventsRpc, SubscribeProjectSessionTreeRpc, SubscribeTerminalRpc, SubstrateBugFiledEvent, SweepEscalatedEvent, SweepRecommendationEvent, SweepScanEvent, SystemHealthConsumer, SystemHealthSeverityChangedEvent, SystemHealthSnapshot, SystemHeartbeatEvent, TELEMETRY_CLI_VERBS, TELEMETRY_EVENT_CATALOG, TELEMETRY_EVENT_NAMES, TELEMETRY_PROPERTY_DOMAINS, TERMINAL_BACKEND_NAMES, TerminalCloseRpc, TerminalOpenRpc, TerminalOutput, TerminalResizeRpc, TerminalWriteRpc, TestPassedEvent, ThinkingState, TickMarker, TickMarkerPhase, TurnDiffFileChange, TurnDiffSummary, WIRED_HOOK_INVENTORY, WIRED_HOOK_NAMES, WS_METHODS, WaitingReason, WaitingState, WorkCompletedEvent, WorkLogEntry, WorkspaceAbortedEvent, WorkspaceArtifactsResponse, WorkspaceContextLayerRecord, WorkspaceContextLayerTarget, WorkspaceCreatedEvent, WorkspaceDeletedEvent, WorkspaceDestroyedEvent, WorkspaceWipeStartedEvent, WriteFileAtPathInput, WriteFileAtPathResult, WriteFileAtPathRpc, applyEvent, applyEvents, applyIssueDelta, canonicalPullRequestUrl, companionTerminalKindFor, compareIssueIds, createIssueDelta, decodeFlywheelDerivedStatus, decodeFlywheelStats, deriveProjectCi, encodeFlywheelStats, getHarness, getHarnessBehavior, getMaxMemoryObservationsPerIssue, getMaxTurnDiffSummariesPerAgent, getRuntimeBehavior, isAgentRole, isAgentSessionName, isChannelReplyKind, isConfiguredPullRequestRepo, isIssueAttention, isIssueState, isTerminalBackendName, isTerminalTurnDiffSummaryStatus, normalizeChannelReplyPayload, omitTurnDiffSummariesForAgent, parsePullRequestRef, projectLegacySystemHealthSummary, repoFromRemoteUrl, resolveEffectivePullRequest, syncSnapshot, trimMemoryObservations, trimTurnDiffSummaries, withPaneLivenessAlias };
12892
13767
 
12893
13768
  //# sourceMappingURL=index.mjs.map