sync-worktrees 1.7.4 → 1.8.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.
Files changed (34) hide show
  1. package/README.md +6 -1
  2. package/dist/constants.d.ts +54 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/constants.js +66 -0
  5. package/dist/constants.js.map +1 -0
  6. package/dist/errors/index.d.ts +51 -0
  7. package/dist/errors/index.d.ts.map +1 -0
  8. package/dist/errors/index.js +119 -0
  9. package/dist/errors/index.js.map +1 -0
  10. package/dist/services/git.service.d.ts +2 -0
  11. package/dist/services/git.service.d.ts.map +1 -1
  12. package/dist/services/git.service.js +52 -40
  13. package/dist/services/git.service.js.map +1 -1
  14. package/dist/services/path-resolution.service.d.ts +7 -0
  15. package/dist/services/path-resolution.service.d.ts.map +1 -0
  16. package/dist/services/path-resolution.service.js +58 -0
  17. package/dist/services/path-resolution.service.js.map +1 -0
  18. package/dist/services/worktree-metadata.service.d.ts +12 -0
  19. package/dist/services/worktree-metadata.service.d.ts.map +1 -1
  20. package/dist/services/worktree-metadata.service.js +162 -3
  21. package/dist/services/worktree-metadata.service.js.map +1 -1
  22. package/dist/services/worktree-status.service.d.ts +28 -0
  23. package/dist/services/worktree-status.service.d.ts.map +1 -0
  24. package/dist/services/worktree-status.service.js +229 -0
  25. package/dist/services/worktree-status.service.js.map +1 -0
  26. package/dist/services/worktree-sync.service.d.ts +1 -0
  27. package/dist/services/worktree-sync.service.d.ts.map +1 -1
  28. package/dist/services/worktree-sync.service.js +37 -21
  29. package/dist/services/worktree-sync.service.js.map +1 -1
  30. package/dist/utils/lfs-error.d.ts +6 -0
  31. package/dist/utils/lfs-error.d.ts.map +1 -1
  32. package/dist/utils/lfs-error.js +16 -14
  33. package/dist/utils/lfs-error.js.map +1 -1
  34. package/package.json +1 -1
package/README.md CHANGED
@@ -252,7 +252,12 @@ sync-worktrees intelligently handles branches that have been rebased or force-pu
252
252
  - Automatically resets the worktree to match the upstream
253
253
  - No data loss since the content is the same
254
254
 
255
- 2. **Diverged branches** - When a branch has different content after rebase/force-push:
255
+ 2. **Diverged branches with NO local changes** - When someone force-pushes but you haven't made local commits:
256
+ - Automatically resets to the new upstream state
257
+ - No move to `.diverged` since you have no work to preserve
258
+ - Keeps `.diverged` clean by only preserving actual user work
259
+
260
+ 3. **Diverged branches WITH local changes** - When a branch has different content AND you've made local commits:
256
261
  - Moves the worktree to `.diverged` directory within your worktrees folder
257
262
  - Preserves all your local changes and commits
258
263
  - Creates a fresh worktree from the upstream branch
