@karmaniverous/jeeves-meta 0.12.2 → 0.12.4

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.
@@ -7007,15 +7007,48 @@ function packageDirectorySync({cwd, ignoreTypeOnlyPackageJson} = {}) {
7007
7007
  return findPackageDirectorySync(cwd ?? process$1.cwd(), ignoreTypeOnlyPackageJson);
7008
7008
  }
7009
7009
 
7010
+ /**
7011
+ * Directory and file path conventions for the Jeeves platform.
7012
+ */
7013
+ /** Core config directory name within the config root. */
7014
+ const CORE_CONFIG_DIR = 'jeeves-core';
7015
+ /** Prefix for component config directories: `jeeves-{name}`. */
7016
+ const COMPONENT_CONFIG_PREFIX = 'jeeves-';
7010
7017
  /** Core config file name. */
7011
7018
  const CONFIG_FILE = 'config.json';
7019
+
7020
+ /**
7021
+ * Workspace and config root initialization.
7022
+ *
7023
+ * @remarks
7024
+ * `init()` must be called once before any other core library functions.
7025
+ * It caches `workspacePath` and `configRoot` at module level.
7026
+ * Core derives all namespaced paths from these values:
7027
+ * - `{configRoot}/jeeves-core/` for core config
7028
+ * - `{configRoot}/jeeves-{name}/` for each component
7029
+ */
7030
+ let state;
7031
+ /**
7032
+ * Initialize the core library with workspace and config root paths.
7033
+ *
7034
+ * @param options - Workspace and config root paths.
7035
+ */
7036
+ function init(options) {
7037
+ state = {
7038
+ workspacePath: options.workspacePath,
7039
+ configRoot: options.configRoot,
7040
+ coreConfigDir: join(options.configRoot, CORE_CONFIG_DIR),
7041
+ };
7042
+ }
7012
7043
  /**
7013
7044
  * Get the core config directory path.
7014
7045
  *
7015
7046
  * @throws Error if `init()` has not been called.
7016
7047
  */
7017
7048
  function getCoreConfigDir() {
7018
- throw new Error('jeeves-core: init() must be called first');
7049
+ if (!state)
7050
+ throw new Error('jeeves-core: init() must be called first');
7051
+ return state.coreConfigDir;
7019
7052
  }
7020
7053
  /**
7021
7054
  * Derive the component config directory from the component name.
@@ -7025,7 +7058,9 @@ function getCoreConfigDir() {
7025
7058
  * @throws Error if `init()` has not been called.
7026
7059
  */
7027
7060
  function getComponentConfigDir(componentName) {
7028
- throw new Error('jeeves-core: init() must be called first');
7061
+ if (!state)
7062
+ throw new Error('jeeves-core: init() must be called first');
7063
+ return join(state.configRoot, `${COMPONENT_CONFIG_PREFIX}${componentName}`);
7029
7064
  }
