@mnemonik/shared 7.97.2 → 7.98.0
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/ambientPointer.d.ts.map +1 -1
- package/dist/ambientPointer.js +2 -1
- package/dist/ambientPointer.js.map +1 -1
- package/dist/apiOrigin.d.ts +3 -0
- package/dist/apiOrigin.d.ts.map +1 -0
- package/dist/apiOrigin.js +5 -0
- package/dist/apiOrigin.js.map +1 -0
- package/dist/ast/astChunker.d.ts +12 -12
- package/dist/ast/astChunker.js +32 -32
- package/dist/ast/grammars.d.ts +9 -9
- package/dist/ast/grammars.js +15 -15
- package/dist/codeScanner.d.ts +56 -43
- package/dist/codeScanner.d.ts.map +1 -1
- package/dist/codeScanner.js +262 -143
- package/dist/codeScanner.js.map +1 -1
- package/dist/contextBudget.js +2 -2
- package/dist/contextBudget.js.map +1 -1
- package/dist/gitEditDetector.d.ts +6 -6
- package/dist/gitEditDetector.js +7 -7
- package/dist/hookRuntime.d.ts +35 -2
- package/dist/hookRuntime.d.ts.map +1 -1
- package/dist/hookRuntime.js +127 -33
- package/dist/hookRuntime.js.map +1 -1
- package/dist/hookTimeouts.d.ts +6 -6
- package/dist/hookTimeouts.js +6 -6
- package/dist/hostAdapter.d.ts +135 -0
- package/dist/hostAdapter.d.ts.map +1 -0
- package/dist/hostAdapter.js +323 -0
- package/dist/hostAdapter.js.map +1 -0
- package/dist/hostBinary.d.ts +29 -0
- package/dist/hostBinary.d.ts.map +1 -0
- package/dist/hostBinary.js +179 -0
- package/dist/hostBinary.js.map +1 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +26 -26
- package/dist/instructions.js +26 -26
- package/dist/jitDeliveryAck.d.ts.map +1 -1
- package/dist/jitDeliveryAck.js +2 -0
- package/dist/jitDeliveryAck.js.map +1 -1
- package/dist/projectIdentityFile.d.ts +25 -0
- package/dist/projectIdentityFile.d.ts.map +1 -0
- package/dist/projectIdentityFile.js +87 -0
- package/dist/projectIdentityFile.js.map +1 -0
- package/dist/projectSetupHandoff.d.ts +24 -0
- package/dist/projectSetupHandoff.d.ts.map +1 -0
- package/dist/projectSetupHandoff.js +249 -0
- package/dist/projectSetupHandoff.js.map +1 -0
- package/dist/protectedPaths.d.ts +9 -0
- package/dist/protectedPaths.d.ts.map +1 -0
- package/dist/protectedPaths.js +66 -0
- package/dist/protectedPaths.js.map +1 -0
- package/dist/readiness.d.ts +143 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +304 -0
- package/dist/readiness.js.map +1 -0
- package/dist/repositoryFingerprint.d.ts +50 -0
- package/dist/repositoryFingerprint.d.ts.map +1 -0
- package/dist/repositoryFingerprint.js +160 -0
- package/dist/repositoryFingerprint.js.map +1 -0
- package/dist/repositoryRoot.d.ts +56 -0
- package/dist/repositoryRoot.d.ts.map +1 -0
- package/dist/repositoryRoot.js +226 -0
- package/dist/repositoryRoot.js.map +1 -0
- package/dist/runtimeReader.d.ts +102 -0
- package/dist/runtimeReader.d.ts.map +1 -0
- package/dist/runtimeReader.js +408 -0
- package/dist/runtimeReader.js.map +1 -0
- package/dist/runtimeSigners.d.ts +37 -0
- package/dist/runtimeSigners.d.ts.map +1 -0
- package/dist/runtimeSigners.js +507 -0
- package/dist/runtimeSigners.js.map +1 -0
- package/dist/scannerSupervisor.d.ts +35 -0
- package/dist/scannerSupervisor.d.ts.map +1 -0
- package/dist/scannerSupervisor.js +2 -0
- package/dist/scannerSupervisor.js.map +1 -0
- package/dist/secretPatterns.d.ts +9 -9
- package/dist/secretPatterns.d.ts.map +1 -1
- package/dist/secretPatterns.js +27 -25
- package/dist/secretPatterns.js.map +1 -1
- package/dist/testing/hostAdapterConformance.d.ts +17 -0
- package/dist/testing/hostAdapterConformance.d.ts.map +1 -0
- package/dist/testing/hostAdapterConformance.js +477 -0
- package/dist/testing/hostAdapterConformance.js.map +1 -0
- package/dist/usageGuide.d.ts +1 -1
- package/dist/usageGuide.d.ts.map +1 -1
- package/dist/usageGuide.js +4 -4
- package/package.json +7 -2
- package/queries/bash.tags.scm +1 -1
- package/queries/groovy.tags.scm +1 -1
- package/scripts/vendor-grammars.ts +13 -13
- package/src/ambientPointer.ts +2 -1
- package/src/apiOrigin.ts +4 -0
- package/src/ast/astChunker.ts +39 -39
- package/src/ast/grammars.ts +16 -16
- package/src/codeScanner.ts +274 -149
- package/src/contextBudget.ts +2 -2
- package/src/gitEditDetector.ts +7 -7
- package/src/hookRuntime.ts +162 -34
- package/src/hookTimeouts.ts +6 -6
- package/src/hostAdapter.ts +468 -0
- package/src/hostBinary.ts +205 -0
- package/src/index.ts +20 -0
- package/src/instructions.ts +26 -26
- package/src/jitDeliveryAck.ts +2 -0
- package/src/projectIdentityFile.ts +100 -0
- package/src/projectSetupHandoff.ts +275 -0
- package/src/protectedPaths.ts +88 -0
- package/src/readiness.ts +516 -0
- package/src/repositoryFingerprint.ts +199 -0
- package/src/repositoryRoot.ts +261 -0
- package/src/runtimeReader.ts +495 -0
- package/src/runtimeSigners.ts +577 -0
- package/src/scannerSupervisor.ts +26 -0
- package/src/secretPatterns.ts +27 -25
- package/src/testing/hostAdapterConformance.ts +538 -0
- package/src/usageGuide.ts +4 -4
- package/test-fixtures/identity/runner.d.mts +12 -0
- package/test-fixtures/identity/runner.mjs +282 -0
- package/tests/fixtures/repository-fingerprint-v1.golden.json +834 -0
- package/tests/projectIdentity.test.ts +56 -0
- package/tests/readiness.test.ts +158 -0
- package/tests/repositoryFingerprint.test.ts +26 -0
- package/tsconfig.test.json +9 -0
- package/wasm/bash.tags.scm +1 -1
- package/wasm/groovy.tags.scm +1 -1
- package/wasm/javascript.tags.scm +2 -2
- package/wasm/solidity.tags.scm +1 -1
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { mkdtemp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
7
|
+
|
|
8
|
+
const exec = promisify(execFile);
|
|
9
|
+
const ROOT_ID = '11111111-1111-4111-8111-111111111111';
|
|
10
|
+
const NESTED_ID = '22222222-2222-4222-8222-222222222222';
|
|
11
|
+
|
|
12
|
+
async function git(cwd, ...args) {
|
|
13
|
+
await exec('git', args, { cwd, env: { ...process.env, LC_ALL: 'C' } });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function initRepo(path) {
|
|
17
|
+
await mkdir(path, { recursive: true });
|
|
18
|
+
await git(path, 'init', '--initial-branch=main');
|
|
19
|
+
await git(path, 'config', 'user.email', 'identity-fixture@example.invalid');
|
|
20
|
+
await git(path, 'config', 'user.name', 'Identity Fixture');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function identity(path, projectId, projectName = 'fixture') {
|
|
24
|
+
await writeFile(
|
|
25
|
+
join(path, '.mnemonik.json'),
|
|
26
|
+
JSON.stringify({
|
|
27
|
+
schemaVersion: 1,
|
|
28
|
+
projectId,
|
|
29
|
+
projectName,
|
|
30
|
+
repositoryFingerprint: { algorithmVersion: 1, hash: 'fixture-hash' },
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function fixture(run) {
|
|
36
|
+
const path = await mkdtemp(join(tmpdir(), 'mnemonik-identity-'));
|
|
37
|
+
try {
|
|
38
|
+
await run(path);
|
|
39
|
+
} finally {
|
|
40
|
+
await rm(path, { recursive: true, force: true });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function runIdentityFixtureSuite(register, adapter) {
|
|
45
|
+
register('linked worktree resolves to the main root and identity', () =>
|
|
46
|
+
fixture(async (base) => {
|
|
47
|
+
const main = join(base, 'main');
|
|
48
|
+
const worktree = join(base, 'linked');
|
|
49
|
+
await initRepo(main);
|
|
50
|
+
await identity(main, ROOT_ID, 'main');
|
|
51
|
+
await git(main, 'add', '.mnemonik.json');
|
|
52
|
+
await git(main, 'commit', '-m', 'fixture identity');
|
|
53
|
+
await git(main, 'worktree', 'add', '-b', 'fixture-linked', worktree);
|
|
54
|
+
await identity(worktree, NESTED_ID, 'wrong-worktree-copy');
|
|
55
|
+
await mkdir(join(worktree, 'src'));
|
|
56
|
+
|
|
57
|
+
const repository = await adapter.resolveRoot(join(worktree, 'src'));
|
|
58
|
+
assert.equal(repository.kind, 'git');
|
|
59
|
+
assert.equal(repository.root, worktree);
|
|
60
|
+
assert.equal(repository.commonDir, join(main, '.git'));
|
|
61
|
+
assert.equal(repository.isLinkedWorktree, true);
|
|
62
|
+
|
|
63
|
+
const result = await adapter.resolve(join(worktree, 'src'));
|
|
64
|
+
assert.equal(result.kind, 'ok');
|
|
65
|
+
assert.equal(result.root, main);
|
|
66
|
+
assert.equal(result.identity.projectId, ROOT_ID);
|
|
67
|
+
assert.equal(result.identity.projectName, 'main');
|
|
68
|
+
assert.deepEqual(result.identity.repositoryFingerprint, {
|
|
69
|
+
algorithmVersion: 1,
|
|
70
|
+
hash: 'fixture-hash',
|
|
71
|
+
});
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
register('git repository selection ignores inherited GIT_* variables', () =>
|
|
76
|
+
fixture(async (base) => {
|
|
77
|
+
const local = join(base, 'local');
|
|
78
|
+
const other = join(base, 'other');
|
|
79
|
+
await initRepo(local);
|
|
80
|
+
await identity(local, ROOT_ID, 'local');
|
|
81
|
+
await initRepo(other);
|
|
82
|
+
await identity(other, NESTED_ID, 'other');
|
|
83
|
+
|
|
84
|
+
const savedGitDir = process.env.GIT_DIR;
|
|
85
|
+
const savedGitWorkTree = process.env.GIT_WORK_TREE;
|
|
86
|
+
process.env.GIT_DIR = join(other, '.git');
|
|
87
|
+
process.env.GIT_WORK_TREE = other;
|
|
88
|
+
try {
|
|
89
|
+
const result = await adapter.resolve(local);
|
|
90
|
+
assert.equal(result.kind, 'ok');
|
|
91
|
+
assert.equal(result.root, local);
|
|
92
|
+
assert.equal(result.identity.projectId, ROOT_ID);
|
|
93
|
+
} finally {
|
|
94
|
+
if (savedGitDir === undefined) delete process.env.GIT_DIR;
|
|
95
|
+
else process.env.GIT_DIR = savedGitDir;
|
|
96
|
+
if (savedGitWorkTree === undefined) delete process.env.GIT_WORK_TREE;
|
|
97
|
+
else process.env.GIT_WORK_TREE = savedGitWorkTree;
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
register('identity file symlinks are malformed and never followed', () =>
|
|
103
|
+
fixture(async (base) => {
|
|
104
|
+
const local = join(base, 'local');
|
|
105
|
+
const other = join(base, 'other');
|
|
106
|
+
await initRepo(local);
|
|
107
|
+
await initRepo(other);
|
|
108
|
+
await identity(other, NESTED_ID, 'other');
|
|
109
|
+
await symlink(join(other, '.mnemonik.json'), join(local, '.mnemonik.json'));
|
|
110
|
+
|
|
111
|
+
const read = await adapter.read(local);
|
|
112
|
+
assert.equal(read.kind, 'malformed');
|
|
113
|
+
assert.equal(read.detail, 'symlink');
|
|
114
|
+
const result = await adapter.resolve(local);
|
|
115
|
+
assert.equal(result.kind, 'malformed');
|
|
116
|
+
assert.equal(result.detail, 'symlink');
|
|
117
|
+
assert.equal(result.root, local);
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
register('nested repository with its own identity is a conflict', () =>
|
|
122
|
+
fixture(async (base) => {
|
|
123
|
+
const main = join(base, 'main');
|
|
124
|
+
const nested = join(main, 'vendor', 'nested');
|
|
125
|
+
await initRepo(main);
|
|
126
|
+
await identity(main, ROOT_ID, 'main');
|
|
127
|
+
await initRepo(nested);
|
|
128
|
+
await identity(nested, NESTED_ID, 'nested');
|
|
129
|
+
|
|
130
|
+
const result = await adapter.resolve(nested);
|
|
131
|
+
assert.equal(result.kind, 'conflict');
|
|
132
|
+
assert.equal(result.root, main);
|
|
133
|
+
assert.equal(result.rootIdentity.projectId, ROOT_ID);
|
|
134
|
+
assert.equal(result.nestedIdentity.projectId, NESTED_ID);
|
|
135
|
+
assert.ok(result.nested.some((entry) => entry.path === nested));
|
|
136
|
+
if (adapter.find) assert.equal(await adapter.find(nested), null);
|
|
137
|
+
})
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
register('nested repository inherits only with allowNestedInherit', () =>
|
|
141
|
+
fixture(async (base) => {
|
|
142
|
+
const main = join(base, 'main');
|
|
143
|
+
const nested = join(main, 'packages', 'nested');
|
|
144
|
+
await initRepo(main);
|
|
145
|
+
await identity(main, ROOT_ID, 'main');
|
|
146
|
+
await initRepo(nested);
|
|
147
|
+
|
|
148
|
+
const unresolved = await adapter.resolve(nested);
|
|
149
|
+
assert.equal(unresolved.kind, 'nested');
|
|
150
|
+
assert.equal(unresolved.parentIdentity?.projectId, ROOT_ID);
|
|
151
|
+
assert.ok(unresolved.nested.some((entry) => entry.path === nested));
|
|
152
|
+
if (adapter.find) assert.equal(await adapter.find(nested), null);
|
|
153
|
+
|
|
154
|
+
const inherited = await adapter.resolve(nested, { allowNestedInherit: true });
|
|
155
|
+
assert.equal(inherited.kind, 'ok');
|
|
156
|
+
assert.equal(inherited.root, main);
|
|
157
|
+
assert.equal(inherited.identity.projectId, ROOT_ID);
|
|
158
|
+
})
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
register('a rejected .git file is not a containing repository boundary', () =>
|
|
162
|
+
fixture(async (base) => {
|
|
163
|
+
const fakeParent = join(base, 'fake-parent');
|
|
164
|
+
const repository = join(fakeParent, 'repository');
|
|
165
|
+
await mkdir(fakeParent, { recursive: true });
|
|
166
|
+
await writeFile(join(fakeParent, '.git'), 'not a gitdir pointer');
|
|
167
|
+
await identity(fakeParent, ROOT_ID, 'fake-parent');
|
|
168
|
+
await initRepo(repository);
|
|
169
|
+
await identity(repository, NESTED_ID, 'repository');
|
|
170
|
+
|
|
171
|
+
const result = await adapter.resolve(repository);
|
|
172
|
+
assert.equal(result.kind, 'ok');
|
|
173
|
+
assert.equal(result.root, repository);
|
|
174
|
+
assert.equal(result.identity.projectId, NESTED_ID);
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
register('schemaVersion 2 is unknown and preserved', () =>
|
|
179
|
+
fixture(async (base) => {
|
|
180
|
+
const text = JSON.stringify({ schemaVersion: 2, projectId: ROOT_ID });
|
|
181
|
+
await writeFile(join(base, '.mnemonik.json'), text);
|
|
182
|
+
assert.deepEqual(adapter.parse(text), { kind: 'unknown_version', version: 2 });
|
|
183
|
+
assert.deepEqual(await adapter.read(base), { kind: 'unknown_version', version: 2 });
|
|
184
|
+
const resolved = await adapter.resolve(base);
|
|
185
|
+
assert.equal(resolved.kind, 'unknown_version');
|
|
186
|
+
assert.equal(resolved.version, 2);
|
|
187
|
+
assert.equal(resolved.root, base);
|
|
188
|
+
if (adapter.find) assert.equal(await adapter.find(base), null);
|
|
189
|
+
assert.equal(await readFile(join(base, '.mnemonik.json'), 'utf8'), text);
|
|
190
|
+
})
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
register('v0 identity without schemaVersion is unknown', () =>
|
|
194
|
+
fixture(async (base) => {
|
|
195
|
+
const text = JSON.stringify({ projectId: ROOT_ID, projectName: 'v0' });
|
|
196
|
+
await writeFile(join(base, '.mnemonik.json'), text);
|
|
197
|
+
const parsed = adapter.parse(text);
|
|
198
|
+
assert.equal(parsed.kind, 'unknown_version');
|
|
199
|
+
assert.equal(parsed.version, undefined);
|
|
200
|
+
const read = await adapter.read(base);
|
|
201
|
+
assert.equal(read.kind, 'unknown_version');
|
|
202
|
+
assert.equal(read.version, undefined);
|
|
203
|
+
const resolved = await adapter.resolve(base);
|
|
204
|
+
assert.equal(resolved.kind, 'unknown_version');
|
|
205
|
+
assert.equal(resolved.version, undefined);
|
|
206
|
+
if (adapter.find) assert.equal(await adapter.find(base), null);
|
|
207
|
+
})
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
register('malformed JSON is malformed', () =>
|
|
211
|
+
fixture(async (base) => {
|
|
212
|
+
const text = '{ not json';
|
|
213
|
+
await writeFile(join(base, '.mnemonik.json'), text);
|
|
214
|
+
assert.equal(adapter.parse(text).kind, 'malformed');
|
|
215
|
+
assert.equal((await adapter.read(base)).kind, 'malformed');
|
|
216
|
+
const resolved = await adapter.resolve(base);
|
|
217
|
+
assert.equal(resolved.kind, 'malformed');
|
|
218
|
+
assert.equal(resolved.root, base);
|
|
219
|
+
if (adapter.find) assert.equal(await adapter.find(base), null);
|
|
220
|
+
})
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
register('folder outside git is plain', () =>
|
|
224
|
+
fixture(async (base) => {
|
|
225
|
+
const repository = await adapter.resolveRoot(base);
|
|
226
|
+
assert.deepEqual(repository, { kind: 'plain', root: base });
|
|
227
|
+
})
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
register('plain folders use the nearest ancestor identity', () =>
|
|
231
|
+
fixture(async (base) => {
|
|
232
|
+
const nearer = join(base, 'projects', 'nearest');
|
|
233
|
+
const nested = join(nearer, 'src', 'feature');
|
|
234
|
+
await identity(base, ROOT_ID, 'outer');
|
|
235
|
+
await mkdir(nested, { recursive: true });
|
|
236
|
+
await identity(nearer, NESTED_ID, 'nearest');
|
|
237
|
+
|
|
238
|
+
const result = await adapter.resolve(nested);
|
|
239
|
+
assert.equal(result.kind, 'ok');
|
|
240
|
+
assert.equal(result.root, nearer);
|
|
241
|
+
assert.equal(result.identity.projectId, NESTED_ID);
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
register('plain folder identity search does not walk above the user home', () =>
|
|
246
|
+
fixture(async (base) => {
|
|
247
|
+
const home = join(base, 'home');
|
|
248
|
+
const nested = join(home, 'projects', 'plain', 'src');
|
|
249
|
+
await identity(base, ROOT_ID, 'above-home');
|
|
250
|
+
await mkdir(nested, { recursive: true });
|
|
251
|
+
|
|
252
|
+
const savedHome = process.env.HOME;
|
|
253
|
+
process.env.HOME = home;
|
|
254
|
+
try {
|
|
255
|
+
const result = await adapter.resolve(nested);
|
|
256
|
+
assert.equal(result.kind, 'absent');
|
|
257
|
+
assert.equal(result.root, nested);
|
|
258
|
+
} finally {
|
|
259
|
+
if (savedHome === undefined) delete process.env.HOME;
|
|
260
|
+
else process.env.HOME = savedHome;
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
register('missing git binary is git_unavailable and hooks fail closed', () =>
|
|
266
|
+
fixture(async (base) => {
|
|
267
|
+
const emptyPath = join(base, 'empty-path');
|
|
268
|
+
await mkdir(emptyPath);
|
|
269
|
+
const savedPath = process.env.PATH;
|
|
270
|
+
process.env.PATH = emptyPath;
|
|
271
|
+
try {
|
|
272
|
+
const repository = await adapter.resolveRoot(base);
|
|
273
|
+
assert.equal(repository.kind, 'git_unavailable');
|
|
274
|
+
assert.match(repository.detail, /git|ENOENT/i);
|
|
275
|
+
if (adapter.find) assert.equal(await adapter.find(base), null);
|
|
276
|
+
} finally {
|
|
277
|
+
if (savedPath === undefined) delete process.env.PATH;
|
|
278
|
+
else process.env.PATH = savedPath;
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
);
|
|
282
|
+
}
|