@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,56 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
import { parseIdentityFile, readIdentityFile } from '../src/projectIdentityFile.js';
|
|
4
|
+
import { resolveProjectIdentity, resolveRepositoryRoot } from '../src/repositoryRoot.js';
|
|
5
|
+
import { runIdentityFixtureSuite } from '../test-fixtures/identity/runner.mjs';
|
|
6
|
+
|
|
7
|
+
runIdentityFixtureSuite(test, {
|
|
8
|
+
parse: parseIdentityFile,
|
|
9
|
+
read: readIdentityFile,
|
|
10
|
+
resolveRoot: resolveRepositoryRoot,
|
|
11
|
+
resolve: resolveProjectIdentity,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('schema-v1 field type errors are malformed', () => {
|
|
15
|
+
const projectId = '11111111-1111-4111-8111-111111111111';
|
|
16
|
+
for (const value of [
|
|
17
|
+
{ schemaVersion: 1, projectId: 42 },
|
|
18
|
+
{ schemaVersion: 1, projectId, projectName: null },
|
|
19
|
+
{ schemaVersion: 1, projectId, repositoryFingerprint: [] },
|
|
20
|
+
{ schemaVersion: 1, projectId, repositoryFingerprint: { algorithmVersion: 2, hash: 'x' } },
|
|
21
|
+
]) {
|
|
22
|
+
assert.equal(parseIdentityFile(JSON.stringify(value)).kind, 'malformed');
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('schema-v1 rejects unknown keys and names them', () => {
|
|
27
|
+
for (const value of [
|
|
28
|
+
{
|
|
29
|
+
schemaVersion: 1,
|
|
30
|
+
projectId: '11111111-1111-4111-8111-111111111111',
|
|
31
|
+
accessToken: 'Bearer secret',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
schemaVersion: 1,
|
|
35
|
+
projectId: '11111111-1111-4111-8111-111111111111',
|
|
36
|
+
repositoryFingerprint: { algorithmVersion: 1, hash: 'x', secret: 'value' },
|
|
37
|
+
},
|
|
38
|
+
]) {
|
|
39
|
+
const result = parseIdentityFile(JSON.stringify(value));
|
|
40
|
+
assert.equal(result.kind, 'malformed');
|
|
41
|
+
assert.match(result.detail, /accessToken|secret/);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('schema-v1 requires canonical RFC 4122 UUID spelling', () => {
|
|
46
|
+
for (const projectId of [
|
|
47
|
+
'11111111-1111-1111-1111-111111111111',
|
|
48
|
+
'11111111-1111-4111-7111-111111111111',
|
|
49
|
+
'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa'.toUpperCase(),
|
|
50
|
+
]) {
|
|
51
|
+
assert.equal(
|
|
52
|
+
parseIdentityFile(JSON.stringify({ schemaVersion: 1, projectId })).kind,
|
|
53
|
+
'malformed'
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import {
|
|
4
|
+
describeReadiness,
|
|
5
|
+
reduceReadiness,
|
|
6
|
+
serializeReadiness,
|
|
7
|
+
type ReadinessCondition,
|
|
8
|
+
type ReadinessState,
|
|
9
|
+
} from '../src/readiness.js';
|
|
10
|
+
|
|
11
|
+
const cases: Array<[ReadinessCondition, ReadinessState]> = [
|
|
12
|
+
[{ kind: 'selected_component_failed', reason: 'Scanner failed.' }, 'FAILED'],
|
|
13
|
+
[{ kind: 'host_trust_pending', reason: 'Approve Cursor.' }, 'ACTION_REQUIRED'],
|
|
14
|
+
[{ kind: 'vendor_policy_pending', reason: 'Allow the extension.' }, 'ACTION_REQUIRED'],
|
|
15
|
+
[{ kind: 'hooks_missing', reason: 'Hook declaration is missing.' }, 'ACTION_REQUIRED'],
|
|
16
|
+
[{ kind: 'host_not_connected', reason: 'Codex has not connected.' }, 'LIMITED'],
|
|
17
|
+
[{ kind: 'scanner_omitted', reason: 'Scanner was omitted.' }, 'LIMITED'],
|
|
18
|
+
[{ kind: 'project_uncovered', reason: 'Project is outside approved roots.' }, 'LIMITED'],
|
|
19
|
+
[{ kind: 'post_commit_upload_failed', reason: 'Result upload failed.' }, 'FAILED'],
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
test('fixed precedence chooses the worse state for every state pair', () => {
|
|
23
|
+
const rank: Record<ReadinessState, number> = {
|
|
24
|
+
READY: 0,
|
|
25
|
+
LIMITED: 1,
|
|
26
|
+
ACTION_REQUIRED: 2,
|
|
27
|
+
FAILED: 3,
|
|
28
|
+
};
|
|
29
|
+
assert.equal(reduceReadiness([]).state, 'READY');
|
|
30
|
+
for (const [left, leftState] of cases) {
|
|
31
|
+
assert.equal(reduceReadiness([left]).state, leftState);
|
|
32
|
+
for (const [right, rightState] of cases) {
|
|
33
|
+
const expected = rank[leftState] >= rank[rightState] ? leftState : rightState;
|
|
34
|
+
assert.equal(reduceReadiness([left, right]).state, expected);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('special cases and indexing semantics stay fixed', () => {
|
|
40
|
+
assert.equal(
|
|
41
|
+
reduceReadiness([
|
|
42
|
+
{ kind: 'scanner_omitted', reason: 'Limited Mode was acknowledged.' },
|
|
43
|
+
{ kind: 'selected_component_failed', reason: 'Codex failed.' },
|
|
44
|
+
]).state,
|
|
45
|
+
'FAILED'
|
|
46
|
+
);
|
|
47
|
+
assert.equal(
|
|
48
|
+
reduceReadiness([
|
|
49
|
+
{ kind: 'scanner_omitted', reason: 'Limited Mode was acknowledged.' },
|
|
50
|
+
{ kind: 'login_pending', reason: 'Sign in.' },
|
|
51
|
+
]).state,
|
|
52
|
+
'ACTION_REQUIRED'
|
|
53
|
+
);
|
|
54
|
+
assert.deepEqual(
|
|
55
|
+
reduceReadiness([{ kind: 'windows_task_creation_failed', reason: 'Access denied.' }]),
|
|
56
|
+
{
|
|
57
|
+
state: 'LIMITED',
|
|
58
|
+
reasons: ['Access denied.'],
|
|
59
|
+
actions: ['Run mnemonik scanner enable to try again.'],
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
assert.equal(
|
|
63
|
+
reduceReadiness([{ kind: 'indexing_stalled', reason: 'No heartbeat in two minutes.' }]).state,
|
|
64
|
+
'FAILED'
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('serialization keeps progress separate and omits an unattempted project', () => {
|
|
69
|
+
const withProject = serializeReadiness({
|
|
70
|
+
installation: { conditions: [] },
|
|
71
|
+
projects: [
|
|
72
|
+
{
|
|
73
|
+
projectId: 'project-1',
|
|
74
|
+
summary: { conditions: [] },
|
|
75
|
+
indexing: { total: 3100, completed: 1240 },
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
generatedAt: '2026-09-11T00:00:00.000Z',
|
|
79
|
+
});
|
|
80
|
+
assert.equal(withProject.projects?.[0]?.summary.state, 'READY');
|
|
81
|
+
assert.deepEqual(withProject.projects?.[0]?.indexing, { total: 3100, completed: 1240 });
|
|
82
|
+
|
|
83
|
+
const omitted = serializeReadiness({
|
|
84
|
+
installation: { conditions: [] },
|
|
85
|
+
generatedAt: '2026-09-11T00:00:00.000Z',
|
|
86
|
+
});
|
|
87
|
+
assert.equal(Object.hasOwn(omitted, 'projects'), false);
|
|
88
|
+
assert.equal(omitted.scanner, null);
|
|
89
|
+
assert.equal(omitted.devicesAndGrants, null);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('the CLI sentence names the concrete reason and action', () => {
|
|
93
|
+
assert.equal(
|
|
94
|
+
describeReadiness(
|
|
95
|
+
reduceReadiness([
|
|
96
|
+
{
|
|
97
|
+
kind: 'host_skipped',
|
|
98
|
+
component: 'cursor',
|
|
99
|
+
reason: 'Cursor was skipped.',
|
|
100
|
+
},
|
|
101
|
+
])
|
|
102
|
+
),
|
|
103
|
+
'Done, with one thing left. Cursor was skipped. Connect it later: mnemonik connect cursor'
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('completion counts reasons requiring attention and preserves the development note', () => {
|
|
108
|
+
assert.equal(
|
|
109
|
+
describeReadiness({ state: 'LIMITED', reasons: ['dev_release_source'], actions: [] }),
|
|
110
|
+
'Done. dev_release_source.'
|
|
111
|
+
);
|
|
112
|
+
const reasons = Array.from({ length: 7 }, (_, index) => `problem_${index}`);
|
|
113
|
+
assert.equal(
|
|
114
|
+
describeReadiness({
|
|
115
|
+
state: 'LIMITED',
|
|
116
|
+
reasons: [...reasons, 'dev_release_source'],
|
|
117
|
+
actions: ['mnemonik repair'],
|
|
118
|
+
}),
|
|
119
|
+
`Done, with 7 things left. ${reasons.map((reason) => `${reason}.`).join(' ')} dev_release_source. mnemonik repair`
|
|
120
|
+
);
|
|
121
|
+
assert.equal(
|
|
122
|
+
describeReadiness({
|
|
123
|
+
state: 'LIMITED',
|
|
124
|
+
reasons: ['Scanner needs attention.'],
|
|
125
|
+
actions: ['First action.', 'Second action.'],
|
|
126
|
+
}),
|
|
127
|
+
'Done, with one thing left. Scanner needs attention. First action. Second action.'
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('optional version receipts round-trip while old schema-1 documents remain valid', async () => {
|
|
132
|
+
const { isReadinessDocument } = await import('../src/readiness.js');
|
|
133
|
+
const old = serializeReadiness({ installation: { conditions: [] } });
|
|
134
|
+
assert.equal(isReadinessDocument(old), true);
|
|
135
|
+
assert.equal(Object.hasOwn(old, 'versions'), false);
|
|
136
|
+
const versions = {
|
|
137
|
+
cli: '0.1.0',
|
|
138
|
+
scanner: '7.95.2',
|
|
139
|
+
hosts: [
|
|
140
|
+
{ host: 'claude_code', editor: '2.1.0', hooks: '0.10.0' },
|
|
141
|
+
{ host: 'codex', hooks: '0.9.0' },
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
const current = serializeReadiness({ installation: { conditions: [] }, versions });
|
|
145
|
+
assert.deepEqual(current.versions, versions);
|
|
146
|
+
assert.equal(isReadinessDocument(current), true);
|
|
147
|
+
for (const invalid of [
|
|
148
|
+
null,
|
|
149
|
+
{ cli: 12 },
|
|
150
|
+
{ scanner: '' },
|
|
151
|
+
{ cli: 'bad\nversion' },
|
|
152
|
+
{ cli: 'x'.repeat(129) },
|
|
153
|
+
{ hosts: [{ host: 'cursor', editor: true }] },
|
|
154
|
+
{ hosts: [{ host: 'cursor', token: 'secret' }] },
|
|
155
|
+
{ secret: 'no' },
|
|
156
|
+
])
|
|
157
|
+
assert.equal(isReadinessDocument({ ...old, versions: invalid }), false);
|
|
158
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { test } from 'node:test';
|
|
4
|
+
import assert from 'node:assert/strict';
|
|
5
|
+
import { canonicalizeRemote, selectRemote } from '../src/repositoryFingerprint.js';
|
|
6
|
+
|
|
7
|
+
const golden = JSON.parse(
|
|
8
|
+
readFileSync(new URL('./fixtures/repository-fingerprint-v1.golden.json', import.meta.url), 'utf8')
|
|
9
|
+
);
|
|
10
|
+
for (const row of golden.remotes) {
|
|
11
|
+
test(`${row.group}/${row.name}`, () =>
|
|
12
|
+
assert.deepEqual(canonicalizeRemote(row.url), row.expected));
|
|
13
|
+
}
|
|
14
|
+
for (const row of golden.selections) {
|
|
15
|
+
test(`selection/${row.name}`, () => assert.deepEqual(selectRemote(row.remotes), row.expected));
|
|
16
|
+
}
|
|
17
|
+
test('all golden hashes are SHA-256 of the exact canonical UTF-8', () => {
|
|
18
|
+
for (const row of [...golden.remotes, ...golden.selections]) {
|
|
19
|
+
const expected = row.expected.fingerprint ?? row.expected;
|
|
20
|
+
if (expected.canonical)
|
|
21
|
+
assert.equal(
|
|
22
|
+
expected.hash,
|
|
23
|
+
createHash('sha256').update(expected.canonical, 'utf8').digest('hex')
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
});
|
package/wasm/bash.tags.scm
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
; Hand-written: tree-sitter-bash ships no queries/tags.scm.
|
|
2
2
|
;
|
|
3
3
|
; Node names verified by parsing a sample with the vendored bash.wasm rather than
|
|
4
|
-
; taken from documentation
|
|
4
|
+
; taken from documentation - `function_definition` carries its name in a `name`
|
|
5
5
|
; field typed `word`, covering both `foo() { }` and `function foo { }`.
|
|
6
6
|
(function_definition
|
|
7
7
|
name: (word) @name) @definition.function
|
package/wasm/groovy.tags.scm
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
;
|
|
3
3
|
; Node names verified against the vendored groovy.wasm. Groovy distinguishes a
|
|
4
4
|
; top-level `function_definition` from a `method_declaration` inside a
|
|
5
|
-
; `class_body`, and both name via an `identifier` field
|
|
5
|
+
; `class_body`, and both name via an `identifier` field - so methods get
|
|
6
6
|
; definition.method and keep their own name, which is the defect this plan
|
|
7
7
|
; exists to fix for every language.
|
|
8
8
|
(class_declaration
|
package/wasm/javascript.tags.scm
CHANGED
|
@@ -68,8 +68,8 @@
|
|
|
68
68
|
; ANCHORED TO `program` ON PURPOSE, and the anchor is load-bearing. The chunker's
|
|
69
69
|
; leaf rule only suppresses a definition nested inside ANOTHER DEFINITION; a bare
|
|
70
70
|
; block, an `if` body and a `for` initialiser are not definitions, so an
|
|
71
|
-
; unanchored variable_declarator pattern writes locals
|
|
72
|
-
; for-loop, every `const` in every block
|
|
71
|
+
; unanchored variable_declarator pattern writes locals - the `i` of every
|
|
72
|
+
; for-loop, every `const` in every block - straight into
|
|
73
73
|
; `memory_file_index.symbol_name`, where the `symbol:` leg prefix-matches them.
|
|
74
74
|
; Measured on this repo, unanchored inflates the chunk count 28.9% and makes
|
|
75
75
|
; `symbol: i` return loop bodies. python.tags.scm anchors its constant pattern to
|
package/wasm/solidity.tags.scm
CHANGED