7030
7065
  /**
7031
7066
  * Write content to a file atomically via a temp file + rename.
@@ -7901,6 +7936,19 @@ function createServiceManager(descriptor) {
7901
7936
  }
7902
7937
  }
7903
7938
 
7939
+ /**
7940
+ * Shared CLI defaults and option registration for Jeeves CLI commands.
7941
+ *
7942
+ * @remarks
7943
+ * All three CLI commands (install, uninstall, status) share the same
7944
+ * `--workspace` and `--config-root` options with the same defaults.
7945
+ * This module centralizes them to eliminate duplication.
7946
+ */
7947
+ /** Default workspace path (current directory). */
7948
+ const DEFAULT_WORKSPACE = '.';
7949
+ /** Default config root path. */
7950
+ const DEFAULT_CONFIG_ROOT = './config';
7951
+
7904
7952
  /**
7905
7953
  * Factory for the standard Jeeves service CLI.
7906
7954
  *
@@ -7943,7 +7991,10 @@ function createServiceCli(descriptor) {
7943
7991
  .command('start')
7944
7992
  .description('Launch the service process (foreground)')
7945
7993
  .requiredOption('-c, --config <path>', 'Config file path')
7994
+ .option('-w, --workspace <path>', 'Workspace root path', DEFAULT_WORKSPACE)
7995
+ .option('--config-root <path>', 'Platform config root path', DEFAULT_CONFIG_ROOT)
7946
7996
  .action(async (opts) => {
7997
+ init({ workspacePath: opts.workspace, configRoot: opts.configRoot });
7947
7998
  await descriptor.run(opts.config);
7948
7999
  });
7949
8000
  // --- status ---
@@ -8251,7 +8302,7 @@ function loadConfig(configDir) {
8251
8302
  function getBindAddress(componentName) {
8252
8303
  // Tier 1: Component config (if provided)
8253
8304
  {
8254
- const componentConfig = loadConfig(getComponentConfigDir());
8305
+ const componentConfig = loadConfig(getComponentConfigDir(componentName));
8255
8306
  if (componentConfig?.bindAddress) {
8256
8307
  return componentConfig.bindAddress;
8257
8308
  }
@@ -10168,7 +10219,11 @@ async function isStale(scopePrefix, meta, watcher) {
10168
10219
  if (!meta._generatedAt)
10169
10220
  return true; // Never synthesized = stale
10170
10221
  const files = await watcher.walk([`${escapeGlob(scopePrefix)}/**`]);
10171
- return hasModifiedAfter(files, new Date(meta._generatedAt).getTime());
10222
+ // Exclude .meta/ subtree — synthesis outputs must not trigger staleness.
10223
+ // Handle both forward and back slashes for cross-platform compatibility.
10224
+ const metaSep = /[/\\]\.meta(?:[/\\]|$)/;
10225
+ const filtered = files.filter((f) => !metaSep.test(f));
10226
+ return hasModifiedAfter(filtered, new Date(meta._generatedAt).getTime());
10172
10227
  }
10173
10228
  /** Maximum staleness for never-synthesized metas (1 year in seconds). */
10174
10229
  const MAX_STALENESS_SECONDS = 365 * 86_400;
@@ -12536,7 +12591,7 @@ async function startService(config, configPath) {
12536
12591
  deps: routeDeps,
12537
12592
  });
12538
12593
  // Start HTTP server
12539
- const bindAddress = getBindAddress();
12594
+ const bindAddress = getBindAddress('meta');
12540
12595
  try {
12541
12596
  await server.listen({ port: config.port, host: bindAddress });
12542
12597
  logger.info({ port: config.port, host: bindAddress }, 'Service listening');
package/dist/index.js CHANGED
@@ -9744,7 +9744,11 @@ async function isStale(scopePrefix, meta, watcher) {
9744
9744
  if (!meta._generatedAt)
9745
9745
  return true; // Never synthesized = stale
9746
9746
  const files = await watcher.walk([`${escapeGlob(scopePrefix)}/**`]);
9747
- return hasModifiedAfter(files, new Date(meta._generatedAt).getTime());
9747
+ // Exclude .meta/ subtree — synthesis outputs must not trigger staleness.
9748
+ // Handle both forward and back slashes for cross-platform compatibility.
9749
+ const metaSep = /[/\\]\.meta(?:[/\\]|$)/;
9750
+ const filtered = files.filter((f) => !metaSep.test(f));
9751
+ return hasModifiedAfter(filtered, new Date(meta._generatedAt).getTime());
9748
9752
  }
9749
9753
  /** Maximum staleness for never-synthesized metas (1 year in seconds). */
9750
9754
  const MAX_STALENESS_SECONDS = 365 * 86_400;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karmaniverous/jeeves-meta",
3
- "version": "0.12.2",
3
+ "version": "0.12.4",
4
4
  "author": "Jason Williscroft",
5
5
  "description": "Fastify HTTP service for the Jeeves Meta synthesis engine",
6
6
  "license": "BSD-3-Clause",
@@ -41,7 +41,7 @@
41
41
  "node": ">=20"
42
42
  },
43
43
  "dependencies": {
44
- "@karmaniverous/jeeves": "^0.4.5",
44
+ "@karmaniverous/jeeves": "^0.4.6",
45
45
  "commander": "^14",
46
46
  "croner": "^10",
47
47
  "fastify": "^5.8",