@karmaniverous/jeeves-meta-openclaw 0.1.0 → 0.1.2
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/index.js +199 -180
- package/dist/skills/jeeves-meta/SKILL.md +28 -1
- package/dist/src/promptInjection.d.ts +1 -1
- package/dist/src/rules.d.ts +2 -1
- package/dist/src/toolsWriter.d.ts +2 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HttpWatcherClient, paginatedScan, isLocked, normalizePath,
|
|
1
|
+
import { HttpWatcherClient, paginatedScan, buildMetaFilter, isLocked, normalizePath, discoverMetas, buildOwnershipTree, findNode, actualStaleness, computeEffectiveStaleness, selectCandidate, filterInScope, computeStructureHash, readLatestArchive, hasSteerChanged, isArchitectTriggered, loadSynthConfig } from '@karmaniverous/jeeves-meta';
|
|
2
2
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
|
|
@@ -55,168 +55,175 @@ function fail(error) {
|
|
|
55
55
|
* @module rules
|
|
56
56
|
*/
|
|
57
57
|
const SOURCE = 'jeeves-meta';
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
schema: [
|
|
73
|
-
'base',
|
|
74
|
-
{
|
|
58
|
+
/**
|
|
59
|
+
* Build virtual rule definitions using configured domain tags.
|
|
60
|
+
*
|
|
61
|
+
* @param config - Synth config with metaProperty/metaArchiveProperty.
|
|
62
|
+
* @returns Array of inference rule specs.
|
|
63
|
+
*/
|
|
64
|
+
function buildSynthRules(config) {
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
name: 'synth-meta-live',
|
|
68
|
+
description: 'Live jeeves-meta .meta/meta.json files',
|
|
69
|
+
match: {
|
|
75
70
|
properties: {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
synth_emphasis: { type: 'number', set: '{{json._emphasis}}' },
|
|
81
|
-
synth_synthesis_count: {
|
|
82
|
-
type: 'integer',
|
|
83
|
-
set: '{{json._synthesisCount}}',
|
|
84
|
-
},
|
|
85
|
-
synth_structure_hash: {
|
|
86
|
-
type: 'string',
|
|
87
|
-
set: '{{json._structureHash}}',
|
|
88
|
-
},
|
|
89
|
-
synth_architect_tokens: {
|
|
90
|
-
type: 'integer',
|
|
91
|
-
set: '{{json._architectTokens}}',
|
|
92
|
-
},
|
|
93
|
-
synth_builder_tokens: {
|
|
94
|
-
type: 'integer',
|
|
95
|
-
set: '{{json._builderTokens}}',
|
|
96
|
-
},
|
|
97
|
-
synth_critic_tokens: {
|
|
98
|
-
type: 'integer',
|
|
99
|
-
set: '{{json._criticTokens}}',
|
|
100
|
-
},
|
|
101
|
-
synth_error_step: {
|
|
102
|
-
type: 'string',
|
|
103
|
-
set: '{{json._error.step}}',
|
|
104
|
-
},
|
|
105
|
-
generated_at_unix: {
|
|
106
|
-
type: 'integer',
|
|
107
|
-
set: '{{toUnix json._generatedAt}}',
|
|
108
|
-
description: 'Synthesis timestamp as Unix seconds for range queries',
|
|
109
|
-
},
|
|
110
|
-
has_error: {
|
|
111
|
-
type: 'boolean',
|
|
112
|
-
set: '{{#if json._error}}true{{else}}false{{/if}}',
|
|
71
|
+
file: {
|
|
72
|
+
properties: {
|
|
73
|
+
path: { type: 'string', glob: '**/.meta/meta.json' },
|
|
74
|
+
},
|
|
113
75
|
},
|
|
114
76
|
},
|
|
115
77
|
},
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
frontmatter: [
|
|
119
|
-
'synth_id',
|
|
120
|
-
'synth_steer',
|
|
121
|
-
'generated_at_unix',
|
|
122
|
-
'synth_depth',
|
|
123
|
-
'synth_emphasis',
|
|
124
|
-
'synth_architect_tokens',
|
|
125
|
-
'synth_builder_tokens',
|
|
126
|
-
'synth_critic_tokens',
|
|
127
|
-
],
|
|
128
|
-
body: [
|
|
78
|
+
schema: [
|
|
79
|
+
'base',
|
|
129
80
|
{
|
|
130
|
-
path: 'json._content',
|
|
131
|
-
heading: 1,
|
|
132
|
-
label: 'Synthesis',
|
|
133
|
-
},
|
|
134
|
-
],
|
|
135
|
-
},
|
|
136
|
-
renderAs: 'md',
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: 'synth-meta-archive',
|
|
140
|
-
description: 'Archived jeeves-meta .meta/archive snapshots',
|
|
141
|
-
match: {
|
|
142
|
-
properties: {
|
|
143
|
-
file: {
|
|
144
81
|
properties: {
|
|
145
|
-
|
|
82
|
+
domains: { set: config.metaProperty.domains },
|
|
83
|
+
synth_id: { type: 'string', set: '{{json._id}}' },
|
|
84
|
+
synth_steer: { type: 'string', set: '{{json._steer}}' },
|
|
85
|
+
synth_depth: { type: 'number', set: '{{json._depth}}' },
|
|
86
|
+
synth_emphasis: { type: 'number', set: '{{json._emphasis}}' },
|
|
87
|
+
synth_synthesis_count: {
|
|
88
|
+
type: 'integer',
|
|
89
|
+
set: '{{json._synthesisCount}}',
|
|
90
|
+
},
|
|
91
|
+
synth_structure_hash: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
set: '{{json._structureHash}}',
|
|
94
|
+
},
|
|
95
|
+
synth_architect_tokens: {
|
|
96
|
+
type: 'integer',
|
|
97
|
+
set: '{{json._architectTokens}}',
|
|
98
|
+
},
|
|
99
|
+
synth_builder_tokens: {
|
|
100
|
+
type: 'integer',
|
|
101
|
+
set: '{{json._builderTokens}}',
|
|
102
|
+
},
|
|
103
|
+
synth_critic_tokens: {
|
|
104
|
+
type: 'integer',
|
|
105
|
+
set: '{{json._criticTokens}}',
|
|
106
|
+
},
|
|
107
|
+
synth_error_step: {
|
|
108
|
+
type: 'string',
|
|
109
|
+
set: '{{json._error.step}}',
|
|
110
|
+
},
|
|
111
|
+
generated_at_unix: {
|
|
112
|
+
type: 'integer',
|
|
113
|
+
set: '{{toUnix json._generatedAt}}',
|
|
114
|
+
description: 'Synthesis timestamp as Unix seconds for range queries',
|
|
115
|
+
},
|
|
116
|
+
has_error: {
|
|
117
|
+
type: 'boolean',
|
|
118
|
+
set: '{{#if json._error}}true{{else}}false{{/if}}',
|
|
119
|
+
},
|
|
146
120
|
},
|
|
147
121
|
},
|
|
122
|
+
],
|
|
123
|
+
render: {
|
|
124
|
+
frontmatter: [
|
|
125
|
+
'synth_id',
|
|
126
|
+
'synth_steer',
|
|
127
|
+
'generated_at_unix',
|
|
128
|
+
'synth_depth',
|
|
129
|
+
'synth_emphasis',
|
|
130
|
+
'synth_architect_tokens',
|
|
131
|
+
'synth_builder_tokens',
|
|
132
|
+
'synth_critic_tokens',
|
|
133
|
+
],
|
|
134
|
+
body: [
|
|
135
|
+
{
|
|
136
|
+
path: 'json._content',
|
|
137
|
+
heading: 1,
|
|
138
|
+
label: 'Synthesis',
|
|
139
|
+
},
|
|
140
|
+
],
|
|
148
141
|
},
|
|
142
|
+
renderAs: 'md',
|
|
149
143
|
},
|
|
150
|
-
|
|
151
|
-
'
|
|
152
|
-
|
|
144
|
+
{
|
|
145
|
+
name: 'synth-meta-archive',
|
|
146
|
+
description: 'Archived jeeves-meta .meta/archive snapshots',
|
|
147
|
+
match: {
|
|
153
148
|
properties: {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
149
|
+
file: {
|
|
150
|
+
properties: {
|
|
151
|
+
path: { type: 'string', glob: '**/.meta/archive/*.json' },
|
|
152
|
+
},
|
|
153
|
+
},
|
|
158
154
|
},
|
|
159
155
|
},
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
frontmatter: ['synth_id', 'archived', 'archived_at'],
|
|
163
|
-
body: [
|
|
156
|
+
schema: [
|
|
157
|
+
'base',
|
|
164
158
|
{
|
|
165
|
-
path: 'json._content',
|
|
166
|
-
heading: 1,
|
|
167
|
-
label: 'Synthesis (archived)',
|
|
168
|
-
},
|
|
169
|
-
],
|
|
170
|
-
},
|
|
171
|
-
renderAs: 'md',
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
name: 'synth-config',
|
|
175
|
-
description: 'jeeves-meta configuration file',
|
|
176
|
-
match: {
|
|
177
|
-
properties: {
|
|
178
|
-
file: {
|
|
179
159
|
properties: {
|
|
180
|
-
|
|
160
|
+
domains: { set: config.metaArchiveProperty.domains },
|
|
161
|
+
synth_id: { type: 'string', set: '{{json._id}}' },
|
|
162
|
+
archived: { type: 'boolean', set: 'true' },
|
|
163
|
+
archived_at: { type: 'string', set: '{{json._archivedAt}}' },
|
|
181
164
|
},
|
|
182
165
|
},
|
|
166
|
+
],
|
|
167
|
+
render: {
|
|
168
|
+
frontmatter: ['synth_id', 'archived', 'archived_at'],
|
|
169
|
+
body: [
|
|
170
|
+
{
|
|
171
|
+
path: 'json._content',
|
|
172
|
+
heading: 1,
|
|
173
|
+
label: 'Synthesis (archived)',
|
|
174
|
+
},
|
|
175
|
+
],
|
|
183
176
|
},
|
|
177
|
+
renderAs: 'md',
|
|
184
178
|
},
|
|
185
|
-
|
|
186
|
-
'
|
|
187
|
-
|
|
179
|
+
{
|
|
180
|
+
name: 'synth-config',
|
|
181
|
+
description: 'jeeves-meta configuration file',
|
|
182
|
+
match: {
|
|
188
183
|
properties: {
|
|
189
|
-
|
|
184
|
+
file: {
|
|
185
|
+
properties: {
|
|
186
|
+
path: { type: 'string', glob: '**/jeeves-meta.config.json' },
|
|
187
|
+
},
|
|
188
|
+
},
|
|
190
189
|
},
|
|
191
190
|
},
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
frontmatter: [
|
|
195
|
-
'watchPaths',
|
|
196
|
-
'watcherUrl',
|
|
197
|
-
'gatewayUrl',
|
|
198
|
-
'architectEvery',
|
|
199
|
-
'depthWeight',
|
|
200
|
-
'maxArchive',
|
|
201
|
-
'maxLines',
|
|
202
|
-
'batchSize',
|
|
203
|
-
],
|
|
204
|
-
body: [
|
|
191
|
+
schema: [
|
|
192
|
+
'base',
|
|
205
193
|
{
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
},
|
|
210
|
-
{
|
|
211
|
-
path: 'json.defaultCritic',
|
|
212
|
-
heading: 2,
|
|
213
|
-
label: 'Default Critic Prompt',
|
|
194
|
+
properties: {
|
|
195
|
+
domains: { set: ['synth-config'] },
|
|
196
|
+
},
|
|
214
197
|
},
|
|
215
198
|
],
|
|
199
|
+
render: {
|
|
200
|
+
frontmatter: [
|
|
201
|
+
'watchPaths',
|
|
202
|
+
'watcherUrl',
|
|
203
|
+
'gatewayUrl',
|
|
204
|
+
'architectEvery',
|
|
205
|
+
'depthWeight',
|
|
206
|
+
'maxArchive',
|
|
207
|
+
'maxLines',
|
|
208
|
+
'batchSize',
|
|
209
|
+
],
|
|
210
|
+
body: [
|
|
211
|
+
{
|
|
212
|
+
path: 'json.defaultArchitect',
|
|
213
|
+
heading: 2,
|
|
214
|
+
label: 'Default Architect Prompt',
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
path: 'json.defaultCritic',
|
|
218
|
+
heading: 2,
|
|
219
|
+
label: 'Default Critic Prompt',
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
},
|
|
223
|
+
renderAs: 'md',
|
|
216
224
|
},
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
];
|
|
225
|
+
];
|
|
226
|
+
}
|
|
220
227
|
/**
|
|
221
228
|
* Register jeeves-meta virtual rules with the watcher.
|
|
222
229
|
*
|
|
@@ -225,9 +232,9 @@ const SYNTH_RULES = [
|
|
|
225
232
|
*
|
|
226
233
|
* @param watcherUrl - Base URL for the watcher service.
|
|
227
234
|
*/
|
|
228
|
-
async function registerSynthRules(watcherUrl) {
|
|
235
|
+
async function registerSynthRules(watcherUrl, config) {
|
|
229
236
|
const client = new HttpWatcherClient({ baseUrl: watcherUrl });
|
|
230
|
-
await client.registerRules(SOURCE,
|
|
237
|
+
await client.registerRules(SOURCE, buildSynthRules(config));
|
|
231
238
|
}
|
|
232
239
|
|
|
233
240
|
/**
|
|
@@ -248,8 +255,6 @@ function registerSynthTools(api) {
|
|
|
248
255
|
};
|
|
249
256
|
/** Derive watcherUrl from loaded config. */
|
|
250
257
|
const getWatcherUrl = () => getConfig().watcherUrl;
|
|
251
|
-
/** Derive watchPaths from loaded config. */
|
|
252
|
-
const getWatchPaths = () => getConfig().watchPaths;
|
|
253
258
|
// ─── synth_list ──────────────────────────────────────────────
|
|
254
259
|
api.registerTool({
|
|
255
260
|
name: 'synth_list',
|
|
@@ -282,12 +287,11 @@ function registerSynthTools(api) {
|
|
|
282
287
|
try {
|
|
283
288
|
const pathPrefix = params.pathPrefix;
|
|
284
289
|
const watcher = new HttpWatcherClient({ baseUrl: getWatcherUrl() });
|
|
285
|
-
|
|
290
|
+
const config = getConfig();
|
|
291
|
+
// Query watcher for synth entity points using configured filter
|
|
286
292
|
const scanFiles = await paginatedScan(watcher, {
|
|
287
293
|
...(pathPrefix ? { pathPrefix } : {}),
|
|
288
|
-
filter:
|
|
289
|
-
must: [{ key: 'domains', match: { value: 'synth-meta' } }],
|
|
290
|
-
},
|
|
294
|
+
filter: buildMetaFilter(config),
|
|
291
295
|
fields: [
|
|
292
296
|
'file_path',
|
|
293
297
|
'synth_depth',
|
|
@@ -300,6 +304,15 @@ function registerSynthTools(api) {
|
|
|
300
304
|
'synth_error_step',
|
|
301
305
|
],
|
|
302
306
|
});
|
|
307
|
+
// Deduplicate by file_path (watcher chunks files into multiple points)
|
|
308
|
+
const seenPaths = new Set();
|
|
309
|
+
const dedupedFiles = scanFiles.filter((sf) => {
|
|
310
|
+
const fp = sf.file_path;
|
|
311
|
+
if (seenPaths.has(fp))
|
|
312
|
+
return false;
|
|
313
|
+
seenPaths.add(fp);
|
|
314
|
+
return true;
|
|
315
|
+
});
|
|
303
316
|
const entities = [];
|
|
304
317
|
let staleCount = 0;
|
|
305
318
|
let errorCount = 0;
|
|
@@ -312,8 +325,7 @@ function registerSynthTools(api) {
|
|
|
312
325
|
let lastSynthAt = null;
|
|
313
326
|
let stalestPath = null;
|
|
314
327
|
let stalestEffective = -1;
|
|
315
|
-
const
|
|
316
|
-
for (const sf of scanFiles) {
|
|
328
|
+
for (const sf of dedupedFiles) {
|
|
317
329
|
const filePath = sf.file_path;
|
|
318
330
|
const depth = typeof sf['synth_depth'] === 'number' ? sf['synth_depth'] : 0;
|
|
319
331
|
const emphasis = typeof sf['synth_emphasis'] === 'number' ? sf['synth_emphasis'] : 1;
|
|
@@ -475,13 +487,16 @@ function registerSynthTools(api) {
|
|
|
475
487
|
'_feedback',
|
|
476
488
|
]);
|
|
477
489
|
const fields = params.fields;
|
|
478
|
-
const
|
|
490
|
+
const watcher = new HttpWatcherClient({ baseUrl: getWatcherUrl() });
|
|
491
|
+
const metaPaths = await discoverMetas(getConfig(), watcher);
|
|
479
492
|
const tree = buildOwnershipTree(metaPaths);
|
|
480
493
|
const targetNode = findNode(tree, targetPath);
|
|
481
494
|
if (!targetNode) {
|
|
482
495
|
return fail('Meta path not found: ' + targetPath);
|
|
483
496
|
}
|
|
484
|
-
const
|
|
497
|
+
const { readFileSync } = await import('node:fs');
|
|
498
|
+
const { join } = await import('node:path');
|
|
499
|
+
const meta = JSON.parse(readFileSync(join(targetNode.metaPath, 'meta.json'), 'utf8'));
|
|
485
500
|
// Apply field projection
|
|
486
501
|
const projectMeta = (m) => {
|
|
487
502
|
if (fields) {
|
|
@@ -542,7 +557,8 @@ function registerSynthTools(api) {
|
|
|
542
557
|
execute: async (_id, params) => {
|
|
543
558
|
try {
|
|
544
559
|
const targetPath = params.path;
|
|
545
|
-
const
|
|
560
|
+
const watcher = new HttpWatcherClient({ baseUrl: getWatcherUrl() });
|
|
561
|
+
const metaPaths = await discoverMetas(getConfig(), watcher);
|
|
546
562
|
const tree = buildOwnershipTree(metaPaths);
|
|
547
563
|
let targetNode;
|
|
548
564
|
if (targetPath) {
|
|
@@ -554,12 +570,19 @@ function registerSynthTools(api) {
|
|
|
554
570
|
}
|
|
555
571
|
else {
|
|
556
572
|
// Select stalest
|
|
573
|
+
const { readFileSync: readFs } = await import('node:fs');
|
|
574
|
+
const { join: joinPath } = await import('node:path');
|
|
557
575
|
const candidates = [];
|
|
558
576
|
for (const node of tree.nodes.values()) {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
577
|
+
try {
|
|
578
|
+
const meta = JSON.parse(readFs(joinPath(node.metaPath, 'meta.json'), 'utf8'));
|
|
579
|
+
const staleness = actualStaleness(meta);
|
|
580
|
+
if (staleness > 0) {
|
|
581
|
+
candidates.push({ node, meta, actualStaleness: staleness });
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
catch {
|
|
585
|
+
// skip unreadable
|
|
563
586
|
}
|
|
564
587
|
}
|
|
565
588
|
const weighted = computeEffectiveStaleness(candidates, getConfig().depthWeight);
|
|
@@ -571,8 +594,9 @@ function registerSynthTools(api) {
|
|
|
571
594
|
}
|
|
572
595
|
targetNode = winner.node;
|
|
573
596
|
}
|
|
574
|
-
const
|
|
575
|
-
const
|
|
597
|
+
const { readFileSync: readMeta } = await import('node:fs');
|
|
598
|
+
const { join: joinMeta } = await import('node:path');
|
|
599
|
+
const meta = JSON.parse(readMeta(joinMeta(targetNode.metaPath, 'meta.json'), 'utf8'));
|
|
576
600
|
// Scope files (paginated for completeness)
|
|
577
601
|
const allScanFiles = await paginatedScan(watcher, {
|
|
578
602
|
pathPrefix: targetNode.ownerPath,
|
|
@@ -661,15 +685,8 @@ function registerSynthTools(api) {
|
|
|
661
685
|
apiKey: config.gatewayApiKey,
|
|
662
686
|
});
|
|
663
687
|
const watcher = new HttpWatcherClient({ baseUrl: getWatcherUrl() });
|
|
664
|
-
// If path specified, temporarily override watchPaths to target it
|
|
665
688
|
const targetPath = params.path;
|
|
666
|
-
const
|
|
667
|
-
? {
|
|
668
|
-
...config,
|
|
669
|
-
watchPaths: [targetPath.replace(/[/\\]\.meta[/\\]?$/, '')],
|
|
670
|
-
}
|
|
671
|
-
: config;
|
|
672
|
-
const results = await orchestrate(effectiveConfig, executor, watcher);
|
|
689
|
+
const results = await orchestrate(config, executor, watcher, targetPath);
|
|
673
690
|
const synthesized = results.filter((r) => r.synthesized);
|
|
674
691
|
if (synthesized.length === 0) {
|
|
675
692
|
return ok({
|
|
@@ -715,19 +732,12 @@ function registerSynthTools(api) {
|
|
|
715
732
|
* @param watcherUrl - Watcher API base URL.
|
|
716
733
|
* @returns Markdown string for the Meta section.
|
|
717
734
|
*/
|
|
718
|
-
async function generateMetaMenu(watcherUrl) {
|
|
735
|
+
async function generateMetaMenu(watcherUrl, metaFilter) {
|
|
719
736
|
let entities = [];
|
|
720
737
|
try {
|
|
721
738
|
const watcher = new HttpWatcherClient({ baseUrl: watcherUrl });
|
|
722
739
|
entities = await paginatedScan(watcher, {
|
|
723
|
-
filter:
|
|
724
|
-
must: [
|
|
725
|
-
{
|
|
726
|
-
key: 'domains',
|
|
727
|
-
match: { value: 'synth-meta' },
|
|
728
|
-
},
|
|
729
|
-
],
|
|
730
|
-
},
|
|
740
|
+
filter: metaFilter,
|
|
731
741
|
fields: [
|
|
732
742
|
'synth_depth',
|
|
733
743
|
'synth_emphasis',
|
|
@@ -751,6 +761,15 @@ async function generateMetaMenu(watcherUrl) {
|
|
|
751
761
|
'> for setup instructions. Do not attempt synthesis until watcher is available.',
|
|
752
762
|
].join('\n');
|
|
753
763
|
}
|
|
764
|
+
// Deduplicate by file_path (watcher chunks files into multiple points)
|
|
765
|
+
const seenPaths = new Set();
|
|
766
|
+
entities = entities.filter((e) => {
|
|
767
|
+
const fp = e.file_path;
|
|
768
|
+
if (seenPaths.has(fp))
|
|
769
|
+
return false;
|
|
770
|
+
seenPaths.add(fp);
|
|
771
|
+
return true;
|
|
772
|
+
});
|
|
754
773
|
if (entities.length === 0) {
|
|
755
774
|
return [
|
|
756
775
|
'> **ACTION REQUIRED: No synthesis entities found.**',
|
|
@@ -926,8 +945,8 @@ function upsertMetaSection(existing, metaMenu) {
|
|
|
926
945
|
* @param watcherUrl - Watcher API base URL.
|
|
927
946
|
* @returns True if the file was updated.
|
|
928
947
|
*/
|
|
929
|
-
async function refreshToolsMd(api,
|
|
930
|
-
const menu = await generateMetaMenu(watcherUrl);
|
|
948
|
+
async function refreshToolsMd(api, config) {
|
|
949
|
+
const menu = await generateMetaMenu(config.watcherUrl, buildMetaFilter(config));
|
|
931
950
|
if (menu === lastWrittenMenu) {
|
|
932
951
|
return false;
|
|
933
952
|
}
|
|
@@ -955,10 +974,10 @@ async function refreshToolsMd(api, watcherUrl) {
|
|
|
955
974
|
* @param api - Plugin API.
|
|
956
975
|
* @param watcherUrl - Watcher API base URL.
|
|
957
976
|
*/
|
|
958
|
-
function startToolsWriter(api,
|
|
977
|
+
function startToolsWriter(api, config) {
|
|
959
978
|
// Deferred initial write
|
|
960
979
|
setTimeout(() => {
|
|
961
|
-
refreshToolsMd(api,
|
|
980
|
+
refreshToolsMd(api, config).catch((err) => {
|
|
962
981
|
console.error('[jeeves-meta] Failed to write TOOLS.md:', err);
|
|
963
982
|
});
|
|
964
983
|
}, INITIAL_DELAY_MS);
|
|
@@ -967,7 +986,7 @@ function startToolsWriter(api, watcherUrl) {
|
|
|
967
986
|
clearInterval(intervalHandle);
|
|
968
987
|
}
|
|
969
988
|
intervalHandle = setInterval(() => {
|
|
970
|
-
refreshToolsMd(api,
|
|
989
|
+
refreshToolsMd(api, config).catch((err) => {
|
|
971
990
|
console.error('[jeeves-meta] Failed to refresh TOOLS.md:', err);
|
|
972
991
|
});
|
|
973
992
|
}, REFRESH_INTERVAL_MS);
|
|
@@ -990,12 +1009,12 @@ function register(api) {
|
|
|
990
1009
|
// Load config for rule registration and tools writer
|
|
991
1010
|
const config = loadSynthConfig(getConfigPath(api));
|
|
992
1011
|
// Register virtual rules with watcher (fire-and-forget at startup)
|
|
993
|
-
registerSynthRules(config.watcherUrl).catch((err) => {
|
|
1012
|
+
registerSynthRules(config.watcherUrl, config).catch((err) => {
|
|
994
1013
|
const message = err instanceof Error ? err.message : String(err);
|
|
995
1014
|
console.error('[jeeves-meta] Failed to register virtual rules:', message);
|
|
996
1015
|
});
|
|
997
1016
|
// Start periodic TOOLS.md writer
|
|
998
|
-
startToolsWriter(api, config
|
|
1017
|
+
startToolsWriter(api, config);
|
|
999
1018
|
}
|
|
1000
1019
|
|
|
1001
1020
|
export { register as default };
|
|
@@ -136,11 +136,38 @@ Before the synthesis engine can operate:
|
|
|
136
136
|
|
|
137
137
|
### Installation
|
|
138
138
|
|
|
139
|
+
1. Install the core library globally (provides the CLI and the dependency for the plugin):
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
npm install -g @karmaniverous/jeeves-meta
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
2. Install the OpenClaw plugin:
|
|
146
|
+
|
|
139
147
|
```bash
|
|
140
148
|
npx @karmaniverous/jeeves-meta-openclaw install
|
|
141
149
|
```
|
|
142
150
|
|
|
143
|
-
|
|
151
|
+
3. Configure the plugin in `openclaw.json`:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"plugins": {
|
|
156
|
+
"entries": {
|
|
157
|
+
"jeeves-meta-openclaw": {
|
|
158
|
+
"enabled": true,
|
|
159
|
+
"config": {
|
|
160
|
+
"configPath": "/path/to/jeeves-meta.config.json"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Alternatively, set the `JEEVES_META_CONFIG` environment variable instead of using plugin config.
|
|
169
|
+
|
|
170
|
+
4. Restart the OpenClaw gateway to load the plugin.
|
|
144
171
|
|
|
145
172
|
### First Synthesis
|
|
146
173
|
|
|
@@ -17,4 +17,4 @@
|
|
|
17
17
|
* @param watcherUrl - Watcher API base URL.
|
|
18
18
|
* @returns Markdown string for the Meta section.
|
|
19
19
|
*/
|
|
20
|
-
export declare function generateMetaMenu(watcherUrl: string): Promise<string>;
|
|
20
|
+
export declare function generateMetaMenu(watcherUrl: string, metaFilter: Record<string, unknown>): Promise<string>;
|
package/dist/src/rules.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @module rules
|
|
10
10
|
*/
|
|
11
|
+
import type { SynthConfig } from '@karmaniverous/jeeves-meta';
|
|
11
12
|
/**
|
|
12
13
|
* Register jeeves-meta virtual rules with the watcher.
|
|
13
14
|
*
|
|
@@ -16,4 +17,4 @@
|
|
|
16
17
|
*
|
|
17
18
|
* @param watcherUrl - Base URL for the watcher service.
|
|
18
19
|
*/
|
|
19
|
-
export declare function registerSynthRules(watcherUrl: string): Promise<void>;
|
|
20
|
+
export declare function registerSynthRules(watcherUrl: string, config: SynthConfig): Promise<void>;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module toolsWriter
|
|
8
8
|
*/
|
|
9
|
+
import { type SynthConfig } from '@karmaniverous/jeeves-meta';
|
|
9
10
|
import type { PluginApi } from './helpers.js';
|
|
10
11
|
/**
|
|
11
12
|
* Upsert the Meta section in TOOLS.md content.
|
|
@@ -23,4 +24,4 @@ export declare function upsertMetaSection(existing: string, metaMenu: string): s
|
|
|
23
24
|
* @param api - Plugin API.
|
|
24
25
|
* @param watcherUrl - Watcher API base URL.
|
|
25
26
|
*/
|
|
26
|
-
export declare function startToolsWriter(api: PluginApi,
|
|
27
|
+
export declare function startToolsWriter(api: PluginApi, config: SynthConfig): void;
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED