@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.
- package/dist/docs/changelogs/preview.md +54 -65
- package/dist/google-gemini-cli-core-0.64.0-nightly.20260929.gd75234cae.tgz +0 -0
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/services/fileSystemService.atomic.test.d.ts +6 -0
- package/dist/src/services/fileSystemService.atomic.test.js +92 -0
- package/dist/src/services/fileSystemService.atomic.test.js.map +1 -0
- package/dist/src/services/fileSystemService.d.ts +10 -0
- package/dist/src/services/fileSystemService.js +96 -1
- package/dist/src/services/fileSystemService.js.map +1 -1
- package/dist/src/services/fileSystemService.test.js +74 -6
- package/dist/src/services/fileSystemService.test.js.map +1 -1
- package/dist/src/services/gitService.js +27 -13
- package/dist/src/services/gitService.js.map +1 -1
- package/dist/src/services/gitService.test.js +29 -0
- package/dist/src/services/gitService.test.js.map +1 -1
- package/dist/src/tools/edit.js +40 -0
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/edit.test.js +81 -0
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/write-file.js +37 -0
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/tools/write-file.test.js +31 -0
- package/dist/src/tools/write-file.test.js.map +1 -1
- package/dist/src/utils/pathMutex.d.ts +19 -0
- package/dist/src/utils/pathMutex.js +99 -0
- package/dist/src/utils/pathMutex.js.map +1 -0
- package/dist/src/utils/pathMutex.test.d.ts +6 -0
- package/dist/src/utils/pathMutex.test.js +95 -0
- package/dist/src/utils/pathMutex.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* In-process, per-path mutex used to serialize read-modify-write sequences
|
|
8
|
+
* against the same file.
|
|
9
|
+
*
|
|
10
|
+
* Parallel tool execution (notably sub-agents) can schedule two writes to the
|
|
11
|
+
* same path concurrently. Without serialization the two sequences interleave
|
|
12
|
+
* and one update is silently lost.
|
|
13
|
+
*
|
|
14
|
+
* Scope: this coordinates callers inside a single process only. It does not
|
|
15
|
+
* guard against a second Gemini CLI process, an editor, or any other program
|
|
16
|
+
* writing the same file; that would require an on-disk lock.
|
|
17
|
+
*
|
|
18
|
+
* Callers are expected to pass an already-resolved absolute path so that two
|
|
19
|
+
* spellings of the same file map to the same lock.
|
|
20
|
+
*/
|
|
21
|
+
const chains = new Map();
|
|
22
|
+
/**
|
|
23
|
+
* Runs `fn` with exclusive access to `key`, relative to other `withPathLock`
|
|
24
|
+
* callers using the same key.
|
|
25
|
+
*
|
|
26
|
+
* @param key - The resolved path (or other identifier) to lock.
|
|
27
|
+
* @param fn - The critical section.
|
|
28
|
+
* @param signal - Optional abort signal for immediate cancellation while waiting.
|
|
29
|
+
* @returns Whatever `fn` resolves to.
|
|
30
|
+
*/
|
|
31
|
+
export async function withPathLock(key, fn, signal) {
|
|
32
|
+
if (signal?.aborted) {
|
|
33
|
+
throw new Error('Aborted');
|
|
34
|
+
}
|
|
35
|
+
const previous = chains.get(key) ?? Promise.resolve();
|
|
36
|
+
let resolveLockReleased = () => { };
|
|
37
|
+
const lockReleased = new Promise((resolve) => {
|
|
38
|
+
resolveLockReleased = resolve;
|
|
39
|
+
});
|
|
40
|
+
chains.set(key, lockReleased);
|
|
41
|
+
const cleanup = () => {
|
|
42
|
+
if (chains.get(key) === lockReleased) {
|
|
43
|
+
chains.delete(key);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
let active = true;
|
|
48
|
+
const onAbort = () => {
|
|
49
|
+
if (!active)
|
|
50
|
+
return;
|
|
51
|
+
active = false;
|
|
52
|
+
if (signal) {
|
|
53
|
+
signal.removeEventListener('abort', onAbort);
|
|
54
|
+
}
|
|
55
|
+
// When the lock holder before us finishes, release our lock for subsequent waiters.
|
|
56
|
+
void previous.then(() => {
|
|
57
|
+
resolveLockReleased();
|
|
58
|
+
cleanup();
|
|
59
|
+
});
|
|
60
|
+
reject(new Error('Aborted'));
|
|
61
|
+
};
|
|
62
|
+
if (signal) {
|
|
63
|
+
signal.addEventListener('abort', onAbort);
|
|
64
|
+
}
|
|
65
|
+
void previous.then(async () => {
|
|
66
|
+
if (!active) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (signal) {
|
|
70
|
+
signal.removeEventListener('abort', onAbort);
|
|
71
|
+
}
|
|
72
|
+
if (signal?.aborted) {
|
|
73
|
+
onAbort();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const result = await fn();
|
|
78
|
+
resolve(result);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
reject(err);
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
if (active) {
|
|
85
|
+
active = false;
|
|
86
|
+
resolveLockReleased();
|
|
87
|
+
cleanup();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Number of paths currently holding lock state. Exposed for tests.
|
|
95
|
+
*/
|
|
96
|
+
export function pendingPathLockCount() {
|
|
97
|
+
return chains.size;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=pathMutex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathMutex.js","sourceRoot":"","sources":["../../../src/utils/pathMutex.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;AAEnD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EACX,EAAoB,EACpB,MAAoB;IAEpB,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAEtD,IAAI,mBAAmB,GAAe,GAAG,EAAE,GAAE,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACjD,mBAAmB,GAAG,OAAO,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAE9B,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,YAAY,EAAE,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,IAAI,MAAM,GAAG,IAAI,CAAC;QAElB,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,MAAM,GAAG,KAAK,CAAC;YACf,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC/C,CAAC;YACD,oFAAoF;YACpF,KAAK,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE;gBACtB,mBAAmB,EAAE,CAAC;gBACtB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;QAED,KAAK,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;YAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC/C,CAAC;YACD,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;gBACpB,OAAO,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;gBAC1B,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC;oBAAS,CAAC;gBACT,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,GAAG,KAAK,CAAC;oBACf,mBAAmB,EAAE,CAAC;oBACtB,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import { pendingPathLockCount, withPathLock } from './pathMutex.js';
|
|
8
|
+
describe('withPathLock', () => {
|
|
9
|
+
it('serializes callbacks that target the same key', async () => {
|
|
10
|
+
const events = [];
|
|
11
|
+
const first = withPathLock('/tmp/same.txt', async () => {
|
|
12
|
+
events.push('first:enter');
|
|
13
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
14
|
+
events.push('first:exit');
|
|
15
|
+
});
|
|
16
|
+
const second = withPathLock('/tmp/same.txt', async () => {
|
|
17
|
+
events.push('second:enter');
|
|
18
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
19
|
+
events.push('second:exit');
|
|
20
|
+
});
|
|
21
|
+
await Promise.all([first, second]);
|
|
22
|
+
expect(events).toEqual([
|
|
23
|
+
'first:enter',
|
|
24
|
+
'first:exit',
|
|
25
|
+
'second:enter',
|
|
26
|
+
'second:exit',
|
|
27
|
+
]);
|
|
28
|
+
});
|
|
29
|
+
it('runs callbacks for different keys concurrently', async () => {
|
|
30
|
+
const events = [];
|
|
31
|
+
const first = withPathLock('/tmp/a.txt', async () => {
|
|
32
|
+
events.push('a:enter');
|
|
33
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
34
|
+
events.push('a:exit');
|
|
35
|
+
});
|
|
36
|
+
const second = withPathLock('/tmp/b.txt', async () => {
|
|
37
|
+
events.push('b:enter');
|
|
38
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
39
|
+
events.push('b:exit');
|
|
40
|
+
});
|
|
41
|
+
await Promise.all([first, second]);
|
|
42
|
+
// b finishes before a because they do not share a lock.
|
|
43
|
+
expect(events).toEqual(['a:enter', 'b:enter', 'b:exit', 'a:exit']);
|
|
44
|
+
});
|
|
45
|
+
it('does not stall waiting callers if an earlier caller throws', async () => {
|
|
46
|
+
const events = [];
|
|
47
|
+
const failing = withPathLock('/tmp/throwing.txt', async () => {
|
|
48
|
+
events.push('failing:run');
|
|
49
|
+
throw new Error('boom');
|
|
50
|
+
});
|
|
51
|
+
const succeeding = withPathLock('/tmp/throwing.txt', async () => {
|
|
52
|
+
events.push('succeeding:run');
|
|
53
|
+
return 'ok';
|
|
54
|
+
});
|
|
55
|
+
await expect(failing).rejects.toThrow('boom');
|
|
56
|
+
await expect(succeeding).resolves.toBe('ok');
|
|
57
|
+
expect(events).toEqual(['failing:run', 'succeeding:run']);
|
|
58
|
+
});
|
|
59
|
+
it('cleans up lock state after the last waiter resolves', async () => {
|
|
60
|
+
const key = '/tmp/cleanup.txt';
|
|
61
|
+
const p1 = withPathLock(key, async () => {
|
|
62
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
63
|
+
});
|
|
64
|
+
const p2 = withPathLock(key, async () => {
|
|
65
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
66
|
+
});
|
|
67
|
+
expect(pendingPathLockCount()).toBeGreaterThan(0);
|
|
68
|
+
await Promise.all([p1, p2]);
|
|
69
|
+
expect(pendingPathLockCount()).toBe(0);
|
|
70
|
+
});
|
|
71
|
+
it('aborts immediately while queued behind an active lock holder', async () => {
|
|
72
|
+
const key = '/tmp/abort_immediate.txt';
|
|
73
|
+
const events = [];
|
|
74
|
+
const p1 = withPathLock(key, async () => {
|
|
75
|
+
events.push('p1:start');
|
|
76
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
77
|
+
events.push('p1:end');
|
|
78
|
+
});
|
|
79
|
+
const controller = new AbortController();
|
|
80
|
+
const p2 = withPathLock(key, async () => {
|
|
81
|
+
events.push('p2:run');
|
|
82
|
+
}, controller.signal);
|
|
83
|
+
setTimeout(() => controller.abort(), 10);
|
|
84
|
+
const p3 = withPathLock(key, async () => {
|
|
85
|
+
events.push('p3:run');
|
|
86
|
+
});
|
|
87
|
+
await expect(p2).rejects.toThrow('Aborted');
|
|
88
|
+
expect(events).toEqual(['p1:start']);
|
|
89
|
+
await p1;
|
|
90
|
+
await p3;
|
|
91
|
+
expect(events).toEqual(['p1:start', 'p1:end', 'p3:run']);
|
|
92
|
+
expect(pendingPathLockCount()).toBe(0);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=pathMutex.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathMutex.test.js","sourceRoot":"","sources":["../../../src/utils/pathMutex.test.ts"],"names":[],"mappings":"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"}
|