@karmaniverous/jeeves 0.3.1 → 0.4.1

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.d.ts CHANGED
@@ -1,5 +1,255 @@
1
+ import { Command } from '@commander-js/extra-typings';
1
2
  import { z } from 'zod';
2
3
 
4
+ /**
5
+ * Core types for the OpenClaw plugin SDK.
6
+ *
7
+ * @remarks
8
+ * These types define the contract between plugins and the OpenClaw gateway.
9
+ * They unify the various `PluginApi` definitions previously duplicated
10
+ * across component plugins into a single canonical source.
11
+ */
12
+ /** Result shape returned by tool executions. */
13
+ interface ToolResult {
14
+ /** Content blocks — typically a single text block. */
15
+ content: Array<{
16
+ /** MIME type identifier (e.g. `"text"`). */
17
+ type: string;
18
+ /** Text content of the block. */
19
+ text: string;
20
+ }>;
21
+ /** Whether this result represents an error. */
22
+ isError?: boolean;
23
+ }
24
+ /** Tool descriptor for registration with the OpenClaw gateway. */
25
+ interface ToolDescriptor {
26
+ /** Unique tool name. */
27
+ name: string;
28
+ /** Human-readable description. */
29
+ description: string;
30
+ /** JSON Schema for the tool's parameters. */
31
+ parameters: Record<string, unknown>;
32
+ /** Execute the tool with the given parameters. */
33
+ execute: (id: string, params: Record<string, unknown>) => Promise<ToolResult>;
34
+ }
35
+ /** Options for tool registration. */
36
+ interface ToolRegistrationOptions {
37
+ /** Whether the tool is optional (non-fatal if registration fails). */
38
+ optional?: boolean;
39
+ }
40
+ /**
41
+ * Canonical OpenClaw plugin API interface.
42
+ *
43
+ * @remarks
44
+ * This is the shape of the `api` object passed to plugins by the
45
+ * OpenClaw gateway at registration time. Fields are optional where
46
+ * the gateway may not provide them in all versions.
47
+ */
48
+ interface PluginApi {
49
+ /** OpenClaw configuration object. */
50
+ config?: {
51
+ /** Agent configuration block. */
52
+ agents?: {
53
+ /** Default agent settings. */
54
+ defaults?: {
55
+ /** Absolute path to the workspace root directory. */
56
+ workspace?: string;
57
+ };
58
+ };
59
+ /** Installed plugin configuration. */
60
+ plugins?: {
61
+ /** Plugin entries keyed by plugin ID. */
62
+ entries?: Record<string, {
63
+ /** Plugin-specific configuration key-value pairs. */
64
+ config?: Record<string, unknown>;
65
+ }>;
66
+ };
67
+ };
68
+ /**
69
+ * Resolve a path relative to the OpenClaw workspace.
70
+ *
71
+ * @remarks
72
+ * Present on newer OpenClaw builds; optional for backwards compatibility.
73
+ */
74
+ resolvePath?: (input: string) => string;
75
+ /**
76
+ * Register a tool with the OpenClaw gateway.
77
+ *
78
+ * @param tool - Tool descriptor.
79
+ * @param options - Registration options.
80
+ */
81
+ registerTool(tool: ToolDescriptor, options?: ToolRegistrationOptions): void;
82
+ }
83
+
84
+ /**
85
+ * Zod schema for the Jeeves component descriptor.
86
+ *
87
+ * @remarks
88
+ * The descriptor replaces the v0.4.0 `JeevesComponent` interface with a
89
+ * Zod-first approach. The TypeScript type is inferred via `z.infer<>`.
90
+ * Validates at parse time: prime interval, callable functions.
91
+ */
92
+
93
+ /**
94
+ * Check whether a number is prime.
95
+ *
96
+ * @param n - Number to check.
97
+ * @returns `true` if n is prime.
98
+ */
99
+ declare function isPrime(n: number): boolean;
100
+ /**
101
+ * Zod schema for the Jeeves component descriptor.
102
+ *
103
+ * @remarks
104
+ * Single source of truth for what a component must provide.
105
+ * Factories consume this descriptor to produce CLI commands,
106
+ * plugin tools, and HTTP handlers.
107
+ */
108
+ declare const jeevesComponentDescriptorSchema: z.ZodObject<{
109
+ /** Component name (e.g., 'watcher', 'runner', 'server', 'meta'). */
110
+ name: z.ZodString;
111
+ /** Component version (from package.json). */
112
+ version: z.ZodString;
113
+ /** npm package name for the service. */
114
+ servicePackage: z.ZodString;
115
+ /** npm package name for the plugin. */
116
+ pluginPackage: z.ZodString;
117
+ /** System service name. Defaults to `jeeves-${name}` when not provided. */
118
+ serviceName: z.ZodOptional<z.ZodString>;
119
+ /** Default port for the service's HTTP API. */
120
+ defaultPort: z.ZodNumber;
121
+ /** Zod schema for validating config files. */
122
+ configSchema: z.ZodType<z.ZodTypeAny, z.ZodTypeDef, z.ZodTypeAny>;
123
+ /** Config file name (e.g., 'jeeves-watcher.config.json'). */
124
+ configFileName: z.ZodString;
125
+ /** Returns a default config object for `init`. */
126
+ initTemplate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
127
+ /**
128
+ * Service-side callback after config apply. Receives the merged,
129
+ * validated config (not the raw patch). Optional — if omitted,
130
+ * write-only (service picks up changes on restart).
131
+ */
132
+ onConfigApply: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodRecord<z.ZodString, z.ZodUnknown>], z.ZodUnknown>, z.ZodPromise<z.ZodVoid>>>;
133
+ /**
134
+ * Returns command + args for launching the service process.
135
+ * Consumed by `start` CLI command and `service install`.
136
+ */
137
+ startCommand: z.ZodFunction<z.ZodTuple<[z.ZodString], z.ZodUnknown>, z.ZodArray<z.ZodString, "many">>;
138
+ /** TOOLS.md section name (e.g., 'Watcher'). */
139
+ sectionId: z.ZodString;
140
+ /** Refresh interval in seconds (must be a prime number). */
141
+ refreshIntervalSeconds: z.ZodEffects<z.ZodNumber, number, number>;
142
+ /** Produce the component's TOOLS.md section content. */
143
+ generateToolsContent: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodString>;
144
+ /** Component dependencies for HEARTBEAT alert suppression. */
145
+ dependencies: z.ZodOptional<z.ZodObject<{
146
+ hard: z.ZodArray<z.ZodString, "many">;
147
+ soft: z.ZodArray<z.ZodString, "many">;
148
+ }, "strip", z.ZodTypeAny, {
149
+ hard: string[];
150
+ soft: string[];
151
+ }, {
152
+ hard: string[];
153
+ soft: string[];
154
+ }>>;
155
+ /** Extension point: add custom CLI commands to the service CLI. */
156
+ customCliCommands: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodType<Command<[], {}, {}>, z.ZodTypeDef, Command<[], {}, {}>>], z.ZodUnknown>, z.ZodVoid>>;
157
+ /** Extension point: return additional plugin tool descriptors. */
158
+ customPluginTools: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodType<PluginApi, z.ZodTypeDef, PluginApi>], z.ZodUnknown>, z.ZodArray<z.ZodUnknown, "many">>>;
159
+ }, "strip", z.ZodTypeAny, {
160
+ name: string;
161
+ version: string;
162
+ servicePackage: string;
163
+ pluginPackage: string;
164
+ defaultPort: number;
165
+ configSchema: z.ZodTypeAny;
166
+ configFileName: string;
167
+ initTemplate: (...args: unknown[]) => Record<string, unknown>;
168
+ startCommand: (args_0: string, ...args: unknown[]) => string[];
169
+ sectionId: string;
170
+ refreshIntervalSeconds: number;
171
+ generateToolsContent: (...args: unknown[]) => string;
172
+ serviceName?: string | undefined;
173
+ onConfigApply?: ((args_0: Record<string, unknown>, ...args: unknown[]) => Promise<void>) | undefined;
174
+ dependencies?: {
175
+ hard: string[];
176
+ soft: string[];
177
+ } | undefined;
178
+ customCliCommands?: ((args_0: Command<[], {}, {}>, ...args: unknown[]) => void) | undefined;
179
+ customPluginTools?: ((args_0: PluginApi, ...args: unknown[]) => unknown[]) | undefined;
180
+ }, {
181
+ name: string;
182
+ version: string;
183
+ servicePackage: string;
184
+ pluginPackage: string;
185
+ defaultPort: number;
186
+ configSchema: z.ZodTypeAny;
187
+ configFileName: string;
188
+ initTemplate: (...args: unknown[]) => Record<string, unknown>;
189
+ startCommand: (args_0: string, ...args: unknown[]) => string[];
190
+ sectionId: string;
191
+ refreshIntervalSeconds: number;
192
+ generateToolsContent: (...args: unknown[]) => string;
193
+ serviceName?: string | undefined;
194
+ onConfigApply?: ((args_0: Record<string, unknown>, ...args: unknown[]) => Promise<void>) | undefined;
195
+ dependencies?: {
196
+ hard: string[];
197
+ soft: string[];
198
+ } | undefined;
199
+ customCliCommands?: ((args_0: Command<[], {}, {}>, ...args: unknown[]) => void) | undefined;
200
+ customPluginTools?: ((args_0: PluginApi, ...args: unknown[]) => unknown[]) | undefined;
201
+ }>;
202
+ /** Inferred TypeScript type for the component descriptor. */
203
+ type JeevesComponentDescriptor = z.infer<typeof jeevesComponentDescriptorSchema>;
204
+ /**
205
+ * Derive the effective service name from a descriptor.
206
+ *
207
+ * @param descriptor - The component descriptor.
208
+ * @returns The service name (explicit or derived from `jeeves-{name}`).
209
+ */
210
+ declare function getEffectiveServiceName(descriptor: JeevesComponentDescriptor): string;
211
+
212
+ /**
213
+ * Factory for a framework-agnostic config apply HTTP handler.
214
+ *
215
+ * @remarks
216
+ * Derives the config file path from the descriptor, validates patches
217
+ * against the descriptor's Zod schema, deep-merges (or replaces),
218
+ * writes atomically, and calls the optional `onConfigApply` callback.
219
+ */
220
+
221
+ /** Request shape for the config apply handler. */
222
+ interface ConfigApplyRequest {
223
+ /** Config patch to apply (deep-merged with existing config). */
224
+ patch: Record<string, unknown>;
225
+ /** When true, replace the entire config instead of merging. */
226
+ replace?: boolean;
227
+ }
228
+ /** Result shape returned by the config apply handler. */
229
+ interface ConfigApplyResult {
230
+ /** HTTP status code. */
231
+ status: number;
232
+ /** Response body. */
233
+ body: unknown;
234
+ }
235
+ /** Config apply handler function signature. */
236
+ type ConfigApplyHandler = (request: ConfigApplyRequest) => Promise<ConfigApplyResult>;
237
+ /**
238
+ * Create a framework-agnostic config apply handler.
239
+ *
240
+ * @remarks
241
+ * The handler:
242
+ * 1. Reads existing config from `{configRoot}/jeeves-{name}/{configFileName}`
243
+ * 2. Deep-merges the patch (or replaces if `replace: true`)
244
+ * 3. Validates the merged result against `descriptor.configSchema`
245
+ * 4. Writes atomically
246
+ * 5. Calls `descriptor.onConfigApply` with the merged config (if defined)
247
+ *
248
+ * @param descriptor - The component descriptor.
249
+ * @returns An async handler returning `{ status, body }`.
250
+ */
251
+ declare function createConfigApplyHandler(descriptor: JeevesComponentDescriptor): ConfigApplyHandler;
252
+
3
253
  /**
4
254
  * Generic config query handler with JSONPath support.
5
255
  *
@@ -37,6 +287,118 @@ type ConfigQueryHandler = (query: {
37
287
  */
