clawpowers 1.0.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/.claude-plugin/manifest.json +19 -0
- package/.codex/INSTALL.md +36 -0
- package/.cursor-plugin/manifest.json +21 -0
- package/.opencode/INSTALL.md +52 -0
- package/ARCHITECTURE.md +69 -0
- package/README.md +381 -0
- package/bin/clawpowers.js +390 -0
- package/bin/clawpowers.sh +91 -0
- package/gemini-extension.json +32 -0
- package/hooks/session-start +205 -0
- package/hooks/session-start.cmd +43 -0
- package/hooks/session-start.js +163 -0
- package/package.json +54 -0
- package/runtime/feedback/analyze.js +621 -0
- package/runtime/feedback/analyze.sh +546 -0
- package/runtime/init.js +172 -0
- package/runtime/init.sh +145 -0
- package/runtime/metrics/collector.js +361 -0
- package/runtime/metrics/collector.sh +308 -0
- package/runtime/persistence/store.js +433 -0
- package/runtime/persistence/store.sh +303 -0
- package/skill.json +74 -0
- package/skills/agent-payments/SKILL.md +411 -0
- package/skills/brainstorming/SKILL.md +233 -0
- package/skills/content-pipeline/SKILL.md +282 -0
- package/skills/dispatching-parallel-agents/SKILL.md +305 -0
- package/skills/executing-plans/SKILL.md +255 -0
- package/skills/finishing-a-development-branch/SKILL.md +260 -0
- package/skills/learn-how-to-learn/SKILL.md +235 -0
- package/skills/market-intelligence/SKILL.md +288 -0
- package/skills/prospecting/SKILL.md +313 -0
- package/skills/receiving-code-review/SKILL.md +225 -0
- package/skills/requesting-code-review/SKILL.md +206 -0
- package/skills/security-audit/SKILL.md +308 -0
- package/skills/subagent-driven-development/SKILL.md +244 -0
- package/skills/systematic-debugging/SKILL.md +279 -0
- package/skills/test-driven-development/SKILL.md +299 -0
- package/skills/using-clawpowers/SKILL.md +137 -0
- package/skills/using-git-worktrees/SKILL.md +261 -0
- package/skills/verification-before-completion/SKILL.md +254 -0
- package/skills/writing-plans/SKILL.md +276 -0
- package/skills/writing-skills/SKILL.md +260 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# runtime/persistence/store.sh — File-based key-value persistence
|
|
3
|
+
#
|
|
4
|
+
# Stores skill state in ~/.clawpowers/state/ using flat files.
|
|
5
|
+
# Each key maps to a file. Safe for concurrent reads; writes are atomic via temp file.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# store.sh set <key> <value> Set a key-value pair
|
|
9
|
+
# store.sh get <key> Get value for key (exits 1 if not found)
|
|
10
|
+
# store.sh get <key> <default> Get value, return default if not found
|
|
11
|
+
# store.sh delete <key> Delete a key
|
|
12
|
+
# store.sh list [prefix] List all keys (optionally filtered by prefix)
|
|
13
|
+
# store.sh list-values [prefix] List key=value pairs
|
|
14
|
+
# store.sh exists <key> Exit 0 if key exists, 1 if not
|
|
15
|
+
# store.sh append <key> <value> Append value to existing (newline-separated)
|
|
16
|
+
# store.sh incr <key> Increment a numeric value by 1
|
|
17
|
+
# store.sh incr <key> <n> Increment by n
|
|
18
|
+
#
|
|
19
|
+
# Key naming convention:
|
|
20
|
+
# namespace:entity:attribute
|
|
21
|
+
# Example: "execution:auth-plan:task_3:status"
|
|
22
|
+
#
|
|
23
|
+
# Keys may contain: [a-zA-Z0-9:_.-]
|
|
24
|
+
# Values may contain any printable characters
|
|
25
|
+
# Keys with '/' are rejected (no path traversal)
|
|
26
|
+
set -euo pipefail
|
|
27
|
+
|
|
28
|
+
## === Configuration ===
|
|
29
|
+
|
|
30
|
+
# State directory — override parent with CLAWPOWERS_DIR env var for testing
|
|
31
|
+
STATE_DIR="${CLAWPOWERS_DIR:-$HOME/.clawpowers}/state"
|
|
32
|
+
|
|
33
|
+
## === Internal Utilities ===
|
|
34
|
+
|
|
35
|
+
# Creates the state directory if it doesn't already exist.
|
|
36
|
+
# Mode 700 ensures the directory is accessible only to the current user.
|
|
37
|
+
ensure_dir() {
|
|
38
|
+
if [[ ! -d "$STATE_DIR" ]]; then
|
|
39
|
+
mkdir -p "$STATE_DIR"
|
|
40
|
+
chmod 700 "$STATE_DIR"
|
|
41
|
+
fi
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Validates a key before use. Rejects empty keys, path separators, and '..'
|
|
45
|
+
# to prevent directory traversal attacks when constructing filenames.
|
|
46
|
+
validate_key() {
|
|
47
|
+
local key="$1"
|
|
48
|
+
if [[ -z "$key" ]]; then
|
|
49
|
+
echo "Error: key cannot be empty" >&2
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
# Reject '/' and '\' — they would allow writing outside STATE_DIR
|
|
53
|
+
if [[ "$key" =~ [/\\] ]]; then
|
|
54
|
+
echo "Error: key cannot contain '/' or '\\': $key" >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
# Reject '..' segments to prevent directory traversal
|
|
58
|
+
if [[ "$key" =~ \.\. ]]; then
|
|
59
|
+
echo "Error: key cannot contain '..': $key" >&2
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Converts a colon-separated key to a safe filesystem filename.
|
|
65
|
+
# Colons are replaced with double underscores because ':' is not valid in
|
|
66
|
+
# Windows filenames and can be ambiguous on some filesystems.
|
|
67
|
+
#
|
|
68
|
+
# Example: "execution:my-plan:task_1" → "$STATE_DIR/execution__my-plan__task_1"
|
|
69
|
+
key_to_file() {
|
|
70
|
+
local key="$1"
|
|
71
|
+
echo "$STATE_DIR/${key//:/__}"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Atomically writes a value to a file using temp-file-then-mv.
|
|
75
|
+
# This prevents partial writes — readers see either the old value or the new
|
|
76
|
+
# value, never an intermediate truncated state.
|
|
77
|
+
atomic_write() {
|
|
78
|
+
local file="$1"
|
|
79
|
+
local value="$2"
|
|
80
|
+
# Use PID in temp filename to avoid collisions with concurrent writes
|
|
81
|
+
local tmpfile="${file}.tmp.$$"
|
|
82
|
+
|
|
83
|
+
echo "$value" > "$tmpfile"
|
|
84
|
+
chmod 600 "$tmpfile"
|
|
85
|
+
# mv is atomic on POSIX filesystems when source and dest are on the same mount
|
|
86
|
+
mv "$tmpfile" "$file"
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
## === Command Implementations ===
|
|
90
|
+
|
|
91
|
+
# set — Write a value to a key, overwriting any existing value.
|
|
92
|
+
cmd_set() {
|
|
93
|
+
local key="$1"
|
|
94
|
+
local value="${2:-}" # Default to empty string if no value provided
|
|
95
|
+
validate_key "$key"
|
|
96
|
+
ensure_dir
|
|
97
|
+
|
|
98
|
+
local file
|
|
99
|
+
file=$(key_to_file "$key")
|
|
100
|
+
atomic_write "$file" "$value"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# get — Read the value for a key.
|
|
104
|
+
# If the key doesn't exist and a default is provided, print the default.
|
|
105
|
+
# If the key doesn't exist and no default is provided, print an error and exit 1.
|
|
106
|
+
# The sentinel "__NOTSET__" distinguishes "no default provided" from "empty default".
|
|
107
|
+
cmd_get() {
|
|
108
|
+
local key="$1"
|
|
109
|
+
local default_val="${2:-__NOTSET__}"
|
|
110
|
+
validate_key "$key"
|
|
111
|
+
ensure_dir
|
|
112
|
+
|
|
113
|
+
local file
|
|
114
|
+
file=$(key_to_file "$key")
|
|
115
|
+
|
|
116
|
+
if [[ -f "$file" ]]; then
|
|
117
|
+
cat "$file"
|
|
118
|
+
elif [[ "$default_val" != "__NOTSET__" ]]; then
|
|
119
|
+
echo "$default_val"
|
|
120
|
+
else
|
|
121
|
+
echo "Error: key not found: $key" >&2
|
|
122
|
+
exit 1
|
|
123
|
+
fi
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# delete — Remove a key and its file.
|
|
127
|
+
# Prints a confirmation on success, or a "not found" message to stderr.
|
|
128
|
+
cmd_delete() {
|
|
129
|
+
local key="$1"
|
|
130
|
+
validate_key "$key"
|
|
131
|
+
|
|
132
|
+
local file
|
|
133
|
+
file=$(key_to_file "$key")
|
|
134
|
+
if [[ -f "$file" ]]; then
|
|
135
|
+
rm -f "$file"
|
|
136
|
+
echo "Deleted: $key"
|
|
137
|
+
else
|
|
138
|
+
# Route "not found" to stderr so shell scripts can distinguish from success output
|
|
139
|
+
echo "Key not found (nothing deleted): $key" >&2
|
|
140
|
+
fi
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# list — Print all keys matching an optional prefix (one key per line).
|
|
144
|
+
# The prefix uses colon notation (e.g. "execution:my-plan:") which is converted
|
|
145
|
+
# to filename notation before globbing.
|
|
146
|
+
cmd_list() {
|
|
147
|
+
local prefix="${1:-}"
|
|
148
|
+
ensure_dir
|
|
149
|
+
|
|
150
|
+
# Convert prefix from key format (colons) to filename format (double underscores)
|
|
151
|
+
local file_prefix="${prefix//:/__}"
|
|
152
|
+
|
|
153
|
+
local found=0
|
|
154
|
+
for f in "$STATE_DIR"/${file_prefix}*; do
|
|
155
|
+
if [[ -f "$f" ]]; then
|
|
156
|
+
# Convert filename back to colon-separated key format for output
|
|
157
|
+
local basename
|
|
158
|
+
basename=$(basename "$f")
|
|
159
|
+
local key="${basename//__/:}"
|
|
160
|
+
echo "$key"
|
|
161
|
+
((found++)) || true
|
|
162
|
+
fi
|
|
163
|
+
done
|
|
164
|
+
|
|
165
|
+
if [[ $found -eq 0 && -n "$prefix" ]]; then
|
|
166
|
+
echo "No keys found with prefix: $prefix" >&2
|
|
167
|
+
fi
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
# list-values — Print all key=value pairs matching an optional prefix.
|
|
171
|
+
# Output format: "key=value" (one pair per line), suitable for shell parsing.
|
|
172
|
+
cmd_list_values() {
|
|
173
|
+
local prefix="${1:-}"
|
|
174
|
+
ensure_dir
|
|
175
|
+
|
|
176
|
+
local file_prefix="${prefix//:/__}"
|
|
177
|
+
|
|
178
|
+
local found=0
|
|
179
|
+
for f in "$STATE_DIR"/${file_prefix}*; do
|
|
180
|
+
if [[ -f "$f" ]]; then
|
|
181
|
+
local basename
|
|
182
|
+
basename=$(basename "$f")
|
|
183
|
+
local key="${basename//__/:}"
|
|
184
|
+
local value
|
|
185
|
+
value=$(cat "$f")
|
|
186
|
+
echo "${key}=${value}"
|
|
187
|
+
((found++)) || true
|
|
188
|
+
fi
|
|
189
|
+
done
|
|
190
|
+
|
|
191
|
+
if [[ $found -eq 0 && -n "$prefix" ]]; then
|
|
192
|
+
echo "No keys found with prefix: $prefix" >&2
|
|
193
|
+
fi
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
# exists — Exit 0 if the key exists, exit 1 if not.
|
|
197
|
+
# Designed for use in shell conditionals: `store.sh exists my:key && echo "found"`
|
|
198
|
+
cmd_exists() {
|
|
199
|
+
local key="$1"
|
|
200
|
+
validate_key "$key"
|
|
201
|
+
|
|
202
|
+
local file
|
|
203
|
+
file=$(key_to_file "$key")
|
|
204
|
+
# The [[ -f "$file" ]] test returns 0/1 directly — no explicit exit needed
|
|
205
|
+
[[ -f "$file" ]]
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
# append — Add a value to an existing key, separated by a newline.
|
|
209
|
+
# Creates the key if it doesn't exist (same behavior as set on first call).
|
|
210
|
+
# Useful for maintaining lists, logs, or multi-line notes in a single key.
|
|
211
|
+
cmd_append() {
|
|
212
|
+
local key="$1"
|
|
213
|
+
local value="${2:-}"
|
|
214
|
+
validate_key "$key"
|
|
215
|
+
ensure_dir
|
|
216
|
+
|
|
217
|
+
local file
|
|
218
|
+
file=$(key_to_file "$key")
|
|
219
|
+
|
|
220
|
+
if [[ -f "$file" ]]; then
|
|
221
|
+
# Append to existing content — echo adds the trailing newline separator
|
|
222
|
+
echo "$value" >> "$file"
|
|
223
|
+
else
|
|
224
|
+
# First write: use atomic write to properly create the file with permissions
|
|
225
|
+
atomic_write "$file" "$value"
|
|
226
|
+
fi
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
# incr — Increment the integer value stored at a key.
|
|
230
|
+
# Creates the key with value equal to `amount` if it doesn't exist (treating missing as 0).
|
|
231
|
+
# Rejects non-integer values with an error.
|
|
232
|
+
cmd_incr() {
|
|
233
|
+
local key="$1"
|
|
234
|
+
local amount="${2:-1}" # Default increment is 1
|
|
235
|
+
validate_key "$key"
|
|
236
|
+
ensure_dir
|
|
237
|
+
|
|
238
|
+
local file
|
|
239
|
+
file=$(key_to_file "$key")
|
|
240
|
+
|
|
241
|
+
# Read the current value; default to 0 if the key doesn't exist
|
|
242
|
+
local current=0
|
|
243
|
+
if [[ -f "$file" ]]; then
|
|
244
|
+
# tr removes all whitespace including the trailing newline written by atomic_write
|
|
245
|
+
current=$(cat "$file" | tr -d '[:space:]')
|
|
246
|
+
# Validate that the stored value is a plain integer (no decimals, no whitespace)
|
|
247
|
+
if ! [[ "$current" =~ ^-?[0-9]+$ ]]; then
|
|
248
|
+
echo "Error: value is not an integer: $current" >&2
|
|
249
|
+
exit 1
|
|
250
|
+
fi
|
|
251
|
+
fi
|
|
252
|
+
|
|
253
|
+
local new_val=$((current + amount))
|
|
254
|
+
atomic_write "$file" "$new_val"
|
|
255
|
+
echo "$new_val"
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
## === Usage ===
|
|
259
|
+
|
|
260
|
+
cmd_usage() {
|
|
261
|
+
cat << 'EOF'
|
|
262
|
+
Usage: store.sh <command> [args]
|
|
263
|
+
|
|
264
|
+
Commands:
|
|
265
|
+
set <key> <value> Set a key-value pair
|
|
266
|
+
get <key> [default] Get value (returns default or error if not found)
|
|
267
|
+
delete <key> Delete a key
|
|
268
|
+
list [prefix] List all keys matching prefix
|
|
269
|
+
list-values [prefix] List key=value pairs matching prefix
|
|
270
|
+
exists <key> Exit 0 if key exists, 1 if not
|
|
271
|
+
append <key> <value> Append value (newline-separated)
|
|
272
|
+
incr <key> [amount] Increment integer value by amount (default: 1)
|
|
273
|
+
|
|
274
|
+
Key format: namespace:entity:attribute (e.g., "execution:auth-plan:task_3:status")
|
|
275
|
+
State stored in: ~/.clawpowers/state/
|
|
276
|
+
|
|
277
|
+
Examples:
|
|
278
|
+
store.sh set "execution:my-plan:task_1:status" "complete"
|
|
279
|
+
store.sh get "execution:my-plan:task_1:status"
|
|
280
|
+
store.sh get "missing-key" "default-value"
|
|
281
|
+
store.sh list "execution:my-plan:"
|
|
282
|
+
store.sh incr "metrics:session:payment_count"
|
|
283
|
+
store.sh exists "execution:my-plan:task_1:status" && echo "exists"
|
|
284
|
+
EOF
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
## === Main Dispatch ===
|
|
288
|
+
|
|
289
|
+
# Route the first positional argument to the appropriate command function.
|
|
290
|
+
# Arguments after the command name are forwarded directly to each function.
|
|
291
|
+
case "${1:-}" in
|
|
292
|
+
set) cmd_set "${2:-}" "${3:-}" ;;
|
|
293
|
+
get) cmd_get "${2:-}" "${3:-__NOTSET__}" ;;
|
|
294
|
+
delete) cmd_delete "${2:-}" ;;
|
|
295
|
+
list) cmd_list "${2:-}" ;;
|
|
296
|
+
list-values) cmd_list_values "${2:-}" ;;
|
|
297
|
+
exists) cmd_exists "${2:-}" ;;
|
|
298
|
+
append) cmd_append "${2:-}" "${3:-}" ;;
|
|
299
|
+
incr) cmd_incr "${2:-}" "${3:-1}" ;;
|
|
300
|
+
help|-h|--help) cmd_usage ;;
|
|
301
|
+
"") cmd_usage; exit 1 ;;
|
|
302
|
+
*) echo "Unknown command: $1"; cmd_usage; exit 1 ;;
|
|
303
|
+
esac
|
package/skill.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clawpowers",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Runtime-powered skills framework — 20 skills with persistent memory, self-improvement (RSI), outcome tracking, and autonomous agent payments (x402). Works on Claude Code, Cursor, Codex, OpenCode, Gemini CLI.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "AI Agent Economy",
|
|
7
|
+
"url": "https://github.com/up2itnow0822"
|
|
8
|
+
},
|
|
9
|
+
"repository": "https://github.com/up2itnow0822/clawpowers",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"skills",
|
|
12
|
+
"agent",
|
|
13
|
+
"runtime",
|
|
14
|
+
"rsi",
|
|
15
|
+
"self-improvement",
|
|
16
|
+
"persistence",
|
|
17
|
+
"payments",
|
|
18
|
+
"x402",
|
|
19
|
+
"tdd",
|
|
20
|
+
"debugging",
|
|
21
|
+
"code-review",
|
|
22
|
+
"security-audit",
|
|
23
|
+
"content-pipeline",
|
|
24
|
+
"market-intelligence",
|
|
25
|
+
"prospecting",
|
|
26
|
+
"subagent"
|
|
27
|
+
],
|
|
28
|
+
"config": {},
|
|
29
|
+
"triggers": [
|
|
30
|
+
"plan this feature",
|
|
31
|
+
"debug this",
|
|
32
|
+
"write tests",
|
|
33
|
+
"code review",
|
|
34
|
+
"brainstorm",
|
|
35
|
+
"security audit",
|
|
36
|
+
"pay for this API",
|
|
37
|
+
"find leads",
|
|
38
|
+
"market research",
|
|
39
|
+
"analyze performance"
|
|
40
|
+
],
|
|
41
|
+
"platforms": ["macos", "linux", "windows"],
|
|
42
|
+
"category": "development",
|
|
43
|
+
"runtime": {
|
|
44
|
+
"init": "node bin/clawpowers.js init",
|
|
45
|
+
"status": "node bin/clawpowers.js status",
|
|
46
|
+
"stateDir": "~/.clawpowers"
|
|
47
|
+
},
|
|
48
|
+
"skills": {
|
|
49
|
+
"core": [
|
|
50
|
+
"subagent-driven-development",
|
|
51
|
+
"test-driven-development",
|
|
52
|
+
"writing-plans",
|
|
53
|
+
"executing-plans",
|
|
54
|
+
"brainstorming",
|
|
55
|
+
"systematic-debugging",
|
|
56
|
+
"verification-before-completion",
|
|
57
|
+
"finishing-a-development-branch",
|
|
58
|
+
"requesting-code-review",
|
|
59
|
+
"receiving-code-review",
|
|
60
|
+
"using-git-worktrees",
|
|
61
|
+
"using-clawpowers",
|
|
62
|
+
"writing-skills",
|
|
63
|
+
"dispatching-parallel-agents"
|
|
64
|
+
],
|
|
65
|
+
"extended": [
|
|
66
|
+
"agent-payments",
|
|
67
|
+
"security-audit",
|
|
68
|
+
"content-pipeline",
|
|
69
|
+
"learn-how-to-learn",
|
|
70
|
+
"market-intelligence",
|
|
71
|
+
"prospecting"
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
}
|