@route_33/opencode 0.4.7-rc.7 → 0.4.7-rc.9

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.
@@ -13,449 +13,6 @@ var __export = (target, all) => {
13
13
  __defProp(target, name, { get: all[name], enumerable: true });
14
14
  };
15
15
 
16
- // src/attribution/detect-worktree-root/detect-worktree-root.ts
17
- import * as fs from "node:fs";
18
- import * as path from "node:path";
19
- var detectWorktreeRoot;
20
- var init_detect_worktree_root = __esm({
21
- "src/attribution/detect-worktree-root/detect-worktree-root.ts"() {
22
- "use strict";
23
- detectWorktreeRoot = (startDirectory) => {
24
- let directory = fs.realpathSync(startDirectory);
25
- for (; ; ) {
26
- const gitEntry = path.join(directory, ".git");
27
- if (fs.existsSync(gitEntry)) {
28
- const entry = fs.statSync(gitEntry);
29
- if (entry.isDirectory() || entry.isFile()) {
30
- return directory;
31
- }
32
- }
33
- const parent = path.dirname(directory);
34
- if (parent === directory) {
35
- return void 0;
36
- }
37
- directory = parent;
38
- }
39
- };
40
- }
41
- });
42
-
43
- // src/attribution/detect-worktree-root/index.ts
44
- var init_detect_worktree_root2 = __esm({
45
- "src/attribution/detect-worktree-root/index.ts"() {
46
- "use strict";
47
- init_detect_worktree_root();
48
- }
49
- });
50
-
51
- // src/attribution/resolve-attribution-file/resolve-attribution-file.ts
52
- import * as fs2 from "node:fs";
53
- import * as path2 from "node:path";
54
- var resolveAttributionFile;
55
- var init_resolve_attribution_file = __esm({
56
- "src/attribution/resolve-attribution-file/resolve-attribution-file.ts"() {
57
- "use strict";
58
- init_detect_worktree_root2();
59
- resolveAttributionFile = (options) => {
60
- const worktreeRoot = detectWorktreeRoot(options.directory);
61
- if (worktreeRoot !== void 0) {
62
- return path2.join(worktreeRoot, ".opencode", "route33.attribution.json");
63
- }
64
- const fallbackRoots = {
65
- "return-undefined": void 0,
66
- "use-directory": fs2.realpathSync(options.directory)
67
- };
68
- const fallbackRoot = fallbackRoots[options.outsideWorktree];
69
- return fallbackRoot === void 0 ? void 0 : path2.join(fallbackRoot, ".opencode", "route33.attribution.json");
70
- };
71
- }
72
- });
73
-
74
- // src/attribution/resolve-attribution-file/index.ts
75
- var init_resolve_attribution_file2 = __esm({
76
- "src/attribution/resolve-attribution-file/index.ts"() {
77
- "use strict";
78
- init_resolve_attribution_file();
79
- }
80
- });
81
-
82
- // src/attribution/clear-attribution/clear-attribution.ts
83
- import * as fs3 from "node:fs";
84
- var clearAttribution;
85
- var init_clear_attribution = __esm({
86
- "src/attribution/clear-attribution/clear-attribution.ts"() {
87
- "use strict";
88
- init_resolve_attribution_file2();
89
- clearAttribution = (options) => {
90
- const file = resolveAttributionFile(options);
91
- if (file === void 0) {
92
- return false;
93
- }
94
- fs3.rmSync(file, { force: true });
95
- return true;
96
- };
97
- }
98
- });
99
-
100
- // src/attribution/clear-attribution/index.ts
101
- var init_clear_attribution2 = __esm({
102
- "src/attribution/clear-attribution/index.ts"() {
103
- "use strict";
104
- init_clear_attribution();
105
- }
106
- });
107
-
108
- // src/contract/adapters/contract-parse-error/contract-parse-error.ts
109
- var ContractParseError;
110
- var init_contract_parse_error = __esm({
111
- "src/contract/adapters/contract-parse-error/contract-parse-error.ts"() {
112
- "use strict";
113
- ContractParseError = class extends Error {
114
- };
115
- }
116
- });
117
-
118
- // src/contract/adapters/contract-parse-error/index.ts
119
- var init_contract_parse_error2 = __esm({
120
- "src/contract/adapters/contract-parse-error/index.ts"() {
121
- "use strict";
122
- init_contract_parse_error();
123
- }
124
- });
125
-
126
- // src/contract/adapters/gateway-api-key/gateway-api-key.ts
127
- var GatewayApiKey;
128
- var init_gateway_api_key = __esm({
129
- "src/contract/adapters/gateway-api-key/gateway-api-key.ts"() {
130
- "use strict";
131
- GatewayApiKey = class {
132
- value;
133
- constructor(value) {
134
- this.value = value;
135
- }
136
- };
137
- }
138
- });
139
-
140
- // src/contract/adapters/gateway-api-key/index.ts
141
- var init_gateway_api_key2 = __esm({
142
- "src/contract/adapters/gateway-api-key/index.ts"() {
143
- "use strict";
144
- init_gateway_api_key();
145
- }
146
- });
147
-
148
- // src/contract/adapters/management-jwt/management-jwt.ts
149
- var ManagementJwt;
150
- var init_management_jwt = __esm({
151
- "src/contract/adapters/management-jwt/management-jwt.ts"() {
152
- "use strict";
153
- ManagementJwt = class {
154
- value;
155
- constructor(value) {
156
- this.value = value;
157
- }
158
- };
159
- }
160
- });
161
-
162
- // src/contract/adapters/management-jwt/index.ts
163
- var init_management_jwt2 = __esm({
164
- "src/contract/adapters/management-jwt/index.ts"() {
165
- "use strict";
166
- init_management_jwt();
167
- }
168
- });
169
-
170
- // src/contract/adapters/parse-gateway-key/parse-gateway-key.ts
171
- var parseGatewayKey;
172
- var init_parse_gateway_key = __esm({
173
- "src/contract/adapters/parse-gateway-key/parse-gateway-key.ts"() {
174
- "use strict";
175
- init_gateway_api_key2();
176
- parseGatewayKey = (value) => {
177
- if (typeof value !== "string" || value.length === 0) {
178
- throw new Error("gateway key must be non-empty");
179
- }
180
- return new GatewayApiKey(value);
181
- };
182
- }
183
- });
184
-
185
- // src/contract/adapters/parse-gateway-key/index.ts
186
- var init_parse_gateway_key2 = __esm({
187
- "src/contract/adapters/parse-gateway-key/index.ts"() {
188
- "use strict";
189
- init_parse_gateway_key();
190
- }
191
- });
192
-
193
- // src/contract/adapters/parse-management-jwt/parse-management-jwt.ts
194
- var parseManagementJwt;
195
- var init_parse_management_jwt = __esm({
196
- "src/contract/adapters/parse-management-jwt/parse-management-jwt.ts"() {
197
- "use strict";
198
- init_management_jwt2();
199
- parseManagementJwt = (value) => {
200
- if (typeof value !== "string" || value.length === 0) {
201
- throw new Error("management token must be non-empty");
202
- }
203
- return new ManagementJwt(value);
204
- };
205
- }
206
- });
207
-
208
- // src/contract/adapters/parse-management-jwt/index.ts
209
- var init_parse_management_jwt2 = __esm({
210
- "src/contract/adapters/parse-management-jwt/index.ts"() {
211
- "use strict";
212
- init_parse_management_jwt();
213
- }
214
- });
215
-
216
- // src/contract/predicates/has-string-fields/has-string-fields.ts
217
- var hasStringFields;
218
- var init_has_string_fields = __esm({
219
- "src/contract/predicates/has-string-fields/has-string-fields.ts"() {
220
- "use strict";
221
- hasStringFields = (record, fields) => fields.every((field) => typeof record[field] === "string");
222
- }
223
- });
224
-
225
- // src/contract/predicates/has-string-fields/index.ts
226
- var init_has_string_fields2 = __esm({
227
- "src/contract/predicates/has-string-fields/index.ts"() {
228
- "use strict";
229
- init_has_string_fields();
230
- }
231
- });
232
-
233
- // src/contract/predicates/is-nullable-string/is-nullable-string.ts
234
- var isNullableString;
235
- var init_is_nullable_string = __esm({
236
- "src/contract/predicates/is-nullable-string/is-nullable-string.ts"() {
237
- "use strict";
238
- isNullableString = (value) => typeof value === "string" || value === null;
239
- }
240
- });
241
-
242
- // src/contract/predicates/is-nullable-string/index.ts
243
- var init_is_nullable_string2 = __esm({
244
- "src/contract/predicates/is-nullable-string/index.ts"() {
245
- "use strict";
246
- init_is_nullable_string();
247
- }
248
- });
249
-
250
- // src/contract/predicates/is-owner-type/is-owner-type.ts
251
- var isOwnerType;
252
- var init_is_owner_type = __esm({
253
- "src/contract/predicates/is-owner-type/is-owner-type.ts"() {
254
- "use strict";
255
- isOwnerType = (value) => value === "project" || value === "user_personal" || value === "user_project";
256
- }
257
- });
258
-
259
- // src/contract/predicates/is-owner-type/index.ts
260
- var init_is_owner_type2 = __esm({
261
- "src/contract/predicates/is-owner-type/index.ts"() {
262
- "use strict";
263
- init_is_owner_type();
264
- }
265
- });
266
-
267
- // src/contract/predicates/is-record/is-record.ts
268
- var isRecord;
269
- var init_is_record = __esm({
270
- "src/contract/predicates/is-record/is-record.ts"() {
271
- "use strict";
272
- isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
273
- }
274
- });
275
-
276
- // src/contract/predicates/is-record/index.ts
277
- var init_is_record2 = __esm({
278
- "src/contract/predicates/is-record/index.ts"() {
279
- "use strict";
280
- init_is_record();
281
- }
282
- });
283
-
284
- // src/contract/predicates/index.ts
285
- var init_predicates = __esm({
286
- "src/contract/predicates/index.ts"() {
287
- "use strict";
288
- init_has_string_fields2();
289
- init_is_nullable_string2();
290
- init_is_owner_type2();
291
- init_is_record2();
292
- }
293
- });
294
-
295
- // src/contract/adapters/parse-management-subject/parse-management-subject.ts
296
- var parseManagementSubject;
297
- var init_parse_management_subject = __esm({
298
- "src/contract/adapters/parse-management-subject/parse-management-subject.ts"() {
299
- "use strict";
300
- init_predicates();
301
- init_contract_parse_error2();
302
- parseManagementSubject = (credential) => {
303
- const encodedPayload = credential.value.split(".")[1];
304
- if (encodedPayload === void 0 || encodedPayload.length === 0) {
305
- throw new ContractParseError("management token carries no usable subject");
306
- }
307
- let payload;
308
- try {
309
- payload = JSON.parse(
310
- Buffer.from(encodedPayload, "base64url").toString("utf8")
311
- );
312
- } catch {
313
- throw new ContractParseError("management token payload is not JSON");
314
- }
315
- if (!isRecord(payload)) {
316
- throw new ContractParseError("management token payload is not an object");
317
- }
318
- const subject = payload["sub"];
319
- if (typeof subject !== "string" || subject.length === 0) {
320
- throw new ContractParseError("management token carries no usable subject");
321
- }
322
- return subject;
323
- };
324
- }
325
- });
326
-
327
- // src/contract/adapters/parse-management-subject/index.ts
328
- var init_parse_management_subject2 = __esm({
329
- "src/contract/adapters/parse-management-subject/index.ts"() {
330
- "use strict";
331
- init_parse_management_subject();
332
- }
333
- });
334
-
335
- // src/contract/adapters/index.ts
336
- var init_adapters = __esm({
337
- "src/contract/adapters/index.ts"() {
338
- "use strict";
339
- init_contract_parse_error2();
340
- init_gateway_api_key2();
341
- init_management_jwt2();
342
- init_parse_gateway_key2();
343
- init_parse_management_jwt2();
344
- init_parse_management_subject2();
345
- }
346
- });
347
-
348
- // src/attribution/parse-attribution/parse-attribution.ts
349
- var parseAttribution;
350
- var init_parse_attribution = __esm({
351
- "src/attribution/parse-attribution/parse-attribution.ts"() {
352
- "use strict";
353
- init_adapters();
354
- init_predicates();
355
- parseAttribution = (value) => {
356
- if (!isRecord(value)) {
357
- throw new ContractParseError("invalid attribution");
358
- }
359
- if (value["kind"] === "personal") {
360
- return { kind: "personal" };
361
- }
362
- if (value["kind"] === "project" && typeof value["projectId"] === "string") {
363
- return { kind: "project", projectId: value["projectId"] };
364
- }
365
- throw new ContractParseError("invalid attribution");
366
- };
367
- }
368
- });
369
-
370
- // src/attribution/parse-attribution/index.ts
371
- var init_parse_attribution2 = __esm({
372
- "src/attribution/parse-attribution/index.ts"() {
373
- "use strict";
374
- init_parse_attribution();
375
- }
376
- });
377
-
378
- // src/attribution/read-attribution/read-attribution.ts
379
- import * as fs4 from "node:fs";
380
- var readAttribution;
381
- var init_read_attribution = __esm({
382
- "src/attribution/read-attribution/read-attribution.ts"() {
383
- "use strict";
384
- init_parse_attribution2();
385
- init_resolve_attribution_file2();
386
- readAttribution = (options) => {
387
- const file = resolveAttributionFile(options);
388
- if (file === void 0) {
389
- return void 0;
390
- }
391
- try {
392
- const parsed = JSON.parse(fs4.readFileSync(file, "utf8"));
393
- return parseAttribution(parsed);
394
- } catch {
395
- return void 0;
396
- }
397
- };
398
- }
399
- });
400
-
401
- // src/attribution/read-attribution/index.ts
402
- var init_read_attribution2 = __esm({
403
- "src/attribution/read-attribution/index.ts"() {
404
- "use strict";
405
- init_read_attribution();
406
- }
407
- });
408
-
409
- // src/attribution/write-attribution/write-attribution.ts
410
- import { randomUUID } from "node:crypto";
411
- import * as fs5 from "node:fs";
412
- import * as path3 from "node:path";
413
- var writeAttribution;
414
- var init_write_attribution = __esm({
415
- "src/attribution/write-attribution/write-attribution.ts"() {
416
- "use strict";
417
- init_resolve_attribution_file2();
418
- writeAttribution = (options, attribution) => {
419
- const file = resolveAttributionFile(options);
420
- if (file === void 0) {
421
- return false;
422
- }
423
- fs5.mkdirSync(path3.dirname(file), { recursive: true });
424
- const temporaryFile = `${file}.${String(process.pid)}.${randomUUID()}.tmp`;
425
- try {
426
- fs5.writeFileSync(temporaryFile, `${JSON.stringify(attribution)}
427
- `, "utf8");
428
- fs5.renameSync(temporaryFile, file);
429
- } catch (error) {
430
- fs5.rmSync(temporaryFile, { force: true });
431
- throw error;
432
- }
433
- return true;
434
- };
435
- }
436
- });
437
-
438
- // src/attribution/write-attribution/index.ts
439
- var init_write_attribution2 = __esm({
440
- "src/attribution/write-attribution/index.ts"() {
441
- "use strict";
442
- init_write_attribution();
443
- }
444
- });
445
-
446
- // src/attribution/index.ts
447
- var init_attribution = __esm({
448
- "src/attribution/index.ts"() {
449
- "use strict";
450
- init_clear_attribution2();
451
- init_detect_worktree_root2();
452
- init_parse_attribution2();
453
- init_read_attribution2();
454
- init_resolve_attribution_file2();
455
- init_write_attribution2();
456
- }
457
- });
458
-
459
16
  // src/cli/read-env-base-url/read-env-base-url.ts