@@ -0,0 +1,54 @@
1
+ export declare const GIT_CONSTANTS: {
2
+ readonly REMOTE_PREFIX: "origin/";
3
+ readonly REMOTE_NAME: "origin";
4
+ readonly HEAD_REF: "/HEAD";
5
+ readonly DEFAULT_BRANCH: "main";
6
+ readonly BARE_DIR_NAME: ".bare";
7
+ readonly DIVERGED_DIR_NAME: ".diverged";
8
+ readonly REFS: {
9
+ readonly HEADS: "refs/heads/";
10
+ readonly REMOTES: "refs/remotes/origin";
11
+ readonly REMOTES_ORIGIN: "refs/remotes/origin/*";
12
+ };
13
+ readonly FETCH_CONFIG: "+refs/heads/*:refs/remotes/origin/*";
14
+ };
15
+ export declare const GIT_OPERATIONS: {
16
+ readonly MERGE_HEAD: "MERGE_HEAD";
17
+ readonly CHERRY_PICK_HEAD: "CHERRY_PICK_HEAD";
18
+ readonly REVERT_HEAD: "REVERT_HEAD";
19
+ readonly BISECT_LOG: "BISECT_LOG";
20
+ readonly REBASE_MERGE: "rebase-merge";
21
+ readonly REBASE_APPLY: "rebase-apply";
22
+ };
23
+ export declare const DEFAULT_CONFIG: {
24
+ readonly CRON_SCHEDULE: "0 * * * *";
25
+ readonly RETRY: {
26
+ readonly MAX_ATTEMPTS: 3;
27
+ readonly MAX_LFS_RETRIES: 2;
28
+ readonly INITIAL_DELAY_MS: 1000;
29
+ readonly MAX_DELAY_MS: 30000;
30
+ readonly BACKOFF_MULTIPLIER: 2;
31
+ };
32
+ readonly UPDATE_EXISTING_WORKTREES: true;
33
+ };
34
+ export declare const ERROR_MESSAGES: {
35
+ readonly GIT_NOT_INITIALIZED: "Git service not initialized. Call initialize() first.";
36
+ readonly ALREADY_EXISTS: "already exists";
37
+ readonly ALREADY_REGISTERED: "already registered worktree";
38
+ readonly FAST_FORWARD_FAILED: readonly ["Not possible to fast-forward", "fatal: Not possible to fast-forward, aborting", "cannot fast-forward"];
39
+ readonly NO_UPSTREAM: readonly ["fatal: no upstream configured", "no upstream configured for branch", "fatal: ambiguous argument", "unknown revision or path"];
40
+ readonly LFS_ERROR: readonly ["smudge filter lfs failed", "git-lfs", "LFS"];
41
+ readonly EXDEV: "EXDEV";
42
+ };
43
+ export declare const TEST_TIMEOUT: {
44
+ readonly DEFAULT: 10000;
45
+ readonly E2E: 60000;
46
+ };
47
+ export declare const PATH_CONSTANTS: {
48
+ readonly GIT_DIR: ".git";
49
+ readonly README: "README";
50
+ };
51
+ export declare const METADATA_CONSTANTS: {
52
+ readonly MAX_HISTORY_ENTRIES: 10;
53
+ };
54
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;;;;;;;;;CAahB,CAAC;AAEX,eAAO,MAAM,cAAc;;;;;;;CAOjB,CAAC;AAEX,eAAO,MAAM,cAAc;;;;;;;;;;CAUjB,CAAC;AAEX,eAAO,MAAM,cAAc;;;;;;;;CAiBjB,CAAC;AAEX,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAEX,eAAO,MAAM,kBAAkB;;CAErB,CAAC"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.METADATA_CONSTANTS = exports.PATH_CONSTANTS = exports.TEST_TIMEOUT = exports.ERROR_MESSAGES = exports.DEFAULT_CONFIG = exports.GIT_OPERATIONS = exports.GIT_CONSTANTS = void 0;
4
+ exports.GIT_CONSTANTS = {
5
+ REMOTE_PREFIX: "origin/",
6
+ REMOTE_NAME: "origin",
7
+ HEAD_REF: "/HEAD",
8
+ DEFAULT_BRANCH: "main",
9
+ BARE_DIR_NAME: ".bare",
10
+ DIVERGED_DIR_NAME: ".diverged",
11
+ REFS: {
12
+ HEADS: "refs/heads/",
13
+ REMOTES: "refs/remotes/origin",
14
+ REMOTES_ORIGIN: "refs/remotes/origin/*",
15
+ },
16
+ FETCH_CONFIG: "+refs/heads/*:refs/remotes/origin/*",
17
+ };
18
+ exports.GIT_OPERATIONS = {
19
+ MERGE_HEAD: "MERGE_HEAD",
20
+ CHERRY_PICK_HEAD: "CHERRY_PICK_HEAD",
21
+ REVERT_HEAD: "REVERT_HEAD",
22
+ BISECT_LOG: "BISECT_LOG",
23
+ REBASE_MERGE: "rebase-merge",
24
+ REBASE_APPLY: "rebase-apply",
25
+ };
26
+ exports.DEFAULT_CONFIG = {
27
+ CRON_SCHEDULE: "0 * * * *",
28
+ RETRY: {
29
+ MAX_ATTEMPTS: 3,
30
+ MAX_LFS_RETRIES: 2,
31
+ INITIAL_DELAY_MS: 1000,
32
+ MAX_DELAY_MS: 30000,
33
+ BACKOFF_MULTIPLIER: 2,
34
+ },
35
+ UPDATE_EXISTING_WORKTREES: true,
36
+ };
37
+ exports.ERROR_MESSAGES = {
38
+ GIT_NOT_INITIALIZED: "Git service not initialized. Call initialize() first.",
39
+ ALREADY_EXISTS: "already exists",
40
+ ALREADY_REGISTERED: "already registered worktree",
41
+ FAST_FORWARD_FAILED: [
42
+ "Not possible to fast-forward",
43
+ "fatal: Not possible to fast-forward, aborting",
44
+ "cannot fast-forward",
45
+ ],
46
+ NO_UPSTREAM: [
47
+ "fatal: no upstream configured",
48
+ "no upstream configured for branch",
49
+ "fatal: ambiguous argument",
50
+ "unknown revision or path",
51
+ ],
52
+ LFS_ERROR: ["smudge filter lfs failed", "git-lfs", "LFS"],
53
+ EXDEV: "EXDEV",
54
+ };
55
+ exports.TEST_TIMEOUT = {
56
+ DEFAULT: 10000,
57
+ E2E: 60000,
58
+ };
59
+ exports.PATH_CONSTANTS = {
60
+ GIT_DIR: ".git",
61
+ README: "README",
62
+ };
63
+ exports.METADATA_CONSTANTS = {
64
+ MAX_HISTORY_ENTRIES: 10,
65
+ };
66
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,aAAa,GAAG;IAC3B,aAAa,EAAE,SAAS;IACxB,WAAW,EAAE,QAAQ;IACrB,QAAQ,EAAE,OAAO;IACjB,cAAc,EAAE,MAAM;IACtB,aAAa,EAAE,OAAO;IACtB,iBAAiB,EAAE,WAAW;IAC9B,IAAI,EAAE;QACJ,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,qBAAqB;QAC9B,cAAc,EAAE,uBAAuB;KACxC;IACD,YAAY,EAAE,qCAAqC;CAC3C,CAAC;AAEE,QAAA,cAAc,GAAG;IAC5B,UAAU,EAAE,YAAY;IACxB,gBAAgB,EAAE,kBAAkB;IACpC,WAAW,EAAE,aAAa;IAC1B,UAAU,EAAE,YAAY;IACxB,YAAY,EAAE,cAAc;IAC5B,YAAY,EAAE,cAAc;CACpB,CAAC;AAEE,QAAA,cAAc,GAAG;IAC5B,aAAa,EAAE,WAAW;IAC1B,KAAK,EAAE;QACL,YAAY,EAAE,CAAC;QACf,eAAe,EAAE,CAAC;QAClB,gBAAgB,EAAE,IAAI;QACtB,YAAY,EAAE,KAAK;QACnB,kBAAkB,EAAE,CAAC;KACtB;IACD,yBAAyB,EAAE,IAAI;CACvB,CAAC;AAEE,QAAA,cAAc,GAAG;IAC5B,mBAAmB,EAAE,uDAAuD;IAC5E,cAAc,EAAE,gBAAgB;IAChC,kBAAkB,EAAE,6BAA6B;IACjD,mBAAmB,EAAE;QACnB,8BAA8B;QAC9B,+CAA+C;QAC/C,qBAAqB;KACtB;IACD,WAAW,EAAE;QACX,+BAA+B;QAC/B,mCAAmC;QACnC,2BAA2B;QAC3B,0BAA0B;KAC3B;IACD,SAAS,EAAE,CAAC,0BAA0B,EAAE,SAAS,EAAE,KAAK,CAAC;IACzD,KAAK,EAAE,OAAO;CACN,CAAC;AAEE,QAAA,YAAY,GAAG;IAC1B,OAAO,EAAE,KAAK;IACd,GAAG,EAAE,KAAK;CACF,CAAC;AAEE,QAAA,cAAc,GAAG;IAC5B,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,QAAQ;CACR,CAAC;AAEE,QAAA,kBAAkB,GAAG;IAChC,mBAAmB,EAAE,EAAE;CACf,CAAC"}
@@ -0,0 +1,51 @@
1
+ export declare class SyncWorktreesError extends Error {
2
+ readonly code: string;
3
+ readonly cause?: Error | undefined;
4
+ constructor(message: string, code: string, cause?: Error | undefined);
5
+ }
6
+ export declare class GitError extends SyncWorktreesError {
7
+ constructor(message: string, code: string, cause?: Error);
8
+ }
9
+ export declare class GitNotInitializedError extends GitError {
10
+ constructor();
11
+ }
12
+ export declare class GitOperationError extends GitError {
13
+ constructor(operation: string, details: string, cause?: Error);
14
+ }
15
+ export declare class FastForwardError extends GitError {
16
+ readonly branchName: string;
17
+ constructor(branchName: string, cause?: Error);
18
+ }
19
+ export declare class WorktreeError extends SyncWorktreesError {
20
+ constructor(message: string, code: string, cause?: Error);
21
+ }
22
+ export declare class WorktreeAlreadyExistsError extends WorktreeError {
23
+ readonly path: string;
24
+ readonly branchName: string;
25
+ constructor(path: string, branchName: string);
26
+ }
27
+ export declare class WorktreeNotCleanError extends WorktreeError {
28
+ readonly path: string;
29
+ readonly reasons: string[];
30
+ constructor(path: string, reasons: string[]);
31
+ }
32
+ export declare class ConfigError extends SyncWorktreesError {
33
+ constructor(message: string, code: string, cause?: Error);
34
+ }
35
+ export declare class ConfigValidationError extends ConfigError {
36
+ readonly field: string;
37
+ readonly reason: string;
38
+ constructor(field: string, reason: string);
39
+ }
40
+ export declare class PathResolutionError extends SyncWorktreesError {
41
+ readonly path: string;
42
+ readonly reason: string;
43
+ constructor(path: string, reason: string);
44
+ }
45
+ export declare class LfsError extends GitError {
46
+ constructor(message: string, cause?: Error);
47
+ }
48
+ export declare function isLfsError(error: Error | string): boolean;
49
+ export declare function isFastForwardError(error: Error | string): boolean;
50
+ export declare function isNoUpstreamError(error: Error | string): boolean;
51
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAEA,qBAAa,kBAAmB,SAAQ,KAAK;aAGzB,IAAI,EAAE,MAAM;aACZ,KAAK,CAAC,EAAE,KAAK;gBAF7B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,KAAK,YAAA;CAShC;AAED,qBAAa,QAAS,SAAQ,kBAAkB;gBAClC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAGzD;AAED,qBAAa,sBAAuB,SAAQ,QAAQ;;CAInD;AAED,qBAAa,iBAAkB,SAAQ,QAAQ;gBACjC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAG9D;AAED,qBAAa,gBAAiB,SAAQ,QAAQ;aAE1B,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM,EAClC,KAAK,CAAC,EAAE,KAAK;CAIhB;AAED,qBAAa,aAAc,SAAQ,kBAAkB;gBACvC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAGzD;AAED,qBAAa,0BAA2B,SAAQ,aAAa;aAEzC,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM;gBADlB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM;CAIrC;AAED,qBAAa,qBAAsB,SAAQ,aAAa;aAEpC,IAAI,EAAE,MAAM;aACZ,OAAO,EAAE,MAAM,EAAE;gBADjB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EAAE;CAIpC;AAED,qBAAa,WAAY,SAAQ,kBAAkB;gBACrC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAGzD;AAED,qBAAa,qBAAsB,SAAQ,WAAW;aAElC,KAAK,EAAE,MAAM;aACb,MAAM,EAAE,MAAM;gBADd,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM;CAIjC;AAED,qBAAa,mBAAoB,SAAQ,kBAAkB;aAEvC,IAAI,EAAE,MAAM;aACZ,MAAM,EAAE,MAAM;gBADd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM;CAIjC;AAED,qBAAa,QAAS,SAAQ,QAAQ;gBACxB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAG3C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAGzD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAGjE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAGhE"}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LfsError = exports.PathResolutionError = exports.ConfigValidationError = exports.ConfigError = exports.WorktreeNotCleanError = exports.WorktreeAlreadyExistsError = exports.WorktreeError = exports.FastForwardError = exports.GitOperationError = exports.GitNotInitializedError = exports.GitError = exports.SyncWorktreesError = void 0;
4
+ exports.isLfsError = isLfsError;
5
+ exports.isFastForwardError = isFastForwardError;
6
+ exports.isNoUpstreamError = isNoUpstreamError;
7
+ const constants_1 = require("../constants");
8
+ class SyncWorktreesError extends Error {
9
+ code;
10
+ cause;
11
+ constructor(message, code, cause) {
12
+ super(message);
13
+ this.code = code;
14
+ this.cause = cause;
15
+ this.name = this.constructor.name;
16
+ Object.setPrototypeOf(this, new.target.prototype);
17
+ if (cause && cause.stack) {
18
+ this.stack = `${this.stack}\nCaused by: ${cause.stack}`;
19
+ }
20
+ }
21
+ }
22
+ exports.SyncWorktreesError = SyncWorktreesError;
23
+ class GitError extends SyncWorktreesError {
24
+ constructor(message, code, cause) {
25
+ super(message, `GIT_${code}`, cause);
26
+ }
27
+ }
28
+ exports.GitError = GitError;
29
+ class GitNotInitializedError extends GitError {
30
+ constructor() {
31
+ super(constants_1.ERROR_MESSAGES.GIT_NOT_INITIALIZED, "NOT_INITIALIZED");
32
+ }
33
+ }
34
+ exports.GitNotInitializedError = GitNotInitializedError;
35
+ class GitOperationError extends GitError {
36
+ constructor(operation, details, cause) {
37
+ super(`Git operation '${operation}' failed: ${details}`, "OPERATION_FAILED", cause);
38
+ }
39
+ }
40
+ exports.GitOperationError = GitOperationError;
41
+ class FastForwardError extends GitError {
42
+ branchName;
43
+ constructor(branchName, cause) {
44
+ super(`Cannot fast-forward branch '${branchName}'`, "FAST_FORWARD_FAILED", cause);
45
+ this.branchName = branchName;
46
+ }
47
+ }
48
+ exports.FastForwardError = FastForwardError;
49
+ class WorktreeError extends SyncWorktreesError {
50
+ constructor(message, code, cause) {
51
+ super(message, `WORKTREE_${code}`, cause);
52
+ }
53
+ }
54
+ exports.WorktreeError = WorktreeError;
55
+ class WorktreeAlreadyExistsError extends WorktreeError {
56
+ path;
57
+ branchName;
58
+ constructor(path, branchName) {
59
+ super(`Worktree already exists at '${path}' for branch '${branchName}'`, "ALREADY_EXISTS");
60
+ this.path = path;
61
+ this.branchName = branchName;
62
+ }
63
+ }
64
+ exports.WorktreeAlreadyExistsError = WorktreeAlreadyExistsError;
65
+ class WorktreeNotCleanError extends WorktreeError {
66
+ path;
67
+ reasons;
68
+ constructor(path, reasons) {
69
+ super(`Worktree at '${path}' is not clean: ${reasons.join(", ")}`, "NOT_CLEAN");
70
+ this.path = path;
71
+ this.reasons = reasons;
72
+ }
73
+ }
74
+ exports.WorktreeNotCleanError = WorktreeNotCleanError;
75
+ class ConfigError extends SyncWorktreesError {
76
+ constructor(message, code, cause) {
77
+ super(message, `CONFIG_${code}`, cause);
78
+ }
79
+ }
80
+ exports.ConfigError = ConfigError;
81
+ class ConfigValidationError extends ConfigError {
82
+ field;
83
+ reason;
84
+ constructor(field, reason) {
85
+ super(`Invalid configuration for '${field}': ${reason}`, "VALIDATION_FAILED");
86
+ this.field = field;
87
+ this.reason = reason;
88
+ }
89
+ }
90
+ exports.ConfigValidationError = ConfigValidationError;
91
+ class PathResolutionError extends SyncWorktreesError {
92
+ path;
93
+ reason;
94
+ constructor(path, reason) {
95
+ super(`Path resolution failed for '${path}': ${reason}`, "PATH_RESOLUTION_FAILED");
96
+ this.path = path;
97
+ this.reason = reason;
98
+ }
99
+ }
100
+ exports.PathResolutionError = PathResolutionError;
101
+ class LfsError extends GitError {
102
+ constructor(message, cause) {
103
+ super(`LFS operation failed: ${message}`, "LFS_ERROR", cause);
104
+ }
105
+ }
106
+ exports.LfsError = LfsError;
107
+ function isLfsError(error) {
108
+ const message = typeof error === "string" ? error : error.message;
109
+ return constants_1.ERROR_MESSAGES.LFS_ERROR.some((pattern) => message.includes(pattern));
110
+ }
111
+ function isFastForwardError(error) {
112
+ const message = typeof error === "string" ? error : error.message;
113
+ return constants_1.ERROR_MESSAGES.FAST_FORWARD_FAILED.some((pattern) => message.includes(pattern));
114
+ }
115
+ function isNoUpstreamError(error) {
116
+ const message = typeof error === "string" ? error : error.message;
117
+ return constants_1.ERROR_MESSAGES.NO_UPSTREAM.some((pattern) => message.includes(pattern));
118
+ }
119
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":";;;AAkGA,gCAGC;AAED,gDAGC;AAED,8CAGC;AA/GD,4CAA8C;AAE9C,MAAa,kBAAmB,SAAQ,KAAK;IAGzB;IACA;IAHlB,YACE,OAAe,EACC,IAAY,EACZ,KAAa;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAQ;QACZ,UAAK,GAAL,KAAK,CAAQ;QAG7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,KAAK,gBAAgB,KAAK,CAAC,KAAK,EAAE,CAAC;QAC1D,CAAC;IACH,CAAC;CACF;AAbD,gDAaC;AAED,MAAa,QAAS,SAAQ,kBAAkB;IAC9C,YAAY,OAAe,EAAE,IAAY,EAAE,KAAa;QACtD,KAAK,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;IACvC,CAAC;CACF;AAJD,4BAIC;AAED,MAAa,sBAAuB,SAAQ,QAAQ;IAClD;QACE,KAAK,CAAC,0BAAc,CAAC,mBAAmB,EAAE,iBAAiB,CAAC,CAAC;IAC/D,CAAC;CACF;AAJD,wDAIC;AAED,MAAa,iBAAkB,SAAQ,QAAQ;IAC7C,YAAY,SAAiB,EAAE,OAAe,EAAE,KAAa;QAC3D,KAAK,CAAC,kBAAkB,SAAS,aAAa,OAAO,EAAE,EAAE,kBAAkB,EAAE,KAAK,CAAC,CAAC;IACtF,CAAC;CACF;AAJD,8CAIC;AAED,MAAa,gBAAiB,SAAQ,QAAQ;IAE1B;IADlB,YACkB,UAAkB,EAClC,KAAa;QAEb,KAAK,CAAC,+BAA+B,UAAU,GAAG,EAAE,qBAAqB,EAAE,KAAK,CAAC,CAAC;QAHlE,eAAU,GAAV,UAAU,CAAQ;IAIpC,CAAC;CACF;AAPD,4CAOC;AAED,MAAa,aAAc,SAAQ,kBAAkB;IACnD,YAAY,OAAe,EAAE,IAAY,EAAE,KAAa;QACtD,KAAK,CAAC,OAAO,EAAE,YAAY,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC;CACF;AAJD,sCAIC;AAED,MAAa,0BAA2B,SAAQ,aAAa;IAEzC;IACA;IAFlB,YACkB,IAAY,EACZ,UAAkB;QAElC,KAAK,CAAC,+BAA+B,IAAI,iBAAiB,UAAU,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAH3E,SAAI,GAAJ,IAAI,CAAQ;QACZ,eAAU,GAAV,UAAU,CAAQ;IAGpC,CAAC;CACF;AAPD,gEAOC;AAED,MAAa,qBAAsB,SAAQ,aAAa;IAEpC;IACA;IAFlB,YACkB,IAAY,EACZ,OAAiB;QAEjC,KAAK,CAAC,gBAAgB,IAAI,mBAAmB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;QAHhE,SAAI,GAAJ,IAAI,CAAQ;QACZ,YAAO,GAAP,OAAO,CAAU;IAGnC,CAAC;CACF;AAPD,sDAOC;AAED,MAAa,WAAY,SAAQ,kBAAkB;IACjD,YAAY,OAAe,EAAE,IAAY,EAAE,KAAa;QACtD,KAAK,CAAC,OAAO,EAAE,UAAU,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;IAC1C,CAAC;CACF;AAJD,kCAIC;AAED,MAAa,qBAAsB,SAAQ,WAAW;IAElC;IACA;IAFlB,YACkB,KAAa,EACb,MAAc;QAE9B,KAAK,CAAC,8BAA8B,KAAK,MAAM,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC;QAH9D,UAAK,GAAL,KAAK,CAAQ;QACb,WAAM,GAAN,MAAM,CAAQ;IAGhC,CAAC;CACF;AAPD,sDAOC;AAED,MAAa,mBAAoB,SAAQ,kBAAkB;IAEvC;IACA;IAFlB,YACkB,IAAY,EACZ,MAAc;QAE9B,KAAK,CAAC,+BAA+B,IAAI,MAAM,MAAM,EAAE,EAAE,wBAAwB,CAAC,CAAC;QAHnE,SAAI,GAAJ,IAAI,CAAQ;QACZ,WAAM,GAAN,MAAM,CAAQ;IAGhC,CAAC;CACF;AAPD,kDAOC;AAED,MAAa,QAAS,SAAQ,QAAQ;IACpC,YAAY,OAAe,EAAE,KAAa;QACxC,KAAK,CAAC,yBAAyB,OAAO,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC;CACF;AAJD,4BAIC;AAED,SAAgB,UAAU,CAAC,KAAqB;IAC9C,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IAClE,OAAO,0BAAc,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,SAAgB,kBAAkB,CAAC,KAAqB;IACtD,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IAClE,OAAO,0BAAc,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACzF,CAAC;AAED,SAAgB,iBAAiB,CAAC,KAAqB;IACrD,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IAClE,OAAO,0BAAc,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACjF,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import type { Config } from "../types";
2
+ import type { SyncMetadata } from "../types/sync-metadata";
2
3
  import type { SimpleGit } from "simple-git";
