log-llm-config 1.0.30 → 1.0.31
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/endpoint_client/startup_api.js +1 -5
- package/dist/log_config_files/collection/config_collector.js +26 -3
- package/dist/log_config_files/collection/directory_collector.js +4 -1
- package/dist/log_config_files/runtime/main_runner.js +5 -0
- package/dist/log_config_files/sender/batch_sender.js +0 -7
- package/dist/log_config_files/sender/signing.js +6 -19
- package/package.json +4 -3
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { executeBody } from './http_transport.js';
|
|
2
2
|
export const postStartupPayload = async (endpointUrl, body, timeoutMs = 5000) => {
|
|
3
3
|
const payload = JSON.stringify(body);
|
|
4
|
-
|
|
5
|
-
const { statusCode, statusMessage, headers, body: responseBody } = await executeBody(endpointUrl, 'POST', payload, timeoutMs);
|
|
6
|
-
console.log(`HTTP ${statusCode} ${statusMessage}`);
|
|
7
|
-
console.log('Response headers:', headers);
|
|
4
|
+
const { statusCode, statusMessage, body: responseBody } = await executeBody(endpointUrl, 'POST', payload, timeoutMs);
|
|
8
5
|
if (statusCode >= 400) {
|
|
9
6
|
const msg = statusCode === 413
|
|
10
7
|
? `413 Request Entity Too Large: ${responseBody.substring(0, 200)}`
|
|
@@ -13,7 +10,6 @@ export const postStartupPayload = async (endpointUrl, body, timeoutMs = 5000) =>
|
|
|
13
10
|
}
|
|
14
11
|
if (!responseBody)
|
|
15
12
|
return { status: 'error', message: 'Empty response from endpoint' };
|
|
16
|
-
console.log('Raw endpoint response body:', responseBody);
|
|
17
13
|
try {
|
|
18
14
|
return JSON.parse(responseBody);
|
|
19
15
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { existsSync, statSync } from 'node:fs';
|
|
1
|
+
import { existsSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
2
3
|
import { homedir } from 'node:os';
|
|
3
4
|
import { readJSONFile, readMCPConfig, readMarkdownFile, readInstalledExtensions } from '../readers/file_readers.js';
|
|
4
5
|
import { getExtensionsCachePath, getExtensionsCacheInstalledSuffix, getVscdbPath } from '../paths/path_constants_helpers.js';
|
|
@@ -46,9 +47,18 @@ function readContentByFormat(path, format) {
|
|
|
46
47
|
}
|
|
47
48
|
function collectRegularFileEntry(t, enrichByFileType) {
|
|
48
49
|
const format = t.content_format || 'json';
|
|
49
|
-
|
|
50
|
+
let content = readContentByFormat(t.path, format);
|
|
50
51
|
if (content === null)
|
|
51
52
|
return null;
|
|
53
|
+
// For JSON-format files, backend/policy engine expect raw_content to be the parsed object (e.g. permissions.allow)
|
|
54
|
+
if (format === 'json' && typeof content === 'string') {
|
|
55
|
+
try {
|
|
56
|
+
content = JSON.parse(content);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// leave as string if parse fails
|
|
60
|
+
}
|
|
61
|
+
}
|
|
52
62
|
let raw;
|
|
53
63
|
if (t.raw_key && typeof content === 'string') {
|
|
54
64
|
raw = { [t.raw_key]: content };
|
|
@@ -81,7 +91,20 @@ function handleInstalledExtensions(handledSpecialPaths, configFiles, extensionsC
|
|
|
81
91
|
configFiles.push({ file_type: 'cursor_extensions', file_path: `${extensionsCachePath}${suffix}`, raw_content: { installedExtensions: installed, source: 'extensions.user.cache', extracted_at: new Date().toISOString() } });
|
|
82
92
|
}
|
|
83
93
|
function collectConfigFilesFromPatterns(patterns, projectRoot, onProgress, options) {
|
|
84
|
-
|
|
94
|
+
// Prefer process.env.HOME so hook invoker (e.g. Cursor) can pass real home when it differs from os.homedir()
|
|
95
|
+
const home = (process.env.HOME && process.env.HOME.trim()) || homedir();
|
|
96
|
+
try {
|
|
97
|
+
const claudeSettingsPath = join(home, '.claude', 'settings.json');
|
|
98
|
+
writeFileSync(join(process.cwd(), '.optimus-home-debug.json'), JSON.stringify({
|
|
99
|
+
process_env_HOME: process.env.HOME ?? null,
|
|
100
|
+
homedir: homedir(),
|
|
101
|
+
resolved_home: home,
|
|
102
|
+
claude_settings_path: claudeSettingsPath,
|
|
103
|
+
claude_settings_exists: existsSync(claudeSettingsPath),
|
|
104
|
+
cwd: process.cwd(),
|
|
105
|
+
}, null, 2));
|
|
106
|
+
}
|
|
107
|
+
catch (_) { }
|
|
85
108
|
const pathConstants = options?.client_path_constants;
|
|
86
109
|
if (!pathConstants)
|
|
87
110
|
throw new Error('client_path_constants required from API response but not provided');
|
|
@@ -32,7 +32,10 @@ function collectDirectoryEntries(t) {
|
|
|
32
32
|
if (!entry.isFile() || !matchName(entry.name))
|
|
33
33
|
continue;
|
|
34
34
|
const fullPath = join(t.path, entry.name);
|
|
35
|
-
|
|
35
|
+
// Prefer parsed JSON for .json files so backend/policy engine see top-level keys (e.g. permissions.allow)
|
|
36
|
+
const content = entry.name.endsWith('.json')
|
|
37
|
+
? readJSONFile(fullPath) ?? readMarkdownFile(fullPath)
|
|
38
|
+
: readMarkdownFile(fullPath) ?? readJSONFile(fullPath);
|
|
36
39
|
if (content !== null) {
|
|
37
40
|
const raw = typeof content === 'string' ? { content, source: 'file' } : content;
|
|
38
41
|
results.push({ file_type: t.file_type, file_path: fullPath, raw_content: raw });
|
|
@@ -118,6 +118,11 @@ async function main() {
|
|
|
118
118
|
const collectMs = Date.now() - collectStartMs;
|
|
119
119
|
const fileTypes = [...new Set(configFiles.map((c) => c.file_type))].join(', ');
|
|
120
120
|
hookRunLog(`collected ${configFiles.length} config file(s) collect_ms=${collectMs} file_types=${fileTypes}`);
|
|
121
|
+
const claudeSettings = configFiles.filter((c) => c.file_type === 'claude_settings');
|
|
122
|
+
if (claudeSettings.length > 0)
|
|
123
|
+
hookRunLog(`claude_settings in batch: ${claudeSettings.length} path(s): ${claudeSettings.map((c) => c.file_path).join(', ')}`);
|
|
124
|
+
else
|
|
125
|
+
hookRunLog(`claude_settings in batch: 0 (none collected)`);
|
|
121
126
|
if (configFiles.length === 0) {
|
|
122
127
|
hookRunLog('no config files found, exiting');
|
|
123
128
|
process.exit(0);
|
|
@@ -103,13 +103,6 @@ async function sendConfigFilesBatch(configFiles, hardwareUuid, authKey, hookRequ
|
|
|
103
103
|
catch (error) {
|
|
104
104
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
105
105
|
hookRunLog(`batch chunk error: ${errorMessage}`);
|
|
106
|
-
const is413 = errorMessage.includes('413') || errorMessage.includes('Request Entity Too Large') || errorMessage.includes('Entity Too Large');
|
|
107
|
-
if (is413 && chunk.length > 1) {
|
|
108
|
-
hookRunLog(`413 error, splitting ${chunk.length} files`);
|
|
109
|
-
splitChunk(chunks, chunkIndex);
|
|
110
|
-
// Don't increment — retry with the smaller first half
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
106
|
totals.failed += chunk.length;
|
|
114
107
|
}
|
|
115
108
|
chunkIndex++;
|
|
@@ -1,27 +1,14 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
if (Array.isArray(value)) {
|
|
5
|
-
return value.map(canonicalizeValue);
|
|
6
|
-
}
|
|
7
|
-
if (value && typeof value === 'object') {
|
|
8
|
-
const sortedKeys = Object.keys(value).sort();
|
|
9
|
-
const result = {};
|
|
10
|
-
for (const key of sortedKeys) {
|
|
11
|
-
result[key] = canonicalizeValue(value[key]);
|
|
12
|
-
}
|
|
13
|
-
return result;
|
|
14
|
-
}
|
|
15
|
-
return value;
|
|
16
|
-
}
|
|
17
|
-
/** Canonicalize payload (sort keys, compact JSON) to match server. */
|
|
2
|
+
import canonicalize from 'canonicalize';
|
|
3
|
+
/** RFC 8785 canonical JSON — must match server's rfc8785.dumps() exactly. */
|
|
18
4
|
function canonicalizePayload(payload) {
|
|
19
|
-
|
|
5
|
+
const out = canonicalize(payload);
|
|
6
|
+
return out ?? '{}';
|
|
20
7
|
}
|
|
21
|
-
/** Create HMAC-SHA256 signature for a payload. */
|
|
8
|
+
/** Create HMAC-SHA256 signature for a payload (canonicalize then sign). */
|
|
22
9
|
function createSignature(payload, keyHex) {
|
|
23
10
|
const canonicalPayload = canonicalizePayload(payload);
|
|
24
11
|
const keyBuffer = Buffer.from(keyHex, 'hex');
|
|
25
12
|
return crypto.createHmac('sha256', keyBuffer).update(canonicalPayload).digest('hex');
|
|
26
13
|
}
|
|
27
|
-
export {
|
|
14
|
+
export { canonicalizePayload, createSignature };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "log-llm-config",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"description": "CLI helpers for logging hardware UUIDs and posting startup payloads to Optimus Security.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"vitest": "^4.0.15"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"axios": "^1.7.9"
|
|
52
|
+
"axios": "^1.7.9",
|
|
53
|
+
"canonicalize": "^2.1.0"
|
|
53
54
|
}
|
|
54
|
-
}
|
|
55
|
+
}
|