opencode-swarm 7.184.17 → 7.185.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 (102) hide show
  1. package/README.md +1 -0
  2. package/binaries/win32-arm64/swarm-sandbox-runner.exe +0 -0
  3. package/binaries/win32-x64/swarm-sandbox-runner.exe +0 -0
  4. package/dist/background/pr-subscriptions.d.ts +18 -0
  5. package/dist/background/stage-b-dispatch-binding-store.d.ts +115 -0
  6. package/dist/cli/{auto-checkpoint-8whpytsm.js → auto-checkpoint-adn8bg66.js} +7 -7
  7. package/dist/cli/{checkpoint-zjtcn0tx.js → checkpoint-dvyx8gee.js} +14 -14
  8. package/dist/cli/{coder-settlement-0z8sr1ep.js → coder-settlement-95dv9r28.js} +10 -10
  9. package/dist/cli/{config-doctor-4zwh0dkn.js → config-doctor-f2jtx8y5.js} +2 -2
  10. package/dist/cli/{core-fqbga0z4.js → core-xn2epqfk.js} +3 -3
  11. package/dist/cli/{curation-policy-1rzheh1x.js → curation-policy-swnyg1jr.js} +4 -4
  12. package/dist/cli/{curator-fkebhqnh.js → curator-91rqz7xg.js} +39 -39
  13. package/dist/cli/{curator-drift-44ba54w1.js → curator-drift-qem70sry.js} +8 -8
  14. package/dist/cli/curator-llm-factory-tr6rabws.js +81 -0
  15. package/dist/cli/{evidence-summary-service-e6wesfq2.js → evidence-summary-service-n7ndpen0.js} +17 -17
  16. package/dist/cli/{gate-evidence-8chc9f8q.js → gate-evidence-ajh95p02.js} +5 -5
  17. package/dist/cli/guardrail-explain-cne2701m.js +82 -0
  18. package/dist/cli/{guardrail-log-t0ketv64.js → guardrail-log-b23sf549.js} +6 -6
  19. package/dist/cli/{guardrail-reset-rzva9emn.js → guardrail-reset-e6njf0hv.js} +39 -39
  20. package/dist/cli/{hive-promoter-h60dddna.js → hive-promoter-8dqvfwsx.js} +39 -39
  21. package/dist/cli/{index-7r3pkgma.js → index-1zpgtnhp.js} +1 -1
  22. package/dist/cli/{index-r472pepw.js → index-26nhk01d.js} +1 -1
  23. package/dist/cli/{index-cyn2cb6k.js → index-2e7h9yw5.js} +5 -5
  24. package/dist/cli/{index-naxrpyb0.js → index-2tv5zp9x.js} +7 -7
  25. package/dist/cli/{index-e708d35g.js → index-359w27b1.js} +4 -4
  26. package/dist/cli/{index-m1pqenq9.js → index-3fnpjy4g.js} +2 -2
  27. package/dist/cli/{index-0zjg4kt5.js → index-4ysdy8sx.js} +4 -4
  28. package/dist/cli/{index-bntwj2tp.js → index-580t912d.js} +2 -1
  29. package/dist/cli/{index-jtg0zsnx.js → index-62z1vsvf.js} +1 -1
  30. package/dist/cli/{index-gx03v1y5.js → index-6wy9m25t.js} +10 -10
  31. package/dist/cli/{index-8twhrz1w.js → index-73vnyt4b.js} +39 -39
  32. package/dist/cli/{index-cftva3pa.js → index-7jqnckzg.js} +1 -1
  33. package/dist/cli/{index-fxf3zhtq.js → index-97nbaxye.js} +1 -1
  34. package/dist/cli/{index-y8gxcmnj.js → index-9am1ry6w.js} +7 -7
  35. package/dist/cli/{index-y0534tfs.js → index-cah5ffkh.js} +5 -5
  36. package/dist/cli/{index-kxacpqwf.js → index-djen6c7q.js} +1 -1
  37. package/dist/cli/{index-drndbj24.js → index-e5wczpj3.js} +2 -2
  38. package/dist/cli/{index-pef8ay7c.js → index-erv39311.js} +2 -2
  39. package/dist/cli/{index-hk2cap4d.js → index-f3grtpy3.js} +3 -3
  40. package/dist/cli/{index-vs1y869b.js → index-fkzv0hj4.js} +41 -41
  41. package/dist/cli/{index-50q314wd.js → index-fmxty2h3.js} +2 -2
  42. package/dist/cli/{index-7rzgdcvc.js → index-gemq38en.js} +1 -1
  43. package/dist/cli/{index-dky6qwrk.js → index-gxjy9y0t.js} +2 -2
  44. package/dist/cli/{index-2y9b45jj.js → index-h5f5q60s.js} +1 -1
  45. package/dist/cli/{index-a7y29h92.js → index-hx9vyvx0.js} +3 -3
  46. package/dist/cli/{index-sfsydeh8.js → index-m7g4dsr4.js} +5 -5
  47. package/dist/cli/{index-ww747mdg.js → index-n0wyd905.js} +3 -3
  48. package/dist/cli/{index-yx5z4200.js → index-p544ppcp.js} +1 -1
  49. package/dist/cli/{index-m8342y3n.js → index-qccnny3g.js} +3 -3
  50. package/dist/cli/{index-tyzmjw2s.js → index-qqjqpmhj.js} +420 -9
  51. package/dist/cli/{index-hx4jkj05.js → index-rcx4kb02.js} +4 -4
  52. package/dist/cli/{index-48we80k1.js → index-rp0pyywc.js} +7 -7
  53. package/dist/cli/{index-denfahc5.js → index-s0c1wxtt.js} +1 -1
  54. package/dist/cli/{index-pwcbtbhd.js → index-s5xmvt3k.js} +1 -1
  55. package/dist/cli/{index-mfqge140.js → index-sz755xt1.js} +1 -1
  56. package/dist/cli/{index-dftztz4y.js → index-t9jr6zc7.js} +1 -1
  57. package/dist/cli/{index-4v60grax.js → index-tmd5j8kh.js} +4 -4
  58. package/dist/cli/{index-bktc2g9n.js → index-v5k5jw0r.js} +2 -2
  59. package/dist/cli/{index-wxr5me67.js → index-vfr3z9rv.js} +5 -1
  60. package/dist/cli/{index-0pvvktht.js → index-w7sftxdy.js} +8 -3
  61. package/dist/cli/{index-yydv4jfy.js → index-yg15df3b.js} +2 -2
  62. package/dist/cli/{index-pak3x772.js → index-zkm995wa.js} +1462 -1078
  63. package/dist/cli/{index-7n1pfpnj.js → index-zxm9h19f.js} +3 -3
  64. package/dist/cli/{index-4g4sr4ah.js → index-zyz0xp2b.js} +1 -1
  65. package/dist/cli/index.js +40 -40
  66. package/dist/cli/{knowledge-escalator-kdeqdj0h.js → knowledge-escalator-xdz6vg62.js} +11 -11
  67. package/dist/cli/{knowledge-events-6fs0tz97.js → knowledge-events-dnca00ye.js} +9 -9
  68. package/dist/cli/{knowledge-link-vvyfhhmr.js → knowledge-link-y653vvr8.js} +3 -3
  69. package/dist/cli/{knowledge-store-z3fee1x1.js → knowledge-store-yc20na25.js} +4 -4
  70. package/dist/cli/{knowledge-validator-sz1bmbvt.js → knowledge-validator-c2kfrqdy.js} +6 -6
  71. package/dist/cli/{mcp-e1cnm4k3.js → mcp-mefjep3p.js} +1 -1
  72. package/dist/cli/{model-preflight-936dhs10.js → model-preflight-5xcxc75n.js} +39 -39
  73. package/dist/cli/{pending-delegations-m0vf63yd.js → pending-delegations-emhmdkn4.js} +10 -10
  74. package/dist/cli/{pr-subscriptions-2gvfff4q.js → pr-subscriptions-amc1z05d.js} +10 -10
  75. package/dist/cli/{pr-workflow-gate-68rg74bk.js → pr-workflow-gate-gpq41zx9.js} +39 -39
  76. package/dist/cli/{runner-cwmgb9rw.js → runner-ss88pbb2.js} +4 -4
  77. package/dist/cli/{scan-cursor-qzsanqx4.js → scan-cursor-71gq82ez.js} +5 -5
  78. package/dist/cli/{schema-jx4v0hg7.js → schema-108trhk6.js} +3 -1
  79. package/dist/cli/{scope-persistence-qk1h0c13.js → scope-persistence-9gfgvy3p.js} +13 -13
  80. package/dist/cli/{server-z9az3wc5.js → server-pkk6y7fa.js} +39 -39
  81. package/dist/cli/{skill-generator-h0veywz6.js → skill-generator-7g6xjwhr.js} +13 -13
  82. package/dist/cli/{snapshot-coordination-init-mwrvch16.js → snapshot-coordination-init-pactfmsy.js} +39 -39
  83. package/dist/cli/{speckit-checkoff-skyray2c.js → speckit-checkoff-xyp4c36r.js} +4 -4
  84. package/dist/cli/{workspace-snapshot-gnwak61t.js → workspace-snapshot-0hffyjhd.js} +3 -3
  85. package/dist/cli/{worktree-collision-ownership-wvxm7q1h.js → worktree-collision-ownership-g26m4c10.js} +11 -11
  86. package/dist/cli/{worktree-isolation-bmzkxa64.js → worktree-isolation-52529c62.js} +39 -39
  87. package/dist/commands/_shared/url-security.d.ts +20 -9
  88. package/dist/commands/pr-ref.d.ts +44 -8
  89. package/dist/commands/pr-subscribe.d.ts +0 -8
  90. package/dist/commands/pr-unsubscribe.d.ts +2 -1
  91. package/dist/config/schema.d.ts +17 -0
  92. package/dist/hooks/delegation-gate.d.ts +5 -1
  93. package/dist/hooks/pr-auto-subscribe.d.ts +5 -4
  94. package/dist/index.js +519 -519
  95. package/dist/providers/forge-provider.d.ts +167 -0
  96. package/dist/providers/host-guards.d.ts +31 -0
  97. package/dist/utils/gh-executable.d.ts +10 -0
  98. package/dist/utils/glab-executable.d.ts +85 -0
  99. package/opencode-swarm.schema.json +19 -0
  100. package/package.json +1 -1
  101. package/dist/cli/curator-llm-factory-65qve6xk.js +0 -81
  102. package/dist/cli/guardrail-explain-2prdgvjk.js +0 -82