3
4
  export declare class GitService {
4
5
  private config;
@@ -44,6 +45,7 @@ export declare class GitService {
44
45
  resetToUpstream(worktreePath: string, branch: string): Promise<void>;
45
46
  getCurrentCommit(worktreePath: string): Promise<string>;
46
47
  getRemoteCommit(ref: string): Promise<string>;
48
+ getWorktreeMetadata(worktreePath: string): Promise<SyncMetadata | null>;
47
49
  private getWorktreesFromBare;
48
50
  }
49
51
  //# sourceMappingURL=git.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"git.service.d.ts","sourceRoot":"","sources":["../../src/services/git.service.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,qBAAa,UAAU;IAOT,OAAO,CAAC,MAAM;IAN1B,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,eAAe,CAA0B;gBAE7B,MAAM,EAAE,MAAM;IAM5B,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC;IA6HtC,MAAM,IAAI,SAAS;IAOnB,gBAAgB,IAAI,MAAM;IAIpB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAWzB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9C,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAStC,6BAA6B,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,IAAI,CAAA;KAAE,EAAE,CAAC;YAkC1E,sBAAsB;IAqB9B,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyHpE,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BnD,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAMnD,cAAc;IAStB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAyC1D,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA6CvD,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYzD,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW7D,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA+B9D,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;YAM3B,mBAAmB;IAsCjC,OAAO,CAAC,gBAAgB;IAIlB,YAAY,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAK3D,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBxD,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BnD,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBlF,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBtE,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAe1E,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpE,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMvD,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAOrC,oBAAoB;CAiCnC"}
1
+ {"version":3,"file":"git.service.d.ts","sourceRoot":"","sources":["../../src/services/git.service.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,qBAAa,UAAU;IAOT,OAAO,CAAC,MAAM;IAN1B,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,eAAe,CAA0B;gBAE7B,MAAM,EAAE,MAAM;IAM5B,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC;IA6HtC,MAAM,IAAI,SAAS;IAOnB,gBAAgB,IAAI,MAAM;IAIpB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAWzB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9C,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAStC,6BAA6B,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,IAAI,CAAA;KAAE,EAAE,CAAC;YAkC1E,sBAAsB;IAsB9B,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8HpE,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcnD,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAMnD,cAAc;IAStB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAyC1D,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkEvD,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYzD,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW7D,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA+B9D,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;YAM3B,mBAAmB;IAsCjC,OAAO,CAAC,gBAAgB;IAIlB,YAAY,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAK3D,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBxD,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCnD,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBlF,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBtE,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAe1E,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBpE,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMvD,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO7C,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;YAI/D,oBAAoB;CAiCnC"}
@@ -41,6 +41,7 @@ const fs = __importStar(require("fs/promises"));
41
41
  const path = __importStar(require("path"));
42
42
  const simple_git_1 = __importDefault(require("simple-git"));
43
43
  const git_url_1 = require("../utils/git-url");
44
+ const lfs_error_1 = require("../utils/lfs-error");
44
45
  const worktree_metadata_service_1 = require("./worktree-metadata.service");
45
46
  class GitService {
46
47
  config;
@@ -132,7 +133,7 @@ class GitService {
132
133
  }
133
134
  }
134
135
  catch (error) {
135
- const errorMessage = error instanceof Error ? error.message : String(error);
136
+ const errorMessage = (0, lfs_error_1.getErrorMessage)(error);
136
137
  // Check if error is because directory already exists
137
138
  if (errorMessage.includes("already exists")) {
138
139
  console.log(`${this.defaultBranch} worktree directory already exists at '${absoluteWorktreePath}', skipping creation.`);
@@ -144,7 +145,7 @@ class GitService {
144
145
  await bareGit.raw(["worktree", "add", absoluteWorktreePath, this.defaultBranch]);
145
146
  }
146
147
  catch (fallbackError) {
147
- const fallbackErrorMessage = fallbackError instanceof Error ? fallbackError.message : String(fallbackError);
148
+ const fallbackErrorMessage = (0, lfs_error_1.getErrorMessage)(fallbackError);
148
149
  if (fallbackErrorMessage.includes("already exists")) {
149
150
  console.log(`${this.defaultBranch} worktree directory already exists at '${absoluteWorktreePath}', skipping creation.`);
150
151
  }
@@ -242,10 +243,11 @@ class GitService {
242
243
  : (0, simple_git_1.default)(worktreePath);
243
244
  const currentCommit = await worktreeGit.revparse(["HEAD"]);
244
245
  const parentCommit = await bareGit.revparse([this.defaultBranch]);
245
- await this.metadataService.createInitialMetadata(this.bareRepoPath, branchName, currentCommit.trim(), `origin/${branchName}`, this.defaultBranch, parentCommit.trim());
246
+ await this.metadataService.createInitialMetadataFromPath(this.bareRepoPath, worktreePath, currentCommit.trim(), `origin/${branchName}`, this.defaultBranch, parentCommit.trim());
246
247
  }
247
248
  catch (metadataError) {
248
- console.warn(` - Failed to create metadata for worktree: ${metadataError}`);
249
+ console.error(` - Failed to create metadata for '${branchName}': ${metadataError}`);
250
+ throw new Error(`Metadata creation failed for ${branchName}. This worktree cannot be auto-managed.`);
249
251
  }
250
252
  }
251
253
  async addWorktree(branchName, worktreePath) {
@@ -303,7 +305,11 @@ class GitService {
303
305
  await this.createWorktreeMetadata(bareGit, absoluteWorktreePath, branchName);
304
306
  }
305
307
  catch (error) {
306
- const errorMessage = error instanceof Error ? error.message : String(error);
308
+ const errorMessage = (0, lfs_error_1.getErrorMessage)(error);
309
+ // Re-throw metadata creation errors - these are fatal and should not fall back
310
+ if (errorMessage.includes("Metadata creation failed")) {
311
+ throw error;
312
+ }
307
313
  // Check if this is an "already registered" error
308
314
  if (errorMessage.includes("already registered worktree")) {
309
315
  console.warn(` - Worktree already registered but missing. Pruning and retrying...`);
@@ -365,27 +371,14 @@ class GitService {
365
371
  }
366
372
  async removeWorktree(worktreePath) {
367
373
  const bareGit = (0, simple_git_1.default)(this.bareRepoPath);
368
- // Try to get branch name before removing worktree
369
- let branchName = null;
370
- try {
371
- const worktrees = await this.getWorktreesFromBare(bareGit);
372
- const worktree = worktrees.find((w) => path.resolve(w.path) === path.resolve(worktreePath));
373
- branchName = worktree?.branch || null;
374
- }
375
- catch {
376
- // If we can't get the branch name, extract from path as fallback
377
- branchName = path.basename(worktreePath);
378
- }
379
374
  await bareGit.raw(["worktree", "remove", worktreePath, "--force"]);
380
375
  console.log(` - ✅ Safely removed stale worktree at '${worktreePath}'.`);
381
- // Clean up metadata
382
- if (branchName) {
383
- try {
384
- await this.metadataService.deleteMetadata(this.bareRepoPath, branchName);
385
- }
386
- catch (metadataError) {
387
- console.warn(`Failed to delete metadata for worktree: ${metadataError}`);
388
- }
376
+ // Clean up metadata using the worktree path
377
+ try {
378
+ await this.metadataService.deleteMetadataFromPath(this.bareRepoPath, worktreePath);
379
+ }
380
+ catch (metadataError) {
381
+ console.warn(`Failed to delete metadata for worktree: ${metadataError}`);
389
382
  }
390
383
  }
391
384
  async pruneWorktrees() {
@@ -420,8 +413,8 @@ class GitService {
420
413
  // Check if upstream is gone
421
414
  const upstreamGone = await this.hasUpstreamGone(worktreePath);
422
415
  if (upstreamGone) {
423
- // Load metadata to check for commits after last sync
424
- const metadata = await this.metadataService.loadMetadata(this.bareRepoPath, currentBranch);
416
+ // Load metadata to check for commits after last sync (use path-based method)
417
+ const metadata = await this.metadataService.loadMetadataFromPath(this.bareRepoPath, worktreePath);
425
418
  if (metadata?.lastSyncCommit) {
426
419
  try {
427
420
  // Check for commits after last sync
@@ -461,22 +454,38 @@ class GitService {
461
454
  return !remoteBranches.all.includes(upstream.trim());
462
455
  }
463
456
  catch (error) {
464
- // Check if the error is because of no upstream configured
465
- const errorMessage = error instanceof Error ? error.message : String(error);
466
- // Match specific Git error messages for missing upstream
457
+ const errorMessage = (0, lfs_error_1.getErrorMessage)(error);
467
458
  if (errorMessage.includes("fatal: no upstream configured") ||
468
- errorMessage.includes("no upstream configured for branch") ||
469
- errorMessage.includes("fatal: ambiguous argument") ||
470
- errorMessage.includes("unknown revision or path")) {
471
- // This is expected when there's no upstream - not an error condition
459
+ errorMessage.includes("no upstream configured for branch")) {
460
+ return false;
461
+ }
462
+ if (errorMessage.includes("fatal: ambiguous argument") || errorMessage.includes("unknown revision or path")) {
463
+ try {
464
+ const branchSummary = await worktreeGit.branch();
465
+ const currentBranch = branchSummary.current;
466
+ const remoteResult = await worktreeGit
467
+ .raw(["config", "--get", `branch.${currentBranch}.remote`])
468
+ .catch(() => "");
469
+ const mergeResult = await worktreeGit
470
+ .raw(["config", "--get", `branch.${currentBranch}.merge`])
471
+ .catch(() => "");
472
+ const remote = remoteResult.trim();
473
+ const merge = mergeResult.trim();
474
+ if (remote && merge) {
475
+ const remoteBranchName = merge.replace("refs/heads/", "");
476
+ const expectedUpstream = `${remote}/${remoteBranchName}`;
477
+ const remoteBranches = await worktreeGit.branch(["-r"]);
478
+ return !remoteBranches.all.includes(expectedUpstream);
479
+ }
480
+ }
481
+ catch {
482
+ // Can't determine config, be conservative
483
+ }
472
484
  return false;
473
485
  }
474
- // Log unexpected errors that don't match known patterns
475
486
  console.error(`Unexpected error checking upstream status for ${worktreePath}. ` +
476
487
  `This might indicate a real issue rather than a missing upstream. ` +
477
488
  `Error: ${errorMessage}`);
478
- // Return false to be safe - we don't want to accidentally delete worktrees
479
- // due to transient errors
480
489
  return false;
481
490
  }
482
491
  }
@@ -619,10 +628,10 @@ class GitService {
619
628
  if (isMainWorktree) {
620
629
  return;
621
630
  }
622
- // Update metadata after successful update
631
+ // Update metadata after successful update (use path-based method)
623
632
  try {
624
633
  const currentCommit = await worktreeGit.revparse(["HEAD"]);
625
- await this.metadataService.updateLastSync(this.bareRepoPath, currentBranch, currentCommit.trim(), "updated");
634
+ await this.metadataService.updateLastSyncFromPath(this.bareRepoPath, worktreePath, currentCommit.trim(), "updated", this.defaultBranch);
626
635
  }
627
636
  catch (metadataError) {
628
637
  console.warn(`Failed to update metadata for worktree: ${metadataError}`);
@@ -681,10 +690,10 @@ class GitService {
681
690
  ? (0, simple_git_1.default)(worktreePath).env({ GIT_LFS_SKIP_SMUDGE: "1" })
682
691
  : (0, simple_git_1.default)(worktreePath);
683
692
  await worktreeGit.reset(["--hard", `origin/${branch}`]);
684
- // Update metadata after reset
693
+ // Update metadata after reset (use path-based method)
685
694
  try {
686
695
  const currentCommit = await worktreeGit.revparse(["HEAD"]);
687
- await this.metadataService.updateLastSync(this.bareRepoPath, branch, currentCommit.trim(), "updated");
696
+ await this.metadataService.updateLastSyncFromPath(this.bareRepoPath, worktreePath, currentCommit.trim(), "updated", this.defaultBranch);
688
697
  }
689
698
  catch (metadataError) {
690
699
  console.warn(`Failed to update metadata after reset: ${metadataError}`);
@@ -701,6 +710,9 @@ class GitService {
701
710
  const commit = await git.revparse([ref]);
702
711
  return commit.trim();
703
712
  }
713
+ async getWorktreeMetadata(worktreePath) {
714
+ return this.metadataService.loadMetadataFromPath(this.bareRepoPath, worktreePath);
715
+ }
704
716
  async getWorktreesFromBare(bareGit) {
705
717
  const result = await bareGit.raw(["worktree", "list", "--porcelain"]);
706
718
  const worktrees = [];