@smilintux/skcapstone 0.4.6 → 0.5.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.
Files changed (77) hide show
  1. package/.github/workflows/publish.yml +8 -1
  2. package/docs/CUSTOM_AGENT.md +184 -0
  3. package/docs/GETTING_STARTED.md +3 -0
  4. package/launchd/com.skcapstone.daemon.plist +52 -0
  5. package/launchd/com.skcapstone.memory-compress.plist +45 -0
  6. package/launchd/com.skcapstone.skcomm-heartbeat.plist +33 -0
  7. package/launchd/com.skcapstone.skcomm-queue-drain.plist +34 -0
  8. package/launchd/install-launchd.sh +156 -0
  9. package/package.json +1 -1
  10. package/pyproject.toml +1 -1
  11. package/scripts/archive-sessions.sh +88 -0
  12. package/scripts/install.sh +39 -8
  13. package/scripts/notion-api.py +259 -0
  14. package/scripts/nvidia-proxy.mjs +878 -0
  15. package/scripts/proxy-monitor.sh +89 -0
  16. package/scripts/refresh-anthropic-token.sh +94 -0
  17. package/scripts/skgateway.mjs +856 -0
  18. package/scripts/telegram-catchup-all.sh +136 -0
  19. package/scripts/watch-anthropic-token.sh +117 -0
  20. package/src/skcapstone/__init__.py +1 -1
  21. package/src/skcapstone/_cli_monolith.py +4 -4
  22. package/src/skcapstone/api.py +36 -35
  23. package/src/skcapstone/auction.py +8 -8
  24. package/src/skcapstone/blueprint_registry.py +2 -2
  25. package/src/skcapstone/blueprints/builtins/itil-operations.yaml +40 -0
  26. package/src/skcapstone/brain_first.py +238 -0
  27. package/src/skcapstone/chat.py +4 -4
  28. package/src/skcapstone/cli/__init__.py +2 -0
  29. package/src/skcapstone/cli/agents_spawner.py +5 -2
  30. package/src/skcapstone/cli/chat.py +5 -2
  31. package/src/skcapstone/cli/consciousness.py +5 -2
  32. package/src/skcapstone/cli/daemon.py +116 -41
  33. package/src/skcapstone/cli/itil.py +434 -0
  34. package/src/skcapstone/cli/memory.py +4 -4
  35. package/src/skcapstone/cli/skills_cmd.py +2 -2
  36. package/src/skcapstone/cli/soul.py +5 -2
  37. package/src/skcapstone/cli/status.py +11 -8
  38. package/src/skcapstone/cli/upgrade_cmd.py +7 -4
  39. package/src/skcapstone/cli/watch_cmd.py +9 -6
  40. package/src/skcapstone/config_validator.py +7 -4
  41. package/src/skcapstone/consciousness_config.py +27 -0
  42. package/src/skcapstone/consciousness_loop.py +20 -18
  43. package/src/skcapstone/coordination.py +6 -2
  44. package/src/skcapstone/daemon.py +51 -42
  45. package/src/skcapstone/dashboard.py +8 -8
  46. package/src/skcapstone/defaults/lumina/config/claude-hooks.md +42 -0
  47. package/src/skcapstone/doctor.py +5 -2
  48. package/src/skcapstone/dreaming.py +1440 -0
  49. package/src/skcapstone/emotion_tracker.py +2 -2
  50. package/src/skcapstone/export.py +2 -2
  51. package/src/skcapstone/fuse_mount.py +21 -13
  52. package/src/skcapstone/heartbeat.py +33 -29
  53. package/src/skcapstone/itil.py +1104 -0
  54. package/src/skcapstone/launchd.py +426 -0
  55. package/src/skcapstone/mcp_server.py +306 -4
  56. package/src/skcapstone/mcp_tools/__init__.py +4 -0
  57. package/src/skcapstone/mcp_tools/_helpers.py +2 -2
  58. package/src/skcapstone/mcp_tools/ansible_tools.py +7 -4
  59. package/src/skcapstone/mcp_tools/brain_first_tools.py +90 -0
  60. package/src/skcapstone/mcp_tools/capauth_tools.py +7 -4
  61. package/src/skcapstone/mcp_tools/coord_tools.py +8 -4
  62. package/src/skcapstone/mcp_tools/did_tools.py +9 -6
  63. package/src/skcapstone/mcp_tools/gtd_tools.py +1 -1
  64. package/src/skcapstone/mcp_tools/itil_tools.py +657 -0
  65. package/src/skcapstone/mcp_tools/memory_tools.py +6 -2
  66. package/src/skcapstone/mcp_tools/soul_tools.py +6 -2
  67. package/src/skcapstone/mdns_discovery.py +2 -2
  68. package/src/skcapstone/metrics.py +8 -8
  69. package/src/skcapstone/migrate_memories.py +2 -2
  70. package/src/skcapstone/models.py +14 -0
  71. package/src/skcapstone/onboard.py +137 -14
  72. package/src/skcapstone/peer_directory.py +2 -2
  73. package/src/skcapstone/providers/docker.py +2 -2
  74. package/src/skcapstone/scheduled_tasks.py +107 -0
  75. package/src/skcapstone/service_health.py +83 -4
  76. package/src/skcapstone/sync_watcher.py +2 -2
  77. 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: npm publish --access public
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 }}
@@ -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
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smilintux/skcapstone",
3
- "version": "0.4.6",
3
+ "version": "0.5.0",
4
4
  "description": "SKCapstone - The sovereign agent framework. CapAuth identity, Cloud 9 trust, SKMemory persistence.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
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.4"
7
+ version = "0.5.0"
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)."