deepwork 0.3.0__py3-none-any.whl → 0.4.0__py3-none-any.whl
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.
- deepwork/cli/hook.py +70 -0
- deepwork/cli/install.py +77 -29
- deepwork/cli/main.py +4 -0
- deepwork/cli/rules.py +32 -0
- deepwork/cli/sync.py +27 -1
- deepwork/core/adapters.py +209 -0
- deepwork/core/command_executor.py +26 -9
- deepwork/core/doc_spec_parser.py +205 -0
- deepwork/core/generator.py +79 -4
- deepwork/core/hooks_syncer.py +15 -2
- deepwork/core/parser.py +64 -2
- deepwork/core/rules_parser.py +58 -10
- deepwork/hooks/__init__.py +9 -3
- deepwork/hooks/check_version.sh +230 -0
- deepwork/hooks/claude_hook.sh +13 -17
- deepwork/hooks/gemini_hook.sh +13 -17
- deepwork/hooks/rules_check.py +269 -24
- deepwork/hooks/wrapper.py +66 -16
- deepwork/schemas/doc_spec_schema.py +64 -0
- deepwork/schemas/job_schema.py +25 -3
- deepwork/schemas/rules_schema.py +38 -6
- deepwork/standard_jobs/deepwork_jobs/doc_specs/job_spec.md +190 -0
- deepwork/standard_jobs/deepwork_jobs/job.yml +41 -8
- deepwork/standard_jobs/deepwork_jobs/steps/define.md +68 -2
- deepwork/standard_jobs/deepwork_jobs/steps/implement.md +3 -3
- deepwork/standard_jobs/deepwork_jobs/steps/learn.md +74 -5
- deepwork/standard_jobs/deepwork_jobs/steps/review_job_spec.md +208 -0
- deepwork/standard_jobs/deepwork_jobs/templates/doc_spec.md.example +86 -0
- deepwork/standard_jobs/deepwork_jobs/templates/doc_spec.md.template +26 -0
- deepwork/standard_jobs/deepwork_rules/hooks/capture_prompt_work_tree.sh +21 -10
- deepwork/standard_jobs/deepwork_rules/job.yml +13 -3
- deepwork/standard_jobs/deepwork_rules/rules/skill-md-validation.md +1 -0
- deepwork/templates/claude/skill-job-meta.md.jinja +7 -0
- deepwork/templates/claude/skill-job-step.md.jinja +60 -7
- deepwork/templates/gemini/skill-job-step.toml.jinja +18 -3
- deepwork/utils/fs.py +36 -0
- deepwork/utils/yaml_utils.py +24 -0
- {deepwork-0.3.0.dist-info → deepwork-0.4.0.dist-info}/METADATA +41 -2
- deepwork-0.4.0.dist-info/RECORD +71 -0
- deepwork-0.3.0.dist-info/RECORD +0 -62
- {deepwork-0.3.0.dist-info → deepwork-0.4.0.dist-info}/WHEEL +0 -0
- {deepwork-0.3.0.dist-info → deepwork-0.4.0.dist-info}/entry_points.txt +0 -0
- {deepwork-0.3.0.dist-info → deepwork-0.4.0.dist-info}/licenses/LICENSE.md +0 -0
deepwork/hooks/__init__.py
CHANGED
|
@@ -17,7 +17,7 @@ Usage with wrapper system:
|
|
|
17
17
|
"Stop": [{
|
|
18
18
|
"hooks": [{
|
|
19
19
|
"type": "command",
|
|
20
|
-
"command": ".deepwork/hooks/claude_hook.sh
|
|
20
|
+
"command": ".deepwork/hooks/claude_hook.sh rules_check"
|
|
21
21
|
}]
|
|
22
22
|
}]
|
|
23
23
|
}
|
|
@@ -29,12 +29,15 @@ Usage with wrapper system:
|
|
|
29
29
|
"AfterAgent": [{
|
|
30
30
|
"hooks": [{
|
|
31
31
|
"type": "command",
|
|
32
|
-
"command": ".gemini/hooks/gemini_hook.sh
|
|
32
|
+
"command": ".gemini/hooks/gemini_hook.sh rules_check"
|
|
33
33
|
}]
|
|
34
34
|
}]
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
The shell wrappers call `deepwork hook <hook_name>` which works regardless
|
|
39
|
+
of how deepwork was installed (pipx, uv, nix flake, etc.).
|
|
40
|
+
|
|
38
41
|
Writing custom hooks:
|
|
39
42
|
from deepwork.hooks.wrapper import (
|
|
40
43
|
HookInput,
|
|
@@ -50,10 +53,13 @@ Writing custom hooks:
|
|
|
50
53
|
return HookOutput(decision="block", reason="Complete X first")
|
|
51
54
|
return HookOutput()
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
def main():
|
|
54
57
|
import os, sys
|
|
55
58
|
platform = Platform(os.environ.get("DEEPWORK_HOOK_PLATFORM", "claude"))
|
|
56
59
|
sys.exit(run_hook(my_hook, platform))
|
|
60
|
+
|
|
61
|
+
if __name__ == "__main__":
|
|
62
|
+
main()
|
|
57
63
|
"""
|
|
58
64
|
|
|
59
65
|
from deepwork.hooks.wrapper import (
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# check_version.sh - SessionStart hook to check Claude Code version and deepwork installation
|
|
3
|
+
#
|
|
4
|
+
# This hook performs two critical checks:
|
|
5
|
+
# 1. Verifies that the 'deepwork' command is installed and directly invokable
|
|
6
|
+
# 2. Warns users if their Claude Code version is below the minimum required
|
|
7
|
+
#
|
|
8
|
+
# The deepwork check is blocking (exit 2) because hooks cannot function without it.
|
|
9
|
+
# The version check is informational only (exit 0) to avoid blocking sessions.
|
|
10
|
+
#
|
|
11
|
+
# Uses hookSpecificOutput.additionalContext to pass messages to Claude's context.
|
|
12
|
+
|
|
13
|
+
# ============================================================================
|
|
14
|
+
# DEEPWORK INSTALLATION CHECK (BLOCKING)
|
|
15
|
+
# ============================================================================
|
|
16
|
+
# This check runs on EVERY hook invocation (no re-entry guard) because if
|
|
17
|
+
# deepwork is not installed, nothing else will work.
|
|
18
|
+
|
|
19
|
+
check_deepwork_installed() {
|
|
20
|
+
# Run 'deepwork rules clear_queue' instead of just '--version' for double utility:
|
|
21
|
+
# 1. Verifies that the 'deepwork' command is installed and directly invokable
|
|
22
|
+
# 2. Clears any stale rules from the queue, ensuring a clean slate for the session
|
|
23
|
+
if ! deepwork rules clear_queue >/dev/null 2>&1; then
|
|
24
|
+
return 1
|
|
25
|
+
fi
|
|
26
|
+
return 0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
print_deepwork_error() {
|
|
30
|
+
cat >&2 << 'EOF'
|
|
31
|
+
|
|
32
|
+
================================================================================
|
|
33
|
+
*** DEEPWORK NOT INSTALLED ***
|
|
34
|
+
================================================================================
|
|
35
|
+
|
|
36
|
+
ERROR: The 'deepwork' command is not available or cannot be directly invoked.
|
|
37
|
+
|
|
38
|
+
DeepWork must be installed such that running 'deepwork' directly works.
|
|
39
|
+
For example, running 'deepwork rules clear_queue' should succeed.
|
|
40
|
+
|
|
41
|
+
IMPORTANT: Do NOT use 'uv run deepwork' or similar wrappers.
|
|
42
|
+
The command must be directly invokable as just 'deepwork'.
|
|
43
|
+
|
|
44
|
+
------------------------------------------------------------------------
|
|
45
|
+
| |
|
|
46
|
+
| Please fix your deepwork installation before proceeding. |
|
|
47
|
+
| |
|
|
48
|
+
| Installation options: |
|
|
49
|
+
| - pipx install deepwork |
|
|
50
|
+
| - pip install --user deepwork (ensure ~/.local/bin is in PATH) |
|
|
51
|
+
| - nix develop (if using the nix flake) |
|
|
52
|
+
| |
|
|
53
|
+
------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
================================================================================
|
|
56
|
+
|
|
57
|
+
EOF
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
output_deepwork_error_json() {
|
|
61
|
+
cat << 'EOF'
|
|
62
|
+
{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"DEEPWORK INSTALLATION ERROR: The 'deepwork' command is not installed or cannot be directly invoked. DeepWork must be installed such that it can be directly invoked (e.g., 'deepwork', NOT 'uv run deepwork'). Please fix your deepwork installation before proceeding with anything else. DO NOT CONTINUE until this is resolved."},"error":"deepwork command not found - please install deepwork so it can be directly invoked"}
|
|
63
|
+
EOF
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Check deepwork installation FIRST (before any other checks)
|
|
67
|
+
if ! check_deepwork_installed; then
|
|
68
|
+
print_deepwork_error
|
|
69
|
+
output_deepwork_error_json
|
|
70
|
+
exit 2 # Blocking error - prevent session from continuing
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# ============================================================================
|
|
74
|
+
# RE-ENTRY GUARD (for version check only)
|
|
75
|
+
# ============================================================================
|
|
76
|
+
# SessionStart hooks can be triggered multiple times in a session (on resume,
|
|
77
|
+
# clear, etc.). We only want to show the version warning once per session to
|
|
78
|
+
# avoid spamming the user. We use an environment variable to track whether
|
|
79
|
+
# we've already run. Note: This relies on the parent process preserving env
|
|
80
|
+
# vars across hook invocations within the same session.
|
|
81
|
+
if [ -n "$DEEPWORK_VERSION_CHECK_DONE" ]; then
|
|
82
|
+
# Already checked version this session, exit silently with empty JSON
|
|
83
|
+
echo '{}'
|
|
84
|
+
exit 0
|
|
85
|
+
fi
|
|
86
|
+
export DEEPWORK_VERSION_CHECK_DONE=1
|
|
87
|
+
|
|
88
|
+
# ============================================================================
|
|
89
|
+
# MINIMUM VERSION CONFIGURATION
|
|
90
|
+
# ============================================================================
|
|
91
|
+
MINIMUM_VERSION="2.1.14"
|
|
92
|
+
|
|
93
|
+
# ============================================================================
|
|
94
|
+
# VERSION CHECK LOGIC
|
|
95
|
+
# ============================================================================
|
|
96
|
+
|
|
97
|
+
# Get current Claude Code version
|
|
98
|
+
get_current_version() {
|
|
99
|
+
local version_output
|
|
100
|
+
version_output=$(claude --version 2>/dev/null) || return 1
|
|
101
|
+
# Extract version number (e.g., "2.1.1" from "2.1.1 (Claude Code)")
|
|
102
|
+
echo "$version_output" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+' | head -1
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Compare two semantic versions
|
|
106
|
+
# Returns 0 if version1 >= version2, 1 otherwise
|
|
107
|
+
version_gte() {
|
|
108
|
+
local version1="$1"
|
|
109
|
+
local version2="$2"
|
|
110
|
+
|
|
111
|
+
# Split versions into components
|
|
112
|
+
local v1_major v1_minor v1_patch
|
|
113
|
+
local v2_major v2_minor v2_patch
|
|
114
|
+
|
|
115
|
+
IFS='.' read -r v1_major v1_minor v1_patch <<< "$version1"
|
|
116
|
+
IFS='.' read -r v2_major v2_minor v2_patch <<< "$version2"
|
|
117
|
+
|
|
118
|
+
# Default to 0 if component is missing
|
|
119
|
+
v1_major=${v1_major:-0}
|
|
120
|
+
v1_minor=${v1_minor:-0}
|
|
121
|
+
v1_patch=${v1_patch:-0}
|
|
122
|
+
v2_major=${v2_major:-0}
|
|
123
|
+
v2_minor=${v2_minor:-0}
|
|
124
|
+
v2_patch=${v2_patch:-0}
|
|
125
|
+
|
|
126
|
+
# Compare major version
|
|
127
|
+
if [ "$v1_major" -gt "$v2_major" ]; then
|
|
128
|
+
return 0
|
|
129
|
+
elif [ "$v1_major" -lt "$v2_major" ]; then
|
|
130
|
+
return 1
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# Compare minor version
|
|
134
|
+
if [ "$v1_minor" -gt "$v2_minor" ]; then
|
|
135
|
+
return 0
|
|
136
|
+
elif [ "$v1_minor" -lt "$v2_minor" ]; then
|
|
137
|
+
return 1
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
# Compare patch version
|
|
141
|
+
if [ "$v1_patch" -ge "$v2_patch" ]; then
|
|
142
|
+
return 0
|
|
143
|
+
else
|
|
144
|
+
return 1
|
|
145
|
+
fi
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# Generate warning message
|
|
149
|
+
get_warning_message() {
|
|
150
|
+
local current_version="$1"
|
|
151
|
+
|
|
152
|
+
cat << EOF
|
|
153
|
+
CLAUDE CODE VERSION WARNING: Your version (${current_version}) is below the minimum recommended (${MINIMUM_VERSION}). Older versions have known bugs that may cause issues with DeepWork. RECOMMENDED: Update your version of Claude Code. TELL THE USER ABOUT THIS ISSUE LOUDLY!!!
|
|
154
|
+
EOF
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# Print visual warning to stderr for immediate user visibility
|
|
158
|
+
print_stderr_warning() {
|
|
159
|
+
local current_version="$1"
|
|
160
|
+
|
|
161
|
+
cat >&2 << EOF
|
|
162
|
+
|
|
163
|
+
================================================================================
|
|
164
|
+
*** CLAUDE CODE VERSION WARNING ***
|
|
165
|
+
================================================================================
|
|
166
|
+
|
|
167
|
+
Your Claude Code version: ${current_version}
|
|
168
|
+
Minimum recommended: ${MINIMUM_VERSION}
|
|
169
|
+
|
|
170
|
+
IMPORTANT: Versions below the minimum have known bugs that may cause
|
|
171
|
+
issues with DeepWork functionality. You may experience unexpected
|
|
172
|
+
behavior, errors, or incomplete operations.
|
|
173
|
+
|
|
174
|
+
------------------------------------------------------------------------
|
|
175
|
+
| |
|
|
176
|
+
| RECOMMENDED ACTION: Update your version of Claude Code |
|
|
177
|
+
| |
|
|
178
|
+
------------------------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
================================================================================
|
|
181
|
+
|
|
182
|
+
EOF
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
# Output JSON with additional context for Claude
|
|
186
|
+
output_json_with_context() {
|
|
187
|
+
local context="$1"
|
|
188
|
+
# Escape special characters for JSON
|
|
189
|
+
local escaped_context
|
|
190
|
+
escaped_context=$(echo "$context" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g' | tr '\n' ' ')
|
|
191
|
+
|
|
192
|
+
cat << EOF
|
|
193
|
+
{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"${escaped_context}"}}
|
|
194
|
+
EOF
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
# ============================================================================
|
|
198
|
+
# MAIN
|
|
199
|
+
# ============================================================================
|
|
200
|
+
|
|
201
|
+
main() {
|
|
202
|
+
local current_version
|
|
203
|
+
local warning_message
|
|
204
|
+
|
|
205
|
+
# Get current version (don't exit on failure)
|
|
206
|
+
current_version=$(get_current_version) || current_version=""
|
|
207
|
+
|
|
208
|
+
if [ -z "$current_version" ]; then
|
|
209
|
+
# Could not determine version, output empty JSON and exit
|
|
210
|
+
echo '{}'
|
|
211
|
+
exit 0
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
# Check if current version is below minimum
|
|
215
|
+
if ! version_gte "$current_version" "$MINIMUM_VERSION"; then
|
|
216
|
+
# Print visual warning to stderr
|
|
217
|
+
print_stderr_warning "$current_version"
|
|
218
|
+
|
|
219
|
+
# Output JSON with context for Claude
|
|
220
|
+
warning_message=$(get_warning_message "$current_version")
|
|
221
|
+
output_json_with_context "$warning_message"
|
|
222
|
+
else
|
|
223
|
+
# Version is OK, output empty JSON
|
|
224
|
+
echo '{}'
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
exit 0
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
main "$@"
|
deepwork/hooks/claude_hook.sh
CHANGED
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
# and work on any supported platform.
|
|
7
7
|
#
|
|
8
8
|
# Usage:
|
|
9
|
-
# claude_hook.sh <
|
|
9
|
+
# claude_hook.sh <hook_name>
|
|
10
10
|
#
|
|
11
11
|
# Example:
|
|
12
|
-
# claude_hook.sh
|
|
12
|
+
# claude_hook.sh rules_check
|
|
13
13
|
#
|
|
14
|
-
# The
|
|
15
|
-
#
|
|
16
|
-
# 2. The hook function receives HookInput and returns HookOutput
|
|
14
|
+
# The hook is run via the deepwork CLI, which works regardless of how
|
|
15
|
+
# deepwork was installed (pipx, uv, nix flake, etc.).
|
|
17
16
|
#
|
|
18
17
|
# Environment variables set by Claude Code:
|
|
19
18
|
# CLAUDE_PROJECT_DIR - Absolute path to project root
|
|
@@ -26,12 +25,12 @@
|
|
|
26
25
|
|
|
27
26
|
set -e
|
|
28
27
|
|
|
29
|
-
# Get the
|
|
30
|
-
|
|
28
|
+
# Get the hook name to run
|
|
29
|
+
HOOK_NAME="${1:-}"
|
|
31
30
|
|
|
32
|
-
if [ -z "${
|
|
33
|
-
echo "Usage: claude_hook.sh <
|
|
34
|
-
echo "Example: claude_hook.sh
|
|
31
|
+
if [ -z "${HOOK_NAME}" ]; then
|
|
32
|
+
echo "Usage: claude_hook.sh <hook_name>" >&2
|
|
33
|
+
echo "Example: claude_hook.sh rules_check" >&2
|
|
35
34
|
exit 1
|
|
36
35
|
fi
|
|
37
36
|
|
|
@@ -41,15 +40,12 @@ if [ ! -t 0 ]; then
|
|
|
41
40
|
HOOK_INPUT=$(cat)
|
|
42
41
|
fi
|
|
43
42
|
|
|
44
|
-
# Set platform environment variable for the
|
|
43
|
+
# Set platform environment variable for the hook
|
|
45
44
|
export DEEPWORK_HOOK_PLATFORM="claude"
|
|
46
45
|
|
|
47
|
-
# Run the
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
# 2. Processing the hook logic
|
|
51
|
-
# 3. Writing JSON to stdout
|
|
52
|
-
echo "${HOOK_INPUT}" | python -m "${PYTHON_MODULE}"
|
|
46
|
+
# Run the hook via deepwork CLI
|
|
47
|
+
# This works regardless of how deepwork was installed (pipx, uv, nix flake, etc.)
|
|
48
|
+
echo "${HOOK_INPUT}" | deepwork hook "${HOOK_NAME}"
|
|
53
49
|
exit_code=$?
|
|
54
50
|
|
|
55
51
|
exit ${exit_code}
|
deepwork/hooks/gemini_hook.sh
CHANGED
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
# and work on any supported platform.
|
|
7
7
|
#
|
|
8
8
|
# Usage:
|
|
9
|
-
# gemini_hook.sh <
|
|
9
|
+
# gemini_hook.sh <hook_name>
|
|
10
10
|
#
|
|
11
11
|
# Example:
|
|
12
|
-
# gemini_hook.sh
|
|
12
|
+
# gemini_hook.sh rules_check
|
|
13
13
|
#
|
|
14
|
-
# The
|
|
15
|
-
#
|
|
16
|
-
# 2. The hook function receives HookInput and returns HookOutput
|
|
14
|
+
# The hook is run via the deepwork CLI, which works regardless of how
|
|
15
|
+
# deepwork was installed (pipx, uv, nix flake, etc.).
|
|
17
16
|
#
|
|
18
17
|
# Environment variables set by Gemini CLI:
|
|
19
18
|
# GEMINI_PROJECT_DIR - Absolute path to project root
|
|
@@ -26,12 +25,12 @@
|
|
|
26
25
|
|
|
27
26
|
set -e
|
|
28
27
|
|
|
29
|
-
# Get the
|
|
30
|
-
|
|
28
|
+
# Get the hook name to run
|
|
29
|
+
HOOK_NAME="${1:-}"
|
|
31
30
|
|
|
32
|
-
if [ -z "${
|
|
33
|
-
echo "Usage: gemini_hook.sh <
|
|
34
|
-
echo "Example: gemini_hook.sh
|
|
31
|
+
if [ -z "${HOOK_NAME}" ]; then
|
|
32
|
+
echo "Usage: gemini_hook.sh <hook_name>" >&2
|
|
33
|
+
echo "Example: gemini_hook.sh rules_check" >&2
|
|
35
34
|
exit 1
|
|
36
35
|
fi
|
|
37
36
|
|
|
@@ -41,15 +40,12 @@ if [ ! -t 0 ]; then
|
|
|
41
40
|
HOOK_INPUT=$(cat)
|
|
42
41
|
fi
|
|
43
42
|
|
|
44
|
-
# Set platform environment variable for the
|
|
43
|
+
# Set platform environment variable for the hook
|
|
45
44
|
export DEEPWORK_HOOK_PLATFORM="gemini"
|
|
46
45
|
|
|
47
|
-
# Run the
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
# 2. Processing the hook logic
|
|
51
|
-
# 3. Writing JSON to stdout
|
|
52
|
-
echo "${HOOK_INPUT}" | python -m "${PYTHON_MODULE}"
|
|
46
|
+
# Run the hook via deepwork CLI
|
|
47
|
+
# This works regardless of how deepwork was installed (pipx, uv, nix flake, etc.)
|
|
48
|
+
echo "${HOOK_INPUT}" | deepwork hook "${HOOK_NAME}"
|
|
53
49
|
exit_code=$?
|
|
54
50
|
|
|
55
51
|
exit ${exit_code}
|