@vib795/agent-memory 0.7.0 → 0.7.1
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/README.md +1 -1
- package/package.json +1 -1
- package/src/compact.js +65 -9
package/README.md
CHANGED
|
@@ -561,7 +561,7 @@ them as skipped, which is the intended outcome, not a failure.
|
|
|
561
561
|
|
|
562
562
|
Needs Node 22.5 or newer; `doctor` says so plainly if the version is too old.
|
|
563
563
|
|
|
564
|
-
Run `npm test` for the suite (
|
|
564
|
+
Run `npm test` for the suite (106 tests, no dependencies). CI runs it on Linux,
|
|
565
565
|
macOS and Windows across Node 22 and 24, and separately installs the packed tarball
|
|
566
566
|
and exercises it end to end on all three.
|
|
567
567
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vib795/agent-memory",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Durable cross-repo knowledge graph for GitHub Copilot and Claude Code. Markdown source of truth, disposable SQLite index, zero runtime dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"github-copilot",
|
package/src/compact.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readFileSync, existsSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { execFileSync } from 'node:child_process';
|
|
2
3
|
import { fileURLToPath } from 'node:url';
|
|
3
4
|
import { join, sep, basename, dirname } from 'node:path';
|
|
4
5
|
import { loadConfig, paths } from './config.js';
|
|
@@ -152,28 +153,78 @@ function decay(active, cfg, now) {
|
|
|
152
153
|
* what it now knows without costing anything at chat time.
|
|
153
154
|
*/
|
|
154
155
|
// The directory this package was installed into. `setup` links skill directories at
|
|
155
|
-
// `<package>/skills/<name>`, so
|
|
156
|
+
// `<package>/skills/<name>`, so a description write normally lands in the package's own
|
|
156
157
|
// files. That is correct for an installed package and wrong for a git checkout, where
|
|
157
158
|
// those files are tracked: one developer's digest gets committed and then published to
|
|
158
159
|
// everyone. It shipped that way for twenty releases, advertising one machine's five
|
|
159
160
|
// notes to every user who installed the plugin.
|
|
160
161
|
const PACKAGE_ROOT = fileURLToPath(new URL('..', import.meta.url));
|
|
161
162
|
|
|
163
|
+
// One process, one answer, so a per-run cache cannot go stale. `compact` asks about
|
|
164
|
+
// every registered path on every call, and most of them resolve to the same few trees.
|
|
165
|
+
const trackedCache = new Map();
|
|
166
|
+
|
|
162
167
|
/**
|
|
163
|
-
*
|
|
168
|
+
* Does git consider this exact file tracked?
|
|
164
169
|
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
* `true` and `false` are answers; `null` means git could not be asked and the caller
|
|
171
|
+
* has to fall back. A non-zero exit covers both "not tracked" and "not in a repository",
|
|
172
|
+
* and those mean the same thing here: writing the file publishes nothing.
|
|
173
|
+
*/
|
|
174
|
+
function isTracked(real) {
|
|
175
|
+
if (trackedCache.has(real)) return trackedCache.get(real);
|
|
176
|
+
let answer;
|
|
177
|
+
try {
|
|
178
|
+
execFileSync('git', ['ls-files', '--error-unmatch', '--', basename(real)], {
|
|
179
|
+
cwd: dirname(real),
|
|
180
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
181
|
+
timeout: 5000,
|
|
182
|
+
});
|
|
183
|
+
answer = true;
|
|
184
|
+
} catch (err) {
|
|
185
|
+
// ENOENT is git missing, which is not an answer about the file. Anything else is
|
|
186
|
+
// git having run and said no.
|
|
187
|
+
answer = err.code === 'ENOENT' ? null : false;
|
|
188
|
+
}
|
|
189
|
+
trackedCache.set(real, answer);
|
|
190
|
+
return answer;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Would writing this file commit local state into someone's repository?
|
|
195
|
+
*
|
|
196
|
+
* The question is about the **target**, not about where this code is running from, and
|
|
197
|
+
* that distinction is the bug this replaced. The old test asked whether the running
|
|
198
|
+
* package had a `.git`, which is true from a checkout and false from an installed
|
|
199
|
+
* package — so a registered path pointing into a checkout was refused in dev mode and
|
|
200
|
+
* silently written in normal mode. Switching a machine from `npm install -g .` to the
|
|
201
|
+
* published package leaves exactly such a path behind, and the next `compact` wrote a
|
|
202
|
+
* machine-specific digest into a tracked file. The same failure that shipped one
|
|
203
|
+
* machine's note count for twenty releases, reached from the other direction.
|
|
204
|
+
*
|
|
205
|
+
* Tracked-ness is the property that actually matters, so ask git directly. Resolved
|
|
206
|
+
* through `realpathSync` first because the path arrives as a symlink planted by
|
|
207
|
+
* `setup`: the link sits outside the repository even when its target is inside it, and
|
|
208
|
+
* asking about the link would answer "not tracked" and then write straight through it.
|
|
209
|
+
*
|
|
210
|
+
* Without git, fall back to the old package-root heuristic. It is narrower than the
|
|
211
|
+
* real question but it is what this shipped with, and a machine with no git also has
|
|
212
|
+
* no tracked file to damage.
|
|
170
213
|
*/
|
|
171
214
|
export function insideCheckout(file) {
|
|
172
|
-
if (!existsSync(join(PACKAGE_ROOT, '.git'))) return false;
|
|
173
215
|
let real;
|
|
174
|
-
let root;
|
|
175
216
|
try {
|
|
176
217
|
real = realpathSync(file);
|
|
218
|
+
} catch {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const tracked = isTracked(real);
|
|
223
|
+
if (tracked !== null) return tracked;
|
|
224
|
+
|
|
225
|
+
if (!existsSync(join(PACKAGE_ROOT, '.git'))) return false;
|
|
226
|
+
let root;
|
|
227
|
+
try {
|
|
177
228
|
root = realpathSync(PACKAGE_ROOT);
|
|
178
229
|
} catch {
|
|
179
230
|
return false;
|
|
@@ -182,6 +233,11 @@ export function insideCheckout(file) {
|
|
|
182
233
|
return real === root || real.startsWith(root + sep);
|
|
183
234
|
}
|
|
184
235
|
|
|
236
|
+
/** Testing seam: the per-process cache would otherwise outlive a fixture repo. */
|
|
237
|
+
export function resetTrackedCache() {
|
|
238
|
+
trackedCache.clear();
|
|
239
|
+
}
|
|
240
|
+
|
|
185
241
|
export function writeSkillDescription(skillPath, description) {
|
|
186
242
|
if (!existsSync(skillPath)) return false;
|
|
187
243
|
if (insideCheckout(skillPath)) return false;
|