@mrpatronz/nexusflow 0.2.18 → 0.2.19

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 (73) hide show
  1. package/dist/commands/sync.d.ts.map +1 -1
  2. package/dist/commands/sync.js +37 -50
  3. package/dist/commands/sync.js.map +1 -1
  4. package/dist/core/sync.d.ts +44 -0
  5. package/dist/core/sync.d.ts.map +1 -0
  6. package/dist/core/sync.js +82 -0
  7. package/dist/core/sync.js.map +1 -0
  8. package/dist/core/workspace-state.d.ts +51 -0
  9. package/dist/core/workspace-state.d.ts.map +1 -0
  10. package/dist/core/workspace-state.js +108 -0
  11. package/dist/core/workspace-state.js.map +1 -0
  12. package/dist/core/workspace-state.test.d.ts +2 -0
  13. package/dist/core/workspace-state.test.d.ts.map +1 -0
  14. package/dist/core/workspace-state.test.js +84 -0
  15. package/dist/core/workspace-state.test.js.map +1 -0
  16. package/dist/gui/assets/index-Bdbld6yY.css +1 -0
  17. package/dist/gui/assets/index-D8iJPvnk.js +26 -0
  18. package/dist/gui/index.html +2 -2
  19. package/dist/mcp/server.d.ts.map +1 -1
  20. package/dist/mcp/server.js +42 -0
  21. package/dist/mcp/server.js.map +1 -1
  22. package/dist/server.d.ts.map +1 -1
  23. package/dist/server.js +94 -13
  24. package/dist/server.js.map +1 -1
  25. package/dist/types.d.ts +31 -0
  26. package/dist/types.d.ts.map +1 -1
  27. package/dist/utils/multi-git.d.ts +33 -8
  28. package/dist/utils/multi-git.d.ts.map +1 -1
  29. package/dist/utils/multi-git.js +91 -19
  30. package/dist/utils/multi-git.js.map +1 -1
  31. package/dist/utils/multi-git.test.d.ts +2 -0
  32. package/dist/utils/multi-git.test.d.ts.map +1 -0
  33. package/dist/utils/multi-git.test.js +125 -0
  34. package/dist/utils/multi-git.test.js.map +1 -0
  35. package/gui/e2e/dashboard.spec.ts +61 -0
  36. package/gui/e2e/wizard.spec.ts +2 -2
  37. package/gui/package-lock.json +62 -4
  38. package/gui/package.json +2 -1
  39. package/gui/src/App.tsx +168 -227
  40. package/gui/src/app/AppSidebar.tsx +69 -0
  41. package/gui/src/components/AddRepoPicker.tsx +81 -0
  42. package/gui/src/components/ui/Button.tsx +40 -0
  43. package/gui/src/components/ui/Card.tsx +6 -0
  44. package/gui/src/components/ui/EmptyState.tsx +22 -0
  45. package/gui/src/components/ui/Input.tsx +21 -0
  46. package/gui/src/components/ui/Menu.tsx +71 -0
  47. package/gui/src/components/ui/Modal.tsx +39 -0
  48. package/gui/src/components/ui/PageHeader.tsx +21 -0
  49. package/gui/src/components/ui/RepoStatusStrip.tsx +33 -0
  50. package/gui/src/components/ui/Skeleton.tsx +5 -0
  51. package/gui/src/components/ui/StatusPill.tsx +36 -0
  52. package/gui/src/components/ui/Tabs.tsx +40 -0
  53. package/gui/src/components/ui/cn.ts +4 -0
  54. package/gui/src/components/ui/index.ts +16 -0
  55. package/gui/src/features/services/ServiceConsole.tsx +4 -39
  56. package/gui/src/index.css +140 -125
  57. package/gui/src/lib/status.ts +24 -0
  58. package/gui/src/pages/DashboardPage.tsx +129 -0
  59. package/gui/src/pages/WorkspacesPage.tsx +352 -0
  60. package/gui/src/types.ts +19 -0
  61. package/package.json +1 -1
  62. package/src/commands/sync.ts +36 -58
  63. package/src/core/sync.ts +121 -0
  64. package/src/core/workspace-state.test.ts +108 -0
  65. package/src/core/workspace-state.ts +130 -0
  66. package/src/mcp/server.ts +44 -0
  67. package/src/server.ts +103 -15
  68. package/src/types.ts +36 -0
  69. package/src/utils/multi-git.test.ts +158 -0
  70. package/src/utils/multi-git.ts +117 -25
  71. package/dist/gui/assets/index-CB-jWded.css +0 -1
  72. package/dist/gui/assets/index-DDXpZZu3.js +0 -25
  73. package/gui/src/features/workspace/WorkspaceList.tsx +0 -666
