rebase-git 0.0.2-nightly.20260928.132 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/runtime.js +1156 -368
  2. package/dist/web/assets/IconCheck-CR2g6WMA.js +1 -0
  3. package/dist/web/assets/IconChevronRight-Ct8_bzuc.js +14 -0
  4. package/dist/web/assets/IconChevronUp-C_TmKquO.js +1 -0
  5. package/dist/web/assets/change-diff-viewer-dGj-oUGX.js +1 -0
  6. package/dist/web/assets/commit-inspection-DWWpkIUb.js +4 -0
  7. package/dist/web/assets/commit-inspection.contract-3uL8JUQ0.js +1 -0
  8. package/dist/web/assets/copy-pill-C_VGk1Pg.js +1 -0
  9. package/dist/web/assets/error-notification-DsQIwzII.js +1 -0
  10. package/dist/web/assets/esm-CvNZ5U7-.js +1 -0
  11. package/dist/web/assets/history-worker-DH9-r88J.js +14 -0
  12. package/dist/web/assets/index-DMxGcYbd.js +15 -0
  13. package/dist/web/assets/index-DXxfLBIU.css +2 -0
  14. package/dist/web/assets/operation-controls-DTfubyMj.js +1 -0
  15. package/dist/web/assets/rebase-actions-B2Wif_Wx.js +1 -0
  16. package/dist/web/assets/rebase-panel-BklGSF3U.js +7 -0
  17. package/dist/web/assets/reflog-panel-b1hVOEPG.js +1 -0
  18. package/dist/web/assets/repository-changes.contract-BbNQSKl4.js +1 -0
  19. package/dist/web/assets/{use-diff-preferences-DOAXsFPX.js → use-diff-preferences-B8VbF4jc.js} +1 -1
  20. package/dist/web/assets/use-operation-CQUl8xaq.js +1 -0
  21. package/dist/web/assets/useToastManager-B9e_QaKk.js +1 -0
  22. package/dist/web/assets/whole-file-menu-pxn9TLHi.js +4 -0
  23. package/dist/web/assets/working-changes-D7-a0GdD.js +5 -0
  24. package/dist/web/index.html +16 -10
  25. package/package.json +1 -1
  26. package/dist/web/assets/IconChevronRight-CVa-IPob.js +0 -14
  27. package/dist/web/assets/IconChevronUp-akdYJ9UK.js +0 -1
  28. package/dist/web/assets/change-diff-viewer-DkyuNndG.js +0 -1
  29. package/dist/web/assets/commit-inspection-Wa83zWbE.js +0 -4
  30. package/dist/web/assets/copy-pill-CZN_HyCK.js +0 -1
  31. package/dist/web/assets/error-notification-DKNN1wDB.js +0 -1
  32. package/dist/web/assets/esm-suPXXIqE.js +0 -1
  33. package/dist/web/assets/history-worker-nldCB9TK.js +0 -14
  34. package/dist/web/assets/index-pRiFsdYb.js +0 -15
  35. package/dist/web/assets/index-vq_NKFMw.css +0 -2
  36. package/dist/web/assets/operation-controls-Dq4VBYEd.js +0 -4
  37. package/dist/web/assets/reflog-panel-INbii9Mx.js +0 -1
  38. package/dist/web/assets/use-operation-DKhyo1ke.js +0 -1
  39. package/dist/web/assets/working-changes-BMEZO_Vq.js +0 -5
package/dist/runtime.js CHANGED
@@ -5,7 +5,7 @@ import { spawn as spawn2 } from "node:child_process";
5
5
  import { existsSync as existsSync2, readFileSync, realpathSync as realpathSync2 } from "node:fs";
6
6
  import { homedir as homedir2, release } from "node:os";
7
7
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8
- import { Deferred as Deferred3, Effect as Effect61 } from "effect";
8
+ import { Deferred as Deferred3, Effect as Effect65 } from "effect";
9
9
 
10
10
  // src/contracts/environment-connection/environment-rpc.contract.ts
11
11
  import { Schema as Schema20 } from "effect";
