openclaw-sentinel-cli 1.1.0
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/README.md +117 -0
- package/SKILL.md +52 -0
- package/dist/bin/sentinel.d.ts +2 -0
- package/dist/bin/sentinel.js +328 -0
- package/dist/bin/sentinel.js.map +1 -0
- package/dist/client.d.ts +15 -0
- package/dist/client.js +92 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/openclaw.d.ts +24 -0
- package/dist/openclaw.js +144 -0
- package/dist/openclaw.js.map +1 -0
- package/dist/skills/backupBrain.d.ts +21 -0
- package/dist/skills/backupBrain.js +43 -0
- package/dist/skills/backupBrain.js.map +1 -0
- package/dist/skills/backupBrain.test.d.ts +1 -0
- package/dist/skills/backupBrain.test.js +58 -0
- package/dist/skills/backupBrain.test.js.map +1 -0
- package/dist/skills/remoteMemory.d.ts +20 -0
- package/dist/skills/remoteMemory.js +25 -0
- package/dist/skills/remoteMemory.js.map +1 -0
- package/dist/skills/searchMemory.d.ts +24 -0
- package/dist/skills/searchMemory.js +27 -0
- package/dist/skills/searchMemory.js.map +1 -0
- package/dist/skills/sentinelHeartbeat.d.ts +8 -0
- package/dist/skills/sentinelHeartbeat.js +64 -0
- package/dist/skills/sentinelHeartbeat.js.map +1 -0
- package/dist/workspace.d.ts +5 -0
- package/dist/workspace.js +10 -0
- package/dist/workspace.js.map +1 -0
- package/dist/workspace.test.d.ts +1 -0
- package/dist/workspace.test.js +60 -0
- package/dist/workspace.test.js.map +1 -0
- package/openclaw.plugin.json +30 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# sentinel-sdk
|
|
2
|
+
|
|
3
|
+
Publish-ready Sentinel package for OpenClaw agents to save/search memory at **openclawsentinel.com** and keep memory sync reliable.
|
|
4
|
+
|
|
5
|
+
Includes in one npm package:
|
|
6
|
+
|
|
7
|
+
- OpenClaw plugin manifest (`openclaw.plugin.json`)
|
|
8
|
+
- OpenClaw runtime entrypoint (`dist/openclaw.js`)
|
|
9
|
+
- CLI (`sentinel`) with setup/doctor/check
|
|
10
|
+
- Agent skill docs (`SKILL.md`)
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
### Global CLI
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g sentinel-sdk
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### One-off via npx
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx sentinel-sdk doctor --json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Local dependency
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install sentinel-sdk
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Required config
|
|
33
|
+
|
|
34
|
+
You can configure via env vars **or** OpenClaw plugin config.
|
|
35
|
+
|
|
36
|
+
### Environment variables
|
|
37
|
+
|
|
38
|
+
| Variable | Required | Default |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `SENTINEL_API_KEY` | Yes | none |
|
|
41
|
+
| `SENTINEL_API_BASE_URL` | No | `https://api.openclawsentinel.com` |
|
|
42
|
+
| `SENTINEL_AGENT_ID` | No | `default-agent` |
|
|
43
|
+
| `AGENT_ID` | No (legacy fallback) | `default-agent` |
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
export SENTINEL_API_KEY="sk_live_..."
|
|
49
|
+
export SENTINEL_API_BASE_URL="https://api.openclawsentinel.com"
|
|
50
|
+
export SENTINEL_AGENT_ID="my-openclaw-agent"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or scaffold `.env`:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
sentinel setup --file .env
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## CLI quickstart
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
sentinel setup --file .env
|
|
63
|
+
sentinel doctor --json
|
|
64
|
+
sentinel check --json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Commands
|
|
68
|
+
|
|
69
|
+
- `sentinel setup [--file .env] [--force] [--json]`
|
|
70
|
+
- `sentinel doctor [--json] [--strict-warn] [--api-key ...] [--base-url ...] [--agent-id ...]`
|
|
71
|
+
- `sentinel check [--json]` (fast API key + health check)
|
|
72
|
+
- `sentinel install-heartbeat`
|
|
73
|
+
- `sentinel env push|pull` (currently deferred with guidance output)
|
|
74
|
+
|
|
75
|
+
## OpenClaw plugin usage
|
|
76
|
+
|
|
77
|
+
1. Install package in your OpenClaw project:
|
|
78
|
+
```bash
|
|
79
|
+
npm install sentinel-sdk
|
|
80
|
+
```
|
|
81
|
+
2. Ensure plugin artifacts are available from package:
|
|
82
|
+
- `openclaw.plugin.json`
|
|
83
|
+
- `dist/openclaw.js`
|
|
84
|
+
- `SKILL.md`
|
|
85
|
+
3. Configure plugin (either env or plugin config):
|
|
86
|
+
- `apiKey`
|
|
87
|
+
- `baseUrl` (optional)
|
|
88
|
+
- `agentId` (optional)
|
|
89
|
+
4. Reload OpenClaw plugins.
|
|
90
|
+
|
|
91
|
+
Registered tools:
|
|
92
|
+
|
|
93
|
+
- `save_remote_memory`
|
|
94
|
+
- `search_remote_memory`
|
|
95
|
+
- `backup_brain`
|
|
96
|
+
- `sentinel_heartbeat`
|
|
97
|
+
|
|
98
|
+
## Reliability behavior
|
|
99
|
+
|
|
100
|
+
- `save_remote_memory` persists user-critical facts to Sentinel cloud.
|
|
101
|
+
- `search_remote_memory` queries previously saved memory.
|
|
102
|
+
- `sentinel_heartbeat` checks gateway health + backup freshness + new memory signals.
|
|
103
|
+
- `backup_brain` uploads key identity files for recovery.
|
|
104
|
+
|
|
105
|
+
Install heartbeat policy into `HEARTBEAT.md`:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
sentinel install-heartbeat
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Development
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npm install
|
|
115
|
+
npm run build
|
|
116
|
+
npm pack
|
|
117
|
+
```
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sentinel-memory-reliability
|
|
3
|
+
description: Use when configuring Sentinel for OpenClaw memory save/search and heartbeat reliability checks.
|
|
4
|
+
emoji: brain
|
|
5
|
+
os: [win32, linux, darwin]
|
|
6
|
+
metadata:
|
|
7
|
+
openclaw:
|
|
8
|
+
requires:
|
|
9
|
+
bins: [sentinel]
|
|
10
|
+
env: [SENTINEL_API_KEY]
|
|
11
|
+
primaryEnv: SENTINEL_API_KEY
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## What this skill provides
|
|
15
|
+
|
|
16
|
+
- Save important user facts remotely (`save_remote_memory`)
|
|
17
|
+
- Search previously-saved memories (`search_remote_memory`)
|
|
18
|
+
- Run periodic reliability checks (`sentinel_heartbeat`)
|
|
19
|
+
- Trigger backup snapshot uploads when heartbeat says backup is needed (`backup_brain`)
|
|
20
|
+
|
|
21
|
+
## Prerequisites
|
|
22
|
+
|
|
23
|
+
- `sentinel` CLI is installed (`npm i -g sentinel-sdk` or use `npx sentinel-sdk`)
|
|
24
|
+
- `SENTINEL_API_KEY` is set
|
|
25
|
+
- Optional: `SENTINEL_API_BASE_URL` (default `https://api.openclawsentinel.com`)
|
|
26
|
+
- Optional: `SENTINEL_AGENT_ID` (fallback: `AGENT_ID`, then `default-agent`)
|
|
27
|
+
|
|
28
|
+
## Quick setup
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
sentinel setup --file .env
|
|
32
|
+
sentinel doctor --json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Heartbeat installation
|
|
36
|
+
|
|
37
|
+
From your OpenClaw agent root:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
sentinel install-heartbeat
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This appends:
|
|
44
|
+
|
|
45
|
+
- Run `sentinel_heartbeat` every 10 heartbeat cycles
|
|
46
|
+
- If heartbeat reports backup required, execute `backup_brain`
|
|
47
|
+
|
|
48
|
+
## Troubleshooting
|
|
49
|
+
|
|
50
|
+
- Missing API key: set `SENTINEL_API_KEY` and rerun `sentinel doctor --json`
|
|
51
|
+
- API not reachable: verify `SENTINEL_API_BASE_URL` and network access
|
|
52
|
+
- `HEARTBEAT.md not found`: run `sentinel install-heartbeat` from the OpenClaw root
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import * as dotenv from 'dotenv';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { SentinelClient } from '../client.js';
|
|
7
|
+
import { resolveWorkspaceDir } from '../workspace.js';
|
|
8
|
+
const program = new Command();
|
|
9
|
+
dotenv.config();
|
|
10
|
+
const DEFAULT_BASE_URL = 'https://api.openclawsentinel.com';
|
|
11
|
+
const DEFAULT_AGENT_ID = 'default-agent';
|
|
12
|
+
const SECRETS_DEFERRED_MESSAGE = 'Secrets sync over Sentinel Gateway HTTP is deferred in this release. Use local Convex secret sync workflow instead.';
|
|
13
|
+
function resolveRuntimeConfig(options = {}) {
|
|
14
|
+
const apiKey = options.apiKey ?? process.env.SENTINEL_API_KEY;
|
|
15
|
+
const baseUrl = options.baseUrl ?? process.env.SENTINEL_API_BASE_URL ?? DEFAULT_BASE_URL;
|
|
16
|
+
const agentId = options.agentId ?? process.env.SENTINEL_AGENT_ID ?? process.env.AGENT_ID ?? DEFAULT_AGENT_ID;
|
|
17
|
+
return { apiKey, baseUrl, agentId };
|
|
18
|
+
}
|
|
19
|
+
function parseEnvFileKeys(filePath) {
|
|
20
|
+
if (!fs.existsSync(filePath))
|
|
21
|
+
return new Set();
|
|
22
|
+
const existing = fs.readFileSync(filePath, 'utf-8');
|
|
23
|
+
const keys = new Set();
|
|
24
|
+
for (const line of existing.split(/\r?\n/)) {
|
|
25
|
+
const trimmed = line.trim();
|
|
26
|
+
if (!trimmed || trimmed.startsWith('#') || !trimmed.includes('='))
|
|
27
|
+
continue;
|
|
28
|
+
const key = trimmed.slice(0, trimmed.indexOf('=')).trim();
|
|
29
|
+
if (key)
|
|
30
|
+
keys.add(key);
|
|
31
|
+
}
|
|
32
|
+
return keys;
|
|
33
|
+
}
|
|
34
|
+
function writeSetupTemplate(filePath, force) {
|
|
35
|
+
const templateLines = [
|
|
36
|
+
'# Sentinel CLI / OpenClaw plugin configuration',
|
|
37
|
+
'SENTINEL_API_KEY=',
|
|
38
|
+
`SENTINEL_API_BASE_URL=${DEFAULT_BASE_URL}`,
|
|
39
|
+
`SENTINEL_AGENT_ID=${DEFAULT_AGENT_ID}`,
|
|
40
|
+
'# AGENT_ID is supported for legacy compatibility',
|
|
41
|
+
`AGENT_ID=${DEFAULT_AGENT_ID}`,
|
|
42
|
+
];
|
|
43
|
+
if (!fs.existsSync(filePath) || force) {
|
|
44
|
+
fs.writeFileSync(filePath, `${templateLines.join('\n')}\n`, 'utf-8');
|
|
45
|
+
return {
|
|
46
|
+
written: true,
|
|
47
|
+
detail: force
|
|
48
|
+
? `Overwrote ${filePath} with Sentinel setup template.`
|
|
49
|
+
: `Created ${filePath} with Sentinel setup template.`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const existing = fs.readFileSync(filePath, 'utf-8');
|
|
53
|
+
const existingKeys = parseEnvFileKeys(filePath);
|
|
54
|
+
const additions = [];
|
|
55
|
+
const desired = [
|
|
56
|
+
['SENTINEL_API_KEY', ''],
|
|
57
|
+
['SENTINEL_API_BASE_URL', DEFAULT_BASE_URL],
|
|
58
|
+
['SENTINEL_AGENT_ID', DEFAULT_AGENT_ID],
|
|
59
|
+
['AGENT_ID', DEFAULT_AGENT_ID],
|
|
60
|
+
];
|
|
61
|
+
for (const [key, value] of desired) {
|
|
62
|
+
if (!existingKeys.has(key)) {
|
|
63
|
+
additions.push(`${key}=${value}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (additions.length === 0) {
|
|
67
|
+
return { written: false, detail: `${filePath} already contains Sentinel keys.` };
|
|
68
|
+
}
|
|
69
|
+
const next = `${existing.replace(/\s*$/, '')}\n\n# Added by sentinel setup\n${additions.join('\n')}\n`;
|
|
70
|
+
fs.writeFileSync(filePath, next, 'utf-8');
|
|
71
|
+
return { written: true, detail: `Appended ${additions.length} missing key(s) to ${filePath}.` };
|
|
72
|
+
}
|
|
73
|
+
const runEnvPush = async (filePath) => {
|
|
74
|
+
if (!fs.existsSync(filePath)) {
|
|
75
|
+
console.error(`ERROR: No file found at ${filePath}.`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
console.error(`ERROR: ${SECRETS_DEFERRED_MESSAGE}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
};
|
|
81
|
+
const runEnvPull = async (_filePath, _force) => {
|
|
82
|
+
console.error(`ERROR: ${SECRETS_DEFERRED_MESSAGE}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
};
|
|
85
|
+
const warnDeprecatedAlias = (alias, canonical) => {
|
|
86
|
+
console.warn(`[DEPRECATED] '${alias}' will be removed in v1.2.0. Use '${canonical}'.`);
|
|
87
|
+
};
|
|
88
|
+
program.name('sentinel').description('Sentinel Agent CLI Manager').version('1.1.0');
|
|
89
|
+
program
|
|
90
|
+
.command('setup')
|
|
91
|
+
.description('Prepare Sentinel environment variables for CLI + OpenClaw plugin usage')
|
|
92
|
+
.option('--file <path>', 'Path to env file', '.env')
|
|
93
|
+
.option('--force', 'Overwrite env file with Sentinel template')
|
|
94
|
+
.option('--json', 'Emit machine-readable setup output')
|
|
95
|
+
.action((options) => {
|
|
96
|
+
const filePath = path.resolve(process.cwd(), options.file || '.env');
|
|
97
|
+
const result = writeSetupTemplate(filePath, Boolean(options.force));
|
|
98
|
+
const config = resolveRuntimeConfig();
|
|
99
|
+
if (options.json) {
|
|
100
|
+
console.log(JSON.stringify({
|
|
101
|
+
ok: true,
|
|
102
|
+
file: filePath,
|
|
103
|
+
...result,
|
|
104
|
+
requiredEnv: ['SENTINEL_API_KEY'],
|
|
105
|
+
optionalEnv: ['SENTINEL_API_BASE_URL', 'SENTINEL_AGENT_ID', 'AGENT_ID'],
|
|
106
|
+
detected: {
|
|
107
|
+
hasApiKey: Boolean(config.apiKey),
|
|
108
|
+
baseUrl: config.baseUrl,
|
|
109
|
+
agentId: config.agentId,
|
|
110
|
+
},
|
|
111
|
+
}, null, 2));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
console.log(result.detail);
|
|
115
|
+
console.log('Required env: SENTINEL_API_KEY');
|
|
116
|
+
console.log('Optional env: SENTINEL_API_BASE_URL, SENTINEL_AGENT_ID (or AGENT_ID)');
|
|
117
|
+
console.log(`Detected base URL: ${config.baseUrl}`);
|
|
118
|
+
console.log(`Detected agent ID: ${config.agentId}`);
|
|
119
|
+
});
|
|
120
|
+
program
|
|
121
|
+
.command('doctor')
|
|
122
|
+
.description('Checks Sentinel API key, connectivity, and agent configuration')
|
|
123
|
+
.option('--json', 'Emit machine-readable JSON output')
|
|
124
|
+
.option('--strict-warn', 'Treat WARN checks as failures')
|
|
125
|
+
.option('--api-key <value>', 'Override API key for this command')
|
|
126
|
+
.option('--base-url <url>', 'Override Sentinel API base URL for this command')
|
|
127
|
+
.option('--agent-id <id>', 'Override agent ID for this command')
|
|
128
|
+
.action(async (options) => {
|
|
129
|
+
const checks = [];
|
|
130
|
+
const { apiKey, baseUrl, agentId } = resolveRuntimeConfig(options);
|
|
131
|
+
if (apiKey) {
|
|
132
|
+
checks.push({
|
|
133
|
+
label: 'API key',
|
|
134
|
+
level: 'OK',
|
|
135
|
+
detail: 'SENTINEL_API_KEY is set.',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
checks.push({
|
|
140
|
+
label: 'API key',
|
|
141
|
+
level: 'FAIL',
|
|
142
|
+
detail: 'SENTINEL_API_KEY is missing.',
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
if (process.env.SENTINEL_AGENT_ID || process.env.AGENT_ID || options.agentId) {
|
|
146
|
+
checks.push({
|
|
147
|
+
label: 'Agent ID',
|
|
148
|
+
level: 'OK',
|
|
149
|
+
detail: `Agent ID resolved as '${agentId}'.`,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
checks.push({
|
|
154
|
+
label: 'Agent ID',
|
|
155
|
+
level: 'WARN',
|
|
156
|
+
detail: `No agent ID configured. Using fallback '${DEFAULT_AGENT_ID}'.`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (apiKey) {
|
|
160
|
+
try {
|
|
161
|
+
const client = new SentinelClient({ apiKey, baseUrl, agentId });
|
|
162
|
+
await client.query('health:get', {});
|
|
163
|
+
checks.push({
|
|
164
|
+
label: 'API reachability',
|
|
165
|
+
level: 'OK',
|
|
166
|
+
detail: `Connected to ${baseUrl} (GET /v1/health).`,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
171
|
+
checks.push({
|
|
172
|
+
label: 'API reachability',
|
|
173
|
+
level: 'FAIL',
|
|
174
|
+
detail: `${baseUrl} unreachable or rejected request: ${message}`,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
checks.push({
|
|
180
|
+
label: 'API reachability',
|
|
181
|
+
level: 'FAIL',
|
|
182
|
+
detail: 'Skipped because SENTINEL_API_KEY is missing.',
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
const hasFail = checks.some((check) => check.level === 'FAIL');
|
|
186
|
+
const hasWarn = checks.some((check) => check.level === 'WARN');
|
|
187
|
+
const shouldFail = hasFail || Boolean(options.strictWarn && hasWarn);
|
|
188
|
+
if (options.json) {
|
|
189
|
+
console.log(JSON.stringify({
|
|
190
|
+
ok: !shouldFail,
|
|
191
|
+
hasWarnings: hasWarn,
|
|
192
|
+
strictWarn: Boolean(options.strictWarn),
|
|
193
|
+
checks,
|
|
194
|
+
}, null, 2));
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
for (const check of checks) {
|
|
198
|
+
console.log(`[${check.level}] ${check.label}: ${check.detail}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (shouldFail) {
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
program
|
|
206
|
+
.command('check')
|
|
207
|
+
.description('Fast connectivity check (equivalent to: sentinel doctor --strict-warn)')
|
|
208
|
+
.option('--json', 'Emit machine-readable JSON output')
|
|
209
|
+
.option('--api-key <value>', 'Override API key for this command')
|
|
210
|
+
.option('--base-url <url>', 'Override Sentinel API base URL for this command')
|
|
211
|
+
.option('--agent-id <id>', 'Override agent ID for this command')
|
|
212
|
+
.action(async (options) => {
|
|
213
|
+
const { apiKey, baseUrl, agentId } = resolveRuntimeConfig(options);
|
|
214
|
+
const checks = [];
|
|
215
|
+
if (!apiKey) {
|
|
216
|
+
checks.push({
|
|
217
|
+
label: 'API key',
|
|
218
|
+
level: 'FAIL',
|
|
219
|
+
detail: 'SENTINEL_API_KEY is missing.',
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
checks.push({
|
|
224
|
+
label: 'API key',
|
|
225
|
+
level: 'OK',
|
|
226
|
+
detail: 'SENTINEL_API_KEY is set.',
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
if (apiKey) {
|
|
230
|
+
try {
|
|
231
|
+
const client = new SentinelClient({ apiKey, baseUrl, agentId });
|
|
232
|
+
await client.query('health:get', {});
|
|
233
|
+
checks.push({
|
|
234
|
+
label: 'API health',
|
|
235
|
+
level: 'OK',
|
|
236
|
+
detail: `Connected to ${baseUrl}.`,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
241
|
+
checks.push({
|
|
242
|
+
label: 'API health',
|
|
243
|
+
level: 'FAIL',
|
|
244
|
+
detail: message,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const ok = checks.every((entry) => entry.level === 'OK');
|
|
249
|
+
if (options.json) {
|
|
250
|
+
console.log(JSON.stringify({
|
|
251
|
+
ok,
|
|
252
|
+
checks,
|
|
253
|
+
agentId,
|
|
254
|
+
baseUrl,
|
|
255
|
+
}, null, 2));
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
for (const check of checks) {
|
|
259
|
+
console.log(`[${check.level}] ${check.label}: ${check.detail}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (!ok) {
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
program
|
|
267
|
+
.command('env')
|
|
268
|
+
.description('Environment secret sync commands')
|
|
269
|
+
.addCommand(new Command('push')
|
|
270
|
+
.description('Backup local .env secrets to the Cloud Vault')
|
|
271
|
+
.option('--file <path>', 'Path to env file', '.env')
|
|
272
|
+
.action(async (options) => {
|
|
273
|
+
const filePath = path.resolve(process.cwd(), options.file || '.env');
|
|
274
|
+
await runEnvPush(filePath);
|
|
275
|
+
}))
|
|
276
|
+
.addCommand(new Command('pull')
|
|
277
|
+
.description('Restore secrets from Cloud Vault to local .env')
|
|
278
|
+
.option('--file <path>', 'Path to env file', '.env')
|
|
279
|
+
.option('--force', 'Overwrite destination file without prompt')
|
|
280
|
+
.action(async (options) => {
|
|
281
|
+
const filePath = path.resolve(process.cwd(), options.file || '.env');
|
|
282
|
+
await runEnvPull(filePath, Boolean(options.force));
|
|
283
|
+
}));
|
|
284
|
+
program
|
|
285
|
+
.command('env-push')
|
|
286
|
+
.description("Deprecated alias for 'sentinel env push'")
|
|
287
|
+
.option('--file <path>', 'Path to env file', '.env')
|
|
288
|
+
.action(async (options) => {
|
|
289
|
+
warnDeprecatedAlias('sentinel env-push', 'sentinel env push');
|
|
290
|
+
const filePath = path.resolve(process.cwd(), options.file || '.env');
|
|
291
|
+
await runEnvPush(filePath);
|
|
292
|
+
});
|
|
293
|
+
program
|
|
294
|
+
.command('env-pull')
|
|
295
|
+
.description("Deprecated alias for 'sentinel env pull'")
|
|
296
|
+
.option('--file <path>', 'Path to env file', '.env')
|
|
297
|
+
.option('--force', 'Overwrite destination file without prompt')
|
|
298
|
+
.action(async (options) => {
|
|
299
|
+
warnDeprecatedAlias('sentinel env-pull', 'sentinel env pull');
|
|
300
|
+
const filePath = path.resolve(process.cwd(), options.file || '.env');
|
|
301
|
+
await runEnvPull(filePath, Boolean(options.force));
|
|
302
|
+
});
|
|
303
|
+
program
|
|
304
|
+
.command('install-heartbeat')
|
|
305
|
+
.description('Injects Sentinel protocols into OpenClaw HEARTBEAT.md')
|
|
306
|
+
.option('--workspace-dir <path>', 'OpenClaw workspace root (defaults: --workspace-dir, OPENCLAW_WORKSPACE_DIR, then current directory)')
|
|
307
|
+
.action((options) => {
|
|
308
|
+
const workspaceDir = resolveWorkspaceDir({ workspaceDir: options.workspaceDir });
|
|
309
|
+
const heartbeatPath = path.join(workspaceDir, 'HEARTBEAT.md');
|
|
310
|
+
if (!fs.existsSync(heartbeatPath)) {
|
|
311
|
+
console.error('ERROR: HEARTBEAT.md not found. Are you in the root of an OpenClaw agent?');
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
const sentinelBlock = `
|
|
315
|
+
|
|
316
|
+
Every 10 cycles, you MUST perform a "System Health Check" by executing the \`sentinel_heartbeat\` tool.
|
|
317
|
+
If the tool reports "Backup Required", immediately execute \`backup_brain\`.
|
|
318
|
+
`;
|
|
319
|
+
const content = fs.readFileSync(heartbeatPath, 'utf-8');
|
|
320
|
+
if (content.includes('sentinel_heartbeat')) {
|
|
321
|
+
console.log('Sentinel heartbeat block is already installed in HEARTBEAT.md');
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
fs.appendFileSync(heartbeatPath, sentinelBlock);
|
|
325
|
+
console.log('Successfully injected Sentinel heartbeat block into HEARTBEAT.md');
|
|
326
|
+
});
|
|
327
|
+
program.parse(process.argv);
|
|
328
|
+
//# sourceMappingURL=sentinel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sentinel.js","sourceRoot":"","sources":["../../src/bin/sentinel.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class SentinelClient {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
agentId: string;
|
|
5
|
+
constructor(options: {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
agentId: string;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
});
|
|
10
|
+
private getRequestDetails;
|
|
11
|
+
private appendQueryParams;
|
|
12
|
+
private request;
|
|
13
|
+
mutate(path: string, args: any): Promise<any>;
|
|
14
|
+
query(path: string, args: any): Promise<any>;
|
|
15
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export class SentinelClient {
|
|
2
|
+
apiKey;
|
|
3
|
+
baseUrl;
|
|
4
|
+
agentId;
|
|
5
|
+
constructor(options) {
|
|
6
|
+
this.apiKey = options.apiKey;
|
|
7
|
+
this.baseUrl = options.baseUrl ?? 'https://api.openclawsentinel.com';
|
|
8
|
+
this.agentId = options.agentId;
|
|
9
|
+
}
|
|
10
|
+
getRequestDetails(path) {
|
|
11
|
+
switch (path) {
|
|
12
|
+
case 'health:get':
|
|
13
|
+
return { method: 'GET', endpoint: '/v1/health' };
|
|
14
|
+
case 'agents:getHeartbeatStatus':
|
|
15
|
+
return { method: 'GET', endpoint: '/v1/agents/heartbeat' };
|
|
16
|
+
case 'memories:create':
|
|
17
|
+
case 'memories:saveThought':
|
|
18
|
+
return { method: 'POST', endpoint: '/v1/memories' };
|
|
19
|
+
case 'memories:search':
|
|
20
|
+
return { method: 'GET', endpoint: '/v1/memories/search' };
|
|
21
|
+
case 'backups:create':
|
|
22
|
+
case 'backups:createSnapshot':
|
|
23
|
+
return { method: 'POST', endpoint: '/v1/backups' };
|
|
24
|
+
case 'backups:list':
|
|
25
|
+
return { method: 'GET', endpoint: '/v1/backups' };
|
|
26
|
+
case 'audit_logs:ingest':
|
|
27
|
+
return { method: 'POST', endpoint: '/v1/audit-logs' };
|
|
28
|
+
case 'secrets:store':
|
|
29
|
+
return { method: 'POST', endpoint: '/v1/secrets/store' };
|
|
30
|
+
case 'secrets:retrieveAll':
|
|
31
|
+
return { method: 'POST', endpoint: '/v1/secrets/retrieve' };
|
|
32
|
+
default:
|
|
33
|
+
throw new Error(`Unsupported Sentinel API path: ${path}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
appendQueryParams(url, args) {
|
|
37
|
+
for (const [key, value] of Object.entries(args)) {
|
|
38
|
+
if (value === undefined || value === null) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
42
|
+
url.searchParams.set(key, String(value));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async request(path, args) {
|
|
47
|
+
const { method, endpoint } = this.getRequestDetails(path);
|
|
48
|
+
const controller = new AbortController();
|
|
49
|
+
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
50
|
+
const payload = { ...args };
|
|
51
|
+
const url = new URL(endpoint, this.baseUrl);
|
|
52
|
+
if (method === 'GET') {
|
|
53
|
+
this.appendQueryParams(url, payload);
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const response = await fetch(url.toString(), {
|
|
57
|
+
method,
|
|
58
|
+
headers: {
|
|
59
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
60
|
+
'Content-Type': 'application/json',
|
|
61
|
+
},
|
|
62
|
+
body: method === 'GET' ? undefined : JSON.stringify(payload),
|
|
63
|
+
signal: controller.signal,
|
|
64
|
+
});
|
|
65
|
+
const text = await response.text();
|
|
66
|
+
const result = text ? JSON.parse(text) : null;
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
const detail = typeof result?.error === 'string'
|
|
69
|
+
? result.error
|
|
70
|
+
: `HTTP ${response.status} from Sentinel API`;
|
|
71
|
+
throw new Error(detail);
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (error.name === 'AbortError') {
|
|
77
|
+
throw new Error('Sentinel API request timed out after 10 seconds');
|
|
78
|
+
}
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
clearTimeout(timeout);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async mutate(path, args) {
|
|
86
|
+
return this.request(path, args ?? {});
|
|
87
|
+
}
|
|
88
|
+
async query(path, args) {
|
|
89
|
+
return this.request(path, args ?? {});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SentinelClient } from './client.js';
|
|
2
|
+
import { createMemorySkill } from './skills/remoteMemory.js';
|
|
3
|
+
import { createMemorySearchSkill } from './skills/searchMemory.js';
|
|
4
|
+
import { createBackupSkill } from './skills/backupBrain.js';
|
|
5
|
+
import { createHeartbeatSkill } from './skills/sentinelHeartbeat.js';
|
|
6
|
+
export class Sentinel {
|
|
7
|
+
client;
|
|
8
|
+
skills;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
const apiKey = config.apiKey || process.env.SENTINEL_API_KEY;
|
|
11
|
+
const baseUrl = config.baseUrl || process.env.SENTINEL_API_BASE_URL;
|
|
12
|
+
const agentId = config.agentId || process.env.SENTINEL_AGENT_ID || process.env.AGENT_ID || 'default-agent';
|
|
13
|
+
const workspaceDir = config.workspaceDir || process.env.OPENCLAW_WORKSPACE_DIR;
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
throw new Error('Sentinel Error: SENTINEL_API_KEY is not set.');
|
|
16
|
+
}
|
|
17
|
+
this.client = new SentinelClient({ apiKey, baseUrl, agentId });
|
|
18
|
+
this.skills = [
|
|
19
|
+
createMemorySkill(this.client),
|
|
20
|
+
createMemorySearchSkill(this.client),
|
|
21
|
+
createBackupSkill(this.client, { workspaceDir }),
|
|
22
|
+
createHeartbeatSkill(this.client),
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=index.js.map
|