460
17
  var readEnvBaseUrl;
461
18
  var init_read_env_base_url = __esm({
@@ -723,7 +280,7 @@ var init_r33_catalog_model = __esm({
723
280
 
724
281
  // src/shared/resolve-cache-dir/resolve-cache-dir.ts
725
282
  import * as os from "node:os";
726
- import * as path4 from "node:path";
283
+ import * as path from "node:path";
727
284
  var resolveCacheDir;
728
285
  var init_resolve_cache_dir = __esm({
729
286
  "src/shared/resolve-cache-dir/resolve-cache-dir.ts"() {
@@ -733,8 +290,8 @@ var init_resolve_cache_dir = __esm({
733
290
  if (override !== void 0 && override !== "") {
734
291
  return override;
735
292
  }
736
- return path4.join(
737
- env["XDG_CACHE_HOME"] ?? path4.join(os.homedir(), ".cache"),
293
+ return path.join(
294
+ env["XDG_CACHE_HOME"] ?? path.join(os.homedir(), ".cache"),
738
295
  "opencode-route33"
739
296
  );
740
297
  };
@@ -904,7 +461,7 @@ var init_read_env_strict2 = __esm({
904
461
 
905
462
  // src/cli/resolve-v1-secret-store-directory/resolve-v1-secret-store-directory.ts
906
463
  import * as os2 from "node:os";
907
- import * as path5 from "node:path";
464
+ import * as path2 from "node:path";
908
465
  var resolveV1SecretStoreDirectory;
909
466
  var init_resolve_v1_secret_store_directory = __esm({
910
467
  "src/cli/resolve-v1-secret-store-directory/resolve-v1-secret-store-directory.ts"() {
@@ -912,13 +469,13 @@ var init_resolve_v1_secret_store_directory = __esm({
912
469
  resolveV1SecretStoreDirectory = (options = {}) => {
913
470
  const explicit = options.directory?.trim();
914
471
  if (explicit !== void 0 && explicit.length > 0) {
915
- return path5.resolve(explicit);
472
+ return path2.resolve(explicit);
916
473
  }
917
474
  const hostConfig = (options.env ?? process.env)["OPENCODE_CONFIG_DIR"]?.trim();
918
475
  if (hostConfig !== void 0 && hostConfig.length > 0) {
919
- return path5.join(path5.resolve(hostConfig), "route33");
476
+ return path2.join(path2.resolve(hostConfig), "route33");
920
477
  }
921
- return path5.join(
478
+ return path2.join(
922
479
  options.homeDirectory ?? os2.homedir(),
923
480
  ".config",
924
481
  "opencode",
@@ -1005,11 +562,251 @@ var init_build_authorize_url = __esm({
1005
562
  }
1006
563
  });
1007
564
 
1008
- // src/auth/build-authorize-url/index.ts
1009
- var init_build_authorize_url2 = __esm({
1010
- "src/auth/build-authorize-url/index.ts"() {
565
+ // src/auth/build-authorize-url/index.ts
566
+ var init_build_authorize_url2 = __esm({
567
+ "src/auth/build-authorize-url/index.ts"() {
568
+ "use strict";
569
+ init_build_authorize_url();
570
+ }
571
+ });
572
+
573
+ // src/contract/adapters/contract-parse-error/contract-parse-error.ts
574
+ var ContractParseError;
575
+ var init_contract_parse_error = __esm({
576
+ "src/contract/adapters/contract-parse-error/contract-parse-error.ts"() {
577
+ "use strict";
578
+ ContractParseError = class extends Error {
579
+ };
580
+ }
581
+ });
582
+
583
+ // src/contract/adapters/contract-parse-error/index.ts
584
+ var init_contract_parse_error2 = __esm({
585
+ "src/contract/adapters/contract-parse-error/index.ts"() {
586
+ "use strict";
587
+ init_contract_parse_error();
588
+ }
589
+ });
590
+
591
+ // src/contract/adapters/gateway-api-key/gateway-api-key.ts
592
+ var GatewayApiKey;
593
+ var init_gateway_api_key = __esm({
594
+ "src/contract/adapters/gateway-api-key/gateway-api-key.ts"() {
595
+ "use strict";
596
+ GatewayApiKey = class {
597
+ value;
598
+ constructor(value) {
599
+ this.value = value;
600
+ }
601
+ };
602
+ }
603
+ });
604
+
605
+ // src/contract/adapters/gateway-api-key/index.ts
606
+ var init_gateway_api_key2 = __esm({
607
+ "src/contract/adapters/gateway-api-key/index.ts"() {
608
+ "use strict";
609
+ init_gateway_api_key();
610
+ }
611
+ });
612
+
613
+ // src/contract/adapters/management-jwt/management-jwt.ts
614
+ var ManagementJwt;
615
+ var init_management_jwt = __esm({
616
+ "src/contract/adapters/management-jwt/management-jwt.ts"() {
617
+ "use strict";
618
+ ManagementJwt = class {
619
+ value;
620
+ constructor(value) {
621
+ this.value = value;
622
+ }
623
+ };
624
+ }
625
+ });
626
+
627
+ // src/contract/adapters/management-jwt/index.ts
628
+ var init_management_jwt2 = __esm({
629
+ "src/contract/adapters/management-jwt/index.ts"() {
630
+ "use strict";
631
+ init_management_jwt();
632
+ }
633
+ });
634
+
635
+ // src/contract/adapters/parse-gateway-key/parse-gateway-key.ts
636
+ var parseGatewayKey;
637
+ var init_parse_gateway_key = __esm({
638
+ "src/contract/adapters/parse-gateway-key/parse-gateway-key.ts"() {
639
+ "use strict";
640
+ init_gateway_api_key2();
641
+ parseGatewayKey = (value) => {
642
+ if (typeof value !== "string" || value.length === 0) {
643
+ throw new Error("gateway key must be non-empty");
644
+ }
645
+ return new GatewayApiKey(value);
646
+ };
647
+ }
648
+ });
649
+
650
+ // src/contract/adapters/parse-gateway-key/index.ts
651
+ var init_parse_gateway_key2 = __esm({
652
+ "src/contract/adapters/parse-gateway-key/index.ts"() {
653
+ "use strict";
654
+ init_parse_gateway_key();
655
+ }
656
+ });
657
+
658
+ // src/contract/adapters/parse-management-jwt/parse-management-jwt.ts
659
+ var parseManagementJwt;
660
+ var init_parse_management_jwt = __esm({
661
+ "src/contract/adapters/parse-management-jwt/parse-management-jwt.ts"() {
662
+ "use strict";
663
+ init_management_jwt2();
664
+ parseManagementJwt = (value) => {
665
+ if (typeof value !== "string" || value.length === 0) {
666
+ throw new Error("management token must be non-empty");
667
+ }
668
+ return new ManagementJwt(value);
669
+ };
670
+ }
671
+ });
672
+
673
+ // src/contract/adapters/parse-management-jwt/index.ts
674
+ var init_parse_management_jwt2 = __esm({
675
+ "src/contract/adapters/parse-management-jwt/index.ts"() {
676
+ "use strict";
677
+ init_parse_management_jwt();
678
+ }
679
+ });
680
+
681
+ // src/contract/predicates/has-string-fields/has-string-fields.ts
682
+ var hasStringFields;
683
+ var init_has_string_fields = __esm({
684
+ "src/contract/predicates/has-string-fields/has-string-fields.ts"() {
685
+ "use strict";
686
+ hasStringFields = (record, fields) => fields.every((field) => typeof record[field] === "string");
687
+ }
688
+ });
689
+
690
+ // src/contract/predicates/has-string-fields/index.ts
691
+ var init_has_string_fields2 = __esm({
692
+ "src/contract/predicates/has-string-fields/index.ts"() {
693
+ "use strict";
694
+ init_has_string_fields();
695
+ }
696
+ });
697
+
698
+ // src/contract/predicates/is-nullable-string/is-nullable-string.ts
699
+ var isNullableString;
700
+ var init_is_nullable_string = __esm({
701
+ "src/contract/predicates/is-nullable-string/is-nullable-string.ts"() {
702
+ "use strict";
703
+ isNullableString = (value) => typeof value === "string" || value === null;
704
+ }
705
+ });
706
+
707
+ // src/contract/predicates/is-nullable-string/index.ts
708
+ var init_is_nullable_string2 = __esm({
709
+ "src/contract/predicates/is-nullable-string/index.ts"() {
710
+ "use strict";
711
+ init_is_nullable_string();
712
+ }
713
+ });
714
+
715
+ // src/contract/predicates/is-owner-type/is-owner-type.ts
716
+ var isOwnerType;
717
+ var init_is_owner_type = __esm({
718
+ "src/contract/predicates/is-owner-type/is-owner-type.ts"() {
719
+ "use strict";
720
+ isOwnerType = (value) => value === "project" || value === "user_personal" || value === "user_project";
721
+ }
722
+ });
723
+
724
+ // src/contract/predicates/is-owner-type/index.ts
725
+ var init_is_owner_type2 = __esm({
726
+ "src/contract/predicates/is-owner-type/index.ts"() {
727
+ "use strict";
728
+ init_is_owner_type();
729
+ }
730
+ });
731
+
732
+ // src/contract/predicates/is-record/is-record.ts
733
+ var isRecord;
734
+ var init_is_record = __esm({
735
+ "src/contract/predicates/is-record/is-record.ts"() {
736
+ "use strict";
737
+ isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
738
+ }
739
+ });
740
+
741
+ // src/contract/predicates/is-record/index.ts
742
+ var init_is_record2 = __esm({
743
+ "src/contract/predicates/is-record/index.ts"() {
744
+ "use strict";
745
+ init_is_record();
746
+ }
747
+ });
748
+
749
+ // src/contract/predicates/index.ts
750
+ var init_predicates = __esm({
751
+ "src/contract/predicates/index.ts"() {
752
+ "use strict";
753
+ init_has_string_fields2();
754
+ init_is_nullable_string2();
755
+ init_is_owner_type2();
756
+ init_is_record2();
757
+ }
758
+ });
759
+
760
+ // src/contract/adapters/parse-management-subject/parse-management-subject.ts
761
+ var parseManagementSubject;
762
+ var init_parse_management_subject = __esm({
763
+ "src/contract/adapters/parse-management-subject/parse-management-subject.ts"() {
764
+ "use strict";
765
+ init_predicates();
766
+ init_contract_parse_error2();
767
+ parseManagementSubject = (credential) => {
768
+ const encodedPayload = credential.value.split(".")[1];
769
+ if (encodedPayload === void 0 || encodedPayload.length === 0) {
770
+ throw new ContractParseError("management token carries no usable subject");
771
+ }
772
+ let payload;
773
+ try {
774
+ payload = JSON.parse(
775
+ Buffer.from(encodedPayload, "base64url").toString("utf8")
776
+ );
777
+ } catch {
778
+ throw new ContractParseError("management token payload is not JSON");
779
+ }
780
+ if (!isRecord(payload)) {
781
+ throw new ContractParseError("management token payload is not an object");
782
+ }
783
+ const subject = payload["sub"];
784
+ if (typeof subject !== "string" || subject.length === 0) {
785
+ throw new ContractParseError("management token carries no usable subject");
786
+ }
787
+ return subject;
788
+ };
789
+ }
790
+ });
791
+
792
+ // src/contract/adapters/parse-management-subject/index.ts
793
+ var init_parse_management_subject2 = __esm({
794
+ "src/contract/adapters/parse-management-subject/index.ts"() {
795
+ "use strict";
796
+ init_parse_management_subject();
797
+ }
798
+ });
799
+
800
+ // src/contract/adapters/index.ts
801
+ var init_adapters = __esm({
802
+ "src/contract/adapters/index.ts"() {
1011
803
  "use strict";
1012
- init_build_authorize_url();
804
+ init_contract_parse_error2();
805
+ init_gateway_api_key2();
806
+ init_management_jwt2();
807
+ init_parse_gateway_key2();
808
+ init_parse_management_jwt2();
809
+ init_parse_management_subject2();
1013
810
  }
1014
811
  });
1015
812
 
@@ -1352,8 +1149,48 @@ var init_loopback_callback2 = __esm({
1352
1149
  }
1353
1150
  });
1354
1151
 
1355
- // src/auth/open-browser-and-capture/open-browser-and-capture.ts
1152
+ // src/auth/open-system-browser/open-system-browser.ts
1356
1153
  import { spawn } from "node:child_process";
1154
+ var openSystemBrowser;
1155
+ var init_open_system_browser = __esm({
1156
+ "src/auth/open-system-browser/open-system-browser.ts"() {
1157
+ "use strict";
1158
+ openSystemBrowser = async (url, options = {}) => new Promise((resolve2, reject) => {
1159
+ let command = "xdg-open";
1160
+ let args = [url.href];
1161
+ if (process.platform === "darwin") {
1162
+ command = "open";
1163
+ } else if (process.platform === "win32") {
1164
+ command = "cmd";
1165
+ args = ["/c", "start", "", url.href];
1166
+ }
1167
+ if (options.spawnUrl !== void 0) {
1168
+ options.spawnUrl(command, args, { detached: true, stdio: "ignore" });
1169
+ resolve2();
1170
+ return;
1171
+ }
1172
+ const child = spawn(command, args, {
1173
+ detached: true,
1174
+ stdio: "ignore"
1175
+ });
1176
+ child.once("error", reject);
1177
+ child.once("spawn", () => {
1178
+ child.unref();
1179
+ resolve2();
1180
+ });
1181
+ });
1182
+ }
1183
+ });
1184
+
1185
+ // src/auth/open-system-browser/index.ts
1186
+ var init_open_system_browser2 = __esm({
1187
+ "src/auth/open-system-browser/index.ts"() {
1188
+ "use strict";
1189
+ init_open_system_browser();
1190
+ }
1191
+ });
1192
+
1193
+ // src/auth/open-browser-and-capture/open-browser-and-capture.ts
1357
1194
  import { timingSafeEqual } from "node:crypto";
1358
1195
  var openBrowserAndCapture;
1359
1196
  var init_open_browser_and_capture = __esm({
@@ -1361,28 +1198,11 @@ var init_open_browser_and_capture = __esm({
1361
1198
  "use strict";
1362
1199
  init_auth_error2();
1363
1200
  init_loopback_callback2();
1201
+ init_open_system_browser2();
1364
1202
  openBrowserAndCapture = async (options) => {
1365
1203
  const callback = await createAuthLoopbackCallback();
1366
1204
  const authorizationUrl = options.authorizationUrl(callback.redirectUri);
1367
- const browserRunner = options.browserRunner ?? ((url) => new Promise((resolve2, reject) => {
1368
- let command = "xdg-open";
1369
- let args = [url.href];
1370
- if (process.platform === "darwin") {
1371
- command = "open";
1372
- } else if (process.platform === "win32") {
1373
- command = "cmd";
1374
- args = ["/c", "start", "", url.href];
1375
- }
1376
- const child = spawn(command, args, {
1377
- detached: true,
1378
- stdio: "ignore"
1379
- });
1380
- child.once("error", reject);
1381
- child.once("spawn", () => {
1382
- child.unref();
1383
- resolve2();
1384
- });
1385
- }));
1205
+ const browserRunner = options.browserRunner ?? ((url) => openSystemBrowser(url));
1386
1206
  let timer;
1387
1207
  const timeout = new Promise((_resolve, reject) => {
1388
1208
  timer = setTimeout(() => {
@@ -2115,12 +1935,12 @@ var init_catalog_fetch_error2 = __esm({
2115
1935
  });
2116
1936
 
2117
1937
  // src/catalog/catalog-cache/cache-file-path/cache-file-path.ts
2118
- import * as path6 from "node:path";
1938
+ import * as path3 from "node:path";
2119
1939
  var cacheFilePath;
2120
1940
  var init_cache_file_path = __esm({
2121
1941
  "src/catalog/catalog-cache/cache-file-path/cache-file-path.ts"() {
2122
1942
  "use strict";
2123
- cacheFilePath = (keyHash, cacheDir) => path6.join(cacheDir, `catalog-${keyHash}.json`);
1943
+ cacheFilePath = (keyHash, cacheDir) => path3.join(cacheDir, `catalog-${keyHash}.json`);
2124
1944
  }
2125
1945
  });
2126
1946
 
@@ -2229,7 +2049,7 @@ var init_is_catalog_model_record2 = __esm({
2229
2049
  });
2230
2050
 
2231
2051
  // src/catalog/catalog-cache/read-disk/read-disk.ts
2232
- import * as fs6 from "node:fs";
2052
+ import * as fs from "node:fs";
2233
2053
  var readDisk;
2234
2054
  var init_read_disk = __esm({
2235
2055
  "src/catalog/catalog-cache/read-disk/read-disk.ts"() {
@@ -2241,7 +2061,7 @@ var init_read_disk = __esm({
2241
2061
  readDisk = (keyHash, cacheDir) => {
2242
2062
  try {
2243
2063
  const parsed = JSON.parse(
2244
- fs6.readFileSync(cacheFilePath(keyHash, cacheDir), "utf8")
2064
+ fs.readFileSync(cacheFilePath(keyHash, cacheDir), "utf8")
2245
2065
  );
2246
2066
  if (!isRecord(parsed) || parsed["version"] !== CATALOG_CACHE_VERSION || typeof parsed["fetchedAt"] !== "number" || !isCatalogModelRecord(parsed["models"])) {
2247
2067
  return void 0;
@@ -2326,7 +2146,7 @@ var init_read_stale_catalog2 = __esm({
2326
2146
  });
2327
2147
 
2328
2148
  // src/catalog/catalog-cache/write-catalog/write-catalog.ts
2329
- import * as fs7 from "node:fs";
2149
+ import * as fs2 from "node:fs";
2330
2150
  var writeCatalog;
2331
2151
  var init_write_catalog = __esm({
2332
2152
  "src/catalog/catalog-cache/write-catalog/write-catalog.ts"() {
@@ -2345,8 +2165,8 @@ var init_write_catalog = __esm({
2345
2165
  };
2346
2166
  catalogMemory.set(keyHash, record);
2347
2167
  try {
2348
- fs7.mkdirSync(options.cacheDir, { recursive: true });
2349
- fs7.writeFileSync(
2168
+ fs2.mkdirSync(options.cacheDir, { recursive: true });
2169
+ fs2.writeFileSync(
2350
2170
  cacheFilePath(keyHash, options.cacheDir),
2351
2171
  JSON.stringify({ version: CATALOG_CACHE_VERSION, ...record })
2352
2172
  );
@@ -3841,7 +3661,7 @@ var init_fetch_live2 = __esm({
3841
3661
  });
3842
3662
 
3843
3663
  // src/enrich/models-dev/read-models-dev-cache/read-models-dev-cache.ts
3844
- import * as fs8 from "node:fs";
3664
+ import * as fs3 from "node:fs";
3845
3665
  var readModelsDevCache;
3846
3666
  var init_read_models_dev_cache = __esm({
3847
3667
  "src/enrich/models-dev/read-models-dev-cache/read-models-dev-cache.ts"() {
@@ -3850,7 +3670,7 @@ var init_read_models_dev_cache = __esm({
3850
3670
  init_num2();
3851
3671
  readModelsDevCache = (cachePath) => {
3852
3672
  try {
3853
- const parsed = JSON.parse(fs8.readFileSync(cachePath, "utf8"));
3673
+ const parsed = JSON.parse(fs3.readFileSync(cachePath, "utf8"));
3854
3674
  if (!isRecord(parsed)) {
3855
3675
  return void 0;
3856
3676
  }
@@ -3876,8 +3696,8 @@ var init_read_models_dev_cache2 = __esm({
3876
3696
  });
3877
3697
 
3878
3698
  // src/enrich/models-dev/write-models-dev-cache/write-models-dev-cache.ts
3879
- import * as fs9 from "node:fs";
3880
- import * as path7 from "node:path";
3699
+ import * as fs4 from "node:fs";
3700
+ import * as path4 from "node:path";
3881
3701
  var writeModelsDevCache;
3882
3702
  var init_write_models_dev_cache = __esm({
3883
3703
  "src/enrich/models-dev/write-models-dev-cache/write-models-dev-cache.ts"() {
@@ -3885,8 +3705,8 @@ var init_write_models_dev_cache = __esm({
3885
3705
  init_shared();
3886
3706
  writeModelsDevCache = (cachePath, envelope) => {
3887
3707
  try {
3888
- fs9.mkdirSync(path7.dirname(cachePath), { recursive: true });
3889
- fs9.writeFileSync(cachePath, JSON.stringify(envelope), "utf8");
3708
+ fs4.mkdirSync(path4.dirname(cachePath), { recursive: true });
3709
+ fs4.writeFileSync(cachePath, JSON.stringify(envelope), "utf8");
3890
3710
  } catch (error) {
3891
3711
  logger.warn(
3892
3712
  "failed to write models.dev cache:",
@@ -3906,7 +3726,7 @@ var init_write_models_dev_cache2 = __esm({
3906
3726
  });
3907
3727
 
3908
3728
  // src/enrich/models-dev/load-models-dev/load-models-dev.ts
3909
- import * as path8 from "node:path";
3729
+ import * as path5 from "node:path";
3910
3730
  var CACHE_FILE, loadModelsDev;
3911
3731
  var init_load_models_dev = __esm({
3912
3732
  "src/enrich/models-dev/load-models-dev/load-models-dev.ts"() {
@@ -3922,7 +3742,7 @@ var init_load_models_dev = __esm({
3922
3742
  const cacheDir = options.cacheDir ?? resolveCacheDir({});
3923
3743
  const ttlMs = options.ttlMs ?? MODELS_DEV_TTL_MS;
3924
3744
  const now = options.now ?? Date.now;
3925
- const cachePath = path8.join(cacheDir, CACHE_FILE);
3745
+ const cachePath = path5.join(cacheDir, CACHE_FILE);
3926
3746
  const cached = readModelsDevCache(cachePath);
3927
3747
  if (cached !== void 0 && now() - cached.fetchedAt < ttlMs) {
3928
3748
  return createModelsDevSource("cache", cached.data);
@@ -4087,20 +3907,20 @@ var init_regenerate_models2 = __esm({
4087
3907
  });
4088
3908
 
4089
3909
  // src/config/remove-legacy-manifest/remove-legacy-manifest.ts
4090
- import * as fs10 from "node:fs";
4091
- import * as path9 from "node:path";
3910
+ import * as fs5 from "node:fs";
3911
+ import * as path6 from "node:path";
4092
3912
  var removeLegacyManifest;
4093
3913
  var init_remove_legacy_manifest = __esm({
4094
3914
  "src/config/remove-legacy-manifest/remove-legacy-manifest.ts"() {
4095
3915
  "use strict";
4096
3916
  init_shared();
4097
3917
  removeLegacyManifest = (root) => {
4098
- const file = path9.join(root, ".opencode", "route33-generated.json");
3918
+ const file = path6.join(root, ".opencode", "route33-generated.json");
4099
3919
  try {
4100
- if (!fs10.existsSync(file)) {
3920
+ if (!fs5.existsSync(file)) {
4101
3921
  return;
4102
3922
  }
4103
- fs10.rmSync(file);
3923
+ fs5.rmSync(file);
4104
3924
  logger.info(
4105
3925
  "route_33: removed obsolete route33-generated.json (regeneration is stateless since 0.4.4)"
4106
3926
  );
@@ -4745,9 +4565,9 @@ var init_default_gateway_key_ttl_ms2 = __esm({
4745
4565
  });
4746
4566
 
4747
4567
  // src/key-lease/file-secret-store/file-secret-store.ts
4748
- import { randomUUID as randomUUID2 } from "node:crypto";
4749
- import * as fs11 from "node:fs/promises";
4750
- import * as path10 from "node:path";
4568
+ import { randomUUID } from "node:crypto";
4569
+ import * as fs6 from "node:fs/promises";
4570
+ import * as path7 from "node:path";
4751
4571
  var FileSecretStore;
4752
4572
  var init_file_secret_store = __esm({
4753
4573
  "src/key-lease/file-secret-store/file-secret-store.ts"() {
@@ -4764,7 +4584,7 @@ var init_file_secret_store = __esm({
4764
4584
  throw new TypeError("File secret store scope is not portable");
4765
4585
  }
4766
4586
  this.#directory = options.directory;
4767
- this.#file = path10.join(options.directory, `lease-${options.scopeId}.json`);
4587
+ this.#file = path7.join(options.directory, `lease-${options.scopeId}.json`);
4768
4588
  }
4769
4589
  /** Reads and parses the scoped gateway credential.
4770
4590
  * @returns The persisted credential, when present.
@@ -4772,7 +4592,7 @@ var init_file_secret_store = __esm({
4772
4592
  async get() {
4773
4593
  let contents;
4774
4594
  try {
4775
- contents = await fs11.readFile(this.#file, "utf8");
4595
+ contents = await fs6.readFile(this.#file, "utf8");
4776
4596
  } catch (cause) {
4777
4597
  if (cause instanceof Error && "code" in cause && cause.code === "ENOENT") {
4778
4598
  return void 0;
@@ -4788,22 +4608,22 @@ var init_file_secret_store = __esm({
4788
4608
  */
4789
4609
  async set(key) {
4790
4610
  if (key === void 0) {
4791
- await fs11.rm(this.#file, { force: true });
4611
+ await fs6.rm(this.#file, { force: true });
4792
4612
  return;
4793
4613
  }
4794
- await fs11.mkdir(this.#directory, { mode: 448, recursive: true });
4795
- await fs11.chmod(this.#directory, 448);
4796
- const temporary = path10.join(this.#directory, `.lease-${randomUUID2()}.tmp`);
4614
+ await fs6.mkdir(this.#directory, { mode: 448, recursive: true });
4615
+ await fs6.chmod(this.#directory, 448);
4616
+ const temporary = path7.join(this.#directory, `.lease-${randomUUID()}.tmp`);
4797
4617
  try {
4798
- await fs11.writeFile(temporary, `${JSON.stringify(key.value)}
4618
+ await fs6.writeFile(temporary, `${JSON.stringify(key.value)}
4799
4619
  `, {
4800
4620
  encoding: "utf8",
4801
4621
  flag: "wx",
4802
4622
  mode: 384
4803
4623
  });
4804
- await fs11.rename(temporary, this.#file);
4624
+ await fs6.rename(temporary, this.#file);
4805
4625
  } finally {
4806
- await fs11.rm(temporary, { force: true });
4626
+ await fs6.rm(temporary, { force: true });
4807
4627
  }
4808
4628
  }
4809
4629
  };
@@ -5423,49 +5243,252 @@ var init_lease_for_attribution = __esm({
5423
5243
  return reusable;
5424
5244
  }
5425
5245
  try {
5426
- const renewed = await renewKey({
5427
- leaseState: options.installation.state,
5428
- mint: {
5429
- attribution: options.attribution,
5430
- clock,
5431
- identity: {
5432
- credential: await resolveSeamValue(options.management.credential),
5433
- subject: await resolveSeamValue(options.management.subject)
5434
- },
5435
- installation: {
5436
- keyName: options.installation.keyName,
5437
- ttlMs: policy.ttlMs
5438
- },
5439
- managementClient: options.management.client
5440
- },
5441
- secretStore: options.installation.secretStore
5442
- });
5443
- if (policy.orphanRetentionCycles !== void 0) {
5444
- await controlOrphans({
5445
- clock,
5446
- currentKeyId: renewed.lease.keyId,
5447
- keyName: options.installation.keyName,
5448
- managementClient: options.management.client,
5449
- managementCredential: await resolveSeamValue(
5450
- options.management.credential
5451
- ),
5452
- retentionCycles: policy.orphanRetentionCycles,
5453
- ttlMs: policy.ttlMs
5454
- });
5455
- }
5456
- return renewed;
5457
- } catch (cause) {
5458
- return mapRenewalFailure({ cause, current, now });
5246
+ const renewed = await renewKey({
5247
+ leaseState: options.installation.state,
5248
+ mint: {
5249
+ attribution: options.attribution,
5250
+ clock,
5251
+ identity: {
5252
+ credential: await resolveSeamValue(options.management.credential),
5253
+ subject: await resolveSeamValue(options.management.subject)
5254
+ },
5255
+ installation: {
5256
+ keyName: options.installation.keyName,
5257
+ ttlMs: policy.ttlMs
5258
+ },
5259
+ managementClient: options.management.client
5260
+ },
5261
+ secretStore: options.installation.secretStore
5262
+ });
5263
+ if (policy.orphanRetentionCycles !== void 0) {
5264
+ await controlOrphans({
5265
+ clock,
5266
+ currentKeyId: renewed.lease.keyId,
5267
+ keyName: options.installation.keyName,
5268
+ managementClient: options.management.client,
5269
+ managementCredential: await resolveSeamValue(
5270
+ options.management.credential
5271
+ ),
5272
+ retentionCycles: policy.orphanRetentionCycles,
5273
+ ttlMs: policy.ttlMs
5274
+ });
5275
+ }
5276
+ return renewed;
5277
+ } catch (cause) {
5278
+ return mapRenewalFailure({ cause, current, now });
5279
+ }
5280
+ };
5281
+ }
5282
+ });
5283
+
5284
+ // src/key-lease/lease-for-attribution/index.ts
5285
+ var init_lease_for_attribution2 = __esm({
5286
+ "src/key-lease/lease-for-attribution/index.ts"() {
5287
+ "use strict";
5288
+ init_lease_for_attribution();
5289
+ }
5290
+ });
5291
+
5292
+ // src/attribution/detect-worktree-root/detect-worktree-root.ts
5293
+ import * as fs7 from "node:fs";
5294
+ import * as path8 from "node:path";
5295
+ var detectWorktreeRoot;
5296
+ var init_detect_worktree_root = __esm({
5297
+ "src/attribution/detect-worktree-root/detect-worktree-root.ts"() {
5298
+ "use strict";
5299
+ detectWorktreeRoot = (startDirectory) => {
5300
+ let directory = fs7.realpathSync(startDirectory);
5301
+ for (; ; ) {
5302
+ const gitEntry = path8.join(directory, ".git");
5303
+ if (fs7.existsSync(gitEntry)) {
5304
+ const entry = fs7.statSync(gitEntry);
5305
+ if (entry.isDirectory() || entry.isFile()) {
5306
+ return directory;
5307
+ }
5308
+ }
5309
+ const parent = path8.dirname(directory);
5310
+ if (parent === directory) {
5311
+ return void 0;
5312
+ }
5313
+ directory = parent;
5314
+ }
5315
+ };
5316
+ }
5317
+ });
5318
+
5319
+ // src/attribution/detect-worktree-root/index.ts
5320
+ var init_detect_worktree_root2 = __esm({
5321
+ "src/attribution/detect-worktree-root/index.ts"() {
5322
+ "use strict";
5323
+ init_detect_worktree_root();
5324
+ }
5325
+ });
5326
+
5327
+ // src/attribution/resolve-attribution-file/resolve-attribution-file.ts
5328
+ import * as fs8 from "node:fs";
5329
+ import * as path9 from "node:path";
5330
+ var resolveAttributionFile;
5331
+ var init_resolve_attribution_file = __esm({
5332
+ "src/attribution/resolve-attribution-file/resolve-attribution-file.ts"() {
5333
+ "use strict";
5334
+ init_detect_worktree_root2();
5335
+ resolveAttributionFile = (options) => {
5336
+ const worktreeRoot = detectWorktreeRoot(options.directory);
5337
+ if (worktreeRoot !== void 0) {
5338
+ return path9.join(worktreeRoot, ".opencode", "route33.attribution.json");
5339
+ }
5340
+ const fallbackRoots = {
5341
+ "return-undefined": void 0,
5342
+ "use-directory": fs8.realpathSync(options.directory)
5343
+ };
5344
+ const fallbackRoot = fallbackRoots[options.outsideWorktree];
5345
+ return fallbackRoot === void 0 ? void 0 : path9.join(fallbackRoot, ".opencode", "route33.attribution.json");
5346
+ };
5347
+ }
5348
+ });
5349
+
5350
+ // src/attribution/resolve-attribution-file/index.ts
5351
+ var init_resolve_attribution_file2 = __esm({
5352
+ "src/attribution/resolve-attribution-file/index.ts"() {
5353
+ "use strict";
5354
+ init_resolve_attribution_file();
5355
+ }
5356
+ });
5357
+
5358
+ // src/attribution/clear-attribution/clear-attribution.ts
5359
+ import * as fs9 from "node:fs";
5360
+ var clearAttribution;
5361
+ var init_clear_attribution = __esm({
5362
+ "src/attribution/clear-attribution/clear-attribution.ts"() {
5363
+ "use strict";
5364
+ init_resolve_attribution_file2();
5365
+ clearAttribution = (options) => {
5366
+ const file = resolveAttributionFile(options);
5367
+ if (file === void 0) {
5368
+ return false;
5369
+ }
5370
+ fs9.rmSync(file, { force: true });
5371
+ return true;
5372
+ };
5373
+ }
5374
+ });
5375
+
5376
+ // src/attribution/clear-attribution/index.ts
5377
+ var init_clear_attribution2 = __esm({
5378
+ "src/attribution/clear-attribution/index.ts"() {
5379
+ "use strict";
5380
+ init_clear_attribution();
5381
+ }
5382
+ });
5383
+
5384
+ // src/attribution/parse-attribution/parse-attribution.ts
5385
+ var parseAttribution;
5386
+ var init_parse_attribution = __esm({
5387
+ "src/attribution/parse-attribution/parse-attribution.ts"() {
5388
+ "use strict";
5389
+ init_adapters();
5390
+ init_predicates();
5391
+ parseAttribution = (value) => {
5392
+ if (!isRecord(value)) {
5393
+ throw new ContractParseError("invalid attribution");
5394
+ }
5395
+ if (value["kind"] === "personal") {
5396
+ return { kind: "personal" };
5397
+ }
5398
+ if (value["kind"] === "project" && typeof value["projectId"] === "string") {
5399
+ return { kind: "project", projectId: value["projectId"] };
5400
+ }
5401
+ throw new ContractParseError("invalid attribution");
5402
+ };
5403
+ }
5404
+ });
5405
+
5406
+ // src/attribution/parse-attribution/index.ts
5407
+ var init_parse_attribution2 = __esm({
5408
+ "src/attribution/parse-attribution/index.ts"() {
5409
+ "use strict";
5410
+ init_parse_attribution();
5411
+ }
5412
+ });
5413
+
5414
+ // src/attribution/read-attribution/read-attribution.ts
5415
+ import * as fs10 from "node:fs";
5416
+ var readAttribution;
5417
+ var init_read_attribution = __esm({
5418
+ "src/attribution/read-attribution/read-attribution.ts"() {
5419
+ "use strict";
5420
+ init_parse_attribution2();
5421
+ init_resolve_attribution_file2();
5422
+ readAttribution = (options) => {
5423
+ const file = resolveAttributionFile(options);
5424
+ if (file === void 0) {
5425
+ return void 0;
5426
+ }
5427
+ try {
5428
+ const parsed = JSON.parse(fs10.readFileSync(file, "utf8"));
5429
+ return parseAttribution(parsed);
5430
+ } catch {
5431
+ return void 0;
5432
+ }
5433
+ };
5434
+ }
5435
+ });
5436
+
5437
+ // src/attribution/read-attribution/index.ts
5438
+ var init_read_attribution2 = __esm({
5439
+ "src/attribution/read-attribution/index.ts"() {
5440
+ "use strict";
5441
+ init_read_attribution();
5442
+ }
5443
+ });
5444
+
5445
+ // src/attribution/write-attribution/write-attribution.ts
5446
+ import { randomUUID as randomUUID2 } from "node:crypto";
5447
+ import * as fs11 from "node:fs";
5448
+ import * as path10 from "node:path";
5449
+ var writeAttribution;
5450
+ var init_write_attribution = __esm({
5451
+ "src/attribution/write-attribution/write-attribution.ts"() {
5452
+ "use strict";
5453
+ init_resolve_attribution_file2();
5454
+ writeAttribution = (options, attribution) => {
5455
+ const file = resolveAttributionFile(options);
5456
+ if (file === void 0) {
5457
+ return false;
5458
+ }
5459
+ fs11.mkdirSync(path10.dirname(file), { recursive: true });
5460
+ const temporaryFile = `${file}.${String(process.pid)}.${randomUUID2()}.tmp`;
5461
+ try {
5462
+ fs11.writeFileSync(temporaryFile, `${JSON.stringify(attribution)}
5463
+ `, "utf8");
5464
+ fs11.renameSync(temporaryFile, file);
5465
+ } catch (error) {
5466
+ fs11.rmSync(temporaryFile, { force: true });
5467
+ throw error;
5459
5468
  }
5469
+ return true;
5460
5470
  };
5461
5471
  }
5462
5472
  });
5463
5473
 
5464
- // src/key-lease/lease-for-attribution/index.ts
5465
- var init_lease_for_attribution2 = __esm({
5466
- "src/key-lease/lease-for-attribution/index.ts"() {
5474
+ // src/attribution/write-attribution/index.ts
5475
+ var init_write_attribution2 = __esm({
5476
+ "src/attribution/write-attribution/index.ts"() {
5467
5477
  "use strict";
5468
- init_lease_for_attribution();
5478
+ init_write_attribution();
5479
+ }
5480
+ });
5481
+
5482
+ // src/attribution/index.ts
5483
+ var init_attribution = __esm({
5484
+ "src/attribution/index.ts"() {
5485
+ "use strict";
5486
+ init_clear_attribution2();
5487
+ init_detect_worktree_root2();
5488
+ init_parse_attribution2();
5489
+ init_read_attribution2();
5490
+ init_resolve_attribution_file2();
5491
+ init_write_attribution2();
5469
5492
  }
5470
5493
  });
5471
5494
 
@@ -6132,7 +6155,7 @@ var init_route33_runtime = __esm({
6132
6155
  if (typeof client !== "function") {
6133
6156
  return client;
6134
6157
  }
6135
- this.#managementClient ??= client(() => this.#session.credential());
6158
+ this.#managementClient ??= client();
6136
6159
  return this.#managementClient;
6137
6160
  }
6138
6161
  #subject(credential) {
@@ -6387,7 +6410,6 @@ var init_create_route33_plugin2 = __esm({
6387
6410
  });
6388
6411
 
6389
6412
  // src/tui-entry/v1-connect-wizard/v1-connect-wizard.ts
6390
- init_attribution();
6391
6413
  init_cli();
6392
6414
 
6393
6415
  // src/tui-entry/production-options/production-options.ts
@@ -6817,20 +6839,20 @@ var HttpManagementKeys = class {
6817
6839
 
6818
6840
  // src/lazy-management-keys/lazy-management-keys.ts
6819
6841
  var lazyManagementKeys = (options) => {
6820
- const client = async () => new HttpManagementKeys({
6842
+ const client = (accessToken) => new HttpManagementKeys({
6821
6843
  baseUrl: options.apiBaseUrl,
6822
- credential: await options.obtainCredential(),
6844
+ credential: accessToken,
6823
6845
  ...options.fetchImpl === void 0 ? {} : { fetchImpl: options.fetchImpl }
6824
6846
  });
6825
6847
  return {
6826
- create: async (accessToken, input) => (await client()).create(accessToken, input),
6827
- delete: async (accessToken, id) => (await client()).delete(accessToken, id),
6828
- get: async (accessToken, id) => (await client()).get(accessToken, id),
6829
- list: async (accessToken) => (await client()).list(accessToken),
6830
- listOrganizations: async (accessToken) => (await client()).listOrganizations(accessToken),
6831
- listProjects: async (accessToken, organisationId) => (await client()).listProjects(accessToken, organisationId),
6832
- regenerate: async (accessToken, id, expiresAt) => (await client()).regenerate(accessToken, id, expiresAt),
6833
- update: async (accessToken, id, input) => (await client()).update(accessToken, id, input)
6848
+ create: async (accessToken, input) => client(accessToken).create(accessToken, input),
6849
+ delete: async (accessToken, id) => client(accessToken).delete(accessToken, id),
6850
+ get: async (accessToken, id) => client(accessToken).get(accessToken, id),
6851
+ list: async (accessToken) => client(accessToken).list(accessToken),
6852
+ listOrganizations: async (accessToken) => client(accessToken).listOrganizations(accessToken),
6853
+ listProjects: async (accessToken, organisationId) => client(accessToken).listProjects(accessToken, organisationId),
6854
+ regenerate: async (accessToken, id, expiresAt) => client(accessToken).regenerate(accessToken, id, expiresAt),
6855
+ update: async (accessToken, id, input) => client(accessToken).update(accessToken, id, input)
6834
6856
  };
6835
6857
  };
6836
6858
 
@@ -6846,10 +6868,7 @@ var buildProductionRuntimeOptions = (input) => ({
6846
6868
  timeoutMs: LOGIN_BUDGET_MS
6847
6869
  },
6848
6870
  management: {
6849
- client: (obtainCredential) => lazyManagementKeys({
6850
- apiBaseUrl: input.apiBaseUrl,
6851
- obtainCredential
6852
- })
6871
+ client: () => lazyManagementKeys({ apiBaseUrl: input.apiBaseUrl })
6853
6872
  },
6854
6873
  ...input.tokenStore === void 0 ? {} : { tokenStore: input.tokenStore }
6855
6874
  });
@@ -6902,12 +6921,10 @@ init_create_route33_plugin2();
6902
6921
  // src/v2-entry/parse-r33-subcommand/parse-r33-subcommand.ts
6903
6922
  var SUBCOMMANDS = ["inspect", "rotate", "reset"];
6904
6923
  var parseR33Subcommand = (promptText) => {
6905
- const [invocation, argument] = promptText.trim().split(/\s+/u);
6906
- const name = invocation?.replace(/^\/+/u, "").split(":")[0] ?? "";
6907
- if (name !== "r33") {
6908
- return "help";
6909
- }
6910
- if (argument === void 0) {
6924
+ const [first = "", ...rest] = promptText.trim().split(/\s+/u).filter(Boolean);
6925
+ const name = first.replace(/^\/+/u, "").split(":")[0] ?? "";
6926
+ const argument = name === "r33" ? rest[0] : first;
6927
+ if (argument === void 0 || argument === "") {
6911
6928
  return "inspect";
6912
6929
  }
6913
6930
  return SUBCOMMANDS.includes(argument) ? argument : "help";
@@ -7098,19 +7115,82 @@ var r33Menu = async (api, composeOptions) => {
7098
7115
  await r33MenuActions({ api, composeOptions })(selection);
7099
7116
  };
7100
7117
 
7118
+ // src/tui-entry/v2-setup-directory/v2-setup-directory.ts
7119
+ init_attribution();
7120
+ init_cli();
7121
+ var v2SetupDirectory = (context) => {
7122
+ if (readEnvDirectApiKey() !== void 0) return void 0;
7123
+ if (readEnvAutoconnectDisabled()) return void 0;
7124
+ const location = context.location;
7125
+ if (location === void 0) return void 0;
7126
+ if (detectWorktreeRoot(location.directory) === void 0) {
7127
+ return void 0;
7128
+ }
7129
+ const attributed = readAttribution({
7130
+ directory: location.directory,
7131
+ outsideWorktree: "return-undefined"
7132
+ }) !== void 0;
7133
+ return attributed ? void 0 : location.directory;
7134
+ };
7135
+
7136
+ // src/tui-entry/v1-setup-lock/v1-setup-lock.ts
7137
+ var SETUP_MODE = "route33-setup";
7138
+ var RESUME_BIND = "enter";
7139
+ var v1SetupLock = (deps) => {
7140
+ const setupPending = () => v2SetupDirectory({ location: { directory: deps.directory() } }) !== void 0;
7141
+ const pop = setupPending() ? deps.mode?.push(SETUP_MODE) : void 0;
7142
+ if (pop !== void 0) {
7143
+ deps.keymap?.registerLayer({
7144
+ bindings: ["route33.setup"],
7145
+ commands: [
7146
+ {
7147
+ bind: RESUME_BIND,
7148
+ id: "route33.setup",
7149
+ run: () => {
7150
+ void settle();
7151
+ },
7152
+ suggested: true,
7153
+ title: "Route 33: pick the budget for this folder"
7154
+ }
7155
+ ],
7156
+ mode: SETUP_MODE,
7157
+ priority: 10
7158
+ });
7159
+ }
7160
+ let running = false;
7161
+ const settle = async () => {
7162
+ if (running) return;
7163
+ running = true;
7164
+ try {
7165
+ if (setupPending()) {
7166
+ await deps.run();
7167
+ }
7168
+ } finally {
7169
+ running = false;
7170
+ }
7171
+ if (setupPending()) return;
7172
+ pop?.();
7173
+ };
7174
+ return { start: settle };
7175
+ };
7176
+
7101
7177
  // src/tui-entry/v1-connect-wizard/v1-connect-wizard.ts
7102
7178
  var createV1ConnectWizard = (composeOptions = productionOptions) => (api) => {
7103
7179
  if (readEnvDirectApiKey() !== void 0 || readEnvAutoconnectDisabled()) {
7104
7180
  return Promise.resolve();
7105
7181
  }
7106
- const directory = api.state.path.directory;
7107
- const unconnected = readAttribution({
7108
- directory,
7109
- outsideWorktree: "return-undefined"
7110
- }) === void 0;
7111
- if (unconnected) {
7112
- void runConnect(api, composeOptions);
7113
- }
7182
+ const surfaces = api;
7183
+ const lock = v1SetupLock({
7184
+ directory: () => api.state.path.directory,
7185
+ ...surfaces.keymap === void 0 ? {} : {
7186
+ keymap: {
7187
+ registerLayer: (layer) => surfaces.keymap?.registerLayer(layer)
7188
+ }
7189
+ },
7190
+ ...surfaces.mode === void 0 ? {} : { mode: surfaces.mode },
7191
+ run: () => runConnect(api, composeOptions)
7192
+ });
7193
+ void lock.start();
7114
7194
  const legacyCommands = api.command;
7115
7195
  legacyCommands?.register(() => [
7116
7196
  {
@@ -7123,6 +7203,367 @@ var createV1ConnectWizard = (composeOptions = productionOptions) => (api) => {
7123
7203
  return Promise.resolve();
7124
7204
  };
7125
7205
 
7206
+ // src/tui-entry/show-r33-menu/show-r33-menu.ts
7207
+ init_attribution();
7208
+
7209
+ // src/tui-entry/v2-autoconnect/v2-autoconnect.ts
7210
+ init_attribution();
7211
+
7212
+ // src/tui-entry/v2-attribution-field/v2-attribution-field.ts
7213
+ var v2AttributionField = (methods) => {
7214
+ const browserMethods = methods?.filter(
7215
+ (entry) => entry.type === "oauth" && entry.id === "browser"
7216
+ );
7217
+ const fields = browserMethods?.flatMap((entry) => entry.form ?? []);
7218
+ const field = fields?.find((entry) => entry.key === "attribution");
7219
+ if (field?.options === void 0 || field.options.length === 0) {
7220
+ return void 0;
7221
+ }
7222
+ return field;
7223
+ };
7224
+
7225
+ // src/tui-entry/v2-integration-surface/v2-integration-surface.ts
7226
+ var v2IntegrationSurface = (context) => context.client?.integration ?? context.client?.api?.integration;
7227
+
7228
+ // src/tui-entry/v2-attribution-form/v2-attribution-form.ts
7229
+ var v2AttributionForm = async (context) => {
7230
+ const get = v2IntegrationSurface(context)?.get;
7231
+ if (get === void 0) return void 0;
7232
+ const integration = await get({
7233
+ integrationID: "route33",
7234
+ ...context.location === void 0 ? {} : { location: { directory: context.location.directory } }
7235
+ }).catch(() => void 0);
7236
+ return v2AttributionField(integration?.data.methods);
7237
+ };
7238
+
7239
+ // src/tui-entry/v2-connect-copy/v2-connect-copy.ts
7240
+ var V2_CONNECT_COPY = {
7241
+ dismissed: "Route 33 is not set up for this folder yet. Press Enter to pick the budget, or run /connect and choose Route 33.",
7242
+ expired: "The Route 33 sign-in link expired. Press Enter to retry, or run /connect and choose Route 33.",
7243
+ manualFallback: "Route 33 is not connected in this folder. Run /connect, choose Route 33, and follow the steps.",
7244
+ manualPath: "Press Enter to retry, or run /connect, choose Route 33, and follow the steps.",
7245
+ pickerTitle: "Which budget covers Route 33 usage in this folder?",
7246
+ setupIncomplete: "Route 33 setup did not complete. Press Enter to retry, or run /connect and choose Route 33.",
7247
+ signInFailed: "Route 33 sign-in did not complete. Press Enter to retry, or run /connect and choose Route 33.",
7248
+ signInTitle: "Route 33 \u2014 sign in",
7249
+ statusUnavailable: "Route 33 sign-in did not settle. Press Enter to retry, or run /connect and choose Route 33.",
7250
+ stale: "That Route 33 option is no longer available. Press Enter to retry, or run /connect and choose Route 33.",
7251
+ success: "Route 33 connected \u2713 \u2014 pick a route_33 model and start.",
7252
+ timedOut: "Route 33 sign-in timed out. Press Enter to retry, or run /connect and choose Route 33."
7253
+ };
7254
+
7255
+ // src/tui-entry/v2-outcome-copy/v2-outcome-copy.ts
7256
+ var v2OutcomeCopy = (outcome, failedFallback) => {
7257
+ if (outcome.kind === "failed") {
7258
+ return {
7259
+ message: `${outcome.message ?? failedFallback} ${V2_CONNECT_COPY.manualPath}`,
7260
+ variant: "error"
7261
+ };
7262
+ }
7263
+ const byKind = {
7264
+ complete: V2_CONNECT_COPY.manualFallback,
7265
+ expired: V2_CONNECT_COPY.expired,
7266
+ failed: failedFallback,
7267
+ timeout: V2_CONNECT_COPY.timedOut,
7268
+ unavailable: V2_CONNECT_COPY.statusUnavailable
7269
+ };
7270
+ return { message: byKind[outcome.kind], variant: "error" };
7271
+ };
7272
+
7273
+ // src/tui-entry/v2-budget-picker/v2-budget-picker.ts
7274
+ var v2BudgetPicker = async (deps) => {
7275
+ if (!deps.unattributed()) {
7276
+ deps.toast({ message: V2_CONNECT_COPY.success, variant: "success" });
7277
+ return;
7278
+ }
7279
+ const options = deps.form.options ?? [];
7280
+ const selection = await deps.dialog.select({
7281
+ options: options.map((option) => ({
7282
+ description: option.description,
7283
+ title: option.label,
7284
+ value: option.value
7285
+ })),
7286
+ title: deps.form.title ?? V2_CONNECT_COPY.pickerTitle
7287
+ });
7288
+ if (selection === void 0) {
7289
+ deps.toast({ message: V2_CONNECT_COPY.dismissed });
7290
+ return;
7291
+ }
7292
+ if (!options.some((option) => option.value === selection)) {
7293
+ deps.toast({ message: V2_CONNECT_COPY.stale, variant: "error" });
7294
+ return;
7295
+ }
7296
+ if (!deps.unattributed()) {
7297
+ deps.toast({ message: V2_CONNECT_COPY.success, variant: "success" });
7298
+ return;
7299
+ }
7300
+ let second;
7301
+ try {
7302
+ second = await deps.connect({
7303
+ answer: { [deps.form.key]: selection },
7304
+ integrationID: "route33",
7305
+ location: deps.locationInput,
7306
+ methodID: "browser"
7307
+ });
7308
+ } catch (error) {
7309
+ deps.toast({
7310
+ message: `${error instanceof Error ? error.message : String(error)} ${V2_CONNECT_COPY.manualPath}`,
7311
+ variant: "error"
7312
+ });
7313
+ return;
7314
+ }
7315
+ const settled = await deps.pollTerminal(second.data.attemptID);
7316
+ if (settled.kind === "complete") {
7317
+ deps.toast({ message: V2_CONNECT_COPY.success, variant: "success" });
7318
+ return;
7319
+ }
7320
+ const copy = v2OutcomeCopy(settled, V2_CONNECT_COPY.setupIncomplete);
7321
+ deps.toast(copy);
7322
+ };
7323
+
7324
+ // src/tui-entry/v2-connect-surface/v2-connect-surface.ts
7325
+ var v2ConnectSurface = (context) => v2IntegrationSurface(context)?.oauth?.connect;
7326
+
7327
+ // src/tui-entry/v2-form-reader/v2-form-reader.ts
7328
+ init_abortable_sleep2();
7329
+ var createV2FormReader = ({ attempts = 5, context, retryDelayMs = 500 }) => async () => {
7330
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
7331
+ const form = await v2AttributionForm(context);
7332
+ if (form !== void 0) return form;
7333
+ if (attempt < attempts) {
7334
+ await abortableSleep(retryDelayMs);
7335
+ }
7336
+ }
7337
+ return void 0;
7338
+ };
7339
+
7340
+ // src/tui-entry/v2-poll-terminal/v2-poll-terminal.ts
7341
+ init_abortable_sleep2();
7342
+ var createV2PollTerminal = ({
7343
+ locationInput,
7344
+ maxPolls = 600,
7345
+ pollDelayMs = 1e3,
7346
+ status,
7347
+ statusErrorLimit = 5
7348
+ }) => async (attemptID) => {
7349
+ let errors = 0;
7350
+ for (let poll = 0; poll < maxPolls; poll += 1) {
7351
+ await abortableSleep(pollDelayMs);
7352
+ try {
7353
+ const result = await status({
7354
+ attemptID,
7355
+ integrationID: "route33",
7356
+ location: locationInput
7357
+ });
7358
+ errors = 0;
7359
+ const state = result.data.status;
7360
+ if (state === "pending") continue;
7361
+ if (state === "failed") {
7362
+ return { kind: "failed", message: result.data.message };
7363
+ }
7364
+ return { kind: state };
7365
+ } catch {
7366
+ errors += 1;
7367
+ if (errors >= statusErrorLimit) return { kind: "unavailable" };
7368
+ }
7369
+ }
7370
+ return { kind: "timeout" };
7371
+ };
7372
+
7373
+ // src/tui-entry/v2-connect-retry/v2-connect-retry.ts
7374
+ init_abortable_sleep2();
7375
+
7376
+ // src/tui-entry/is-method-not-registered/is-method-not-registered.ts
7377
+ var isMethodNotRegistered = (error) => error instanceof Error && error.message.includes("OAuth method not found");
7378
+
7379
+ // src/tui-entry/v2-connect-retry/v2-connect-retry.ts
7380
+ var v2ConnectRetry = async ({
7381
+ connect,
7382
+ input,
7383
+ maxAttempts = 20,
7384
+ retryDelayMs = 500
7385
+ }) => {
7386
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
7387
+ try {
7388
+ return await connect(input);
7389
+ } catch (error) {
7390
+ if (!isMethodNotRegistered(error)) {
7391
+ throw error;
7392
+ }
7393
+ if (attempt < maxAttempts) {
7394
+ await abortableSleep(retryDelayMs);
7395
+ }
7396
+ }
7397
+ }
7398
+ return void 0;
7399
+ };
7400
+
7401
+ // src/tui-entry/v2-sign-in-wait/v2-sign-in-wait.ts
7402
+ var v2SignInWait = async (deps) => {
7403
+ const state = { dismissed: false };
7404
+ void deps.alert().then(() => {
7405
+ state.dismissed = true;
7406
+ }).catch(() => {
7407
+ state.dismissed = true;
7408
+ });
7409
+ const outcome = await deps.pollTerminal(deps.attemptID);
7410
+ return { dismissed: state.dismissed, outcome };
7411
+ };
7412
+
7413
+ // src/tui-entry/v2-sign-in-pass/v2-sign-in-pass.ts
7414
+ var v2SignInPass = async ({
7415
+ connect,
7416
+ dialog,
7417
+ formReader,
7418
+ locationInput,
7419
+ maxAttempts,
7420
+ pollTerminal,
7421
+ retryDelayMs,
7422
+ toast,
7423
+ unattributed
7424
+ }) => {
7425
+ let attempt;
7426
+ try {
7427
+ attempt = await v2ConnectRetry({
7428
+ connect,
7429
+ input: {
7430
+ integrationID: "route33",
7431
+ location: locationInput,
7432
+ methodID: "browser"
7433
+ },
7434
+ maxAttempts,
7435
+ retryDelayMs
7436
+ });
7437
+ } catch (error) {
7438
+ toast({
7439
+ message: `${error instanceof Error ? error.message : String(error)} ${V2_CONNECT_COPY.manualPath}`,
7440
+ variant: "error"
7441
+ });
7442
+ return { aborted: true };
7443
+ }
7444
+ if (attempt === void 0) {
7445
+ toast({ message: V2_CONNECT_COPY.manualFallback, variant: "error" });
7446
+ return { aborted: true };
7447
+ }
7448
+ const waited = await v2SignInWait({
7449
+ alert: () => dialog.alert({
7450
+ message: `${attempt.data.instructions}
7451
+
7452
+ ${attempt.data.url}`,
7453
+ title: V2_CONNECT_COPY.signInTitle
7454
+ }),
7455
+ attemptID: attempt.data.attemptID,
7456
+ pollTerminal
7457
+ });
7458
+ if (waited.dismissed) {
7459
+ if (waited.outcome.kind === "complete") {
7460
+ return { connected: true };
7461
+ }
7462
+ toast({ message: V2_CONNECT_COPY.dismissed });
7463
+ return { aborted: true };
7464
+ }
7465
+ dialog.clear();
7466
+ const outcome = waited.outcome;
7467
+ if (outcome.kind === "complete") {
7468
+ return { connected: true };
7469
+ }
7470
+ if (outcome.kind === "failed") {
7471
+ if (!unattributed()) {
7472
+ return { connected: true };
7473
+ }
7474
+ const form = await formReader();
7475
+ if (form === void 0) {
7476
+ toast(v2OutcomeCopy(outcome, V2_CONNECT_COPY.signInFailed));
7477
+ return { aborted: true };
7478
+ }
7479
+ return { form };
7480
+ }
7481
+ toast(v2OutcomeCopy(outcome, V2_CONNECT_COPY.signInFailed));
7482
+ return { aborted: true };
7483
+ };
7484
+
7485
+ // src/tui-entry/v2-status-surface/v2-status-surface.ts
7486
+ var v2StatusSurface = (context) => v2IntegrationSurface(context)?.oauth?.status;
7487
+
7488
+ // src/tui-entry/v2-connect-runner/v2-connect-runner.ts
7489
+ var v2GuidedConnect = async (deps) => {
7490
+ const { context, unattributed } = deps;
7491
+ const connect = v2ConnectSurface(context);
7492
+ const status = v2StatusSurface(context);
7493
+ const dialog = context.ui.dialog;
7494
+ const toast = (input) => {
7495
+ context.ui.toast.show(input);
7496
+ };
7497
+ const location = context.location;
7498
+ if (connect === void 0 || location === void 0) return;
7499
+ if (!unattributed()) return;
7500
+ if (status === void 0 || dialog === void 0) {
7501
+ toast({ message: V2_CONNECT_COPY.manualFallback });
7502
+ return;
7503
+ }
7504
+ const locationInput = { directory: location.directory };
7505
+ const pollTerminal = createV2PollTerminal({
7506
+ locationInput,
7507
+ maxPolls: deps.maxPolls,
7508
+ pollDelayMs: deps.pollDelayMs,
7509
+ status,
7510
+ statusErrorLimit: deps.statusErrorLimit
7511
+ });
7512
+ const earlyForm = await v2AttributionForm(context);
7513
+ if (earlyForm !== void 0) {
7514
+ await v2BudgetPicker({
7515
+ connect,
7516
+ dialog,
7517
+ form: earlyForm,
7518
+ locationInput,
7519
+ pollTerminal,
7520
+ toast,
7521
+ unattributed
7522
+ });
7523
+ return;
7524
+ }
7525
+ const result = await v2SignInPass({
7526
+ connect,
7527
+ dialog,
7528
+ formReader: createV2FormReader({
7529
+ attempts: deps.formReadAttempts,
7530
+ context,
7531
+ retryDelayMs: deps.retryDelayMs
7532
+ }),
7533
+ locationInput,
7534
+ maxAttempts: deps.maxAttempts,
7535
+ pollTerminal,
7536
+ retryDelayMs: deps.retryDelayMs,
7537
+ toast,
7538
+ unattributed
7539
+ });
7540
+ if ("aborted" in result) return;
7541
+ if ("connected" in result) {
7542
+ toast({ message: V2_CONNECT_COPY.success, variant: "success" });
7543
+ return;
7544
+ }
7545
+ await v2BudgetPicker({
7546
+ connect,
7547
+ dialog,
7548
+ form: result.form,
7549
+ locationInput,
7550
+ pollTerminal,
7551
+ toast,
7552
+ unattributed
7553
+ });
7554
+ };
7555
+
7556
+ // src/tui-entry/v2-autoconnect/v2-autoconnect.ts
7557
+ var v2Autoconnect = async (context) => {
7558
+ const directory = v2SetupDirectory(context);
7559
+ if (directory === void 0) return;
7560
+ const unattributed = () => readAttribution({
7561
+ directory,
7562
+ outsideWorktree: "return-undefined"
7563
+ }) === void 0;
7564
+ await v2GuidedConnect({ context, unattributed });
7565
+ };
7566
+
7126
7567
  // src/tui-entry/show-r33-menu/show-r33-menu.ts
7127
7568
  var menuOptions2 = [
7128
7569
  {
@@ -7152,11 +7593,15 @@ var showR33Menu = async (context) => {
7152
7593
  options: menuOptions2
7153
7594
  });
7154
7595
  if (selection === void 0) return;
7155
- if (selection === "connect") {
7156
- context.ui.toast.show({
7157
- message: "Route 33 connect \u2014 finish the browser sign-in, then run /connect in OpenCode and choose Route 33 to assign a budget.",
7158
- variant: "info"
7159
- });
7596
+ if (selection === "connect" || selection === "change") {
7597
+ const location = context.location ?? context.data?.location.default();
7598
+ if (selection === "change" && location !== void 0) {
7599
+ clearAttribution({
7600
+ directory: location.directory,
7601
+ outsideWorktree: "return-undefined"
7602
+ });
7603
+ }
7604
+ await v2Autoconnect({ ...context, location });
7160
7605
  return;
7161
7606
  }
7162
7607
  context.ui.toast.show({
@@ -7165,72 +7610,49 @@ var showR33Menu = async (context) => {
7165
7610
  });
7166
7611
  };
7167
7612
 
7168
- // src/tui-entry/v2-autoconnect/v2-autoconnect.ts
7169
- init_attribution();
7170
- init_cli();
7171
-
7172
- // src/tui-entry/is-method-not-registered/is-method-not-registered.ts
7173
- var isMethodNotRegistered = (error) => error instanceof Error && error.message.includes("OAuth method not found");
7174
-
7175
- // src/tui-entry/v2-connect-surface/v2-connect-surface.ts
7176
- var v2ConnectSurface = (context) => {
7177
- const oauth = context.client?.integration?.oauth ?? context.client?.api?.integration?.oauth;
7178
- return oauth?.connect;
7179
- };
7180
-
7181
- // src/tui-entry/v2-connect-runner/v2-connect-runner.ts
7182
- var createV2ConnectRunner = ({
7183
- context,
7184
- maxAttempts = 20,
7185
- retryDelayMs = 500,
7186
- unattributed
7187
- }) => {
7188
- const connect = v2ConnectSurface(context);
7189
- const sleep = (ms) => new Promise((resolve2) => {
7190
- setTimeout(resolve2, ms);
7191
- });
7192
- return async (message) => {
7193
- if (connect === void 0) return;
7194
- if (!unattributed()) return;
7195
- context.ui.toast.show({ message, variant: "info" });
7196
- for (let attempt = 1; ; attempt += 1) {
7197
- if (!unattributed()) return;
7198
- try {
7199
- await connect({
7200
- integrationID: "route33",
7201
- methodID: "browser"
7202
- });
7203
- return;
7204
- } catch (error) {
7205
- if (attempt >= maxAttempts || !isMethodNotRegistered(error)) return;
7206
- await sleep(retryDelayMs);
7207
- }
7613
+ // src/tui-entry/v2-setup-lock/v2-setup-lock.ts
7614
+ var SETUP_MODE2 = "route33-setup";
7615
+ var RESUME_BIND2 = "enter";
7616
+ var v2SetupLock = (context) => {
7617
+ const required = v2SetupDirectory(context) !== void 0;
7618
+ const release = required ? context.keymap?.mode.push(SETUP_MODE2) : void 0;
7619
+ if (required) {
7620
+ context.keymap?.layer(() => ({
7621
+ bindings: ["route33.setup"],
7622
+ commands: [
7623
+ {
7624
+ bind: RESUME_BIND2,
7625
+ id: "route33.setup",
7626
+ run: () => {
7627
+ void settle();
7628
+ },
7629
+ suggested: true,
7630
+ title: "Route 33: pick the budget for this folder"
7631
+ }
7632
+ ],
7633
+ mode: SETUP_MODE2,
7634
+ priority: 10
7635
+ }));
7636
+ }
7637
+ let running = false;
7638
+ const settle = async () => {
7639
+ if (running) return;
7640
+ running = true;
7641
+ try {
7642
+ await v2Autoconnect(context);
7643
+ } finally {
7644
+ running = false;
7208
7645
  }
7646
+ if (v2SetupDirectory(context) !== void 0) return;
7647
+ release?.();
7209
7648
  };
7210
- };
7211
-
7212
- // src/tui-entry/v2-autoconnect/v2-autoconnect.ts
7213
- var v2Autoconnect = async (context) => {
7214
- if (readEnvDirectApiKey() !== void 0) return;
7215
- if (readEnvAutoconnectDisabled()) return;
7216
- const location = context.location;
7217
- if (location === void 0) return;
7218
- const unattributed = () => readAttribution({
7219
- directory: location.directory,
7220
- outsideWorktree: "return-undefined"
7221
- }) === void 0;
7222
- const connectPass = createV2ConnectRunner({ context, unattributed });
7223
- await connectPass(
7224
- "Route 33 is not connected \u2014 signing in now, then pick the budget for this folder."
7225
- );
7226
- await connectPass("Signed in to Route 33 \u2014 opening the budget picker.");
7649
+ return { start: settle };
7227
7650
  };
7228
7651
 
7229
7652
  // src/tui-entry/v2-tui/v2-tui.ts
7230
7653
  var createV2Tui = () => ({
7231
7654
  id: "route33",
7232
- setup: async (context) => {
7233
- await v2Autoconnect(context);
7655
+ setup: (context) => {
7234
7656
  context.keymap?.layer(() => ({
7235
7657
  mode: "global",
7236
7658
  priority: 10,
@@ -7248,6 +7670,8 @@ var createV2Tui = () => ({
7248
7670
  ],
7249
7671
  bindings: ["route33.menu"]
7250
7672
  }));
7673
+ const location = context.location ?? context.data?.location.default();
7674
+ void v2SetupLock({ ...context, location }).start().catch(() => void 0);
7251
7675
  }
7252
7676
  });
7253
7677