@@ -5,6 +5,8 @@
5
5
  * Provides helpers for querying repo status, rebasing, committing, pushing,
6
6
  * and generating diff summaries across all repos in a NexusFlow workspace.
7
7
  */
8
+ import type { SyncStatus } from '../types.js';
9
+ export type { SyncStatus };
8
10
  /** Metadata about a single repo within a workspace. */
9
11
  export interface WorkspaceRepo {
10
12
  /** Directory name of the repo (e.g. 'api-gateway'). */
@@ -25,14 +27,32 @@ export interface RepoStatus {
25
27
  /** Human-readable summary, e.g. '3 files changed'. */
26
28
  summary: string;
27
29
  }
28
- /** Result of a rebase operation. */
30
+ /**
31
+ * Result of a rebase operation.
32
+ *
33
+ * The classified {@link SyncStatus} values mean:
34
+ * - `up-to-date` — branch already contained the latest base commits.
35
+ * - `rebased` — new base commits were applied cleanly.
36
+ * - `conflict` — a genuine merge conflict; the rebase was aborted.
37
+ * - `stash-conflict` — the rebase succeeded but re-applying auto-stashed local
38
+ * changes conflicted; the stash is preserved for manual merge.
39
+ * - `error` — an infrastructure failure (network/auth on fetch, etc.) that
40
+ * is *not* a merge conflict.
41
+ */
29
42
  export interface RebaseResult {
30
- /** Whether the rebase completed without conflicts. */
43
+ /**
44
+ * Whether the rebase itself completed. True for `up-to-date`, `rebased`, and
45
+ * `stash-conflict` (the rebase landed; only the stash pop needs attention).
46
+ */
31
47
  success: boolean;
48
+ /** Classified outcome. */
49
+ status: SyncStatus;
32
50
  /** Human-readable outcome message. */
33
51
  message: string;
34
- /** Stderr output when a conflict is detected. */
52
+ /** Stderr output populated only for `status === 'conflict'`. */
35
53
  conflict?: string;
54
+ /** Whether dirty working-tree changes were auto-stashed during the operation. */
55
+ stashed?: boolean;
36
56
  }
37
57
  /** Result of a commit-and-push operation. */
38
58
  export interface CommitResult {
@@ -74,15 +94,20 @@ export declare function getWorkspaceRepos(workspacePath: string): Promise<Worksp
74
94
  */
75
95
  export declare function getRepoStatus(repoPath: string): Promise<RepoStatus>;
76
96
  /**
77
- * Rebases the current branch on top of the latest upstream base branch.
97
+ * Rebases the current branch on top of the latest upstream base branch, while
98
+ * safely preserving any uncommitted local changes.
99
+ *
100
+ * Unlike a bare `git rebase`, this is safe to call from non-interactive agents
101
+ * against a *dirty* working tree: dirty changes are stashed first and restored
102
+ * afterwards. The outcome is classified (see {@link SyncStatus}) so that a dirty
103
+ * tree or a network failure is never mis-reported as a merge conflict.
78
104
  *
79
- * Fetches from origin first, then attempts `git rebase origin/{baseBranch}`.
80
- * If a conflict occurs the rebase is aborted and the conflict details are
81
- * returned.
105
+ * Sequence: `git fetch` (stash if dirty) → `git rebase origin/{base}` →
106
+ * (pop the stash if one was made).
82
107
  *
83
108
  * @param repoPath - Absolute path to the repo root.
84
109
  * @param baseBranch - The upstream branch to rebase onto (e.g. 'main').
85
- * @returns Result indicating success or conflict information.
110
+ * @returns Classified result; `conflict` text is set only for real merge conflicts.
86
111
  */
87
112
  export declare function rebaseRepo(repoPath: string, baseBranch: string): Promise<RebaseResult>;
88
113
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"multi-git.d.ts","sourceRoot":"","sources":["../../src/utils/multi-git.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,iEAAiE;IACjE,UAAU,EAAE,OAAO,CAAC;IACpB,0DAA0D;IAC1D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,OAAO,EAAE,OAAO,CAAC;IACjB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,OAAO,EAAE,OAAO,CAAC;IACjB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;CACnB;AA8BD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,EAAE,CAAC,CAkB1B;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAwBzE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,CAAC,CAuCvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,OAAO,CAAC,YAAY,CAAC,CAmCvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAiC3E"}
1
+ {"version":3,"file":"multi-git.d.ts","sourceRoot":"","sources":["../../src/utils/multi-git.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,aAAa,CAAC;AAGvD,YAAY,EAAE,UAAU,EAAE,CAAC;AAI3B,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,iEAAiE;IACjE,UAAU,EAAE,OAAO,CAAC;IACpB,0DAA0D;IAC1D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,0BAA0B;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,OAAO,EAAE,OAAO,CAAC;IACjB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;CACnB;AA8BD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,EAAE,CAAC,CAkB1B;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAwBzE;AAaD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,CAAC,CA+FvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,OAAO,CAAC,YAAY,CAAC,CAmCvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAiC3E"}
@@ -89,47 +89,119 @@ export async function getRepoStatus(repoPath) {
89
89
  }
90
90
  }
91
91
  /**
92
- * Rebases the current branch on top of the latest upstream base branch.
92
+ * Extracts the stderr (falling back to the message) from a thrown execa error.
93
+ */
94
+ function errText(error) {
95
+ if (error instanceof Error && 'stderr' in error) {
96
+ const stderr = String(error.stderr).trim();
97
+ if (stderr)
98
+ return stderr;
99
+ }
100
+ return error instanceof Error ? error.message : String(error);
101
+ }
102
+ /**
103
+ * Rebases the current branch on top of the latest upstream base branch, while
104
+ * safely preserving any uncommitted local changes.
105
+ *
106
+ * Unlike a bare `git rebase`, this is safe to call from non-interactive agents
107
+ * against a *dirty* working tree: dirty changes are stashed first and restored
108
+ * afterwards. The outcome is classified (see {@link SyncStatus}) so that a dirty
109
+ * tree or a network failure is never mis-reported as a merge conflict.
93
110
  *
94
- * Fetches from origin first, then attempts `git rebase origin/{baseBranch}`.
95
- * If a conflict occurs the rebase is aborted and the conflict details are
96
- * returned.
111
+ * Sequence: `git fetch` (stash if dirty) → `git rebase origin/{base}` →
112
+ * (pop the stash if one was made).
97
113
  *
98
114
  * @param repoPath - Absolute path to the repo root.
99
115
  * @param baseBranch - The upstream branch to rebase onto (e.g. 'main').
100
- * @returns Result indicating success or conflict information.
116
+ * @returns Classified result; `conflict` text is set only for real merge conflicts.
101
117
  */
102
118
  export async function rebaseRepo(repoPath, baseBranch) {
119
+ // 1. Fetch latest from origin. A failure here is infrastructure (network/auth),
120
+ // not a conflict.
103
121
  try {
104
- // Fetch latest from origin.
105
122
  await execa('git', ['fetch', 'origin'], { cwd: repoPath });
106
- // Attempt rebase.
123
+ }
124
+ catch (error) {
125
+ return {
126
+ success: false,
127
+ status: 'error',
128
+ message: `Fetch failed: ${errText(error).split('\n')[0]}`,
129
+ };
130
+ }
131
+ // 2. Stash dirty changes (including untracked) so the rebase has a clean tree.
132
+ let stashed = false;
133
+ const status = await getRepoStatus(repoPath);
134
+ if (status.hasChanges) {
135
+ try {
136
+ await execa('git', ['stash', 'push', '-u', '-m', 'nexusflow-autostash'], { cwd: repoPath });
137
+ stashed = true;
138
+ }
139
+ catch (error) {
140
+ return {
141
+ success: false,
142
+ status: 'error',
143
+ message: `Failed to stash local changes: ${errText(error).split('\n')[0]}`,
144
+ };
145
+ }
146
+ }
147
+ // 3. Attempt the rebase.
148
+ let rebaseStatus;
149
+ let rebaseMessage;
150
+ try {
107
151
  const { stdout } = await execa('git', ['rebase', `origin/${baseBranch}`], { cwd: repoPath });
108
- // Determine how far ahead the branch is.
109
- const message = stdout.includes('up to date')
110
- ? 'Up to date'
111
- : stdout.includes('Applied')
112
- ? stdout.trim()
113
- : 'Rebased successfully';
114
- return { success: true, message };
152
+ if (stdout.includes('up to date') || stdout.includes('up-to-date')) {
153
+ rebaseStatus = 'up-to-date';
154
+ rebaseMessage = 'Up to date';
155
+ }
156
+ else {
157
+ rebaseStatus = 'rebased';
158
+ rebaseMessage = 'Rebased onto latest base';
159
+ }
115
160
  }
116
161
  catch (error) {
117
- // Abort the in-progress rebase so the repo isn't left in a broken state.
162
+ // Genuine merge conflict (or other rebase failure). Abort so the repo is
163
+ // never left mid-rebase, then restore the user's stashed work.
118
164
  try {
119
165
  await execa('git', ['rebase', '--abort'], { cwd: repoPath });
120
166
  }
121
167
  catch {
122
168
  // Best-effort abort; ignore if it fails.
123
169
  }
124
- const stderr = error instanceof Error && 'stderr' in error
125
- ? String(error.stderr)
126
- : String(error);
170
+ if (stashed) {
171
+ try {
172
+ await execa('git', ['stash', 'pop'], { cwd: repoPath });
173
+ }
174
+ catch {
175
+ // Stash pop after an abort should normally succeed (tree is unchanged);
176
+ // if it doesn't, the stash is preserved for manual recovery.
177
+ }
178
+ }
127
179
  return {
128
180
  success: false,
181
+ status: 'conflict',
129
182
  message: 'Conflict during rebase',
130
- conflict: stderr,
183
+ conflict: errText(error),
184
+ stashed,
131
185
  };
132
186
  }
187
+ // 4. Restore stashed local changes, if any.
188
+ if (stashed) {
189
+ try {
190
+ await execa('git', ['stash', 'pop'], { cwd: repoPath });
191
+ }
192
+ catch (error) {
193
+ // The rebase landed, but re-applying local changes conflicts. `git stash
194
+ // pop` leaves the stash in place on conflict, so the work is not lost.
195
+ return {
196
+ success: true,
197
+ status: 'stash-conflict',
198
+ message: 'Rebased; local changes need manual merge — stash preserved',
199
+ conflict: errText(error),
200
+ stashed,
201
+ };
202
+ }
203
+ }
204
+ return { success: true, status: rebaseStatus, message: rebaseMessage, stashed };
133
205
  }
134
206
  /**
135
207
  * Stages all changes, commits with the given message, and pushes to origin.
@@ -1 +1 @@
1
- {"version":3,"file":"multi-git.js","sourceRoot":"","sources":["../../src/utils/multi-git.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"multi-git.js","sourceRoot":"","sources":["../../src/utils/multi-git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=multi-git.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-git.test.d.ts","sourceRoot":"","sources":["../../src/utils/multi-git.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,125 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { execa } from 'execa';
3
+ import { rebaseRepo } from './multi-git.js';
4
+ vi.mock('execa');
5
+ /** Builds an execa-style error carrying stderr (as execa does on non-zero exit). */
6
+ function gitError(stderr) {
7
+ return Object.assign(new Error('git failed'), { stderr });
8
+ }
9
+ /** Resolves a single mocked `git` call by subcommand. */
10
+ async function routeGit(a, opts) {
11
+ const sub = a[0];
12
+ if (sub === 'fetch') {
13
+ if (opts.fetchError)
14
+ throw opts.fetchError;
15
+ return { stdout: '' };
16
+ }
17
+ if (sub === 'status') {
18
+ return { stdout: opts.statusStdout ?? '' };
19
+ }
20
+ if (sub === 'stash' && a[1] === 'push') {
21
+ if (opts.stashPushError)
22
+ throw opts.stashPushError;
23
+ return { stdout: '' };
24
+ }
25
+ if (sub === 'stash' && a[1] === 'pop') {
26
+ if (opts.stashPopError)
27
+ throw opts.stashPopError;
28
+ return { stdout: '' };
29
+ }
30
+ if (sub === 'rebase' && a[1] === '--abort') {
31
+ return { stdout: '' };
32
+ }
33
+ if (sub === 'rebase') {
34
+ if (opts.rebaseError)
35
+ throw opts.rebaseError;
36
+ return { stdout: opts.rebaseStdout ?? 'Successfully rebased.' };
37
+ }
38
+ return { stdout: '' };
39
+ }
40
+ /** Routes mocked `git` calls by subcommand so each test declares only what matters. */
41
+ function mockGit(opts) {
42
+ vi.mocked(execa).mockImplementation(((_file, args) => routeGit(args, opts)));
43
+ }
44
+ /** Returns the recorded execa calls as arrays of git args. */
45
+ function gitCalls() {
46
+ return vi.mocked(execa).mock.calls.map((c) => c[1]);
47
+ }
48
+ describe('rebaseRepo', () => {
49
+ beforeEach(() => {
50
+ vi.clearAllMocks();
51
+ });
52
+ it('reports "rebased" for a clean tree with new base commits', async () => {
53
+ mockGit({ statusStdout: '', rebaseStdout: 'Successfully rebased and updated.' });
54
+ const result = await rebaseRepo('/repo', 'main');
55
+ expect(result.success).toBe(true);
56
+ expect(result.status).toBe('rebased');
57
+ expect(result.stashed).toBeFalsy();
58
+ // No stash should be created for a clean tree.
59
+ expect(gitCalls().some((c) => c[0] === 'stash')).toBe(false);
60
+ });
61
+ it('reports "up-to-date" when already current', async () => {
62
+ mockGit({ statusStdout: '', rebaseStdout: 'Current branch feature is up to date.' });
63
+ const result = await rebaseRepo('/repo', 'main');
64
+ expect(result.success).toBe(true);
65
+ expect(result.status).toBe('up-to-date');
66
+ });
67
+ it('auto-stashes a dirty tree and restores it (the regression fix)', async () => {
68
+ mockGit({ statusStdout: ' M src/app.ts\n', rebaseStdout: 'Successfully rebased.' });
69
+ const result = await rebaseRepo('/repo', 'main');
70
+ expect(result.success).toBe(true);
71
+ expect(result.status).toBe('rebased');
72
+ expect(result.stashed).toBe(true);
73
+ const calls = gitCalls();
74
+ // Stash push (with untracked) before rebase, stash pop after.
75
+ expect(calls).toContainEqual(['stash', 'push', '-u', '-m', 'nexusflow-autostash']);
76
+ expect(calls).toContainEqual(['stash', 'pop']);
77
+ });
78
+ it('classifies a fetch failure as "error", not a conflict', async () => {
79
+ mockGit({ fetchError: gitError('fatal: unable to access origin: Could not resolve host') });
80
+ const result = await rebaseRepo('/repo', 'main');
81
+ expect(result.success).toBe(false);
82
+ expect(result.status).toBe('error');
83
+ expect(result.message).toMatch(/^Fetch failed:/);
84
+ expect(result.conflict).toBeUndefined();
85
+ // Should never attempt a rebase if fetch failed.
86
+ expect(gitCalls().some((c) => c[0] === 'rebase')).toBe(false);
87
+ });
88
+ it('classifies a real merge conflict as "conflict" and aborts', async () => {
89
+ mockGit({
90
+ statusStdout: '',
91
+ rebaseError: gitError('CONFLICT (content): Merge conflict in src/app.ts'),
92
+ });
93
+ const result = await rebaseRepo('/repo', 'main');
94
+ expect(result.success).toBe(false);
95
+ expect(result.status).toBe('conflict');
96
+ expect(result.conflict).toContain('CONFLICT');
97
+ expect(gitCalls()).toContainEqual(['rebase', '--abort']);
98
+ });
99
+ it('restores the stash after aborting a conflicting rebase on a dirty tree', async () => {
100
+ mockGit({
101
+ statusStdout: ' M src/app.ts\n',
102
+ rebaseError: gitError('CONFLICT (content): Merge conflict'),
103
+ });
104
+ const result = await rebaseRepo('/repo', 'main');
105
+ expect(result.status).toBe('conflict');
106
+ expect(result.stashed).toBe(true);
107
+ const calls = gitCalls();
108
+ expect(calls).toContainEqual(['rebase', '--abort']);
109
+ expect(calls).toContainEqual(['stash', 'pop']); // local work restored
110
+ });
111
+ it('reports "stash-conflict" when the rebase lands but the stash pop conflicts', async () => {
112
+ mockGit({
113
+ statusStdout: ' M src/app.ts\n',
114
+ rebaseStdout: 'Successfully rebased.',
115
+ stashPopError: gitError('CONFLICT (content): Merge conflict in src/app.ts'),
116
+ });
117
+ const result = await rebaseRepo('/repo', 'main');
118
+ // The rebase itself succeeded, so success is true, but it needs attention.
119
+ expect(result.success).toBe(true);
120
+ expect(result.status).toBe('stash-conflict');
121
+ expect(result.stashed).toBe(true);
122
+ expect(result.message).toMatch(/stash preserved/i);
123
+ });
124
+ });
125
+ //# sourceMappingURL=multi-git.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-git.test.js","sourceRoot":"","sources":["../../src/utils/multi-git.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { test, expect, type Route } from '@playwright/test';
2
+
3
+ /** Minimal API mocks so the redesigned shell can render without a backend. */
4
+ async function mockApi(page: import('@playwright/test').Page) {
5
+ const feature = {
6
+ id: 'feature-x',
7
+ branchName: 'feature-x',
8
+ description: 'Test feature workspace',
9
+ repos: ['C:/dev/api-gateway'],
10
+ assistants: [],
11
+ workspacePath: 'C:/ws/feature-x',
12
+ createdAt: '2026-06-01T00:00:00.000Z',
13
+ };
14
+ const json = (body: unknown) => (route: Route) =>
15
+ route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(body) });
16
+
17
+ await page.route('**/api/config', json({
18
+ exists: true,
19
+ config: { version: '0.2.19', devDir: 'C:/dev', workspacesDir: 'C:/ws', defaultAssistant: 'claude', scanDepth: 2 },
20
+ }));
21
+ await page.route('**/api/workspaces', json([feature]));
22
+ await page.route('**/api/workspaces/status', json({
23
+ 'feature-x': { id: 'feature-x', branchName: 'feature-x', changedFiles: 3, dirtyRepos: 1, runningServices: 0, syncStatus: 'up-to-date', pendingValidation: false },
24
+ }));
25
+ await page.route('**/api/ai-detect', json([]));
26
+ await page.route('**/api/editor-detect', json([]));
27
+ await page.route('**/api/update-status', json({ updateAvailable: false, currentVersion: '0.2.19', latestVersion: '0.2.19' }));
28
+ await page.route('**/api/workflows/templates', json({ templates: [] }));
29
+ await page.route('**/api/repos', json([]));
30
+ await page.route('**/api/workspace/*/services', json({ services: [], orchestrationTools: [], runningState: [] }));
31
+ await page.route('**/api/workspace/*/changes', json({ changes: [] }));
32
+ }
33
+
34
+ test.describe('Redesigned NexusFlow shell', () => {
35
+ test('shows the dashboard overview with environment stats', async ({ page }) => {
36
+ await mockApi(page);
37
+ await page.goto('/');
38
+
39
+ await expect(page.getByRole('heading', { name: 'Overview' })).toBeVisible();
40
+ // Stat tiles + workspace row driven by the mocked status endpoint.
41
+ await expect(page.getByText('With uncommitted changes')).toBeVisible();
42
+ await expect(page.getByText('feature-x').first()).toBeVisible();
43
+ await expect(page.getByText('3 changed').first()).toBeVisible();
44
+ });
45
+
46
+ test('navigates to the workspaces master-detail and opens a workspace via deep link', async ({ page }) => {
47
+ await mockApi(page);
48
+
49
+ // Sidebar navigation updates the route.
50
+ await page.goto('/');
51
+ await page.getByRole('button', { name: 'Workspaces' }).click();
52
+ await expect(page).toHaveURL(/#\/workspaces/);
53
+ await expect(page.getByRole('heading', { name: 'Workspaces' })).toBeVisible();
54
+
55
+ // Deep link selects a workspace and shows the detail tabs.
56
+ await page.goto('/#/workspaces/feature-x');
57
+ await expect(page.getByRole('heading', { name: 'feature-x' })).toBeVisible();
58
+ await expect(page.getByRole('tab', { name: 'Overview' })).toBeVisible();
59
+ await expect(page.getByText('Test feature workspace')).toBeVisible();
60
+ });
61
+ });
@@ -224,8 +224,8 @@ test.describe('NexusFlow E2E GUI Tests', () => {
224
224
  // 3. Open dashboard
225
225
  await page.goto('/');
226
226
 
227
- // 4. Click New Workspace in Sidebar
228
- await page.locator('button:has-text("New Workspace")').click();
227
+ // 4. Click New Workspace in the sidebar (scoped to avoid matching page-level buttons)
228
+ await page.getByRole('complementary').getByRole('button', { name: 'New workspace' }).click();
229
229
 
230
230
  // 5. Fill Details
231
231
  await page.getByPlaceholder('e.g., feature/oauth-authentication-flow').fill('feat-test-branch');
@@ -12,6 +12,7 @@
12
12
  "lucide-react": "^1.20.0",
13
13
  "react": "^19.2.7",
14
14
  "react-dom": "^19.2.7",
15
+ "react-router-dom": "^7.18.1",
15
16
  "tailwindcss": "^4.3.1"
16
17
  },
17
18
  "devDependencies": {
@@ -27,7 +28,7 @@
27
28
  "globals": "^17.6.0",
28
29
  "typescript": "~6.0.2",
29
30
  "typescript-eslint": "^8.61.1",
30
- "vite": "^8.0.16"
31
+ "vite": "^8.1.2"
31
32
  }
32
33
  },
33
34
  "node_modules/@babel/code-frame": {
@@ -1556,6 +1557,19 @@
1556
1557
  "dev": true,
1557
1558
  "license": "MIT"
1558
1559
  },
1560
+ "node_modules/cookie": {
1561
+ "version": "1.1.1",
1562
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
1563
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
1564
+ "license": "MIT",
1565
+ "engines": {
1566
+ "node": ">=18"
1567
+ },
1568
+ "funding": {
1569
+ "type": "opencollective",
1570
+ "url": "https://opencollective.com/express"
1571
+ }
1572
+ },
1559
1573
  "node_modules/cross-spawn": {
1560
1574
  "version": "7.0.6",
1561
1575
  "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2680,6 +2694,44 @@
2680
2694
  "react": "^19.2.7"
2681
2695
  }
2682
2696
  },
