jamdesk 1.1.39 → 1.1.41

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 (55) hide show
  1. package/dist/__tests__/unit/clean.test.d.ts +2 -0
  2. package/dist/__tests__/unit/clean.test.d.ts.map +1 -0
  3. package/dist/__tests__/unit/clean.test.js +59 -0
  4. package/dist/__tests__/unit/clean.test.js.map +1 -0
  5. package/dist/__tests__/unit/dev-cache-cleanup.test.d.ts +2 -0
  6. package/dist/__tests__/unit/dev-cache-cleanup.test.d.ts.map +1 -0
  7. package/dist/__tests__/unit/dev-cache-cleanup.test.js +74 -0
  8. package/dist/__tests__/unit/dev-cache-cleanup.test.js.map +1 -0
  9. package/dist/__tests__/unit/dev-lock.test.d.ts +2 -0
  10. package/dist/__tests__/unit/dev-lock.test.d.ts.map +1 -0
  11. package/dist/__tests__/unit/dev-lock.test.js +70 -0
  12. package/dist/__tests__/unit/dev-lock.test.js.map +1 -0
  13. package/dist/__tests__/unit/dev-sync-vendored.test.d.ts +2 -0
  14. package/dist/__tests__/unit/dev-sync-vendored.test.d.ts.map +1 -0
  15. package/dist/__tests__/unit/dev-sync-vendored.test.js +58 -0
  16. package/dist/__tests__/unit/dev-sync-vendored.test.js.map +1 -0
  17. package/dist/__tests__/unit/run-build-script.test.d.ts +2 -0
  18. package/dist/__tests__/unit/run-build-script.test.d.ts.map +1 -0
  19. package/dist/__tests__/unit/run-build-script.test.js +58 -0
  20. package/dist/__tests__/unit/run-build-script.test.js.map +1 -0
  21. package/dist/__tests__/unit/workspace-paths.test.d.ts +2 -0
  22. package/dist/__tests__/unit/workspace-paths.test.d.ts.map +1 -0
  23. package/dist/__tests__/unit/workspace-paths.test.js +104 -0
  24. package/dist/__tests__/unit/workspace-paths.test.js.map +1 -0
  25. package/dist/commands/clean.d.ts +17 -2
  26. package/dist/commands/clean.d.ts.map +1 -1
  27. package/dist/commands/clean.js +47 -27
  28. package/dist/commands/clean.js.map +1 -1
  29. package/dist/commands/dev.d.ts +17 -0
  30. package/dist/commands/dev.d.ts.map +1 -1
  31. package/dist/commands/dev.js +116 -95
  32. package/dist/commands/dev.js.map +1 -1
  33. package/dist/index.js +9 -10
  34. package/dist/index.js.map +1 -1
  35. package/dist/lib/deps.d.ts +0 -4
  36. package/dist/lib/deps.d.ts.map +1 -1
  37. package/dist/lib/deps.js +0 -6
  38. package/dist/lib/deps.js.map +1 -1
  39. package/dist/lib/dev-lock.d.ts +15 -0
  40. package/dist/lib/dev-lock.d.ts.map +1 -0
  41. package/dist/lib/dev-lock.js +95 -0
  42. package/dist/lib/dev-lock.js.map +1 -0
  43. package/dist/lib/run-build-script.d.ts +13 -0
  44. package/dist/lib/run-build-script.d.ts.map +1 -0
  45. package/dist/lib/run-build-script.js +36 -0
  46. package/dist/lib/run-build-script.js.map +1 -0
  47. package/dist/lib/safe-fs.d.ts +18 -0
  48. package/dist/lib/safe-fs.d.ts.map +1 -0
  49. package/dist/lib/safe-fs.js +55 -0
  50. package/dist/lib/safe-fs.js.map +1 -0
  51. package/dist/lib/workspace-paths.d.ts +37 -0
  52. package/dist/lib/workspace-paths.d.ts.map +1 -0
  53. package/dist/lib/workspace-paths.js +64 -0
  54. package/dist/lib/workspace-paths.js.map +1 -0
  55. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=clean.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clean.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/clean.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @vitest-environment node