@@ -575,14 +575,40 @@ var OperationScope = Schema13.Struct({
575
575
  }), OperationAction = Schema13.Literals(["continue", "skip", "abort"]), OperationKind = Schema13.Literals([
576
576
  "idle",
577
577
  "merge",
578
+ "squash",
578
579
  "rebase",
579
580
  "cherry-pick",
580
581
  "revert",
581
582
  "am",
582
583
  "unknown"
583
- ]), RepositoryOperation = Schema13.Struct({
584
+ ]), PlanAction = Schema13.Literals([
585
+ "pick",
586
+ "reword",
587
+ "edit",
588
+ "squash",
589
+ "fixup",
590
+ "drop"
591
+ ]), PlanStep = Schema13.Struct({
592
+ commit: ObjectId,
593
+ action: PlanAction,
594
+ message: Schema13.NullOr(
595
+ Schema13.String.check(Schema13.isMinLength(1), Schema13.isMaxLength(32e3))
596
+ )
597
+ }), RebaseStep = Schema13.Struct({
598
+ commit: ObjectId,
599
+ action: PlanAction,
600
+ subject: Schema13.String,
601
+ done: Schema13.Boolean
602
+ }), RepositoryOperation = Schema13.Struct({
584
603
  kind: OperationKind,
585
- phase: Schema13.Literals(["idle", "conflicts", "edit", "ready", "blocked"]),
604
+ phase: Schema13.Literals([
605
+ "idle",
606
+ "conflicts",
607
+ "edit",
608
+ "ready",
609
+ "empty",
610
+ "blocked"
611
+ ]),
586
612
  revision: Schema13.String,
587
613
  branch: Schema13.NullOr(Schema13.String),
588
614
  commit: Schema13.NullOr(Schema13.String),
@@ -598,20 +624,79 @@ var OperationScope = Schema13.Struct({
598
624
  reason: Schema13.NullOr(Schema13.String)
599
625
  })
600
626
  ),
601
- lock: Schema13.NullOr(Schema13.String)
627
+ lock: Schema13.NullOr(Schema13.String),
628
+ steps: Schema13.NullOr(Schema13.Array(RebaseStep))
602
629
  }), ExecuteOperation = Schema13.Struct({
603
630
  ...OperationScope.fields,
604
631
  revision: Schema13.String.check(Schema13.isPattern(/^[a-f0-9]{64}$/)),
605
632
  action: OperationAction
633
+ }), MergeMode = Schema13.Literals([
634
+ "merge",
635
+ "ff-only",
636
+ "no-ff",
637
+ "squash"
638
+ ]), StartMerge = Schema13.TaggedStruct("Merge", {
639
+ source: Schema13.Struct({ ref: Schema13.NullOr(RefName), commit: ObjectId }),
640
+ mode: MergeMode
641
+ }), StartRebase = Schema13.TaggedStruct("Rebase", {
642
+ onto: Schema13.Struct({ ref: Schema13.NullOr(RefName), commit: ObjectId }),
643
+ stash: Schema13.Boolean,
644
+ plan: Schema13.optionalKey(
645
+ Schema13.Array(PlanStep).check(
646
+ Schema13.isMinLength(1),
647
+ Schema13.isMaxLength(1e3)
648
+ )
649
+ )
650
+ }), StartRevert = Schema13.TaggedStruct("Revert", {
651
+ commits: Schema13.Array(ObjectId).check(
652
+ Schema13.isMinLength(1),
653
+ Schema13.isMaxLength(256)
654
+ ),
655
+ commit: Schema13.Boolean
656
+ }), CherryPickResult = Schema13.Literals(["commit", "stage"]), StartCherryPick = Schema13.TaggedStruct("CherryPick", {
657
+ commits: Schema13.Array(ObjectId).check(
658
+ Schema13.isMinLength(1),
659
+ Schema13.isMaxLength(1e3)
660
+ ),
661
+ mainline: Schema13.NullOr(
662
+ Schema13.Int.check(Schema13.isBetween({ minimum: 1, maximum: 64 }))
663
+ ),
664
+ result: CherryPickResult
665
+ }), StartOperation = Schema13.Struct({
666
+ ...OperationScope.fields,
667
+ expectedHead: ObjectId,
668
+ operation: Schema13.Union([
669
+ StartMerge,
670
+ StartRebase,
671
+ StartRevert,
672
+ StartCherryPick
673
+ ])
674
+ }), OperationStarted = Schema13.Struct({
675
+ outcome: Schema13.Literals([
676
+ "UpToDate",
677
+ "FastForwarded",
678
+ "Committed",
679
+ "Rebased",
680
+ "Staged",
681
+ "Stopped"
682
+ ]),
683
+ operation: RepositoryOperation
606
684
  }), OperationFailure = Schema13.TaggedStruct("OperationFailed", {
607
685
  reason: Schema13.Literals([
608
686
  "Stale",
609
687
  "Incompatible",
610
688
  "HookFailed",
611
689
  "GitRejected",
612
- "Uncertain"
690
+ "Uncertain",
691
+ "NotFastForward",
692
+ "Unrelated",
693
+ "WouldOverwrite",
694
+ "Empty"
613
695
  ]),
614
- detail: Schema13.String.check(Schema13.isMaxLength(2048))
696
+ detail: Schema13.String.check(Schema13.isMaxLength(2048)),
697
+ paths: Schema13.optionalKey(
698
+ Schema13.Array(RepositoryPath).check(Schema13.isMaxLength(100))
699
+ )
615
700
  }), RepositoryOperationsApi = {
616
701
  read: repositoryQuery("repositories/operations/read", {
617
702
  request: OperationScope,
@@ -621,6 +706,11 @@ var OperationScope = Schema13.Struct({
621
706
  request: ExecuteOperation,
622
707
  success: RepositoryOperation,
623
708
  failure: OperationFailure
709
+ }),
710
+ start: repositoryCommand("repositories/operations/start", {
711
+ request: StartOperation,
712
+ success: OperationStarted,
713
+ failure: OperationFailure
624
714
  })
625
715
  };
626
716
 
@@ -710,9 +800,22 @@ var PushDestination = Schema15.Struct({
710
800
  }), RemoteBranchUpdated = Schema15.Struct({
711
801
  destination: PushDestination,
712
802
  target: ObjectId
803
+ }), PushTags = Schema15.Struct({
804
+ repositoryId: RepositoryId,
805
+ worktreePath: RepositoryPath,
806
+ remote: RemoteName,
807
+ tags: Schema15.Array(RefName).check(
808
+ Schema15.isMinLength(1),
809
+ Schema15.isMaxLength(100)
810
+ )
811
+ }), TagsPushed = Schema15.Struct({
812
+ remote: RemoteName,
813
+ pushed: Schema15.Array(RefName),
814
+ upToDate: Schema15.Array(RefName)
713
815
  }), PushRejectedReason = Schema15.Literals([
714
816
  "RemoteMissing",
715
817
  "InvalidBranch",
818
+ "TagExists",
716
819
  "NonFastForward",
717
820
  "LeaseRejected",
718
821
  "HookDeclined",
@@ -727,6 +830,11 @@ var PushDestination = Schema15.Struct({
727
830
  request: PushBranch,
728
831
  success: RemoteBranchUpdated,
729
832
  failure: PushRejected
833
+ }),
834
+ pushTags: repositoryCommand("repositories/push/tags", {
835
+ request: PushTags,
836
+ success: TagsPushed,
837
+ failure: PushRejected
730
838
  })
731
839
  };
732
840
 
@@ -735,7 +843,7 @@ import { Schema as Schema17 } from "effect";
735
843
 
736
844
  // src/contracts/repository-refs/repository-refs.contract.ts
737
845
  import { Schema as Schema16 } from "effect";
738
- var FailureDetail = Schema16.String.check(Schema16.isMaxLength(2048)), RepositoryHead = Schema16.Struct({
846
+ var RepositoryHead = Schema16.Struct({
739
847
  branch: Schema16.optional(RefName),
740
848
  commit: ObjectId
741
849
  }), RepositoryWorktree = Schema16.Struct({
@@ -761,7 +869,8 @@ var FailureDetail = Schema16.String.check(Schema16.isMaxLength(2048)), Repositor
761
869
  remote: RemoteName
762
870
  }), RepositoryTag = Schema16.Struct({
763
871
  name: RefName,
764
- target: Schema16.optional(ObjectId)
872
+ target: Schema16.optional(ObjectId),
873
+ object: Schema16.optional(ObjectId)
765
874
  }), RepositoryRefsTruncation = Schema16.Struct({
766
875
  branches: Schema16.Boolean,
767
876
  remoteBranches: Schema16.Boolean,
@@ -822,7 +931,6 @@ var FailureDetail = Schema16.String.check(Schema16.isMaxLength(2048)), Repositor
822
931
  worktreePath: RepositoryPath
823
932
  }
824
933
  ), CheckoutRejected = Schema16.TaggedStruct("CheckoutRejected", {
825
- detail: FailureDetail,
826
934
  reason: Schema16.Literals(["LocalChanges", "StashFailed"])
827
935
  }), RepositoryCheckoutFailure = Schema16.Union([
828
936
  RefMissing,
@@ -995,18 +1103,44 @@ import { Schema as Schema19 } from "effect";
995
1103
  var TagScope = {
996
1104
  repositoryId: RepositoryId,
997
1105
  worktreePath: RepositoryPath
998
- }, CreateRepositoryTag = Schema19.Struct({
1106
+ }, TagMessage = Schema19.String.check(
1107
+ Schema19.isMinLength(1),
1108
+ Schema19.isMaxLength(65536)
1109
+ ), CreateRepositoryTag = Schema19.Struct({
999
1110
  ...TagScope,
1000
1111
  name: RefName,
1001
- target: ObjectId
1112
+ target: ObjectId,
1113
+ message: Schema19.optional(TagMessage)
1002
1114
  }), DeleteRepositoryTag = Schema19.Struct({
1003
1115
  ...TagScope,
1004
- name: RefName
1116
+ name: RefName,
1117
+ local: Schema19.optional(Schema19.Struct({ object: ObjectId })),
1118
+ remote: Schema19.optional(
1119
+ Schema19.Struct({ remote: RemoteName, object: ObjectId })
1120
+ )
1005
1121
  }), RepositoryTagDeleted = Schema19.Struct({
1122
+ name: RefName
1123
+ }), ReadRepositoryTag = Schema19.Struct({
1124
+ ...TagScope,
1125
+ name: RefName
1126
+ }), RepositoryTagAnnotation = Schema19.Struct({
1006
1127
  name: RefName,
1007
- target: ObjectId
1128
+ object: ObjectId,
1129
+ target: ObjectId,
1130
+ tagger: Schema19.Struct({
1131
+ name: Schema19.String.check(Schema19.isMaxLength(512)),
1132
+ date: Schema19.String.check(Schema19.isMaxLength(64))
1133
+ }),
1134
+ message: Schema19.String.check(Schema19.isMaxLength(65536)),
1135
+ signed: Schema19.Boolean
1008
1136
  }), TagRejected = Schema19.TaggedStruct("TagRejected", {
1009
- reason: Schema19.Literals(["InvalidName", "Exists"])
1137
+ reason: Schema19.Literals([
1138
+ "InvalidName",
1139
+ "Exists",
1140
+ "MessageRequired",
1141
+ "Moved",
1142
+ "RemoteDiffers"
1143
+ ])
1010
1144
  }), RepositoryTagsApi = {
1011
1145
  create: repositoryCommand("repositories/tags/create", {
1012
1146
  request: CreateRepositoryTag,
@@ -1016,6 +1150,11 @@ var TagScope = {
1016
1150
  delete: repositoryCommand("repositories/tags/delete", {
1017
1151
  request: DeleteRepositoryTag,
1018
1152
  success: RepositoryTagDeleted,
1153
+ failure: Schema19.Union([RefMissing, TagRejected])
1154
+ }),
1155
+ annotation: repositoryQuery("repositories/tags/annotation", {
1156
+ request: ReadRepositoryTag,
1157
+ success: RepositoryTagAnnotation,
1019
1158
  failure: RefMissing
1020
1159
  })
1021
1160
  };
@@ -1111,7 +1250,7 @@ function octets(address) {
1111
1250
  }
1112
1251
 
1113
1252
  // src/apps/server/app/server/start-environment-server.ts
1114
- import { Effect as Effect60 } from "effect";
1253
+ import { Effect as Effect64 } from "effect";
1115
1254
 
1116
1255
  // src/apps/server/adapters/local-git/git-commands.ts
1117
1256
  import {
@@ -1280,8 +1419,10 @@ function gitArguments(command) {
1280
1419
  ];
1281
1420
  }
1282
1421
  function gitEnvironment(command) {
1422
+ let { GIT_SEQUENCE_EDITOR: _, ...inherited } = process.env;
1283
1423
  return {
1284
- ...process.env,
1424
+ ...inherited,
1425
+ ...command.environment,
1285
1426
  GIT_EDITOR: "true",
1286
1427
  GIT_OPTIONAL_LOCKS: "0",
1287
1428
  GIT_TERMINAL_PROMPT: "0",
@@ -1371,9 +1512,9 @@ function compareVersions(left, right) {
1371
1512
  }
1372
1513
 
1373
1514
  // src/apps/server/app/server/serve-environment.ts
1374
- import { join as join11 } from "node:path";
1515
+ import { join as join12 } from "node:path";
1375
1516
  import { and, eq as eq4, isNull } from "drizzle-orm";
1376
- import { Effect as Effect59 } from "effect";
1517
+ import { Effect as Effect63 } from "effect";
1377
1518
 
1378
1519
  // src/apps/server/adapters/environment-transport/environment-event-publisher.ts
1379
1520
  function createEnvironmentEventPublisher() {
@@ -2173,6 +2314,11 @@ function createEnvironmentHttpHandler(authorization, runEnvironmentEffect, brows
2173
2314
  Effect10.catch(
2174
2315
  (error) => Effect10.sync(() => writeEnvironmentHttpError(response, error))
2175
2316
  ),
2317
+ Effect10.catchCause(
2318
+ () => Effect10.sync(() => {
2319
+ response.headersSent || response.writeHead(500).end();
2320
+ })
2321
+ ),
2176
2322
  Effect10.ensuring(Effect10.sync(() => response.off("close", abort)))
2177
2323
  ),
2178
2324
  abortController.signal
@@ -4742,7 +4888,7 @@ function readConflictSides(git, directory, operation) {
4742
4888
  });
4743
4889
  }
4744
4890
  function baseCommit(git, directory, kind, incoming) {
4745
- return incoming === null ? Effect28.succeed(null) : kind === "merge" ? firstLine(
4891
+ return incoming === null ? Effect28.succeed(null) : kind === "merge" || kind === "squash" ? firstLine(
4746
4892
  runRepositoryGit(git, directory, ["merge-base", "HEAD", incoming], {
4747
4893
  exitCodes: [0, 1]
4748
4894
  })
@@ -5410,7 +5556,459 @@ function sameOids(left, right) {
5410
5556
  }
5411
5557
 
5412
5558
  // src/apps/server/features/repository-operations/repository-operations.ts
5559
+ import { Effect as Effect40 } from "effect";
5560
+
5561
+ // src/apps/server/features/repository-operations/cherry-pick.ts
5562
+ import { readFile as readFile4 } from "node:fs/promises";
5563
+ import { join as join8, resolve as resolve4 } from "node:path";
5564
+ import { Effect as Effect37 } from "effect";
5565
+
5566
+ // src/apps/server/features/repository-operations/operation-outcome.ts
5413
5567
  import { Effect as Effect36 } from "effect";
5568
+ function started(outcome, operation) {
5569
+ return { outcome, operation };
5570
+ }
5571
+ function readCommit(git, directory, rev) {
5572
+ return runRepositoryGit(
5573
+ git,
5574
+ directory,
5575
+ ["rev-parse", "--verify", "--quiet", "--end-of-options", `${rev}^{commit}`],
5576
+ { exitCodes: [0, 1] }
5577
+ ).pipe(Effect36.map((output) => output.trim()));
5578
+ }
5579
+ function requireGitSuccess(output) {
5580
+ if (output.exitCode === 0) return Effect36.void;
5581
+ let detail = output.stderr || output.stdout || "Git rejected the action. Check the worktree and configured hooks.";
5582
+ return /\.lock['\s:]|another git process/i.test(detail) ? Effect36.fail(repositoryRejected("Busy", detail)) : /would be overwritten by merge/i.test(detail) ? Effect36.fail({
5583
+ ...operationError("WouldOverwrite", detail),
5584
+ paths: detail.split(`
5585
+ `).filter((line) => line.startsWith(" ")).map((line) => line.trim()).filter((path) => path.length > 0).slice(0, 100)
5586
+ }) : Effect36.fail(
5587
+ operationError(
5588
+ /hook|pre-commit|commit-msg|pre-rebase|not committing merge/i.test(detail) ? "HookFailed" : "GitRejected",
5589
+ detail
5590
+ )
5591
+ );
5592
+ }
5593
+ function uncertain() {
5594
+ return operationError(
5595
+ "Uncertain",
5596
+ "Git's result could not be confirmed. Refresh the worktree before trying again."
5597
+ );
5598
+ }
5599
+ function operationFailure(reason, detail) {
5600
+ return Effect36.fail(operationError(reason, detail));
5601
+ }
5602
+ function operationError(reason, detail) {
5603
+ return { _tag: "OperationFailed", reason, detail: detail.slice(0, 2048) };
5604
+ }
5605
+
5606
+ // src/apps/server/features/repository-operations/cherry-pick.ts
5607
+ function startCherryPick(git, coordination, { worktreePath: directory, expectedHead }, { commits, mainline, result }) {
5608
+ return Effect37.gen(function* () {
5609
+ if ((yield* readCommit(git, directory, "HEAD")) !== expectedHead)
5610
+ return yield* operationFailure("Stale", "HEAD moved. Try again.");
5611
+ let merges = (yield* readParentCounts(git, directory, commits)).filter(
5612
+ (count) => count > 1
5613
+ );
5614
+ if (merges.length > 1)
5615
+ return yield* operationFailure(
5616
+ "Incompatible",
5617
+ "Cherry-pick one merge commit at a time."
5618
+ );
5619
+ if (merges.length === 1 && mainline === null)
5620
+ return yield* operationFailure(
5621
+ "Incompatible",
5622
+ "Choose a parent for the merge commit."
5623
+ );
5624
+ if (mainline !== null && merges.some((count) => mainline > count))
5625
+ return yield* operationFailure(
5626
+ "Incompatible",
5627
+ `The merge commit has no parent ${mainline}.`
5628
+ );
5629
+ if (result === "stage" && (yield* hasStagedChanges(git, directory)))
5630
+ return yield* operationFailure(
5631
+ "Incompatible",
5632
+ "Commit or unstage the staged changes first."
5633
+ );
5634
+ let output = yield* git.run({
5635
+ directory,
5636
+ arguments: [
5637
+ "cherry-pick",
5638
+ ...result === "stage" ? ["--no-commit"] : [],
5639
+ ...mainline === null ? [] : ["-m", String(mainline)],
5640
+ "--end-of-options",
5641
+ ...commits
5642
+ ],
5643
+ timeoutMilliseconds: 12e4
5644
+ }).pipe(Effect37.mapError(uncertain), Effect37.uninterruptible), state = yield* coordination.operation(directory);
5645
+ return output.exitCode !== 0 && (state.kind === "cherry-pick" || result === "stage" && (yield* hasUnmergedPaths(git, directory))) ? started("Stopped", state) : (yield* requireGitSuccess(output), started(result === "stage" ? "Staged" : "Committed", state));
5646
+ });
5647
+ }
5648
+ function continueStagedCherryPick(git, directory) {
5649
+ return Effect37.gen(function* () {
5650
+ let sequencer = yield* readStagedSequencer(git, directory);
5651
+ if (sequencer === void 0) return !1;
5652
+ if (yield* runRepositoryGit(git, directory, ["cherry-pick", "--quit"]), sequencer.remaining.length === 0) return !0;
5653
+ let output = yield* git.run({
5654
+ directory,
5655
+ arguments: [
5656
+ "cherry-pick",
5657
+ "--no-commit",
5658
+ ...sequencer.mainline === null ? [] : ["-m", sequencer.mainline],
5659
+ "--end-of-options",
5660
+ ...sequencer.remaining
5661
+ ],
5662
+ timeoutMilliseconds: 12e4
5663
+ }).pipe(Effect37.mapError(uncertain));
5664
+ return output.exitCode !== 0 && !(yield* hasUnmergedPaths(git, directory)) && (yield* requireGitSuccess(output)), !0;
5665
+ });
5666
+ }
5667
+ function readStagedSequencer(git, directory) {
5668
+ return Effect37.gen(function* () {
5669
+ let path = resolve4(
5670
+ directory,
5671
+ (yield* runRepositoryGit(git, directory, [
5672
+ "rev-parse",
5673
+ "--git-path",
5674
+ "sequencer"
5675
+ ])).trim()
5676
+ ), [options, todo] = yield* Effect37.tryPromise({
5677
+ try: () => Promise.all([
5678
+ readFile4(join8(path, "opts"), "utf8"),
5679
+ readFile4(join8(path, "todo"), "utf8")
5680
+ ]),
5681
+ catch: () => {
5682
+ }
5683
+ }).pipe(Effect37.orElseSucceed(() => [null, null]));
5684
+ if (!(options === null || todo === null) && /no-commit\s*=\s*true/.test(options))
5685
+ return {
5686
+ mainline: /mainline\s*=\s*(\d+)/.exec(options)?.[1] ?? null,
5687
+ remaining: todo.split(`
5688
+ `).flatMap((line) => /^(?:pick|p)\s+(\S+)/.exec(line)?.[1] ?? []).slice(1)
5689
+ };
5690
+ });
5691
+ }
5692
+ function readParentCounts(git, directory, commits) {
5693
+ return runRepositoryGit(git, directory, [
5694
+ "rev-list",
5695
+ "--no-walk=unsorted",
5696
+ "--parents",
5697
+ "--end-of-options",
5698
+ ...commits
5699
+ ]).pipe(
5700
+ Effect37.catchTag(
5701
+ "GitFailed",
5702
+ () => operationFailure(
5703
+ "Incompatible",
5704
+ "A selected commit is not in this repository."
5705
+ )
5706
+ ),
5707
+ Effect37.map(
5708
+ (output) => output.split(`
5709
+ `).filter((line) => line.length > 0).map((line) => line.split(" ").length - 1)
5710
+ )
5711
+ );
5712
+ }
5713
+ function hasStagedChanges(git, directory) {
5714
+ return runRepositoryGitOutput(
5715
+ git,
5716
+ directory,
5717
+ ["diff", "--cached", "--quiet"],
5718
+ { exitCodes: [0, 1] }
5719
+ ).pipe(Effect37.map(({ exitCode }) => exitCode === 1));
5720
+ }
5721
+ function hasUnmergedPaths(git, directory) {
5722
+ return runRepositoryGit(git, directory, ["ls-files", "--unmerged"]).pipe(
5723
+ Effect37.map((unmerged) => unmerged.length > 0)
5724
+ );
5725
+ }
5726
+
5727
+ // src/apps/server/features/repository-operations/start-operation.ts
5728
+ import { Effect as Effect39 } from "effect";
5729
+
5730
+ // src/apps/server/features/repository-operations/rebase-plan.ts
5731
+ import { Effect as Effect38 } from "effect";
5732
+ var todoCommands = {
5733
+ pick: "pick",
5734
+ reword: "pick",
5735
+ edit: "edit",
5736
+ squash: "fixup",
5737
+ fixup: "fixup",
5738
+ drop: "drop"
5739
+ };
5740
+ function rebasePlanTodo(git, directory, range, plan) {
5741
+ return Effect38.gen(function* () {
5742
+ let replayed = new Map(
5743
+ (yield* runRepositoryGit(git, directory, [
5744
+ "log",
5745
+ "--no-merges",
5746
+ "--format=%H%x00%P%x00%an%x00%ae%x00%ad%x00%s",
5747
+ "--date=raw",
5748
+ range
5749
+ ])).split(`
5750
+ `).filter(Boolean).map((line) => {
5751
+ let [commit = "", parents = "", name, email, date, subject] = line.split("\0");
5752
+ return [
5753
+ commit,
5754
+ { parent: parents.split(" ")[0] ?? "", name, email, date, subject }
5755
+ ];
5756
+ })
5757
+ );
5758
+ if (new Set(plan.map((step) => step.commit)).size !== plan.length || replayed.size !== plan.length || plan.some((step) => !replayed.has(step.commit)))
5759
+ return yield* operationFailure(
5760
+ "Stale",
5761
+ "The branch changed since the plan was made. Try again."
5762
+ );
5763
+ let problem = planProblem(plan);
5764
+ if (problem !== void 0)
5765
+ return yield* operationFailure("Incompatible", problem);
5766
+ let signed = (yield* runRepositoryGit(
5767
+ git,
5768
+ directory,
5769
+ ["config", "--type=bool", "--get", "commit.gpgSign"],
5770
+ { exitCodes: [0, 1] }
5771
+ )).trim() === "true", lines = [];
5772
+ for (let step of plan) {
5773
+ let original = replayed.get(step.commit), commit = step.message === null || original === void 0 ? step.commit : (yield* runRepositoryGit(
5774
+ git,
5775
+ directory,
5776
+ [
5777
+ "commit-tree",
5778
+ signed ? "-S" : "--no-gpg-sign",
5779
+ `${step.commit}^{tree}`,
5780
+ ...original.parent === "" ? [] : ["-p", original.parent]
5781
+ ],
5782
+ {
5783
+ input: `${step.message}
5784
+ `,
5785
+ environment: {
5786
+ GIT_AUTHOR_NAME: original.name ?? "",
5787
+ GIT_AUTHOR_EMAIL: original.email ?? "",
5788
+ GIT_AUTHOR_DATE: `@${original.date ?? ""}`
5789
+ }
5790
+ }
5791
+ )).trim(), subject = (step.message ?? original?.subject ?? "").split(
5792
+ /\r?\n/
5793
+ )[0];
5794
+ lines.push(`${todoCommands[step.action]} ${commit} # ${subject}`);
5795
+ }
5796
+ return `${lines.join(`
5797
+ `)}
5798
+ `;
5799
+ });
5800
+ }
5801
+ function planProblem(plan) {
5802
+ let kept, squashed = !1, unmatched = (head) => head !== void 0 && head.message !== null !== (head.action === "reword" || squashed);
5803
+ for (let step of plan) {
5804
+ if (step.action === "drop") {
5805
+ if (step.message !== null) return "A dropped commit has no message.";
5806
+ continue;
5807
+ }
5808
+ if (folds(step)) {
5809
+ if (kept === void 0)
5810
+ return `${step.commit.slice(0, 8)} has nothing older to fold into.`;
5811
+ if (step.message !== null)
5812
+ return "A folded commit takes the message of its group.";
5813
+ squashed ||= step.action === "squash";
5814
+ continue;
5815
+ }
5816
+ if (unmatched(kept))
5817
+ return `${kept?.commit.slice(0, 8)} needs exactly one message.`;
5818
+ kept = step, squashed = !1;
5819
+ }
5820
+ return unmatched(kept) ? `${kept?.commit.slice(0, 8)} needs exactly one message.` : void 0;
5821
+ }
5822
+ function folds(step) {
5823
+ return step.action === "squash" || step.action === "fixup";
5824
+ }
5825
+
5826
+ // src/apps/server/features/repository-operations/start-operation.ts
5827
+ function startOperation(git, coordination, command) {
5828
+ let { operation } = command;
5829
+ switch (operation._tag) {
5830
+ case "Merge":
5831
+ return startMerge(git, coordination, command, operation);
5832
+ case "Rebase":
5833
+ return startRebase(git, coordination, command, operation);
5834
+ case "Revert":
5835
+ return revertCommits(git, coordination, command, operation);
5836
+ case "CherryPick":
5837
+ return startCherryPick(git, coordination, command, operation);
5838
+ }
5839
+ }
5840
+ var mergeArguments = {
5841
+ merge: ["--ff", "--no-edit"],
5842
+ "ff-only": ["--ff-only"],
5843
+ "no-ff": ["--no-ff", "--no-edit"],
5844
+ squash: ["--squash"]
5845
+ };
5846
+ function startMerge(git, coordination, { worktreePath: directory, expectedHead }, { source, mode }) {
5847
+ let revision = source.ref ?? source.commit;
5848
+ return Effect39.gen(function* () {
5849
+ let head = yield* readCommit(git, directory, "HEAD");
5850
+ if (head !== expectedHead)
5851
+ return yield* operationFailure("Stale", "HEAD moved. Try again.");
5852
+ if (!(yield* onBranch(git, directory)))
5853
+ return yield* operationFailure("Incompatible", "HEAD is detached.");
5854
+ if ((yield* readCommit(git, directory, revision)) !== source.commit)
5855
+ return yield* operationFailure("Stale", `${revision} moved. Try again.`);
5856
+ let base = yield* runRepositoryGit(
5857
+ git,
5858
+ directory,
5859
+ ["merge-base", head, source.commit],
5860
+ { exitCodes: [0, 1] }
5861
+ );
5862
+ if (base.trim() === "")
5863
+ return yield* operationFailure(
5864
+ "Unrelated",
5865
+ `${revision} has no history in common with the current branch.`
5866
+ );
5867
+ if (base.trim() === source.commit)
5868
+ return started("UpToDate", yield* coordination.operation(directory));
5869
+ if (mode === "ff-only" && base.trim() !== head)
5870
+ return yield* operationFailure(
5871
+ "NotFastForward",
5872
+ `Can't fast-forward to ${revision}.`
5873
+ );
5874
+ let output = yield* git.run({
5875
+ directory,
5876
+ arguments: [
5877
+ "merge",
5878
+ "--no-autostash",
5879
+ "--no-stat",
5880
+ ...mergeArguments[mode],
5881
+ "--end-of-options",
5882
+ revision
5883
+ ],
5884
+ timeoutMilliseconds: 12e4
5885
+ }).pipe(Effect39.mapError(uncertain), Effect39.uninterruptible), state = yield* coordination.operation(directory);
5886
+ if (state.phase === "conflicts") return started("Stopped", state);
5887
+ if (yield* requireGitSuccess(output), mode === "squash") return started("Staged", state);
5888
+ let merged = yield* readCommit(git, directory, "HEAD");
5889
+ return started(
5890
+ merged === head ? "UpToDate" : merged === source.commit ? "FastForwarded" : "Committed",
5891
+ state
5892
+ );
5893
+ });
5894
+ }
5895
+ function startRebase(git, coordination, { worktreePath: directory, expectedHead }, { onto, stash, plan }) {
5896
+ let revision = onto.ref ?? onto.commit;
5897
+ return Effect39.gen(function* () {
5898
+ let [head, branch, target, changes, merges] = yield* Effect39.all(
5899
+ [
5900
+ readCommit(git, directory, "HEAD"),
5901
+ onBranch(git, directory),
5902
+ readCommit(git, directory, revision),
5903
+ runRepositoryGit(
5904
+ git,
5905
+ directory,
5906
+ ["status", "--porcelain=v1", "-z", "--untracked-files=no"],
5907
+ { globalArguments: ["--no-optional-locks"] }
5908
+ ),
5909
+ runRepositoryGit(
5910
+ git,
5911
+ directory,
5912
+ [
5913
+ "rev-list",
5914
+ "--merges",
5915
+ "--max-count=1",
5916
+ `${onto.commit}..${expectedHead}`
5917
+ ],
5918
+ { exitCodes: [0, 128] }
5919
+ )
5920
+ ],
5921
+ { concurrency: "unbounded" }
5922
+ );
5923
+ if (head !== expectedHead)
5924
+ return yield* operationFailure("Stale", "HEAD moved. Try again.");
5925
+ if (!branch)
5926
+ return yield* operationFailure("Incompatible", "HEAD is detached.");
5927
+ if (target !== onto.commit)
5928
+ return yield* operationFailure("Stale", `${revision} moved. Try again.`);
5929
+ if (changes.length > 0 && !stash)
5930
+ return yield* operationFailure(
5931
+ "Stale",
5932
+ "Files changed in the worktree. Try again."
5933
+ );
5934
+ let todo = plan === void 0 ? void 0 : yield* rebasePlanTodo(
5935
+ git,
5936
+ directory,
5937
+ `${onto.commit}..${expectedHead}`,
5938
+ plan
5939
+ ), output = yield* git.run({
5940
+ directory,
5941
+ ...todo === void 0 ? {} : { globalArguments: ["-c", "sequence.editor=cat >"], input: todo },
5942
+ arguments: [
5943
+ "rebase",
5944
+ ...todo === void 0 ? [] : ["--interactive", "--empty=drop"],
5945
+ merges.length > 0 && todo === void 0 ? "--rebase-merges" : "--no-rebase-merges",
5946
+ stash ? "--autostash" : "--no-autostash",
5947
+ "--end-of-options",
5948
+ revision
5949
+ ],
5950
+ timeoutMilliseconds: 6e5
5951
+ }).pipe(Effect39.mapError(uncertain), Effect39.uninterruptible), state = yield* coordination.operation(directory);
5952
+ if (state.kind === "rebase") return started("Stopped", state);
5953
+ if (yield* requireGitSuccess(output), /resulted in conflicts/.test(`${output.stdout}
5954
+ ${output.stderr}`))
5955
+ return yield* operationFailure(
5956
+ "GitRejected",
5957
+ `${output.stderr}${output.stdout}`
5958
+ );
5959
+ let rebased = yield* readCommit(git, directory, "HEAD");
5960
+ return started(
5961
+ rebased === head ? "UpToDate" : rebased === onto.commit ? "FastForwarded" : "Rebased",
5962
+ state
5963
+ );
5964
+ });
5965
+ }
5966
+ function revertCommits(git, coordination, { worktreePath: directory, expectedHead }, { commits, commit }) {
5967
+ return Effect39.gen(function* () {
5968
+ if ((yield* readCommit(git, directory, "HEAD")) !== expectedHead)
5969
+ return yield* operationFailure("Stale", "HEAD moved. Try again.");
5970
+ let outside = yield* runRepositoryGit(git, directory, [
5971
+ "rev-list",
5972
+ ...commits,
5973
+ "--not",
5974
+ "HEAD"
5975
+ ]), foreign = commits.find((oid) => outside.includes(oid));
5976
+ if (foreign !== void 0)
5977
+ return yield* operationFailure(
5978
+ "Incompatible",
5979
+ `${foreign.slice(0, 8)} is not in the checked-out branch.`
5980
+ );
5981
+ let output = yield* git.run({
5982
+ directory,
5983
+ arguments: [
5984
+ "revert",
5985
+ "--no-edit",
5986
+ "--mainline",
5987
+ "1",
5988
+ ...commit ? [] : ["--no-commit"],
5989
+ ...commits
5990
+ ],
5991
+ timeoutMilliseconds: 12e4
5992
+ }).pipe(Effect39.mapError(uncertain), Effect39.uninterruptible), state = yield* coordination.operation(directory), empty = /nothing to commit/i.test(
5993
+ `${output.stdout}
5994
+ ${output.stderr}`
5995
+ );
5996
+ return output.exitCode === 0 ? started(commit ? "Committed" : "Staged", state) : state.kind === "revert" && (state.phase === "conflicts" || empty) ? started("Stopped", state) : empty ? yield* operationFailure(
5997
+ "Empty",
5998
+ "Nothing to revert. The changes are already undone."
5999
+ ) : (yield* requireGitSuccess(output), started("Stopped", state));
6000
+ });
6001
+ }
6002
+ function onBranch(git, directory) {
6003
+ return runRepositoryGitOutput(
6004
+ git,
6005
+ directory,
6006
+ ["symbolic-ref", "--quiet", "HEAD"],
6007
+ { exitCodes: [0, 1] }
6008
+ ).pipe(Effect39.map((output) => output.exitCode === 0));
6009
+ }
6010
+
6011
+ // src/apps/server/features/repository-operations/repository-operations.ts
5414
6012
  function repositoryOperationsFeature(dependencies) {
5415
6013
  let { command, query } = repositoryRoutes(dependencies), { coordination } = dependencies, api = RepositoryOperationsApi;
5416
6014
  return {
@@ -5424,42 +6022,45 @@ function repositoryOperationsFeature(dependencies) {
5424
6022
  duringOperation: "proceed"
5425
6023
  },
5426
6024
  (input, git) => recoverRepositoryOperation(git, coordination, input)
6025
+ ),
6026
+ command(
6027
+ api.start,
6028
+ (input) => ({
6029
+ name: input.operation._tag.toLowerCase(),
6030
+ locks: { refs: "wait", worktree: "wait" },
6031
+ duringOperation: "block"
6032
+ }),
6033
+ (input, git) => startOperation(git, coordination, input)
5427
6034
  )
5428
6035
  ]
5429
6036
  };
5430
6037
  }
5431
6038
  function recoverRepositoryOperation(git, coordination, command) {
5432
- return Effect36.gen(function* () {
6039
+ return Effect40.gen(function* () {
5433
6040
  let state = yield* coordination.operation(command.worktreePath);
5434
- yield* validateRecoveryAction(state, command);
6041
+ if (yield* validateRecoveryAction(state, command), state.kind === "cherry-pick" && command.action === "continue" && (yield* continueStagedCherryPick(git, command.worktreePath)))
6042
+ return yield* coordination.operation(command.worktreePath).pipe(Effect40.mapError(uncertain));
5435
6043
  let output = yield* git.run({
5436
6044
  directory: command.worktreePath,
5437
- arguments: [state.kind, `--${command.action}`],
6045
+ arguments: state.kind === "squash" ? ["reset", "--merge"] : [state.kind, `--${command.action}`],
5438
6046
  timeoutMilliseconds: 12e4
5439
- }).pipe(
5440
- Effect36.mapError(
5441
- () => operationError(
5442
- "Uncertain",
5443
- "Git's result could not be confirmed. Refresh the worktree before trying again."
5444
- )
5445
- )
5446
- ), operation = yield* coordination.operation(command.worktreePath).pipe(
5447
- Effect36.mapError(
6047
+ }).pipe(Effect40.mapError(uncertain)), operation = yield* coordination.operation(command.worktreePath).pipe(
6048
+ Effect40.mapError(
5448
6049
  () => operationError(
5449
6050
  "Uncertain",
5450
6051
  "Git finished, but its current state could not be read."
5451
6052
  )
5452
6053
  )
5453
6054
  );
5454
- return (command.action === "abort" || !advancedToConflict(state, operation)) && (yield* requireRecoverySuccess(output)), operation;
5455
- }).pipe(Effect36.uninterruptible);
6055
+ return (command.action === "abort" || !advancedToStop(state, operation)) && (yield* requireGitSuccess(output)), operation;
6056
+ }).pipe(Effect40.uninterruptible);
5456
6057
  }
5457
- function advancedToConflict(previous, current) {
5458
- return current.kind === previous.kind && current.phase === "conflicts" && (current.commit !== null && current.commit !== previous.commit || current.progress !== null && previous.progress !== null && current.progress.current > previous.progress.current);
6058
+ function advancedToStop(previous, current) {
6059
+ return current.kind === previous.kind && (current.phase === "conflicts" || current.phase === "empty") && (current.commit !== null && current.commit !== previous.commit || current.progress !== null && previous.progress !== null && current.progress.current > previous.progress.current);
5459
6060
  }
5460
6061
  function validateRecoveryAction(state, command) {
5461
6062
  if (state.revision !== command.revision)
5462
- return Effect36.fail(
6063
+ return Effect40.fail(
5463
6064
  operationError(
5464
6065
  "Stale",
5465
6066
  "Git state changed. Review the refreshed operation before trying again."
@@ -5468,44 +6069,31 @@ function validateRecoveryAction(state, command) {
5468
6069
  let action = state.actions.find(
5469
6070
  (candidate) => candidate.action === command.action
5470
6071
  );
5471
- if (action?.enabled) return Effect36.void;
6072
+ if (action?.enabled) return Effect40.void;
5472
6073
  let detail = action?.reason ?? "This action is not supported by the current Git state.";
5473
- return Effect36.fail(
6074
+ return Effect40.fail(
5474
6075
  state.lock ? repositoryRejected("Busy", detail) : operationError("Incompatible", detail)
5475
6076
  );
5476
6077
  }
5477
- function requireRecoverySuccess(output) {
5478
- if (output.exitCode === 0) return Effect36.void;
5479
- let detail = output.stderr || output.stdout || "Git rejected the action. Check the worktree and configured hooks.";
5480
- return /\.lock['\s:]|another git process/i.test(detail) ? Effect36.fail(repositoryRejected("Busy", detail)) : Effect36.fail(
5481
- operationError(
5482
- /hook|pre-commit|commit-msg|pre-rebase/i.test(detail) ? "HookFailed" : "GitRejected",
5483
- detail
5484
- )
5485
- );
5486
- }
5487
- function operationError(reason, detail) {
5488
- return { _tag: "OperationFailed", reason, detail: detail.slice(0, 2048) };
5489
- }
5490
6078
 
5491
6079
  // src/apps/server/features/repository-pull/repository-pull.feature.ts
5492
- import { Effect as Effect40 } from "effect";
6080
+ import { Effect as Effect44 } from "effect";
5493
6081
 
5494
6082
  // src/apps/server/features/repository-pull/fast-forward-branch.ts
5495
- import { Effect as Effect37 } from "effect";
6083
+ import { Effect as Effect41 } from "effect";
5496
6084
  var pullCommand = { timeoutMilliseconds: 6e4 };
5497
6085
  function fastForwardBranch(git, directory, branch, checkedOut) {
5498
- return Effect37.gen(function* () {
6086
+ return Effect41.gen(function* () {
5499
6087
  let tracked = yield* readTrackedBranch(git, directory, branch), upstreamTarget = yield* resolveUpstream(git, directory, tracked), { ahead, behind } = yield* countDivergence(
5500
6088
  git,
5501
6089
  directory,
5502
6090
  tracked.target,
5503
6091
  upstreamTarget
5504
6092
  );
5505
- return behind === 0 ? { outcome: "UpToDate" } : ahead > 0 ? yield* Effect37.fail({
6093
+ return behind === 0 ? { outcome: "UpToDate" } : ahead > 0 ? yield* Effect41.fail({
5506
6094
  _tag: "PullDiverged",
5507
6095
  upstream: tracked.upstream
5508
- }) : (yield* Effect37.uninterruptible(
6096
+ }) : (yield* Effect41.uninterruptible(
5509
6097
  checkedOut ? mergeFastForward(git, directory, tracked, upstreamTarget) : moveBranch(git, directory, tracked, upstreamTarget)
5510
6098
  ), { outcome: "FastForwarded" });
5511
6099
  });
@@ -5522,10 +6110,10 @@ function readTrackedBranch(git, directory, branch) {
5522
6110
  ],
5523
6111
  pullCommand
5524
6112
  ).pipe(
5525
- Effect37.flatMap((output) => {
6113
+ Effect41.flatMap((output) => {
5526
6114
  let [, target, upstreamRef, upstream] = output.split(`
5527
6115
  `).map((line) => line.split("\0")).find(([name]) => name === ref) ?? [];
5528
- return target === void 0 ? Effect37.fail({ _tag: "BranchMissing" }) : !upstreamRef || !upstream ? Effect37.fail({ _tag: "UpstreamMissing" }) : Effect37.succeed({
6116
+ return target === void 0 ? Effect41.fail({ _tag: "BranchMissing" }) : !upstreamRef || !upstream ? Effect41.fail({ _tag: "UpstreamMissing" }) : Effect41.succeed({
5529
6117
  name: branch,
5530
6118
  target,
5531
6119
  upstreamRef,
@@ -5541,11 +6129,11 @@ function resolveUpstream(git, directory, tracked) {
5541
6129
  ["rev-parse", "--verify", "--quiet", `${tracked.upstreamRef}^{commit}`],
5542
6130
  { ...pullCommand, exitCodes: [0, 1] }
5543
6131
  ).pipe(
5544
- Effect37.flatMap(
5545
- (output) => output.trim() === "" ? Effect37.fail({
6132
+ Effect41.flatMap(
6133
+ (output) => output.trim() === "" ? Effect41.fail({
5546
6134
  _tag: "UpstreamMissing",
5547
6135
  upstream: tracked.upstream
5548
- }) : Effect37.succeed(output.trim())
6136
+ }) : Effect41.succeed(output.trim())
5549
6137
  )
5550
6138
  );
5551
6139
  }
@@ -5556,7 +6144,7 @@ function countDivergence(git, directory, target, upstreamTarget) {
5556
6144
  ["rev-list", "--left-right", "--count", `${target}...${upstreamTarget}`],
5557
6145
  pullCommand
5558
6146
  ).pipe(
5559
- Effect37.map((output) => {
6147
+ Effect41.map((output) => {
5560
6148
  let [ahead = 0, behind = 0] = output.trim().split(/\s+/).map(Number);
5561
6149
  return { ahead, behind };
5562
6150
  })
@@ -5576,8 +6164,8 @@ function mergeFastForward(git, directory, tracked, upstreamTarget) {
5576
6164
  ],
5577
6165
  pullCommand
5578
6166
  ).pipe(
5579
- Effect37.asVoid,
5580
- Effect37.mapError((error) => mergeFailure(error, tracked))
6167
+ Effect41.asVoid,
6168
+ Effect41.mapError((error) => mergeFailure(error, tracked))
5581
6169
  );
5582
6170
  }
5583
6171
  function mergeFailure(error, tracked) {
@@ -5604,8 +6192,8 @@ function moveBranch(git, directory, tracked, upstreamTarget) {
5604
6192
  ],
5605
6193
  pullCommand
5606
6194
  ).pipe(
5607
- Effect37.asVoid,
5608
- Effect37.mapError(
6195
+ Effect41.asVoid,
6196
+ Effect41.mapError(
5609
6197
  (error) => isGitRejection(error) ? branchMoved(tracked) : { _tag: "PullUncertain" }
5610
6198
  )
5611
6199
  );
@@ -5618,7 +6206,7 @@ function pullBlocked(detail) {
5618
6206
  }
5619
6207
 
5620
6208
  // src/apps/server/features/repository-pull/repository-fetch.ts
5621
- import { Cause, Effect as Effect38, Fiber as Fiber2, Option, Semaphore } from "effect";
6209
+ import { Cause, Effect as Effect42, Fiber as Fiber2, Option, Semaphore } from "effect";
5622
6210
  var defaultIntervalSeconds = 300, maximumFetchedRepositories = 32, settingKey = "rebase.autoFetchIntervalSeconds";
5623
6211
  function acquireRepositoryFetch({
5624
6212
  access,
@@ -5626,24 +6214,24 @@ function acquireRepositoryFetch({
5626
6214
  events,
5627
6215
  git
5628
6216
  }) {
5629
- return Effect38.gen(function* () {
5630
- let scope = yield* Effect38.scope, mutex = yield* Semaphore.make(1), repositories = /* @__PURE__ */ new Map(), status = (repository) => ({
6217
+ return Effect42.gen(function* () {
6218
+ let scope = yield* Effect42.scope, mutex = yield* Semaphore.make(1), repositories = /* @__PURE__ */ new Map(), status = (repository) => ({
5631
6219
  fetching: repository.fetching !== void 0,
5632
6220
  defaultIntervalSeconds,
5633
6221
  setting: repository.setting,
5634
6222
  ...repository.failure === void 0 ? {} : { failure: repository.failure }
5635
- }), publish = (repository) => events.publishChanged([...repository.repositoryIds], "Fetch"), schedule = (repository) => Effect38.gen(function* () {
6223
+ }), publish = (repository) => events.publishChanged([...repository.repositoryIds], "Fetch"), schedule = (repository) => Effect42.gen(function* () {
5636
6224
  let previous = repository.schedule;
5637
6225
  if (repository.schedule = void 0, previous !== void 0 && (yield* Fiber2.interrupt(previous)), repository.fetching !== void 0 || repository.setting._tag === "Disabled")
5638
6226
  return;
5639
6227
  let seconds = repository.setting._tag === "Interval" ? repository.setting.seconds : defaultIntervalSeconds;
5640
- repository.schedule = yield* Effect38.sleep(seconds * 1e3).pipe(
5641
- Effect38.andThen(tick(repository)),
5642
- Effect38.forkIn(scope)
6228
+ repository.schedule = yield* Effect42.sleep(seconds * 1e3).pipe(
6229
+ Effect42.andThen(tick(repository)),
6230
+ Effect42.forkIn(scope)
5643
6231
  );
5644
- }), tick = (repository) => Effect38.gen(function* () {
6232
+ }), tick = (repository) => Effect42.gen(function* () {
5645
6233
  repository.schedule = void 0, events.listening() ? yield* begin(repository) : yield* schedule(repository);
5646
- }).pipe(Semaphore.withPermit(mutex)), begin = (repository) => Effect38.gen(function* () {
6234
+ }).pipe(Semaphore.withPermit(mutex)), begin = (repository) => Effect42.gen(function* () {
5647
6235
  if (repository.fetching !== void 0) return repository.fetching;
5648
6236
  let previous = repository.schedule;
5649
6237
  repository.schedule = void 0, previous !== void 0 && (yield* Fiber2.interrupt(previous));
@@ -5652,15 +6240,15 @@ function acquireRepositoryFetch({
5652
6240
  coordination,
5653
6241
  repository.path
5654
6242
  ).pipe(
5655
- Effect38.tap(
5656
- (failure) => Effect38.gen(function* () {
6243
+ Effect42.tap(
6244
+ (failure) => Effect42.gen(function* () {
5657
6245
  repository.fetching = void 0, failure === void 0 ? delete repository.failure : repository.failure = failure, publish(repository), yield* schedule(repository);
5658
6246
  }).pipe(Semaphore.withPermit(mutex))
5659
6247
  ),
5660
- Effect38.forkIn(scope)
6248
+ Effect42.forkIn(scope)
5661
6249
  );
5662
6250
  return repository.fetching = fetching, publish(repository), fetching;
5663
- }), register = (repositoryId) => Effect38.gen(function* () {
6251
+ }), register = (repositoryId) => Effect42.gen(function* () {
5664
6252
  let entry = yield* access.repository(repositoryId), key = entry.logicalRepositoryId ?? entry.id, known = repositories.get(key);
5665
6253
  if (known !== void 0)
5666
6254
  return known.repositoryIds.add(repositoryId), repositories.delete(key), repositories.set(key, known), known;
@@ -5670,28 +6258,28 @@ function acquireRepositoryFetch({
5670
6258
  setting: yield* readFetchSetting(git, entry.path)
5671
6259
  };
5672
6260
  return repositories.set(key, repository), yield* evictOldest, repository.setting._tag !== "Disabled" && (yield* begin(repository)), repository;
5673
- }).pipe(Semaphore.withPermit(mutex)), evictOldest = Effect38.suspend(() => {
6261
+ }).pipe(Semaphore.withPermit(mutex)), evictOldest = Effect42.suspend(() => {
5674
6262
  let oldest = repositories.entries().next().value;
5675
6263
  if (repositories.size <= maximumFetchedRepositories || oldest === void 0)
5676
- return Effect38.void;
6264
+ return Effect42.void;
5677
6265
  repositories.delete(oldest[0]);
5678
6266
  let { schedule: scheduled, fetching } = oldest[1];
5679
- return Effect38.all([
5680
- scheduled === void 0 ? Effect38.void : Fiber2.interrupt(scheduled),
5681
- fetching === void 0 ? Effect38.void : Fiber2.interrupt(fetching)
6267
+ return Effect42.all([
6268
+ scheduled === void 0 ? Effect42.void : Fiber2.interrupt(scheduled),
6269
+ fetching === void 0 ? Effect42.void : Fiber2.interrupt(fetching)
5682
6270
  ]);
5683
6271
  });
5684
6272
  return {
5685
- status: (repositoryId) => register(repositoryId).pipe(Effect38.map(status)),
5686
- fetch: (repositoryId) => Effect38.gen(function* () {
6273
+ status: (repositoryId) => register(repositoryId).pipe(Effect42.map(status)),
6274
+ fetch: (repositoryId) => Effect42.gen(function* () {
5687
6275
  let repository = yield* register(repositoryId), fetching = yield* begin(repository).pipe(
5688
6276
  Semaphore.withPermit(mutex)
5689
6277
  ), failure = yield* Fiber2.join(fetching);
5690
- return failure !== void 0 ? yield* Effect38.fail(failure) : status(repository);
6278
+ return failure !== void 0 ? yield* Effect42.fail(failure) : status(repository);
5691
6279
  }),
5692
- configure: (repositoryId, setting) => Effect38.gen(function* () {
6280
+ configure: (repositoryId, setting) => Effect42.gen(function* () {
5693
6281
  let repository = yield* register(repositoryId);
5694
- return yield* Effect38.gen(function* () {
6282
+ return yield* Effect42.gen(function* () {
5695
6283
  return yield* writeFetchSetting(git, repository.path, setting), repository.setting = setting, yield* schedule(repository), publish(repository), status(repository);
5696
6284
  }).pipe(Semaphore.withPermit(mutex));
5697
6285
  })
@@ -5708,12 +6296,12 @@ function runFetch(git, coordination, path) {
5708
6296
  },
5709
6297
  runRepositoryGit(git, path, ["fetch"], { timeoutMilliseconds: 12e4 })
5710
6298
  ).pipe(
5711
- Effect38.as(void 0),
5712
- Effect38.catchCause((cause) => {
6299
+ Effect42.as(void 0),
6300
+ Effect42.catchCause((cause) => {
5713
6301
  if (Cause.hasInterrupts(cause))
5714
- return Effect38.failCause(Cause.interrupt());
6302
+ return Effect42.failCause(Cause.interrupt());
5715
6303
  let error = Cause.findErrorOption(cause);
5716
- return Effect38.succeed({
6304
+ return Effect42.succeed({
5717
6305
  _tag: "FetchFailed",
5718
6306
  reason: Option.isSome(error) && error.value._tag === "GitFailed" ? error.value.reason : "Failed"
5719
6307
  });
@@ -5727,11 +6315,11 @@ function readFetchSetting(git, path) {
5727
6315
  ["config", "--local", "--get", settingKey],
5728
6316
  { exitCodes: [0, 1] }
5729
6317
  ).pipe(
5730
- Effect38.map((output) => {
6318
+ Effect42.map((output) => {
5731
6319
  let value = output.trim(), seconds = Number(value);
5732
6320
  return value === "0" ? { _tag: "Disabled" } : Number.isInteger(seconds) && seconds > 0 && seconds <= 86400 ? { _tag: "Interval", seconds } : { _tag: "Inherit" };
5733
6321
  }),
5734
- Effect38.mapError(settingsUnavailable)
6322
+ Effect42.mapError(settingsUnavailable)
5735
6323
  );
5736
6324
  }
5737
6325
  function writeFetchSetting(git, path, setting) {
@@ -5741,7 +6329,7 @@ function writeFetchSetting(git, path, setting) {
5741
6329
  "--local",
5742
6330
  settingKey,
5743
6331
  value
5744
- ]).pipe(Effect38.asVoid, Effect38.mapError(settingsUnavailable));
6332
+ ]).pipe(Effect42.asVoid, Effect42.mapError(settingsUnavailable));
5745
6333
  }
5746
6334
  function settingsUnavailable() {
5747
6335
  return repositoryRejected(
@@ -5753,29 +6341,29 @@ function settingsUnavailable() {
5753
6341
  // src/apps/server/repository/repository-access.ts
5754
6342
  import { realpath as realpath4 } from "node:fs";
5755
6343
  import { promisify as promisify3 } from "node:util";
5756
- import { Effect as Effect39 } from "effect";
6344
+ import { Effect as Effect43 } from "effect";
5757
6345
  var realpathNative3 = promisify3(realpath4.native), branchPrefix = "refs/heads/";
5758
6346
  function createRepositoryAccess(catalog, git, watcher) {
5759
6347
  let worktreePaths = createWorktreePathCache(git, watcher), repository = (repositoryId) => catalog.find(repositoryId).pipe(
5760
- Effect39.flatMap(
5761
- (entry) => entry === void 0 ? Effect39.fail(
6348
+ Effect43.flatMap(
6349
+ (entry) => entry === void 0 ? Effect43.fail(
5762
6350
  repositoryRejected(
5763
6351
  "Missing",
5764
6352
  "This repository is no longer available."
5765
6353
  )
5766
- ) : Effect39.succeed(entry)
6354
+ ) : Effect43.succeed(entry)
5767
6355
  )
5768
6356
  );
5769
6357
  return {
5770
6358
  repository,
5771
6359
  worktrees: (repositoryPath) => readWorktrees(git, repositoryPath).pipe(
5772
- Effect39.flatMap(canonicalizeWorktrees),
5773
- Effect39.mapError(worktreesUnreadable)
6360
+ Effect43.flatMap(canonicalizeWorktrees),
6361
+ Effect43.mapError(worktreesUnreadable)
5774
6362
  ),
5775
- requireWorktree: (scope) => Effect39.gen(function* () {
6363
+ requireWorktree: (scope) => Effect43.gen(function* () {
5776
6364
  let entry = yield* repository(scope.repositoryId);
5777
- if (!(yield* worktreePaths.contains(entry.path, scope.worktreePath).pipe(Effect39.mapError(worktreesUnreadable))))
5778
- return yield* Effect39.fail(
6365
+ if (!(yield* worktreePaths.contains(entry.path, scope.worktreePath).pipe(Effect43.mapError(worktreesUnreadable))))
6366
+ return yield* Effect43.fail(
5779
6367
  repositoryRejected(
5780
6368
  "Missing",
5781
6369
  "This worktree does not belong to the repository."
@@ -5790,12 +6378,12 @@ function readWorktrees(git, directory) {
5790
6378
  directory,
5791
6379
  ["worktree", "list", "--porcelain", "-z"],
5792
6380
  { timeoutMilliseconds: 15e3 }
5793
- ).pipe(Effect39.map(parseWorktreeList));
6381
+ ).pipe(Effect43.map(parseWorktreeList));
5794
6382
  }
5795
6383
  function canonicalizeWorktrees(worktrees) {
5796
- return Effect39.all(
6384
+ return Effect43.all(
5797
6385
  worktrees.map(
5798
- (worktree) => Effect39.promise(async () => ({
6386
+ (worktree) => Effect43.promise(async () => ({
5799
6387
  ...worktree,
5800
6388
  path: await realpathNative3(worktree.path).catch(() => worktree.path)
5801
6389
  }))
@@ -5816,13 +6404,13 @@ function createWorktreePathCache(git, watcher) {
5816
6404
  entry.watch = void 0, watch3?.close();
5817
6405
  }, reload = (repositoryPath) => {
5818
6406
  let entry = {}, changed = !1;
5819
- return Effect39.gen(function* () {
6407
+ return Effect43.gen(function* () {
5820
6408
  let directory = yield* readGitCommonDirectory(git, repositoryPath);
5821
6409
  entry.watch = yield* watcher.watch(directory, (kind) => {
5822
6410
  kind !== "Index" && (changed = !0, forget(repositoryPath, entry));
5823
6411
  });
5824
6412
  let worktrees = yield* readWorktrees(git, repositoryPath).pipe(
5825
- Effect39.flatMap(canonicalizeWorktrees)
6413
+ Effect43.flatMap(canonicalizeWorktrees)
5826
6414
  );
5827
6415
  if (entry.paths = new Set(worktrees.map((worktree) => worktree.path)), !changed) {
5828
6416
  let previous = cache.get(repositoryPath);
@@ -5830,16 +6418,16 @@ function createWorktreePathCache(git, watcher) {
5830
6418
  }
5831
6419
  return entry.paths;
5832
6420
  }).pipe(
5833
- Effect39.onExit(
5834
- () => Effect39.sync(() => {
6421
+ Effect43.onExit(
6422
+ () => Effect43.sync(() => {
5835
6423
  cache.get(repositoryPath) !== entry && forget(repositoryPath, entry);
5836
6424
  })
5837
6425
  )
5838
6426
  );
5839
6427
  };
5840
6428
  return {
5841
- contains: (repositoryPath, worktreePath) => cache.get(repositoryPath)?.paths?.has(worktreePath) ? Effect39.succeed(!0) : reload(repositoryPath).pipe(
5842
- Effect39.map((paths) => paths.has(worktreePath))
6429
+ contains: (repositoryPath, worktreePath) => cache.get(repositoryPath)?.paths?.has(worktreePath) ? Effect43.succeed(!0) : reload(repositoryPath).pipe(
6430
+ Effect43.map((paths) => paths.has(worktreePath))
5843
6431
  )
5844
6432
  };
5845
6433
  }
@@ -5882,7 +6470,7 @@ function worktreeFromEntry(entry, main2) {
5882
6470
 
5883
6471
  // src/apps/server/features/repository-pull/repository-pull.feature.ts
5884
6472
  function repositoryPullFeature(dependencies) {
5885
- return Effect40.gen(function* () {
6473
+ return Effect44.gen(function* () {
5886
6474
  let { command } = repositoryRoutes(dependencies), fetch = yield* acquireRepositoryFetch(dependencies);
5887
6475
  return {
5888
6476
  routes: [
@@ -5912,7 +6500,7 @@ function repositoryPullFeature(dependencies) {
5912
6500
  });
5913
6501
  }
5914
6502
  function pullBranch(coordination) {
5915
- return (command, git) => Effect40.gen(function* () {
6503
+ return (command, git) => Effect44.gen(function* () {
5916
6504
  let checkout = yield* findCheckout(git, command), directory = checkout ?? command.worktreePath;
5917
6505
  return yield* coordination.run(
5918
6506
  directory,
@@ -5922,7 +6510,7 @@ function pullBranch(coordination) {
5922
6510
  duringOperation: "block"
5923
6511
  },
5924
6512
  requireSameCheckout(git, command, checkout).pipe(
5925
- Effect40.andThen(
6513
+ Effect44.andThen(
5926
6514
  fastForwardBranch(
5927
6515
  git,
5928
6516
  directory,
@@ -5936,7 +6524,7 @@ function pullBranch(coordination) {
5936
6524
  }
5937
6525
  function requireSameCheckout(git, command, checkout) {
5938
6526
  return findCheckout(git, command).pipe(
5939
- Effect40.filterOrFail(
6527
+ Effect44.filterOrFail(
5940
6528
  (current) => current === checkout,
5941
6529
  () => pullBlocked(`${command.branch} was checked out while pulling`)
5942
6530
  )
@@ -5944,15 +6532,15 @@ function requireSameCheckout(git, command, checkout) {
5944
6532
  }
5945
6533
  function findCheckout(git, command) {
5946
6534
  return readWorktrees(git, command.worktreePath).pipe(
5947
- Effect40.flatMap(canonicalizeWorktrees),
5948
- Effect40.map(
6535
+ Effect44.flatMap(canonicalizeWorktrees),
6536
+ Effect44.map(
5949
6537
  (worktrees) => worktrees.find((worktree) => worktree.head.branch === command.branch)?.path
5950
6538
  )
5951
6539
  );
5952
6540
  }
5953
6541
 
5954
6542
  // src/apps/server/features/repository-push/repository-push.ts
5955
- import { Effect as Effect42 } from "effect";
6543
+ import { Effect as Effect46 } from "effect";
5956
6544
 
5957
6545
  // src/apps/server/features/repository-push/git/push-failures.ts
5958
6546
  function pushError(reason, detail) {
@@ -5993,11 +6581,11 @@ function classifyPushFailure(output, destinationRef) {
5993
6581
  }
5994
6582
 
5995
6583
  // src/apps/server/features/repository-push/git/reconcile-remote-branch.ts
5996
- import { Effect as Effect41 } from "effect";
6584
+ import { Effect as Effect45 } from "effect";
5997
6585
  var reconcileTimeoutMilliseconds = 3e4;
5998
6586
  function reconcileRemoteBranch(git, directory, { remote, branch }) {
5999
6587
  let remoteRef = `refs/heads/${branch}`, trackingRef = `refs/remotes/${remote}/${branch}`, options = { timeoutMilliseconds: reconcileTimeoutMilliseconds };
6000
- return Effect41.gen(function* () {
6588
+ return Effect45.gen(function* () {
6001
6589
  let target = (yield* runRepositoryGit(
6002
6590
  git,
6003
6591
  directory,
@@ -6026,13 +6614,13 @@ function reconcileRemoteBranch(git, directory, { remote, branch }) {
6026
6614
  function uncertainPush(git, directory, destination) {
6027
6615
  let name = `${destination.remote}/${destination.branch}`;
6028
6616
  return reconcileRemoteBranch(git, directory, destination).pipe(
6029
- Effect41.map(
6617
+ Effect45.map(
6030
6618
  (target) => target === null ? `Push unconfirmed. ${name} no longer exists.` : `Push unconfirmed. ${name} is at ${target.slice(0, 8)}.`
6031
6619
  ),
6032
- Effect41.orElseSucceed(
6620
+ Effect45.orElseSucceed(
6033
6621
  () => `Push unconfirmed and ${name} could not be read. Fetch to check.`
6034
6622
  ),
6035
- Effect41.flatMap((detail) => Effect41.fail(pushError("Uncertain", detail)))
6623
+ Effect45.flatMap((detail) => Effect45.fail(pushError("Uncertain", detail)))
6036
6624
  );
6037
6625
  }
6038
6626
 
@@ -6040,7 +6628,7 @@ function uncertainPush(git, directory, destination) {
6040
6628
  var pushTimeoutMilliseconds = 12e4;
6041
6629
  function pushRemoteBranch(git, command) {
6042
6630
  let directory = command.worktreePath, destinationRef = `refs/heads/${command.destination.branch}`;
6043
- return Effect42.gen(function* () {
6631
+ return Effect46.gen(function* () {
6044
6632
  yield* requireDestination(git, directory, command.destination);
6045
6633
  let target = yield* readBranchTip(git, directory, command.branch);
6046
6634
  return yield* runPush(
@@ -6059,18 +6647,66 @@ function pushRemoteBranch(git, command) {
6059
6647
  };
6060
6648
  });
6061
6649
  }
6650
+ function pushTagsToRemote(git, { worktreePath, remote, tags }) {
6651
+ let refs = tags.map((tag) => `refs/tags/${tag}`);
6652
+ return Effect46.gen(function* () {
6653
+ yield* requireRemote(git, worktreePath, remote);
6654
+ let output = yield* git.run({
6655
+ directory: worktreePath,
6656
+ arguments: [
6657
+ "push",
6658
+ "--porcelain",
6659
+ "--atomic",
6660
+ remote,
6661
+ ...refs.map((ref) => `${ref}:${ref}`)
6662
+ ],
6663
+ timeoutMilliseconds: pushTimeoutMilliseconds
6664
+ }).pipe(
6665
+ Effect46.mapError(
6666
+ (error) => error.reason === "Timeout" ? pushError(
6667
+ "Uncertain",
6668
+ `The push to ${remote} did not finish. Fetch to see which tags arrived.`
6669
+ ) : repositoryRejected(
6670
+ "GitFailed",
6671
+ `Git could not run the push (${error.reason}).`
6672
+ )
6673
+ )
6674
+ ), statuses = tags.map((tag, index2) => ({
6675
+ tag,
6676
+ status: pushRefStatus(output.stdout, refs[index2] ?? "")
6677
+ }));
6678
+ if (output.exitCode === 0)
6679
+ return {
6680
+ remote,
6681
+ pushed: statuses.filter(({ status }) => status?.flag !== "=").map(({ tag }) => tag),
6682
+ upToDate: statuses.filter(({ status }) => status?.flag === "=").map(({ tag }) => tag)
6683
+ };
6684
+ let existing = statuses.filter(({ status }) => status?.summary.includes("(already exists)")).map(({ tag }) => tag);
6685
+ return yield* Effect46.fail(
6686
+ existing.length > 0 ? pushError("TagExists", existing.join(", ")) : classifyPushFailure(output, refs[0] ?? "")
6687
+ );
6688
+ });
6689
+ }
6690
+ function requireRemote(git, directory, remote) {
6691
+ return runRepositoryGit(git, directory, ["remote"]).pipe(
6692
+ Effect46.flatMap(
6693
+ (remotes) => remotes.split(`
6694
+ `).includes(remote) ? Effect46.void : Effect46.fail(
6695
+ pushError(
6696
+ "RemoteMissing",
6697
+ `The remote "${remote}" does not exist.`
6698
+ )
6699
+ )
6700
+ )
6701
+ );
6702
+ }
6062
6703
  function requireDestination(git, directory, { remote, branch }) {
6063
- return Effect42.gen(function* () {
6064
- if (!(yield* runRepositoryGit(git, directory, ["remote"])).split(`
6065
- `).includes(remote))
6066
- return yield* Effect42.fail(
6067
- pushError("RemoteMissing", `The remote "${remote}" does not exist.`)
6068
- );
6069
- yield* runRepositoryGit(git, directory, [
6704
+ return Effect46.gen(function* () {
6705
+ yield* requireRemote(git, directory, remote), yield* runRepositoryGit(git, directory, [
6070
6706
  "check-ref-format",
6071
6707
  `refs/heads/${branch}`
6072
6708
  ]).pipe(
6073
- Effect42.mapError(
6709
+ Effect46.mapError(
6074
6710
  () => pushError("InvalidBranch", `"${branch}" is not a valid branch name.`)
6075
6711
  )
6076
6712
  );
@@ -6083,8 +6719,8 @@ function readBranchTip(git, directory, branch) {
6083
6719
  "--quiet",
6084
6720
  `refs/heads/${branch}^{commit}`
6085
6721
  ]).pipe(
6086
- Effect42.map((output) => output.trim()),
6087
- Effect42.mapError(
6722
+ Effect46.map((output) => output.trim()),
6723
+ Effect46.mapError(
6088
6724
  () => pushError("InvalidBranch", `The branch "${branch}" does not exist.`)
6089
6725
  )
6090
6726
  );
@@ -6096,23 +6732,23 @@ function runPush(git, directory, args, destination) {
6096
6732
  arguments: ["push", "--porcelain", ...args],
6097
6733
  timeoutMilliseconds: pushTimeoutMilliseconds
6098
6734
  }).pipe(
6099
- Effect42.catch(
6100
- (error) => error.reason === "Timeout" ? uncertainPush(git, directory, destination) : Effect42.fail(
6735
+ Effect46.catch(
6736
+ (error) => error.reason === "Timeout" ? uncertainPush(git, directory, destination) : Effect46.fail(
6101
6737
  repositoryRejected(
6102
6738
  "GitFailed",
6103
6739
  `Git could not run the push (${error.reason}).`
6104
6740
  )
6105
6741
  )
6106
6742
  ),
6107
- Effect42.flatMap((output) => requirePushed(output, destinationRef)),
6108
- Effect42.onInterrupt(
6109
- () => reconcileRemoteBranch(git, directory, destination).pipe(Effect42.ignore)
6743
+ Effect46.flatMap((output) => requirePushed(output, destinationRef)),
6744
+ Effect46.onInterrupt(
6745
+ () => reconcileRemoteBranch(git, directory, destination).pipe(Effect46.ignore)
6110
6746
  )
6111
6747
  );
6112
6748
  }
6113
6749
  function requirePushed(output, destinationRef) {
6114
6750
  let status = pushRefStatus(output.stdout, destinationRef);
6115
- return output.exitCode === 0 && status !== void 0 && status.flag !== "!" ? Effect42.void : Effect42.fail(classifyPushFailure(output, destinationRef));
6751
+ return output.exitCode === 0 && status !== void 0 && status.flag !== "!" ? Effect46.void : Effect46.fail(classifyPushFailure(output, destinationRef));
6116
6752
  }
6117
6753
  function repositoryPushFeature(dependencies) {
6118
6754
  let { command } = repositoryRoutes(dependencies);
@@ -6122,6 +6758,11 @@ function repositoryPushFeature(dependencies) {
6122
6758
  RepositoryPushApi.push,
6123
6759
  { name: "push", locks: { refs: "wait" }, duringOperation: "block" },
6124
6760
  (input, git) => pushRemoteBranch(git, input)
6761
+ ),
6762
+ command(
6763
+ RepositoryPushApi.pushTags,
6764
+ { name: "push", locks: { refs: "wait" }, duringOperation: "proceed" },
6765
+ (input, git) => pushTagsToRemote(git, input)
6125
6766
  )
6126
6767
  ]
6127
6768
  };
@@ -6129,7 +6770,7 @@ function repositoryPushFeature(dependencies) {
6129
6770
 
6130
6771
  // src/apps/server/features/repository-reflog/repository-reflog.ts
6131
6772
  import { createHash as createHash3 } from "node:crypto";
6132
- import { Effect as Effect44 } from "effect";
6773
+ import { Effect as Effect48 } from "effect";
6133
6774
 
6134
6775
  // src/apps/server/features/repository-reflog/reflog-entries.ts
6135
6776
  function parseReflog(output) {
@@ -6248,7 +6889,7 @@ function text2(value) {
6248
6889
  }
6249
6890
 
6250
6891
  // src/apps/server/features/repository-refs/git/ref-git.ts
6251
- import { Effect as Effect43 } from "effect";
6892
+ import { Effect as Effect47 } from "effect";
6252
6893
  var refCommand = {
6253
6894
  literalPathspecs: !1,
6254
6895
  timeoutMilliseconds: 3e4
@@ -6260,8 +6901,8 @@ function requireValidRefName(git, directory, fullRef, invalid) {
6260
6901
  ["check-ref-format", fullRef],
6261
6902
  refCommand
6262
6903
  ).pipe(
6263
- Effect43.catchIf(isGitRejection, () => Effect43.fail(invalid)),
6264
- Effect43.asVoid
6904
+ Effect47.catchIf(isGitRejection, () => Effect47.fail(invalid)),
6905
+ Effect47.asVoid
6265
6906
  );
6266
6907
  }
6267
6908
  function readRefTarget(git, directory, revision) {
@@ -6270,7 +6911,7 @@ function readRefTarget(git, directory, revision) {
6270
6911
  directory,
6271
6912
  ["rev-parse", "--verify", "--quiet", revision],
6272
6913
  { ...refCommand, exitCodes: [0, 1] }
6273
- ).pipe(Effect43.map((output) => output.trim() || void 0));
6914
+ ).pipe(Effect47.map((output) => output.trim() || void 0));
6274
6915
  }
6275
6916
 
6276
6917
  // src/apps/server/features/repository-reflog/repository-reflog.ts
@@ -6293,8 +6934,8 @@ function repositoryReflogFeature(dependencies) {
6293
6934
  };
6294
6935
  }
6295
6936
  function readReflog(git, { worktreePath, ref }) {
6296
- return Effect44.gen(function* () {
6297
- let [output, tips] = yield* Effect44.all(
6937
+ return Effect48.gen(function* () {
6938
+ let [output, tips] = yield* Effect48.all(
6298
6939
  [
6299
6940
  readReflogOutput(git, worktreePath, ref),
6300
6941
  runRepositoryGit(
@@ -6339,20 +6980,20 @@ function readReflogOutput(git, directory, ref) {
6339
6980
  ],
6340
6981
  { maxOutputBytes: 8 * 1048576 }
6341
6982
  ).pipe(
6342
- Effect44.catchIf(
6983
+ Effect48.catchIf(
6343
6984
  (error) => /does not have any commits yet/i.test(error.detail),
6344
- () => Effect44.succeed("")
6985
+ () => Effect48.succeed("")
6345
6986
  )
6346
6987
  );
6347
6988
  }
6348
6989
  function readOrphaned(git, directory, oids, tips) {
6349
- return oids.length === 0 ? Effect44.succeed(/* @__PURE__ */ new Set()) : runRepositoryGit(git, directory, ["rev-list", "--stdin"], {
6990
+ return oids.length === 0 ? Effect48.succeed(/* @__PURE__ */ new Set()) : runRepositoryGit(git, directory, ["rev-list", "--stdin"], {
6350
6991
  input: `${[...oids, ...tips.map((tip) => `^${tip}`)].join(`
6351
6992
  `)}
6352
6993
  `,
6353
6994
  maxOutputBytes: 64 * 1048576
6354
6995
  }).pipe(
6355
- Effect44.map((output) => {
6996
+ Effect48.map((output) => {
6356
6997
  let candidates = new Set(oids);
6357
6998
  return new Set(
6358
6999
  output.split(`
@@ -6363,10 +7004,10 @@ function readOrphaned(git, directory, oids, tips) {
6363
7004
  }
6364
7005
  function resetToCommit(git, command) {
6365
7006
  let { worktreePath, target, mode, expectedHead, discard } = command;
6366
- return Effect44.gen(function* () {
7007
+ return Effect48.gen(function* () {
6367
7008
  let head = yield* readRefTarget(git, worktreePath, "HEAD");
6368
7009
  if (head !== expectedHead)
6369
- return yield* Effect44.fail({
7010
+ return yield* Effect48.fail({
6370
7011
  _tag: "HeadMoved",
6371
7012
  head: head ?? null
6372
7013
  });
@@ -6375,7 +7016,7 @@ function resetToCommit(git, command) {
6375
7016
  worktreePath,
6376
7017
  `${target}^{commit}`
6377
7018
  );
6378
- return commit === void 0 ? yield* Effect44.fail({
7019
+ return commit === void 0 ? yield* Effect48.fail({
6379
7020
  _tag: "RefMissing",
6380
7021
  name: target
6381
7022
  }) : (mode === "hard" && (yield* requireDiscardConfirmed(git, worktreePath, commit, discard)), yield* runRepositoryGit(
@@ -6387,7 +7028,7 @@ function resetToCommit(git, command) {
6387
7028
  });
6388
7029
  }
6389
7030
  function requireDiscardConfirmed(git, directory, target, discard) {
6390
- return Effect44.gen(function* () {
7031
+ return Effect48.gen(function* () {
6391
7032
  let records = (yield* runRepositoryGit(
6392
7033
  git,
6393
7034
  directory,
@@ -6409,7 +7050,7 @@ function requireDiscardConfirmed(git, directory, target, discard) {
6409
7050
  if (paths.length === 0) return;
6410
7051
  let fingerprint2 = createHash3("sha256").update(paths.join("\0")).digest("hex");
6411
7052
  if (discard !== fingerprint2)
6412
- return yield* Effect44.fail({
7053
+ return yield* Effect48.fail({
6413
7054
  _tag: "ResetDiscardsChanges",
6414
7055
  paths: paths.slice(0, listedDiscards),
6415
7056
  count: paths.length,
@@ -6424,7 +7065,7 @@ function readOverwrittenUntracked(git, directory, target, untracked) {
6424
7065
  ["diff", "--name-only", "-z", "--no-renames", "HEAD", target],
6425
7066
  { maxOutputBytes: 64 * 1048576 }
6426
7067
  ).pipe(
6427
- Effect44.map((output) => {
7068
+ Effect48.map((output) => {
6428
7069
  let changed = new Set(output.split("\0"));
6429
7070
  return untracked.filter((path) => changed.has(path));
6430
7071
  })
@@ -6432,7 +7073,7 @@ function readOverwrittenUntracked(git, directory, target, untracked) {
6432
7073
  }
6433
7074
 
6434
7075
  // src/apps/server/features/repository-refs/repository-refs.feature.ts
6435
- import { Effect as Effect52 } from "effect";
7076
+ import { Effect as Effect56 } from "effect";
6436
7077
 
6437
7078
  // src/apps/server/features/repository-refs/git/branches/branch-failures.ts
6438
7079
  function branchWriteFailed(error, name) {
@@ -6449,7 +7090,7 @@ function branchWriteFailed(error, name) {
6449
7090
  }
6450
7091
 
6451
7092
  // src/apps/server/features/repository-refs/git/branches/branch-git.ts
6452
- import { Effect as Effect45 } from "effect";
7093
+ import { Effect as Effect49 } from "effect";
6453
7094
 
6454
7095
  // src/apps/server/features/repository-refs/git/parse-for-each-ref.ts
6455
7096
  var forEachRefFormat = [
@@ -6530,7 +7171,12 @@ function tagFromRecord(record) {
6530
7171
  if (!record.name.startsWith(tagPrefix))
6531
7172
  return;
6532
7173
  let target = record.objectType === "commit" ? record.commit : record.peeledObjectType === "commit" ? record.peeledObject : void 0;
6533
- return target === void 0 ? void 0 : { name: record.name.slice(tagPrefix.length), target };
7174
+ if (target !== void 0)
7175
+ return {
7176
+ name: record.name.slice(tagPrefix.length),
7177
+ target,
7178
+ ...record.objectType === "tag" ? { object: record.commit } : {}
7179
+ };
6534
7180
  }
6535
7181
  function parseTracking(track) {
6536
7182
  return {
@@ -6553,20 +7199,20 @@ function requireValidBranchName(git, directory, name) {
6553
7199
  _tag: "InvalidBranchName",
6554
7200
  name
6555
7201
  };
6556
- return name.startsWith("-") || name === "HEAD" ? Effect45.fail(invalid) : requireValidRefName(git, directory, branchRef(name), invalid);
7202
+ return name.startsWith("-") || name === "HEAD" ? Effect49.fail(invalid) : requireValidRefName(git, directory, branchRef(name), invalid);
6557
7203
  }
6558
7204
  function readBranchTarget(git, directory, name) {
6559
7205
  return readRefTarget(git, directory, `${branchRef(name)}^{commit}`);
6560
7206
  }
6561
7207
  function requireBranchTarget(git, directory, name, expectedTarget) {
6562
7208
  return readBranchTarget(git, directory, name).pipe(
6563
- Effect45.flatMap((target) => target === void 0 ? Effect45.fail({
7209
+ Effect49.flatMap((target) => target === void 0 ? Effect49.fail({
6564
7210
  _tag: "RefMissing",
6565
7211
  name
6566
- }) : expectedTarget !== void 0 && target !== expectedTarget ? Effect45.fail({
7212
+ }) : expectedTarget !== void 0 && target !== expectedTarget ? Effect49.fail({
6567
7213
  _tag: "BranchMoved",
6568
7214
  name
6569
- }) : Effect45.succeed(target))
7215
+ }) : Effect49.succeed(target))
6570
7216
  );
6571
7217
  }
6572
7218
  function worktreeHolding(worktrees, name) {
@@ -6579,7 +7225,7 @@ function readLocalBranch(git, directory, worktrees, name) {
6579
7225
  ["for-each-ref", `--format=${forEachRefFormat}`, branchRef(name)],
6580
7226
  refCommand
6581
7227
  ).pipe(
6582
- Effect45.map((output) => {
7228
+ Effect49.map((output) => {
6583
7229
  let record = parseForEachRef(output).find(
6584
7230
  (candidate) => candidate.name === branchRef(name)
6585
7231
  ), { worktreePath: _raw, ...branch } = (record === void 0 ? void 0 : localBranchFromRecord(record)) ?? { name }, holder = worktreeHolding(worktrees, name);
@@ -6602,19 +7248,19 @@ function requireRemoteBranch(git, directory, upstream) {
6602
7248
  ["rev-parse", "--verify", "--quiet", `refs/remotes/${name}`],
6603
7249
  refCommand
6604
7250
  ).pipe(
6605
- Effect45.mapError(
7251
+ Effect49.mapError(
6606
7252
  (error) => isGitRejection(error) ? { _tag: "RefMissing", name } : branchWriteFailed(error, name)
6607
7253
  ),
6608
- Effect45.asVoid
7254
+ Effect49.asVoid
6609
7255
  );
6610
7256
  }
6611
7257
 
6612
7258
  // src/apps/server/features/repository-refs/git/branches/delete-branch.ts
6613
- import { Effect as Effect46 } from "effect";
7259
+ import { Effect as Effect50 } from "effect";
6614
7260
  var listedCommits = 20, pushCommand = { literalPathspecs: !1, timeoutMilliseconds: 12e4 };
6615
7261
  function deleteBranch(git, access, command) {
6616
7262
  let { force, local, remote, worktreePath } = command;
6617
- return Effect46.gen(function* () {
7263
+ return Effect50.gen(function* () {
6618
7264
  return local !== void 0 && (yield* requireDeletableLocal(git, access, worktreePath, local)), remote !== void 0 && (yield* requireRemoteTarget(git, worktreePath, remote)), force || (yield* rejectUnmergedCommits(git, worktreePath, command)), remote !== void 0 && (yield* deleteRemote(git, worktreePath, remote)), local !== void 0 && (yield* deleteLocal(git, worktreePath, local)), {
6619
7265
  ...local === void 0 ? {} : { local },
6620
7266
  ...remote === void 0 ? {} : { remote }
@@ -6622,10 +7268,10 @@ function deleteBranch(git, access, command) {
6622
7268
  });
6623
7269
  }
6624
7270
  function requireDeletableLocal(git, access, worktreePath, { name, target }) {
6625
- return Effect46.gen(function* () {
7271
+ return Effect50.gen(function* () {
6626
7272
  let holder = worktreeHolding(yield* access.worktrees(worktreePath), name);
6627
7273
  if (holder !== void 0)
6628
- return yield* Effect46.fail({
7274
+ return yield* Effect50.fail({
6629
7275
  _tag: "BranchCheckedOutElsewhere",
6630
7276
  name,
6631
7277
  worktreePath: holder.path
@@ -6640,14 +7286,14 @@ function deleteLocal(git, directory, { name, target }) {
6640
7286
  ["update-ref", "-d", branchRef(name), target],
6641
7287
  refCommand
6642
7288
  ).pipe(
6643
- Effect46.catchIf(
7289
+ Effect50.catchIf(
6644
7290
  isGitRejection,
6645
- () => Effect46.fail({
7291
+ () => Effect50.fail({
6646
7292
  _tag: "BranchMoved",
6647
7293
  name
6648
7294
  })
6649
7295
  ),
6650
- Effect46.andThen(
7296
+ Effect50.andThen(
6651
7297
  runRepositoryGit(
6652
7298
  git,
6653
7299
  directory,
@@ -6655,7 +7301,7 @@ function deleteLocal(git, directory, { name, target }) {
6655
7301
  { ...refCommand, exitCodes: [0, 1, 128] }
6656
7302
  )
6657
7303
  ),
6658
- Effect46.asVoid
7304
+ Effect50.asVoid
6659
7305
  );
6660
7306
  }
6661
7307
  function requireRemoteTarget(git, directory, remote) {
@@ -6666,12 +7312,12 @@ function requireRemoteTarget(git, directory, remote) {
6666
7312
  ["rev-parse", "--verify", "--quiet", `refs/remotes/${name}^{commit}`],
6667
7313
  { ...refCommand, exitCodes: [0, 1] }
6668
7314
  ).pipe(
6669
- Effect46.flatMap((output) => {
7315
+ Effect50.flatMap((output) => {
6670
7316
  let target = output.trim();
6671
- return target.length === 0 ? Effect46.fail({
7317
+ return target.length === 0 ? Effect50.fail({
6672
7318
  _tag: "RefMissing",
6673
7319
  name
6674
- }) : target === remote.target ? Effect46.void : Effect46.fail({
7320
+ }) : target === remote.target ? Effect50.void : Effect50.fail({
6675
7321
  _tag: "BranchMoved",
6676
7322
  name
6677
7323
  });
@@ -6690,7 +7336,7 @@ function rejectUnmergedCommits(git, directory, { local, remote }) {
6690
7336
  "--remotes",
6691
7337
  "--tags"
6692
7338
  ];
6693
- return Effect46.all(
7339
+ return Effect50.all(
6694
7340
  {
6695
7341
  count: runRepositoryGit(
6696
7342
  git,
@@ -6712,9 +7358,9 @@ function rejectUnmergedCommits(git, directory, { local, remote }) {
6712
7358
  },
6713
7359
  { concurrency: "unbounded" }
6714
7360
  ).pipe(
6715
- Effect46.flatMap(({ count, log }) => {
7361
+ Effect50.flatMap(({ count, log }) => {
6716
7362
  let unmerged = Number.parseInt(count.trim(), 10);
6717
- return unmerged === 0 ? Effect46.void : Effect46.fail({
7363
+ return unmerged === 0 ? Effect50.void : Effect50.fail({
6718
7364
  _tag: "BranchNotMerged",
6719
7365
  commits: parseCommits(log),
6720
7366
  count: unmerged,
@@ -6736,8 +7382,8 @@ function deleteRemote(git, directory, remote) {
6736
7382
  ],
6737
7383
  pushCommand
6738
7384
  ).pipe(
6739
- Effect46.asVoid,
6740
- Effect46.mapError(
7385
+ Effect50.asVoid,
7386
+ Effect50.mapError(
6741
7387
  (error) => isGitRejection(error) && /stale info|fetch first/i.test(error.detail) ? { _tag: "BranchMoved", name: remoteLabel(remote) } : branchWriteFailed(error, remoteLabel(remote))
6742
7388
  )
6743
7389
  );
@@ -6757,10 +7403,10 @@ function isDefined(value) {
6757
7403
  }
6758
7404
 
6759
7405
  // src/apps/server/features/repository-refs/git/branches/rename-branch.ts
6760
- import { Effect as Effect47 } from "effect";
7406
+ import { Effect as Effect51 } from "effect";
6761
7407
  function renameBranch(git, access, command) {
6762
7408
  let { name, newName, worktreePath } = command;
6763
- return Effect47.gen(function* () {
7409
+ return Effect51.gen(function* () {
6764
7410
  yield* requireValidBranchName(git, worktreePath, newName);
6765
7411
  let before = yield* access.worktrees(worktreePath);
6766
7412
  yield* rejectHeldElsewhere(before, name, worktreePath), yield* requireRenameSource(git, command, before), yield* runRepositoryGit(
@@ -6768,17 +7414,17 @@ function renameBranch(git, access, command) {
6768
7414
  worktreePath,
6769
7415
  ["branch", "-m", name, newName],
6770
7416
  refCommand
6771
- ).pipe(Effect47.mapError((error) => branchWriteFailed(error, newName)));
7417
+ ).pipe(Effect51.mapError((error) => branchWriteFailed(error, newName)));
6772
7418
  let after = yield* access.worktrees(worktreePath);
6773
7419
  return { branch: yield* readLocalBranch(git, worktreePath, after, newName), previousName: name };
6774
7420
  });
6775
7421
  }
6776
7422
  function requireRenameSource(git, { expectedTarget, name, worktreePath }, worktrees) {
6777
7423
  return readBranchTarget(git, worktreePath, name).pipe(
6778
- Effect47.flatMap((target) => target !== void 0 ? target === expectedTarget ? Effect47.void : Effect47.fail({
7424
+ Effect51.flatMap((target) => target !== void 0 ? target === expectedTarget ? Effect51.void : Effect51.fail({
6779
7425
  _tag: "BranchMoved",
6780
7426
  name
6781
- }) : expectedTarget === void 0 && worktreeHolding(worktrees, name)?.path === worktreePath ? Effect47.void : Effect47.fail({
7427
+ }) : expectedTarget === void 0 && worktreeHolding(worktrees, name)?.path === worktreePath ? Effect51.void : Effect51.fail({
6782
7428
  _tag: "RefMissing",
6783
7429
  name
6784
7430
  }))
@@ -6786,7 +7432,7 @@ function requireRenameSource(git, { expectedTarget, name, worktreePath }, worktr
6786
7432
  }
6787
7433
  function rejectHeldElsewhere(worktrees, name, worktreePath) {
6788
7434
  let holder = worktreeHolding(worktrees, name);
6789
- return holder === void 0 || holder.path === worktreePath ? Effect47.void : Effect47.fail({
7435
+ return holder === void 0 || holder.path === worktreePath ? Effect51.void : Effect51.fail({
6790
7436
  _tag: "BranchCheckedOutElsewhere",
6791
7437
  name,
6792
7438
  worktreePath: holder.path
@@ -6795,13 +7441,13 @@ function rejectHeldElsewhere(worktrees, name, worktreePath) {
6795
7441
 
6796
7442
  // src/apps/server/features/repository-refs/git/checkout-repository-ref.ts
6797
7443
  import { randomUUID as randomUUID5 } from "node:crypto";
6798
- import { Effect as Effect48 } from "effect";
7444
+ import { Effect as Effect52 } from "effect";
6799
7445
  var checkoutCommand = {
6800
7446
  literalPathspecs: !1,
6801
7447
  timeoutMilliseconds: 6e4
6802
7448
  };
6803
7449
  function checkoutRepositoryRef(git, access, command) {
6804
- return Effect48.gen(function* () {
7450
+ return Effect52.gen(function* () {
6805
7451
  let worktrees = yield* access.worktrees(command.worktreePath), worktree = yield* requireWorktree(worktrees, command.worktreePath), target = yield* resolveTarget(git, worktree.path, command.target);
6806
7452
  if (yield* rejectBranchCheckedOutElsewhere(worktrees, worktree, target), target._tag === "LocalBranch" && worktree.head.branch === target.name)
6807
7453
  return {
@@ -6809,18 +7455,18 @@ function checkoutRepositoryRef(git, access, command) {
6809
7455
  stash: "none",
6810
7456
  worktreePath: worktree.path
6811
7457
  };
6812
- let stash = yield* Effect48.uninterruptible(
7458
+ let stash = yield* Effect52.uninterruptible(
6813
7459
  checkoutWithAutoStash(git, worktree.path, target)
6814
7460
  );
6815
7461
  return { head: yield* readCheckedOutHead(access, worktree.path), stash, worktreePath: worktree.path };
6816
7462
  });
6817
7463
  }
6818
7464
  function checkoutWithAutoStash(git, directory, target) {
6819
- return Effect48.gen(function* () {
7465
+ return Effect52.gen(function* () {
6820
7466
  let stash = yield* stashLocalChanges(git, directory, target);
6821
7467
  return stash === void 0 ? (yield* runCheckout(git, directory, target), "none") : (yield* runCheckout(git, directory, target).pipe(
6822
- Effect48.tapError(
6823
- () => restoreStash(git, directory, stash).pipe(Effect48.ignore)
7468
+ Effect52.tapError(
7469
+ () => restoreStash(git, directory, stash).pipe(Effect52.ignore)
6824
7470
  )
6825
7471
  ), (yield* restoreStash(git, directory, stash)) ? "restored" : "kept");
6826
7472
  });
@@ -6829,15 +7475,15 @@ function requireWorktree(worktrees, worktreePath) {
6829
7475
  let worktree = worktrees.find(
6830
7476
  (candidate) => candidate.path === worktreePath
6831
7477
  );
6832
- return worktree === void 0 ? Effect48.fail(
7478
+ return worktree === void 0 ? Effect52.fail(
6833
7479
  repositoryRejected(
6834
7480
  "Missing",
6835
7481
  "This worktree does not belong to the repository."
6836
7482
  )
6837
- ) : Effect48.succeed(worktree);
7483
+ ) : Effect52.succeed(worktree);
6838
7484
  }
6839
7485
  function resolveTarget(git, directory, target) {
6840
- return target._tag !== "RemoteBranch" ? Effect48.succeed(target) : Effect48.gen(function* () {
7486
+ return target._tag !== "RemoteBranch" ? Effect52.succeed(target) : Effect52.gen(function* () {
6841
7487
  if (!(yield* gitAccepts(git, directory, [
6842
7488
  "show-ref",
6843
7489
  "--verify",
@@ -6850,8 +7496,8 @@ function resolveTarget(git, directory, target) {
6850
7496
  ["rev-parse", "--abbrev-ref", "--quiet", `${target.name}@{upstream}`],
6851
7497
  checkoutCommand
6852
7498
  ).pipe(
6853
- Effect48.map((upstream) => upstream.trim()),
6854
- Effect48.catchIf(isGitRejection, () => Effect48.succeed(""))
7499
+ Effect52.map((upstream) => upstream.trim()),
7500
+ Effect52.catchIf(isGitRejection, () => Effect52.succeed(""))
6855
7501
  );
6856
7502
  return tracked.length === 0 || tracked === `${target.remote}/${target.name}` ? { _tag: "LocalBranch", name: target.name } : {
6857
7503
  _tag: "DetachedRemoteBranch",
@@ -6861,25 +7507,25 @@ function resolveTarget(git, directory, target) {
6861
7507
  });
6862
7508
  }
6863
7509
  function rejectBranchCheckedOutElsewhere(worktrees, worktree, target) {
6864
- if (target._tag !== "LocalBranch") return Effect48.void;
7510
+ if (target._tag !== "LocalBranch") return Effect52.void;
6865
7511
  let elsewhere = worktrees.find(
6866
7512
  (candidate) => candidate.path !== worktree.path && candidate.head.branch === target.name
6867
7513
  );
6868
- return elsewhere === void 0 ? Effect48.void : Effect48.fail({
7514
+ return elsewhere === void 0 ? Effect52.void : Effect52.fail({
6869
7515
  _tag: "BranchCheckedOutElsewhere",
6870
7516
  name: target.name,
6871
7517
  worktreePath: elsewhere.path
6872
7518
  });
6873
7519
  }
6874
7520
  function stashLocalChanges(git, directory, target) {
6875
- return Effect48.gen(function* () {
7521
+ return Effect52.gen(function* () {
6876
7522
  if ((yield* runRepositoryGit(
6877
7523
  git,
6878
7524
  directory,
6879
7525
  ["status", "--porcelain", "-z"],
6880
7526
  checkoutCommand
6881
- ).pipe(Effect48.mapError((error) => checkoutFailure(error, target.name)))).length === 0) return;
6882
- let token = `rebase-auto-stash:${randomUUID5()}`, stashFailure = yield* runRepositoryGit(
7527
+ ).pipe(Effect52.mapError((error) => checkoutFailure(error, target.name)))).length === 0) return;
7528
+ let token = `rebase-auto-stash:${randomUUID5()}`, stashed = yield* runRepositoryGit(
6883
7529
  git,
6884
7530
  directory,
6885
7531
  [
@@ -6891,12 +7537,11 @@ function stashLocalChanges(git, directory, target) {
6891
7537
  ],
6892
7538
  checkoutCommand
6893
7539
  ).pipe(
6894
- Effect48.as(""),
6895
- Effect48.catchIf(isGitRejection, (error) => Effect48.succeed(error.detail))
7540
+ Effect52.as(!0),
7541
+ Effect52.catchIf(isGitRejection, () => Effect52.succeed(!1))
6896
7542
  ), entry = yield* findStash(git, directory, token);
6897
- return stashFailure !== "" || entry === void 0 ? yield* Effect48.fail({
7543
+ return !stashed || entry === void 0 ? yield* Effect52.fail({
6898
7544
  _tag: "CheckoutRejected",
6899
- detail: stashFailure,
6900
7545
  reason: "StashFailed"
6901
7546
  }) : token;
6902
7547
  });
@@ -6908,7 +7553,7 @@ function findStash(git, directory, token) {
6908
7553
  ["stash", "list", "--format=%H%x00%s"],
6909
7554
  checkoutCommand
6910
7555
  ).pipe(
6911
- Effect48.map((listed) => {
7556
+ Effect52.map((listed) => {
6912
7557
  let lines = listed.split(`
6913
7558
  `), index2 = lines.findIndex(
6914
7559
  (line) => line.split("\0")[1]?.includes(token)
@@ -6924,8 +7569,8 @@ function runCheckout(git, directory, target) {
6924
7569
  checkoutArguments(target),
6925
7570
  checkoutCommand
6926
7571
  ).pipe(
6927
- Effect48.asVoid,
6928
- Effect48.mapError((error) => checkoutFailure(error, target.name))
7572
+ Effect52.asVoid,
7573
+ Effect52.mapError((error) => checkoutFailure(error, target.name))
6929
7574
  );
6930
7575
  }
6931
7576
  function checkoutArguments(target) {
@@ -6951,7 +7596,7 @@ function checkoutArguments(target) {
6951
7596
  }
6952
7597
  }
6953
7598
  function restoreStash(git, directory, token) {
6954
- return Effect48.gen(function* () {
7599
+ return Effect52.gen(function* () {
6955
7600
  let entry = yield* findStash(git, directory, token);
6956
7601
  if (entry === void 0 || !(yield* gitAccepts(git, directory, [
6957
7602
  "stash",
@@ -6968,14 +7613,14 @@ function restoreStash(git, directory, token) {
6968
7613
  }
6969
7614
  function readCheckedOutHead(access, worktreePath) {
6970
7615
  return access.worktrees(worktreePath).pipe(
6971
- Effect48.flatMap((worktrees) => requireWorktree(worktrees, worktreePath)),
6972
- Effect48.map((worktree) => worktree.head)
7616
+ Effect52.flatMap((worktrees) => requireWorktree(worktrees, worktreePath)),
7617
+ Effect52.map((worktree) => worktree.head)
6973
7618
  );
6974
7619
  }
6975
7620
  function gitAccepts(git, directory, args) {
6976
7621
  return runRepositoryGit(git, directory, args, checkoutCommand).pipe(
6977
- Effect48.as(!0),
6978
- Effect48.catchIf(isGitRejection, () => Effect48.succeed(!1))
7622
+ Effect52.as(!0),
7623
+ Effect52.catchIf(isGitRejection, () => Effect52.succeed(!1))
6979
7624
  );
6980
7625
  }
6981
7626
  function checkoutFailure(error, targetName) {
@@ -6990,17 +7635,16 @@ function checkoutFailure(error, targetName) {
6990
7635
  error.detail
6991
7636
  ) ? { _tag: "RefMissing", name: targetName } : /would be overwritten by checkout/i.test(error.detail) ? {
6992
7637
  _tag: "CheckoutRejected",
6993
- detail: error.detail,
6994
7638
  reason: "LocalChanges"
6995
7639
  } : repositoryRejected("GitFailed", error.detail);
6996
7640
  }
6997
7641
 
6998
7642
  // src/apps/server/features/repository-refs/git/read-repository-refs.ts
6999
- import { Effect as Effect49 } from "effect";
7643
+ import { Effect as Effect53 } from "effect";
7000
7644
  var readTimeoutMilliseconds = 15e3, maximumRefsOutputBytes2 = 16 * 1048576;
7001
7645
  function readRepositoryRefs(git, repository) {
7002
- return Effect49.gen(function* () {
7003
- let output = yield* Effect49.all(
7646
+ return Effect53.gen(function* () {
7647
+ let output = yield* Effect53.all(
7004
7648
  {
7005
7649
  branches: listRefs(
7006
7650
  git,
@@ -7051,7 +7695,7 @@ function listRefs(git, directory, pattern, sort) {
7051
7695
  maxOutputBytes: maximumRefsOutputBytes2,
7052
7696
  timeoutMilliseconds: readTimeoutMilliseconds
7053
7697
  }
7054
- ).pipe(Effect49.map(parseForEachRef));
7698
+ ).pipe(Effect53.map(parseForEachRef));
7055
7699
  }
7056
7700
  function canonicalizeBranchWorktrees(branches, rawWorktrees, canonicalWorktrees) {
7057
7701
  let canonicalByRawPath = new Map(
@@ -7080,12 +7724,12 @@ function readRemoteMetadata(git, directory) {
7080
7724
  ["config", "--get-regexp", "^remote\\..*\\.url$"],
7081
7725
  { timeoutMilliseconds: 5e3, maxOutputBytes: 65536 }
7082
7726
  ).pipe(
7083
- Effect49.map((remotes) => ({
7727
+ Effect53.map((remotes) => ({
7084
7728
  githubRepository: githubRepositoryFromRemotes(remotes),
7085
7729
  remoteProviders: remoteProvidersFromConfig(remotes)
7086
7730
  })),
7087
- Effect49.catch(
7088
- () => Effect49.succeed({ githubRepository: void 0, remoteProviders: [] })
7731
+ Effect53.catch(
7732
+ () => Effect53.succeed({ githubRepository: void 0, remoteProviders: [] })
7089
7733
  )
7090
7734
  );
7091
7735
  }
@@ -7146,88 +7790,165 @@ function fitRepositoryRefs(refs) {
7146
7790
  }
7147
7791
 
7148
7792
  // src/apps/server/features/repository-refs/git/repository-tags.ts
7149
- import { Effect as Effect50 } from "effect";
7150
- function createTag(git, { name, target, worktreePath }) {
7151
- return Effect50.gen(function* () {
7152
- return yield* requireValidTagName(git, worktreePath, name), yield* runRepositoryGit(
7793
+ import { Effect as Effect54 } from "effect";
7794
+ var pushCommand2 = { literalPathspecs: !1, timeoutMilliseconds: 12e4 };
7795
+ function createTag(git, { name, target, message, worktreePath }) {
7796
+ return Effect54.gen(function* () {
7797
+ if (yield* requireValidTagName(git, worktreePath, name), message === void 0)
7798
+ return yield* requireUnsignedTagsAllowed(git, worktreePath), yield* runRepositoryGit(
7799
+ git,
7800
+ worktreePath,
7801
+ ["tag", "--no-sign", name, target],
7802
+ refCommand
7803
+ ).pipe(Effect54.mapError(tagWriteFailed)), { name, target };
7804
+ yield* runRepositoryGit(
7153
7805
  git,
7154
7806
  worktreePath,
7155
- ["tag", "--no-sign", name, target],
7156
- refCommand
7157
- ).pipe(Effect50.mapError(tagWriteFailed)), { name, target };
7807
+ ["tag", "--annotate", "--file=-", name, target],
7808
+ { ...refCommand, input: message }
7809
+ ).pipe(Effect54.mapError(tagWriteFailed));
7810
+ let object = yield* readRefTarget(git, worktreePath, tagRef(name));
7811
+ return object === void 0 ? { name, target } : { name, target, object };
7158
7812
  });
7159
7813
  }
7160
- function deleteTag(git, { name, worktreePath }) {
7161
- return Effect50.gen(function* () {
7162
- let target = yield* requireTagTarget(git, worktreePath, name);
7163
- return yield* runRepositoryGit(
7814
+ function deleteTag(git, { name, local, remote, worktreePath }) {
7815
+ return Effect54.gen(function* () {
7816
+ return local !== void 0 && (yield* requireTagObject(git, worktreePath, name)), remote !== void 0 && (yield* runRepositoryGit(
7817
+ git,
7818
+ worktreePath,
7819
+ [
7820
+ "push",
7821
+ `--force-with-lease=${tagRef(name)}:${remote.object}`,
7822
+ remote.remote,
7823
+ "--delete",
7824
+ tagRef(name)
7825
+ ],
7826
+ pushCommand2
7827
+ ).pipe(
7828
+ Effect54.catchIf(
7829
+ (error) => isGitRejection(error) && /stale info/.test(error.detail),
7830
+ () => Effect54.fail(tagRejected("RemoteDiffers"))
7831
+ )
7832
+ )), local !== void 0 && (yield* runRepositoryGit(
7164
7833
  git,
7165
7834
  worktreePath,
7166
- ["tag", "--delete", "--", name],
7835
+ ["update-ref", "-d", tagRef(name), local.object],
7167
7836
  refCommand
7168
- ), { name, target };
7837
+ ).pipe(
7838
+ Effect54.catchIf(isGitRejection, () => Effect54.fail(tagRejected("Moved")))
7839
+ )), { name };
7169
7840
  });
7170
7841
  }
7842
+ function readTagAnnotation(git, { name, worktreePath }) {
7843
+ return runRepositoryGit(
7844
+ git,
7845
+ worktreePath,
7846
+ [
7847
+ "for-each-ref",
7848
+ "--count=1",
7849
+ "--sort=refname",
7850
+ `--format=${[
7851
+ "%(refname)",
7852
+ "%(objecttype)",
7853
+ "%(objectname)",
7854
+ "%(*objectname)",
7855
+ "%(taggername)",
7856
+ "%(taggerdate:iso-strict)",
7857
+ "%(contents:signature)",
7858
+ "%(contents)"
7859
+ ].join("%00")}`,
7860
+ tagRef(name)
7861
+ ],
7862
+ refCommand
7863
+ ).pipe(
7864
+ Effect54.flatMap((output) => {
7865
+ let record = output.replace(/\n$/, "").split("\0"), [refname, type, object, target, tagger = "", date = ""] = record, signature = record[6] ?? "", contents = record.slice(7).join("\0");
7866
+ return refname !== tagRef(name) || type !== "tag" || object === void 0 || target === void 0 ? Effect54.fail({ _tag: "RefMissing", name }) : Effect54.succeed({
7867
+ name,
7868
+ object,
7869
+ target,
7870
+ tagger: { name: tagger.slice(0, 512), date: date.slice(0, 64) },
7871
+ message: (contents.endsWith(signature) && signature.length > 0 ? contents.slice(0, -signature.length) : contents).trimEnd().slice(0, 65536),
7872
+ signed: signature.length > 0
7873
+ });
7874
+ })
7875
+ );
7876
+ }
7171
7877
  function requireValidTagName(git, directory, name) {
7172
- let invalid = { _tag: "TagRejected", reason: "InvalidName" };
7173
- return name.startsWith("-") ? Effect50.fail(invalid) : requireValidRefName(git, directory, tagRef(name), invalid);
7878
+ let invalid = tagRejected("InvalidName");
7879
+ return name.startsWith("-") ? Effect54.fail(invalid) : requireValidRefName(git, directory, tagRef(name), invalid);
7174
7880
  }
7175
- function requireTagTarget(git, directory, name) {
7176
- return readRefTarget(git, directory, `${tagRef(name)}^{}`).pipe(
7177
- Effect50.flatMap(
7178
- (target) => target === void 0 ? Effect50.fail({ _tag: "RefMissing", name }) : Effect50.succeed(target)
7881
+ function requireUnsignedTagsAllowed(git, directory) {
7882
+ return runRepositoryGit(
7883
+ git,
7884
+ directory,
7885
+ ["config", "--type=bool", "--get", "tag.gpgSign"],
7886
+ { ...refCommand, exitCodes: [0, 1] }
7887
+ ).pipe(
7888
+ Effect54.flatMap(
7889
+ (value) => value.trim() === "true" ? Effect54.fail(tagRejected("MessageRequired")) : Effect54.void
7890
+ )
7891
+ );
7892
+ }
7893
+ function requireTagObject(git, directory, name) {
7894
+ return readRefTarget(git, directory, tagRef(name)).pipe(
7895
+ Effect54.flatMap(
7896
+ (object) => object === void 0 ? Effect54.fail({ _tag: "RefMissing", name }) : Effect54.void
7179
7897
  )
7180
7898
  );
7181
7899
  }
7182
7900
  function tagRef(name) {
7183
7901
  return `refs/tags/${name}`;
7184
7902
  }
7903
+ function tagRejected(reason) {
7904
+ return { _tag: "TagRejected", reason };
7905
+ }
7185
7906
  function tagWriteFailed(error) {
7186
- return isGitRejection(error) && /already exists/.test(error.detail) ? { _tag: "TagRejected", reason: "Exists" } : repositoryRejected("GitFailed", error.detail);
7907
+ return isGitRejection(error) && /already exists/.test(error.detail) ? tagRejected("Exists") : repositoryRejected("GitFailed", error.detail);
7187
7908
  }
7188
7909
 
7189
7910
  // src/apps/server/features/repository-refs/repository-change-publisher.ts
7190
- import { Effect as Effect51, Exit, Queue as Queue3, Scope, Semaphore as Semaphore2 } from "effect";
7911
+ import { Effect as Effect55, Exit, Queue as Queue3, Scope, Semaphore as Semaphore2 } from "effect";
7191
7912
  var maximumWatchedRepositories = 32;
7192
7913
  function acquireRepositoryChangePublisher(git, watcher, events) {
7193
- return Effect51.gen(function* () {
7194
- let scope = yield* Effect51.scope, mutex = yield* Semaphore2.make(1), watches = /* @__PURE__ */ new Map(), changed = /* @__PURE__ */ new Map(), pending = yield* Queue3.make({
7914
+ return Effect55.gen(function* () {
7915
+ let scope = yield* Effect55.scope, mutex = yield* Semaphore2.make(1), watches = /* @__PURE__ */ new Map(), changed = /* @__PURE__ */ new Map(), pending = yield* Queue3.make({
7195
7916
  capacity: 1,
7196
7917
  strategy: "dropping"
7197
7918
  }), closed = !1;
7198
- yield* Effect51.addFinalizer(
7199
- () => Effect51.sync(() => {
7919
+ yield* Effect55.addFinalizer(
7920
+ () => Effect55.sync(() => {
7200
7921
  closed = !0, watches.clear(), changed.clear();
7201
7922
  })
7202
7923
  ), yield* publishRepositoryChanges(pending, changed, events).pipe(
7203
- Effect51.forkScoped
7924
+ Effect55.forkScoped
7204
7925
  );
7205
- let register = (repositoryId, directory) => Effect51.gen(function* () {
7926
+ let register = (repositoryId, directory) => Effect55.gen(function* () {
7206
7927
  let oldest = watches.entries().next().value;
7207
7928
  watches.size >= maximumWatchedRepositories && oldest !== void 0 && (watches.delete(oldest[0]), yield* Scope.close(oldest[1], Exit.void));
7208
7929
  let owned = yield* Scope.fork(scope);
7209
- yield* Effect51.acquireRelease(
7930
+ yield* Effect55.acquireRelease(
7210
7931
  watcher.watch(directory, (kind) => {
7211
7932
  changed.get(repositoryId) !== "Refs" && changed.set(repositoryId, kind), Queue3.offerUnsafe(pending, void 0);
7212
7933
  }),
7213
- (handle) => Effect51.sync(handle.close)
7214
- ).pipe(Effect51.provideService(Scope.Scope, owned)), watches.set(repositoryId, owned);
7215
- }).pipe(Effect51.uninterruptible);
7934
+ (handle) => Effect55.sync(handle.close)
7935
+ ).pipe(Effect55.provideService(Scope.Scope, owned)), watches.set(repositoryId, owned);
7936
+ }).pipe(Effect55.uninterruptible);
7216
7937
  return {
7217
- watch: (repository) => Effect51.gen(function* () {
7938
+ watch: (repository) => Effect55.gen(function* () {
7218
7939
  if (closed || watches.has(repository.id)) return;
7219
7940
  let directory = yield* readGitCommonDirectory(
7220
7941
  git,
7221
7942
  repository.path,
7222
7943
  { timeoutMilliseconds: 5e3 }
7223
- ).pipe(Effect51.catch(() => Effect51.succeed(void 0)));
7944
+ ).pipe(Effect55.catch(() => Effect55.succeed(void 0)));
7224
7945
  closed || directory === void 0 || (yield* register(repository.id, directory));
7225
7946
  }).pipe(Semaphore2.withPermit(mutex))
7226
7947
  };
7227
7948
  });
7228
7949
  }
7229
7950
  function publishRepositoryChanges(pending, changed, events) {
7230
- return Effect51.gen(function* () {
7951
+ return Effect55.gen(function* () {
7231
7952
  for (; ; ) {
7232
7953
  yield* Queue3.take(pending), yield* Queue3.clear(pending);
7233
7954
  let batch = [...changed];
@@ -7253,16 +7974,16 @@ var branchPolicy = {
7253
7974
  duringOperation: "proceed"
7254
7975
  };
7255
7976
  function repositoryRefsFeature(dependencies) {
7256
- return Effect52.gen(function* () {
7257
- let { access, git } = dependencies, { command } = repositoryRoutes(dependencies), changes = yield* acquireRepositoryChangePublisher(
7977
+ return Effect56.gen(function* () {
7978
+ let { access, git } = dependencies, { command, query } = repositoryRoutes(dependencies), changes = yield* acquireRepositoryChangePublisher(
7258
7979
  git,
7259
7980
  dependencies.watcher,
7260
7981
  dependencies.events
7261
- ), readRefs = (repositoryId) => Effect52.gen(function* () {
7982
+ ), readRefs = (repositoryId) => Effect56.gen(function* () {
7262
7983
  let repository = yield* access.repository(repositoryId);
7263
7984
  return yield* changes.watch(repository), yield* readRepositoryRefs(git, repository);
7264
7985
  }).pipe(
7265
- Effect52.mapError(
7986
+ Effect56.mapError(
7266
7987
  (error) => error._tag === "RepositoryRejected" ? error : repositoryRejected(
7267
7988
  "GitFailed",
7268
7989
  error._tag === "GitFailed" ? error.detail : "The repository catalog is unavailable."
@@ -7310,6 +8031,10 @@ function repositoryRefsFeature(dependencies) {
7310
8031
  RepositoryTagsApi.delete,
7311
8032
  tagPolicy,
7312
8033
  (input, git2) => deleteTag(git2, input)
8034
+ ),
8035
+ query(
8036
+ RepositoryTagsApi.annotation,
8037
+ (input, git2) => readTagAnnotation(git2, input)
7313
8038
  )
7314
8039
  ]
7315
8040
  };
@@ -7317,14 +8042,14 @@ function repositoryRefsFeature(dependencies) {
7317
8042
  }
7318
8043
  function createBranch(git, access, command) {
7319
8044
  let { name, startPoint, track, worktreePath } = command;
7320
- return Effect52.gen(function* () {
8045
+ return Effect56.gen(function* () {
7321
8046
  yield* requireValidBranchName(git, worktreePath, name), track !== void 0 && (yield* requireRemoteBranch(git, worktreePath, track)), yield* runRepositoryGit(
7322
8047
  git,
7323
8048
  worktreePath,
7324
8049
  ["branch", "--no-track", name, startPoint],
7325
8050
  refCommand
7326
8051
  ).pipe(
7327
- Effect52.mapError(
8052
+ Effect56.mapError(
7328
8053
  (error) => /not a valid object name/i.test(error.detail) ? { _tag: "RefMissing", name: startPoint } : branchWriteFailed(error, name)
7329
8054
  )
7330
8055
  ), track !== void 0 && (yield* runRepositoryGit(
@@ -7332,20 +8057,20 @@ function createBranch(git, access, command) {
7332
8057
  worktreePath,
7333
8058
  setUpstreamArguments(name, track),
7334
8059
  refCommand
7335
- ).pipe(Effect52.mapError((error) => branchWriteFailed(error, name))));
8060
+ ).pipe(Effect56.mapError((error) => branchWriteFailed(error, name))));
7336
8061
  let worktrees = yield* access.worktrees(worktreePath);
7337
8062
  return yield* readLocalBranch(git, worktreePath, worktrees, name);
7338
8063
  });
7339
8064
  }
7340
8065
  function setBranchUpstream(git, access, command) {
7341
8066
  let { name, upstream, worktreePath } = command;
7342
- return Effect52.gen(function* () {
8067
+ return Effect56.gen(function* () {
7343
8068
  yield* requireBranchTarget(git, worktreePath, name, void 0), upstream === null ? yield* unsetUpstream(git, worktreePath, name) : (yield* requireRemoteBranch(git, worktreePath, upstream), yield* runRepositoryGit(
7344
8069
  git,
7345
8070
  worktreePath,
7346
8071
  setUpstreamArguments(name, upstream),
7347
8072
  refCommand
7348
- ).pipe(Effect52.mapError((error) => branchWriteFailed(error, name))));
8073
+ ).pipe(Effect56.mapError((error) => branchWriteFailed(error, name))));
7349
8074
  let worktrees = yield* access.worktrees(worktreePath);
7350
8075
  return yield* readLocalBranch(git, worktreePath, worktrees, name);
7351
8076
  });
@@ -7357,12 +8082,12 @@ function unsetUpstream(git, directory, name) {
7357
8082
  ["branch", "--unset-upstream", name],
7358
8083
  refCommand
7359
8084
  ).pipe(
7360
- Effect52.asVoid,
7361
- Effect52.catchIf(
8085
+ Effect56.asVoid,
8086
+ Effect56.catchIf(
7362
8087
  (error) => /has no upstream information/i.test(error.detail),
7363
- () => Effect52.void
8088
+ () => Effect56.void
7364
8089
  ),
7365
- Effect52.mapError((error) => branchWriteFailed(error, name))
8090
+ Effect56.mapError((error) => branchWriteFailed(error, name))
7366
8091
  );
7367
8092
  }
7368
8093
 
@@ -7370,13 +8095,13 @@ function unsetUpstream(git, directory, name) {
7370
8095
  import { randomUUID as randomUUID6 } from "node:crypto";
7371
8096
  import { eq as eq3 } from "drizzle-orm";
7372
8097
  import { drizzle as drizzle2 } from "drizzle-orm/node-sqlite";
7373
- import { Effect as Effect56, Semaphore as Semaphore3 } from "effect";
8098
+ import { Effect as Effect60, Semaphore as Semaphore3 } from "effect";
7374
8099
 
7375
8100
  // src/apps/server/persistence/sqlite/database.ts
7376
8101
  import { chmodSync } from "node:fs";
7377
8102
  import { DatabaseSync } from "node:sqlite";
7378
8103
  import { drizzle } from "drizzle-orm/node-sqlite";
7379
- import { Effect as Effect53, Schedule } from "effect";
8104
+ import { Effect as Effect57, Schedule } from "effect";
7380
8105
 
7381
8106
  // src/apps/server/persistence/sqlite/migrations.ts
7382
8107
  import { existsSync } from "node:fs";
@@ -7436,7 +8161,7 @@ function resolveMigrationsFolder() {
7436
8161
  // src/apps/server/persistence/sqlite/database.ts
7437
8162
  var busyTimeoutMilliseconds = 1e3, databaseLockRetryDelay = "10 millis", databaseLockRetryCount = 10;
7438
8163
  function openEnvironmentDatabase(paths) {
7439
- return Effect53.gen(function* () {
8164
+ return Effect57.gen(function* () {
7440
8165
  let database = yield* storageSync(
7441
8166
  "Could not open Environment state",
7442
8167
  () => new DatabaseSync(paths.stateDatabase, {
@@ -7445,7 +8170,7 @@ function openEnvironmentDatabase(paths) {
7445
8170
  timeout: busyTimeoutMilliseconds
7446
8171
  })
7447
8172
  );
7448
- return yield* Effect53.gen(function* () {
8173
+ return yield* Effect57.gen(function* () {
7449
8174
  return yield* storageSync(
7450
8175
  "Could not open Environment state",
7451
8176
  () => configureDatabase(database)
@@ -7453,11 +8178,11 @@ function openEnvironmentDatabase(paths) {
7453
8178
  "Could not open Environment state",
7454
8179
  () => restrictDatabasePermissions(paths.stateDatabase)
7455
8180
  ), database;
7456
- }).pipe(Effect53.onError(() => closeEnvironmentDatabase(database)));
8181
+ }).pipe(Effect57.onError(() => closeEnvironmentDatabase(database)));
7457
8182
  });
7458
8183
  }
7459
8184
  function closeEnvironmentDatabase(database) {
7460
- return Effect53.sync(() => database.close()).pipe(Effect53.orDie);
8185
+ return Effect57.sync(() => database.close()).pipe(Effect57.orDie);
7461
8186
  }
7462
8187
  function configureDatabase(database) {
7463
8188
  database.exec(`
@@ -7473,7 +8198,7 @@ function migrateDatabase(database) {
7473
8198
  }
7474
8199
  function retryDatabaseLock(effect) {
7475
8200
  return effect.pipe(
7476
- Effect53.retry({
8201
+ Effect57.retry({
7477
8202
  schedule: Schedule.spaced(databaseLockRetryDelay),
7478
8203
  times: databaseLockRetryCount,
7479
8204
  while: isDatabaseLocked
@@ -7499,19 +8224,19 @@ function restrictDatabasePermissions(path) {
7499
8224
 
7500
8225
  // src/apps/server/persistence/storage/environment-paths.ts
7501
8226
  import { chmod, mkdir as mkdir2 } from "node:fs/promises";
7502
- import { join as join8 } from "node:path";
7503
- import { Effect as Effect54 } from "effect";
8227
+ import { join as join9 } from "node:path";
8228
+ import { Effect as Effect58 } from "effect";
7504
8229
  function environmentPaths(root) {
7505
- let cacheDirectory = join8(root, "cache"), runtimeDirectory = join8(root, "runtime"), secretsDirectory = join8(root, "secrets"), settingsDirectory = join8(root, "settings"), stateDirectory = join8(root, "state");
8230
+ let cacheDirectory = join9(root, "cache"), runtimeDirectory = join9(root, "runtime"), secretsDirectory = join9(root, "secrets"), settingsDirectory = join9(root, "settings"), stateDirectory = join9(root, "state");
7506
8231
  return {
7507
8232
  cacheDirectory,
7508
8233
  root,
7509
8234
  runtimeDirectory,
7510
- runtimeMarker: join8(runtimeDirectory, "runtime.json"),
8235
+ runtimeMarker: join9(runtimeDirectory, "runtime.json"),
7511
8236
  secretsDirectory,
7512
- serverSecret: join8(secretsDirectory, "server.key"),
8237
+ serverSecret: join9(secretsDirectory, "server.key"),
7513
8238
  settingsDirectory,
7514
- stateDatabase: join8(stateDirectory, "state.sqlite"),
8239
+ stateDatabase: join9(stateDirectory, "state.sqlite"),
7515
8240
  stateDirectory
7516
8241
  };
7517
8242
  }
@@ -7524,7 +8249,7 @@ function prepareEnvironmentDirectories(paths) {
7524
8249
  paths.secretsDirectory,
7525
8250
  paths.cacheDirectory
7526
8251
  ];
7527
- return Effect54.tryPromise({
8252
+ return Effect58.tryPromise({
7528
8253
  try: async () => {
7529
8254
  for (let directory of directories)
7530
8255
  await mkdir2(directory, { mode: 448, recursive: !0 }), process.platform !== "win32" && await chmod(directory, 448);
@@ -7542,14 +8267,14 @@ import {
7542
8267
  chmod as chmod2,
7543
8268
  link,
7544
8269
  mkdtemp as mkdtemp2,
7545
- readFile as readFile4,
8270
+ readFile as readFile5,
7546
8271
  rm as rm4,
7547
8272
  writeFile as writeFile4
7548
8273
  } from "node:fs/promises";
7549
- import { join as join9 } from "node:path";
7550
- import { Effect as Effect55 } from "effect";
8274
+ import { join as join10 } from "node:path";
8275
+ import { Effect as Effect59 } from "effect";
7551
8276
  function ensureServerSecret(paths) {
7552
- return Effect55.tryPromise({
8277
+ return Effect59.tryPromise({
7553
8278
  try: () => readOrCreateServerSecret(paths.serverSecret),
7554
8279
  catch: (cause) => new EnvironmentStorageError({
7555
8280
  cause,
@@ -7560,7 +8285,7 @@ function ensureServerSecret(paths) {
7560
8285
  async function readOrCreateServerSecret(path) {
7561
8286
  let secret;
7562
8287
  try {
7563
- secret = await readFile4(path, "utf8");
8288
+ secret = await readFile5(path, "utf8");
7564
8289
  } catch (error) {
7565
8290
  if (!isMissingFile2(error))
7566
8291
  throw error;
@@ -7571,7 +8296,7 @@ async function readOrCreateServerSecret(path) {
7571
8296
  return process.platform !== "win32" && await chmod2(path, 384), secret.trim();
7572
8297
  }
7573
8298
  async function publishServerSecret(path) {
7574
- let directory = await mkdtemp2(`${path}.`), temporaryPath = join9(directory, "key"), generated = `${randomBytes2(32).toString("base64url")}
8299
+ let directory = await mkdtemp2(`${path}.`), temporaryPath = join10(directory, "key"), generated = `${randomBytes2(32).toString("base64url")}
7575
8300
  `;
7576
8301
  try {
7577
8302
  await writeFile4(temporaryPath, generated, { flag: "wx", mode: 384 });
@@ -7579,7 +8304,7 @@ async function publishServerSecret(path) {
7579
8304
  return await link(temporaryPath, path), generated;
7580
8305
  } catch (error) {
7581
8306
  if (!isExistingFile(error)) throw error;
7582
- return await readFile4(path, "utf8");
8307
+ return await readFile5(path, "utf8");
7583
8308
  }
7584
8309
  } finally {
7585
8310
  await rm4(directory, { recursive: !0, force: !0 });
@@ -7594,9 +8319,9 @@ function isExistingFile(error) {
7594
8319
 
7595
8320
  // src/apps/server/persistence/environment-context.ts
7596
8321
  function acquireEnvironmentContext(paths) {
7597
- return Effect56.gen(function* () {
8322
+ return Effect60.gen(function* () {
7598
8323
  yield* prepareEnvironmentDirectories(paths);
7599
- let serverSecret = yield* ensureServerSecret(paths), database = yield* Effect56.acquireRelease(
8324
+ let serverSecret = yield* ensureServerSecret(paths), database = yield* Effect60.acquireRelease(
7600
8325
  openEnvironmentDatabase(paths),
7601
8326
  closeEnvironmentDatabase
7602
8327
  ), context = yield* storageSync(
@@ -7627,19 +8352,20 @@ function initializeEnvironment(context) {
7627
8352
 
7628
8353
  // src/apps/server/repository/repository-coordination.ts
7629
8354
  import { realpath as realpath5 } from "node:fs/promises";
7630
- import { Effect as Effect58, Option as Option2, Semaphore as Semaphore4 } from "effect";
8355
+ import { Effect as Effect62, Option as Option2, Semaphore as Semaphore4 } from "effect";
7631
8356
 
7632
8357
  // src/apps/server/repository/repository-operation.ts
7633
8358
  import { createHash as createHash4 } from "node:crypto";
7634
- import { lstat as lstat3, readFile as readFile5, stat as stat5 } from "node:fs/promises";
7635
- import { join as join10 } from "node:path";
7636
- import { Effect as Effect57 } from "effect";
8359
+ import { lstat as lstat3, readFile as readFile6, stat as stat5 } from "node:fs/promises";
8360
+ import { join as join11 } from "node:path";
8361
+ import { Effect as Effect61 } from "effect";
7637
8362
  var maximumMetadataBytes = 2 * 1024 * 1024, metadataNames = [
7638
8363
  "HEAD",
7639
8364
  "MERGE_HEAD",
7640
8365
  "CHERRY_PICK_HEAD",
7641
8366
  "REVERT_HEAD",
7642
8367
  "MERGE_MSG",
8368
+ "SQUASH_MSG",
7643
8369
  "AUTO_MERGE",
7644
8370
  "rebase-merge/head-name",
7645
8371
  "rebase-merge/onto",
@@ -7668,23 +8394,23 @@ var maximumMetadataBytes = 2 * 1024 * 1024, metadataNames = [
7668
8394
  worktree: []
7669
8395
  };
7670
8396
  function readRepositoryOperation(git, worktreePath, directories) {
7671
- return Effect57.gen(function* () {
8397
+ return Effect61.gen(function* () {
7672
8398
  let { values, metadata, stamps } = yield* readOperationMetadata(
7673
8399
  directories.gitDirectory
7674
- ), lock = yield* readGitLock(directories), kind = identifyOperation(metadata, stamps), worktree = kind === "idle" ? idleWorktree : yield* inspectWorktree(git, worktreePath, directories.gitDirectory), unresolvedPaths = [
8400
+ ), lock = yield* readGitLock(directories), candidate = identifyOperation(metadata, stamps), worktree = candidate === "idle" ? idleWorktree : yield* inspectWorktree(git, worktreePath, directories.gitDirectory), unresolvedPaths = [
7675
8401
  ...new Set(
7676
8402
  worktree.unresolved.split("\0").filter(Boolean).map((line) => line.slice(line.indexOf(" ") + 1))
7677
8403
  )
7678
- ].sort(), edit = kind === "rebase" && metadata["rebase-merge/amend"] !== null && unresolvedPaths.length === 0, reason = blockedReason(
8404
+ ].sort(), kind = candidate === "squash" && unresolvedPaths.length === 0 ? "idle" : candidate, edit = kind === "rebase" && metadata["rebase-merge/amend"] !== null && unresolvedPaths.length === 0, empty = unresolvedPaths.length === 0 && (metadata.CHERRY_PICK_HEAD ?? metadata.REVERT_HEAD) !== null && !hasStagedChanges2(worktree.status), reason = empty ? lockedReason(lock) ?? "Nothing to commit. Skip this commit." : blockedReason(
7679
8405
  kind,
7680
8406
  lock,
7681
8407
  unresolvedPaths.length,
7682
8408
  edit,
7683
8409
  worktree.status
7684
- );
8410
+ ), steps = kind === "rebase" ? rebaseSteps(metadata) : null, progress = stepProgress(steps) ?? operationProgress(metadata) ?? (yield* sequenceProgress(git, worktreePath, metadata, worktree.head));
7685
8411
  return {
7686
8412
  kind,
7687
- phase: operationPhase(kind, unresolvedPaths.length, edit),
8413
+ phase: empty ? "empty" : operationPhase(kind, unresolvedPaths.length, edit),
7688
8414
  actions: availableActions(kind, metadata, stamps, edit, lock, reason),
7689
8415
  unresolvedPaths,
7690
8416
  lock,
@@ -7693,21 +8419,22 @@ function readRepositoryOperation(git, worktreePath, directories) {
7693
8419
  metadata["rebase-merge/head-name"] ?? metadata["rebase-apply/head-name"] ?? metadata.HEAD
7694
8420
  ),
7695
8421
  commit: (kind === "merge" ? metadata.MERGE_HEAD?.split(`
7696
- `)[0] : metadata["rebase-merge/stopped-sha"] ?? metadata["rebase-apply/original-commit"] ?? metadata.CHERRY_PICK_HEAD ?? metadata.REVERT_HEAD)?.trim() ?? null,
8422
+ `)[0] : kind === "squash" ? /^commit ([0-9a-f]+)$/m.exec(metadata.SQUASH_MSG ?? "")?.[1] : metadata["rebase-merge/stopped-sha"] ?? metadata["rebase-apply/original-commit"] ?? metadata.CHERRY_PICK_HEAD ?? metadata.REVERT_HEAD)?.trim() ?? null,
7697
8423
  mergedBranch: kind === "merge" ? mergedBranchName(metadata.MERGE_MSG) : null,
7698
- progress: operationProgress(metadata)
8424
+ progress,
8425
+ steps
7699
8426
  };
7700
8427
  });
7701
8428
  }
7702
8429
  function readOperationMetadata(gitDirectory) {
7703
- return Effect57.gen(function* () {
7704
- let values = yield* Effect57.forEach(
8430
+ return Effect61.gen(function* () {
8431
+ let values = yield* Effect61.forEach(
7705
8432
  metadataNames,
7706
8433
  (name) => readOperationFile(gitDirectory, name),
7707
8434
  { concurrency: 8 }
7708
8435
  ), metadata = Object.fromEntries(
7709
8436
  metadataNames.map((name, index2) => [name, values[index2] ?? null])
7710
- ), stamps = yield* Effect57.forEach(
8437
+ ), stamps = yield* Effect61.forEach(
7711
8438
  ["rebase-merge", "rebase-apply", "sequencer"],
7712
8439
  (name) => operationFileStamp(gitDirectory, name)
7713
8440
  );
@@ -7715,7 +8442,7 @@ function readOperationMetadata(gitDirectory) {
7715
8442
  });
7716
8443
  }
7717
8444
  function readGitLock({ gitDirectory, commonDirectory }) {
7718
- return Effect57.gen(function* () {
8445
+ return Effect61.gen(function* () {
7719
8446
  return (yield* operationFileStamp(gitDirectory, "index.lock")) !== null ? "index.lock" : (yield* operationFileStamp(commonDirectory, "packed-refs.lock")) !== null ? "packed-refs.lock" : null;
7720
8447
  });
7721
8448
  }
@@ -7723,13 +8450,13 @@ function operationPhase(kind, unresolved, edit) {
7723
8450
  return kind === "idle" ? "idle" : kind === "unknown" ? "blocked" : unresolved ? "conflicts" : edit ? "edit" : "ready";
7724
8451
  }
7725
8452
  function inspectWorktree(git, worktreePath, gitDirectory) {
7726
- return Effect57.gen(function* () {
8453
+ return Effect61.gen(function* () {
7727
8454
  let head = yield* inspect(
7728
8455
  git,
7729
8456
  worktreePath,
7730
8457
  ["rev-parse", "--verify", "--quiet", "HEAD"],
7731
8458
  [0, 1]
7732
- ).pipe(Effect57.map((output) => output.trim() || null)), index2 = yield* operationFileStamp(gitDirectory, "index"), unresolved = yield* inspect(git, worktreePath, [
8459
+ ).pipe(Effect61.map((output) => output.trim() || null)), index2 = yield* operationFileStamp(gitDirectory, "index"), unresolved = yield* inspect(git, worktreePath, [
7733
8460
  "ls-files",
7734
8461
  "--unmerged",
7735
8462
  "-z"
@@ -7739,7 +8466,7 @@ function inspectWorktree(git, worktreePath, gitDirectory) {
7739
8466
  "--no-renames",
7740
8467
  "-z",
7741
8468
  "--untracked-files=no"
7742
- ]), worktree = yield* Effect57.forEach(
8469
+ ]), worktree = yield* Effect61.forEach(
7743
8470
  status.split("\0").filter(Boolean),
7744
8471
  (record) => operationFileStamp(worktreePath, record.slice(3)),
7745
8472
  { concurrency: 16 }
@@ -7753,7 +8480,7 @@ function inspect(git, worktreePath, args, exitCodes) {
7753
8480
  worktreePath,
7754
8481
  args,
7755
8482
  exitCodes === void 0 ? {} : { exitCodes }
7756
- ).pipe(Effect57.mapError((error) => inspectionFailed(error.detail)));
8483
+ ).pipe(Effect61.mapError((error) => inspectionFailed(error.detail)));
7757
8484
  }
7758
8485
  function identifyOperation(metadata, stamps) {
7759
8486
  if (stamps[0] !== null) return "rebase";
@@ -7763,11 +8490,14 @@ function identifyOperation(metadata, stamps) {
7763
8490
  if (metadata.CHERRY_PICK_HEAD !== null) return "cherry-pick";
7764
8491
  if (metadata.REVERT_HEAD !== null) return "revert";
7765
8492
  let todo = metadata["sequencer/todo"]?.trimStart();
7766
- return todo?.startsWith("pick ") ? "cherry-pick" : todo?.startsWith("revert ") ? "revert" : stamps[2] === null ? "idle" : "unknown";
8493
+ return todo?.startsWith("pick ") ? "cherry-pick" : todo?.startsWith("revert ") ? "revert" : stamps[2] !== null ? "unknown" : metadata.SQUASH_MSG === null ? "idle" : "squash";
8494
+ }
8495
+ function lockedReason(lock) {
8496
+ return lock === null ? null : "Git is using this worktree. Check again when it finishes.";
7767
8497
  }
7768
8498
  function blockedReason(kind, lock, unresolved, edit, status) {
7769
- if (lock !== null)
7770
- return "Git is using this worktree. Check again when it finishes.";
8499
+ let locked = lockedReason(lock);
8500
+ if (locked !== null) return locked;
7771
8501
  if (unresolved)
7772
8502
  return `Resolve and stage ${unresolved} ${unresolved === 1 ? "file" : "files"} to continue.`;
7773
8503
  if (edit && status.length > 0)
@@ -7780,7 +8510,9 @@ function availableActions(kind, metadata, stamps, edit, lock, reason) {
7780
8510
  let unlocked = {
7781
8511
  enabled: lock === null,
7782
8512
  reason: lock === null ? null : reason
7783
- }, skippable = kind !== "merge" && !edit && (kind !== "rebase" || metadata["rebase-merge/stopped-sha"] !== null || stamps[1] !== null);
8513
+ };
8514
+ if (kind === "squash") return [{ action: "abort", ...unlocked }];
8515
+ let skippable = kind !== "merge" && !edit && !/no-commit\s*=\s*true/.test(metadata["sequencer/opts"] ?? "") && (kind !== "rebase" || metadata["rebase-merge/stopped-sha"] !== null || stamps[1] !== null);
7784
8516
  return [
7785
8517
  { action: "continue", enabled: reason === null, reason },
7786
8518
  ...skippable ? [{ action: "skip", ...unlocked }] : [],
@@ -7793,6 +8525,45 @@ function branchName(headName) {
7793
8525
  function mergedBranchName(message) {
7794
8526
  return /^Merge (?:remote-tracking )?branch '([^']+)'/.exec(message ?? "")?.[1] ?? null;
7795
8527
  }
8528
+ var planActions = {
8529
+ pick: "pick",
8530
+ p: "pick",
8531
+ reword: "reword",
8532
+ r: "reword",
8533
+ edit: "edit",
8534
+ e: "edit",
8535
+ squash: "squash",
8536
+ s: "squash",
8537
+ fixup: "fixup",
8538
+ f: "fixup",
8539
+ drop: "drop",
8540
+ d: "drop"
8541
+ };
8542
+ function rebaseSteps(metadata) {
8543
+ let steps = [];
8544
+ for (let [text3, done] of [
8545
+ [metadata["rebase-merge/done"], !0],
8546
+ [metadata["rebase-merge/git-rebase-todo"], !1]
8547
+ ])
8548
+ for (let line of (text3 ?? "").split(`
8549
+ `)) {
8550
+ let trimmed = line.trim();
8551
+ if (trimmed === "" || trimmed.startsWith("#")) continue;
8552
+ let match = /^(\w+)\s+([0-9a-f]{40,64})(?:\s+(.*))?$/.exec(trimmed), action = match?.[1] === void 0 ? void 0 : planActions[match[1]];
8553
+ if (match === null || action === void 0) return null;
8554
+ steps.push({
8555
+ commit: match[2] ?? "",
8556
+ action,
8557
+ subject: (match[3] ?? "").replace(/^#\s*/, ""),
8558
+ done
8559
+ });
8560
+ }
8561
+ return steps.length === 0 ? null : steps;
8562
+ }
8563
+ function stepProgress(steps) {
8564
+ let current = steps?.filter((step) => step.done).length ?? 0;
8565
+ return steps === null || current === 0 ? null : { current, total: steps.length };
8566
+ }
7796
8567
  function operationProgress(metadata) {
7797
8568
  let current = Number(
7798
8569
  metadata["rebase-merge/msgnum"] ?? metadata["rebase-apply/next"]
@@ -7801,14 +8572,31 @@ function operationProgress(metadata) {
7801
8572
  );
7802
8573
  return Number.isSafeInteger(current) && Number.isSafeInteger(total) && current > 0 && total >= current ? { current, total } : null;
7803
8574
  }
8575
+ function hasStagedChanges2(status) {
8576
+ return status.split("\0").some((line) => line.length > 2 && line[0] !== " " && line[0] !== "?");
8577
+ }
8578
+ function sequenceProgress(git, worktreePath, metadata, head) {
8579
+ let start = metadata["sequencer/head"]?.trim(), remaining = (metadata["sequencer/todo"] ?? "").split(`
8580
+ `).filter((line) => /^(pick|revert|p|r)\s/.test(line)).length;
8581
+ return start === void 0 || head === null || remaining === 0 || /no-commit\s*=\s*true/.test(metadata["sequencer/opts"] ?? "") ? Effect61.succeed(null) : inspect(git, worktreePath, [
8582
+ "rev-list",
8583
+ "--count",
8584
+ `${start}..${head}`
8585
+ ]).pipe(
8586
+ Effect61.map((output) => {
8587
+ let done = Number(output.trim());
8588
+ return Number.isSafeInteger(done) ? { current: done + 1, total: done + remaining } : null;
8589
+ })
8590
+ );
8591
+ }
7804
8592
  function readOperationFile(directory, name) {
7805
- return Effect57.tryPromise({
8593
+ return Effect61.tryPromise({
7806
8594
  try: async () => {
7807
8595
  try {
7808
- let path = join10(directory, name);
8596
+ let path = join11(directory, name);
7809
8597
  if ((await stat5(path)).size > maximumMetadataBytes)
7810
8598
  throw new Error("Operation metadata is too large.");
7811
- return await readFile5(path, "utf8");
8599
+ return await readFile6(path, "utf8");
7812
8600
  } catch (error) {
7813
8601
  if (isMissing(error)) return null;
7814
8602
  throw error;
@@ -7818,10 +8606,10 @@ function readOperationFile(directory, name) {
7818
8606
  });
7819
8607
  }
7820
8608
  function operationFileStamp(directory, name) {
7821
- return Effect57.tryPromise({
8609
+ return Effect61.tryPromise({
7822
8610
  try: async () => {
7823
8611
  try {
7824
- let info = await lstat3(join10(directory, name), { bigint: !0 });
8612
+ let info = await lstat3(join11(directory, name), { bigint: !0 });
7825
8613
  return `${info.ino}:${info.size}:${info.mtimeNs}:${info.ctimeNs}`;
7826
8614
  } catch (error) {
7827
8615
  if (isMissing(error)) return null;
@@ -7840,16 +8628,16 @@ function isMissing(error) {
7840
8628
 
7841
8629
  // src/apps/server/repository/repository-coordination.ts
7842
8630
  function createRepositoryCoordination(git) {
7843
- let locks = /* @__PURE__ */ new Map(), withLock = (key, acquisition, operation) => Effect58.acquireUseRelease(
7844
- Effect58.sync(() => {
8631
+ let locks = /* @__PURE__ */ new Map(), withLock = (key, acquisition, operation) => Effect62.acquireUseRelease(
8632
+ Effect62.sync(() => {
7845
8633
  let entry = locks.get(key);
7846
8634
  return entry === void 0 && (entry = { semaphore: Semaphore4.makeUnsafe(1), owners: 0 }, locks.set(key, entry)), entry.owners++, entry;
7847
8635
  }),
7848
8636
  (entry) => acquisition === "wait" ? entry.semaphore.withPermit(operation) : entry.semaphore.withPermitsIfAvailable(1)(operation).pipe(
7849
- Effect58.flatMap(
8637
+ Effect62.flatMap(
7850
8638
  Option2.match({
7851
- onSome: Effect58.succeed,
7852
- onNone: () => Effect58.fail(
8639
+ onSome: Effect62.succeed,
8640
+ onNone: () => Effect62.fail(
7853
8641
  repositoryRejected(
7854
8642
  "Busy",
7855
8643
  "Another repository write is in progress."
@@ -7858,35 +8646,35 @@ function createRepositoryCoordination(git) {
7858
8646
  })
7859
8647
  )
7860
8648
  ),
7861
- (entry) => Effect58.sync(() => {
8649
+ (entry) => Effect62.sync(() => {
7862
8650
  --entry.owners === 0 && locks.delete(key);
7863
8651
  })
7864
- ), directories = /* @__PURE__ */ new Map(), gitDirectories = (directory) => Effect58.gen(function* () {
8652
+ ), directories = /* @__PURE__ */ new Map(), gitDirectories = (directory) => Effect62.gen(function* () {
7865
8653
  let identity = yield* readGitEntryIdentity(directory), cached = directories.get(directory);
7866
8654
  if (identity !== void 0 && cached?.identity === identity)
7867
8655
  return cached.paths;
7868
8656
  let paths = yield* resolveGitDirectories(git, directory);
7869
8657
  return identity !== void 0 && directories.set(directory, { identity, paths }), paths;
7870
8658
  }), forgetOnError = (directory, effect) => effect.pipe(
7871
- Effect58.onError(() => Effect58.sync(() => directories.delete(directory)))
8659
+ Effect62.onError(() => Effect62.sync(() => directories.delete(directory)))
7872
8660
  );
7873
8661
  return {
7874
8662
  run: (directory, policy, operation) => forgetOnError(
7875
8663
  directory,
7876
- Effect58.gen(function* () {
8664
+ Effect62.gen(function* () {
7877
8665
  let { refs, worktree } = policy.locks, paths = yield* gitDirectories(directory), guarded = requireCompatibleWrite(
7878
8666
  git,
7879
8667
  directory,
7880
8668
  paths,
7881
8669
  policy
7882
- ).pipe(Effect58.andThen(operation)), inWorktree = worktree === void 0 ? guarded : withLock(`worktree:${paths.gitDirectory}`, worktree, guarded);
8670
+ ).pipe(Effect62.andThen(operation)), inWorktree = worktree === void 0 ? guarded : withLock(`worktree:${paths.gitDirectory}`, worktree, guarded);
7883
8671
  return yield* refs === void 0 ? inWorktree : withLock(`refs:${paths.commonDirectory}`, refs, inWorktree);
7884
8672
  })
7885
8673
  ),
7886
8674
  operation: (directory) => forgetOnError(
7887
8675
  directory,
7888
8676
  gitDirectories(directory).pipe(
7889
- Effect58.flatMap(
8677
+ Effect62.flatMap(
7890
8678
  (paths) => readRepositoryOperation(git, directory, paths)
7891
8679
  )
7892
8680
  )
@@ -7894,10 +8682,10 @@ function createRepositoryCoordination(git) {
7894
8682
  };
7895
8683
  }
7896
8684
  function requireCompatibleWrite(git, directory, paths, { name, duringOperation }) {
7897
- return duringOperation === "proceed" ? Effect58.void : readRepositoryOperation(git, directory, paths).pipe(
7898
- Effect58.flatMap((state) => state.lock !== null ? Effect58.fail(
8685
+ return duringOperation === "proceed" ? Effect62.void : readRepositoryOperation(git, directory, paths).pipe(
8686
+ Effect62.flatMap((state) => state.lock !== null ? Effect62.fail(
7899
8687
  repositoryRejected("Busy", `Git lock exists: ${state.lock}.`)
7900
- ) : state.kind === "idle" || duringOperation !== "block" && duringOperation.allowWhen(state) ? Effect58.void : Effect58.fail(
8688
+ ) : state.kind === "idle" || duringOperation !== "block" && duringOperation.allowWhen(state) ? Effect62.void : Effect62.fail(
7901
8689
  repositoryRejected(
7902
8690
  "Incompatible",
7903
8691
  `Cannot ${name} while ${state.kind === "unknown" ? "an unrecognized Git operation is" : `${state.kind} is`} in progress.`
@@ -7906,12 +8694,12 @@ function requireCompatibleWrite(git, directory, paths, { name, duringOperation }
7906
8694
  );
7907
8695
  }
7908
8696
  function resolveGitDirectories(git, directory) {
7909
- return Effect58.gen(function* () {
8697
+ return Effect62.gen(function* () {
7910
8698
  let gitDirectory = (yield* runRepositoryGit(git, directory, [
7911
8699
  "rev-parse",
7912
8700
  "--absolute-git-dir"
7913
8701
  ])).trimEnd(), commonDirectory = yield* readGitCommonDirectory(git, directory);
7914
- return yield* Effect58.tryPromise({
8702
+ return yield* Effect62.tryPromise({
7915
8703
  try: async () => ({
7916
8704
  gitDirectory: await realpath5(gitDirectory),
7917
8705
  commonDirectory: await realpath5(commonDirectory)
@@ -7922,7 +8710,7 @@ function resolveGitDirectories(git, directory) {
7922
8710
  )
7923
8711
  });
7924
8712
  }).pipe(
7925
- Effect58.mapError(
8713
+ Effect62.mapError(
7926
8714
  (error) => error._tag === "GitFailed" ? repositoryRejected("GitFailed", error.detail) : error
7927
8715
  )
7928
8716
  );
@@ -7930,7 +8718,7 @@ function resolveGitDirectories(git, directory) {
7930
8718
 
7931
8719
  // src/apps/server/app/server/serve-environment.ts
7932
8720
  function serveEnvironment(dependencies, options) {
7933
- return Effect59.gen(function* () {
8721
+ return Effect63.gen(function* () {
7934
8722
  let environment = yield* readCurrentEnvironment(dependencies.context), useAutomaticPort = options.port === void 0 || options.port === 0, listener = yield* acquireEnvironmentListener({
7935
8723
  authorization: dependencies.authorization,
7936
8724
  ...options.browserAssetsRoot === void 0 ? {} : { browserAssetsRoot: options.browserAssetsRoot },
@@ -7956,8 +8744,8 @@ function serveEnvironment(dependencies, options) {
7956
8744
  });
7957
8745
  }
7958
8746
  function acquireEnvironment(home, git) {
7959
- return Effect59.gen(function* () {
7960
- let paths = environmentPaths(join11(home, ".rebase")), context = yield* acquireEnvironmentContext(paths), watcher = createLocalRepositoryWatcher(), catalog = createRepositoryCatalog(context, git);
8747
+ return Effect63.gen(function* () {
8748
+ let paths = environmentPaths(join12(home, ".rebase")), context = yield* acquireEnvironmentContext(paths), watcher = createLocalRepositoryWatcher(), catalog = createRepositoryCatalog(context, git);
7961
8749
  return {
7962
8750
  access: createRepositoryAccess(catalog, git, watcher),
7963
8751
  authorization: createEnvironmentAuthorization(context),
@@ -7972,7 +8760,7 @@ function acquireEnvironment(home, git) {
7972
8760
  });
7973
8761
  }
7974
8762
  function environmentFeatures(dependencies) {
7975
- return Effect59.gen(function* () {
8763
+ return Effect63.gen(function* () {
7976
8764
  return combineEnvironmentFeatures([
7977
8765
  environmentAuthorizationFeature(dependencies.authorization),
7978
8766
  environmentFilesystemFeature(),
@@ -8030,7 +8818,7 @@ function hasNoAutomaticPort() {
8030
8818
 
8031
8819
  // src/apps/server/app/server/start-environment-server.ts
8032
8820
  function startEnvironmentServer(options) {
8033
- return Effect60.gen(function* () {
8821
+ return Effect64.gen(function* () {
8034
8822
  return yield* verifyRuntimeRequirements, yield* serveEnvironment(
8035
8823
  yield* acquireEnvironment(options.home, createLocalGitCommandRunner()),
8036
8824
  options
@@ -8042,20 +8830,20 @@ function startEnvironmentServer(options) {
8042
8830
  var usage = "Usage: rebase [serve] [--host <ip-address|lan|tailscale>] [--port <1-65535>]";
8043
8831
  function runCli(arguments_ = process.argv.slice(2)) {
8044
8832
  if (arguments_.includes("--help") || arguments_.includes("-h"))
8045
- return writeOutput(usage).pipe(Effect61.as(0));
8833
+ return writeOutput(usage).pipe(Effect65.as(0));
8046
8834
  if (arguments_.includes("--version") || arguments_.includes("-v"))
8047
- return writeOutput(versionOutput()).pipe(Effect61.as(0));
8048
- let program = Effect61.try({
8835
+ return writeOutput(versionOutput()).pipe(Effect65.as(0));
8836
+ let program = Effect65.try({
8049
8837
  try: () => parseServeArguments(arguments_),
8050
8838
  catch: normalizeError
8051
- }).pipe(Effect61.flatMap(serve));
8052
- return Effect61.matchEffect(program, {
8053
- onFailure: (error) => writeFailure(`rebase serve failed: ${error.message}`).pipe(Effect61.as(1)),
8054
- onSuccess: () => Effect61.succeed(0)
8839
+ }).pipe(Effect65.flatMap(serve));
8840
+ return Effect65.matchEffect(program, {
8841
+ onFailure: (error) => writeFailure(`rebase serve failed: ${error.message}`).pipe(Effect65.as(1)),
8842
+ onSuccess: () => Effect65.succeed(0)
8055
8843
  });
8056
8844
  }
8057
8845
  async function main() {
8058
- process.exitCode = await Effect61.runPromise(runCli());
8846
+ process.exitCode = await Effect65.runPromise(runCli());
8059
8847
  }
8060
8848
  function parseServeArguments(arguments_) {
8061
8849
  let normalizedArguments = arguments_.length === 0 || arguments_[0]?.startsWith("--") ? ["serve", ...arguments_] : arguments_, [command, ...options] = normalizedArguments;
@@ -8083,13 +8871,13 @@ function parsePort(value) {
8083
8871
  return port;
8084
8872
  }
8085
8873
  function serve(options) {
8086
- return Effect61.scoped(
8087
- Effect61.gen(function* () {
8088
- let shutdown = yield* acquireShutdownSignal(), server = yield* Effect61.raceFirst(
8874
+ return Effect65.scoped(
8875
+ Effect65.gen(function* () {
8876
+ let shutdown = yield* acquireShutdownSignal(), server = yield* Effect65.raceFirst(
8089
8877
  startEnvironmentServer(options),
8090
8878
  Deferred3.await(shutdown)
8091
8879
  );
8092
- server !== void 0 && (yield* Effect61.sync(() => {
8880
+ server !== void 0 && (yield* Effect65.sync(() => {
8093
8881
  process.stdout.write(`Listening URL: ${server.origin}
8094
8882
  `), process.stdout.write(`Pairing URL: ${server.pairingUrl}
8095
8883
  `), openDefaultBrowser(server.pairingUrl);
@@ -8098,29 +8886,29 @@ function serve(options) {
8098
8886
  );
8099
8887
  }
8100
8888
  function acquireShutdownSignal() {
8101
- return Effect61.gen(function* () {
8889
+ return Effect65.gen(function* () {
8102
8890
  let shutdown = yield* Deferred3.make();
8103
- return yield* Effect61.acquireRelease(
8104
- Effect61.sync(() => {
8891
+ return yield* Effect65.acquireRelease(
8892
+ Effect65.sync(() => {
8105
8893
  let stop = () => {
8106
- Deferred3.doneUnsafe(shutdown, Effect61.void);
8894
+ Deferred3.doneUnsafe(shutdown, Effect65.void);
8107
8895
  };
8108
8896
  return process.once("SIGINT", stop), process.once("SIGTERM", stop), stop;
8109
8897
  }),
8110
- (stop) => Effect61.sync(() => {
8898
+ (stop) => Effect65.sync(() => {
8111
8899
  process.off("SIGINT", stop), process.off("SIGTERM", stop);
8112
8900
  })
8113
8901
  ), shutdown;
8114
8902
  });
8115
8903
  }
8116
8904
  function writeOutput(line) {
8117
- return Effect61.sync(() => {
8905
+ return Effect65.sync(() => {
8118
8906
  process.stdout.write(`${line}
8119
8907
  `);
8120
8908
  });
8121
8909
  }
8122
8910
  function writeFailure(line) {
8123
- return Effect61.sync(() => {
8911
+ return Effect65.sync(() => {
8124
8912
  process.stderr.write(`${line}
8125
8913
  `);
8126
8914
  });
@@ -8140,7 +8928,7 @@ function resolveBrowserAssetsRoot() {
8140
8928
  return fileURLToPath2(root);
8141
8929
  }
8142
8930
  function productVersion() {
8143
- return "0.0.2-nightly.20260928.132";
8931
+ return "0.0.2";
8144
8932
  }
8145
8933
  function versionOutput() {
8146
8934
  return [