opencode-swarm 7.185.0 → 7.186.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +5 -1
  2. package/binaries/win32-arm64/swarm-sandbox-runner.exe +0 -0
  3. package/binaries/win32-x64/swarm-sandbox-runner.exe +0 -0
  4. package/dist/background/pr-feedback-event-queue.d.ts +3 -2
  5. package/dist/background/pr-feedback-loop-runtime.d.ts +4 -1
  6. package/dist/background/pr-feedback-loop.d.ts +2 -1
  7. package/dist/background/pr-monitor-worker.d.ts +9 -1
  8. package/dist/background/pr-review-trigger-receipt-reader.d.ts +35 -0
  9. package/dist/background/pr-subscriptions.d.ts +23 -0
  10. package/dist/cli/{auto-checkpoint-adn8bg66.js → auto-checkpoint-wd99h2bt.js} +7 -7
  11. package/dist/cli/{checkpoint-dvyx8gee.js → checkpoint-kjzwsxw2.js} +14 -14
  12. package/dist/cli/{coder-settlement-95dv9r28.js → coder-settlement-kp3ph56n.js} +10 -10
  13. package/dist/cli/{config-doctor-f2jtx8y5.js → config-doctor-28ggsms8.js} +2 -2
  14. package/dist/cli/{core-xn2epqfk.js → core-pj2fz34e.js} +3 -3
  15. package/dist/cli/{curation-policy-swnyg1jr.js → curation-policy-ytzwb080.js} +4 -4
  16. package/dist/cli/{curator-drift-qem70sry.js → curator-drift-q84jn9cc.js} +8 -8
  17. package/dist/cli/curator-llm-factory-13h02244.js +81 -0
  18. package/dist/cli/{curator-91rqz7xg.js → curator-r0jfc7xw.js} +39 -39
  19. package/dist/cli/{evidence-summary-service-n7ndpen0.js → evidence-summary-service-rsectw2t.js} +17 -17
  20. package/dist/cli/{gate-evidence-ajh95p02.js → gate-evidence-mpwhcm2s.js} +5 -5
  21. package/dist/cli/guardrail-explain-njv3pnsw.js +82 -0
  22. package/dist/cli/{guardrail-log-b23sf549.js → guardrail-log-r8zmh4rd.js} +6 -6
  23. package/dist/cli/{guardrail-reset-e6njf0hv.js → guardrail-reset-11cvwgbe.js} +39 -39
  24. package/dist/cli/{hive-promoter-8dqvfwsx.js → hive-promoter-0vg8w79a.js} +39 -39
  25. package/dist/cli/{index-2tv5zp9x.js → index-151bdyf9.js} +7 -7
  26. package/dist/cli/{index-sz755xt1.js → index-1fc5aj26.js} +1 -1
  27. package/dist/cli/{index-73vnyt4b.js → index-22f1ek6k.js} +39 -39
  28. package/dist/cli/{index-gemq38en.js → index-373880cv.js} +1 -1
  29. package/dist/cli/{index-fkzv0hj4.js → index-4dwhfbed.js} +41 -41
  30. package/dist/cli/{index-gxjy9y0t.js → index-4fd28s8v.js} +2 -2
  31. package/dist/cli/{index-4ysdy8sx.js → index-5pa0e0k3.js} +4 -4
  32. package/dist/cli/{index-62z1vsvf.js → index-62akgg9d.js} +1 -1
  33. package/dist/cli/{index-26nhk01d.js → index-6bfcsczm.js} +1 -1
  34. package/dist/cli/{index-s0c1wxtt.js → index-6ndc8cmn.js} +1 -1
  35. package/dist/cli/{index-h5f5q60s.js → index-6sffjy74.js} +1 -1
  36. package/dist/cli/{index-s5xmvt3k.js → index-74yxwf8y.js} +1 -1
  37. package/dist/cli/{index-cah5ffkh.js → index-7xt5m1cz.js} +5 -5
  38. package/dist/cli/{index-97nbaxye.js → index-8nsjefpc.js} +1 -1
  39. package/dist/cli/{index-1zpgtnhp.js → index-9g61bfj9.js} +1 -1
  40. package/dist/cli/{index-2e7h9yw5.js → index-9th8npp7.js} +5 -5
  41. package/dist/cli/{index-359w27b1.js → index-9y6cyc7z.js} +4 -4
  42. package/dist/cli/{index-djen6c7q.js → index-a1tpq5zr.js} +1 -1
  43. package/dist/cli/{index-rcx4kb02.js → index-a6h5arqs.js} +4 -4
  44. package/dist/cli/{index-t9jr6zc7.js → index-afmyp3kt.js} +1 -1
  45. package/dist/cli/{index-tmd5j8kh.js → index-amamkcpy.js} +4 -4
  46. package/dist/cli/{index-hx9vyvx0.js → index-bajvxmnb.js} +3 -3
  47. package/dist/cli/{index-zkm995wa.js → index-bgpq7wn2.js} +856 -619
  48. package/dist/cli/{index-v5k5jw0r.js → index-d7mcdyqb.js} +2 -2
  49. package/dist/cli/{index-qccnny3g.js → index-fp4hxcsy.js} +3 -3
  50. package/dist/cli/{index-n0wyd905.js → index-hvmfa7m8.js} +3 -3
  51. package/dist/cli/{index-qqjqpmhj.js → index-j972ags2.js} +43 -20
  52. package/dist/cli/{index-vfr3z9rv.js → index-jxd67x6z.js} +1 -1
  53. package/dist/cli/{index-fmxty2h3.js → index-kv3n7g8w.js} +2 -2
  54. package/dist/cli/{index-9am1ry6w.js → index-m94gfe82.js} +7 -7
  55. package/dist/cli/{index-7jqnckzg.js → index-nen885g8.js} +1 -1
  56. package/dist/cli/{index-e5wczpj3.js → index-nxjm66qb.js} +2 -2
  57. package/dist/cli/{index-f3grtpy3.js → index-p6bvzgp2.js} +3 -3
  58. package/dist/cli/{index-zxm9h19f.js → index-p9m1nhds.js} +3 -3
  59. package/dist/cli/{index-w7sftxdy.js → index-qyjyd3ej.js} +1 -1
  60. package/dist/cli/{index-3fnpjy4g.js → index-s68z4a39.js} +2 -2
  61. package/dist/cli/{index-m7g4dsr4.js → index-vk3ngryj.js} +5 -5
  62. package/dist/cli/{index-yg15df3b.js → index-vqz0avr4.js} +2 -2
  63. package/dist/cli/{index-rp0pyywc.js → index-w2b8qq6d.js} +7 -7
  64. package/dist/cli/{index-6wy9m25t.js → index-wkv1qdb0.js} +18 -20
  65. package/dist/cli/{index-erv39311.js → index-wmazt588.js} +2 -2
  66. package/dist/cli/{index-p544ppcp.js → index-xgdypzch.js} +1 -1
  67. package/dist/cli/{index-580t912d.js → index-yj7etak0.js} +1 -1
  68. package/dist/cli/{index-zyz0xp2b.js → index-zxck9sr7.js} +1 -1
  69. package/dist/cli/index.js +40 -40
  70. package/dist/cli/{knowledge-escalator-xdz6vg62.js → knowledge-escalator-7xcd0zea.js} +11 -11
  71. package/dist/cli/{knowledge-events-dnca00ye.js → knowledge-events-e4ts8y2v.js} +9 -9
  72. package/dist/cli/{knowledge-link-y653vvr8.js → knowledge-link-dv78fb9g.js} +3 -3
  73. package/dist/cli/{knowledge-store-yc20na25.js → knowledge-store-mmeqmjwj.js} +4 -4
  74. package/dist/cli/{knowledge-validator-c2kfrqdy.js → knowledge-validator-w2ttgxyj.js} +6 -6
  75. package/dist/cli/{mcp-mefjep3p.js → mcp-5dmm4fk2.js} +1 -1
  76. package/dist/cli/{model-preflight-5xcxc75n.js → model-preflight-kap3zp3g.js} +39 -39
  77. package/dist/cli/{pending-delegations-emhmdkn4.js → pending-delegations-q3sj608s.js} +10 -10
  78. package/dist/cli/{pr-subscriptions-amc1z05d.js → pr-subscriptions-qw4wjv66.js} +12 -10
  79. package/dist/cli/{pr-workflow-gate-gpq41zx9.js → pr-workflow-gate-tdj50p2g.js} +39 -39
  80. package/dist/cli/{runner-ss88pbb2.js → runner-tb3eppeg.js} +4 -4
  81. package/dist/cli/{scan-cursor-71gq82ez.js → scan-cursor-fgecb928.js} +5 -5
  82. package/dist/cli/{schema-108trhk6.js → schema-zrcgm9d9.js} +1 -1
  83. package/dist/cli/{scope-persistence-9gfgvy3p.js → scope-persistence-08xd3kyb.js} +13 -13
  84. package/dist/cli/{server-pkk6y7fa.js → server-kng2nggc.js} +39 -39
  85. package/dist/cli/{skill-generator-7g6xjwhr.js → skill-generator-dztn1ctf.js} +13 -13
  86. package/dist/cli/{snapshot-coordination-init-pactfmsy.js → snapshot-coordination-init-5q0hac3d.js} +39 -39
  87. package/dist/cli/{speckit-checkoff-xyp4c36r.js → speckit-checkoff-hhsy83m9.js} +4 -4
  88. package/dist/cli/{workspace-snapshot-0hffyjhd.js → workspace-snapshot-kcfkk3a2.js} +3 -3
  89. package/dist/cli/{worktree-collision-ownership-g26m4c10.js → worktree-collision-ownership-e2cqcmnw.js} +11 -11
  90. package/dist/cli/{worktree-isolation-52529c62.js → worktree-isolation-refd2n16.js} +39 -39
  91. package/dist/git/pr.d.ts +73 -0
  92. package/dist/hooks/extractors.d.ts +24 -0
  93. package/dist/hooks/pr-workflow-gate.d.ts +2 -0
  94. package/dist/index.js +52 -48
  95. package/dist/pr-review/completion.d.ts +14 -1
  96. package/dist/pr-review/types.d.ts +8 -1
  97. package/dist/tools/write-pr-review-trigger-eval.d.ts +2 -0
  98. package/package.json +1 -1
  99. package/dist/cli/curator-llm-factory-tr6rabws.js +0 -81
  100. package/dist/cli/guardrail-explain-cne2701m.js +0 -82
@@ -8,13 +8,13 @@ import {
8
8
  protectedRoots,
9
9
  redactDecisionLineForArchive,
10
10
  stableCanonicalStringify
11
- } from "./index-gxjy9y0t.js";
11
+ } from "./index-4fd28s8v.js";
12
12
  import {
13
13
  detectStraySwarmDirs,
14
14
  readDoctorArtifact,
15
15
  removeStraySwarmDir,
16
16
  runConfigDoctor
17
- } from "./index-vfr3z9rv.js";
17
+ } from "./index-jxd67x6z.js";
18
18
  import {
19
19
  archiveEvidence,
20
20
  checkRequirementCoverage,
@@ -26,7 +26,7 @@ import {
26
26
  sanitizeTaskId,
27
27
  saveEvidence,
28
28
  validateProjectRoot
29
- } from "./index-tmd5j8kh.js";
29
+ } from "./index-amamkcpy.js";
30
30
  import {
31
31
  LANGUAGE_REGISTRY,
32
32
  _internals as _internals3,
@@ -44,7 +44,7 @@ import {
44
44
  runEvaluation,
45
45
  runExternalTool,
46
46
  withDisposableWorktree
47
- } from "./index-sz755xt1.js";
47
+ } from "./index-1fc5aj26.js";
48
48
  import {
49
49
  EvaluationTaskV1Schema,
50
50
  GateAuditManifestV1Schema,
@@ -61,7 +61,7 @@ import {
61
61
  saveGateAuditResult,
62
62
  savePromotionDecision,
63
63
  saveTaskSetSnapshot
64
- } from "./index-62z1vsvf.js";
64
+ } from "./index-62akgg9d.js";
65
65
  import {
66
66
  canonicalHash,
67
67
  canonicalJson,
@@ -77,7 +77,7 @@ import {
77
77
  alreadyCuratedThisGeneration,
78
78
  claimNextScanBatch,
79
79
  resolveCohortId
80
- } from "./index-erv39311.js";
80
+ } from "./index-wmazt588.js";
81
81
  import {
82
82
  CURATOR_CONSOLIDATION_PROMPT,
83
83
  CURATOR_INIT_PROMPT,
@@ -96,13 +96,13 @@ import {
96
96
  getGroupCommitWriter,
97
97
  importLegacyJsonl,
98
98
  readPriorDriftReports
99
- } from "./index-n0wyd905.js";
99
+ } from "./index-hvmfa7m8.js";
100
100
  import {
101
101
  assertNoUnsettledCoderDispatch,
102
102
  listCoderSettlementWalStates,
103
103
  recoverCoderSettlement,
104
104
  recoverStaleCoderSettlements
105
- } from "./index-2tv5zp9x.js";
105
+ } from "./index-151bdyf9.js";
106
106
  import {
107
107
  BUNDLED_PROJECT_SKILL_ROOT,
108
108
  DEFAULT_SKILL_MIN_CONFIDENCE,
@@ -123,11 +123,11 @@ import {
123
123
  retireSkill,
124
124
  selectCandidateEntries,
125
125
  syncBundledProjectSkillsIfMissingAsync
126
- } from "./index-359w27b1.js";
126
+ } from "./index-9y6cyc7z.js";
127
127
  import {
128
128
  buildEscalationBriefing,
129
129
  readRecentEscalations
130
- } from "./index-cah5ffkh.js";
130
+ } from "./index-7xt5m1cz.js";
131
131
  import {
132
132
  parsePorcelainV2Snapshot,
133
133
  resolveCommitCountSince,
@@ -155,7 +155,7 @@ import {
155
155
  resolveRemoteUrlIdentity,
156
156
  resolveRemoteUrlIdentityAsync,
157
157
  switchPrFeedbackTrackingCandidateAsync
158
- } from "./index-3fnpjy4g.js";
158
+ } from "./index-s68z4a39.js";
159
159
  import {
160
160
  buildCorrelationId,
161
161
  buildIssueUrl,
@@ -163,8 +163,8 @@ import {
163
163
  canonicalForgePrUrl,
164
164
  containsControlCharacters,
165
165
  detectForgeFromUrl,
166
+ findSubscriptionRecordForPrUrl,
166
167
  getPrSubscriptionHealth,
167
- getProviderCapabilities,
168
168
  hasNonAsciiHostname,
169
169
  isPrSubscriptionCapacityError,
170
170
  isPrivateHost,
@@ -176,12 +176,12 @@ import {
176
176
  sweepStale,
177
177
  unsubscribe,
178
178
  updateSnapshot
179
- } from "./index-qqjqpmhj.js";
179
+ } from "./index-j972ags2.js";
180
180
  import {
181
181
  WORKTREE_LIFECYCLE_LOCK_FILE,
182
182
  recordWorktreeProvisioningOwner,
183
183
  removeWorktreeProvisioningOwner
184
- } from "./index-yg15df3b.js";
184
+ } from "./index-vqz0avr4.js";
185
185
  import {
186
186
  getLanguageForExtension
187
187
  } from "./index-pt7h91zc.js";
@@ -194,7 +194,7 @@ import {
194
194
  checkpoint,
195
195
  createSwarmTool,
196
196
  resolveWorkingDirectory
197
- } from "./index-rcx4kb02.js";
197
+ } from "./index-a6h5arqs.js";
198
198
  import {
199
199
  MAX_TRANSIENT_RETRIES,
200
200
  PlanRecoverySupersededError,
@@ -222,7 +222,7 @@ import {
222
222
  transientBackoff,
223
223
  updateTaskStatus,
224
224
  withPlanLifecycleLock
225
- } from "./index-6wy9m25t.js";
225
+ } from "./index-wkv1qdb0.js";
226
226
  import {
227
227
  containsControlChars,
228
228
  containsPathTraversal,
@@ -238,7 +238,7 @@ import {
238
238
  resolveSpeckitProjection,
239
239
  validateSpeckit,
240
240
  writeProjectedSpecSync
241
- } from "./index-s0c1wxtt.js";
241
+ } from "./index-6ndc8cmn.js";
242
242
  import {
243
243
  clearWorktreeMergeStatus,
244
244
  getAllWorktreeMergeFailures,
@@ -269,7 +269,7 @@ import {
269
269
  transitionTaskWorkflowEvidenceWithStatus,
270
270
  withTaskEvidenceTransaction,
271
271
  writeWorkflowWalFile
272
- } from "./index-qccnny3g.js";
272
+ } from "./index-fp4hxcsy.js";
273
273
  import {
274
274
  isPathUnderSwarmWorktreeBase,
275
275
  listLiveLaneOwners,
@@ -278,7 +278,7 @@ import {
278
278
  recordLiveLaneOwner,
279
279
  removeWorktree,
280
280
  resolveWorktreeBaseDir
281
- } from "./index-zxm9h19f.js";
281
+ } from "./index-p9m1nhds.js";
282
282
  import {
283
283
  DEFAULT_STALE_DELEGATION_TIMEOUT_MS,
284
284
  DELEGATION_COMPACTION_HIGH_WATER_BYTES,
@@ -312,7 +312,7 @@ import {
312
312
  scanBackgroundCoderReservationsForAdmission,
313
313
  scanDelegationsForRecovery,
314
314
  sweepStaleDelegations
315
- } from "./index-2e7h9yw5.js";
315
+ } from "./index-9th8npp7.js";
316
316
  import {
317
317
  MAX_EVENT_LOG_ENTRIES,
318
318
  _internals,
@@ -331,7 +331,7 @@ import {
331
331
  recordKnowledgeEvent,
332
332
  recordPhaseCloseIntent,
333
333
  resolveKnowledgeEventsPath
334
- } from "./index-rp0pyywc.js";
334
+ } from "./index-w2b8qq6d.js";
335
335
  import {
336
336
  estimateCharsForTokens,
337
337
  estimateTokens,
@@ -339,7 +339,7 @@ import {
339
339
  readSwarmFileAsync,
340
340
  safeHook,
341
341
  validateSwarmPath
342
- } from "./index-t9jr6zc7.js";
342
+ } from "./index-afmyp3kt.js";
343
343
  import {
344
344
  bunFile,
345
345
  bunSpawn,
@@ -359,18 +359,18 @@ import {
359
359
  validateActionableFields,
360
360
  validateLesson,
361
361
  validateSkillPath
362
- } from "./index-4ysdy8sx.js";
362
+ } from "./index-5pa0e0k3.js";
363
363
  import {
364
364
  MAX_CURATION_PROPOSALS,
365
365
  authorizeCuration,
366
366
  buildConfigFingerprintInput
367
- } from "./index-97nbaxye.js";
367
+ } from "./index-8nsjefpc.js";
368
368
  import {
369
369
  cohortConfigFingerprint
370
370
  } from "./index-rtry5xyf.js";
371
371
  import {
372
372
  resolveWorktreeIsolationConfig
373
- } from "./index-v5k5jw0r.js";
373
+ } from "./index-d7mcdyqb.js";
374
374
  import {
375
375
  RetrospectiveEvidenceSchema
376
376
  } from "./index-frcemc0b.js";