2697
+ "node_modules/react-router": {
2698
+ "version": "7.18.1",
2699
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.1.tgz",
2700
+ "integrity": "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==",
2701
+ "license": "MIT",
2702
+ "dependencies": {
2703
+ "cookie": "^1.0.1",
2704
+ "set-cookie-parser": "^2.6.0"
2705
+ },
2706
+ "engines": {
2707
+ "node": ">=20.0.0"
2708
+ },
2709
+ "peerDependencies": {
2710
+ "react": ">=18",
2711
+ "react-dom": ">=18"
2712
+ },
2713
+ "peerDependenciesMeta": {
2714
+ "react-dom": {
2715
+ "optional": true
2716
+ }
2717
+ }
2718
+ },
2719
+ "node_modules/react-router-dom": {
2720
+ "version": "7.18.1",
2721
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.1.tgz",
2722
+ "integrity": "sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==",
2723
+ "license": "MIT",
2724
+ "dependencies": {
2725
+ "react-router": "7.18.1"
2726
+ },
2727
+ "engines": {
2728
+ "node": ">=20.0.0"
2729
+ },
2730
+ "peerDependencies": {
2731
+ "react": ">=18",
2732
+ "react-dom": ">=18"
2733
+ }
2734
+ },
2683
2735
  "node_modules/rolldown": {
2684
2736
  "version": "1.1.3",
2685
2737
  "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.3.tgz",
@@ -2729,6 +2781,12 @@
2729
2781
  "semver": "bin/semver.js"
2730
2782
  }