@@ -1,21 +1,21 @@
1
1
  // @bun
2
2
  import {
3
3
  validateSwarmPath
4
- } from "./index-dftztz4y.js";
4
+ } from "./index-t9jr6zc7.js";
5
5
  import {
6
6
  deleteCoordinationState,
7
7
  importCoordinationOnce,
8
8
  listCoordinationStates,
9
9
  transitionCoordinationState,
10
10
  withCoordinationTransaction
11
- } from "./index-cftva3pa.js";
11
+ } from "./index-7jqnckzg.js";
12
12
  import {
13
13
  getProjectDb,
14
14
  projectDbExists
15
- } from "./index-pwcbtbhd.js";
15
+ } from "./index-s5xmvt3k.js";
16
16
  import {
17
17
  observeStoreHealth
18
- } from "./index-yx5z4200.js";
18
+ } from "./index-p544ppcp.js";
19
19
  import {
20
20
  withEvidenceLock
21
21
  } from "./index-6cjpmvpa.js";
@@ -29,7 +29,7 @@ import {
29
29
  } from "./index-mc72pk74.js";
30
30
  import {
31
31
  atomicWriteSwarmFileSync
32
- } from "./index-bntwj2tp.js";
32
+ } from "./index-580t912d.js";
33
33
  import {
34
34
  exports_external,
35
35
  init_zod
@@ -43,6 +43,397 @@ init_zod();
43
43
  import { createHash } from "crypto";
44
44
  import * as fs from "fs";
45
45
  import * as path from "path";
46
+
47
+ // src/providers/host-guards.ts
48
+ var IPV4_PRIVATE = /^10\./;
49
+ var IPV4_LOOPBACK = /^127\./;
50
+ var IPV4_LINK_LOCAL = /^169\.254\./;
51
+ var IPV4_PRIVATE_172 = /^172\.(1[6-9]|2\d|3[0-1])\./;
52
+ var IPV4_PRIVATE_192 = /^192\.168\./;
53
+ var IPV4_ZERO_NETWORK = /^0\./;
54
+ var IPV6_LINK_LOCAL = /^fe80:/i;
55
+ var IPV6_UNIQUE_LOCAL = /^f[cd][0-9a-f]{2}:/i;
56
+ function containsControlCharacters(value) {
57
+ for (const ch of value) {
58
+ const cp = ch.codePointAt(0);
59
+ if (cp !== undefined && (cp <= 31 || cp === 127)) {
60
+ return true;
61
+ }
62
+ }
63
+ return false;
64
+ }
65
+ function hasNonAsciiHostname(hostname) {
66
+ for (const ch of hostname) {
67
+ const cp = ch.codePointAt(0);
68
+ if (cp !== undefined && cp > 127)
69
+ return true;
70
+ }
71
+ return false;
72
+ }
73
+ function isIpv4MappedPrivateHost(inner) {
74
+ if (IPV4_PRIVATE.test(inner) || IPV4_LOOPBACK.test(inner) || IPV4_LINK_LOCAL.test(inner) || IPV4_PRIVATE_172.test(inner) || IPV4_PRIVATE_192.test(inner) || IPV4_ZERO_NETWORK.test(inner)) {
75
+ return true;
76
+ }
77
+ const firstSegment = inner.split(":", 1)[0];
78
+ if (!firstSegment)
79
+ return false;
80
+ const firstWord = Number.parseInt(firstSegment, 16);
81
+ if (!Number.isFinite(firstWord))
82
+ return false;
83
+ return firstWord >= 0 && firstWord <= 255 || firstWord >= 2560 && firstWord <= 2815 || firstWord >= 32512 && firstWord <= 32767 || firstWord === 43518 || firstWord >= 44048 && firstWord <= 44063 || firstWord === 49320;
84
+ }
85
+ function isPrivateHost(url) {
86
+ const host = url.hostname.toLowerCase().replace(/^\[|\]$/g, "");
87
+ if (host === "localhost" || host === "::1" || host === "0.0.0.0" || IPV4_LOOPBACK.test(host) || IPV4_ZERO_NETWORK.test(host)) {
88
+ return true;
89
+ }
90
+ if (host.startsWith("localhost") || host === "localhost.com") {
91
+ return true;
92
+ }
93
+ if (host.endsWith(".localhost")) {
94
+ return true;
95
+ }
96
+ if (IPV4_PRIVATE.test(host) || IPV4_LINK_LOCAL.test(host) || IPV4_PRIVATE_172.test(host) || IPV4_PRIVATE_192.test(host) || IPV6_LINK_LOCAL.test(host) || IPV6_UNIQUE_LOCAL.test(host)) {
97
+ return true;
98
+ }
99
+ if (host.startsWith("::ffff:")) {
100
+ const inner = host.slice(7);
101
+ if (isIpv4MappedPrivateHost(inner)) {
102
+ return true;
103
+ }
104
+ }
105
+ return false;
106
+ }
107
+ function hasPunycodeLabel(host) {
108
+ const lower = host.toLowerCase();
109
+ return lower.split(".").some((label) => label.startsWith("xn--"));
110
+ }
111
+
112
+ // src/providers/forge-provider.ts
113
+ var GITHUB_CANONICAL_HOST = "github.com";
114
+ var GITLAB_PUBLIC_HOST = "gitlab.com";
115
+ function isGitLabIndicatingHost(host) {
116
+ const lower = host.toLowerCase();
117
+ if (lower === GITLAB_PUBLIC_HOST)
118
+ return true;
119
+ if (!lower.startsWith("gitlab."))
120
+ return false;
121
+ const remainder = lower.slice("gitlab.".length);
122
+ if (remainder.length === 0)
123
+ return false;
124
+ return remainder.split(".").every((label) => /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(label));
125
+ }
126
+ function isForgePrUrl(url, configured) {
127
+ return canonicalForgePrUrl(url, configured) !== null;
128
+ }
129
+ function detectForgeFromUrl(url, configured) {
130
+ try {
131
+ const parsed = new URL(url);
132
+ if (parsed.protocol !== "https:")
133
+ return null;
134
+ const host = parsed.hostname.toLowerCase();
135
+ if (hasUserinfo(parsed))
136
+ return null;
137
+ if (hasNonAsciiHostname(host) || hasPunycodeLabel(host))
138
+ return null;
139
+ if (isPrivateHost(parsed))
140
+ return null;
141
+ if (host === GITHUB_CANONICAL_HOST) {
142
+ return { provider: "github", host };
143
+ }
144
+ if (isGitLabIndicatingHost(host)) {
145
+ return { provider: "gitlab", host };
146
+ }
147
+ if (configured && configured.provider === "gitlab" && host === configured.host) {
148
+ return { provider: "gitlab", host };
149
+ }
150
+ return null;
151
+ } catch {
152
+ return null;
153
+ }
154
+ }
155
+ function hasUserinfo(parsed) {
156
+ return parsed.username !== "" || parsed.password !== "";
157
+ }
158
+ function isConfiguredGitLabHost(host, configured) {
159
+ return configured !== undefined && configured.provider === "gitlab" && host === configured.host;
160
+ }
161
+ var GITLAB_PROJECT_PATH_PATTERN = /^\/(.+)\/([^/]+)\/-\/(merge_requests|issues)\/(\d+)\/?$/;
162
+ function matchForgeResourceUrl(url, resource, configured) {
163
+ if (containsControlCharacters(url))
164
+ return null;
165
+ let parsed;
166
+ try {
167
+ parsed = new URL(url);
168
+ } catch {
169
+ return null;
170
+ }
171
+ if (parsed.protocol !== "https:")
172
+ return null;
173
+ if (hasUserinfo(parsed))
174
+ return null;
175
+ const host = parsed.hostname.toLowerCase();
176
+ if (hasNonAsciiHostname(host) || hasPunycodeLabel(host))
177
+ return null;
178
+ if (isPrivateHost(parsed))
179
+ return null;
180
+ try {
181
+ if (containsControlCharacters(decodeURIComponent(parsed.pathname))) {
182
+ return null;
183
+ }
184
+ } catch {
185
+ return null;
186
+ }
187
+ if (host === GITHUB_CANONICAL_HOST) {
188
+ const m = parsed.pathname.match(new RegExp(`^\\/([^/]+)\\/([^/]+)\\/${resource === "pull" ? "pull" : "issues"}\\/([0-9]+)\\/?$`));
189
+ if (!m)
190
+ return null;
191
+ if (containsControlCharacters(m[1]) || containsControlCharacters(m[2])) {
192
+ return null;
193
+ }
194
+ const number = Number.parseInt(m[3], 10);
195
+ if (!Number.isSafeInteger(number) || number <= 0)
196
+ return null;
197
+ return { provider: "github", host, owner: m[1], repo: m[2], number };
198
+ }
199
+ if (isGitLabIndicatingHost(host) || isConfiguredGitLabHost(host, configured)) {
200
+ const resourceSegment = resource === "pull" ? "merge_requests" : "issues";
201
+ const m = parsed.pathname.match(GITLAB_PROJECT_PATH_PATTERN);
202
+ if (!m || m[3] !== resourceSegment)
203
+ return null;
204
+ if (containsControlCharacters(m[1]) || containsControlCharacters(m[2])) {
205
+ return null;
206
+ }
207
+ const number = Number.parseInt(m[4], 10);
208
+ if (!Number.isSafeInteger(number) || number <= 0)
209
+ return null;
210
+ return { provider: "gitlab", host, owner: m[1], repo: m[2], number };
211
+ }
212
+ return null;
213
+ }
214
+ function parseForgeRemoteUrl(remoteUrl) {
215
+ const https = remoteUrl.match(/^https:\/\/([^/]+)\/(.+?)(?:\.git)?\/?$/i);
216
+ if (https) {
217
+ return remotePathResult(https[1], https[2]);
218
+ }
219
+ const ssh = remoteUrl.match(/^git@([^:/]+):(.+?)(?:\.git)?$/i);
220
+ if (ssh) {
221
+ return remotePathResult(ssh[1], ssh[2]);
222
+ }
223
+ return null;
224
+ }
225
+ function remotePathResult(rawHost, projectPath) {
226
+ const host = rawHost.toLowerCase();
227
+ if (!host || hasNonAsciiHostname(host) || hasPunycodeLabel(host))
228
+ return null;
229
+ if (!isGitLabIndicatingHost(host) && host !== GITHUB_CANONICAL_HOST) {
230
+ return null;
231
+ }
232
+ const segments = projectPath.split("/").filter((s) => s.length > 0);
233
+ if (segments.length < 2)
234
+ return null;
235
+ const repo = segments[segments.length - 1];
236
+ const owner = segments.slice(0, -1).join("/");
237
+ if (!owner || !repo)
238
+ return null;
239
+ if (containsControlCharacters(owner) || containsControlCharacters(repo)) {
240
+ return null;
241
+ }
242
+ return {
243
+ provider: host === GITHUB_CANONICAL_HOST ? "github" : "gitlab",
244
+ host,
245
+ owner,
246
+ repo
247
+ };
248
+ }
249
+ function buildPrUrl(ctx, owner, repo, number) {
250
+ if (ctx.provider === "gitlab") {
251
+ return `https://${ctx.host}/${owner}/${repo}/-/merge_requests/${number}`;
252
+ }
253
+ return `https://github.com/${owner}/${repo}/pull/${number}`;
254
+ }
255
+ function buildIssueUrl(ctx, owner, repo, number) {
256
+ if (ctx.provider === "gitlab") {
257
+ return `https://${ctx.host}/${owner}/${repo}/-/issues/${number}`;
258
+ }
259
+ return `https://github.com/${owner}/${repo}/issues/${number}`;
260
+ }
261
+ function canonicalForgePrUrl(value, configured) {
262
+ try {
263
+ const url = new URL(value);
264
+ if (url.protocol !== "https:")
265
+ return null;
266
+ if (hasUserinfo(url))
267
+ return null;
268
+ const host = url.hostname.toLowerCase();
269
+ if (hasNonAsciiHostname(host) || hasPunycodeLabel(host))
270
+ return null;
271
+ if (isPrivateHost(url))
272
+ return null;
273
+ if (host === GITHUB_CANONICAL_HOST) {
274
+ const m = url.pathname.match(/^\/([^/]+)\/([^/]+)\/pull\/(\d+)\/?$/);
275
+ if (!m)
276
+ return null;
277
+ const number = Number(m[3]);
278
+ if (!Number.isSafeInteger(number) || number <= 0)
279
+ return null;
280
+ return `github.com/${m[1].toLowerCase()}/${m[2].toLowerCase()}/pull/${number}`;
281
+ }
282
+ if (isGitLabIndicatingHost(host) || isConfiguredGitLabHost(host, configured)) {
283
+ const m = url.pathname.match(/^\/(.+)\/([^/]+)\/-\/merge_requests\/(\d+)\/?$/);
284
+ if (!m)
285
+ return null;
286
+ const number = Number(m[3]);
287
+ if (!Number.isSafeInteger(number) || number <= 0)
288
+ return null;
289
+ return `${host}/${m[1].toLowerCase()}/${m[2].toLowerCase()}/-/merge_requests/${number}`;
290
+ }
291
+ return null;
292
+ } catch {
293
+ return null;
294
+ }
295
+ }
296
+ function getProviderCapabilities(provider) {
297
+ if (provider === "gitlab") {
298
+ return {
299
+ statusCheckRollup: false,
300
+ reviewDecision: false,
301
+ mergeStateStatus: false
302
+ };
303
+ }
304
+ return {
305
+ statusCheckRollup: true,
306
+ reviewDecision: true,
307
+ mergeStateStatus: true
308
+ };
309
+ }
310
+ function resolveForgeContextFromPluginConfig(pluginConfig, remotes) {
311
+ if (!pluginConfig?.forge)
312
+ return null;
313
+ const forge = pluginConfig.forge;
314
+ const provider = forge.provider === "github" || forge.provider === "gitlab" || forge.provider === "auto" ? forge.provider : undefined;
315
+ const selection = resolveProviderSelection({
316
+ config: { provider, baseUrl: forge.base_url },
317
+ remotes
318
+ });
319
+ return selection.ok ? selection.context : null;
320
+ }
321
+ function invalidBaseUrlError(reason) {
322
+ return `Invalid forge.base_url (${reason}) \u2014 provider config rejected; base_url must be an HTTPS URL on a public, ASCII host and is never a trust whitelist.`;
323
+ }
324
+ function resolveProviderSelection(input) {
325
+ const provider = input.config?.provider ?? "auto";
326
+ const remotes = input.remotes;
327
+ let baseUrlHost;
328
+ const rawBaseUrl = input.config?.baseUrl ?? input.config?.base_url;
329
+ if (rawBaseUrl !== undefined) {
330
+ const raw = rawBaseUrl.trim();
331
+ let parsed;
332
+ try {
333
+ parsed = new URL(raw);
334
+ } catch {
335
+ return { ok: false, error: invalidBaseUrlError("not a valid URL") };
336
+ }
337
+ if (parsed.protocol !== "https:") {
338
+ return { ok: false, error: invalidBaseUrlError("must use HTTPS") };
339
+ }
340
+ const host = parsed.hostname.toLowerCase();
341
+ if (hasNonAsciiHostname(host) || hasPunycodeLabel(host)) {
342
+ return {
343
+ ok: false,
344
+ error: invalidBaseUrlError("non-ASCII (IDN) hosts are not allowed")
345
+ };
346
+ }
347
+ if (isPrivateHost(parsed)) {
348
+ return {
349
+ ok: false,
350
+ error: invalidBaseUrlError("private or localhost hosts are not allowed")
351
+ };
352
+ }
353
+ if (!host) {
354
+ return { ok: false, error: invalidBaseUrlError("empty host") };
355
+ }
356
+ baseUrlHost = host;
357
+ }
358
+ if (provider === "github") {
359
+ if (baseUrlHost !== undefined) {
360
+ return {
361
+ ok: false,
362
+ error: 'Provider config conflict: forge.provider is "github" but forge.base_url is set \u2014 GitHub has a fixed base (github.com) and accepts no override. Remove base_url or set provider to "gitlab".'
363
+ };
364
+ }
365
+ return {
366
+ ok: true,
367
+ context: { provider: "github", host: GITHUB_CANONICAL_HOST }
368
+ };
369
+ }
370
+ if (baseUrlHost !== undefined) {
371
+ return { ok: true, context: { provider: "gitlab", host: baseUrlHost } };
372
+ }
373
+ const gitlabHosts = new Set;
374
+ let sawGithub = false;
375
+ let sawUnrecognized = false;
376
+ for (const remote of remotes) {
377
+ const parsed = parseForgeRemoteUrl(remote);
378
+ if (!parsed) {
379
+ sawUnrecognized = true;
380
+ continue;
381
+ }
382
+ if (parsed.provider === "github") {
383
+ sawGithub = true;
384
+ } else {
385
+ gitlabHosts.add(parsed.host);
386
+ }
387
+ }
388
+ if (provider === "gitlab") {
389
+ if (gitlabHosts.size === 1 && !sawGithub && !sawUnrecognized) {
390
+ return {
391
+ ok: true,
392
+ context: { provider: "gitlab", host: [...gitlabHosts][0] }
393
+ };
394
+ }
395
+ return {
396
+ ok: false,
397
+ error: 'Provider config incomplete: forge.provider is "gitlab" but no forge.base_url is set and the git remotes do not unanimously indicate a single GitLab host \u2014 set forge.base_url (e.g. https://gitlab.example.com) in config.'
398
+ };
399
+ }
400
+ if (sawGithub && gitlabHosts.size > 0) {
401
+ return {
402
+ ok: false,
403
+ error: "Provider selection ambiguous: git remotes indicate both GitHub and GitLab \u2014 set forge.provider (and forge.base_url for self-hosted GitLab) explicitly in config."
404
+ };
405
+ }
406
+ if (sawUnrecognized) {
407
+ return {
408
+ ok: false,
409
+ error: "Provider selection ambiguous: a git remote host matches no recognized provider (generic self-hosted) \u2014 set forge.provider and forge.base_url explicitly in config."
410
+ };
411
+ }
412
+ if (sawGithub) {
413
+ return {
414
+ ok: true,
415
+ context: { provider: "github", host: GITHUB_CANONICAL_HOST }
416
+ };
417
+ }
418
+ if (gitlabHosts.size === 1) {
419
+ return {
420
+ ok: true,
421
+ context: { provider: "gitlab", host: [...gitlabHosts][0] }
422
+ };
423
+ }
424
+ if (gitlabHosts.size > 1) {
425
+ return {
426
+ ok: false,
427
+ error: "Provider selection ambiguous: git remotes indicate multiple different GitLab hosts \u2014 set forge.provider and forge.base_url explicitly in config."
428
+ };
429
+ }
430
+ return {
431
+ ok: false,
432
+ error: "Provider selection failed: no workflow-relevant git remote and no forge.base_url \u2014 set forge.provider (and forge.base_url for self-hosted GitLab) explicitly in config."
433
+ };
434
+ }
435
+
436
+ // src/background/pr-subscriptions.ts
46
437
  var PR_SUBSCRIPTIONS_FILE = "pr-monitor/subscriptions.jsonl";
47
438
  var PR_SUBSCRIPTIONS_CHECKPOINT_FILE = "pr-monitor/subscriptions.checkpoint.json";
48
439
  var PR_SUBSCRIPTIONS_AUDIT_FILE = "pr-monitor/subscriptions.audit.jsonl";
@@ -115,8 +506,12 @@ var RecordSchema = exports_external.object({
115
506
  correlationId: exports_external.string().min(1),
116
507
  sessionID: exports_external.string().min(1),
117
508
  prNumber: exports_external.number().int().positive(),
118
- repoFullName: exports_external.string().regex(/^[^/]+\/[^/]+$/, "Must be owner/repo format"),
119
- prUrl: exports_external.string().min(1).regex(/^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+$/, "Must be a valid GitHub PR URL"),
509
+ repoFullName: exports_external.string().regex(/^[^/\s]+(?:\/[^/\s]+)+$/, "Must be owner/repo format (GitLab nested namespaces allowed)"),
510
+ prUrl: exports_external.string().min(1),
511
+ forge: exports_external.object({
512
+ provider: exports_external.literal("gitlab"),
513
+ host: exports_external.string().min(1)
514
+ }).optional(),
120
515
  headRefOid: exports_external.string().optional(),
121
516
  lastCheckedAt: exports_external.number(),
122
517
  lastCommentId: exports_external.string().optional(),
@@ -134,7 +529,21 @@ var RecordSchema = exports_external.object({
134
529
  customPollIntervalSeconds: exports_external.number().int().positive().optional(),
135
530
  customFailureThreshold: exports_external.number().int().min(0).optional(),
136
531
  customCooldownSeconds: exports_external.number().int().min(0).optional()
137
- }).strict();
532
+ }).strict().superRefine((record, ctx) => {
533
+ if (isForgePrUrl(record.prUrl))
534
+ return;
535
+ if (record.forge && isForgePrUrl(record.prUrl, {
536
+ provider: record.forge.provider,
537
+ host: record.forge.host
538
+ })) {
539
+ return;
540
+ }
541
+ ctx.addIssue({
542
+ code: exports_external.ZodIssueCode.custom,
543
+ path: ["prUrl"],
544
+ message: "Must be a valid PR URL (GitHub /pull/N or GitLab /-/merge_requests/N)"
545
+ });
546
+ });
138
547
  var TerminalSummarySchema = exports_external.object({
139
548
  removed: exports_external.number().int().min(0),
140
549
  expired: exports_external.number().int().min(0),
@@ -2050,6 +2459,7 @@ async function subscribe(directory, input) {
2050
2459
  prNumber: input.prNumber,
2051
2460
  repoFullName: input.repoFullName,
2052
2461
  prUrl: input.prUrl,
2462
+ ...input.forge ? { forge: input.forge } : {},
2053
2463
  lastCheckedAt: now,
2054
2464
  isWatching: true,
2055
2465
  hasUnaddressedEvents: false,
@@ -2086,6 +2496,7 @@ async function subscribe(directory, input) {
2086
2496
  prNumber: input.prNumber,
2087
2497
  repoFullName: input.repoFullName,
2088
2498
  prUrl: input.prUrl,
2499
+ ...input.forge ? { forge: input.forge } : {},
2089
2500
  lastCheckedAt: now,
2090
2501
  isWatching: true,
2091
2502
  hasUnaddressedEvents: false,
@@ -2463,4 +2874,4 @@ var _internals = {
2463
2874
  writeCheckpointFile
2464
2875
  };
2465
2876
 
2466
- export { PR_SUBSCRIPTIONS_FILE, PR_SUBSCRIPTIONS_CHECKPOINT_FILE, PR_SUBSCRIPTIONS_AUDIT_FILE, PR_SUBSCRIPTION_LIMITS, setOnSubscriptionCreated, registerPrMonitorWorkerHandler, removePrMonitorWorkerHandler, ensurePrSubscriptionDispatcherInstalled, PrSubscriptionCapacityError, isPrSubscriptionCapacityError, buildCorrelationId, subscribe, unsubscribe, listActive, lookupByPr, updateSnapshot, sweepStale, getPrSubscriptionHealth, _internals };
2877
+ export { containsControlCharacters, hasNonAsciiHostname, isPrivateHost, detectForgeFromUrl, matchForgeResourceUrl, parseForgeRemoteUrl, buildPrUrl, buildIssueUrl, canonicalForgePrUrl, getProviderCapabilities, resolveForgeContextFromPluginConfig, PR_SUBSCRIPTIONS_FILE, PR_SUBSCRIPTIONS_CHECKPOINT_FILE, PR_SUBSCRIPTIONS_AUDIT_FILE, PR_SUBSCRIPTION_LIMITS, setOnSubscriptionCreated, registerPrMonitorWorkerHandler, removePrMonitorWorkerHandler, ensurePrSubscriptionDispatcherInstalled, PrSubscriptionCapacityError, isPrSubscriptionCapacityError, buildCorrelationId, subscribe, unsubscribe, listActive, lookupByPr, updateSnapshot, sweepStale, getPrSubscriptionHealth, _internals };
@@ -7,7 +7,7 @@ import {
7
7
  loadPlan,
8
8
  transientBackoff,
9
9
  updateTaskCheckpointReceipt
10
- } from "./index-gx03v1y5.js";
10
+ } from "./index-6wy9m25t.js";
11
11
  import {
12
12
  tool
13
13
  } from "./index-9nyqt3kb.js";
@@ -20,10 +20,10 @@ import {
20
20
  } from "./index-g4fs6z4e.js";
21
21
  import {
22
22
  readLedgerEvents
23
- } from "./index-a7y29h92.js";
23
+ } from "./index-hx9vyvx0.js";
24
24
  import {
25
25
  appendCoreEventSync
26
- } from "./index-7rzgdcvc.js";
26
+ } from "./index-gemq38en.js";
27
27
  import {
28
28
  derivePlanId,
29
29
  derivePlanIdentityHash
@@ -38,7 +38,7 @@ import {
38
38
  } from "./index-ejhxgyvm.js";
39
39
  import {
40
40
  loadPluginConfigWithMeta
41
- } from "./index-kxacpqwf.js";
41
+ } from "./index-djen6c7q.js";
42
42
  import {
43
43
  init_git_executable,
44
44
  resolveGitExecutable
@@ -1,19 +1,19 @@
1
1
  // @bun
2
2
  import {
3
3
  validateSwarmPath
4
- } from "./index-dftztz4y.js";
4
+ } from "./index-t9jr6zc7.js";
5
5
  import {
6
6
  observeReceiptTransition
7
- } from "./index-yx5z4200.js";
7
+ } from "./index-p544ppcp.js";
8
8
  import {
9
9
  resolveHiveEventsPath
10
10
  } from "./index-ae75rja9.js";
11
11
  import {
12
12
  resolveKnowledgeStoreDir
13
- } from "./index-4g4sr4ah.js";
13
+ } from "./index-zyz0xp2b.js";
14
14
  import {
15
15
  atomicWriteFile
16
- } from "./index-2y9b45jj.js";
16
+ } from "./index-h5f5q60s.js";
17
17
  import {
18
18
  assertProjectRoot
19
19
  } from "./index-t7hmqgjy.js";
