@mnemonik/shared 7.100.0 → 7.101.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/dist/hostAdapter.d.ts +3 -0
- package/dist/hostAdapter.d.ts.map +1 -1
- package/dist/hostAdapter.js +85 -60
- package/dist/hostAdapter.js.map +1 -1
- package/dist/readiness.d.ts +1 -1
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +1 -5
- package/dist/readiness.js.map +1 -1
- package/dist/runtimeSigners.d.ts +3 -0
- package/dist/runtimeSigners.d.ts.map +1 -1
- package/dist/runtimeSigners.js +11 -6
- package/dist/runtimeSigners.js.map +1 -1
- package/dist/testing/hostAdapterConformance.d.ts.map +1 -1
- package/dist/testing/hostAdapterConformance.js +55 -48
- package/dist/testing/hostAdapterConformance.js.map +1 -1
- package/package.json +1 -1
- package/src/hostAdapter.ts +110 -73
- package/src/readiness.ts +1 -8
- package/src/runtimeSigners.ts +18 -6
- package/src/testing/hostAdapterConformance.ts +62 -53
- package/tests/readiness.test.ts +1 -2
|
@@ -53,6 +53,7 @@ export function hostAdapterConformance(
|
|
|
53
53
|
runtimeRoot,
|
|
54
54
|
credentialFamily: 'hook-family',
|
|
55
55
|
runtimeEntry: join(runtimeRoot, '1.0.0', 'dist', 'hook.js'),
|
|
56
|
+
installationId: '11111111-1111-4111-8111-111111111111',
|
|
56
57
|
};
|
|
57
58
|
const deps: AdapterDependencies = {
|
|
58
59
|
target,
|
|
@@ -391,55 +392,10 @@ export function hostAdapterConformance(
|
|
|
391
392
|
assert.deepEqual(await readFile(configPath('user')), before);
|
|
392
393
|
}
|
|
393
394
|
);
|
|
394
|
-
check(
|
|
395
|
-
'parses connected listings without inferring account and uses execFile arguments',
|
|
396
|
-
async ({ deps, project, target }) => {
|
|
397
|
-
let stdout = 'mnemonik: https://api.mnemonik.dev/mcp - ✔ Connected\n';
|
|
398
|
-
const calls: unknown[][] = [];
|
|
399
|
-
const host = create({
|
|
400
|
-
...deps,
|
|
401
|
-
target: { ...target, component: 'mcp' },
|
|
402
|
-
execFile: async (...args) => {
|
|
403
|
-
if (args[1][0] === '--version') return { stdout: versionOutput, stderr: '' };
|
|
404
|
-
calls.push(args);
|
|
405
|
-
return { stdout, stderr: '' };
|
|
406
|
-
},
|
|
407
|
-
});
|
|
408
|
-
const inspection = await host.verify();
|
|
409
|
-
if (options.name === 'cursor') {
|
|
410
|
-
assert.equal(inspection.authenticatedTools, false);
|
|
411
|
-
assert.equal(inspection.grant, undefined);
|
|
412
|
-
assert.deepEqual(calls, []);
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
assert.equal(inspection.authenticatedTools, true);
|
|
416
|
-
assert.equal(inspection.grant, undefined);
|
|
417
|
-
assert.deepEqual(calls[0], [
|
|
418
|
-
options.name === 'claude-code'
|
|
419
|
-
? 'claude'
|
|
420
|
-
: options.name === 'cursor'
|
|
421
|
-
? 'agent'
|
|
422
|
-
: options.name,
|
|
423
|
-
['mcp', 'list'],
|
|
424
|
-
{ env: deps.env, cwd: project, timeout: 5000, maxBuffer: 64 * 1024, windowsHide: true },
|
|
425
|
-
]);
|
|
426
|
-
for (const listing of [
|
|
427
|
-
'mnemonik: not connected',
|
|
428
|
-
'foreign: ✔ Connected',
|
|
429
|
-
'mnemonik: enabled OAuth',
|
|
430
|
-
'mnemonik-foreign: Connected',
|
|
431
|
-
'mnemonik: warning: was previously connected',
|
|
432
|
-
'unrecognized format',
|
|
433
|
-
]) {
|
|
434
|
-
stdout = listing;
|
|
435
|
-
assert.equal((await host.verify()).authenticatedTools, false);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
);
|
|
439
395
|
if (options.mcpConfig)
|
|
440
396
|
for (const scope of options.scopes)
|
|
441
397
|
check(
|
|
442
|
-
`${scope}: MCP
|
|
398
|
+
`${scope}: MCP declaration has the correct machine header and preserves foreign fields`,
|
|
443
399
|
async ({ root, project, deps, target: base }) => {
|
|
444
400
|
const target = { ...base, component: 'mcp' as const, scope };
|
|
445
401
|
const adapter = create({ ...deps, target });
|
|
@@ -458,14 +414,14 @@ export function hostAdapterConformance(
|
|
|
458
414
|
const raw = plan.changes[0]?.content.toString();
|
|
459
415
|
assert.ok(raw);
|
|
460
416
|
assert.ok(raw.includes('https://api.mnemonik.dev/mcp'));
|
|
461
|
-
const sessionHeader =
|
|
417
|
+
const sessionHeader = /headers\s*=.*"x-mcp-session-id"\s*=\s*"\{\{session_id\}\}"/u;
|
|
462
418
|
const withoutSessionHeader =
|
|
463
|
-
options.name === 'grok' && config.toml
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
);
|
|
419
|
+
options.name === 'grok' && config.toml
|
|
420
|
+
? raw.replace(/,?\s*"x-mcp-session-id"\s*=\s*"\{\{session_id\}\}"/u, '')
|
|
421
|
+
: raw;
|
|
422
|
+
if (options.name === 'grok') assert.match(raw, sessionHeader);
|
|
423
|
+
if (scope === 'user') assert.match(withoutSessionHeader, /x-mnemonik-installation-id/);
|
|
424
|
+
else assert.doesNotMatch(withoutSessionHeader, /x-mnemonik-installation-id/);
|
|
469
425
|
if (config.toml) assert.ok(raw.startsWith(original));
|
|
470
426
|
else {
|
|
471
427
|
const parsed = JSON.parse(raw);
|
|
@@ -473,6 +429,13 @@ export function hostAdapterConformance(
|
|
|
473
429
|
assert.deepEqual(parsed.mcpServers.mnemonik, {
|
|
474
430
|
...(config.type ? { type: config.type } : {}),
|
|
475
431
|
url: 'https://api.mnemonik.dev/mcp',
|
|
432
|
+
...(scope === 'user'
|
|
433
|
+
? {
|
|
434
|
+
headers: {
|
|
435
|
+
'x-mnemonik-installation-id': '11111111-1111-4111-8111-111111111111',
|
|
436
|
+
},
|
|
437
|
+
}
|
|
438
|
+
: {}),
|
|
476
439
|
});
|
|
477
440
|
}
|
|
478
441
|
const staged: FileChange[] = [];
|
|
@@ -487,6 +450,52 @@ export function hostAdapterConformance(
|
|
|
487
450
|
await writeChanges(staged);
|
|
488
451
|
assert.equal((await adapter.inspect()).declarationPresent, true);
|
|
489
452
|
assert.deepEqual((await adapter.plan()).changes, plan.changes);
|
|
453
|
+
|
|
454
|
+
if (scope === 'user') {
|
|
455
|
+
const installed = await readFile(path, 'utf8');
|
|
456
|
+
if (config.toml)
|
|
457
|
+
await writeFile(
|
|
458
|
+
path,
|
|
459
|
+
installed
|
|
460
|
+
.replace(/,?\s*"x-mnemonik-installation-id"\s*=\s*"[^"]*"/u, '')
|
|
461
|
+
.replace(/\{\s*,/u, '{')
|
|
462
|
+
.replace(/,\s*\}/u, ' }')
|
|
463
|
+
.replace(
|
|
464
|
+
'url = "https://api.mnemonik.dev/mcp"\n',
|
|
465
|
+
'url = "https://api.mnemonik.dev/mcp"\ncustom = "keep exactly"\n'
|
|
466
|
+
)
|
|
467
|
+
);
|
|
468
|
+
else {
|
|
469
|
+
const missing = JSON.parse(installed);
|
|
470
|
+
missing.mcpServers.mnemonik.custom = 'keep exactly';
|
|
471
|
+
missing.mcpServers.mnemonik.headers['x-foreign'] = 'keep exactly';
|
|
472
|
+
delete missing.mcpServers.mnemonik.headers['x-mnemonik-installation-id'];
|
|
473
|
+
await writeFile(path, JSON.stringify(missing, null, 2) + '\n');
|
|
474
|
+
}
|
|
475
|
+
const missingHeader = await readFile(path, 'utf8');
|
|
476
|
+
staged.length = 0;
|
|
477
|
+
await adapter.repair(writer, target);
|
|
478
|
+
await writeChanges(staged);
|
|
479
|
+
const repaired = await readFile(path, 'utf8');
|
|
480
|
+
assert.match(repaired, /x-mnemonik-installation-id/);
|
|
481
|
+
assert.match(repaired, /keep exactly/);
|
|
482
|
+
if (options.name === 'grok') assert.match(repaired, /x-mcp-session-id/);
|
|
483
|
+
if (config.toml) {
|
|
484
|
+
const withoutManagedHeader = repaired
|
|
485
|
+
.replace(
|
|
486
|
+
/(?:,\s*)?(?:["']x-mnemonik-installation-id["']|x-mnemonik-installation-id)\s*=\s*["'][^"']*["']\s*,?/u,
|
|
487
|
+
''
|
|
488
|
+
)
|
|
489
|
+
.replace(/\{\s*,/u, '{')
|
|
490
|
+
.replace(/,\s*\}/u, ' }');
|
|
491
|
+
assert.equal(withoutManagedHeader, missingHeader);
|
|
492
|
+
} else {
|
|
493
|
+
const withoutManagedHeader = JSON.parse(repaired);
|
|
494
|
+
delete withoutManagedHeader.mcpServers.mnemonik.headers['x-mnemonik-installation-id'];
|
|
495
|
+
assert.equal(JSON.stringify(withoutManagedHeader, null, 2) + '\n', missingHeader);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
490
499
|
staged.length = 0;
|
|
491
500
|
await adapter.uninstall(writer, target);
|
|
492
501
|
await writeChanges(staged);
|
package/tests/readiness.test.ts
CHANGED
|
@@ -13,7 +13,6 @@ const cases: Array<[ReadinessCondition, ReadinessState]> = [
|
|
|
13
13
|
[{ kind: 'host_trust_pending', reason: 'Approve Cursor.' }, 'ACTION_REQUIRED'],
|
|
14
14
|
[{ kind: 'vendor_policy_pending', reason: 'Allow the extension.' }, 'ACTION_REQUIRED'],
|
|
15
15
|
[{ kind: 'hooks_missing', reason: 'Hook declaration is missing.' }, 'ACTION_REQUIRED'],
|
|
16
|
-
[{ kind: 'host_not_connected', reason: 'Codex has not connected.' }, 'LIMITED'],
|
|
17
16
|
[{ kind: 'scanner_omitted', reason: 'Scanner was omitted.' }, 'LIMITED'],
|
|
18
17
|
[{ kind: 'project_uncovered', reason: 'Project is outside approved roots.' }, 'LIMITED'],
|
|
19
18
|
[{ kind: 'post_commit_upload_failed', reason: 'Result upload failed.' }, 'FAILED'],
|
|
@@ -100,7 +99,7 @@ test('the CLI sentence names the concrete reason and action', () => {
|
|
|
100
99
|
},
|
|
101
100
|
])
|
|
102
101
|
),
|
|
103
|
-
'Done, with one thing left. Cursor was skipped.
|
|
102
|
+
'Done, with one thing left. Cursor was skipped.'
|
|
104
103
|
);
|
|
105
104
|
});
|
|
106
105
|
|