@route_33/opencode 0.4.7-rc.6 → 0.4.7-rc.8

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",
@@ -970,46 +527,286 @@ var init_auth_error = __esm({
970
527
  this.name = "AuthError";
971
528
  this.statusCode = options?.statusCode;
972
529
  }
973
- code;
974
- statusCode;
530
+ code;
531
+ statusCode;
532
+ };
533
+ }
534
+ });
535
+
536
+ // src/auth/auth-error/index.ts
537
+ var init_auth_error2 = __esm({
538
+ "src/auth/auth-error/index.ts"() {
539
+ "use strict";
540
+ init_auth_error();
541
+ }
542
+ });
543
+
544
+ // src/auth/build-authorize-url/build-authorize-url.ts
545
+ var buildAuthorizeUrl;
546
+ var init_build_authorize_url = __esm({
547
+ "src/auth/build-authorize-url/build-authorize-url.ts"() {
548
+ "use strict";
549
+ buildAuthorizeUrl = (issuerUrl, request) => {
550
+ const url = new URL("/authorize", issuerUrl);
551
+ url.search = new URLSearchParams({
552
+ client_id: request.clientId,
553
+ code_challenge: request.codeChallenge,
554
+ code_challenge_method: "S256",
555
+ redirect_uri: request.redirectUri,
556
+ response_type: "code",
557
+ scope: request.scope,
558
+ state: request.state
559
+ }).toString();
560
+ return url;
561
+ };
562
+ }
563
+ });
564
+
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;
975
788
  };
976
789
  }
977
790
  });
978
791
 
979
- // src/auth/auth-error/index.ts
980
- var init_auth_error2 = __esm({
981
- "src/auth/auth-error/index.ts"() {
982
- "use strict";
983
- init_auth_error();
984
- }
985
- });
986
-
987
- // src/auth/build-authorize-url/build-authorize-url.ts
988
- var buildAuthorizeUrl;
989
- var init_build_authorize_url = __esm({
990
- "src/auth/build-authorize-url/build-authorize-url.ts"() {
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"() {
991
795
  "use strict";
992
- buildAuthorizeUrl = (issuerUrl, request) => {
993
- const url = new URL("/authorize", issuerUrl);
994
- url.search = new URLSearchParams({
995
- client_id: request.clientId,
996
- code_challenge: request.codeChallenge,
997
- code_challenge_method: "S256",
998
- redirect_uri: request.redirectUri,
999
- response_type: "code",
1000
- scope: request.scope,
1001
- state: request.state
1002
- }).toString();
1003
- return url;
1004
- };
796
+ init_parse_management_subject();
1005
797
  }
1006
798
  });
1007
799
 