3
+ *
4
+ * Note: clean() takes both jamdeskDir and projectDir as parameters so we
5
+ * never have to mock os.homedir() — the production callsite passes
6
+ * getJamdeskDir() and process.cwd().
7
+ */
8
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
9
+ import fs from 'fs-extra';
10
+ import path from 'path';
11
+ import { tmpdir } from 'os';
12
+ import { clean } from '../../commands/clean.js';
13
+ import { computeWorkspaceSlug } from '../../lib/workspace-paths.js';
14
+ describe('clean', () => {
15
+ let tmpRoot;
16
+ let jamdeskDir;
17
+ let cwd;
18
+ beforeEach(() => {
19
+ tmpRoot = fs.mkdtempSync(path.join(tmpdir(), 'jam-clean-'));
20
+ jamdeskDir = path.join(tmpRoot, '.jamdesk');
21
+ cwd = path.join(tmpRoot, 'my-docs');
22
+ fs.mkdirpSync(cwd);
23
+ });
24
+ afterEach(() => {
25
+ vi.restoreAllMocks();
26
+ fs.removeSync(tmpRoot);
27
+ });
28
+ it('default: removes only the current project workspace, leaves siblings', async () => {
29
+ const mySlug = computeWorkspaceSlug(fs.realpathSync(cwd));
30
+ fs.mkdirpSync(path.join(jamdeskDir, 'workspaces', mySlug, '.next'));
31
+ fs.mkdirpSync(path.join(jamdeskDir, 'workspaces', 'other-abc123', '.next'));
32
+ fs.mkdirpSync(path.join(jamdeskDir, 'node_modules', 'next'));
33
+ await clean({ all: false }, { jamdeskDir, projectDir: cwd });
34
+ expect(fs.existsSync(path.join(jamdeskDir, 'workspaces', mySlug))).toBe(false);
35
+ expect(fs.existsSync(path.join(jamdeskDir, 'workspaces', 'other-abc123'))).toBe(true);
36
+ expect(fs.existsSync(path.join(jamdeskDir, 'node_modules'))).toBe(true);
37
+ });
38
+ it('--all: removes the entire jamdeskDir', async () => {
39
+ fs.mkdirpSync(path.join(jamdeskDir, 'node_modules'));
40
+ fs.mkdirpSync(path.join(jamdeskDir, 'workspaces', 'a-1'));
41
+ await clean({ all: true }, { jamdeskDir, projectDir: cwd });
42
+ expect(fs.existsSync(jamdeskDir)).toBe(false);
43
+ });
44
+ it('--all: no-op when jamdeskDir does not exist', async () => {
45
+ await expect(clean({ all: true }, { jamdeskDir, projectDir: cwd }))
46
+ .resolves.toBeUndefined();
47
+ expect(fs.existsSync(jamdeskDir)).toBe(false);
48
+ });
49
+ it('default: no-op when current workspace does not exist', async () => {
50
+ await expect(clean({ all: false }, { jamdeskDir, projectDir: cwd }))
51
+ .resolves.toBeUndefined();
52
+ });
53
+ it('default: ENOENT projectDir falls back to path.resolve, no crash', async () => {
54
+ const ghost = path.join(tmpRoot, 'never-existed');
55
+ await expect(clean({ all: false }, { jamdeskDir, projectDir: ghost }))
56
+ .resolves.toBeUndefined();
57
+ });
58
+ });
59
+ //# sourceMappingURL=clean.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clean.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/clean.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=dev-cache-cleanup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-cache-cleanup.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-cache-cleanup.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @vitest-environment node
3
+ *
4
+ * Unit tests for `safeRemoveCache` in `src/lib/safe-fs.ts`.
5
+ *
6
+ * Regression: previously the dev command crashed with an unhandled
7
+ * `ENOTEMPTY: directory not empty, rmdir '.../turbopack'` rejection when
8
+ * a concurrent `next dev` instance held files in the workspace cache
9
+ * during a CLI version bump. The handler must surface a clear message
10
+ * and `process.exit(1)` instead of stack-trace-crashing.
11
+ */
12
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
13
+ import fs from 'fs-extra';
14
+ import { safeRemoveCache } from '../../lib/safe-fs.js';
15
+ import { output } from '../../lib/output.js';
16
+ describe('safeRemoveCache', () => {
17
+ let exitSpy;
18
+ let errorSpy;
19
+ let rmSpy;
20
+ const lastErrorMsg = () => errorSpy.mock.calls[0]?.[0] ?? '';
21
+ beforeEach(() => {
22
+ exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code) => {
23
+ throw new Error(`process.exit:${code}`);
24
+ }));
25
+ errorSpy = vi.spyOn(output, 'error').mockImplementation(() => undefined);
26
+ rmSpy = vi.spyOn(fs, 'rm');
27
+ });
28
+ afterEach(() => {
29
+ vi.restoreAllMocks();
30
+ });
31
+ it('resolves silently when fs.rm succeeds', async () => {
32
+ rmSpy.mockResolvedValueOnce(undefined);
33
+ await expect(safeRemoveCache('/tmp/jam-cache')).resolves.toBeUndefined();
34
+ expect(errorSpy).not.toHaveBeenCalled();
35
+ expect(exitSpy).not.toHaveBeenCalled();
36
+ expect(rmSpy).toHaveBeenCalledWith('/tmp/jam-cache', expect.objectContaining({ recursive: true, force: true, maxRetries: 2 }));
37
+ });
38
+ it('exits with friendly message on ENOTEMPTY (concurrent dev session)', async () => {
39
+ const err = Object.assign(new Error('ENOTEMPTY'), { code: 'ENOTEMPTY' });
40
+ rmSpy.mockRejectedValueOnce(err);
41
+ await expect(safeRemoveCache('/tmp/jam-cache')).rejects.toThrow('process.exit:1');
42
+ const msg = lastErrorMsg();
43
+ expect(msg).toContain('Could not clear cache');
44
+ expect(msg).toContain('ENOTEMPTY');
45
+ expect(msg).toContain('Another `jamdesk dev` instance');
46
+ expect(msg).toContain('pkill -f');
47
+ expect(exitSpy).toHaveBeenCalledWith(1);
48
+ });
49
+ it.each(['EBUSY', 'EPERM'])('treats %s as a concurrent-dev race (same friendly message)', async (code) => {
50
+ const err = Object.assign(new Error(code), { code });
51
+ rmSpy.mockRejectedValueOnce(err);
52
+ await expect(safeRemoveCache('/tmp/jam-cache')).rejects.toThrow('process.exit:1');
53
+ expect(lastErrorMsg()).toContain('Another `jamdesk dev` instance');
54
+ expect(exitSpy).toHaveBeenCalledWith(1);
55
+ });
56
+ it('on EACCES surfaces a permissions-specific message (not the pkill fix)', async () => {
57
+ const err = Object.assign(new Error('EACCES'), { code: 'EACCES' });
58
+ rmSpy.mockRejectedValueOnce(err);
59
+ await expect(safeRemoveCache('/tmp/jam-cache')).rejects.toThrow('process.exit:1');
60
+ const msg = lastErrorMsg();
61
+ expect(msg).toContain('Permission denied');
62
+ expect(msg).toContain('chown');
63
+ expect(msg).not.toContain('pkill');
64
+ expect(exitSpy).toHaveBeenCalledWith(1);
65
+ });
66
+ it('rethrows non-race errors so they surface through normal error handling', async () => {
67
+ const err = Object.assign(new Error('disk full'), { code: 'ENOSPC' });
68
+ rmSpy.mockRejectedValueOnce(err);
69
+ await expect(safeRemoveCache('/tmp/jam-cache')).rejects.toThrow('disk full');
70
+ expect(errorSpy).not.toHaveBeenCalled();
71
+ expect(exitSpy).not.toHaveBeenCalled();
72
+ });
73
+ });
74
+ //# sourceMappingURL=dev-cache-cleanup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-cache-cleanup.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-cache-cleanup.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,OAAoC,CAAC;IACzC,IAAI,QAAqC,CAAC;IAC1C,IAAI,KAAkC,CAAC;IAEvC,MAAM,YAAY,GAAG,GAAW,EAAE,CAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAY,IAAI,EAAE,CAAC;IAEjF,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAa,EAAE,EAAE;YACxE,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAU,CAAC,CAAC;QACb,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACzE,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,eAAe,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,KAAK,CAAC,qBAAqB,CAAC,SAAkB,CAAC,CAAC;QAChD,MAAM,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;QACzE,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAChC,gBAAgB,EAChB,MAAM,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CACzE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACzE,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAEjC,MAAM,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAElF,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,gCAAgC,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAClC,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CACzB,4DAA4D,EAC5D,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAEjC,MAAM,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAClF,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,SAAS,CAAC,gCAAgC,CAAC,CAAC;QACnE,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC,CACF,CAAC;IAEF,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACnE,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAEjC,MAAM,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAClF,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAC3C,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACnC,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACtE,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAEjC,MAAM,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC7E,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=dev-lock.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-lock.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-lock.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @vitest-environment node
3
+ */
4
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
5
+ import fs from 'fs-extra';
6
+ import path from 'path';
7
+ import { tmpdir } from 'os';
8
+ import { acquireDevLock, releaseDevLock } from '../../lib/dev-lock.js';
9
+ describe('dev-lock', () => {
10
+ let tmpRoot;
11
+ let workspace;
12
+ beforeEach(() => {
13
+ tmpRoot = fs.mkdtempSync(path.join(tmpdir(), 'jam-lock-'));
14
+ workspace = path.join(tmpRoot, 'ws');
15
+ fs.mkdirpSync(workspace);
16
+ });
17
+ afterEach(() => {
18
+ fs.removeSync(tmpRoot);
19
+ });
20
+ it('acquires a fresh lock when no lockfile exists', () => {
21
+ const result = acquireDevLock(workspace);
22
+ expect(result.acquired).toBe(true);
23
+ expect(result.heldBy).toBe(process.pid);
24
+ expect(fs.existsSync(path.join(workspace, '.jamdesk-dev.lock'))).toBe(true);
25
+ });
26
+ it('refuses when an alive PID holds the lock', () => {
27
+ fs.writeFileSync(path.join(workspace, '.jamdesk-dev.lock'), String(process.pid));
28
+ const result = acquireDevLock(workspace);
29
+ expect(result.acquired).toBe(false);
30
+ expect(result.heldBy).toBe(process.pid);
31
+ });
32
+ it('reclaims a stale lock (PID dead)', () => {
33
+ // PID 999999 is "almost certainly dead"; verify it's not alive first.
34
+ const fakeDeadPid = 999999;
35
+ try {
36
+ process.kill(fakeDeadPid, 0);
37
+ }
38
+ catch {
39
+ // ESRCH or EPERM both fine — PID is not a target we can signal.
40
+ }
41
+ fs.writeFileSync(path.join(workspace, '.jamdesk-dev.lock'), String(fakeDeadPid));
42
+ const result = acquireDevLock(workspace);
43
+ expect(result.acquired).toBe(true);
44
+ expect(result.heldBy).toBe(process.pid);
45
+ });
46
+ it('releaseDevLock removes only our own lock, leaves stale ones', () => {
47
+ fs.writeFileSync(path.join(workspace, '.jamdesk-dev.lock'), String(process.pid));
48
+ releaseDevLock(workspace);
49
+ expect(fs.existsSync(path.join(workspace, '.jamdesk-dev.lock'))).toBe(false);
50
+ });
51
+ it('release is a no-op if lock is held by another PID', () => {
52
+ fs.writeFileSync(path.join(workspace, '.jamdesk-dev.lock'), String(process.pid + 1));
53
+ releaseDevLock(workspace);
54
+ expect(fs.existsSync(path.join(workspace, '.jamdesk-dev.lock'))).toBe(true);
55
+ });
56
+ it('treats a corrupted/non-positive lockfile as stale and reclaims it', () => {
57
+ fs.writeFileSync(path.join(workspace, '.jamdesk-dev.lock'), 'not-a-pid');
58
+ let result = acquireDevLock(workspace);
59
+ expect(result.acquired).toBe(true);
60
+ expect(result.heldBy).toBe(process.pid);
61
+ // Also covers: zero PID, negative PID, empty file
62
+ for (const garbage of ['0', '-1', '']) {
63
+ fs.writeFileSync(path.join(workspace, '.jamdesk-dev.lock'), garbage);
64
+ result = acquireDevLock(workspace);
65
+ expect(result.acquired).toBe(true);
66
+ expect(result.heldBy).toBe(process.pid);
67
+ }
68
+ });
69
+ });
70
+ //# sourceMappingURL=dev-lock.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-lock.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-lock.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=dev-sync-vendored.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-sync-vendored.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-sync-vendored.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @vitest-environment node
3
+ *
4
+ * Regression: syncVendoredFiles must NOT sweep CLI-managed dotfiles like the
5
+ * dev lockfile or content-hash. They are written to the workspace root before
6
+ * this runs, and prior to the fix the walkDest pass deleted them — silently
7
+ * defeating the concurrent-dev guard.
8
+ */
9
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
10
+ import fs from 'fs-extra';
11
+ import path from 'path';
12
+ import { tmpdir } from 'os';
13
+ import { syncVendoredFiles } from '../../commands/dev.js';
14
+ describe('syncVendoredFiles', () => {
15
+ let tmpRoot;
16
+ let src;
17
+ let dest;
18
+ beforeEach(() => {
19
+ tmpRoot = fs.mkdtempSync(path.join(tmpdir(), 'jam-sync-'));
20
+ src = path.join(tmpRoot, 'src');
21
+ dest = path.join(tmpRoot, 'dest');
22
+ fs.mkdirpSync(src);
23
+ fs.mkdirpSync(dest);
24
+ });
25
+ afterEach(() => {
26
+ fs.removeSync(tmpRoot);
27
+ });
28
+ it('preserves .jamdesk-dev.lock and .content-hash in dest', async () => {
29
+ fs.writeFileSync(path.join(src, 'package.json'), '{"name":"vendored"}');
30
+ fs.writeFileSync(path.join(dest, '.jamdesk-dev.lock'), String(process.pid));
31
+ fs.writeFileSync(path.join(dest, '.content-hash'), 'abc123');
32
+ await syncVendoredFiles(src, dest, () => true);
33
+ expect(fs.readFileSync(path.join(dest, '.jamdesk-dev.lock'), 'utf-8')).toBe(String(process.pid));
34
+ expect(fs.readFileSync(path.join(dest, '.content-hash'), 'utf-8')).toBe('abc123');
35
+ expect(fs.existsSync(path.join(dest, 'package.json'))).toBe(true);
36
+ });
37
+ it('still removes other dest files not in source (sweep behavior intact)', async () => {
38
+ fs.writeFileSync(path.join(src, 'keep.txt'), 'kept');
39
+ fs.writeFileSync(path.join(dest, 'keep.txt'), 'kept');
40
+ fs.writeFileSync(path.join(dest, 'orphan.txt'), 'should be removed');
41
+ const stats = await syncVendoredFiles(src, dest, () => true);
42
+ expect(fs.existsSync(path.join(dest, 'keep.txt'))).toBe(true);
43
+ expect(fs.existsSync(path.join(dest, 'orphan.txt'))).toBe(false);
44
+ expect(stats.removed).toBe(1);
45
+ });
46
+ it('skips .next/, node_modules/, projects/, public/ dirs', async () => {
47
+ fs.writeFileSync(path.join(src, 'a.txt'), 'a');
48
+ for (const skipped of ['.next', 'node_modules', 'projects', 'public']) {
49
+ fs.mkdirpSync(path.join(dest, skipped));
50
+ fs.writeFileSync(path.join(dest, skipped, 'inner.txt'), 'inner');
51
+ }
52
+ await syncVendoredFiles(src, dest, () => true);
53
+ for (const skipped of ['.next', 'node_modules', 'projects', 'public']) {
54
+ expect(fs.existsSync(path.join(dest, skipped, 'inner.txt'))).toBe(true);
55
+ }
56
+ });
57
+ });
58
+ //# sourceMappingURL=dev-sync-vendored.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-sync-vendored.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/dev-sync-vendored.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=run-build-script.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-build-script.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/run-build-script.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @vitest-environment node
3
+ *
4
+ * Covers the runBuildScript helper extracted from dev.ts so we exercise:
5
+ * - the success path,
6
+ * - the failure path (stderr surfaced via result.stderr, not just thrown),
7
+ * - the maxBuffer ceiling (50MB absorbs >1MB stdout).
8
+ */
9
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
10
+ import fs from 'fs-extra';
11
+ import path from 'path';
12
+ import { tmpdir } from 'os';
13
+ import { runBuildScript } from '../../lib/run-build-script.js';
14
+ describe('runBuildScript', () => {
15
+ let cwd;
16
+ let scriptsDir;
17
+ beforeEach(() => {
18
+ cwd = fs.mkdtempSync(path.join(tmpdir(), 'jam-runscript-'));
19
+ scriptsDir = path.join(cwd, 'scripts');
20
+ fs.mkdirpSync(scriptsDir);
21
+ });
22
+ afterEach(() => {
23
+ fs.removeSync(cwd);
24
+ });
25
+ it('returns success: true for a script that exits 0', async () => {
26
+ fs.writeFileSync(path.join(scriptsDir, 'ok.cjs'), `console.log('ran ok');`);
27
+ const result = await runBuildScript('ok.cjs', { cwd, env: process.env, verbose: false });
28
+ expect(result.success).toBe(true);
29
+ expect(result.script).toBe('ok.cjs');
30
+ });
31
+ it('returns success: false with stderr surfaced when the script exits non-zero', async () => {
32
+ fs.writeFileSync(path.join(scriptsDir, 'broken.cjs'), `console.error('something broke');\nprocess.exit(7);`);
33
+ const result = await runBuildScript('broken.cjs', { cwd, env: process.env, verbose: false });
34
+ expect(result.success).toBe(false);
35
+ expect(result.stderr).toContain('something broke');
36
+ // The error object must still be present so verbose mode can dump it.
37
+ expect(result.error).toBeDefined();
38
+ });
39
+ it('handles >1MB stdout without ERR_CHILD_PROCESS_STDIO_MAXBUFFER', async () => {
40
+ // ~2MB of stdout — would have failed with default 1MB buffer.
41
+ fs.writeFileSync(path.join(scriptsDir, 'noisy.cjs'), `const line = 'x'.repeat(1024); for (let i = 0; i < 2048; i++) console.log(line);`);
42
+ const result = await runBuildScript('noisy.cjs', { cwd, env: process.env, verbose: false });
43
+ expect(result.success).toBe(true);
44
+ });
45
+ it('captures stdout on failure too (some scripts log progress to stdout then exit non-zero)', async () => {
46
+ fs.writeFileSync(path.join(scriptsDir, 'mixed.cjs'), `console.log('progress: 50%');\nconsole.error('then it died');\nprocess.exit(1);`);
47
+ const result = await runBuildScript('mixed.cjs', { cwd, env: process.env, verbose: false });
48
+ expect(result.success).toBe(false);
49
+ expect(result.stdout).toContain('progress: 50%');
50
+ expect(result.stderr).toContain('then it died');
51
+ });
52
+ it('returns success: false when the script file is missing', async () => {
53
+ const result = await runBuildScript('missing.cjs', { cwd, env: process.env, verbose: false });
54
+ expect(result.success).toBe(false);
55
+ expect(result.error).toBeDefined();
56
+ });
57
+ });
58
+ //# sourceMappingURL=run-build-script.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-build-script.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/run-build-script.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=workspace-paths.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-paths.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/workspace-paths.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @vitest-environment node
3
+ */
4
+ import { describe, it, expect, afterEach, beforeEach } from 'vitest';
5
+ import path from 'path';
6
+ import fs from 'fs-extra';
7
+ import { tmpdir } from 'os';
8
+ import { computeWorkspaceSlug, getProjectWorkspaceDir, migrateLegacyWorkspace } from '../../lib/workspace-paths.js';
9
+ describe('computeWorkspaceSlug', () => {
10
+ it('returns <basename>-<6char-hash> for a normal path', () => {
11
+ expect(computeWorkspaceSlug('/Users/x/projects/jamdesk-docs'))
12
+ .toMatch(/^jamdesk-docs-[0-9a-f]{6}$/);
13
+ });
14
+ it('is deterministic', () => {
15
+ const a = computeWorkspaceSlug('/Users/x/projects/jamdesk-docs');
16
+ const b = computeWorkspaceSlug('/Users/x/projects/jamdesk-docs');
17
+ expect(a).toBe(b);
18
+ });
19
+ it('different paths with same basename → different slugs', () => {
20
+ expect(computeWorkspaceSlug('/clone-1/jamdesk-docs'))
21
+ .not.toBe(computeWorkspaceSlug('/clone-2/jamdesk-docs'));
22
+ });
23
+ it('sanitises unsafe basename characters to "-"', () => {
24
+ expect(computeWorkspaceSlug('/tmp/My Project (v2)'))
25
+ .toMatch(/^my-project-v2-[0-9a-f]{6}$/);
26
+ });
27
+ it('truncates very long basenames before appending hash (NAME_MAX safety)', () => {
28
+ const long = '/tmp/' + 'a'.repeat(300);
29
+ const slug = computeWorkspaceSlug(long);
30
+ // safe segment capped at 80 + "-" + 6 hash chars = 87
31
+ expect(slug.length).toBeLessThanOrEqual(87);
32
+ expect(slug).toMatch(/^a{80}-[0-9a-f]{6}$/);
33
+ });
34
+ it('falls back to "project" when sanitisation strips everything (non-ASCII)', () => {
35
+ expect(computeWorkspaceSlug('/tmp/プロジェクト'))
36
+ .toMatch(/^project-[0-9a-f]{6}$/);
37
+ });
38
+ it('handles trailing slashes and root paths', () => {
39
+ expect(computeWorkspaceSlug('/Users/x/foo/')).toMatch(/^foo-[0-9a-f]{6}$/);
40
+ expect(computeWorkspaceSlug('/')).toMatch(/^project-[0-9a-f]{6}$/);
41
+ });
42
+ });
43
+ describe('getProjectWorkspaceDir', () => {
44
+ let tmpRoot;
45
+ let fakeJamdeskDir;
46
+ beforeEach(() => {
47
+ tmpRoot = fs.mkdtempSync(path.join(tmpdir(), 'jam-ws-'));
48
+ fakeJamdeskDir = path.join(tmpRoot, '.jamdesk');
49
+ });
50
+ afterEach(() => {
51
+ fs.removeSync(tmpRoot);
52
+ });
53
+ it('returns <jamdeskDir>/workspaces/<slug> for an existing project dir', () => {
54
+ const projectDir = path.join(tmpRoot, 'my-docs');
55
+ fs.mkdirpSync(projectDir);
56
+ expect(getProjectWorkspaceDir(fakeJamdeskDir, projectDir))
57
+ .toMatch(new RegExp(`${fakeJamdeskDir}/workspaces/my-docs-[0-9a-f]{6}$`));
58
+ });
59
+ it('resolves symlinks before hashing (same workspace via symlink or real path)', () => {
60
+ const real = path.join(tmpRoot, 'real');
61
+ const link = path.join(tmpRoot, 'link');
62
+ fs.mkdirpSync(real);
63
+ fs.symlinkSync(real, link);
64
+ expect(getProjectWorkspaceDir(fakeJamdeskDir, real))
65
+ .toBe(getProjectWorkspaceDir(fakeJamdeskDir, link));
66
+ });
67
+ it('falls back to path.resolve when projectDir does not exist (no ENOENT)', () => {
68
+ const ghost = path.join(tmpRoot, 'never-existed');
69
+ expect(() => getProjectWorkspaceDir(fakeJamdeskDir, ghost)).not.toThrow();
70
+ const slug = getProjectWorkspaceDir(fakeJamdeskDir, ghost);
71
+ expect(slug).toMatch(new RegExp(`${fakeJamdeskDir}/workspaces/never-existed-[0-9a-f]{6}$`));
72
+ });
73
+ });
74
+ describe('migrateLegacyWorkspace', () => {
75
+ let tmpRoot;
76
+ beforeEach(() => {
77
+ tmpRoot = fs.mkdtempSync(path.join(tmpdir(), 'jam-mig-'));
78
+ });
79
+ afterEach(() => {
80
+ fs.removeSync(tmpRoot);
81
+ });
82
+ it('removes <jamdeskDir>/workspace when it exists', async () => {
83
+ const fakeJamdeskDir = path.join(tmpRoot, '.jamdesk');
84
+ const legacy = path.join(fakeJamdeskDir, 'workspace');
85
+ fs.mkdirpSync(path.join(legacy, '.next', 'cache'));
86
+ fs.writeFileSync(path.join(legacy, 'marker'), 'x');
87
+ const removed = await migrateLegacyWorkspace(fakeJamdeskDir);
88
+ expect(removed).toBe(true);
89
+ expect(fs.existsSync(legacy)).toBe(false);
90
+ });
91
+ it('returns false (no-op) when legacy workspace does not exist', async () => {
92
+ const fakeJamdeskDir = path.join(tmpRoot, '.jamdesk-empty');
93
+ fs.mkdirpSync(fakeJamdeskDir);
94
+ expect(await migrateLegacyWorkspace(fakeJamdeskDir)).toBe(false);
95
+ });
96
+ it('leaves <jamdeskDir>/workspaces/ untouched (singular vs plural)', async () => {
97
+ const fakeJamdeskDir = path.join(tmpRoot, '.jamdesk');
98
+ fs.mkdirpSync(path.join(fakeJamdeskDir, 'workspaces', 'foo-abc123'));
99
+ fs.writeFileSync(path.join(fakeJamdeskDir, 'workspaces', 'foo-abc123', 'marker'), 'x');
100
+ await migrateLegacyWorkspace(fakeJamdeskDir);
101
+ expect(fs.existsSync(path.join(fakeJamdeskDir, 'workspaces', 'foo-abc123', 'marker'))).toBe(true);
102
+ });
103
+ });
104
+ //# sourceMappingURL=workspace-paths.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-paths.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/workspace-paths.test.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,22 @@
1
1
  /**
2
2
  * Clean Command
3
3
  *
4
- * Clears the ~/.jamdesk cache directory.
4
+ * Default: clears the current project's workspace
5
+ * (`<jamdeskDir>/workspaces/<slug>/`).
6
+ *
7
+ * `--all`: clears everything under `<jamdeskDir>/`, including shared
8
+ * `node_modules` (next dev will reinstall on first run).
9
+ *
10
+ * Both modes use safeRemoveCache so a still-running dev session in the
11
+ * target tree surfaces a clear "another dev is running" message rather
12
+ * than crashing ENOTEMPTY.
5
13
  */
6
- export declare function clean(): Promise<void>;
14
+ export interface CleanOptions {
15
+ all?: boolean;
16
+ }
17
+ export interface CleanContext {
18
+ jamdeskDir: string;
19
+ projectDir: string;
20
+ }
21
+ export declare function clean(options?: CleanOptions, ctx?: CleanContext): Promise<void>;
7
22
  //# sourceMappingURL=clean.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"clean.d.ts","sourceRoot":"","sources":["../../src/commands/clean.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAyB3C"}
1
+ {"version":3,"file":"clean.d.ts","sourceRoot":"","sources":["../../src/commands/clean.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,KAAK,CACzB,OAAO,GAAE,YAAiB,EAC1B,GAAG,GAAE,YAAyE,GAC7E,OAAO,CAAC,IAAI,CAAC,CAmCf"}