38
288
  declare function createConfigQueryHandler(getConfig: () => unknown): ConfigQueryHandler;
39
289
 
290
+ /**
291
+ * Factory for a framework-agnostic `/status` HTTP handler.
292
+ *
293
+ * @remarks
294
+ * Returns a standard status response shape consumed by HEARTBEAT
295
+ * orchestration and the `{name}_status` plugin tool.
296
+ * Tracks process start time internally for uptime calculation.
297
+ */
298
+ /** Options for creating a status handler. */
299
+ interface CreateStatusHandlerOptions {
300
+ /** Component name (e.g., 'watcher'). */
301
+ name: string;
302
+ /** Component version. */
303
+ version: string;
304
+ /** Optional callback returning component-specific health details. */
305
+ getHealth?: () => Promise<Record<string, unknown>>;
306
+ }
307
+ /** Standard status response body. */
308
+ interface StatusResponse {
309
+ /** Component name. */
310
+ name: string;
311
+ /** Component version. */
312
+ version: string;
313
+ /** Seconds since process start. */
314
+ uptime: number;
315
+ /** Overall status. */
316
+ status: 'healthy' | 'degraded' | 'unhealthy';
317
+ /** Component-specific health details. */
318
+ health: Record<string, unknown>;
319
+ }
320
+ /** Return type from a status handler invocation. */
321
+ interface StatusHandlerResult {
322
+ /** HTTP status code. */
323
+ status: number;
324
+ /** Response body. */
325
+ body: StatusResponse;
326
+ }
327
+ /** Status handler function signature. */
328
+ type StatusHandler = () => Promise<StatusHandlerResult>;
329
+ /**
330
+ * Create a framework-agnostic status handler.
331
+ *
332
+ * @param options - Handler configuration.
333
+ * @returns An async function returning `{ status, body }`.
334
+ */
335
+ declare function createStatusHandler(options: CreateStatusHandlerOptions): StatusHandler;
336
+
337
+ /**
338
+ * Factory for the standard `-openclaw` plugin installer CLI.
339
+ *
340
+ * @remarks
341
+ * Produces a Commander program with `install` and `uninstall` commands
342
+ * that handle the full plugin lifecycle: copy dist to extensions,
343
+ * patch OpenClaw config, manage HEARTBEAT entries, and clean up
344
+ * managed sections on uninstall.
345
+ */
346
+
347
+ /** Options for creating a plugin installer CLI. */
348
+ interface CreatePluginCliOptions {
349
+ /** Plugin identifier (e.g., 'jeeves-watcher-openclaw'). */
350
+ pluginId: string;
351
+ /** Absolute path to the dist directory to copy. */
352
+ distDir: string;
353
+ /** npm package name for the plugin. */
354
+ pluginPackage: string;
355
+ /** Component name (e.g., 'watcher'). Derived from pluginId if omitted. */
356
+ componentName?: string;
357
+ /** Workspace root (defaults to OpenClaw workspace). */
358
+ workspace?: string;
359
+ /** Config root (defaults to 'j:/config'). */
360
+ configRoot?: string;
361
+ }
362
+ /**
363
+ * Create a standard plugin installer CLI program.
364
+ *
365
+ * @param options - Plugin CLI configuration.
366
+ * @returns A Commander program ready for `.parse()`.
367
+ */
368
+ declare function createPluginCli(options: CreatePluginCliOptions): Command;
369
+
370
+ /**
371
+ * Factory for the standard Jeeves service CLI.
372
+ *
373
+ * @remarks
374
+ * Produces a Commander program with all standard commands from
375
+ * a component descriptor. Components add domain-specific commands
376
+ * via `descriptor.customCliCommands`.
377
+ */
378
+
379
+ /**
380
+ * Create a standard service CLI program from a component descriptor.
381
+ *
382
+ * @remarks
383
+ * Standard commands:
384
+ * - `start -c <path>` - Launch the service process (foreground)
385
+ * - `status [-p port]` - Probe service health
386
+ * - `config [jsonpath] [-p port]` - Query running config
387
+ * - `config validate -c <path>` - Validate a config file
388
+ * - `config apply [-p port] [--file path] [--replace]` - Apply config patch
389
+ * - `init [-o path]` - Generate default config
390
+ * - `service install` - Install system service
391
+ * - `service uninstall` - Uninstall system service
392
+ * - `service start` - Start system service
393
+ * - `service stop` - Stop system service
394
+ * - `service restart` - Restart system service
395
+ * - `service status` - Query system service state
396
+ *
397
+ * @param descriptor - The component descriptor.
398
+ * @returns A Commander program ready for custom commands and `.parse()`.
399
+ */
400
+ declare function createServiceCli(descriptor: JeevesComponentDescriptor): Command;
401
+
40
402
  /**
41
403
  * Shared component version state file management.
42
404
  *
@@ -87,62 +449,18 @@ interface WriteComponentVersionOptions {
87
449
  * @param options - Component version data to write.
88
450
  */