@@ -382,7 +382,7 @@ import {
382
382
  clearScopeBindings,
383
383
  readAuthoritativeScopeBindingSet,
384
384
  readDeclaredScopeFilesFromBindings
385
- } from "./index-m7g4dsr4.js";
385
+ } from "./index-vk3ngryj.js";
386
386
  import {
387
387
  clearPlanLedgerForReset,
388
388
  computePlanStructureHash,
@@ -398,7 +398,7 @@ import {
398
398
  replayFromLedgerWithStatus,
399
399
  resolvePlanningProfile,
400
400
  takeSnapshotEvent
401
- } from "./index-hx9vyvx0.js";
401
+ } from "./index-bajvxmnb.js";
402
402
  import {
403
403
  CORE_EVENT_LOCKED,
404
404
  appendCoreEventSync,
@@ -408,7 +408,7 @@ import {
408
408
  hasSpecDriftAuditEvent,
409
409
  hasTaskRepairAuditEvent,
410
410
  readCoreEvents
411
- } from "./index-gemq38en.js";
411
+ } from "./index-373880cv.js";
412
412
  import {
413
413
  DEFAULT_QA_GATES,
414
414
  computeProfileHash,
@@ -416,7 +416,7 @@ import {
416
416
  getEffectiveGates,
417
417
  getProfileLookupForIdentity,
418
418
  setGatesForIdentity
419
- } from "./index-1zpgtnhp.js";
419
+ } from "./index-9g61bfj9.js";
420
420
  import {
421
421
  MAX_COORDINATION_STATE_LIST_ROWS,
422
422
  deleteCoordinationImports,
@@ -427,7 +427,7 @@ import {
427
427
  listCoordinationStates,
428
428
  transitionCoordinationState,
429
429
  withCoordinationTransaction
430
- } from "./index-7jqnckzg.js";
430
+ } from "./index-nen885g8.js";
431
431
  import {
432
432
  DURABILITY_CLASSES,
433
433
  closeAllProjectDbs,
@@ -436,7 +436,7 @@ import {
436
436
  projectDbExists,
437
437
  projectDbPath,
438
438
  withImmediateTransaction
439
- } from "./index-s5xmvt3k.js";
439
+ } from "./index-74yxwf8y.js";
440
440
  import {
441
441
  canonicalExistingFilesystemPath,
442
442
  canonicalPathForFutureIo,
@@ -456,7 +456,7 @@ import {
456
456
  observeModelLimitResolution,
457
457
  observeStoreHealth,
458
458
  readLearningHealth
459
- } from "./index-p544ppcp.js";
459
+ } from "./index-xgdypzch.js";
460
460
  import {
461
461
  appendKnowledge,
462
462
  appendRejectedLesson,
@@ -487,7 +487,7 @@ import {
487
487
  transactFile,
488
488
  transactKnowledge,
489
489
  wordBigrams
490
- } from "./index-9am1ry6w.js";
490
+ } from "./index-m94gfe82.js";
491
491
  import {
492
492
  readTailJsonl,
493
493
  readTailJsonlDetailed,
@@ -508,10 +508,10 @@ import {
508
508
  resolveLinkDir,
509
509
  sanitizeLinkId,
510
510
  writeLinkPointer
511
- } from "./index-zyz0xp2b.js";
511
+ } from "./index-zxck9sr7.js";
512
512
  import {
513
513
  atomicWriteFile
514
- } from "./index-h5f5q60s.js";
514
+ } from "./index-6sffjy74.js";
515
515
  import {
516
516
  withEvidenceLock
517
517
  } from "./index-6cjpmvpa.js";
