@karmaniverous/jeeves 0.5.3 → 0.5.5

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.
@@ -269,14 +269,14 @@ const PLATFORM_COMPONENTS = [
269
269
  * Core library version, inlined at build time.
270
270
  *
271
271
  * @remarks
272
- * The `0.5.2` placeholder is replaced by
272
+ * The `0.5.4` placeholder is replaced by
273
273
  * `@rollup/plugin-replace` during the build with the actual version
274
274
  * from `package.json`. This ensures the correct version survives
275
275
  * when consumers bundle core into their own dist (where runtime
276
276
  * `import.meta.url`-based resolution would find the wrong package.json).
277
277
  */
278
278
  /** The core library version from package.json (inlined at build time). */
279
- const CORE_VERSION = '0.5.2';
279
+ const CORE_VERSION = '0.5.4';
280
280
 
281
281
  /**
282
282
  * Runtime Node.js version floor check.
@@ -2,11 +2,14 @@
2
2
  import { writeFileSync, renameSync, unlinkSync, existsSync, mkdirSync, readFileSync, readdirSync, copyFileSync, rmSync } from 'node:fs';
3
3
  import { dirname, basename, join, resolve } from 'node:path';
4
4
  import * as commander from 'commander';
5
- import { packageDirectorySync } from 'package-directory';
6
5
  import { randomUUID } from 'node:crypto';
7
6
  import { lock } from 'proper-lockfile';
8
7
  import 'semver';
8
+ import 'node:child_process';
9
9
  import { homedir } from 'node:os';
10
+ import { z } from 'zod';
11
+ import { fileURLToPath } from 'node:url';
12
+ import { packageDirectorySync } from 'package-directory';
10
13
 
11
14
  function getDefaultExportFromCjs (x) {
12
15
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -127,14 +130,14 @@ const COMPONENT_VERSIONS_FILE = 'component-versions.json';
127
130
  * Core library version, inlined at build time.
128
131
  *
129
132
  * @remarks
130
- * The `0.5.2` placeholder is replaced by
133
+ * The `0.5.4` placeholder is replaced by
131
134
  * `@rollup/plugin-replace` during the build with the actual version
132
135
  * from `package.json`. This ensures the correct version survives
133
136
  * when consumers bundle core into their own dist (where runtime
134
137
  * `import.meta.url`-based resolution would find the wrong package.json).
135
138
  */
136
139
  /** The core library version from package.json (inlined at build time). */
137
- const CORE_VERSION = '0.5.2';
140
+ const CORE_VERSION = '0.5.4';
138
141
 
139
142
  /**
140
143
  * Shared file I/O helpers for managed section operations.
@@ -887,6 +890,153 @@ function seedSkill(workspacePath) {
887
890
  writeFileSync(skillPath, skillContent, 'utf-8');
888
891
  }
889
892
 
893
+ /**
894
+ * Zod schema for the Jeeves component descriptor.
895
+ *
896
+ * @remarks
897
+ * The descriptor replaces the v0.4.0 `JeevesComponent` interface with a
898
+ * Zod-first approach. The TypeScript type is inferred via `z.infer<>`.
899
+ * Validates at parse time: prime interval, callable functions.
900
+ */
901
+ /**
902
+ * Check whether a number is prime.
903
+ *
904
+ * @param n - Number to check.
905
+ * @returns `true` if n is prime.
906
+ */
907
+ function isPrime(n) {
908
+ if (n < 2)
909
+ return false;
910
+ if (n === 2)
911
+ return true;
912
+ if (n % 2 === 0)
913
+ return false;
914
+ for (let i = 3; i * i <= n; i += 2) {
915
+ if (n % i === 0)
916
+ return false;
917
+ }
918
+ return true;
919
+ }
920
+ /**
921
+ * Zod schema for the Jeeves component descriptor.
922
+ *
923
+ * @remarks
924
+ * Single source of truth for what a component must provide.
925
+ * Factories consume this descriptor to produce CLI commands,
926
+ * plugin tools, and HTTP handlers.
927
+ */
928
+ z.object({
929
+ /** Component name (e.g., 'watcher', 'runner', 'server', 'meta'). */
930
+ name: z.string().min(1, 'name must be a non-empty string'),
931
+ /** Component version (from package.json). */
932
+ version: z.string().min(1, 'version must be a non-empty string'),
933
+ /** npm package name for the service. */
934
+ servicePackage: z.string().min(1),
935
+ /** npm package name for the plugin. */
936
+ pluginPackage: z.string().min(1),
937
+ /** System service name. Defaults to `jeeves-${name}` when not provided. */
938
+ serviceName: z.string().min(1).optional(),
939
+ /** Default port for the service's HTTP API. */
940
+ defaultPort: z.number().int().positive(),
941
+ /** Zod schema for validating config files. */
942
+ configSchema: z.custom((val) => val !== null &&
943
+ typeof val === 'object' &&
944
+ typeof val.parse === 'function', { message: 'configSchema must be a Zod schema' }),
945
+ /** Config file name (e.g., 'jeeves-watcher.config.json'). */
946
+ configFileName: z.string().min(1),
947
+ /** Returns a default config object for `init`. */
948
+ initTemplate: z.function({
949
+ input: [],
950
+ output: z.record(z.string(), z.unknown()),
951
+ }),
952
+ /**
953
+ * Service-side callback after config apply. Receives the merged,
954
+ * validated config (not the raw patch). Optional — if omitted,
955
+ * write-only (service picks up changes on restart).
956
+ */
957
+ onConfigApply: z
958
+ .function({
959
+ input: [z.record(z.string(), z.unknown())],
960
+ output: z.promise(z.void()),
961
+ })
962
+ .optional(),
963
+ /**
964
+ * Custom merge function for config apply. Receives the existing config
965
+ * and the patch, returns the merged result. Optional — if omitted,
966
+ * the default deep-merge (object-recursive, array-replacing) is used.
967
+ *
968
+ * Use this to implement domain-specific merge strategies such as
969
+ * name-based array merging for inference rules.
970
+ */
971
+ customMerge: z
972
+ .function({
973
+ input: [
974
+ z.record(z.string(), z.unknown()),
975
+ z.record(z.string(), z.unknown()),
976
+ ],
977
+ output: z.record(z.string(), z.unknown()),
978
+ })
979
+ .optional(),
980
+ /**
981
+ * Returns command + args for launching the service process.
982
+ * Consumed by `service install`.
983
+ */
984
+ startCommand: z.function({
985
+ input: [z.string()],
986
+ output: z.array(z.string()),
987
+ }),
988
+ /** In-process service entry point for the CLI `start` command. */
989
+ run: z.function({
990
+ input: [z.string()],
991
+ output: z.promise(z.void()),
992
+ }),
993
+ /** TOOLS.md section name (e.g., 'Watcher'). */
994
+ sectionId: z.string().min(1, 'sectionId must be a non-empty string'),
995
+ /** Refresh interval in seconds (must be a prime number). */
996
+ refreshIntervalSeconds: z.number().int().positive().refine(isPrime, {
997
+ message: 'refreshIntervalSeconds must be a prime number',
998
+ }),
999
+ /** Produce the component's TOOLS.md section content. */
1000
+ generateToolsContent: z.function({ input: [], output: z.string() }),
1001
+ /** Component dependencies for HEARTBEAT alert suppression. */
1002
+ dependencies: z
1003
+ .object({
1004
+ /** Components that must be healthy for this component to function. */
1005
+ hard: z.array(z.string()),
1006
+ /** Components that improve behavior but are not strictly required. */
1007
+ soft: z.array(z.string()),
1008
+ })
1009
+ .optional(),
1010
+ /** Extension point: add custom CLI commands to the service CLI. */
1011
+ customCliCommands: z
1012
+ .function({ input: [z.custom()], output: z.void() })
1013
+ .optional(),
1014
+ /** Extension point: return additional plugin tool descriptors. */
1015
+ customPluginTools: z
1016
+ .function({ input: [z.custom()], output: z.array(z.unknown()) })
1017
+ .optional(),
1018
+ });
1019
+
1020
+ /**
1021
+ * Resolve the package root directory from a module's `import.meta.url`.
1022
+ *
1023
+ * @module
1024
+ */
1025
+ /**
1026
+ * Get the nearest package root directory relative to the calling module URL.
1027
+ *
1028
+ * @param importMetaUrl - The `import.meta.url` of the calling module.
1029
+ * @returns The absolute package root path, or `undefined` on any error.
1030
+ */
1031
+ function getPackageRoot(importMetaUrl) {
1032
+ try {
1033
+ return packageDirectorySync({ cwd: fileURLToPath(importMetaUrl) });
1034
+ }
1035
+ catch {
1036
+ return undefined;
1037
+ }
1038
+ }
1039
+
890
1040
  /**
891
1041
  * OpenClaw configuration helpers for plugin CLI installers.
892
1042
  *
@@ -1090,8 +1240,13 @@ function readJsonFile(filePath) {
1090
1240
  * @returns A Commander program ready for `.parse()`.
1091
1241
  */
1092
1242
  function createPluginCli(options) {
1093
- const { pluginId, distDir, pluginPackage, configRoot = 'j:/config', } = options;
1243
+ const { pluginId, importMetaUrl, pluginPackage, configRoot = 'j:/config', } = options;
1094
1244
  const componentName = options.componentName ?? deriveComponentName(pluginId);
1245
+ const pkgRoot = getPackageRoot(importMetaUrl);
1246
+ if (!pkgRoot) {
1247
+ throw new Error(`Unable to resolve package root for plugin CLI: ${pluginPackage}`);
1248
+ }
1249
+ const distDir = join(pkgRoot, 'dist');
1095
1250
  const program = new Command()
1096
1251
  .name(pluginPackage)
1097
1252
  .description(`Jeeves ${componentName} plugin installer`);
@@ -1106,16 +1261,16 @@ function createPluginCli(options) {
1106
1261
  const configPath = resolveConfigPath(openClawHome);
1107
1262
  // 1. Copy dist to extensions
1108
1263
  const extensionsDir = join(openClawHome, 'extensions', pluginId);
1264
+ if (!existsSync(distDir)) {
1265
+ throw new Error(`Plugin dist directory not found: ${distDir}. Ensure the plugin is built before installing.`);
1266
+ }
1109
1267
  console.log(`Copying dist to ${extensionsDir}...`);
1110
- copyDistFiles(distDir, extensionsDir);
1268
+ copyDistFiles(distDir, join(extensionsDir, 'dist'));
1111
1269
  // Copy package.json and openclaw.plugin.json from package root
1112
- const pkgRoot = packageDirectorySync({ cwd: distDir });
1113
- if (pkgRoot) {
1114
- for (const file of ['package.json', 'openclaw.plugin.json']) {
1115
- const src = join(pkgRoot, file);
1116
- if (existsSync(src)) {
1117
- copyFileSync(src, join(extensionsDir, file));
1118
- }
1270
+ for (const file of ['package.json', 'openclaw.plugin.json']) {
1271
+ const src = join(pkgRoot, file);
1272
+ if (existsSync(src)) {
1273
+ copyFileSync(src, join(extensionsDir, file));
1119
1274
  }
1120
1275
  }
1121
1276
  console.log(' ✓ Dist files copied');
package/dist/index.d.ts CHANGED
@@ -427,8 +427,8 @@ declare function buildEffectiveConfig(opts: WorkspaceOptions): ResolvedCliConfig
427
427
  interface CreatePluginCliOptions {
428
428
  /** Plugin identifier (e.g., 'jeeves-watcher-openclaw'). */
429
429
  pluginId: string;
430
- /** Absolute path to the dist directory to copy. */
431
- distDir: string;
430
+ /** `import.meta.url` for the calling plugin CLI module. */
431
+ importMetaUrl: string;
432
432
  /** npm package name for the plugin. */
433
433
  pluginPackage: string;
434
434
  /** Component name (e.g., 'watcher'). Derived from pluginId if omitted. */
@@ -1497,6 +1497,19 @@ declare function seedSkill(workspacePath: string): void;
1497
1497
  */
1498
1498
  declare function createPluginToolset(descriptor: JeevesComponentDescriptor): ToolDescriptor[];
1499
1499
 
1500
+ /**
1501
+ * Resolve the package root directory from a module's `import.meta.url`.
1502
+ *
1503
+ * @module
1504
+ */
1505
+ /**
1506
+ * Get the nearest package root directory relative to the calling module URL.
1507
+ *
1508
+ * @param importMetaUrl - The `import.meta.url` of the calling module.
1509
+ * @returns The absolute package root path, or `undefined` on any error.
1510
+ */
1511
+ declare function getPackageRoot(importMetaUrl: string): string | undefined;
1512
+
1500
1513
  /**
1501
1514
  * Resolve the version of a package from its `import.meta.url`.
1502
1515
  *
@@ -1879,5 +1892,5 @@ interface ServiceManager {
1879
1892
  */
1880
1893
  declare function createServiceManager(descriptor: JeevesComponentDescriptor): ServiceManager;
1881
1894
 
1882
- export { AGENTS_MARKERS, CLEANUP_FLAG, COMPONENT_CONFIG_PREFIX, COMPONENT_VERSIONS_FILE, CONFIG_FILE, CORE_CONFIG_DIR, CORE_VERSION, ComponentWriter, DEFAULT_BIND_ADDRESS, DEFAULT_CORE_VERSION, DEFAULT_PORTS, HEARTBEAT_HEADING, JEEVES_SKILL_DIR, MEMORY_HEARTBEAT_NAME, META_PORT, PLATFORM_COMPONENTS, REGISTRY_CACHE_FILE, RUNNER_PORT, SECTION_IDS, SECTION_ORDER, SERVER_PORT, SKILLS_DIR, SOUL_MARKERS, STALENESS_THRESHOLD_MS, STALE_LOCK_MS, TEMPLATES_DIR, TOOLS_MARKERS, VERSION_STAMP_PATTERN, WATCHER_PORT, WORKSPACE_CONFIG_DEFAULTS, WORKSPACE_CONFIG_FILE, WORKSPACE_FILES, analyzeMemory, appendJsonl, atomicWrite, buildEffectiveConfig, buildHeartbeatSection, checkMemoryHealth, checkNodeVersion, checkRegistryVersion, connectionFail, coreConfigSchema, createAsyncContentCache, createComponentWriter, createConfigApplyHandler, createConfigQueryHandler, createGoogleAuth, createPluginCli, createPluginToolset, createServiceCli, createServiceManager, createStatusHandler, ensureDir, extractMostRecentDate, fail, fetchJson, fetchWithTimeout, formatBeginMarker, formatEndMarker, generateJsonSchema, generateWorkspaceJsonSchema, getArg, getBindAddress, getChannelWorkspace, getComponentConfigDir, getConfigRoot, getCoreConfigDir, getCoreConfigFile, getEffectiveServiceName, getPackageVersion, getServiceState, getServiceUrl, getWorkspacePath, init, isPrime, jaccard, jeevesComponentDescriptorSchema, loadEnvFile, loadWorkspaceConfig, needsCleanup, nowIso, ok, orchestrateHeartbeat, parseArgs, parseHeartbeat, parseManaged, patchConfig, postJson, readComponentVersions, readJson, readJsonl, refreshPlatformContent, removeComponentVersion, removeManagedSection, resetInit, resolveConfigPath, resolveConfigValue, resolveOpenClawHome, resolveOptionalPluginSetting, resolvePluginSetting, resolveWorkspacePath, run, runScript, runWithRetry, saveCache, seedContent, seedSkill, shingles, shouldWrite, sleepAsync, sleepMs, updateManagedSection, uuid, withFileLock, workspaceConfigSchema, writeComponentVersion, writeHeartbeatSection, writeJsonAtomic, writeJsonl };
1895
+ export { AGENTS_MARKERS, CLEANUP_FLAG, COMPONENT_CONFIG_PREFIX, COMPONENT_VERSIONS_FILE, CONFIG_FILE, CORE_CONFIG_DIR, CORE_VERSION, ComponentWriter, DEFAULT_BIND_ADDRESS, DEFAULT_CORE_VERSION, DEFAULT_PORTS, HEARTBEAT_HEADING, JEEVES_SKILL_DIR, MEMORY_HEARTBEAT_NAME, META_PORT, PLATFORM_COMPONENTS, REGISTRY_CACHE_FILE, RUNNER_PORT, SECTION_IDS, SECTION_ORDER, SERVER_PORT, SKILLS_DIR, SOUL_MARKERS, STALENESS_THRESHOLD_MS, STALE_LOCK_MS, TEMPLATES_DIR, TOOLS_MARKERS, VERSION_STAMP_PATTERN, WATCHER_PORT, WORKSPACE_CONFIG_DEFAULTS, WORKSPACE_CONFIG_FILE, WORKSPACE_FILES, analyzeMemory, appendJsonl, atomicWrite, buildEffectiveConfig, buildHeartbeatSection, checkMemoryHealth, checkNodeVersion, checkRegistryVersion, connectionFail, coreConfigSchema, createAsyncContentCache, createComponentWriter, createConfigApplyHandler, createConfigQueryHandler, createGoogleAuth, createPluginCli, createPluginToolset, createServiceCli, createServiceManager, createStatusHandler, ensureDir, extractMostRecentDate, fail, fetchJson, fetchWithTimeout, formatBeginMarker, formatEndMarker, generateJsonSchema, generateWorkspaceJsonSchema, getArg, getBindAddress, getChannelWorkspace, getComponentConfigDir, getConfigRoot, getCoreConfigDir, getCoreConfigFile, getEffectiveServiceName, getPackageRoot, getPackageVersion, getServiceState, getServiceUrl, getWorkspacePath, init, isPrime, jaccard, jeevesComponentDescriptorSchema, loadEnvFile, loadWorkspaceConfig, needsCleanup, nowIso, ok, orchestrateHeartbeat, parseArgs, parseHeartbeat, parseManaged, patchConfig, postJson, readComponentVersions, readJson, readJsonl, refreshPlatformContent, removeComponentVersion, removeManagedSection, resetInit, resolveConfigPath, resolveConfigValue, resolveOpenClawHome, resolveOptionalPluginSetting, resolvePluginSetting, resolveWorkspacePath, run, runScript, runWithRetry, saveCache, seedContent, seedSkill, shingles, shouldWrite, sleepAsync, sleepMs, updateManagedSection, uuid, withFileLock, workspaceConfigSchema, writeComponentVersion, writeHeartbeatSection, writeJsonAtomic, writeJsonl };
1883
1896
  export type { AccountConfig, AsyncContentCacheOptions, ComponentDependencies, ComponentState, ComponentVersionEntry, ComponentVersionsState, ComponentWriterOptions, ConfigApplyHandler, ConfigApplyRequest, ConfigApplyResult, ConfigProvenance, ConfigQueryHandler, ConfigQueryResponse, CoreConfig, CreatePluginCliOptions, CreateStatusHandlerOptions, GoogleAuthOptions, HeartbeatEntry, InitOptions, JeevesComponentDescriptor, ManagedMarkers, ManagedSection, MemoryHygieneOptions, MemoryHygieneResult, OrchestrateHeartbeatOptions, ParseManagedResult, ParsedHeartbeat, PlatformComponent, PluginApi, PluginInstallRecord, RefreshPlatformContentOptions, RemoveManagedSectionOptions, ResolvedCliConfig, ResolvedValue, RetryOptions, RunOptions, SectionId, SeedContentOptions, ServiceAccountFileConfig, ServiceManager, ServiceManagerOptions, ServiceState, SlackWorkspaceOptions, StatusHandler, StatusHandlerResult, StatusResponse, ToolDescriptor, ToolRegistrationOptions, ToolResult, UpdateManagedSectionOptions, VersionStamp, WorkspaceConfig, WorkspaceOptions, WriteComponentVersionOptions };