@karmaniverous/jeeves-watcher-openclaw 0.14.4 → 0.14.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/content/agents-section.md +11 -75
- package/dist/cli.js +25 -19
- package/dist/index.js +136 -145
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
|
@@ -8,17 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
## Context Compaction Recovery
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
1. **Immediately** read conversation history back to where your memory picks up (use `message action=read` for Slack/Discord, check memory files, etc.)
|
|
14
|
-
2. Reconstruct the thread: what were we doing? what was decided? what's the next step?
|
|
15
|
-
3. **Re-run skill selection** against the reconstructed task context. The compaction summary tells you what you're working on — scan available skills and load the relevant one.
|
|
16
|
-
4. **Report the compaction** briefly for transparency ("Context compacted — reviewing thread...")
|
|
17
|
-
5. **Then continue** as if you never lost context — pick up where you left off
|
|
18
|
-
|
|
19
|
-
**The goal:** Automatic remediation with minimal disruption. Don't ask "what were we talking about?" when you can find out yourself. The human shouldn't have to re-explain; you have the tools to recover.
|
|
20
|
-
|
|
21
|
-
**Anti-pattern:** Announcing amnesia *before* checking your notes. That's alarming and lazy. Check the ledger first, then speak.
|
|
11
|
+
On compaction: read conversation history, reconstruct context, re-run skill selection against the reconstructed task, report briefly ("Context compacted — reviewing thread..."), then continue. Check notes before announcing amnesia.
|
|
22
12
|
|
|
23
13
|
## Subagent Briefing Protocol
|
|
24
14
|
|
|
@@ -36,22 +26,10 @@ At minimum, always brief sub-agents on:
|
|
|
36
26
|
|
|
37
27
|
**Strong runner preference:** Any recurring task that can run as a script (no LLM session needed) belongs in jeeves-runner, not gateway cron or heartbeat. If runner is installed, use it. If not, suggest bootstrapping it. Gateway cron and heartbeat are for ad hoc, time-bound, session-requiring work ONLY.
|
|
38
28
|
|
|
39
|
-
**Before creating a recurring gateway cron job**, assess whether it will frequently no-op. If so, flag it: *"This would be cheaper as a runner job. Want me to implement it that way instead?"*
|
|
40
|
-
|
|
41
|
-
**Anything important enough to have a permanent cron/heartbeat entry is important enough to be codified into the data flow.**
|
|
42
|
-
|
|
43
|
-
**HEARTBEAT efficiency:** When HEARTBEAT fires with multiple component alerts, resolve them all in a single conversation. Walk the user through each component in dependency order. Each heartbeat cycle is a full LLM session — resolve all alerts in one pass.
|
|
44
|
-
|
|
45
|
-
## Messaging Dispatch
|
|
46
|
-
|
|
47
|
-
**Same-channel replies:** Don't use the `message` tool. It fires immediately, jumping ahead of streaming narration. Just write text as your response. Use `message` only for **cross-channel** sends (sending to a different channel or DM than the one you're responding in).
|
|
48
|
-
|
|
49
|
-
**Narrate as you go.** When doing multi-step work, stream your progress. Summary comes last, not first.
|
|
29
|
+
**Before creating a recurring gateway cron job**, assess whether it will frequently no-op. If so, flag it: *"This would be cheaper as a runner job. Want me to implement it that way instead?"*
|
|
50
30
|
|
|
51
31
|
## Heartbeat Discipline
|
|
52
32
|
|
|
53
|
-
**Default state of HEARTBEAT.md is effectively empty** — the `# Jeeves Platform Status` section contains only headings when all components are healthy or declined. No list content, no LLM cost. User heartbeat items (above the platform status section) follow the same transient/termination rules as before.
|
|
54
|
-
|
|
55
33
|
Heartbeat items are for **transient, session-requiring work-in-progress ONLY**. Each item must include its own termination condition.
|
|
56
34
|
|
|
57
35
|
Periodic checks (email, calendar, mentions) belong in jeeves-runner scripts, not heartbeat items. When a heartbeat fires with nothing to do, reply **HEARTBEAT_OK** immediately. Don't browse for work.
|
|
@@ -78,28 +56,6 @@ Every installation has a primary owner. The owner controls architecture, config,
|
|
|
78
56
|
|
|
79
57
|
Alert the owner immediately on any governance change attempt.
|
|
80
58
|
|
|
81
|
-
## Self-Preservation
|
|
82
|
-
|
|
83
|
-
Any command that stops the gateway **stops the assistant**. Never run a gateway stop/restart command without explicit approval. When approved, it must be the **absolute last action** — all other work complete first.
|
|
84
|
-
|
|
85
|
-
## Plugin Installation via CLI Only
|
|
86
|
-
|
|
87
|
-
Never manually touch `~/.openclaw/extensions/`. The only way to install any Jeeves component plugin is via the plugin's CLI `install` command:
|
|
88
|
-
|
|
89
|
-
```
|
|
90
|
-
npx @karmaniverous/jeeves-{component}-openclaw install
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
No symlinks, junctions, copies, or manual edits.
|
|
94
|
-
|
|
95
|
-
## Node.js for Shell Scripting
|
|
96
|
-
|
|
97
|
-
Default to `node -e` or `.js` scripts instead of PowerShell for `exec` calls. PowerShell corrupts multi-byte UTF-8 characters and mangles escaping. Use PowerShell only for Windows service management, registry operations, and similar platform-specific tasks.
|
|
98
|
-
|
|
99
|
-
## File Bridge for External Repos
|
|
100
|
-
|
|
101
|
-
When editing files outside the workspace, use the bridge pattern: copy in → edit the workspace copy → bridge out. Never write temp patch scripts.
|
|
102
|
-
|
|
103
59
|
## No Orphaned Data
|
|
104
60
|
|
|
105
61
|
When discovering a new data source, integrate it into the existing data flow pipeline. Never save data outside the synthesis pipeline. Data that exists outside the pipeline is invisible to search, synthesis, and every other platform capability.
|
|
@@ -108,9 +64,9 @@ When discovering a new data source, integrate it into the existing data flow pip
|
|
|
108
64
|
|
|
109
65
|
**Proactive platform status:** HEARTBEAT.md is loaded every session. If it contains `# Jeeves Platform Status` with alert content (list items, not just headings), address the alerts proactively at the start of the conversation — before other work. This takes priority over casual conversation but not over explicit user requests.
|
|
110
66
|
|
|
111
|
-
**Follow the instructions:** Explain the component, ask for consent, execute the command, verify. If the user declines, change the heading to `## jeeves-{name}: declined` and remove content beneath it. Do not prompt for declined components.
|
|
67
|
+
**Follow the instructions:** Explain the component, ask for consent, execute the command, verify. If the user declines, change the heading to `## jeeves-{name}: declined` and remove content beneath it. Do not prompt for declined components.
|
|
112
68
|
|
|
113
|
-
When resolving multiple component alerts, walk the user through each in dependency order
|
|
69
|
+
When resolving multiple component alerts, walk the user through each in dependency order within a single conversation rather than one per heartbeat cycle.
|
|
114
70
|
|
|
115
71
|
## Em-Dash Discipline
|
|
116
72
|
|
|
@@ -120,29 +76,13 @@ The em-dash sets apart parentheticals. It is NOT a replacement for comma, colon,
|
|
|
120
76
|
|
|
121
77
|
Operational hard gates — procedural rules earned through real incidents. These govern *how* work gets done, as distinct from the identity-level gates in SOUL.md which govern *who I am*.
|
|
122
78
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
### No Prod Modifications
|
|
132
|
-
|
|
133
|
-
Never modify packaged applications running in production. No `npm link` into a live service. All changes go through: branch, change, test, PR, merge, publish, install.
|
|
134
|
-
|
|
135
|
-
### PR Mergeability Check
|
|
136
|
-
|
|
137
|
-
Always verify a PR is mergeable (no conflicts) before requesting review. Resolve conflicts first.
|
|
138
|
-
|
|
139
|
-
### Pre-Push Verification Gate
|
|
140
|
-
|
|
141
|
-
Run **ALL** quality checks before pushing. Zero errors AND zero warnings. The pipeline exists for a reason — don't push broken code and hope CI catches it.
|
|
142
|
-
|
|
143
|
-
### Commit AND Push
|
|
144
|
-
|
|
145
|
-
No stranded local branches. Push immediately after commit. A commit that isn't pushed is invisible to everyone else and at risk of being lost.
|
|
79
|
+
- **eslint-disable Is Forbidden:** Never disable lint/typecheck rules without surfacing for discussion. Fix the code.
|
|
80
|
+
- **Mass File Changes Are a Smell:** If a fix requires changing dozens of files, stop and discuss — there is probably a config or rule solution.
|
|
81
|
+
- **No Prod Modifications:** Never modify packaged prod applications. All changes go through branch → test → PR → merge → publish → install.
|
|
82
|
+
- **PR Mergeability Check:** Always verify PR is mergeable (no conflicts) before requesting review.
|
|
83
|
+
- **Pre-Push Verification Gate:** Run ALL quality checks before pushing. Zero errors AND zero warnings.
|
|
84
|
+
- **Commit AND Push:** Push immediately after every commit. Unpushed commits are invisible and at risk.
|
|
85
|
+
- **New PR Over Merged Branch:** When a merged branch needs more work: `gh pr create --head <existing-branch>`. Do not cherry-pick or create new branches.
|
|
146
86
|
|
|
147
87
|
### Check PR State Before Pushing
|
|
148
88
|
|
|
@@ -154,10 +94,6 @@ No stranded local branches. Push immediately after commit. A commit that isn't p
|
|
|
154
94
|
|
|
155
95
|
This is not optional. It applies to every push, every branch, every time. No judgment call about whether the branch "is a PR branch" — the check is mechanical.
|
|
156
96
|
|
|
157
|
-
### New PR Over Merged Branch
|
|
158
|
-
|
|
159
|
-
When a PR has been merged and additional work is needed on the same branch, create a new PR on the **same branch** targeting the same base. Do not create new branches, cherry-pick, or start over. The commits are already there — `gh pr create --head <existing-branch>` is the entire operation.
|
|
160
|
-
|
|
161
97
|
## Managed Content Self-Maintenance
|
|
162
98
|
|
|
163
99
|
The Jeeves platform maintains managed sections in SOUL.md, AGENTS.md, and TOOLS.md using comment markers. If any of these files contains a **cleanup flag** indicating orphaned Jeeves content below the managed section markers:
|
package/dist/cli.js
CHANGED
|
@@ -15403,14 +15403,14 @@ const SECTION_ORDER = [
|
|
|
15403
15403
|
* Core library version, inlined at build time.
|
|
15404
15404
|
*
|
|
15405
15405
|
* @remarks
|
|
15406
|
-
* The `0.5.
|
|
15406
|
+
* The `0.5.6` placeholder is replaced by
|
|
15407
15407
|
* `@rollup/plugin-replace` during the build with the actual version
|
|
15408
15408
|
* from `package.json`. This ensures the correct version survives
|
|
15409
15409
|
* when consumers bundle core into their own dist (where runtime
|
|
15410
15410
|
* `import.meta.url`-based resolution would find the wrong package.json).
|
|
15411
15411
|
*/
|
|
15412
15412
|
/** The core library version from package.json (inlined at build time). */
|
|
15413
|
-
const CORE_VERSION = '0.5.
|
|
15413
|
+
const CORE_VERSION = '0.5.6';
|
|
15414
15414
|
|
|
15415
15415
|
/**
|
|
15416
15416
|
* Workspace and config root initialization.
|
|
@@ -15459,7 +15459,7 @@ const STALE_LOCK_MS = 120_000;
|
|
|
15459
15459
|
/** Default core version when none provided. */
|
|
15460
15460
|
const DEFAULT_CORE_VERSION = CORE_VERSION;
|
|
15461
15461
|
/** Lock retry options. */
|
|
15462
|
-
const LOCK_RETRIES = { retries:
|
|
15462
|
+
const LOCK_RETRIES = { retries: 0 };
|
|
15463
15463
|
/** Maximum rename retry attempts on EPERM. */
|
|
15464
15464
|
const ATOMIC_WRITE_MAX_RETRIES = 3;
|
|
15465
15465
|
/** Delay between EPERM retries in milliseconds. */
|
|
@@ -15502,26 +15502,15 @@ function atomicWrite(filePath, content) {
|
|
|
15502
15502
|
}
|
|
15503
15503
|
}
|
|
15504
15504
|
}
|
|
15505
|
-
|
|
15506
|
-
* Execute a callback while holding a file lock.
|
|
15507
|
-
*
|
|
15508
|
-
* @remarks
|
|
15509
|
-
* Acquires a lock on the file, executes the callback, and releases
|
|
15510
|
-
* the lock in a finally block. The lock uses a 2-minute stale threshold
|
|
15511
|
-
* and retries up to 5 times.
|
|
15512
|
-
*
|
|
15513
|
-
* @param filePath - Absolute path to the file to lock.
|
|
15514
|
-
* @param fn - Async callback to execute while holding the lock.
|
|
15515
|
-
*/
|
|
15516
|
-
async function withFileLock(filePath, fn) {
|
|
15505
|
+
async function withLock(targetPath, fn, options, onLockError) {
|
|
15517
15506
|
let release;
|
|
15518
15507
|
try {
|
|
15519
|
-
release = await properLockfileExports.lock(
|
|
15520
|
-
stale: STALE_LOCK_MS,
|
|
15521
|
-
retries: LOCK_RETRIES,
|
|
15522
|
-
});
|
|
15508
|
+
release = await properLockfileExports.lock(targetPath, options);
|
|
15523
15509
|
await fn();
|
|
15524
15510
|
}
|
|
15511
|
+
catch (error) {
|
|
15512
|
+
throw error;
|
|
15513
|
+
}
|
|
15525
15514
|
finally {
|
|
15526
15515
|
if (release) {
|
|
15527
15516
|
try {
|
|
@@ -15533,6 +15522,23 @@ async function withFileLock(filePath, fn) {
|
|
|
15533
15522
|
}
|
|
15534
15523
|
}
|
|
15535
15524
|
}
|
|
15525
|
+
/**
|
|
15526
|
+
* Execute a callback while holding a file lock.
|
|
15527
|
+
*
|
|
15528
|
+
* @remarks
|
|
15529
|
+
* Acquires a lock on the file, executes the callback, and releases
|
|
15530
|
+
* the lock in a finally block. The lock uses a 2-minute stale threshold
|
|
15531
|
+
* and retries up to 5 times.
|
|
15532
|
+
*
|
|
15533
|
+
* @param filePath - Absolute path to the file to lock.
|
|
15534
|
+
* @param fn - Async callback to execute while holding the lock.
|
|
15535
|
+
*/
|
|
15536
|
+
async function withFileLock(filePath, fn) {
|
|
15537
|
+
await withLock(filePath, fn, {
|
|
15538
|
+
stale: STALE_LOCK_MS,
|
|
15539
|
+
retries: LOCK_RETRIES,
|
|
15540
|
+
});
|
|
15541
|
+
}
|
|
15536
15542
|
/** Core shared config section. */
|
|
15537
15543
|
const workspaceCoreConfigSchema = object({
|
|
15538
15544
|
/** Workspace root path. */
|
package/dist/index.js
CHANGED
|
@@ -15480,14 +15480,14 @@ const PLATFORM_COMPONENTS = [
|
|
|
15480
15480
|
* Core library version, inlined at build time.
|
|
15481
15481
|
*
|
|
15482
15482
|
* @remarks
|
|
15483
|
-
* The `0.5.
|
|
15483
|
+
* The `0.5.6` placeholder is replaced by
|
|
15484
15484
|
* `@rollup/plugin-replace` during the build with the actual version
|
|
15485
15485
|
* from `package.json`. This ensures the correct version survives
|
|
15486
15486
|
* when consumers bundle core into their own dist (where runtime
|
|
15487
15487
|
* `import.meta.url`-based resolution would find the wrong package.json).
|
|
15488
15488
|
*/
|
|
15489
15489
|
/** The core library version from package.json (inlined at build time). */
|
|
15490
|
-
const CORE_VERSION = '0.5.
|
|
15490
|
+
const CORE_VERSION = '0.5.6';
|
|
15491
15491
|
|
|
15492
15492
|
/**
|
|
15493
15493
|
* Workspace and config root initialization.
|
|
@@ -15568,7 +15568,11 @@ const STALE_LOCK_MS = 120_000;
|
|
|
15568
15568
|
/** Default core version when none provided. */
|
|
15569
15569
|
const DEFAULT_CORE_VERSION = CORE_VERSION;
|
|
15570
15570
|
/** Lock retry options. */
|
|
15571
|
-
const LOCK_RETRIES = { retries:
|
|
15571
|
+
const LOCK_RETRIES = { retries: 0 };
|
|
15572
|
+
/** Workspace lock retry options. */
|
|
15573
|
+
const WORKSPACE_LOCK_RETRIES = { retries: 0 };
|
|
15574
|
+
/** Workspace lock file name. */
|
|
15575
|
+
const WORKSPACE_LOCK_FILE = 'jeeves.lock';
|
|
15572
15576
|
/** Maximum rename retry attempts on EPERM. */
|
|
15573
15577
|
const ATOMIC_WRITE_MAX_RETRIES = 3;
|
|
15574
15578
|
/** Delay between EPERM retries in milliseconds. */
|
|
@@ -15611,26 +15615,18 @@ function atomicWrite(filePath, content) {
|
|
|
15611
15615
|
}
|
|
15612
15616
|
}
|
|
15613
15617
|
}
|
|
15614
|
-
|
|
15615
|
-
* Execute a callback while holding a file lock.
|
|
15616
|
-
*
|
|
15617
|
-
* @remarks
|
|
15618
|
-
* Acquires a lock on the file, executes the callback, and releases
|
|
15619
|
-
* the lock in a finally block. The lock uses a 2-minute stale threshold
|
|
15620
|
-
* and retries up to 5 times.
|
|
15621
|
-
*
|
|
15622
|
-
* @param filePath - Absolute path to the file to lock.
|
|
15623
|
-
* @param fn - Async callback to execute while holding the lock.
|
|
15624
|
-
*/
|
|
15625
|
-
async function withFileLock(filePath, fn) {
|
|
15618
|
+
async function withLock(targetPath, fn, options, onLockError) {
|
|
15626
15619
|
let release;
|
|
15627
15620
|
try {
|
|
15628
|
-
release = await properLockfileExports.lock(
|
|
15629
|
-
stale: STALE_LOCK_MS,
|
|
15630
|
-
retries: LOCK_RETRIES,
|
|
15631
|
-
});
|
|
15621
|
+
release = await properLockfileExports.lock(targetPath, options);
|
|
15632
15622
|
await fn();
|
|
15633
15623
|
}
|
|
15624
|
+
catch (error) {
|
|
15625
|
+
if (onLockError?.(error)) {
|
|
15626
|
+
return;
|
|
15627
|
+
}
|
|
15628
|
+
throw error;
|
|
15629
|
+
}
|
|
15634
15630
|
finally {
|
|
15635
15631
|
if (release) {
|
|
15636
15632
|
try {
|
|
@@ -15642,6 +15638,44 @@ async function withFileLock(filePath, fn) {
|
|
|
15642
15638
|
}
|
|
15643
15639
|
}
|
|
15644
15640
|
}
|
|
15641
|
+
/**
|
|
15642
|
+
* Execute a callback while holding a file lock.
|
|
15643
|
+
*
|
|
15644
|
+
* @remarks
|
|
15645
|
+
* Acquires a lock on the file, executes the callback, and releases
|
|
15646
|
+
* the lock in a finally block. The lock uses a 2-minute stale threshold
|
|
15647
|
+
* and retries up to 5 times.
|
|
15648
|
+
*
|
|
15649
|
+
* @param filePath - Absolute path to the file to lock.
|
|
15650
|
+
* @param fn - Async callback to execute while holding the lock.
|
|
15651
|
+
*/
|
|
15652
|
+
async function withFileLock(filePath, fn) {
|
|
15653
|
+
await withLock(filePath, fn, {
|
|
15654
|
+
stale: STALE_LOCK_MS,
|
|
15655
|
+
retries: LOCK_RETRIES,
|
|
15656
|
+
});
|
|
15657
|
+
}
|
|
15658
|
+
/**
|
|
15659
|
+
* Execute a callback while holding the workspace cycle lock.
|
|
15660
|
+
*
|
|
15661
|
+
* @remarks
|
|
15662
|
+
* Acquires a lock on `{workspacePath}/jeeves.lock`, executes the callback,
|
|
15663
|
+
* and releases the lock in a finally block. If the lock is already held,
|
|
15664
|
+
* returns silently so the caller can skip this cycle.
|
|
15665
|
+
*
|
|
15666
|
+
* @param workspacePath - Absolute workspace path.
|
|
15667
|
+
* @param fn - Async callback to execute while holding the lock.
|
|
15668
|
+
*/
|
|
15669
|
+
async function withWorkspaceLock(workspacePath, fn) {
|
|
15670
|
+
const lockPath = join(workspacePath, WORKSPACE_LOCK_FILE);
|
|
15671
|
+
writeFileSync(lockPath, '', { flag: 'a' });
|
|
15672
|
+
await withLock(lockPath, fn, {
|
|
15673
|
+
stale: STALE_LOCK_MS,
|
|
15674
|
+
retries: WORKSPACE_LOCK_RETRIES,
|
|
15675
|
+
}, (error) => error instanceof Error &&
|
|
15676
|
+
'code' in error &&
|
|
15677
|
+
error.code === 'ELOCKED');
|
|
15678
|
+
}
|
|
15645
15679
|
|
|
15646
15680
|
/**
|
|
15647
15681
|
* Shared internal utility functions.
|
|
@@ -15973,7 +16007,7 @@ function buildHeartbeatSection(entries) {
|
|
|
15973
16007
|
*
|
|
15974
16008
|
* @remarks
|
|
15975
16009
|
* Replaces everything from `# Jeeves Platform Status` to EOF.
|
|
15976
|
-
* Preserves user content above the heading.
|
|
16010
|
+
* Preserves user content above the heading.
|
|
15977
16011
|
*
|
|
15978
16012
|
* @param filePath - Absolute path to HEARTBEAT.md.
|
|
15979
16013
|
* @param entries - Component entries to write.
|
|
@@ -17194,7 +17228,7 @@ function stripForeignMarkers(content, currentMarkers) {
|
|
|
17194
17228
|
* - `block`: Replaces the entire managed block (SOUL.md, AGENTS.md).
|
|
17195
17229
|
* - `section`: Upserts a named H2 section within the managed block (TOOLS.md).
|
|
17196
17230
|
*
|
|
17197
|
-
* Provides
|
|
17231
|
+
* Provides version-stamp convergence and atomic writes.
|
|
17198
17232
|
*/
|
|
17199
17233
|
/**
|
|
17200
17234
|
* Update a managed section in a file.
|
|
@@ -17341,17 +17375,7 @@ var agentsSectionContent = `## "I'll Note This" Is Not Noting
|
|
|
17341
17375
|
|
|
17342
17376
|
## Context Compaction Recovery
|
|
17343
17377
|
|
|
17344
|
-
|
|
17345
|
-
|
|
17346
|
-
1. **Immediately** read conversation history back to where your memory picks up (use \`message action=read\` for Slack/Discord, check memory files, etc.)
|
|
17347
|
-
2. Reconstruct the thread: what were we doing? what was decided? what's the next step?
|
|
17348
|
-
3. **Re-run skill selection** against the reconstructed task context. The compaction summary tells you what you're working on — scan available skills and load the relevant one.
|
|
17349
|
-
4. **Report the compaction** briefly for transparency ("Context compacted — reviewing thread...")
|
|
17350
|
-
5. **Then continue** as if you never lost context — pick up where you left off
|
|
17351
|
-
|
|
17352
|
-
**The goal:** Automatic remediation with minimal disruption. Don't ask "what were we talking about?" when you can find out yourself. The human shouldn't have to re-explain; you have the tools to recover.
|
|
17353
|
-
|
|
17354
|
-
**Anti-pattern:** Announcing amnesia *before* checking your notes. That's alarming and lazy. Check the ledger first, then speak.
|
|
17378
|
+
On compaction: read conversation history, reconstruct context, re-run skill selection against the reconstructed task, report briefly ("Context compacted — reviewing thread..."), then continue. Check notes before announcing amnesia.
|
|
17355
17379
|
|
|
17356
17380
|
## Subagent Briefing Protocol
|
|
17357
17381
|
|
|
@@ -17369,22 +17393,10 @@ At minimum, always brief sub-agents on:
|
|
|
17369
17393
|
|
|
17370
17394
|
**Strong runner preference:** Any recurring task that can run as a script (no LLM session needed) belongs in jeeves-runner, not gateway cron or heartbeat. If runner is installed, use it. If not, suggest bootstrapping it. Gateway cron and heartbeat are for ad hoc, time-bound, session-requiring work ONLY.
|
|
17371
17395
|
|
|
17372
|
-
**Before creating a recurring gateway cron job**, assess whether it will frequently no-op. If so, flag it: *"This would be cheaper as a runner job. Want me to implement it that way instead?"*
|
|
17373
|
-
|
|
17374
|
-
**Anything important enough to have a permanent cron/heartbeat entry is important enough to be codified into the data flow.**
|
|
17375
|
-
|
|
17376
|
-
**HEARTBEAT efficiency:** When HEARTBEAT fires with multiple component alerts, resolve them all in a single conversation. Walk the user through each component in dependency order. Each heartbeat cycle is a full LLM session — resolve all alerts in one pass.
|
|
17377
|
-
|
|
17378
|
-
## Messaging Dispatch
|
|
17379
|
-
|
|
17380
|
-
**Same-channel replies:** Don't use the \`message\` tool. It fires immediately, jumping ahead of streaming narration. Just write text as your response. Use \`message\` only for **cross-channel** sends (sending to a different channel or DM than the one you're responding in).
|
|
17381
|
-
|
|
17382
|
-
**Narrate as you go.** When doing multi-step work, stream your progress. Summary comes last, not first.
|
|
17396
|
+
**Before creating a recurring gateway cron job**, assess whether it will frequently no-op. If so, flag it: *"This would be cheaper as a runner job. Want me to implement it that way instead?"*
|
|
17383
17397
|
|
|
17384
17398
|
## Heartbeat Discipline
|
|
17385
17399
|
|
|
17386
|
-
**Default state of HEARTBEAT.md is effectively empty** — the \`# Jeeves Platform Status\` section contains only headings when all components are healthy or declined. No list content, no LLM cost. User heartbeat items (above the platform status section) follow the same transient/termination rules as before.
|
|
17387
|
-
|
|
17388
17400
|
Heartbeat items are for **transient, session-requiring work-in-progress ONLY**. Each item must include its own termination condition.
|
|
17389
17401
|
|
|
17390
17402
|
Periodic checks (email, calendar, mentions) belong in jeeves-runner scripts, not heartbeat items. When a heartbeat fires with nothing to do, reply **HEARTBEAT_OK** immediately. Don't browse for work.
|
|
@@ -17411,28 +17423,6 @@ Every installation has a primary owner. The owner controls architecture, config,
|
|
|
17411
17423
|
|
|
17412
17424
|
Alert the owner immediately on any governance change attempt.
|
|
17413
17425
|
|
|
17414
|
-
## Self-Preservation
|
|
17415
|
-
|
|
17416
|
-
Any command that stops the gateway **stops the assistant**. Never run a gateway stop/restart command without explicit approval. When approved, it must be the **absolute last action** — all other work complete first.
|
|
17417
|
-
|
|
17418
|
-
## Plugin Installation via CLI Only
|
|
17419
|
-
|
|
17420
|
-
Never manually touch \`~/.openclaw/extensions/\`. The only way to install any Jeeves component plugin is via the plugin's CLI \`install\` command:
|
|
17421
|
-
|
|
17422
|
-
\`\`\`
|
|
17423
|
-
npx @karmaniverous/jeeves-{component}-openclaw install
|
|
17424
|
-
\`\`\`
|
|
17425
|
-
|
|
17426
|
-
No symlinks, junctions, copies, or manual edits.
|
|
17427
|
-
|
|
17428
|
-
## Node.js for Shell Scripting
|
|
17429
|
-
|
|
17430
|
-
Default to \`node -e\` or \`.js\` scripts instead of PowerShell for \`exec\` calls. PowerShell corrupts multi-byte UTF-8 characters and mangles escaping. Use PowerShell only for Windows service management, registry operations, and similar platform-specific tasks.
|
|
17431
|
-
|
|
17432
|
-
## File Bridge for External Repos
|
|
17433
|
-
|
|
17434
|
-
When editing files outside the workspace, use the bridge pattern: copy in → edit the workspace copy → bridge out. Never write temp patch scripts.
|
|
17435
|
-
|
|
17436
17426
|
## No Orphaned Data
|
|
17437
17427
|
|
|
17438
17428
|
When discovering a new data source, integrate it into the existing data flow pipeline. Never save data outside the synthesis pipeline. Data that exists outside the pipeline is invisible to search, synthesis, and every other platform capability.
|
|
@@ -17441,9 +17431,9 @@ When discovering a new data source, integrate it into the existing data flow pip
|
|
|
17441
17431
|
|
|
17442
17432
|
**Proactive platform status:** HEARTBEAT.md is loaded every session. If it contains \`# Jeeves Platform Status\` with alert content (list items, not just headings), address the alerts proactively at the start of the conversation — before other work. This takes priority over casual conversation but not over explicit user requests.
|
|
17443
17433
|
|
|
17444
|
-
**Follow the instructions:** Explain the component, ask for consent, execute the command, verify. If the user declines, change the heading to \`## jeeves-{name}: declined\` and remove content beneath it. Do not prompt for declined components.
|
|
17434
|
+
**Follow the instructions:** Explain the component, ask for consent, execute the command, verify. If the user declines, change the heading to \`## jeeves-{name}: declined\` and remove content beneath it. Do not prompt for declined components.
|
|
17445
17435
|
|
|
17446
|
-
When resolving multiple component alerts, walk the user through each in dependency order
|
|
17436
|
+
When resolving multiple component alerts, walk the user through each in dependency order within a single conversation rather than one per heartbeat cycle.
|
|
17447
17437
|
|
|
17448
17438
|
## Em-Dash Discipline
|
|
17449
17439
|
|
|
@@ -17453,29 +17443,13 @@ The em-dash sets apart parentheticals. It is NOT a replacement for comma, colon,
|
|
|
17453
17443
|
|
|
17454
17444
|
Operational hard gates — procedural rules earned through real incidents. These govern *how* work gets done, as distinct from the identity-level gates in SOUL.md which govern *who I am*.
|
|
17455
17445
|
|
|
17456
|
-
|
|
17457
|
-
|
|
17458
|
-
|
|
17459
|
-
|
|
17460
|
-
|
|
17461
|
-
|
|
17462
|
-
|
|
17463
|
-
|
|
17464
|
-
### No Prod Modifications
|
|
17465
|
-
|
|
17466
|
-
Never modify packaged applications running in production. No \`npm link\` into a live service. All changes go through: branch, change, test, PR, merge, publish, install.
|
|
17467
|
-
|
|
17468
|
-
### PR Mergeability Check
|
|
17469
|
-
|
|
17470
|
-
Always verify a PR is mergeable (no conflicts) before requesting review. Resolve conflicts first.
|
|
17471
|
-
|
|
17472
|
-
### Pre-Push Verification Gate
|
|
17473
|
-
|
|
17474
|
-
Run **ALL** quality checks before pushing. Zero errors AND zero warnings. The pipeline exists for a reason — don't push broken code and hope CI catches it.
|
|
17475
|
-
|
|
17476
|
-
### Commit AND Push
|
|
17477
|
-
|
|
17478
|
-
No stranded local branches. Push immediately after commit. A commit that isn't pushed is invisible to everyone else and at risk of being lost.
|
|
17446
|
+
- **eslint-disable Is Forbidden:** Never disable lint/typecheck rules without surfacing for discussion. Fix the code.
|
|
17447
|
+
- **Mass File Changes Are a Smell:** If a fix requires changing dozens of files, stop and discuss — there is probably a config or rule solution.
|
|
17448
|
+
- **No Prod Modifications:** Never modify packaged prod applications. All changes go through branch → test → PR → merge → publish → install.
|
|
17449
|
+
- **PR Mergeability Check:** Always verify PR is mergeable (no conflicts) before requesting review.
|
|
17450
|
+
- **Pre-Push Verification Gate:** Run ALL quality checks before pushing. Zero errors AND zero warnings.
|
|
17451
|
+
- **Commit AND Push:** Push immediately after every commit. Unpushed commits are invisible and at risk.
|
|
17452
|
+
- **New PR Over Merged Branch:** When a merged branch needs more work: \`gh pr create --head <existing-branch>\`. Do not cherry-pick or create new branches.
|
|
17479
17453
|
|
|
17480
17454
|
### Check PR State Before Pushing
|
|
17481
17455
|
|
|
@@ -17487,10 +17461,6 @@ No stranded local branches. Push immediately after commit. A commit that isn't p
|
|
|
17487
17461
|
|
|
17488
17462
|
This is not optional. It applies to every push, every branch, every time. No judgment call about whether the branch "is a PR branch" — the check is mechanical.
|
|
17489
17463
|
|
|
17490
|
-
### New PR Over Merged Branch
|
|
17491
|
-
|
|
17492
|
-
When a PR has been merged and additional work is needed on the same branch, create a new PR on the **same branch** targeting the same base. Do not create new branches, cherry-pick, or start over. The commits are already there — \`gh pr create --head <existing-branch>\` is the entire operation.
|
|
17493
|
-
|
|
17494
17464
|
## Managed Content Self-Maintenance
|
|
17495
17465
|
|
|
17496
17466
|
The Jeeves platform maintains managed sections in SOUL.md, AGENTS.md, and TOOLS.md using comment markers. If any of these files contains a **cleanup flag** indicating orphaned Jeeves content below the managed section markers:
|
|
@@ -18014,13 +17984,6 @@ const WORKSPACE_SIZE_FILES = [
|
|
|
18014
17984
|
'MEMORY.md',
|
|
18015
17985
|
'USER.md',
|
|
18016
17986
|
];
|
|
18017
|
-
/** Trimming guidance lines emitted in HEARTBEAT entries. */
|
|
18018
|
-
const TRIMMING_GUIDANCE = [
|
|
18019
|
-
' 1. Move domain-specific content to a local skill',
|
|
18020
|
-
' 2. Extract reference material to companion files with a pointer',
|
|
18021
|
-
' 3. Summarize verbose instructions',
|
|
18022
|
-
' 4. Remove stale content',
|
|
18023
|
-
].join('\n');
|
|
18024
17987
|
/**
|
|
18025
17988
|
* Check all workspace files against the character budget.
|
|
18026
17989
|
*
|
|
@@ -18069,10 +18032,17 @@ function workspaceFileHealthEntries(results) {
|
|
|
18069
18032
|
.filter((r) => r.exists && r.warning)
|
|
18070
18033
|
.map((r) => {
|
|
18071
18034
|
const pct = Math.round(r.usage * 100);
|
|
18072
|
-
const overBudgetNote = r.overBudget ? ' **Over budget.**' : '';
|
|
18035
|
+
const overBudgetNote = r.overBudget ? ' **Over budget.** ' : ' ';
|
|
18073
18036
|
const content = [
|
|
18074
|
-
|
|
18075
|
-
|
|
18037
|
+
`${r.file} is at ${String(pct)}% of its ${(r.budget / 1000).toLocaleString()}K char injection budget (${r.charCount.toLocaleString()} / ${r.budget.toLocaleString()} chars).${overBudgetNote}Action required:`,
|
|
18038
|
+
'',
|
|
18039
|
+
'1. Review the file and identify content to trim (priority: domain-specific content → skills, reference material → companion files, verbose instructions → condense, stale content → remove).',
|
|
18040
|
+
'2. Ask the owner for permission, then trim.',
|
|
18041
|
+
"3. If the owner declines, change this heading to '## " +
|
|
18042
|
+
r.file +
|
|
18043
|
+
": declined' to suppress this alert.",
|
|
18044
|
+
'',
|
|
18045
|
+
'Do NOT reply HEARTBEAT_OK while this alert is unresolved.',
|
|
18076
18046
|
].join('\n');
|
|
18077
18047
|
return {
|
|
18078
18048
|
name: r.file,
|
|
@@ -18572,6 +18542,7 @@ class ComponentWriter {
|
|
|
18572
18542
|
configDir;
|
|
18573
18543
|
gatewayUrl;
|
|
18574
18544
|
pendingCleanups = new Set();
|
|
18545
|
+
cyclePromise;
|
|
18575
18546
|
/** @internal */
|
|
18576
18547
|
constructor(component, options) {
|
|
18577
18548
|
this.component = component;
|
|
@@ -18584,7 +18555,9 @@ class ComponentWriter {
|
|
|
18584
18555
|
}
|
|
18585
18556
|
/** Whether the writer timer is currently running or pending its first cycle. */
|
|
18586
18557
|
get isRunning() {
|
|
18587
|
-
return this.jitterTimeout !== undefined ||
|
|
18558
|
+
return (this.jitterTimeout !== undefined ||
|
|
18559
|
+
this.timer !== undefined ||
|
|
18560
|
+
this.cyclePromise !== undefined);
|
|
18588
18561
|
}
|
|
18589
18562
|
/**
|
|
18590
18563
|
* Start the writer timer.
|
|
@@ -18602,8 +18575,7 @@ class ComponentWriter {
|
|
|
18602
18575
|
const jitterMs = Math.floor(Math.random() * intervalMs);
|
|
18603
18576
|
this.jitterTimeout = setTimeout(() => {
|
|
18604
18577
|
this.jitterTimeout = undefined;
|
|
18605
|
-
|
|
18606
|
-
this.timer = setInterval(() => void this.cycle(), intervalMs);
|
|
18578
|
+
this.scheduleNextCycle(0, intervalMs);
|
|
18607
18579
|
}, jitterMs);
|
|
18608
18580
|
}
|
|
18609
18581
|
/** Stop the writer timer. */
|
|
@@ -18613,10 +18585,19 @@ class ComponentWriter {
|
|
|
18613
18585
|
this.jitterTimeout = undefined;
|
|
18614
18586
|
}
|
|
18615
18587
|
if (this.timer) {
|
|
18616
|
-
|
|
18588
|
+
clearTimeout(this.timer);
|
|
18617
18589
|
this.timer = undefined;
|
|
18618
18590
|
}
|
|
18619
18591
|
}
|
|
18592
|
+
scheduleNextCycle(delayMs, intervalMs) {
|
|
18593
|
+
this.timer = setTimeout(() => {
|
|
18594
|
+
this.timer = undefined;
|
|
18595
|
+
void this.cycle().finally(() => {
|
|
18596
|
+
if (this.isRunning)
|
|
18597
|
+
this.scheduleNextCycle(intervalMs, intervalMs);
|
|
18598
|
+
});
|
|
18599
|
+
}, delayMs);
|
|
18600
|
+
}
|
|
18620
18601
|
/**
|
|
18621
18602
|
* Execute a single write cycle.
|
|
18622
18603
|
*
|
|
@@ -18627,44 +18608,54 @@ class ComponentWriter {
|
|
|
18627
18608
|
* 4. Run HEARTBEAT health orchestration.
|
|
18628
18609
|
*/
|
|
18629
18610
|
async cycle() {
|
|
18611
|
+
if (this.cyclePromise)
|
|
18612
|
+
return this.cyclePromise;
|
|
18613
|
+
this.cyclePromise = this.runCycle().finally(() => {
|
|
18614
|
+
this.cyclePromise = undefined;
|
|
18615
|
+
});
|
|
18616
|
+
return this.cyclePromise;
|
|
18617
|
+
}
|
|
18618
|
+
async runCycle() {
|
|
18630
18619
|
try {
|
|
18631
18620
|
const workspacePath = getWorkspacePath();
|
|
18632
18621
|
const toolsPath = join(workspacePath, WORKSPACE_FILES.tools);
|
|
18633
|
-
|
|
18634
|
-
|
|
18635
|
-
|
|
18636
|
-
|
|
18637
|
-
|
|
18638
|
-
|
|
18639
|
-
|
|
18640
|
-
|
|
18641
|
-
|
|
18642
|
-
|
|
18643
|
-
|
|
18644
|
-
|
|
18645
|
-
|
|
18646
|
-
|
|
18647
|
-
|
|
18648
|
-
|
|
18649
|
-
|
|
18650
|
-
|
|
18651
|
-
|
|
18652
|
-
|
|
18653
|
-
|
|
18654
|
-
|
|
18655
|
-
|
|
18656
|
-
|
|
18657
|
-
|
|
18658
|
-
|
|
18659
|
-
|
|
18660
|
-
|
|
18661
|
-
|
|
18662
|
-
|
|
18663
|
-
|
|
18664
|
-
|
|
18665
|
-
|
|
18666
|
-
|
|
18667
|
-
|
|
18622
|
+
await withWorkspaceLock(workspacePath, async () => {
|
|
18623
|
+
// 1. Write the component's TOOLS.md section
|
|
18624
|
+
const toolsContent = this.component.generateToolsContent();
|
|
18625
|
+
await updateManagedSection(toolsPath, toolsContent, {
|
|
18626
|
+
mode: 'section',
|
|
18627
|
+
sectionId: this.component.sectionId,
|
|
18628
|
+
markers: TOOLS_MARKERS,
|
|
18629
|
+
coreVersion: CORE_VERSION,
|
|
18630
|
+
});
|
|
18631
|
+
// 2. Platform content maintenance
|
|
18632
|
+
await refreshPlatformContent({
|
|
18633
|
+
coreVersion: CORE_VERSION,
|
|
18634
|
+
componentName: this.component.name,
|
|
18635
|
+
componentVersion: this.component.version,
|
|
18636
|
+
servicePackage: this.component.servicePackage,
|
|
18637
|
+
pluginPackage: this.component.pluginPackage,
|
|
18638
|
+
});
|
|
18639
|
+
// 3. Cleanup escalation
|
|
18640
|
+
if (this.gatewayUrl) {
|
|
18641
|
+
scanAndEscalateCleanup([
|
|
18642
|
+
{ filePath: toolsPath, markerIdentity: 'TOOLS' },
|
|
18643
|
+
{
|
|
18644
|
+
filePath: join(workspacePath, WORKSPACE_FILES.soul),
|
|
18645
|
+
markerIdentity: 'SOUL',
|
|
18646
|
+
},
|
|
18647
|
+
{
|
|
18648
|
+
filePath: join(workspacePath, WORKSPACE_FILES.agents),
|
|
18649
|
+
markerIdentity: 'AGENTS',
|
|
18650
|
+
},
|
|
18651
|
+
], this.gatewayUrl, this.pendingCleanups);
|
|
18652
|
+
}
|
|
18653
|
+
// 4. HEARTBEAT orchestration
|
|
18654
|
+
await runHeartbeatCycle({
|
|
18655
|
+
workspacePath,
|
|
18656
|
+
coreConfigDir: getCoreConfigDir(),
|
|
18657
|
+
configRoot: getConfigRoot$1(),
|
|
18658
|
+
});
|
|
18668
18659
|
});
|
|
18669
18660
|
}
|
|
18670
18661
|
catch (err) {
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "jeeves-watcher-openclaw",
|
|
3
3
|
"name": "Jeeves Watcher",
|
|
4
4
|
"description": "Semantic search, metadata enrichment, and instance administration for a jeeves-watcher deployment.",
|
|
5
|
-
"version": "0.14.
|
|
5
|
+
"version": "0.14.6",
|
|
6
6
|
"skills": [
|
|
7
7
|
"dist/skills/jeeves-watcher"
|
|
8
8
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karmaniverous/jeeves-watcher-openclaw",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.6",
|
|
4
4
|
"author": "Jason Williscroft",
|
|
5
5
|
"description": "OpenClaw plugin for jeeves-watcher — semantic search and metadata enrichment tools",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
@@ -118,6 +118,6 @@
|
|
|
118
118
|
}
|
|
119
119
|
},
|
|
120
120
|
"dependencies": {
|
|
121
|
-
"@karmaniverous/jeeves": "^0.5.
|
|
121
|
+
"@karmaniverous/jeeves": "^0.5.7"
|
|
122
122
|
}
|
|
123
123
|
}
|