@@ -554,7 +554,7 @@ import {
554
554
  matchTempGrammar,
555
555
  parseTargetBasename,
556
556
  resetSwarmArtifactCache
557
- } from "./index-580t912d.js";
557
+ } from "./index-yj7etak0.js";
558
558
  import {
559
559
  PlanSchema,
560
560
  TaskStatusSchema,
@@ -568,7 +568,7 @@ import {
568
568
  loadGateOverrides,
569
569
  loadPluginConfig,
570
570
  loadPluginConfigWithMeta
571
- } from "./index-djen6c7q.js";
571
+ } from "./index-a1tpq5zr.js";
572
572
  import {
573
573
  addDeferredWarning,
574
574
  advisoryWarn,
@@ -600,7 +600,7 @@ import {
600
600
  resolveContextWindow,
601
601
  resolveGeneratedAgentRole,
602
602
  stripKnownSwarmPrefix
603
- } from "./index-w7sftxdy.js";
603
+ } from "./index-qyjyd3ej.js";
604
604
  import {
605
605
  AGENT_TOOL_MAP,
606
606
  ALL_AGENT_NAMES,
@@ -770,7 +770,6 @@ init_loader();
770
770
  // src/hooks/pr-workflow-gate.ts
771
771
  init_zod();
772
772
  import { createHash as createHash23, randomUUID as randomUUID6 } from "crypto";
773
- import { readFileSync as readFileSync14, statSync as statSync10 } from "fs";
774
773
  import * as fsp5 from "fs/promises";
775
774
  import * as path28 from "path";
776
775
 
@@ -2586,6 +2585,33 @@ function parsePrReviewTriggerReceipt(input) {
2586
2585
  return parsedReceipt(schemaVersion === 1 ? 1 : 0, validated.rows);
2587
2586
  }
2588
2587
 
2588
+ // src/background/pr-review-trigger-receipt-reader.ts
2589
+ import { readFileSync as readFileSync2, statSync } from "fs";
2590
+ function readPrReviewTriggerReceiptForGate(directory, triggerEvalPath) {
2591
+ if (!triggerEvalPath)
2592
+ return { noReceipt: true };
2593
+ const triggerPath = validateSwarmPath(directory, triggerEvalPath);
2594
+ let triggerArtifact;
2595
+ try {
2596
+ const triggerStat = statSync(triggerPath);
2597
+ if (!triggerStat.isFile() || triggerStat.size > PR_REVIEW_TRIGGER_RECEIPT_MAX_BYTES) {
2598
+ throw new Error("trigger evaluation artifact exceeds its read bound");
2599
+ }
2600
+ triggerArtifact = JSON.parse(readFileSync2(triggerPath, "utf-8"));
2601
+ } catch {
2602
+ throw new Error("BLOCKED: PR_REVIEW trigger evaluation artifact is missing or invalid");
2603
+ }
2604
+ try {
2605
+ return { receipt: parsePrReviewTriggerReceipt(triggerArtifact) };
2606
+ } catch (error2) {
2607
+ throw new Error(`BLOCKED: PR_REVIEW trigger evaluation is invalid: ${error2 instanceof Error ? error2.message : String(error2)}`);
2608
+ }
2609
+ }
2610
+ function prReviewReceiptHasCoverageDegradations(directory, triggerEvalPath) {
2611
+ const read = readPrReviewTriggerReceiptForGate(directory, triggerEvalPath);
2612
+ return "noReceipt" in read ? false : read.receipt.coverageDegradations.length > 0;
2613
+ }
2614
+
2589
2615
  // src/hooks/pr-workflow-gate.ts
2590
2616
  init_constants();
2591
2617
  init_schema();
@@ -3363,7 +3389,7 @@ async function importLegacyPrWorkflowGateStateIfNeeded(directory, sessionID, all
3363
3389
  return null;
3364
3390
  throw error2;
3365
3391
  }
3366
- const legacy = allowSalvagedImport ? (await (await import("./pr-workflow-gate-gpq41zx9.js")).readPrWorkflowGateStateForRecovery(directory, sessionID))?.state ?? null : await readPrWorkflowGateStateFileFromDisk(filePath, sessionID);
3392
+ const legacy = allowSalvagedImport ? (await (await import("./pr-workflow-gate-tdj50p2g.js")).readPrWorkflowGateStateForRecovery(directory, sessionID))?.state ?? null : await readPrWorkflowGateStateFileFromDisk(filePath, sessionID);
3367
3393
  if (!legacy)
3368
3394
  return null;
3369
3395
  const namespace = workflowGateStateCoordinationNamespace(sessionID);
@@ -3450,7 +3476,7 @@ async function deleteStateWhileLocked(directory, sessionID, options = {}) {
3450
3476
  let recoveryState = null;
3451
3477
  if (!currentAuthoritative) {
3452
3478
  if (options.allowSalvagedRead) {
3453
- const { readPrWorkflowGateStateForRecovery } = await import("./pr-workflow-gate-gpq41zx9.js");
3479
+ const { readPrWorkflowGateStateForRecovery } = await import("./pr-workflow-gate-tdj50p2g.js");
3454
3480
  recoveryState = (await readPrWorkflowGateStateForRecovery(directory, normalizedSessionID))?.state ?? null;
3455
3481
  }
3456
3482
  if (!recoveryState) {
@@ -4494,7 +4520,7 @@ function rollbackPrReviewCircuitProbe(circuit, nowMs, openDurationMs) {
4494
4520
  // src/pr-review/completion.ts
4495
4521
  init_zod();
4496
4522
  import { createHash as createHash8 } from "crypto";
4497
- import { readFileSync as readFileSync2 } from "fs";
4523
+ import { readFileSync as readFileSync3 } from "fs";
4498
4524
  import * as fsp4 from "fs/promises";
4499
4525
  import * as path6 from "path";
4500
4526
 
@@ -4697,14 +4723,20 @@ var PR_REVIEW_REPORT_VERDICTS = [
4697
4723
  "REQUEST_CHANGES",
4698
4724
  "INCOMPLETE"
4699
4725
  ];
4700
- function allowedPrReviewReportVerdicts(kind, findings = []) {
4726
+ function allowedPrReviewReportVerdicts(kind, findings = [], options) {
4701
4727
  if (kind === "PARTIAL" && findings.length === 0) {
4702
4728
  return ["REQUEST_CHANGES", "INCOMPLETE"];
4703
4729
  }
4730
+ const degraded = kind === "COMPLETE" && options?.disclosedCoverageDegradation === true;
4704
4731
  const projection = evaluateFinalFindingPolicy({
4705
4732
  policyVersion: 1,
4706
4733
  finalStatus: "COMPLETE",
4707
- coverage: kind === "COMPLETE" ? { kind: "base", quality: "complete", provenance: "valid" } : kind === "PARTIAL" ? { kind: "base", quality: "partial", provenance: "valid" } : { kind: "base", quality: "none", provenance: "valid" },
4734
+ coverage: degraded ? {
4735
+ kind: "base",
4736
+ quality: "degraded",
4737
+ disclosed: true,
4738
+ provenance: "valid"
4739
+ } : kind === "COMPLETE" ? { kind: "base", quality: "complete", provenance: "valid" } : kind === "PARTIAL" ? { kind: "base", quality: "partial", provenance: "valid" } : { kind: "base", quality: "none", provenance: "valid" },
4708
4740
  findings: [...findings]
4709
4741
  });
4710
4742
  const supported = projection.permittedVerdicts.filter((value) => (value === "APPROVE" || value === "REQUEST_CHANGES" || value === "INCOMPLETE") && (kind === "COMPLETE" || value !== "APPROVE"));
@@ -5219,7 +5251,7 @@ async function admitPrReviewPartialBaseCoverage(directory, sessionID, runId, unr
5219
5251
  } catch {}
5220
5252
  };
5221
5253
  try {
5222
- const persisted = readFileSync2(absolutePath, "utf8");
5254
+ const persisted = readFileSync3(absolutePath, "utf8");
5223
5255
  if (persisted !== raw) {
5224
5256
  throw new Error("BLOCKED: partial base coverage disclosure path already contains different content");
5225
5257
  }
@@ -5323,7 +5355,9 @@ async function readPrReviewTerminalCoverageForReport(directory, sessionID) {
5323
5355
  failure_class: entry.failureClass
5324
5356
  })),
5325
5357
  liveDimensions: settlement.liveDimensions,
5326
- allowedVerdicts: allowedPrReviewReportVerdicts(settlement.kind, [])
5358
+ allowedVerdicts: allowedPrReviewReportVerdicts(settlement.kind, [], {
5359
+ disclosedCoverageDegradation: prReviewReceiptHasCoverageDegradations(directory, state.prReviewTriggerEvalPath)
5360
+ })
5327
5361
  };
5328
5362
  }
5329
5363
 
@@ -5892,6 +5926,9 @@ function reducePrReviewEvent(state, event) {
5892
5926
  if (settlement.kind === "NO_COVERAGE" && verdict !== "INCOMPLETE") {
5893
5927
  return rejected(state, "no_coverage_requires_incomplete", `a zero-coverage review must report INCOMPLETE, not ${verdict}`);
5894
5928
  }
5929
+ if (settlement.kind === "COMPLETE" && event.disclosedDegradation === true && verdict === "APPROVE") {
5930
+ return rejected(state, "degraded_disclosure_cannot_approve", "a disclosed coverage degradation (dead family) can never emit APPROVE; report REQUEST_CHANGES with the disclosed degradation or INCOMPLETE");
5931
+ }
5895
5932
  }
5896
5933
  return applied(state);
5897
5934
  }
@@ -15002,7 +15039,7 @@ function isLaneOwnedByCurrentSession(branchName, expectedSessionId) {
15002
15039
  return extracted === expectedSessionId;
15003
15040
  }
15004
15041
  async function inspectStandardWorktreeCollisionOwnership(identity) {
15005
- const collisionOwnership = await import("./worktree-collision-ownership-g26m4c10.js");
15042
+ const collisionOwnership = await import("./worktree-collision-ownership-e2cqcmnw.js");
15006
15043
  return collisionOwnership.inspectStandardWorktreeCollisionOwnership(identity);
15007
15044
  }
15008
15045
  async function runRecoveryGit(directory, args, timeoutMs = 15000) {
@@ -15428,7 +15465,7 @@ async function precreateStandardWorktreeSession(args) {
15428
15465
  const laneProfile = computeLaneRuntimeProfile(worktreeConfig.runtime_isolation, laneIndex, handle.worktreePath);
15429
15466
  if (laneProfile) {
15430
15467
  try {
15431
- const { writeLaneProfileToDiskReal } = await import("./core-xn2epqfk.js");
15468
+ const { writeLaneProfileToDiskReal } = await import("./core-pj2fz34e.js");
15432
15469
  await writeLaneProfileToDiskReal(handle.worktreePath, laneProfile.laneIndex, laneProfile.envOverrides);
15433
15470
  } catch {}
15434
15471
  }
@@ -16407,7 +16444,7 @@ async function finishStandardWorktreeDispatch(directory, dispatch, config, callI
16407
16444
  }
16408
16445
  clearWorktreeMergeStatus(statusKey);
16409
16446
  try {
16410
- const { removeLaneProfileFromDiskReal } = await import("./core-xn2epqfk.js");
16447
+ const { removeLaneProfileFromDiskReal } = await import("./core-pj2fz34e.js");
16411
16448
  await removeLaneProfileFromDiskReal(dispatch.handle.worktreePath, dispatch.laneIndex);
16412
16449
  } catch {}
16413
16450
  const state = serializationStateBySessionID.get(dispatch.parentSessionID);
@@ -16676,6 +16713,7 @@ function extractCurrentPhase(planContent) {
16676
16713
  if (!planContent) {
16677
16714
  return null;
16678
16715
  }
16716
+ planContent = sanitizeContextText(planContent);
16679
16717
  const lines = planContent.split(`
16680
16718
  `);
16681
16719
  for (let i = 0;i < Math.min(20, lines.length); i++) {
@@ -16687,6 +16725,15 @@ function extractCurrentPhase(planContent) {
16687
16725
  return `Phase ${phaseNum}: ${description} [IN PROGRESS]`;
16688
16726
  }
16689
16727
  }
16728
+ for (let i = 0;i < Math.min(20, lines.length); i++) {
16729
+ const line = lines[i].trim();
16730
+ const blockedMatch = line.match(/^## Phase (\d+):?\s*(.*?)\s*\[BLOCKED\]/i);
16731
+ if (blockedMatch) {
16732
+ const phaseNum = blockedMatch[1];
16733
+ const description = blockedMatch[2]?.trim() || "";
16734
+ return `Phase ${phaseNum}: ${description} [BLOCKED]`;
16735
+ }
16736
+ }
16690
16737
  for (let i = 0;i < Math.min(3, lines.length); i++) {
16691
16738
  const line = lines[i].trim();
16692
16739
  const phaseMatch = line.match(/Phase:\s*(\d+)/i);
@@ -16709,7 +16756,7 @@ function extractCurrentPhaseFromPlan(plan) {
16709
16756
  blocked: "BLOCKED"
16710
16757
  };
16711
16758
  const statusText = statusMap[phase.status] || "PENDING";
16712
- return `Phase ${phase.id}: ${phase.name} [${statusText}]`;
16759
+ return sanitizeContextText(`Phase ${phase.id}: ${phase.name} [${statusText}]`);
16713
16760
  }
16714
16761
 
16715
16762
  // src/hooks/task-result-classifier.ts
@@ -19047,7 +19094,7 @@ ${text}`;
19047
19094
 
19048
19095
  // src/db/observability-event-store.ts
19049
19096
  import { createHash as createHash21 } from "crypto";
19050
- import { existsSync as existsSync11, readFileSync as readFileSync11, statSync as statSync7 } from "fs";
19097
+ import { existsSync as existsSync11, readFileSync as readFileSync12, statSync as statSync8 } from "fs";
19051
19098
  import { join as join20 } from "path";
19052
19099
  var MAX_OBSERVABILITY_EVENT_ROWS = 50000;
19053
19100
  var MAX_EVENT_PAYLOAD_BYTES = 16 * 1024;
@@ -19263,7 +19310,7 @@ function syncObservabilityImport(directory) {
19263
19310
  const filePath = join20(root, ".swarm", fileName);
19264
19311
  let stats;
19265
19312
  try {
19266
- const st = statSync7(filePath);
19313
+ const st = statSync8(filePath);
19267
19314
  stats = { size: st.size, mtimeMs: st.mtimeMs };
19268
19315
  } catch {
19269
19316
  continue;
@@ -19276,7 +19323,7 @@ function syncObservabilityImport(directory) {
19276
19323
  result.skippedUnchanged = false;
19277
19324
  let content;
19278
19325
  try {
19279
- content = readFileSync11(filePath, "utf-8");
19326
+ content = readFileSync12(filePath, "utf-8");
19280
19327
  } catch {
19281
19328
  continue;
19282
19329
  }
@@ -19426,9 +19473,9 @@ var _internals28 = {
19426
19473
  import {
19427
19474
  existsSync as existsSync12,
19428
19475
  mkdirSync as mkdirSync6,
19429
- readFileSync as readFileSync12,
19476
+ readFileSync as readFileSync13,
19430
19477
  renameSync as renameSync4,
19431
- statSync as statSync8,
19478
+ statSync as statSync9,
19432
19479
  writeFileSync as writeFileSync6
19433
19480
  } from "fs";
19434
19481
  import { join as join21 } from "path";
@@ -19449,7 +19496,7 @@ function statePath(directory) {
19449
19496
  }
19450
19497
  function loadState(directory) {
19451
19498
  try {
19452
- const raw = readFileSync12(statePath(directory), "utf-8");
19499
+ const raw = readFileSync13(statePath(directory), "utf-8");
19453
19500
  const parsed = JSON.parse(raw);
19454
19501
  if (parsed.v !== STATE_VERSION)
19455
19502
  return null;
@@ -19460,7 +19507,7 @@ function loadState(directory) {
19460
19507
  }
19461
19508
  function readSpoolLines(directory) {
19462
19509
  try {
19463
- const content = readFileSync12(spoolPath(directory), "utf-8");
19510
+ const content = readFileSync13(spoolPath(directory), "utf-8");
19464
19511
  return content.split(`
19465
19512
  `).filter((l) => l.length > 0);
19466
19513
  } catch {
@@ -19480,7 +19527,7 @@ function readOtlpExporterHealth(directory) {
19480
19527
  let spoolRecords = 0;
19481
19528
  let spoolBytes = 0;
19482
19529
  try {
19483
- const st = statSync8(spoolPath(directory));
19530
+ const st = statSync9(spoolPath(directory));
19484
19531
  spoolBytes = st.size;
19485
19532
  spoolRecords = readSpoolLines(directory).length;
19486
19533
  } catch {}
@@ -22436,7 +22483,7 @@ function clearHydrationOwnershipState() {
22436
22483
  }
22437
22484
 
22438
22485
  // src/session/session-start-store.ts
22439
- import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "fs";
22486
+ import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync8 } from "fs";
22440
22487
  import * as path26 from "path";
22441
22488
  var SESSION_START_FILE = "session-start.jsonl";
22442
22489
  function recordSessionStart(directory, startMs) {
@@ -22455,7 +22502,7 @@ function readEarliestSessionStart(directory) {
22455
22502
  const filePath = path26.join(directory, ".swarm", "session", SESSION_START_FILE);
22456
22503
  if (!existsSync14(filePath))
22457
22504
  return null;
22458
- const content = readFileSync13(filePath, "utf-8");
22505
+ const content = readFileSync14(filePath, "utf-8");
22459
22506
  const lines = content.split(`
22460
22507
  `);
22461
22508
  const validStartMs = [];
@@ -24036,7 +24083,7 @@ function clearCriticalShownIds(sessionID) {
24036
24083
  async function rehydratePrSubscriptions(sessionID, directory) {
24037
24084
  const map = new Map;
24038
24085
  try {
24039
- const { listActive: listActive2 } = await import("./pr-subscriptions-amc1z05d.js");
24086
+ const { listActive: listActive2 } = await import("./pr-subscriptions-qw4wjv66.js");
24040
24087
  const records = await listActive2(directory);
24041
24088
  for (const record of records) {
24042
24089
  if (record.sessionID !== sessionID)
@@ -24521,11 +24568,11 @@ async function activatePrWorkflow(directory, sessionID, mode, options = {}) {
24521
24568
  let existing = await readPrWorkflowGateStateFromDisk3(directory, normalizedSessionID);
24522
24569
  if (existing?.mode === mode) {
24523
24570
  if (mode === "PR_FEEDBACK" && options.prUrl) {
24524
- const requestedTarget = canonicalGitHubPrUrl(options.prUrl);
24571
+ const requestedTarget = canonicalGitHubPrUrl(options.prUrl, options.forge);
24525
24572
  if (!requestedTarget) {
24526
24573
  throw new Error("BLOCKED: PR_FEEDBACK target must be a canonical GitHub PR URL");
24527
24574
  }
24528
- const existingTarget = existing.prFeedbackTargetUrl ? canonicalGitHubPrUrl(existing.prFeedbackTargetUrl) : null;
24575
+ const existingTarget = existing.prFeedbackTargetUrl ? canonicalGitHubPrUrl(existing.prFeedbackTargetUrl, options.forge) : null;
24529
24576
  if (existingTarget && requestedTarget !== existingTarget) {
24530
24577
  throw new Error(`BLOCKED: active PR_FEEDBACK targets a different GitHub pull request`);
24531
24578
  }
@@ -24559,7 +24606,7 @@ async function activatePrWorkflow(directory, sessionID, mode, options = {}) {
24559
24606
  const initialHead = options.prHeadSha ? await assertCurrentCheckoutHead(directory, options.prHeadSha, mode) : undefined;
24560
24607
  const skillContractAdvisories = await ensurePrWorkflowSkillContractsFresh(directory, mode);
24561
24608
  const timestamp = isoNow();
24562
- const feedbackTargetUrl = mode === "PR_FEEDBACK" && options.prUrl ? canonicalGitHubPrUrl(options.prUrl) ? options.prUrl : null : undefined;
24609
+ const feedbackTargetUrl = mode === "PR_FEEDBACK" && options.prUrl ? canonicalGitHubPrUrl(options.prUrl, options.forge) ? options.prUrl : null : undefined;
24563
24610
  if (feedbackTargetUrl === null) {
24564
24611
  throw new Error("BLOCKED: PR_FEEDBACK target must be a canonical GitHub PR URL");
24565
24612
  }
@@ -29086,7 +29133,10 @@ async function readPrReviewFinalFindingPolicyForReport(directory, sessionID) {
29086
29133
  const settlement = derivePrReviewDimensionSettlement(directory, state, ctx.revisionDigest);
29087
29134
  const authority = await readAuthoritativeFindingPolicy(directory, state);
29088
29135
  const findings = authority.policyFindings;
29089
- const permittedVerdicts = allowedPrReviewReportVerdicts(settlement.kind, findings);
29136
+ const disclosedDegradation = prReviewReceiptHasCoverageDegradations(directory, state.prReviewTriggerEvalPath);
29137
+ const permittedVerdicts = allowedPrReviewReportVerdicts(settlement.kind, findings, {
29138
+ disclosedCoverageDegradation: disclosedDegradation
29139
+ });
29090
29140
  const policyProjection = evaluateFinalFindingPolicy({
29091
29141
  policyVersion: FINDING_POLICY_VERSION,
29092
29142
  finalStatus: "COMPLETE",
@@ -29100,8 +29150,8 @@ async function readPrReviewFinalFindingPolicyForReport(directory, sessionID) {
29100
29150
  const blockingFindingIds = policyProjection.blockingFindingIds.flatMap((id) => sourceIdsByPolicyFindingId.get(id) ?? [id]).sort();
29101
29151
  return { policyVersion: 1, permittedVerdicts, blockingFindingIds };
29102
29152
  }
29103
- function canonicalGitHubPrUrl(value) {
29104
- return canonicalForgePrUrl(value);
29153
+ function canonicalGitHubPrUrl(value, configured) {
29154
+ return canonicalForgePrUrl(value, configured);
29105
29155
  }
29106
29156
  function assertMatchingPrReviewFeedbackConsent(record, input) {
29107
29157
  if (record.session_id !== input.sessionID || record.run_id !== input.runId || record.handoff_path !== input.handoffPath || record.handoff_digest !== input.handoffDigest || canonicalGitHubPrUrl(record.pr_url) !== canonicalGitHubPrUrl(input.prUrl) || record.pr_head_sha.toLowerCase() !== input.prHeadSha.toLowerCase() || record.finding_ids_digest !== input.findingIdsDigest || record.source_workflow_instance_id !== input.sourceWorkflowInstanceId) {
@@ -29689,6 +29739,7 @@ async function completePrWorkflow(directory, sessionID, expectedMode, prHeadSha,
29689
29739
  }
29690
29740
  const ctx = await createPrReviewGateContext2(directory, state);
29691
29741
  const settlement = derivePrReviewDimensionSettlement(directory, state, ctx.revisionDigest);
29742
+ let disclosedDegradation = settlement.kind === "COMPLETE" && prReviewReceiptHasCoverageDegradations(directory, state.prReviewTriggerEvalPath);
29692
29743
  const dispatchCoverageFinalization = (finalizationSettlement) => {
29693
29744
  const outcome = reducePrReviewEvent(state, {
29694
29745
  type: "coverage_finalization_requested",
@@ -29698,7 +29749,8 @@ async function completePrWorkflow(directory, sessionID, expectedMode, prHeadSha,
29698
29749
  unresolvedDimensions: finalizationSettlement.unresolvedDimensions,
29699
29750
  liveDimensions: finalizationSettlement.liveDimensions
29700
29751
  },
29701
- requestedVerdict: verdict
29752
+ requestedVerdict: verdict,
29753
+ disclosedDegradation
29702
29754
  });
29703
29755
  if (outcome.status === "applied")
29704
29756
  return;
@@ -29712,7 +29764,10 @@ async function completePrWorkflow(directory, sessionID, expectedMode, prHeadSha,
29712
29764
  if (code === "no_coverage_requires_incomplete") {
29713
29765
  throw new Error(`BLOCKED: PR_REVIEW NO_COVERAGE completion must report verdict INCOMPLETE; got "${verdict}". A zero-coverage report never approves and never claims a code-quality review.`);
29714
29766
  }
29715
- const allowedList = allowedPrReviewReportVerdicts(finalizationSettlement.kind, []).join(" | ");
29767
+ if (code === "degraded_disclosure_cannot_approve") {
29768
+ throw new Error(`BLOCKED: PR_REVIEW ${finalizationSettlement.kind} completion discloses a coverage degradation (dead family) and cannot report verdict APPROVE; got "${verdict}". Report REQUEST_CHANGES with the disclosed degradation surfaced in the report, or INCOMPLETE.`);
29769
+ }
29770
+ const allowedList = allowedPrReviewReportVerdicts(finalizationSettlement.kind, [], { disclosedCoverageDegradation: disclosedDegradation }).join(" | ");
29716
29771
  throw new Error(`BLOCKED: PR_REVIEW ${finalizationSettlement.kind} completion allows report_verdict ${allowedList}; got "${verdict}". Partial coverage never approves and never claims a full review.`);
29717
29772
  };
29718
29773
  dispatchCoverageFinalization(settlement);
@@ -29734,7 +29789,9 @@ async function completePrWorkflow(directory, sessionID, expectedMode, prHeadSha,
29734
29789
  });
29735
29790
  } catch {}
29736
29791
  } else {
29737
- const preAllowed = allowedPrReviewReportVerdicts(settlement.kind, []);
29792
+ const preAllowed = allowedPrReviewReportVerdicts(settlement.kind, [], {
29793
+ disclosedCoverageDegradation: disclosedDegradation
29794
+ });
29738
29795
  if (!preAllowed.includes(verdict)) {
29739
29796
  throw new Error(`BLOCKED: PR_REVIEW ${settlement.kind} completion allows report_verdict ${preAllowed.join(" | ")}; got "${verdict}". Partial coverage never approves and never claims a full review.`);
29740
29797
  }
@@ -29743,9 +29800,12 @@ async function completePrWorkflow(directory, sessionID, expectedMode, prHeadSha,
29743
29800
  if (workflowIdentity(readyState) !== workflowIdentity(state) || readyState.revision !== state.revision) {
29744
29801
  throw new Error("BLOCKED: PR_REVIEW state changed while checking terminal readiness; retry from current state");
29745
29802
  }
29803
+ if (ready.settlement.kind === "COMPLETE") {
29804
+ disclosedDegradation = prReviewReceiptHasCoverageDegradations(directory, readyState.prReviewTriggerEvalPath);
29805
+ }
29746
29806
  dispatchCoverageFinalization(ready.settlement);
29747
29807
  const finalFindingAuthority = await readAuthoritativeFindingPolicy(directory, readyState);
29748
- const policyAllowed = allowedPrReviewReportVerdicts(ready.settlement.kind, finalFindingAuthority.policyFindings);
29808
+ const policyAllowed = allowedPrReviewReportVerdicts(ready.settlement.kind, finalFindingAuthority.policyFindings, { disclosedCoverageDegradation: disclosedDegradation });
29749
29809
  if (!policyAllowed.includes(verdict)) {
29750
29810
  throw new Error(`BLOCKED: PR_REVIEW ${ready.settlement.kind} completion allows report_verdict ${policyAllowed.join(" | ")}; got "${verdict}". Final finding policy and coverage do not permit this report.`);
29751
29811
  }
@@ -30840,23 +30900,11 @@ function derivePrReviewCandidateInventory2(directory, state, ctx) {
30840
30900
  }
30841
30901
  const degradedSourceKeys = new Set;
30842
30902
  if (state.prReviewTriggerEvalPath) {
30843
- const triggerPath = validateSwarmPath(directory, state.prReviewTriggerEvalPath);
30844
- let triggerArtifact;
30845
- try {
30846
- const triggerStat = statSync10(triggerPath);
30847
- if (!triggerStat.isFile() || triggerStat.size > PR_REVIEW_TRIGGER_RECEIPT_MAX_BYTES) {
30848
- throw new Error("trigger evaluation artifact exceeds its read bound");
30849
- }
30850
- triggerArtifact = JSON.parse(readFileSync14(triggerPath, "utf-8"));
30851
- } catch {
30903
+ const receiptRead = readPrReviewTriggerReceiptForGate(directory, state.prReviewTriggerEvalPath);
30904
+ const receipt = "noReceipt" in receiptRead ? null : receiptRead.receipt;
30905
+ if (!receipt) {
30852
30906
  throw new Error("BLOCKED: PR_REVIEW trigger evaluation artifact is missing or invalid");
30853
30907
  }
30854
- let receipt;
30855
- try {
30856
- receipt = parsePrReviewTriggerReceipt(triggerArtifact);
30857
- } catch (error2) {
30858
- throw new Error(`BLOCKED: PR_REVIEW trigger evaluation is invalid: ${error2 instanceof Error ? error2.message : String(error2)}`);
30859
- }
30860
30908
  for (const row of receipt.matchedRows) {
30861
30909
  sources.push({
30862
30910
  batchId: row.source_batch_id,
@@ -32175,6 +32223,128 @@ async function readPrWorkflowGateStateForRecovery(directory, sessionID) {
32175
32223
  // src/commands/registry.ts
32176
32224
  init_logger();
32177
32225
 
32226
+ // src/commands/_shared/url-security.ts
32227
+ import * as child_process from "child_process";
32228
+ init_git_executable();
32229
+ var MAX_URL_LEN = 2048;
32230
+ var _internals32 = {
32231
+ spawnSync: (cmd, args, options) => {
32232
+ const mergedEnv = mergeEnvForChild(options?.env, options?.envOverrides);
32233
+ return child_process.spawnSync(cmd, args, {
32234
+ ...options,
32235
+ env: mergedEnv
32236
+ });
32237
+ }
32238
+ };
32239
+ function sanitizeUrl(raw) {
32240
+ let urlStr = raw.trim();
32241
+ urlStr = urlStr.replace(/^([A-Za-z][A-Za-z0-9+.-]*:\/\/)\/?[^@/]+@/, "$1");
32242
+ urlStr = urlStr.replace(/\[\s*MODE\s*:[^\]]*\]/gi, "");
32243
+ urlStr = urlStr.replace(/^([A-Za-z][A-Za-z0-9+.-]*:\/\/)\/?[^@/]+@/, "$1");
32244
+ const fragmentIdx = urlStr.indexOf("#");
32245
+ if (fragmentIdx !== -1) {
32246
+ urlStr = urlStr.slice(0, fragmentIdx);
32247
+ }
32248
+ const queryIdx = urlStr.indexOf("?");
32249
+ if (queryIdx !== -1) {
32250
+ urlStr = urlStr.slice(0, queryIdx);
32251
+ }
32252
+ if (urlStr.length > MAX_URL_LEN) {
32253
+ urlStr = urlStr.slice(0, MAX_URL_LEN);
32254
+ }
32255
+ return urlStr.trim();
32256
+ }
32257
+ function sanitizeErrorEcho(raw, maxLength = 80) {
32258
+ let stripped = "";
32259
+ for (const ch of raw) {
32260
+ const cp = ch.codePointAt(0);
32261
+ if (cp !== undefined && (cp <= 31 || cp === 127)) {
32262
+ stripped += " ";
32263
+ continue;
32264
+ }
32265
+ stripped += ch;
32266
+ }
32267
+ const collapsed = stripped.replace(/\s+/g, " ").trim();
32268
+ if (collapsed.length <= maxLength)
32269
+ return collapsed;
32270
+ return `${collapsed.slice(0, maxLength)}\u2026`;
32271
+ }
32272
+ function validateAndSanitizeGithubUrl(rawUrl, resource, configured) {
32273
+ const sanitized = sanitizeUrl(rawUrl);
32274
+ if (!sanitized) {
32275
+ return { error: "Empty URL" };
32276
+ }
32277
+ if (!sanitized.startsWith("https://")) {
32278
+ return { error: "URL must use HTTPS scheme" };
32279
+ }
32280
+ try {
32281
+ const url = new URL(sanitized);
32282
+ if (hasNonAsciiHostname(url.hostname)) {
32283
+ return { error: "Non-ASCII hostnames are not allowed" };
32284
+ }
32285
+ if (isPrivateHost(url)) {
32286
+ return { error: "Private or localhost URLs are not allowed" };
32287
+ }
32288
+ const matched = matchForgeResourceUrl(sanitized, resource, configured);
32289
+ if (!matched) {
32290
+ return {
32291
+ error: resource === "issues" ? "URL must be a GitHub issue URL (https://github.com/owner/repo/issues/N) or a GitLab issue URL (https://<gitlab-host>/owner/repo/-/issues/N)" : "URL must be a GitHub pull request URL (https://github.com/owner/repo/pull/N) or a GitLab merge request URL (https://<gitlab-host>/owner/repo/-/merge_requests/N)"
32292
+ };
32293
+ }
32294
+ return { sanitized };
32295
+ } catch {
32296
+ return { error: "Invalid URL format" };
32297
+ }
32298
+ }
32299
+ function detectGitRemote(cwd, laneEnv) {
32300
+ try {
32301
+ const result = _internals32.spawnSync(resolveGitExecutable(), ["remote", "get-url", "origin"], {
32302
+ encoding: "utf-8",
32303
+ stdio: ["ignore", "pipe", "pipe"],
32304
+ timeout: 5000,
32305
+ ...cwd ? { cwd } : {},
32306
+ envOverrides: laneEnv
32307
+ });
32308
+ if (result.status !== 0 || result.error) {
32309
+ return null;
32310
+ }
32311
+ const remoteUrl = (result.stdout ?? "").trim();
32312
+ return remoteUrl || null;
32313
+ } catch {
32314
+ return null;
32315
+ }
32316
+ }
32317
+ function parseGitRemoteUrl(remoteUrl) {
32318
+ const httpsMatch = remoteUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i);
32319
+ if (httpsMatch) {
32320
+ const owner = httpsMatch[1];
32321
+ const repo = httpsMatch[2].replace(/\.git$/, "");
32322
+ if (containsControlCharacters(owner) || containsControlCharacters(repo)) {
32323
+ return null;
32324
+ }
32325
+ return { owner, repo };
32326
+ }
32327
+ const sshMatch = remoteUrl.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/i);
32328
+ if (sshMatch) {
32329
+ const owner = sshMatch[1];
32330
+ const repo = sshMatch[2].replace(/\.git$/, "");
32331
+ if (containsControlCharacters(owner) || containsControlCharacters(repo)) {
32332
+ return null;
32333
+ }
32334
+ return { owner, repo };
32335
+ }
32336
+ const pathMatch = remoteUrl.match(/\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
32337
+ if (pathMatch) {
32338
+ const owner = pathMatch[1];
32339
+ const repo = pathMatch[2].replace(/\.git$/, "");
32340
+ if (containsControlCharacters(owner) || containsControlCharacters(repo)) {
32341
+ return null;
32342
+ }
32343
+ return { owner, repo };
32344
+ }
32345
+ return null;
32346
+ }
32347
+
32178
32348
  // src/commands/abort-pr-workflow.ts
32179
32349
  var USAGE2 = [
32180
32350
  "Usage: /swarm abort-pr-workflow [PR_REVIEW|PR_FEEDBACK] [reason...]",
@@ -32279,7 +32449,7 @@ import { createHash as createHash24 } from "crypto";
32279
32449
  import { mkdir as mkdir6, readFile as readFile10, unlink as unlink2 } from "fs/promises";
32280
32450
  import { dirname as dirname15 } from "path";
32281
32451
  var SPEC_DRIFT_RECOVERY_AGENT = "spec-drift-recovery";
32282
- var _internals32 = {
32452
+ var _internals33 = {
32283
32453
  appendEvent,
32284
32454
  assertProjectRoot,
32285
32455
  bunWrite,
@@ -32364,21 +32534,21 @@ async function writeWal3(walPath, wal) {
32364
32534
  }
32365
32535
  async function verifySnapshot(snapshotPath, currentSpec) {
32366
32536
  if (!currentSpec) {
32367
- await _internals32.unlinkIfExists(snapshotPath);
32368
- const stillExists = await _internals32.readFileText(snapshotPath) !== null;
32537
+ await _internals33.unlinkIfExists(snapshotPath);
32538
+ const stillExists = await _internals33.readFileText(snapshotPath) !== null;
32369
32539
  if (stillExists) {
32370
32540
  throw new Error("spec snapshot verification failed: snapshot still exists after delete");
32371
32541
  }
32372
32542
  return;
32373
32543
  }
32374
32544
  await atomicWriteFile(snapshotPath, currentSpec.content);
32375
- const written = await _internals32.readFileText(snapshotPath);
32545
+ const written = await _internals33.readFileText(snapshotPath);
32376
32546
  if (written !== currentSpec.content) {
32377
32547
  throw new Error("spec snapshot verification failed: snapshot content does not match effective spec");
32378
32548
  }
32379
32549
  }
32380
32550
  async function ensureSnapshotEvent(directory, plan, transitionId) {
32381
- const events = await _internals32.readLedgerEvents(directory);
32551
+ const events = await _internals33.readLedgerEvents(directory);
32382
32552
  for (const event of events) {
32383
32553
  const payload = event.payload;
32384
32554
  const approval = payload?.approval;
@@ -32386,17 +32556,17 @@ async function ensureSnapshotEvent(directory, plan, transitionId) {
32386
32556
  return;
32387
32557
  }
32388
32558
  }
32389
- await _internals32.takeSnapshotEvent(directory, plan, {
32559
+ await _internals33.takeSnapshotEvent(directory, plan, {
32390
32560
  source: "spec_drift_recovery",
32391
32561
  approvalMetadata: { specDriftTransitionId: transitionId }
32392
32562
  });
32393
32563
  }
32394
32564
  async function appendEvent(directory, event) {
32395
- const existing = await _internals32.verifyEventPresence(directory, event.type, event.transitionId);
32565
+ const existing = await _internals33.verifyEventPresence(directory, event.type, event.transitionId);
32396
32566
  if (existing)
32397
32567
  return;
32398
32568
  appendCoreEventSync(directory, { ...event }, { dedupeOnAuthorityKey: true });
32399
- const verified = await _internals32.verifyEventPresence(directory, event.type, event.transitionId);
32569
+ const verified = await _internals33.verifyEventPresence(directory, event.type, event.transitionId);
32400
32570
  if (!verified) {
32401
32571
  throw new Error(`spec drift audit verification failed for transition ${event.transitionId}`);
32402
32572
  }
@@ -32418,7 +32588,7 @@ function buildRecoveryEvent(args) {
32418
32588
  if (args.mode === "acknowledge") {
32419
32589
  return {
32420
32590
  type: "spec_drift_acknowledged",
32421
- timestamp: _internals32.now(),
32591
+ timestamp: _internals33.now(),
32422
32592
  phase: args.phase,
32423
32593
  planTitle: args.planTitle,
32424
32594
  acknowledgedBy: args.actor === "spec_write" ? "unknown" : args.actor,
@@ -32430,7 +32600,7 @@ function buildRecoveryEvent(args) {
32430
32600
  }
32431
32601
  return {
32432
32602
  type: "spec_drift_repaired",
32433
- timestamp: _internals32.now(),
32603
+ timestamp: _internals33.now(),
32434
32604
  phase: args.phase,
32435
32605
  planTitle: args.planTitle,
32436
32606
  repairedBy: args.actor,
@@ -32441,11 +32611,11 @@ function buildRecoveryEvent(args) {
32441
32611
  };
32442
32612
  }
32443
32613
  async function reconcileSpecDrift(directory, options) {
32444
- _internals32.assertProjectRoot(directory);
32445
- const markerPath = _internals32.validateSwarmPath(directory, "spec-staleness.json");
32446
- const walPath = _internals32.validateSwarmPath(directory, "spec-drift-recovery.json");
32447
- const snapshotPath = _internals32.validateSwarmPath(directory, "spec-snapshot.md");
32448
- const markerMaybe = await _internals32.readFileText(markerPath);
32614
+ _internals33.assertProjectRoot(directory);
32615
+ const markerPath = _internals33.validateSwarmPath(directory, "spec-staleness.json");
32616
+ const walPath = _internals33.validateSwarmPath(directory, "spec-drift-recovery.json");
32617
+ const snapshotPath = _internals33.validateSwarmPath(directory, "spec-snapshot.md");
32618
+ const markerMaybe = await _internals33.readFileText(markerPath);
32449
32619
  if (markerMaybe === null) {
32450
32620
  return {
32451
32621
  status: "no_marker",
@@ -32453,7 +32623,7 @@ async function reconcileSpecDrift(directory, options) {
32453
32623
  message: "No spec drift detected."
32454
32624
  };
32455
32625
  }
32456
- const specLockResult = options.specLockAlreadyHeld ? null : await _internals32.tryAcquireLock(directory, "spec.md", SPEC_DRIFT_RECOVERY_AGENT, `spec-${options.mode}-${Date.now()}`);
32626
+ const specLockResult = options.specLockAlreadyHeld ? null : await _internals33.tryAcquireLock(directory, "spec.md", SPEC_DRIFT_RECOVERY_AGENT, `spec-${options.mode}-${Date.now()}`);
32457
32627
  if (specLockResult && !specLockResult.acquired) {
32458
32628
  return {
32459
32629
  status: "retry_later",
@@ -32463,7 +32633,7 @@ async function reconcileSpecDrift(directory, options) {
32463
32633
  }
32464
32634
  let lockResult;
32465
32635
  try {
32466
- lockResult = await _internals32.tryAcquireLock(directory, "plan.json", SPEC_DRIFT_RECOVERY_AGENT, `${options.mode}-${Date.now()}`);
32636
+ lockResult = await _internals33.tryAcquireLock(directory, "plan.json", SPEC_DRIFT_RECOVERY_AGENT, `${options.mode}-${Date.now()}`);
32467
32637
  } catch (error2) {
32468
32638
  if (specLockResult?.acquired && specLockResult.lock._release) {
32469
32639
  await specLockResult.lock._release().catch(() => {});
@@ -32489,7 +32659,7 @@ async function reconcileSpecDrift(directory, options) {
32489
32659
  let errorNewHash;
32490
32660
  try {
32491
32661
  try {
32492
- const authoritativeMarkerRaw = await _internals32.readFileText(markerPath);
32662
+ const authoritativeMarkerRaw = await _internals33.readFileText(markerPath);
32493
32663
  if (authoritativeMarkerRaw === null) {
32494
32664
  return {
32495
32665
  status: "no_marker",
@@ -32497,14 +32667,14 @@ async function reconcileSpecDrift(directory, options) {
32497
32667
  message: "No spec drift detected."
32498
32668
  };
32499
32669
  }
32500
- const marker = _internals32.parseMarker(authoritativeMarkerRaw);
32670
+ const marker = _internals33.parseMarker(authoritativeMarkerRaw);
32501
32671
  if (!marker) {
32502
32672
  return buildCorruptMarkerResult(options.mode);
32503
32673
  }
32504
32674
  errorMarker = marker;
32505
32675
  const markerHash = sha2563(authoritativeMarkerRaw);
32506
- const existingWalRaw = await _internals32.readFileText(walPath);
32507
- const existingWal = existingWalRaw === null ? null : _internals32.parseWal(existingWalRaw);
32676
+ const existingWalRaw = await _internals33.readFileText(walPath);
32677
+ const existingWal = existingWalRaw === null ? null : _internals33.parseWal(existingWalRaw);
32508
32678
  if (existingWalRaw !== null && !existingWal) {
32509
32679
  return {
32510
32680
  status: "failed",
@@ -32514,7 +32684,7 @@ async function reconcileSpecDrift(directory, options) {
32514
32684
  planTitle: marker.planTitle
32515
32685
  };
32516
32686
  }
32517
- const currentSpec = _internals32.readEffectiveSpecSync(directory);
32687
+ const currentSpec = _internals33.readEffectiveSpecSync(directory);
32518
32688
  const proposedNewHash = currentSpec?.hash ?? null;
32519
32689
  const proposedTransitionId = buildTransitionId(options.mode, markerHash, marker.specHash_plan, proposedNewHash);
32520
32690
  const proposedWal = {
@@ -32529,7 +32699,7 @@ async function reconcileSpecDrift(directory, options) {
32529
32699
  newHash: proposedNewHash,
32530
32700
  specContent: currentSpec?.content ?? null,
32531
32701
  actor: options.actor,
32532
- recordedAt: _internals32.now()
32702
+ recordedAt: _internals33.now()
32533
32703
  };
32534
32704
  const markerReplacedDuringPrepared = existingWal?.state === "PREPARED" && existingWal.markerHash !== markerHash;
32535
32705
  const wal = existingWal?.state === "PREPARED" || existingWal?.markerHash === markerHash ? existingWal : proposedWal;
@@ -32538,12 +32708,12 @@ async function reconcileSpecDrift(directory, options) {
32538
32708
  errorTransitionId = transitionId;
32539
32709
  errorNewHash = newHash;
32540
32710
  if (wal === proposedWal) {
32541
- await _internals32.writeWal(walPath, wal);
32711
+ await _internals33.writeWal(walPath, wal);
32542
32712
  }
32543
32713
  if (wal.newHash === null !== (wal.specContent === null) || wal.specContent !== null && sha2563(wal.specContent) !== wal.newHash) {
32544
32714
  throw new Error(`Spec drift recovery WAL ${transitionId} has inconsistent captured spec content`);
32545
32715
  }
32546
- let plan = await _internals32.loadPlanJsonOnly(directory);
32716
+ let plan = await _internals33.loadPlanJsonOnly(directory);
32547
32717
  if (!plan) {
32548
32718
  return {
32549
32719
  status: "failed",
@@ -32574,13 +32744,13 @@ async function reconcileSpecDrift(directory, options) {
32574
32744
  }
32575
32745
  if (planMatchesOld) {
32576
32746
  plan.specHash = newHash ?? undefined;
32577
- await _internals32.savePlan(directory, plan, {
32747
+ await _internals33.savePlan(directory, plan, {
32578
32748
  planLockAlreadyHeld: true
32579
32749
  });
32580
- plan = await _internals32.loadPlanJsonOnly(directory) ?? plan;
32750
+ plan = await _internals33.loadPlanJsonOnly(directory) ?? plan;
32581
32751
  }
32582
- await _internals32.ensureSnapshotEvent(directory, plan, transitionId);
32583
- await _internals32.verifySnapshot(snapshotPath, wal.specContent === null ? null : { content: wal.specContent });
32752
+ await _internals33.ensureSnapshotEvent(directory, plan, transitionId);
32753
+ await _internals33.verifySnapshot(snapshotPath, wal.specContent === null ? null : { content: wal.specContent });
32584
32754
  const event = buildRecoveryEvent({
32585
32755
  mode: wal.mode,
32586
32756
  actor: wal.actor,
@@ -32591,15 +32761,15 @@ async function reconcileSpecDrift(directory, options) {
32591
32761
  previousHash: wal.previousHash,
32592
32762
  transitionId
32593
32763
  });
32594
- await _internals32.appendEvent(directory, event);
32595
- await _internals32.writeWal(walPath, { ...wal, state: "COMMITTED" });
32764
+ await _internals33.appendEvent(directory, event);
32765
+ await _internals33.writeWal(walPath, { ...wal, state: "COMMITTED" });
32596
32766
  }
32597
32767
  if (markerReplacedDuringPrepared) {
32598
32768
  const preservedMarker = {
32599
32769
  ...marker,
32600
32770
  specHash_plan: newHash,
32601
32771
  reason: `prior prepared drift recovery committed before this marker: ${marker.reason}`,
32602
- timestamp: _internals32.now()
32772
+ timestamp: _internals33.now()
32603
32773
  };
32604
32774
  await atomicWriteFile(markerPath, `${JSON.stringify(preservedMarker, null, 2)}
32605
32775
  `);
@@ -32614,7 +32784,7 @@ async function reconcileSpecDrift(directory, options) {
32614
32784
  transitionId
32615
32785
  };
32616
32786
  }
32617
- const latestSpec = _internals32.readEffectiveSpecSync(directory);
32787
+ const latestSpec = _internals33.readEffectiveSpecSync(directory);
32618
32788
  if ((latestSpec?.hash ?? null) !== newHash) {
32619
32789
  const refreshedMarker = {
32620
32790
  planTitle: wal.planTitle,
@@ -32622,7 +32792,7 @@ async function reconcileSpecDrift(directory, options) {
32622
32792
  specHash_plan: newHash,
32623
32793
  specHash_current: latestSpec?.hash ?? null,
32624
32794
  reason: "spec changed while drift recovery was committing",
32625
- timestamp: _internals32.now()
32795
+ timestamp: _internals33.now()
32626
32796
  };
32627
32797
  await atomicWriteFile(markerPath, `${JSON.stringify(refreshedMarker, null, 2)}
32628
32798
  `);
@@ -32638,8 +32808,8 @@ async function reconcileSpecDrift(directory, options) {
32638
32808
  };
32639
32809
  }
32640
32810
  try {
32641
- await _internals32.unlinkIfExists(markerPath);
32642
- _internals32.invalidateCachedArtifact(markerPath);
32811
+ await _internals33.unlinkIfExists(markerPath);
32812
+ _internals33.invalidateCachedArtifact(markerPath);
32643
32813
  } catch (error2) {
32644
32814
  return {
32645
32815
  status: "cleanup_pending",
@@ -33136,7 +33306,7 @@ ${USAGE4}`;
33136
33306
 
33137
33307
  // src/commands/archive.ts
33138
33308
  init_loader();
33139
- var _internals33 = {
33309
+ var _internals34 = {
33140
33310
  now: () => new Date
33141
33311
  };
33142
33312
  function artifactLabel(artifact) {
@@ -33192,7 +33362,7 @@ async function handleArchiveCommand(directory, args) {
33192
33362
  const report = await archiveEvidence(directory, maxAgeDays, maxBundles, {
33193
33363
  report: true,
33194
33364
  dryRun,
33195
- now: _internals33.now(),
33365
+ now: _internals34.now(),
33196
33366
  cacheMaxBytes,
33197
33367
  cacheMaxRecords
33198
33368
  });
@@ -35159,7 +35329,7 @@ function createShadowCopy(directory, maxBytes = MAX_SHADOW_COPY_BYTES) {
35159
35329
  const rel = path33.relative(directory, src);
35160
35330
  const dest = path33.join(shadowRoot, rel);
35161
35331
  fs21.mkdirSync(path33.dirname(dest), { recursive: true });
35162
- const copied = _internals34.copyFileBounded(src, dest, maxBytes - copiedBytes);
35332
+ const copied = _internals35.copyFileBounded(src, dest, maxBytes - copiedBytes);
35163
35333
  if (copied === null) {
35164
35334
  removeShadowRoot(shadowRoot);
35165
35335
  return null;
@@ -35172,7 +35342,7 @@ function createShadowCopy(directory, maxBytes = MAX_SHADOW_COPY_BYTES) {
35172
35342
  throw error2;
35173
35343
  }
35174
35344
  }
35175
- var _internals34 = {
35345
+ var _internals35 = {
35176
35346
  computeEvidenceQualitySummary,
35177
35347
  copyFileBounded,
35178
35348
  createShadowCopy
@@ -35419,7 +35589,7 @@ async function evaluateAdvisoryCi(options) {
35419
35589
  });
35420
35590
  }
35421
35591
  }
35422
- const summary = await _internals34.computeEvidenceQualitySummary(directory);
35592
+ const summary = await _internals35.computeEvidenceQualitySummary(directory);
35423
35593
  const q = summary.qualityMetrics;
35424
35594
  const qualityRows = [
35425
35595
  [
@@ -35813,7 +35983,7 @@ async function handleCiCommand(ctx) {
35813
35983
  const signals = createSignalCancellation(controller);
35814
35984
  signals.install();
35815
35985
  try {
35816
- const result = await _internals35.runAdvisoryCiRuntime({
35986
+ const result = await _internals36.runAdvisoryCiRuntime({
35817
35987
  directory: ctx.directory,
35818
35988
  deadlineMs,
35819
35989
  signal: controller.signal,
@@ -35862,134 +36032,10 @@ async function handleCiCommand(ctx) {
35862
36032
  signals.dispose();
35863
36033
  }
35864
36034
  }
35865
- var _internals35 = { runAdvisoryCiRuntime };
36035
+ var _internals36 = { runAdvisoryCiRuntime };
35866
36036
 
35867
36037
  // src/commands/pr-ref.ts
35868
36038
  init_loader();
35869
-
35870
- // src/commands/_shared/url-security.ts
35871
- import * as child_process from "child_process";
35872
- init_git_executable();
35873
- var MAX_URL_LEN = 2048;
35874
- var _internals36 = {
35875
- spawnSync: (cmd, args, options) => {
35876
- const mergedEnv = mergeEnvForChild(options?.env, options?.envOverrides);
35877
- return child_process.spawnSync(cmd, args, {
35878
- ...options,
35879
- env: mergedEnv
35880
- });
35881
- }
35882
- };
35883
- function sanitizeUrl(raw) {
35884
- let urlStr = raw.trim();
35885
- urlStr = urlStr.replace(/^([A-Za-z][A-Za-z0-9+.-]*:\/\/)\/?[^@/]+@/, "$1");
35886
- urlStr = urlStr.replace(/\[\s*MODE\s*:[^\]]*\]/gi, "");
35887
- urlStr = urlStr.replace(/^([A-Za-z][A-Za-z0-9+.-]*:\/\/)\/?[^@/]+@/, "$1");
35888
- const fragmentIdx = urlStr.indexOf("#");
35889
- if (fragmentIdx !== -1) {
35890
- urlStr = urlStr.slice(0, fragmentIdx);
35891
- }
35892
- const queryIdx = urlStr.indexOf("?");
35893
- if (queryIdx !== -1) {
35894
- urlStr = urlStr.slice(0, queryIdx);
35895
- }
35896
- if (urlStr.length > MAX_URL_LEN) {
35897
- urlStr = urlStr.slice(0, MAX_URL_LEN);
35898
- }
35899
- return urlStr.trim();
35900
- }
35901
- function sanitizeErrorEcho(raw, maxLength = 80) {
35902
- let stripped = "";
35903
- for (const ch of raw) {
35904
- const cp = ch.codePointAt(0);
35905
- if (cp !== undefined && (cp <= 31 || cp === 127)) {
35906
- stripped += " ";
35907
- continue;
35908
- }
35909
- stripped += ch;
35910
- }
35911
- const collapsed = stripped.replace(/\s+/g, " ").trim();
35912
- if (collapsed.length <= maxLength)
35913
- return collapsed;
35914
- return `${collapsed.slice(0, maxLength)}\u2026`;
35915
- }
35916
- function validateAndSanitizeGithubUrl(rawUrl, resource, configured) {
35917
- const sanitized = sanitizeUrl(rawUrl);
35918
- if (!sanitized) {
35919
- return { error: "Empty URL" };
35920
- }
35921
- if (!sanitized.startsWith("https://")) {
35922
- return { error: "URL must use HTTPS scheme" };
35923
- }
35924
- try {
35925
- const url = new URL(sanitized);
35926
- if (hasNonAsciiHostname(url.hostname)) {
35927
- return { error: "Non-ASCII hostnames are not allowed" };
35928
- }
35929
- if (isPrivateHost(url)) {
35930
- return { error: "Private or localhost URLs are not allowed" };
35931
- }
35932
- const matched = matchForgeResourceUrl(sanitized, resource, configured);
35933
- if (!matched) {
35934
- return {
35935
- error: resource === "issues" ? "URL must be a GitHub issue URL (https://github.com/owner/repo/issues/N) or a GitLab issue URL (https://<gitlab-host>/owner/repo/-/issues/N)" : "URL must be a GitHub pull request URL (https://github.com/owner/repo/pull/N) or a GitLab merge request URL (https://<gitlab-host>/owner/repo/-/merge_requests/N)"
35936
- };
35937
- }
35938
- return { sanitized };
35939
- } catch {
35940
- return { error: "Invalid URL format" };
35941
- }
35942
- }
35943
- function detectGitRemote(cwd, laneEnv) {
35944
- try {
35945
- const result = _internals36.spawnSync(resolveGitExecutable(), ["remote", "get-url", "origin"], {
35946
- encoding: "utf-8",
35947
- stdio: ["ignore", "pipe", "pipe"],
35948
- timeout: 5000,
35949
- ...cwd ? { cwd } : {},
35950
- envOverrides: laneEnv
35951
- });
35952
- if (result.status !== 0 || result.error) {
35953
- return null;
35954
- }
35955
- const remoteUrl = (result.stdout ?? "").trim();
35956
- return remoteUrl || null;
35957
- } catch {
35958
- return null;
35959
- }
35960
- }
35961
- function parseGitRemoteUrl(remoteUrl) {
35962
- const httpsMatch = remoteUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i);
35963
- if (httpsMatch) {
35964
- const owner = httpsMatch[1];
35965
- const repo = httpsMatch[2].replace(/\.git$/, "");
35966
- if (containsControlCharacters(owner) || containsControlCharacters(repo)) {
35967
- return null;
35968
- }
35969
- return { owner, repo };
35970
- }
35971
- const sshMatch = remoteUrl.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/i);
35972
- if (sshMatch) {
35973
- const owner = sshMatch[1];
35974
- const repo = sshMatch[2].replace(/\.git$/, "");
35975
- if (containsControlCharacters(owner) || containsControlCharacters(repo)) {
35976
- return null;
35977
- }
35978
- return { owner, repo };
35979
- }
35980
- const pathMatch = remoteUrl.match(/\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
35981
- if (pathMatch) {
35982
- const owner = pathMatch[1];
35983
- const repo = pathMatch[2].replace(/\.git$/, "");
35984
- if (containsControlCharacters(owner) || containsControlCharacters(repo)) {
35985
- return null;
35986
- }
35987
- return { owner, repo };
35988
- }
35989
- return null;
35990
- }
35991
-
35992
- // src/commands/pr-ref.ts
35993
36039
  var MAX_INSTRUCTIONS_LEN = 1000;
35994
36040
  var GITHUB_CONTEXT = {
35995
36041
  provider: "github",
@@ -40407,9 +40453,9 @@ function hashContent(content) {
40407
40453
  return createHash27("sha1").update(content).digest("hex");
40408
40454
  }
40409
40455
  async function loadConfigForPolicyCurator(directory) {
40410
- const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-108trhk6.js");
40456
+ const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-zrcgm9d9.js");
40411
40457
  try {
40412
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-f3grtpy3.js");
40458
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-p6bvzgp2.js");
40413
40459
  const { config: loadedConfig } = loadPluginConfigWithMeta2(directory);
40414
40460
  return KnowledgeConfigSchema2.parse(loadedConfig.knowledge ?? {});
40415
40461
  } catch {
@@ -43467,7 +43513,7 @@ async function resolveCuratorLLMDelegate(directory, mode, sessionId) {
43467
43513
  const seam = _internals38.createCuratorLLMDelegate;
43468
43514
  if (seam)
43469
43515
  return seam(directory, mode, sessionId);
43470
- const { createCuratorLLMDelegate } = await import("./curator-llm-factory-tr6rabws.js");
43516
+ const { createCuratorLLMDelegate } = await import("./curator-llm-factory-13h02244.js");
43471
43517
  return createCuratorLLMDelegate(directory, mode, sessionId);
43472
43518
  }
43473
43519
  async function reconcileCloseTerminalStateForPlan(directory, targetPlan, options) {
@@ -43862,7 +43908,7 @@ async function runFinalizeStage(ctx) {
43862
43908
  }
43863
43909
  }
43864
43910
  try {
43865
- const { CuratorConfigSchema: CCS } = await import("./schema-108trhk6.js");
43911
+ const { CuratorConfigSchema: CCS } = await import("./schema-zrcgm9d9.js");
43866
43912
  const { config: pmLoadedConfig } = _internals38.loadPluginConfigWithMeta(ctx.directory);
43867
43913
  const curatorCfg = CCS.parse(pmLoadedConfig.curator ?? {});
43868
43914
  if (curatorCfg.enabled && curatorCfg.postmortem_enabled) {
@@ -46048,7 +46094,7 @@ function serializeAgentSession(s) {
46048
46094
  }
46049
46095
  async function writeSnapshot(directory, state) {
46050
46096
  try {
46051
- const { ensureSnapshotCoordinationReady } = await import("./snapshot-coordination-init-pactfmsy.js");
46097
+ const { ensureSnapshotCoordinationReady } = await import("./snapshot-coordination-init-5q0hac3d.js");
46052
46098
  await ensureSnapshotCoordinationReady(directory);
46053
46099
  const snapshot = {
46054
46100
  version: 3,
@@ -49226,7 +49272,7 @@ function planMerges(active, threshold, maxComparisons, maxMerges) {
49226
49272
  };
49227
49273
  }
49228
49274
  async function sweepActiveNearDuplicates(directory, options = {}) {
49229
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-f3grtpy3.js");
49275
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-p6bvzgp2.js");
49230
49276
  const { config } = loadPluginConfigWithMeta2(directory);
49231
49277
  const sweepConfig = config.learning?.dedup_sweep;
49232
49278
  if (sweepConfig?.enabled === false)
@@ -50107,14 +50153,14 @@ async function runCuratorInit(directory, config, llmDelegate) {
50107
50153
  }));
50108
50154
  if (llmDelegate) {
50109
50155
  try {
50110
- const userInput = [
50156
+ const userInput = sanitizeContextText([
50111
50157
  "TASK: CURATOR_INIT",
50112
50158
  `PRIOR_SUMMARY: ${priorSummary ? JSON.stringify(priorSummary) : "none"}`,
50113
50159
  `KNOWLEDGE_ENTRIES: ${JSON.stringify(allEntriesForCurator)}`,
50114
- `PROJECT_CONTEXT: ${contextMd?.slice(0, config.max_summary_tokens * 2) ?? "none"}`,
50115
- `POST_MORTEM_DIGEST: ${latestPostMortemDigest ?? "none"}`
50160
+ `PROJECT_CONTEXT: ${sanitizeContextText(contextMd?.slice(0, config.max_summary_tokens * 2) ?? "none")}`,
50161
+ `POST_MORTEM_DIGEST: ${sanitizeContextText(latestPostMortemDigest ?? "none")}`
50116
50162
  ].join(`
50117
- `);
50163
+ `));
50118
50164
  const systemPrompt = CURATOR_INIT_PROMPT;
50119
50165
  const timeoutMs = config.llm_timeout_ms ?? DEFAULT_CURATOR_LLM_TIMEOUT_MS;
50120
50166
  const ac = new AbortController;
@@ -50208,7 +50254,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
50208
50254
  const phaseData = plan?.phases.find((p) => p.id === phase);
50209
50255
  const tasksCompleted = phaseData ? phaseData.tasks.filter((t) => t.status === "completed").length : 0;
50210
50256
  const tasksTotal = phaseData ? phaseData.tasks.length : 0;
50211
- const keyDecisions = contextMd ? extractContextDecisions(contextMd).map((decision) => decision.raw.trim().slice(2)) : [];
50257
+ const keyDecisions = contextMd ? extractContextDecisions(contextMd).map((decision) => sanitizeContextText(decision.raw.trim().slice(2))) : [];
50212
50258
  const phaseDigest = {
50213
50259
  phase,
50214
50260
  timestamp: new Date().toISOString(),
@@ -50239,16 +50285,16 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
50239
50285
  try {
50240
50286
  const priorDigest = priorSummary?.digest ?? "none";
50241
50287
  const systemPrompt = CURATOR_PHASE_PROMPT;
50242
- const userInput = [
50288
+ const userInput = sanitizeContextText([
50243
50289
  `TASK: CURATOR_PHASE ${phase}`,
50244
- `PRIOR_DIGEST: ${priorDigest}`,
50290
+ `PRIOR_DIGEST: ${sanitizeContextText(priorDigest)}`,
50245
50291
  `PHASE_EVENTS: ${JSON.stringify(phaseEvents.slice(0, 50))}`,
50246
50292
  `PHASE_DECISIONS: ${JSON.stringify(keyDecisions)}`,
50247
50293
  `AGENTS_DISPATCHED: ${JSON.stringify(agentsDispatched)}`,
50248
50294
  `AGENTS_EXPECTED: ["reviewer", "test_engineer"]`,
50249
50295
  `KNOWLEDGE_ENTRIES: ${JSON.stringify(knowledgeForCurator)}`
50250
50296
  ].join(`
50251
- `);
50297
+ `));
50252
50298
  const timeoutMs = config.llm_timeout_ms ?? DEFAULT_CURATOR_LLM_TIMEOUT_MS;
50253
50299
  const ac = new AbortController;
50254
50300
  const timer = setTimeout(() => ac.abort(), timeoutMs);
@@ -50350,7 +50396,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
50350
50396
  }
50351
50397
  if (config.skill_generation_enabled === true && skillCandidates.length > 0) {
50352
50398
  try {
50353
- const skillModule = await import("./skill-generator-7g6xjwhr.js");
50399
+ const skillModule = await import("./skill-generator-dztn1ctf.js");
50354
50400
  for (const cand of skillCandidates) {
50355
50401
  if (cand.confidence < (config.min_skill_confidence ?? DEFAULT_SKILL_MIN_CONFIDENCE)) {
50356
50402
  continue;
@@ -50822,7 +50868,7 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
50822
50868
  } catch {}
50823
50869
  }
50824
50870
  if (contradictedEntries.length > 0 && knowledgeConfig.contradiction_threshold_action === "quarantine") {
50825
- const { maybeQuarantineOnContradiction } = await import("./knowledge-escalator-xdz6vg62.js");
50871
+ const { maybeQuarantineOnContradiction } = await import("./knowledge-escalator-7xcd0zea.js");
50826
50872
  for (const { id } of contradictedEntries) {
50827
50873
  try {
50828
50874
  await maybeQuarantineOnContradiction(directory, id, knowledgeConfig.contradiction_quarantine_threshold, knowledgeConfig.contradiction_quarantine_window_days);
@@ -51335,9 +51381,9 @@ async function repairPostMortemActions(llmOutput, diagnostics, options) {
51335
51381
  "Allowed queue_triage action values: apply, reject.",
51336
51382
  "Do not include unsupported actions such as merge.",
51337
51383
  "Diagnostics:",
51338
- diagnostics.join("; "),
51384
+ diagnostics.map((d) => sanitizeContextText(d)).join("; "),
51339
51385
  "Original output:",
51340
- llmOutput.slice(0, 8000)
51386
+ sanitizeContextText(llmOutput).slice(0, 8000)
51341
51387
  ].join(`
51342
51388
  `);
51343
51389
  const repaired = await options.llmDelegate("", repairPrompt, ac.signal);
@@ -51553,8 +51599,8 @@ function assembleLLMInput(planId, scope, sessionID, planSummary, knowledgeSummar
51553
51599
  const sections = [];
51554
51600
  sections.push(`TASK: CURATOR_POSTMORTEM ${planId}`);
51555
51601
  sections.push(`SCOPE: ${scope}${sessionID ? ` (${sessionID})` : ""}`);
51556
- sections.push(`PLAN_SUMMARY: ${planSummary}`);
51557
- sections.push(`CURATOR_DIGESTS: ${curatorDigest ?? "none"}`);
51602
+ sections.push(`PLAN_SUMMARY: ${sanitizeContextText(planSummary)}`);
51603
+ sections.push(`CURATOR_DIGESTS: ${sanitizeContextText(curatorDigest ?? "none")}`);
51558
51604
  const eventsSummary = knowledgeSummary.map((e) => `${e.id}: applied=${e.applied} violated=${e.violated} ignored=${e.ignored} unacknowledged=${e.unacknowledged} confidence=${e.confidence.toFixed(2)} status=${e.status}`).join(`
51559
51605
  `);
51560
51606
  sections.push(`KNOWLEDGE_EVENTS_SUMMARY:
@@ -51585,9 +51631,9 @@ ${retroText}`);
51585
51631
  sections.push(`DRIFT_REPORTS:
51586
51632
  ${driftText}`);
51587
51633
  }
51588
- return sections.join(`
51634
+ return sanitizeContextText(sections.join(`
51589
51635
 
51590
- `);
51636
+ `));
51591
51637
  }
51592
51638
  async function runCuratorPostMortem(directory, options = {}) {
51593
51639
  const warnings = [];
@@ -51654,7 +51700,7 @@ async function runCuratorPostMortem(directory, options = {}) {
51654
51700
  warnings.push("Failed to collect knowledge summary.");
51655
51701
  }
51656
51702
  try {
51657
- const { getScanStatus } = await import("./scan-cursor-71gq82ez.js");
51703
+ const { getScanStatus } = await import("./scan-cursor-fgecb928.js");
51658
51704
  const scanStatus = await getScanStatus(directory);
51659
51705
  if (scanStatus.remaining_estimate > 0) {
51660
51706
  warnings.push(`Fair scan: reviewed ${knowledgeSummary.length} entries this sweep (generation ${scanStatus.generation}); ${scanStatus.remaining_estimate} more eligible entries will be visited in future curation sweeps.`);
@@ -51826,9 +51872,9 @@ var _internals57 = {
51826
51872
  verifyPostMortemKnowledgeActions,
51827
51873
  repairPostMortemActions,
51828
51874
  loadDefaultKnowledgeConfig: async (directory) => {
51829
- const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-108trhk6.js");
51875
+ const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-zrcgm9d9.js");
51830
51876
  try {
51831
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-f3grtpy3.js");
51877
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-p6bvzgp2.js");
51832
51878
  const loaded = loadPluginConfigWithMeta2(directory);
51833
51879
  return KnowledgeConfigSchema2.parse(loaded.config.knowledge ?? {});
51834
51880
  } catch {
@@ -51836,11 +51882,11 @@ var _internals57 = {
51836
51882
  }
51837
51883
  },
51838
51884
  applyCuratorKnowledgeUpdates: async (directory, recommendations, knowledgeConfig, generation) => {
51839
- const { applyCuratorKnowledgeUpdates: applyCuratorKnowledgeUpdates2 } = await import("./curator-91rqz7xg.js");
51885
+ const { applyCuratorKnowledgeUpdates: applyCuratorKnowledgeUpdates2 } = await import("./curator-r0jfc7xw.js");
51840
51886
  return applyCuratorKnowledgeUpdates2(directory, recommendations, knowledgeConfig, generation);
51841
51887
  },
51842
51888
  checkHivePromotions: async (entries2, knowledgeConfig, directory) => {
51843
- const { checkHivePromotions } = await import("./hive-promoter-8dqvfwsx.js");
51889
+ const { checkHivePromotions } = await import("./hive-promoter-0vg8w79a.js");
51844
51890
  return checkHivePromotions(entries2, knowledgeConfig, directory);
51845
51891
  },
51846
51892
  applyProposalTriage: async (directory, triage) => {
@@ -51849,7 +51895,7 @@ var _internals57 = {
51849
51895
  activateProposal,
51850
51896
  listSkills: listSkills2,
51851
51897
  sanitizeSlug
51852
- } = await import("./skill-generator-7g6xjwhr.js");
51898
+ } = await import("./skill-generator-dztn1ctf.js");
51853
51899
  const result = {
51854
51900
  approved: [],
51855
51901
  rejected: [],
@@ -51891,7 +51937,7 @@ var _internals57 = {
51891
51937
  return result;
51892
51938
  },
51893
51939
  readPriorDriftReports: async (directory) => {
51894
- const { readPriorDriftReports: readPriorDriftReports2 } = await import("./curator-drift-qem70sry.js");
51940
+ const { readPriorDriftReports: readPriorDriftReports2 } = await import("./curator-drift-q84jn9cc.js");
51895
51941
  return readPriorDriftReports2(directory);
51896
51942
  },
51897
51943
  readSwarmKnowledge: (directory) => readKnowledge(resolveSwarmKnowledgePath(directory))
@@ -61687,9 +61733,9 @@ var _internals67 = {
61687
61733
  loadPluginConfigWithMeta,
61688
61734
  loadCuratorDeps: async () => {
61689
61735
  const [{ CuratorConfigSchema }, curator, { createCuratorLLMDelegate }] = await Promise.all([
61690
- import("./schema-108trhk6.js"),
61691
- import("./curator-91rqz7xg.js"),
61692
- import("./curator-llm-factory-tr6rabws.js")
61736
+ import("./schema-zrcgm9d9.js"),
61737
+ import("./curator-r0jfc7xw.js"),
61738
+ import("./curator-llm-factory-13h02244.js")
61693
61739
  ]);
61694
61740
  return { CuratorConfigSchema, curator, createCuratorLLMDelegate };
61695
61741
  }
@@ -64082,7 +64128,7 @@ async function computeCurationDiagnostics(directory, entries2) {
64082
64128
  let scanCompleted = false;
64083
64129
  let scanRemaining = 0;
64084
64130
  try {
64085
- const { getScanStatus } = await import("./scan-cursor-71gq82ez.js");
64131
+ const { getScanStatus } = await import("./scan-cursor-fgecb928.js");
64086
64132
  const status = await getScanStatus(directory);
64087
64133
  scanGeneration = status.generation;
64088
64134
  scanCompleted = status.completed;
@@ -64090,19 +64136,19 @@ async function computeCurationDiagnostics(directory, entries2) {
64090
64136
  } catch {}
64091
64137
  let configMatch = null;
64092
64138
  try {
64093
- const { isLinked: isLinked2 } = await import("./knowledge-link-y653vvr8.js");
64139
+ const { isLinked: isLinked2 } = await import("./knowledge-link-dv78fb9g.js");
64094
64140
  if (isLinked2(directory)) {
64095
- const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-108trhk6.js");
64141
+ const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-zrcgm9d9.js");
64096
64142
  let config;
64097
64143
  try {
64098
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-f3grtpy3.js");
64144
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-p6bvzgp2.js");
64099
64145
  const loaded = loadPluginConfigWithMeta2(directory);
64100
64146
  config = KnowledgeConfigSchema2.parse(loaded.config.knowledge ?? {});
64101
64147
  } catch {
64102
64148
  config = KnowledgeConfigSchema2.parse({});
64103
64149
  }
64104
64150
  const { cohortConfigFingerprint: cohortConfigFingerprint2 } = await import("./config-fingerprint-v22xh5a2.js");
64105
- const { buildConfigFingerprintInput: buildConfigFingerprintInput2, readCohortConfigFingerprint } = await import("./curation-policy-swnyg1jr.js");
64151
+ const { buildConfigFingerprintInput: buildConfigFingerprintInput2, readCohortConfigFingerprint } = await import("./curation-policy-ytzwb080.js");
64106
64152
  const currentFp = cohortConfigFingerprint2(buildConfigFingerprintInput2(config));
64107
64153
  const cohortFp = await readCohortConfigFingerprint(directory);
64108
64154
  configMatch = cohortFp === null ? null : currentFp === cohortFp;
@@ -65550,7 +65596,7 @@ async function handleDoctorCommand(directory, args) {
65550
65596
  const result = runConfigDoctor(config, directory);
65551
65597
  let output;
65552
65598
  if (enableAutoFix && result.hasAutoFixableIssues) {
65553
- const { runConfigDoctorWithFixes } = await import("./config-doctor-f2jtx8y5.js");
65599
+ const { runConfigDoctorWithFixes } = await import("./config-doctor-28ggsms8.js");
65554
65600
  const fixResult = await runConfigDoctorWithFixes(directory, config, true, {
65555
65601
  applyLossy: true
65556
65602
  });
@@ -65588,7 +65634,7 @@ async function handleDoctorCommand(directory, args) {
65588
65634
  `;
65589
65635
  }
65590
65636
  try {
65591
- const { runModelPreflight } = await import("./model-preflight-5xcxc75n.js");
65637
+ const { runModelPreflight } = await import("./model-preflight-kap3zp3g.js");
65592
65638
  const preflight = await runModelPreflight(config, swarmState.opencodeClient, { generatedAgentNames: swarmState.generatedAgentNames });
65593
65639
  const missingSelection = preflight.resolutions.filter((resolution) => resolution.status === "missing-selection");
65594
65640
  const unresolved = preflight.catalogAvailable ? preflight.resolutions.filter((resolution) => resolution.status === "unresolved") : [];
@@ -66515,7 +66561,7 @@ async function handleEvidenceCommand(directory, args) {
66515
66561
  return formatTaskEvidenceMarkdown(evidenceData);
66516
66562
  }
66517
66563
  async function handleEvidenceSummaryCommand(directory) {
66518
- const { buildEvidenceSummary } = await import("./evidence-summary-service-n7ndpen0.js");
66564
+ const { buildEvidenceSummary } = await import("./evidence-summary-service-rsectw2t.js");
66519
66565
  const artifact = await buildEvidenceSummary(directory);
66520
66566
  if (!artifact) {
66521
66567
  return "No plan found. Run `/swarm plan` to check plan status.";
@@ -90848,7 +90894,7 @@ function createCuratorLLMDelegate(directory, mode = "init", sessionId) {
90848
90894
  }
90849
90895
  const sdkOpts = signal ? { signal } : {};
90850
90896
  try {
90851
- const { getSwarmAgents: getSwarmAgents2, resolveFallbackModel: resolveFallbackModel2 } = await import("./index-73vnyt4b.js");
90897
+ const { getSwarmAgents: getSwarmAgents2, resolveFallbackModel: resolveFallbackModel2 } = await import("./index-22f1ek6k.js");
90852
90898
  const createResult = await client.session.create({
90853
90899
  ...sessionId ? {
90854
90900
  body: {
@@ -91140,8 +91186,8 @@ init_zod();
91140
91186
  init_loader();
91141
91187
  import { createHash as createHash51, randomUUID as randomUUID22 } from "crypto";
91142
91188
  import * as fsSync9 from "fs";
91143
- import * as fs63 from "fs/promises";
91144
- import * as path127 from "path";
91189
+ import * as fs64 from "fs/promises";
91190
+ import * as path128 from "path";
91145
91191
  init_logger();
91146
91192
 
91147
91193
  // src/background/pr-feedback-event-queue.ts
@@ -92106,6 +92152,228 @@ var _internals98 = {
92106
92152
 
92107
92153
  // src/git/pr.ts
92108
92154
  init_git_executable();
92155
+
92156
+ // src/utils/glab-executable.ts
92157
+ init_warning_buffer();
92158
+ import { spawnSync as spawnSync5 } from "child_process";
92159
+ import * as fs63 from "fs";
92160
+ import * as os14 from "os";
92161
+ import * as path127 from "path";
92162
+ var GLAB_BINARY_ENV_VAR = "OPENCODE_SWARM_GLAB_BINARY";
92163
+ var PER_PROBE_TIMEOUT_MS2 = 250;
92164
+ var TOTAL_BUDGET_MS3 = 1000;
92165
+ var NEGATIVE_CACHE_TTL_MS2 = 60000;
92166
+ var BARE_GLAB = "glab";
92167
+ var PROBE_MAX_BUFFER_BYTES2 = 64 * 1024;
92168
+ var PROBE_OUTPUT_EXCERPT_CHARS2 = 60;
92169
+ var WINDOWS_PATH_EXTENSIONS2 = [".exe", ".cmd", ".bat"];
92170
+ var GLAB_VERSION_PATTERN = /^glab version \d+\.\d+/;
92171
+ function excerptProbeOutput2(raw) {
92172
+ return raw.slice(0, PROBE_OUTPUT_EXCERPT_CHARS2).replace(/[^\x20-\x7E]/g, " ").trim();
92173
+ }
92174
+ var cache3 = null;
92175
+ var lastAttempts2 = [];
92176
+ var cacheGeneration2 = 0;
92177
+ function windowsGlabAbsoluteCandidates(env) {
92178
+ const candidates = [];
92179
+ const push = (...parts) => {
92180
+ const candidate2 = path127.join(...parts);
92181
+ if (!candidates.includes(candidate2))
92182
+ candidates.push(candidate2);
92183
+ };
92184
+ if (env.ProgramFiles) {
92185
+ push(env.ProgramFiles, "GitLab CLI", "glab.exe");
92186
+ }
92187
+ if (env["ProgramFiles(x86)"]) {
92188
+ push(env["ProgramFiles(x86)"], "GitLab CLI", "glab.exe");
92189
+ }
92190
+ if (env.LOCALAPPDATA) {
92191
+ push(env.LOCALAPPDATA, "GitLab CLI", "glab.exe");
92192
+ push(env.LOCALAPPDATA, "Programs", "GitLab CLI", "glab.exe");
92193
+ }
92194
+ return candidates;
92195
+ }
92196
+ function platformCandidates2(platform, env) {
92197
+ if (platform === "win32") {
92198
+ return windowsGlabAbsoluteCandidates(env);
92199
+ }
92200
+ if (platform === "darwin") {
92201
+ return ["/opt/homebrew/bin/glab", "/usr/local/bin/glab", "/usr/bin/glab"];
92202
+ }
92203
+ return ["/usr/bin/glab", "/usr/local/bin/glab", "/bin/glab"];
92204
+ }
92205
+ function isAbsoluteForPlatform2(candidate2, platform) {
92206
+ return platform === "win32" ? path127.win32.isAbsolute(candidate2) : path127.posix.isAbsolute(candidate2);
92207
+ }
92208
+ function joinDirAndName2(dir, name, platform) {
92209
+ const sep22 = platform === "win32" ? "\\" : "/";
92210
+ const trimmed = dir.replace(/[\\/]+$/, "");
92211
+ return trimmed ? `${trimmed}${sep22}${name}` : `${sep22}${name}`;
92212
+ }
92213
+ function pathCandidates2(platform) {
92214
+ const pathValue = _internals99.env().PATH ?? "";
92215
+ if (!pathValue)
92216
+ return [];
92217
+ const dirs = pathValue.split(platform === "win32" ? ";" : ":").filter(Boolean);
92218
+ const names = platform === "win32" ? [...WINDOWS_PATH_EXTENSIONS2.map((ext) => `glab${ext}`), "glab"] : ["glab"];
92219
+ const out = [];
92220
+ for (const dir of dirs) {
92221
+ for (const name of names) {
92222
+ const candidate2 = joinDirAndName2(dir, name, platform);
92223
+ if (!out.includes(candidate2))
92224
+ out.push(candidate2);
92225
+ }
92226
+ }
92227
+ return out;
92228
+ }
92229
+ function envOverride2() {
92230
+ const raw = _internals99.env()[GLAB_BINARY_ENV_VAR];
92231
+ return raw && raw.trim() !== "" ? raw : undefined;
92232
+ }
92233
+ function buildCandidates2(platform) {
92234
+ const override = envOverride2();
92235
+ const overrideCandidate = override ? [{ source: "override", path: override }] : [];
92236
+ const seen = new Set(overrideCandidate.map((c) => c.path));
92237
+ const rest = [];
92238
+ for (const p of platformCandidates2(platform, _internals99.env())) {
92239
+ if (seen.has(p))
92240
+ continue;
92241
+ seen.add(p);
92242
+ rest.push({ source: "platform", path: p });
92243
+ }
92244
+ for (const p of pathCandidates2(platform)) {
92245
+ if (seen.has(p))
92246
+ continue;
92247
+ seen.add(p);
92248
+ rest.push({ source: "path", path: p });
92249
+ }
92250
+ return [...overrideCandidate, ...rest];
92251
+ }
92252
+ function probeCandidate2(candidatePath2, platform) {
92253
+ if (!isAbsoluteForPlatform2(candidatePath2, platform)) {
92254
+ return { accepted: false, reason: "not an absolute path" };
92255
+ }
92256
+ let stat13;
92257
+ try {
92258
+ stat13 = fs63.statSync(candidatePath2);
92259
+ } catch (err) {
92260
+ const code = err?.code;
92261
+ if (code === "ENOENT")
92262
+ return { accepted: false, reason: "no such file" };
92263
+ return {
92264
+ accepted: false,
92265
+ reason: `cannot stat (${code ?? "unknown error"})`
92266
+ };
92267
+ }
92268
+ if (stat13.isDirectory()) {
92269
+ return { accepted: false, reason: "is a directory" };
92270
+ }
92271
+ if (!stat13.isFile()) {
92272
+ return { accepted: false, reason: "not a regular file" };
92273
+ }
92274
+ let result;
92275
+ try {
92276
+ result = _internals99.spawnSync(candidatePath2, ["--version"], {
92277
+ cwd: os14.tmpdir(),
92278
+ stdio: ["ignore", "pipe", "ignore"],
92279
+ windowsHide: true,
92280
+ timeout: PER_PROBE_TIMEOUT_MS2,
92281
+ maxBuffer: PROBE_MAX_BUFFER_BYTES2
92282
+ });
92283
+ } catch (err) {
92284
+ return {
92285
+ accepted: false,
92286
+ reason: `spawn threw: ${err instanceof Error ? err.message : String(err)}`
92287
+ };
92288
+ }
92289
+ if (result.error) {
92290
+ return { accepted: false, reason: `spawn failed: ${result.error.message}` };
92291
+ }
92292
+ if (result.status !== 0) {
92293
+ const statusDescription = result.status !== null ? `exit ${result.status}` : `signal ${result.signal ?? "unknown"}`;
92294
+ return {
92295
+ accepted: false,
92296
+ reason: `glab --version returned ${statusDescription}`
92297
+ };
92298
+ }
92299
+ const versionOutput = (result.stdout ?? "").toString().trim();
92300
+ if (!GLAB_VERSION_PATTERN.test(versionOutput)) {
92301
+ const excerpt = excerptProbeOutput2(versionOutput);
92302
+ return {
92303
+ accepted: false,
92304
+ reason: excerpt ? `not glab: --version printed "${excerpt}"` : "not glab: --version printed nothing"
92305
+ };
92306
+ }
92307
+ return { accepted: true };
92308
+ }
92309
+ function probeCycle2(candidates, platform, attempts) {
92310
+ const start = _internals99.now();
92311
+ let budgetExceeded = false;
92312
+ for (const candidate2 of candidates) {
92313
+ if (_internals99.now() - start > TOTAL_BUDGET_MS3) {
92314
+ budgetExceeded = true;
92315
+ break;
92316
+ }
92317
+ const result = probeCandidate2(candidate2.path, platform);
92318
+ attempts.push({
92319
+ source: candidate2.source,
92320
+ candidate: candidate2.path,
92321
+ accepted: result.accepted,
92322
+ reason: result.accepted ? undefined : result.reason
92323
+ });
92324
+ if (candidate2.source === "override" && !result.accepted) {
92325
+ advisoryWarn(`[opencode-swarm] ${GLAB_BINARY_ENV_VAR} override "${candidate2.path}" is unusable (${result.reason}); falling back to automatic glab resolution.`);
92326
+ }
92327
+ if (result.accepted) {
92328
+ return { outcome: "accepted", path: candidate2.path };
92329
+ }
92330
+ }
92331
+ return budgetExceeded ? { outcome: "exhausted-budget" } : { outcome: "all-rejected" };
92332
+ }
92333
+ function readCache3() {
92334
+ if (cache3 === null)
92335
+ return null;
92336
+ if (cache3.kind === "success")
92337
+ return cache3;
92338
+ if (_internals99.now() < cache3.expiresAt)
92339
+ return cache3;
92340
+ cache3 = null;
92341
+ return null;
92342
+ }
92343
+ function applyProbeResult2(result, attempts, generation) {
92344
+ if (generation !== cacheGeneration2) {
92345
+ return result.outcome === "accepted" ? result.path : BARE_GLAB;
92346
+ }
92347
+ lastAttempts2 = attempts;
92348
+ if (result.outcome === "accepted") {
92349
+ cache3 = { kind: "success", path: result.path };
92350
+ return result.path;
92351
+ }
92352
+ cache3 = {
92353
+ kind: "fallback",
92354
+ expiresAt: _internals99.now() + NEGATIVE_CACHE_TTL_MS2
92355
+ };
92356
+ return BARE_GLAB;
92357
+ }
92358
+ function resolveGlabExecutable() {
92359
+ const cached = readCache3();
92360
+ if (cached)
92361
+ return cached.kind === "success" ? cached.path : BARE_GLAB;
92362
+ const platform = _internals99.platform();
92363
+ const attempts = [];
92364
+ const generation = cacheGeneration2;
92365
+ const candidates = buildCandidates2(platform);
92366
+ const result = probeCycle2(candidates, platform, attempts);
92367
+ return applyProbeResult2(result, attempts, generation);
92368
+ }
92369
+ var _internals99 = {
92370
+ spawnSync: spawnSync5,
92371
+ platform: () => process.platform,
92372
+ env: () => process.env,
92373
+ now: () => Date.now()
92374
+ };
92375
+
92376
+ // src/git/pr.ts
92109
92377
  init_logger();
92110
92378
 
92111
92379
  // src/utils/untrusted-markdown.ts
@@ -92141,7 +92409,7 @@ var EvidencePlanSchema = exports_external.object({
92141
92409
  }).passthrough()).optional()
92142
92410
  }).passthrough();
92143
92411
  function ghExec(args, cwd) {
92144
- const ghBinary = _internals99.resolveGhExecutable();
92412
+ const ghBinary = _internals100.resolveGhExecutable();
92145
92413
  for (let attempt = 0;attempt < MAX_TRANSIENT_RETRIES; attempt++) {
92146
92414
  const result = child_process5.spawnSync(ghBinary, args, {
92147
92415
  cwd,
@@ -92197,12 +92465,18 @@ function spawnSyncWithTransientRetry(command, args, options) {
92197
92465
  throw new Error(`${command} exited with null`);
92198
92466
  }
92199
92467
  async function ghExecAsync(args, cwd) {
92468
+ return _internals100.forgeExecAsync(_internals100.resolveGhExecutable(), args, cwd, "gh");
92469
+ }
92470
+ async function forgeExecAsyncImpl(binary, args, cwd, label, opts) {
92200
92471
  return new Promise((resolve40, reject) => {
92201
- const ghBinary = _internals99.resolveGhExecutable();
92202
- const proc = child_process5.spawn(ghBinary, args, {
92472
+ const spawnOptions = {
92203
92473
  cwd,
92204
92474
  stdio: ["ignore", "pipe", "pipe"]
92205
- });
92475
+ };
92476
+ if (opts?.env) {
92477
+ spawnOptions.env = mergeEnvForChild(undefined, opts.env);
92478
+ }
92479
+ const proc = child_process5.spawn(binary, args, spawnOptions);
92206
92480
  const stdoutChunks = [];
92207
92481
  const stderrChunks = [];
92208
92482
  let stdoutBytes = 0;
@@ -92226,7 +92500,7 @@ async function ghExecAsync(args, cwd) {
92226
92500
  proc.stdout?.on("data", (chunk) => {
92227
92501
  stdoutBytes += chunk.length;
92228
92502
  if (stdoutBytes > MAX_OUTPUT_BYTES2) {
92229
- settle2(() => reject(new Error(`gh ${args[0]} stdout exceeded ${MAX_OUTPUT_BYTES2} bytes`)));
92503
+ settle2(() => reject(new Error(`${label} ${args[0]} stdout exceeded ${MAX_OUTPUT_BYTES2} bytes`)));
92230
92504
  return;
92231
92505
  }
92232
92506
  stdoutChunks.push(chunk);
@@ -92234,13 +92508,13 @@ async function ghExecAsync(args, cwd) {
92234
92508
  proc.stderr?.on("data", (chunk) => {
92235
92509
  stderrBytes += chunk.length;
92236
92510
  if (stderrBytes > MAX_OUTPUT_BYTES2) {
92237
- settle2(() => reject(new Error(`gh ${args[0]} stderr exceeded ${MAX_OUTPUT_BYTES2} bytes`)));
92511
+ settle2(() => reject(new Error(`${label} ${args[0]} stderr exceeded ${MAX_OUTPUT_BYTES2} bytes`)));
92238
92512
  return;
92239
92513
  }
92240
92514
  stderrChunks.push(chunk);
92241
92515
  });
92242
92516
  const timer = setTimeout(() => {
92243
- settle2(() => reject(new Error(`gh ${args[0]} timed out after ${GIT_TIMEOUT_MS5}ms`)));
92517
+ settle2(() => reject(new Error(`${label} ${args[0]} timed out after ${GIT_TIMEOUT_MS5}ms`)));
92244
92518
  }, GIT_TIMEOUT_MS5);
92245
92519
  proc.on("error", (err) => {
92246
92520
  settle2(() => reject(err));
@@ -92249,7 +92523,7 @@ async function ghExecAsync(args, cwd) {
92249
92523
  settle2(() => {
92250
92524
  if (code !== 0) {
92251
92525
  const stderr = Buffer.concat(stderrChunks).toString("utf-8");
92252
- reject(new Error(stderr || `gh exited with ${code}`));
92526
+ reject(new Error(stderr || `${label} exited with ${code}`));
92253
92527
  } else {
92254
92528
  const stdout = Buffer.concat(stdoutChunks).toString("utf-8");
92255
92529
  resolve40(stdout);
@@ -92258,20 +92532,24 @@ async function ghExecAsync(args, cwd) {
92258
92532
  });
92259
92533
  });
92260
92534
  }
92261
- var _internals99 = {
92535
+ var _internals100 = {
92262
92536
  ghExec,
92263
92537
  ghExecAsync,
92538
+ forgeExecAsync: forgeExecAsyncImpl,
92539
+ getMRPollSnapshot,
92540
+ getMRComments,
92264
92541
  spawnSyncWithTransientRetry,
92265
92542
  spawnSync: __spawnSyncSeam.spawnSync,
92266
92543
  readLaneEnvFileFromDiskSync,
92267
92544
  getMergeGroupRun,
92268
92545
  resolveGhExecutable,
92269
- resolveGitExecutable
92546
+ resolveGitExecutable,
92547
+ resolveGlabExecutable
92270
92548
  };
92271
92549
  async function getPRPollSnapshot(prNumber, repoFullName, cwd) {
92272
92550
  let stdout;
92273
92551
  try {
92274
- stdout = await _internals99.ghExecAsync([
92552
+ stdout = await _internals100.ghExecAsync([
92275
92553
  "pr",
92276
92554
  "view",
92277
92555
  String(prNumber),
@@ -92328,7 +92606,7 @@ function numericIssueCommentId(url, fallbackId, fallbacks) {
92328
92606
  async function getPRReviewComments(prNumber, repoFullName, cwd) {
92329
92607
  let stdout;
92330
92608
  try {
92331
- stdout = await _internals99.ghExecAsync(["api", `repos/${repoFullName}/pulls/${prNumber}/comments`], cwd);
92609
+ stdout = await _internals100.ghExecAsync(["api", `repos/${repoFullName}/pulls/${prNumber}/comments`], cwd);
92332
92610
  } catch (err) {
92333
92611
  throw new Error(`Failed to fetch review comments for ${repoFullName}#${prNumber}: ${err instanceof Error ? err.message : String(err)}`);
92334
92612
  }
@@ -92341,6 +92619,129 @@ async function getPRReviewComments(prNumber, repoFullName, cwd) {
92341
92619
  isReviewComment: true
92342
92620
  }));
92343
92621
  }
92622
+ var MR_SYNTHESIZED_FIELD_MARKER = "NOT_AVAILABLE";
92623
+ function glabSpawnEnv(input) {
92624
+ if (!input.host || input.host === "gitlab.com")
92625
+ return;
92626
+ return { env: { GITLAB_HOST: input.host } };
92627
+ }
92628
+ function mapMrState(state) {
92629
+ if (state === "merged")
92630
+ return "MERGED";
92631
+ if (state === "closed")
92632
+ return "CLOSED";
92633
+ return "OPEN";
92634
+ }
92635
+ function mapMrMergeable(mr, detail) {
92636
+ if (mr.has_conflicts === true)
92637
+ return "CONFLICTING";
92638
+ if (mr.detailed_merge_status === "conflict")
92639
+ return "CONFLICTING";
92640
+ if (detail.merge_status === "cannot_be_merged")
92641
+ return "CONFLICTING";
92642
+ if (mr.detailed_merge_status === "mergeable")
92643
+ return "MERGEABLE";
92644
+ if (detail.merge_status === "can_be_merged")
92645
+ return "MERGEABLE";
92646
+ return "UNKNOWN";
92647
+ }
92648
+ function mapPipelineConclusion(status) {
92649
+ if (status === "success")
92650
+ return "success";
92651
+ if (status === "failed")
92652
+ return "failure";
92653
+ return null;
92654
+ }
92655
+ async function getMRPollSnapshot(input) {
92656
+ const overlay = glabSpawnEnv(input);
92657
+ const glabBinary = _internals100.resolveGlabExecutable();
92658
+ let viewStdout;
92659
+ try {
92660
+ viewStdout = await _internals100.forgeExecAsync(glabBinary, ["mr", "view", String(input.iid), "-R", input.projectPath, "-F", "json"], input.cwd, "glab", overlay);
92661
+ } catch (err) {
92662
+ throw new Error(`Failed to fetch MR view for ${input.projectPath}!${input.iid}: ${err instanceof Error ? err.message : String(err)}`);
92663
+ }
92664
+ const mr = JSON.parse(viewStdout);
92665
+ let detailStdout;
92666
+ try {
92667
+ detailStdout = await _internals100.forgeExecAsync(glabBinary, [
92668
+ "api",
92669
+ `projects/${encodeURIComponent(input.projectPath)}/merge_requests/${input.iid}`
92670
+ ], input.cwd, "glab", overlay);
92671
+ } catch (err) {
92672
+ throw new Error(`Failed to fetch MR detail for ${input.projectPath}!${input.iid}: ${err instanceof Error ? err.message : String(err)}`);
92673
+ }
92674
+ const detail = JSON.parse(detailStdout);
92675
+ let pipelines = [];
92676
+ let pipelinesFetchSucceeded = false;
92677
+ try {
92678
+ const pipelinesStdout = await _internals100.forgeExecAsync(glabBinary, [
92679
+ "api",
92680
+ `projects/${encodeURIComponent(input.projectPath)}/merge_requests/${input.iid}/pipelines?per_page=20`
92681
+ ], input.cwd, "glab", overlay);
92682
+ const rawPipelines = JSON.parse(pipelinesStdout);
92683
+ const headSha = typeof mr.sha === "string" ? mr.sha : "";
92684
+ const forHead = rawPipelines.filter((p) => typeof p.sha === "string" && p.sha === headSha).sort((a, b) => (Number(b.id) || 0) - (Number(a.id) || 0));
92685
+ const latest = forHead[0];
92686
+ const conclusion = mapPipelineConclusion(latest?.status);
92687
+ pipelines = latest && conclusion ? [
92688
+ {
92689
+ name: `pipeline #${String(latest.id ?? "")}`,
92690
+ status: "completed",
92691
+ conclusion,
92692
+ ...typeof latest.web_url === "string" ? { detailsUrl: latest.web_url } : {}
92693
+ }
92694
+ ] : [];
92695
+ pipelinesFetchSucceeded = true;
92696
+ } catch {
92697
+ pipelines = [];
92698
+ pipelinesFetchSucceeded = false;
92699
+ }
92700
+ const state = mapMrState(mr.state);
92701
+ const mergeable = mapMrMergeable(mr, detail);
92702
+ const reviewers = Array.isArray(mr.reviewers) ? mr.reviewers.length : 0;
92703
+ return {
92704
+ status: {
92705
+ number: input.iid,
92706
+ state,
92707
+ mergeable,
92708
+ mergeStateStatus: MR_SYNTHESIZED_FIELD_MARKER,
92709
+ headRefOid: typeof mr.sha === "string" ? mr.sha : "",
92710
+ statusCheckRollup: []
92711
+ },
92712
+ comments: [],
92713
+ merge: {
92714
+ mergeable,
92715
+ mergeStateStatus: MR_SYNTHESIZED_FIELD_MARKER,
92716
+ headRefOid: typeof mr.sha === "string" ? mr.sha : ""
92717
+ },
92718
+ review: {
92719
+ reviewDecision: "",
92720
+ reviewRequestCount: reviewers
92721
+ },
92722
+ pipelines,
92723
+ pipelinesFetchSucceeded
92724
+ };
92725
+ }
92726
+ async function getMRComments(input) {
92727
+ let stdout;
92728
+ try {
92729
+ stdout = await _internals100.forgeExecAsync(_internals100.resolveGlabExecutable(), [
92730
+ "api",
92731
+ `projects/${encodeURIComponent(input.projectPath)}/merge_requests/${input.iid}/notes?per_page=100&sort=asc&order_by=created_at`
92732
+ ], input.cwd, "glab", glabSpawnEnv(input));
92733
+ } catch (err) {
92734
+ throw new Error(`Failed to fetch MR comments for ${input.projectPath}!${input.iid}: ${err instanceof Error ? err.message : String(err)}`);
92735
+ }
92736
+ const notes = JSON.parse(stdout);
92737
+ return notes.filter((note) => note.system !== true).map((note) => ({
92738
+ id: String(note.id ?? ""),
92739
+ author: String(note.author?.username ?? ""),
92740
+ body: neutralizeUntrustedMarkdown(String(note.body ?? ""), "GitLab MR note"),
92741
+ createdAt: String(note.created_at ?? ""),
92742
+ isReviewComment: false
92743
+ }));
92744
+ }
92344
92745
  async function getMergeGroupRun(statusCheckRollup, repoFullName, cwd) {
92345
92746
  const mergeGroupCheck = statusCheckRollup.find((check) => check.name === "Merge pull request" && check.detailsUrl);
92346
92747
  if (!mergeGroupCheck?.detailsUrl) {
@@ -92353,7 +92754,7 @@ async function getMergeGroupRun(statusCheckRollup, repoFullName, cwd) {
92353
92754
  const runId = runIdMatch[1];
92354
92755
  let stdout;
92355
92756
  try {
92356
- stdout = await _internals99.ghExecAsync([
92757
+ stdout = await _internals100.ghExecAsync([
92357
92758
  "run",
92358
92759
  "view",
92359
92760
  runId,
@@ -92382,7 +92783,7 @@ var registrationsByCanonical = new Map;
92382
92783
  function resolveRegistration(directory) {
92383
92784
  const lexical = canonicalRootKeyLexical(directory);
92384
92785
  try {
92385
- const freshKey = _internals100.canonicalRootKeyFresh(directory);
92786
+ const freshKey = _internals101.canonicalRootKeyFresh(directory);
92386
92787
  const canonical = registrationsByCanonical.get(freshKey);
92387
92788
  if (canonical)
92388
92789
  return canonical;
@@ -92404,8 +92805,10 @@ async function evaluatePrFeedbackCurrentHead(directory, repoFullName, prNumber)
92404
92805
  async function dispatchPrFeedbackOversight(input) {
92405
92806
  return await getPrFeedbackLoopRuntime(input.directory)?.dispatchOversight(input) ?? { dispatched: false, verdict: "unavailable", decision: "pending" };
92406
92807
  }
92407
- var _internals100 = {
92808
+ var _internals101 = {
92408
92809
  getPRPollSnapshot,
92810
+ getMRPollSnapshot,
92811
+ findSubscriptionRecordForPrUrl,
92409
92812
  dispatchEphemeralAgent,
92410
92813
  parseCriticResponseFields,
92411
92814
  canonicalRootKeyFresh,
@@ -92414,11 +92817,11 @@ var _internals100 = {
92414
92817
  };
92415
92818
 
92416
92819
  // src/background/pr-feedback-loop.ts
92417
- var PR_FEEDBACK_LOOP_STATE_REL = path127.join(".swarm", "pr-feedback-loop-state.json");
92820
+ var PR_FEEDBACK_LOOP_STATE_REL = path128.join(".swarm", "pr-feedback-loop-state.json");
92418
92821
  var PR_FEEDBACK_CLEANUP_DIR = "pr-feedback-loop-cleanups";
92419
- var PR_FEEDBACK_EVIDENCE_DIR = path127.join(".swarm", "pr-feedback-evidence");
92822
+ var PR_FEEDBACK_EVIDENCE_DIR = path128.join(".swarm", "pr-feedback-evidence");
92420
92823
  var PR_FEEDBACK_LOOP_STATE_LOCK_FILENAME = "pr-feedback-loop-state.lock";
92421
- var PR_FEEDBACK_LOOP_STATE_LOCK_REL = path127.join(".swarm", PR_FEEDBACK_LOOP_STATE_LOCK_FILENAME);
92824
+ var PR_FEEDBACK_LOOP_STATE_LOCK_REL = path128.join(".swarm", PR_FEEDBACK_LOOP_STATE_LOCK_FILENAME);
92422
92825
  var MAX_TRACKED_SESSIONS5 = 200;
92423
92826
  var MAX_IN_FLIGHT_SESSIONS = 64;
92424
92827
  var MAX_CANCELLATION_REQUESTS = 64;
@@ -92434,7 +92837,7 @@ var LoopStateSchema = exports_external.object({
92434
92837
  correlations: exports_external.record(exports_external.string(), exports_external.any()),
92435
92838
  sessionTerminals: exports_external.record(exports_external.string(), exports_external.any()).default({})
92436
92839
  });
92437
- var _internals101 = {
92840
+ var _internals102 = {
92438
92841
  async evaluateCurrentHead(directory, repoFullName, prNumber) {
92439
92842
  return evaluatePrFeedbackCurrentHead(directory, repoFullName, prNumber);
92440
92843
  },
@@ -92443,13 +92846,20 @@ var _internals101 = {
92443
92846
  },
92444
92847
  async performAuthorizedAction(input) {
92445
92848
  try {
92849
+ const subscription = await findSubscriptionRecordForPrUrl(input.directory, {
92850
+ prUrl: input.event.prUrl,
92851
+ repoFullName: input.event.repoFullName,
92852
+ prNumber: input.event.prNumber,
92853
+ sessionID: input.sessionID
92854
+ });
92446
92855
  await activatePrWorkflow(input.directory, input.sessionID, "PR_FEEDBACK", {
92447
92856
  requireCheckoutPreflight: true,
92448
- prUrl: input.event.prUrl
92857
+ prUrl: input.event.prUrl,
92858
+ forge: subscription?.forge
92449
92859
  });
92450
92860
  return {
92451
92861
  performed: true,
92452
- recordPath: path127.join(".swarm", "pr-feedback-loop-state.json")
92862
+ recordPath: path128.join(".swarm", "pr-feedback-loop-state.json")
92453
92863
  };
92454
92864
  } catch (err) {
92455
92865
  const message = err instanceof Error ? err.message : String(err);
@@ -92471,13 +92881,13 @@ var _internals101 = {
92471
92881
  listActive,
92472
92882
  isProcessAlive: isProcessAlive3,
92473
92883
  resetLoopStateLock() {
92474
- _internals101.beforeLoopStateLockWrite = undefined;
92884
+ _internals102.beforeLoopStateLockWrite = undefined;
92475
92885
  },
92476
92886
  loopStateLockRelativePath: () => PR_FEEDBACK_LOOP_STATE_LOCK_REL,
92477
92887
  reclaimAbandonedLoopStateLock,
92478
92888
  removeLoopStateLockIfOwned
92479
92889
  };
92480
- var defaultLoopInternals = { ..._internals101 };
92890
+ var defaultLoopInternals = { ..._internals102 };
92481
92891
  function emptyState2() {
92482
92892
  return {
92483
92893
  schemaVersion: 1,
@@ -92553,7 +92963,7 @@ function hasReservationIdentity(reservation) {
92553
92963
  return Boolean(reservation?.workflowInstanceId.trim() && Number.isInteger(reservation?.ownerPid) && (reservation?.ownerPid ?? 0) > 0);
92554
92964
  }
92555
92965
  async function readLoopState(directory) {
92556
- const file = path127.join(directory, PR_FEEDBACK_LOOP_STATE_REL);
92966
+ const file = path128.join(directory, PR_FEEDBACK_LOOP_STATE_REL);
92557
92967
  try {
92558
92968
  const raw = fsSync9.readFileSync(file, "utf-8");
92559
92969
  const parsed = LoopStateSchema.safeParse(JSON.parse(raw));
@@ -92584,7 +92994,7 @@ async function writeLoopState(directory, state) {
92584
92994
  }
92585
92995
  }
92586
92996
  state.updatedAt = new Date().toISOString();
92587
- await writePrWorkflowAtomicJson(directory, validateSwarmPath(directory, path127.basename(PR_FEEDBACK_LOOP_STATE_REL)), state);
92997
+ await writePrWorkflowAtomicJson(directory, validateSwarmPath(directory, path128.basename(PR_FEEDBACK_LOOP_STATE_REL)), state);
92588
92998
  }
92589
92999
  async function withLoopStateLock(directory, fn) {
92590
93000
  const lock = await acquireLoopStateLock(directory);
@@ -92599,21 +93009,21 @@ async function acquireLoopStateLock(directory) {
92599
93009
  const verifiedStateDirectory = await ensurePrWorkflowSafeParentDirectory(directory, lockPath);
92600
93010
  for (let attempt = 0;attempt < LOOP_STATE_LOCK_MAX_ATTEMPTS; attempt++) {
92601
93011
  try {
92602
- const handle = await fs63.open(lockPath, "wx");
93012
+ const handle = await fs64.open(lockPath, "wx");
92603
93013
  const lock = {
92604
93014
  ownerToken: randomUUID22(),
92605
93015
  pid: process.pid,
92606
- createdAtMs: _internals101.now()
93016
+ createdAtMs: _internals102.now()
92607
93017
  };
92608
93018
  let writeError;
92609
93019
  try {
92610
- await _internals101.beforeLoopStateLockWrite?.();
93020
+ await _internals102.beforeLoopStateLockWrite?.();
92611
93021
  const [openedStat, pathStat, realLockPath] = await Promise.all([
92612
93022
  handle.stat({ bigint: true }),
92613
- fs63.lstat(lockPath, { bigint: true }),
92614
- fs63.realpath(lockPath)
93023
+ fs64.lstat(lockPath, { bigint: true }),
93024
+ fs64.realpath(lockPath)
92615
93025
  ]);
92616
- if (!openedStat.isFile() || pathStat.isSymbolicLink() || !pathStat.isFile() || !sameFileIdentity4(openedStat, pathStat) || normalizeComparablePath2(path127.dirname(realLockPath)) !== normalizeComparablePath2(verifiedStateDirectory)) {
93026
+ if (!openedStat.isFile() || pathStat.isSymbolicLink() || !pathStat.isFile() || !sameFileIdentity4(openedStat, pathStat) || normalizeComparablePath2(path128.dirname(realLockPath)) !== normalizeComparablePath2(verifiedStateDirectory)) {
92617
93027
  throw new Error("BLOCKED: PR feedback loop state lock changed or escaped before initialization");
92618
93028
  }
92619
93029
  await handle.writeFile(JSON.stringify(lock), "utf8");
@@ -92654,17 +93064,17 @@ async function reclaimAbandonedLoopStateLock(lockPath) {
92654
93064
  lock = null;
92655
93065
  }
92656
93066
  if (lock) {
92657
- if (_internals101.isProcessAlive(lock.pid) && _internals101.now() - lock.createdAtMs < LOOP_STATE_LOCK_ALIVE_OWNER_STALE_MS) {
93067
+ if (_internals102.isProcessAlive(lock.pid) && _internals102.now() - lock.createdAtMs < LOOP_STATE_LOCK_ALIVE_OWNER_STALE_MS) {
92658
93068
  return false;
92659
93069
  }
92660
93070
  return removeLoopStateLockIfOwned(lockPath, lock.ownerToken);
92661
93071
  }
92662
93072
  try {
92663
- const stat14 = await fs63.stat(lockPath);
92664
- if (_internals101.now() - stat14.mtimeMs < LOOP_STATE_LOCK_UNINITIALIZED_STALE_MS) {
93073
+ const stat14 = await fs64.stat(lockPath);
93074
+ if (_internals102.now() - stat14.mtimeMs < LOOP_STATE_LOCK_UNINITIALIZED_STALE_MS) {
92665
93075
  return false;
92666
93076
  }
92667
- await fs63.rm(lockPath, { force: true });
93077
+ await fs64.rm(lockPath, { force: true });
92668
93078
  return true;
92669
93079
  } catch (error2) {
92670
93080
  if (error2.code === "ENOENT")
@@ -92675,7 +93085,7 @@ async function reclaimAbandonedLoopStateLock(lockPath) {
92675
93085
  async function readLoopStateLock(lockPath) {
92676
93086
  let raw;
92677
93087
  try {
92678
- raw = await fs63.readFile(lockPath, "utf8");
93088
+ raw = await fs64.readFile(lockPath, "utf8");
92679
93089
  } catch (error2) {
92680
93090
  if (error2.code === "ENOENT")
92681
93091
  return null;
@@ -92699,7 +93109,7 @@ async function removeLoopStateLockIfOwned(lockPath, ownerToken) {
92699
93109
  if (!lock || lock.ownerToken !== ownerToken)
92700
93110
  return false;
92701
93111
  try {
92702
- await fs63.rm(lockPath);
93112
+ await fs64.rm(lockPath);
92703
93113
  return true;
92704
93114
  } catch {
92705
93115
  return false;
@@ -92717,7 +93127,7 @@ function sameFileIdentity4(left, right) {
92717
93127
  return left.dev === right.dev && left.ino === right.ino;
92718
93128
  }
92719
93129
  function normalizeComparablePath2(value) {
92720
- const normalized = path127.normalize(path127.resolve(value));
93130
+ const normalized = path128.normalize(path128.resolve(value));
92721
93131
  return process.platform === "win32" ? normalized.toLowerCase() : normalized;
92722
93132
  }
92723
93133
  function delay3(ms) {
@@ -92821,14 +93231,14 @@ async function cancelPrFeedbackLoopUnlocked(directory, sessionID, reason) {
92821
93231
  clearedEvents: []
92822
93232
  };
92823
93233
  try {
92824
- const { cancelPrFeedbackPublication: cancelPrFeedbackPublication2 } = await import("./pr-workflow-gate-gpq41zx9.js");
93234
+ const { cancelPrFeedbackPublication: cancelPrFeedbackPublication2 } = await import("./pr-workflow-gate-tdj50p2g.js");
92825
93235
  await cancelPrFeedbackPublication2(directory, sessionID, reason);
92826
93236
  } catch (err) {
92827
93237
  warn(`[pr-feedback-loop] cancelPrFeedbackPublication failed (fail-open): ${err instanceof Error ? err.message : String(err)}`);
92828
93238
  }
92829
93239
  try {
92830
93240
  await withLoopStateLock(directory, async () => {
92831
- const readResult = await _internals101.readState(directory);
93241
+ const readResult = await _internals102.readState(directory);
92832
93242
  if (isCorruptState(readResult)) {
92833
93243
  throw new Error("BLOCKED: loop state is corrupt during durable cancellation admission");
92834
93244
  }
@@ -92841,7 +93251,7 @@ async function cancelPrFeedbackLoopUnlocked(directory, sessionID, reason) {
92841
93251
  correlation.terminal = { state: "cancelled", reason };
92842
93252
  }
92843
93253
  const inFlight = correlation.inFlight;
92844
- const ownerAlive = inFlight && hasReservationIdentity(inFlight) ? _internals101.isProcessAlive(inFlight.ownerPid) : false;
93254
+ const ownerAlive = inFlight && hasReservationIdentity(inFlight) ? _internals102.isProcessAlive(inFlight.ownerPid) : false;
92845
93255
  const reclaimedReservation = Boolean(inFlight && (inFlight.actionStartedAt === undefined || !ownerAlive));
92846
93256
  if (reclaimedReservation) {
92847
93257
  correlation.inFlight = null;
@@ -92856,7 +93266,7 @@ async function cancelPrFeedbackLoopUnlocked(directory, sessionID, reason) {
92856
93266
  reason
92857
93267
  };
92858
93268
  }
92859
- await _internals101.writeState(directory, nextState);
93269
+ await _internals102.writeState(directory, nextState);
92860
93270
  return nextState;
92861
93271
  });
92862
93272
  } catch (err) {
@@ -92877,12 +93287,12 @@ async function cancelPrFeedbackLoopUnlocked(directory, sessionID, reason) {
92877
93287
  }
92878
93288
  }
92879
93289
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
92880
- receipt.path = path127.join(".swarm", PR_FEEDBACK_CLEANUP_DIR, `cancel-${stamp}.json`);
93290
+ receipt.path = path128.join(".swarm", PR_FEEDBACK_CLEANUP_DIR, `cancel-${stamp}.json`);
92881
93291
  try {
92882
- fsSync9.mkdirSync(path127.join(directory, ".swarm", PR_FEEDBACK_CLEANUP_DIR), {
93292
+ fsSync9.mkdirSync(path128.join(directory, ".swarm", PR_FEEDBACK_CLEANUP_DIR), {
92883
93293
  recursive: true
92884
93294
  });
92885
- fsSync9.writeFileSync(path127.join(directory, receipt.path), JSON.stringify({
93295
+ fsSync9.writeFileSync(path128.join(directory, receipt.path), JSON.stringify({
92886
93296
  schemaVersion: 1,
92887
93297
  at: new Date().toISOString(),
92888
93298
  sessionID,
@@ -92934,228 +93344,6 @@ ${USAGE14}`;
92934
93344
 
92935
93345
  // src/background/pr-monitor-worker.ts
92936
93346
  init_warning_buffer();
92937
-
92938
- // src/utils/glab-executable.ts
92939
- init_warning_buffer();
92940
- import { spawnSync as spawnSync6 } from "child_process";
92941
- import * as fs64 from "fs";
92942
- import * as os14 from "os";
92943
- import * as path128 from "path";
92944
- var GLAB_BINARY_ENV_VAR = "OPENCODE_SWARM_GLAB_BINARY";
92945
- var PER_PROBE_TIMEOUT_MS2 = 250;
92946
- var TOTAL_BUDGET_MS3 = 1000;
92947
- var NEGATIVE_CACHE_TTL_MS2 = 60000;
92948
- var BARE_GLAB = "glab";
92949
- var PROBE_MAX_BUFFER_BYTES2 = 64 * 1024;
92950
- var PROBE_OUTPUT_EXCERPT_CHARS2 = 60;
92951
- var WINDOWS_PATH_EXTENSIONS2 = [".exe", ".cmd", ".bat"];
92952
- var GLAB_VERSION_PATTERN = /^glab version \d+\.\d+/;
92953
- function excerptProbeOutput2(raw) {
92954
- return raw.slice(0, PROBE_OUTPUT_EXCERPT_CHARS2).replace(/[^\x20-\x7E]/g, " ").trim();
92955
- }
92956
- var cache3 = null;
92957
- var lastAttempts2 = [];
92958
- var cacheGeneration2 = 0;
92959
- function windowsGlabAbsoluteCandidates(env) {
92960
- const candidates = [];
92961
- const push = (...parts) => {
92962
- const candidate2 = path128.join(...parts);
92963
- if (!candidates.includes(candidate2))
92964
- candidates.push(candidate2);
92965
- };
92966
- if (env.ProgramFiles) {
92967
- push(env.ProgramFiles, "GitLab CLI", "glab.exe");
92968
- }
92969
- if (env["ProgramFiles(x86)"]) {
92970
- push(env["ProgramFiles(x86)"], "GitLab CLI", "glab.exe");
92971
- }
92972
- if (env.LOCALAPPDATA) {
92973
- push(env.LOCALAPPDATA, "GitLab CLI", "glab.exe");
92974
- push(env.LOCALAPPDATA, "Programs", "GitLab CLI", "glab.exe");
92975
- }
92976
- return candidates;
92977
- }
92978
- function platformCandidates2(platform, env) {
92979
- if (platform === "win32") {
92980
- return windowsGlabAbsoluteCandidates(env);
92981
- }
92982
- if (platform === "darwin") {
92983
- return ["/opt/homebrew/bin/glab", "/usr/local/bin/glab", "/usr/bin/glab"];
92984
- }
92985
- return ["/usr/bin/glab", "/usr/local/bin/glab", "/bin/glab"];
92986
- }
92987
- function isAbsoluteForPlatform2(candidate2, platform) {
92988
- return platform === "win32" ? path128.win32.isAbsolute(candidate2) : path128.posix.isAbsolute(candidate2);
92989
- }
92990
- function joinDirAndName2(dir, name, platform) {
92991
- const sep22 = platform === "win32" ? "\\" : "/";
92992
- const trimmed = dir.replace(/[\\/]+$/, "");
92993
- return trimmed ? `${trimmed}${sep22}${name}` : `${sep22}${name}`;
92994
- }
92995
- function pathCandidates2(platform) {
92996
- const pathValue = _internals102.env().PATH ?? "";
92997
- if (!pathValue)
92998
- return [];
92999
- const dirs = pathValue.split(platform === "win32" ? ";" : ":").filter(Boolean);
93000
- const names = platform === "win32" ? [...WINDOWS_PATH_EXTENSIONS2.map((ext) => `glab${ext}`), "glab"] : ["glab"];
93001
- const out = [];
93002
- for (const dir of dirs) {
93003
- for (const name of names) {
93004
- const candidate2 = joinDirAndName2(dir, name, platform);
93005
- if (!out.includes(candidate2))
93006
- out.push(candidate2);
93007
- }
93008
- }
93009
- return out;
93010
- }
93011
- function envOverride2() {
93012
- const raw = _internals102.env()[GLAB_BINARY_ENV_VAR];
93013
- return raw && raw.trim() !== "" ? raw : undefined;
93014
- }
93015
- function buildCandidates2(platform) {
93016
- const override = envOverride2();
93017
- const overrideCandidate = override ? [{ source: "override", path: override }] : [];
93018
- const seen = new Set(overrideCandidate.map((c) => c.path));
93019
- const rest = [];
93020
- for (const p of platformCandidates2(platform, _internals102.env())) {
93021
- if (seen.has(p))
93022
- continue;
93023
- seen.add(p);
93024
- rest.push({ source: "platform", path: p });
93025
- }
93026
- for (const p of pathCandidates2(platform)) {
93027
- if (seen.has(p))
93028
- continue;
93029
- seen.add(p);
93030
- rest.push({ source: "path", path: p });
93031
- }
93032
- return [...overrideCandidate, ...rest];
93033
- }
93034
- function probeCandidate2(candidatePath2, platform) {
93035
- if (!isAbsoluteForPlatform2(candidatePath2, platform)) {
93036
- return { accepted: false, reason: "not an absolute path" };
93037
- }
93038
- let stat14;
93039
- try {
93040
- stat14 = fs64.statSync(candidatePath2);
93041
- } catch (err) {
93042
- const code = err?.code;
93043
- if (code === "ENOENT")
93044
- return { accepted: false, reason: "no such file" };
93045
- return {
93046
- accepted: false,
93047
- reason: `cannot stat (${code ?? "unknown error"})`
93048
- };
93049
- }
93050
- if (stat14.isDirectory()) {
93051
- return { accepted: false, reason: "is a directory" };
93052
- }
93053
- if (!stat14.isFile()) {
93054
- return { accepted: false, reason: "not a regular file" };
93055
- }
93056
- let result;
93057
- try {
93058
- result = _internals102.spawnSync(candidatePath2, ["--version"], {
93059
- cwd: os14.tmpdir(),
93060
- stdio: ["ignore", "pipe", "ignore"],
93061
- windowsHide: true,
93062
- timeout: PER_PROBE_TIMEOUT_MS2,
93063
- maxBuffer: PROBE_MAX_BUFFER_BYTES2
93064
- });
93065
- } catch (err) {
93066
- return {
93067
- accepted: false,
93068
- reason: `spawn threw: ${err instanceof Error ? err.message : String(err)}`
93069
- };
93070
- }
93071
- if (result.error) {
93072
- return { accepted: false, reason: `spawn failed: ${result.error.message}` };
93073
- }
93074
- if (result.status !== 0) {
93075
- const statusDescription = result.status !== null ? `exit ${result.status}` : `signal ${result.signal ?? "unknown"}`;
93076
- return {
93077
- accepted: false,
93078
- reason: `glab --version returned ${statusDescription}`
93079
- };
93080
- }
93081
- const versionOutput = (result.stdout ?? "").toString().trim();
93082
- if (!GLAB_VERSION_PATTERN.test(versionOutput)) {
93083
- const excerpt = excerptProbeOutput2(versionOutput);
93084
- return {
93085
- accepted: false,
93086
- reason: excerpt ? `not glab: --version printed "${excerpt}"` : "not glab: --version printed nothing"
93087
- };
93088
- }
93089
- return { accepted: true };
93090
- }
93091
- function probeCycle2(candidates, platform, attempts) {
93092
- const start = _internals102.now();
93093
- let budgetExceeded = false;
93094
- for (const candidate2 of candidates) {
93095
- if (_internals102.now() - start > TOTAL_BUDGET_MS3) {
93096
- budgetExceeded = true;
93097
- break;
93098
- }
93099
- const result = probeCandidate2(candidate2.path, platform);
93100
- attempts.push({
93101
- source: candidate2.source,
93102
- candidate: candidate2.path,
93103
- accepted: result.accepted,
93104
- reason: result.accepted ? undefined : result.reason
93105
- });
93106
- if (candidate2.source === "override" && !result.accepted) {
93107
- advisoryWarn(`[opencode-swarm] ${GLAB_BINARY_ENV_VAR} override "${candidate2.path}" is unusable (${result.reason}); falling back to automatic glab resolution.`);
93108
- }
93109
- if (result.accepted) {
93110
- return { outcome: "accepted", path: candidate2.path };
93111
- }
93112
- }
93113
- return budgetExceeded ? { outcome: "exhausted-budget" } : { outcome: "all-rejected" };
93114
- }
93115
- function readCache3() {
93116
- if (cache3 === null)
93117
- return null;
93118
- if (cache3.kind === "success")
93119
- return cache3;
93120
- if (_internals102.now() < cache3.expiresAt)
93121
- return cache3;
93122
- cache3 = null;
93123
- return null;
93124
- }
93125
- function applyProbeResult2(result, attempts, generation) {
93126
- if (generation !== cacheGeneration2) {
93127
- return result.outcome === "accepted" ? result.path : BARE_GLAB;
93128
- }
93129
- lastAttempts2 = attempts;
93130
- if (result.outcome === "accepted") {
93131
- cache3 = { kind: "success", path: result.path };
93132
- return result.path;
93133
- }
93134
- cache3 = {
93135
- kind: "fallback",
93136
- expiresAt: _internals102.now() + NEGATIVE_CACHE_TTL_MS2
93137
- };
93138
- return BARE_GLAB;
93139
- }
93140
- function resolveGlabExecutable() {
93141
- const cached = readCache3();
93142
- if (cached)
93143
- return cached.kind === "success" ? cached.path : BARE_GLAB;
93144
- const platform = _internals102.platform();
93145
- const attempts = [];
93146
- const generation = cacheGeneration2;
93147
- const candidates = buildCandidates2(platform);
93148
- const result = probeCycle2(candidates, platform, attempts);
93149
- return applyProbeResult2(result, attempts, generation);
93150
- }
93151
- var _internals102 = {
93152
- spawnSync: spawnSync6,
93153
- platform: () => process.platform,
93154
- env: () => process.env,
93155
- now: () => Date.now()
93156
- };
93157
-
93158
- // src/background/pr-monitor-worker.ts
93159
93347
  var prMonitorWorkerRegistry = new Map;
93160
93348
  function getPrMonitorWorkerHealth(directory) {
93161
93349
  return prMonitorWorkerRegistry.get(directory)?.getHealth() ?? null;
@@ -93365,12 +93553,7 @@ class PrMonitorWorker {
93365
93553
  async pollSinglePr(sub, isTimedOut, isProbe = false) {
93366
93554
  const correlationId = sub.correlationId;
93367
93555
  const forgeContext = detectForgeFromUrl(sub.prUrl) ?? (sub.forge ? { provider: sub.forge.provider, host: sub.forge.host } : null);
93368
- if (forgeContext && !getProviderCapabilities(forgeContext.provider).statusCheckRollup && !getProviderCapabilities(forgeContext.provider).reviewDecision && !getProviderCapabilities(forgeContext.provider).mergeStateStatus) {
93369
- const glabBinary = resolveGlabExecutable();
93370
- const glabStatus = glabBinary === "glab" ? "glab binary not resolved (bare-name fallback)" : "glab binary resolved";
93371
- log("[PrMonitorWorker] GitLab MR monitoring unavailable: glab-backed polling is not wired yet (issue #2882); skipping gh poll for this subscription", { correlationId, glabStatus });
93372
- return;
93373
- }
93556
+ const isGitLab = forgeContext?.provider === "gitlab";
93374
93557
  if (!this.circuitBreakerMap.has(correlationId) && sub.errorCount > 0) {
93375
93558
  this.circuitBreakerMap.set(correlationId, {
93376
93559
  errorCount: sub.errorCount,
@@ -93395,40 +93578,76 @@ class PrMonitorWorker {
93395
93578
  return;
93396
93579
  }
93397
93580
  try {
93398
- const [snapshot, reviewComments] = await Promise.all([
93399
- _internals103.getPRPollSnapshot(sub.prNumber, sub.repoFullName, this.directory),
93400
- _internals103.getPRReviewComments(sub.prNumber, sub.repoFullName, this.directory)
93401
- ]);
93402
- if (isTimedOut?.()) {
93403
- log("[PrMonitorWorker] Skipping late result \u2014 poll already timed out", {
93404
- correlationId: sub.correlationId
93581
+ let changes;
93582
+ if (isGitLab) {
93583
+ const glabBinary = resolveGlabExecutable();
93584
+ const glabStatus = glabBinary === "glab" ? "glab binary not resolved (bare-name fallback)" : "glab binary resolved";
93585
+ log("[PrMonitorWorker] Polling GitLab MR (glab-backed)", {
93586
+ correlationId,
93587
+ glabStatus
93405
93588
  });
93406
- return;
93407
- }
93408
- let mergeGroupRunResult = null;
93409
- let mergeGroupRunFetchSucceeded = false;
93410
- try {
93411
- mergeGroupRunResult = await _internals103.getMergeGroupRun(snapshot.status.statusCheckRollup, sub.repoFullName, this.directory);
93412
- mergeGroupRunFetchSucceeded = true;
93413
- } catch (err) {
93414
- log("[PrMonitorWorker] Failed to fetch merge group run", {
93415
- correlationId: sub.correlationId,
93416
- error: err instanceof Error ? err.message : String(err)
93417
- });
93418
- }
93419
- if (isTimedOut?.()) {
93420
- log("[PrMonitorWorker] Skipping late result \u2014 poll already timed out", {
93421
- correlationId: sub.correlationId
93589
+ const mrInput = {
93590
+ projectPath: sub.repoFullName,
93591
+ iid: sub.prNumber,
93592
+ cwd: this.directory,
93593
+ ...forgeContext ? { host: forgeContext.host } : {}
93594
+ };
93595
+ const [mrSnapshot, mrComments] = await Promise.all([
93596
+ _internals103.getMRPollSnapshot(mrInput),
93597
+ _internals103.getMRComments(mrInput)
93598
+ ]);
93599
+ if (isTimedOut?.()) {
93600
+ log("[PrMonitorWorker] Skipping late result \u2014 poll already timed out", {
93601
+ correlationId: sub.correlationId
93602
+ });
93603
+ return;
93604
+ }
93605
+ changes = this.computeChanges(sub, {
93606
+ status: mrSnapshot.status,
93607
+ comments: mrComments,
93608
+ merge: mrSnapshot.merge,
93609
+ review: mrSnapshot.review,
93610
+ mergeGroupRun: null
93611
+ }, true, {
93612
+ checks: mrSnapshot.pipelines,
93613
+ fetchSucceeded: mrSnapshot.pipelinesFetchSucceeded
93422
93614
  });
93423
- return;
93615
+ } else {
93616
+ const [snapshot, reviewComments] = await Promise.all([
93617
+ _internals103.getPRPollSnapshot(sub.prNumber, sub.repoFullName, this.directory),
93618
+ _internals103.getPRReviewComments(sub.prNumber, sub.repoFullName, this.directory)
93619
+ ]);
93620
+ if (isTimedOut?.()) {
93621
+ log("[PrMonitorWorker] Skipping late result \u2014 poll already timed out", {
93622
+ correlationId: sub.correlationId
93623
+ });
93624
+ return;
93625
+ }
93626
+ let mergeGroupRunResult = null;
93627
+ let mergeGroupRunFetchSucceeded = false;
93628
+ try {
93629
+ mergeGroupRunResult = await _internals103.getMergeGroupRun(snapshot.status.statusCheckRollup, sub.repoFullName, this.directory);
93630
+ mergeGroupRunFetchSucceeded = true;
93631
+ } catch (err) {
93632
+ log("[PrMonitorWorker] Failed to fetch merge group run", {
93633
+ correlationId: sub.correlationId,
93634
+ error: err instanceof Error ? err.message : String(err)
93635
+ });
93636
+ }
93637
+ if (isTimedOut?.()) {
93638
+ log("[PrMonitorWorker] Skipping late result \u2014 poll already timed out", {
93639
+ correlationId: sub.correlationId
93640
+ });
93641
+ return;
93642
+ }
93643
+ changes = this.computeChanges(sub, {
93644
+ status: snapshot.status,
93645
+ comments: [...snapshot.comments, ...reviewComments],
93646
+ merge: snapshot.merge,
93647
+ review: snapshot.review,
93648
+ mergeGroupRun: mergeGroupRunResult
93649
+ }, mergeGroupRunFetchSucceeded);
93424
93650
  }
93425
- const changes = this.computeChanges(sub, {
93426
- status: snapshot.status,
93427
- comments: [...snapshot.comments, ...reviewComments],
93428
- merge: snapshot.merge,
93429
- review: snapshot.review,
93430
- mergeGroupRun: mergeGroupRunResult
93431
- }, mergeGroupRunFetchSucceeded);
93432
93651
  await this.applyChanges(sub, changes, isTimedOut);
93433
93652
  if (!isTimedOut?.()) {
93434
93653
  this.circuitBreakerMap.delete(correlationId);
@@ -93464,7 +93683,7 @@ class PrMonitorWorker {
93464
93683
  await this.handlePollError(sub, err instanceof Error ? err : new Error(String(err)));
93465
93684
  }
93466
93685
  }
93467
- computeChanges(sub, current, mergeGroupRunFetchSucceeded) {
93686
+ computeChanges(sub, current, mergeGroupRunFetchSucceeded, gitLabPipelines) {
93468
93687
  const events = [];
93469
93688
  const snapshotUpdates = {
93470
93689
  headRefOid: current.status.headRefOid,
@@ -93491,13 +93710,17 @@ class PrMonitorWorker {
93491
93710
  }
93492
93711
  });
93493
93712
  }
93494
- const currentCheckSet = this.serializeChecks(current.status.statusCheckRollup);
93495
- snapshotUpdates.lastCheckRunSet = currentCheckSet;
93496
- if (sub.lastCheckRunSet !== undefined && currentCheckSet !== sub.lastCheckRunSet) {
93497
- const prevChecks = this.parseCheckSet(sub.lastCheckRunSet);
93498
- this.computeCIEvents(sub, prevChecks, current.status.statusCheckRollup, current.status.headRefOid, events);
93713
+ const ciChecks = gitLabPipelines ? gitLabPipelines.checks : current.status.statusCheckRollup;
93714
+ const gitlabNoTerminalVerdict = gitLabPipelines !== undefined && gitLabPipelines.checks.length === 0;
93715
+ if (!gitlabNoTerminalVerdict && (!gitLabPipelines || gitLabPipelines.fetchSucceeded)) {
93716
+ const currentCheckSet = this.serializeChecks(ciChecks);
93717
+ snapshotUpdates.lastCheckRunSet = currentCheckSet;
93718
+ if (sub.lastCheckRunSet !== undefined && currentCheckSet !== sub.lastCheckRunSet) {
93719
+ const prevChecks = this.parseCheckSet(sub.lastCheckRunSet);
93720
+ this.computeCIEvents(sub, prevChecks, ciChecks, current.status.headRefOid, events);
93721
+ }
93722
+ snapshotUpdates.lastCheckRunSet = currentCheckSet;
93499
93723
  }
93500
- snapshotUpdates.lastCheckRunSet = currentCheckSet;
93501
93724
  if (current.comments.length > 0) {
93502
93725
  const sorted2 = [...current.comments].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
93503
93726
  let newComments;
@@ -93829,6 +94052,8 @@ class PrMonitorWorker {
93829
94052
  var _internals103 = {
93830
94053
  getPRPollSnapshot,
93831
94054
  getPRReviewComments,
94055
+ getMRPollSnapshot,
94056
+ getMRComments,
93832
94057
  getMergeGroupRun,
93833
94058
  listActive,
93834
94059
  updateSnapshot,
@@ -94192,11 +94417,10 @@ async function handlePrSubscribeCommand(directory, args, sessionID) {
94192
94417
  deliveryLine
94193
94418
  ].concat(prUrl.includes("/-/merge_requests/") ? [
94194
94419
  "",
94195
- "Note: live monitoring is NOT AVAILABLE for GitLab merge",
94196
- "requests yet \u2014 glab-backed polling is tracked as issue #2882.",
94197
- "The subscription is recorded and PR reference/gate/",
94198
- "publication workflows operate on this MR, but no CI/comment/",
94199
- "review events will be delivered until that lands."
94420
+ "Note: live GitLab MR monitoring is active (glab-backed:",
94421
+ "state, comments, and pipeline CI events). Review-decision",
94422
+ "and status-check rollup equivalents remain NOT AVAILABLE",
94423
+ "for GitLab \u2014 the monitor never fabricates them (issue #2733)."
94200
94424
  ] : []).join(`
94201
94425
  `);
94202
94426
  } catch (err) {
@@ -106632,7 +106856,7 @@ async function runValidationWithTransientRetry(input, candidateContent, baseline
106632
106856
  if (!input.dispatcher) {
106633
106857
  throw new Error("no evaluation dispatcher available (cannot run validation)");
106634
106858
  }
106635
- const { createModelEvaluationExecutor: createModelEvaluationExecutor2 } = await import("./runner-ss88pbb2.js");
106859
+ const { createModelEvaluationExecutor: createModelEvaluationExecutor2 } = await import("./runner-tb3eppeg.js");
106636
106860
  const executor = createModelEvaluationExecutor2(input.dispatcher, input.sessionId);
106637
106861
  const result = await withProtectedSetIntegrity([evalInputRoot, ...protectedRoots(input.directory)], () => _internals129.evaluateCandidateV1({
106638
106862
  projectRoot: input.directory,
@@ -109261,7 +109485,7 @@ function buildDetailedHelp(commandName, entry) {
109261
109485
  async function handleHelpCommand(ctx) {
109262
109486
  const targetCommand = ctx.args.join(" ");
109263
109487
  if (!targetCommand) {
109264
- const { buildHelpText } = await import("./index-fkzv0hj4.js");
109488
+ const { buildHelpText } = await import("./index-4dwhfbed.js");
109265
109489
  return buildHelpText();
109266
109490
  }
109267
109491
  const tokens = targetCommand.split(/\s+/);
@@ -109275,7 +109499,7 @@ async function handleHelpCommand(ctx) {
109275
109499
  > Note: \`/swarm ${resolved.key}\` is a deprecated alias for \`/swarm ${aliasTarget}\`.` : detailed;
109276
109500
  }
109277
109501
  const similar = _internals27.findSimilarCommands(targetCommand);
109278
- const { buildHelpText: fullHelp } = await import("./index-fkzv0hj4.js");
109502
+ const { buildHelpText: fullHelp } = await import("./index-4dwhfbed.js");
109279
109503
  if (similar.length > 0) {
109280
109504
  return `Command '/swarm ${targetCommand}' not found.
109281
109505
 
@@ -109310,6 +109534,18 @@ async function handleModeCommandWithBundledSkills(ctx, handler, mechanicalMode)
109310
109534
  }
109311
109535
  return result;
109312
109536
  }
109537
+ function resolveCommandForgeContext(directory, prUrl) {
109538
+ if (detectForgeFromUrl(prUrl))
109539
+ return;
109540
+ try {
109541
+ const config = loadPluginConfig(directory);
109542
+ const remote = detectGitRemote(directory, undefined);
109543
+ const remotes = remote ? [remote] : [];
109544
+ return resolveForgeContextFromPluginConfig(config, remotes) ?? undefined;
109545
+ } catch {
109546
+ return;
109547
+ }
109548
+ }
109313
109549
  async function handlePrFeedbackCommandWithTransition(ctx) {
109314
109550
  if (ctx.packageRoot) {
109315
109551
  await syncBundledProjectSkillsIfMissingAsync(ctx.directory, ctx.packageRoot, true);
@@ -109340,7 +109576,8 @@ async function handlePrFeedbackCommandWithTransition(ctx) {
109340
109576
  } else {
109341
109577
  await activatePrWorkflow(ctx.directory, ctx.sessionID, "PR_FEEDBACK", {
109342
109578
  requireCheckoutPreflight: true,
109343
- ...parsed.prUrl ? { prUrl: parsed.prUrl } : {}
109579
+ ...parsed.prUrl ? { prUrl: parsed.prUrl } : {},
109580
+ ...parsed.prUrl ? { forge: resolveCommandForgeContext(ctx.directory, parsed.prUrl) } : {}
109344
109581
  });
109345
109582
  }
109346
109583
  return handlePrFeedbackCommand(ctx.directory, ctx.args);
@@ -109590,7 +109827,7 @@ var COMMAND_REGISTRY = {
109590
109827
  },
109591
109828
  "guardrail explain": {
109592
109829
  handler: async (ctx) => {
109593
- const { handleGuardrailExplain } = await import("./guardrail-explain-cne2701m.js");
109830
+ const { handleGuardrailExplain } = await import("./guardrail-explain-njv3pnsw.js");
109594
109831
  return handleGuardrailExplain(ctx.directory, ctx.args);
109595
109832
  },
109596
109833
  description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
@@ -109600,7 +109837,7 @@ var COMMAND_REGISTRY = {
109600
109837
  },
109601
109838
  "guardrail reset": {
109602
109839
  handler: async (ctx) => {
109603
- const { handleGuardrailReset } = await import("./guardrail-reset-e6njf0hv.js");
109840
+ const { handleGuardrailReset } = await import("./guardrail-reset-11cvwgbe.js");
109604
109841
  return handleGuardrailReset(ctx.args, ctx.sessionID);
109605
109842
  },
109606
109843
  description: "Reset one exact active invocation/action circuit after repair",
@@ -109621,7 +109858,7 @@ var COMMAND_REGISTRY = {
109621
109858
  },
109622
109859
  "guardrail-log": {
109623
109860
  handler: async (ctx) => {
109624
- const { handleGuardrailLog } = await import("./guardrail-log-b23sf549.js");
109861
+ const { handleGuardrailLog } = await import("./guardrail-log-r8zmh4rd.js");
109625
109862
  return handleGuardrailLog(ctx.directory, ctx.args);
109626
109863
  },
109627
109864
  description: "Read the guardrail decision log (use --blocks-only for blocks)",