@google/gemini-cli-core 0.63.0-preview.0 → 0.64.0-nightly.20261001.gc6bccb7ec

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 (33) hide show
  1. package/dist/docs/changelogs/preview.md +54 -65
  2. package/dist/google-gemini-cli-core-0.64.0-nightly.20260929.gd75234cae.tgz +0 -0
  3. package/dist/src/generated/git-commit.d.ts +2 -2
  4. package/dist/src/generated/git-commit.js +2 -2
  5. package/dist/src/generated/git-commit.js.map +1 -1
  6. package/dist/src/services/fileSystemService.atomic.test.d.ts +6 -0
  7. package/dist/src/services/fileSystemService.atomic.test.js +92 -0
  8. package/dist/src/services/fileSystemService.atomic.test.js.map +1 -0
  9. package/dist/src/services/fileSystemService.d.ts +10 -0
  10. package/dist/src/services/fileSystemService.js +96 -1
  11. package/dist/src/services/fileSystemService.js.map +1 -1
  12. package/dist/src/services/fileSystemService.test.js +74 -6
  13. package/dist/src/services/fileSystemService.test.js.map +1 -1
  14. package/dist/src/services/gitService.js +27 -13
  15. package/dist/src/services/gitService.js.map +1 -1
  16. package/dist/src/services/gitService.test.js +29 -0
  17. package/dist/src/services/gitService.test.js.map +1 -1
  18. package/dist/src/tools/edit.js +40 -0
  19. package/dist/src/tools/edit.js.map +1 -1
  20. package/dist/src/tools/edit.test.js +81 -0
  21. package/dist/src/tools/edit.test.js.map +1 -1
  22. package/dist/src/tools/write-file.js +37 -0
  23. package/dist/src/tools/write-file.js.map +1 -1
  24. package/dist/src/tools/write-file.test.js +31 -0
  25. package/dist/src/tools/write-file.test.js.map +1 -1
  26. package/dist/src/utils/pathMutex.d.ts +19 -0
  27. package/dist/src/utils/pathMutex.js +99 -0
  28. package/dist/src/utils/pathMutex.js.map +1 -0
  29. package/dist/src/utils/pathMutex.test.d.ts +6 -0
  30. package/dist/src/utils/pathMutex.test.js +95 -0
  31. package/dist/src/utils/pathMutex.test.js.map +1 -0
  32. package/dist/tsconfig.tsbuildinfo +1 -1
  33. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
- # Preview release: v0.62.0-preview.0
1
+ # Preview release: v0.63.0-preview.0
2
2
 
3
- Released: September 23, 2026
3
+ Released: September 29, 2026
4
4
 
5
5
  Our preview release includes the latest, new, and experimental features. This
6
6
  release may not be as stable as our [latest weekly release](latest.md).
@@ -13,73 +13,62 @@ npm install -g @google/gemini-cli@preview
13
13
 
14
14
  ## Highlights
15
15
 
16
- - **New Model Support**: Added support for Gemini 3.8 Flash and 3.5 Flash Lite
17
- models, expanding the selection of available models.
18
- - **MCP Tool Call Formatting**: Improved Model Context Protocol (ACP/MCP)
19
- interactions by formatting tool call titles as structured signatures and
20
- separating explanations.
21
- - **PTY & Process Lifecycle Hardening**: Hardened Pseudo-Terminal (PTY)
22
- execution, improving file descriptor cleanup, exit synchronization on ConPTY,
23
- and finalization of terminal output.
24
- - **Memory & Reliability Refinements**: Refined terminal buffer memory
25
- management, preserved OAuth refresh tokens during credential refresh, and
26
- added layout dimension guarding in the UI border rendering.
16
+ - **Autonomous Plan Execution**: Enabled autonomous plan execution in
17
+ non-interactive mode, allowing automated agent workflows to run multi-step
18
+ plans without requiring interactive user confirmation.
19
+ - **Memory Lifecycle & Output Bounding**: Bounded tool output sizes and
20
+ optimized the memory lifecycle in long-running agent loops to prevent memory
21
+ leaks, while ensuring full output formatting when truncation is disabled.
22
+ - **Authentication Resilience**: Prevented infinite authentication loops caused
23
+ by file contention, headless keyring environments, and supervisor state drops,
24
+ ensuring reliable credential handling across environments.
25
+ - **CLI & Connection Recovery UX**: Displayed a retry progress indicator during
26
+ connection recovery, restored paused stdin after capability detection, and
27
+ ensured automatic temporary directory cleanup upon background shell execution
28
+ exit.
27
29
 
