@karmaniverous/jeeves-meta 0.3.1 → 0.3.3
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/cli.js +53 -22
- package/dist/index.d.ts +6 -6
- package/dist/index.js +53 -22
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -48,20 +48,20 @@ const synthConfigSchema = z.object({
|
|
|
48
48
|
/** Number of metas to synthesize per invocation. */
|
|
49
49
|
batchSize: z.number().int().min(1).default(1),
|
|
50
50
|
/**
|
|
51
|
-
* Watcher metadata properties
|
|
52
|
-
* Virtual rules
|
|
53
|
-
*
|
|
51
|
+
* Watcher metadata properties applied to live .meta/meta.json files.
|
|
52
|
+
* Virtual rules set these on every indexed live meta point.
|
|
53
|
+
* Discovery filter is derived from these properties.
|
|
54
|
+
* Default: `\{ _meta: "current" \}`
|
|
54
55
|
*/
|
|
55
|
-
metaProperty: z
|
|
56
|
-
.object({ domains: z.array(z.string()).min(1) })
|
|
57
|
-
.default({ domains: ['meta'] }),
|
|
56
|
+
metaProperty: z.record(z.string(), z.unknown()).default({ _meta: 'current' }),
|
|
58
57
|
/**
|
|
59
|
-
* Watcher metadata properties
|
|
60
|
-
* Virtual rules
|
|
58
|
+
* Watcher metadata properties applied to .meta/archive/** snapshots.
|
|
59
|
+
* Virtual rules set these on every indexed archive point.
|
|
60
|
+
* Default: `\{ _meta: "archive" \}`
|
|
61
61
|
*/
|
|
62
62
|
metaArchiveProperty: z
|
|
63
|
-
.
|
|
64
|
-
.default({
|
|
63
|
+
.record(z.string(), z.unknown())
|
|
64
|
+
.default({ _meta: 'archive' }),
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
/**
|
|
@@ -373,21 +373,50 @@ async function paginatedScan(watcher, params) {
|
|
|
373
373
|
*
|
|
374
374
|
* @module discovery/discoverMetas
|
|
375
375
|
*/
|
|
376
|
+
/**
|
|
377
|
+
* Build a single Qdrant filter clause from a key-value pair.
|
|
378
|
+
*
|
|
379
|
+
* Arrays use `match.value` on the first element (Qdrant array membership).
|
|
380
|
+
* Scalars (string, number, boolean) use `match.value` directly.
|
|
381
|
+
* Objects and other non-filterable types are skipped with a warning.
|
|
382
|
+
*/
|
|
383
|
+
function buildMatchClause(key, value) {
|
|
384
|
+
if (Array.isArray(value)) {
|
|
385
|
+
if (value.length === 0)
|
|
386
|
+
return null;
|
|
387
|
+
return { key, match: { value: value[0] } };
|
|
388
|
+
}
|
|
389
|
+
if (typeof value === 'string' ||
|
|
390
|
+
typeof value === 'number' ||
|
|
391
|
+
typeof value === 'boolean') {
|
|
392
|
+
return { key, match: { value } };
|
|
393
|
+
}
|
|
394
|
+
// Non-filterable value (object, null, etc.) — valid for tagging but
|
|
395
|
+
// cannot be expressed as a Qdrant match clause.
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
376
398
|
/**
|
|
377
399
|
* Build a Qdrant filter from config metaProperty.
|
|
378
400
|
*
|
|
401
|
+
* Iterates all key-value pairs in `metaProperty` (a generic record)
|
|
402
|
+
* to construct `must` clauses. Always appends `file_path: meta.json`
|
|
403
|
+
* for deduplication.
|
|
404
|
+
*
|
|
379
405
|
* @param config - Synth config with metaProperty.
|
|
380
406
|
* @returns Qdrant filter object for scanning live metas.
|
|
381
407
|
*/
|
|
382
408
|
function buildMetaFilter(config) {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
409
|
+
const must = [];
|
|
410
|
+
for (const [key, value] of Object.entries(config.metaProperty)) {
|
|
411
|
+
const clause = buildMatchClause(key, value);
|
|
412
|
+
if (clause)
|
|
413
|
+
must.push(clause);
|
|
414
|
+
}
|
|
415
|
+
must.push({
|
|
416
|
+
key: 'file_path',
|
|
417
|
+
match: { text: 'meta.json' },
|
|
418
|
+
});
|
|
419
|
+
return { must };
|
|
391
420
|
}
|
|
392
421
|
/**
|
|
393
422
|
* Discover all .meta/ directories via watcher scan.
|
|
@@ -405,16 +434,16 @@ async function discoverMetas(config, watcher) {
|
|
|
405
434
|
filter,
|
|
406
435
|
fields: ['file_path'],
|
|
407
436
|
});
|
|
408
|
-
// Deduplicate by
|
|
437
|
+
// Deduplicate by .meta/ directory path (handles multi-chunk files)
|
|
409
438
|
const seen = new Set();
|
|
410
439
|
const metaPaths = [];
|
|
411
440
|
for (const sf of scanFiles) {
|
|
412
441
|
const fp = normalizePath$1(sf.file_path);
|
|
413
|
-
if (seen.has(fp))
|
|
414
|
-
continue;
|
|
415
|
-
seen.add(fp);
|
|
416
442
|
// Derive .meta/ directory from file_path (strip /meta.json)
|
|
417
443
|
const metaPath = fp.replace(/\/meta\.json$/, '');
|
|
444
|
+
if (seen.has(metaPath))
|
|
445
|
+
continue;
|
|
446
|
+
seen.add(metaPath);
|
|
418
447
|
metaPaths.push(metaPath);
|
|
419
448
|
}
|
|
420
449
|
return metaPaths;
|
|
@@ -1471,6 +1500,8 @@ async function orchestrateOnce(config, executor, watcher, targetPath) {
|
|
|
1471
1500
|
const candidates = [];
|
|
1472
1501
|
for (const node of tree.nodes.values()) {
|
|
1473
1502
|
const meta = metas.get(node.metaPath);
|
|
1503
|
+
if (!meta)
|
|
1504
|
+
continue; // Node not in metas map (e.g. unreadable meta.json)
|
|
1474
1505
|
const staleness = actualStaleness(meta);
|
|
1475
1506
|
if (staleness > 0) {
|
|
1476
1507
|
candidates.push({ node, meta, actualStaleness: staleness });
|
package/dist/index.d.ts
CHANGED
|
@@ -53,12 +53,8 @@ declare const synthConfigSchema: z.ZodObject<{
|
|
|
53
53
|
defaultCritic: z.ZodString;
|
|
54
54
|
skipUnchanged: z.ZodDefault<z.ZodBoolean>;
|
|
55
55
|
batchSize: z.ZodDefault<z.ZodNumber>;
|
|
56
|
-
metaProperty: z.ZodDefault<z.
|
|
57
|
-
|
|
58
|
-
}, z.core.$strip>>;
|
|
59
|
-
metaArchiveProperty: z.ZodDefault<z.ZodObject<{
|
|
60
|
-
domains: z.ZodArray<z.ZodString>;
|
|
61
|
-
}, z.core.$strip>>;
|
|
56
|
+
metaProperty: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
57
|
+
metaArchiveProperty: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
62
58
|
}, z.core.$strip>;
|
|
63
59
|
/** Inferred type for jeeves-meta configuration. */
|
|
64
60
|
type SynthConfig = z.infer<typeof synthConfigSchema>;
|
|
@@ -347,6 +343,10 @@ interface WatcherClient {
|
|
|
347
343
|
/**
|
|
348
344
|
* Build a Qdrant filter from config metaProperty.
|
|
349
345
|
*
|
|
346
|
+
* Iterates all key-value pairs in `metaProperty` (a generic record)
|
|
347
|
+
* to construct `must` clauses. Always appends `file_path: meta.json`
|
|
348
|
+
* for deduplication.
|
|
349
|
+
*
|
|
350
350
|
* @param config - Synth config with metaProperty.
|
|
351
351
|
* @returns Qdrant filter object for scanning live metas.
|
|
352
352
|
*/
|
package/dist/index.js
CHANGED
|
@@ -143,20 +143,20 @@ const synthConfigSchema = z.object({
|
|
|
143
143
|
/** Number of metas to synthesize per invocation. */
|
|
144
144
|
batchSize: z.number().int().min(1).default(1),
|
|
145
145
|
/**
|
|
146
|
-
* Watcher metadata properties
|
|
147
|
-
* Virtual rules
|
|
148
|
-
*
|
|
146
|
+
* Watcher metadata properties applied to live .meta/meta.json files.
|
|
147
|
+
* Virtual rules set these on every indexed live meta point.
|
|
148
|
+
* Discovery filter is derived from these properties.
|
|
149
|
+
* Default: `\{ _meta: "current" \}`
|
|
149
150
|
*/
|
|
150
|
-
metaProperty: z
|
|
151
|
-
.object({ domains: z.array(z.string()).min(1) })
|
|
152
|
-
.default({ domains: ['meta'] }),
|
|
151
|
+
metaProperty: z.record(z.string(), z.unknown()).default({ _meta: 'current' }),
|
|
153
152
|
/**
|
|
154
|
-
* Watcher metadata properties
|
|
155
|
-
* Virtual rules
|
|
153
|
+
* Watcher metadata properties applied to .meta/archive/** snapshots.
|
|
154
|
+
* Virtual rules set these on every indexed archive point.
|
|
155
|
+
* Default: `\{ _meta: "archive" \}`
|
|
156
156
|
*/
|
|
157
157
|
metaArchiveProperty: z
|
|
158
|
-
.
|
|
159
|
-
.default({
|
|
158
|
+
.record(z.string(), z.unknown())
|
|
159
|
+
.default({ _meta: 'archive' }),
|
|
160
160
|
});
|
|
161
161
|
|
|
162
162
|
/**
|
|
@@ -358,21 +358,50 @@ async function paginatedScan(watcher, params) {
|
|
|
358
358
|
*
|
|
359
359
|
* @module discovery/discoverMetas
|
|
360
360
|
*/
|
|
361
|
+
/**
|
|
362
|
+
* Build a single Qdrant filter clause from a key-value pair.
|
|
363
|
+
*
|
|
364
|
+
* Arrays use `match.value` on the first element (Qdrant array membership).
|
|
365
|
+
* Scalars (string, number, boolean) use `match.value` directly.
|
|
366
|
+
* Objects and other non-filterable types are skipped with a warning.
|
|
367
|
+
*/
|
|
368
|
+
function buildMatchClause(key, value) {
|
|
369
|
+
if (Array.isArray(value)) {
|
|
370
|
+
if (value.length === 0)
|
|
371
|
+
return null;
|
|
372
|
+
return { key, match: { value: value[0] } };
|
|
373
|
+
}
|
|
374
|
+
if (typeof value === 'string' ||
|
|
375
|
+
typeof value === 'number' ||
|
|
376
|
+
typeof value === 'boolean') {
|
|
377
|
+
return { key, match: { value } };
|
|
378
|
+
}
|
|
379
|
+
// Non-filterable value (object, null, etc.) — valid for tagging but
|
|
380
|
+
// cannot be expressed as a Qdrant match clause.
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
361
383
|
/**
|
|
362
384
|
* Build a Qdrant filter from config metaProperty.
|
|
363
385
|
*
|
|
386
|
+
* Iterates all key-value pairs in `metaProperty` (a generic record)
|
|
387
|
+
* to construct `must` clauses. Always appends `file_path: meta.json`
|
|
388
|
+
* for deduplication.
|
|
389
|
+
*
|
|
364
390
|
* @param config - Synth config with metaProperty.
|
|
365
391
|
* @returns Qdrant filter object for scanning live metas.
|
|
366
392
|
*/
|
|
367
393
|
function buildMetaFilter(config) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
394
|
+
const must = [];
|
|
395
|
+
for (const [key, value] of Object.entries(config.metaProperty)) {
|
|
396
|
+
const clause = buildMatchClause(key, value);
|
|
397
|
+
if (clause)
|
|
398
|
+
must.push(clause);
|
|
399
|
+
}
|
|
400
|
+
must.push({
|
|
401
|
+
key: 'file_path',
|
|
402
|
+
match: { text: 'meta.json' },
|
|
403
|
+
});
|
|
404
|
+
return { must };
|
|
376
405
|
}
|
|
377
406
|
/**
|
|
378
407
|
* Discover all .meta/ directories via watcher scan.
|
|
@@ -390,16 +419,16 @@ async function discoverMetas(config, watcher) {
|
|
|
390
419
|
filter,
|
|
391
420
|
fields: ['file_path'],
|
|
392
421
|
});
|
|
393
|
-
// Deduplicate by
|
|
422
|
+
// Deduplicate by .meta/ directory path (handles multi-chunk files)
|
|
394
423
|
const seen = new Set();
|
|
395
424
|
const metaPaths = [];
|
|
396
425
|
for (const sf of scanFiles) {
|
|
397
426
|
const fp = normalizePath$1(sf.file_path);
|
|
398
|
-
if (seen.has(fp))
|
|
399
|
-
continue;
|
|
400
|
-
seen.add(fp);
|
|
401
427
|
// Derive .meta/ directory from file_path (strip /meta.json)
|
|
402
428
|
const metaPath = fp.replace(/\/meta\.json$/, '');
|
|
429
|
+
if (seen.has(metaPath))
|
|
430
|
+
continue;
|
|
431
|
+
seen.add(metaPath);
|
|
403
432
|
metaPaths.push(metaPath);
|
|
404
433
|
}
|
|
405
434
|
return metaPaths;
|
|
@@ -1456,6 +1485,8 @@ async function orchestrateOnce(config, executor, watcher, targetPath) {
|
|
|
1456
1485
|
const candidates = [];
|
|
1457
1486
|
for (const node of tree.nodes.values()) {
|
|
1458
1487
|
const meta = metas.get(node.metaPath);
|
|
1488
|
+
if (!meta)
|
|
1489
|
+
continue; // Node not in metas map (e.g. unreadable meta.json)
|
|
1459
1490
|
const staleness = actualStaleness(meta);
|
|
1460
1491
|
if (staleness > 0) {
|
|
1461
1492
|
candidates.push({ node, meta, actualStaleness: staleness });
|