@@ -28,11 +28,11 @@ import {
28
28
  } from "./index-7g4c7s5r.js";
29
29
  import {
30
30
  loadPluginConfigWithMeta
31
- } from "./index-kxacpqwf.js";
31
+ } from "./index-djen6c7q.js";
32
32
  import {
33
33
  KnowledgeConfigSchema,
34
34
  init_schema
35
- } from "./index-0pvvktht.js";
35
+ } from "./index-w7sftxdy.js";
36
36
  import {
37
37
  init_logger,
38
38
  warn
@@ -2946,7 +2946,7 @@ async function applyKnowledgeVerdictFeedback(directory, options) {
2946
2946
  }
2947
2947
  let bumps = 0;
2948
2948
  if (deltas.length > 0) {
2949
- const { bumpKnowledgeConfidenceBatch } = await import("./knowledge-store-z3fee1x1.js");
2949
+ const { bumpKnowledgeConfidenceBatch } = await import("./knowledge-store-yc20na25.js");
2950
2950
  bumps = await bumpKnowledgeConfidenceBatch(directory, deltas, options?.floorOptions);
2951
2951
  }
2952
2952
  return {
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  writeSpeckitCheckoffLedger
4
- } from "./index-50q314wd.js";
4
+ } from "./index-fmxty2h3.js";
5
5
  import {
6
6
  validateSpecContent
7
7
  } from "./index-0725jpp7.js";
