@paths.design/caws-cli 11.1.6 → 11.1.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/README.md +1 -1
- package/dist/init/hook-packs/manifest-claude-code.d.ts +1 -1
- package/dist/init/hook-packs/manifest-claude-code.d.ts.map +1 -1
- package/dist/init/hook-packs/manifest-claude-code.js +59 -6
- package/dist/init/hook-packs/manifest-claude-code.js.map +1 -1
- package/dist/init/hook-packs/types.js +1 -1
- package/dist/init/hook-packs/types.js.map +1 -1
- package/dist/shell/commands/agents.d.ts +49 -0
- package/dist/shell/commands/agents.d.ts.map +1 -0
- package/dist/shell/commands/agents.js +577 -0
- package/dist/shell/commands/agents.js.map +1 -0
- package/dist/shell/commands/claim.d.ts.map +1 -1
- package/dist/shell/commands/claim.js +3 -4
- package/dist/shell/commands/claim.js.map +1 -1
- package/dist/shell/commands/status.d.ts +12 -0
- package/dist/shell/commands/status.d.ts.map +1 -1
- package/dist/shell/commands/status.js +236 -21
- package/dist/shell/commands/status.js.map +1 -1
- package/dist/shell/commands/worktree.d.ts +9 -0
- package/dist/shell/commands/worktree.d.ts.map +1 -1
- package/dist/shell/commands/worktree.js +302 -0
- package/dist/shell/commands/worktree.js.map +1 -1
- package/dist/shell/index.d.ts +4 -2
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +12 -1
- package/dist/shell/index.js.map +1 -1
- package/dist/shell/register.d.ts.map +1 -1
- package/dist/shell/register.js +150 -0
- package/dist/shell/register.js.map +1 -1
- package/dist/shell/render/status.d.ts +7 -1
- package/dist/shell/render/status.d.ts.map +1 -1
- package/dist/shell/render/status.js +72 -0
- package/dist/shell/render/status.js.map +1 -1
- package/dist/store/agents-store.d.ts.map +1 -1
- package/dist/store/agents-store.js +9 -0
- package/dist/store/agents-store.js.map +1 -1
- package/dist/store/apply-patch.d.ts.map +1 -1
- package/dist/store/apply-patch.js +15 -0
- package/dist/store/apply-patch.js.map +1 -1
- package/dist/store/doctor-snapshot.d.ts.map +1 -1
- package/dist/store/doctor-snapshot.js +143 -3
- package/dist/store/doctor-snapshot.js.map +1 -1
- package/dist/store/git-sparse-checkout.d.ts +25 -0
- package/dist/store/git-sparse-checkout.d.ts.map +1 -0
- package/dist/store/git-sparse-checkout.js +101 -0
- package/dist/store/git-sparse-checkout.js.map +1 -0
- package/dist/store/index.d.ts +2 -0
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +10 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store/leases-store.d.ts +89 -0
- package/dist/store/leases-store.d.ts.map +1 -0
- package/dist/store/leases-store.js +369 -0
- package/dist/store/leases-store.js.map +1 -0
- package/dist/store/lifecycle-transaction.d.ts.map +1 -1
- package/dist/store/lifecycle-transaction.js +34 -1
- package/dist/store/lifecycle-transaction.js.map +1 -1
- package/dist/store/rules.d.ts +21 -1
- package/dist/store/rules.d.ts.map +1 -1
- package/dist/store/rules.js +22 -0
- package/dist/store/rules.js.map +1 -1
- package/dist/store/types.d.ts +25 -1
- package/dist/store/types.d.ts.map +1 -1
- package/dist/store/worktrees-migration.d.ts +141 -0
- package/dist/store/worktrees-migration.d.ts.map +1 -0
- package/dist/store/worktrees-migration.js +356 -0
- package/dist/store/worktrees-migration.js.map +1 -0
- package/dist/store/worktrees-writer.d.ts.map +1 -1
- package/dist/store/worktrees-writer.js +37 -1
- package/dist/store/worktrees-writer.js.map +1 -1
- package/package.json +2 -2
- package/templates/hook-packs/claude-code/CLAUDE.md +5 -5
- package/templates/hook-packs/claude-code/agent-heartbeat.sh +131 -0
- package/templates/hook-packs/claude-code/agent-register.sh +62 -0
- package/templates/hook-packs/claude-code/agent-stop.sh +51 -0
- package/templates/hook-packs/claude-code/audit.sh +1 -1
- package/templates/hook-packs/claude-code/block-dangerous.sh +1 -1
- package/templates/hook-packs/claude-code/classify_command.py +1 -1
- package/templates/hook-packs/claude-code/dispatch/post_tool_use.sh +1 -1
- package/templates/hook-packs/claude-code/dispatch/pre_tool_use.sh +11 -2
- package/templates/hook-packs/claude-code/dispatch/session_start.sh +6 -2
- package/templates/hook-packs/claude-code/dispatch/stop.sh +7 -2
- package/templates/hook-packs/claude-code/guard-strikes.sh +1 -1
- package/templates/hook-packs/claude-code/lib/parse-input.sh +1 -1
- package/templates/hook-packs/claude-code/lib/run-handlers.sh +1 -1
- package/templates/hook-packs/claude-code/reset-danger-latch.sh +1 -1
- package/templates/hook-packs/claude-code/reset-strikes.sh +1 -1
- package/templates/hook-packs/claude-code/runtime-paths.sh +1 -1
- package/templates/hook-packs/claude-code/scope-guard.sh +1 -1
- package/templates/hook-packs/claude-code/session-caws-status.sh +7 -1
- package/templates/hook-packs/claude-code/session-log.sh +1 -1
- package/templates/hook-packs/claude-code/worktree-guard.sh +130 -4
- package/templates/hook-packs/claude-code/worktree-write-guard.sh +133 -18
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# CAWS-MANAGED-HOOK
|
|
3
3
|
# hook_pack: claude-code
|
|
4
|
-
# hook_pack_version:
|
|
4
|
+
# hook_pack_version: 5
|
|
5
5
|
# caws_min_major: 11
|
|
6
6
|
# lineage_refs: 4,8,13
|
|
7
7
|
# do_not_edit_directly: update via `caws init --agent-surface claude-code`
|
|
8
8
|
#
|
|
9
|
-
# CAWS Worktree Write Guard for Claude Code
|
|
10
|
-
# fail-open for v11.1).
|
|
9
|
+
# CAWS Worktree Write Guard for Claude Code.
|
|
11
10
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
11
|
+
# Two responsibilities:
|
|
12
|
+
#
|
|
13
|
+
# 1. Canonical-spec-materialization refusal
|
|
14
|
+
# (WORKTREE-SPEC-CANONICAL-ACCESS-GUARD-001 A1/A2).
|
|
15
|
+
# From inside a linked worktree (git rev-parse --git-common-dir !=
|
|
16
|
+
# git rev-parse --git-dir, after realpath normalization), refuse
|
|
17
|
+
# Read/Write/Edit tool calls whose file_path resolves under
|
|
18
|
+
# <linked-worktree>/.caws/specs/*. Such files would be private
|
|
19
|
+
# materialized copies of canonical spec authority, divergent from
|
|
20
|
+
# the canonical .caws/specs bytes, silently consulted by anything
|
|
21
|
+
# that walks cwd upward. The refusal MUST fire BEFORE the broad
|
|
22
|
+
# .caws/* allowlist below, otherwise the allowlist would exit 0
|
|
23
|
+
# first and the slice would appear implemented while the target
|
|
24
|
+
# path still bypassed the guard. The canonical checkout itself
|
|
25
|
+
# (git_common_dir == git_dir) IS spec authority and is allowed
|
|
26
|
+
# through this predicate; this refusal targets the linked-worktree
|
|
27
|
+
# materialization class only.
|
|
28
|
+
#
|
|
29
|
+
# 2. Base-branch write enforcement (intentionally fail-open for
|
|
30
|
+
# v11.1, restored in CLI-WORKTREE-001). The hook serves as the
|
|
31
|
+
# managed-install seat for the worktree-write enforcement surface
|
|
32
|
+
# and asserts the always-allowed allowlist so .caws/, .claude/,
|
|
33
|
+
# docs/, scripts/, tmp/, and tests/ writes are never inadvertently
|
|
34
|
+
# blocked by a future enforcement pass that forgets the allowlist.
|
|
19
35
|
#
|
|
20
36
|
# Worktree-active enforcement (when restored) must read the worktrees
|
|
21
37
|
# registry under both shapes:
|
|
@@ -34,23 +50,122 @@ TOOL_NAME="$HOOK_TOOL_NAME"
|
|
|
34
50
|
FILE_PATH="$HOOK_FILE_PATH"
|
|
35
51
|
|
|
36
52
|
case "$TOOL_NAME" in
|
|
37
|
-
Write|Edit) ;;
|
|
53
|
+
Read|Write|Edit) ;;
|
|
38
54
|
*) exit 0 ;;
|
|
39
55
|
esac
|
|
40
56
|
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
# WORKTREE_ROOT: where the agent is operating from. This is the cwd
|
|
58
|
+
# whose .caws/specs/* path is the refusal target. Kept distinct from
|
|
59
|
+
# CANONICAL_ROOT below — these MUST NOT be conflated for the spec-path
|
|
60
|
+
# predicate.
|
|
61
|
+
WORKTREE_ROOT="${CLAUDE_PROJECT_DIR:-.}"
|
|
62
|
+
WORKTREE_ROOT="$(cd "$WORKTREE_ROOT" 2>/dev/null && pwd -P || printf '%s\n' "$WORKTREE_ROOT")"
|
|
43
63
|
|
|
64
|
+
# _realpath: best-effort realpath. macOS lacks `readlink -f` by default;
|
|
65
|
+
# python3 is available on every supported runner (CI matrix verified).
|
|
66
|
+
# Falls back to the original path if realpath cannot resolve.
|
|
67
|
+
_realpath() {
|
|
68
|
+
local p="$1"
|
|
69
|
+
if [[ -z "$p" ]]; then
|
|
70
|
+
printf '%s\n' ""
|
|
71
|
+
return 0
|
|
72
|
+
fi
|
|
73
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
74
|
+
python3 -c "import os, sys; print(os.path.realpath(sys.argv[1]))" "$p" 2>/dev/null || printf '%s\n' "$p"
|
|
75
|
+
else
|
|
76
|
+
printf '%s\n' "$p"
|
|
77
|
+
fi
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# Linked-worktree detection via git as primary signal. CAWS registry
|
|
81
|
+
# (.caws/worktrees.json) is consulted ONLY for diagnostic enrichment;
|
|
82
|
+
# a registry desync MUST NOT suppress the refusal (I3).
|
|
83
|
+
IS_LINKED_WORKTREE=0
|
|
84
|
+
CANONICAL_ROOT=""
|
|
44
85
|
if command -v git >/dev/null 2>&1; then
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
86
|
+
GIT_COMMON_DIR_RAW="$(cd "$WORKTREE_ROOT" 2>/dev/null && git rev-parse --git-common-dir 2>/dev/null || printf '')"
|
|
87
|
+
GIT_DIR_RAW="$(cd "$WORKTREE_ROOT" 2>/dev/null && git rev-parse --git-dir 2>/dev/null || printf '')"
|
|
88
|
+
if [[ -n "$GIT_COMMON_DIR_RAW" ]] && [[ -n "$GIT_DIR_RAW" ]]; then
|
|
89
|
+
# Resolve relative paths against WORKTREE_ROOT before realpath.
|
|
90
|
+
case "$GIT_COMMON_DIR_RAW" in
|
|
91
|
+
/*) GIT_COMMON_DIR_ABS="$GIT_COMMON_DIR_RAW" ;;
|
|
92
|
+
*) GIT_COMMON_DIR_ABS="$WORKTREE_ROOT/$GIT_COMMON_DIR_RAW" ;;
|
|
93
|
+
esac
|
|
94
|
+
case "$GIT_DIR_RAW" in
|
|
95
|
+
/*) GIT_DIR_ABS="$GIT_DIR_RAW" ;;
|
|
96
|
+
*) GIT_DIR_ABS="$WORKTREE_ROOT/$GIT_DIR_RAW" ;;
|
|
97
|
+
esac
|
|
98
|
+
GIT_COMMON_DIR="$(_realpath "$GIT_COMMON_DIR_ABS")"
|
|
99
|
+
GIT_DIR="$(_realpath "$GIT_DIR_ABS")"
|
|
100
|
+
if [[ -n "$GIT_COMMON_DIR" ]] && [[ "$GIT_COMMON_DIR" != "$GIT_DIR" ]]; then
|
|
101
|
+
IS_LINKED_WORKTREE=1
|
|
102
|
+
# CANONICAL_ROOT = parent of GIT_COMMON_DIR. Used for allowlist
|
|
103
|
+
# rewriting only; NOT used for the spec-path refusal predicate.
|
|
104
|
+
CANONICAL_CANDIDATE="$(_realpath "$GIT_COMMON_DIR/..")"
|
|
105
|
+
if [[ -n "$CANONICAL_CANDIDATE" ]] && [[ -d "$CANONICAL_CANDIDATE/.caws" ]]; then
|
|
106
|
+
CANONICAL_ROOT="$CANONICAL_CANDIDATE"
|
|
107
|
+
fi
|
|
50
108
|
fi
|
|
51
109
|
fi
|
|
52
110
|
fi
|
|
53
111
|
|
|
112
|
+
# Canonical-spec-materialization refusal (I1: BEFORE the allowlist).
|
|
113
|
+
#
|
|
114
|
+
# Predicate: tool_name in {Read,Write,Edit} (already gated above)
|
|
115
|
+
# AND is_linked_worktree (via git signal)
|
|
116
|
+
# AND FILE_PATH resolves under <WORKTREE_ROOT>/.caws/specs/.
|
|
117
|
+
#
|
|
118
|
+
# WORKTREE_ROOT is the cwd-as-resolved-via-CLAUDE_PROJECT_DIR. NOT
|
|
119
|
+
# CANONICAL_ROOT, NOT a PROJECT_DIR that has been rewritten upward. The
|
|
120
|
+
# refused path lives under the LINKED worktree's tree.
|
|
121
|
+
if [[ "$IS_LINKED_WORKTREE" == "1" ]] && [[ -n "$FILE_PATH" ]]; then
|
|
122
|
+
# WORKTREE_ROOT is already realpath-normalized (pwd -P above), so
|
|
123
|
+
# SPEC_ROOT inherits that normalization. We MUST also normalize
|
|
124
|
+
# FILE_PATH_ABS through _realpath so the comparison is symlink-
|
|
125
|
+
# immune. On macOS, /tmp -> /private/tmp; without normalization, an
|
|
126
|
+
# agent-supplied /tmp/.../.caws/specs/X.yaml would NOT prefix-match
|
|
127
|
+
# SPEC_ROOT=/private/tmp/.../.caws/specs because the literal strings
|
|
128
|
+
# diverge. python3 os.path.realpath resolves the existing prefix
|
|
129
|
+
# even when the leaf does not exist (Write tool case).
|
|
130
|
+
SPEC_ROOT="$WORKTREE_ROOT/.caws/specs"
|
|
131
|
+
case "$FILE_PATH" in
|
|
132
|
+
/*) FILE_PATH_ABS="$FILE_PATH" ;;
|
|
133
|
+
*) FILE_PATH_ABS="$WORKTREE_ROOT/$FILE_PATH" ;;
|
|
134
|
+
esac
|
|
135
|
+
FILE_PATH_ABS="$(_realpath "$FILE_PATH_ABS")"
|
|
136
|
+
case "$FILE_PATH_ABS" in
|
|
137
|
+
"$SPEC_ROOT"/*|"$SPEC_ROOT")
|
|
138
|
+
echo "[worktree-write-guard.sh] BLOCKED: $FILE_PATH" >&2
|
|
139
|
+
echo "[worktree-write-guard.sh] Refusing $TOOL_NAME against a linked-worktree .caws/specs/ path." >&2
|
|
140
|
+
echo "[worktree-write-guard.sh]" >&2
|
|
141
|
+
echo "[worktree-write-guard.sh] Linked worktrees must not use worktree-local .caws/specs/ files as authority." >&2
|
|
142
|
+
echo "[worktree-write-guard.sh] That path would be a private materialized copy, not canonical spec authority." >&2
|
|
143
|
+
echo "[worktree-write-guard.sh] CAWS resolves spec reads through the canonical control plane regardless of cwd." >&2
|
|
144
|
+
echo "[worktree-write-guard.sh]" >&2
|
|
145
|
+
echo "[worktree-write-guard.sh] To read a spec from any cwd (including this worktree), use:" >&2
|
|
146
|
+
echo "[worktree-write-guard.sh] caws specs show <id>" >&2
|
|
147
|
+
echo "[worktree-write-guard.sh]" >&2
|
|
148
|
+
echo "[worktree-write-guard.sh] To check scope from any cwd, use:" >&2
|
|
149
|
+
echo "[worktree-write-guard.sh] caws scope show <path>" >&2
|
|
150
|
+
echo "[worktree-write-guard.sh] caws scope check <path>" >&2
|
|
151
|
+
echo "[worktree-write-guard.sh]" >&2
|
|
152
|
+
echo "[worktree-write-guard.sh] If sparse-checkout was disabled in this worktree and you need to restore" >&2
|
|
153
|
+
echo "[worktree-write-guard.sh] the canonical-only invariant, run from the canonical checkout:" >&2
|
|
154
|
+
echo "[worktree-write-guard.sh] caws worktree repair-sparse <name>" >&2
|
|
155
|
+
exit 2
|
|
156
|
+
;;
|
|
157
|
+
esac
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
# Legacy allowlist preserved from v11.1 fail-open base-branch enforcement.
|
|
161
|
+
# For the allowlist, use PROJECT_DIR rewritten toward the canonical checkout
|
|
162
|
+
# (the historical behavior) so that .caws/ etc. paths under canonical also
|
|
163
|
+
# match when the agent is operating from inside a linked worktree.
|
|
164
|
+
PROJECT_DIR="$WORKTREE_ROOT"
|
|
165
|
+
if [[ -n "$CANONICAL_ROOT" ]]; then
|
|
166
|
+
PROJECT_DIR="$CANONICAL_ROOT"
|
|
167
|
+
fi
|
|
168
|
+
|
|
54
169
|
# Always-allowed paths bypass any future enforcement.
|
|
55
170
|
# User-global Claude state lives outside the repo; .caws/, .claude/, docs/,
|
|
56
171
|
# scripts/, tmp/, .archive/, and .githooks/ are coordination/governance
|