28
30
  ## What's Changed
29
31
 
30
- - fix(a2a-server): add early return on unsupported store in tasks metadata
31
- endpoint by @jesussamuel-byte in
32
- [#29334](https://github.com/google-gemini/gemini-cli/pull/29334)
33
- - Changelog for v0.61.0-preview.0 by @gemini-cli-robot in
34
- [#29344](https://github.com/google-gemini/gemini-cli/pull/29344)
35
- - Changelog for v0.60.0 by @gemini-cli-robot in
36
- [#29345](https://github.com/google-gemini/gemini-cli/pull/29345)
37
- - fix(core,acp): format MCP tool call titles as structured signatures and
38
- segregate explanations by @jvargassanchez-dot in
39
- [#29341](https://github.com/google-gemini/gemini-cli/pull/29341)
40
- - chore(release): bump version to 0.62.0-nightly.20260915.gae28844fb by
32
+ - fix(cli): display retry progress indicator during connection recovery (#28340)
33
+ by @amelidev in
34
+ [#29468](https://github.com/google-gemini/gemini-cli/pull/29468)
35
+ - Changelog for v0.61.0-preview.1 by @gemini-cli-robot in
36
+ [#29469](https://github.com/google-gemini/gemini-cli/pull/29469)
37
+ - Changelog for v0.61.0 by @gemini-cli-robot in
38
+ [#29472](https://github.com/google-gemini/gemini-cli/pull/29472)
39
+ - fix(cli): distinguish missing MCP enablement config from malformed JSON by
40
+ @jesussamuel-byte in
41
+ [#29446](https://github.com/google-gemini/gemini-cli/pull/29446)
42
+ - fix(cli): restore paused stdin after capability detection by @ugorla-dev in
43
+ [#29487](https://github.com/google-gemini/gemini-cli/pull/29487)
44
+ - fix(core): bound tool output size and optimize memory lifecycle in
45
+ long-running agent loops by @diegogodinezr in
46
+ [#29451](https://github.com/google-gemini/gemini-cli/pull/29451)
47
+ - fix(core): remove invalid diff.external override by @urielefrenvirtusa in
48
+ [#29467](https://github.com/google-gemini/gemini-cli/pull/29467)
49
+ - chore(release): bump version to 0.63.0-nightly.20260923.gf50ba8608 by
41
50
  @gemini-cli-robot in
42
- [#29346](https://github.com/google-gemini/gemini-cli/pull/29346)
43
- - fix(core): retain oauth refresh token on refresh and make credential deletion
44
- idempotent by @villahernandez-coder in
45
- [#29339](https://github.com/google-gemini/gemini-cli/pull/29339)
46
- - fix(ui): guard against negative layout dimensions in border rendering by
47
- @diegogodinezr in
48
- [#29347](https://github.com/google-gemini/gemini-cli/pull/29347)
49
- - test(integration): deflake run_shell_command and file-system-interactive tests
50
- by @DavidAPierce in
51
- [#29185](https://github.com/google-gemini/gemini-cli/pull/29185)
52
- - fix(core): improve PTY file descriptor cleanup and execution lifecycle
53
- management by @jesussamuel-byte in
54
- [#29340](https://github.com/google-gemini/gemini-cli/pull/29340)
55
- - chore/release: bump version to 0.62.0-nightly.20260918.g9450ade79 by
56
- @gemini-cli-robot in
57
- [#29383](https://github.com/google-gemini/gemini-cli/pull/29383)
58
- - fix(core): synchronize ConPTY process exit lifecycle and harden PTY output
59
- finalization by @jvargassanchez-dot in
60
- [#29379](https://github.com/google-gemini/gemini-cli/pull/29379)
61
- - fix(cli): suppress uncaught AbortError logs during request cancellation by
62
- @urielefrenvirtusa in
63
- [#29343](https://github.com/google-gemini/gemini-cli/pull/29343)
64
- - fix(core,cli): improve terminal buffer memory management and format Windows
65
- diagnostic paths by @jesussamuel-byte in
66
- [#29380](https://github.com/google-gemini/gemini-cli/pull/29380)
67
- - fix(vscode-ide-companion): preserve terminal focus when closing diff tabs by
68
- @amelidev in [#29378](https://github.com/google-gemini/gemini-cli/pull/29378)
69
- - fix(core): update auth error documentation link to valid anchor and add
70
- fallback (#26140) by @villahernandez-coder in
71
- [#29377](https://github.com/google-gemini/gemini-cli/pull/29377)
72
- - fix(core): normalize proxy-agent esbuild interop for environment proxy
73
- resolution by @diegogodinezr in
74
- [#29401](https://github.com/google-gemini/gemini-cli/pull/29401)
75
- - fix(cli): emit tool_call update prior to request_permission in ACP mode by
51
+ [#29471](https://github.com/google-gemini/gemini-cli/pull/29471)
52
+ - Changelog for v0.62.0-preview.0 by @gemini-cli-robot in
53
+ [#29470](https://github.com/google-gemini/gemini-cli/pull/29470)
54
+ - fix(core): clean up temporary directory when background shell execution exits
55
+ by @jesussamuel-byte in
56
+ [#29437](https://github.com/google-gemini/gemini-cli/pull/29437)
57
+ - fix(acp): resolve session before config initialization and avoid same-minute
58
+ filename collisions by @jesussamuel-byte in
59
+ [#29463](https://github.com/google-gemini/gemini-cli/pull/29463)
60
+ - fix(core): align policy redirection gates, path validation, and workflow
61
+ parsing by @DavidAPierce in
62
+ [#29506](https://github.com/google-gemini/gemini-cli/pull/29506)
63
+ - fix(auth): prevent infinite auth loop from file contention, headless keyring,
64
+ and supervisor state drops (#28341) by @villahernandez-coder in
65
+ [#29448](https://github.com/google-gemini/gemini-cli/pull/29448)
66
+ - fix(core): enable autonomous plan execution in non-interactive mode by
76
67
  @urielefrenvirtusa in
77
- [#29439](https://github.com/google-gemini/gemini-cli/pull/29439)
78
- - Feat/gemini 3.8 flash 3.5 flash lite by @DavidAPierce in
79
- [#29443](https://github.com/google-gemini/gemini-cli/pull/29443)
80
- - Check for vsc integration test presence when attempting to run. by
81
- @DavidAPierce in
82
- [#29462](https://github.com/google-gemini/gemini-cli/pull/29462)
68
+ [#29539](https://github.com/google-gemini/gemini-cli/pull/29539)
69
+ - fix(core): disable truncation when maxChars <= 0 in formatTruncatedToolOutput
70
+ by @diegogodinezr in
71
+ [#29542](https://github.com/google-gemini/gemini-cli/pull/29542)
83
72
 
84
73
  **Full Changelog**:
85
- https://github.com/google-gemini/gemini-cli/compare/v0.61.0-preview.1...v0.62.0-preview.0
74
+ https://github.com/google-gemini/gemini-cli/compare/v0.62.0-preview.0...v0.63.0-preview.0
@@ -3,5 +3,5 @@
3
3
  * Copyright 2026 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- export declare const GIT_COMMIT_INFO = "d75234cae";
7
- export declare const CLI_VERSION = "0.63.0-preview.0";
6
+ export declare const GIT_COMMIT_INFO = "c6bccb7ec";
7
+ export declare const CLI_VERSION = "0.64.0-nightly.20261001.gc6bccb7ec";
@@ -5,6 +5,6 @@
5
5
  */
6
6
  // This file is auto-generated by the build script (scripts/generate-git-commit-info.js)
7
7
  // Do not edit this file manually.
8
- export const GIT_COMMIT_INFO = 'd75234cae';
9
- export const CLI_VERSION = '0.63.0-preview.0';
8
+ export const GIT_COMMIT_INFO = 'c6bccb7ec';
9
+ export const CLI_VERSION = '0.64.0-nightly.20261001.gc6bccb7ec';
10
10
  //# sourceMappingURL=git-commit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"git-commit.js","sourceRoot":"","sources":["../../../src/generated/git-commit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wFAAwF;AACxF,kCAAkC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAC3C,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAC"}
1
+ {"version":3,"file":"git-commit.js","sourceRoot":"","sources":["../../../src/generated/git-commit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wFAAwF;AACxF,kCAAkC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAC3C,MAAM,CAAC,MAAM,WAAW,GAAG,oCAAoC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
7
+ import fs from 'node:fs';
8
+ import fsp from 'node:fs/promises';
9
+ import os from 'node:os';
10
+ import path from 'node:path';
11
+ import { StandardFileSystemService } from './fileSystemService.js';
12
+ /**
13
+ * These tests exercise the real filesystem on purpose: the behaviour under
14
+ * test is what a concurrent observer can see on disk while a write is in
15
+ * flight, which a mocked `fs` cannot express.
16
+ */
17
+ describe('StandardFileSystemService atomicity', () => {
18
+ let dir;
19
+ let service;
20
+ beforeEach(async () => {
21
+ dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'gemini-atomic-write-'));
22
+ service = new StandardFileSystemService();
23
+ });
24
+ afterEach(async () => {
25
+ await fsp.rm(dir, { recursive: true, force: true });
26
+ });
27
+ it('never exposes a partially written file to a concurrent observer', async () => {
28
+ // Large enough that the underlying write is split into several chunks;
29
+ // old and new are the same length so any other size is a partial state.
30
+ const SIZE = 16 * 1024 * 1024;
31
+ const filePath = path.join(dir, 'large.txt');
32
+ await fsp.writeFile(filePath, 'o'.repeat(SIZE), 'utf-8');
33
+ // The write runs on the libuv threadpool, so a *synchronous* loop on the
34
+ // main thread is what actually catches the destination mid-write. An
35
+ // async reader tends to be scheduled only before or after it.
36
+ const sizes = new Set();
37
+ let settled = false;
38
+ const write = service
39
+ .writeTextFile(filePath, 'n'.repeat(SIZE))
40
+ .finally(() => {
41
+ settled = true;
42
+ });
43
+ let spins = 0;
44
+ while (!settled && spins < 2_000_000) {
45
+ try {
46
+ sizes.add(fs.statSync(filePath).size);
47
+ }
48
+ catch {
49
+ // The destination may briefly not exist while being replaced.
50
+ sizes.add(-1);
51
+ }
52
+ spins++;
53
+ if (spins % 200 === 0) {
54
+ await new Promise((resolve) => setImmediate(resolve));
55
+ }
56
+ }
57
+ await write;
58
+ // Guard against a vacuous pass where the observer never ran.
59
+ expect(sizes.size).toBeGreaterThan(0);
60
+ const partialStates = [...sizes].filter((size) => size !== SIZE && size !== -1);
61
+ expect(partialStates).toEqual([]);
62
+ });
63
+ it('writes the requested content', async () => {
64
+ const filePath = path.join(dir, 'content.txt');
65
+ await service.writeTextFile(filePath, 'hello');
66
+ await expect(fsp.readFile(filePath, 'utf-8')).resolves.toBe('hello');
67
+ });
68
+ it.skipIf(process.platform === 'win32')('preserves the permissions of an existing file', async () => {
69
+ const filePath = path.join(dir, 'secret.txt');
70
+ await fsp.writeFile(filePath, 'before', { mode: 0o600 });
71
+ await fsp.chmod(filePath, 0o600);
72
+ await service.writeTextFile(filePath, 'after');
73
+ const stats = await fsp.stat(filePath);
74
+ expect(stats.mode & 0o777).toBe(0o600);
75
+ });
76
+ it('leaves no temporary files behind on success', async () => {
77
+ const filePath = path.join(dir, 'clean.txt');
78
+ await service.writeTextFile(filePath, 'done');
79
+ await expect(fsp.readdir(dir)).resolves.toEqual(['clean.txt']);
80
+ });
81
+ it('updates the target of a symlink without replacing the symlink itself', async () => {
82
+ const targetPath = path.join(dir, 'target.txt');
83
+ const symlinkPath = path.join(dir, 'link.txt');
84
+ await fsp.writeFile(targetPath, 'original');
85
+ await fsp.symlink(targetPath, symlinkPath);
86
+ await service.writeTextFile(symlinkPath, 'updated');
87
+ await expect(fsp.readFile(targetPath, 'utf-8')).resolves.toBe('updated');
88
+ const lstat = await fsp.lstat(symlinkPath);
89
+ expect(lstat.isSymbolicLink()).toBe(true);
90
+ });
91
+ });
92
+ //# sourceMappingURL=fileSystemService.atomic.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileSystemService.atomic.test.js","sourceRoot":"","sources":["../../../src/services/fileSystemService.atomic.test.ts"],"names":[],"mappings":"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"}
@@ -27,5 +27,15 @@ export interface FileSystemService {
27
27
  */
28
28
  export declare class StandardFileSystemService implements FileSystemService {
29
29
  readTextFile(filePath: string): Promise<string>;
30
+ /**
31
+ * Writes `content` to `filePath` atomically.
32
+ *
33
+ * A plain `fs.writeFile` truncates the destination and then streams the
34
+ * content in chunks, so anything reading the file concurrently can observe
35
+ * a truncated prefix. Writing to a sibling temp file and renaming it into
36
+ * place means an observer sees either the old file or the new one.
37
+ */
30
38
  writeTextFile(filePath: string, content: string): Promise<void>;
39
+ private getFileMode;
40
+ private renameWithRetry;
31
41
  }
@@ -3,7 +3,13 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ import { randomUUID } from 'node:crypto';
6
7
  import fs from 'node:fs/promises';
8
+ import path from 'node:path';
9
+ import { isNodeError } from '../utils/errors.js';
10
+ import { resolveToRealPath } from '../utils/paths.js';
11
+ /** Rename retries, for transient Windows lock errors. */
12
+ const RENAME_MAX_RETRIES = 5;
7
13
  /**
8
14
  * Standard file system implementation
9
15
  */
@@ -11,8 +17,97 @@ export class StandardFileSystemService {
11
17
  async readTextFile(filePath) {
12
18
  return fs.readFile(filePath, 'utf-8');
13
19
  }
20
+ /**
21
+ * Writes `content` to `filePath` atomically.
22
+ *
23
+ * A plain `fs.writeFile` truncates the destination and then streams the
24
+ * content in chunks, so anything reading the file concurrently can observe
25
+ * a truncated prefix. Writing to a sibling temp file and renaming it into
26
+ * place means an observer sees either the old file or the new one.
27
+ */
14
28
  async writeTextFile(filePath, content) {
15
- await fs.writeFile(filePath, content, 'utf-8');
29
+ // When filePath is a symlink, resolve to its real target path so that the
30
+ // rename updates the underlying target file rather than replacing the
31
+ // symlink itself with a regular file.
32
+ let realPath = filePath;
33
+ try {
34
+ realPath = resolveToRealPath(filePath);
35
+ }
36
+ catch {
37
+ try {
38
+ const dir = path.dirname(filePath);
39
+ const base = path.basename(filePath);
40
+ realPath = path.join(resolveToRealPath(dir), base);
41
+ }
42
+ catch {
43
+ realPath = filePath;
44
+ }
45
+ }
46
+ // The temp file must share a directory with the destination so that the
47
+ // rename stays within one filesystem, and must be uniquely named so that
48
+ // concurrent writers do not clobber each other's temp file.
49
+ const tmpPath = `${realPath}.${randomUUID()}.tmp`;
50
+ // A fresh temp file does not inherit the destination's permissions, so
51
+ // without this, replacing a 0600 file would silently widen it to the
52
+ // default mode.
53
+ const existingMode = await this.getFileMode(realPath);
54
+ try {
55
+ // Create the temp file already carrying the destination's mode, so the
56
+ // content is never briefly readable through a wider default mode. The
57
+ // mode is masked by umask, so this can only be more restrictive.
58
+ await fs.writeFile(tmpPath, content, {
59
+ encoding: 'utf-8',
60
+ ...(existingMode !== undefined ? { mode: existingMode } : {}),
61
+ });
62
+ if (existingMode !== undefined) {
63
+ try {
64
+ // Correct any narrowing that umask applied above. Best effort: some
65
+ // filesystems (FAT32, exFAT, a few NFS/CIFS mounts) and restricted
66
+ // sandboxes reject chmod with EPERM/ENOTSUP, and permissions must
67
+ // not be the reason a write fails.
68
+ await fs.chmod(tmpPath, existingMode);
69
+ }
70
+ catch {
71
+ // Keep whatever mode the temp file was created with.
72
+ }
73
+ }
74
+ await this.renameWithRetry(tmpPath, realPath);
75
+ }
76
+ catch (error) {
77
+ await fs.rm(tmpPath, { force: true }).catch(() => {
78
+ // Best effort: the original error is the one worth reporting.
79
+ });
80
+ throw error;
81
+ }
82
+ }
83
+ async getFileMode(filePath) {
84
+ try {
85
+ const stats = await fs.stat(filePath);
86
+ return stats.mode & 0o777;
87
+ }
88
+ catch {
89
+ // New file, or a destination we cannot stat; keep the default mode.
90
+ return undefined;
91
+ }
92
+ }
93
+ async renameWithRetry(from, to) {
94
+ for (let attempt = 0; attempt < RENAME_MAX_RETRIES; attempt++) {
95
+ try {
96
+ await fs.rename(from, to);
97
+ return;
98
+ }
99
+ catch (error) {
100
+ // Windows can transiently refuse a rename while another process has
101
+ // the destination open (antivirus, editors, watchers).
102
+ const code = isNodeError(error) ? error.code : '';
103
+ const isRetryable = code === 'EBUSY' || code === 'EPERM' || code === 'EACCES';
104
+ if (!isRetryable || attempt === RENAME_MAX_RETRIES - 1) {
105
+ throw error;
106
+ }
107
+ const delayMs = Math.pow(2, attempt) * 50;
108
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
109
+ }
110
+ }
16
111
  }
17
112
  }
18
113
  //# sourceMappingURL=fileSystemService.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fileSystemService.js","sourceRoot":"","sources":["../../../src/services/fileSystemService.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAuBlC;;GAEG;AACH,MAAM,OAAO,yBAAyB;IACpC,KAAK,CAAC,YAAY,CAAC,QAAgB;QACjC,OAAO,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,OAAe;QACnD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;CACF"}
1
+ {"version":3,"file":"fileSystemService.js","sourceRoot":"","sources":["../../../src/services/fileSystemService.ts"],"names":[],"mappings":"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"}
@@ -5,10 +5,16 @@
5
5
  */
6
6
  import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
7
  import fs from 'node:fs/promises';
8
+ import path from 'node:path';
8
9
  import { StandardFileSystemService } from './fileSystemService.js';
9
10
  vi.mock('fs/promises');
11
+ function escapeRegex(str) {
12
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
13
+ }
10
14
  describe('StandardFileSystemService', () => {
11
15
  let fileSystem;
16
+ const targetFile = path.resolve('/test/file.txt');
17
+ const tmpPattern = new RegExp(`^${escapeRegex(targetFile)}\\..*\\.tmp$`);
12
18
  beforeEach(() => {
13
19
  vi.resetAllMocks();
14
20
  fileSystem = new StandardFileSystemService();
@@ -20,21 +26,83 @@ describe('StandardFileSystemService', () => {
20
26
  it('should read file content using fs', async () => {
21
27
  const testContent = 'Hello, World!';
22
28
  vi.mocked(fs.readFile).mockResolvedValue(testContent);
23
- const result = await fileSystem.readTextFile('/test/file.txt');
24
- expect(fs.readFile).toHaveBeenCalledWith('/test/file.txt', 'utf-8');
29
+ const result = await fileSystem.readTextFile(targetFile);
30
+ expect(fs.readFile).toHaveBeenCalledWith(targetFile, 'utf-8');
25
31
  expect(result).toBe(testContent);
26
32
  });
27
33
  it('should propagate fs.readFile errors', async () => {
28
34
  const error = new Error('ENOENT: File not found');
29
35
  vi.mocked(fs.readFile).mockRejectedValue(error);
30
- await expect(fileSystem.readTextFile('/test/file.txt')).rejects.toThrow('ENOENT: File not found');
36
+ await expect(fileSystem.readTextFile(targetFile)).rejects.toThrow('ENOENT: File not found');
31
37
  });
32
38
  });
33
39
  describe('writeTextFile', () => {
34
- it('should write file content using fs', async () => {
40
+ it('should write to a sibling temp file and rename it into place', async () => {
35
41
  vi.mocked(fs.writeFile).mockResolvedValue();
36
- await fileSystem.writeTextFile('/test/file.txt', 'Hello, World!');
37
- expect(fs.writeFile).toHaveBeenCalledWith('/test/file.txt', 'Hello, World!', 'utf-8');
42
+ vi.mocked(fs.rename).mockResolvedValue();
43
+ vi.mocked(fs.stat).mockRejectedValue(new Error('ENOENT'));
44
+ await fileSystem.writeTextFile(targetFile, 'Hello, World!');
45
+ const [tmpPath, content, options] = vi.mocked(fs.writeFile).mock
46
+ .calls[0];
47
+ expect(content).toBe('Hello, World!');
48
+ expect(options.encoding).toBe('utf-8');
49
+ expect(tmpPath).toMatch(tmpPattern);
50
+ expect(fs.rename).toHaveBeenCalledWith(tmpPath, targetFile);
51
+ });
52
+ it('should match temp file patterns with Windows-style backslash paths', () => {
53
+ const winTarget = 'C:\\test\\folder\\file.txt';
54
+ const winTmpPattern = new RegExp(`^${escapeRegex(winTarget)}\\..*\\.tmp$`);
55
+ const sampleWinTmp = 'C:\\test\\folder\\file.txt.12345678-1234-1234-1234-123456789abc.tmp';
56
+ expect(sampleWinTmp).toMatch(winTmpPattern);
57
+ });
58
+ it('should create the temp file with the destination permissions', async () => {
59
+ vi.mocked(fs.writeFile).mockResolvedValue();
60
+ vi.mocked(fs.rename).mockResolvedValue();
61
+ vi.mocked(fs.chmod).mockResolvedValue();
62
+ vi.mocked(fs.stat).mockResolvedValue({
63
+ mode: 0o600,
64
+ });
65
+ const secretFile = path.resolve('/test/secret.txt');
66
+ await fileSystem.writeTextFile(secretFile, 'Hello, World!');
67
+ // Creating the temp file already restricted means the content is never
68
+ // briefly readable through a wider default mode.
69
+ const [, , options] = vi.mocked(fs.writeFile).mock.calls[0];
70
+ expect(options).toEqual({ encoding: 'utf-8', mode: 0o600 });
71
+ });
72
+ it('should still write the file when chmod is not permitted', async () => {
73
+ vi.mocked(fs.writeFile).mockResolvedValue();
74
+ vi.mocked(fs.rename).mockResolvedValue();
75
+ vi.mocked(fs.rm).mockResolvedValue();
76
+ vi.mocked(fs.stat).mockResolvedValue({
77
+ mode: 0o600,
78
+ });
79
+ // FAT32/exFAT, some NFS/CIFS mounts and restricted sandboxes reject chmod.
80
+ vi.mocked(fs.chmod).mockRejectedValue(Object.assign(new Error('operation not supported'), {
81
+ code: 'ENOTSUP',
82
+ }));
83
+ await expect(fileSystem.writeTextFile(targetFile, 'Hello, World!')).resolves.toBeUndefined();
84
+ expect(fs.rename).toHaveBeenCalled();
85
+ expect(fs.rm).not.toHaveBeenCalled();
86
+ });
87
+ it('should remove the temp file when the write fails', async () => {
88
+ vi.mocked(fs.writeFile).mockRejectedValue(new Error('ENOSPC'));
89
+ vi.mocked(fs.rm).mockResolvedValue();
90
+ await expect(fileSystem.writeTextFile(targetFile, 'Hello, World!')).rejects.toThrow('ENOSPC');
91
+ expect(fs.rename).not.toHaveBeenCalled();
92
+ const [removed] = vi.mocked(fs.rm).mock.calls[0];
93
+ expect(removed).toMatch(tmpPattern);
94
+ });
95
+ it('should retry rename when encountering EACCES', async () => {
96
+ vi.mocked(fs.writeFile).mockResolvedValue();
97
+ vi.mocked(fs.stat).mockRejectedValue(new Error('ENOENT'));
98
+ const eaccesError = Object.assign(new Error('permission denied'), {
99
+ code: 'EACCES',
100
+ });
101
+ vi.mocked(fs.rename)
102
+ .mockRejectedValueOnce(eaccesError)
103
+ .mockResolvedValueOnce();
104
+ await expect(fileSystem.writeTextFile(targetFile, 'Hello, World!')).resolves.toBeUndefined();
105
+ expect(fs.rename).toHaveBeenCalledTimes(2);
38
106
  });
39
107
  });
40
108
  });
@@ -1 +1 @@
1
- {"version":3,"file":"fileSystemService.test.js","sourceRoot":"","sources":["../../../src/services/fileSystemService.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AAEvB,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,IAAI,UAAqC,CAAC;IAE1C,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;QACnB,UAAU,GAAG,IAAI,yBAAyB,EAAE,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,eAAe,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,WAAW,GAAG,eAAe,CAAC;YACpC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;YAEtD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;YAE/D,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;YACpE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAClD,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAEhD,MAAM,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACrE,wBAAwB,CACzB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,iBAAiB,EAAE,CAAC;YAE5C,MAAM,UAAU,CAAC,aAAa,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;YAElE,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,oBAAoB,CACvC,gBAAgB,EAChB,eAAe,EACf,OAAO,CACR,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"fileSystemService.test.js","sourceRoot":"","sources":["../../../src/services/fileSystemService.test.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,8 @@
6
6
  import * as fs from 'node:fs/promises';
7
7
  import * as path from 'node:path';
8
8
  import { isNodeError } from '../utils/errors.js';
9
+ import { withPathLock } from '../utils/pathMutex.js';
10
+ import { resolveToRealPath } from '../utils/paths.js';
9
11
  import { spawnAsync } from '../utils/shell-utils.js';
10
12
  import { simpleGit, CheckRepoActions, } from 'simple-git';
11
13
  import { debugLogger } from '../utils/debugLogger.js';
@@ -155,22 +157,34 @@ export class GitService {
155
157
  return hash.trim();
156
158
  }
157
159
  async createFileSnapshot(message) {
160
+ // `add('.')` stages the entire working tree, so two snapshots running at
161
+ // once fold each other's files into whichever commit lands first. Serialize
162
+ // stage -> status -> commit per shadow repository.
163
+ let realProjectRoot = this.projectRoot;
158
164
  try {
159
- const repo = this.shadowGitRepository;
160
- await repo.add('.');
161
- const status = await repo.status();
162
- if (status.isClean()) {
163
- // If no changes are staged, return the current HEAD commit hash
164
- return await this.getCurrentCommitHash();
165
- }
166
- const commitResult = await repo.commit(message, {
167
- '--no-verify': null,
168
- });
169
- return commitResult.commit;
165
+ realProjectRoot = resolveToRealPath(this.projectRoot);
170
166
  }
171
- catch (error) {
172
- throw new Error(`Failed to create checkpoint snapshot: ${error instanceof Error ? error.message : 'Unknown error'}. Checkpointing may not be working properly.`);
167
+ catch {
168
+ // Keep unresolved
173
169
  }
170
+ return withPathLock(`git-snapshot:${realProjectRoot}`, async () => {
171
+ try {
172
+ const repo = this.shadowGitRepository;
173
+ await repo.add('.');
174
+ const status = await repo.status();
175
+ if (status.isClean()) {
176
+ // If no changes are staged, return the current HEAD commit hash
177
+ return await this.getCurrentCommitHash();
178
+ }
179
+ const commitResult = await repo.commit(message, {
180
+ '--no-verify': null,
181
+ });
182
+ return commitResult.commit;
183
+ }
184
+ catch (error) {
185
+ throw new Error(`Failed to create checkpoint snapshot: ${error instanceof Error ? error.message : 'Unknown error'}. Checkpointing may not be working properly.`);
186
+ }
187
+ });
174
188
  }
175
189
  async restoreProjectFromSnapshot(commitHash) {
176
190
  const repo = this.shadowGitRepository;
@@ -1 +1 @@
1
- {"version":3,"file":"gitService.js","sourceRoot":"","sources":["../../../src/services/gitService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gitService.js","sourceRoot":"","sources":["../../../src/services/gitService.ts"],"names":[],"mappings":"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"}