1008
- // src/auth/build-authorize-url/index.ts
1009
- var init_build_authorize_url2 = __esm({
1010
- "src/auth/build-authorize-url/index.ts"() {
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
 
@@ -2115,12 +1912,12 @@ var init_catalog_fetch_error2 = __esm({
2115
1912
  });
2116
1913
 
2117
1914
  // src/catalog/catalog-cache/cache-file-path/cache-file-path.ts
2118
- import * as path6 from "node:path";
1915
+ import * as path3 from "node:path";
2119
1916
  var cacheFilePath;
2120
1917
  var init_cache_file_path = __esm({
2121
1918
  "src/catalog/catalog-cache/cache-file-path/cache-file-path.ts"() {
2122
1919
  "use strict";
2123
- cacheFilePath = (keyHash, cacheDir) => path6.join(cacheDir, `catalog-${keyHash}.json`);
1920
+ cacheFilePath = (keyHash, cacheDir) => path3.join(cacheDir, `catalog-${keyHash}.json`);
2124
1921
  }
2125
1922
  });
2126
1923
 
@@ -2229,7 +2026,7 @@ var init_is_catalog_model_record2 = __esm({
2229
2026
  });
2230
2027
 
2231
2028
  // src/catalog/catalog-cache/read-disk/read-disk.ts
2232
- import * as fs6 from "node:fs";
2029
+ import * as fs from "node:fs";
2233
2030
  var readDisk;
2234
2031
  var init_read_disk = __esm({
2235
2032
  "src/catalog/catalog-cache/read-disk/read-disk.ts"() {
@@ -2241,7 +2038,7 @@ var init_read_disk = __esm({
2241
2038
  readDisk = (keyHash, cacheDir) => {
2242
2039
  try {
2243
2040
  const parsed = JSON.parse(
2244
- fs6.readFileSync(cacheFilePath(keyHash, cacheDir), "utf8")
2041
+ fs.readFileSync(cacheFilePath(keyHash, cacheDir), "utf8")
2245
2042
  );
2246
2043
  if (!isRecord(parsed) || parsed["version"] !== CATALOG_CACHE_VERSION || typeof parsed["fetchedAt"] !== "number" || !isCatalogModelRecord(parsed["models"])) {
2247
2044
  return void 0;
@@ -2326,7 +2123,7 @@ var init_read_stale_catalog2 = __esm({
2326
2123
  });
2327
2124
 
2328
2125
  // src/catalog/catalog-cache/write-catalog/write-catalog.ts
2329
- import * as fs7 from "node:fs";
2126
+ import * as fs2 from "node:fs";
2330
2127
  var writeCatalog;
2331
2128
  var init_write_catalog = __esm({
2332
2129
  "src/catalog/catalog-cache/write-catalog/write-catalog.ts"() {
@@ -2345,8 +2142,8 @@ var init_write_catalog = __esm({
2345
2142
  };
2346
2143
  catalogMemory.set(keyHash, record);
2347
2144
  try {
2348
- fs7.mkdirSync(options.cacheDir, { recursive: true });
2349
- fs7.writeFileSync(
2145
+ fs2.mkdirSync(options.cacheDir, { recursive: true });
2146
+ fs2.writeFileSync(
2350
2147
  cacheFilePath(keyHash, options.cacheDir),
2351
2148
  JSON.stringify({ version: CATALOG_CACHE_VERSION, ...record })
2352
2149
  );
@@ -3841,7 +3638,7 @@ var init_fetch_live2 = __esm({
3841
3638
  });
3842
3639
 
3843
3640
  // src/enrich/models-dev/read-models-dev-cache/read-models-dev-cache.ts
3844
- import * as fs8 from "node:fs";
3641
+ import * as fs3 from "node:fs";
3845
3642
  var readModelsDevCache;
3846
3643
  var init_read_models_dev_cache = __esm({
3847
3644
  "src/enrich/models-dev/read-models-dev-cache/read-models-dev-cache.ts"() {
@@ -3850,7 +3647,7 @@ var init_read_models_dev_cache = __esm({
3850
3647
  init_num2();
3851
3648
  readModelsDevCache = (cachePath) => {
3852
3649
  try {
3853
- const parsed = JSON.parse(fs8.readFileSync(cachePath, "utf8"));
3650
+ const parsed = JSON.parse(fs3.readFileSync(cachePath, "utf8"));
3854
3651
  if (!isRecord(parsed)) {
3855
3652
  return void 0;
3856
3653
  }
@@ -3876,8 +3673,8 @@ var init_read_models_dev_cache2 = __esm({
3876
3673
  });
3877
3674
 
3878
3675
  // 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";
3676
+ import * as fs4 from "node:fs";
3677
+ import * as path4 from "node:path";
3881
3678
  var writeModelsDevCache;
3882
3679
  var init_write_models_dev_cache = __esm({
3883
3680
  "src/enrich/models-dev/write-models-dev-cache/write-models-dev-cache.ts"() {
@@ -3885,8 +3682,8 @@ var init_write_models_dev_cache = __esm({
3885
3682
  init_shared();
3886
3683
  writeModelsDevCache = (cachePath, envelope) => {
3887
3684
  try {
3888
- fs9.mkdirSync(path7.dirname(cachePath), { recursive: true });
3889
- fs9.writeFileSync(cachePath, JSON.stringify(envelope), "utf8");
3685
+ fs4.mkdirSync(path4.dirname(cachePath), { recursive: true });
3686
+ fs4.writeFileSync(cachePath, JSON.stringify(envelope), "utf8");
3890
3687
  } catch (error) {
3891
3688
  logger.warn(
3892
3689
  "failed to write models.dev cache:",
@@ -3906,7 +3703,7 @@ var init_write_models_dev_cache2 = __esm({
3906
3703
  });
3907
3704
 
3908
3705
  // src/enrich/models-dev/load-models-dev/load-models-dev.ts
3909
- import * as path8 from "node:path";
3706
+ import * as path5 from "node:path";
3910
3707
  var CACHE_FILE, loadModelsDev;
3911
3708
  var init_load_models_dev = __esm({
3912
3709
  "src/enrich/models-dev/load-models-dev/load-models-dev.ts"() {
@@ -3922,7 +3719,7 @@ var init_load_models_dev = __esm({
3922
3719
  const cacheDir = options.cacheDir ?? resolveCacheDir({});
3923
3720
  const ttlMs = options.ttlMs ?? MODELS_DEV_TTL_MS;
3924
3721
  const now = options.now ?? Date.now;
3925
- const cachePath = path8.join(cacheDir, CACHE_FILE);
3722
+ const cachePath = path5.join(cacheDir, CACHE_FILE);
3926
3723
  const cached = readModelsDevCache(cachePath);
3927
3724
  if (cached !== void 0 && now() - cached.fetchedAt < ttlMs) {
3928
3725
  return createModelsDevSource("cache", cached.data);
@@ -4087,20 +3884,20 @@ var init_regenerate_models2 = __esm({
4087
3884
  });
4088
3885
 
4089
3886
  // src/config/remove-legacy-manifest/remove-legacy-manifest.ts
4090
- import * as fs10 from "node:fs";
4091
- import * as path9 from "node:path";
3887
+ import * as fs5 from "node:fs";
3888
+ import * as path6 from "node:path";
4092
3889
  var removeLegacyManifest;
4093
3890
  var init_remove_legacy_manifest = __esm({
4094
3891
  "src/config/remove-legacy-manifest/remove-legacy-manifest.ts"() {
4095
3892
  "use strict";
4096
3893
  init_shared();
4097
3894
  removeLegacyManifest = (root) => {
4098
- const file = path9.join(root, ".opencode", "route33-generated.json");
3895
+ const file = path6.join(root, ".opencode", "route33-generated.json");
4099
3896
  try {
4100
- if (!fs10.existsSync(file)) {
3897
+ if (!fs5.existsSync(file)) {
4101
3898
  return;
4102
3899
  }
4103
- fs10.rmSync(file);
3900
+ fs5.rmSync(file);
4104
3901
  logger.info(
4105
3902
  "route_33: removed obsolete route33-generated.json (regeneration is stateless since 0.4.4)"
4106
3903
  );
@@ -4745,9 +4542,9 @@ var init_default_gateway_key_ttl_ms2 = __esm({
4745
4542
  });
4746
4543
 
4747
4544
  // 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";
4545
+ import { randomUUID } from "node:crypto";
4546
+ import * as fs6 from "node:fs/promises";
4547
+ import * as path7 from "node:path";
4751
4548
  var FileSecretStore;
4752
4549
  var init_file_secret_store = __esm({
4753
4550
  "src/key-lease/file-secret-store/file-secret-store.ts"() {
@@ -4764,7 +4561,7 @@ var init_file_secret_store = __esm({
4764
4561
  throw new TypeError("File secret store scope is not portable");
4765
4562
  }
4766
4563
  this.#directory = options.directory;
4767
- this.#file = path10.join(options.directory, `lease-${options.scopeId}.json`);
4564
+ this.#file = path7.join(options.directory, `lease-${options.scopeId}.json`);
4768
4565
  }
4769
4566
  /** Reads and parses the scoped gateway credential.
4770
4567
  * @returns The persisted credential, when present.
@@ -4772,7 +4569,7 @@ var init_file_secret_store = __esm({
4772
4569
  async get() {
4773
4570
  let contents;
4774
4571
  try {
4775
- contents = await fs11.readFile(this.#file, "utf8");
4572
+ contents = await fs6.readFile(this.#file, "utf8");
4776
4573
  } catch (cause) {
4777
4574
  if (cause instanceof Error && "code" in cause && cause.code === "ENOENT") {
4778
4575
  return void 0;
@@ -4788,22 +4585,22 @@ var init_file_secret_store = __esm({
4788
4585
  */
4789
4586
  async set(key) {
4790
4587
  if (key === void 0) {
4791
- await fs11.rm(this.#file, { force: true });
4588
+ await fs6.rm(this.#file, { force: true });
4792
4589
  return;
4793
4590
  }
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`);
4591
+ await fs6.mkdir(this.#directory, { mode: 448, recursive: true });
4592
+ await fs6.chmod(this.#directory, 448);
4593
+ const temporary = path7.join(this.#directory, `.lease-${randomUUID()}.tmp`);
4797
4594
  try {
4798
- await fs11.writeFile(temporary, `${JSON.stringify(key.value)}
4595
+ await fs6.writeFile(temporary, `${JSON.stringify(key.value)}
4799
4596
  `, {
4800
4597
  encoding: "utf8",
4801
4598
  flag: "wx",
4802
4599
  mode: 384
4803
4600
  });
4804
- await fs11.rename(temporary, this.#file);
4601
+ await fs6.rename(temporary, this.#file);
4805
4602
  } finally {
4806
- await fs11.rm(temporary, { force: true });
4603
+ await fs6.rm(temporary, { force: true });
4807
4604
  }
4808
4605
  }
4809
4606
  };
@@ -5402,70 +5199,273 @@ var init_lease_for_attribution = __esm({
5402
5199
  state: options.installation.state
5403
5200
  });
5404
5201
  }
5405
- if (options.rejection !== void 0) {
5406
- return rejectLease({
5407
- current,
5408
- rejection: options.rejection,
5409
- secretStore: options.installation.secretStore,
5410
- state: options.installation.state,
5411
- storedKey
5412
- });
5202
+ if (options.rejection !== void 0) {
5203
+ return rejectLease({
5204
+ current,
5205
+ rejection: options.rejection,
5206
+ secretStore: options.installation.secretStore,
5207
+ state: options.installation.state,
5208
+ storedKey
5209
+ });
5210
+ }
5211
+ const reusable = reusableLease({
5212
+ attribution: options.attribution,
5213
+ current,
5214
+ now,
5215
+ policy,
5216
+ state: options.installation.state,
5217
+ storedKey
5218
+ });
5219
+ if (reusable !== void 0) {
5220
+ return reusable;
5221
+ }
5222
+ try {
5223
+ const renewed = await renewKey({
5224
+ leaseState: options.installation.state,
5225
+ mint: {
5226
+ attribution: options.attribution,
5227
+ clock,
5228
+ identity: {
5229
+ credential: await resolveSeamValue(options.management.credential),
5230
+ subject: await resolveSeamValue(options.management.subject)
5231
+ },
5232
+ installation: {
5233
+ keyName: options.installation.keyName,
5234
+ ttlMs: policy.ttlMs
5235
+ },
5236
+ managementClient: options.management.client
5237
+ },
5238
+ secretStore: options.installation.secretStore
5239
+ });
5240
+ if (policy.orphanRetentionCycles !== void 0) {
5241
+ await controlOrphans({
5242
+ clock,
5243
+ currentKeyId: renewed.lease.keyId,
5244
+ keyName: options.installation.keyName,
5245
+ managementClient: options.management.client,
5246
+ managementCredential: await resolveSeamValue(
5247
+ options.management.credential
5248
+ ),
5249
+ retentionCycles: policy.orphanRetentionCycles,
5250
+ ttlMs: policy.ttlMs
5251
+ });
5252
+ }
5253
+ return renewed;
5254
+ } catch (cause) {
5255
+ return mapRenewalFailure({ cause, current, now });
5256
+ }
5257
+ };
5258
+ }
5259
+ });
5260
+
5261
+ // src/key-lease/lease-for-attribution/index.ts
5262
+ var init_lease_for_attribution2 = __esm({
5263
+ "src/key-lease/lease-for-attribution/index.ts"() {
5264
+ "use strict";
5265
+ init_lease_for_attribution();
5266
+ }
5267
+ });
5268
+
5269
+ // src/attribution/detect-worktree-root/detect-worktree-root.ts
5270
+ import * as fs7 from "node:fs";
5271
+ import * as path8 from "node:path";
5272
+ var detectWorktreeRoot;
5273
+ var init_detect_worktree_root = __esm({
5274
+ "src/attribution/detect-worktree-root/detect-worktree-root.ts"() {
5275
+ "use strict";
5276
+ detectWorktreeRoot = (startDirectory) => {
5277
+ let directory = fs7.realpathSync(startDirectory);
5278
+ for (; ; ) {
5279
+ const gitEntry = path8.join(directory, ".git");
5280
+ if (fs7.existsSync(gitEntry)) {
5281
+ const entry = fs7.statSync(gitEntry);
5282
+ if (entry.isDirectory() || entry.isFile()) {
5283
+ return directory;
5284
+ }
5285
+ }
5286
+ const parent = path8.dirname(directory);
5287
+ if (parent === directory) {
5288
+ return void 0;
5289
+ }
5290
+ directory = parent;
5291
+ }
5292
+ };
5293
+ }
5294
+ });
5295
+
5296
+ // src/attribution/detect-worktree-root/index.ts
5297
+ var init_detect_worktree_root2 = __esm({
5298
+ "src/attribution/detect-worktree-root/index.ts"() {
5299
+ "use strict";
5300
+ init_detect_worktree_root();
5301
+ }
5302
+ });
5303
+
5304
+ // src/attribution/resolve-attribution-file/resolve-attribution-file.ts
5305
+ import * as fs8 from "node:fs";
5306
+ import * as path9 from "node:path";
5307
+ var resolveAttributionFile;
5308
+ var init_resolve_attribution_file = __esm({
5309
+ "src/attribution/resolve-attribution-file/resolve-attribution-file.ts"() {
5310
+ "use strict";
5311
+ init_detect_worktree_root2();
5312
+ resolveAttributionFile = (options) => {
5313
+ const worktreeRoot = detectWorktreeRoot(options.directory);
5314
+ if (worktreeRoot !== void 0) {
5315
+ return path9.join(worktreeRoot, ".opencode", "route33.attribution.json");
5316
+ }
5317
+ const fallbackRoots = {
5318
+ "return-undefined": void 0,
5319
+ "use-directory": fs8.realpathSync(options.directory)
5320
+ };
5321
+ const fallbackRoot = fallbackRoots[options.outsideWorktree];
5322
+ return fallbackRoot === void 0 ? void 0 : path9.join(fallbackRoot, ".opencode", "route33.attribution.json");
5323
+ };
5324
+ }
5325
+ });
5326
+
5327
+ // src/attribution/resolve-attribution-file/index.ts
5328
+ var init_resolve_attribution_file2 = __esm({
5329
+ "src/attribution/resolve-attribution-file/index.ts"() {
5330
+ "use strict";
5331
+ init_resolve_attribution_file();
5332
+ }
5333
+ });
5334
+
5335
+ // src/attribution/clear-attribution/clear-attribution.ts
5336
+ import * as fs9 from "node:fs";
5337
+ var clearAttribution;
5338
+ var init_clear_attribution = __esm({
5339
+ "src/attribution/clear-attribution/clear-attribution.ts"() {
5340
+ "use strict";
5341
+ init_resolve_attribution_file2();
5342
+ clearAttribution = (options) => {
5343
+ const file = resolveAttributionFile(options);
5344
+ if (file === void 0) {
5345
+ return false;
5346
+ }
5347
+ fs9.rmSync(file, { force: true });
5348
+ return true;
5349
+ };
5350
+ }
5351
+ });
5352
+
5353
+ // src/attribution/clear-attribution/index.ts
5354
+ var init_clear_attribution2 = __esm({
5355
+ "src/attribution/clear-attribution/index.ts"() {
5356
+ "use strict";
5357
+ init_clear_attribution();
5358
+ }
5359
+ });
5360
+
5361
+ // src/attribution/parse-attribution/parse-attribution.ts
5362
+ var parseAttribution;
5363
+ var init_parse_attribution = __esm({
5364
+ "src/attribution/parse-attribution/parse-attribution.ts"() {
5365
+ "use strict";
5366
+ init_adapters();
5367
+ init_predicates();
5368
+ parseAttribution = (value) => {
5369
+ if (!isRecord(value)) {
5370
+ throw new ContractParseError("invalid attribution");
5371
+ }
5372
+ if (value["kind"] === "personal") {
5373
+ return { kind: "personal" };
5374
+ }
5375
+ if (value["kind"] === "project" && typeof value["projectId"] === "string") {
5376
+ return { kind: "project", projectId: value["projectId"] };
5377
+ }
5378
+ throw new ContractParseError("invalid attribution");
5379
+ };
5380
+ }
5381
+ });
5382
+
5383
+ // src/attribution/parse-attribution/index.ts
5384
+ var init_parse_attribution2 = __esm({
5385
+ "src/attribution/parse-attribution/index.ts"() {
5386
+ "use strict";
5387
+ init_parse_attribution();
5388
+ }
5389
+ });
5390
+
5391
+ // src/attribution/read-attribution/read-attribution.ts
5392
+ import * as fs10 from "node:fs";
5393
+ var readAttribution;
5394
+ var init_read_attribution = __esm({
5395
+ "src/attribution/read-attribution/read-attribution.ts"() {
5396
+ "use strict";
5397
+ init_parse_attribution2();
5398
+ init_resolve_attribution_file2();
5399
+ readAttribution = (options) => {
5400
+ const file = resolveAttributionFile(options);
5401
+ if (file === void 0) {
5402
+ return void 0;
5403
+ }
5404
+ try {
5405
+ const parsed = JSON.parse(fs10.readFileSync(file, "utf8"));
5406
+ return parseAttribution(parsed);
5407
+ } catch {
5408
+ return void 0;
5413
5409
  }
5414
- const reusable = reusableLease({
5415
- attribution: options.attribution,
5416
- current,
5417
- now,
5418
- policy,
5419
- state: options.installation.state,
5420
- storedKey
5421
- });
5422
- if (reusable !== void 0) {
5423
- return reusable;
5410
+ };
5411
+ }
5412
+ });
5413
+
5414
+ // src/attribution/read-attribution/index.ts
5415
+ var init_read_attribution2 = __esm({
5416
+ "src/attribution/read-attribution/index.ts"() {
5417
+ "use strict";
5418
+ init_read_attribution();
5419
+ }
5420
+ });
5421
+
5422
+ // src/attribution/write-attribution/write-attribution.ts
5423
+ import { randomUUID as randomUUID2 } from "node:crypto";
5424
+ import * as fs11 from "node:fs";
5425
+ import * as path10 from "node:path";
5426
+ var writeAttribution;
5427
+ var init_write_attribution = __esm({
5428
+ "src/attribution/write-attribution/write-attribution.ts"() {
5429
+ "use strict";
5430
+ init_resolve_attribution_file2();
5431
+ writeAttribution = (options, attribution) => {
5432
+ const file = resolveAttributionFile(options);
5433
+ if (file === void 0) {
5434
+ return false;
5424
5435
  }
5436
+ fs11.mkdirSync(path10.dirname(file), { recursive: true });
5437
+ const temporaryFile = `${file}.${String(process.pid)}.${randomUUID2()}.tmp`;
5425
5438
  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 });
5439
+ fs11.writeFileSync(temporaryFile, `${JSON.stringify(attribution)}
5440
+ `, "utf8");
5441
+ fs11.renameSync(temporaryFile, file);
5442
+ } catch (error) {
5443
+ fs11.rmSync(temporaryFile, { force: true });
5444
+ throw error;
5459
5445
  }
5446
+ return true;
5460
5447
  };
5461
5448
  }
5462
5449
  });
5463
5450
 
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"() {
5451
+ // src/attribution/write-attribution/index.ts
5452
+ var init_write_attribution2 = __esm({
5453
+ "src/attribution/write-attribution/index.ts"() {
5467
5454
  "use strict";
5468
- init_lease_for_attribution();
5455
+ init_write_attribution();
5456
+ }
5457
+ });
5458
+
5459
+ // src/attribution/index.ts
5460
+ var init_attribution = __esm({
5461
+ "src/attribution/index.ts"() {
5462
+ "use strict";
5463
+ init_clear_attribution2();
5464
+ init_detect_worktree_root2();
5465
+ init_parse_attribution2();
5466
+ init_read_attribution2();
5467
+ init_resolve_attribution_file2();
5468
+ init_write_attribution2();
5469
5469
  }
5470
5470
  });
5471
5471
 
@@ -6387,7 +6387,6 @@ var init_create_route33_plugin2 = __esm({
6387
6387
  });
6388
6388
 
6389
6389
  // src/tui-entry/v1-connect-wizard/v1-connect-wizard.ts
6390
- init_attribution();
6391
6390
  init_cli();
6392
6391
 
6393
6392
  // src/tui-entry/production-options/production-options.ts
@@ -6902,12 +6901,10 @@ init_create_route33_plugin2();
6902
6901
  // src/v2-entry/parse-r33-subcommand/parse-r33-subcommand.ts
6903
6902
  var SUBCOMMANDS = ["inspect", "rotate", "reset"];
6904
6903
  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) {
6904
+ const [first = "", ...rest] = promptText.trim().split(/\s+/u).filter(Boolean);
6905
+ const name = first.replace(/^\/+/u, "").split(":")[0] ?? "";
6906
+ const argument = name === "r33" ? rest[0] : first;
6907
+ if (argument === void 0 || argument === "") {
6911
6908
  return "inspect";
6912
6909
  }
6913
6910
  return SUBCOMMANDS.includes(argument) ? argument : "help";
@@ -7098,19 +7095,82 @@ var r33Menu = async (api, composeOptions) => {
7098
7095
  await r33MenuActions({ api, composeOptions })(selection);
7099
7096
  };
7100
7097
 
7098
+ // src/tui-entry/v2-setup-directory/v2-setup-directory.ts
7099
+ init_attribution();
7100
+ init_cli();
7101
+ var v2SetupDirectory = (context) => {
7102
+ if (readEnvDirectApiKey() !== void 0) return void 0;
7103
+ if (readEnvAutoconnectDisabled()) return void 0;
7104
+ const location = context.location;
7105
+ if (location === void 0) return void 0;
7106
+ if (detectWorktreeRoot(location.directory) === void 0) {
7107
+ return void 0;
7108
+ }
7109
+ const attributed = readAttribution({
7110
+ directory: location.directory,
7111
+ outsideWorktree: "return-undefined"
7112
+ }) !== void 0;
7113
+ return attributed ? void 0 : location.directory;
7114
+ };
7115
+
7116
+ // src/tui-entry/v1-setup-lock/v1-setup-lock.ts
7117
+ var SETUP_MODE = "route33-setup";
7118
+ var RESUME_BIND = "enter";
7119
+ var v1SetupLock = (deps) => {
7120
+ const setupPending = () => v2SetupDirectory({ location: { directory: deps.directory() } }) !== void 0;
7121
+ const pop = setupPending() ? deps.mode?.push(SETUP_MODE) : void 0;
7122
+ if (pop !== void 0) {
7123
+ deps.keymap?.registerLayer({
7124
+ bindings: ["route33.setup"],
7125
+ commands: [
7126
+ {
7127
+ bind: RESUME_BIND,
7128
+ id: "route33.setup",
7129
+ run: () => {
7130
+ void settle();
7131
+ },
7132
+ suggested: true,
7133
+ title: "Route 33: pick the budget for this folder"
7134
+ }
7135
+ ],
7136
+ mode: SETUP_MODE,
7137
+ priority: 10
7138
+ });
7139
+ }
7140
+ let running = false;
7141
+ const settle = async () => {
7142
+ if (running) return;
7143
+ running = true;
7144
+ try {
7145
+ if (setupPending()) {
7146
+ await deps.run();
7147
+ }
7148
+ } finally {
7149
+ running = false;
7150
+ }
7151
+ if (setupPending()) return;
7152
+ pop?.();
7153
+ };
7154
+ return { start: settle };
7155
+ };
7156
+
7101
7157
  // src/tui-entry/v1-connect-wizard/v1-connect-wizard.ts
7102
7158
  var createV1ConnectWizard = (composeOptions = productionOptions) => (api) => {
7103
7159
  if (readEnvDirectApiKey() !== void 0 || readEnvAutoconnectDisabled()) {
7104
7160
  return Promise.resolve();
7105
7161
  }
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
- }
7162
+ const surfaces = api;
7163
+ const lock = v1SetupLock({
7164
+ directory: () => api.state.path.directory,
7165
+ ...surfaces.keymap === void 0 ? {} : {
7166
+ keymap: {
7167
+ registerLayer: (layer) => surfaces.keymap?.registerLayer(layer)
7168
+ }
7169
+ },
7170
+ ...surfaces.mode === void 0 ? {} : { mode: surfaces.mode },
7171
+ run: () => runConnect(api, composeOptions)
7172
+ });
7173
+ void lock.start();
7114
7174
  const legacyCommands = api.command;
7115
7175
  legacyCommands?.register(() => [
7116
7176
  {
@@ -7167,48 +7227,405 @@ var showR33Menu = async (context) => {
7167
7227
 
7168
7228
  // src/tui-entry/v2-autoconnect/v2-autoconnect.ts
7169
7229
  init_attribution();
7170
- init_cli();
7171
7230
 
7172
- // src/tui-entry/v2-connect-runner/v2-connect-runner.ts
7173
- var createV2ConnectRunner = ({
7174
- context,
7175
- unattributed
7176
- }) => {
7177
- const oauth = context.client?.api?.integration?.oauth;
7178
- return async (message) => {
7179
- const connect = oauth?.connect;
7180
- if (connect === void 0) return;
7181
- if (!unattributed()) return;
7182
- context.ui.toast.show({ message, variant: "info" });
7183
- await connect({
7231
+ // src/tui-entry/v2-attribution-field/v2-attribution-field.ts
7232
+ var v2AttributionField = (methods) => {
7233
+ const browserMethods = methods?.filter(
7234
+ (entry) => entry.type === "oauth" && entry.id === "browser"
7235
+ );
7236
+ const fields = browserMethods?.flatMap((entry) => entry.form ?? []);
7237
+ const field = fields?.find((entry) => entry.key === "attribution");
7238
+ if (field?.options === void 0 || field.options.length === 0) {
7239
+ return void 0;
7240
+ }
7241
+ return field;
7242
+ };
7243
+
7244
+ // src/tui-entry/v2-integration-surface/v2-integration-surface.ts
7245
+ var v2IntegrationSurface = (context) => context.client?.integration ?? context.client?.api?.integration;
7246
+
7247
+ // src/tui-entry/v2-attribution-form/v2-attribution-form.ts
7248
+ var v2AttributionForm = async (context) => {
7249
+ const get = v2IntegrationSurface(context)?.get;
7250
+ if (get === void 0) return void 0;
7251
+ const integration = await get({
7252
+ integrationID: "route33",
7253
+ ...context.location === void 0 ? {} : { location: { directory: context.location.directory } }
7254
+ }).catch(() => void 0);
7255
+ return v2AttributionField(integration?.data.methods);
7256
+ };
7257
+
7258
+ // src/tui-entry/v2-connect-copy/v2-connect-copy.ts
7259
+ var V2_CONNECT_COPY = {
7260
+ dismissed: "Route 33 is not set up for this folder yet. Press Enter to pick the budget, or run /connect and choose Route 33.",
7261
+ expired: "The Route 33 sign-in link expired. Press Enter to retry, or run /connect and choose Route 33.",
7262
+ manualFallback: "Route 33 is not connected in this folder. Run /connect, choose Route 33, and follow the steps.",
7263
+ manualPath: "Press Enter to retry, or run /connect, choose Route 33, and follow the steps.",
7264
+ pickerTitle: "Which budget covers Route 33 usage in this folder?",
7265
+ setupIncomplete: "Route 33 setup did not complete. Press Enter to retry, or run /connect and choose Route 33.",
7266
+ signInFailed: "Route 33 sign-in did not complete. Press Enter to retry, or run /connect and choose Route 33.",
7267
+ signInTitle: "Route 33 \u2014 sign in",
7268
+ statusUnavailable: "Route 33 sign-in did not settle. Press Enter to retry, or run /connect and choose Route 33.",
7269
+ stale: "That Route 33 option is no longer available. Press Enter to retry, or run /connect and choose Route 33.",
7270
+ success: "Route 33 connected \u2713 \u2014 pick a route_33 model and start.",
7271
+ timedOut: "Route 33 sign-in timed out. Press Enter to retry, or run /connect and choose Route 33."
7272
+ };
7273
+
7274
+ // src/tui-entry/v2-outcome-copy/v2-outcome-copy.ts
7275
+ var v2OutcomeCopy = (outcome, failedFallback) => {
7276
+ if (outcome.kind === "failed") {
7277
+ return {
7278
+ message: `${outcome.message ?? failedFallback} ${V2_CONNECT_COPY.manualPath}`,
7279
+ variant: "error"
7280
+ };
7281
+ }
7282
+ const byKind = {
7283
+ complete: V2_CONNECT_COPY.manualFallback,
7284
+ expired: V2_CONNECT_COPY.expired,
7285
+ failed: failedFallback,
7286
+ timeout: V2_CONNECT_COPY.timedOut,
7287
+ unavailable: V2_CONNECT_COPY.statusUnavailable
7288
+ };
7289
+ return { message: byKind[outcome.kind], variant: "error" };
7290
+ };
7291
+
7292
+ // src/tui-entry/v2-budget-picker/v2-budget-picker.ts
7293
+ var v2BudgetPicker = async (deps) => {
7294
+ if (!deps.unattributed()) {
7295
+ deps.toast({ message: V2_CONNECT_COPY.success, variant: "success" });
7296
+ return;
7297
+ }
7298
+ const options = deps.form.options ?? [];
7299
+ const selection = await deps.dialog.select({
7300
+ options: options.map((option) => ({
7301
+ description: option.description,
7302
+ title: option.label,
7303
+ value: option.value
7304
+ })),
7305
+ title: deps.form.title ?? V2_CONNECT_COPY.pickerTitle
7306
+ });
7307
+ if (selection === void 0) {
7308
+ deps.toast({ message: V2_CONNECT_COPY.dismissed });
7309
+ return;
7310
+ }
7311
+ if (!options.some((option) => option.value === selection)) {
7312
+ deps.toast({ message: V2_CONNECT_COPY.stale, variant: "error" });
7313
+ return;
7314
+ }
7315
+ if (!deps.unattributed()) {
7316
+ deps.toast({ message: V2_CONNECT_COPY.success, variant: "success" });
7317
+ return;
7318
+ }
7319
+ let second;
7320
+ try {
7321
+ second = await deps.connect({
7322
+ answer: { [deps.form.key]: selection },
7184
7323
  integrationID: "route33",
7324
+ location: deps.locationInput,
7185
7325
  methodID: "browser"
7186
- }).catch(() => void 0);
7326
+ });
7327
+ } catch (error) {
7328
+ deps.toast({
7329
+ message: `${error instanceof Error ? error.message : String(error)} ${V2_CONNECT_COPY.manualPath}`,
7330
+ variant: "error"
7331
+ });
7332
+ return;
7333
+ }
7334
+ const settled = await deps.pollTerminal(second.data.attemptID);
7335
+ if (settled.kind === "complete") {
7336
+ deps.toast({ message: V2_CONNECT_COPY.success, variant: "success" });
7337
+ return;
7338
+ }
7339
+ const copy = v2OutcomeCopy(settled, V2_CONNECT_COPY.setupIncomplete);
7340
+ deps.toast(copy);
7341
+ };
7342
+
7343
+ // src/tui-entry/v2-connect-surface/v2-connect-surface.ts
7344
+ var v2ConnectSurface = (context) => v2IntegrationSurface(context)?.oauth?.connect;
7345
+
7346
+ // src/tui-entry/v2-form-reader/v2-form-reader.ts
7347
+ init_abortable_sleep2();
7348
+ var createV2FormReader = ({ attempts = 5, context, retryDelayMs = 500 }) => async () => {
7349
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
7350
+ const form = await v2AttributionForm(context);
7351
+ if (form !== void 0) return form;
7352
+ if (attempt < attempts) {
7353
+ await abortableSleep(retryDelayMs);
7354
+ }
7355
+ }
7356
+ return void 0;
7357
+ };
7358
+
7359
+ // src/tui-entry/v2-poll-terminal/v2-poll-terminal.ts
7360
+ init_abortable_sleep2();
7361
+ var createV2PollTerminal = ({
7362
+ locationInput,
7363
+ maxPolls = 600,
7364
+ pollDelayMs = 1e3,
7365
+ status,
7366
+ statusErrorLimit = 5
7367
+ }) => async (attemptID) => {
7368
+ let errors = 0;
7369
+ for (let poll = 0; poll < maxPolls; poll += 1) {
7370
+ await abortableSleep(pollDelayMs);
7371
+ try {
7372
+ const result = await status({
7373
+ attemptID,
7374
+ integrationID: "route33",
7375
+ location: locationInput
7376
+ });
7377
+ errors = 0;
7378
+ const state = result.data.status;
7379
+ if (state === "pending") continue;
7380
+ if (state === "failed") {
7381
+ return { kind: "failed", message: result.data.message };
7382
+ }
7383
+ return { kind: state };
7384
+ } catch {
7385
+ errors += 1;
7386
+ if (errors >= statusErrorLimit) return { kind: "unavailable" };
7387
+ }
7388
+ }
7389
+ return { kind: "timeout" };
7390
+ };
7391
+
7392
+ // src/tui-entry/v2-connect-retry/v2-connect-retry.ts
7393
+ init_abortable_sleep2();
7394
+
7395
+ // src/tui-entry/is-method-not-registered/is-method-not-registered.ts
7396
+ var isMethodNotRegistered = (error) => error instanceof Error && error.message.includes("OAuth method not found");
7397
+
7398
+ // src/tui-entry/v2-connect-retry/v2-connect-retry.ts
7399
+ var v2ConnectRetry = async ({
7400
+ connect,
7401
+ input,
7402
+ maxAttempts = 20,
7403
+ retryDelayMs = 500
7404
+ }) => {
7405
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
7406
+ try {
7407
+ return await connect(input);
7408
+ } catch (error) {
7409
+ if (!isMethodNotRegistered(error)) {
7410
+ throw error;
7411
+ }
7412
+ if (attempt < maxAttempts) {
7413
+ await abortableSleep(retryDelayMs);
7414
+ }
7415
+ }
7416
+ }
7417
+ return void 0;
7418
+ };
7419
+
7420
+ // src/tui-entry/v2-sign-in-wait/v2-sign-in-wait.ts
7421
+ var v2SignInWait = async (deps) => {
7422
+ const state = { dismissed: false };
7423
+ void deps.alert().then(() => {
7424
+ state.dismissed = true;
7425
+ }).catch(() => {
7426
+ state.dismissed = true;
7427
+ });
7428
+ const outcome = await deps.pollTerminal(deps.attemptID);
7429
+ return { dismissed: state.dismissed, outcome };
7430
+ };
7431
+
7432
+ // src/tui-entry/v2-sign-in-pass/v2-sign-in-pass.ts
7433
+ var v2SignInPass = async ({
7434
+ connect,
7435
+ dialog,
7436
+ formReader,
7437
+ locationInput,
7438
+ maxAttempts,
7439
+ pollTerminal,
7440
+ retryDelayMs,
7441
+ toast,
7442
+ unattributed
7443
+ }) => {
7444
+ let attempt;
7445
+ try {
7446
+ attempt = await v2ConnectRetry({
7447
+ connect,
7448
+ input: {
7449
+ integrationID: "route33",
7450
+ location: locationInput,
7451
+ methodID: "browser"
7452
+ },
7453
+ maxAttempts,
7454
+ retryDelayMs
7455
+ });
7456
+ } catch (error) {
7457
+ toast({
7458
+ message: `${error instanceof Error ? error.message : String(error)} ${V2_CONNECT_COPY.manualPath}`,
7459
+ variant: "error"
7460
+ });
7461
+ return { aborted: true };
7462
+ }
7463
+ if (attempt === void 0) {
7464
+ toast({ message: V2_CONNECT_COPY.manualFallback, variant: "error" });
7465
+ return { aborted: true };
7466
+ }
7467
+ const waited = await v2SignInWait({
7468
+ alert: () => dialog.alert({
7469
+ message: `${attempt.data.instructions}
7470
+
7471
+ ${attempt.data.url}`,
7472
+ title: V2_CONNECT_COPY.signInTitle
7473
+ }),
7474
+ attemptID: attempt.data.attemptID,
7475
+ pollTerminal
7476
+ });
7477
+ if (waited.dismissed) {
7478
+ if (waited.outcome.kind === "complete") {
7479
+ return { connected: true };
7480
+ }
7481
+ toast({ message: V2_CONNECT_COPY.dismissed });
7482
+ return { aborted: true };
7483
+ }
7484
+ dialog.clear();
7485
+ const outcome = waited.outcome;
7486
+ if (outcome.kind === "complete") {
7487
+ return { connected: true };
7488
+ }
7489
+ if (outcome.kind === "failed") {
7490
+ if (!unattributed()) {
7491
+ return { connected: true };
7492
+ }
7493
+ const form = await formReader();
7494
+ if (form === void 0) {
7495
+ toast(v2OutcomeCopy(outcome, V2_CONNECT_COPY.signInFailed));
7496
+ return { aborted: true };
7497
+ }
7498
+ return { form };
7499
+ }
7500
+ toast(v2OutcomeCopy(outcome, V2_CONNECT_COPY.signInFailed));
7501
+ return { aborted: true };
7502
+ };
7503
+
7504
+ // src/tui-entry/v2-status-surface/v2-status-surface.ts
7505
+ var v2StatusSurface = (context) => v2IntegrationSurface(context)?.oauth?.status;
7506
+
7507
+ // src/tui-entry/v2-connect-runner/v2-connect-runner.ts
7508
+ var v2GuidedConnect = async (deps) => {
7509
+ const { context, unattributed } = deps;
7510
+ const connect = v2ConnectSurface(context);
7511
+ const status = v2StatusSurface(context);
7512
+ const dialog = context.ui.dialog;
7513
+ const toast = (input) => {
7514
+ context.ui.toast.show(input);
7187
7515
  };
7516
+ const location = context.location;
7517
+ if (connect === void 0 || location === void 0) return;
7518
+ if (!unattributed()) return;
7519
+ if (status === void 0 || dialog === void 0) {
7520
+ toast({ message: V2_CONNECT_COPY.manualFallback });
7521
+ return;
7522
+ }
7523
+ const locationInput = { directory: location.directory };
7524
+ const pollTerminal = createV2PollTerminal({
7525
+ locationInput,
7526
+ maxPolls: deps.maxPolls,
7527
+ pollDelayMs: deps.pollDelayMs,
7528
+ status,
7529
+ statusErrorLimit: deps.statusErrorLimit
7530
+ });
7531
+ const earlyForm = await v2AttributionForm(context);
7532
+ if (earlyForm !== void 0) {
7533
+ await v2BudgetPicker({
7534
+ connect,
7535
+ dialog,
7536
+ form: earlyForm,
7537
+ locationInput,
7538
+ pollTerminal,
7539
+ toast,
7540
+ unattributed
7541
+ });
7542
+ return;
7543
+ }
7544
+ const result = await v2SignInPass({
7545
+ connect,
7546
+ dialog,
7547
+ formReader: createV2FormReader({
7548
+ attempts: deps.formReadAttempts,
7549
+ context,
7550
+ retryDelayMs: deps.retryDelayMs
7551
+ }),
7552
+ locationInput,
7553
+ maxAttempts: deps.maxAttempts,
7554
+ pollTerminal,
7555
+ retryDelayMs: deps.retryDelayMs,
7556
+ toast,
7557
+ unattributed
7558
+ });
7559
+ if ("aborted" in result) return;
7560
+ if ("connected" in result) {
7561
+ toast({ message: V2_CONNECT_COPY.success, variant: "success" });
7562
+ return;
7563
+ }
7564
+ await v2BudgetPicker({
7565
+ connect,
7566
+ dialog,
7567
+ form: result.form,
7568
+ locationInput,
7569
+ pollTerminal,
7570
+ toast,
7571
+ unattributed
7572
+ });
7188
7573
  };
7189
7574
 
7190
7575
  // src/tui-entry/v2-autoconnect/v2-autoconnect.ts
7191
7576
  var v2Autoconnect = async (context) => {
7192
- if (readEnvDirectApiKey() !== void 0) return;
7193
- if (readEnvAutoconnectDisabled()) return;
7194
- const location = context.location;
7195
- if (location === void 0) return;
7577
+ const directory = v2SetupDirectory(context);
7578
+ if (directory === void 0) return;
7196
7579
  const unattributed = () => readAttribution({
7197
- directory: location.directory,
7580
+ directory,
7198
7581
  outsideWorktree: "return-undefined"
7199
7582
  }) === void 0;
7200
- const connectPass = createV2ConnectRunner({ context, unattributed });
7201
- await connectPass(
7202
- "Route 33 is not connected \u2014 signing in now, then pick the budget for this folder."
7203
- );
7204
- await connectPass("Signed in to Route 33 \u2014 opening the budget picker.");
7583
+ await v2GuidedConnect({ context, unattributed });
7584
+ };
7585
+
7586
+ // src/tui-entry/v2-setup-lock/v2-setup-lock.ts
7587
+ var SETUP_MODE2 = "route33-setup";
7588
+ var RESUME_BIND2 = "enter";
7589
+ var v2SetupLock = (context) => {
7590
+ const required = v2SetupDirectory(context) !== void 0;
7591
+ const release = required ? context.keymap?.mode.push(SETUP_MODE2) : void 0;
7592
+ if (required) {
7593
+ context.keymap?.layer(() => ({
7594
+ bindings: ["route33.setup"],
7595
+ commands: [
7596
+ {
7597
+ bind: RESUME_BIND2,
7598
+ id: "route33.setup",
7599
+ run: () => {
7600
+ void settle();
7601
+ },
7602
+ suggested: true,
7603
+ title: "Route 33: pick the budget for this folder"
7604
+ }
7605
+ ],
7606
+ mode: SETUP_MODE2,
7607
+ priority: 10
7608
+ }));
7609
+ }
7610
+ let running = false;
7611
+ const settle = async () => {
7612
+ if (running) return;
7613
+ running = true;
7614
+ try {
7615
+ await v2Autoconnect(context);
7616
+ } finally {
7617
+ running = false;
7618
+ }
7619
+ if (v2SetupDirectory(context) !== void 0) return;
7620
+ release?.();
7621
+ };
7622
+ return { start: settle };
7205
7623
  };
7206
7624
 
7207
7625
  // src/tui-entry/v2-tui/v2-tui.ts
7208
7626
  var createV2Tui = () => ({
7209
7627
  id: "route33",
7210
- setup: async (context) => {
7211
- await v2Autoconnect(context);
7628
+ setup: (context) => {
7212
7629
  context.keymap?.layer(() => ({
7213
7630
  mode: "global",
7214
7631
  priority: 10,
@@ -7226,6 +7643,7 @@ var createV2Tui = () => ({
7226
7643
  ],
7227
7644
  bindings: ["route33.menu"]
7228
7645
  }));
7646
+ void v2SetupLock(context).start().catch(() => void 0);
7229
7647
  }
7230
7648
  });
7231
7649