@karmaniverous/jeeves 0.5.0 → 0.5.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/content/skill.md CHANGED
@@ -97,3 +97,9 @@ MEMORY.md has a character budget (default 20,000). Core tracks:
97
97
  - Evergreen sections (no dates) are never flagged
98
98
 
99
99
  Review is human/agent-mediated — core does not auto-delete.
100
+
101
+ ### HEARTBEAT Integration
102
+
103
+ Memory hygiene is checked on every `ComponentWriter` cycle alongside component health. When budget or staleness thresholds are breached, a `## MEMORY.md` alert appears in HEARTBEAT.md under `# Jeeves Platform Status`. The alert includes character count, budget usage percentage, and any stale section names. When memory is healthy, the heading is absent — no alert content, no LLM cost on heartbeat polls.
104
+
105
+ The `## MEMORY.md` heading follows the same declined/active lifecycle as component headings (`## jeeves-{name}`). Users can decline memory alerts by changing the heading to `## MEMORY.md: declined`.
@@ -268,14 +268,14 @@ const PLATFORM_COMPONENTS = [
268
268
  * Core library version, inlined at build time.
269
269
  *
270
270
  * @remarks
271
- * The `0.4.7` placeholder is replaced by
271
+ * The `0.5.0` placeholder is replaced by
272
272
  * `@rollup/plugin-replace` during the build with the actual version
273
273
  * from `package.json`. This ensures the correct version survives
274
274
  * when consumers bundle core into their own dist (where runtime
275
275
  * `import.meta.url`-based resolution would find the wrong package.json).
276
276
  */
277
277
  /** The core library version from package.json (inlined at build time). */
278
- const CORE_VERSION = '0.4.7';
278
+ const CORE_VERSION = '0.5.0';
279
279
 
280
280
  /**
281
281
  * Runtime Node.js version floor check.
@@ -1007,7 +1007,7 @@ function parseHeartbeat(fileContent) {
1007
1007
  const userContent = fileContent.slice(0, headingIndex).trim();
1008
1008
  const sectionContent = fileContent.slice(headingIndex + HEARTBEAT_HEADING.length);
1009
1009
  const entries = [];
1010
- const h2Re = /^## (jeeves-\S+?)(?:: declined)?$/gm;
1010
+ const h2Re = /^## (jeeves-\S+?|MEMORY\.md)(?:: declined)?$/gm;
1011
1011
  let match;
1012
1012
  const h2Positions = [];
1013
1013
  while ((match = h2Re.exec(sectionContent)) !== null) {
@@ -2109,6 +2109,12 @@ MEMORY.md has a character budget (default 20,000). Core tracks:
2109
2109
  - Evergreen sections (no dates) are never flagged
2110
2110
 
2111
2111
  Review is human/agent-mediated — core does not auto-delete.
2112
+
2113
+ ### HEARTBEAT Integration
2114
+
2115
+ Memory hygiene is checked on every \`ComponentWriter\` cycle alongside component health. When budget or staleness thresholds are breached, a \`## MEMORY.md\` alert appears in HEARTBEAT.md under \`# Jeeves Platform Status\`. The alert includes character count, budget usage percentage, and any stale section names. When memory is healthy, the heading is absent — no alert content, no LLM cost on heartbeat polls.
2116
+
2117
+ The \`## MEMORY.md\` heading follows the same declined/active lifecycle as component headings (\`## jeeves-{name}\`). Users can decline memory alerts by changing the heading to \`## MEMORY.md: declined\`.
2112
2118
  `;
2113
2119
 
2114
2120
  /**
@@ -126,14 +126,14 @@ const COMPONENT_VERSIONS_FILE = 'component-versions.json';
126
126
  * Core library version, inlined at build time.
127
127
  *
128
128
  * @remarks
129
- * The `0.4.7` placeholder is replaced by
129
+ * The `0.5.0` placeholder is replaced by
130
130
  * `@rollup/plugin-replace` during the build with the actual version
131
131
  * from `package.json`. This ensures the correct version survives
132
132
  * when consumers bundle core into their own dist (where runtime
133
133
  * `import.meta.url`-based resolution would find the wrong package.json).
134
134
  */
135
135
  /** The core library version from package.json (inlined at build time). */
136
- const CORE_VERSION = '0.4.7';
136
+ const CORE_VERSION = '0.5.0';
137
137
 
138
138
  /**
139
139
  * Shared file I/O helpers for managed section operations.
@@ -402,7 +402,7 @@ function parseHeartbeat(fileContent) {
402
402
  const userContent = fileContent.slice(0, headingIndex).trim();
403
403
  const sectionContent = fileContent.slice(headingIndex + HEARTBEAT_HEADING.length);
404
404
  const entries = [];
405
- const h2Re = /^## (jeeves-\S+?)(?:: declined)?$/gm;
405
+ const h2Re = /^## (jeeves-\S+?|MEMORY\.md)(?:: declined)?$/gm;
406
406
  let match;
407
407
  const h2Positions = [];
408
408
  while ((match = h2Re.exec(sectionContent)) !== null) {
@@ -813,6 +813,12 @@ MEMORY.md has a character budget (default 20,000). Core tracks:
813
813
  - Evergreen sections (no dates) are never flagged
814
814
 
815
815
  Review is human/agent-mediated — core does not auto-delete.
816
+
817
+ ### HEARTBEAT Integration
818
+
819
+ Memory hygiene is checked on every \`ComponentWriter\` cycle alongside component health. When budget or staleness thresholds are breached, a \`## MEMORY.md\` alert appears in HEARTBEAT.md under \`# Jeeves Platform Status\`. The alert includes character count, budget usage percentage, and any stale section names. When memory is healthy, the heading is absent — no alert content, no LLM cost on heartbeat polls.
820
+
821
+ The \`## MEMORY.md\` heading follows the same declined/active lifecycle as component headings (\`## jeeves-{name}\`). Users can decline memory alerts by changing the heading to \`## MEMORY.md: declined\`.
816
822
  `;
817
823
 
818
824
  /**
package/dist/index.d.ts CHANGED
@@ -1355,6 +1355,28 @@ declare function extractMostRecentDate(text: string): Date | undefined;
1355
1355
  */
1356
1356
  declare function analyzeMemory(options: MemoryHygieneOptions): MemoryHygieneResult;
1357
1357
 
1358
+ /**
1359
+ * HEARTBEAT integration for memory hygiene.
1360
+ *
1361
+ * @remarks
1362
+ * Calls `analyzeMemory()` and converts the result into a `HeartbeatEntry`
1363
+ * suitable for inclusion in the HEARTBEAT.md platform status section.
1364
+ * Returns `undefined` when MEMORY.md is healthy (no alert needed).
1365
+ *
1366
+ * Uses the `## MEMORY.md` heading (Decision 50) to distinguish memory
1367
+ * alerts from component alerts (`## jeeves-{name}`).
1368
+ */
1369
+
1370
+ /** The HEARTBEAT heading name for memory alerts. */
1371
+ declare const MEMORY_HEARTBEAT_NAME = "MEMORY.md";
1372
+ /**
1373
+ * Check memory health and return a HEARTBEAT entry if unhealthy.
1374
+ *
1375
+ * @param options - Memory hygiene options (workspacePath, budget, etc.).
1376
+ * @returns A `HeartbeatEntry` when memory needs attention, `undefined` when healthy.
1377
+ */
1378
+ declare function checkMemoryHealth(options: MemoryHygieneOptions): HeartbeatEntry | undefined;
1379
+
1358
1380
  /**
1359
1381
  * Internal function to maintain SOUL.md, AGENTS.md, and TOOLS.md Platform section.
1360
1382
  *
@@ -1816,5 +1838,5 @@ interface ServiceManager {
1816
1838
  */
1817
1839
  declare function createServiceManager(descriptor: JeevesComponentDescriptor): ServiceManager;
1818
1840
 
1819
- 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, 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, 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 };
1841
+ 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 };
1820
1842
  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, RefreshPlatformContentOptions, RemoveManagedSectionOptions, ResolvedValue, RetryOptions, RunOptions, SectionId, SeedContentOptions, ServiceAccountFileConfig, ServiceManager, ServiceManagerOptions, ServiceState, SlackWorkspaceOptions, StatusHandler, StatusHandlerResult, StatusResponse, ToolDescriptor, ToolRegistrationOptions, ToolResult, UpdateManagedSectionOptions, VersionStamp, WorkspaceConfig, WriteComponentVersionOptions };