89
451
  declare function writeComponentVersion(coreConfigDir: string, options: WriteComponentVersionOptions): void;
90
-
91
452
  /**
92
- * Component interface types for the Jeeves platform.
453
+ * Remove a component's version entry from the shared state file.
93
454
  *
94
455
  * @remarks
95
- * These types define the contract that component plugins must implement
96
- * to participate in the platform. The `JeevesComponent` interface is
97
- * the primary integration point.
98
- */
99
- /** Service health status. */
100
- interface ServiceStatus {
101
- /** Whether the service is running. */
102
- running: boolean;
103
- /** Optional version string. */
104
- version?: string;
105
- /** Optional uptime in seconds. */
106
- uptimeSeconds?: number;
107
- }
108
- /** Service lifecycle commands. */
109
- interface ServiceCommands {
110
- /** Stop the service. */
111
- stop(): Promise<void>;
112
- /** Uninstall the service. */
113
- uninstall(): Promise<void>;
114
- /** Query service status. */
115
- status(): Promise<ServiceStatus>;
116
- }
117
- /** Plugin lifecycle commands. */
118
- interface PluginCommands {
119
- /** Uninstall the plugin. */
120
- uninstall(): Promise<void>;
121
- }
122
- /**
123
- * Component descriptor — the contract that Jeeves component plugins
124
- * must implement to participate in the platform.
456
+ * Called during plugin uninstall to prevent the HEARTBEAT writer from
457
+ * probing a service that's intentionally gone. If the component isn't
458
+ * in the file, this is a no-op.
459
+ *
460
+ * @param coreConfigDir - Path to the core config directory.
461
+ * @param componentName - The component name to remove.
125
462
  */
