@karmaniverous/jeeves-meta-openclaw 0.12.4 → 0.12.6

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.
@@ -24,6 +24,20 @@ When editing files outside the workspace, use the bridge pattern: copy in → ed
24
24
 
25
25
  **Cross-channel sends:** Use the `message` tool with an explicit `target` to send to a different channel or DM.
26
26
 
27
+ ### Slack File Downloads
28
+
29
+ To download a Slack-hosted file, first try the `message` tool's `download-file` action. If that fails, fall back to a direct HTTP fetch using the bot token:
30
+
31
+ ```js
32
+ fetch(url_private_download, {
33
+ headers: { Authorization: 'Bearer ' + botToken },
34
+ });
35
+ ```
36
+
37
+ The bot token is at `channels.slack.accounts.default.botToken` in `openclaw.json`.
38
+
39
+ Never tell the user a file can't be downloaded until both methods have been tried.
40
+
27
41
  ### Plugin Lifecycle
28
42
 
29
43
  ```bash
package/dist/cli.js CHANGED
@@ -4749,6 +4749,9 @@ function requireRange () {
4749
4749
  }
4750
4750
 
4751
4751
  parseRange (range) {
4752
+ // strip build metadata so it can't bleed into the version
4753
+ range = range.replace(BUILDSTRIPRE, '');
4754
+
4752
4755
  // memoize range parsing for performance.
4753
4756
  // this is a very hot path, and fully deterministic.
4754
4757
  const memoOpts =
@@ -4874,6 +4877,7 @@ function requireRange () {
4874
4877
  const SemVer = requireSemver$1();
4875
4878
  const {
4876
4879
  safeRe: re,
4880
+ src,
4877
4881
  t,
4878
4882
  comparatorTrimReplace,
4879
4883
  tildeTrimReplace,
@@ -4881,6 +4885,9 @@ function requireRange () {
4881
4885
  } = requireRe();
4882
4886
  const { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = requireConstants();
4883
4887
 
4888
+ // unbounded global build-metadata stripper used by parseRange
4889
+ const BUILDSTRIPRE = new RegExp(src[t.BUILD], 'g');
4890
+
4884
4891
  const isNullSet = c => c.value === '<0.0.0-0';
4885
4892
  const isAny = c => c.value === '';
4886
4893
 
@@ -5932,7 +5939,7 @@ function requireSubset () {
5932
5939
  if (higher === c && higher !== gt) {
5933
5940
  return false
5934
5941
  }
5935
- } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) {
5942
+ } else if (gt.operator === '>=' && !c.test(gt.semver)) {
5936
5943
  return false
5937
5944
  }
5938
5945
  }
@@ -5950,7 +5957,7 @@ function requireSubset () {
5950
5957
  if (lower === c && lower !== lt) {
5951
5958
  return false
5952
5959
  }
5953
- } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) {
5960
+ } else if (lt.operator === '<=' && !c.test(lt.semver)) {
5954
5961
  return false
5955
5962
  }
5956
5963
  }
@@ -24346,14 +24353,14 @@ const SECTION_ORDER = [
24346
24353
  * Core library version, inlined at build time.
24347
24354
  *
24348
24355
  * @remarks
24349
- * The `0.5.9` placeholder is replaced by
24356
+ * The `0.5.10` placeholder is replaced by
24350
24357
  * `@rollup/plugin-replace` during the build with the actual version
24351
24358
  * from `package.json`. This ensures the correct version survives
24352
24359
  * when consumers bundle core into their own dist (where runtime
24353
24360
  * `import.meta.url`-based resolution would find the wrong package.json).
24354
24361
  */
24355
24362
  /** The core library version from package.json (inlined at build time). */
24356
- const CORE_VERSION = '0.5.9';
24363
+ const CORE_VERSION = '0.5.10';
24357
24364
 
24358
24365
  /**
24359
24366
  * Workspace and config root initialization.
@@ -24366,12 +24373,26 @@ const CORE_VERSION = '0.5.9';
24366
24373
  * - `{configRoot}/jeeves-{name}/` for each component
24367
24374
  */
24368
24375
  let state;
24376
+ const WINDOWS_DRIVE_RE = /^[a-zA-Z]:/;
24377
+ /**
24378
+ * Throw if a path looks like a Windows drive letter on a non-Windows platform.
24379
+ *
24380
+ * @param label - Human-readable name for the path (used in error messages).
24381
+ * @param value - The raw path string to validate.
24382
+ */
24383
+ function rejectWindowsDrivePath(label, value) {
24384
+ if (process.platform !== 'win32' && WINDOWS_DRIVE_RE.test(value)) {
24385
+ throw new Error(`jeeves-core: ${label} "${value}" looks like a Windows drive-letter path and will not resolve correctly on this platform.`);
24386
+ }
24387
+ }
24369
24388
  /**
24370
24389
  * Initialize the core library with workspace and config root paths.
24371
24390
  *
24372
24391
  * @param options - Workspace and config root paths.
24373
24392
  */
24374
24393
  function init(options) {
24394
+ rejectWindowsDrivePath('configRoot', options.configRoot);
24395
+ rejectWindowsDrivePath('workspacePath', options.workspacePath);
24375
24396
  state = {
24376
24397
  workspacePath: options.workspacePath,
24377
24398
  configRoot: options.configRoot,
@@ -26177,6 +26198,20 @@ When editing files outside the workspace, use the bridge pattern: copy in → ed
26177
26198
 
26178
26199
  **Cross-channel sends:** Use the \`message\` tool with an explicit \`target\` to send to a different channel or DM.
26179
26200
 
26201
+ ### Slack File Downloads
26202
+
26203
+ To download a Slack-hosted file, first try the \`message\` tool's \`download-file\` action. If that fails, fall back to a direct HTTP fetch using the bot token:
26204
+
26205
+ \`\`\`js
26206
+ fetch(url_private_download, {
26207
+ headers: { Authorization: 'Bearer ' + botToken },
26208
+ });
26209
+ \`\`\`
26210
+
26211
+ The bot token is at \`channels.slack.accounts.default.botToken\` in \`openclaw.json\`.
26212
+
26213
+ Never tell the user a file can't be downloaded until both methods have been tried.
26214
+
26180
26215
  ### Plugin Lifecycle
26181
26216
 
26182
26217
  \`\`\`bash
package/dist/index.js CHANGED
@@ -4748,6 +4748,9 @@ function requireRange () {
4748
4748
  }
4749
4749
 
4750
4750
  parseRange (range) {
4751
+ // strip build metadata so it can't bleed into the version
4752
+ range = range.replace(BUILDSTRIPRE, '');
4753
+
4751
4754
  // memoize range parsing for performance.
4752
4755
  // this is a very hot path, and fully deterministic.
4753
4756
  const memoOpts =
@@ -4873,6 +4876,7 @@ function requireRange () {
4873
4876
  const SemVer = requireSemver$1();
4874
4877
  const {
4875
4878
  safeRe: re,
4879
+ src,
4876
4880
  t,
4877
4881
  comparatorTrimReplace,
4878
4882
  tildeTrimReplace,
@@ -4880,6 +4884,9 @@ function requireRange () {
4880
4884
  } = requireRe();
4881
4885
  const { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = requireConstants();
4882
4886
 
4887
+ // unbounded global build-metadata stripper used by parseRange
4888
+ const BUILDSTRIPRE = new RegExp(src[t.BUILD], 'g');
4889
+
4883
4890
  const isNullSet = c => c.value === '<0.0.0-0';
4884
4891
  const isAny = c => c.value === '';
4885
4892
 
@@ -5931,7 +5938,7 @@ function requireSubset () {
5931
5938
  if (higher === c && higher !== gt) {
5932
5939
  return false
5933
5940
  }
5934
- } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) {
5941
+ } else if (gt.operator === '>=' && !c.test(gt.semver)) {
5935
5942
  return false
5936
5943
  }
5937
5944
  }
@@ -5949,7 +5956,7 @@ function requireSubset () {
5949
5956
  if (lower === c && lower !== lt) {
5950
5957
  return false
5951
5958
  }
5952
- } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) {
5959
+ } else if (lt.operator === '<=' && !c.test(lt.semver)) {
5953
5960
  return false
5954
5961
  }
5955
5962
  }
@@ -24465,14 +24472,14 @@ const PLATFORM_COMPONENTS = [
24465
24472
  * Core library version, inlined at build time.
24466
24473
  *
24467
24474
  * @remarks
24468
- * The `0.5.9` placeholder is replaced by
24475
+ * The `0.5.10` placeholder is replaced by
24469
24476
  * `@rollup/plugin-replace` during the build with the actual version
24470
24477
  * from `package.json`. This ensures the correct version survives
24471
24478
  * when consumers bundle core into their own dist (where runtime
24472
24479
  * `import.meta.url`-based resolution would find the wrong package.json).
24473
24480
  */
24474
24481
  /** The core library version from package.json (inlined at build time). */
24475
- const CORE_VERSION = '0.5.9';
24482
+ const CORE_VERSION = '0.5.10';
24476
24483
 
24477
24484
  /**
24478
24485
  * Workspace and config root initialization.
@@ -24485,12 +24492,26 @@ const CORE_VERSION = '0.5.9';
24485
24492
  * - `{configRoot}/jeeves-{name}/` for each component
24486
24493
  */
24487
24494
  let state;
24495
+ const WINDOWS_DRIVE_RE = /^[a-zA-Z]:/;
24496
+ /**
24497
+ * Throw if a path looks like a Windows drive letter on a non-Windows platform.
24498
+ *
24499
+ * @param label - Human-readable name for the path (used in error messages).
24500
+ * @param value - The raw path string to validate.
24501
+ */
24502
+ function rejectWindowsDrivePath(label, value) {
24503
+ if (process.platform !== 'win32' && WINDOWS_DRIVE_RE.test(value)) {
24504
+ throw new Error(`jeeves-core: ${label} "${value}" looks like a Windows drive-letter path and will not resolve correctly on this platform.`);
24505
+ }
24506
+ }
24488
24507
  /**
24489
24508
  * Initialize the core library with workspace and config root paths.
24490
24509
  *
24491
24510
  * @param options - Workspace and config root paths.
24492
24511
  */
24493
24512
  function init(options) {
24513
+ rejectWindowsDrivePath('configRoot', options.configRoot);
24514
+ rejectWindowsDrivePath('workspacePath', options.workspacePath);
24494
24515
  state = {
24495
24516
  workspacePath: options.workspacePath,
24496
24517
  configRoot: options.configRoot,
@@ -26599,6 +26620,20 @@ When editing files outside the workspace, use the bridge pattern: copy in → ed
26599
26620
 
26600
26621
  **Cross-channel sends:** Use the \`message\` tool with an explicit \`target\` to send to a different channel or DM.
26601
26622
 
26623
+ ### Slack File Downloads
26624
+
26625
+ To download a Slack-hosted file, first try the \`message\` tool's \`download-file\` action. If that fails, fall back to a direct HTTP fetch using the bot token:
26626
+
26627
+ \`\`\`js
26628
+ fetch(url_private_download, {
26629
+ headers: { Authorization: 'Bearer ' + botToken },
26630
+ });
26631
+ \`\`\`
26632
+
26633
+ The bot token is at \`channels.slack.accounts.default.botToken\` in \`openclaw.json\`.
26634
+
26635
+ Never tell the user a file can't be downloaded until both methods have been tried.
26636
+
26602
26637
  ### Plugin Lifecycle
26603
26638
 
26604
26639
  \`\`\`bash
@@ -27757,6 +27792,113 @@ const META_COMPONENT = {
27757
27792
  pluginPackage: '@karmaniverous/jeeves-meta-openclaw',
27758
27793
  defaultPort: 1938};
27759
27794
 
27795
+ /**
27796
+ * Shared endpoint catalog — single source of truth for the jeeves-meta API.
27797
+ *
27798
+ * Both the CLI service and the OpenClaw plugin derive their registrations
27799
+ * from this declarative catalog, eliminating drift between the two.
27800
+ *
27801
+ */
27802
+ /**
27803
+ * Canonical endpoint catalog for the jeeves-meta API.
27804
+ *
27805
+ * Every entry describes a single HTTP endpoint exposed by the service.
27806
+ * Route handlers, plugin tools, and HTTP clients should reference these
27807
+ * descriptors rather than hard-coding paths and descriptions.
27808
+ */
27809
+ const META_ENDPOINTS = [
27810
+ {
27811
+ name: 'status',
27812
+ method: 'GET',
27813
+ path: '/status',
27814
+ description: 'Service health and status overview.',
27815
+ },
27816
+ {
27817
+ name: 'listMetas',
27818
+ method: 'GET',
27819
+ path: '/metas',
27820
+ description: 'List metas with summary stats and per-meta projection. Response includes _phaseState and owedPhase per meta.',
27821
+ },
27822
+ {
27823
+ name: 'metaDetail',
27824
+ method: 'GET',
27825
+ path: '/metas/:path',
27826
+ description: 'Full detail for a single meta, with optional archive history. Response includes _phaseState and owedPhase.',
27827
+ },
27828
+ {
27829
+ name: 'updateMeta',
27830
+ method: 'PATCH',
27831
+ path: '/metas/:path',
27832
+ description: 'Update user-settable reserved properties on a meta entity.',
27833
+ },
27834
+ {
27835
+ name: 'synthesize',
27836
+ method: 'POST',
27837
+ path: '/synthesize',
27838
+ description: 'Trigger synthesis. Path-targeted creates an override queue entry; returns owedPhase. Fully-fresh metas return status:skipped.',
27839
+ },
27840
+ {
27841
+ name: 'abort',
27842
+ method: 'POST',
27843
+ path: '/synthesize/abort',
27844
+ description: 'Abort the currently running synthesis.',
27845
+ },
27846
+ {
27847
+ name: 'preview',
27848
+ method: 'GET',
27849
+ path: '/preview',
27850
+ description: 'Dry-run preview of next synthesis. Returns owedPhase, priorityBand, phaseState, inputStatus, and architectInvalidators.',
27851
+ },
27852
+ {
27853
+ name: 'seed',
27854
+ method: 'POST',
27855
+ path: '/seed',
27856
+ description: 'Create a .meta/ directory and initial meta.json for a new entity path.',
27857
+ },
27858
+ {
27859
+ name: 'unlock',
27860
+ method: 'POST',
27861
+ path: '/unlock',
27862
+ description: 'Remove a stale .lock from a meta entity that is stuck.',
27863
+ },
27864
+ {
27865
+ name: 'config',
27866
+ method: 'GET',
27867
+ path: '/config',
27868
+ description: 'Query service configuration with optional JSONPath.',
27869
+ },
27870
+ {
27871
+ name: 'configApply',
27872
+ method: 'POST',
27873
+ path: '/config/apply',
27874
+ description: 'Apply a configuration patch.',
27875
+ },
27876
+ {
27877
+ name: 'queue',
27878
+ method: 'GET',
27879
+ path: '/queue',
27880
+ description: 'List queued synthesis operations (3-layer model: current, overrides, automatic).',
27881
+ },
27882
+ {
27883
+ name: 'queueClear',
27884
+ method: 'POST',
27885
+ path: '/queue/clear',
27886
+ description: 'Clear override entries from the queue.',
27887
+ },
27888
+ ];
27889
+ /**
27890
+ * Look up an endpoint descriptor by name.
27891
+ *
27892
+ * @param name - The endpoint identifier.
27893
+ * @returns The matching {@link EndpointDescriptor}.
27894
+ */
27895
+ function getEndpoint(name) {
27896
+ const ep = META_ENDPOINTS.find((e) => e.name === name);
27897
+ if (!ep)
27898
+ throw new Error(`Unknown endpoint: ${name}`);
27899
+ return ep;
27900
+ }
27901
+
27760
27902
  /**
27761
27903
  * Structured error schema from a synthesis step failure.
27762
27904
  *
@@ -28032,9 +28174,22 @@ class MetaServiceClient {
28032
28174
  async post(path, body) {
28033
28175
  return postJson(this.baseUrl + path, body);
28034
28176
  }
28177
+ /**
28178
+ * Interpolate a parameterized endpoint path.
28179
+ * Replaces `:param` placeholders with URI-encoded values.
28180
+ */
28181
+ endpointPath(name, params) {
28182
+ let p = getEndpoint(name).path;
28183
+ if (params) {
28184
+ for (const [key, value] of Object.entries(params)) {
28185
+ p = p.replace(`:${key}`, encodeURIComponent(value));
28186
+ }
28187
+ }
28188
+ return p;
28189
+ }
28035
28190
  /** GET /status — service health + queue state. */
28036
28191
  async status() {
28037
- return this.get('/status');
28192
+ return this.get(this.endpointPath('status'));
28038
28193
  }
28039
28194
  /** GET /metas — list all meta entities with summary. */
28040
28195
  async listMetas(params) {
@@ -28054,12 +28209,11 @@ class MetaServiceClient {
28054
28209
  if (params?.fields?.length)
28055
28210
  qs.set('fields', params.fields.join(','));
28056
28211
  const query = qs.toString();
28057
- return this.get('/metas' + (query ? '?' + query : ''));
28212
+ return this.get(this.endpointPath('listMetas') + (query ? '?' + query : ''));
28058
28213
  }
28059
28214
  /** PATCH /metas/:path — update user-settable reserved properties. */
28060
28215
  async update(metaPath, updates) {
28061
- const encoded = encodeURIComponent(metaPath);
28062
- return fetchJson(`${this.baseUrl}/metas/${encoded}`, {
28216
+ return fetchJson(`${this.baseUrl}${this.endpointPath('updateMeta', { path: metaPath })}`, {
28063
28217
  method: 'PATCH',
28064
28218
  headers: { 'Content-Type': 'application/json' },
28065
28219
  body: JSON.stringify(updates),
@@ -28067,23 +28221,23 @@ class MetaServiceClient {
28067
28221
  }
28068
28222
  /** GET /metas/:path — detail for a single meta. */
28069
28223
  async detail(metaPath, options) {
28070
- const encoded = encodeURIComponent(metaPath);
28071
28224
  const qs = new URLSearchParams();
28072
28225
  if (options?.includeArchive !== undefined)
28073
28226
  qs.set('includeArchive', String(options.includeArchive));
28074
28227
  if (options?.fields?.length)
28075
28228
  qs.set('fields', options.fields.join(','));
28076
28229
  const query = qs.toString();
28077
- return this.get(`/metas/${encoded}` + (query ? '?' + query : ''));
28230
+ return this.get(this.endpointPath('metaDetail', { path: metaPath }) +
28231
+ (query ? '?' + query : ''));
28078
28232
  }
28079
28233
  /** GET /preview — dry-run next synthesis candidate. */
28080
28234
  async preview(path) {
28081
28235
  const qs = path ? '?path=' + encodeURIComponent(path) : '';
28082
- return this.get('/preview' + qs);
28236
+ return this.get(this.endpointPath('preview') + qs);
28083
28237
  }
28084
28238
  /** POST /synthesize — enqueue synthesis. */
28085
28239
  async synthesize(path) {
28086
- return this.post('/synthesize', path ? { path } : {});
28240
+ return this.post(this.endpointPath('synthesize'), path ? { path } : {});
28087
28241
  }
28088
28242
  /** POST /seed — create .meta/ for a path. */
28089
28243
  async seed(path, crossRefs, steer) {
@@ -28092,28 +28246,28 @@ class MetaServiceClient {
28092
28246
  body.crossRefs = crossRefs;
28093
28247
  if (steer !== undefined)
28094
28248
  body.steer = steer;
28095
- return this.post('/seed', body);
28249
+ return this.post(this.endpointPath('seed'), body);
28096
28250
  }
28097
28251
  /** POST /unlock — remove .lock from a meta entity. */
28098
28252
  async unlock(path) {
28099
- return this.post('/unlock', { path });
28253
+ return this.post(this.endpointPath('unlock'), { path });
28100
28254
  }
28101
28255
  /** GET /config — query service config with optional JSONPath. */
28102
28256
  async config(path) {
28103
28257
  const qs = path ? '?path=' + encodeURIComponent(path) : '';
28104
- return this.get('/config' + qs);
28258
+ return this.get(this.endpointPath('config') + qs);
28105
28259
  }
28106
28260
  /** GET /queue — current queue state. */
28107
28261
  async queue() {
28108
- return this.get('/queue');
28262
+ return this.get(this.endpointPath('queue'));
28109
28263
  }
28110
28264
  /** POST /queue/clear — remove all pending queue items. */
28111
28265
  async clearQueue() {
28112
- return this.post('/queue/clear', {});
28266
+ return this.post(this.endpointPath('queueClear'), {});
28113
28267
  }
28114
28268
  /** POST /synthesize/abort — abort current synthesis. */
28115
28269
  async abort() {
28116
- return this.post('/synthesize/abort', {});
28270
+ return this.post(this.endpointPath('abort'), {});
28117
28271
  }
28118
28272
  }
28119
28273
 
@@ -28147,7 +28301,7 @@ function wrap(baseUrl, fn) {
28147
28301
  function buildMetaListTool(client, baseUrl) {
28148
28302
  return {
28149
28303
  name: 'meta_list',
28150
- description: 'List metas with summary stats and per-meta projection. Response includes _phaseState and owedPhase per meta.',
28304
+ description: getEndpoint('listMetas').description,
28151
28305
  parameters: {
28152
28306
  type: 'object',
28153
28307
  properties: {
@@ -28190,7 +28344,7 @@ function buildMetaListTool(client, baseUrl) {
28190
28344
  function buildMetaDetailTool(client, baseUrl) {
28191
28345
  return {
28192
28346
  name: 'meta_detail',
28193
- description: 'Full detail for a single meta, with optional archive history. Response includes _phaseState and owedPhase.',
28347
+ description: getEndpoint('metaDetail').description,
28194
28348
  parameters: {
28195
28349
  type: 'object',
28196
28350
  properties: {
@@ -28219,7 +28373,7 @@ function buildMetaDetailTool(client, baseUrl) {
28219
28373
  function buildMetaPreviewTool(client, baseUrl) {
28220
28374
  return {
28221
28375
  name: 'meta_preview',
28222
- description: 'Dry-run preview of next synthesis. Returns owedPhase, priorityBand, phaseState, stalenessInputs, and architectInvalidators.',
28376
+ description: getEndpoint('preview').description,
28223
28377
  parameters: {
28224
28378
  type: 'object',
28225
28379
  properties: {
@@ -28235,7 +28389,7 @@ function buildMetaPreviewTool(client, baseUrl) {
28235
28389
  function buildMetaTriggerTool(client, baseUrl) {
28236
28390
  return {
28237
28391
  name: 'meta_trigger',
28238
- description: 'Trigger synthesis. Path-targeted creates an override queue entry; returns owedPhase. Fully-fresh metas return status:skipped.',
28392
+ description: getEndpoint('synthesize').description,
28239
28393
  parameters: {
28240
28394
  type: 'object',
28241
28395
  properties: {
@@ -28251,7 +28405,7 @@ function buildMetaTriggerTool(client, baseUrl) {
28251
28405
  function buildMetaSeedTool(client, baseUrl) {
28252
28406
  return {
28253
28407
  name: 'meta_seed',
28254
- description: 'Create a .meta/ directory and initial meta.json for a new entity path.',
28408
+ description: getEndpoint('seed').description,
28255
28409
  parameters: {
28256
28410
  type: 'object',
28257
28411
  properties: {
@@ -28294,7 +28448,7 @@ function buildMetaSeedTool(client, baseUrl) {
28294
28448
  function buildMetaUnlockTool(client, baseUrl) {
28295
28449
  return {
28296
28450
  name: 'meta_unlock',
28297
- description: 'Remove a stale .lock from a meta entity that is stuck.',
28451
+ description: getEndpoint('unlock').description,
28298
28452
  parameters: {
28299
28453
  type: 'object',
28300
28454
  properties: {
@@ -28311,7 +28465,7 @@ function buildMetaUnlockTool(client, baseUrl) {
28311
28465
  function buildMetaQueueTool(client, baseUrl) {
28312
28466
  return {
28313
28467
  name: 'meta_queue',
28314
- description: 'Queue management. list: 3-layer model (current with phase, overrides, automatic, pending). clear: removes overrides only. abort: returns {status,path,phase} or {status:idle}.',
28468
+ description: `Queue management. list: ${getEndpoint('queue').description} clear: ${getEndpoint('queueClear').description} abort: ${getEndpoint('abort').description}`,
28315
28469
  parameters: {
28316
28470
  type: 'object',
28317
28471
  properties: {
@@ -28341,7 +28495,7 @@ function buildMetaQueueTool(client, baseUrl) {
28341
28495
  function buildMetaUpdateTool(client, baseUrl) {
28342
28496
  return {
28343
28497
  name: 'meta_update',
28344
- description: 'Update user-settable reserved properties on a meta entity.',
28498
+ description: getEndpoint('updateMeta').description,
28345
28499
  parameters: {
28346
28500
  type: 'object',
28347
28501
  properties: {
@@ -28351,7 +28505,7 @@ function buildMetaUpdateTool(client, baseUrl) {
28351
28505
  },
28352
28506
  updates: {
28353
28507
  type: 'object',
28354
- description: 'Properties to set. Supported: _steer, _emphasis, _depth, _crossRefs, _disabled. Set to null to remove.',
28508
+ description: 'Properties to set. Supported: _steer, _emphasis, _depth, _crossRefs, _disabled, _architectTimeout, _builderTimeout, _criticTimeout. Set to null to remove.',
28355
28509
  properties: {
28356
28510
  _steer: { type: ['string', 'null'] },
28357
28511
  _emphasis: { type: ['number', 'null'] },
@@ -28363,6 +28517,9 @@ function buildMetaUpdateTool(client, baseUrl) {
28363
28517
  ],
28364
28518
  },
28365
28519
  _disabled: { type: ['boolean', 'null'] },
28520
+ _architectTimeout: { type: ['number', 'null'] },
28521
+ _builderTimeout: { type: ['number', 'null'] },
28522
+ _criticTimeout: { type: ['number', 'null'] },
28366
28523
  },
28367
28524
  },
28368
28525
  },
@@ -28414,15 +28571,27 @@ function register(api) {
28414
28571
  WORKSPACE_CONFIG_DEFAULTS.core.gatewayUrl;
28415
28572
  const placeholder = 'The jeeves-meta synthesis engine is initializing...\n\n' +
28416
28573
  'Read the `jeeves-meta` skill for usage guidance, configuration, and troubleshooting.';
28574
+ let consecutive503s = 0;
28417
28575
  const getContent = createAsyncContentCache({
28418
- fetch: async () => generateMetaMenu(client),
28576
+ fetch: async () => {
28577
+ const content = await generateMetaMenu(client);
28578
+ consecutive503s = 0;
28579
+ return content;
28580
+ },
28419
28581
  placeholder,
28420
28582
  onError: (error) => {
28421
28583
  const msg = error instanceof Error ? error.message : String(error);
28422
28584
  if (/HTTP 503\b/i.test(msg) || /scan.in.progress/i.test(msg)) {
28423
- console.warn('[jeeves-meta] Watcher scan still in progress — will retry on next refresh cycle.');
28585
+ consecutive503s++;
28586
+ if (consecutive503s === 1) {
28587
+ console.warn('[jeeves-meta] Watcher scan still in progress — will retry on next refresh cycle.');
28588
+ }
28589
+ else {
28590
+ console.debug(`[jeeves-meta] Watcher scan still in progress (attempt ${String(consecutive503s)}) — suppressing repeated warnings.`);
28591
+ }
28424
28592
  return;
28425
28593
  }
28594
+ consecutive503s = 0;
28426
28595
  console.warn('[jeeves-meta] Content fetch failed:', msg);
28427
28596
  },
28428
28597
  });
@@ -48,8 +48,12 @@ Full detail for a single meta, with optional archive history. Includes
48
48
  Dry-run for the next synthesis candidate. Shows scope files, delta files,
49
49
  architect trigger reasons, steer status, structure changes, and the
50
50
  phase that would execute next — without running any LLM calls. Includes
51
- `phaseState` and `owedPhase` (the phase that would run). Use before
52
- `meta_trigger` to understand what will happen.
51
+ `phaseState`, `owedPhase` (the phase that would run), `inputStatus`
52
+ (informational flags: structureHash, steerChanged, architectChanged,
53
+ criticChanged, crossRefsDeclChanged, crossRefContentChanged), and
54
+ `architectInvalidators` (list of reasons architect was triggered, e.g.
55
+ `structureHash`, `steer`, `_crossRefs`, `firstRun`, `architectEvery`).
56
+ Use before `meta_trigger` to understand what will happen.
53
57
 
54
58
  **Parameters:**
55
59
  - `path` (optional): Specific `.meta/` or owner directory path. If omitted,
@@ -105,7 +109,8 @@ modify `_crossRefs` — without editing `meta.json` directly on the filesystem.
105
109
  **Parameters:**
106
110
  - `path` (required): `.meta/` or owner directory path.
107
111
  - `updates` (required): Object with properties to set. Supported:
108
- `_steer`, `_emphasis`, `_depth`, `_crossRefs`, `_disabled`.
112
+ `_steer`, `_emphasis`, `_depth`, `_crossRefs`, `_disabled`,
113
+ `_architectTimeout`, `_builderTimeout`, `_criticTimeout`.
109
114
  Set a value to `null` to remove the property.
110
115
 
111
116
  ### meta_queue
@@ -141,6 +146,7 @@ compatibility.
141
146
  - **Disabling a meta:** `meta_update` with path and `updates: { _disabled: true }`
142
147
  - **Re-enabling a meta:** `meta_update` with path and `updates: { _disabled: null }`
143
148
  - **Changing steer via API:** `meta_update` with path and `updates: { _steer: "new focus" }`
149
+ - **Setting per-entity timeouts:** `meta_update` with path and `updates: { _builderTimeout: 600 }`
144
150
  - **Reading synthesis output:** Use `watcher_search` filtered by the properties
145
151
  configured in `metaProperty` (e.g. `{ "domains": ["meta"] }` in production).
146
152
  The default properties are `{ _meta: "current" }` for live metas and
@@ -213,7 +219,9 @@ Key settings:
213
219
 
214
220
  | `schedule` | `*/30 * * * *` | Cron expression for automatic synthesis scheduling |
215
221
  | `serverBaseUrl` | (optional) | Public base URL of the service (e.g. `http://myhost:1938`). When set, progress reports include clickable entity links. |
