apt-mcp-agent-setup 3.5.36 → 3.5.61
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 +123 -123
- package/bin/cli.js +1 -1
- package/build-input.json +302 -241
- package/bundle/NOTICES.md +0 -0
- package/bundle/core.enc +0 -0
- package/bundle/mcp-rules.enc +0 -0
- package/bundle/skills-aso.enc +0 -0
- package/bundle/skills-ba.enc +0 -0
- package/bundle/skills-base.enc +0 -0
- package/bundle/skills-be.enc +0 -0
- package/bundle/skills-design.enc +0 -0
- package/bundle/skills-fe.enc +0 -0
- package/bundle/skills-marketing.enc +0 -0
- package/bundle/skills-mobile.enc +0 -0
- package/bundle/skills-pm.enc +0 -0
- package/docs/technical-sources.md +7 -7
- package/integrity-manifest.json +183 -178
- package/package.json +1 -1
- package/release-check.js +30 -30
- package/src/backends/browser-tools.js +1 -1
- package/src/backends/index-cache-authority.js +1 -1
- package/src/backends/index-command.js +1 -1
- package/src/backends/index-contract.json +11 -11
- package/src/backends/index-maintenance.js +1 -1
- package/src/backends/index-store.js +1 -1
- package/src/backends/linked-worktrees.js +1 -0
- package/src/backends/profiles.js +1 -1
- package/src/backends/review_graph.py +125 -103
- package/src/backends/source-discovery.js +1 -1
- package/src/core/admission-fence.js +1 -1
- package/src/core/aso-import.js +1 -1
- package/src/core/backend-lease-recovery.js +1 -1
- package/src/core/boot-evidence.js +1 -1
- package/src/core/caller-context.js +1 -1
- package/src/core/catalog.js +1 -1
- package/src/core/claude-caller-authority.js +1 -1
- package/src/core/claude-invocation.js +1 -1
- package/src/core/claude-launch-recovery.js +1 -1
- package/src/core/claude-native.js +1 -1
- package/src/core/claude-plan.js +1 -1
- package/src/core/claude-transcript-scan.js +1 -1
- package/src/core/claude-worker-transcript.js +1 -1
- package/src/core/codex-host-metadata.js +1 -1
- package/src/core/codex-transcript-receipt.js +1 -1
- package/src/core/connection-inspector.js +1 -1
- package/src/core/content-hash-cache.js +1 -1
- package/src/core/context-metrics.js +1 -1
- package/src/core/doctor.js +1 -1
- package/src/core/draining-completion.js +1 -1
- package/src/core/execution.js +1 -1
- package/src/core/git-context.js +1 -1
- package/src/core/hook-bridge.js +1 -1
- package/src/core/hook-diagnostics.js +1 -1
- package/src/core/hook-lease.js +1 -1
- package/src/core/host-adapters.js +1 -1
- package/src/core/interrupted-boot-transport-proof.js +1 -1
- package/src/core/interrupted-natural-closure-proof.js +1 -1
- package/src/core/interrupted-operation-audit.js +1 -1
- package/src/core/interrupted-transport-proof.js +1 -1
- package/src/core/ipc-envelope.js +1 -1
- package/src/core/legacy-retirement-proof.js +1 -1
- package/src/core/memory-scope.js +1 -1
- package/src/core/memory-store.js +1 -1
- package/src/core/model-inventory.js +1 -1
- package/src/core/model-routing.js +1 -1
- package/src/core/native-dispatch.js +1 -1
- package/src/core/native-receipt.js +1 -1
- package/src/core/native-retirement.js +1 -1
- package/src/core/node-version.js +1 -1
- package/src/core/npm-cli.js +1 -1
- package/src/core/owned-command-child.js +1 -1
- package/src/core/owned-command.js +1 -1
- package/src/core/owned-lock.js +1 -1
- package/src/core/owned-process.js +1 -1
- package/src/core/pipeline-journal.js +1 -1
- package/src/core/presentations.js +1 -1
- package/src/core/quality-artifacts.js +1 -1
- package/src/core/quality.js +1 -1
- package/src/core/read-command.js +1 -1
- package/src/core/readonly-skill.js +1 -1
- package/src/core/recovery-archive.js +1 -1
- package/src/core/recovery-proof.js +1 -1
- package/src/core/resource-transaction.js +1 -1
- package/src/core/run-checkpoint.js +1 -1
- package/src/core/run-compatibility.js +1 -1
- package/src/core/run-owner.js +1 -0
- package/src/core/run-state-codec.js +1 -1
- package/src/core/runtime-authority.js +1 -1
- package/src/core/runtime-info.js +1 -1
- package/src/core/runtime-ownership.js +1 -1
- package/src/core/session.js +1 -1
- package/src/core/shared-checkout.js +1 -1
- package/src/core/skill-companions.js +1 -1
- package/src/core/skill-names.js +1 -1
- package/src/core/storage-retry.js +1 -1
- package/src/core/tool-contracts.js +1 -1
- package/src/core/transport-boot-contract.json +12 -12
- package/src/core/transport-close-contract.json +10 -10
- package/src/core/transport-contract.json +10 -10
- package/src/core/transport-pending-boot-contract.json +12 -12
- package/src/core/update-control.js +1 -1
- package/src/core/upgrade-runs.js +1 -1
- package/src/core/upgrade-stop.js +1 -1
- package/src/core/windows-job.js +1 -1
- package/src/core/workflow-policy.js +1 -1
- package/src/core/workspace-generation.js +1 -1
- package/src/core/workspace-path.js +1 -1
- package/src/installer/bounded-command.js +1 -1
- package/src/installer/candidate-preflight.js +1 -1
- package/src/installer/claude-commands.js +1 -1
- package/src/installer/codex-hook-trust.js +1 -0
- package/src/installer/connection-activation.js +1 -1
- package/src/installer/connection-supervisor.js +1 -1
- package/src/installer/deployment-draft.js +1 -1
- package/src/installer/gateway-context.js +1 -1
- package/src/installer/gateway-migration.js +1 -1
- package/src/installer/gateway-runtime.js +1 -1
- package/src/installer/global-setup.js +1 -1
- package/src/installer/hook-context-client.js +1 -1
- package/src/installer/hook-dispatcher.js +179 -179
- package/src/installer/host-hooks.js +1 -1
- package/src/installer/index-interruption-recovery.js +1 -1
- package/src/installer/index-recovery.js +1 -1
- package/src/installer/install-intent.js +1 -1
- package/src/installer/interrupted-operation-recovery.js +1 -1
- package/src/installer/legacy-prepared-plan.js +1 -1
- package/src/installer/legacy-registration.js +1 -1
- package/src/installer/managed-config.js +1 -1
- package/src/installer/migration-scope.js +1 -1
- package/src/installer/platform-config.js +1 -1
- package/src/installer/prerequisites.js +1 -1
- package/src/installer/presentations.js +1 -1
- package/src/installer/project-outcome.js +1 -1
- package/src/installer/project-setup.js +1 -1
- package/src/installer/recovery-backup-retention.js +1 -1
- package/src/installer/registration-closure.js +1 -1
- package/src/installer/registration-plan.js +1 -1
- package/src/installer/registration-receipt.js +1 -1
- package/src/installer/registrations.js +1 -1
- package/src/installer/runtime-activation.js +1 -1
- package/src/installer/runtime-child.js +1 -1
- package/src/installer/runtime-cleanup.js +1 -1
- package/src/installer/runtime-lock.js +1 -1
- package/src/installer/runtime-store.js +1 -1
- package/src/installer/runtime-supervisor.js +1 -1
- package/src/installer/setup-wizard.js +1 -1
- package/src/installer/stale-run-release.js +1 -1
- package/src/installer/uninstall.js +1 -0
- package/src/installer/update-addons.js +1 -1
- package/src/installer/update-cleanup.js +1 -1
- package/src/installer/update-executor.js +1 -1
- package/src/installer/update-history.js +1 -1
- package/src/installer/update-registration.js +1 -1
- package/src/installer/update-report.js +1 -1
- package/src/installer/update-request.js +1 -1
- package/src/installer/update-scope.js +1 -1
- package/src/installer/workspace-registry.js +1 -1
- package/src/installer/workspace-transaction.js +1 -1
- package/src/installer/workspace-update.js +1 -1
- package/src/license/crypto.js +1 -1
- package/src/license/fingerprint.js +1 -1
- package/src/license/terms.js +1 -1
- package/src/license/verify.js +1 -1
- package/src/presets/index.js +1 -1
- package/src/proxy/backends.js +1 -1
- package/src/proxy/browser-sessions.js +1 -1
- package/src/proxy/core-tools.js +1 -1
- package/src/proxy/pipeline.js +1 -1
- package/src/proxy/public-catalog.js +1 -1
- package/src/proxy/router.config.js +1 -1
- package/src/proxy/router.js +1 -1
- package/src/proxy/run-summary.js +1 -1
- package/src/proxy/server-instructions.js +1 -0
- package/src/proxy/server.js +1 -1
- package/src/proxy/workspace-gateway.js +1 -1
- package/src/templates/AGENTS.md +1 -1
- package/src/templates/CLAUDE.md +1 -1
- package/src/templates/GEMINI.md +1 -1
- package/src/templates/apt-runtime.md +5 -4
- package/src/templates/copilot-instructions.md +1 -1
- package/src/templates/cursorrules.mdc +1 -1
- package/src/templates/mcp-tools.md +4 -4
- package/src/templates/windsurfrules.md +1 -1
|
@@ -1,179 +1,179 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Embedded with a trusted installation key. Only built-in modules may be used
|
|
4
|
-
// until the committed release has been verified.
|
|
5
|
-
function hookDispatcher(root, publicKey) {
|
|
6
|
-
return { runCLI(host, event, projectPath, executionOptions = {}) {
|
|
7
|
-
const fs = require('node:fs'), path = require('node:path'), crypto = require('node:crypto');
|
|
8
|
-
// Host adapters pass the workspace as base64 so hook command shells never
|
|
9
|
-
// reinterpret path data. Keep absolute raw paths usable for internal calls.
|
|
10
|
-
const inputPath = String(projectPath);
|
|
11
|
-
const decodedProjectPath = Buffer.from(inputPath, 'base64').toString('utf8');
|
|
12
|
-
const workspaceInput = path.isAbsolute(inputPath) || !fs.existsSync(decodedProjectPath) ? inputPath : decodedProjectPath;
|
|
13
|
-
const workspace = fs.realpathSync(workspaceInput);
|
|
14
|
-
const canonical = process.platform === 'win32' ? workspace.toLowerCase() : workspace;
|
|
15
|
-
const authorityFile = path.join(workspace, '.agents', 'runtime', 'generation.json');
|
|
16
|
-
let selected;
|
|
17
|
-
try { selected = JSON.parse(fs.readFileSync(authorityFile, 'utf8')); }
|
|
18
|
-
catch (error) {
|
|
19
|
-
if (error.code !== 'ENOENT') throw error;
|
|
20
|
-
// Migration only: the workspace pin is explicit, never the machine's
|
|
21
|
-
// latest pointer or a release inferred from deployed resource version.
|
|
22
|
-
selected = JSON.parse(fs.readFileSync(path.join(root, 'workspaces',
|
|
23
|
-
crypto.createHash('sha256').update(canonical).digest('hex') + '.json'), 'utf8'));
|
|
24
|
-
}
|
|
25
|
-
if (selected.workspace && (process.platform === 'win32' ? selected.workspace.toLowerCase() : selected.workspace) !== canonical)
|
|
26
|
-
throw Error('HOOK_WORKSPACE_BINDING_CONFLICT');
|
|
27
|
-
if (!/^\d+\.\d+\.\d+$/.test(selected.version) || !/^[a-f0-9]{64}$/.test(selected.digest))
|
|
28
|
-
throw Error('HOOK_RUNTIME_BINDING_REQUIRED');
|
|
29
|
-
const release = path.join(root, 'releases', `${selected.version}-${selected.digest}`);
|
|
30
|
-
if (fs.lstatSync(release).isSymbolicLink()) throw Error('HOOK_RUNTIME_LINK_REJECTED');
|
|
31
|
-
const manifest = JSON.parse(fs.readFileSync(path.join(release, 'integrity-manifest.json'), 'utf8'));
|
|
32
|
-
if (crypto.createHash('sha256').update(JSON.stringify(manifest)).digest('hex') !== selected.digest ||
|
|
33
|
-
!crypto.verify(null, Buffer.from(JSON.stringify(manifest.files)), publicKey, Buffer.from(manifest.signature, 'base64url')))
|
|
34
|
-
throw Error('HOOK_RUNTIME_SIGNATURE_INVALID');
|
|
35
|
-
for (const required of ['src/core/hook-bridge.js'])
|
|
36
|
-
if (!manifest.files[required]) throw Error('HOOK_RUNTIME_RECONNECT_REQUIRED');
|
|
37
|
-
for (const [file, digest] of Object.entries(manifest.files)) {
|
|
38
|
-
if (path.isAbsolute(file) || file.includes('\\') || file.split('/').some(part => !part || part === '..' || part === '.'))
|
|
39
|
-
throw Error('HOOK_RUNTIME_PATH_INVALID');
|
|
40
|
-
let cursor = release;
|
|
41
|
-
for (const part of file.split('/')) {
|
|
42
|
-
cursor = path.join(cursor, part);
|
|
43
|
-
if (fs.lstatSync(cursor).isSymbolicLink()) throw Error('HOOK_RUNTIME_LINK_REJECTED');
|
|
44
|
-
}
|
|
45
|
-
if (crypto.createHash('sha256').update(fs.readFileSync(cursor)).digest('hex') !== digest)
|
|
46
|
-
throw Error('HOOK_RUNTIME_INTEGRITY_INVALID');
|
|
47
|
-
}
|
|
48
|
-
return require(path.join(release, 'src/core/hook-bridge.js')).runCLI(host, event,
|
|
49
|
-
Buffer.from(workspace, 'utf8').toString('base64'), executionOptions);
|
|
50
|
-
} };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// The parent only uses built-ins. Synchronous hashing/locks in the signed
|
|
54
|
-
// worker cannot prevent the parent from producing a blocking decision.
|
|
55
|
-
function superviseHook(root, publicKey, dispatcherSource, args, timeoutMs, passive) {
|
|
56
|
-
const cp = require('node:child_process'), crypto = require('node:crypto');
|
|
57
|
-
const lease = { id: crypto.randomUUID(), notAfter: Date.now() + timeoutMs, maxDurationMs: timeoutMs };
|
|
58
|
-
// The worker lives for one host event. APT_HOOK_PROCESS lets its runtime
|
|
59
|
-
// locks record a start hint instead of starting PowerShell on every tool call.
|
|
60
|
-
const program = `process.env.APT_HOOK_PROCESS = '1';
|
|
61
|
-
const dispatcher = (${dispatcherSource})(${JSON.stringify(root)}, ${JSON.stringify(publicKey)});
|
|
62
|
-
process.once('message', async message => {
|
|
63
|
-
try { await dispatcher.runCLI(...message.args, { hookLease: message.lease }); }
|
|
64
|
-
catch (error) { process.stderr.write('APT hook: ' + (error.message || String(error)) + '\\n'); process.exitCode = 2; }
|
|
65
|
-
finally { if (process.connected) process.disconnect(); }
|
|
66
|
-
});`;
|
|
67
|
-
return new Promise((resolve, reject) => {
|
|
68
|
-
let settled = false, output = '', errors = '', inputBytes = 0;
|
|
69
|
-
const received = [];
|
|
70
|
-
// APT allows a passive host read in every session state. A fault of APT
|
|
71
|
-
// itself, a missed deadline above all, must not refuse one. The answer is
|
|
72
|
-
// the output that lets the call proceed, or null for every other call.
|
|
73
|
-
const allowance = () => {
|
|
74
|
-
try {
|
|
75
|
-
const table = passive && passive[args[0]];
|
|
76
|
-
const allow = table && table.events[args[1]];
|
|
77
|
-
if (typeof allow !== 'string') return null;
|
|
78
|
-
const input = JSON.parse(Buffer.concat(received).toString('utf8'));
|
|
79
|
-
const name = input.tool_name;
|
|
80
|
-
if (typeof name !== 'string' || input.toolCall !== undefined || input.userStopped === true) return null;
|
|
81
|
-
return table.exact.includes(name) || table.insensitive.includes(name.toLowerCase()) ? allow : null;
|
|
82
|
-
} catch { return null; }
|
|
83
|
-
};
|
|
84
|
-
const child = cp.spawn(process.execPath, ['-e', program], { windowsHide: true, stdio: ['pipe', 'pipe', 'pipe', 'ipc'] });
|
|
85
|
-
const detach = () => {
|
|
86
|
-
clearTimeout(timer); process.stdin.unpipe(child.stdin); process.stdin.removeListener('data', countInput);
|
|
87
|
-
child.stdin.destroy();
|
|
88
|
-
};
|
|
89
|
-
const fail = code => {
|
|
90
|
-
if (settled) return;
|
|
91
|
-
settled = true; detach();
|
|
92
|
-
if (child.connected) child.disconnect();
|
|
93
|
-
child.kill(); child.stdout.destroy(); child.stderr.destroy(); child.unref();
|
|
94
|
-
const allow = allowance();
|
|
95
|
-
if (allow === null) return reject(new Error(code));
|
|
96
|
-
process.stderr.write('APT hook: ' + code + ' (not refused)\n');
|
|
97
|
-
process.stdout.write(allow + '\n');
|
|
98
|
-
process.exitCode = 0;
|
|
99
|
-
resolve();
|
|
100
|
-
};
|
|
101
|
-
const countInput = chunk => {
|
|
102
|
-
inputBytes += chunk.length;
|
|
103
|
-
if (inputBytes > 2 * 1024 * 1024) fail('HOOK_INPUT_LIMIT'); else received.push(Buffer.from(chunk));
|
|
104
|
-
};
|
|
105
|
-
const timer = setTimeout(() => fail('HOOK_DEADLINE_EXCEEDED'), timeoutMs);
|
|
106
|
-
child.on('error', () => fail('HOOK_WORKER_UNAVAILABLE'));
|
|
107
|
-
child.stdin.on('error', () => {});
|
|
108
|
-
child.stdout.on('data', chunk => { output += chunk.toString(); if (Buffer.byteLength(output) > 2 * 1024 * 1024) fail('HOOK_OUTPUT_LIMIT'); });
|
|
109
|
-
child.stderr.on('data', chunk => { errors += chunk.toString(); if (Buffer.byteLength(errors) > 64 * 1024) fail('HOOK_OUTPUT_LIMIT'); });
|
|
110
|
-
child.on('close', code => {
|
|
111
|
-
if (settled) return;
|
|
112
|
-
if (Date.now() >= lease.notAfter) return fail('HOOK_DEADLINE_EXCEEDED');
|
|
113
|
-
settled = true; detach();
|
|
114
|
-
// A worker that failed before the bridge could decide refuses nothing
|
|
115
|
-
// that APT always allows.
|
|
116
|
-
const allow = code === 0 ? null : allowance();
|
|
117
|
-
if (code === 0) { if (output) process.stdout.write(output); }
|
|
118
|
-
if (errors) process.stderr.write(errors);
|
|
119
|
-
if (allow !== null) process.stdout.write(allow + '\n');
|
|
120
|
-
process.exitCode = code === 0 || allow !== null ? 0 : 2;
|
|
121
|
-
resolve();
|
|
122
|
-
});
|
|
123
|
-
process.stdin.on('data', countInput); process.stdin.pipe(child.stdin);
|
|
124
|
-
child.send({ args, lease }, error => { if (error) fail('HOOK_WORKER_UNAVAILABLE'); });
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Only a pre-tool decision may block its host. Any other event observes
|
|
129
|
-
// something that already happened, so a dispatcher or runtime fault there is a
|
|
130
|
-
// non-blocking error: it must not reject a prompt or force a continuation.
|
|
131
|
-
function blockingEvents() {
|
|
132
|
-
const { HOSTS } = require('../core/host-adapters');
|
|
133
|
-
return Object.fromEntries(Object.entries(HOSTS).map(([host, adapter]) =>
|
|
134
|
-
[host, Object.keys(adapter.events).filter(event => adapter.events[event] === 'before-tool')]));
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// For each host: the events that guard a tool call, each with the output
|
|
138
|
-
// that lets the call proceed, and the tools APT allows in every session state.
|
|
139
|
-
function passiveReads() {
|
|
140
|
-
const { HOSTS, formatHookResult } = require('../core/host-adapters');
|
|
141
|
-
const { passiveHostTools } = require('../core/hook-bridge');
|
|
142
|
-
return Object.fromEntries(Object.entries(HOSTS).map(([host, adapter]) => [host, {
|
|
143
|
-
events: Object.fromEntries(Object.keys(adapter.events).filter(event => adapter.events[event] === 'before-tool')
|
|
144
|
-
.map(event => [event, JSON.stringify(formatHookResult(host, event, { allow: true }).output)])),
|
|
145
|
-
...passiveHostTools(host) }]));
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function renderDispatcher(runtimeRoot, publicKey, options = {}) {
|
|
149
|
-
const timeoutMs = options.timeoutMs === undefined ? 10000 : options.timeoutMs;
|
|
150
|
-
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 10000) throw new Error('HOOK_DEADLINE_INVALID');
|
|
151
|
-
return `'use strict';
|
|
152
|
-
const dispatcher = (${hookDispatcher.toString()})(${JSON.stringify(runtimeRoot)}, ${JSON.stringify(publicKey.toString())});
|
|
153
|
-
const blockingEvents = ${JSON.stringify(blockingEvents())};
|
|
154
|
-
// An unknown host or event stays blocking.
|
|
155
|
-
const failureCode = args => !blockingEvents[args[0]] || blockingEvents[args[0]].includes(args[1]) ? 2 : 1;
|
|
156
|
-
function reportFailure(error, args) {
|
|
157
|
-
process.stderr.write('APT hook: ' + (error && error.message ? error.message : String(error)) + '\\n');
|
|
158
|
-
process.exitCode = failureCode(args);
|
|
159
|
-
}
|
|
160
|
-
module.exports = { runCLI(...args) {
|
|
161
|
-
try {
|
|
162
|
-
// Generated host commands use node --eval. Direct verifier consumers keep
|
|
163
|
-
// the synchronous interface; host execution always has an outer watchdog.
|
|
164
|
-
const hostCLI = process.argv.length === 1 && process.execArgv.some(arg => arg === '-e' || arg === '--eval');
|
|
165
|
-
const result = hostCLI
|
|
166
|
-
? (${superviseHook.toString()})(${JSON.stringify(runtimeRoot)}, ${JSON.stringify(publicKey.toString())}, ${JSON.stringify(hookDispatcher.toString())}, args, ${timeoutMs}, ${JSON.stringify(passiveReads())})
|
|
167
|
-
: dispatcher.runCLI(...args);
|
|
168
|
-
if (result && typeof result.then === 'function')
|
|
169
|
-
result.then(() => { if (hostCLI && process.exitCode) process.exitCode = failureCode(args); },
|
|
170
|
-
error => reportFailure(error, args));
|
|
171
|
-
return result;
|
|
172
|
-
} catch (error) {
|
|
173
|
-
reportFailure(error, args);
|
|
174
|
-
}
|
|
175
|
-
} };
|
|
176
|
-
`;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
module.exports = { hookDispatcher, renderDispatcher };
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Embedded with a trusted installation key. Only built-in modules may be used
|
|
4
|
+
// until the committed release has been verified.
|
|
5
|
+
function hookDispatcher(root, publicKey) {
|
|
6
|
+
return { runCLI(host, event, projectPath, executionOptions = {}) {
|
|
7
|
+
const fs = require('node:fs'), path = require('node:path'), crypto = require('node:crypto');
|
|
8
|
+
// Host adapters pass the workspace as base64 so hook command shells never
|
|
9
|
+
// reinterpret path data. Keep absolute raw paths usable for internal calls.
|
|
10
|
+
const inputPath = String(projectPath);
|
|
11
|
+
const decodedProjectPath = Buffer.from(inputPath, 'base64').toString('utf8');
|
|
12
|
+
const workspaceInput = path.isAbsolute(inputPath) || !fs.existsSync(decodedProjectPath) ? inputPath : decodedProjectPath;
|
|
13
|
+
const workspace = fs.realpathSync(workspaceInput);
|
|
14
|
+
const canonical = process.platform === 'win32' ? workspace.toLowerCase() : workspace;
|
|
15
|
+
const authorityFile = path.join(workspace, '.agents', 'runtime', 'generation.json');
|
|
16
|
+
let selected;
|
|
17
|
+
try { selected = JSON.parse(fs.readFileSync(authorityFile, 'utf8')); }
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (error.code !== 'ENOENT') throw error;
|
|
20
|
+
// Migration only: the workspace pin is explicit, never the machine's
|
|
21
|
+
// latest pointer or a release inferred from deployed resource version.
|
|
22
|
+
selected = JSON.parse(fs.readFileSync(path.join(root, 'workspaces',
|
|
23
|
+
crypto.createHash('sha256').update(canonical).digest('hex') + '.json'), 'utf8'));
|
|
24
|
+
}
|
|
25
|
+
if (selected.workspace && (process.platform === 'win32' ? selected.workspace.toLowerCase() : selected.workspace) !== canonical)
|
|
26
|
+
throw Error('HOOK_WORKSPACE_BINDING_CONFLICT');
|
|
27
|
+
if (!/^\d+\.\d+\.\d+$/.test(selected.version) || !/^[a-f0-9]{64}$/.test(selected.digest))
|
|
28
|
+
throw Error('HOOK_RUNTIME_BINDING_REQUIRED');
|
|
29
|
+
const release = path.join(root, 'releases', `${selected.version}-${selected.digest}`);
|
|
30
|
+
if (fs.lstatSync(release).isSymbolicLink()) throw Error('HOOK_RUNTIME_LINK_REJECTED');
|
|
31
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(release, 'integrity-manifest.json'), 'utf8'));
|
|
32
|
+
if (crypto.createHash('sha256').update(JSON.stringify(manifest)).digest('hex') !== selected.digest ||
|
|
33
|
+
!crypto.verify(null, Buffer.from(JSON.stringify(manifest.files)), publicKey, Buffer.from(manifest.signature, 'base64url')))
|
|
34
|
+
throw Error('HOOK_RUNTIME_SIGNATURE_INVALID');
|
|
35
|
+
for (const required of ['src/core/hook-bridge.js'])
|
|
36
|
+
if (!manifest.files[required]) throw Error('HOOK_RUNTIME_RECONNECT_REQUIRED');
|
|
37
|
+
for (const [file, digest] of Object.entries(manifest.files)) {
|
|
38
|
+
if (path.isAbsolute(file) || file.includes('\\') || file.split('/').some(part => !part || part === '..' || part === '.'))
|
|
39
|
+
throw Error('HOOK_RUNTIME_PATH_INVALID');
|
|
40
|
+
let cursor = release;
|
|
41
|
+
for (const part of file.split('/')) {
|
|
42
|
+
cursor = path.join(cursor, part);
|
|
43
|
+
if (fs.lstatSync(cursor).isSymbolicLink()) throw Error('HOOK_RUNTIME_LINK_REJECTED');
|
|
44
|
+
}
|
|
45
|
+
if (crypto.createHash('sha256').update(fs.readFileSync(cursor)).digest('hex') !== digest)
|
|
46
|
+
throw Error('HOOK_RUNTIME_INTEGRITY_INVALID');
|
|
47
|
+
}
|
|
48
|
+
return require(path.join(release, 'src/core/hook-bridge.js')).runCLI(host, event,
|
|
49
|
+
Buffer.from(workspace, 'utf8').toString('base64'), executionOptions);
|
|
50
|
+
} };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// The parent only uses built-ins. Synchronous hashing/locks in the signed
|
|
54
|
+
// worker cannot prevent the parent from producing a blocking decision.
|
|
55
|
+
function superviseHook(root, publicKey, dispatcherSource, args, timeoutMs, passive) {
|
|
56
|
+
const cp = require('node:child_process'), crypto = require('node:crypto');
|
|
57
|
+
const lease = { id: crypto.randomUUID(), notAfter: Date.now() + timeoutMs, maxDurationMs: timeoutMs };
|
|
58
|
+
// The worker lives for one host event. APT_HOOK_PROCESS lets its runtime
|
|
59
|
+
// locks record a start hint instead of starting PowerShell on every tool call.
|
|
60
|
+
const program = `process.env.APT_HOOK_PROCESS = '1';
|
|
61
|
+
const dispatcher = (${dispatcherSource})(${JSON.stringify(root)}, ${JSON.stringify(publicKey)});
|
|
62
|
+
process.once('message', async message => {
|
|
63
|
+
try { await dispatcher.runCLI(...message.args, { hookLease: message.lease }); }
|
|
64
|
+
catch (error) { process.stderr.write('APT hook: ' + (error.message || String(error)) + '\\n'); process.exitCode = 2; }
|
|
65
|
+
finally { if (process.connected) process.disconnect(); }
|
|
66
|
+
});`;
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
let settled = false, output = '', errors = '', inputBytes = 0;
|
|
69
|
+
const received = [];
|
|
70
|
+
// APT allows a passive host read in every session state. A fault of APT
|
|
71
|
+
// itself, a missed deadline above all, must not refuse one. The answer is
|
|
72
|
+
// the output that lets the call proceed, or null for every other call.
|
|
73
|
+
const allowance = () => {
|
|
74
|
+
try {
|
|
75
|
+
const table = passive && passive[args[0]];
|
|
76
|
+
const allow = table && table.events[args[1]];
|
|
77
|
+
if (typeof allow !== 'string') return null;
|
|
78
|
+
const input = JSON.parse(Buffer.concat(received).toString('utf8'));
|
|
79
|
+
const name = input.tool_name;
|
|
80
|
+
if (typeof name !== 'string' || input.toolCall !== undefined || input.userStopped === true) return null;
|
|
81
|
+
return table.exact.includes(name) || table.insensitive.includes(name.toLowerCase()) ? allow : null;
|
|
82
|
+
} catch { return null; }
|
|
83
|
+
};
|
|
84
|
+
const child = cp.spawn(process.execPath, ['-e', program], { windowsHide: true, stdio: ['pipe', 'pipe', 'pipe', 'ipc'] });
|
|
85
|
+
const detach = () => {
|
|
86
|
+
clearTimeout(timer); process.stdin.unpipe(child.stdin); process.stdin.removeListener('data', countInput);
|
|
87
|
+
child.stdin.destroy();
|
|
88
|
+
};
|
|
89
|
+
const fail = code => {
|
|
90
|
+
if (settled) return;
|
|
91
|
+
settled = true; detach();
|
|
92
|
+
if (child.connected) child.disconnect();
|
|
93
|
+
child.kill(); child.stdout.destroy(); child.stderr.destroy(); child.unref();
|
|
94
|
+
const allow = allowance();
|
|
95
|
+
if (allow === null) return reject(new Error(code));
|
|
96
|
+
process.stderr.write('APT hook: ' + code + ' (not refused)\n');
|
|
97
|
+
process.stdout.write(allow + '\n');
|
|
98
|
+
process.exitCode = 0;
|
|
99
|
+
resolve();
|
|
100
|
+
};
|
|
101
|
+
const countInput = chunk => {
|
|
102
|
+
inputBytes += chunk.length;
|
|
103
|
+
if (inputBytes > 2 * 1024 * 1024) fail('HOOK_INPUT_LIMIT'); else received.push(Buffer.from(chunk));
|
|
104
|
+
};
|
|
105
|
+
const timer = setTimeout(() => fail('HOOK_DEADLINE_EXCEEDED'), timeoutMs);
|
|
106
|
+
child.on('error', () => fail('HOOK_WORKER_UNAVAILABLE'));
|
|
107
|
+
child.stdin.on('error', () => {});
|
|
108
|
+
child.stdout.on('data', chunk => { output += chunk.toString(); if (Buffer.byteLength(output) > 2 * 1024 * 1024) fail('HOOK_OUTPUT_LIMIT'); });
|
|
109
|
+
child.stderr.on('data', chunk => { errors += chunk.toString(); if (Buffer.byteLength(errors) > 64 * 1024) fail('HOOK_OUTPUT_LIMIT'); });
|
|
110
|
+
child.on('close', code => {
|
|
111
|
+
if (settled) return;
|
|
112
|
+
if (Date.now() >= lease.notAfter) return fail('HOOK_DEADLINE_EXCEEDED');
|
|
113
|
+
settled = true; detach();
|
|
114
|
+
// A worker that failed before the bridge could decide refuses nothing
|
|
115
|
+
// that APT always allows.
|
|
116
|
+
const allow = code === 0 ? null : allowance();
|
|
117
|
+
if (code === 0) { if (output) process.stdout.write(output); }
|
|
118
|
+
if (errors) process.stderr.write(errors);
|
|
119
|
+
if (allow !== null) process.stdout.write(allow + '\n');
|
|
120
|
+
process.exitCode = code === 0 || allow !== null ? 0 : 2;
|
|
121
|
+
resolve();
|
|
122
|
+
});
|
|
123
|
+
process.stdin.on('data', countInput); process.stdin.pipe(child.stdin);
|
|
124
|
+
child.send({ args, lease }, error => { if (error) fail('HOOK_WORKER_UNAVAILABLE'); });
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Only a pre-tool decision may block its host. Any other event observes
|
|
129
|
+
// something that already happened, so a dispatcher or runtime fault there is a
|
|
130
|
+
// non-blocking error: it must not reject a prompt or force a continuation.
|
|
131
|
+
function blockingEvents() {
|
|
132
|
+
const { HOSTS } = require('../core/host-adapters');
|
|
133
|
+
return Object.fromEntries(Object.entries(HOSTS).map(([host, adapter]) =>
|
|
134
|
+
[host, Object.keys(adapter.events).filter(event => adapter.events[event] === 'before-tool')]));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// For each host: the events that guard a tool call, each with the output
|
|
138
|
+
// that lets the call proceed, and the tools APT allows in every session state.
|
|
139
|
+
function passiveReads() {
|
|
140
|
+
const { HOSTS, formatHookResult } = require('../core/host-adapters');
|
|
141
|
+
const { passiveHostTools } = require('../core/hook-bridge');
|
|
142
|
+
return Object.fromEntries(Object.entries(HOSTS).map(([host, adapter]) => [host, {
|
|
143
|
+
events: Object.fromEntries(Object.keys(adapter.events).filter(event => adapter.events[event] === 'before-tool')
|
|
144
|
+
.map(event => [event, JSON.stringify(formatHookResult(host, event, { allow: true }).output)])),
|
|
145
|
+
...passiveHostTools(host) }]));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function renderDispatcher(runtimeRoot, publicKey, options = {}) {
|
|
149
|
+
const timeoutMs = options.timeoutMs === undefined ? 10000 : options.timeoutMs;
|
|
150
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 10000) throw new Error('HOOK_DEADLINE_INVALID');
|
|
151
|
+
return `'use strict';
|
|
152
|
+
const dispatcher = (${hookDispatcher.toString()})(${JSON.stringify(runtimeRoot)}, ${JSON.stringify(publicKey.toString())});
|
|
153
|
+
const blockingEvents = ${JSON.stringify(blockingEvents())};
|
|
154
|
+
// An unknown host or event stays blocking.
|
|
155
|
+
const failureCode = args => !blockingEvents[args[0]] || blockingEvents[args[0]].includes(args[1]) ? 2 : 1;
|
|
156
|
+
function reportFailure(error, args) {
|
|
157
|
+
process.stderr.write('APT hook: ' + (error && error.message ? error.message : String(error)) + '\\n');
|
|
158
|
+
process.exitCode = failureCode(args);
|
|
159
|
+
}
|
|
160
|
+
module.exports = { runCLI(...args) {
|
|
161
|
+
try {
|
|
162
|
+
// Generated host commands use node --eval. Direct verifier consumers keep
|
|
163
|
+
// the synchronous interface; host execution always has an outer watchdog.
|
|
164
|
+
const hostCLI = process.argv.length === 1 && process.execArgv.some(arg => arg === '-e' || arg === '--eval');
|
|
165
|
+
const result = hostCLI
|
|
166
|
+
? (${superviseHook.toString()})(${JSON.stringify(runtimeRoot)}, ${JSON.stringify(publicKey.toString())}, ${JSON.stringify(hookDispatcher.toString())}, args, ${timeoutMs}, ${JSON.stringify(passiveReads())})
|
|
167
|
+
: dispatcher.runCLI(...args);
|
|
168
|
+
if (result && typeof result.then === 'function')
|
|
169
|
+
result.then(() => { if (hostCLI && process.exitCode) process.exitCode = failureCode(args); },
|
|
170
|
+
error => reportFailure(error, args));
|
|
171
|
+
return result;
|
|
172
|
+
} catch (error) {
|
|
173
|
+
reportFailure(error, args);
|
|
174
|
+
}
|
|
175
|
+
} };
|
|
176
|
+
`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
module.exports = { hookDispatcher, renderDispatcher };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const _0x3b39ef=_0x314b;(function(_0x575461,_0x1d6146){const _0xe3bd2d=_0x314b,_0x2f36e1=_0x575461();while(!![]){try{const _0x1cebbe=-parseInt(_0xe3bd2d(0x1ec))/0x1+parseInt(_0xe3bd2d(0x1d8))/0x2+-parseInt(_0xe3bd2d(0x1d5))/0x3*(-parseInt(_0xe3bd2d(0x1ed))/0x4)+-parseInt(_0xe3bd2d(0x1f3))/0x5*(-parseInt(_0xe3bd2d(0x1de))/0x6)+-parseInt(_0xe3bd2d(0x1db))/0x7+-parseInt(_0xe3bd2d(0x1df))/0x8+-parseInt(_0xe3bd2d(0x1f4))/0x9*(-parseInt(_0xe3bd2d(0x1fd))/0xa);if(_0x1cebbe===_0x1d6146)break;else _0x2f36e1['push'](_0x2f36e1['shift']());}catch(_0x4674a9){_0x2f36e1['push'](_0x2f36e1['shift']());}}}(_0x530d,0xc8831));const fs=require('fs'),path=require(_0x3b39ef(0x204)),{buildHookConfig}=require(_0x3b39ef(0x1eb)),{readJsonWithBackup,parseJson}=require(_0x3b39ef(0x201));function mergeHooks(_0x61db91,_0x462a15){const _0x35e53c=_0x3b39ef;if(Array[_0x35e53c(0x1f9)](_0x462a15)){const _0x86fa25=(Array[_0x35e53c(0x1f9)](_0x61db91)?_0x61db91:[])['filter'](_0x22aa64=>!JSON['stringify'](_0x22aa64)[_0x35e53c(0x209)](_0x35e53c(0x1ff)));return[..._0x86fa25,..._0x462a15];}if(_0x462a15&&typeof _0x462a15===_0x35e53c(0x1d6)){const _0x44a2de={..._0x61db91&&typeof _0x61db91==='object'?_0x61db91:{}},_0x2031df=_0x44a2de;for(const [_0x518295,_0x3a3cf6]of Object[_0x35e53c(0x20f)](_0x462a15)){const _0x14aef0=Array[_0x35e53c(0x1f9)](_0x3a3cf6)&&!JSON[_0x35e53c(0x1fc)](_0x2031df[_0x518295]??'')['includes']('APT_HOOK_BRIDGE')&&Object['entries'](_0x2031df)[_0x35e53c(0x202)](([_0x330867,_0x586a4e])=>_0x330867[_0x35e53c(0x1d3)](_0x518295+'_')&&JSON['stringify'](_0x586a4e)[_0x35e53c(0x209)](_0x35e53c(0x1ff)));if(!_0x14aef0)_0x2031df[_0x518295]=mergeHooks(_0x2031df[_0x518295],_0x3a3cf6);}return _0x2031df;}return _0x462a15;}function installHostHooks(_0x4d2a58,_0x3cc7bb=null,_0x471096={}){const _0xa0f5d3=_0x3b39ef,_0x4bf5de=_0x471096[_0xa0f5d3(0x208)]||fs,_0x5707e7={};_0x5707e7[_0xa0f5d3(0x1fb)]=_0xa0f5d3(0x1fb),_0x5707e7[_0xa0f5d3(0x1ea)]=_0xa0f5d3(0x1e2),_0x5707e7['cursor']=_0xa0f5d3(0x1e8),_0x5707e7['antigravity']=_0xa0f5d3(0x1dc),_0x5707e7[_0xa0f5d3(0x1f0)]='vscode-copilot',_0x5707e7[_0xa0f5d3(0x20c)]=_0xa0f5d3(0x20c),_0x5707e7[_0xa0f5d3(0x1fe)]=_0xa0f5d3(0x1fe);const _0xb4c1b7=_0x5707e7;let _0x318764=path[_0xa0f5d3(0x1e5)](_0x4d2a58,_0xa0f5d3(0x1ef));if(!_0x4bf5de[_0xa0f5d3(0x1e3)](_0x318764))return[];if(_0x471096[_0xa0f5d3(0x1f5)]&&_0x471096[_0xa0f5d3(0x203)]){_0x318764=path[_0xa0f5d3(0x1e5)](_0x4d2a58,'.agents/core/hook-dispatcher.js');const _0xeb248=require(_0xa0f5d3(0x1e1))['renderDispatcher'](_0x471096[_0xa0f5d3(0x1f5)],_0x471096[_0xa0f5d3(0x203)]);if(!_0x4bf5de[_0xa0f5d3(0x1e3)](_0x318764)||_0x4bf5de[_0xa0f5d3(0x20d)](_0x318764,_0xa0f5d3(0x20a))!==_0xeb248)_0x4bf5de[_0xa0f5d3(0x1e7)](_0x318764,_0xeb248);}const _0x3cc78b=[];for(const _0x10210f of _0x3cc7bb||Object['keys'](_0xb4c1b7)[_0xa0f5d3(0x20e)](_0x8a9272=>_0x8a9272!=='claude-desktop')){const _0x3fb3da=buildHookConfig(_0xb4c1b7[_0x10210f]||_0x10210f,_0x318764,_0x4d2a58);if(!_0x3fb3da?.[_0xa0f5d3(0x204)]||!_0x3fb3da[_0xa0f5d3(0x20b)]||_0x3fb3da[_0xa0f5d3(0x1e4)])continue;const _0x30d3ae=path[_0xa0f5d3(0x1dd)](_0x4d2a58,_0x3fb3da['path']);if(path[_0xa0f5d3(0x200)](_0x4d2a58,_0x30d3ae)['startsWith']('..'))throw new Error(_0xa0f5d3(0x207));const _0x266c4f=JSON[_0xa0f5d3(0x1f8)](JSON[_0xa0f5d3(0x1fc)](_0x3fb3da['config']),(_0x27c738,_0x1311c0)=>{const _0x33804b=_0xa0f5d3;if(_0x27c738===_0x33804b(0x1fa)&&typeof _0x1311c0===_0x33804b(0x1f7)&&_0x1311c0[_0x33804b(0x1d3)](_0x33804b(0x1ee))&&!_0x1311c0[_0x33804b(0x209)](_0x33804b(0x1ff)))return _0x1311c0['replace'](_0x33804b(0x206),_0x33804b(0x1d7));return _0x1311c0;});let _0x446082;if(!_0x471096[_0xa0f5d3(0x208)])_0x446082=readJsonWithBackup(_0x30d3ae);else{if(!_0x4bf5de[_0xa0f5d3(0x1e3)](_0x30d3ae))_0x446082={};else try{_0x446082=parseJson(_0x4bf5de[_0xa0f5d3(0x20d)](_0x30d3ae,'utf8'));}catch(_0x45f9aa){const _0x5db49e={};_0x5db49e['code']=_0xa0f5d3(0x1e0);throw Object['assign'](new Error('Invalid\x20config\x20at\x20'+_0x30d3ae+';\x20original\x20file\x20was\x20preserved:\x20'+_0x45f9aa[_0xa0f5d3(0x1f6)]),_0x5db49e);}}const _0x285820=mergeHooks(_0x446082,_0x266c4f),_0xa96398={};_0xa96398[_0xa0f5d3(0x1da)]=!![],_0x4bf5de['mkdirSync'](path[_0xa0f5d3(0x1d4)](_0x30d3ae),_0xa96398),_0x4bf5de[_0xa0f5d3(0x1e7)](_0x30d3ae,JSON['stringify'](_0x285820,null,0x2)+'\x0a');const _0x42f98e={};_0x42f98e[_0xa0f5d3(0x1f2)]=_0x10210f,_0x42f98e[_0xa0f5d3(0x204)]=_0x3fb3da['path'],_0x42f98e[_0xa0f5d3(0x205)]=![],_0x42f98e[_0xa0f5d3(0x1f1)]=![],_0x42f98e[_0xa0f5d3(0x1e9)]='installed-unobserved',_0x3cc78b[_0xa0f5d3(0x1e6)](_0x42f98e);}return _0x3cc78b;}function _0x314b(_0x54fe93,_0x1bcea5){_0x54fe93=_0x54fe93-0x1d3;const _0x530d48=_0x530d();let _0x314b68=_0x530d48[_0x54fe93];if(_0x314b['cSwDoq']===undefined){var _0x17a11b=function(_0x42d780){const _0x2238d1='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0xfd02cb='',_0x22ee82='';for(let _0x6c2713=0x0,_0x515b04,_0x517145,_0x17251e=0x0;_0x517145=_0x42d780['charAt'](_0x17251e++);~_0x517145&&(_0x515b04=_0x6c2713%0x4?_0x515b04*0x40+_0x517145:_0x517145,_0x6c2713++%0x4)?_0xfd02cb+=String['fromCharCode'](0xff&_0x515b04>>(-0x2*_0x6c2713&0x6)):0x0){_0x517145=_0x2238d1['indexOf'](_0x517145);}for(let _0x61db91=0x0,_0x462a15=_0xfd02cb['length'];_0x61db91<_0x462a15;_0x61db91++){_0x22ee82+='%'+('00'+_0xfd02cb['charCodeAt'](_0x61db91)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x22ee82);};_0x314b['HBVjkj']=_0x17a11b,_0x314b['JVazQZ']={},_0x314b['cSwDoq']=!![];}const _0x811710=_0x530d48[0x0],_0x3dbdb8=_0x54fe93+_0x811710,_0x187dac=_0x314b['JVazQZ'][_0x3dbdb8];return!_0x187dac?(_0x314b68=_0x314b['HBVjkj'](_0x314b68),_0x314b['JVazQZ'][_0x3dbdb8]=_0x314b68):_0x314b68=_0x187dac,_0x314b68;}const _0x17251e={};_0x17251e[_0x3b39ef(0x1d9)]=installHostHooks,_0x17251e['mergeHooks']=mergeHooks,module['exports']=_0x17251e;function _0x530d(){const _0x37c9f4=['C3rYAw5N','CgfYC2u','AxnbCNjHEq','y29TBwfUza','y29KzxG','C3rYAw5NAwz5','mtiWrKTxCer6','y2XHDwrLlwrLC2T0B3a','qvbux0Hpt0TFqLjjreDf','CMvSyxrPDMu','lI9Tyw5Hz2vKlwnVBMzPzW','C29Tzq','ChvIBgLJs2v5','Cgf0Aa','ChjVDg9JB2Xuzxn0zwq','BM9KzsaTzsaI','sg9VAYbJB25MAwCGCgf0AcbLC2nHCgvZihbYB2PLy3q','zMLSzvn5C3rLBq','Aw5JBhvKzxm','DxrMoa','y29UzMLN','D2LUzhn1CMy','CMvHzezPBgvtEw5J','zMLSDgvY','zw50CMLLCW','C3rHCNrZv2L0Aa','zgLYBMfTzq','mJe0mJnQvgTtuuy','B2jQzwn0','BM9KzsaTzsaIlYPbufrFse9ps19cuKLer0uQlW','mZiYodKWqM50Exb3','Aw5ZDgfSBeHVC3riB29RCW','CMvJDxjZAxzL','mJu5mZGWoe9ssLLeCq','yw50AwDYyxzPDhK','CMvZB2X2zq','nZKXndaWnKLbBLfPva','mJa1mJHrrg91z3y','su5wquXjrf9dt05gsuC','lI9OB29RlwrPC3bHDgnOzxi','y2XHDwrLlwnVzgu','zxHPC3rZu3LUyW','ywr2AxnVCNK','AM9PBG','ChvZAa','D3jPDgvgAwXLu3LUyW','y3vYC29Y','C3rHDhvZ','y2XHDwrL','lI4Vy29Yzs9OB3n0lwfKyxb0zxjZ','mte2nZe3nK5gB3ntsq','ntjxAefWuee','BM9KzsaTzsa','lMfNzw50CY9JB3jLl2HVB2STyNjPzgDLlMPZ','DNnJB2rL','BgL2zvzLCMLMAwvK','Ag9ZDa','nvjJsNr6Ea','ntKXmJi4zunorfLI','CNvUDgLTzvjVB3q','BwvZC2fNzq'];_0x530d=function(){return _0x37c9f4;};return _0x530d();}
|