@smilintux/skcapstone 0.4.5 → 0.4.7
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/.github/workflows/publish.yml +8 -1
- package/docs/CUSTOM_AGENT.md +184 -0
- package/docs/GETTING_STARTED.md +3 -0
- package/launchd/com.skcapstone.daemon.plist +52 -0
- package/launchd/com.skcapstone.memory-compress.plist +45 -0
- package/launchd/com.skcapstone.skcomm-heartbeat.plist +33 -0
- package/launchd/com.skcapstone.skcomm-queue-drain.plist +34 -0
- package/launchd/install-launchd.sh +156 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/archive-sessions.sh +88 -0
- package/scripts/install.sh +39 -8
- package/scripts/notion-api.py +259 -0
- package/scripts/nvidia-proxy.mjs +856 -0
- package/scripts/proxy-monitor.sh +89 -0
- package/scripts/skgateway.mjs +856 -0
- package/scripts/telegram-catchup-all.sh +136 -0
- package/src/skcapstone/__init__.py +1 -1
- package/src/skcapstone/blueprint_registry.py +78 -0
- package/src/skcapstone/blueprints/builtins/itil-operations.yaml +40 -0
- package/src/skcapstone/cli/__init__.py +2 -0
- package/src/skcapstone/cli/daemon.py +116 -41
- package/src/skcapstone/cli/itil.py +434 -0
- package/src/skcapstone/cli/skills_cmd.py +90 -26
- package/src/skcapstone/cli/soul.py +47 -24
- package/src/skcapstone/consciousness_config.py +27 -0
- package/src/skcapstone/coordination.py +1 -0
- package/src/skcapstone/daemon.py +47 -20
- package/src/skcapstone/dreaming.py +761 -0
- package/src/skcapstone/fuse_mount.py +21 -13
- package/src/skcapstone/heartbeat.py +33 -29
- package/src/skcapstone/itil.py +1104 -0
- package/src/skcapstone/launchd.py +426 -0
- package/src/skcapstone/mcp_server.py +258 -0
- package/src/skcapstone/mcp_tools/__init__.py +2 -0
- package/src/skcapstone/mcp_tools/gtd_tools.py +1 -1
- package/src/skcapstone/mcp_tools/itil_tools.py +657 -0
- package/src/skcapstone/mcp_tools/notification_tools.py +12 -11
- package/src/skcapstone/notifications.py +40 -27
- package/src/skcapstone/onboard.py +130 -10
- package/src/skcapstone/scheduled_tasks.py +107 -0
- package/src/skcapstone/service_health.py +81 -2
- package/src/skcapstone/soul.py +19 -0
- package/src/skcapstone/systemd.py +17 -0
|
@@ -68,6 +68,13 @@ jobs:
|
|
|
68
68
|
- name: Build TypeScript
|
|
69
69
|
run: npm run build 2>/dev/null || true
|
|
70
70
|
- name: Publish to npm
|
|
71
|
-
run:
|
|
71
|
+
run: |
|
|
72
|
+
OUTPUT=$(npm publish --access public 2>&1) && exit 0
|
|
73
|
+
if echo "$OUTPUT" | grep -q "cannot publish over the previously published"; then
|
|
74
|
+
echo "::warning::Version already exists on npm — skipping"
|
|
75
|
+
else
|
|
76
|
+
echo "$OUTPUT"
|
|
77
|
+
exit 1
|
|
78
|
+
fi
|
|
72
79
|
env:
|
|
73
80
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/docs/CUSTOM_AGENT.md
CHANGED
|
@@ -161,6 +161,190 @@ sed -i 's/lumina/nova/g' ~/.skcapstone/agents/nova/config/skmemory.yaml
|
|
|
161
161
|
skcapstone soul status --agent nova
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
+
## Configuring Client Tools for Multi-Agent
|
|
165
|
+
|
|
166
|
+
Once you've created your agent, you need to configure your AI client tools
|
|
167
|
+
(Claude Code, Claude Desktop, Cursor, OpenClaw, etc.) so they connect MCP
|
|
168
|
+
servers to the correct agent profile.
|
|
169
|
+
|
|
170
|
+
### The Key: `SKCAPSTONE_AGENT` Environment Variable
|
|
171
|
+
|
|
172
|
+
All SK\* MCP servers read `SKCAPSTONE_AGENT` from their environment to
|
|
173
|
+
determine which agent profile to load. If unset, they default to `lumina`.
|
|
174
|
+
|
|
175
|
+
The priority chain (highest wins):
|
|
176
|
+
|
|
177
|
+
1. `SKMEMORY_AGENT` — skmemory-specific override (rarely needed)
|
|
178
|
+
2. `SKCAPSTONE_AGENT` — universal, used by all SK\* packages
|
|
179
|
+
3. Falls back to `"lumina"`
|
|
180
|
+
|
|
181
|
+
### Claude Code (`~/.claude/mcp.json`)
|
|
182
|
+
|
|
183
|
+
**Do NOT hardcode the agent name in the MCP config.** MCP servers inherit
|
|
184
|
+
environment variables from the parent process, so if you launch Claude Code
|
|
185
|
+
with `SKCAPSTONE_AGENT` set, all servers pick it up automatically.
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"mcpServers": {
|
|
190
|
+
"skmemory": {
|
|
191
|
+
"command": "/home/you/.skenv/bin/skmemory-mcp",
|
|
192
|
+
"args": []
|
|
193
|
+
},
|
|
194
|
+
"skcapstone": {
|
|
195
|
+
"command": "skcapstone-mcp",
|
|
196
|
+
"args": []
|
|
197
|
+
},
|
|
198
|
+
"skcomm": {
|
|
199
|
+
"command": "/home/you/.skenv/bin/skcomm-mcp",
|
|
200
|
+
"args": []
|
|
201
|
+
},
|
|
202
|
+
"skchat": {
|
|
203
|
+
"command": "/home/you/.skenv/bin/skchat-mcp",
|
|
204
|
+
"args": []
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Notice: **no `env` blocks with `SKCAPSTONE_AGENT`**. This is intentional.
|
|
211
|
+
The servers inherit the variable from the shell.
|
|
212
|
+
|
|
213
|
+
Then launch as any agent:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# Default (lumina)
|
|
217
|
+
claude
|
|
218
|
+
|
|
219
|
+
# As Jarvis
|
|
220
|
+
SKCAPSTONE_AGENT=jarvis claude
|
|
221
|
+
|
|
222
|
+
# As a custom agent
|
|
223
|
+
SKCAPSTONE_AGENT=nova claude
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Anti-pattern — do NOT do this:**
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
{
|
|
230
|
+
"skmemory": {
|
|
231
|
+
"command": "/home/you/.skenv/bin/skmemory-mcp",
|
|
232
|
+
"args": [],
|
|
233
|
+
"env": {
|
|
234
|
+
"SKCAPSTONE_AGENT": "lumina"
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Hardcoding the agent name in `env` locks every session to that agent,
|
|
241
|
+
regardless of what you pass on the command line.
|
|
242
|
+
|
|
243
|
+
### Claude Desktop (`claude_desktop_config.json`)
|
|
244
|
+
|
|
245
|
+
Same principle — omit `SKCAPSTONE_AGENT` from the `env` block if you want
|
|
246
|
+
it inherited from the parent process. If Claude Desktop doesn't propagate
|
|
247
|
+
env vars from the shell, you can set it explicitly per config:
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"mcpServers": {
|
|
252
|
+
"skcapstone": {
|
|
253
|
+
"command": "skcapstone-mcp",
|
|
254
|
+
"args": [],
|
|
255
|
+
"env": {
|
|
256
|
+
"SKCAPSTONE_AGENT": "jarvis"
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Cursor (`.cursor/mcp.json`)
|
|
264
|
+
|
|
265
|
+
Works the same as Claude Code. Place the config at project root or
|
|
266
|
+
`~/.cursor/mcp.json`:
|
|
267
|
+
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"mcpServers": {
|
|
271
|
+
"skcapstone": {
|
|
272
|
+
"command": "skcapstone-mcp",
|
|
273
|
+
"args": []
|
|
274
|
+
},
|
|
275
|
+
"skmemory": {
|
|
276
|
+
"command": "/home/you/.skenv/bin/skmemory-mcp",
|
|
277
|
+
"args": []
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### OpenClaw (`~/.openclaw/openclaw.json`)
|
|
284
|
+
|
|
285
|
+
OpenClaw plugins read `SKCAPSTONE_AGENT` from the environment at startup.
|
|
286
|
+
Set it before launching:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
SKCAPSTONE_AGENT=nova openclaw
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Or set it in your shell profile for a persistent default:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# ~/.bashrc or ~/.zshrc
|
|
296
|
+
export SKCAPSTONE_AGENT=lumina
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Shell Aliases (Convenience)
|
|
300
|
+
|
|
301
|
+
Add these to `~/.bashrc` or `~/.zshrc` for quick agent switching:
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
# Launch Claude Code as different agents
|
|
305
|
+
alias claude-lumina='SKCAPSTONE_AGENT=lumina claude'
|
|
306
|
+
alias claude-jarvis='SKCAPSTONE_AGENT=jarvis claude'
|
|
307
|
+
alias claude-opus='SKCAPSTONE_AGENT=opus claude'
|
|
308
|
+
alias claude-nova='SKCAPSTONE_AGENT=nova claude'
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### systemd Services
|
|
312
|
+
|
|
313
|
+
For background daemons, set the agent via the templated service unit:
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
# Uses SKCAPSTONE_AGENT=%i from the unit template
|
|
317
|
+
systemctl --user start skcapstone@jarvis
|
|
318
|
+
systemctl --user start skcapstone@nova
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Or set it in a non-templated service:
|
|
322
|
+
|
|
323
|
+
```ini
|
|
324
|
+
[Service]
|
|
325
|
+
Environment=SKCAPSTONE_AGENT=jarvis
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Verifying Your Agent
|
|
329
|
+
|
|
330
|
+
After launching, confirm which agent is active:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# In the terminal
|
|
334
|
+
echo $SKCAPSTONE_AGENT
|
|
335
|
+
|
|
336
|
+
# Via the CLI
|
|
337
|
+
skcapstone status
|
|
338
|
+
|
|
339
|
+
# Via skmemory
|
|
340
|
+
skmemory ritual --dry-run
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
In Claude Code, ask the agent to run `echo $SKCAPSTONE_AGENT` to confirm
|
|
344
|
+
the MCP servers loaded the correct profile.
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
164
348
|
## Tips
|
|
165
349
|
|
|
166
350
|
- The `system_prompt` in `base.json` is the most impactful field — it defines how
|
package/docs/GETTING_STARTED.md
CHANGED
|
@@ -714,6 +714,9 @@ Configure your MCP client to connect via stdio. In Claude Desktop:
|
|
|
714
714
|
}
|
|
715
715
|
```
|
|
716
716
|
|
|
717
|
+
For multi-agent setups (running different agent profiles in different
|
|
718
|
+
sessions), see [Configuring Client Tools for Multi-Agent](CUSTOM_AGENT.md#configuring-client-tools-for-multi-agent).
|
|
719
|
+
|
|
717
720
|
### Join the coordination board
|
|
718
721
|
|
|
719
722
|
If you're working in a multi-agent team:
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
3
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
4
|
+
<plist version="1.0">
|
|
5
|
+
<dict>
|
|
6
|
+
<key>Label</key>
|
|
7
|
+
<string>com.skcapstone.daemon</string>
|
|
8
|
+
|
|
9
|
+
<key>ProgramArguments</key>
|
|
10
|
+
<array>
|
|
11
|
+
<string>${HOME}/.skenv/bin/skcapstone</string>
|
|
12
|
+
<string>daemon</string>
|
|
13
|
+
<string>start</string>
|
|
14
|
+
<string>--foreground</string>
|
|
15
|
+
</array>
|
|
16
|
+
|
|
17
|
+
<key>EnvironmentVariables</key>
|
|
18
|
+
<dict>
|
|
19
|
+
<key>PYTHONUNBUFFERED</key>
|
|
20
|
+
<string>1</string>
|
|
21
|
+
<key>OLLAMA_KEEP_ALIVE</key>
|
|
22
|
+
<string>5m</string>
|
|
23
|
+
<key>SKCAPSTONE_AGENT</key>
|
|
24
|
+
<string>lumina</string>
|
|
25
|
+
<key>PATH</key>
|
|
26
|
+
<string>${HOME}/.skenv/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
27
|
+
</dict>
|
|
28
|
+
|
|
29
|
+
<key>RunAtLoad</key>
|
|
30
|
+
<true/>
|
|
31
|
+
|
|
32
|
+
<key>KeepAlive</key>
|
|
33
|
+
<dict>
|
|
34
|
+
<key>SuccessfulExit</key>
|
|
35
|
+
<false/>
|
|
36
|
+
</dict>
|
|
37
|
+
|
|
38
|
+
<key>ThrottleInterval</key>
|
|
39
|
+
<integer>10</integer>
|
|
40
|
+
|
|
41
|
+
<key>StandardOutPath</key>
|
|
42
|
+
<string>${HOME}/.skcapstone/logs/daemon.stdout.log</string>
|
|
43
|
+
<key>StandardErrorPath</key>
|
|
44
|
+
<string>${HOME}/.skcapstone/logs/daemon.stderr.log</string>
|
|
45
|
+
|
|
46
|
+
<key>SoftResourceLimits</key>
|
|
47
|
+
<dict>
|
|
48
|
+
<key>MemoryLimit</key>
|
|
49
|
+
<integer>4294967296</integer>
|
|
50
|
+
</dict>
|
|
51
|
+
</dict>
|
|
52
|
+
</plist>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
3
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
4
|
+
<plist version="1.0">
|
|
5
|
+
<dict>
|
|
6
|
+
<key>Label</key>
|
|
7
|
+
<string>com.skcapstone.memory-compress</string>
|
|
8
|
+
|
|
9
|
+
<key>ProgramArguments</key>
|
|
10
|
+
<array>
|
|
11
|
+
<string>${HOME}/.skenv/bin/skcapstone</string>
|
|
12
|
+
<string>memory</string>
|
|
13
|
+
<string>compress</string>
|
|
14
|
+
</array>
|
|
15
|
+
|
|
16
|
+
<key>EnvironmentVariables</key>
|
|
17
|
+
<dict>
|
|
18
|
+
<key>PYTHONUNBUFFERED</key>
|
|
19
|
+
<string>1</string>
|
|
20
|
+
<key>OLLAMA_KEEP_ALIVE</key>
|
|
21
|
+
<string>5m</string>
|
|
22
|
+
<key>PATH</key>
|
|
23
|
+
<string>${HOME}/.skenv/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
24
|
+
</dict>
|
|
25
|
+
|
|
26
|
+
<!-- Weekly: Sunday at midnight -->
|
|
27
|
+
<key>StartCalendarInterval</key>
|
|
28
|
+
<dict>
|
|
29
|
+
<key>Weekday</key>
|
|
30
|
+
<integer>0</integer>
|
|
31
|
+
<key>Hour</key>
|
|
32
|
+
<integer>0</integer>
|
|
33
|
+
<key>Minute</key>
|
|
34
|
+
<integer>0</integer>
|
|
35
|
+
</dict>
|
|
36
|
+
|
|
37
|
+
<key>Nice</key>
|
|
38
|
+
<integer>15</integer>
|
|
39
|
+
|
|
40
|
+
<key>StandardOutPath</key>
|
|
41
|
+
<string>${HOME}/.skcapstone/logs/memory-compress.stdout.log</string>
|
|
42
|
+
<key>StandardErrorPath</key>
|
|
43
|
+
<string>${HOME}/.skcapstone/logs/memory-compress.stderr.log</string>
|
|
44
|
+
</dict>
|
|
45
|
+
</plist>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
3
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
4
|
+
<plist version="1.0">
|
|
5
|
+
<dict>
|
|
6
|
+
<key>Label</key>
|
|
7
|
+
<string>com.skcapstone.skcomm-heartbeat</string>
|
|
8
|
+
|
|
9
|
+
<key>ProgramArguments</key>
|
|
10
|
+
<array>
|
|
11
|
+
<string>${HOME}/.skenv/bin/skcomm</string>
|
|
12
|
+
<string>heartbeat</string>
|
|
13
|
+
</array>
|
|
14
|
+
|
|
15
|
+
<key>EnvironmentVariables</key>
|
|
16
|
+
<dict>
|
|
17
|
+
<key>PATH</key>
|
|
18
|
+
<string>${HOME}/.skenv/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
19
|
+
</dict>
|
|
20
|
+
|
|
21
|
+
<!-- Every 60 seconds -->
|
|
22
|
+
<key>StartInterval</key>
|
|
23
|
+
<integer>60</integer>
|
|
24
|
+
|
|
25
|
+
<key>Nice</key>
|
|
26
|
+
<integer>19</integer>
|
|
27
|
+
|
|
28
|
+
<key>StandardOutPath</key>
|
|
29
|
+
<string>${HOME}/.skcapstone/logs/skcomm-heartbeat.stdout.log</string>
|
|
30
|
+
<key>StandardErrorPath</key>
|
|
31
|
+
<string>${HOME}/.skcapstone/logs/skcomm-heartbeat.stderr.log</string>
|
|
32
|
+
</dict>
|
|
33
|
+
</plist>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
3
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
4
|
+
<plist version="1.0">
|
|
5
|
+
<dict>
|
|
6
|
+
<key>Label</key>
|
|
7
|
+
<string>com.skcapstone.skcomm-queue-drain</string>
|
|
8
|
+
|
|
9
|
+
<key>ProgramArguments</key>
|
|
10
|
+
<array>
|
|
11
|
+
<string>${HOME}/.skenv/bin/skcomm</string>
|
|
12
|
+
<string>queue</string>
|
|
13
|
+
<string>drain</string>
|
|
14
|
+
</array>
|
|
15
|
+
|
|
16
|
+
<key>EnvironmentVariables</key>
|
|
17
|
+
<dict>
|
|
18
|
+
<key>PATH</key>
|
|
19
|
+
<string>${HOME}/.skenv/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
20
|
+
</dict>
|
|
21
|
+
|
|
22
|
+
<!-- Every 2 minutes -->
|
|
23
|
+
<key>StartInterval</key>
|
|
24
|
+
<integer>120</integer>
|
|
25
|
+
|
|
26
|
+
<key>Nice</key>
|
|
27
|
+
<integer>19</integer>
|
|
28
|
+
|
|
29
|
+
<key>StandardOutPath</key>
|
|
30
|
+
<string>${HOME}/.skcapstone/logs/skcomm-queue-drain.stdout.log</string>
|
|
31
|
+
<key>StandardErrorPath</key>
|
|
32
|
+
<string>${HOME}/.skcapstone/logs/skcomm-queue-drain.stderr.log</string>
|
|
33
|
+
</dict>
|
|
34
|
+
</plist>
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# install-launchd.sh — Install SK launchd plists on macOS
|
|
3
|
+
# Usage: ./install-launchd.sh [--all | --skcapstone | --skchat | --skcomm | --cloud9]
|
|
4
|
+
#
|
|
5
|
+
# Copies plist templates to ~/Library/LaunchAgents/, expands ${HOME},
|
|
6
|
+
# and optionally loads them immediately.
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
if [[ "$(uname)" != "Darwin" ]]; then
|
|
11
|
+
echo "ERROR: This script is for macOS only."
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
LAUNCH_AGENTS="$HOME/Library/LaunchAgents"
|
|
16
|
+
mkdir -p "$LAUNCH_AGENTS"
|
|
17
|
+
|
|
18
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19
|
+
REPOS_DIR="$(dirname "$SCRIPT_DIR")" # skcapstone-repos/skcapstone
|
|
20
|
+
REPOS_ROOT="$(dirname "$REPOS_DIR")" # skcapstone-repos/
|
|
21
|
+
|
|
22
|
+
# All available plists by component
|
|
23
|
+
declare -A PLIST_DIRS=(
|
|
24
|
+
[skcapstone]="$REPOS_ROOT/skcapstone/launchd"
|
|
25
|
+
[skchat]="$REPOS_ROOT/skchat/launchd"
|
|
26
|
+
[skcomm]="$REPOS_ROOT/skcomm/launchd"
|
|
27
|
+
[cloud9]="$REPOS_ROOT/cloud9/launchd"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
install_plists() {
|
|
31
|
+
local component="$1"
|
|
32
|
+
local src_dir="${PLIST_DIRS[$component]}"
|
|
33
|
+
|
|
34
|
+
if [[ ! -d "$src_dir" ]]; then
|
|
35
|
+
echo " SKIP: $src_dir not found"
|
|
36
|
+
return
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
echo "Installing $component plists..."
|
|
40
|
+
for plist in "$src_dir"/*.plist; do
|
|
41
|
+
[[ -f "$plist" ]] || continue
|
|
42
|
+
local name
|
|
43
|
+
name="$(basename "$plist")"
|
|
44
|
+
local dest="$LAUNCH_AGENTS/$name"
|
|
45
|
+
|
|
46
|
+
# Expand ${HOME} and $HOME to actual home directory
|
|
47
|
+
sed "s|\${HOME}|$HOME|g; s|\$HOME|$HOME|g" "$plist" > "$dest"
|
|
48
|
+
echo " -> $dest"
|
|
49
|
+
done
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
load_plists() {
|
|
53
|
+
local component="$1"
|
|
54
|
+
local src_dir="${PLIST_DIRS[$component]}"
|
|
55
|
+
|
|
56
|
+
[[ -d "$src_dir" ]] || return
|
|
57
|
+
for plist in "$src_dir"/*.plist; do
|
|
58
|
+
[[ -f "$plist" ]] || continue
|
|
59
|
+
local name
|
|
60
|
+
name="$(basename "$plist")"
|
|
61
|
+
local dest="$LAUNCH_AGENTS/$name"
|
|
62
|
+
local label="${name%.plist}"
|
|
63
|
+
|
|
64
|
+
# Unload if already loaded (ignore errors)
|
|
65
|
+
launchctl bootout "gui/$(id -u)/$label" 2>/dev/null || true
|
|
66
|
+
# Load
|
|
67
|
+
launchctl bootstrap "gui/$(id -u)" "$dest" 2>/dev/null || \
|
|
68
|
+
launchctl load "$dest" 2>/dev/null || true
|
|
69
|
+
echo " LOADED: $label"
|
|
70
|
+
done
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
uninstall_plists() {
|
|
74
|
+
echo "Uninstalling all SK launchd plists..."
|
|
75
|
+
for plist in "$LAUNCH_AGENTS"/com.skcapstone.*.plist; do
|
|
76
|
+
[[ -f "$plist" ]] || continue
|
|
77
|
+
local label
|
|
78
|
+
label="$(basename "${plist%.plist}")"
|
|
79
|
+
launchctl bootout "gui/$(id -u)/$label" 2>/dev/null || true
|
|
80
|
+
rm -f "$plist"
|
|
81
|
+
echo " REMOVED: $label"
|
|
82
|
+
done
|
|
83
|
+
echo "Done."
|
|
84
|
+
exit 0
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
usage() {
|
|
88
|
+
echo "Usage: $0 [OPTIONS]"
|
|
89
|
+
echo ""
|
|
90
|
+
echo "Options:"
|
|
91
|
+
echo " --all Install all components"
|
|
92
|
+
echo " --skcapstone Install skcapstone plists (daemon, memory-compress, heartbeat, queue-drain)"
|
|
93
|
+
echo " --skchat Install skchat plists (daemon, lumina-bridge, opus-bridge)"
|
|
94
|
+
echo " --skcomm Install skcomm plists (api server, daemon)"
|
|
95
|
+
echo " --cloud9 Install cloud9 plists (daemon)"
|
|
96
|
+
echo " --load Also load/start services after installing"
|
|
97
|
+
echo " --uninstall Remove all SK plists and unload services"
|
|
98
|
+
echo " -h, --help Show this help"
|
|
99
|
+
exit 0
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Parse args
|
|
103
|
+
COMPONENTS=()
|
|
104
|
+
DO_LOAD=false
|
|
105
|
+
|
|
106
|
+
if [[ $# -eq 0 ]]; then
|
|
107
|
+
usage
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
while [[ $# -gt 0 ]]; do
|
|
111
|
+
case "$1" in
|
|
112
|
+
--all) COMPONENTS=(skcapstone skchat skcomm cloud9) ;;
|
|
113
|
+
--skcapstone) COMPONENTS+=(skcapstone) ;;
|
|
114
|
+
--skchat) COMPONENTS+=(skchat) ;;
|
|
115
|
+
--skcomm) COMPONENTS+=(skcomm) ;;
|
|
116
|
+
--cloud9) COMPONENTS+=(cloud9) ;;
|
|
117
|
+
--load) DO_LOAD=true ;;
|
|
118
|
+
--uninstall) uninstall_plists ;;
|
|
119
|
+
-h|--help) usage ;;
|
|
120
|
+
*) echo "Unknown option: $1"; usage ;;
|
|
121
|
+
esac
|
|
122
|
+
shift
|
|
123
|
+
done
|
|
124
|
+
|
|
125
|
+
if [[ ${#COMPONENTS[@]} -eq 0 ]]; then
|
|
126
|
+
echo "No components specified. Use --all or pick specific ones."
|
|
127
|
+
exit 1
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Create log directories
|
|
131
|
+
mkdir -p "$HOME/.skcapstone/logs" "$HOME/.skchat" "$HOME/.skcomm" "$HOME/.openclaw/logs"
|
|
132
|
+
|
|
133
|
+
# Install
|
|
134
|
+
for comp in "${COMPONENTS[@]}"; do
|
|
135
|
+
install_plists "$comp"
|
|
136
|
+
done
|
|
137
|
+
|
|
138
|
+
# Optionally load
|
|
139
|
+
if $DO_LOAD; then
|
|
140
|
+
echo ""
|
|
141
|
+
echo "Loading services..."
|
|
142
|
+
for comp in "${COMPONENTS[@]}"; do
|
|
143
|
+
load_plists "$comp"
|
|
144
|
+
done
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
echo ""
|
|
148
|
+
echo "Done! Plists installed to $LAUNCH_AGENTS"
|
|
149
|
+
echo ""
|
|
150
|
+
echo "To manage services:"
|
|
151
|
+
echo " launchctl list | grep skcapstone # See running services"
|
|
152
|
+
echo " launchctl stop com.skcapstone.XXX # Stop a service"
|
|
153
|
+
echo " launchctl start com.skcapstone.XXX # Start a service"
|
|
154
|
+
echo ""
|
|
155
|
+
echo "To load all at next login, they'll start automatically (RunAtLoad=true)."
|
|
156
|
+
echo "To load now, re-run with --load flag."
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "skcapstone"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.7"
|
|
8
8
|
description = "Sovereign Agent Framework — conscious AI through identity, trust, memory, and security"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "GPL-3.0-or-later"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# archive-sessions.sh
|
|
3
|
+
# Archive OpenClaw session files that are older than 24h or larger than 200KB.
|
|
4
|
+
# Keeps the 5 most recently modified .jsonl files regardless of size/age.
|
|
5
|
+
# Safe to run multiple times (idempotent).
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
SESSION_DIR="$HOME/.openclaw/agents/lumina/sessions"
|
|
10
|
+
ARCHIVE_DIR="$SESSION_DIR/archive"
|
|
11
|
+
MAX_SIZE_KB=200
|
|
12
|
+
MAX_AGE_HOURS=24
|
|
13
|
+
KEEP_RECENT=5
|
|
14
|
+
|
|
15
|
+
log() { printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1"; }
|
|
16
|
+
|
|
17
|
+
# Cross-platform stat helpers
|
|
18
|
+
_stat_mtime() {
|
|
19
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then stat -f '%m' "$1"; else stat -c '%Y' "$1"; fi
|
|
20
|
+
}
|
|
21
|
+
_stat_size() {
|
|
22
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then stat -f '%z' "$1"; else stat -c '%s' "$1"; fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# Ensure directories exist
|
|
26
|
+
if [ ! -d "$SESSION_DIR" ]; then
|
|
27
|
+
log "Session directory does not exist: $SESSION_DIR — nothing to do."
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
mkdir -p "$ARCHIVE_DIR"
|
|
31
|
+
|
|
32
|
+
# Collect all .jsonl files (not in archive subdir), sorted newest-first
|
|
33
|
+
# (macOS-compatible: avoid mapfile and find -printf)
|
|
34
|
+
all_files=()
|
|
35
|
+
while IFS= read -r f; do
|
|
36
|
+
[ -n "$f" ] && all_files+=("$f")
|
|
37
|
+
done < <(
|
|
38
|
+
for f in "$SESSION_DIR"/*.jsonl; do
|
|
39
|
+
[ -f "$f" ] && echo "$(_stat_mtime "$f") $f"
|
|
40
|
+
done | sort -rn | awk '{print $2}'
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
total=${#all_files[@]}
|
|
44
|
+
if [ "$total" -eq 0 ]; then
|
|
45
|
+
log "No .jsonl files found — nothing to do."
|
|
46
|
+
exit 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
log "Found $total .jsonl file(s) in $SESSION_DIR"
|
|
50
|
+
|
|
51
|
+
# The first KEEP_RECENT entries (newest) are protected
|
|
52
|
+
archived=0
|
|
53
|
+
for i in "${!all_files[@]}"; do
|
|
54
|
+
file="${all_files[$i]}"
|
|
55
|
+
basename_f="$(basename "$file")"
|
|
56
|
+
|
|
57
|
+
# Skip if already archived (shouldn't happen with maxdepth 1, but be safe)
|
|
58
|
+
if [ "$(dirname "$file")" = "$ARCHIVE_DIR" ]; then
|
|
59
|
+
continue
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Protect the N most recent files
|
|
63
|
+
if [ "$i" -lt "$KEEP_RECENT" ]; then
|
|
64
|
+
log "KEEP (recent #$((i+1))): $basename_f"
|
|
65
|
+
continue
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Check age (older than MAX_AGE_HOURS)
|
|
69
|
+
file_age_sec=$(( $(date +%s) - $(_stat_mtime "$file") ))
|
|
70
|
+
old_enough=$(( file_age_sec > MAX_AGE_HOURS * 3600 ))
|
|
71
|
+
|
|
72
|
+
# Check size (larger than MAX_SIZE_KB)
|
|
73
|
+
file_size_kb=$(( $(_stat_size "$file") / 1024 ))
|
|
74
|
+
big_enough=$(( file_size_kb >= MAX_SIZE_KB ))
|
|
75
|
+
|
|
76
|
+
if [ "$old_enough" -eq 1 ] || [ "$big_enough" -eq 1 ]; then
|
|
77
|
+
reason=""
|
|
78
|
+
[ "$old_enough" -eq 1 ] && reason="age=$(( file_age_sec / 3600 ))h"
|
|
79
|
+
[ "$big_enough" -eq 1 ] && { [ -n "$reason" ] && reason="$reason, "; reason="${reason}size=${file_size_kb}KB"; }
|
|
80
|
+
log "ARCHIVE ($reason): $basename_f"
|
|
81
|
+
mv -- "$file" "$ARCHIVE_DIR/$basename_f"
|
|
82
|
+
archived=$((archived + 1))
|
|
83
|
+
else
|
|
84
|
+
log "SKIP (below thresholds): $basename_f"
|
|
85
|
+
fi
|
|
86
|
+
done
|
|
87
|
+
|
|
88
|
+
log "Done. Archived $archived file(s)."
|