216
- | `reportChannel` | (optional) | Gateway channel target for progress messages (e.g. Slack channel ID) |
222
+ | `reportChannel` | (optional) | Gateway channel name (e.g. `slack`). Legacy: also used as target if `reportTarget` is unset. |
223
+ | `reportTarget` | (optional) | Channel/user ID to send progress messages to |
224
+ | `tier2ScanLimit` | 50 | Max all-fresh candidates to scan per tick in Tier 2 invalidation |
217
225
  | `logging.level` | `info` | Log level (trace/debug/info/warn/error) |
218
226
  | `logging.file` | (optional) | Log file path |
219
227
 
@@ -335,7 +343,7 @@ The `autoSeed` config field enables declarative, config-driven `.meta/`
335
343
  creation. It is an array of policy rules, each with the shape:
336
344
 
337
345
  ```json
338
- { "match": "<glob>", "steer": "<optional prompt>", "crossRefs": ["<optional paths>"] }
346
+ { "match": "<glob>", "steer": "<optional>", "crossRefs": ["<optional>"], "parentDepth": 0 }
339
347
  ```
340
348
 
341
349
  - **`match`** (required) — a glob pattern compatible with `watcher.walk()`.
@@ -345,6 +353,14 @@ creation. It is an array of policy rules, each with the shape:
345
353
  seeded `meta.json`.
