opencode-swarm 7.185.1 → 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 (74) hide show
  1. package/binaries/win32-arm64/swarm-sandbox-runner.exe +0 -0
  2. package/binaries/win32-x64/swarm-sandbox-runner.exe +0 -0
  3. package/dist/background/pr-feedback-event-queue.d.ts +3 -2
  4. package/dist/background/pr-feedback-loop-runtime.d.ts +4 -1
  5. package/dist/background/pr-feedback-loop.d.ts +2 -1
  6. package/dist/background/pr-monitor-worker.d.ts +9 -1
  7. package/dist/background/pr-subscriptions.d.ts +23 -0
  8. package/dist/cli/{auto-checkpoint-2jecngee.js → auto-checkpoint-wd99h2bt.js} +4 -4
  9. package/dist/cli/{checkpoint-qm05wdbh.js → checkpoint-kjzwsxw2.js} +8 -8
  10. package/dist/cli/{coder-settlement-56prayae.js → coder-settlement-kp3ph56n.js} +3 -3
  11. package/dist/cli/{config-doctor-3b99vx74.js → config-doctor-28ggsms8.js} +2 -2
  12. package/dist/cli/{core-cxnqsrxp.js → core-pj2fz34e.js} +1 -1
  13. package/dist/cli/{curator-drift-dt4g79a4.js → curator-drift-q84jn9cc.js} +5 -5
  14. package/dist/cli/{curator-llm-factory-hkk29g2y.js → curator-llm-factory-13h02244.js} +25 -25
  15. package/dist/cli/{curator-5k3mktpe.js → curator-r0jfc7xw.js} +25 -25
  16. package/dist/cli/{evidence-summary-service-8e2fghz0.js → evidence-summary-service-rsectw2t.js} +9 -9
  17. package/dist/cli/{gate-evidence-vk8rebsx.js → gate-evidence-mpwhcm2s.js} +2 -2
  18. package/dist/cli/{guardrail-explain-ma658hkw.js → guardrail-explain-njv3pnsw.js} +26 -26
  19. package/dist/cli/{guardrail-log-m6mydjet.js → guardrail-log-r8zmh4rd.js} +3 -3
  20. package/dist/cli/{guardrail-reset-w41yndke.js → guardrail-reset-11cvwgbe.js} +25 -25
  21. package/dist/cli/{hive-promoter-400xzdds.js → hive-promoter-0vg8w79a.js} +25 -25
  22. package/dist/cli/{index-ek5gvpvm.js → index-151bdyf9.js} +3 -3
  23. package/dist/cli/{index-rtznwf0g.js → index-22f1ek6k.js} +25 -25
  24. package/dist/cli/{index-r9zc92pb.js → index-4dwhfbed.js} +27 -27
  25. package/dist/cli/{index-ss6b8jpz.js → index-4fd28s8v.js} +1 -1
  26. package/dist/cli/{index-ycqsnfd1.js → index-5pa0e0k3.js} +1 -1
  27. package/dist/cli/{index-07bk0zm9.js → index-6bfcsczm.js} +1 -1
  28. package/dist/cli/{index-2b3bgm20.js → index-6ndc8cmn.js} +1 -1
  29. package/dist/cli/{index-5n08z6qj.js → index-7xt5m1cz.js} +5 -5
  30. package/dist/cli/{index-nw16apxs.js → index-9th8npp7.js} +1 -1
  31. package/dist/cli/{index-dz5cbkrm.js → index-9y6cyc7z.js} +3 -3
  32. package/dist/cli/{index-ekyg4p8b.js → index-a1tpq5zr.js} +1 -1
  33. package/dist/cli/{index-nhw5rt5x.js → index-a6h5arqs.js} +3 -3
  34. package/dist/cli/{index-pa6fzbms.js → index-amamkcpy.js} +1 -1
  35. package/dist/cli/{index-dryhmaft.js → index-bajvxmnb.js} +2 -2
  36. package/dist/cli/{index-hgfkcb1q.js → index-bgpq7wn2.js} +754 -565
  37. package/dist/cli/{index-7jt24hpz.js → index-d7mcdyqb.js} +2 -2
  38. package/dist/cli/{index-cnbpht7m.js → index-fp4hxcsy.js} +1 -1
  39. package/dist/cli/{index-s7va6n84.js → index-hvmfa7m8.js} +1 -1
  40. package/dist/cli/{index-cp2nerjd.js → index-j972ags2.js} +38 -15
  41. package/dist/cli/{index-9h93zjm3.js → index-jxd67x6z.js} +1 -1
  42. package/dist/cli/{index-zt3taseq.js → index-kv3n7g8w.js} +1 -1
  43. package/dist/cli/{index-7n3h39h9.js → index-m94gfe82.js} +4 -4
  44. package/dist/cli/{index-m1bhg85z.js → index-nxjm66qb.js} +2 -2
  45. package/dist/cli/{index-fa014mra.js → index-p6bvzgp2.js} +3 -3
  46. package/dist/cli/{index-2c6e1p7j.js → index-p9m1nhds.js} +1 -1
  47. package/dist/cli/{index-rr1dggfe.js → index-qyjyd3ej.js} +1 -1
  48. package/dist/cli/{index-6wqv8f7d.js → index-vk3ngryj.js} +1 -1
  49. package/dist/cli/{index-ppj5bjaq.js → index-w2b8qq6d.js} +3 -3
  50. package/dist/cli/{index-pppjg0ct.js → index-wkv1qdb0.js} +13 -15
  51. package/dist/cli/{index-smwybqka.js → index-wmazt588.js} +1 -1
  52. package/dist/cli/index.js +26 -26
  53. package/dist/cli/{knowledge-escalator-30bb9fyg.js → knowledge-escalator-7xcd0zea.js} +6 -6
  54. package/dist/cli/{knowledge-events-gfbx97x0.js → knowledge-events-e4ts8y2v.js} +4 -4
  55. package/dist/cli/{knowledge-store-2ssd489f.js → knowledge-store-mmeqmjwj.js} +1 -1
  56. package/dist/cli/{knowledge-validator-7bxvezgv.js → knowledge-validator-w2ttgxyj.js} +2 -2
  57. package/dist/cli/{mcp-apr65eya.js → mcp-5dmm4fk2.js} +1 -1
  58. package/dist/cli/{model-preflight-g7b12yn2.js → model-preflight-kap3zp3g.js} +25 -25
  59. package/dist/cli/{pending-delegations-x8q7cxr7.js → pending-delegations-q3sj608s.js} +2 -2
  60. package/dist/cli/{pr-subscriptions-qwr6ybcb.js → pr-subscriptions-qw4wjv66.js} +4 -2
  61. package/dist/cli/{pr-workflow-gate-qd5tfkak.js → pr-workflow-gate-tdj50p2g.js} +25 -25
  62. package/dist/cli/{scan-cursor-1m6dj2s2.js → scan-cursor-fgecb928.js} +2 -2
  63. package/dist/cli/{schema-yvhamv41.js → schema-zrcgm9d9.js} +1 -1
  64. package/dist/cli/{scope-persistence-xdedbzdg.js → scope-persistence-08xd3kyb.js} +5 -5
  65. package/dist/cli/{server-nhdkvdt2.js → server-kng2nggc.js} +25 -25
  66. package/dist/cli/{skill-generator-fzvp9m8z.js → skill-generator-dztn1ctf.js} +7 -7
  67. package/dist/cli/{snapshot-coordination-init-xqxek8kn.js → snapshot-coordination-init-5q0hac3d.js} +25 -25
  68. package/dist/cli/{speckit-checkoff-57tf4079.js → speckit-checkoff-hhsy83m9.js} +3 -3
  69. package/dist/cli/{worktree-collision-ownership-80n814a8.js → worktree-collision-ownership-e2cqcmnw.js} +2 -2
  70. package/dist/cli/{worktree-isolation-kaxkr61t.js → worktree-isolation-refd2n16.js} +25 -25
  71. package/dist/git/pr.d.ts +73 -0
  72. package/dist/hooks/pr-workflow-gate.d.ts +2 -0
  73. package/dist/index.js +34 -34
  74. package/package.json +1 -1