126
- interface JeevesComponent {
127
- /** Component name (e.g., 'watcher', 'runner', 'server', 'meta'). */
128
- name: string;
129
- /** Component's own version (plugin package version). */
130
- version: string;
131
- /** npm package name for the service (e.g., `\@karmaniverous/jeeves-watcher`). */
132
- servicePackage?: string;
133
- /** npm package name for the plugin (e.g., `\@karmaniverous/jeeves-watcher-openclaw`). */
134
- pluginPackage?: string;
135
- /** TOOLS.md section name (e.g., 'Watcher'). */
136
- sectionId: string;
137
- /** Refresh interval in seconds (must be a prime number). */
138
- refreshIntervalSeconds: number;
139
- /** Produce the component's TOOLS.md section content. */
140
- generateToolsContent(): string;
141
- /** Service lifecycle commands. */
142
- serviceCommands: ServiceCommands;
143
- /** Plugin lifecycle commands. */
144
- pluginCommands: PluginCommands;
145
- }
463
+ declare function removeComponentVersion(coreConfigDir: string, componentName: string): void;
146
464
 
147
465
  /**
148
466
  * Timer-based orchestrator for managed content writing.
@@ -166,7 +484,7 @@ declare class ComponentWriter {
166
484
  private readonly component;
167
485
  private readonly configDir;
168
486
  /** @internal */
169
- constructor(component: JeevesComponent);
487
+ constructor(component: JeevesComponentDescriptor);
170
488
  /** The component's config directory path. */
171
489
  get componentConfigDir(): string;
172
490
  /** Whether the writer timer is currently running. */