346
354
  - **`crossRefs`** (optional) — array of cross-ref owner paths written as
347
355
  `_crossRefs` in the seeded `meta.json`.
356
+ - **`parentDepth`** (optional, default 0) — walk up this many extra parent
357
+ levels from the matched file's directory.
358
+ - **`architectTimeout`** (optional) — per-category timeout override for
359
+ the architect phase (seconds, min 30).
360
+ - **`builderTimeout`** (optional) — per-category timeout override for
361
+ the builder phase (seconds, min 30).
362
+ - **`criticTimeout`** (optional) — per-category timeout override for
363
+ the critic phase (seconds, min 30).
348
364
 
349
365
  **Evaluation order:** Rules are processed in array order. If multiple rules
350
366
  match the same directory, the last match wins for `steer` and `crossRefs`.
@@ -567,7 +583,8 @@ jeeves-meta <command> [options]
567
583
  ```
568
584
 
569
585
  Commands: `start`, `status`, `list`, `detail`, `preview`, `synthesize`,
570
- `seed`, `unlock`, `config`, `service install|start|stop|status|remove`.
586
+ `seed`, `unlock`, `abort`, `prune`, `config`, `queue list|clear`,
587
+ `service install|start|stop|status|remove`.
571
588
 
572
589
  Config resolution: `--config` flag → `JEEVES_META_CONFIG` env var → error.
573
590
  All client commands support `-p, --port` to specify the service port (default: 1938).
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @module serviceClient
8
8
  */
9
- import type { DepHealth, GatewayDepHealth, MetaListSummary, MetasItem, MetasResponse, ServiceState, WatcherDepHealth } from '@karmaniverous/jeeves-meta-core';
9
+ import { type DepHealth, type GatewayDepHealth, type MetaListSummary, type MetasItem, type MetasResponse, type ServiceState, type WatcherDepHealth } from '@karmaniverous/jeeves-meta-core';
10
10
  export type { DepHealth, GatewayDepHealth, MetaListSummary, MetasItem, MetasResponse, ServiceState, WatcherDepHealth, };
11
11
  /**
12
12
  * Service status response from GET /status.
@@ -48,6 +48,11 @@ export declare class MetaServiceClient {
48
48
  private get;
49
49
  /** POST helper — returns parsed JSON. */
50
50
  private post;
51
+ /**
52
+ * Interpolate a parameterized endpoint path.
53
+ * Replaces `:param` placeholders with URI-encoded values.
54
+ */
55
+ private endpointPath;
51
56
  /** GET /status — service health + queue state. */
52
57
  status(): Promise<StatusResponse>;
53
58
  /** GET /metas — list all meta entities with summary. */
@@ -67,6 +72,9 @@ export declare class MetaServiceClient {
67
72
  _depth?: number | null;
68
73
  _crossRefs?: string[] | null;
69
74
  _disabled?: boolean | null;
75
+ _architectTimeout?: number | null;
76
+ _builderTimeout?: number | null;
77
+ _criticTimeout?: number | null;
70
78
  }): Promise<unknown>;
71
79
  /** GET /metas/:path — detail for a single meta. */
72
80
  detail(metaPath: string, options?: {
@@ -2,7 +2,7 @@
2
2
  "id": "jeeves-meta-openclaw",
3
3
  "name": "Jeeves Meta",
4
4
  "description": "Knowledge synthesis tools — trigger synthesis, view status, manage entities.",
5
- "version": "0.12.4",
5
+ "version": "0.12.6",
6
6
  "skills": [
7
7
  "dist/skills/jeeves-meta"
8
8
  ],
package/package.json CHANGED
@@ -1,15 +1,30 @@
1
1
  {
2
- "name": "@karmaniverous/jeeves-meta-openclaw",
3
- "version": "0.12.4",
4
2
  "author": "Jason Williscroft",
5
- "description": "OpenClaw plugin for jeeves-meta — synthesis tools and virtual rule registration",
6
- "license": "BSD-3-Clause",
7
- "type": "module",
8
- "main": "dist/index.js",
9
- "types": "dist/index.d.ts",
10
3
  "bin": {
11
4
  "jeeves-meta-openclaw": "./dist/cli.js"
12
5
  },
6
+ "bugs": {
7
+ "url": "https://github.com/karmaniverous/jeeves-meta/issues"
8
+ },
9
+ "dependencies": {
10
+ "@karmaniverous/jeeves": "^0.5.11",
11
+ "@karmaniverous/jeeves-meta-core": "^0.1.3"
12
+ },
13
+ "description": "OpenClaw plugin for jeeves-meta — synthesis tools and virtual rule registration",
14
+ "devDependencies": {
15
+ "@dotenvx/dotenvx": "^1.69.1",
16
+ "@rollup/plugin-commonjs": "^29.0.2",
17
+ "@rollup/plugin-node-resolve": "^16.0.3",
18
+ "@rollup/plugin-typescript": "^12.3.0",
19
+ "cross-env": "^10.1.0",
20
+ "release-it": "^20.0.1",
21
+ "rollup": "^4.60.4",
22
+ "tslib": "^2.8.1",
23
+ "vitest": "^4.1.7"
24
+ },
25
+ "engines": {
26
+ "node": ">=22"
27
+ },
13
28
  "exports": {
14
29
  ".": {
15
30
  "import": {
@@ -23,17 +38,6 @@
23
38
  "content",
24
39
  "openclaw.plugin.json"
25
40
  ],
26
- "publishConfig": {
27
- "access": "public"
28
- },
29
- "repository": {
30
- "type": "git",
31
- "url": "git+https://github.com/karmaniverous/jeeves-meta.git",
32
- "directory": "packages/openclaw"
33
- },
34
- "bugs": {
35
- "url": "https://github.com/karmaniverous/jeeves-meta/issues"
36
- },
37
41
  "homepage": "https://github.com/karmaniverous/jeeves-meta#readme",
38
42
  "keywords": [
39
43
  "openclaw",
@@ -41,46 +45,23 @@
41
45
  "jeeves-meta",
42
46
  "synthesis"
43
47
  ],
44
- "engines": {
45
- "node": ">=22"
46
- },
48
+ "license": "BSD-3-Clause",
49
+ "main": "dist/index.js",
50
+ "name": "@karmaniverous/jeeves-meta-openclaw",
47
51
  "openclaw": {
48
52
  "extensions": [
49
53
  "./dist/index.js"
50
54
  ]
51
55
  },
52
- "devDependencies": {
53
- "@dotenvx/dotenvx": "^1.65.0",
54
- "@rollup/plugin-commonjs": "^29.0.2",
55
- "@rollup/plugin-node-resolve": "^16.0.3",
56
- "@rollup/plugin-typescript": "^12.3.0",
57
- "cross-env": "^10.1.0",
58
- "release-it": "^20.0.1",
59
- "rollup": "^4.60.3",
60
- "tslib": "^2.8.1",
61
- "vitest": "^4.1.6"
62
- },
63
- "scripts": {
64
- "build": "npm run build:plugin && npm run build:skills && npm run build:content",
65
- "changelog": "git-cliff -o CHANGELOG.md",
66
- "lint": "eslint .",
67
- "lint:fix": "eslint --fix .",
68
- "release": "dotenvx run -f .env.local -- release-it",
69
- "release:pre": "dotenvx run -f .env.local -- release-it --no-git.requireBranch --github.prerelease --preRelease",
70
- "knip": "knip",
71
- "test": "vitest run",
72
- "typecheck": "tsc",
73
- "diagrams": "cd diagrams && plantuml -tpng -o ../assets -r .",
74
- "build:plugin": "rimraf dist && cross-env NO_COLOR=1 rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript",
75
- "build:skills": "node scripts/build-skills.mjs",
76
- "build:content": "node scripts/copy-content.mjs"
56
+ "publishConfig": {
57
+ "access": "public"
77
58
  },
78
59
  "release-it": {
79
60
  "git": {
80
61
  "changelog": "npx git-cliff --unreleased --strip header",
81
62
  "commitMessage": "chore: release @karmaniverous/jeeves-meta-openclaw v${version}",
82
- "tagName": "openclaw/${version}",
83
- "requireBranch": "main"
63
+ "requireBranch": "main",
64
+ "tagName": "openclaw/${version}"
84
65
  },
85
66
  "github": {
86
67
  "release": true
@@ -89,10 +70,6 @@
89
70
  "after:bump": [
90
71
  "node -e \"const f='openclaw.plugin.json';const j=JSON.parse(require('fs').readFileSync(f,'utf8'));j.version='${version}';require('fs').writeFileSync(f,JSON.stringify(j,null,2)+'')\""
91
72
  ],
92
- "before:npm:release": [
93
- "npx git-cliff -o CHANGELOG.md",
94
- "git add -A"
95
- ],
96
73
  "after:init": [
97
74
  "npm run lint",
98
75
  "npm run typecheck",
@@ -103,14 +80,37 @@
103
80
  "git switch -c release/openclaw/${version}",
104
81
  "git push -u origin release/openclaw/${version}",
105
82
  "git switch ${branchName}"
83
+ ],
84
+ "before:npm:release": [
85
+ "npx git-cliff -o CHANGELOG.md",
86
+ "git add -A"
106
87
  ]
107
88
  },
108
89
  "npm": {
109
90
  "publish": true
110
91
  }
111
92
  },
112
- "dependencies": {
113
- "@karmaniverous/jeeves": "^0.5.10",
114
- "@karmaniverous/jeeves-meta-core": "^0.1.0"
115
- }
93
+ "repository": {
94
+ "directory": "packages/openclaw",
95
+ "type": "git",
96
+ "url": "git+https://github.com/karmaniverous/jeeves-meta.git"
97
+ },
98
+ "scripts": {
99
+ "build": "npm run build:plugin && npm run build:skills && npm run build:content",
100
+ "build:content": "node scripts/copy-content.mjs",
101
+ "build:plugin": "rimraf dist && cross-env NO_COLOR=1 rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript",
102
+ "build:skills": "node scripts/build-skills.mjs",
103
+ "changelog": "git-cliff -o CHANGELOG.md",
104
+ "diagrams": "cd diagrams && plantuml -tpng -o ../assets -r .",
105
+ "knip": "knip",
106
+ "lint": "eslint .",
107
+ "lint:fix": "eslint --fix .",
108
+ "release": "dotenvx run -f .env.local -- release-it",
109
+ "release:pre": "dotenvx run -f .env.local -- release-it --no-git.requireBranch --github.prerelease --preRelease",
110
+ "test": "vitest run",
111
+ "typecheck": "tsc"
112
+ },
113
+ "type": "module",
114
+ "types": "dist/index.d.ts",
115
+ "version": "0.12.6"
116
116
  }