@agentuity/claude-code 1.0.5
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/plugin.json +19 -0
- package/AGENTS.md +78 -0
- package/LICENSE +13 -0
- package/README.md +165 -0
- package/agents/architect.md +311 -0
- package/agents/builder.md +398 -0
- package/agents/lead.md +692 -0
- package/agents/memory.md +983 -0
- package/agents/product.md +473 -0
- package/agents/reviewer.md +340 -0
- package/agents/scout.md +294 -0
- package/commands/agentuity-cadence-cancel.md +15 -0
- package/commands/agentuity-cadence.md +74 -0
- package/commands/agentuity-coder.md +14 -0
- package/commands/agentuity-memory-save.md +14 -0
- package/commands/agentuity-memory-share.md +31 -0
- package/commands/agentuity-sandbox.md +33 -0
- package/dist/install.d.ts +22 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +113 -0
- package/dist/install.js.map +1 -0
- package/hooks/hooks.json +67 -0
- package/hooks/scripts/block-sensitive-commands.sh +43 -0
- package/hooks/scripts/cadence-stop.sh +180 -0
- package/hooks/scripts/pre-compact.sh +24 -0
- package/hooks/scripts/session-end.sh +203 -0
- package/hooks/scripts/session-start.sh +68 -0
- package/hooks/scripts/setup-cadence.sh +133 -0
- package/hooks/scripts/stop-memory-save.sh +69 -0
- package/package.json +49 -0
- package/skills/agentuity-backend/SKILL.md +471 -0
- package/skills/agentuity-cloud/SKILL.md +108 -0
- package/skills/agentuity-command-runner/SKILL.md +127 -0
- package/skills/agentuity-frontend/SKILL.md +321 -0
- package/skills/agentuity-ops/SKILL.md +207 -0
- package/src/install.ts +150 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Session end hook: Save session context via TWO paths:
|
|
3
|
+
#
|
|
4
|
+
# PATH 1 (Immediate): Structured KV save — session metadata + conversation extract.
|
|
5
|
+
# Fast, reliable, always works. Extracts actual text content from transcript.
|
|
6
|
+
#
|
|
7
|
+
# PATH 2 (Async/Agentic): Spawn background `claude -p` with the plugin loaded.
|
|
8
|
+
# Delegates to the Memory agent for full agentic processing:
|
|
9
|
+
# entity extraction, corrections, Vector upsert, structured conclusions.
|
|
10
|
+
# Runs as a fire-and-forget background process.
|
|
11
|
+
#
|
|
12
|
+
# This dual approach ensures:
|
|
13
|
+
# - Something is ALWAYS saved (Path 1, even if claude -p fails)
|
|
14
|
+
# - Full agentic memory processing happens asynchronously (Path 2)
|
|
15
|
+
#
|
|
16
|
+
# Receives JSON on stdin with:
|
|
17
|
+
# - session_id: session identifier
|
|
18
|
+
# - transcript_path: path to conversation JSONL file
|
|
19
|
+
# - cwd: working directory
|
|
20
|
+
# - reason: why session ended
|
|
21
|
+
#
|
|
22
|
+
# Claude Code JSONL format notes:
|
|
23
|
+
# - Each line is a JSON object with top-level .type field
|
|
24
|
+
# - Types: "user", "assistant", "progress", "file-history-snapshot"
|
|
25
|
+
# - Text content: .message.content[] where item .type == "text" and text in .text
|
|
26
|
+
# - "progress" entries (subagent updates) can be very large (100KB+)
|
|
27
|
+
# - Filter by line size (< 5KB) before jq processing to avoid OOM/hangs
|
|
28
|
+
|
|
29
|
+
set -uo pipefail
|
|
30
|
+
|
|
31
|
+
INPUT=$(cat)
|
|
32
|
+
|
|
33
|
+
if ! command -v agentuity &>/dev/null; then
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Derive plugin root from this script's location
|
|
38
|
+
# Script is at: <plugin_root>/hooks/scripts/session-end.sh
|
|
39
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
40
|
+
PLUGIN_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
41
|
+
|
|
42
|
+
# Extract fields from input JSON
|
|
43
|
+
if command -v jq &>/dev/null; then
|
|
44
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
|
|
45
|
+
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
|
|
46
|
+
REASON=$(echo "$INPUT" | jq -r '.reason // empty' 2>/dev/null)
|
|
47
|
+
CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
|
|
48
|
+
else
|
|
49
|
+
SESSION_ID=$(echo "$INPUT" | grep -o '"session_id"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
|
|
50
|
+
TRANSCRIPT_PATH=$(echo "$INPUT" | grep -o '"transcript_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
|
|
51
|
+
REASON=$(echo "$INPUT" | grep -o '"reason"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
|
|
52
|
+
CWD=$(echo "$INPUT" | grep -o '"cwd"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
if [ -z "$SESSION_ID" ] || [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
|
|
56
|
+
exit 0
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
GIT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
|
|
60
|
+
GIT_REMOTE=$(git remote get-url origin 2>/dev/null || echo "unknown")
|
|
61
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
62
|
+
|
|
63
|
+
# ─────────────────────────────────────────────────────
|
|
64
|
+
# Extract conversation content from JSONL transcript
|
|
65
|
+
# ─────────────────────────────────────────────────────
|
|
66
|
+
# Key: filter lines < 5KB to skip huge "progress" entries that crash jq.
|
|
67
|
+
# Only extract .message.content[] items with .type == "text"
|
|
68
|
+
|
|
69
|
+
CONVERSATION=""
|
|
70
|
+
if command -v jq &>/dev/null && command -v awk &>/dev/null; then
|
|
71
|
+
CONVERSATION=$(awk 'length < 5000' "$TRANSCRIPT_PATH" 2>/dev/null | jq -r '
|
|
72
|
+
if .type == "assistant" then
|
|
73
|
+
.message.content[]? | select(.type == "text") | "ASSISTANT: " + (.text // "")
|
|
74
|
+
elif .type == "user" then
|
|
75
|
+
.message.content[]? | select(.type == "text") | "USER: " + (.text // "")
|
|
76
|
+
else empty end
|
|
77
|
+
' 2>/dev/null | tail -40 | head -c 8000)
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# Fallback: raw tail
|
|
81
|
+
if [ -z "$CONVERSATION" ]; then
|
|
82
|
+
CONVERSATION=$(tail -20 "$TRANSCRIPT_PATH" 2>/dev/null | head -c 4000)
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# ─────────────────────────────────────────────────────
|
|
86
|
+
# PATH 1: Immediate structured KV save
|
|
87
|
+
# ─────────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
SESSION_RECORD=$(jq -n \
|
|
90
|
+
--arg sid "$SESSION_ID" \
|
|
91
|
+
--arg branch "$GIT_BRANCH" \
|
|
92
|
+
--arg remote "$GIT_REMOTE" \
|
|
93
|
+
--arg reason "$REASON" \
|
|
94
|
+
--arg ts "$TIMESTAMP" \
|
|
95
|
+
--arg cwd "$CWD" \
|
|
96
|
+
--arg convo "$CONVERSATION" \
|
|
97
|
+
'{
|
|
98
|
+
sessionId: $sid,
|
|
99
|
+
branch: $branch,
|
|
100
|
+
remote: $remote,
|
|
101
|
+
endReason: $reason,
|
|
102
|
+
timestamp: $ts,
|
|
103
|
+
source: "claude-code",
|
|
104
|
+
cwd: $cwd,
|
|
105
|
+
conversation: $convo
|
|
106
|
+
}' 2>/dev/null)
|
|
107
|
+
|
|
108
|
+
if [ -n "$SESSION_RECORD" ]; then
|
|
109
|
+
agentuity cloud kv set agentuity-opencode-memory "session:cc:${SESSION_ID}" "$SESSION_RECORD" --region use 2>/dev/null || true
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# ─────────────────────────────────────────────────────
|
|
113
|
+
# PATH 2: Async agentic processing via background claude -p
|
|
114
|
+
# ─────────────────────────────────────────────────────
|
|
115
|
+
# Spawns a background claude -p with the plugin loaded, delegating to the
|
|
116
|
+
# Memory agent for full agentic processing (entity extraction, corrections,
|
|
117
|
+
# Vector upsert, structured conclusions).
|
|
118
|
+
#
|
|
119
|
+
# Key learnings from iteration:
|
|
120
|
+
# - --allowedTools must be SEPARATE arguments, not comma-separated
|
|
121
|
+
# - Pattern syntax is Bash(agentuity *) not Bash(pattern agentuity*)
|
|
122
|
+
# - Memory agent (via Task tool) handles all KV/Vector storage
|
|
123
|
+
# - --plugin-dir loads the plugin so Task can access the Memory agent
|
|
124
|
+
#
|
|
125
|
+
# This is "Option A" — local/sandbox use. For production at scale,
|
|
126
|
+
# replace with queue-based worker (Option B) or control plane (Option C).
|
|
127
|
+
|
|
128
|
+
if command -v claude &>/dev/null; then
|
|
129
|
+
# Write session context to temp file for claude -p to read
|
|
130
|
+
MEMORY_FILE=$(mktemp /tmp/agentuity-session-XXXXXX.md)
|
|
131
|
+
|
|
132
|
+
cat > "$MEMORY_FILE" <<MEMORY_CONTEXT
|
|
133
|
+
# Session Memorialization Request
|
|
134
|
+
|
|
135
|
+
**Session ID:** ${SESSION_ID}
|
|
136
|
+
**Branch:** ${GIT_BRANCH}
|
|
137
|
+
**Repository:** ${GIT_REMOTE}
|
|
138
|
+
**Working Directory:** ${CWD}
|
|
139
|
+
**End Reason:** ${REASON}
|
|
140
|
+
**Timestamp:** ${TIMESTAMP}
|
|
141
|
+
|
|
142
|
+
## Conversation Transcript
|
|
143
|
+
|
|
144
|
+
${CONVERSATION}
|
|
145
|
+
MEMORY_CONTEXT
|
|
146
|
+
|
|
147
|
+
LOG_DIR="/tmp/agentuity-memory-logs"
|
|
148
|
+
mkdir -p "$LOG_DIR" 2>/dev/null
|
|
149
|
+
|
|
150
|
+
# Spawn background claude -p with plugin loaded.
|
|
151
|
+
# Delegates to Memory agent via Task tool for full agentic processing.
|
|
152
|
+
# --dangerously-skip-permissions: background process, no user to prompt.
|
|
153
|
+
# --tools: restricts available tools to Task, Read, Bash (scoped).
|
|
154
|
+
nohup claude -p "Read the file ${MEMORY_FILE} which contains a session transcript to memorialize.
|
|
155
|
+
|
|
156
|
+
Use the Task tool to delegate to the Memory agent:
|
|
157
|
+
- subagent_type: agentuity-coder:agentuity-coder-memory
|
|
158
|
+
- description: Memorialize session ${SESSION_ID}
|
|
159
|
+
- prompt: Memorialize this session. You are being invoked automatically at session end. Read the file ${MEMORY_FILE} for the full session context. Then perform a full session memorialization: create a session summary (PROBLEM, CONTEXT, DECISIONS, CORRECTIONS, SOLUTIONS, PATTERNS, FILES, OPEN QUESTIONS), extract and store corrections to KV, store decisions to KV, upsert the full session document to Vector for semantic search, and apply reasoning to extract conclusions. Session ID: ${SESSION_ID}, Branch: ${GIT_BRANCH}, Repo: ${GIT_REMOTE}. Do NOT ask questions. Prioritize corrections and decisions.
|
|
160
|
+
|
|
161
|
+
After the Memory agent completes, clean up by running: rm ${MEMORY_FILE}" \
|
|
162
|
+
--plugin-dir "$PLUGIN_ROOT" \
|
|
163
|
+
--dangerously-skip-permissions \
|
|
164
|
+
--tools "Task,Read,Bash" \
|
|
165
|
+
> "$LOG_DIR/session-${SESSION_ID}.log" 2>&1 &
|
|
166
|
+
|
|
167
|
+
# Don't wait for completion — fire and forget
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# ─────────────────────────────────────────────────────
|
|
171
|
+
# (Future) PATH 3: Queue publish for worker-based processing
|
|
172
|
+
# ─────────────────────────────────────────────────────
|
|
173
|
+
# Uncomment when a queue worker (Option B/C) is available.
|
|
174
|
+
# The queue provides durability, retry, and DLQ for production use.
|
|
175
|
+
#
|
|
176
|
+
# QUEUE_PAYLOAD=$(jq -n \
|
|
177
|
+
# --arg type "session-memorialize" \
|
|
178
|
+
# --arg sid "$SESSION_ID" \
|
|
179
|
+
# --arg branch "$GIT_BRANCH" \
|
|
180
|
+
# --arg remote "$GIT_REMOTE" \
|
|
181
|
+
# --arg cwd "$CWD" \
|
|
182
|
+
# --arg reason "$REASON" \
|
|
183
|
+
# --arg ts "$TIMESTAMP" \
|
|
184
|
+
# --arg convo "$CONVERSATION" \
|
|
185
|
+
# '{
|
|
186
|
+
# type: $type,
|
|
187
|
+
# sessionId: $sid,
|
|
188
|
+
# branch: $branch,
|
|
189
|
+
# remote: $remote,
|
|
190
|
+
# cwd: $cwd,
|
|
191
|
+
# endReason: $reason,
|
|
192
|
+
# timestamp: $ts,
|
|
193
|
+
# transcript: $convo
|
|
194
|
+
# }' 2>/dev/null)
|
|
195
|
+
#
|
|
196
|
+
# if [ -n "$QUEUE_PAYLOAD" ]; then
|
|
197
|
+
# agentuity cloud queue publish coder-memory-processing "$QUEUE_PAYLOAD" \
|
|
198
|
+
# --metadata "{\"sessionId\":\"$SESSION_ID\",\"branch\":\"$GIT_BRANCH\",\"type\":\"session-memorialize\"}" \
|
|
199
|
+
# --idempotency-key "session:$SESSION_ID" \
|
|
200
|
+
# 2>/dev/null || true
|
|
201
|
+
# fi
|
|
202
|
+
|
|
203
|
+
exit 0
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Session start hook: Gather Agentuity context
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
# Find agentuity.json by walking up directories
|
|
6
|
+
find_agentuity_json() {
|
|
7
|
+
local dir="$PWD"
|
|
8
|
+
while [ "$dir" != "/" ]; do
|
|
9
|
+
if [ -f "$dir/agentuity.json" ]; then
|
|
10
|
+
echo "$dir/agentuity.json"
|
|
11
|
+
return 0
|
|
12
|
+
fi
|
|
13
|
+
dir="$(dirname "$dir")"
|
|
14
|
+
done
|
|
15
|
+
return 1
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# Initialize context
|
|
19
|
+
CONTEXT="{}"
|
|
20
|
+
|
|
21
|
+
# Check CLI availability
|
|
22
|
+
if command -v agentuity &>/dev/null; then
|
|
23
|
+
CLI_AVAILABLE=true
|
|
24
|
+
else
|
|
25
|
+
CLI_AVAILABLE=false
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Read agentuity.json
|
|
29
|
+
AGENTUITY_JSON=""
|
|
30
|
+
if AGENTUITY_JSON_PATH=$(find_agentuity_json); then
|
|
31
|
+
AGENTUITY_JSON=$(cat "$AGENTUITY_JSON_PATH" 2>/dev/null || echo "{}")
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Extract project info
|
|
35
|
+
PROJECT_ID=$(echo "$AGENTUITY_JSON" | grep -o '"projectId"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"projectId"[[:space:]]*:[[:space:]]*"\([^"]*\)"/\1/' || echo "")
|
|
36
|
+
ORG_ID=$(echo "$AGENTUITY_JSON" | grep -o '"orgId"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"orgId"[[:space:]]*:[[:space:]]*"\([^"]*\)"/\1/' || echo "")
|
|
37
|
+
|
|
38
|
+
# If no orgId in agentuity.json, try CLI profile
|
|
39
|
+
if [ -z "$ORG_ID" ] && [ -f "$HOME/.config/agentuity/production.yaml" ]; then
|
|
40
|
+
ORG_ID=$(grep 'orgId' "$HOME/.config/agentuity/production.yaml" 2>/dev/null | head -1 | sed 's/.*orgId:[[:space:]]*//' | tr -d '"' || echo "")
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Get user info from CLI
|
|
44
|
+
USER_INFO=""
|
|
45
|
+
if [ "$CLI_AVAILABLE" = true ]; then
|
|
46
|
+
USER_INFO=$(agentuity auth whoami --json 2>/dev/null || echo "")
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Get git info
|
|
50
|
+
GIT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
|
|
51
|
+
GIT_REMOTE=$(git remote get-url origin 2>/dev/null || echo "unknown")
|
|
52
|
+
|
|
53
|
+
# Output context
|
|
54
|
+
cat <<EOF
|
|
55
|
+
{
|
|
56
|
+
"agentuity": {
|
|
57
|
+
"cliAvailable": $CLI_AVAILABLE,
|
|
58
|
+
"projectId": "$PROJECT_ID",
|
|
59
|
+
"orgId": "$ORG_ID",
|
|
60
|
+
"configPath": "${AGENTUITY_JSON_PATH:-}",
|
|
61
|
+
"userInfo": ${USER_INFO:-null}
|
|
62
|
+
},
|
|
63
|
+
"git": {
|
|
64
|
+
"branch": "$GIT_BRANCH",
|
|
65
|
+
"remote": "$GIT_REMOTE"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
EOF
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Setup script for Cadence mode.
|
|
3
|
+
# Creates the .claude/agentuity-cadence.local.md state file and saves initial state to KV.
|
|
4
|
+
#
|
|
5
|
+
# Usage: setup-cadence.sh [--max-iterations N] [--completion-promise TEXT] PROMPT
|
|
6
|
+
#
|
|
7
|
+
# The state file is read by cadence-stop.sh (Stop hook) to keep
|
|
8
|
+
# the loop running until the completion promise is detected.
|
|
9
|
+
# State is also persisted to Agentuity Cloud KV for cross-session recall.
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
MAX_ITERATIONS=50
|
|
14
|
+
COMPLETION_PROMISE="DONE"
|
|
15
|
+
PROMPT=""
|
|
16
|
+
|
|
17
|
+
# Parse arguments
|
|
18
|
+
while [[ $# -gt 0 ]]; do
|
|
19
|
+
case "$1" in
|
|
20
|
+
--max-iterations)
|
|
21
|
+
MAX_ITERATIONS="$2"
|
|
22
|
+
shift 2
|
|
23
|
+
;;
|
|
24
|
+
--completion-promise)
|
|
25
|
+
COMPLETION_PROMISE="$2"
|
|
26
|
+
shift 2
|
|
27
|
+
;;
|
|
28
|
+
-h|--help)
|
|
29
|
+
echo "Usage: setup-cadence.sh [OPTIONS] PROMPT"
|
|
30
|
+
echo ""
|
|
31
|
+
echo "Options:"
|
|
32
|
+
echo " --max-iterations N Maximum loop iterations (default: 50)"
|
|
33
|
+
echo " --completion-promise TEXT Completion signal text (default: DONE)"
|
|
34
|
+
echo " -h, --help Show this help"
|
|
35
|
+
exit 0
|
|
36
|
+
;;
|
|
37
|
+
*)
|
|
38
|
+
# Everything else is the prompt
|
|
39
|
+
if [ -z "$PROMPT" ]; then
|
|
40
|
+
PROMPT="$1"
|
|
41
|
+
else
|
|
42
|
+
PROMPT="$PROMPT $1"
|
|
43
|
+
fi
|
|
44
|
+
shift
|
|
45
|
+
;;
|
|
46
|
+
esac
|
|
47
|
+
done
|
|
48
|
+
|
|
49
|
+
if [ -z "$PROMPT" ]; then
|
|
50
|
+
echo "Error: No prompt provided" >&2
|
|
51
|
+
echo "Usage: setup-cadence.sh [OPTIONS] PROMPT" >&2
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Validate max-iterations
|
|
56
|
+
if ! [[ "$MAX_ITERATIONS" =~ ^[0-9]+$ ]] || [[ "$MAX_ITERATIONS" -lt 1 ]]; then
|
|
57
|
+
echo "Error: --max-iterations must be a positive integer" >&2
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Generate a loop ID: lp_{short_name}_{random}
|
|
62
|
+
# Take first 3 words of prompt, lowercase, underscored, plus random suffix
|
|
63
|
+
SHORT_NAME=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]' | tr -cs '[:alnum:]' '_' | cut -c1-30 | sed 's/_$//')
|
|
64
|
+
RANDOM_SUFFIX=$(head -c 4 /dev/urandom | od -An -tx1 | tr -d ' \n' | cut -c1-6)
|
|
65
|
+
LOOP_ID="lp_${SHORT_NAME}_${RANDOM_SUFFIX}"
|
|
66
|
+
|
|
67
|
+
# Get git branch
|
|
68
|
+
GIT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
|
|
69
|
+
|
|
70
|
+
# Create .claude directory if needed
|
|
71
|
+
mkdir -p .claude
|
|
72
|
+
|
|
73
|
+
# Check for existing cadence session
|
|
74
|
+
if [ -f ".claude/agentuity-cadence.local.md" ]; then
|
|
75
|
+
EXISTING_ITER=$(sed -n '/^---$/,/^---$/{ /^iteration:/s/iteration: *//p }' .claude/agentuity-cadence.local.md)
|
|
76
|
+
EXISTING_LOOP=$(sed -n '/^---$/,/^---$/{ /^loop_id:/s/loop_id: *//p }' .claude/agentuity-cadence.local.md | tr -d '"')
|
|
77
|
+
echo "Warning: Active Cadence loop found (${EXISTING_LOOP:-?} at iteration ${EXISTING_ITER:-?}). Replacing with new loop." >&2
|
|
78
|
+
rm -f .claude/agentuity-cadence.local.md
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Create state file
|
|
82
|
+
CREATED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
83
|
+
cat > .claude/agentuity-cadence.local.md << STATEFILE
|
|
84
|
+
---
|
|
85
|
+
active: true
|
|
86
|
+
loop_id: "${LOOP_ID}"
|
|
87
|
+
iteration: 1
|
|
88
|
+
max_iterations: ${MAX_ITERATIONS}
|
|
89
|
+
completion_promise: "${COMPLETION_PROMISE}"
|
|
90
|
+
branch: "${GIT_BRANCH}"
|
|
91
|
+
created_at: ${CREATED_AT}
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
${PROMPT}
|
|
95
|
+
STATEFILE
|
|
96
|
+
|
|
97
|
+
# Save initial cadence state to KV (if agentuity CLI available)
|
|
98
|
+
if command -v agentuity &>/dev/null; then
|
|
99
|
+
KV_STATE=$(jq -n \
|
|
100
|
+
--arg loopId "$LOOP_ID" \
|
|
101
|
+
--arg prompt "$PROMPT" \
|
|
102
|
+
--arg branch "$GIT_BRANCH" \
|
|
103
|
+
--arg createdAt "$CREATED_AT" \
|
|
104
|
+
--argjson iteration 1 \
|
|
105
|
+
--argjson maxIterations "$MAX_ITERATIONS" \
|
|
106
|
+
--arg completionPromise "$COMPLETION_PROMISE" \
|
|
107
|
+
--arg status "active" \
|
|
108
|
+
'{
|
|
109
|
+
loopId: $loopId,
|
|
110
|
+
prompt: $prompt,
|
|
111
|
+
branch: $branch,
|
|
112
|
+
iteration: $iteration,
|
|
113
|
+
maxIterations: $maxIterations,
|
|
114
|
+
completionPromise: $completionPromise,
|
|
115
|
+
status: $status,
|
|
116
|
+
startedAt: $createdAt,
|
|
117
|
+
lastActivity: $createdAt,
|
|
118
|
+
checkpoints: []
|
|
119
|
+
}')
|
|
120
|
+
agentuity cloud kv set agentuity-opencode-memory "cadence:${LOOP_ID}" "$KV_STATE" --region use 2>/dev/null || true
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
echo "Cadence loop initialized:"
|
|
124
|
+
echo " Loop ID: ${LOOP_ID}"
|
|
125
|
+
echo " Max iterations: ${MAX_ITERATIONS}"
|
|
126
|
+
echo " Completion promise: ${COMPLETION_PROMISE}"
|
|
127
|
+
echo " Branch: ${GIT_BRANCH}"
|
|
128
|
+
echo " State file: .claude/agentuity-cadence.local.md"
|
|
129
|
+
echo " KV key: cadence:${LOOP_ID}"
|
|
130
|
+
echo ""
|
|
131
|
+
echo "The loop will continue until you output <promise>${COMPLETION_PROMISE}</promise>"
|
|
132
|
+
echo "or reach ${MAX_ITERATIONS} iterations."
|
|
133
|
+
echo "To cancel: /agentuity-cadence-cancel"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Stop hook: Request memory save before session ends (interactive mode only).
|
|
3
|
+
#
|
|
4
|
+
# In INTERACTIVE mode: blocks the first stop to request memory save via Memory agent.
|
|
5
|
+
# In HEADLESS mode (-p): skips entirely — session-end.sh handles KV save directly.
|
|
6
|
+
#
|
|
7
|
+
# Exit 0 = let Claude stop normally.
|
|
8
|
+
# Exit 2 + JSON with decision:block = prevent stop and inject instructions.
|
|
9
|
+
|
|
10
|
+
INPUT=$(cat)
|
|
11
|
+
|
|
12
|
+
# Check if agentuity CLI is available — if not, skip memory save
|
|
13
|
+
if ! command -v agentuity &>/dev/null; then
|
|
14
|
+
exit 0
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# If Cadence mode is active, skip memory save — cadence-stop.sh handles the loop
|
|
18
|
+
# and includes Memory checkpoints at each iteration.
|
|
19
|
+
if [ -f ".claude/agentuity-cadence.local.md" ]; then
|
|
20
|
+
exit 0
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# Detect headless mode: check if CLAUDE_CODE_HEADLESS is set, or if
|
|
24
|
+
# the session was started with -p (no TTY on parent's stdin).
|
|
25
|
+
# In headless mode, session-end.sh handles memory save directly via KV.
|
|
26
|
+
if [ "${CLAUDE_CODE_HEADLESS:-}" = "1" ] || [ "${CLAUDE_NON_INTERACTIVE:-}" = "1" ]; then
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Also detect headless by checking if the parent process has no TTY
|
|
31
|
+
if ! kill -0 $PPID 2>/dev/null || [ ! -t 0 ] 2>/dev/null; then
|
|
32
|
+
# Can't reliably detect, but hooks don't have a TTY in either mode.
|
|
33
|
+
# Use the marker-only approach and keep the block minimal.
|
|
34
|
+
:
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Use a session-specific marker file to track save state.
|
|
38
|
+
# PPID is the Claude Code process that spawns hooks — consistent within a session.
|
|
39
|
+
MARKER_DIR="/tmp/agentuity-coder-memory"
|
|
40
|
+
mkdir -p "$MARKER_DIR" 2>/dev/null
|
|
41
|
+
MARKER_FILE="$MARKER_DIR/saved-$PPID"
|
|
42
|
+
|
|
43
|
+
# If we've already requested a save this session, let Claude stop
|
|
44
|
+
if [ -f "$MARKER_FILE" ]; then
|
|
45
|
+
exit 0
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Mark that we've requested a save
|
|
49
|
+
touch "$MARKER_FILE"
|
|
50
|
+
|
|
51
|
+
# Clean up old markers (older than 24h)
|
|
52
|
+
find "$MARKER_DIR" -name 'saved-*' -mtime +1 -delete 2>/dev/null || true
|
|
53
|
+
|
|
54
|
+
# Get git branch for context
|
|
55
|
+
GIT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
|
|
56
|
+
|
|
57
|
+
# Block the stop and request agentic memory save via Memory agent.
|
|
58
|
+
# The Memory agent has full reasoning capabilities: entity extraction,
|
|
59
|
+
# corrections identification, Vector upsert, and structured KV storage.
|
|
60
|
+
#
|
|
61
|
+
# IMPORTANT: We use the Task tool to delegate to Memory agent (subagent),
|
|
62
|
+
# NOT Lead, to avoid complex multi-agent orchestration that can hang.
|
|
63
|
+
cat <<EOF
|
|
64
|
+
{
|
|
65
|
+
"decision": "block",
|
|
66
|
+
"reason": "Before ending this session, you MUST save session context to persistent memory. Use the Task tool to delegate to the Memory agent:\n\nTask tool parameters:\n- subagent_type: agentuity-coder:agentuity-coder-memory\n- description: Save session memory\n- prompt: \"Memorialize this session. You are being invoked automatically at session end. Review the conversation above and perform a full session memorialization:\\n\\n1. Create a session summary using the Session Summary Template (PROBLEM, CONTEXT, DECISIONS, CORRECTIONS, SOLUTIONS, PATTERNS, FILES, OPEN QUESTIONS)\\n2. Extract and store any corrections/mistakes as high-priority KV entries (correction:{name})\\n3. Store any key decisions (decision:{name})\\n4. Store any reusable patterns (pattern:{name})\\n5. Upsert the FULL session document to Vector storage for semantic search\\n6. Apply reasoning to extract conclusions (explicit, deductive, inductive, abductive) and update entity representations\\n7. Current branch: ${GIT_BRANCH}\\n\\nDo NOT ask questions. Summarize and store everything you can from the conversation history. Prioritize corrections and decisions.\"\n\nAfter the Memory agent completes, you may stop."
|
|
67
|
+
}
|
|
68
|
+
EOF
|
|
69
|
+
exit 2
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentuity/claude-code",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"author": "Agentuity employees and contributors",
|
|
6
|
+
"description": "Agentuity Coder plugin for Claude Code with specialized AI coding agents",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/install.js",
|
|
9
|
+
"module": "./dist/install.js",
|
|
10
|
+
"types": "./dist/install.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"AGENTS.md",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE",
|
|
15
|
+
".claude-plugin",
|
|
16
|
+
"agents",
|
|
17
|
+
"skills",
|
|
18
|
+
"hooks",
|
|
19
|
+
"commands",
|
|
20
|
+
"src",
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"exports": {
|
|
24
|
+
".": "./dist/install.js"
|
|
25
|
+
},
|
|
26
|
+
"typesVersions": {
|
|
27
|
+
"*": {
|
|
28
|
+
".": [
|
|
29
|
+
"./dist/install.d.ts"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
35
|
+
"build": "bunx tsc --build --force",
|
|
36
|
+
"typecheck": "bunx tsc --noEmit",
|
|
37
|
+
"test": "bun test",
|
|
38
|
+
"prepublishOnly": "bun run clean && bun run build"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/bun": "latest",
|
|
42
|
+
"bun-types": "latest",
|
|
43
|
+
"typescript": "^5.9.0"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"sideEffects": false
|
|
49
|
+
}
|