2731
2783
  },
2784
+ "node_modules/set-cookie-parser": {
2785
+ "version": "2.7.2",
2786
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
2787
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
2788
+ "license": "MIT"
2789
+ },
2732
2790
  "node_modules/shebang-command": {
2733
2791
  "version": "2.0.0",
2734
2792
  "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -2916,9 +2974,9 @@
2916
2974
  }
2917
2975
  },
2918
2976
  "node_modules/vite": {
2919
- "version": "8.1.1",
2920
- "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.1.tgz",
2921
- "integrity": "sha512-X/05/cT+VITy2AeDc1der6smvGWWREtL4hPbPTaVbjSBuuWkmNOjR6HP3NzqcQA2nF6VHGUPaFRJyft/2AE9Kg==",
2977
+ "version": "8.1.2",
2978
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.2.tgz",
2979
+ "integrity": "sha512-6YYPbRXTxx6bRXmOn7XdnQAy5DQNHhDgtjhDHI13oe4pY93kkcdGJWxpGwOm++/Wh0QpQhDrpIoVMrmrsI5AGQ==",
2922
2980
  "license": "MIT",
2923
2981
  "dependencies": {
2924
2982
  "lightningcss": "^1.32.0",
package/gui/package.json CHANGED
@@ -16,6 +16,7 @@
16
16
  "lucide-react": "^1.20.0",
17
17
  "react": "^19.2.7",
18
18
  "react-dom": "^19.2.7",
19
+ "react-router-dom": "^7.18.1",
19
20
  "tailwindcss": "^4.3.1"
20
21
  },
21
22
  "devDependencies": {
@@ -31,6 +32,6 @@
31
32
  "globals": "^17.6.0",
32
33
  "typescript": "~6.0.2",
33
34
  "typescript-eslint": "^8.61.1",
34
- "vite": "^8.0.16"
35
+ "vite": "^8.1.2"
35
36
  }
36
37
  }