@@ -11,7 +11,7 @@ import {
11
11
  } from "./index-mc72pk74.js";
12
12
  import {
13
13
  atomicWriteSwarmFileSync
14
- } from "./index-bntwj2tp.js";
14
+ } from "./index-580t912d.js";
15
15
 
16
16
  // src/db/project-db.ts
17
17
  import { existsSync, mkdirSync, unlinkSync } from "fs";
@@ -9,7 +9,7 @@ import {
9
9
  readEvaluationRun,
10
10
  saveEvaluationRun,
11
11
  saveTaskSetSnapshot
12
- } from "./index-jtg0zsnx.js";
12
+ } from "./index-62z1vsvf.js";
13
13
  import {
14
14
  canonicalHash,
15
15
  computeCandidateInputContentHash,
@@ -10,7 +10,7 @@ import {
10
10
  readCachedTextFile,
11
11
  wasObservedToExist,
12
12
  wasRecentlyWrittenByThisProcess
13
- } from "./index-bntwj2tp.js";
13
+ } from "./index-580t912d.js";
14
14
  import {
15
15
  warn
16
16
  } from "./index-zgwm4ryv.js";
@@ -3,7 +3,7 @@ import {
3
3
  EvaluationRunV1Schema,
4
4
  GateAuditResultV1Schema,
5
5
  getProtectedEvaluationRunIds
6
- } from "./index-jtg0zsnx.js";
6
+ } from "./index-62z1vsvf.js";
7
7
  import {
8
8
  TASK_WORKFLOW_SCHEMA_MARKER,
9
9
  deriveApplicableGateSet,
@@ -12,11 +12,11 @@ import {
12
12
  readTaskEvidence,
13
13
  readTaskEvidenceRaw,
14
14
  sanitizeTaskId
15
- } from "./index-m8342y3n.js";
15
+ } from "./index-qccnny3g.js";
16
16
  import {
17
17
  readSwarmFileAsync,
18
18
  validateSwarmPath
19
- } from "./index-dftztz4y.js";
19
+ } from "./index-t9jr6zc7.js";
20
20
  import {
21
21
  bunWrite
22
22
  } from "./index-2s7dvzff.js";