@@ -195,7 +513,7 @@ declare class ComponentWriter {
195
513
  * Creates a synchronous content accessor backed by an async data source.
196
514
  *
197
515
  * @remarks
198
- * Solves the sync/async gap in `JeevesComponent.generateToolsContent()`:
516
+ * Solves the sync/async gap in `JeevesComponentDescriptor.generateToolsContent()`:
199
517
  * the interface is synchronous, but most components fetch live data from
200
518
  * their HTTP service. This utility returns a sync `() => string` that
201
519
  * serves the last successfully fetched value while kicking off a background
@@ -249,24 +567,136 @@ interface AsyncContentCacheOptions {
249
567
  declare function createAsyncContentCache(options: AsyncContentCacheOptions): () => string;
250
568
 
251
569
  /**
252
- * Factory function for creating a ComponentWriter.
570
+ * Factory function for creating a ComponentWriter from a descriptor.
253
571
  *
254
572
  * @remarks
255
- * Validates the component descriptor at runtime:
256
- * - `refreshIntervalSeconds` must be a prime number
257
- * - `serviceCommands` and `pluginCommands` must be provided
258
- * - `name`, `version`, `sectionId` must be non-empty strings
259
- * - `generateToolsContent` must be a function
573
+ * Validates the descriptor via Zod schema and creates a ComponentWriter.
574
+ * Accepts `JeevesComponentDescriptor` (v0.5.0) only. The v0.4.0
575
+ * `JeevesComponent` interface is no longer accepted.
260
576
  */
261
577
 
262
578
  /**
263
579
  * Create a ComponentWriter for a validated component descriptor.
264
580
  *
265
- * @param component - The component descriptor to validate and wrap.
581
+ * @remarks
582
+ * The descriptor is validated via the Zod schema at runtime.
583
+ * This replaces the v0.4.0 `createComponentWriter(JeevesComponent)`.
584
+ *
585
+ * @param descriptor - The component descriptor to validate and wrap.
266
586
  * @returns A new `ComponentWriter` instance.
267
- * @throws Error if the component descriptor is invalid.
587
+ * @throws ZodError if the descriptor is invalid.
588
+ */
589
+ declare function createComponentWriter(descriptor: JeevesComponentDescriptor): ComponentWriter;
590
+
591
+ /**
592
+ * Heading-based HEARTBEAT section writer.
593
+ *
594
+ * @remarks
595
+ * Manages the `# Jeeves Platform Status` section in HEARTBEAT.md.
596
+ * Unlike TOOLS/SOUL/AGENTS (which use HTML comment markers), HEARTBEAT
597
+ * uses markdown headings as markers — this ensures the file passes
598
+ * OpenClaw's heartbeat emptiness check when only headings remain.
599
+ *
600
+ * The section is always at the bottom of the file (H1 to EOF).
601
+ * User heartbeat items above the section are preserved.
602
+ */
603
+ /** The H1 heading that anchors the platform status section. */
604
+ declare const HEARTBEAT_HEADING = "# Jeeves Platform Status";
605
+ /** A single component entry in the HEARTBEAT section. */
606
+ interface HeartbeatEntry {
607
+ /** Component name (e.g., 'runner', 'watcher'). */
608
+ name: string;
609
+ /** Whether the component is declined. */
610
+ declined: boolean;
611
+ /** Alert content (list items). Empty string if healthy or declined. */
612
+ content: string;
613
+ }
614
+ /** Result of parsing the HEARTBEAT section. */
615
+ interface ParsedHeartbeat {
616
+ /** Content above the `# Jeeves Platform Status` heading (user zone). */
617
+ userContent: string;
618
+ /** Whether the heading was found. */
619
+ found: boolean;
620
+ /** Parsed component entries. */
621
+ entries: HeartbeatEntry[];
622
+ }
623
+ /**
624
+ * Parse the HEARTBEAT.md file content.
625
+ *
626
+ * @param fileContent - Full file content.
627
+ * @returns Parsed result with user zone and component entries.
628
+ */
629
+ declare function parseHeartbeat(fileContent: string): ParsedHeartbeat;
630
+ /**
631
+ * Build the HEARTBEAT section content from entries.
632
+ *
633
+ * @param entries - Component entries to write.
634
+ * @returns The full section string (H1 + H2s).
635
+ */
636
+ declare function buildHeartbeatSection(entries: HeartbeatEntry[]): string;
637
+ /**
638
+ * Write the HEARTBEAT section to a file.
639
+ *
640
+ * @remarks
641
+ * Replaces everything from `# Jeeves Platform Status` to EOF.
642
+ * Preserves user content above the heading. Uses file-level locking.
643
+ *
644
+ * @param filePath - Absolute path to HEARTBEAT.md.
645
+ * @param entries - Component entries to write.
646
+ */
647
+ declare function writeHeartbeatSection(filePath: string, entries: HeartbeatEntry[]): Promise<void>;
648
+
649
+ /**
650
+ * HEARTBEAT health orchestration.
651
+ *
652
+ * @remarks
653
+ * Determines the state of each platform component and generates
654
+ * HEARTBEAT entries with actionable alert text. Applies the dependency
655
+ * graph for alert suppression and auto-decline.
656
+ */
657
+
658
+ /** Component state as determined by the orchestrator. */
659
+ type ComponentState = 'not_installed' | 'deps_missing' | 'config_missing' | 'service_not_installed' | 'service_stopped' | 'healthy' | 'update_available';
660
+ /** Options for the orchestrator. */
661
+ interface OrchestrateHeartbeatOptions {
662
+ /** Path to the core config directory. */
663
+ coreConfigDir: string;
664
+ /** Path to the config root. */
665
+ configRoot: string;
666
+ /** Existing declined component names (from parsing current HEARTBEAT). */
667
+ declinedNames: Set<string>;
668
+ }
669
+ /**
670
+ * Orchestrate HEARTBEAT entries for all platform components.
671
+ *
672
+ * @param options - Orchestration configuration.
673
+ * @returns Array of HeartbeatEntry for writeHeartbeatSection.
268
674
  */
269
- declare function createComponentWriter(component: JeevesComponent): ComponentWriter;
675
+ declare function orchestrateHeartbeat(options: OrchestrateHeartbeatOptions): Promise<HeartbeatEntry[]>;
676
+
677
+ /**
678
+ * Component interface types for the Jeeves platform.
679
+ *
680
+ * @remarks
681
+ * These types support the platform's HEARTBEAT orchestration and
682
+ * dependency graph resolution.
683
+ */
684
+ /** Component dependency declarations. */
685
+ interface ComponentDependencies {
686
+ /**
687
+ * Hard dependencies — the component cannot function without these.
688
+ * If a hard dep is not healthy, suppress all alerts for this component
689
+ * except a "waiting for dependency" message. If a hard dep is declined,
690
+ * auto-decline this component.
691
+ */
692
+ hard: string[];
693
+ /**
694
+ * Soft dependencies — the component works without these but with reduced
695
+ * functionality. When the component is healthy and a soft dep is missing,
696
+ * generate an informational alert. No alert when a soft dep is declined.
697
+ */
698
+ soft: string[];
699
+ }
270
700
 
271
701
  /**
272
702
  * Comment markers for managed content blocks.
@@ -285,6 +715,14 @@ interface ManagedMarkers {
285
715
  end: string;
286
716
  /** Optional H1 title prepended inside the managed block. */
287
717
  title?: string;
718
+ /**
719
+ * Position of the managed block within the file.
720
+ * - `'top'`: managed block first, user content below (current default).
721
+ * - `'bottom'`: user content first, managed block at end.
722
+ *
723
+ * @defaultValue `'top'`
724
+ */
725
+ position?: 'top' | 'bottom';
288
726
  }
289
727
  /** Default markers for TOOLS.md managed block. */
290
728
  declare const TOOLS_MARKERS: ManagedMarkers;
@@ -320,6 +758,8 @@ declare const WORKSPACE_FILES: {
320
758
  readonly soul: "SOUL.md";
321
759
  /** AGENTS.md — operational protocols and memory architecture. */
322
760
  readonly agents: "AGENTS.md";
761
+ /** HEARTBEAT.md — platform status and health alerts. */
762
+ readonly heartbeat: "HEARTBEAT.md";
323
763
  };
324
764
  /** Templates directory name within core config. */
325
765
  declare const TEMPLATES_DIR = "templates";
@@ -352,7 +792,7 @@ declare const META_PORT = 1938;
352
792
  declare const DEFAULT_PORTS: Record<string, number>;
353
793
 
354
794
  /**
355
- * Managed section IDs and their stable ordering for TOOLS.md.
795
+ * Managed section IDs, stable ordering, and platform component registry.
356
796
  *
357
797
  * @remarks
358
798
  * Section ordering is fixed to prevent diff churn regardless of which
@@ -378,6 +818,19 @@ type SectionId = (typeof SECTION_IDS)[keyof typeof SECTION_IDS];
378
818
  * Sections always appear in this order regardless of write order.
379
819
  */
380
820
  declare const SECTION_ORDER: readonly string[];
821
+ /**
822
+ * The four essential platform components.
823
+ *
824
+ * @remarks
825
+ * These components constitute the Jeeves platform. `jeeves install` writes
826
+ * initial HEARTBEAT "Not installed" alerts for all of them. The HEARTBEAT
827
+ * writer generates "Not installed" alerts only for platform components not
828
+ * in `component-versions.json`. Optional future components (not in this list)
829
+ * appear in HEARTBEAT only after explicit install.
830
+ */
831
+ declare const PLATFORM_COMPONENTS: readonly ["runner", "watcher", "server", "meta"];
832
+ /** A platform component name. */
833
+ type PlatformComponent = (typeof PLATFORM_COMPONENTS)[number];
381
834
 
382
835
  /**
383
836
  * Core library version, inlined at build time.
@@ -403,12 +856,19 @@ declare const CORE_VERSION: string;
403
856
  * 3. Hardcoded library defaults
404
857
  */
405
858
 
859
+ /** Default bind address for all Jeeves services. */
860
+ declare const DEFAULT_BIND_ADDRESS = "0.0.0.0";
406
861
  /** Zod schema for the core config file. */
407
862
  declare const coreConfigSchema: z.ZodObject<{
408
863
  /** JSON Schema pointer for IDE autocomplete. */
409
864
  $schema: z.ZodOptional<z.ZodString>;
410
865
  /** Owner identity keys (canonical identityLinks references). */
411
866
  owners: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
867
+ /**
868
+ * Bind address for all Jeeves services. Default: `0.0.0.0` (all interfaces).
869
+ * Individual components can override in their own config.
870
+ */
871
+ bindAddress: z.ZodDefault<z.ZodString>;
412
872
  /** Service URL overrides keyed by service name. */
413
873
  services: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
414
874
  /** Service URL (must be a valid URL). */
@@ -429,6 +889,7 @@ declare const coreConfigSchema: z.ZodObject<{
429
889
  }>>;
430
890
  }, "strip", z.ZodTypeAny, {
431
891
  owners: string[];
892
+ bindAddress: string;
432
893
  services: Record<string, {
433
894
  url: string;
434
895
  }>;
@@ -439,6 +900,7 @@ declare const coreConfigSchema: z.ZodObject<{
439
900
  }, {
440
901
  $schema?: string | undefined;
441
902
  owners?: string[] | undefined;
903
+ bindAddress?: string | undefined;
442
904
  services?: Record<string, {
443
905
  url: string;
444
906
  }> | undefined;
@@ -455,6 +917,41 @@ type CoreConfig = z.infer<typeof coreConfigSchema>;
455
917
  */
456
918
  declare function generateJsonSchema(): Record<string, unknown>;
457
919
 
920
+ /**
921
+ * Resolve the bind address for a Jeeves service.
922
+ *
923
+ * @remarks
924
+ * Resolution order (four-tier):
925
+ * 1. Component config `bindAddress` field (if componentName provided)
926
+ * 2. Core config `bindAddress` field
927
+ * 3. `JEEVES_BIND_ADDRESS` environment variable
928
+ * 4. Default: `0.0.0.0`
929
+ */
930
+ /**
931
+ * Resolve the bind address for a Jeeves service.
932
+ *
933
+ * @param componentName - Optional component name for component-specific override.
934
+ * @returns The resolved bind address.
935
+ */
936
+ declare function getBindAddress(componentName?: string): string;
937
+
938
+ /**
939
+ * Platform-aware service state detection.
940
+ *
941
+ * @remarks
942
+ * Detects whether a system service is installed and running.
943
+ * Delegates to NSSM (Windows), systemd (Linux), or launchd (macOS).
944
+ */
945
+ /** Service states returned by getServiceState. */
946
+ type ServiceState = 'not_installed' | 'stopped' | 'running';
947
+ /**
948
+ * Detect the state of a system service by name.
949
+ *
950
+ * @param serviceName - The service name (e.g., 'jeeves-runner').
951
+ * @returns The detected service state.
952
+ */
953
+ declare function getServiceState(serviceName: string): ServiceState;
954
+
458
955
  /**
459
956
  * Service URL resolution.
460
957
  *
@@ -813,12 +1310,34 @@ interface SeedContentOptions {
813
1310
  * @remarks
814
1311
  * Uses the same `updateManagedSection()` code path as writer cycles.
815
1312
  * Creates core config with defaults if missing. Copies templates.
1313
+ * Writes initial HEARTBEAT with "Not installed" alerts for all platform components.
816
1314
  * Jaccard cleanup detection runs automatically via `updateManagedSection`.
817
1315
  *
818
1316
  * @param options - Seeding configuration.
819
1317
  */
820
1318
  declare function seedContent(options: SeedContentOptions): Promise<void>;
821
1319
 
1320
+ /**
1321
+ * Factory for the standard plugin tool set.
1322
+ *
1323
+ * @remarks
1324
+ * Produces four standard tools from a component descriptor:
1325
+ * - `{name}_status` - Probe service health + version + uptime
1326
+ * - `{name}_config` - Query running config with optional JSONPath
1327
+ * - `{name}_config_apply` - Push config patch to running service
1328
+ * - `{name}_service` - Service lifecycle management
1329
+ *
1330
+ * Components add domain-specific tools separately.
1331
+ */
1332
+
1333
+ /**
1334
+ * Create the standard plugin tool set from a component descriptor.
1335
+ *
1336
+ * @param descriptor - The component descriptor.
1337
+ * @returns Array of tool descriptors to register.
1338
+ */
1339
+ declare function createPluginToolset(descriptor: JeevesComponentDescriptor): ToolDescriptor[];
1340
+
822
1341
  /**
823
1342
  * HTTP helpers for the OpenClaw plugin SDK.
824
1343
  *
@@ -898,86 +1417,6 @@ declare function resolveConfigPath(home: string): string;
898
1417
  */
899
1418
  declare function patchConfig(config: Record<string, unknown>, pluginId: string, mode: 'add' | 'remove'): string[];
900
1419
 
901
- /**
902
- * Core types for the OpenClaw plugin SDK.
903
- *
904
- * @remarks
905
- * These types define the contract between plugins and the OpenClaw gateway.
906
- * They unify the various `PluginApi` definitions previously duplicated
907
- * across component plugins into a single canonical source.
908
- */
909
- /** Result shape returned by tool executions. */
910
- interface ToolResult {
911
- /** Content blocks — typically a single text block. */
912
- content: Array<{
913
- /** MIME type identifier (e.g. `"text"`). */
914
- type: string;
915
- /** Text content of the block. */
916
- text: string;
917
- }>;
918
- /** Whether this result represents an error. */
919
- isError?: boolean;
920
- }
921
- /** Tool descriptor for registration with the OpenClaw gateway. */
922
- interface ToolDescriptor {
923
- /** Unique tool name. */
924
- name: string;
925
- /** Human-readable description. */
926
- description: string;
927
- /** JSON Schema for the tool's parameters. */
928
- parameters: Record<string, unknown>;
929
- /** Execute the tool with the given parameters. */
930
- execute: (id: string, params: Record<string, unknown>) => Promise<ToolResult>;
931
- }
932
- /** Options for tool registration. */
933
- interface ToolRegistrationOptions {
934
- /** Whether the tool is optional (non-fatal if registration fails). */
935
- optional?: boolean;
936
- }
937
- /**
938
- * Canonical OpenClaw plugin API interface.
939
- *
940
- * @remarks
941
- * This is the shape of the `api` object passed to plugins by the
942
- * OpenClaw gateway at registration time. Fields are optional where
943
- * the gateway may not provide them in all versions.
944
- */
945
- interface PluginApi {
946
- /** OpenClaw configuration object. */
947
- config?: {
948
- /** Agent configuration block. */
949
- agents?: {
950
- /** Default agent settings. */
951
- defaults?: {
952
- /** Absolute path to the workspace root directory. */
953
- workspace?: string;
954
- };
955
- };
956
- /** Installed plugin configuration. */
957
- plugins?: {
958
- /** Plugin entries keyed by plugin ID. */
959
- entries?: Record<string, {
960
- /** Plugin-specific configuration key-value pairs. */
961
- config?: Record<string, unknown>;
962
- }>;
963
- };
964
- };
965
- /**
966
- * Resolve a path relative to the OpenClaw workspace.
967
- *
968
- * @remarks
969
- * Present on newer OpenClaw builds; optional for backwards compatibility.
970
- */
971
- resolvePath?: (input: string) => string;
972
- /**
973
- * Register a tool with the OpenClaw gateway.
974
- *
975
- * @param tool - Tool descriptor.
976
- * @param options - Registration options.
977
- */
978
- registerTool(tool: ToolDescriptor, options?: ToolRegistrationOptions): void;
979
- }
980
-
981
1420
  /**
982
1421
  * Plugin resolution helpers for the OpenClaw plugin SDK.
983
1422
  *
@@ -1063,5 +1502,48 @@ declare function fail(error: unknown): ToolResult;
1063
1502
  */
1064
1503
  declare function connectionFail(error: unknown, baseUrl: string, pluginId: string): ToolResult;
1065
1504
 
1066
- export { AGENTS_MARKERS, CLEANUP_FLAG, COMPONENT_CONFIG_PREFIX, COMPONENT_VERSIONS_FILE, CONFIG_FILE, CORE_CONFIG_DIR, CORE_VERSION, ComponentWriter, DEFAULT_CORE_VERSION, DEFAULT_PORTS, META_PORT, REGISTRY_CACHE_FILE, RUNNER_PORT, SECTION_IDS, SECTION_ORDER, SERVER_PORT, SOUL_MARKERS, STALENESS_THRESHOLD_MS, STALE_LOCK_MS, TEMPLATES_DIR, TOOLS_MARKERS, VERSION_STAMP_PATTERN, WATCHER_PORT, WORKSPACE_FILES, atomicWrite, checkRegistryVersion, connectionFail, coreConfigSchema, createAsyncContentCache, createComponentWriter, createConfigQueryHandler, fail, fetchJson, fetchWithTimeout, formatBeginMarker, formatEndMarker, generateJsonSchema, getComponentConfigDir, getConfigRoot, getCoreConfigDir, getCoreConfigFile, getServiceUrl, getWorkspacePath, init, jaccard, needsCleanup, ok, parseManaged, patchConfig, postJson, readComponentVersions, refreshPlatformContent, removeManagedSection, resetInit, resolveConfigPath, resolveOpenClawHome, resolveOptionalPluginSetting, resolvePluginSetting, resolveWorkspacePath, seedContent, shingles, shouldWrite, updateManagedSection, withFileLock, writeComponentVersion };
1067
- export type { AsyncContentCacheOptions, ComponentVersionEntry, ComponentVersionsState, ConfigQueryHandler, ConfigQueryResponse, CoreConfig, InitOptions, JeevesComponent, ManagedMarkers, ManagedSection, ParseManagedResult, PluginApi, PluginCommands, RefreshPlatformContentOptions, RemoveManagedSectionOptions, SectionId, SeedContentOptions, ServiceCommands, ServiceStatus, ToolDescriptor, ToolRegistrationOptions, ToolResult, UpdateManagedSectionOptions, VersionStamp, WriteComponentVersionOptions };
1505
+ /**
1506
+ * Factory for platform-aware service lifecycle management.
1507
+ *
1508
+ * @remarks
1509
+ * Produces a `ServiceManager` that handles install, uninstall, start,
1510
+ * stop, restart, and status for system services. Delegates to NSSM
1511
+ * (Windows), systemd (Linux), or launchd (macOS) based on platform.
1512
+ */
1513
+
1514
+ /** Options for service manager commands that accept a service name override. */
1515
+ interface ServiceManagerOptions {
1516
+ /** Override the default service name. */
1517
+ name?: string;
1518
+ /** Override config path for install. */
1519
+ configPath?: string;
1520
+ }
1521
+ /** Service lifecycle manager produced by the factory. */
1522
+ interface ServiceManager {
1523
+ /** Install the service with the system service manager. */
1524
+ install(options?: ServiceManagerOptions): void;
1525
+ /** Uninstall the service from the system service manager. */
1526
+ uninstall(options?: ServiceManagerOptions): void;
1527
+ /** Start the service. */
1528
+ start(options?: ServiceManagerOptions): void;
1529
+ /** Stop the service. */
1530
+ stop(options?: ServiceManagerOptions): void;
1531
+ /** Restart the service (stop + start). */
1532
+ restart(options?: ServiceManagerOptions): void;
1533
+ /** Query the service state. */
1534
+ status(options?: ServiceManagerOptions): ServiceState;
1535
+ }
1536
+ /**
1537
+ * Create a platform-aware service manager from a component descriptor.
1538
+ *
1539
+ * @remarks
1540
+ * Detects the current platform and returns a `ServiceManager` that
1541
+ * delegates to NSSM (Windows), systemd (Linux), or launchd (macOS).
1542
+ *
1543
+ * @param descriptor - The component descriptor.
1544
+ * @returns A `ServiceManager` for the current platform.
1545
+ */
1546
+ declare function createServiceManager(descriptor: JeevesComponentDescriptor): ServiceManager;
1547
+
1548
+ 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, META_PORT, PLATFORM_COMPONENTS, REGISTRY_CACHE_FILE, RUNNER_PORT, SECTION_IDS, SECTION_ORDER, SERVER_PORT, SOUL_MARKERS, STALENESS_THRESHOLD_MS, STALE_LOCK_MS, TEMPLATES_DIR, TOOLS_MARKERS, VERSION_STAMP_PATTERN, WATCHER_PORT, WORKSPACE_FILES, atomicWrite, buildHeartbeatSection, checkRegistryVersion, connectionFail, coreConfigSchema, createAsyncContentCache, createComponentWriter, createConfigApplyHandler, createConfigQueryHandler, createPluginCli, createPluginToolset, createServiceCli, createServiceManager, createStatusHandler, fail, fetchJson, fetchWithTimeout, formatBeginMarker, formatEndMarker, generateJsonSchema, getBindAddress, getComponentConfigDir, getConfigRoot, getCoreConfigDir, getCoreConfigFile, getEffectiveServiceName, getServiceState, getServiceUrl, getWorkspacePath, init, isPrime, jaccard, jeevesComponentDescriptorSchema, needsCleanup, ok, orchestrateHeartbeat, parseHeartbeat, parseManaged, patchConfig, postJson, readComponentVersions, refreshPlatformContent, removeComponentVersion, removeManagedSection, resetInit, resolveConfigPath, resolveOpenClawHome, resolveOptionalPluginSetting, resolvePluginSetting, resolveWorkspacePath, seedContent, shingles, shouldWrite, updateManagedSection, withFileLock, writeComponentVersion, writeHeartbeatSection };
1549
+ export type { AsyncContentCacheOptions, ComponentDependencies, ComponentState, ComponentVersionEntry, ComponentVersionsState, ConfigApplyHandler, ConfigApplyRequest, ConfigApplyResult, ConfigQueryHandler, ConfigQueryResponse, CoreConfig, CreatePluginCliOptions, CreateStatusHandlerOptions, HeartbeatEntry, InitOptions, JeevesComponentDescriptor, ManagedMarkers, ManagedSection, OrchestrateHeartbeatOptions, ParseManagedResult, ParsedHeartbeat, PlatformComponent, PluginApi, RefreshPlatformContentOptions, RemoveManagedSectionOptions, SectionId, SeedContentOptions, ServiceManager, ServiceManagerOptions, ServiceState, StatusHandler, StatusHandlerResult, StatusResponse, ToolDescriptor, ToolRegistrationOptions, ToolResult, UpdateManagedSectionOptions, VersionStamp, WriteComponentVersionOptions };