@cvr/stacked 0.4.4 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,6 +22,7 @@ const StackRecordSchema = Schema.Struct({
22
22
  const BranchRecordSchema = Schema.Struct({
23
23
  stack: Schema.String,
24
24
  parent: Schema.NullOr(Schema.String),
25
+ syncedOnto: Schema.optional(Schema.NullOr(Schema.String)),
25
26
  });
26
27
 
27
28
  const StackFileV2Schema = Schema.Struct({
@@ -54,7 +55,14 @@ interface CanonicalStackFile {
54
55
  readonly trunk: string;
55
56
  readonly stacks: Readonly<Record<string, { readonly root: string }>>;
56
57
  readonly branches: Readonly<
57
- Record<string, { readonly stack: string; readonly parent: string | null }>
58
+ Record<
59
+ string,
60
+ {
61
+ readonly stack: string;
62
+ readonly parent: string | null;
63
+ readonly syncedOnto?: string | null | undefined;
64
+ }
65
+ >
58
66
  >;
59
67
  readonly mergedBranches: readonly string[];
60
68
  }
@@ -224,7 +232,10 @@ const rewriteStackBranches = (
224
232
  stackName: string,
225
233
  branches: readonly string[],
226
234
  ): CanonicalStackFile => {
227
- const nextBranches: Record<string, { stack: string; parent: string | null }> = {
235
+ const nextBranches: Record<
236
+ string,
237
+ { stack: string; parent: string | null; syncedOnto?: string | null }
238
+ > = {
228
239
  ...data.branches,
229
240
  };
230
241
 
@@ -237,9 +248,11 @@ const rewriteStackBranches = (
237
248
  for (let i = 0; i < branches.length; i++) {
238
249
  const branch = branches[i];
239
250
  if (branch === undefined) continue;
251
+ const existing = data.branches[branch];
240
252
  nextBranches[branch] = {
241
253
  stack: stackName,
242
254
  parent: i === 0 ? null : (branches[i - 1] ?? null),
255
+ ...(existing?.syncedOnto != null ? { syncedOnto: existing.syncedOnto } : {}),
243
256
  };
244
257
  }
245
258
 
@@ -252,10 +265,8 @@ const rewriteStackBranches = (
252
265
  };
253
266
  }
254
267
 
255
- const [root] = branches;
256
- if (root === undefined) {
257
- return data;
258
- }
268
+ // branches.length > 0 guaranteed by the early return above
269
+ const root = branches[0] as string;
259
270
 
260
271
  return {
261
272
  ...data,
@@ -276,7 +287,10 @@ const renameStackRefs = (
276
287
  if (stackRecord === undefined) return data;
277
288
 
278
289
  const { [oldName]: _, ...restStacks } = data.stacks;
279
- const branches: Record<string, { stack: string; parent: string | null }> = {};
290
+ const branches: Record<
291
+ string,
292
+ { stack: string; parent: string | null; syncedOnto?: string | null }
293
+ > = {};
280
294
 
281
295
  for (const [branch, record] of Object.entries(data.branches)) {
282
296
  branches[branch] = {
@@ -586,6 +600,33 @@ const makeStackService = ({
586
600
  });
587
601
  }),
588
602
 
603
+ getSyncedOnto: Effect.fn("StackService.getSyncedOnto")(function* (branch: string) {
604
+ const data = yield* loadData();
605
+ const record = data.branches[branch];
606
+ if (record === undefined) return null;
607
+ return record.syncedOnto ?? null;
608
+ }),
609
+
610
+ updateSyncedOnto: Effect.fn("StackService.updateSyncedOnto")(function* (
611
+ branch: string,
612
+ oid: string | null,
613
+ ) {
614
+ const data = yield* loadData();
615
+ const record = data.branches[branch];
616
+ if (record === undefined) {
617
+ return yield* new StackError({
618
+ message: `Branch "${branch}" not found in stack metadata`,
619
+ });
620
+ }
621
+ yield* saveData({
622
+ ...data,
623
+ branches: {
624
+ ...data.branches,
625
+ [branch]: { ...record, syncedOnto: oid },
626
+ },
627
+ });
628
+ }),
629
+
589
630
  getTrunk: Effect.fn("StackService.getTrunk")(function* () {
590
631
  const data = yield* loadData();
591
632
  return data.trunk;
@@ -632,25 +673,28 @@ export class StackService extends ServiceMap.Service<
632
673
  branch: string,
633
674
  ) => Effect.Effect<{ name: string; stack: Stack } | null, StackError>;
634
675
  readonly detectTrunkCandidate: () => Effect.Effect<Option.Option<string>, never>;
676
+ readonly getSyncedOnto: (branch: string) => Effect.Effect<string | null, StackError>;
677
+ readonly updateSyncedOnto: (
678
+ branch: string,
679
+ oid: string | null,
680
+ ) => Effect.Effect<void, StackError>;
635
681
  readonly getTrunk: () => Effect.Effect<string, StackError>;
636
682
  readonly setTrunk: (name: string) => Effect.Effect<void, StackError>;
637
683
  }
638
684
  >()("@cvr/stacked/services/Stack/StackService") {
639
- static layer: Layer.Layer<StackService, never, GitService> = Layer.effect(
685
+ static layer: Layer.Layer<StackService, StackError, GitService> = Layer.effect(
640
686
  StackService,
641
687
  Effect.gen(function* () {
642
688
  const git = yield* GitService;
643
689
 
644
- const stackFilePath = Effect.fn("StackService.stackFilePath")(function* () {
645
- const gitDir = yield* git
646
- .revParse("--absolute-git-dir")
647
- .pipe(
648
- Effect.mapError(
649
- (e) => new StackError({ message: `Not a git repository: ${e.message}` }),
650
- ),
651
- );
652
- return `${gitDir}/stacked.json`;
653
- });
690
+ // Resolve git dir once at construction time, then capture in closure
691
+ const gitDir = yield* git
692
+ .revParse("--absolute-git-dir")
693
+ .pipe(
694
+ Effect.mapError((e) => new StackError({ message: `Not a git repository: ${e.message}` })),
695
+ );
696
+ const resolvedStackFilePath = `${gitDir}/stacked.json`;
697
+ const stackFilePath = () => Effect.succeed(resolvedStackFilePath);
654
698
 
655
699
  const StackFileJson = Schema.fromJsonString(
656
700
  Schema.Union([StackFileV1Schema, StackFileV2Schema]),