@senad-d/branchme 0.1.8 → 0.2.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.
package/src/types.ts CHANGED
@@ -20,6 +20,27 @@ export interface WorkingTreeDetails {
20
20
  untracked: number;
21
21
  }
22
22
 
23
+ export interface BranchStatusAncestryQuery {
24
+ sourceBranch: string;
25
+ targetBranch: string;
26
+ }
27
+
28
+ export interface BranchStatusToolInput {
29
+ ancestry?: BranchStatusAncestryQuery;
30
+ }
31
+
32
+ export interface IntegrateBranchToolInput {
33
+ sourceBranch: string;
34
+ targetBranch: string;
35
+ }
36
+
37
+ export interface RetireBranchToolInput {
38
+ branchName: string;
39
+ expectedHead: string;
40
+ targetBranch: string;
41
+ force: boolean;
42
+ }
43
+
23
44
  export type CreateWorktreeMode = "new" | "existing";
24
45
 
25
46
  export type ListWorktreesToolInput = Record<string, never>;
@@ -165,6 +186,12 @@ export type RelatedPullRequest =
165
186
  | { status: "none" }
166
187
  | { status: "unavailable"; reason: string };
167
188
 
189
+ export interface BranchAncestryDetails extends BranchStatusAncestryQuery {
190
+ sourceHead: string;
191
+ targetHead: string;
192
+ isAncestor: boolean;
193
+ }
194
+
168
195
  export interface BranchStatusDetails {
169
196
  repoRoot: string;
170
197
  currentBranch: string | null;
@@ -173,6 +200,7 @@ export interface BranchStatusDetails {
173
200
  hasChanges: boolean;
174
201
  ahead: number | null;
175
202
  behind: number | null;
203
+ ancestry?: BranchAncestryDetails;
176
204
  warnings?: string[];
177
205
  githubRepository?: GitHubRepository;
178
206
  }
@@ -239,6 +267,169 @@ export interface PushBranchDetails {
239
267
  output: string;
240
268
  }
241
269
 
270
+ export type IntegrateBranchStatus = "already_integrated" | "fast_forward" | "merge_commit" | "conflict";
271
+
272
+ export interface IntegrateBranchHeads {
273
+ sourceHead: string;
274
+ targetHead: string;
275
+ }
276
+
277
+ export interface IntegrateBranchRepositoryVerification {
278
+ worktreeRoot: string;
279
+ canonicalCommonGitDirectory: string;
280
+ identityPreserved: true;
281
+ }
282
+
283
+ export interface IntegrateBranchControlWorktreeVerification {
284
+ targetBranch: string;
285
+ currentBranchPreserved: true;
286
+ cleanBefore: true;
287
+ cleanAfter: true;
288
+ operationStateAbsentBefore: true;
289
+ operationStateAbsentAfter: true;
290
+ }
291
+
292
+ export interface IntegrateBranchFinalAncestryProof {
293
+ sourceHead: string;
294
+ previousTargetHead: string;
295
+ targetHead: string;
296
+ sourceIsAncestorOfTarget: boolean;
297
+ previousTargetIsAncestorOfTarget: boolean;
298
+ }
299
+
300
+ export interface IntegrateBranchVerification {
301
+ repository: IntegrateBranchRepositoryVerification;
302
+ controlWorktree: IntegrateBranchControlWorktreeVerification;
303
+ heads: {
304
+ before: IntegrateBranchHeads;
305
+ after: IntegrateBranchHeads;
306
+ };
307
+ finalAncestry: IntegrateBranchFinalAncestryProof;
308
+ }
309
+
310
+ export interface IntegrateBranchDetailsBase {
311
+ action: "integrate_branch";
312
+ request: IntegrateBranchToolInput;
313
+ verified: IntegrateBranchVerification;
314
+ }
315
+
316
+ export interface IntegrateBranchAlreadyIntegratedDetails extends IntegrateBranchDetailsBase {
317
+ status: "already_integrated";
318
+ mergeExecuted: false;
319
+ }
320
+
321
+ export interface IntegrateBranchFastForwardDetails extends IntegrateBranchDetailsBase {
322
+ status: "fast_forward";
323
+ mergeExecuted: true;
324
+ }
325
+
326
+ export interface IntegrateBranchMergeCommitDetails extends IntegrateBranchDetailsBase {
327
+ status: "merge_commit";
328
+ mergeExecuted: true;
329
+ }
330
+
331
+ export interface IntegrateBranchConflictPathEntry {
332
+ /** Exact repository-relative identity; human-readable renderers must sanitize a separate display copy. */
333
+ path: string;
334
+ }
335
+
336
+ export interface IntegrateBranchConflictDetails extends IntegrateBranchDetailsBase {
337
+ status: "conflict";
338
+ mergeExecuted: true;
339
+ conflict: {
340
+ paths: IntegrateBranchConflictPathEntry[];
341
+ omitted: number;
342
+ abort: {
343
+ attempted: true;
344
+ succeeded: true;
345
+ };
346
+ restoration: {
347
+ verified: true;
348
+ repositoryIdentityPreserved: true;
349
+ controlWorktreeBranchPreserved: true;
350
+ sourceHeadPreserved: true;
351
+ targetHeadRestored: true;
352
+ operationStateCleared: true;
353
+ cleanControlWorktree: true;
354
+ };
355
+ };
356
+ }
357
+
358
+ export type IntegrateBranchDetails =
359
+ | IntegrateBranchAlreadyIntegratedDetails
360
+ | IntegrateBranchFastForwardDetails
361
+ | IntegrateBranchMergeCommitDetails
362
+ | IntegrateBranchConflictDetails;
363
+
364
+ export type RetireBranchMode = "merged" | "forced_unmerged";
365
+
366
+ export interface RetireBranchRepositoryIdentity {
367
+ worktreeRoot: string;
368
+ canonicalCommonGitDirectory: string;
369
+ }
370
+
371
+ export interface RetireBranchRefIdentity {
372
+ branchName: string;
373
+ fullRef: string;
374
+ head: string;
375
+ }
376
+
377
+ export interface RetireBranchAbsentRefProof {
378
+ branchName: string;
379
+ fullRef: string;
380
+ absent: true;
381
+ }
382
+
383
+ export interface RetireBranchWorktreeOccupancyProof {
384
+ branchName: string;
385
+ completeInventoryInspected: true;
386
+ occupied: false;
387
+ matchingWorktreeCount: 0;
388
+ }
389
+
390
+ export interface RetireBranchDetails {
391
+ action: "retire_branch";
392
+ status: "retired";
393
+ mode: RetireBranchMode;
394
+ /** Exact normalized request values used for the verified retirement. */
395
+ request: RetireBranchToolInput;
396
+ verified: {
397
+ repository: {
398
+ before: RetireBranchRepositoryIdentity;
399
+ after: RetireBranchRepositoryIdentity;
400
+ identityPreserved: true;
401
+ };
402
+ refs: {
403
+ before: {
404
+ retiring: RetireBranchRefIdentity;
405
+ target: RetireBranchRefIdentity;
406
+ expectedHead: string;
407
+ expectedHeadMatches: true;
408
+ };
409
+ after: {
410
+ retiring: RetireBranchAbsentRefProof;
411
+ target: RetireBranchRefIdentity;
412
+ targetHeadPreserved: true;
413
+ };
414
+ };
415
+ ancestry: {
416
+ retiringHead: string;
417
+ targetHead: string;
418
+ retiringIsAncestorOfTarget: boolean;
419
+ };
420
+ worktreeOccupancy: {
421
+ before: RetireBranchWorktreeOccupancyProof;
422
+ after: RetireBranchWorktreeOccupancyProof;
423
+ };
424
+ mutation: {
425
+ exactLocalRefDeletionAttempted: true;
426
+ localBranchAbsentAfterDeletion: true;
427
+ directRemoteDeletionAttempted: false;
428
+ remoteTrackingRefDeletionAttempted: false;
429
+ };
430
+ };
431
+ }
432
+
242
433
  export interface PullRequestDetails {
243
434
  repository: GitHubRepository;
244
435
  number: number;
@@ -24,14 +24,14 @@ type PanelCell =
24
24
  preserveLeading?: boolean;
25
25
  };
26
26
 
27
- export type BranchMePanelSection = "status" | "workflow" | "worktrees";
27
+ export type BranchMePanelSection = "status" | "workflow" | "integration" | "worktrees";
28
28
 
29
29
  const NARROW_MIN_WIDTH = 24;
30
30
  const WIDE_MIN_WIDTH = 72;
31
31
  const MAX_PANEL_WIDTH = 96;
32
32
  const MAX_PANEL_HEIGHT = 16;
33
33
  const BODY_HEIGHT = 9;
34
- const PANEL_SECTIONS: BranchMePanelSection[] = ["status", "workflow", "worktrees"];
34
+ const PANEL_SECTIONS: BranchMePanelSection[] = ["status", "workflow", "integration", "worktrees"];
35
35
  const ANSI_RESET = "\u001b[0m";
36
36
 
37
37
  function truncateVisible(value: string, width: number, ellipsis = "…", pad = false): string {
@@ -144,7 +144,7 @@ function statusDetailRow(label: string, value: string): PanelCell {
144
144
  }
145
145
 
146
146
  function workflowDetailRow(tool: string, description: string): PanelCell {
147
- return layoutCell(` ${tool.padEnd(16, " ")}-> ${sanitize(description)}`);
147
+ return layoutCell(` ${tool.padEnd(17, " ")}-> ${sanitize(description)}`);
148
148
  }
149
149
 
150
150
  function sectionTitle(section: BranchMePanelSection): string {
@@ -153,6 +153,8 @@ function sectionTitle(section: BranchMePanelSection): string {
153
153
  return "STATUS";
154
154
  case "workflow":
155
155
  return "WORKFLOW";
156
+ case "integration":
157
+ return "LIFECYCLE";
156
158
  case "worktrees":
157
159
  return "WORKTREES";
158
160
  }
@@ -180,6 +182,8 @@ function sectionFooter(section: BranchMePanelSection, data: BranchMePanelData):
180
182
  return "status • current repository only • tools perform actions";
181
183
  case "workflow":
182
184
  return "workflow • inspect → change → fetch/pull/rebase → create → push → PR";
185
+ case "integration":
186
+ return "lifecycle • integrate → remove worktree separately → retire local ref";
183
187
  case "worktrees":
184
188
  return "worktrees • create → handoff cwd → next session • remove retains branch";
185
189
  }
@@ -208,6 +212,18 @@ function sectionRows(section: BranchMePanelSection, data: BranchMePanelData): Pa
208
212
  workflowDetailRow("push_branch", "current branch"),
209
213
  workflowDetailRow("pull_request", "after push"),
210
214
  ];
215
+ case "integration":
216
+ return [
217
+ heading("LIFECYCLE"),
218
+ workflowDetailRow("integrate_branch", "exact local source -> target"),
219
+ workflowDetailRow("control target", "checked out + clean"),
220
+ workflowDetailRow("conflict", "automatic verified abort"),
221
+ workflowDetailRow("semantic intent", "separate developer workflow"),
222
+ workflowDetailRow("remove_worktree", "separate; branch retained"),
223
+ workflowDetailRow("retire_branch", "leased local ref deletion"),
224
+ workflowDetailRow("retirement guard", "unoccupied + target ancestry"),
225
+ workflowDetailRow("remote effects", "never delete remote refs"),
226
+ ];
211
227
  case "worktrees":
212
228
  return [
213
229
  heading("WORKTREES"),