log-llm-config 1.0.31 → 1.0.32
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.
|
@@ -5,7 +5,7 @@ import { readJSONFile, readMCPConfig, readMarkdownFile, readInstalledExtensions
|
|
|
5
5
|
import { getExtensionsCachePath, getExtensionsCacheInstalledSuffix, getVscdbPath } from '../paths/path_constants_helpers.js';
|
|
6
6
|
import { resolvePatternToTargets, normalizePathSkipPrefixes } from '../paths/pattern_resolver.js';
|
|
7
7
|
import { enrichRawFromRecipe } from './enrichment_helpers.js';
|
|
8
|
-
import { collectDirectoryEntries } from './directory_collector.js';
|
|
8
|
+
import { collectDirectoryEntries, collectDirectoryMetadata } from './directory_collector.js';
|
|
9
9
|
import { collectVscdbEntries } from '../readers/vscdb_config_builder.js';
|
|
10
10
|
import { pushDerivedFilesFromRecipe } from './openclaw_helpers.js';
|
|
11
11
|
function buildCollectionContext(patterns, projectRoot, home, homeRecurseSkipDirs = [], absolutePathPrefixes = [], mcpToolGlobSpec = null, clientPathConstants = null, pathResolutionSpecs = null) {
|
|
@@ -124,7 +124,14 @@ function collectConfigFilesFromPatterns(patterns, projectRoot, onProgress, optio
|
|
|
124
124
|
onProgress(`scanning file_type=${t.file_type}`);
|
|
125
125
|
}
|
|
126
126
|
if (t.isDirectory) {
|
|
127
|
-
|
|
127
|
+
if (metadataOnlyFileTypes.has(t.file_type) || t.collect_style === 'metadata') {
|
|
128
|
+
const entry = collectDirectoryMetadata(t);
|
|
129
|
+
if (entry)
|
|
130
|
+
configFiles.push(entry);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
configFiles.push(...collectDirectoryEntries(t));
|
|
134
|
+
}
|
|
128
135
|
continue;
|
|
129
136
|
}
|
|
130
137
|
if (extensionsInstalledSuffix && t.path.includes(extensionsInstalledSuffix)) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readdirSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { readJSONFile, readMarkdownFile } from '../readers/file_readers.js';
|
|
4
4
|
function collectSubdirMdFiles(dirPath, fileType, mdFilename, source) {
|
|
@@ -50,4 +50,47 @@ function collectDirectoryEntries(t) {
|
|
|
50
50
|
}
|
|
51
51
|
return results;
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
/**
|
|
54
|
+
* For metadata-style DIR targets: scan files matching dir_glob, return one entry
|
|
55
|
+
* with the highest mtime found. Falls back to the directory's own mtime if no files match.
|
|
56
|
+
*/
|
|
57
|
+
function collectDirectoryMetadata(t) {
|
|
58
|
+
try {
|
|
59
|
+
const dirStat = statSync(t.path);
|
|
60
|
+
let bestMtime = dirStat.mtime;
|
|
61
|
+
let bestPath = t.path;
|
|
62
|
+
const glob = t.dir_glob ?? '*';
|
|
63
|
+
const matchName = (name) => {
|
|
64
|
+
if (glob === '*')
|
|
65
|
+
return true;
|
|
66
|
+
if (glob.startsWith('*.'))
|
|
67
|
+
return name.endsWith(glob.slice(1));
|
|
68
|
+
return name === glob;
|
|
69
|
+
};
|
|
70
|
+
try {
|
|
71
|
+
for (const entry of readdirSync(t.path, { withFileTypes: true })) {
|
|
72
|
+
if (!entry.isFile() || !matchName(entry.name))
|
|
73
|
+
continue;
|
|
74
|
+
try {
|
|
75
|
+
const fileStat = statSync(join(t.path, entry.name));
|
|
76
|
+
if (fileStat.mtime > bestMtime) {
|
|
77
|
+
bestMtime = fileStat.mtime;
|
|
78
|
+
bestPath = join(t.path, entry.name);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch { /* ignore unreadable files */ }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch { /* ignore unreadable dir */ }
|
|
85
|
+
return {
|
|
86
|
+
file_type: t.file_type,
|
|
87
|
+
file_path: bestPath,
|
|
88
|
+
raw_content: { filename: bestPath, last_modified: bestMtime.toISOString(), source: 'file_metadata' },
|
|
89
|
+
collect_style: 'metadata',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export { collectDirectoryEntries, collectDirectoryMetadata };
|
|
@@ -60,17 +60,27 @@ function expandGlobPathPattern(pathPattern, fileType, home, projectRoot, content
|
|
|
60
60
|
return targets;
|
|
61
61
|
const isDir = norm.endsWith('/');
|
|
62
62
|
const [before, after] = norm.split('*');
|
|
63
|
-
const beforeNorm = before.replace(/\/+$/, '');
|
|
64
63
|
const afterNorm = after.replace(/^\/+/, '');
|
|
64
|
+
// If `before` doesn't end with '/', the * is mid-segment (e.g. "extensions/saoudrizwan.claude-dev*/" →
|
|
65
|
+
// parent="extensions/", namePrefix="saoudrizwan.claude-dev"). Split on last '/' to get the real base dir.
|
|
66
|
+
let parentPart = before.replace(/\/+$/, '');
|
|
67
|
+
let namePrefix = '';
|
|
68
|
+
if (!before.endsWith('/')) {
|
|
69
|
+
const lastSlash = parentPart.lastIndexOf('/');
|
|
70
|
+
if (lastSlash !== -1) {
|
|
71
|
+
namePrefix = parentPart.slice(lastSlash + 1);
|
|
72
|
+
parentPart = parentPart.slice(0, lastSlash);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
65
75
|
let basePath;
|
|
66
|
-
if (
|
|
67
|
-
basePath = join(home,
|
|
76
|
+
if (parentPart.startsWith('~/')) {
|
|
77
|
+
basePath = join(home, parentPart.slice(2));
|
|
68
78
|
}
|
|
69
|
-
else if (
|
|
70
|
-
basePath =
|
|
79
|
+
else if (parentPart.startsWith('/') && absolutePathPrefixes.some((prefix) => parentPart.startsWith(prefix))) {
|
|
80
|
+
basePath = parentPart;
|
|
71
81
|
}
|
|
72
82
|
else {
|
|
73
|
-
basePath = join(projectRoot,
|
|
83
|
+
basePath = join(projectRoot, parentPart.startsWith('/') ? parentPart.slice(1) : parentPart);
|
|
74
84
|
}
|
|
75
85
|
if (!existsSync(basePath))
|
|
76
86
|
return targets;
|
|
@@ -78,6 +88,8 @@ function expandGlobPathPattern(pathPattern, fileType, home, projectRoot, content
|
|
|
78
88
|
for (const entry of readdirSync(basePath, { withFileTypes: true })) {
|
|
79
89
|
if (!entry.isDirectory())
|
|
80
90
|
continue;
|
|
91
|
+
if (namePrefix && !entry.name.startsWith(namePrefix))
|
|
92
|
+
continue;
|
|
81
93
|
const resolvedPath = join(basePath, entry.name, afterNorm);
|
|
82
94
|
if (!existsSync(resolvedPath))
|
|
83
95
|
continue;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
|
-
import
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
const canonicalize = createRequire(import.meta.url)('canonicalize');
|
|
3
4
|
/** RFC 8785 canonical JSON — must match server's rfc8785.dumps() exactly. */
|
|
4
5
|
function canonicalizePayload(payload) {
|
|
5
6
|
const out = canonicalize(payload);
|