package/dist/index.js CHANGED
@@ -183,14 +183,14 @@ const PLATFORM_COMPONENTS = [
183
183
  * Core library version, inlined at build time.
184
184
  *
185
185
  * @remarks
186
- * The `0.4.7` placeholder is replaced by
186
+ * The `0.5.0` placeholder is replaced by
187
187
  * `@rollup/plugin-replace` during the build with the actual version
188
188
  * from `package.json`. This ensures the correct version survives
189
189
  * when consumers bundle core into their own dist (where runtime
190
190
  * `import.meta.url`-based resolution would find the wrong package.json).
191
191
  */
192
192
  /** The core library version from package.json (inlined at build time). */
193
- const CORE_VERSION = '0.4.7';
193
+ const CORE_VERSION = '0.5.0';
194
194
 
195
195
  /**
196
196
  * Workspace and config root initialization.
@@ -1007,7 +1007,7 @@ function parseHeartbeat(fileContent) {
1007
1007
  const userContent = fileContent.slice(0, headingIndex).trim();
1008
1008
  const sectionContent = fileContent.slice(headingIndex + HEARTBEAT_HEADING.length);
1009
1009
  const entries = [];
1010
- const h2Re = /^## (jeeves-\S+?)(?:: declined)?$/gm;
1010
+ const h2Re = /^## (jeeves-\S+?|MEMORY\.md)(?:: declined)?$/gm;
1011
1011
  let match;
1012
1012
  const h2Positions = [];
1013
1013
  while ((match = h2Re.exec(sectionContent)) !== null) {
@@ -1477,6 +1477,12 @@ MEMORY.md has a character budget (default 20,000). Core tracks:
1477
1477
  - Evergreen sections (no dates) are never flagged
1478
1478
 
1479
1479
  Review is human/agent-mediated — core does not auto-delete.
1480
+
1481
+ ### HEARTBEAT Integration
1482
+
1483
+ Memory hygiene is checked on every \`ComponentWriter\` cycle alongside component health. When budget or staleness thresholds are breached, a \`## MEMORY.md\` alert appears in HEARTBEAT.md under \`# Jeeves Platform Status\`. The alert includes character count, budget usage percentage, and any stale section names. When memory is healthy, the heading is absent — no alert content, no LLM cost on heartbeat polls.
1484
+
1485
+ The \`## MEMORY.md\` heading follows the same declined/active lifecycle as component headings (\`## jeeves-{name}\`). Users can decline memory alerts by changing the heading to \`## MEMORY.md: declined\`.
1480
1486
  `;
1481
1487
 
1482
1488
  /**
@@ -3520,6 +3526,132 @@ function scanAndEscalateCleanup(targets, gatewayUrl, pendingCleanups) {
3520
3526
  }
3521
3527
  }
3522
3528
 
3529
+ /**
3530
+ * Memory budget accounting and staleness detection for MEMORY.md.
3531
+ *
3532
+ * @remarks
3533
+ * Scans MEMORY.md for ISO date patterns in H2/H3 headings and bullet items.
3534
+ * Reports character count against a configured budget, warning threshold state,
3535
+ * and stale section candidates. Does not auto-delete: review remains
3536
+ * human- or agent-mediated (Decision 42).
3537
+ */
3538
+ /** ISO date pattern: YYYY-MM-DD. */
3539
+ const ISO_DATE_RE = /\b(\d{4}-\d{2}-\d{2})\b/g;
3540
+ /** H2 heading pattern used to split sections. */
3541
+ const H2_RE = /^## /m;
3542
+ /**
3543
+ * Extract the most recent ISO date from a string.
3544
+ *
3545
+ * @param text - Text to scan for dates.
3546
+ * @returns The most recent date found, or undefined.
3547
+ */
3548
+ function extractMostRecentDate(text) {
3549
+ const matches = text.match(ISO_DATE_RE);
3550
+ if (!matches)
3551
+ return undefined;
3552
+ let latest;
3553
+ for (const match of matches) {
3554
+ const d = new Date(match + 'T00:00:00Z');
3555
+ if (!Number.isNaN(d.getTime())) {
3556
+ if (!latest || d > latest)
3557
+ latest = d;
3558
+ }
3559
+ }
3560
+ return latest;
3561
+ }
3562
+ /**
3563
+ * Analyze MEMORY.md for budget and staleness.
3564
+ *
3565
+ * @param options - Analysis configuration.
3566
+ * @returns Memory hygiene result.
3567
+ */
3568
+ function analyzeMemory(options) {
3569
+ const { workspacePath, budget, warningThreshold, staleDays } = options;
3570
+ const memoryPath = join(workspacePath, WORKSPACE_FILES.memory);
3571
+ if (!existsSync(memoryPath)) {
3572
+ return {
3573
+ exists: false,
3574
+ charCount: 0,
3575
+ budget,
3576
+ usage: 0,
3577
+ warning: false,
3578
+ overBudget: false,
3579
+ staleCandidates: 0,
3580
+ staleSectionNames: [],
3581
+ };
3582
+ }
3583
+ const content = readFileSync(memoryPath, 'utf-8');
3584
+ const charCount = content.length;
3585
+ const usage = budget > 0 ? charCount / budget : charCount > 0 ? Infinity : 0;
3586
+ const warning = usage >= warningThreshold;
3587
+ const overBudget = usage > 1;
3588
+ // Split into H2 sections and scan for staleness
3589
+ const sections = content.split(H2_RE).slice(1); // skip content before first H2
3590
+ const now = Date.now();
3591
+ const thresholdMs = staleDays * 24 * 60 * 60 * 1000;
3592
+ const staleSectionNames = [];
3593
+ for (const section of sections) {
3594
+ const sectionName = section.split('\n')[0]?.trim() ?? '';
3595
+ const recentDate = extractMostRecentDate(section);
3596
+ // Sections without dates are evergreen — never flagged (Decision 47)
3597
+ if (!recentDate)
3598
+ continue;
3599
+ if (now - recentDate.getTime() > thresholdMs) {
3600
+ staleSectionNames.push(sectionName);
3601
+ }
3602
+ }
3603
+ return {
3604
+ exists: true,
3605
+ charCount,
3606
+ budget,
3607
+ usage,
3608
+ warning,
3609
+ overBudget,
3610
+ staleCandidates: staleSectionNames.length,
3611
+ staleSectionNames,
3612
+ };
3613
+ }
3614
+
3615
+ /**
3616
+ * HEARTBEAT integration for memory hygiene.
3617
+ *
3618
+ * @remarks
3619
+ * Calls `analyzeMemory()` and converts the result into a `HeartbeatEntry`
3620
+ * suitable for inclusion in the HEARTBEAT.md platform status section.
3621
+ * Returns `undefined` when MEMORY.md is healthy (no alert needed).
3622
+ *
3623
+ * Uses the `## MEMORY.md` heading (Decision 50) to distinguish memory
3624
+ * alerts from component alerts (`## jeeves-{name}`).
3625
+ */
3626
+ /** The HEARTBEAT heading name for memory alerts. */
3627
+ const MEMORY_HEARTBEAT_NAME = 'MEMORY.md';
3628
+ /**
3629
+ * Check memory health and return a HEARTBEAT entry if unhealthy.
3630
+ *
3631
+ * @param options - Memory hygiene options (workspacePath, budget, etc.).
3632
+ * @returns A `HeartbeatEntry` when memory needs attention, `undefined` when healthy.
3633
+ */
3634
+ function checkMemoryHealth(options) {
3635
+ const result = analyzeMemory(options);
3636
+ if (!result.exists)
3637
+ return undefined;
3638
+ if (!result.warning && result.staleCandidates === 0)
3639
+ return undefined;
3640
+ const lines = [];
3641
+ if (result.warning) {
3642
+ const pct = Math.round(result.usage * 100);
3643
+ lines.push(`- Budget: ${result.charCount.toLocaleString()} / ${result.budget.toLocaleString()} chars (${String(pct)}%).${result.overBudget ? ' **Over budget.**' : ' Consider reviewing.'}`);
3644
+ }
3645
+ if (result.staleCandidates > 0) {
3646
+ lines.push(`- ${String(result.staleCandidates)} stale section${result.staleCandidates === 1 ? '' : 's'}: ${result.staleSectionNames.join(', ')}`);
3647
+ }
3648
+ return {
3649
+ name: MEMORY_HEARTBEAT_NAME,
3650
+ declined: false,
3651
+ content: lines.join('\n'),
3652
+ };
3653
+ }
3654
+
3523
3655
  /**
3524
3656
  * Core configuration schema and resolution.
3525
3657
  *
@@ -4007,6 +4139,27 @@ async function runHeartbeatCycle(options) {
4007
4139
  configRoot,
4008
4140
  declinedNames,
4009
4141
  });
4142
+ // Memory hygiene check (Decision 49)
4143
+ if (!declinedNames.has(MEMORY_HEARTBEAT_NAME)) {
4144
+ const wsConfig = loadWorkspaceConfig(workspacePath);
4145
+ const memoryEntry = checkMemoryHealth({
4146
+ workspacePath,
4147
+ budget: wsConfig?.memory?.budget ?? WORKSPACE_CONFIG_DEFAULTS.memory.budget,
4148
+ warningThreshold: wsConfig?.memory?.warningThreshold ??
4149
+ WORKSPACE_CONFIG_DEFAULTS.memory.warningThreshold,
4150
+ staleDays: wsConfig?.memory?.staleDays ??
4151
+ WORKSPACE_CONFIG_DEFAULTS.memory.staleDays,
4152
+ });
4153
+ if (memoryEntry)
4154
+ entries.push(memoryEntry);
4155
+ }
4156
+ else {
4157
+ entries.push({
4158
+ name: MEMORY_HEARTBEAT_NAME,
4159
+ declined: true,
4160
+ content: '',
4161
+ });
4162
+ }
4010
4163
  await writeHeartbeatSection(heartbeatPath, entries);
4011
4164
  }
4012
4165
  catch (err) {
@@ -4242,92 +4395,6 @@ function getBindAddress(componentName) {
4242
4395
  return DEFAULT_BIND_ADDRESS;
4243
4396
  }
4244
4397
 
4245
- /**
4246
- * Memory budget accounting and staleness detection for MEMORY.md.
4247
- *
4248
- * @remarks
4249
- * Scans MEMORY.md for ISO date patterns in H2/H3 headings and bullet items.
4250
- * Reports character count against a configured budget, warning threshold state,
4251
- * and stale section candidates. Does not auto-delete: review remains
4252
- * human- or agent-mediated (Decision 42).
4253
- */
4254
- /** ISO date pattern: YYYY-MM-DD. */
4255
- const ISO_DATE_RE = /\b(\d{4}-\d{2}-\d{2})\b/g;
4256
- /** H2 heading pattern used to split sections. */
4257
- const H2_RE = /^## /m;
4258
- /**
4259
- * Extract the most recent ISO date from a string.
4260
- *
4261
- * @param text - Text to scan for dates.
4262
- * @returns The most recent date found, or undefined.
4263
- */
4264
- function extractMostRecentDate(text) {
4265
- const matches = text.match(ISO_DATE_RE);
4266
- if (!matches)
4267
- return undefined;
4268
- let latest;
4269
- for (const match of matches) {
4270
- const d = new Date(match + 'T00:00:00Z');
4271
- if (!Number.isNaN(d.getTime())) {
4272
- if (!latest || d > latest)
4273
- latest = d;
4274
- }
4275
- }
4276
- return latest;
4277
- }
4278
- /**
4279
- * Analyze MEMORY.md for budget and staleness.
4280
- *
4281
- * @param options - Analysis configuration.
4282
- * @returns Memory hygiene result.
4283
- */
4284
- function analyzeMemory(options) {
4285
- const { workspacePath, budget, warningThreshold, staleDays } = options;
4286
- const memoryPath = join(workspacePath, WORKSPACE_FILES.memory);
4287
- if (!existsSync(memoryPath)) {
4288
- return {
4289
- exists: false,
4290
- charCount: 0,
4291
- budget,
4292
- usage: 0,
4293
- warning: false,
4294
- overBudget: false,
4295
- staleCandidates: 0,
4296
- staleSectionNames: [],
4297
- };
4298
- }
4299
- const content = readFileSync(memoryPath, 'utf-8');
4300
- const charCount = content.length;
4301
- const usage = budget > 0 ? charCount / budget : charCount > 0 ? Infinity : 0;
4302
- const warning = usage >= warningThreshold;
4303
- const overBudget = usage > 1;
4304
- // Split into H2 sections and scan for staleness
4305
- const sections = content.split(H2_RE).slice(1); // skip content before first H2
4306
- const now = Date.now();
4307
- const thresholdMs = staleDays * 24 * 60 * 60 * 1000;
4308
- const staleSectionNames = [];
4309
- for (const section of sections) {
4310
- const sectionName = section.split('\n')[0]?.trim() ?? '';
4311
- const recentDate = extractMostRecentDate(section);
4312
- // Sections without dates are evergreen — never flagged (Decision 47)
4313
- if (!recentDate)
4314
- continue;
4315
- if (now - recentDate.getTime() > thresholdMs) {
4316
- staleSectionNames.push(sectionName);
4317
- }
4318
- }
4319
- return {
4320
- exists: true,
4321
- charCount,
4322
- budget,
4323
- usage,
4324
- warning,
4325
- overBudget,
4326
- staleCandidates: staleSectionNames.length,
4327
- staleSectionNames,
4328
- };
4329
- }
4330
-
4331
4398
  /**
4332
4399
  * One-shot content seeding used by the CLI install command.
4333
4400
  *
@@ -5091,4 +5158,4 @@ async function getChannelWorkspace(channelId, token, options) {
5091
5158
  return teamId;
5092
5159
  }
5093
5160
 
5094
- 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, 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, 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 };
5161
+ 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 };
package/package.json CHANGED
@@ -139,5 +139,5 @@
139
139
  },
140
140
  "type": "module",
141
141
  "types": "dist/index.d.ts",
142
- "version": "0.5.0"
142
+ "version": "0.5.1"
143
143
  }