@@ -8,13 +8,13 @@ import {
8
8
  protectedRoots,
9
9
  redactDecisionLineForArchive,
10
10
  stableCanonicalStringify
11
- } from "./index-ss6b8jpz.js";
11
+ } from "./index-4fd28s8v.js";
12
12
  import {
13
13
  detectStraySwarmDirs,
14
14
  readDoctorArtifact,
15
15
  removeStraySwarmDir,
16
16
  runConfigDoctor
17
- } from "./index-9h93zjm3.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-pa6fzbms.js";
29
+ } from "./index-amamkcpy.js";
30
30
  import {
31
31
  LANGUAGE_REGISTRY,
32
32
  _internals as _internals3,
@@ -77,7 +77,7 @@ import {
77
77
  alreadyCuratedThisGeneration,
78
78
  claimNextScanBatch,
79
79
  resolveCohortId
80
- } from "./index-smwybqka.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-s7va6n84.js";
99
+ } from "./index-hvmfa7m8.js";
100
100
  import {
101
101
  assertNoUnsettledCoderDispatch,
102
102
  listCoderSettlementWalStates,
103
103
  recoverCoderSettlement,
104
104
  recoverStaleCoderSettlements
105
- } from "./index-ek5gvpvm.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-dz5cbkrm.js";
126
+ } from "./index-9y6cyc7z.js";
127
127
  import {
128
128
  buildEscalationBriefing,
129
129
  readRecentEscalations
130
- } from "./index-5n08z6qj.js";
130
+ } from "./index-7xt5m1cz.js";
131
131
  import {
132
132
  parsePorcelainV2Snapshot,
133
133
  resolveCommitCountSince,
@@ -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,7 +176,7 @@ import {
176
176
  sweepStale,
177
177
  unsubscribe,
178
178
  updateSnapshot
179
- } from "./index-cp2nerjd.js";
179
+ } from "./index-j972ags2.js";
180
180
  import {
181
181
  WORKTREE_LIFECYCLE_LOCK_FILE,
182
182
  recordWorktreeProvisioningOwner,
@@ -194,7 +194,7 @@ import {
194
194
  checkpoint,
195
195
  createSwarmTool,
196
196
  resolveWorkingDirectory
197
- } from "./index-nhw5rt5x.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-pppjg0ct.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-2b3bgm20.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-cnbpht7m.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-2c6e1p7j.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-nw16apxs.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-ppj5bjaq.js";
334
+ } from "./index-w2b8qq6d.js";
335
335
  import {
336
336
  estimateCharsForTokens,
337
337
  estimateTokens,
@@ -359,7 +359,7 @@ import {
359
359
  validateActionableFields,
360
360
  validateLesson,
361
361
  validateSkillPath
362
- } from "./index-ycqsnfd1.js";
362
+ } from "./index-5pa0e0k3.js";
363
363
  import {
364
364
  MAX_CURATION_PROPOSALS,
365
365
  authorizeCuration,
@@ -370,7 +370,7 @@ import {
370
370
  } from "./index-rtry5xyf.js";
371
371
  import {
372
372
  resolveWorktreeIsolationConfig
373
- } from "./index-7jt24hpz.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-6wqv8f7d.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-dryhmaft.js";
401
+ } from "./index-bajvxmnb.js";
402
402
  import {
403
403
  CORE_EVENT_LOCKED,
404
404
  appendCoreEventSync,
@@ -487,7 +487,7 @@ import {
487
487
  transactFile,
488
488
  transactKnowledge,
489
489
  wordBigrams
490
- } from "./index-7n3h39h9.js";
490
+ } from "./index-m94gfe82.js";
491
491
  import {
492
492
  readTailJsonl,
493
493
  readTailJsonlDetailed,
@@ -568,7 +568,7 @@ import {
568
568
  loadGateOverrides,
569
569
  loadPluginConfig,
570
570
  loadPluginConfigWithMeta
571
- } from "./index-ekyg4p8b.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-rr1dggfe.js";
603
+ } from "./index-qyjyd3ej.js";
604
604
  import {
605
605
  AGENT_TOOL_MAP,
606
606
  ALL_AGENT_NAMES,
@@ -3389,7 +3389,7 @@ async function importLegacyPrWorkflowGateStateIfNeeded(directory, sessionID, all
3389
3389
  return null;
3390
3390
  throw error2;
3391
3391
  }
3392
- const legacy = allowSalvagedImport ? (await (await import("./pr-workflow-gate-qd5tfkak.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);
3393
3393
  if (!legacy)
3394
3394
  return null;
3395
3395
  const namespace = workflowGateStateCoordinationNamespace(sessionID);
@@ -3476,7 +3476,7 @@ async function deleteStateWhileLocked(directory, sessionID, options = {}) {
3476
3476
  let recoveryState = null;
3477
3477
  if (!currentAuthoritative) {
3478
3478
  if (options.allowSalvagedRead) {
3479
- const { readPrWorkflowGateStateForRecovery } = await import("./pr-workflow-gate-qd5tfkak.js");
3479
+ const { readPrWorkflowGateStateForRecovery } = await import("./pr-workflow-gate-tdj50p2g.js");
3480
3480
  recoveryState = (await readPrWorkflowGateStateForRecovery(directory, normalizedSessionID))?.state ?? null;
3481
3481
  }
3482
3482
  if (!recoveryState) {
@@ -15039,7 +15039,7 @@ function isLaneOwnedByCurrentSession(branchName, expectedSessionId) {
15039
15039
  return extracted === expectedSessionId;
15040
15040
  }
15041
15041
  async function inspectStandardWorktreeCollisionOwnership(identity) {
15042
- const collisionOwnership = await import("./worktree-collision-ownership-80n814a8.js");
15042
+ const collisionOwnership = await import("./worktree-collision-ownership-e2cqcmnw.js");
15043
15043
  return collisionOwnership.inspectStandardWorktreeCollisionOwnership(identity);
15044
15044
  }
15045
15045
  async function runRecoveryGit(directory, args, timeoutMs = 15000) {
@@ -15465,7 +15465,7 @@ async function precreateStandardWorktreeSession(args) {
15465
15465
  const laneProfile = computeLaneRuntimeProfile(worktreeConfig.runtime_isolation, laneIndex, handle.worktreePath);
15466
15466
  if (laneProfile) {
15467
15467
  try {
15468
- const { writeLaneProfileToDiskReal } = await import("./core-cxnqsrxp.js");
15468
+ const { writeLaneProfileToDiskReal } = await import("./core-pj2fz34e.js");
15469
15469
  await writeLaneProfileToDiskReal(handle.worktreePath, laneProfile.laneIndex, laneProfile.envOverrides);
15470
15470
  } catch {}
15471
15471
  }
@@ -16444,7 +16444,7 @@ async function finishStandardWorktreeDispatch(directory, dispatch, config, callI
16444
16444
  }
16445
16445
  clearWorktreeMergeStatus(statusKey);
16446
16446
  try {
16447
- const { removeLaneProfileFromDiskReal } = await import("./core-cxnqsrxp.js");
16447
+ const { removeLaneProfileFromDiskReal } = await import("./core-pj2fz34e.js");
16448
16448
  await removeLaneProfileFromDiskReal(dispatch.handle.worktreePath, dispatch.laneIndex);
16449
16449
  } catch {}
16450
16450
  const state = serializationStateBySessionID.get(dispatch.parentSessionID);
@@ -24083,7 +24083,7 @@ function clearCriticalShownIds(sessionID) {
24083
24083
  async function rehydratePrSubscriptions(sessionID, directory) {
24084
24084
  const map = new Map;
24085
24085
  try {
24086
- const { listActive: listActive2 } = await import("./pr-subscriptions-qwr6ybcb.js");
24086
+ const { listActive: listActive2 } = await import("./pr-subscriptions-qw4wjv66.js");
24087
24087
  const records = await listActive2(directory);
24088
24088
  for (const record of records) {
24089
24089
  if (record.sessionID !== sessionID)
@@ -24568,11 +24568,11 @@ async function activatePrWorkflow(directory, sessionID, mode, options = {}) {
24568
24568
  let existing = await readPrWorkflowGateStateFromDisk3(directory, normalizedSessionID);
24569
24569
  if (existing?.mode === mode) {
24570
24570
  if (mode === "PR_FEEDBACK" && options.prUrl) {
24571
- const requestedTarget = canonicalGitHubPrUrl(options.prUrl);
24571
+ const requestedTarget = canonicalGitHubPrUrl(options.prUrl, options.forge);
24572
24572
  if (!requestedTarget) {
24573
24573
  throw new Error("BLOCKED: PR_FEEDBACK target must be a canonical GitHub PR URL");
24574
24574
  }
24575
- const existingTarget = existing.prFeedbackTargetUrl ? canonicalGitHubPrUrl(existing.prFeedbackTargetUrl) : null;
24575
+ const existingTarget = existing.prFeedbackTargetUrl ? canonicalGitHubPrUrl(existing.prFeedbackTargetUrl, options.forge) : null;
24576
24576
  if (existingTarget && requestedTarget !== existingTarget) {
24577
24577
  throw new Error(`BLOCKED: active PR_FEEDBACK targets a different GitHub pull request`);
24578
24578
  }
@@ -24606,7 +24606,7 @@ async function activatePrWorkflow(directory, sessionID, mode, options = {}) {
24606
24606
  const initialHead = options.prHeadSha ? await assertCurrentCheckoutHead(directory, options.prHeadSha, mode) : undefined;
24607
24607
  const skillContractAdvisories = await ensurePrWorkflowSkillContractsFresh(directory, mode);
24608
24608
  const timestamp = isoNow();
24609
- 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;
24610
24610
  if (feedbackTargetUrl === null) {
24611
24611
  throw new Error("BLOCKED: PR_FEEDBACK target must be a canonical GitHub PR URL");
24612
24612
  }
@@ -29150,8 +29150,8 @@ async function readPrReviewFinalFindingPolicyForReport(directory, sessionID) {
29150
29150
  const blockingFindingIds = policyProjection.blockingFindingIds.flatMap((id) => sourceIdsByPolicyFindingId.get(id) ?? [id]).sort();
29151
29151
  return { policyVersion: 1, permittedVerdicts, blockingFindingIds };
29152
29152
  }
29153
- function canonicalGitHubPrUrl(value) {
29154
- return canonicalForgePrUrl(value);
29153
+ function canonicalGitHubPrUrl(value, configured) {
29154
+ return canonicalForgePrUrl(value, configured);
29155
29155
  }
29156
29156
  function assertMatchingPrReviewFeedbackConsent(record, input) {
29157
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) {
@@ -32223,6 +32223,128 @@ async function readPrWorkflowGateStateForRecovery(directory, sessionID) {
32223
32223
  // src/commands/registry.ts
32224
32224
  init_logger();
32225
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
+
32226
32348
  // src/commands/abort-pr-workflow.ts
32227
32349
  var USAGE2 = [
32228
32350
  "Usage: /swarm abort-pr-workflow [PR_REVIEW|PR_FEEDBACK] [reason...]",
@@ -32327,7 +32449,7 @@ import { createHash as createHash24 } from "crypto";
32327
32449
  import { mkdir as mkdir6, readFile as readFile10, unlink as unlink2 } from "fs/promises";
32328
32450
  import { dirname as dirname15 } from "path";
32329
32451
  var SPEC_DRIFT_RECOVERY_AGENT = "spec-drift-recovery";
32330
- var _internals32 = {
32452
+ var _internals33 = {
32331
32453
  appendEvent,
32332
32454
  assertProjectRoot,
32333
32455
  bunWrite,
@@ -32412,21 +32534,21 @@ async function writeWal3(walPath, wal) {
32412
32534
  }
32413
32535
  async function verifySnapshot(snapshotPath, currentSpec) {
32414
32536
  if (!currentSpec) {
32415
- await _internals32.unlinkIfExists(snapshotPath);
32416
- const stillExists = await _internals32.readFileText(snapshotPath) !== null;
32537
+ await _internals33.unlinkIfExists(snapshotPath);
32538
+ const stillExists = await _internals33.readFileText(snapshotPath) !== null;
32417
32539
  if (stillExists) {
32418
32540
  throw new Error("spec snapshot verification failed: snapshot still exists after delete");
32419
32541
  }
32420
32542
  return;
32421
32543
  }
32422
32544
  await atomicWriteFile(snapshotPath, currentSpec.content);
32423
- const written = await _internals32.readFileText(snapshotPath);
32545
+ const written = await _internals33.readFileText(snapshotPath);
32424
32546
  if (written !== currentSpec.content) {
32425
32547
  throw new Error("spec snapshot verification failed: snapshot content does not match effective spec");
32426
32548
  }
32427
32549
  }
32428
32550
  async function ensureSnapshotEvent(directory, plan, transitionId) {
32429
- const events = await _internals32.readLedgerEvents(directory);
32551
+ const events = await _internals33.readLedgerEvents(directory);
32430
32552
  for (const event of events) {
32431
32553
  const payload = event.payload;
32432
32554
  const approval = payload?.approval;
@@ -32434,17 +32556,17 @@ async function ensureSnapshotEvent(directory, plan, transitionId) {
32434
32556
  return;
32435
32557
  }
32436
32558
  }
32437
- await _internals32.takeSnapshotEvent(directory, plan, {
32559
+ await _internals33.takeSnapshotEvent(directory, plan, {
32438
32560
  source: "spec_drift_recovery",
32439
32561
  approvalMetadata: { specDriftTransitionId: transitionId }
32440
32562
  });
32441
32563
  }
32442
32564
  async function appendEvent(directory, event) {
32443
- const existing = await _internals32.verifyEventPresence(directory, event.type, event.transitionId);
32565
+ const existing = await _internals33.verifyEventPresence(directory, event.type, event.transitionId);
32444
32566
  if (existing)
32445
32567
  return;
32446
32568
  appendCoreEventSync(directory, { ...event }, { dedupeOnAuthorityKey: true });
32447
- const verified = await _internals32.verifyEventPresence(directory, event.type, event.transitionId);
32569
+ const verified = await _internals33.verifyEventPresence(directory, event.type, event.transitionId);
32448
32570
  if (!verified) {
32449
32571
  throw new Error(`spec drift audit verification failed for transition ${event.transitionId}`);
32450
32572
  }
@@ -32466,7 +32588,7 @@ function buildRecoveryEvent(args) {
32466
32588
  if (args.mode === "acknowledge") {
32467
32589
  return {
32468
32590
  type: "spec_drift_acknowledged",
32469
- timestamp: _internals32.now(),
32591
+ timestamp: _internals33.now(),
32470
32592
  phase: args.phase,
32471
32593
  planTitle: args.planTitle,
32472
32594
  acknowledgedBy: args.actor === "spec_write" ? "unknown" : args.actor,
@@ -32478,7 +32600,7 @@ function buildRecoveryEvent(args) {
32478
32600
  }
32479
32601
  return {
32480
32602
  type: "spec_drift_repaired",
32481
- timestamp: _internals32.now(),
32603
+ timestamp: _internals33.now(),
32482
32604
  phase: args.phase,
32483
32605
  planTitle: args.planTitle,
32484
32606
  repairedBy: args.actor,
@@ -32489,11 +32611,11 @@ function buildRecoveryEvent(args) {
32489
32611
  };
32490
32612
  }
32491
32613
  async function reconcileSpecDrift(directory, options) {
32492
- _internals32.assertProjectRoot(directory);
32493
- const markerPath = _internals32.validateSwarmPath(directory, "spec-staleness.json");
32494
- const walPath = _internals32.validateSwarmPath(directory, "spec-drift-recovery.json");
32495
- const snapshotPath = _internals32.validateSwarmPath(directory, "spec-snapshot.md");
32496
- 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);
32497
32619
  if (markerMaybe === null) {
32498
32620
  return {
32499
32621
  status: "no_marker",
@@ -32501,7 +32623,7 @@ async function reconcileSpecDrift(directory, options) {
32501
32623
  message: "No spec drift detected."
32502
32624
  };
32503
32625
  }
32504
- 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()}`);
32505
32627
  if (specLockResult && !specLockResult.acquired) {
32506
32628
  return {
32507
32629
  status: "retry_later",
@@ -32511,7 +32633,7 @@ async function reconcileSpecDrift(directory, options) {
32511
32633
  }
32512
32634
  let lockResult;
32513
32635
  try {
32514
- 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()}`);
32515
32637
  } catch (error2) {
32516
32638
  if (specLockResult?.acquired && specLockResult.lock._release) {
32517
32639
  await specLockResult.lock._release().catch(() => {});
@@ -32537,7 +32659,7 @@ async function reconcileSpecDrift(directory, options) {
32537
32659
  let errorNewHash;
32538
32660
  try {
32539
32661
  try {
32540
- const authoritativeMarkerRaw = await _internals32.readFileText(markerPath);
32662
+ const authoritativeMarkerRaw = await _internals33.readFileText(markerPath);
32541
32663
  if (authoritativeMarkerRaw === null) {
32542
32664
  return {
32543
32665
  status: "no_marker",
@@ -32545,14 +32667,14 @@ async function reconcileSpecDrift(directory, options) {
32545
32667
  message: "No spec drift detected."
32546
32668
  };
32547
32669
  }
32548
- const marker = _internals32.parseMarker(authoritativeMarkerRaw);
32670
+ const marker = _internals33.parseMarker(authoritativeMarkerRaw);
32549
32671
  if (!marker) {
32550
32672
  return buildCorruptMarkerResult(options.mode);
32551
32673
  }
32552
32674
  errorMarker = marker;
32553
32675
  const markerHash = sha2563(authoritativeMarkerRaw);
32554
- const existingWalRaw = await _internals32.readFileText(walPath);
32555
- const existingWal = existingWalRaw === null ? null : _internals32.parseWal(existingWalRaw);
32676
+ const existingWalRaw = await _internals33.readFileText(walPath);
32677
+ const existingWal = existingWalRaw === null ? null : _internals33.parseWal(existingWalRaw);
32556
32678
  if (existingWalRaw !== null && !existingWal) {
32557
32679
  return {
32558
32680
  status: "failed",
@@ -32562,7 +32684,7 @@ async function reconcileSpecDrift(directory, options) {
32562
32684
  planTitle: marker.planTitle
32563
32685
  };
32564
32686
  }
32565
- const currentSpec = _internals32.readEffectiveSpecSync(directory);
32687
+ const currentSpec = _internals33.readEffectiveSpecSync(directory);
32566
32688
  const proposedNewHash = currentSpec?.hash ?? null;
32567
32689
  const proposedTransitionId = buildTransitionId(options.mode, markerHash, marker.specHash_plan, proposedNewHash);
32568
32690
  const proposedWal = {
@@ -32577,7 +32699,7 @@ async function reconcileSpecDrift(directory, options) {
32577
32699
  newHash: proposedNewHash,
32578
32700
  specContent: currentSpec?.content ?? null,
32579
32701
  actor: options.actor,
32580
- recordedAt: _internals32.now()
32702
+ recordedAt: _internals33.now()
32581
32703
  };
32582
32704
  const markerReplacedDuringPrepared = existingWal?.state === "PREPARED" && existingWal.markerHash !== markerHash;
32583
32705
  const wal = existingWal?.state === "PREPARED" || existingWal?.markerHash === markerHash ? existingWal : proposedWal;
@@ -32586,12 +32708,12 @@ async function reconcileSpecDrift(directory, options) {
32586
32708
  errorTransitionId = transitionId;
32587
32709
  errorNewHash = newHash;
32588
32710
  if (wal === proposedWal) {
32589
- await _internals32.writeWal(walPath, wal);
32711
+ await _internals33.writeWal(walPath, wal);
32590
32712
  }
32591
32713
  if (wal.newHash === null !== (wal.specContent === null) || wal.specContent !== null && sha2563(wal.specContent) !== wal.newHash) {
32592
32714
  throw new Error(`Spec drift recovery WAL ${transitionId} has inconsistent captured spec content`);
32593
32715
  }
32594
- let plan = await _internals32.loadPlanJsonOnly(directory);
32716
+ let plan = await _internals33.loadPlanJsonOnly(directory);
32595
32717
  if (!plan) {
32596
32718
  return {
32597
32719
  status: "failed",
@@ -32622,13 +32744,13 @@ async function reconcileSpecDrift(directory, options) {
32622
32744
  }
32623
32745
  if (planMatchesOld) {
32624
32746
  plan.specHash = newHash ?? undefined;
32625
- await _internals32.savePlan(directory, plan, {
32747
+ await _internals33.savePlan(directory, plan, {
32626
32748
  planLockAlreadyHeld: true
32627
32749
  });
32628
- plan = await _internals32.loadPlanJsonOnly(directory) ?? plan;
32750
+ plan = await _internals33.loadPlanJsonOnly(directory) ?? plan;
32629
32751
  }
32630
- await _internals32.ensureSnapshotEvent(directory, plan, transitionId);
32631
- 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 });
32632
32754
  const event = buildRecoveryEvent({
32633
32755
  mode: wal.mode,
32634
32756
  actor: wal.actor,
@@ -32639,15 +32761,15 @@ async function reconcileSpecDrift(directory, options) {
32639
32761
  previousHash: wal.previousHash,
32640
32762
  transitionId
32641
32763
  });
32642
- await _internals32.appendEvent(directory, event);
32643
- await _internals32.writeWal(walPath, { ...wal, state: "COMMITTED" });
32764
+ await _internals33.appendEvent(directory, event);
32765
+ await _internals33.writeWal(walPath, { ...wal, state: "COMMITTED" });
32644
32766
  }
32645
32767
  if (markerReplacedDuringPrepared) {
32646
32768
  const preservedMarker = {
32647
32769
  ...marker,
32648
32770
  specHash_plan: newHash,
32649
32771
  reason: `prior prepared drift recovery committed before this marker: ${marker.reason}`,
32650
- timestamp: _internals32.now()
32772
+ timestamp: _internals33.now()
32651
32773
  };
32652
32774
  await atomicWriteFile(markerPath, `${JSON.stringify(preservedMarker, null, 2)}
32653
32775
  `);
@@ -32662,7 +32784,7 @@ async function reconcileSpecDrift(directory, options) {
32662
32784
  transitionId
32663
32785
  };
32664
32786
  }
32665
- const latestSpec = _internals32.readEffectiveSpecSync(directory);
32787
+ const latestSpec = _internals33.readEffectiveSpecSync(directory);
32666
32788
  if ((latestSpec?.hash ?? null) !== newHash) {
32667
32789
  const refreshedMarker = {
32668
32790
  planTitle: wal.planTitle,
@@ -32670,7 +32792,7 @@ async function reconcileSpecDrift(directory, options) {
32670
32792
  specHash_plan: newHash,
32671
32793
  specHash_current: latestSpec?.hash ?? null,
32672
32794
  reason: "spec changed while drift recovery was committing",
32673
- timestamp: _internals32.now()
32795
+ timestamp: _internals33.now()
32674
32796
  };
32675
32797
  await atomicWriteFile(markerPath, `${JSON.stringify(refreshedMarker, null, 2)}
32676
32798
  `);
@@ -32686,8 +32808,8 @@ async function reconcileSpecDrift(directory, options) {
32686
32808
  };
32687
32809
  }
32688
32810
  try {
32689
- await _internals32.unlinkIfExists(markerPath);
32690
- _internals32.invalidateCachedArtifact(markerPath);
32811
+ await _internals33.unlinkIfExists(markerPath);
32812
+ _internals33.invalidateCachedArtifact(markerPath);
32691
32813
  } catch (error2) {
32692
32814
  return {
32693
32815
  status: "cleanup_pending",
@@ -33184,7 +33306,7 @@ ${USAGE4}`;
33184
33306
 
33185
33307
  // src/commands/archive.ts
33186
33308
  init_loader();
33187
- var _internals33 = {
33309
+ var _internals34 = {
33188
33310
  now: () => new Date
33189
33311
  };
33190
33312
  function artifactLabel(artifact) {
@@ -33240,7 +33362,7 @@ async function handleArchiveCommand(directory, args) {
33240
33362
  const report = await archiveEvidence(directory, maxAgeDays, maxBundles, {
33241
33363
  report: true,
33242
33364
  dryRun,
33243
- now: _internals33.now(),
33365
+ now: _internals34.now(),
33244
33366
  cacheMaxBytes,
33245
33367
  cacheMaxRecords
33246
33368
  });
@@ -35207,7 +35329,7 @@ function createShadowCopy(directory, maxBytes = MAX_SHADOW_COPY_BYTES) {
35207
35329
  const rel = path33.relative(directory, src);
35208
35330
  const dest = path33.join(shadowRoot, rel);
35209
35331
  fs21.mkdirSync(path33.dirname(dest), { recursive: true });
35210
- const copied = _internals34.copyFileBounded(src, dest, maxBytes - copiedBytes);
35332
+ const copied = _internals35.copyFileBounded(src, dest, maxBytes - copiedBytes);
35211
35333
  if (copied === null) {
35212
35334
  removeShadowRoot(shadowRoot);
35213
35335
  return null;
@@ -35220,7 +35342,7 @@ function createShadowCopy(directory, maxBytes = MAX_SHADOW_COPY_BYTES) {
35220
35342
  throw error2;
35221
35343
  }
35222
35344
  }
35223
- var _internals34 = {
35345
+ var _internals35 = {
35224
35346
  computeEvidenceQualitySummary,
35225
35347
  copyFileBounded,
35226
35348
  createShadowCopy
@@ -35467,7 +35589,7 @@ async function evaluateAdvisoryCi(options) {
35467
35589
  });
35468
35590
  }
35469
35591
  }
35470
- const summary = await _internals34.computeEvidenceQualitySummary(directory);
35592
+ const summary = await _internals35.computeEvidenceQualitySummary(directory);
35471
35593
  const q = summary.qualityMetrics;
35472
35594
  const qualityRows = [
35473
35595
  [
@@ -35861,7 +35983,7 @@ async function handleCiCommand(ctx) {
35861
35983
  const signals = createSignalCancellation(controller);
35862
35984
  signals.install();
35863
35985
  try {
35864
- const result = await _internals35.runAdvisoryCiRuntime({
35986
+ const result = await _internals36.runAdvisoryCiRuntime({
35865
35987
  directory: ctx.directory,
35866
35988
  deadlineMs,
35867
35989
  signal: controller.signal,
@@ -35910,134 +36032,10 @@ async function handleCiCommand(ctx) {
35910
36032
  signals.dispose();
35911
36033
  }
35912
36034
  }
35913
- var _internals35 = { runAdvisoryCiRuntime };
36035
+ var _internals36 = { runAdvisoryCiRuntime };
35914
36036
 
35915
36037
  // src/commands/pr-ref.ts
35916
36038
  init_loader();
35917
-
35918
- // src/commands/_shared/url-security.ts
35919
- import * as child_process from "child_process";
35920
- init_git_executable();
35921
- var MAX_URL_LEN = 2048;
35922
- var _internals36 = {
35923
- spawnSync: (cmd, args, options) => {
35924
- const mergedEnv = mergeEnvForChild(options?.env, options?.envOverrides);
35925
- return child_process.spawnSync(cmd, args, {
35926
- ...options,
35927
- env: mergedEnv
35928
- });
35929
- }
35930
- };
35931
- function sanitizeUrl(raw) {
35932
- let urlStr = raw.trim();
35933
- urlStr = urlStr.replace(/^([A-Za-z][A-Za-z0-9+.-]*:\/\/)\/?[^@/]+@/, "$1");
35934
- urlStr = urlStr.replace(/\[\s*MODE\s*:[^\]]*\]/gi, "");
35935
- urlStr = urlStr.replace(/^([A-Za-z][A-Za-z0-9+.-]*:\/\/)\/?[^@/]+@/, "$1");
35936
- const fragmentIdx = urlStr.indexOf("#");
35937
- if (fragmentIdx !== -1) {
35938
- urlStr = urlStr.slice(0, fragmentIdx);
35939
- }
35940
- const queryIdx = urlStr.indexOf("?");
35941
- if (queryIdx !== -1) {
35942
- urlStr = urlStr.slice(0, queryIdx);
35943
- }
35944
- if (urlStr.length > MAX_URL_LEN) {
35945
- urlStr = urlStr.slice(0, MAX_URL_LEN);
35946
- }
35947
- return urlStr.trim();
35948
- }
35949
- function sanitizeErrorEcho(raw, maxLength = 80) {
35950
- let stripped = "";
35951
- for (const ch of raw) {
35952
- const cp = ch.codePointAt(0);
35953
- if (cp !== undefined && (cp <= 31 || cp === 127)) {
35954
- stripped += " ";
35955
- continue;
35956
- }
35957
- stripped += ch;
35958
- }
35959
- const collapsed = stripped.replace(/\s+/g, " ").trim();
35960
- if (collapsed.length <= maxLength)
35961
- return collapsed;
35962
- return `${collapsed.slice(0, maxLength)}\u2026`;
35963
- }
35964
- function validateAndSanitizeGithubUrl(rawUrl, resource, configured) {
35965
- const sanitized = sanitizeUrl(rawUrl);
35966
- if (!sanitized) {
35967
- return { error: "Empty URL" };
35968
- }
35969
- if (!sanitized.startsWith("https://")) {
35970
- return { error: "URL must use HTTPS scheme" };
35971
- }
35972
- try {
35973
- const url = new URL(sanitized);
35974
- if (hasNonAsciiHostname(url.hostname)) {
35975
- return { error: "Non-ASCII hostnames are not allowed" };
35976
- }
35977
- if (isPrivateHost(url)) {
35978
- return { error: "Private or localhost URLs are not allowed" };
35979
- }
35980
- const matched = matchForgeResourceUrl(sanitized, resource, configured);
35981
- if (!matched) {
35982
- return {
35983
- 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)"
35984
- };
35985
- }
35986
- return { sanitized };
35987
- } catch {
35988
- return { error: "Invalid URL format" };
35989
- }
35990
- }
35991
- function detectGitRemote(cwd, laneEnv) {
35992
- try {
35993
- const result = _internals36.spawnSync(resolveGitExecutable(), ["remote", "get-url", "origin"], {
35994
- encoding: "utf-8",
35995
- stdio: ["ignore", "pipe", "pipe"],
35996
- timeout: 5000,
35997
- ...cwd ? { cwd } : {},
35998
- envOverrides: laneEnv
35999
- });
36000
- if (result.status !== 0 || result.error) {
36001
- return null;
36002
- }
36003
- const remoteUrl = (result.stdout ?? "").trim();
36004
- return remoteUrl || null;
36005
- } catch {
36006
- return null;
36007
- }
36008
- }
36009
- function parseGitRemoteUrl(remoteUrl) {
36010
- const httpsMatch = remoteUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i);
36011
- if (httpsMatch) {
36012
- const owner = httpsMatch[1];
36013
- const repo = httpsMatch[2].replace(/\.git$/, "");
36014
- if (containsControlCharacters(owner) || containsControlCharacters(repo)) {
36015
- return null;
36016
- }
36017
- return { owner, repo };
36018
- }
36019
- const sshMatch = remoteUrl.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/i);
36020
- if (sshMatch) {
36021
- const owner = sshMatch[1];
36022
- const repo = sshMatch[2].replace(/\.git$/, "");
36023
- if (containsControlCharacters(owner) || containsControlCharacters(repo)) {
36024
- return null;
36025
- }
36026
- return { owner, repo };
36027
- }
36028
- const pathMatch = remoteUrl.match(/\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
36029
- if (pathMatch) {
36030
- const owner = pathMatch[1];
36031
- const repo = pathMatch[2].replace(/\.git$/, "");
36032
- if (containsControlCharacters(owner) || containsControlCharacters(repo)) {
36033
- return null;
36034
- }
36035
- return { owner, repo };
36036
- }
36037
- return null;
36038
- }
36039
-
36040
- // src/commands/pr-ref.ts
36041
36039
  var MAX_INSTRUCTIONS_LEN = 1000;
36042
36040
  var GITHUB_CONTEXT = {
36043
36041
  provider: "github",
@@ -40455,9 +40453,9 @@ function hashContent(content) {
40455
40453
  return createHash27("sha1").update(content).digest("hex");
40456
40454
  }
40457
40455
  async function loadConfigForPolicyCurator(directory) {
40458
- const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-yvhamv41.js");
40456
+ const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-zrcgm9d9.js");
40459
40457
  try {
40460
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-fa014mra.js");
40458
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-p6bvzgp2.js");
40461
40459
  const { config: loadedConfig } = loadPluginConfigWithMeta2(directory);
40462
40460
  return KnowledgeConfigSchema2.parse(loadedConfig.knowledge ?? {});
40463
40461
  } catch {
@@ -43515,7 +43513,7 @@ async function resolveCuratorLLMDelegate(directory, mode, sessionId) {
43515
43513
  const seam = _internals38.createCuratorLLMDelegate;
43516
43514
  if (seam)
43517
43515
  return seam(directory, mode, sessionId);
43518
- const { createCuratorLLMDelegate } = await import("./curator-llm-factory-hkk29g2y.js");
43516
+ const { createCuratorLLMDelegate } = await import("./curator-llm-factory-13h02244.js");
43519
43517
  return createCuratorLLMDelegate(directory, mode, sessionId);
43520
43518
  }
43521
43519
  async function reconcileCloseTerminalStateForPlan(directory, targetPlan, options) {
@@ -43910,7 +43908,7 @@ async function runFinalizeStage(ctx) {
43910
43908
  }
43911
43909
  }
43912
43910
  try {
43913
- const { CuratorConfigSchema: CCS } = await import("./schema-yvhamv41.js");
43911
+ const { CuratorConfigSchema: CCS } = await import("./schema-zrcgm9d9.js");
43914
43912
  const { config: pmLoadedConfig } = _internals38.loadPluginConfigWithMeta(ctx.directory);
43915
43913
  const curatorCfg = CCS.parse(pmLoadedConfig.curator ?? {});
43916
43914
  if (curatorCfg.enabled && curatorCfg.postmortem_enabled) {
@@ -46096,7 +46094,7 @@ function serializeAgentSession(s) {
46096
46094
  }
46097
46095
  async function writeSnapshot(directory, state) {
46098
46096
  try {
46099
- const { ensureSnapshotCoordinationReady } = await import("./snapshot-coordination-init-xqxek8kn.js");
46097
+ const { ensureSnapshotCoordinationReady } = await import("./snapshot-coordination-init-5q0hac3d.js");
46100
46098
  await ensureSnapshotCoordinationReady(directory);
46101
46099
  const snapshot = {
46102
46100
  version: 3,
@@ -49274,7 +49272,7 @@ function planMerges(active, threshold, maxComparisons, maxMerges) {
49274
49272
  };
49275
49273
  }
49276
49274
  async function sweepActiveNearDuplicates(directory, options = {}) {
49277
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-fa014mra.js");
49275
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-p6bvzgp2.js");
49278
49276
  const { config } = loadPluginConfigWithMeta2(directory);
49279
49277
  const sweepConfig = config.learning?.dedup_sweep;
49280
49278
  if (sweepConfig?.enabled === false)
@@ -50155,14 +50153,14 @@ async function runCuratorInit(directory, config, llmDelegate) {
50155
50153
  }));
50156
50154
  if (llmDelegate) {
50157
50155
  try {
50158
- const userInput = [
50156
+ const userInput = sanitizeContextText([
50159
50157
  "TASK: CURATOR_INIT",
50160
50158
  `PRIOR_SUMMARY: ${priorSummary ? JSON.stringify(priorSummary) : "none"}`,
50161
50159
  `KNOWLEDGE_ENTRIES: ${JSON.stringify(allEntriesForCurator)}`,
50162
- `PROJECT_CONTEXT: ${contextMd?.slice(0, config.max_summary_tokens * 2) ?? "none"}`,
50163
- `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")}`
50164
50162
  ].join(`
50165
- `);
50163
+ `));
50166
50164
  const systemPrompt = CURATOR_INIT_PROMPT;
50167
50165
  const timeoutMs = config.llm_timeout_ms ?? DEFAULT_CURATOR_LLM_TIMEOUT_MS;
50168
50166
  const ac = new AbortController;
@@ -50256,7 +50254,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
50256
50254
  const phaseData = plan?.phases.find((p) => p.id === phase);
50257
50255
  const tasksCompleted = phaseData ? phaseData.tasks.filter((t) => t.status === "completed").length : 0;
50258
50256
  const tasksTotal = phaseData ? phaseData.tasks.length : 0;
50259
- 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))) : [];
50260
50258
  const phaseDigest = {
50261
50259
  phase,
50262
50260
  timestamp: new Date().toISOString(),
@@ -50287,16 +50285,16 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
50287
50285
  try {
50288
50286
  const priorDigest = priorSummary?.digest ?? "none";
50289
50287
  const systemPrompt = CURATOR_PHASE_PROMPT;
50290
- const userInput = [
50288
+ const userInput = sanitizeContextText([
50291
50289
  `TASK: CURATOR_PHASE ${phase}`,
50292
- `PRIOR_DIGEST: ${priorDigest}`,
50290
+ `PRIOR_DIGEST: ${sanitizeContextText(priorDigest)}`,
50293
50291
  `PHASE_EVENTS: ${JSON.stringify(phaseEvents.slice(0, 50))}`,
50294
50292
  `PHASE_DECISIONS: ${JSON.stringify(keyDecisions)}`,
50295
50293
  `AGENTS_DISPATCHED: ${JSON.stringify(agentsDispatched)}`,
50296
50294
  `AGENTS_EXPECTED: ["reviewer", "test_engineer"]`,
50297
50295
  `KNOWLEDGE_ENTRIES: ${JSON.stringify(knowledgeForCurator)}`
50298
50296
  ].join(`
50299
- `);
50297
+ `));
50300
50298
  const timeoutMs = config.llm_timeout_ms ?? DEFAULT_CURATOR_LLM_TIMEOUT_MS;
50301
50299
  const ac = new AbortController;
50302
50300
  const timer = setTimeout(() => ac.abort(), timeoutMs);
@@ -50398,7 +50396,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
50398
50396
  }
50399
50397
  if (config.skill_generation_enabled === true && skillCandidates.length > 0) {
50400
50398
  try {
50401
- const skillModule = await import("./skill-generator-fzvp9m8z.js");
50399
+ const skillModule = await import("./skill-generator-dztn1ctf.js");
50402
50400
  for (const cand of skillCandidates) {
50403
50401
  if (cand.confidence < (config.min_skill_confidence ?? DEFAULT_SKILL_MIN_CONFIDENCE)) {
50404
50402
  continue;
@@ -50870,7 +50868,7 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
50870
50868
  } catch {}
50871
50869
  }
50872
50870
  if (contradictedEntries.length > 0 && knowledgeConfig.contradiction_threshold_action === "quarantine") {
50873
- const { maybeQuarantineOnContradiction } = await import("./knowledge-escalator-30bb9fyg.js");
50871
+ const { maybeQuarantineOnContradiction } = await import("./knowledge-escalator-7xcd0zea.js");
50874
50872
  for (const { id } of contradictedEntries) {
50875
50873
  try {
50876
50874
  await maybeQuarantineOnContradiction(directory, id, knowledgeConfig.contradiction_quarantine_threshold, knowledgeConfig.contradiction_quarantine_window_days);
@@ -51383,9 +51381,9 @@ async function repairPostMortemActions(llmOutput, diagnostics, options) {
51383
51381
  "Allowed queue_triage action values: apply, reject.",
51384
51382
  "Do not include unsupported actions such as merge.",
51385
51383
  "Diagnostics:",
51386
- diagnostics.join("; "),
51384
+ diagnostics.map((d) => sanitizeContextText(d)).join("; "),
51387
51385
  "Original output:",
51388
- llmOutput.slice(0, 8000)
51386
+ sanitizeContextText(llmOutput).slice(0, 8000)
51389
51387
  ].join(`
51390
51388
  `);
51391
51389
  const repaired = await options.llmDelegate("", repairPrompt, ac.signal);
@@ -51601,8 +51599,8 @@ function assembleLLMInput(planId, scope, sessionID, planSummary, knowledgeSummar
51601
51599
  const sections = [];
51602
51600
  sections.push(`TASK: CURATOR_POSTMORTEM ${planId}`);
51603
51601
  sections.push(`SCOPE: ${scope}${sessionID ? ` (${sessionID})` : ""}`);
51604
- sections.push(`PLAN_SUMMARY: ${planSummary}`);
51605
- sections.push(`CURATOR_DIGESTS: ${curatorDigest ?? "none"}`);
51602
+ sections.push(`PLAN_SUMMARY: ${sanitizeContextText(planSummary)}`);
51603
+ sections.push(`CURATOR_DIGESTS: ${sanitizeContextText(curatorDigest ?? "none")}`);
51606
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(`
51607
51605
  `);
51608
51606
  sections.push(`KNOWLEDGE_EVENTS_SUMMARY:
@@ -51633,9 +51631,9 @@ ${retroText}`);
51633
51631
  sections.push(`DRIFT_REPORTS:
51634
51632
  ${driftText}`);
51635
51633
  }
51636
- return sections.join(`
51634
+ return sanitizeContextText(sections.join(`
51637
51635
 
51638
- `);
51636
+ `));
51639
51637
  }
51640
51638
  async function runCuratorPostMortem(directory, options = {}) {
51641
51639
  const warnings = [];
@@ -51702,7 +51700,7 @@ async function runCuratorPostMortem(directory, options = {}) {
51702
51700
  warnings.push("Failed to collect knowledge summary.");
51703
51701
  }
51704
51702
  try {
51705
- const { getScanStatus } = await import("./scan-cursor-1m6dj2s2.js");
51703
+ const { getScanStatus } = await import("./scan-cursor-fgecb928.js");
51706
51704
  const scanStatus = await getScanStatus(directory);
51707
51705
  if (scanStatus.remaining_estimate > 0) {
51708
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.`);
@@ -51874,9 +51872,9 @@ var _internals57 = {
51874
51872
  verifyPostMortemKnowledgeActions,
51875
51873
  repairPostMortemActions,
51876
51874
  loadDefaultKnowledgeConfig: async (directory) => {
51877
- const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-yvhamv41.js");
51875
+ const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-zrcgm9d9.js");
51878
51876
  try {
51879
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-fa014mra.js");
51877
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-p6bvzgp2.js");
51880
51878
  const loaded = loadPluginConfigWithMeta2(directory);
51881
51879
  return KnowledgeConfigSchema2.parse(loaded.config.knowledge ?? {});
51882
51880
  } catch {
@@ -51884,11 +51882,11 @@ var _internals57 = {
51884
51882
  }
51885
51883
  },
51886
51884
  applyCuratorKnowledgeUpdates: async (directory, recommendations, knowledgeConfig, generation) => {
51887
- const { applyCuratorKnowledgeUpdates: applyCuratorKnowledgeUpdates2 } = await import("./curator-5k3mktpe.js");
51885
+ const { applyCuratorKnowledgeUpdates: applyCuratorKnowledgeUpdates2 } = await import("./curator-r0jfc7xw.js");
51888
51886
  return applyCuratorKnowledgeUpdates2(directory, recommendations, knowledgeConfig, generation);
51889
51887
  },
51890
51888
  checkHivePromotions: async (entries2, knowledgeConfig, directory) => {
51891
- const { checkHivePromotions } = await import("./hive-promoter-400xzdds.js");
51889
+ const { checkHivePromotions } = await import("./hive-promoter-0vg8w79a.js");
51892
51890
  return checkHivePromotions(entries2, knowledgeConfig, directory);
51893
51891
  },
51894
51892
  applyProposalTriage: async (directory, triage) => {
@@ -51897,7 +51895,7 @@ var _internals57 = {
51897
51895
  activateProposal,
51898
51896
  listSkills: listSkills2,
51899
51897
  sanitizeSlug
51900
- } = await import("./skill-generator-fzvp9m8z.js");
51898
+ } = await import("./skill-generator-dztn1ctf.js");
51901
51899
  const result = {
51902
51900
  approved: [],
51903
51901
  rejected: [],
@@ -51939,7 +51937,7 @@ var _internals57 = {
51939
51937
  return result;
51940
51938
  },
51941
51939
  readPriorDriftReports: async (directory) => {
51942
- const { readPriorDriftReports: readPriorDriftReports2 } = await import("./curator-drift-dt4g79a4.js");
51940
+ const { readPriorDriftReports: readPriorDriftReports2 } = await import("./curator-drift-q84jn9cc.js");
51943
51941
  return readPriorDriftReports2(directory);
51944
51942
  },
51945
51943
  readSwarmKnowledge: (directory) => readKnowledge(resolveSwarmKnowledgePath(directory))
@@ -61735,9 +61733,9 @@ var _internals67 = {
61735
61733
  loadPluginConfigWithMeta,
61736
61734
  loadCuratorDeps: async () => {
61737
61735
  const [{ CuratorConfigSchema }, curator, { createCuratorLLMDelegate }] = await Promise.all([
61738
- import("./schema-yvhamv41.js"),
61739
- import("./curator-5k3mktpe.js"),
61740
- import("./curator-llm-factory-hkk29g2y.js")
61736
+ import("./schema-zrcgm9d9.js"),
61737
+ import("./curator-r0jfc7xw.js"),
61738
+ import("./curator-llm-factory-13h02244.js")
61741
61739
  ]);
61742
61740
  return { CuratorConfigSchema, curator, createCuratorLLMDelegate };
61743
61741
  }
@@ -64130,7 +64128,7 @@ async function computeCurationDiagnostics(directory, entries2) {
64130
64128
  let scanCompleted = false;
64131
64129
  let scanRemaining = 0;
64132
64130
  try {
64133
- const { getScanStatus } = await import("./scan-cursor-1m6dj2s2.js");
64131
+ const { getScanStatus } = await import("./scan-cursor-fgecb928.js");
64134
64132
  const status = await getScanStatus(directory);
64135
64133
  scanGeneration = status.generation;
64136
64134
  scanCompleted = status.completed;
@@ -64140,10 +64138,10 @@ async function computeCurationDiagnostics(directory, entries2) {
64140
64138
  try {
64141
64139
  const { isLinked: isLinked2 } = await import("./knowledge-link-dv78fb9g.js");
64142
64140
  if (isLinked2(directory)) {
64143
- const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-yvhamv41.js");
64141
+ const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-zrcgm9d9.js");
64144
64142
  let config;
64145
64143
  try {
64146
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-fa014mra.js");
64144
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-p6bvzgp2.js");
64147
64145
  const loaded = loadPluginConfigWithMeta2(directory);
64148
64146
  config = KnowledgeConfigSchema2.parse(loaded.config.knowledge ?? {});
64149
64147
  } catch {
@@ -65598,7 +65596,7 @@ async function handleDoctorCommand(directory, args) {
65598
65596
  const result = runConfigDoctor(config, directory);
65599
65597
  let output;
65600
65598
  if (enableAutoFix && result.hasAutoFixableIssues) {
65601
- const { runConfigDoctorWithFixes } = await import("./config-doctor-3b99vx74.js");
65599
+ const { runConfigDoctorWithFixes } = await import("./config-doctor-28ggsms8.js");
65602
65600
  const fixResult = await runConfigDoctorWithFixes(directory, config, true, {
65603
65601
  applyLossy: true
65604
65602
  });
@@ -65636,7 +65634,7 @@ async function handleDoctorCommand(directory, args) {
65636
65634
  `;
65637
65635
  }
65638
65636
  try {
65639
- const { runModelPreflight } = await import("./model-preflight-g7b12yn2.js");
65637
+ const { runModelPreflight } = await import("./model-preflight-kap3zp3g.js");
65640
65638
  const preflight = await runModelPreflight(config, swarmState.opencodeClient, { generatedAgentNames: swarmState.generatedAgentNames });
65641
65639
  const missingSelection = preflight.resolutions.filter((resolution) => resolution.status === "missing-selection");
65642
65640
  const unresolved = preflight.catalogAvailable ? preflight.resolutions.filter((resolution) => resolution.status === "unresolved") : [];
@@ -66563,7 +66561,7 @@ async function handleEvidenceCommand(directory, args) {
66563
66561
  return formatTaskEvidenceMarkdown(evidenceData);
66564
66562
  }
66565
66563
  async function handleEvidenceSummaryCommand(directory) {
66566
- const { buildEvidenceSummary } = await import("./evidence-summary-service-8e2fghz0.js");
66564
+ const { buildEvidenceSummary } = await import("./evidence-summary-service-rsectw2t.js");
66567
66565
  const artifact = await buildEvidenceSummary(directory);
66568
66566
  if (!artifact) {
66569
66567
  return "No plan found. Run `/swarm plan` to check plan status.";
@@ -90896,7 +90894,7 @@ function createCuratorLLMDelegate(directory, mode = "init", sessionId) {
90896
90894
  }
90897
90895
  const sdkOpts = signal ? { signal } : {};
90898
90896
  try {
90899
- const { getSwarmAgents: getSwarmAgents2, resolveFallbackModel: resolveFallbackModel2 } = await import("./index-rtznwf0g.js");
90897
+ const { getSwarmAgents: getSwarmAgents2, resolveFallbackModel: resolveFallbackModel2 } = await import("./index-22f1ek6k.js");
90900
90898
  const createResult = await client.session.create({
90901
90899
  ...sessionId ? {
90902
90900
  body: {
@@ -91188,8 +91186,8 @@ init_zod();
91188
91186
  init_loader();
91189
91187
  import { createHash as createHash51, randomUUID as randomUUID22 } from "crypto";
91190
91188
  import * as fsSync9 from "fs";
91191
- import * as fs63 from "fs/promises";
91192
- import * as path127 from "path";
91189
+ import * as fs64 from "fs/promises";
91190
+ import * as path128 from "path";
91193
91191
  init_logger();
91194
91192
 
91195
91193
  // src/background/pr-feedback-event-queue.ts
@@ -92154,6 +92152,228 @@ var _internals98 = {
92154
92152
 
92155
92153
  // src/git/pr.ts
92156
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
92157
92377
  init_logger();
92158
92378
 
92159
92379
  // src/utils/untrusted-markdown.ts
@@ -92189,7 +92409,7 @@ var EvidencePlanSchema = exports_external.object({
92189
92409
  }).passthrough()).optional()
92190
92410
  }).passthrough();
92191
92411
  function ghExec(args, cwd) {
92192
- const ghBinary = _internals99.resolveGhExecutable();
92412
+ const ghBinary = _internals100.resolveGhExecutable();
92193
92413
  for (let attempt = 0;attempt < MAX_TRANSIENT_RETRIES; attempt++) {
92194
92414
  const result = child_process5.spawnSync(ghBinary, args, {
92195
92415
  cwd,
@@ -92245,12 +92465,18 @@ function spawnSyncWithTransientRetry(command, args, options) {
92245
92465
  throw new Error(`${command} exited with null`);
92246
92466
  }
92247
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) {
92248
92471
  return new Promise((resolve40, reject) => {
92249
- const ghBinary = _internals99.resolveGhExecutable();
92250
- const proc = child_process5.spawn(ghBinary, args, {
92472
+ const spawnOptions = {
92251
92473
  cwd,
92252
92474
  stdio: ["ignore", "pipe", "pipe"]
92253
- });
92475
+ };
92476
+ if (opts?.env) {
92477
+ spawnOptions.env = mergeEnvForChild(undefined, opts.env);
92478
+ }
92479
+ const proc = child_process5.spawn(binary, args, spawnOptions);
92254
92480
  const stdoutChunks = [];
92255
92481
  const stderrChunks = [];
92256
92482
  let stdoutBytes = 0;
@@ -92274,7 +92500,7 @@ async function ghExecAsync(args, cwd) {
92274
92500
  proc.stdout?.on("data", (chunk) => {
92275
92501
  stdoutBytes += chunk.length;
92276
92502
  if (stdoutBytes > MAX_OUTPUT_BYTES2) {
92277
- 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`)));
92278
92504
  return;
92279
92505
  }
92280
92506
  stdoutChunks.push(chunk);
@@ -92282,13 +92508,13 @@ async function ghExecAsync(args, cwd) {
92282
92508
  proc.stderr?.on("data", (chunk) => {
92283
92509
  stderrBytes += chunk.length;
92284
92510
  if (stderrBytes > MAX_OUTPUT_BYTES2) {
92285
- 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`)));
92286
92512
  return;
92287
92513
  }
92288
92514
  stderrChunks.push(chunk);
92289
92515
  });
92290
92516
  const timer = setTimeout(() => {
92291
- 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`)));
92292
92518
  }, GIT_TIMEOUT_MS5);
92293
92519
  proc.on("error", (err) => {
92294
92520
  settle2(() => reject(err));
@@ -92297,7 +92523,7 @@ async function ghExecAsync(args, cwd) {
92297
92523
  settle2(() => {
92298
92524
  if (code !== 0) {
92299
92525
  const stderr = Buffer.concat(stderrChunks).toString("utf-8");
92300
- reject(new Error(stderr || `gh exited with ${code}`));
92526
+ reject(new Error(stderr || `${label} exited with ${code}`));
92301
92527
  } else {
92302
92528
  const stdout = Buffer.concat(stdoutChunks).toString("utf-8");
92303
92529
  resolve40(stdout);
@@ -92306,20 +92532,24 @@ async function ghExecAsync(args, cwd) {
92306
92532
  });
92307
92533
  });
92308
92534
  }
92309
- var _internals99 = {
92535
+ var _internals100 = {
92310
92536
  ghExec,
92311
92537
  ghExecAsync,
92538
+ forgeExecAsync: forgeExecAsyncImpl,
92539
+ getMRPollSnapshot,
92540
+ getMRComments,
92312
92541
  spawnSyncWithTransientRetry,
92313
92542
  spawnSync: __spawnSyncSeam.spawnSync,
92314
92543
  readLaneEnvFileFromDiskSync,
92315
92544
  getMergeGroupRun,
92316
92545
  resolveGhExecutable,
92317
- resolveGitExecutable
92546
+ resolveGitExecutable,
92547
+ resolveGlabExecutable
92318
92548
  };
92319
92549
  async function getPRPollSnapshot(prNumber, repoFullName, cwd) {
92320
92550
  let stdout;
92321
92551
  try {
92322
- stdout = await _internals99.ghExecAsync([
92552
+ stdout = await _internals100.ghExecAsync([
92323
92553
  "pr",
92324
92554
  "view",
92325
92555
  String(prNumber),
@@ -92376,7 +92606,7 @@ function numericIssueCommentId(url, fallbackId, fallbacks) {
92376
92606
  async function getPRReviewComments(prNumber, repoFullName, cwd) {
92377
92607
  let stdout;
92378
92608
  try {
92379
- stdout = await _internals99.ghExecAsync(["api", `repos/${repoFullName}/pulls/${prNumber}/comments`], cwd);
92609
+ stdout = await _internals100.ghExecAsync(["api", `repos/${repoFullName}/pulls/${prNumber}/comments`], cwd);
92380
92610
  } catch (err) {
92381
92611
  throw new Error(`Failed to fetch review comments for ${repoFullName}#${prNumber}: ${err instanceof Error ? err.message : String(err)}`);
92382
92612
  }
@@ -92389,6 +92619,129 @@ async function getPRReviewComments(prNumber, repoFullName, cwd) {
92389
92619
  isReviewComment: true
92390
92620
  }));
92391
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
+ }
92392
92745
  async function getMergeGroupRun(statusCheckRollup, repoFullName, cwd) {
92393
92746
  const mergeGroupCheck = statusCheckRollup.find((check) => check.name === "Merge pull request" && check.detailsUrl);
92394
92747
  if (!mergeGroupCheck?.detailsUrl) {
@@ -92401,7 +92754,7 @@ async function getMergeGroupRun(statusCheckRollup, repoFullName, cwd) {
92401
92754
  const runId = runIdMatch[1];
92402
92755
  let stdout;
92403
92756
  try {
92404
- stdout = await _internals99.ghExecAsync([
92757
+ stdout = await _internals100.ghExecAsync([
92405
92758
  "run",
92406
92759
  "view",
92407
92760
  runId,
@@ -92430,7 +92783,7 @@ var registrationsByCanonical = new Map;
92430
92783
  function resolveRegistration(directory) {
92431
92784
  const lexical = canonicalRootKeyLexical(directory);
92432
92785
  try {
92433
- const freshKey = _internals100.canonicalRootKeyFresh(directory);
92786
+ const freshKey = _internals101.canonicalRootKeyFresh(directory);
92434
92787
  const canonical = registrationsByCanonical.get(freshKey);
92435
92788
  if (canonical)
92436
92789
  return canonical;
@@ -92452,8 +92805,10 @@ async function evaluatePrFeedbackCurrentHead(directory, repoFullName, prNumber)
92452
92805
  async function dispatchPrFeedbackOversight(input) {
92453
92806
  return await getPrFeedbackLoopRuntime(input.directory)?.dispatchOversight(input) ?? { dispatched: false, verdict: "unavailable", decision: "pending" };
92454
92807
  }
92455
- var _internals100 = {
92808
+ var _internals101 = {
92456
92809
  getPRPollSnapshot,
92810
+ getMRPollSnapshot,
92811
+ findSubscriptionRecordForPrUrl,
92457
92812
  dispatchEphemeralAgent,
92458
92813
  parseCriticResponseFields,
92459
92814
  canonicalRootKeyFresh,
@@ -92462,11 +92817,11 @@ var _internals100 = {
92462
92817
  };
92463
92818
 
92464
92819
  // src/background/pr-feedback-loop.ts
92465
- 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");
92466
92821
  var PR_FEEDBACK_CLEANUP_DIR = "pr-feedback-loop-cleanups";
92467
- var PR_FEEDBACK_EVIDENCE_DIR = path127.join(".swarm", "pr-feedback-evidence");
92822
+ var PR_FEEDBACK_EVIDENCE_DIR = path128.join(".swarm", "pr-feedback-evidence");
92468
92823
  var PR_FEEDBACK_LOOP_STATE_LOCK_FILENAME = "pr-feedback-loop-state.lock";
92469
- 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);
92470
92825
  var MAX_TRACKED_SESSIONS5 = 200;
92471
92826
  var MAX_IN_FLIGHT_SESSIONS = 64;
92472
92827
  var MAX_CANCELLATION_REQUESTS = 64;
@@ -92482,7 +92837,7 @@ var LoopStateSchema = exports_external.object({
92482
92837
  correlations: exports_external.record(exports_external.string(), exports_external.any()),
92483
92838
  sessionTerminals: exports_external.record(exports_external.string(), exports_external.any()).default({})
92484
92839
  });
92485
- var _internals101 = {
92840
+ var _internals102 = {
92486
92841
  async evaluateCurrentHead(directory, repoFullName, prNumber) {
92487
92842
  return evaluatePrFeedbackCurrentHead(directory, repoFullName, prNumber);
92488
92843
  },
@@ -92491,13 +92846,20 @@ var _internals101 = {
92491
92846
  },
92492
92847
  async performAuthorizedAction(input) {
92493
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
+ });
92494
92855
  await activatePrWorkflow(input.directory, input.sessionID, "PR_FEEDBACK", {
92495
92856
  requireCheckoutPreflight: true,
92496
- prUrl: input.event.prUrl
92857
+ prUrl: input.event.prUrl,
92858
+ forge: subscription?.forge
92497
92859
  });
92498
92860
  return {
92499
92861
  performed: true,
92500
- recordPath: path127.join(".swarm", "pr-feedback-loop-state.json")
92862
+ recordPath: path128.join(".swarm", "pr-feedback-loop-state.json")
92501
92863
  };
92502
92864
  } catch (err) {
92503
92865
  const message = err instanceof Error ? err.message : String(err);
@@ -92519,13 +92881,13 @@ var _internals101 = {
92519
92881
  listActive,
92520
92882
  isProcessAlive: isProcessAlive3,
92521
92883
  resetLoopStateLock() {
92522
- _internals101.beforeLoopStateLockWrite = undefined;
92884
+ _internals102.beforeLoopStateLockWrite = undefined;
92523
92885
  },
92524
92886
  loopStateLockRelativePath: () => PR_FEEDBACK_LOOP_STATE_LOCK_REL,
92525
92887
  reclaimAbandonedLoopStateLock,
92526
92888
  removeLoopStateLockIfOwned
92527
92889
  };
92528
- var defaultLoopInternals = { ..._internals101 };
92890
+ var defaultLoopInternals = { ..._internals102 };
92529
92891
  function emptyState2() {
92530
92892
  return {
92531
92893
  schemaVersion: 1,
@@ -92601,7 +92963,7 @@ function hasReservationIdentity(reservation) {
92601
92963
  return Boolean(reservation?.workflowInstanceId.trim() && Number.isInteger(reservation?.ownerPid) && (reservation?.ownerPid ?? 0) > 0);
92602
92964
  }
92603
92965
  async function readLoopState(directory) {
92604
- const file = path127.join(directory, PR_FEEDBACK_LOOP_STATE_REL);
92966
+ const file = path128.join(directory, PR_FEEDBACK_LOOP_STATE_REL);
92605
92967
  try {
92606
92968
  const raw = fsSync9.readFileSync(file, "utf-8");
92607
92969
  const parsed = LoopStateSchema.safeParse(JSON.parse(raw));
@@ -92632,7 +92994,7 @@ async function writeLoopState(directory, state) {
92632
92994
  }
92633
92995
  }
92634
92996
  state.updatedAt = new Date().toISOString();
92635
- 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);
92636
92998
  }
92637
92999
  async function withLoopStateLock(directory, fn) {
92638
93000
  const lock = await acquireLoopStateLock(directory);
@@ -92647,21 +93009,21 @@ async function acquireLoopStateLock(directory) {
92647
93009
  const verifiedStateDirectory = await ensurePrWorkflowSafeParentDirectory(directory, lockPath);
92648
93010
  for (let attempt = 0;attempt < LOOP_STATE_LOCK_MAX_ATTEMPTS; attempt++) {
92649
93011
  try {
92650
- const handle = await fs63.open(lockPath, "wx");
93012
+ const handle = await fs64.open(lockPath, "wx");
92651
93013
  const lock = {
92652
93014
  ownerToken: randomUUID22(),
92653
93015
  pid: process.pid,
92654
- createdAtMs: _internals101.now()
93016
+ createdAtMs: _internals102.now()
92655
93017
  };
92656
93018
  let writeError;
92657
93019
  try {
92658
- await _internals101.beforeLoopStateLockWrite?.();
93020
+ await _internals102.beforeLoopStateLockWrite?.();
92659
93021
  const [openedStat, pathStat, realLockPath] = await Promise.all([
92660
93022
  handle.stat({ bigint: true }),
92661
- fs63.lstat(lockPath, { bigint: true }),
92662
- fs63.realpath(lockPath)
93023
+ fs64.lstat(lockPath, { bigint: true }),
93024
+ fs64.realpath(lockPath)
92663
93025
  ]);
92664
- 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)) {
92665
93027
  throw new Error("BLOCKED: PR feedback loop state lock changed or escaped before initialization");
92666
93028
  }
92667
93029
  await handle.writeFile(JSON.stringify(lock), "utf8");
@@ -92702,17 +93064,17 @@ async function reclaimAbandonedLoopStateLock(lockPath) {
92702
93064
  lock = null;
92703
93065
  }
92704
93066
  if (lock) {
92705
- 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) {
92706
93068
  return false;
92707
93069
  }
92708
93070
  return removeLoopStateLockIfOwned(lockPath, lock.ownerToken);
92709
93071
  }
92710
93072
  try {
92711
- const stat14 = await fs63.stat(lockPath);
92712
- 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) {
92713
93075
  return false;
92714
93076
  }
92715
- await fs63.rm(lockPath, { force: true });
93077
+ await fs64.rm(lockPath, { force: true });
92716
93078
  return true;
92717
93079
  } catch (error2) {
92718
93080
  if (error2.code === "ENOENT")
@@ -92723,7 +93085,7 @@ async function reclaimAbandonedLoopStateLock(lockPath) {
92723
93085
  async function readLoopStateLock(lockPath) {
92724
93086
  let raw;
92725
93087
  try {
92726
- raw = await fs63.readFile(lockPath, "utf8");
93088
+ raw = await fs64.readFile(lockPath, "utf8");
92727
93089
  } catch (error2) {
92728
93090
  if (error2.code === "ENOENT")
92729
93091
  return null;
@@ -92747,7 +93109,7 @@ async function removeLoopStateLockIfOwned(lockPath, ownerToken) {
92747
93109
  if (!lock || lock.ownerToken !== ownerToken)
92748
93110
  return false;
92749
93111
  try {
92750
- await fs63.rm(lockPath);
93112
+ await fs64.rm(lockPath);
92751
93113
  return true;
92752
93114
  } catch {
92753
93115
  return false;
@@ -92765,7 +93127,7 @@ function sameFileIdentity4(left, right) {
92765
93127
  return left.dev === right.dev && left.ino === right.ino;
92766
93128
  }
92767
93129
  function normalizeComparablePath2(value) {
92768
- const normalized = path127.normalize(path127.resolve(value));
93130
+ const normalized = path128.normalize(path128.resolve(value));
92769
93131
  return process.platform === "win32" ? normalized.toLowerCase() : normalized;
92770
93132
  }
92771
93133
  function delay3(ms) {
@@ -92869,14 +93231,14 @@ async function cancelPrFeedbackLoopUnlocked(directory, sessionID, reason) {
92869
93231
  clearedEvents: []
92870
93232
  };
92871
93233
  try {
92872
- const { cancelPrFeedbackPublication: cancelPrFeedbackPublication2 } = await import("./pr-workflow-gate-qd5tfkak.js");
93234
+ const { cancelPrFeedbackPublication: cancelPrFeedbackPublication2 } = await import("./pr-workflow-gate-tdj50p2g.js");
92873
93235
  await cancelPrFeedbackPublication2(directory, sessionID, reason);
92874
93236
  } catch (err) {
92875
93237
  warn(`[pr-feedback-loop] cancelPrFeedbackPublication failed (fail-open): ${err instanceof Error ? err.message : String(err)}`);
92876
93238
  }
92877
93239
  try {
92878
93240
  await withLoopStateLock(directory, async () => {
92879
- const readResult = await _internals101.readState(directory);
93241
+ const readResult = await _internals102.readState(directory);
92880
93242
  if (isCorruptState(readResult)) {
92881
93243
  throw new Error("BLOCKED: loop state is corrupt during durable cancellation admission");
92882
93244
  }
@@ -92889,7 +93251,7 @@ async function cancelPrFeedbackLoopUnlocked(directory, sessionID, reason) {
92889
93251
  correlation.terminal = { state: "cancelled", reason };
92890
93252
  }
92891
93253
  const inFlight = correlation.inFlight;
92892
- const ownerAlive = inFlight && hasReservationIdentity(inFlight) ? _internals101.isProcessAlive(inFlight.ownerPid) : false;
93254
+ const ownerAlive = inFlight && hasReservationIdentity(inFlight) ? _internals102.isProcessAlive(inFlight.ownerPid) : false;
92893
93255
  const reclaimedReservation = Boolean(inFlight && (inFlight.actionStartedAt === undefined || !ownerAlive));
92894
93256
  if (reclaimedReservation) {
92895
93257
  correlation.inFlight = null;
@@ -92904,7 +93266,7 @@ async function cancelPrFeedbackLoopUnlocked(directory, sessionID, reason) {
92904
93266
  reason
92905
93267
  };
92906
93268
  }
92907
- await _internals101.writeState(directory, nextState);
93269
+ await _internals102.writeState(directory, nextState);
92908
93270
  return nextState;
92909
93271
  });
92910
93272
  } catch (err) {
@@ -92925,12 +93287,12 @@ async function cancelPrFeedbackLoopUnlocked(directory, sessionID, reason) {
92925
93287
  }
92926
93288
  }
92927
93289
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
92928
- 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`);
92929
93291
  try {
92930
- fsSync9.mkdirSync(path127.join(directory, ".swarm", PR_FEEDBACK_CLEANUP_DIR), {
93292
+ fsSync9.mkdirSync(path128.join(directory, ".swarm", PR_FEEDBACK_CLEANUP_DIR), {
92931
93293
  recursive: true
92932
93294
  });
92933
- fsSync9.writeFileSync(path127.join(directory, receipt.path), JSON.stringify({
93295
+ fsSync9.writeFileSync(path128.join(directory, receipt.path), JSON.stringify({
92934
93296
  schemaVersion: 1,
92935
93297
  at: new Date().toISOString(),
92936
93298
  sessionID,
@@ -92982,228 +93344,6 @@ ${USAGE14}`;
92982
93344
 
92983
93345
  // src/background/pr-monitor-worker.ts
92984
93346
  init_warning_buffer();
92985
-
92986
- // src/utils/glab-executable.ts
92987
- init_warning_buffer();
92988
- import { spawnSync as spawnSync6 } from "child_process";
92989
- import * as fs64 from "fs";
92990
- import * as os14 from "os";
92991
- import * as path128 from "path";
92992
- var GLAB_BINARY_ENV_VAR = "OPENCODE_SWARM_GLAB_BINARY";
92993
- var PER_PROBE_TIMEOUT_MS2 = 250;
92994
- var TOTAL_BUDGET_MS3 = 1000;
92995
- var NEGATIVE_CACHE_TTL_MS2 = 60000;
92996
- var BARE_GLAB = "glab";
92997
- var PROBE_MAX_BUFFER_BYTES2 = 64 * 1024;
92998
- var PROBE_OUTPUT_EXCERPT_CHARS2 = 60;
92999
- var WINDOWS_PATH_EXTENSIONS2 = [".exe", ".cmd", ".bat"];
93000
- var GLAB_VERSION_PATTERN = /^glab version \d+\.\d+/;
93001
- function excerptProbeOutput2(raw) {
93002
- return raw.slice(0, PROBE_OUTPUT_EXCERPT_CHARS2).replace(/[^\x20-\x7E]/g, " ").trim();
93003
- }
93004
- var cache3 = null;
93005
- var lastAttempts2 = [];
93006
- var cacheGeneration2 = 0;
93007
- function windowsGlabAbsoluteCandidates(env) {
93008
- const candidates = [];
93009
- const push = (...parts) => {
93010
- const candidate2 = path128.join(...parts);
93011
- if (!candidates.includes(candidate2))
93012
- candidates.push(candidate2);
93013
- };
93014
- if (env.ProgramFiles) {
93015
- push(env.ProgramFiles, "GitLab CLI", "glab.exe");
93016
- }
93017
- if (env["ProgramFiles(x86)"]) {
93018
- push(env["ProgramFiles(x86)"], "GitLab CLI", "glab.exe");
93019
- }
93020
- if (env.LOCALAPPDATA) {
93021
- push(env.LOCALAPPDATA, "GitLab CLI", "glab.exe");
93022
- push(env.LOCALAPPDATA, "Programs", "GitLab CLI", "glab.exe");
93023
- }
93024
- return candidates;
93025
- }
93026
- function platformCandidates2(platform, env) {
93027
- if (platform === "win32") {
93028
- return windowsGlabAbsoluteCandidates(env);
93029
- }
93030
- if (platform === "darwin") {
93031
- return ["/opt/homebrew/bin/glab", "/usr/local/bin/glab", "/usr/bin/glab"];
93032
- }
93033
- return ["/usr/bin/glab", "/usr/local/bin/glab", "/bin/glab"];
93034
- }
93035
- function isAbsoluteForPlatform2(candidate2, platform) {
93036
- return platform === "win32" ? path128.win32.isAbsolute(candidate2) : path128.posix.isAbsolute(candidate2);
93037
- }
93038
- function joinDirAndName2(dir, name, platform) {
93039
- const sep22 = platform === "win32" ? "\\" : "/";
93040
- const trimmed = dir.replace(/[\\/]+$/, "");
93041
- return trimmed ? `${trimmed}${sep22}${name}` : `${sep22}${name}`;
93042
- }
93043
- function pathCandidates2(platform) {
93044
- const pathValue = _internals102.env().PATH ?? "";
93045
- if (!pathValue)
93046
- return [];
93047
- const dirs = pathValue.split(platform === "win32" ? ";" : ":").filter(Boolean);
93048
- const names = platform === "win32" ? [...WINDOWS_PATH_EXTENSIONS2.map((ext) => `glab${ext}`), "glab"] : ["glab"];
93049
- const out = [];
93050
- for (const dir of dirs) {
93051
- for (const name of names) {
93052
- const candidate2 = joinDirAndName2(dir, name, platform);
93053
- if (!out.includes(candidate2))
93054
- out.push(candidate2);
93055
- }
93056
- }
93057
- return out;
93058
- }
93059
- function envOverride2() {
93060
- const raw = _internals102.env()[GLAB_BINARY_ENV_VAR];
93061
- return raw && raw.trim() !== "" ? raw : undefined;
93062
- }
93063
- function buildCandidates2(platform) {
93064
- const override = envOverride2();
93065
- const overrideCandidate = override ? [{ source: "override", path: override }] : [];
93066
- const seen = new Set(overrideCandidate.map((c) => c.path));
93067
- const rest = [];
93068
- for (const p of platformCandidates2(platform, _internals102.env())) {
93069
- if (seen.has(p))
93070
- continue;
93071
- seen.add(p);
93072
- rest.push({ source: "platform", path: p });
93073
- }
93074
- for (const p of pathCandidates2(platform)) {
93075
- if (seen.has(p))
93076
- continue;
93077
- seen.add(p);
93078
- rest.push({ source: "path", path: p });
93079
- }
93080
- return [...overrideCandidate, ...rest];
93081
- }
93082
- function probeCandidate2(candidatePath2, platform) {
93083
- if (!isAbsoluteForPlatform2(candidatePath2, platform)) {
93084
- return { accepted: false, reason: "not an absolute path" };
93085
- }
93086
- let stat14;
93087
- try {
93088
- stat14 = fs64.statSync(candidatePath2);
93089
- } catch (err) {
93090
- const code = err?.code;
93091
- if (code === "ENOENT")
93092
- return { accepted: false, reason: "no such file" };
93093
- return {
93094
- accepted: false,
93095
- reason: `cannot stat (${code ?? "unknown error"})`
93096
- };
93097
- }
93098
- if (stat14.isDirectory()) {
93099
- return { accepted: false, reason: "is a directory" };
93100
- }
93101
- if (!stat14.isFile()) {
93102
- return { accepted: false, reason: "not a regular file" };
93103
- }
93104
- let result;
93105
- try {
93106
- result = _internals102.spawnSync(candidatePath2, ["--version"], {
93107
- cwd: os14.tmpdir(),
93108
- stdio: ["ignore", "pipe", "ignore"],
93109
- windowsHide: true,
93110
- timeout: PER_PROBE_TIMEOUT_MS2,
93111
- maxBuffer: PROBE_MAX_BUFFER_BYTES2
93112
- });
93113
- } catch (err) {
93114
- return {
93115
- accepted: false,
93116
- reason: `spawn threw: ${err instanceof Error ? err.message : String(err)}`
93117
- };
93118
- }
93119
- if (result.error) {
93120
- return { accepted: false, reason: `spawn failed: ${result.error.message}` };
93121
- }
93122
- if (result.status !== 0) {
93123
- const statusDescription = result.status !== null ? `exit ${result.status}` : `signal ${result.signal ?? "unknown"}`;
93124
- return {
93125
- accepted: false,
93126
- reason: `glab --version returned ${statusDescription}`
93127
- };
93128
- }
93129
- const versionOutput = (result.stdout ?? "").toString().trim();
93130
- if (!GLAB_VERSION_PATTERN.test(versionOutput)) {
93131
- const excerpt = excerptProbeOutput2(versionOutput);
93132
- return {
93133
- accepted: false,
93134
- reason: excerpt ? `not glab: --version printed "${excerpt}"` : "not glab: --version printed nothing"
93135
- };
93136
- }
93137
- return { accepted: true };
93138
- }
93139
- function probeCycle2(candidates, platform, attempts) {
93140
- const start = _internals102.now();
93141
- let budgetExceeded = false;
93142
- for (const candidate2 of candidates) {
93143
- if (_internals102.now() - start > TOTAL_BUDGET_MS3) {
93144
- budgetExceeded = true;
93145
- break;
93146
- }
93147
- const result = probeCandidate2(candidate2.path, platform);
93148
- attempts.push({
93149
- source: candidate2.source,
93150
- candidate: candidate2.path,
93151
- accepted: result.accepted,
93152
- reason: result.accepted ? undefined : result.reason
93153
- });
93154
- if (candidate2.source === "override" && !result.accepted) {
93155
- advisoryWarn(`[opencode-swarm] ${GLAB_BINARY_ENV_VAR} override "${candidate2.path}" is unusable (${result.reason}); falling back to automatic glab resolution.`);
93156
- }
93157
- if (result.accepted) {
93158
- return { outcome: "accepted", path: candidate2.path };
93159
- }
93160
- }
93161
- return budgetExceeded ? { outcome: "exhausted-budget" } : { outcome: "all-rejected" };
93162
- }
93163
- function readCache3() {
93164
- if (cache3 === null)
93165
- return null;
93166
- if (cache3.kind === "success")
93167
- return cache3;
93168
- if (_internals102.now() < cache3.expiresAt)
93169
- return cache3;
93170
- cache3 = null;
93171
- return null;
93172
- }
93173
- function applyProbeResult2(result, attempts, generation) {
93174
- if (generation !== cacheGeneration2) {
93175
- return result.outcome === "accepted" ? result.path : BARE_GLAB;
93176
- }
93177
- lastAttempts2 = attempts;
93178
- if (result.outcome === "accepted") {
93179
- cache3 = { kind: "success", path: result.path };
93180
- return result.path;
93181
- }
93182
- cache3 = {
93183
- kind: "fallback",
93184
- expiresAt: _internals102.now() + NEGATIVE_CACHE_TTL_MS2
93185
- };
93186
- return BARE_GLAB;
93187
- }
93188
- function resolveGlabExecutable() {
93189
- const cached = readCache3();
93190
- if (cached)
93191
- return cached.kind === "success" ? cached.path : BARE_GLAB;
93192
- const platform = _internals102.platform();
93193
- const attempts = [];
93194
- const generation = cacheGeneration2;
93195
- const candidates = buildCandidates2(platform);
93196
- const result = probeCycle2(candidates, platform, attempts);
93197
- return applyProbeResult2(result, attempts, generation);
93198
- }
93199
- var _internals102 = {
93200
- spawnSync: spawnSync6,
93201
- platform: () => process.platform,
93202
- env: () => process.env,
93203
- now: () => Date.now()
93204
- };
93205
-
93206
- // src/background/pr-monitor-worker.ts
93207
93347
  var prMonitorWorkerRegistry = new Map;
93208
93348
  function getPrMonitorWorkerHealth(directory) {
93209
93349
  return prMonitorWorkerRegistry.get(directory)?.getHealth() ?? null;
@@ -93413,12 +93553,7 @@ class PrMonitorWorker {
93413
93553
  async pollSinglePr(sub, isTimedOut, isProbe = false) {
93414
93554
  const correlationId = sub.correlationId;
93415
93555
  const forgeContext = detectForgeFromUrl(sub.prUrl) ?? (sub.forge ? { provider: sub.forge.provider, host: sub.forge.host } : null);
93416
- if (forgeContext && !getProviderCapabilities(forgeContext.provider).statusCheckRollup && !getProviderCapabilities(forgeContext.provider).reviewDecision && !getProviderCapabilities(forgeContext.provider).mergeStateStatus) {
93417
- const glabBinary = resolveGlabExecutable();
93418
- const glabStatus = glabBinary === "glab" ? "glab binary not resolved (bare-name fallback)" : "glab binary resolved";
93419
- log("[PrMonitorWorker] GitLab MR monitoring unavailable: glab-backed polling is not wired yet (issue #2882); skipping gh poll for this subscription", { correlationId, glabStatus });
93420
- return;
93421
- }
93556
+ const isGitLab = forgeContext?.provider === "gitlab";
93422
93557
  if (!this.circuitBreakerMap.has(correlationId) && sub.errorCount > 0) {
93423
93558
  this.circuitBreakerMap.set(correlationId, {
93424
93559
  errorCount: sub.errorCount,
@@ -93443,40 +93578,76 @@ class PrMonitorWorker {
93443
93578
  return;
93444
93579
  }
93445
93580
  try {
93446
- const [snapshot, reviewComments] = await Promise.all([
93447
- _internals103.getPRPollSnapshot(sub.prNumber, sub.repoFullName, this.directory),
93448
- _internals103.getPRReviewComments(sub.prNumber, sub.repoFullName, this.directory)
93449
- ]);
93450
- if (isTimedOut?.()) {
93451
- log("[PrMonitorWorker] Skipping late result \u2014 poll already timed out", {
93452
- correlationId: sub.correlationId
93453
- });
93454
- return;
93455
- }
93456
- let mergeGroupRunResult = null;
93457
- let mergeGroupRunFetchSucceeded = false;
93458
- try {
93459
- mergeGroupRunResult = await _internals103.getMergeGroupRun(snapshot.status.statusCheckRollup, sub.repoFullName, this.directory);
93460
- mergeGroupRunFetchSucceeded = true;
93461
- } catch (err) {
93462
- log("[PrMonitorWorker] Failed to fetch merge group run", {
93463
- correlationId: sub.correlationId,
93464
- error: err instanceof Error ? err.message : String(err)
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
93465
93588
  });
93466
- }
93467
- if (isTimedOut?.()) {
93468
- log("[PrMonitorWorker] Skipping late result \u2014 poll already timed out", {
93469
- 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
93470
93614
  });
93471
- 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);
93472
93650
  }
93473
- const changes = this.computeChanges(sub, {
93474
- status: snapshot.status,
93475
- comments: [...snapshot.comments, ...reviewComments],
93476
- merge: snapshot.merge,
93477
- review: snapshot.review,
93478
- mergeGroupRun: mergeGroupRunResult
93479
- }, mergeGroupRunFetchSucceeded);
93480
93651
  await this.applyChanges(sub, changes, isTimedOut);
93481
93652
  if (!isTimedOut?.()) {
93482
93653
  this.circuitBreakerMap.delete(correlationId);
@@ -93512,7 +93683,7 @@ class PrMonitorWorker {
93512
93683
  await this.handlePollError(sub, err instanceof Error ? err : new Error(String(err)));
93513
93684
  }
93514
93685
  }
93515
- computeChanges(sub, current, mergeGroupRunFetchSucceeded) {
93686
+ computeChanges(sub, current, mergeGroupRunFetchSucceeded, gitLabPipelines) {
93516
93687
  const events = [];
93517
93688
  const snapshotUpdates = {
93518
93689
  headRefOid: current.status.headRefOid,
@@ -93539,13 +93710,17 @@ class PrMonitorWorker {
93539
93710
  }
93540
93711
  });
93541
93712
  }
93542
- const currentCheckSet = this.serializeChecks(current.status.statusCheckRollup);
93543
- snapshotUpdates.lastCheckRunSet = currentCheckSet;
93544
- if (sub.lastCheckRunSet !== undefined && currentCheckSet !== sub.lastCheckRunSet) {
93545
- const prevChecks = this.parseCheckSet(sub.lastCheckRunSet);
93546
- 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;
93547
93723
  }
93548
- snapshotUpdates.lastCheckRunSet = currentCheckSet;
93549
93724
  if (current.comments.length > 0) {
93550
93725
  const sorted2 = [...current.comments].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
93551
93726
  let newComments;
@@ -93877,6 +94052,8 @@ class PrMonitorWorker {
93877
94052
  var _internals103 = {
93878
94053
  getPRPollSnapshot,
93879
94054
  getPRReviewComments,
94055
+ getMRPollSnapshot,
94056
+ getMRComments,
93880
94057
  getMergeGroupRun,
93881
94058
  listActive,
93882
94059
  updateSnapshot,
@@ -94240,11 +94417,10 @@ async function handlePrSubscribeCommand(directory, args, sessionID) {
94240
94417
  deliveryLine
94241
94418
  ].concat(prUrl.includes("/-/merge_requests/") ? [
94242
94419
  "",
94243
- "Note: live monitoring is NOT AVAILABLE for GitLab merge",
94244
- "requests yet \u2014 glab-backed polling is tracked as issue #2882.",
94245
- "The subscription is recorded and PR reference/gate/",
94246
- "publication workflows operate on this MR, but no CI/comment/",
94247
- "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)."
94248
94424
  ] : []).join(`
94249
94425
  `);
94250
94426
  } catch (err) {
@@ -109309,7 +109485,7 @@ function buildDetailedHelp(commandName, entry) {
109309
109485
  async function handleHelpCommand(ctx) {
109310
109486
  const targetCommand = ctx.args.join(" ");
109311
109487
  if (!targetCommand) {
109312
- const { buildHelpText } = await import("./index-r9zc92pb.js");
109488
+ const { buildHelpText } = await import("./index-4dwhfbed.js");
109313
109489
  return buildHelpText();
109314
109490
  }
109315
109491
  const tokens = targetCommand.split(/\s+/);
@@ -109323,7 +109499,7 @@ async function handleHelpCommand(ctx) {
109323
109499
  > Note: \`/swarm ${resolved.key}\` is a deprecated alias for \`/swarm ${aliasTarget}\`.` : detailed;
109324
109500
  }
109325
109501
  const similar = _internals27.findSimilarCommands(targetCommand);
109326
- const { buildHelpText: fullHelp } = await import("./index-r9zc92pb.js");
109502
+ const { buildHelpText: fullHelp } = await import("./index-4dwhfbed.js");
109327
109503
  if (similar.length > 0) {
109328
109504
  return `Command '/swarm ${targetCommand}' not found.
109329
109505
 
@@ -109358,6 +109534,18 @@ async function handleModeCommandWithBundledSkills(ctx, handler, mechanicalMode)
109358
109534
  }
109359
109535
  return result;
109360
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
+ }
109361
109549
  async function handlePrFeedbackCommandWithTransition(ctx) {
109362
109550
  if (ctx.packageRoot) {
109363
109551
  await syncBundledProjectSkillsIfMissingAsync(ctx.directory, ctx.packageRoot, true);
@@ -109388,7 +109576,8 @@ async function handlePrFeedbackCommandWithTransition(ctx) {
109388
109576
  } else {
109389
109577
  await activatePrWorkflow(ctx.directory, ctx.sessionID, "PR_FEEDBACK", {
109390
109578
  requireCheckoutPreflight: true,
109391
- ...parsed.prUrl ? { prUrl: parsed.prUrl } : {}
109579
+ ...parsed.prUrl ? { prUrl: parsed.prUrl } : {},
109580
+ ...parsed.prUrl ? { forge: resolveCommandForgeContext(ctx.directory, parsed.prUrl) } : {}
109392
109581
  });
109393
109582
  }
109394
109583
  return handlePrFeedbackCommand(ctx.directory, ctx.args);
@@ -109638,7 +109827,7 @@ var COMMAND_REGISTRY = {
109638
109827
  },
109639
109828
  "guardrail explain": {
109640
109829
  handler: async (ctx) => {
109641
- const { handleGuardrailExplain } = await import("./guardrail-explain-ma658hkw.js");
109830
+ const { handleGuardrailExplain } = await import("./guardrail-explain-njv3pnsw.js");
109642
109831
  return handleGuardrailExplain(ctx.directory, ctx.args);
109643
109832
  },
109644
109833
  description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
@@ -109648,7 +109837,7 @@ var COMMAND_REGISTRY = {
109648
109837
  },
109649
109838
  "guardrail reset": {
109650
109839
  handler: async (ctx) => {
109651
- const { handleGuardrailReset } = await import("./guardrail-reset-w41yndke.js");
109840
+ const { handleGuardrailReset } = await import("./guardrail-reset-11cvwgbe.js");
109652
109841
  return handleGuardrailReset(ctx.args, ctx.sessionID);
109653
109842
  },
109654
109843
  description: "Reset one exact active invocation/action circuit after repair",
@@ -109669,7 +109858,7 @@ var COMMAND_REGISTRY = {
109669
109858
  },
109670
109859
  "guardrail-log": {
109671
109860
  handler: async (ctx) => {
109672
- const { handleGuardrailLog } = await import("./guardrail-log-m6mydjet.js");
109861
+ const { handleGuardrailLog } = await import("./guardrail-log-r8zmh4rd.js");
109673
109862
  return handleGuardrailLog(ctx.directory, ctx.args);
109674
109863
  },
109675
109864
  description: "Read the guardrail decision log (use --blocks-only for blocks)",