deepwork 0.1.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/__init__.py +25 -0
- deepwork/cli/__init__.py +1 -0
- deepwork/cli/install.py +290 -0
- deepwork/cli/main.py +25 -0
- deepwork/cli/sync.py +176 -0
- deepwork/core/__init__.py +1 -0
- deepwork/core/adapters.py +373 -0
- deepwork/core/detector.py +93 -0
- deepwork/core/generator.py +290 -0
- deepwork/core/hooks_syncer.py +206 -0
- deepwork/core/parser.py +310 -0
- deepwork/core/policy_parser.py +285 -0
- deepwork/hooks/__init__.py +1 -0
- deepwork/hooks/evaluate_policies.py +159 -0
- deepwork/schemas/__init__.py +1 -0
- deepwork/schemas/job_schema.py +212 -0
- deepwork/schemas/policy_schema.py +68 -0
- deepwork/standard_jobs/deepwork_jobs/job.yml +102 -0
- deepwork/standard_jobs/deepwork_jobs/steps/define.md +359 -0
- deepwork/standard_jobs/deepwork_jobs/steps/implement.md +435 -0
- deepwork/standard_jobs/deepwork_jobs/steps/refine.md +447 -0
- deepwork/standard_jobs/deepwork_policy/hooks/capture_work_tree.sh +26 -0
- deepwork/standard_jobs/deepwork_policy/hooks/get_changed_files.sh +30 -0
- deepwork/standard_jobs/deepwork_policy/hooks/global_hooks.yml +8 -0
- deepwork/standard_jobs/deepwork_policy/hooks/policy_stop_hook.sh +72 -0
- deepwork/standard_jobs/deepwork_policy/hooks/user_prompt_submit.sh +17 -0
- deepwork/standard_jobs/deepwork_policy/job.yml +35 -0
- deepwork/standard_jobs/deepwork_policy/steps/define.md +174 -0
- deepwork/templates/__init__.py +1 -0
- deepwork/templates/claude/command-job-step.md.jinja +210 -0
- deepwork/templates/gemini/command-job-step.toml.jinja +169 -0
- deepwork/utils/__init__.py +1 -0
- deepwork/utils/fs.py +128 -0
- deepwork/utils/git.py +164 -0
- deepwork/utils/validation.py +31 -0
- deepwork/utils/yaml_utils.py +89 -0
- deepwork-0.1.0.dist-info/METADATA +389 -0
- deepwork-0.1.0.dist-info/RECORD +41 -0
- deepwork-0.1.0.dist-info/WHEEL +4 -0
- deepwork-0.1.0.dist-info/entry_points.txt +2 -0
- deepwork-0.1.0.dist-info/licenses/LICENSE.md +60 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Define Policy
|
|
2
|
+
|
|
3
|
+
## Objective
|
|
4
|
+
|
|
5
|
+
Create or update policy entries in the `.deepwork.policy.yml` file to enforce team guidelines, documentation requirements, or other constraints when specific files change.
|
|
6
|
+
|
|
7
|
+
## Task
|
|
8
|
+
|
|
9
|
+
Guide the user through defining a new policy by asking clarifying questions. **Do not create the policy without first understanding what they want to enforce.**
|
|
10
|
+
|
|
11
|
+
### Step 1: Understand the Policy Purpose
|
|
12
|
+
|
|
13
|
+
Start by asking questions to understand what the user wants to enforce:
|
|
14
|
+
|
|
15
|
+
1. **What guideline or constraint should this policy enforce?**
|
|
16
|
+
- What situation triggers the need for action?
|
|
17
|
+
- What files or directories, when changed, should trigger this policy?
|
|
18
|
+
- Examples: "When config files change", "When API code changes", "When database schema changes"
|
|
19
|
+
|
|
20
|
+
2. **What action should be taken?**
|
|
21
|
+
- What should the agent do when the policy triggers?
|
|
22
|
+
- Update documentation? Perform a security review? Update tests?
|
|
23
|
+
- Is there a specific file or process that needs attention?
|
|
24
|
+
|
|
25
|
+
3. **Are there any "safety" conditions?**
|
|
26
|
+
- Are there files that, if also changed, mean the policy doesn't need to fire?
|
|
27
|
+
- For example: If config changes AND install_guide.md changes, assume docs are already updated
|
|
28
|
+
- This prevents redundant prompts when the user has already done the right thing
|
|
29
|
+
|
|
30
|
+
### Step 2: Define the Trigger Patterns
|
|
31
|
+
|
|
32
|
+
Help the user define glob patterns for files that should trigger the policy:
|
|
33
|
+
|
|
34
|
+
**Common patterns:**
|
|
35
|
+
- `src/**/*.py` - All Python files in src directory (recursive)
|
|
36
|
+
- `app/config/**/*` - All files in app/config directory
|
|
37
|
+
- `*.md` - All markdown files in root
|
|
38
|
+
- `src/api/**/*` - All files in the API directory
|
|
39
|
+
- `migrations/**/*.sql` - All SQL migrations
|
|
40
|
+
|
|
41
|
+
**Pattern syntax:**
|
|
42
|
+
- `*` - Matches any characters within a single path segment
|
|
43
|
+
- `**` - Matches any characters across multiple path segments (recursive)
|
|
44
|
+
- `?` - Matches a single character
|
|
45
|
+
|
|
46
|
+
### Step 3: Define Safety Patterns (Optional)
|
|
47
|
+
|
|
48
|
+
If there are files that, when also changed, mean the policy shouldn't fire:
|
|
49
|
+
|
|
50
|
+
**Examples:**
|
|
51
|
+
- Policy: "Update install guide when config changes"
|
|
52
|
+
- Trigger: `app/config/**/*`
|
|
53
|
+
- Safety: `docs/install_guide.md` (if already updated, don't prompt)
|
|
54
|
+
|
|
55
|
+
- Policy: "Security review for auth changes"
|
|
56
|
+
- Trigger: `src/auth/**/*`
|
|
57
|
+
- Safety: `SECURITY.md`, `docs/security_review.md`
|
|
58
|
+
|
|
59
|
+
### Step 4: Write the Instructions
|
|
60
|
+
|
|
61
|
+
Create clear, actionable instructions for what the agent should do when the policy fires.
|
|
62
|
+
|
|
63
|
+
**Good instructions include:**
|
|
64
|
+
- What to check or review
|
|
65
|
+
- What files might need updating
|
|
66
|
+
- Specific actions to take
|
|
67
|
+
- Quality criteria for completion
|
|
68
|
+
|
|
69
|
+
**Example:**
|
|
70
|
+
```
|
|
71
|
+
Configuration files have changed. Please:
|
|
72
|
+
1. Review docs/install_guide.md for accuracy
|
|
73
|
+
2. Update any installation steps that reference changed config
|
|
74
|
+
3. Verify environment variable documentation is current
|
|
75
|
+
4. Test that installation instructions still work
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Step 5: Create the Policy Entry
|
|
79
|
+
|
|
80
|
+
Create or update `.deepwork.policy.yml` in the project root.
|
|
81
|
+
|
|
82
|
+
**File Location**: `.deepwork.policy.yml` (root of project)
|
|
83
|
+
|
|
84
|
+
**Format**:
|
|
85
|
+
```yaml
|
|
86
|
+
- name: "[Friendly name for the policy]"
|
|
87
|
+
trigger: "[glob pattern]" # or array: ["pattern1", "pattern2"]
|
|
88
|
+
safety: "[glob pattern]" # optional, or array
|
|
89
|
+
instructions: |
|
|
90
|
+
[Multi-line instructions for the agent...]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Alternative with instructions_file**:
|
|
94
|
+
```yaml
|
|
95
|
+
- name: "[Friendly name for the policy]"
|
|
96
|
+
trigger: "[glob pattern]"
|
|
97
|
+
safety: "[glob pattern]"
|
|
98
|
+
instructions_file: "path/to/instructions.md"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Step 6: Verify the Policy
|
|
102
|
+
|
|
103
|
+
After creating the policy:
|
|
104
|
+
|
|
105
|
+
1. **Check the YAML syntax** - Ensure valid YAML formatting
|
|
106
|
+
2. **Test trigger patterns** - Verify patterns match intended files
|
|
107
|
+
3. **Review instructions** - Ensure they're clear and actionable
|
|
108
|
+
4. **Check for conflicts** - Ensure the policy doesn't conflict with existing ones
|
|
109
|
+
|
|
110
|
+
## Example Policies
|
|
111
|
+
|
|
112
|
+
### Update Documentation on Config Changes
|
|
113
|
+
```yaml
|
|
114
|
+
- name: "Update install guide on config changes"
|
|
115
|
+
trigger: "app/config/**/*"
|
|
116
|
+
safety: "docs/install_guide.md"
|
|
117
|
+
instructions: |
|
|
118
|
+
Configuration files have been modified. Please review docs/install_guide.md
|
|
119
|
+
and update it if any installation instructions need to change based on the
|
|
120
|
+
new configuration.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Security Review for Auth Code
|
|
124
|
+
```yaml
|
|
125
|
+
- name: "Security review for authentication changes"
|
|
126
|
+
trigger:
|
|
127
|
+
- "src/auth/**/*"
|
|
128
|
+
- "src/security/**/*"
|
|
129
|
+
safety:
|
|
130
|
+
- "SECURITY.md"
|
|
131
|
+
- "docs/security_audit.md"
|
|
132
|
+
instructions: |
|
|
133
|
+
Authentication or security code has been changed. Please:
|
|
134
|
+
1. Review for hardcoded credentials or secrets
|
|
135
|
+
2. Check input validation on user inputs
|
|
136
|
+
3. Verify access control logic is correct
|
|
137
|
+
4. Update security documentation if needed
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### API Documentation Sync
|
|
141
|
+
```yaml
|
|
142
|
+
- name: "API documentation update"
|
|
143
|
+
trigger: "src/api/**/*.py"
|
|
144
|
+
safety: "docs/api/**/*.md"
|
|
145
|
+
instructions: |
|
|
146
|
+
API code has changed. Please verify that API documentation in docs/api/
|
|
147
|
+
is up to date with the code changes. Pay special attention to:
|
|
148
|
+
- New or changed endpoints
|
|
149
|
+
- Modified request/response schemas
|
|
150
|
+
- Updated authentication requirements
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Output Format
|
|
154
|
+
|
|
155
|
+
### .deepwork.policy.yml
|
|
156
|
+
Create or update this file at the project root with the new policy entry.
|
|
157
|
+
|
|
158
|
+
## Quality Criteria
|
|
159
|
+
|
|
160
|
+
- Policy name is clear and descriptive
|
|
161
|
+
- Trigger patterns accurately match the intended files
|
|
162
|
+
- Safety patterns prevent unnecessary triggering
|
|
163
|
+
- Instructions are actionable and specific
|
|
164
|
+
- YAML is valid and properly formatted
|
|
165
|
+
|
|
166
|
+
## Context
|
|
167
|
+
|
|
168
|
+
Policies are evaluated automatically when you finish working on a task. The system:
|
|
169
|
+
1. Tracks which files you changed during the session
|
|
170
|
+
2. Checks if any changes match policy trigger patterns
|
|
171
|
+
3. Skips policies where safety patterns also matched
|
|
172
|
+
4. Prompts you with instructions for any triggered policies
|
|
173
|
+
|
|
174
|
+
You can mark a policy as addressed by including `<promise>✓ Policy Name</promise>` in your response (replace Policy Name with the actual policy name). This tells the system you've already handled that policy's requirements.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Skill templates for different AI platforms."""
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: {{ step_description }}
|
|
3
|
+
{% if hooks %}
|
|
4
|
+
hooks:
|
|
5
|
+
{% for event_name, event_hooks in hooks.items() %}
|
|
6
|
+
{{ event_name }}:
|
|
7
|
+
- hooks:
|
|
8
|
+
{% for hook in event_hooks %}
|
|
9
|
+
{% if hook.type == "script" %}
|
|
10
|
+
- type: command
|
|
11
|
+
command: ".deepwork/jobs/{{ job_name }}/{{ hook.path }}"
|
|
12
|
+
{% else %}
|
|
13
|
+
- type: prompt
|
|
14
|
+
prompt: |
|
|
15
|
+
{% if event_name == "Stop" %}
|
|
16
|
+
You must evaluate whether Claude has met all the below quality criteria for the request.
|
|
17
|
+
|
|
18
|
+
## Quality Criteria
|
|
19
|
+
|
|
20
|
+
{{ hook.content | indent(12) }}
|
|
21
|
+
|
|
22
|
+
## Instructions
|
|
23
|
+
|
|
24
|
+
Review the conversation and determine if ALL quality criteria above have been satisfied.
|
|
25
|
+
Look for evidence that each criterion has been addressed.
|
|
26
|
+
|
|
27
|
+
If the agent has included `<promise>✓ Quality Criteria Met</promise>` in their response AND
|
|
28
|
+
all criteria appear to be met, respond with: {"ok": true}
|
|
29
|
+
|
|
30
|
+
If criteria are NOT met AND the promise tag is missing, respond with:
|
|
31
|
+
{"ok": false, "reason": "Continue working. [specific feedback on what's wrong]"}
|
|
32
|
+
{% else %}
|
|
33
|
+
{{ hook.content | indent(12) }}
|
|
34
|
+
{% endif %}
|
|
35
|
+
{% endif %}
|
|
36
|
+
{% endfor %}
|
|
37
|
+
{% endfor %}
|
|
38
|
+
{% endif %}
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
# {{ job_name }}.{{ step_id }}
|
|
42
|
+
|
|
43
|
+
{% if is_standalone %}
|
|
44
|
+
**Standalone command** in the **{{ job_name }}** job - can be run anytime
|
|
45
|
+
{% else %}
|
|
46
|
+
**Step {{ step_number }} of {{ total_steps }}** in the **{{ job_name }}** workflow
|
|
47
|
+
{% endif %}
|
|
48
|
+
|
|
49
|
+
**Summary**: {{ job_summary }}
|
|
50
|
+
|
|
51
|
+
{% if job_description %}
|
|
52
|
+
## Job Overview
|
|
53
|
+
|
|
54
|
+
{{ job_description }}
|
|
55
|
+
{% endif %}
|
|
56
|
+
|
|
57
|
+
{% if dependencies %}
|
|
58
|
+
## Prerequisites
|
|
59
|
+
|
|
60
|
+
This step requires completion of the following step(s):
|
|
61
|
+
{% for dep in dependencies %}
|
|
62
|
+
- `/{{ job_name }}.{{ dep }}`
|
|
63
|
+
{% endfor %}
|
|
64
|
+
|
|
65
|
+
Please ensure these steps have been completed before proceeding.
|
|
66
|
+
{% endif %}
|
|
67
|
+
|
|
68
|
+
## Instructions
|
|
69
|
+
|
|
70
|
+
{{ instructions_content }}
|
|
71
|
+
|
|
72
|
+
{% if user_inputs or file_inputs %}
|
|
73
|
+
## Inputs
|
|
74
|
+
|
|
75
|
+
{% if user_inputs %}
|
|
76
|
+
### User Parameters
|
|
77
|
+
|
|
78
|
+
Please gather the following information from the user:
|
|
79
|
+
{% for input in user_inputs %}
|
|
80
|
+
- **{{ input.name }}**: {{ input.description }}
|
|
81
|
+
{% endfor %}
|
|
82
|
+
{% endif %}
|
|
83
|
+
|
|
84
|
+
{% if file_inputs %}
|
|
85
|
+
### Required Files
|
|
86
|
+
|
|
87
|
+
This step requires the following files from previous steps:
|
|
88
|
+
{% for input in file_inputs %}
|
|
89
|
+
- `{{ input.file }}` (from step `{{ input.from_step }}`)
|
|
90
|
+
{% endfor %}
|
|
91
|
+
|
|
92
|
+
Make sure to read and use these files as context for this step.
|
|
93
|
+
{% endif %}
|
|
94
|
+
{% endif %}
|
|
95
|
+
|
|
96
|
+
## Work Branch Management
|
|
97
|
+
|
|
98
|
+
All work for this job should be done on a dedicated work branch:
|
|
99
|
+
|
|
100
|
+
1. **Check current branch**:
|
|
101
|
+
- If already on a work branch for this job (format: `deepwork/{{ job_name }}-[instance]-[date]`), continue using it
|
|
102
|
+
- If on main/master, create a new work branch
|
|
103
|
+
|
|
104
|
+
2. **Create work branch** (if needed):
|
|
105
|
+
```bash
|
|
106
|
+
git checkout -b deepwork/{{ job_name }}-[instance]-$(date +%Y%m%d)
|
|
107
|
+
```
|
|
108
|
+
Replace `[instance]` with a descriptive identifier (e.g., `acme`, `q1-launch`, etc.)
|
|
109
|
+
|
|
110
|
+
## Output Requirements
|
|
111
|
+
|
|
112
|
+
{% if outputs %}
|
|
113
|
+
Create the following output(s):
|
|
114
|
+
{% for output in outputs %}
|
|
115
|
+
- `{{ output }}`{% if output.endswith('/') %} (directory){% endif %}
|
|
116
|
+
{% endfor %}
|
|
117
|
+
|
|
118
|
+
Ensure all outputs are:
|
|
119
|
+
- Well-formatted and complete
|
|
120
|
+
- Ready for review or use by subsequent steps
|
|
121
|
+
{% else %}
|
|
122
|
+
No specific files are output by this command.
|
|
123
|
+
{% endif %}
|
|
124
|
+
|
|
125
|
+
{% if stop_hooks %}
|
|
126
|
+
## Quality Validation Loop
|
|
127
|
+
|
|
128
|
+
This step uses an iterative quality validation loop. After completing your work, stop hook(s) will evaluate whether the outputs meet quality criteria. If criteria are not met, you will be prompted to continue refining.
|
|
129
|
+
|
|
130
|
+
{% for hook in stop_hooks %}
|
|
131
|
+
{% if hook.type == "script" %}
|
|
132
|
+
**Validation Script**: `.deepwork/jobs/{{ job_name }}/{{ hook.path }}`
|
|
133
|
+
|
|
134
|
+
The validation script will be executed automatically when you attempt to complete this step.
|
|
135
|
+
{% else %}
|
|
136
|
+
### Quality Criteria{% if stop_hooks | length > 1 %} ({{ loop.index }}){% endif %}
|
|
137
|
+
|
|
138
|
+
{{ hook.content }}
|
|
139
|
+
{% endif %}
|
|
140
|
+
{% endfor %}
|
|
141
|
+
|
|
142
|
+
### Completion Promise
|
|
143
|
+
|
|
144
|
+
To signal that all quality criteria have been met, include this tag in your final response:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
<promise>✓ Quality Criteria Met</promise>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Important**: Only include this promise tag when you have verified that ALL quality criteria above are satisfied. The validation loop will continue until this promise is detected.
|
|
151
|
+
|
|
152
|
+
{% endif %}
|
|
153
|
+
## Completion
|
|
154
|
+
|
|
155
|
+
After completing this step:
|
|
156
|
+
|
|
157
|
+
1. **Verify outputs**: Confirm all required files have been created
|
|
158
|
+
|
|
159
|
+
2. **Inform the user**:
|
|
160
|
+
{% if is_standalone %}
|
|
161
|
+
- The {{ step_id }} command is complete
|
|
162
|
+
{% if outputs %}
|
|
163
|
+
- Outputs created: {{ outputs | join(', ') }}
|
|
164
|
+
{% endif %}
|
|
165
|
+
- This command can be run again anytime to make further changes
|
|
166
|
+
{% else %}
|
|
167
|
+
- Step {{ step_number }} of {{ total_steps }} is complete
|
|
168
|
+
{% if outputs %}
|
|
169
|
+
- Outputs created: {{ outputs | join(', ') }}
|
|
170
|
+
{% endif %}
|
|
171
|
+
{% if next_step %}
|
|
172
|
+
- Ready to proceed to next step: `/{{ job_name }}.{{ next_step }}`
|
|
173
|
+
{% else %}
|
|
174
|
+
- This is the final step - the job is complete!
|
|
175
|
+
{% endif %}
|
|
176
|
+
{% endif %}
|
|
177
|
+
|
|
178
|
+
{% if is_standalone %}
|
|
179
|
+
## Command Complete
|
|
180
|
+
|
|
181
|
+
This is a standalone command that can be run anytime. The outputs are ready for use.
|
|
182
|
+
|
|
183
|
+
Consider:
|
|
184
|
+
- Reviewing the outputs
|
|
185
|
+
- Running `deepwork sync` if job definitions were changed
|
|
186
|
+
- Re-running this command later if further changes are needed
|
|
187
|
+
{% elif next_step %}
|
|
188
|
+
## Next Step
|
|
189
|
+
|
|
190
|
+
To continue the workflow, run:
|
|
191
|
+
```
|
|
192
|
+
/{{ job_name }}.{{ next_step }}
|
|
193
|
+
```
|
|
194
|
+
{% else %}
|
|
195
|
+
## Workflow Complete
|
|
196
|
+
|
|
197
|
+
This is the final step in the {{ job_name }} workflow. All outputs should now be complete and ready for review.
|
|
198
|
+
|
|
199
|
+
Consider:
|
|
200
|
+
- Reviewing all work products
|
|
201
|
+
- Creating a pull request to merge the work branch
|
|
202
|
+
- Documenting any insights or learnings
|
|
203
|
+
{% endif %}
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Context Files
|
|
208
|
+
|
|
209
|
+
- Job definition: `.deepwork/jobs/{{ job_name }}/job.yml`
|
|
210
|
+
- Step instructions: `.deepwork/jobs/{{ job_name }}/{{ instructions_file }}`
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# {{ job_name }}:{{ step_id }}
|
|
2
|
+
#
|
|
3
|
+
# {{ step_description }}
|
|
4
|
+
#
|
|
5
|
+
# Generated by DeepWork - do not edit manually
|
|
6
|
+
|
|
7
|
+
description = "{{ step_description | replace('"', '\\"') }}"
|
|
8
|
+
|
|
9
|
+
prompt = """
|
|
10
|
+
# {{ job_name }}:{{ step_id }}
|
|
11
|
+
|
|
12
|
+
{% if is_standalone %}
|
|
13
|
+
**Standalone command** in the **{{ job_name }}** job - can be run anytime
|
|
14
|
+
{% else %}
|
|
15
|
+
**Step {{ step_number }} of {{ total_steps }}** in the **{{ job_name }}** workflow
|
|
16
|
+
{% endif %}
|
|
17
|
+
|
|
18
|
+
**Summary**: {{ job_summary }}
|
|
19
|
+
|
|
20
|
+
{% if job_description %}
|
|
21
|
+
## Job Overview
|
|
22
|
+
|
|
23
|
+
{{ job_description }}
|
|
24
|
+
{% endif %}
|
|
25
|
+
|
|
26
|
+
{% if dependencies %}
|
|
27
|
+
## Prerequisites
|
|
28
|
+
|
|
29
|
+
This step requires completion of the following step(s):
|
|
30
|
+
{% for dep in dependencies %}
|
|
31
|
+
- `/{{ job_name }}:{{ dep }}`
|
|
32
|
+
{% endfor %}
|
|
33
|
+
|
|
34
|
+
Please ensure these steps have been completed before proceeding.
|
|
35
|
+
{% endif %}
|
|
36
|
+
|
|
37
|
+
## Instructions
|
|
38
|
+
|
|
39
|
+
{{ instructions_content }}
|
|
40
|
+
|
|
41
|
+
{% if user_inputs or file_inputs %}
|
|
42
|
+
## Inputs
|
|
43
|
+
|
|
44
|
+
{% if user_inputs %}
|
|
45
|
+
### User Parameters
|
|
46
|
+
|
|
47
|
+
Please gather the following information from the user:
|
|
48
|
+
{% for input in user_inputs %}
|
|
49
|
+
- **{{ input.name }}**: {{ input.description }}
|
|
50
|
+
{% endfor %}
|
|
51
|
+
{% endif %}
|
|
52
|
+
|
|
53
|
+
{% if file_inputs %}
|
|
54
|
+
### Required Files
|
|
55
|
+
|
|
56
|
+
This step requires the following files from previous steps:
|
|
57
|
+
{% for input in file_inputs %}
|
|
58
|
+
- `{{ input.file }}` (from step `{{ input.from_step }}`)
|
|
59
|
+
{% endfor %}
|
|
60
|
+
|
|
61
|
+
Make sure to read and use these files as context for this step.
|
|
62
|
+
{% endif %}
|
|
63
|
+
{% endif %}
|
|
64
|
+
|
|
65
|
+
## Work Branch Management
|
|
66
|
+
|
|
67
|
+
All work for this job should be done on a dedicated work branch:
|
|
68
|
+
|
|
69
|
+
1. **Check current branch**:
|
|
70
|
+
- If already on a work branch for this job (format: `deepwork/{{ job_name }}-[instance]-[date]`), continue using it
|
|
71
|
+
- If on main/master, create a new work branch
|
|
72
|
+
|
|
73
|
+
2. **Create work branch** (if needed):
|
|
74
|
+
```bash
|
|
75
|
+
git checkout -b deepwork/{{ job_name }}-[instance]-$(date +%Y%m%d)
|
|
76
|
+
```
|
|
77
|
+
Replace `[instance]` with a descriptive identifier (e.g., `acme`, `q1-launch`, etc.)
|
|
78
|
+
|
|
79
|
+
## Output Requirements
|
|
80
|
+
|
|
81
|
+
{% if outputs %}
|
|
82
|
+
Create the following output(s):
|
|
83
|
+
{% for output in outputs %}
|
|
84
|
+
- `{{ output }}`{% if output.endswith('/') %} (directory){% endif %}
|
|
85
|
+
|
|
86
|
+
{% endfor %}
|
|
87
|
+
|
|
88
|
+
Ensure all outputs are:
|
|
89
|
+
- Well-formatted and complete
|
|
90
|
+
- Ready for review or use by subsequent steps
|
|
91
|
+
{% else %}
|
|
92
|
+
No specific files are output by this command.
|
|
93
|
+
{% endif %}
|
|
94
|
+
|
|
95
|
+
{% if stop_hooks %}
|
|
96
|
+
## Quality Validation
|
|
97
|
+
|
|
98
|
+
This step has quality criteria that should be verified before completion.
|
|
99
|
+
|
|
100
|
+
{% for hook in stop_hooks %}
|
|
101
|
+
{% if hook.type != "script" %}
|
|
102
|
+
### Quality Criteria{% if stop_hooks | length > 1 %} ({{ loop.index }}){% endif %}
|
|
103
|
+
|
|
104
|
+
{{ hook.content }}
|
|
105
|
+
{% endif %}
|
|
106
|
+
{% endfor %}
|
|
107
|
+
|
|
108
|
+
**Note**: Gemini CLI does not support automated validation hooks. Please manually verify the criteria above before proceeding.
|
|
109
|
+
|
|
110
|
+
{% endif %}
|
|
111
|
+
## Completion
|
|
112
|
+
|
|
113
|
+
After completing this step:
|
|
114
|
+
|
|
115
|
+
1. **Verify outputs**: Confirm all required files have been created
|
|
116
|
+
|
|
117
|
+
2. **Inform the user**:
|
|
118
|
+
{% if is_standalone %}
|
|
119
|
+
- The {{ step_id }} command is complete
|
|
120
|
+
{% if outputs %}
|
|
121
|
+
- Outputs created: {{ outputs | join(', ') }}
|
|
122
|
+
{% endif %}
|
|
123
|
+
- This command can be run again anytime to make further changes
|
|
124
|
+
{% else %}
|
|
125
|
+
- Step {{ step_number }} of {{ total_steps }} is complete
|
|
126
|
+
{% if outputs %}
|
|
127
|
+
- Outputs created: {{ outputs | join(', ') }}
|
|
128
|
+
{% endif %}
|
|
129
|
+
{% if next_step %}
|
|
130
|
+
- Ready to proceed to next step: `/{{ job_name }}:{{ next_step }}`
|
|
131
|
+
{% else %}
|
|
132
|
+
- This is the final step - the job is complete!
|
|
133
|
+
{% endif %}
|
|
134
|
+
{% endif %}
|
|
135
|
+
|
|
136
|
+
{% if is_standalone %}
|
|
137
|
+
## Command Complete
|
|
138
|
+
|
|
139
|
+
This is a standalone command that can be run anytime. The outputs are ready for use.
|
|
140
|
+
|
|
141
|
+
Consider:
|
|
142
|
+
- Reviewing the outputs
|
|
143
|
+
- Running `deepwork sync` if job definitions were changed
|
|
144
|
+
- Re-running this command later if further changes are needed
|
|
145
|
+
{% elif next_step %}
|
|
146
|
+
## Next Step
|
|
147
|
+
|
|
148
|
+
To continue the workflow, run:
|
|
149
|
+
```
|
|
150
|
+
/{{ job_name }}:{{ next_step }}
|
|
151
|
+
```
|
|
152
|
+
{% else %}
|
|
153
|
+
## Workflow Complete
|
|
154
|
+
|
|
155
|
+
This is the final step in the {{ job_name }} workflow. All outputs should now be complete and ready for review.
|
|
156
|
+
|
|
157
|
+
Consider:
|
|
158
|
+
- Reviewing all work products
|
|
159
|
+
- Creating a pull request to merge the work branch
|
|
160
|
+
- Documenting any insights or learnings
|
|
161
|
+
{% endif %}
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Context Files
|
|
166
|
+
|
|
167
|
+
- Job definition: `.deepwork/jobs/{{ job_name }}/job.yml`
|
|
168
|
+
- Step instructions: `.deepwork/jobs/{{ job_name }}/{{ instructions_file }}`
|
|
169
|
+
"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Utility functions for DeepWork."""
|
deepwork/utils/fs.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Filesystem utilities for safe file operations."""
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def ensure_dir(path: Path | str) -> Path:
|
|
8
|
+
"""
|
|
9
|
+
Create directory if it doesn't exist.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
path: Directory path to create
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
Path object for the created/existing directory
|
|
16
|
+
"""
|
|
17
|
+
path_obj = Path(path)
|
|
18
|
+
path_obj.mkdir(parents=True, exist_ok=True)
|
|
19
|
+
return path_obj
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def safe_write(path: Path | str, content: str) -> None:
|
|
23
|
+
"""
|
|
24
|
+
Write content to file, creating parent directories if needed.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
path: File path to write to
|
|
28
|
+
content: Content to write
|
|
29
|
+
|
|
30
|
+
Raises:
|
|
31
|
+
OSError: If write operation fails
|
|
32
|
+
"""
|
|
33
|
+
path_obj = Path(path)
|
|
34
|
+
ensure_dir(path_obj.parent)
|
|
35
|
+
path_obj.write_text(content, encoding="utf-8")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def safe_read(path: Path | str) -> str | None:
|
|
39
|
+
"""
|
|
40
|
+
Read content from file, return None if file doesn't exist.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
path: File path to read from
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
File content as string, or None if file doesn't exist
|
|
47
|
+
|
|
48
|
+
Raises:
|
|
49
|
+
OSError: If read operation fails for reasons other than file not existing
|
|
50
|
+
"""
|
|
51
|
+
path_obj = Path(path)
|
|
52
|
+
if not path_obj.exists():
|
|
53
|
+
return None
|
|
54
|
+
return path_obj.read_text(encoding="utf-8")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def copy_dir(src: Path | str, dst: Path | str, ignore_patterns: list[str] | None = None) -> None:
|
|
58
|
+
"""
|
|
59
|
+
Recursively copy directory, optionally ignoring patterns.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
src: Source directory path
|
|
63
|
+
dst: Destination directory path
|
|
64
|
+
ignore_patterns: Optional list of glob patterns to ignore
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
FileNotFoundError: If source directory doesn't exist
|
|
68
|
+
OSError: If copy operation fails
|
|
69
|
+
"""
|
|
70
|
+
src_path = Path(src)
|
|
71
|
+
dst_path = Path(dst)
|
|
72
|
+
|
|
73
|
+
if not src_path.exists():
|
|
74
|
+
raise FileNotFoundError(f"Source directory does not exist: {src_path}")
|
|
75
|
+
|
|
76
|
+
if not src_path.is_dir():
|
|
77
|
+
raise NotADirectoryError(f"Source is not a directory: {src_path}")
|
|
78
|
+
|
|
79
|
+
# Create ignore function if patterns provided
|
|
80
|
+
ignore_func = None
|
|
81
|
+
if ignore_patterns:
|
|
82
|
+
|
|
83
|
+
def _ignore(directory: str, contents: list[str]) -> set[str]:
|
|
84
|
+
ignored = set()
|
|
85
|
+
dir_path = Path(directory)
|
|
86
|
+
for item in contents:
|
|
87
|
+
item_path = dir_path / item
|
|
88
|
+
for pattern in ignore_patterns:
|
|
89
|
+
if item_path.match(pattern):
|
|
90
|
+
ignored.add(item)
|
|
91
|
+
break
|
|
92
|
+
return ignored
|
|
93
|
+
|
|
94
|
+
ignore_func = _ignore
|
|
95
|
+
|
|
96
|
+
shutil.copytree(src_path, dst_path, ignore=ignore_func, dirs_exist_ok=True)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def find_files(directory: Path | str, pattern: str) -> list[Path]:
|
|
100
|
+
"""
|
|
101
|
+
Find files matching glob pattern in directory.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
directory: Directory to search in
|
|
105
|
+
pattern: Glob pattern to match (e.g., "*.py", "**/*.md")
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
List of matching file paths (sorted)
|
|
109
|
+
|
|
110
|
+
Raises:
|
|
111
|
+
FileNotFoundError: If directory doesn't exist
|
|
112
|
+
"""
|
|
113
|
+
dir_path = Path(directory)
|
|
114
|
+
|
|
115
|
+
if not dir_path.exists():
|
|
116
|
+
raise FileNotFoundError(f"Directory does not exist: {dir_path}")
|
|
117
|
+
|
|
118
|
+
if not dir_path.is_dir():
|
|
119
|
+
raise NotADirectoryError(f"Path is not a directory: {dir_path}")
|
|
120
|
+
|
|
121
|
+
# Use rglob for ** patterns, otherwise use glob
|
|
122
|
+
if "**" in pattern:
|
|
123
|
+
matches = dir_path.glob(pattern)
|
|
124
|
+
else:
|
|
125
|
+
matches = dir_path.glob(pattern)
|
|
126
|
+
|
|
127
|
+
# Return only files, not directories, sorted by path
|
|
128
|
+
return sorted([p for p in matches if p.is_file()])
|