mcp-pacemaker 2.0.1 → 2.1.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/CHANGELOG.md +105 -1
- package/CONTRIBUTING.md +49 -13
- package/README.md +361 -60
- package/THIRD_PARTY_NOTICES.txt +1 -28
- package/autostart/windows/account-task.ps1 +167 -0
- package/autostart/windows/inspect-task.ps1 +42 -0
- package/autostart/windows/inspect-worker-process-sessions.ps1 +155 -0
- package/autostart/windows/legacy-task.ps1 +301 -0
- package/autostart/windows/register-task.ps1 +11 -2
- package/bin/account-task-adapter.mjs +47 -0
- package/bin/account-upgrade-controller.mjs +198 -0
- package/bin/account-upgrade-worker.mjs +134 -0
- package/bin/account-worker-session.mjs +215 -0
- package/bin/cli-dispatch.mjs +154 -0
- package/bin/cli-main.mjs +1007 -0
- package/bin/cli-selection.mjs +43 -0
- package/bin/cli.mjs +7 -876
- package/bin/legacy-1.3.json +32 -0
- package/bin/legacy-installation.mjs +217 -0
- package/bin/legacy-task.mjs +52 -0
- package/bin/legacy-upgrade.mjs +471 -0
- package/bin/managed-runtime.mjs +170 -0
- package/bin/managed-state.mjs +257 -0
- package/bin/managed-upgrade.mjs +491 -0
- package/bin/mcp-bridge.mjs +132 -4
- package/bin/pooling-batches.mjs +13 -0
- package/bin/pooling-writer.mjs +4 -0
- package/bin/prewarm.mjs +33 -21
- package/bin/runtime-context.mjs +100 -0
- package/bin/service-control.mjs +27 -4
- package/bin/stable-launcher.mjs +54 -0
- package/bin/task-only-controller.mjs +226 -0
- package/bin/task-scope.mjs +65 -0
- package/bin/task-transaction-protocol.mjs +173 -0
- package/bin/top.mjs +22 -10
- package/bin/update-check.mjs +13 -2
- package/bin/upgrade-autostart.mjs +47 -0
- package/bin/upgrade-capability.json +8 -0
- package/bin/upgrade-dependencies.mjs +122 -0
- package/bin/upgrade-package.mjs +203 -0
- package/bin/windows-legacy/LegacyProcessBroker.build.json +42 -0
- package/bin/windows-legacy/LegacyProcessBroker.exe +0 -0
- package/bin/windows-legacy/src/AssemblyInfo.cs +8 -0
- package/bin/windows-legacy/src/LegacyNative.cs +783 -0
- package/bin/windows-legacy/src/LegacyProcessBroker.cs +841 -0
- package/bin/windows-legacy-process.mjs +241 -0
- package/bin/windows-lifetime/ProcessLifetimeHelper.build.json +38 -0
- package/bin/windows-lifetime/ProcessLifetimeHelper.exe +0 -0
- package/bin/windows-lifetime/src/AssemblyInfo.cs +8 -0
- package/bin/windows-lifetime/src/ProcessLifetimeHelper.cs +468 -0
- package/bin/windows-process-lifetime.mjs +218 -0
- package/bin/windows-task-channel/TaskChannelGuard.build.json +45 -0
- package/bin/windows-task-channel/TaskChannelGuard.exe +0 -0
- package/bin/windows-task-channel/src/AssemblyInfo.cs +8 -0
- package/bin/windows-task-channel/src/ChannelCliContext.cs +210 -0
- package/bin/windows-task-channel/src/ChannelFiles.cs +231 -0
- package/bin/windows-task-channel/src/ChannelNative.cs +477 -0
- package/bin/windows-task-channel/src/ChannelSession.cs +203 -0
- package/bin/windows-task-channel/src/TaskChannelGuard.cs +686 -0
- package/bin/windows-task-channel.mjs +335 -0
- package/docs/account-upgrades.md +205 -0
- package/docs/execution-context.md +113 -0
- package/package.json +12 -5
- package/supervisor/supervise.mjs +226 -40
- package/tools/account-upgrade/qualify-two-account.ps1 +66 -0
- package/tools/windows-legacy/README.md +225 -0
- package/tools/windows-legacy/build.ps1 +122 -0
- package/tools/windows-legacy/inventory.mjs +90 -0
- package/tools/windows-process-lifetime/README.md +119 -0
- package/tools/windows-process-lifetime/build.ps1 +122 -0
- package/tools/windows-process-lifetime/inventory.mjs +86 -0
- package/tools/windows-task-channel/README.md +329 -0
- package/tools/windows-task-channel/build.ps1 +107 -0
- package/tools/windows-task-channel/inventory.mjs +117 -0
- package/ui/dist/THIRD_PARTY_NOTICES.txt +1 -28
- package/ui/dist/assets/{index-CgPruWYi.js → index-CcwMo2sI.js} +1 -1
- package/ui/dist/assets/index-PVcuDNrN.css +1 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/third-party-manifest.json +37 -25
- package/ui/dist/assets/index-CaLPg0c-.css +0 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { durableJson, loadInstance, readInstanceState, readManagedJson, readRecoveryContext, verifySelection } from './managed-state.mjs';
|
|
6
|
+
import { managementScope } from './task-scope.mjs';
|
|
7
|
+
|
|
8
|
+
export function registerDefaultCli(home, instance) {
|
|
9
|
+
const path = join(home, 'cli-instance.json');
|
|
10
|
+
if (existsSync(path)) {
|
|
11
|
+
const selected = readManagedJson(path);
|
|
12
|
+
const current = loadInstance(selected.directory, { verifyFiles: false });
|
|
13
|
+
if (selected.protocol !== 1 ||
|
|
14
|
+
selected.id !== current.id) throw new Error('Default CLI routing identity changed.');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
durableJson(path, { protocol: 1, id: instance.id, directory: instance.directory });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function normalizeInstanceSelection(args) {
|
|
21
|
+
let directory;
|
|
22
|
+
const remaining = [];
|
|
23
|
+
for (let index = 0; index < args.length; index++) {
|
|
24
|
+
const argument = args[index];
|
|
25
|
+
if (argument === '--') {
|
|
26
|
+
remaining.push(...args.slice(index));
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
if (argument !== '--instance' &&
|
|
30
|
+
!argument.startsWith('--instance=')) {
|
|
31
|
+
remaining.push(argument);
|
|
32
|
+
const takesValue = ['--port', '--config', '--client', '--from', '--since', '--server', '--grep',
|
|
33
|
+
'--enable', '--disable', '--count', '--undo', '--to', '--registry'].includes(argument);
|
|
34
|
+
if (takesValue &&
|
|
35
|
+
index + 1 < args.length) {
|
|
36
|
+
if (args[index + 1] === '--') {
|
|
37
|
+
remaining.push(...args.slice(index + 1));
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
remaining.push(args[++index]);
|
|
41
|
+
}
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const value = argument === '--instance' ? args[++index] : argument.slice('--instance='.length);
|
|
45
|
+
if (!value ||
|
|
46
|
+
value.length > 4096 ||
|
|
47
|
+
value.startsWith('-') ||
|
|
48
|
+
value.includes('\0')) throw new Error('Invalid --instance value; no default fallback was selected.');
|
|
49
|
+
const canonical = realpathSync.native(resolve(value));
|
|
50
|
+
if (directory &&
|
|
51
|
+
canonical !== directory) throw new Error('Conflicting --instance selectors; no action was taken.');
|
|
52
|
+
directory = canonical;
|
|
53
|
+
}
|
|
54
|
+
return { directory, explicit: directory !== undefined, args: remaining };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function verifyCliSelectionTrust(root, instance, selection, { context, inspect, report = console.error }) {
|
|
58
|
+
const caller = await context();
|
|
59
|
+
if (caller.proofScope !== 'cli-effective-context-snapshot' ||
|
|
60
|
+
caller.identity?.pid !== process.pid ||
|
|
61
|
+
typeof caller.identity.ownerSid !== 'string' ||
|
|
62
|
+
caller.identity.ownerSid !== caller.actorFacts?.ownerSid ||
|
|
63
|
+
caller.helperExit?.code !== 0 ||
|
|
64
|
+
caller.helperExit.signal !== null ||
|
|
65
|
+
caller.cleanupUnverified === true) throw new Error('CLI effective-context identity or helper exit is unverified; no target code was imported.');
|
|
66
|
+
const observation = caller.observation;
|
|
67
|
+
const complete = observation?.method === 'pss-threads-held-token-query' &&
|
|
68
|
+
observation.processAccess === '0x101400' &&
|
|
69
|
+
observation.captureFlags === '0x80' &&
|
|
70
|
+
observation.threadContextFlags === 0 &&
|
|
71
|
+
observation.completeStableThreadSet === true &&
|
|
72
|
+
observation.primaryStable === true &&
|
|
73
|
+
observation.atomicFutureProtection === false &&
|
|
74
|
+
Number.isSafeInteger(observation.threadCount) &&
|
|
75
|
+
observation.threadCount > 0;
|
|
76
|
+
const ordinary = caller.ordinaryEligible === true &&
|
|
77
|
+
complete &&
|
|
78
|
+
caller.actorFacts.elevated === false &&
|
|
79
|
+
caller.actorFacts.enabledAdministrator === false &&
|
|
80
|
+
caller.actorFacts.guardThreadImpersonating === false &&
|
|
81
|
+
caller.actorFacts.parentThreadImpersonation === 'observed-none';
|
|
82
|
+
if (ordinary) return;
|
|
83
|
+
report(`CLI strict code-root checks: ${JSON.stringify(caller.reason ?? 'effective-context-unverified')}.`);
|
|
84
|
+
await inspect(instance.directory);
|
|
85
|
+
const within = relative(realpathSync.native(instance.directory), realpathSync.native(selection.root));
|
|
86
|
+
const covered = within === '' ||
|
|
87
|
+
(!isAbsolute(within) && within !== '..' && !within.startsWith(`..${sep}`));
|
|
88
|
+
if (!covered) await inspect(selection.root);
|
|
89
|
+
await inspect(root);
|
|
90
|
+
await inspect(dirname(instance.node));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function dispatchCli(root, args = process.argv.slice(2)) {
|
|
94
|
+
const scope = managementScope(args);
|
|
95
|
+
if (scope.explicit) {
|
|
96
|
+
const { runAccountController } = await import(pathToFileURL(join(root, 'bin', 'account-upgrade-controller.mjs')).href);
|
|
97
|
+
const confirm = async message => {
|
|
98
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error('Explicit account management requires interactive confirmation.');
|
|
99
|
+
const prompts = await import('@clack/prompts');
|
|
100
|
+
return await prompts.confirm({ message }) === true;
|
|
101
|
+
};
|
|
102
|
+
const result = await runAccountController(root, scope, { confirm });
|
|
103
|
+
console.log(JSON.stringify(result, null, 2));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const normalized = normalizeInstanceSelection(args);
|
|
107
|
+
let { directory } = normalized;
|
|
108
|
+
process.argv = [...process.argv.slice(0, 2), ...normalized.args];
|
|
109
|
+
const end = normalized.args.indexOf('--');
|
|
110
|
+
const options = end < 0 ? normalized.args : normalized.args.slice(0, end);
|
|
111
|
+
const recovery = options.includes('upgrade') && options.includes('--recover');
|
|
112
|
+
const pointer = join(homedir(), '.mcp-pacemaker', 'cli-instance.json');
|
|
113
|
+
let expectedId;
|
|
114
|
+
if (!directory &&
|
|
115
|
+
existsSync(pointer)) {
|
|
116
|
+
const selected = readManagedJson(pointer);
|
|
117
|
+
if (selected.protocol !== 1) throw new Error('Unknown default CLI routing protocol.');
|
|
118
|
+
directory = selected.directory;
|
|
119
|
+
expectedId = selected.id;
|
|
120
|
+
}
|
|
121
|
+
let target = root;
|
|
122
|
+
if (directory) {
|
|
123
|
+
const instance = readInstanceState(directory);
|
|
124
|
+
if (expectedId &&
|
|
125
|
+
instance.id !== expectedId) throw new Error('Default CLI instance identity changed.');
|
|
126
|
+
let selection = instance.active;
|
|
127
|
+
const journalPath = join(directory, 'journal.json');
|
|
128
|
+
if (existsSync(journalPath)) {
|
|
129
|
+
const { journal } = readRecoveryContext(directory);
|
|
130
|
+
if (recovery ||
|
|
131
|
+
!['committed', 'rolled-back', 'aborted'].includes(journal.phase)) {
|
|
132
|
+
selection = journal.previous ?? journal.recovery;
|
|
133
|
+
if (!selection) throw new Error('Interrupted activation has no retained recovery CLI.');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (recovery &&
|
|
137
|
+
!existsSync(journalPath)) throw new Error('No activation journal exists for this instance.');
|
|
138
|
+
if (selection) {
|
|
139
|
+
verifySelection(selection);
|
|
140
|
+
if (process.platform === 'win32') {
|
|
141
|
+
const { inspectTrustedCodeRoot, queryCliCallerContext } = await import(pathToFileURL(join(root, 'bin', 'windows-task-channel.mjs')).href);
|
|
142
|
+
await verifyCliSelectionTrust(root, instance, selection, { inspect: inspectTrustedCodeRoot, context: queryCliCallerContext });
|
|
143
|
+
}
|
|
144
|
+
target = selection.root;
|
|
145
|
+
}
|
|
146
|
+
process.env.MCP_PACEMAKER_CLI_CONTEXT = JSON.stringify({
|
|
147
|
+
directory: instance.directory, id: instance.id, explicit: normalized.explicit, recovery,
|
|
148
|
+
});
|
|
149
|
+
} else {
|
|
150
|
+
delete process.env.MCP_PACEMAKER_CLI_CONTEXT;
|
|
151
|
+
}
|
|
152
|
+
delete process.env.MCP_PACEMAKER_CLI_INSTANCE;
|
|
153
|
+
await import(pathToFileURL(join(target, 'bin', 'cli-main.mjs')).href);
|
|
154
|
+
}
|