@@ -33,7 +33,7 @@ import {
33
33
  } from "./index-t7hmqgjy.js";
34
34
  import {
35
35
  invalidateCachedArtifact
36
- } from "./index-bntwj2tp.js";
36
+ } from "./index-580t912d.js";
37
37
  import {
38
38
  ZodError,
39
39
  init_zod
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  init_loader,
4
4
  loadPluginConfigWithMeta
5
- } from "./index-kxacpqwf.js";
5
+ } from "./index-djen6c7q.js";
6
6
  import {
7
7
  init_schema
8
- } from "./index-0pvvktht.js";
8
+ } from "./index-w7sftxdy.js";
9
9
  import {
10
10
  DEFAULT_WORKTREE_ISOLATION_CONFIG,
11
11
  init_constants
@@ -12,7 +12,7 @@ import {
12
12
  PluginConfigSchema,
13
13
  init_schema,
14
14
  stripKnownSwarmPrefix
15
- } from "./index-0pvvktht.js";
15
+ } from "./index-w7sftxdy.js";
16
16
  import {
17
17
  ALL_AGENT_NAMES,
18
18
  TOOL_NAME_SET,
@@ -1087,6 +1087,10 @@ function validateConfigKey(path2, value) {
1087
1087
  emitObjectTypeMismatch("docs", value, findings);
1088
1088
  break;
1089
1089
  }
1090
+ case "forge": {
1091
+ emitObjectTypeMismatch("forge", value, findings);
1092
+ break;
1093
+ }
1090
1094
  case "design_docs": {
1091
1095
  emitObjectTypeMismatch("design_docs", value, findings);
1092
1096
  break;